@setsquare/ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -0
- package/LICENSE +202 -0
- package/NOTICE +49 -0
- package/README.md +313 -0
- package/dist/index.d.ts +129 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +78 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/cn.d.ts +4 -0
- package/dist/lib/cn.d.ts.map +1 -0
- package/dist/lib/cn.js +59 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/lib/tokens.d.ts +5 -0
- package/dist/lib/tokens.d.ts.map +1 -0
- package/dist/lib/tokens.js +22 -0
- package/dist/lib/tokens.js.map +1 -0
- package/dist/lib/use-element-width.d.ts +4 -0
- package/dist/lib/use-element-width.d.ts.map +1 -0
- package/dist/lib/use-element-width.js +17 -0
- package/dist/lib/use-element-width.js.map +1 -0
- package/dist/lint/index.d.ts +41 -0
- package/dist/lint/index.d.ts.map +1 -0
- package/dist/lint/index.js +648 -0
- package/dist/lint/index.js.map +1 -0
- package/dist/shell/app-header.d.ts +13 -0
- package/dist/shell/app-header.d.ts.map +1 -0
- package/dist/shell/app-header.js +11 -0
- package/dist/shell/app-header.js.map +1 -0
- package/dist/shell/dashboard-shell.d.ts +67 -0
- package/dist/shell/dashboard-shell.d.ts.map +1 -0
- package/dist/shell/dashboard-shell.js +168 -0
- package/dist/shell/dashboard-shell.js.map +1 -0
- package/dist/shell/page-header.d.ts +19 -0
- package/dist/shell/page-header.d.ts.map +1 -0
- package/dist/shell/page-header.js +11 -0
- package/dist/shell/page-header.js.map +1 -0
- package/dist/shell/right-panel.d.ts +25 -0
- package/dist/shell/right-panel.d.ts.map +1 -0
- package/dist/shell/right-panel.js +37 -0
- package/dist/shell/right-panel.js.map +1 -0
- package/dist/shell/sidebar.d.ts +68 -0
- package/dist/shell/sidebar.d.ts.map +1 -0
- package/dist/shell/sidebar.js +68 -0
- package/dist/shell/sidebar.js.map +1 -0
- package/dist/shell/site-footer.d.ts +28 -0
- package/dist/shell/site-footer.d.ts.map +1 -0
- package/dist/shell/site-footer.js +15 -0
- package/dist/shell/site-footer.js.map +1 -0
- package/dist/shell/site-header-padding.d.ts +7 -0
- package/dist/shell/site-header-padding.d.ts.map +1 -0
- package/dist/shell/site-header-padding.js +27 -0
- package/dist/shell/site-header-padding.js.map +1 -0
- package/dist/shell/site-header.d.ts +23 -0
- package/dist/shell/site-header.d.ts.map +1 -0
- package/dist/shell/site-header.js +13 -0
- package/dist/shell/site-header.js.map +1 -0
- package/dist/shell/site-menu.d.ts +27 -0
- package/dist/shell/site-menu.d.ts.map +1 -0
- package/dist/shell/site-menu.js +56 -0
- package/dist/shell/site-menu.js.map +1 -0
- package/dist/shell/site-nav-link.d.ts +24 -0
- package/dist/shell/site-nav-link.d.ts.map +1 -0
- package/dist/shell/site-nav-link.js +35 -0
- package/dist/shell/site-nav-link.js.map +1 -0
- package/dist/shell/site-nav.d.ts +12 -0
- package/dist/shell/site-nav.d.ts.map +1 -0
- package/dist/shell/site-nav.js +9 -0
- package/dist/shell/site-nav.js.map +1 -0
- package/dist/shell/site-path.d.ts +8 -0
- package/dist/shell/site-path.d.ts.map +1 -0
- package/dist/shell/site-path.js +11 -0
- package/dist/shell/site-path.js.map +1 -0
- package/dist/shell/site-shell.d.ts +25 -0
- package/dist/shell/site-shell.d.ts.map +1 -0
- package/dist/shell/site-shell.js +17 -0
- package/dist/shell/site-shell.js.map +1 -0
- package/dist/styles/styles.css +10 -0
- package/dist/styles/theme.css +579 -0
- package/dist/styles/tokens.css +295 -0
- package/dist/testing/index.d.ts +321 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +1175 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/tokens.json +982 -0
- package/dist/ui/alert.d.ts +35 -0
- package/dist/ui/alert.d.ts.map +1 -0
- package/dist/ui/alert.js +65 -0
- package/dist/ui/alert.js.map +1 -0
- package/dist/ui/avatar.d.ts +16 -0
- package/dist/ui/avatar.d.ts.map +1 -0
- package/dist/ui/avatar.js +13 -0
- package/dist/ui/avatar.js.map +1 -0
- package/dist/ui/badge.d.ts +13 -0
- package/dist/ui/badge.d.ts.map +1 -0
- package/dist/ui/badge.js +24 -0
- package/dist/ui/badge.js.map +1 -0
- package/dist/ui/breadcrumbs.d.ts +13 -0
- package/dist/ui/breadcrumbs.d.ts.map +1 -0
- package/dist/ui/breadcrumbs.js +12 -0
- package/dist/ui/breadcrumbs.js.map +1 -0
- package/dist/ui/button-styles.d.ts +24 -0
- package/dist/ui/button-styles.d.ts.map +1 -0
- package/dist/ui/button-styles.js +50 -0
- package/dist/ui/button-styles.js.map +1 -0
- package/dist/ui/button.d.ts +27 -0
- package/dist/ui/button.d.ts.map +1 -0
- package/dist/ui/button.js +30 -0
- package/dist/ui/button.js.map +1 -0
- package/dist/ui/calendar.d.ts +19 -0
- package/dist/ui/calendar.d.ts.map +1 -0
- package/dist/ui/calendar.js +52 -0
- package/dist/ui/calendar.js.map +1 -0
- package/dist/ui/card.d.ts +30 -0
- package/dist/ui/card.d.ts.map +1 -0
- package/dist/ui/card.js +18 -0
- package/dist/ui/card.js.map +1 -0
- package/dist/ui/checkbox.d.ts +36 -0
- package/dist/ui/checkbox.d.ts.map +1 -0
- package/dist/ui/checkbox.js +38 -0
- package/dist/ui/checkbox.js.map +1 -0
- package/dist/ui/code-block.d.ts +20 -0
- package/dist/ui/code-block.d.ts.map +1 -0
- package/dist/ui/code-block.js +22 -0
- package/dist/ui/code-block.js.map +1 -0
- package/dist/ui/combo-box.d.ts +17 -0
- package/dist/ui/combo-box.d.ts.map +1 -0
- package/dist/ui/combo-box.js +14 -0
- package/dist/ui/combo-box.js.map +1 -0
- package/dist/ui/copy-button.d.ts +14 -0
- package/dist/ui/copy-button.d.ts.map +1 -0
- package/dist/ui/copy-button.js +36 -0
- package/dist/ui/copy-button.js.map +1 -0
- package/dist/ui/date-field.d.ts +38 -0
- package/dist/ui/date-field.d.ts.map +1 -0
- package/dist/ui/date-field.js +78 -0
- package/dist/ui/date-field.js.map +1 -0
- package/dist/ui/dialog.d.ts +41 -0
- package/dist/ui/dialog.d.ts.map +1 -0
- package/dist/ui/dialog.js +69 -0
- package/dist/ui/dialog.js.map +1 -0
- package/dist/ui/disclosure.d.ts +18 -0
- package/dist/ui/disclosure.d.ts.map +1 -0
- package/dist/ui/disclosure.js +15 -0
- package/dist/ui/disclosure.js.map +1 -0
- package/dist/ui/empty-state.d.ts +17 -0
- package/dist/ui/empty-state.d.ts.map +1 -0
- package/dist/ui/empty-state.js +9 -0
- package/dist/ui/empty-state.js.map +1 -0
- package/dist/ui/error-state.d.ts +45 -0
- package/dist/ui/error-state.d.ts.map +1 -0
- package/dist/ui/error-state.js +88 -0
- package/dist/ui/error-state.js.map +1 -0
- package/dist/ui/field.d.ts +46 -0
- package/dist/ui/field.d.ts.map +1 -0
- package/dist/ui/field.js +79 -0
- package/dist/ui/field.js.map +1 -0
- package/dist/ui/file-upload.d.ts +54 -0
- package/dist/ui/file-upload.d.ts.map +1 -0
- package/dist/ui/file-upload.js +170 -0
- package/dist/ui/file-upload.js.map +1 -0
- package/dist/ui/form.d.ts +56 -0
- package/dist/ui/form.d.ts.map +1 -0
- package/dist/ui/form.js +137 -0
- package/dist/ui/form.js.map +1 -0
- package/dist/ui/grid-list.d.ts +24 -0
- package/dist/ui/grid-list.d.ts.map +1 -0
- package/dist/ui/grid-list.js +21 -0
- package/dist/ui/grid-list.js.map +1 -0
- package/dist/ui/hero.d.ts +36 -0
- package/dist/ui/hero.d.ts.map +1 -0
- package/dist/ui/hero.js +19 -0
- package/dist/ui/hero.js.map +1 -0
- package/dist/ui/icon-button.d.ts +18 -0
- package/dist/ui/icon-button.d.ts.map +1 -0
- package/dist/ui/icon-button.js +13 -0
- package/dist/ui/icon-button.js.map +1 -0
- package/dist/ui/icon.d.ts +20 -0
- package/dist/ui/icon.d.ts.map +1 -0
- package/dist/ui/icon.js +26 -0
- package/dist/ui/icon.js.map +1 -0
- package/dist/ui/kbd.d.ts +7 -0
- package/dist/ui/kbd.d.ts.map +1 -0
- package/dist/ui/kbd.js +7 -0
- package/dist/ui/kbd.js.map +1 -0
- package/dist/ui/link-card.d.ts +23 -0
- package/dist/ui/link-card.d.ts.map +1 -0
- package/dist/ui/link-card.js +19 -0
- package/dist/ui/link-card.js.map +1 -0
- package/dist/ui/list-box.d.ts +17 -0
- package/dist/ui/list-box.d.ts.map +1 -0
- package/dist/ui/list-box.js +18 -0
- package/dist/ui/list-box.js.map +1 -0
- package/dist/ui/menu.d.ts +31 -0
- package/dist/ui/menu.d.ts.map +1 -0
- package/dist/ui/menu.js +40 -0
- package/dist/ui/menu.js.map +1 -0
- package/dist/ui/number-field.d.ts +19 -0
- package/dist/ui/number-field.d.ts.map +1 -0
- package/dist/ui/number-field.js +19 -0
- package/dist/ui/number-field.js.map +1 -0
- package/dist/ui/prose.d.ts +12 -0
- package/dist/ui/prose.d.ts.map +1 -0
- package/dist/ui/prose.js +11 -0
- package/dist/ui/prose.js.map +1 -0
- package/dist/ui/radio-group.d.ts +20 -0
- package/dist/ui/radio-group.d.ts.map +1 -0
- package/dist/ui/radio-group.js +16 -0
- package/dist/ui/radio-group.js.map +1 -0
- package/dist/ui/scroll-region.d.ts +18 -0
- package/dist/ui/scroll-region.d.ts.map +1 -0
- package/dist/ui/scroll-region.js +29 -0
- package/dist/ui/scroll-region.js.map +1 -0
- package/dist/ui/search-field.d.ts +12 -0
- package/dist/ui/search-field.d.ts.map +1 -0
- package/dist/ui/search-field.js +12 -0
- package/dist/ui/search-field.js.map +1 -0
- package/dist/ui/search.d.ts +43 -0
- package/dist/ui/search.d.ts.map +1 -0
- package/dist/ui/search.js +45 -0
- package/dist/ui/search.js.map +1 -0
- package/dist/ui/section.d.ts +50 -0
- package/dist/ui/section.d.ts.map +1 -0
- package/dist/ui/section.js +25 -0
- package/dist/ui/section.js.map +1 -0
- package/dist/ui/segmented-control.d.ts +18 -0
- package/dist/ui/segmented-control.d.ts.map +1 -0
- package/dist/ui/segmented-control.js +17 -0
- package/dist/ui/segmented-control.js.map +1 -0
- package/dist/ui/select.d.ts +18 -0
- package/dist/ui/select.d.ts.map +1 -0
- package/dist/ui/select.js +13 -0
- package/dist/ui/select.js.map +1 -0
- package/dist/ui/selection-bar.d.ts +28 -0
- package/dist/ui/selection-bar.d.ts.map +1 -0
- package/dist/ui/selection-bar.js +35 -0
- package/dist/ui/selection-bar.js.map +1 -0
- package/dist/ui/sheet.d.ts +21 -0
- package/dist/ui/sheet.d.ts.map +1 -0
- package/dist/ui/sheet.js +16 -0
- package/dist/ui/sheet.js.map +1 -0
- package/dist/ui/skeleton.d.ts +31 -0
- package/dist/ui/skeleton.d.ts.map +1 -0
- package/dist/ui/skeleton.js +38 -0
- package/dist/ui/skeleton.js.map +1 -0
- package/dist/ui/slider.d.ts +31 -0
- package/dist/ui/slider.d.ts.map +1 -0
- package/dist/ui/slider.js +33 -0
- package/dist/ui/slider.js.map +1 -0
- package/dist/ui/spinner.d.ts +27 -0
- package/dist/ui/spinner.d.ts.map +1 -0
- package/dist/ui/spinner.js +21 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/split.d.ts +14 -0
- package/dist/ui/split.d.ts.map +1 -0
- package/dist/ui/split.js +11 -0
- package/dist/ui/split.js.map +1 -0
- package/dist/ui/stat-list.d.ts +25 -0
- package/dist/ui/stat-list.d.ts.map +1 -0
- package/dist/ui/stat-list.js +14 -0
- package/dist/ui/stat-list.js.map +1 -0
- package/dist/ui/steps.d.ts +23 -0
- package/dist/ui/steps.d.ts.map +1 -0
- package/dist/ui/steps.js +16 -0
- package/dist/ui/steps.js.map +1 -0
- package/dist/ui/switch.d.ts +13 -0
- package/dist/ui/switch.d.ts.map +1 -0
- package/dist/ui/switch.js +12 -0
- package/dist/ui/switch.js.map +1 -0
- package/dist/ui/table.d.ts +25 -0
- package/dist/ui/table.d.ts.map +1 -0
- package/dist/ui/table.js +29 -0
- package/dist/ui/table.js.map +1 -0
- package/dist/ui/tag.d.ts +14 -0
- package/dist/ui/tag.d.ts.map +1 -0
- package/dist/ui/tag.js +11 -0
- package/dist/ui/tag.js.map +1 -0
- package/dist/ui/text-field.d.ts +27 -0
- package/dist/ui/text-field.d.ts.map +1 -0
- package/dist/ui/text-field.js +17 -0
- package/dist/ui/text-field.js.map +1 -0
- package/dist/ui/text-link.d.ts +17 -0
- package/dist/ui/text-link.d.ts.map +1 -0
- package/dist/ui/text-link.js +15 -0
- package/dist/ui/text-link.js.map +1 -0
- package/dist/ui/theme-switcher.d.ts +26 -0
- package/dist/ui/theme-switcher.d.ts.map +1 -0
- package/dist/ui/theme-switcher.js +32 -0
- package/dist/ui/theme-switcher.js.map +1 -0
- package/dist/ui/theme.d.ts +54 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +135 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/toast.d.ts +34 -0
- package/dist/ui/toast.d.ts.map +1 -0
- package/dist/ui/toast.js +69 -0
- package/dist/ui/toast.js.map +1 -0
- package/dist/ui/tooltip.d.ts +10 -0
- package/dist/ui/tooltip.d.ts.map +1 -0
- package/dist/ui/tooltip.js +10 -0
- package/dist/ui/tooltip.js.map +1 -0
- package/package.json +123 -0
- package/templates/next/error.tsx +32 -0
- package/templates/next/loading.tsx +19 -0
- package/templates/next/not-found.tsx +18 -0
- package/templates/next/page-transition.tsx +33 -0
- package/templates/next/portal-layout.tsx +70 -0
- package/templates/next/prefetch-on-intent.ts +31 -0
- package/templates/next/root-layout.tsx +16 -0
- package/templates/next/site-layout.tsx +58 -0
- package/templates/next/site-nav.ts +16 -0
- package/templates/next/site-not-found.tsx +21 -0
- package/templates/next/site-router.tsx +17 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useContext, useId } from 'react';
|
|
4
|
+
import { Checkbox as RACCheckbox, CheckboxGroup as RACCheckboxGroup, } from 'react-aria-components';
|
|
5
|
+
import { Check, CircleAlert, Minus } from 'lucide-react';
|
|
6
|
+
import { cn } from '../lib/cn.js';
|
|
7
|
+
import { FieldDescription, FieldError, FieldLabel, NecessityContext, fieldStack, withRequired, } from './field.js';
|
|
8
|
+
/** The visible box, shared by Checkbox and SelectionCheckbox. Checked: a tick; mixed: a dash — shape, not only fill. */
|
|
9
|
+
const boxStyles = cn('grid size-choice shrink-0 place-items-center rounded-sm border border-input bg-background text-primary-foreground', 'group-data-focus-visible/choice:focus-ring group-data-hovered/choice:border-foreground', 'group-data-selected/choice:border-primary group-data-selected/choice:bg-primary group-data-indeterminate/choice:border-primary group-data-indeterminate/choice:bg-primary', 'group-data-invalid/choice:border-destructive group-data-invalid/choice:shadow-[0_0_0_1px_var(--destructive)]', '[&_svg]:size-[calc(var(--choice-size)-4px)] [&_svg]:[stroke-width:3]');
|
|
10
|
+
/**
|
|
11
|
+
* A yes/no choice submitted with the form (settings that apply at once are a Switch).
|
|
12
|
+
* The whole row — box and label — is the target, at least --target-min tall.
|
|
13
|
+
*/
|
|
14
|
+
export function Checkbox({ children, description, requiredMessage, className, ...props }) {
|
|
15
|
+
const necessity = useContext(NecessityContext);
|
|
16
|
+
const autoId = useId();
|
|
17
|
+
const id = props.id ?? autoId;
|
|
18
|
+
const errorId = `${id}-error`;
|
|
19
|
+
return (_jsx(RACCheckbox, { ...props, id: id, "aria-describedby": [props['aria-describedby'], props.isRequired ? errorId : null].filter(Boolean).join(' ') ||
|
|
20
|
+
undefined, validate: props.isRequired
|
|
21
|
+
? withRequired(true, requiredMessage ?? 'Select this to continue', (v) => !v)
|
|
22
|
+
: undefined, className: cn('group/choice relative flex min-h-target cursor-pointer items-start gap-3 py-[calc((var(--target-min)-var(--choice-size))/2)] text-sm leading-5 text-foreground outline-none data-disabled:cursor-not-allowed data-disabled:opacity-60 data-readonly:cursor-default', className), children: ({ isSelected, isIndeterminate, isInvalid }) => (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": "true", className: cn('mt-[calc((20px-var(--choice-size))/2)]', boxStyles), children: isIndeterminate ? _jsx(Minus, {}) : isSelected ? _jsx(Check, {}) : null }), _jsxs("span", { className: "flex min-w-0 flex-col", children: [_jsxs("span", { children: [children, props.isRequired && necessity === 'required' && (_jsxs("span", { "aria-hidden": "true", className: "text-muted-foreground", children: [' ', "(required)"] }))] }), description && (_jsx("span", { className: "text-[13px] text-muted-foreground", children: description })), props.isRequired && isInvalid && (_jsxs("span", { id: errorId, "aria-hidden": "true", className: "mt-1 flex items-start gap-1.5 text-[13px] leading-5 font-semibold text-destructive", children: [_jsx(CircleAlert, { className: "mt-0.5 size-4 shrink-0" }), _jsxs("span", { "data-field-error-text": true, children: [_jsx("span", { className: "sr-only", children: "Error: " }), requiredMessage ?? 'Select this to continue'] })] }))] })] })) }));
|
|
23
|
+
}
|
|
24
|
+
/** A labelled list of checkboxes, read as a group. */
|
|
25
|
+
export function CheckboxGroup({ label, description, errorMessage, requiredMessage, children, className, ...props }) {
|
|
26
|
+
return (_jsxs(RACCheckboxGroup, { ...props, validate: props.isRequired
|
|
27
|
+
? withRequired(true, requiredMessage ?? 'Select at least one option', (v) => !v?.length)
|
|
28
|
+
: undefined, className: cn(fieldStack, className), children: [_jsx(FieldLabel, { elementType: "span", isRequired: props.isRequired, children: label }), description && _jsx(FieldDescription, { children: description }), _jsx(FieldError, { requiredMessage: requiredMessage ?? 'Select at least one option', children: errorMessage }), _jsx("div", { className: "flex flex-col", children: children })] }));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The box alone, for the selection column of a Table or a GridList item. React Aria wires it to the row
|
|
32
|
+
* (`slot="selection"`) and names it — "Select" for a row, "Select All" in the header — so it needs no label.
|
|
33
|
+
* The target is --target-min square and, like every choice control, the root is `relative`.
|
|
34
|
+
*/
|
|
35
|
+
export function SelectionCheckbox({ className, ...props }) {
|
|
36
|
+
return (_jsx(RACCheckbox, { ...props, slot: "selection", className: cn('group/choice relative grid size-target shrink-0 cursor-pointer place-items-center outline-none data-disabled:cursor-not-allowed', className), children: ({ isSelected, isIndeterminate }) => (_jsx("span", { "aria-hidden": "true", className: boxStyles, children: isIndeterminate ? _jsx(Minus, {}) : isSelected ? _jsx(Check, {}) : null })) }));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=checkbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkbox.js","sourceRoot":"","sources":["../../src/ui/checkbox.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface CodeBlockProps {
|
|
2
|
+
code: string;
|
|
3
|
+
/** What it is: a file path (`app/layout.tsx`), a language, or "Terminal". Shown above the code. */
|
|
4
|
+
label?: string;
|
|
5
|
+
/**
|
|
6
|
+
* `terminal`: lines that start with `$ ` are commands. The prompt is drawn but not read out or copied, the
|
|
7
|
+
* other lines (output) are muted, and Copy copies the commands only.
|
|
8
|
+
*/
|
|
9
|
+
tone?: 'code' | 'terminal';
|
|
10
|
+
/** Show the Copy button. Default true. */
|
|
11
|
+
copy?: boolean;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Code with a label and a copy button. Long lines scroll sideways inside a ScrollRegion, never the page; the
|
|
16
|
+
* region is named by the label and the first line, so two on a page can be told apart. Server-safe: it renders
|
|
17
|
+
* ScrollRegion and CopyButton, which are client components, and holds no state itself.
|
|
18
|
+
*/
|
|
19
|
+
export declare function CodeBlock({ code, label, tone, copy, className }: CodeBlockProps): import("react").JSX.Element;
|
|
20
|
+
//# sourceMappingURL=code-block.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-block.d.ts","sourceRoot":"","sources":["../../src/ui/code-block.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,mGAAmG;IACnG,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC3B,0CAA0C;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAa,EAAE,IAAW,EAAE,SAAS,EAAE,EAAE,cAAc,+BAgD/F"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '../lib/cn.js';
|
|
3
|
+
import { CopyButton } from './copy-button.js';
|
|
4
|
+
import { ScrollRegion } from './scroll-region.js';
|
|
5
|
+
const PROMPT = /^\$ /;
|
|
6
|
+
/**
|
|
7
|
+
* Code with a label and a copy button. Long lines scroll sideways inside a ScrollRegion, never the page; the
|
|
8
|
+
* region is named by the label and the first line, so two on a page can be told apart. Server-safe: it renders
|
|
9
|
+
* ScrollRegion and CopyButton, which are client components, and holds no state itself.
|
|
10
|
+
*/
|
|
11
|
+
export function CodeBlock({ code, label, tone = 'code', copy = true, className }) {
|
|
12
|
+
const lines = code.split('\n');
|
|
13
|
+
const terminal = tone === 'terminal';
|
|
14
|
+
const commands = terminal ? lines.filter((l) => PROMPT.test(l)) : [];
|
|
15
|
+
const copied = commands.length ? commands.map((l) => l.replace(PROMPT, '')).join('\n') : code;
|
|
16
|
+
const name = label ?? (terminal ? 'Terminal' : 'code');
|
|
17
|
+
const first = (commands[0]?.replace(PROMPT, '') ?? lines[0]).trim().slice(0, 60);
|
|
18
|
+
return (_jsxs("figure", { className: cn('relative m-0 min-w-0 overflow-clip rounded-lg border border-border bg-background', className), children: [(label || terminal || copy) && (_jsxs("figcaption", { className: "relative flex items-center justify-between gap-2.5 border-b border-border py-1 pr-1.5 pl-4", children: [_jsx("span", { className: "min-w-0 truncate font-mono text-[13px] leading-5 text-muted-foreground", children: label ?? (terminal ? 'Terminal' : '') }), copy && _jsx(CopyButton, { text: copied, label: name })] })), _jsx(ScrollRegion, { label: first ? `${name}: ${first}` : name, children: _jsx("pre", { className: "m-0 w-max min-w-full p-[18px] text-code", children: _jsx("code", { children: terminal
|
|
19
|
+
? lines.map((line, i) => (_jsx("span", { className: "block", children: PROMPT.test(line) ? (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": "true", className: "text-muted-foreground select-none", children: '$ ' }), line.replace(PROMPT, '')] })) : (_jsx("span", { className: "text-muted-foreground", children: line || ' ' })) }, i)))
|
|
20
|
+
: code }) }) })] }));
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=code-block.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-block.js","sourceRoot":"","sources":["../../src/ui/code-block.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAgBlD,MAAM,MAAM,GAAG,MAAM,CAAC;AAEtB;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,MAAM,EAAE,IAAI,GAAG,IAAI,EAAE,SAAS,EAAkB;IAC9F,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,IAAI,KAAK,UAAU,CAAC;IACrC,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9F,MAAM,IAAI,GAAG,KAAK,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACvD,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACjF,OAAO,CACL,kBACE,SAAS,EAAE,EAAE,CACX,kFAAkF,EAClF,SAAS,CACV,aAEA,CAAC,KAAK,IAAI,QAAQ,IAAI,IAAI,CAAC,IAAI,CAC9B,sBAAY,SAAS,EAAC,4FAA4F,aAChH,eAAM,SAAS,EAAC,wEAAwE,YACrF,KAAK,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,GACjC,EACN,IAAI,IAAI,KAAC,UAAU,IAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,GAAI,IACvC,CACd,EACD,KAAC,YAAY,IAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,YAErD,cAAK,SAAS,EAAC,yCAAyC,YACtD,yBACG,QAAQ;4BACP,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAErB,eAAc,SAAS,EAAC,OAAO,YAC5B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CACnB,8BACE,8BAAkB,MAAM,EAAC,SAAS,EAAC,mCAAmC,YACnE,IAAI,GACA,EACN,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IACxB,CACJ,CAAC,CAAC,CAAC,CACF,eAAM,SAAS,EAAC,uBAAuB,YAAE,IAAI,IAAI,GAAG,GAAQ,CAC7D,IAVQ,CAAC,CAWL,CACR,CAAC;4BACJ,CAAC,CAAC,IAAI,GACH,GACH,GACO,IACR,CACV,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { type ComboBoxProps as RACComboBoxProps, type Key } from 'react-aria-components';
|
|
3
|
+
import { type FieldWidth } from './field.js';
|
|
4
|
+
export interface ComboBoxProps<T extends object> extends Omit<RACComboBoxProps<T>, 'className' | 'children' | 'validate'> {
|
|
5
|
+
label: string;
|
|
6
|
+
description?: ReactNode;
|
|
7
|
+
errorMessage?: string;
|
|
8
|
+
requiredMessage?: string;
|
|
9
|
+
validate?: (value: Key | null) => string | string[] | true | null | undefined;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
children: ReactNode | ((item: T) => ReactNode);
|
|
12
|
+
width?: FieldWidth;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
/** Type to filter a long list, then choose (people, countries, projects). The list opens as you type or from the button. */
|
|
16
|
+
export declare function ComboBox<T extends object>({ label, description, errorMessage, requiredMessage, validate, placeholder, children, width, className, ...props }: ComboBoxProps<T>): import("react").JSX.Element;
|
|
17
|
+
//# sourceMappingURL=combo-box.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combo-box.d.ts","sourceRoot":"","sources":["../../src/ui/combo-box.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAGL,KAAK,aAAa,IAAI,gBAAgB,EACtC,KAAK,GAAG,EACT,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EAUL,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAIpB,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM,CAAE,SAAQ,IAAI,CAC3D,gBAAgB,CAAC,CAAC,CAAC,EACnB,WAAW,GAAG,UAAU,GAAG,UAAU,CACtC;IACC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI,KAAK,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,SAAS,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS,CAAC,CAAC;IAC/C,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,4HAA4H;AAC5H,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,EACzC,KAAK,EACL,WAAW,EACX,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,KAAY,EACZ,SAAS,EACT,GAAG,KAAK,EACT,EAAE,aAAa,CAAC,CAAC,CAAC,+BA4ClB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ComboBox as RACComboBox, Input, } from 'react-aria-components';
|
|
4
|
+
import { ChevronsUpDown } from 'lucide-react';
|
|
5
|
+
import { cn } from '../lib/cn.js';
|
|
6
|
+
import { Button } from './button.js';
|
|
7
|
+
import { FieldDescription, FieldError, FieldLabel, fieldBox, fieldInput, fieldStack, fieldWidths, lcFirst, withRequired, } from './field.js';
|
|
8
|
+
import { ListBox } from './list-box.js';
|
|
9
|
+
import { Popover } from './menu.js';
|
|
10
|
+
/** Type to filter a long list, then choose (people, countries, projects). The list opens as you type or from the button. */
|
|
11
|
+
export function ComboBox({ label, description, errorMessage, requiredMessage, validate, placeholder, children, width = 'md', className, ...props }) {
|
|
12
|
+
return (_jsxs(RACComboBox, { ...props, validate: withRequired(props.isRequired, requiredMessage ?? `Choose ${lcFirst(label)}`, (v) => v == null, validate), className: cn(fieldStack, fieldWidths[width], className), children: [_jsx(FieldLabel, { isRequired: props.isRequired, children: label }), description && _jsx(FieldDescription, { children: description }), _jsx(FieldError, { requiredMessage: requiredMessage ?? `Choose ${lcFirst(label)}`, children: errorMessage }), _jsxs("div", { className: fieldBox, children: [_jsx(Input, { placeholder: placeholder, className: fieldInput }), _jsx(Button, { variant: "ghost", visualSize: "icon-sm", className: "me-1 justify-end", visualClassName: "text-muted-foreground group-data-hovered/button:text-foreground [&_svg]:size-4", children: _jsx(ChevronsUpDown, { "aria-hidden": "true" }) })] }), _jsx(Popover, { placement: "bottom start", className: "max-h-80", children: _jsx(ListBox, { renderEmptyState: () => (_jsx("p", { className: "px-3 py-2 text-sm text-muted-foreground", children: "No matches. Check the spelling or try fewer letters." })), children: children }) })] }));
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=combo-box.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combo-box.js","sourceRoot":"","sources":["../../src/ui/combo-box.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EACL,QAAQ,IAAI,WAAW,EACvB,KAAK,GAGN,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,QAAQ,EACR,UAAU,EACV,UAAU,EACV,WAAW,EACX,OAAO,EACP,YAAY,GAEb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBpC,4HAA4H;AAC5H,MAAM,UAAU,QAAQ,CAAmB,EACzC,KAAK,EACL,WAAW,EACX,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,KAAK,GAAG,IAAI,EACZ,SAAS,EACT,GAAG,KAAK,EACS;IACjB,OAAO,CACL,MAAC,WAAW,OACL,KAA6B,EAClC,QAAQ,EACN,YAAY,CACV,KAAK,CAAC,UAAU,EAChB,eAAe,IAAI,UAAU,OAAO,CAAC,KAAK,CAAC,EAAE,EAC7C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,EAChB,QAAQ,CACA,EAEZ,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,aAExD,KAAC,UAAU,IAAC,UAAU,EAAE,KAAK,CAAC,UAAU,YAAG,KAAK,GAAc,EAC7D,WAAW,IAAI,KAAC,gBAAgB,cAAE,WAAW,GAAoB,EAClE,KAAC,UAAU,IAAC,eAAe,EAAE,eAAe,IAAI,UAAU,OAAO,CAAC,KAAK,CAAC,EAAE,YACvE,YAAY,GACF,EACb,eAAK,SAAS,EAAE,QAAQ,aACtB,KAAC,KAAK,IAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,GAAI,EAE1D,KAAC,MAAM,IACL,OAAO,EAAC,OAAO,EACf,UAAU,EAAC,SAAS,EACpB,SAAS,EAAC,kBAAkB,EAC5B,eAAe,EAAC,gFAAgF,YAEhG,KAAC,cAAc,mBAAa,MAAM,GAAG,GAC9B,IACL,EACN,KAAC,OAAO,IAAC,SAAS,EAAC,cAAc,EAAC,SAAS,EAAC,UAAU,YACpD,KAAC,OAAO,IACN,gBAAgB,EAAE,GAAG,EAAE,CAAC,CACtB,YAAG,SAAS,EAAC,yCAAyC,qEAElD,CACL,YAEA,QAAiB,GACV,GACF,IACE,CACf,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ButtonProps } from './button.js';
|
|
2
|
+
export interface CopyButtonProps extends Omit<ButtonProps, 'onPress' | 'children' | 'aria-label'> {
|
|
3
|
+
/** What to copy. */
|
|
4
|
+
text: string;
|
|
5
|
+
/** What it copies, said after "Copy" to a screen reader: "install command", "app/layout.tsx". */
|
|
6
|
+
label: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Copies text to the clipboard and says so: the button reads Copied (or Not copied) for two seconds, and a
|
|
10
|
+
* status message says what happened, again on a second copy. The visible word starts the button's name, so a
|
|
11
|
+
* voice command for what's on screen reaches it.
|
|
12
|
+
*/
|
|
13
|
+
export declare function CopyButton({ text, label, variant, visualSize, ...props }: CopyButtonProps): import("react").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=copy-button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-button.d.ts","sourceRoot":"","sources":["../../src/ui/copy-button.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,UAAU,GAAG,YAAY,CAAC;IAC/F,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iGAAiG;IACjG,KAAK,EAAE,MAAM,CAAC;CACf;AAKD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,KAAK,EACL,OAAiB,EACjB,UAAiB,EACjB,GAAG,KAAK,EACT,EAAE,eAAe,+BAuCjB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { Button } from './button.js';
|
|
5
|
+
const SHOWN = { idle: 'Copy', copied: 'Copied', failed: 'Not copied' };
|
|
6
|
+
/**
|
|
7
|
+
* Copies text to the clipboard and says so: the button reads Copied (or Not copied) for two seconds, and a
|
|
8
|
+
* status message says what happened, again on a second copy. The visible word starts the button's name, so a
|
|
9
|
+
* voice command for what's on screen reaches it.
|
|
10
|
+
*/
|
|
11
|
+
export function CopyButton({ text, label, variant = 'ghost', visualSize = 'sm', ...props }) {
|
|
12
|
+
const [state, setState] = useState('idle');
|
|
13
|
+
const [message, setMessage] = useState('');
|
|
14
|
+
const timers = useRef([]);
|
|
15
|
+
useEffect(() => () => timers.current.forEach(clearTimeout), []);
|
|
16
|
+
const later = (fn, ms) => timers.current.push(setTimeout(fn, ms));
|
|
17
|
+
const announce = (next, words) => {
|
|
18
|
+
timers.current.forEach(clearTimeout);
|
|
19
|
+
timers.current = [];
|
|
20
|
+
setState(next);
|
|
21
|
+
// Empty the region first: a screen reader doesn't repeat a status that didn't change.
|
|
22
|
+
setMessage('');
|
|
23
|
+
later(() => setMessage(words), 100);
|
|
24
|
+
later(() => setState('idle'), 2000);
|
|
25
|
+
};
|
|
26
|
+
return (_jsxs("span", { className: "relative inline-flex", children: [_jsxs(Button, { ...props, variant: variant, visualSize: visualSize, onPress: async () => {
|
|
27
|
+
try {
|
|
28
|
+
await navigator.clipboard.writeText(text);
|
|
29
|
+
announce('copied', `Copied ${label}`);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
announce('failed', `Couldn't copy ${label}. Select it and copy it yourself.`);
|
|
33
|
+
}
|
|
34
|
+
}, children: [SHOWN[state], _jsxs("span", { className: "sr-only", children: [" ", label] })] }), _jsx("span", { role: "status", className: "sr-only", children: message })] }));
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=copy-button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-button.js","sourceRoot":"","sources":["../../src/ui/copy-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,MAAM,EAAoB,MAAM,aAAa,CAAC;AAUvD,MAAM,KAAK,GAA0B,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;AAE9F;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,EACzB,IAAI,EACJ,KAAK,EACL,OAAO,GAAG,OAAO,EACjB,UAAU,GAAG,IAAI,EACjB,GAAG,KAAK,EACQ;IAChB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAQ,MAAM,CAAC,CAAC;IAClD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAkC,EAAE,CAAC,CAAC;IAC3D,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,CAAC,EAAc,EAAE,EAAU,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IACtF,MAAM,QAAQ,GAAG,CAAC,IAAW,EAAE,KAAa,EAAE,EAAE;QAC9C,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACrC,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC;QACpB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,sFAAsF;QACtF,UAAU,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;QACpC,KAAK,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC,CAAC;IACF,OAAO,CAEL,gBAAM,SAAS,EAAC,sBAAsB,aACpC,MAAC,MAAM,OACD,KAAK,EACT,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,KAAK,IAAI,EAAE;oBAClB,IAAI,CAAC;wBACH,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;wBAC1C,QAAQ,CAAC,QAAQ,EAAE,UAAU,KAAK,EAAE,CAAC,CAAC;oBACxC,CAAC;oBAAC,MAAM,CAAC;wBACP,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,KAAK,mCAAmC,CAAC,CAAC;oBAChF,CAAC;gBACH,CAAC,aAEA,KAAK,CAAC,KAAK,CAAC,EACb,gBAAM,SAAS,EAAC,SAAS,kBAAG,KAAK,IAAQ,IAClC,EACT,eAAM,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,SAAS,YACpC,OAAO,GACH,IACF,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { type DateFieldProps as RACDateFieldProps, type DatePickerProps as RACDatePickerProps, type DateRange, type DateRangePickerProps as RACDateRangePickerProps, type DateValue, type TimeFieldProps as RACTimeFieldProps, type TimeValue } from 'react-aria-components';
|
|
3
|
+
import { type FieldWidth } from './field.js';
|
|
4
|
+
interface FieldBase {
|
|
5
|
+
label: string;
|
|
6
|
+
/** Hint beyond the format, e.g. "The date on your certificate". */
|
|
7
|
+
description?: ReactNode;
|
|
8
|
+
errorMessage?: string;
|
|
9
|
+
/** Default "Enter <label>". */
|
|
10
|
+
requiredMessage?: string;
|
|
11
|
+
width?: FieldWidth;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface DateFieldProps<T extends DateValue> extends FieldBase, Omit<RACDateFieldProps<T>, 'className' | 'children' | 'validate'> {
|
|
15
|
+
validate?: (value: DateValue | null) => string | string[] | true | null | undefined;
|
|
16
|
+
}
|
|
17
|
+
/** A date typed in parts. Best for dates people know without looking — a date of birth, an expiry date. */
|
|
18
|
+
export declare function DateField<T extends DateValue>({ label, description, errorMessage, requiredMessage, validate, width, className, ...props }: DateFieldProps<T>): import("react").JSX.Element;
|
|
19
|
+
export interface TimeFieldProps<T extends TimeValue> extends FieldBase, Omit<RACTimeFieldProps<T>, 'className' | 'children' | 'validate'> {
|
|
20
|
+
validate?: (value: TimeValue | null) => string | string[] | true | null | undefined;
|
|
21
|
+
}
|
|
22
|
+
/** A time typed in parts. The hour cycle (12 or 24) follows the locale unless `hourCycle` is set. */
|
|
23
|
+
export declare function TimeField<T extends TimeValue>({ label, description, errorMessage, requiredMessage, validate, width, className, ...props }: TimeFieldProps<T>): import("react").JSX.Element;
|
|
24
|
+
export interface DatePickerProps<T extends DateValue> extends FieldBase, Omit<RACDatePickerProps<T>, 'className' | 'children' | 'validate'> {
|
|
25
|
+
validate?: (value: DateValue | null) => string | string[] | true | null | undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A date typed in parts, with a calendar for dates people need to see in context — a due date, a booking.
|
|
29
|
+
* The calendar is an alternative, never the only way in: everything can be typed.
|
|
30
|
+
*/
|
|
31
|
+
export declare function DatePicker<T extends DateValue>({ label, description, errorMessage, requiredMessage, validate, width, className, ...props }: DatePickerProps<T>): import("react").JSX.Element;
|
|
32
|
+
export interface DateRangePickerProps<T extends DateValue> extends FieldBase, Omit<RACDateRangePickerProps<T>, 'className' | 'children' | 'validate'> {
|
|
33
|
+
validate?: (value: DateRange | null) => string | string[] | true | null | undefined;
|
|
34
|
+
}
|
|
35
|
+
/** A start and an end date, each typed in parts, with a two-click range calendar. */
|
|
36
|
+
export declare function DateRangePicker<T extends DateValue>({ label, description, errorMessage, requiredMessage, validate, width, className, ...props }: DateRangePickerProps<T>): import("react").JSX.Element;
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=date-field.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-field.d.ts","sourceRoot":"","sources":["../../src/ui/date-field.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { DateField as RACDateField, DateInput, DatePicker as RACDatePicker, DateRangePicker as RACDateRangePicker, DateSegment, Dialog as RACDialog, Group, TimeField as RACTimeField, useLocale, } from 'react-aria-components';
|
|
4
|
+
import { DateFormatter, getLocalTimeZone } from '@internationalized/date';
|
|
5
|
+
import { CalendarDays } from 'lucide-react';
|
|
6
|
+
import { cn } from '../lib/cn.js';
|
|
7
|
+
import { Button } from './button.js';
|
|
8
|
+
import { Calendar, RangeCalendar } from './calendar.js';
|
|
9
|
+
import { FieldDescription, FieldError, FieldLabel, fieldBox, fieldStack, fieldWidths, lcFirst, withRequired, } from './field.js';
|
|
10
|
+
import { Popover } from './menu.js';
|
|
11
|
+
/**
|
|
12
|
+
* The box around the segments (Layer 2, painted by field-paint), the same height, edge and focus ring as
|
|
13
|
+
* every other input. The segments inside are the targets: each is the full target height. At AAA every part
|
|
14
|
+
* is at least 44px wide, so on a narrow screen the parts and the calendar button wrap onto another line
|
|
15
|
+
* inside the box rather than overflowing it or the page (1.4.10); the paint grows around them.
|
|
16
|
+
*/
|
|
17
|
+
const boxStyles = cn(fieldBox, 'min-h-control-target flex-wrap');
|
|
18
|
+
/**
|
|
19
|
+
* Typed entry first: each part (day, month, year, hour…) is its own spin button — type the digits, or use
|
|
20
|
+
* the arrow keys. The placeholder shows the order for the person's locale, so it doubles as the format hint.
|
|
21
|
+
*/
|
|
22
|
+
function Segments({ className, slot }) {
|
|
23
|
+
return (_jsx(DateInput, { slot: slot, className: cn('flex min-w-0 flex-wrap items-stretch', className), children: (segment) => (_jsx(DateSegment, { segment: segment, className: cn(
|
|
24
|
+
// Each editable part is a target of its own (Layer 1): at least --target-min wide and the full
|
|
25
|
+
// target tall. Its transparent block borders are the band, so the focused ground is painted at
|
|
26
|
+
// the box's height, not the target's.
|
|
27
|
+
'flex min-h-control-target min-w-(--target-min) cursor-text items-center justify-center self-stretch rounded-sm border-y-(length:--field-band) border-transparent bg-clip-padding px-1 tabular-nums outline-none caret-transparent', 'data-disabled:cursor-not-allowed data-[type=literal]:min-w-0 data-[type=literal]:cursor-default', 'data-placeholder:text-muted-foreground data-[type=literal]:px-0 data-[type=literal]:text-muted-foreground', 'data-focused:bg-primary data-focused:text-primary-foreground data-invalid:data-focused:bg-destructive data-invalid:data-focused:text-destructive-foreground') })) }));
|
|
28
|
+
}
|
|
29
|
+
/** Messages that say what to do, for the limits React Aria checks. */
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
+
function useLimitMessages(minValue, maxValue, isDateUnavailable) {
|
|
32
|
+
const { locale } = useLocale();
|
|
33
|
+
const fmt = new DateFormatter(locale, { dateStyle: 'medium' });
|
|
34
|
+
const show = (d) => fmt.format(d.toDate(getLocalTimeZone()));
|
|
35
|
+
return (value) => {
|
|
36
|
+
if (!value)
|
|
37
|
+
return null;
|
|
38
|
+
if (minValue && value.compare(minValue) < 0)
|
|
39
|
+
return `Enter a date on or after ${show(minValue)}`;
|
|
40
|
+
if (maxValue && value.compare(maxValue) > 0)
|
|
41
|
+
return `Enter a date on or before ${show(maxValue)}`;
|
|
42
|
+
if (isDateUnavailable?.(value, null))
|
|
43
|
+
return `${show(value)} isn't available. Choose another date`;
|
|
44
|
+
return null;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** A date typed in parts. Best for dates people know without looking — a date of birth, an expiry date. */
|
|
48
|
+
export function DateField({ label, description, errorMessage, requiredMessage, validate, width = 'sm', className, ...props }) {
|
|
49
|
+
const limits = useLimitMessages(props.minValue, props.maxValue, props.isDateUnavailable);
|
|
50
|
+
const required = requiredMessage ?? `Enter ${lcFirst(label)}`;
|
|
51
|
+
return (_jsxs(RACDateField, { ...props, validate: withRequired(props.isRequired, required, (v) => v == null, (v) => validate?.(v) ?? limits(v)), className: cn(fieldStack, fieldWidths[width], className), children: [_jsx(FieldLabel, { isRequired: props.isRequired, children: label }), description && _jsx(FieldDescription, { children: description }), _jsx(FieldError, { requiredMessage: required, children: errorMessage }), _jsx(Segments, { className: cn(boxStyles, 'px-(--control-pad-x)') })] }));
|
|
52
|
+
}
|
|
53
|
+
/** A time typed in parts. The hour cycle (12 or 24) follows the locale unless `hourCycle` is set. */
|
|
54
|
+
export function TimeField({ label, description, errorMessage, requiredMessage, validate, width = 'sm', className, ...props }) {
|
|
55
|
+
const required = requiredMessage ?? `Enter ${lcFirst(label)}`;
|
|
56
|
+
return (_jsxs(RACTimeField, { ...props, validate: withRequired(props.isRequired, required, (v) => v == null, validate), className: cn(fieldStack, fieldWidths[width], className), children: [_jsx(FieldLabel, { isRequired: props.isRequired, children: label }), description && _jsx(FieldDescription, { children: description }), _jsx(FieldError, { requiredMessage: required, children: errorMessage }), _jsx(Segments, { className: cn(boxStyles, 'px-(--control-pad-x)') })] }));
|
|
57
|
+
}
|
|
58
|
+
function PickerButton() {
|
|
59
|
+
// React Aria names it ("Calendar", localised) and wires it to the popover. The painted button stays 4px
|
|
60
|
+
// from the box's edge at every level; the target grows inwards.
|
|
61
|
+
return (_jsx(Button, { variant: "ghost", visualSize: "icon-sm", className: "ms-auto me-1 justify-end", visualClassName: "text-muted-foreground group-data-hovered/button:text-foreground", children: _jsx(CalendarDays, { "aria-hidden": "true" }) }));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A date typed in parts, with a calendar for dates people need to see in context — a due date, a booking.
|
|
65
|
+
* The calendar is an alternative, never the only way in: everything can be typed.
|
|
66
|
+
*/
|
|
67
|
+
export function DatePicker({ label, description, errorMessage, requiredMessage, validate, width = 'sm', className, ...props }) {
|
|
68
|
+
const limits = useLimitMessages(props.minValue, props.maxValue, props.isDateUnavailable);
|
|
69
|
+
const required = requiredMessage ?? `Enter ${lcFirst(label)}`;
|
|
70
|
+
return (_jsxs(RACDatePicker, { ...props, validate: withRequired(props.isRequired, required, (v) => v == null, (v) => validate?.(v) ?? limits(v)), className: cn(fieldStack, fieldWidths[width], className), children: [_jsx(FieldLabel, { isRequired: props.isRequired, children: label }), description && _jsx(FieldDescription, { children: description }), _jsx(FieldError, { requiredMessage: required, children: errorMessage }), _jsxs(Group, { className: boxStyles, children: [_jsx(Segments, { className: "ps-(--control-pad-x)" }), _jsx(PickerButton, {})] }), _jsx(Popover, { placement: "bottom end", className: "min-w-0 p-3", children: _jsx(RACDialog, { className: "outline-none", children: _jsx(Calendar, {}) }) })] }));
|
|
71
|
+
}
|
|
72
|
+
/** A start and an end date, each typed in parts, with a two-click range calendar. */
|
|
73
|
+
export function DateRangePicker({ label, description, errorMessage, requiredMessage, validate, width = 'md', className, ...props }) {
|
|
74
|
+
const limits = useLimitMessages(props.minValue, props.maxValue, props.isDateUnavailable);
|
|
75
|
+
const required = requiredMessage ?? `Enter ${lcFirst(label)}`;
|
|
76
|
+
return (_jsxs(RACDateRangePicker, { ...props, validate: withRequired(props.isRequired, required, (v) => !v?.start || !v?.end, (v) => validate?.(v) ?? (v ? (limits(v.start) ?? limits(v.end)) : null)), className: cn(fieldStack, fieldWidths[width], className), children: [_jsx(FieldLabel, { isRequired: props.isRequired, children: label }), description && _jsx(FieldDescription, { children: description }), _jsx(FieldError, { requiredMessage: required, children: errorMessage }), _jsxs(Group, { className: boxStyles, children: [_jsx(Segments, { slot: "start", className: "ps-(--control-pad-x)" }), _jsx("span", { "aria-hidden": "true", className: "flex items-center px-2 text-muted-foreground", children: "\u2013" }), _jsx(Segments, { slot: "end" }), _jsx(PickerButton, {})] }), _jsx(Popover, { placement: "bottom end", className: "min-w-0 p-3", children: _jsx(RACDialog, { className: "outline-none", children: _jsx(RangeCalendar, {}) }) })] }));
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=date-field.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-field.js","sourceRoot":"","sources":["../../src/ui/date-field.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export interface DialogProps {
|
|
3
|
+
isOpen: boolean;
|
|
4
|
+
onOpenChange: (open: boolean) => void;
|
|
5
|
+
title: string;
|
|
6
|
+
/** One or two sentences under the title; read as the dialog's description. */
|
|
7
|
+
description?: ReactNode;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
footer?: ReactNode;
|
|
10
|
+
/** 'alertdialog' for confirmations that interrupt. */
|
|
11
|
+
role?: 'dialog' | 'alertdialog';
|
|
12
|
+
/** Backdrop click and the × close it. Default true; false for confirmations. Escape always closes. */
|
|
13
|
+
isDismissable?: boolean;
|
|
14
|
+
size?: 'sm' | 'md' | 'lg';
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
/** A centred modal: focus moves in and is trapped, Escape closes, focus returns to what opened it. */
|
|
18
|
+
export declare function Dialog({ isOpen, onOpenChange, title, description, children, footer, role, isDismissable, size, className, }: DialogProps): import("react").JSX.Element;
|
|
19
|
+
export interface ConfirmDialogProps {
|
|
20
|
+
isOpen: boolean;
|
|
21
|
+
onOpenChange: (open: boolean) => void;
|
|
22
|
+
/** A question that names the thing: "Delete Billing redesign?" */
|
|
23
|
+
title: string;
|
|
24
|
+
/** What happens, what is lost, whether it can be undone. */
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
/** A verb phrase that repeats the action: "Delete project" — never "OK" or "Yes". */
|
|
27
|
+
confirmLabel: string;
|
|
28
|
+
cancelLabel?: string;
|
|
29
|
+
tone?: 'danger' | 'default';
|
|
30
|
+
/** For the riskiest actions: the exact text to type before confirming (the project's name). */
|
|
31
|
+
confirmText?: string;
|
|
32
|
+
/** May return a promise: the button shows pending, and a thrown Error is shown inside the dialog. */
|
|
33
|
+
onConfirm: () => void | Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Confirms an action that cannot be undone: the "confirmed" option of WCAG 3.3.4 (AA) and 3.3.6 (AAA).
|
|
37
|
+
* role=alertdialog, not dismissed by the backdrop; focus starts on Cancel, or the confirm-text field.
|
|
38
|
+
* Anything reversible should skip this and offer Undo in a toast instead.
|
|
39
|
+
*/
|
|
40
|
+
export declare function ConfirmDialog({ isOpen, onOpenChange, title, children, confirmLabel, cancelLabel, tone, confirmText, onConfirm, }: ConfirmDialogProps): import("react").JSX.Element;
|
|
41
|
+
//# sourceMappingURL=dialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../src/ui/dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AASxD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,sDAAsD;IACtD,IAAI,CAAC,EAAE,QAAQ,GAAG,aAAa,CAAC;IAChC,sGAAsG;IACtG,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,sGAAsG;AACtG,wBAAgB,MAAM,CAAC,EACrB,MAAM,EACN,YAAY,EACZ,KAAK,EACL,WAAW,EACX,QAAQ,EACR,MAAM,EACN,IAAe,EACf,aAAoB,EACpB,IAAW,EACX,SAAS,GACV,EAAE,WAAW,+BAuDb;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,QAAQ,EAAE,SAAS,CAAC;IACpB,qFAAqF;IACrF,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC5B,+FAA+F;IAC/F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qGAAqG;IACrG,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,WAAsB,EACtB,IAAe,EACf,WAAW,EACX,SAAS,GACV,EAAE,kBAAkB,+BA2FpB"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useId, useState } from 'react';
|
|
4
|
+
import { Dialog as RACDialog, Heading, Modal, ModalOverlay } from 'react-aria-components';
|
|
5
|
+
import { X } from 'lucide-react';
|
|
6
|
+
import { cn } from '../lib/cn.js';
|
|
7
|
+
import { Alert } from './alert.js';
|
|
8
|
+
import { Button } from './button.js';
|
|
9
|
+
import { IconButton } from './icon-button.js';
|
|
10
|
+
import { TextField } from './text-field.js';
|
|
11
|
+
const widths = { sm: 'max-w-[26rem]', md: 'max-w-[32rem]', lg: 'max-w-[44rem]' };
|
|
12
|
+
/** A centred modal: focus moves in and is trapped, Escape closes, focus returns to what opened it. */
|
|
13
|
+
export function Dialog({ isOpen, onOpenChange, title, description, children, footer, role = 'dialog', isDismissable = true, size = 'md', className, }) {
|
|
14
|
+
const descId = useId();
|
|
15
|
+
return (_jsx(ModalOverlay, { isOpen: isOpen, onOpenChange: onOpenChange, isDismissable: isDismissable, "data-overlay": true, className: "fixed inset-0 z-(--z-sheet) flex items-center justify-center bg-overlay p-4", children: _jsx(Modal, { "data-sheet": "top", className: cn('relative max-h-[calc(100dvh-2rem)] w-full overflow-auto rounded-xl border border-border bg-popover text-popover-foreground shadow-(--shadow-lg) outline-none', widths[size], className), children: _jsxs(RACDialog, { role: role, "aria-describedby": description ? descId : undefined, className: "flex flex-col outline-none", children: [_jsxs("div", { className: "flex items-start justify-between gap-3 px-5 pt-5", children: [_jsx(Heading, { slot: "title", className: "text-heading", children: title }), isDismissable && (_jsx(IconButton, { label: "Close", icon: X, visualSize: "icon-sm", slot: "close", tooltip: false, className: "-mt-1 -mr-2 items-start justify-end" }))] }), _jsxs("div", { className: "flex flex-col gap-4 px-5 pt-2 pb-5 text-sm leading-6", children: [description && (_jsx("div", { id: descId, className: "max-w-(--measure) text-muted-foreground", children: description })), children] }), footer && (_jsx("div", { className: "flex flex-wrap items-center justify-end gap-(--control-gap) border-t border-border px-5 py-4", children: footer }))] }) }) }));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Confirms an action that cannot be undone: the "confirmed" option of WCAG 3.3.4 (AA) and 3.3.6 (AAA).
|
|
19
|
+
* role=alertdialog, not dismissed by the backdrop; focus starts on Cancel, or the confirm-text field.
|
|
20
|
+
* Anything reversible should skip this and offer Undo in a toast instead.
|
|
21
|
+
*/
|
|
22
|
+
export function ConfirmDialog({ isOpen, onOpenChange, title, children, confirmLabel, cancelLabel = 'Cancel', tone = 'danger', confirmText, onConfirm, }) {
|
|
23
|
+
const [typed, setTyped] = useState('');
|
|
24
|
+
const [mismatch, setMismatch] = useState(false);
|
|
25
|
+
const [pending, setPending] = useState(false);
|
|
26
|
+
const [error, setError] = useState(null);
|
|
27
|
+
const fieldId = useId();
|
|
28
|
+
// Start clean each time it opens (adjusting state during render, not in an effect).
|
|
29
|
+
const [wasOpen, setWasOpen] = useState(isOpen);
|
|
30
|
+
if (isOpen !== wasOpen) {
|
|
31
|
+
setWasOpen(isOpen);
|
|
32
|
+
if (isOpen) {
|
|
33
|
+
setTyped('');
|
|
34
|
+
setMismatch(false);
|
|
35
|
+
setError(null);
|
|
36
|
+
setPending(false);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const run = async () => {
|
|
40
|
+
if (confirmText && typed.trim() !== confirmText) {
|
|
41
|
+
setMismatch(true);
|
|
42
|
+
// Like a failed form submit: focus goes to the field that needs fixing.
|
|
43
|
+
requestAnimationFrame(() => document.getElementById(fieldId)?.focus());
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
setPending(true);
|
|
47
|
+
setError(null);
|
|
48
|
+
try {
|
|
49
|
+
await onConfirm();
|
|
50
|
+
onOpenChange(false);
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
setError(e instanceof Error && e.message
|
|
54
|
+
? e.message
|
|
55
|
+
: "That didn't work. Check your connection and try again.");
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
setPending(false);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
return (_jsxs(Dialog, { isOpen: isOpen, onOpenChange: (open) => !pending && onOpenChange(open), title: title, role: "alertdialog", isDismissable: false, description: children, footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "ghost", slot: "close", autoFocus: !confirmText, isDisabled: pending, children: cancelLabel }), _jsx(Button, { variant: tone === 'danger' ? 'destructive' : 'primary', isPending: pending, onPress: run, children: confirmLabel })] }), children: [confirmText && (_jsx(TextField, { id: fieldId, label: `Type ${confirmText} to confirm`, value: typed, onChange: (v) => {
|
|
62
|
+
setTyped(v);
|
|
63
|
+
setMismatch(false);
|
|
64
|
+
},
|
|
65
|
+
// Type-to-confirm: the field is the dialog's first task, so it takes focus when the dialog opens.
|
|
66
|
+
// oxlint-disable-next-line jsx-a11y/no-autofocus
|
|
67
|
+
autoFocus: true, autoComplete: "off", spellCheck: "false", isInvalid: mismatch, errorMessage: `Type ${confirmText} exactly, including capitals` })), error && (_jsx(Alert, { tone: "danger", live: "assertive", title: `${confirmLabel} didn't work`, children: error }))] }));
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=dialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialog.js","sourceRoot":"","sources":["../../src/ui/dialog.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { type DisclosureProps as RACDisclosureProps } from 'react-aria-components';
|
|
3
|
+
export interface DisclosureProps extends Omit<RACDisclosureProps, 'children' | 'className'> {
|
|
4
|
+
/** The trigger's label: what the panel holds, such as the question it answers. */
|
|
5
|
+
title: ReactNode;
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
/** The heading the trigger sits in, so the page's outline has it. Default 3. */
|
|
8
|
+
headingLevel?: 2 | 3 | 4;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A heading that shows and hides what's under it: questions and answers, or detail most people skip. React
|
|
13
|
+
* Aria's Disclosure, with the trigger in three layers: the button is the target (the full width, at least
|
|
14
|
+
* --target-min tall), the span inside it the paint, and the title and chevron the content. The chevron turns
|
|
15
|
+
* without animating.
|
|
16
|
+
*/
|
|
17
|
+
export declare function Disclosure({ title, children, headingLevel, className, ...props }: DisclosureProps): import("react").JSX.Element;
|
|
18
|
+
//# sourceMappingURL=disclosure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disclosure.d.ts","sourceRoot":"","sources":["../../src/ui/disclosure.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAKL,KAAK,eAAe,IAAI,kBAAkB,EAC3C,MAAM,uBAAuB,CAAC;AAG/B,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,WAAW,CAAC;IACzF,kFAAkF;IAClF,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,gFAAgF;IAChF,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,YAAgB,EAChB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,eAAe,+BAoBjB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ChevronDown } from 'lucide-react';
|
|
4
|
+
import { Button as RACButton, Disclosure as RACDisclosure, DisclosurePanel, Heading, } from 'react-aria-components';
|
|
5
|
+
import { cn } from '../lib/cn.js';
|
|
6
|
+
/**
|
|
7
|
+
* A heading that shows and hides what's under it: questions and answers, or detail most people skip. React
|
|
8
|
+
* Aria's Disclosure, with the trigger in three layers: the button is the target (the full width, at least
|
|
9
|
+
* --target-min tall), the span inside it the paint, and the title and chevron the content. The chevron turns
|
|
10
|
+
* without animating.
|
|
11
|
+
*/
|
|
12
|
+
export function Disclosure({ title, children, headingLevel = 3, className, ...props }) {
|
|
13
|
+
return (_jsxs(RACDisclosure, { ...props, className: cn('group/disclosure border-b border-border', className), children: [_jsx(Heading, { level: headingLevel, className: "m-0", children: _jsx(RACButton, { slot: "trigger", className: "group/disclosure-trigger flex min-h-target w-full cursor-pointer items-center text-left outline-none", children: _jsxs("span", { className: "flex min-h-control w-full items-center justify-between gap-3 rounded-md px-2 text-subheading group-data-hovered/disclosure-trigger:bg-accent group-data-focus-visible/disclosure-trigger:focus-ring", children: [title, _jsx(ChevronDown, { "aria-hidden": "true", className: "size-5 shrink-0 group-data-expanded/disclosure:rotate-180" })] }) }) }), _jsx(DisclosurePanel, { className: "px-2 pb-4 text-body", children: children })] }));
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=disclosure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disclosure.js","sourceRoot":"","sources":["../../src/ui/disclosure.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EACL,MAAM,IAAI,SAAS,EACnB,UAAU,IAAI,aAAa,EAC3B,eAAe,EACf,OAAO,GAER,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAWlC;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,YAAY,GAAG,CAAC,EAChB,SAAS,EACT,GAAG,KAAK,EACQ;IAChB,OAAO,CACL,MAAC,aAAa,OAAK,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,yCAAyC,EAAE,SAAS,CAAC,aAC3F,KAAC,OAAO,IAAC,KAAK,EAAE,YAAY,EAAE,SAAS,EAAC,KAAK,YAC3C,KAAC,SAAS,IACR,IAAI,EAAC,SAAS,EACd,SAAS,EAAC,sGAAsG,YAEhH,gBAAM,SAAS,EAAC,qMAAqM,aAClN,KAAK,EACN,KAAC,WAAW,mBACE,MAAM,EAClB,SAAS,EAAC,2DAA2D,GACrE,IACG,GACG,GACJ,EACV,KAAC,eAAe,IAAC,SAAS,EAAC,qBAAqB,YAAE,QAAQ,GAAmB,IAC/D,CACjB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { type IconProp } from './icon.js';
|
|
3
|
+
export interface EmptyStateProps {
|
|
4
|
+
icon?: IconProp;
|
|
5
|
+
/** What is empty and why, in plain words: "No projects yet", "No projects match 'bill'". */
|
|
6
|
+
title: string;
|
|
7
|
+
/** What this place is for, or what to try. */
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
/** The next step — usually one primary button, sometimes a secondary link. */
|
|
10
|
+
actions?: ReactNode;
|
|
11
|
+
headingLevel?: 2 | 3;
|
|
12
|
+
size?: 'page' | 'section';
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
/** Nothing to show yet, or nothing matches. Always explains and offers the next step. */
|
|
16
|
+
export declare function EmptyState({ icon, title, children, actions, headingLevel, size, className, }: EmptyStateProps): import("react").JSX.Element;
|
|
17
|
+
//# sourceMappingURL=empty-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"empty-state.d.ts","sourceRoot":"","sources":["../../src/ui/empty-state.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,4FAA4F;IAC5F,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,OAAO,EACP,YAAgB,EAChB,IAAa,EACb,SAAS,GACV,EAAE,eAAe,+BAgCjB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '../lib/cn.js';
|
|
3
|
+
import { renderIcon } from './icon.js';
|
|
4
|
+
/** Nothing to show yet, or nothing matches. Always explains and offers the next step. */
|
|
5
|
+
export function EmptyState({ icon, title, children, actions, headingLevel = 2, size = 'page', className, }) {
|
|
6
|
+
const H = headingLevel === 3 ? 'h3' : 'h2';
|
|
7
|
+
return (_jsxs("div", { className: cn('mx-auto flex max-w-(--measure) flex-col items-center px-6 text-center', size === 'page' ? 'py-16' : 'py-10', className), children: [icon && (_jsx("span", { "aria-hidden": "true", className: cn('mb-4 grid place-items-center rounded-full bg-muted text-muted-foreground', size === 'page' ? 'size-14' : 'size-11'), children: renderIcon(icon, size === 'page' ? 'size-7' : 'size-5') })), _jsx(H, { className: size === 'page' ? 'text-heading' : 'text-subheading', children: title }), children && (_jsx("div", { className: "mt-2 text-[15px] leading-6 text-muted-foreground", children: children })), actions && (_jsx("div", { className: "mt-6 flex flex-wrap items-center justify-center gap-(--control-gap)", children: actions }))] }));
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=empty-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"empty-state.js","sourceRoot":"","sources":["../../src/ui/empty-state.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,UAAU,EAAiB,MAAM,WAAW,CAAC;AAetD,yFAAyF;AACzF,MAAM,UAAU,UAAU,CAAC,EACzB,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,OAAO,EACP,YAAY,GAAG,CAAC,EAChB,IAAI,GAAG,MAAM,EACb,SAAS,GACO;IAChB,MAAM,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3C,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CACX,uEAAuE,EACvE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EACnC,SAAS,CACV,aAEA,IAAI,IAAI,CACP,8BACc,MAAM,EAClB,SAAS,EAAE,EAAE,CACX,0EAA0E,EAC1E,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CACxC,YAEA,UAAU,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GACnD,CACR,EACD,KAAC,CAAC,IAAC,SAAS,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,iBAAiB,YAAG,KAAK,GAAK,EAC9E,QAAQ,IAAI,CACX,cAAK,SAAS,EAAC,kDAAkD,YAAE,QAAQ,GAAO,CACnF,EACA,OAAO,IAAI,CACV,cAAK,SAAS,EAAC,qEAAqE,YACjF,OAAO,GACJ,CACP,IACG,CACP,CAAC;AACJ,CAAC"}
|