@mangtre/ui 0.1.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/LICENSE +26 -0
  2. package/dist/MangThemeProvider-BqdGKBP2.d.ts +34 -0
  3. package/dist/Money-Dw3GnUvX.d.ts +27 -0
  4. package/dist/actions.d.ts +31 -0
  5. package/dist/actions.js +13 -0
  6. package/dist/ai.d.ts +58 -0
  7. package/dist/ai.js +13 -0
  8. package/dist/analytics.d.ts +40 -0
  9. package/dist/analytics.js +15 -0
  10. package/dist/app.d.ts +24 -0
  11. package/dist/app.js +9 -0
  12. package/dist/catalog.d.ts +76 -0
  13. package/dist/catalog.js +1210 -0
  14. package/dist/charts.d.ts +89 -0
  15. package/dist/charts.js +34 -0
  16. package/dist/chunk-3AL4SUFD.js +301 -0
  17. package/dist/chunk-4XNSYKQE.js +142 -0
  18. package/dist/chunk-5Z4VLQKH.js +43 -0
  19. package/dist/chunk-7P2EQZYD.js +59 -0
  20. package/dist/chunk-7WHNIEDV.js +120 -0
  21. package/dist/chunk-ASZKHSMG.js +82 -0
  22. package/dist/chunk-BCBN2EGH.js +216 -0
  23. package/dist/chunk-BLYAFV45.js +320 -0
  24. package/dist/chunk-DLKEXWPA.js +90 -0
  25. package/dist/chunk-DTASXPTB.js +70 -0
  26. package/dist/chunk-FZRXVRC7.js +63 -0
  27. package/dist/chunk-ID233AGM.js +108 -0
  28. package/dist/chunk-IVYXOKMO.js +74 -0
  29. package/dist/chunk-IX3DYETF.js +61 -0
  30. package/dist/chunk-JJB4PJC3.js +166 -0
  31. package/dist/chunk-K5Q3RCV6.js +119 -0
  32. package/dist/chunk-LNRUPJDF.js +161 -0
  33. package/dist/chunk-LZORNMBL.js +0 -0
  34. package/dist/chunk-OBPXCUVF.js +282 -0
  35. package/dist/chunk-OJX2EIMB.js +145 -0
  36. package/dist/chunk-PPOYMKV3.js +170 -0
  37. package/dist/chunk-PQGUWJG4.js +47 -0
  38. package/dist/chunk-RE7OWRA4.js +187 -0
  39. package/dist/chunk-SJF3CHAW.js +108 -0
  40. package/dist/chunk-UF6ANDJZ.js +112 -0
  41. package/dist/chunk-VGC5DMOM.js +107 -0
  42. package/dist/chunk-VP56Z4BS.js +0 -0
  43. package/dist/chunk-VRD66FIA.js +77 -0
  44. package/dist/chunk-X7T2DJLU.js +113 -0
  45. package/dist/chunk-XPV3OOLU.js +147 -0
  46. package/dist/chunk-YN5O6YL6.js +69 -0
  47. package/dist/chunk-Z4ANGBPC.js +94 -0
  48. package/dist/creator.d.ts +55 -0
  49. package/dist/creator.js +20 -0
  50. package/dist/data-room.d.ts +50 -0
  51. package/dist/data-room.js +17 -0
  52. package/dist/editor.d.ts +32 -0
  53. package/dist/editor.js +14 -0
  54. package/dist/feedback.d.ts +48 -0
  55. package/dist/feedback.js +16 -0
  56. package/dist/forms.d.ts +91 -0
  57. package/dist/forms.js +26 -0
  58. package/dist/handoff.d.ts +37 -0
  59. package/dist/handoff.js +13 -0
  60. package/dist/index.css +2 -0
  61. package/dist/index.d.ts +62 -0
  62. package/dist/index.js +338 -0
  63. package/dist/layout.d.ts +57 -0
  64. package/dist/layout.js +22 -0
  65. package/dist/learning.d.ts +46 -0
  66. package/dist/learning.js +15 -0
  67. package/dist/media.d.ts +48 -0
  68. package/dist/media.js +16 -0
  69. package/dist/monetization.d.ts +30 -0
  70. package/dist/monetization.js +14 -0
  71. package/dist/money.d.ts +45 -0
  72. package/dist/money.js +28 -0
  73. package/dist/navigation.d.ts +36 -0
  74. package/dist/navigation.js +14 -0
  75. package/dist/overlay.d.ts +72 -0
  76. package/dist/overlay.js +20 -0
  77. package/dist/platform.d.ts +94 -0
  78. package/dist/platform.js +42 -0
  79. package/dist/primitives.d.ts +83 -0
  80. package/dist/primitives.js +22 -0
  81. package/dist/privacy.d.ts +28 -0
  82. package/dist/privacy.js +15 -0
  83. package/dist/sandbox.d.ts +40 -0
  84. package/dist/sandbox.js +15 -0
  85. package/dist/settings.d.ts +29 -0
  86. package/dist/settings.js +13 -0
  87. package/dist/surface.d.ts +33 -0
  88. package/dist/surface.js +16 -0
  89. package/dist/theme.css +63 -0
  90. package/dist/theme.d.ts +64 -0
  91. package/dist/theme.js +27 -0
  92. package/dist/tokens.css +119 -0
  93. package/dist/tokens.d.ts +128 -0
  94. package/dist/tokens.js +8 -0
  95. package/package.json +151 -0
@@ -0,0 +1,187 @@
1
+ import {
2
+ cx,
3
+ useAreaStyles,
4
+ useScope
5
+ } from "./chunk-3AL4SUFD.js";
6
+ import {
7
+ tokens
8
+ } from "./chunk-PPOYMKV3.js";
9
+
10
+ // src/media/Media.tsx
11
+ import { useRef, useState } from "react";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ var STYLE_ID = "mang-ui-media";
14
+ var { color, fontSize, fontWeight, radius, font } = tokens;
15
+ var CSS = (
16
+ /* css */
17
+ `
18
+ .mang-dropzone { display: grid; gap: 0.35rem; justify-items: center; text-align: center; padding: 1.5rem 1.25rem; border: 2px dashed var(--m-line-strong); border-radius: ${radius.lg}; background: var(--m-sunken); color: var(--m-text-muted); cursor: pointer; transition: border-color 140ms, background 140ms; }
19
+ .mang-dropzone[data-over="true"] { border-color: var(--m-accent); background: var(--m-accent-soft); }
20
+ .mang-dropzone-icon { font-size: 1.6rem; }
21
+ .mang-fileprev { display: flex; align-items: center; gap: 0.6rem; padding: 0.55rem 0.7rem; border: 1px solid var(--m-line); border-radius: ${radius.md}; background: var(--m-surface); }
22
+ .mang-fileprev-icon { font-size: 1.25rem; }
23
+ .mang-fileprev-main { flex: 1; min-width: 0; }
24
+ .mang-fileprev-name { font-weight: ${fontWeight.semibold}; font-size: ${fontSize.sm}; color: var(--m-text-strong); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
25
+ .mang-fileprev-meta { font-size: ${fontSize.xs}; color: var(--m-text-muted); }
26
+ .mang-imgprev { max-width: 100%; border-radius: ${radius.md}; border: 1px solid var(--m-line); display: block; }
27
+ .mang-avatar { display: inline-grid; place-items: center; border-radius: 50%; background: var(--m-accent); color: #fff; font-family: "${font.heading}", system-ui, sans-serif; font-weight: ${fontWeight.bold}; overflow: hidden; flex: none; }
28
+ .mang-avatar img { width: 100%; height: 100%; object-fit: cover; }
29
+ .mang-avatargroup { display: inline-flex; }
30
+ .mang-avatargroup .mang-avatar { margin-left: -0.5rem; box-shadow: 0 0 0 2px var(--m-surface); }
31
+ .mang-avatargroup .mang-avatar:first-child { margin-left: 0; }
32
+ `
33
+ );
34
+ function Dropzone({
35
+ onFiles,
36
+ accept,
37
+ multiple,
38
+ label,
39
+ icon = "\u2B06\uFE0F",
40
+ theme,
41
+ className
42
+ }) {
43
+ useAreaStyles(STYLE_ID, CSS);
44
+ const scope = useScope(theme);
45
+ const inputRef = useRef(null);
46
+ const [over, setOver] = useState(false);
47
+ const emit = (list) => {
48
+ if (list && list.length > 0) onFiles(Array.from(list));
49
+ };
50
+ const onDrop = (e) => {
51
+ e.preventDefault();
52
+ setOver(false);
53
+ emit(e.dataTransfer.files);
54
+ };
55
+ const trigger = { role: "button", tabIndex: 0 };
56
+ return /* @__PURE__ */ jsxs(
57
+ "div",
58
+ {
59
+ ...scope,
60
+ ...trigger,
61
+ className: cx(scope.className, "mang-dropzone", className),
62
+ "data-over": over ? "true" : void 0,
63
+ onClick: () => inputRef.current?.click(),
64
+ onKeyDown: (e) => {
65
+ if (e.key === "Enter" || e.key === " ") inputRef.current?.click();
66
+ },
67
+ onDragOver: (e) => {
68
+ e.preventDefault();
69
+ setOver(true);
70
+ },
71
+ onDragLeave: () => setOver(false),
72
+ onDrop,
73
+ children: [
74
+ /* @__PURE__ */ jsx("span", { className: "mang-dropzone-icon", "aria-hidden": "true", children: icon }),
75
+ /* @__PURE__ */ jsx("span", { children: label ?? "K\xE9o th\u1EA3 t\u1EC7p v\xE0o \u0111\xE2y" }),
76
+ /* @__PURE__ */ jsx(
77
+ "input",
78
+ {
79
+ ref: inputRef,
80
+ type: "file",
81
+ accept,
82
+ multiple,
83
+ hidden: true,
84
+ onChange: (e) => {
85
+ emit(e.target.files);
86
+ e.target.value = "";
87
+ }
88
+ }
89
+ )
90
+ ]
91
+ }
92
+ );
93
+ }
94
+ function FilePreview({
95
+ name,
96
+ size,
97
+ icon = "\u{1F4C4}",
98
+ action,
99
+ theme,
100
+ className
101
+ }) {
102
+ useAreaStyles(STYLE_ID, CSS);
103
+ const scope = useScope(theme);
104
+ return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-fileprev", className), children: [
105
+ /* @__PURE__ */ jsx("span", { className: "mang-fileprev-icon", "aria-hidden": "true", children: icon }),
106
+ /* @__PURE__ */ jsxs("div", { className: "mang-fileprev-main", children: [
107
+ /* @__PURE__ */ jsx("div", { className: "mang-fileprev-name", children: name }),
108
+ size != null && /* @__PURE__ */ jsxs("div", { className: "mang-fileprev-meta", children: [
109
+ (size / 1024).toFixed(0),
110
+ " KB"
111
+ ] })
112
+ ] }),
113
+ action
114
+ ] });
115
+ }
116
+ function ImagePreview({
117
+ src,
118
+ alt,
119
+ maxHeight = "16rem",
120
+ theme,
121
+ className
122
+ }) {
123
+ useAreaStyles(STYLE_ID, CSS);
124
+ const scope = useScope(theme);
125
+ return /* @__PURE__ */ jsx(
126
+ "img",
127
+ {
128
+ ...scope,
129
+ className: cx(scope.className, "mang-imgprev", className),
130
+ src,
131
+ alt,
132
+ style: { maxHeight }
133
+ }
134
+ );
135
+ }
136
+ function Avatar({ src, name, size = 36, theme, className }) {
137
+ useAreaStyles(STYLE_ID, CSS);
138
+ const scope = useScope(theme);
139
+ const initials = (name ?? "?").trim().slice(0, 1).toUpperCase();
140
+ return /* @__PURE__ */ jsx(
141
+ "span",
142
+ {
143
+ ...scope,
144
+ className: cx(scope.className, "mang-avatar", className),
145
+ style: { width: size, height: size, fontSize: size * 0.42 },
146
+ "aria-label": name,
147
+ children: src ? /* @__PURE__ */ jsx("img", { src, alt: name ?? "" }) : initials
148
+ }
149
+ );
150
+ }
151
+ function AvatarGroup({ people, max = 4, size = 32, theme, className }) {
152
+ useAreaStyles(STYLE_ID, CSS);
153
+ const scope = useScope(theme);
154
+ const shown = people.slice(0, max);
155
+ const extra = people.length - shown.length;
156
+ return /* @__PURE__ */ jsxs("span", { ...scope, className: cx(scope.className, "mang-avatargroup", className), children: [
157
+ shown.map((p, i) => /* @__PURE__ */ jsx(
158
+ Avatar,
159
+ {
160
+ src: p.src,
161
+ name: p.name,
162
+ size,
163
+ theme
164
+ },
165
+ i
166
+ )),
167
+ extra > 0 && /* @__PURE__ */ jsxs(
168
+ "span",
169
+ {
170
+ className: "mang-avatar",
171
+ style: { width: size, height: size, fontSize: size * 0.36, background: color.bamboo },
172
+ children: [
173
+ "+",
174
+ extra
175
+ ]
176
+ }
177
+ )
178
+ ] });
179
+ }
180
+
181
+ export {
182
+ Dropzone,
183
+ FilePreview,
184
+ ImagePreview,
185
+ Avatar,
186
+ AvatarGroup
187
+ };
@@ -0,0 +1,108 @@
1
+ import {
2
+ cx,
3
+ useKitStyles,
4
+ useScope
5
+ } from "./chunk-3AL4SUFD.js";
6
+
7
+ // src/navigation/Tabs.tsx
8
+ import {
9
+ createContext,
10
+ useContext,
11
+ useId,
12
+ useState
13
+ } from "react";
14
+ import { jsx } from "react/jsx-runtime";
15
+ var Ctx = createContext(null);
16
+ var useTabs = () => {
17
+ const c = useContext(Ctx);
18
+ if (!c) throw new Error("Tabs subcomponents must be used inside <Tabs>");
19
+ return c;
20
+ };
21
+ function Tabs({
22
+ value,
23
+ defaultValue,
24
+ onValueChange,
25
+ theme,
26
+ className,
27
+ children
28
+ }) {
29
+ useKitStyles();
30
+ const scope = useScope(theme);
31
+ const baseId = useId();
32
+ const [internal, setInternal] = useState(defaultValue ?? "");
33
+ const active = value ?? internal;
34
+ const setValue = (v) => {
35
+ if (value === void 0) setInternal(v);
36
+ onValueChange?.(v);
37
+ };
38
+ return /* @__PURE__ */ jsx(Ctx.Provider, { value: { value: active, setValue, baseId }, children: /* @__PURE__ */ jsx("div", { ...scope, className: cx(scope.className, className), children }) });
39
+ }
40
+ function TabList({ label, className, children }) {
41
+ const onKeyDown = (e) => {
42
+ const tabs = Array.from(
43
+ e.currentTarget.querySelectorAll('[role="tab"]:not(:disabled)')
44
+ );
45
+ const i = tabs.indexOf(document.activeElement);
46
+ if (i < 0) return;
47
+ let next = -1;
48
+ if (e.key === "ArrowRight") next = (i + 1) % tabs.length;
49
+ else if (e.key === "ArrowLeft") next = (i - 1 + tabs.length) % tabs.length;
50
+ else if (e.key === "Home") next = 0;
51
+ else if (e.key === "End") next = tabs.length - 1;
52
+ if (next >= 0) {
53
+ e.preventDefault();
54
+ tabs[next]?.focus();
55
+ tabs[next]?.click();
56
+ }
57
+ };
58
+ return /* @__PURE__ */ jsx(
59
+ "div",
60
+ {
61
+ role: "tablist",
62
+ "aria-label": label,
63
+ className: cx("mang-tablist", className),
64
+ onKeyDown,
65
+ children
66
+ }
67
+ );
68
+ }
69
+ function Tab({ value, disabled, className, children }) {
70
+ const { value: active, setValue, baseId } = useTabs();
71
+ const selected = active === value;
72
+ return /* @__PURE__ */ jsx(
73
+ "button",
74
+ {
75
+ type: "button",
76
+ role: "tab",
77
+ id: `${baseId}-tab-${value}`,
78
+ "aria-selected": selected,
79
+ "aria-controls": `${baseId}-panel-${value}`,
80
+ tabIndex: selected ? 0 : -1,
81
+ disabled,
82
+ className: cx("mang-tab", className),
83
+ onClick: () => setValue(value),
84
+ children
85
+ }
86
+ );
87
+ }
88
+ function TabPanel({ value, className, children }) {
89
+ const { value: active, baseId } = useTabs();
90
+ if (active !== value) return null;
91
+ return /* @__PURE__ */ jsx(
92
+ "div",
93
+ {
94
+ role: "tabpanel",
95
+ id: `${baseId}-panel-${value}`,
96
+ "aria-labelledby": `${baseId}-tab-${value}`,
97
+ className: cx("mang-tabpanel", className),
98
+ children
99
+ }
100
+ );
101
+ }
102
+
103
+ export {
104
+ Tabs,
105
+ TabList,
106
+ Tab,
107
+ TabPanel
108
+ };
@@ -0,0 +1,112 @@
1
+ import {
2
+ VndText
3
+ } from "./chunk-IX3DYETF.js";
4
+ import {
5
+ Badge
6
+ } from "./chunk-FZRXVRC7.js";
7
+ import {
8
+ Button
9
+ } from "./chunk-YN5O6YL6.js";
10
+ import {
11
+ cx,
12
+ useAreaStyles,
13
+ useScope
14
+ } from "./chunk-3AL4SUFD.js";
15
+ import {
16
+ tokens
17
+ } from "./chunk-PPOYMKV3.js";
18
+
19
+ // src/money/MoneyKit.tsx
20
+ import { jsx, jsxs } from "react/jsx-runtime";
21
+ var STYLE_ID = "mang-ui-money";
22
+ var { fontSize, fontWeight, radius, font } = tokens;
23
+ var CSS = (
24
+ /* css */
25
+ `
26
+ .mang-amount { display: grid; gap: 0.15rem; }
27
+ .mang-amount-label { font-size: ${fontSize.xs}; color: var(--m-text-muted); font-weight: ${fontWeight.semibold}; text-transform: uppercase; letter-spacing: 0.07em; }
28
+ .mang-amount-value { font-family: "${font.heading}", system-ui, sans-serif; font-weight: ${fontWeight.bold}; font-size: ${fontSize["3xl"]}; color: var(--m-text-strong); font-variant-numeric: tabular-nums; line-height: 1.05; }
29
+ .mang-explist { display: grid; gap: 0.4rem; }
30
+ .mang-exprow { display: flex; align-items: center; gap: 0.6rem; padding: 0.6rem 0.75rem; border: 1px solid var(--m-line); border-radius: ${radius.md}; background: var(--m-surface); }
31
+ .mang-exprow-main { flex: 1; min-width: 0; }
32
+ .mang-exprow-note { font-weight: ${fontWeight.semibold}; color: var(--m-text-strong); font-size: ${fontSize.sm}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
33
+ .mang-exprow-meta { font-size: ${fontSize.xs}; color: var(--m-text-muted); }
34
+ .mang-settle { display: grid; gap: 0.7rem; padding: 0.9rem 1rem; border: 1px solid var(--m-line); border-radius: ${radius.lg}; background: var(--m-surface); }
35
+ .mang-settle-line { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; }
36
+ .mang-settle-who { font-size: ${fontSize.sm}; color: var(--m-text); }
37
+ .mang-settle-who b { color: var(--m-text-strong); }
38
+ .mang-settle-qr { justify-self: center; padding: 0.5rem; background: #fff; border-radius: ${radius.md}; line-height: 0; }
39
+ `
40
+ );
41
+ function AmountSummary({
42
+ label,
43
+ amount,
44
+ sign = "none",
45
+ theme,
46
+ className
47
+ }) {
48
+ useAreaStyles(STYLE_ID, CSS);
49
+ const scope = useScope(theme);
50
+ return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-amount", className), children: [
51
+ /* @__PURE__ */ jsx("span", { className: "mang-amount-label", children: label }),
52
+ /* @__PURE__ */ jsx("span", { className: "mang-amount-value", children: /* @__PURE__ */ jsx(VndText, { amount, sign, theme }) })
53
+ ] });
54
+ }
55
+ function ExpenseRow({ note, meta, amount, action, theme, className }) {
56
+ useAreaStyles(STYLE_ID, CSS);
57
+ const scope = useScope(theme);
58
+ return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-exprow", className), children: [
59
+ /* @__PURE__ */ jsxs("div", { className: "mang-exprow-main", children: [
60
+ /* @__PURE__ */ jsx("div", { className: "mang-exprow-note", children: note }),
61
+ meta != null && /* @__PURE__ */ jsx("div", { className: "mang-exprow-meta", children: meta })
62
+ ] }),
63
+ /* @__PURE__ */ jsx(VndText, { amount, theme }),
64
+ action
65
+ ] });
66
+ }
67
+ function ExpenseList({ children, theme, className }) {
68
+ useAreaStyles(STYLE_ID, CSS);
69
+ const scope = useScope(theme);
70
+ return /* @__PURE__ */ jsx("div", { ...scope, className: cx(scope.className, "mang-explist", className), children });
71
+ }
72
+ function PaidBadge({ locale = "vi", theme, className }) {
73
+ return /* @__PURE__ */ jsx(Badge, { tone: "success", icon: "\u2713", theme, className, children: locale === "vi" ? "\u0110\xE3 tr\u1EA3" : "Paid" });
74
+ }
75
+ function UnpaidBadge({ locale = "vi", theme, className }) {
76
+ return /* @__PURE__ */ jsx(Badge, { tone: "neutral", theme, className, children: locale === "vi" ? "Ch\u01B0a tr\u1EA3" : "Unpaid" });
77
+ }
78
+ function SettlementCard({
79
+ from,
80
+ to,
81
+ amount,
82
+ qr,
83
+ paid,
84
+ onMarkPaid,
85
+ locale = "vi",
86
+ theme,
87
+ className
88
+ }) {
89
+ useAreaStyles(STYLE_ID, CSS);
90
+ const scope = useScope(theme);
91
+ return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-settle", className), children: [
92
+ /* @__PURE__ */ jsxs("div", { className: "mang-settle-line", children: [
93
+ /* @__PURE__ */ jsxs("span", { className: "mang-settle-who", children: [
94
+ /* @__PURE__ */ jsx("b", { children: from }),
95
+ " \u2192 ",
96
+ /* @__PURE__ */ jsx("b", { children: to })
97
+ ] }),
98
+ paid ? /* @__PURE__ */ jsx(PaidBadge, { locale, theme }) : /* @__PURE__ */ jsx(VndText, { amount, theme })
99
+ ] }),
100
+ qr != null && !paid && /* @__PURE__ */ jsx("div", { className: "mang-settle-qr", children: qr }),
101
+ onMarkPaid && !paid && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "secondary", theme, onClick: onMarkPaid, children: locale === "vi" ? "\u0110\xE1nh d\u1EA5u \u0111\xE3 tr\u1EA3" : "Mark as paid" })
102
+ ] });
103
+ }
104
+
105
+ export {
106
+ AmountSummary,
107
+ ExpenseRow,
108
+ ExpenseList,
109
+ PaidBadge,
110
+ UnpaidBadge,
111
+ SettlementCard
112
+ };
@@ -0,0 +1,107 @@
1
+ import {
2
+ cx,
3
+ useKitStyles,
4
+ useScope
5
+ } from "./chunk-3AL4SUFD.js";
6
+
7
+ // src/feedback/Feedback.tsx
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ function EmptyState({
10
+ icon,
11
+ title,
12
+ description,
13
+ action,
14
+ theme,
15
+ className
16
+ }) {
17
+ useKitStyles();
18
+ const scope = useScope(theme);
19
+ return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-empty", className), children: [
20
+ icon != null && /* @__PURE__ */ jsx("div", { className: "mang-empty-icon", "aria-hidden": "true", children: icon }),
21
+ title != null && /* @__PURE__ */ jsx("div", { className: "mang-empty-title", children: title }),
22
+ description != null && /* @__PURE__ */ jsx("div", { children: description }),
23
+ action
24
+ ] });
25
+ }
26
+ function ErrorState({
27
+ icon = "\u26A0\uFE0F",
28
+ title,
29
+ description,
30
+ action,
31
+ theme,
32
+ className
33
+ }) {
34
+ useKitStyles();
35
+ const scope = useScope(theme);
36
+ return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-error-state", className), role: "alert", children: [
37
+ icon != null && /* @__PURE__ */ jsx("div", { className: "mang-empty-icon", "aria-hidden": "true", children: icon }),
38
+ title != null && /* @__PURE__ */ jsx("div", { className: "mang-empty-title", children: title }),
39
+ description != null && /* @__PURE__ */ jsx("div", { children: description }),
40
+ action
41
+ ] });
42
+ }
43
+ function Skeleton({
44
+ width,
45
+ height = "1rem",
46
+ rounded,
47
+ theme,
48
+ className,
49
+ style
50
+ }) {
51
+ useKitStyles();
52
+ const scope = useScope(theme);
53
+ return /* @__PURE__ */ jsx(
54
+ "span",
55
+ {
56
+ ...scope,
57
+ className: cx(scope.className, "mang-skeleton", className),
58
+ style: { width, height, borderRadius: rounded ? "999px" : void 0, ...style },
59
+ "aria-hidden": "true"
60
+ }
61
+ );
62
+ }
63
+ function Spinner({ size, label = "\u0110ang t\u1EA3i\u2026", theme, className }) {
64
+ useKitStyles();
65
+ const scope = useScope(theme);
66
+ return /* @__PURE__ */ jsx(
67
+ "span",
68
+ {
69
+ ...scope,
70
+ className: cx(scope.className, "mang-spinner", className),
71
+ style: size != null ? { width: size, height: size } : void 0,
72
+ role: "status",
73
+ "aria-label": label
74
+ }
75
+ );
76
+ }
77
+ function Progress({ value, theme, className, label }) {
78
+ useKitStyles();
79
+ const scope = useScope(theme);
80
+ const indeterminate = value == null;
81
+ const pct = indeterminate ? void 0 : Math.max(0, Math.min(100, value));
82
+ const bar = {
83
+ role: "progressbar",
84
+ "aria-label": label,
85
+ "aria-valuenow": pct,
86
+ "aria-valuemin": indeterminate ? void 0 : 0,
87
+ "aria-valuemax": indeterminate ? void 0 : 100
88
+ };
89
+ return /* @__PURE__ */ jsx(
90
+ "div",
91
+ {
92
+ ...scope,
93
+ ...bar,
94
+ className: cx(scope.className, "mang-progress", className),
95
+ "data-indeterminate": indeterminate ? "true" : void 0,
96
+ children: /* @__PURE__ */ jsx("div", { className: "mang-progress-bar", style: { width: indeterminate ? void 0 : `${pct}%` } })
97
+ }
98
+ );
99
+ }
100
+
101
+ export {
102
+ EmptyState,
103
+ ErrorState,
104
+ Skeleton,
105
+ Spinner,
106
+ Progress
107
+ };
File without changes
@@ -0,0 +1,77 @@
1
+ import {
2
+ Switch
3
+ } from "./chunk-PQGUWJG4.js";
4
+ import {
5
+ cx,
6
+ useAreaStyles,
7
+ useScope
8
+ } from "./chunk-3AL4SUFD.js";
9
+ import {
10
+ tokens
11
+ } from "./chunk-PPOYMKV3.js";
12
+
13
+ // src/settings/Settings.tsx
14
+ import { jsx, jsxs } from "react/jsx-runtime";
15
+ var STYLE_ID = "mang-ui-settings";
16
+ var { fontSize, fontWeight, radius, font } = tokens;
17
+ var CSS = (
18
+ /* css */
19
+ `
20
+ .mang-set-section { display: grid; gap: 0.1rem; border: 1px solid var(--m-line); border-radius: ${radius.lg}; background: var(--m-surface); overflow: clip; }
21
+ .mang-set-section-title { font-family: "${font.heading}", system-ui, sans-serif; font-weight: ${fontWeight.semibold}; font-size: ${fontSize.sm}; color: var(--m-text-muted); padding: 0.7rem 1rem 0.3rem; text-transform: uppercase; letter-spacing: 0.06em; }
22
+ .mang-set-row { display: flex; align-items: center; gap: 0.75rem; padding: 0.8rem 1rem; border-top: 1px solid var(--m-line); }
23
+ .mang-set-row:first-of-type { border-top: none; }
24
+ .mang-set-row-main { flex: 1; min-width: 0; }
25
+ .mang-set-row-label { font-weight: ${fontWeight.semibold}; font-size: ${fontSize.sm}; color: var(--m-text-strong); }
26
+ .mang-set-row-desc { font-size: ${fontSize.xs}; color: var(--m-text-muted); }
27
+ `
28
+ );
29
+ function SettingsSection({
30
+ title,
31
+ theme,
32
+ className,
33
+ children
34
+ }) {
35
+ useAreaStyles(STYLE_ID, CSS);
36
+ const scope = useScope(theme);
37
+ return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-set-section", className), children: [
38
+ title != null && /* @__PURE__ */ jsx("div", { className: "mang-set-section-title", children: title }),
39
+ children
40
+ ] });
41
+ }
42
+ function SettingsRow({ label, description, control, theme, className }) {
43
+ useAreaStyles(STYLE_ID, CSS);
44
+ const scope = useScope(theme);
45
+ return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-set-row", className), children: [
46
+ /* @__PURE__ */ jsxs("div", { className: "mang-set-row-main", children: [
47
+ /* @__PURE__ */ jsx("div", { className: "mang-set-row-label", children: label }),
48
+ description != null && /* @__PURE__ */ jsx("div", { className: "mang-set-row-desc", children: description })
49
+ ] }),
50
+ control
51
+ ] });
52
+ }
53
+ function SettingsToggle({
54
+ label,
55
+ description,
56
+ checked,
57
+ onChange,
58
+ theme,
59
+ className
60
+ }) {
61
+ return /* @__PURE__ */ jsx(
62
+ SettingsRow,
63
+ {
64
+ theme,
65
+ className,
66
+ label,
67
+ description,
68
+ control: /* @__PURE__ */ jsx(Switch, { theme, checked, onChange: (e) => onChange(e.target.checked) })
69
+ }
70
+ );
71
+ }
72
+
73
+ export {
74
+ SettingsSection,
75
+ SettingsRow,
76
+ SettingsToggle
77
+ };