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,194 @@
|
|
|
1
|
+
import { mkdirSync, existsSync, watch, utimesSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { writeDtsFile } from './dts.mjs';
|
|
4
|
+
import { createRnwindResolver } from './resolver.mjs';
|
|
5
|
+
import { configureRnwindState, getRnwindState, onThemeChange } from './state.mjs';
|
|
6
|
+
|
|
7
|
+
/** Default cache directory at the project root. Visible for debugging. */
|
|
8
|
+
const DEFAULT_CACHE_DIR = '.rnwind';
|
|
9
|
+
/**
|
|
10
|
+
* Active CSS watcher — replaced (and the prior one closed) when
|
|
11
|
+
* `withRnwindConfig` is called again (Metro restart, repeated init).
|
|
12
|
+
* Only one watcher per process; no stacking.
|
|
13
|
+
*/
|
|
14
|
+
let activeCssWatcher = null;
|
|
15
|
+
/**
|
|
16
|
+
* Watch the theme CSS for edits. On change, rewrite the per-scheme
|
|
17
|
+
* files with the fresh theme AND bump `mtime` on every source file
|
|
18
|
+
* rnwind has transformed so far — Metro's own watcher sees those
|
|
19
|
+
* mtime changes, invalidates the modules, and re-transforms them
|
|
20
|
+
* against the new CSS on the next request. `getCacheKey()` alone is
|
|
21
|
+
* NOT enough: Metro samples the cache key once per worker lifetime,
|
|
22
|
+
* so edits during an already-running dev server don't propagate
|
|
23
|
+
* without this explicit nudge.
|
|
24
|
+
* @param cssPath Absolute path to the theme CSS to watch.
|
|
25
|
+
* @param projectRoot Metro's project root (for `getRnwindState`).
|
|
26
|
+
*/
|
|
27
|
+
function watchThemeCss(cssPath, projectRoot) {
|
|
28
|
+
if (activeCssWatcher?.cssPath === cssPath)
|
|
29
|
+
return;
|
|
30
|
+
activeCssWatcher?.close();
|
|
31
|
+
if (!existsSync(cssPath))
|
|
32
|
+
return;
|
|
33
|
+
let pending = false;
|
|
34
|
+
const watcher = watch(cssPath, { persistent: false }, () => {
|
|
35
|
+
// Debounce: editors often emit 2-3 change events per save (atomic
|
|
36
|
+
// rename dance, tmp files). Coalesce to ONE rebuild per microtask.
|
|
37
|
+
if (pending)
|
|
38
|
+
return;
|
|
39
|
+
pending = true;
|
|
40
|
+
queueMicrotask(async () => {
|
|
41
|
+
pending = false;
|
|
42
|
+
try {
|
|
43
|
+
await onThemeChange(projectRoot);
|
|
44
|
+
touchRecordedFiles(projectRoot);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Invalidation is best-effort — never crash the dev server.
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
activeCssWatcher = { cssPath, close: () => watcher.close() };
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Bump the mtime on every file the builder has transformed. Metro's
|
|
55
|
+
* file watcher keys on `mtime`, so this is what makes it invalidate
|
|
56
|
+
* those modules and re-transform them.
|
|
57
|
+
* @param projectRoot Metro's project root.
|
|
58
|
+
*/
|
|
59
|
+
function touchRecordedFiles(projectRoot) {
|
|
60
|
+
const state = getRnwindState(projectRoot);
|
|
61
|
+
const files = state.builder.recordedFiles();
|
|
62
|
+
const now = new Date();
|
|
63
|
+
for (const file of files) {
|
|
64
|
+
try {
|
|
65
|
+
if (existsSync(file))
|
|
66
|
+
utimesSync(file, now, now);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// One file's stat failure shouldn't stop the others.
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Where the rnwind babel transformer lives — resolved relative to this
|
|
75
|
+
* module so the path works from both the `src/` tree (tests) and the
|
|
76
|
+
* built `lib/` output. Tries a few extensions because `require.resolve`
|
|
77
|
+
* doesn't auto-find `.cjs` / `.mjs` from a bare specifier.
|
|
78
|
+
* @returns Absolute path to the rnwind transformer module.
|
|
79
|
+
*/
|
|
80
|
+
function transformerPath() {
|
|
81
|
+
for (const candidate of ['./transformer.cjs', './transformer.mjs', './transformer.js', './transformer.ts', './transformer']) {
|
|
82
|
+
try {
|
|
83
|
+
return require.resolve(candidate);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// try the next extension
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
throw new Error('rnwind: could not resolve the metro transformer path');
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Resolve the effective cache directory, honoring a user override and
|
|
93
|
+
* falling back to `<projectRoot>/.rnwind`.
|
|
94
|
+
* @param projectRoot Anchor for relative paths.
|
|
95
|
+
* @param override User-supplied option.
|
|
96
|
+
* @returns Absolute cache directory.
|
|
97
|
+
*/
|
|
98
|
+
function resolveCacheDir(projectRoot, override) {
|
|
99
|
+
if (!override || override.length === 0)
|
|
100
|
+
return path.resolve(projectRoot, DEFAULT_CACHE_DIR);
|
|
101
|
+
return path.isAbsolute(override) ? override : path.resolve(projectRoot, override);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Read the theme CSS and extract `@variant <name>` blocks for the .d.ts
|
|
105
|
+
* generator. Forces construction of `getRnwindState`, then reads
|
|
106
|
+
* `parser.declaredSchemes` (populated synchronously at construction).
|
|
107
|
+
* @param cssEntry Absolute path to theme CSS.
|
|
108
|
+
* @param projectRoot
|
|
109
|
+
* @returns Scheme names (empty when the theme has no variants; `'base'` is filtered).
|
|
110
|
+
*/
|
|
111
|
+
function discoverSchemes(cssEntry, projectRoot) {
|
|
112
|
+
if (!existsSync(cssEntry))
|
|
113
|
+
return [];
|
|
114
|
+
try {
|
|
115
|
+
const { parser } = getRnwindState(projectRoot);
|
|
116
|
+
return parser.declaredSchemes.filter((name) => name !== 'base');
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Wrap a Metro config with rnwind's pipeline:
|
|
124
|
+
* - Install the rnwind babel transformer.
|
|
125
|
+
* - Chain a `resolveRequest` hook that serves
|
|
126
|
+
* `rnwind/__generated/schemes` from `<cacheDir>/schemes.js`.
|
|
127
|
+
* - Write the `.d.ts` so TypeScript accepts `className=` on RN components.
|
|
128
|
+
* - Publish the theme CSS path + cache dir via env so Metro workers
|
|
129
|
+
* can rebuild their local state.
|
|
130
|
+
* - Ensure the cache dir is a watched folder Metro's haste-map indexes.
|
|
131
|
+
*
|
|
132
|
+
* Theme-edit hot reload happens implicitly: every transformed file
|
|
133
|
+
* imports `rnwind/__generated/schemes`, and that module eager-imports
|
|
134
|
+
* `common.style.js`. When the theme changes, the per-scheme files
|
|
135
|
+
* regenerate with new bytes; Metro's content SHA1 dedup detects the
|
|
136
|
+
* change and invalidates every importer automatically.
|
|
137
|
+
* `getCacheKey()` on the transformer covers the per-file transform
|
|
138
|
+
* cache. No file watcher / source-padding hack needed — the dep graph
|
|
139
|
+
* carries the signal.
|
|
140
|
+
* @param metroConfig Config from `getDefaultConfig(__dirname)` or equivalent.
|
|
141
|
+
* @param options rnwind options.
|
|
142
|
+
* @returns The same config, mutated.
|
|
143
|
+
*/
|
|
144
|
+
function withRnwindConfig(metroConfig, options) {
|
|
145
|
+
const projectRoot = options.projectRoot ?? metroConfig.projectRoot ?? process.cwd();
|
|
146
|
+
const cacheDir = resolveCacheDir(projectRoot, options.cacheDir);
|
|
147
|
+
const cssEntry = path.isAbsolute(options.cssEntryFile) ? options.cssEntryFile : path.resolve(projectRoot, options.cssEntryFile);
|
|
148
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
149
|
+
const watchFolders = (metroConfig.watchFolders ?? []).filter((p) => typeof p === 'string' && p.length > 0);
|
|
150
|
+
configureRnwindState(cssEntry, cacheDir, watchFolders, options.classNamePrefixes, options.hostSources, options.hostComponents);
|
|
151
|
+
// Warm the state eagerly (in the Metro master process) so oxide's
|
|
152
|
+
// Scanner walks every project source (and every monorepo
|
|
153
|
+
// watch-folder) ONCE and the manifest + scheme files hold the
|
|
154
|
+
// complete union before Metro's resolver tries to SHA1 them on the
|
|
155
|
+
// first transform. Each worker lazy-repeats this scan on its first
|
|
156
|
+
// transform to converge on identical state.
|
|
157
|
+
try {
|
|
158
|
+
void getRnwindState(projectRoot).builder.ensureFilesExist();
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// Any init error surfaces again at the first transform; don't crash Metro boot.
|
|
162
|
+
}
|
|
163
|
+
// Install transformer + resolver. Capture the existing
|
|
164
|
+
// babelTransformerPath BEFORE we override it — our worker chains to
|
|
165
|
+
// it (env-passed) so Flow / expo-router / babel-preset-expo etc. all
|
|
166
|
+
// continue to run.
|
|
167
|
+
const existingTransformerPath = metroConfig.transformer?.babelTransformerPath;
|
|
168
|
+
if (typeof existingTransformerPath === 'string' && existingTransformerPath.length > 0) {
|
|
169
|
+
process.env.RNWIND_UPSTREAM_TRANSFORMER = existingTransformerPath;
|
|
170
|
+
}
|
|
171
|
+
const upstream = metroConfig.resolver?.resolveRequest ?? null;
|
|
172
|
+
metroConfig.transformer = { ...metroConfig.transformer, babelTransformerPath: transformerPath() };
|
|
173
|
+
metroConfig.resolver = { ...metroConfig.resolver, resolveRequest: createRnwindResolver(upstream) };
|
|
174
|
+
// Metro's haste-map indexes `watchFolders` at startup. Adding the
|
|
175
|
+
// cache dir guarantees scheme style files + manifest get SHA1'd
|
|
176
|
+
// without a "Failed to get the SHA-1" race when the first transform
|
|
177
|
+
// writes them.
|
|
178
|
+
const existingWatch = metroConfig.watchFolders ?? [];
|
|
179
|
+
metroConfig.watchFolders = existingWatch.includes(cacheDir) ? existingWatch : [...existingWatch, cacheDir];
|
|
180
|
+
if (options.dtsFile !== false) {
|
|
181
|
+
const dtsPath = options.dtsFile ?? path.resolve(projectRoot, 'rnwind-types.d.ts');
|
|
182
|
+
const schemes = discoverSchemes(cssEntry, projectRoot);
|
|
183
|
+
writeDtsFile(dtsPath, schemes, options.classNamePrefixes);
|
|
184
|
+
}
|
|
185
|
+
// Watch the theme CSS. On edit, we rewrite scheme files AND touch
|
|
186
|
+
// mtime on every transformed source file so Metro invalidates them
|
|
187
|
+
// and re-transforms — the only reliable way to propagate theme
|
|
188
|
+
// changes to an already-running dev server.
|
|
189
|
+
watchThemeCss(cssEntry, projectRoot);
|
|
190
|
+
return metroConfig;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export { withRnwindConfig };
|
|
194
|
+
//# sourceMappingURL=with-config.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-config.mjs","sources":["../../../../src/metro/with-config.ts"],"sourcesContent":["import { existsSync, mkdirSync, utimesSync, watch as watchFile } from 'node:fs'\nimport path from 'node:path'\nimport { writeDtsFile } from './dts'\nimport { createRnwindResolver, type ResolveRequestFn } from './resolver'\nimport { configureRnwindState, getRnwindState, onThemeChange } from './state'\n\n/** Default cache directory at the project root. Visible for debugging. */\nconst DEFAULT_CACHE_DIR = '.rnwind'\n\n/**\n * Active CSS watcher — replaced (and the prior one closed) when\n * `withRnwindConfig` is called again (Metro restart, repeated init).\n * Only one watcher per process; no stacking.\n */\nlet activeCssWatcher: { cssPath: string; close: () => void } | null = null\n\n/**\n * Watch the theme CSS for edits. On change, rewrite the per-scheme\n * files with the fresh theme AND bump `mtime` on every source file\n * rnwind has transformed so far — Metro's own watcher sees those\n * mtime changes, invalidates the modules, and re-transforms them\n * against the new CSS on the next request. `getCacheKey()` alone is\n * NOT enough: Metro samples the cache key once per worker lifetime,\n * so edits during an already-running dev server don't propagate\n * without this explicit nudge.\n * @param cssPath Absolute path to the theme CSS to watch.\n * @param projectRoot Metro's project root (for `getRnwindState`).\n */\nfunction watchThemeCss(cssPath: string, projectRoot: string): void {\n if (activeCssWatcher?.cssPath === cssPath) return\n activeCssWatcher?.close()\n if (!existsSync(cssPath)) return\n let pending = false\n const watcher = watchFile(cssPath, { persistent: false }, () => {\n // Debounce: editors often emit 2-3 change events per save (atomic\n // rename dance, tmp files). Coalesce to ONE rebuild per microtask.\n if (pending) return\n pending = true\n queueMicrotask(async () => {\n pending = false\n try {\n await onThemeChange(projectRoot)\n touchRecordedFiles(projectRoot)\n } catch {\n // Invalidation is best-effort — never crash the dev server.\n }\n })\n })\n activeCssWatcher = { cssPath, close: () => watcher.close() }\n}\n\n/**\n * Bump the mtime on every file the builder has transformed. Metro's\n * file watcher keys on `mtime`, so this is what makes it invalidate\n * those modules and re-transform them.\n * @param projectRoot Metro's project root.\n */\nfunction touchRecordedFiles(projectRoot: string): void {\n const state = getRnwindState(projectRoot)\n const files = state.builder.recordedFiles()\n const now = new Date()\n for (const file of files) {\n try {\n if (existsSync(file)) utimesSync(file, now, now)\n } catch {\n // One file's stat failure shouldn't stop the others.\n }\n }\n}\n\n/**\n * Where the rnwind babel transformer lives — resolved relative to this\n * module so the path works from both the `src/` tree (tests) and the\n * built `lib/` output. Tries a few extensions because `require.resolve`\n * doesn't auto-find `.cjs` / `.mjs` from a bare specifier.\n * @returns Absolute path to the rnwind transformer module.\n */\nfunction transformerPath(): string {\n for (const candidate of ['./transformer.cjs', './transformer.mjs', './transformer.js', './transformer.ts', './transformer']) {\n try {\n return require.resolve(candidate)\n } catch {\n // try the next extension\n }\n }\n throw new Error('rnwind: could not resolve the metro transformer path')\n}\n\n/**\n * Resolve the effective cache directory, honoring a user override and\n * falling back to `<projectRoot>/.rnwind`.\n * @param projectRoot Anchor for relative paths.\n * @param override User-supplied option.\n * @returns Absolute cache directory.\n */\nfunction resolveCacheDir(projectRoot: string, override: string | undefined): string {\n if (!override || override.length === 0) return path.resolve(projectRoot, DEFAULT_CACHE_DIR)\n return path.isAbsolute(override) ? override : path.resolve(projectRoot, override)\n}\n\n/**\n * Read the theme CSS and extract `@variant <name>` blocks for the .d.ts\n * generator. Forces construction of `getRnwindState`, then reads\n * `parser.declaredSchemes` (populated synchronously at construction).\n * @param cssEntry Absolute path to theme CSS.\n * @param projectRoot\n * @returns Scheme names (empty when the theme has no variants; `'base'` is filtered).\n */\nfunction discoverSchemes(cssEntry: string, projectRoot: string): readonly string[] {\n if (!existsSync(cssEntry)) return []\n try {\n const { parser } = getRnwindState(projectRoot)\n return parser.declaredSchemes.filter((name) => name !== 'base')\n } catch {\n return []\n }\n}\n\n/** User-facing options for `withRnwindConfig`. */\nexport interface RnwindMetroOptions {\n /** Path to the theme CSS (absolute or relative to `projectRoot`). Required. */\n cssEntryFile: string\n /** Where rnwind writes the `.d.ts` file. Set `false` to disable. Defaults to `<projectRoot>/rnwind-types.d.ts`. */\n dtsFile?: string | false\n /** Optional project-root override — defaults to `metroConfig.projectRoot` then `process.cwd()`. */\n projectRoot?: string\n /** Cache directory. Absolute, or relative to `projectRoot`. Default: `.rnwind` at project root. */\n cacheDir?: string\n /**\n * Extra JSX prop-name prefixes that rnwind should rewrite. Each\n * prefix `P` turns `<Tag PClassName=\"…\">` into `<Tag\n * PStyle={lookupCss(…)}>`. The built-in `'contentContainer'` prefix\n * is always on (covers ScrollView / FlatList / SectionList); user\n * entries merge on top.\n */\n classNamePrefixes?: readonly string[]\n /**\n * Extra module specifiers whose JSX exports rnwind should treat as\n * \"host components\" — i.e. tags whose `className=\"…\"` attribute is\n * rewritten to `style={lookupCss(…)}` at build time (zero runtime\n * cost). Merged with the built-in defaults: `react-native`,\n * `react-native-reanimated`, `react-native-svg`,\n * `react-native-gesture-handler`, `expo-linear-gradient`, `expo-image`.\n *\n * Anything NOT marked as a host has its `className` left untouched —\n * the importing component receives the raw string and decides what\n * to do with it. Use this option to opt your design-system / UI\n * primitive packages into the zero-runtime path.\n */\n hostSources?: readonly string[]\n /**\n * Extra JSX tag names (verbatim — may include `.` for member access\n * like `'Animated.View'`) rnwind should treat as host components,\n * regardless of where they're imported from. Useful for one-off\n * escape-hatches: `import { View as MyBox } from 'react-native'`\n * doesn't change the local name → `'MyBox'` here picks it up.\n */\n hostComponents?: readonly string[]\n}\n\n/** Shape we mutate on Metro's config. Loose so we don't pin Metro's internal types. */\nexport interface MetroConfigLike {\n projectRoot?: string\n watchFolders?: string[]\n transformer?: {\n babelTransformerPath?: string\n [key: string]: unknown\n }\n resolver?: {\n resolveRequest?: ResolveRequestFn | null\n [key: string]: unknown\n }\n [key: string]: unknown\n}\n\n/**\n * Wrap a Metro config with rnwind's pipeline:\n * - Install the rnwind babel transformer.\n * - Chain a `resolveRequest` hook that serves\n * `rnwind/__generated/schemes` from `<cacheDir>/schemes.js`.\n * - Write the `.d.ts` so TypeScript accepts `className=` on RN components.\n * - Publish the theme CSS path + cache dir via env so Metro workers\n * can rebuild their local state.\n * - Ensure the cache dir is a watched folder Metro's haste-map indexes.\n *\n * Theme-edit hot reload happens implicitly: every transformed file\n * imports `rnwind/__generated/schemes`, and that module eager-imports\n * `common.style.js`. When the theme changes, the per-scheme files\n * regenerate with new bytes; Metro's content SHA1 dedup detects the\n * change and invalidates every importer automatically.\n * `getCacheKey()` on the transformer covers the per-file transform\n * cache. No file watcher / source-padding hack needed — the dep graph\n * carries the signal.\n * @param metroConfig Config from `getDefaultConfig(__dirname)` or equivalent.\n * @param options rnwind options.\n * @returns The same config, mutated.\n */\nexport function withRnwindConfig<C extends MetroConfigLike>(metroConfig: C, options: RnwindMetroOptions): C {\n const projectRoot = options.projectRoot ?? metroConfig.projectRoot ?? process.cwd()\n const cacheDir = resolveCacheDir(projectRoot, options.cacheDir)\n const cssEntry = path.isAbsolute(options.cssEntryFile) ? options.cssEntryFile : path.resolve(projectRoot, options.cssEntryFile)\n\n mkdirSync(cacheDir, { recursive: true })\n const watchFolders = (metroConfig.watchFolders ?? []).filter((p) => typeof p === 'string' && p.length > 0)\n configureRnwindState(cssEntry, cacheDir, watchFolders, options.classNamePrefixes, options.hostSources, options.hostComponents)\n\n // Warm the state eagerly (in the Metro master process) so oxide's\n // Scanner walks every project source (and every monorepo\n // watch-folder) ONCE and the manifest + scheme files hold the\n // complete union before Metro's resolver tries to SHA1 them on the\n // first transform. Each worker lazy-repeats this scan on its first\n // transform to converge on identical state.\n try {\n void getRnwindState(projectRoot).builder.ensureFilesExist()\n } catch {\n // Any init error surfaces again at the first transform; don't crash Metro boot.\n }\n\n // Install transformer + resolver. Capture the existing\n // babelTransformerPath BEFORE we override it — our worker chains to\n // it (env-passed) so Flow / expo-router / babel-preset-expo etc. all\n // continue to run.\n const existingTransformerPath = metroConfig.transformer?.babelTransformerPath\n if (typeof existingTransformerPath === 'string' && existingTransformerPath.length > 0) {\n process.env.RNWIND_UPSTREAM_TRANSFORMER = existingTransformerPath\n }\n const upstream = metroConfig.resolver?.resolveRequest ?? null\n metroConfig.transformer = { ...metroConfig.transformer, babelTransformerPath: transformerPath() }\n metroConfig.resolver = { ...metroConfig.resolver, resolveRequest: createRnwindResolver(upstream) }\n\n // Metro's haste-map indexes `watchFolders` at startup. Adding the\n // cache dir guarantees scheme style files + manifest get SHA1'd\n // without a \"Failed to get the SHA-1\" race when the first transform\n // writes them.\n const existingWatch = metroConfig.watchFolders ?? []\n metroConfig.watchFolders = existingWatch.includes(cacheDir) ? existingWatch : [...existingWatch, cacheDir]\n\n if (options.dtsFile !== false) {\n const dtsPath = options.dtsFile ?? path.resolve(projectRoot, 'rnwind-types.d.ts')\n const schemes = discoverSchemes(cssEntry, projectRoot)\n writeDtsFile(dtsPath, schemes, options.classNamePrefixes)\n }\n\n // Watch the theme CSS. On edit, we rewrite scheme files AND touch\n // mtime on every transformed source file so Metro invalidates them\n // and re-transforms — the only reliable way to propagate theme\n // changes to an already-running dev server.\n watchThemeCss(cssEntry, projectRoot)\n\n return metroConfig\n}\n"],"names":["watchFile"],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny helpers that compose rnwind's press / focus handlers with any
|
|
3
|
+
* user-provided ones the JSX site already has. The transformer uses
|
|
4
|
+
* these when it rewrites a `<Pressable onPressIn={user}>` into
|
|
5
|
+
* `<Pressable onPressIn={chainPress(user, _i.onPressIn)}>` so the user's
|
|
6
|
+
* callback keeps firing.
|
|
7
|
+
*
|
|
8
|
+
* Both helpers bail out when the user's handler is `null` / `undefined`,
|
|
9
|
+
* returning rnwind's handler directly — that gives the transformer a
|
|
10
|
+
* cheap uniform rewrite ("always chain") without allocating a new
|
|
11
|
+
* function per render when the user didn't opt in to the handler.
|
|
12
|
+
*/
|
|
13
|
+
import type { GestureResponderEvent, NativeSyntheticEvent, TargetedEvent } from 'react-native';
|
|
14
|
+
type PressHandler = (event: GestureResponderEvent) => void;
|
|
15
|
+
type FocusHandler = (event: NativeSyntheticEvent<TargetedEvent>) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Compose a user-supplied press handler with rnwind's internal one.
|
|
18
|
+
* User fires first (its return / side-effects happen pre-gate flip); the
|
|
19
|
+
* rnwind handler then updates the active flag.
|
|
20
|
+
* @param user User-supplied handler from the original JSX (optional).
|
|
21
|
+
* @param ours rnwind's internal active-toggling handler.
|
|
22
|
+
* @returns Combined handler, or `ours` directly when the user didn't provide one.
|
|
23
|
+
*/
|
|
24
|
+
export declare function chainPress(user: PressHandler | null | undefined, ours: PressHandler): PressHandler;
|
|
25
|
+
/**
|
|
26
|
+
* Compose a user-supplied focus/blur handler with rnwind's internal one.
|
|
27
|
+
* Same ordering rule as {@link chainPress}: user first, rnwind second.
|
|
28
|
+
* @param user User-supplied handler (optional).
|
|
29
|
+
* @param ours rnwind's internal focus-toggling handler.
|
|
30
|
+
* @returns Combined handler, or `ours` directly when the user didn't provide one.
|
|
31
|
+
*/
|
|
32
|
+
export declare function chainFocus(user: FocusHandler | null | undefined, ours: FocusHandler): FocusHandler;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compose a user-supplied press handler with rnwind's internal one.
|
|
3
|
+
* User fires first (its return / side-effects happen pre-gate flip); the
|
|
4
|
+
* rnwind handler then updates the active flag.
|
|
5
|
+
* @param user User-supplied handler from the original JSX (optional).
|
|
6
|
+
* @param ours rnwind's internal active-toggling handler.
|
|
7
|
+
* @returns Combined handler, or `ours` directly when the user didn't provide one.
|
|
8
|
+
*/
|
|
9
|
+
function chainPress(user, ours) {
|
|
10
|
+
if (user == null)
|
|
11
|
+
return ours;
|
|
12
|
+
return (event) => {
|
|
13
|
+
user(event);
|
|
14
|
+
ours(event);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Compose a user-supplied focus/blur handler with rnwind's internal one.
|
|
19
|
+
* Same ordering rule as {@link chainPress}: user first, rnwind second.
|
|
20
|
+
* @param user User-supplied handler (optional).
|
|
21
|
+
* @param ours rnwind's internal focus-toggling handler.
|
|
22
|
+
* @returns Combined handler, or `ours` directly when the user didn't provide one.
|
|
23
|
+
*/
|
|
24
|
+
function chainFocus(user, ours) {
|
|
25
|
+
if (user == null)
|
|
26
|
+
return ours;
|
|
27
|
+
return (event) => {
|
|
28
|
+
user(event);
|
|
29
|
+
ours(event);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { chainFocus, chainPress };
|
|
34
|
+
//# sourceMappingURL=chain-handlers.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain-handlers.mjs","sources":["../../../../src/runtime/chain-handlers.ts"],"sourcesContent":["/**\n * Tiny helpers that compose rnwind's press / focus handlers with any\n * user-provided ones the JSX site already has. The transformer uses\n * these when it rewrites a `<Pressable onPressIn={user}>` into\n * `<Pressable onPressIn={chainPress(user, _i.onPressIn)}>` so the user's\n * callback keeps firing.\n *\n * Both helpers bail out when the user's handler is `null` / `undefined`,\n * returning rnwind's handler directly — that gives the transformer a\n * cheap uniform rewrite (\"always chain\") without allocating a new\n * function per render when the user didn't opt in to the handler.\n */\nimport type { GestureResponderEvent, NativeSyntheticEvent, TargetedEvent } from 'react-native'\n\ntype PressHandler = (event: GestureResponderEvent) => void\ntype FocusHandler = (event: NativeSyntheticEvent<TargetedEvent>) => void\n\n/**\n * Compose a user-supplied press handler with rnwind's internal one.\n * User fires first (its return / side-effects happen pre-gate flip); the\n * rnwind handler then updates the active flag.\n * @param user User-supplied handler from the original JSX (optional).\n * @param ours rnwind's internal active-toggling handler.\n * @returns Combined handler, or `ours` directly when the user didn't provide one.\n */\nexport function chainPress(user: PressHandler | null | undefined, ours: PressHandler): PressHandler {\n if (user == null) return ours\n return (event: GestureResponderEvent): void => {\n user(event)\n ours(event)\n }\n}\n\n/**\n * Compose a user-supplied focus/blur handler with rnwind's internal one.\n * Same ordering rule as {@link chainPress}: user first, rnwind second.\n * @param user User-supplied handler (optional).\n * @param ours rnwind's internal focus-toggling handler.\n * @returns Combined handler, or `ours` directly when the user didn't provide one.\n */\nexport function chainFocus(user: FocusHandler | null | undefined, ours: FocusHandler): FocusHandler {\n if (user == null) return ours\n return (event: NativeSyntheticEvent<TargetedEvent>): void => {\n user(event)\n ours(event)\n }\n}\n"],"names":[],"mappings":"AAiBA;;;;;;;AAOG;AACG,SAAU,UAAU,CAAC,IAAqC,EAAE,IAAkB,EAAA;IAClF,IAAI,IAAI,IAAI,IAAI;AAAE,QAAA,OAAO,IAAI;IAC7B,OAAO,CAAC,KAA4B,KAAU;QAC5C,IAAI,CAAC,KAAK,CAAC;QACX,IAAI,CAAC,KAAK,CAAC;AACb,IAAA,CAAC;AACH;AAEA;;;;;;AAMG;AACG,SAAU,UAAU,CAAC,IAAqC,EAAE,IAAkB,EAAA;IAClF,IAAI,IAAI,IAAI,IAAI;AAAE,QAAA,OAAO,IAAI;IAC7B,OAAO,CAAC,KAA0C,KAAU;QAC1D,IAAI,CAAC,KAAK,CAAC;QACX,IAAI,CAAC,KAAK,CAAC;AACb,IAAA,CAAC;AACH;;;;"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { ThemeTables } from '../../core/types';
|
|
3
|
+
import type { Scheme } from '../types';
|
|
4
|
+
import type { OnHaptics } from '../../core/parser/haptics';
|
|
5
|
+
/**
|
|
6
|
+
* Per-render safe-area insets snapshot. Bridge from any source
|
|
7
|
+
* (`useSafeAreaInsets()`, expo-router insets, a manually computed
|
|
8
|
+
* value) into the {@link RnwindProvider} — rnwind stays
|
|
9
|
+
* library-agnostic.
|
|
10
|
+
*/
|
|
11
|
+
export type Insets = Readonly<{
|
|
12
|
+
top: number;
|
|
13
|
+
right: number;
|
|
14
|
+
bottom: number;
|
|
15
|
+
left: number;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Single value carried by the rnwind context. Every piece of runtime
|
|
19
|
+
* state rnwind needs — scheme, theme tables, insets, font scale,
|
|
20
|
+
* window width, active responsive breakpoint, optional haptic
|
|
21
|
+
* dispatcher — lives on this one bag. Consumers read it via
|
|
22
|
+
* {@link useRnwind} and either destructure or forward straight to
|
|
23
|
+
* `lookupCss` / `useCss`.
|
|
24
|
+
*
|
|
25
|
+
* `activeBreakpoint` is the highest-threshold registered breakpoint
|
|
26
|
+
* whose min-width is `<= windowWidth`, or `'base'` when below the
|
|
27
|
+
* smallest one (mobile-first tier) or when no breakpoints are
|
|
28
|
+
* registered yet (tests, bundles without rnwind-transformed sources).
|
|
29
|
+
* Always a string — never null. Reactive: it updates with
|
|
30
|
+
* `useWindowDimensions().width`, so consumers can branch on it
|
|
31
|
+
* without a separate hook.
|
|
32
|
+
*/
|
|
33
|
+
export type RnwindState = Readonly<{
|
|
34
|
+
scheme: Scheme;
|
|
35
|
+
tables: ThemeTables;
|
|
36
|
+
insets: Insets;
|
|
37
|
+
onHaptics: OnHaptics | undefined;
|
|
38
|
+
fontScale: number;
|
|
39
|
+
windowWidth: number;
|
|
40
|
+
activeBreakpoint: string;
|
|
41
|
+
}>;
|
|
42
|
+
/** Props accepted by {@link RnwindProvider}. */
|
|
43
|
+
export type RnwindProviderProps = Readonly<{
|
|
44
|
+
scheme: Scheme;
|
|
45
|
+
tables?: ThemeTables;
|
|
46
|
+
insets?: Partial<Insets>;
|
|
47
|
+
onHaptics?: OnHaptics;
|
|
48
|
+
children?: ReactNode;
|
|
49
|
+
}>;
|
|
50
|
+
/**
|
|
51
|
+
* Read rnwind's full runtime state — scheme, theme tables, insets,
|
|
52
|
+
* fontScale, windowWidth, onHaptics — in one go. Pass the returned
|
|
53
|
+
* value straight to `lookupCss` / `useCss`, or destructure what you
|
|
54
|
+
* need.
|
|
55
|
+
* @returns Active rnwind state under the nearest {@link RnwindProvider}.
|
|
56
|
+
*/
|
|
57
|
+
export declare function useRnwind(): RnwindState;
|
|
58
|
+
/**
|
|
59
|
+
* Internal context hook the babel transformer injects at the top of
|
|
60
|
+
* every rewritten component as `const _t = useR_()`. Same body as the
|
|
61
|
+
* public {@link useRnwind} — exposed under a `use*`-prefixed name so
|
|
62
|
+
* react-refresh's babel plugin (which only tracks call-sites whose
|
|
63
|
+
* identifier matches `^use[A-Z]`) folds it into each component's
|
|
64
|
+
* fast-refresh signature. Without that prefix the signature stayed
|
|
65
|
+
* stable across transformer changes; HMR then preserved fiber state
|
|
66
|
+
* while the rendered hook list shifted, surfacing as "change in the
|
|
67
|
+
* order of Hooks" runtime errors. Trailing underscore keeps it
|
|
68
|
+
* visually distinct from the user-facing `useRnwind`.
|
|
69
|
+
* @returns Active rnwind state.
|
|
70
|
+
*/
|
|
71
|
+
export declare function useR_(): RnwindState;
|
|
72
|
+
/**
|
|
73
|
+
* Provider for rnwind's full runtime state. fontScale + windowWidth
|
|
74
|
+
* come from `useWindowDimensions()` so they react to OS-level
|
|
75
|
+
* orientation / accessibility-text-size changes automatically.
|
|
76
|
+
* @param props Provider props.
|
|
77
|
+
* @param props.scheme Active scheme name.
|
|
78
|
+
* @param props.tables Optional pre-resolved token tables.
|
|
79
|
+
* @param props.insets Optional safe-area insets.
|
|
80
|
+
* @param props.onHaptics Optional haptic dispatcher.
|
|
81
|
+
* @param props.children React subtree.
|
|
82
|
+
* @returns Provider element.
|
|
83
|
+
*/
|
|
84
|
+
export declare function RnwindProvider({ scheme, tables, insets, onHaptics, children }: RnwindProviderProps): ReactNode;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { createContext, useMemo, useContext } from 'react';
|
|
3
|
+
import { useWindowDimensions } from 'react-native';
|
|
4
|
+
import { BASE_BREAKPOINT, loadScheme, activeBreakpointFor } from '../lookup-css.mjs';
|
|
5
|
+
|
|
6
|
+
const EMPTY_TABLES = {};
|
|
7
|
+
const ZERO_INSETS = { top: 0, right: 0, bottom: 0, left: 0 };
|
|
8
|
+
const DEFAULT_STATE = {
|
|
9
|
+
scheme: 'light',
|
|
10
|
+
tables: EMPTY_TABLES,
|
|
11
|
+
insets: ZERO_INSETS,
|
|
12
|
+
onHaptics: undefined,
|
|
13
|
+
fontScale: 1,
|
|
14
|
+
windowWidth: 0,
|
|
15
|
+
activeBreakpoint: BASE_BREAKPOINT,
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Normalise a `Partial<Insets>` into a complete {@link Insets}, returning
|
|
19
|
+
* the shared {@link ZERO_INSETS} reference when nothing is supplied so
|
|
20
|
+
* downstream memoisation stays stable.
|
|
21
|
+
* @param partial Caller-supplied insets (or undefined).
|
|
22
|
+
* @returns Complete insets record.
|
|
23
|
+
*/
|
|
24
|
+
function normaliseInsets(partial) {
|
|
25
|
+
if (!partial)
|
|
26
|
+
return ZERO_INSETS;
|
|
27
|
+
const top = partial.top ?? 0;
|
|
28
|
+
const right = partial.right ?? 0;
|
|
29
|
+
const bottom = partial.bottom ?? 0;
|
|
30
|
+
const left = partial.left ?? 0;
|
|
31
|
+
if (top === 0 && right === 0 && bottom === 0 && left === 0)
|
|
32
|
+
return ZERO_INSETS;
|
|
33
|
+
return { top, right, bottom, left };
|
|
34
|
+
}
|
|
35
|
+
/** Single internal context the runtime reads from. */
|
|
36
|
+
const RnwindContext = createContext(DEFAULT_STATE);
|
|
37
|
+
/**
|
|
38
|
+
* Read rnwind's full runtime state — scheme, theme tables, insets,
|
|
39
|
+
* fontScale, windowWidth, onHaptics — in one go. Pass the returned
|
|
40
|
+
* value straight to `lookupCss` / `useCss`, or destructure what you
|
|
41
|
+
* need.
|
|
42
|
+
* @returns Active rnwind state under the nearest {@link RnwindProvider}.
|
|
43
|
+
*/
|
|
44
|
+
function useRnwind() {
|
|
45
|
+
return useContext(RnwindContext);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Internal context hook the babel transformer injects at the top of
|
|
49
|
+
* every rewritten component as `const _t = useR_()`. Same body as the
|
|
50
|
+
* public {@link useRnwind} — exposed under a `use*`-prefixed name so
|
|
51
|
+
* react-refresh's babel plugin (which only tracks call-sites whose
|
|
52
|
+
* identifier matches `^use[A-Z]`) folds it into each component's
|
|
53
|
+
* fast-refresh signature. Without that prefix the signature stayed
|
|
54
|
+
* stable across transformer changes; HMR then preserved fiber state
|
|
55
|
+
* while the rendered hook list shifted, surfacing as "change in the
|
|
56
|
+
* order of Hooks" runtime errors. Trailing underscore keeps it
|
|
57
|
+
* visually distinct from the user-facing `useRnwind`.
|
|
58
|
+
* @returns Active rnwind state.
|
|
59
|
+
*/
|
|
60
|
+
function useR_() {
|
|
61
|
+
return useContext(RnwindContext);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Provider for rnwind's full runtime state. fontScale + windowWidth
|
|
65
|
+
* come from `useWindowDimensions()` so they react to OS-level
|
|
66
|
+
* orientation / accessibility-text-size changes automatically.
|
|
67
|
+
* @param props Provider props.
|
|
68
|
+
* @param props.scheme Active scheme name.
|
|
69
|
+
* @param props.tables Optional pre-resolved token tables.
|
|
70
|
+
* @param props.insets Optional safe-area insets.
|
|
71
|
+
* @param props.onHaptics Optional haptic dispatcher.
|
|
72
|
+
* @param props.children React subtree.
|
|
73
|
+
* @returns Provider element.
|
|
74
|
+
*/
|
|
75
|
+
function RnwindProvider({ scheme, tables, insets, onHaptics, children }) {
|
|
76
|
+
const normalized = normaliseInsets(insets);
|
|
77
|
+
const { fontScale, width } = useWindowDimensions();
|
|
78
|
+
const value = useMemo(() => {
|
|
79
|
+
loadScheme(scheme);
|
|
80
|
+
return {
|
|
81
|
+
scheme,
|
|
82
|
+
tables: tables ?? EMPTY_TABLES,
|
|
83
|
+
insets: normalized,
|
|
84
|
+
onHaptics,
|
|
85
|
+
fontScale,
|
|
86
|
+
windowWidth: width,
|
|
87
|
+
activeBreakpoint: activeBreakpointFor(width),
|
|
88
|
+
};
|
|
89
|
+
}, [scheme, tables, normalized, onHaptics, fontScale, width]);
|
|
90
|
+
return jsx(RnwindContext.Provider, { value: value, children: children });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export { RnwindProvider, useR_, useRnwind };
|
|
94
|
+
//# sourceMappingURL=rnwind-provider.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rnwind-provider.mjs","sources":["../../../../../src/runtime/components/rnwind-provider.tsx"],"sourcesContent":["import { createContext, useContext, useMemo, type ReactNode } from 'react'\nimport { useWindowDimensions } from 'react-native'\nimport type { ThemeTables } from '../../core/types'\nimport type { Scheme } from '../types'\nimport type { OnHaptics } from '../../core/parser/haptics'\nimport { activeBreakpointFor, BASE_BREAKPOINT, loadScheme } from '../lookup-css'\n\n/**\n * Per-render safe-area insets snapshot. Bridge from any source\n * (`useSafeAreaInsets()`, expo-router insets, a manually computed\n * value) into the {@link RnwindProvider} — rnwind stays\n * library-agnostic.\n */\nexport type Insets = Readonly<{\n top: number\n right: number\n bottom: number\n left: number\n}>\n\n/**\n * Single value carried by the rnwind context. Every piece of runtime\n * state rnwind needs — scheme, theme tables, insets, font scale,\n * window width, active responsive breakpoint, optional haptic\n * dispatcher — lives on this one bag. Consumers read it via\n * {@link useRnwind} and either destructure or forward straight to\n * `lookupCss` / `useCss`.\n *\n * `activeBreakpoint` is the highest-threshold registered breakpoint\n * whose min-width is `<= windowWidth`, or `'base'` when below the\n * smallest one (mobile-first tier) or when no breakpoints are\n * registered yet (tests, bundles without rnwind-transformed sources).\n * Always a string — never null. Reactive: it updates with\n * `useWindowDimensions().width`, so consumers can branch on it\n * without a separate hook.\n */\nexport type RnwindState = Readonly<{\n scheme: Scheme\n tables: ThemeTables\n insets: Insets\n onHaptics: OnHaptics | undefined\n fontScale: number\n windowWidth: number\n activeBreakpoint: string\n}>\n\n/** Props accepted by {@link RnwindProvider}. */\nexport type RnwindProviderProps = Readonly<{\n scheme: Scheme\n tables?: ThemeTables\n insets?: Partial<Insets>\n onHaptics?: OnHaptics\n children?: ReactNode\n}>\n\nconst EMPTY_TABLES: ThemeTables = {}\nconst ZERO_INSETS: Insets = { top: 0, right: 0, bottom: 0, left: 0 }\nconst DEFAULT_STATE: RnwindState = {\n scheme: 'light' as Scheme,\n tables: EMPTY_TABLES,\n insets: ZERO_INSETS,\n onHaptics: undefined,\n fontScale: 1,\n windowWidth: 0,\n activeBreakpoint: BASE_BREAKPOINT,\n}\n\n/**\n * Normalise a `Partial<Insets>` into a complete {@link Insets}, returning\n * the shared {@link ZERO_INSETS} reference when nothing is supplied so\n * downstream memoisation stays stable.\n * @param partial Caller-supplied insets (or undefined).\n * @returns Complete insets record.\n */\nfunction normaliseInsets(partial: Partial<Insets> | undefined): Insets {\n if (!partial) return ZERO_INSETS\n const top = partial.top ?? 0\n const right = partial.right ?? 0\n const bottom = partial.bottom ?? 0\n const left = partial.left ?? 0\n if (top === 0 && right === 0 && bottom === 0 && left === 0) return ZERO_INSETS\n return { top, right, bottom, left }\n}\n\n/** Single internal context the runtime reads from. */\nconst RnwindContext = createContext<RnwindState>(DEFAULT_STATE)\n\n/**\n * Read rnwind's full runtime state — scheme, theme tables, insets,\n * fontScale, windowWidth, onHaptics — in one go. Pass the returned\n * value straight to `lookupCss` / `useCss`, or destructure what you\n * need.\n * @returns Active rnwind state under the nearest {@link RnwindProvider}.\n */\nexport function useRnwind(): RnwindState {\n return useContext(RnwindContext)\n}\n\n/**\n * Internal context hook the babel transformer injects at the top of\n * every rewritten component as `const _t = useR_()`. Same body as the\n * public {@link useRnwind} — exposed under a `use*`-prefixed name so\n * react-refresh's babel plugin (which only tracks call-sites whose\n * identifier matches `^use[A-Z]`) folds it into each component's\n * fast-refresh signature. Without that prefix the signature stayed\n * stable across transformer changes; HMR then preserved fiber state\n * while the rendered hook list shifted, surfacing as \"change in the\n * order of Hooks\" runtime errors. Trailing underscore keeps it\n * visually distinct from the user-facing `useRnwind`.\n * @returns Active rnwind state.\n */\nexport function useR_(): RnwindState {\n return useContext(RnwindContext)\n}\n\n/**\n * Provider for rnwind's full runtime state. fontScale + windowWidth\n * come from `useWindowDimensions()` so they react to OS-level\n * orientation / accessibility-text-size changes automatically.\n * @param props Provider props.\n * @param props.scheme Active scheme name.\n * @param props.tables Optional pre-resolved token tables.\n * @param props.insets Optional safe-area insets.\n * @param props.onHaptics Optional haptic dispatcher.\n * @param props.children React subtree.\n * @returns Provider element.\n */\nexport function RnwindProvider({ scheme, tables, insets, onHaptics, children }: RnwindProviderProps): ReactNode {\n const normalized = normaliseInsets(insets)\n const { fontScale, width } = useWindowDimensions()\n const value = useMemo<RnwindState>(() => {\n loadScheme(scheme)\n return {\n scheme,\n tables: tables ?? EMPTY_TABLES,\n insets: normalized,\n onHaptics,\n fontScale,\n windowWidth: width,\n activeBreakpoint: activeBreakpointFor(width),\n }\n }, [scheme, tables, normalized, onHaptics, fontScale, width])\n return <RnwindContext.Provider value={value}>{children}</RnwindContext.Provider>\n}\n"],"names":["_jsx"],"mappings":";;;;;AAuDA,MAAM,YAAY,GAAgB,EAAE;AACpC,MAAM,WAAW,GAAW,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE;AACpE,MAAM,aAAa,GAAgB;AACjC,IAAA,MAAM,EAAE,OAAiB;AACzB,IAAA,MAAM,EAAE,YAAY;AACpB,IAAA,MAAM,EAAE,WAAW;AACnB,IAAA,SAAS,EAAE,SAAS;AACpB,IAAA,SAAS,EAAE,CAAC;AACZ,IAAA,WAAW,EAAE,CAAC;AACd,IAAA,gBAAgB,EAAE,eAAe;CAClC;AAED;;;;;;AAMG;AACH,SAAS,eAAe,CAAC,OAAoC,EAAA;AAC3D,IAAA,IAAI,CAAC,OAAO;AAAE,QAAA,OAAO,WAAW;AAChC,IAAA,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC;AAC5B,IAAA,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC;AAChC,IAAA,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;AAClC,IAAA,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC;AAC9B,IAAA,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC;AAAE,QAAA,OAAO,WAAW;IAC9E,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE;AACrC;AAEA;AACA,MAAM,aAAa,GAAG,aAAa,CAAc,aAAa,CAAC;AAE/D;;;;;;AAMG;SACa,SAAS,GAAA;AACvB,IAAA,OAAO,UAAU,CAAC,aAAa,CAAC;AAClC;AAEA;;;;;;;;;;;;AAYG;SACa,KAAK,GAAA;AACnB,IAAA,OAAO,UAAU,CAAC,aAAa,CAAC;AAClC;AAEA;;;;;;;;;;;AAWG;AACG,SAAU,cAAc,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAuB,EAAA;AACjG,IAAA,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC;IAC1C,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,mBAAmB,EAAE;AAClD,IAAA,MAAM,KAAK,GAAG,OAAO,CAAc,MAAK;QACtC,UAAU,CAAC,MAAM,CAAC;QAClB,OAAO;YACL,MAAM;YACN,MAAM,EAAE,MAAM,IAAI,YAAY;AAC9B,YAAA,MAAM,EAAE,UAAU;YAClB,SAAS;YACT,SAAS;AACT,YAAA,WAAW,EAAE,KAAK;AAClB,YAAA,gBAAgB,EAAE,mBAAmB,CAAC,KAAK,CAAC;SAC7C;AACH,IAAA,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IAC7D,OAAOA,GAAA,CAAC,aAAa,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,KAAK,EAAA,QAAA,EAAG,QAAQ,EAAA,CAA0B;AAClF;;;;"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed contract for the component rnwind's transformer calls with a
|
|
3
|
+
* gradient-class `className`. Matches `expo-linear-gradient` verbatim
|
|
4
|
+
* so users can plug any gradient library that mirrors that API.
|
|
5
|
+
*
|
|
6
|
+
* A typical wiring:
|
|
7
|
+
*
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { LinearGradient } from 'expo-linear-gradient'
|
|
10
|
+
* import type { AsLinearGradientProps } from 'rnwind'
|
|
11
|
+
*
|
|
12
|
+
* // Assert at the type level — CI catches mismatches before runtime.
|
|
13
|
+
* const _typeCheck: AsLinearGradientProps = {} as Parameters<typeof LinearGradient>[0]
|
|
14
|
+
*
|
|
15
|
+
* // Then use it in real JSX. rnwind fills in colors / start / end.
|
|
16
|
+
* <LinearGradient className="bg-gradient-to-r from-red-500 to-blue-500" />
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* The rnwind transformer emits `colors` as a frozen `readonly string[]`,
|
|
20
|
+
* and `start` / `end` as frozen `{x: number, y: number}` records.
|
|
21
|
+
* Users pass the component; rnwind fills the props. Unused props
|
|
22
|
+
* (`locations`, `dither`, …) are forwarded verbatim from the JSX site.
|
|
23
|
+
*/
|
|
24
|
+
/** A unit-square point. Matches the `LinearGradientPoint` object form. */
|
|
25
|
+
export interface LinearGradientPoint {
|
|
26
|
+
/** Horizontal component, 0..1. */
|
|
27
|
+
readonly x: number;
|
|
28
|
+
/** Vertical component, 0..1. */
|
|
29
|
+
readonly y: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The exact prop shape rnwind fills onto a gradient component at
|
|
33
|
+
* build time. A user-supplied `<LinearGradient>` (or any other
|
|
34
|
+
* component) must accept these props — no wrapper, no adapter.
|
|
35
|
+
*/
|
|
36
|
+
export interface AsLinearGradientProps {
|
|
37
|
+
/**
|
|
38
|
+
* Gradient colour stops in source order. rnwind emits a frozen
|
|
39
|
+
* `readonly string[]` with 2+ entries (at least `from` + `to`).
|
|
40
|
+
* Compatible with expo-linear-gradient's `colors: readonly [ColorValue, ColorValue, ...ColorValue[]]`.
|
|
41
|
+
*/
|
|
42
|
+
readonly colors: readonly string[];
|
|
43
|
+
/**
|
|
44
|
+
* Start point, in the unit square (0,0)=top-left → (1,1)=bottom-right.
|
|
45
|
+
* rnwind emits a frozen `{x, y}` record matching the Tailwind
|
|
46
|
+
* direction utility (`to-r` → `{x: 0, y: 0.5}`).
|
|
47
|
+
*/
|
|
48
|
+
readonly start: LinearGradientPoint;
|
|
49
|
+
/** End point — same unit-square coordinates as `start`. */
|
|
50
|
+
readonly end: LinearGradientPoint;
|
|
51
|
+
/**
|
|
52
|
+
* Optional colour-stop positions matching `colors` length. rnwind
|
|
53
|
+
* doesn't emit this today (Tailwind v4's stop-position atoms aren't
|
|
54
|
+
* wired yet); listed here so the prop surface still matches
|
|
55
|
+
* expo-linear-gradient when a consumer passes their own.
|
|
56
|
+
*/
|
|
57
|
+
readonly locations?: readonly number[] | null;
|
|
58
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime helpers the transformer injects for haptic utilities.
|
|
3
|
+
*
|
|
4
|
+
* Two entry points:
|
|
5
|
+
*
|
|
6
|
+
* useMountHaptic(requests) — fires each request on mount via
|
|
7
|
+
* `useEffect(() => { ... }, [])`. Used by the transformer for bare
|
|
8
|
+
* `haptic-*` atoms (no variant prefix).
|
|
9
|
+
*
|
|
10
|
+
* triggerHaptic(onHaptics, request, trigger) — thin forwarding
|
|
11
|
+
* helper for event-driven variants (`active:haptic-*`, `focus:...`,
|
|
12
|
+
* `hover:...`). The transformer emits an inline arrow that calls
|
|
13
|
+
* this from `onPressIn` / `onFocus` / etc.
|
|
14
|
+
*
|
|
15
|
+
* Both emit a one-shot dev-mode warning when `onHaptics` is missing —
|
|
16
|
+
* so developers get a clear "you forgot to wire <SchemeProvider
|
|
17
|
+
* onHaptics=...>" signal instead of silently dropping the haptic.
|
|
18
|
+
*/
|
|
19
|
+
import type { HapticRequest, HapticTrigger, OnHaptics } from '../core/parser/haptics';
|
|
20
|
+
/**
|
|
21
|
+
* Test-only hook — clears the warned-haptics set so successive test
|
|
22
|
+
* runs don't silently swallow their own warnings.
|
|
23
|
+
*/
|
|
24
|
+
declare function __resetHapticWarnings(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Invoke every request in `requests` on mount (once per component
|
|
27
|
+
* mount), using the `onHaptics` dispatcher from the nearest
|
|
28
|
+
* `<SchemeProvider>`. Missing-provider dev warnings fire via
|
|
29
|
+
* {@link warnMissingOnHaptics}.
|
|
30
|
+
*
|
|
31
|
+
* Uses `useEffect(..., [])` — the requests array is identity-stable
|
|
32
|
+
* (hoisted at module scope by the transformer), so re-firing on
|
|
33
|
+
* re-renders isn't a concern.
|
|
34
|
+
* @param requests Hoisted request list for this component.
|
|
35
|
+
*/
|
|
36
|
+
declare function useMountHaptic(requests: readonly HapticRequest[]): void;
|
|
37
|
+
/**
|
|
38
|
+
* Fire one haptic request through the provider dispatcher. Emits the
|
|
39
|
+
* missing-provider dev warning when no dispatcher is wired. Designed
|
|
40
|
+
* for the inline arrows the transformer synthesises:
|
|
41
|
+
*
|
|
42
|
+
* onPressIn={(e) => { triggerHaptic(_h, _HR_xxx, 'pressIn'); user?.(e) }}
|
|
43
|
+
* @param onHaptics Provider dispatcher (may be undefined).
|
|
44
|
+
* @param request Pre-hoisted request object.
|
|
45
|
+
* @param trigger Lifecycle trigger.
|
|
46
|
+
*/
|
|
47
|
+
declare function triggerHaptic(onHaptics: OnHaptics | undefined, request: HapticRequest, trigger: HapticTrigger): void;
|
|
48
|
+
export { useMountHaptic, triggerHaptic, __resetHapticWarnings };
|