Skip to content

Commit 206da4e

Browse files
committed
chore: fix text-left and text-right adding new tests
1 parent 0c64c2f commit 206da4e

2 files changed

Lines changed: 52 additions & 57 deletions

File tree

test/unit/uno-preset-rtl.spec.ts

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ describe('uno-preset-rtl', () => {
2828
:root, :host { --spacing: 0.25rem; --font-sans: ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; --font-mono: ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; --default-font-family: var(--font-sans); --default-monoFont-family: var(--font-mono); }
2929
/* layer: base */
3030
*, ::after, ::before, ::backdrop, ::file-selector-button { box-sizing: border-box; margin: 0; padding: 0; border: 0 solid; } html, :host { line-height: 1.5; -webkit-text-size-adjust: 100%; tab-size: 4; font-family: var( --default-font-family, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji' ); font-feature-settings: var(--default-font-featureSettings, normal); font-variation-settings: var(--default-font-variationSettings, normal); -webkit-tap-highlight-color: transparent; } hr { height: 0; color: inherit; border-top-width: 1px; } abbr:where([title]) { -webkit-text-decoration: underline dotted; text-decoration: underline dotted; } h1, h2, h3, h4, h5, h6 { font-size: inherit; font-weight: inherit; } a { color: inherit; -webkit-text-decoration: inherit; text-decoration: inherit; } b, strong { font-weight: bolder; } code, kbd, samp, pre { font-family: var( --default-monoFont-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace ); font-feature-settings: var(--default-monoFont-featureSettings, normal); font-variation-settings: var(--default-monoFont-variationSettings, normal); font-size: 1em; } small { font-size: 80%; } sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sub { bottom: -0.25em; } sup { top: -0.5em; } table { text-indent: 0; border-color: inherit; border-collapse: collapse; } :-moz-focusring { outline: auto; } progress { vertical-align: baseline; } summary { display: list-item; } ol, ul, menu { list-style: none; } img, svg, video, canvas, audio, iframe, embed, object { display: block; vertical-align: middle; } img, video { max-width: 100%; height: auto; } button, input, select, optgroup, textarea, ::file-selector-button { font: inherit; font-feature-settings: inherit; font-variation-settings: inherit; letter-spacing: inherit; color: inherit; border-radius: 0; background-color: transparent; opacity: 1; } :where(select:is([multiple], [size])) optgroup { font-weight: bolder; } :where(select:is([multiple], [size])) optgroup option { padding-inline-start: 20px; } ::file-selector-button { margin-inline-end: 4px; } ::placeholder { opacity: 1; } @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) { ::placeholder { color: color-mix(in oklab, currentcolor 50%, transparent); } } textarea { resize: vertical; } ::-webkit-search-decoration { -webkit-appearance: none; } ::-webkit-date-and-time-value { min-height: 1lh; text-align: inherit; } ::-webkit-datetime-edit { display: inline-flex; } ::-webkit-datetime-edit-fields-wrapper { padding: 0; } ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field { padding-block: 0; } ::-webkit-calendar-picker-indicator { line-height: 1; } :-moz-ui-invalid { box-shadow: none; } button, input:where([type='button'], [type='reset'], [type='submit']), ::file-selector-button { appearance: button; } ::-webkit-inner-spin-button, ::-webkit-outer-spin-button { height: auto; } [hidden]:where(:not([hidden~='until-found'])) { display: none !important; }
31+
/* layer: shortcuts */
32+
.text-left{text-align:start;--x-rtl-start:"text-left -> text-start";}
33+
.text-right{text-align:end;--x-rtl-end:"text-right -> text-end";}
34+
.hover\\:text-right:hover{text-align:end;--x-rtl-end:"hover:text-right -> hover:text-end";}
3135
/* layer: default */
32-
.text-left{text-align:left;}
33-
.text-right{text-align:right;}
34-
.hover\\:text-right:hover{text-align:right;}
3536
.pl-1{padding-inline-start:calc(var(--spacing) * 1);}
3637
.pr-1{padding-inline-end:calc(var(--spacing) * 1);}
3738
.ml-1{margin-inline-start:calc(var(--spacing) * 1);}
@@ -51,18 +52,21 @@ describe('uno-preset-rtl', () => {
5152
const warnings = warnSpy.mock.calls.flat()
5253
expect(warnings).toMatchInlineSnapshot(`
5354
[
54-
"[RTL] Avoid using 'left-0'. Use 'inset-is-0' instead.",
55-
"[RTL] Avoid using 'right-0'. Use 'inset-ie-0' instead.",
56-
"[RTL] Avoid using 'pl-1'. Use 'ps-1' instead.",
57-
"[RTL] Avoid using 'ml-1'. Use 'ms-1' instead.",
58-
"[RTL] Avoid using 'pr-1'. Use 'pe-1' instead.",
59-
"[RTL] Avoid using 'mr-1'. Use 'me-1' instead.",
60-
"[RTL] Avoid using 'border-l'. Use 'border-is' instead.",
61-
"[RTL] Avoid using 'border-r'. Use 'border-ie' instead.",
62-
"[RTL] Avoid using 'rounded-l'. Use 'rounded-is' instead.",
63-
"[RTL] Avoid using 'rounded-r'. Use 'rounded-ie' instead.",
64-
"[RTL] Avoid using 'position-left-4'. Use 'inset-is-4' instead.",
65-
"[RTL] Avoid using 'sm:pl-2'. Use 'sm:ps-2' instead.",
55+
"[RTL] Avoid using 'left-0', use 'inset-is-0' instead.",
56+
"[RTL] Avoid using 'right-0', use 'inset-ie-0' instead.",
57+
"[RTL] Avoid using 'pl-1', use 'ps-1' instead.",
58+
"[RTL] Avoid using 'ml-1', use 'ms-1' instead.",
59+
"[RTL] Avoid using 'pr-1', use 'pe-1' instead.",
60+
"[RTL] Avoid using 'mr-1', use 'me-1' instead.",
61+
"[RTL] Avoid using 'border-l', use 'border-is' instead.",
62+
"[RTL] Avoid using 'border-r', use 'border-ie' instead.",
63+
"[RTL] Avoid using 'rounded-l', use 'rounded-is' instead.",
64+
"[RTL] Avoid using 'rounded-r', use 'rounded-ie' instead.",
65+
"[RTL] Avoid using 'position-left-4', use 'inset-is-4' instead.",
66+
"[RTL] Avoid using 'sm:pl-2', use 'sm:ps-2' instead.",
67+
"[RTL] Avoid using 'text-left', use 'text-start' instead.",
68+
"[RTL] Avoid using 'text-right', use 'text-end' instead.",
69+
"[RTL] Avoid using 'hover:text-right', use 'hover:text-end' instead.",
6670
]
6771
`)
6872
})

uno-preset-rtl.ts

Lines changed: 33 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ export function resetRtlWarnings() {
1919
warnedClasses.clear()
2020
}
2121

22+
function reportWarning(match: string, suggestedClass: string, checker?: CollectorChecker) {
23+
const message = `${checker ? 'a' : 'A'}void using '${match}', use '${suggestedClass}' instead.`
24+
if (checker) {
25+
checker(message, match)
26+
} else {
27+
warnOnce(`[RTL] ${message}`, match)
28+
}
29+
}
30+
2231
const directionMap: Record<string, string[]> = {
2332
'l': ['-left'],
2433
'r': ['-right'],
@@ -54,11 +63,8 @@ function directionSizeRTL(
5463
const suggestedBase = match.replace(`${prefix}${direction!}`, `${prefix}${replacement}`)
5564
const suggestedClass = fullClass.replace(match, suggestedBase)
5665

57-
if (checker) {
58-
checker(`avoid using '${fullClass}', use '${suggestedClass}' instead.`, fullClass)
59-
} else {
60-
warnOnce(`[RTL] Avoid using '${fullClass}'. Use '${suggestedClass}' instead.`, fullClass)
61-
}
66+
reportWarning(fullClass, suggestedClass, checker)
67+
6268
return matcher([match, replacement, size], context)
6369
}
6470
}
@@ -90,6 +96,10 @@ function handlerBorderSize([, a = '', b = '1']: string[]): CSSEntries | undefine
9096
export function presetRtl(checker?: CollectorChecker): Preset {
9197
return {
9298
name: 'rtl-preset',
99+
shortcuts: [
100+
['text-left', 'text-start x-rtl-start'],
101+
['text-right', 'text-end x-rtl-end'],
102+
],
93103
rules: [
94104
// RTL overrides
95105
// We need to move the dash out of the capturing group to avoid capturing it in the direction
@@ -116,36 +126,29 @@ export function presetRtl(checker?: CollectorChecker): Preset {
116126
const suggestedBase = `${replacement}-${size}`
117127
const suggestedClass = fullClass.replace(match, suggestedBase)
118128

119-
if (checker) {
120-
checker(`avoid using '${fullClass}', use '${suggestedClass}' instead.`, fullClass)
121-
} else {
122-
warnOnce(
123-
`[RTL] Avoid using '${fullClass}'. Use '${suggestedClass}' instead.`,
124-
fullClass,
125-
)
126-
}
129+
reportWarning(fullClass, suggestedClass, checker)
130+
127131
return directionSize('inset')(['', direction === 'left' ? 'is' : 'ie', size], context)
128132
},
129133
{ autocomplete: '(left|right)-<num>' },
130134
],
131135
[
132-
/^text-(left|right)$/,
136+
/^x-rtl-(start|end)$/,
133137
([match, direction], context) => {
134-
const replacement = direction === 'left' ? 'start' : 'end'
138+
const originalClass = context.rawSelector || match
135139

136-
const fullClass = context.rawSelector || match
137-
const suggestedBase = match.replace(`text-${direction!}`, `text-${replacement}`)
138-
const suggestedClass = fullClass.replace(match, suggestedBase)
140+
const suggestedClass = originalClass.replace(
141+
direction === 'start' ? 'left' : 'right',
142+
direction!,
143+
)
139144

140-
if (checker) {
141-
checker(`avoid using '${fullClass}', use '${suggestedClass}' instead.`, fullClass)
142-
} else {
143-
warnOnce(
144-
`[RTL] Avoid using '${fullClass}'. Use '${suggestedClass}' instead.`,
145-
fullClass,
146-
)
145+
reportWarning(originalClass, suggestedClass, checker)
146+
147+
// Return a cssvar with the warning message to satisfy UnoCSS
148+
// and avoid "unmatched utility" warning.
149+
return {
150+
[`--x-rtl-${direction!}`]: `"${originalClass} -> ${suggestedClass}"`,
147151
}
148-
return { 'text-align': replacement }
149152
},
150153
{ autocomplete: 'text-(left|right)' },
151154
],
@@ -164,14 +167,8 @@ export function presetRtl(checker?: CollectorChecker): Preset {
164167
const suggestedBase = match.replace(`rounded-${direction!}`, `rounded-${replacement}`)
165168
const suggestedClass = fullClass.replace(match, suggestedBase)
166169

167-
if (checker) {
168-
checker(`avoid using '${fullClass}', use '${suggestedClass}' instead.`, fullClass)
169-
} else {
170-
warnOnce(
171-
`[RTL] Avoid using '${fullClass}'. Use '${suggestedClass}' instead.`,
172-
fullClass,
173-
)
174-
}
170+
reportWarning(fullClass, suggestedClass, checker)
171+
175172
return handlerRounded(['', replacement, size ?? 'DEFAULT'], context)
176173
},
177174
],
@@ -184,14 +181,8 @@ export function presetRtl(checker?: CollectorChecker): Preset {
184181
const suggestedBase = match.replace(`border-${direction!}`, `border-${replacement}`)
185182
const suggestedClass = fullClass.replace(match, suggestedBase)
186183

187-
if (checker) {
188-
checker(`avoid using '${fullClass}', use '${suggestedClass}' instead.`, fullClass)
189-
} else {
190-
warnOnce(
191-
`[RTL] Avoid using '${fullClass}'. Use '${suggestedClass}' instead.`,
192-
fullClass,
193-
)
194-
}
184+
reportWarning(fullClass, suggestedClass, checker)
185+
195186
return handlerBorderSize(['', replacement, size || '1'])
196187
},
197188
],

0 commit comments

Comments
 (0)