@titan-design/react-ui 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/MesoStatusCard-CQk71hSi.d.mts +77 -0
  2. package/dist/MesoStatusCard-CQk71hSi.d.ts +77 -0
  3. package/dist/bodymap.d.mts +246 -3
  4. package/dist/bodymap.d.ts +246 -3
  5. package/dist/bodymap.mjs +1911 -6
  6. package/dist/bodymap.mjs.map +1 -1
  7. package/dist/index.d.mts +31 -738
  8. package/dist/index.d.ts +31 -738
  9. package/dist/index.js +894 -1692
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +10287 -8203
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/pages-D7Jlssvp.d.ts +791 -0
  14. package/dist/pages-MO0JCySL.d.mts +791 -0
  15. package/dist/pages.d.mts +4 -0
  16. package/dist/pages.d.ts +4 -0
  17. package/dist/pages.js +6646 -0
  18. package/dist/pages.js.map +1 -0
  19. package/dist/pages.mjs +6626 -0
  20. package/dist/pages.mjs.map +1 -0
  21. package/dist/theme/index.d.mts +12 -12
  22. package/dist/theme/index.d.ts +12 -12
  23. package/dist/theme/index.js +30 -30
  24. package/dist/theme/index.js.map +1 -1
  25. package/dist/theme/index.mjs +1880 -2
  26. package/dist/theme/index.mjs.map +1 -1
  27. package/dist/theme/tokens-css.mjs +573 -1
  28. package/dist/theme/tokens-css.mjs.map +1 -1
  29. package/package.json +9 -7
  30. package/src/components/custom/Workout/BaseBadge.stories.tsx +3 -3
  31. package/src/components/custom/Workout/BaseBadge.test.tsx +1 -1
  32. package/src/components/custom/Workout/BaseBadge.tsx +1 -1
  33. package/src/components/custom/Workout/ExerciseCard.tsx +5 -1
  34. package/src/components/custom/Workout/ExerciseDetailPage.tsx +17 -4
  35. package/src/components/custom/Workout/IntensityBar.test.tsx +112 -60
  36. package/src/components/custom/Workout/IntensityBar.tsx +109 -58
  37. package/src/components/custom/Workout/PlaceholderStrip.tsx +5 -9
  38. package/src/components/custom/Workout/PrBadge.tsx +3 -3
  39. package/src/components/custom/Workout/PrHistoryModal.tsx +2 -2
  40. package/src/components/custom/Workout/README.md +50 -0
  41. package/src/components/custom/Workout/RestTimer.test.tsx +41 -10
  42. package/src/components/custom/Workout/RestTimer.tsx +48 -43
  43. package/src/components/custom/Workout/SetRow.tsx +10 -1
  44. package/src/components/custom/Workout/TempoDisplay.stories.tsx +69 -2
  45. package/src/components/custom/Workout/TempoDisplay.test.tsx +35 -0
  46. package/src/components/custom/Workout/TempoDisplay.tsx +104 -1
  47. package/src/components/custom/Workout/VelocityStrip.test.tsx +89 -2
  48. package/src/components/custom/Workout/VelocityStrip.tsx +203 -38
  49. package/src/components/custom/Workout/WeekRow.test.tsx +2 -2
  50. package/src/components/custom/Workout/WeightBadge.test.tsx +2 -2
  51. package/src/components/custom/Workout/WeightBadge.tsx +2 -2
  52. package/src/components/custom/Workout/icons.tsx +68 -0
  53. package/src/components/custom/Workout/index.ts +38 -47
  54. package/src/index.ts +3 -2
  55. package/src/pages.ts +61 -0
  56. package/src/test/stories-smoke.test.tsx +50 -0
  57. package/src/theme/barrel.ts +53 -0
  58. package/src/theme/index.ts +8 -43
  59. package/src/theme/native-theming-guard.test.ts +117 -0
  60. package/dist/bodymap-BhG55xHM.d.mts +0 -318
  61. package/dist/bodymap-BhG55xHM.d.ts +0 -318
  62. package/dist/chunk-2SISKTWM.mjs +0 -1027
  63. package/dist/chunk-2SISKTWM.mjs.map +0 -1
  64. package/dist/chunk-7XPB4NAO.mjs +0 -1013
  65. package/dist/chunk-7XPB4NAO.mjs.map +0 -1
  66. package/dist/chunk-SNVKL5WZ.mjs +0 -883
  67. package/dist/chunk-SNVKL5WZ.mjs.map +0 -1
@@ -1,883 +0,0 @@
1
- import { lightThemeCSSVars, darkThemeCSSVars, semanticColorsLight, semanticColorsDark, getSemanticColors } from './chunk-7XPB4NAO.mjs';
2
- import { Platform, View } from 'react-native';
3
- import { vars } from 'nativewind';
4
- import { jsx as jsx$1, jsxs as jsxs$1 } from 'react/jsx-runtime';
5
- export { Fragment } from 'react/jsx-runtime';
6
-
7
- function hexToRgb(hex) {
8
- const cleaned = hex.replace("#", "");
9
- let r, g, b;
10
- if (cleaned.length === 3) {
11
- r = parseInt(cleaned[0] + cleaned[0], 16);
12
- g = parseInt(cleaned[1] + cleaned[1], 16);
13
- b = parseInt(cleaned[2] + cleaned[2], 16);
14
- } else if (cleaned.length === 6) {
15
- r = parseInt(cleaned.slice(0, 2), 16);
16
- g = parseInt(cleaned.slice(2, 4), 16);
17
- b = parseInt(cleaned.slice(4, 6), 16);
18
- } else {
19
- return null;
20
- }
21
- return { r, g, b };
22
- }
23
- function rgbToHsv(r, g, b) {
24
- const rNorm = r / 255;
25
- const gNorm = g / 255;
26
- const bNorm = b / 255;
27
- const max = Math.max(rNorm, gNorm, bNorm);
28
- const min = Math.min(rNorm, gNorm, bNorm);
29
- const delta = max - min;
30
- const v = max;
31
- const s = max === 0 ? 0 : delta / max;
32
- let h = 0;
33
- if (delta !== 0) {
34
- if (max === rNorm) {
35
- h = 60 * ((gNorm - bNorm) / delta % 6);
36
- } else if (max === gNorm) {
37
- h = 60 * ((bNorm - rNorm) / delta + 2);
38
- } else {
39
- h = 60 * ((rNorm - gNorm) / delta + 4);
40
- }
41
- }
42
- if (h < 0) h += 360;
43
- return { h, s, v };
44
- }
45
- function hsvToRgb(h, s, v) {
46
- const c = v * s;
47
- const x = c * (1 - Math.abs(h / 60 % 2 - 1));
48
- const m = v - c;
49
- let rPrime, gPrime, bPrime;
50
- if (h >= 0 && h < 60) {
51
- rPrime = c;
52
- gPrime = x;
53
- bPrime = 0;
54
- } else if (h >= 60 && h < 120) {
55
- rPrime = x;
56
- gPrime = c;
57
- bPrime = 0;
58
- } else if (h >= 120 && h < 180) {
59
- rPrime = 0;
60
- gPrime = c;
61
- bPrime = x;
62
- } else if (h >= 180 && h < 240) {
63
- rPrime = 0;
64
- gPrime = x;
65
- bPrime = c;
66
- } else if (h >= 240 && h < 300) {
67
- rPrime = x;
68
- gPrime = 0;
69
- bPrime = c;
70
- } else {
71
- rPrime = c;
72
- gPrime = 0;
73
- bPrime = x;
74
- }
75
- return {
76
- r: Math.round((rPrime + m) * 255),
77
- g: Math.round((gPrime + m) * 255),
78
- b: Math.round((bPrime + m) * 255)
79
- };
80
- }
81
- function rgbToHex(r, g, b) {
82
- const toHex = (n) => {
83
- const clamped = Math.max(0, Math.min(255, Math.round(n)));
84
- return clamped.toString(16).padStart(2, "0");
85
- };
86
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
87
- }
88
- function lighten(hex, amount = 0.1) {
89
- const rgb = hexToRgb(hex);
90
- if (!rgb) return hex;
91
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
92
- const newV = Math.min(1, hsv.v + amount);
93
- const newRgb = hsvToRgb(hsv.h, hsv.s, newV);
94
- return rgbToHex(newRgb.r, newRgb.g, newRgb.b);
95
- }
96
- function darken(hex, amount = 0.1) {
97
- const rgb = hexToRgb(hex);
98
- if (!rgb) return hex;
99
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
100
- const newV = Math.max(0, hsv.v - amount);
101
- const newRgb = hsvToRgb(hsv.h, hsv.s, newV);
102
- return rgbToHex(newRgb.r, newRgb.g, newRgb.b);
103
- }
104
- function getHoverColors(bgColor, intensity = "medium") {
105
- const amounts = {
106
- subtle: 0.01,
107
- medium: 0.02,
108
- strong: 0.03
109
- };
110
- const amount = amounts[intensity];
111
- return {
112
- raised: lighten(bgColor, amount),
113
- // Raised hover: lighten (lifting up)
114
- pressed: darken(bgColor, amount)
115
- // Pressed hover: darken (pressing down)
116
- };
117
- }
118
- function isDark(hex) {
119
- const rgb = hexToRgb(hex);
120
- if (!rgb) return true;
121
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
122
- return hsv.v < 0.6;
123
- }
124
- var shadowColors = {
125
- // For charcoal surfaces (~#2C2C2C to #3C3C3C)
126
- charcoal: {
127
- dark: "rgba(0, 0, 0, 0.5)",
128
- light: "rgba(255, 255, 255, 0.12)",
129
- // brighter for crisp rim light
130
- darker: "rgba(0, 0, 0, 0.6)"
131
- },
132
- // For neutral dark surfaces (~#1F2937)
133
- neutralDark: {
134
- dark: "rgba(0, 0, 0, 0.4)",
135
- light: "rgba(255, 255, 255, 0.08)",
136
- darker: "rgba(0, 0, 0, 0.5)"
137
- },
138
- // For light surfaces (white/light gray backgrounds)
139
- neutralLight: {
140
- dark: "rgba(0, 0, 0, 0.15)",
141
- // Visible dark shadow for depth on light backgrounds
142
- light: "rgba(255, 255, 255, 1)",
143
- // Bright highlight for raised effect (visible on light gray)
144
- darker: "rgba(0, 0, 0, 0.2)"
145
- // Deeper shadow for pressed states
146
- }
147
- };
148
- var intensityConfig = {
149
- subtle: { offset: 1, blur: 2 },
150
- // very light, barely visible
151
- medium: { offset: 2, blur: 4 },
152
- // noticeable but restrained
153
- strong: { offset: 2, blur: 5 }
154
- // slightly deeper blur, same offset as medium
155
- };
156
- function createRaisedShadow(surface = "charcoal", intensity = "medium") {
157
- const colors = shadowColors[surface];
158
- const { offset, blur } = intensityConfig[intensity];
159
- const rimBlur = 1;
160
- return Platform.select({
161
- web: {
162
- boxShadow: `${offset}px ${offset}px ${blur}px ${colors.dark}, -${offset}px -${offset}px ${rimBlur}px ${colors.light}`
163
- },
164
- default: {
165
- // React Native shadow approximation (limited compared to web)
166
- shadowColor: "#000",
167
- shadowOffset: { width: offset, height: offset },
168
- shadowOpacity: 0.3,
169
- shadowRadius: blur / 2,
170
- elevation: offset
171
- }
172
- });
173
- }
174
- function createPressedShadow(surface = "charcoal", intensity = "medium") {
175
- const colors = shadowColors[surface];
176
- const { offset, blur } = intensityConfig[intensity];
177
- const rimOffset = 1;
178
- const rimBlur = 1;
179
- return Platform.select({
180
- web: {
181
- boxShadow: `inset ${offset}px ${offset}px ${blur}px ${colors.darker}, inset -${rimOffset}px -${rimOffset}px ${rimBlur}px ${colors.light}`
182
- },
183
- default: {
184
- // React Native doesn't support inset shadows, approximate with darker bg
185
- shadowOpacity: 0,
186
- elevation: 0
187
- }
188
- });
189
- }
190
- function createFlatShadow() {
191
- return Platform.select({
192
- web: {
193
- boxShadow: "none"
194
- },
195
- default: {
196
- shadowOpacity: 0,
197
- elevation: 0
198
- }
199
- });
200
- }
201
- function createRaisedHoverShadow(surface = "charcoal", intensity = "medium") {
202
- const colors = shadowColors[surface];
203
- const { offset, blur } = intensityConfig[intensity];
204
- const hoverOffset = Math.max(1, Math.round(offset / 2));
205
- const hoverBlur = Math.max(1, Math.round(blur / 2));
206
- const rimBlur = 1;
207
- return Platform.select({
208
- web: {
209
- // Keep same offsets as normal state for rim to prevent "shrinking" effect
210
- boxShadow: `${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${colors.dark}, -${offset}px -${offset}px ${rimBlur}px ${colors.light}`
211
- },
212
- default: {
213
- shadowColor: "#000",
214
- shadowOffset: { width: hoverOffset, height: hoverOffset },
215
- shadowOpacity: 0.2,
216
- shadowRadius: hoverBlur / 2,
217
- elevation: hoverOffset
218
- }
219
- });
220
- }
221
- function createPressedHoverShadow(surface = "charcoal", intensity = "medium") {
222
- const colors = shadowColors[surface];
223
- const { offset, blur } = intensityConfig[intensity];
224
- const hoverOffset = Math.max(1, Math.round(offset / 2));
225
- const hoverBlur = Math.max(1, Math.round(blur / 2));
226
- const rimBlur = 1;
227
- return Platform.select({
228
- web: {
229
- // Keep rim offset at 1px (same as pressed normal) to prevent "shrinking" effect
230
- boxShadow: `inset ${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${colors.darker}, inset -1px -1px ${rimBlur}px ${colors.light}`
231
- },
232
- default: {
233
- shadowOpacity: 0,
234
- elevation: 0
235
- }
236
- });
237
- }
238
- var neumorphicShadows = {
239
- // Charcoal surface shadows (for dark toolbars, cards)
240
- charcoal: {
241
- raised: {
242
- subtle: createRaisedShadow("charcoal", "subtle"),
243
- medium: createRaisedShadow("charcoal", "medium"),
244
- strong: createRaisedShadow("charcoal", "strong")
245
- },
246
- raisedHover: {
247
- subtle: createRaisedHoverShadow("charcoal", "subtle"),
248
- medium: createRaisedHoverShadow("charcoal", "medium"),
249
- strong: createRaisedHoverShadow("charcoal", "strong")
250
- },
251
- pressed: {
252
- subtle: createPressedShadow("charcoal", "subtle"),
253
- medium: createPressedShadow("charcoal", "medium"),
254
- strong: createPressedShadow("charcoal", "strong")
255
- },
256
- pressedHover: {
257
- subtle: createPressedHoverShadow("charcoal", "subtle"),
258
- medium: createPressedHoverShadow("charcoal", "medium"),
259
- strong: createPressedHoverShadow("charcoal", "strong")
260
- },
261
- flat: createFlatShadow()
262
- },
263
- // Neutral dark surface shadows
264
- neutralDark: {
265
- raised: {
266
- subtle: createRaisedShadow("neutralDark", "subtle"),
267
- medium: createRaisedShadow("neutralDark", "medium"),
268
- strong: createRaisedShadow("neutralDark", "strong")
269
- },
270
- raisedHover: {
271
- subtle: createRaisedHoverShadow("neutralDark", "subtle"),
272
- medium: createRaisedHoverShadow("neutralDark", "medium"),
273
- strong: createRaisedHoverShadow("neutralDark", "strong")
274
- },
275
- pressed: {
276
- subtle: createPressedShadow("neutralDark", "subtle"),
277
- medium: createPressedShadow("neutralDark", "medium"),
278
- strong: createPressedShadow("neutralDark", "strong")
279
- },
280
- pressedHover: {
281
- subtle: createPressedHoverShadow("neutralDark", "subtle"),
282
- medium: createPressedHoverShadow("neutralDark", "medium"),
283
- strong: createPressedHoverShadow("neutralDark", "strong")
284
- },
285
- flat: createFlatShadow()
286
- },
287
- // Neutral light surface shadows
288
- neutralLight: {
289
- raised: {
290
- subtle: createRaisedShadow("neutralLight", "subtle"),
291
- medium: createRaisedShadow("neutralLight", "medium"),
292
- strong: createRaisedShadow("neutralLight", "strong")
293
- },
294
- raisedHover: {
295
- subtle: createRaisedHoverShadow("neutralLight", "subtle"),
296
- medium: createRaisedHoverShadow("neutralLight", "medium"),
297
- strong: createRaisedHoverShadow("neutralLight", "strong")
298
- },
299
- pressed: {
300
- subtle: createPressedShadow("neutralLight", "subtle"),
301
- medium: createPressedShadow("neutralLight", "medium"),
302
- strong: createPressedShadow("neutralLight", "strong")
303
- },
304
- pressedHover: {
305
- subtle: createPressedHoverShadow("neutralLight", "subtle"),
306
- medium: createPressedHoverShadow("neutralLight", "medium"),
307
- strong: createPressedHoverShadow("neutralLight", "strong")
308
- },
309
- flat: createFlatShadow()
310
- }
311
- };
312
- var elevationSystem = {
313
- // Deep inset (recessed input fields, deeply pressed buttons)
314
- [-2]: {
315
- name: "deep-inset",
316
- colorAdjustment: 0,
317
- shadowIntensity: "strong",
318
- shadowStyle: "pressed",
319
- description: "Deeply recessed elements (e.g., input fields, deeply pressed buttons)"
320
- },
321
- // Shallow inset (pressed buttons, sunken panels)
322
- [-1]: {
323
- name: "inset",
324
- colorAdjustment: 0,
325
- shadowIntensity: "medium",
326
- shadowStyle: "pressed",
327
- description: "Shallow inset elements (e.g., pressed buttons, sunken panels within cards)"
328
- },
329
- // Base level (page background, default surface)
330
- [0]: {
331
- name: "base",
332
- colorAdjustment: 0,
333
- shadowIntensity: "subtle",
334
- shadowStyle: "raised",
335
- description: "Base surface level (page background, default containers)"
336
- },
337
- // Level 1: Subtle elevation (outline cards, subtle containers)
338
- [1]: {
339
- name: "subtle",
340
- colorAdjustment: 0.01,
341
- shadowIntensity: "subtle",
342
- shadowStyle: "raised",
343
- description: "Subtle elevation (outline cards, subtle containers)"
344
- },
345
- // Level 2: Standard elevation (default cards, buttons)
346
- [2]: {
347
- name: "standard",
348
- colorAdjustment: 0.02,
349
- shadowIntensity: "medium",
350
- shadowStyle: "raised",
351
- description: "Standard elevation (default cards, raised buttons)"
352
- },
353
- // Level 3: Prominent elevation (important cards, modals)
354
- [3]: {
355
- name: "prominent",
356
- colorAdjustment: 0.04,
357
- shadowIntensity: "strong",
358
- shadowStyle: "raised",
359
- description: "Prominent elevation (important cards, modals, dropdowns)"
360
- },
361
- // Level 4: High elevation (overlays, popovers)
362
- [4]: {
363
- name: "high",
364
- colorAdjustment: 0.06,
365
- shadowIntensity: "strong",
366
- shadowStyle: "raised",
367
- description: "High elevation (overlays, popovers, tooltips)"
368
- },
369
- // Level 5: Floating (toasts, floating action buttons)
370
- [5]: {
371
- name: "floating",
372
- colorAdjustment: 0.08,
373
- shadowIntensity: "strong",
374
- shadowStyle: "raised",
375
- description: "Floating elevation (toasts, floating action buttons, highest z-index)"
376
- }
377
- };
378
- function calculateRimLightColor(baseColor, level) {
379
- const rgb = hexToRgb(baseColor);
380
- if (!rgb) {
381
- return "rgba(255, 255, 255, 0.5)";
382
- }
383
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
384
- const isLight = hsv.v > 0.6;
385
- const isSaturated = hsv.s > 0.3;
386
- const absLevel = Math.abs(level);
387
- const opacityBoost = Math.max(0, (absLevel - 1) * 0.05);
388
- if (isSaturated) {
389
- const rimLightValue = 0.95;
390
- const rimLightRgb = hsvToRgb(hsv.h, hsv.s * 0.3, rimLightValue);
391
- const baseOpacity = isLight ? 0.9 : 0.5;
392
- const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
393
- return `rgba(${rimLightRgb.r}, ${rimLightRgb.g}, ${rimLightRgb.b}, ${finalOpacity.toFixed(2)})`;
394
- } else {
395
- const baseOpacity = isLight ? 0.9 : 0.12;
396
- const finalOpacity = Math.min(1, baseOpacity + opacityBoost);
397
- return `rgba(255, 255, 255, ${finalOpacity.toFixed(2)})`;
398
- }
399
- }
400
- function calculateDarkShadowColors(surfaceColor) {
401
- const rgb = hexToRgb(surfaceColor);
402
- if (!rgb) {
403
- return {
404
- dark: "rgba(0, 0, 0, 0.3)",
405
- darker: "rgba(0, 0, 0, 0.4)"
406
- };
407
- }
408
- const hsv = rgbToHsv(rgb.r, rgb.g, rgb.b);
409
- const isLight = hsv.v > 0.6;
410
- const isSaturated = hsv.s > 0.3;
411
- if (isSaturated) {
412
- const darkShadowValue = 0.15;
413
- const darkShadowRgb = hsvToRgb(hsv.h, hsv.s, darkShadowValue);
414
- if (isLight) {
415
- return {
416
- dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.3)`,
417
- darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.4)`
418
- };
419
- } else {
420
- return {
421
- dark: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.5)`,
422
- darker: `rgba(${darkShadowRgb.r}, ${darkShadowRgb.g}, ${darkShadowRgb.b}, 0.6)`
423
- };
424
- }
425
- } else {
426
- if (isLight) {
427
- return {
428
- dark: "rgba(0, 0, 0, 0.2)",
429
- darker: "rgba(0, 0, 0, 0.3)"
430
- };
431
- } else {
432
- return {
433
- dark: "rgba(0, 0, 0, 0.5)",
434
- darker: "rgba(0, 0, 0, 0.6)"
435
- };
436
- }
437
- }
438
- }
439
- function getRimLightConfig() {
440
- return {
441
- offset: 1,
442
- // Fixed 1px for crisp rim
443
- blur: 1
444
- // Tight blur for crisp edge
445
- };
446
- }
447
- function getElevationConfig(level) {
448
- return elevationSystem[level];
449
- }
450
- var elevationSurfaceCache = /* @__PURE__ */ new Map();
451
- var MAX_CACHE_SIZE = 100;
452
- function getCacheKey(baseColor, level, theme) {
453
- return `${baseColor}-${level}-${theme}`;
454
- }
455
- function calculateElevationSurface(baseColor, level, theme) {
456
- const config = elevationSystem[level];
457
- if (config.colorAdjustment === 0) {
458
- return baseColor;
459
- }
460
- if (level < 0) {
461
- return baseColor;
462
- }
463
- return lighten(baseColor, config.colorAdjustment);
464
- }
465
- function getElevationSurface(baseColor, level, theme) {
466
- const cacheKey = getCacheKey(baseColor, level, theme);
467
- if (elevationSurfaceCache.has(cacheKey)) {
468
- return elevationSurfaceCache.get(cacheKey);
469
- }
470
- const result = calculateElevationSurface(baseColor, level);
471
- if (elevationSurfaceCache.size >= MAX_CACHE_SIZE) {
472
- const firstKey = elevationSurfaceCache.keys().next().value;
473
- elevationSurfaceCache.delete(firstKey);
474
- }
475
- elevationSurfaceCache.set(cacheKey, result);
476
- return result;
477
- }
478
- var elevationShadowCache = /* @__PURE__ */ new Map();
479
- var MAX_SHADOW_CACHE_SIZE = 50;
480
- function getShadowCacheKey(baseColor, level, theme, isHovered) {
481
- return `${baseColor}-${level}-${theme}-${isHovered}`;
482
- }
483
- function calculateElevationShadow(baseColor, level, theme, isHovered = false) {
484
- const config = elevationSystem[level];
485
- if (level === 0) {
486
- return {};
487
- }
488
- const elevatedSurfaceColor = calculateElevationSurface(baseColor, level);
489
- const rimLightColor = calculateRimLightColor(baseColor, level);
490
- const darkShadowColors = calculateDarkShadowColors(elevatedSurfaceColor);
491
- const intensityConfig2 = {
492
- subtle: { offset: 1, blur: 2 },
493
- medium: { offset: 2, blur: 4 },
494
- strong: { offset: 2, blur: 5 }
495
- };
496
- const { offset, blur } = intensityConfig2[config.shadowIntensity];
497
- const rimConfig = getRimLightConfig();
498
- if (config.shadowStyle === "pressed") {
499
- if (isHovered) {
500
- const hoverOffset = Math.max(1, Math.round(offset / 2));
501
- const hoverBlur = Math.max(1, Math.round(blur / 2));
502
- return Platform.select({
503
- web: {
504
- boxShadow: `inset ${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
505
- },
506
- default: {
507
- shadowOpacity: 0,
508
- elevation: 0
509
- }
510
- });
511
- }
512
- return Platform.select({
513
- web: {
514
- boxShadow: `inset ${offset}px ${offset}px ${blur}px ${darkShadowColors.darker}, inset -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
515
- },
516
- default: {
517
- shadowOpacity: 0,
518
- elevation: 0
519
- }
520
- });
521
- } else {
522
- if (isHovered) {
523
- const hoverOffset = Math.max(1, Math.round(offset / 2));
524
- const hoverBlur = Math.max(1, Math.round(blur / 2));
525
- return Platform.select({
526
- web: {
527
- boxShadow: `${hoverOffset}px ${hoverOffset}px ${hoverBlur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
528
- },
529
- default: {
530
- shadowColor: "#000",
531
- shadowOffset: { width: hoverOffset, height: hoverOffset },
532
- shadowOpacity: 0.2,
533
- shadowRadius: hoverBlur / 2,
534
- elevation: hoverOffset
535
- }
536
- });
537
- }
538
- return Platform.select({
539
- web: {
540
- boxShadow: `${offset}px ${offset}px ${blur}px ${darkShadowColors.dark}, -${rimConfig.offset}px -${rimConfig.offset}px ${rimConfig.blur}px ${rimLightColor}`
541
- },
542
- default: {
543
- shadowColor: "#000",
544
- shadowOffset: { width: offset, height: offset },
545
- shadowOpacity: 0.3,
546
- shadowRadius: blur / 2,
547
- elevation: offset
548
- }
549
- });
550
- }
551
- }
552
- function getElevationShadow(baseColor, level, theme, isHovered = false) {
553
- const cacheKey = getShadowCacheKey(baseColor, level, theme, isHovered);
554
- if (elevationShadowCache.has(cacheKey)) {
555
- return elevationShadowCache.get(cacheKey);
556
- }
557
- const result = calculateElevationShadow(baseColor, level, theme, isHovered);
558
- if (elevationShadowCache.size >= MAX_SHADOW_CACHE_SIZE) {
559
- const firstKey = elevationShadowCache.keys().next().value;
560
- elevationShadowCache.delete(firstKey);
561
- }
562
- elevationShadowCache.set(cacheKey, result);
563
- return result;
564
- }
565
- function getBaseSurfaceColor(theme) {
566
- return theme === "light" ? semanticColorsLight["surface-raised"] : semanticColorsDark["surface-elevated"];
567
- }
568
- var componentElevationRanges = {
569
- button: {
570
- allowed: [2],
571
- default: 2,
572
- hover: 3
573
- },
574
- card: {
575
- allowed: [1, 2, 3],
576
- default: 2,
577
- hover: 3
578
- },
579
- input: {
580
- allowed: [-2, -1, 0],
581
- default: -1
582
- },
583
- overlay: {
584
- allowed: [4, 5],
585
- default: 4
586
- }
587
- };
588
- function getValidatedElevation(component, requested) {
589
- const range = componentElevationRanges[component];
590
- if (range.allowed.includes(requested)) {
591
- return requested;
592
- }
593
- const sorted = [...range.allowed].sort((a, b) => a - b);
594
- if (requested < sorted[0]) return sorted[0];
595
- if (requested > sorted[sorted.length - 1]) return sorted[sorted.length - 1];
596
- return sorted.reduce(
597
- (prev, curr) => Math.abs(curr - requested) < Math.abs(prev - requested) ? curr : prev
598
- );
599
- }
600
- var glowConfig = {
601
- subtle: { blur: 12, spread: 0, opacity: 0.25 },
602
- medium: { blur: 20, spread: 2, opacity: 0.4 },
603
- strong: { blur: 30, spread: 4, opacity: 0.55 }
604
- };
605
- function getGlowShadow(color, intensity = "medium") {
606
- const config = glowConfig[intensity];
607
- const rgb = hexToRgb(color);
608
- if (!rgb) return {};
609
- return Platform.select({
610
- web: {
611
- boxShadow: `0 0 ${config.blur}px ${config.spread}px rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${config.opacity})`
612
- },
613
- default: {
614
- shadowColor: color,
615
- shadowOffset: { width: 0, height: 0 },
616
- shadowOpacity: config.opacity,
617
- shadowRadius: config.blur / 2,
618
- elevation: 0
619
- }
620
- });
621
- }
622
-
623
- // src/theme/manifest/css-property-manifest.validate.ts
624
- var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
625
- var isVariantAxes = (value) => isPlainObject(value) && Object.keys(value).length > 0 && Object.values(value).every((axisValue) => typeof axisValue === "string");
626
- function collectVariantOverrideErrors(override, path) {
627
- if (!isPlainObject(override)) return [`${path} must be an object`];
628
- const errors = [];
629
- if (!isVariantAxes(override.variant))
630
- errors.push(`${path}.variant must be a non-empty string-keyed object`);
631
- if (override.token !== void 0 && override.token !== null && typeof override.token !== "string") {
632
- errors.push(`${path}.token must be a string or null`);
633
- }
634
- if (typeof override.resolvedValue !== "string" || override.resolvedValue.length === 0) {
635
- errors.push(`${path}.resolvedValue must be a non-empty string`);
636
- }
637
- return errors;
638
- }
639
- function collectPropertyErrors(entry, path) {
640
- if (!isPlainObject(entry)) return [`${path} must be an object`];
641
- const errors = [];
642
- if (typeof entry.property !== "string" || entry.property.length === 0) {
643
- errors.push(`${path}.property must be a non-empty string`);
644
- }
645
- if (entry.token !== null && typeof entry.token !== "string") {
646
- errors.push(`${path}.token must be a string or null`);
647
- }
648
- if (typeof entry.resolvedValue !== "string" || entry.resolvedValue.length === 0) {
649
- errors.push(`${path}.resolvedValue must be a non-empty string`);
650
- }
651
- if (entry.variantOverrides !== void 0) {
652
- if (!Array.isArray(entry.variantOverrides)) {
653
- errors.push(`${path}.variantOverrides must be an array`);
654
- } else {
655
- entry.variantOverrides.forEach(
656
- (override, i) => errors.push(...collectVariantOverrideErrors(override, `${path}.variantOverrides[${i}]`))
657
- );
658
- }
659
- }
660
- return errors;
661
- }
662
- function validateCssPropertyManifest(candidate) {
663
- if (!isPlainObject(candidate)) return { valid: false, errors: ["manifest must be an object"] };
664
- const errors = [];
665
- if (typeof candidate.component !== "string" || candidate.component.length === 0) {
666
- errors.push("component must be a non-empty string");
667
- }
668
- if (candidate.baseVariant !== void 0 && !isVariantAxes(candidate.baseVariant)) {
669
- errors.push("baseVariant must be a non-empty string-keyed object");
670
- }
671
- if (!Array.isArray(candidate.properties) || candidate.properties.length === 0) {
672
- errors.push("properties must be a non-empty array");
673
- } else {
674
- candidate.properties.forEach(
675
- (entry, i) => errors.push(...collectPropertyErrors(entry, `properties[${i}]`))
676
- );
677
- }
678
- return { valid: errors.length === 0, errors };
679
- }
680
- function isCssPropertyManifest(candidate) {
681
- return validateCssPropertyManifest(candidate).valid;
682
- }
683
- function wrapJsx(fn) {
684
- return function(type, props, ...rest) {
685
- if (props && typeof props.className === "string" && props.className) {
686
- const cn = props.className;
687
- const cssStyle = { $$css: true, [cn]: cn };
688
- const existing = props.style;
689
- props = {
690
- ...props,
691
- style: existing ? [cssStyle, existing] : cssStyle
692
- };
693
- delete props.className;
694
- }
695
- return fn(type, props, ...rest);
696
- };
697
- }
698
- var jsx = wrapJsx(jsx$1);
699
- var jsxs = wrapJsx(jsxs$1);
700
-
701
- // src/theme/ThemeProvider.tsx
702
- var MODE_VARS = {
703
- dark: vars(darkThemeCSSVars),
704
- light: vars(lightThemeCSSVars)
705
- };
706
- function ThemeProvider({
707
- mode = "dark",
708
- style,
709
- children,
710
- ...props
711
- }) {
712
- return /* @__PURE__ */ jsx(View, { style: [MODE_VARS[mode], { flex: 1 }, style], ...props, children });
713
- }
714
- function resolveColor(token, mode = "dark") {
715
- return Platform.OS === "web" ? `var(--color-${token})` : getSemanticColors(mode)[token];
716
- }
717
-
718
- // src/theme/presets/apply.ts
719
- function colorKeyToVar(key) {
720
- return `--color-${key}`;
721
- }
722
- function applyColorOverrides(colors, root) {
723
- for (const [key, value] of Object.entries(colors)) {
724
- if (value !== void 0) {
725
- root.style.setProperty(colorKeyToVar(key), value);
726
- }
727
- }
728
- }
729
- function applyFontOverrides(fonts, root) {
730
- const fontVarMap = {
731
- sans: "--font-family-sans",
732
- body: "--font-family-body",
733
- heading: "--font-family-heading",
734
- mono: "--font-family-mono"
735
- };
736
- for (const [key, value] of Object.entries(fonts)) {
737
- if (value !== void 0 && fontVarMap[key]) {
738
- root.style.setProperty(fontVarMap[key], value);
739
- }
740
- }
741
- }
742
- function injectFontImport(url) {
743
- if (typeof document === "undefined") return;
744
- const existing = document.querySelector(`link[href="${url}"]`);
745
- if (existing) return;
746
- const link = document.createElement("link");
747
- link.rel = "stylesheet";
748
- link.href = url;
749
- document.head.appendChild(link);
750
- }
751
- function applyThemePreset(preset) {
752
- if (typeof document === "undefined") {
753
- return () => {
754
- };
755
- }
756
- const root = document.documentElement;
757
- const removals = [];
758
- if (preset.fontImport) {
759
- injectFontImport(preset.fontImport);
760
- }
761
- const isLight = root.classList.contains("light");
762
- const modeColors = isLight ? preset.colors?.light : preset.colors?.dark;
763
- if (modeColors) {
764
- const previousValues = {};
765
- for (const key of Object.keys(modeColors)) {
766
- previousValues[colorKeyToVar(key)] = root.style.getPropertyValue(colorKeyToVar(key)) || null;
767
- }
768
- applyColorOverrides(modeColors, root);
769
- removals.push(() => {
770
- for (const [varName, prev] of Object.entries(previousValues)) {
771
- if (prev === null) {
772
- root.style.removeProperty(varName);
773
- } else {
774
- root.style.setProperty(varName, prev);
775
- }
776
- }
777
- });
778
- }
779
- if (preset.fonts) {
780
- applyFontOverrides(preset.fonts, root);
781
- }
782
- if (preset.rootClasses) {
783
- for (const cls of preset.rootClasses) {
784
- root.classList.add(cls);
785
- }
786
- removals.push(() => {
787
- for (const cls of preset.rootClasses) {
788
- root.classList.remove(cls);
789
- }
790
- });
791
- }
792
- return () => {
793
- for (const remove of removals) {
794
- remove();
795
- }
796
- };
797
- }
798
-
799
- // src/theme/presets/default.ts
800
- var defaultPreset = {
801
- name: "default",
802
- description: "Titan Design System default theme \u2014 orange accent, steel secondary"
803
- };
804
-
805
- // src/theme/presets/audiobook.ts
806
- var audiobookPreset = {
807
- name: "audiobook",
808
- description: "Warm copper/patina theme with editorial typography",
809
- fontImport: "https://fonts.googleapis.com/css2?family=Newsreader:ital,wght@0,400;0,600;0,700;1,400&family=Outfit:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap",
810
- fonts: {
811
- sans: "'Outfit', 'Avenir', 'Avenir Next', system-ui, sans-serif",
812
- body: "'Outfit', 'Avenir', 'Avenir Next', system-ui, sans-serif",
813
- heading: "'Newsreader', 'Libre Baskerville', Georgia, serif",
814
- mono: "'JetBrains Mono', 'SF Mono', 'Fira Code', monospace"
815
- },
816
- colors: {
817
- dark: {
818
- // Brand: Copper accent
819
- "brand-primary": "#d4782a",
820
- "brand-primary-light": "#e8944a",
821
- "brand-primary-dark": "#9a4a15",
822
- "brand-primary-subtle": "rgba(212, 120, 42, 0.12)",
823
- "brand-primary-hover": "#e8944a",
824
- "brand-primary-active": "#f5b070",
825
- // Brand secondary: Patina/verdigris
826
- "brand-secondary": "#3a9b8a",
827
- "brand-secondary-light": "#55baa7",
828
- "brand-secondary-dark": "#1f5c52",
829
- "brand-secondary-subtle": "rgba(58, 155, 138, 0.12)",
830
- "brand-secondary-hover": "#55baa7",
831
- "brand-secondary-active": "#7ed4c4",
832
- "on-brand-primary": "#FFFFFF",
833
- "on-brand-secondary": "#FFFFFF",
834
- // Status colors (audiobook's warmer status palette)
835
- "status-success": "#5fb870",
836
- "status-error": "#d85c4a",
837
- "status-warning": "#d4a43a",
838
- "status-info": "#5a8fd4",
839
- // Text: warm off-whites
840
- "text-primary": "#f4f3f1",
841
- "text-secondary": "#b5b3af",
842
- "text-tertiary": "#7a7875",
843
- // Surfaces: warm charcoals (not pure gray)
844
- "surface-base": "#101114",
845
- "surface-elevated": "#15171c",
846
- "surface-raised": "#1a1d24",
847
- "surface-overlay": "#15171c",
848
- "surface-input": "#15171c",
849
- // Backgrounds
850
- "background-base": "#0a0b0d",
851
- "background-default": "#101114",
852
- "background-subtle": "#1a1d24",
853
- // Borders
854
- "border-default": "rgba(255, 255, 255, 0.06)",
855
- "border-subtle": "rgba(255, 255, 255, 0.03)",
856
- "border-strong": "#2d323d",
857
- "border-focus": "#d4782a",
858
- "border-input": "#2d323d",
859
- "border-input-hover": "#454c5c",
860
- "border-input-focus": "#d4782a",
861
- "border-input-error": "#d85c4a",
862
- // Interactive
863
- "interactive-hover": "rgba(255, 255, 255, 0.04)",
864
- "interactive-focus": "rgba(255, 255, 255, 0.12)",
865
- "interactive-active": "rgba(255, 255, 255, 0.16)",
866
- "interactive-selected": "rgba(255, 255, 255, 0.08)",
867
- "divider": "rgba(255, 255, 255, 0.06)",
868
- // Glow RGB values for shadow utilities
869
- "brand-primary-rgb": "212, 120, 42",
870
- "brand-secondary-rgb": "58, 155, 138",
871
- "status-success-rgb": "95, 184, 112",
872
- "status-error-rgb": "216, 92, 74",
873
- "status-warning-rgb": "212, 164, 58",
874
- "status-info-rgb": "90, 143, 212",
875
- "background-base-rgb": "10, 11, 13"
876
- }
877
- },
878
- rootClasses: ["atmosphere-warm", "grain"]
879
- };
880
-
881
- export { ThemeProvider, applyThemePreset, audiobookPreset, componentElevationRanges, createFlatShadow, createPressedHoverShadow, createPressedShadow, createRaisedHoverShadow, createRaisedShadow, darken, defaultPreset, elevationSystem, getBaseSurfaceColor, getElevationConfig, getElevationShadow, getElevationSurface, getGlowShadow, getHoverColors, getValidatedElevation, hexToRgb, hsvToRgb, isCssPropertyManifest, isDark, jsx, jsxs, lighten, neumorphicShadows, resolveColor, rgbToHex, rgbToHsv, shadowColors, validateCssPropertyManifest };
882
- //# sourceMappingURL=chunk-SNVKL5WZ.mjs.map
883
- //# sourceMappingURL=chunk-SNVKL5WZ.mjs.map