@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.
- package/LICENSE +26 -0
- package/dist/MangThemeProvider-BqdGKBP2.d.ts +34 -0
- package/dist/Money-Dw3GnUvX.d.ts +27 -0
- package/dist/actions.d.ts +31 -0
- package/dist/actions.js +13 -0
- package/dist/ai.d.ts +58 -0
- package/dist/ai.js +13 -0
- package/dist/analytics.d.ts +40 -0
- package/dist/analytics.js +15 -0
- package/dist/app.d.ts +24 -0
- package/dist/app.js +9 -0
- package/dist/catalog.d.ts +76 -0
- package/dist/catalog.js +1210 -0
- package/dist/charts.d.ts +89 -0
- package/dist/charts.js +34 -0
- package/dist/chunk-3AL4SUFD.js +301 -0
- package/dist/chunk-4XNSYKQE.js +142 -0
- package/dist/chunk-5Z4VLQKH.js +43 -0
- package/dist/chunk-7P2EQZYD.js +59 -0
- package/dist/chunk-7WHNIEDV.js +120 -0
- package/dist/chunk-ASZKHSMG.js +82 -0
- package/dist/chunk-BCBN2EGH.js +216 -0
- package/dist/chunk-BLYAFV45.js +320 -0
- package/dist/chunk-DLKEXWPA.js +90 -0
- package/dist/chunk-DTASXPTB.js +70 -0
- package/dist/chunk-FZRXVRC7.js +63 -0
- package/dist/chunk-ID233AGM.js +108 -0
- package/dist/chunk-IVYXOKMO.js +74 -0
- package/dist/chunk-IX3DYETF.js +61 -0
- package/dist/chunk-JJB4PJC3.js +166 -0
- package/dist/chunk-K5Q3RCV6.js +119 -0
- package/dist/chunk-LNRUPJDF.js +161 -0
- package/dist/chunk-LZORNMBL.js +0 -0
- package/dist/chunk-OBPXCUVF.js +282 -0
- package/dist/chunk-OJX2EIMB.js +145 -0
- package/dist/chunk-PPOYMKV3.js +170 -0
- package/dist/chunk-PQGUWJG4.js +47 -0
- package/dist/chunk-RE7OWRA4.js +187 -0
- package/dist/chunk-SJF3CHAW.js +108 -0
- package/dist/chunk-UF6ANDJZ.js +112 -0
- package/dist/chunk-VGC5DMOM.js +107 -0
- package/dist/chunk-VP56Z4BS.js +0 -0
- package/dist/chunk-VRD66FIA.js +77 -0
- package/dist/chunk-X7T2DJLU.js +113 -0
- package/dist/chunk-XPV3OOLU.js +147 -0
- package/dist/chunk-YN5O6YL6.js +69 -0
- package/dist/chunk-Z4ANGBPC.js +94 -0
- package/dist/creator.d.ts +55 -0
- package/dist/creator.js +20 -0
- package/dist/data-room.d.ts +50 -0
- package/dist/data-room.js +17 -0
- package/dist/editor.d.ts +32 -0
- package/dist/editor.js +14 -0
- package/dist/feedback.d.ts +48 -0
- package/dist/feedback.js +16 -0
- package/dist/forms.d.ts +91 -0
- package/dist/forms.js +26 -0
- package/dist/handoff.d.ts +37 -0
- package/dist/handoff.js +13 -0
- package/dist/index.css +2 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +338 -0
- package/dist/layout.d.ts +57 -0
- package/dist/layout.js +22 -0
- package/dist/learning.d.ts +46 -0
- package/dist/learning.js +15 -0
- package/dist/media.d.ts +48 -0
- package/dist/media.js +16 -0
- package/dist/monetization.d.ts +30 -0
- package/dist/monetization.js +14 -0
- package/dist/money.d.ts +45 -0
- package/dist/money.js +28 -0
- package/dist/navigation.d.ts +36 -0
- package/dist/navigation.js +14 -0
- package/dist/overlay.d.ts +72 -0
- package/dist/overlay.js +20 -0
- package/dist/platform.d.ts +94 -0
- package/dist/platform.js +42 -0
- package/dist/primitives.d.ts +83 -0
- package/dist/primitives.js +22 -0
- package/dist/privacy.d.ts +28 -0
- package/dist/privacy.js +15 -0
- package/dist/sandbox.d.ts +40 -0
- package/dist/sandbox.js +15 -0
- package/dist/settings.d.ts +29 -0
- package/dist/settings.js +13 -0
- package/dist/surface.d.ts +33 -0
- package/dist/surface.js +16 -0
- package/dist/theme.css +63 -0
- package/dist/theme.d.ts +64 -0
- package/dist/theme.js +27 -0
- package/dist/tokens.css +119 -0
- package/dist/tokens.d.ts +128 -0
- package/dist/tokens.js +8 -0
- package/package.json +151 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Badge
|
|
3
|
+
} from "./chunk-FZRXVRC7.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/privacy/Privacy.tsx
|
|
14
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
var STYLE_ID = "mang-ui-privacy";
|
|
16
|
+
var { fontSize, radius } = tokens;
|
|
17
|
+
var CSS = (
|
|
18
|
+
/* css */
|
|
19
|
+
`
|
|
20
|
+
.mang-privacy { display: flex; align-items: flex-start; gap: 0.5rem; padding: 0.7rem 0.85rem; border-radius: ${radius.md}; background: var(--m-success-soft); color: var(--m-success-on); font-size: ${fontSize.sm}; }
|
|
21
|
+
.mang-privacy[data-tone="warn"] { background: var(--m-warning-soft); color: var(--m-warning-on); }
|
|
22
|
+
.mang-privacy-icon { flex: none; }
|
|
23
|
+
`
|
|
24
|
+
);
|
|
25
|
+
function PrivacyNotice({ children, icon = "\u{1F512}", theme, className }) {
|
|
26
|
+
useAreaStyles(STYLE_ID, CSS);
|
|
27
|
+
const scope = useScope(theme);
|
|
28
|
+
return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-privacy", className), role: "note", children: [
|
|
29
|
+
/* @__PURE__ */ jsx("span", { className: "mang-privacy-icon", "aria-hidden": "true", children: icon }),
|
|
30
|
+
/* @__PURE__ */ jsx("span", { children })
|
|
31
|
+
] });
|
|
32
|
+
}
|
|
33
|
+
function LocalFirstNotice({
|
|
34
|
+
locale = "vi",
|
|
35
|
+
theme,
|
|
36
|
+
className
|
|
37
|
+
}) {
|
|
38
|
+
return /* @__PURE__ */ jsx(PrivacyNotice, { theme, className, children: locale === "vi" ? "Ch\u1EA1y offline \xB7 d\u1EEF li\u1EC7u ch\u1EC9 \u1EDF tr\xEAn m\xE1y b\u1EA1n" : "Runs offline \xB7 data stays on your device" });
|
|
39
|
+
}
|
|
40
|
+
function NoPiiBadge({ locale = "vi", theme, className }) {
|
|
41
|
+
return /* @__PURE__ */ jsx(Badge, { tone: "success", icon: "\u{1F512}", theme, className, children: locale === "vi" ? "Kh\xF4ng thu th\u1EADp PII" : "No PII" });
|
|
42
|
+
}
|
|
43
|
+
function ExternalLinkWarning({
|
|
44
|
+
href,
|
|
45
|
+
locale = "vi",
|
|
46
|
+
theme,
|
|
47
|
+
className
|
|
48
|
+
}) {
|
|
49
|
+
useAreaStyles(STYLE_ID, CSS);
|
|
50
|
+
const scope = useScope(theme);
|
|
51
|
+
return /* @__PURE__ */ jsxs(
|
|
52
|
+
"div",
|
|
53
|
+
{
|
|
54
|
+
...scope,
|
|
55
|
+
className: cx(scope.className, "mang-privacy", className),
|
|
56
|
+
"data-tone": "warn",
|
|
57
|
+
role: "note",
|
|
58
|
+
children: [
|
|
59
|
+
/* @__PURE__ */ jsx("span", { className: "mang-privacy-icon", "aria-hidden": "true", children: "\u2197" }),
|
|
60
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
61
|
+
locale === "vi" ? "M\u1EDF li\xEAn k\u1EBFt ngo\xE0i: " : "Opens an external link: ",
|
|
62
|
+
/* @__PURE__ */ jsx("b", { children: href })
|
|
63
|
+
] })
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export {
|
|
70
|
+
PrivacyNotice,
|
|
71
|
+
LocalFirstNotice,
|
|
72
|
+
NoPiiBadge,
|
|
73
|
+
ExternalLinkWarning
|
|
74
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cx,
|
|
3
|
+
useKitStyles,
|
|
4
|
+
useScope
|
|
5
|
+
} from "./chunk-3AL4SUFD.js";
|
|
6
|
+
|
|
7
|
+
// src/platform/Money.tsx
|
|
8
|
+
import { jsx } from "react/jsx-runtime";
|
|
9
|
+
function formatVnd(amount) {
|
|
10
|
+
const rounded = Math.round(amount);
|
|
11
|
+
const grouped = new Intl.NumberFormat("vi-VN").format(Math.abs(rounded));
|
|
12
|
+
return `${rounded < 0 ? "-" : ""}${grouped} \u0111`;
|
|
13
|
+
}
|
|
14
|
+
function signAttr(value, sign) {
|
|
15
|
+
if (sign === "none") return void 0;
|
|
16
|
+
if (sign === "positive") return "positive";
|
|
17
|
+
if (sign === "negative") return "negative";
|
|
18
|
+
if (value > 0) return "positive";
|
|
19
|
+
if (value < 0) return "negative";
|
|
20
|
+
return void 0;
|
|
21
|
+
}
|
|
22
|
+
function VndText({ amount, sign = "none", theme, className }) {
|
|
23
|
+
useKitStyles();
|
|
24
|
+
const scope = useScope(theme);
|
|
25
|
+
return /* @__PURE__ */ jsx(
|
|
26
|
+
"span",
|
|
27
|
+
{
|
|
28
|
+
...scope,
|
|
29
|
+
className: cx(scope.className, "mang-money", className),
|
|
30
|
+
"data-sign": signAttr(amount, sign),
|
|
31
|
+
children: formatVnd(amount)
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
function MoneyText({
|
|
36
|
+
amount,
|
|
37
|
+
locale = "vi-VN",
|
|
38
|
+
currency = "VND",
|
|
39
|
+
sign = "none",
|
|
40
|
+
theme,
|
|
41
|
+
className
|
|
42
|
+
}) {
|
|
43
|
+
useKitStyles();
|
|
44
|
+
const scope = useScope(theme);
|
|
45
|
+
const text = new Intl.NumberFormat(locale, { style: "currency", currency }).format(amount);
|
|
46
|
+
return /* @__PURE__ */ jsx(
|
|
47
|
+
"span",
|
|
48
|
+
{
|
|
49
|
+
...scope,
|
|
50
|
+
className: cx(scope.className, "mang-money", className),
|
|
51
|
+
"data-sign": signAttr(amount, sign),
|
|
52
|
+
children: text
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
formatVnd,
|
|
59
|
+
VndText,
|
|
60
|
+
MoneyText
|
|
61
|
+
};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SafetyScanBadge,
|
|
3
|
+
StaticScanResult
|
|
4
|
+
} from "./chunk-X7T2DJLU.js";
|
|
5
|
+
import {
|
|
6
|
+
Badge
|
|
7
|
+
} from "./chunk-FZRXVRC7.js";
|
|
8
|
+
import {
|
|
9
|
+
cx,
|
|
10
|
+
useAreaStyles,
|
|
11
|
+
useScope
|
|
12
|
+
} from "./chunk-3AL4SUFD.js";
|
|
13
|
+
import {
|
|
14
|
+
tokens
|
|
15
|
+
} from "./chunk-PPOYMKV3.js";
|
|
16
|
+
|
|
17
|
+
// src/creator/Creator.tsx
|
|
18
|
+
import { useRef, useState } from "react";
|
|
19
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
var STYLE_ID = "mang-ui-creator";
|
|
21
|
+
var { fontSize, fontWeight, radius, font } = tokens;
|
|
22
|
+
var CSS = (
|
|
23
|
+
/* css */
|
|
24
|
+
`
|
|
25
|
+
.mang-drop { display: grid; gap: 0.4rem; justify-items: center; text-align: center; padding: 1.75rem 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; }
|
|
26
|
+
.mang-drop[data-over="true"] { border-color: var(--m-accent); background: var(--m-accent-soft); }
|
|
27
|
+
.mang-drop-icon { font-size: 1.8rem; }
|
|
28
|
+
.mang-drop-title { font-family: "${font.heading}", system-ui, sans-serif; font-weight: ${fontWeight.bold}; color: var(--m-text-strong); font-size: ${fontSize.base}; }
|
|
29
|
+
.mang-drop-file { font-size: ${fontSize.sm}; color: var(--m-text); }
|
|
30
|
+
.mang-manifest { display: grid; gap: 0.5rem; padding: 0.9rem 1rem; border: 1px solid var(--m-line); border-radius: ${radius.lg}; background: var(--m-surface); }
|
|
31
|
+
.mang-manifest-row { display: grid; grid-template-columns: 7rem 1fr; gap: 0.5rem; font-size: ${fontSize.sm}; }
|
|
32
|
+
.mang-manifest-key { color: var(--m-text-muted); font-weight: ${fontWeight.semibold}; }
|
|
33
|
+
.mang-manifest-val { color: var(--m-text); }
|
|
34
|
+
.mang-manifest-chips { display: flex; flex-wrap: wrap; gap: 0.3rem; }
|
|
35
|
+
.mang-scanpanel { display: grid; gap: 0.6rem; }
|
|
36
|
+
`
|
|
37
|
+
);
|
|
38
|
+
function BundleUploadDropzone({
|
|
39
|
+
onFile,
|
|
40
|
+
accept = ".js,.mjs",
|
|
41
|
+
file,
|
|
42
|
+
locale = "vi",
|
|
43
|
+
theme,
|
|
44
|
+
className
|
|
45
|
+
}) {
|
|
46
|
+
useAreaStyles(STYLE_ID, CSS);
|
|
47
|
+
const scope = useScope(theme);
|
|
48
|
+
const inputRef = useRef(null);
|
|
49
|
+
const [over, setOver] = useState(false);
|
|
50
|
+
const pick = (f) => {
|
|
51
|
+
if (f) onFile(f);
|
|
52
|
+
};
|
|
53
|
+
const onDrop = (e) => {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
setOver(false);
|
|
56
|
+
pick(e.dataTransfer.files?.[0]);
|
|
57
|
+
};
|
|
58
|
+
const trigger = { role: "button", tabIndex: 0 };
|
|
59
|
+
return /* @__PURE__ */ jsxs(
|
|
60
|
+
"div",
|
|
61
|
+
{
|
|
62
|
+
...scope,
|
|
63
|
+
...trigger,
|
|
64
|
+
className: cx(scope.className, "mang-drop", className),
|
|
65
|
+
"data-over": over ? "true" : void 0,
|
|
66
|
+
onClick: () => inputRef.current?.click(),
|
|
67
|
+
onKeyDown: (e) => {
|
|
68
|
+
if (e.key === "Enter" || e.key === " ") inputRef.current?.click();
|
|
69
|
+
},
|
|
70
|
+
onDragOver: (e) => {
|
|
71
|
+
e.preventDefault();
|
|
72
|
+
setOver(true);
|
|
73
|
+
},
|
|
74
|
+
onDragLeave: () => setOver(false),
|
|
75
|
+
onDrop,
|
|
76
|
+
children: [
|
|
77
|
+
/* @__PURE__ */ jsx("span", { className: "mang-drop-icon", "aria-hidden": "true", children: "\u{1F4E6}" }),
|
|
78
|
+
/* @__PURE__ */ jsx("span", { className: "mang-drop-title", children: locale === "vi" ? "K\xE9o th\u1EA3 bundle ho\u1EB7c b\u1EA5m \u0111\u1EC3 ch\u1ECDn" : "Drop a bundle or click to choose" }),
|
|
79
|
+
file && /* @__PURE__ */ jsxs("span", { className: "mang-drop-file", children: [
|
|
80
|
+
file.name,
|
|
81
|
+
" \xB7 ",
|
|
82
|
+
(file.size / 1024).toFixed(0),
|
|
83
|
+
" KB"
|
|
84
|
+
] }),
|
|
85
|
+
/* @__PURE__ */ jsx(
|
|
86
|
+
"input",
|
|
87
|
+
{
|
|
88
|
+
ref: inputRef,
|
|
89
|
+
type: "file",
|
|
90
|
+
accept,
|
|
91
|
+
hidden: true,
|
|
92
|
+
onChange: (e) => {
|
|
93
|
+
pick(e.target.files?.[0]);
|
|
94
|
+
e.target.value = "";
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
function ManifestPreview({ manifest, theme, className }) {
|
|
103
|
+
useAreaStyles(STYLE_ID, CSS);
|
|
104
|
+
const scope = useScope(theme);
|
|
105
|
+
const row = (k, v) => /* @__PURE__ */ jsxs("div", { className: "mang-manifest-row", children: [
|
|
106
|
+
/* @__PURE__ */ jsx("span", { className: "mang-manifest-key", children: k }),
|
|
107
|
+
/* @__PURE__ */ jsx("span", { className: "mang-manifest-val", children: v })
|
|
108
|
+
] });
|
|
109
|
+
const chips = (items) => items && items.length > 0 ? /* @__PURE__ */ jsx("span", { className: "mang-manifest-chips", children: items.map((it) => /* @__PURE__ */ jsx(Badge, { tone: "neutral", theme, children: it }, it)) }) : "\u2014";
|
|
110
|
+
return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-manifest", className), children: [
|
|
111
|
+
row("id", /* @__PURE__ */ jsx("code", { children: manifest.id })),
|
|
112
|
+
manifest.name != null && row("name", manifest.name),
|
|
113
|
+
manifest.version != null && row("version", /* @__PURE__ */ jsx("code", { children: manifest.version })),
|
|
114
|
+
row("permissions", chips(manifest.permissions)),
|
|
115
|
+
row("surfaces", chips(manifest.surfaces)),
|
|
116
|
+
row("commands", chips(manifest.commands))
|
|
117
|
+
] });
|
|
118
|
+
}
|
|
119
|
+
function StaticScanPanel({
|
|
120
|
+
level,
|
|
121
|
+
findings,
|
|
122
|
+
locale = "vi",
|
|
123
|
+
theme,
|
|
124
|
+
className
|
|
125
|
+
}) {
|
|
126
|
+
useAreaStyles(STYLE_ID, CSS);
|
|
127
|
+
const scope = useScope(theme);
|
|
128
|
+
return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-scanpanel", className), children: [
|
|
129
|
+
/* @__PURE__ */ jsx(SafetyScanBadge, { level, locale, theme }),
|
|
130
|
+
/* @__PURE__ */ jsx(StaticScanResult, { findings, theme })
|
|
131
|
+
] });
|
|
132
|
+
}
|
|
133
|
+
var REVIEW_META = {
|
|
134
|
+
draft: { tone: "neutral", icon: "\u{1F4DD}", vi: "Nh\xE1p", en: "Draft" },
|
|
135
|
+
pending_review: { tone: "info", icon: "\u23F3", vi: "Ch\u1EDD duy\u1EC7t", en: "Pending review" },
|
|
136
|
+
changes: { tone: "warning", icon: "\u270F\uFE0F", vi: "C\u1EA7n s\u1EEDa", en: "Changes requested" },
|
|
137
|
+
live: { tone: "success", icon: "\u{1F7E2}", vi: "\u0110ang ch\u1EA1y", en: "Live" },
|
|
138
|
+
rejected: { tone: "danger", icon: "\u26D4", vi: "T\u1EEB ch\u1ED1i", en: "Rejected" }
|
|
139
|
+
};
|
|
140
|
+
function ReviewStatusBadge({
|
|
141
|
+
status,
|
|
142
|
+
locale = "vi",
|
|
143
|
+
theme,
|
|
144
|
+
className
|
|
145
|
+
}) {
|
|
146
|
+
const m = REVIEW_META[status];
|
|
147
|
+
return /* @__PURE__ */ jsx(Badge, { tone: m.tone, icon: m.icon, theme, className, children: locale === "vi" ? m.vi : m.en });
|
|
148
|
+
}
|
|
149
|
+
function VersionBadge({ version, theme, className }) {
|
|
150
|
+
return /* @__PURE__ */ jsxs(Badge, { tone: "neutral", theme, className, children: [
|
|
151
|
+
"v",
|
|
152
|
+
version.replace(/^v/, "")
|
|
153
|
+
] });
|
|
154
|
+
}
|
|
155
|
+
function BuildBadge({ sha, theme, className }) {
|
|
156
|
+
return /* @__PURE__ */ jsx(Badge, { tone: "neutral", icon: "\u{1F3D7}\uFE0F", theme, className, children: sha.slice(0, 7) });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export {
|
|
160
|
+
BundleUploadDropzone,
|
|
161
|
+
ManifestPreview,
|
|
162
|
+
StaticScanPanel,
|
|
163
|
+
ReviewStatusBadge,
|
|
164
|
+
VersionBadge,
|
|
165
|
+
BuildBadge
|
|
166
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Badge
|
|
3
|
+
} from "./chunk-FZRXVRC7.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/platform/StatusBadges.tsx
|
|
14
|
+
import { jsx } from "react/jsx-runtime";
|
|
15
|
+
var SURFACE_META = {
|
|
16
|
+
desktop: { icon: "\u{1F5A5}\uFE0F", vi: "M\xE1y t\xEDnh", en: "Desktop" },
|
|
17
|
+
web: { icon: "\u{1F310}", vi: "Web", en: "Web" },
|
|
18
|
+
zalo: { icon: "\u{1F4AC}", vi: "Zalo", en: "Zalo" }
|
|
19
|
+
};
|
|
20
|
+
function SurfaceBadge({ surface, locale = "vi", theme, className }) {
|
|
21
|
+
const m = SURFACE_META[surface];
|
|
22
|
+
return /* @__PURE__ */ jsx(Badge, { tone: "neutral", icon: m.icon, theme, className, children: locale === "vi" ? m.vi : m.en });
|
|
23
|
+
}
|
|
24
|
+
function PermissionBadge({ permission, sensitive, theme, className }) {
|
|
25
|
+
return /* @__PURE__ */ jsx(
|
|
26
|
+
Badge,
|
|
27
|
+
{
|
|
28
|
+
tone: sensitive ? "warning" : "neutral",
|
|
29
|
+
icon: sensitive ? "\u{1F512}" : "\u{1F511}",
|
|
30
|
+
theme,
|
|
31
|
+
className,
|
|
32
|
+
children: permission
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
function LocalBadge({ locale = "vi", theme, className }) {
|
|
37
|
+
return /* @__PURE__ */ jsx(Badge, { tone: "neutral", icon: "\u{1F4E6}", theme, className, children: locale === "vi" ? "Tr\xEAn m\xE1y" : "On-device" });
|
|
38
|
+
}
|
|
39
|
+
function CloudBadge({ locale = "vi", theme, className }) {
|
|
40
|
+
return /* @__PURE__ */ jsx(Badge, { tone: "info", icon: "\u2601\uFE0F", theme, className, children: locale === "vi" ? "\u0110\xE1m m\xE2y" : "Cloud" });
|
|
41
|
+
}
|
|
42
|
+
function RealtimeBadge({ locale = "vi", theme, className }) {
|
|
43
|
+
return /* @__PURE__ */ jsx(Badge, { tone: "success", icon: "\u26A1", theme, className, children: locale === "vi" ? "Tr\u1EF1c ti\u1EBFp" : "Live" });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/platform/Gates.tsx
|
|
47
|
+
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
48
|
+
var STYLE_ID = "mang-ui-gates";
|
|
49
|
+
var { fontSize, fontWeight, radius, font } = tokens;
|
|
50
|
+
var CSS = (
|
|
51
|
+
/* css */
|
|
52
|
+
`
|
|
53
|
+
.mang-degrade { display: grid; gap: 0.4rem; justify-items: center; text-align: center; padding: 1.25rem; border: 1px dashed var(--m-line-strong); border-radius: ${radius.lg}; background: var(--m-sunken); color: var(--m-text-muted); }
|
|
54
|
+
.mang-degrade-icon { font-size: 1.6rem; }
|
|
55
|
+
.mang-degrade-title { font-family: "${font.heading}", system-ui, sans-serif; font-weight: ${fontWeight.bold}; color: var(--m-text-strong); font-size: ${fontSize.base}; }
|
|
56
|
+
.mang-degrade-body { font-size: ${fontSize.sm}; max-width: 28rem; }
|
|
57
|
+
`
|
|
58
|
+
);
|
|
59
|
+
var SURFACE_LABEL = {
|
|
60
|
+
desktop: { vi: "m\xE1y t\xEDnh", en: "desktop" },
|
|
61
|
+
web: { vi: "web", en: "web" },
|
|
62
|
+
zalo: { vi: "Zalo", en: "Zalo" }
|
|
63
|
+
};
|
|
64
|
+
function GracefulDegradePanel({
|
|
65
|
+
icon = "\u{1F6A7}",
|
|
66
|
+
title,
|
|
67
|
+
children,
|
|
68
|
+
theme,
|
|
69
|
+
className
|
|
70
|
+
}) {
|
|
71
|
+
useAreaStyles(STYLE_ID, CSS);
|
|
72
|
+
const scope = useScope(theme);
|
|
73
|
+
return /* @__PURE__ */ jsxs("div", { ...scope, className: cx(scope.className, "mang-degrade", className), role: "note", children: [
|
|
74
|
+
/* @__PURE__ */ jsx2("span", { className: "mang-degrade-icon", "aria-hidden": "true", children: icon }),
|
|
75
|
+
title != null && /* @__PURE__ */ jsx2("span", { className: "mang-degrade-title", children: title }),
|
|
76
|
+
children != null && /* @__PURE__ */ jsx2("span", { className: "mang-degrade-body", children })
|
|
77
|
+
] });
|
|
78
|
+
}
|
|
79
|
+
function SurfaceGate({
|
|
80
|
+
surfaces,
|
|
81
|
+
current,
|
|
82
|
+
locale = "vi",
|
|
83
|
+
fallback,
|
|
84
|
+
theme,
|
|
85
|
+
children
|
|
86
|
+
}) {
|
|
87
|
+
const allowed = !surfaces || surfaces.length === 0 || surfaces.includes(current);
|
|
88
|
+
if (allowed) return /* @__PURE__ */ jsx2(Fragment, { children });
|
|
89
|
+
if (fallback !== void 0) return /* @__PURE__ */ jsx2(Fragment, { children: fallback });
|
|
90
|
+
const where = (surfaces ?? []).map((s) => SURFACE_LABEL[s][locale]).join(" / ");
|
|
91
|
+
return /* @__PURE__ */ jsx2(
|
|
92
|
+
GracefulDegradePanel,
|
|
93
|
+
{
|
|
94
|
+
theme,
|
|
95
|
+
title: locale === "vi" ? "Ch\u01B0a h\u1ED7 tr\u1EE3 \u1EDF \u0111\xE2y" : "Not available here",
|
|
96
|
+
children: locale === "vi" ? `T\xEDnh n\u0103ng n\xE0y ch\u1EA1y tr\xEAn ${where}.` : `This feature runs on ${where}.`
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
function PermissionGate({ granted, fallback = null, children }) {
|
|
101
|
+
return /* @__PURE__ */ jsx2(Fragment, { children: granted ? children : fallback });
|
|
102
|
+
}
|
|
103
|
+
var DesktopOnly = ({ current, children }) => current === "desktop" ? /* @__PURE__ */ jsx2(Fragment, { children }) : null;
|
|
104
|
+
var WebOnly = ({ current, children }) => current === "web" ? /* @__PURE__ */ jsx2(Fragment, { children }) : null;
|
|
105
|
+
var ZaloOnly = ({ current, children }) => current === "zalo" ? /* @__PURE__ */ jsx2(Fragment, { children }) : null;
|
|
106
|
+
|
|
107
|
+
export {
|
|
108
|
+
SurfaceBadge,
|
|
109
|
+
PermissionBadge,
|
|
110
|
+
LocalBadge,
|
|
111
|
+
CloudBadge,
|
|
112
|
+
RealtimeBadge,
|
|
113
|
+
GracefulDegradePanel,
|
|
114
|
+
SurfaceGate,
|
|
115
|
+
PermissionGate,
|
|
116
|
+
DesktopOnly,
|
|
117
|
+
WebOnly,
|
|
118
|
+
ZaloOnly
|
|
119
|
+
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cx,
|
|
3
|
+
useKitStyles,
|
|
4
|
+
useScope
|
|
5
|
+
} from "./chunk-3AL4SUFD.js";
|
|
6
|
+
|
|
7
|
+
// src/overlay/Dialog.tsx
|
|
8
|
+
import { useId, useRef } from "react";
|
|
9
|
+
|
|
10
|
+
// src/overlay/useOverlay.ts
|
|
11
|
+
import { useEffect } from "react";
|
|
12
|
+
var FOCUSABLE = 'a[href],button:not(:disabled),textarea:not(:disabled),input:not(:disabled),select:not(:disabled),[tabindex]:not([tabindex="-1"])';
|
|
13
|
+
function useOverlay(open, onClose, ref) {
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (!open) return;
|
|
16
|
+
const node = ref.current;
|
|
17
|
+
const prevActive = document.activeElement;
|
|
18
|
+
const prevOverflow = document.body.style.overflow;
|
|
19
|
+
document.body.style.overflow = "hidden";
|
|
20
|
+
const focusables = node ? Array.from(node.querySelectorAll(FOCUSABLE)) : [];
|
|
21
|
+
(focusables[0] ?? node)?.focus();
|
|
22
|
+
const onKeyDown = (e) => {
|
|
23
|
+
if (e.key === "Escape") {
|
|
24
|
+
e.stopPropagation();
|
|
25
|
+
onClose();
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (e.key !== "Tab" || !node) return;
|
|
29
|
+
const items = Array.from(node.querySelectorAll(FOCUSABLE)).filter(
|
|
30
|
+
(el) => el.offsetParent !== null
|
|
31
|
+
);
|
|
32
|
+
const first = items[0];
|
|
33
|
+
const last = items[items.length - 1];
|
|
34
|
+
if (!first || !last) {
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const active = document.activeElement;
|
|
39
|
+
if (e.shiftKey && active === first) {
|
|
40
|
+
e.preventDefault();
|
|
41
|
+
last.focus();
|
|
42
|
+
} else if (!e.shiftKey && active === last) {
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
first.focus();
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
document.addEventListener("keydown", onKeyDown, true);
|
|
48
|
+
return () => {
|
|
49
|
+
document.removeEventListener("keydown", onKeyDown, true);
|
|
50
|
+
document.body.style.overflow = prevOverflow;
|
|
51
|
+
prevActive?.focus?.();
|
|
52
|
+
};
|
|
53
|
+
}, [open, onClose, ref]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/overlay/Dialog.tsx
|
|
57
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
58
|
+
function Dialog({
|
|
59
|
+
open,
|
|
60
|
+
onClose,
|
|
61
|
+
title,
|
|
62
|
+
footer,
|
|
63
|
+
dismissOnBackdrop = true,
|
|
64
|
+
theme,
|
|
65
|
+
className,
|
|
66
|
+
children
|
|
67
|
+
}) {
|
|
68
|
+
useKitStyles();
|
|
69
|
+
const scope = useScope(theme);
|
|
70
|
+
const ref = useRef(null);
|
|
71
|
+
const titleId = useId();
|
|
72
|
+
useOverlay(open, onClose, ref);
|
|
73
|
+
if (!open) return null;
|
|
74
|
+
const panel = {
|
|
75
|
+
role: "dialog",
|
|
76
|
+
"aria-modal": true,
|
|
77
|
+
"aria-labelledby": title ? titleId : void 0
|
|
78
|
+
};
|
|
79
|
+
return /* @__PURE__ */ jsx(
|
|
80
|
+
"div",
|
|
81
|
+
{
|
|
82
|
+
className: "mang-overlay-backdrop",
|
|
83
|
+
onMouseDown: (e) => {
|
|
84
|
+
if (dismissOnBackdrop && e.target === e.currentTarget) onClose();
|
|
85
|
+
},
|
|
86
|
+
children: /* @__PURE__ */ jsxs(
|
|
87
|
+
"div",
|
|
88
|
+
{
|
|
89
|
+
ref,
|
|
90
|
+
...scope,
|
|
91
|
+
...panel,
|
|
92
|
+
tabIndex: -1,
|
|
93
|
+
className: cx(scope.className, "mang-dialog", className),
|
|
94
|
+
children: [
|
|
95
|
+
title != null && /* @__PURE__ */ jsx("div", { className: "mang-dialog-head", children: /* @__PURE__ */ jsx("h2", { className: "mang-dialog-title", id: titleId, children: title }) }),
|
|
96
|
+
/* @__PURE__ */ jsx("div", { className: "mang-dialog-body", children }),
|
|
97
|
+
footer != null && /* @__PURE__ */ jsx("div", { className: "mang-dialog-foot", children: footer })
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/overlay/Sheet.tsx
|
|
106
|
+
import { useId as useId2, useRef as useRef2 } from "react";
|
|
107
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
108
|
+
function Sheet({
|
|
109
|
+
open,
|
|
110
|
+
onClose,
|
|
111
|
+
side = "right",
|
|
112
|
+
title,
|
|
113
|
+
footer,
|
|
114
|
+
dismissOnBackdrop = true,
|
|
115
|
+
theme,
|
|
116
|
+
className,
|
|
117
|
+
children
|
|
118
|
+
}) {
|
|
119
|
+
useKitStyles();
|
|
120
|
+
const scope = useScope(theme);
|
|
121
|
+
const ref = useRef2(null);
|
|
122
|
+
const titleId = useId2();
|
|
123
|
+
useOverlay(open, onClose, ref);
|
|
124
|
+
if (!open) return null;
|
|
125
|
+
const panel = {
|
|
126
|
+
role: "dialog",
|
|
127
|
+
"aria-modal": true,
|
|
128
|
+
"aria-labelledby": title ? titleId : void 0
|
|
129
|
+
};
|
|
130
|
+
return /* @__PURE__ */ jsx2(
|
|
131
|
+
"div",
|
|
132
|
+
{
|
|
133
|
+
className: "mang-overlay-backdrop",
|
|
134
|
+
"data-variant": "sheet",
|
|
135
|
+
onMouseDown: (e) => {
|
|
136
|
+
if (dismissOnBackdrop && e.target === e.currentTarget) onClose();
|
|
137
|
+
},
|
|
138
|
+
children: /* @__PURE__ */ jsxs2(
|
|
139
|
+
"div",
|
|
140
|
+
{
|
|
141
|
+
ref,
|
|
142
|
+
...scope,
|
|
143
|
+
...panel,
|
|
144
|
+
tabIndex: -1,
|
|
145
|
+
"data-side": side,
|
|
146
|
+
className: cx(scope.className, "mang-sheet", className),
|
|
147
|
+
children: [
|
|
148
|
+
title != null && /* @__PURE__ */ jsx2("div", { className: "mang-sheet-head", children: /* @__PURE__ */ jsx2("h2", { className: "mang-sheet-title", id: titleId, children: title }) }),
|
|
149
|
+
/* @__PURE__ */ jsx2("div", { className: "mang-sheet-body", style: { flex: 1, overflow: "auto" }, children }),
|
|
150
|
+
footer != null && /* @__PURE__ */ jsx2("div", { className: "mang-sheet-foot", children: footer })
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export {
|
|
159
|
+
Dialog,
|
|
160
|
+
Sheet
|
|
161
|
+
};
|
|
File without changes
|