rnwind 0.0.1 → 0.0.3
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/lib/cjs/core/parser/animation.cjs +427 -0
- package/lib/cjs/core/parser/animation.cjs.map +1 -0
- package/lib/cjs/core/parser/animation.d.ts +126 -0
- package/lib/cjs/core/parser/border-dispatcher.cjs +180 -0
- package/lib/cjs/core/parser/border-dispatcher.cjs.map +1 -0
- package/lib/cjs/core/parser/border-dispatcher.d.ts +15 -0
- package/lib/cjs/core/parser/case-convert.cjs +15 -0
- package/lib/cjs/core/parser/case-convert.cjs.map +1 -0
- package/lib/cjs/core/parser/case-convert.d.ts +6 -0
- package/lib/cjs/core/parser/color-properties-dispatcher.cjs +84 -0
- package/lib/cjs/core/parser/color-properties-dispatcher.cjs.map +1 -0
- package/lib/cjs/core/parser/color-properties-dispatcher.d.ts +19 -0
- package/lib/cjs/core/parser/color.cjs +193 -0
- package/lib/cjs/core/parser/color.cjs.map +1 -0
- package/lib/cjs/core/parser/color.d.ts +12 -0
- package/lib/cjs/core/parser/constants.cjs +21 -0
- package/lib/cjs/core/parser/constants.cjs.map +1 -0
- package/lib/cjs/core/parser/constants.d.ts +8 -0
- package/lib/cjs/core/parser/declaration.cjs +347 -0
- package/lib/cjs/core/parser/declaration.cjs.map +1 -0
- package/lib/cjs/core/parser/declaration.d.ts +15 -0
- package/lib/cjs/core/parser/gradient.cjs +132 -0
- package/lib/cjs/core/parser/gradient.cjs.map +1 -0
- package/lib/cjs/core/parser/gradient.d.ts +59 -0
- package/lib/cjs/core/parser/haptics.cjs +73 -0
- package/lib/cjs/core/parser/haptics.cjs.map +1 -0
- package/lib/cjs/core/parser/haptics.d.ts +47 -0
- package/lib/cjs/core/parser/index.d.ts +8 -0
- package/lib/cjs/core/parser/keyframes.cjs +95 -0
- package/lib/cjs/core/parser/keyframes.cjs.map +1 -0
- package/lib/cjs/core/parser/keyframes.d.ts +26 -0
- package/lib/cjs/core/parser/layout-dispatcher.cjs +120 -0
- package/lib/cjs/core/parser/layout-dispatcher.cjs.map +1 -0
- package/lib/cjs/core/parser/layout-dispatcher.d.ts +14 -0
- package/lib/cjs/core/parser/length.cjs +110 -0
- package/lib/cjs/core/parser/length.cjs.map +1 -0
- package/lib/cjs/core/parser/length.d.ts +51 -0
- package/lib/cjs/core/parser/motion-dispatcher.cjs +77 -0
- package/lib/cjs/core/parser/motion-dispatcher.cjs.map +1 -0
- package/lib/cjs/core/parser/motion-dispatcher.d.ts +11 -0
- package/lib/cjs/core/parser/property.cjs +22 -0
- package/lib/cjs/core/parser/property.cjs.map +1 -0
- package/lib/cjs/core/parser/property.d.ts +8 -0
- package/lib/cjs/core/parser/safe-area.cjs +404 -0
- package/lib/cjs/core/parser/safe-area.cjs.map +1 -0
- package/lib/cjs/core/parser/safe-area.d.ts +39 -0
- package/lib/cjs/core/parser/selector.cjs +22 -0
- package/lib/cjs/core/parser/selector.cjs.map +1 -0
- package/lib/cjs/core/parser/selector.d.ts +11 -0
- package/lib/cjs/core/parser/shorthand.cjs +188 -0
- package/lib/cjs/core/parser/shorthand.cjs.map +1 -0
- package/lib/cjs/core/parser/shorthand.d.ts +67 -0
- package/lib/cjs/core/parser/text-truncate.cjs +78 -0
- package/lib/cjs/core/parser/text-truncate.cjs.map +1 -0
- package/lib/cjs/core/parser/text-truncate.d.ts +44 -0
- package/lib/cjs/core/parser/theme-vars.cjs +467 -0
- package/lib/cjs/core/parser/theme-vars.cjs.map +1 -0
- package/lib/cjs/core/parser/theme-vars.d.ts +82 -0
- package/lib/cjs/core/parser/tokens.cjs +486 -0
- package/lib/cjs/core/parser/tokens.cjs.map +1 -0
- package/lib/cjs/core/parser/tokens.d.ts +45 -0
- package/lib/cjs/core/parser/transform.cjs +198 -0
- package/lib/cjs/core/parser/transform.cjs.map +1 -0
- package/lib/cjs/core/parser/transform.d.ts +36 -0
- package/lib/cjs/core/parser/tw-parser.cjs +1680 -0
- package/lib/cjs/core/parser/tw-parser.cjs.map +1 -0
- package/lib/cjs/core/parser/tw-parser.d.ts +210 -0
- package/lib/cjs/core/parser/types.d.ts +37 -0
- package/lib/cjs/core/parser/typography-dispatcher.cjs +108 -0
- package/lib/cjs/core/parser/typography-dispatcher.cjs.map +1 -0
- package/lib/cjs/core/parser/typography-dispatcher.d.ts +11 -0
- package/lib/cjs/core/parser/typography.cjs +97 -0
- package/lib/cjs/core/parser/typography.cjs.map +1 -0
- package/lib/cjs/core/parser/typography.d.ts +43 -0
- package/lib/cjs/core/style-builder/build-style.cjs +444 -0
- package/lib/cjs/core/style-builder/build-style.cjs.map +1 -0
- package/lib/cjs/core/style-builder/build-style.d.ts +54 -0
- package/lib/cjs/core/style-builder/index.d.ts +3 -0
- package/lib/cjs/core/style-builder/union-builder.cjs +326 -0
- package/lib/cjs/core/style-builder/union-builder.cjs.map +1 -0
- package/lib/cjs/core/style-builder/union-builder.d.ts +128 -0
- package/lib/cjs/core/types.d.ts +14 -0
- package/lib/cjs/metro/dts.cjs +127 -0
- package/lib/cjs/metro/dts.cjs.map +1 -0
- package/lib/cjs/metro/dts.d.ts +16 -0
- package/lib/cjs/metro/index.cjs +19 -0
- package/lib/cjs/metro/index.cjs.map +1 -0
- package/lib/cjs/metro/index.d.ts +9 -0
- package/lib/cjs/metro/resolver.cjs +47 -0
- package/lib/cjs/metro/resolver.cjs.map +1 -0
- package/lib/cjs/metro/resolver.d.ts +22 -0
- package/lib/cjs/metro/state.cjs +301 -0
- package/lib/cjs/metro/state.cjs.map +1 -0
- package/lib/cjs/metro/state.d.ts +88 -0
- package/lib/cjs/metro/transform-ast.cjs +1472 -0
- package/lib/cjs/metro/transform-ast.cjs.map +1 -0
- package/lib/cjs/metro/transform-ast.d.ts +88 -0
- package/lib/cjs/metro/transformer.cjs +372 -0
- package/lib/cjs/metro/transformer.cjs.map +1 -0
- package/lib/cjs/metro/transformer.d.ts +47 -0
- package/lib/cjs/metro/warn-unknown-classes.cjs +86 -0
- package/lib/cjs/metro/warn-unknown-classes.cjs.map +1 -0
- package/lib/cjs/metro/warn-unknown-classes.d.ts +21 -0
- package/lib/cjs/metro/with-config.cjs +196 -0
- package/lib/cjs/metro/with-config.cjs.map +1 -0
- package/lib/cjs/metro/with-config.d.ts +79 -0
- package/lib/cjs/runtime/chain-handlers.cjs +37 -0
- package/lib/cjs/runtime/chain-handlers.cjs.map +1 -0
- package/lib/cjs/runtime/chain-handlers.d.ts +33 -0
- package/lib/cjs/runtime/components/rnwind-provider.cjs +98 -0
- package/lib/cjs/runtime/components/rnwind-provider.cjs.map +1 -0
- package/lib/cjs/runtime/components/rnwind-provider.d.ts +84 -0
- package/lib/cjs/runtime/gradient-types.d.ts +58 -0
- package/lib/cjs/runtime/haptics.cjs +113 -0
- package/lib/cjs/runtime/haptics.cjs.map +1 -0
- package/lib/cjs/runtime/haptics.d.ts +48 -0
- package/lib/cjs/runtime/hooks/use-css.cjs +21 -0
- package/lib/cjs/runtime/hooks/use-css.cjs.map +1 -0
- package/lib/cjs/runtime/hooks/use-css.d.ts +11 -0
- package/lib/cjs/runtime/hooks/use-interact.cjs +46 -0
- package/lib/cjs/runtime/hooks/use-interact.cjs.map +1 -0
- package/lib/cjs/runtime/hooks/use-interact.d.ts +42 -0
- package/lib/cjs/runtime/hooks/use-scheme.cjs +68 -0
- package/lib/cjs/runtime/hooks/use-scheme.cjs.map +1 -0
- package/lib/cjs/runtime/hooks/use-scheme.d.ts +34 -0
- package/lib/cjs/runtime/index.cjs +45 -0
- package/lib/cjs/runtime/index.cjs.map +1 -0
- package/lib/cjs/runtime/index.d.ts +27 -0
- package/lib/cjs/runtime/interactive-box.cjs +35 -0
- package/lib/cjs/runtime/interactive-box.cjs.map +1 -0
- package/lib/cjs/runtime/interactive-box.d.ts +40 -0
- package/lib/cjs/runtime/lookup-css.cjs +542 -0
- package/lib/cjs/runtime/lookup-css.cjs.map +1 -0
- package/lib/cjs/runtime/lookup-css.d.ts +164 -0
- package/lib/cjs/runtime/types.d.ts +29 -0
- package/lib/cjs/testing/index.cjs +367 -0
- package/lib/cjs/testing/index.cjs.map +1 -0
- package/lib/cjs/testing/index.d.ts +145 -0
- package/lib/esm/core/parser/animation.d.ts +126 -0
- package/lib/esm/core/parser/animation.mjs +408 -0
- package/lib/esm/core/parser/animation.mjs.map +1 -0
- package/lib/esm/core/parser/border-dispatcher.d.ts +15 -0
- package/lib/esm/core/parser/border-dispatcher.mjs +178 -0
- package/lib/esm/core/parser/border-dispatcher.mjs.map +1 -0
- package/lib/esm/core/parser/case-convert.d.ts +6 -0
- package/lib/esm/core/parser/case-convert.mjs +13 -0
- package/lib/esm/core/parser/case-convert.mjs.map +1 -0
- package/lib/esm/core/parser/color-properties-dispatcher.d.ts +19 -0
- package/lib/esm/core/parser/color-properties-dispatcher.mjs +82 -0
- package/lib/esm/core/parser/color-properties-dispatcher.mjs.map +1 -0
- package/lib/esm/core/parser/color.d.ts +12 -0
- package/lib/esm/core/parser/color.mjs +191 -0
- package/lib/esm/core/parser/color.mjs.map +1 -0
- package/lib/esm/core/parser/constants.d.ts +8 -0
- package/lib/esm/core/parser/constants.mjs +13 -0
- package/lib/esm/core/parser/constants.mjs.map +1 -0
- package/lib/esm/core/parser/declaration.d.ts +15 -0
- package/lib/esm/core/parser/declaration.mjs +345 -0
- package/lib/esm/core/parser/declaration.mjs.map +1 -0
- package/lib/esm/core/parser/gradient.d.ts +59 -0
- package/lib/esm/core/parser/gradient.mjs +130 -0
- package/lib/esm/core/parser/gradient.mjs.map +1 -0
- package/lib/esm/core/parser/haptics.d.ts +47 -0
- package/lib/esm/core/parser/haptics.mjs +71 -0
- package/lib/esm/core/parser/haptics.mjs.map +1 -0
- package/lib/esm/core/parser/index.d.ts +8 -0
- package/lib/esm/core/parser/keyframes.d.ts +26 -0
- package/lib/esm/core/parser/keyframes.mjs +91 -0
- package/lib/esm/core/parser/keyframes.mjs.map +1 -0
- package/lib/esm/core/parser/layout-dispatcher.d.ts +14 -0
- package/lib/esm/core/parser/layout-dispatcher.mjs +118 -0
- package/lib/esm/core/parser/layout-dispatcher.mjs.map +1 -0
- package/lib/esm/core/parser/length.d.ts +51 -0
- package/lib/esm/core/parser/length.mjs +104 -0
- package/lib/esm/core/parser/length.mjs.map +1 -0
- package/lib/esm/core/parser/motion-dispatcher.d.ts +11 -0
- package/lib/esm/core/parser/motion-dispatcher.mjs +75 -0
- package/lib/esm/core/parser/motion-dispatcher.mjs.map +1 -0
- package/lib/esm/core/parser/property.d.ts +8 -0
- package/lib/esm/core/parser/property.mjs +20 -0
- package/lib/esm/core/parser/property.mjs.map +1 -0
- package/lib/esm/core/parser/safe-area.d.ts +39 -0
- package/lib/esm/core/parser/safe-area.mjs +402 -0
- package/lib/esm/core/parser/safe-area.mjs.map +1 -0
- package/lib/esm/core/parser/selector.d.ts +11 -0
- package/lib/esm/core/parser/selector.mjs +20 -0
- package/lib/esm/core/parser/selector.mjs.map +1 -0
- package/lib/esm/core/parser/shorthand.d.ts +67 -0
- package/lib/esm/core/parser/shorthand.mjs +180 -0
- package/lib/esm/core/parser/shorthand.mjs.map +1 -0
- package/lib/esm/core/parser/text-truncate.d.ts +44 -0
- package/lib/esm/core/parser/text-truncate.mjs +75 -0
- package/lib/esm/core/parser/text-truncate.mjs.map +1 -0
- package/lib/esm/core/parser/theme-vars.d.ts +82 -0
- package/lib/esm/core/parser/theme-vars.mjs +461 -0
- package/lib/esm/core/parser/theme-vars.mjs.map +1 -0
- package/lib/esm/core/parser/tokens.d.ts +45 -0
- package/lib/esm/core/parser/tokens.mjs +480 -0
- package/lib/esm/core/parser/tokens.mjs.map +1 -0
- package/lib/esm/core/parser/transform.d.ts +36 -0
- package/lib/esm/core/parser/transform.mjs +193 -0
- package/lib/esm/core/parser/transform.mjs.map +1 -0
- package/lib/esm/core/parser/tw-parser.d.ts +210 -0
- package/lib/esm/core/parser/tw-parser.mjs +1678 -0
- package/lib/esm/core/parser/tw-parser.mjs.map +1 -0
- package/lib/esm/core/parser/types.d.ts +37 -0
- package/lib/esm/core/parser/typography-dispatcher.d.ts +11 -0
- package/lib/esm/core/parser/typography-dispatcher.mjs +106 -0
- package/lib/esm/core/parser/typography-dispatcher.mjs.map +1 -0
- package/lib/esm/core/parser/typography.d.ts +43 -0
- package/lib/esm/core/parser/typography.mjs +91 -0
- package/lib/esm/core/parser/typography.mjs.map +1 -0
- package/lib/esm/core/style-builder/build-style.d.ts +54 -0
- package/lib/esm/core/style-builder/build-style.mjs +442 -0
- package/lib/esm/core/style-builder/build-style.mjs.map +1 -0
- package/lib/esm/core/style-builder/index.d.ts +3 -0
- package/lib/esm/core/style-builder/union-builder.d.ts +128 -0
- package/lib/esm/core/style-builder/union-builder.mjs +324 -0
- package/lib/esm/core/style-builder/union-builder.mjs.map +1 -0
- package/lib/esm/core/types.d.ts +14 -0
- package/lib/esm/metro/dts.d.ts +16 -0
- package/lib/esm/metro/dts.mjs +125 -0
- package/lib/esm/metro/dts.mjs.map +1 -0
- package/lib/esm/metro/index.d.ts +9 -0
- package/lib/esm/metro/index.mjs +6 -0
- package/lib/esm/metro/index.mjs.map +1 -0
- package/lib/esm/metro/resolver.d.ts +22 -0
- package/lib/esm/metro/resolver.mjs +43 -0
- package/lib/esm/metro/resolver.mjs.map +1 -0
- package/lib/esm/metro/state.d.ts +88 -0
- package/lib/esm/metro/state.mjs +291 -0
- package/lib/esm/metro/state.mjs.map +1 -0
- package/lib/esm/metro/transform-ast.d.ts +88 -0
- package/lib/esm/metro/transform-ast.mjs +1451 -0
- package/lib/esm/metro/transform-ast.mjs.map +1 -0
- package/lib/esm/metro/transformer.d.ts +47 -0
- package/lib/esm/metro/transformer.mjs +349 -0
- package/lib/esm/metro/transformer.mjs.map +1 -0
- package/lib/esm/metro/warn-unknown-classes.d.ts +21 -0
- package/lib/esm/metro/warn-unknown-classes.mjs +84 -0
- package/lib/esm/metro/warn-unknown-classes.mjs.map +1 -0
- package/lib/esm/metro/with-config.d.ts +79 -0
- package/lib/esm/metro/with-config.mjs +194 -0
- package/lib/esm/metro/with-config.mjs.map +1 -0
- package/lib/esm/runtime/chain-handlers.d.ts +33 -0
- package/lib/esm/runtime/chain-handlers.mjs +34 -0
- package/lib/esm/runtime/chain-handlers.mjs.map +1 -0
- package/lib/esm/runtime/components/rnwind-provider.d.ts +84 -0
- package/lib/esm/runtime/components/rnwind-provider.mjs +94 -0
- package/lib/esm/runtime/components/rnwind-provider.mjs.map +1 -0
- package/lib/esm/runtime/gradient-types.d.ts +58 -0
- package/lib/esm/runtime/haptics.d.ts +48 -0
- package/lib/esm/runtime/haptics.mjs +110 -0
- package/lib/esm/runtime/haptics.mjs.map +1 -0
- package/lib/esm/runtime/hooks/use-css.d.ts +11 -0
- package/lib/esm/runtime/hooks/use-css.mjs +19 -0
- package/lib/esm/runtime/hooks/use-css.mjs.map +1 -0
- package/lib/esm/runtime/hooks/use-interact.d.ts +42 -0
- package/lib/esm/runtime/hooks/use-interact.mjs +44 -0
- package/lib/esm/runtime/hooks/use-interact.mjs.map +1 -0
- package/lib/esm/runtime/hooks/use-scheme.d.ts +34 -0
- package/lib/esm/runtime/hooks/use-scheme.mjs +63 -0
- package/lib/esm/runtime/hooks/use-scheme.mjs.map +1 -0
- package/lib/esm/runtime/index.d.ts +27 -0
- package/lib/esm/runtime/index.mjs +18 -0
- package/lib/esm/runtime/index.mjs.map +1 -0
- package/lib/esm/runtime/interactive-box.d.ts +40 -0
- package/lib/esm/runtime/interactive-box.mjs +33 -0
- package/lib/esm/runtime/interactive-box.mjs.map +1 -0
- package/lib/esm/runtime/lookup-css.d.ts +164 -0
- package/lib/esm/runtime/lookup-css.mjs +531 -0
- package/lib/esm/runtime/lookup-css.mjs.map +1 -0
- package/lib/esm/runtime/types.d.ts +29 -0
- package/lib/esm/testing/index.d.ts +145 -0
- package/lib/esm/testing/index.mjs +344 -0
- package/lib/esm/testing/index.mjs.map +1 -0
- package/package.json +80 -13
- package/preset.css +1171 -0
- package/src/core/parser/animation.ts +404 -0
- package/src/core/parser/border-dispatcher.ts +176 -0
- package/src/core/parser/case-convert.ts +10 -0
- package/src/core/parser/color-properties-dispatcher.ts +78 -0
- package/src/core/parser/color.ts +191 -0
- package/src/core/parser/constants.ts +11 -0
- package/src/core/parser/declaration.ts +340 -0
- package/src/core/parser/gradient.ts +148 -0
- package/src/core/parser/haptics.ts +88 -0
- package/src/core/parser/index.ts +8 -0
- package/src/core/parser/keyframes.ts +84 -0
- package/src/core/parser/layout-dispatcher.ts +111 -0
- package/src/core/parser/length.ts +114 -0
- package/src/core/parser/motion-dispatcher.ts +89 -0
- package/src/core/parser/property.ts +15 -0
- package/src/core/parser/safe-area.ts +404 -0
- package/src/core/parser/selector.ts +17 -0
- package/src/core/parser/shorthand.ts +182 -0
- package/src/core/parser/text-truncate.ts +79 -0
- package/src/core/parser/theme-vars.ts +465 -0
- package/src/core/parser/tokens.ts +456 -0
- package/src/core/parser/transform.ts +195 -0
- package/src/core/parser/tw-parser.ts +1828 -0
- package/src/core/parser/types.ts +45 -0
- package/src/core/parser/typography-dispatcher.ts +97 -0
- package/src/core/parser/typography.ts +83 -0
- package/src/core/style-builder/build-style.ts +500 -0
- package/src/core/style-builder/index.ts +3 -0
- package/src/core/style-builder/union-builder.ts +328 -0
- package/src/core/types.ts +15 -0
- package/src/metro/dts.ts +128 -0
- package/src/metro/index.ts +9 -0
- package/src/metro/resolver.ts +42 -0
- package/src/metro/state.ts +305 -0
- package/src/metro/transform-ast.ts +1729 -0
- package/src/metro/transformer.ts +372 -0
- package/src/metro/warn-unknown-classes.ts +79 -0
- package/src/metro/with-config.ts +251 -0
- package/src/runtime/chain-handlers.ts +47 -0
- package/src/runtime/components/rnwind-provider.tsx +144 -0
- package/src/runtime/gradient-types.ts +60 -0
- package/src/runtime/haptics.ts +120 -0
- package/src/runtime/hooks/use-css.ts +16 -0
- package/src/runtime/hooks/use-interact.ts +65 -0
- package/src/runtime/hooks/use-scheme.ts +63 -0
- package/src/runtime/index.ts +54 -0
- package/src/runtime/interactive-box.tsx +57 -0
- package/src/runtime/lookup-css.ts +628 -0
- package/src/runtime/types.ts +32 -0
- package/src/testing/index.ts +507 -0
- package/src/types/tailwindcss-node.d.ts +33 -0
- package/src/index.ts +0 -1
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Animation,
|
|
3
|
+
AnimationDirection,
|
|
4
|
+
AnimationFillMode,
|
|
5
|
+
AnimationIterationCount,
|
|
6
|
+
AnimationName,
|
|
7
|
+
AnimationPlayState,
|
|
8
|
+
EasingFunction,
|
|
9
|
+
PropertyId,
|
|
10
|
+
Time,
|
|
11
|
+
Transition,
|
|
12
|
+
} from 'lightningcss'
|
|
13
|
+
import { kebabToCamel } from './case-convert'
|
|
14
|
+
import type { RNEntry } from './types'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Convert one PropertyId ident into the camelCase RN style key
|
|
18
|
+
* Reanimated v4's CSS engine matches against. Tailwind emits CSS names
|
|
19
|
+
* in kebab-case (`background-color`); RN stores `backgroundColor` in
|
|
20
|
+
* the actual style object, and Reanimated only fires a transition when
|
|
21
|
+
* the watched key matches the changed key — so kebab-case here would
|
|
22
|
+
* silently no-op every multi-word color/border transition.
|
|
23
|
+
*
|
|
24
|
+
* Special cases:
|
|
25
|
+
* - `'all'` passes through unchanged.
|
|
26
|
+
* - `--tw-*` Tailwind internal custom props are dropped — they have
|
|
27
|
+
* no RN equivalent and Reanimated can't watch them.
|
|
28
|
+
* - Other `--user-defined` custom props pass through verbatim.
|
|
29
|
+
* @param property Typed property identifier.
|
|
30
|
+
* @returns RN-style key, or null when the property has no RN equivalent.
|
|
31
|
+
*/
|
|
32
|
+
function propertyIdToString(property: PropertyId): string | null {
|
|
33
|
+
// Custom properties surface in two shapes: either as `{property:
|
|
34
|
+
// 'custom', value: {name: '--x'}}` or — when lightningcss recognises
|
|
35
|
+
// the leading `--` directly in propertyId — as `{property: '--x'}`.
|
|
36
|
+
// Handle both, drop Tailwind internals, keep user customs verbatim.
|
|
37
|
+
if (property.property === 'custom' && 'value' in property) {
|
|
38
|
+
const { value } = property
|
|
39
|
+
const customName = value && typeof value === 'object' && 'name' in value && typeof value.name === 'string' ? value.name : null
|
|
40
|
+
if (!customName) return null
|
|
41
|
+
return customName.startsWith('--tw-') ? null : customName
|
|
42
|
+
}
|
|
43
|
+
if (typeof property.property === 'string' && property.property.startsWith('--')) {
|
|
44
|
+
return property.property.startsWith('--tw-') ? null : property.property
|
|
45
|
+
}
|
|
46
|
+
if (property.property === 'all') return 'all'
|
|
47
|
+
return kebabToCamel(property.property)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Collapse a single-element list into its scalar, otherwise return the
|
|
52
|
+
* list unchanged. Reanimated accepts both forms; the scalar is the
|
|
53
|
+
* common case.
|
|
54
|
+
* @param values Values to collapse.
|
|
55
|
+
* @returns A scalar when the list has one element, otherwise the list.
|
|
56
|
+
*/
|
|
57
|
+
function singleOrArray<T>(values: readonly T[]): T | readonly T[] {
|
|
58
|
+
if (values.length === 1) return values[0]!
|
|
59
|
+
return values
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Render a number without trailing noise (strips IEEE drift beyond 4
|
|
64
|
+
* decimals, then removes trailing zeros).
|
|
65
|
+
* @param value Number to format.
|
|
66
|
+
* @returns Compact string form.
|
|
67
|
+
*/
|
|
68
|
+
function formatNumber(value: number): string {
|
|
69
|
+
const rounded = Math.round(value * 10_000) / 10_000
|
|
70
|
+
return String(rounded)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Reanimated v4's CSS engine doesn't accept `cubic-bezier(...)` as a
|
|
75
|
+
* string — only the predefined keywords `linear`, `ease`, `ease-in`,
|
|
76
|
+
* `ease-out`, `ease-in-out`, `step-start`, `step-end`. Tailwind's
|
|
77
|
+
* `transition-colors` / `ease-in-out` / etc. emit the CSS-standard
|
|
78
|
+
* Material curves as cubic-bezier; we snap those to the closest
|
|
79
|
+
* predefined keyword by matching the well-known control-point shapes,
|
|
80
|
+
* falling back to `ease-in-out` (the most common Tailwind default).
|
|
81
|
+
*
|
|
82
|
+
* Direct matches:
|
|
83
|
+
* - `cubic-bezier(0.25, 0.1, 0.25, 1)` → `ease` (CSS spec default)
|
|
84
|
+
* - `cubic-bezier(0.4, 0, 1, 1)` → `ease-in`
|
|
85
|
+
* - `cubic-bezier(0, 0, 0.2, 1)` → `ease-out`
|
|
86
|
+
* - `cubic-bezier(0.4, 0, 0.2, 1)` → `ease-in-out` (Material standard)
|
|
87
|
+
* - linear shape (`x1=y1=0, x2=y2=1`) → `linear`
|
|
88
|
+
*
|
|
89
|
+
* Anything else: classify by control-point shape — front-loaded curves
|
|
90
|
+
* → `ease-in`, back-loaded → `ease-out`, both → `ease-in-out`.
|
|
91
|
+
* @param x1 First control-point x (0–1).
|
|
92
|
+
* @param y1 First control-point y (0–1).
|
|
93
|
+
* @param x2 Second control-point x (0–1).
|
|
94
|
+
* @param y2 Second control-point y (0–1).
|
|
95
|
+
* @returns Closest matching CSS easing keyword.
|
|
96
|
+
*/
|
|
97
|
+
function snapCubicBezierToKeyword(x1: number, y1: number, x2: number, y2: number): string {
|
|
98
|
+
if (matchesBezier(x1, y1, x2, y2, 0, 0, 1, 1)) return 'linear'
|
|
99
|
+
if (matchesBezier(x1, y1, x2, y2, 0.25, 0.1, 0.25, 1)) return 'ease'
|
|
100
|
+
if (matchesBezier(x1, y1, x2, y2, 0.4, 0, 1, 1)) return 'ease-in'
|
|
101
|
+
if (matchesBezier(x1, y1, x2, y2, 0, 0, 0.2, 1)) return 'ease-out'
|
|
102
|
+
if (matchesBezier(x1, y1, x2, y2, 0.4, 0, 0.2, 1)) return 'ease-in-out'
|
|
103
|
+
// Heuristic for unknown bezier shapes:
|
|
104
|
+
// - x1 ≈ 0 → starts straight (decelerates) → ease-out
|
|
105
|
+
// - x2 ≈ 1 → ends straight (accelerates) → ease-in
|
|
106
|
+
// - both small, both medium → ease-in-out
|
|
107
|
+
const startsFlat = x1 < 0.1
|
|
108
|
+
const endsFlat = x2 > 0.9
|
|
109
|
+
if (startsFlat && !endsFlat) return 'ease-out'
|
|
110
|
+
if (!startsFlat && endsFlat) return 'ease-in'
|
|
111
|
+
return 'ease-in-out'
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Approximate equality of two cubic-bezier control-point sets — IEEE
|
|
116
|
+
* float noise from lightningcss / culori means literal `===` rarely
|
|
117
|
+
* holds, so we tolerate a tiny epsilon.
|
|
118
|
+
* @param ax1 Actual first x.
|
|
119
|
+
* @param ay1 Actual first y.
|
|
120
|
+
* @param ax2 Actual second x.
|
|
121
|
+
* @param ay2 Actual second y.
|
|
122
|
+
* @param tx1 Target first x.
|
|
123
|
+
* @param ty1 Target first y.
|
|
124
|
+
* @param tx2 Target second x.
|
|
125
|
+
* @param ty2 Target second y.
|
|
126
|
+
* @returns Whether the two beziers are component-wise within 0.01 of each other.
|
|
127
|
+
*/
|
|
128
|
+
function matchesBezier(
|
|
129
|
+
ax1: number,
|
|
130
|
+
ay1: number,
|
|
131
|
+
ax2: number,
|
|
132
|
+
ay2: number,
|
|
133
|
+
tx1: number,
|
|
134
|
+
ty1: number,
|
|
135
|
+
tx2: number,
|
|
136
|
+
ty2: number,
|
|
137
|
+
): boolean {
|
|
138
|
+
const tolerance = 0.01
|
|
139
|
+
return (
|
|
140
|
+
Math.abs(ax1 - tx1) < tolerance &&
|
|
141
|
+
Math.abs(ay1 - ty1) < tolerance &&
|
|
142
|
+
Math.abs(ax2 - tx2) < tolerance &&
|
|
143
|
+
Math.abs(ay2 - ty2) < tolerance
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Serialize a lightningcss `EasingFunction` into a CSS string Reanimated
|
|
149
|
+
* v4's CSS engine understands. Reanimated accepts the same timing-function
|
|
150
|
+
* strings as CSS transitions/animations, so we emit the canonical CSS
|
|
151
|
+
* form.
|
|
152
|
+
* @param fn Typed easing function.
|
|
153
|
+
* @returns CSS string, e.g. `'linear'` / `'ease-in-out'` / `'cubic-bezier(0.4, 0, 0.2, 1)'`.
|
|
154
|
+
*/
|
|
155
|
+
export function easingFunctionToString(fn: EasingFunction): string {
|
|
156
|
+
switch (fn.type) {
|
|
157
|
+
case 'linear': {
|
|
158
|
+
return 'linear'
|
|
159
|
+
}
|
|
160
|
+
case 'ease':
|
|
161
|
+
case 'ease-in':
|
|
162
|
+
case 'ease-out':
|
|
163
|
+
case 'ease-in-out': {
|
|
164
|
+
return fn.type
|
|
165
|
+
}
|
|
166
|
+
case 'cubic-bezier': {
|
|
167
|
+
return snapCubicBezierToKeyword(fn.x1, fn.y1, fn.x2, fn.y2)
|
|
168
|
+
}
|
|
169
|
+
case 'steps': {
|
|
170
|
+
const pos = fn.position?.type ?? 'end'
|
|
171
|
+
return `steps(${fn.count}, ${pos})`
|
|
172
|
+
}
|
|
173
|
+
default: {
|
|
174
|
+
return 'ease'
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Format a `Time` value into a CSS string (`150ms`, `1s`). Reanimated's
|
|
181
|
+
* CSS engine accepts either `ms` or `s`; we pick `ms` unless the value
|
|
182
|
+
* is a whole-second multiple for readability.
|
|
183
|
+
* @param time Typed time value.
|
|
184
|
+
* @returns CSS time string.
|
|
185
|
+
*/
|
|
186
|
+
export function timeToString(time: Time): string {
|
|
187
|
+
if (time.type === 'milliseconds') return `${formatNumber(time.value)}ms`
|
|
188
|
+
return `${formatNumber(time.value)}s`
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Convert a single `animation-name` value to a string. Tailwind's
|
|
193
|
+
* `animate-none` produces `{ type: 'none' }` which we drop.
|
|
194
|
+
* @param name Typed animation name.
|
|
195
|
+
* @returns Keyframe identifier, or null when `none`.
|
|
196
|
+
*/
|
|
197
|
+
export function animationNameToString(name: AnimationName): string | null {
|
|
198
|
+
if (name.type === 'none') return null
|
|
199
|
+
if (name.type === 'ident') return name.value
|
|
200
|
+
if (name.type === 'string') return name.value
|
|
201
|
+
return null
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Convert a single `animation-iteration-count` value to the CSS shape
|
|
206
|
+
* Reanimated wants: either a finite integer or the `'infinite'` string.
|
|
207
|
+
* @param count Typed iteration count.
|
|
208
|
+
* @returns Number or `'infinite'`.
|
|
209
|
+
*/
|
|
210
|
+
export function iterationCountToValue(count: AnimationIterationCount): number | string {
|
|
211
|
+
if (count.type === 'infinite') return 'infinite'
|
|
212
|
+
return count.value
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Decompose the `animation: <name> <duration> <timing> <iteration> …`
|
|
217
|
+
* shorthand into the per-property RN entries Reanimated consumes. A single
|
|
218
|
+
* `animation` declaration can name multiple animations — we emit the first
|
|
219
|
+
* one (Tailwind's `animate-*` utilities always emit exactly one).
|
|
220
|
+
* @param animations Parsed animation list from lightningcss.
|
|
221
|
+
* @returns RN entries, empty when the shorthand names `none`.
|
|
222
|
+
*/
|
|
223
|
+
export function animationShorthandToEntries(animations: readonly Animation[]): readonly RNEntry[] {
|
|
224
|
+
const [first] = animations
|
|
225
|
+
if (!first) return []
|
|
226
|
+
const name = animationNameToString(first.name)
|
|
227
|
+
if (!name) return []
|
|
228
|
+
const entries: RNEntry[] = [['animationName', name]]
|
|
229
|
+
if (first.duration) entries.push(['animationDuration', timeToString(first.duration)])
|
|
230
|
+
if (first.timingFunction) entries.push(['animationTimingFunction', easingFunctionToString(first.timingFunction)])
|
|
231
|
+
if (first.iterationCount) entries.push(['animationIterationCount', iterationCountToValue(first.iterationCount)])
|
|
232
|
+
if (first.direction && first.direction !== 'normal') entries.push(['animationDirection', first.direction])
|
|
233
|
+
if (first.fillMode && first.fillMode !== 'none') entries.push(['animationFillMode', first.fillMode])
|
|
234
|
+
if (first.delay && first.delay.value !== 0) entries.push(['animationDelay', timeToString(first.delay)])
|
|
235
|
+
if (first.playState && first.playState !== 'running') entries.push(['animationPlayState', first.playState])
|
|
236
|
+
return entries
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Emit `animationName` for a standalone `animation-name: spin` declaration.
|
|
241
|
+
* @param names Typed `animation-name` list.
|
|
242
|
+
* @returns Single-entry `animationName` or empty when `none`.
|
|
243
|
+
*/
|
|
244
|
+
export function animationNameEntries(names: readonly AnimationName[]): readonly RNEntry[] {
|
|
245
|
+
const [first] = names
|
|
246
|
+
if (!first) return []
|
|
247
|
+
const name = animationNameToString(first)
|
|
248
|
+
if (!name) return []
|
|
249
|
+
return [['animationName', name]]
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Emit `animationDuration` for a standalone `animation-duration` declaration.
|
|
254
|
+
* @param durations Typed duration list.
|
|
255
|
+
* @returns Single-entry list.
|
|
256
|
+
*/
|
|
257
|
+
export function animationDurationEntries(durations: readonly Time[]): readonly RNEntry[] {
|
|
258
|
+
const [first] = durations
|
|
259
|
+
if (!first) return []
|
|
260
|
+
return [['animationDuration', timeToString(first)]]
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Emit `animationTimingFunction` for a standalone `animation-timing-function`.
|
|
265
|
+
* @param fns Typed timing-function list.
|
|
266
|
+
* @returns Single-entry list.
|
|
267
|
+
*/
|
|
268
|
+
export function animationTimingFunctionEntries(fns: readonly EasingFunction[]): readonly RNEntry[] {
|
|
269
|
+
const [first] = fns
|
|
270
|
+
if (!first) return []
|
|
271
|
+
return [['animationTimingFunction', easingFunctionToString(first)]]
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Emit `animationIterationCount` for a standalone declaration.
|
|
276
|
+
* @param counts Typed iteration-count list.
|
|
277
|
+
* @returns Single-entry list.
|
|
278
|
+
*/
|
|
279
|
+
export function animationIterationCountEntries(counts: readonly AnimationIterationCount[]): readonly RNEntry[] {
|
|
280
|
+
const [first] = counts
|
|
281
|
+
if (!first) return []
|
|
282
|
+
return [['animationIterationCount', iterationCountToValue(first)]]
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Emit `animationDelay` for a standalone declaration.
|
|
287
|
+
* @param delays Typed delay list.
|
|
288
|
+
* @returns Single-entry list.
|
|
289
|
+
*/
|
|
290
|
+
export function animationDelayEntries(delays: readonly Time[]): readonly RNEntry[] {
|
|
291
|
+
const [first] = delays
|
|
292
|
+
if (!first) return []
|
|
293
|
+
return [['animationDelay', timeToString(first)]]
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Emit `animationDirection` for a standalone declaration.
|
|
298
|
+
* @param directions Typed direction list.
|
|
299
|
+
* @returns Single-entry list.
|
|
300
|
+
*/
|
|
301
|
+
export function animationDirectionEntries(directions: readonly AnimationDirection[]): readonly RNEntry[] {
|
|
302
|
+
const [first] = directions
|
|
303
|
+
if (!first) return []
|
|
304
|
+
return [['animationDirection', first]]
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Emit `animationFillMode` for a standalone declaration.
|
|
309
|
+
* @param modes Typed fill-mode list.
|
|
310
|
+
* @returns Single-entry list.
|
|
311
|
+
*/
|
|
312
|
+
export function animationFillModeEntries(modes: readonly AnimationFillMode[]): readonly RNEntry[] {
|
|
313
|
+
const [first] = modes
|
|
314
|
+
if (!first) return []
|
|
315
|
+
return [['animationFillMode', first]]
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Emit `animationPlayState` for a standalone declaration.
|
|
320
|
+
* @param states Typed play-state list.
|
|
321
|
+
* @returns Single-entry list.
|
|
322
|
+
*/
|
|
323
|
+
export function animationPlayStateEntries(states: readonly AnimationPlayState[]): readonly RNEntry[] {
|
|
324
|
+
const [first] = states
|
|
325
|
+
if (!first) return []
|
|
326
|
+
return [['animationPlayState', first]]
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Convert the `transition-property` list into an RN-consumable form.
|
|
331
|
+
* Reanimated accepts either a string (`'all'`, `'opacity'`) or an array
|
|
332
|
+
* of property names. We emit the array shape even for singletons so the
|
|
333
|
+
* runtime can handle it uniformly.
|
|
334
|
+
* @param properties Typed transition-property list.
|
|
335
|
+
* @returns Single-entry list with `transitionProperty`.
|
|
336
|
+
*/
|
|
337
|
+
export function transitionPropertyEntries(properties: readonly PropertyId[]): readonly RNEntry[] {
|
|
338
|
+
const names = properties.map((p) => propertyIdToString(p)).filter((name): name is string => name !== null)
|
|
339
|
+
if (names.length === 0) return []
|
|
340
|
+
if (names.length === 1) return [['transitionProperty', names[0]!]]
|
|
341
|
+
return [['transitionProperty', names]]
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Decompose the `transition: <prop> <duration> <timing> <delay>` shorthand
|
|
346
|
+
* into the per-property RN entries Reanimated consumes. A declaration can
|
|
347
|
+
* name multiple transitions; we emit one entry per slot, collapsing
|
|
348
|
+
* identical slots into a scalar.
|
|
349
|
+
* @param transitions Parsed transition list from lightningcss.
|
|
350
|
+
* @returns RN entries — zero or more.
|
|
351
|
+
*/
|
|
352
|
+
export function transitionShorthandToEntries(transitions: readonly Transition[]): readonly RNEntry[] {
|
|
353
|
+
if (transitions.length === 0) return []
|
|
354
|
+
const properties: string[] = []
|
|
355
|
+
const durations: string[] = []
|
|
356
|
+
const timings: string[] = []
|
|
357
|
+
const delays: string[] = []
|
|
358
|
+
for (const t of transitions) {
|
|
359
|
+
const name = propertyIdToString(t.property)
|
|
360
|
+
if (name) properties.push(name)
|
|
361
|
+
if (t.duration) durations.push(timeToString(t.duration))
|
|
362
|
+
if (t.timingFunction) timings.push(easingFunctionToString(t.timingFunction))
|
|
363
|
+
if (t.delay) delays.push(timeToString(t.delay))
|
|
364
|
+
}
|
|
365
|
+
const entries: RNEntry[] = []
|
|
366
|
+
if (properties.length > 0) entries.push(['transitionProperty', singleOrArray(properties)])
|
|
367
|
+
if (durations.length > 0) entries.push(['transitionDuration', singleOrArray(durations)])
|
|
368
|
+
if (timings.length > 0) entries.push(['transitionTimingFunction', singleOrArray(timings)])
|
|
369
|
+
if (delays.some((d) => d !== '0s')) entries.push(['transitionDelay', singleOrArray(delays)])
|
|
370
|
+
return entries
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Emit `transitionDuration` for a standalone declaration.
|
|
375
|
+
* @param durations Typed duration list.
|
|
376
|
+
* @returns Single-entry list.
|
|
377
|
+
*/
|
|
378
|
+
export function transitionDurationEntries(durations: readonly Time[]): readonly RNEntry[] {
|
|
379
|
+
if (durations.length === 0) return []
|
|
380
|
+
const strings = durations.map((d) => timeToString(d))
|
|
381
|
+
return [['transitionDuration', singleOrArray(strings)]]
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Emit `transitionTimingFunction` for a standalone declaration.
|
|
386
|
+
* @param fns Typed timing-function list.
|
|
387
|
+
* @returns Single-entry list.
|
|
388
|
+
*/
|
|
389
|
+
export function transitionTimingFunctionEntries(fns: readonly EasingFunction[]): readonly RNEntry[] {
|
|
390
|
+
if (fns.length === 0) return []
|
|
391
|
+
const strings = fns.map((f) => easingFunctionToString(f))
|
|
392
|
+
return [['transitionTimingFunction', singleOrArray(strings)]]
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Emit `transitionDelay` for a standalone declaration.
|
|
397
|
+
* @param delays Typed delay list.
|
|
398
|
+
* @returns Single-entry list.
|
|
399
|
+
*/
|
|
400
|
+
export function transitionDelayEntries(delays: readonly Time[]): readonly RNEntry[] {
|
|
401
|
+
if (delays.length === 0) return []
|
|
402
|
+
const strings = delays.map((d) => timeToString(d))
|
|
403
|
+
return [['transitionDelay', singleOrArray(strings)]]
|
|
404
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import type { Declaration as LcDeclaration } from 'lightningcss'
|
|
2
|
+
import { kebabToCamel } from './case-convert'
|
|
3
|
+
import { cssColorToString } from './color'
|
|
4
|
+
import type { RNEntry } from './types'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Build an inline-color pair from a `{start, end}`-shaped value.
|
|
8
|
+
* @param leftKey RN key for the start side.
|
|
9
|
+
* @param rightKey RN key for the end side.
|
|
10
|
+
* @param value Typed `{start, end}` color value.
|
|
11
|
+
* @returns Two RN entries.
|
|
12
|
+
*/
|
|
13
|
+
function colorPair(leftKey: string, rightKey: string, value: unknown): readonly RNEntry[] {
|
|
14
|
+
const tagged = value as { start?: unknown; end?: unknown }
|
|
15
|
+
return [
|
|
16
|
+
[leftKey, cssColorToString(tagged.start as never)],
|
|
17
|
+
[rightKey, cssColorToString(tagged.end as never)],
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Coerce a border-width-shaped length to a pixel number. Drops
|
|
23
|
+
* percentages — RN borders don't accept them.
|
|
24
|
+
* @param value Typed length value (`{type: 'length', value: {unit, value}}`).
|
|
25
|
+
* @returns Pixel number, or null when unrepresentable.
|
|
26
|
+
*/
|
|
27
|
+
function lengthToPxValue(value: unknown): number | null {
|
|
28
|
+
if (typeof value !== 'object' || value === null) return null
|
|
29
|
+
const tagged = value as {
|
|
30
|
+
type?: string
|
|
31
|
+
value?: { type?: string; value?: { unit?: string; value?: number } } | { unit?: string; value?: number }
|
|
32
|
+
}
|
|
33
|
+
const inner =
|
|
34
|
+
tagged.type === 'length'
|
|
35
|
+
? (tagged.value as { type?: string; value?: { unit?: string; value?: number } })?.value
|
|
36
|
+
: tagged.value
|
|
37
|
+
if (!inner || typeof (inner as { value?: number }).value !== 'number') return null
|
|
38
|
+
const dim = inner as { unit?: string; value: number }
|
|
39
|
+
if (dim.unit === 'px') return dim.value
|
|
40
|
+
if (dim.unit === 'rem' || dim.unit === 'em') return dim.value * 16
|
|
41
|
+
return dim.value
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Build an inline-width pair from a `{start, end}`-shaped value.
|
|
46
|
+
* @param leftKey RN key for the start side.
|
|
47
|
+
* @param rightKey RN key for the end side.
|
|
48
|
+
* @param value Typed `{start, end}` length value.
|
|
49
|
+
* @returns Two RN entries, or empty when either side is unrepresentable.
|
|
50
|
+
*/
|
|
51
|
+
function widthPair(leftKey: string, rightKey: string, value: unknown): readonly RNEntry[] {
|
|
52
|
+
const tagged = value as { start?: unknown; end?: unknown }
|
|
53
|
+
const start = lengthToPxValue(tagged.start)
|
|
54
|
+
const end = lengthToPxValue(tagged.end)
|
|
55
|
+
if (start === null || end === null) return []
|
|
56
|
+
return [
|
|
57
|
+
[leftKey, start],
|
|
58
|
+
[rightKey, end],
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Expand a `border-width` shorthand to RN longhands. Collapses to the
|
|
64
|
+
* `borderWidth` shorthand when all four sides match.
|
|
65
|
+
* @param value Typed border-width value with `{top, right, bottom, left}`.
|
|
66
|
+
* @returns RN entries.
|
|
67
|
+
*/
|
|
68
|
+
function borderWidthShorthand(value: unknown): readonly RNEntry[] {
|
|
69
|
+
const tagged = value as { top?: unknown; right?: unknown; bottom?: unknown; left?: unknown }
|
|
70
|
+
const top = lengthToPxValue(tagged.top)
|
|
71
|
+
const right = lengthToPxValue(tagged.right)
|
|
72
|
+
const bottom = lengthToPxValue(tagged.bottom)
|
|
73
|
+
const left = lengthToPxValue(tagged.left)
|
|
74
|
+
if (top === null || right === null || bottom === null || left === null) return []
|
|
75
|
+
if (top === right && right === bottom && bottom === left) return [['borderWidth', top]]
|
|
76
|
+
return [
|
|
77
|
+
['borderTopWidth', top],
|
|
78
|
+
['borderRightWidth', right],
|
|
79
|
+
['borderBottomWidth', bottom],
|
|
80
|
+
['borderLeftWidth', left],
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Map CSS `border-style` keywords to the strings RN accepts. RN
|
|
86
|
+
* supports only `solid` / `dashed` / `dotted` / `none` — fall back to
|
|
87
|
+
* `solid` for everything else.
|
|
88
|
+
* @param css CSS border-style keyword.
|
|
89
|
+
* @returns RN border-style.
|
|
90
|
+
*/
|
|
91
|
+
function mapBorderStyle(css: string): string {
|
|
92
|
+
if (css === 'dashed' || css === 'dotted' || css === 'none') return css
|
|
93
|
+
return 'solid'
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Dispatch border-* longhands and their logical-direction variants to
|
|
98
|
+
* RN style entries. Returns `null` for any property the dispatcher
|
|
99
|
+
* doesn't handle so the caller can fall through.
|
|
100
|
+
*
|
|
101
|
+
* Logical-direction inputs (`border-inline-*`, `border-block-*`,
|
|
102
|
+
* `border-inline-start-*`, …) lower to RN's physical pairs
|
|
103
|
+
* (`borderLeft*` / `borderRight*` / `borderTop*` / `borderBottom*`)
|
|
104
|
+
* since RN doesn't honor logical directions at the style level.
|
|
105
|
+
* @param decl One lightningcss declaration.
|
|
106
|
+
* @returns RN entries when the property matched, else `null`.
|
|
107
|
+
*/
|
|
108
|
+
export function dispatchBorderDeclaration(decl: LcDeclaration): readonly RNEntry[] | null {
|
|
109
|
+
switch (decl.property) {
|
|
110
|
+
case 'border-inline-color': {
|
|
111
|
+
return colorPair('borderLeftColor', 'borderRightColor', decl.value)
|
|
112
|
+
}
|
|
113
|
+
case 'border-block-color': {
|
|
114
|
+
return colorPair('borderTopColor', 'borderBottomColor', decl.value)
|
|
115
|
+
}
|
|
116
|
+
case 'border-inline-start-color': {
|
|
117
|
+
return [['borderLeftColor', cssColorToString(decl.value)]]
|
|
118
|
+
}
|
|
119
|
+
case 'border-inline-end-color': {
|
|
120
|
+
return [['borderRightColor', cssColorToString(decl.value)]]
|
|
121
|
+
}
|
|
122
|
+
case 'border-block-start-color': {
|
|
123
|
+
return [['borderTopColor', cssColorToString(decl.value)]]
|
|
124
|
+
}
|
|
125
|
+
case 'border-block-end-color': {
|
|
126
|
+
return [['borderBottomColor', cssColorToString(decl.value)]]
|
|
127
|
+
}
|
|
128
|
+
case 'border-width': {
|
|
129
|
+
return borderWidthShorthand(decl.value)
|
|
130
|
+
}
|
|
131
|
+
case 'border-top-width':
|
|
132
|
+
case 'border-right-width':
|
|
133
|
+
case 'border-bottom-width':
|
|
134
|
+
case 'border-left-width': {
|
|
135
|
+
const v = lengthToPxValue(decl.value)
|
|
136
|
+
return v === null ? [] : [[kebabToCamel(decl.property), v]]
|
|
137
|
+
}
|
|
138
|
+
case 'border-inline-width': {
|
|
139
|
+
return widthPair('borderLeftWidth', 'borderRightWidth', decl.value)
|
|
140
|
+
}
|
|
141
|
+
case 'border-block-width': {
|
|
142
|
+
return widthPair('borderTopWidth', 'borderBottomWidth', decl.value)
|
|
143
|
+
}
|
|
144
|
+
case 'border-inline-start-width': {
|
|
145
|
+
const v = lengthToPxValue(decl.value)
|
|
146
|
+
return v === null ? [] : [['borderLeftWidth', v]]
|
|
147
|
+
}
|
|
148
|
+
case 'border-inline-end-width': {
|
|
149
|
+
const v = lengthToPxValue(decl.value)
|
|
150
|
+
return v === null ? [] : [['borderRightWidth', v]]
|
|
151
|
+
}
|
|
152
|
+
case 'border-block-start-width': {
|
|
153
|
+
const v = lengthToPxValue(decl.value)
|
|
154
|
+
return v === null ? [] : [['borderTopWidth', v]]
|
|
155
|
+
}
|
|
156
|
+
case 'border-block-end-width': {
|
|
157
|
+
const v = lengthToPxValue(decl.value)
|
|
158
|
+
return v === null ? [] : [['borderBottomWidth', v]]
|
|
159
|
+
}
|
|
160
|
+
case 'border-style': {
|
|
161
|
+
const styleValue = (decl.value as { top?: string }).top
|
|
162
|
+
if (typeof styleValue !== 'string') return []
|
|
163
|
+
return [['borderStyle', mapBorderStyle(styleValue)]]
|
|
164
|
+
}
|
|
165
|
+
case 'border-top-style':
|
|
166
|
+
case 'border-right-style':
|
|
167
|
+
case 'border-bottom-style':
|
|
168
|
+
case 'border-left-style': {
|
|
169
|
+
if (typeof decl.value !== 'string') return []
|
|
170
|
+
return [['borderStyle', mapBorderStyle(decl.value)]]
|
|
171
|
+
}
|
|
172
|
+
default: {
|
|
173
|
+
return null
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { KEBAB_BOUNDARY_REGEX } from './constants'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Kebab-case to camelCase — `border-radius` → `borderRadius`.
|
|
5
|
+
* @param name Kebab-case CSS property name.
|
|
6
|
+
* @returns camelCase RN key.
|
|
7
|
+
*/
|
|
8
|
+
export function kebabToCamel(name: string): string {
|
|
9
|
+
return name.replaceAll(KEBAB_BOUNDARY_REGEX, (_, c: string) => c.toUpperCase())
|
|
10
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Declaration as LcDeclaration } from 'lightningcss'
|
|
2
|
+
import { cssColorToString } from './color'
|
|
3
|
+
import type { RNEntry } from './types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Build a `[key, hex]` entry from a typed CssColor. Drops keyword colors
|
|
7
|
+
* (e.g. `'currentcolor'` strings — RN can't render them).
|
|
8
|
+
* @param key RN style key (camelCase).
|
|
9
|
+
* @param value Typed `CssColor`-shaped value.
|
|
10
|
+
* @returns Single-entry list or empty.
|
|
11
|
+
*/
|
|
12
|
+
function colorEntry(key: string, value: unknown): readonly RNEntry[] {
|
|
13
|
+
if (value === null || value === undefined) return []
|
|
14
|
+
if (typeof value === 'string') return [[key, value]]
|
|
15
|
+
const hex = cssColorToString(value as never)
|
|
16
|
+
if (!hex || hex === 'transparent' || hex === 'currentColor') return [[key, hex]]
|
|
17
|
+
return [[key, hex]]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Several typed color properties wrap their `CssColor` payload inside a
|
|
22
|
+
* `{type: 'color', value: CssColor}` envelope. Unwrap so the inner color
|
|
23
|
+
* reaches {@link cssColorToString}.
|
|
24
|
+
* @param value Either a `CssColor` directly or a `{type: 'color', value}` wrapper.
|
|
25
|
+
* @returns Unwrapped `CssColor` (or the input untouched).
|
|
26
|
+
*/
|
|
27
|
+
function unwrapTaggedColor(value: unknown): unknown {
|
|
28
|
+
if (typeof value !== 'object' || value === null) return value
|
|
29
|
+
const tagged = value as { type?: string; value?: unknown }
|
|
30
|
+
if (tagged.type === 'color') return tagged.value
|
|
31
|
+
return value
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Dispatch color-typed CSS properties (text-decoration-color, fill,
|
|
36
|
+
* stroke, caret-color, outline-color, …) to RN-compatible style entries.
|
|
37
|
+
*
|
|
38
|
+
* lightningcss emits two shapes for color properties:
|
|
39
|
+
* - bare `CssColor` value (e.g. `text-decoration-color`, `outline-color`)
|
|
40
|
+
* - wrapped `{type: 'color', value: CssColor}` (e.g. `fill`, `stroke`,
|
|
41
|
+
* `caret-color`, `accent-color`)
|
|
42
|
+
* We unwrap both and run them through {@link cssColorToString} to land
|
|
43
|
+
* at hex/rgba.
|
|
44
|
+
*
|
|
45
|
+
* Returns `null` for any property the dispatcher doesn't handle so the
|
|
46
|
+
* caller can fall through to the next dispatcher.
|
|
47
|
+
* @param decl One lightningcss declaration.
|
|
48
|
+
* @returns RN entries when the property matched, else `null`.
|
|
49
|
+
*/
|
|
50
|
+
export function dispatchColorPropertyDeclaration(decl: LcDeclaration): readonly RNEntry[] | null {
|
|
51
|
+
switch (decl.property) {
|
|
52
|
+
case 'text-decoration-color': {
|
|
53
|
+
return colorEntry('textDecorationColor', decl.value)
|
|
54
|
+
}
|
|
55
|
+
case 'caret-color': {
|
|
56
|
+
return colorEntry('caretColor', unwrapTaggedColor(decl.value))
|
|
57
|
+
}
|
|
58
|
+
case 'fill': {
|
|
59
|
+
return colorEntry('fill', unwrapTaggedColor(decl.value))
|
|
60
|
+
}
|
|
61
|
+
case 'stroke': {
|
|
62
|
+
return colorEntry('stroke', unwrapTaggedColor(decl.value))
|
|
63
|
+
}
|
|
64
|
+
case 'outline-color': {
|
|
65
|
+
// RN doesn't render outlines, but tooling like react-native-web /
|
|
66
|
+
// a11y overlays read it — keep so cross-platform code carries the
|
|
67
|
+
// value through.
|
|
68
|
+
return colorEntry('outlineColor', decl.value)
|
|
69
|
+
}
|
|
70
|
+
case 'accent-color': {
|
|
71
|
+
// RN has no native accent color; skip silently.
|
|
72
|
+
return []
|
|
73
|
+
}
|
|
74
|
+
default: {
|
|
75
|
+
return null
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|