@azmr/ui 0.1.0 → 0.3.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 (95) hide show
  1. package/README.md +171 -0
  2. package/dist/avatar.d.ts +58 -0
  3. package/dist/avatar.js +84 -0
  4. package/dist/breadcrumb.d.ts +47 -0
  5. package/dist/breadcrumb.js +120 -0
  6. package/dist/button-CYt2Zw3D.d.ts +64 -0
  7. package/dist/button.d.ts +54 -0
  8. package/dist/button.js +19 -0
  9. package/dist/chunk-2RIWL363.js +27 -0
  10. package/dist/chunk-2TQSHVXA.js +12 -0
  11. package/dist/chunk-7EOSDFS3.js +10 -0
  12. package/dist/chunk-C2HKIPLQ.js +118 -0
  13. package/dist/chunk-CAJLW6K2.js +16 -0
  14. package/dist/chunk-CZJZYN54.js +36 -0
  15. package/dist/chunk-EE4V6XMB.js +35 -0
  16. package/dist/chunk-EFHRRLAW.js +211 -0
  17. package/dist/chunk-GLB75NT3.js +21 -0
  18. package/dist/chunk-GX2YEJ43.js +36 -0
  19. package/dist/chunk-LTOLV67A.js +19 -0
  20. package/dist/chunk-LZMX27IZ.js +10 -0
  21. package/dist/chunk-NIIDYIZA.js +1 -0
  22. package/dist/chunk-Q4PPM2SU.js +97 -0
  23. package/dist/chunk-WVE2E37B.js +20 -0
  24. package/dist/chunk-XRZHP6BD.js +92 -0
  25. package/dist/disclosure.d.ts +72 -0
  26. package/dist/disclosure.js +221 -0
  27. package/dist/display.d.ts +111 -0
  28. package/dist/display.js +237 -0
  29. package/dist/features-dom-MCGKRLN5.js +7 -0
  30. package/dist/features-max-COBTQCO6.js +7 -0
  31. package/dist/floating.d.ts +81 -0
  32. package/dist/floating.js +231 -0
  33. package/dist/hooks.d.ts +33 -0
  34. package/dist/hooks.js +55 -0
  35. package/dist/icons/lucide.d.ts +77 -0
  36. package/dist/icons/lucide.js +135 -0
  37. package/dist/icons/mui-map.d.ts +1268 -0
  38. package/dist/icons/mui-map.js +352 -0
  39. package/dist/icons.d.ts +48 -0
  40. package/dist/icons.js +19 -0
  41. package/dist/index.d.ts +238 -3
  42. package/dist/index.js +242 -15
  43. package/dist/input.d.ts +14 -0
  44. package/dist/input.js +8 -0
  45. package/dist/layout/mui-map.d.ts +80 -0
  46. package/dist/layout/mui-map.js +104 -0
  47. package/dist/layout.d.ts +89 -0
  48. package/dist/layout.js +455 -0
  49. package/dist/lib.d.ts +11 -0
  50. package/dist/lib.js +6 -0
  51. package/dist/menu.d.ts +105 -0
  52. package/dist/menu.js +56 -0
  53. package/dist/modal.d.ts +105 -0
  54. package/dist/modal.js +273 -0
  55. package/dist/motion.css +295 -0
  56. package/dist/motion.d.ts +49 -0
  57. package/dist/motion.js +48 -0
  58. package/dist/pagination.d.ts +82 -0
  59. package/dist/pagination.js +211 -0
  60. package/dist/presets.d.ts +97 -0
  61. package/dist/presets.js +94 -0
  62. package/dist/progress.d.ts +70 -0
  63. package/dist/progress.js +138 -0
  64. package/dist/react.d.ts +81 -0
  65. package/dist/react.js +281 -0
  66. package/dist/responsive-YJBnvsjt.d.ts +69 -0
  67. package/dist/scroll-area.d.ts +30 -0
  68. package/dist/scroll-area.js +80 -0
  69. package/dist/shared-Fkx-sjPt.d.ts +15 -0
  70. package/dist/spinner.d.ts +18 -0
  71. package/dist/spinner.js +39 -0
  72. package/dist/split-button.d.ts +32 -0
  73. package/dist/split-button.js +54 -0
  74. package/dist/stepper.d.ts +27 -0
  75. package/dist/stepper.js +104 -0
  76. package/dist/styles.css +24 -0
  77. package/dist/table.d.ts +52 -0
  78. package/dist/table.js +124 -0
  79. package/dist/theme.d.ts +111 -0
  80. package/dist/theme.js +414 -0
  81. package/dist/toast.d.ts +77 -0
  82. package/dist/toast.js +203 -0
  83. package/dist/toggle.d.ts +55 -0
  84. package/dist/toggle.js +88 -0
  85. package/dist/tokens.css +337 -0
  86. package/dist/transition.d.ts +51 -0
  87. package/dist/transition.js +79 -0
  88. package/dist/types-BBudf463.d.ts +39 -0
  89. package/dist/typography/mui-map.d.ts +91 -0
  90. package/dist/typography/mui-map.js +62 -0
  91. package/dist/typography.d.ts +90 -0
  92. package/dist/typography.js +193 -0
  93. package/dist/useSignal-C-3ZGURN.d.ts +21 -0
  94. package/dist/variants-De0c0ucO.d.ts +60 -0
  95. package/package.json +179 -13
package/dist/theme.js ADDED
@@ -0,0 +1,414 @@
1
+ // src/theme/preferences.ts
2
+ var THEME_PREFERENCES = ["light", "dark", "system"];
3
+ var DENSITIES = ["compact", "comfortable", "spacious"];
4
+ var THEME_COOKIE = "azmr-theme";
5
+ var DENSITY_COOKIE = "azmr-density";
6
+ var ONE_YEAR_SECONDS = 60 * 60 * 24 * 365;
7
+ function parseThemePreference(value, fallback = "system") {
8
+ return typeof value === "string" && THEME_PREFERENCES.includes(value) ? value : fallback;
9
+ }
10
+ function parseDensity(value, fallback = "comfortable") {
11
+ return typeof value === "string" && DENSITIES.includes(value) ? value : fallback;
12
+ }
13
+ function readCookie(header, name) {
14
+ if (!header) return void 0;
15
+ for (const part of header.split(";")) {
16
+ const trimmed = part.trim();
17
+ const eq = trimmed.indexOf("=");
18
+ if (eq === -1 || trimmed.slice(0, eq) !== name) continue;
19
+ const raw = trimmed.slice(eq + 1);
20
+ try {
21
+ return decodeURIComponent(raw);
22
+ } catch {
23
+ return raw;
24
+ }
25
+ }
26
+ return void 0;
27
+ }
28
+ var COOKIE_NAME = /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/;
29
+ var COOKIE_VALUE = /^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*$/;
30
+ function serializeCookie(name, value, options = {}) {
31
+ if (!COOKIE_NAME.test(name)) throw new Error(`Invalid cookie name: ${JSON.stringify(name)}`);
32
+ if (!COOKIE_VALUE.test(value)) throw new Error(`Invalid cookie value for "${name}"`);
33
+ const secure = options.secure ? "; Secure" : "";
34
+ return `${name}=${value}; Path=/; Max-Age=${ONE_YEAR_SECONDS}; SameSite=Lax${secure}`;
35
+ }
36
+ function buildHtmlAttributes({ theme, density }) {
37
+ const attributes = {};
38
+ if (theme === "light" || theme === "dark") attributes["data-theme"] = theme;
39
+ if (density === "compact" || density === "spacious") attributes["data-density"] = density;
40
+ return attributes;
41
+ }
42
+ var htmlAttributes = Object.assign(buildHtmlAttributes, {
43
+ fromCookies(header) {
44
+ return buildHtmlAttributes({
45
+ theme: parseThemePreference(readCookie(header, THEME_COOKIE)),
46
+ density: parseDensity(readCookie(header, DENSITY_COOKIE))
47
+ });
48
+ }
49
+ });
50
+
51
+ // src/theme/create-theme.ts
52
+ var rad = (deg) => deg * Math.PI / 180;
53
+ function toLinearSrgb({ l, c, h }) {
54
+ const a = c * Math.cos(rad(h));
55
+ const b = c * Math.sin(rad(h));
56
+ const l_ = (l + 0.3963377774 * a + 0.2158037573 * b) ** 3;
57
+ const m_ = (l - 0.1055613458 * a - 0.0638541728 * b) ** 3;
58
+ const s_ = (l - 0.0894841775 * a - 1.291485548 * b) ** 3;
59
+ return [
60
+ 4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_,
61
+ -1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_,
62
+ -0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_
63
+ ];
64
+ }
65
+ function fromLinearSrgb([r, g, b]) {
66
+ const l_ = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
67
+ const m_ = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
68
+ const s_ = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
69
+ const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
70
+ const A = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
71
+ const B = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
72
+ const c = Math.hypot(A, B);
73
+ return { l: L, c, h: c < 4e-4 ? 0 : (Math.atan2(B, A) * 180 / Math.PI + 360) % 360 };
74
+ }
75
+ var EPS = 1e-4;
76
+ var inGamut = (color) => toLinearSrgb(color).every((v) => v >= -EPS && v <= 1 + EPS);
77
+ function clampToGamut(color) {
78
+ let { c } = color;
79
+ while (c > 0 && !inGamut({ ...color, c })) c = Math.max(0, c - 4e-3);
80
+ return { ...color, c };
81
+ }
82
+ var luminance = (color) => {
83
+ const [r, g, b] = toLinearSrgb(color).map((v) => Math.min(1, Math.max(0, v)));
84
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
85
+ };
86
+ function contrast(a, b) {
87
+ const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
88
+ return (hi + 0.05) / (lo + 0.05);
89
+ }
90
+ var round = (n, digits) => Number(n.toFixed(digits));
91
+ var format = ({ l, c, h }) => `oklch(${round(l, 3)} ${round(c, 3)} ${round(h, 1)})`;
92
+ var lightDark = (light, dark) => `light-dark(${format(light)}, ${format(dark)})`;
93
+ function fromHex(hex) {
94
+ const digits = hex.length === 3 ? [...hex].map((d) => d + d).join("") : hex;
95
+ const decode2 = (i) => {
96
+ const v = Number.parseInt(digits.slice(i, i + 2), 16) / 255;
97
+ return v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
98
+ };
99
+ const color = fromLinearSrgb([decode2(0), decode2(2), decode2(4)]);
100
+ return color.c < 4e-3 ? { l: color.l, c: 0, h: 0 } : color;
101
+ }
102
+ function parseColour(input, name) {
103
+ if (typeof input === "object" && input !== null) {
104
+ const { l, c, h } = input;
105
+ if (![l, c, h].every(Number.isFinite) || l < 0 || l > 1 || c < 0 || c > 0.5) {
106
+ throw new Error(
107
+ `createTheme: ${name} { l, c, h } must be finite, with 0 <= l <= 1 and 0 <= c <= 0.5`
108
+ );
109
+ }
110
+ return { l, c, h: (h % 360 + 360) % 360 };
111
+ }
112
+ const text = String(input).trim();
113
+ const hex = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.exec(text);
114
+ if (hex?.[1]) return fromHex(hex[1]);
115
+ const ok = /^oklch\(\s*(\d*\.?\d+)(%?)\s+(\d*\.?\d+)\s+(\d*\.?\d+)(?:deg)?\s*\)$/i.exec(text);
116
+ if (ok) {
117
+ const l = Number(ok[1]) / (ok[2] ? 100 : 1);
118
+ return parseColour({ l, c: Number(ok[3]), h: Number(ok[4]) }, name);
119
+ }
120
+ throw new Error(
121
+ `createTheme: ${name} must be #rgb, #rrggbb, oklch(L C H) or { l, c, h }; got ${JSON.stringify(text)}`
122
+ // conventions-ignore: the message names the accepted colour syntax
123
+ );
124
+ }
125
+ var WHITE = { l: 0.985, c: 0, h: 0 };
126
+ var NEAR_BLACK = { l: 0.145, c: 0, h: 0 };
127
+ var DARK_CARD = { l: 0.205, c: 0, h: 0 };
128
+ var WARNING_FOREGROUND = { l: 0.25, c: 0.04, h: 70 };
129
+ var AA_TEXT = 4.5;
130
+ var AA_SURFACE = 4.55;
131
+ var AA_NON_TEXT = 3.2;
132
+ var STEP = 5e-3;
133
+ var SURFACES = {
134
+ light: [WHITE],
135
+ dark: [NEAR_BLACK, DARK_CARD]
136
+ };
137
+ var HOVER_ALPHA = 0.9;
138
+ var SECONDARY_HOVER_ALPHA = 0.8;
139
+ var encode = (v) => v <= 31308e-7 ? 12.92 * v : 1.055 * v ** (1 / 2.4) - 0.055;
140
+ var decode = (v) => v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
141
+ function encodedSrgb(color) {
142
+ return toLinearSrgb(color).map((v) => encode(Math.min(1, Math.max(0, v))));
143
+ }
144
+ function mixedLuminance(color, surface, alpha) {
145
+ const top = encodedSrgb(color);
146
+ const base = encodedSrgb(surface);
147
+ const [r, g, b] = top.map((v, i) => decode(v * alpha + base[i] * (1 - alpha)));
148
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
149
+ }
150
+ function contrastOfLuminance(a, b) {
151
+ const [hi, lo] = [a, b].sort((x, y) => y - x);
152
+ return (hi + 0.05) / (lo + 0.05);
153
+ }
154
+ function holdsOnHover(bg, fg, mode, alpha = HOVER_ALPHA) {
155
+ if (contrast(bg, fg) < AA_SURFACE) return false;
156
+ return SURFACES[mode].every(
157
+ (surface) => contrastOfLuminance(luminance(fg), mixedLuminance(bg, surface, alpha)) >= AA_SURFACE
158
+ );
159
+ }
160
+ function shiftUntil(color, direction, limit, ok) {
161
+ for (let shift = 0; shift <= limit + 1e-9; shift += STEP) {
162
+ const candidate = clampToGamut({
163
+ ...color,
164
+ l: Math.min(1, Math.max(0, color.l + direction * shift))
165
+ });
166
+ if (ok(candidate)) return candidate;
167
+ }
168
+ return void 0;
169
+ }
170
+ function lightPair(brand, alpha = HOVER_ALPHA) {
171
+ const withWhite = shiftUntil(brand, -1, 0.12, (c) => holdsOnHover(c, WHITE, "light", alpha));
172
+ if (withWhite) return { bg: withWhite, fg: WHITE };
173
+ const withBlack = shiftUntil(brand, 1, 0.3, (c) => holdsOnHover(c, NEAR_BLACK, "light", alpha));
174
+ if (withBlack) return { bg: withBlack, fg: NEAR_BLACK };
175
+ const forced = shiftUntil(brand, -1, 1, (c) => holdsOnHover(c, WHITE, "light", alpha));
176
+ return { bg: forced ?? clampToGamut({ ...brand, l: 0.2 }), fg: WHITE };
177
+ }
178
+ function darkPair(brand, alpha = HOVER_ALPHA) {
179
+ const start = clampToGamut({ ...brand, l: Math.min(0.88, Math.max(0.7, brand.l)) });
180
+ const bg = shiftUntil(start, 1, 0.3, (c) => holdsOnHover(c, NEAR_BLACK, "dark", alpha)) ?? start;
181
+ return { bg, fg: NEAR_BLACK };
182
+ }
183
+ function statusPair(brand, mode) {
184
+ if (mode === "light") {
185
+ const bg2 = shiftUntil(brand, -1, 1, (c) => holdsOnHover(c, WHITE, "light"));
186
+ return { bg: bg2 ?? clampToGamut({ ...brand, l: 0.2 }), fg: WHITE };
187
+ }
188
+ const start = clampToGamut({ ...brand, l: Math.min(0.88, Math.max(0.7, brand.l)) });
189
+ const bg = shiftUntil(start, 1, 0.3, (c) => holdsOnHover(c, NEAR_BLACK, "dark"));
190
+ return { bg: bg ?? start, fg: NEAR_BLACK };
191
+ }
192
+ function warningColours(brand, mode) {
193
+ const start = clampToGamut({ ...brand, l: Math.min(0.9, Math.max(0.7, brand.l)) });
194
+ if (mode === "light") {
195
+ const bg = shiftUntil(start, 1, 0.3, (c) => holdsOnHover(c, WARNING_FOREGROUND, "light")) ?? start;
196
+ const text = shiftUntil(brand, -1, 1, (c) => contrast(c, WHITE) >= AA_TEXT);
197
+ return { bg, fg: WARNING_FOREGROUND, text: text ?? clampToGamut({ ...brand, l: 0.2 }) };
198
+ }
199
+ const both = shiftUntil(start, 1, 0.3, (c) => holdsOnHover(c, WARNING_FOREGROUND, "dark"));
200
+ const colour = both ?? start;
201
+ return { bg: colour, fg: WARNING_FOREGROUND, text: colour };
202
+ }
203
+ function ringFor(brand, mode) {
204
+ const surfaces = mode === "light" ? [WHITE] : [
205
+ { l: 0.145, c: 0, h: 0 },
206
+ { l: 0.205, c: 0, h: 0 }
207
+ ];
208
+ const start = clampToGamut({
209
+ l: mode === "light" ? Math.min(brand.l, 0.6) : Math.max(brand.l, 0.7),
210
+ c: Math.min(brand.c, 0.18),
211
+ h: brand.h
212
+ });
213
+ const ok = (c) => surfaces.every((s) => contrast(c, s) >= AA_NON_TEXT);
214
+ return shiftUntil(start, mode === "light" ? -1 : 1, 0.6, ok) ?? start;
215
+ }
216
+ var RADIUS = /^(?:\d+|\d*\.\d+)(?:rem|px)$/;
217
+ var FONT = /^[A-Za-z0-9 ,'"._-]+$/;
218
+ function assertRadius(radius) {
219
+ if (!RADIUS.test(radius))
220
+ throw new Error(
221
+ `createTheme: radius must be a number in rem or px, got ${JSON.stringify(radius)}`
222
+ );
223
+ return radius;
224
+ }
225
+ function assertFont(font) {
226
+ if (font.length > 200 || !FONT.test(font)) {
227
+ throw new Error(
228
+ "createTheme: font must be a short font-family list (letters, digits, spaces, commas, quotes)"
229
+ );
230
+ }
231
+ return font;
232
+ }
233
+ function createTheme(options = {}) {
234
+ const cssVariables = {};
235
+ if (options.secondary !== void 0) {
236
+ const brand = parseColour(options.secondary, "secondary");
237
+ const light = lightPair(brand, SECONDARY_HOVER_ALPHA);
238
+ const dark = darkPair(brand, SECONDARY_HOVER_ALPHA);
239
+ cssVariables["--secondary"] = lightDark(light.bg, dark.bg);
240
+ cssVariables["--secondary-foreground"] = lightDark(light.fg, dark.fg);
241
+ }
242
+ for (const name of ["success", "info", "destructive"]) {
243
+ const input = options[name];
244
+ if (input === void 0) continue;
245
+ const brand = parseColour(input, name);
246
+ const light = statusPair(brand, "light");
247
+ const dark = statusPair(brand, "dark");
248
+ cssVariables[`--${name}`] = lightDark(light.bg, dark.bg);
249
+ cssVariables[`--${name}-foreground`] = lightDark(light.fg, dark.fg);
250
+ }
251
+ if (options.warning !== void 0) {
252
+ const brand = parseColour(options.warning, "warning");
253
+ const light = warningColours(brand, "light");
254
+ const dark = warningColours(brand, "dark");
255
+ cssVariables["--warning"] = lightDark(light.bg, dark.bg);
256
+ cssVariables["--warning-foreground"] = lightDark(light.fg, dark.fg);
257
+ cssVariables["--warning-text"] = lightDark(light.text, dark.text);
258
+ }
259
+ if (options.primary !== void 0) {
260
+ const brand = parseColour(options.primary, "primary");
261
+ const light = lightPair(brand);
262
+ const dark = darkPair(brand);
263
+ const ring = lightDark(ringFor(brand, "light"), ringFor(brand, "dark"));
264
+ cssVariables["--primary"] = lightDark(light.bg, dark.bg);
265
+ cssVariables["--primary-foreground"] = lightDark(light.fg, dark.fg);
266
+ cssVariables["--ring"] = ring;
267
+ cssVariables["--sidebar-primary"] = cssVariables["--primary"];
268
+ cssVariables["--sidebar-primary-foreground"] = cssVariables["--primary-foreground"];
269
+ cssVariables["--sidebar-ring"] = ring;
270
+ }
271
+ if (options.radius !== void 0) cssVariables["--radius"] = assertRadius(options.radius);
272
+ if (options.font !== void 0) cssVariables["--font-sans-stack"] = assertFont(options.font);
273
+ let density;
274
+ if (options.density !== void 0) {
275
+ density = parseDensity(options.density, "comfortable");
276
+ if (density !== options.density)
277
+ throw new Error(`createTheme: unknown density ${JSON.stringify(options.density)}`);
278
+ }
279
+ const entries = Object.entries(cssVariables);
280
+ const css = entries.length === 0 ? ":root {}" : `:root {
281
+ ${entries.map(([k, v]) => ` ${k}: ${v};`).join("\n")}
282
+ }`;
283
+ return { cssVariables, css, htmlAttributes: htmlAttributes({ density }) };
284
+ }
285
+
286
+ // src/theme/init-script.ts
287
+ function themeInitScript() {
288
+ return `(function(){try{var t,d,c=(document.cookie||'').split(';');for(var i=0;i<c.length;i++){var p=c[i].trim();if(p.indexOf('${THEME_COOKIE}=')===0)t=p.slice(${THEME_COOKIE.length + 1});else if(p.indexOf('${DENSITY_COOKIE}=')===0)d=p.slice(${DENSITY_COOKIE.length + 1});}var e=document.documentElement;if(t==='light'||t==='dark')e.setAttribute('data-theme',t);if(d==='compact'||d==='spacious')e.setAttribute('data-density',d);}catch(_){}})();`;
289
+ }
290
+
291
+ // src/theme/locale.ts
292
+ var DEFAULT_MESSAGES = Object.freeze({
293
+ close: "Close",
294
+ cancel: "Cancel",
295
+ confirm: "Confirm",
296
+ loading: "Loading",
297
+ noResults: "No results found",
298
+ clear: "Clear",
299
+ search: "Search",
300
+ previousPage: "Previous page",
301
+ nextPage: "Next page"
302
+ });
303
+ var DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
304
+ var FIELD_OPTIONS = [
305
+ "weekday",
306
+ "era",
307
+ "year",
308
+ "month",
309
+ "day",
310
+ "dayPeriod",
311
+ "hour",
312
+ "minute",
313
+ "second",
314
+ "fractionalSecondDigits",
315
+ "timeZoneName"
316
+ ];
317
+ function toInstant(value) {
318
+ if (value === null || value === void 0 || value === "") return void 0;
319
+ if (typeof value === "string") {
320
+ const match = DATE_ONLY.exec(value);
321
+ if (match) {
322
+ const date2 = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])));
323
+ return Number.isNaN(date2.getTime()) ? void 0 : { date: date2, calendarDay: true };
324
+ }
325
+ }
326
+ const date = value instanceof Date ? value : new Date(value);
327
+ return Number.isNaN(date.getTime()) ? void 0 : { date, calendarDay: false };
328
+ }
329
+ function createLocale(options = {}) {
330
+ const locale = options.locale ?? "en-NZ";
331
+ const currency = options.currency ?? "NZD";
332
+ const weekStartsOn = options.weekStartsOn ?? 1;
333
+ const timeZone = options.timeZone;
334
+ try {
335
+ Intl.getCanonicalLocales(locale);
336
+ } catch {
337
+ throw new Error(`createLocale: invalid locale ${JSON.stringify(locale)}`);
338
+ }
339
+ if (!/^[A-Z]{3}$/.test(currency)) {
340
+ throw new Error(
341
+ `createLocale: currency must be an ISO 4217 code like "NZD", got ${JSON.stringify(currency)}`
342
+ );
343
+ }
344
+ if (timeZone !== void 0) {
345
+ try {
346
+ new Intl.DateTimeFormat(locale, { timeZone });
347
+ } catch {
348
+ throw new Error(`createLocale: unknown time zone ${JSON.stringify(timeZone)}`);
349
+ }
350
+ }
351
+ if (!Number.isInteger(weekStartsOn) || weekStartsOn < 0 || weekStartsOn > 6) {
352
+ throw new Error(
353
+ `createLocale: weekStartsOn must be an integer from 0 to 6, got ${weekStartsOn}`
354
+ );
355
+ }
356
+ const numberFormats = /* @__PURE__ */ new Map();
357
+ const dateFormats = /* @__PURE__ */ new Map();
358
+ const numberFormat = (opts) => {
359
+ const key = JSON.stringify(opts);
360
+ let format2 = numberFormats.get(key);
361
+ if (!format2) {
362
+ format2 = new Intl.NumberFormat(locale, opts);
363
+ numberFormats.set(key, format2);
364
+ }
365
+ return format2;
366
+ };
367
+ const dateFormat = (opts) => {
368
+ const key = JSON.stringify(opts);
369
+ let format2 = dateFormats.get(key);
370
+ if (!format2) {
371
+ format2 = new Intl.DateTimeFormat(locale, opts);
372
+ dateFormats.set(key, format2);
373
+ }
374
+ return format2;
375
+ };
376
+ const formatDateWith = (defaults) => (value, opts = {}) => {
377
+ const instant = toInstant(value);
378
+ if (!instant) return "";
379
+ const zone = instant.calendarDay ? "UTC" : opts.timeZone ?? timeZone;
380
+ const customised = FIELD_OPTIONS.some((key) => key in opts) || "dateStyle" in opts || "timeStyle" in opts;
381
+ return dateFormat({
382
+ ...customised ? {} : defaults,
383
+ ...opts,
384
+ ...zone ? { timeZone: zone } : {}
385
+ }).format(instant.date);
386
+ };
387
+ const isNumber = (value) => typeof value === "number" && Number.isFinite(value);
388
+ return {
389
+ locale,
390
+ currency,
391
+ weekStartsOn,
392
+ timeZone,
393
+ messages: { ...DEFAULT_MESSAGES, ...options.messages },
394
+ formatNumber: (value, opts = {}) => isNumber(value) ? numberFormat(opts).format(value) : "",
395
+ formatCurrency: (value, opts = {}) => isNumber(value) ? numberFormat({ style: "currency", currency, ...opts }).format(value) : "",
396
+ formatDate: formatDateWith({ dateStyle: "medium" }),
397
+ formatDateTime: formatDateWith({ dateStyle: "medium", timeStyle: "short" })
398
+ };
399
+ }
400
+ export {
401
+ DEFAULT_MESSAGES,
402
+ DENSITIES,
403
+ DENSITY_COOKIE,
404
+ THEME_COOKIE,
405
+ THEME_PREFERENCES,
406
+ createLocale,
407
+ createTheme,
408
+ htmlAttributes,
409
+ parseDensity,
410
+ parseThemePreference,
411
+ readCookie,
412
+ serializeCookie,
413
+ themeInitScript
414
+ };
@@ -0,0 +1,77 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ type ToastType = "success" | "error" | "info" | "warning" | "loading";
5
+ interface ToastOptions {
6
+ /** A second line under the title. */
7
+ description?: ReactNode;
8
+ /**
9
+ * Milliseconds before it dismisses itself. `0` keeps it until dismissed. Defaults to the
10
+ * `Toaster`'s `duration` (5000), and loading toasts never time out.
11
+ */
12
+ duration?: number;
13
+ /** Showing a toast with an id that is already visible updates that toast instead of stacking another. */
14
+ id?: string;
15
+ /**
16
+ * `high` is announced urgently (`role="alert"`), `low` politely. Errors are `high` by default,
17
+ * everything else `low`.
18
+ */
19
+ priority?: "low" | "high";
20
+ /** A button in the toast, such as Undo. It runs `onClick` and then dismisses the toast. */
21
+ action?: {
22
+ label: ReactNode;
23
+ onClick?: () => void;
24
+ };
25
+ /** Called when the toast is dismissed, by the person or by the timer. */
26
+ onClose?: () => void;
27
+ }
28
+ interface ToastUpdate extends ToastOptions {
29
+ title?: ReactNode;
30
+ type?: ToastType | "default";
31
+ }
32
+ /**
33
+ * Show a notification from anywhere, including outside React. Mount one `<Toaster />` near the root
34
+ * first; a toast shown before it is mounted has nowhere to render. Every method returns the toast's id.
35
+ */
36
+ declare const toast: ((title: ReactNode, options?: ToastOptions) => string) & {
37
+ success: (title: ReactNode, options?: ToastOptions) => string;
38
+ error: (title: ReactNode, options?: ToastOptions) => string;
39
+ info: (title: ReactNode, options?: ToastOptions) => string;
40
+ warning: (title: ReactNode, options?: ToastOptions) => string;
41
+ /** Stays until updated or dismissed. Pair it with `toast.update`, or use `toast.promise`. */
42
+ loading: (title: ReactNode, options?: ToastOptions) => string;
43
+ /** Show `loading`, then `success` or `error` when the promise settles. Returns the same promise. */
44
+ promise<Value, Reason = Error>(promise: Promise<Value>, messages: {
45
+ loading: string;
46
+ success: string | ((value: Value) => string);
47
+ error: string | ((error: Reason) => string);
48
+ }): Promise<Value>;
49
+ /** Change a toast that is showing: its text, its type or its timer. */
50
+ update(id: string, changes: ToastUpdate): void;
51
+ /** Dismiss one toast, or all of them when called without an id. */
52
+ dismiss(id?: string): void;
53
+ };
54
+
55
+ type ToasterPosition = "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right";
56
+ interface ToasterProps {
57
+ /** Where the stack sits. Default `bottom-right`. New toasts come in from that edge. */
58
+ position?: ToasterPosition;
59
+ /** The most toasts shown at once; older ones wait behind. Default 3. */
60
+ limit?: number;
61
+ /** Default milliseconds before a toast dismisses itself. `0` never does. Default 5000. */
62
+ duration?: number;
63
+ /** The accessible name of the notifications region. Default "Notifications". */
64
+ label?: string;
65
+ className?: string;
66
+ }
67
+ /**
68
+ * Renders the toasts raised by `toast.*`. Mount it once, near the root of the app.
69
+ *
70
+ * Toasts pause their timer while the pointer is over the stack or focus is inside it, the stack
71
+ * fans out on hover or focus, and each toast can be swiped away toward the edge it came from.
72
+ * F6 jumps keyboard focus into the stack. The region is a polite live region; errors are announced
73
+ * urgently.
74
+ */
75
+ declare function Toaster({ position, limit, duration, label, className, }: ToasterProps): react.JSX.Element;
76
+
77
+ export { type ToastOptions, type ToastType, type ToastUpdate, Toaster, type ToasterPosition, type ToasterProps, toast };