@eifi1/ui-kit 0.17.0 → 0.18.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/README.md +29 -4
- package/dist/chart.d.ts +10 -1
- package/dist/components/account-chips.d.ts +153 -0
- package/dist/components/account-chips.js +135 -0
- package/dist/components/account-chips.js.map +1 -0
- package/dist/components/account-settings-labels.d.ts +10 -2
- package/dist/components/account-settings-labels.js +3 -0
- package/dist/components/account-settings-labels.js.map +1 -1
- package/dist/components/amount-input.d.ts +10 -1
- package/dist/components/button-group.d.ts +10 -1
- package/dist/components/calculator.d.ts +10 -1
- package/dist/components/chip.d.ts +25 -1
- package/dist/components/chip.js +143 -6
- package/dist/components/chip.js.map +1 -1
- package/dist/components/confirm-dialog.d.ts +42 -1
- package/dist/components/confirm-dialog.js +36 -5
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/copy-button.d.ts +10 -1
- package/dist/components/danger-confirm.d.ts +55 -4
- package/dist/components/danger-confirm.js +67 -30
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/data-table-cells.d.ts +1 -1
- package/dist/components/data-table-filter-popover.d.ts +1 -1
- package/dist/components/data-table-filters.d.ts +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +2 -0
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/facing-pair.d.ts +10 -1
- package/dist/components/file-button.d.ts +10 -1
- package/dist/components/file-dropzone.d.ts +10 -1
- package/dist/components/form-actions.d.ts +10 -1
- package/dist/components/form-actions.js +3 -0
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/money-field.d.ts +10 -1
- package/dist/components/number-field.d.ts +11 -2
- package/dist/components/number-field.js +23 -22
- package/dist/components/number-field.js.map +1 -1
- package/dist/components/number-input.d.ts +10 -1
- package/dist/components/numpad-sheet.d.ts +10 -1
- package/dist/components/passkeys-setting.d.ts +27 -1
- package/dist/components/passkeys-setting.js +31 -5
- package/dist/components/passkeys-setting.js.map +1 -1
- package/dist/components/progress-bar.d.ts +15 -1
- package/dist/components/progress-bar.js +8 -1
- package/dist/components/progress-bar.js.map +1 -1
- package/dist/components/reauth-dialog.d.ts +90 -0
- package/dist/components/reauth-dialog.js +158 -0
- package/dist/components/reauth-dialog.js.map +1 -0
- package/dist/components/series-chart.d.ts +10 -1
- package/dist/components/server-wake.d.ts +58 -0
- package/dist/components/server-wake.js +58 -0
- package/dist/components/server-wake.js.map +1 -0
- package/dist/components/settings-fields.d.ts +10 -1
- package/dist/components/share-card.d.ts +61 -0
- package/dist/components/share-card.js +350 -0
- package/dist/components/share-card.js.map +1 -0
- package/dist/components/status-dot.d.ts +2 -0
- package/dist/components/text-link.d.ts +10 -1
- package/dist/components/time-input.d.ts +10 -1
- package/dist/components/toast.d.ts +10 -1
- package/dist/components/toast.js +42 -2
- package/dist/components/toast.js.map +1 -1
- package/dist/components/toggle-group.js +5 -2
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/ui.d.ts +10 -1
- package/dist/components/ui.js +43 -28
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +1 -1
- package/dist/components/user-avatar.d.ts +2 -0
- package/dist/components/write-lock.d.ts +68 -0
- package/dist/components/write-lock.js +33 -0
- package/dist/components/write-lock.js.map +1 -0
- package/dist/{data-table-CpkWUJBY.d.ts → data-table-3mi2R3so.d.ts} +19 -1
- package/dist/data-table.d.ts +1 -1
- package/dist/hooks/use-file-drop.d.ts +10 -1
- package/dist/hooks/use-overlay-history.js +16 -0
- package/dist/hooks/use-overlay-history.js.map +1 -1
- package/dist/i18n/defaults.d.ts +10 -1
- package/dist/i18n/defaults.js +11 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.d.ts +78 -0
- package/dist/i18n/{locales/de.js → german.js} +59 -9
- package/dist/i18n/german.js.map +1 -0
- package/dist/i18n/kit-labels.d.ts +10 -1
- package/dist/i18n/kit-labels.js +5 -0
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/de-CH.d.ts +23 -8
- package/dist/i18n/locales/de-CH.js +7 -3
- package/dist/i18n/locales/de-CH.js.map +1 -1
- package/dist/i18n/locales/en.d.ts +10 -1
- package/dist/i18n/locales/es.d.ts +10 -1
- package/dist/i18n/locales/es.js +51 -1
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +10 -1
- package/dist/i18n/locales/fr.js +51 -1
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +10 -1
- package/dist/i18n/locales/hu.js +54 -1
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +10 -1
- package/dist/i18n/locales/it.js +51 -1
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +10 -1
- package/dist/i18n/locales/zh.js +50 -1
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/swiss.d.ts +3 -3
- package/dist/i18n/swiss.js.map +1 -1
- package/dist/index.d.ts +9 -4
- package/dist/index.js +33 -1
- package/dist/index.js.map +1 -1
- package/dist/{kit-labels-C4uB_zmg.d.ts → kit-labels-CPbsjlXr.d.ts} +229 -9
- package/dist/lib/server-wake.d.ts +130 -0
- package/dist/lib/server-wake.js +121 -0
- package/dist/lib/server-wake.js.map +1 -0
- package/dist/rhf/fields.d.ts +10 -1
- package/dist/rhf/form.d.ts +10 -1
- package/dist/rhf.d.ts +10 -1
- package/dist/search/global-search.d.ts +3 -1
- package/dist/search/global-search.js.map +1 -1
- package/dist/shell/app-shell.d.ts +10 -1
- package/dist/shell/top-bar-brand.d.ts +10 -1
- package/dist/shell/topbar-action-menu.d.ts +2 -0
- package/dist/shell.d.ts +10 -1
- package/dist/wizard/stepper-nav.d.ts +10 -1
- package/dist/wizard.d.ts +10 -1
- package/package.json +1 -1
- package/src/components/account-chips.tsx +302 -0
- package/src/components/account-settings-labels.ts +16 -2
- package/src/components/chip.tsx +239 -6
- package/src/components/confirm-dialog.tsx +82 -7
- package/src/components/danger-confirm.tsx +118 -33
- package/src/components/data-table.tsx +20 -0
- package/src/components/form-actions.tsx +22 -3
- package/src/components/number-field.tsx +32 -26
- package/src/components/passkeys-setting.tsx +68 -7
- package/src/components/progress-bar.tsx +21 -1
- package/src/components/reauth-dialog.tsx +273 -0
- package/src/components/server-wake.tsx +124 -0
- package/src/components/share-card.tsx +615 -0
- package/src/components/toast.tsx +72 -2
- package/src/components/toggle-group.tsx +5 -2
- package/src/components/ui.tsx +89 -32
- package/src/components/write-lock.tsx +96 -0
- package/src/hooks/use-overlay-history.ts +51 -0
- package/src/i18n/defaults.ts +10 -0
- package/src/i18n/{locales/de.ts → german.ts} +68 -13
- package/src/i18n/kit-labels.tsx +22 -2
- package/src/i18n/locales/de-CH.ts +17 -8
- package/src/i18n/locales/es.ts +51 -0
- package/src/i18n/locales/fr.ts +52 -0
- package/src/i18n/locales/hu.ts +55 -0
- package/src/i18n/locales/it.ts +51 -0
- package/src/i18n/locales/zh.ts +50 -0
- package/src/i18n/swiss.ts +3 -3
- package/src/index.ts +23 -1
- package/src/lib/server-wake.ts +270 -0
- package/src/search/global-search.tsx +3 -1
- package/dist/i18n/locales/de-CH-informal.d.ts +0 -61
- package/dist/i18n/locales/de-CH-informal.js +0 -8
- package/dist/i18n/locales/de-CH-informal.js.map +0 -1
- package/dist/i18n/locales/de-informal.d.ts +0 -82
- package/dist/i18n/locales/de-informal.js +0 -37
- package/dist/i18n/locales/de-informal.js.map +0 -1
- package/dist/i18n/locales/de.d.ts +0 -66
- package/dist/i18n/locales/de.js.map +0 -1
- package/src/i18n/locales/de-CH-informal.ts +0 -10
- package/src/i18n/locales/de-informal.ts +0 -61
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ServerWakeWatcher, ServerWakeStage } from '../lib/server-wake.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The visible half of the cold-start watchdog (`lib/server-wake.ts`), keksdose's
|
|
6
|
+
* `app/server-wake-notice.tsx` lifted into the kit: after a couple of seconds of an
|
|
7
|
+
* unanswered read it says the app is still loading, and after seven it says WHY — the
|
|
8
|
+
* server sleeps when nobody is using it, and the first request has to start it again.
|
|
9
|
+
*
|
|
10
|
+
* Corner-anchored and non-blocking on purpose. The pages underneath already show their
|
|
11
|
+
* own skeletons; what was missing is the explanation, not another overlay. Start
|
|
12
|
+
* corner, above the phone's bottom nav, so it collides with neither the centred toasts
|
|
13
|
+
* nor the nav bar.
|
|
14
|
+
*
|
|
15
|
+
* Mount it next to the router, not inside the app layout, so it also covers the login
|
|
16
|
+
* screen and the landing page — a cold start is at its most confusing exactly there,
|
|
17
|
+
* before anything of the app is on screen.
|
|
18
|
+
*/
|
|
19
|
+
interface ServerWakeLabels {
|
|
20
|
+
/** Past `slowMs` (2 s): a warm server would have answered by now. */
|
|
21
|
+
slow: string;
|
|
22
|
+
/** Past `wakingMs` (7 s): the explanation. `appName` is the notice's prop; without
|
|
23
|
+
* one the sentence says "the app". */
|
|
24
|
+
waking: (appName?: string) => string;
|
|
25
|
+
}
|
|
26
|
+
declare const DEFAULT_SERVER_WAKE_LABELS: ServerWakeLabels;
|
|
27
|
+
/** The watcher's current stage, re-rendering on every change. Default: the shared
|
|
28
|
+
* {@link serverWake} instance. */
|
|
29
|
+
declare function useServerWakeStage(watcher?: ServerWakeWatcher): ServerWakeStage;
|
|
30
|
+
interface ServerWakeNoticeProps {
|
|
31
|
+
/** Default: the shared {@link serverWake} instance. Pass the app's own when it was
|
|
32
|
+
* made with {@link createServerWake} (e.g. to watch the login POST too). */
|
|
33
|
+
watcher?: ServerWakeWatcher;
|
|
34
|
+
/** Named in the `waking` sentence ("…when nobody is using Keksdose…"). Default: the
|
|
35
|
+
* label says "the app". */
|
|
36
|
+
appName?: string;
|
|
37
|
+
labels?: Partial<ServerWakeLabels>;
|
|
38
|
+
/**
|
|
39
|
+
* The height to keep clear at the bottom — AppShell's bottom nav. Default: its
|
|
40
|
+
* measured `--app-nav-h` (0px from `md` up and on pages without a shell, such as the
|
|
41
|
+
* login screen), so nothing has to be passed under an AppShell. The safe area is
|
|
42
|
+
* respected either way, and a 1rem gap is added. Numbers are px.
|
|
43
|
+
*/
|
|
44
|
+
navOffset?: string | number;
|
|
45
|
+
/** Extra classes on the fixed anchor — a different width or `start-*`. The bottom
|
|
46
|
+
* offset is an inline style, so move it vertically with {@link navOffset}. */
|
|
47
|
+
className?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Renders nothing visible while idle. The LIVE REGION, though, is always mounted: a
|
|
51
|
+
* `role="status"` element inserted together with its text is announced unreliably
|
|
52
|
+
* (several screen readers only speak changes to a region they already knew about),
|
|
53
|
+
* so the region waits empty and the banner appears inside it. keksdose's notice
|
|
54
|
+
* mounted the region and the words at once.
|
|
55
|
+
*/
|
|
56
|
+
declare function ServerWakeNotice({ watcher, appName, labels: labelsProp, navOffset, className }: ServerWakeNoticeProps): react.JSX.Element;
|
|
57
|
+
|
|
58
|
+
export { DEFAULT_SERVER_WAKE_LABELS, type ServerWakeLabels, ServerWakeNotice, type ServerWakeNoticeProps, useServerWakeStage };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useSyncExternalStore } from "react";
|
|
4
|
+
import { useKitLabels } from "../i18n/kit-labels.js";
|
|
5
|
+
import { cn } from "../lib/cn.js";
|
|
6
|
+
import { serverWake } from "../lib/server-wake.js";
|
|
7
|
+
import { AlertBanner } from "./alert-banner.js";
|
|
8
|
+
import { Spinner } from "./ui.js";
|
|
9
|
+
const DEFAULT_SERVER_WAKE_LABELS = {
|
|
10
|
+
slow: "Still loading \u2014 this is taking longer than usual.",
|
|
11
|
+
waking: (appName) => `The server goes to sleep when nobody is using ${appName ?? "the app"}, so the first request after a break has to start it again. That can take a moment \u2014 nothing is lost, the page fills in by itself.`
|
|
12
|
+
};
|
|
13
|
+
function useServerWakeStage(watcher = serverWake) {
|
|
14
|
+
return useSyncExternalStore(watcher.subscribe, watcher.getStage, () => "idle");
|
|
15
|
+
}
|
|
16
|
+
const px = (v) => typeof v === "number" ? `${v}px` : v;
|
|
17
|
+
function ServerWakeNotice({ watcher, appName, labels: labelsProp, navOffset, className }) {
|
|
18
|
+
const labels = useKitLabels("serverWake", DEFAULT_SERVER_WAKE_LABELS, labelsProp);
|
|
19
|
+
const stage = useServerWakeStage(watcher);
|
|
20
|
+
const waking = stage === "waking";
|
|
21
|
+
const style = {
|
|
22
|
+
bottom: `calc(max(${navOffset === void 0 ? "var(--app-nav-h, 0px)" : px(navOffset)}, env(safe-area-inset-bottom, 0px)) + 1rem)`
|
|
23
|
+
};
|
|
24
|
+
return /* @__PURE__ */ jsx(
|
|
25
|
+
"div",
|
|
26
|
+
{
|
|
27
|
+
role: "status",
|
|
28
|
+
"aria-live": "polite",
|
|
29
|
+
"data-stage": stage,
|
|
30
|
+
style,
|
|
31
|
+
className: cn(
|
|
32
|
+
"fixed start-4 z-50 max-w-[min(24rem,calc(100vw-2rem))]",
|
|
33
|
+
stage === "idle" && "pointer-events-none",
|
|
34
|
+
className
|
|
35
|
+
),
|
|
36
|
+
children: stage !== "idle" && // `elevated`: OPAQUE in both themes (keksdose live #209) — the notice that
|
|
37
|
+
// explains a stall is read over whatever stalled, and a translucent dark tint
|
|
38
|
+
// let the page's own text show through it. A box banner is role-less, so the
|
|
39
|
+
// wrapper above stays the one live region.
|
|
40
|
+
/* @__PURE__ */ jsx(
|
|
41
|
+
AlertBanner,
|
|
42
|
+
{
|
|
43
|
+
tone: waking ? "warning" : "neutral",
|
|
44
|
+
size: "sm",
|
|
45
|
+
elevated: true,
|
|
46
|
+
icon: /* @__PURE__ */ jsx(Spinner, { label: null, className: "h-3.5 w-3.5" }),
|
|
47
|
+
children: waking ? labels.waking(appName) : labels.slow
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
DEFAULT_SERVER_WAKE_LABELS,
|
|
55
|
+
ServerWakeNotice,
|
|
56
|
+
useServerWakeStage
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=server-wake.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/server-wake.tsx"],"sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport type { CSSProperties } from \"react\";\n\nimport { useKitLabels } from \"../i18n/kit-labels\";\nimport { cn } from \"../lib/cn\";\nimport { serverWake } from \"../lib/server-wake\";\nimport type { ServerWakeStage, ServerWakeWatcher } from \"../lib/server-wake\";\nimport { AlertBanner } from \"./alert-banner\";\nimport { Spinner } from \"./ui\";\n\n/**\n * The visible half of the cold-start watchdog (`lib/server-wake.ts`), keksdose's\n * `app/server-wake-notice.tsx` lifted into the kit: after a couple of seconds of an\n * unanswered read it says the app is still loading, and after seven it says WHY — the\n * server sleeps when nobody is using it, and the first request has to start it again.\n *\n * Corner-anchored and non-blocking on purpose. The pages underneath already show their\n * own skeletons; what was missing is the explanation, not another overlay. Start\n * corner, above the phone's bottom nav, so it collides with neither the centred toasts\n * nor the nav bar.\n *\n * Mount it next to the router, not inside the app layout, so it also covers the login\n * screen and the landing page — a cold start is at its most confusing exactly there,\n * before anything of the app is on screen.\n */\n\n// ── Labels ────────────────────────────────────────────────────────────────────\n\nexport interface ServerWakeLabels {\n /** Past `slowMs` (2 s): a warm server would have answered by now. */\n slow: string;\n /** Past `wakingMs` (7 s): the explanation. `appName` is the notice's prop; without\n * one the sentence says \"the app\". */\n waking: (appName?: string) => string;\n}\n\nexport const DEFAULT_SERVER_WAKE_LABELS: ServerWakeLabels = {\n slow: \"Still loading — this is taking longer than usual.\",\n waking: (appName) =>\n `The server goes to sleep when nobody is using ${appName ?? \"the app\"}, so the first request after a break has to start it again. That can take a moment — nothing is lost, the page fills in by itself.`,\n};\n\n// ── Hook ──────────────────────────────────────────────────────────────────────\n\n/** The watcher's current stage, re-rendering on every change. Default: the shared\n * {@link serverWake} instance. */\nexport function useServerWakeStage(watcher: ServerWakeWatcher = serverWake): ServerWakeStage {\n // The server snapshot is `idle`: nothing is in flight while the HTML is rendered.\n return useSyncExternalStore(watcher.subscribe, watcher.getStage, () => \"idle\");\n}\n\n// ── Notice ────────────────────────────────────────────────────────────────────\n\nexport interface ServerWakeNoticeProps {\n /** Default: the shared {@link serverWake} instance. Pass the app's own when it was\n * made with {@link createServerWake} (e.g. to watch the login POST too). */\n watcher?: ServerWakeWatcher;\n /** Named in the `waking` sentence (\"…when nobody is using Keksdose…\"). Default: the\n * label says \"the app\". */\n appName?: string;\n labels?: Partial<ServerWakeLabels>;\n /**\n * The height to keep clear at the bottom — AppShell's bottom nav. Default: its\n * measured `--app-nav-h` (0px from `md` up and on pages without a shell, such as the\n * login screen), so nothing has to be passed under an AppShell. The safe area is\n * respected either way, and a 1rem gap is added. Numbers are px.\n */\n navOffset?: string | number;\n /** Extra classes on the fixed anchor — a different width or `start-*`. The bottom\n * offset is an inline style, so move it vertically with {@link navOffset}. */\n className?: string;\n}\n\nconst px = (v: string | number) => (typeof v === \"number\" ? `${v}px` : v);\n\n/**\n * Renders nothing visible while idle. The LIVE REGION, though, is always mounted: a\n * `role=\"status\"` element inserted together with its text is announced unreliably\n * (several screen readers only speak changes to a region they already knew about),\n * so the region waits empty and the banner appears inside it. keksdose's notice\n * mounted the region and the words at once.\n */\nexport function ServerWakeNotice({ watcher, appName, labels: labelsProp, navOffset, className }: ServerWakeNoticeProps) {\n const labels = useKitLabels(\"serverWake\", DEFAULT_SERVER_WAKE_LABELS, labelsProp);\n const stage = useServerWakeStage(watcher);\n const waking = stage === \"waking\";\n const style: CSSProperties = {\n bottom: `calc(max(${navOffset === undefined ? \"var(--app-nav-h, 0px)\" : px(navOffset)}, env(safe-area-inset-bottom, 0px)) + 1rem)`,\n };\n\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n data-stage={stage}\n style={style}\n // `pointer-events-none` on the empty anchor: a fixed box, even an empty one, is not\n // allowed to swallow a tap on what it sits over.\n className={cn(\n \"fixed start-4 z-50 max-w-[min(24rem,calc(100vw-2rem))]\",\n stage === \"idle\" && \"pointer-events-none\",\n className,\n )}\n >\n {stage !== \"idle\" && (\n // `elevated`: OPAQUE in both themes (keksdose live #209) — the notice that\n // explains a stall is read over whatever stalled, and a translucent dark tint\n // let the page's own text show through it. A box banner is role-less, so the\n // wrapper above stays the one live region.\n <AlertBanner\n tone={waking ? \"warning\" : \"neutral\"}\n size=\"sm\"\n elevated\n // `label={null}`: a Spinner is its own `role=\"status\"` saying \"Loading…\" —\n // nested here, a second live region and a second announcement ahead of the\n // words that actually explain the wait. Here it is decoration.\n icon={<Spinner label={null} className=\"h-3.5 w-3.5\" />}\n >\n {waking ? labels.waking(appName) : labels.slow}\n </AlertBanner>\n )}\n </div>\n );\n}\n"],"mappings":";AAoHgB;AApHhB,SAAS,4BAA4B;AAGrC,SAAS,oBAAoB;AAC7B,SAAS,UAAU;AACnB,SAAS,kBAAkB;AAE3B,SAAS,mBAAmB;AAC5B,SAAS,eAAe;AA4BjB,MAAM,6BAA+C;AAAA,EAC1D,MAAM;AAAA,EACN,QAAQ,CAAC,YACP,iDAAiD,WAAW,SAAS;AACzE;AAMO,SAAS,mBAAmB,UAA6B,YAA6B;AAE3F,SAAO,qBAAqB,QAAQ,WAAW,QAAQ,UAAU,MAAM,MAAM;AAC/E;AAwBA,MAAM,KAAK,CAAC,MAAwB,OAAO,MAAM,WAAW,GAAG,CAAC,OAAO;AAShE,SAAS,iBAAiB,EAAE,SAAS,SAAS,QAAQ,YAAY,WAAW,UAAU,GAA0B;AACtH,QAAM,SAAS,aAAa,cAAc,4BAA4B,UAAU;AAChF,QAAM,QAAQ,mBAAmB,OAAO;AACxC,QAAM,SAAS,UAAU;AACzB,QAAM,QAAuB;AAAA,IAC3B,QAAQ,YAAY,cAAc,SAAY,0BAA0B,GAAG,SAAS,CAAC;AAAA,EACvF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,cAAY;AAAA,MACZ;AAAA,MAGA,WAAW;AAAA,QACT;AAAA,QACA,UAAU,UAAU;AAAA,QACpB;AAAA,MACF;AAAA,MAEC,oBAAU;AAAA;AAAA;AAAA;AAAA,MAKT;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,SAAS,YAAY;AAAA,UAC3B,MAAK;AAAA,UACL,UAAQ;AAAA,UAIR,MAAM,oBAAC,WAAQ,OAAO,MAAM,WAAU,eAAc;AAAA,UAEnD,mBAAS,OAAO,OAAO,OAAO,IAAI,OAAO;AAAA;AAAA,MAC5C;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { aQ as SelectProps } from '../kit-labels-CPbsjlXr.js';
|
|
4
4
|
import { ThemePreference } from '../theme/theme-store.js';
|
|
5
5
|
import './data-table-labels.js';
|
|
6
6
|
import './mini-calendar.js';
|
|
@@ -52,6 +52,15 @@ import './authed-image.js';
|
|
|
52
52
|
import '../hooks/use-authed-src.js';
|
|
53
53
|
import './image-grid.js';
|
|
54
54
|
import './lightbox.js';
|
|
55
|
+
import './write-lock.js';
|
|
56
|
+
import './account-chips.js';
|
|
57
|
+
import '../lib/format.js';
|
|
58
|
+
import '../data-table-3mi2R3so.js';
|
|
59
|
+
import './data-table-sort.js';
|
|
60
|
+
import './swipeable-row.js';
|
|
61
|
+
import './reauth-dialog.js';
|
|
62
|
+
import './server-wake.js';
|
|
63
|
+
import '../lib/server-wake.js';
|
|
55
64
|
import 'zustand/middleware';
|
|
56
65
|
import 'zustand';
|
|
57
66
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import 'react';
|
|
2
|
+
import './account-chips.js';
|
|
3
|
+
import './dialog-frame.js';
|
|
4
|
+
export { U as DEFAULT_SHARE_CARD_LABELS, aR as ShareAddRequest, aS as ShareCandidate, aT as ShareCard, aU as ShareCardLabels, aV as ShareCardProps, aW as ShareDialog, aX as ShareDialogProps, aY as ShareGrantee, aZ as SharePanel, a_ as SharePanelProps, a$ as SharePendingGrant, b0 as ShareRole } from '../kit-labels-CPbsjlXr.js';
|
|
5
|
+
import 'lucide-react';
|
|
6
|
+
import '../lib/format.js';
|
|
7
|
+
import './chip.js';
|
|
8
|
+
import '../data-table-3mi2R3so.js';
|
|
9
|
+
import './data-table-sort.js';
|
|
10
|
+
import './swipeable-row.js';
|
|
11
|
+
import './data-table-labels.js';
|
|
12
|
+
import './modal.js';
|
|
13
|
+
import '../hooks/use-search-param-state.js';
|
|
14
|
+
import './mini-calendar.js';
|
|
15
|
+
import './calendar-heatmap.js';
|
|
16
|
+
import './popover.js';
|
|
17
|
+
import './field-sync.js';
|
|
18
|
+
import './tooltip.js';
|
|
19
|
+
import '../hooks/use-anchored-rect.js';
|
|
20
|
+
import '../lib/clipping.js';
|
|
21
|
+
import '../wizard/types.js';
|
|
22
|
+
import '../tour/tour.js';
|
|
23
|
+
import '../search/command-palette.js';
|
|
24
|
+
import '../search/global-search.js';
|
|
25
|
+
import '../search/search-index.js';
|
|
26
|
+
import './month-picker.js';
|
|
27
|
+
import './page-contents.js';
|
|
28
|
+
import './series-chart-labels.js';
|
|
29
|
+
import './pie-chart-labels.js';
|
|
30
|
+
import './sparkline.js';
|
|
31
|
+
import './stat-tile.js';
|
|
32
|
+
import './signature-pad.js';
|
|
33
|
+
import './password-strength.js';
|
|
34
|
+
import './danger-confirm.js';
|
|
35
|
+
import './swatch-picker.js';
|
|
36
|
+
import './tile-radio.js';
|
|
37
|
+
import './icon-picker.js';
|
|
38
|
+
import './measured-grid.js';
|
|
39
|
+
import '../feedback-attachment-WFiXJ8We.js';
|
|
40
|
+
import '../feedback/feedback-thread.js';
|
|
41
|
+
import '../feedback/feedback-inbox.js';
|
|
42
|
+
import './account-settings-labels.js';
|
|
43
|
+
import './confirm-dialog.js';
|
|
44
|
+
import './floating-panel.js';
|
|
45
|
+
import './bulk-action-bar.js';
|
|
46
|
+
import './list.js';
|
|
47
|
+
import './signed-amount.js';
|
|
48
|
+
import './breadcrumbs.js';
|
|
49
|
+
import './toast.js';
|
|
50
|
+
import './description-list.js';
|
|
51
|
+
import './line-items.js';
|
|
52
|
+
import './progress-bar.js';
|
|
53
|
+
import './error-boundary.js';
|
|
54
|
+
import './authed-image.js';
|
|
55
|
+
import '../hooks/use-authed-src.js';
|
|
56
|
+
import './image-grid.js';
|
|
57
|
+
import './lightbox.js';
|
|
58
|
+
import './write-lock.js';
|
|
59
|
+
import './reauth-dialog.js';
|
|
60
|
+
import './server-wake.js';
|
|
61
|
+
import '../lib/server-wake.js';
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Trash2, UserPlus, UsersRound } from "lucide-react";
|
|
5
|
+
import { useKitLabels } from "../i18n/kit-labels.js";
|
|
6
|
+
import { cn } from "../lib/cn.js";
|
|
7
|
+
import { AlertBanner } from "./alert-banner.js";
|
|
8
|
+
import { Autocomplete } from "./autocomplete.js";
|
|
9
|
+
import { Chip } from "./chip.js";
|
|
10
|
+
import { RoleChip } from "./account-chips.js";
|
|
11
|
+
import { useConfirm } from "./confirm-dialog.js";
|
|
12
|
+
import { CopyButton } from "./copy-button.js";
|
|
13
|
+
import { DialogFrame } from "./dialog-frame.js";
|
|
14
|
+
import { Caption, SectionLabel } from "./text.js";
|
|
15
|
+
import { ToggleGroup } from "./toggle-group.js";
|
|
16
|
+
import { Tooltip } from "./tooltip.js";
|
|
17
|
+
import { Button, Card, IconButton, Spinner } from "./ui.js";
|
|
18
|
+
import { useWriteLock } from "./write-lock.js";
|
|
19
|
+
const DEFAULT_SHARE_CARD_LABELS = {
|
|
20
|
+
dialogTitle: "Share",
|
|
21
|
+
close: "Close",
|
|
22
|
+
email: "Email address",
|
|
23
|
+
emailOptional: "Email address (optional)",
|
|
24
|
+
emailPlaceholder: "name@example.com",
|
|
25
|
+
invalidEmail: "Enter a complete email address.",
|
|
26
|
+
role: "Role",
|
|
27
|
+
roleOf: (name) => `Role of ${name}`,
|
|
28
|
+
add: "Share",
|
|
29
|
+
whoHasAccess: "Who has access",
|
|
30
|
+
nobodyYet: "Nobody else has access yet.",
|
|
31
|
+
pending: "Pending",
|
|
32
|
+
openInvite: "Open invite link",
|
|
33
|
+
copyLink: "Copy link",
|
|
34
|
+
team: "Team",
|
|
35
|
+
teamHint: (name) => `Everyone in ${name} gets access.`,
|
|
36
|
+
remove: "Remove access",
|
|
37
|
+
removeConfirm: (name) => `Remove access for ${name}?`,
|
|
38
|
+
revokePending: "Withdraw invitation",
|
|
39
|
+
revokePendingConfirm: (name) => `Withdraw the invitation for ${name}?`,
|
|
40
|
+
failed: "That did not work. Please try again.",
|
|
41
|
+
loading: "Loading\u2026"
|
|
42
|
+
};
|
|
43
|
+
const EMAIL_SHAPE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
44
|
+
function ShareRoleChip({ role }) {
|
|
45
|
+
if (!role) return null;
|
|
46
|
+
const chip = /* @__PURE__ */ jsx(RoleChip, { value: role.key, roles: { [role.key]: role } });
|
|
47
|
+
return role.description ? /* @__PURE__ */ jsx(Tooltip, { label: role.description, children: chip }) : chip;
|
|
48
|
+
}
|
|
49
|
+
function LockedRoleChoice({ reason, children }) {
|
|
50
|
+
return reason === void 0 ? children : /* @__PURE__ */ jsx(Tooltip, { label: reason, children });
|
|
51
|
+
}
|
|
52
|
+
function SharePanel({
|
|
53
|
+
grantees,
|
|
54
|
+
roles,
|
|
55
|
+
pending = [],
|
|
56
|
+
candidates,
|
|
57
|
+
defaultRole,
|
|
58
|
+
onAdd,
|
|
59
|
+
onRoleChange,
|
|
60
|
+
onRemove,
|
|
61
|
+
onRevokePending,
|
|
62
|
+
addWithoutEmail = false,
|
|
63
|
+
caption,
|
|
64
|
+
intro,
|
|
65
|
+
loading = false,
|
|
66
|
+
error,
|
|
67
|
+
formatError,
|
|
68
|
+
readOnly = false,
|
|
69
|
+
autoFocus,
|
|
70
|
+
labels: labelsProp
|
|
71
|
+
}) {
|
|
72
|
+
const labels = useKitLabels("shareCard", DEFAULT_SHARE_CARD_LABELS, labelsProp);
|
|
73
|
+
const confirm = useConfirm();
|
|
74
|
+
const lock = useWriteLock();
|
|
75
|
+
const [email, setEmail] = useState("");
|
|
76
|
+
const [target, setTarget] = useState(null);
|
|
77
|
+
const [newRole, setNewRole] = useState(defaultRole ?? roles[0]?.key ?? "");
|
|
78
|
+
const [invalid, setInvalid] = useState(false);
|
|
79
|
+
const [busy, setBusy] = useState(null);
|
|
80
|
+
const [failure, setFailure] = useState(null);
|
|
81
|
+
const roleOf = (key) => roles.find((r) => r.key === key);
|
|
82
|
+
const choosable = roles.length > 1;
|
|
83
|
+
const canAdd = !readOnly && onAdd !== void 0;
|
|
84
|
+
const run = async (key, action) => {
|
|
85
|
+
setBusy(key);
|
|
86
|
+
setFailure(null);
|
|
87
|
+
try {
|
|
88
|
+
await action();
|
|
89
|
+
return true;
|
|
90
|
+
} catch (caught) {
|
|
91
|
+
setFailure(formatError ? formatError(caught) : labels.failed);
|
|
92
|
+
return false;
|
|
93
|
+
} finally {
|
|
94
|
+
setBusy(null);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const address = email.trim();
|
|
98
|
+
const empty = !target && address === "";
|
|
99
|
+
const submit = async () => {
|
|
100
|
+
if (!onAdd || busy || lock.locked) return;
|
|
101
|
+
if (empty && !addWithoutEmail) return;
|
|
102
|
+
if (!target && address !== "" && !EMAIL_SHAPE.test(address)) {
|
|
103
|
+
setInvalid(true);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const request = {
|
|
107
|
+
email: target ? null : address || null,
|
|
108
|
+
candidate: target,
|
|
109
|
+
role: newRole
|
|
110
|
+
};
|
|
111
|
+
if (await run("add", () => onAdd(request))) {
|
|
112
|
+
setEmail("");
|
|
113
|
+
setTarget(null);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const options = (candidates ?? []).map((c) => ({
|
|
117
|
+
value: String(c.id),
|
|
118
|
+
label: c.name,
|
|
119
|
+
sublabel: c.kind === "team" ? labels.team : c.email ?? void 0,
|
|
120
|
+
icon: c.icon ?? (c.kind === "team" ? /* @__PURE__ */ jsx(UsersRound, { className: "size-4" }) : void 0)
|
|
121
|
+
}));
|
|
122
|
+
const needle = (target ? "" : email).trim().toLowerCase();
|
|
123
|
+
const offers = needle !== "" && options.some((o) => o.label.toLowerCase().includes(needle) || (o.sublabel ?? "").toLowerCase().includes(needle));
|
|
124
|
+
const captionNode = typeof caption === "function" ? caption(target) : caption;
|
|
125
|
+
const shownError = error ?? failure;
|
|
126
|
+
const nobody = grantees.length === 0 && pending.length === 0;
|
|
127
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
128
|
+
intro && /* @__PURE__ */ jsx("div", { className: "text-xs text-[var(--text-muted)]", children: intro }),
|
|
129
|
+
canAdd && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
130
|
+
/* @__PURE__ */ jsxs(
|
|
131
|
+
"div",
|
|
132
|
+
{
|
|
133
|
+
className: cn(
|
|
134
|
+
"grid grid-cols-1 gap-2",
|
|
135
|
+
choosable && "sm:grid-cols-[minmax(0,1fr)_auto] sm:items-start"
|
|
136
|
+
),
|
|
137
|
+
children: [
|
|
138
|
+
/* @__PURE__ */ jsx(
|
|
139
|
+
Autocomplete,
|
|
140
|
+
{
|
|
141
|
+
label: addWithoutEmail ? labels.emailOptional : labels.email,
|
|
142
|
+
placeholder: labels.emailPlaceholder,
|
|
143
|
+
value: target ? target.name : email,
|
|
144
|
+
options,
|
|
145
|
+
open: offers ? void 0 : false,
|
|
146
|
+
fillOnSelect: false,
|
|
147
|
+
autoFocus,
|
|
148
|
+
inputMode: "email",
|
|
149
|
+
autoComplete: "off",
|
|
150
|
+
autoCapitalize: "none",
|
|
151
|
+
spellCheck: false,
|
|
152
|
+
disabled: busy !== null,
|
|
153
|
+
error: invalid ? labels.invalidEmail : void 0,
|
|
154
|
+
onChange: (text) => {
|
|
155
|
+
setTarget(null);
|
|
156
|
+
setInvalid(false);
|
|
157
|
+
setFailure(null);
|
|
158
|
+
setEmail(text);
|
|
159
|
+
},
|
|
160
|
+
onSelect: (option) => {
|
|
161
|
+
const chosen = (candidates ?? []).find((c) => String(c.id) === option.value);
|
|
162
|
+
if (!chosen) return;
|
|
163
|
+
setInvalid(false);
|
|
164
|
+
if (chosen.kind !== "team" && chosen.email) {
|
|
165
|
+
setTarget(null);
|
|
166
|
+
setEmail(chosen.email);
|
|
167
|
+
} else {
|
|
168
|
+
setTarget(chosen);
|
|
169
|
+
setEmail("");
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
onKeyDown: (event) => {
|
|
173
|
+
if (event.key === "Enter") void submit();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
),
|
|
177
|
+
choosable && /* @__PURE__ */ jsx(
|
|
178
|
+
ToggleGroup,
|
|
179
|
+
{
|
|
180
|
+
"aria-label": labels.role,
|
|
181
|
+
options: roles.map((r) => ({ value: r.key, label: r.label })),
|
|
182
|
+
value: newRole,
|
|
183
|
+
onChange: setNewRole,
|
|
184
|
+
disabled: busy !== null,
|
|
185
|
+
caption: roles.some((r) => r.description) ? (key) => roleOf(key)?.description : void 0,
|
|
186
|
+
optionClassName: "sm:min-h-10"
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
),
|
|
192
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
|
|
193
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 basis-48 space-y-1", children: [
|
|
194
|
+
target?.kind === "team" && /* @__PURE__ */ jsx(Caption, { children: labels.teamHint(target.name) }),
|
|
195
|
+
captionNode && /* @__PURE__ */ jsx(Caption, { as: "div", children: captionNode })
|
|
196
|
+
] }),
|
|
197
|
+
/* @__PURE__ */ jsxs(
|
|
198
|
+
Button,
|
|
199
|
+
{
|
|
200
|
+
variant: "brand",
|
|
201
|
+
commit: true,
|
|
202
|
+
pending: busy === "add",
|
|
203
|
+
disabled: busy !== null || empty && !addWithoutEmail,
|
|
204
|
+
onClick: () => void submit(),
|
|
205
|
+
className: "ms-auto",
|
|
206
|
+
children: [
|
|
207
|
+
/* @__PURE__ */ jsx(UserPlus, { className: "size-4", "aria-hidden": true }),
|
|
208
|
+
labels.add
|
|
209
|
+
]
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
] })
|
|
213
|
+
] }),
|
|
214
|
+
shownError && /* @__PURE__ */ jsx(AlertBanner, { tone: "danger", size: "sm", children: shownError }),
|
|
215
|
+
loading ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-3", children: /* @__PURE__ */ jsx(Spinner, { label: labels.loading }) }) : /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
216
|
+
/* @__PURE__ */ jsx(SectionLabel, { as: "h4", children: labels.whoHasAccess }),
|
|
217
|
+
nobody && /* @__PURE__ */ jsx(Caption, { children: labels.nobodyYet }),
|
|
218
|
+
/* @__PURE__ */ jsxs("ul", { className: "divide-y divide-[var(--border)]", children: [
|
|
219
|
+
grantees.map((g) => {
|
|
220
|
+
const editable = !readOnly && !g.locked;
|
|
221
|
+
const changeable = editable && onRoleChange !== void 0 && choosable;
|
|
222
|
+
const key = `grantee:${g.id}`;
|
|
223
|
+
return /* @__PURE__ */ jsxs("li", { className: "space-y-1.5 py-2 first:pt-0 last:pb-0", children: [
|
|
224
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-x-3 gap-y-1.5", children: [
|
|
225
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 basis-40", children: [
|
|
226
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-1.5 text-sm font-medium text-[var(--text-primary)]", children: [
|
|
227
|
+
g.kind === "team" && /* @__PURE__ */ jsx(UsersRound, { className: "size-4 shrink-0", "aria-hidden": true }),
|
|
228
|
+
/* @__PURE__ */ jsx("span", { "data-private": true, className: "truncate", children: g.name }),
|
|
229
|
+
!changeable && /* @__PURE__ */ jsx(ShareRoleChip, { role: roleOf(g.role) })
|
|
230
|
+
] }),
|
|
231
|
+
(g.kind === "team" || g.email) && /* @__PURE__ */ jsx("div", { "data-private": true, className: "truncate text-xs text-[var(--text-muted)]", children: g.kind === "team" ? labels.team : g.email })
|
|
232
|
+
] }),
|
|
233
|
+
(changeable || editable && onRemove) && /* @__PURE__ */ jsxs("div", { className: "ms-auto flex shrink-0 items-center gap-1", children: [
|
|
234
|
+
changeable && /* @__PURE__ */ jsx(LockedRoleChoice, { reason: lock.locked ? lock.reason : void 0, children: /* @__PURE__ */ jsx(
|
|
235
|
+
ToggleGroup,
|
|
236
|
+
{
|
|
237
|
+
size: "sm",
|
|
238
|
+
"aria-label": labels.roleOf(g.name),
|
|
239
|
+
options: roles.map((r) => ({ value: r.key, label: r.label })),
|
|
240
|
+
value: g.role,
|
|
241
|
+
disabled: busy !== null || lock.locked,
|
|
242
|
+
onChange: (next) => {
|
|
243
|
+
if (next !== g.role) void run(`role:${g.id}`, () => onRoleChange(g, next));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
) }),
|
|
247
|
+
editable && onRemove && /* @__PURE__ */ jsx(
|
|
248
|
+
IconButton,
|
|
249
|
+
{
|
|
250
|
+
tone: "danger",
|
|
251
|
+
size: "xs",
|
|
252
|
+
commit: true,
|
|
253
|
+
label: labels.remove,
|
|
254
|
+
pending: busy === key,
|
|
255
|
+
disabled: busy !== null,
|
|
256
|
+
onClick: async () => {
|
|
257
|
+
const yes = await confirm({
|
|
258
|
+
title: labels.removeConfirm(g.name),
|
|
259
|
+
confirmLabel: labels.remove,
|
|
260
|
+
tone: "danger"
|
|
261
|
+
});
|
|
262
|
+
if (yes) await run(key, () => onRemove(g));
|
|
263
|
+
},
|
|
264
|
+
children: /* @__PURE__ */ jsx(Trash2, {})
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
] })
|
|
268
|
+
] }),
|
|
269
|
+
g.extra
|
|
270
|
+
] }, key);
|
|
271
|
+
}),
|
|
272
|
+
pending.map((p) => {
|
|
273
|
+
const key = `pending:${p.id}`;
|
|
274
|
+
const name = p.email || labels.openInvite;
|
|
275
|
+
return /* @__PURE__ */ jsx("li", { className: "py-2 first:pt-0 last:pb-0", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-x-3 gap-y-1.5", children: [
|
|
276
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 basis-40", children: [
|
|
277
|
+
/* @__PURE__ */ jsx(
|
|
278
|
+
"div",
|
|
279
|
+
{
|
|
280
|
+
"data-private": p.email ? true : void 0,
|
|
281
|
+
className: cn(
|
|
282
|
+
"truncate text-sm",
|
|
283
|
+
p.email ? "text-[var(--text-primary)]" : "text-[var(--text-muted)]"
|
|
284
|
+
),
|
|
285
|
+
children: name
|
|
286
|
+
}
|
|
287
|
+
),
|
|
288
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-0.5 flex flex-wrap items-center gap-1", children: [
|
|
289
|
+
/* @__PURE__ */ jsx(Chip, { size: "sm", shape: "square", tone: "warning", caps: true, children: labels.pending }),
|
|
290
|
+
/* @__PURE__ */ jsx(ShareRoleChip, { role: roleOf(p.role) })
|
|
291
|
+
] })
|
|
292
|
+
] }),
|
|
293
|
+
(p.link || !readOnly && onRevokePending) && /* @__PURE__ */ jsxs("div", { className: "ms-auto flex shrink-0 items-center gap-1", children: [
|
|
294
|
+
p.link && /* @__PURE__ */ jsx(CopyButton, { size: "xs", tone: "muted", text: p.link, label: labels.copyLink }),
|
|
295
|
+
!readOnly && onRevokePending && /* @__PURE__ */ jsx(
|
|
296
|
+
IconButton,
|
|
297
|
+
{
|
|
298
|
+
tone: "danger",
|
|
299
|
+
size: "xs",
|
|
300
|
+
commit: true,
|
|
301
|
+
label: labels.revokePending,
|
|
302
|
+
pending: busy === key,
|
|
303
|
+
disabled: busy !== null,
|
|
304
|
+
onClick: async () => {
|
|
305
|
+
const yes = await confirm({
|
|
306
|
+
title: labels.revokePendingConfirm(name),
|
|
307
|
+
confirmLabel: labels.revokePending,
|
|
308
|
+
tone: "danger"
|
|
309
|
+
});
|
|
310
|
+
if (yes) await run(key, () => onRevokePending(p));
|
|
311
|
+
},
|
|
312
|
+
children: /* @__PURE__ */ jsx(Trash2, {})
|
|
313
|
+
}
|
|
314
|
+
)
|
|
315
|
+
] })
|
|
316
|
+
] }) }, key);
|
|
317
|
+
})
|
|
318
|
+
] })
|
|
319
|
+
] })
|
|
320
|
+
] });
|
|
321
|
+
}
|
|
322
|
+
function ShareCard({ title, variant = "outline", className, ...panel }) {
|
|
323
|
+
return /* @__PURE__ */ jsxs(Card, { variant, padding: "sm", className: cn("space-y-3", className), children: [
|
|
324
|
+
title && /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-[var(--text-primary)]", children: title }),
|
|
325
|
+
/* @__PURE__ */ jsx(SharePanel, { ...panel })
|
|
326
|
+
] });
|
|
327
|
+
}
|
|
328
|
+
function ShareDialog({ open, onClose, size, className, title, description, ...panel }) {
|
|
329
|
+
const labels = useKitLabels("shareCard", DEFAULT_SHARE_CARD_LABELS, panel.labels);
|
|
330
|
+
return /* @__PURE__ */ jsx(
|
|
331
|
+
DialogFrame,
|
|
332
|
+
{
|
|
333
|
+
open,
|
|
334
|
+
onClose,
|
|
335
|
+
size,
|
|
336
|
+
className,
|
|
337
|
+
title: title ?? labels.dialogTitle,
|
|
338
|
+
description,
|
|
339
|
+
actions: (close) => /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: close, children: labels.close }),
|
|
340
|
+
children: /* @__PURE__ */ jsx(SharePanel, { ...panel })
|
|
341
|
+
}
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
export {
|
|
345
|
+
DEFAULT_SHARE_CARD_LABELS,
|
|
346
|
+
ShareCard,
|
|
347
|
+
ShareDialog,
|
|
348
|
+
SharePanel
|
|
349
|
+
};
|
|
350
|
+
//# sourceMappingURL=share-card.js.map
|