@better-forge/ui 0.0.0-stage → 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 +21 -0
- package/README.md +13 -3
- package/dist/api/client.d.ts +42 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +130 -0
- package/dist/api/client.js.map +1 -0
- package/dist/components/ConfirmIdentityModal.d.ts +18 -0
- package/dist/components/ConfirmIdentityModal.d.ts.map +1 -0
- package/dist/components/ConfirmIdentityModal.js +30 -0
- package/dist/components/ConfirmIdentityModal.js.map +1 -0
- package/dist/components/ConfirmModal.d.ts +18 -0
- package/dist/components/ConfirmModal.d.ts.map +1 -0
- package/dist/components/ConfirmModal.js +11 -0
- package/dist/components/ConfirmModal.js.map +1 -0
- package/dist/components/CopyButton.d.ts +11 -0
- package/dist/components/CopyButton.d.ts.map +1 -0
- package/dist/components/CopyButton.js +44 -0
- package/dist/components/CopyButton.js.map +1 -0
- package/dist/components/CredentialSection.d.ts +38 -0
- package/dist/components/CredentialSection.d.ts.map +1 -0
- package/dist/components/CredentialSection.js +69 -0
- package/dist/components/CredentialSection.js.map +1 -0
- package/dist/components/ErrorBoundary.d.ts +18 -0
- package/dist/components/ErrorBoundary.d.ts.map +1 -0
- package/dist/components/ErrorBoundary.js +25 -0
- package/dist/components/ErrorBoundary.js.map +1 -0
- package/dist/components/ModalShell.d.ts +58 -0
- package/dist/components/ModalShell.d.ts.map +1 -0
- package/dist/components/ModalShell.js +92 -0
- package/dist/components/ModalShell.js.map +1 -0
- package/dist/components/ResetTwoFactorModal.d.ts +14 -0
- package/dist/components/ResetTwoFactorModal.d.ts.map +1 -0
- package/dist/components/ResetTwoFactorModal.js +16 -0
- package/dist/components/ResetTwoFactorModal.js.map +1 -0
- package/dist/components/SidePanel.d.ts +35 -0
- package/dist/components/SidePanel.d.ts.map +1 -0
- package/dist/components/SidePanel.js +19 -0
- package/dist/components/SidePanel.js.map +1 -0
- package/dist/components/SingleSignOnModal.d.ts +4 -0
- package/dist/components/SingleSignOnModal.d.ts.map +1 -0
- package/dist/components/SingleSignOnModal.js +64 -0
- package/dist/components/SingleSignOnModal.js.map +1 -0
- package/dist/components/SsoConfirmation.d.ts +22 -0
- package/dist/components/SsoConfirmation.d.ts.map +1 -0
- package/dist/components/SsoConfirmation.js +87 -0
- package/dist/components/SsoConfirmation.js.map +1 -0
- package/dist/components/VaultTypePicker.d.ts +13 -0
- package/dist/components/VaultTypePicker.d.ts.map +1 -0
- package/dist/components/VaultTypePicker.js +62 -0
- package/dist/components/VaultTypePicker.js.map +1 -0
- package/dist/components/WhatsNew.d.ts +18 -0
- package/dist/components/WhatsNew.d.ts.map +1 -0
- package/dist/components/WhatsNew.js +50 -0
- package/dist/components/WhatsNew.js.map +1 -0
- package/dist/components/formParts.d.ts +40 -0
- package/dist/components/formParts.d.ts.map +1 -0
- package/dist/components/formParts.js +31 -0
- package/dist/components/formParts.js.map +1 -0
- package/dist/components/ui/Alert.d.ts +15 -0
- package/dist/components/ui/Alert.d.ts.map +1 -0
- package/dist/components/ui/Alert.js +14 -0
- package/dist/components/ui/Alert.js.map +1 -0
- package/dist/components/ui/DataTable.d.ts +52 -0
- package/dist/components/ui/DataTable.d.ts.map +1 -0
- package/dist/components/ui/DataTable.js +112 -0
- package/dist/components/ui/DataTable.js.map +1 -0
- package/dist/components/ui/Field.d.ts +27 -0
- package/dist/components/ui/Field.d.ts.map +1 -0
- package/dist/components/ui/Field.js +25 -0
- package/dist/components/ui/Field.js.map +1 -0
- package/dist/components/ui/PageHeader.d.ts +18 -0
- package/dist/components/ui/PageHeader.d.ts.map +1 -0
- package/dist/components/ui/PageHeader.js +10 -0
- package/dist/components/ui/PageHeader.js.map +1 -0
- package/dist/components/ui/Pagination.d.ts +21 -0
- package/dist/components/ui/Pagination.d.ts.map +1 -0
- package/dist/components/ui/Pagination.js +10 -0
- package/dist/components/ui/Pagination.js.map +1 -0
- package/dist/components/ui/QuickStartPanel.d.ts +21 -0
- package/dist/components/ui/QuickStartPanel.d.ts.map +1 -0
- package/dist/components/ui/QuickStartPanel.js +11 -0
- package/dist/components/ui/QuickStartPanel.js.map +1 -0
- package/dist/components/ui/StateViews.d.ts +50 -0
- package/dist/components/ui/StateViews.d.ts.map +1 -0
- package/dist/components/ui/StateViews.js +33 -0
- package/dist/components/ui/StateViews.js.map +1 -0
- package/dist/components/ui/Switch.d.ts +16 -0
- package/dist/components/ui/Switch.d.ts.map +1 -0
- package/dist/components/ui/Switch.js +15 -0
- package/dist/components/ui/Switch.js.map +1 -0
- package/dist/components/ui/Toast.d.ts +20 -0
- package/dist/components/ui/Toast.d.ts.map +1 -0
- package/dist/components/ui/Toast.js +46 -0
- package/dist/components/ui/Toast.js.map +1 -0
- package/dist/components/ui/index.d.ts +10 -0
- package/dist/components/ui/index.d.ts.map +1 -0
- package/dist/components/ui/index.js +10 -0
- package/dist/components/ui/index.js.map +1 -0
- package/dist/config.d.ts +46 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +12 -0
- package/dist/config.js.map +1 -0
- package/dist/hooks/useDarkMode.d.ts +2 -0
- package/dist/hooks/useDarkMode.d.ts.map +1 -0
- package/dist/hooks/useDarkMode.js +37 -0
- package/dist/hooks/useDarkMode.js.map +1 -0
- package/dist/hooks/useDebouncedValue.d.ts +6 -0
- package/dist/hooks/useDebouncedValue.d.ts.map +1 -0
- package/dist/hooks/useDebouncedValue.js +19 -0
- package/dist/hooks/useDebouncedValue.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/changelog.d.ts +32 -0
- package/dist/lib/changelog.d.ts.map +1 -0
- package/dist/lib/changelog.js +71 -0
- package/dist/lib/changelog.js.map +1 -0
- package/dist/lib/dateFormat.d.ts +24 -0
- package/dist/lib/dateFormat.d.ts.map +1 -0
- package/dist/lib/dateFormat.js +67 -0
- package/dist/lib/dateFormat.js.map +1 -0
- package/dist/navigation.d.ts +5 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +7 -0
- package/dist/navigation.js.map +1 -0
- package/dist/pages/ApiTokens.d.ts +9 -0
- package/dist/pages/ApiTokens.d.ts.map +1 -0
- package/dist/pages/ApiTokens.js +116 -0
- package/dist/pages/ApiTokens.js.map +1 -0
- package/dist/pages/AuditLog.d.ts +14 -0
- package/dist/pages/AuditLog.d.ts.map +1 -0
- package/dist/pages/AuditLog.js +104 -0
- package/dist/pages/AuditLog.js.map +1 -0
- package/dist/pages/Backups.d.ts +2 -0
- package/dist/pages/Backups.d.ts.map +1 -0
- package/dist/pages/Backups.js +118 -0
- package/dist/pages/Backups.js.map +1 -0
- package/dist/pages/ChangePassword.d.ts +2 -0
- package/dist/pages/ChangePassword.d.ts.map +1 -0
- package/dist/pages/ChangePassword.js +40 -0
- package/dist/pages/ChangePassword.js.map +1 -0
- package/dist/pages/Login.d.ts +12 -0
- package/dist/pages/Login.d.ts.map +1 -0
- package/dist/pages/Login.js +69 -0
- package/dist/pages/Login.js.map +1 -0
- package/dist/pages/Settings.d.ts +2 -0
- package/dist/pages/Settings.d.ts.map +1 -0
- package/dist/pages/Settings.js +149 -0
- package/dist/pages/Settings.js.map +1 -0
- package/dist/pages/Setup.d.ts +2 -0
- package/dist/pages/Setup.d.ts.map +1 -0
- package/dist/pages/Setup.js +113 -0
- package/dist/pages/Setup.js.map +1 -0
- package/dist/pages/SsoConfirm.d.ts +3 -0
- package/dist/pages/SsoConfirm.d.ts.map +1 -0
- package/dist/pages/SsoConfirm.js +20 -0
- package/dist/pages/SsoConfirm.js.map +1 -0
- package/dist/pages/SsoTestResult.d.ts +2 -0
- package/dist/pages/SsoTestResult.d.ts.map +1 -0
- package/dist/pages/SsoTestResult.js +49 -0
- package/dist/pages/SsoTestResult.js.map +1 -0
- package/dist/pages/Users.d.ts +22 -0
- package/dist/pages/Users.d.ts.map +1 -0
- package/dist/pages/Users.js +124 -0
- package/dist/pages/Users.js.map +1 -0
- package/dist/pages/Vault.d.ts +2 -0
- package/dist/pages/Vault.d.ts.map +1 -0
- package/dist/pages/Vault.js +372 -0
- package/dist/pages/Vault.js.map +1 -0
- package/dist/shell/AdminShell.d.ts +46 -0
- package/dist/shell/AdminShell.d.ts.map +1 -0
- package/dist/shell/AdminShell.js +76 -0
- package/dist/shell/AdminShell.js.map +1 -0
- package/dist/shell/guards.d.ts +28 -0
- package/dist/shell/guards.d.ts.map +1 -0
- package/dist/shell/guards.js +71 -0
- package/dist/shell/guards.js.map +1 -0
- package/icons.json +170 -0
- package/package.json +71 -6
- package/src/api/client.ts +139 -0
- package/src/components/ConfirmIdentityModal.tsx +82 -0
- package/src/components/ConfirmModal.tsx +83 -0
- package/src/components/CopyButton.tsx +71 -0
- package/src/components/CredentialSection.tsx +270 -0
- package/src/components/ErrorBoundary.tsx +47 -0
- package/src/components/ModalShell.tsx +160 -0
- package/src/components/ResetTwoFactorModal.tsx +74 -0
- package/src/components/SidePanel.tsx +96 -0
- package/src/components/SingleSignOnModal.tsx +161 -0
- package/src/components/SsoConfirmation.tsx +96 -0
- package/src/components/VaultTypePicker.tsx +131 -0
- package/src/components/WhatsNew.tsx +84 -0
- package/src/components/formParts.tsx +59 -0
- package/src/components/ui/Alert.tsx +45 -0
- package/src/components/ui/DataTable.tsx +225 -0
- package/src/components/ui/Field.tsx +63 -0
- package/src/components/ui/PageHeader.tsx +36 -0
- package/src/components/ui/Pagination.tsx +37 -0
- package/src/components/ui/QuickStartPanel.tsx +57 -0
- package/src/components/ui/StateViews.tsx +135 -0
- package/src/components/ui/Switch.tsx +65 -0
- package/src/components/ui/Toast.tsx +104 -0
- package/src/components/ui/index.ts +9 -0
- package/src/config.ts +46 -0
- package/src/hooks/useDarkMode.ts +38 -0
- package/src/hooks/useDebouncedValue.ts +22 -0
- package/src/index.ts +42 -0
- package/src/lib/changelog.ts +93 -0
- package/src/lib/dateFormat.ts +90 -0
- package/src/navigation.ts +6 -0
- package/src/pages/ApiTokens.tsx +361 -0
- package/src/pages/AuditLog.tsx +388 -0
- package/src/pages/Backups.tsx +170 -0
- package/src/pages/ChangePassword.tsx +84 -0
- package/src/pages/Login.tsx +275 -0
- package/src/pages/Settings.tsx +264 -0
- package/src/pages/Setup.tsx +438 -0
- package/src/pages/SsoConfirm.tsx +26 -0
- package/src/pages/SsoTestResult.tsx +104 -0
- package/src/pages/Users.tsx +426 -0
- package/src/pages/Vault.tsx +1036 -0
- package/src/shell/AdminShell.tsx +256 -0
- package/src/shell/guards.tsx +88 -0
- package/styles/base.css +521 -0
- package/styles/fonts/inter-latin-1.woff2 +0 -0
- package/styles/fonts/inter-latin-ext.woff2 +0 -0
- package/styles/fonts/jetbrains-mono-latin-3.woff2 +0 -0
- package/styles/fonts/jetbrains-mono-latin-ext-2.woff2 +0 -0
- package/styles/fonts/manrope-latin-5.woff2 +0 -0
- package/styles/fonts/manrope-latin-ext-4.woff2 +0 -0
- package/styles/fonts/material-symbols-outlined-fill.woff2 +0 -0
- package/styles/icons.css +4 -0
- package/tailwind-preset.js +79 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VaultTypePicker.js","sourceRoot":"","sources":["../../src/components/VaultTypePicker.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ReleaseNotes } from '../lib/changelog';
|
|
2
|
+
/** Remembers that this user has seen the notes up to `version`. */
|
|
3
|
+
export declare function markWhatsNewSeen(userId: number, version: string): void;
|
|
4
|
+
/**
|
|
5
|
+
* Releases this user has not seen yet. A user with no record (new, or from before this existed) is only
|
|
6
|
+
* marked as up to date, so the first run shows nothing.
|
|
7
|
+
*/
|
|
8
|
+
export declare function pendingWhatsNew(userId: number, changelog: string, current: string): ReleaseNotes[];
|
|
9
|
+
/**
|
|
10
|
+
* The newest release as collapsible sections (the first one with entries open, empty ones left out), earlier ones in one line each.
|
|
11
|
+
* Only one section is open at a time, so the dialog stays small however many entries a release has.
|
|
12
|
+
*/
|
|
13
|
+
export declare function WhatsNew({ releases, onClose, docsUrl }: {
|
|
14
|
+
releases: ReleaseNotes[];
|
|
15
|
+
onClose: () => void;
|
|
16
|
+
docsUrl: string;
|
|
17
|
+
}): import("react").JSX.Element;
|
|
18
|
+
//# sourceMappingURL=WhatsNew.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WhatsNew.d.ts","sourceRoot":"","sources":["../../src/components/WhatsNew.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAuE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAKzH,mEAAmE;AACnE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAEtE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE,CAWlG;AAuBD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;IAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,+BA6B1H"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { safeLocalStorage } from '@better-forge/contracts';
|
|
3
|
+
import { storageKey } from '../config';
|
|
4
|
+
import { parseChangelog, releasesBetween, summarizeRelease } from '../lib/changelog';
|
|
5
|
+
import { ModalFooter, ModalHeader, ModalShell } from './ModalShell';
|
|
6
|
+
const seenKey = (userId) => storageKey(`whatsnew-seen-${userId}`);
|
|
7
|
+
/** Remembers that this user has seen the notes up to `version`. */
|
|
8
|
+
export function markWhatsNewSeen(userId, version) {
|
|
9
|
+
safeLocalStorage.set(seenKey(userId), version); // blocked storage: the notes may show again next visit
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Releases this user has not seen yet. A user with no record (new, or from before this existed) is only
|
|
13
|
+
* marked as up to date, so the first run shows nothing.
|
|
14
|
+
*/
|
|
15
|
+
export function pendingWhatsNew(userId, changelog, current) {
|
|
16
|
+
try {
|
|
17
|
+
const seen = safeLocalStorage.get(seenKey(userId));
|
|
18
|
+
if (seen === null) {
|
|
19
|
+
markWhatsNewSeen(userId, current);
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
return releasesBetween(parseChangelog(changelog), seen, current).filter((release) => release.groups.length > 0);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const plural = (count, one, many) => `${count} ${count === 1 ? one : many}`;
|
|
29
|
+
/** Opening one section closes the others (shared `name`), so the dialog keeps its size. */
|
|
30
|
+
function Section({ title, items, defaultOpen }) {
|
|
31
|
+
return (_jsxs("details", { name: "whats-new-sections", open: defaultOpen, className: "group rounded-xl", style: { border: '1px solid var(--m3-outline-variant)' }, children: [_jsxs("summary", { className: "flex items-center justify-between gap-2 px-4 py-3 cursor-pointer list-none [&::-webkit-details-marker]:hidden font-headline font-semibold text-sm", style: { color: 'var(--m3-on-surface)' }, children: [_jsxs("span", { children: [title, " ", _jsxs("span", { className: "font-mono text-xs", style: { color: 'var(--m3-outline)' }, children: ["(", items.length, ")"] })] }), _jsx("span", { "aria-hidden": "true", className: "material-symbols-outlined transition-transform group-open:rotate-180", style: { fontSize: '20px' }, children: "expand_more" })] }), _jsx("ul", { className: "space-y-2 px-4 pb-3 overflow-y-auto", style: { maxHeight: '40vh' }, children: items.map((item) => (_jsxs("li", { className: "font-sans text-sm", style: { color: 'var(--m3-on-surface)' }, children: [item.title && _jsxs("span", { className: "font-bold", children: [item.title, ". "] }), item.summary] }, item.title + item.summary))) })] }));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The newest release as collapsible sections (the first one with entries open, empty ones left out), earlier ones in one line each.
|
|
35
|
+
* Only one section is open at a time, so the dialog stays small however many entries a release has.
|
|
36
|
+
*/
|
|
37
|
+
export function WhatsNew({ releases, onClose, docsUrl }) {
|
|
38
|
+
const [latest, ...earlier] = releases.map(summarizeRelease);
|
|
39
|
+
const sections = [
|
|
40
|
+
{ title: 'New', items: latest.added },
|
|
41
|
+
{ title: 'Changed', items: latest.changed },
|
|
42
|
+
{ title: 'Fixes', items: latest.fixed },
|
|
43
|
+
].filter((section) => section.items.length > 0);
|
|
44
|
+
return (_jsx(ModalShell, { onClose: onClose, label: "What's new", children: _jsxs("div", { className: "w-full max-w-lg rounded-2xl", style: { background: 'var(--m3-surface-container-low)', border: '1px solid var(--m3-outline-variant)' }, children: [_jsx(ModalHeader, { icon: "celebration", title: `What's new in ${latest.version}`, onClose: onClose }), _jsxs("div", { className: "p-6 space-y-3", children: [sections.map((section, index) => _jsx(Section, { title: section.title, items: section.items, defaultOpen: index === 0 }, section.title)), earlier.length > 0 && (_jsxs("p", { className: "font-sans text-sm pt-1", style: { color: 'var(--m3-secondary)' }, children: ["Earlier: ", earlier.map((release) => `${release.version} (${[
|
|
45
|
+
release.added.length > 0 && `${release.added.length} new`,
|
|
46
|
+
release.changed.length > 0 && plural(release.changed.length, 'change', 'changes'),
|
|
47
|
+
release.fixed.length > 0 && plural(release.fixed.length, 'fix', 'fixes'),
|
|
48
|
+
].filter(Boolean).join(', ')})`).join(' · ')] }))] }), _jsx(ModalFooter, { start: _jsx("a", { href: `${docsUrl}/changelog/`, target: "_blank", rel: "noopener", className: "btn btn-secondary", children: "Full changelog" }), children: _jsx("button", { type: "button", onClick: onClose, className: "btn btn-primary", children: "Got it" }) })] }) }));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=WhatsNew.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WhatsNew.js","sourceRoot":"","sources":["../../src/components/WhatsNew.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAuC,MAAM,kBAAkB,CAAA;AACzH,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEnE,MAAM,OAAO,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,UAAU,CAAC,iBAAiB,MAAM,EAAE,CAAC,CAAA;AAEzE,mEAAmE;AACnE,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,OAAe;IAC9D,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAA,CAAC,uDAAuD;AACxG,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,SAAiB,EAAE,OAAe;IAChF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;QAClD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;YACjC,OAAO,EAAE,CAAA;QACX,CAAC;QACD,OAAO,eAAe,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACjH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,GAAW,EAAE,IAAY,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;AAEnG,2FAA2F;AAC3F,SAAS,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAkE;IAC5G,OAAO,CACL,mBAAS,IAAI,EAAC,oBAAoB,EAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAC,kBAAkB,EAAC,KAAK,EAAE,EAAE,MAAM,EAAE,qCAAqC,EAAE,aACzI,mBAAS,SAAS,EAAC,mJAAmJ,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,sBAAsB,EAAE,aAC7M,2BAAO,KAAK,OAAE,gBAAM,SAAS,EAAC,mBAAmB,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,kBAAI,KAAK,CAAC,MAAM,SAAS,IAAO,EACvH,8BAAkB,MAAM,EAAC,SAAS,EAAC,sEAAsE,EAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,4BAAoB,IACjJ,EACV,aAAI,SAAS,EAAC,qCAAqC,EAAC,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,YAC7E,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,cAAoC,SAAS,EAAC,mBAAmB,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,sBAAsB,EAAE,aACvG,IAAI,CAAC,KAAK,IAAI,gBAAM,SAAS,EAAC,WAAW,aAAE,IAAI,CAAC,KAAK,UAAU,EAAE,IAAI,CAAC,OAAO,KADvE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAE7B,CACN,CAAC,GACC,IACG,CACX,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAsE;IACzH,MAAM,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;IAC3D,MAAM,QAAQ,GAAG;QACf,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAO,CAAC,KAAK,EAAE;QACtC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAO,CAAC,OAAO,EAAE;QAC5C,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAO,CAAC,KAAK,EAAE;KACzC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC/C,OAAO,CACL,KAAC,UAAU,IAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAC,YAAY,YAC9C,eAAK,SAAS,EAAC,6BAA6B,EAAC,KAAK,EAAE,EAAE,UAAU,EAAE,iCAAiC,EAAE,MAAM,EAAE,qCAAqC,EAAE,aAClJ,KAAC,WAAW,IAAC,IAAI,EAAC,aAAa,EAAC,KAAK,EAAE,iBAAiB,MAAO,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,GAAI,EAC/F,eAAK,SAAS,EAAC,eAAe,aAC3B,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,KAAC,OAAO,IAAqB,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,KAAK,CAAC,IAAnF,OAAO,CAAC,KAAK,CAA0E,CAAC,EACvI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CACrB,aAAG,SAAS,EAAC,wBAAwB,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,0BACjE,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,KAAK;oCACxD,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,MAAM;oCACzD,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC;oCACjF,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC;iCACzE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAC1C,CACL,IACG,EACN,KAAC,WAAW,IAAC,KAAK,EAAE,YAAG,IAAI,EAAE,GAAG,OAAO,aAAa,EAAE,MAAM,EAAC,QAAQ,EAAC,GAAG,EAAC,UAAU,EAAC,SAAS,EAAC,mBAAmB,+BAAmB,YACnI,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAC,iBAAiB,uBAAgB,GACvE,IACV,GACK,CACd,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface VaultSummary {
|
|
3
|
+
id: number;
|
|
4
|
+
name: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SecretSummary {
|
|
7
|
+
id: number;
|
|
8
|
+
name: string;
|
|
9
|
+
type: 'userpass' | 'value' | 'json';
|
|
10
|
+
}
|
|
11
|
+
/** What every vault-aware credential picker needs to list vaults and lazily load their secrets. */
|
|
12
|
+
export interface VaultPickerProps {
|
|
13
|
+
vaults: {
|
|
14
|
+
id: number;
|
|
15
|
+
name: string;
|
|
16
|
+
}[];
|
|
17
|
+
secretsByVault: Record<number, {
|
|
18
|
+
id: number;
|
|
19
|
+
name: string;
|
|
20
|
+
type: string;
|
|
21
|
+
}[]>;
|
|
22
|
+
onLoadSecrets: (vaultId: number) => Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export declare const JSON_MAPPING_FIELDS: Record<'basic' | 'oauth2' | 'cas' | 'database', {
|
|
25
|
+
key: string;
|
|
26
|
+
label: string;
|
|
27
|
+
}[]>;
|
|
28
|
+
/** The shared caps-style form field: its label is programmatically tied to the control it wraps. */
|
|
29
|
+
export { Field } from './ui';
|
|
30
|
+
export declare function SectionDivider({ label }: {
|
|
31
|
+
label: string;
|
|
32
|
+
}): import("react").JSX.Element;
|
|
33
|
+
/** Tinted callout: `info` uses the accent blue, `warning` the degraded amber (text colour, not the bar colour). */
|
|
34
|
+
export declare function Note({ tone, children }: {
|
|
35
|
+
tone: 'info' | 'warning';
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
}): import("react").JSX.Element;
|
|
38
|
+
/** Adds or removes one id from a selection set without mutating it. */
|
|
39
|
+
export declare function toggleInSet(set: Set<number>, id: number, on: boolean): Set<number>;
|
|
40
|
+
//# sourceMappingURL=formParts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formParts.d.ts","sourceRoot":"","sources":["../../src/components/formParts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC,MAAM,WAAW,YAAY;IAAI,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AAC3D,MAAM,WAAW,aAAa;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,MAAM,CAAA;CAAE;AAEhG,mGAAmG;AACnG,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACtC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC,CAAA;IAC5E,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAClD;AAGD,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,UAAU,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAKjH,CAAA;AAED,oGAAoG;AACpG,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAA;AAE5B,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,+BAQ1D;AAED,mHAAmH;AACnH,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,+BAczF;AAED,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAKlF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Fields that can be sourced from a json vault secret, per context
|
|
3
|
+
export const JSON_MAPPING_FIELDS = {
|
|
4
|
+
basic: [{ key: 'username', label: 'Username' }, { key: 'password', label: 'Password' }],
|
|
5
|
+
oauth2: [{ key: 'clientId', label: 'Client ID' }, { key: 'clientSecret', label: 'Client Secret' }],
|
|
6
|
+
cas: [{ key: 'username', label: 'Username' }, { key: 'password', label: 'Password' }],
|
|
7
|
+
database: [{ key: 'username', label: 'Username' }, { key: 'password', label: 'Password' }],
|
|
8
|
+
};
|
|
9
|
+
/** The shared caps-style form field: its label is programmatically tied to the control it wraps. */
|
|
10
|
+
export { Field } from './ui';
|
|
11
|
+
export function SectionDivider({ label }) {
|
|
12
|
+
return (_jsxs("div", { className: "flex items-center gap-3 pt-1", children: [_jsx("div", { style: { flex: 1, borderTop: '1px solid var(--m3-outline-variant)' } }), _jsx("span", { className: "font-mono text-xs uppercase tracking-wider", style: { color: 'var(--m3-secondary)' }, children: label }), _jsx("div", { style: { flex: 1, borderTop: '1px solid var(--m3-outline-variant)' } })] }));
|
|
13
|
+
}
|
|
14
|
+
/** Tinted callout: `info` uses the accent blue, `warning` the degraded amber (text colour, not the bar colour). */
|
|
15
|
+
export function Note({ tone, children }) {
|
|
16
|
+
const color = tone === 'info' ? 'var(--m3-on-primary-container)' : 'var(--m3-degraded)';
|
|
17
|
+
const tint = tone === 'info' ? color : 'var(--m3-degraded-bar)';
|
|
18
|
+
return (_jsxs("div", { className: "flex items-start gap-2 rounded-lg px-3 py-2", style: { background: `color-mix(in srgb, ${tint} 8%, transparent)`, border: `1px solid color-mix(in srgb, ${tint} 20%, transparent)` }, children: [tone === 'info'
|
|
19
|
+
? _jsx("span", { className: "material-symbols-outlined", "aria-hidden": "true", style: { fontSize: '16px', color, lineHeight: '20px' }, children: "info" })
|
|
20
|
+
: _jsx("span", { "aria-hidden": "true", style: { color, lineHeight: '20px' }, children: "\u26A0" }), _jsx("p", { className: "text-xs", style: { color: 'var(--m3-on-surface-variant)' }, children: children })] }));
|
|
21
|
+
}
|
|
22
|
+
/** Adds or removes one id from a selection set without mutating it. */
|
|
23
|
+
export function toggleInSet(set, id, on) {
|
|
24
|
+
const next = new Set(set);
|
|
25
|
+
if (on)
|
|
26
|
+
next.add(id);
|
|
27
|
+
else
|
|
28
|
+
next.delete(id);
|
|
29
|
+
return next;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=formParts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formParts.js","sourceRoot":"","sources":["../../src/components/formParts.tsx"],"names":[],"mappings":";AAcA,mEAAmE;AACnE,MAAM,CAAC,MAAM,mBAAmB,GAAsF;IACpH,KAAK,EAAM,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAC3F,MAAM,EAAK,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;IACrG,GAAG,EAAQ,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAC3F,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;CAC3F,CAAA;AAED,oGAAoG;AACpG,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAA;AAE5B,MAAM,UAAU,cAAc,CAAC,EAAE,KAAK,EAAqB;IACzD,OAAO,CACL,eAAK,SAAS,EAAC,8BAA8B,aAC3C,cAAK,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,qCAAqC,EAAE,GAAI,EAC7E,eAAM,SAAS,EAAC,4CAA4C,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,YAAG,KAAK,GAAQ,EACpH,cAAK,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,qCAAqC,EAAE,GAAI,IACzE,CACP,CAAA;AACH,CAAC;AAED,mHAAmH;AACnH,MAAM,UAAU,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAqD;IACxF,MAAM,KAAK,GAAG,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,oBAAoB,CAAA;IACvF,MAAM,IAAI,GAAG,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,wBAAwB,CAAA;IAC/D,OAAO,CACL,eACE,SAAS,EAAC,6CAA6C,EACvD,KAAK,EAAE,EAAE,UAAU,EAAE,sBAAsB,IAAI,mBAAmB,EAAE,MAAM,EAAE,gCAAgC,IAAI,oBAAoB,EAAE,aAErI,IAAI,KAAK,MAAM;gBACd,CAAC,CAAC,eAAM,SAAS,EAAC,2BAA2B,iBAAa,MAAM,EAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,qBAAa;gBACpI,CAAC,CAAC,8BAAkB,MAAM,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,uBAAU,EAC3E,YAAG,SAAS,EAAC,SAAS,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,8BAA8B,EAAE,YAAG,QAAQ,GAAK,IACnF,CACP,CAAA;AACH,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,WAAW,CAAC,GAAgB,EAAE,EAAU,EAAE,EAAW;IACnE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;IACzB,IAAI,EAAE;QAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;;QACf,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IACpB,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export type AlertTone = 'error' | 'success' | 'info' | 'warning';
|
|
3
|
+
interface AlertProps {
|
|
4
|
+
tone: AlertTone;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
/** Optional bold first line. */
|
|
7
|
+
title?: ReactNode | undefined;
|
|
8
|
+
/** Renders a × button (aria-label "Dismiss") that calls this. */
|
|
9
|
+
onDismiss?: (() => void) | undefined;
|
|
10
|
+
className?: string | undefined;
|
|
11
|
+
}
|
|
12
|
+
/** Inline, token-coloured message box. Errors are announced assertively (role="alert"); other tones politely. */
|
|
13
|
+
export declare function Alert({ tone, children, title, onDismiss, className }: AlertProps): import("react").JSX.Element;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=Alert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Alert.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Alert.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAErD,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAA;AAShE,UAAU,UAAU;IAClB,IAAI,EAAE,SAAS,CAAA;IACf,QAAQ,EAAE,SAAS,CAAA;IACnB,gCAAgC;IAChC,KAAK,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IAC7B,iEAAiE;IACjE,SAAS,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;IACpC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC/B;AAED,iHAAiH;AACjH,wBAAgB,KAAK,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,UAAU,+BAqBhF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
const TONES = {
|
|
4
|
+
error: { icon: 'error', style: { background: 'var(--m3-down-bg)', color: 'var(--m3-down)', borderColor: 'color-mix(in srgb, var(--m3-down) 30%, transparent)' } },
|
|
5
|
+
success: { icon: 'check_circle', style: { background: 'var(--m3-up-bg)', color: 'var(--m3-up)', borderColor: 'color-mix(in srgb, var(--m3-up) 30%, transparent)' } },
|
|
6
|
+
warning: { icon: 'warning', style: { background: 'var(--m3-degraded-bg)', color: 'var(--m3-degraded)', borderColor: 'color-mix(in srgb, var(--m3-degraded) 30%, transparent)' } },
|
|
7
|
+
info: { icon: 'info', style: { background: 'var(--m3-surface-container-high)', color: 'var(--m3-on-surface)', borderColor: 'var(--m3-outline-variant)' } },
|
|
8
|
+
};
|
|
9
|
+
/** Inline, token-coloured message box. Errors are announced assertively (role="alert"); other tones politely. */
|
|
10
|
+
export function Alert({ tone, children, title, onDismiss, className }) {
|
|
11
|
+
const { icon, style } = TONES[tone];
|
|
12
|
+
return (_jsxs("div", { role: tone === 'error' ? 'alert' : 'status', "data-tone": tone, className: clsx('flex items-start gap-3 rounded-xl border px-4 py-3 text-sm', className), style: style, children: [_jsx("span", { className: "material-symbols-outlined flex-shrink-0 mt-px", "aria-hidden": "true", style: { fontSize: '18px' }, children: icon }), _jsxs("div", { className: "flex-1 min-w-0 break-words", children: [title && _jsx("p", { className: "font-semibold", children: title }), _jsx("div", { className: title ? 'mt-0.5' : undefined, children: children })] }), onDismiss && (_jsx("button", { type: "button", onClick: onDismiss, "aria-label": "Dismiss", className: "btn-icon -my-1 -mr-2", style: { color: 'inherit' }, children: _jsx("span", { className: "material-symbols-outlined", "aria-hidden": "true", style: { fontSize: '18px' }, children: "close" }) }))] }));
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=Alert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Alert.js","sourceRoot":"","sources":["../../../src/components/ui/Alert.tsx"],"names":[],"mappings":";AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AAKvB,MAAM,KAAK,GAA8D;IACvE,KAAK,EAAI,EAAE,IAAI,EAAE,OAAO,EAAS,KAAK,EAAE,EAAE,UAAU,EAAE,mBAAmB,EAAE,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,qDAAqD,EAAE,EAAE;IAC1K,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,iBAAiB,EAAE,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,mDAAmD,EAAE,EAAE;IACpK,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAO,KAAK,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,yDAAyD,EAAE,EAAE;IACtL,IAAI,EAAK,EAAE,IAAI,EAAE,MAAM,EAAU,KAAK,EAAE,EAAE,UAAU,EAAE,kCAAkC,EAAE,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,2BAA2B,EAAE,EAAE;CACtK,CAAA;AAYD,iHAAiH;AACjH,MAAM,UAAU,KAAK,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAc;IAC/E,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;IACnC,OAAO,CACL,eACE,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,eAChC,IAAI,EACf,SAAS,EAAE,IAAI,CAAC,4DAA4D,EAAE,SAAS,CAAC,EACxF,KAAK,EAAE,KAAK,aAEZ,eAAM,SAAS,EAAC,+CAA+C,iBAAa,MAAM,EAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAG,IAAI,GAAQ,EAC7H,eAAK,SAAS,EAAC,4BAA4B,aACxC,KAAK,IAAI,YAAG,SAAS,EAAC,eAAe,YAAE,KAAK,GAAK,EAClD,cAAK,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,YAAG,QAAQ,GAAO,IAC1D,EACL,SAAS,IAAI,CACZ,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,SAAS,gBAAa,SAAS,EAAC,SAAS,EAAC,sBAAsB,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,YACzH,eAAM,SAAS,EAAC,2BAA2B,iBAAa,MAAM,EAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,sBAAc,GACjG,CACV,IACG,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type ReactNode, type TableHTMLAttributes, type ThHTMLAttributes } from 'react';
|
|
2
|
+
export declare const MIN_COLUMN_WIDTH = 60;
|
|
3
|
+
export declare const MAX_COLUMN_WIDTH = 600;
|
|
4
|
+
interface ResizeHandleProps {
|
|
5
|
+
/** Column name, used for the accessible description. */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Current width in px; shown to assistive technology. */
|
|
8
|
+
width: number | undefined;
|
|
9
|
+
/** Reads the width the column has right now; called when a drag starts and for key presses. */
|
|
10
|
+
measure: () => number;
|
|
11
|
+
onResize: (width: number) => void;
|
|
12
|
+
/** Restores the default width. */
|
|
13
|
+
onReset: () => void;
|
|
14
|
+
}
|
|
15
|
+
/** Grip on the right edge of a column header: drag, arrow keys, double-click or Home to reset. Place it in a `position: relative` header cell. */
|
|
16
|
+
export declare function ResizeHandle({ label, width, measure, onResize, onReset }: ResizeHandleProps): import("react").JSX.Element;
|
|
17
|
+
export type SortDirection = 'asc' | 'desc';
|
|
18
|
+
export type SortValue = string | number | boolean | null | undefined;
|
|
19
|
+
export interface TableSort {
|
|
20
|
+
key: string | null;
|
|
21
|
+
dir: SortDirection;
|
|
22
|
+
/** Sorts by the column; repeated calls on the same column go ascending, descending, then back to the original order. */
|
|
23
|
+
toggle: (key: string) => void;
|
|
24
|
+
}
|
|
25
|
+
/** Sorts `rows` by the column picked in a `DataTable` header. `accessors` maps a column key to the value to compare; empty values always go last. */
|
|
26
|
+
export declare function useTableSort<T>(rows: readonly T[], accessors: Readonly<Record<string, (row: T) => SortValue>>, initial?: {
|
|
27
|
+
key: string;
|
|
28
|
+
dir?: SortDirection;
|
|
29
|
+
}): {
|
|
30
|
+
rows: T[];
|
|
31
|
+
sort: TableSort;
|
|
32
|
+
};
|
|
33
|
+
interface DataTableProps extends TableHTMLAttributes<HTMLTableElement> {
|
|
34
|
+
/** From `useTableSort`; without it the headers are not sortable. */
|
|
35
|
+
sort?: TableSort;
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* `<table>` whose `DataTh` headers can be sorted and resized. The first resize fixes every column at its
|
|
40
|
+
* current width; a drag then moves the boundary to the next column, so the other columns stay where they are.
|
|
41
|
+
*/
|
|
42
|
+
export declare function DataTable({ sort, children, style, className, ...rest }: DataTableProps): import("react").JSX.Element;
|
|
43
|
+
interface DataThProps extends ThHTMLAttributes<HTMLTableCellElement> {
|
|
44
|
+
/** Column key from `useTableSort`'s accessors; makes the header a sort button. */
|
|
45
|
+
sortKey?: string;
|
|
46
|
+
/** Set false for columns without a title, such as the row actions. */
|
|
47
|
+
resizable?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/** `<th>` for a `DataTable`: sortable with `sortKey`, resizable unless `resizable={false}`. Give it the classes and colours you would give a `<th>`. */
|
|
50
|
+
export declare function DataTh({ sortKey, resizable, children, className, style, ...rest }: DataThProps): import("react").JSX.Element;
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=DataTable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/components/ui/DataTable.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEkC,KAAK,SAAS,EAAE,KAAK,mBAAmB,EAAE,KAAK,gBAAgB,EACvG,MAAM,OAAO,CAAA;AAEd,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAClC,eAAO,MAAM,gBAAgB,MAAM,CAAA;AAGnC,UAAU,iBAAiB;IACzB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAA;IACb,0DAA0D;IAC1D,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,+FAA+F;IAC/F,OAAO,EAAE,MAAM,MAAM,CAAA;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,kCAAkC;IAClC,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,kJAAkJ;AAClJ,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,iBAAiB,+BA8C3F;AAED,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,CAAA;AAC1C,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAA;AAEpE,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,GAAG,EAAE,aAAa,CAAA;IAClB,wHAAwH;IACxH,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAC9B;AAUD,qJAAqJ;AACrJ,wBAAgB,YAAY,CAAC,CAAC,EAC5B,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,SAAS,CAAC,CAAC,EAC1D,OAAO,CAAC,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,aAAa,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,CA0BhC;AAWD,UAAU,cAAe,SAAQ,mBAAmB,CAAC,gBAAgB,CAAC;IACpE,oEAAoE;IACpE,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,+BAkCtF;AAED,UAAU,WAAY,SAAQ,gBAAgB,CAAC,oBAAoB,CAAC;IAClE,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sEAAsE;IACtE,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,wJAAwJ;AACxJ,wBAAgB,MAAM,CAAC,EAAE,OAAO,EAAE,SAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE,WAAW,+BAwCrG"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useCallback, useContext, useMemo, useRef, useState, } from 'react';
|
|
3
|
+
export const MIN_COLUMN_WIDTH = 60;
|
|
4
|
+
export const MAX_COLUMN_WIDTH = 600;
|
|
5
|
+
const KEY_STEP = 16;
|
|
6
|
+
/** Grip on the right edge of a column header: drag, arrow keys, double-click or Home to reset. Place it in a `position: relative` header cell. */
|
|
7
|
+
export function ResizeHandle({ label, width, measure, onResize, onReset }) {
|
|
8
|
+
const drag = useRef(null);
|
|
9
|
+
const clamp = (w) => Math.min(MAX_COLUMN_WIDTH, Math.max(MIN_COLUMN_WIDTH, Math.round(w)));
|
|
10
|
+
function onPointerDown(e) {
|
|
11
|
+
e.preventDefault();
|
|
12
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
13
|
+
drag.current = { startX: e.clientX, startWidth: measure() };
|
|
14
|
+
}
|
|
15
|
+
function onPointerMove(e) {
|
|
16
|
+
if (drag.current)
|
|
17
|
+
onResize(clamp(drag.current.startWidth + e.clientX - drag.current.startX));
|
|
18
|
+
}
|
|
19
|
+
function onKeyDown(e) {
|
|
20
|
+
if (e.key === 'ArrowLeft')
|
|
21
|
+
onResize(clamp(measure() - KEY_STEP));
|
|
22
|
+
else if (e.key === 'ArrowRight')
|
|
23
|
+
onResize(clamp(measure() + KEY_STEP));
|
|
24
|
+
else if (e.key === 'Home')
|
|
25
|
+
onReset();
|
|
26
|
+
else
|
|
27
|
+
return;
|
|
28
|
+
e.preventDefault();
|
|
29
|
+
}
|
|
30
|
+
return (_jsx("span", { role: "separator", "aria-orientation": "vertical", "aria-description": `Resize ${label} column`, "aria-valuenow": width, "aria-valuemin": MIN_COLUMN_WIDTH, "aria-valuemax": MAX_COLUMN_WIDTH, tabIndex: 0, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: () => { drag.current = null; }, onPointerCancel: () => { drag.current = null; }, onKeyDown: onKeyDown, onDoubleClick: onReset, className: "group focus-ring absolute top-0 right-0 z-10 flex h-full w-3 cursor-col-resize touch-none select-none justify-center", children: _jsx("span", { "aria-hidden": "true", className: "block h-full w-px opacity-60 transition-all group-hover:w-0.5 group-hover:opacity-100 group-focus-visible:w-0.5 group-focus-visible:opacity-100 group-active:w-0.5 group-active:opacity-100", style: { background: 'var(--m3-outline-variant)' } }) }));
|
|
31
|
+
}
|
|
32
|
+
const isEmpty = (v) => v == null || v === '';
|
|
33
|
+
function compareValues(a, b) {
|
|
34
|
+
if (typeof a === 'number' && typeof b === 'number')
|
|
35
|
+
return a - b;
|
|
36
|
+
if (typeof a === 'boolean' && typeof b === 'boolean')
|
|
37
|
+
return Number(a) - Number(b);
|
|
38
|
+
return String(a).localeCompare(String(b), undefined, { numeric: true, sensitivity: 'base' });
|
|
39
|
+
}
|
|
40
|
+
/** Sorts `rows` by the column picked in a `DataTable` header. `accessors` maps a column key to the value to compare; empty values always go last. */
|
|
41
|
+
export function useTableSort(rows, accessors, initial) {
|
|
42
|
+
const [key, setKey] = useState(initial?.key ?? null);
|
|
43
|
+
const [dir, setDir] = useState(initial?.dir ?? 'asc');
|
|
44
|
+
const toggle = useCallback((next) => {
|
|
45
|
+
if (key !== next) {
|
|
46
|
+
setKey(next);
|
|
47
|
+
setDir('asc');
|
|
48
|
+
}
|
|
49
|
+
else if (dir === 'asc')
|
|
50
|
+
setDir('desc');
|
|
51
|
+
else {
|
|
52
|
+
setKey(null);
|
|
53
|
+
setDir('asc');
|
|
54
|
+
}
|
|
55
|
+
}, [key, dir]);
|
|
56
|
+
// The accessors are declared inline by callers; the rows, column and direction are what change the order.
|
|
57
|
+
const accessorsRef = useRef(accessors);
|
|
58
|
+
accessorsRef.current = accessors;
|
|
59
|
+
const sorted = useMemo(() => {
|
|
60
|
+
const get = key === null ? undefined : accessorsRef.current[key];
|
|
61
|
+
if (!get)
|
|
62
|
+
return [...rows];
|
|
63
|
+
const sign = dir === 'asc' ? 1 : -1;
|
|
64
|
+
return [...rows].sort((x, y) => {
|
|
65
|
+
const a = get(x), b = get(y);
|
|
66
|
+
if (isEmpty(a) || isEmpty(b))
|
|
67
|
+
return Number(isEmpty(a)) - Number(isEmpty(b));
|
|
68
|
+
return sign * compareValues(a, b);
|
|
69
|
+
});
|
|
70
|
+
}, [rows, key, dir]);
|
|
71
|
+
return { rows: sorted, sort: useMemo(() => ({ key, dir, toggle }), [key, dir, toggle]) };
|
|
72
|
+
}
|
|
73
|
+
const DataTableContext = createContext(null);
|
|
74
|
+
/**
|
|
75
|
+
* `<table>` whose `DataTh` headers can be sorted and resized. The first resize fixes every column at its
|
|
76
|
+
* current width; a drag then moves the boundary to the next column, so the other columns stay where they are.
|
|
77
|
+
*/
|
|
78
|
+
export function DataTable({ sort, children, style, className, ...rest }) {
|
|
79
|
+
const [widths, setWidths] = useState(null);
|
|
80
|
+
const resize = useCallback((row, index, width) => {
|
|
81
|
+
setWidths((current) => {
|
|
82
|
+
const next = current ? [...current] : Array.from(row.cells, (cell) => cell.offsetWidth);
|
|
83
|
+
const own = next[index];
|
|
84
|
+
if (own === undefined)
|
|
85
|
+
return current;
|
|
86
|
+
const neighbour = next[index + 1];
|
|
87
|
+
let delta = width - own;
|
|
88
|
+
if (neighbour !== undefined)
|
|
89
|
+
delta = Math.min(delta, neighbour - MIN_COLUMN_WIDTH);
|
|
90
|
+
next[index] = own + delta;
|
|
91
|
+
if (neighbour !== undefined)
|
|
92
|
+
next[index + 1] = neighbour - delta;
|
|
93
|
+
return next;
|
|
94
|
+
});
|
|
95
|
+
}, []);
|
|
96
|
+
const context = useMemo(() => ({ sort, widths, resize, reset: () => setWidths(null) }), [sort, widths, resize]);
|
|
97
|
+
return (_jsx(DataTableContext.Provider, { value: context, children: _jsxs("table", { ...rest, className: `${className ?? ''} ${widths ? '[&_td]:break-words [&_th]:overflow-hidden' : ''}`, style: widths ? { ...style, tableLayout: 'fixed', width: widths.reduce((a, b) => a + b, 0), minWidth: 0 } : style, children: [widths && _jsx("colgroup", { children: widths.map((w, i) => _jsx("col", { style: { width: w } }, i)) }), children] }) }));
|
|
98
|
+
}
|
|
99
|
+
/** `<th>` for a `DataTable`: sortable with `sortKey`, resizable unless `resizable={false}`. Give it the classes and colours you would give a `<th>`. */
|
|
100
|
+
export function DataTh({ sortKey, resizable = true, children, className, style, ...rest }) {
|
|
101
|
+
const table = useContext(DataTableContext);
|
|
102
|
+
const ref = useRef(null);
|
|
103
|
+
const sorted = sortKey !== undefined && table?.sort?.key === sortKey;
|
|
104
|
+
const dir = table?.sort?.dir;
|
|
105
|
+
const label = typeof children === 'string' ? children : sortKey ?? 'this';
|
|
106
|
+
return (_jsxs("th", { ref: ref, ...rest, "aria-sort": sorted ? (dir === 'asc' ? 'ascending' : 'descending') : rest['aria-sort'], className: `${className ?? ''} ${resizable && table ? 'relative' : ''}`, style: sorted ? { ...style, color: 'var(--m3-primary)' } : style, children: [sortKey !== undefined && table?.sort ? (_jsxs("button", { type: "button", onClick: () => table.sort?.toggle(sortKey), className: "inline-flex items-center gap-1 uppercase tracking-wider rounded focus-ring", style: { color: 'inherit', userSelect: 'none' }, children: [children, sorted && _jsx("span", { "aria-hidden": "true", style: { fontSize: '10px' }, children: dir === 'asc' ? '↑' : '↓' })] })) : children, resizable && table && (_jsx(ResizeHandle, { label: label, width: table.widths?.[ref.current?.cellIndex ?? -1], measure: () => ref.current?.offsetWidth ?? MIN_COLUMN_WIDTH, onResize: (w) => {
|
|
107
|
+
const cell = ref.current;
|
|
108
|
+
if (cell?.parentElement instanceof HTMLTableRowElement)
|
|
109
|
+
table.resize(cell.parentElement, cell.cellIndex, w);
|
|
110
|
+
}, onReset: table.reset }))] }));
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=DataTable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataTable.js","sourceRoot":"","sources":["../../../src/components/ui/DataTable.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,GAElE,MAAM,OAAO,CAAA;AAEd,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAA;AAClC,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAA;AACnC,MAAM,QAAQ,GAAG,EAAE,CAAA;AAcnB,kJAAkJ;AAClJ,MAAM,UAAU,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAqB;IAC1F,MAAM,IAAI,GAAG,MAAM,CAAgD,IAAI,CAAC,CAAA;IACxE,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAElG,SAAS,aAAa,CAAC,CAAgC;QACrD,CAAC,CAAC,cAAc,EAAE,CAAA;QAClB,CAAC,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;QAC9C,IAAI,CAAC,OAAO,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,CAAA;IAC7D,CAAC;IAED,SAAS,aAAa,CAAC,CAAgC;QACrD,IAAI,IAAI,CAAC,OAAO;YAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,GAAG,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;IAC9F,CAAC;IAED,SAAS,SAAS,CAAC,CAAiC;QAClD,IAAI,CAAC,CAAC,GAAG,KAAK,WAAW;YAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAA;aAC3D,IAAI,CAAC,CAAC,GAAG,KAAK,YAAY;YAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAA;aACjE,IAAI,CAAC,CAAC,GAAG,KAAK,MAAM;YAAE,OAAO,EAAE,CAAA;;YAC/B,OAAM;QACX,CAAC,CAAC,cAAc,EAAE,CAAA;IACpB,CAAC;IAED,OAAO,CACL,eACE,IAAI,EAAC,WAAW,sBACC,UAAU,sBACT,UAAU,KAAK,SAAS,mBAC3B,KAAK,mBACL,gBAAgB,mBAChB,gBAAgB,EAC/B,QAAQ,EAAE,CAAC,EACX,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,aAAa,EAC5B,WAAW,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA,CAAC,CAAC,EAC1C,eAAe,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA,CAAC,CAAC,EAC9C,SAAS,EAAE,SAAS,EACpB,aAAa,EAAE,OAAO,EACtB,SAAS,EAAC,sHAAsH,YAEhI,8BACc,MAAM,EAClB,SAAS,EAAC,6LAA6L,EACvM,KAAK,EAAE,EAAE,UAAU,EAAE,2BAA2B,EAAE,GAClD,GACG,CACR,CAAA;AACH,CAAC;AAYD,MAAM,OAAO,GAAG,CAAC,CAAY,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAA;AAEvD,SAAS,aAAa,CAAC,CAAY,EAAE,CAAY;IAC/C,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,GAAG,CAAC,CAAA;IAChE,IAAI,OAAO,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;IAClF,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAA;AAC9F,CAAC;AAED,qJAAqJ;AACrJ,MAAM,UAAU,YAAY,CAC1B,IAAkB,EAClB,SAA0D,EAC1D,OAA8C;IAE9C,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAgB,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAA;IACnE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAgB,OAAO,EAAE,GAAG,IAAI,KAAK,CAAC,CAAA;IAEpE,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,IAAY,EAAE,EAAE;QAC1C,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAAC,CAAC;aAC5C,IAAI,GAAG,KAAK,KAAK;YAAE,MAAM,CAAC,MAAM,CAAC,CAAA;aACjC,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAAC,CAAC;IACtC,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;IAEd,0GAA0G;IAC1G,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,CAAA;IACtC,YAAY,CAAC,OAAO,GAAG,SAAS,CAAA;IAEhC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE;QAC1B,MAAM,GAAG,GAAG,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAChE,IAAI,CAAC,GAAG;YAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;QAC1B,MAAM,IAAI,GAAG,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACnC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAC7B,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAA;YAC5B,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC;gBAAE,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;YAC5E,OAAO,IAAI,GAAG,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACnC,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;IAEpB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,CAAA;AAC1F,CAAC;AASD,MAAM,gBAAgB,GAAG,aAAa,CAAsB,IAAI,CAAC,CAAA;AAQjE;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,EAAkB;IACrF,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAkB,IAAI,CAAC,CAAA;IAE3D,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,GAAwB,EAAE,KAAa,EAAE,KAAa,EAAE,EAAE;QACpF,SAAS,CAAC,CAAC,OAAO,EAAE,EAAE;YACpB,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;YACvF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAA;YACvB,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO,OAAO,CAAA;YACrC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;YACjC,IAAI,KAAK,GAAG,KAAK,GAAG,GAAG,CAAA;YACvB,IAAI,SAAS,KAAK,SAAS;gBAAE,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,GAAG,gBAAgB,CAAC,CAAA;YAClF,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,KAAK,CAAA;YACzB,IAAI,SAAS,KAAK,SAAS;gBAAE,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,SAAS,GAAG,KAAK,CAAA;YAChE,OAAO,IAAI,CAAA;QACb,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,OAAO,GAAG,OAAO,CACrB,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,EAC9D,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CACvB,CAAA;IAED,OAAO,CACL,KAAC,gBAAgB,CAAC,QAAQ,IAAC,KAAK,EAAE,OAAO,YACvC,oBACM,IAAI,EACR,SAAS,EAAE,GAAG,SAAS,IAAI,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,2CAA2C,CAAC,CAAC,CAAC,EAAE,EAAE,EAC5F,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,aAEhH,MAAM,IAAI,6BAAW,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,cAAa,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAtB,CAAC,CAAyB,CAAC,GAAY,EAC3F,QAAQ,IACH,GACkB,CAC7B,CAAA;AACH,CAAC;AASD,wJAAwJ;AACxJ,MAAM,UAAU,MAAM,CAAC,EAAE,OAAO,EAAE,SAAS,GAAG,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,IAAI,EAAe;IACpG,MAAM,KAAK,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAA;IAC1C,MAAM,GAAG,GAAG,MAAM,CAAuB,IAAI,CAAC,CAAA;IAC9C,MAAM,MAAM,GAAG,OAAO,KAAK,SAAS,IAAI,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,OAAO,CAAA;IACpE,MAAM,GAAG,GAAG,KAAK,EAAE,IAAI,EAAE,GAAG,CAAA;IAC5B,MAAM,KAAK,GAAG,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,IAAI,MAAM,CAAA;IAEzE,OAAO,CACL,cACE,GAAG,EAAE,GAAG,KACJ,IAAI,eACG,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EACpF,SAAS,EAAE,GAAG,SAAS,IAAI,EAAE,IAAI,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,EACvE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC,KAAK,aAE/D,OAAO,KAAK,SAAS,IAAI,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CACtC,kBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,EAC1C,SAAS,EAAC,4EAA4E,EACtF,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,aAE9C,QAAQ,EACR,MAAM,IAAI,8BAAkB,MAAM,EAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAG,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAQ,IAC5F,CACV,CAAC,CAAC,CAAC,QAAQ,EACX,SAAS,IAAI,KAAK,IAAI,CACrB,KAAC,YAAY,IACX,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,IAAI,CAAC,CAAC,CAAC,EACnD,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,IAAI,gBAAgB,EAC3D,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;oBACd,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAA;oBACxB,IAAI,IAAI,EAAE,aAAa,YAAY,mBAAmB;wBAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;gBAC7G,CAAC,EACD,OAAO,EAAE,KAAK,CAAC,KAAK,GACpB,CACH,IACE,CACN,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type ReactElement, type ReactNode } from 'react';
|
|
2
|
+
/** Props Field hands to its control so the label, hint and error are programmatically associated. */
|
|
3
|
+
export interface FieldControlProps {
|
|
4
|
+
id: string;
|
|
5
|
+
'aria-describedby'?: string | undefined;
|
|
6
|
+
'aria-invalid'?: true | undefined;
|
|
7
|
+
'aria-required'?: true | undefined;
|
|
8
|
+
}
|
|
9
|
+
interface FieldProps {
|
|
10
|
+
label: ReactNode;
|
|
11
|
+
hint?: ReactNode | undefined;
|
|
12
|
+
error?: ReactNode | undefined;
|
|
13
|
+
required?: boolean | undefined;
|
|
14
|
+
/** Use a specific id for the control (otherwise one is generated, or the child's own `id` is kept). */
|
|
15
|
+
id?: string | undefined;
|
|
16
|
+
/** `caps`: small mono uppercase label (form default); `plain`: small sentence-case label. */
|
|
17
|
+
variant?: 'caps' | 'plain' | undefined;
|
|
18
|
+
className?: string | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Either a single control element (input/select/textarea/custom component that forwards `id` and aria-*),
|
|
21
|
+
* which receives the props via cloneElement, or a render function receiving them to spread where needed.
|
|
22
|
+
*/
|
|
23
|
+
children: ReactElement<Partial<FieldControlProps>> | ((control: FieldControlProps) => ReactNode);
|
|
24
|
+
}
|
|
25
|
+
export declare function Field({ label, hint, error, required, id, variant, className, children }: FieldProps): import("react").JSX.Element;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=Field.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Field.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Field.tsx"],"names":[],"mappings":"AACA,OAAO,EAAuC,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAE9F,qGAAqG;AACrG,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,cAAc,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;IACjC,eAAe,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;CACnC;AAED,UAAU,UAAU;IAClB,KAAK,EAAE,SAAS,CAAA;IAChB,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IAC5B,KAAK,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IAC7B,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC9B,uGAAuG;IACvG,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvB,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACtC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B;;;OAGG;IACH,QAAQ,EAAE,YAAY,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,iBAAiB,KAAK,SAAS,CAAC,CAAA;CACjG;AAOD,wBAAgB,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,QAAgB,EAAE,EAAE,EAAE,OAAgB,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,UAAU,+BA6BpH"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import { cloneElement, isValidElement, useId } from 'react';
|
|
4
|
+
const LABEL_CLASS = {
|
|
5
|
+
caps: 'block font-mono text-xs uppercase tracking-wider mb-2',
|
|
6
|
+
plain: 'block text-xs mb-1.5',
|
|
7
|
+
};
|
|
8
|
+
export function Field({ label, hint, error, required = false, id, variant = 'caps', className, children }) {
|
|
9
|
+
const generatedId = useId();
|
|
10
|
+
const childId = typeof children !== 'function' && isValidElement(children) ? children.props.id : undefined;
|
|
11
|
+
const controlId = id ?? childId ?? generatedId;
|
|
12
|
+
const hintId = hint ? `${controlId}-hint` : undefined;
|
|
13
|
+
const errorId = error ? `${controlId}-error` : undefined;
|
|
14
|
+
const existingDescribedBy = typeof children !== 'function' && isValidElement(children) ? children.props['aria-describedby'] : undefined;
|
|
15
|
+
const describedBy = [existingDescribedBy, hintId, errorId].filter(Boolean).join(' ') || undefined;
|
|
16
|
+
const controlProps = {
|
|
17
|
+
id: controlId,
|
|
18
|
+
'aria-describedby': describedBy,
|
|
19
|
+
...(error ? { 'aria-invalid': true } : {}),
|
|
20
|
+
...(required ? { 'aria-required': true } : {}),
|
|
21
|
+
};
|
|
22
|
+
const control = typeof children === 'function' ? children(controlProps) : cloneElement(children, controlProps);
|
|
23
|
+
return (_jsxs("div", { className: className, children: [_jsxs("label", { htmlFor: controlId, className: LABEL_CLASS[variant], style: { color: 'var(--m3-secondary)' }, children: [label, required && _jsx("span", { "aria-hidden": "true", style: { color: 'var(--m3-down)' }, children: " *" })] }), control, hint && _jsx("p", { id: hintId, className: "text-xs mt-1.5", style: { color: 'var(--m3-secondary)' }, children: hint }), error && _jsx("p", { id: errorId, className: clsx('text-xs', hint ? 'mt-1' : 'mt-1.5'), style: { color: 'var(--m3-down)' }, children: error })] }));
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=Field.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Field.js","sourceRoot":"","sources":["../../../src/components/ui/Field.tsx"],"names":[],"mappings":";AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,EAAqC,MAAM,OAAO,CAAA;AA2B9F,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,uDAAuD;IAC7D,KAAK,EAAE,sBAAsB;CAC9B,CAAA;AAED,MAAM,UAAU,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,GAAG,KAAK,EAAE,EAAE,EAAE,OAAO,GAAG,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAc;IACnH,MAAM,WAAW,GAAG,KAAK,EAAE,CAAA;IAC3B,MAAM,OAAO,GAAG,OAAO,QAAQ,KAAK,UAAU,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IAC1G,MAAM,SAAS,GAAG,EAAE,IAAI,OAAO,IAAI,WAAW,CAAA;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,SAAS,OAAO,CAAC,CAAC,CAAC,SAAS,CAAA;IACrD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;IACxD,MAAM,mBAAmB,GAAG,OAAO,QAAQ,KAAK,UAAU,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACvI,MAAM,WAAW,GAAG,CAAC,mBAAmB,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS,CAAA;IAEjG,MAAM,YAAY,GAAsB;QACtC,EAAE,EAAE,SAAS;QACb,kBAAkB,EAAE,WAAW;QAC/B,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,IAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxD,CAAA;IAED,MAAM,OAAO,GAAG,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;IAE9G,OAAO,CACL,eAAK,SAAS,EAAE,SAAS,aACvB,iBAAO,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,aAChG,KAAK,EACL,QAAQ,IAAI,8BAAkB,MAAM,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,mBAAW,IAC7E,EACP,OAAO,EACP,IAAI,IAAI,YAAG,EAAE,EAAE,MAAM,EAAE,SAAS,EAAC,gBAAgB,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,YAAG,IAAI,GAAK,EACrG,KAAK,IAAI,YAAG,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,YAAG,KAAK,GAAK,IAC3H,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
interface PageContainerProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
className?: string | undefined;
|
|
5
|
+
}
|
|
6
|
+
/** Standard page padding and vertical rhythm with the entrance animation every admin page uses. */
|
|
7
|
+
export declare function PageContainer({ children, className }: PageContainerProps): import("react").JSX.Element;
|
|
8
|
+
interface PageHeaderProps {
|
|
9
|
+
title: ReactNode;
|
|
10
|
+
subtitle?: ReactNode | undefined;
|
|
11
|
+
/** Right-aligned controls (buttons, filters); they wrap under the title on narrow screens. */
|
|
12
|
+
actions?: ReactNode | undefined;
|
|
13
|
+
/** Extra content rendered under the title row, e.g. tabs or a filter bar. */
|
|
14
|
+
children?: ReactNode | undefined;
|
|
15
|
+
}
|
|
16
|
+
export declare function PageHeader({ title, subtitle, actions, children }: PageHeaderProps): import("react").JSX.Element;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=PageHeader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageHeader.d.ts","sourceRoot":"","sources":["../../../src/components/ui/PageHeader.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC/B;AAED,mGAAmG;AACnG,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,kBAAkB,+BAExE;AAED,UAAU,eAAe;IACvB,KAAK,EAAE,SAAS,CAAA;IAChB,QAAQ,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IAChC,8FAA8F;IAC9F,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IAC/B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;CACjC;AAED,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,eAAe,+BAajF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
/** Standard page padding and vertical rhythm with the entrance animation every admin page uses. */
|
|
4
|
+
export function PageContainer({ children, className }) {
|
|
5
|
+
return _jsx("div", { className: clsx('p-4 md:p-8 space-y-6 fade-up', className), children: children });
|
|
6
|
+
}
|
|
7
|
+
export function PageHeader({ title, subtitle, actions, children }) {
|
|
8
|
+
return (_jsxs("header", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-x-4 gap-y-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("h1", { className: "font-headline font-bold text-2xl", style: { color: 'var(--m3-on-surface)' }, children: title }), subtitle && _jsx("p", { className: "text-sm mt-1", style: { color: 'var(--m3-secondary)' }, children: subtitle })] }), actions && _jsx("div", { className: "flex flex-wrap items-center gap-2", children: actions })] }), children] }));
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=PageHeader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageHeader.js","sourceRoot":"","sources":["../../../src/components/ui/PageHeader.tsx"],"names":[],"mappings":";AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AAQvB,mGAAmG;AACnG,MAAM,UAAU,aAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAsB;IACvE,OAAO,cAAK,SAAS,EAAE,IAAI,CAAC,8BAA8B,EAAE,SAAS,CAAC,YAAG,QAAQ,GAAO,CAAA;AAC1F,CAAC;AAWD,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAmB;IAChF,OAAO,CACL,kBAAQ,SAAS,EAAC,WAAW,aAC3B,eAAK,SAAS,EAAC,4DAA4D,aACzE,eAAK,SAAS,EAAC,SAAS,aACtB,aAAI,SAAS,EAAC,kCAAkC,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,sBAAsB,EAAE,YAAG,KAAK,GAAM,EACtG,QAAQ,IAAI,YAAG,SAAS,EAAC,cAAc,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,YAAG,QAAQ,GAAK,IAC5F,EACL,OAAO,IAAI,cAAK,SAAS,EAAC,mCAAmC,YAAE,OAAO,GAAO,IAC1E,EACL,QAAQ,IACF,CACV,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
type PaginationProps = {
|
|
3
|
+
/** 1-based current page. */
|
|
4
|
+
page: number;
|
|
5
|
+
onPageChange: (page: number) => void;
|
|
6
|
+
/** Text on the left, e.g. "Page 2 of 5 · 93 entries". Defaults to "Page X of Y" when pageCount is known. */
|
|
7
|
+
summary?: ReactNode | undefined;
|
|
8
|
+
/** Hide the whole bar when there is only one page (default true; ignored with hasNext). */
|
|
9
|
+
hideWhenSingle?: boolean | undefined;
|
|
10
|
+
} & ({
|
|
11
|
+
pageCount: number;
|
|
12
|
+
hasNext?: never;
|
|
13
|
+
}
|
|
14
|
+
/** For cursor/unknown-total lists: whether a next page exists. */
|
|
15
|
+
| {
|
|
16
|
+
hasNext: boolean;
|
|
17
|
+
pageCount?: never;
|
|
18
|
+
});
|
|
19
|
+
export declare function Pagination({ page, onPageChange, summary, hideWhenSingle, pageCount, hasNext }: PaginationProps): import("react").JSX.Element | null;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=Pagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["../../../src/components/ui/Pagination.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,KAAK,eAAe,GAAG;IACrB,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,4GAA4G;IAC5G,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IAC/B,2FAA2F;IAC3F,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CACrC,GAAG,CACA;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAA;CAAE;AACxC,kEAAkE;GAChE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,KAAK,CAAA;CAAE,CAC1C,CAAA;AAED,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,cAAqB,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,eAAe,sCAoBrH"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export function Pagination({ page, onPageChange, summary, hideWhenSingle = true, pageCount, hasNext }) {
|
|
3
|
+
const canPrev = page > 1;
|
|
4
|
+
const canNext = pageCount !== undefined ? page < pageCount : Boolean(hasNext);
|
|
5
|
+
if (pageCount !== undefined && hideWhenSingle && pageCount <= 1)
|
|
6
|
+
return null;
|
|
7
|
+
const text = summary ?? (pageCount !== undefined ? `Page ${page} of ${pageCount}` : `Page ${page}`);
|
|
8
|
+
return (_jsxs("nav", { "aria-label": "Pagination", className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("span", { className: "text-sm", style: { color: 'var(--m3-secondary)' }, children: text }), _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { type: "button", onClick: () => onPageChange(page - 1), disabled: !canPrev, "aria-label": "Previous page", className: "btn btn-outline btn-sm text-sm font-normal", children: "\u2190 Prev" }), _jsx("button", { type: "button", onClick: () => onPageChange(page + 1), disabled: !canNext, "aria-label": "Next page", className: "btn btn-outline btn-sm text-sm font-normal", children: "Next \u2192" })] })] }));
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=Pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Pagination.js","sourceRoot":"","sources":["../../../src/components/ui/Pagination.tsx"],"names":[],"mappings":";AAgBA,MAAM,UAAU,UAAU,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,EAAE,SAAS,EAAE,OAAO,EAAmB;IACpH,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAA;IACxB,MAAM,OAAO,GAAG,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7E,IAAI,SAAS,KAAK,SAAS,IAAI,cAAc,IAAI,SAAS,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAE5E,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,IAAI,OAAO,SAAS,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAA;IAEnG,OAAO,CACL,6BAAgB,YAAY,EAAC,SAAS,EAAC,mDAAmD,aACxF,eAAM,SAAS,EAAC,SAAS,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,YAAG,IAAI,GAAQ,EAChF,eAAK,SAAS,EAAC,YAAY,aACzB,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,OAAO,gBAAa,eAAe,EAAC,SAAS,EAAC,4CAA4C,4BAEzJ,EACT,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,OAAO,gBAAa,WAAW,EAAC,SAAS,EAAC,4CAA4C,4BAErJ,IACL,IACF,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export interface QuickStartOption<K extends string> {
|
|
3
|
+
key: K;
|
|
4
|
+
label: string;
|
|
5
|
+
hint: string;
|
|
6
|
+
/** Icon element (a Material Symbol or a brand glyph), rendered inside the tile's icon chip. */
|
|
7
|
+
icon: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
interface QuickStartPanelProps<K extends string> {
|
|
10
|
+
title: string;
|
|
11
|
+
description?: ReactNode | undefined;
|
|
12
|
+
options: QuickStartOption<K>[];
|
|
13
|
+
onPick: (key: K) => void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* First-run panel shown in place of an empty list when the first step is a choice, e.g. which kind of
|
|
17
|
+
* channel to create. Each tile starts the create flow with that choice already made.
|
|
18
|
+
*/
|
|
19
|
+
export declare function QuickStartPanel<K extends string>({ title, description, options, onPick }: QuickStartPanelProps<K>): import("react").JSX.Element;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=QuickStartPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QuickStartPanel.d.ts","sourceRoot":"","sources":["../../../src/components/ui/QuickStartPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAE7C,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM;IAChD,GAAG,EAAE,CAAC,CAAA;IACN,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,+FAA+F;IAC/F,IAAI,EAAE,SAAS,CAAA;CAChB;AAED,UAAU,oBAAoB,CAAC,CAAC,SAAS,MAAM;IAC7C,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IACnC,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAA;IAC9B,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAA;CACzB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,oBAAoB,CAAC,CAAC,CAAC,+BAmCjH"}
|