@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,320 @@
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/charts/chart-utils.ts
11
+ function axisMax(values) {
12
+ return Math.max(1, ...values.map((v) => Number.isFinite(v) ? v : 0));
13
+ }
14
+ function linePoints(values, w, h, pad = 2) {
15
+ if (values.length === 0) return "";
16
+ const max = axisMax(values);
17
+ const span = values.length > 1 ? values.length - 1 : 1;
18
+ return values.map((v, i) => {
19
+ const x = pad + i / span * (w - pad * 2);
20
+ const y = h - pad - Math.max(0, v) / max * (h - pad * 2);
21
+ return `${round(x)},${round(y)}`;
22
+ }).join(" ");
23
+ }
24
+ function barFractions(values) {
25
+ const max = axisMax(values);
26
+ return values.map((v) => Math.max(0, Math.min(1, (Number.isFinite(v) ? v : 0) / max)));
27
+ }
28
+ function pieSegments(values) {
29
+ const total = values.reduce((s, v) => s + Math.max(0, v), 0);
30
+ if (total <= 0) return [];
31
+ let acc = 0;
32
+ return values.map((v) => {
33
+ const frac = Math.max(0, v) / total;
34
+ const seg = { start: acc, end: acc + frac, frac };
35
+ acc += frac;
36
+ return seg;
37
+ });
38
+ }
39
+ function round(n) {
40
+ return Math.round(n * 100) / 100;
41
+ }
42
+
43
+ // src/charts/Charts.tsx
44
+ import { jsx, jsxs } from "react/jsx-runtime";
45
+ var STYLE_ID = "mang-ui-charts";
46
+ var { color, semantic, font, fontSize, fontWeight, radius } = tokens;
47
+ var SERIES = [
48
+ color.mangGreen,
49
+ color.sun,
50
+ color.soil,
51
+ semantic.state.info,
52
+ color.shoot,
53
+ color.bamboo
54
+ ];
55
+ var seriesColor = (i) => SERIES[i % SERIES.length];
56
+ var CSS = (
57
+ /* css */
58
+ `
59
+ .mang-stat { display: grid; gap: 0.15rem; }
60
+ .mang-stat-label { font-size: ${fontSize.xs}; color: var(--m-text-muted); font-weight: ${fontWeight.semibold}; text-transform: uppercase; letter-spacing: 0.08em; }
61
+ .mang-stat-value { font-family: "${font.heading}", system-ui, sans-serif; font-weight: ${fontWeight.bold}; font-size: ${fontSize["2xl"]}; color: var(--m-text-strong); font-variant-numeric: tabular-nums; line-height: 1.1; }
62
+ .mang-stat-delta { font-size: ${fontSize.xs}; font-weight: ${fontWeight.bold}; }
63
+ .mang-stat-delta[data-dir="up"] { color: var(--m-success); }
64
+ .mang-stat-delta[data-dir="down"] { color: var(--m-danger); }
65
+ .mang-statgroup { display: grid; grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); gap: 1rem; }
66
+ .mang-chart { display: block; width: 100%; height: auto; overflow: visible; }
67
+ .mang-chart-bars { display: flex; align-items: flex-end; gap: 0.3rem; height: 100%; }
68
+ .mang-chart-bar { flex: 1; border-radius: ${radius.sm} ${radius.sm} 0 0; background: var(--m-accent); min-height: 2px; transition: height 240ms var(--m-ease, cubic-bezier(0.16,1,0.3,1)); }
69
+ .mang-barchart { height: 8rem; }
70
+ .mang-legend { display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; }
71
+ .mang-legend-item { display: inline-flex; align-items: center; gap: 0.4rem; font-size: ${fontSize.sm}; color: var(--m-text); }
72
+ .mang-legend-dot { width: 0.7rem; height: 0.7rem; border-radius: 3px; flex: none; }
73
+ .mang-heatmap { display: grid; gap: 3px; grid-auto-flow: column; grid-template-rows: repeat(7, 0.85rem); }
74
+ .mang-heatmap-cell { width: 0.85rem; height: 0.85rem; border-radius: 2px; background: var(--m-sunken); }
75
+ @media (prefers-reduced-motion: reduce) { .mang-chart-bar { transition: none; } }
76
+ `
77
+ );
78
+ function Stat({ label, value, delta, direction, theme, className }) {
79
+ useAreaStyles(STYLE_ID, CSS);
80
+ const scope = useScope(theme);
81
+ return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-stat", className), children: [
82
+ /* @__PURE__ */ jsx("span", { className: "mang-stat-label", children: label }),
83
+ /* @__PURE__ */ jsx("span", { className: "mang-stat-value", children: value }),
84
+ delta != null && /* @__PURE__ */ jsx("span", { className: "mang-stat-delta", "data-dir": direction, children: delta })
85
+ ] });
86
+ }
87
+ function StatGroup({ children, theme, className }) {
88
+ useAreaStyles(STYLE_ID, CSS);
89
+ const scope = useScope(theme);
90
+ return /* @__PURE__ */ jsx("div", { ...scope, className: cx(scope.className, "mang-statgroup", className), children });
91
+ }
92
+ function Sparkline({
93
+ values,
94
+ width = 120,
95
+ height = 32,
96
+ colorIndex = 0,
97
+ theme,
98
+ className
99
+ }) {
100
+ useAreaStyles(STYLE_ID, CSS);
101
+ const scope = useScope(theme);
102
+ return /* @__PURE__ */ jsx(
103
+ "svg",
104
+ {
105
+ ...scope,
106
+ className: cx(scope.className, "mang-chart", className),
107
+ viewBox: `0 0 ${width} ${height}`,
108
+ role: "img",
109
+ "aria-label": "sparkline",
110
+ preserveAspectRatio: "none",
111
+ children: /* @__PURE__ */ jsx(
112
+ "polyline",
113
+ {
114
+ points: linePoints(values, width, height, 2),
115
+ fill: "none",
116
+ stroke: seriesColor(colorIndex),
117
+ strokeWidth: 2,
118
+ strokeLinejoin: "round",
119
+ strokeLinecap: "round"
120
+ }
121
+ )
122
+ }
123
+ );
124
+ }
125
+ function BarChart({ values, labels, theme, className }) {
126
+ useAreaStyles(STYLE_ID, CSS);
127
+ const scope = useScope(theme);
128
+ const fr = barFractions(values);
129
+ return /* @__PURE__ */ jsx("div", { ...scope, className: cx(scope.className, "mang-barchart", className), children: /* @__PURE__ */ jsx("div", { className: "mang-chart-bars", children: fr.map((f, i) => /* @__PURE__ */ jsx(
130
+ "div",
131
+ {
132
+ className: "mang-chart-bar",
133
+ style: { height: `${Math.max(2, f * 100)}%` },
134
+ title: labels?.[i]
135
+ },
136
+ i
137
+ )) }) });
138
+ }
139
+ function LineChart({
140
+ values,
141
+ width = 280,
142
+ height = 120,
143
+ colorIndex = 0,
144
+ area,
145
+ theme,
146
+ className
147
+ }) {
148
+ useAreaStyles(STYLE_ID, CSS);
149
+ const scope = useScope(theme);
150
+ const pts = linePoints(values, width, height, 4);
151
+ const c = seriesColor(colorIndex);
152
+ return /* @__PURE__ */ jsxs(
153
+ "svg",
154
+ {
155
+ ...scope,
156
+ className: cx(scope.className, "mang-chart", className),
157
+ viewBox: `0 0 ${width} ${height}`,
158
+ role: "img",
159
+ "aria-label": "line chart",
160
+ children: [
161
+ area && pts && /* @__PURE__ */ jsx(
162
+ "polygon",
163
+ {
164
+ points: `${pts} ${width - 4},${height - 4} 4,${height - 4}`,
165
+ fill: c,
166
+ opacity: 0.16
167
+ }
168
+ ),
169
+ /* @__PURE__ */ jsx(
170
+ "polyline",
171
+ {
172
+ points: pts,
173
+ fill: "none",
174
+ stroke: c,
175
+ strokeWidth: 2.5,
176
+ strokeLinejoin: "round",
177
+ strokeLinecap: "round"
178
+ }
179
+ )
180
+ ]
181
+ }
182
+ );
183
+ }
184
+ function AreaChart(props) {
185
+ return /* @__PURE__ */ jsx(LineChart, { ...props, area: true });
186
+ }
187
+ function DonutChart({
188
+ values,
189
+ size = 120,
190
+ thickness = 16,
191
+ center,
192
+ theme,
193
+ className
194
+ }) {
195
+ useAreaStyles(STYLE_ID, CSS);
196
+ const scope = useScope(theme);
197
+ const r = (size - thickness) / 2;
198
+ const c = 2 * Math.PI * r;
199
+ const segs = pieSegments(values);
200
+ return /* @__PURE__ */ jsxs(
201
+ "div",
202
+ {
203
+ ...scope,
204
+ className: cx(scope.className, className),
205
+ style: { position: "relative", width: size, height: size },
206
+ children: [
207
+ /* @__PURE__ */ jsxs(
208
+ "svg",
209
+ {
210
+ viewBox: `0 0 ${size} ${size}`,
211
+ width: size,
212
+ height: size,
213
+ role: "img",
214
+ "aria-label": "donut chart",
215
+ children: [
216
+ /* @__PURE__ */ jsx(
217
+ "circle",
218
+ {
219
+ cx: size / 2,
220
+ cy: size / 2,
221
+ r,
222
+ fill: "none",
223
+ stroke: "var(--m-sunken)",
224
+ strokeWidth: thickness
225
+ }
226
+ ),
227
+ segs.map((s, i) => /* @__PURE__ */ jsx(
228
+ "circle",
229
+ {
230
+ cx: size / 2,
231
+ cy: size / 2,
232
+ r,
233
+ fill: "none",
234
+ stroke: seriesColor(i),
235
+ strokeWidth: thickness,
236
+ strokeDasharray: `${s.frac * c} ${c}`,
237
+ strokeDashoffset: -s.start * c,
238
+ transform: `rotate(-90 ${size / 2} ${size / 2})`
239
+ },
240
+ i
241
+ ))
242
+ ]
243
+ }
244
+ ),
245
+ center != null && /* @__PURE__ */ jsx(
246
+ "div",
247
+ {
248
+ style: {
249
+ position: "absolute",
250
+ inset: 0,
251
+ display: "grid",
252
+ placeItems: "center",
253
+ textAlign: "center"
254
+ },
255
+ children: center
256
+ }
257
+ )
258
+ ]
259
+ }
260
+ );
261
+ }
262
+ function Heatmap({ values, theme, className }) {
263
+ useAreaStyles(STYLE_ID, CSS);
264
+ const scope = useScope(theme);
265
+ return /* @__PURE__ */ jsx(
266
+ "div",
267
+ {
268
+ ...scope,
269
+ className: cx(scope.className, "mang-heatmap", className),
270
+ role: "img",
271
+ "aria-label": "activity heatmap",
272
+ children: values.map((v, i) => /* @__PURE__ */ jsx(
273
+ "div",
274
+ {
275
+ className: "mang-heatmap-cell",
276
+ style: v > 0 ? { background: color.mangGreen, opacity: 0.25 + Math.min(1, v) * 0.75 } : void 0
277
+ },
278
+ i
279
+ ))
280
+ }
281
+ );
282
+ }
283
+ function Legend({ items, theme, className }) {
284
+ useAreaStyles(STYLE_ID, CSS);
285
+ const scope = useScope(theme);
286
+ return /* @__PURE__ */ jsx("div", { ...scope, className: cx(scope.className, "mang-legend", className), children: items.map((it, i) => /* @__PURE__ */ jsxs(
287
+ "span",
288
+ {
289
+ className: "mang-legend-item",
290
+ children: [
291
+ /* @__PURE__ */ jsx(
292
+ "span",
293
+ {
294
+ className: "mang-legend-dot",
295
+ style: { background: seriesColor(it.colorIndex ?? i) }
296
+ }
297
+ ),
298
+ it.label
299
+ ]
300
+ },
301
+ i
302
+ )) });
303
+ }
304
+
305
+ export {
306
+ axisMax,
307
+ linePoints,
308
+ barFractions,
309
+ pieSegments,
310
+ SERIES,
311
+ Stat,
312
+ StatGroup,
313
+ Sparkline,
314
+ BarChart,
315
+ LineChart,
316
+ AreaChart,
317
+ DonutChart,
318
+ Heatmap,
319
+ Legend
320
+ };
@@ -0,0 +1,90 @@
1
+ import {
2
+ Button
3
+ } from "./chunk-YN5O6YL6.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/handoff/Handoff.tsx
14
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
+ var STYLE_ID = "mang-ui-handoff";
16
+ var { fontSize, fontWeight, radius, font } = tokens;
17
+ var CSS = (
18
+ /* css */
19
+ `
20
+ .mang-handoff { display: grid; gap: 0.7rem; justify-items: center; text-align: center; padding: 1rem 1.1rem; border: 1px solid var(--m-line); border-radius: ${radius.lg}; background: var(--m-surface); color: var(--m-text); }
21
+ .mang-handoff-title { font-family: "${font.heading}", system-ui, sans-serif; font-weight: ${fontWeight.bold}; color: var(--m-text-strong); font-size: ${fontSize.base}; }
22
+ .mang-handoff-qr { padding: 0.6rem; background: #fff; border-radius: ${radius.md}; line-height: 0; }
23
+ .mang-handoff-note { font-size: ${fontSize.sm}; color: var(--m-text-muted); max-width: 22rem; }
24
+ .mang-handoff-status { display: inline-flex; align-items: center; gap: 0.4rem; font-size: ${fontSize.sm}; font-weight: ${fontWeight.semibold}; }
25
+ .mang-handoff-status[data-on="true"] { color: var(--m-success); }
26
+ .mang-handoff-status[data-on="false"] { color: var(--m-text-muted); }
27
+ .mang-handoff-banner { display: flex; align-items: center; gap: 0.6rem; padding: 0.7rem 0.9rem; border-radius: ${radius.md}; border: 1px solid var(--m-line); border-left: 4px solid var(--m-accent); background: var(--m-accent-soft); color: var(--m-text); }
28
+ .mang-handoff-banner-msg { flex: 1; font-size: ${fontSize.sm}; }
29
+ .mang-handoff-banner-msg b { color: var(--m-text-strong); }
30
+ `
31
+ );
32
+ function HandoffConnectionStatus({
33
+ connected,
34
+ device,
35
+ locale = "vi"
36
+ }) {
37
+ const label = connected ? locale === "vi" ? `\u{1F4F1} ${device ?? "Thi\u1EBFt b\u1ECB"} \u0111\xE3 k\u1EBFt n\u1ED1i` : `\u{1F4F1} ${device ?? "Device"} connected` : locale === "vi" ? "Ch\u01B0a k\u1EBFt n\u1ED1i" : "Not connected";
38
+ return /* @__PURE__ */ jsx("span", { className: "mang-handoff-status", "data-on": connected ? "true" : "false", children: label });
39
+ }
40
+ function HandoffPairingPanel({
41
+ qr,
42
+ connected = false,
43
+ device,
44
+ title,
45
+ note,
46
+ locale = "vi",
47
+ theme,
48
+ className
49
+ }) {
50
+ useAreaStyles(STYLE_ID, CSS);
51
+ const scope = useScope(theme);
52
+ return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-handoff", className), children: [
53
+ /* @__PURE__ */ jsx("span", { className: "mang-handoff-title", children: title ?? (locale === "vi" ? "Qu\xE9t \u0111\u1EC3 g\u1EEDi t\u1EEB \u0111i\u1EC7n tho\u1EA1i" : "Scan to send from your phone") }),
54
+ qr != null && /* @__PURE__ */ jsx("div", { className: "mang-handoff-qr", children: qr }),
55
+ /* @__PURE__ */ jsx(HandoffConnectionStatus, { connected, device, locale }),
56
+ note != null && /* @__PURE__ */ jsx("span", { className: "mang-handoff-note", children: note })
57
+ ] });
58
+ }
59
+ function HandoffPayloadBanner({
60
+ kind,
61
+ device,
62
+ onPaste,
63
+ onDismiss,
64
+ locale = "vi",
65
+ theme,
66
+ className
67
+ }) {
68
+ useAreaStyles(STYLE_ID, CSS);
69
+ const scope = useScope(theme);
70
+ const live = { role: "status" };
71
+ return /* @__PURE__ */ jsxs("div", { ...scope, ...live, className: cx(scope.className, "mang-handoff-banner", className), children: [
72
+ /* @__PURE__ */ jsx("span", { className: "mang-handoff-banner-msg", children: locale === "vi" ? /* @__PURE__ */ jsxs(Fragment, { children: [
73
+ "Nh\u1EADn ",
74
+ /* @__PURE__ */ jsx("b", { children: kind }),
75
+ device ? ` t\u1EEB ${device}` : ""
76
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
77
+ "Got ",
78
+ /* @__PURE__ */ jsx("b", { children: kind }),
79
+ device ? ` from ${device}` : ""
80
+ ] }) }),
81
+ /* @__PURE__ */ jsx(Button, { size: "sm", theme, onClick: onPaste, children: locale === "vi" ? "D\xE1n" : "Paste" }),
82
+ onDismiss && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", theme, onClick: onDismiss, children: "\u2715" })
83
+ ] });
84
+ }
85
+
86
+ export {
87
+ HandoffConnectionStatus,
88
+ HandoffPairingPanel,
89
+ HandoffPayloadBanner
90
+ };
@@ -0,0 +1,70 @@
1
+ import {
2
+ cx,
3
+ useKitStyles,
4
+ useScope
5
+ } from "./chunk-3AL4SUFD.js";
6
+
7
+ // src/overlay/Toast.tsx
8
+ import {
9
+ createContext,
10
+ useCallback,
11
+ useContext,
12
+ useEffect,
13
+ useMemo,
14
+ useReducer
15
+ } from "react";
16
+ import { jsx, jsxs } from "react/jsx-runtime";
17
+ function toastReducer(state, action) {
18
+ switch (action.type) {
19
+ case "add":
20
+ return [...state, action.toast].slice(-4);
21
+ case "dismiss":
22
+ return state.filter((t) => t.id !== action.id);
23
+ default:
24
+ return state;
25
+ }
26
+ }
27
+ var Ctx = createContext(null);
28
+ var nextId = 1;
29
+ function ToastProvider({ theme, children }) {
30
+ const [items, dispatch] = useReducer(toastReducer, []);
31
+ const dismiss = useCallback((id) => dispatch({ type: "dismiss", id }), []);
32
+ const toast = useCallback((input) => {
33
+ const id = nextId++;
34
+ dispatch({ type: "add", toast: { id, ...input } });
35
+ return id;
36
+ }, []);
37
+ const api = useMemo(() => ({ toast, dismiss }), [toast, dismiss]);
38
+ return /* @__PURE__ */ jsxs(Ctx.Provider, { value: api, children: [
39
+ children,
40
+ /* @__PURE__ */ jsx(ToastViewport, { items, onDismiss: dismiss, theme })
41
+ ] });
42
+ }
43
+ function useToast() {
44
+ const c = useContext(Ctx);
45
+ if (!c) throw new Error("useToast must be used inside <ToastProvider>");
46
+ return c;
47
+ }
48
+ function ToastView({ item, onDismiss }) {
49
+ useEffect(() => {
50
+ const ms = item.duration ?? 4e3;
51
+ if (ms <= 0) return;
52
+ const t = setTimeout(() => onDismiss(item.id), ms);
53
+ return () => clearTimeout(t);
54
+ }, [item, onDismiss]);
55
+ const live = { role: "status" };
56
+ return /* @__PURE__ */ jsx("div", { className: "mang-toast", "data-tone": item.tone ?? "default", ...live, children: /* @__PURE__ */ jsx("span", { className: "mang-toast-msg", children: item.message }) });
57
+ }
58
+ function ToastViewport({ items, onDismiss, theme }) {
59
+ useKitStyles();
60
+ const scope = useScope(theme);
61
+ if (items.length === 0) return null;
62
+ return /* @__PURE__ */ jsx("div", { ...scope, className: cx(scope.className, "mang-toast-viewport"), "aria-live": "polite", children: items.map((item) => /* @__PURE__ */ jsx(ToastView, { item, onDismiss }, item.id)) });
63
+ }
64
+
65
+ export {
66
+ toastReducer,
67
+ ToastProvider,
68
+ useToast,
69
+ ToastViewport
70
+ };
@@ -0,0 +1,63 @@
1
+ import {
2
+ cx,
3
+ useKitStyles,
4
+ useScope
5
+ } from "./chunk-3AL4SUFD.js";
6
+
7
+ // src/platform/Badge.tsx
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ function Badge({ tone = "accent", icon, theme, className, children }) {
10
+ useKitStyles();
11
+ const scope = useScope(theme);
12
+ return /* @__PURE__ */ jsxs("span", { ...scope, className: cx(scope.className, "mang-badge", className), "data-tone": tone, children: [
13
+ icon != null && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { display: "inline-flex" }, children: icon }),
14
+ children
15
+ ] });
16
+ }
17
+ function VerifiedBadge({
18
+ label = "M\u0103ng Verified",
19
+ compact = false,
20
+ title,
21
+ theme,
22
+ className
23
+ }) {
24
+ useKitStyles();
25
+ const scope = useScope(theme);
26
+ return /* @__PURE__ */ jsxs(
27
+ "span",
28
+ {
29
+ ...scope,
30
+ className: cx(scope.className, "mang-badge", "mang-verified", className),
31
+ title: title ?? label,
32
+ children: [
33
+ /* @__PURE__ */ jsx("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
34
+ "path",
35
+ {
36
+ d: "M9 12l2 2 4-4M12 3l2.3 1.7 2.8-.2 1 2.7 2.3 1.6-.8 2.7.8 2.7-2.3 1.6-1 2.7-2.8-.2L12 21l-2.3-1.7-2.8.2-1-2.7L3.6 15.4l.8-2.7-.8-2.7 2.3-1.6 1-2.7 2.8.2z",
37
+ stroke: "currentColor",
38
+ strokeWidth: "2",
39
+ strokeLinecap: "round",
40
+ strokeLinejoin: "round"
41
+ }
42
+ ) }),
43
+ compact ? /* @__PURE__ */ jsx("span", { style: srOnly, children: label }) : /* @__PURE__ */ jsx("span", { children: label })
44
+ ]
45
+ }
46
+ );
47
+ }
48
+ var srOnly = {
49
+ position: "absolute",
50
+ width: 1,
51
+ height: 1,
52
+ padding: 0,
53
+ margin: -1,
54
+ overflow: "hidden",
55
+ clip: "rect(0 0 0 0)",
56
+ whiteSpace: "nowrap",
57
+ border: 0
58
+ };
59
+
60
+ export {
61
+ Badge,
62
+ VerifiedBadge
63
+ };
@@ -0,0 +1,108 @@
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/analytics/Analytics.tsx
14
+ import { jsx, jsxs } from "react/jsx-runtime";
15
+ var STYLE_ID = "mang-ui-analytics";
16
+ var { fontSize, fontWeight, radius, font } = tokens;
17
+ var CSS = (
18
+ /* css */
19
+ `
20
+ .mang-gate-badge { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.2rem 0.6rem; border-radius: ${radius.full}; font-family: "${font.heading}", system-ui, sans-serif; font-weight: ${fontWeight.bold}; font-size: ${fontSize.xs}; }
21
+ .mang-gate-badge[data-met="true"] { background: var(--m-success-soft); color: var(--m-success-on); }
22
+ .mang-gate-badge[data-met="false"] { background: var(--m-sunken); color: var(--m-text-muted); }
23
+ .mang-atable { width: 100%; border-collapse: collapse; font-size: ${fontSize.sm}; }
24
+ .mang-atable th, .mang-atable td { text-align: left; padding: 0.5rem 0.65rem; border-bottom: 1px solid var(--m-line); }
25
+ .mang-atable th { font-family: "${font.heading}", system-ui, sans-serif; font-weight: ${fontWeight.semibold}; color: var(--m-text-muted); font-size: ${fontSize.xs}; text-transform: uppercase; letter-spacing: 0.06em; }
26
+ .mang-atable td { color: var(--m-text); font-variant-numeric: tabular-nums; }
27
+ .mang-atable td b { color: var(--m-text-strong); }
28
+ .mang-atable code { font-size: ${fontSize.xs}; color: var(--m-text-muted); }
29
+ `
30
+ );
31
+ function AnalyticsConsentToggle({
32
+ enabled,
33
+ onChange,
34
+ locale = "vi",
35
+ theme,
36
+ className
37
+ }) {
38
+ return /* @__PURE__ */ jsx(
39
+ Switch,
40
+ {
41
+ theme,
42
+ className,
43
+ checked: enabled,
44
+ onChange: (e) => onChange(e.target.checked),
45
+ label: locale === "vi" ? "G\u1EEDi th\u1ED1ng k\xEA \u1EA9n danh \u0111\u1EC3 c\u1EA3i thi\u1EC7n M\u0103ng" : "Send anonymous usage stats to improve M\u0103ng"
46
+ }
47
+ );
48
+ }
49
+ function GateMetBadge({ met, locale = "vi", theme, className }) {
50
+ useAreaStyles(STYLE_ID, CSS);
51
+ const scope = useScope(theme);
52
+ return /* @__PURE__ */ jsxs(
53
+ "span",
54
+ {
55
+ ...scope,
56
+ className: cx(scope.className, "mang-gate-badge", className),
57
+ "data-met": met ? "true" : "false",
58
+ children: [
59
+ met ? "\u2705" : "\u2B1C",
60
+ " ",
61
+ met ? locale === "vi" ? "\u0110\u1EA1t c\u1ED5ng" : "Gate met" : locale === "vi" ? "Ch\u01B0a \u0111\u1EA1t" : "Not met"
62
+ ]
63
+ }
64
+ );
65
+ }
66
+ function GateReport({ rows, locale = "vi", theme, className }) {
67
+ useAreaStyles(STYLE_ID, CSS);
68
+ const scope = useScope(theme);
69
+ return /* @__PURE__ */ jsxs("table", { ...scope, className: cx(scope.className, "mang-atable", className), children: [
70
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
71
+ /* @__PURE__ */ jsx("th", { children: locale === "vi" ? "App" : "App" }),
72
+ /* @__PURE__ */ jsx("th", { children: locale === "vi" ? "Thi\u1EBFt b\u1ECB" : "Devices" }),
73
+ /* @__PURE__ */ jsx("th", { children: locale === "vi" ? "Quay l\u1EA1i" : "Returning" })
74
+ ] }) }),
75
+ /* @__PURE__ */ jsx("tbody", { children: rows.map((r) => /* @__PURE__ */ jsxs("tr", { children: [
76
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("b", { children: r.app }) }),
77
+ /* @__PURE__ */ jsx("td", { children: r.devices }),
78
+ /* @__PURE__ */ jsx("td", { children: r.returning })
79
+ ] }, r.app)) })
80
+ ] });
81
+ }
82
+ function EventLogTable({ events, theme, className }) {
83
+ useAreaStyles(STYLE_ID, CSS);
84
+ const scope = useScope(theme);
85
+ return /* @__PURE__ */ jsxs("table", { ...scope, className: cx(scope.className, "mang-atable", className), children: [
86
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
87
+ /* @__PURE__ */ jsx("th", { children: "event" }),
88
+ /* @__PURE__ */ jsx("th", { children: "props" })
89
+ ] }) }),
90
+ /* @__PURE__ */ jsx("tbody", { children: events.map((e, i) => /* @__PURE__ */ jsxs(
91
+ "tr",
92
+ {
93
+ children: [
94
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("b", { children: e.name }) }),
95
+ /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("code", { children: e.props ? JSON.stringify(e.props) : "\u2014" }) })
96
+ ]
97
+ },
98
+ i
99
+ )) })
100
+ ] });
101
+ }
102
+
103
+ export {
104
+ AnalyticsConsentToggle,
105
+ GateMetBadge,
106
+ GateReport,
107
+ EventLogTable
108
+ };