@northstar-js/react 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/LICENSE +21 -0
  2. package/dist/actions.d.ts +99 -0
  3. package/dist/actions.d.ts.map +1 -0
  4. package/dist/actions.js +61 -0
  5. package/dist/actions.js.map +1 -0
  6. package/dist/backdrops/StarBackdrop.d.ts +31 -0
  7. package/dist/backdrops/StarBackdrop.d.ts.map +1 -0
  8. package/dist/backdrops/StarBackdrop.js +84 -0
  9. package/dist/backdrops/StarBackdrop.js.map +1 -0
  10. package/dist/backdrops/index.d.ts +7 -0
  11. package/dist/backdrops/index.d.ts.map +1 -0
  12. package/dist/backdrops/index.js +8 -0
  13. package/dist/backdrops/index.js.map +1 -0
  14. package/dist/backdrops/math.d.ts +39 -0
  15. package/dist/backdrops/math.d.ts.map +1 -0
  16. package/dist/backdrops/math.js +44 -0
  17. package/dist/backdrops/math.js.map +1 -0
  18. package/dist/backdrops/scenes.d.ts +20 -0
  19. package/dist/backdrops/scenes.d.ts.map +1 -0
  20. package/dist/backdrops/scenes.js +417 -0
  21. package/dist/backdrops/scenes.js.map +1 -0
  22. package/dist/backdrops.css +141 -0
  23. package/dist/data.d.ts +91 -0
  24. package/dist/data.d.ts.map +1 -0
  25. package/dist/data.js +69 -0
  26. package/dist/data.js.map +1 -0
  27. package/dist/effects/actions.d.ts +48 -0
  28. package/dist/effects/actions.d.ts.map +1 -0
  29. package/dist/effects/actions.js +80 -0
  30. package/dist/effects/actions.js.map +1 -0
  31. package/dist/effects/controls.d.ts +84 -0
  32. package/dist/effects/controls.d.ts.map +1 -0
  33. package/dist/effects/controls.js +121 -0
  34. package/dist/effects/controls.js.map +1 -0
  35. package/dist/effects/display.d.ts +92 -0
  36. package/dist/effects/display.d.ts.map +1 -0
  37. package/dist/effects/display.js +138 -0
  38. package/dist/effects/display.js.map +1 -0
  39. package/dist/effects/hooks.d.ts +13 -0
  40. package/dist/effects/hooks.d.ts.map +1 -0
  41. package/dist/effects/hooks.js +68 -0
  42. package/dist/effects/hooks.js.map +1 -0
  43. package/dist/effects/index.d.ts +14 -0
  44. package/dist/effects/index.d.ts.map +1 -0
  45. package/dist/effects/index.js +12 -0
  46. package/dist/effects/index.js.map +1 -0
  47. package/dist/effects/loaders.d.ts +67 -0
  48. package/dist/effects/loaders.d.ts.map +1 -0
  49. package/dist/effects/loaders.js +73 -0
  50. package/dist/effects/loaders.js.map +1 -0
  51. package/dist/effects/math.d.ts +23 -0
  52. package/dist/effects/math.d.ts.map +1 -0
  53. package/dist/effects/math.js +56 -0
  54. package/dist/effects/math.js.map +1 -0
  55. package/dist/effects/navigation.d.ts +55 -0
  56. package/dist/effects/navigation.d.ts.map +1 -0
  57. package/dist/effects/navigation.js +103 -0
  58. package/dist/effects/navigation.js.map +1 -0
  59. package/dist/effects/overlays.d.ts +34 -0
  60. package/dist/effects/overlays.d.ts.map +1 -0
  61. package/dist/effects/overlays.js +56 -0
  62. package/dist/effects/overlays.js.map +1 -0
  63. package/dist/effects.css +1659 -0
  64. package/dist/feedback.d.ts +55 -0
  65. package/dist/feedback.d.ts.map +1 -0
  66. package/dist/feedback.js +60 -0
  67. package/dist/feedback.js.map +1 -0
  68. package/dist/flow.d.ts +70 -0
  69. package/dist/flow.d.ts.map +1 -0
  70. package/dist/flow.js +118 -0
  71. package/dist/flow.js.map +1 -0
  72. package/dist/forms.d.ts +130 -0
  73. package/dist/forms.d.ts.map +1 -0
  74. package/dist/forms.js +241 -0
  75. package/dist/forms.js.map +1 -0
  76. package/dist/glass.d.ts +74 -0
  77. package/dist/glass.d.ts.map +1 -0
  78. package/dist/glass.js +139 -0
  79. package/dist/glass.js.map +1 -0
  80. package/dist/illustrations/data.d.ts +103 -0
  81. package/dist/illustrations/data.d.ts.map +1 -0
  82. package/dist/illustrations/data.js +3 -0
  83. package/dist/illustrations/data.js.map +1 -0
  84. package/dist/illustrations/index.d.ts +110 -0
  85. package/dist/illustrations/index.d.ts.map +1 -0
  86. package/dist/illustrations/index.js +54 -0
  87. package/dist/illustrations/index.js.map +1 -0
  88. package/dist/illustrations/types.d.ts +30 -0
  89. package/dist/illustrations/types.d.ts.map +1 -0
  90. package/dist/illustrations/types.js +2 -0
  91. package/dist/illustrations/types.js.map +1 -0
  92. package/dist/index.d.ts +27 -0
  93. package/dist/index.d.ts.map +1 -0
  94. package/dist/index.js +13 -0
  95. package/dist/index.js.map +1 -0
  96. package/dist/internal/expand.d.ts +17 -0
  97. package/dist/internal/expand.d.ts.map +1 -0
  98. package/dist/internal/expand.js +23 -0
  99. package/dist/internal/expand.js.map +1 -0
  100. package/dist/internal/icons.d.ts +9 -0
  101. package/dist/internal/icons.d.ts.map +1 -0
  102. package/dist/internal/icons.js +12 -0
  103. package/dist/internal/icons.js.map +1 -0
  104. package/dist/internal/interaction.d.ts +21 -0
  105. package/dist/internal/interaction.d.ts.map +1 -0
  106. package/dist/internal/interaction.js +129 -0
  107. package/dist/internal/interaction.js.map +1 -0
  108. package/dist/internal/layers.d.ts +12 -0
  109. package/dist/internal/layers.d.ts.map +1 -0
  110. package/dist/internal/layers.js +108 -0
  111. package/dist/internal/layers.js.map +1 -0
  112. package/dist/internal/util.d.ts +9 -0
  113. package/dist/internal/util.d.ts.map +1 -0
  114. package/dist/internal/util.js +33 -0
  115. package/dist/internal/util.js.map +1 -0
  116. package/dist/layout.d.ts +34 -0
  117. package/dist/layout.d.ts.map +1 -0
  118. package/dist/layout.js +27 -0
  119. package/dist/layout.js.map +1 -0
  120. package/dist/motion.d.ts +36 -0
  121. package/dist/motion.d.ts.map +1 -0
  122. package/dist/motion.js +80 -0
  123. package/dist/motion.js.map +1 -0
  124. package/dist/navigation.d.ts +100 -0
  125. package/dist/navigation.d.ts.map +1 -0
  126. package/dist/navigation.js +154 -0
  127. package/dist/navigation.js.map +1 -0
  128. package/dist/northstar/BriefForm.d.ts +23 -0
  129. package/dist/northstar/BriefForm.d.ts.map +1 -0
  130. package/dist/northstar/BriefForm.js +40 -0
  131. package/dist/northstar/BriefForm.js.map +1 -0
  132. package/dist/northstar/ExportMenu.d.ts +16 -0
  133. package/dist/northstar/ExportMenu.d.ts.map +1 -0
  134. package/dist/northstar/ExportMenu.js +11 -0
  135. package/dist/northstar/ExportMenu.js.map +1 -0
  136. package/dist/northstar/PopulationPanel.d.ts +30 -0
  137. package/dist/northstar/PopulationPanel.d.ts.map +1 -0
  138. package/dist/northstar/PopulationPanel.js +18 -0
  139. package/dist/northstar/PopulationPanel.js.map +1 -0
  140. package/dist/northstar/ResearchBuilder.d.ts +26 -0
  141. package/dist/northstar/ResearchBuilder.d.ts.map +1 -0
  142. package/dist/northstar/ResearchBuilder.js +81 -0
  143. package/dist/northstar/ResearchBuilder.js.map +1 -0
  144. package/dist/northstar/ResponsesView.d.ts +20 -0
  145. package/dist/northstar/ResponsesView.d.ts.map +1 -0
  146. package/dist/northstar/ResponsesView.js +42 -0
  147. package/dist/northstar/ResponsesView.js.map +1 -0
  148. package/dist/northstar/Run.d.ts +37 -0
  149. package/dist/northstar/Run.d.ts.map +1 -0
  150. package/dist/northstar/Run.js +32 -0
  151. package/dist/northstar/Run.js.map +1 -0
  152. package/dist/northstar/StudyShell.d.ts +50 -0
  153. package/dist/northstar/StudyShell.d.ts.map +1 -0
  154. package/dist/northstar/StudyShell.js +18 -0
  155. package/dist/northstar/StudyShell.js.map +1 -0
  156. package/dist/northstar/StudyStatus.d.ts +17 -0
  157. package/dist/northstar/StudyStatus.d.ts.map +1 -0
  158. package/dist/northstar/StudyStatus.js +26 -0
  159. package/dist/northstar/StudyStatus.js.map +1 -0
  160. package/dist/northstar/index.d.ts +10 -0
  161. package/dist/northstar/index.d.ts.map +1 -0
  162. package/dist/northstar/index.js +10 -0
  163. package/dist/northstar/index.js.map +1 -0
  164. package/dist/northstar/messages.d.ts +84 -0
  165. package/dist/northstar/messages.d.ts.map +1 -0
  166. package/dist/northstar/messages.js +107 -0
  167. package/dist/northstar/messages.js.map +1 -0
  168. package/dist/overlays.d.ts +136 -0
  169. package/dist/overlays.d.ts.map +1 -0
  170. package/dist/overlays.js +447 -0
  171. package/dist/overlays.js.map +1 -0
  172. package/dist/provider.d.ts +82 -0
  173. package/dist/provider.d.ts.map +1 -0
  174. package/dist/provider.js +128 -0
  175. package/dist/provider.js.map +1 -0
  176. package/dist/styles.css +2033 -0
  177. package/dist/surface.d.ts +58 -0
  178. package/dist/surface.d.ts.map +1 -0
  179. package/dist/surface.js +39 -0
  180. package/dist/surface.js.map +1 -0
  181. package/package.json +81 -3
  182. package/README.md +0 -3
@@ -0,0 +1,129 @@
1
+ 'use client';
2
+ // The interaction layer's only JavaScript: pointer tracking for spotlights and
3
+ // magnetic controls, and a presence hook that lets overlays play an exit
4
+ // animation. Everything writes CSS custom properties or attributes straight to
5
+ // the element, so pointer movement never re-renders React.
6
+ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
7
+ const useIsoLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;
8
+ const raf = typeof window !== 'undefined' && window.requestAnimationFrame
9
+ ? (cb) => window.requestAnimationFrame(cb)
10
+ : (cb) => setTimeout(cb, 16);
11
+ const caf = typeof window !== 'undefined' && window.cancelAnimationFrame ? (id) => window.cancelAnimationFrame(id) : (id) => clearTimeout(id);
12
+ function prefersReducedMotion() {
13
+ return typeof window !== 'undefined' && !!window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
14
+ }
15
+ /**
16
+ * Tracks the pointer over an element, rAF-throttled, and writes
17
+ * `--ns-mx` / `--ns-my` (px from the top-left, for spotlights and specular
18
+ * highlights), `--ns-pointer-x` / `--ns-pointer-y` (unitless, -1 at the
19
+ * left/top edge to 1 at the right/bottom, for the spin finish's turning
20
+ * sweep) and, when magnetic, `--ns-mag-x` / `--ns-mag-y`. Touch is
21
+ * ignored; the pointer effects are a hover affordance and keyboard focus gets
22
+ * an equivalent centred highlight from CSS.
23
+ */
24
+ export function usePointerTracking(enabled, options = {}) {
25
+ const magnetic = options.magnetic ?? 0;
26
+ const cleanup = useRef(null);
27
+ // A predicate is decided once, when the element mounts (e.g. "am I on glass?").
28
+ const test = useRef(enabled);
29
+ test.current = enabled;
30
+ const key = typeof enabled === 'function' ? 'test' : enabled;
31
+ return useCallback((el) => {
32
+ cleanup.current?.();
33
+ cleanup.current = null;
34
+ const on = typeof test.current === 'function' ? !!el && test.current(el) : test.current;
35
+ if (!el || !on)
36
+ return;
37
+ let frame = 0;
38
+ let last = null;
39
+ const flush = () => {
40
+ frame = 0;
41
+ if (!last)
42
+ return;
43
+ const r = el.getBoundingClientRect();
44
+ const x = last.clientX - r.left;
45
+ const y = last.clientY - r.top;
46
+ el.style.setProperty('--ns-mx', `${x.toFixed(1)}px`);
47
+ el.style.setProperty('--ns-my', `${y.toFixed(1)}px`);
48
+ if (r.width <= 0 || r.height <= 0)
49
+ return;
50
+ const dx = Math.max(-1, Math.min(1, (x / r.width - 0.5) * 2));
51
+ const dy = Math.max(-1, Math.min(1, (y / r.height - 0.5) * 2));
52
+ el.style.setProperty('--ns-pointer-x', dx.toFixed(3));
53
+ el.style.setProperty('--ns-pointer-y', dy.toFixed(3));
54
+ if (magnetic > 0 && !prefersReducedMotion()) {
55
+ el.style.setProperty('--ns-mag-x', `${(dx * magnetic).toFixed(2)}px`);
56
+ el.style.setProperty('--ns-mag-y', `${(dy * magnetic).toFixed(2)}px`);
57
+ }
58
+ };
59
+ const onMove = (e) => {
60
+ if (e.pointerType === 'touch')
61
+ return;
62
+ last = e;
63
+ el.setAttribute('data-pointer', '');
64
+ if (!frame)
65
+ frame = raf(flush);
66
+ };
67
+ const onLeave = () => {
68
+ last = null;
69
+ if (frame)
70
+ caf(frame);
71
+ frame = 0;
72
+ el.removeAttribute('data-pointer');
73
+ el.style.removeProperty('--ns-pointer-x');
74
+ el.style.removeProperty('--ns-pointer-y');
75
+ el.style.removeProperty('--ns-mag-x');
76
+ el.style.removeProperty('--ns-mag-y');
77
+ };
78
+ el.addEventListener('pointermove', onMove, { passive: true });
79
+ el.addEventListener('pointerleave', onLeave);
80
+ cleanup.current = () => {
81
+ el.removeEventListener('pointermove', onMove);
82
+ el.removeEventListener('pointerleave', onLeave);
83
+ if (frame)
84
+ caf(frame);
85
+ };
86
+ }, [key, magnetic]);
87
+ }
88
+ function longestAnimation(el) {
89
+ const cs = getComputedStyle(el);
90
+ if (!cs.animationName || cs.animationName === 'none')
91
+ return 0;
92
+ const parse = (s) => (s.trim().endsWith('ms') ? parseFloat(s) : parseFloat(s) * 1000) || 0;
93
+ const durations = (cs.animationDuration || '0s').split(',').map(parse);
94
+ const delays = (cs.animationDelay || '0s').split(',').map(parse);
95
+ return Math.max(0, ...durations.map((d, i) => d + (delays[i] ?? 0)));
96
+ }
97
+ /**
98
+ * Keeps a layer mounted after `open` turns false until its exit animation
99
+ * (`[data-state='closed']` in CSS) has played. With no animation — reduced
100
+ * motion, forced zero durations, or no stylesheet — it unmounts at once.
101
+ */
102
+ export function usePresence(open, ref) {
103
+ const [mounted, setMounted] = useState(open);
104
+ if (open && !mounted)
105
+ setMounted(true);
106
+ useIsoLayoutEffect(() => {
107
+ if (open || !mounted)
108
+ return;
109
+ const el = ref.current;
110
+ const ms = el ? longestAnimation(el) : 0;
111
+ if (!el || ms <= 0) {
112
+ setMounted(false);
113
+ return;
114
+ }
115
+ const done = () => setMounted(false);
116
+ const onEnd = (e) => {
117
+ if (e.target === el)
118
+ done();
119
+ };
120
+ el.addEventListener('animationend', onEnd);
121
+ const t = setTimeout(done, ms + 60);
122
+ return () => {
123
+ el.removeEventListener('animationend', onEnd);
124
+ clearTimeout(t);
125
+ };
126
+ }, [open, mounted]);
127
+ return open || mounted;
128
+ }
129
+ //# sourceMappingURL=interaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction.js","sourceRoot":"","sources":["../../src/internal/interaction.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Close on Escape (topmost layer only) and on pointer-down outside every
3
+ * element in `inside`.
4
+ */
5
+ export declare function useDismiss(active: boolean, inside: Array<React.RefObject<HTMLElement | null>>, onDismiss: () => void, options?: {
6
+ outside?: boolean;
7
+ }): void;
8
+ /** Keep Tab inside `ref` while active; restore focus to the opener afterwards. */
9
+ export declare function useFocusTrap(active: boolean, ref: React.RefObject<HTMLElement | null>, restore?: boolean): void;
10
+ /** Roving focus over `selector` items inside a container (arrow keys, Home, End). */
11
+ export declare function rovingKeyDown(e: React.KeyboardEvent<HTMLElement>, selector: string, orientation?: 'horizontal' | 'vertical' | 'both'): HTMLElement | null;
12
+ //# sourceMappingURL=layers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layers.d.ts","sourceRoot":"","sources":["../../src/internal/layers.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,EAClD,SAAS,EAAE,MAAM,IAAI,EACrB,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAClC,IAAI,CA+BN;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAAE,OAAO,UAAO,GAAG,IAAI,CAiC5G;AAED,qFAAqF;AACrF,wBAAgB,aAAa,CAC3B,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,EACnC,QAAQ,EAAE,MAAM,EAChB,WAAW,GAAE,YAAY,GAAG,UAAU,GAAG,MAAmB,GAC3D,WAAW,GAAG,IAAI,CAiBpB"}
@@ -0,0 +1,108 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { focusables } from './util.js';
3
+ /** Stack of open dismissable layers, so Escape closes only the topmost. */
4
+ const stack = [];
5
+ /**
6
+ * Close on Escape (topmost layer only) and on pointer-down outside every
7
+ * element in `inside`.
8
+ */
9
+ export function useDismiss(active, inside, onDismiss, options = {}) {
10
+ const cb = useRef(onDismiss);
11
+ cb.current = onDismiss;
12
+ const insideRef = useRef(inside);
13
+ insideRef.current = inside;
14
+ const outside = options.outside ?? true;
15
+ useEffect(() => {
16
+ if (!active)
17
+ return;
18
+ const id = Symbol('layer');
19
+ stack.push(id);
20
+ const onKey = (e) => {
21
+ if (e.key === 'Escape' && stack[stack.length - 1] === id) {
22
+ e.stopPropagation();
23
+ cb.current();
24
+ }
25
+ };
26
+ const onPointer = (e) => {
27
+ if (!outside || stack[stack.length - 1] !== id)
28
+ return;
29
+ const t = e.target;
30
+ if (t && insideRef.current.some((r) => r.current?.contains(t)))
31
+ return;
32
+ cb.current();
33
+ };
34
+ document.addEventListener('keydown', onKey);
35
+ document.addEventListener('pointerdown', onPointer);
36
+ return () => {
37
+ document.removeEventListener('keydown', onKey);
38
+ document.removeEventListener('pointerdown', onPointer);
39
+ const i = stack.indexOf(id);
40
+ if (i >= 0)
41
+ stack.splice(i, 1);
42
+ };
43
+ }, [active, outside]);
44
+ }
45
+ /** Keep Tab inside `ref` while active; restore focus to the opener afterwards. */
46
+ export function useFocusTrap(active, ref, restore = true) {
47
+ useEffect(() => {
48
+ if (!active)
49
+ return;
50
+ const el = ref.current;
51
+ if (!el)
52
+ return;
53
+ const previous = document.activeElement;
54
+ const auto = el.querySelector('[data-autofocus]') ?? focusables(el)[0] ?? el;
55
+ auto.focus();
56
+ const onKey = (e) => {
57
+ if (e.key !== 'Tab')
58
+ return;
59
+ const items = focusables(el);
60
+ if (items.length === 0) {
61
+ e.preventDefault();
62
+ el.focus();
63
+ return;
64
+ }
65
+ const first = items[0];
66
+ const last = items[items.length - 1];
67
+ const current = document.activeElement;
68
+ if (e.shiftKey && (current === first || current === el)) {
69
+ e.preventDefault();
70
+ last?.focus();
71
+ }
72
+ else if (!e.shiftKey && current === last) {
73
+ e.preventDefault();
74
+ first?.focus();
75
+ }
76
+ };
77
+ el.addEventListener('keydown', onKey);
78
+ return () => {
79
+ el.removeEventListener('keydown', onKey);
80
+ if (restore && previous && document.contains(previous))
81
+ previous.focus();
82
+ };
83
+ }, [active, ref, restore]);
84
+ }
85
+ /** Roving focus over `selector` items inside a container (arrow keys, Home, End). */
86
+ export function rovingKeyDown(e, selector, orientation = 'vertical') {
87
+ const items = Array.from(e.currentTarget.querySelectorAll(selector)).filter((el) => !el.hasAttribute('disabled') && el.getAttribute('aria-disabled') !== 'true');
88
+ if (items.length === 0)
89
+ return null;
90
+ const i = items.indexOf(document.activeElement);
91
+ const next = (orientation !== 'horizontal' && e.key === 'ArrowDown') || (orientation !== 'vertical' && e.key === 'ArrowRight');
92
+ const prev = (orientation !== 'horizontal' && e.key === 'ArrowUp') || (orientation !== 'vertical' && e.key === 'ArrowLeft');
93
+ let target;
94
+ if (next)
95
+ target = items[(i + 1) % items.length];
96
+ else if (prev)
97
+ target = items[(i - 1 + items.length) % items.length];
98
+ else if (e.key === 'Home')
99
+ target = items[0];
100
+ else if (e.key === 'End')
101
+ target = items[items.length - 1];
102
+ if (!target)
103
+ return null;
104
+ e.preventDefault();
105
+ target.focus();
106
+ return target;
107
+ }
108
+ //# sourceMappingURL=layers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layers.js","sourceRoot":"","sources":["../../src/internal/layers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export type Size = 'sm' | 'md' | 'lg' | 'xl';
2
+ export type Tone = 'neutral' | 'signal';
3
+ export declare function cx(...parts: Array<string | false | null | undefined>): string;
4
+ /** Controlled/uncontrolled state: `value` wins when defined. */
5
+ export declare function useControllable<T>(value: T | undefined, defaultValue: T, onChange?: (next: T) => void): [T, (next: T) => void];
6
+ export declare const FOCUSABLE = "a[href],button:not([disabled]),input:not([disabled]):not([type=\"hidden\"]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex=\"-1\"]),[contenteditable=\"true\"]";
7
+ export declare function focusables(root: HTMLElement): HTMLElement[];
8
+ export declare function mergeRefs<T>(...refs: Array<React.Ref<T> | undefined>): React.RefCallback<T>;
9
+ //# sourceMappingURL=util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/internal/util.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAC7C,MAAM,MAAM,IAAI,GAAG,SAAS,GAAG,QAAQ,CAAC;AAExC,wBAAgB,EAAE,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,CAE7E;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,CAAC,EAC/B,KAAK,EAAE,CAAC,GAAG,SAAS,EACpB,YAAY,EAAE,CAAC,EACf,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,GAC3B,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,CAcxB;AAED,eAAO,MAAM,SAAS,6LACgK,CAAC;AAEvL,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,EAAE,CAI3D;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAO3F"}
@@ -0,0 +1,33 @@
1
+ import { useCallback, useRef, useState } from 'react';
2
+ export function cx(...parts) {
3
+ return parts.filter(Boolean).join(' ');
4
+ }
5
+ /** Controlled/uncontrolled state: `value` wins when defined. */
6
+ export function useControllable(value, defaultValue, onChange) {
7
+ const [inner, setInner] = useState(defaultValue);
8
+ const controlled = value !== undefined;
9
+ const current = controlled ? value : inner;
10
+ const ref = useRef(onChange);
11
+ ref.current = onChange;
12
+ const set = useCallback((next) => {
13
+ if (!controlled)
14
+ setInner(next);
15
+ ref.current?.(next);
16
+ }, [controlled]);
17
+ return [current, set];
18
+ }
19
+ export const FOCUSABLE = 'a[href],button:not([disabled]),input:not([disabled]):not([type="hidden"]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"]),[contenteditable="true"]';
20
+ export function focusables(root) {
21
+ return Array.from(root.querySelectorAll(FOCUSABLE)).filter((el) => !el.hasAttribute('inert') && el.getAttribute('aria-hidden') !== 'true');
22
+ }
23
+ export function mergeRefs(...refs) {
24
+ return (node) => {
25
+ for (const ref of refs) {
26
+ if (typeof ref === 'function')
27
+ ref(node);
28
+ else if (ref)
29
+ ref.current = node;
30
+ }
31
+ };
32
+ }
33
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/internal/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAKtD,MAAM,UAAU,EAAE,CAAC,GAAG,KAA+C;IACnE,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,eAAe,CAC7B,KAAoB,EACpB,YAAe,EACf,QAA4B;IAE5B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAI,YAAY,CAAC,CAAC;IACpD,MAAM,UAAU,GAAG,KAAK,KAAK,SAAS,CAAC;IACvC,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IAC3C,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7B,GAAG,CAAC,OAAO,GAAG,QAAQ,CAAC;IACvB,MAAM,GAAG,GAAG,WAAW,CACrB,CAAC,IAAO,EAAE,EAAE;QACV,IAAI,CAAC,UAAU;YAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChC,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC,EACD,CAAC,UAAU,CAAC,CACb,CAAC;IACF,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GACpB,oLAAoL,CAAC;AAEvL,MAAM,UAAU,UAAU,CAAC,IAAiB;IAC1C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAc,SAAS,CAAC,CAAC,CAAC,MAAM,CACrE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC,KAAK,MAAM,CAC/E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAI,GAAG,IAAqC;IACnE,OAAO,CAAC,IAAI,EAAE,EAAE;QACd,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,OAAO,GAAG,KAAK,UAAU;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC;iBACpC,IAAI,GAAG;gBAAG,GAAiC,CAAC,OAAO,GAAG,IAAI,CAAC;QAClE,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,34 @@
1
+ type Space = 0 | 2 | 4 | 6 | 8 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 64;
2
+ export interface StackProps extends React.HTMLAttributes<HTMLElement> {
3
+ direction?: 'row' | 'column';
4
+ gap?: Space;
5
+ align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline';
6
+ justify?: 'start' | 'center' | 'end' | 'between';
7
+ wrap?: boolean;
8
+ as?: 'div' | 'section' | 'ul' | 'ol' | 'header' | 'footer' | 'nav' | 'main' | 'form';
9
+ }
10
+ export declare function Stack({ direction, gap, align, justify, wrap, as: Tag, className, style, ...rest }: StackProps): import("react/jsx-runtime").JSX.Element;
11
+ export interface GridProps extends React.HTMLAttributes<HTMLDivElement> {
12
+ /** A column count, or a minimum column width for an auto-fill grid. */
13
+ columns?: number | {
14
+ min: number;
15
+ };
16
+ gap?: Space;
17
+ }
18
+ export declare function Grid({ columns, gap, className, style, ...rest }: GridProps): import("react/jsx-runtime").JSX.Element;
19
+ export interface AppShellProps extends React.HTMLAttributes<HTMLDivElement> {
20
+ sidebar?: React.ReactNode;
21
+ topBar?: React.ReactNode;
22
+ /** Id of <main>, the target for a skip link. */
23
+ mainId?: string;
24
+ skipLabel?: string;
25
+ }
26
+ /** Sidebar, top bar and a single <main> landmark, with a skip link. */
27
+ export declare function AppShell({ sidebar, topBar, mainId, skipLabel, className, children, ...rest }: AppShellProps): import("react/jsx-runtime").JSX.Element;
28
+ export interface TopBarProps extends React.HTMLAttributes<HTMLElement> {
29
+ start?: React.ReactNode;
30
+ end?: React.ReactNode;
31
+ }
32
+ export declare function TopBar({ start, end, className, children, ...rest }: TopBarProps): import("react/jsx-runtime").JSX.Element;
33
+ export {};
34
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.tsx"],"names":[],"mappings":"AAGA,KAAK,KAAK,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAKvE,MAAM,WAAW,UAAW,SAAQ,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC;IACnE,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC7B,GAAG,CAAC,EAAE,KAAK,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,GAAG,UAAU,CAAC;IAC5D,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;IACjD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,EAAE,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;CACtF;AAID,wBAAgB,KAAK,CAAC,EAAE,SAAoB,EAAE,GAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAY,EAAE,EAAE,EAAE,GAAW,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE,UAAU,2CAe5I;AAID,MAAM,WAAW,SAAU,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACrE,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,GAAG,CAAC,EAAE,KAAK,CAAC;CACb;AAED,wBAAgB,IAAI,CAAC,EAAE,OAAW,EAAE,GAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE,SAAS,2CAGnF;AAID,MAAM,WAAW,aAAc,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACzE,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,MAAkB,EAAE,SAA6B,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,aAAa,2CAe3I;AAED,MAAM,WAAW,WAAY,SAAQ,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC;IACpE,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,GAAG,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACvB;AAED,wBAAgB,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,WAAW,2CAQ/E"}
package/dist/layout.js ADDED
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Server-component safe: no state, no context.
3
+ import { cx } from './internal/util.js';
4
+ const space = (n) => (n === undefined ? undefined : n === 0 ? '0' : `var(--ns-space-${n})`);
5
+ const flex = { start: 'flex-start', end: 'flex-end', center: 'center', stretch: 'stretch', baseline: 'baseline', between: 'space-between' };
6
+ export function Stack({ direction = 'column', gap = 8, align, justify, wrap = false, as: Tag = 'div', className, style, ...rest }) {
7
+ return (_jsx(Tag, { ...rest, className: cx('ns-stack', className), style: {
8
+ flexDirection: direction,
9
+ gap: space(gap),
10
+ alignItems: align && flex[align],
11
+ justifyContent: justify && flex[justify],
12
+ flexWrap: wrap ? 'wrap' : undefined,
13
+ ...style,
14
+ } }));
15
+ }
16
+ export function Grid({ columns = 2, gap = 16, className, style, ...rest }) {
17
+ const template = typeof columns === 'number' ? `repeat(${columns}, minmax(0, 1fr))` : `repeat(auto-fill, minmax(${columns.min}px, 1fr))`;
18
+ return _jsx("div", { ...rest, className: cx('ns-grid', className), style: { gridTemplateColumns: template, gap: space(gap), ...style } });
19
+ }
20
+ /** Sidebar, top bar and a single <main> landmark, with a skip link. */
21
+ export function AppShell({ sidebar, topBar, mainId = 'ns-main', skipLabel = 'Skip to content', className, children, ...rest }) {
22
+ return (_jsxs("div", { ...rest, className: cx('ns-app-shell', !sidebar && 'ns-app-shell--no-sidebar', className), children: [_jsx("a", { className: "ns-skip-link", href: `#${mainId}`, children: skipLabel }), sidebar && _jsx("div", { className: "ns-app-shell__sidebar", children: sidebar }), _jsxs("div", { className: "ns-app-shell__column", children: [topBar, _jsx("main", { id: mainId, className: "ns-app-shell__main", tabIndex: -1, children: children })] })] }));
23
+ }
24
+ export function TopBar({ start, end, className, children, ...rest }) {
25
+ return (_jsxs("header", { ...rest, className: cx('ns-top-bar', className), children: [start && _jsx("div", { className: "ns-top-bar__start", children: start }), _jsx("div", { className: "ns-top-bar__center", children: children }), end && _jsx("div", { className: "ns-top-bar__end", children: end })] }));
26
+ }
27
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ export declare function prefersReducedMotion(): boolean;
2
+ /** True where the View Transitions API is available and motion is allowed. */
3
+ export declare function canViewTransition(): boolean;
4
+ /**
5
+ * Runs a React state update inside `document.startViewTransition` where it is
6
+ * supported (flushing synchronously so the new DOM is captured), and plainly
7
+ * everywhere else. With `scope`, only that element is named for the
8
+ * transition (as `name`, default `ns-step`) and only while it runs, so several
9
+ * instances on one page never clash. Returns true when a view transition ran.
10
+ */
11
+ export declare function withViewTransition(update: () => void, scope?: HTMLElement | null, name?: string): boolean;
12
+ /** A stable callback version of `withViewTransition`. */
13
+ export declare function useViewTransition(): (update: () => void, scope?: HTMLElement | null, name?: string) => boolean;
14
+ type RevealTag = 'div' | 'section' | 'article' | 'li' | 'ul' | 'ol' | 'span' | 'header' | 'footer';
15
+ export interface RevealProps extends React.HTMLAttributes<HTMLElement> {
16
+ /** Stagger the direct children in sequence instead of revealing as one block. */
17
+ stagger?: boolean;
18
+ /** Extra delay before the reveal, in ms. */
19
+ delay?: number;
20
+ /** How the content arrives. Default `rise`. */
21
+ effect?: 'rise' | 'fade' | 'scale';
22
+ /** Reveal again each time it re-enters the viewport. Default false. */
23
+ repeat?: boolean;
24
+ /** Fraction of the element visible before it reveals. Default 0.15. */
25
+ threshold?: number;
26
+ as?: RevealTag;
27
+ ref?: React.Ref<HTMLElement>;
28
+ }
29
+ /**
30
+ * Fades and rises its content in when it scrolls into view. The server HTML
31
+ * and no-JS render are fully visible: the element is only held back once the
32
+ * observer is attached. Under reduced motion it shows at once.
33
+ */
34
+ export declare function Reveal({ stagger, delay, effect, repeat, threshold, as: Tag, className, style, ref, ...rest }: RevealProps): import("react/jsx-runtime").JSX.Element;
35
+ export {};
36
+ //# sourceMappingURL=motion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"motion.d.ts","sourceRoot":"","sources":["../src/motion.tsx"],"names":[],"mappings":"AAQA,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAID,8EAA8E;AAC9E,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,EAAE,IAAI,SAAY,GAAG,OAAO,CAgB5G;AAED,yDAAyD;AACzD,wBAAgB,iBAAiB,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAE9G;AAED,KAAK,SAAS,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEnG,MAAM,WAAW,WAAY,SAAQ,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC;IACpE,iFAAiF;IACjF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACnC,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,SAAS,CAAC;IACf,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,EAAE,OAAe,EAAE,KAAS,EAAE,MAAe,EAAE,MAAc,EAAE,SAAgB,EAAE,EAAE,EAAE,GAAW,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,WAAW,2CAkCrK"}
package/dist/motion.js ADDED
@@ -0,0 +1,80 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ // Motion utilities without a motion library: a scroll-linked Reveal on
4
+ // IntersectionObserver, and a View Transitions wrapper for step and tab
5
+ // changes. Both do nothing visible under prefers-reduced-motion.
6
+ import { useCallback, useEffect, useRef } from 'react';
7
+ import { flushSync } from 'react-dom';
8
+ import { cx, mergeRefs } from './internal/util.js';
9
+ export function prefersReducedMotion() {
10
+ return typeof window !== 'undefined' && !!window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
11
+ }
12
+ /** True where the View Transitions API is available and motion is allowed. */
13
+ export function canViewTransition() {
14
+ return typeof document !== 'undefined' && typeof document.startViewTransition === 'function' && !prefersReducedMotion();
15
+ }
16
+ /**
17
+ * Runs a React state update inside `document.startViewTransition` where it is
18
+ * supported (flushing synchronously so the new DOM is captured), and plainly
19
+ * everywhere else. With `scope`, only that element is named for the
20
+ * transition (as `name`, default `ns-step`) and only while it runs, so several
21
+ * instances on one page never clash. Returns true when a view transition ran.
22
+ */
23
+ export function withViewTransition(update, scope, name = 'ns-step') {
24
+ if (!canViewTransition()) {
25
+ update();
26
+ return false;
27
+ }
28
+ if (scope)
29
+ scope.style.setProperty('view-transition-name', name);
30
+ try {
31
+ const t = document.startViewTransition(() => flushSync(update));
32
+ const clear = () => scope?.style.removeProperty('view-transition-name');
33
+ t.finished.then(clear, clear);
34
+ }
35
+ catch {
36
+ scope?.style.removeProperty('view-transition-name');
37
+ update();
38
+ return false;
39
+ }
40
+ return true;
41
+ }
42
+ /** A stable callback version of `withViewTransition`. */
43
+ export function useViewTransition() {
44
+ return useCallback((update, scope, name) => withViewTransition(update, scope, name), []);
45
+ }
46
+ /**
47
+ * Fades and rises its content in when it scrolls into view. The server HTML
48
+ * and no-JS render are fully visible: the element is only held back once the
49
+ * observer is attached. Under reduced motion it shows at once.
50
+ */
51
+ export function Reveal({ stagger = false, delay = 0, effect = 'rise', repeat = false, threshold = 0.15, as: Tag = 'div', className, style, ref, ...rest }) {
52
+ const node = useRef(null);
53
+ useEffect(() => {
54
+ const el = node.current;
55
+ if (!el)
56
+ return;
57
+ if (typeof IntersectionObserver === 'undefined' || prefersReducedMotion()) {
58
+ el.setAttribute('data-reveal', 'in');
59
+ return;
60
+ }
61
+ el.setAttribute('data-reveal', 'pending');
62
+ const io = new IntersectionObserver((entries) => {
63
+ for (const e of entries) {
64
+ if (e.isIntersecting) {
65
+ el.setAttribute('data-reveal', 'in');
66
+ if (!repeat)
67
+ io.disconnect();
68
+ }
69
+ else if (repeat)
70
+ el.setAttribute('data-reveal', 'pending');
71
+ }
72
+ }, { threshold, rootMargin: '0px 0px -8% 0px' });
73
+ io.observe(el);
74
+ return () => io.disconnect();
75
+ }, [repeat, threshold]);
76
+ return (_jsx(Tag, { ...rest, ref: mergeRefs(ref, (el) => {
77
+ node.current = el;
78
+ }), className: cx('ns-reveal', `ns-reveal--${effect}`, stagger && 'ns-reveal--stagger', className), style: delay ? { '--ns-reveal-delay': `${delay}ms`, ...style } : style }));
79
+ }
80
+ //# sourceMappingURL=motion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"motion.js","sourceRoot":"","sources":["../src/motion.tsx"],"names":[],"mappings":"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"}