@kznlabs/labsui 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/index.js +267 -56
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4504,14 +4504,14 @@ export function RolePicker() {
|
|
|
4504
4504
|
placeholder="Add roles…"
|
|
4505
4505
|
/>
|
|
4506
4506
|
);
|
|
4507
|
-
}` }], api: { entries: [{ kind: "component", name: "Combobox", props: [{ name: "options", type: "ComboboxOption[]", required: true, description: "Choices; filtered as the user types." }, { name: "aria-describedby", type: "string", required: false, description: "Ids of hint or error text; Field fills it in." }, { name: "aria-invalid", type: "boolean", required: false, description: "Error styling; Field sets it from `error`." }, { name: "aria-label", type: "string", required: false, description: "Accessible name when there is no visible label." }, { name: "defaultValue", type: "string | string[]", required: false, description: "Value, or values when `multiple`, at first render (uncontrolled)." }, { name: "disabled", type: "boolean", required: false, description: "Blocks typing and opening; the value isn't submitted." }, { name: "emptyText", type: "ReactNode", required: false, description: "Shown in the list when nothing matches." }, { name: "id", type: "string", required: false, description: "Id of the input; Field fills it in." }, { name: "multiple", type: "boolean", required: false, description: "Picks stay open and show as removable tags; Backspace removes the last one." }, { name: "name", type: "string", required: false, description: "Form field name: one entry per picked value." }, { name: "onValueChange", type: "((value: string) => void) | ((value: string[]) => void)", required: false, description: "Called with the picked value, or every picked value when `multiple`." }, { name: "placeholder", type: "string", required: false, description: "Field text when nothing is picked." }, { name: "required", type: "boolean", required: false, description: "Form submit needs a value." }, { name: "value", type: "string | string[]", required: false, description: "Controlled value, or values when `multiple`; pair with `onValueChange`." }], description: "Select you can type into: the input filters the list, Up and Down move, Enter picks, Esc closes.\nSingle shows the pick in the input; `multiple` shows picks as tags and keeps the list open." }], types: { ComboboxOption: "{ value: string; label: string; icon?: ReactNode; keywords?: string[]; disabled?: boolean; }" } }, dependencies: ["lucide-react@1.63.0", "motion@14.7.1"], registryDependencies: ["https://kznlabs.github.io/labsUI/r/field.json", "https://kznlabs.github.io/labsUI/r/form-value.json", "https://kznlabs.github.io/labsUI/r/list.json", "https://kznlabs.github.io/labsUI/r/platform.json", "https://kznlabs.github.io/labsUI/r/tag-input.json", "https://kznlabs.github.io/labsUI/r/use-anchor.json", "https://kznlabs.github.io/labsUI/r/use-controllable-state.json", "https://kznlabs.github.io/labsUI/r/use-dismiss.json", "https://kznlabs.github.io/labsUI/r/utils.json"], files: [{ path: "components/ui/combobox.tsx", type: "registry:ui", content: `"use client";
|
|
4507
|
+
}` }], api: { entries: [{ kind: "component", name: "Combobox", props: [{ name: "options", type: "ComboboxOption[]", required: true, description: "Choices; filtered as the user types." }, { name: "aria-describedby", type: "string", required: false, description: "Ids of hint or error text; Field fills it in." }, { name: "aria-invalid", type: "boolean", required: false, description: "Error styling; Field sets it from `error`." }, { name: "aria-label", type: "string", required: false, description: "Accessible name when there is no visible label." }, { name: "defaultValue", type: "string | string[]", required: false, description: "Value, or values when `multiple`, at first render (uncontrolled)." }, { name: "disabled", type: "boolean", required: false, description: "Blocks typing and opening; the value isn't submitted." }, { name: "emptyText", type: "ReactNode", required: false, description: "Shown in the list when nothing matches." }, { name: "id", type: "string", required: false, description: "Id of the input; Field fills it in." }, { name: "multiple", type: "boolean", required: false, description: "Picks stay open and show as removable tags; Backspace removes the last one, ← walks onto them." }, { name: "name", type: "string", required: false, description: "Form field name: one entry per picked value." }, { name: "onValueChange", type: "((value: string) => void) | ((value: string[]) => void)", required: false, description: "Called with the picked value, or every picked value when `multiple`." }, { name: "placeholder", type: "string", required: false, description: "Field text when nothing is picked." }, { name: "required", type: "boolean", required: false, description: "Form submit needs a value." }, { name: "value", type: "string | string[]", required: false, description: "Controlled value, or values when `multiple`; pair with `onValueChange`." }], description: "Select you can type into: the input filters the list, Up and Down move, Enter picks, Esc closes.\nSingle shows the pick in the input; `multiple` shows picks as tags and keeps the list open." }], types: { ComboboxOption: "{ value: string; label: string; icon?: ReactNode; keywords?: string[]; disabled?: boolean; }" } }, dependencies: ["lucide-react@1.63.0", "motion@14.7.1"], registryDependencies: ["https://kznlabs.github.io/labsUI/r/field.json", "https://kznlabs.github.io/labsUI/r/form-value.json", "https://kznlabs.github.io/labsUI/r/list.json", "https://kznlabs.github.io/labsUI/r/platform.json", "https://kznlabs.github.io/labsUI/r/tag-input.json", "https://kznlabs.github.io/labsUI/r/use-anchor.json", "https://kznlabs.github.io/labsUI/r/use-controllable-state.json", "https://kznlabs.github.io/labsUI/r/use-dismiss.json", "https://kznlabs.github.io/labsUI/r/utils.json"], files: [{ path: "components/ui/combobox.tsx", type: "registry:ui", content: `"use client";
|
|
4508
4508
|
|
|
4509
4509
|
import { Check, ChevronsUpDown } from "lucide-react";
|
|
4510
4510
|
import { AnimatePresence, motion } from "motion/react";
|
|
4511
4511
|
import { type KeyboardEvent, type ReactNode, useEffect, useId, useRef, useState } from "react";
|
|
4512
4512
|
import { createPortal } from "react-dom";
|
|
4513
4513
|
import { useFieldControl } from "@/components/ui/field";
|
|
4514
|
-
import { Tag, tagFieldClass } from "@/components/ui/tag-input";
|
|
4514
|
+
import { Tag, tagFieldClass, useTagKeys } from "@/components/ui/tag-input";
|
|
4515
4515
|
import { FormValue, useFormReset } from "@/lib/form-value";
|
|
4516
4516
|
import { listKeyTarget, scrollIntoList } from "@/lib/list";
|
|
4517
4517
|
import { useMounted } from "@/lib/platform";
|
|
@@ -4560,7 +4560,7 @@ type BaseProps = {
|
|
|
4560
4560
|
type ComboboxProps = BaseProps &
|
|
4561
4561
|
(
|
|
4562
4562
|
| {
|
|
4563
|
-
/** Picks stay open and show as removable tags; Backspace removes the last one. */
|
|
4563
|
+
/** Picks stay open and show as removable tags; Backspace removes the last one, ← walks onto them. */
|
|
4564
4564
|
multiple?: false;
|
|
4565
4565
|
/** Controlled value, or values when \`multiple\`; pair with \`onValueChange\`. */
|
|
4566
4566
|
value?: string;
|
|
@@ -4658,6 +4658,12 @@ export function Combobox(allProps: ComboboxProps) {
|
|
|
4658
4658
|
}
|
|
4659
4659
|
};
|
|
4660
4660
|
|
|
4661
|
+
const keys = useTagKeys(
|
|
4662
|
+
selected.map((option) => option.value),
|
|
4663
|
+
input,
|
|
4664
|
+
(value) => commit(values.filter((other) => other !== value)),
|
|
4665
|
+
);
|
|
4666
|
+
|
|
4661
4667
|
const show = () => {
|
|
4662
4668
|
if (open || disabled) return;
|
|
4663
4669
|
setActive(values[0]);
|
|
@@ -4678,6 +4684,8 @@ export function Combobox(allProps: ComboboxProps) {
|
|
|
4678
4684
|
});
|
|
4679
4685
|
|
|
4680
4686
|
const onKey = (event: KeyboardEvent<HTMLInputElement>) => {
|
|
4687
|
+
if (multiple && !query && keys.fromInput(event)) return setOpen(false);
|
|
4688
|
+
|
|
4681
4689
|
const i = enabled.findIndex((option) => option.value === current);
|
|
4682
4690
|
const step = listKeyTarget(enabled, i, event, {
|
|
4683
4691
|
orientation: "vertical",
|
|
@@ -4718,20 +4726,28 @@ export function Combobox(allProps: ComboboxProps) {
|
|
|
4718
4726
|
|
|
4719
4727
|
return (
|
|
4720
4728
|
<>
|
|
4721
|
-
{/* biome-ignore lint/a11y/noStaticElementInteractions:
|
|
4722
|
-
{/* biome-ignore lint/a11y/useKeyWithClickEvents: same as above */}
|
|
4729
|
+
{/* biome-ignore lint/a11y/noStaticElementInteractions: field wrapper: clicks go to the input, keys from the tags bubble here */}
|
|
4723
4730
|
<div
|
|
4724
4731
|
ref={box}
|
|
4725
4732
|
onClick={() => {
|
|
4726
4733
|
input.current?.focus();
|
|
4727
4734
|
show();
|
|
4728
4735
|
}}
|
|
4736
|
+
onKeyDown={keys.onKeyDown}
|
|
4729
4737
|
className={cn(tagFieldClass, !multiple && "h-9 flex-nowrap py-0 pl-3", "pr-2", className)}
|
|
4730
4738
|
>
|
|
4731
4739
|
{multiple && (
|
|
4732
4740
|
<AnimatePresence initial={false} mode="popLayout">
|
|
4733
4741
|
{selected.map((option) => (
|
|
4734
|
-
<Tag
|
|
4742
|
+
<Tag
|
|
4743
|
+
key={option.value}
|
|
4744
|
+
disabled={disabled}
|
|
4745
|
+
removeRef={keys.tagRef(option.value)}
|
|
4746
|
+
onRemove={() => {
|
|
4747
|
+
keys.removed();
|
|
4748
|
+
pick(option.value);
|
|
4749
|
+
}}
|
|
4750
|
+
>
|
|
4735
4751
|
{option.label}
|
|
4736
4752
|
</Tag>
|
|
4737
4753
|
))}
|
|
@@ -7611,7 +7627,7 @@ export function tabbables(root: HTMLElement | null) {
|
|
|
7611
7627
|
return element === (group.find((radio) => radio.checked) ?? group[0]);
|
|
7612
7628
|
});
|
|
7613
7629
|
}
|
|
7614
|
-
` }] }, "form-value": { $schema: "https://kznlabs.github.io/labsUI/r/registry-item.schema.json", name: "form-value", type: "registry:lib", description: "Submits a custom control's value and takes part in native validation, which a hidden input\ncan't: an empty `required` value blocks submit, shows the browser's message and focuses `anchor`.", api: { entries: [{ kind: "component", name: "FormValue", props: [{ name: "anchor", type: "RefObject<HTMLElement | null>", required: true, description: "The visible control that gets focus when the value is invalid." }, { name: "value", type: "string", required: true, description: 'The value to submit, "" when nothing is picked.' }, { name: "disabled", type: "boolean", required: false, description: "Skips validation and leaves the value out of the submit, like a disabled input." }, { name: "name", type: "string", required: false, description: "Form field name; without it the value only takes part in validation." }, { name: "onInvalid", type: "() => void", required: false, description: "Called when a submit finds the value invalid." }, { name: "required", type: "boolean", required: false, description: "An empty value blocks submit." }], description: "Submits a custom control's value and takes part in native validation, which a hidden input\ncan't: an empty `required` value blocks submit, shows the browser's message and focuses `anchor`." }, { kind: "function", name: "useFormReset", signature: "useFormReset(field: RefObject<HTMLElement | null>, onReset: () => void) => void", description: "Calls `onReset` when the control's form resets: a reset button, or React after a `<form action>`\nsucceeds. Custom state goes back to its default there, as a native control's does." }], types: {} }, dependencies: [], registryDependencies: [], files: [{ path: "lib/form-value.tsx", type: "registry:lib", content: `import { type RefObject, useEffect, useEffectEvent } from "react";
|
|
7630
|
+
` }] }, "form-value": { $schema: "https://kznlabs.github.io/labsUI/r/registry-item.schema.json", name: "form-value", type: "registry:lib", description: "Submits a custom control's value and takes part in native validation, which a hidden input\ncan't: an empty `required` value blocks submit, shows the browser's message and focuses `anchor`.", api: { entries: [{ kind: "component", name: "FormValue", props: [{ name: "anchor", type: "RefObject<HTMLElement | null>", required: true, description: "The visible control that gets focus when the value is invalid." }, { name: "value", type: "string", required: true, description: 'The value to submit, "" when nothing is picked.' }, { name: "disabled", type: "boolean", required: false, description: "Skips validation and leaves the value out of the submit, like a disabled input." }, { name: "name", type: "string", required: false, description: "Form field name; without it the value only takes part in validation." }, { name: "onInvalid", type: "() => void", required: false, description: "Called when a submit finds the value invalid." }, { name: "required", type: "boolean", required: false, description: "An empty value blocks submit." }], description: "Submits a custom control's value and takes part in native validation, which a hidden input\ncan't: an empty `required` value blocks submit, shows the browser's message and focuses `anchor`." }, { kind: "function", name: "useFormReset", signature: "useFormReset(field: RefObject<HTMLElement | null>, onReset: () => void) => void", description: "Calls `onReset` when the control's form resets: a reset button, or React after a `<form action>`\nsucceeds. Custom state goes back to its default there, as a native control's does; a controlled\ncontrol reports the default through its `onValueChange`, so the parent's state resets too." }], types: {} }, dependencies: [], registryDependencies: [], files: [{ path: "lib/form-value.tsx", type: "registry:lib", content: `import { type RefObject, useEffect, useEffectEvent } from "react";
|
|
7615
7631
|
|
|
7616
7632
|
type FormValueProps = {
|
|
7617
7633
|
/** Form field name; without it the value only takes part in validation. */
|
|
@@ -7653,7 +7669,8 @@ export function FormValue({ name, value, required, disabled, anchor, onInvalid }
|
|
|
7653
7669
|
|
|
7654
7670
|
/**
|
|
7655
7671
|
* Calls \`onReset\` when the control's form resets: a reset button, or React after a \`<form action>\`
|
|
7656
|
-
* succeeds. Custom state goes back to its default there, as a native control's does
|
|
7672
|
+
* succeeds. Custom state goes back to its default there, as a native control's does; a controlled
|
|
7673
|
+
* control reports the default through its \`onValueChange\`, so the parent's state resets too.
|
|
7657
7674
|
*/
|
|
7658
7675
|
export function useFormReset(field: RefObject<HTMLElement | null>, onReset: () => void) {
|
|
7659
7676
|
const reset = useEffectEvent(onReset);
|
|
@@ -15423,7 +15440,7 @@ export function TabsContent({
|
|
|
15423
15440
|
</motion.div>
|
|
15424
15441
|
);
|
|
15425
15442
|
}
|
|
15426
|
-
` }] }, "tag-input": { $schema: "https://kznlabs.github.io/labsUI/r/registry-item.schema.json", name: "tag-input", type: "registry:ui", title: "Tag Input", description: "Free-form tags: Enter or a separator adds, Backspace removes the last, pasting a list adds them all. Duplicates, a max and a validate function keep bad tags in the input. Submits one entry per tag; required needs one.", docs: "https://kznlabs.github.io/labsUI/components/tag-input", usage: "<TagInput value={tags} onValueChange={setTags} max={5} validate={(t) => t.length <= 24} />", examples: [{ name: "clip-tags.tsx", code: `"use client";
|
|
15443
|
+
` }] }, "tag-input": { $schema: "https://kznlabs.github.io/labsUI/r/registry-item.schema.json", name: "tag-input", type: "registry:ui", title: "Tag Input", description: "Free-form tags: Enter or a separator adds, Backspace removes the last, ← walks onto the tags and Delete removes one, pasting a list adds them all. Duplicates, a max and a validate function keep bad tags in the input. Submits one entry per tag; required needs one.", docs: "https://kznlabs.github.io/labsUI/components/tag-input", usage: "<TagInput value={tags} onValueChange={setTags} max={5} validate={(t) => t.length <= 24} />", examples: [{ name: "clip-tags.tsx", code: `"use client";
|
|
15427
15444
|
|
|
15428
15445
|
import { useState } from "react";
|
|
15429
15446
|
import { Field } from "@/components/ui/field";
|
|
@@ -15443,11 +15460,25 @@ export function ClipTags() {
|
|
|
15443
15460
|
/>
|
|
15444
15461
|
</Field>
|
|
15445
15462
|
);
|
|
15446
|
-
}` }], api: { entries: [{ kind: "component", name: "Tag", props: [{ name: "children", type: "ReactNode", required: true, description: "Tag text." }, { name: "disabled", type: "boolean", required: false, description: "Hides the remove button." }, { name: "onRemove", type: "() => void", required: false, description: 'Shows a remove button; its accessible name is "Remove <children>".' }
|
|
15463
|
+
}` }], api: { entries: [{ kind: "component", name: "Tag", props: [{ name: "children", type: "ReactNode", required: true, description: "Tag text." }, { name: "disabled", type: "boolean", required: false, description: "Hides the remove button." }, { name: "onRemove", type: "() => void", required: false, description: 'Shows a remove button; its accessible name is "Remove <children>".' }, { name: "removeRef", type: "Ref<HTMLButtonElement>", required: false, description: "The remove button, for `useTagKeys`." }], description: 'Removable chip. Springs in and out when rendered inside AnimatePresence (`mode="popLayout"`).' }, { kind: "function", name: "useTagKeys", signature: `useTagKeys(tags: string[], input: RefObject<HTMLInputElement | null>, remove: (tag: string) => void) => {
|
|
15464
|
+
tagRef: (tag: string) => (element: HTMLButtonElement | null) => void;
|
|
15465
|
+
fromInput: (event: KeyboardEvent<HTMLInputElement>) => boolean;
|
|
15466
|
+
onKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
|
|
15467
|
+
removed: () => void;
|
|
15468
|
+
}`, description: "Keyboard reach for a field's tags, which stay out of the Tab order: ← from the empty input walks\nonto them, ← → move, Backspace, Delete, Enter or Space removes the focused one and Esc returns to\nthe input. Put `onKeyDown` on the field, `tagRef(tag)` on each Tag's `removeRef`, and call\n`fromInput` first in the input's keydown." }, { kind: "component", name: "TagInput", props: [{ name: "defaultValue", type: "string[]", required: false, default: "[]", description: "Tags at first render (uncontrolled)." }, { name: "max", type: "number", required: false, description: "Most tags allowed; typing stops at the limit." }, { name: "onValueChange", type: "(tags: string[]) => void", required: false, description: "Called with every tag after an add or remove." }, { name: "separators", type: "string[]", required: false, default: '[","]', description: "Keys that commit the typed text, besides Enter. Pasted text is split on these too." }, { name: "validate", type: "(tag: string) => boolean", required: false, description: "Return false to reject a tag (it stays in the input). Runs after trimming." }, { name: "value", type: "string[]", required: false, description: "Controlled tags; pair with `onValueChange`." }], extends: "<input>", description: "Free-form tags: type and press Enter or a separator; paste a list to add many; Backspace in an\nempty input removes the last tag, ← walks onto the tags (Backspace or Delete removes one). `name`\nsubmits one value per tag; `required` needs at least one." }], types: {} }, dependencies: ["lucide-react@1.63.0", "motion@14.7.1"], registryDependencies: ["https://kznlabs.github.io/labsUI/r/field.json", "https://kznlabs.github.io/labsUI/r/form-value.json", "https://kznlabs.github.io/labsUI/r/use-controllable-state.json", "https://kznlabs.github.io/labsUI/r/utils.json"], files: [{ path: "components/ui/tag-input.tsx", type: "registry:ui", content: `"use client";
|
|
15447
15469
|
|
|
15448
15470
|
import { X } from "lucide-react";
|
|
15449
15471
|
import { AnimatePresence, motion } from "motion/react";
|
|
15450
|
-
import {
|
|
15472
|
+
import {
|
|
15473
|
+
type ComponentProps,
|
|
15474
|
+
type KeyboardEvent,
|
|
15475
|
+
type ReactNode,
|
|
15476
|
+
type Ref,
|
|
15477
|
+
type RefObject,
|
|
15478
|
+
useEffect,
|
|
15479
|
+
useRef,
|
|
15480
|
+
useState,
|
|
15481
|
+
} from "react";
|
|
15451
15482
|
import { useFieldControl } from "@/components/ui/field";
|
|
15452
15483
|
import { FormValue, useFormReset } from "@/lib/form-value";
|
|
15453
15484
|
import { useControllableState } from "@/lib/use-controllable-state";
|
|
@@ -15461,6 +15492,7 @@ export const tagFieldClass =
|
|
|
15461
15492
|
export function Tag({
|
|
15462
15493
|
children,
|
|
15463
15494
|
onRemove,
|
|
15495
|
+
removeRef,
|
|
15464
15496
|
disabled,
|
|
15465
15497
|
className,
|
|
15466
15498
|
}: {
|
|
@@ -15468,6 +15500,8 @@ export function Tag({
|
|
|
15468
15500
|
children: ReactNode;
|
|
15469
15501
|
/** Shows a remove button; its accessible name is "Remove <children>". */
|
|
15470
15502
|
onRemove?: () => void;
|
|
15503
|
+
/** The remove button, for \`useTagKeys\`. */
|
|
15504
|
+
removeRef?: Ref<HTMLButtonElement>;
|
|
15471
15505
|
/** Hides the remove button. */
|
|
15472
15506
|
disabled?: boolean;
|
|
15473
15507
|
className?: string;
|
|
@@ -15489,6 +15523,7 @@ export function Tag({
|
|
|
15489
15523
|
|
|
15490
15524
|
{onRemove && (
|
|
15491
15525
|
<button
|
|
15526
|
+
ref={removeRef}
|
|
15492
15527
|
type="button"
|
|
15493
15528
|
tabIndex={-1}
|
|
15494
15529
|
disabled={disabled}
|
|
@@ -15497,7 +15532,7 @@ export function Tag({
|
|
|
15497
15532
|
onRemove();
|
|
15498
15533
|
}}
|
|
15499
15534
|
aria-label={typeof children === "string" ? \`Remove \${children}\` : "Remove"}
|
|
15500
|
-
className="grid size-5 shrink-0 place-items-center rounded text-muted-foreground transition-colors hover:bg-foreground/10 hover:text-foreground"
|
|
15535
|
+
className="grid size-5 shrink-0 place-items-center rounded text-muted-foreground outline-none transition-colors hover:bg-foreground/10 hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50"
|
|
15501
15536
|
>
|
|
15502
15537
|
<X className="size-3" aria-hidden="true" />
|
|
15503
15538
|
</button>
|
|
@@ -15506,6 +15541,70 @@ export function Tag({
|
|
|
15506
15541
|
);
|
|
15507
15542
|
}
|
|
15508
15543
|
|
|
15544
|
+
/**
|
|
15545
|
+
* Keyboard reach for a field's tags, which stay out of the Tab order: ← from the empty input walks
|
|
15546
|
+
* onto them, ← → move, Backspace, Delete, Enter or Space removes the focused one and Esc returns to
|
|
15547
|
+
* the input. Put \`onKeyDown\` on the field, \`tagRef(tag)\` on each Tag's \`removeRef\`, and call
|
|
15548
|
+
* \`fromInput\` first in the input's keydown.
|
|
15549
|
+
*/
|
|
15550
|
+
export function useTagKeys(
|
|
15551
|
+
tags: string[],
|
|
15552
|
+
input: RefObject<HTMLInputElement | null>,
|
|
15553
|
+
remove: (tag: string) => void,
|
|
15554
|
+
) {
|
|
15555
|
+
const buttons = useRef(new Map<string, HTMLButtonElement>());
|
|
15556
|
+
// The tag to focus once a removal renders; "" = the input.
|
|
15557
|
+
const after = useRef<string | null>(null);
|
|
15558
|
+
const focus = (tag: string | undefined) =>
|
|
15559
|
+
(tag ? buttons.current.get(tag) : input.current)?.focus();
|
|
15560
|
+
|
|
15561
|
+
useEffect(() => {
|
|
15562
|
+
const target = after.current;
|
|
15563
|
+
|
|
15564
|
+
if (target === null || !tags) return;
|
|
15565
|
+
after.current = null;
|
|
15566
|
+
(target ? buttons.current.get(target) : input.current)?.focus();
|
|
15567
|
+
}, [tags, input]);
|
|
15568
|
+
|
|
15569
|
+
return {
|
|
15570
|
+
tagRef: (tag: string) => (element: HTMLButtonElement | null) => {
|
|
15571
|
+
if (element) buttons.current.set(tag, element);
|
|
15572
|
+
else buttons.current.delete(tag);
|
|
15573
|
+
},
|
|
15574
|
+
fromInput: (event: KeyboardEvent<HTMLInputElement>) => {
|
|
15575
|
+
if (event.key !== "ArrowLeft" || event.currentTarget.value || !tags.length) return false;
|
|
15576
|
+
event.preventDefault();
|
|
15577
|
+
focus(tags.at(-1));
|
|
15578
|
+
|
|
15579
|
+
return true;
|
|
15580
|
+
},
|
|
15581
|
+
onKeyDown: (event: KeyboardEvent<HTMLElement>) => {
|
|
15582
|
+
const at = tags.findIndex((tag) => buttons.current.get(tag) === event.target);
|
|
15583
|
+
const tag = tags[at];
|
|
15584
|
+
|
|
15585
|
+
if (tag === undefined) return;
|
|
15586
|
+
|
|
15587
|
+
if (event.key === "ArrowLeft") focus(tags[Math.max(at - 1, 0)]);
|
|
15588
|
+
else if (event.key === "ArrowRight") focus(tags[at + 1]);
|
|
15589
|
+
else if (event.key === "Escape") focus(undefined);
|
|
15590
|
+
else if (["Backspace", "Delete", "Enter", " "].includes(event.key)) {
|
|
15591
|
+
const rest = tags.filter((other) => other !== tag);
|
|
15592
|
+
|
|
15593
|
+
after.current =
|
|
15594
|
+
(event.key === "Backspace" ? (rest[at - 1] ?? rest[at]) : (rest[at] ?? rest[at - 1])) ??
|
|
15595
|
+
"";
|
|
15596
|
+
remove(tag);
|
|
15597
|
+
} else return;
|
|
15598
|
+
|
|
15599
|
+
event.preventDefault();
|
|
15600
|
+
},
|
|
15601
|
+
/** A pointer removal: focus goes back to the input. */
|
|
15602
|
+
removed: () => {
|
|
15603
|
+
after.current = "";
|
|
15604
|
+
},
|
|
15605
|
+
};
|
|
15606
|
+
}
|
|
15607
|
+
|
|
15509
15608
|
type TagInputProps = Omit<
|
|
15510
15609
|
ComponentProps<"input">,
|
|
15511
15610
|
"value" | "defaultValue" | "onChange" | "type" | "size"
|
|
@@ -15526,7 +15625,8 @@ type TagInputProps = Omit<
|
|
|
15526
15625
|
|
|
15527
15626
|
/**
|
|
15528
15627
|
* Free-form tags: type and press Enter or a separator; paste a list to add many; Backspace in an
|
|
15529
|
-
* empty input removes the last tag
|
|
15628
|
+
* empty input removes the last tag, ← walks onto the tags (Backspace or Delete removes one). \`name\`
|
|
15629
|
+
* submits one value per tag; \`required\` needs at least one.
|
|
15530
15630
|
*/
|
|
15531
15631
|
export function TagInput({
|
|
15532
15632
|
value: valueProp,
|
|
@@ -15556,6 +15656,7 @@ export function TagInput({
|
|
|
15556
15656
|
});
|
|
15557
15657
|
|
|
15558
15658
|
const full = max !== undefined && tags.length >= max;
|
|
15659
|
+
const keys = useTagKeys(tags, input, (tag) => set(tags.filter((other) => other !== tag)));
|
|
15559
15660
|
|
|
15560
15661
|
const add = (raw: string[]) => {
|
|
15561
15662
|
const next = [...tags];
|
|
@@ -15586,15 +15687,22 @@ export function TagInput({
|
|
|
15586
15687
|
);
|
|
15587
15688
|
|
|
15588
15689
|
return (
|
|
15589
|
-
// biome-ignore lint/a11y/noStaticElementInteractions:
|
|
15590
|
-
|
|
15591
|
-
|
|
15690
|
+
// biome-ignore lint/a11y/noStaticElementInteractions: field wrapper: clicks go to the input, keys from the tags bubble here
|
|
15691
|
+
<div
|
|
15692
|
+
className={cn(tagFieldClass, className)}
|
|
15693
|
+
onClick={() => input.current?.focus()}
|
|
15694
|
+
onKeyDown={keys.onKeyDown}
|
|
15695
|
+
>
|
|
15592
15696
|
<AnimatePresence initial={false} mode="popLayout">
|
|
15593
15697
|
{tags.map((tag) => (
|
|
15594
15698
|
<Tag
|
|
15595
15699
|
key={tag}
|
|
15596
15700
|
disabled={props.disabled}
|
|
15597
|
-
|
|
15701
|
+
removeRef={keys.tagRef(tag)}
|
|
15702
|
+
onRemove={() => {
|
|
15703
|
+
keys.removed();
|
|
15704
|
+
set(tags.filter((other) => other !== tag));
|
|
15705
|
+
}}
|
|
15598
15706
|
>
|
|
15599
15707
|
{tag}
|
|
15600
15708
|
</Tag>
|
|
@@ -15615,7 +15723,7 @@ export function TagInput({
|
|
|
15615
15723
|
onChange={(event) => setDraft(event.target.value)}
|
|
15616
15724
|
onKeyDown={(event) => {
|
|
15617
15725
|
onKeyDown?.(event);
|
|
15618
|
-
if (event.defaultPrevented) return;
|
|
15726
|
+
if (event.defaultPrevented || keys.fromInput(event)) return;
|
|
15619
15727
|
|
|
15620
15728
|
if (event.key === "Enter" || separators.includes(event.key)) {
|
|
15621
15729
|
// Enter with an empty draft still submits the form.
|
|
@@ -16463,13 +16571,15 @@ export function TimelineItem({
|
|
|
16463
16571
|
</li>
|
|
16464
16572
|
);
|
|
16465
16573
|
}
|
|
16466
|
-
` }] }, toast: { $schema: "https://kznlabs.github.io/labsUI/r/registry-item.schema.json", name: "toast", type: "registry:ui", title: "Toast", description: "Stacked notifications. Hover to expand, swipe to dismiss, timers pause on hover.", docs: "https://kznlabs.github.io/labsUI/components/toast", mount: "<Toaster />", usage: 'toast.success("Saved", { description: "All changes synced", action: { label: "Undo", onClick } })', examples: [{ name: "save.tsx", code: `import { toast } from "@/components/ui/toast";
|
|
16574
|
+
` }] }, toast: { $schema: "https://kznlabs.github.io/labsUI/r/registry-item.schema.json", name: "toast", type: "registry:ui", title: "Toast", description: "Stacked notifications. Hover to expand, swipe to dismiss, timers pause on hover or focus, a toast with an action stays until it's used or dismissed, and F8 jumps to the newest toast from the keyboard.", docs: "https://kznlabs.github.io/labsUI/components/toast", mount: "<Toaster />", usage: 'toast.success("Saved", { description: "All changes synced", action: { label: "Undo", onClick } })', examples: [{ name: "save.tsx", code: `import { toast } from "@/components/ui/toast";
|
|
16467
16575
|
export function notifySaved(undo: () => void) {
|
|
16468
16576
|
toast.success("Changes saved", {
|
|
16469
16577
|
description: "All changes synced",
|
|
16470
16578
|
action: { label: "Undo", onClick: undo },
|
|
16471
16579
|
});
|
|
16472
|
-
}` }], api: { entries: [{ kind: "function", name: "toast", signature: 'toast(title: ReactNode, opts?: Partial<Omit<ToastData, "id" | "title">>) => number', description: '`toast("Saved")`, `toast.success(title, { description, action, duration })`, `toast.loading(title)`, `toast.promise(p, { loading, success, error })`, `toast.dismiss(id?)`.' }, { kind: "component", name: "Toaster", props: [
|
|
16580
|
+
}` }], api: { entries: [{ kind: "function", name: "toast", signature: 'toast(title: ReactNode, opts?: Partial<Omit<ToastData, "id" | "title">>) => number', description: '`toast("Saved")`, `toast.success(title, { description, action, duration })`, `toast.loading(title)`, `toast.promise(p, { loading, success, error })`, `toast.dismiss(id?)`.' }, { kind: "component", name: "Toaster", props: [{ name: "actionDuration", type: "number", required: false, default: "Number.POSITIVE_INFINITY", description: "ms before a toast with an action closes; Infinity by default, so it stays until used or dismissed." }, { name: "duration", type: "number", required: false, default: "4000", description: "ms before a toast without an action closes; a toast's own `duration` wins." }], description: `Mount once (root layout). Stacked toasts: hover, focus or a tap expands, swipe dismisses. F8
|
|
16581
|
+
jumps to the newest toast's buttons (timers pause while focus is there); Esc, the action or
|
|
16582
|
+
Dismiss sends focus back.` }], types: { ToastData: "{ id: number; title: ReactNode; description?: ReactNode; variant: ToastVariant; duration?: number; action?: { label: string; onClick: () => void }; }" } }, dependencies: ["lucide-react@1.63.0", "motion@14.7.1"], registryDependencies: ["https://kznlabs.github.io/labsUI/r/focus.json", "https://kznlabs.github.io/labsUI/r/use-dismiss.json", "https://kznlabs.github.io/labsUI/r/use-hotkey.json", "https://kznlabs.github.io/labsUI/r/utils.json"], files: [{ path: "components/ui/toast.tsx", type: "registry:ui", content: `"use client";
|
|
16473
16583
|
|
|
16474
16584
|
import { CircleAlert, CircleCheck, Info, Loader2, X } from "lucide-react";
|
|
16475
16585
|
import { AnimatePresence, animate, motion, type PanInfo, useMotionValue } from "motion/react";
|
|
@@ -16481,7 +16591,9 @@ import {
|
|
|
16481
16591
|
useState,
|
|
16482
16592
|
useSyncExternalStore,
|
|
16483
16593
|
} from "react";
|
|
16594
|
+
import { tabbables } from "@/lib/focus";
|
|
16484
16595
|
import { useDismiss } from "@/lib/use-dismiss";
|
|
16596
|
+
import { useHotkey } from "@/lib/use-hotkey";
|
|
16485
16597
|
import { cn, material, spring } from "@/lib/utils";
|
|
16486
16598
|
|
|
16487
16599
|
/* ---------- store (module-level, no provider needed) ---------- */
|
|
@@ -16492,8 +16604,8 @@ export type ToastData = {
|
|
|
16492
16604
|
title: ReactNode;
|
|
16493
16605
|
description?: ReactNode;
|
|
16494
16606
|
variant: ToastVariant;
|
|
16495
|
-
/** ms; Infinity = sticky. */
|
|
16496
|
-
duration
|
|
16607
|
+
/** ms; Infinity = sticky. Defaults to the Toaster's \`duration\` or \`actionDuration\`. */
|
|
16608
|
+
duration?: number;
|
|
16497
16609
|
action?: { label: string; onClick: () => void };
|
|
16498
16610
|
};
|
|
16499
16611
|
type ToastOptions = Partial<Omit<ToastData, "id" | "title">>;
|
|
@@ -16520,7 +16632,7 @@ const MAX = 6;
|
|
|
16520
16632
|
|
|
16521
16633
|
function create(title: ReactNode, opts: ToastOptions = {}) {
|
|
16522
16634
|
const id = ++nextId;
|
|
16523
|
-
const next: ToastData = { id, title, variant: "default",
|
|
16635
|
+
const next: ToastData = { id, title, variant: "default", ...opts };
|
|
16524
16636
|
|
|
16525
16637
|
toasts = [next, ...toasts].slice(0, MAX);
|
|
16526
16638
|
emit();
|
|
@@ -16551,7 +16663,7 @@ function promise<T>(
|
|
|
16551
16663
|
|
|
16552
16664
|
pending.then(
|
|
16553
16665
|
(value) =>
|
|
16554
|
-
update(id, { title: resolve(msgs.success, value), variant: "success", duration:
|
|
16666
|
+
update(id, { title: resolve(msgs.success, value), variant: "success", duration: undefined }),
|
|
16555
16667
|
(error) => update(id, { title: resolve(msgs.error, error), variant: "error", duration: 6000 }),
|
|
16556
16668
|
);
|
|
16557
16669
|
|
|
@@ -16600,14 +16712,57 @@ const icons = {
|
|
|
16600
16712
|
loading: <Loader2 className="size-4 animate-spin text-muted-foreground" aria-hidden="true" />,
|
|
16601
16713
|
};
|
|
16602
16714
|
|
|
16603
|
-
|
|
16604
|
-
|
|
16715
|
+
export type ToasterProps = {
|
|
16716
|
+
/** ms before a toast without an action closes; a toast's own \`duration\` wins. */
|
|
16717
|
+
duration?: number;
|
|
16718
|
+
/** ms before a toast with an action closes; Infinity by default, so it stays until used or dismissed. */
|
|
16719
|
+
actionDuration?: number;
|
|
16720
|
+
className?: string;
|
|
16721
|
+
};
|
|
16722
|
+
|
|
16723
|
+
/**
|
|
16724
|
+
* Mount once (root layout). Stacked toasts: hover, focus or a tap expands, swipe dismisses. F8
|
|
16725
|
+
* jumps to the newest toast's buttons (timers pause while focus is there); Esc, the action or
|
|
16726
|
+
* Dismiss sends focus back.
|
|
16727
|
+
*/
|
|
16728
|
+
export function Toaster({
|
|
16729
|
+
duration = 4000,
|
|
16730
|
+
actionDuration = Number.POSITIVE_INFINITY,
|
|
16731
|
+
className,
|
|
16732
|
+
}: ToasterProps) {
|
|
16605
16733
|
const items = useSyncExternalStore(
|
|
16606
16734
|
subscribe,
|
|
16607
16735
|
() => toasts,
|
|
16608
16736
|
() => EMPTY,
|
|
16609
16737
|
);
|
|
16610
16738
|
const section = useRef<HTMLElement>(null);
|
|
16739
|
+
const back = useRef<HTMLElement | null>(null);
|
|
16740
|
+
|
|
16741
|
+
useHotkey(
|
|
16742
|
+
"F8",
|
|
16743
|
+
() => {
|
|
16744
|
+
const first = tabbables(section.current)[0];
|
|
16745
|
+
|
|
16746
|
+
if (!first) return false;
|
|
16747
|
+
back.current = document.activeElement as HTMLElement | null;
|
|
16748
|
+
first.focus();
|
|
16749
|
+
},
|
|
16750
|
+
{ skipInFields: false },
|
|
16751
|
+
);
|
|
16752
|
+
|
|
16753
|
+
// The buttons unmount with their toast, so focus moves first.
|
|
16754
|
+
const leave = useCallback((from: Element) => {
|
|
16755
|
+
if (!section.current?.contains(document.activeElement)) return;
|
|
16756
|
+
|
|
16757
|
+
const toast = from.closest("li");
|
|
16758
|
+
const target = back.current?.isConnected
|
|
16759
|
+
? back.current
|
|
16760
|
+
: tabbables(section.current).find((element) => !toast?.contains(element));
|
|
16761
|
+
|
|
16762
|
+
back.current = null;
|
|
16763
|
+
target?.focus();
|
|
16764
|
+
}, []);
|
|
16765
|
+
|
|
16611
16766
|
const [expanded, setExpanded] = useState(false);
|
|
16612
16767
|
const [heights, setHeights] = useState<Record<number, number>>({});
|
|
16613
16768
|
const onHeight = useCallback(
|
|
@@ -16627,15 +16782,20 @@ export function Toaster({ className }: { className?: string }) {
|
|
|
16627
16782
|
let offset = 0;
|
|
16628
16783
|
|
|
16629
16784
|
return (
|
|
16630
|
-
// biome-ignore lint/a11y/useKeyWithClickEvents: keyboard focus already expands the stack
|
|
16631
16785
|
<section
|
|
16632
16786
|
aria-label="Notifications"
|
|
16787
|
+
aria-keyshortcuts="F8"
|
|
16633
16788
|
className={cn("fixed right-4 bottom-4 z-[100] w-[min(360px,calc(100vw-2rem))]", className)}
|
|
16634
16789
|
ref={section}
|
|
16635
16790
|
onPointerEnter={(event) => event.pointerType !== "touch" && setExpanded(true)}
|
|
16636
16791
|
onPointerLeave={(event) => event.pointerType !== "touch" && setExpanded(false)}
|
|
16637
16792
|
onClick={() => setExpanded(true)}
|
|
16638
16793
|
onFocus={() => setExpanded(true)}
|
|
16794
|
+
onKeyDown={(event) => {
|
|
16795
|
+
if (event.key !== "Escape" || !back.current) return;
|
|
16796
|
+
back.current.focus();
|
|
16797
|
+
back.current = null;
|
|
16798
|
+
}}
|
|
16639
16799
|
onBlur={(event) => {
|
|
16640
16800
|
if (!event.currentTarget.contains(event.relatedTarget)) setExpanded(false);
|
|
16641
16801
|
}}
|
|
@@ -16652,12 +16812,14 @@ export function Toaster({ className }: { className?: string }) {
|
|
|
16652
16812
|
<ToastItem
|
|
16653
16813
|
key={item.id}
|
|
16654
16814
|
toast={item}
|
|
16815
|
+
duration={item.duration ?? (item.action ? actionDuration : duration)}
|
|
16655
16816
|
index={i}
|
|
16656
16817
|
y={y}
|
|
16657
16818
|
expanded={expanded}
|
|
16658
16819
|
frontHeight={frontH}
|
|
16659
16820
|
total={items.length}
|
|
16660
16821
|
onHeight={onHeight}
|
|
16822
|
+
onLeave={leave}
|
|
16661
16823
|
/>
|
|
16662
16824
|
);
|
|
16663
16825
|
})}
|
|
@@ -16669,15 +16831,27 @@ export function Toaster({ className }: { className?: string }) {
|
|
|
16669
16831
|
|
|
16670
16832
|
type ItemProps = {
|
|
16671
16833
|
toast: ToastData;
|
|
16834
|
+
duration: number;
|
|
16672
16835
|
index: number;
|
|
16673
16836
|
y: number;
|
|
16674
16837
|
expanded: boolean;
|
|
16675
16838
|
frontHeight: number;
|
|
16676
16839
|
total: number;
|
|
16677
16840
|
onHeight: (id: number, height: number) => void;
|
|
16841
|
+
onLeave: (from: Element) => void;
|
|
16678
16842
|
};
|
|
16679
16843
|
|
|
16680
|
-
function ToastItem({
|
|
16844
|
+
function ToastItem({
|
|
16845
|
+
toast: data,
|
|
16846
|
+
duration,
|
|
16847
|
+
index,
|
|
16848
|
+
y,
|
|
16849
|
+
expanded,
|
|
16850
|
+
frontHeight,
|
|
16851
|
+
total,
|
|
16852
|
+
onHeight,
|
|
16853
|
+
onLeave,
|
|
16854
|
+
}: ItemProps) {
|
|
16681
16855
|
const inner = useRef<HTMLDivElement>(null);
|
|
16682
16856
|
const [height, setHeight] = useState(0);
|
|
16683
16857
|
const x = useMotionValue(0);
|
|
@@ -16686,7 +16860,7 @@ function ToastItem({ toast: data, index, y, expanded, frontHeight, total, onHeig
|
|
|
16686
16860
|
// Paused while you read the stack and while the tab is in the background.
|
|
16687
16861
|
const visible = useSyncExternalStore(onVisibility, isVisible, () => true);
|
|
16688
16862
|
const paused = expanded || !visible;
|
|
16689
|
-
const remaining = useRef({ duration
|
|
16863
|
+
const remaining = useRef({ duration, left: duration });
|
|
16690
16864
|
|
|
16691
16865
|
useEffect(() => {
|
|
16692
16866
|
const element = inner.current;
|
|
@@ -16705,9 +16879,8 @@ function ToastItem({ toast: data, index, y, expanded, frontHeight, total, onHeig
|
|
|
16705
16879
|
|
|
16706
16880
|
useEffect(() => {
|
|
16707
16881
|
// Time left restarts when the duration changes (a promise toast settling).
|
|
16708
|
-
if (remaining.current.duration !==
|
|
16709
|
-
|
|
16710
|
-
if (paused || !Number.isFinite(data.duration)) return;
|
|
16882
|
+
if (remaining.current.duration !== duration) remaining.current = { duration, left: duration };
|
|
16883
|
+
if (paused || !Number.isFinite(duration)) return;
|
|
16711
16884
|
|
|
16712
16885
|
const start = Date.now();
|
|
16713
16886
|
const timer = setTimeout(() => dismiss(data.id), remaining.current.left);
|
|
@@ -16716,7 +16889,7 @@ function ToastItem({ toast: data, index, y, expanded, frontHeight, total, onHeig
|
|
|
16716
16889
|
clearTimeout(timer);
|
|
16717
16890
|
remaining.current.left -= Date.now() - start;
|
|
16718
16891
|
};
|
|
16719
|
-
}, [paused, data.id,
|
|
16892
|
+
}, [paused, data.id, duration]);
|
|
16720
16893
|
|
|
16721
16894
|
const onDragEnd = (_: unknown, info: PanInfo) => {
|
|
16722
16895
|
if (Math.abs(info.offset.x) > 80 || Math.abs(info.velocity.x) > 500) {
|
|
@@ -16774,8 +16947,9 @@ function ToastItem({ toast: data, index, y, expanded, frontHeight, total, onHeig
|
|
|
16774
16947
|
{data.action && (
|
|
16775
16948
|
<button
|
|
16776
16949
|
type="button"
|
|
16777
|
-
onClick={() => {
|
|
16950
|
+
onClick={(event) => {
|
|
16778
16951
|
data.action?.onClick();
|
|
16952
|
+
onLeave(event.currentTarget);
|
|
16779
16953
|
dismiss(data.id);
|
|
16780
16954
|
}}
|
|
16781
16955
|
className="h-7 shrink-0 cursor-pointer rounded-md bg-primary px-2.5 font-medium text-primary-foreground text-xs outline-none transition-opacity hover:opacity-90 focus-visible:ring-[3px] focus-visible:ring-ring/50"
|
|
@@ -16786,7 +16960,10 @@ function ToastItem({ toast: data, index, y, expanded, frontHeight, total, onHeig
|
|
|
16786
16960
|
|
|
16787
16961
|
<button
|
|
16788
16962
|
type="button"
|
|
16789
|
-
onClick={() =>
|
|
16963
|
+
onClick={(event) => {
|
|
16964
|
+
onLeave(event.currentTarget);
|
|
16965
|
+
dismiss(data.id);
|
|
16966
|
+
}}
|
|
16790
16967
|
className="-mt-1 -mr-1 shrink-0 cursor-pointer rounded-md p-1 text-muted-foreground opacity-0 outline-none transition-opacity hover:text-foreground focus-visible:opacity-100 focus-visible:ring-[3px] focus-visible:ring-ring/50 group-hover:opacity-100"
|
|
16791
16968
|
>
|
|
16792
16969
|
<X className="size-3.5" aria-hidden="true" />
|
|
@@ -17719,9 +17896,9 @@ export const spring = { type: "spring", stiffness: 400, damping: 30 } as const;
|
|
|
17719
17896
|
export const clamp = (value: number, min: number, max: number) =>
|
|
17720
17897
|
Math.min(Math.max(value, min), max);
|
|
17721
17898
|
` }] } },
|
|
17722
|
-
index: [{ name: "accent-picker", type: "registry:ui", title: "Accent Picker", description: "Accent color row: eight swatches (red to slate) that retint primary, focus rings, selection, switches and checkboxes app-wide. Persisted, applied before paint, or set your own hue with --accent-hue.", exports: ["AccentPicker"], keywords: ["accent", "app", "color", "radio", "retint", "row", "setaccent", "swatches", "that", "the", "via", "whole"], registryDependencies: ["theme", "utils"] }, { name: "accordion", type: "registry:ui", title: "Accordion", description: "Single or multiple panels with spring height animation. Closed content stays in the DOM for SEO.", exports: ["Accordion", "AccordionItem", "AccordionTrigger", "AccordionContent"], keywords: ["accordion", "accordioncontent", "accordionitem", "accordiontrigger", "allow", "and", "called", "children", "closed", "closes", "closing", "collapsible", "content", "controlled", "crawlable", "default", "defaultvalue", "every", "first", "heading", "height", "html", "independent", "inert", "item", "items", "level", "match", "matched", "mounted", "multiple", "none", "one", "only", "onvaluechange", "open", "outline", "page", "panel", "panels", "question", "remains", "render", "single", "stays", "text", "the", "time", "type", "uncontrolled", "unique", "value", "when", "while", "with", "within", "wrapping"], registryDependencies: ["use-controllable-state", "utils"] }, { name: "alert", type: "registry:ui", title: "Alert", description: "Server-safe inline banner: tinted surface, colored icon, title, description and an optional action. Info, success, warning and destructive tones follow the accent and status tokens.", exports: ["Alert", "AlertTitle", "AlertDescription"], keywords: ["action", "add", "alert", "aligned", "and", "announced", "appears", "banner", "button", "colored", "default", "description", "did", "for", "icon", "inline", "live", "load", "none", "not", "null", "pass", "region", "replaces", "response", "right", "role", "sets", "should", "slot", "small", "something", "static", "surface", "the", "tint", "tinted", "title", "tone", "user", "variant", "when"], registryDependencies: ["utils"] }, { name: "app-window", type: "registry:ui", title: "AppWindow", description: "Window container with close / minimize / zoom controls, title, custom header slot and actions. SegmentedTabs is the compact view switcher for its title bar.", exports: ["AppWindow"], keywords: ["actions", "aligned", "area", "bar", "blurred", "bodyclassname", "button", "called", "centered", "classes", "content", "control", "custom", "dot", "for", "glass", "handler", "header", "into", "matching", "maximize", "minimize", "navbar", "onclose", "onmaximize", "onminimize", "passing", "pressed", "replaces", "right", "search", "shows", "slot", "surface", "tabs", "text", "the", "title", "titlebar", "translucent", "turns", "under", "when"], registryDependencies: ["utils"] }, { name: "aspect-ratio", type: "registry:ui", title: "Aspect Ratio", description: "Server-safe box locked to a ratio (16:9 thumbnails, 9:16 clips). A direct image or video child fills it with object-cover.", exports: ["AspectRatio"], keywords: ["box", "child", "cover", "direct", "fills", "height", "img", "locked", "object", "ratio", "video", "width"], registryDependencies: ["utils"] }, { name: "attachment", type: "registry:ui", title: "Attachment & Dropzone", description: "File chips with image thumbnails or type icons, size, a springing upload bar, error state and remove; the list springs chips in and closes the gap. FileDropzone wraps a real file input: click, keyboard and the native picker work, drop and paste are checked against accept and maxSize, and dropped files land in the input so forms and Server Actions receive them.", exports: ["formatBytes", "Attachment", "AttachmentList", "FileDropzone"], keywords: ["accept", "actions", "along", "and", "are", "area", "aria", "around", "attachments", "attribute", "back", "bar", "bcp", "blocks", "both", "bottom", "browse", "button", "bytes", "called", "child", "children", "chip", "click", "content", "createobjecturl", "default", "describedby", "disabled", "download", "drop", "dropped", "drops", "each", "edge", "enforced", "enter", "error", "failed", "field", "file", "files", "fills", "for", "form", "forms", "fresh", "from", "get", "given", "hint", "href", "icon", "ids", "image", "input", "into", "invalid", "key", "least", "line", "link", "locale", "makes", "maxsize", "mime", "more", "multiple", "name", "native", "needs", "one", "onfiles", "onreject", "onremove", "out", "passed", "paste", "pdf", "picked", "picker", "picks", "place", "plain", "pressed", "progress", "real", "reason", "red", "remove", "removed", "replaces", "required", "same", "server", "sets", "show", "shows", "size", "source", "space", "spring", "springs", "src", "styling", "submit", "submitted", "syntax", "text", "than", "that", "the", "them", "thumbnail", "too", "turns", "type", "types", "upload", "uploading", "url", "when", "while", "with", "work", "written"], registryDependencies: ["field", "utils"] }, { name: "avatar", type: "registry:ui", title: "Avatar", description: "Image with initials fallback on error, three sizes and online/away/busy/offline dots.", exports: ["Avatar"], keywords: ["alt", "and", "announced", "corner", "diameter", "dot", "fails", "fallback", "for", "icon", "image", "initials", "loads", "name", "overrides", "person", "presence", "show", "size", "src", "status", "text", "the", "url", "used", "while", "with"], registryDependencies: ["utils"] }, { name: "avatar-group", type: "registry:ui", title: "AvatarGroup", description: "Overlapping avatars with a +N overflow chip. Hover gently enlarges the avatar on a spring, keeping stack order.", exports: ["AvatarGroup"], keywords: ["alt", "and", "avatar", "avatars", "before", "chip", "each", "enlarges", "every", "gently", "hover", "how", "many", "max", "name", "one", "order", "overflow", "overlapping", "people", "show", "size", "spring", "stack", "staying", "the", "users", "with"], registryDependencies: ["avatar", "utils"] }, { name: "badge", type: "registry:ui", title: "Badge & Pill", description: "Minimal status tags. Rounded badge or fully rounded pill, with optional dot. pulse adds an expanding live-status ring.", exports: ["Badge"], keywords: ["and", "color", "current", "dot", "emits", "expanding", "forever", "fully", "leading", "like", "live", "needs", "pill", "pulse", "ring", "rounded", "shape", "status", "surface", "tag", "text", "the", "variant"], registryDependencies: ["utils"] }, { name: "breadcrumb", type: "registry:ui", title: "Breadcrumb", description: "Navigation trail from a list of items: links up to the current page, which is marked for assistive tech. Server-safe, custom separator.", exports: ["Breadcrumb"], keywords: ["between", "chevron", "current", "default", "drawn", "ending", "first", "item", "items", "last", "links", "list", "outermost", "page", "safe", "separator", "server", "site", "sits", "the", "trail", "where"], registryDependencies: [] }, { name: "button", type: "registry:ui", title: "Button", description: "Five variants, four sizes, spring press feedback, an animated loading spinner and in-place success state, a two-step confirm that swaps the label on first click, and a configurable swap direction. Width stays fixed to the longest label.", exports: ["Button"], keywords: ["action", "also", "and", "aria", "armed", "before", "blur", "both", "button", "can", "check", "children", "click", "clicks", "confirm", "confirmlabel", "confirmtimeout", "default", "defaults", "destructive", "done", "emphasis", "enter", "esc", "feedback", "fill", "first", "focusable", "for", "form", "give", "height", "icon", "ignore", "ignores", "irreversible", "its", "label", "left", "loading", "loadinglabel", "never", "old", "onclick", "one", "ones", "out", "padding", "per", "place", "primary", "reserved", "resets", "resize", "runs", "second", "shown", "shows", "size", "slides", "spinner", "spins", "square", "status", "stays", "step", "submit", "success", "successlabel", "swap", "swaps", "text", "the", "this", "twice", "two", "variant", "view", "where", "while", "width", "with"], registryDependencies: ["button-variants", "utils"] }, { name: "button-group", type: "registry:ui", title: "Button Group", description: "Joins buttons into one strip that shares borders, corners and active states. Horizontal or vertical.", exports: ["ButtonGroup"], keywords: ["and", "attached", "borders", "buttons", "connected", "control", "corners", "default", "fuse", "groups", "horizontal", "into", "orientation", "related", "single", "strip", "together", "toolbar", "true", "vertical"], registryDependencies: ["utils"] }, { name: "button-variants", type: "registry:ui", description: 'Button classes for non-button elements, e.g. `<a className={buttonVariants({ variant: "outline" })}>`.', exports: ["buttonVariants"], keywords: ["button", "buttonvariants", "classes", "classname", "elements", "for", "non", "outline", "variant"], registryDependencies: ["utils"] }, { name: "calendar", type: "registry:ui", title: "Calendar", description: "Month grid on the WAI-ARIA date-grid pattern: single date or range with a hover preview, min/max and custom disabled days, months that slide in from the direction of travel. Arrows, Home/End and PageUp/PageDown (+Shift for years). Hydration-safe: today is only marked in the browser.", exports: ["key", "Calendar"], keywords: ["and", "another", "any", "aria", "arrows", "autofocus", "bcp", "called", "client", "controlled", "current", "custom", "date", "datepicker", "dates", "day", "days", "default", "defaultmonth", "defaultvalue", "direction", "disabled", "displayed", "earliest", "end", "ends", "extra", "first", "focus", "for", "from", "function", "grid", "home", "hover", "into", "isdisabled", "iso", "keyboard", "latest", "like", "local", "locale", "max", "min", "mode", "monday", "month", "months", "mount", "names", "nothing", "null", "off", "one", "only", "onmonthchange", "onvaluechange", "pagedown", "pages", "pageup", "pattern", "pick", "picked", "preview", "range", "render", "rule", "saturday", "selectable", "sets", "shift", "shown", "single", "slide", "sorts", "start", "sunday", "the", "then", "this", "travel", "uncontrolled", "user", "value", "wai", "week", "weekday", "weekends", "weekstartson", "when", "with", "year", "yyyy"], registryDependencies: ["button", "use-controllable-state", "utils"] }, { name: "card", type: "registry:ui", title: "Card", description: "Composable surface: header, title, description, content and footer. Optional glass.", exports: ["Card", "CardHeader", "CardTitle", "CardDescription", "CardContent", "CardFooter"], keywords: ["backgrounds", "colored", "default", "directly", "fits", "follows", "glass", "heading", "level", "not", "outline", "over", "page", "place", "subtle", "textured", "that", "the", "translucency", "under", "when"], registryDependencies: ["utils"] }, { name: "carousel", type: "registry:ui", title: "Carousel", description: "Native scroll-snap row, so touch, trackpad and no-JS scrolling work, with spring-driven arrows, page dots, arrow keys and mouse drag that throws to the next snap point. APG carousel semantics: a labeled region of slides announced as 3 of 8.", exports: ["Carousel", "CarouselContent", "CarouselItem", "CarouselPrevious", "CarouselNext", "CarouselDots"], keywords: ["accessible", "all", "and", "announced", "any", "apg", "are", "arrow", "basis", "buttons", "carousel", "css", "default", "dot", "dots", "drag", "driven", "edge", "end", "fewer", "from", "gap", "hides", "keys", "label", "labeled", "left", "mouse", "name", "native", "not", "one", "overlaid", "page", "pages", "per", "projects", "region", "rem", "right", "row", "scroll", "scrolling", "semantics", "sized", "slide", "slides", "snap", "spring", "start", "the", "there", "total", "touch", "trackpad", "two", "variables", "view", "with", "work"], registryDependencies: ["button", "utils"] }, { name: "changelog", type: "registry:block", title: "Changelog", description: "Release notes on a Timeline: newest release highlighted, changes typed New / Improved / Fixed with Badges, and a Kbd shortcut to try the headline feature. Server-safe.", exports: ["Changelog"], keywords: ["are", "badges", "changes", "first", "highlighted", "how", "kbd", "newest", "notes", "one", "release", "releases", "shows", "the", "timeline", "try", "typed", "with"], registryDependencies: ["badge", "kbd", "timeline", "utils"] }, { name: "chart", type: "registry:ui", title: "Chart", description: "Line, area and bar (grouped or stacked) charts in SVG with a colorblind-validated eight-color palette that keeps each series' color. Crosshair tooltip listing every series, arrow-key readout, legend that hides series, direct end labels, a table view, and spring transitions between data.", exports: ["Chart"], keywords: ["add", "and", "are", "area", "areas", "arrow", "assistive", "axis", "bar", "bars", "bcp", "can", "captions", "categorical", "category", "chart", "charts", "compact", "crosshair", "currency", "data", "direct", "each", "eight", "end", "every", "filled", "fold", "for", "format", "grouping", "height", "hides", "index", "instead", "into", "key", "keys", "label", "labels", "legend", "line", "lines", "listing", "locale", "mark", "most", "names", "notation", "numbers", "object", "one", "only", "other", "pages", "palette", "past", "per", "plot", "plus", "props", "render", "row", "serializable", "series", "server", "split", "stack", "stacked", "style", "svg", "table", "tail", "tech", "that", "the", "them", "ticks", "too", "tooltip", "type", "usd", "value", "view", "with"], registryDependencies: ["button", "table", "use-dismiss", "utils"] }, { name: "checkbox", type: "registry:ui", title: "Checkbox", description: "Native checkbox with a spring-drawn check mark and an indeterminate state for select-all rows. Controlled or uncontrolled; submits with forms.", exports: ["Checkbox"], keywords: ["all", "called", "check", "checkbox", "checked", "controlled", "dash", "defaultchecked", "drawn", "field", "first", "indeterminate", "inside", "mixed", "native", "new", "oncheckedchange", "pair", "render", "rows", "select", "selected", "shows", "some", "spring", "state", "the", "uncontrolled", "with", "works"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "clip-card", type: "registry:block", title: "Clip Card", description: "Video tile: AspectRatio thumbnail (16:9 or 9:16), duration Badge, watched Progress along the bottom, and a ContextMenu of actions.", exports: ["ClipCard"], keywords: ["accessible", "actions", "ago", "along", "also", "and", "aspectratio", "badge", "bar", "bottom", "card", "click", "clip", "clips", "context", "contextmenuitem", "days", "duration", "f10", "film", "for", "glyph", "height", "how", "img", "items", "menu", "meta", "much", "name", "one", "opens", "print", "progress", "ratio", "right", "shift", "small", "stands", "the", "them", "thin", "thumbnail", "tile", "title", "under", "vertical", "video", "views", "was", "watched", "width", "without"], registryDependencies: ["aspect-ratio", "badge", "context-menu", "progress", "utils"] }, { name: "code", type: "registry:ui", title: "Code", description: "Shiki-highlighted code that follows light and dark through light-dark() token colors, as a block, an inline one-liner or a tabbed file panel. Line numbers (from any start line), tinted lines with an accent bar, <mark>ed words or column ranges, and per-line notes in a tooltip that keyboard users can tab to. Optional Prettier at display time; copy hands out exactly what is shown.", exports: ["CopyButton", "Code", "CodePanel"], keywords: ["accessible", "active", "add", "all", "and", "animates", "annotations", "bar", "bash", "before", "behind", "block", "body", "build", "button", "clipboard", "code", "collapse", "copied", "copy", "dark", "default", "dom", "each", "every", "excerpts", "file", "files", "first", "focus", "fold", "for", "format", "formatted", "from", "gets", "ghost", "gutter", "header", "highlight", "highlightcode", "highlighted", "highlighting", "hover", "ignored", "inline", "inside", "into", "its", "json", "keep", "label", "language", "least", "left", "light", "line", "linenumbers", "lines", "loads", "longer", "made", "many", "mark", "marks", "name", "never", "note", "notes", "number", "numbers", "one", "options", "own", "page", "paint", "panel", "per", "place", "prettier", "primary", "ranges", "refer", "registry", "remember", "renders", "run", "scrolling", "scrolls", "server", "sets", "shared", "shiki", "show", "source", "stays", "switching", "syntax", "tab", "terminal", "text", "than", "that", "the", "themes", "this", "time", "tint", "tokens", "too", "touch", "tsx", "turns", "variant", "vertically", "wheel", "with", "words", "wrapped", "written"], registryDependencies: ["button", "highlight", "overflow-focus", "tabs", "tooltip", "utils"] }, { name: "collapsible", type: "registry:ui", title: "Collapsible", description: "A single show/hide region with a spring height animation and rotating chevron. Controlled or uncontrolled; closed content stays in the DOM for SEO.", exports: ["Collapsible", "CollapsibleTrigger", "CollapsibleContent"], keywords: ["after", "and", "called", "chevron", "children", "closed", "collapsiblecontent", "collapsibletrigger", "content", "controlled", "crawlable", "default", "defaultopen", "first", "height", "hide", "html", "inert", "label", "mounted", "one", "onopenchange", "open", "pair", "region", "remains", "render", "rotating", "show", "springs", "state", "stays", "that", "the", "toggles", "trigger", "true", "uncontrolled", "when", "while", "with"], registryDependencies: ["use-controllable-state", "utils"] }, { name: "combobox", type: "registry:ui", title: "Combobox", description: "A Select you can type into: the query filters by label and keywords (prefix matches first), arrows move, Enter picks. multiple keeps the list open and shows picks as removable tags. Submits and validates with the form.", exports: ["Combobox"], keywords: ["accessible", "and", "aria", "backspace", "blocks", "called", "can", "choices", "closes", "controlled", "defaultvalue", "describedby", "disabled", "down", "emptytext", "enter", "entry", "error", "esc", "every", "field", "fills", "filtered", "filters", "first", "form", "from", "hint", "ids", "input", "into", "invalid", "isn", "keeps", "label", "last", "list", "matches", "move", "multiple", "name", "needs", "nothing", "one", "onvaluechange", "open", "opening", "options", "pair", "per", "pick", "picked", "picks", "placeholder", "removable", "removes", "render", "required", "select", "sets", "show", "shown", "shows", "single", "stay", "styling", "submit", "submitted", "tags", "text", "the", "there", "type", "types", "typing", "uncontrolled", "user", "value", "values", "visible", "when", "with", "you"], registryDependencies: ["field", "form-value", "list", "platform", "tag-input", "use-anchor", "use-controllable-state", "use-dismiss", "utils"] }, { name: "command", type: "registry:ui", title: "Command", description: "⌘K palette: filterable groups, arrow-key highlight, Enter to run, keyword matching. Inline or as CommandDialog with a global shortcut; the first Esc clears, the second closes.", exports: ["Command", "CommandInput", "CommandList", "CommandEmpty", "CommandGroup", "CommandSeparator", "CommandItem", "CommandDialog"], keywords: ["accessible", "after", "against", "and", "arrows", "but", "called", "children", "click", "close", "closes", "collapse", "command", "commanddialog", "commandempty", "commandinput", "commanditem", "commandlist", "content", "controlled", "ctrl", "defaults", "dialog", "disable", "disabled", "driven", "elsewhere", "end", "enter", "esc", "extra", "false", "filterable", "filtering", "for", "global", "group", "groups", "heading", "hidden", "hides", "home", "icon", "inline", "input", "inside", "item", "items", "its", "itself", "keepopen", "keyboard", "keywords", "label", "list", "listbox", "mac", "match", "matched", "matches", "mod", "move", "name", "none", "not", "only", "onopenchange", "onselect", "open", "option", "outside", "own", "pair", "palette", "pass", "passes", "placeholder", "preferences", "query", "results", "scrollable", "search", "selectable", "selecting", "selection", "selects", "separators", "settings", "shortcut", "shown", "shows", "stack", "state", "stay", "terms", "text", "the", "title", "toggle", "toggled", "use", "used", "value", "visible", "visually", "when", "while", "with", "would"], registryDependencies: ["dialog", "list", "search-input", "separator", "use-controllable-state", "use-hotkey", "utils"] }, { name: "confirm", type: "registry:ui", title: "Confirm", description: "Promise-based confirm dialog called like toast: await confirm({ title, description, destructive }) resolves true or false. Built on Dialog's alert mode, Cancel takes the first focus, Esc cancels, one host mounted in the layout.", exports: ["confirm", "Confirmer"], keywords: ["acting", "asks", "await", "before", "cancel", "confirm", "confirmer", "delete", "destructive", "esc", "false", "for", "host", "layout", "mount", "mounted", "needs", "newer", "next", "once", "project", "remove", "resolves", "root", "title", "toaster", "true"], registryDependencies: ["button", "dialog"] }, { name: "context-menu", type: "registry:ui", title: "Context Menu", description: "Right-click menu for an area, opening at the pointer and flipping at screen edges. Shares Dropdown Menu's items, checkbox and radio items, keyboard and typeahead; Menu key or Shift+F10 opens it from the keyboard.", exports: ["ContextMenuContent", "ContextMenuItem", "ContextMenuCheckboxItem", "ContextMenuRadioGroup", "ContextMenuRadioItem", "ContextMenuLabel", "ContextMenuSeparator", "ContextMenu", "ContextMenuTrigger"], keywords: ["actions", "align", "aligned", "and", "area", "but", "called", "center", "check", "checked", "children", "click", "clickable", "closes", "contextmenucontent", "contextmenutrigger", "destructive", "disabled", "dropdownmenuradioitem", "edge", "enter", "equals", "f10", "first", "focus", "focusable", "for", "group", "groups", "hint", "icon", "irreversible", "item", "items", "its", "key", "keyboard", "label", "labels", "leading", "lines", "mark", "menu", "new", "not", "oncheckedchange", "onopenchange", "onselect", "onvaluechange", "opens", "optionally", "picked", "pointer", "press", "red", "right", "selectable", "separators", "shift", "shortcut", "shown", "shows", "state", "the", "then", "trigger", "value", "variant", "when", "with"], registryDependencies: ["dropdown-menu", "utils"] }, { name: "count-to", type: "registry:ui", title: "CountTo", description: "Springs a number up from a start value once it scrolls into view. Prefix, suffix, decimals and locale.", exports: ["CountTo"], keywords: ["after", "and", "bcp", "before", "decimal", "decimals", "digits", "dom", "final", "for", "from", "grouping", "into", "locale", "number", "once", "point", "prefix", "scrolls", "seo", "springs", "starting", "stays", "suffix", "text", "the", "value", "view"], registryDependencies: ["utils"] }, { name: "custom-cursor", type: "registry:ui", title: "Custom Cursor", description: "Optional spring cursor that expands over interactive elements. Off on touch and reduced motion.", exports: ["CustomCursor"], keywords: ["coarse", "cursor", "dot", "elements", "expands", "interactive", "motion", "mount", "nothing", "once", "opt", "over", "pointers", "reduced", "renders", "ring", "spring", "touch", "trailing", "with"], registryDependencies: ["platform", "utils"] }, { name: "data-table", type: "registry:ui", title: "Data Table", description: "Table with columns as data: search across every column, sortable headers, checkbox selection that survives paging, a ⋯ menu per row, bulk actions in the toolbar and pagination. Built from Table, SearchInput, Checkbox, DropdownMenu, Pagination and Empty.", exports: ["DataTable"], keywords: ["accessor", "across", "actions", "all", "alternate", "and", "are", "backgrounds", "box", "bulk", "called", "cell", "checkbox", "client", "column", "columns", "compose", "controlled", "controls", "data", "defaultsort", "definitions", "display", "driven", "dropdownmenuitem", "each", "every", "field", "filters", "first", "for", "friends", "getrowid", "happen", "header", "ids", "items", "its", "jane", "kept", "label", "members", "menu", "name", "names", "onselectionchange", "order", "page", "pages", "pagesize", "pagination", "paging", "pair", "per", "placeholder", "readers", "receives", "render", "right", "row", "rowactions", "rowlabel", "rows", "screen", "search", "searchable", "searchplaceholder", "select", "selectable", "selected", "selection", "server", "show", "side", "sort", "sortable", "stable", "striped", "survives", "table", "that", "the", "toolbar", "with", "yourself"], registryDependencies: ["button", "checkbox", "dropdown-menu", "empty", "pagination", "search-input", "table", "use-controllable-state", "utils"] }, { name: "date-picker", type: "registry:ui", title: "Date Picker", description: "Field-styled button that opens a Calendar in a Popover, focused on the picked day. Single or range, presets such as Last 7 days, closes once the pick is complete, and submits ISO dates with the form. Works inside Field.", exports: ["DatePicker"], keywords: ["accessible", "and", "are", "aria", "bcp", "beside", "blocks", "both", "button", "calendar", "called", "client", "closes", "controlled", "date", "day", "days", "default", "defaultvalue", "describedby", "disabled", "earliest", "end", "ends", "error", "extra", "field", "fill", "fills", "first", "focused", "for", "form", "from", "function", "grid", "hint", "htmlfor", "ids", "invalid", "isdisabled", "isn", "iso", "label", "last", "latest", "let", "locale", "max", "min", "mode", "monday", "name", "needs", "nothing", "null", "off", "once", "one", "only", "onvaluechange", "opening", "opens", "optional", "pair", "pick", "picked", "placeholder", "popover", "presets", "range", "reach", "readers", "ready", "render", "required", "rule", "saturday", "selectable", "set", "sets", "shortcuts", "single", "start", "styled", "styling", "submit", "submits", "submitted", "sunday", "text", "that", "the", "then", "there", "these", "today", "uncontrolled", "value", "visible", "weekends", "weekstartson", "when", "with"], registryDependencies: ["calendar", "field", "form-value", "input", "popover", "use-controllable-state", "utils"] }, { name: "dialog", type: "registry:ui", title: "Dialog", description: "Portal modal with blurred backdrop, spring scale-in, focus trap, Esc and scroll lock.", exports: ["useDialog", "Dialog", "DialogTrigger", "DialogClose", "useModal", "DialogContent", "DialogHeader", "DialogFooter", "DialogTitle", "DialogDescription"], keywords: ["action", "alert", "alertdialog", "also", "and", "aria", "armed", "attach", "backdrop", "before", "behavior", "blur", "blurred", "body", "both", "button", "called", "can", "check", "children", "click", "clicks", "close", "confirm", "confirmlabel", "confirmtimeout", "controlled", "corner", "default", "defaultopen", "defaults", "destructive", "dialog", "dialogclose", "dialogcontent", "dialogs", "dialogtrigger", "does", "done", "drawer", "emphasis", "enter", "esc", "feedback", "field", "fill", "first", "focus", "focusable", "footer", "for", "form", "give", "header", "height", "icon", "ignore", "ignores", "irreversible", "its", "label", "left", "loading", "loadinglabel", "lock", "modal", "mode", "never", "not", "off", "old", "onclick", "one", "ones", "only", "onopenchange", "open", "out", "padding", "page", "pair", "panel", "per", "place", "portal", "primary", "ref", "render", "reserved", "resets", "resize", "restore", "returned", "role", "root", "runs", "scale", "scroll", "second", "shared", "showclose", "shown", "shows", "size", "slides", "spinner", "spins", "spring", "square", "state", "status", "stays", "step", "submit", "success", "successlabel", "swap", "swaps", "tab", "text", "the", "this", "topmost", "trap", "trigger", "twice", "two", "uncontrolled", "variant", "view", "where", "while", "width", "with"], registryDependencies: ["button", "focus", "platform", "use-controllable-state", "utils"] }, { name: "drawer", type: "registry:ui", title: "Drawer", description: "Edge panel (left, right, top, bottom) that springs in and swipes away. Shares Dialog's focus trap, scroll lock and Esc handling. Sidebar uses it below md.", exports: ["Drawer", "DrawerTrigger", "DrawerClose", "DrawerTitle", "DrawerDescription", "DrawerContent", "DrawerHeader", "DrawerBody", "DrawerFooter"], keywords: ["action", "also", "and", "anywhere", "aria", "armed", "backdrop", "before", "blur", "body", "both", "bottom", "button", "called", "can", "check", "children", "click", "clicks", "close", "confirm", "confirmlabel", "confirmtimeout", "content", "controlled", "corner", "default", "defaultopen", "defaults", "destructive", "dialogclose", "dialogcontent", "dialogtrigger", "dismiss", "done", "drag", "drawer", "drawers", "edge", "emphasis", "enter", "esc", "feedback", "fill", "first", "focusable", "footer", "for", "form", "from", "give", "handle", "header", "height", "icon", "ignore", "ignores", "irreversible", "its", "label", "left", "loading", "loadinglabel", "never", "old", "onclick", "one", "ones", "onopenchange", "open", "out", "padding", "pair", "panel", "per", "place", "primary", "render", "reserved", "resets", "resize", "runs", "scroll", "scrolls", "second", "showclose", "shown", "shows", "side", "size", "slides", "spinner", "spins", "spring", "square", "state", "status", "stays", "step", "submit", "success", "successlabel", "swap", "swaps", "swipe", "taller", "text", "than", "that", "the", "their", "this", "top", "toward", "trigger", "twice", "two", "uncontrolled", "variant", "view", "when", "where", "while", "width", "with"], registryDependencies: ["dialog", "platform", "utils"] }, { name: "dropdown-menu", type: "registry:ui", title: "Dropdown Menu", description: "Action menu anchored to a Button: items with icons and shortcuts, checkbox and radio items, labels, separators, destructive variant. Arrow keys, typeahead, focus follows the pointer, Esc returns focus.", exports: ["MenuContext", "DropdownMenu", "DropdownMenuTrigger", "DropdownMenuContent", "DropdownMenuItem", "DropdownMenuCheckboxItem", "DropdownMenuRadioGroup", "DropdownMenuRadioItem", "DropdownMenuLabel", "DropdownMenuSeparator"], keywords: ["action", "actions", "align", "aligned", "also", "anchored", "and", "aria", "armed", "before", "blur", "both", "but", "button", "called", "can", "check", "checked", "children", "choice", "click", "clicks", "closes", "closing", "confirm", "confirmlabel", "confirmtimeout", "content", "controlled", "default", "defaultopen", "defaults", "destructive", "disabled", "done", "down", "dropdownmenuradioitem", "edge", "emphasis", "enter", "equals", "esc", "feedback", "fill", "first", "focusable", "for", "form", "give", "group", "groups", "height", "hint", "icon", "ignore", "ignores", "irreversible", "item", "items", "its", "keeps", "keyboard", "label", "labels", "last", "leading", "left", "lines", "loading", "loadinglabel", "mark", "menu", "never", "new", "not", "old", "oncheckedchange", "onclick", "one", "ones", "onopenchange", "onselect", "onvaluechange", "open", "opens", "optionally", "out", "outside", "padding", "pair", "per", "picked", "picking", "place", "primary", "radiogroup", "red", "render", "reserved", "resets", "resize", "right", "runs", "second", "selectable", "selection", "separators", "shortcut", "shown", "shows", "size", "slides", "space", "spinner", "spins", "square", "state", "status", "stays", "step", "submit", "success", "successlabel", "swap", "swaps", "text", "the", "then", "this", "toggles", "trigger", "twice", "two", "uncontrolled", "value", "variant", "view", "when", "where", "while", "width", "with", "without"], registryDependencies: ["button", "list", "platform", "use-anchor", "use-controllable-state", "use-dismiss", "utils"] }, { name: "empty", type: "registry:ui", title: "Empty", description: "Server-safe empty state: icon tile, title, one helpful sentence and the next action. Bordered variant for empty lists and drop zones.", exports: ["Empty"], keywords: ["about", "action", "and", "app", "area", "bordered", "children", "clips", "dashed", "description", "drop", "empty", "for", "helpful", "icon", "inside", "like", "list", "next", "one", "outline", "page", "rounded", "sentence", "shown", "state", "the", "tile", "title", "what", "yet", "zone"], registryDependencies: ["utils"] }, { name: "field", type: "registry:ui", title: "Field", description: "Label, control, description and error as one unit. Controls inside (Input, Textarea, Select, Checkbox, Switch, RadioGroup) get id, aria-describedby, aria-invalid and required automatically; errors spring in and are announced.", exports: ["useFieldControl", "useFieldLabel", "Field"], keywords: ["and", "aria", "automatically", "beside", "can", "checkbox", "children", "control", "controls", "describedby", "description", "dims", "disabled", "disables", "enclosing", "error", "explicit", "field", "fieldset", "fills", "first", "for", "form", "from", "group", "have", "hint", "horizontal", "ids", "input", "invalid", "its", "label", "makes", "marks", "match", "must", "names", "one", "orientation", "out", "outside", "own", "picks", "props", "radiogroup", "rating", "renders", "required", "returns", "shown", "single", "springs", "state", "switch", "target", "the", "unchanged", "under", "unit", "use", "when", "which", "win", "wired", "with"], registryDependencies: ["label", "utils"] }, { name: "focus", type: "registry:lib", description: "What Tab reaches inside `root`, in order. Skips disabled and hidden fields, tabIndex -1 (a\nFormValue helper) and all but one radio per group, so the first and last are real stops.", exports: ["tabbables"], keywords: ["all", "and", "are", "but", "disabled", "fields", "first", "formvalue", "group", "helper", "hidden", "inside", "last", "one", "order", "per", "radio", "reaches", "real", "root", "skips", "stops", "tab", "tabindex", "the", "what"], registryDependencies: [] }, { name: "form-value", type: "registry:lib", description: "Submits a custom control's value and takes part in native validation, which a hidden input\ncan't: an empty `required` value blocks submit, shows the browser's message and focuses `anchor`.", exports: ["FormValue", "useFormReset"], keywords: ["action", "after", "anchor", "and", "back", "blocks", "browser", "button", "called", "calls", "can", "control", "custom", "default", "disabled", "does", "empty", "field", "finds", "focus", "focuses", "form", "gets", "goes", "hidden", "input", "invalid", "its", "leaves", "like", "message", "name", "native", "nothing", "oninvalid", "only", "onreset", "out", "part", "picked", "react", "required", "reset", "resets", "shows", "skips", "state", "submit", "submits", "succeeds", "takes", "that", "the", "there", "validation", "value", "visible", "when", "which", "without"], registryDependencies: [] }, { name: "highlight", type: "registry:lib", description: "Lines of colored tokens, with Shiki loaded on demand. Runs anywhere: Code calls it in the\nbrowser, and a Server Component or a build can call it ahead of time and pass the result as\n`tokens`, so the browser never loads Shiki. Null for unknown languages.", exports: ["highlightCode", "languageOf"], keywords: ["ahead", "and", "anywhere", "back", "browser", "build", "call", "calls", "can", "code", "colored", "component", "demand", "extension", "falls", "file", "for", "from", "language", "languages", "lines", "loaded", "loads", "name", "never", "null", "pass", "result", "runs", "server", "shiki", "the", "time", "tokens", "tsx", "unknown", "with"], registryDependencies: [] }, { name: "hover-card", type: "registry:ui", title: "Hover Card", description: "Rich preview (profile, product, clip) that opens after a hover delay or keyboard focus. The pointer can move into the card; supplementary only.", exports: ["HoverCard"], keywords: ["acts", "align", "alignment", "avatar", "before", "bio", "can", "card", "children", "clip", "closedelay", "closes", "content", "first", "flips", "focus", "hover", "into", "keyboard", "leaves", "link", "move", "must", "once", "only", "opendelay", "opens", "pointer", "preferred", "preview", "product", "profile", "rich", "room", "second", "side", "stats", "supplementary", "tap", "the", "there", "time", "touch", "trigger", "usually", "when", "with", "without", "work"], registryDependencies: ["platform", "use-anchor", "use-dismiss", "use-hover-open", "utils"] }, { name: "input", type: "registry:ui", title: "Forms", description: "Input, Textarea, Label and Switch: smooth focus rings, native :user-invalid validation (red only after interaction), aria-invalid, auto-growing textarea with an optional character count, and a spring switch.", exports: ["fieldClass", "Input"], keywords: ["and", "aria", "chrome", "field", "filled", "group", "handed", "inputgroup", "inside", "the", "works"], registryDependencies: ["field", "utils"] }, { name: "input-group", type: "registry:ui", title: "Input Group", description: "Server-safe wrapper that fuses an Input with icons, text (https://, USD) or buttons into one field with a shared border and focus ring. Clicking an addon focuses the input.", exports: ["InputGroup", "InputGroupAddon"], keywords: ["addons", "align", "and", "beside", "border", "button", "buttons", "clicking", "control", "data", "draws", "drops", "field", "focus", "focuses", "group", "https", "icon", "icons", "inner", "input", "its", "like", "made", "matched", "one", "own", "plain", "plus", "ring", "side", "sits", "slot", "text", "the"], registryDependencies: ["utils"] }, { name: "input-otp", type: "registry:ui", title: "Input OTP", description: "One-time code in separate slots, backed by one real input: paste and SMS autofill work, screen readers hear one field. Grouped slots, numeric or alphanumeric, characters spring in, onComplete to submit. verified turns each character into a check, then merges them into one mark.", exports: ["InputOTP"], keywords: ["accepted", "again", "allowed", "alphanumeric", "and", "announced", "are", "autocomplete", "autofill", "back", "beside", "between", "called", "change", "character", "characters", "charset", "check", "code", "controlled", "counts", "dash", "defaultvalue", "draws", "dropped", "each", "edit", "every", "false", "filled", "fires", "first", "for", "group", "groups", "input", "into", "label", "laid", "length", "mark", "merge", "merged", "number", "once", "oncomplete", "one", "only", "onvaluechange", "others", "over", "pair", "paste", "pasted", "per", "read", "readers", "real", "render", "screen", "set", "shown", "single", "sits", "slides", "slot", "slots", "sms", "submit", "the", "then", "time", "transparently", "turns", "typed", "uncontrolled", "uppercased", "value", "verified", "verifiedlabel", "via", "visual", "was", "with"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "kbd", type: "registry:ui", title: "Kbd", description: "Server-safe key caps for shortcut hints. KbdGroup nests keys per the HTML spec.", exports: ["Kbd", "KbdGroup"], keywords: ["cap", "html", "kbd", "kbdgroup", "key", "keys", "made", "nested", "one", "per", "several", "shortcut", "spec", "the"], registryDependencies: ["utils"] }, { name: "label", type: "registry:ui", title: "Forms", description: "Input, Textarea, Label and Switch: smooth focus rings, native :user-invalid validation (red only after interaction), aria-invalid, auto-growing textarea with an optional character count, and a spring switch.", exports: ["Label"], keywords: [], registryDependencies: ["utils"] }, { name: "list", type: "registry:lib", description: "The item a navigation key moves to in a list, from the item at `index` (-1: none active).\nUndefined when the key doesn't navigate.", exports: ["listKeyTarget", "scrollIntoList"], keywords: ["active", "box", "can", "doesn", "enough", "from", "index", "item", "just", "key", "list", "moves", "moving", "navigate", "navigation", "none", "page", "scrollintoview", "scrolls", "show", "the", "undefined", "way", "when", "without"], registryDependencies: ["utils"] }, { name: "marker", type: "registry:ui", title: "Marker", description: "Highlighter-pen <mark> in four tints that wraps cleanly across lines and can draw itself on, left to right, when it scrolls into view. Highlight marks every match of a search in a string, for transcripts and search results.", exports: ["Marker", "Highlight"], keywords: ["across", "before", "case", "cleanly", "color", "delay", "draw", "drawing", "draws", "every", "first", "full", "fully", "highlight", "highlighter", "insensitive", "inside", "instant", "into", "left", "lines", "mark", "markers", "marks", "match", "motion", "one", "paragraph", "pen", "query", "reduced", "right", "scrolls", "search", "seconds", "several", "shown", "stagger", "sweeps", "term", "terms", "text", "the", "time", "view", "with", "without", "wraps"], registryDependencies: ["utils"] }, { name: "menubar", type: "registry:ui", title: "Menubar", description: "Desktop-style menu bar on the WAI-ARIA menubar pattern: one menu open at a time, hovering the next title while one is open switches to it, ← → walk the bar with or without a menu open, one Tab stop. A single highlight springs between titles; menus reuse every DropdownMenu item.", exports: ["MenubarContent", "MenubarItem", "MenubarCheckboxItem", "MenubarRadioGroup", "MenubarRadioItem", "MenubarLabel", "MenubarSeparator", "Menubar", "MenubarMenu", "MenubarTrigger"], keywords: ["actions", "align", "aligned", "analytics", "and", "another", "apart", "bar", "between", "but", "called", "check", "checked", "children", "click", "closes", "desktop", "destructive", "disabled", "down", "dropdownmenuradioitem", "edge", "enter", "equals", "first", "for", "generated", "give", "group", "groups", "highlight", "hint", "hovering", "icon", "irreversible", "item", "items", "its", "label", "labels", "last", "leading", "left", "lines", "mark", "menu", "menubarcontent", "menubartrigger", "menus", "move", "new", "not", "omitted", "oncheckedchange", "one", "onselect", "onvaluechange", "open", "opens", "optional", "optionally", "picked", "red", "right", "selectable", "separators", "shortcut", "shown", "shows", "space", "springs", "stable", "state", "style", "switches", "tell", "tests", "the", "then", "time", "title", "titles", "toggles", "trigger", "value", "variant", "when", "while", "with"], registryDependencies: ["dropdown-menu", "list", "use-indicator", "utils"] }, { name: "message-bubble", type: "registry:ui", title: "Message Bubble", description: "User/assistant chat bubbles with avatar slot, streaming dots and copyable code blocks.", exports: ["MessageBubble"], keywords: ["above", "accent", "after", "and", "animated", "are", "assistant", "attachments", "avatar", "bubble", "chat", "children", "code", "content", "dots", "from", "inline", "left", "lists", "message", "name", "next", "rich", "right", "sender", "shown", "shows", "side", "size", "slot", "streaming", "surface", "text", "the", "time", "typing", "user"], registryDependencies: ["utils"] }, { name: "meter", type: "registry:ui", title: "Meter", description: "Server-safe gauge for a value in a known range (storage, quota, server load, password strength). Colors by <meter> thresholds, or stacked segments with a legend, like a storage bar.", exports: ["Meter"], keywords: ["above", "accessible", "also", "and", "away", "bar", "below", "between", "bound", "color", "colors", "decides", "defaults", "disk", "follow", "good", "green", "high", "known", "label", "legend", "like", "load", "low", "lower", "max", "measurement", "meter", "min", "name", "not", "one", "optimum", "orange", "overrides", "parts", "password", "progress", "quota", "range", "red", "region", "right", "segments", "server", "stacked", "storage", "strength", "sum", "task", "text", "the", "their", "this", "threshold", "thresholds", "total", "two", "upper", "use", "used", "value", "valuetext", "visible", "where", "with", "within"], registryDependencies: ["utils"] }, { name: "motion-provider", type: "registry:component", exports: ["MotionProvider"], keywords: [], registryDependencies: ["utils"] }, { name: "native-select", type: "registry:ui", title: "Native Select", description: "A real <select> with option groups: native picker on phones, no-JS forms, native required validation. Where customizable select is supported (appearance: base-select), the open list gets the menu look.", exports: ["NativeSelect", "NativeSelectGroup", "NativeSelectOption"], keywords: ["appearance", "base", "browser", "custom", "customizable", "elsewhere", "forms", "gets", "group", "heading", "icons", "instead", "invalid", "label", "labeled", "list", "look", "menu", "native", "need", "open", "optgroup", "options", "phones", "picker", "real", "rendering", "required", "select", "stays", "supports", "the", "use", "user", "validation", "when", "where", "without", "works"], registryDependencies: ["field", "input", "utils"] }, { name: "navigation-menu", type: "registry:ui", title: "Navigation Menu", description: "Website top navigation on the APG disclosure pattern: plain links and panels of rich links. Hover opens after a beat, then sliding along the bar switches panels at once; every panel shares one viewport that springs to the next panel's size and position while the content slides in from the side you moved toward. Click, Enter, ↓, ← → and Esc work; closed panels keep their links in the HTML for crawlers.", exports: ["NavigationMenu", "NavigationMenuList", "NavigationMenuItem", "NavigationMenuTrigger", "NavigationMenuContent", "NavigationMenuLink"], keywords: ["active", "after", "all", "along", "and", "aria", "bar", "beat", "bold", "called", "children", "classname", "click", "closed", "closes", "content", "controlled", "crawlers", "current", "defaultvalue", "description", "down", "enter", "entry", "esc", "find", "first", "focuses", "following", "for", "generated", "hidden", "hover", "html", "icon", "inset", "into", "item", "items", "its", "left", "level", "line", "link", "links", "look", "matched", "menu", "mouse", "muted", "navigation", "omitted", "once", "one", "onvaluechange", "open", "opened", "opens", "optional", "own", "padding", "page", "pair", "panel", "panels", "pill", "plain", "readers", "rem", "render", "rich", "right", "row", "selected", "single", "size", "sliding", "space", "springs", "stable", "stay", "still", "switches", "the", "them", "then", "tile", "title", "toggle", "top", "trigger", "uncontrolled", "under", "value", "viewport", "walk", "website", "while", "with", "your"], registryDependencies: ["focus", "use-controllable-state", "use-dismiss", "use-indicator", "utils"] }, { name: "newsletter", type: "registry:block", title: "Newsletter", description: "Email signup: InputGroup with the submit Button inside, native email validation, a loading → success toast and an in-place success state on the button.", exports: ["Newsletter"], keywords: ["above", "address", "after", "and", "button", "check", "confirm", "confirms", "description", "email", "field", "for", "form", "heading", "inbox", "inputgroup", "inside", "into", "its", "line", "loading", "message", "native", "next", "onsubscribe", "place", "placeholder", "rejection", "resets", "resolves", "saved", "shows", "signup", "submit", "submitlabel", "success", "successmessage", "supporting", "text", "that", "the", "then", "title", "toast", "turns", "under", "validation", "when", "with", "your"], registryDependencies: ["button", "input", "input-group", "toast", "utils"] }, { name: "number-input", type: "registry:ui", title: "Number Input", description: "Native number field with −/+ buttons: arrow keys, min/max/step validation and form submit from the platform; clamps on blur, rounds to the step's precision.", exports: ["NumberInput"], keywords: ["amount", "and", "are", "arrows", "arrowup", "buttons", "called", "cart", "change", "controlled", "defaultvalue", "down", "field", "first", "form", "helpers", "highest", "keyboard", "lowest", "max", "min", "native", "new", "number", "onvaluechange", "pair", "pointer", "quantity", "render", "step", "submit", "tabindex", "the", "uncontrolled", "use", "users", "validation", "value", "with"], registryDependencies: ["form-value", "input", "input-group", "use-controllable-state", "utils"] }, { name: "overflow-focus", type: "registry:lib", description: `Drop inside a scroll container: while the container overflows it becomes keyboard-focusable
|
|
17899
|
+
index: [{ name: "accent-picker", type: "registry:ui", title: "Accent Picker", description: "Accent color row: eight swatches (red to slate) that retint primary, focus rings, selection, switches and checkboxes app-wide. Persisted, applied before paint, or set your own hue with --accent-hue.", exports: ["AccentPicker"], keywords: ["accent", "app", "color", "radio", "retint", "row", "setaccent", "swatches", "that", "the", "via", "whole"], registryDependencies: ["theme", "utils"] }, { name: "accordion", type: "registry:ui", title: "Accordion", description: "Single or multiple panels with spring height animation. Closed content stays in the DOM for SEO.", exports: ["Accordion", "AccordionItem", "AccordionTrigger", "AccordionContent"], keywords: ["accordion", "accordioncontent", "accordionitem", "accordiontrigger", "allow", "and", "called", "children", "closed", "closes", "closing", "collapsible", "content", "controlled", "crawlable", "default", "defaultvalue", "every", "first", "heading", "height", "html", "independent", "inert", "item", "items", "level", "match", "matched", "mounted", "multiple", "none", "one", "only", "onvaluechange", "open", "outline", "page", "panel", "panels", "question", "remains", "render", "single", "stays", "text", "the", "time", "type", "uncontrolled", "unique", "value", "when", "while", "with", "within", "wrapping"], registryDependencies: ["use-controllable-state", "utils"] }, { name: "alert", type: "registry:ui", title: "Alert", description: "Server-safe inline banner: tinted surface, colored icon, title, description and an optional action. Info, success, warning and destructive tones follow the accent and status tokens.", exports: ["Alert", "AlertTitle", "AlertDescription"], keywords: ["action", "add", "alert", "aligned", "and", "announced", "appears", "banner", "button", "colored", "default", "description", "did", "for", "icon", "inline", "live", "load", "none", "not", "null", "pass", "region", "replaces", "response", "right", "role", "sets", "should", "slot", "small", "something", "static", "surface", "the", "tint", "tinted", "title", "tone", "user", "variant", "when"], registryDependencies: ["utils"] }, { name: "app-window", type: "registry:ui", title: "AppWindow", description: "Window container with close / minimize / zoom controls, title, custom header slot and actions. SegmentedTabs is the compact view switcher for its title bar.", exports: ["AppWindow"], keywords: ["actions", "aligned", "area", "bar", "blurred", "bodyclassname", "button", "called", "centered", "classes", "content", "control", "custom", "dot", "for", "glass", "handler", "header", "into", "matching", "maximize", "minimize", "navbar", "onclose", "onmaximize", "onminimize", "passing", "pressed", "replaces", "right", "search", "shows", "slot", "surface", "tabs", "text", "the", "title", "titlebar", "translucent", "turns", "under", "when"], registryDependencies: ["utils"] }, { name: "aspect-ratio", type: "registry:ui", title: "Aspect Ratio", description: "Server-safe box locked to a ratio (16:9 thumbnails, 9:16 clips). A direct image or video child fills it with object-cover.", exports: ["AspectRatio"], keywords: ["box", "child", "cover", "direct", "fills", "height", "img", "locked", "object", "ratio", "video", "width"], registryDependencies: ["utils"] }, { name: "attachment", type: "registry:ui", title: "Attachment & Dropzone", description: "File chips with image thumbnails or type icons, size, a springing upload bar, error state and remove; the list springs chips in and closes the gap. FileDropzone wraps a real file input: click, keyboard and the native picker work, drop and paste are checked against accept and maxSize, and dropped files land in the input so forms and Server Actions receive them.", exports: ["formatBytes", "Attachment", "AttachmentList", "FileDropzone"], keywords: ["accept", "actions", "along", "and", "are", "area", "aria", "around", "attachments", "attribute", "back", "bar", "bcp", "blocks", "both", "bottom", "browse", "button", "bytes", "called", "child", "children", "chip", "click", "content", "createobjecturl", "default", "describedby", "disabled", "download", "drop", "dropped", "drops", "each", "edge", "enforced", "enter", "error", "failed", "field", "file", "files", "fills", "for", "form", "forms", "fresh", "from", "get", "given", "hint", "href", "icon", "ids", "image", "input", "into", "invalid", "key", "least", "line", "link", "locale", "makes", "maxsize", "mime", "more", "multiple", "name", "native", "needs", "one", "onfiles", "onreject", "onremove", "out", "passed", "paste", "pdf", "picked", "picker", "picks", "place", "plain", "pressed", "progress", "real", "reason", "red", "remove", "removed", "replaces", "required", "same", "server", "sets", "show", "shows", "size", "source", "space", "spring", "springs", "src", "styling", "submit", "submitted", "syntax", "text", "than", "that", "the", "them", "thumbnail", "too", "turns", "type", "types", "upload", "uploading", "url", "when", "while", "with", "work", "written"], registryDependencies: ["field", "utils"] }, { name: "avatar", type: "registry:ui", title: "Avatar", description: "Image with initials fallback on error, three sizes and online/away/busy/offline dots.", exports: ["Avatar"], keywords: ["alt", "and", "announced", "corner", "diameter", "dot", "fails", "fallback", "for", "icon", "image", "initials", "loads", "name", "overrides", "person", "presence", "show", "size", "src", "status", "text", "the", "url", "used", "while", "with"], registryDependencies: ["utils"] }, { name: "avatar-group", type: "registry:ui", title: "AvatarGroup", description: "Overlapping avatars with a +N overflow chip. Hover gently enlarges the avatar on a spring, keeping stack order.", exports: ["AvatarGroup"], keywords: ["alt", "and", "avatar", "avatars", "before", "chip", "each", "enlarges", "every", "gently", "hover", "how", "many", "max", "name", "one", "order", "overflow", "overlapping", "people", "show", "size", "spring", "stack", "staying", "the", "users", "with"], registryDependencies: ["avatar", "utils"] }, { name: "badge", type: "registry:ui", title: "Badge & Pill", description: "Minimal status tags. Rounded badge or fully rounded pill, with optional dot. pulse adds an expanding live-status ring.", exports: ["Badge"], keywords: ["and", "color", "current", "dot", "emits", "expanding", "forever", "fully", "leading", "like", "live", "needs", "pill", "pulse", "ring", "rounded", "shape", "status", "surface", "tag", "text", "the", "variant"], registryDependencies: ["utils"] }, { name: "breadcrumb", type: "registry:ui", title: "Breadcrumb", description: "Navigation trail from a list of items: links up to the current page, which is marked for assistive tech. Server-safe, custom separator.", exports: ["Breadcrumb"], keywords: ["between", "chevron", "current", "default", "drawn", "ending", "first", "item", "items", "last", "links", "list", "outermost", "page", "safe", "separator", "server", "site", "sits", "the", "trail", "where"], registryDependencies: [] }, { name: "button", type: "registry:ui", title: "Button", description: "Five variants, four sizes, spring press feedback, an animated loading spinner and in-place success state, a two-step confirm that swaps the label on first click, and a configurable swap direction. Width stays fixed to the longest label.", exports: ["Button"], keywords: ["action", "also", "and", "aria", "armed", "before", "blur", "both", "button", "can", "check", "children", "click", "clicks", "confirm", "confirmlabel", "confirmtimeout", "default", "defaults", "destructive", "done", "emphasis", "enter", "esc", "feedback", "fill", "first", "focusable", "for", "form", "give", "height", "icon", "ignore", "ignores", "irreversible", "its", "label", "left", "loading", "loadinglabel", "never", "old", "onclick", "one", "ones", "out", "padding", "per", "place", "primary", "reserved", "resets", "resize", "runs", "second", "shown", "shows", "size", "slides", "spinner", "spins", "square", "status", "stays", "step", "submit", "success", "successlabel", "swap", "swaps", "text", "the", "this", "twice", "two", "variant", "view", "where", "while", "width", "with"], registryDependencies: ["button-variants", "utils"] }, { name: "button-group", type: "registry:ui", title: "Button Group", description: "Joins buttons into one strip that shares borders, corners and active states. Horizontal or vertical.", exports: ["ButtonGroup"], keywords: ["and", "attached", "borders", "buttons", "connected", "control", "corners", "default", "fuse", "groups", "horizontal", "into", "orientation", "related", "single", "strip", "together", "toolbar", "true", "vertical"], registryDependencies: ["utils"] }, { name: "button-variants", type: "registry:ui", description: 'Button classes for non-button elements, e.g. `<a className={buttonVariants({ variant: "outline" })}>`.', exports: ["buttonVariants"], keywords: ["button", "buttonvariants", "classes", "classname", "elements", "for", "non", "outline", "variant"], registryDependencies: ["utils"] }, { name: "calendar", type: "registry:ui", title: "Calendar", description: "Month grid on the WAI-ARIA date-grid pattern: single date or range with a hover preview, min/max and custom disabled days, months that slide in from the direction of travel. Arrows, Home/End and PageUp/PageDown (+Shift for years). Hydration-safe: today is only marked in the browser.", exports: ["key", "Calendar"], keywords: ["and", "another", "any", "aria", "arrows", "autofocus", "bcp", "called", "client", "controlled", "current", "custom", "date", "datepicker", "dates", "day", "days", "default", "defaultmonth", "defaultvalue", "direction", "disabled", "displayed", "earliest", "end", "ends", "extra", "first", "focus", "for", "from", "function", "grid", "home", "hover", "into", "isdisabled", "iso", "keyboard", "latest", "like", "local", "locale", "max", "min", "mode", "monday", "month", "months", "mount", "names", "nothing", "null", "off", "one", "only", "onmonthchange", "onvaluechange", "pagedown", "pages", "pageup", "pattern", "pick", "picked", "preview", "range", "render", "rule", "saturday", "selectable", "sets", "shift", "shown", "single", "slide", "sorts", "start", "sunday", "the", "then", "this", "travel", "uncontrolled", "user", "value", "wai", "week", "weekday", "weekends", "weekstartson", "when", "with", "year", "yyyy"], registryDependencies: ["button", "use-controllable-state", "utils"] }, { name: "card", type: "registry:ui", title: "Card", description: "Composable surface: header, title, description, content and footer. Optional glass.", exports: ["Card", "CardHeader", "CardTitle", "CardDescription", "CardContent", "CardFooter"], keywords: ["backgrounds", "colored", "default", "directly", "fits", "follows", "glass", "heading", "level", "not", "outline", "over", "page", "place", "subtle", "textured", "that", "the", "translucency", "under", "when"], registryDependencies: ["utils"] }, { name: "carousel", type: "registry:ui", title: "Carousel", description: "Native scroll-snap row, so touch, trackpad and no-JS scrolling work, with spring-driven arrows, page dots, arrow keys and mouse drag that throws to the next snap point. APG carousel semantics: a labeled region of slides announced as 3 of 8.", exports: ["Carousel", "CarouselContent", "CarouselItem", "CarouselPrevious", "CarouselNext", "CarouselDots"], keywords: ["accessible", "all", "and", "announced", "any", "apg", "are", "arrow", "basis", "buttons", "carousel", "css", "default", "dot", "dots", "drag", "driven", "edge", "end", "fewer", "from", "gap", "hides", "keys", "label", "labeled", "left", "mouse", "name", "native", "not", "one", "overlaid", "page", "pages", "per", "projects", "region", "rem", "right", "row", "scroll", "scrolling", "semantics", "sized", "slide", "slides", "snap", "spring", "start", "the", "there", "total", "touch", "trackpad", "two", "variables", "view", "with", "work"], registryDependencies: ["button", "utils"] }, { name: "changelog", type: "registry:block", title: "Changelog", description: "Release notes on a Timeline: newest release highlighted, changes typed New / Improved / Fixed with Badges, and a Kbd shortcut to try the headline feature. Server-safe.", exports: ["Changelog"], keywords: ["are", "badges", "changes", "first", "highlighted", "how", "kbd", "newest", "notes", "one", "release", "releases", "shows", "the", "timeline", "try", "typed", "with"], registryDependencies: ["badge", "kbd", "timeline", "utils"] }, { name: "chart", type: "registry:ui", title: "Chart", description: "Line, area and bar (grouped or stacked) charts in SVG with a colorblind-validated eight-color palette that keeps each series' color. Crosshair tooltip listing every series, arrow-key readout, legend that hides series, direct end labels, a table view, and spring transitions between data.", exports: ["Chart"], keywords: ["add", "and", "are", "area", "areas", "arrow", "assistive", "axis", "bar", "bars", "bcp", "can", "captions", "categorical", "category", "chart", "charts", "compact", "crosshair", "currency", "data", "direct", "each", "eight", "end", "every", "filled", "fold", "for", "format", "grouping", "height", "hides", "index", "instead", "into", "key", "keys", "label", "labels", "legend", "line", "lines", "listing", "locale", "mark", "most", "names", "notation", "numbers", "object", "one", "only", "other", "pages", "palette", "past", "per", "plot", "plus", "props", "render", "row", "serializable", "series", "server", "split", "stack", "stacked", "style", "svg", "table", "tail", "tech", "that", "the", "them", "ticks", "too", "tooltip", "type", "usd", "value", "view", "with"], registryDependencies: ["button", "table", "use-dismiss", "utils"] }, { name: "checkbox", type: "registry:ui", title: "Checkbox", description: "Native checkbox with a spring-drawn check mark and an indeterminate state for select-all rows. Controlled or uncontrolled; submits with forms.", exports: ["Checkbox"], keywords: ["all", "called", "check", "checkbox", "checked", "controlled", "dash", "defaultchecked", "drawn", "field", "first", "indeterminate", "inside", "mixed", "native", "new", "oncheckedchange", "pair", "render", "rows", "select", "selected", "shows", "some", "spring", "state", "the", "uncontrolled", "with", "works"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "clip-card", type: "registry:block", title: "Clip Card", description: "Video tile: AspectRatio thumbnail (16:9 or 9:16), duration Badge, watched Progress along the bottom, and a ContextMenu of actions.", exports: ["ClipCard"], keywords: ["accessible", "actions", "ago", "along", "also", "and", "aspectratio", "badge", "bar", "bottom", "card", "click", "clip", "clips", "context", "contextmenuitem", "days", "duration", "f10", "film", "for", "glyph", "height", "how", "img", "items", "menu", "meta", "much", "name", "one", "opens", "print", "progress", "ratio", "right", "shift", "small", "stands", "the", "them", "thin", "thumbnail", "tile", "title", "under", "vertical", "video", "views", "was", "watched", "width", "without"], registryDependencies: ["aspect-ratio", "badge", "context-menu", "progress", "utils"] }, { name: "code", type: "registry:ui", title: "Code", description: "Shiki-highlighted code that follows light and dark through light-dark() token colors, as a block, an inline one-liner or a tabbed file panel. Line numbers (from any start line), tinted lines with an accent bar, <mark>ed words or column ranges, and per-line notes in a tooltip that keyboard users can tab to. Optional Prettier at display time; copy hands out exactly what is shown.", exports: ["CopyButton", "Code", "CodePanel"], keywords: ["accessible", "active", "add", "all", "and", "animates", "annotations", "bar", "bash", "before", "behind", "block", "body", "build", "button", "clipboard", "code", "collapse", "copied", "copy", "dark", "default", "dom", "each", "every", "excerpts", "file", "files", "first", "focus", "fold", "for", "format", "formatted", "from", "gets", "ghost", "gutter", "header", "highlight", "highlightcode", "highlighted", "highlighting", "hover", "ignored", "inline", "inside", "into", "its", "json", "keep", "label", "language", "least", "left", "light", "line", "linenumbers", "lines", "loads", "longer", "made", "many", "mark", "marks", "name", "never", "note", "notes", "number", "numbers", "one", "options", "own", "page", "paint", "panel", "per", "place", "prettier", "primary", "ranges", "refer", "registry", "remember", "renders", "run", "scrolling", "scrolls", "server", "sets", "shared", "shiki", "show", "source", "stays", "switching", "syntax", "tab", "terminal", "text", "than", "that", "the", "themes", "this", "time", "tint", "tokens", "too", "touch", "tsx", "turns", "variant", "vertically", "wheel", "with", "words", "wrapped", "written"], registryDependencies: ["button", "highlight", "overflow-focus", "tabs", "tooltip", "utils"] }, { name: "collapsible", type: "registry:ui", title: "Collapsible", description: "A single show/hide region with a spring height animation and rotating chevron. Controlled or uncontrolled; closed content stays in the DOM for SEO.", exports: ["Collapsible", "CollapsibleTrigger", "CollapsibleContent"], keywords: ["after", "and", "called", "chevron", "children", "closed", "collapsiblecontent", "collapsibletrigger", "content", "controlled", "crawlable", "default", "defaultopen", "first", "height", "hide", "html", "inert", "label", "mounted", "one", "onopenchange", "open", "pair", "region", "remains", "render", "rotating", "show", "springs", "state", "stays", "that", "the", "toggles", "trigger", "true", "uncontrolled", "when", "while", "with"], registryDependencies: ["use-controllable-state", "utils"] }, { name: "combobox", type: "registry:ui", title: "Combobox", description: "A Select you can type into: the query filters by label and keywords (prefix matches first), arrows move, Enter picks. multiple keeps the list open and shows picks as removable tags. Submits and validates with the form.", exports: ["Combobox"], keywords: ["accessible", "and", "aria", "backspace", "blocks", "called", "can", "choices", "closes", "controlled", "defaultvalue", "describedby", "disabled", "down", "emptytext", "enter", "entry", "error", "esc", "every", "field", "fills", "filtered", "filters", "first", "form", "from", "hint", "ids", "input", "into", "invalid", "isn", "keeps", "label", "last", "list", "matches", "move", "multiple", "name", "needs", "nothing", "one", "onto", "onvaluechange", "open", "opening", "options", "pair", "per", "pick", "picked", "picks", "placeholder", "removable", "removes", "render", "required", "select", "sets", "show", "shown", "shows", "single", "stay", "styling", "submit", "submitted", "tags", "text", "the", "them", "there", "type", "types", "typing", "uncontrolled", "user", "value", "values", "visible", "walks", "when", "with", "you"], registryDependencies: ["field", "form-value", "list", "platform", "tag-input", "use-anchor", "use-controllable-state", "use-dismiss", "utils"] }, { name: "command", type: "registry:ui", title: "Command", description: "⌘K palette: filterable groups, arrow-key highlight, Enter to run, keyword matching. Inline or as CommandDialog with a global shortcut; the first Esc clears, the second closes.", exports: ["Command", "CommandInput", "CommandList", "CommandEmpty", "CommandGroup", "CommandSeparator", "CommandItem", "CommandDialog"], keywords: ["accessible", "after", "against", "and", "arrows", "but", "called", "children", "click", "close", "closes", "collapse", "command", "commanddialog", "commandempty", "commandinput", "commanditem", "commandlist", "content", "controlled", "ctrl", "defaults", "dialog", "disable", "disabled", "driven", "elsewhere", "end", "enter", "esc", "extra", "false", "filterable", "filtering", "for", "global", "group", "groups", "heading", "hidden", "hides", "home", "icon", "inline", "input", "inside", "item", "items", "its", "itself", "keepopen", "keyboard", "keywords", "label", "list", "listbox", "mac", "match", "matched", "matches", "mod", "move", "name", "none", "not", "only", "onopenchange", "onselect", "open", "option", "outside", "own", "pair", "palette", "pass", "passes", "placeholder", "preferences", "query", "results", "scrollable", "search", "selectable", "selecting", "selection", "selects", "separators", "settings", "shortcut", "shown", "shows", "stack", "state", "stay", "terms", "text", "the", "title", "toggle", "toggled", "use", "used", "value", "visible", "visually", "when", "while", "with", "would"], registryDependencies: ["dialog", "list", "search-input", "separator", "use-controllable-state", "use-hotkey", "utils"] }, { name: "confirm", type: "registry:ui", title: "Confirm", description: "Promise-based confirm dialog called like toast: await confirm({ title, description, destructive }) resolves true or false. Built on Dialog's alert mode, Cancel takes the first focus, Esc cancels, one host mounted in the layout.", exports: ["confirm", "Confirmer"], keywords: ["acting", "asks", "await", "before", "cancel", "confirm", "confirmer", "delete", "destructive", "esc", "false", "for", "host", "layout", "mount", "mounted", "needs", "newer", "next", "once", "project", "remove", "resolves", "root", "title", "toaster", "true"], registryDependencies: ["button", "dialog"] }, { name: "context-menu", type: "registry:ui", title: "Context Menu", description: "Right-click menu for an area, opening at the pointer and flipping at screen edges. Shares Dropdown Menu's items, checkbox and radio items, keyboard and typeahead; Menu key or Shift+F10 opens it from the keyboard.", exports: ["ContextMenuContent", "ContextMenuItem", "ContextMenuCheckboxItem", "ContextMenuRadioGroup", "ContextMenuRadioItem", "ContextMenuLabel", "ContextMenuSeparator", "ContextMenu", "ContextMenuTrigger"], keywords: ["actions", "align", "aligned", "and", "area", "but", "called", "center", "check", "checked", "children", "click", "clickable", "closes", "contextmenucontent", "contextmenutrigger", "destructive", "disabled", "dropdownmenuradioitem", "edge", "enter", "equals", "f10", "first", "focus", "focusable", "for", "group", "groups", "hint", "icon", "irreversible", "item", "items", "its", "key", "keyboard", "label", "labels", "leading", "lines", "mark", "menu", "new", "not", "oncheckedchange", "onopenchange", "onselect", "onvaluechange", "opens", "optionally", "picked", "pointer", "press", "red", "right", "selectable", "separators", "shift", "shortcut", "shown", "shows", "state", "the", "then", "trigger", "value", "variant", "when", "with"], registryDependencies: ["dropdown-menu", "utils"] }, { name: "count-to", type: "registry:ui", title: "CountTo", description: "Springs a number up from a start value once it scrolls into view. Prefix, suffix, decimals and locale.", exports: ["CountTo"], keywords: ["after", "and", "bcp", "before", "decimal", "decimals", "digits", "dom", "final", "for", "from", "grouping", "into", "locale", "number", "once", "point", "prefix", "scrolls", "seo", "springs", "starting", "stays", "suffix", "text", "the", "value", "view"], registryDependencies: ["utils"] }, { name: "custom-cursor", type: "registry:ui", title: "Custom Cursor", description: "Optional spring cursor that expands over interactive elements. Off on touch and reduced motion.", exports: ["CustomCursor"], keywords: ["coarse", "cursor", "dot", "elements", "expands", "interactive", "motion", "mount", "nothing", "once", "opt", "over", "pointers", "reduced", "renders", "ring", "spring", "touch", "trailing", "with"], registryDependencies: ["platform", "utils"] }, { name: "data-table", type: "registry:ui", title: "Data Table", description: "Table with columns as data: search across every column, sortable headers, checkbox selection that survives paging, a ⋯ menu per row, bulk actions in the toolbar and pagination. Built from Table, SearchInput, Checkbox, DropdownMenu, Pagination and Empty.", exports: ["DataTable"], keywords: ["accessor", "across", "actions", "all", "alternate", "and", "are", "backgrounds", "box", "bulk", "called", "cell", "checkbox", "client", "column", "columns", "compose", "controlled", "controls", "data", "defaultsort", "definitions", "display", "driven", "dropdownmenuitem", "each", "every", "field", "filters", "first", "for", "friends", "getrowid", "happen", "header", "ids", "items", "its", "jane", "kept", "label", "members", "menu", "name", "names", "onselectionchange", "order", "page", "pages", "pagesize", "pagination", "paging", "pair", "per", "placeholder", "readers", "receives", "render", "right", "row", "rowactions", "rowlabel", "rows", "screen", "search", "searchable", "searchplaceholder", "select", "selectable", "selected", "selection", "server", "show", "side", "sort", "sortable", "stable", "striped", "survives", "table", "that", "the", "toolbar", "with", "yourself"], registryDependencies: ["button", "checkbox", "dropdown-menu", "empty", "pagination", "search-input", "table", "use-controllable-state", "utils"] }, { name: "date-picker", type: "registry:ui", title: "Date Picker", description: "Field-styled button that opens a Calendar in a Popover, focused on the picked day. Single or range, presets such as Last 7 days, closes once the pick is complete, and submits ISO dates with the form. Works inside Field.", exports: ["DatePicker"], keywords: ["accessible", "and", "are", "aria", "bcp", "beside", "blocks", "both", "button", "calendar", "called", "client", "closes", "controlled", "date", "day", "days", "default", "defaultvalue", "describedby", "disabled", "earliest", "end", "ends", "error", "extra", "field", "fill", "fills", "first", "focused", "for", "form", "from", "function", "grid", "hint", "htmlfor", "ids", "invalid", "isdisabled", "isn", "iso", "label", "last", "latest", "let", "locale", "max", "min", "mode", "monday", "name", "needs", "nothing", "null", "off", "once", "one", "only", "onvaluechange", "opening", "opens", "optional", "pair", "pick", "picked", "placeholder", "popover", "presets", "range", "reach", "readers", "ready", "render", "required", "rule", "saturday", "selectable", "set", "sets", "shortcuts", "single", "start", "styled", "styling", "submit", "submits", "submitted", "sunday", "text", "that", "the", "then", "there", "these", "today", "uncontrolled", "value", "visible", "weekends", "weekstartson", "when", "with"], registryDependencies: ["calendar", "field", "form-value", "input", "popover", "use-controllable-state", "utils"] }, { name: "dialog", type: "registry:ui", title: "Dialog", description: "Portal modal with blurred backdrop, spring scale-in, focus trap, Esc and scroll lock.", exports: ["useDialog", "Dialog", "DialogTrigger", "DialogClose", "useModal", "DialogContent", "DialogHeader", "DialogFooter", "DialogTitle", "DialogDescription"], keywords: ["action", "alert", "alertdialog", "also", "and", "aria", "armed", "attach", "backdrop", "before", "behavior", "blur", "blurred", "body", "both", "button", "called", "can", "check", "children", "click", "clicks", "close", "confirm", "confirmlabel", "confirmtimeout", "controlled", "corner", "default", "defaultopen", "defaults", "destructive", "dialog", "dialogclose", "dialogcontent", "dialogs", "dialogtrigger", "does", "done", "drawer", "emphasis", "enter", "esc", "feedback", "field", "fill", "first", "focus", "focusable", "footer", "for", "form", "give", "header", "height", "icon", "ignore", "ignores", "irreversible", "its", "label", "left", "loading", "loadinglabel", "lock", "modal", "mode", "never", "not", "off", "old", "onclick", "one", "ones", "only", "onopenchange", "open", "out", "padding", "page", "pair", "panel", "per", "place", "portal", "primary", "ref", "render", "reserved", "resets", "resize", "restore", "returned", "role", "root", "runs", "scale", "scroll", "second", "shared", "showclose", "shown", "shows", "size", "slides", "spinner", "spins", "spring", "square", "state", "status", "stays", "step", "submit", "success", "successlabel", "swap", "swaps", "tab", "text", "the", "this", "topmost", "trap", "trigger", "twice", "two", "uncontrolled", "variant", "view", "where", "while", "width", "with"], registryDependencies: ["button", "focus", "platform", "use-controllable-state", "utils"] }, { name: "drawer", type: "registry:ui", title: "Drawer", description: "Edge panel (left, right, top, bottom) that springs in and swipes away. Shares Dialog's focus trap, scroll lock and Esc handling. Sidebar uses it below md.", exports: ["Drawer", "DrawerTrigger", "DrawerClose", "DrawerTitle", "DrawerDescription", "DrawerContent", "DrawerHeader", "DrawerBody", "DrawerFooter"], keywords: ["action", "also", "and", "anywhere", "aria", "armed", "backdrop", "before", "blur", "body", "both", "bottom", "button", "called", "can", "check", "children", "click", "clicks", "close", "confirm", "confirmlabel", "confirmtimeout", "content", "controlled", "corner", "default", "defaultopen", "defaults", "destructive", "dialogclose", "dialogcontent", "dialogtrigger", "dismiss", "done", "drag", "drawer", "drawers", "edge", "emphasis", "enter", "esc", "feedback", "fill", "first", "focusable", "footer", "for", "form", "from", "give", "handle", "header", "height", "icon", "ignore", "ignores", "irreversible", "its", "label", "left", "loading", "loadinglabel", "never", "old", "onclick", "one", "ones", "onopenchange", "open", "out", "padding", "pair", "panel", "per", "place", "primary", "render", "reserved", "resets", "resize", "runs", "scroll", "scrolls", "second", "showclose", "shown", "shows", "side", "size", "slides", "spinner", "spins", "spring", "square", "state", "status", "stays", "step", "submit", "success", "successlabel", "swap", "swaps", "swipe", "taller", "text", "than", "that", "the", "their", "this", "top", "toward", "trigger", "twice", "two", "uncontrolled", "variant", "view", "when", "where", "while", "width", "with"], registryDependencies: ["dialog", "platform", "utils"] }, { name: "dropdown-menu", type: "registry:ui", title: "Dropdown Menu", description: "Action menu anchored to a Button: items with icons and shortcuts, checkbox and radio items, labels, separators, destructive variant. Arrow keys, typeahead, focus follows the pointer, Esc returns focus.", exports: ["MenuContext", "DropdownMenu", "DropdownMenuTrigger", "DropdownMenuContent", "DropdownMenuItem", "DropdownMenuCheckboxItem", "DropdownMenuRadioGroup", "DropdownMenuRadioItem", "DropdownMenuLabel", "DropdownMenuSeparator"], keywords: ["action", "actions", "align", "aligned", "also", "anchored", "and", "aria", "armed", "before", "blur", "both", "but", "button", "called", "can", "check", "checked", "children", "choice", "click", "clicks", "closes", "closing", "confirm", "confirmlabel", "confirmtimeout", "content", "controlled", "default", "defaultopen", "defaults", "destructive", "disabled", "done", "down", "dropdownmenuradioitem", "edge", "emphasis", "enter", "equals", "esc", "feedback", "fill", "first", "focusable", "for", "form", "give", "group", "groups", "height", "hint", "icon", "ignore", "ignores", "irreversible", "item", "items", "its", "keeps", "keyboard", "label", "labels", "last", "leading", "left", "lines", "loading", "loadinglabel", "mark", "menu", "never", "new", "not", "old", "oncheckedchange", "onclick", "one", "ones", "onopenchange", "onselect", "onvaluechange", "open", "opens", "optionally", "out", "outside", "padding", "pair", "per", "picked", "picking", "place", "primary", "radiogroup", "red", "render", "reserved", "resets", "resize", "right", "runs", "second", "selectable", "selection", "separators", "shortcut", "shown", "shows", "size", "slides", "space", "spinner", "spins", "square", "state", "status", "stays", "step", "submit", "success", "successlabel", "swap", "swaps", "text", "the", "then", "this", "toggles", "trigger", "twice", "two", "uncontrolled", "value", "variant", "view", "when", "where", "while", "width", "with", "without"], registryDependencies: ["button", "list", "platform", "use-anchor", "use-controllable-state", "use-dismiss", "utils"] }, { name: "empty", type: "registry:ui", title: "Empty", description: "Server-safe empty state: icon tile, title, one helpful sentence and the next action. Bordered variant for empty lists and drop zones.", exports: ["Empty"], keywords: ["about", "action", "and", "app", "area", "bordered", "children", "clips", "dashed", "description", "drop", "empty", "for", "helpful", "icon", "inside", "like", "list", "next", "one", "outline", "page", "rounded", "sentence", "shown", "state", "the", "tile", "title", "what", "yet", "zone"], registryDependencies: ["utils"] }, { name: "field", type: "registry:ui", title: "Field", description: "Label, control, description and error as one unit. Controls inside (Input, Textarea, Select, Checkbox, Switch, RadioGroup) get id, aria-describedby, aria-invalid and required automatically; errors spring in and are announced.", exports: ["useFieldControl", "useFieldLabel", "Field"], keywords: ["and", "aria", "automatically", "beside", "can", "checkbox", "children", "control", "controls", "describedby", "description", "dims", "disabled", "disables", "enclosing", "error", "explicit", "field", "fieldset", "fills", "first", "for", "form", "from", "group", "have", "hint", "horizontal", "ids", "input", "invalid", "its", "label", "makes", "marks", "match", "must", "names", "one", "orientation", "out", "outside", "own", "picks", "props", "radiogroup", "rating", "renders", "required", "returns", "shown", "single", "springs", "state", "switch", "target", "the", "unchanged", "under", "unit", "use", "when", "which", "win", "wired", "with"], registryDependencies: ["label", "utils"] }, { name: "focus", type: "registry:lib", description: "What Tab reaches inside `root`, in order. Skips disabled and hidden fields, tabIndex -1 (a\nFormValue helper) and all but one radio per group, so the first and last are real stops.", exports: ["tabbables"], keywords: ["all", "and", "are", "but", "disabled", "fields", "first", "formvalue", "group", "helper", "hidden", "inside", "last", "one", "order", "per", "radio", "reaches", "real", "root", "skips", "stops", "tab", "tabindex", "the", "what"], registryDependencies: [] }, { name: "form-value", type: "registry:lib", description: "Submits a custom control's value and takes part in native validation, which a hidden input\ncan't: an empty `required` value blocks submit, shows the browser's message and focuses `anchor`.", exports: ["FormValue", "useFormReset"], keywords: ["action", "after", "anchor", "and", "back", "blocks", "browser", "button", "called", "calls", "can", "control", "controlled", "custom", "default", "disabled", "does", "empty", "field", "finds", "focus", "focuses", "form", "gets", "goes", "hidden", "input", "invalid", "its", "leaves", "like", "message", "name", "native", "nothing", "oninvalid", "only", "onreset", "onvaluechange", "out", "parent", "part", "picked", "react", "reports", "required", "reset", "resets", "shows", "skips", "state", "submit", "submits", "succeeds", "takes", "that", "the", "there", "through", "too", "validation", "value", "visible", "when", "which", "without"], registryDependencies: [] }, { name: "highlight", type: "registry:lib", description: "Lines of colored tokens, with Shiki loaded on demand. Runs anywhere: Code calls it in the\nbrowser, and a Server Component or a build can call it ahead of time and pass the result as\n`tokens`, so the browser never loads Shiki. Null for unknown languages.", exports: ["highlightCode", "languageOf"], keywords: ["ahead", "and", "anywhere", "back", "browser", "build", "call", "calls", "can", "code", "colored", "component", "demand", "extension", "falls", "file", "for", "from", "language", "languages", "lines", "loaded", "loads", "name", "never", "null", "pass", "result", "runs", "server", "shiki", "the", "time", "tokens", "tsx", "unknown", "with"], registryDependencies: [] }, { name: "hover-card", type: "registry:ui", title: "Hover Card", description: "Rich preview (profile, product, clip) that opens after a hover delay or keyboard focus. The pointer can move into the card; supplementary only.", exports: ["HoverCard"], keywords: ["acts", "align", "alignment", "avatar", "before", "bio", "can", "card", "children", "clip", "closedelay", "closes", "content", "first", "flips", "focus", "hover", "into", "keyboard", "leaves", "link", "move", "must", "once", "only", "opendelay", "opens", "pointer", "preferred", "preview", "product", "profile", "rich", "room", "second", "side", "stats", "supplementary", "tap", "the", "there", "time", "touch", "trigger", "usually", "when", "with", "without", "work"], registryDependencies: ["platform", "use-anchor", "use-dismiss", "use-hover-open", "utils"] }, { name: "input", type: "registry:ui", title: "Forms", description: "Input, Textarea, Label and Switch: smooth focus rings, native :user-invalid validation (red only after interaction), aria-invalid, auto-growing textarea with an optional character count, and a spring switch.", exports: ["fieldClass", "Input"], keywords: ["and", "aria", "chrome", "field", "filled", "group", "handed", "inputgroup", "inside", "the", "works"], registryDependencies: ["field", "utils"] }, { name: "input-group", type: "registry:ui", title: "Input Group", description: "Server-safe wrapper that fuses an Input with icons, text (https://, USD) or buttons into one field with a shared border and focus ring. Clicking an addon focuses the input.", exports: ["InputGroup", "InputGroupAddon"], keywords: ["addons", "align", "and", "beside", "border", "button", "buttons", "clicking", "control", "data", "draws", "drops", "field", "focus", "focuses", "group", "https", "icon", "icons", "inner", "input", "its", "like", "made", "matched", "one", "own", "plain", "plus", "ring", "side", "sits", "slot", "text", "the"], registryDependencies: ["utils"] }, { name: "input-otp", type: "registry:ui", title: "Input OTP", description: "One-time code in separate slots, backed by one real input: paste and SMS autofill work, screen readers hear one field. Grouped slots, numeric or alphanumeric, characters spring in, onComplete to submit. verified turns each character into a check, then merges them into one mark.", exports: ["InputOTP"], keywords: ["accepted", "again", "allowed", "alphanumeric", "and", "announced", "are", "autocomplete", "autofill", "back", "beside", "between", "called", "change", "character", "characters", "charset", "check", "code", "controlled", "counts", "dash", "defaultvalue", "draws", "dropped", "each", "edit", "every", "false", "filled", "fires", "first", "for", "group", "groups", "input", "into", "label", "laid", "length", "mark", "merge", "merged", "number", "once", "oncomplete", "one", "only", "onvaluechange", "others", "over", "pair", "paste", "pasted", "per", "read", "readers", "real", "render", "screen", "set", "shown", "single", "sits", "slides", "slot", "slots", "sms", "submit", "the", "then", "time", "transparently", "turns", "typed", "uncontrolled", "uppercased", "value", "verified", "verifiedlabel", "via", "visual", "was", "with"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "kbd", type: "registry:ui", title: "Kbd", description: "Server-safe key caps for shortcut hints. KbdGroup nests keys per the HTML spec.", exports: ["Kbd", "KbdGroup"], keywords: ["cap", "html", "kbd", "kbdgroup", "key", "keys", "made", "nested", "one", "per", "several", "shortcut", "spec", "the"], registryDependencies: ["utils"] }, { name: "label", type: "registry:ui", title: "Forms", description: "Input, Textarea, Label and Switch: smooth focus rings, native :user-invalid validation (red only after interaction), aria-invalid, auto-growing textarea with an optional character count, and a spring switch.", exports: ["Label"], keywords: [], registryDependencies: ["utils"] }, { name: "list", type: "registry:lib", description: "The item a navigation key moves to in a list, from the item at `index` (-1: none active).\nUndefined when the key doesn't navigate.", exports: ["listKeyTarget", "scrollIntoList"], keywords: ["active", "box", "can", "doesn", "enough", "from", "index", "item", "just", "key", "list", "moves", "moving", "navigate", "navigation", "none", "page", "scrollintoview", "scrolls", "show", "the", "undefined", "way", "when", "without"], registryDependencies: ["utils"] }, { name: "marker", type: "registry:ui", title: "Marker", description: "Highlighter-pen <mark> in four tints that wraps cleanly across lines and can draw itself on, left to right, when it scrolls into view. Highlight marks every match of a search in a string, for transcripts and search results.", exports: ["Marker", "Highlight"], keywords: ["across", "before", "case", "cleanly", "color", "delay", "draw", "drawing", "draws", "every", "first", "full", "fully", "highlight", "highlighter", "insensitive", "inside", "instant", "into", "left", "lines", "mark", "markers", "marks", "match", "motion", "one", "paragraph", "pen", "query", "reduced", "right", "scrolls", "search", "seconds", "several", "shown", "stagger", "sweeps", "term", "terms", "text", "the", "time", "view", "with", "without", "wraps"], registryDependencies: ["utils"] }, { name: "menubar", type: "registry:ui", title: "Menubar", description: "Desktop-style menu bar on the WAI-ARIA menubar pattern: one menu open at a time, hovering the next title while one is open switches to it, ← → walk the bar with or without a menu open, one Tab stop. A single highlight springs between titles; menus reuse every DropdownMenu item.", exports: ["MenubarContent", "MenubarItem", "MenubarCheckboxItem", "MenubarRadioGroup", "MenubarRadioItem", "MenubarLabel", "MenubarSeparator", "Menubar", "MenubarMenu", "MenubarTrigger"], keywords: ["actions", "align", "aligned", "analytics", "and", "another", "apart", "bar", "between", "but", "called", "check", "checked", "children", "click", "closes", "desktop", "destructive", "disabled", "down", "dropdownmenuradioitem", "edge", "enter", "equals", "first", "for", "generated", "give", "group", "groups", "highlight", "hint", "hovering", "icon", "irreversible", "item", "items", "its", "label", "labels", "last", "leading", "left", "lines", "mark", "menu", "menubarcontent", "menubartrigger", "menus", "move", "new", "not", "omitted", "oncheckedchange", "one", "onselect", "onvaluechange", "open", "opens", "optional", "optionally", "picked", "red", "right", "selectable", "separators", "shortcut", "shown", "shows", "space", "springs", "stable", "state", "style", "switches", "tell", "tests", "the", "then", "time", "title", "titles", "toggles", "trigger", "value", "variant", "when", "while", "with"], registryDependencies: ["dropdown-menu", "list", "use-indicator", "utils"] }, { name: "message-bubble", type: "registry:ui", title: "Message Bubble", description: "User/assistant chat bubbles with avatar slot, streaming dots and copyable code blocks.", exports: ["MessageBubble"], keywords: ["above", "accent", "after", "and", "animated", "are", "assistant", "attachments", "avatar", "bubble", "chat", "children", "code", "content", "dots", "from", "inline", "left", "lists", "message", "name", "next", "rich", "right", "sender", "shown", "shows", "side", "size", "slot", "streaming", "surface", "text", "the", "time", "typing", "user"], registryDependencies: ["utils"] }, { name: "meter", type: "registry:ui", title: "Meter", description: "Server-safe gauge for a value in a known range (storage, quota, server load, password strength). Colors by <meter> thresholds, or stacked segments with a legend, like a storage bar.", exports: ["Meter"], keywords: ["above", "accessible", "also", "and", "away", "bar", "below", "between", "bound", "color", "colors", "decides", "defaults", "disk", "follow", "good", "green", "high", "known", "label", "legend", "like", "load", "low", "lower", "max", "measurement", "meter", "min", "name", "not", "one", "optimum", "orange", "overrides", "parts", "password", "progress", "quota", "range", "red", "region", "right", "segments", "server", "stacked", "storage", "strength", "sum", "task", "text", "the", "their", "this", "threshold", "thresholds", "total", "two", "upper", "use", "used", "value", "valuetext", "visible", "where", "with", "within"], registryDependencies: ["utils"] }, { name: "motion-provider", type: "registry:component", exports: ["MotionProvider"], keywords: [], registryDependencies: ["utils"] }, { name: "native-select", type: "registry:ui", title: "Native Select", description: "A real <select> with option groups: native picker on phones, no-JS forms, native required validation. Where customizable select is supported (appearance: base-select), the open list gets the menu look.", exports: ["NativeSelect", "NativeSelectGroup", "NativeSelectOption"], keywords: ["appearance", "base", "browser", "custom", "customizable", "elsewhere", "forms", "gets", "group", "heading", "icons", "instead", "invalid", "label", "labeled", "list", "look", "menu", "native", "need", "open", "optgroup", "options", "phones", "picker", "real", "rendering", "required", "select", "stays", "supports", "the", "use", "user", "validation", "when", "where", "without", "works"], registryDependencies: ["field", "input", "utils"] }, { name: "navigation-menu", type: "registry:ui", title: "Navigation Menu", description: "Website top navigation on the APG disclosure pattern: plain links and panels of rich links. Hover opens after a beat, then sliding along the bar switches panels at once; every panel shares one viewport that springs to the next panel's size and position while the content slides in from the side you moved toward. Click, Enter, ↓, ← → and Esc work; closed panels keep their links in the HTML for crawlers.", exports: ["NavigationMenu", "NavigationMenuList", "NavigationMenuItem", "NavigationMenuTrigger", "NavigationMenuContent", "NavigationMenuLink"], keywords: ["active", "after", "all", "along", "and", "aria", "bar", "beat", "bold", "called", "children", "classname", "click", "closed", "closes", "content", "controlled", "crawlers", "current", "defaultvalue", "description", "down", "enter", "entry", "esc", "find", "first", "focuses", "following", "for", "generated", "hidden", "hover", "html", "icon", "inset", "into", "item", "items", "its", "left", "level", "line", "link", "links", "look", "matched", "menu", "mouse", "muted", "navigation", "omitted", "once", "one", "onvaluechange", "open", "opened", "opens", "optional", "own", "padding", "page", "pair", "panel", "panels", "pill", "plain", "readers", "rem", "render", "rich", "right", "row", "selected", "single", "size", "sliding", "space", "springs", "stable", "stay", "still", "switches", "the", "them", "then", "tile", "title", "toggle", "top", "trigger", "uncontrolled", "under", "value", "viewport", "walk", "website", "while", "with", "your"], registryDependencies: ["focus", "use-controllable-state", "use-dismiss", "use-indicator", "utils"] }, { name: "newsletter", type: "registry:block", title: "Newsletter", description: "Email signup: InputGroup with the submit Button inside, native email validation, a loading → success toast and an in-place success state on the button.", exports: ["Newsletter"], keywords: ["above", "address", "after", "and", "button", "check", "confirm", "confirms", "description", "email", "field", "for", "form", "heading", "inbox", "inputgroup", "inside", "into", "its", "line", "loading", "message", "native", "next", "onsubscribe", "place", "placeholder", "rejection", "resets", "resolves", "saved", "shows", "signup", "submit", "submitlabel", "success", "successmessage", "supporting", "text", "that", "the", "then", "title", "toast", "turns", "under", "validation", "when", "with", "your"], registryDependencies: ["button", "input", "input-group", "toast", "utils"] }, { name: "number-input", type: "registry:ui", title: "Number Input", description: "Native number field with −/+ buttons: arrow keys, min/max/step validation and form submit from the platform; clamps on blur, rounds to the step's precision.", exports: ["NumberInput"], keywords: ["amount", "and", "are", "arrows", "arrowup", "buttons", "called", "cart", "change", "controlled", "defaultvalue", "down", "field", "first", "form", "helpers", "highest", "keyboard", "lowest", "max", "min", "native", "new", "number", "onvaluechange", "pair", "pointer", "quantity", "render", "step", "submit", "tabindex", "the", "uncontrolled", "use", "users", "validation", "value", "with"], registryDependencies: ["form-value", "input", "input-group", "use-controllable-state", "utils"] }, { name: "overflow-focus", type: "registry:lib", description: `Drop inside a scroll container: while the container overflows it becomes keyboard-focusable
|
|
17723
17900
|
(tabIndex 0) so arrow keys can scroll it, and it leaves the tab order again once it fits.
|
|
17724
|
-
Renders a hidden span, so server components (Table) can use it as a child.`, exports: ["OverflowFocus"], keywords: ["again", "and", "arrow", "becomes", "can", "child", "components", "container", "drop", "fits", "focusable", "hidden", "inside", "keyboard", "keys", "leaves", "once", "order", "overflows", "renders", "scroll", "server", "span", "tab", "tabindex", "table", "the", "use", "while"], registryDependencies: [] }, { name: "pagination", type: "registry:ui", title: "Pagination", description: "Server-safe page links from page and total: previous/next, ellipsis gaps and a sliding active pill, with numbers that swipe the way you moved. Links by default; buttons with onPageChange. The row keeps a fixed width so it never jumps.", exports: ["Pagination", "pageRange"], keywords: ["active", "always", "and", "arrows", "bar", "become", "between", "buttons", "called", "changes", "client", "controls", "current", "default", "each", "ellipsis", "first", "for", "from", "gaps", "href", "index", "instead", "items", "its", "keeps", "kept", "key", "labels", "last", "length", "links", "mounted", "moved", "never", "next", "number", "numbers", "one", "only", "onpagechange", "page", "pagerange", "pages", "parents", "phones", "picked", "pill", "previous", "remounting", "render", "returns", "row", "same", "show", "siblings", "side", "slides", "slot", "stays", "swipe", "swipes", "text", "that", "the", "total", "unused", "url", "way", "width", "with", "without", "work", "you"], registryDependencies: ["button-variants", "pagination-motion", "utils"] }, { name: "pagination-motion", type: "registry:ui", description: "Scopes the active pill's `layoutId` so several paginations on a page don't share it.", exports: ["PaginationMotion", "PaginationActivePill", "PaginationNumber"], keywords: ["active", "behind", "changes", "children", "direction", "don", "from", "items", "its", "layoutid", "link", "moved", "next", "number", "outline", "page", "pagination", "paginations", "pill", "scopes", "several", "share", "side", "slot", "springs", "swipes", "that", "the", "toward", "travel", "value", "when"], registryDependencies: ["utils"] }, { name: "platform", type: "registry:lib", description: "False on the server and during hydration, true after: gates portals and other client-only output.", exports: ["useMounted", "useIsMac", "useMediaQuery"], keywords: ["after", "and", "assumes", "client", "corrects", "ctrl", "during", "false", "gates", "hydration", "live", "match", "media", "not", "only", "other", "output", "portals", "query", "render", "server", "shortcuts", "ssr", "the", "then", "true", "use", "where"], registryDependencies: [] }, { name: "popover", type: "registry:ui", title: "Popover", description: "Non-modal panel anchored to a Button for filters, pickers and quick edits. Focus moves in, Esc returns it, outside clicks close; Selects and menus opened inside don't count as outside.", exports: ["Popover", "PopoverTrigger", "PopoverContent"], keywords: ["above", "action", "align", "alignment", "also", "anchored", "and", "any", "aria", "armed", "before", "blur", "both", "button", "called", "can", "check", "children", "click", "clicks", "closed", "closes", "confirm", "confirmlabel", "confirmtimeout", "content", "controlled", "default", "defaultopen", "defaults", "destructive", "done", "edits", "emphasis", "end", "enter", "esc", "feedback", "field", "fill", "filters", "first", "flips", "focus", "focusable", "for", "form", "from", "give", "height", "icon", "ignore", "ignores", "irreversible", "its", "keep", "label", "left", "like", "loading", "loadinglabel", "modal", "moves", "never", "non", "not", "old", "onclick", "one", "ones", "onopenchange", "open", "out", "outside", "padding", "pair", "panel", "past", "per", "pickers", "place", "popovercontent", "popovertrigger", "popup", "preferred", "primary", "quick", "render", "reserved", "resets", "resize", "returns", "room", "runs", "second", "shift", "shown", "shows", "side", "size", "slides", "spinner", "spins", "square", "state", "status", "stays", "step", "submit", "success", "successlabel", "swap", "swaps", "tab", "text", "the", "there", "this", "trap", "trigger", "twice", "two", "uncontrolled", "unmount", "values", "variant", "view", "when", "where", "while", "width", "with"], registryDependencies: ["button", "focus", "platform", "use-anchor", "use-controllable-state", "use-dismiss", "utils"] }, { name: "pricing", type: "registry:block", title: "Pricing", description: "Plan cards with a monthly / yearly segmented switch. Prices roll on a spring in the direction they moved; the featured plan is outlined in the accent. Card, Badge, ToggleGroup, Button.", exports: ["Pricing"], keywords: ["and", "bcp", "billing", "cards", "code", "currency", "defaultperiod", "display", "down", "drop", "eur", "first", "for", "formatting", "iso", "locale", "monthly", "next", "number", "order", "period", "plan", "plans", "price", "prices", "render", "rise", "rolling", "segmented", "selected", "spring", "swap", "switch", "the", "they", "togglegroup", "when", "with", "yearly", "yearlynote"], registryDependencies: ["badge", "card", "toggle-group", "utils"] }, { name: "product-card", type: "registry:block", title: "Product Card", description: "Shop tile: photos in an AspectRatio (a swipeable Carousel with dots when there are several), sale price, Badge and add-to-cart Button.", exports: ["ProductCard"], keywords: ["add", "addlabel", "are", "aspectratio", "badge", "bcp", "become", "button", "called", "card", "carousel", "code", "compareat", "currency", "current", "dots", "for", "formatting", "heading", "height", "href", "img", "iso", "label", "link", "locale", "major", "media", "name", "new", "number", "onaddtocart", "one", "original", "over", "page", "per", "photos", "pressed", "price", "product", "ratio", "sale", "several", "shop", "shows", "slide", "small", "square", "struck", "swipeable", "text", "the", "there", "through", "tile", "units", "when", "width", "with"], registryDependencies: ["aspect-ratio", "badge", "button", "carousel", "utils"] }, { name: "progress", type: "registry:ui", title: "Progress", description: "Accent bar that springs to each new value, with an optional label and percentage. Leave out value for an indeterminate sweep (static under reduced motion).", exports: ["Progress"], keywords: ["above", "accent", "accessible", "across", "allowed", "also", "aria", "bar", "colored", "duration", "each", "for", "frame", "indeterminate", "infinite", "its", "label", "layout", "max", "motion", "name", "new", "next", "omit", "one", "per", "percentage", "reduced", "scalex", "segment", "show", "showvalue", "size", "springs", "static", "sweeps", "that", "the", "there", "thickness", "tween", "under", "unknown", "value", "visible", "when", "work"], registryDependencies: ["utils"] }, { name: "quote", type: "registry:ui", title: "Quote", description: "Semantic figure, blockquote and figcaption. Plain, card and large variants, with author, subtitle, avatar, lang, typewriter and textSwap.", exports: ["Quote"], keywords: ["accent", "alt", "and", "array", "author", "avatar", "blockquote", "card", "children", "correct", "custom", "cycles", "delay", "display", "doe", "effect", "enables", "fades", "figcaption", "figure", "for", "into", "jane", "job", "lang", "language", "large", "line", "mark", "options", "pass", "plain", "pronunciation", "quote", "quoted", "quotes", "reader", "said", "screen", "scrolls", "secondary", "semantic", "seo", "size", "slot", "speed", "spring", "string", "strings", "subtitle", "supports", "surface", "swap", "text", "textswap", "the", "through", "title", "transitions", "typewriter", "under", "variant", "view", "when", "who", "with", "work", "wrote"], registryDependencies: ["text-swap", "typewriter", "utils"] }, { name: "radio-group", type: "registry:ui", title: "Radio Group", description: "Native radios in a fieldset with a legend: browser arrow keys and form submit, a dot that springs in, optional per-option descriptions, vertical or horizontal.", exports: ["RadioGroup", "RadioGroupItem"], keywords: ["adds", "and", "application", "aria", "arrow", "browser", "but", "called", "children", "conform", "controlled", "defaultvalue", "description", "disabled", "does", "enclosing", "entered", "expected", "field", "fieldset", "first", "form", "format", "generated", "group", "indicates", "invalid", "item", "items", "its", "keys", "label", "labels", "lay", "legend", "line", "muted", "name", "names", "native", "needs", "not", "omitted", "one", "onvaluechange", "option", "orientation", "pair", "picked", "radios", "render", "rendered", "required", "row", "selectable", "shown", "stack", "submit", "submitted", "the", "them", "uncontrolled", "under", "value", "visible", "when", "with", "without", "work"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "rating", type: "registry:ui", title: "Rating", description: "Star rating on native radios (arrow keys, forms) with hover preview, or readOnly display with fractional stars for averages.", exports: ["Rating"], keywords: ["and", "aria", "arrow", "called", "can", "chosen", "controlled", "defaults", "defaultvalue", "describedby", "disabled", "display", "else", "enclosing", "error", "field", "filled", "fills", "first", "for", "form", "forms", "fractions", "from", "group", "hidden", "hint", "hover", "ids", "image", "included", "inputs", "interactive", "invalid", "isn", "keys", "label", "lift", "max", "name", "native", "needs", "number", "only", "onvaluechange", "pair", "partially", "picked", "press", "preview", "radios", "rating", "readers", "readonly", "render", "renders", "required", "score", "screen", "sets", "size", "spring", "star", "stars", "styling", "submit", "submitted", "text", "the", "uncontrolled", "value", "visually", "with"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "relative-time", type: "registry:ui", title: "Relative Time", description: "Self-updating “5 minutes ago” in a semantic <time> with the full date as its title. Server renders the absolute date (no hydration mismatch); one shared ticker for the whole page.", exports: ["RelativeTime"], keywords: ["absolute", "ago", "and", "both", "client", "crawlers", "current", "date", "default", "differ", "full", "get", "hydration", "its", "itself", "keeps", "locale", "minutes", "mismatch", "not", "now", "one", "page", "pass", "real", "relative", "render", "renders", "semantic", "server", "shared", "stored", "text", "that", "the", "there", "ticker", "time", "timestamp", "title", "with", "would"], registryDependencies: ["utils"] }, { name: "resizable", type: "registry:ui", title: "Resizable", description: "Split panes for admin layouts, docs and editors. Hairline dividers with a wide grab area follow the pointer; collapsible panels snap shut past half their minimum. Dividers are APG window splitters: arrows step, Home/End jump to the limits, Enter or double-click collapses with a spring. Groups nest.", exports: ["ResizablePanelGroup", "ResizablePanel", "ResizableHandle"], keywords: ["adds", "admin", "after", "already", "and", "apg", "are", "arrow", "arrows", "basis", "between", "click", "collapsed", "collapsedsize", "collapses", "collapsible", "component", "cookie", "css", "default", "defaultsize", "direction", "divider", "docs", "dom", "double", "drag", "dragging", "each", "editors", "end", "enter", "evenly", "final", "find", "flex", "follows", "for", "grip", "group", "half", "handle", "handles", "home", "horizontal", "hydration", "icon", "jump", "key", "keyboardstep", "keys", "largest", "layout", "layouts", "left", "limits", "maxsize", "middle", "minimum", "minsize", "neighbor", "one", "onlayout", "order", "others", "panels", "panes", "parents", "past", "per", "plain", "pointer", "press", "rail", "rest", "save", "server", "share", "shows", "shut", "side", "size", "sizes", "smallest", "snaps", "split", "splitters", "spring", "ssr", "stacked", "starting", "step", "the", "their", "them", "toggle", "toggles", "two", "until", "vertical", "visible", "what", "when", "window", "withhandle", "without", "work", "wrappers"], registryDependencies: ["utils"] }, { name: "reveal", type: "registry:ui", title: "Reveal", description: "Scroll reveal: content fades and rises on a spring the first time it enters the viewport.", exports: ["Reveal"], keywords: ["after", "and", "content", "delay", "entering", "fades", "first", "into", "offset", "place", "rises", "scrolls", "seconds", "spring", "start", "stays", "the", "time", "view", "visible", "wait"], registryDependencies: ["utils"] }, { name: "scroll-area", type: "registry:ui", title: "Scroll Area", description: "Overlay scrollbars: thin thumbs that fade in while scrolling or on hover, widen under the pointer and drag. Scrolling stays native; the labeled region is keyboard-focusable.", exports: ["ScrollArea"], keywords: ["also", "and", "aria", "axes", "can", "classes", "drag", "fade", "focus", "for", "get", "give", "goes", "height", "here", "horizontal", "hover", "itself", "keyboard", "label", "mouse", "names", "native", "one", "orientation", "overlay", "padding", "region", "scroll", "scrollable", "scrollbars", "scrolling", "stays", "takes", "that", "the", "thin", "thumb", "thumbs", "touch", "users", "viewport", "viewportclassname", "wheel", "while", "widen"], registryDependencies: ["utils"] }, { name: "search-input", type: "registry:ui", title: "Search Input", description: 'Search field built on Input: leading icon, spring-in clear button, Esc to clear, and an optional focus shortcut ("/" or mod+k) with a Kbd hint.', exports: ["SearchInput"], keywords: ["accessible", "already", "and", "anywhere", "aside", "border", "browser", "button", "called", "change", "clear", "cleared", "clears", "command", "controlled", "ctrl", "default", "defaultvalue", "elsewhere", "embedded", "esc", "every", "field", "find", "first", "focus", "focused", "focuses", "for", "from", "ghost", "hidden", "hint", "htmlfor", "icon", "inputs", "kbd", "key", "label", "mac", "mod", "name", "onvaluechange", "opens", "optional", "own", "pair", "palette", "pass", "query", "render", "ring", "search", "second", "shadow", "shortcut", "single", "skipped", "spring", "steps", "still", "surface", "the", "uncontrolled", "value", "variant", "when", "while", "with", "you"], registryDependencies: ["input", "kbd", "platform", "use-controllable-state", "use-hotkey", "utils"] }, { name: "segmented-tabs", type: "registry:ui", title: "AppWindow", description: "Window container with close / minimize / zoom controls, title, custom header slot and actions. SegmentedTabs is the compact view switcher for its title bar.", exports: ["SegmentedTabs"], keywords: ["accessible", "active", "also", "always", "aria", "behind", "called", "current", "for", "indicator", "item", "items", "label", "labels", "list", "marked", "name", "onchange", "one", "pressed", "segmented", "slides", "spring", "tab", "tabs", "the", "under", "used", "value", "values", "with"], registryDependencies: ["overflow-focus", "use-indicator", "utils"] }, { name: "select", type: "registry:ui", title: "Select", description: "Single-choice listbox styled like Input, with groups, icons and disabled options. Native-select keyboard (arrows, typeahead even while closed), flips above the trigger near the viewport edge, submits and validates with the form.", exports: ["Select"], keywords: ["accessible", "also", "aria", "blocks", "called", "cancel", "choice", "closed", "controlled", "defaultvalue", "describedby", "disabled", "down", "end", "enter", "error", "esc", "field", "fill", "fills", "first", "flat", "for", "form", "from", "groups", "hint", "home", "htmlfor", "ids", "input", "invalid", "isn", "keyboard", "label", "labeled", "let", "like", "listbox", "matches", "name", "native", "needs", "nothing", "onvaluechange", "opening", "options", "pair", "pick", "picked", "placeholder", "render", "required", "select", "sets", "single", "space", "styled", "styling", "submit", "submitted", "text", "the", "there", "trigger", "typeahead", "uncontrolled", "value", "visible", "when", "while", "with"], registryDependencies: ["field", "form-value", "input", "list", "platform", "use-anchor", "use-controllable-state", "use-dismiss", "utils"] }, { name: "separator", type: "registry:ui", title: "Separator", description: 'Server-safe hairline, horizontal or vertical, decorative by default, with an optional centered label like "or".', exports: ["Separator"], keywords: ["assistive", "centered", "content", "decorative", "default", "direction", "false", "for", "horizontal", "label", "line", "only", "orientation", "purely", "separates", "set", "tech", "text", "the", "visual", "when"], registryDependencies: ["utils"] }, { name: "sidebar", type: "registry:ui", title: "Sidebar", description: "App navigation from data: header, groups (optionally foldable), badges and pinned footer entries. Collapses to an icon rail on a spring (⌘B / Ctrl+B) with labels kept for assistive tech; below md it is a left drawer.", exports: ["SidebarLayout", "Sidebar", "SidebarTrigger"], keywords: ["a11y", "accessible", "and", "aria", "below", "bottom", "but", "called", "client", "clip", "collapsed", "collapses", "controlled", "ctrl", "current", "data", "default", "defaultcollapsed", "drawer", "entries", "field", "footer", "for", "from", "groups", "header", "highlighted", "holds", "icon", "ignored", "item", "label", "labels", "landmark", "lays", "left", "links", "name", "navigation", "oncollapsedchange", "onselect", "page", "pair", "picked", "pinned", "rail", "routing", "settings", "shortcut", "side", "sidebar", "slot", "spring", "start", "state", "stay", "the", "toggle", "too", "top", "tree", "trigger", "true", "typing", "uncontrolled", "when", "while", "with", "workspace"], registryDependencies: ["button", "collapsible", "drawer", "platform", "use-controllable-state", "use-hotkey", "utils"] }, { name: "site-header", type: "registry:block", title: "Site Header", description: "Sticky, translucent site header from one nav array: brand, NavigationMenu panels from md up, a right Drawer with the same links below it, and your actions on the right. The hairline underneath appears only once content scrolls beneath it.", exports: ["SiteHeader"], keywords: ["accessible", "acme", "actions", "alike", "and", "appears", "aria", "below", "brand", "client", "close", "controls", "current", "demo", "desktop", "drawer", "every", "for", "from", "hairline", "hand", "header", "href", "label", "left", "level", "link", "links", "logo", "marks", "matching", "name", "nav", "navigation", "navigationmenu", "once", "onclick", "only", "onnavigate", "over", "page", "panels", "right", "routing", "same", "scrolls", "search", "shown", "sign", "site", "sticky", "stub", "the", "theme", "top", "under", "width", "with"], registryDependencies: ["button", "drawer", "navigation-menu", "use-disclosure", "utils"] }, { name: "skeleton", type: "registry:ui", title: "Skeleton", description: 'Server-safe loading placeholders that pulse (static under reduced motion). SkeletonGroup announces one "Loading" to screen readers.', exports: ["Skeleton", "SkeletonGroup"], keywords: ["announced", "block", "classes", "classname", "hear", "instead", "label", "loading", "nothing", "one", "placeholder", "readers", "screen", "shown", "size", "skeleton", "skeletons", "this", "while", "with", "wrap"], registryDependencies: ["utils"] }, { name: "slider", type: "registry:ui", title: "Slider", description: "Slider over native range inputs: thin accent track, white knob that lifts while held. One value or two for a range; keyboard, forms, touch and Field wiring come from the platform.", exports: ["Slider"], keywords: ["accent", "accessible", "and", "aren", "aria", "arrow", "blocks", "browser", "called", "defaults", "defaultvalue", "describedby", "disabled", "does", "drag", "dragging", "error", "every", "field", "fills", "filter", "first", "for", "forms", "from", "held", "highest", "hint", "ids", "increment", "inputs", "invalid", "keyboard", "keys", "knob", "labels", "lifts", "lowest", "max", "maximum", "min", "minimum", "name", "names", "native", "one", "onvaluechange", "over", "per", "price", "range", "readers", "render", "screen", "sets", "slider", "step", "styling", "submitted", "text", "that", "the", "thin", "thumb", "touch", "track", "twice", "two", "uncontrolled", "value", "values", "while", "white", "with", "work"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "spinner", type: "registry:ui", title: "Spinner", description: "Server-safe activity indicator: eight spokes in currentColor, three sizes, its own status label (or silent inside a parent that announces). Holds still under reduced motion.", exports: ["Spinner"], keywords: ["accessible", "activity", "already", "announces", "busy", "currentcolor", "diameter", "eight", "holds", "indicator", "label", "motion", "name", "parent", "pass", "reduced", "size", "spokes", "state", "still", "the", "under", "when"], registryDependencies: ["utils"] }, { name: "stat-tile", type: "registry:block", title: "Stat Tile", description: "Admin dashboard metric: value, a delta Badge that is green when the change is good news (invert for errors and latency), and an area Chart of the trend. Server-safe.", exports: ["StatTile"], keywords: ["admin", "and", "area", "axis", "badge", "below", "change", "chart", "dashboard", "data", "datakey", "delta", "down", "each", "errors", "for", "format", "formatted", "good", "green", "headline", "index", "intl", "invert", "key", "label", "last", "latency", "metric", "metrics", "month", "name", "news", "number", "period", "positive", "revenue", "row", "rows", "the", "tile", "tooltip", "trend", "unless", "value", "when", "where"], registryDependencies: ["badge", "card", "chart", "utils"] }, { name: "stats-strip", type: "registry:block", title: "Stats Strip", description: "Headline numbers, each card a <dl>: cards rise in turn with Reveal, then each number springs up with CountTo. Final values are in the HTML.", exports: ["StatsStrip"], keywords: ["card", "display", "each", "headline", "its", "number", "numbers", "order", "rises", "row", "springs", "stats", "then", "turn"], registryDependencies: ["card", "count-to", "reveal", "utils"] }, { name: "stepper", type: "registry:ui", title: "Stepper", description: "Multi-step form (questionnaire, checkout, setup wizard). Steps stay mounted so values survive Back and submit together; Continue checks only the current step's native constraints, plus an optional async onNext guard with a spinner. Progress header with springing connectors; works with onSubmit or a Server Action.", exports: ["Stepper", "StepperList", "StepperStep", "StepperFooter"], keywords: ["action", "after", "and", "are", "back", "backlabel", "button", "called", "check", "checks", "children", "connector", "constraints", "continue", "controlled", "current", "defaultvalue", "description", "every", "false", "fields", "fills", "finished", "first", "for", "form", "header", "hidden", "inactive", "its", "last", "links", "matches", "mounted", "multi", "native", "new", "nextlabel", "not", "one", "only", "onnext", "onsubmit", "onvaluechange", "optional", "order", "pass", "progress", "render", "resolve", "return", "runs", "server", "shown", "shows", "spinner", "spring", "start", "stay", "stays", "step", "steps", "submit", "submitlabel", "submits", "survive", "text", "the", "through", "title", "together", "uncontrolled", "unmounted", "value", "values", "while", "with"], registryDependencies: ["button", "focus", "use-controllable-state", "utils"] }, { name: "styles", type: "registry:file", exports: [], keywords: [], registryDependencies: [] }, { name: "switch", type: "registry:ui", title: "Forms", description: "Input, Textarea, Label and Switch: smooth focus rings, native :user-invalid validation (red only after interaction), aria-invalid, auto-growing textarea with an optional character count, and a spring switch.", exports: ["Switch"], keywords: ["called", "checkbox", "checked", "controlled", "defaultchecked", "first", "knob", "native", "new", "oncheckedchange", "pair", "render", "role", "spring", "state", "switch", "the", "uncontrolled", "with"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "table", type: "registry:ui", title: "Table", description: "Server-safe semantic <table> in a scrolling card: header, body, footer and caption, striped rows, tinted selected rows, and sortable headers that set aria-sort and flip their arrow.", exports: ["Table", "TableHeader", "TableBody", "TableFooter", "TableRow", "TableHead", "TableCell", "TableCaption"], keywords: ["alternating", "and", "aria", "around", "arrow", "button", "called", "card", "classes", "column", "containerclassname", "data", "direction", "for", "header", "keyboard", "makes", "narrow", "onsort", "pass", "pressed", "real", "requires", "row", "screens", "scrollable", "scrolling", "scrolls", "selected", "sets", "shading", "shows", "sideways", "sort", "sortable", "state", "striped", "table", "that", "the", "then", "tint", "when"], registryDependencies: ["overflow-focus", "utils"] }, { name: "tabs", type: "registry:ui", title: "Tabs", description: "WAI-ARIA tabs with arrow, Home and End keys. One indicator springs between tabs, segmented or underline. Inactive panels stay in the DOM for SEO; the active one fades in.", exports: ["Tabs", "TabsList", "TabsTrigger", "TabsContent"], keywords: ["activated", "active", "always", "and", "aria", "arrows", "bar", "behind", "called", "children", "content", "controlled", "crawlable", "defaultvalue", "dom", "end", "first", "focus", "hidden", "home", "html", "inactive", "indicator", "labels", "matches", "move", "muted", "one", "onvaluechange", "pair", "panel", "panels", "pill", "remains", "render", "segmented", "springs", "stay", "stays", "tab", "tabs", "tabscontent", "tabstrigger", "the", "their", "track", "uncontrolled", "under", "underline", "value", "variant", "wai", "while", "with"], registryDependencies: ["list", "use-controllable-state", "use-indicator", "utils"] }, { name: "tag-input", type: "registry:ui", title: "Tag Input", description: "Free-form tags: Enter or a separator adds, Backspace removes the last, pasting a list adds them all. Duplicates, a max and a validate function keep bad tags in the input. Submits one entry per tag; required needs one.", exports: ["tagFieldClass", "Tag", "TagInput"], keywords: ["accessible", "add", "after", "allowed", "and", "animatepresence", "backspace", "besides", "button", "called", "children", "chip", "commit", "controlled", "defaultvalue", "disabled", "empty", "enter", "every", "false", "first", "form", "free", "hides", "input", "inside", "its", "keys", "last", "least", "limit", "list", "many", "max", "mode", "most", "name", "needs", "one", "onremove", "onvaluechange", "out", "pair", "paste", "pasted", "per", "poplayout", "press", "reject", "removable", "remove", "removes", "render", "rendered", "required", "return", "runs", "separator", "separators", "shows", "split", "springs", "stays", "stops", "submits", "tag", "tags", "text", "that", "the", "these", "too", "trimming", "type", "typed", "typing", "uncontrolled", "validate", "value", "when", "with"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "terminal", type: "registry:ui", title: "Terminal", description: "Terminal window. Snippet mode types install commands once scrolled into view, with the full transcript kept in the DOM for SEO and no-JS; log mode streams lines into a live region that follows the bottom unless you scroll up, then offers a jump back. Status lines carry glyphs, copy grabs the commands.", exports: ["Terminal"], keywords: ["and", "append", "arrives", "back", "before", "body", "bodyclassname", "bottom", "character", "clipboard", "commands", "copy", "copytext", "defaults", "dom", "false", "follows", "for", "full", "hides", "install", "jump", "lines", "live", "log", "mode", "new", "offering", "once", "order", "output", "per", "prompt", "puts", "read", "reveals", "role", "scroll", "scrolling", "seo", "size", "snippet", "snippets", "speed", "stays", "sticks", "stream", "streams", "symbol", "terminal", "text", "the", "title", "typed", "types", "typing", "unless", "view", "what", "when", "window", "you"], registryDependencies: ["app-window", "code", "platform", "utils"] }, { name: "testimonial", type: "registry:block", title: "Testimonial", description: "A large Quote with its author, and everyone else who agrees as an overlapping AvatarGroup. Server-safe.", exports: ["Testimonial"], keywords: ["agrees", "and", "author", "avatar", "avatargroup", "behind", "beside", "carried", "children", "company", "crowd", "else", "everyone", "few", "first", "fold", "initials", "into", "its", "lang", "language", "large", "line", "one", "others", "otherslabel", "photo", "quote", "rest", "role", "said", "show", "stack", "streamers", "subtitle", "the", "trusted", "under", "url", "who", "with", "without"], registryDependencies: ["avatar", "avatar-group", "quote", "utils"] }, { name: "text-swap", type: "registry:ui", title: "TextSwap", description: "Spring-powered text morphing and ticker. Auto-cycles phrases or animates whenever children change with blur and slide transitions.", exports: ["TextSwap"], keywords: ["active", "array", "automatically", "between", "changing", "child", "children", "controlling", "cycle", "cycling", "default", "direction", "externally", "hover", "index", "interval", "items", "milliseconds", "mouse", "new", "pass", "pause", "pauseonhover", "single", "string", "swap", "swaps", "text", "the", "through", "true", "when"], registryDependencies: ["utils"] }, { name: "textarea", type: "registry:ui", title: "Forms", description: "Input, Textarea, Label and Switch: smooth focus rings, native :user-invalid validation (red only after interaction), aria-invalid, auto-growing textarea with an optional character count, and a spring switch.", exports: ["Textarea"], keywords: ["auto", "cap", "content", "corner", "end", "field", "firefox", "grows", "max", "maxlength", "near", "needs", "red", "resizable", "show", "showcount", "sizing", "the", "then", "turns", "unsupported", "used", "warning", "where", "with"], registryDependencies: ["field", "form-value", "input", "utils"] }, { name: "theme", type: "registry:lib", description: "Retints primary, focus rings, selection and switches app-wide. Persists like the theme.", exports: ["isDark", "setTheme", "subscribeTheme", "accents", "getAccent", "setAccent", "themeScript"], keywords: ["and", "app", "focus", "like", "persists", "primary", "retints", "rings", "selection", "switches", "the", "theme", "wide"], registryDependencies: [] }, { name: "theme-toggle", type: "registry:ui", title: "Theme Toggle", description: "Light/dark icon switch with spring rotate-swap; follows the OS until first use.", exports: ["ThemeToggle"], keywords: ["button", "click", "first", "follows", "icon", "moon", "rotate", "spring", "sun", "swap", "until"], registryDependencies: ["button", "theme", "utils"] }, { name: "timeline", type: "registry:ui", title: "Timeline", description: "Server-safe ordered list of events on a rail: icon or dot markers with status colors, machine-readable <time>, title and an optional body. For changelogs, experience and mod logs.", exports: ["Timeline", "TimelineItem"], keywords: ["above", "and", "body", "children", "color", "date", "datetime", "dot", "event", "events", "first", "for", "headline", "icon", "inside", "list", "machine", "marker", "newest", "oldest", "one", "optional", "order", "ordered", "pair", "rail", "readable", "render", "shown", "small", "the", "then", "time", "title", "variant", "with", "without", "yours"], registryDependencies: ["utils"] }, { name: "toast", type: "registry:ui", title: "Toast", description: "Stacked notifications. Hover to expand, swipe to dismiss, timers pause on hover.", exports: ["toast", "Toaster"], keywords: ["action", "description", "dismiss", "dismisses", "duration", "error", "expands", "focus", "hover", "layout", "loading", "mount", "once", "promise", "root", "saved", "stacked", "success", "swipe", "tap", "title", "toast", "toasts"], registryDependencies: ["use-dismiss", "utils"] }, { name: "toggle-group", type: "registry:ui", title: "Toggle Group", description: "Segmented control of toggle buttons. Single mode slides one pill to the pressed item (view mode, billing period); multiple mode toggles items independently (bold, italic). Arrow keys move between items.", exports: ["ToggleGroup", "ToggleGroupItem"], keywords: ["always", "and", "aria", "arrow", "behind", "between", "billing", "bold", "buttons", "called", "choice", "control", "controlled", "defaultvalue", "end", "every", "filters", "first", "height", "home", "icon", "independent", "italic", "item", "items", "keys", "label", "labels", "mode", "move", "multiple", "need", "one", "only", "onvaluechange", "pair", "period", "pill", "pressed", "render", "reported", "segment", "segmented", "set", "single", "size", "slides", "springs", "the", "time", "toggle", "toggles", "type", "uncontrolled", "value", "values", "view", "when", "with"], registryDependencies: ["list", "use-controllable-state", "use-indicator", "utils"] }, { name: "tooltip", type: "registry:ui", title: "Tooltip", description: "Short label on hover or keyboard focus, also wired as the trigger's aria-describedby. Warm-up: once one opens, neighbors open instantly. Hoverable, Esc dismisses, ignores touch.", exports: ["Tooltip"], keywords: ["accessible", "action", "align", "alignment", "also", "and", "aria", "becomes", "before", "button", "children", "content", "control", "default", "delay", "description", "dismisses", "element", "esc", "first", "flips", "focus", "focusable", "for", "hold", "hover", "how", "icon", "keyboard", "label", "one", "open", "opens", "own", "pointer", "preferred", "press", "reaches", "room", "short", "shows", "side", "stays", "still", "tap", "text", "the", "their", "there", "toggles", "tooltip", "touch", "trigger", "triggers", "wcag", "when", "while", "with"], registryDependencies: ["platform", "use-anchor", "use-dismiss", "use-hover-open", "utils"] }, { name: "typewriter", type: "registry:ui", title: "Typewriter", description: "Types out text character-by-character with optional phrase cycling and pulsing cursor. Full copy stays in the DOM for SEO.", exports: ["Typewriter"], keywords: ["and", "array", "before", "blinking", "called", "character", "classes", "cursor", "cursorchar", "cursorclassname", "custom", "cycle", "default", "delay", "deletespeed", "deleting", "dom", "effect", "for", "full", "fully", "headers", "hero", "loop", "milliseconds", "once", "oncomplete", "pause", "pauseduration", "per", "phrase", "phrases", "quotes", "seo", "show", "speed", "starting", "stays", "text", "the", "through", "true", "type", "typed", "typewriter", "typing", "wait", "when", "whether", "while"], registryDependencies: ["platform", "utils"] }, { name: "use-anchor", type: "registry:hook", description: `Fixed-position coordinates for a floating panel next to its anchor: on the preferred side,
|
|
17901
|
+
Renders a hidden span, so server components (Table) can use it as a child.`, exports: ["OverflowFocus"], keywords: ["again", "and", "arrow", "becomes", "can", "child", "components", "container", "drop", "fits", "focusable", "hidden", "inside", "keyboard", "keys", "leaves", "once", "order", "overflows", "renders", "scroll", "server", "span", "tab", "tabindex", "table", "the", "use", "while"], registryDependencies: [] }, { name: "pagination", type: "registry:ui", title: "Pagination", description: "Server-safe page links from page and total: previous/next, ellipsis gaps and a sliding active pill, with numbers that swipe the way you moved. Links by default; buttons with onPageChange. The row keeps a fixed width so it never jumps.", exports: ["Pagination", "pageRange"], keywords: ["active", "always", "and", "arrows", "bar", "become", "between", "buttons", "called", "changes", "client", "controls", "current", "default", "each", "ellipsis", "first", "for", "from", "gaps", "href", "index", "instead", "items", "its", "keeps", "kept", "key", "labels", "last", "length", "links", "mounted", "moved", "never", "next", "number", "numbers", "one", "only", "onpagechange", "page", "pagerange", "pages", "parents", "phones", "picked", "pill", "previous", "remounting", "render", "returns", "row", "same", "show", "siblings", "side", "slides", "slot", "stays", "swipe", "swipes", "text", "that", "the", "total", "unused", "url", "way", "width", "with", "without", "work", "you"], registryDependencies: ["button-variants", "pagination-motion", "utils"] }, { name: "pagination-motion", type: "registry:ui", description: "Scopes the active pill's `layoutId` so several paginations on a page don't share it.", exports: ["PaginationMotion", "PaginationActivePill", "PaginationNumber"], keywords: ["active", "behind", "changes", "children", "direction", "don", "from", "items", "its", "layoutid", "link", "moved", "next", "number", "outline", "page", "pagination", "paginations", "pill", "scopes", "several", "share", "side", "slot", "springs", "swipes", "that", "the", "toward", "travel", "value", "when"], registryDependencies: ["utils"] }, { name: "platform", type: "registry:lib", description: "False on the server and during hydration, true after: gates portals and other client-only output.", exports: ["useMounted", "useIsMac", "useMediaQuery"], keywords: ["after", "and", "assumes", "client", "corrects", "ctrl", "during", "false", "gates", "hydration", "live", "match", "media", "not", "only", "other", "output", "portals", "query", "render", "server", "shortcuts", "ssr", "the", "then", "true", "use", "where"], registryDependencies: [] }, { name: "popover", type: "registry:ui", title: "Popover", description: "Non-modal panel anchored to a Button for filters, pickers and quick edits. Focus moves in, Esc returns it, outside clicks close; Selects and menus opened inside don't count as outside.", exports: ["Popover", "PopoverTrigger", "PopoverContent"], keywords: ["above", "action", "align", "alignment", "also", "anchored", "and", "any", "aria", "armed", "before", "blur", "both", "button", "called", "can", "check", "children", "click", "clicks", "closed", "closes", "confirm", "confirmlabel", "confirmtimeout", "content", "controlled", "default", "defaultopen", "defaults", "destructive", "done", "edits", "emphasis", "end", "enter", "esc", "feedback", "field", "fill", "filters", "first", "flips", "focus", "focusable", "for", "form", "from", "give", "height", "icon", "ignore", "ignores", "irreversible", "its", "keep", "label", "left", "like", "loading", "loadinglabel", "modal", "moves", "never", "non", "not", "old", "onclick", "one", "ones", "onopenchange", "open", "out", "outside", "padding", "pair", "panel", "past", "per", "pickers", "place", "popovercontent", "popovertrigger", "popup", "preferred", "primary", "quick", "render", "reserved", "resets", "resize", "returns", "room", "runs", "second", "shift", "shown", "shows", "side", "size", "slides", "spinner", "spins", "square", "state", "status", "stays", "step", "submit", "success", "successlabel", "swap", "swaps", "tab", "text", "the", "there", "this", "trap", "trigger", "twice", "two", "uncontrolled", "unmount", "values", "variant", "view", "when", "where", "while", "width", "with"], registryDependencies: ["button", "focus", "platform", "use-anchor", "use-controllable-state", "use-dismiss", "utils"] }, { name: "pricing", type: "registry:block", title: "Pricing", description: "Plan cards with a monthly / yearly segmented switch. Prices roll on a spring in the direction they moved; the featured plan is outlined in the accent. Card, Badge, ToggleGroup, Button.", exports: ["Pricing"], keywords: ["and", "bcp", "billing", "cards", "code", "currency", "defaultperiod", "display", "down", "drop", "eur", "first", "for", "formatting", "iso", "locale", "monthly", "next", "number", "order", "period", "plan", "plans", "price", "prices", "render", "rise", "rolling", "segmented", "selected", "spring", "swap", "switch", "the", "they", "togglegroup", "when", "with", "yearly", "yearlynote"], registryDependencies: ["badge", "card", "toggle-group", "utils"] }, { name: "product-card", type: "registry:block", title: "Product Card", description: "Shop tile: photos in an AspectRatio (a swipeable Carousel with dots when there are several), sale price, Badge and add-to-cart Button.", exports: ["ProductCard"], keywords: ["add", "addlabel", "are", "aspectratio", "badge", "bcp", "become", "button", "called", "card", "carousel", "code", "compareat", "currency", "current", "dots", "for", "formatting", "heading", "height", "href", "img", "iso", "label", "link", "locale", "major", "media", "name", "new", "number", "onaddtocart", "one", "original", "over", "page", "per", "photos", "pressed", "price", "product", "ratio", "sale", "several", "shop", "shows", "slide", "small", "square", "struck", "swipeable", "text", "the", "there", "through", "tile", "units", "when", "width", "with"], registryDependencies: ["aspect-ratio", "badge", "button", "carousel", "utils"] }, { name: "progress", type: "registry:ui", title: "Progress", description: "Accent bar that springs to each new value, with an optional label and percentage. Leave out value for an indeterminate sweep (static under reduced motion).", exports: ["Progress"], keywords: ["above", "accent", "accessible", "across", "allowed", "also", "aria", "bar", "colored", "duration", "each", "for", "frame", "indeterminate", "infinite", "its", "label", "layout", "max", "motion", "name", "new", "next", "omit", "one", "per", "percentage", "reduced", "scalex", "segment", "show", "showvalue", "size", "springs", "static", "sweeps", "that", "the", "there", "thickness", "tween", "under", "unknown", "value", "visible", "when", "work"], registryDependencies: ["utils"] }, { name: "quote", type: "registry:ui", title: "Quote", description: "Semantic figure, blockquote and figcaption. Plain, card and large variants, with author, subtitle, avatar, lang, typewriter and textSwap.", exports: ["Quote"], keywords: ["accent", "alt", "and", "array", "author", "avatar", "blockquote", "card", "children", "correct", "custom", "cycles", "delay", "display", "doe", "effect", "enables", "fades", "figcaption", "figure", "for", "into", "jane", "job", "lang", "language", "large", "line", "mark", "options", "pass", "plain", "pronunciation", "quote", "quoted", "quotes", "reader", "said", "screen", "scrolls", "secondary", "semantic", "seo", "size", "slot", "speed", "spring", "string", "strings", "subtitle", "supports", "surface", "swap", "text", "textswap", "the", "through", "title", "transitions", "typewriter", "under", "variant", "view", "when", "who", "with", "work", "wrote"], registryDependencies: ["text-swap", "typewriter", "utils"] }, { name: "radio-group", type: "registry:ui", title: "Radio Group", description: "Native radios in a fieldset with a legend: browser arrow keys and form submit, a dot that springs in, optional per-option descriptions, vertical or horizontal.", exports: ["RadioGroup", "RadioGroupItem"], keywords: ["adds", "and", "application", "aria", "arrow", "browser", "but", "called", "children", "conform", "controlled", "defaultvalue", "description", "disabled", "does", "enclosing", "entered", "expected", "field", "fieldset", "first", "form", "format", "generated", "group", "indicates", "invalid", "item", "items", "its", "keys", "label", "labels", "lay", "legend", "line", "muted", "name", "names", "native", "needs", "not", "omitted", "one", "onvaluechange", "option", "orientation", "pair", "picked", "radios", "render", "rendered", "required", "row", "selectable", "shown", "stack", "submit", "submitted", "the", "them", "uncontrolled", "under", "value", "visible", "when", "with", "without", "work"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "rating", type: "registry:ui", title: "Rating", description: "Star rating on native radios (arrow keys, forms) with hover preview, or readOnly display with fractional stars for averages.", exports: ["Rating"], keywords: ["and", "aria", "arrow", "called", "can", "chosen", "controlled", "defaults", "defaultvalue", "describedby", "disabled", "display", "else", "enclosing", "error", "field", "filled", "fills", "first", "for", "form", "forms", "fractions", "from", "group", "hidden", "hint", "hover", "ids", "image", "included", "inputs", "interactive", "invalid", "isn", "keys", "label", "lift", "max", "name", "native", "needs", "number", "only", "onvaluechange", "pair", "partially", "picked", "press", "preview", "radios", "rating", "readers", "readonly", "render", "renders", "required", "score", "screen", "sets", "size", "spring", "star", "stars", "styling", "submit", "submitted", "text", "the", "uncontrolled", "value", "visually", "with"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "relative-time", type: "registry:ui", title: "Relative Time", description: "Self-updating “5 minutes ago” in a semantic <time> with the full date as its title. Server renders the absolute date (no hydration mismatch); one shared ticker for the whole page.", exports: ["RelativeTime"], keywords: ["absolute", "ago", "and", "both", "client", "crawlers", "current", "date", "default", "differ", "full", "get", "hydration", "its", "itself", "keeps", "locale", "minutes", "mismatch", "not", "now", "one", "page", "pass", "real", "relative", "render", "renders", "semantic", "server", "shared", "stored", "text", "that", "the", "there", "ticker", "time", "timestamp", "title", "with", "would"], registryDependencies: ["utils"] }, { name: "resizable", type: "registry:ui", title: "Resizable", description: "Split panes for admin layouts, docs and editors. Hairline dividers with a wide grab area follow the pointer; collapsible panels snap shut past half their minimum. Dividers are APG window splitters: arrows step, Home/End jump to the limits, Enter or double-click collapses with a spring. Groups nest.", exports: ["ResizablePanelGroup", "ResizablePanel", "ResizableHandle"], keywords: ["adds", "admin", "after", "already", "and", "apg", "are", "arrow", "arrows", "basis", "between", "click", "collapsed", "collapsedsize", "collapses", "collapsible", "component", "cookie", "css", "default", "defaultsize", "direction", "divider", "docs", "dom", "double", "drag", "dragging", "each", "editors", "end", "enter", "evenly", "final", "find", "flex", "follows", "for", "grip", "group", "half", "handle", "handles", "home", "horizontal", "hydration", "icon", "jump", "key", "keyboardstep", "keys", "largest", "layout", "layouts", "left", "limits", "maxsize", "middle", "minimum", "minsize", "neighbor", "one", "onlayout", "order", "others", "panels", "panes", "parents", "past", "per", "plain", "pointer", "press", "rail", "rest", "save", "server", "share", "shows", "shut", "side", "size", "sizes", "smallest", "snaps", "split", "splitters", "spring", "ssr", "stacked", "starting", "step", "the", "their", "them", "toggle", "toggles", "two", "until", "vertical", "visible", "what", "when", "window", "withhandle", "without", "work", "wrappers"], registryDependencies: ["utils"] }, { name: "reveal", type: "registry:ui", title: "Reveal", description: "Scroll reveal: content fades and rises on a spring the first time it enters the viewport.", exports: ["Reveal"], keywords: ["after", "and", "content", "delay", "entering", "fades", "first", "into", "offset", "place", "rises", "scrolls", "seconds", "spring", "start", "stays", "the", "time", "view", "visible", "wait"], registryDependencies: ["utils"] }, { name: "scroll-area", type: "registry:ui", title: "Scroll Area", description: "Overlay scrollbars: thin thumbs that fade in while scrolling or on hover, widen under the pointer and drag. Scrolling stays native; the labeled region is keyboard-focusable.", exports: ["ScrollArea"], keywords: ["also", "and", "aria", "axes", "can", "classes", "drag", "fade", "focus", "for", "get", "give", "goes", "height", "here", "horizontal", "hover", "itself", "keyboard", "label", "mouse", "names", "native", "one", "orientation", "overlay", "padding", "region", "scroll", "scrollable", "scrollbars", "scrolling", "stays", "takes", "that", "the", "thin", "thumb", "thumbs", "touch", "users", "viewport", "viewportclassname", "wheel", "while", "widen"], registryDependencies: ["utils"] }, { name: "search-input", type: "registry:ui", title: "Search Input", description: 'Search field built on Input: leading icon, spring-in clear button, Esc to clear, and an optional focus shortcut ("/" or mod+k) with a Kbd hint.', exports: ["SearchInput"], keywords: ["accessible", "already", "and", "anywhere", "aside", "border", "browser", "button", "called", "change", "clear", "cleared", "clears", "command", "controlled", "ctrl", "default", "defaultvalue", "elsewhere", "embedded", "esc", "every", "field", "find", "first", "focus", "focused", "focuses", "for", "from", "ghost", "hidden", "hint", "htmlfor", "icon", "inputs", "kbd", "key", "label", "mac", "mod", "name", "onvaluechange", "opens", "optional", "own", "pair", "palette", "pass", "query", "render", "ring", "search", "second", "shadow", "shortcut", "single", "skipped", "spring", "steps", "still", "surface", "the", "uncontrolled", "value", "variant", "when", "while", "with", "you"], registryDependencies: ["input", "kbd", "platform", "use-controllable-state", "use-hotkey", "utils"] }, { name: "segmented-tabs", type: "registry:ui", title: "AppWindow", description: "Window container with close / minimize / zoom controls, title, custom header slot and actions. SegmentedTabs is the compact view switcher for its title bar.", exports: ["SegmentedTabs"], keywords: ["accessible", "active", "also", "always", "aria", "behind", "called", "current", "for", "indicator", "item", "items", "label", "labels", "list", "marked", "name", "onchange", "one", "pressed", "segmented", "slides", "spring", "tab", "tabs", "the", "under", "used", "value", "values", "with"], registryDependencies: ["overflow-focus", "use-indicator", "utils"] }, { name: "select", type: "registry:ui", title: "Select", description: "Single-choice listbox styled like Input, with groups, icons and disabled options. Native-select keyboard (arrows, typeahead even while closed), flips above the trigger near the viewport edge, submits and validates with the form.", exports: ["Select"], keywords: ["accessible", "also", "aria", "blocks", "called", "cancel", "choice", "closed", "controlled", "defaultvalue", "describedby", "disabled", "down", "end", "enter", "error", "esc", "field", "fill", "fills", "first", "flat", "for", "form", "from", "groups", "hint", "home", "htmlfor", "ids", "input", "invalid", "isn", "keyboard", "label", "labeled", "let", "like", "listbox", "matches", "name", "native", "needs", "nothing", "onvaluechange", "opening", "options", "pair", "pick", "picked", "placeholder", "render", "required", "select", "sets", "single", "space", "styled", "styling", "submit", "submitted", "text", "the", "there", "trigger", "typeahead", "uncontrolled", "value", "visible", "when", "while", "with"], registryDependencies: ["field", "form-value", "input", "list", "platform", "use-anchor", "use-controllable-state", "use-dismiss", "utils"] }, { name: "separator", type: "registry:ui", title: "Separator", description: 'Server-safe hairline, horizontal or vertical, decorative by default, with an optional centered label like "or".', exports: ["Separator"], keywords: ["assistive", "centered", "content", "decorative", "default", "direction", "false", "for", "horizontal", "label", "line", "only", "orientation", "purely", "separates", "set", "tech", "text", "the", "visual", "when"], registryDependencies: ["utils"] }, { name: "sidebar", type: "registry:ui", title: "Sidebar", description: "App navigation from data: header, groups (optionally foldable), badges and pinned footer entries. Collapses to an icon rail on a spring (⌘B / Ctrl+B) with labels kept for assistive tech; below md it is a left drawer.", exports: ["SidebarLayout", "Sidebar", "SidebarTrigger"], keywords: ["a11y", "accessible", "and", "aria", "below", "bottom", "but", "called", "client", "clip", "collapsed", "collapses", "controlled", "ctrl", "current", "data", "default", "defaultcollapsed", "drawer", "entries", "field", "footer", "for", "from", "groups", "header", "highlighted", "holds", "icon", "ignored", "item", "label", "labels", "landmark", "lays", "left", "links", "name", "navigation", "oncollapsedchange", "onselect", "page", "pair", "picked", "pinned", "rail", "routing", "settings", "shortcut", "side", "sidebar", "slot", "spring", "start", "state", "stay", "the", "toggle", "too", "top", "tree", "trigger", "true", "typing", "uncontrolled", "when", "while", "with", "workspace"], registryDependencies: ["button", "collapsible", "drawer", "platform", "use-controllable-state", "use-hotkey", "utils"] }, { name: "site-header", type: "registry:block", title: "Site Header", description: "Sticky, translucent site header from one nav array: brand, NavigationMenu panels from md up, a right Drawer with the same links below it, and your actions on the right. The hairline underneath appears only once content scrolls beneath it.", exports: ["SiteHeader"], keywords: ["accessible", "acme", "actions", "alike", "and", "appears", "aria", "below", "brand", "client", "close", "controls", "current", "demo", "desktop", "drawer", "every", "for", "from", "hairline", "hand", "header", "href", "label", "left", "level", "link", "links", "logo", "marks", "matching", "name", "nav", "navigation", "navigationmenu", "once", "onclick", "only", "onnavigate", "over", "page", "panels", "right", "routing", "same", "scrolls", "search", "shown", "sign", "site", "sticky", "stub", "the", "theme", "top", "under", "width", "with"], registryDependencies: ["button", "drawer", "navigation-menu", "use-disclosure", "utils"] }, { name: "skeleton", type: "registry:ui", title: "Skeleton", description: 'Server-safe loading placeholders that pulse (static under reduced motion). SkeletonGroup announces one "Loading" to screen readers.', exports: ["Skeleton", "SkeletonGroup"], keywords: ["announced", "block", "classes", "classname", "hear", "instead", "label", "loading", "nothing", "one", "placeholder", "readers", "screen", "shown", "size", "skeleton", "skeletons", "this", "while", "with", "wrap"], registryDependencies: ["utils"] }, { name: "slider", type: "registry:ui", title: "Slider", description: "Slider over native range inputs: thin accent track, white knob that lifts while held. One value or two for a range; keyboard, forms, touch and Field wiring come from the platform.", exports: ["Slider"], keywords: ["accent", "accessible", "and", "aren", "aria", "arrow", "blocks", "browser", "called", "defaults", "defaultvalue", "describedby", "disabled", "does", "drag", "dragging", "error", "every", "field", "fills", "filter", "first", "for", "forms", "from", "held", "highest", "hint", "ids", "increment", "inputs", "invalid", "keyboard", "keys", "knob", "labels", "lifts", "lowest", "max", "maximum", "min", "minimum", "name", "names", "native", "one", "onvaluechange", "over", "per", "price", "range", "readers", "render", "screen", "sets", "slider", "step", "styling", "submitted", "text", "that", "the", "thin", "thumb", "touch", "track", "twice", "two", "uncontrolled", "value", "values", "while", "white", "with", "work"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "spinner", type: "registry:ui", title: "Spinner", description: "Server-safe activity indicator: eight spokes in currentColor, three sizes, its own status label (or silent inside a parent that announces). Holds still under reduced motion.", exports: ["Spinner"], keywords: ["accessible", "activity", "already", "announces", "busy", "currentcolor", "diameter", "eight", "holds", "indicator", "label", "motion", "name", "parent", "pass", "reduced", "size", "spokes", "state", "still", "the", "under", "when"], registryDependencies: ["utils"] }, { name: "stat-tile", type: "registry:block", title: "Stat Tile", description: "Admin dashboard metric: value, a delta Badge that is green when the change is good news (invert for errors and latency), and an area Chart of the trend. Server-safe.", exports: ["StatTile"], keywords: ["admin", "and", "area", "axis", "badge", "below", "change", "chart", "dashboard", "data", "datakey", "delta", "down", "each", "errors", "for", "format", "formatted", "good", "green", "headline", "index", "intl", "invert", "key", "label", "last", "latency", "metric", "metrics", "month", "name", "news", "number", "period", "positive", "revenue", "row", "rows", "the", "tile", "tooltip", "trend", "unless", "value", "when", "where"], registryDependencies: ["badge", "card", "chart", "utils"] }, { name: "stats-strip", type: "registry:block", title: "Stats Strip", description: "Headline numbers, each card a <dl>: cards rise in turn with Reveal, then each number springs up with CountTo. Final values are in the HTML.", exports: ["StatsStrip"], keywords: ["card", "display", "each", "headline", "its", "number", "numbers", "order", "rises", "row", "springs", "stats", "then", "turn"], registryDependencies: ["card", "count-to", "reveal", "utils"] }, { name: "stepper", type: "registry:ui", title: "Stepper", description: "Multi-step form (questionnaire, checkout, setup wizard). Steps stay mounted so values survive Back and submit together; Continue checks only the current step's native constraints, plus an optional async onNext guard with a spinner. Progress header with springing connectors; works with onSubmit or a Server Action.", exports: ["Stepper", "StepperList", "StepperStep", "StepperFooter"], keywords: ["action", "after", "and", "are", "back", "backlabel", "button", "called", "check", "checks", "children", "connector", "constraints", "continue", "controlled", "current", "defaultvalue", "description", "every", "false", "fields", "fills", "finished", "first", "for", "form", "header", "hidden", "inactive", "its", "last", "links", "matches", "mounted", "multi", "native", "new", "nextlabel", "not", "one", "only", "onnext", "onsubmit", "onvaluechange", "optional", "order", "pass", "progress", "render", "resolve", "return", "runs", "server", "shown", "shows", "spinner", "spring", "start", "stay", "stays", "step", "steps", "submit", "submitlabel", "submits", "survive", "text", "the", "through", "title", "together", "uncontrolled", "unmounted", "value", "values", "while", "with"], registryDependencies: ["button", "focus", "use-controllable-state", "utils"] }, { name: "styles", type: "registry:file", exports: [], keywords: [], registryDependencies: [] }, { name: "switch", type: "registry:ui", title: "Forms", description: "Input, Textarea, Label and Switch: smooth focus rings, native :user-invalid validation (red only after interaction), aria-invalid, auto-growing textarea with an optional character count, and a spring switch.", exports: ["Switch"], keywords: ["called", "checkbox", "checked", "controlled", "defaultchecked", "first", "knob", "native", "new", "oncheckedchange", "pair", "render", "role", "spring", "state", "switch", "the", "uncontrolled", "with"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "table", type: "registry:ui", title: "Table", description: "Server-safe semantic <table> in a scrolling card: header, body, footer and caption, striped rows, tinted selected rows, and sortable headers that set aria-sort and flip their arrow.", exports: ["Table", "TableHeader", "TableBody", "TableFooter", "TableRow", "TableHead", "TableCell", "TableCaption"], keywords: ["alternating", "and", "aria", "around", "arrow", "button", "called", "card", "classes", "column", "containerclassname", "data", "direction", "for", "header", "keyboard", "makes", "narrow", "onsort", "pass", "pressed", "real", "requires", "row", "screens", "scrollable", "scrolling", "scrolls", "selected", "sets", "shading", "shows", "sideways", "sort", "sortable", "state", "striped", "table", "that", "the", "then", "tint", "when"], registryDependencies: ["overflow-focus", "utils"] }, { name: "tabs", type: "registry:ui", title: "Tabs", description: "WAI-ARIA tabs with arrow, Home and End keys. One indicator springs between tabs, segmented or underline. Inactive panels stay in the DOM for SEO; the active one fades in.", exports: ["Tabs", "TabsList", "TabsTrigger", "TabsContent"], keywords: ["activated", "active", "always", "and", "aria", "arrows", "bar", "behind", "called", "children", "content", "controlled", "crawlable", "defaultvalue", "dom", "end", "first", "focus", "hidden", "home", "html", "inactive", "indicator", "labels", "matches", "move", "muted", "one", "onvaluechange", "pair", "panel", "panels", "pill", "remains", "render", "segmented", "springs", "stay", "stays", "tab", "tabs", "tabscontent", "tabstrigger", "the", "their", "track", "uncontrolled", "under", "underline", "value", "variant", "wai", "while", "with"], registryDependencies: ["list", "use-controllable-state", "use-indicator", "utils"] }, { name: "tag-input", type: "registry:ui", title: "Tag Input", description: "Free-form tags: Enter or a separator adds, Backspace removes the last, ← walks onto the tags and Delete removes one, pasting a list adds them all. Duplicates, a max and a validate function keep bad tags in the input. Submits one entry per tag; required needs one.", exports: ["tagFieldClass", "Tag", "useTagKeys", "TagInput"], keywords: ["accessible", "add", "after", "allowed", "and", "animatepresence", "backspace", "besides", "button", "call", "called", "children", "chip", "commit", "controlled", "defaultvalue", "delete", "disabled", "each", "empty", "enter", "esc", "every", "false", "field", "first", "focused", "for", "form", "free", "from", "frominput", "hides", "input", "inside", "its", "keyboard", "keydown", "keys", "last", "least", "limit", "list", "many", "max", "mode", "most", "move", "name", "needs", "one", "onkeydown", "onremove", "onto", "onvaluechange", "order", "out", "pair", "paste", "pasted", "per", "poplayout", "press", "put", "reach", "reject", "removable", "remove", "removeref", "removes", "render", "rendered", "required", "return", "returns", "runs", "separator", "separators", "shows", "space", "split", "springs", "stay", "stays", "stops", "submits", "tab", "tag", "tagref", "tags", "text", "that", "the", "them", "these", "too", "trimming", "type", "typed", "typing", "uncontrolled", "usetagkeys", "validate", "value", "walks", "when", "which", "with"], registryDependencies: ["field", "form-value", "use-controllable-state", "utils"] }, { name: "terminal", type: "registry:ui", title: "Terminal", description: "Terminal window. Snippet mode types install commands once scrolled into view, with the full transcript kept in the DOM for SEO and no-JS; log mode streams lines into a live region that follows the bottom unless you scroll up, then offers a jump back. Status lines carry glyphs, copy grabs the commands.", exports: ["Terminal"], keywords: ["and", "append", "arrives", "back", "before", "body", "bodyclassname", "bottom", "character", "clipboard", "commands", "copy", "copytext", "defaults", "dom", "false", "follows", "for", "full", "hides", "install", "jump", "lines", "live", "log", "mode", "new", "offering", "once", "order", "output", "per", "prompt", "puts", "read", "reveals", "role", "scroll", "scrolling", "seo", "size", "snippet", "snippets", "speed", "stays", "sticks", "stream", "streams", "symbol", "terminal", "text", "the", "title", "typed", "types", "typing", "unless", "view", "what", "when", "window", "you"], registryDependencies: ["app-window", "code", "platform", "utils"] }, { name: "testimonial", type: "registry:block", title: "Testimonial", description: "A large Quote with its author, and everyone else who agrees as an overlapping AvatarGroup. Server-safe.", exports: ["Testimonial"], keywords: ["agrees", "and", "author", "avatar", "avatargroup", "behind", "beside", "carried", "children", "company", "crowd", "else", "everyone", "few", "first", "fold", "initials", "into", "its", "lang", "language", "large", "line", "one", "others", "otherslabel", "photo", "quote", "rest", "role", "said", "show", "stack", "streamers", "subtitle", "the", "trusted", "under", "url", "who", "with", "without"], registryDependencies: ["avatar", "avatar-group", "quote", "utils"] }, { name: "text-swap", type: "registry:ui", title: "TextSwap", description: "Spring-powered text morphing and ticker. Auto-cycles phrases or animates whenever children change with blur and slide transitions.", exports: ["TextSwap"], keywords: ["active", "array", "automatically", "between", "changing", "child", "children", "controlling", "cycle", "cycling", "default", "direction", "externally", "hover", "index", "interval", "items", "milliseconds", "mouse", "new", "pass", "pause", "pauseonhover", "single", "string", "swap", "swaps", "text", "the", "through", "true", "when"], registryDependencies: ["utils"] }, { name: "textarea", type: "registry:ui", title: "Forms", description: "Input, Textarea, Label and Switch: smooth focus rings, native :user-invalid validation (red only after interaction), aria-invalid, auto-growing textarea with an optional character count, and a spring switch.", exports: ["Textarea"], keywords: ["auto", "cap", "content", "corner", "end", "field", "firefox", "grows", "max", "maxlength", "near", "needs", "red", "resizable", "show", "showcount", "sizing", "the", "then", "turns", "unsupported", "used", "warning", "where", "with"], registryDependencies: ["field", "form-value", "input", "utils"] }, { name: "theme", type: "registry:lib", description: "Retints primary, focus rings, selection and switches app-wide. Persists like the theme.", exports: ["isDark", "setTheme", "subscribeTheme", "accents", "getAccent", "setAccent", "themeScript"], keywords: ["and", "app", "focus", "like", "persists", "primary", "retints", "rings", "selection", "switches", "the", "theme", "wide"], registryDependencies: [] }, { name: "theme-toggle", type: "registry:ui", title: "Theme Toggle", description: "Light/dark icon switch with spring rotate-swap; follows the OS until first use.", exports: ["ThemeToggle"], keywords: ["button", "click", "first", "follows", "icon", "moon", "rotate", "spring", "sun", "swap", "until"], registryDependencies: ["button", "theme", "utils"] }, { name: "timeline", type: "registry:ui", title: "Timeline", description: "Server-safe ordered list of events on a rail: icon or dot markers with status colors, machine-readable <time>, title and an optional body. For changelogs, experience and mod logs.", exports: ["Timeline", "TimelineItem"], keywords: ["above", "and", "body", "children", "color", "date", "datetime", "dot", "event", "events", "first", "for", "headline", "icon", "inside", "list", "machine", "marker", "newest", "oldest", "one", "optional", "order", "ordered", "pair", "rail", "readable", "render", "shown", "small", "the", "then", "time", "title", "variant", "with", "without", "yours"], registryDependencies: ["utils"] }, { name: "toast", type: "registry:ui", title: "Toast", description: "Stacked notifications. Hover to expand, swipe to dismiss, timers pause on hover or focus, a toast with an action stays until it's used or dismissed, and F8 jumps to the newest toast from the keyboard.", exports: ["toast", "Toaster"], keywords: ["action", "actionduration", "back", "before", "buttons", "closes", "default", "description", "dismiss", "dismissed", "dismisses", "duration", "error", "esc", "expands", "focus", "hover", "infinity", "jumps", "layout", "loading", "mount", "newest", "once", "own", "pause", "promise", "root", "saved", "sends", "stacked", "stays", "success", "swipe", "tap", "the", "there", "timers", "title", "toast", "toasts", "until", "used", "while", "wins", "with", "without"], registryDependencies: ["focus", "use-dismiss", "use-hotkey", "utils"] }, { name: "toggle-group", type: "registry:ui", title: "Toggle Group", description: "Segmented control of toggle buttons. Single mode slides one pill to the pressed item (view mode, billing period); multiple mode toggles items independently (bold, italic). Arrow keys move between items.", exports: ["ToggleGroup", "ToggleGroupItem"], keywords: ["always", "and", "aria", "arrow", "behind", "between", "billing", "bold", "buttons", "called", "choice", "control", "controlled", "defaultvalue", "end", "every", "filters", "first", "height", "home", "icon", "independent", "italic", "item", "items", "keys", "label", "labels", "mode", "move", "multiple", "need", "one", "only", "onvaluechange", "pair", "period", "pill", "pressed", "render", "reported", "segment", "segmented", "set", "single", "size", "slides", "springs", "the", "time", "toggle", "toggles", "type", "uncontrolled", "value", "values", "view", "when", "with"], registryDependencies: ["list", "use-controllable-state", "use-indicator", "utils"] }, { name: "tooltip", type: "registry:ui", title: "Tooltip", description: "Short label on hover or keyboard focus, also wired as the trigger's aria-describedby. Warm-up: once one opens, neighbors open instantly. Hoverable, Esc dismisses, ignores touch.", exports: ["Tooltip"], keywords: ["accessible", "action", "align", "alignment", "also", "and", "aria", "becomes", "before", "button", "children", "content", "control", "default", "delay", "description", "dismisses", "element", "esc", "first", "flips", "focus", "focusable", "for", "hold", "hover", "how", "icon", "keyboard", "label", "one", "open", "opens", "own", "pointer", "preferred", "press", "reaches", "room", "short", "shows", "side", "stays", "still", "tap", "text", "the", "their", "there", "toggles", "tooltip", "touch", "trigger", "triggers", "wcag", "when", "while", "with"], registryDependencies: ["platform", "use-anchor", "use-dismiss", "use-hover-open", "utils"] }, { name: "typewriter", type: "registry:ui", title: "Typewriter", description: "Types out text character-by-character with optional phrase cycling and pulsing cursor. Full copy stays in the DOM for SEO.", exports: ["Typewriter"], keywords: ["and", "array", "before", "blinking", "called", "character", "classes", "cursor", "cursorchar", "cursorclassname", "custom", "cycle", "default", "delay", "deletespeed", "deleting", "dom", "effect", "for", "full", "fully", "headers", "hero", "loop", "milliseconds", "once", "oncomplete", "pause", "pauseduration", "per", "phrase", "phrases", "quotes", "seo", "show", "speed", "starting", "stays", "text", "the", "through", "true", "type", "typed", "typewriter", "typing", "wait", "when", "whether", "while"], registryDependencies: ["platform", "utils"] }, { name: "use-anchor", type: "registry:hook", description: `Fixed-position coordinates for a floating panel next to its anchor: on the preferred side,
|
|
17725
17902
|
flipped when it doesn't fit, clamped to the viewport, kept in place on scroll and resize.
|
|
17726
17903
|
Measures before paint, so nothing jumps.`, exports: ["useAnchor"], keywords: ["anchor", "and", "before", "clamped", "coordinates", "doesn", "fit", "fixed", "flipped", "floating", "for", "its", "jumps", "kept", "measures", "next", "nothing", "paint", "panel", "place", "position", "preferred", "resize", "scroll", "side", "the", "viewport", "when"], registryDependencies: ["utils"] }, { name: "use-controllable-state", type: "registry:hook", description: "State a parent may own. Controlled while `value` is defined; otherwise kept here, seeded from\n`defaultValue`. The setter always reports through `onChange`, so both modes stay observable.", exports: ["useControllableState"], keywords: ["always", "both", "controlled", "defaultvalue", "defined", "from", "here", "kept", "may", "modes", "observable", "onchange", "otherwise", "own", "parent", "reports", "seeded", "setter", "state", "stay", "the", "through", "value", "while"], registryDependencies: [] }, { name: "use-disclosure", type: "registry:hook", description: "Open state for any overlay. Spread `props` onto Dialog, Drawer, Popover or DropdownMenu and\nopen it from anywhere: `const drawer = useDisclosure(); <Drawer {...drawer.props}>`, `drawer.show()`.", exports: ["useDisclosure"], keywords: ["and", "any", "anywhere", "const", "dialog", "drawer", "dropdownmenu", "for", "from", "onto", "open", "overlay", "popover", "props", "show", "spread", "state", "usedisclosure"], registryDependencies: [] }, { name: "use-dismiss", type: "registry:hook", description: "Inside one of `refs` (panel first, then its trigger), or inside a floating child opened from\nthe panel: a Select list or menu portals out, but it is marked `data-floating`.", exports: ["isWithin", "useDismiss"], keywords: ["and", "but", "child", "children", "closes", "data", "first", "floating", "from", "inside", "its", "list", "marked", "menu", "one", "opened", "out", "outside", "panel", "pointerdown", "portals", "refs", "select", "the", "then", "trigger"], registryDependencies: [] }, { name: "use-hotkey", type: "registry:hook", description: '`"mod+k"`: ⌘K on Mac, Ctrl+K elsewhere, without Alt. `"/"`: the key alone, no modifiers.', exports: ["matchesHotkey", "useHotkey"], keywords: ["alone", "alt", "browser", "ctrl", "disable", "elsewhere", "false", "handler", "key", "keyboard", "leave", "mac", "mod", "modifiers", "pass", "preventdefault", "returns", "shortcut", "the", "undefined", "wide", "window", "without"], registryDependencies: [] }, { name: "use-hover-open", type: "registry:hook", description: "Open-on-hover state with intent delays, shared by Tooltip and HoverCard. Mouse only (touch\ntaps go to the trigger's own action); keyboard focus opens it too. Spread `trigger` on the\nanchor and `floating` on the panel so moving between them keeps it open.", exports: ["useHoverOpen"], keywords: ["action", "anchor", "and", "between", "delays", "floating", "focus", "hover", "hovercard", "intent", "keeps", "keyboard", "mouse", "moving", "only", "open", "opens", "own", "panel", "shared", "spread", "state", "taps", "the", "them", "too", "tooltip", "touch", "trigger", "with"], registryDependencies: [] }, { name: "use-indicator", type: "registry:hook", description: `Offset and width of the active item, for one indicator that springs between items (Tabs,
|
|
17727
17904
|
ToggleGroup). Re-measures when the item or its row resizes (font swap, wrap), or the pill
|
|
@@ -17818,10 +17995,18 @@ async function fetchAllItems(source) {
|
|
|
17818
17995
|
const index = await fetchIndex(source);
|
|
17819
17996
|
return Promise.all(index.map((i) => fetchItem(source, i.name)));
|
|
17820
17997
|
}
|
|
17998
|
+
var jsrBase = async (version) => {
|
|
17999
|
+
try {
|
|
18000
|
+
const res = await fetch(`https://jsr.io/@kznlabs/labsui/${version}/src/registry.json`);
|
|
18001
|
+
return res.ok ? (await res.json()).items : undefined;
|
|
18002
|
+
} catch {
|
|
18003
|
+
return;
|
|
18004
|
+
}
|
|
18005
|
+
};
|
|
17821
18006
|
// jsr.json
|
|
17822
18007
|
var jsr_default = {
|
|
17823
18008
|
name: "@kznlabs/labsui",
|
|
17824
|
-
version: "0.1.
|
|
18009
|
+
version: "0.1.13",
|
|
17825
18010
|
license: "MIT",
|
|
17826
18011
|
exports: "./src/index.ts",
|
|
17827
18012
|
publish: {
|
|
@@ -17949,6 +18134,9 @@ ${bold("Mount once")} in the root layout, inside <MotionProvider>:`);
|
|
|
17949
18134
|
// src/commands/diff.ts
|
|
17950
18135
|
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
|
|
17951
18136
|
import { relative as relative3 } from "node:path";
|
|
18137
|
+
var same = (a, b) => lines(a).join(`
|
|
18138
|
+
`) === lines(b).join(`
|
|
18139
|
+
`);
|
|
17952
18140
|
function matches(a, b) {
|
|
17953
18141
|
const out = new Int32Array(a.length).fill(-1);
|
|
17954
18142
|
let i = 0;
|
|
@@ -18029,7 +18217,7 @@ async function installedItems(config, base, all) {
|
|
|
18029
18217
|
return files.some((file) => existsSync4(file)) ? [{ item, files }] : [];
|
|
18030
18218
|
});
|
|
18031
18219
|
}
|
|
18032
|
-
async function diff(cwd, config, names, version) {
|
|
18220
|
+
async function diff(cwd, config, names, version, loadBase = jsrBase) {
|
|
18033
18221
|
const base = projectBase(cwd, config);
|
|
18034
18222
|
const wanted = new Set(names.map(itemName));
|
|
18035
18223
|
const all = await fetchAllItems(config.registry);
|
|
@@ -18038,10 +18226,22 @@ async function diff(cwd, config, names, version) {
|
|
|
18038
18226
|
throw new CliError(`Unknown item(s): ${unknown.join(", ")}. Search finds the names.`);
|
|
18039
18227
|
const installed = await installedItems(config, base, all);
|
|
18040
18228
|
const out = [...wanted].filter((name) => !installed.some(({ item }) => item.name === name)).map((name) => ({ name, installed: false, files: [] }));
|
|
18229
|
+
const bases = new Map;
|
|
18230
|
+
const baseOf = async (name, since) => {
|
|
18231
|
+
if (!since || config.registry)
|
|
18232
|
+
return;
|
|
18233
|
+
if (since === version)
|
|
18234
|
+
return all.find((item) => item.name === name);
|
|
18235
|
+
if (!bases.has(since))
|
|
18236
|
+
bases.set(since, loadBase(since));
|
|
18237
|
+
return (await bases.get(since))?.[name];
|
|
18238
|
+
};
|
|
18041
18239
|
for (const { item, files } of installed) {
|
|
18042
18240
|
if (wanted.size && !wanted.has(item.name))
|
|
18043
18241
|
continue;
|
|
18044
18242
|
const changed = [];
|
|
18243
|
+
const since = config.installed?.[item.name];
|
|
18244
|
+
const old = await baseOf(item.name, since);
|
|
18045
18245
|
item.files.forEach((file, i) => {
|
|
18046
18246
|
const local = files[i];
|
|
18047
18247
|
if (!local || !existsSync4(local))
|
|
@@ -18054,19 +18254,31 @@ async function diff(cwd, config, names, version) {
|
|
|
18054
18254
|
return;
|
|
18055
18255
|
const body = patch.split(`
|
|
18056
18256
|
`).slice(2);
|
|
18257
|
+
const before = old?.files.find((entry) => entry.path === file.path)?.content;
|
|
18258
|
+
const was = before === undefined ? undefined : rewriteAlias(before, config.alias);
|
|
18057
18259
|
changed.push({
|
|
18058
18260
|
path: shown,
|
|
18059
18261
|
added: body.filter((line) => line.startsWith("+")).length,
|
|
18060
18262
|
removed: body.filter((line) => line.startsWith("-")).length,
|
|
18061
18263
|
formatting: sameCode(theirs, yours),
|
|
18264
|
+
changedBy: was === undefined ? undefined : same(was, yours) ? "upstream" : same(was, theirs) ? "local" : "both",
|
|
18062
18265
|
patch
|
|
18063
18266
|
});
|
|
18064
18267
|
});
|
|
18065
18268
|
if (changed.length)
|
|
18066
|
-
out.push({ name: item.name, installed: true, files: changed });
|
|
18269
|
+
out.push({ name: item.name, installed: true, since, files: changed });
|
|
18067
18270
|
}
|
|
18068
18271
|
return out;
|
|
18069
18272
|
}
|
|
18273
|
+
function changeNote(file, since) {
|
|
18274
|
+
if (file.changedBy === "upstream")
|
|
18275
|
+
return `only labsUI changed it since ${since}; update replaces it`;
|
|
18276
|
+
if (file.changedBy === "local")
|
|
18277
|
+
return "your edits; update keeps them";
|
|
18278
|
+
if (file.changedBy === "both")
|
|
18279
|
+
return `your edits and labsUI's since ${since}; update merges them`;
|
|
18280
|
+
return "";
|
|
18281
|
+
}
|
|
18070
18282
|
function printDiff(items, full) {
|
|
18071
18283
|
if (!items.length)
|
|
18072
18284
|
return console.log(`${green("✓")} Installed items match this labsui version.`);
|
|
@@ -18074,10 +18286,13 @@ function printDiff(items, full) {
|
|
|
18074
18286
|
if (!item.installed)
|
|
18075
18287
|
console.log(` ${item.name.padEnd(24)} ${dim(`not installed (labsui add ${item.name})`)}`);
|
|
18076
18288
|
for (const file of item.files) {
|
|
18289
|
+
const note = file.formatting ? "formatting only" : changeNote(file, item.since);
|
|
18077
18290
|
if (!full) {
|
|
18078
|
-
console.log(` ${item.name.padEnd(24)} ${green(`+${file.added}`)} ${red(`-${file.removed}`)} ${dim(file.path)}${
|
|
18291
|
+
console.log(` ${item.name.padEnd(24)} ${green(`+${file.added}`)} ${red(`-${file.removed}`)} ${dim(file.path)}${note ? dim(` (${note})`) : ""}`);
|
|
18079
18292
|
continue;
|
|
18080
18293
|
}
|
|
18294
|
+
if (note)
|
|
18295
|
+
console.log(dim(`# ${item.name}: ${note}`));
|
|
18081
18296
|
for (const line of file.patch.split(`
|
|
18082
18297
|
`))
|
|
18083
18298
|
console.log(line.startsWith("+") ? green(line) : line.startsWith("-") ? red(line) : line.startsWith("@@") ? dim(line) : line);
|
|
@@ -18085,7 +18300,7 @@ function printDiff(items, full) {
|
|
|
18085
18300
|
}
|
|
18086
18301
|
if (!full)
|
|
18087
18302
|
console.log(`
|
|
18088
|
-
${dim("labsui diff <name> shows the changes;
|
|
18303
|
+
${dim("labsui diff <name> shows the changes; labsui update <name> takes this version and keeps your edits.")}`);
|
|
18089
18304
|
}
|
|
18090
18305
|
|
|
18091
18306
|
// src/commands/doctor.ts
|
|
@@ -18093,7 +18308,7 @@ import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as
|
|
|
18093
18308
|
import { join as join4, relative as relative4 } from "node:path";
|
|
18094
18309
|
|
|
18095
18310
|
// src/merge.ts
|
|
18096
|
-
var
|
|
18311
|
+
var same2 = (a, b) => a.length === b.length && a.every((line, i) => line === b[i]);
|
|
18097
18312
|
function merge3(base, ours, theirs, labels = { ours: "yours", theirs: "labsui" }) {
|
|
18098
18313
|
const baseLines = lines(base);
|
|
18099
18314
|
const ourLines = lines(ours);
|
|
@@ -18114,9 +18329,9 @@ function merge3(base, ours, theirs, labels = { ours: "yours", theirs: "labsui" }
|
|
|
18114
18329
|
const chunkO = baseLines.slice(i, key);
|
|
18115
18330
|
const chunkA = ourLines.slice(ourIndex, ourStop);
|
|
18116
18331
|
const chunkB = theirLines.slice(theirIndex, theirStop);
|
|
18117
|
-
if (
|
|
18332
|
+
if (same2(chunkA, chunkO))
|
|
18118
18333
|
out.push(...chunkB);
|
|
18119
|
-
else if (
|
|
18334
|
+
else if (same2(chunkB, chunkO) || same2(chunkA, chunkB))
|
|
18120
18335
|
out.push(...chunkA);
|
|
18121
18336
|
else {
|
|
18122
18337
|
conflicts++;
|
|
@@ -18495,14 +18710,6 @@ ${dim(`labsui view ${hits[0]?.name} shows props and an example.`)}`);
|
|
|
18495
18710
|
// src/commands/update.ts
|
|
18496
18711
|
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
18497
18712
|
import { dirname as dirname3, relative as relative6 } from "node:path";
|
|
18498
|
-
var jsrBase = async (version) => {
|
|
18499
|
-
try {
|
|
18500
|
-
const res = await fetch(`https://jsr.io/@kznlabs/labsui/${version}/src/registry.json`);
|
|
18501
|
-
return res.ok ? (await res.json()).items : undefined;
|
|
18502
|
-
} catch {
|
|
18503
|
-
return;
|
|
18504
|
-
}
|
|
18505
|
-
};
|
|
18506
18713
|
var norm = (text) => text.replace(/\r\n/g, `
|
|
18507
18714
|
`).replace(/\n*$/, `
|
|
18508
18715
|
`);
|
|
@@ -18822,7 +19029,7 @@ var TOOLS = [
|
|
|
18822
19029
|
{
|
|
18823
19030
|
name: "diff",
|
|
18824
19031
|
title: "Diff installed labsUI items",
|
|
18825
|
-
description: "Compare installed labsUI items with this labsUI version. Returns a unified patch per changed file, from the registry file to the project file (+ lines exist only in the project), with formatting: true when only blank lines or indentation differ; matching items are left out, a named item that isn't installed comes back with installed: false, and when nothing differs it says so. Use it to see
|
|
19032
|
+
description: "Compare installed labsUI items with this labsUI version. Returns a unified patch per changed file, from the registry file to the project file (+ lines exist only in the project), with formatting: true when only blank lines or indentation differ and changedBy saying whose change it is since the installed version: upstream (only labsUI changed it; update replaces the file), local (only you did; update keeps it) or both (update merges), unset when that version can't be fetched; matching items are left out, a named item that isn't installed comes back with installed: false, and when nothing differs it says so. Use it before update to see what it will do. Needs init.",
|
|
18826
19033
|
inputSchema: {
|
|
18827
19034
|
type: "object",
|
|
18828
19035
|
properties: { names: installed }
|
|
@@ -18911,9 +19118,13 @@ async function callTool(ctx, name, args) {
|
|
|
18911
19118
|
if (!config)
|
|
18912
19119
|
throw new CliError("labsUI is not set up here. Call the init tool first.");
|
|
18913
19120
|
const items = await diff(ctx.cwd, { ...config, ...ctx.registry && { registry: ctx.registry } }, list(args.names), ctx.version);
|
|
18914
|
-
const body = items.length ? items.flatMap((i) => i.installed ? i.files.map((file) =>
|
|
19121
|
+
const body = items.length ? items.flatMap((i) => i.installed ? i.files.map((file) => {
|
|
19122
|
+
const note = changeNote(file, i.since);
|
|
19123
|
+
return `${note ? `${i.name}: ${note}
|
|
19124
|
+
` : ""}\`\`\`diff
|
|
18915
19125
|
${file.patch}
|
|
18916
|
-
|
|
19126
|
+
\`\`\``;
|
|
19127
|
+
}) : [`${i.name} is not installed; add installs it.`]).join(`
|
|
18917
19128
|
|
|
18918
19129
|
`) : "Installed items match this labsui version.";
|
|
18919
19130
|
return text(body, { items });
|