orn-ui 0.1.1 → 0.2.1

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 (240) hide show
  1. package/README.md +20 -2
  2. package/lib/commonjs/atoms/PressableScale.js +9 -10
  3. package/lib/commonjs/atoms/PressableScale.js.map +1 -1
  4. package/lib/commonjs/atoms/Skeleton.js +96 -0
  5. package/lib/commonjs/atoms/Skeleton.js.map +1 -0
  6. package/lib/commonjs/atoms/Transition.js +171 -0
  7. package/lib/commonjs/atoms/Transition.js.map +1 -0
  8. package/lib/commonjs/atoms/index.js +20 -0
  9. package/lib/commonjs/atoms/index.js.map +1 -1
  10. package/lib/commonjs/molecules/OptionCard.js +55 -22
  11. package/lib/commonjs/molecules/OptionCard.js.map +1 -1
  12. package/lib/commonjs/molecules/{ThemeToggle.js → SegmentedControl.js} +36 -36
  13. package/lib/commonjs/molecules/SegmentedControl.js.map +1 -0
  14. package/lib/commonjs/molecules/Stepper.js +124 -47
  15. package/lib/commonjs/molecules/Stepper.js.map +1 -1
  16. package/lib/commonjs/molecules/Steps.js +36 -6
  17. package/lib/commonjs/molecules/Steps.js.map +1 -1
  18. package/lib/commonjs/molecules/index.js +9 -3
  19. package/lib/commonjs/molecules/index.js.map +1 -1
  20. package/lib/commonjs/organisms/AlertProvider.js +26 -0
  21. package/lib/commonjs/organisms/AlertProvider.js.map +1 -1
  22. package/lib/commonjs/organisms/BottomSheet.js +118 -39
  23. package/lib/commonjs/organisms/BottomSheet.js.map +1 -1
  24. package/lib/commonjs/organisms/DateField.js +46 -15
  25. package/lib/commonjs/organisms/DateField.js.map +1 -1
  26. package/lib/commonjs/organisms/DatePicker.js +129 -50
  27. package/lib/commonjs/organisms/DatePicker.js.map +1 -1
  28. package/lib/commonjs/organisms/List.js +66 -44
  29. package/lib/commonjs/organisms/List.js.map +1 -1
  30. package/lib/commonjs/organisms/Modal.js +42 -87
  31. package/lib/commonjs/organisms/Modal.js.map +1 -1
  32. package/lib/commonjs/organisms/NavigationBar.js +210 -0
  33. package/lib/commonjs/organisms/NavigationBar.js.map +1 -0
  34. package/lib/commonjs/organisms/Screen.js +9 -2
  35. package/lib/commonjs/organisms/Screen.js.map +1 -1
  36. package/lib/commonjs/organisms/SearchList.js +95 -27
  37. package/lib/commonjs/organisms/SearchList.js.map +1 -1
  38. package/lib/commonjs/organisms/Select.js +222 -50
  39. package/lib/commonjs/organisms/Select.js.map +1 -1
  40. package/lib/commonjs/organisms/ThemeToggle.js +52 -0
  41. package/lib/commonjs/organisms/ThemeToggle.js.map +1 -0
  42. package/lib/commonjs/organisms/Toast.js +8 -22
  43. package/lib/commonjs/organisms/Toast.js.map +1 -1
  44. package/lib/commonjs/organisms/ToastProvider.js +24 -0
  45. package/lib/commonjs/organisms/ToastProvider.js.map +1 -1
  46. package/lib/commonjs/organisms/Wizard.js +23 -2
  47. package/lib/commonjs/organisms/Wizard.js.map +1 -1
  48. package/lib/commonjs/organisms/imperativeBridge.js +28 -0
  49. package/lib/commonjs/organisms/imperativeBridge.js.map +1 -0
  50. package/lib/commonjs/organisms/index.js +50 -0
  51. package/lib/commonjs/organisms/index.js.map +1 -1
  52. package/lib/commonjs/theme/colors.js +207 -0
  53. package/lib/commonjs/theme/colors.js.map +1 -0
  54. package/lib/commonjs/theme/createTheme.js +25 -2
  55. package/lib/commonjs/theme/createTheme.js.map +1 -1
  56. package/lib/commonjs/theme/index.js +25 -0
  57. package/lib/commonjs/theme/index.js.map +1 -1
  58. package/lib/commonjs/theme/labels.js +5 -1
  59. package/lib/commonjs/theme/labels.js.map +1 -1
  60. package/lib/commonjs/theme/palettes.js +5 -2
  61. package/lib/commonjs/theme/palettes.js.map +1 -1
  62. package/lib/module/atoms/PressableScale.js +9 -10
  63. package/lib/module/atoms/PressableScale.js.map +1 -1
  64. package/lib/module/atoms/Skeleton.js +91 -0
  65. package/lib/module/atoms/Skeleton.js.map +1 -0
  66. package/lib/module/atoms/Transition.js +165 -0
  67. package/lib/module/atoms/Transition.js.map +1 -0
  68. package/lib/module/atoms/index.js +2 -0
  69. package/lib/module/atoms/index.js.map +1 -1
  70. package/lib/module/molecules/OptionCard.js +56 -23
  71. package/lib/module/molecules/OptionCard.js.map +1 -1
  72. package/lib/module/molecules/{ThemeToggle.js → SegmentedControl.js} +36 -36
  73. package/lib/module/molecules/SegmentedControl.js.map +1 -0
  74. package/lib/module/molecules/Stepper.js +125 -49
  75. package/lib/module/molecules/Stepper.js.map +1 -1
  76. package/lib/module/molecules/Steps.js +37 -7
  77. package/lib/module/molecules/Steps.js.map +1 -1
  78. package/lib/module/molecules/index.js +2 -2
  79. package/lib/module/molecules/index.js.map +1 -1
  80. package/lib/module/organisms/AlertProvider.js +24 -1
  81. package/lib/module/organisms/AlertProvider.js.map +1 -1
  82. package/lib/module/organisms/BottomSheet.js +120 -41
  83. package/lib/module/organisms/BottomSheet.js.map +1 -1
  84. package/lib/module/organisms/DateField.js +49 -18
  85. package/lib/module/organisms/DateField.js.map +1 -1
  86. package/lib/module/organisms/DatePicker.js +131 -52
  87. package/lib/module/organisms/DatePicker.js.map +1 -1
  88. package/lib/module/organisms/List.js +68 -46
  89. package/lib/module/organisms/List.js.map +1 -1
  90. package/lib/module/organisms/Modal.js +44 -89
  91. package/lib/module/organisms/Modal.js.map +1 -1
  92. package/lib/module/organisms/NavigationBar.js +205 -0
  93. package/lib/module/organisms/NavigationBar.js.map +1 -0
  94. package/lib/module/organisms/Screen.js +9 -2
  95. package/lib/module/organisms/Screen.js.map +1 -1
  96. package/lib/module/organisms/SearchList.js +96 -28
  97. package/lib/module/organisms/SearchList.js.map +1 -1
  98. package/lib/module/organisms/Select.js +224 -52
  99. package/lib/module/organisms/Select.js.map +1 -1
  100. package/lib/module/organisms/ThemeToggle.js +47 -0
  101. package/lib/module/organisms/ThemeToggle.js.map +1 -0
  102. package/lib/module/organisms/Toast.js +10 -24
  103. package/lib/module/organisms/Toast.js.map +1 -1
  104. package/lib/module/organisms/ToastProvider.js +21 -0
  105. package/lib/module/organisms/ToastProvider.js.map +1 -1
  106. package/lib/module/organisms/Wizard.js +24 -3
  107. package/lib/module/organisms/Wizard.js.map +1 -1
  108. package/lib/module/organisms/imperativeBridge.js +24 -0
  109. package/lib/module/organisms/imperativeBridge.js.map +1 -0
  110. package/lib/module/organisms/index.js +4 -2
  111. package/lib/module/organisms/index.js.map +1 -1
  112. package/lib/module/theme/colors.js +194 -0
  113. package/lib/module/theme/colors.js.map +1 -0
  114. package/lib/module/theme/createTheme.js +25 -2
  115. package/lib/module/theme/createTheme.js.map +1 -1
  116. package/lib/module/theme/index.js +1 -0
  117. package/lib/module/theme/index.js.map +1 -1
  118. package/lib/module/theme/labels.js +5 -1
  119. package/lib/module/theme/labels.js.map +1 -1
  120. package/lib/module/theme/palettes.js +5 -2
  121. package/lib/module/theme/palettes.js.map +1 -1
  122. package/lib/typescript/atoms/PressableScale.d.ts +3 -2
  123. package/lib/typescript/atoms/PressableScale.d.ts.map +1 -1
  124. package/lib/typescript/atoms/Skeleton.d.ts +29 -0
  125. package/lib/typescript/atoms/Skeleton.d.ts.map +1 -0
  126. package/lib/typescript/atoms/Transition.d.ts +51 -0
  127. package/lib/typescript/atoms/Transition.d.ts.map +1 -0
  128. package/lib/typescript/atoms/index.d.ts +4 -0
  129. package/lib/typescript/atoms/index.d.ts.map +1 -1
  130. package/lib/typescript/molecules/OptionCard.d.ts +11 -6
  131. package/lib/typescript/molecules/OptionCard.d.ts.map +1 -1
  132. package/lib/typescript/molecules/SegmentedControl.d.ts +24 -0
  133. package/lib/typescript/molecules/SegmentedControl.d.ts.map +1 -0
  134. package/lib/typescript/molecules/Stepper.d.ts +35 -3
  135. package/lib/typescript/molecules/Stepper.d.ts.map +1 -1
  136. package/lib/typescript/molecules/Steps.d.ts.map +1 -1
  137. package/lib/typescript/molecules/index.d.ts +4 -4
  138. package/lib/typescript/molecules/index.d.ts.map +1 -1
  139. package/lib/typescript/organisms/AlertProvider.d.ts +9 -0
  140. package/lib/typescript/organisms/AlertProvider.d.ts.map +1 -1
  141. package/lib/typescript/organisms/BottomSheet.d.ts +26 -4
  142. package/lib/typescript/organisms/BottomSheet.d.ts.map +1 -1
  143. package/lib/typescript/organisms/DateField.d.ts +23 -5
  144. package/lib/typescript/organisms/DateField.d.ts.map +1 -1
  145. package/lib/typescript/organisms/DatePicker.d.ts +5 -1
  146. package/lib/typescript/organisms/DatePicker.d.ts.map +1 -1
  147. package/lib/typescript/organisms/List.d.ts +9 -2
  148. package/lib/typescript/organisms/List.d.ts.map +1 -1
  149. package/lib/typescript/organisms/Modal.d.ts +3 -5
  150. package/lib/typescript/organisms/Modal.d.ts.map +1 -1
  151. package/lib/typescript/organisms/NavigationBar.d.ts +32 -0
  152. package/lib/typescript/organisms/NavigationBar.d.ts.map +1 -0
  153. package/lib/typescript/organisms/Screen.d.ts +2 -1
  154. package/lib/typescript/organisms/Screen.d.ts.map +1 -1
  155. package/lib/typescript/organisms/SearchList.d.ts +21 -5
  156. package/lib/typescript/organisms/SearchList.d.ts.map +1 -1
  157. package/lib/typescript/organisms/Select.d.ts +19 -4
  158. package/lib/typescript/organisms/Select.d.ts.map +1 -1
  159. package/lib/typescript/{molecules → organisms}/ThemeToggle.d.ts +4 -4
  160. package/lib/typescript/organisms/ThemeToggle.d.ts.map +1 -0
  161. package/lib/typescript/organisms/Toast.d.ts.map +1 -1
  162. package/lib/typescript/organisms/ToastProvider.d.ts +8 -0
  163. package/lib/typescript/organisms/ToastProvider.d.ts.map +1 -1
  164. package/lib/typescript/organisms/Wizard.d.ts +7 -1
  165. package/lib/typescript/organisms/Wizard.d.ts.map +1 -1
  166. package/lib/typescript/organisms/imperativeBridge.d.ts +12 -0
  167. package/lib/typescript/organisms/imperativeBridge.d.ts.map +1 -0
  168. package/lib/typescript/organisms/index.d.ts +7 -3
  169. package/lib/typescript/organisms/index.d.ts.map +1 -1
  170. package/lib/typescript/theme/colors.d.ts +44 -0
  171. package/lib/typescript/theme/colors.d.ts.map +1 -0
  172. package/lib/typescript/theme/createTheme.d.ts +3 -0
  173. package/lib/typescript/theme/createTheme.d.ts.map +1 -1
  174. package/lib/typescript/theme/index.d.ts +3 -1
  175. package/lib/typescript/theme/index.d.ts.map +1 -1
  176. package/lib/typescript/theme/labels.d.ts +6 -0
  177. package/lib/typescript/theme/labels.d.ts.map +1 -1
  178. package/lib/typescript/theme/palettes.d.ts.map +1 -1
  179. package/lib/typescript/theme/types.d.ts +9 -0
  180. package/lib/typescript/theme/types.d.ts.map +1 -1
  181. package/package.json +67 -6
  182. package/registry/alert-provider.json +9 -2
  183. package/registry/bottom-sheet.json +6 -2
  184. package/registry/core.json +9 -5
  185. package/registry/date-field.json +2 -1
  186. package/registry/date-picker.json +1 -1
  187. package/registry/index.json +99 -30
  188. package/registry/list.json +2 -1
  189. package/registry/manifest.json +44 -6
  190. package/registry/modal.json +3 -2
  191. package/registry/navigation-bar.json +18 -0
  192. package/registry/option-card.json +3 -2
  193. package/registry/pressable-scale.json +1 -1
  194. package/registry/screen.json +1 -1
  195. package/registry/search-list.json +2 -1
  196. package/registry/segmented-control.json +18 -0
  197. package/registry/select.json +1 -1
  198. package/registry/skeleton.json +18 -0
  199. package/registry/stepper.json +3 -2
  200. package/registry/steps.json +1 -1
  201. package/registry/theme-toggle.json +5 -4
  202. package/registry/toast-provider.json +11 -3
  203. package/registry/toast.json +3 -2
  204. package/registry/transition.json +19 -0
  205. package/registry/wizard.json +3 -2
  206. package/src/atoms/PressableScale.tsx +16 -6
  207. package/src/atoms/Skeleton.tsx +114 -0
  208. package/src/atoms/Transition.tsx +189 -0
  209. package/src/atoms/index.ts +4 -0
  210. package/src/molecules/OptionCard.tsx +62 -25
  211. package/src/molecules/SegmentedControl.tsx +84 -0
  212. package/src/molecules/Stepper.tsx +147 -32
  213. package/src/molecules/Steps.tsx +27 -8
  214. package/src/molecules/index.ts +4 -4
  215. package/src/organisms/AlertProvider.tsx +26 -1
  216. package/src/organisms/BottomSheet.tsx +214 -62
  217. package/src/organisms/DateField.tsx +79 -19
  218. package/src/organisms/DatePicker.tsx +198 -80
  219. package/src/organisms/List.tsx +73 -41
  220. package/src/organisms/Modal.tsx +49 -61
  221. package/src/organisms/NavigationBar.tsx +226 -0
  222. package/src/organisms/Screen.tsx +11 -3
  223. package/src/organisms/SearchList.tsx +131 -35
  224. package/src/organisms/Select.tsx +223 -45
  225. package/src/organisms/ThemeToggle.tsx +30 -0
  226. package/src/organisms/Toast.tsx +8 -21
  227. package/src/organisms/ToastProvider.tsx +24 -0
  228. package/src/organisms/Wizard.tsx +37 -3
  229. package/src/organisms/imperativeBridge.ts +28 -0
  230. package/src/organisms/index.ts +7 -3
  231. package/src/theme/colors.ts +175 -0
  232. package/src/theme/createTheme.ts +38 -4
  233. package/src/theme/index.ts +3 -1
  234. package/src/theme/labels.ts +13 -0
  235. package/src/theme/palettes.ts +5 -2
  236. package/src/theme/types.ts +10 -0
  237. package/lib/commonjs/molecules/ThemeToggle.js.map +0 -1
  238. package/lib/module/molecules/ThemeToggle.js.map +0 -1
  239. package/lib/typescript/molecules/ThemeToggle.d.ts.map +0 -1
  240. package/src/molecules/ThemeToggle.tsx +0 -67
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Utilidades de color sin dependencias, usadas para derivar una familia de
3
+ * roles (relleno / encima / tenue / legible) a partir de un solo hex de marca.
4
+ */
5
+
6
+ /** Contraste mínimo AA para texto normal. */
7
+ export const AA_CONTRAST = 4.5;
8
+
9
+ export interface Rgb {
10
+ r: number;
11
+ g: number;
12
+ b: number;
13
+ }
14
+
15
+ export interface Hsl {
16
+ h: number;
17
+ s: number;
18
+ l: number;
19
+ }
20
+
21
+ /** Roles que necesita un acento del theme, en un esquema concreto. */
22
+ export interface AccentRoles {
23
+ /** Relleno pleno: fondo de botón, círculo del paso actual. */
24
+ base: string;
25
+ /** Texto/ícono que va encima del relleno. */
26
+ on: string;
27
+ /** Fondo tenue: badges, pill del indicador activo. */
28
+ soft: string;
29
+ /** El acento legible sobre `surface`: labels, links. */
30
+ text: string;
31
+ }
32
+
33
+ const HEX = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i;
34
+
35
+ export function hexToRgb(hex: string): Rgb {
36
+ const match = HEX.exec(hex.trim());
37
+ if (!match) {
38
+ throw new Error(`orn-ui: se esperaba un color hex como "#7c3aed", se recibió "${hex}".`);
39
+ }
40
+ const digits = match[1]!;
41
+ const full = digits.length === 3 ? digits.replace(/./g, (c) => c + c) : digits;
42
+ return {
43
+ r: parseInt(full.slice(0, 2), 16),
44
+ g: parseInt(full.slice(2, 4), 16),
45
+ b: parseInt(full.slice(4, 6), 16),
46
+ };
47
+ }
48
+
49
+ const toHexPair = (value: number) => Math.round(clamp(value, 0, 255)).toString(16).padStart(2, '0');
50
+
51
+ export function rgbToHex({ r, g, b }: Rgb): string {
52
+ return `#${toHexPair(r)}${toHexPair(g)}${toHexPair(b)}`;
53
+ }
54
+
55
+ function clamp(value: number, min: number, max: number) {
56
+ return Math.min(max, Math.max(min, value));
57
+ }
58
+
59
+ export function rgbToHsl({ r, g, b }: Rgb): Hsl {
60
+ const rn = r / 255;
61
+ const gn = g / 255;
62
+ const bn = b / 255;
63
+ const max = Math.max(rn, gn, bn);
64
+ const min = Math.min(rn, gn, bn);
65
+ const delta = max - min;
66
+ const l = (max + min) / 2;
67
+
68
+ if (delta === 0) return { h: 0, s: 0, l };
69
+
70
+ const s = delta / (1 - Math.abs(2 * l - 1));
71
+ let h: number;
72
+ if (max === rn) h = ((gn - bn) / delta) % 6;
73
+ else if (max === gn) h = (bn - rn) / delta + 2;
74
+ else h = (rn - gn) / delta + 4;
75
+
76
+ h *= 60;
77
+ return { h: h < 0 ? h + 360 : h, s, l };
78
+ }
79
+
80
+ export function hslToRgb({ h, s, l }: Hsl): Rgb {
81
+ const c = (1 - Math.abs(2 * l - 1)) * s;
82
+ const hp = (((h % 360) + 360) % 360) / 60;
83
+ const x = c * (1 - Math.abs((hp % 2) - 1));
84
+ const [r1, g1, b1] =
85
+ hp < 1 ? [c, x, 0] : hp < 2 ? [x, c, 0] : hp < 3 ? [0, c, x] : hp < 4 ? [0, x, c] : hp < 5 ? [x, 0, c] : [c, 0, x];
86
+ const m = l - c / 2;
87
+ return { r: (r1 + m) * 255, g: (g1 + m) * 255, b: (b1 + m) * 255 };
88
+ }
89
+
90
+ export function toHsl(hex: string): Hsl {
91
+ return rgbToHsl(hexToRgb(hex));
92
+ }
93
+
94
+ export function toHex(hsl: Hsl): string {
95
+ return rgbToHex(hslToRgb({ ...hsl, s: clamp(hsl.s, 0, 1), l: clamp(hsl.l, 0, 1) }));
96
+ }
97
+
98
+ function channelLuminance(value: number) {
99
+ const c = value / 255;
100
+ return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
101
+ }
102
+
103
+ /** Luminancia relativa WCAG de un hex. */
104
+ export function luminance(hex: string): number {
105
+ const { r, g, b } = hexToRgb(hex);
106
+ return 0.2126 * channelLuminance(r) + 0.7152 * channelLuminance(g) + 0.0722 * channelLuminance(b);
107
+ }
108
+
109
+ /** Ratio de contraste WCAG entre dos hex: 1 (igual) a 21 (blanco sobre negro). */
110
+ export function contrast(a: string, b: string): number {
111
+ const la = luminance(a);
112
+ const lb = luminance(b);
113
+ return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);
114
+ }
115
+
116
+ /**
117
+ * Blanco si alcanza el contraste AA —es lo que se espera encima de un relleno
118
+ * de color— y si no, el extremo que más contraste dé.
119
+ */
120
+ function bestOnColor(background: string, light: string, dark: string): string {
121
+ if (contrast(background, light) >= AA_CONTRAST) return light;
122
+ return contrast(background, dark) >= contrast(background, light) ? dark : light;
123
+ }
124
+
125
+ /**
126
+ * Mueve la luminosidad del tono hasta alcanzar el contraste pedido contra
127
+ * `against`. Si ni el extremo llega —un amarillo puro sobre blanco, por
128
+ * ejemplo— devuelve el más contrastado que encontró en el camino.
129
+ */
130
+ function reachContrast(hsl: Hsl, against: string, target: number, direction: 'darker' | 'lighter'): string {
131
+ const step = direction === 'darker' ? -0.02 : 0.02;
132
+ let best = toHex(hsl);
133
+ let bestRatio = contrast(best, against);
134
+
135
+ for (let l = hsl.l; l >= 0 && l <= 1; l += step) {
136
+ const candidate = toHex({ ...hsl, l });
137
+ const ratio = contrast(candidate, against);
138
+ if (ratio > bestRatio) {
139
+ best = candidate;
140
+ bestRatio = ratio;
141
+ }
142
+ if (ratio >= target) return candidate;
143
+ }
144
+
145
+ return best;
146
+ }
147
+
148
+ /**
149
+ * Deriva los cuatro roles de un acento a partir de un hex, para un esquema.
150
+ * `surface` es el fondo sobre el que tiene que leerse el rol `text`, así que
151
+ * cada esquema pasa el suyo.
152
+ */
153
+ export function deriveAccent(hex: string, scheme: 'light' | 'dark', surface: string): AccentRoles {
154
+ const hsl = toHsl(hex);
155
+
156
+ if (scheme === 'light') {
157
+ const base = toHex(hsl);
158
+ return {
159
+ base,
160
+ on: bestOnColor(base, '#ffffff', '#1a1a1a'),
161
+ soft: toHex({ h: hsl.h, s: Math.min(hsl.s, 0.85), l: 0.94 }),
162
+ text: reachContrast({ ...hsl, l: Math.min(hsl.l, 0.38) }, surface, AA_CONTRAST, 'darker'),
163
+ };
164
+ }
165
+
166
+ // En oscuro el acento sube de luminosidad y lo que va encima baja: un
167
+ // #004cef sobre #1e1e1e no se distingue del fondo.
168
+ const base = toHex({ ...hsl, l: 0.72 });
169
+ return {
170
+ base,
171
+ on: bestOnColor(base, '#ffffff', toHex({ ...hsl, s: Math.min(hsl.s, 0.9), l: 0.16 })),
172
+ soft: toHex({ h: hsl.h, s: Math.min(hsl.s, 0.35), l: 0.18 }),
173
+ text: reachContrast({ ...hsl, l: Math.max(hsl.l, 0.74) }, surface, AA_CONTRAST, 'lighter'),
174
+ };
175
+ }
@@ -1,6 +1,7 @@
1
- import { lightPalette, darkPalette } from './palettes';
1
+ import { lightPalette, darkPalette, type ThemeColors } from './palettes';
2
2
  import { tokens as defaultTokens } from './tokens';
3
- import type { Theme, ThemeOverrides, ThemePair } from './types';
3
+ import { deriveAccent } from './colors';
4
+ import type { BrandAccent, Theme, ThemeOverrides, ThemePair } from './types';
4
5
 
5
6
  function mergeDeep<T extends Record<string, any>>(base: T, patch?: Partial<T>): T {
6
7
  if (!patch) return base;
@@ -23,22 +24,55 @@ function mergeDeep<T extends Record<string, any>>(base: T, patch?: Partial<T>):
23
24
  return out as T;
24
25
  }
25
26
 
27
+ const capitalize = <T extends string>(name: T) => (name.charAt(0).toUpperCase() + name.slice(1)) as Capitalize<T>;
28
+
29
+ /** Expande cada hex de `brand` a los cuatro roles del acento en un esquema. */
30
+ function brandColors(
31
+ brand: ThemeOverrides['brand'],
32
+ scheme: 'light' | 'dark',
33
+ palette: ThemeColors
34
+ ): Partial<ThemeColors> {
35
+ if (!brand) return {};
36
+ const accents = typeof brand === 'string' ? { primary: brand } : brand;
37
+ const out: Partial<ThemeColors> = {};
38
+
39
+ for (const [name, hex] of Object.entries(accents) as [BrandAccent, string | undefined][]) {
40
+ if (!hex) continue;
41
+ const roles = deriveAccent(hex, scheme, palette.surface);
42
+ out[name] = roles.base;
43
+ out[`on${capitalize(name)}`] = roles.on;
44
+ out[`${name}Soft`] = roles.soft;
45
+ out[`${name}Text`] = roles.text;
46
+ }
47
+
48
+ return out;
49
+ }
50
+
26
51
  /**
27
52
  * Construye el par de themes light/dark que consume <UIProvider theme={...}>.
28
53
  * Nunca muta los defaults: cada llamada produce objetos nuevos, seguros de
29
54
  * compartir entre providers distintos (tests, multi-brand en el mismo árbol).
55
+ *
56
+ * `brand` se aplica antes que `colors`, así que un rol escrito a mano siempre
57
+ * gana sobre el derivado.
30
58
  */
31
59
  export function createTheme(overrides?: ThemeOverrides): ThemePair {
32
60
  const tokens = mergeDeep(defaultTokens, overrides?.tokens as any);
33
61
 
34
62
  const light: Theme = {
35
- colors: mergeDeep(lightPalette, overrides?.colors?.light),
63
+ colors: mergeDeep(
64
+ mergeDeep(lightPalette, brandColors(overrides?.brand, 'light', lightPalette)),
65
+ overrides?.colors?.light
66
+ ),
36
67
  tokens,
37
68
  scheme: 'light',
38
69
  };
39
70
 
40
71
  const dark: Theme = {
41
- colors: mergeDeep(darkPalette, overrides?.colors?.dark),
72
+ colors: mergeDeep(
73
+ mergeDeep(darkPalette, brandColors(overrides?.brand, 'dark', darkPalette)),
74
+ overrides?.colors?.dark
75
+ ),
42
76
  tokens,
43
77
  scheme: 'dark',
44
78
  };
@@ -3,7 +3,9 @@ export type { Tokens } from './tokens';
3
3
  export { lightPalette, darkPalette } from './palettes';
4
4
  export type { ThemeColors } from './palettes';
5
5
  export { createTheme, defaultTheme } from './createTheme';
6
- export type { Theme, ThemePair, ThemeOverrides, DeepPartial } from './types';
6
+ export type { Theme, ThemePair, ThemeOverrides, BrandAccent, DeepPartial } from './types';
7
+ export { deriveAccent, contrast, luminance, AA_CONTRAST } from './colors';
8
+ export type { AccentRoles } from './colors';
7
9
  export { defaultLabels } from './labels';
8
10
  export type { Labels } from './labels';
9
11
  export { zeroInsets } from './insets';
@@ -8,6 +8,12 @@ export interface Labels {
8
8
  noResultsDescription: string;
9
9
  search: string;
10
10
  selectPlaceholder: string;
11
+ /** Nombres de los meses, de enero a diciembre. */
12
+ months: string[];
13
+ /** Iniciales de los días, índice 0 = domingo (alinea con `Date.getDay()`). */
14
+ weekdaysShort: string[];
15
+ selectDate: string;
16
+ clear: string;
11
17
  }
12
18
 
13
19
  export const defaultLabels: Labels = {
@@ -20,4 +26,11 @@ export const defaultLabels: Labels = {
20
26
  noResultsDescription: 'Try a different search term',
21
27
  search: 'Search...',
22
28
  selectPlaceholder: 'Select...',
29
+ months: [
30
+ 'January', 'February', 'March', 'April', 'May', 'June',
31
+ 'July', 'August', 'September', 'October', 'November', 'December',
32
+ ],
33
+ weekdaysShort: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
34
+ selectDate: 'Select date',
35
+ clear: 'Clear',
23
36
  };
@@ -81,8 +81,11 @@ export const lightPalette: ThemeColors = {
81
81
  successSoft: '#e3f6e9',
82
82
  successText: '#116a30',
83
83
 
84
- error: '#ff3b30',
85
- onError: '#3d0300',
84
+ // El rojo va con texto blanco, que es lo que la gente espera de un botón
85
+ // destructivo. #ff3b30 no llega a 4.5:1 con blanco y obligaba a texto casi
86
+ // negro sobre rojo; este tono sí, y sigue leyéndose como rojo de alerta.
87
+ error: '#dc2626',
88
+ onError: '#ffffff',
86
89
  errorSoft: '#fdeaea',
87
90
  errorText: '#c62222',
88
91
 
@@ -18,7 +18,17 @@ export type DeepPartial<T> = {
18
18
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
19
19
  };
20
20
 
21
+ /** Acentos que se pueden definir con un solo hex vía `brand`. */
22
+ export type BrandAccent = 'primary' | 'secondary' | 'success' | 'error' | 'warning';
23
+
21
24
  export interface ThemeOverrides {
25
+ /**
26
+ * Un hex por acento; de cada uno se derivan sus cuatro roles (relleno, lo
27
+ * que va encima, el fondo tenue y la variante legible sobre `surface`) para
28
+ * light y para dark, con el contraste ya resuelto. Un string suelto define
29
+ * `primary`. Lo que se pase en `colors` gana sobre lo derivado.
30
+ */
31
+ brand?: string | Partial<Record<BrandAccent, string>>;
22
32
  colors?: {
23
33
  light?: Partial<ThemeColors>;
24
34
  dark?: Partial<ThemeColors>;
@@ -1 +0,0 @@
1
- {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_createStyles","_UIProvider","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","MODES","DEFAULT_LABELS","system","light","dark","useStyles","createStyles","theme","track","flexDirection","backgroundColor","colors","inputBackground","borderRadius","tokens","radius","md","padding","segment","flex","paddingVertical","spacing","sm","alignItems","segmentActive","surface","shadow","label","fontSize","fontWeight","medium","color","textLight","labelActive","primaryText","semibold","ThemeToggle","exports","memo","style","labels","labelOverrides","mode","setMode","useThemeMode","useColors","styles","allowFontScaling","useAllowFontScaling","jsx","View","accessibilityRole","children","map","m","active","TouchableOpacity","onPress","accessibilityState","selected","accessibilityLabel","Text","displayName"],"sourceRoot":"../../../src","sources":["molecules/ThemeToggle.tsx"],"mappings":"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","ignoreList":[]}
@@ -1 +0,0 @@
1
- {"version":3,"names":["React","memo","Text","TouchableOpacity","View","createStyles","useAllowFontScaling","useColors","useThemeMode","jsx","_jsx","MODES","DEFAULT_LABELS","system","light","dark","useStyles","theme","track","flexDirection","backgroundColor","colors","inputBackground","borderRadius","tokens","radius","md","padding","segment","flex","paddingVertical","spacing","sm","alignItems","segmentActive","surface","shadow","label","fontSize","fontWeight","medium","color","textLight","labelActive","primaryText","semibold","ThemeToggle","style","labels","labelOverrides","mode","setMode","styles","allowFontScaling","accessibilityRole","children","map","m","active","onPress","accessibilityState","selected","accessibilityLabel","displayName"],"sourceRoot":"../../../src","sources":["molecules/ThemeToggle.tsx"],"mappings":"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","ignoreList":[]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ThemeToggle.d.ts","sourceRoot":"","sources":["../../../src/molecules/ThemeToggle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAe,MAAM,OAAO,CAAC;AACpC,OAAO,EAAgC,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE5F,OAAO,EAAgD,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEnG,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;CAC7C;AAuBD;;;;;GAKG;AACH,eAAO,MAAM,WAAW,gEAA4C,gBAAgB,uBA4BlF,CAAC"}
@@ -1,67 +0,0 @@
1
- import React, { memo } from 'react';
2
- import { Text, TouchableOpacity, View, type StyleProp, type ViewStyle } from 'react-native';
3
- import { createStyles } from '../theme/createStyles';
4
- import { useAllowFontScaling, useColors, useThemeMode, type ThemeMode } from '../theme/UIProvider';
5
-
6
- export interface ThemeToggleProps {
7
- style?: StyleProp<ViewStyle>;
8
- labels?: Partial<Record<ThemeMode, string>>;
9
- }
10
-
11
- const MODES: ThemeMode[] = ['system', 'light', 'dark'];
12
- const DEFAULT_LABELS: Record<ThemeMode, string> = { system: 'Auto', light: 'Light', dark: 'Dark' };
13
-
14
- const useStyles = createStyles((theme) => ({
15
- track: {
16
- flexDirection: 'row',
17
- backgroundColor: theme.colors.inputBackground,
18
- borderRadius: theme.tokens.radius.md,
19
- padding: 3,
20
- },
21
- segment: {
22
- flex: 1,
23
- paddingVertical: theme.tokens.spacing.sm,
24
- borderRadius: theme.tokens.radius.sm,
25
- alignItems: 'center',
26
- },
27
- segmentActive: { backgroundColor: theme.colors.surface, ...theme.tokens.shadow.sm },
28
- label: { fontSize: theme.tokens.fontSize.sm, fontWeight: theme.tokens.fontWeight.medium, color: theme.colors.textLight },
29
- labelActive: { color: theme.colors.primaryText, fontWeight: theme.tokens.fontWeight.semibold },
30
- }));
31
-
32
- /**
33
- * ThemeToggle
34
- * Segmented control de 3 estados (system/light/dark) conectado a
35
- * UIProvider.setMode. Sin persistencia — el consumidor la resuelve vía
36
- * onModeChange en <UIProvider>.
37
- */
38
- export const ThemeToggle = memo(({ style, labels: labelOverrides }: ThemeToggleProps) => {
39
- const { mode, setMode } = useThemeMode();
40
- const colors = useColors();
41
- const styles = useStyles();
42
- const allowFontScaling = useAllowFontScaling();
43
- const labels = { ...DEFAULT_LABELS, ...labelOverrides };
44
-
45
- return (
46
- <View style={[styles.track, style]} accessibilityRole="tablist">
47
- {MODES.map((m) => {
48
- const active = mode === m;
49
- return (
50
- <TouchableOpacity
51
- key={m}
52
- style={[styles.segment, active && styles.segmentActive]}
53
- onPress={() => setMode(m)}
54
- accessibilityRole="tab"
55
- accessibilityState={{ selected: active }}
56
- accessibilityLabel={labels[m]}
57
- >
58
- <Text allowFontScaling={allowFontScaling} style={[styles.label, active && styles.labelActive]}>
59
- {labels[m]}
60
- </Text>
61
- </TouchableOpacity>
62
- );
63
- })}
64
- </View>
65
- );
66
- });
67
- ThemeToggle.displayName = 'ThemeToggle';