@newtonedev/components 0.1.12 → 0.1.13

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 (149) hide show
  1. package/dist/_COMPONENT_TEMPLATE/ComponentName.styles.d.ts +3 -2
  2. package/dist/_COMPONENT_TEMPLATE/ComponentName.styles.d.ts.map +1 -1
  3. package/dist/_COMPONENT_TEMPLATE/ComponentName.types.d.ts +1 -1
  4. package/dist/_COMPONENT_TEMPLATE/ComponentName.types.d.ts.map +1 -1
  5. package/dist/composites/actions/Button/Button.styles.d.ts +1 -1
  6. package/dist/composites/actions/Button/Button.styles.d.ts.map +1 -1
  7. package/dist/composites/form-controls/Select/Select.d.ts.map +1 -1
  8. package/dist/composites/form-controls/Select/Select.styles.d.ts +2 -2
  9. package/dist/composites/form-controls/Select/Select.styles.d.ts.map +1 -1
  10. package/dist/composites/form-controls/Select/SelectOption.d.ts.map +1 -1
  11. package/dist/composites/form-controls/TextInput/TextInput.d.ts.map +1 -1
  12. package/dist/composites/form-controls/TextInput/TextInput.styles.d.ts +2 -2
  13. package/dist/composites/form-controls/TextInput/TextInput.styles.d.ts.map +1 -1
  14. package/dist/composites/form-controls/Toggle/Toggle.styles.d.ts +2 -2
  15. package/dist/composites/form-controls/Toggle/Toggle.styles.d.ts.map +1 -1
  16. package/dist/composites/layout/AppShell/AppShell.styles.d.ts +2 -2
  17. package/dist/composites/layout/AppShell/AppShell.styles.d.ts.map +1 -1
  18. package/dist/composites/layout/Card/Card.styles.d.ts +2 -2
  19. package/dist/composites/layout/Card/Card.styles.d.ts.map +1 -1
  20. package/dist/composites/layout/Card/Card.types.d.ts +1 -1
  21. package/dist/composites/layout/Card/Card.types.d.ts.map +1 -1
  22. package/dist/composites/layout/Navbar/Navbar.styles.d.ts +3 -2
  23. package/dist/composites/layout/Navbar/Navbar.styles.d.ts.map +1 -1
  24. package/dist/composites/layout/Sidebar/Sidebar.styles.d.ts +3 -2
  25. package/dist/composites/layout/Sidebar/Sidebar.styles.d.ts.map +1 -1
  26. package/dist/composites/overlays/Popover/Popover.styles.d.ts +2 -2
  27. package/dist/composites/overlays/Popover/Popover.styles.d.ts.map +1 -1
  28. package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.d.ts +1 -1
  29. package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.d.ts.map +1 -1
  30. package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.styles.d.ts +2 -2
  31. package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.styles.d.ts.map +1 -1
  32. package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.types.d.ts +2 -0
  33. package/dist/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.types.d.ts.map +1 -1
  34. package/dist/composites/range-inputs/HueSlider/HueSlider.d.ts +3 -4
  35. package/dist/composites/range-inputs/HueSlider/HueSlider.d.ts.map +1 -1
  36. package/dist/composites/range-inputs/HueSlider/HueSlider.styles.d.ts +4 -4
  37. package/dist/composites/range-inputs/HueSlider/HueSlider.styles.d.ts.map +1 -1
  38. package/dist/composites/range-inputs/Slider/Slider.styles.d.ts +2 -2
  39. package/dist/composites/range-inputs/Slider/Slider.styles.d.ts.map +1 -1
  40. package/dist/index.cjs +1232 -1823
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.ts +12 -24
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +1084 -1737
  45. package/dist/index.js.map +1 -1
  46. package/dist/primitives/Frame/Frame.d.ts.map +1 -1
  47. package/dist/primitives/Frame/Frame.styles.d.ts +3 -2
  48. package/dist/primitives/Frame/Frame.styles.d.ts.map +1 -1
  49. package/dist/primitives/Frame/Frame.types.d.ts +1 -1
  50. package/dist/primitives/Frame/Frame.types.d.ts.map +1 -1
  51. package/dist/primitives/Frame/Frame.utils.d.ts +1 -1
  52. package/dist/primitives/Frame/Frame.utils.d.ts.map +1 -1
  53. package/dist/primitives/Icon/Icon.d.ts.map +1 -1
  54. package/dist/primitives/Text/Text.d.ts +1 -1
  55. package/dist/primitives/Text/Text.d.ts.map +1 -1
  56. package/dist/primitives/Text/Text.types.d.ts +1 -1
  57. package/dist/primitives/Text/Text.types.d.ts.map +1 -1
  58. package/dist/primitives/Wrapper/Wrapper.styles.d.ts +1 -1
  59. package/dist/primitives/Wrapper/Wrapper.styles.d.ts.map +1 -1
  60. package/package.json +3 -2
  61. package/src/_COMPONENT_TEMPLATE/ComponentName.styles.ts +4 -4
  62. package/src/_COMPONENT_TEMPLATE/ComponentName.tsx +2 -2
  63. package/src/_COMPONENT_TEMPLATE/ComponentName.types.ts +1 -1
  64. package/src/composites/actions/Button/Button.styles.ts +37 -36
  65. package/src/composites/actions/Button/Button.tsx +1 -1
  66. package/src/composites/form-controls/Select/Select.styles.ts +8 -8
  67. package/src/composites/form-controls/Select/Select.tsx +4 -5
  68. package/src/composites/form-controls/Select/SelectOption.tsx +7 -8
  69. package/src/composites/form-controls/TextInput/TextInput.styles.ts +7 -8
  70. package/src/composites/form-controls/TextInput/TextInput.tsx +3 -4
  71. package/src/composites/form-controls/Toggle/Toggle.styles.ts +6 -6
  72. package/src/composites/form-controls/Toggle/Toggle.tsx +2 -2
  73. package/src/composites/layout/AppShell/AppShell.styles.ts +3 -4
  74. package/src/composites/layout/AppShell/AppShell.tsx +2 -2
  75. package/src/composites/layout/Card/Card.styles.ts +4 -5
  76. package/src/composites/layout/Card/Card.tsx +2 -2
  77. package/src/composites/layout/Card/Card.types.ts +1 -1
  78. package/src/composites/layout/Navbar/Navbar.styles.ts +5 -5
  79. package/src/composites/layout/Navbar/Navbar.tsx +2 -2
  80. package/src/composites/layout/Sidebar/Sidebar.styles.ts +5 -5
  81. package/src/composites/layout/Sidebar/Sidebar.tsx +2 -2
  82. package/src/composites/overlays/Popover/Popover.styles.ts +4 -4
  83. package/src/composites/overlays/Popover/Popover.tsx +2 -2
  84. package/src/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.styles.ts +5 -6
  85. package/src/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.tsx +6 -3
  86. package/src/composites/range-inputs/ColorScaleSlider/ColorScaleSlider.types.ts +2 -0
  87. package/src/composites/range-inputs/HueSlider/HueSlider.styles.ts +14 -21
  88. package/src/composites/range-inputs/HueSlider/HueSlider.tsx +8 -9
  89. package/src/composites/range-inputs/Slider/Slider.styles.ts +9 -10
  90. package/src/composites/range-inputs/Slider/Slider.tsx +2 -2
  91. package/src/index.ts +73 -60
  92. package/src/primitives/Frame/Frame.styles.ts +8 -7
  93. package/src/primitives/Frame/Frame.tsx +9 -9
  94. package/src/primitives/Frame/Frame.types.ts +1 -1
  95. package/src/primitives/Frame/Frame.utils.ts +1 -1
  96. package/src/primitives/Icon/Icon.tsx +2 -3
  97. package/src/primitives/Text/Text.spans.ts +1 -1
  98. package/src/primitives/Text/Text.tsx +16 -16
  99. package/src/primitives/Text/Text.types.ts +1 -1
  100. package/src/primitives/Wrapper/Wrapper.styles.ts +1 -1
  101. package/src/primitives/Wrapper/Wrapper.tsx +1 -1
  102. package/dist/fonts/GoogleFontLoader.d.ts +0 -20
  103. package/dist/fonts/GoogleFontLoader.d.ts.map +0 -1
  104. package/dist/fonts/IconFontLoader.d.ts +0 -13
  105. package/dist/fonts/IconFontLoader.d.ts.map +0 -1
  106. package/dist/fonts/SelfHostedFontLoader.d.ts +0 -14
  107. package/dist/fonts/SelfHostedFontLoader.d.ts.map +0 -1
  108. package/dist/fonts/buildGoogleFontsUrl.d.ts +0 -2
  109. package/dist/fonts/buildGoogleFontsUrl.d.ts.map +0 -1
  110. package/dist/fonts/measureFont.d.ts +0 -19
  111. package/dist/fonts/measureFont.d.ts.map +0 -1
  112. package/dist/fonts/reportQueue.d.ts +0 -7
  113. package/dist/fonts/reportQueue.d.ts.map +0 -1
  114. package/dist/fonts/useLocalCalibration.d.ts +0 -19
  115. package/dist/fonts/useLocalCalibration.d.ts.map +0 -1
  116. package/dist/fonts/useTypographyCalibrations.d.ts +0 -11
  117. package/dist/fonts/useTypographyCalibrations.d.ts.map +0 -1
  118. package/dist/theme/FrameContext.d.ts +0 -26
  119. package/dist/theme/FrameContext.d.ts.map +0 -1
  120. package/dist/theme/NewtoneProvider.d.ts +0 -40
  121. package/dist/theme/NewtoneProvider.d.ts.map +0 -1
  122. package/dist/theme/defaults.d.ts +0 -8
  123. package/dist/theme/defaults.d.ts.map +0 -1
  124. package/dist/theme/types.d.ts +0 -156
  125. package/dist/theme/types.d.ts.map +0 -1
  126. package/dist/theme/useBreakpoint.d.ts +0 -9
  127. package/dist/theme/useBreakpoint.d.ts.map +0 -1
  128. package/dist/tokens/computeTokens.d.ts +0 -151
  129. package/dist/tokens/computeTokens.d.ts.map +0 -1
  130. package/dist/tokens/types.d.ts +0 -162
  131. package/dist/tokens/types.d.ts.map +0 -1
  132. package/dist/tokens/useTokens.d.ts +0 -26
  133. package/dist/tokens/useTokens.d.ts.map +0 -1
  134. package/src/fonts/GoogleFontLoader.tsx +0 -80
  135. package/src/fonts/IconFontLoader.tsx +0 -51
  136. package/src/fonts/SelfHostedFontLoader.tsx +0 -44
  137. package/src/fonts/buildGoogleFontsUrl.ts +0 -2
  138. package/src/fonts/measureFont.ts +0 -55
  139. package/src/fonts/reportQueue.ts +0 -54
  140. package/src/fonts/useLocalCalibration.ts +0 -97
  141. package/src/fonts/useTypographyCalibrations.ts +0 -15
  142. package/src/theme/FrameContext.tsx +0 -31
  143. package/src/theme/NewtoneProvider.tsx +0 -84
  144. package/src/theme/defaults.ts +0 -71
  145. package/src/theme/types.ts +0 -191
  146. package/src/theme/useBreakpoint.ts +0 -14
  147. package/src/tokens/computeTokens.ts +0 -516
  148. package/src/tokens/types.ts +0 -146
  149. package/src/tokens/useTokens.ts +0 -62
package/dist/index.cjs CHANGED
@@ -1,830 +1,510 @@
1
1
  'use strict';
2
2
 
3
- var React14 = require('react');
4
- var newtone = require('newtone');
5
- var fonts = require('@newtonedev/fonts');
3
+ var newtoneApi = require('newtone-api');
4
+ var React13 = require('react');
6
5
  var reactNative = require('react-native');
6
+ var fonts = require('@newtonedev/fonts');
7
+ var newtone = require('newtone');
7
8
 
8
9
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
10
 
10
- var React14__default = /*#__PURE__*/_interopDefault(React14);
11
-
12
- // src/theme/NewtoneProvider.tsx
13
- var DEFAULT_THEME_CONFIG = {
14
- colorSystem: {
15
- dynamicRange: {
16
- lightest: 1,
17
- darkest: 1
18
- },
19
- palettes: [
20
- { hue: newtone.DEFAULT_NEUTRAL_HUE, saturation: newtone.DEFAULT_NEUTRAL_SATURATION },
21
- { hue: newtone.DEFAULT_ACCENT_HUE, saturation: newtone.DEFAULT_ACCENT_SATURATION },
22
- { hue: newtone.DEFAULT_SUCCESS_HUE, saturation: newtone.DEFAULT_SUCCESS_SATURATION },
23
- { hue: newtone.DEFAULT_WARNING_HUE, saturation: newtone.DEFAULT_WARNING_SATURATION },
24
- { hue: newtone.DEFAULT_ERROR_HUE, saturation: newtone.DEFAULT_ERROR_SATURATION }
25
- ]
26
- },
27
- spacing: {
28
- "00": 0,
29
- // base * 0
30
- "02": 2,
31
- // base * 0.25
32
- "04": 4,
33
- // base * 0.5
34
- "06": 6,
35
- // base * 0.75
36
- "08": 8,
37
- // base * 1 (Medium preset, 8px base)
38
- "10": 10,
39
- // base * 1.25
40
- "12": 12,
41
- // base * 1.5
42
- "16": 16,
43
- // base * 2
44
- "20": 20,
45
- // base * 2.5
46
- "24": 24,
47
- // base * 3
48
- "32": 32,
49
- // base * 4
50
- "40": 40,
51
- // base * 5
52
- "48": 48
53
- // base * 6
54
- },
55
- radius: {
56
- none: 0,
57
- sm: 4,
58
- md: 6,
59
- lg: 8,
60
- xl: 12,
61
- pill: 999
62
- },
63
- typography: {
64
- fonts: fonts.DEFAULT_FONT_SLOTS,
65
- fontSizes: fonts.DEFAULT_FONT_SIZES,
66
- lineHeights: fonts.DEFAULT_LINE_HEIGHTS,
67
- roles: fonts.DEFAULT_ROLE_SCALES
68
- },
69
- icons: {
70
- variant: "rounded",
71
- // Material Design 3 aesthetic
72
- weight: 400,
73
- // Normal weight
74
- autoGrade: true
75
- // Enable mode-aware grade
76
- }
77
- };
11
+ var React13__default = /*#__PURE__*/_interopDefault(React13);
78
12
 
79
- // src/fonts/GoogleFontLoader.tsx
80
- function GoogleFontLoader({ fonts: fonts$1 }) {
81
- const linkRef = React14.useRef(null);
82
- React14.useEffect(() => {
83
- if (typeof document === "undefined") return;
84
- const url = fonts.buildGoogleFontsUrl(fonts$1);
85
- if (linkRef.current) {
86
- linkRef.current.remove();
87
- linkRef.current = null;
88
- }
89
- if (!url) return;
90
- const links = Array.from(document.head.querySelectorAll('link[rel="stylesheet"]'));
91
- if (links.some((el) => el.href === url)) return;
92
- const link = document.createElement("link");
93
- link.rel = "stylesheet";
94
- link.href = url;
95
- document.head.appendChild(link);
96
- linkRef.current = link;
97
- return () => {
98
- if (linkRef.current) {
99
- linkRef.current.remove();
100
- linkRef.current = null;
101
- }
102
- };
103
- }, [
104
- fonts$1.main.config.family,
105
- fonts$1.main.config.type,
106
- fonts$1.main.weights.regular,
107
- fonts$1.main.weights.medium,
108
- fonts$1.main.weights.bold,
109
- fonts$1.display.config.family,
110
- fonts$1.display.config.type,
111
- fonts$1.display.weights.regular,
112
- fonts$1.display.weights.medium,
113
- fonts$1.display.weights.bold,
114
- fonts$1.mono.config.family,
115
- fonts$1.mono.config.type,
116
- fonts$1.mono.weights.regular,
117
- fonts$1.mono.weights.medium,
118
- fonts$1.mono.weights.bold,
119
- fonts$1.currency.config.family,
120
- fonts$1.currency.config.type,
121
- fonts$1.currency.weights.regular,
122
- fonts$1.currency.weights.medium,
123
- fonts$1.currency.weights.bold
13
+ // src/index.ts
14
+ var hadKeyboardEvent = false;
15
+ var isListenerSetup = false;
16
+ function setupModality() {
17
+ if (isListenerSetup || typeof document === "undefined") return;
18
+ isListenerSetup = true;
19
+ const NAVIGATION_KEYS = /* @__PURE__ */ new Set([
20
+ "Tab",
21
+ "ArrowUp",
22
+ "ArrowDown",
23
+ "ArrowLeft",
24
+ "ArrowRight",
25
+ "Enter",
26
+ " ",
27
+ "Escape"
124
28
  ]);
125
- return null;
126
- }
127
- function SelfHostedFontLoader({ fontFaceCss }) {
128
- const styleRef = React14.useRef(null);
129
- React14.useEffect(() => {
130
- if (typeof document === "undefined") return;
131
- if (styleRef.current) {
132
- styleRef.current.remove();
133
- styleRef.current = null;
29
+ document.addEventListener("keydown", (e) => {
30
+ if (NAVIGATION_KEYS.has(e.key)) {
31
+ hadKeyboardEvent = true;
134
32
  }
135
- if (!fontFaceCss) return;
136
- const style = document.createElement("style");
137
- style.setAttribute("data-newtone-fonts", "self-hosted");
138
- style.textContent = fontFaceCss;
139
- document.head.appendChild(style);
140
- styleRef.current = style;
141
- return () => {
142
- if (styleRef.current) {
143
- styleRef.current.remove();
144
- styleRef.current = null;
145
- }
146
- };
147
- }, [fontFaceCss]);
148
- return null;
33
+ }, true);
34
+ document.addEventListener("pointerdown", () => {
35
+ hadKeyboardEvent = false;
36
+ }, true);
37
+ document.addEventListener("mousedown", () => {
38
+ hadKeyboardEvent = false;
39
+ }, true);
149
40
  }
150
- function IconFontLoader({ icons }) {
151
- const linkRef = React14.useRef(null);
152
- React14.useEffect(() => {
153
- if (typeof document === "undefined") return;
154
- const variantName = icons.variant.charAt(0).toUpperCase() + icons.variant.slice(1);
155
- const family = `Material+Symbols+${variantName}`;
156
- const url = `https://fonts.googleapis.com/css2?family=${family}:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=block`;
157
- if (linkRef.current) {
158
- linkRef.current.remove();
159
- linkRef.current = null;
41
+ function useFocusVisible() {
42
+ const [isFocusVisible, setIsFocusVisible] = React13.useState(false);
43
+ React13.useEffect(() => {
44
+ setupModality();
45
+ }, []);
46
+ const onFocus = React13.useCallback(() => {
47
+ if (hadKeyboardEvent) {
48
+ setIsFocusVisible(true);
160
49
  }
161
- const links = Array.from(document.head.querySelectorAll('link[rel="stylesheet"]'));
162
- if (links.some((el) => el.href === url)) return;
163
- const link = document.createElement("link");
164
- link.rel = "stylesheet";
165
- link.href = url;
166
- document.head.appendChild(link);
167
- linkRef.current = link;
168
- return () => {
169
- if (linkRef.current) {
170
- linkRef.current.remove();
171
- linkRef.current = null;
172
- }
173
- };
174
- }, [icons.variant]);
175
- return null;
50
+ }, []);
51
+ const onBlur = React13.useCallback(() => {
52
+ setIsFocusVisible(false);
53
+ }, []);
54
+ const focusProps = { onFocus, onBlur };
55
+ return { isFocusVisible, focusProps };
176
56
  }
177
57
 
178
- // src/theme/NewtoneProvider.tsx
179
- var ThemeContext = React14.createContext(null);
180
- function NewtoneProvider({
181
- config = DEFAULT_THEME_CONFIG,
182
- initialMode = "light",
183
- children,
184
- reportingEndpoint,
185
- fontFaceCss
186
- }) {
187
- const [mode, setMode] = React14.useState(initialMode);
188
- const value = React14.useMemo(
189
- () => ({
190
- config,
191
- mode,
192
- setMode,
193
- reportingEndpoint
194
- }),
195
- [config, mode, reportingEndpoint]
196
- );
197
- return /* @__PURE__ */ React14__default.default.createElement(ThemeContext.Provider, { value }, fontFaceCss ? /* @__PURE__ */ React14__default.default.createElement(SelfHostedFontLoader, { fontFaceCss }) : /* @__PURE__ */ React14__default.default.createElement(GoogleFontLoader, { fonts: config.typography.fonts }), /* @__PURE__ */ React14__default.default.createElement(IconFontLoader, { icons: config.icons }), children);
198
- }
199
- function useNewtoneTheme() {
200
- const context = React14.useContext(ThemeContext);
201
- if (!context) {
202
- throw new Error("useNewtoneTheme must be used within NewtoneProvider");
203
- }
204
- return context;
205
- }
206
- var FrameContext = React14.createContext(null);
207
- function useFrameContext() {
208
- return React14.useContext(FrameContext);
58
+ // src/primitives/Frame/Frame.utils.ts
59
+ function resolveSpacing(value, tokens) {
60
+ if (typeof value === "number") return value;
61
+ return tokens.spacing[value];
209
62
  }
210
- var NEUTRAL_DEFAULTS = {
211
- light: {
212
- background: { elevated: 0, ground: 0.03, sunken: 0.06 },
213
- text: { primary: 0.9, secondary: 0.7, tertiary: 0.5, disabled: 0.3 },
214
- action: { enabled: 0.04, hovered: 0.06, pressed: 0.08 },
215
- border: { enabled: 0.08, focused: 0.16, filled: 0.24 }
216
- },
217
- dark: {
218
- background: { elevated: 0.24, ground: 0.2, sunken: 0.16 },
219
- text: { primary: 1, secondary: 0.85, tertiary: 0.7, disabled: 0.55 },
220
- action: { enabled: 0.04, hovered: 0.06, pressed: 0.08 },
221
- border: { enabled: 0.08, focused: 0.16, filled: 0.24 }
222
- }
223
- };
224
- var ACCENT_DEFAULTS = {
225
- light: {
226
- background: { elevated: 0, ground: 0.03, sunken: 0.06 },
227
- text: { primary: 0.9, secondary: 0.7, tertiary: 0.5, disabled: 0.3 },
228
- action: { enabled: 0.04, hovered: 0.06, pressed: 0.08 },
229
- border: { enabled: 0.08, focused: 0.16, filled: 0.24 }
230
- },
231
- dark: {
232
- background: { elevated: 0.24, ground: 0.2, sunken: 0.16 },
233
- text: { primary: 1, secondary: 0.85, tertiary: 0.7, disabled: 0.55 },
234
- action: { enabled: 0.04, hovered: 0.06, pressed: 0.08 },
235
- border: { enabled: 0.08, focused: 0.16, filled: 0.24 }
236
- }
237
- };
238
- var SUCCESS_DEFAULTS = {
239
- light: {
240
- background: { elevated: 0, ground: 0.03, sunken: 0.06 },
241
- text: { primary: 0.9, secondary: 0.7, tertiary: 0.5, disabled: 0.3 },
242
- action: { enabled: 0.04, hovered: 0.06, pressed: 0.08 },
243
- border: { enabled: 0.08, focused: 0.16, filled: 0.24 }
244
- },
245
- dark: {
246
- background: { elevated: 0.24, ground: 0.2, sunken: 0.16 },
247
- text: { primary: 1, secondary: 0.85, tertiary: 0.7, disabled: 0.55 },
248
- action: { enabled: 0.04, hovered: 0.06, pressed: 0.08 },
249
- border: { enabled: 0.08, focused: 0.16, filled: 0.24 }
250
- }
251
- };
252
- var WARNING_DEFAULTS = {
253
- light: {
254
- background: { elevated: 0, ground: 0.03, sunken: 0.06 },
255
- text: { primary: 0.9, secondary: 0.7, tertiary: 0.5, disabled: 0.3 },
256
- action: { enabled: 0.04, hovered: 0.06, pressed: 0.08 },
257
- border: { enabled: 0.08, focused: 0.16, filled: 0.24 }
258
- },
259
- dark: {
260
- background: { elevated: 0.24, ground: 0.2, sunken: 0.16 },
261
- text: { primary: 1, secondary: 0.85, tertiary: 0.7, disabled: 0.55 },
262
- action: { enabled: 0.04, hovered: 0.06, pressed: 0.08 },
263
- border: { enabled: 0.08, focused: 0.16, filled: 0.24 }
63
+ function resolvePadding(prop, tokens) {
64
+ if (typeof prop === "string" || typeof prop === "number") {
65
+ const px = resolveSpacing(prop, tokens);
66
+ return { top: px, right: px, bottom: px, left: px };
264
67
  }
265
- };
266
- var ERROR_DEFAULTS = {
267
- light: {
268
- background: { elevated: 0, ground: 0.03, sunken: 0.06 },
269
- text: { primary: 0.9, secondary: 0.7, tertiary: 0.5, disabled: 0.3 },
270
- action: { enabled: 0.04, hovered: 0.06, pressed: 0.08 },
271
- border: { enabled: 0.08, focused: 0.16, filled: 0.24 }
272
- },
273
- dark: {
274
- background: { elevated: 0.24, ground: 0.2, sunken: 0.16 },
275
- text: { primary: 1, secondary: 0.85, tertiary: 0.7, disabled: 0.55 },
276
- action: { enabled: 0.04, hovered: 0.06, pressed: 0.08 },
277
- border: { enabled: 0.08, focused: 0.16, filled: 0.24 }
68
+ if ("x" in prop || "y" in prop) {
69
+ const axes = prop;
70
+ const x = axes.x !== void 0 ? resolveSpacing(axes.x, tokens) : 0;
71
+ const y = axes.y !== void 0 ? resolveSpacing(axes.y, tokens) : 0;
72
+ return { top: y, right: x, bottom: y, left: x };
278
73
  }
279
- };
280
- var clamp = (n) => Math.max(0, Math.min(1, n));
281
- function computePaletteTokens(palette, defaults, mode, elevation, dynamicRange, elevationDelta, effectiveTextMode, autoAccentNv, neutralTextPrimary, neutralBgElevated) {
282
- const modeDefaults = defaults[mode];
283
- const toEngineNv = (nv) => mode === "light" ? 1 - nv : nv;
284
- const textToEngineNv = (nv) => effectiveTextMode === "light" ? 1 - nv : nv;
285
- const colorAt = (engineNv) => newtone.getColor(
286
- palette.hue,
287
- palette.saturation,
288
- dynamicRange,
289
- clamp(engineNv),
290
- palette.desaturation,
291
- palette.paletteHueGrading
292
- );
293
- const resolveKeyNv = (p) => mode === "dark" ? p.keyNormalizedValueDark : p.keyNormalizedValue;
294
- const keyNv = resolveKeyNv(palette);
295
- const fillBaseNv = keyNv ?? autoAccentNv;
296
- const fillNv = clamp(fillBaseNv + elevationDelta);
297
- const fill = colorAt(fillNv);
298
- const hoverDir = effectiveTextMode === "light" ? -modeDefaults.action.hovered : modeDefaults.action.hovered;
299
- const activeDir = effectiveTextMode === "light" ? -modeDefaults.action.pressed : modeDefaults.action.pressed;
300
- const fillHover = colorAt(clamp(fillNv + hoverDir));
301
- const fillActive = colorAt(clamp(fillNv + activeDir));
302
- const onFill = fill.oklch.L > 0.6 ? neutralTextPrimary : neutralBgElevated;
303
- const bgNormalized = elevation === 2 ? modeDefaults.background.elevated : elevation === 1 ? modeDefaults.background.ground : modeDefaults.background.sunken;
304
- const bgNv = clamp(toEngineNv(bgNormalized));
305
- const background = colorAt(bgNv);
306
- const backgroundElevated = colorAt(clamp(toEngineNv(modeDefaults.background.elevated)));
307
- const backgroundSunken = colorAt(clamp(toEngineNv(modeDefaults.background.sunken)));
308
- const interactiveOffset = modeDefaults.action.enabled;
309
- const interactiveNv = clamp(bgNv + (effectiveTextMode === "light" ? -interactiveOffset : interactiveOffset));
310
- const backgroundInteractive = colorAt(interactiveNv);
311
- const hoverShift = modeDefaults.action.hovered;
312
- const activeShift = modeDefaults.action.pressed;
313
- const backgroundInteractiveHover = colorAt(clamp(interactiveNv + (effectiveTextMode === "light" ? -hoverShift : hoverShift)));
314
- const backgroundInteractiveActive = colorAt(clamp(interactiveNv + (effectiveTextMode === "light" ? -activeShift : activeShift)));
315
- const textPrimary = colorAt(clamp(textToEngineNv(modeDefaults.text.primary) + elevationDelta));
316
- const textSecondary = colorAt(clamp(textToEngineNv(modeDefaults.text.secondary) + elevationDelta));
317
- const textTertiary = colorAt(clamp(textToEngineNv(modeDefaults.text.tertiary) + elevationDelta));
318
- const textDisabled = colorAt(clamp(textToEngineNv(modeDefaults.text.disabled) + elevationDelta));
319
- const borderOffset = modeDefaults.border.enabled;
320
- const borderNv = effectiveTextMode === "light" ? bgNv - borderOffset : bgNv + borderOffset;
321
- const border = colorAt(clamp(borderNv));
74
+ const sides = prop;
322
75
  return {
323
- fill,
324
- fillHover,
325
- fillActive,
326
- onFill,
327
- background,
328
- backgroundElevated,
329
- backgroundSunken,
330
- backgroundInteractive,
331
- backgroundInteractiveHover,
332
- backgroundInteractiveActive,
333
- textPrimary,
334
- textSecondary,
335
- textTertiary,
336
- textDisabled,
337
- border
76
+ top: sides.top !== void 0 ? resolveSpacing(sides.top, tokens) : 0,
77
+ right: sides.right !== void 0 ? resolveSpacing(sides.right, tokens) : 0,
78
+ bottom: sides.bottom !== void 0 ? resolveSpacing(sides.bottom, tokens) : 0,
79
+ left: sides.left !== void 0 ? resolveSpacing(sides.left, tokens) : 0
338
80
  };
339
81
  }
340
- function computeTokens(config, mode, elevation, spacing, radius, typography, icons, tokenOverrides) {
341
- const { dynamicRange, palettes } = config;
342
- const palette = palettes[0];
343
- if (!palette) {
344
- throw new Error("Neutral palette (index 0) not found");
345
- }
346
- const neutralDefaults = NEUTRAL_DEFAULTS[mode];
347
- const toEngineNv = (nv) => mode === "light" ? 1 - nv : nv;
348
- const bgElevatedNorm = mode === "light" ? tokenOverrides?.backgroundElevated : tokenOverrides?.backgroundElevatedDark;
349
- const bgDefaultNorm = mode === "light" ? tokenOverrides?.backgroundDefault : tokenOverrides?.backgroundDefaultDark;
350
- const bgSunkenNorm = mode === "light" ? tokenOverrides?.backgroundSunken : tokenOverrides?.backgroundSunkenDark;
351
- const textPrimaryNorm = mode === "light" ? tokenOverrides?.textPrimaryNormalized : tokenOverrides?.textPrimaryNormalizedDark;
352
- const textSecondaryNorm = mode === "light" ? tokenOverrides?.textSecondaryNormalized : tokenOverrides?.textSecondaryNormalizedDark;
353
- const textTertiaryNorm = mode === "light" ? tokenOverrides?.textTertiaryNormalized : tokenOverrides?.textTertiaryNormalizedDark;
354
- const textDisabledNorm = mode === "light" ? tokenOverrides?.textDisabledNormalized : tokenOverrides?.textDisabledNormalizedDark;
355
- const bgNormalized = elevation === 2 ? bgElevatedNorm ?? neutralDefaults.background.elevated : elevation === 1 ? bgDefaultNorm ?? neutralDefaults.background.ground : bgSunkenNorm ?? neutralDefaults.background.sunken;
356
- const backgroundNv = clamp(toEngineNv(bgNormalized));
357
- const elevatedNv = clamp(toEngineNv(bgElevatedNorm ?? neutralDefaults.background.elevated));
358
- const sunkenNv = clamp(toEngineNv(bgSunkenNorm ?? neutralDefaults.background.sunken));
359
- const elevationDelta = backgroundNv - elevatedNv;
360
- const effectiveTextMode = backgroundNv >= 0.5 ? "light" : "dark";
361
- const background = newtone.getColor(
362
- palette.hue,
363
- palette.saturation,
364
- dynamicRange,
365
- backgroundNv,
366
- palette.desaturation,
367
- palette.paletteHueGrading
368
- );
369
- const backgroundElevated = newtone.getColor(
370
- palette.hue,
371
- palette.saturation,
372
- dynamicRange,
373
- elevatedNv,
374
- palette.desaturation,
375
- palette.paletteHueGrading
376
- );
377
- const backgroundSunken = newtone.getColor(
378
- palette.hue,
379
- palette.saturation,
380
- dynamicRange,
381
- sunkenNv,
382
- palette.desaturation,
383
- palette.paletteHueGrading
384
- );
385
- const INTERACTIVE_COMPONENT_OFFSET = mode === "light" ? tokenOverrides?.interactiveComponentOffset ?? neutralDefaults.action.enabled : tokenOverrides?.interactiveComponentOffsetDark ?? neutralDefaults.action.enabled;
386
- const HOVER_SHIFT = mode === "light" ? tokenOverrides?.hoverShift ?? neutralDefaults.action.hovered : tokenOverrides?.hoverShiftDark ?? neutralDefaults.action.hovered;
387
- const ACTIVE_SHIFT = mode === "light" ? tokenOverrides?.activeShift ?? neutralDefaults.action.pressed : tokenOverrides?.activeShiftDark ?? neutralDefaults.action.pressed;
388
- const BORDER_OFFSET = mode === "light" ? tokenOverrides?.borderOffset ?? neutralDefaults.border.enabled : tokenOverrides?.borderOffsetDark ?? neutralDefaults.border.enabled;
389
- const interactiveComponentNv = clamp(backgroundNv + (effectiveTextMode === "light" ? -INTERACTIVE_COMPONENT_OFFSET : INTERACTIVE_COMPONENT_OFFSET));
390
- const backgroundInteractive = newtone.getColor(
391
- palette.hue,
392
- palette.saturation,
393
- dynamicRange,
394
- interactiveComponentNv,
395
- palette.desaturation,
396
- palette.paletteHueGrading
397
- );
398
- const neutralHoverNv = clamp(interactiveComponentNv + (effectiveTextMode === "light" ? -HOVER_SHIFT : HOVER_SHIFT));
399
- const backgroundInteractiveHover = newtone.getColor(
400
- palette.hue,
401
- palette.saturation,
402
- dynamicRange,
403
- neutralHoverNv,
404
- palette.desaturation,
405
- palette.paletteHueGrading
406
- );
407
- const neutralActiveNv = clamp(interactiveComponentNv + (effectiveTextMode === "light" ? -ACTIVE_SHIFT : ACTIVE_SHIFT));
408
- const backgroundInteractiveActive = newtone.getColor(
409
- palette.hue,
410
- palette.saturation,
411
- dynamicRange,
412
- neutralActiveNv,
413
- palette.desaturation,
414
- palette.paletteHueGrading
415
- );
416
- const textToEngineNv = (nv) => effectiveTextMode === "light" ? 1 - nv : nv;
417
- const textPrimary = newtone.getColor(
418
- palette.hue,
419
- palette.saturation,
420
- dynamicRange,
421
- clamp(textToEngineNv(textPrimaryNorm ?? neutralDefaults.text.primary) + elevationDelta),
422
- palette.desaturation,
423
- palette.paletteHueGrading
424
- );
425
- const textSecondary = newtone.getColor(
426
- palette.hue,
427
- palette.saturation,
428
- dynamicRange,
429
- clamp(textToEngineNv(textSecondaryNorm ?? neutralDefaults.text.secondary) + elevationDelta),
430
- palette.desaturation,
431
- palette.paletteHueGrading
432
- );
433
- const textTertiary = newtone.getColor(
434
- palette.hue,
435
- palette.saturation,
436
- dynamicRange,
437
- clamp(textToEngineNv(textTertiaryNorm ?? neutralDefaults.text.tertiary) + elevationDelta),
438
- palette.desaturation,
439
- palette.paletteHueGrading
440
- );
441
- const textDisabled = newtone.getColor(
442
- palette.hue,
443
- palette.saturation,
444
- dynamicRange,
445
- clamp(textToEngineNv(textDisabledNorm ?? neutralDefaults.text.disabled) + elevationDelta),
446
- palette.desaturation,
447
- palette.paletteHueGrading
448
- );
449
- const borderNv = effectiveTextMode === "light" ? backgroundNv - BORDER_OFFSET : backgroundNv + BORDER_OFFSET;
450
- const border = newtone.getColor(
451
- palette.hue,
452
- palette.saturation,
453
- dynamicRange,
454
- clamp(borderNv),
455
- palette.desaturation,
456
- palette.paletteHueGrading
457
- );
458
- const autoAccentNv = clamp(textToEngineNv(textPrimaryNorm ?? neutralDefaults.text.primary));
459
- const accentPalette = palettes[1];
460
- if (!accentPalette) {
461
- throw new Error("Accent palette (index 1) not found");
82
+ function resolveGap(prop, tokens) {
83
+ if (typeof prop === "string" || typeof prop === "number") {
84
+ const px = resolveSpacing(prop, tokens);
85
+ return { rowGap: px, columnGap: px };
462
86
  }
463
- const accent = computePaletteTokens(
464
- accentPalette,
465
- ACCENT_DEFAULTS,
466
- mode,
467
- elevation,
468
- dynamicRange,
469
- elevationDelta,
470
- effectiveTextMode,
471
- autoAccentNv,
472
- textPrimary,
473
- backgroundElevated
474
- );
475
- const successPalette = palettes[2];
476
- const warningPalette = palettes[3];
477
- const errorPalette = palettes[4];
478
- const success = successPalette ? computePaletteTokens(
479
- successPalette,
480
- SUCCESS_DEFAULTS,
481
- mode,
482
- elevation,
483
- dynamicRange,
484
- elevationDelta,
485
- effectiveTextMode,
486
- autoAccentNv,
487
- textPrimary,
488
- backgroundElevated
489
- ) : accent;
490
- const warning = warningPalette ? computePaletteTokens(
491
- warningPalette,
492
- WARNING_DEFAULTS,
493
- mode,
494
- elevation,
495
- dynamicRange,
496
- elevationDelta,
497
- effectiveTextMode,
498
- autoAccentNv,
499
- textPrimary,
500
- backgroundElevated
501
- ) : accent;
502
- const error = errorPalette ? computePaletteTokens(
503
- errorPalette,
504
- ERROR_DEFAULTS,
505
- mode,
506
- elevation,
507
- dynamicRange,
508
- elevationDelta,
509
- effectiveTextMode,
510
- autoAccentNv,
511
- textPrimary,
512
- backgroundElevated
513
- ) : accent;
514
87
  return {
515
- background,
516
- backgroundElevated,
517
- backgroundSunken,
518
- backgroundInteractive,
519
- backgroundInteractiveHover,
520
- backgroundInteractiveActive,
521
- textPrimary,
522
- textSecondary,
523
- textTertiary,
524
- textDisabled,
525
- border,
526
- accent,
527
- success,
528
- warning,
529
- error,
530
- spacing,
531
- radius,
532
- typography: {
533
- fonts: {
534
- main: {
535
- family: fonts.fontConfigToFamily(typography.fonts.main.config),
536
- weights: typography.fonts.main.weights
537
- },
538
- display: {
539
- family: fonts.fontConfigToFamily(typography.fonts.display.config),
540
- weights: typography.fonts.display.weights
541
- },
542
- mono: {
543
- family: fonts.fontConfigToFamily(typography.fonts.mono.config),
544
- weights: typography.fonts.mono.weights
545
- },
546
- currency: {
547
- family: fonts.fontConfigToFamily(typography.fonts.currency.config),
548
- weights: typography.fonts.currency.weights
549
- }
550
- },
551
- fontSizes: typography.fontSizes,
552
- lineHeights: typography.lineHeights
553
- },
554
- icons: {
555
- variant: icons.variant,
556
- weight: icons.weight,
557
- grade: icons.autoGrade ? mode === "light" ? -25 : 200 : 0
558
- }
88
+ rowGap: prop.row !== void 0 ? resolveSpacing(prop.row, tokens) : 0,
89
+ columnGap: prop.column !== void 0 ? resolveSpacing(prop.column, tokens) : 0
559
90
  };
560
91
  }
561
-
562
- // src/tokens/useTokens.ts
563
- function useTokens(elevation) {
564
- const { config, mode } = useNewtoneTheme();
565
- const frameCtx = useFrameContext();
566
- const resolvedElevation = elevation ?? frameCtx?.elevation ?? 1;
567
- const canReuse = frameCtx !== null && elevation === void 0 && frameCtx.elevation === resolvedElevation;
568
- return React14.useMemo(() => {
569
- if (canReuse) {
570
- return { ...frameCtx.tokens, elevation: resolvedElevation };
571
- }
572
- const tokens = computeTokens(
573
- config.colorSystem,
574
- mode,
575
- resolvedElevation,
576
- config.spacing,
577
- config.radius,
578
- config.typography,
579
- config.icons,
580
- config.tokenOverrides
581
- );
582
- return { ...tokens, elevation: resolvedElevation };
583
- }, [config, mode, resolvedElevation, canReuse, frameCtx?.tokens]);
92
+ function resolveRadius(value, tokens) {
93
+ if (typeof value === "number") return value;
94
+ return tokens.radius[value];
584
95
  }
585
- function computeButtonPadding(size, hasIcon, hasText, iconPosition) {
586
- const basePadding = {
587
- sm: 8,
588
- md: 12,
589
- lg: 16
590
- };
591
- const base = basePadding[size];
592
- const textExtra = 8;
593
- if (!hasText && hasIcon) {
594
- return {
595
- paddingLeft: base,
596
- paddingRight: base,
597
- paddingTop: base,
598
- paddingBottom: base
599
- };
600
- }
601
- if (hasText && !hasIcon) {
602
- return {
603
- paddingLeft: base + textExtra,
604
- paddingRight: base + textExtra,
605
- paddingTop: base,
606
- paddingBottom: base
607
- };
608
- }
609
- if (hasText && hasIcon) {
610
- if (iconPosition === "left") {
611
- return {
612
- paddingLeft: base,
613
- paddingRight: base + textExtra,
614
- paddingTop: base,
615
- paddingBottom: base
616
- };
617
- } else {
618
- return {
619
- paddingLeft: base + textExtra,
620
- paddingRight: base,
621
- paddingTop: base,
622
- paddingBottom: base
623
- };
624
- }
96
+ function resolveRadiusCorners(prop, tokens) {
97
+ if (typeof prop === "string" || typeof prop === "number") {
98
+ const px = resolveRadius(prop, tokens);
99
+ return { topLeft: px, topRight: px, bottomLeft: px, bottomRight: px };
625
100
  }
626
101
  return {
627
- paddingLeft: base,
628
- paddingRight: base,
629
- paddingTop: base,
630
- paddingBottom: base
102
+ topLeft: prop.topLeft !== void 0 ? resolveRadius(prop.topLeft, tokens) : 0,
103
+ topRight: prop.topRight !== void 0 ? resolveRadius(prop.topRight, tokens) : 0,
104
+ bottomLeft: prop.bottomLeft !== void 0 ? resolveRadius(prop.bottomLeft, tokens) : 0,
105
+ bottomRight: prop.bottomRight !== void 0 ? resolveRadius(prop.bottomRight, tokens) : 0
631
106
  };
632
107
  }
633
- function getPaletteTokens(semantic, tokens) {
634
- switch (semantic) {
635
- case "accent":
636
- return tokens.accent;
637
- case "success":
638
- return tokens.success;
639
- case "error":
640
- return tokens.error;
641
- case "warning":
642
- return tokens.warning;
643
- default:
644
- return void 0;
645
- }
108
+ function hasPositiveRadius(corners) {
109
+ return corners.topLeft > 0 || corners.topRight > 0 || corners.bottomLeft > 0 || corners.bottomRight > 0;
646
110
  }
647
- function getButtonConfig(variant, semantic, size, disabled, tokens) {
648
- const sizeConfig = getSizeConfig(size, tokens);
649
- const variantColors = getVariantColors(variant, semantic, disabled, tokens);
650
- return {
651
- variantColors,
652
- sizeTokens: {
653
- padding: sizeConfig.padding,
654
- gap: sizeConfig.gap,
655
- borderRadius: sizeConfig.borderRadius,
656
- textSize: sizeConfig.textSize,
657
- iconSize: sizeConfig.iconSize
111
+ function resolveSizing(width, height) {
112
+ const style = {};
113
+ if (width !== void 0) {
114
+ if (width === "fill") {
115
+ style.flexGrow = 1;
116
+ style.width = "100%";
117
+ } else if (typeof width === "number") {
118
+ style.width = width;
658
119
  }
659
- };
120
+ }
121
+ if (height !== void 0) {
122
+ if (height === "fill") {
123
+ style.flexGrow = 1;
124
+ style.height = "100%";
125
+ } else if (typeof height === "number") {
126
+ style.height = height;
127
+ }
128
+ }
129
+ return style;
660
130
  }
661
- function getSizeConfig(size, tokens) {
662
- const configs = {
663
- sm: {
664
- padding: 8,
665
- gap: tokens.spacing["08"],
666
- borderRadius: 8,
667
- textSize: "md",
668
- // 16px
669
- iconSize: 24
670
- },
671
- md: {
672
- padding: 12,
673
- gap: tokens.spacing["08"],
674
- borderRadius: 12,
675
- textSize: "md",
676
- // 16px
677
- iconSize: 24
678
- },
679
- lg: {
680
- padding: 16,
681
- gap: tokens.spacing["08"],
682
- borderRadius: 16,
683
- textSize: "md",
684
- // 16px
685
- iconSize: 24
686
- }
687
- };
688
- return configs[size];
131
+ var ALIGN_MAP = {
132
+ start: "flex-start",
133
+ center: "center",
134
+ end: "flex-end",
135
+ stretch: "stretch",
136
+ baseline: "baseline"
137
+ };
138
+ var JUSTIFY_MAP = {
139
+ start: "flex-start",
140
+ center: "center",
141
+ end: "flex-end",
142
+ between: "space-between",
143
+ around: "space-around",
144
+ evenly: "space-evenly"
145
+ };
146
+ function resolveAlignment(align) {
147
+ return ALIGN_MAP[align];
689
148
  }
690
- function getVariantColors(variant, semantic, disabled, tokens) {
691
- if (disabled) {
692
- const baseColors = getVariantColorsForState(variant, semantic, tokens);
693
- const disabledBg = newtone.srgbToHex(tokens.backgroundSunken.srgb);
694
- return {
695
- ...baseColors,
696
- bg: disabledBg,
697
- hoveredBg: disabledBg,
698
- pressedBg: disabledBg,
699
- textColor: newtone.srgbToHex(tokens.textSecondary.srgb),
700
- iconColor: newtone.srgbToHex(tokens.textSecondary.srgb)
701
- };
149
+ function resolveJustification(justify) {
150
+ return JUSTIFY_MAP[justify];
151
+ }
152
+ function resolveFlexDirection(direction, reverse) {
153
+ if (direction === "horizontal") {
154
+ return reverse ? "row-reverse" : "row";
702
155
  }
703
- return getVariantColorsForState(variant, semantic, tokens);
156
+ return reverse ? "column-reverse" : "column";
704
157
  }
705
- function getVariantColorsForState(variant, semantic, tokens) {
706
- const paletteTokens = getPaletteTokens(semantic, tokens);
707
- if (variant === "primary") {
708
- if (semantic === "neutral") {
709
- return {
710
- bg: newtone.srgbToHex(tokens.backgroundInteractive.srgb),
711
- hoveredBg: newtone.srgbToHex(tokens.backgroundInteractiveHover.srgb),
712
- pressedBg: newtone.srgbToHex(tokens.backgroundInteractiveActive.srgb),
713
- textColor: newtone.srgbToHex(tokens.textPrimary.srgb),
714
- iconColor: newtone.srgbToHex(tokens.textPrimary.srgb),
715
- borderWidth: 1,
716
- borderColor: "transparent"
717
- };
718
- }
719
- return {
720
- bg: newtone.srgbToHex(paletteTokens.fill.srgb),
721
- hoveredBg: newtone.srgbToHex(paletteTokens.fillHover.srgb),
722
- pressedBg: newtone.srgbToHex(paletteTokens.fillActive.srgb),
723
- textColor: newtone.srgbToHex(paletteTokens.onFill.srgb),
724
- iconColor: newtone.srgbToHex(paletteTokens.onFill.srgb),
725
- borderWidth: 1,
726
- borderColor: "transparent"
727
- };
158
+
159
+ // src/primitives/Frame/Frame.styles.ts
160
+ function getFrameStyles(input) {
161
+ const {
162
+ tokens,
163
+ gamut,
164
+ frameElevation,
165
+ layout = "flex",
166
+ direction = "vertical",
167
+ wrap = false,
168
+ reverse = false,
169
+ columns,
170
+ rows,
171
+ align,
172
+ justify,
173
+ padding,
174
+ gap,
175
+ width,
176
+ height,
177
+ minWidth,
178
+ maxWidth,
179
+ minHeight,
180
+ maxHeight,
181
+ radius,
182
+ bordered = false,
183
+ disabled = false
184
+ } = input;
185
+ const container = {};
186
+ container.backgroundColor = tokens.background[gamut];
187
+ container.color = tokens.textPrimary[gamut];
188
+ if (layout === "flex") {
189
+ container.display = "flex";
190
+ container.flexDirection = resolveFlexDirection(direction, reverse);
191
+ if (wrap) container.flexWrap = "wrap";
728
192
  }
729
- if (variant === "secondary") {
730
- if (semantic === "neutral") {
731
- return {
732
- bg: "transparent",
733
- hoveredBg: newtone.srgbToHex(tokens.backgroundInteractive.srgb),
734
- pressedBg: newtone.srgbToHex(tokens.backgroundInteractiveHover.srgb),
735
- textColor: newtone.srgbToHex(tokens.textPrimary.srgb),
736
- iconColor: newtone.srgbToHex(tokens.textPrimary.srgb),
737
- borderWidth: 1,
738
- borderColor: newtone.srgbToHex(tokens.border.srgb)
739
- };
740
- }
741
- return {
742
- bg: newtone.srgbToHex(paletteTokens.background.srgb),
743
- hoveredBg: newtone.srgbToHex(paletteTokens.backgroundInteractive.srgb),
744
- pressedBg: newtone.srgbToHex(paletteTokens.backgroundInteractiveHover.srgb),
745
- textColor: newtone.srgbToHex(paletteTokens.fill.srgb),
746
- iconColor: newtone.srgbToHex(paletteTokens.fill.srgb),
747
- borderWidth: 1,
748
- borderColor: "transparent"
749
- };
193
+ if (layout === "grid") {
194
+ container.display = "flex";
195
+ container.flexDirection = "row";
196
+ container.flexWrap = "wrap";
750
197
  }
751
- if (variant === "tertiary") {
752
- if (semantic === "neutral") {
753
- return {
754
- bg: "transparent",
755
- hoveredBg: newtone.srgbToHex(tokens.backgroundInteractive.srgb),
756
- pressedBg: newtone.srgbToHex(tokens.backgroundInteractiveHover.srgb),
757
- textColor: newtone.srgbToHex(tokens.textPrimary.srgb),
758
- iconColor: newtone.srgbToHex(tokens.textPrimary.srgb),
759
- borderWidth: 1,
760
- borderColor: "transparent"
761
- };
198
+ if (align) container.alignItems = resolveAlignment(align);
199
+ if (justify) container.justifyContent = resolveJustification(justify);
200
+ if (padding !== void 0) {
201
+ const p = resolvePadding(padding, tokens);
202
+ container.paddingTop = p.top;
203
+ container.paddingRight = p.right;
204
+ container.paddingBottom = p.bottom;
205
+ container.paddingLeft = p.left;
206
+ }
207
+ if (gap !== void 0) {
208
+ const g = resolveGap(gap, tokens);
209
+ container.rowGap = g.rowGap;
210
+ container.columnGap = g.columnGap;
211
+ }
212
+ const sizing = resolveSizing(width, height);
213
+ Object.assign(container, sizing);
214
+ if (minWidth !== void 0) container.minWidth = minWidth;
215
+ if (maxWidth !== void 0) container.maxWidth = maxWidth;
216
+ if (minHeight !== void 0) container.minHeight = minHeight;
217
+ if (maxHeight !== void 0) container.maxHeight = maxHeight;
218
+ if (radius !== void 0) {
219
+ const corners = resolveRadiusCorners(radius, tokens);
220
+ container.borderTopLeftRadius = corners.topLeft;
221
+ container.borderTopRightRadius = corners.topRight;
222
+ container.borderBottomLeftRadius = corners.bottomLeft;
223
+ container.borderBottomRightRadius = corners.bottomRight;
224
+ if (hasPositiveRadius(corners)) {
225
+ container.overflow = "hidden";
762
226
  }
763
- return {
764
- bg: "transparent",
765
- hoveredBg: newtone.srgbToHex(paletteTokens.background.srgb),
766
- pressedBg: newtone.srgbToHex(paletteTokens.backgroundInteractive.srgb),
767
- textColor: newtone.srgbToHex(paletteTokens.fill.srgb),
768
- iconColor: newtone.srgbToHex(paletteTokens.fill.srgb),
769
- borderWidth: 1,
770
- borderColor: "transparent"
227
+ }
228
+ if (bordered) {
229
+ container.borderWidth = 1;
230
+ container.borderColor = tokens.border[gamut];
231
+ }
232
+ if (frameElevation === 2) {
233
+ container.shadowColor = "#000";
234
+ container.shadowOffset = { width: 0, height: 2 };
235
+ container.shadowOpacity = 0.12;
236
+ container.shadowRadius = 6;
237
+ container.elevation = 4;
238
+ }
239
+ if (disabled) {
240
+ container.opacity = 0.5;
241
+ }
242
+ const pressed = reactNative.StyleSheet.create({
243
+ s: { backgroundColor: tokens.backgroundSunken[gamut] }
244
+ }).s;
245
+ let gridWebStyle = null;
246
+ if (layout === "grid") {
247
+ gridWebStyle = {
248
+ display: "grid",
249
+ // Divide into equal-width columns (e.g. 3 columns → "repeat(3, 1fr)").
250
+ gridTemplateColumns: columns ? `repeat(${columns}, 1fr)` : void 0,
251
+ gridTemplateRows: rows ? `repeat(${rows}, 1fr)` : void 0
771
252
  };
772
253
  }
254
+ const insetBoxShadow = frameElevation === -2 ? "inset 0 2px 4px rgba(0,0,0,0.12)" : null;
773
255
  return {
774
- bg: "transparent",
775
- hoveredBg: "transparent",
776
- pressedBg: "transparent",
777
- textColor: newtone.srgbToHex(tokens.textPrimary.srgb),
778
- iconColor: newtone.srgbToHex(tokens.textPrimary.srgb),
779
- borderWidth: 0
256
+ // Validate and optimize the container styles through StyleSheet.create(),
257
+ // then extract the single style object with `.c`.
258
+ container: reactNative.StyleSheet.create({ c: container }).c,
259
+ pressed,
260
+ gridWebStyle,
261
+ insetBoxShadow
780
262
  };
781
263
  }
782
- function Icon({
783
- name,
784
- size,
785
- opticalSize,
786
- fill = 0,
787
- color,
788
- style,
264
+
265
+ // src/primitives/Frame/Frame.tsx
266
+ function wrapTextChildren(children, textStyle) {
267
+ return React13__default.default.Children.map(children, (child) => {
268
+ if (typeof child === "string" || typeof child === "number") {
269
+ return /* @__PURE__ */ React13__default.default.createElement(reactNative.Text, { style: textStyle }, child);
270
+ }
271
+ return child;
272
+ });
273
+ }
274
+ function toElevationLevel(frameElevation) {
275
+ if (frameElevation <= -1) return 0;
276
+ if (frameElevation === 0) return 1;
277
+ return 2;
278
+ }
279
+ function Frame({
280
+ children,
281
+ // Elevation
282
+ elevation,
283
+ // Layout
284
+ layout,
285
+ direction,
286
+ wrap,
287
+ reverse,
288
+ columns,
289
+ rows,
290
+ // Alignment
291
+ align,
292
+ justify,
293
+ // Spacing
294
+ padding,
295
+ gap,
296
+ // Sizing
297
+ width,
298
+ height,
299
+ minWidth,
300
+ maxWidth,
301
+ minHeight,
302
+ maxHeight,
303
+ // Appearance
304
+ radius,
305
+ bordered,
306
+ // Interactivity
307
+ onPress,
308
+ href,
309
+ disabled = false,
789
310
  // Accessibility
790
311
  accessibilityLabel,
312
+ accessibilityHint,
791
313
  // Testing & platform
792
314
  testID,
793
315
  nativeID,
794
- ref
316
+ ref,
317
+ // Style override
318
+ style
795
319
  }) {
796
- const tokens = useTokens();
797
- const iconStyle = React14.useMemo(() => {
798
- const fontSize = size ?? tokens.typography.fontSizes["05"];
799
- const getOpticalSize = (size2) => {
800
- if (size2 <= 22) return 20;
801
- if (size2 <= 32) return 24;
802
- if (size2 <= 44) return 40;
803
- return 48;
804
- };
805
- const opsz = opticalSize ?? getOpticalSize(fontSize);
806
- const iconColor = color ?? newtone.srgbToHex(tokens.textPrimary.srgb);
807
- const fontFamily = `Material Symbols ${tokens.icons.variant.charAt(0).toUpperCase() + tokens.icons.variant.slice(1)}`;
808
- const fillValue = typeof fill === "boolean" ? fill ? 1 : 0 : fill;
809
- const fontVariationSettings = `'FILL' ${fillValue}, 'wght' ${tokens.icons.weight}, 'GRAD' ${tokens.icons.grade}, 'opsz' ${opsz}`;
810
- return {
811
- fontFamily,
812
- fontSize,
813
- width: fontSize,
814
- // Explicit width ensures square rendering
815
- height: fontSize,
816
- // Explicit height ensures square rendering
817
- lineHeight: fontSize,
818
- // Prevent text line-height from affecting total height
819
- color: iconColor,
820
- userSelect: "none",
821
- // web-only: prevents users from selecting the icon as text
320
+ const { config, mode, gamut } = newtoneApi.useNewtoneTheme();
321
+ const parentFrameCtx = newtoneApi.useFrameContext();
322
+ const resolvedFrameElevation = elevation ?? 0;
323
+ const resolvedElevation = elevation !== void 0 ? toElevationLevel(elevation) : parentFrameCtx?.elevation ?? 1;
324
+ const tokens = React13.useMemo(() => {
325
+ return newtoneApi.computeTokens(
326
+ config.colorSystem,
327
+ mode,
328
+ resolvedElevation,
329
+ config.spacing,
330
+ config.radius,
331
+ config.typography,
332
+ config.icons,
333
+ config.tokenOverrides
334
+ );
335
+ }, [config, mode, resolvedElevation]);
336
+ const styles = React13.useMemo(
337
+ () => getFrameStyles({
338
+ tokens,
339
+ gamut,
340
+ frameElevation: resolvedFrameElevation,
341
+ layout,
342
+ direction,
343
+ wrap,
344
+ reverse,
345
+ columns,
346
+ rows,
347
+ align,
348
+ justify,
349
+ padding,
350
+ gap,
351
+ width,
352
+ height,
353
+ minWidth,
354
+ maxWidth,
355
+ minHeight,
356
+ maxHeight,
357
+ radius,
358
+ bordered,
359
+ disabled
360
+ }),
361
+ [
362
+ tokens,
363
+ gamut,
364
+ resolvedFrameElevation,
365
+ layout,
366
+ direction,
367
+ wrap,
368
+ reverse,
369
+ columns,
370
+ rows,
371
+ align,
372
+ justify,
373
+ padding,
374
+ gap,
375
+ width,
376
+ height,
377
+ minWidth,
378
+ maxWidth,
379
+ minHeight,
380
+ maxHeight,
381
+ radius,
382
+ bordered,
383
+ disabled
384
+ ]
385
+ );
386
+ const contextValue = React13.useMemo(
387
+ () => ({ elevation: resolvedElevation, tokens }),
388
+ [resolvedElevation, tokens]
389
+ );
390
+ const webOverrides = [];
391
+ if (styles.gridWebStyle) {
392
+ webOverrides.push(styles.gridWebStyle);
393
+ }
394
+ if (styles.insetBoxShadow) {
395
+ webOverrides.push({ boxShadow: styles.insetBoxShadow });
396
+ }
397
+ const userStyles = Array.isArray(style) ? style : style ? [style] : [];
398
+ const isInteractive = onPress !== void 0 || href !== void 0;
399
+ const { isFocusVisible, focusProps } = useFocusVisible();
400
+ const focusRingStyle = isFocusVisible && !disabled ? {
401
+ outlineWidth: 2,
402
+ outlineStyle: "solid",
403
+ outlineColor: tokens.accent.fill[gamut],
404
+ outlineOffset: 2
405
+ } : void 0;
406
+ const webFocusProps = isInteractive ? focusProps : {};
407
+ const textStyle = React13.useMemo(
408
+ () => ({
409
+ color: tokens.textPrimary[gamut],
410
+ fontSize: tokens.typography.fontSizes["05"],
411
+ fontFamily: tokens.typography.fonts.main.family,
412
+ lineHeight: tokens.typography.lineHeights["06"]
413
+ }),
414
+ [tokens]
415
+ );
416
+ const wrappedChildren = React13.useMemo(
417
+ () => wrapTextChildren(children, textStyle),
418
+ [children, textStyle]
419
+ );
420
+ return /* @__PURE__ */ React13__default.default.createElement(newtoneApi.FrameContext.Provider, { value: contextValue }, isInteractive ? (
421
+ // Pressable handles taps. When href is set, react-native-web renders
422
+ // it as an <a> tag so it works like a regular link on the web.
423
+ /* @__PURE__ */ React13__default.default.createElement(
424
+ reactNative.Pressable,
425
+ {
426
+ ref,
427
+ testID,
428
+ nativeID,
429
+ accessibilityLabel,
430
+ accessibilityHint,
431
+ accessibilityState: disabled ? { disabled: true } : void 0,
432
+ onPress,
433
+ disabled,
434
+ ...href ? { href, accessibilityRole: "link" } : { accessibilityRole: "button" },
435
+ ...webFocusProps,
436
+ style: ({ pressed }) => [
437
+ styles.container,
438
+ pressed && !disabled && styles.pressed,
439
+ focusRingStyle,
440
+ ...webOverrides,
441
+ ...userStyles
442
+ ]
443
+ },
444
+ wrappedChildren
445
+ )
446
+ ) : (
447
+ // Non-interactive Frame: just a plain View with no tap handling.
448
+ /* @__PURE__ */ React13__default.default.createElement(
449
+ reactNative.View,
450
+ {
451
+ ref,
452
+ testID,
453
+ nativeID,
454
+ accessibilityLabel,
455
+ accessibilityHint,
456
+ style: [styles.container, ...webOverrides, ...userStyles]
457
+ },
458
+ wrappedChildren
459
+ )
460
+ ));
461
+ }
462
+ function Icon({
463
+ name,
464
+ size,
465
+ opticalSize,
466
+ fill = 0,
467
+ color,
468
+ style,
469
+ // Accessibility
470
+ accessibilityLabel,
471
+ // Testing & platform
472
+ testID,
473
+ nativeID,
474
+ ref
475
+ }) {
476
+ const tokens = newtoneApi.useTokens();
477
+ const iconStyle = React13.useMemo(() => {
478
+ const fontSize = size ?? tokens.typography.fontSizes["05"];
479
+ const getOpticalSize = (size2) => {
480
+ if (size2 <= 22) return 20;
481
+ if (size2 <= 32) return 24;
482
+ if (size2 <= 44) return 40;
483
+ return 48;
484
+ };
485
+ const opsz = opticalSize ?? getOpticalSize(fontSize);
486
+ const iconColor = color ?? tokens.textPrimary[tokens.gamut];
487
+ const fontFamily = `Material Symbols ${tokens.icons.variant.charAt(0).toUpperCase() + tokens.icons.variant.slice(1)}`;
488
+ const fillValue = typeof fill === "boolean" ? fill ? 1 : 0 : fill;
489
+ const fontVariationSettings = `'FILL' ${fillValue}, 'wght' ${tokens.icons.weight}, 'GRAD' ${tokens.icons.grade}, 'opsz' ${opsz}`;
490
+ return {
491
+ fontFamily,
492
+ fontSize,
493
+ width: fontSize,
494
+ // Explicit width ensures square rendering
495
+ height: fontSize,
496
+ // Explicit height ensures square rendering
497
+ lineHeight: fontSize,
498
+ // Prevent text line-height from affecting total height
499
+ color: iconColor,
500
+ userSelect: "none",
501
+ // web-only: prevents users from selecting the icon as text
822
502
  fontVariationSettings,
823
503
  // web-only: controls the variable font axes listed above
824
504
  ...style
825
505
  };
826
506
  }, [tokens, size, opticalSize, fill, color, style]);
827
- return /* @__PURE__ */ React14__default.default.createElement(
507
+ return /* @__PURE__ */ React13__default.default.createElement(
828
508
  reactNative.Text,
829
509
  {
830
510
  ref,
@@ -837,164 +517,154 @@ function Icon({
837
517
  name
838
518
  );
839
519
  }
840
-
841
- // src/fonts/measureFont.ts
842
- var REF_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ";
843
- function withTimeout(promise, ms, fallback) {
844
- return Promise.race([
845
- promise,
846
- new Promise((resolve) => setTimeout(() => resolve(fallback), ms))
847
- ]);
848
- }
849
- async function measureAvgCharWidth(fontFamily, fontWeight, fallback, fontSize = 16) {
850
- if (typeof document === "undefined") return 0.55;
851
- try {
852
- await withTimeout(
853
- document.fonts.load(`${fontWeight} ${fontSize}px "${fontFamily}"`),
854
- 3e3,
855
- []
856
- );
857
- const canvas = document.createElement("canvas");
858
- const ctx = canvas.getContext("2d");
859
- if (!ctx) return 0.55;
860
- ctx.font = `${fontWeight} ${fontSize}px "${fontFamily}", ${fallback}`;
861
- const ratio = ctx.measureText(REF_STRING).width / REF_STRING.length / fontSize;
862
- return Math.round(ratio * 1e3) / 1e3;
863
- } catch {
864
- return 0.55;
865
- }
866
- }
867
-
868
- // src/fonts/useLocalCalibration.ts
869
- var STORAGE_KEY = "newtone:font-metrics:v1";
870
- var TTL_MS = 7 * 24 * 60 * 60 * 1e3;
871
- function readCache() {
872
- if (typeof localStorage === "undefined") return {};
873
- try {
874
- const raw = localStorage.getItem(STORAGE_KEY);
875
- return raw ? JSON.parse(raw) : {};
876
- } catch {
877
- return {};
878
- }
879
- }
880
- function writeCache(cache) {
881
- if (typeof localStorage === "undefined") return;
882
- try {
883
- localStorage.setItem(STORAGE_KEY, JSON.stringify(cache));
884
- } catch {
885
- }
886
- }
887
- function cacheKey(fontFamily, fontWeight) {
888
- return `${fontFamily}:${fontWeight}`;
889
- }
890
- function useLocalCalibration(fontFamily, fontWeight, fallback, baseCalibration) {
891
- const key = cacheKey(fontFamily, fontWeight);
892
- const [ratio, setRatio] = React14.useState(() => {
893
- const cache = readCache();
894
- const entry = cache[key];
895
- if (entry && Date.now() - entry.measuredAt < TTL_MS) {
896
- return entry.ratio;
897
- }
898
- return baseCalibration ?? 0.55;
899
- });
900
- React14.useEffect(() => {
901
- const cache = readCache();
902
- const entry = cache[key];
903
- if (entry && Date.now() - entry.measuredAt < TTL_MS) {
904
- if (entry.ratio !== ratio) setRatio(entry.ratio);
905
- return;
906
- }
907
- let cancelled = false;
908
- measureAvgCharWidth(fontFamily, fontWeight, fallback).then((measured) => {
909
- if (cancelled) return;
910
- const updated = { ...readCache(), [key]: { ratio: measured, measuredAt: Date.now() } };
911
- writeCache(updated);
912
- setRatio(measured);
913
- });
914
- return () => {
915
- cancelled = true;
916
- };
917
- }, [key, fontFamily, fontWeight, fallback]);
918
- return ratio;
919
- }
920
-
921
- // src/fonts/useTypographyCalibrations.ts
922
- function useTypographyCalibrations() {
923
- const { config } = useNewtoneTheme();
924
- return config.typography.calibrations ?? {};
925
- }
926
-
927
- // src/fonts/reportQueue.ts
928
- var queue = [];
929
- var flushTimer;
930
- function flush() {
931
- if (queue.length === 0) return;
932
- const byEndpoint = /* @__PURE__ */ new Map();
933
- for (const item of queue) {
934
- const group = byEndpoint.get(item.endpoint) ?? [];
935
- group.push(item.payload);
936
- byEndpoint.set(item.endpoint, group);
937
- }
938
- queue.length = 0;
939
- for (const [endpoint, observations] of byEndpoint) {
940
- fetch(endpoint, {
941
- method: "POST",
942
- headers: { "Content-Type": "application/json" },
943
- body: JSON.stringify({ observations }),
944
- // keepalive: true allows the request to outlive the page
945
- keepalive: true
946
- }).catch(() => {
947
- });
520
+ function getWrapperStyles(input) {
521
+ const {
522
+ tokens,
523
+ direction = "vertical",
524
+ wrap = false,
525
+ reverse = false,
526
+ align,
527
+ justify,
528
+ padding,
529
+ gap,
530
+ width,
531
+ height,
532
+ minWidth,
533
+ maxWidth,
534
+ minHeight,
535
+ maxHeight
536
+ } = input;
537
+ const container = {};
538
+ container.flexDirection = resolveFlexDirection(direction, reverse);
539
+ if (wrap) container.flexWrap = "wrap";
540
+ if (align) container.alignItems = resolveAlignment(align);
541
+ if (justify) container.justifyContent = resolveJustification(justify);
542
+ if (padding !== void 0) {
543
+ const p = resolvePadding(padding, tokens);
544
+ container.paddingTop = p.top;
545
+ container.paddingRight = p.right;
546
+ container.paddingBottom = p.bottom;
547
+ container.paddingLeft = p.left;
948
548
  }
949
- }
950
- function enqueueObservation(endpoint, payload) {
951
- queue.push({ endpoint, payload });
952
- if (flushTimer !== void 0) clearTimeout(flushTimer);
953
- flushTimer = setTimeout(flush, 2e3);
954
- }
955
- function useBreakpoint() {
956
- const { width } = reactNative.useWindowDimensions();
957
- return fonts.getBreakpointForWidth(width);
958
- }
959
-
960
- // src/primitives/Text/Text.tsx
961
- var TextScopeContext = React14.createContext(null);
962
- function resolveTextColor(color, tokens) {
963
- switch (color) {
964
- case "primary":
965
- return newtone.srgbToHex(tokens.textPrimary.srgb);
966
- case "secondary":
967
- return newtone.srgbToHex(tokens.textSecondary.srgb);
968
- case "tertiary":
969
- return newtone.srgbToHex(tokens.textTertiary.srgb);
970
- case "disabled":
971
- return newtone.srgbToHex(tokens.textDisabled.srgb);
972
- case "accent":
973
- return newtone.srgbToHex(tokens.accent.fill.srgb);
974
- case "success":
975
- return newtone.srgbToHex(tokens.success.fill.srgb);
976
- case "warning":
977
- return newtone.srgbToHex(tokens.warning.fill.srgb);
978
- case "error":
979
- return newtone.srgbToHex(tokens.error.fill.srgb);
549
+ if (gap !== void 0) {
550
+ const g = resolveGap(gap, tokens);
551
+ container.rowGap = g.rowGap;
552
+ container.columnGap = g.columnGap;
980
553
  }
554
+ Object.assign(container, resolveSizing(width, height));
555
+ if (minWidth !== void 0) container.minWidth = minWidth;
556
+ if (maxWidth !== void 0) container.maxWidth = maxWidth;
557
+ if (minHeight !== void 0) container.minHeight = minHeight;
558
+ if (maxHeight !== void 0) container.maxHeight = maxHeight;
559
+ return reactNative.StyleSheet.create({ c: container }).c;
981
560
  }
982
- var ADAPTIVE_ROLES = /* @__PURE__ */ new Set(["headline", "title", "heading", "subheading"]);
983
- var ROLE_HEADING_LEVEL = {
984
- headline: 1,
985
- title: 2,
986
- heading: 3
987
- };
988
- function extractCharacterCount(node) {
989
- if (typeof node === "string") return node.length;
990
- if (typeof node === "number") return String(node).length;
991
- if (!node) return 0;
992
- if (Array.isArray(node)) {
993
- return node.reduce((sum, child) => sum + extractCharacterCount(child), 0);
994
- }
995
- if (typeof node === "object" && "props" in node) {
996
- return extractCharacterCount(node.props?.children);
997
- }
561
+ function Wrapper({
562
+ children,
563
+ direction,
564
+ wrap,
565
+ reverse,
566
+ align,
567
+ justify,
568
+ padding,
569
+ gap,
570
+ width,
571
+ height,
572
+ minWidth,
573
+ maxWidth,
574
+ minHeight,
575
+ maxHeight,
576
+ style,
577
+ // Testing & platform
578
+ testID,
579
+ nativeID,
580
+ ref
581
+ }) {
582
+ const tokens = newtoneApi.useTokens(1);
583
+ const containerStyle = React13.useMemo(
584
+ () => getWrapperStyles({
585
+ tokens,
586
+ direction,
587
+ wrap,
588
+ reverse,
589
+ align,
590
+ justify,
591
+ padding,
592
+ gap,
593
+ width,
594
+ height,
595
+ minWidth,
596
+ maxWidth,
597
+ minHeight,
598
+ maxHeight
599
+ }),
600
+ [
601
+ tokens,
602
+ direction,
603
+ wrap,
604
+ reverse,
605
+ align,
606
+ justify,
607
+ padding,
608
+ gap,
609
+ width,
610
+ height,
611
+ minWidth,
612
+ maxWidth,
613
+ minHeight,
614
+ maxHeight
615
+ ]
616
+ );
617
+ const userStyles = Array.isArray(style) ? style : style ? [style] : [];
618
+ return /* @__PURE__ */ React13__default.default.createElement(
619
+ reactNative.View,
620
+ {
621
+ ref,
622
+ testID,
623
+ nativeID,
624
+ accessibilityRole: "none",
625
+ style: [containerStyle, ...userStyles]
626
+ },
627
+ children
628
+ );
629
+ }
630
+ var TextScopeContext = React13.createContext(null);
631
+ function resolveTextColor(color, tokens) {
632
+ const { gamut } = tokens;
633
+ switch (color) {
634
+ case "primary":
635
+ return tokens.textPrimary[gamut];
636
+ case "secondary":
637
+ return tokens.textSecondary[gamut];
638
+ case "tertiary":
639
+ return tokens.textTertiary[gamut];
640
+ case "disabled":
641
+ return tokens.textDisabled[gamut];
642
+ case "accent":
643
+ return tokens.accent.fill[gamut];
644
+ case "success":
645
+ return tokens.success.fill[gamut];
646
+ case "warning":
647
+ return tokens.warning.fill[gamut];
648
+ case "error":
649
+ return tokens.error.fill[gamut];
650
+ }
651
+ }
652
+ var ADAPTIVE_ROLES = /* @__PURE__ */ new Set(["headline", "title", "heading", "subheading"]);
653
+ var ROLE_HEADING_LEVEL = {
654
+ headline: 1,
655
+ title: 2,
656
+ heading: 3
657
+ };
658
+ function extractCharacterCount(node) {
659
+ if (typeof node === "string") return node.length;
660
+ if (typeof node === "number") return String(node).length;
661
+ if (!node) return 0;
662
+ if (Array.isArray(node)) {
663
+ return node.reduce((sum, child) => sum + extractCharacterCount(child), 0);
664
+ }
665
+ if (typeof node === "object" && "props" in node) {
666
+ return extractCharacterCount(node.props?.children);
667
+ }
998
668
  return 0;
999
669
  }
1000
670
  function TextBase({
@@ -1016,27 +686,27 @@ function TextBase({
1016
686
  centerVertically = false,
1017
687
  features
1018
688
  }) {
1019
- const tokens = useTokens(elevation);
1020
- const { config, reportingEndpoint } = useNewtoneTheme();
689
+ const tokens = newtoneApi.useTokens(elevation);
690
+ const { config, reportingEndpoint } = newtoneApi.useNewtoneTheme();
1021
691
  const size = sizeOverride ?? "md";
1022
692
  const fontSlot = tokens.typography.fonts[scope];
1023
693
  const resolvedFontWeight = weightOverride ? fonts.SEMANTIC_WEIGHT_MAP[weightOverride] : config.typography.roleWeights?.[role] ?? fonts.ROLE_DEFAULT_WEIGHTS[role];
1024
- const breakpoint = useBreakpoint();
694
+ const breakpoint = newtoneApi.useBreakpoint();
1025
695
  const baseStep = config.typography.roles[role][size];
1026
696
  const bpScale = fonts.BREAKPOINT_ROLE_SCALE[breakpoint][role];
1027
697
  const step = bpScale === 1 ? baseStep : fonts.scaleRoleStep(baseStep, bpScale);
1028
- const calibrations = useTypographyCalibrations();
698
+ const calibrations = newtoneApi.useTypographyCalibrations();
1029
699
  const fontSlotFull = config.typography.fonts[scope];
1030
- const localRatio = useLocalCalibration(
700
+ const localRatio = newtoneApi.useLocalCalibration(
1031
701
  fontSlot.family,
1032
702
  fonts.SEMANTIC_WEIGHT_MAP.regular,
1033
703
  fontSlotFull.config.fallback,
1034
704
  calibrations[fontSlot.family]
1035
705
  );
1036
706
  const isAdaptive = ADAPTIVE_ROLES.has(role);
1037
- const [containerWidth, setContainerWidth] = React14.useState(null);
1038
- const characterCount = React14.useMemo(() => extractCharacterCount(children), [children]);
1039
- const resolvedStep = React14.useMemo(
707
+ const [containerWidth, setContainerWidth] = React13.useState(null);
708
+ const characterCount = React13.useMemo(() => extractCharacterCount(children), [children]);
709
+ const resolvedStep = React13.useMemo(
1040
710
  () => fonts.resolveResponsiveSize(
1041
711
  {
1042
712
  role,
@@ -1053,11 +723,11 @@ function TextBase({
1053
723
  // eslint-disable-next-line react-hooks/exhaustive-deps
1054
724
  [role, size, responsive, isAdaptive, fontSlot.family, step.fontSize, config.typography.roles, containerWidth, characterCount, localRatio]
1055
725
  );
1056
- React14.useEffect(() => {
726
+ React13.useEffect(() => {
1057
727
  if (!reportingEndpoint || !responsive || !isAdaptive || containerWidth == null) return;
1058
728
  const lineWidths = fonts.estimateLineWidths(characterCount, containerWidth, resolvedStep.fontSize, localRatio);
1059
729
  const lastLine = lineWidths[lineWidths.length - 1];
1060
- enqueueObservation(reportingEndpoint, {
730
+ newtoneApi.enqueueObservation(reportingEndpoint, {
1061
731
  fontFamily: fontSlot.family,
1062
732
  fontWeight: resolvedFontWeight,
1063
733
  role,
@@ -1069,7 +739,7 @@ function TextBase({
1069
739
  lastLineRatio: containerWidth > 0 ? lastLine / containerWidth : 1
1070
740
  });
1071
741
  }, [reportingEndpoint, resolvedStep.fontSize, containerWidth]);
1072
- const resolvedStyle = React14.useMemo(() => {
742
+ const resolvedStyle = React13.useMemo(() => {
1073
743
  const activeStep = responsive && isAdaptive ? resolvedStep : step;
1074
744
  const currentMetrics = config.typography.fontMetrics?.[fontSlot.family];
1075
745
  const correctedLineHeight = currentMetrics ? Math.round(activeStep.lineHeight * currentMetrics.naturalLineHeightRatio / fonts.REFERENCE_LINE_HEIGHT_RATIO / 4) * 4 : activeStep.lineHeight;
@@ -1090,8 +760,8 @@ function TextBase({
1090
760
  const inferredA11yRole = role === "headline" || role === "title" || role === "heading" ? "header" : void 0;
1091
761
  const effectiveA11yRole = accessibilityRoleOverride ?? inferredA11yRole;
1092
762
  const ariaLevel = effectiveA11yRole === "header" ? ROLE_HEADING_LEVEL[role] : void 0;
1093
- const scopeCtx = React14.useMemo(() => ({ weights: fonts.SEMANTIC_WEIGHT_MAP }), []);
1094
- const textNode = /* @__PURE__ */ React14__default.default.createElement(TextScopeContext.Provider, { value: scopeCtx }, /* @__PURE__ */ React14__default.default.createElement(
763
+ const scopeCtx = React13.useMemo(() => ({ weights: fonts.SEMANTIC_WEIGHT_MAP }), []);
764
+ const textNode = /* @__PURE__ */ React13__default.default.createElement(TextScopeContext.Provider, { value: scopeCtx }, /* @__PURE__ */ React13__default.default.createElement(
1095
765
  reactNative.Text,
1096
766
  {
1097
767
  ref,
@@ -1105,7 +775,7 @@ function TextBase({
1105
775
  children
1106
776
  ));
1107
777
  if (responsive && isAdaptive) {
1108
- return /* @__PURE__ */ React14__default.default.createElement(
778
+ return /* @__PURE__ */ React13__default.default.createElement(
1109
779
  reactNative.View,
1110
780
  {
1111
781
  onLayout: (e) => {
@@ -1120,9 +790,9 @@ function TextBase({
1120
790
  return textNode;
1121
791
  }
1122
792
  function TextSpan({ children, color, weight, italic, underline, highlight, style }) {
1123
- const tokens = useTokens(1);
1124
- const scopeCtx = React14.useContext(TextScopeContext);
1125
- const spanStyle = React14.useMemo(() => {
793
+ const tokens = newtoneApi.useTokens(1);
794
+ const scopeCtx = React13.useContext(TextScopeContext);
795
+ const spanStyle = React13.useMemo(() => {
1126
796
  const s = {};
1127
797
  if (color) s.color = resolveTextColor(color, tokens);
1128
798
  if (weight && scopeCtx) s.fontWeight = String(scopeCtx.weights[weight]);
@@ -1131,30 +801,30 @@ function TextSpan({ children, color, weight, italic, underline, highlight, style
1131
801
  if (highlight) s.backgroundColor = resolveTextColor(highlight, tokens);
1132
802
  return s;
1133
803
  }, [tokens, scopeCtx, color, weight, italic, underline, highlight]);
1134
- return React14__default.default.createElement(
804
+ return React13__default.default.createElement(
1135
805
  reactNative.Text,
1136
806
  { style: style ? [spanStyle, ...Array.isArray(style) ? style : [style]] : spanStyle },
1137
807
  children
1138
808
  );
1139
809
  }
1140
810
  function TextBold(props) {
1141
- return React14__default.default.createElement(TextSpan, { ...props, weight: "bold" });
811
+ return React13__default.default.createElement(TextSpan, { ...props, weight: "bold" });
1142
812
  }
1143
813
  function TextMedium(props) {
1144
- return React14__default.default.createElement(TextSpan, { ...props, weight: "medium" });
814
+ return React13__default.default.createElement(TextSpan, { ...props, weight: "medium" });
1145
815
  }
1146
816
  function TextItalic(props) {
1147
- return React14__default.default.createElement(TextSpan, { ...props, italic: true });
817
+ return React13__default.default.createElement(TextSpan, { ...props, italic: true });
1148
818
  }
1149
819
  function TextUnderline(props) {
1150
- return React14__default.default.createElement(TextSpan, { ...props, underline: true });
820
+ return React13__default.default.createElement(TextSpan, { ...props, underline: true });
1151
821
  }
1152
822
  function TextHighlight(props) {
1153
- return React14__default.default.createElement(TextSpan, props);
823
+ return React13__default.default.createElement(TextSpan, props);
1154
824
  }
1155
825
 
1156
826
  // src/primitives/Text/index.ts
1157
- var Text2 = Object.assign(TextBase, {
827
+ var Text3 = Object.assign(TextBase, {
1158
828
  Span: TextSpan,
1159
829
  Bold: TextBold,
1160
830
  Medium: TextMedium,
@@ -1163,655 +833,297 @@ var Text2 = Object.assign(TextBase, {
1163
833
  Highlight: TextHighlight
1164
834
  });
1165
835
 
1166
- // src/primitives/Frame/Frame.utils.ts
1167
- function resolveSpacing(value, tokens) {
1168
- if (typeof value === "number") return value;
1169
- return tokens.spacing[value];
1170
- }
1171
- function resolvePadding(prop, tokens) {
1172
- if (typeof prop === "string" || typeof prop === "number") {
1173
- const px = resolveSpacing(prop, tokens);
1174
- return { top: px, right: px, bottom: px, left: px };
836
+ // src/composites/actions/Button/Button.styles.ts
837
+ function computeButtonPadding(size, hasIcon, hasText, iconPosition) {
838
+ const basePadding = {
839
+ sm: 8,
840
+ md: 12,
841
+ lg: 16
842
+ };
843
+ const base = basePadding[size];
844
+ const textExtra = 8;
845
+ if (!hasText && hasIcon) {
846
+ return {
847
+ paddingLeft: base,
848
+ paddingRight: base,
849
+ paddingTop: base,
850
+ paddingBottom: base
851
+ };
1175
852
  }
1176
- if ("x" in prop || "y" in prop) {
1177
- const axes = prop;
1178
- const x = axes.x !== void 0 ? resolveSpacing(axes.x, tokens) : 0;
1179
- const y = axes.y !== void 0 ? resolveSpacing(axes.y, tokens) : 0;
1180
- return { top: y, right: x, bottom: y, left: x };
853
+ if (hasText && !hasIcon) {
854
+ return {
855
+ paddingLeft: base + textExtra,
856
+ paddingRight: base + textExtra,
857
+ paddingTop: base,
858
+ paddingBottom: base
859
+ };
1181
860
  }
1182
- const sides = prop;
1183
- return {
1184
- top: sides.top !== void 0 ? resolveSpacing(sides.top, tokens) : 0,
1185
- right: sides.right !== void 0 ? resolveSpacing(sides.right, tokens) : 0,
1186
- bottom: sides.bottom !== void 0 ? resolveSpacing(sides.bottom, tokens) : 0,
1187
- left: sides.left !== void 0 ? resolveSpacing(sides.left, tokens) : 0
1188
- };
1189
- }
1190
- function resolveGap(prop, tokens) {
1191
- if (typeof prop === "string" || typeof prop === "number") {
1192
- const px = resolveSpacing(prop, tokens);
1193
- return { rowGap: px, columnGap: px };
861
+ if (hasText && hasIcon) {
862
+ if (iconPosition === "left") {
863
+ return {
864
+ paddingLeft: base,
865
+ paddingRight: base + textExtra,
866
+ paddingTop: base,
867
+ paddingBottom: base
868
+ };
869
+ } else {
870
+ return {
871
+ paddingLeft: base + textExtra,
872
+ paddingRight: base,
873
+ paddingTop: base,
874
+ paddingBottom: base
875
+ };
876
+ }
1194
877
  }
1195
878
  return {
1196
- rowGap: prop.row !== void 0 ? resolveSpacing(prop.row, tokens) : 0,
1197
- columnGap: prop.column !== void 0 ? resolveSpacing(prop.column, tokens) : 0
879
+ paddingLeft: base,
880
+ paddingRight: base,
881
+ paddingTop: base,
882
+ paddingBottom: base
1198
883
  };
1199
884
  }
1200
- function resolveRadius(value, tokens) {
1201
- if (typeof value === "number") return value;
1202
- return tokens.radius[value];
1203
- }
1204
- function resolveRadiusCorners(prop, tokens) {
1205
- if (typeof prop === "string" || typeof prop === "number") {
1206
- const px = resolveRadius(prop, tokens);
1207
- return { topLeft: px, topRight: px, bottomLeft: px, bottomRight: px };
885
+ function getPaletteTokens(semantic, tokens) {
886
+ switch (semantic) {
887
+ case "accent":
888
+ return tokens.accent;
889
+ case "success":
890
+ return tokens.success;
891
+ case "error":
892
+ return tokens.error;
893
+ case "warning":
894
+ return tokens.warning;
895
+ default:
896
+ return void 0;
1208
897
  }
1209
- return {
1210
- topLeft: prop.topLeft !== void 0 ? resolveRadius(prop.topLeft, tokens) : 0,
1211
- topRight: prop.topRight !== void 0 ? resolveRadius(prop.topRight, tokens) : 0,
1212
- bottomLeft: prop.bottomLeft !== void 0 ? resolveRadius(prop.bottomLeft, tokens) : 0,
1213
- bottomRight: prop.bottomRight !== void 0 ? resolveRadius(prop.bottomRight, tokens) : 0
1214
- };
1215
- }
1216
- function hasPositiveRadius(corners) {
1217
- return corners.topLeft > 0 || corners.topRight > 0 || corners.bottomLeft > 0 || corners.bottomRight > 0;
1218
898
  }
1219
- function resolveSizing(width, height) {
1220
- const style = {};
1221
- if (width !== void 0) {
1222
- if (width === "fill") {
1223
- style.flexGrow = 1;
1224
- style.width = "100%";
1225
- } else if (typeof width === "number") {
1226
- style.width = width;
1227
- }
1228
- }
1229
- if (height !== void 0) {
1230
- if (height === "fill") {
1231
- style.flexGrow = 1;
1232
- style.height = "100%";
1233
- } else if (typeof height === "number") {
1234
- style.height = height;
899
+ function getButtonConfig(variant, semantic, size, disabled, tokens) {
900
+ const sizeConfig = getSizeConfig(size, tokens);
901
+ const variantColors = getVariantColors(variant, semantic, disabled, tokens);
902
+ return {
903
+ variantColors,
904
+ sizeTokens: {
905
+ padding: sizeConfig.padding,
906
+ gap: sizeConfig.gap,
907
+ borderRadius: sizeConfig.borderRadius,
908
+ textSize: sizeConfig.textSize,
909
+ iconSize: sizeConfig.iconSize
1235
910
  }
1236
- }
1237
- return style;
1238
- }
1239
- var ALIGN_MAP = {
1240
- start: "flex-start",
1241
- center: "center",
1242
- end: "flex-end",
1243
- stretch: "stretch",
1244
- baseline: "baseline"
1245
- };
1246
- var JUSTIFY_MAP = {
1247
- start: "flex-start",
1248
- center: "center",
1249
- end: "flex-end",
1250
- between: "space-between",
1251
- around: "space-around",
1252
- evenly: "space-evenly"
1253
- };
1254
- function resolveAlignment(align) {
1255
- return ALIGN_MAP[align];
1256
- }
1257
- function resolveJustification(justify) {
1258
- return JUSTIFY_MAP[justify];
1259
- }
1260
- function resolveFlexDirection(direction, reverse) {
1261
- if (direction === "horizontal") {
1262
- return reverse ? "row-reverse" : "row";
1263
- }
1264
- return reverse ? "column-reverse" : "column";
911
+ };
1265
912
  }
1266
-
1267
- // src/primitives/Wrapper/Wrapper.styles.ts
1268
- function getWrapperStyles(input) {
1269
- const {
1270
- tokens,
1271
- direction = "vertical",
1272
- wrap = false,
1273
- reverse = false,
1274
- align,
1275
- justify,
1276
- padding,
1277
- gap,
1278
- width,
1279
- height,
1280
- minWidth,
1281
- maxWidth,
1282
- minHeight,
1283
- maxHeight
1284
- } = input;
1285
- const container = {};
1286
- container.flexDirection = resolveFlexDirection(direction, reverse);
1287
- if (wrap) container.flexWrap = "wrap";
1288
- if (align) container.alignItems = resolveAlignment(align);
1289
- if (justify) container.justifyContent = resolveJustification(justify);
1290
- if (padding !== void 0) {
1291
- const p = resolvePadding(padding, tokens);
1292
- container.paddingTop = p.top;
1293
- container.paddingRight = p.right;
1294
- container.paddingBottom = p.bottom;
1295
- container.paddingLeft = p.left;
1296
- }
1297
- if (gap !== void 0) {
1298
- const g = resolveGap(gap, tokens);
1299
- container.rowGap = g.rowGap;
1300
- container.columnGap = g.columnGap;
1301
- }
1302
- Object.assign(container, resolveSizing(width, height));
1303
- if (minWidth !== void 0) container.minWidth = minWidth;
1304
- if (maxWidth !== void 0) container.maxWidth = maxWidth;
1305
- if (minHeight !== void 0) container.minHeight = minHeight;
1306
- if (maxHeight !== void 0) container.maxHeight = maxHeight;
1307
- return reactNative.StyleSheet.create({ c: container }).c;
1308
- }
1309
-
1310
- // src/primitives/Wrapper/Wrapper.tsx
1311
- function Wrapper({
1312
- children,
1313
- direction,
1314
- wrap,
1315
- reverse,
1316
- align,
1317
- justify,
1318
- padding,
1319
- gap,
1320
- width,
1321
- height,
1322
- minWidth,
1323
- maxWidth,
1324
- minHeight,
1325
- maxHeight,
1326
- style,
1327
- // Testing & platform
1328
- testID,
1329
- nativeID,
1330
- ref
1331
- }) {
1332
- const tokens = useTokens(1);
1333
- const containerStyle = React14.useMemo(
1334
- () => getWrapperStyles({
1335
- tokens,
1336
- direction,
1337
- wrap,
1338
- reverse,
1339
- align,
1340
- justify,
1341
- padding,
1342
- gap,
1343
- width,
1344
- height,
1345
- minWidth,
1346
- maxWidth,
1347
- minHeight,
1348
- maxHeight
1349
- }),
1350
- [
1351
- tokens,
1352
- direction,
1353
- wrap,
1354
- reverse,
1355
- align,
1356
- justify,
1357
- padding,
1358
- gap,
1359
- width,
1360
- height,
1361
- minWidth,
1362
- maxWidth,
1363
- minHeight,
1364
- maxHeight
1365
- ]
1366
- );
1367
- const userStyles = Array.isArray(style) ? style : style ? [style] : [];
1368
- return /* @__PURE__ */ React14__default.default.createElement(
1369
- reactNative.View,
1370
- {
1371
- ref,
1372
- testID,
1373
- nativeID,
1374
- accessibilityRole: "none",
1375
- style: [containerStyle, ...userStyles]
1376
- },
1377
- children
1378
- );
1379
- }
1380
-
1381
- // src/composites/actions/Button/Button.tsx
1382
- function Button({
1383
- children,
1384
- icon,
1385
- iconPosition = "left",
1386
- variant = "primary",
1387
- semantic = "neutral",
1388
- size = "md",
1389
- disabled = false,
1390
- style,
1391
- textStyle,
1392
- ...pressableProps
1393
- }) {
1394
- const tokens = useTokens();
1395
- const { variantColors, sizeTokens } = React14__default.default.useMemo(
1396
- () => getButtonConfig(variant, semantic, size, disabled, tokens),
1397
- [variant, semantic, size, disabled, tokens]
1398
- );
1399
- const padding = React14__default.default.useMemo(
1400
- () => computeButtonPadding(size, !!icon, !!children, iconPosition),
1401
- [size, icon, children, iconPosition]
1402
- );
1403
- return /* @__PURE__ */ React14__default.default.createElement(reactNative.Pressable, { disabled, ...pressableProps }, ({ pressed, hovered }) => (
1404
- // Wrapper handles layout: direction, gap, alignment (padding via style)
1405
- /* @__PURE__ */ React14__default.default.createElement(
1406
- Wrapper,
1407
- {
1408
- direction: "horizontal",
1409
- align: "center",
1410
- justify: "center",
1411
- gap: sizeTokens.gap,
1412
- style: [
1413
- {
1414
- ...padding,
1415
- // Asymmetric horizontal padding for text optical balance
1416
- backgroundColor: pressed && !disabled ? variantColors.pressedBg : hovered && !disabled ? variantColors.hoveredBg : variantColors.bg,
1417
- borderRadius: sizeTokens.borderRadius,
1418
- borderWidth: variantColors.borderWidth,
1419
- // Always 1 for consistent sizing
1420
- borderColor: variantColors.borderColor || "transparent",
1421
- opacity: disabled ? 0.4 : 1
1422
- },
1423
- ...Array.isArray(style) ? style : style ? [style] : []
1424
- ]
1425
- },
1426
- icon && iconPosition === "left" && /* @__PURE__ */ React14__default.default.createElement(Icon, { name: icon, size: sizeTokens.iconSize, color: variantColors.iconColor }),
1427
- children && // Text primitive with semantic props + color style override
1428
- /* @__PURE__ */ React14__default.default.createElement(
1429
- Text2,
1430
- {
1431
- role: "label",
1432
- size: sizeTokens.textSize,
1433
- centerVertically: true,
1434
- style: [
1435
- { color: variantColors.textColor },
1436
- ...Array.isArray(textStyle) ? textStyle : textStyle ? [textStyle] : []
1437
- ]
1438
- },
1439
- children
1440
- ),
1441
- icon && iconPosition === "right" && /* @__PURE__ */ React14__default.default.createElement(Icon, { name: icon, size: sizeTokens.iconSize, color: variantColors.iconColor })
1442
- )
1443
- ));
1444
- }
1445
- function getCardStyles(tokens, disabled) {
1446
- return reactNative.StyleSheet.create({
1447
- container: {
1448
- backgroundColor: newtone.srgbToHex(tokens.background.srgb),
1449
- borderWidth: 1,
1450
- borderColor: newtone.srgbToHex(tokens.border.srgb),
1451
- borderRadius: tokens.radius.lg,
1452
- padding: tokens.spacing["16"],
1453
- opacity: disabled ? 0.5 : 1
1454
- }
1455
- });
1456
- }
1457
-
1458
- // src/composites/layout/Card/Card.tsx
1459
- function Card({
1460
- children,
1461
- elevation = 1,
1462
- style,
1463
- disabled = false
1464
- }) {
1465
- const tokens = useTokens(elevation);
1466
- const styles = React14__default.default.useMemo(
1467
- () => getCardStyles(tokens, disabled),
1468
- [tokens, disabled]
1469
- );
1470
- return /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : [style]] }, children);
1471
- }
1472
- var hadKeyboardEvent = false;
1473
- var isListenerSetup = false;
1474
- function setupModality() {
1475
- if (isListenerSetup || typeof document === "undefined") return;
1476
- isListenerSetup = true;
1477
- const NAVIGATION_KEYS = /* @__PURE__ */ new Set([
1478
- "Tab",
1479
- "ArrowUp",
1480
- "ArrowDown",
1481
- "ArrowLeft",
1482
- "ArrowRight",
1483
- "Enter",
1484
- " ",
1485
- "Escape"
1486
- ]);
1487
- document.addEventListener("keydown", (e) => {
1488
- if (NAVIGATION_KEYS.has(e.key)) {
1489
- hadKeyboardEvent = true;
1490
- }
1491
- }, true);
1492
- document.addEventListener("pointerdown", () => {
1493
- hadKeyboardEvent = false;
1494
- }, true);
1495
- document.addEventListener("mousedown", () => {
1496
- hadKeyboardEvent = false;
1497
- }, true);
1498
- }
1499
- function useFocusVisible() {
1500
- const [isFocusVisible, setIsFocusVisible] = React14.useState(false);
1501
- React14.useEffect(() => {
1502
- setupModality();
1503
- }, []);
1504
- const onFocus = React14.useCallback(() => {
1505
- if (hadKeyboardEvent) {
1506
- setIsFocusVisible(true);
1507
- }
1508
- }, []);
1509
- const onBlur = React14.useCallback(() => {
1510
- setIsFocusVisible(false);
1511
- }, []);
1512
- const focusProps = { onFocus, onBlur };
1513
- return { isFocusVisible, focusProps };
1514
- }
1515
- function getFrameStyles(input) {
1516
- const {
1517
- tokens,
1518
- frameElevation,
1519
- layout = "flex",
1520
- direction = "vertical",
1521
- wrap = false,
1522
- reverse = false,
1523
- columns,
1524
- rows,
1525
- align,
1526
- justify,
1527
- padding,
1528
- gap,
1529
- width,
1530
- height,
1531
- minWidth,
1532
- maxWidth,
1533
- minHeight,
1534
- maxHeight,
1535
- radius,
1536
- bordered = false,
1537
- disabled = false
1538
- } = input;
1539
- const container = {};
1540
- container.backgroundColor = newtone.srgbToHex(tokens.background.srgb);
1541
- container.color = newtone.srgbToHex(tokens.textPrimary.srgb);
1542
- if (layout === "flex") {
1543
- container.display = "flex";
1544
- container.flexDirection = resolveFlexDirection(direction, reverse);
1545
- if (wrap) container.flexWrap = "wrap";
1546
- }
1547
- if (layout === "grid") {
1548
- container.display = "flex";
1549
- container.flexDirection = "row";
1550
- container.flexWrap = "wrap";
1551
- }
1552
- if (align) container.alignItems = resolveAlignment(align);
1553
- if (justify) container.justifyContent = resolveJustification(justify);
1554
- if (padding !== void 0) {
1555
- const p = resolvePadding(padding, tokens);
1556
- container.paddingTop = p.top;
1557
- container.paddingRight = p.right;
1558
- container.paddingBottom = p.bottom;
1559
- container.paddingLeft = p.left;
1560
- }
1561
- if (gap !== void 0) {
1562
- const g = resolveGap(gap, tokens);
1563
- container.rowGap = g.rowGap;
1564
- container.columnGap = g.columnGap;
1565
- }
1566
- const sizing = resolveSizing(width, height);
1567
- Object.assign(container, sizing);
1568
- if (minWidth !== void 0) container.minWidth = minWidth;
1569
- if (maxWidth !== void 0) container.maxWidth = maxWidth;
1570
- if (minHeight !== void 0) container.minHeight = minHeight;
1571
- if (maxHeight !== void 0) container.maxHeight = maxHeight;
1572
- if (radius !== void 0) {
1573
- const corners = resolveRadiusCorners(radius, tokens);
1574
- container.borderTopLeftRadius = corners.topLeft;
1575
- container.borderTopRightRadius = corners.topRight;
1576
- container.borderBottomLeftRadius = corners.bottomLeft;
1577
- container.borderBottomRightRadius = corners.bottomRight;
1578
- if (hasPositiveRadius(corners)) {
1579
- container.overflow = "hidden";
1580
- }
1581
- }
1582
- if (bordered) {
1583
- container.borderWidth = 1;
1584
- container.borderColor = newtone.srgbToHex(tokens.border.srgb);
1585
- }
1586
- if (frameElevation === 2) {
1587
- container.shadowColor = "#000";
1588
- container.shadowOffset = { width: 0, height: 2 };
1589
- container.shadowOpacity = 0.12;
1590
- container.shadowRadius = 6;
1591
- container.elevation = 4;
1592
- }
1593
- if (disabled) {
1594
- container.opacity = 0.5;
1595
- }
1596
- const pressed = reactNative.StyleSheet.create({
1597
- s: { backgroundColor: newtone.srgbToHex(tokens.backgroundSunken.srgb) }
1598
- }).s;
1599
- let gridWebStyle = null;
1600
- if (layout === "grid") {
1601
- gridWebStyle = {
1602
- display: "grid",
1603
- // Divide into equal-width columns (e.g. 3 columns → "repeat(3, 1fr)").
1604
- gridTemplateColumns: columns ? `repeat(${columns}, 1fr)` : void 0,
1605
- gridTemplateRows: rows ? `repeat(${rows}, 1fr)` : void 0
1606
- };
1607
- }
1608
- const insetBoxShadow = frameElevation === -2 ? "inset 0 2px 4px rgba(0,0,0,0.12)" : null;
1609
- return {
1610
- // Validate and optimize the container styles through StyleSheet.create(),
1611
- // then extract the single style object with `.c`.
1612
- container: reactNative.StyleSheet.create({ c: container }).c,
1613
- pressed,
1614
- gridWebStyle,
1615
- insetBoxShadow
1616
- };
1617
- }
1618
-
1619
- // src/primitives/Frame/Frame.tsx
1620
- function wrapTextChildren(children, textStyle) {
1621
- return React14__default.default.Children.map(children, (child) => {
1622
- if (typeof child === "string" || typeof child === "number") {
1623
- return /* @__PURE__ */ React14__default.default.createElement(reactNative.Text, { style: textStyle }, child);
1624
- }
1625
- return child;
1626
- });
1627
- }
1628
- function toElevationLevel(frameElevation) {
1629
- if (frameElevation <= -1) return 0;
1630
- if (frameElevation === 0) return 1;
1631
- return 2;
1632
- }
1633
- function Frame({
1634
- children,
1635
- // Elevation
1636
- elevation,
1637
- // Layout
1638
- layout,
1639
- direction,
1640
- wrap,
1641
- reverse,
1642
- columns,
1643
- rows,
1644
- // Alignment
1645
- align,
1646
- justify,
1647
- // Spacing
1648
- padding,
1649
- gap,
1650
- // Sizing
1651
- width,
1652
- height,
1653
- minWidth,
1654
- maxWidth,
1655
- minHeight,
1656
- maxHeight,
1657
- // Appearance
1658
- radius,
1659
- bordered,
1660
- // Interactivity
1661
- onPress,
1662
- href,
1663
- disabled = false,
1664
- // Accessibility
1665
- accessibilityLabel,
1666
- accessibilityHint,
1667
- // Testing & platform
1668
- testID,
1669
- nativeID,
1670
- ref,
1671
- // Style override
1672
- style
1673
- }) {
1674
- const { config, mode } = useNewtoneTheme();
1675
- const parentFrameCtx = useFrameContext();
1676
- const resolvedFrameElevation = elevation ?? 0;
1677
- const resolvedElevation = elevation !== void 0 ? toElevationLevel(elevation) : parentFrameCtx?.elevation ?? 1;
1678
- const tokens = React14.useMemo(() => {
1679
- return computeTokens(
1680
- config.colorSystem,
1681
- mode,
1682
- resolvedElevation,
1683
- config.spacing,
1684
- config.radius,
1685
- config.typography,
1686
- config.icons,
1687
- config.tokenOverrides
1688
- );
1689
- }, [config, mode, resolvedElevation]);
1690
- const styles = React14.useMemo(
1691
- () => getFrameStyles({
1692
- tokens,
1693
- frameElevation: resolvedFrameElevation,
1694
- layout,
1695
- direction,
1696
- wrap,
1697
- reverse,
1698
- columns,
1699
- rows,
1700
- align,
1701
- justify,
1702
- padding,
1703
- gap,
1704
- width,
1705
- height,
1706
- minWidth,
1707
- maxWidth,
1708
- minHeight,
1709
- maxHeight,
1710
- radius,
1711
- bordered,
1712
- disabled
1713
- }),
1714
- [
1715
- tokens,
1716
- resolvedFrameElevation,
1717
- layout,
1718
- direction,
1719
- wrap,
1720
- reverse,
1721
- columns,
1722
- rows,
1723
- align,
1724
- justify,
1725
- padding,
1726
- gap,
1727
- width,
1728
- height,
1729
- minWidth,
1730
- maxWidth,
1731
- minHeight,
1732
- maxHeight,
1733
- radius,
1734
- bordered,
1735
- disabled
1736
- ]
1737
- );
1738
- const contextValue = React14.useMemo(
1739
- () => ({ elevation: resolvedElevation, tokens }),
1740
- [resolvedElevation, tokens]
1741
- );
1742
- const webOverrides = [];
1743
- if (styles.gridWebStyle) {
1744
- webOverrides.push(styles.gridWebStyle);
913
+ function getSizeConfig(size, tokens) {
914
+ const configs = {
915
+ sm: {
916
+ padding: 8,
917
+ gap: tokens.spacing["08"],
918
+ borderRadius: 8,
919
+ textSize: "md",
920
+ // 16px
921
+ iconSize: 24
922
+ },
923
+ md: {
924
+ padding: 12,
925
+ gap: tokens.spacing["08"],
926
+ borderRadius: 12,
927
+ textSize: "md",
928
+ // 16px
929
+ iconSize: 24
930
+ },
931
+ lg: {
932
+ padding: 16,
933
+ gap: tokens.spacing["08"],
934
+ borderRadius: 16,
935
+ textSize: "md",
936
+ // 16px
937
+ iconSize: 24
938
+ }
939
+ };
940
+ return configs[size];
941
+ }
942
+ function getVariantColors(variant, semantic, disabled, tokens) {
943
+ if (disabled) {
944
+ const baseColors = getVariantColorsForState(variant, semantic, tokens);
945
+ const { gamut } = tokens;
946
+ const disabledBg = tokens.backgroundSunken[gamut];
947
+ return {
948
+ ...baseColors,
949
+ bg: disabledBg,
950
+ hoveredBg: disabledBg,
951
+ pressedBg: disabledBg,
952
+ textColor: tokens.textSecondary[gamut],
953
+ iconColor: tokens.textSecondary[gamut]
954
+ };
1745
955
  }
1746
- if (styles.insetBoxShadow) {
1747
- webOverrides.push({ boxShadow: styles.insetBoxShadow });
956
+ return getVariantColorsForState(variant, semantic, tokens);
957
+ }
958
+ function getVariantColorsForState(variant, semantic, tokens) {
959
+ const { gamut } = tokens;
960
+ const paletteTokens = getPaletteTokens(semantic, tokens);
961
+ if (variant === "primary") {
962
+ if (semantic === "neutral") {
963
+ return {
964
+ bg: tokens.backgroundInteractive[gamut],
965
+ hoveredBg: tokens.backgroundInteractiveHover[gamut],
966
+ pressedBg: tokens.backgroundInteractiveActive[gamut],
967
+ textColor: tokens.textPrimary[gamut],
968
+ iconColor: tokens.textPrimary[gamut],
969
+ borderWidth: 1,
970
+ borderColor: "transparent"
971
+ };
972
+ }
973
+ return {
974
+ bg: paletteTokens.fill[gamut],
975
+ hoveredBg: paletteTokens.fillHover[gamut],
976
+ pressedBg: paletteTokens.fillActive[gamut],
977
+ textColor: paletteTokens.onFill[gamut],
978
+ iconColor: paletteTokens.onFill[gamut],
979
+ borderWidth: 1,
980
+ borderColor: "transparent"
981
+ };
1748
982
  }
1749
- const userStyles = Array.isArray(style) ? style : style ? [style] : [];
1750
- const isInteractive = onPress !== void 0 || href !== void 0;
1751
- const { isFocusVisible, focusProps } = useFocusVisible();
1752
- const focusRingStyle = isFocusVisible && !disabled ? {
1753
- outlineWidth: 2,
1754
- outlineStyle: "solid",
1755
- outlineColor: newtone.srgbToHex(tokens.accent.fill.srgb),
1756
- outlineOffset: 2
1757
- } : void 0;
1758
- const webFocusProps = isInteractive ? focusProps : {};
1759
- const textStyle = React14.useMemo(
1760
- () => ({
1761
- color: newtone.srgbToHex(tokens.textPrimary.srgb),
1762
- fontSize: tokens.typography.fontSizes["05"],
1763
- fontFamily: tokens.typography.fonts.main.family,
1764
- lineHeight: tokens.typography.lineHeights["06"]
1765
- }),
1766
- [tokens]
983
+ if (variant === "secondary") {
984
+ if (semantic === "neutral") {
985
+ return {
986
+ bg: "transparent",
987
+ hoveredBg: tokens.backgroundInteractive[gamut],
988
+ pressedBg: tokens.backgroundInteractiveHover[gamut],
989
+ textColor: tokens.textPrimary[gamut],
990
+ iconColor: tokens.textPrimary[gamut],
991
+ borderWidth: 1,
992
+ borderColor: tokens.border[gamut]
993
+ };
994
+ }
995
+ return {
996
+ bg: paletteTokens.background[gamut],
997
+ hoveredBg: paletteTokens.backgroundInteractive[gamut],
998
+ pressedBg: paletteTokens.backgroundInteractiveHover[gamut],
999
+ textColor: paletteTokens.fill[gamut],
1000
+ iconColor: paletteTokens.fill[gamut],
1001
+ borderWidth: 1,
1002
+ borderColor: "transparent"
1003
+ };
1004
+ }
1005
+ if (variant === "tertiary") {
1006
+ if (semantic === "neutral") {
1007
+ return {
1008
+ bg: "transparent",
1009
+ hoveredBg: tokens.backgroundInteractive[gamut],
1010
+ pressedBg: tokens.backgroundInteractiveHover[gamut],
1011
+ textColor: tokens.textPrimary[gamut],
1012
+ iconColor: tokens.textPrimary[gamut],
1013
+ borderWidth: 1,
1014
+ borderColor: "transparent"
1015
+ };
1016
+ }
1017
+ return {
1018
+ bg: "transparent",
1019
+ hoveredBg: paletteTokens.background[gamut],
1020
+ pressedBg: paletteTokens.backgroundInteractive[gamut],
1021
+ textColor: paletteTokens.fill[gamut],
1022
+ iconColor: paletteTokens.fill[gamut],
1023
+ borderWidth: 1,
1024
+ borderColor: "transparent"
1025
+ };
1026
+ }
1027
+ return {
1028
+ bg: "transparent",
1029
+ hoveredBg: "transparent",
1030
+ pressedBg: "transparent",
1031
+ textColor: tokens.textPrimary[gamut],
1032
+ iconColor: tokens.textPrimary[gamut],
1033
+ borderWidth: 0
1034
+ };
1035
+ }
1036
+ function Button({
1037
+ children,
1038
+ icon,
1039
+ iconPosition = "left",
1040
+ variant = "primary",
1041
+ semantic = "neutral",
1042
+ size = "md",
1043
+ disabled = false,
1044
+ style,
1045
+ textStyle,
1046
+ ...pressableProps
1047
+ }) {
1048
+ const tokens = newtoneApi.useTokens();
1049
+ const { variantColors, sizeTokens } = React13__default.default.useMemo(
1050
+ () => getButtonConfig(variant, semantic, size, disabled, tokens),
1051
+ [variant, semantic, size, disabled, tokens]
1767
1052
  );
1768
- const wrappedChildren = React14.useMemo(
1769
- () => wrapTextChildren(children, textStyle),
1770
- [children, textStyle]
1053
+ const padding = React13__default.default.useMemo(
1054
+ () => computeButtonPadding(size, !!icon, !!children, iconPosition),
1055
+ [size, icon, children, iconPosition]
1771
1056
  );
1772
- return /* @__PURE__ */ React14__default.default.createElement(FrameContext.Provider, { value: contextValue }, isInteractive ? (
1773
- // Pressable handles taps. When href is set, react-native-web renders
1774
- // it as an <a> tag so it works like a regular link on the web.
1775
- /* @__PURE__ */ React14__default.default.createElement(
1776
- reactNative.Pressable,
1057
+ return /* @__PURE__ */ React13__default.default.createElement(reactNative.Pressable, { disabled, ...pressableProps }, ({ pressed, hovered }) => (
1058
+ // Wrapper handles layout: direction, gap, alignment (padding via style)
1059
+ /* @__PURE__ */ React13__default.default.createElement(
1060
+ Wrapper,
1777
1061
  {
1778
- ref,
1779
- testID,
1780
- nativeID,
1781
- accessibilityLabel,
1782
- accessibilityHint,
1783
- accessibilityState: disabled ? { disabled: true } : void 0,
1784
- onPress,
1785
- disabled,
1786
- ...href ? { href, accessibilityRole: "link" } : { accessibilityRole: "button" },
1787
- ...webFocusProps,
1788
- style: ({ pressed }) => [
1789
- styles.container,
1790
- pressed && !disabled && styles.pressed,
1791
- focusRingStyle,
1792
- ...webOverrides,
1793
- ...userStyles
1062
+ direction: "horizontal",
1063
+ align: "center",
1064
+ justify: "center",
1065
+ gap: sizeTokens.gap,
1066
+ style: [
1067
+ {
1068
+ ...padding,
1069
+ // Asymmetric horizontal padding for text optical balance
1070
+ backgroundColor: pressed && !disabled ? variantColors.pressedBg : hovered && !disabled ? variantColors.hoveredBg : variantColors.bg,
1071
+ borderRadius: sizeTokens.borderRadius,
1072
+ borderWidth: variantColors.borderWidth,
1073
+ // Always 1 for consistent sizing
1074
+ borderColor: variantColors.borderColor || "transparent",
1075
+ opacity: disabled ? 0.4 : 1
1076
+ },
1077
+ ...Array.isArray(style) ? style : style ? [style] : []
1794
1078
  ]
1795
1079
  },
1796
- wrappedChildren
1797
- )
1798
- ) : (
1799
- // Non-interactive Frame: just a plain View with no tap handling.
1800
- /* @__PURE__ */ React14__default.default.createElement(
1801
- reactNative.View,
1802
- {
1803
- ref,
1804
- testID,
1805
- nativeID,
1806
- accessibilityLabel,
1807
- accessibilityHint,
1808
- style: [styles.container, ...webOverrides, ...userStyles]
1809
- },
1810
- wrappedChildren
1080
+ icon && iconPosition === "left" && /* @__PURE__ */ React13__default.default.createElement(Icon, { name: icon, size: sizeTokens.iconSize, color: variantColors.iconColor }),
1081
+ children && // Text primitive with semantic props + color style override
1082
+ /* @__PURE__ */ React13__default.default.createElement(
1083
+ Text3,
1084
+ {
1085
+ role: "label",
1086
+ size: sizeTokens.textSize,
1087
+ centerVertically: true,
1088
+ style: [
1089
+ { color: variantColors.textColor },
1090
+ ...Array.isArray(textStyle) ? textStyle : textStyle ? [textStyle] : []
1091
+ ]
1092
+ },
1093
+ children
1094
+ ),
1095
+ icon && iconPosition === "right" && /* @__PURE__ */ React13__default.default.createElement(Icon, { name: icon, size: sizeTokens.iconSize, color: variantColors.iconColor })
1811
1096
  )
1812
1097
  ));
1813
1098
  }
1814
- function getTextInputStyles(tokens, disabled) {
1099
+ function getCardStyles(tokens, gamut, disabled) {
1100
+ return reactNative.StyleSheet.create({
1101
+ container: {
1102
+ backgroundColor: tokens.background[gamut],
1103
+ borderWidth: 1,
1104
+ borderColor: tokens.border[gamut],
1105
+ borderRadius: tokens.radius.lg,
1106
+ padding: tokens.spacing["16"],
1107
+ opacity: disabled ? 0.5 : 1
1108
+ }
1109
+ });
1110
+ }
1111
+
1112
+ // src/composites/layout/Card/Card.tsx
1113
+ function Card({
1114
+ children,
1115
+ elevation = 1,
1116
+ style,
1117
+ disabled = false
1118
+ }) {
1119
+ const tokens = newtoneApi.useTokens(elevation);
1120
+ const styles = React13__default.default.useMemo(
1121
+ () => getCardStyles(tokens, tokens.gamut, disabled),
1122
+ [tokens, disabled]
1123
+ );
1124
+ return /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : [style]] }, children);
1125
+ }
1126
+ function getTextInputStyles(tokens, gamut, disabled) {
1815
1127
  return reactNative.StyleSheet.create({
1816
1128
  container: {
1817
1129
  gap: tokens.spacing["04"]
@@ -1820,44 +1132,46 @@ function getTextInputStyles(tokens, disabled) {
1820
1132
  fontFamily: tokens.typography.fonts.main.family,
1821
1133
  fontSize: tokens.typography.fontSizes["04"],
1822
1134
  fontWeight: tokens.typography.fonts.main.weights.medium,
1823
- color: newtone.srgbToHex(tokens.textSecondary.srgb)
1135
+ color: tokens.textSecondary[gamut]
1824
1136
  },
1825
1137
  input: {
1826
1138
  fontFamily: tokens.typography.fonts.main.family,
1827
- backgroundColor: newtone.srgbToHex(tokens.backgroundSunken.srgb),
1139
+ backgroundColor: tokens.backgroundSunken[gamut],
1828
1140
  borderWidth: 1,
1829
- borderColor: newtone.srgbToHex(tokens.border.srgb),
1141
+ borderColor: tokens.border[gamut],
1830
1142
  borderRadius: tokens.radius.md,
1831
1143
  paddingVertical: tokens.spacing["08"],
1832
1144
  paddingHorizontal: tokens.spacing["12"],
1833
1145
  fontSize: tokens.typography.fontSizes["05"],
1834
- color: disabled ? newtone.srgbToHex(tokens.textSecondary.srgb) : newtone.srgbToHex(tokens.textPrimary.srgb),
1146
+ color: disabled ? tokens.textSecondary[gamut] : tokens.textPrimary[gamut],
1835
1147
  opacity: disabled ? 0.5 : 1
1836
1148
  }
1837
1149
  });
1838
1150
  }
1151
+
1152
+ // src/composites/form-controls/TextInput/TextInput.tsx
1839
1153
  function TextInput({
1840
1154
  label,
1841
1155
  disabled = false,
1842
1156
  style,
1843
1157
  ...textInputProps
1844
1158
  }) {
1845
- const tokens = useTokens(1);
1846
- const styles = React14__default.default.useMemo(
1847
- () => getTextInputStyles(tokens, disabled),
1159
+ const tokens = newtoneApi.useTokens(1);
1160
+ const styles = React13__default.default.useMemo(
1161
+ () => getTextInputStyles(tokens, tokens.gamut, disabled),
1848
1162
  [tokens, disabled]
1849
1163
  );
1850
- return /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : [style]] }, label && /* @__PURE__ */ React14__default.default.createElement(reactNative.Text, { style: styles.label }, label), /* @__PURE__ */ React14__default.default.createElement(
1164
+ return /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : [style]] }, label && /* @__PURE__ */ React13__default.default.createElement(reactNative.Text, { style: styles.label }, label), /* @__PURE__ */ React13__default.default.createElement(
1851
1165
  reactNative.TextInput,
1852
1166
  {
1853
1167
  style: styles.input,
1854
1168
  editable: !disabled,
1855
- placeholderTextColor: newtone.srgbToHex(tokens.textSecondary.srgb),
1169
+ placeholderTextColor: tokens.textSecondary[tokens.gamut],
1856
1170
  ...textInputProps
1857
1171
  }
1858
1172
  ));
1859
1173
  }
1860
- function getPopoverStyles(tokens, triggerHeight, offset, maxHeight, width, isOpen) {
1174
+ function getPopoverStyles(tokens, gamut, triggerHeight, offset, maxHeight, width, isOpen) {
1861
1175
  const widthStyle = width === "trigger" ? { left: 0, right: 0 } : typeof width === "number" ? { width, left: 0 } : { left: 0 };
1862
1176
  return reactNative.StyleSheet.create({
1863
1177
  container: {
@@ -1868,9 +1182,9 @@ function getPopoverStyles(tokens, triggerHeight, offset, maxHeight, width, isOpe
1868
1182
  position: "absolute",
1869
1183
  top: triggerHeight + offset,
1870
1184
  ...widthStyle,
1871
- backgroundColor: newtone.srgbToHex(tokens.backgroundElevated.srgb),
1185
+ backgroundColor: tokens.backgroundElevated[gamut],
1872
1186
  borderWidth: 1,
1873
- borderColor: newtone.srgbToHex(tokens.border.srgb),
1187
+ borderColor: tokens.border[gamut],
1874
1188
  borderRadius: tokens.radius.md,
1875
1189
  maxHeight,
1876
1190
  zIndex: 1e3,
@@ -1898,16 +1212,16 @@ function Popover({
1898
1212
  style,
1899
1213
  contentStyle
1900
1214
  }) {
1901
- const tokens = useTokens(1);
1902
- const containerRef = React14.useRef(null);
1903
- const [triggerHeight, setTriggerHeight] = React14.useState(0);
1904
- const onTriggerLayout = React14.useCallback(
1215
+ const tokens = newtoneApi.useTokens(1);
1216
+ const containerRef = React13.useRef(null);
1217
+ const [triggerHeight, setTriggerHeight] = React13.useState(0);
1218
+ const onTriggerLayout = React13.useCallback(
1905
1219
  (e) => {
1906
1220
  setTriggerHeight(e.nativeEvent.layout.height);
1907
1221
  },
1908
1222
  []
1909
1223
  );
1910
- React14.useEffect(() => {
1224
+ React13.useEffect(() => {
1911
1225
  if (!isOpen) return;
1912
1226
  openPopovers.forEach((closeFn) => closeFn());
1913
1227
  openPopovers.clear();
@@ -1916,7 +1230,7 @@ function Popover({
1916
1230
  openPopovers.delete(onClose);
1917
1231
  };
1918
1232
  }, [isOpen, onClose]);
1919
- React14.useEffect(() => {
1233
+ React13.useEffect(() => {
1920
1234
  if (!isOpen) return;
1921
1235
  if (typeof document === "undefined") return;
1922
1236
  const handleMouseDown = (e) => {
@@ -1928,7 +1242,7 @@ function Popover({
1928
1242
  document.addEventListener("mousedown", handleMouseDown, true);
1929
1243
  return () => document.removeEventListener("mousedown", handleMouseDown, true);
1930
1244
  }, [isOpen, onClose]);
1931
- const handleKeyDown = React14.useCallback(
1245
+ const handleKeyDown = React13.useCallback(
1932
1246
  (e) => {
1933
1247
  if (closeOnEscape && e.key === "Escape") {
1934
1248
  e.stopPropagation();
@@ -1937,41 +1251,41 @@ function Popover({
1937
1251
  },
1938
1252
  [closeOnEscape, onClose]
1939
1253
  );
1940
- const styles = React14.useMemo(
1941
- () => getPopoverStyles(tokens, triggerHeight, offset, maxHeight, width, isOpen),
1254
+ const styles = React13.useMemo(
1255
+ () => getPopoverStyles(tokens, tokens.gamut, triggerHeight, offset, maxHeight, width, isOpen),
1942
1256
  [tokens, triggerHeight, offset, maxHeight, width, isOpen]
1943
1257
  );
1944
- const containerStyles = React14.useMemo(
1258
+ const containerStyles = React13.useMemo(
1945
1259
  () => [styles.container, ...Array.isArray(style) ? style : style ? [style] : []],
1946
1260
  [styles.container, style]
1947
1261
  );
1948
- const mergedContentStyles = React14.useMemo(
1262
+ const mergedContentStyles = React13.useMemo(
1949
1263
  () => [styles.content, ...Array.isArray(contentStyle) ? contentStyle : contentStyle ? [contentStyle] : []],
1950
1264
  [styles.content, contentStyle]
1951
1265
  );
1952
1266
  const webProps = { onKeyDown: handleKeyDown };
1953
- return /* @__PURE__ */ React14__default.default.createElement(
1267
+ return /* @__PURE__ */ React13__default.default.createElement(
1954
1268
  reactNative.View,
1955
1269
  {
1956
1270
  ref: containerRef,
1957
1271
  style: containerStyles,
1958
1272
  ...webProps
1959
1273
  },
1960
- /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { onLayout: onTriggerLayout }, trigger),
1961
- isOpen && /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: mergedContentStyles }, children)
1274
+ /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { onLayout: onTriggerLayout }, trigger),
1275
+ isOpen && /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: mergedContentStyles }, children)
1962
1276
  );
1963
1277
  }
1964
1278
  function usePopover(options) {
1965
- const [isOpen, setIsOpen] = React14.useState(options?.initialOpen ?? false);
1966
- const open = React14.useCallback(() => {
1279
+ const [isOpen, setIsOpen] = React13.useState(options?.initialOpen ?? false);
1280
+ const open = React13.useCallback(() => {
1967
1281
  setIsOpen(true);
1968
1282
  options?.onOpenChange?.(true);
1969
1283
  }, [options]);
1970
- const close = React14.useCallback(() => {
1284
+ const close = React13.useCallback(() => {
1971
1285
  setIsOpen(false);
1972
1286
  options?.onOpenChange?.(false);
1973
1287
  }, [options]);
1974
- const toggle = React14.useCallback(() => {
1288
+ const toggle = React13.useCallback(() => {
1975
1289
  setIsOpen((prev) => {
1976
1290
  const next = !prev;
1977
1291
  options?.onOpenChange?.(next);
@@ -1985,7 +1299,7 @@ function usePopover(options) {
1985
1299
  function isOptionGroup(item) {
1986
1300
  return "options" in item;
1987
1301
  }
1988
- function getSelectStyles(tokens, disabled, size, isOpen) {
1302
+ function getSelectStyles(tokens, gamut, disabled, size, isOpen) {
1989
1303
  const isSm = size === "sm";
1990
1304
  const fontSize = isSm ? tokens.typography.fontSizes["04"] : tokens.typography.fontSizes["05"];
1991
1305
  const iconSize = fontSize + 2;
@@ -2001,14 +1315,14 @@ function getSelectStyles(tokens, disabled, size, isOpen) {
2001
1315
  fontFamily: tokens.typography.fonts.main.family,
2002
1316
  fontSize: tokens.typography.fontSizes["04"],
2003
1317
  fontWeight: tokens.typography.fonts.main.weights.medium,
2004
- color: newtone.srgbToHex(tokens.textSecondary.srgb)
1318
+ color: tokens.textSecondary[gamut]
2005
1319
  },
2006
1320
  trigger: {
2007
1321
  flexDirection: "row",
2008
1322
  alignItems: "center",
2009
- backgroundColor: newtone.srgbToHex(tokens.backgroundSunken.srgb),
1323
+ backgroundColor: tokens.backgroundSunken[gamut],
2010
1324
  borderWidth: 1,
2011
- borderColor: newtone.srgbToHex(tokens.border.srgb),
1325
+ borderColor: tokens.border[gamut],
2012
1326
  borderRadius: tokens.radius.md,
2013
1327
  paddingVertical,
2014
1328
  paddingLeft: paddingHorizontal,
@@ -2019,7 +1333,7 @@ function getSelectStyles(tokens, disabled, size, isOpen) {
2019
1333
  flex: 1,
2020
1334
  fontFamily: tokens.typography.fonts.main.family,
2021
1335
  fontSize,
2022
- color: disabled ? newtone.srgbToHex(tokens.textSecondary.srgb) : newtone.srgbToHex(tokens.textPrimary.srgb)
1336
+ color: disabled ? tokens.textSecondary[gamut] : tokens.textPrimary[gamut]
2023
1337
  },
2024
1338
  iconWrapper: {
2025
1339
  position: "absolute",
@@ -2032,7 +1346,7 @@ function getSelectStyles(tokens, disabled, size, isOpen) {
2032
1346
  fontFamily: tokens.typography.fonts.main.family,
2033
1347
  fontSize: tokens.typography.fontSizes["01"],
2034
1348
  fontWeight: tokens.typography.fonts.main.weights.medium,
2035
- color: newtone.srgbToHex(tokens.textSecondary.srgb),
1349
+ color: tokens.textSecondary[gamut],
2036
1350
  textTransform: "uppercase",
2037
1351
  letterSpacing: 0.5,
2038
1352
  paddingVertical: tokens.spacing["04"],
@@ -2058,10 +1372,10 @@ function useSelect({
2058
1372
  onClose,
2059
1373
  onOpen
2060
1374
  }) {
2061
- const [focusedIndex, setFocusedIndex] = React14.useState(-1);
2062
- const typeAheadRef = React14.useRef("");
2063
- const typeAheadTimerRef = React14.useRef();
2064
- React14.useEffect(() => {
1375
+ const [focusedIndex, setFocusedIndex] = React13.useState(-1);
1376
+ const typeAheadRef = React13.useRef("");
1377
+ const typeAheadTimerRef = React13.useRef();
1378
+ React13.useEffect(() => {
2065
1379
  if (isOpen) {
2066
1380
  const selectedIdx = flatOptions.findIndex((o) => o.value === value);
2067
1381
  if (selectedIdx >= 0 && !flatOptions[selectedIdx].disabled) {
@@ -2074,7 +1388,7 @@ function useSelect({
2074
1388
  setFocusedIndex(-1);
2075
1389
  }
2076
1390
  }, [isOpen, flatOptions, value]);
2077
- const handleKeyDown = React14.useCallback(
1391
+ const handleKeyDown = React13.useCallback(
2078
1392
  (e) => {
2079
1393
  const key = e.key;
2080
1394
  if (!isOpen) {
@@ -2150,12 +1464,12 @@ function SelectOptionRow({
2150
1464
  renderOption,
2151
1465
  size
2152
1466
  }) {
2153
- const tokens = useTokens(1);
1467
+ const tokens = newtoneApi.useTokens(1);
2154
1468
  const paddingVertical = size === "sm" ? tokens.spacing["04"] : tokens.spacing["08"];
2155
1469
  const paddingHorizontal = size === "sm" ? tokens.spacing["08"] : tokens.spacing["12"];
2156
1470
  const fontSize = size === "sm" ? tokens.typography.fontSizes["04"] : tokens.typography.fontSizes["05"];
2157
1471
  if (renderOption) {
2158
- return /* @__PURE__ */ React14__default.default.createElement(
1472
+ return /* @__PURE__ */ React13__default.default.createElement(
2159
1473
  reactNative.Pressable,
2160
1474
  {
2161
1475
  onPress: option.disabled ? void 0 : onSelect,
@@ -2166,7 +1480,7 @@ function SelectOptionRow({
2166
1480
  renderOption(option, { isSelected, isFocused })
2167
1481
  );
2168
1482
  }
2169
- return /* @__PURE__ */ React14__default.default.createElement(
1483
+ return /* @__PURE__ */ React13__default.default.createElement(
2170
1484
  reactNative.Pressable,
2171
1485
  {
2172
1486
  onPress: option.disabled ? void 0 : onSelect,
@@ -2182,10 +1496,10 @@ function SelectOptionRow({
2182
1496
  paddingHorizontal
2183
1497
  },
2184
1498
  isSelected && {
2185
- backgroundColor: newtone.srgbToHex(tokens.backgroundSunken.srgb)
1499
+ backgroundColor: tokens.backgroundSunken[tokens.gamut]
2186
1500
  },
2187
1501
  isFocused && !isSelected && {
2188
- backgroundColor: `${newtone.srgbToHex(tokens.border.srgb)}20`
1502
+ backgroundColor: `${tokens.border[tokens.gamut]}20`
2189
1503
  },
2190
1504
  option.disabled && {
2191
1505
  opacity: 0.5
@@ -2195,7 +1509,7 @@ function SelectOptionRow({
2195
1509
  }
2196
1510
  ]
2197
1511
  },
2198
- /* @__PURE__ */ React14__default.default.createElement(
1512
+ /* @__PURE__ */ React13__default.default.createElement(
2199
1513
  reactNative.Text,
2200
1514
  {
2201
1515
  style: [
@@ -2203,30 +1517,32 @@ function SelectOptionRow({
2203
1517
  flex: 1,
2204
1518
  fontFamily: tokens.typography.fonts.main.family,
2205
1519
  fontSize,
2206
- color: newtone.srgbToHex(tokens.textPrimary.srgb)
1520
+ color: tokens.textPrimary[tokens.gamut]
2207
1521
  },
2208
1522
  isSelected && {
2209
1523
  fontWeight: tokens.typography.fonts.main.weights.medium,
2210
- color: newtone.srgbToHex(tokens.accent.fill.srgb)
1524
+ color: tokens.accent.fill[tokens.gamut]
2211
1525
  },
2212
1526
  option.disabled && {
2213
- color: newtone.srgbToHex(tokens.textSecondary.srgb)
1527
+ color: tokens.textSecondary[tokens.gamut]
2214
1528
  }
2215
1529
  ],
2216
1530
  numberOfLines: 1
2217
1531
  },
2218
1532
  option.label
2219
1533
  ),
2220
- isSelected && /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: { marginLeft: tokens.spacing["08"] } }, /* @__PURE__ */ React14__default.default.createElement(
1534
+ isSelected && /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: { marginLeft: tokens.spacing["08"] } }, /* @__PURE__ */ React13__default.default.createElement(
2221
1535
  Icon,
2222
1536
  {
2223
1537
  name: "check",
2224
1538
  size: fontSize,
2225
- color: newtone.srgbToHex(tokens.accent.fill.srgb)
1539
+ color: tokens.accent.fill[tokens.gamut]
2226
1540
  }
2227
1541
  ))
2228
1542
  );
2229
1543
  }
1544
+
1545
+ // src/composites/form-controls/Select/Select.tsx
2230
1546
  function flattenOptions(items) {
2231
1547
  const result = [];
2232
1548
  for (const item of items) {
@@ -2250,9 +1566,9 @@ function Select({
2250
1566
  size = "md",
2251
1567
  style
2252
1568
  }) {
2253
- const tokens = useTokens(1);
1569
+ const tokens = newtoneApi.useTokens(1);
2254
1570
  const { isOpen, open, close, toggle } = usePopover();
2255
- const flatOptions = React14.useMemo(() => flattenOptions(options), [options]);
1571
+ const flatOptions = React13.useMemo(() => flattenOptions(options), [options]);
2256
1572
  const { focusedIndex, handleKeyDown } = useSelect({
2257
1573
  flatOptions,
2258
1574
  value,
@@ -2264,15 +1580,15 @@ function Select({
2264
1580
  onClose: close,
2265
1581
  onOpen: open
2266
1582
  });
2267
- const styles = React14.useMemo(
2268
- () => getSelectStyles(tokens, disabled, size, isOpen),
1583
+ const styles = React13.useMemo(
1584
+ () => getSelectStyles(tokens, tokens.gamut, disabled, size, isOpen),
2269
1585
  [tokens, disabled, size, isOpen]
2270
1586
  );
2271
1587
  const selectedOption = flatOptions.find((o) => o.value === value);
2272
1588
  const displayLabel = selectedOption?.label ?? placeholder ?? value;
2273
- const iconColor = disabled ? newtone.srgbToHex(tokens.textSecondary.srgb) : newtone.srgbToHex(tokens.textPrimary.srgb);
1589
+ const iconColor = disabled ? tokens.textSecondary[tokens.gamut] : tokens.textPrimary[tokens.gamut];
2274
1590
  const triggerWebProps = { onKeyDown: handleKeyDown };
2275
- const trigger = /* @__PURE__ */ React14__default.default.createElement(
1591
+ const trigger = /* @__PURE__ */ React13__default.default.createElement(
2276
1592
  reactNative.Pressable,
2277
1593
  {
2278
1594
  onPress: disabled ? void 0 : toggle,
@@ -2282,8 +1598,8 @@ function Select({
2282
1598
  ...triggerWebProps,
2283
1599
  style: styles.trigger
2284
1600
  },
2285
- renderValue ? renderValue(selectedOption) : /* @__PURE__ */ React14__default.default.createElement(reactNative.Text, { style: styles.triggerText, numberOfLines: 1 }, displayLabel),
2286
- /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.iconWrapper, pointerEvents: "none" }, /* @__PURE__ */ React14__default.default.createElement(
1601
+ renderValue ? renderValue(selectedOption) : /* @__PURE__ */ React13__default.default.createElement(reactNative.Text, { style: styles.triggerText, numberOfLines: 1 }, displayLabel),
1602
+ /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.iconWrapper, pointerEvents: "none" }, /* @__PURE__ */ React13__default.default.createElement(
2287
1603
  Icon,
2288
1604
  {
2289
1605
  name: isOpen ? "expand_less" : "expand_more",
@@ -2292,14 +1608,14 @@ function Select({
2292
1608
  }
2293
1609
  ))
2294
1610
  );
2295
- return /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : style ? [style] : []] }, label && /* @__PURE__ */ React14__default.default.createElement(reactNative.Text, { style: styles.label }, label), /* @__PURE__ */ React14__default.default.createElement(
1611
+ return /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : style ? [style] : []] }, label && /* @__PURE__ */ React13__default.default.createElement(reactNative.Text, { style: styles.label }, label), /* @__PURE__ */ React13__default.default.createElement(
2296
1612
  Popover,
2297
1613
  {
2298
1614
  isOpen: isOpen && !disabled,
2299
1615
  onClose: close,
2300
1616
  trigger
2301
1617
  },
2302
- /* @__PURE__ */ React14__default.default.createElement(
1618
+ /* @__PURE__ */ React13__default.default.createElement(
2303
1619
  reactNative.ScrollView,
2304
1620
  {
2305
1621
  bounces: false,
@@ -2308,7 +1624,7 @@ function Select({
2308
1624
  },
2309
1625
  options.map((item) => {
2310
1626
  if (isOptionGroup(item)) {
2311
- return /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { key: item.label }, /* @__PURE__ */ React14__default.default.createElement(reactNative.Text, { style: styles.groupLabel }, item.label), item.options.map((opt) => /* @__PURE__ */ React14__default.default.createElement(
1627
+ return /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { key: item.label }, /* @__PURE__ */ React13__default.default.createElement(reactNative.Text, { style: styles.groupLabel }, item.label), item.options.map((opt) => /* @__PURE__ */ React13__default.default.createElement(
2312
1628
  SelectOptionRow,
2313
1629
  {
2314
1630
  key: opt.value,
@@ -2324,7 +1640,7 @@ function Select({
2324
1640
  }
2325
1641
  )));
2326
1642
  }
2327
- return /* @__PURE__ */ React14__default.default.createElement(
1643
+ return /* @__PURE__ */ React13__default.default.createElement(
2328
1644
  SelectOptionRow,
2329
1645
  {
2330
1646
  key: item.value,
@@ -2347,7 +1663,7 @@ var TRACK_WIDTH = 40;
2347
1663
  var TRACK_HEIGHT = 22;
2348
1664
  var THUMB_SIZE = 18;
2349
1665
  var THUMB_OFFSET = 2;
2350
- function getToggleStyles(tokens, value, disabled) {
1666
+ function getToggleStyles(tokens, gamut, value, disabled) {
2351
1667
  return reactNative.StyleSheet.create({
2352
1668
  container: {
2353
1669
  flexDirection: "row",
@@ -2359,13 +1675,13 @@ function getToggleStyles(tokens, value, disabled) {
2359
1675
  fontFamily: tokens.typography.fonts.main.family,
2360
1676
  fontSize: tokens.typography.fontSizes["04"],
2361
1677
  fontWeight: tokens.typography.fonts.main.weights.medium,
2362
- color: newtone.srgbToHex(tokens.textSecondary.srgb)
1678
+ color: tokens.textSecondary[gamut]
2363
1679
  },
2364
1680
  track: {
2365
1681
  width: TRACK_WIDTH,
2366
1682
  height: TRACK_HEIGHT,
2367
1683
  borderRadius: TRACK_HEIGHT / 2,
2368
- backgroundColor: value ? newtone.srgbToHex(tokens.accent.fill.srgb) : newtone.srgbToHex(tokens.border.srgb),
1684
+ backgroundColor: value ? tokens.accent.fill[gamut] : tokens.border[gamut],
2369
1685
  justifyContent: "center",
2370
1686
  paddingHorizontal: THUMB_OFFSET
2371
1687
  },
@@ -2373,7 +1689,7 @@ function getToggleStyles(tokens, value, disabled) {
2373
1689
  width: THUMB_SIZE,
2374
1690
  height: THUMB_SIZE,
2375
1691
  borderRadius: THUMB_SIZE / 2,
2376
- backgroundColor: newtone.srgbToHex(tokens.background.srgb),
1692
+ backgroundColor: tokens.background[gamut],
2377
1693
  alignSelf: value ? "flex-end" : "flex-start"
2378
1694
  }
2379
1695
  });
@@ -2387,17 +1703,17 @@ function Toggle({
2387
1703
  disabled = false,
2388
1704
  style
2389
1705
  }) {
2390
- const tokens = useTokens(1);
2391
- const styles = React14__default.default.useMemo(
2392
- () => getToggleStyles(tokens, value, disabled),
1706
+ const tokens = newtoneApi.useTokens(1);
1707
+ const styles = React13__default.default.useMemo(
1708
+ () => getToggleStyles(tokens, tokens.gamut, value, disabled),
2393
1709
  [tokens, value, disabled]
2394
1710
  );
2395
- const handlePress = React14__default.default.useCallback(() => {
1711
+ const handlePress = React13__default.default.useCallback(() => {
2396
1712
  if (!disabled) {
2397
1713
  onValueChange(!value);
2398
1714
  }
2399
1715
  }, [disabled, value, onValueChange]);
2400
- return /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : [style]] }, label && /* @__PURE__ */ React14__default.default.createElement(reactNative.Text, { style: styles.label }, label), /* @__PURE__ */ React14__default.default.createElement(
1716
+ return /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : [style]] }, label && /* @__PURE__ */ React13__default.default.createElement(reactNative.Text, { style: styles.label }, label), /* @__PURE__ */ React13__default.default.createElement(
2401
1717
  reactNative.Pressable,
2402
1718
  {
2403
1719
  onPress: handlePress,
@@ -2405,12 +1721,12 @@ function Toggle({
2405
1721
  accessibilityRole: "switch",
2406
1722
  accessibilityState: { checked: value, disabled }
2407
1723
  },
2408
- /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.track }, /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.thumb }))
1724
+ /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.track }, /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.thumb }))
2409
1725
  ));
2410
1726
  }
2411
1727
  var TRACK_HEIGHT2 = 6;
2412
1728
  var THUMB_SIZE2 = 16;
2413
- function getSliderStyles(tokens, disabled) {
1729
+ function getSliderStyles(tokens, gamut, disabled) {
2414
1730
  return reactNative.StyleSheet.create({
2415
1731
  container: {
2416
1732
  gap: tokens.spacing["04"],
@@ -2425,23 +1741,23 @@ function getSliderStyles(tokens, disabled) {
2425
1741
  fontFamily: tokens.typography.fonts.main.family,
2426
1742
  fontSize: tokens.typography.fontSizes["04"],
2427
1743
  fontWeight: tokens.typography.fonts.main.weights.medium,
2428
- color: newtone.srgbToHex(tokens.textSecondary.srgb)
1744
+ color: tokens.textSecondary[gamut]
2429
1745
  },
2430
1746
  value: {
2431
1747
  fontFamily: tokens.typography.fonts.main.family,
2432
1748
  fontSize: tokens.typography.fontSizes["04"],
2433
1749
  fontWeight: tokens.typography.fonts.main.weights.medium,
2434
- color: newtone.srgbToHex(tokens.textPrimary.srgb)
1750
+ color: tokens.textPrimary[gamut]
2435
1751
  },
2436
1752
  valueInput: {
2437
1753
  width: 48,
2438
1754
  paddingVertical: 0,
2439
1755
  paddingHorizontal: 4,
2440
1756
  borderWidth: 1,
2441
- borderColor: newtone.srgbToHex(tokens.border.srgb),
1757
+ borderColor: tokens.border[gamut],
2442
1758
  borderRadius: 4,
2443
1759
  backgroundColor: "transparent",
2444
- color: newtone.srgbToHex(tokens.textPrimary.srgb),
1760
+ color: tokens.textPrimary[gamut],
2445
1761
  fontFamily: tokens.typography.fonts.main.family,
2446
1762
  fontSize: tokens.typography.fontSizes["04"],
2447
1763
  fontWeight: tokens.typography.fonts.main.weights.medium,
@@ -2458,21 +1774,21 @@ function getSliderStyles(tokens, disabled) {
2458
1774
  right: 0,
2459
1775
  height: TRACK_HEIGHT2,
2460
1776
  borderRadius: TRACK_HEIGHT2 / 2,
2461
- backgroundColor: newtone.srgbToHex(tokens.border.srgb)
1777
+ backgroundColor: tokens.border[gamut]
2462
1778
  },
2463
1779
  trackFill: {
2464
1780
  position: "absolute",
2465
1781
  left: 0,
2466
1782
  height: TRACK_HEIGHT2,
2467
1783
  borderRadius: TRACK_HEIGHT2 / 2,
2468
- backgroundColor: newtone.srgbToHex(tokens.accent.fill.srgb)
1784
+ backgroundColor: tokens.accent.fill[gamut]
2469
1785
  },
2470
1786
  thumb: {
2471
1787
  position: "absolute",
2472
1788
  width: THUMB_SIZE2,
2473
1789
  height: THUMB_SIZE2,
2474
1790
  borderRadius: THUMB_SIZE2 / 2,
2475
- backgroundColor: newtone.srgbToHex(tokens.accent.fill.srgb)
1791
+ backgroundColor: tokens.accent.fill[gamut]
2476
1792
  }
2477
1793
  });
2478
1794
  }
@@ -2490,43 +1806,43 @@ function Slider({
2490
1806
  disabled = false,
2491
1807
  style
2492
1808
  }) {
2493
- const tokens = useTokens(1);
2494
- const styles = React14__default.default.useMemo(
2495
- () => getSliderStyles(tokens, disabled),
1809
+ const tokens = newtoneApi.useTokens(1);
1810
+ const styles = React13__default.default.useMemo(
1811
+ () => getSliderStyles(tokens, tokens.gamut, disabled),
2496
1812
  [tokens, disabled]
2497
1813
  );
2498
- const trackRef = React14__default.default.useRef(null);
2499
- const trackWidth = React14__default.default.useRef(0);
2500
- const trackPageX = React14__default.default.useRef(0);
2501
- const [layoutWidth, setLayoutWidth] = React14__default.default.useState(0);
2502
- const onValueChangeRef = React14__default.default.useRef(onValueChange);
2503
- const minRef = React14__default.default.useRef(min);
2504
- const maxRef = React14__default.default.useRef(max);
2505
- const stepRef = React14__default.default.useRef(step);
2506
- const disabledRef = React14__default.default.useRef(disabled);
2507
- React14__default.default.useEffect(() => {
1814
+ const trackRef = React13__default.default.useRef(null);
1815
+ const trackWidth = React13__default.default.useRef(0);
1816
+ const trackPageX = React13__default.default.useRef(0);
1817
+ const [layoutWidth, setLayoutWidth] = React13__default.default.useState(0);
1818
+ const onValueChangeRef = React13__default.default.useRef(onValueChange);
1819
+ const minRef = React13__default.default.useRef(min);
1820
+ const maxRef = React13__default.default.useRef(max);
1821
+ const stepRef = React13__default.default.useRef(step);
1822
+ const disabledRef = React13__default.default.useRef(disabled);
1823
+ React13__default.default.useEffect(() => {
2508
1824
  onValueChangeRef.current = onValueChange;
2509
1825
  }, [onValueChange]);
2510
- React14__default.default.useEffect(() => {
1826
+ React13__default.default.useEffect(() => {
2511
1827
  minRef.current = min;
2512
1828
  }, [min]);
2513
- React14__default.default.useEffect(() => {
1829
+ React13__default.default.useEffect(() => {
2514
1830
  maxRef.current = max;
2515
1831
  }, [max]);
2516
- React14__default.default.useEffect(() => {
1832
+ React13__default.default.useEffect(() => {
2517
1833
  stepRef.current = step;
2518
1834
  }, [step]);
2519
- React14__default.default.useEffect(() => {
1835
+ React13__default.default.useEffect(() => {
2520
1836
  disabledRef.current = disabled;
2521
1837
  }, [disabled]);
2522
- const computeValue = React14__default.default.useCallback((pageX) => {
1838
+ const computeValue = React13__default.default.useCallback((pageX) => {
2523
1839
  const localX = pageX - trackPageX.current;
2524
1840
  const ratio2 = Math.min(1, Math.max(0, localX / trackWidth.current));
2525
1841
  const raw = minRef.current + ratio2 * (maxRef.current - minRef.current);
2526
1842
  const stepped = Math.round(raw / stepRef.current) * stepRef.current;
2527
1843
  return Math.min(maxRef.current, Math.max(minRef.current, stepped));
2528
1844
  }, []);
2529
- const panResponder = React14__default.default.useRef(
1845
+ const panResponder = React13__default.default.useRef(
2530
1846
  reactNative.PanResponder.create({
2531
1847
  onStartShouldSetPanResponder: () => !disabledRef.current,
2532
1848
  onMoveShouldSetPanResponder: () => !disabledRef.current,
@@ -2554,7 +1870,7 @@ function Slider({
2554
1870
  fillLeft = 0;
2555
1871
  fillWidth = thumbLeft + THUMB_SIZE2 / 2;
2556
1872
  }
2557
- const handleValueTextSubmit = React14__default.default.useCallback(
1873
+ const handleValueTextSubmit = React13__default.default.useCallback(
2558
1874
  (text) => {
2559
1875
  const raw = Number(text);
2560
1876
  if (!Number.isNaN(raw)) {
@@ -2563,12 +1879,12 @@ function Slider({
2563
1879
  },
2564
1880
  [onValueChange, min, max]
2565
1881
  );
2566
- const [editText, setEditText] = React14__default.default.useState(String(value));
2567
- React14__default.default.useEffect(() => {
1882
+ const [editText, setEditText] = React13__default.default.useState(String(value));
1883
+ React13__default.default.useEffect(() => {
2568
1884
  setEditText(String(value));
2569
1885
  }, [value]);
2570
1886
  const showLabel = label || showValue || editableValue;
2571
- return /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : [style]] }, showLabel && /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.labelRow }, label && /* @__PURE__ */ React14__default.default.createElement(reactNative.Text, { style: styles.label }, label), editableValue ? /* @__PURE__ */ React14__default.default.createElement(
1887
+ return /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : [style]] }, showLabel && /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.labelRow }, label && /* @__PURE__ */ React13__default.default.createElement(reactNative.Text, { style: styles.label }, label), editableValue ? /* @__PURE__ */ React13__default.default.createElement(
2572
1888
  reactNative.TextInput,
2573
1889
  {
2574
1890
  style: styles.valueInput,
@@ -2580,7 +1896,7 @@ function Slider({
2580
1896
  selectTextOnFocus: true,
2581
1897
  editable: !disabled
2582
1898
  }
2583
- ) : showValue && /* @__PURE__ */ React14__default.default.createElement(reactNative.Text, { style: styles.value }, value)), /* @__PURE__ */ React14__default.default.createElement(
1899
+ ) : showValue && /* @__PURE__ */ React13__default.default.createElement(reactNative.Text, { style: styles.value }, value)), /* @__PURE__ */ React13__default.default.createElement(
2584
1900
  reactNative.View,
2585
1901
  {
2586
1902
  ref: trackRef,
@@ -2595,45 +1911,19 @@ function Slider({
2595
1911
  },
2596
1912
  ...panResponder.panHandlers
2597
1913
  },
2598
- /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.trackRail }),
2599
- /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: [styles.trackFill, { left: fillLeft, width: fillWidth }] }),
2600
- /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: [styles.thumb, { left: thumbLeft }] })
1914
+ /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.trackRail }),
1915
+ /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: [styles.trackFill, { left: fillLeft, width: fillWidth }] }),
1916
+ /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: [styles.thumb, { left: thumbLeft }] })
2601
1917
  ));
2602
1918
  }
2603
1919
  var TRACK_HEIGHT3 = 22;
2604
1920
  var THUMB_SIZE3 = 18;
2605
1921
  var SEGMENT_COUNT = 48;
2606
- function hueToHex(hue) {
2607
- const h = (hue % 360 + 360) % 360;
2608
- const x = 1 - Math.abs(h / 60 % 2 - 1);
2609
- let r, g, b;
2610
- if (h < 60) {
2611
- r = 1;
2612
- g = x;
2613
- b = 0;
2614
- } else if (h < 120) {
2615
- r = x;
2616
- g = 1;
2617
- b = 0;
2618
- } else if (h < 180) {
2619
- r = 0;
2620
- g = 1;
2621
- b = x;
2622
- } else if (h < 240) {
2623
- r = 0;
2624
- g = x;
2625
- b = 1;
2626
- } else if (h < 300) {
2627
- r = x;
2628
- g = 0;
2629
- b = 1;
2630
- } else {
2631
- r = 1;
2632
- g = 0;
2633
- b = x;
2634
- }
2635
- const toHex = (v) => Math.round(v * 255).toString(16).padStart(2, "0");
2636
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
1922
+ var OKLCH_L = 0.7;
1923
+ var OKLCH_C = 0.4;
1924
+ function hueToHex(oklchHue) {
1925
+ const { color } = newtone.gamutMapToSrgb({ L: OKLCH_L, C: OKLCH_C, h: oklchHue });
1926
+ return newtone.srgbToHex(color);
2637
1927
  }
2638
1928
  function buildHueSegments(min, max) {
2639
1929
  return Array.from({ length: SEGMENT_COUNT }, (_, i) => {
@@ -2641,7 +1931,7 @@ function buildHueSegments(min, max) {
2641
1931
  return hueToHex(hue);
2642
1932
  });
2643
1933
  }
2644
- function getHueSliderStyles(tokens, disabled) {
1934
+ function getHueSliderStyles(tokens, gamut, disabled) {
2645
1935
  return reactNative.StyleSheet.create({
2646
1936
  container: {
2647
1937
  gap: tokens.spacing["04"],
@@ -2656,23 +1946,23 @@ function getHueSliderStyles(tokens, disabled) {
2656
1946
  fontFamily: tokens.typography.fonts.main.family,
2657
1947
  fontSize: tokens.typography.fontSizes["04"],
2658
1948
  fontWeight: tokens.typography.fonts.main.weights.medium,
2659
- color: newtone.srgbToHex(tokens.textSecondary.srgb)
1949
+ color: tokens.textSecondary[gamut]
2660
1950
  },
2661
1951
  value: {
2662
1952
  fontFamily: tokens.typography.fonts.main.family,
2663
1953
  fontSize: tokens.typography.fontSizes["04"],
2664
1954
  fontWeight: tokens.typography.fonts.main.weights.medium,
2665
- color: newtone.srgbToHex(tokens.textPrimary.srgb)
1955
+ color: tokens.textPrimary[gamut]
2666
1956
  },
2667
1957
  valueInput: {
2668
1958
  width: 48,
2669
1959
  paddingVertical: 0,
2670
1960
  paddingHorizontal: 4,
2671
1961
  borderWidth: 1,
2672
- borderColor: newtone.srgbToHex(tokens.border.srgb),
1962
+ borderColor: tokens.border[gamut],
2673
1963
  borderRadius: 4,
2674
1964
  backgroundColor: "transparent",
2675
- color: newtone.srgbToHex(tokens.textPrimary.srgb),
1965
+ color: tokens.textPrimary[gamut],
2676
1966
  fontFamily: tokens.typography.fonts.main.family,
2677
1967
  fontSize: tokens.typography.fontSizes["04"],
2678
1968
  fontWeight: tokens.typography.fonts.main.weights.medium,
@@ -2702,7 +1992,7 @@ function getHueSliderStyles(tokens, disabled) {
2702
1992
  borderRadius: THUMB_SIZE3 / 2,
2703
1993
  backgroundColor: "#ffffff",
2704
1994
  borderWidth: 2,
2705
- borderColor: newtone.srgbToHex(tokens.border.srgb)
1995
+ borderColor: tokens.border[gamut]
2706
1996
  }
2707
1997
  });
2708
1998
  }
@@ -2712,50 +2002,50 @@ function HueSlider({
2712
2002
  value,
2713
2003
  onValueChange,
2714
2004
  min = 0,
2715
- max = 359,
2005
+ max = 360,
2716
2006
  label,
2717
2007
  showValue = false,
2718
2008
  editableValue = false,
2719
2009
  disabled = false,
2720
2010
  style
2721
2011
  }) {
2722
- const tokens = useTokens(1);
2723
- const styles = React14__default.default.useMemo(
2724
- () => getHueSliderStyles(tokens, disabled),
2012
+ const tokens = newtoneApi.useTokens(1);
2013
+ const styles = React13__default.default.useMemo(
2014
+ () => getHueSliderStyles(tokens, tokens.gamut, disabled),
2725
2015
  [tokens, disabled]
2726
2016
  );
2727
- const segments = React14__default.default.useMemo(
2017
+ const segments = React13__default.default.useMemo(
2728
2018
  () => buildHueSegments(min, max),
2729
2019
  [min, max]
2730
2020
  );
2731
- const trackRef = React14__default.default.useRef(null);
2732
- const trackWidth = React14__default.default.useRef(0);
2733
- const trackPageX = React14__default.default.useRef(0);
2734
- const [layoutWidth, setLayoutWidth] = React14__default.default.useState(0);
2735
- const onValueChangeRef = React14__default.default.useRef(onValueChange);
2736
- const minRef = React14__default.default.useRef(min);
2737
- const maxRef = React14__default.default.useRef(max);
2738
- const disabledRef = React14__default.default.useRef(disabled);
2739
- React14__default.default.useEffect(() => {
2021
+ const trackRef = React13__default.default.useRef(null);
2022
+ const trackWidth = React13__default.default.useRef(0);
2023
+ const trackPageX = React13__default.default.useRef(0);
2024
+ const [layoutWidth, setLayoutWidth] = React13__default.default.useState(0);
2025
+ const onValueChangeRef = React13__default.default.useRef(onValueChange);
2026
+ const minRef = React13__default.default.useRef(min);
2027
+ const maxRef = React13__default.default.useRef(max);
2028
+ const disabledRef = React13__default.default.useRef(disabled);
2029
+ React13__default.default.useEffect(() => {
2740
2030
  onValueChangeRef.current = onValueChange;
2741
2031
  }, [onValueChange]);
2742
- React14__default.default.useEffect(() => {
2032
+ React13__default.default.useEffect(() => {
2743
2033
  minRef.current = min;
2744
2034
  }, [min]);
2745
- React14__default.default.useEffect(() => {
2035
+ React13__default.default.useEffect(() => {
2746
2036
  maxRef.current = max;
2747
2037
  }, [max]);
2748
- React14__default.default.useEffect(() => {
2038
+ React13__default.default.useEffect(() => {
2749
2039
  disabledRef.current = disabled;
2750
2040
  }, [disabled]);
2751
- const computeHue = React14__default.default.useCallback((pageX) => {
2041
+ const computeHue = React13__default.default.useCallback((pageX) => {
2752
2042
  const localX = pageX - trackPageX.current;
2753
2043
  const ratio2 = Math.min(1, Math.max(0, localX / trackWidth.current));
2754
2044
  const raw = minRef.current + ratio2 * (maxRef.current - minRef.current);
2755
2045
  const stepped = Math.round(raw);
2756
2046
  return (stepped % 360 + 360) % 360;
2757
2047
  }, []);
2758
- const panResponder = React14__default.default.useRef(
2048
+ const panResponder = React13__default.default.useRef(
2759
2049
  reactNative.PanResponder.create({
2760
2050
  onStartShouldSetPanResponder: () => !disabledRef.current,
2761
2051
  onMoveShouldSetPanResponder: () => !disabledRef.current,
@@ -2767,11 +2057,11 @@ function HueSlider({
2767
2057
  }
2768
2058
  })
2769
2059
  ).current;
2770
- const sliderValue = max > 359 && value < min ? value + 360 : value;
2060
+ const sliderValue = max > 360 && value < min ? value + 360 : value;
2771
2061
  const ratio = max > min ? (sliderValue - min) / (max - min) : 0;
2772
2062
  const usableWidth = Math.max(0, layoutWidth - THUMB_SIZE3);
2773
2063
  const thumbLeft = ratio * usableWidth;
2774
- const handleValueTextSubmit = React14__default.default.useCallback(
2064
+ const handleValueTextSubmit = React13__default.default.useCallback(
2775
2065
  (text) => {
2776
2066
  const raw = Number(text);
2777
2067
  if (!Number.isNaN(raw)) {
@@ -2780,12 +2070,12 @@ function HueSlider({
2780
2070
  },
2781
2071
  [onValueChange]
2782
2072
  );
2783
- const [editText, setEditText] = React14__default.default.useState(String(value));
2784
- React14__default.default.useEffect(() => {
2073
+ const [editText, setEditText] = React13__default.default.useState(String(value));
2074
+ React13__default.default.useEffect(() => {
2785
2075
  setEditText(String(value));
2786
2076
  }, [value]);
2787
2077
  const showLabel = label || showValue || editableValue;
2788
- return /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : [style]] }, showLabel && /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.labelRow }, label && /* @__PURE__ */ React14__default.default.createElement(reactNative.Text, { style: styles.label }, label), editableValue ? /* @__PURE__ */ React14__default.default.createElement(
2078
+ return /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : [style]] }, showLabel && /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.labelRow }, label && /* @__PURE__ */ React13__default.default.createElement(reactNative.Text, { style: styles.label }, label), editableValue ? /* @__PURE__ */ React13__default.default.createElement(
2789
2079
  reactNative.TextInput,
2790
2080
  {
2791
2081
  style: styles.valueInput,
@@ -2797,7 +2087,7 @@ function HueSlider({
2797
2087
  selectTextOnFocus: true,
2798
2088
  editable: !disabled
2799
2089
  }
2800
- ) : showValue && /* @__PURE__ */ React14__default.default.createElement(reactNative.Text, { style: styles.value }, value, "\xB0")), /* @__PURE__ */ React14__default.default.createElement(
2090
+ ) : showValue && /* @__PURE__ */ React13__default.default.createElement(reactNative.Text, { style: styles.value }, value, "\xB0")), /* @__PURE__ */ React13__default.default.createElement(
2801
2091
  reactNative.View,
2802
2092
  {
2803
2093
  ref: trackRef,
@@ -2812,13 +2102,69 @@ function HueSlider({
2812
2102
  },
2813
2103
  ...panResponder.panHandlers
2814
2104
  },
2815
- /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.gradientTrack }, segments.map((color, i) => /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { key: i, style: [styles.segment, { backgroundColor: color }] }))),
2816
- /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: [styles.thumb, { left: thumbLeft }] })
2105
+ /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.gradientTrack }, segments.map((color, i) => /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { key: i, style: [styles.segment, { backgroundColor: color }] }))),
2106
+ /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: [styles.thumb, { left: thumbLeft }] })
2817
2107
  ));
2818
2108
  }
2109
+
2110
+ // node_modules/@newtonedev/colors/dist/index.js
2111
+ var SRGB_GAMMA_THRESHOLD_LINEAR = 31308e-7;
2112
+ var SRGB_GAMMA_SLOPE = 12.92;
2113
+ var SRGB_GAMMA_EXPONENT = 2.4;
2114
+ var SRGB_GAMMA_OFFSET = 0.055;
2115
+ var SRGB_GAMMA_SCALE = 1.055;
2116
+ var OKLAB_TO_LMS_PRIME = [
2117
+ [1, 0.3963377774, 0.2158037573],
2118
+ [1, -0.1055613458, -0.0638541728],
2119
+ [1, -0.0894841775, -1.291485548]
2120
+ ];
2121
+ var LMS_TO_LINEAR_P3 = [
2122
+ [3.127769439, -2.2570600176, 0.1291828502],
2123
+ [-1.0910091977, 2.4133065499, -0.3222615148],
2124
+ [-0.0260108068, -0.5080402362, 1.5340494942]
2125
+ ];
2126
+ var DEG_TO_RAD = Math.PI / 180;
2127
+ function oklchToOklab(lch) {
2128
+ const hRad = lch.h * DEG_TO_RAD;
2129
+ return {
2130
+ L: lch.L,
2131
+ a: lch.C * Math.cos(hRad),
2132
+ b: lch.C * Math.sin(hRad)
2133
+ };
2134
+ }
2135
+ function oklabToLinearP3(color) {
2136
+ const lp = OKLAB_TO_LMS_PRIME[0][0] * color.L + OKLAB_TO_LMS_PRIME[0][1] * color.a + OKLAB_TO_LMS_PRIME[0][2] * color.b;
2137
+ const mp = OKLAB_TO_LMS_PRIME[1][0] * color.L + OKLAB_TO_LMS_PRIME[1][1] * color.a + OKLAB_TO_LMS_PRIME[1][2] * color.b;
2138
+ const sp = OKLAB_TO_LMS_PRIME[2][0] * color.L + OKLAB_TO_LMS_PRIME[2][1] * color.a + OKLAB_TO_LMS_PRIME[2][2] * color.b;
2139
+ const l = lp * lp * lp;
2140
+ const m = mp * mp * mp;
2141
+ const s = sp * sp * sp;
2142
+ return {
2143
+ r: LMS_TO_LINEAR_P3[0][0] * l + LMS_TO_LINEAR_P3[0][1] * m + LMS_TO_LINEAR_P3[0][2] * s,
2144
+ g: LMS_TO_LINEAR_P3[1][0] * l + LMS_TO_LINEAR_P3[1][1] * m + LMS_TO_LINEAR_P3[1][2] * s,
2145
+ b: LMS_TO_LINEAR_P3[2][0] * l + LMS_TO_LINEAR_P3[2][1] * m + LMS_TO_LINEAR_P3[2][2] * s
2146
+ };
2147
+ }
2148
+ function linearChannelToSrgb(value) {
2149
+ return value <= SRGB_GAMMA_THRESHOLD_LINEAR ? value * SRGB_GAMMA_SLOPE : SRGB_GAMMA_SCALE * value ** (1 / SRGB_GAMMA_EXPONENT) - SRGB_GAMMA_OFFSET;
2150
+ }
2151
+ function linearSrgbToSrgb(color) {
2152
+ return {
2153
+ r: linearChannelToSrgb(color.r),
2154
+ g: linearChannelToSrgb(color.g),
2155
+ b: linearChannelToSrgb(color.b)
2156
+ };
2157
+ }
2158
+ function oklchToP3(color) {
2159
+ return linearSrgbToSrgb(oklabToLinearP3(oklchToOklab(color)));
2160
+ }
2161
+ function oklchToP3Css(color) {
2162
+ const { r, g, b } = oklchToP3(color);
2163
+ return `color(display-p3 ${r} ${g} ${b})`;
2164
+ }
2819
2165
  var TRACK_HEIGHT4 = 22;
2820
2166
  var THUMB_SIZE4 = 18;
2821
- function getColorScaleSliderStyles(tokens, disabled) {
2167
+ function getColorScaleSliderStyles(tokens, gamut, disabled) {
2822
2168
  return reactNative.StyleSheet.create({
2823
2169
  container: {
2824
2170
  gap: tokens.spacing["04"],
@@ -2833,7 +2179,7 @@ function getColorScaleSliderStyles(tokens, disabled) {
2833
2179
  fontFamily: tokens.typography.fonts.main.family,
2834
2180
  fontSize: tokens.typography.fontSizes["04"],
2835
2181
  fontWeight: tokens.typography.fonts.main.weights.medium,
2836
- color: newtone.srgbToHex(tokens.textSecondary.srgb)
2182
+ color: tokens.textSecondary[gamut]
2837
2183
  },
2838
2184
  trackContainer: {
2839
2185
  height: TRACK_HEIGHT4 + THUMB_SIZE4,
@@ -2859,13 +2205,13 @@ function getColorScaleSliderStyles(tokens, disabled) {
2859
2205
  borderRadius: THUMB_SIZE4 / 2,
2860
2206
  backgroundColor: "#ffffff",
2861
2207
  borderWidth: 2,
2862
- borderColor: newtone.srgbToHex(tokens.border.srgb)
2208
+ borderColor: tokens.border[gamut]
2863
2209
  },
2864
2210
  warning: {
2865
2211
  fontFamily: tokens.typography.fonts.main.family,
2866
2212
  fontSize: tokens.typography.fontSizes["01"],
2867
2213
  fontWeight: tokens.typography.fonts.main.weights.medium,
2868
- color: newtone.srgbToHex(tokens.error.fill.srgb)
2214
+ color: tokens.error.fill[gamut]
2869
2215
  }
2870
2216
  });
2871
2217
  }
@@ -2881,40 +2227,41 @@ function ColorScaleSlider({
2881
2227
  snap = false,
2882
2228
  disabled = false,
2883
2229
  animateValue = false,
2230
+ useP3: _useP3,
2884
2231
  style
2885
2232
  }) {
2886
- const tokens = useTokens(1);
2887
- const styles = React14__default.default.useMemo(
2888
- () => getColorScaleSliderStyles(tokens, disabled),
2233
+ const tokens = newtoneApi.useTokens(1);
2234
+ const styles = React13__default.default.useMemo(
2235
+ () => getColorScaleSliderStyles(tokens, tokens.gamut, disabled),
2889
2236
  [tokens, disabled]
2890
2237
  );
2891
- const trackRef = React14__default.default.useRef(null);
2892
- const trackWidth = React14__default.default.useRef(0);
2893
- const trackPageX = React14__default.default.useRef(0);
2894
- const isDragging = React14__default.default.useRef(false);
2895
- const thumbAnim = React14__default.default.useRef(new reactNative.Animated.Value(0)).current;
2896
- const [layoutWidth, setLayoutWidth] = React14__default.default.useState(0);
2897
- const onValueChangeRef = React14__default.default.useRef(onValueChange);
2898
- const disabledRef = React14__default.default.useRef(disabled);
2899
- const colorsLengthRef = React14__default.default.useRef(colors.length);
2900
- const trimEndsRef = React14__default.default.useRef(trimEnds);
2901
- const snapRef = React14__default.default.useRef(snap);
2902
- React14__default.default.useEffect(() => {
2238
+ const trackRef = React13__default.default.useRef(null);
2239
+ const trackWidth = React13__default.default.useRef(0);
2240
+ const trackPageX = React13__default.default.useRef(0);
2241
+ const isDragging = React13__default.default.useRef(false);
2242
+ const thumbAnim = React13__default.default.useRef(new reactNative.Animated.Value(0)).current;
2243
+ const [layoutWidth, setLayoutWidth] = React13__default.default.useState(0);
2244
+ const onValueChangeRef = React13__default.default.useRef(onValueChange);
2245
+ const disabledRef = React13__default.default.useRef(disabled);
2246
+ const colorsLengthRef = React13__default.default.useRef(colors.length);
2247
+ const trimEndsRef = React13__default.default.useRef(trimEnds);
2248
+ const snapRef = React13__default.default.useRef(snap);
2249
+ React13__default.default.useEffect(() => {
2903
2250
  onValueChangeRef.current = onValueChange;
2904
2251
  }, [onValueChange]);
2905
- React14__default.default.useEffect(() => {
2252
+ React13__default.default.useEffect(() => {
2906
2253
  disabledRef.current = disabled;
2907
2254
  }, [disabled]);
2908
- React14__default.default.useEffect(() => {
2255
+ React13__default.default.useEffect(() => {
2909
2256
  colorsLengthRef.current = colors.length;
2910
2257
  }, [colors.length]);
2911
- React14__default.default.useEffect(() => {
2258
+ React13__default.default.useEffect(() => {
2912
2259
  trimEndsRef.current = trimEnds;
2913
2260
  }, [trimEnds]);
2914
- React14__default.default.useEffect(() => {
2261
+ React13__default.default.useEffect(() => {
2915
2262
  snapRef.current = snap;
2916
2263
  }, [snap]);
2917
- const computeNv = React14__default.default.useCallback((pageX) => {
2264
+ const computeNv = React13__default.default.useCallback((pageX) => {
2918
2265
  const localX = pageX - trackPageX.current;
2919
2266
  const ratio2 = Math.min(1, Math.max(0, localX / trackWidth.current));
2920
2267
  const totalSteps2 = colorsLengthRef.current - 1;
@@ -2929,7 +2276,7 @@ function ColorScaleSlider({
2929
2276
  }
2930
2277
  return nv;
2931
2278
  }, []);
2932
- const panResponder = React14__default.default.useRef(
2279
+ const panResponder = React13__default.default.useRef(
2933
2280
  reactNative.PanResponder.create({
2934
2281
  onStartShouldSetPanResponder: () => !disabledRef.current,
2935
2282
  onMoveShouldSetPanResponder: () => !disabledRef.current,
@@ -2957,7 +2304,7 @@ function ColorScaleSlider({
2957
2304
  const ratio = range > 0 ? (maxNV - clampedValue) / range : 0.5;
2958
2305
  const usableWidth = Math.max(0, layoutWidth - THUMB_SIZE4);
2959
2306
  const thumbLeft = ratio * usableWidth;
2960
- React14__default.default.useEffect(() => {
2307
+ React13__default.default.useEffect(() => {
2961
2308
  if (isDragging.current || !animateValue) {
2962
2309
  thumbAnim.setValue(thumbLeft);
2963
2310
  } else {
@@ -2968,7 +2315,7 @@ function ColorScaleSlider({
2968
2315
  }).start();
2969
2316
  }
2970
2317
  }, [thumbLeft, animateValue, thumbAnim]);
2971
- return /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : [style]] }, label && /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.labelRow }, /* @__PURE__ */ React14__default.default.createElement(reactNative.Text, { style: styles.label }, label)), /* @__PURE__ */ React14__default.default.createElement(
2318
+ return /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: [styles.container, ...Array.isArray(style) ? style : [style]] }, label && /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.labelRow }, /* @__PURE__ */ React13__default.default.createElement(reactNative.Text, { style: styles.label }, label)), /* @__PURE__ */ React13__default.default.createElement(
2972
2319
  reactNative.View,
2973
2320
  {
2974
2321
  ref: trackRef,
@@ -2983,17 +2330,17 @@ function ColorScaleSlider({
2983
2330
  },
2984
2331
  ...panResponder.panHandlers
2985
2332
  },
2986
- /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.gradientTrack }, visibleColors.map((color, i) => /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { key: i, style: [styles.segment, { backgroundColor: newtone.srgbToHex(color.srgb) }] }))),
2987
- /* @__PURE__ */ React14__default.default.createElement(reactNative.Animated.View, { style: [styles.thumb, { left: thumbAnim }] })
2988
- ), warning && /* @__PURE__ */ React14__default.default.createElement(reactNative.Text, { style: styles.warning }, warning));
2333
+ /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.gradientTrack }, visibleColors.map((color, i) => /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { key: i, style: [styles.segment, { backgroundColor: tokens.gamut === "p3" ? oklchToP3Css(color.oklch) : newtone.srgbToHex(color.srgb) }] }))),
2334
+ /* @__PURE__ */ React13__default.default.createElement(reactNative.Animated.View, { style: [styles.thumb, { left: thumbAnim }] })
2335
+ ), warning && /* @__PURE__ */ React13__default.default.createElement(reactNative.Text, { style: styles.warning }, warning));
2989
2336
  }
2990
- function getAppShellStyles(tokens) {
2337
+ function getAppShellStyles(tokens, gamut) {
2991
2338
  return reactNative.StyleSheet.create({
2992
2339
  container: {
2993
2340
  flex: 1,
2994
2341
  flexDirection: "row",
2995
2342
  overflow: "hidden",
2996
- backgroundColor: newtone.srgbToHex(tokens.background.srgb)
2343
+ backgroundColor: tokens.background[gamut]
2997
2344
  },
2998
2345
  main: {
2999
2346
  flex: 1,
@@ -3006,18 +2353,18 @@ function getAppShellStyles(tokens) {
3006
2353
 
3007
2354
  // src/composites/layout/AppShell/AppShell.tsx
3008
2355
  function AppShell({ sidebar, children }) {
3009
- const tokens = useTokens();
3010
- const styles = React14__default.default.useMemo(() => getAppShellStyles(tokens), [tokens]);
3011
- return /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.container }, sidebar, /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.main }, children));
2356
+ const tokens = newtoneApi.useTokens();
2357
+ const styles = React13__default.default.useMemo(() => getAppShellStyles(tokens, tokens.gamut), [tokens]);
2358
+ return /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.container }, sidebar, /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.main }, children));
3012
2359
  }
3013
- function getSidebarStyles({ tokens, width, bordered }) {
3014
- const borderColor = newtone.srgbToHex(tokens.border.srgb);
2360
+ function getSidebarStyles({ tokens, gamut, width, bordered }) {
2361
+ const borderColor = tokens.border[gamut];
3015
2362
  return reactNative.StyleSheet.create({
3016
2363
  container: {
3017
2364
  width,
3018
2365
  flexShrink: 0,
3019
2366
  flexDirection: "column",
3020
- backgroundColor: newtone.srgbToHex(tokens.background.srgb),
2367
+ backgroundColor: tokens.background[gamut],
3021
2368
  borderRightWidth: bordered ? 1 : 0,
3022
2369
  borderRightColor: borderColor
3023
2370
  },
@@ -3045,15 +2392,15 @@ function Sidebar({
3045
2392
  width = 260,
3046
2393
  bordered = true
3047
2394
  }) {
3048
- const tokens = useTokens();
3049
- const styles = React14__default.default.useMemo(
3050
- () => getSidebarStyles({ tokens, width, bordered }),
2395
+ const tokens = newtoneApi.useTokens();
2396
+ const styles = React13__default.default.useMemo(
2397
+ () => getSidebarStyles({ tokens, gamut: tokens.gamut, width, bordered }),
3051
2398
  [tokens, width, bordered]
3052
2399
  );
3053
- return /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.container }, header && /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.header }, header), /* @__PURE__ */ React14__default.default.createElement(reactNative.ScrollView, { style: styles.body }, children), footer && /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.footer }, footer));
2400
+ return /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.container }, header && /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.header }, header), /* @__PURE__ */ React13__default.default.createElement(reactNative.ScrollView, { style: styles.body }, children), footer && /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.footer }, footer));
3054
2401
  }
3055
- function getNavbarStyles({ tokens, height, bordered }) {
3056
- const borderColor = newtone.srgbToHex(tokens.border.srgb);
2402
+ function getNavbarStyles({ tokens, gamut, height, bordered }) {
2403
+ const borderColor = tokens.border[gamut];
3057
2404
  return reactNative.StyleSheet.create({
3058
2405
  container: {
3059
2406
  flexDirection: "row",
@@ -3061,7 +2408,7 @@ function getNavbarStyles({ tokens, height, bordered }) {
3061
2408
  height,
3062
2409
  flexShrink: 0,
3063
2410
  paddingHorizontal: 24,
3064
- backgroundColor: newtone.srgbToHex(tokens.background.srgb),
2411
+ backgroundColor: tokens.background[gamut],
3065
2412
  borderBottomWidth: bordered ? 1 : 0,
3066
2413
  borderBottomColor: borderColor
3067
2414
  },
@@ -3087,12 +2434,12 @@ function Navbar({
3087
2434
  height = 56,
3088
2435
  bordered = true
3089
2436
  }) {
3090
- const tokens = useTokens();
3091
- const styles = React14__default.default.useMemo(
3092
- () => getNavbarStyles({ tokens, height, bordered }),
2437
+ const tokens = newtoneApi.useTokens();
2438
+ const styles = React13__default.default.useMemo(
2439
+ () => getNavbarStyles({ tokens, gamut: tokens.gamut, height, bordered }),
3093
2440
  [tokens, height, bordered]
3094
2441
  );
3095
- return /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.container }, children ? children : /* @__PURE__ */ React14__default.default.createElement(React14__default.default.Fragment, null, /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.left }, left), /* @__PURE__ */ React14__default.default.createElement(reactNative.View, { style: styles.right }, right)));
2442
+ return /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.container }, children ? children : /* @__PURE__ */ React13__default.default.createElement(React13__default.default.Fragment, null, /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.left }, left), /* @__PURE__ */ React13__default.default.createElement(reactNative.View, { style: styles.right }, right)));
3096
2443
  }
3097
2444
 
3098
2445
  // src/registry/registry.ts
@@ -4040,61 +3387,123 @@ var ICON_CATALOG = [
4040
3387
  }
4041
3388
  ];
4042
3389
 
3390
+ Object.defineProperty(exports, "ACCENT_DEFAULTS", {
3391
+ enumerable: true,
3392
+ get: function () { return newtoneApi.ACCENT_DEFAULTS; }
3393
+ });
4043
3394
  Object.defineProperty(exports, "DEFAULT_FONT_SIZES", {
4044
3395
  enumerable: true,
4045
- get: function () { return fonts.DEFAULT_FONT_SIZES; }
3396
+ get: function () { return newtoneApi.DEFAULT_FONT_SIZES; }
4046
3397
  });
4047
3398
  Object.defineProperty(exports, "DEFAULT_LINE_HEIGHTS", {
4048
3399
  enumerable: true,
4049
- get: function () { return fonts.DEFAULT_LINE_HEIGHTS; }
3400
+ get: function () { return newtoneApi.DEFAULT_LINE_HEIGHTS; }
4050
3401
  });
4051
3402
  Object.defineProperty(exports, "DEFAULT_ROLE_SCALES", {
4052
3403
  enumerable: true,
4053
- get: function () { return fonts.DEFAULT_ROLE_SCALES; }
3404
+ get: function () { return newtoneApi.DEFAULT_ROLE_SCALES; }
3405
+ });
3406
+ Object.defineProperty(exports, "DEFAULT_THEME_CONFIG", {
3407
+ enumerable: true,
3408
+ get: function () { return newtoneApi.DEFAULT_THEME_CONFIG; }
3409
+ });
3410
+ Object.defineProperty(exports, "ERROR_DEFAULTS", {
3411
+ enumerable: true,
3412
+ get: function () { return newtoneApi.ERROR_DEFAULTS; }
3413
+ });
3414
+ Object.defineProperty(exports, "FrameContext", {
3415
+ enumerable: true,
3416
+ get: function () { return newtoneApi.FrameContext; }
3417
+ });
3418
+ Object.defineProperty(exports, "NEUTRAL_DEFAULTS", {
3419
+ enumerable: true,
3420
+ get: function () { return newtoneApi.NEUTRAL_DEFAULTS; }
3421
+ });
3422
+ Object.defineProperty(exports, "NewtoneProvider", {
3423
+ enumerable: true,
3424
+ get: function () { return newtoneApi.NewtoneProvider; }
3425
+ });
3426
+ Object.defineProperty(exports, "SUCCESS_DEFAULTS", {
3427
+ enumerable: true,
3428
+ get: function () { return newtoneApi.SUCCESS_DEFAULTS; }
3429
+ });
3430
+ Object.defineProperty(exports, "WARNING_DEFAULTS", {
3431
+ enumerable: true,
3432
+ get: function () { return newtoneApi.WARNING_DEFAULTS; }
4054
3433
  });
4055
3434
  Object.defineProperty(exports, "buildGoogleFontsUrl", {
4056
3435
  enumerable: true,
4057
- get: function () { return fonts.buildGoogleFontsUrl; }
3436
+ get: function () { return newtoneApi.buildGoogleFontsUrl; }
3437
+ });
3438
+ Object.defineProperty(exports, "computeTokens", {
3439
+ enumerable: true,
3440
+ get: function () { return newtoneApi.computeTokens; }
3441
+ });
3442
+ Object.defineProperty(exports, "enqueueObservation", {
3443
+ enumerable: true,
3444
+ get: function () { return newtoneApi.enqueueObservation; }
3445
+ });
3446
+ Object.defineProperty(exports, "isV2TokenOverrides", {
3447
+ enumerable: true,
3448
+ get: function () { return newtoneApi.isV2TokenOverrides; }
3449
+ });
3450
+ Object.defineProperty(exports, "measureAvgCharWidth", {
3451
+ enumerable: true,
3452
+ get: function () { return newtoneApi.measureAvgCharWidth; }
3453
+ });
3454
+ Object.defineProperty(exports, "migrateV1ToV2", {
3455
+ enumerable: true,
3456
+ get: function () { return newtoneApi.migrateV1ToV2; }
3457
+ });
3458
+ Object.defineProperty(exports, "useBreakpoint", {
3459
+ enumerable: true,
3460
+ get: function () { return newtoneApi.useBreakpoint; }
3461
+ });
3462
+ Object.defineProperty(exports, "useFrameContext", {
3463
+ enumerable: true,
3464
+ get: function () { return newtoneApi.useFrameContext; }
3465
+ });
3466
+ Object.defineProperty(exports, "useLocalCalibration", {
3467
+ enumerable: true,
3468
+ get: function () { return newtoneApi.useLocalCalibration; }
3469
+ });
3470
+ Object.defineProperty(exports, "useNewtoneTheme", {
3471
+ enumerable: true,
3472
+ get: function () { return newtoneApi.useNewtoneTheme; }
3473
+ });
3474
+ Object.defineProperty(exports, "useTokens", {
3475
+ enumerable: true,
3476
+ get: function () { return newtoneApi.useTokens; }
3477
+ });
3478
+ Object.defineProperty(exports, "useTypographyCalibrations", {
3479
+ enumerable: true,
3480
+ get: function () { return newtoneApi.useTypographyCalibrations; }
4058
3481
  });
4059
- exports.ACCENT_DEFAULTS = ACCENT_DEFAULTS;
4060
3482
  exports.AppShell = AppShell;
4061
3483
  exports.Button = Button;
4062
3484
  exports.CATEGORIES = CATEGORIES;
4063
3485
  exports.COMPONENTS = COMPONENTS;
4064
3486
  exports.Card = Card;
4065
3487
  exports.ColorScaleSlider = ColorScaleSlider;
4066
- exports.DEFAULT_THEME_CONFIG = DEFAULT_THEME_CONFIG;
4067
- exports.ERROR_DEFAULTS = ERROR_DEFAULTS;
4068
3488
  exports.Frame = Frame;
4069
3489
  exports.HueSlider = HueSlider;
4070
3490
  exports.ICON_CATALOG = ICON_CATALOG;
4071
3491
  exports.Icon = Icon;
4072
- exports.NEUTRAL_DEFAULTS = NEUTRAL_DEFAULTS;
4073
3492
  exports.Navbar = Navbar;
4074
- exports.NewtoneProvider = NewtoneProvider;
4075
3493
  exports.Popover = Popover;
4076
- exports.SUCCESS_DEFAULTS = SUCCESS_DEFAULTS;
4077
3494
  exports.Select = Select;
4078
3495
  exports.Sidebar = Sidebar;
4079
3496
  exports.Slider = Slider;
4080
- exports.Text = Text2;
3497
+ exports.Text = Text3;
4081
3498
  exports.TextInput = TextInput;
4082
3499
  exports.Toggle = Toggle;
4083
- exports.WARNING_DEFAULTS = WARNING_DEFAULTS;
4084
3500
  exports.Wrapper = Wrapper;
4085
- exports.computeTokens = computeTokens;
4086
3501
  exports.generateComponentCode = generateComponentCode;
4087
3502
  exports.getCategory = getCategory;
4088
3503
  exports.getComponent = getComponent;
4089
3504
  exports.getComponentsByCategory = getComponentsByCategory;
4090
3505
  exports.isOptionGroup = isOptionGroup;
4091
- exports.measureAvgCharWidth = measureAvgCharWidth;
4092
3506
  exports.useFocusVisible = useFocusVisible;
4093
- exports.useFrameContext = useFrameContext;
4094
- exports.useLocalCalibration = useLocalCalibration;
4095
- exports.useNewtoneTheme = useNewtoneTheme;
4096
3507
  exports.usePopover = usePopover;
4097
- exports.useTokens = useTokens;
4098
- exports.useTypographyCalibrations = useTypographyCalibrations;
4099
3508
  //# sourceMappingURL=index.cjs.map
4100
3509
  //# sourceMappingURL=index.cjs.map