@uisatin/ui 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +67 -2
- package/chunk-2HKBZFIK.js +339 -0
- package/chunk-2HKBZFIK.js.map +1 -0
- package/chunk-2YEWSJD7.js +95 -0
- package/chunk-2YEWSJD7.js.map +1 -0
- package/chunk-3DINAQLL.js +153 -0
- package/chunk-3DINAQLL.js.map +1 -0
- package/chunk-3ERGAHKA.js +179 -0
- package/chunk-3ERGAHKA.js.map +1 -0
- package/chunk-6C7CGJX2.js +86 -0
- package/chunk-6C7CGJX2.js.map +1 -0
- package/chunk-6YXUBP27.js +474 -0
- package/chunk-6YXUBP27.js.map +1 -0
- package/chunk-72OCFAPT.js +175 -0
- package/chunk-72OCFAPT.js.map +1 -0
- package/chunk-7TXHCRAG.js +51 -0
- package/chunk-7TXHCRAG.js.map +1 -0
- package/chunk-A5XEM3GF.js +260 -0
- package/chunk-A5XEM3GF.js.map +1 -0
- package/chunk-AN2RNJLR.js +79 -0
- package/chunk-AN2RNJLR.js.map +1 -0
- package/chunk-B2K45IUR.js +36 -0
- package/chunk-B2K45IUR.js.map +1 -0
- package/chunk-B6V4VSGH.js +82 -0
- package/chunk-B6V4VSGH.js.map +1 -0
- package/chunk-BKZBWPUH.js +59 -0
- package/chunk-BKZBWPUH.js.map +1 -0
- package/chunk-BNTPPZCK.js +220 -0
- package/chunk-BNTPPZCK.js.map +1 -0
- package/chunk-BNZVTLHV.js +98 -0
- package/chunk-BNZVTLHV.js.map +1 -0
- package/chunk-CL2II6BX.js +89 -0
- package/chunk-CL2II6BX.js.map +1 -0
- package/chunk-DETGJAIC.js +147 -0
- package/chunk-DETGJAIC.js.map +1 -0
- package/chunk-DO3TBNSC.js +130 -0
- package/chunk-DO3TBNSC.js.map +1 -0
- package/chunk-ESC5JCVQ.js +90 -0
- package/chunk-ESC5JCVQ.js.map +1 -0
- package/chunk-FDKIX4DC.js +55 -0
- package/chunk-FDKIX4DC.js.map +1 -0
- package/chunk-GICKPMJU.js +239 -0
- package/chunk-GICKPMJU.js.map +1 -0
- package/chunk-GQA24FYG.js +57 -0
- package/chunk-GQA24FYG.js.map +1 -0
- package/chunk-H4NU7NPO.js +264 -0
- package/chunk-H4NU7NPO.js.map +1 -0
- package/chunk-H63FYCMY.js +11 -0
- package/chunk-H63FYCMY.js.map +1 -0
- package/chunk-HL42K2NH.js +76 -0
- package/chunk-HL42K2NH.js.map +1 -0
- package/chunk-HNQUX43Z.js +109 -0
- package/chunk-HNQUX43Z.js.map +1 -0
- package/chunk-HRKPV66B.js +32 -0
- package/chunk-HRKPV66B.js.map +1 -0
- package/chunk-J3NSDRVH.js +83 -0
- package/chunk-J3NSDRVH.js.map +1 -0
- package/chunk-JPNWHWAQ.js +151 -0
- package/chunk-JPNWHWAQ.js.map +1 -0
- package/chunk-KNUWZNFV.js +240 -0
- package/chunk-KNUWZNFV.js.map +1 -0
- package/chunk-L6NCCSIP.js +213 -0
- package/chunk-L6NCCSIP.js.map +1 -0
- package/chunk-LLHTVIM3.js +50 -0
- package/chunk-LLHTVIM3.js.map +1 -0
- package/chunk-LW3TRU5W.js +131 -0
- package/chunk-LW3TRU5W.js.map +1 -0
- package/chunk-LZMKSFCF.js +79 -0
- package/chunk-LZMKSFCF.js.map +1 -0
- package/chunk-MR3JDI7E.js +122 -0
- package/chunk-MR3JDI7E.js.map +1 -0
- package/chunk-NN6PKJWS.js +44 -0
- package/chunk-NN6PKJWS.js.map +1 -0
- package/chunk-NSRTTYQ4.js +252 -0
- package/chunk-NSRTTYQ4.js.map +1 -0
- package/chunk-O7F3CIDV.js +45 -0
- package/chunk-O7F3CIDV.js.map +1 -0
- package/chunk-P4O6TGDR.js +166 -0
- package/chunk-P4O6TGDR.js.map +1 -0
- package/chunk-PF3YBUKT.js +81 -0
- package/chunk-PF3YBUKT.js.map +1 -0
- package/chunk-PVOLDO4G.js +47 -0
- package/chunk-PVOLDO4G.js.map +1 -0
- package/chunk-QS4N4MNP.js +215 -0
- package/chunk-QS4N4MNP.js.map +1 -0
- package/chunk-QUF2IPOZ.js +98 -0
- package/chunk-QUF2IPOZ.js.map +1 -0
- package/chunk-RTJ76X5U.js +126 -0
- package/chunk-RTJ76X5U.js.map +1 -0
- package/chunk-SH6NG6VN.js +40 -0
- package/chunk-SH6NG6VN.js.map +1 -0
- package/chunk-SHDFUXYV.js +195 -0
- package/chunk-SHDFUXYV.js.map +1 -0
- package/chunk-TKO44NDI.js +84 -0
- package/chunk-TKO44NDI.js.map +1 -0
- package/chunk-TOMSU4S4.js +149 -0
- package/chunk-TOMSU4S4.js.map +1 -0
- package/chunk-TVLGZGYN.js +59 -0
- package/chunk-TVLGZGYN.js.map +1 -0
- package/chunk-TX3H3QMA.js +520 -0
- package/chunk-TX3H3QMA.js.map +1 -0
- package/chunk-UBNHSZSE.js +88 -0
- package/chunk-UBNHSZSE.js.map +1 -0
- package/chunk-UC3ZJWOD.js +73 -0
- package/chunk-UC3ZJWOD.js.map +1 -0
- package/chunk-UGRSWP6U.js +69 -0
- package/chunk-UGRSWP6U.js.map +1 -0
- package/chunk-VAGIAREV.js +214 -0
- package/chunk-VAGIAREV.js.map +1 -0
- package/chunk-WTMZT3IT.js +105 -0
- package/chunk-WTMZT3IT.js.map +1 -0
- package/chunk-WX6BP5ZP.js +39 -0
- package/chunk-WX6BP5ZP.js.map +1 -0
- package/chunk-X3PQANZO.js +255 -0
- package/chunk-X3PQANZO.js.map +1 -0
- package/chunk-XILQ7GXE.js +66 -0
- package/chunk-XILQ7GXE.js.map +1 -0
- package/chunk-XL75JRUA.js +130 -0
- package/chunk-XL75JRUA.js.map +1 -0
- package/chunk-XZNHT6MO.js +348 -0
- package/chunk-XZNHT6MO.js.map +1 -0
- package/chunk-Y5AYU7PK.js +44 -0
- package/chunk-Y5AYU7PK.js.map +1 -0
- package/chunk-YG7JOOLJ.js +28 -0
- package/chunk-YG7JOOLJ.js.map +1 -0
- package/chunk-YPJYW624.js +195 -0
- package/chunk-YPJYW624.js.map +1 -0
- package/chunk-YPNKBE5X.js +104 -0
- package/chunk-YPNKBE5X.js.map +1 -0
- package/components/accordion.d.ts +27 -0
- package/components/accordion.js +4 -0
- package/components/accordion.js.map +1 -0
- package/components/agent-loading.d.ts +65 -0
- package/components/agent-loading.js +4 -0
- package/components/agent-loading.js.map +1 -0
- package/components/agent-picker.d.ts +82 -0
- package/components/agent-picker.js +5 -0
- package/components/agent-picker.js.map +1 -0
- package/components/agent-suggestion.d.ts +69 -0
- package/components/agent-suggestion.js +6 -0
- package/components/agent-suggestion.js.map +1 -0
- package/components/announcement-bar.d.ts +39 -0
- package/components/announcement-bar.js +6 -0
- package/components/announcement-bar.js.map +1 -0
- package/components/attachment.d.ts +73 -0
- package/components/attachment.js +5 -0
- package/components/attachment.js.map +1 -0
- package/components/avatar.d.ts +34 -0
- package/components/avatar.js +6 -0
- package/components/avatar.js.map +1 -0
- package/components/badge.d.ts +19 -0
- package/components/badge.js +4 -0
- package/components/badge.js.map +1 -0
- package/components/banner.d.ts +54 -0
- package/components/banner.js +5 -0
- package/components/banner.js.map +1 -0
- package/components/bar-chart.d.ts +32 -0
- package/components/bar-chart.js +11 -0
- package/components/bar-chart.js.map +1 -0
- package/components/breadcrumb.d.ts +32 -0
- package/components/breadcrumb.js +6 -0
- package/components/breadcrumb.js.map +1 -0
- package/components/button.d.ts +32 -0
- package/components/button.js +4 -0
- package/components/button.js.map +1 -0
- package/components/card.d.ts +28 -0
- package/components/card.js +5 -0
- package/components/card.js.map +1 -0
- package/components/channel-chart.d.ts +14 -0
- package/components/channel-chart.js +11 -0
- package/components/channel-chart.js.map +1 -0
- package/components/chart.d.ts +88 -0
- package/components/chart.js +10 -0
- package/components/chart.js.map +1 -0
- package/components/checkbox.d.ts +17 -0
- package/components/checkbox.js +4 -0
- package/components/checkbox.js.map +1 -0
- package/components/chip.d.ts +54 -0
- package/components/chip.js +4 -0
- package/components/chip.js.map +1 -0
- package/components/citations.d.ts +37 -0
- package/components/citations.js +5 -0
- package/components/citations.js.map +1 -0
- package/components/code-block.d.ts +13 -0
- package/components/code-block.js +5 -0
- package/components/code-block.js.map +1 -0
- package/components/combobox.d.ts +58 -0
- package/components/combobox.js +10 -0
- package/components/combobox.js.map +1 -0
- package/components/command-menu.d.ts +54 -0
- package/components/command-menu.js +6 -0
- package/components/command-menu.js.map +1 -0
- package/components/context-menu.d.ts +46 -0
- package/components/context-menu.js +6 -0
- package/components/context-menu.js.map +1 -0
- package/components/cookie-consent.d.ts +26 -0
- package/components/cookie-consent.js +5 -0
- package/components/cookie-consent.js.map +1 -0
- package/components/date-picker.d.ts +112 -0
- package/components/date-picker.js +9 -0
- package/components/date-picker.js.map +1 -0
- package/components/decision-card.d.ts +65 -0
- package/components/decision-card.js +7 -0
- package/components/decision-card.js.map +1 -0
- package/components/dialog.d.ts +68 -0
- package/components/dialog.js +5 -0
- package/components/dialog.js.map +1 -0
- package/components/donut-chart.d.ts +20 -0
- package/components/donut-chart.js +11 -0
- package/components/donut-chart.js.map +1 -0
- package/components/dot.d.ts +21 -0
- package/components/dot.js +4 -0
- package/components/dot.js.map +1 -0
- package/components/dropdown.d.ts +74 -0
- package/components/dropdown.js +5 -0
- package/components/dropdown.js.map +1 -0
- package/components/empty-state.d.ts +25 -0
- package/components/empty-state.js +4 -0
- package/components/empty-state.js.map +1 -0
- package/components/file-upload.d.ts +78 -0
- package/components/file-upload.js +7 -0
- package/components/file-upload.js.map +1 -0
- package/components/floating.d.ts +30 -0
- package/components/floating.js +3 -0
- package/components/floating.js.map +1 -0
- package/components/form-field.d.ts +35 -0
- package/components/form-field.js +4 -0
- package/components/form-field.js.map +1 -0
- package/components/hover-card.d.ts +30 -0
- package/components/hover-card.js +4 -0
- package/components/hover-card.js.map +1 -0
- package/components/input-otp.d.ts +49 -0
- package/components/input-otp.js +8 -0
- package/components/input-otp.js.map +1 -0
- package/components/input.d.ts +28 -0
- package/components/input.js +5 -0
- package/components/input.js.map +1 -0
- package/components/kbd.d.ts +37 -0
- package/components/kbd.js +4 -0
- package/components/kbd.js.map +1 -0
- package/components/line-chart.d.ts +29 -0
- package/components/line-chart.js +12 -0
- package/components/line-chart.js.map +1 -0
- package/components/message-actions.d.ts +24 -0
- package/components/message-actions.js +5 -0
- package/components/message-actions.js.map +1 -0
- package/components/message.d.ts +40 -0
- package/components/message.js +8 -0
- package/components/message.js.map +1 -0
- package/components/number-input.d.ts +33 -0
- package/components/number-input.js +8 -0
- package/components/number-input.js.map +1 -0
- package/components/pagination.d.ts +45 -0
- package/components/pagination.js +6 -0
- package/components/pagination.js.map +1 -0
- package/components/popover.d.ts +44 -0
- package/components/popover.js +4 -0
- package/components/popover.js.map +1 -0
- package/components/progress.d.ts +24 -0
- package/components/progress.js +4 -0
- package/components/progress.js.map +1 -0
- package/components/prompt-bar.d.ts +63 -0
- package/components/prompt-bar.js +6 -0
- package/components/prompt-bar.js.map +1 -0
- package/components/radio.d.ts +27 -0
- package/components/radio.js +4 -0
- package/components/radio.js.map +1 -0
- package/components/search-bar.d.ts +20 -0
- package/components/search-bar.js +5 -0
- package/components/search-bar.js.map +1 -0
- package/components/segmented-control.d.ts +32 -0
- package/components/segmented-control.js +5 -0
- package/components/segmented-control.js.map +1 -0
- package/components/select.d.ts +97 -0
- package/components/select.js +7 -0
- package/components/select.js.map +1 -0
- package/components/sheet.d.ts +37 -0
- package/components/sheet.js +6 -0
- package/components/sheet.js.map +1 -0
- package/components/sidebar.d.ts +52 -0
- package/components/sidebar.js +4 -0
- package/components/sidebar.js.map +1 -0
- package/components/skeleton.d.ts +18 -0
- package/components/skeleton.js +4 -0
- package/components/skeleton.js.map +1 -0
- package/components/slider.d.ts +57 -0
- package/components/slider.js +8 -0
- package/components/slider.js.map +1 -0
- package/components/sliding-indicator.d.ts +23 -0
- package/components/sliding-indicator.js +3 -0
- package/components/sliding-indicator.js.map +1 -0
- package/components/streaming-text.d.ts +33 -0
- package/components/streaming-text.js +4 -0
- package/components/streaming-text.js.map +1 -0
- package/components/switch.d.ts +15 -0
- package/components/switch.js +4 -0
- package/components/switch.js.map +1 -0
- package/components/table.d.ts +57 -0
- package/components/table.js +5 -0
- package/components/table.js.map +1 -0
- package/components/tabs.d.ts +45 -0
- package/components/tabs.js +5 -0
- package/components/tabs.js.map +1 -0
- package/components/textarea.d.ts +30 -0
- package/components/textarea.js +5 -0
- package/components/textarea.js.map +1 -0
- package/components/thinking.d.ts +64 -0
- package/components/thinking.js +5 -0
- package/components/thinking.js.map +1 -0
- package/components/toast.d.ts +71 -0
- package/components/toast.js +5 -0
- package/components/toast.js.map +1 -0
- package/components/toggle.d.ts +30 -0
- package/components/toggle.js +4 -0
- package/components/toggle.js.map +1 -0
- package/components/tooltip.d.ts +35 -0
- package/components/tooltip.js +5 -0
- package/components/tooltip.js.map +1 -0
- package/index.d.ts +64 -0
- package/index.js +230 -0
- package/index.js.map +1 -0
- package/lib/utils.d.ts +3 -0
- package/lib/utils.js +3 -0
- package/lib/utils.js.map +1 -0
- package/package.json +54 -4
- package/styles.css +2 -0
- package/theme/create-theme.d.ts +44 -0
- package/theme/index.d.ts +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/segmented-control.tsx"],"names":[],"mappings":"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","file":"chunk-WTMZT3IT.js","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { ToggleGroup } from 'radix-ui'\nimport { cva } from 'class-variance-authority'\nimport { cn } from '../lib/utils'\nimport { useSlidingIndicator } from './sliding-indicator'\n\n/**\n * SegmentedControl, from the uiKit `segmented control` page: 2–5 segments that switch\n * views or filters in place. One segment is always selected; the selected pill slides under\n * the labels to the new segment, as in Tabs and Pagination (sliding-indicator.tsx: 300 ms,\n * the leading edge first): a white card with Shadow/sm in Light. Arrow keys move between segments.\n * Values 1:1 with the uiKit `_segmentedControl/item` (3080:20278) and `SegmentedControl` (3080:21247) sets.\n */\ntype Size = 'xs' | 'md' | 'lg'\ntype Shape = 'default' | 'rounded'\n\nexport interface SegmentedControlItem {\n value: string\n label: React.ReactNode\n icon?: React.ReactNode\n disabled?: boolean\n}\n\nexport interface SegmentedControlProps {\n items: SegmentedControlItem[]\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n size?: Size\n shape?: Shape\n /** A 1px border-subtle outline around the track. */\n border?: boolean\n fullWidth?: boolean\n /** Required when the segments have no visible text of their own. */\n 'aria-label'?: string\n className?: string\n}\n\nconst track = cva('relative isolate inline-flex items-center gap-0.5 bg-bg-muted p-1', {\n variants: {\n shape: { default: 'rounded-lg', rounded: 'rounded-pill' },\n border: { true: 'border border-border-subtle', false: '' },\n fullWidth: { true: 'flex w-full', false: '' },\n },\n})\n\nconst segment = cva(\n [\n 'relative z-10 inline-flex items-center justify-center font-medium whitespace-nowrap text-text-muted select-none',\n 'transition-[color,background-color,box-shadow] duration-(--duration-fast) ease-(--ease-out)',\n 'satin-hover:text-text-default data-[state=on]:text-text-default',\n 'satin-pressed:bg-component-segmented-pressed satin-pressed:text-text-default',\n 'focus-visible:outline-none satin-focus:text-text-default satin-focus:[box-shadow:0_0_0_2px_var(--action-focus-ring)]',\n 'disabled:pointer-events-none disabled:text-text-subtle',\n '[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:[stroke-width:1.875]',\n ],\n {\n variants: {\n size: {\n xs: 'h-control-height-xs gap-1 px-2.5 text-sm [&_svg]:size-icon-size-sm',\n md: 'h-control-height gap-1.5 px-3 text-sm [&_svg]:size-icon-size',\n lg: 'h-control-height-lg gap-1.5 px-4 text-base [&_svg]:size-icon-size',\n },\n shape: { default: 'rounded-sm', rounded: 'rounded-pill' },\n fullWidth: { true: 'flex-1', false: '' },\n },\n },\n)\n\nexport function SegmentedControl({\n items,\n value: valueProp,\n defaultValue,\n onValueChange,\n size = 'md',\n shape = 'default',\n border = false,\n fullWidth = false,\n className,\n ...aria\n}: SegmentedControlProps) {\n const [inner, setInner] = React.useState(defaultValue ?? items[0]?.value ?? '')\n const value = valueProp ?? inner\n const trackRef = React.useRef<HTMLDivElement>(null)\n // The pill slides under the selected segment (sliding-indicator.tsx).\n const pill = useSlidingIndicator(trackRef, '[data-state=\"on\"]', `${value}|${size}|${fullWidth}|${items.length}`)\n\n return (\n <ToggleGroup.Root\n ref={trackRef}\n type=\"single\"\n value={value}\n onValueChange={(next) => {\n // A segmented control never ends up with nothing selected.\n if (!next) return\n setInner(next)\n onValueChange?.(next)\n }}\n data-slot=\"segmented-control\"\n className={cn(track({ shape, border, fullWidth }), className)}\n {...aria}\n >\n <span\n ref={pill.ref}\n aria-hidden\n className={cn(\n 'pointer-events-none absolute top-1 bottom-1 left-0 z-0 bg-component-segmented-selected opacity-0 [box-shadow:0_1px_3px_0_var(--effect-shadow-sm),0_1px_2px_-1px_var(--effect-shadow-sm)]',\n shape === 'rounded' ? 'rounded-pill' : 'rounded-sm',\n )}\n />\n {items.map((item) => (\n <ToggleGroup.Item\n key={item.value}\n value={item.value}\n disabled={item.disabled}\n className={cn(\n segment({ size, shape, fullWidth }),\n // Unselected focus: bg/muted under the ring. Selected focus keeps the pill's fill.\n 'data-[state=off]:satin-focus:bg-bg-muted',\n // Before the pill is measured (server render), the selected segment paints its own fill.\n !pill.ready && 'data-[state=on]:bg-component-segmented-selected data-[state=on]:[box-shadow:0_1px_3px_0_var(--effect-shadow-sm),0_1px_2px_-1px_var(--effect-shadow-sm)]',\n )}\n >\n {item.icon}\n {item.label}\n </ToggleGroup.Item>\n ))}\n </ToggleGroup.Root>\n )\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { cn } from './chunk-H63FYCMY.js';
|
|
2
|
+
import 'react';
|
|
3
|
+
import { cva } from 'class-variance-authority';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var emptyStateVariants = cva(
|
|
7
|
+
"flex w-[350px] max-w-[560px] min-w-[min(320px,100%)] flex-col items-center gap-4 rounded-2xl px-4 pt-4 pb-5 text-center",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
border: {
|
|
11
|
+
ghost: "",
|
|
12
|
+
dashed: "border border-dashed border-border-default",
|
|
13
|
+
outline: "border border-border-default"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
defaultVariants: { border: "ghost" }
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
function EmptyState({ className, border, title, description, icon, actions, ...props }) {
|
|
20
|
+
return /* @__PURE__ */ jsxs("div", { "data-slot": "empty-state", className: cn(emptyStateVariants({ border }), className), ...props, children: [
|
|
21
|
+
icon && /* @__PURE__ */ jsx(
|
|
22
|
+
"div",
|
|
23
|
+
{
|
|
24
|
+
"aria-hidden": true,
|
|
25
|
+
className: "flex shrink-0 items-center justify-center rounded-lg bg-bg-muted p-2.5 text-text-default [&_svg]:size-4 [&_svg]:[stroke-width:1.875]",
|
|
26
|
+
children: icon
|
|
27
|
+
}
|
|
28
|
+
),
|
|
29
|
+
/* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col items-center gap-2", children: [
|
|
30
|
+
/* @__PURE__ */ jsx("p", { className: "w-full text-lg font-medium text-text-default", children: title }),
|
|
31
|
+
description && /* @__PURE__ */ jsx("p", { className: "w-full text-body-lg text-text-muted", children: description })
|
|
32
|
+
] }),
|
|
33
|
+
actions && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-start justify-center gap-2", children: actions })
|
|
34
|
+
] });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { EmptyState, emptyStateVariants };
|
|
38
|
+
//# sourceMappingURL=chunk-WX6BP5ZP.js.map
|
|
39
|
+
//# sourceMappingURL=chunk-WX6BP5ZP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/empty-state.tsx"],"names":[],"mappings":";;;;;AAgBA,IAAM,kBAAA,GAAqB,GAAA;AAAA,EACzB,yHAAA;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,MAAA,EAAQ;AAAA,QACN,KAAA,EAAO,EAAA;AAAA,QACP,MAAA,EAAQ,4CAAA;AAAA,QACR,OAAA,EAAS;AAAA;AACX,KACF;AAAA,IACA,eAAA,EAAiB,EAAE,MAAA,EAAQ,OAAA;AAAQ;AAEvC;AAaO,SAAS,UAAA,CAAW,EAAE,SAAA,EAAW,MAAA,EAAQ,KAAA,EAAO,aAAa,IAAA,EAAM,OAAA,EAAS,GAAG,KAAA,EAAM,EAAoB;AAC9G,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,WAAA,EAAU,aAAA,EAAc,WAAW,EAAA,CAAG,kBAAA,CAAmB,EAAE,MAAA,EAAQ,CAAA,EAAG,SAAS,CAAA,EAAI,GAAG,KAAA,EACxF,QAAA,EAAA;AAAA,IAAA,IAAA,oBACC,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,aAAA,EAAW,IAAA;AAAA,QACX,SAAA,EAAU,sIAAA;AAAA,QAET,QAAA,EAAA;AAAA;AAAA,KACH;AAAA,oBAEF,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yCAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,8CAAA,EAAgD,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,MAClE,WAAA,oBAAe,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,uCAAuC,QAAA,EAAA,WAAA,EAAY;AAAA,KAAA,EAClF,CAAA;AAAA,IACC,OAAA,oBAAW,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mDAAmD,QAAA,EAAA,OAAA,EAAQ;AAAA,GAAA,EACxF,CAAA;AAEJ","file":"chunk-WX6BP5ZP.js","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '../lib/utils'\n\n/**\n * EmptyState, 1:1 with the uiKit `EmptyState` set (852:51897) and its `_buttonGroup`\n * (852:51922): a centred column 350 wide (320–560), padding 16 / 16 / 20, 16 apart, radius-2xl.\n *\n * - icon: a 16px glyph in text/default on a bg/muted tile, 10 padding, radius-lg (36 square).\n * - title in text/lg medium (16/24), description in Body/lg (14/21) text/muted, 8 apart, centred.\n * - actions: a row of Buttons 8 apart: Primary + Secondary, Secondary alone, or a Tertiary\n * \"Learn more\" with a trailing arrow. Pass them as `<Button>` elements.\n * - border: ghost (none), dashed or outline, both 1px border/default.\n */\nconst emptyStateVariants = cva(\n 'flex w-[350px] max-w-[560px] min-w-[min(320px,100%)] flex-col items-center gap-4 rounded-2xl px-4 pt-4 pb-5 text-center',\n {\n variants: {\n border: {\n ghost: '',\n dashed: 'border border-dashed border-border-default',\n outline: 'border border-border-default',\n },\n },\n defaultVariants: { border: 'ghost' },\n },\n)\n\nexport interface EmptyStateProps\n extends Omit<React.ComponentProps<'div'>, 'title'>,\n VariantProps<typeof emptyStateVariants> {\n title: React.ReactNode\n description?: React.ReactNode\n /** A 16px icon, e.g. from iconoir-react. */\n icon?: React.ReactNode\n /** One or two Buttons. */\n actions?: React.ReactNode\n}\n\nexport function EmptyState({ className, border, title, description, icon, actions, ...props }: EmptyStateProps) {\n return (\n <div data-slot=\"empty-state\" className={cn(emptyStateVariants({ border }), className)} {...props}>\n {icon && (\n <div\n aria-hidden\n className=\"flex shrink-0 items-center justify-center rounded-lg bg-bg-muted p-2.5 text-text-default [&_svg]:size-4 [&_svg]:[stroke-width:1.875]\"\n >\n {icon}\n </div>\n )}\n <div className=\"flex w-full flex-col items-center gap-2\">\n <p className=\"w-full text-lg font-medium text-text-default\">{title}</p>\n {description && <p className=\"w-full text-body-lg text-text-muted\">{description}</p>}\n </div>\n {actions && <div className=\"flex flex-wrap items-start justify-center gap-2\">{actions}</div>}\n </div>\n )\n}\n\nexport { emptyStateVariants }\n"]}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { Checkbox } from './chunk-FDKIX4DC.js';
|
|
2
|
+
import { cn } from './chunk-H63FYCMY.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
function SortIcon({ direction }) {
|
|
7
|
+
return /* @__PURE__ */ jsx(
|
|
8
|
+
"svg",
|
|
9
|
+
{
|
|
10
|
+
width: "14",
|
|
11
|
+
height: "14",
|
|
12
|
+
viewBox: "0 0 14 14",
|
|
13
|
+
fill: "none",
|
|
14
|
+
"aria-hidden": true,
|
|
15
|
+
className: cn("shrink-0 text-text-muted", direction === "desc" && "rotate-180"),
|
|
16
|
+
children: /* @__PURE__ */ jsx(
|
|
17
|
+
"path",
|
|
18
|
+
{
|
|
19
|
+
d: "M7.00025 11.4515L7.00025 2.54852M11.2044 6.7527L7.00025 2.54852L2.79608 6.7527",
|
|
20
|
+
stroke: "currentColor",
|
|
21
|
+
strokeWidth: "1.09375",
|
|
22
|
+
strokeLinecap: "round",
|
|
23
|
+
strokeLinejoin: "round"
|
|
24
|
+
}
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
var cellHover = {
|
|
30
|
+
first: [
|
|
31
|
+
"group-hover/row:rounded-l-xl group-hover/row:bg-bg-hover group-hover/row:[box-shadow:inset_1px_0_0_var(--border-strong),inset_0_1px_0_var(--border-strong),inset_0_-1px_0_var(--border-strong)]",
|
|
32
|
+
"group-data-[force=hover]/row:rounded-l-xl group-data-[force=hover]/row:bg-bg-hover group-data-[force=hover]/row:[box-shadow:inset_1px_0_0_var(--border-strong),inset_0_1px_0_var(--border-strong),inset_0_-1px_0_var(--border-strong)]"
|
|
33
|
+
].join(" "),
|
|
34
|
+
middle: [
|
|
35
|
+
"group-hover/row:bg-bg-hover group-hover/row:[box-shadow:inset_0_1px_0_var(--border-strong),inset_0_-1px_0_var(--border-strong)]",
|
|
36
|
+
"group-data-[force=hover]/row:bg-bg-hover group-data-[force=hover]/row:[box-shadow:inset_0_1px_0_var(--border-strong),inset_0_-1px_0_var(--border-strong)]"
|
|
37
|
+
].join(" "),
|
|
38
|
+
last: [
|
|
39
|
+
"group-hover/row:rounded-r-xl group-hover/row:bg-bg-hover group-hover/row:[box-shadow:inset_-1px_0_0_var(--border-strong),inset_0_1px_0_var(--border-strong),inset_0_-1px_0_var(--border-strong)]",
|
|
40
|
+
"group-data-[force=hover]/row:rounded-r-xl group-data-[force=hover]/row:bg-bg-hover group-data-[force=hover]/row:[box-shadow:inset_-1px_0_0_var(--border-strong),inset_0_1px_0_var(--border-strong),inset_0_-1px_0_var(--border-strong)]"
|
|
41
|
+
].join(" "),
|
|
42
|
+
only: [
|
|
43
|
+
"group-hover/row:rounded-xl group-hover/row:bg-bg-hover group-hover/row:[box-shadow:inset_0_0_0_1px_var(--border-strong)]",
|
|
44
|
+
"group-data-[force=hover]/row:rounded-xl group-data-[force=hover]/row:bg-bg-hover group-data-[force=hover]/row:[box-shadow:inset_0_0_0_1px_var(--border-strong)]"
|
|
45
|
+
].join(" ")
|
|
46
|
+
};
|
|
47
|
+
var rowHover = "hover:[filter:drop-shadow(0_1px_1px_var(--effect-shadow-sm))_drop-shadow(0_1px_1.5px_var(--effect-shadow-sm))] data-[force=hover]:[filter:drop-shadow(0_1px_1px_var(--effect-shadow-sm))_drop-shadow(0_1px_1.5px_var(--effect-shadow-sm))]";
|
|
48
|
+
function compare(a, b) {
|
|
49
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
50
|
+
return String(a ?? "").localeCompare(String(b ?? ""), void 0, { numeric: true });
|
|
51
|
+
}
|
|
52
|
+
function Table({
|
|
53
|
+
columns,
|
|
54
|
+
rows,
|
|
55
|
+
selectable = false,
|
|
56
|
+
zebra = false,
|
|
57
|
+
overflow = "fit",
|
|
58
|
+
onSortChange,
|
|
59
|
+
defaultSort = null,
|
|
60
|
+
manualSort = false,
|
|
61
|
+
selected: selectedProp,
|
|
62
|
+
onSelectedChange,
|
|
63
|
+
label,
|
|
64
|
+
className,
|
|
65
|
+
...props
|
|
66
|
+
}) {
|
|
67
|
+
const [sort, setSort] = React.useState(defaultSort);
|
|
68
|
+
const [selectedState, setSelectedState] = React.useState([]);
|
|
69
|
+
const selected = selectedProp ?? selectedState;
|
|
70
|
+
const setSelected = (ids) => {
|
|
71
|
+
if (selectedProp === void 0) setSelectedState(ids);
|
|
72
|
+
onSelectedChange?.(ids);
|
|
73
|
+
};
|
|
74
|
+
const cycleSort = (key) => {
|
|
75
|
+
const next = sort?.key !== key ? { key, direction: "asc" } : sort.direction === "asc" ? { key, direction: "desc" } : null;
|
|
76
|
+
setSort(next);
|
|
77
|
+
onSortChange?.(next);
|
|
78
|
+
};
|
|
79
|
+
const sortedRows = React.useMemo(() => {
|
|
80
|
+
if (!sort || manualSort) return rows;
|
|
81
|
+
const s = [...rows].sort((a, b) => compare(a[sort.key], b[sort.key]));
|
|
82
|
+
return sort.direction === "desc" ? s.reverse() : s;
|
|
83
|
+
}, [rows, sort, manualSort]);
|
|
84
|
+
const scroll = overflow === "scroll";
|
|
85
|
+
const allSelected = rows.length > 0 && rows.every((r) => selected.includes(r.id));
|
|
86
|
+
const someSelected = !allSelected && rows.some((r) => selected.includes(r.id));
|
|
87
|
+
const totalFr = columns.reduce((n, c) => n + (c.width ?? 1), 0);
|
|
88
|
+
const colWidth = (c) => scroll ? `${c.width ?? 160}px` : `${(c.width ?? 1) / totalFr * 100}%`;
|
|
89
|
+
const tableWidth = scroll ? columns.reduce((n, c) => n + (c.width ?? 160), selectable ? 24 : 0) : void 0;
|
|
90
|
+
const viewport = React.useRef(null);
|
|
91
|
+
const [bar, setBar] = React.useState({ size: 1, offset: 0, atEnd: true });
|
|
92
|
+
React.useEffect(() => {
|
|
93
|
+
const el = viewport.current;
|
|
94
|
+
if (!scroll || !el) return;
|
|
95
|
+
const update = () => {
|
|
96
|
+
const size = el.clientWidth / el.scrollWidth;
|
|
97
|
+
const max = el.scrollWidth - el.clientWidth;
|
|
98
|
+
setBar({ size, offset: max > 0 ? el.scrollLeft / el.scrollWidth : 0, atEnd: el.scrollLeft >= max - 1 });
|
|
99
|
+
};
|
|
100
|
+
update();
|
|
101
|
+
el.addEventListener("scroll", update, { passive: true });
|
|
102
|
+
const ro = new ResizeObserver(update);
|
|
103
|
+
ro.observe(el);
|
|
104
|
+
return () => {
|
|
105
|
+
el.removeEventListener("scroll", update);
|
|
106
|
+
ro.disconnect();
|
|
107
|
+
};
|
|
108
|
+
}, [scroll, columns, rows]);
|
|
109
|
+
const stickyFirst = (bg) => scroll ? cn("sticky z-[1]", bg) : "";
|
|
110
|
+
const firstDataLeft = selectable ? "left-6" : "left-0";
|
|
111
|
+
const cellPosition = (index, count) => count === 1 ? cellHover.only : index === 0 ? cellHover.first : index === count - 1 ? cellHover.last : cellHover.middle;
|
|
112
|
+
const cellCount = columns.length + (selectable ? 1 : 0);
|
|
113
|
+
const table = /* @__PURE__ */ jsxs(
|
|
114
|
+
"table",
|
|
115
|
+
{
|
|
116
|
+
"aria-label": label,
|
|
117
|
+
className: "w-full table-fixed border-separate border-spacing-0 text-left",
|
|
118
|
+
style: tableWidth ? { width: tableWidth, minWidth: "100%" } : { minWidth: columns.length * 120 + (selectable ? 24 : 0) },
|
|
119
|
+
children: [
|
|
120
|
+
/* @__PURE__ */ jsxs("colgroup", { children: [
|
|
121
|
+
selectable && /* @__PURE__ */ jsx("col", { style: { width: 24 } }),
|
|
122
|
+
columns.map((c) => /* @__PURE__ */ jsx("col", { style: { width: colWidth(c) } }, c.key))
|
|
123
|
+
] }),
|
|
124
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "bg-component-table-header", children: [
|
|
125
|
+
selectable && /* @__PURE__ */ jsx(
|
|
126
|
+
"th",
|
|
127
|
+
{
|
|
128
|
+
scope: "col",
|
|
129
|
+
className: cn("border-b border-border-subtle py-2 pl-2 align-middle", stickyFirst("left-0 bg-component-table-header")),
|
|
130
|
+
children: /* @__PURE__ */ jsx(
|
|
131
|
+
Checkbox,
|
|
132
|
+
{
|
|
133
|
+
"aria-label": "Select all rows",
|
|
134
|
+
checked: allSelected ? true : someSelected ? "indeterminate" : false,
|
|
135
|
+
onCheckedChange: (v) => setSelected(v === true ? rows.map((r) => r.id) : []),
|
|
136
|
+
className: "align-middle"
|
|
137
|
+
}
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
),
|
|
141
|
+
columns.map((c, i) => {
|
|
142
|
+
const active = sort?.key === c.key ? sort.direction : void 0;
|
|
143
|
+
const labelClass = "inline-flex max-w-full items-center gap-2.5 overflow-hidden rounded-md px-2 py-[3px] text-sm leading-[18px] font-medium whitespace-nowrap text-text-muted";
|
|
144
|
+
return /* @__PURE__ */ jsx(
|
|
145
|
+
"th",
|
|
146
|
+
{
|
|
147
|
+
scope: "col",
|
|
148
|
+
"aria-sort": c.sortable ? active === "asc" ? "ascending" : active === "desc" ? "descending" : "none" : void 0,
|
|
149
|
+
className: cn(
|
|
150
|
+
"h-8 overflow-hidden border-b border-border-subtle py-1 pr-2 pl-1 align-middle font-medium",
|
|
151
|
+
c.align === "right" && "text-right",
|
|
152
|
+
i === 0 && stickyFirst(cn(firstDataLeft, "bg-component-table-header"))
|
|
153
|
+
),
|
|
154
|
+
children: c.sortable ? /* @__PURE__ */ jsxs(
|
|
155
|
+
"button",
|
|
156
|
+
{
|
|
157
|
+
type: "button",
|
|
158
|
+
onClick: () => cycleSort(c.key),
|
|
159
|
+
className: cn(
|
|
160
|
+
labelClass,
|
|
161
|
+
"transition-colors duration-(--duration-fast) ease-(--ease-out) focus-visible:outline-none",
|
|
162
|
+
"satin-hover:bg-bg-hover satin-focus:bg-bg-hover satin-focus:[box-shadow:0_0_0_2px_var(--action-focus-ring)]"
|
|
163
|
+
),
|
|
164
|
+
children: [
|
|
165
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: c.header }),
|
|
166
|
+
active && /* @__PURE__ */ jsx(SortIcon, { direction: active })
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
) : /* @__PURE__ */ jsx("span", { className: labelClass, children: c.header })
|
|
170
|
+
},
|
|
171
|
+
c.key
|
|
172
|
+
);
|
|
173
|
+
})
|
|
174
|
+
] }) }),
|
|
175
|
+
/* @__PURE__ */ jsx("tbody", { children: sortedRows.map((row, r) => {
|
|
176
|
+
const isSelected = selected.includes(row.id);
|
|
177
|
+
const rowBg = zebra && r % 2 === 1 ? "bg-component-table-zebra" : "bg-bg-card";
|
|
178
|
+
return /* @__PURE__ */ jsxs("tr", { "data-state": isSelected ? "selected" : void 0, className: cn("group/row", rowBg, rowHover), children: [
|
|
179
|
+
selectable && /* @__PURE__ */ jsx("td", { className: cn("py-2 pl-2 align-middle", cellPosition(0, cellCount), stickyFirst(cn("left-0", rowBg))), children: /* @__PURE__ */ jsx(
|
|
180
|
+
Checkbox,
|
|
181
|
+
{
|
|
182
|
+
"aria-label": `Select row ${r + 1}`,
|
|
183
|
+
checked: isSelected,
|
|
184
|
+
onCheckedChange: (v) => setSelected(v === true ? [...selected, row.id] : selected.filter((id) => id !== row.id)),
|
|
185
|
+
className: "align-middle"
|
|
186
|
+
}
|
|
187
|
+
) }),
|
|
188
|
+
columns.map((c, i) => {
|
|
189
|
+
const content = c.cell ? c.cell(row) : row[c.key];
|
|
190
|
+
const plain = typeof content === "string" || typeof content === "number";
|
|
191
|
+
return /* @__PURE__ */ jsx(
|
|
192
|
+
"td",
|
|
193
|
+
{
|
|
194
|
+
className: cn(
|
|
195
|
+
"h-10 overflow-hidden py-2 pr-2.5 pl-3 align-middle text-body leading-(--text-body--line-height) text-text-default",
|
|
196
|
+
c.align === "right" && "text-right",
|
|
197
|
+
cellPosition(i + (selectable ? 1 : 0), cellCount),
|
|
198
|
+
i === 0 && stickyFirst(cn(firstDataLeft, rowBg))
|
|
199
|
+
),
|
|
200
|
+
children: plain ? /* @__PURE__ */ jsx("span", { className: "block truncate", children: content }) : /* @__PURE__ */ jsx("div", { className: cn("flex min-w-0 items-center gap-1 overflow-hidden", c.align === "right" && "justify-end"), children: content })
|
|
201
|
+
},
|
|
202
|
+
c.key
|
|
203
|
+
);
|
|
204
|
+
})
|
|
205
|
+
] }, row.id);
|
|
206
|
+
}) })
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
return /* @__PURE__ */ jsx(
|
|
211
|
+
"div",
|
|
212
|
+
{
|
|
213
|
+
"data-slot": "table",
|
|
214
|
+
className: cn("relative overflow-hidden rounded-xl border border-border-subtle bg-bg-card", className),
|
|
215
|
+
...props,
|
|
216
|
+
children: scroll ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
217
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
218
|
+
/* @__PURE__ */ jsx(
|
|
219
|
+
"div",
|
|
220
|
+
{
|
|
221
|
+
ref: viewport,
|
|
222
|
+
tabIndex: 0,
|
|
223
|
+
role: "region",
|
|
224
|
+
"aria-label": label ? `${label}, scrolls sideways` : "Table, scrolls sideways",
|
|
225
|
+
className: "overflow-x-auto [scrollbar-width:none] focus-visible:outline-none [&::-webkit-scrollbar]:hidden",
|
|
226
|
+
children: table
|
|
227
|
+
}
|
|
228
|
+
),
|
|
229
|
+
/* @__PURE__ */ jsx(
|
|
230
|
+
"div",
|
|
231
|
+
{
|
|
232
|
+
"aria-hidden": true,
|
|
233
|
+
className: cn(
|
|
234
|
+
"pointer-events-none absolute inset-y-0 right-0 w-16 bg-linear-to-r from-bg-card-fade to-bg-card",
|
|
235
|
+
"transition-opacity duration-(--duration-fast) ease-(--ease-out)",
|
|
236
|
+
bar.atEnd && "opacity-0"
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
] }),
|
|
241
|
+
/* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "px-3 pt-1.5 pb-1", children: /* @__PURE__ */ jsx("div", { className: "relative h-1.5 overflow-hidden rounded-full bg-bg-muted", children: /* @__PURE__ */ jsx(
|
|
242
|
+
"div",
|
|
243
|
+
{
|
|
244
|
+
className: "absolute inset-y-0 left-0 rounded-full bg-border-strong",
|
|
245
|
+
style: { width: `${bar.size * 100}%`, transform: `translateX(${bar.offset / bar.size * 100}%)` }
|
|
246
|
+
}
|
|
247
|
+
) }) })
|
|
248
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "overflow-x-auto overscroll-x-contain", children: table })
|
|
249
|
+
}
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export { Table };
|
|
254
|
+
//# sourceMappingURL=chunk-X3PQANZO.js.map
|
|
255
|
+
//# sourceMappingURL=chunk-X3PQANZO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/table.tsx"],"names":[],"mappings":"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","file":"chunk-X3PQANZO.js","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cn } from '../lib/utils'\nimport { Checkbox } from './checkbox'\n\n/**\n * Table, 1:1 with the uiKit `Table` set (3411:21610) and its parts: table/header (3410:17835),\n * table/row (3410:18040), table/cell (3409:17760), table/headerCell (3409:17734) and\n * table/checkboxCell (3409:17703). A real `<table>`.\n *\n * - Frame: bg/card, 1px border-subtle, radius-xl, clipped.\n * - Header row: component/table-header fill, 1px border-subtle under it. Header cells pad\n * 4 / 8 / 4 / 4 around a label button (8px sides, 3px top and bottom, radius-md, medium\n * 13/18, text-muted); hover tints the button bg-hover. Sortable headers cycle\n * none → asc → desc with a 14px arrow 10px after the label, and set aria-sort.\n * - Cells: 12 left, 10 right, 8 top and bottom, at least 40 high, regular 13/19.5, clipped\n * with an ellipsis. Chips and other nodes sit in a row 4px apart.\n * - Checkbox column: 8px left padding, no right padding; the header box selects all.\n * - zebra: every second row on component/table-zebra.\n * - Row hover lifts the row: bg-hover, 1px border-strong edge, radius-xl, shadow sm.\n * - overflow=\"fit\": columns are proportional (`width` is an fr weight). overflow=\"scroll\":\n * columns keep their pixel `width`, the first column stays in place, a 64px fade marks\n * the clipped edge and a 6px scrollbar (bg-muted track, border-strong thumb) sits below.\n *\n * The row edge is drawn with inset shadows on the cells, since table rows can't take a\n * border radius. `data-force=\"hover\"` on a `<tr>` shows the hover state.\n */\n\nexport type Sort = { key: string; direction: 'asc' | 'desc' } | null\n\nexport type Row = { id: string } & Record<string, unknown>\n\nexport interface Column<R extends Row = Row> {\n key: string\n header: React.ReactNode\n /** fr weight with overflow=\"fit\" (default 1), pixels with overflow=\"scroll\" (default 160). */\n width?: number\n sortable?: boolean\n /** Renders the cell; defaults to the row's value at `key`. */\n cell?: (row: R) => React.ReactNode\n align?: 'left' | 'right'\n}\n\nexport interface TableProps<R extends Row = Row> extends Omit<React.ComponentProps<'div'>, 'children'> {\n columns: Column<R>[]\n rows: R[]\n selectable?: boolean\n zebra?: boolean\n overflow?: 'fit' | 'scroll'\n /** Called with the new sort; rows are sorted by value unless `manualSort` is set. */\n onSortChange?: (sort: Sort) => void\n defaultSort?: Sort\n /** Leave rows in the order given (sort them yourself in onSortChange). */\n manualSort?: boolean\n selected?: string[]\n onSelectedChange?: (ids: string[]) => void\n /** Accessible name of the table. */\n label?: string\n}\n\n/** The Figma sort arrow, 14 at 1.09. Pointing down for descending. */\nfunction SortIcon({ direction }: { direction: 'asc' | 'desc' }) {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n aria-hidden\n className={cn('shrink-0 text-text-muted', direction === 'desc' && 'rotate-180')}\n >\n <path\n d=\"M7.00025 11.4515L7.00025 2.54852M11.2044 6.7527L7.00025 2.54852L2.79608 6.7527\"\n stroke=\"currentColor\"\n strokeWidth=\"1.09375\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n )\n}\n\n// Hover styles for the cells of a hovered (or data-force=\"hover\") row. Written out in full so\n// Tailwind sees every class.\nconst cellHover = {\n first: [\n 'group-hover/row:rounded-l-xl group-hover/row:bg-bg-hover group-hover/row:[box-shadow:inset_1px_0_0_var(--border-strong),inset_0_1px_0_var(--border-strong),inset_0_-1px_0_var(--border-strong)]',\n 'group-data-[force=hover]/row:rounded-l-xl group-data-[force=hover]/row:bg-bg-hover group-data-[force=hover]/row:[box-shadow:inset_1px_0_0_var(--border-strong),inset_0_1px_0_var(--border-strong),inset_0_-1px_0_var(--border-strong)]',\n ].join(' '),\n middle: [\n 'group-hover/row:bg-bg-hover group-hover/row:[box-shadow:inset_0_1px_0_var(--border-strong),inset_0_-1px_0_var(--border-strong)]',\n 'group-data-[force=hover]/row:bg-bg-hover group-data-[force=hover]/row:[box-shadow:inset_0_1px_0_var(--border-strong),inset_0_-1px_0_var(--border-strong)]',\n ].join(' '),\n last: [\n 'group-hover/row:rounded-r-xl group-hover/row:bg-bg-hover group-hover/row:[box-shadow:inset_-1px_0_0_var(--border-strong),inset_0_1px_0_var(--border-strong),inset_0_-1px_0_var(--border-strong)]',\n 'group-data-[force=hover]/row:rounded-r-xl group-data-[force=hover]/row:bg-bg-hover group-data-[force=hover]/row:[box-shadow:inset_-1px_0_0_var(--border-strong),inset_0_1px_0_var(--border-strong),inset_0_-1px_0_var(--border-strong)]',\n ].join(' '),\n only: [\n 'group-hover/row:rounded-xl group-hover/row:bg-bg-hover group-hover/row:[box-shadow:inset_0_0_0_1px_var(--border-strong)]',\n 'group-data-[force=hover]/row:rounded-xl group-data-[force=hover]/row:bg-bg-hover group-data-[force=hover]/row:[box-shadow:inset_0_0_0_1px_var(--border-strong)]',\n ].join(' '),\n}\n\n// Shadow sm under a hovered row (Figma: 0 1 1 and 0 1 1.5 in effect/shadow-sm).\nconst rowHover =\n 'hover:[filter:drop-shadow(0_1px_1px_var(--effect-shadow-sm))_drop-shadow(0_1px_1.5px_var(--effect-shadow-sm))] data-[force=hover]:[filter:drop-shadow(0_1px_1px_var(--effect-shadow-sm))_drop-shadow(0_1px_1.5px_var(--effect-shadow-sm))]'\n\nfunction compare(a: unknown, b: unknown) {\n if (typeof a === 'number' && typeof b === 'number') return a - b\n return String(a ?? '').localeCompare(String(b ?? ''), undefined, { numeric: true })\n}\n\nexport function Table<R extends Row = Row>({\n columns,\n rows,\n selectable = false,\n zebra = false,\n overflow = 'fit',\n onSortChange,\n defaultSort = null,\n manualSort = false,\n selected: selectedProp,\n onSelectedChange,\n label,\n className,\n ...props\n}: TableProps<R>) {\n const [sort, setSort] = React.useState<Sort>(defaultSort)\n const [selectedState, setSelectedState] = React.useState<string[]>([])\n const selected = selectedProp ?? selectedState\n const setSelected = (ids: string[]) => {\n if (selectedProp === undefined) setSelectedState(ids)\n onSelectedChange?.(ids)\n }\n\n const cycleSort = (key: string) => {\n const next: Sort =\n sort?.key !== key ? { key, direction: 'asc' } : sort.direction === 'asc' ? { key, direction: 'desc' } : null\n setSort(next)\n onSortChange?.(next)\n }\n\n const sortedRows = React.useMemo(() => {\n if (!sort || manualSort) return rows\n const s = [...rows].sort((a, b) => compare(a[sort.key], b[sort.key]))\n return sort.direction === 'desc' ? s.reverse() : s\n }, [rows, sort, manualSort])\n\n const scroll = overflow === 'scroll'\n const allSelected = rows.length > 0 && rows.every((r) => selected.includes(r.id))\n const someSelected = !allSelected && rows.some((r) => selected.includes(r.id))\n\n // Column widths: fr weights as percentages, or fixed pixels when scrolling.\n const totalFr = columns.reduce((n, c) => n + (c.width ?? 1), 0)\n const colWidth = (c: Column<R>) => (scroll ? `${c.width ?? 160}px` : `${((c.width ?? 1) / totalFr) * 100}%`)\n const tableWidth = scroll ? columns.reduce((n, c) => n + (c.width ?? 160), selectable ? 24 : 0) : undefined\n\n // The custom scrollbar and the edge fade follow the viewport's scroll position.\n const viewport = React.useRef<HTMLDivElement>(null)\n const [bar, setBar] = React.useState({ size: 1, offset: 0, atEnd: true })\n React.useEffect(() => {\n const el = viewport.current\n if (!scroll || !el) return\n const update = () => {\n const size = el.clientWidth / el.scrollWidth\n const max = el.scrollWidth - el.clientWidth\n setBar({ size, offset: max > 0 ? el.scrollLeft / el.scrollWidth : 0, atEnd: el.scrollLeft >= max - 1 })\n }\n update()\n el.addEventListener('scroll', update, { passive: true })\n const ro = new ResizeObserver(update)\n ro.observe(el)\n return () => {\n el.removeEventListener('scroll', update)\n ro.disconnect()\n }\n }, [scroll, columns, rows])\n\n // The leading column(s) stay put while the rest scroll.\n const stickyFirst = (bg: string) => (scroll ? cn('sticky z-[1]', bg) : '')\n const firstDataLeft = selectable ? 'left-6' : 'left-0'\n\n const cellPosition = (index: number, count: number) =>\n count === 1 ? cellHover.only : index === 0 ? cellHover.first : index === count - 1 ? cellHover.last : cellHover.middle\n const cellCount = columns.length + (selectable ? 1 : 0)\n\n const table = (\n <table\n aria-label={label}\n className=\"w-full table-fixed border-separate border-spacing-0 text-left\"\n // With overflow=\"fit\" the columns keep at least 120px each, so a phone scrolls instead of crushing them.\n style={tableWidth ? { width: tableWidth, minWidth: '100%' } : { minWidth: columns.length * 120 + (selectable ? 24 : 0) }}\n >\n <colgroup>\n {selectable && <col style={{ width: 24 }} />}\n {columns.map((c) => (\n <col key={c.key} style={{ width: colWidth(c) }} />\n ))}\n </colgroup>\n <thead>\n <tr className=\"bg-component-table-header\">\n {selectable && (\n <th\n scope=\"col\"\n className={cn('border-b border-border-subtle py-2 pl-2 align-middle', stickyFirst('left-0 bg-component-table-header'))}\n >\n <Checkbox\n aria-label=\"Select all rows\"\n checked={allSelected ? true : someSelected ? 'indeterminate' : false}\n onCheckedChange={(v) => setSelected(v === true ? rows.map((r) => r.id) : [])}\n className=\"align-middle\"\n />\n </th>\n )}\n {columns.map((c, i) => {\n const active = sort?.key === c.key ? sort.direction : undefined\n const labelClass =\n 'inline-flex max-w-full items-center gap-2.5 overflow-hidden rounded-md px-2 py-[3px] text-sm leading-[18px] font-medium whitespace-nowrap text-text-muted'\n return (\n <th\n key={c.key}\n scope=\"col\"\n aria-sort={c.sortable ? (active === 'asc' ? 'ascending' : active === 'desc' ? 'descending' : 'none') : undefined}\n className={cn(\n 'h-8 overflow-hidden border-b border-border-subtle py-1 pr-2 pl-1 align-middle font-medium',\n c.align === 'right' && 'text-right',\n i === 0 && stickyFirst(cn(firstDataLeft, 'bg-component-table-header')),\n )}\n >\n {c.sortable ? (\n <button\n type=\"button\"\n onClick={() => cycleSort(c.key)}\n className={cn(\n labelClass,\n 'transition-colors duration-(--duration-fast) ease-(--ease-out) focus-visible:outline-none',\n 'satin-hover:bg-bg-hover satin-focus:bg-bg-hover satin-focus:[box-shadow:0_0_0_2px_var(--action-focus-ring)]',\n )}\n >\n <span className=\"truncate\">{c.header}</span>\n {active && <SortIcon direction={active} />}\n </button>\n ) : (\n <span className={labelClass}>{c.header}</span>\n )}\n </th>\n )\n })}\n </tr>\n </thead>\n <tbody>\n {sortedRows.map((row, r) => {\n const isSelected = selected.includes(row.id)\n const rowBg = zebra && r % 2 === 1 ? 'bg-component-table-zebra' : 'bg-bg-card'\n return (\n <tr key={row.id} data-state={isSelected ? 'selected' : undefined} className={cn('group/row', rowBg, rowHover)}>\n {selectable && (\n <td className={cn('py-2 pl-2 align-middle', cellPosition(0, cellCount), stickyFirst(cn('left-0', rowBg)))}>\n <Checkbox\n aria-label={`Select row ${r + 1}`}\n checked={isSelected}\n onCheckedChange={(v) =>\n setSelected(v === true ? [...selected, row.id] : selected.filter((id) => id !== row.id))\n }\n className=\"align-middle\"\n />\n </td>\n )}\n {columns.map((c, i) => {\n const content = c.cell ? c.cell(row) : (row[c.key] as React.ReactNode)\n const plain = typeof content === 'string' || typeof content === 'number'\n return (\n <td\n key={c.key}\n className={cn(\n 'h-10 overflow-hidden py-2 pr-2.5 pl-3 align-middle text-body leading-(--text-body--line-height) text-text-default',\n c.align === 'right' && 'text-right',\n cellPosition(i + (selectable ? 1 : 0), cellCount),\n i === 0 && stickyFirst(cn(firstDataLeft, rowBg)),\n )}\n >\n {plain ? (\n <span className=\"block truncate\">{content}</span>\n ) : (\n <div className={cn('flex min-w-0 items-center gap-1 overflow-hidden', c.align === 'right' && 'justify-end')}>\n {content}\n </div>\n )}\n </td>\n )\n })}\n </tr>\n )\n })}\n </tbody>\n </table>\n )\n\n return (\n <div\n data-slot=\"table\"\n className={cn('relative overflow-hidden rounded-xl border border-border-subtle bg-bg-card', className)}\n {...props}\n >\n {scroll ? (\n <>\n <div className=\"relative\">\n <div\n ref={viewport}\n tabIndex={0}\n role=\"region\"\n aria-label={label ? `${label}, scrolls sideways` : 'Table, scrolls sideways'}\n className=\"overflow-x-auto [scrollbar-width:none] focus-visible:outline-none [&::-webkit-scrollbar]:hidden\"\n >\n {table}\n </div>\n <div\n aria-hidden\n className={cn(\n 'pointer-events-none absolute inset-y-0 right-0 w-16 bg-linear-to-r from-bg-card-fade to-bg-card',\n 'transition-opacity duration-(--duration-fast) ease-(--ease-out)',\n bar.atEnd && 'opacity-0',\n )}\n />\n </div>\n <div aria-hidden className=\"px-3 pt-1.5 pb-1\">\n <div className=\"relative h-1.5 overflow-hidden rounded-full bg-bg-muted\">\n <div\n className=\"absolute inset-y-0 left-0 rounded-full bg-border-strong\"\n style={{ width: `${bar.size * 100}%`, transform: `translateX(${(bar.offset / bar.size) * 100}%)` }}\n />\n </div>\n </div>\n </>\n ) : (\n <div className=\"overflow-x-auto overscroll-x-contain\">{table}</div>\n )}\n </div>\n )\n}\n"]}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Button } from './chunk-HNQUX43Z.js';
|
|
2
|
+
import { cn } from './chunk-H63FYCMY.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cva } from 'class-variance-authority';
|
|
5
|
+
import { Xmark } from 'iconoir-react';
|
|
6
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
var cardVariants = cva(
|
|
9
|
+
"relative flex w-[405px] max-w-full flex-col overflow-clip rounded-2xl border border-border-default bg-bg-card",
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
size: {
|
|
13
|
+
md: "[--card-pad:calc(var(--spacing)*4)]",
|
|
14
|
+
sm: "[--card-pad:calc(var(--spacing)*3)]"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
defaultVariants: { size: "md" }
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
function Card({
|
|
21
|
+
className,
|
|
22
|
+
size,
|
|
23
|
+
title,
|
|
24
|
+
description,
|
|
25
|
+
footer,
|
|
26
|
+
onClose,
|
|
27
|
+
closeLabel = "Close",
|
|
28
|
+
children,
|
|
29
|
+
...props
|
|
30
|
+
}) {
|
|
31
|
+
const titleId = React.useId();
|
|
32
|
+
const hasHeader = title != null || description != null;
|
|
33
|
+
return /* @__PURE__ */ jsxs(
|
|
34
|
+
"div",
|
|
35
|
+
{
|
|
36
|
+
"data-slot": "card",
|
|
37
|
+
role: title != null ? "group" : void 0,
|
|
38
|
+
"aria-labelledby": title != null ? titleId : void 0,
|
|
39
|
+
className: cn(cardVariants({ size }), className),
|
|
40
|
+
...props,
|
|
41
|
+
children: [
|
|
42
|
+
hasHeader && /* @__PURE__ */ jsxs("div", { "data-slot": "card-header", className: cn("flex flex-col gap-0.5 px-(--card-pad) pt-(--card-pad)", onClose && "pr-10"), children: [
|
|
43
|
+
title != null && /* @__PURE__ */ jsx("div", { id: titleId, className: "text-base leading-[14px] font-medium tracking-normal text-text-default", children: title }),
|
|
44
|
+
description != null && /* @__PURE__ */ jsx("p", { className: "text-body text-text-muted", children: description })
|
|
45
|
+
] }),
|
|
46
|
+
children != null && /* @__PURE__ */ jsx("div", { "data-slot": "card-body", className: "flex flex-col gap-2 p-(--card-pad)", children }),
|
|
47
|
+
footer != null && /* @__PURE__ */ jsx("div", { "data-slot": "card-footer", className: "flex items-center gap-2 p-(--card-pad)", children: footer }),
|
|
48
|
+
onClose && /* @__PURE__ */ jsx(
|
|
49
|
+
Button,
|
|
50
|
+
{
|
|
51
|
+
variant: "tertiary",
|
|
52
|
+
iconOnly: true,
|
|
53
|
+
"aria-label": closeLabel,
|
|
54
|
+
onClick: onClose,
|
|
55
|
+
className: "absolute top-[7px] right-[7px]",
|
|
56
|
+
children: /* @__PURE__ */ jsx(Xmark, { "aria-hidden": true })
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { Card, cardVariants };
|
|
65
|
+
//# sourceMappingURL=chunk-XILQ7GXE.js.map
|
|
66
|
+
//# sourceMappingURL=chunk-XILQ7GXE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/card.tsx"],"names":[],"mappings":";;;;;;;AAoBA,IAAM,YAAA,GAAe,GAAA;AAAA,EACnB,+GAAA;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,EAAA,EAAI,qCAAA;AAAA,QACJ,EAAA,EAAI;AAAA;AACN,KACF;AAAA,IACA,eAAA,EAAiB,EAAE,IAAA,EAAM,IAAA;AAAK;AAElC;AAYO,SAAS,IAAA,CAAK;AAAA,EACnB,SAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA,GAAa,OAAA;AAAA,EACb,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAc;AACZ,EAAA,MAAM,UAAgB,KAAA,CAAA,KAAA,EAAM;AAC5B,EAAA,MAAM,SAAA,GAAY,KAAA,IAAS,IAAA,IAAQ,WAAA,IAAe,IAAA;AAClD,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,WAAA,EAAU,MAAA;AAAA,MACV,IAAA,EAAM,KAAA,IAAS,IAAA,GAAO,OAAA,GAAU,MAAA;AAAA,MAChC,iBAAA,EAAiB,KAAA,IAAS,IAAA,GAAO,OAAA,GAAU,MAAA;AAAA,MAC3C,WAAW,EAAA,CAAG,YAAA,CAAa,EAAE,IAAA,EAAM,GAAG,SAAS,CAAA;AAAA,MAC9C,GAAG,KAAA;AAAA,MAEH,QAAA,EAAA;AAAA,QAAA,SAAA,oBACC,IAAA,CAAC,SAAI,WAAA,EAAU,aAAA,EAAc,WAAW,EAAA,CAAG,uDAAA,EAAyD,OAAA,IAAW,OAAO,CAAA,EACnH,QAAA,EAAA;AAAA,UAAA,KAAA,IAAS,wBACR,GAAA,CAAC,KAAA,EAAA,EAAI,IAAI,OAAA,EAAS,SAAA,EAAU,0EACzB,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,UAED,eAAe,IAAA,oBAAQ,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,6BAA6B,QAAA,EAAA,WAAA,EAAY;AAAA,SAAA,EAChF,CAAA;AAAA,QAED,QAAA,IAAY,wBACX,GAAA,CAAC,KAAA,EAAA,EAAI,aAAU,WAAA,EAAY,SAAA,EAAU,sCAClC,QAAA,EACH,CAAA;AAAA,QAED,MAAA,IAAU,wBACT,GAAA,CAAC,KAAA,EAAA,EAAI,aAAU,aAAA,EAAc,SAAA,EAAU,0CACpC,QAAA,EAAA,MAAA,EACH,CAAA;AAAA,QAED,OAAA,oBACC,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,OAAA,EAAQ,UAAA;AAAA,YACR,QAAA,EAAQ,IAAA;AAAA,YACR,YAAA,EAAY,UAAA;AAAA,YACZ,OAAA,EAAS,OAAA;AAAA,YACT,SAAA,EAAU,gCAAA;AAAA,YAEV,QAAA,kBAAA,GAAA,CAAC,KAAA,EAAA,EAAM,aAAA,EAAW,IAAA,EAAC;AAAA;AAAA;AACrB;AAAA;AAAA,GAEJ;AAEJ","file":"chunk-XILQ7GXE.js","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { Xmark } from 'iconoir-react'\nimport { cn } from '../lib/utils'\nimport { Button } from './button'\n\n/**\n * Card, 1:1 with the uiKit `Card` set (1122:20156): bg/card, 1px border/default, radius-2xl (16),\n * no shadow, 405 wide by default. Three stacked sections with no gap between them:\n *\n * - header: title in Label/lg (14/14 medium), description in text/sm muted, 2px apart.\n * Padding 16 / 16 / 0 on md, 12 / 12 / 0 on sm (no bottom padding: the body's top padding\n * is the space under it).\n * - body (children): 16 padding on md, 12 on sm, children 8 apart.\n * - footer: same padding as the body; its items sit in a row, 8 apart.\n *\n * `onClose` adds a tertiary 28px icon button 7px from the top-right corner.\n */\nconst cardVariants = cva(\n 'relative flex w-[405px] max-w-full flex-col overflow-clip rounded-2xl border border-border-default bg-bg-card',\n {\n variants: {\n size: {\n md: '[--card-pad:calc(var(--spacing)*4)]',\n sm: '[--card-pad:calc(var(--spacing)*3)]',\n },\n },\n defaultVariants: { size: 'md' },\n },\n)\n\nexport interface CardProps extends Omit<React.ComponentProps<'div'>, 'title'>, VariantProps<typeof cardVariants> {\n title?: React.ReactNode\n description?: React.ReactNode\n footer?: React.ReactNode\n /** Shows the close button. */\n onClose?: () => void\n /** Accessible name of the close button. */\n closeLabel?: string\n}\n\nexport function Card({\n className,\n size,\n title,\n description,\n footer,\n onClose,\n closeLabel = 'Close',\n children,\n ...props\n}: CardProps) {\n const titleId = React.useId()\n const hasHeader = title != null || description != null\n return (\n <div\n data-slot=\"card\"\n role={title != null ? 'group' : undefined}\n aria-labelledby={title != null ? titleId : undefined}\n className={cn(cardVariants({ size }), className)}\n {...props}\n >\n {hasHeader && (\n <div data-slot=\"card-header\" className={cn('flex flex-col gap-0.5 px-(--card-pad) pt-(--card-pad)', onClose && 'pr-10')}>\n {title != null && (\n <div id={titleId} className=\"text-base leading-[14px] font-medium tracking-normal text-text-default\">\n {title}\n </div>\n )}\n {description != null && <p className=\"text-body text-text-muted\">{description}</p>}\n </div>\n )}\n {children != null && (\n <div data-slot=\"card-body\" className=\"flex flex-col gap-2 p-(--card-pad)\">\n {children}\n </div>\n )}\n {footer != null && (\n <div data-slot=\"card-footer\" className=\"flex items-center gap-2 p-(--card-pad)\">\n {footer}\n </div>\n )}\n {onClose && (\n <Button\n variant=\"tertiary\"\n iconOnly\n aria-label={closeLabel}\n onClick={onClose}\n className=\"absolute top-[7px] right-[7px]\"\n >\n <Xmark aria-hidden />\n </Button>\n )}\n </div>\n )\n}\n\nexport { cardVariants }\n"]}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { useFieldChrome, FieldChrome } from './chunk-72OCFAPT.js';
|
|
2
|
+
import { cn } from './chunk-H63FYCMY.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { CheckCircle } from 'iconoir-react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function InputOTP({
|
|
8
|
+
length = 6,
|
|
9
|
+
groupSize = 3,
|
|
10
|
+
value: valueProp,
|
|
11
|
+
defaultValue = "",
|
|
12
|
+
onValueChange,
|
|
13
|
+
onComplete,
|
|
14
|
+
pattern = /^\d$/,
|
|
15
|
+
label,
|
|
16
|
+
hint,
|
|
17
|
+
error,
|
|
18
|
+
success,
|
|
19
|
+
disabled,
|
|
20
|
+
autoFocus,
|
|
21
|
+
id,
|
|
22
|
+
name,
|
|
23
|
+
className,
|
|
24
|
+
...props
|
|
25
|
+
}) {
|
|
26
|
+
const chrome = useFieldChrome({ id, disabled, error: error ? true : void 0 });
|
|
27
|
+
const isError = typeof error === "string" || React.isValidElement(error);
|
|
28
|
+
const isSuccess = !chrome.invalid && Boolean(success);
|
|
29
|
+
const successMessage = isSuccess && success !== true ? success : null;
|
|
30
|
+
const message = isError ? error : successMessage ?? (chrome.invalid ? null : hint);
|
|
31
|
+
const messageId = message ? `${chrome.controlId}-message` : void 0;
|
|
32
|
+
const describedBy = [chrome.describedBy, messageId].filter(Boolean).join(" ") || void 0;
|
|
33
|
+
const [inner, setInner] = React.useState(defaultValue);
|
|
34
|
+
const value = (valueProp ?? inner).slice(0, length);
|
|
35
|
+
const [focused, setFocused] = React.useState(false);
|
|
36
|
+
const inputRef = React.useRef(null);
|
|
37
|
+
const set = (raw) => {
|
|
38
|
+
const next = [...raw].filter((c) => pattern.test(c)).join("").slice(0, length);
|
|
39
|
+
if (valueProp == null) setInner(next);
|
|
40
|
+
onValueChange?.(next);
|
|
41
|
+
if (next.length === length && next !== value) onComplete?.(next);
|
|
42
|
+
};
|
|
43
|
+
const active = Math.min(value.length, length - 1);
|
|
44
|
+
const cells = Array.from({ length }, (_, i) => i);
|
|
45
|
+
return /* @__PURE__ */ jsxs(FieldChrome, { label, chrome, className: cn("w-fit", className), children: [
|
|
46
|
+
/* @__PURE__ */ jsxs(
|
|
47
|
+
"div",
|
|
48
|
+
{
|
|
49
|
+
"data-slot": "input-otp",
|
|
50
|
+
"data-disabled": chrome.disabled || void 0,
|
|
51
|
+
className: cn("relative flex w-fit items-center gap-2", chrome.disabled && "opacity-50"),
|
|
52
|
+
children: [
|
|
53
|
+
cells.map((i) => {
|
|
54
|
+
const isActive = focused && i === active;
|
|
55
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
56
|
+
groupSize > 0 && i > 0 && i % groupSize === 0 && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "h-px w-2 shrink-0 bg-border-strong" }),
|
|
57
|
+
/* @__PURE__ */ jsxs(
|
|
58
|
+
"span",
|
|
59
|
+
{
|
|
60
|
+
"aria-hidden": true,
|
|
61
|
+
"data-active": isActive || void 0,
|
|
62
|
+
className: cn(
|
|
63
|
+
"relative grid size-9 shrink-0 place-items-center rounded-lg border bg-bg-field text-base leading-[21px] font-medium text-text-default",
|
|
64
|
+
"[box-shadow:0_1px_2px_0_var(--effect-shadow-xs)]",
|
|
65
|
+
"transition-[border-color,box-shadow] duration-(--duration-fast) ease-(--ease-out)",
|
|
66
|
+
chrome.invalid ? "border-action-destructive-bg" : isSuccess ? "border-status-green-fg" : "border-border-default",
|
|
67
|
+
isActive && (chrome.invalid ? "[box-shadow:0_0_0_2px_var(--action-destructive-glow)]" : isSuccess ? "[box-shadow:0_0_0_2px_var(--status-green-border)]" : "border-border-focus [box-shadow:0_0_0_2px_var(--action-focus-ring)]")
|
|
68
|
+
),
|
|
69
|
+
children: [
|
|
70
|
+
value[i] ?? "",
|
|
71
|
+
isActive && value.length < length && /* @__PURE__ */ jsx("span", { className: "absolute h-[18px] w-px animate-[satin-caret_1s_steps(1)_infinite] bg-text-default" })
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
] }, i);
|
|
76
|
+
}),
|
|
77
|
+
/* @__PURE__ */ jsx(
|
|
78
|
+
"input",
|
|
79
|
+
{
|
|
80
|
+
ref: inputRef,
|
|
81
|
+
id: chrome.controlId,
|
|
82
|
+
name,
|
|
83
|
+
value,
|
|
84
|
+
onChange: (e) => set(e.target.value),
|
|
85
|
+
onFocus: (e) => {
|
|
86
|
+
setFocused(true);
|
|
87
|
+
const end = e.currentTarget.value.length;
|
|
88
|
+
requestAnimationFrame(() => inputRef.current?.setSelectionRange(end, end));
|
|
89
|
+
},
|
|
90
|
+
onBlur: () => setFocused(false),
|
|
91
|
+
onSelect: (e) => {
|
|
92
|
+
const end = e.currentTarget.value.length;
|
|
93
|
+
if (e.currentTarget.selectionStart !== end) e.currentTarget.setSelectionRange(end, end);
|
|
94
|
+
},
|
|
95
|
+
maxLength: length,
|
|
96
|
+
inputMode: pattern.test("5") && !pattern.test("a") ? "numeric" : "text",
|
|
97
|
+
autoComplete: "one-time-code",
|
|
98
|
+
autoFocus,
|
|
99
|
+
disabled: chrome.disabled,
|
|
100
|
+
"aria-invalid": chrome.invalid || void 0,
|
|
101
|
+
"aria-describedby": describedBy,
|
|
102
|
+
"aria-label": props["aria-label"],
|
|
103
|
+
spellCheck: false,
|
|
104
|
+
className: "absolute inset-0 w-full cursor-text bg-transparent text-transparent caret-transparent outline-none selection:bg-transparent focus-visible:outline-none focus-visible:ring-0 focus-visible:[box-shadow:none] disabled:cursor-not-allowed"
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
),
|
|
110
|
+
/* @__PURE__ */ jsxs(
|
|
111
|
+
"p",
|
|
112
|
+
{
|
|
113
|
+
id: messageId,
|
|
114
|
+
"aria-live": "polite",
|
|
115
|
+
className: cn(
|
|
116
|
+
"flex min-h-5 w-0 min-w-full items-start gap-1.5 text-sm leading-5",
|
|
117
|
+
isError ? "text-action-destructive-bg" : successMessage ? "text-status-green-fg" : "text-text-muted"
|
|
118
|
+
),
|
|
119
|
+
children: [
|
|
120
|
+
successMessage && /* @__PURE__ */ jsx(CheckCircle, { "aria-hidden": true, className: "mt-0.5 size-4 shrink-0 [stroke-width:1.875]" }),
|
|
121
|
+
message
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
)
|
|
125
|
+
] });
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { InputOTP };
|
|
129
|
+
//# sourceMappingURL=chunk-XL75JRUA.js.map
|
|
130
|
+
//# sourceMappingURL=chunk-XL75JRUA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/input-otp.tsx"],"names":[],"mappings":";;;;;;AAuDO,SAAS,QAAA,CAAS;AAAA,EACvB,MAAA,GAAS,CAAA;AAAA,EACT,SAAA,GAAY,CAAA;AAAA,EACZ,KAAA,EAAO,SAAA;AAAA,EACP,YAAA,GAAe,EAAA;AAAA,EACf,aAAA;AAAA,EACA,UAAA;AAAA,EACA,OAAA,GAAU,MAAA;AAAA,EACV,KAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,EAAA;AAAA,EACA,IAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAkB;AAEhB,EAAA,MAAM,MAAA,GAAS,eAAe,EAAE,EAAA,EAAI,UAAU,KAAA,EAAO,KAAA,GAAQ,IAAA,GAAO,MAAA,EAAW,CAAA;AAC/E,EAAA,MAAM,OAAA,GAAU,OAAO,KAAA,KAAU,QAAA,IAAkB,qBAAe,KAAK,CAAA;AACvE,EAAA,MAAM,SAAA,GAAY,CAAC,MAAA,CAAO,OAAA,IAAW,QAAQ,OAAO,CAAA;AACpD,EAAA,MAAM,cAAA,GAAiB,SAAA,IAAa,OAAA,KAAY,IAAA,GAAQ,OAAA,GAA8B,IAAA;AACtF,EAAA,MAAM,UAAU,OAAA,GAAW,KAAA,GAA4B,cAAA,KAAmB,MAAA,CAAO,UAAU,IAAA,GAAO,IAAA,CAAA;AAClG,EAAA,MAAM,SAAA,GAAY,OAAA,GAAU,CAAA,EAAG,MAAA,CAAO,SAAS,CAAA,QAAA,CAAA,GAAa,MAAA;AAC5D,EAAA,MAAM,WAAA,GAAc,CAAC,MAAA,CAAO,WAAA,EAAa,SAAS,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,IAAK,MAAA;AACjF,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAU,eAAS,YAAY,CAAA;AACrD,EAAA,MAAM,KAAA,GAAA,CAAS,SAAA,IAAa,KAAA,EAAO,KAAA,CAAM,GAAG,MAAM,CAAA;AAClD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAU,eAAS,KAAK,CAAA;AAClD,EAAA,MAAM,QAAA,GAAiB,aAAyB,IAAI,CAAA;AAEpD,EAAA,MAAM,GAAA,GAAM,CAAC,GAAA,KAAgB;AAC3B,IAAA,MAAM,OAAO,CAAC,GAAG,GAAG,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAC,CAAA,CAAE,IAAA,CAAK,EAAE,CAAA,CAAE,KAAA,CAAM,GAAG,MAAM,CAAA;AAC7E,IAAA,IAAI,SAAA,IAAa,IAAA,EAAM,QAAA,CAAS,IAAI,CAAA;AACpC,IAAA,aAAA,GAAgB,IAAI,CAAA;AACpB,IAAA,IAAI,KAAK,MAAA,KAAW,MAAA,IAAU,IAAA,KAAS,KAAA,eAAoB,IAAI,CAAA;AAAA,EACjE,CAAA;AAEA,EAAA,MAAM,SAAS,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,MAAA,EAAQ,SAAS,CAAC,CAAA;AAChD,EAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,EAAE,QAAO,EAAG,CAAC,CAAA,EAAG,CAAA,KAAM,CAAC,CAAA;AAEhD,EAAA,uBACE,IAAA,CAAC,eAAY,KAAA,EAAc,MAAA,EAAgB,WAAW,EAAA,CAAG,OAAA,EAAS,SAAS,CAAA,EACzE,QAAA,EAAA;AAAA,oBAAA,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,WAAA,EAAU,WAAA;AAAA,QACV,eAAA,EAAe,OAAO,QAAA,IAAY,MAAA;AAAA,QAClC,SAAA,EAAW,EAAA,CAAG,wCAAA,EAA0C,MAAA,CAAO,YAAY,YAAY,CAAA;AAAA,QAEtF,QAAA,EAAA;AAAA,UAAA,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM;AAChB,YAAA,MAAM,QAAA,GAAW,WAAW,CAAA,KAAM,MAAA;AAClC,YAAA,uBACE,IAAA,CAAO,gBAAN,EACE,QAAA,EAAA;AAAA,cAAA,SAAA,GAAY,CAAA,IAAK,CAAA,GAAI,CAAA,IAAK,CAAA,GAAI,SAAA,KAAc,CAAA,oBAC3C,GAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAW,IAAA,EAAC,SAAA,EAAU,oCAAA,EAAqC,CAAA;AAAA,8BAEnE,IAAA;AAAA,gBAAC,MAAA;AAAA,gBAAA;AAAA,kBACC,aAAA,EAAW,IAAA;AAAA,kBACX,eAAa,QAAA,IAAY,MAAA;AAAA,kBACzB,SAAA,EAAW,EAAA;AAAA,oBACT,uIAAA;AAAA,oBACA,kDAAA;AAAA,oBACA,mFAAA;AAAA,oBACA,MAAA,CAAO,OAAA,GAAU,8BAAA,GAAiC,SAAA,GAAY,wBAAA,GAA2B,uBAAA;AAAA,oBACzF,QAAA,KACG,MAAA,CAAO,OAAA,GACJ,uDAAA,GACA,YACE,mDAAA,GACA,qEAAA;AAAA,mBACV;AAAA,kBAEC,QAAA,EAAA;AAAA,oBAAA,KAAA,CAAM,CAAC,CAAA,IAAK,EAAA;AAAA,oBACZ,YAAY,KAAA,CAAM,MAAA,GAAS,0BAC1B,GAAA,CAAC,MAAA,EAAA,EAAK,WAAU,mFAAA,EAAoF;AAAA;AAAA;AAAA;AAExG,aAAA,EAAA,EAxBmB,CAyBrB,CAAA;AAAA,UAEJ,CAAC,CAAA;AAAA,0BACD,GAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,GAAA,EAAK,QAAA;AAAA,cACL,IAAI,MAAA,CAAO,SAAA;AAAA,cACX,IAAA;AAAA,cACA,KAAA;AAAA,cACA,UAAU,CAAC,CAAA,KAAM,GAAA,CAAI,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,cACnC,OAAA,EAAS,CAAC,CAAA,KAAM;AACd,gBAAA,UAAA,CAAW,IAAI,CAAA;AAEf,gBAAA,MAAM,GAAA,GAAM,CAAA,CAAE,aAAA,CAAc,KAAA,CAAM,MAAA;AAClC,gBAAA,qBAAA,CAAsB,MAAM,QAAA,CAAS,OAAA,EAAS,iBAAA,CAAkB,GAAA,EAAK,GAAG,CAAC,CAAA;AAAA,cAC3E,CAAA;AAAA,cACA,MAAA,EAAQ,MAAM,UAAA,CAAW,KAAK,CAAA;AAAA,cAC9B,QAAA,EAAU,CAAC,CAAA,KAAM;AACf,gBAAA,MAAM,GAAA,GAAM,CAAA,CAAE,aAAA,CAAc,KAAA,CAAM,MAAA;AAClC,gBAAA,IAAI,CAAA,CAAE,cAAc,cAAA,KAAmB,GAAA,IAAO,aAAA,CAAc,iBAAA,CAAkB,KAAK,GAAG,CAAA;AAAA,cACxF,CAAA;AAAA,cACA,SAAA,EAAW,MAAA;AAAA,cACX,SAAA,EAAW,OAAA,CAAQ,IAAA,CAAK,GAAG,CAAA,IAAK,CAAC,OAAA,CAAQ,IAAA,CAAK,GAAG,CAAA,GAAI,SAAA,GAAY,MAAA;AAAA,cACjE,YAAA,EAAa,eAAA;AAAA,cACb,SAAA;AAAA,cACA,UAAU,MAAA,CAAO,QAAA;AAAA,cACjB,cAAA,EAAc,OAAO,OAAA,IAAW,MAAA;AAAA,cAChC,kBAAA,EAAkB,WAAA;AAAA,cAClB,YAAA,EAAY,MAAM,YAAY,CAAA;AAAA,cAC9B,UAAA,EAAY,KAAA;AAAA,cACZ,SAAA,EAAU;AAAA;AAAA;AACZ;AAAA;AAAA,KACF;AAAA,oBAEA,IAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,EAAA,EAAI,SAAA;AAAA,QACJ,WAAA,EAAU,QAAA;AAAA,QACV,SAAA,EAAW,EAAA;AAAA,UACT,mEAAA;AAAA,UACA,OAAA,GAAU,4BAAA,GAA+B,cAAA,GAAiB,sBAAA,GAAyB;AAAA,SACrF;AAAA,QAEC,QAAA,EAAA;AAAA,UAAA,cAAA,oBAAkB,GAAA,CAAC,WAAA,EAAA,EAAY,aAAA,EAAW,IAAA,EAAC,WAAU,6CAAA,EAA8C,CAAA;AAAA,UACnG;AAAA;AAAA;AAAA;AACH,GAAA,EACF,CAAA;AAEJ","file":"chunk-XL75JRUA.js","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { CheckCircle } from 'iconoir-react'\nimport { cn } from '../lib/utils'\nimport { FieldChrome, useFieldChrome } from './select'\n\n/**\n * InputOTP, 1:1 with the uiKit design (🆕 input otp & number): a one-time code as 36×36 cells,\n * 8px apart, in groups (3 + 3 by default) split by an 8px border/strong dash. Each cell wears the\n * field skin (bg/field, border/default, radius-lg, shadow xs); the cell the next digit goes into\n * gets the focus border and ring and a blinking caret while the field has focus. A digit is\n * text/base medium. With an error every cell turns action/destructive and the message replaces the\n * hint under the cells; label, hint and error sit like Input's. With `success` (the code checked\n * out) every cell's border turns status/green/fg and the message, in the same colour, leads with a\n * 16px check.\n *\n * The message never moves the cells: it is as wide as the cells (it wraps rather than widening\n * the field, which would shift a centred field sideways) and keeps a 20px line even while empty,\n * so swapping hint → \"Checking…\" → success or error leaves the code where it is.\n *\n * The field is as wide as its cells, so it centres wherever it is placed. Focus shows only on\n * the active cell: the real input carries no ring of its own.\n *\n * One real <input> lies over the cells (transparent text and caret), so typing, deleting, paste\n * and the browser's SMS autofill (`autocomplete=\"one-time-code\"`) all work as in any field, and\n * screen readers hear one text box. Only digits by default (`pattern`); `onComplete` fires when\n * every cell is filled.\n */\nexport interface InputOTPProps {\n /** How many characters. */\n length?: number\n /** Cells per group; groups are split by a dash. 0 for one group. */\n groupSize?: number\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n /** Every cell is filled. */\n onComplete?: (value: string) => void\n /** Which characters are allowed. Digits by default. */\n pattern?: RegExp\n label?: React.ReactNode\n hint?: React.ReactNode\n /** An error message (replaces the hint), or `true` to mark the cells invalid without one. */\n error?: React.ReactNode | boolean\n /** The code checked out: a message under the cells (replaces the hint), or `true` for green cells alone. Ignored while there is an error. */\n success?: React.ReactNode | boolean\n disabled?: boolean\n autoFocus?: boolean\n id?: string\n name?: string\n 'aria-label'?: string\n className?: string\n}\n\nexport function InputOTP({\n length = 6,\n groupSize = 3,\n value: valueProp,\n defaultValue = '',\n onValueChange,\n onComplete,\n pattern = /^\\d$/,\n label,\n hint,\n error,\n success,\n disabled,\n autoFocus,\n id,\n name,\n className,\n ...props\n}: InputOTPProps) {\n // The message under the cells is drawn here, so the chrome only gets whether there is an error.\n const chrome = useFieldChrome({ id, disabled, error: error ? true : undefined })\n const isError = typeof error === 'string' || React.isValidElement(error)\n const isSuccess = !chrome.invalid && Boolean(success)\n const successMessage = isSuccess && success !== true ? (success as React.ReactNode) : null\n const message = isError ? (error as React.ReactNode) : successMessage ?? (chrome.invalid ? null : hint)\n const messageId = message ? `${chrome.controlId}-message` : undefined\n const describedBy = [chrome.describedBy, messageId].filter(Boolean).join(' ') || undefined\n const [inner, setInner] = React.useState(defaultValue)\n const value = (valueProp ?? inner).slice(0, length)\n const [focused, setFocused] = React.useState(false)\n const inputRef = React.useRef<HTMLInputElement>(null)\n\n const set = (raw: string) => {\n const next = [...raw].filter((c) => pattern.test(c)).join('').slice(0, length)\n if (valueProp == null) setInner(next)\n onValueChange?.(next)\n if (next.length === length && next !== value) onComplete?.(next)\n }\n\n const active = Math.min(value.length, length - 1)\n const cells = Array.from({ length }, (_, i) => i)\n\n return (\n <FieldChrome label={label} chrome={chrome} className={cn('w-fit', className)}>\n <div\n data-slot=\"input-otp\"\n data-disabled={chrome.disabled || undefined}\n className={cn('relative flex w-fit items-center gap-2', chrome.disabled && 'opacity-50')}\n >\n {cells.map((i) => {\n const isActive = focused && i === active\n return (\n <React.Fragment key={i}>\n {groupSize > 0 && i > 0 && i % groupSize === 0 && (\n <span aria-hidden className=\"h-px w-2 shrink-0 bg-border-strong\" />\n )}\n <span\n aria-hidden\n data-active={isActive || undefined}\n className={cn(\n 'relative grid size-9 shrink-0 place-items-center rounded-lg border bg-bg-field text-base leading-[21px] font-medium text-text-default',\n '[box-shadow:0_1px_2px_0_var(--effect-shadow-xs)]',\n 'transition-[border-color,box-shadow] duration-(--duration-fast) ease-(--ease-out)',\n chrome.invalid ? 'border-action-destructive-bg' : isSuccess ? 'border-status-green-fg' : 'border-border-default',\n isActive &&\n (chrome.invalid\n ? '[box-shadow:0_0_0_2px_var(--action-destructive-glow)]'\n : isSuccess\n ? '[box-shadow:0_0_0_2px_var(--status-green-border)]'\n : 'border-border-focus [box-shadow:0_0_0_2px_var(--action-focus-ring)]'),\n )}\n >\n {value[i] ?? ''}\n {isActive && value.length < length && (\n <span className=\"absolute h-[18px] w-px animate-[satin-caret_1s_steps(1)_infinite] bg-text-default\" />\n )}\n </span>\n </React.Fragment>\n )\n })}\n <input\n ref={inputRef}\n id={chrome.controlId}\n name={name}\n value={value}\n onChange={(e) => set(e.target.value)}\n onFocus={(e) => {\n setFocused(true)\n // Always type at the end: the cells show where.\n const end = e.currentTarget.value.length\n requestAnimationFrame(() => inputRef.current?.setSelectionRange(end, end))\n }}\n onBlur={() => setFocused(false)}\n onSelect={(e) => {\n const end = e.currentTarget.value.length\n if (e.currentTarget.selectionStart !== end) e.currentTarget.setSelectionRange(end, end)\n }}\n maxLength={length}\n inputMode={pattern.test('5') && !pattern.test('a') ? 'numeric' : 'text'}\n autoComplete=\"one-time-code\"\n autoFocus={autoFocus}\n disabled={chrome.disabled}\n aria-invalid={chrome.invalid || undefined}\n aria-describedby={describedBy}\n aria-label={props['aria-label']}\n spellCheck={false}\n className=\"absolute inset-0 w-full cursor-text bg-transparent text-transparent caret-transparent outline-none selection:bg-transparent focus-visible:outline-none focus-visible:ring-0 focus-visible:[box-shadow:none] disabled:cursor-not-allowed\"\n />\n </div>\n {/* 0 wide and min-w-full: as wide as the cells, never wider; min-h-5 holds the line while empty. */}\n <p\n id={messageId}\n aria-live=\"polite\"\n className={cn(\n 'flex min-h-5 w-0 min-w-full items-start gap-1.5 text-sm leading-5',\n isError ? 'text-action-destructive-bg' : successMessage ? 'text-status-green-fg' : 'text-text-muted',\n )}\n >\n {successMessage && <CheckCircle aria-hidden className=\"mt-0.5 size-4 shrink-0 [stroke-width:1.875]\" />}\n {message}\n </p>\n </FieldChrome>\n )\n}\n"]}
|