@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,282 @@
1
+ import {
2
+ cx,
3
+ useAreaStyles,
4
+ useKitStyles,
5
+ useScope
6
+ } from "./chunk-3AL4SUFD.js";
7
+ import {
8
+ tokens
9
+ } from "./chunk-PPOYMKV3.js";
10
+
11
+ // src/forms/Field.tsx
12
+ import { cloneElement, isValidElement, useId } from "react";
13
+ import { jsx, jsxs } from "react/jsx-runtime";
14
+ function Field({
15
+ label,
16
+ description,
17
+ error,
18
+ required,
19
+ theme,
20
+ className,
21
+ children
22
+ }) {
23
+ useKitStyles();
24
+ const scope = useScope(theme);
25
+ const id = useId();
26
+ const descId = description ? `${id}-desc` : void 0;
27
+ const errId = error ? `${id}-err` : void 0;
28
+ const describedBy = [descId, errId].filter(Boolean).join(" ") || void 0;
29
+ const control = isValidElement(children) ? cloneElement(children, {
30
+ id: children.props.id ?? id,
31
+ "aria-describedby": describedBy,
32
+ "aria-invalid": error ? true : void 0
33
+ }) : children;
34
+ return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-field", className), children: [
35
+ label != null && /* @__PURE__ */ jsxs("label", { className: "mang-field-label", htmlFor: id, children: [
36
+ label,
37
+ required && /* @__PURE__ */ jsx("span", { className: "mang-field-req", "aria-hidden": "true", children: "*" })
38
+ ] }),
39
+ description != null && /* @__PURE__ */ jsx("span", { className: "mang-field-desc", id: descId, children: description }),
40
+ control,
41
+ error != null && /* @__PURE__ */ jsx("span", { className: "mang-field-error", id: errId, role: "alert", children: error })
42
+ ] });
43
+ }
44
+
45
+ // src/forms/Input.tsx
46
+ import { jsx as jsx2 } from "react/jsx-runtime";
47
+ function Input({ theme, className, ...rest }) {
48
+ useKitStyles();
49
+ const scope = useScope(theme);
50
+ return /* @__PURE__ */ jsx2(
51
+ "input",
52
+ {
53
+ ...rest,
54
+ className: cx(scope.className, "mang-control", className),
55
+ "data-theme": scope["data-theme"],
56
+ "data-density": scope["data-density"]
57
+ }
58
+ );
59
+ }
60
+ function TextArea({ theme, className, ...rest }) {
61
+ useKitStyles();
62
+ const scope = useScope(theme);
63
+ return /* @__PURE__ */ jsx2(
64
+ "textarea",
65
+ {
66
+ ...rest,
67
+ className: cx(scope.className, "mang-control", className),
68
+ "data-theme": scope["data-theme"],
69
+ "data-density": scope["data-density"]
70
+ }
71
+ );
72
+ }
73
+ function Select({ theme, className, children, ...rest }) {
74
+ useKitStyles();
75
+ const scope = useScope(theme);
76
+ return /* @__PURE__ */ jsx2(
77
+ "select",
78
+ {
79
+ ...rest,
80
+ className: cx(scope.className, "mang-control", className),
81
+ "data-theme": scope["data-theme"],
82
+ "data-density": scope["data-density"],
83
+ children
84
+ }
85
+ );
86
+ }
87
+
88
+ // src/forms/Controls.tsx
89
+ import { useId as useId2 } from "react";
90
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
91
+ var STYLE_ID = "mang-ui-forms-ext";
92
+ var { color, radius, fontSize, fontWeight, font, motion } = tokens;
93
+ var ease = motion.ease.standard;
94
+ var mix = (a, pct, b) => `color-mix(in oklab, ${a} ${pct}%, ${b})`;
95
+ var focusRing = `3px solid ${mix(color.mangGreen, 45, "transparent")}`;
96
+ var CSS = (
97
+ /* css */
98
+ `
99
+ .mang-seg { display: inline-flex; gap: 0.2rem; padding: 0.25rem; background: var(--m-sunken); border-radius: ${radius.md}; border: 1px solid var(--m-line); max-width: 100%; flex-wrap: wrap; }
100
+ .mang-seg-opt { appearance: none; cursor: pointer; border: none; background: transparent; padding: 0.45rem 0.85rem; border-radius: ${radius.sm}; font-family: "${font.heading}", system-ui, sans-serif; font-weight: ${fontWeight.semibold}; font-size: ${fontSize.sm}; color: var(--m-text-muted); transition: background ${motion.duration.fast} ${ease}, color ${motion.duration.fast} ${ease}; }
101
+ .mang-seg-opt:hover { color: var(--m-text-strong); }
102
+ .mang-seg-opt[aria-pressed="true"] { background: var(--m-surface); color: var(--m-accent); box-shadow: var(--m-shadow); }
103
+ .mang-seg-opt:focus-visible { outline: ${focusRing}; outline-offset: 1px; }
104
+ .mang-seg-opt:disabled { opacity: 0.5; cursor: not-allowed; }
105
+ .mang-seg[data-size="sm"] .mang-seg-opt { padding: 0.25rem 0.6rem; font-size: ${fontSize.xs}; }
106
+
107
+ .mang-chip { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.28rem 0.65rem; border-radius: ${radius.full}; font-family: "${font.body}", system-ui, sans-serif; font-size: ${fontSize.sm}; font-weight: ${fontWeight.medium}; border: 1.5px solid var(--m-line-strong); background: var(--m-surface); color: var(--m-text); }
108
+ button.mang-chip { cursor: pointer; transition: border-color ${motion.duration.fast} ${ease}, background ${motion.duration.fast} ${ease}, color ${motion.duration.fast} ${ease}; }
109
+ button.mang-chip:hover { border-color: var(--m-accent); }
110
+ button.mang-chip:focus-visible { outline: ${focusRing}; outline-offset: 2px; }
111
+ .mang-chip[data-selected="true"] { background: var(--m-accent-soft); border-color: var(--m-accent); color: var(--m-accent); }
112
+ .mang-chip-x { appearance: none; border: none; background: transparent; cursor: pointer; color: inherit; font-size: 1.05em; line-height: 1; padding: 0 0.05em; opacity: 0.65; }
113
+ .mang-chip-x:hover { opacity: 1; }
114
+ .mang-chip-x:focus-visible { outline: ${focusRing}; outline-offset: 2px; border-radius: ${radius.sm}; }
115
+
116
+ .mang-stepper { display: inline-flex; align-items: stretch; border: 1.5px solid var(--m-line-strong); border-radius: ${radius.md}; overflow: clip; background: var(--m-surface); }
117
+ .mang-stepper:focus-within { border-color: var(--m-accent); box-shadow: 0 0 0 3px ${mix(color.mangGreen, 35, "transparent")}; }
118
+ .mang-stepper-btn { appearance: none; cursor: pointer; border: none; background: transparent; color: var(--m-text-strong); width: 2.3rem; font-size: ${fontSize.lg}; line-height: 1; display: inline-flex; align-items: center; justify-content: center; transition: background ${motion.duration.fast} ${ease}, color ${motion.duration.fast} ${ease}; }
119
+ .mang-stepper-btn:hover:not(:disabled) { background: var(--m-accent-soft); color: var(--m-accent); }
120
+ .mang-stepper-btn:disabled { opacity: 0.4; cursor: not-allowed; }
121
+ .mang-stepper-input { width: 3.4rem; text-align: center; border: none; border-left: 1px solid var(--m-line); border-right: 1px solid var(--m-line); background: transparent; color: var(--m-text); font-family: "${font.body}", system-ui, sans-serif; font-size: ${fontSize.base}; font-variant-numeric: tabular-nums; -moz-appearance: textfield; }
122
+ .mang-stepper-input::-webkit-outer-spin-button, .mang-stepper-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
123
+ .mang-stepper-input:focus { outline: none; }
124
+
125
+ @media (prefers-reduced-motion: reduce) {
126
+ .mang-seg-opt, button.mang-chip, .mang-stepper-btn { transition: none; }
127
+ }
128
+ `
129
+ );
130
+ function SegmentedControl({
131
+ options,
132
+ value,
133
+ onChange,
134
+ ariaLabel,
135
+ size = "md",
136
+ theme,
137
+ className
138
+ }) {
139
+ useAreaStyles(STYLE_ID, CSS);
140
+ const scope = useScope(theme);
141
+ const group = { role: "group", "aria-label": ariaLabel };
142
+ return /* @__PURE__ */ jsx3(
143
+ "div",
144
+ {
145
+ ...scope,
146
+ ...group,
147
+ className: cx(scope.className, "mang-seg", className),
148
+ "data-size": size,
149
+ children: options.map((o) => /* @__PURE__ */ jsx3(
150
+ "button",
151
+ {
152
+ type: "button",
153
+ className: "mang-seg-opt",
154
+ "aria-pressed": o.value === value,
155
+ disabled: o.disabled,
156
+ onClick: () => onChange(o.value),
157
+ children: o.label
158
+ },
159
+ o.value
160
+ ))
161
+ }
162
+ );
163
+ }
164
+ function Chip({
165
+ children,
166
+ selected,
167
+ onClick,
168
+ onRemove,
169
+ removeLabel = "Xo\xE1",
170
+ icon,
171
+ theme,
172
+ className
173
+ }) {
174
+ useAreaStyles(STYLE_ID, CSS);
175
+ const scope = useScope(theme);
176
+ const content = /* @__PURE__ */ jsxs2(Fragment, { children: [
177
+ icon != null && /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: icon }),
178
+ /* @__PURE__ */ jsx3("span", { children }),
179
+ onRemove != null && /* @__PURE__ */ jsx3(
180
+ "button",
181
+ {
182
+ type: "button",
183
+ className: "mang-chip-x",
184
+ "aria-label": removeLabel,
185
+ onClick: (e) => {
186
+ e.stopPropagation();
187
+ onRemove();
188
+ },
189
+ children: "\xD7"
190
+ }
191
+ )
192
+ ] });
193
+ if (onClick) {
194
+ return /* @__PURE__ */ jsx3(
195
+ "button",
196
+ {
197
+ ...scope,
198
+ type: "button",
199
+ className: cx(scope.className, "mang-chip", className),
200
+ "data-selected": selected ? "true" : void 0,
201
+ "aria-pressed": selected,
202
+ onClick,
203
+ children: content
204
+ }
205
+ );
206
+ }
207
+ return /* @__PURE__ */ jsx3(
208
+ "span",
209
+ {
210
+ ...scope,
211
+ className: cx(scope.className, "mang-chip", className),
212
+ "data-selected": selected ? "true" : void 0,
213
+ children: content
214
+ }
215
+ );
216
+ }
217
+ function NumberStepper({
218
+ value,
219
+ onChange,
220
+ min = Number.NEGATIVE_INFINITY,
221
+ max = Number.POSITIVE_INFINITY,
222
+ step = 1,
223
+ ariaLabel,
224
+ theme,
225
+ className
226
+ }) {
227
+ useAreaStyles(STYLE_ID, CSS);
228
+ const scope = useScope(theme);
229
+ const id = useId2();
230
+ const clamp = (n) => Math.min(max, Math.max(min, n));
231
+ const set = (n) => {
232
+ if (!Number.isNaN(n)) onChange(clamp(n));
233
+ };
234
+ return /* @__PURE__ */ jsxs2("div", { ...scope, className: cx(scope.className, "mang-stepper", className), children: [
235
+ /* @__PURE__ */ jsx3(
236
+ "button",
237
+ {
238
+ type: "button",
239
+ className: "mang-stepper-btn",
240
+ "aria-label": `${ariaLabel ?? "S\u1ED1"} \u2212${step}`,
241
+ disabled: value <= min,
242
+ onClick: () => set(value - step),
243
+ children: "\u2212"
244
+ }
245
+ ),
246
+ /* @__PURE__ */ jsx3(
247
+ "input",
248
+ {
249
+ id,
250
+ type: "number",
251
+ className: "mang-stepper-input",
252
+ value,
253
+ min: min === Number.NEGATIVE_INFINITY ? void 0 : min,
254
+ max: max === Number.POSITIVE_INFINITY ? void 0 : max,
255
+ step,
256
+ "aria-label": ariaLabel,
257
+ onChange: (e) => set(Number(e.target.value))
258
+ }
259
+ ),
260
+ /* @__PURE__ */ jsx3(
261
+ "button",
262
+ {
263
+ type: "button",
264
+ className: "mang-stepper-btn",
265
+ "aria-label": `${ariaLabel ?? "S\u1ED1"} +${step}`,
266
+ disabled: value >= max,
267
+ onClick: () => set(value + step),
268
+ children: "+"
269
+ }
270
+ )
271
+ ] });
272
+ }
273
+
274
+ export {
275
+ Field,
276
+ Input,
277
+ TextArea,
278
+ Select,
279
+ SegmentedControl,
280
+ Chip,
281
+ NumberStepper
282
+ };
@@ -0,0 +1,145 @@
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/data-room/DataRoom.tsx
14
+ import { jsx, jsxs } from "react/jsx-runtime";
15
+ var STYLE_ID = "mang-ui-dataroom";
16
+ var { color, fontSize, fontWeight, radius, font } = tokens;
17
+ var CSS = (
18
+ /* css */
19
+ `
20
+ .mang-room-badge { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.18rem 0.55rem; border-radius: ${radius.full}; font-family: "${font.heading}", system-ui, sans-serif; font-weight: ${fontWeight.semibold}; font-size: ${fontSize.xs}; }
21
+ .mang-room-badge[data-status="offline"] { background: var(--m-sunken); color: var(--m-text-muted); }
22
+ .mang-room-badge[data-status="cloud"] { background: var(--m-info-soft); color: var(--m-info-on); }
23
+ .mang-room-badge[data-status="realtime"] { background: var(--m-success-soft); color: var(--m-success-on); }
24
+ .mang-room-peers { font-weight: ${fontWeight.bold}; }
25
+ .mang-room-link { display: flex; align-items: center; gap: 0.5rem; padding: 0.6rem 0.7rem; border: 1px solid var(--m-line); border-radius: ${radius.md}; background: var(--m-sunken); }
26
+ .mang-room-link code { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: ${fontSize.sm}; color: var(--m-text); }
27
+ .mang-room-presence { display: inline-flex; align-items: center; }
28
+ .mang-room-dot { width: 1.4rem; height: 1.4rem; border-radius: 50%; display: grid; place-items: center; font-size: 0.65rem; font-weight: ${fontWeight.bold}; color: #fff; margin-left: -0.4rem; box-shadow: 0 0 0 2px var(--m-surface); }
29
+ .mang-room-dot:first-child { margin-left: 0; }
30
+ .mang-room-conflict { display: flex; align-items: center; gap: 0.6rem; padding: 0.7rem 0.9rem; border-radius: ${radius.md}; background: var(--m-warning-soft); color: var(--m-warning-on); border: 1px solid color-mix(in oklab, ${color.sun} 40%, transparent); }
31
+ .mang-room-conflict-msg { flex: 1; font-size: ${fontSize.sm}; }
32
+ `
33
+ );
34
+ var STATUS_META = {
35
+ offline: { icon: "\u{1F4E6}", vi: "Tr\xEAn m\xE1y", en: "On-device" },
36
+ cloud: { icon: "\u2601\uFE0F", vi: "\u0110\xE1m m\xE2y", en: "Cloud" },
37
+ realtime: { icon: "\u26A1", vi: "Tr\u1EF1c ti\u1EBFp", en: "Live" }
38
+ };
39
+ function RoomStatusBadge({
40
+ status,
41
+ peers,
42
+ locale = "vi",
43
+ theme,
44
+ className
45
+ }) {
46
+ useAreaStyles(STYLE_ID, CSS);
47
+ const scope = useScope(theme);
48
+ const m = STATUS_META[status];
49
+ return /* @__PURE__ */ jsxs(
50
+ "span",
51
+ {
52
+ ...scope,
53
+ className: cx(scope.className, "mang-room-badge", className),
54
+ "data-status": status,
55
+ children: [
56
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: m.icon }),
57
+ locale === "vi" ? m.vi : m.en,
58
+ status === "realtime" && peers != null && peers > 0 && /* @__PURE__ */ jsxs("span", { className: "mang-room-peers", children: [
59
+ " \xB7 ",
60
+ peers
61
+ ] })
62
+ ]
63
+ }
64
+ );
65
+ }
66
+ function RoomShareButton({
67
+ onShare,
68
+ locale = "vi",
69
+ theme,
70
+ className,
71
+ children
72
+ }) {
73
+ return /* @__PURE__ */ jsx(Button, { theme, className, icon: "\u{1F517}", onClick: onShare, children: children ?? (locale === "vi" ? "Chia s\u1EBB ph\xF2ng" : "Share room") });
74
+ }
75
+ function RoomLinkCard({ url, onCopy, locale = "vi", theme, className }) {
76
+ useAreaStyles(STYLE_ID, CSS);
77
+ const scope = useScope(theme);
78
+ return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-room-link", className), children: [
79
+ /* @__PURE__ */ jsx("code", { children: url }),
80
+ /* @__PURE__ */ jsx(
81
+ Button,
82
+ {
83
+ size: "sm",
84
+ variant: "secondary",
85
+ theme,
86
+ onClick: () => {
87
+ onCopy?.();
88
+ void navigator.clipboard?.writeText(url).catch(() => {
89
+ });
90
+ },
91
+ children: locale === "vi" ? "Sao ch\xE9p" : "Copy"
92
+ }
93
+ )
94
+ ] });
95
+ }
96
+ function RoomPresence({ peers, max = 5, theme, className }) {
97
+ useAreaStyles(STYLE_ID, CSS);
98
+ const scope = useScope(theme);
99
+ const shown = peers.slice(0, max);
100
+ const extra = peers.length - shown.length;
101
+ return /* @__PURE__ */ jsxs(
102
+ "span",
103
+ {
104
+ ...scope,
105
+ className: cx(scope.className, "mang-room-presence", className),
106
+ "aria-label": `${peers.length} ng\u01B0\u1EDDi`,
107
+ children: [
108
+ shown.map((p, i) => /* @__PURE__ */ jsx(
109
+ "span",
110
+ {
111
+ className: "mang-room-dot",
112
+ style: { background: [color.mangGreen, color.soil, color.bamboo, color.sun][i % 4] },
113
+ children: (p[0] ?? "?").toUpperCase()
114
+ },
115
+ i
116
+ )),
117
+ extra > 0 && /* @__PURE__ */ jsxs("span", { className: "mang-room-dot", style: { background: color.bamboo }, children: [
118
+ "+",
119
+ extra
120
+ ] })
121
+ ]
122
+ }
123
+ );
124
+ }
125
+ function RoomConflictNotice({
126
+ onReload,
127
+ locale = "vi",
128
+ theme,
129
+ className
130
+ }) {
131
+ useAreaStyles(STYLE_ID, CSS);
132
+ const scope = useScope(theme);
133
+ return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-room-conflict", className), role: "alert", children: [
134
+ /* @__PURE__ */ jsx("span", { className: "mang-room-conflict-msg", children: locale === "vi" ? "C\xF3 thay \u0111\u1ED5i m\u1EDBi t\u1EEB ng\u01B0\u1EDDi kh\xE1c. T\u1EA3i l\u1EA1i \u0111\u1EC3 \u0111\u1ED3ng b\u1ED9." : "Someone else made changes. Reload to sync." }),
135
+ /* @__PURE__ */ jsx(Button, { size: "sm", theme, onClick: onReload, children: locale === "vi" ? "T\u1EA3i l\u1EA1i" : "Reload" })
136
+ ] });
137
+ }
138
+
139
+ export {
140
+ RoomStatusBadge,
141
+ RoomShareButton,
142
+ RoomLinkCard,
143
+ RoomPresence,
144
+ RoomConflictNotice
145
+ };
@@ -0,0 +1,170 @@
1
+ // src/tokens.ts
2
+ var color = {
3
+ mangGreen: "#37B693",
4
+ // xanh tre chủ đạo · "by RumitX" thread
5
+ shoot: "#8FE3B8",
6
+ // mầm non · highlight
7
+ bamboo: "#1F7A5C",
8
+ // tre đậm · shadow/line
9
+ soil: "#B5793A",
10
+ // đất · warm accent (chất đồng quê)
11
+ sun: "#E8C547",
12
+ // tre vàng · accent nổi
13
+ paper: "#F4F1E8",
14
+ // nền sáng (giấy)
15
+ dark: "#14201C"
16
+ // nền tối (charcoal ngả xanh)
17
+ };
18
+ var font = {
19
+ heading: "Quicksand Variable",
20
+ // rounded VN-safe display (@fontsource-variable/quicksand)
21
+ body: "Inter"
22
+ // body & UI (system-ui fallback today)
23
+ };
24
+ var semantic = {
25
+ surface: {
26
+ base: "#FFFFFF",
27
+ // cards, primary content surface
28
+ sunken: "#F6FAF9",
29
+ // subtle fills: inputs, chips, inset panels
30
+ inverse: "#14201C"
31
+ // dark sections (mirrors brand `dark`)
32
+ },
33
+ content: {
34
+ default: "#16242C",
35
+ // body text
36
+ strong: "#14201C",
37
+ // headings/titles (brand charcoal-green)
38
+ muted: "#5D6F78",
39
+ // secondary / meta text
40
+ inverse: "#F4F1E8",
41
+ // text on dark surfaces (mirrors brand `paper`)
42
+ onAccent: "#FFFFFF"
43
+ // text on the accent fill
44
+ },
45
+ line: {
46
+ subtle: "#EEF3F2",
47
+ // hairline dividers
48
+ default: "#E4ECEB",
49
+ // default borders
50
+ strong: "#CDD9D6"
51
+ // emphasised borders
52
+ },
53
+ accent: {
54
+ default: "#37B693",
55
+ // = mangGreen
56
+ hover: "#2E9E80",
57
+ // mangGreen nudged toward dark, for hover
58
+ soft: "#E7F6F1"
59
+ // tint: selected chips, active fills
60
+ },
61
+ state: {
62
+ success: "#1F9C7E",
63
+ // credit / positive money
64
+ successSoft: "#E7F6F1",
65
+ // success tint background
66
+ danger: "#D2674A",
67
+ // debit / destructive
68
+ dangerSoft: "#FBEEE9",
69
+ // danger tint background
70
+ warning: "#C77D2E",
71
+ // caution (earthy amber, sits with the bamboo palette)
72
+ warningSoft: "#FBF1E2",
73
+ // warning tint background
74
+ info: "#2E7CB8",
75
+ // neutral info (calm water-blue)
76
+ infoSoft: "#E6F0F8"
77
+ // info tint background
78
+ }
79
+ };
80
+ var space = {
81
+ 0: "0",
82
+ 1: "0.25rem",
83
+ 2: "0.5rem",
84
+ 3: "0.75rem",
85
+ 4: "1rem",
86
+ 5: "1.25rem",
87
+ 6: "1.5rem",
88
+ 8: "2rem",
89
+ 10: "2.5rem",
90
+ 12: "3rem",
91
+ 16: "4rem"
92
+ };
93
+ var radius = {
94
+ none: "0",
95
+ sm: "0.5rem",
96
+ md: "0.6875rem",
97
+ // 11px — chips, inputs, small buttons
98
+ lg: "1rem",
99
+ // 16px — cards
100
+ xl: "1.375rem",
101
+ // 22px — dialogs
102
+ full: "999px"
103
+ // pills, avatars
104
+ };
105
+ var shadow = {
106
+ sm: "0 1px 2px rgba(11, 30, 45, 0.05)",
107
+ md: "0 1px 2px rgba(11, 30, 45, 0.05), 0 12px 28px -16px rgba(11, 30, 45, 0.28)",
108
+ lg: "0 18px 40px -18px rgba(11, 30, 45, 0.32)"
109
+ };
110
+ var fontSize = {
111
+ xs: "0.75rem",
112
+ sm: "0.85rem",
113
+ base: "1rem",
114
+ lg: "1.15rem",
115
+ xl: "1.35rem",
116
+ "2xl": "1.6rem",
117
+ "3xl": "2.1rem"
118
+ };
119
+ var fontWeight = {
120
+ normal: "400",
121
+ medium: "600",
122
+ semibold: "700",
123
+ bold: "800"
124
+ };
125
+ var lineHeight = {
126
+ tight: "1.15",
127
+ snug: "1.3",
128
+ normal: "1.5",
129
+ relaxed: "1.7"
130
+ };
131
+ var motion = {
132
+ duration: {
133
+ fast: "140ms",
134
+ base: "180ms",
135
+ slow: "240ms"
136
+ },
137
+ ease: {
138
+ standard: "cubic-bezier(0.16, 1, 0.3, 1)",
139
+ // juicy ease-out — the Măng default
140
+ out: "cubic-bezier(0.16, 1, 0.3, 1)",
141
+ in: "cubic-bezier(0.4, 0, 1, 1)"
142
+ }
143
+ };
144
+ var z = {
145
+ base: "0",
146
+ dropdown: "100",
147
+ sticky: "200",
148
+ overlay: "900",
149
+ modal: "1000",
150
+ toast: "1100"
151
+ };
152
+ var tokens = {
153
+ color,
154
+ font,
155
+ semantic,
156
+ space,
157
+ radius,
158
+ shadow,
159
+ fontSize,
160
+ fontWeight,
161
+ lineHeight,
162
+ motion,
163
+ z
164
+ };
165
+ var defaultTheme = { color, font };
166
+
167
+ export {
168
+ tokens,
169
+ defaultTheme
170
+ };
@@ -0,0 +1,47 @@
1
+ import {
2
+ cx,
3
+ useKitStyles,
4
+ useScope
5
+ } from "./chunk-3AL4SUFD.js";
6
+
7
+ // src/forms/Toggle.tsx
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ function Checkbox({ label, theme, className, disabled, ...rest }) {
10
+ useKitStyles();
11
+ const scope = useScope(theme);
12
+ return /* @__PURE__ */ jsxs(
13
+ "label",
14
+ {
15
+ ...scope,
16
+ className: cx(scope.className, "mang-checkbox", className),
17
+ "data-disabled": disabled ? "true" : void 0,
18
+ children: [
19
+ /* @__PURE__ */ jsx("input", { type: "checkbox", disabled, ...rest }),
20
+ label != null && /* @__PURE__ */ jsx("span", { children: label })
21
+ ]
22
+ }
23
+ );
24
+ }
25
+ function Switch({ label, theme, className, disabled, ...rest }) {
26
+ useKitStyles();
27
+ const scope = useScope(theme);
28
+ return /* @__PURE__ */ jsxs(
29
+ "label",
30
+ {
31
+ ...scope,
32
+ className: cx(scope.className, "mang-switch", className),
33
+ "data-disabled": disabled ? "true" : void 0,
34
+ children: [
35
+ /* @__PURE__ */ jsx("input", { type: "checkbox", disabled, ...rest }),
36
+ /* @__PURE__ */ jsx("span", { className: "mang-switch-track", "aria-hidden": "true" }),
37
+ /* @__PURE__ */ jsx("span", { className: "mang-switch-thumb", "aria-hidden": "true" }),
38
+ label != null && /* @__PURE__ */ jsx("span", { children: label })
39
+ ]
40
+ }
41
+ );
42
+ }
43
+
44
+ export {
45
+ Checkbox,
46
+ Switch
47
+ };