@lt-three/love3 0.0.0 → 0.1.1
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 +85 -1
- package/dist/native/analytics/animation.d.ts +4 -0
- package/dist/native/analytics/animation.js +6 -0
- package/dist/native/analytics/chart.types.d.ts +25 -0
- package/dist/native/analytics/chart.types.js +0 -0
- package/dist/native/analytics/line-chart.d.ts +4 -0
- package/dist/native/analytics/line-chart.ios.d.ts +4 -0
- package/dist/native/analytics/line-chart.ios.js +24 -0
- package/dist/native/analytics/line-chart.js +33 -0
- package/dist/native/analytics/metric-card.d.ts +10 -0
- package/dist/native/analytics/metric-card.js +29 -0
- package/dist/native/analytics/multi-line-chart.d.ts +18 -0
- package/dist/native/analytics/multi-line-chart.js +216 -0
- package/dist/native/analytics/pie-chart.d.ts +15 -0
- package/dist/native/analytics/pie-chart.ios.d.ts +4 -0
- package/dist/native/analytics/pie-chart.ios.js +24 -0
- package/dist/native/analytics/pie-chart.js +92 -0
- package/dist/native/analytics/single-number.d.ts +19 -0
- package/dist/native/analytics/single-number.js +101 -0
- package/dist/native/atom/avatar.d.ts +21 -0
- package/dist/native/atom/avatar.js +46 -0
- package/dist/native/atom/badge.d.ts +28 -0
- package/dist/native/atom/badge.js +51 -0
- package/dist/native/atom/button.d.ts +46 -0
- package/dist/native/atom/button.js +109 -0
- package/dist/native/atom/checkbox.d.ts +21 -0
- package/dist/native/atom/checkbox.js +47 -0
- package/dist/native/atom/colored-value.d.ts +12 -0
- package/dist/native/atom/colored-value.js +24 -0
- package/dist/native/atom/image.d.ts +21 -0
- package/dist/native/atom/image.js +72 -0
- package/dist/native/atom/label.d.ts +18 -0
- package/dist/native/atom/label.js +33 -0
- package/dist/native/atom/link.d.ts +18 -0
- package/dist/native/atom/link.js +25 -0
- package/dist/native/atom/readout.d.ts +22 -0
- package/dist/native/atom/readout.js +39 -0
- package/dist/native/atom/search-input.d.ts +12 -0
- package/dist/native/atom/search-input.js +36 -0
- package/dist/native/atom/select.d.ts +54 -0
- package/dist/native/atom/select.js +200 -0
- package/dist/native/atom/separator.d.ts +12 -0
- package/dist/native/atom/separator.js +16 -0
- package/dist/native/atom/skeleton.d.ts +12 -0
- package/dist/native/atom/skeleton.js +39 -0
- package/dist/native/atom/slider.d.ts +32 -0
- package/dist/native/atom/slider.js +75 -0
- package/dist/native/atom/spinner.d.ts +15 -0
- package/dist/native/atom/spinner.js +25 -0
- package/dist/native/atom/switch.d.ts +18 -0
- package/dist/native/atom/switch.js +52 -0
- package/dist/native/atom/symbol.d.ts +16 -0
- package/dist/native/atom/symbol.js +38 -0
- package/dist/native/atom/symbol.types.d.ts +25 -0
- package/dist/native/atom/symbol.types.js +49 -0
- package/dist/native/atom/text-field.d.ts +49 -0
- package/dist/native/atom/text-field.js +56 -0
- package/dist/native/atom/text.d.ts +2 -0
- package/dist/native/atom/text.js +3 -0
- package/dist/native/atom/theme-toggle.d.ts +21 -0
- package/dist/native/atom/theme-toggle.js +36 -0
- package/dist/native/atom/timezone-select.d.ts +16 -0
- package/dist/native/atom/timezone-select.js +28 -0
- package/dist/native/atom/typography.d.ts +13 -0
- package/dist/native/atom/typography.js +28 -0
- package/dist/native/base/button.d.ts +61 -0
- package/dist/native/base/button.js +92 -0
- package/dist/native/base/form.d.ts +72 -0
- package/dist/native/base/form.js +113 -0
- package/dist/native/base/glass-card.d.ts +15 -0
- package/dist/native/base/glass-card.js +38 -0
- package/dist/native/base/input.d.ts +29 -0
- package/dist/native/base/input.js +27 -0
- package/dist/native/base/sheet.d.ts +71 -0
- package/dist/native/base/sheet.js +187 -0
- package/dist/native/base/text.d.ts +14 -0
- package/dist/native/base/text.js +53 -0
- package/dist/native/form/checkbox.d.ts +13 -0
- package/dist/native/form/checkbox.js +55 -0
- package/dist/native/form/date-picker.d.ts +23 -0
- package/dist/native/form/date-picker.js +119 -0
- package/dist/native/form/form.d.ts +22 -0
- package/dist/native/form/form.js +44 -0
- package/dist/native/form/radio-group.d.ts +23 -0
- package/dist/native/form/radio-group.js +88 -0
- package/dist/native/form/select.d.ts +13 -0
- package/dist/native/form/select.js +45 -0
- package/dist/native/form/slider.d.ts +14 -0
- package/dist/native/form/slider.js +42 -0
- package/dist/native/form/switch.d.ts +9 -0
- package/dist/native/form/switch.js +59 -0
- package/dist/native/form/text-area.d.ts +11 -0
- package/dist/native/form/text-area.js +50 -0
- package/dist/native/form/text-input.d.ts +18 -0
- package/dist/native/form/text-input.js +90 -0
- package/dist/native/index.d.ts +1 -0
- package/dist/native/index.js +0 -0
- package/dist/native/layout/accordion.d.ts +25 -0
- package/dist/native/layout/accordion.js +54 -0
- package/dist/native/layout/card.d.ts +47 -0
- package/dist/native/layout/card.js +57 -0
- package/dist/native/layout/description.d.ts +16 -0
- package/dist/native/layout/description.js +32 -0
- package/dist/native/layout/error.d.ts +21 -0
- package/dist/native/layout/error.js +44 -0
- package/dist/native/layout/information.d.ts +25 -0
- package/dist/native/layout/information.js +35 -0
- package/dist/native/layout/locked.d.ts +38 -0
- package/dist/native/layout/locked.js +94 -0
- package/dist/native/layout/modal.d.ts +25 -0
- package/dist/native/layout/modal.js +93 -0
- package/dist/native/layout/not-found.d.ts +17 -0
- package/dist/native/layout/not-found.js +30 -0
- package/dist/native/layout/page-frame.d.ts +23 -0
- package/dist/native/layout/page-frame.js +46 -0
- package/dist/native/layout/panel.d.ts +18 -0
- package/dist/native/layout/panel.js +23 -0
- package/dist/native/layout/reorderable-list.d.ts +42 -0
- package/dist/native/layout/reorderable-list.js +52 -0
- package/dist/native/layout/sheet.d.ts +30 -0
- package/dist/native/layout/sheet.js +46 -0
- package/dist/native/layout/simple-dialog.d.ts +16 -0
- package/dist/native/layout/simple-dialog.js +20 -0
- package/dist/native/layout/simple-table.d.ts +50 -0
- package/dist/native/layout/simple-table.js +75 -0
- package/dist/native/layout/tab-bar.d.ts +33 -0
- package/dist/native/layout/tab-bar.js +48 -0
- package/dist/native/layout/tabs.d.ts +28 -0
- package/dist/native/layout/tabs.js +54 -0
- package/dist/native/layout/tuning-panel.d.ts +24 -0
- package/dist/native/layout/tuning-panel.js +246 -0
- package/dist/native/lib/autocomplete.d.ts +7 -0
- package/dist/native/lib/autocomplete.js +34 -0
- package/dist/native/lib/breakpoints.d.ts +14 -0
- package/dist/native/lib/breakpoints.js +17 -0
- package/dist/native/lib/chart-palette.d.ts +8 -0
- package/dist/native/lib/chart-palette.js +20 -0
- package/dist/native/lib/confirm.d.ts +48 -0
- package/dist/native/lib/confirm.js +69 -0
- package/dist/native/lib/control.d.ts +24 -0
- package/dist/native/lib/control.js +0 -0
- package/dist/native/lib/external-store.d.ts +16 -0
- package/dist/native/lib/external-store.js +30 -0
- package/dist/native/lib/keyboard.d.ts +15 -0
- package/dist/native/lib/keyboard.js +24 -0
- package/dist/native/lib/labels.d.ts +15 -0
- package/dist/native/lib/labels.js +17 -0
- package/dist/native/lib/loading.d.ts +10 -0
- package/dist/native/lib/loading.js +15 -0
- package/dist/native/lib/network.d.ts +11 -0
- package/dist/native/lib/network.js +20 -0
- package/dist/native/lib/scheme.d.ts +18 -0
- package/dist/native/lib/scheme.js +22 -0
- package/dist/native/lib/snackbar.d.ts +45 -0
- package/dist/native/lib/snackbar.js +59 -0
- package/dist/native/lib/theme.d.ts +34 -0
- package/dist/native/lib/theme.js +53 -0
- package/dist/native/lib/timezone.d.ts +26 -0
- package/dist/native/lib/timezone.js +95 -0
- package/dist/native/lib/token-color.d.ts +5 -0
- package/dist/native/lib/token-color.js +13 -0
- package/dist/native/lib/token-color.web.d.ts +4 -0
- package/dist/native/lib/token-color.web.js +7 -0
- package/dist/native/lib/tuning-context.d.ts +9 -0
- package/dist/native/lib/tuning-context.js +7 -0
- package/dist/native/lib/tuning.d.ts +24 -0
- package/dist/native/lib/tuning.js +42 -0
- package/dist/native/lib/typography.d.ts +10 -0
- package/dist/native/lib/typography.js +11 -0
- package/dist/native/lib/utils.d.ts +11 -0
- package/dist/native/lib/utils.js +21 -0
- package/dist/native/once/confirm.d.ts +7 -0
- package/dist/native/once/confirm.js +60 -0
- package/dist/native/once/error-boundary.d.ts +28 -0
- package/dist/native/once/error-boundary.js +55 -0
- package/dist/native/once/loading-lock.d.ts +8 -0
- package/dist/native/once/loading-lock.js +28 -0
- package/dist/native/once/offline-banner.d.ts +15 -0
- package/dist/native/once/offline-banner.js +35 -0
- package/dist/native/once/snackbar.d.ts +17 -0
- package/dist/native/once/snackbar.js +106 -0
- package/dist/native/styles.css +46 -0
- package/dist/shared/analytics.d.ts +71 -0
- package/dist/shared/analytics.js +0 -0
- package/dist/shared/button.d.ts +7 -0
- package/dist/shared/button.js +23 -0
- package/dist/shared/form.d.ts +45 -0
- package/dist/shared/form.js +46 -0
- package/dist/shared/index.d.ts +3 -0
- package/dist/shared/index.js +3 -0
- package/dist/tokens/contrast-pairs.d.ts +30 -0
- package/dist/tokens/contrast-pairs.js +404 -0
- package/dist/tokens/index.d.ts +6 -0
- package/dist/tokens/index.js +10 -0
- package/dist/tokens/styles.gen.css +250 -0
- package/dist/tokens/tokens.gen.d.ts +141 -0
- package/dist/tokens/tokens.gen.js +206 -0
- package/dist/tuning/catalog.d.ts +27 -0
- package/dist/tuning/catalog.gen.d.ts +4 -0
- package/dist/tuning/catalog.gen.js +397 -0
- package/dist/tuning/catalog.js +128 -0
- package/dist/tuning/color.d.ts +20 -0
- package/dist/tuning/color.js +80 -0
- package/dist/tuning/css.d.ts +35 -0
- package/dist/tuning/css.js +147 -0
- package/dist/tuning/index.d.ts +8 -0
- package/dist/tuning/index.js +9 -0
- package/dist/tuning/model.d.ts +33 -0
- package/dist/tuning/model.js +154 -0
- package/dist/tuning/native.d.ts +35 -0
- package/dist/tuning/native.js +80 -0
- package/dist/tuning/schema.d.ts +69 -0
- package/dist/tuning/schema.js +247 -0
- package/dist/tuning/types.d.ts +75 -0
- package/dist/tuning/types.js +39 -0
- package/dist/web/analytics/line-chart.d.ts +20 -0
- package/dist/web/analytics/line-chart.js +28 -0
- package/dist/web/analytics/metric-card.d.ts +18 -0
- package/dist/web/analytics/metric-card.js +40 -0
- package/dist/web/analytics/multi-line-chart.d.ts +39 -0
- package/dist/web/analytics/multi-line-chart.js +345 -0
- package/dist/web/atom/avatar.d.ts +11 -0
- package/dist/web/atom/avatar.js +24 -0
- package/dist/web/atom/badge.d.ts +2 -0
- package/dist/web/atom/badge.js +3 -0
- package/dist/web/atom/button.d.ts +23 -0
- package/dist/web/atom/button.js +35 -0
- package/dist/web/atom/checkbox.d.ts +19 -0
- package/dist/web/atom/checkbox.js +33 -0
- package/dist/web/atom/colored-value.d.ts +13 -0
- package/dist/web/atom/colored-value.js +24 -0
- package/dist/web/atom/help.d.ts +10 -0
- package/dist/web/atom/help.js +18 -0
- package/dist/web/atom/label.d.ts +2 -0
- package/dist/web/atom/label.js +3 -0
- package/dist/web/atom/segmented-control.d.ts +39 -0
- package/dist/web/atom/segmented-control.js +42 -0
- package/dist/web/atom/select.d.ts +43 -0
- package/dist/web/atom/select.js +93 -0
- package/dist/web/atom/separator.d.ts +2 -0
- package/dist/web/atom/separator.js +3 -0
- package/dist/web/atom/skeleton.d.ts +2 -0
- package/dist/web/atom/skeleton.js +3 -0
- package/dist/web/atom/slider.d.ts +33 -0
- package/dist/web/atom/slider.js +70 -0
- package/dist/web/atom/spinner.d.ts +8 -0
- package/dist/web/atom/spinner.js +14 -0
- package/dist/web/atom/switch.d.ts +11 -0
- package/dist/web/atom/switch.js +10 -0
- package/dist/web/atom/text-area.d.ts +23 -0
- package/dist/web/atom/text-area.js +27 -0
- package/dist/web/atom/text-field.d.ts +18 -0
- package/dist/web/atom/text-field.js +22 -0
- package/dist/web/atom/toggle-chip.d.ts +22 -0
- package/dist/web/atom/toggle-chip.js +28 -0
- package/dist/web/atom/tooltip.d.ts +23 -0
- package/dist/web/atom/tooltip.js +26 -0
- package/dist/web/atom/typography.d.ts +6 -0
- package/dist/web/atom/typography.js +23 -0
- package/dist/web/base/accordion.d.ts +9 -0
- package/dist/web/base/accordion.js +44 -0
- package/dist/web/base/alert.d.ts +11 -0
- package/dist/web/base/alert.js +37 -0
- package/dist/web/base/avatar.d.ts +8 -0
- package/dist/web/base/avatar.js +29 -0
- package/dist/web/base/badge.d.ts +12 -0
- package/dist/web/base/badge.js +26 -0
- package/dist/web/base/breadcrumb.d.ts +16 -0
- package/dist/web/base/breadcrumb.js +72 -0
- package/dist/web/base/button.d.ts +12 -0
- package/dist/web/base/button.js +47 -0
- package/dist/web/base/card.d.ts +19 -0
- package/dist/web/base/card.js +74 -0
- package/dist/web/base/checkbox.d.ts +6 -0
- package/dist/web/base/checkbox.js +21 -0
- package/dist/web/base/dialog.d.ts +20 -0
- package/dist/web/base/dialog.js +92 -0
- package/dist/web/base/dropdown-menu.d.ts +29 -0
- package/dist/web/base/dropdown-menu.js +125 -0
- package/dist/web/base/field.d.ts +27 -0
- package/dist/web/base/field.js +118 -0
- package/dist/web/base/form.d.ts +38 -0
- package/dist/web/base/form.js +110 -0
- package/dist/web/base/input.d.ts +9 -0
- package/dist/web/base/input.js +23 -0
- package/dist/web/base/label.d.ts +6 -0
- package/dist/web/base/label.js +15 -0
- package/dist/web/base/pagination.d.ts +34 -0
- package/dist/web/base/pagination.js +90 -0
- package/dist/web/base/popover.d.ts +11 -0
- package/dist/web/base/popover.js +37 -0
- package/dist/web/base/radio-group.d.ts +7 -0
- package/dist/web/base/radio-group.js +27 -0
- package/dist/web/base/scroll-area.d.ts +10 -0
- package/dist/web/base/scroll-area.js +41 -0
- package/dist/web/base/select.d.ts +17 -0
- package/dist/web/base/select.js +96 -0
- package/dist/web/base/separator.d.ts +6 -0
- package/dist/web/base/separator.js +17 -0
- package/dist/web/base/sheet.d.ts +19 -0
- package/dist/web/base/sheet.js +88 -0
- package/dist/web/base/skeleton.d.ts +5 -0
- package/dist/web/base/skeleton.js +14 -0
- package/dist/web/base/slider.d.ts +9 -0
- package/dist/web/base/slider.js +39 -0
- package/dist/web/base/sonner.d.ts +9 -0
- package/dist/web/base/sonner.js +25 -0
- package/dist/web/base/spinner.d.ts +5 -0
- package/dist/web/base/spinner.js +17 -0
- package/dist/web/base/switch.d.ts +6 -0
- package/dist/web/base/switch.js +19 -0
- package/dist/web/base/table.d.ts +14 -0
- package/dist/web/base/table.js +68 -0
- package/dist/web/base/tabs.d.ts +9 -0
- package/dist/web/base/tabs.js +36 -0
- package/dist/web/base/textarea.d.ts +9 -0
- package/dist/web/base/textarea.js +23 -0
- package/dist/web/base/tooltip.d.ts +9 -0
- package/dist/web/base/tooltip.js +36 -0
- package/dist/web/form/checkbox.d.ts +35 -0
- package/dist/web/form/checkbox.js +91 -0
- package/dist/web/form/radio-group.d.ts +24 -0
- package/dist/web/form/radio-group.js +75 -0
- package/dist/web/form/select.d.ts +16 -0
- package/dist/web/form/select.js +44 -0
- package/dist/web/form/slider.d.ts +19 -0
- package/dist/web/form/slider.js +51 -0
- package/dist/web/form/switch.d.ts +11 -0
- package/dist/web/form/switch.js +50 -0
- package/dist/web/form/text-area.d.ts +10 -0
- package/dist/web/form/text-area.js +31 -0
- package/dist/web/form/text-input.d.ts +10 -0
- package/dist/web/form/text-input.js +42 -0
- package/dist/web/index.d.ts +1 -0
- package/dist/web/index.js +0 -0
- package/dist/web/layout/accordion.d.ts +26 -0
- package/dist/web/layout/accordion.js +29 -0
- package/dist/web/layout/alert-modal.d.ts +41 -0
- package/dist/web/layout/alert-modal.js +71 -0
- package/dist/web/layout/card.d.ts +17 -0
- package/dist/web/layout/card.js +35 -0
- package/dist/web/layout/description.d.ts +12 -0
- package/dist/web/layout/description.js +20 -0
- package/dist/web/layout/information.d.ts +36 -0
- package/dist/web/layout/information.js +53 -0
- package/dist/web/layout/modal.d.ts +16 -0
- package/dist/web/layout/modal.js +37 -0
- package/dist/web/layout/page-frame.d.ts +37 -0
- package/dist/web/layout/page-frame.js +79 -0
- package/dist/web/layout/scroll-area.d.ts +10 -0
- package/dist/web/layout/scroll-area.js +13 -0
- package/dist/web/layout/sheet.d.ts +32 -0
- package/dist/web/layout/sheet.js +68 -0
- package/dist/web/layout/simple-dialog.d.ts +11 -0
- package/dist/web/layout/simple-dialog.js +24 -0
- package/dist/web/layout/simple-table.d.ts +49 -0
- package/dist/web/layout/simple-table.js +58 -0
- package/dist/web/layout/tabs.d.ts +26 -0
- package/dist/web/layout/tabs.js +42 -0
- package/dist/web/layout/titled-modal.d.ts +32 -0
- package/dist/web/layout/titled-modal.js +58 -0
- package/dist/web/lib/css-vars.d.ts +14 -0
- package/dist/web/lib/css-vars.js +18 -0
- package/dist/web/lib/dialog.d.ts +13 -0
- package/dist/web/lib/dialog.js +0 -0
- package/dist/web/lib/form.d.ts +2 -0
- package/dist/web/lib/form.js +3 -0
- package/dist/web/lib/labels.d.ts +27 -0
- package/dist/web/lib/labels.js +29 -0
- package/dist/web/lib/modal-open-focus.d.ts +17 -0
- package/dist/web/lib/modal-open-focus.js +44 -0
- package/dist/web/lib/restore-focus.d.ts +12 -0
- package/dist/web/lib/restore-focus.js +32 -0
- package/dist/web/lib/utils.d.ts +4 -0
- package/dist/web/lib/utils.js +10 -0
- package/dist/web/styles.css +162 -0
- package/package.json +203 -4
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Button } from "../base/button.js";
|
|
2
|
+
import { Dialog, DialogContent, DialogDescription, DialogTitle } from "../base/dialog.js";
|
|
3
|
+
import { useModalOpenAutoFocus } from "../lib/modal-open-focus.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { TriangleAlertIcon } from "lucide-react";
|
|
6
|
+
|
|
7
|
+
//#region src/web/layout/alert-modal.tsx
|
|
8
|
+
/**
|
|
9
|
+
* A small modal for confirmation (it has no ×).
|
|
10
|
+
*
|
|
11
|
+
* Overlay surface, p-5, width 400 (fitted to the viewport). A heading (16/24 semibold) and body text (13/20, muted), with right-aligned actions (gap-2, the default Button size).
|
|
12
|
+
* With `danger`, a small state-error icon is added to the left of the heading and the primary action gets the destructive-solid fill.
|
|
13
|
+
* No border and no ring (it floats on the shadow alone, like `DialogContent`). The caller holds the open state (controlled only).
|
|
14
|
+
*
|
|
15
|
+
* While shown it carries `data-modal-open`, so floating persistent UI can be hidden with CSS.
|
|
16
|
+
*
|
|
17
|
+
* The initial focus on open goes to the first action only when it was opened by keyboard, and otherwise to the modal body
|
|
18
|
+
* (so that no ring appears on the first button when opened with the mouse; `useModalOpenAutoFocus`).
|
|
19
|
+
*/
|
|
20
|
+
function AlertModal({ open, onOpenChange, tone = "default", title, description, actions, dismissible = true, "data-testid": testId }) {
|
|
21
|
+
const danger = tone === "danger";
|
|
22
|
+
const lastIndex = actions.length - 1;
|
|
23
|
+
const { contentRef, onOpenAutoFocus } = useModalOpenAutoFocus();
|
|
24
|
+
return /* @__PURE__ */ jsx(Dialog, {
|
|
25
|
+
open,
|
|
26
|
+
onOpenChange,
|
|
27
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
28
|
+
ref: contentRef,
|
|
29
|
+
onOpenAutoFocus,
|
|
30
|
+
showCloseButton: false,
|
|
31
|
+
"data-modal-open": "",
|
|
32
|
+
"data-testid": testId,
|
|
33
|
+
onInteractOutside: (e) => {
|
|
34
|
+
if (!dismissible) e.preventDefault();
|
|
35
|
+
},
|
|
36
|
+
onEscapeKeyDown: (e) => {
|
|
37
|
+
if (!dismissible) e.preventDefault();
|
|
38
|
+
},
|
|
39
|
+
className: "flex w-[400px] max-w-[calc(100%-2rem)] flex-col gap-4 outline-none sm:max-w-[400px]",
|
|
40
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
41
|
+
className: "flex flex-col gap-1.5",
|
|
42
|
+
children: [/* @__PURE__ */ jsxs(DialogTitle, {
|
|
43
|
+
className: "flex items-center gap-2 text-base leading-6 font-semibold",
|
|
44
|
+
children: [danger && /* @__PURE__ */ jsx(TriangleAlertIcon, {
|
|
45
|
+
className: "size-4 shrink-0 text-state-error",
|
|
46
|
+
"aria-hidden": true
|
|
47
|
+
}), title]
|
|
48
|
+
}), description && /* @__PURE__ */ jsx(DialogDescription, {
|
|
49
|
+
className: "text-[13px] leading-5 whitespace-pre-line text-muted-foreground",
|
|
50
|
+
children: description
|
|
51
|
+
})]
|
|
52
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
53
|
+
className: "flex items-center justify-end gap-2",
|
|
54
|
+
children: actions.map((action, i) => {
|
|
55
|
+
const primary = (action.emphasis ?? (i === lastIndex ? "primary" : "secondary")) === "primary";
|
|
56
|
+
return /* @__PURE__ */ jsx(Button, {
|
|
57
|
+
type: "button",
|
|
58
|
+
variant: primary ? danger ? "destructive" : "default" : "outline",
|
|
59
|
+
disabled: action.disabled,
|
|
60
|
+
"data-testid": action["data-testid"],
|
|
61
|
+
onClick: action.onClick,
|
|
62
|
+
children: action.label
|
|
63
|
+
}, action.label);
|
|
64
|
+
})
|
|
65
|
+
})]
|
|
66
|
+
})
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
export { AlertModal };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Card as Card$1, CardHeadingLevel } from "../base/card.js";
|
|
2
|
+
import React from "react";
|
|
3
|
+
//#region src/web/layout/card.d.ts
|
|
4
|
+
export type CardProps = {
|
|
5
|
+
title?: React.ReactNode;
|
|
6
|
+
/** Make the title a heading (`<h2>` to `<h6>`). Pass it when you want it in the heading hierarchy (omitted means `<div>`). Native has the same name. */
|
|
7
|
+
headingLevel?: CardHeadingLevel;
|
|
8
|
+
description?: React.ReactNode;
|
|
9
|
+
action?: React.ReactNode;
|
|
10
|
+
actionOnClick?: () => void;
|
|
11
|
+
content: React.ReactNode;
|
|
12
|
+
footer?: React.ReactNode;
|
|
13
|
+
shadow?: boolean;
|
|
14
|
+
contentClassName?: string;
|
|
15
|
+
} & Omit<React.ComponentProps<typeof Card$1>, "content" | "title">;
|
|
16
|
+
export declare function Card({ title, headingLevel, description, action, shadow, className, actionOnClick, footer, content, contentClassName, ...props }: CardProps): React.JSX.Element;
|
|
17
|
+
//#endregion
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Card as Card$1, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "../base/card.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
|
|
5
|
+
//#region src/web/layout/card.tsx
|
|
6
|
+
function Card({ title, headingLevel, description, action, shadow = true, className, actionOnClick, footer, content, contentClassName, ...props }) {
|
|
7
|
+
return /* @__PURE__ */ jsxs(Card$1, {
|
|
8
|
+
className: cn("gap-2", !shadow && "shadow-none", className),
|
|
9
|
+
...props,
|
|
10
|
+
children: [
|
|
11
|
+
(title || action || description) && /* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
12
|
+
title && /* @__PURE__ */ jsx(CardTitle, {
|
|
13
|
+
headingLevel,
|
|
14
|
+
children: title
|
|
15
|
+
}),
|
|
16
|
+
description && /* @__PURE__ */ jsx(CardDescription, { children: description }),
|
|
17
|
+
/* @__PURE__ */ jsx(CardAction, {
|
|
18
|
+
onClick: actionOnClick,
|
|
19
|
+
children: action
|
|
20
|
+
})
|
|
21
|
+
] }),
|
|
22
|
+
/* @__PURE__ */ jsx(CardContent, {
|
|
23
|
+
className: cn("grow flex flex-col gap-4", contentClassName),
|
|
24
|
+
children: content
|
|
25
|
+
}),
|
|
26
|
+
footer && /* @__PURE__ */ jsx(CardFooter, {
|
|
27
|
+
className: "flex justify-end gap-4 mt-2",
|
|
28
|
+
children: footer
|
|
29
|
+
})
|
|
30
|
+
]
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { Card };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
//#region src/web/layout/description.d.ts
|
|
3
|
+
type DescriptionProps = {
|
|
4
|
+
sections: {
|
|
5
|
+
title: string;
|
|
6
|
+
titleIcon?: React.ReactNode;
|
|
7
|
+
description: React.ReactNode;
|
|
8
|
+
}[];
|
|
9
|
+
};
|
|
10
|
+
export declare function Description(props: DescriptionProps): React.JSX.Element;
|
|
11
|
+
//#endregion
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Separator } from "../base/separator.js";
|
|
2
|
+
import { Fragment } from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
|
|
5
|
+
//#region src/web/layout/description.tsx
|
|
6
|
+
function Description(props) {
|
|
7
|
+
return /* @__PURE__ */ jsx("div", {
|
|
8
|
+
className: "flex flex-col gap-8 mx-auto",
|
|
9
|
+
children: props.sections.map((section, index) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("h2", {
|
|
10
|
+
className: "flex items-center gap-2 font-bold mb-2",
|
|
11
|
+
children: [section.titleIcon, section.title]
|
|
12
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
13
|
+
className: "flex flex-col gap-4 whitespace-pre-wrap",
|
|
14
|
+
children: section.description
|
|
15
|
+
})] }), index < props.sections.length - 1 && /* @__PURE__ */ jsx(Separator, {})] }, section.title))
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
export { Description };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
//#region src/web/layout/information.d.ts
|
|
3
|
+
export type InformationField = {
|
|
4
|
+
label: string;
|
|
5
|
+
value: React.ReactNode;
|
|
6
|
+
separator?: never;
|
|
7
|
+
} | {
|
|
8
|
+
label?: never;
|
|
9
|
+
value?: never;
|
|
10
|
+
separator: true;
|
|
11
|
+
};
|
|
12
|
+
type InformationProps = {
|
|
13
|
+
displayType?: "half" | "fitContent";
|
|
14
|
+
highlighted?: boolean;
|
|
15
|
+
fields: InformationField[][];
|
|
16
|
+
wrap?: "no-wrap" | "pre-wrap";
|
|
17
|
+
/**
|
|
18
|
+
* The class of the inner element (a flex container) that lays out the columns. `className` goes on the outer container (`@container`),
|
|
19
|
+
* so use this one when changing the column spacing (`gap-*`) or direction (`flex-*`).
|
|
20
|
+
*/
|
|
21
|
+
columnsClassName?: string;
|
|
22
|
+
} & React.HTMLAttributes<HTMLDivElement>;
|
|
23
|
+
/**
|
|
24
|
+
* A read-only detail view that lays out pairs of a label and a value.
|
|
25
|
+
*
|
|
26
|
+
* **It assumes the parent has a width.** Whether columns stack vertically or sit side by side is decided by the outer element's container query (`@container`, `@xl:`).
|
|
27
|
+
* A container query cannot measure the outer width from the content (inline-size containment), so inside a **parent whose width is determined by its content**
|
|
28
|
+
* (a `flex` child, `inline-block`, `inline-flex`, a table cell, `grid-cols-[auto_…]`) it collapses to width 0.
|
|
29
|
+
* In such parents, give `className` a concrete width (such as `w-96`; `flex-1` also works for a `flex` child).
|
|
30
|
+
* `w-full` does not work (the parent's width is decided by the content, so there is no basis for the percentage).
|
|
31
|
+
*
|
|
32
|
+
* `className` and the remaining attributes go on the **outer container**.
|
|
33
|
+
*/
|
|
34
|
+
export declare const Information: ({ displayType, highlighted, fields, className, columnsClassName, wrap, ...remain }: InformationProps) => React.JSX.Element;
|
|
35
|
+
//#endregion
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Separator } from "../base/separator.js";
|
|
3
|
+
import { Fragment } from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/web/layout/information.tsx
|
|
7
|
+
/**
|
|
8
|
+
* A read-only detail view that lays out pairs of a label and a value.
|
|
9
|
+
*
|
|
10
|
+
* **It assumes the parent has a width.** Whether columns stack vertically or sit side by side is decided by the outer element's container query (`@container`, `@xl:`).
|
|
11
|
+
* A container query cannot measure the outer width from the content (inline-size containment), so inside a **parent whose width is determined by its content**
|
|
12
|
+
* (a `flex` child, `inline-block`, `inline-flex`, a table cell, `grid-cols-[auto_…]`) it collapses to width 0.
|
|
13
|
+
* In such parents, give `className` a concrete width (such as `w-96`; `flex-1` also works for a `flex` child).
|
|
14
|
+
* `w-full` does not work (the parent's width is decided by the content, so there is no basis for the percentage).
|
|
15
|
+
*
|
|
16
|
+
* `className` and the remaining attributes go on the **outer container**.
|
|
17
|
+
*/
|
|
18
|
+
const Information = ({ displayType = "fitContent", highlighted, fields, className, columnsClassName, wrap = "pre-wrap", ...remain }) => {
|
|
19
|
+
return /* @__PURE__ */ jsx("div", {
|
|
20
|
+
"data-slot": "information",
|
|
21
|
+
className: cn("@container", className),
|
|
22
|
+
...remain,
|
|
23
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
24
|
+
"data-slot": "information-columns",
|
|
25
|
+
className: cn("flex flex-col @xl:flex-row gap-2 @xl:gap-4", columnsClassName),
|
|
26
|
+
children: fields.map((innerFields, index) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
27
|
+
style: { gridTemplateRows: `repeat(${innerFields.length}, min-content)` },
|
|
28
|
+
className: cn("flex-[1] grid gap-y-3 gap-x-2", displayType === "fitContent" ? "grid-cols-[min-content_min-content_1fr]" : "grid-cols-[minmax(max-content,100px)_min-content_2fr]", highlighted && "gap-x-4"),
|
|
29
|
+
children: innerFields.map(({ label, value, separator }, innerIndex) => separator ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
30
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "horizontal" }),
|
|
31
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "horizontal" }),
|
|
32
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "horizontal" })
|
|
33
|
+
] }, `${index}-${innerIndex.toString()}-separator`) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
34
|
+
/* @__PURE__ */ jsx("div", {
|
|
35
|
+
className: cn("self-center text-xs text-muted-foreground font-semibold whitespace-nowrap underline decoration-border underline-offset-4"),
|
|
36
|
+
children: label
|
|
37
|
+
}),
|
|
38
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical" }),
|
|
39
|
+
/* @__PURE__ */ jsx("div", {
|
|
40
|
+
className: cn("flex justify-between items-center gap-2 text-sm min-h-7", wrap === "no-wrap" && "whitespace-nowrap", wrap === "pre-wrap" && "whitespace-pre-wrap", highlighted && "text-lg py-1"),
|
|
41
|
+
children: value
|
|
42
|
+
})
|
|
43
|
+
] }, label))
|
|
44
|
+
}), index < fields.length - 1 && /* @__PURE__ */ jsx(Separator, {
|
|
45
|
+
orientation: "vertical",
|
|
46
|
+
className: cn("hidden @xl:block")
|
|
47
|
+
})] }, `${innerFields[0]?.label}`))
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
export { Information };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DialogController } from "../lib/dialog.js";
|
|
2
|
+
import React from "react";
|
|
3
|
+
//#region src/web/layout/modal.d.ts
|
|
4
|
+
type Props = {
|
|
5
|
+
title: React.ReactNode;
|
|
6
|
+
description?: React.ReactNode;
|
|
7
|
+
dialog: DialogController;
|
|
8
|
+
content: React.ReactNode;
|
|
9
|
+
footer: React.ReactNode;
|
|
10
|
+
size?: "md" | "flexible";
|
|
11
|
+
/** Accessible name of the close button (defaults to the Japanese "Close" label) */
|
|
12
|
+
closeLabel?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function Modal({ title, description, dialog, content, footer, size, closeLabel }: Props): React.JSX.Element;
|
|
15
|
+
//#endregion
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../base/dialog.js";
|
|
3
|
+
import { ScrollArea } from "../base/scroll-area.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/web/layout/modal.tsx
|
|
7
|
+
function Modal({ title, description, dialog, content, footer, size, closeLabel }) {
|
|
8
|
+
return /* @__PURE__ */ jsx(Dialog, {
|
|
9
|
+
open: dialog.isOpen,
|
|
10
|
+
modal: true,
|
|
11
|
+
onOpenChange: (next) => !next && dialog.close(),
|
|
12
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
13
|
+
className: cn("max-h-3/4 flex flex-col", size === "flexible" && "!max-w-[80vw] min-w-lg w-max"),
|
|
14
|
+
onInteractOutside: (e) => {
|
|
15
|
+
e.preventDefault();
|
|
16
|
+
dialog.onOutsideClick();
|
|
17
|
+
},
|
|
18
|
+
closeLabel,
|
|
19
|
+
children: [
|
|
20
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: title }), description && /* @__PURE__ */ jsx(DialogDescription, { children: description })] }),
|
|
21
|
+
/* @__PURE__ */ jsx(ScrollArea, {
|
|
22
|
+
className: "flex-1 -mx-2",
|
|
23
|
+
viewPortClassName: "w-full",
|
|
24
|
+
innerViewPortClassName: "px-2",
|
|
25
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
26
|
+
className: "flex flex-col gap-4 wrap-break-word",
|
|
27
|
+
children: content
|
|
28
|
+
})
|
|
29
|
+
}),
|
|
30
|
+
/* @__PURE__ */ jsx(DialogFooter, { children: footer })
|
|
31
|
+
]
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
export { Modal };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
//#region src/web/layout/page-frame.d.ts
|
|
3
|
+
export type PageFrameNavItem = {
|
|
4
|
+
label: string;
|
|
5
|
+
/** The current screen. It gets `aria-current="page"`. */
|
|
6
|
+
current?: boolean;
|
|
7
|
+
/** A link (`<a>`) when present, otherwise a button (`<button>`; pressing it calls `onSelect`). */
|
|
8
|
+
href?: string;
|
|
9
|
+
onSelect?: () => void;
|
|
10
|
+
};
|
|
11
|
+
export type PageFrameProps = {
|
|
12
|
+
/** The brand at the left end of the header (text or an element). */
|
|
13
|
+
brand: React.ReactNode;
|
|
14
|
+
nav?: readonly PageFrameNavItem[];
|
|
15
|
+
/** Accessible name of the nav (to tell landmarks apart when there are several). */
|
|
16
|
+
navLabel?: string;
|
|
17
|
+
/** The right end of the header (theme toggle, user and so on). */
|
|
18
|
+
trailing?: React.ReactNode;
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
/** The content of the footer. When omitted, a copyright notice with no year (the year is decided by the consumer). */
|
|
21
|
+
footer?: React.ReactNode;
|
|
22
|
+
/** The maximum width of the header, body and footer content (a Tailwind class). */
|
|
23
|
+
maxWidthClassName?: string;
|
|
24
|
+
className?: string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The skeleton of a page. It has `header` (banner), `nav`, `main` and `footer` (contentinfo), so the landmarks are complete.
|
|
28
|
+
* Assembling each screen by hand leads to forgetting `main`, a nav with no name, and breaking at narrow widths, so it is placed here once.
|
|
29
|
+
*
|
|
30
|
+
* - The DOM order of the header (brand, nav, right end) matches the visual order (one row at a time at narrow widths). Swapping only the look with `order`
|
|
31
|
+
* would make the Tab order differ from the visual order
|
|
32
|
+
* - The body is `flex-1` (the footer sticks to the bottom even on a short screen). The `id` of `main` is `main` (the target a consumer can jump to when placing a skip link.
|
|
33
|
+
* PageFrame itself places no skip link. The `main` landmark satisfies axe's bypass (skipping blocks))
|
|
34
|
+
* - Colours are only `border-border` / `text-muted-foreground`. The tokens switch them for dark
|
|
35
|
+
*/
|
|
36
|
+
export declare function PageFrame({ brand, nav, navLabel, trailing, children, footer, maxWidthClassName, className }: PageFrameProps): React.JSX.Element;
|
|
37
|
+
//#endregion
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/web/layout/page-frame.tsx
|
|
5
|
+
/**
|
|
6
|
+
* The skeleton of a page. It has `header` (banner), `nav`, `main` and `footer` (contentinfo), so the landmarks are complete.
|
|
7
|
+
* Assembling each screen by hand leads to forgetting `main`, a nav with no name, and breaking at narrow widths, so it is placed here once.
|
|
8
|
+
*
|
|
9
|
+
* - The DOM order of the header (brand, nav, right end) matches the visual order (one row at a time at narrow widths). Swapping only the look with `order`
|
|
10
|
+
* would make the Tab order differ from the visual order
|
|
11
|
+
* - The body is `flex-1` (the footer sticks to the bottom even on a short screen). The `id` of `main` is `main` (the target a consumer can jump to when placing a skip link.
|
|
12
|
+
* PageFrame itself places no skip link. The `main` landmark satisfies axe's bypass (skipping blocks))
|
|
13
|
+
* - Colours are only `border-border` / `text-muted-foreground`. The tokens switch them for dark
|
|
14
|
+
*/
|
|
15
|
+
function PageFrame({ brand, nav = [], navLabel = "メイン", trailing, children, footer, maxWidthClassName = "max-w-[1280px]", className }) {
|
|
16
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
17
|
+
"data-slot": "page-frame",
|
|
18
|
+
className: cn("flex min-h-dvh flex-col", className),
|
|
19
|
+
children: [
|
|
20
|
+
/* @__PURE__ */ jsx("header", {
|
|
21
|
+
className: "border-border border-b",
|
|
22
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
23
|
+
className: cn("mx-auto flex w-full flex-wrap items-center gap-x-6 gap-y-2 px-4 py-3 sm:px-6", maxWidthClassName),
|
|
24
|
+
children: [
|
|
25
|
+
/* @__PURE__ */ jsx("p", {
|
|
26
|
+
className: "basis-full font-mono text-base font-semibold tracking-tight sm:basis-auto",
|
|
27
|
+
children: brand
|
|
28
|
+
}),
|
|
29
|
+
nav.length > 0 ? /* @__PURE__ */ jsx("nav", {
|
|
30
|
+
"aria-label": navLabel,
|
|
31
|
+
className: "min-w-0 basis-full sm:basis-0 sm:flex-1",
|
|
32
|
+
children: /* @__PURE__ */ jsx("ul", {
|
|
33
|
+
className: "flex flex-wrap items-center gap-x-4 gap-y-1",
|
|
34
|
+
children: nav.map((item) => {
|
|
35
|
+
const select = () => {
|
|
36
|
+
if (!item.current) item.onSelect?.();
|
|
37
|
+
};
|
|
38
|
+
const itemClass = cn("focus-visible:ring-ring cursor-pointer rounded-control py-1 text-sm underline-offset-8 outline-none hover:underline focus-visible:ring-2", item.current ? "text-foreground font-medium underline" : "text-muted-foreground");
|
|
39
|
+
return /* @__PURE__ */ jsx("li", { children: item.href !== void 0 ? /* @__PURE__ */ jsx("a", {
|
|
40
|
+
href: item.href,
|
|
41
|
+
"aria-current": item.current ? "page" : void 0,
|
|
42
|
+
onClick: select,
|
|
43
|
+
className: itemClass,
|
|
44
|
+
children: item.label
|
|
45
|
+
}) : /* @__PURE__ */ jsx("button", {
|
|
46
|
+
type: "button",
|
|
47
|
+
"aria-current": item.current ? "page" : void 0,
|
|
48
|
+
onClick: select,
|
|
49
|
+
className: itemClass,
|
|
50
|
+
children: item.label
|
|
51
|
+
}) }, item.label);
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
}) : null,
|
|
55
|
+
trailing ? /* @__PURE__ */ jsx("div", {
|
|
56
|
+
className: "ml-auto flex items-center gap-2",
|
|
57
|
+
children: trailing
|
|
58
|
+
}) : null
|
|
59
|
+
]
|
|
60
|
+
})
|
|
61
|
+
}),
|
|
62
|
+
/* @__PURE__ */ jsx("main", {
|
|
63
|
+
id: "main",
|
|
64
|
+
className: cn("mx-auto flex w-full flex-1 flex-col gap-6 px-4 py-6 sm:px-6", maxWidthClassName),
|
|
65
|
+
children
|
|
66
|
+
}),
|
|
67
|
+
/* @__PURE__ */ jsx("footer", {
|
|
68
|
+
className: "border-border text-muted-foreground border-t",
|
|
69
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
70
|
+
className: cn("mx-auto w-full px-4 py-4 text-xs sm:px-6", maxWidthClassName),
|
|
71
|
+
children: footer ?? /* @__PURE__ */ jsx("p", { children: "© <3(Less Than Three)" })
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
export { PageFrame };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ScrollArea as ScrollArea$1 } from "../base/scroll-area.js";
|
|
2
|
+
import { ComponentProps } from "react";
|
|
3
|
+
//#region src/web/layout/scroll-area.d.ts
|
|
4
|
+
type ScrollAreaProps = ComponentProps<typeof ScrollArea$1> & {
|
|
5
|
+
/** Show the horizontal scrollbar */
|
|
6
|
+
horizontal?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare function ScrollArea({ horizontal, children, ...props }: ScrollAreaProps): import("react").JSX.Element;
|
|
9
|
+
//#endregion
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ScrollArea as ScrollArea$1, ScrollBar } from "../base/scroll-area.js";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/web/layout/scroll-area.tsx
|
|
5
|
+
function ScrollArea({ horizontal, children, ...props }) {
|
|
6
|
+
return /* @__PURE__ */ jsxs(ScrollArea$1, {
|
|
7
|
+
...props,
|
|
8
|
+
children: [children, horizontal && /* @__PURE__ */ jsx(ScrollBar, { orientation: "horizontal" })]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
export { ScrollArea };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { SheetContent } from "../base/sheet.js";
|
|
2
|
+
import { DialogController } from "../lib/dialog.js";
|
|
3
|
+
import React, { ComponentProps } from "react";
|
|
4
|
+
//#region src/web/layout/sheet.d.ts
|
|
5
|
+
type BaseProps = {
|
|
6
|
+
title: React.ReactNode;
|
|
7
|
+
description?: string;
|
|
8
|
+
content: React.ReactNode;
|
|
9
|
+
footer?: React.ReactNode;
|
|
10
|
+
/** The direction the sheet appears from */
|
|
11
|
+
side?: ComponentProps<typeof SheetContent>["side"];
|
|
12
|
+
/** Class name passed to SheetContent */
|
|
13
|
+
contentClassName?: string;
|
|
14
|
+
/** Class name passed to SheetTitle */
|
|
15
|
+
titleClassName?: string;
|
|
16
|
+
/** Accessible name of the close button (defaults to the Japanese "Close" label) */
|
|
17
|
+
closeLabel?: string;
|
|
18
|
+
};
|
|
19
|
+
type DialogModeProps = BaseProps & {
|
|
20
|
+
dialog: DialogController;
|
|
21
|
+
open?: never;
|
|
22
|
+
onOpenChange?: never;
|
|
23
|
+
};
|
|
24
|
+
type ControlledModeProps = BaseProps & {
|
|
25
|
+
dialog?: never;
|
|
26
|
+
open: boolean;
|
|
27
|
+
onOpenChange: (open: boolean) => void;
|
|
28
|
+
};
|
|
29
|
+
type Props = DialogModeProps | ControlledModeProps;
|
|
30
|
+
export declare function Sheet(props: Props): React.JSX.Element;
|
|
31
|
+
//#endregion
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { ScrollArea } from "../base/scroll-area.js";
|
|
3
|
+
import { Sheet as Sheet$1, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle } from "../base/sheet.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/web/layout/sheet.tsx
|
|
7
|
+
function Sheet(props) {
|
|
8
|
+
const { title, description, content, footer, side, contentClassName, titleClassName, closeLabel } = props;
|
|
9
|
+
if (props.dialog) {
|
|
10
|
+
const { dialog } = props;
|
|
11
|
+
return /* @__PURE__ */ jsx(Sheet$1, {
|
|
12
|
+
open: dialog.isOpen,
|
|
13
|
+
onOpenChange: (next) => !next && dialog.close(),
|
|
14
|
+
children: /* @__PURE__ */ jsxs(SheetContent, {
|
|
15
|
+
side,
|
|
16
|
+
className: cn("flex flex-col", contentClassName),
|
|
17
|
+
onInteractOutside: (e) => {
|
|
18
|
+
e.preventDefault();
|
|
19
|
+
dialog.onOutsideClick();
|
|
20
|
+
},
|
|
21
|
+
closeLabel,
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ jsxs(SheetHeader, { children: [/* @__PURE__ */ jsx(SheetTitle, {
|
|
24
|
+
className: titleClassName,
|
|
25
|
+
children: title
|
|
26
|
+
}), description && /* @__PURE__ */ jsx(SheetDescription, { children: description })] }),
|
|
27
|
+
/* @__PURE__ */ jsx(ScrollArea, {
|
|
28
|
+
className: "flex-1",
|
|
29
|
+
viewPortClassName: "w-full",
|
|
30
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
31
|
+
className: "flex flex-col gap-4 px-5 pb-5 wrap-break-word",
|
|
32
|
+
children: content
|
|
33
|
+
})
|
|
34
|
+
}),
|
|
35
|
+
footer && /* @__PURE__ */ jsx(SheetFooter, { children: footer })
|
|
36
|
+
]
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const { open, onOpenChange } = props;
|
|
41
|
+
return /* @__PURE__ */ jsx(Sheet$1, {
|
|
42
|
+
open,
|
|
43
|
+
onOpenChange,
|
|
44
|
+
children: /* @__PURE__ */ jsxs(SheetContent, {
|
|
45
|
+
side,
|
|
46
|
+
className: cn("flex flex-col", contentClassName),
|
|
47
|
+
closeLabel,
|
|
48
|
+
children: [
|
|
49
|
+
/* @__PURE__ */ jsxs(SheetHeader, { children: [/* @__PURE__ */ jsx(SheetTitle, {
|
|
50
|
+
className: titleClassName,
|
|
51
|
+
children: title
|
|
52
|
+
}), description && /* @__PURE__ */ jsx(SheetDescription, { children: description })] }),
|
|
53
|
+
/* @__PURE__ */ jsx(ScrollArea, {
|
|
54
|
+
className: "flex-1",
|
|
55
|
+
viewPortClassName: "w-full",
|
|
56
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
57
|
+
className: "flex flex-col gap-4 px-5 pb-5 wrap-break-word",
|
|
58
|
+
children: content
|
|
59
|
+
})
|
|
60
|
+
}),
|
|
61
|
+
footer && /* @__PURE__ */ jsx(SheetFooter, { children: footer })
|
|
62
|
+
]
|
|
63
|
+
})
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
export { Sheet };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
//#region src/web/layout/simple-dialog.d.ts
|
|
3
|
+
type Props = {
|
|
4
|
+
open: boolean;
|
|
5
|
+
onOpenChange: (open: boolean) => void;
|
|
6
|
+
title: React.ReactNode;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
};
|
|
9
|
+
export declare function SimpleDialog({ open, onOpenChange, title, children }: Props): React.JSX.Element;
|
|
10
|
+
//#endregion
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../base/dialog.js";
|
|
2
|
+
import { ScrollArea } from "../base/scroll-area.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
|
|
5
|
+
//#region src/web/layout/simple-dialog.tsx
|
|
6
|
+
function SimpleDialog({ open, onOpenChange, title, children }) {
|
|
7
|
+
return /* @__PURE__ */ jsx(Dialog, {
|
|
8
|
+
open,
|
|
9
|
+
onOpenChange,
|
|
10
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
11
|
+
className: "max-h-[calc(100dvh-2rem)] grid-rows-[auto_minmax(0,1fr)]",
|
|
12
|
+
children: [/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: title }) }), /* @__PURE__ */ jsx(ScrollArea, {
|
|
13
|
+
className: "h-full",
|
|
14
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
15
|
+
className: "pr-3",
|
|
16
|
+
children
|
|
17
|
+
})
|
|
18
|
+
})]
|
|
19
|
+
})
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
export { SimpleDialog };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { TableRow } from "../base/table.js";
|
|
2
|
+
import React from "react";
|
|
3
|
+
//#region src/web/layout/simple-table.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* A declarative data table with thin rules. Just pass columns / data.
|
|
6
|
+
* The header is a pale frame surface and the row rules are an ultra-thin 1px line (following base/table).
|
|
7
|
+
* Numeric columns are mono + tabular-nums + right-aligned.
|
|
8
|
+
*
|
|
9
|
+
* It is a different thing from a TanStack-based DataTable (with pagination and selection),
|
|
10
|
+
* and is a lightweight version for short tables that need no sorting or paging (dashboard summaries and the like).
|
|
11
|
+
*/
|
|
12
|
+
export type SimpleColumn<T> = {
|
|
13
|
+
/** Column key (unique within a row). */
|
|
14
|
+
key: string;
|
|
15
|
+
header: React.ReactNode;
|
|
16
|
+
/** Alignment of the cell / header (default left). */
|
|
17
|
+
align?: "left" | "right" | "center";
|
|
18
|
+
/** Monospace + tabular-nums (for numbers and IDs). */
|
|
19
|
+
mono?: boolean;
|
|
20
|
+
/** Emphasis (font-medium). */
|
|
21
|
+
strong?: boolean;
|
|
22
|
+
/** Extra class for the cell. */
|
|
23
|
+
cellClassName?: string;
|
|
24
|
+
/** Extra class for the header. */
|
|
25
|
+
headClassName?: string;
|
|
26
|
+
/** Cell rendering. When not given, row[key] is shown. */
|
|
27
|
+
render?: (row: T) => React.ReactNode;
|
|
28
|
+
/**
|
|
29
|
+
* Hide the column when narrower than this width (a Tailwind breakpoint). Used to fold away columns that are not important at narrow widths (IDs, supplements and so on)
|
|
30
|
+
* and avoid horizontal scrolling. When not given, the column is always shown.
|
|
31
|
+
*/
|
|
32
|
+
hideBelow?: "sm" | "md" | "lg";
|
|
33
|
+
};
|
|
34
|
+
export declare function SimpleTable<T extends object>({ columns, data, getRowKey, onRowClick, getRowProps, className, wrapperClassName }: {
|
|
35
|
+
columns: SimpleColumn<T>[];
|
|
36
|
+
data: T[];
|
|
37
|
+
/** Derives the row key. When not given, the index is used. */
|
|
38
|
+
getRowKey?: (row: T, index: number) => string;
|
|
39
|
+
/**
|
|
40
|
+
* Row click (optional). When passed, a row can take focus (tabIndex=0) and can also be pressed with Enter and Space.
|
|
41
|
+
* It does not steal key handling from buttons or links inside the row (it reacts only when the row itself has focus).
|
|
42
|
+
*/
|
|
43
|
+
onRowClick?: (row: T) => void;
|
|
44
|
+
/** Extra attributes per row (data-* / className and so on). Used for whole-row clicks and for attaching e2e selectors. */
|
|
45
|
+
getRowProps?: (row: T, index: number) => Omit<React.ComponentPropsWithoutRef<typeof TableRow>, "key">;
|
|
46
|
+
className?: string;
|
|
47
|
+
wrapperClassName?: string;
|
|
48
|
+
}): React.JSX.Element;
|
|
49
|
+
//#endregion
|