@syncedco/flow 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/bin/synced-flow.mjs +99 -37
- package/examples/wordpress/assets/css/synced-flow.css +0 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0 - 2026-09-25
|
|
4
|
+
|
|
5
|
+
- Fix `border`, `border-t`, `border-2` and the other border width utilities
|
|
6
|
+
drawing nothing: they now also set `border-style: solid`.
|
|
7
|
+
- Fix `space-x-*`, `space-y-*`, `divide-x` and `divide-y` doing nothing unless
|
|
8
|
+
core CSS was included. They now generate their own child rules for any
|
|
9
|
+
value, so `space-y-7` works too.
|
|
10
|
+
- Fix `h-screen`, `min-h-screen`, `max-h-screen`, `top-screen`,
|
|
11
|
+
`bottom-screen` and `translate-y-screen` using the viewport width (`100svw`)
|
|
12
|
+
instead of the viewport height (`100svh`). `size-screen` now sets
|
|
13
|
+
`100svw` by `100svh`.
|
|
14
|
+
- Add `dvh`, `dvw`, `lvh` and `lvw` sizing keywords, such as `min-h-dvh`.
|
|
15
|
+
- Add common utilities: `border-dashed`/`dotted`/`double`/`none`,
|
|
16
|
+
`divide-<colour>`, `divide-dashed`, `divide-x-2`, `order-*`,
|
|
17
|
+
`col-start-*`/`col-end-*`/`row-start-*`/`row-end-*`, `justify-items-*`,
|
|
18
|
+
`justify-self-*`, `flex-initial`, `max-w-none`, `max-h-none`,
|
|
19
|
+
`object-<position>`, `bg-cover`/`contain`, `bg-<position>`,
|
|
20
|
+
`bg-no-repeat` and other repeat values, `bg-fixed`, `bg-linear-to-*`,
|
|
21
|
+
`bg-none`, `origin-*`, `font-serif`, `text-ellipsis`, `text-clip`, `blur`,
|
|
22
|
+
`transition-opacity`, `transition-shadow`, `transition-none`,
|
|
23
|
+
`animate-ping`, `animate-bounce` and `animate-none`.
|
|
24
|
+
- Improve `synced-flow lint` hints: suggest Flow's own class first
|
|
25
|
+
(`prose` suggests `sf-prose`), suggest the same utility with a valid value
|
|
26
|
+
(`h-scren` suggests `h-screen`, not `hidden`), and only suggest near typos,
|
|
27
|
+
so hints no longer name a class that does something else.
|
|
28
|
+
|
|
3
29
|
## 0.4.1 - 2026-09-09
|
|
4
30
|
|
|
5
31
|
- Fix source-tree generated-CSS checks when the package is tested from a
|
package/bin/synced-flow.mjs
CHANGED
|
@@ -3618,6 +3618,12 @@ function rawDeclarationsFor(base) {
|
|
|
3618
3618
|
[/^overflow-x-(hidden|visible|auto|scroll|clip)$/, 'overflow-x'],
|
|
3619
3619
|
[/^overflow-y-(hidden|visible|auto|scroll|clip)$/, 'overflow-y'],
|
|
3620
3620
|
[/^object-(cover|contain|fill|none|scale-down)$/, 'object-fit'],
|
|
3621
|
+
[/^object-(center|top|bottom|left|right|left-top|left-bottom|right-top|right-bottom)$/, 'object-position'],
|
|
3622
|
+
[/^bg-(cover|contain|auto)$/, 'background-size'],
|
|
3623
|
+
[/^bg-(center|top|bottom|left|right|left-top|left-bottom|right-top|right-bottom)$/, 'background-position'],
|
|
3624
|
+
[/^bg-(repeat|no-repeat|repeat-x|repeat-y|repeat-round|repeat-space)$/, 'background-repeat'],
|
|
3625
|
+
[/^bg-(fixed|local|scroll)$/, 'background-attachment'],
|
|
3626
|
+
[/^origin-(center|top|bottom|left|right|top-left|top-right|bottom-left|bottom-right)$/, 'transform-origin'],
|
|
3621
3627
|
[/^whitespace-(normal|nowrap|pre|pre-line|pre-wrap|break-spaces)$/, 'white-space'],
|
|
3622
3628
|
[/^break-(normal|words|all|keep)$/, 'overflow-wrap'],
|
|
3623
3629
|
[/^cursor-(pointer|default|not-allowed|grab|grabbing|text)$/, 'cursor'],
|
|
@@ -3627,11 +3633,17 @@ function rawDeclarationsFor(base) {
|
|
|
3627
3633
|
]
|
|
3628
3634
|
for (const [pattern, property] of simpleMaps) {
|
|
3629
3635
|
const match = base.match(pattern)
|
|
3630
|
-
if (match)
|
|
3636
|
+
if (match) {
|
|
3637
|
+
if (match[1] === 'words') return [[property, 'break-word']]
|
|
3638
|
+
// Positions are written `left-top` in the class and `left top` in CSS.
|
|
3639
|
+
return [[property, /-position$|-origin$/.test(property) ? match[1].replace('-', ' ') : match[1]]]
|
|
3640
|
+
}
|
|
3631
3641
|
}
|
|
3632
3642
|
|
|
3633
3643
|
if (base === 'appearance-none') return [['appearance', 'none']]
|
|
3634
3644
|
if (base === 'resize') return [['resize', 'both']]
|
|
3645
|
+
if (base === 'text-ellipsis') return [['text-overflow', 'ellipsis']]
|
|
3646
|
+
if (base === 'text-clip') return [['text-overflow', 'clip']]
|
|
3635
3647
|
if (base === 'truncate') return [['overflow', 'hidden'], ['text-overflow', 'ellipsis'], ['white-space', 'nowrap']]
|
|
3636
3648
|
const lineClamp = base.match(/^line-clamp-(\d+)$/)
|
|
3637
3649
|
if (lineClamp) return [['overflow', 'hidden'], ['display', '-webkit-box'], ['-webkit-box-orient', 'vertical'], ['-webkit-line-clamp', lineClamp[1]]]
|
|
@@ -3679,7 +3691,8 @@ function sideUtility(base, prefixes) {
|
|
|
3679
3691
|
const match = base.match(new RegExp(`^-?${prefix}-(.+)$`))
|
|
3680
3692
|
if (!match) continue
|
|
3681
3693
|
const negative = base.startsWith('-')
|
|
3682
|
-
const
|
|
3694
|
+
const axis = prefix === 'top' || prefix === 'bottom' ? 'y' : 'x'
|
|
3695
|
+
const value = spacingUnit(match[1]) ?? sizeKeyword(match[1], axis)
|
|
3683
3696
|
if (!value) continue
|
|
3684
3697
|
const resolved = negative ? `calc(${value} * -1)` : value
|
|
3685
3698
|
if (prefix === 'inset') return [['inset', resolved]]
|
|
@@ -3720,18 +3733,22 @@ function spacingUtility(base) {
|
|
|
3720
3733
|
'gap-x': ['column-gap'],
|
|
3721
3734
|
'gap-y': ['row-gap'],
|
|
3722
3735
|
}
|
|
3723
|
-
if (prefix === 'space-x') return [['
|
|
3724
|
-
if (prefix === 'space-y') return [['
|
|
3736
|
+
if (prefix === 'space-x') return [['margin-inline-start', resolved]]
|
|
3737
|
+
if (prefix === 'space-y') return [['margin-block-start', resolved]]
|
|
3725
3738
|
return map[prefix].map((property) => [property, resolved])
|
|
3726
3739
|
}
|
|
3727
3740
|
|
|
3728
|
-
|
|
3729
|
-
|
|
3741
|
+
// Keyword sizes. `screen` is swapped for the viewport height on the y axis.
|
|
3742
|
+
const sizeKeywords = {
|
|
3730
3743
|
auto: 'auto',
|
|
3731
3744
|
full: '100%',
|
|
3732
3745
|
screen: '100svw',
|
|
3733
3746
|
svw: '100svw',
|
|
3734
3747
|
svh: '100svh',
|
|
3748
|
+
dvw: '100dvw',
|
|
3749
|
+
dvh: '100dvh',
|
|
3750
|
+
lvw: '100lvw',
|
|
3751
|
+
lvh: '100lvh',
|
|
3735
3752
|
min: 'min-content',
|
|
3736
3753
|
max: 'max-content',
|
|
3737
3754
|
fit: 'fit-content',
|
|
@@ -3758,15 +3775,21 @@ function sizeKeyword(valueName) {
|
|
|
3758
3775
|
'4/5': '80%',
|
|
3759
3776
|
'1/6': '16.666667%',
|
|
3760
3777
|
'5/6': '83.333333%',
|
|
3761
|
-
|
|
3762
|
-
|
|
3778
|
+
}
|
|
3779
|
+
|
|
3780
|
+
function sizeKeyword(valueName, axis = 'x') {
|
|
3781
|
+
if (valueName === 'screen' && axis === 'y') return '100svh'
|
|
3782
|
+
return Object.hasOwn(sizeKeywords, valueName) ? sizeKeywords[valueName] : null
|
|
3763
3783
|
}
|
|
3764
3784
|
|
|
3765
3785
|
function sizingUtility(base) {
|
|
3766
3786
|
const match = base.match(/^(w|h|min-w|min-h|max-w|max-h|size|basis)-(.+)$/)
|
|
3767
3787
|
if (!match) return null
|
|
3768
3788
|
const [, prefix, valueName] = match
|
|
3769
|
-
|
|
3789
|
+
if ((prefix === 'max-w' || prefix === 'max-h') && valueName === 'none') return [[prefix === 'max-w' ? 'max-width' : 'max-height', 'none']]
|
|
3790
|
+
if (prefix === 'size' && valueName === 'screen') return [['width', '100svw'], ['height', '100svh']]
|
|
3791
|
+
const axis = prefix === 'h' || prefix === 'min-h' || prefix === 'max-h' ? 'y' : 'x'
|
|
3792
|
+
const value = spacingUnit(valueName) ?? sizeKeyword(valueName, axis)
|
|
3770
3793
|
if (!value) return null
|
|
3771
3794
|
const props = {
|
|
3772
3795
|
w: ['width'],
|
|
@@ -3792,6 +3815,7 @@ function flexGridUtility(base) {
|
|
|
3792
3815
|
'flex-1': [['flex', '1 1 0%']],
|
|
3793
3816
|
'flex-auto': [['flex', '1 1 auto']],
|
|
3794
3817
|
'flex-none': [['flex', 'none']],
|
|
3818
|
+
'flex-initial': [['flex', '0 1 auto']],
|
|
3795
3819
|
grow: [['flex-grow', '1']],
|
|
3796
3820
|
'grow-0': [['flex-grow', '0']],
|
|
3797
3821
|
shrink: [['flex-shrink', '1']],
|
|
@@ -3818,6 +3842,12 @@ function flexGridUtility(base) {
|
|
|
3818
3842
|
const placeMap = { center: 'center', start: 'start', end: 'end', stretch: 'stretch' }
|
|
3819
3843
|
let match = base.match(/^items-(start|end|center|baseline|stretch)$/)
|
|
3820
3844
|
if (match) return [['align-items', alignMap[match[1]]]]
|
|
3845
|
+
match = base.match(/^justify-items-(start|end|center|stretch)$/)
|
|
3846
|
+
if (match) return [['justify-items', match[1]]]
|
|
3847
|
+
match = base.match(/^justify-self-(auto|start|end|center|stretch)$/)
|
|
3848
|
+
if (match) return [['justify-self', match[1]]]
|
|
3849
|
+
match = base.match(/^order-(\d+|first|last|none)$/)
|
|
3850
|
+
if (match) return [['order', { first: '-9999', last: '9999', none: '0' }[match[1]] ?? match[1]]]
|
|
3821
3851
|
match = base.match(/^justify-(start|end|center|between|around|evenly|stretch)$/)
|
|
3822
3852
|
if (match) return [['justify-content', justifyMap[match[1]]]]
|
|
3823
3853
|
match = base.match(/^content-(start|end|center|between|around|evenly|stretch)$/)
|
|
@@ -3836,6 +3866,8 @@ function flexGridUtility(base) {
|
|
|
3836
3866
|
match = base.match(/^row-span-(\d+)$/)
|
|
3837
3867
|
if (match) return [['grid-row', `span ${match[1]} / span ${match[1]}`]]
|
|
3838
3868
|
if (base === 'col-span-full') return [['grid-column', '1 / -1']]
|
|
3869
|
+
match = base.match(/^(col|row)-(start|end)-(\d+|auto)$/)
|
|
3870
|
+
if (match) return [[`grid-${match[1] === 'col' ? 'column' : 'row'}-${match[2]}`, match[3]]]
|
|
3839
3871
|
if (base === 'grid-flow-col') return [['grid-auto-flow', 'column']]
|
|
3840
3872
|
if (base === 'grid-flow-row') return [['grid-auto-flow', 'row']]
|
|
3841
3873
|
|
|
@@ -3843,10 +3875,11 @@ function flexGridUtility(base) {
|
|
|
3843
3875
|
}
|
|
3844
3876
|
|
|
3845
3877
|
function typographyUtility(base) {
|
|
3846
|
-
let match = base.match(/^font-(sans|display|mono)$/)
|
|
3878
|
+
let match = base.match(/^font-(sans|serif|display|mono)$/)
|
|
3847
3879
|
if (match) {
|
|
3848
3880
|
const map = {
|
|
3849
3881
|
sans: 'var(--font-inter, var(--sf-font-sans, ui-sans-serif, system-ui, sans-serif))',
|
|
3882
|
+
serif: 'var(--font-serif, var(--sf-font-serif, ui-serif, Georgia, Cambria, "Times New Roman", serif))',
|
|
3850
3883
|
display: 'var(--font-display, var(--sf-font-display, ui-serif, Georgia, serif))',
|
|
3851
3884
|
mono: 'var(--font-mono, var(--sf-font-mono, ui-monospace, monospace))',
|
|
3852
3885
|
}
|
|
@@ -3894,22 +3927,33 @@ function colourUtility(base) {
|
|
|
3894
3927
|
}
|
|
3895
3928
|
|
|
3896
3929
|
function borderUtility(base) {
|
|
3897
|
-
|
|
3930
|
+
// A border width draws nothing without a line style, so width utilities set both.
|
|
3931
|
+
if (base === 'border') return [['border-width', '1px'], ['border-style', 'solid']]
|
|
3898
3932
|
if (base === 'border-0') return [['border-width', '0']]
|
|
3899
|
-
if (base === 'border-2') return [['border-width', '0.125rem']]
|
|
3900
|
-
if (base === 'border-t') return [['border-top-width', '1px']]
|
|
3901
|
-
if (base === 'border-r') return [['border-right-width', '1px']]
|
|
3902
|
-
if (base === 'border-b') return [['border-bottom-width', '1px']]
|
|
3903
|
-
if (base === 'border-l') return [['border-left-width', '1px']]
|
|
3904
|
-
if (base === 'border-y') return [['border-top-width', '1px'], ['border-bottom-width', '1px']]
|
|
3905
|
-
if (base === 'border-x') return [['border-left-width', '1px'], ['border-right-width', '1px']]
|
|
3933
|
+
if (base === 'border-2') return [['border-width', '0.125rem'], ['border-style', 'solid']]
|
|
3934
|
+
if (base === 'border-t') return [['border-top-width', '1px'], ['border-top-style', 'solid']]
|
|
3935
|
+
if (base === 'border-r') return [['border-right-width', '1px'], ['border-right-style', 'solid']]
|
|
3936
|
+
if (base === 'border-b') return [['border-bottom-width', '1px'], ['border-bottom-style', 'solid']]
|
|
3937
|
+
if (base === 'border-l') return [['border-left-width', '1px'], ['border-left-style', 'solid']]
|
|
3938
|
+
if (base === 'border-y') return [['border-top-width', '1px'], ['border-bottom-width', '1px'], ['border-top-style', 'solid'], ['border-bottom-style', 'solid']]
|
|
3939
|
+
if (base === 'border-x') return [['border-left-width', '1px'], ['border-right-width', '1px'], ['border-left-style', 'solid'], ['border-right-style', 'solid']]
|
|
3906
3940
|
const sideWidth = base.match(/^border-(t|r|b|l)-(\d+)$/)
|
|
3907
3941
|
if (sideWidth) {
|
|
3908
3942
|
const side = { t: 'top', r: 'right', b: 'bottom', l: 'left' }[sideWidth[1]]
|
|
3909
|
-
return [[`border-${side}-width`, borderWidthUnit(sideWidth[2])]]
|
|
3910
|
-
}
|
|
3911
|
-
|
|
3912
|
-
if (
|
|
3943
|
+
return [[`border-${side}-width`, borderWidthUnit(sideWidth[2])], [`border-${side}-style`, 'solid']]
|
|
3944
|
+
}
|
|
3945
|
+
const borderStyle = base.match(/^border-(solid|dashed|dotted|double|hidden|none)$/)
|
|
3946
|
+
if (borderStyle) return [['border-style', borderStyle[1]]]
|
|
3947
|
+
const divide = base.match(/^divide-(x|y)(?:-(\d+))?$/)
|
|
3948
|
+
if (divide) {
|
|
3949
|
+
const side = divide[1] === 'y' ? 'block' : 'inline'
|
|
3950
|
+
const width = divide[2] === undefined ? '1px' : borderWidthUnit(divide[2])
|
|
3951
|
+
return [[`border-${side}-start-width`, width], [`border-${side}-start-style`, 'solid']]
|
|
3952
|
+
}
|
|
3953
|
+
const divideStyle = base.match(/^divide-(solid|dashed|dotted|double|none)$/)
|
|
3954
|
+
if (divideStyle) return [['border-style', divideStyle[1]]]
|
|
3955
|
+
const divideColour = base.match(/^divide-(.+)$/)
|
|
3956
|
+
if (divideColour && colourValue(divideColour[1])) return [['border-color', colourValue(divideColour[1])]]
|
|
3913
3957
|
const roundedSide = base.match(/^rounded-(t|r|b|l|tr|tl|br|bl)-(none|xs|sm|md|lg|xl|2xl|3xl|full)$/)
|
|
3914
3958
|
if (roundedSide) {
|
|
3915
3959
|
const radius = `var(--radius-${roundedSide[2]})`
|
|
@@ -3947,6 +3991,9 @@ function borderUtility(base) {
|
|
|
3947
3991
|
}
|
|
3948
3992
|
|
|
3949
3993
|
function effectUtility(base) {
|
|
3994
|
+
const linear = base.match(/^bg-linear-to-(t|b|l|r|tl|tr|bl|br)$/)
|
|
3995
|
+
if (linear) return effectUtility(`bg-gradient-to-${linear[1]}`)
|
|
3996
|
+
if (base === 'bg-none') return [['background-image', 'none']]
|
|
3950
3997
|
if (base === 'bg-gradient-to-r') return [['background-image', 'linear-gradient(to right, var(--sf-gradient-stops))']]
|
|
3951
3998
|
if (base === 'bg-gradient-to-l') return [['background-image', 'linear-gradient(to left, var(--sf-gradient-stops))']]
|
|
3952
3999
|
if (base === 'bg-gradient-to-t') return [['background-image', 'linear-gradient(to top, var(--sf-gradient-stops))']]
|
|
@@ -3968,6 +4015,7 @@ function effectUtility(base) {
|
|
|
3968
4015
|
|
|
3969
4016
|
let match = base.match(/^opacity-(\d+)$/)
|
|
3970
4017
|
if (match) return [['opacity', String(Number(match[1]) / 100)]]
|
|
4018
|
+
if (base === 'blur') return [['filter', 'blur(0.5rem)']]
|
|
3971
4019
|
match = base.match(/^blur-(none|sm|md|lg|xl|2xl|3xl)$/)
|
|
3972
4020
|
if (match) {
|
|
3973
4021
|
const map = { none: '0', sm: '0.25rem', md: '0.75rem', lg: '1rem', xl: '1.5rem', '2xl': '2.5rem', '3xl': '4rem' }
|
|
@@ -3998,6 +4046,9 @@ function effectUtility(base) {
|
|
|
3998
4046
|
if (base === 'transition') return [['transition-property', 'color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter'], ['transition-duration', 'var(--duration-normal)'], ['transition-timing-function', 'var(--ease-standard)']]
|
|
3999
4047
|
if (base === 'transition-all') return [['transition-property', 'all'], ['transition-duration', 'var(--duration-normal)'], ['transition-timing-function', 'var(--ease-standard)']]
|
|
4000
4048
|
if (base === 'transition-colors') return [['transition-property', 'color, background-color, border-color, text-decoration-color, fill, stroke'], ['transition-duration', 'var(--duration-normal)'], ['transition-timing-function', 'var(--ease-standard)']]
|
|
4049
|
+
if (base === 'transition-opacity') return [['transition-property', 'opacity'], ['transition-duration', 'var(--duration-normal)'], ['transition-timing-function', 'var(--ease-standard)']]
|
|
4050
|
+
if (base === 'transition-shadow') return [['transition-property', 'box-shadow'], ['transition-duration', 'var(--duration-normal)'], ['transition-timing-function', 'var(--ease-standard)']]
|
|
4051
|
+
if (base === 'transition-none') return [['transition-property', 'none']]
|
|
4001
4052
|
if (base === 'transition-transform') return [['transition-property', 'transform'], ['transition-duration', 'var(--duration-normal)'], ['transition-timing-function', 'var(--ease-standard)']]
|
|
4002
4053
|
match = base.match(/^transition-\[(.+)\]$/)
|
|
4003
4054
|
if (match) return [['transition-property', arbitraryValue(match[1])], ['transition-duration', 'var(--duration-normal)']]
|
|
@@ -4010,6 +4061,9 @@ function effectUtility(base) {
|
|
|
4010
4061
|
if (base === 'ease-in-out') return [['transition-timing-function', 'cubic-bezier(0.4, 0, 0.2, 1)']]
|
|
4011
4062
|
if (base === 'animate-pulse') return [['animation', 'sf-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite']]
|
|
4012
4063
|
if (base === 'animate-spin') return [['animation', 'sf-spin 1s linear infinite']]
|
|
4064
|
+
if (base === 'animate-ping') return [['animation', 'sf-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite']]
|
|
4065
|
+
if (base === 'animate-bounce') return [['animation', 'sf-bounce 1s infinite']]
|
|
4066
|
+
if (base === 'animate-none') return [['animation', 'none']]
|
|
4013
4067
|
if (base === 'animate-in') return [['animation', 'sf-enter var(--duration-normal) var(--ease-standard) both']]
|
|
4014
4068
|
if (base === 'animate-out') return [['animation', 'sf-exit var(--duration-fast) var(--ease-standard) both']]
|
|
4015
4069
|
return null
|
|
@@ -4020,7 +4074,7 @@ function transformUtility(base) {
|
|
|
4020
4074
|
let match = base.match(/^(-?)translate-x-(.+)$/)
|
|
4021
4075
|
if (match) declarations.push(['--sf-translate-x', `${match[1] ? '-' : ''}${spacingUnit(match[2]) ?? sizeKeyword(match[2])}`])
|
|
4022
4076
|
match = base.match(/^(-?)translate-y-(.+)$/)
|
|
4023
|
-
if (match) declarations.push(['--sf-translate-y', `${match[1] ? '-' : ''}${spacingUnit(match[2]) ?? sizeKeyword(match[2])}`])
|
|
4077
|
+
if (match) declarations.push(['--sf-translate-y', `${match[1] ? '-' : ''}${spacingUnit(match[2]) ?? sizeKeyword(match[2], 'y')}`])
|
|
4024
4078
|
match = base.match(/^scale-\[(.+)\]$/)
|
|
4025
4079
|
if (match) declarations.push(['--sf-scale-x', arbitraryValue(match[1])], ['--sf-scale-y', arbitraryValue(match[1])])
|
|
4026
4080
|
match = base.match(/^scale-(\d+)$/)
|
|
@@ -4045,7 +4099,9 @@ function cssRuleFor(token) {
|
|
|
4045
4099
|
const selectorResult = selectorFor(token, variants)
|
|
4046
4100
|
if (!selectorResult) return null
|
|
4047
4101
|
|
|
4048
|
-
const {
|
|
4102
|
+
const { wrappers, needsPseudoContent } = selectorResult
|
|
4103
|
+
// space-* and divide-* style the gaps between children, not the element itself.
|
|
4104
|
+
const selector = /^-?(space-[xy]-|divide-)/.test(base) ? `${selectorResult.selector} > * + *` : selectorResult.selector
|
|
4049
4105
|
const allDeclarations = needsPseudoContent ? [['content', '""'], ...declarations] : declarations
|
|
4050
4106
|
let rule = `${selector}{${allDeclarations.map(([property, value]) => `${property}:${value}`).join(';')}}`
|
|
4051
4107
|
|
|
@@ -4713,16 +4769,6 @@ function buildLayoutCss() {
|
|
|
4713
4769
|
}
|
|
4714
4770
|
}
|
|
4715
4771
|
|
|
4716
|
-
:where(.space-y-1, .space-y-2, .space-y-3, .space-y-4, .space-y-5, .space-y-6, .space-y-8, .space-y-10, .space-y-12) > * + * {
|
|
4717
|
-
margin-block-start: var(--sf-space-y);
|
|
4718
|
-
}
|
|
4719
|
-
|
|
4720
|
-
:where(.space-x-1, .space-x-2, .space-x-3, .space-x-4, .space-x-5, .space-x-6, .space-x-8) > * + * {
|
|
4721
|
-
margin-inline-start: var(--sf-space-x);
|
|
4722
|
-
}
|
|
4723
|
-
|
|
4724
|
-
.divide-y > * + * { border-block-start-width: var(--sf-divide-y); }
|
|
4725
|
-
.divide-x > * + * { border-inline-start-width: var(--sf-divide-x); }
|
|
4726
4772
|
}`
|
|
4727
4773
|
}
|
|
4728
4774
|
|
|
@@ -5550,6 +5596,8 @@ function buildUsedKeyframesCss(bases) {
|
|
|
5550
5596
|
|
|
5551
5597
|
if (bases.has('animate-pulse')) keyframes.push('@keyframes sf-pulse { 50% { opacity: .5; } }')
|
|
5552
5598
|
if (bases.has('animate-spin')) keyframes.push('@keyframes sf-spin { to { transform: rotate(360deg); } }')
|
|
5599
|
+
if (bases.has('animate-ping')) keyframes.push('@keyframes sf-ping { 75%, 100% { transform: scale(2); opacity: 0; } }')
|
|
5600
|
+
if (bases.has('animate-bounce')) keyframes.push('@keyframes sf-bounce { 0%, 100% { transform: translateY(-25%); animation-timing-function: cubic-bezier(0.8, 0, 1, 1); } 50% { transform: none; animation-timing-function: cubic-bezier(0, 0, 0.2, 1); } }')
|
|
5553
5601
|
if (bases.has('animate-in')) keyframes.push('@keyframes sf-enter { from { opacity: 0; transform: translate3d(0, .5rem, 0) scale(.98); } to { opacity: 1; transform: translate3d(0, 0, 0) scale(1); } }')
|
|
5554
5602
|
if (bases.has('animate-out')) keyframes.push('@keyframes sf-exit { from { opacity: 1; transform: translate3d(0, 0, 0) scale(1); } to { opacity: 0; transform: translate3d(0, .25rem, 0) scale(.98); } }')
|
|
5555
5603
|
|
|
@@ -5591,11 +5639,25 @@ function utilitySuggestionClasses() {
|
|
|
5591
5639
|
|
|
5592
5640
|
function nearestClass(token) {
|
|
5593
5641
|
const { base } = splitVariants(token)
|
|
5594
|
-
const
|
|
5595
|
-
|
|
5642
|
+
const known = knownPublicClasses()
|
|
5643
|
+
// Flow's own version of a common class, e.g. `prose` -> `sf-prose`.
|
|
5644
|
+
if (known.includes(`sf-${base}`)) return `sf-${base}`
|
|
5645
|
+
const scored = [...siblingUtilities(base), ...known]
|
|
5596
5646
|
.map((candidate) => ({ candidate, score: levenshtein(base, candidate) }))
|
|
5597
5647
|
.sort((a, b) => a.score - b.score)
|
|
5598
|
-
|
|
5648
|
+
// Only near typos: a looser match often names a class that does something else.
|
|
5649
|
+
return scored[0]?.score <= Math.max(1, Math.floor(base.length / 5)) ? scored[0].candidate : null
|
|
5650
|
+
}
|
|
5651
|
+
|
|
5652
|
+
// The same utility with other keyword or spacing values, e.g. `h-scren` -> `h-screen`.
|
|
5653
|
+
function siblingUtilities(base) {
|
|
5654
|
+
const cut = base.lastIndexOf('-')
|
|
5655
|
+
if (cut <= 0) return []
|
|
5656
|
+
const prefix = base.slice(0, cut)
|
|
5657
|
+
const values = [...Object.keys(sizeKeywords), 'none', 'first', 'last', 'center', 'start', 'end', '0', 'px', '1', '2', '3', '4', '6', '8', '10', '12', '16', '24']
|
|
5658
|
+
return values
|
|
5659
|
+
.map((value) => `${prefix}-${value}`)
|
|
5660
|
+
.filter((candidate) => candidate !== base && declarationsFor(candidate))
|
|
5599
5661
|
}
|
|
5600
5662
|
|
|
5601
5663
|
function lintSourceFiles() {
|
|
@@ -602,16 +602,6 @@
|
|
|
602
602
|
}
|
|
603
603
|
}
|
|
604
604
|
|
|
605
|
-
:where(.space-y-1, .space-y-2, .space-y-3, .space-y-4, .space-y-5, .space-y-6, .space-y-8, .space-y-10, .space-y-12) > * + * {
|
|
606
|
-
margin-block-start: var(--sf-space-y);
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
:where(.space-x-1, .space-x-2, .space-x-3, .space-x-4, .space-x-5, .space-x-6, .space-x-8) > * + * {
|
|
610
|
-
margin-inline-start: var(--sf-space-x);
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
.divide-y > * + * { border-block-start-width: var(--sf-divide-y); }
|
|
614
|
-
.divide-x > * + * { border-inline-start-width: var(--sf-divide-x); }
|
|
615
605
|
}
|
|
616
606
|
|
|
617
607
|
@layer components {
|