@cueplusplus/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/dist/charts/_token.js +39 -0
- package/dist/charts/container.d.ts +58 -0
- package/dist/charts/container.js +77 -0
- package/dist/charts/index.d.ts +5 -0
- package/dist/charts/index.js +5 -0
- package/dist/charts/ramps.d.ts +140 -0
- package/dist/charts/ramps.js +615 -0
- package/dist/charts/theme.d.ts +112 -0
- package/dist/charts/theme.js +165 -0
- package/dist/charts/tones.d.ts +111 -0
- package/dist/charts/tones.js +127 -0
- package/dist/chat/_glyphs.js +55 -0
- package/dist/chat/agent-color.d.ts +84 -0
- package/dist/chat/agent-color.js +101 -0
- package/dist/chat/agent-pile.d.ts +55 -0
- package/dist/chat/agent-pile.js +121 -0
- package/dist/chat/ask-box.d.ts +88 -0
- package/dist/chat/ask-box.js +341 -0
- package/dist/chat/composer.d.ts +66 -0
- package/dist/chat/composer.js +144 -0
- package/dist/chat/delegation-card.d.ts +60 -0
- package/dist/chat/delegation-card.js +129 -0
- package/dist/chat/index.d.ts +8 -0
- package/dist/chat/index.js +8 -0
- package/dist/chat/message-list.d.ts +39 -0
- package/dist/chat/message-list.js +105 -0
- package/dist/chat/message.d.ts +47 -0
- package/dist/chat/message.js +108 -0
- package/dist/chrome/_glyphs.js +101 -0
- package/dist/chrome/_tabs-scroll.d.ts +62 -0
- package/dist/chrome/_tabs-scroll.js +68 -0
- package/dist/chrome/_tree.d.ts +75 -0
- package/dist/chrome/_tree.js +49 -0
- package/dist/chrome/empty-state.d.ts +37 -0
- package/dist/chrome/empty-state.js +57 -0
- package/dist/chrome/eyebrow.d.ts +29 -0
- package/dist/chrome/eyebrow.js +36 -0
- package/dist/chrome/index.d.ts +17 -0
- package/dist/chrome/index.js +17 -0
- package/dist/chrome/navigation-menu.d.ts +80 -0
- package/dist/chrome/navigation-menu.js +121 -0
- package/dist/chrome/page-shell.d.ts +38 -0
- package/dist/chrome/page-shell.js +66 -0
- package/dist/chrome/panel.d.ts +55 -0
- package/dist/chrome/panel.js +67 -0
- package/dist/chrome/row.d.ts +82 -0
- package/dist/chrome/row.js +106 -0
- package/dist/chrome/scroll-area.d.ts +39 -0
- package/dist/chrome/scroll-area.js +70 -0
- package/dist/chrome/section-header.d.ts +42 -0
- package/dist/chrome/section-header.js +79 -0
- package/dist/chrome/segmented-control.d.ts +58 -0
- package/dist/chrome/segmented-control.js +76 -0
- package/dist/chrome/status-bar.d.ts +46 -0
- package/dist/chrome/status-bar.js +56 -0
- package/dist/chrome/tabs.d.ts +80 -0
- package/dist/chrome/tabs.js +176 -0
- package/dist/chrome/title-bar.d.ts +37 -0
- package/dist/chrome/title-bar.js +45 -0
- package/dist/chrome/toolbar.d.ts +46 -0
- package/dist/chrome/toolbar.js +62 -0
- package/dist/chrome/tree.d.ts +98 -0
- package/dist/chrome/tree.js +248 -0
- package/dist/color/_checker.js +14 -0
- package/dist/color/_convert.d.ts +52 -0
- package/dist/color/_convert.js +66 -0
- package/dist/color/_glyphs.js +28 -0
- package/dist/color/_thumb.js +15 -0
- package/dist/color/_value.js +28 -0
- package/dist/color/color-area.d.ts +27 -0
- package/dist/color/color-area.js +40 -0
- package/dist/color/color-field.d.ts +32 -0
- package/dist/color/color-field.js +43 -0
- package/dist/color/color-picker.d.ts +71 -0
- package/dist/color/color-picker.js +178 -0
- package/dist/color/color-slider.d.ts +31 -0
- package/dist/color/color-slider.js +51 -0
- package/dist/color/color-swatch.d.ts +32 -0
- package/dist/color/color-swatch.js +44 -0
- package/dist/color/index.d.ts +7 -0
- package/dist/color/index.js +7 -0
- package/dist/configurator/_export.d.ts +78 -0
- package/dist/configurator/_export.js +261 -0
- package/dist/configurator/_glyphs.js +92 -0
- package/dist/configurator/_overrides.d.ts +247 -0
- package/dist/configurator/_overrides.js +514 -0
- package/dist/configurator/configurator.d.ts +71 -0
- package/dist/configurator/configurator.js +279 -0
- package/dist/configurator/export-dialog.d.ts +30 -0
- package/dist/configurator/export-dialog.js +121 -0
- package/dist/configurator/index.d.ts +8 -0
- package/dist/configurator/index.js +8 -0
- package/dist/configurator/panel-sections.d.ts +86 -0
- package/dist/configurator/panel-sections.js +316 -0
- package/dist/configurator/token-editor.d.ts +74 -0
- package/dist/configurator/token-editor.js +149 -0
- package/dist/configurator/use-zoom.d.ts +87 -0
- package/dist/configurator/use-zoom.js +113 -0
- package/dist/date/_glyphs.js +34 -0
- package/dist/date/_segments.js +55 -0
- package/dist/date/_trigger.js +31 -0
- package/dist/date/calendar.d.ts +25 -0
- package/dist/date/calendar.js +125 -0
- package/dist/date/date-field.d.ts +34 -0
- package/dist/date/date-field.js +41 -0
- package/dist/date/date-picker.d.ts +69 -0
- package/dist/date/date-picker.js +89 -0
- package/dist/date/date-range-picker.d.ts +65 -0
- package/dist/date/date-range-picker.js +92 -0
- package/dist/date/index.d.ts +6 -0
- package/dist/date/index.js +6 -0
- package/dist/date/time-field.d.ts +29 -0
- package/dist/date/time-field.js +36 -0
- package/dist/dmx/_ramp.d.ts +77 -0
- package/dist/dmx/_ramp.js +169 -0
- package/dist/dmx/_readout.js +53 -0
- package/dist/dmx/_universe.d.ts +105 -0
- package/dist/dmx/_universe.js +112 -0
- package/dist/dmx/channel-matrix.d.ts +81 -0
- package/dist/dmx/channel-matrix.js +285 -0
- package/dist/dmx/dmx-bar.d.ts +50 -0
- package/dist/dmx/dmx-bar.js +107 -0
- package/dist/dmx/dmx-strip.d.ts +41 -0
- package/dist/dmx/dmx-strip.js +196 -0
- package/dist/dmx/index.d.ts +7 -0
- package/dist/dmx/index.js +7 -0
- package/dist/dmx/universe-grid.d.ts +61 -0
- package/dist/dmx/universe-grid.js +182 -0
- package/dist/flow/_frame.d.ts +52 -0
- package/dist/flow/_frame.js +38 -0
- package/dist/flow/controls.d.ts +41 -0
- package/dist/flow/controls.js +53 -0
- package/dist/flow/flow.css +121 -0
- package/dist/flow/handles.d.ts +40 -0
- package/dist/flow/handles.js +61 -0
- package/dist/flow/index.d.ts +7 -0
- package/dist/flow/index.js +7 -0
- package/dist/flow/node-card.d.ts +71 -0
- package/dist/flow/node-card.js +102 -0
- package/dist/flow/signal-edge.d.ts +60 -0
- package/dist/flow/signal-edge.js +108 -0
- package/dist/flow/use-flow-theme.d.ts +69 -0
- package/dist/flow/use-flow-theme.js +109 -0
- package/dist/forms/_chassis.d.ts +64 -0
- package/dist/forms/_chassis.js +59 -0
- package/dist/forms/_glyphs.js +143 -0
- package/dist/forms/_listbox.js +55 -0
- package/dist/forms/autocomplete.d.ts +61 -0
- package/dist/forms/autocomplete.js +88 -0
- package/dist/forms/button-group.d.ts +47 -0
- package/dist/forms/button-group.js +52 -0
- package/dist/forms/checkbox.d.ts +51 -0
- package/dist/forms/checkbox.js +98 -0
- package/dist/forms/combobox.d.ts +73 -0
- package/dist/forms/combobox.js +108 -0
- package/dist/forms/env-var-input.d.ts +74 -0
- package/dist/forms/env-var-input.js +116 -0
- package/dist/forms/field.d.ts +89 -0
- package/dist/forms/field.js +102 -0
- package/dist/forms/file-upload.d.ts +113 -0
- package/dist/forms/file-upload.js +232 -0
- package/dist/forms/index.d.ts +26 -0
- package/dist/forms/index.js +26 -0
- package/dist/forms/input-group.d.ts +31 -0
- package/dist/forms/input-group.js +54 -0
- package/dist/forms/input.d.ts +33 -0
- package/dist/forms/input.js +36 -0
- package/dist/forms/multi-select.d.ts +62 -0
- package/dist/forms/multi-select.js +107 -0
- package/dist/forms/number-field.d.ts +38 -0
- package/dist/forms/number-field.js +64 -0
- package/dist/forms/otp-field.d.ts +54 -0
- package/dist/forms/otp-field.js +59 -0
- package/dist/forms/password-input.d.ts +46 -0
- package/dist/forms/password-input.js +62 -0
- package/dist/forms/radio-group.d.ts +50 -0
- package/dist/forms/radio-group.js +64 -0
- package/dist/forms/rating.d.ts +69 -0
- package/dist/forms/rating.js +103 -0
- package/dist/forms/scrub-input.d.ts +81 -0
- package/dist/forms/scrub-input.js +249 -0
- package/dist/forms/search-input.d.ts +54 -0
- package/dist/forms/search-input.js +112 -0
- package/dist/forms/select.d.ts +75 -0
- package/dist/forms/select.js +91 -0
- package/dist/forms/slider.d.ts +44 -0
- package/dist/forms/slider.js +65 -0
- package/dist/forms/switch.d.ts +36 -0
- package/dist/forms/switch.js +71 -0
- package/dist/forms/tags-input.d.ts +69 -0
- package/dist/forms/tags-input.js +148 -0
- package/dist/forms/textarea.d.ts +27 -0
- package/dist/forms/textarea.js +37 -0
- package/dist/forms/toggle-group.d.ts +41 -0
- package/dist/forms/toggle-group.js +56 -0
- package/dist/forms/toggle.d.ts +41 -0
- package/dist/forms/toggle.js +100 -0
- package/dist/index.d.ts +112 -0
- package/dist/index.js +104 -0
- package/dist/instruments/_ansi.js +116 -0
- package/dist/instruments/_glyphs.js +90 -0
- package/dist/instruments/_motion.js +56 -0
- package/dist/instruments/_rem.js +21 -0
- package/dist/instruments/app-window-frame.d.ts +48 -0
- package/dist/instruments/app-window-frame.js +76 -0
- package/dist/instruments/copy-button.d.ts +41 -0
- package/dist/instruments/copy-button.js +112 -0
- package/dist/instruments/data-table.d.ts +168 -0
- package/dist/instruments/data-table.js +212 -0
- package/dist/instruments/group-bar.d.ts +63 -0
- package/dist/instruments/group-bar.js +122 -0
- package/dist/instruments/index.d.ts +13 -0
- package/dist/instruments/index.js +13 -0
- package/dist/instruments/log-viewer.d.ts +74 -0
- package/dist/instruments/log-viewer.js +215 -0
- package/dist/instruments/meter.d.ts +77 -0
- package/dist/instruments/meter.js +96 -0
- package/dist/instruments/progress.d.ts +45 -0
- package/dist/instruments/progress.js +61 -0
- package/dist/instruments/seam-grid.d.ts +66 -0
- package/dist/instruments/seam-grid.js +78 -0
- package/dist/instruments/sparkline.d.ts +39 -0
- package/dist/instruments/sparkline.js +85 -0
- package/dist/instruments/stat.d.ts +35 -0
- package/dist/instruments/stat.js +59 -0
- package/dist/instruments/table.d.ts +51 -0
- package/dist/instruments/table.js +92 -0
- package/dist/instruments/terminal-frame.d.ts +89 -0
- package/dist/instruments/terminal-frame.js +256 -0
- package/dist/instruments/two-step-button.d.ts +47 -0
- package/dist/instruments/two-step-button.js +147 -0
- package/dist/instruments/usage-chart.d.ts +55 -0
- package/dist/instruments/usage-chart.js +235 -0
- package/dist/layout/_collapse.js +46 -0
- package/dist/layout/_glyphs.js +45 -0
- package/dist/layout/accordion.d.ts +52 -0
- package/dist/layout/accordion.js +81 -0
- package/dist/layout/breadcrumb.d.ts +35 -0
- package/dist/layout/breadcrumb.js +67 -0
- package/dist/layout/card.d.ts +51 -0
- package/dist/layout/card.js +76 -0
- package/dist/layout/carousel.d.ts +96 -0
- package/dist/layout/carousel.js +211 -0
- package/dist/layout/collapsible.d.ts +74 -0
- package/dist/layout/collapsible.js +126 -0
- package/dist/layout/container.d.ts +27 -0
- package/dist/layout/container.js +40 -0
- package/dist/layout/description-list.d.ts +24 -0
- package/dist/layout/description-list.js +37 -0
- package/dist/layout/grid.d.ts +40 -0
- package/dist/layout/grid.js +48 -0
- package/dist/layout/index.d.ts +15 -0
- package/dist/layout/index.js +15 -0
- package/dist/layout/item.d.ts +65 -0
- package/dist/layout/item.js +100 -0
- package/dist/layout/link.d.ts +48 -0
- package/dist/layout/link.js +63 -0
- package/dist/layout/pagination.d.ts +54 -0
- package/dist/layout/pagination.js +121 -0
- package/dist/layout/resizable.d.ts +38 -0
- package/dist/layout/resizable.js +68 -0
- package/dist/layout/sidebar.d.ts +67 -0
- package/dist/layout/sidebar.js +129 -0
- package/dist/layout/stack.d.ts +46 -0
- package/dist/layout/stack.js +62 -0
- package/dist/layout/stepper.d.ts +49 -0
- package/dist/layout/stepper.js +81 -0
- package/dist/layout/timeline.d.ts +43 -0
- package/dist/layout/timeline.js +63 -0
- package/dist/lib/aria-class.js +24 -0
- package/dist/lib/cn.js +18 -0
- package/dist/lib/compose.js +38 -0
- package/dist/lib/cva.d.ts +18 -0
- package/dist/lib/cva.js +65 -0
- package/dist/midi/_notes.d.ts +101 -0
- package/dist/midi/_notes.js +183 -0
- package/dist/midi/_ruler.d.ts +100 -0
- package/dist/midi/_ruler.js +105 -0
- package/dist/midi/_time.d.ts +107 -0
- package/dist/midi/_time.js +130 -0
- package/dist/midi/index.d.ts +9 -0
- package/dist/midi/index.js +9 -0
- package/dist/midi/musical-time-input.d.ts +48 -0
- package/dist/midi/musical-time-input.js +154 -0
- package/dist/midi/piano-keyboard.d.ts +50 -0
- package/dist/midi/piano-keyboard.js +193 -0
- package/dist/midi/spectrum-visualizer.d.ts +65 -0
- package/dist/midi/spectrum-visualizer.js +213 -0
- package/dist/midi/threshold-rail.d.ts +72 -0
- package/dist/midi/threshold-rail.js +214 -0
- package/dist/midi/timeline-ruler.d.ts +83 -0
- package/dist/midi/timeline-ruler.js +152 -0
- package/dist/overlays/_debounce.js +34 -0
- package/dist/overlays/_glyphs.js +59 -0
- package/dist/overlays/_surface.d.ts +70 -0
- package/dist/overlays/_surface.js +70 -0
- package/dist/overlays/_wheel.js +42 -0
- package/dist/overlays/alert-dialog.d.ts +67 -0
- package/dist/overlays/alert-dialog.js +117 -0
- package/dist/overlays/command-palette.d.ts +93 -0
- package/dist/overlays/command-palette.js +193 -0
- package/dist/overlays/context-menu.d.ts +64 -0
- package/dist/overlays/context-menu.js +78 -0
- package/dist/overlays/dialog.d.ts +72 -0
- package/dist/overlays/dialog.js +124 -0
- package/dist/overlays/drawer.d.ts +75 -0
- package/dist/overlays/drawer.js +151 -0
- package/dist/overlays/dropdown-menu.d.ts +79 -0
- package/dist/overlays/dropdown-menu.js +156 -0
- package/dist/overlays/hover-card.d.ts +58 -0
- package/dist/overlays/hover-card.js +91 -0
- package/dist/overlays/index.d.ts +15 -0
- package/dist/overlays/index.js +15 -0
- package/dist/overlays/info-tip.d.ts +41 -0
- package/dist/overlays/info-tip.js +45 -0
- package/dist/overlays/menubar.d.ts +72 -0
- package/dist/overlays/menubar.js +100 -0
- package/dist/overlays/popover.d.ts +66 -0
- package/dist/overlays/popover.js +114 -0
- package/dist/overlays/sheet.d.ts +78 -0
- package/dist/overlays/sheet.js +131 -0
- package/dist/overlays/toast.d.ts +106 -0
- package/dist/overlays/toast.js +146 -0
- package/dist/overlays/tooltip.d.ts +57 -0
- package/dist/overlays/tooltip.js +95 -0
- package/dist/primitives/avatar.d.ts +51 -0
- package/dist/primitives/avatar.js +93 -0
- package/dist/primitives/button.d.ts +46 -0
- package/dist/primitives/button.js +94 -0
- package/dist/primitives/chip.d.ts +47 -0
- package/dist/primitives/chip.js +152 -0
- package/dist/primitives/icon-button.d.ts +41 -0
- package/dist/primitives/icon-button.js +59 -0
- package/dist/primitives/index.d.ts +10 -0
- package/dist/primitives/index.js +10 -0
- package/dist/primitives/kbd.d.ts +17 -0
- package/dist/primitives/kbd.js +24 -0
- package/dist/primitives/separator.d.ts +25 -0
- package/dist/primitives/separator.js +30 -0
- package/dist/primitives/skeleton.d.ts +20 -0
- package/dist/primitives/skeleton.js +27 -0
- package/dist/primitives/spinner.d.ts +26 -0
- package/dist/primitives/spinner.js +31 -0
- package/dist/primitives/status-dot.d.ts +44 -0
- package/dist/primitives/status-dot.js +50 -0
- package/dist/styles.css +19 -0
- package/dist/system/density.d.ts +33 -0
- package/dist/system/density.js +49 -0
- package/dist/system/index.d.ts +8 -0
- package/dist/system/index.js +7 -0
- package/dist/system/portal.d.ts +51 -0
- package/dist/system/portal.js +122 -0
- package/dist/system/prepaint.d.ts +38 -0
- package/dist/system/prepaint.js +37 -0
- package/dist/system/theme-provider.d.ts +72 -0
- package/dist/system/theme-provider.js +252 -0
- package/dist/system/use-density.d.ts +33 -0
- package/dist/system/use-density.js +84 -0
- package/dist/system/use-isomorphic-layout-effect.js +15 -0
- package/dist/system/use-theme.d.ts +19 -0
- package/dist/system/use-theme.js +25 -0
- package/dist/theming/_presets.d.ts +11 -0
- package/dist/theming/_presets.js +487 -0
- package/dist/theming/contrast.d.ts +110 -0
- package/dist/theming/contrast.js +167 -0
- package/dist/theming/create-theme.d.ts +165 -0
- package/dist/theming/create-theme.js +442 -0
- package/dist/theming/index.d.ts +5 -0
- package/dist/theming/index.js +5 -0
- package/dist/theming/serialize.d.ts +145 -0
- package/dist/theming/serialize.js +165 -0
- package/package.json +216 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { Field } from "@base-ui/react/field";
|
|
6
|
+
//#region src/forms/field.tsx
|
|
7
|
+
/**
|
|
8
|
+
* The labelling and validation wrapper every form control belongs in.
|
|
9
|
+
*
|
|
10
|
+
* Wraps Base UI's `Field.Root`, which generates the ids that tie
|
|
11
|
+
* {@link FieldLabel}, {@link FieldDescription} and {@link FieldError} to the
|
|
12
|
+
* control inside it — so `<FieldLabel>Cue name</FieldLabel>` names an
|
|
13
|
+
* {@link Input} with no `htmlFor`/`id` bookkeeping from the caller. Base UI also
|
|
14
|
+
* stamps `data-invalid` / `data-disabled` down the subtree, which is what the
|
|
15
|
+
* chassis' danger rim keys off.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* <Field name="cue">
|
|
19
|
+
* <FieldLabel>Cue name</FieldLabel>
|
|
20
|
+
* <Input placeholder="e.g. Blackout" />
|
|
21
|
+
* <FieldDescription>Shown in the cue list.</FieldDescription>
|
|
22
|
+
* <FieldError issues={result.issues} />
|
|
23
|
+
* </Field>
|
|
24
|
+
*/
|
|
25
|
+
const Field$1 = React.forwardRef(function Field$2({ className, ...elementProps }, ref) {
|
|
26
|
+
return /* @__PURE__ */ jsx(Field.Root, {
|
|
27
|
+
ref,
|
|
28
|
+
"data-slot": "field",
|
|
29
|
+
className: cn("flex w-full flex-col gap-(--cue-space-2)", className),
|
|
30
|
+
...elementProps
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* The name of a field: mono, uppercase, tracked out, one rung below body text.
|
|
35
|
+
*
|
|
36
|
+
* Renders a real `<label>` wired to the field's control, so clicking it focuses
|
|
37
|
+
* (or toggles) that control.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* <FieldLabel>Universe</FieldLabel>
|
|
41
|
+
*/
|
|
42
|
+
const FieldLabel = React.forwardRef(function FieldLabel({ className, ...elementProps }, ref) {
|
|
43
|
+
return /* @__PURE__ */ jsx(Field.Label, {
|
|
44
|
+
ref,
|
|
45
|
+
"data-slot": "field-label",
|
|
46
|
+
className: cn("font-mono text-(length:--cue-text-label) leading-none tracking-[0.1em] text-fg-muted uppercase select-none data-[disabled]:opacity-40", className),
|
|
47
|
+
...elementProps
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
/**
|
|
51
|
+
* Quiet helper text under a control, published to assistive tech as the
|
|
52
|
+
* control's `aria-describedby` target.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* <FieldDescription>1–512</FieldDescription>
|
|
56
|
+
*/
|
|
57
|
+
const FieldDescription = React.forwardRef(function FieldDescription({ className, ...elementProps }, ref) {
|
|
58
|
+
return /* @__PURE__ */ jsx(Field.Description, {
|
|
59
|
+
ref,
|
|
60
|
+
"data-slot": "field-description",
|
|
61
|
+
className: cn("font-mono text-(length:--cue-text-micro) text-fg-subtle", className),
|
|
62
|
+
...elementProps
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* The error line under a control.
|
|
67
|
+
*
|
|
68
|
+
* Two ways to drive it, and they are mutually exclusive by design:
|
|
69
|
+
* pass `issues` from a Standard Schema parse (`schema.safeParse(x).issues`) and
|
|
70
|
+
* the component owns visibility, or pass `match` + `children` and let Base UI
|
|
71
|
+
* key off the native `ValidityState`.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* <FieldError issues={result.issues} />
|
|
75
|
+
* @example
|
|
76
|
+
* <FieldError match="valueMissing">Please name the cue</FieldError>
|
|
77
|
+
*/
|
|
78
|
+
const FieldError = React.forwardRef(function FieldError({ className, issues, match, children, ...elementProps }, ref) {
|
|
79
|
+
if (issues !== void 0 && issues.length === 0) return null;
|
|
80
|
+
const classes = cn("font-mono text-(length:--cue-text-micro) text-danger", className);
|
|
81
|
+
if (issues === void 0) return /* @__PURE__ */ jsx(Field.Error, {
|
|
82
|
+
ref,
|
|
83
|
+
"data-slot": "field-error",
|
|
84
|
+
match,
|
|
85
|
+
className: classes,
|
|
86
|
+
...elementProps,
|
|
87
|
+
children
|
|
88
|
+
});
|
|
89
|
+
return /* @__PURE__ */ jsx(Field.Error, {
|
|
90
|
+
ref,
|
|
91
|
+
"data-slot": "field-error",
|
|
92
|
+
match: true,
|
|
93
|
+
className: classes,
|
|
94
|
+
...elementProps,
|
|
95
|
+
children: issues.length === 1 ? issues[0]?.message : /* @__PURE__ */ jsx("ul", {
|
|
96
|
+
className: "flex flex-col gap-(--cue-space-1)",
|
|
97
|
+
children: issues.map((issue, index) => /* @__PURE__ */ jsx("li", { children: issue.message }, `${index}:${issue.message}`))
|
|
98
|
+
})
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
//#endregion
|
|
102
|
+
export { Field$1 as Field, FieldDescription, FieldError, FieldLabel };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
//#region src/forms/file-upload.d.ts
|
|
3
|
+
/** Why a dropped file did not make it into the list. */
|
|
4
|
+
type FileRejectReason = "type" | "size" | "count";
|
|
5
|
+
interface FileRejection {
|
|
6
|
+
/** The file that was turned away. */
|
|
7
|
+
file: File;
|
|
8
|
+
/** Which rule turned it away. */
|
|
9
|
+
reason: FileRejectReason;
|
|
10
|
+
}
|
|
11
|
+
interface FilePartitionOptions {
|
|
12
|
+
/** An `accept` string: extensions, exact mime types, `image/*` wildcards. */
|
|
13
|
+
accept?: string;
|
|
14
|
+
/** Largest accepted file, in bytes. */
|
|
15
|
+
maxSize?: number;
|
|
16
|
+
/** How many files may be accepted in total. */
|
|
17
|
+
maxFiles?: number;
|
|
18
|
+
}
|
|
19
|
+
interface FilePartition {
|
|
20
|
+
/** Files that passed every rule, in the order they arrived. */
|
|
21
|
+
accepted: File[];
|
|
22
|
+
/** Files that failed one, each with the reason. */
|
|
23
|
+
rejected: FileRejection[];
|
|
24
|
+
}
|
|
25
|
+
/** Where a file is in its journey. Drives the row's readout. */
|
|
26
|
+
type UploadStatus = "pending" | "uploading" | "done" | "error";
|
|
27
|
+
interface UploadFile {
|
|
28
|
+
/** Stable identity — what `onRemove` reports. */
|
|
29
|
+
id: string;
|
|
30
|
+
/** File name, shown verbatim. */
|
|
31
|
+
name: string;
|
|
32
|
+
/** Size in bytes; rendered in SI units. */
|
|
33
|
+
size?: number;
|
|
34
|
+
/** Completion 0–100. Drawn as a bar while `status` is `"uploading"`. */
|
|
35
|
+
progress?: number;
|
|
36
|
+
/** Defaults to `"pending"`. */
|
|
37
|
+
status?: UploadStatus;
|
|
38
|
+
/** Why it failed. Shown in the danger tone under the name. */
|
|
39
|
+
error?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Split a drop into the files that pass the rules and the ones that do not,
|
|
43
|
+
* each with the reason it was turned away.
|
|
44
|
+
*
|
|
45
|
+
* Exported and pure because "why was my file rejected?" is the question a drop
|
|
46
|
+
* zone most often has to answer, and a caller filtering by hand would answer it
|
|
47
|
+
* differently from the component. Order is preserved, and the count ceiling
|
|
48
|
+
* keeps the *first* files rather than an arbitrary subset.
|
|
49
|
+
*
|
|
50
|
+
* @param files - Everything the drop or the file dialog produced.
|
|
51
|
+
* @param options - The rules to apply.
|
|
52
|
+
* @returns The accepted files and the reasoned rejections.
|
|
53
|
+
* @example
|
|
54
|
+
* partitionFiles(files, { accept: "image/*", maxSize: 2_000_000 })
|
|
55
|
+
*/
|
|
56
|
+
declare function partitionFiles(files: readonly File[], { accept, maxSize, maxFiles }: FilePartitionOptions): FilePartition;
|
|
57
|
+
interface FileUploadProps extends Omit<React.ComponentPropsWithoutRef<"div">, "onDrop" | "children"> {
|
|
58
|
+
/** The zone's own copy, and its accessible name. Defaults to `"Drop files"`. */
|
|
59
|
+
label?: React.ReactNode;
|
|
60
|
+
/** A second line under the label — the rules, in plain words. */
|
|
61
|
+
hint?: React.ReactNode;
|
|
62
|
+
/** `accept` string forwarded to the input and used for rejection. */
|
|
63
|
+
accept?: string;
|
|
64
|
+
/** Allow more than one file per drop. */
|
|
65
|
+
multiple?: boolean;
|
|
66
|
+
/** Largest accepted file, in bytes. */
|
|
67
|
+
maxSize?: number;
|
|
68
|
+
/** How many files may be accepted per drop. */
|
|
69
|
+
maxFiles?: number;
|
|
70
|
+
/** Refuse drops and grey the zone out. */
|
|
71
|
+
disabled?: boolean;
|
|
72
|
+
/** Rows to render under the zone. The caller owns upload state. */
|
|
73
|
+
files?: readonly UploadFile[];
|
|
74
|
+
/** Called with the files that passed the rules. */
|
|
75
|
+
onFilesAccepted?: (files: File[]) => void;
|
|
76
|
+
/** Called with the files that did not, each with its reason. */
|
|
77
|
+
onFilesRejected?: (rejections: FileRejection[]) => void;
|
|
78
|
+
/** Called with a row's `id` when its remove control is pressed. */
|
|
79
|
+
onRemove?: (id: string) => void;
|
|
80
|
+
/** Spoken name of a row's remove control. Defaults to `Remove <name>`. */
|
|
81
|
+
removeLabel?: (file: UploadFile) => string;
|
|
82
|
+
/** Extra classes for the drop zone. */
|
|
83
|
+
zoneClassName?: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A drop zone with a file list under it.
|
|
87
|
+
*
|
|
88
|
+
* The zone is a real `<button>`, not a div with a drop handler: dropping is the
|
|
89
|
+
* mouse affordance, and pressing Enter on a focused button to open the file
|
|
90
|
+
* dialog is the keyboard one. A zone that only accepts drops is unusable
|
|
91
|
+
* without a pointer (WCAG 2.1.1), and it is the single most common defect in
|
|
92
|
+
* hand-rolled uploaders.
|
|
93
|
+
*
|
|
94
|
+
* State is the caller's. This component turns drops into `File[]` (plus
|
|
95
|
+
* reasoned rejections, via {@link partitionFiles}) and renders whatever rows it
|
|
96
|
+
* is handed — it never holds an upload queue, because the transport, the
|
|
97
|
+
* retries and the progress belong to the app.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* <FileUpload
|
|
101
|
+
* label="Drop show files"
|
|
102
|
+
* hint="CSV or QLab bundle, up to 20 MB"
|
|
103
|
+
* accept=".csv,.qlab"
|
|
104
|
+
* maxSize={20_000_000}
|
|
105
|
+
* files={rows}
|
|
106
|
+
* onFilesAccepted={enqueue}
|
|
107
|
+
* onFilesRejected={explain}
|
|
108
|
+
* onRemove={cancel}
|
|
109
|
+
* />
|
|
110
|
+
*/
|
|
111
|
+
declare const FileUpload: React.ForwardRefExoticComponent<FileUploadProps & React.RefAttributes<HTMLDivElement>>;
|
|
112
|
+
//#endregion
|
|
113
|
+
export { FilePartition, FilePartitionOptions, FileRejectReason, FileRejection, FileUpload, FileUploadProps, UploadFile, UploadStatus, partitionFiles };
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { CrossGlyph } from "./_glyphs.js";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/forms/file-upload.tsx
|
|
7
|
+
/** Does `file` satisfy one clause of an `accept` string? */
|
|
8
|
+
function matchesAcceptClause(file, clause) {
|
|
9
|
+
const rule = clause.trim().toLowerCase();
|
|
10
|
+
if (rule === "") return true;
|
|
11
|
+
if (rule.startsWith(".")) return file.name.toLowerCase().endsWith(rule);
|
|
12
|
+
if (rule.endsWith("/*")) return file.type.toLowerCase().startsWith(rule.slice(0, -1));
|
|
13
|
+
return file.type.toLowerCase() === rule;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Split a drop into the files that pass the rules and the ones that do not,
|
|
17
|
+
* each with the reason it was turned away.
|
|
18
|
+
*
|
|
19
|
+
* Exported and pure because "why was my file rejected?" is the question a drop
|
|
20
|
+
* zone most often has to answer, and a caller filtering by hand would answer it
|
|
21
|
+
* differently from the component. Order is preserved, and the count ceiling
|
|
22
|
+
* keeps the *first* files rather than an arbitrary subset.
|
|
23
|
+
*
|
|
24
|
+
* @param files - Everything the drop or the file dialog produced.
|
|
25
|
+
* @param options - The rules to apply.
|
|
26
|
+
* @returns The accepted files and the reasoned rejections.
|
|
27
|
+
* @example
|
|
28
|
+
* partitionFiles(files, { accept: "image/*", maxSize: 2_000_000 })
|
|
29
|
+
*/
|
|
30
|
+
function partitionFiles(files, { accept, maxSize, maxFiles }) {
|
|
31
|
+
const clauses = accept === void 0 ? [] : accept.split(",").filter((part) => part.trim() !== "");
|
|
32
|
+
const accepted = [];
|
|
33
|
+
const rejected = [];
|
|
34
|
+
for (const file of files) if (clauses.length > 0 && !clauses.some((clause) => matchesAcceptClause(file, clause))) rejected.push({
|
|
35
|
+
file,
|
|
36
|
+
reason: "type"
|
|
37
|
+
});
|
|
38
|
+
else if (maxSize !== void 0 && file.size > maxSize) rejected.push({
|
|
39
|
+
file,
|
|
40
|
+
reason: "size"
|
|
41
|
+
});
|
|
42
|
+
else if (maxFiles !== void 0 && accepted.length >= maxFiles) rejected.push({
|
|
43
|
+
file,
|
|
44
|
+
reason: "count"
|
|
45
|
+
});
|
|
46
|
+
else accepted.push(file);
|
|
47
|
+
return {
|
|
48
|
+
accepted,
|
|
49
|
+
rejected
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** SI units, one decimal — `1536` reads as `1.5 kB`, not `1.5 KiB`. */
|
|
53
|
+
function formatBytes(bytes) {
|
|
54
|
+
if (bytes < 1e3) return `${bytes} B`;
|
|
55
|
+
const units = [
|
|
56
|
+
"kB",
|
|
57
|
+
"MB",
|
|
58
|
+
"GB",
|
|
59
|
+
"TB"
|
|
60
|
+
];
|
|
61
|
+
let value = bytes / 1e3;
|
|
62
|
+
let unit = 0;
|
|
63
|
+
while (value >= 1e3 && unit < units.length - 1) {
|
|
64
|
+
value /= 1e3;
|
|
65
|
+
unit += 1;
|
|
66
|
+
}
|
|
67
|
+
return `${value.toFixed(1)} ${units[unit]}`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A drop zone with a file list under it.
|
|
71
|
+
*
|
|
72
|
+
* The zone is a real `<button>`, not a div with a drop handler: dropping is the
|
|
73
|
+
* mouse affordance, and pressing Enter on a focused button to open the file
|
|
74
|
+
* dialog is the keyboard one. A zone that only accepts drops is unusable
|
|
75
|
+
* without a pointer (WCAG 2.1.1), and it is the single most common defect in
|
|
76
|
+
* hand-rolled uploaders.
|
|
77
|
+
*
|
|
78
|
+
* State is the caller's. This component turns drops into `File[]` (plus
|
|
79
|
+
* reasoned rejections, via {@link partitionFiles}) and renders whatever rows it
|
|
80
|
+
* is handed — it never holds an upload queue, because the transport, the
|
|
81
|
+
* retries and the progress belong to the app.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* <FileUpload
|
|
85
|
+
* label="Drop show files"
|
|
86
|
+
* hint="CSV or QLab bundle, up to 20 MB"
|
|
87
|
+
* accept=".csv,.qlab"
|
|
88
|
+
* maxSize={20_000_000}
|
|
89
|
+
* files={rows}
|
|
90
|
+
* onFilesAccepted={enqueue}
|
|
91
|
+
* onFilesRejected={explain}
|
|
92
|
+
* onRemove={cancel}
|
|
93
|
+
* />
|
|
94
|
+
*/
|
|
95
|
+
const FileUpload = React.forwardRef(function FileUpload({ className, zoneClassName, label = "Drop files", hint, accept, multiple = false, maxSize, maxFiles, disabled = false, files, onFilesAccepted, onFilesRejected, onRemove, removeLabel = (file) => `Remove ${file.name}`, ...elementProps }, ref) {
|
|
96
|
+
const inputRef = React.useRef(null);
|
|
97
|
+
const [dragging, setDragging] = React.useState(false);
|
|
98
|
+
const depth = React.useRef(0);
|
|
99
|
+
const intake = (incoming) => {
|
|
100
|
+
if (disabled || incoming === null || incoming.length === 0) return;
|
|
101
|
+
const { accepted, rejected } = partitionFiles(Array.from(incoming), {
|
|
102
|
+
accept,
|
|
103
|
+
maxSize,
|
|
104
|
+
maxFiles: maxFiles ?? (multiple ? void 0 : 1)
|
|
105
|
+
});
|
|
106
|
+
if (accepted.length > 0) onFilesAccepted?.(accepted);
|
|
107
|
+
if (rejected.length > 0) onFilesRejected?.(rejected);
|
|
108
|
+
};
|
|
109
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
110
|
+
ref,
|
|
111
|
+
"data-slot": "file-upload",
|
|
112
|
+
className: cn("flex w-full flex-col gap-(--cue-space-2)", className),
|
|
113
|
+
...elementProps,
|
|
114
|
+
children: [
|
|
115
|
+
/* @__PURE__ */ jsxs("button", {
|
|
116
|
+
type: "button",
|
|
117
|
+
"data-slot": "file-upload-zone",
|
|
118
|
+
"data-dragging": dragging ? "true" : void 0,
|
|
119
|
+
disabled,
|
|
120
|
+
onClick: () => inputRef.current?.click(),
|
|
121
|
+
onDragEnter: (event) => {
|
|
122
|
+
if (disabled) return;
|
|
123
|
+
event.preventDefault();
|
|
124
|
+
depth.current += 1;
|
|
125
|
+
setDragging(true);
|
|
126
|
+
},
|
|
127
|
+
onDragOver: (event) => {
|
|
128
|
+
if (disabled) return;
|
|
129
|
+
event.preventDefault();
|
|
130
|
+
},
|
|
131
|
+
onDragLeave: (event) => {
|
|
132
|
+
if (disabled) return;
|
|
133
|
+
event.preventDefault();
|
|
134
|
+
depth.current -= 1;
|
|
135
|
+
if (depth.current <= 0) {
|
|
136
|
+
depth.current = 0;
|
|
137
|
+
setDragging(false);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
onDrop: (event) => {
|
|
141
|
+
event.preventDefault();
|
|
142
|
+
depth.current = 0;
|
|
143
|
+
setDragging(false);
|
|
144
|
+
intake(event.dataTransfer?.files ?? null);
|
|
145
|
+
},
|
|
146
|
+
className: cn("flex w-full cursor-pointer flex-col items-center justify-center gap-(--cue-space-1) rounded-(--radius-control) border border-dashed border-border bg-sunken px-(--cue-space-4) py-(--cue-space-5) font-mono text-(length:--cue-text-ui) text-fg-muted outline-none transition-colors duration-150 hover:border-border-strong hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-1 focus-visible:outline-accent disabled:pointer-events-none disabled:opacity-40 data-[dragging=true]:border-accent data-[dragging=true]:bg-accent-soft data-[dragging=true]:text-fg motion-reduce:transition-none", zoneClassName),
|
|
147
|
+
children: [/* @__PURE__ */ jsx("span", { children: label }), hint === void 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
148
|
+
className: "text-(length:--cue-text-label) text-fg-subtle",
|
|
149
|
+
children: hint
|
|
150
|
+
})]
|
|
151
|
+
}),
|
|
152
|
+
/* @__PURE__ */ jsx("input", {
|
|
153
|
+
ref: inputRef,
|
|
154
|
+
type: "file",
|
|
155
|
+
hidden: true,
|
|
156
|
+
tabIndex: -1,
|
|
157
|
+
accept,
|
|
158
|
+
multiple,
|
|
159
|
+
disabled,
|
|
160
|
+
"data-slot": "file-upload-input",
|
|
161
|
+
onChange: (event) => {
|
|
162
|
+
intake(event.target.files);
|
|
163
|
+
event.target.value = "";
|
|
164
|
+
}
|
|
165
|
+
}),
|
|
166
|
+
files === void 0 || files.length === 0 ? null : /* @__PURE__ */ jsx("ul", {
|
|
167
|
+
"data-slot": "file-upload-list",
|
|
168
|
+
className: "flex flex-col gap-px",
|
|
169
|
+
children: files.map((file) => /* @__PURE__ */ jsx(FileUploadRow, {
|
|
170
|
+
file,
|
|
171
|
+
onRemove,
|
|
172
|
+
removeLabel
|
|
173
|
+
}, file.id))
|
|
174
|
+
})
|
|
175
|
+
]
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
/** One file: name, size, progress or reason, and a way out. */
|
|
179
|
+
function FileUploadRow({ file, onRemove, removeLabel }) {
|
|
180
|
+
const status = file.status ?? "pending";
|
|
181
|
+
const showProgress = status === "uploading" && file.progress !== void 0;
|
|
182
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
183
|
+
"data-slot": "file-upload-row",
|
|
184
|
+
"data-status": status,
|
|
185
|
+
className: "flex min-h-control-sm items-center gap-(--cue-space-3) bg-surface-2 px-(--cue-space-3) py-(--cue-space-1) font-mono text-(length:--cue-text-label)",
|
|
186
|
+
children: [
|
|
187
|
+
/* @__PURE__ */ jsxs("div", {
|
|
188
|
+
className: "flex min-w-0 flex-1 flex-col gap-px",
|
|
189
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
190
|
+
className: "truncate text-fg",
|
|
191
|
+
children: file.name
|
|
192
|
+
}), file.error === void 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
193
|
+
"data-slot": "file-upload-error",
|
|
194
|
+
className: "truncate text-danger",
|
|
195
|
+
children: file.error
|
|
196
|
+
})]
|
|
197
|
+
}),
|
|
198
|
+
file.size === void 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
199
|
+
className: "shrink-0 tabular-nums text-fg-subtle",
|
|
200
|
+
children: formatBytes(file.size)
|
|
201
|
+
}),
|
|
202
|
+
showProgress ? /* @__PURE__ */ jsx("div", {
|
|
203
|
+
role: "progressbar",
|
|
204
|
+
"aria-label": `Uploading ${file.name}`,
|
|
205
|
+
"aria-valuenow": file.progress,
|
|
206
|
+
"aria-valuemin": 0,
|
|
207
|
+
"aria-valuemax": 100,
|
|
208
|
+
"data-slot": "file-upload-progress",
|
|
209
|
+
className: "h-px w-[4rem] shrink-0 overflow-hidden bg-surface-3",
|
|
210
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
211
|
+
className: "h-full bg-accent transition-[width] duration-[120ms] ease-linear motion-reduce:transition-none",
|
|
212
|
+
style: { width: `${file.progress}%` }
|
|
213
|
+
})
|
|
214
|
+
}) : null,
|
|
215
|
+
status === "done" ? /* @__PURE__ */ jsx("span", {
|
|
216
|
+
className: "shrink-0 text-ok",
|
|
217
|
+
"aria-hidden": "true",
|
|
218
|
+
children: "✓"
|
|
219
|
+
}) : null,
|
|
220
|
+
onRemove === void 0 ? null : /* @__PURE__ */ jsx("button", {
|
|
221
|
+
type: "button",
|
|
222
|
+
"aria-label": removeLabel(file),
|
|
223
|
+
"data-slot": "file-upload-remove",
|
|
224
|
+
onClick: () => onRemove(file.id),
|
|
225
|
+
className: "flex size-icon-sm shrink-0 cursor-pointer items-center justify-center rounded-(--radius-control) border-0 bg-transparent p-0 text-fg-subtle outline-none transition-colors hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-1 focus-visible:outline-accent motion-reduce:transition-none",
|
|
226
|
+
children: /* @__PURE__ */ jsx(CrossGlyph, { className: "size-full" })
|
|
227
|
+
})
|
|
228
|
+
]
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
//#endregion
|
|
232
|
+
export { FileUpload, partitionFiles };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ControlVariantProps, FormControlSize, bareControlClasses, controlClasses, controlGroupFocusClasses, controlSurface, controlVariants } from "./_chassis.js";
|
|
2
|
+
import { Autocomplete, AutocompleteProps } from "./autocomplete.js";
|
|
3
|
+
import { ButtonGroup, ButtonGroupOrientation, ButtonGroupProps } from "./button-group.js";
|
|
4
|
+
import { Checkbox, CheckboxGroup, CheckboxGroupProps, CheckboxProps } from "./checkbox.js";
|
|
5
|
+
import { Combobox, ComboboxOption, ComboboxProps } from "./combobox.js";
|
|
6
|
+
import { EnvVarInput, EnvVarInputProps, envReference, parseEnvReference } from "./env-var-input.js";
|
|
7
|
+
import { Field, FieldDescription, FieldDescriptionProps, FieldError, FieldErrorProps, FieldIssue, FieldLabel, FieldLabelProps, FieldProps } from "./field.js";
|
|
8
|
+
import { FilePartition, FilePartitionOptions, FileRejectReason, FileRejection, FileUpload, FileUploadProps, UploadFile, UploadStatus, partitionFiles } from "./file-upload.js";
|
|
9
|
+
import { Input, InputProps } from "./input.js";
|
|
10
|
+
import { InputGroup, InputGroupProps } from "./input-group.js";
|
|
11
|
+
import { MultiSelect, MultiSelectProps } from "./multi-select.js";
|
|
12
|
+
import { NumberField, NumberFieldProps } from "./number-field.js";
|
|
13
|
+
import { OTPField, OTPFieldProps } from "./otp-field.js";
|
|
14
|
+
import { PasswordInput, PasswordInputProps } from "./password-input.js";
|
|
15
|
+
import { Radio, RadioGroup, RadioGroupProps, RadioProps } from "./radio-group.js";
|
|
16
|
+
import { Rating, RatingProps, RatingSize } from "./rating.js";
|
|
17
|
+
import { ScrubInput, ScrubInputProps } from "./scrub-input.js";
|
|
18
|
+
import { SearchInput, SearchInputProps } from "./search-input.js";
|
|
19
|
+
import { Select, SelectOption, SelectProps } from "./select.js";
|
|
20
|
+
import { Slider, SliderProps } from "./slider.js";
|
|
21
|
+
import { Switch, SwitchProps } from "./switch.js";
|
|
22
|
+
import { TagsInput, TagsInputProps } from "./tags-input.js";
|
|
23
|
+
import { Textarea, TextareaProps } from "./textarea.js";
|
|
24
|
+
import { Toggle, ToggleProps } from "./toggle.js";
|
|
25
|
+
import { ToggleGroup, ToggleGroupProps } from "./toggle-group.js";
|
|
26
|
+
export { Autocomplete, type AutocompleteProps, ButtonGroup, type ButtonGroupOrientation, type ButtonGroupProps, Checkbox, CheckboxGroup, type CheckboxGroupProps, type CheckboxProps, Combobox, type ComboboxOption, type ComboboxProps, type ControlVariantProps, EnvVarInput, type EnvVarInputProps, Field, FieldDescription, type FieldDescriptionProps, FieldError, type FieldErrorProps, type FieldIssue, FieldLabel, type FieldLabelProps, type FieldProps, type FilePartition, type FilePartitionOptions, type FileRejectReason, type FileRejection, FileUpload, type FileUploadProps, type FormControlSize, Input, InputGroup, type InputGroupProps, type InputProps, MultiSelect, type MultiSelectProps, NumberField, type NumberFieldProps, OTPField, type OTPFieldProps, PasswordInput, type PasswordInputProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, Rating, type RatingProps, type RatingSize, ScrubInput, type ScrubInputProps, SearchInput, type SearchInputProps, Select, type SelectOption, type SelectProps, Slider, type SliderProps, Switch, type SwitchProps, TagsInput, type TagsInputProps, Textarea, type TextareaProps, Toggle, ToggleGroup, type ToggleGroupProps, type ToggleProps, type UploadFile, type UploadStatus, bareControlClasses, controlClasses, controlGroupFocusClasses, controlSurface, controlVariants, envReference, parseEnvReference, partitionFiles };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Checkbox, CheckboxGroup } from "./checkbox.js";
|
|
2
|
+
import { bareControlClasses, controlClasses, controlGroupFocusClasses, controlSurface, controlVariants } from "./_chassis.js";
|
|
3
|
+
import { InputGroup } from "./input-group.js";
|
|
4
|
+
import { Input } from "./input.js";
|
|
5
|
+
import { NumberField } from "./number-field.js";
|
|
6
|
+
import { Radio, RadioGroup } from "./radio-group.js";
|
|
7
|
+
import { Autocomplete } from "./autocomplete.js";
|
|
8
|
+
import { ButtonGroup } from "./button-group.js";
|
|
9
|
+
import { Combobox } from "./combobox.js";
|
|
10
|
+
import { PasswordInput } from "./password-input.js";
|
|
11
|
+
import { EnvVarInput, envReference, parseEnvReference } from "./env-var-input.js";
|
|
12
|
+
import { Field, FieldDescription, FieldError, FieldLabel } from "./field.js";
|
|
13
|
+
import { FileUpload, partitionFiles } from "./file-upload.js";
|
|
14
|
+
import { MultiSelect } from "./multi-select.js";
|
|
15
|
+
import { OTPField } from "./otp-field.js";
|
|
16
|
+
import { Rating } from "./rating.js";
|
|
17
|
+
import { ScrubInput } from "./scrub-input.js";
|
|
18
|
+
import { SearchInput } from "./search-input.js";
|
|
19
|
+
import { Select } from "./select.js";
|
|
20
|
+
import { Slider } from "./slider.js";
|
|
21
|
+
import { Switch } from "./switch.js";
|
|
22
|
+
import { TagsInput } from "./tags-input.js";
|
|
23
|
+
import { Textarea } from "./textarea.js";
|
|
24
|
+
import { ToggleGroup } from "./toggle-group.js";
|
|
25
|
+
import { Toggle } from "./toggle.js";
|
|
26
|
+
export { Autocomplete, ButtonGroup, Checkbox, CheckboxGroup, Combobox, EnvVarInput, Field, FieldDescription, FieldError, FieldLabel, FileUpload, Input, InputGroup, MultiSelect, NumberField, OTPField, PasswordInput, Radio, RadioGroup, Rating, ScrubInput, SearchInput, Select, Slider, Switch, TagsInput, Textarea, Toggle, ToggleGroup, bareControlClasses, controlClasses, controlGroupFocusClasses, controlSurface, controlVariants, envReference, parseEnvReference, partitionFiles };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { FormControlSize } from "./_chassis.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
//#region src/forms/input-group.d.ts
|
|
4
|
+
interface InputGroupProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
5
|
+
/** Content pinned to the left gutter — a glyph, a unit prefix, a protocol. */
|
|
6
|
+
leading?: React.ReactNode;
|
|
7
|
+
/** Content pinned to the right gutter — a unit suffix, a `Kbd`, a clear button. */
|
|
8
|
+
trailing?: React.ReactNode;
|
|
9
|
+
/** Rung of the control ladder for the whole cluster. Defaults to `"md"`. */
|
|
10
|
+
size?: FormControlSize;
|
|
11
|
+
/** The control. An {@link Input} here renders bare and fills the middle. */
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A control and its adornments, drawn as a single field.
|
|
16
|
+
*
|
|
17
|
+
* The group — not the input — owns the chassis, so there is exactly one rim and
|
|
18
|
+
* one fill however many affordances are bolted on. It publishes that fact
|
|
19
|
+
* through context: an {@link Input} rendered inside strips its own border,
|
|
20
|
+
* background, height and padding and inherits the group's font size. Focus
|
|
21
|
+
* feedback moves to `focus-within`, since a `<div>` never matches
|
|
22
|
+
* `:focus-visible`.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* <InputGroup leading={<Search />} trailing={<Kbd>⌘K</Kbd>}>
|
|
26
|
+
* <Input aria-label="Search cues" />
|
|
27
|
+
* </InputGroup>
|
|
28
|
+
*/
|
|
29
|
+
declare const InputGroup: React.ForwardRefExoticComponent<InputGroupProps & React.RefAttributes<HTMLDivElement>>;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { InputGroup, InputGroupProps };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { controlGroupFocusClasses, controlVariants } from "./_chassis.js";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/forms/input-group.tsx
|
|
7
|
+
/**
|
|
8
|
+
* `true` inside an {@link InputGroup}: tells a nested control to render bare
|
|
9
|
+
* because the group already paints the rim, the fill and the height.
|
|
10
|
+
*
|
|
11
|
+
* @internal Not part of the public API; read by `input.tsx`.
|
|
12
|
+
*/
|
|
13
|
+
const InputGroupContext = React.createContext(false);
|
|
14
|
+
/**
|
|
15
|
+
* A control and its adornments, drawn as a single field.
|
|
16
|
+
*
|
|
17
|
+
* The group — not the input — owns the chassis, so there is exactly one rim and
|
|
18
|
+
* one fill however many affordances are bolted on. It publishes that fact
|
|
19
|
+
* through context: an {@link Input} rendered inside strips its own border,
|
|
20
|
+
* background, height and padding and inherits the group's font size. Focus
|
|
21
|
+
* feedback moves to `focus-within`, since a `<div>` never matches
|
|
22
|
+
* `:focus-visible`.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* <InputGroup leading={<Search />} trailing={<Kbd>⌘K</Kbd>}>
|
|
26
|
+
* <Input aria-label="Search cues" />
|
|
27
|
+
* </InputGroup>
|
|
28
|
+
*/
|
|
29
|
+
const InputGroup = React.forwardRef(function InputGroup({ className, leading, trailing, size, children, ...elementProps }, ref) {
|
|
30
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
31
|
+
ref,
|
|
32
|
+
"data-slot": "input-group",
|
|
33
|
+
className: cn(controlVariants({ size }), "flex items-center gap-(--cue-space-2)", controlGroupFocusClasses, className),
|
|
34
|
+
...elementProps,
|
|
35
|
+
children: [
|
|
36
|
+
leading === void 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
37
|
+
"data-slot": "input-group-leading",
|
|
38
|
+
className: "flex shrink-0 items-center text-fg-subtle",
|
|
39
|
+
children: leading
|
|
40
|
+
}),
|
|
41
|
+
/* @__PURE__ */ jsx(InputGroupContext.Provider, {
|
|
42
|
+
value: true,
|
|
43
|
+
children
|
|
44
|
+
}),
|
|
45
|
+
trailing === void 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
46
|
+
"data-slot": "input-group-trailing",
|
|
47
|
+
className: "flex shrink-0 items-center text-fg-subtle",
|
|
48
|
+
children: trailing
|
|
49
|
+
})
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
//#endregion
|
|
54
|
+
export { InputGroup, InputGroupContext };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { FormControlSize } from "./_chassis.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Input } from "@base-ui/react/input";
|
|
4
|
+
//#region src/forms/input.d.ts
|
|
5
|
+
interface InputProps extends Omit<Input.Props, "className" | "size"> {
|
|
6
|
+
/** Extra classes, merged over the chassis. */
|
|
7
|
+
className?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Rung of the control ladder. Defaults to `"md"`. Shadows the native `size`
|
|
10
|
+
* attribute (a character count), which nothing in a token-driven layout wants.
|
|
11
|
+
*/
|
|
12
|
+
size?: FormControlSize;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The single-line text control.
|
|
16
|
+
*
|
|
17
|
+
* Wraps Base UI's `Input`, so dropping one inside a {@link Field} wires up the
|
|
18
|
+
* label, the description and the validity state with no `id` plumbing. Rides
|
|
19
|
+
* the recessed chassis: `bg-sunken` sets it into the panel rather than raising
|
|
20
|
+
* it off, which is how this system distinguishes "you type here" from "you
|
|
21
|
+
* press here".
|
|
22
|
+
*
|
|
23
|
+
* Inside an {@link InputGroup} it renders bare — the group owns the rim — so the
|
|
24
|
+
* two compose without a doubled border.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* <Input placeholder="e.g. Blackout" />
|
|
28
|
+
* @example
|
|
29
|
+
* <Input type="number" size="sm" defaultValue={512} />
|
|
30
|
+
*/
|
|
31
|
+
declare const Input$1: React.ForwardRefExoticComponent<Omit<InputProps, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { Input$1 as Input, InputProps };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { bareControlClasses, controlVariants } from "./_chassis.js";
|
|
4
|
+
import { InputGroupContext } from "./input-group.js";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
import { Input } from "@base-ui/react/input";
|
|
8
|
+
//#region src/forms/input.tsx
|
|
9
|
+
/**
|
|
10
|
+
* The single-line text control.
|
|
11
|
+
*
|
|
12
|
+
* Wraps Base UI's `Input`, so dropping one inside a {@link Field} wires up the
|
|
13
|
+
* label, the description and the validity state with no `id` plumbing. Rides
|
|
14
|
+
* the recessed chassis: `bg-sunken` sets it into the panel rather than raising
|
|
15
|
+
* it off, which is how this system distinguishes "you type here" from "you
|
|
16
|
+
* press here".
|
|
17
|
+
*
|
|
18
|
+
* Inside an {@link InputGroup} it renders bare — the group owns the rim — so the
|
|
19
|
+
* two compose without a doubled border.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* <Input placeholder="e.g. Blackout" />
|
|
23
|
+
* @example
|
|
24
|
+
* <Input type="number" size="sm" defaultValue={512} />
|
|
25
|
+
*/
|
|
26
|
+
const Input$1 = React.forwardRef(function Input$2({ className, size, ...elementProps }, ref) {
|
|
27
|
+
const inGroup = React.useContext(InputGroupContext);
|
|
28
|
+
return /* @__PURE__ */ jsx(Input, {
|
|
29
|
+
ref,
|
|
30
|
+
"data-slot": "input",
|
|
31
|
+
className: cn(inGroup ? bareControlClasses : controlVariants({ size }), className),
|
|
32
|
+
...elementProps
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
//#endregion
|
|
36
|
+
export { Input$1 as Input };
|