gridsmith-ui 0.30.2 → 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +71 -1
- package/dist/charts.d.ts +114 -1
- package/dist/charts.js +1113 -206
- package/dist/charts.js.map +1 -1
- package/dist/chat.js +20 -12
- package/dist/chat.js.map +1 -1
- package/dist/{chunk-HVGHGBKV.js → chunk-2TCCSKL3.js} +6 -7
- package/dist/chunk-2TCCSKL3.js.map +1 -0
- package/dist/{chunk-L6HWACK7.js → chunk-53F7GVBQ.js} +6 -3
- package/dist/chunk-53F7GVBQ.js.map +1 -0
- package/dist/chunk-BHTAVJIG.js +285 -0
- package/dist/chunk-BHTAVJIG.js.map +1 -0
- package/dist/{chunk-WWN6CQKI.js → chunk-DR6WEI3A.js} +60 -7
- package/dist/chunk-DR6WEI3A.js.map +1 -0
- package/dist/{chunk-4HJDOZ2M.js → chunk-EZ3ZGFGA.js} +203 -34
- package/dist/chunk-EZ3ZGFGA.js.map +1 -0
- package/dist/{chunk-MIUSSYVE.js → chunk-HQFTP7Y5.js} +27 -52
- package/dist/chunk-HQFTP7Y5.js.map +1 -0
- package/dist/{chunk-SIWERRP2.js → chunk-I6JJ7KKP.js} +14 -15
- package/dist/chunk-I6JJ7KKP.js.map +1 -0
- package/dist/chunk-IOHGE4EW.js +755 -0
- package/dist/chunk-IOHGE4EW.js.map +1 -0
- package/dist/{chunk-USHW523V.js → chunk-IZW5XHKA.js} +73 -699
- package/dist/chunk-IZW5XHKA.js.map +1 -0
- package/dist/{chunk-ZASGFL5D.js → chunk-K3NAFQ4S.js} +3 -4
- package/dist/chunk-K3NAFQ4S.js.map +1 -0
- package/dist/{chunk-ACLKDE5W.js → chunk-KSJTMSYA.js} +23 -11
- package/dist/chunk-KSJTMSYA.js.map +1 -0
- package/dist/{chunk-SQHKC4HA.js → chunk-NDL2JGQ7.js} +8 -7
- package/dist/chunk-NDL2JGQ7.js.map +1 -0
- package/dist/{chunk-TYNDXMBV.js → chunk-QOMP4D6V.js} +3 -3
- package/dist/{chunk-TYNDXMBV.js.map → chunk-QOMP4D6V.js.map} +1 -1
- package/dist/{chunk-BZRZENBS.js → chunk-SLGGZ3MU.js} +6 -6
- package/dist/{chunk-BZRZENBS.js.map → chunk-SLGGZ3MU.js.map} +1 -1
- package/dist/{chunk-K6IDOCGE.js → chunk-TH272DIC.js} +10 -10
- package/dist/{chunk-K6IDOCGE.js.map → chunk-TH272DIC.js.map} +1 -1
- package/dist/chunk-V73LHNRL.js +51 -0
- package/dist/chunk-V73LHNRL.js.map +1 -0
- package/dist/{chunk-ZCDA74RQ.js → chunk-W3GY5ROH.js} +3 -3
- package/dist/{chunk-ZCDA74RQ.js.map → chunk-W3GY5ROH.js.map} +1 -1
- package/dist/data-grid.js +11 -12
- package/dist/data-grid.js.map +1 -1
- package/dist/editor-mentions.js +2 -3
- package/dist/editor-mentions.js.map +1 -1
- package/dist/editor.js +4 -6
- package/dist/editor.js.map +1 -1
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +100 -16
- package/dist/index.js +1177 -660
- package/dist/index.js.map +1 -1
- package/dist/kanban.js +10 -11
- package/dist/kanban.js.map +1 -1
- package/dist/resizable.js +10 -11
- package/dist/resizable.js.map +1 -1
- package/dist/virtualized.js +11 -12
- package/dist/virtualized.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-4HJDOZ2M.js.map +0 -1
- package/dist/chunk-6C2IUMY7.js +0 -46
- package/dist/chunk-6C2IUMY7.js.map +0 -1
- package/dist/chunk-7Q46JXSK.js +0 -51
- package/dist/chunk-7Q46JXSK.js.map +0 -1
- package/dist/chunk-ACLKDE5W.js.map +0 -1
- package/dist/chunk-HVGHGBKV.js.map +0 -1
- package/dist/chunk-L6HWACK7.js.map +0 -1
- package/dist/chunk-MIUSSYVE.js.map +0 -1
- package/dist/chunk-NKUCS67T.js +0 -13
- package/dist/chunk-NKUCS67T.js.map +0 -1
- package/dist/chunk-SIWERRP2.js.map +0 -1
- package/dist/chunk-SQHKC4HA.js.map +0 -1
- package/dist/chunk-USHW523V.js.map +0 -1
- package/dist/chunk-WWN6CQKI.js.map +0 -1
- package/dist/chunk-YL5KD5RC.js +0 -49
- package/dist/chunk-YL5KD5RC.js.map +0 -1
- package/dist/chunk-ZASGFL5D.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/lib/control-looks.ts","../../../showcase/src/lib/filter-row.ts","../../../showcase/src/components/Input.tsx","../../../showcase/src/components/InlineFieldError.tsx","../../../showcase/src/components/Field.tsx","../../../showcase/src/components/Dropdown.tsx"],"names":["jsxs","jsx","createContext","useContext","useEffect","useId","useState","useRef","useCallback","useLayoutEffect"],"mappings":"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","file":"chunk-IZW5XHKA.js","sourcesContent":["/**\n * Sprint 25.14 A20: the checked and switched looks, shared by the controls (Checkbox, RadioGroup, Toggle) and the Card's\n * selection indicators, so the two never drift apart (the review of 30 September: the Card kept the old switch, the\n * accent's gradient and the accent dot after the controls moved).\n */\n\n/** A checked box's fill and a selected radio's dot: the check colour, with the theme's check gradient (by default the accent's) over it. */\nexport const CHECK_FILL = \"bg-[var(--ds-check-bg)] [background-image:var(--ds-check-gradient,var(--ds-gradient))]\";\n\n/** A switch's track when on: the check colour, as a checked box's. */\nexport const SWITCH_TRACK_ON = \"bg-[var(--ds-check-bg)] border-transparent\";\n\n/**\n * A switch's track when off: from tokens only a regenerated stylesheet has (the theme writers emit them), falling back\n * to the switch as it was, so an app that hasn't regenerated never gets an outline in its old, fainter edge colour.\n */\nexport const SWITCH_TRACK_OFF = \"bg-[var(--ds-switch-off-fill,var(--ds-bg-muted))] border-[var(--ds-switch-off-edge,var(--ds-border-default))]\";\n\n/**\n * A switch's knob when on: the surface made opaque (a glass theme's half-white surface would show the track through it),\n * as pinned table cells are (D31); a surface that is wholly transparent stays so.\n */\nexport const SWITCH_KNOB_ON = \"bg-[var(--ds-bg-surface)] supports-[color:oklch(from_red_l_c_h)]:bg-[oklch(from_var(--ds-bg-surface)_l_c_h_/_max(alpha,min(1,alpha*1000)))]\";\n\n/** A switch's knob when off: the edge colour, beside the outline (the same fallback as the track). */\nexport const SWITCH_KNOB_OFF = \"bg-[var(--ds-switch-off-knob,var(--ds-bg-surface))]\";\n\n/** The knob moves and changes colour together with its track, so it never shows before the track does. */\nexport const SWITCH_KNOB_MOTION = \"transition-[transform,background-color] duration-[var(--ds-transition-speed)]\";\n","import { createContext } from \"react\";\n\n/**\n * A row of filters (PageHeader's filters slot) tells the controls in it that they are in one, so a text field takes a\n * search field's width, the table toolbar's (280 px), instead of a line of its own (the owner's\n * look at a bold header with content overlap, 30 September 2026: the search box filled a whole line).\n */\nexport const FilterRowContext = createContext(false);\n\n/**\n * A text field's width in a filter row: the toolbar search's 280 px, never wider than the row. A set width, not a flex\n * basis: a row that hugs its controls (the strip on a bold band) sizes itself from their widths, and a basis it doesn't\n * count pushed the field onto a line of its own.\n */\nexport const FILTER_FIELD_WIDTH = \"w-[280px] max-w-full\";\n","import { useCallback, useContext, useEffect, useRef, type Ref } from \"react\";\nimport { cn, FIELD_FOCUS_RING, FIELD_HAS_FOCUS_RING, ERROR_FOCUS_RING, ERROR_HAS_FOCUS_RING, FOCUS_RING } from \"../lib/utils\";\nimport { useInputModality } from \"../lib/input-modality\";\nimport type { ReactNode, InputHTMLAttributes, TextareaHTMLAttributes, LabelHTMLAttributes } from \"react\";\nimport { ControlSizeContext } from \"./Button\";\nimport { useReportedChange } from \"../lib/form-context\";\nimport { warnNameLeftOut } from \"../lib/dev-warn\";\nimport { SWITCH_KNOB_MOTION, SWITCH_KNOB_OFF, SWITCH_KNOB_ON, SWITCH_TRACK_OFF, SWITCH_TRACK_ON } from \"../lib/control-looks\";\nimport { FILTER_FIELD_WIDTH, FilterRowContext } from \"../lib/filter-row\";\n\n/** A native field's new value from its change event: `checked` for a box, `value` for the rest (Sprint 25.12 A15). */\n/** An uncontrolled field's value, which no edit equals: the field holds its value itself. */\nconst UNCONTROLLED = Symbol(\"uncontrolled\");\nconst valueOf = (e: { target: EventTarget | null }) => {\n const t = e.target as HTMLInputElement | HTMLTextAreaElement | null;\n if (!t) return undefined;\n return t instanceof HTMLInputElement && (t.type === \"checkbox\" || t.type === \"radio\") ? t.checked : t.value;\n};\n\ntype InputSize = \"sm\" | \"md\" | \"lg\";\n\n// \"prefix\" must be omitted from the inherited attributes: React's HTMLAttributes\n// declares the RDFa attribute `prefix?: string`, and intersecting it with\n// `prefix?: ReactNode` collapses the prop to string-only at use sites.\nconst INPUT_HEIGHT: Record<InputSize, string> = {\n sm: \"h-[var(--ds-control-height-sm)]\",\n md: \"h-[var(--ds-control-height-md)]\",\n lg: \"h-[var(--ds-control-height-lg)]\",\n};\n\nconst INPUT_TEXT: Record<InputSize, string> = {\n sm: \"px-ds-2 py-ds-1 text-xs\",\n md: \"px-ds-3 py-ds-2 text-sm\",\n lg: \"px-ds-4 py-ds-3 text-base\",\n};\n\nexport function Input({ className, size: sizeProp, error = false, prefix, suffix, ...props }: Omit<InputHTMLAttributes<HTMLInputElement>, \"size\" | \"prefix\"> & { size?: InputSize; error?: boolean; prefix?: ReactNode; suffix?: ReactNode }) {\n // a field: clicked into, the active look; reached with Tab, the outline (Sprint 30, lib/input-modality.ts)\n useInputModality();\n const contextSize = useContext(ControlSizeContext);\n const size = sizeProp ?? contextSize ?? \"md\";\n // in a row of filters, a search field's width rather than a line of its own (the owner, 30 September)\n const width = useContext(FilterRowContext) ? FILTER_FIELD_WIDTH : \"w-full\";\n // Sprint 25.12 A15: the user's typing marks the form's overlay (only a new value); the page's onChange runs as given.\n // Uncontrolled (defaultValue), every edit is new: clearing a prefilled field compared \"\" with no value (0.21.0).\n const onChange = useReportedChange(props.onChange, props.value === undefined ? UNCONTROLLED : props.value, valueOf);\n const borderColor = error ? \"border-[var(--ds-status-error)]\" : \"border-[var(--ds-input-border)]\";\n const hoverBorder = !error && !props.disabled && !props.readOnly ? \"hover:border-[var(--ds-input-border-hover)]\" : \"\";\n\n if (prefix || suffix) {\n return (\n <div\n className={cn(\n \"flex items-center\", width,\n INPUT_HEIGHT[size],\n \"bg-[var(--ds-input-bg)]\",\n \"border-[length:var(--ds-border-width)]\", borderColor,\n \"rounded-[var(--ds-radius-md)]\",\n \"shadow-[var(--ds-input-shadow)]\",\n hoverBorder,\n error ? ERROR_HAS_FOCUS_RING : FIELD_HAS_FOCUS_RING,\n \"transition-colors duration-[var(--ds-transition-speed)]\",\n props.disabled && \"cursor-not-allowed opacity-disabled\",\n props.readOnly && \"bg-[var(--ds-bg-muted)] cursor-default\",\n className\n )}\n >\n {prefix && <span className=\"shrink-0 pl-ds-3 text-[var(--ds-text-muted)] flex items-center\">{prefix}</span>}\n <input\n aria-invalid={error || undefined}\n className={cn(\n \"flex-1 min-w-0 bg-transparent outline-none\",\n INPUT_TEXT[size],\n \"text-[var(--ds-text-primary)]\",\n \"placeholder:text-[var(--ds-text-muted)]\",\n \"disabled:cursor-not-allowed\",\n \"read-only:text-[var(--ds-text-secondary)] read-only:cursor-default\",\n )}\n {...props}\n onChange={props.onChange || props.value === undefined ? onChange : undefined}\n />\n {suffix && <span className=\"shrink-0 pr-ds-3 text-[var(--ds-text-muted)] flex items-center\">{suffix}</span>}\n </div>\n );\n }\n\n return (\n <input\n aria-invalid={error || undefined}\n className={cn(\n \"flex\", width,\n INPUT_TEXT[size], INPUT_HEIGHT[size],\n \"bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)]\",\n \"border-[length:var(--ds-border-width)]\", borderColor,\n \"rounded-[var(--ds-radius-md)]\",\n \"shadow-[var(--ds-input-shadow)]\",\n \"placeholder:text-[var(--ds-text-muted)]\",\n hoverBorder,\n error ? ERROR_FOCUS_RING : FIELD_FOCUS_RING,\n \"disabled:cursor-not-allowed disabled:opacity-disabled\",\n \"read-only:bg-[var(--ds-bg-muted)] read-only:text-[var(--ds-text-secondary)] read-only:cursor-default\",\n \"transition-colors duration-[var(--ds-transition-speed)]\",\n className\n )}\n {...props}\n onChange={props.onChange || props.value === undefined ? onChange : undefined}\n />\n );\n}\n\ninterface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {\n autoResize?: boolean;\n maxRows?: number;\n error?: boolean;\n ref?: Ref<HTMLTextAreaElement>;\n}\n\nexport function Textarea({ className, autoResize, maxRows, error = false, ref, ...props }: TextareaProps) {\n // a field, as Input (Sprint 30)\n useInputModality();\n // Sprint 25.12 A15: as Input\n const onChange = useReportedChange(props.onChange, props.value === undefined ? UNCONTROLLED : props.value, valueOf);\n const internalRef = useRef<HTMLTextAreaElement>(null);\n const textareaRef = (ref ?? internalRef) as React.RefObject<HTMLTextAreaElement>;\n\n const resize = useCallback(() => {\n const el = textareaRef.current;\n if (!el || !autoResize) return;\n el.style.height = \"auto\";\n let target = el.scrollHeight;\n if (maxRows) {\n const lineHeight = parseFloat(getComputedStyle(el).lineHeight) || 20;\n const maxHeight = lineHeight * maxRows + parseFloat(getComputedStyle(el).paddingTop) + parseFloat(getComputedStyle(el).paddingBottom);\n target = Math.min(target, maxHeight);\n }\n el.style.height = `${target}px`;\n }, [autoResize, maxRows, textareaRef]);\n\n useEffect(() => { resize(); }, [resize, props.value, props.defaultValue]);\n\n return (\n <textarea\n ref={textareaRef}\n aria-invalid={error || undefined}\n className={cn(\n \"flex min-h-[var(--ds-control-height-md)] w-full px-ds-3 py-ds-2 text-sm\",\n \"bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)]\",\n \"border-[length:var(--ds-border-width)]\",\n error ? \"border-[var(--ds-status-error)]\" : \"border-[var(--ds-input-border)] hover:border-[var(--ds-input-border-hover)]\",\n \"rounded-[var(--ds-radius-md)]\",\n \"shadow-[var(--ds-input-shadow)]\",\n \"placeholder:text-[var(--ds-text-muted)]\",\n error ? ERROR_FOCUS_RING : FIELD_FOCUS_RING,\n \"disabled:cursor-not-allowed disabled:opacity-disabled disabled:hover:border-[var(--ds-input-border)]\",\n \"read-only:bg-[var(--ds-bg-muted)] read-only:text-[var(--ds-text-secondary)] read-only:cursor-default read-only:hover:border-[var(--ds-input-border)]\",\n \"transition-colors duration-[var(--ds-transition-speed)]\",\n autoResize && \"resize-none overflow-hidden\",\n className\n )}\n onInput={autoResize ? resize : undefined}\n {...props}\n onChange={props.onChange || props.value === undefined ? onChange : undefined}\n />\n );\n}\n\nexport function Label({ className, children, ...props }: LabelHTMLAttributes<HTMLLabelElement>) {\n return (\n <label\n className={cn(\n \"text-sm font-medium leading-none text-[var(--ds-text-secondary)]\",\n \"peer-disabled:cursor-not-allowed peer-disabled:opacity-disabled\",\n className\n )}\n {...props}\n >\n {children}\n </label>\n );\n}\n\nexport type ToggleLayout = \"full\" | \"compact\";\nexport type ToggleSize = \"sm\" | \"md\";\n\n// Track width/height and thumb diameter; the thumb sits 1px inside the border.\nconst TOGGLE_SIZES: Record<ToggleSize, { w: number; h: number; thumb: number }> = {\n sm: { w: 32, h: 18, thumb: 12 },\n md: { w: 44, h: 24, thumb: 16 },\n};\n\nexport function Toggle({ checked, onChange, label, disabled, error = false, layout = \"full\", size = \"md\", \"aria-label\": pageLabel, \"aria-labelledby\": pageLabelledBy, ...rest }: { checked: boolean; onChange: (v: boolean) => void; label?: string; disabled?: boolean; error?: boolean; layout?: ToggleLayout; size?: ToggleSize; \"aria-labelledby\"?: string } & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"onChange\">) {\n // its own label on screen leads its name, which a page's aria-label or aria-labelledby beside it would replace (the final\n // review of 0.31.0, 1; WCAG 2.5.3); a Field's label leaves them out before they reach here\n useEffect(() => {\n if (!label) return;\n if (pageLabel) warnNameLeftOut(\"Toggle\", \"aria-label\", pageLabel, \"its own label\");\n if (pageLabelledBy) warnNameLeftOut(\"Toggle\", \"aria-labelledby\", pageLabelledBy, \"its own label\");\n }, [label, pageLabel, pageLabelledBy]);\n const ariaLabel = label ? undefined : pageLabel;\n const ariaLabelledBy = label ? undefined : pageLabelledBy;\n // Sprint 25.12 A15: a flip is a change, reported to the form's overlay\n const change = useReportedChange(onChange, checked);\n const dims = TOGGLE_SIZES[size];\n const travel = dims.w - dims.thumb - 3;\n const switchButton = (\n <button type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n // \"Toggle\" only where nothing names it: an id is for a label (a Field's <label for>), as TagInput's\n aria-label={ariaLabel ?? (!label && !ariaLabelledBy && !rest.id ? \"Toggle\" : undefined)}\n aria-labelledby={ariaLabelledBy}\n aria-invalid={error || undefined}\n disabled={disabled}\n onClick={() => !disabled && change(!checked)}\n {...rest}\n className={cn(\n \"relative inline-flex shrink-0 items-center overflow-hidden\",\n \"border-[length:var(--ds-border-width)]\",\n \"rounded-[var(--ds-radius-full)]\",\n \"transition-colors duration-[var(--ds-transition-speed)]\",\n FOCUS_RING,\n disabled ? \"cursor-not-allowed\" : \"cursor-pointer\",\n // Sprint 25.14 A20: on, the checked colour, as a checkbox's; off, the outline in the edge colour (lib/control-looks.ts)\n checked ? SWITCH_TRACK_ON : SWITCH_TRACK_OFF,\n error && \"border-[var(--ds-status-error)]\"\n )}\n style={{ width: dims.w, height: dims.h }}\n >\n <span\n className={cn(\n \"pointer-events-none inline-block shrink-0\",\n // on: the surface made opaque; off: the edge colour, beside the outline\n checked ? SWITCH_KNOB_ON : SWITCH_KNOB_OFF,\n \"border-[length:var(--ds-border-width)] border-transparent\",\n \"rounded-[var(--ds-radius-full)]\",\n SWITCH_KNOB_MOTION\n )}\n style={{\n width: dims.thumb,\n height: dims.thumb,\n transform: checked\n ? `translateX(calc(${travel}px - var(--ds-border-width)))`\n : \"translateX(calc(1px + var(--ds-border-width)))\",\n }}\n />\n </button>\n );\n\n if (!label) {\n return <div className={cn(disabled && \"opacity-disabled\")}>{switchButton}</div>;\n }\n\n return (\n <label\n className={cn(\n layout === \"full\"\n ? \"flex items-center justify-between gap-ds-4\"\n : \"inline-flex items-center gap-ds-3\",\n disabled ? \"cursor-not-allowed opacity-disabled\" : \"cursor-pointer\",\n )}\n >\n <span className=\"text-sm font-medium text-[var(--ds-text-primary)]\">{label}</span>\n {switchButton}\n </label>\n );\n}\n","import { cn } from \"../lib/utils\";\nimport { Icon } from \"../lib/icons\";\n\ninterface InlineFieldErrorProps {\n message: string;\n id: string;\n className?: string;\n}\n\nexport function InlineFieldError({ message, id, className }: InlineFieldErrorProps) {\n return (\n <p\n id={id}\n role=\"alert\"\n className={cn(\n \"flex items-center gap-ds-1.5 text-xs text-[var(--ds-status-error-text)]\",\n \"mt-ds-1.5\",\n className\n )}\n >\n {/* the words take the status's words colour (Sprint 30, P10); the icon, a mark, keeps the status colour */}\n <Icon name=\"error\" size={14} className=\"shrink-0 text-[var(--ds-status-error)]\" />\n <span>{message}</span>\n </p>\n );\n}\n","import { Children, cloneElement, createContext, isValidElement, useContext, useEffect, useId, useLayoutEffect, useMemo, useState, type ReactElement, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useLatest } from \"../lib/use-latest\";\nimport { useFocusLeave } from \"../lib/focus\";\nimport { useOptionalFormContext } from \"../lib/form-context\";\nimport { Label } from \"./Input\";\nimport { InlineFieldError } from \"./InlineFieldError\";\nimport { warnNameLeftOut } from \"../lib/dev-warn\";\n\nexport interface FieldControlProps {\n id: string;\n \"aria-describedby\"?: string;\n \"aria-invalid\"?: true;\n \"aria-required\"?: true;\n required?: boolean;\n /** Set on Gridsmith form components (Input, Textarea, Dropdown, DatePicker, …). */\n error?: boolean;\n}\n\n/**\n * What a control inside a Field knows about it (Sprint 25.7, C5): the label's id, for a control that `<label for>`\n * cannot name (a slider is a div with role=\"slider\") to take it with aria-labelledby, and the hint and error ids.\n */\nexport interface FieldContextValue {\n controlId: string;\n labelId: string;\n describedBy?: string;\n /** The Field shows an error. */\n invalid?: boolean;\n required?: boolean;\n /** Its label is read but not shown (`hideLabel`): no words on screen for the control's name to start with. */\n labelHidden?: boolean;\n}\n\nconst FieldContext = createContext<FieldContextValue | null>(null);\n\n/** The Field a control sits in, or null. */\nexport function useField(): FieldContextValue | null {\n return useContext(FieldContext);\n}\n\n/**\n * The parts of a control that has several (Sprint 25.19 R2: RecurrencePicker's custom repeat), each with a label of its\n * own: inside, no control takes the Field's id, label, description or error, which name the control's main part only.\n */\nexport function OutsideField({ children }: { children: ReactNode }) {\n return <FieldContext.Provider value={null}>{children}</FieldContext.Provider>;\n}\n\n/** The wiring a control may be given as props: by a Field's clone, or by a page that labels it itself. */\nexport interface FieldControlWiring {\n id?: string;\n /**\n * A name the page gives the control where nothing on screen names it (a row's checkbox, a filter's dropdown). It\n * names the control's focusable element, or its group (Sprint 25.8.7 item 22: TSX checks no hyphenated attribute,\n * so a control that didn't declare it dropped it silently).\n */\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n \"aria-describedby\"?: string;\n \"aria-invalid\"?: boolean | \"true\" | \"false\";\n \"aria-required\"?: boolean | \"true\" | \"false\";\n required?: boolean;\n error?: boolean;\n}\n\n/**\n * What a Gridsmith control that is not a native input takes from the Field it sits in, merged with its own props, which\n * win (round 27 review: Dropdown, DatePicker and SegmentedControl dropped the Field's id and description, so the error\n * summary read \"A field: Needs attention\" with no link, and a screen reader heard the placeholder as the name):\n * - `id`, for the Field's `<label for>`, the summary's link and the focus after a submit;\n * - `labelId`, the label that names it by aria-labelledby, which reaches a button, a group or a radiogroup alike;\n * - `describedBy`, the hint and the error, each id once;\n * - `invalid` and `required`. A role that cannot carry aria-required (a button, a group) says it in its description\n * instead: `requiredNote` is the hidden text, already in `describedBy`, for the control to render.\n * Outside a Field a control gets its own props back.\n *\n * The name, one rule for every such control (the final review of Sprint 25.31, 2): a label on screen, the control's own\n * (`ownLabel`) or its Field's, always leads it, since a name must start with the words on screen (WCAG 2.5.3). A page's\n * `aria-label` or `aria-labelledby` beside one is left out of the name, and a development warning names `component`.\n * With none on screen, ARIA's own order: the page's `aria-labelledby`, else its `aria-label`, else a Field label that\n * isn't shown. A Field applies the same rule to a control that takes no part in it (an Input, a Toggle): see Field.\n */\nexport function useFieldControl(own: FieldControlWiring, options: {\n requiredInDescription?: boolean;\n /** The control, as a page writes it, for the warning: \"Dropdown\". */\n component?: string;\n /** The control's own label on screen: its element's id, or true where it names the control natively (a <label>). */\n ownLabel?: string | true;\n} = {}): {\n id?: string;\n /** The page's aria-label, where no label on screen names the control: the control puts it on what it names. */\n label?: string;\n /**\n * What names it by aria-labelledby: the label on screen (its own, else its Field's; none where its own names it\n * natively), else the page's aria-labelledby, else, where the page gave no aria-label, a Field label that isn't shown.\n */\n labelId?: string;\n /** A label on screen names it, its own or its Field's: the page's names are left out. */\n shown: boolean;\n describedBy?: string;\n invalid: boolean;\n required: boolean;\n requiredNote: ReactNode;\n} {\n const field = useField();\n const id = own.id ?? field?.controlId;\n const invalid = !!own.error || own[\"aria-invalid\"] === true || own[\"aria-invalid\"] === \"true\" || !!field?.invalid;\n const required = !!own.required || own[\"aria-required\"] === true || own[\"aria-required\"] === \"true\" || !!field?.required;\n const noteId = options.requiredInDescription && required && id ? `${id}-required` : undefined;\n const ids = [own[\"aria-describedby\"], field?.describedBy, noteId].filter(Boolean).join(\" \").split(/\\s+/).filter(Boolean);\n const { ownLabel, component } = options;\n const fieldShown = !!field && !field.labelHidden;\n const shown = !!ownLabel || fieldShown;\n const pageLabel = own[\"aria-label\"], pageLabelledBy = own[\"aria-labelledby\"];\n useEffect(() => {\n if (!shown) return;\n const whose = ownLabel ? \"its own label\" : \"its Field's label\";\n for (const [attr, value] of [[\"aria-label\", pageLabel], [\"aria-labelledby\", pageLabelledBy]] as const) {\n if (value) warnNameLeftOut(component ?? \"A Field's control\", attr, value, whose);\n }\n }, [shown, ownLabel, component, pageLabel, pageLabelledBy]);\n return {\n id,\n label: shown ? undefined : pageLabel,\n // with none on screen, ARIA's own order: the page's aria-labelledby, its aria-label, then a Field label that isn't shown\n // (the final review of 0.31.0, 3: a hidden \"Select\" had named every row's box, over the page's \"Select Alice\")\n labelId: shown ? (typeof ownLabel === \"string\" ? ownLabel : ownLabel ? undefined : field?.labelId) : pageLabelledBy ?? (pageLabel ? undefined : field?.labelId),\n shown,\n describedBy: [...new Set(ids)].join(\" \") || undefined,\n invalid,\n required,\n requiredNote: noteId ? <span id={noteId} hidden>Required</span> : null,\n };\n}\n\n/**\n * A field's label: any text or element, never nothing. Sprint 25.12 A31 (R28-59): run 75 labelled only the first of its\n * repeated rows (`label={index === 0 ? … : undefined}`), and every other row's fields had no name. A label that\n * shouldn't show takes `hideLabel`; repeated rows use AddAnother, which shows each label once.\n */\nexport type FieldLabel = Exclude<ReactNode, null | undefined | boolean>;\n\n/** Set by AddAnother around each row: a hidden label shows again when the group is too narrow for its headings. */\nexport const AddAnotherRowCtx = createContext(false);\n\nexport interface FieldProps {\n label: FieldLabel;\n /**\n * The label is read out but not shown (Sprint 25.12 A31): for a field whose purpose the page shows another way, such\n * as a column heading above repeated rows. In an AddAnother group it shows again when the group stacks its rows.\n */\n hideLabel?: boolean;\n /** The single form control. Receives id, aria-describedby, aria-invalid/error and required automatically. */\n children: ReactElement | ((props: FieldControlProps) => ReactNode);\n /** Persistent help text (format requirements, why a field is disabled). Shown below the control, above any error. */\n hint?: ReactNode;\n /** Current validation error. Rendered as InlineFieldError (role=\"alert\") and linked via aria-describedby. Wins over `validate`. */\n error?: string | null | false;\n /**\n * The field's check: the message for what is wrong with its value, or nothing (`validate={(v) => v ? undefined :\n * \"Enter a title\"}`). It gets the control's `value` (or `checked`); a closure over your own state works as well.\n * Inside a FormWrapper it runs at the project's validation timing (forms.validationTiming, through the form):\n * - `onBlur`: when the field is left;\n * - `onChange`: as the value changes, once the field has been left;\n * - `onSubmit`: on submit only.\n *\n * Whatever the timing, it runs on every submit, and FormWrapper's `onSubmit` gets its message under this Field's\n * `id`, or no key at all when the value passes, so an empty `errors` means the form is valid. A message that shows is\n * checked again as the value changes, so it goes as soon as the value is right. Focus\n * moving into the control's own popup (a Dropdown's list, a DatePicker's calendar) is not leaving the field. Outside\n * a FormWrapper it runs when the field is left (round 26, R26-2).\n */\n validate?: (value: unknown) => string | undefined | null | false;\n required?: boolean;\n /** Slot to the right of the label, e.g. a \"Forgot password?\" Link. */\n labelAction?: ReactNode;\n /** Explicit id for the control; generated when omitted. */\n id?: string;\n className?: string;\n}\n\n/**\n * Label + control + hint + error, wired together. Guarantees the label is\n * associated (htmlFor/id), that hint and error are announced\n * (aria-describedby), that the control is marked invalid, and that the error\n * sits directly below the field (forms-002/006/009/010). Use one Field per\n * control; do not add a separate <Label> or a label prop on the child.\n *\n * In a SettingsLayout panel a Field keeps the narrow page's reading width however wide the page is (the panel's\n * --ds-form-max, Sprint 25.9); a `max-w-*` class of your own wins.\n */\nexport function Field({ label, children, hint, error, required, labelAction, hideLabel = false, id: idProp, validate, className }: FieldProps) {\n const inGroupRow = useContext(AddAnotherRowCtx);\n const generated = useId();\n const id = idProp ?? `field-${generated}`;\n const hintId = `${id}-hint`;\n const errorId = `${id}-error`;\n\n // ── The field's own check (round 26, R26-2) ──\n const form = useOptionalFormContext();\n // outside a form, the only moment a field can check itself is when it is left\n const mode = form?.validationMode ?? \"onBlur\";\n const [localError, setLocalError] = useState<string | undefined>(undefined);\n const [left, setLeft] = useState(false);\n const checkError = validate ? (form ? form.errors[id] : localError) : undefined;\n const child = typeof children === \"function\" ? null : Children.only(children);\n const childProps = child && isValidElement(child) ? (child.props as Record<string, unknown>) : null;\n const latest = useLatest({ validate, childProps, id, mode, left, showing: !!checkError, form });\n // the check and its message read what is current through `latest`, so they need no memo of their own\n const check = (): string | undefined => {\n const { validate: fn, childProps: props, id: controlId } = latest.current;\n if (!fn) return undefined;\n const value = props && \"value\" in props ? props.value : props && \"checked\" in props ? props.checked : (document.getElementById(controlId) as HTMLInputElement | null)?.value;\n const message = fn(value);\n return typeof message === \"string\" && message.length > 0 ? message : undefined;\n };\n const show = (message: string | undefined) => {\n const { form: f, id: controlId } = latest.current;\n if (f) f.setError(controlId, message);\n else setLocalError(message);\n };\n // every submit runs the check, whatever the timing: the form holds one check, which runs the field's latest\n const register = form?.register;\n const checks = !!validate;\n const checkNow = useLatest(check);\n useEffect(() => (register && checks ? register(id, () => checkNow.current()) : undefined), [register, checks, id, checkNow]);\n // Left: focus goes out of the field's React tree and doesn't come back straight away. React carries focus events\n // through portals, so moving into the control's own popup comes back in, and cancels the check (lib/focus.ts).\n const leave = useFocusLeave(() => {\n setLeft(true);\n if (latest.current.mode !== \"onSubmit\" || latest.current.showing) show(check());\n });\n // Changed: checked again once the page has the new value, if the timing is onChange and the field has been left,\n // or if its message shows, so it goes as soon as the value is right\n const recheck = () => {\n if (!validate) return;\n setTimeout(() => {\n const { mode: m, left: wasLeft, showing } = latest.current;\n if ((m === \"onChange\" && wasLeft) || showing) show(check());\n }, 0);\n };\n\n const shownError = typeof error === \"string\" && error.length > 0 ? error : checkError;\n const hasError = typeof shownError === \"string\" && shownError.length > 0;\n const describedBy = [hint ? hintId : null, hasError ? errorId : null].filter(Boolean).join(\" \") || undefined;\n const labelId = `${id}-label`;\n // whether the label is on screen: not with hideLabel, unless an AddAnother row shows it again as the group stacks its\n // rows (a container query), which only the page can say (the final review of 0.31.0, 4)\n const [rowShowsLabel, setRowShowsLabel] = useState(false);\n useLayoutEffect(() => {\n const el = document.getElementById(labelId);\n if (!hideLabel || !inGroupRow || !el || typeof ResizeObserver === \"undefined\") return;\n const ro = new ResizeObserver(() => {\n const box = el.getBoundingClientRect();\n setRowShowsLabel(box.width > 1 && box.height > 1);\n });\n ro.observe(el);\n return () => ro.disconnect();\n }, [hideLabel, inGroupRow, labelId]);\n const labelShown = !hideLabel || (inGroupRow && rowShowsLabel);\n const fieldContext = useMemo<FieldContextValue>(() => ({ controlId: id, labelId, describedBy, invalid: hasError, required: !!required, labelHidden: !labelShown }), [id, labelId, describedBy, hasError, required, labelShown]);\n // The naming rule for any control (the final review of 0.31.0, 1): with the label on screen, it leads the name, so a\n // page's aria-label or aria-labelledby on the control is left out, with a development warning naming the control. A\n // native input took it over the Field's <label for>. A control on useFieldControl hears the same from it, deeper in.\n const childType = child && isValidElement(child) ? child.type : null;\n const childName = typeof childType === \"string\" ? childType : childType ? ((childType as { displayName?: string }).displayName ?? (childType as { name?: string }).name ?? \"A Field's control\") : \"A Field's control\";\n const pageLabel = labelShown ? (childProps?.[\"aria-label\"] as string | undefined) : undefined;\n const pageLabelledBy = labelShown ? (childProps?.[\"aria-labelledby\"] as string | undefined) : undefined;\n useEffect(() => {\n if (pageLabel) warnNameLeftOut(childName, \"aria-label\", pageLabel, \"its Field's label\");\n if (pageLabelledBy) warnNameLeftOut(childName, \"aria-labelledby\", pageLabelledBy, \"its Field's label\");\n }, [childName, pageLabel, pageLabelledBy]);\n // a control's own description kept beside the hint and the error (the final review of 0.31.0, 9: the Field's replaced it)\n const ownDescribedBy = childProps?.[\"aria-describedby\"] as string | undefined;\n const allDescribedBy = [...new Set([ownDescribedBy, describedBy].filter(Boolean).join(\" \").split(/\\s+/).filter(Boolean))].join(\" \") || undefined;\n\n const controlProps: FieldControlProps = {\n id,\n \"aria-describedby\": allDescribedBy,\n ...(hasError ? { \"aria-invalid\": true as const, error: true } : {}),\n ...(required ? { \"aria-required\": true as const, required: true } : {}),\n };\n\n let control: ReactNode;\n if (typeof children === \"function\") {\n control = children(controlProps);\n } else {\n if (!child || !isValidElement(child)) throw new Error(\"Field expects a single form control as its child\");\n const isNative = typeof child.type === \"string\";\n const { error: errorFlag, ...ariaOnly } = controlProps;\n // with a check, the control's own onChange is kept and the check follows it (a Gridsmith control calls onChange\n // with its value; a native one's input event reaches the wrapper too)\n const ownOnChange = childProps?.onChange as ((...args: unknown[]) => void) | undefined;\n const onChange = validate && !isNative ? { onChange: (...args: unknown[]) => { ownOnChange?.(...args); recheck(); } } : {};\n // Native elements get ARIA only (an unknown `error` attribute would warn);\n // Gridsmith components get `error` so they render their error styling.\n const names = labelShown ? { \"aria-label\": undefined, \"aria-labelledby\": undefined } : {};\n control = cloneElement(child as ReactElement<Record<string, unknown>>, isNative ? { ...ariaOnly, ...names } : { ...ariaOnly, ...names, ...(errorFlag ? { error: true } : {}), ...onChange });\n }\n\n const labelNode = (\n <Label id={labelId} htmlFor={id} className={cn(hideLabel && \"sr-only\", hideLabel && inGroupRow && \"@max-[30rem]:not-sr-only\")}>\n {label}\n {required && <span aria-hidden=\"true\" className=\"ml-ds-0.5 text-[var(--ds-status-error)]\">*</span>}\n </Label>\n );\n\n return (\n // In a settings panel a field keeps the narrow reading width however wide the page is (--ds-form-max, Sprint 25.9 A4)\n <div\n className={cn(\"flex flex-col gap-ds-1.5 max-w-[var(--ds-form-max,none)]\", className)}\n {...(validate ? { ...leave, onInputCapture: recheck } : {})}\n >\n {/* A hidden label with no action beside it takes no row of its own, so the field keeps its height (A31); in an\n AddAnother row it shows again once the group stacks its rows and hides its headings. */}\n {hideLabel && !labelAction ? labelNode : (\n <div className=\"flex items-center justify-between gap-ds-2\">\n {labelNode}\n {labelAction}\n </div>\n )}\n <FieldContext.Provider value={fieldContext}>{control}</FieldContext.Provider>\n {hint && (\n <p id={hintId} className=\"text-xs text-[var(--ds-text-muted)]\">{hint}</p>\n )}\n {hasError && <InlineFieldError id={errorId} message={shownError} className=\"mt-0\" />}\n </div>\n );\n}\n","import { cn, ACTIVE_RING, FIELD_FOCUS_RING, ERROR_ACTIVE_RING, ERROR_FOCUS_RING, FOCUS_RING } from \"../lib/utils\";\nimport { Icon } from \"../lib/icons\";\nimport { focusAfterRemoval, usePopupFocus } from \"../lib/focus\";\nimport { useInputModality } from \"../lib/input-modality\";\nimport { useRevealFocus } from \"../lib/reveal-focus\";\nimport { AutoTooltip } from \"./Tooltip\";\nimport { useTextOverflow } from \"../lib/use-text-overflow\";\nimport { useState, useRef, useEffect, useLayoutEffect, useCallback, useContext, useId, type Ref } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { ControlSizeContext } from \"./Button\";\nimport { useFieldControl, type FieldControlWiring } from \"./Field\";\nimport { useReportedChange } from \"../lib/form-context\";\n\ninterface Option {\n id: string;\n label: string;\n group?: string;\n}\n\ntype DropdownSize = \"sm\" | \"md\" | \"lg\";\n\nconst DROPDOWN_HEIGHT: Record<DropdownSize, string> = {\n sm: \"px-ds-2 py-ds-1 text-xs h-[var(--ds-control-height-sm)]\",\n md: \"px-ds-3 py-ds-2 text-sm h-[var(--ds-control-height-md)]\",\n lg: \"px-ds-4 py-ds-3 text-base h-[var(--ds-control-height-lg)]\",\n};\n\ninterface DropdownProps extends FieldControlWiring {\n options: Option[];\n value: string | string[];\n onChange: (value: string | string[]) => void;\n label?: string;\n disabled?: boolean;\n placeholder?: string;\n multiple?: boolean;\n searchable?: boolean;\n size?: DropdownSize;\n className?: string;\n ref?: Ref<HTMLDivElement>;\n container?: Element | DocumentFragment;\n error?: boolean;\n /** When multiple, show removable chips below the trigger. Defaults to true. Set false in toolbar contexts where chips are shown elsewhere. */\n showChips?: boolean;\n /**\n * Accessible name for the trigger, for when there is no visible `label` (e.g. in a toolbar). The trigger reads it, then\n * what it shows, \"Status, Open\", so the words on screen are in its name; the open list is named by it alone. Beside a\n * visible label (`label`, or a Field's) it's left out: the label leads the name, and a development warning says so.\n */\n \"aria-label\"?: string;\n}\n\nexport function Dropdown({\n options,\n value,\n onChange: onChangeProp,\n label,\n disabled,\n placeholder = \"Select...\",\n multiple,\n searchable,\n size: sizeProp,\n className,\n ref,\n container,\n error = false,\n showChips = true,\n \"aria-label\": ariaLabel,\n ...wiring\n}: DropdownProps) {\n // Sprint 25.12 A15: a choice the user makes marks the form's overlay; the list's search box doesn't (its own state)\n const onChange = useReportedChange(onChangeProp, value);\n // A field (Sprint 30, P13): from the keyboard the trigger and the list's search box show the outline; after a pointer\n // press the search box shows the active look, and while the list is open the trigger keeps it (ACTIVE_RING)\n useInputModality();\n const contextSize = useContext(ControlSizeContext);\n // Inside a Field the trigger takes the Field's id, label, hint, error and required state (round 27 review): the label\n // and then the trigger's own text name it, the list-box button pattern's \"Plan, Starter\" (APG collapsible listbox).\n const generatedId = useId();\n // its own label's id, apart from the trigger's, which inside a Field is the Field's (whose label is `${id}-label`)\n const labelSpanId = `${generatedId}-label`;\n const nameSpanId = `${generatedId}-name`;\n // the name, by the one rule for a Field's controls (useFieldControl; the final review of Sprint 25.31, 2): a label on\n // screen, its own or its Field's, leads it, and a page's aria-label or aria-labelledby beside one is left out, with a\n // development warning\n const control = useFieldControl({ ...wiring, \"aria-label\": ariaLabel, error: error || undefined }, { requiredInDescription: true, component: \"Dropdown\", ownLabel: label ? labelSpanId : undefined });\n const triggerId = control.id ?? generatedId;\n // the open list is named by the field's label alone (Sprint 25.29 item 11): the trigger's text is the choice, not the list\n const listLabelledBy = control.labelId;\n const invalid = control.invalid;\n const size = sizeProp ?? contextSize ?? \"md\";\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n const [positioned, setPositioned] = useState(false);\n const triggerRef = useRef<HTMLButtonElement>(null);\n // the arrows' option comes into view whole, with its outline (Sprint 30, P3): the list shows part of one at its foot\n const [listbox, setListbox] = useState<HTMLDivElement | null>(null);\n useRevealFocus(listbox);\n const menuRef = useRef<HTMLDivElement>(null);\n const searchRef = useRef<HTMLInputElement>(null);\n const [pos, setPos] = useState({ top: 0, left: 0, width: 0 });\n\n const selectedValues = Array.isArray(value) ? value : [value].filter(Boolean);\n\n const updatePos = useCallback(() => {\n if (!triggerRef.current) return;\n const rect = triggerRef.current.getBoundingClientRect();\n let top = rect.bottom + 4;\n let left = rect.left;\n const width = rect.width;\n\n if (menuRef.current) {\n const menuRect = menuRef.current.getBoundingClientRect();\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n if (left + menuRect.width > vw) left = Math.max(0, vw - menuRect.width - 8);\n if (top + menuRect.height > vh) {\n const above = rect.top - 4 - menuRect.height;\n if (above >= 0) top = above;\n else top = Math.max(0, vh - menuRect.height - 8);\n }\n }\n\n setPos({ top, left, width });\n }, []);\n\n // Opening clears the search; closing forgets the last position (render-time\n // state adjustment, so the menu never paints with stale values).\n const [prevOpen, setPrevOpen] = useState(open);\n if (open !== prevOpen) {\n setPrevOpen(open);\n if (open) setSearch(\"\");\n else setPositioned(false);\n }\n\n useEffect(() => {\n if (!open) return;\n updatePos();\n const raf = requestAnimationFrame(() => {\n updatePos();\n setPositioned(true);\n });\n const onScroll = () => updatePos();\n window.addEventListener(\"scroll\", onScroll, true);\n window.addEventListener(\"resize\", updatePos);\n return () => {\n cancelAnimationFrame(raf);\n window.removeEventListener(\"scroll\", onScroll, true);\n window.removeEventListener(\"resize\", updatePos);\n };\n }, [open, updatePos]);\n\n // Sprint 25.7: the user moved to an option since the list opened (arrows, Home/End, type-ahead). Tab then picks it (D14(a)).\n const moved = useRef(false);\n\n // Focus moves in once the panel is visible: it opens with visibility hidden until positioned, and a hidden element\n // cannot take focus (focusing it in the same frame used to leave focus on the trigger in real browsers).\n useLayoutEffect(() => {\n if (!open || !positioned) return;\n moved.current = false;\n if (searchRef.current) {\n searchRef.current.focus();\n return;\n }\n const els = Array.from(menuRef.current?.querySelectorAll<HTMLButtonElement>('[role=\"option\"]') ?? []);\n (els.find((el) => el.getAttribute(\"aria-selected\") === \"true\") ?? els[0])?.focus();\n }, [open, positioned]);\n\n useEffect(() => {\n if (!open) return;\n const handler = (e: MouseEvent) => {\n const target = e.target as Node;\n if (triggerRef.current?.contains(target) || menuRef.current?.contains(target)) return;\n setOpen(false);\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [open]);\n\n // Tab while open (D14(a)): a single-select list picks the option the user moved to; opened and left, nothing changes.\n const commitMoved = () => {\n if (multiple || !moved.current) return;\n const el = document.activeElement;\n const id = el instanceof HTMLElement && menuRef.current?.contains(el) ? el.getAttribute(\"data-option-id\") : null;\n if (id) onChange(id);\n };\n // Sprint 25.7: focus hands back on close, and Tab out carries on from the trigger (lib/focus usePopupFocus).\n const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: menuRef, close: () => setOpen(false), tabExits: \"any\", onTabOut: commitMoved });\n\n // Keyboard while open: Escape closes (focus returns to the trigger); arrows,\n // Home/End move focus through the options; typing jumps to the first option\n // starting with those letters (when there is no search box); Enter/Space\n // activate the focused option natively.\n const typeahead = useRef({ buffer: \"\", at: 0 });\n useEffect(() => {\n if (!open) return;\n const optionButtons = () => Array.from(menuRef.current?.querySelectorAll<HTMLButtonElement>('[role=\"option\"]') ?? []);\n const focusOption = (idx: number) => {\n const els = optionButtons();\n if (els.length === 0) return;\n els[((idx % els.length) + els.length) % els.length].focus();\n moved.current = true;\n };\n const onKey = (e: KeyboardEvent) => {\n const inMenu = menuRef.current?.contains(document.activeElement) || triggerRef.current === document.activeElement;\n if (!inMenu) return;\n const els = optionButtons();\n const current = els.findIndex((el) => el === document.activeElement);\n if (e.key === \"Escape\") { if (e.defaultPrevented || !isTopLayer()) return; e.preventDefault(); returnFocus(); setOpen(false); return; }\n if (e.key === \"ArrowDown\") { e.preventDefault(); focusOption(current < 0 ? 0 : current + 1); return; }\n if (e.key === \"ArrowUp\") { e.preventDefault(); focusOption(current < 0 ? els.length - 1 : current - 1); return; }\n const inSearch = document.activeElement === searchRef.current;\n if (e.key === \"Home\" && !inSearch) { e.preventDefault(); focusOption(0); return; }\n if (e.key === \"End\" && !inSearch) { e.preventDefault(); focusOption(els.length - 1); return; }\n if (!searchable && e.key.length === 1 && !e.metaKey && !e.ctrlKey && !e.altKey) {\n const now = Date.now();\n typeahead.current.buffer = now - typeahead.current.at > 700 ? e.key : typeahead.current.buffer + e.key;\n typeahead.current.at = now;\n const q = typeahead.current.buffer.toLowerCase();\n const hit = els.findIndex((el) => (el.textContent ?? \"\").trim().toLowerCase().startsWith(q));\n if (hit >= 0) { e.preventDefault(); focusOption(hit); }\n }\n };\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [open, searchable, isTopLayer, returnFocus]);\n\n const filtered = searchable && search\n ? options.filter((o) => o.label.toLowerCase().includes(search.toLowerCase()))\n : options;\n\n const groups = new Map<string, Option[]>();\n for (const opt of filtered) {\n const g = opt.group ?? \"\";\n if (!groups.has(g)) groups.set(g, []);\n groups.get(g)!.push(opt);\n }\n const hasGroups = Array.from(groups.keys()).some((k) => k !== \"\");\n // the list's one Tab stop: the chosen option, else the first, in the order the list draws them\n const drawn = hasGroups ? Array.from(groups.values()).flat() : filtered;\n const stopId = (drawn.find((o) => selectedValues.includes(o.id)) ?? drawn[0])?.id;\n\n const handleSelect = (id: string) => {\n if (multiple) {\n const arr = selectedValues.includes(id)\n ? selectedValues.filter((v) => v !== id)\n : [...selectedValues, id];\n onChange(arr);\n } else {\n // Focus back on the trigger before the consumer runs, so a dialog it opens records the trigger (Sprint 25.7).\n returnFocus();\n onChange(id);\n setOpen(false);\n }\n };\n\n // Removing a chip moves focus to the chip before it, else the one after, else the trigger (D14(c)), once the value\n // no longer holds it. The next render drops the request either way, so a removal the consumer refused never moves\n // focus later.\n const chipsRef = useRef<HTMLDivElement>(null);\n const pendingChipFocus = useRef<{ index: number; value: string } | null>(null);\n useLayoutEffect(() => {\n const pending = pendingChipFocus.current;\n if (pending === null) return;\n pendingChipFocus.current = null;\n if (selectedValues.includes(pending.value)) return;\n const chips = Array.from(chipsRef.current?.querySelectorAll<HTMLElement>(\"[data-chip-remove]\") ?? []);\n focusAfterRemoval(chips, pending.index, triggerRef.current);\n });\n\n const displayLabel = multiple\n ? selectedValues.length > 0\n ? `${selectedValues.length} selected`\n : placeholder\n : options.find((o) => o.id === selectedValues[0])?.label ?? placeholder;\n\n const { ref: overflowRef, isTruncated } = useTextOverflow({ lines: 1, content: displayLabel });\n\n // named by the page's aria-label alone, the trigger is that name and then its own text, as a visible label names it: a\n // phone's Tabs reads \"Contents, Security\", never \"Contents\" alone over a trigger that shows \"Security\" (Sprint 25.31\n // item 1; WCAG 2.5.3, 4.1.2). The name waits in a hidden span, with a comma before what the trigger shows, unless it\n // ends in punctuation or the trigger shows nothing. A trigger that shows the name itself, or starts with it (\"Status\"\n // as its placeholder), reads its own words alone (the final review of Sprint 25.31, 3: \"Status, Status\"): the name as a\n // word, so \"View\" over \"Viewer\" still reads both (the final review of 0.31.0, 5). Its words through String(): an option\n // labelled by a number, as untyped data can be, is drawn as before (item 6)\n const shows = String(displayLabel).trim();\n const name = control.label?.trim() ?? \"\";\n const repeats = !!name && new RegExp(`^${name.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")}(?!\\\\p{L})`, \"iu\").test(shows);\n const nameSpan = !control.labelId && !!control.label && !repeats;\n const labelledBy = control.labelId ? `${control.labelId} ${triggerId}` : nameSpan ? `${nameSpanId} ${triggerId}` : undefined;\n\n return (\n <div ref={ref} className={cn(\"relative\", className)}>\n {label && (\n <span id={labelSpanId} className=\"block mb-ds-1.5 text-sm font-medium text-[var(--ds-text-secondary)]\">{label}</span>\n )}\n {control.requiredNote}\n {nameSpan && <span id={nameSpanId} hidden>{shows && !/[,.:;!?]$/.test(control.label!.trim()) ? `${control.label},` : control.label}</span>}\n <button\n ref={triggerRef}\n id={triggerId}\n type=\"button\"\n onClick={() => !disabled && setOpen(!open)}\n onKeyDown={(e) => {\n if (disabled || open) return;\n if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\") { e.preventDefault(); setOpen(true); }\n }}\n disabled={disabled}\n aria-invalid={invalid || undefined}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-labelledby={labelledBy}\n aria-describedby={control.describedBy}\n className={cn(\n \"w-full flex items-center justify-between gap-ds-2\",\n DROPDOWN_HEIGHT[size],\n \"bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)]\",\n \"border-[length:var(--ds-border-width)]\",\n invalid ? \"border-[var(--ds-status-error)]\" : \"border-[var(--ds-input-border)]\",\n \"rounded-[var(--ds-radius-md)]\",\n \"shadow-[var(--ds-input-shadow)]\",\n \"transition-colors\",\n !invalid && !disabled && !open && \"hover:border-[var(--ds-input-border-hover)]\",\n open && (invalid ? ERROR_ACTIVE_RING : ACTIVE_RING),\n invalid ? ERROR_FOCUS_RING : FIELD_FOCUS_RING,\n \"cursor-pointer disabled:cursor-not-allowed disabled:opacity-disabled\",\n !selectedValues.length && \"text-[var(--ds-text-muted)]\"\n )}\n >\n {isTruncated ? (\n <AutoTooltip content={displayLabel}><span ref={overflowRef} className=\"truncate\">{displayLabel}</span></AutoTooltip>\n ) : (\n <span ref={overflowRef} className=\"truncate\">{displayLabel}</span>\n )}\n <span className={cn(\"transition-transform\", open && \"rotate-180\")}>\n <Icon name=\"chevron-right\" size={14} className=\"rotate-90\" />\n </span>\n </button>\n\n {open && createPortal(\n <div\n ref={menuRef}\n // Safari focuses no button on a mousedown and drops focus to the body; a panel that can take focus keeps it\n // inside the control's React tree, so a Field's leave check never fires mid-choice (round 27 review)\n tabIndex={-1}\n // A choice is the list's own: its click must not also reach a clickable row or card around the Dropdown.\n onClick={(e) => e.stopPropagation()}\n className={cn(\n \"fixed z-[var(--ds-z-popover)] outline-none\",\n \"bg-[var(--ds-bg-surface-elevated)]\",\n \"[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\",\n \"rounded-[var(--ds-radius-md)] overflow-hidden\",\n \"shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]\",\n )}\n style={{ top: pos.top, left: pos.left, minWidth: pos.width, width: \"max-content\", maxWidth: \"calc(100vw - 16px)\", visibility: positioned ? \"visible\" : \"hidden\" }}\n >\n {searchable && (\n <div className=\"border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\" style={{ padding: \"var(--ds-space-2)\" }}>\n <input\n ref={searchRef}\n type=\"text\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search…\"\n // the list's own search field, its first row: no look of its own (Sprint 30, the owner's decision B)\n data-popup-search=\"\"\n className={cn(\"w-full bg-transparent text-[var(--ds-text-primary)] placeholder:text-[var(--ds-text-muted)] outline-none\", size === \"sm\" ? \"text-xs\" : \"text-sm\")}\n />\n </div>\n )}\n {/* its padding is room for the options' outline, never under its 4 px reach (Sprint 30, P3) */}\n {/* one Tab stop, the Authoring Practices' roving one: the chosen option, else the first (Sprint 25.29 item 11) */}\n <div ref={setListbox} role=\"listbox\" aria-labelledby={listLabelledBy} aria-label={listLabelledBy ? undefined : control.label} aria-multiselectable={multiple || undefined} className=\"overflow-y-auto scroll-p-[4px]\" style={{ padding: \"max(var(--ds-space-1), 4px)\", maxHeight: \"var(--ds-dropdown-max-height)\" }}>\n {filtered.length === 0 ? (\n <p className={cn(\"text-[var(--ds-text-muted)] text-center py-ds-4\", size === \"sm\" ? \"text-xs\" : \"text-sm\")}>No options found</p>\n ) : hasGroups ? (\n Array.from(groups.entries()).map(([group, opts]) => (\n <div key={group}>\n {group && (\n <p className=\"text-2xs font-medium uppercase tracking-wider text-[var(--ds-text-muted)] px-ds-2 pt-ds-2 pb-ds-1\">\n {group}\n </p>\n )}\n {opts.map((opt) => (\n <OptionButton\n key={opt.id}\n opt={opt}\n tabStop={opt.id === stopId}\n isSelected={selectedValues.includes(opt.id)}\n multiple={multiple}\n onSelect={handleSelect}\n size={size}\n />\n ))}\n </div>\n ))\n ) : (\n filtered.map((opt) => (\n <OptionButton\n key={opt.id}\n opt={opt}\n tabStop={opt.id === stopId}\n isSelected={selectedValues.includes(opt.id)}\n multiple={multiple}\n onSelect={handleSelect}\n size={size}\n />\n ))\n )}\n </div>\n </div>,\n container ?? document.body\n )}\n\n {multiple && showChips && selectedValues.length > 0 && (\n <div ref={chipsRef} className=\"flex flex-wrap gap-ds-1 mt-ds-1.5\">\n {selectedValues.map((v, i) => {\n const opt = options.find((o) => o.id === v);\n return opt ? (\n <span\n key={v}\n className=\"inline-flex items-center gap-ds-1 text-xs rounded-[var(--ds-radius-sm)] bg-[var(--ds-bg-muted)] text-[var(--ds-text-secondary)] px-ds-1.5 py-ds-0.5\"\n >\n {opt.label}\n <AutoTooltip content={`Remove ${opt.label}`}>\n <button type=\"button\"\n data-chip-remove=\"\"\n onClick={() => { pendingChipFocus.current = { index: i, value: v }; handleSelect(v); }}\n className={cn(\"hover:text-[var(--ds-text-primary)] cursor-pointer\", FOCUS_RING)}\n aria-label={`Remove ${opt.label}`}\n >\n <Icon name=\"close\" size={10} />\n </button>\n </AutoTooltip>\n </span>\n ) : null;\n })}\n </div>\n )}\n </div>\n );\n}\n\nfunction OptionButton({\n opt,\n tabStop,\n isSelected,\n multiple,\n onSelect,\n size = \"md\",\n}: {\n opt: Option;\n tabStop: boolean;\n isSelected: boolean;\n multiple?: boolean;\n onSelect: (id: string) => void;\n size?: DropdownSize;\n}) {\n return (\n <button\n type=\"button\"\n role=\"option\"\n data-option-id={opt.id}\n aria-selected={isSelected}\n tabIndex={tabStop ? 0 : -1}\n onClick={() => onSelect(opt.id)}\n className={cn(\n \"w-full text-left cursor-pointer rounded-[var(--ds-radius-sm)]\",\n \"transition-colors flex items-center gap-ds-2\",\n // the arrows move DOM focus here, so the option draws the outline; outside it, clear of the chosen one's fill\n FOCUS_RING,\n size === \"sm\" ? \"px-ds-2 py-ds-1 text-xs\" : \"px-ds-2 py-ds-1.5 text-sm\",\n isSelected && !multiple\n ? \"bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]\"\n : \"text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-emphasis)]\"\n )}\n >\n {multiple && (\n <span\n className={cn(\n \"w-[var(--ds-icon-size-sm)] h-[var(--ds-icon-size-sm)] rounded-[var(--ds-radius-sm)] border-[length:var(--ds-border-width)] shrink-0 flex items-center justify-center\",\n isSelected\n ? \"bg-[var(--ds-accent-primary)] border-[var(--ds-accent-primary)]\"\n : \"border-[var(--ds-border-default)]\"\n )}\n >\n {isSelected && <Icon name=\"check\" size={10} className=\"text-[var(--ds-text-on-primary)]\" />}\n </span>\n )}\n <span className=\"flex-1\">{opt.label}</span>\n {isSelected && !multiple && <Icon name=\"check\" size={size === \"sm\" ? 12 : 14} />}\n </button>\n );\n}\n"]}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useLatest, usePosition } from './chunk-
|
|
3
|
-
import { cn } from './chunk-YL5KD5RC.js';
|
|
2
|
+
import { cn, useLatest, usePosition } from './chunk-EZ3ZGFGA.js';
|
|
4
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
4
|
import { useRef, useLayoutEffect, useMemo } from 'react';
|
|
6
5
|
import { createPortal } from 'react-dom';
|
|
@@ -205,5 +204,5 @@ function MentionList({ id, label, items, more = 0, activeIndex, onActiveIndexCha
|
|
|
205
204
|
}
|
|
206
205
|
|
|
207
206
|
export { Avatar, MentionList, foldForSearch, initialsOf, matchMentions, mentionOptionId, shownMentions, useActiveOptionInView };
|
|
208
|
-
//# sourceMappingURL=chunk-
|
|
209
|
-
//# sourceMappingURL=chunk-
|
|
207
|
+
//# sourceMappingURL=chunk-K3NAFQ4S.js.map
|
|
208
|
+
//# sourceMappingURL=chunk-K3NAFQ4S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/lib/initials.ts","../../../showcase/src/components/Avatar.tsx","../../../showcase/src/lib/use-active-option.ts","../../../showcase/src/lib/search-text.ts","../../../showcase/src/components/MentionList.tsx"],"names":["useRef","jsxs","jsx"],"mappings":"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","file":"chunk-K3NAFQ4S.js","sourcesContent":["/**\n * Initials for an avatar. Round 21 (run 58): a builder passed each person's full name as `initials`, and the avatar\n * printed \"Amara Haddad\" across a 40 px circle on every row of the Team table. The avatar now reads what it is given:\n * up to three characters with no space are initials already and stay as they are (\"JB\", \"ABC\"); anything longer is a\n * name, and its first two words give the letters.\n */\n\n/** \"Sarah Chen\" → \"SC\"; \"Acme\" → \"A\"; \"Mary Jane Watson\" → \"MJ\". */\nexport function initialsOf(name: string): string {\n return name\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((word) => Array.from(word)[0] ?? \"\")\n .join(\"\")\n .toUpperCase();\n}\n\n/** What an avatar shows for an `initials` value: initials as given, or the initials of a name. */\nexport function toInitials(value: string): string {\n const s = value.trim();\n if (!s) return \"\";\n if (!/\\s/.test(s) && Array.from(s).length <= 3) return s;\n return initialsOf(s);\n}\n","import { cn } from \"../lib/utils\";\nimport { toInitials } from \"../lib/initials\";\n\nexport type AvatarStatus = \"online\" | \"away\" | \"busy\" | \"offline\";\nexport type AvatarColor = \"auto\" | \"accent\" | \"neutral\" | 1 | 2 | 3 | 4 | 5;\n\ninterface AvatarProps {\n /** One to three letters (\"JB\"). A name passed here shows its initials (\"Amara Haddad\" → \"AH\"), never the whole name. */\n initials?: string;\n src?: string;\n alt?: string;\n size?: \"sm\" | \"md\" | \"lg\";\n status?: AvatarStatus;\n /** Initials background. \"auto\" (default) derives a stable palette tint from alt/initials so groups vary; use \"accent\" sparingly. */\n color?: AvatarColor;\n className?: string;\n}\n\nconst sizeStyles = {\n sm: \"h-8 w-8 text-xs\",\n md: \"h-10 w-10 text-sm\",\n lg: \"h-12 w-12 text-base\",\n};\n\n// Fallbacks cover themes whose tokens CSS predates the decorative palette.\nconst paletteStyles = {\n 1: \"bg-[var(--ds-palette-1-bg,var(--ds-bg-muted))] text-[var(--ds-palette-1-text,var(--ds-text-secondary))]\",\n 2: \"bg-[var(--ds-palette-2-bg,var(--ds-bg-muted))] text-[var(--ds-palette-2-text,var(--ds-text-secondary))]\",\n 3: \"bg-[var(--ds-palette-3-bg,var(--ds-bg-muted))] text-[var(--ds-palette-3-text,var(--ds-text-secondary))]\",\n 4: \"bg-[var(--ds-palette-4-bg,var(--ds-bg-muted))] text-[var(--ds-palette-4-text,var(--ds-text-secondary))]\",\n 5: \"bg-[var(--ds-palette-5-bg,var(--ds-bg-muted))] text-[var(--ds-palette-5-text,var(--ds-text-secondary))]\",\n} as const;\n\nfunction paletteFor(seed: string): keyof typeof paletteStyles {\n let h = 0;\n for (const ch of seed) h = (h * 31 + ch.charCodeAt(0)) >>> 0;\n return ((h % 5) + 1) as keyof typeof paletteStyles;\n}\n\nfunction colorStyles(color: AvatarColor, seed: string): string {\n if (color === \"accent\") return \"bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]\";\n if (color === \"neutral\") return \"bg-[var(--ds-bg-muted)] text-[var(--ds-text-secondary)]\";\n return paletteStyles[color === \"auto\" ? paletteFor(seed) : color];\n}\n\n/**\n * Presence as a shape as well as a colour (Sprint 25.12 A48, WCAG 1.4.1), as Fluent's presence badges do: online a filled\n * dot, away a ring, busy a dot with a bar, offline a ring with a slash. The words are in the avatar's name.\n */\nfunction PresenceMark({ status }: { status: AvatarStatus }) {\n return (\n <svg viewBox=\"0 0 10 10\" width=\"10\" height=\"10\" aria-hidden=\"true\" focusable=\"false\" data-presence={status} className=\"block\">\n {status === \"online\" && <circle cx=\"5\" cy=\"5\" r=\"5\" className=\"fill-[var(--ds-status-success)]\" />}\n {status === \"away\" && <circle cx=\"5\" cy=\"5\" r=\"4\" fill=\"none\" strokeWidth=\"2\" className=\"stroke-[var(--ds-status-warning)]\" />}\n {status === \"busy\" && (\n <>\n <circle cx=\"5\" cy=\"5\" r=\"5\" className=\"fill-[var(--ds-status-error)]\" />\n <rect x=\"2.5\" y=\"4.1\" width=\"5\" height=\"1.8\" rx=\"0.9\" className=\"fill-[var(--ds-bg-canvas)]\" />\n </>\n )}\n {status === \"offline\" && (\n <>\n <circle cx=\"5\" cy=\"5\" r=\"4\" fill=\"none\" strokeWidth=\"2\" className=\"stroke-[var(--ds-text-muted)]\" />\n <line x1=\"3.1\" y1=\"6.9\" x2=\"6.9\" y2=\"3.1\" strokeWidth=\"1.5\" strokeLinecap=\"round\" className=\"stroke-[var(--ds-text-muted)]\" />\n </>\n )}\n </svg>\n );\n}\n\nexport function Avatar({ initials, src, alt, size = \"md\", status, color = \"auto\", className }: AvatarProps) {\n // A48: presence can't show words beside a small avatar, so the avatar's own name carries it (\"Priya Nair, online\")\n const who = alt ?? initials ?? \"\";\n const named = status ? [who, status].filter(Boolean).join(\", \") : undefined;\n const base = cn(\n \"inline-flex items-center justify-center font-medium shrink-0\",\n \"rounded-[var(--ds-radius-full)]\",\n sizeStyles[size],\n className,\n );\n\n // data-avatar: the Table and DataGrid card mode stacks a cell that holds an avatar (Sprint 25.4 C-2).\n const avatarElement = src ? (\n <img\n data-avatar=\"\"\n src={src}\n alt={named ?? alt ?? initials ?? \"\"}\n className={cn(base, \"object-cover\")}\n />\n ) : (\n <div\n data-avatar=\"\"\n role={named ? \"img\" : undefined}\n aria-label={named}\n className={cn(\n base,\n colorStyles(color, alt ?? initials ?? \"\"),\n \"border-[length:var(--ds-border-width)] border-transparent\",\n )}\n >\n {/* round 21: a full name passed as initials shows its initials, not the name squeezed into the circle */}\n {initials != null ? toInitials(initials) : null}\n </div>\n );\n\n if (!status) return avatarElement;\n\n return (\n <div className=\"relative inline-flex\">\n {avatarElement}\n <span\n className={cn(\n \"absolute\",\n size === \"sm\" && \"bottom-[-2px] right-[-2px]\",\n size === \"md\" && \"bottom-[0px] right-[0px]\",\n size === \"lg\" && \"bottom-[2px] right-[2px]\",\n )}\n aria-hidden=\"true\"\n >\n {/* the canvas behind the mark fills a ring's middle and draws the 2px halo that separates it from the photo */}\n <span className=\"block rounded-[var(--ds-radius-full)] bg-[var(--ds-bg-canvas)] shadow-[0_0_0_2px_var(--ds-bg-canvas)]\">\n <PresenceMark status={status} />\n </span>\n </span>\n </div>\n );\n}\n","import { useLayoutEffect, useRef, type RefObject } from \"react\";\n\n/**\n * Keeps the active option of a list driven by aria-activedescendant in view (Sprint 25.17's review; WCAG 2.4.11): when\n * the list opens and when the active option changes, the list scrolls just enough to show it. Only the list's own box\n * scrolls, never the page: the list sits fixed over it. The option is found by its id, in the list's own document or\n * shadow root.\n *\n * Only a change brings it back into view (the second review): a render that leaves the same option active — the page\n * scrolling, the list scrolled by touch or by its scrollbar — leaves the list where the user put it.\n */\nexport function useActiveOptionInView(list: RefObject<HTMLElement | null>, activeId: string | undefined): void {\n // the option last brought into view, by its id and its text: a filtered list reuses an id for another option\n const shown = useRef<string | null>(null);\n useLayoutEffect(() => {\n const box = list.current;\n if (!box || !activeId) {\n shown.current = null;\n return;\n }\n const root = box.getRootNode() as Document | ShadowRoot;\n const option = typeof root.getElementById === \"function\" ? root.getElementById(activeId) : null;\n if (!option || !box.contains(option)) return;\n const seen = `${activeId}\\u0000${option.textContent ?? \"\"}`;\n if (seen === shown.current) return;\n shown.current = seen;\n const top = option.getBoundingClientRect().top - box.getBoundingClientRect().top + box.scrollTop;\n const bottom = top + option.offsetHeight;\n if (top < box.scrollTop) box.scrollTo({ top });\n else if (bottom > box.scrollTop + box.clientHeight) box.scrollTo({ top: bottom - box.clientHeight });\n });\n}\n","/**\n * Text as a search reads it, one way for every picker (Sprint 25.17's second review): no case, no accents, and \"_\" as a\n * space, so \"@toma\" finds Tomás, \"Sao Paulo\" and \"São Paulo\" find America/Sao_Paulo, and \"New_York\" finds New York.\n */\nexport function foldForSearch(text: string): string {\n return text.normalize(\"NFD\").replace(/\\p{M}/gu, \"\").replace(/_/g, \" \").toLowerCase();\n}\n","import { useMemo, useRef, type RefObject } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"../lib/utils\";\nimport { usePosition } from \"../lib/use-position\";\nimport { useLatest } from \"../lib/use-latest\";\nimport { useActiveOptionInView } from \"../lib/use-active-option\";\nimport { foldForSearch } from \"../lib/search-text\";\nimport { Avatar } from \"./Avatar\";\n\nexport interface MentionSuggestion {\n id: string;\n label: string;\n avatar?: string;\n description?: string;\n}\n\n/** Text as a search reads it: no case, no accents (\"@toma\" finds Tomás, \"@zoe\" Zoë), as every picker reads it. */\nconst fold = foldForSearch;\n\n/**\n * The suggestions a query matches, by name or by description, ignoring case and accents, best first: a name that starts with it\n * (\"@Mar\": Marcus Chen), then a name with a word that does (Tomás Martin), then a name holding it anywhere (Amara), then\n * a description that does; in their own order within each.\n */\nexport function matchMentions(items: MentionSuggestion[], query: string): MentionSuggestion[] {\n const q = fold(query);\n const rank = (s: MentionSuggestion): number => {\n const name = fold(s.label);\n if (name.startsWith(q)) return 0;\n if (name.split(/\\s+/).some((word) => word.startsWith(q))) return 1;\n if (name.includes(q)) return 2;\n return s.description && fold(s.description).includes(q) ? 3 : -1;\n };\n return items.map((s) => ({ s, r: rank(s) })).filter(({ r }) => r >= 0).sort((a, b) => a.r - b.r).map(({ s }) => s);\n}\n\n/** An option's id, for the field's aria-activedescendant. */\nexport const mentionOptionId = (listId: string, index: number) => `${listId}-option-${index}`;\n\n/**\n * The most people a list shows (Sprint 25.17's second review: two thousand drawn at once took a key a third of a second\n * to paint): the best matches, and a line saying how many more match, which typing narrows.\n */\nexport const MENTION_LIST_LIMIT = 10;\n\n/** The matches a list shows, best first, and how many more there are. */\nexport function shownMentions(found: MentionSuggestion[]): { items: MentionSuggestion[]; more: number } {\n return { items: found.slice(0, MENTION_LIST_LIMIT), more: Math.max(0, found.length - MENTION_LIST_LIMIT) };\n}\n\nexport interface MentionListProps {\n /** The listbox's id: the field's aria-controls, and the stem of its options' ids. */\n id: string;\n /** The listbox's name (\"People\", \"Suggestions\"). */\n label: string;\n /** The people shown, at most MENTION_LIST_LIMIT (shownMentions). */\n items: MentionSuggestion[];\n /** How many more match than are shown: the list says so under its people. */\n more?: number;\n activeIndex: number;\n onActiveIndexChange: (index: number) => void;\n onPick: (item: MentionSuggestion) => void;\n /** Where the mention being typed is, in the viewport: the list opens under it, above it when the screen runs out below. */\n anchorRect: () => DOMRect | null;\n /** The list's element, for the owner's checks (a click outside, focus moving into it). */\n listRef?: RefObject<HTMLDivElement | null>;\n}\n\n/**\n * The list of suggestions while a mention is typed (Sprint 25.17 A17): MentionInput's and the editor's, so a mention\n * looks and works the same in a comment box and a document. The field keeps focus and carries aria-activedescendant\n * (the field's owner wires the keys: arrows move, Enter or Tab inserts, Escape closes); the options are no Tab stops,\n * and a pointer picks one without taking focus from the field.\n */\nexport function MentionList({ id, label, items, more = 0, activeIndex, onActiveIndexChange, onPick, anchorRect, listRef }: MentionListProps) {\n const ownRef = useRef<HTMLDivElement | null>(null);\n const floatingRef = listRef ?? ownRef;\n const boxRef = useRef<HTMLDivElement | null>(null);\n const anchorRef = useLatest(anchorRect);\n // the caret as an element for usePosition, which reads only its rectangle\n const anchor = useMemo(() => ({ current: { getBoundingClientRect: () => anchorRef.current() ?? new DOMRect() } as HTMLElement }), [anchorRef]);\n const pos = usePosition(anchor, floatingRef, items.length > 0, { side: \"bottom\", align: \"start\", offset: 4 });\n // the arrows move through a list longer than its box: the active person stays in view\n useActiveOptionInView(boxRef, items.length > 0 ? mentionOptionId(id, activeIndex) : undefined);\n if (items.length === 0) return null;\n\n return createPortal(\n <div\n ref={floatingRef}\n className={cn(\n \"fixed z-[var(--ds-z-popover)] min-w-[200px] flex flex-col\",\n \"bg-[var(--ds-bg-surface-elevated)]\",\n \"[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]\",\n \"rounded-[var(--ds-radius-md)] shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]\",\n )}\n style={{ top: pos.top, left: pos.left }}\n >\n {/* rows inset in the list, rounded, as Combobox's and the menus' are (the second review: full-width square rows) */}\n <div ref={boxRef} id={id} role=\"listbox\" aria-label={label} className=\"max-h-[200px] overflow-y-auto p-ds-1\">\n {items.map((s, i) => (\n <button\n key={s.id}\n id={mentionOptionId(id, i)}\n type=\"button\"\n role=\"option\"\n tabIndex={-1}\n aria-selected={i === activeIndex}\n className={cn(\n \"flex items-center gap-ds-2.5 w-full px-ds-2 py-ds-1.5 text-left text-sm cursor-pointer rounded-[var(--ds-radius-sm)]\",\n \"transition-colors duration-[var(--ds-transition-speed)]\",\n i === activeIndex ? \"bg-[var(--ds-bg-muted)] text-[var(--ds-text-primary)]\" : \"text-[var(--ds-text-secondary)]\",\n )}\n // the field keeps focus, so the pick lands where the mention is being typed\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onPick(s)}\n onMouseEnter={() => onActiveIndexChange(i)}\n >\n {/* the name follows as text, so the picture is decoration */}\n <span aria-hidden=\"true\" className=\"inline-flex shrink-0\">\n <Avatar src={s.avatar} initials={s.label} size=\"sm\" className=\"!h-6 !w-6 !text-2xs\" />\n </span>\n <span className=\"min-w-0\">\n <span className=\"block font-medium text-[var(--ds-text-primary)] truncate\">{s.label}</span>\n {s.description && <span className=\"block text-xs text-[var(--ds-text-muted)] truncate\">{s.description}</span>}\n </span>\n </button>\n ))}\n </div>\n {more > 0 && (\n <p className=\"px-ds-3 py-ds-1.5 text-xs text-[var(--ds-text-muted)] border-t-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]\">\n {more} more {more === 1 ? \"matches\" : \"match\"}: keep typing to narrow\n </p>\n )}\n </div>,\n document.body,\n );\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useRevealFocus } from './chunk-
|
|
3
|
-
import {
|
|
2
|
+
import { useRevealFocus } from './chunk-DR6WEI3A.js';
|
|
3
|
+
import { hasTabStop } from './chunk-EZ3ZGFGA.js';
|
|
4
4
|
import { useEffect } from 'react';
|
|
5
5
|
|
|
6
6
|
function useKeyboardScroll(el, label, enabled = true, nameFromHeading = false, axis = "y") {
|
|
@@ -34,26 +34,38 @@ function useKeyboardScroll(el, label, enabled = true, nameFromHeading = false, a
|
|
|
34
34
|
}
|
|
35
35
|
};
|
|
36
36
|
const update = () => {
|
|
37
|
+
if (el.closest("[inert]")) return;
|
|
38
|
+
if (el.hasAttribute("data-scroll-stop") && document.activeElement === el) return set(true);
|
|
39
|
+
if (hasTabStop(el)) return set(false);
|
|
37
40
|
const wide = el.scrollWidth > el.clientWidth + 1, tall = el.scrollHeight > el.clientHeight + 1;
|
|
38
|
-
|
|
39
|
-
const scrolls = overflows && tabStops(el).length === 0;
|
|
40
|
-
set(scrolls || el.hasAttribute("data-scroll-stop") && document.activeElement === el);
|
|
41
|
+
set(axis === "x" ? wide : axis === "both" ? wide || tall : tall);
|
|
41
42
|
};
|
|
42
43
|
update();
|
|
43
44
|
const ro = new ResizeObserver(update);
|
|
44
45
|
ro.observe(el);
|
|
45
|
-
const
|
|
46
|
-
mo
|
|
47
|
-
|
|
46
|
+
const itsOwn = (r) => r.type === "attributes" && r.target === el && r.attributeName === "tabindex";
|
|
47
|
+
const mo = typeof MutationObserver === "undefined" ? null : new MutationObserver((records) => {
|
|
48
|
+
if (!records.every(itsOwn)) update();
|
|
49
|
+
});
|
|
50
|
+
mo?.observe(el, { childList: true, subtree: true, characterData: true, attributes: true, attributeFilter: ["inert", "disabled", "hidden", "tabindex"] });
|
|
51
|
+
const around = typeof MutationObserver === "undefined" ? null : new MutationObserver((records) => {
|
|
52
|
+
if (records.some((r) => r.target !== el && r.target instanceof Element && r.target.contains(el))) update();
|
|
53
|
+
});
|
|
54
|
+
around?.observe(el.ownerDocument.documentElement, { subtree: true, attributes: true, attributeFilter: ["inert"] });
|
|
55
|
+
const onFocusOut = (e) => {
|
|
56
|
+
if (e.target === el) update();
|
|
57
|
+
};
|
|
58
|
+
el.addEventListener("focusout", onFocusOut);
|
|
48
59
|
return () => {
|
|
49
60
|
ro.disconnect();
|
|
50
61
|
mo?.disconnect();
|
|
51
|
-
|
|
62
|
+
around?.disconnect();
|
|
63
|
+
el.removeEventListener("focusout", onFocusOut);
|
|
52
64
|
set(false);
|
|
53
65
|
};
|
|
54
66
|
}, [el, label, enabled, nameFromHeading, axis]);
|
|
55
67
|
}
|
|
56
68
|
|
|
57
69
|
export { useKeyboardScroll };
|
|
58
|
-
//# sourceMappingURL=chunk-
|
|
59
|
-
//# sourceMappingURL=chunk-
|
|
70
|
+
//# sourceMappingURL=chunk-KSJTMSYA.js.map
|
|
71
|
+
//# sourceMappingURL=chunk-KSJTMSYA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/lib/use-keyboard-scroll.ts"],"names":[],"mappings":"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","file":"chunk-KSJTMSYA.js","sourcesContent":["import { useEffect } from \"react\";\nimport { hasTabStop } from \"./focus\";\nimport { useRevealFocus } from \"./reveal-focus\";\n\n/**\n * WCAG 2.1.1: a region that scrolls, with nothing inside it to Tab to, is a Tab stop of its own, named, so a keyboard\n * can scroll it (Chrome makes such a scroller focusable by itself; Safari doesn't). Sprint 25.16 A42: what fills the\n * page scrolls inside itself, so a board's column or a split view's pane can be such a region. It stops being one when\n * it no longer scrolls or something inside it takes focus — but while it has focus it stays one, until focus leaves it,\n * so a resize that makes it fit never drops the focus to the page (as Table's scroll region does; the review of\n * 1 October). Give the element a visible focus style (FOCUS_INSET). Pass the element itself (a callback ref's), so a\n * pane drawn later (a detail that opens) is read when it appears. With `nameFromHeading`, the region takes its first\n * heading's words as its name (an item's view: its title), and `label` only when it has none. What the keyboard focuses\n * inside it is scrolled into view whole (useRevealFocus, Sprint 30): give the region `scroll-p-[4px]` for the outline.\n * `axis` \"x\" for a strip that scrolls sideways (the Calendar's week of days on a phone, Sprint 25.29 item 10), \"both\"\n * for an area that scrolls either way (ScrollArea's, Sprint 25.30 item 2).\n */\nexport function useKeyboardScroll(el: HTMLElement | null, label: string, enabled = true, nameFromHeading = false, axis: \"y\" | \"x\" | \"both\" = \"y\"): void {\n useRevealFocus(el, enabled);\n useEffect(() => {\n if (!enabled || !el || typeof ResizeObserver === \"undefined\") return;\n const name = () => {\n const heading = nameFromHeading ? el.querySelector(\"h1, h2, h3, h4, h5, h6\")?.textContent?.trim() : \"\";\n return heading || label;\n };\n // what the element has of its own, kept: a landmark's role and name (the shell's <main>), and the skip link's target's\n // tabindex -1, put back when it stops being a stop (Sprint 25.29 item 10)\n const own = { tabindex: el.getAttribute(\"tabindex\"), role: el.getAttribute(\"role\"), label: el.getAttribute(\"aria-label\") };\n const landmark = /^(MAIN|NAV|ASIDE|ARTICLE|SECTION|FORM)$/.test(el.tagName);\n const keepRole = own.role !== null || landmark;\n const keepName = own.label !== null || landmark;\n const restore = (attr: string, value: string | null) => (value === null ? el.removeAttribute(attr) : el.setAttribute(attr, value));\n const set = (on: boolean) => {\n if (on === el.hasAttribute(\"data-scroll-stop\")) {\n if (on && !keepName && el.getAttribute(\"aria-label\") !== name()) el.setAttribute(\"aria-label\", name());\n return;\n }\n if (on) {\n el.setAttribute(\"data-scroll-stop\", \"\");\n el.tabIndex = 0;\n if (!keepRole) el.setAttribute(\"role\", \"region\");\n if (!keepName) el.setAttribute(\"aria-label\", name());\n } else {\n el.removeAttribute(\"data-scroll-stop\");\n restore(\"tabindex\", own.tabindex);\n if (!keepRole) restore(\"role\", own.role);\n if (!keepName) restore(\"aria-label\", own.label);\n }\n };\n const update = () => {\n // inert (the shell's phone menu over <main>), nothing in it is a stop, nor is it: what it is waits until it isn't\n // (Sprint 25.31 item 6: a clock ticking in <main> made it a stop then, and it stayed one once the menu closed)\n if (el.closest(\"[inert]\")) return;\n // a stop with focus stays one until focus leaves it\n if (el.hasAttribute(\"data-scroll-stop\") && document.activeElement === el) return set(true);\n // anything inside to Tab to, and it's no stop, with no need to measure: the first found ends the search (item 7)\n if (hasTabStop(el)) return set(false);\n const wide = el.scrollWidth > el.clientWidth + 1, tall = el.scrollHeight > el.clientHeight + 1;\n set(axis === \"x\" ? wide : axis === \"both\" ? wide || tall : tall);\n };\n update();\n const ro = new ResizeObserver(update);\n ro.observe(el);\n // what's inside changing, and what decides whether it's a stop (item 6): a control enabled, shown, given a tabindex,\n // or made inert. The element's own tabindex is this hook's to write, so its change is no news.\n const itsOwn = (r: MutationRecord) => r.type === \"attributes\" && r.target === el && r.attributeName === \"tabindex\";\n const mo = typeof MutationObserver === \"undefined\" ? null : new MutationObserver((records) => { if (!records.every(itsOwn)) update(); });\n mo?.observe(el, { childList: true, subtree: true, characterData: true, attributes: true, attributeFilter: [\"inert\", \"disabled\", \"hidden\", \"tabindex\"] });\n // and a box round it made inert, or no longer inert: the page's own, or the phone menu's (item 6)\n const around = typeof MutationObserver === \"undefined\" ? null : new MutationObserver((records) => {\n if (records.some((r) => r.target !== el && r.target instanceof Element && r.target.contains(el))) update();\n });\n around?.observe(el.ownerDocument.documentElement, { subtree: true, attributes: true, attributeFilter: [\"inert\"] });\n // focus leaving a stop that no longer scrolls ends it: focus leaving the element itself, not a control inside it (item 7)\n const onFocusOut = (e: FocusEvent) => { if (e.target === el) update(); };\n el.addEventListener(\"focusout\", onFocusOut);\n return () => {\n ro.disconnect();\n mo?.disconnect();\n around?.disconnect();\n el.removeEventListener(\"focusout\", onFocusOut);\n set(false);\n };\n }, [el, label, enabled, nameFromHeading, axis]);\n}\n\n/** The focus style for such a region: the theme's outline, drawn inside its edge so a neighbour can't hide it (lib/utils.ts since Sprint 30). */\nexport { FOCUS_INSET } from \"./utils\";\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { Badge } from './chunk-
|
|
3
|
-
import { useKeyboardScroll } from './chunk-
|
|
4
|
-
import { slotIcon, Icon } from './chunk-
|
|
5
|
-
import { cn, FOCUS_RING, FOCUS_INSET } from './chunk-
|
|
2
|
+
import { Badge } from './chunk-SLGGZ3MU.js';
|
|
3
|
+
import { useKeyboardScroll } from './chunk-KSJTMSYA.js';
|
|
4
|
+
import { slotIcon, Icon } from './chunk-53F7GVBQ.js';
|
|
5
|
+
import { cn, FOCUS_RING, FOCUS_INSET } from './chunk-EZ3ZGFGA.js';
|
|
6
6
|
import { forwardRef, useState, useCallback } from 'react';
|
|
7
7
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
8
8
|
|
|
@@ -11,6 +11,7 @@ function CodeBlock({
|
|
|
11
11
|
language,
|
|
12
12
|
showLineNumbers = false,
|
|
13
13
|
wrap,
|
|
14
|
+
"aria-label": ariaLabel,
|
|
14
15
|
className
|
|
15
16
|
}) {
|
|
16
17
|
const [copied, setCopied] = useState(false);
|
|
@@ -25,7 +26,7 @@ function CodeBlock({
|
|
|
25
26
|
const lines = code.split("\n");
|
|
26
27
|
const wraps = wrap ?? lines.length === 1;
|
|
27
28
|
const [scroller, setScroller] = useState(null);
|
|
28
|
-
useKeyboardScroll(scroller, "Code", !wraps, false, "x");
|
|
29
|
+
useKeyboardScroll(scroller, ariaLabel ?? (language ? `Code: ${language}` : "Code"), !wraps, false, "x");
|
|
29
30
|
const gutterWidth = showLineNumbers ? `${String(lines.length).length + 1}ch` : void 0;
|
|
30
31
|
return /* @__PURE__ */ jsxs(
|
|
31
32
|
"div",
|
|
@@ -162,5 +163,5 @@ function Divider({
|
|
|
162
163
|
}
|
|
163
164
|
|
|
164
165
|
export { CodeBlock, Divider, Link };
|
|
165
|
-
//# sourceMappingURL=chunk-
|
|
166
|
-
//# sourceMappingURL=chunk-
|
|
166
|
+
//# sourceMappingURL=chunk-NDL2JGQ7.js.map
|
|
167
|
+
//# sourceMappingURL=chunk-NDL2JGQ7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/components/CodeBlock.tsx","../../../showcase/src/components/Link.tsx","../../../showcase/src/components/Divider.tsx"],"names":["Link","jsxs","jsx"],"mappings":"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","file":"chunk-NDL2JGQ7.js","sourcesContent":["import { useState, useCallback } from \"react\";\nimport { cn, FOCUS_INSET, FOCUS_RING } from \"../lib/utils\";\nimport { useKeyboardScroll } from \"../lib/use-keyboard-scroll\";\nimport { Icon } from \"../lib/icons\";\nimport { Badge } from \"./Badge\";\n\ninterface CodeBlockProps {\n code: string;\n language?: string;\n showLineNumbers?: boolean;\n /** Wrap long lines instead of scrolling sideways. Default: on for a single-line snippet (a tracking tag, a command), off for multi-line code. */\n wrap?: boolean;\n /**\n * What the code is (\"app.tsx\"): its name while it scrolls sideways, a Tab stop of its own then, so a page of several\n * reads them apart. Default: its language, \"Code: tsx\", else \"Code\".\n */\n \"aria-label\"?: string;\n className?: string;\n}\n\nexport function CodeBlock({\n code,\n language,\n showLineNumbers = false,\n wrap,\n \"aria-label\": ariaLabel,\n className,\n}: CodeBlockProps) {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch {\n /* clipboard not available */\n }\n }, [code]);\n\n const lines = code.split(\"\\n\");\n const wraps = wrap ?? lines.length === 1;\n // code that scrolls sideways, with nothing in it to Tab to: a Tab stop while it scrolls (Sprint 25.30 item 2), named by\n // the page's aria-label, else its language where it has one, so a page of several reads them apart: \"Code: tsx\"\n // (Sprint 25.31 item 8 and the review of 16 October, 7)\n const [scroller, setScroller] = useState<HTMLDivElement | null>(null);\n useKeyboardScroll(scroller, ariaLabel ?? (language ? `Code: ${language}` : \"Code\"), !wraps, false, \"x\");\n const gutterWidth = showLineNumbers ? `${String(lines.length).length + 1}ch` : undefined;\n\n return (\n <div\n className={cn(\n \"relative group\",\n \"bg-[var(--ds-bg-surface)] text-[var(--ds-text-primary)]\",\n \"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]\",\n \"rounded-[var(--ds-radius-md)]\",\n \"shadow-[var(--ds-shadow-sm)]\",\n \"overflow-hidden\",\n className,\n )}\n >\n <div className=\"flex items-center justify-between px-ds-4 py-ds-2 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] bg-[var(--ds-bg-muted)]\">\n <div className=\"flex items-center gap-ds-2\">\n {language && <Badge variant=\"outline\" size=\"sm\">{language}</Badge>}\n </div>\n <button\n type=\"button\"\n onClick={handleCopy}\n className={cn(\n \"inline-flex items-center gap-ds-1.5 px-ds-2 py-ds-1 text-xs font-medium cursor-pointer\",\n \"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]\",\n \"rounded-[var(--ds-radius-sm)]\",\n \"hover:bg-[var(--ds-bg-surface)]\",\n \"transition-colors\",\n FOCUS_RING,\n )}\n aria-label={copied ? \"Copied\" : \"Copy code\"}\n >\n {/* Sprint 25.8.7 item 12: the copy icon, where a folder stood */}\n <Icon name={copied ? \"check\" : \"copy\"} size={14} />\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n </div>\n\n <div ref={setScroller} className={wraps ? undefined : cn(\"overflow-x-auto\", FOCUS_INSET)} data-wrap={wraps ? \"true\" : undefined}>\n <pre className={cn(\"p-ds-4 text-sm leading-relaxed font-[family-name:var(--ds-font-mono)]\", wraps && \"whitespace-pre-wrap break-words\")}>\n <code>\n {lines.map((line, i) => (\n // with line numbers each line is a two-column row, so a wrapped line continues under its text, not under the gutter\n <span key={i} className={showLineNumbers ? \"grid grid-cols-[max-content_1fr]\" : \"block\"}>\n {showLineNumbers && (\n <span\n className=\"text-right text-[var(--ds-text-muted)] select-none mr-ds-4 opacity-50\"\n style={{ width: gutterWidth }}\n >\n {i + 1}\n </span>\n )}\n <span className=\"min-w-0\">{line || \" \"}</span>\n </span>\n ))}\n </code>\n </pre>\n </div>\n </div>\n );\n}\n","import { forwardRef, type AnchorHTMLAttributes, type ElementType, type ReactNode } from \"react\";\nimport { cn, FOCUS_RING } from \"../lib/utils\";\nimport { slotIcon, type IconSlot } from \"../lib/icons\";\n\ntype LinkUnderline = \"hover\" | \"always\" | \"none\";\ntype LinkTone = \"accent\" | \"muted\" | \"inherit\";\n\nexport interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n href: string;\n children: ReactNode;\n /** When to show the underline. Default \"hover\". */\n underline?: LinkUnderline;\n /** Colour: accent (default), muted for secondary links, inherit to match surrounding text. */\n tone?: LinkTone;\n /** Opens in a new tab with rel=\"noopener noreferrer\". Default false. */\n external?: boolean;\n /**\n * Render through a router link component instead of a plain anchor\n * (e.g. `component={RouterLink}` from react-router or next/link). The\n * component receives the same props; `href` is also passed as `to` for\n * react-router compatibility. Any element type: a router's Link requires\n * its own props (react-router's `to`), which a narrower type refused under\n * strict TypeScript (Sprint 25.16 A19).\n */\n component?: ElementType;\n /** An icon name (\"info\"), drawn as the theme's icon at 14 px, or an element. Not text: use children. */\n iconLeft?: IconSlot;\n /** As iconLeft, after the label. */\n iconRight?: IconSlot;\n}\n\nconst toneStyles: Record<LinkTone, string> = {\n accent: \"text-[var(--ds-accent-ink)] hover:text-[var(--ds-accent-primary-hover)] active:text-[var(--ds-accent-primary-active)]\",\n muted: \"text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)]\",\n inherit: \"text-inherit hover:text-[var(--ds-accent-ink)]\",\n};\n\nconst underlineStyles: Record<LinkUnderline, string> = {\n hover: \"no-underline hover:underline\",\n always: \"underline underline-offset-2\",\n none: \"no-underline\",\n};\n\n/**\n * Navigation link. Renders a real <a> (or a router link via `component`) so\n * middle-click, open-in-new-tab, right-click \"copy link\" and screen readers\n * all behave correctly. Visually identical to Button variant=\"link\".\n *\n * Use Link for NAVIGATION (to a page or URL). Use Button variant=\"link\" for an\n * ACTION that should look like a link (show more, resend code). Never use a\n * ghost Button for inline text — its padding breaks the line.\n */\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(function Link(\n { href, children, underline = \"hover\", tone = \"accent\", external = false, component: Component, iconLeft, iconRight, className, target, rel, ...props },\n ref,\n) {\n const classes = cn(\n \"inline-flex items-center gap-ds-1 font-medium cursor-pointer\",\n \"transition-colors duration-[var(--ds-transition-speed)]\",\n FOCUS_RING,\n \"rounded-[var(--ds-radius-sm)]\",\n toneStyles[tone],\n underlineStyles[underline],\n className,\n );\n const resolvedTarget = external ? \"_blank\" : target;\n const resolvedRel = external ? cn(\"noopener noreferrer\", rel) : rel;\n const content = (\n <>\n {slotIcon(iconLeft, 14, \"Link's iconLeft\")}\n {children}\n {slotIcon(iconRight, 14, \"Link's iconRight\")}\n </>\n );\n\n if (Component) {\n return (\n <Component ref={ref} href={href} to={href} className={classes} target={resolvedTarget} rel={resolvedRel} {...props}>\n {content}\n </Component>\n );\n }\n\n return (\n <a ref={ref} href={href} className={classes} target={resolvedTarget} rel={resolvedRel} {...props}>\n {content}\n </a>\n );\n});\n","import { cn } from \"../lib/utils\";\nimport type { ReactNode } from \"react\";\n\ntype Orientation = \"horizontal\" | \"vertical\";\n\ninterface DividerProps {\n orientation?: Orientation;\n label?: ReactNode;\n className?: string;\n}\n\nexport function Divider({\n orientation = \"horizontal\",\n label,\n className,\n}: DividerProps) {\n if (orientation === \"vertical\") {\n return (\n <div\n role=\"separator\"\n aria-orientation=\"vertical\"\n className={cn(\n \"inline-block self-stretch min-h-[1em]\",\n \"w-[var(--ds-divider-width)]\",\n \"bg-[var(--ds-border-default)]\",\n className,\n )}\n />\n );\n }\n\n if (label) {\n return (\n <div\n role=\"separator\"\n className={cn(\"flex items-center gap-ds-3\", className)}\n >\n <span className=\"flex-1 h-[var(--ds-divider-width)] bg-[var(--ds-border-default)]\" />\n <span className=\"text-xs font-medium text-[var(--ds-text-muted)] shrink-0\">\n {label}\n </span>\n <span className=\"flex-1 h-[var(--ds-divider-width)] bg-[var(--ds-border-default)]\" />\n </div>\n );\n }\n\n return (\n <hr\n role=\"separator\"\n className={cn(\n \"border-none w-full\",\n \"h-[var(--ds-divider-width)]\",\n \"bg-[var(--ds-border-default)]\",\n className,\n )}\n />\n );\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { formatLocale } from './chunk-7QLXYRPD.js';
|
|
3
|
-
import { warnOnce } from './chunk-
|
|
3
|
+
import { warnOnce } from './chunk-53F7GVBQ.js';
|
|
4
4
|
import { createContext, useMemo, useContext } from 'react';
|
|
5
5
|
|
|
6
6
|
// ../../showcase/src/lib/relative-time.ts
|
|
@@ -101,5 +101,5 @@ function preferenceActionKey(label) {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
export { DAY, HOUR, MINUTE, PREFERENCE_HOUSE_DEFAULTS, PreferencesContext, datedMillis, formatFullTime, formatRelativeTime, preferenceActionKey, thresholdOf, toMillis, usePreferences, useShellPreferences };
|
|
104
|
-
//# sourceMappingURL=chunk-
|
|
105
|
-
//# sourceMappingURL=chunk-
|
|
104
|
+
//# sourceMappingURL=chunk-QOMP4D6V.js.map
|
|
105
|
+
//# sourceMappingURL=chunk-QOMP4D6V.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../showcase/src/lib/relative-time.ts","../../../showcase/src/lib/preferences.ts"],"names":[],"mappings":";;;;;;AAYO,IAAM,MAAA,GAAS;AACf,IAAM,OAAO,EAAA,GAAK;AAClB,IAAM,MAAM,EAAA,GAAK;AAGjB,IAAM,8BAAA,GAAiC,EAAA;AAEvC,SAAS,SAAS,IAAA,EAAyB;AAChD,EAAA,IAAI,IAAA,YAAgB,IAAA,EAAM,OAAO,IAAA,CAAK,OAAA,EAAQ;AAC9C,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA;AACrC,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,GAAA;AAGrC,EAAA,MAAM,GAAA,GAAM,2BAAA,CAA4B,IAAA,CAAK,IAAA,CAAK,MAAM,CAAA;AACxD,EAAA,IAAI,GAAA,SAAY,IAAI,IAAA,CAAK,OAAO,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,MAAA,CAAO,IAAI,CAAC,CAAC,IAAI,CAAA,EAAG,MAAA,CAAO,IAAI,CAAC,CAAC,CAAC,CAAA,CAAE,OAAA,EAAQ;AACrF,EAAA,OAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AACxB;AAOA,IAAM,QAAA,GAAW,uFAAA;AAQV,SAAS,YAAY,IAAA,EAAyB;AACnD,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,SAAS,IAAI,CAAA;AAClD,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,IAAA,CAAK,IAAI,CAAA;AAC9B,EAAA,IAAI,CAAC,KAAK,OAAO,GAAA;AACjB,EAAA,MAAM,CAAC,MAAM,KAAA,EAAO,GAAG,IAAI,CAAC,MAAA,CAAO,IAAI,CAAC,CAAC,GAAG,MAAA,CAAO,GAAA,CAAI,CAAC,CAAC,CAAA,GAAI,GAAG,MAAA,CAAO,GAAA,CAAI,CAAC,CAAC,CAAC,CAAA;AAE9E,EAAA,MAAM,KAAA,mBAAQ,IAAI,IAAA,CAAK,CAAC,CAAA;AACxB,EAAA,KAAA,CAAM,cAAA,CAAe,IAAA,EAAM,KAAA,EAAO,GAAG,CAAA;AACrC,EAAA,IAAI,KAAA,CAAM,cAAA,EAAe,KAAM,IAAA,IAAQ,KAAA,CAAM,WAAA,EAAY,KAAM,KAAA,IAAS,KAAA,CAAM,UAAA,EAAW,KAAM,GAAA,EAAK,OAAO,GAAA;AAC3G,EAAA,OAAO,SAAS,IAAI,CAAA;AACtB;AAMO,SAAS,WAAA,CAAY,OAAgB,IAAA,EAAsB;AAChE,EAAA,IAAI,OAAO,UAAU,QAAA,IAAY,MAAA,CAAO,SAAS,KAAK,CAAA,IAAK,KAAA,IAAS,CAAA,EAAG,OAAO,KAAA;AAC9E,EAAA,MAAM,KAAA,GAAQ,8BAAA;AACd,EAAA,QAAA,CAAS,MAAM,CAAA,eAAA,EAAkB,MAAA,CAAO,KAAK,CAAC,CAAA,yCAAA,EAA4C,KAAK,CAAA,SAAA,CAAW,CAAA;AAC1G,EAAA,OAAO,KAAA;AACT;AAGA,SAAS,SAAS,CAAA,EAAmB;AACnC,EAAA,MAAM,CAAA,GAAI,IAAI,IAAA,CAAK,CAAC,CAAA;AACpB,EAAA,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AACrB,EAAA,OAAO,EAAE,OAAA,EAAQ;AACnB;AAQO,SAAS,kBAAA,CAAmB,MAAiB,OAAA,EAA4E;AAC9H,EAAA,MAAM,EAAA,GAAK,SAAS,IAAI,CAAA;AACxB,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,EAAE,GAAG,OAAO,EAAA;AACjC,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,GAAA,IAAO,IAAA,CAAK,GAAA,EAAI;AAEpC,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,IAAU,YAAA,EAAa;AAC9C,EAAA,MAAM,OAAO,EAAA,GAAK,GAAA;AAClB,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA;AAGzB,EAAA,IAAI,GAAA,GAAM,YAAY,OAAA,CAAQ,cAAA,EAAgB,oBAAoB,CAAA,GAAI,IAAA,SAAa,IAAI,IAAA,CAAK,eAAe,MAAA,EAAQ,EAAE,WAAW,QAAA,EAAU,SAAA,EAAW,SAAS,CAAA,CAAE,OAAO,EAAE,CAAA;AAGzK,EAAA,MAAM,GAAA,GAAM,IAAI,IAAA,CAAK,kBAAA,CAAmB,QAAQ,EAAE,OAAA,EAAS,QAAQ,CAAA;AACnE,EAAA,IAAI,MAAM,MAAA,EAAQ,OAAO,GAAA,CAAI,MAAA,CAAO,GAAG,QAAQ,CAAA;AAC/C,EAAA,IAAI,GAAA,GAAM,IAAA,EAAM,OAAO,GAAA,CAAI,MAAA,CAAO,KAAK,KAAA,CAAM,IAAA,GAAO,MAAM,CAAA,EAAG,QAAQ,CAAA;AACrE,EAAA,IAAI,GAAA,GAAM,GAAA,EAAK,OAAO,GAAA,CAAI,MAAA,CAAO,KAAK,KAAA,CAAM,IAAA,GAAO,IAAI,CAAA,EAAG,MAAM,CAAA;AAChE,EAAA,OAAO,GAAA,CAAI,MAAA,CAAO,IAAA,CAAK,KAAA,CAAA,CAAO,QAAA,CAAS,EAAE,CAAA,GAAI,QAAA,CAAS,GAAG,CAAA,IAAK,GAAG,CAAA,EAAG,KAAK,CAAA;AAC3E;AAMO,SAAS,cAAA,CAAe,MAAiB,MAAA,EAAyB;AACvE,EAAA,MAAM,EAAA,GAAK,SAAS,IAAI,CAAA;AACxB,EAAA,OAAO,MAAA,CAAO,QAAA,CAAS,EAAE,CAAA,GACrB,IAAI,IAAA,CAAK,cAAA,CAAe,MAAA,IAAU,YAAA,EAAa,EAAG,EAAE,IAAA,EAAM,SAAA,EAAW,KAAA,EAAO,MAAA,EAAQ,GAAA,EAAK,SAAA,EAAW,IAAA,EAAM,SAAA,EAAW,MAAA,EAAQ,SAAA,EAAW,YAAA,EAAc,OAAA,EAAS,CAAA,CAAE,MAAA,CAAO,EAAE,CAAA,GAC1K,EAAA;AACN;ACrDO,IAAM,kBAAA,GAAqB,cAA0C,IAAI;AAuBhF,IAAM,cAAA,GAAsC;AAAA,EAC1C,gBAAA,EAAkB,QAAA;AAAA,EAClB,WAAA,EAAa,EAAE,KAAA,EAAO,KAAA,EAAO,WAAW,MAAA,EAAO;AAAA,EAC/C,YAAA,EAAc,EAAA;AAAA,EACd,eAAA,EAAiB,YAAA;AAAA,EACjB,sBAAA,EAAwB,IAAA;AAAA,EACxB,UAAA,EAAY,kBAAA;AAAA,EACZ,YAAA,EAAc,UAAA;AAAA,EACd,eAAA,EAAiB,QAAA;AAAA,EACjB,mBAAA,EAAqB,CAAC,gBAAA,EAAkB,oBAAoB,CAAA;AAAA,EAC5D,oBAAA,EAAsB,CAAC,gBAAgB,CAAA;AAAA,EACvC,iBAAA,EAAmB,CAAA;AAAA,EACnB,sBAAA,EAAwB,8BAAA;AAAA,EACxB,eAAA,EAAiB;AACnB,CAAA;AACO,IAAM,yBAAA,GAA2D,MAAA,CAAO,MAAA,CAAO,cAAc;AAQ7F,SAAS,cAAA,GAAsC;AACpD,EAAA,MAAM,MAAM,mBAAA,EAAoB;AAChC,EAAA,OAAO,QAAQ,MAAM,kBAAA,CAAmB,GAAG,CAAA,EAAG,CAAC,GAAG,CAAC,CAAA;AACrD;AAGO,SAAS,mBAAmB,GAAA,EAA+C;AAChF,EAAA,MAAM,CAAA,GAAI,yBAAA;AACV,EAAA,MAAM,GAAA,GAA2B,EAAE,GAAG,CAAA,EAAG,aAAa,EAAE,GAAG,EAAE,WAAA,EAAY,EAAG,qBAAqB,CAAC,GAAG,EAAE,mBAAmB,CAAA,EAAG,sBAAsB,CAAC,GAAG,CAAA,CAAE,oBAAoB,CAAA,EAAE;AAC/K,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAkD;AAC7F,IAAA,IAAI,UAAU,MAAA,EAAW;AACzB,IAAA,IAAI,QAAQ,aAAA,EAAe;AACzB,MAAA,MAAM,OAAA,GAAU,KAAA;AAChB,MAAA,IAAI,SAAS,KAAA,KAAU,MAAA,EAAW,GAAA,CAAI,WAAA,CAAY,QAAQ,OAAA,CAAQ,KAAA;AAClE,MAAA,IAAI,SAAS,SAAA,KAAc,MAAA,EAAW,GAAA,CAAI,WAAA,CAAY,YAAY,OAAA,CAAQ,SAAA;AAC1E,MAAA;AAAA,IACF;AACA,IAAC,GAAA,CAA2C,GAAG,CAAA,GAAI,KAAA;AAAA,EACrD;AACA,EAAA,OAAO,GAAA;AACT;AAMO,SAAS,mBAAA,GAA2C;AACzD,EAAA,OAAO,UAAA,CAAW,kBAAkB,CAAA,IAAK,KAAA;AAC3C;AAEA,IAAM,KAAA,GAA6B,MAAA,CAAO,MAAA,CAAO,EAAE,CAAA;AAM5C,SAAS,oBAAoB,KAAA,EAAuB;AACzD,EAAA,OAAO,KAAA,CAAM,IAAA,EAAK,CAAE,WAAA,EAAY,CAAE,OAAA,CAAQ,aAAA,EAAe,GAAG,CAAA,CAAE,OAAA,CAAQ,QAAA,EAAU,EAAE,CAAA;AACpF","file":"chunk-TYNDXMBV.js","sourcesContent":["import { warnOnce } from \"./dev-warn\";\nimport { formatLocale } from \"./format-locale\";\n\n/**\n * Times as people read them, relative or in full (Sprint 25.17 A29), apart from the RelativeTime component since Sprint\n * 25.22 (nothing here needs React). Not on `gridsmith-ui/utils` (that sprint's review): a relative time and a full one\n * depend on the visitor's clock and time zone, which a server doesn't know, so a server page hands RelativeTime the time.\n */\n\n/** A time: an ISO string, a Date, or milliseconds since the epoch. */\nexport type TimeValue = string | Date | number;\n\nexport const MINUTE = 60_000;\nexport const HOUR = 60 * MINUTE;\nexport const DAY = 24 * HOUR;\n\n/** The house's threshold, dateTime.relativeThresholdHours: within this many hours a time reads relative. The shell's preferences default to it. */\nexport const HOUSE_RELATIVE_THRESHOLD_HOURS = 24;\n\nexport function toMillis(time: TimeValue): number {\n if (time instanceof Date) return time.getTime();\n if (typeof time === \"number\") return time;\n if (typeof time !== \"string\") return NaN;\n // a date alone (\"2026-09-01\") is that day on the calendar here, as people read it: Date.parse reads it as midnight in\n // UTC, which New York showed as the evening before (the 25.17 second review)\n const day = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(time.trim());\n if (day) return new Date(Number(day[1]), Number(day[2]) - 1, Number(day[3])).getTime();\n return Date.parse(time);\n}\n\n/**\n * ISO 8601's extended form, as ECMAScript's date-time format writes it: a calendar date, then perhaps a time (hours and\n * minutes, perhaps seconds and a fraction) and perhaps its zone, Z or ±hh:mm (±hhmm is ISO 8601 too, but outside the\n * format every browser must read, so it stays text).\n */\nconst ISO_8601 = /^(\\d{4})-(\\d{2})-(\\d{2})(?:T\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?(?:Z|[+-]\\d{2}:\\d{2})?)?$/;\n\n/**\n * A time's milliseconds when it can be dated, else NaN (Sprint 25.8.7 item 10): a Date or a number as it is, a string\n * only in ISO 8601's form and on a day the calendar has. Date.parse guesses at other text (\"March 3\" is 3 March 2001,\n * \"12\" December 2001) and carries a day past its month's end into the next (\"2026-02-30\" is 2 March), so text that\n * only reads like a time (\"2 days ago\", \"Yesterday\") is never given a date.\n */\nexport function datedMillis(time: TimeValue): number {\n if (typeof time !== \"string\") return toMillis(time);\n const iso = ISO_8601.exec(time);\n if (!iso) return NaN;\n const [year, month, day] = [Number(iso[1]), Number(iso[2]) - 1, Number(iso[3])];\n // in UTC, so no zone moves the day; setUTCFullYear, since Date.UTC reads the years 0–99 as 1900–1999\n const check = new Date(0);\n check.setUTCFullYear(year, month, day);\n if (check.getUTCFullYear() !== year || check.getUTCMonth() !== month || check.getUTCDate() !== day) return NaN;\n return toMillis(time);\n}\n\n/**\n * A threshold as given, or the house's when it isn't a number of hours (a missing setting read as `Number(undefined)`\n * re-rendered every time in a loop: the 25.17 second review), which development builds are told about.\n */\nexport function thresholdOf(hours: unknown, from: string): number {\n if (typeof hours === \"number\" && Number.isFinite(hours) && hours >= 0) return hours;\n const house = HOUSE_RELATIVE_THRESHOLD_HOURS;\n warnOnce(from, `a threshold of ${String(hours)} isn't a number of hours, so the house's ${house} is used.`);\n return house;\n}\n\n/** Local midnight before a moment: days are counted on the calendar, so Monday 23:30 is two days before Wednesday 00:30. */\nfunction midnight(t: number): number {\n const d = new Date(t);\n d.setHours(0, 0, 0, 0);\n return d.getTime();\n}\n\n/**\n * A time as people read it (Sprint 25.17 A29, R28-48; date_time#1, #11 and #13): within `thresholdHours` of now,\n * relative (\"now\", \"5 minutes ago\", \"in 2 hours\", \"yesterday\", counting days on the calendar), in the page's language;\n * beyond it, the date and the time. The threshold is given: the project's is the shell's\n * (dateTime.relativeThresholdHours), which RelativeTime and useRelativeTimeFormat read for you.\n */\nexport function formatRelativeTime(time: TimeValue, options: { thresholdHours: number; now?: number; locale?: string }): string {\n const at = toMillis(time);\n if (!Number.isFinite(at)) return \"\";\n const now = options.now ?? Date.now();\n // the locale given (a component's useFormatLocale(), Sprint 25.20), else the browser's reading\n const locale = options.locale ?? formatLocale();\n const diff = at - now;\n const age = Math.abs(diff);\n // past the threshold the moment itself: a log or a table keeps its time of day (the review: a log read \"1 Oct 2026\"\n // on every row)\n if (age > thresholdOf(options.thresholdHours, \"formatRelativeTime\") * HOUR) return new Intl.DateTimeFormat(locale, { dateStyle: \"medium\", timeStyle: \"short\" }).format(at);\n // whole units, counted as they pass (\"5 minutes ago\" until the sixth minute), so the text changes when the shown time\n // refreshes, on the minute or the hour\n const rtf = new Intl.RelativeTimeFormat(locale, { numeric: \"auto\" });\n if (age < MINUTE) return rtf.format(0, \"second\");\n if (age < HOUR) return rtf.format(Math.trunc(diff / MINUTE), \"minute\");\n if (age < DAY) return rtf.format(Math.trunc(diff / HOUR), \"hour\");\n return rtf.format(Math.round((midnight(at) - midnight(now)) / DAY), \"day\");\n}\n\n/**\n * The full timestamp, as the tooltip and a screen reader give it: the date, the time and its zone, in the locale given\n * (a component's useFormatLocale()), else the browser's reading.\n */\nexport function formatFullTime(time: TimeValue, locale?: string): string {\n const at = toMillis(time);\n return Number.isFinite(at)\n ? new Intl.DateTimeFormat(locale ?? formatLocale(), { year: \"numeric\", month: \"long\", day: \"numeric\", hour: \"numeric\", minute: \"2-digit\", timeZoneName: \"short\" }).format(at)\n : \"\";\n}\n","/**\n * The customer's UX preferences, carried once by AppShell the way the theme is (Sprint 25.6 B9).\n *\n * The generated shell passes the object the template emits from the profile's rules; the builder preview passes the\n * same values from the theme state. Components default from it when no prop is passed — FormWrapper's validation mode\n * and actions alignment, Table and DataGrid's mobile breakpoint, Pagination's page size, EmptyState's style, the\n * destructive-action helper's mode, lists and undo window, and RelativeTime's threshold (Sprint 25.17 A29) and a flow's going back (useFlowSteps, Sprint 25.19 S3) — so a page\n * gets the customer's value by doing nothing. A\n * prop always wins; a component outside any shell keeps the default it always had (components read\n * `useShellPreferences`). App code reads `usePreferences`, which fills every field (round 21); a paged list reads its\n * page size through `usePagination`.\n */\nimport { createContext, useContext, useMemo } from \"react\";\nimport { HOUSE_RELATIVE_THRESHOLD_HOURS } from \"./relative-time\";\n\nexport type PreferenceValidationTiming = \"onBlur\" | \"onSubmit\" | \"onChange\";\nexport type PreferenceBreakpoint = \"sm\" | \"md\" | \"lg\";\nexport type PreferenceEmptyStyle = \"illustration-cta\" | \"text-cta\" | \"redirect\";\nexport type PreferenceLoadingStyle = \"skeleton\" | \"spinner\" | \"progress-bar\";\nexport type PreferenceDestructiveMode = \"dialog\" | \"undo\";\n/** dataDisplay.paginationStyle — how a long list shows more: page numbers, a Load more button, or loading as the user scrolls. */\nexport type PreferencePaginationStyle = \"pagination\" | \"load-more\" | \"infinite-scroll\";\n\nexport interface AppShellPreferences {\n /** forms.validationTiming — when a field first shows its error. */\n validationTiming?: PreferenceValidationTiming;\n /** forms.actions — where a form's buttons sit and how they align. */\n formActions?: { align?: \"start\" | \"end\"; placement?: \"auto\" | \"inline\" };\n /** dataDisplay.itemsPerPage — the page size of a paged or load-more list. */\n itemsPerPage?: number;\n /** dataDisplay.paginationStyle — page numbers, a Load more button, or loading on scroll; usePagination and Pagination follow it (round 22). */\n paginationStyle?: PreferencePaginationStyle;\n /** responsive.tableToCardsBreakpoint — below this width a Table becomes stacked cards. */\n tableToCardsBreakpoint?: PreferenceBreakpoint;\n /** emptyStates.emptyStyle — illustration with an action, text with an action, or redirect to creation. */\n emptyStyle?: PreferenceEmptyStyle;\n /** emptyStates.loadingStyle — what a page shows while data loads. */\n loadingStyle?: PreferenceLoadingStyle;\n /** destructiveActions.mode — confirm in a dialog, or act now with an Undo toast. */\n destructiveMode?: PreferenceDestructiveMode;\n /** destructiveActions.highSeverityActions — always confirm in a dialog, even in undo mode. */\n highSeverityActions?: string[];\n /** destructiveActions.typeToConfirmActions — the user types the name before the confirm enables. */\n typeToConfirmActions?: string[];\n /** destructiveActions.undoWindowSeconds — how long the Undo toast stays. */\n undoWindowSeconds?: number;\n /** dateTime.relativeThresholdHours — within this many hours a time reads relative (\"2 hours ago\"), older the date (RelativeTime). */\n relativeThresholdHours?: number;\n /**\n * forms.canNavigateBack — a flow with steps lets the user go back (Sprint 25.19 S3). On, its step list opens any step\n * already reached and it has a Back; off, the list only shows progress and there is no Back. useFlowSteps reads it.\n */\n canNavigateBack?: boolean;\n}\n\nexport const PreferencesContext = createContext<AppShellPreferences | null>(null);\n\n/** Every preference in force, the shell's value or the house default — what app code reads. */\nexport interface ResolvedPreferences {\n validationTiming: PreferenceValidationTiming;\n formActions: { align: \"start\" | \"end\"; placement: \"auto\" | \"inline\" };\n itemsPerPage: number;\n paginationStyle: PreferencePaginationStyle;\n tableToCardsBreakpoint: PreferenceBreakpoint;\n emptyStyle: PreferenceEmptyStyle;\n loadingStyle: PreferenceLoadingStyle;\n destructiveMode: PreferenceDestructiveMode;\n highSeverityActions: string[];\n typeToConfirmActions: string[];\n undoWindowSeconds: number;\n relativeThresholdHours: number;\n canNavigateBack: boolean;\n}\n\n/**\n * The house defaults for the fields the shell carries: the platform's preference-defaults.ts, mirrored in\n * decisions-schema.ts (DEFAULT_PATTERN_DECISIONS); a test keeps the three equal.\n */\nconst HOUSE_DEFAULTS: ResolvedPreferences = {\n validationTiming: \"onBlur\",\n formActions: { align: \"end\", placement: \"auto\" },\n itemsPerPage: 25,\n paginationStyle: \"pagination\",\n tableToCardsBreakpoint: \"md\",\n emptyStyle: \"illustration-cta\",\n loadingStyle: \"skeleton\",\n destructiveMode: \"dialog\",\n highSeverityActions: [\"delete_account\", \"remove_team_member\"],\n typeToConfirmActions: [\"delete_account\"],\n undoWindowSeconds: 5,\n relativeThresholdHours: HOUSE_RELATIVE_THRESHOLD_HOURS,\n canNavigateBack: true,\n};\nexport const PREFERENCE_HOUSE_DEFAULTS: Readonly<ResolvedPreferences> = Object.freeze(HOUSE_DEFAULTS);\n\n/**\n * For app code: every preference in force — the shell's value, else the house default — so a page never writes a\n * fallback of its own. Round 21 (run 58): with every field optional, TypeScript made the builder write\n * `const { itemsPerPage = 20 } = usePreferences()`, a second copy of the preference it then edited by hand when the\n * rule changed. Paged lists use `usePagination`, which reads the page size itself.\n */\nexport function usePreferences(): ResolvedPreferences {\n const raw = useShellPreferences();\n return useMemo(() => resolvePreferences(raw), [raw]);\n}\n\n/** The shell's values over the house defaults; a field the shell leaves undefined keeps its default. */\nexport function resolvePreferences(raw: AppShellPreferences): ResolvedPreferences {\n const d = PREFERENCE_HOUSE_DEFAULTS;\n const out: ResolvedPreferences = { ...d, formActions: { ...d.formActions }, highSeverityActions: [...d.highSeverityActions], typeToConfirmActions: [...d.typeToConfirmActions] };\n for (const [key, value] of Object.entries(raw) as Array<[keyof AppShellPreferences, unknown]>) {\n if (value === undefined) continue;\n if (key === \"formActions\") {\n const actions = value as AppShellPreferences[\"formActions\"];\n if (actions?.align !== undefined) out.formActions.align = actions.align;\n if (actions?.placement !== undefined) out.formActions.placement = actions.placement;\n continue;\n }\n (out as unknown as Record<string, unknown>)[key] = value;\n }\n return out;\n}\n\n/**\n * For components: only what the shell passed, or an empty object outside any shell — a component with no prop takes\n * the shell's value, and a bare component keeps the default it always had.\n */\nexport function useShellPreferences(): AppShellPreferences {\n return useContext(PreferencesContext) ?? EMPTY;\n}\n\nconst EMPTY: AppShellPreferences = Object.freeze({});\n\n/**\n * \"Remove range\" → \"remove_range\": the key the high-severity and type-to-confirm lists use. The engine's `actionKey`\n * (platform/src/lib/destructive-mode.ts) is the same rule for compliance; a platform test keeps the two identical.\n */\nexport function preferenceActionKey(label: string): string {\n return label.trim().toLowerCase().replace(/[^a-z0-9]+/g, \"_\").replace(/^_|_$/g, \"\");\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../showcase/src/lib/relative-time.ts","../../../showcase/src/lib/preferences.ts"],"names":[],"mappings":"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","file":"chunk-QOMP4D6V.js","sourcesContent":["import { warnOnce } from \"./dev-warn\";\nimport { formatLocale } from \"./format-locale\";\n\n/**\n * Times as people read them, relative or in full (Sprint 25.17 A29), apart from the RelativeTime component since Sprint\n * 25.22 (nothing here needs React). Not on `gridsmith-ui/utils` (that sprint's review): a relative time and a full one\n * depend on the visitor's clock and time zone, which a server doesn't know, so a server page hands RelativeTime the time.\n */\n\n/** A time: an ISO string, a Date, or milliseconds since the epoch. */\nexport type TimeValue = string | Date | number;\n\nexport const MINUTE = 60_000;\nexport const HOUR = 60 * MINUTE;\nexport const DAY = 24 * HOUR;\n\n/** The house's threshold, dateTime.relativeThresholdHours: within this many hours a time reads relative. The shell's preferences default to it. */\nexport const HOUSE_RELATIVE_THRESHOLD_HOURS = 24;\n\nexport function toMillis(time: TimeValue): number {\n if (time instanceof Date) return time.getTime();\n if (typeof time === \"number\") return time;\n if (typeof time !== \"string\") return NaN;\n // a date alone (\"2026-09-01\") is that day on the calendar here, as people read it: Date.parse reads it as midnight in\n // UTC, which New York showed as the evening before (the 25.17 second review)\n const day = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(time.trim());\n if (day) return new Date(Number(day[1]), Number(day[2]) - 1, Number(day[3])).getTime();\n return Date.parse(time);\n}\n\n/**\n * ISO 8601's extended form, as ECMAScript's date-time format writes it: a calendar date, then perhaps a time (hours and\n * minutes, perhaps seconds and a fraction) and perhaps its zone, Z or ±hh:mm (±hhmm is ISO 8601 too, but outside the\n * format every browser must read, so it stays text).\n */\nconst ISO_8601 = /^(\\d{4})-(\\d{2})-(\\d{2})(?:T\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?(?:Z|[+-]\\d{2}:\\d{2})?)?$/;\n\n/**\n * A time's milliseconds when it can be dated, else NaN (Sprint 25.8.7 item 10): a Date or a number as it is, a string\n * only in ISO 8601's form and on a day the calendar has. Date.parse guesses at other text (\"March 3\" is 3 March 2001,\n * \"12\" December 2001) and carries a day past its month's end into the next (\"2026-02-30\" is 2 March), so text that\n * only reads like a time (\"2 days ago\", \"Yesterday\") is never given a date.\n */\nexport function datedMillis(time: TimeValue): number {\n if (typeof time !== \"string\") return toMillis(time);\n const iso = ISO_8601.exec(time);\n if (!iso) return NaN;\n const [year, month, day] = [Number(iso[1]), Number(iso[2]) - 1, Number(iso[3])];\n // in UTC, so no zone moves the day; setUTCFullYear, since Date.UTC reads the years 0–99 as 1900–1999\n const check = new Date(0);\n check.setUTCFullYear(year, month, day);\n if (check.getUTCFullYear() !== year || check.getUTCMonth() !== month || check.getUTCDate() !== day) return NaN;\n return toMillis(time);\n}\n\n/**\n * A threshold as given, or the house's when it isn't a number of hours (a missing setting read as `Number(undefined)`\n * re-rendered every time in a loop: the 25.17 second review), which development builds are told about.\n */\nexport function thresholdOf(hours: unknown, from: string): number {\n if (typeof hours === \"number\" && Number.isFinite(hours) && hours >= 0) return hours;\n const house = HOUSE_RELATIVE_THRESHOLD_HOURS;\n warnOnce(from, `a threshold of ${String(hours)} isn't a number of hours, so the house's ${house} is used.`);\n return house;\n}\n\n/** Local midnight before a moment: days are counted on the calendar, so Monday 23:30 is two days before Wednesday 00:30. */\nfunction midnight(t: number): number {\n const d = new Date(t);\n d.setHours(0, 0, 0, 0);\n return d.getTime();\n}\n\n/**\n * A time as people read it (Sprint 25.17 A29, R28-48; date_time#1, #11 and #13): within `thresholdHours` of now,\n * relative (\"now\", \"5 minutes ago\", \"in 2 hours\", \"yesterday\", counting days on the calendar), in the page's language;\n * beyond it, the date and the time. The threshold is given: the project's is the shell's\n * (dateTime.relativeThresholdHours), which RelativeTime and useRelativeTimeFormat read for you.\n */\nexport function formatRelativeTime(time: TimeValue, options: { thresholdHours: number; now?: number; locale?: string }): string {\n const at = toMillis(time);\n if (!Number.isFinite(at)) return \"\";\n const now = options.now ?? Date.now();\n // the locale given (a component's useFormatLocale(), Sprint 25.20), else the browser's reading\n const locale = options.locale ?? formatLocale();\n const diff = at - now;\n const age = Math.abs(diff);\n // past the threshold the moment itself: a log or a table keeps its time of day (the review: a log read \"1 Oct 2026\"\n // on every row)\n if (age > thresholdOf(options.thresholdHours, \"formatRelativeTime\") * HOUR) return new Intl.DateTimeFormat(locale, { dateStyle: \"medium\", timeStyle: \"short\" }).format(at);\n // whole units, counted as they pass (\"5 minutes ago\" until the sixth minute), so the text changes when the shown time\n // refreshes, on the minute or the hour\n const rtf = new Intl.RelativeTimeFormat(locale, { numeric: \"auto\" });\n if (age < MINUTE) return rtf.format(0, \"second\");\n if (age < HOUR) return rtf.format(Math.trunc(diff / MINUTE), \"minute\");\n if (age < DAY) return rtf.format(Math.trunc(diff / HOUR), \"hour\");\n return rtf.format(Math.round((midnight(at) - midnight(now)) / DAY), \"day\");\n}\n\n/**\n * The full timestamp, as the tooltip and a screen reader give it: the date, the time and its zone, in the locale given\n * (a component's useFormatLocale()), else the browser's reading.\n */\nexport function formatFullTime(time: TimeValue, locale?: string): string {\n const at = toMillis(time);\n return Number.isFinite(at)\n ? new Intl.DateTimeFormat(locale ?? formatLocale(), { year: \"numeric\", month: \"long\", day: \"numeric\", hour: \"numeric\", minute: \"2-digit\", timeZoneName: \"short\" }).format(at)\n : \"\";\n}\n","/**\n * The customer's UX preferences, carried once by AppShell the way the theme is (Sprint 25.6 B9).\n *\n * The generated shell passes the object the template emits from the profile's rules; the builder preview passes the\n * same values from the theme state. Components default from it when no prop is passed — FormWrapper's validation mode\n * and actions alignment, Table and DataGrid's mobile breakpoint, Pagination's page size, EmptyState's style, the\n * destructive-action helper's mode, lists and undo window, and RelativeTime's threshold (Sprint 25.17 A29) and a flow's going back (useFlowSteps, Sprint 25.19 S3) — so a page\n * gets the customer's value by doing nothing. A\n * prop always wins; a component outside any shell keeps the default it always had (components read\n * `useShellPreferences`). App code reads `usePreferences`, which fills every field (round 21); a paged list reads its\n * page size through `usePagination`.\n */\nimport { createContext, useContext, useMemo } from \"react\";\nimport { HOUSE_RELATIVE_THRESHOLD_HOURS } from \"./relative-time\";\n\nexport type PreferenceValidationTiming = \"onBlur\" | \"onSubmit\" | \"onChange\";\nexport type PreferenceBreakpoint = \"sm\" | \"md\" | \"lg\";\nexport type PreferenceEmptyStyle = \"illustration-cta\" | \"text-cta\" | \"redirect\";\nexport type PreferenceLoadingStyle = \"skeleton\" | \"spinner\" | \"progress-bar\";\nexport type PreferenceDestructiveMode = \"dialog\" | \"undo\";\n/** dataDisplay.paginationStyle — how a long list shows more: page numbers, a Load more button, or loading as the user scrolls. */\nexport type PreferencePaginationStyle = \"pagination\" | \"load-more\" | \"infinite-scroll\";\n\nexport interface AppShellPreferences {\n /** forms.validationTiming — when a field first shows its error. */\n validationTiming?: PreferenceValidationTiming;\n /** forms.actions — where a form's buttons sit and how they align. */\n formActions?: { align?: \"start\" | \"end\"; placement?: \"auto\" | \"inline\" };\n /** dataDisplay.itemsPerPage — the page size of a paged or load-more list. */\n itemsPerPage?: number;\n /** dataDisplay.paginationStyle — page numbers, a Load more button, or loading on scroll; usePagination and Pagination follow it (round 22). */\n paginationStyle?: PreferencePaginationStyle;\n /** responsive.tableToCardsBreakpoint — below this width a Table becomes stacked cards. */\n tableToCardsBreakpoint?: PreferenceBreakpoint;\n /** emptyStates.emptyStyle — illustration with an action, text with an action, or redirect to creation. */\n emptyStyle?: PreferenceEmptyStyle;\n /** emptyStates.loadingStyle — what a page shows while data loads. */\n loadingStyle?: PreferenceLoadingStyle;\n /** destructiveActions.mode — confirm in a dialog, or act now with an Undo toast. */\n destructiveMode?: PreferenceDestructiveMode;\n /** destructiveActions.highSeverityActions — always confirm in a dialog, even in undo mode. */\n highSeverityActions?: string[];\n /** destructiveActions.typeToConfirmActions — the user types the name before the confirm enables. */\n typeToConfirmActions?: string[];\n /** destructiveActions.undoWindowSeconds — how long the Undo toast stays. */\n undoWindowSeconds?: number;\n /** dateTime.relativeThresholdHours — within this many hours a time reads relative (\"2 hours ago\"), older the date (RelativeTime). */\n relativeThresholdHours?: number;\n /**\n * forms.canNavigateBack — a flow with steps lets the user go back (Sprint 25.19 S3). On, its step list opens any step\n * already reached and it has a Back; off, the list only shows progress and there is no Back. useFlowSteps reads it.\n */\n canNavigateBack?: boolean;\n}\n\nexport const PreferencesContext = createContext<AppShellPreferences | null>(null);\n\n/** Every preference in force, the shell's value or the house default — what app code reads. */\nexport interface ResolvedPreferences {\n validationTiming: PreferenceValidationTiming;\n formActions: { align: \"start\" | \"end\"; placement: \"auto\" | \"inline\" };\n itemsPerPage: number;\n paginationStyle: PreferencePaginationStyle;\n tableToCardsBreakpoint: PreferenceBreakpoint;\n emptyStyle: PreferenceEmptyStyle;\n loadingStyle: PreferenceLoadingStyle;\n destructiveMode: PreferenceDestructiveMode;\n highSeverityActions: string[];\n typeToConfirmActions: string[];\n undoWindowSeconds: number;\n relativeThresholdHours: number;\n canNavigateBack: boolean;\n}\n\n/**\n * The house defaults for the fields the shell carries: the platform's preference-defaults.ts, mirrored in\n * decisions-schema.ts (DEFAULT_PATTERN_DECISIONS); a test keeps the three equal.\n */\nconst HOUSE_DEFAULTS: ResolvedPreferences = {\n validationTiming: \"onBlur\",\n formActions: { align: \"end\", placement: \"auto\" },\n itemsPerPage: 25,\n paginationStyle: \"pagination\",\n tableToCardsBreakpoint: \"md\",\n emptyStyle: \"illustration-cta\",\n loadingStyle: \"skeleton\",\n destructiveMode: \"dialog\",\n highSeverityActions: [\"delete_account\", \"remove_team_member\"],\n typeToConfirmActions: [\"delete_account\"],\n undoWindowSeconds: 5,\n relativeThresholdHours: HOUSE_RELATIVE_THRESHOLD_HOURS,\n canNavigateBack: true,\n};\nexport const PREFERENCE_HOUSE_DEFAULTS: Readonly<ResolvedPreferences> = Object.freeze(HOUSE_DEFAULTS);\n\n/**\n * For app code: every preference in force — the shell's value, else the house default — so a page never writes a\n * fallback of its own. Round 21 (run 58): with every field optional, TypeScript made the builder write\n * `const { itemsPerPage = 20 } = usePreferences()`, a second copy of the preference it then edited by hand when the\n * rule changed. Paged lists use `usePagination`, which reads the page size itself.\n */\nexport function usePreferences(): ResolvedPreferences {\n const raw = useShellPreferences();\n return useMemo(() => resolvePreferences(raw), [raw]);\n}\n\n/** The shell's values over the house defaults; a field the shell leaves undefined keeps its default. */\nexport function resolvePreferences(raw: AppShellPreferences): ResolvedPreferences {\n const d = PREFERENCE_HOUSE_DEFAULTS;\n const out: ResolvedPreferences = { ...d, formActions: { ...d.formActions }, highSeverityActions: [...d.highSeverityActions], typeToConfirmActions: [...d.typeToConfirmActions] };\n for (const [key, value] of Object.entries(raw) as Array<[keyof AppShellPreferences, unknown]>) {\n if (value === undefined) continue;\n if (key === \"formActions\") {\n const actions = value as AppShellPreferences[\"formActions\"];\n if (actions?.align !== undefined) out.formActions.align = actions.align;\n if (actions?.placement !== undefined) out.formActions.placement = actions.placement;\n continue;\n }\n (out as unknown as Record<string, unknown>)[key] = value;\n }\n return out;\n}\n\n/**\n * For components: only what the shell passed, or an empty object outside any shell — a component with no prop takes\n * the shell's value, and a bare component keeps the default it always had.\n */\nexport function useShellPreferences(): AppShellPreferences {\n return useContext(PreferencesContext) ?? EMPTY;\n}\n\nconst EMPTY: AppShellPreferences = Object.freeze({});\n\n/**\n * \"Remove range\" → \"remove_range\": the key the high-severity and type-to-confirm lists use. The engine's `actionKey`\n * (platform/src/lib/destructive-mode.ts) is the same rule for compliance; a platform test keeps the two identical.\n */\nexport function preferenceActionKey(label: string): string {\n return label.trim().toLowerCase().replace(/[^a-z0-9]+/g, \"_\").replace(/^_|_$/g, \"\");\n}\n"]}
|