marclayui 0.0.0-stage → 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 (71) hide show
  1. package/README.md +50 -3
  2. package/dist/index.cjs +1551 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.mts +394 -0
  5. package/dist/index.d.ts +394 -0
  6. package/dist/index.js +1483 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/theme-init.cjs +31 -0
  9. package/dist/theme-init.cjs.map +1 -0
  10. package/dist/theme-init.d.mts +8 -0
  11. package/dist/theme-init.d.ts +8 -0
  12. package/dist/theme-init.js +6 -0
  13. package/dist/theme-init.js.map +1 -0
  14. package/package.json +71 -4
  15. package/src/components/accordion/accordion.css +66 -0
  16. package/src/components/accordion/accordion.tsx +86 -0
  17. package/src/components/alert/alert.css +86 -0
  18. package/src/components/alert/alert.tsx +45 -0
  19. package/src/components/avatar/avatar.css +75 -0
  20. package/src/components/avatar/avatar.tsx +59 -0
  21. package/src/components/badge/badge.css +106 -0
  22. package/src/components/badge/badge.tsx +26 -0
  23. package/src/components/button/button.css +118 -0
  24. package/src/components/button/button.tsx +86 -0
  25. package/src/components/card/card.css +41 -0
  26. package/src/components/card/card.tsx +26 -0
  27. package/src/components/checks/checks.css +157 -0
  28. package/src/components/checks/checks.tsx +167 -0
  29. package/src/components/divider/divider.css +41 -0
  30. package/src/components/divider/divider.tsx +24 -0
  31. package/src/components/dropdown/dropdown.css +182 -0
  32. package/src/components/dropdown/dropdown.tsx +268 -0
  33. package/src/components/input/input.css +73 -0
  34. package/src/components/input/input.tsx +85 -0
  35. package/src/components/kbd/kbd.css +66 -0
  36. package/src/components/kbd/kbd.tsx +14 -0
  37. package/src/components/modal/modal.css +93 -0
  38. package/src/components/modal/modal.tsx +114 -0
  39. package/src/components/navbar/navbar.css +127 -0
  40. package/src/components/navbar/navbar.tsx +64 -0
  41. package/src/components/progress/progress.css +62 -0
  42. package/src/components/progress/progress.tsx +50 -0
  43. package/src/components/range/range.css +68 -0
  44. package/src/components/range/range.tsx +60 -0
  45. package/src/components/select/select.css +58 -0
  46. package/src/components/select/select.tsx +72 -0
  47. package/src/components/skeleton/skeleton.css +43 -0
  48. package/src/components/skeleton/skeleton.tsx +35 -0
  49. package/src/components/spinner/spinner.css +21 -0
  50. package/src/components/spinner/spinner.tsx +10 -0
  51. package/src/components/stack/stack.css +60 -0
  52. package/src/components/stack/stack.tsx +34 -0
  53. package/src/components/stat/stat.css +54 -0
  54. package/src/components/stat/stat.tsx +19 -0
  55. package/src/components/tabs/tabs.css +58 -0
  56. package/src/components/tabs/tabs.tsx +84 -0
  57. package/src/components/toast/toast.css +94 -0
  58. package/src/components/toast/toast.tsx +100 -0
  59. package/src/components/tooltip/tooltip.css +100 -0
  60. package/src/components/tooltip/tooltip.tsx +19 -0
  61. package/src/index.ts +115 -0
  62. package/src/styles/base.css +78 -0
  63. package/src/styles/index.css +27 -0
  64. package/src/styles/theme.css +246 -0
  65. package/src/theme-init.ts +6 -0
  66. package/src/theming/ThemeMenu.tsx +158 -0
  67. package/src/theming/ThemeProvider.tsx +234 -0
  68. package/src/theming/ThemeToggle.tsx +27 -0
  69. package/src/theming/presets.ts +33 -0
  70. package/src/theming/theming.css +155 -0
  71. package/src/utils/color.ts +58 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,1551 @@
1
+ "use client";
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/index.ts
32
+ var index_exports = {};
33
+ __export(index_exports, {
34
+ Accordion: () => Accordion,
35
+ Alert: () => Alert,
36
+ Avatar: () => Avatar,
37
+ AvatarGroup: () => AvatarGroup,
38
+ Badge: () => Badge,
39
+ Button: () => Button,
40
+ ButtonGroup: () => ButtonGroup,
41
+ COLOR_SWATCHES: () => COLOR_SWATCHES,
42
+ Card: () => Card,
43
+ CardBody: () => CardBody,
44
+ CardFooter: () => CardFooter,
45
+ CardHeader: () => CardHeader,
46
+ CardTitle: () => CardTitle,
47
+ Checkbox: () => Checkbox,
48
+ CheckboxGroup: () => CheckboxGroup,
49
+ Divider: () => Divider,
50
+ Dropdown: () => Dropdown,
51
+ Input: () => Input,
52
+ Kbd: () => Kbd,
53
+ MarclayProvider: () => MarclayProvider,
54
+ Modal: () => Modal,
55
+ Navbar: () => Navbar,
56
+ PRESETS: () => PRESETS,
57
+ Progress: () => Progress,
58
+ Radio: () => Radio,
59
+ Range: () => Range,
60
+ Select: () => Select,
61
+ Skeleton: () => Skeleton,
62
+ Spinner: () => Spinner,
63
+ Stack: () => Stack,
64
+ Stat: () => Stat,
65
+ Switch: () => Switch,
66
+ Tabs: () => Tabs,
67
+ Textarea: () => Textarea,
68
+ ThemeMenu: () => ThemeMenu,
69
+ ThemeProvider: () => ThemeProvider,
70
+ ThemeToggle: () => ThemeToggle,
71
+ ToastProvider: () => ToastProvider,
72
+ Tooltip: () => Tooltip,
73
+ useTheme: () => useTheme,
74
+ useToast: () => useToast
75
+ });
76
+ module.exports = __toCommonJS(index_exports);
77
+
78
+ // src/theming/ThemeProvider.tsx
79
+ var import_react = require("react");
80
+
81
+ // src/utils/color.ts
82
+ var WHITE = { r: 255, g: 255, b: 255 };
83
+ var BLACK = { r: 0, g: 0, b: 0 };
84
+ function clamp(n, min = 0, max = 255) {
85
+ return Math.min(max, Math.max(min, n));
86
+ }
87
+ function parseHex(hex) {
88
+ let h = hex.trim().replace("#", "");
89
+ if (h.length === 3) h = h.split("").map((c) => c + c).join("");
90
+ if (h.length !== 6 || /[^0-9a-f]/i.test(h)) return { ...BLACK };
91
+ const n = parseInt(h, 16);
92
+ return { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
93
+ }
94
+ function toHex(c) {
95
+ const part = (v) => clamp(Math.round(v)).toString(16).padStart(2, "0");
96
+ return `#${part(c.r)}${part(c.g)}${part(c.b)}`;
97
+ }
98
+ function rgba(c, a) {
99
+ return `rgba(${clamp(Math.round(c.r))}, ${clamp(Math.round(c.g))}, ${clamp(Math.round(c.b))}, ${a})`;
100
+ }
101
+ function mix(a, b, t) {
102
+ return {
103
+ r: a.r + (b.r - a.r) * t,
104
+ g: a.g + (b.g - a.g) * t,
105
+ b: a.b + (b.b - a.b) * t
106
+ };
107
+ }
108
+ function lighten(hex, t) {
109
+ return toHex(mix(parseHex(hex), WHITE, t));
110
+ }
111
+ function darken(hex, t) {
112
+ return toHex(mix(parseHex(hex), BLACK, t));
113
+ }
114
+ function alpha(hex, a) {
115
+ return rgba(parseHex(hex), a);
116
+ }
117
+ function readableInk(base) {
118
+ const { r, g, b } = mix(parseHex(base), WHITE, 0.12);
119
+ const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
120
+ return lum > 0.62 ? "#3a2d20" : "#fff8f2";
121
+ }
122
+
123
+ // src/theming/presets.ts
124
+ var PRESETS = [
125
+ {
126
+ id: "clay",
127
+ label: "Claymorphism",
128
+ description: "Warm terracotta clay, squircles, Quicksand \u2014 the signature MarclayUI look."
129
+ },
130
+ {
131
+ id: "neo",
132
+ label: "Neumorphism",
133
+ description: "Soft grey-blue extrusions, violet (light) / gold (dark) accent, circles, Poppins & Manrope."
134
+ }
135
+ ];
136
+ var PRESET_STORAGE_KEY = "mcl-preset";
137
+ var COLOR_SWATCHES = [
138
+ { name: "Terra", color: "#e0785a" },
139
+ { name: "Violet", color: "#7c5cff" },
140
+ { name: "Ocean", color: "#4a90d9" },
141
+ { name: "Forest", color: "#5a8a46" },
142
+ { name: "Magenta", color: "#c74f9d" }
143
+ ];
144
+
145
+ // src/theming/ThemeProvider.tsx
146
+ var import_jsx_runtime = require("react/jsx-runtime");
147
+ var ThemeContext = (0, import_react.createContext)(null);
148
+ var STORAGE_KEY = "mcl-theme";
149
+ var TONES = [
150
+ ["primary", "primary", "p"],
151
+ ["secondary", "secondary", "s"],
152
+ ["accent", "accent", "a"],
153
+ ["success", "success", "c"],
154
+ ["danger", "danger", "d"],
155
+ ["warning", "warning", "w"],
156
+ ["info", "info", "i"]
157
+ ];
158
+ function systemMode() {
159
+ if (typeof window === "undefined" || !window.matchMedia) return "light";
160
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
161
+ }
162
+ function toneVars(base, dark) {
163
+ return {
164
+ base,
165
+ light: lighten(base, dark ? 0.24 : 0.16),
166
+ deep: darken(base, 0.32),
167
+ ink: readableInk(base),
168
+ clay: `inset -5px -6px 10px ${alpha(darken(base, 0.68), dark ? 0.5 : 0.3)}, inset 5px 6px 10px ${alpha(
169
+ lighten(base, 0.45),
170
+ dark ? 0.38 : 0.5
171
+ )}`
172
+ };
173
+ }
174
+ function colorVars(c, mode) {
175
+ const vars = {};
176
+ const dark = mode === "dark";
177
+ for (const [key, name, short] of TONES) {
178
+ const base = c[key];
179
+ if (!base) continue;
180
+ const t = toneVars(base, dark);
181
+ vars[`--mcl-${name}`] = t.base;
182
+ vars[`--mcl-${name}-2`] = t.light;
183
+ vars[`--mcl-${name}-deep`] = t.deep;
184
+ vars[`--mcl-${name}-ink`] = t.ink;
185
+ vars[`--mcl-clay-${short}`] = t.clay;
186
+ if (key === "primary") vars["--mcl-ring"] = alpha(base, dark ? 0.45 : 0.4);
187
+ }
188
+ if (c.bg) {
189
+ vars["--mcl-bg"] = c.bg;
190
+ vars["--mcl-sd"] = alpha(darken(c.bg, dark ? 0.78 : 0.4), dark ? 0.72 : 0.6);
191
+ vars["--mcl-sl"] = alpha(lighten(c.bg, dark ? 0.3 : 0.9), dark ? 0.07 : 0.95);
192
+ vars["--mcl-sheen"] = alpha(lighten(c.bg, 0.9), dark ? 0.08 : 0.5);
193
+ }
194
+ if (c.ink) vars["--mcl-ink"] = c.ink;
195
+ if (c.muted) vars["--mcl-muted"] = c.muted;
196
+ return vars;
197
+ }
198
+ function MarclayProvider({
199
+ children,
200
+ defaultMode = "system",
201
+ preset: initialPreset = "clay",
202
+ colors: initialColors
203
+ }) {
204
+ const [preference, setPreferenceState] = (0, import_react.useState)(defaultMode);
205
+ const [mode, setMode] = (0, import_react.useState)("light");
206
+ const [preset, setPresetState] = (0, import_react.useState)(initialPreset);
207
+ const [colors, setColorsState] = (0, import_react.useState)(initialColors ?? {});
208
+ const appliedKeys = (0, import_react.useRef)(/* @__PURE__ */ new Set());
209
+ (0, import_react.useEffect)(() => {
210
+ let stored = null;
211
+ let storedPreset = null;
212
+ try {
213
+ stored = localStorage.getItem(STORAGE_KEY);
214
+ storedPreset = localStorage.getItem(PRESET_STORAGE_KEY);
215
+ } catch {
216
+ stored = null;
217
+ }
218
+ setPreferenceState(stored ?? defaultMode);
219
+ if (storedPreset === "clay" || storedPreset === "neo") setPresetState(storedPreset);
220
+ }, []);
221
+ (0, import_react.useEffect)(() => {
222
+ const apply = () => {
223
+ const m = preference === "system" ? systemMode() : preference;
224
+ setMode(m);
225
+ document.documentElement.setAttribute("data-theme", m);
226
+ };
227
+ apply();
228
+ if (preference !== "system" || !window.matchMedia) return;
229
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
230
+ const onChange = () => apply();
231
+ mq.addEventListener?.("change", onChange);
232
+ return () => mq.removeEventListener?.("change", onChange);
233
+ }, [preference]);
234
+ (0, import_react.useEffect)(() => {
235
+ if (preset === "clay") document.documentElement.removeAttribute("data-preset");
236
+ else document.documentElement.setAttribute("data-preset", preset);
237
+ }, [preset]);
238
+ (0, import_react.useEffect)(() => {
239
+ const root = document.documentElement;
240
+ appliedKeys.current.forEach((k) => root.style.removeProperty(k));
241
+ appliedKeys.current.clear();
242
+ if (Object.keys(colors).length === 0) return;
243
+ const vars = colorVars(colors, mode);
244
+ for (const [k, v] of Object.entries(vars)) {
245
+ root.style.setProperty(k, v);
246
+ appliedKeys.current.add(k);
247
+ }
248
+ }, [colors, mode]);
249
+ const setPreference = (0, import_react.useCallback)((p) => {
250
+ setPreferenceState(p);
251
+ try {
252
+ localStorage.setItem(STORAGE_KEY, p);
253
+ } catch {
254
+ }
255
+ }, []);
256
+ const toggle = (0, import_react.useCallback)(() => {
257
+ setPreference(mode === "dark" ? "light" : "dark");
258
+ }, [mode, setPreference]);
259
+ const setPreset = (0, import_react.useCallback)((p) => {
260
+ setPresetState(p);
261
+ try {
262
+ localStorage.setItem(PRESET_STORAGE_KEY, p);
263
+ } catch {
264
+ }
265
+ setColorsState({});
266
+ }, []);
267
+ const setColors = (0, import_react.useCallback)((c) => {
268
+ setColorsState((prev) => ({ ...prev, ...c }));
269
+ }, []);
270
+ const resetColors = (0, import_react.useCallback)(() => setColorsState({}), []);
271
+ const value = (0, import_react.useMemo)(
272
+ () => ({
273
+ mode,
274
+ preference,
275
+ setPreference,
276
+ toggle,
277
+ preset,
278
+ setPreset,
279
+ colors,
280
+ setColors,
281
+ resetColors
282
+ }),
283
+ [mode, preference, setPreference, toggle, preset, setPreset, colors, setColors, resetColors]
284
+ );
285
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeContext.Provider, { value, children });
286
+ }
287
+ function useTheme() {
288
+ const ctx = (0, import_react.useContext)(ThemeContext);
289
+ if (!ctx) throw new Error("useTheme must be used inside <MarclayProvider>.");
290
+ return ctx;
291
+ }
292
+ var ThemeProvider = MarclayProvider;
293
+
294
+ // src/theming/ThemeToggle.tsx
295
+ var import_jsx_runtime2 = require("react/jsx-runtime");
296
+ function ThemeToggle({ className = "" }) {
297
+ const { mode, toggle } = useTheme();
298
+ const next = mode === "dark" ? "light" : "dark";
299
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
300
+ "button",
301
+ {
302
+ type: "button",
303
+ className: `mcl-theme-toggle ${className}`.trim(),
304
+ onClick: toggle,
305
+ "aria-label": `Switch to ${next} mode`,
306
+ title: `Switch to ${next} mode`,
307
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "mcl-theme-toggle-icon", "aria-hidden": "true", children: mode === "dark" ? "\u2600\uFE0F" : "\u{1F319}" })
308
+ }
309
+ );
310
+ }
311
+
312
+ // src/theming/ThemeMenu.tsx
313
+ var import_react2 = require("react");
314
+ var import_jsx_runtime3 = require("react/jsx-runtime");
315
+ var MODE_OPTIONS = [
316
+ { key: "light", label: "Light", icon: "\u2600\uFE0F" },
317
+ { key: "system", label: "System", icon: "\u{1F5A5}\uFE0F" },
318
+ { key: "dark", label: "Dark", icon: "\u{1F319}" }
319
+ ];
320
+ function ThemeMenu({ className = "" }) {
321
+ const {
322
+ mode,
323
+ preference,
324
+ setPreference,
325
+ preset,
326
+ setPreset,
327
+ colors,
328
+ setColors,
329
+ resetColors
330
+ } = useTheme();
331
+ const [open, setOpen] = (0, import_react2.useState)(false);
332
+ const [flipUp, setFlipUp] = (0, import_react2.useState)(false);
333
+ const shellRef = (0, import_react2.useRef)(null);
334
+ const panelRef = (0, import_react2.useRef)(null);
335
+ const triggerRef = (0, import_react2.useRef)(null);
336
+ (0, import_react2.useEffect)(() => {
337
+ if (!open) return;
338
+ const onDown = (e) => {
339
+ if (shellRef.current && !shellRef.current.contains(e.target)) {
340
+ setOpen(false);
341
+ triggerRef.current?.focus();
342
+ }
343
+ };
344
+ const onKey = (e) => {
345
+ if (e.key === "Escape") {
346
+ setOpen(false);
347
+ triggerRef.current?.focus();
348
+ }
349
+ };
350
+ document.addEventListener("mousedown", onDown);
351
+ document.addEventListener("keydown", onKey);
352
+ return () => {
353
+ document.removeEventListener("mousedown", onDown);
354
+ document.removeEventListener("keydown", onKey);
355
+ };
356
+ }, [open]);
357
+ (0, import_react2.useEffect)(() => {
358
+ if (open) {
359
+ panelRef.current?.focus();
360
+ const t = window.setTimeout(() => {
361
+ const trig = triggerRef.current;
362
+ const panel = panelRef.current;
363
+ if (!trig || !panel) return;
364
+ const r = trig.getBoundingClientRect();
365
+ setFlipUp(window.innerHeight - r.bottom < panel.offsetHeight + 12);
366
+ }, 0);
367
+ return () => window.clearTimeout(t);
368
+ }
369
+ setFlipUp(false);
370
+ }, [open]);
371
+ const activeSwatch = colors.primary?.toLowerCase();
372
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { ref: shellRef, className: `mcl-theme-menu-shell ${className}`.trim(), children: [
373
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
374
+ "button",
375
+ {
376
+ ref: triggerRef,
377
+ type: "button",
378
+ className: "mcl-theme-toggle",
379
+ "aria-haspopup": "dialog",
380
+ "aria-expanded": open,
381
+ "aria-label": "Customize theme",
382
+ title: "Customize theme",
383
+ onClick: () => setOpen((o) => !o),
384
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "mcl-theme-toggle-icon", "aria-hidden": "true", children: preference === "system" ? "\u{1F5A5}\uFE0F" : mode === "dark" ? "\u{1F319}" : "\u2600\uFE0F" })
385
+ }
386
+ ),
387
+ open && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
388
+ "div",
389
+ {
390
+ ref: panelRef,
391
+ tabIndex: -1,
392
+ role: "dialog",
393
+ "aria-label": "Customize theme",
394
+ className: `mcl-theme-menu${flipUp ? " mcl-theme-menu-up" : ""}`,
395
+ children: [
396
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mcl-theme-menu-section", children: [
397
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "mcl-theme-menu-label", children: [
398
+ "Mode \xB7 ",
399
+ mode
400
+ ] }),
401
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mcl-theme-menu-chips", children: MODE_OPTIONS.map((m) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
402
+ "button",
403
+ {
404
+ type: "button",
405
+ className: `mcl-theme-menu-chip${preference === m.key ? " mcl-theme-menu-chip-on" : ""}`,
406
+ "aria-pressed": preference === m.key,
407
+ onClick: () => setPreference(m.key),
408
+ children: [
409
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { "aria-hidden": "true", children: m.icon }),
410
+ " ",
411
+ m.label
412
+ ]
413
+ },
414
+ m.key
415
+ )) })
416
+ ] }),
417
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mcl-theme-menu-section", children: [
418
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "mcl-theme-menu-label", children: "Style preset" }),
419
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mcl-theme-menu-chips", children: PRESETS.map((p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
420
+ "button",
421
+ {
422
+ type: "button",
423
+ className: `mcl-theme-menu-chip${preset === p.id ? " mcl-theme-menu-chip-on" : ""}`,
424
+ "aria-pressed": preset === p.id,
425
+ onClick: () => setPreset(p.id),
426
+ children: p.label
427
+ },
428
+ p.id
429
+ )) })
430
+ ] }),
431
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "mcl-theme-menu-section", children: [
432
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "mcl-theme-menu-label", children: "Primary color" }),
433
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mcl-theme-menu-swatches", children: COLOR_SWATCHES.map((s) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
434
+ "button",
435
+ {
436
+ type: "button",
437
+ className: `mcl-theme-menu-swatch${activeSwatch === s.color.toLowerCase() ? " mcl-theme-menu-swatch-on" : ""}`,
438
+ style: { background: s.color },
439
+ title: s.name,
440
+ "aria-label": `Primary ${s.name}`,
441
+ "aria-pressed": activeSwatch === s.color.toLowerCase(),
442
+ onClick: () => setColors({ primary: s.color })
443
+ },
444
+ s.color
445
+ )) }),
446
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "mcl-theme-menu-reset", onClick: resetColors, children: "Reset colors" })
447
+ ] })
448
+ ]
449
+ }
450
+ )
451
+ ] });
452
+ }
453
+
454
+ // src/components/button/button.tsx
455
+ var import_react3 = __toESM(require("react"));
456
+ var import_jsx_runtime4 = require("react/jsx-runtime");
457
+ var Button = import_react3.default.forwardRef(
458
+ function Button2({
459
+ variant = "soft",
460
+ size = "md",
461
+ loading = false,
462
+ block = false,
463
+ className = "",
464
+ disabled,
465
+ children,
466
+ type = "button",
467
+ href,
468
+ ...rest
469
+ }, ref) {
470
+ const cls = [
471
+ "mcl-btn",
472
+ `mcl-btn-${variant}`,
473
+ `mcl-btn-${size}`,
474
+ block ? "mcl-btn-block" : "",
475
+ loading ? "mcl-btn-loading" : "",
476
+ className
477
+ ].filter(Boolean).join(" ");
478
+ if (href) {
479
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
480
+ "a",
481
+ {
482
+ ref,
483
+ href,
484
+ className: cls,
485
+ "aria-disabled": disabled || void 0,
486
+ ...rest,
487
+ children: [
488
+ loading && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "mcl-btn-spinner", "aria-hidden": "true" }),
489
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "mcl-btn-label", children })
490
+ ]
491
+ }
492
+ );
493
+ }
494
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
495
+ "button",
496
+ {
497
+ ref,
498
+ type,
499
+ className: cls,
500
+ disabled: disabled || loading,
501
+ ...rest,
502
+ children: [
503
+ loading && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "mcl-btn-spinner", "aria-hidden": "true" }),
504
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "mcl-btn-label", children })
505
+ ]
506
+ }
507
+ );
508
+ }
509
+ );
510
+ function ButtonGroup({ children, className = "", ...rest }) {
511
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `mcl-btn-group ${className}`.trim(), role: "group", ...rest, children });
512
+ }
513
+
514
+ // src/components/kbd/kbd.tsx
515
+ var import_jsx_runtime5 = require("react/jsx-runtime");
516
+ function Kbd({ children, className = "", ...rest }) {
517
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("kbd", { className: `mcl-kbd ${className}`.trim(), ...rest, children });
518
+ }
519
+
520
+ // src/components/card/card.tsx
521
+ var import_jsx_runtime6 = require("react/jsx-runtime");
522
+ function Card({ hover = false, className = "", ...rest }) {
523
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: `mcl-card${hover ? " mcl-card-hover" : ""} ${className}`.trim(), ...rest });
524
+ }
525
+ function CardHeader({ className = "", ...rest }) {
526
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: `mcl-card-header ${className}`.trim(), ...rest });
527
+ }
528
+ function CardTitle({ className = "", ...rest }) {
529
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { className: `mcl-card-title ${className}`.trim(), ...rest });
530
+ }
531
+ function CardBody({ className = "", ...rest }) {
532
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: `mcl-card-body ${className}`.trim(), ...rest });
533
+ }
534
+ function CardFooter({ className = "", ...rest }) {
535
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: `mcl-card-footer ${className}`.trim(), ...rest });
536
+ }
537
+
538
+ // src/components/input/input.tsx
539
+ var import_react4 = __toESM(require("react"));
540
+ var import_jsx_runtime7 = require("react/jsx-runtime");
541
+ function fieldClasses(base, size, invalid) {
542
+ return [base, `${base}-${size}`, invalid ? `${base}-invalid` : ""].filter(Boolean).join(" ");
543
+ }
544
+ function Chrome({
545
+ id,
546
+ label,
547
+ hint,
548
+ error,
549
+ block,
550
+ children
551
+ }) {
552
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `mcl-field${block ? " mcl-field-block" : ""}`, children: [
553
+ label && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("label", { className: "mcl-label", htmlFor: id, children: label }),
554
+ children,
555
+ error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mcl-hint mcl-hint-error", role: "alert", children: error }) : hint ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mcl-hint", children: hint }) : null
556
+ ] });
557
+ }
558
+ function Input({ label, hint, error, size = "md", block = false, className = "", id, ...rest }) {
559
+ const autoId = import_react4.default.useId();
560
+ const inputId = id ?? autoId;
561
+ const input = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
562
+ "input",
563
+ {
564
+ id: inputId,
565
+ className: `${fieldClasses("mcl-input", size, !!error)}${block ? " mcl-input-block" : ""} ${className}`.trim(),
566
+ "aria-invalid": error ? true : void 0,
567
+ ...rest
568
+ }
569
+ );
570
+ if (!label && !hint && !error) return input;
571
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Chrome, { id: inputId, label, hint, error, block, children: input });
572
+ }
573
+ function Textarea({ label, hint, error, size = "md", block = true, className = "", id, rows = 4, ...rest }) {
574
+ const autoId = import_react4.default.useId();
575
+ const inputId = id ?? autoId;
576
+ const el = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
577
+ "textarea",
578
+ {
579
+ id: inputId,
580
+ rows,
581
+ className: `${fieldClasses("mcl-textarea", size, !!error)} ${className}`.trim(),
582
+ "aria-invalid": error ? true : void 0,
583
+ ...rest
584
+ }
585
+ );
586
+ if (!label && !hint && !error) return el;
587
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Chrome, { id: inputId, label, hint, error, block: true, children: el });
588
+ }
589
+
590
+ // src/components/select/select.tsx
591
+ var import_react5 = __toESM(require("react"));
592
+ var import_jsx_runtime8 = require("react/jsx-runtime");
593
+ function Select({
594
+ label,
595
+ hint,
596
+ error,
597
+ size = "md",
598
+ options,
599
+ placeholder,
600
+ className = "",
601
+ id,
602
+ children,
603
+ ...rest
604
+ }) {
605
+ const autoId = import_react5.default.useId();
606
+ const selectId = id ?? autoId;
607
+ const select = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: `mcl-select-shell ${className}`.trim(), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
608
+ "select",
609
+ {
610
+ id: selectId,
611
+ className: `mcl-select mcl-select-${size}${error ? " mcl-select-invalid" : ""}`,
612
+ "aria-invalid": error ? true : void 0,
613
+ ...rest,
614
+ children: [
615
+ placeholder && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "", disabled: true, children: placeholder }),
616
+ options?.map((o) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: o.value, children: o.label }, o.value)),
617
+ children
618
+ ]
619
+ }
620
+ ) });
621
+ if (!label && !hint && !error) return select;
622
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "mcl-field", children: [
623
+ label && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("label", { className: "mcl-label", htmlFor: selectId, children: label }),
624
+ select,
625
+ error ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "mcl-hint mcl-hint-error", role: "alert", children: error }) : hint ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "mcl-hint", children: hint }) : null
626
+ ] });
627
+ }
628
+
629
+ // src/components/checks/checks.tsx
630
+ var import_react6 = require("react");
631
+ var import_jsx_runtime9 = require("react/jsx-runtime");
632
+ function withLabel(input, label) {
633
+ if (label === void 0 || label === null) return input;
634
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "mcl-check", children: [
635
+ input,
636
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "mcl-check-label", children: label })
637
+ ] });
638
+ }
639
+ function Checkbox({ label, indeterminate = false, className = "", ...rest }) {
640
+ const inputRef = (0, import_react6.useRef)(null);
641
+ (0, import_react6.useEffect)(() => {
642
+ if (inputRef.current) inputRef.current.indeterminate = indeterminate;
643
+ }, [indeterminate]);
644
+ return withLabel(
645
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
646
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { ref: inputRef, type: "checkbox", className: `mcl-check-input ${className}`.trim(), ...rest }),
647
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "mcl-check-box", "aria-hidden": "true" })
648
+ ] }),
649
+ label
650
+ );
651
+ }
652
+ function CheckboxGroup({
653
+ options,
654
+ value,
655
+ defaultValue = [],
656
+ onChange,
657
+ selectAll = false,
658
+ selectAllLabel = "Select all",
659
+ label,
660
+ disabled = false,
661
+ className = ""
662
+ }) {
663
+ const [inner, setInner] = (0, import_react6.useState)(defaultValue);
664
+ const allRef = (0, import_react6.useRef)(null);
665
+ const selected = value ?? inner;
666
+ const enabled = options.filter((o) => !o.disabled).map((o) => o.value);
667
+ const allOn = enabled.length > 0 && enabled.every((v) => selected.includes(v));
668
+ const someOn = enabled.some((v) => selected.includes(v));
669
+ (0, import_react6.useEffect)(() => {
670
+ if (allRef.current) allRef.current.indeterminate = someOn && !allOn;
671
+ }, [someOn, allOn]);
672
+ const commit = (next) => {
673
+ setInner(next);
674
+ onChange?.(next);
675
+ };
676
+ const toggle = (v) => {
677
+ commit(selected.includes(v) ? selected.filter((x) => x !== v) : [...selected, v]);
678
+ };
679
+ const toggleAll = () => {
680
+ commit(allOn ? selected.filter((v) => !enabled.includes(v)) : Array.from(/* @__PURE__ */ new Set([...selected, ...enabled])));
681
+ };
682
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
683
+ "div",
684
+ {
685
+ className: `mcl-check-group ${className}`.trim(),
686
+ role: "group",
687
+ "aria-label": typeof label === "string" ? label : void 0,
688
+ children: [
689
+ label && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "mcl-label", children: label }),
690
+ selectAll && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: `mcl-check mcl-check-group-all${disabled ? " mcl-check-disabled" : ""}`, children: [
691
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
692
+ "input",
693
+ {
694
+ ref: allRef,
695
+ type: "checkbox",
696
+ className: "mcl-check-input",
697
+ checked: allOn,
698
+ disabled,
699
+ onChange: toggleAll
700
+ }
701
+ ),
702
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "mcl-check-box", "aria-hidden": "true" }),
703
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "mcl-check-label", children: selectAllLabel })
704
+ ] }),
705
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "mcl-check-group-items", children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: `mcl-check${o.disabled || disabled ? " mcl-check-disabled" : ""}`, children: [
706
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
707
+ "input",
708
+ {
709
+ type: "checkbox",
710
+ className: "mcl-check-input",
711
+ checked: selected.includes(o.value),
712
+ disabled: o.disabled || disabled,
713
+ onChange: () => toggle(o.value)
714
+ }
715
+ ),
716
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "mcl-check-box", "aria-hidden": "true" }),
717
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "mcl-check-label", children: o.label })
718
+ ] }, o.value)) })
719
+ ]
720
+ }
721
+ );
722
+ }
723
+ function Radio({ label, className = "", ...rest }) {
724
+ return withLabel(
725
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
726
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "radio", className: `mcl-check-input ${className}`.trim(), ...rest }),
727
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "mcl-check-box mcl-radio-box", "aria-hidden": "true" })
728
+ ] }),
729
+ label
730
+ );
731
+ }
732
+ function Switch({ label, className = "", ...rest }) {
733
+ return withLabel(
734
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
735
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
736
+ "input",
737
+ {
738
+ type: "checkbox",
739
+ role: "switch",
740
+ className: `mcl-switch-input ${className}`.trim(),
741
+ ...rest
742
+ }
743
+ ),
744
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "mcl-switch-track", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "mcl-switch-knob" }) })
745
+ ] }),
746
+ label
747
+ );
748
+ }
749
+
750
+ // src/components/dropdown/dropdown.tsx
751
+ var import_react7 = require("react");
752
+ var import_jsx_runtime10 = require("react/jsx-runtime");
753
+ function Dropdown({
754
+ items,
755
+ value,
756
+ defaultValue,
757
+ onChange,
758
+ multiple = false,
759
+ placeholder = "Select\u2026",
760
+ label,
761
+ hint,
762
+ size = "md",
763
+ block = false,
764
+ disabled = false,
765
+ className = ""
766
+ }) {
767
+ const [open, setOpen] = (0, import_react7.useState)(false);
768
+ const [inner, setInner] = (0, import_react7.useState)(defaultValue);
769
+ const [active, setActive] = (0, import_react7.useState)(0);
770
+ const [flip, setFlip] = (0, import_react7.useState)({ up: false, left: false });
771
+ const shellRef = (0, import_react7.useRef)(null);
772
+ const menuRef = (0, import_react7.useRef)(null);
773
+ const triggerRef = (0, import_react7.useRef)(null);
774
+ const current = value ?? inner;
775
+ const selectedValues = multiple ? Array.isArray(current) ? current : [] : [];
776
+ const singleValue = !multiple && !Array.isArray(current) ? current : void 0;
777
+ const labelFor = (v) => items.find((i) => i.value === v)?.label;
778
+ let triggerText = placeholder;
779
+ if (multiple) {
780
+ if (selectedValues.length > 0) {
781
+ const labels = items.filter((i) => selectedValues.includes(i.value)).map((i) => i.label);
782
+ triggerText = labels.length <= 2 ? labels.join(", ") : `${labels.length} selected`;
783
+ }
784
+ } else if (singleValue !== void 0) {
785
+ triggerText = labelFor(singleValue) ?? singleValue;
786
+ }
787
+ const hasSelection = multiple ? selectedValues.length > 0 : singleValue !== void 0 && singleValue !== "";
788
+ (0, import_react7.useEffect)(() => {
789
+ if (!open) return;
790
+ const onDown = (e) => {
791
+ if (shellRef.current && !shellRef.current.contains(e.target)) {
792
+ setOpen(false);
793
+ triggerRef.current?.focus();
794
+ }
795
+ };
796
+ document.addEventListener("mousedown", onDown);
797
+ return () => document.removeEventListener("mousedown", onDown);
798
+ }, [open]);
799
+ (0, import_react7.useEffect)(() => {
800
+ if (!open) return;
801
+ const firstSelected = multiple ? items.findIndex((i) => selectedValues.includes(i.value)) : items.findIndex((i) => i.value === singleValue);
802
+ const firstEnabled = items.findIndex((i) => !i.disabled);
803
+ const idx = firstSelected >= 0 ? firstSelected : Math.max(firstEnabled, 0);
804
+ setActive(idx);
805
+ menuRef.current?.focus();
806
+ const t = window.setTimeout(() => {
807
+ const el = menuRef.current?.children[idx];
808
+ if (el && typeof el.scrollIntoView === "function") el.scrollIntoView({ block: "nearest" });
809
+ }, 0);
810
+ return () => window.clearTimeout(t);
811
+ }, [open]);
812
+ (0, import_react7.useEffect)(() => {
813
+ if (!open) return;
814
+ const t = window.setTimeout(() => {
815
+ const trig = triggerRef.current;
816
+ const menu = menuRef.current;
817
+ if (!trig || !menu) return;
818
+ const r = trig.getBoundingClientRect();
819
+ const m = menu.getBoundingClientRect();
820
+ const below = window.innerHeight - r.bottom;
821
+ const above = r.top;
822
+ setFlip({
823
+ up: below < m.height + 12 && above > below,
824
+ left: r.left + Math.max(m.width, r.width) > window.innerWidth - 12
825
+ });
826
+ }, 0);
827
+ return () => window.clearTimeout(t);
828
+ }, [open]);
829
+ const close = (refocus = true) => {
830
+ setOpen(false);
831
+ if (refocus) triggerRef.current?.focus();
832
+ };
833
+ const commit = (v) => {
834
+ if (multiple) {
835
+ const next = selectedValues.includes(v) ? selectedValues.filter((x) => x !== v) : [...selectedValues, v];
836
+ setInner(next);
837
+ onChange?.(next);
838
+ } else {
839
+ setInner(v);
840
+ onChange?.(v);
841
+ close();
842
+ }
843
+ };
844
+ const move = (dir) => {
845
+ const enabled = items.map((it, i) => it.disabled ? -1 : i).filter((i) => i >= 0);
846
+ if (enabled.length === 0) return;
847
+ const pos = enabled.indexOf(active);
848
+ const next = enabled[(pos + dir + enabled.length) % enabled.length];
849
+ setActive(next);
850
+ const el = menuRef.current?.children[next];
851
+ if (el && typeof el.scrollIntoView === "function") el.scrollIntoView({ block: "nearest" });
852
+ };
853
+ const onMenuKeyDown = (e) => {
854
+ if (e.key === "Escape") {
855
+ e.preventDefault();
856
+ close();
857
+ } else if (e.key === "ArrowDown") {
858
+ e.preventDefault();
859
+ move(1);
860
+ } else if (e.key === "ArrowUp") {
861
+ e.preventDefault();
862
+ move(-1);
863
+ } else if (e.key === "Home") {
864
+ e.preventDefault();
865
+ const first = items.findIndex((i) => !i.disabled);
866
+ if (first >= 0) setActive(first);
867
+ } else if (e.key === "End") {
868
+ e.preventDefault();
869
+ const last = items.map((i, idx) => i.disabled ? -1 : idx).filter((i) => i >= 0).pop();
870
+ if (last !== void 0) setActive(last);
871
+ } else if (e.key === "Enter" || e.key === " ") {
872
+ e.preventDefault();
873
+ const it = items[active];
874
+ if (it && !it.disabled) commit(it.value);
875
+ } else if (e.key === "Tab") {
876
+ setOpen(false);
877
+ }
878
+ };
879
+ const onTriggerKeyDown = (e) => {
880
+ if (!open && e.key === "ArrowDown") {
881
+ e.preventDefault();
882
+ setOpen(true);
883
+ }
884
+ };
885
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: `mcl-field${block ? " mcl-field-block" : ""} ${className}`.trim(), children: [
886
+ label && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "mcl-label", children: label }),
887
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
888
+ "div",
889
+ {
890
+ ref: shellRef,
891
+ className: `mcl-dropdown-shell${block ? " mcl-dropdown-block" : ""}`,
892
+ children: [
893
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
894
+ "button",
895
+ {
896
+ ref: triggerRef,
897
+ type: "button",
898
+ className: `mcl-dropdown-trigger mcl-dropdown-${size}`,
899
+ "aria-haspopup": "listbox",
900
+ "aria-expanded": open,
901
+ disabled,
902
+ onClick: () => setOpen((o) => !o),
903
+ onKeyDown: onTriggerKeyDown,
904
+ children: [
905
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: `mcl-dropdown-value${hasSelection ? "" : " mcl-dropdown-placeholder"}`, children: triggerText }),
906
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "mcl-dropdown-chevron", "aria-hidden": "true" })
907
+ ]
908
+ }
909
+ ),
910
+ open && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
911
+ "div",
912
+ {
913
+ ref: menuRef,
914
+ tabIndex: -1,
915
+ role: "listbox",
916
+ "aria-multiselectable": multiple || void 0,
917
+ className: [
918
+ "mcl-dropdown-menu",
919
+ "mcl-scroll",
920
+ `mcl-dropdown-${size}`,
921
+ flip.up ? "mcl-dropdown-menu-up" : "",
922
+ flip.left ? "mcl-dropdown-menu-left" : ""
923
+ ].filter(Boolean).join(" "),
924
+ onKeyDown: onMenuKeyDown,
925
+ children: items.map((it, i) => {
926
+ const selected = multiple ? selectedValues.includes(it.value) : singleValue === it.value;
927
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
928
+ "div",
929
+ {
930
+ role: "option",
931
+ "aria-selected": selected,
932
+ "aria-disabled": it.disabled || void 0,
933
+ className: [
934
+ "mcl-dropdown-item",
935
+ i === active ? "mcl-dropdown-item-active" : "",
936
+ selected ? "mcl-dropdown-item-selected" : "",
937
+ it.disabled ? "mcl-dropdown-item-disabled" : ""
938
+ ].filter(Boolean).join(" "),
939
+ onMouseEnter: () => setActive(i),
940
+ onClick: () => {
941
+ if (!it.disabled) commit(it.value);
942
+ },
943
+ children: [
944
+ multiple && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "mcl-dropdown-check", "aria-hidden": "true" }),
945
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "mcl-dropdown-item-label", children: it.label }),
946
+ !multiple && selected && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "mcl-dropdown-tick", "aria-hidden": "true", children: "\u2713" })
947
+ ]
948
+ },
949
+ it.value
950
+ );
951
+ })
952
+ }
953
+ )
954
+ ]
955
+ }
956
+ ),
957
+ hint && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mcl-hint", children: hint })
958
+ ] });
959
+ }
960
+
961
+ // src/components/range/range.tsx
962
+ var import_react8 = __toESM(require("react"));
963
+ var import_jsx_runtime11 = require("react/jsx-runtime");
964
+ function Range({
965
+ label,
966
+ hint,
967
+ showValue = false,
968
+ value,
969
+ defaultValue,
970
+ onChange,
971
+ className = "",
972
+ id,
973
+ ...rest
974
+ }) {
975
+ const autoId = import_react8.default.useId();
976
+ const inputId = id ?? autoId;
977
+ const isControlled = value !== void 0;
978
+ const [inner, setInner] = (0, import_react8.useState)(
979
+ () => value !== void 0 ? String(value) : defaultValue !== void 0 ? String(defaultValue) : "0"
980
+ );
981
+ const current = isControlled ? String(value) : inner;
982
+ const input = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
983
+ "input",
984
+ {
985
+ id: inputId,
986
+ type: "range",
987
+ className: `mcl-range ${className}`.trim(),
988
+ value: isControlled ? value : inner,
989
+ onChange: (e) => {
990
+ if (!isControlled) setInner(e.target.value);
991
+ onChange?.(e);
992
+ },
993
+ ...rest
994
+ }
995
+ );
996
+ const field = /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "mcl-field", children: [
997
+ label && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { className: "mcl-range-head", htmlFor: inputId, children: [
998
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "mcl-label", children: label }),
999
+ showValue && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "mcl-range-value", children: current })
1000
+ ] }),
1001
+ input,
1002
+ hint && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "mcl-hint", children: hint })
1003
+ ] });
1004
+ if (!label && !hint) return input;
1005
+ return field;
1006
+ }
1007
+
1008
+ // src/components/badge/badge.tsx
1009
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1010
+ function Badge({ variant = "neutral", solid = false, className = "", ...rest }) {
1011
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1012
+ "span",
1013
+ {
1014
+ className: `mcl-badge mcl-badge-${variant}${solid ? " mcl-badge-solid" : ""} ${className}`.trim(),
1015
+ ...rest
1016
+ }
1017
+ );
1018
+ }
1019
+
1020
+ // src/components/alert/alert.tsx
1021
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1022
+ var DEFAULT_ICONS = {
1023
+ success: "\u2713",
1024
+ danger: "\u2715",
1025
+ warning: "!",
1026
+ info: "i"
1027
+ };
1028
+ function Alert({
1029
+ variant = "info",
1030
+ title,
1031
+ icon,
1032
+ onClose,
1033
+ className = "",
1034
+ children,
1035
+ ...rest
1036
+ }) {
1037
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `mcl-alert mcl-alert-${variant} ${className}`.trim(), role: "alert", ...rest, children: [
1038
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "mcl-alert-icon", "aria-hidden": "true", children: icon ?? DEFAULT_ICONS[variant] }),
1039
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "mcl-alert-content", children: [
1040
+ title && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "mcl-alert-title", children: title }),
1041
+ children
1042
+ ] }),
1043
+ onClose && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: "mcl-alert-close", onClick: onClose, "aria-label": "Dismiss", children: "\u2715" })
1044
+ ] });
1045
+ }
1046
+
1047
+ // src/components/avatar/avatar.tsx
1048
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1049
+ function initialsOf(name) {
1050
+ const parts = name.trim().split(/\s+/).slice(0, 2);
1051
+ return parts.map((p) => p[0]?.toUpperCase() ?? "").join("");
1052
+ }
1053
+ function Avatar({
1054
+ src,
1055
+ alt,
1056
+ name,
1057
+ size = "md",
1058
+ status,
1059
+ gradient = false,
1060
+ className = "",
1061
+ children,
1062
+ ...rest
1063
+ }) {
1064
+ const label = alt ?? (name ? `${name}'s avatar` : "avatar");
1065
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1066
+ "span",
1067
+ {
1068
+ className: `mcl-avatar mcl-avatar-${size}${gradient ? " mcl-avatar-gradient" : ""} ${className}`.trim(),
1069
+ role: "img",
1070
+ "aria-label": label,
1071
+ ...rest,
1072
+ children: [
1073
+ src ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("img", { src, alt: "", className: "mcl-avatar-img", loading: "lazy", decoding: "async" }) : children ?? initialsOf(name ?? "??") ?? "",
1074
+ status && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: `mcl-avatar-status mcl-avatar-status-${status}`, "aria-hidden": "true" })
1075
+ ]
1076
+ }
1077
+ );
1078
+ }
1079
+ function AvatarGroup({ className = "", children, ...rest }) {
1080
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: `mcl-avatar-group ${className}`.trim(), ...rest, children });
1081
+ }
1082
+
1083
+ // src/components/progress/progress.tsx
1084
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1085
+ function Progress({
1086
+ value = 0,
1087
+ max = 100,
1088
+ tone = "primary",
1089
+ size = "md",
1090
+ label,
1091
+ showValue = false,
1092
+ indeterminate = false,
1093
+ className = ""
1094
+ }) {
1095
+ const pct = Math.max(0, Math.min(100, value / max * 100));
1096
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1097
+ "div",
1098
+ {
1099
+ className: `mcl-progress mcl-progress-${size} ${className}`.trim(),
1100
+ role: "progressbar",
1101
+ "aria-valuemin": 0,
1102
+ "aria-valuemax": max,
1103
+ "aria-valuenow": indeterminate ? void 0 : Math.round(pct),
1104
+ children: [
1105
+ (label || showValue) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "mcl-progress-head", children: [
1106
+ label && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: label }),
1107
+ showValue && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "mcl-progress-value", children: indeterminate ? "\u2026" : `${Math.round(pct)}%` })
1108
+ ] }),
1109
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "mcl-progress-track", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1110
+ "span",
1111
+ {
1112
+ className: `mcl-progress-fill mcl-progress-fill-${tone}${indeterminate ? " mcl-progress-fill-indeterminate" : ""}`,
1113
+ style: indeterminate ? void 0 : { width: `${pct}%` }
1114
+ }
1115
+ ) })
1116
+ ]
1117
+ }
1118
+ );
1119
+ }
1120
+
1121
+ // src/components/spinner/spinner.tsx
1122
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1123
+ function Spinner({ size = "md", className = "" }) {
1124
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: `mcl-spinner mcl-spinner-${size} ${className}`.trim(), role: "status", "aria-label": "Loading" });
1125
+ }
1126
+
1127
+ // src/components/skeleton/skeleton.tsx
1128
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1129
+ function Skeleton({ variant = "text", width, height, count = 1, className = "" }) {
1130
+ const lines = variant === "text" ? Math.max(1, count) : 1;
1131
+ const style = (last) => ({
1132
+ width: width ?? (variant === "circle" ? 48 : "100%"),
1133
+ height: height ?? (variant === "text" ? 14 : variant === "circle" ? 48 : 96),
1134
+ ...variant === "text" && count > 1 && last ? { width: "62%" } : null
1135
+ });
1136
+ if (lines === 1) {
1137
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1138
+ "span",
1139
+ {
1140
+ className: `mcl-skeleton mcl-skeleton-${variant} ${className}`.trim(),
1141
+ style: style(true),
1142
+ "aria-hidden": "true"
1143
+ }
1144
+ );
1145
+ }
1146
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: `mcl-skeleton-lines ${className}`.trim(), "aria-hidden": "true", children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "mcl-skeleton mcl-skeleton-text", style: style(i === lines - 1) }, i)) });
1147
+ }
1148
+
1149
+ // src/components/modal/modal.tsx
1150
+ var import_react9 = require("react");
1151
+ var import_react_dom = require("react-dom");
1152
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1153
+ var FOCUSABLE = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
1154
+ function Modal({
1155
+ open,
1156
+ onClose,
1157
+ title,
1158
+ footer,
1159
+ size = "md",
1160
+ closeOnBackdrop = true,
1161
+ closeOnEsc = true,
1162
+ children,
1163
+ className = ""
1164
+ }) {
1165
+ const [mounted, setMounted] = (0, import_react9.useState)(false);
1166
+ const panelRef = (0, import_react9.useRef)(null);
1167
+ const lastFocusedRef = (0, import_react9.useRef)(null);
1168
+ const titleId = (0, import_react9.useId)();
1169
+ (0, import_react9.useEffect)(() => setMounted(true), []);
1170
+ (0, import_react9.useEffect)(() => {
1171
+ if (!open) return;
1172
+ lastFocusedRef.current = document.activeElement;
1173
+ const onKey = (e) => {
1174
+ if (e.key === "Escape" && closeOnEsc) onClose();
1175
+ };
1176
+ document.addEventListener("keydown", onKey);
1177
+ const prevOverflow = document.body.style.overflow;
1178
+ document.body.style.overflow = "hidden";
1179
+ panelRef.current?.focus();
1180
+ return () => {
1181
+ document.removeEventListener("keydown", onKey);
1182
+ document.body.style.overflow = prevOverflow;
1183
+ lastFocusedRef.current?.focus?.();
1184
+ };
1185
+ }, [open, onClose, closeOnEsc]);
1186
+ const trapFocus = (e) => {
1187
+ if (e.key !== "Tab" || !panelRef.current) return;
1188
+ const focusable = Array.from(panelRef.current.querySelectorAll(FOCUSABLE)).filter(
1189
+ (el) => el.offsetParent !== null
1190
+ );
1191
+ if (focusable.length === 0) {
1192
+ e.preventDefault();
1193
+ return;
1194
+ }
1195
+ const first = focusable[0];
1196
+ const last = focusable[focusable.length - 1];
1197
+ const active = document.activeElement;
1198
+ if (e.shiftKey && (active === first || !panelRef.current.contains(active))) {
1199
+ e.preventDefault();
1200
+ last.focus();
1201
+ } else if (!e.shiftKey && active === last) {
1202
+ e.preventDefault();
1203
+ first.focus();
1204
+ }
1205
+ };
1206
+ if (!open || !mounted) return null;
1207
+ return (0, import_react_dom.createPortal)(
1208
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1209
+ "div",
1210
+ {
1211
+ className: "mcl-modal-overlay",
1212
+ onMouseDown: (e) => {
1213
+ if (e.target === e.currentTarget && closeOnBackdrop) onClose();
1214
+ },
1215
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1216
+ "div",
1217
+ {
1218
+ ref: panelRef,
1219
+ className: `mcl-modal mcl-modal-${size} ${className}`.trim(),
1220
+ role: "dialog",
1221
+ "aria-modal": "true",
1222
+ "aria-labelledby": title ? titleId : void 0,
1223
+ tabIndex: -1,
1224
+ onKeyDown: trapFocus,
1225
+ children: [
1226
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "mcl-modal-header", children: [
1227
+ title ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { id: titleId, className: "mcl-modal-title", children: title }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", {}),
1228
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "mcl-modal-close", onClick: onClose, "aria-label": "Close dialog", children: "\u2715" })
1229
+ ] }),
1230
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "mcl-modal-body mcl-scroll", children }),
1231
+ footer && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "mcl-modal-footer", children: footer })
1232
+ ]
1233
+ }
1234
+ )
1235
+ }
1236
+ ),
1237
+ document.body
1238
+ );
1239
+ }
1240
+
1241
+ // src/components/tooltip/tooltip.tsx
1242
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1243
+ function Tooltip({ label, placement = "top", className = "", children }) {
1244
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: `mcl-tooltip mcl-tooltip-${placement} ${className}`.trim(), "data-mcl-tooltip": label, children });
1245
+ }
1246
+
1247
+ // src/components/tabs/tabs.tsx
1248
+ var import_react10 = require("react");
1249
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1250
+ function Tabs({ items, value, onChange, className = "" }) {
1251
+ const uid = (0, import_react10.useId)();
1252
+ const [inner, setInner] = (0, import_react10.useState)(0);
1253
+ const active = value ?? inner;
1254
+ const tabRefs = (0, import_react10.useRef)([]);
1255
+ const select = (i) => {
1256
+ if (items[i]?.disabled) return;
1257
+ setInner(i);
1258
+ onChange?.(i);
1259
+ };
1260
+ const onKeyDown = (e) => {
1261
+ const focusable = items.map((it, i) => it.disabled ? -1 : i).filter((i) => i >= 0);
1262
+ let next = -1;
1263
+ if (e.key === "ArrowRight") next = focusable[(focusable.indexOf(active) + 1) % focusable.length];
1264
+ if (e.key === "ArrowLeft") next = focusable[(focusable.indexOf(active) - 1 + focusable.length) % focusable.length];
1265
+ if (e.key === "Home") next = focusable[0];
1266
+ if (e.key === "End") next = focusable[focusable.length - 1];
1267
+ if (next >= 0 && next !== active) {
1268
+ e.preventDefault();
1269
+ select(next);
1270
+ tabRefs.current[next]?.focus();
1271
+ }
1272
+ };
1273
+ const current = items[active];
1274
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: `mcl-tabs ${className}`.trim(), children: [
1275
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "mcl-tablist", role: "tablist", "aria-label": "Tabs", onKeyDown, children: items.map((it, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1276
+ "button",
1277
+ {
1278
+ ref: (el) => {
1279
+ tabRefs.current[i] = el;
1280
+ },
1281
+ type: "button",
1282
+ role: "tab",
1283
+ id: `mcl-tab-${uid}-${it.key}`,
1284
+ "aria-selected": i === active,
1285
+ "aria-controls": `mcl-panel-${uid}-${it.key}`,
1286
+ tabIndex: i === active ? 0 : -1,
1287
+ className: `mcl-tab${i === active ? " mcl-tab-active" : ""}`,
1288
+ disabled: it.disabled,
1289
+ onClick: () => select(i),
1290
+ children: it.label
1291
+ },
1292
+ it.key
1293
+ )) }),
1294
+ current && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1295
+ "div",
1296
+ {
1297
+ role: "tabpanel",
1298
+ id: `mcl-panel-${uid}-${current.key}`,
1299
+ "aria-labelledby": `mcl-tab-${uid}-${current.key}`,
1300
+ className: "mcl-tabpanel",
1301
+ children: current.content
1302
+ },
1303
+ current.key
1304
+ )
1305
+ ] });
1306
+ }
1307
+
1308
+ // src/components/accordion/accordion.tsx
1309
+ var import_react11 = require("react");
1310
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1311
+ function Accordion({ items, defaultOpen = -1, exclusive = true, className = "" }) {
1312
+ const uid = (0, import_react11.useId)();
1313
+ const [openSet, setOpenSet] = (0, import_react11.useState)(
1314
+ () => new Set(defaultOpen >= 0 ? [defaultOpen] : [])
1315
+ );
1316
+ const panelRefs = (0, import_react11.useRef)([]);
1317
+ const [heights, setHeights] = (0, import_react11.useState)([]);
1318
+ const measure = () => {
1319
+ setHeights(items.map((_, i) => panelRefs.current[i]?.scrollHeight ?? 0));
1320
+ };
1321
+ (0, import_react11.useEffect)(() => {
1322
+ measure();
1323
+ window.addEventListener("resize", measure);
1324
+ return () => window.removeEventListener("resize", measure);
1325
+ }, [items, openSet]);
1326
+ const toggle = (i) => {
1327
+ if (!openSet.has(i)) {
1328
+ const h = panelRefs.current[i]?.scrollHeight ?? 0;
1329
+ setHeights((prev) => prev[i] === h ? prev : prev.map((x, j) => j === i ? h : x));
1330
+ }
1331
+ setOpenSet((prev) => {
1332
+ const next = new Set(exclusive ? [] : prev);
1333
+ if (prev.has(i)) next.delete(i);
1334
+ else next.add(i);
1335
+ return next;
1336
+ });
1337
+ };
1338
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: `mcl-accordion ${className}`.trim(), children: items.map((item, i) => {
1339
+ const open = openSet.has(i);
1340
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: `mcl-accordion-item${open ? " mcl-accordion-item-open" : ""}`, children: [
1341
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
1342
+ "button",
1343
+ {
1344
+ type: "button",
1345
+ className: "mcl-accordion-header",
1346
+ "aria-expanded": open,
1347
+ "aria-controls": `mcl-acc-${uid}-${i}`,
1348
+ onClick: () => toggle(i),
1349
+ children: [
1350
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: item.title }),
1351
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "mcl-accordion-chevron", "aria-hidden": "true", children: "\u25BE" })
1352
+ ]
1353
+ }
1354
+ ),
1355
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1356
+ "div",
1357
+ {
1358
+ id: `mcl-acc-${uid}-${i}`,
1359
+ ref: (el) => {
1360
+ panelRefs.current[i] = el;
1361
+ },
1362
+ className: "mcl-accordion-panel",
1363
+ style: { maxHeight: open ? heights[i] || 999 : 0 },
1364
+ role: "region",
1365
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mcl-accordion-panel-inner", children: item.content })
1366
+ }
1367
+ )
1368
+ ] }, i);
1369
+ }) });
1370
+ }
1371
+
1372
+ // src/components/toast/toast.tsx
1373
+ var import_react12 = require("react");
1374
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1375
+ var ToastContext = (0, import_react12.createContext)(null);
1376
+ function ToastProvider({ children, placement = "bottom-right" }) {
1377
+ const [toasts, setToasts] = (0, import_react12.useState)([]);
1378
+ const idRef = (0, import_react12.useRef)(0);
1379
+ const timersRef = (0, import_react12.useRef)(/* @__PURE__ */ new Map());
1380
+ const dismiss = (0, import_react12.useCallback)((id) => {
1381
+ const timer = timersRef.current.get(id);
1382
+ if (timer !== void 0) {
1383
+ window.clearTimeout(timer);
1384
+ timersRef.current.delete(id);
1385
+ }
1386
+ setToasts((list) => list.filter((t) => t.id !== id));
1387
+ }, []);
1388
+ const toast = (0, import_react12.useCallback)(
1389
+ (o) => {
1390
+ const id = ++idRef.current;
1391
+ setToasts((list) => [...list, { ...o, id }].slice(-4));
1392
+ const d = o.duration ?? 4200;
1393
+ if (d > 0) {
1394
+ const timer = window.setTimeout(() => dismiss(id), d);
1395
+ timersRef.current.set(id, timer);
1396
+ }
1397
+ },
1398
+ [dismiss]
1399
+ );
1400
+ (0, import_react12.useEffect)(
1401
+ () => () => {
1402
+ timersRef.current.forEach((timer) => window.clearTimeout(timer));
1403
+ timersRef.current.clear();
1404
+ },
1405
+ []
1406
+ );
1407
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(ToastContext.Provider, { value: { toast, dismiss }, children: [
1408
+ children,
1409
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: `mcl-toasts mcl-toasts-${placement}`, "aria-live": "polite", children: toasts.map((t) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToastCard, { item: t, onClose: () => dismiss(t.id) }, t.id)) })
1410
+ ] });
1411
+ }
1412
+ function ToastCard({ item, onClose }) {
1413
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: `mcl-toast mcl-toast-${item.variant ?? "info"}`, role: "status", children: [
1414
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "mcl-toast-dot", "aria-hidden": "true" }),
1415
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "mcl-toast-content", children: [
1416
+ item.title && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "mcl-toast-title", children: item.title }),
1417
+ item.message && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "mcl-toast-message", children: item.message })
1418
+ ] }),
1419
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", className: "mcl-toast-close", onClick: onClose, "aria-label": "Dismiss notification", children: "\u2715" })
1420
+ ] });
1421
+ }
1422
+ function useToast() {
1423
+ const ctx = (0, import_react12.useContext)(ToastContext);
1424
+ if (!ctx) throw new Error("useToast must be used inside <ToastProvider>.");
1425
+ return ctx;
1426
+ }
1427
+
1428
+ // src/components/navbar/navbar.tsx
1429
+ var import_react13 = require("react");
1430
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1431
+ function Navbar({ brand, links = [], activeHref, right, sticky = true, className = "" }) {
1432
+ const [open, setOpen] = (0, import_react13.useState)(false);
1433
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("nav", { className: `mcl-navbar${sticky ? " mcl-navbar-sticky" : ""} ${className}`.trim(), children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "mcl-navbar-inner", children: [
1434
+ brand && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("a", { className: "mcl-navbar-brand", href: "/", children: brand }),
1435
+ links.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1436
+ "button",
1437
+ {
1438
+ type: "button",
1439
+ className: "mcl-navbar-toggle",
1440
+ "aria-expanded": open,
1441
+ "aria-label": "Toggle menu",
1442
+ onClick: () => setOpen((o) => !o),
1443
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "mcl-navbar-burger", "aria-hidden": "true" })
1444
+ }
1445
+ ),
1446
+ links.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("ul", { className: `mcl-navbar-links${open ? " mcl-navbar-open" : ""}`, children: links.map((l) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1447
+ "a",
1448
+ {
1449
+ href: l.href,
1450
+ className: `mcl-navbar-link${activeHref === l.href ? " mcl-navbar-link-active" : ""}`,
1451
+ onClick: () => setOpen(false),
1452
+ "aria-current": activeHref === l.href ? "page" : void 0,
1453
+ children: l.label
1454
+ }
1455
+ ) }, l.href)) }),
1456
+ right && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "mcl-navbar-right", children: right })
1457
+ ] }) });
1458
+ }
1459
+
1460
+ // src/components/stat/stat.tsx
1461
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1462
+ function Stat({ value, label, tone = "primary", className = "" }) {
1463
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: `mcl-stat mcl-stat-${tone} ${className}`.trim(), children: [
1464
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("b", { className: "mcl-stat-value", children: value }),
1465
+ label && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "mcl-stat-label", children: label })
1466
+ ] });
1467
+ }
1468
+
1469
+ // src/components/divider/divider.tsx
1470
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1471
+ function Divider({ orientation = "horizontal", label, className = "", ...rest }) {
1472
+ if (label !== void 0 && label !== null) {
1473
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: `mcl-divider-label ${className}`.trim(), role: "separator", ...rest, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "mcl-divider-label-text", children: label }) });
1474
+ }
1475
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
1476
+ "div",
1477
+ {
1478
+ className: `mcl-divider mcl-divider-${orientation} ${className}`.trim(),
1479
+ role: "separator",
1480
+ ...rest
1481
+ }
1482
+ );
1483
+ }
1484
+
1485
+ // src/components/stack/stack.tsx
1486
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1487
+ function Stack({
1488
+ direction = "column",
1489
+ gap = "md",
1490
+ wrap = false,
1491
+ align,
1492
+ justify,
1493
+ className = "",
1494
+ ...rest
1495
+ }) {
1496
+ const cls = [
1497
+ "mcl-stack",
1498
+ direction === "row" ? "mcl-stack-row" : "",
1499
+ `mcl-stack-gap-${gap}`,
1500
+ wrap ? "mcl-stack-wrap" : "",
1501
+ align ? `mcl-stack-align-${align}` : "",
1502
+ justify ? `mcl-stack-justify-${justify}` : "",
1503
+ className
1504
+ ].filter(Boolean).join(" ");
1505
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: cls, ...rest });
1506
+ }
1507
+ // Annotate the CommonJS export names for ESM import in node:
1508
+ 0 && (module.exports = {
1509
+ Accordion,
1510
+ Alert,
1511
+ Avatar,
1512
+ AvatarGroup,
1513
+ Badge,
1514
+ Button,
1515
+ ButtonGroup,
1516
+ COLOR_SWATCHES,
1517
+ Card,
1518
+ CardBody,
1519
+ CardFooter,
1520
+ CardHeader,
1521
+ CardTitle,
1522
+ Checkbox,
1523
+ CheckboxGroup,
1524
+ Divider,
1525
+ Dropdown,
1526
+ Input,
1527
+ Kbd,
1528
+ MarclayProvider,
1529
+ Modal,
1530
+ Navbar,
1531
+ PRESETS,
1532
+ Progress,
1533
+ Radio,
1534
+ Range,
1535
+ Select,
1536
+ Skeleton,
1537
+ Spinner,
1538
+ Stack,
1539
+ Stat,
1540
+ Switch,
1541
+ Tabs,
1542
+ Textarea,
1543
+ ThemeMenu,
1544
+ ThemeProvider,
1545
+ ThemeToggle,
1546
+ ToastProvider,
1547
+ Tooltip,
1548
+ useTheme,
1549
+ useToast
1550
+ });
1551
+ //# sourceMappingURL=index.cjs.map