diff --git a/docs/src/api.json b/docs/src/api.json index 4520866e..57722f2b 100644 --- a/docs/src/api.json +++ b/docs/src/api.json @@ -1,1843 +1,2213 @@ { - "Tree": { - "constructorProps": [ - { - "name": "multiple", - "type": "MaybeGetter", - "description": "If `true`, the user can select multiple items.", - "defaultValue": "false", - "optional": true - }, - { - "name": "selected", - "type": "MaybeMultiple | undefined", - "description": "The currently selected item(s).\nIf `multiple` is `true`, this should be an `Iterable`.\nOtherwise, it'll be a `string`.", - "defaultValue": "undefined", - "optional": true - }, - { - "name": "onSelectedChange", - "type": "| ((value: Multiple extends true ? Set : string | undefined) => void)\n | undefined", - "description": "Callback fired when selection changes", - "optional": true - }, - { - "name": "expanded", - "type": "IterableProp", - "description": "The currently expanded items", - "defaultValue": "undefined", - "optional": true - }, - { - "name": "onExpandedChange", - "type": "((value: Set) => void) | undefined", - "description": "Callback fired when expanded state changes", - "optional": true - }, - { - "name": "expandOnClick", - "type": "MaybeGetter", - "description": "If `true`, groups (items with children) expand on click.", - "defaultValue": "true", - "optional": true - }, - { - "name": "items", - "type": "IterableProp", - "description": "The items contained in the tree.", - "optional": false - }, - { - "name": "typeaheadTimeout", - "type": "MaybeGetter", - "description": "How many time (in ms) the typeahead string is held before it is cleared", - "defaultValue": "500", - "optional": true - } - ], - "methods": [ - { - "name": "isSelected", - "type": "(id: string) => boolean", - "description": "Checks if an item is currently selected\n@param id - ID of the item to check" - }, - { - "name": "isExpanded", - "type": "(id: string) => boolean", - "description": "Checks if an item is currently expanded\n@param id - ID of the item to check" - }, - { - "name": "expand", - "type": "(id: string) => void", - "description": "Expands a specific item\n@param id - ID of the item to expand" - }, - { - "name": "collapse", - "type": "(id: string) => void", - "description": "Collapses a specific item\n@param id - ID of the item to collapse" - }, - { - "name": "toggleExpand", - "type": "(id: string) => void", - "description": "Toggles the expanded state of an item\n@param id - ID of the item to toggle" - }, - { - "name": "select", - "type": "(id: string) => void", - "description": "Selects a specific item\n@param id - ID of the item to select" - }, - { - "name": "deselect", - "type": "(id: string) => void", - "description": "Deselects a specific item\n@param id - ID of the item to deselect" - }, - { - "name": "clearSelection", - "type": "() => void", - "description": "Clears all current selections" - }, - { - "name": "toggleSelect", - "type": "(id: string) => void", - "description": "Toggles the selected state of an item\n@param id - ID of the item to toggle" - }, - { - "name": "selectAll", - "type": "() => void", - "description": "Selects all visible items.\nIf all items are already selected, clears the selection." - }, - { - "name": "getItemId", - "type": "(id: string) => string", - "description": "Gets the DOM ID for a specific tree item\n@param id - ID of the item" - }, - { - "name": "getItemEl", - "type": "(id: string) => HTMLElement | null", - "description": "Gets the DOM element for a specific tree item\n@param id - ID of the item" - }, - { - "name": "selectUntil", - "type": "(id: string) => void", - "description": "Selects all items between the last selected item and the specified item\n@param id - ID of the item to select until" - } - ], - "properties": [ - { - "name": "collection", - "type": "Collection", - "description": "The items contained in the tree" - }, - { - "name": "multiple", - "type": "Multiple", - "description": "If `true`, the user can select multiple items holding `Control`/`Meta` or `Shift`" - }, - { - "name": "expandOnClick", - "type": "boolean", - "description": "If `true`, groups (items with children) expand on click" - }, - { - "name": "typeaheadTimeout", - "type": "number", - "description": "" - }, - { - "name": "typeahead", - "type": "(\n letter: string,\n) =>\n | {\n readonly child: Child\n readonly value: string\n readonly typeahead: string\n readonly current: boolean\n }\n | undefined", - "description": "" - }, - { - "name": "items", - "type": "I[]", - "description": "" - }, - { - "name": "selected", - "type": "FalseIfUndefined>", - "description": "Currently selected item(s)\nFor multiple selection, returns a Set of IDs\nFor single selection, returns a single ID or undefined" - }, - { - "name": "expanded", - "type": "SvelteSet", - "description": "Set of currently expanded item IDs" - }, - { - "name": "root", - "type": "{ role: string; \"data-melt-tree-root\": string }", - "description": "Gets ARIA attributes for the root tree element" - }, - { - "name": "group", - "type": "{ role: string; \"data-melt-tree-group\": string }", - "description": "ARIA attributes for group elements" - }, - { - "name": "children", - "type": "Child[]", - "description": "Array of Child instances representing the top-level items" - } - ], - "propsAlt": "\n\nexport type TreeProps = {\n /**\n * If `true`, the user can select multiple items.\n * @default false\n */\n multiple?: MaybeGetter;\n /**\n * The currently selected item(s).\n * If `multiple` is `true`, this should be an `Iterable`.\n * Otherwise, it'll be a `string`.\n * @default undefined\n */\n selected?: MaybeMultiple;\n /**\n * Callback fired when selection changes\n * @param value - For multiple selection, a Set of selected IDs. For single selection, a single ID or undefined\n */\n onSelectedChange?: (value: Multiple extends true ? Set : string | undefined) => void;\n /**\n * The currently expanded items\n *\n * @default undefined\n */\n expanded?: MaybeMultiple;\n /**\n * Callback fired when expanded state changes\n * @param value - Set of expanded item IDs\n */\n onExpandedChange?: (value: Set) => void;\n /**\n * If `true`, groups (items with children) expand on click.\n * @default true\n */\n expandOnClick?: MaybeGetter;\n /**\n * The items contained in the tree.\n * @required\n */\n items: IterableProp;\n /**\n * How many time (in ms) the typeahead string is held before it is cleared\n * @default 500\n */\n typeaheadTimeout?: MaybeGetter;\n};" - }, - "Tooltip": { - "constructorProps": [ - { - "name": "open", - "type": "MaybeGetter", - "description": "If the Tooltip is open.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", - "defaultValue": "false", - "optional": true - }, - { - "name": "onOpenChange", - "type": "((value: boolean) => void) | undefined", - "description": "Called when the value is supposed to change.", - "optional": true - }, - { - "name": "closeOnPointerDown", - "type": "MaybeGetter", - "description": "If `true`, tooltip will close if trigger is pressed.", - "defaultValue": "true", - "optional": true - }, - { - "name": "openDelay", - "type": "MaybeGetter", - "description": "Tooltip open delay in milliseconds.", - "defaultValue": "1000", - "optional": true - }, - { - "name": "closeDelay", - "type": "MaybeGetter", - "description": "Tooltip close delay in milliseconds.", - "defaultValue": "0", - "optional": true - }, - { - "name": "floatingConfig", - "type": "UseFloatingConfig | undefined>", - "description": "Config to be passed to `useFloating`", - "optional": true - }, - { - "name": "forceVisible", - "type": "MaybeGetter", - "description": "If the popover visibility should be controlled by the user.", - "defaultValue": "false", - "optional": true - }, - { - "name": "disableHoverableContent", - "type": "MaybeGetter", - "description": "If `true`, leaving trigger will close the tooltip.", - "defaultValue": "false", - "optional": true - } - ], - "methods": [], - "properties": [ - { - "name": "ids", - "type": "{ trigger: string; content: string; arrow: string }", - "description": "" - }, - { - "name": "invokerRect", - "type": "{ x: number; y: number; width: number; height: number } | undefined", - "description": "" - }, - { - "name": "closeOnPointerDown", - "type": "boolean", - "description": "" - }, - { - "name": "openDelay", - "type": "number", - "description": "" - }, - { - "name": "closeDelay", - "type": "number", - "description": "" - }, - { - "name": "disableHoverableContent", - "type": "boolean", - "description": "" - }, - { - "name": "forceVisible", - "type": "boolean", - "description": "" - }, - { - "name": "floatingConfig", - "type": "UseFloatingConfig", - "description": "" - }, - { - "name": "isVisible", - "type": "boolean", - "description": "State" - }, - { - "name": "graceAreaPolygon", - "type": "{ x: number; y: number }[]", - "description": "" - }, - { - "name": "open", - "type": "boolean", - "description": "" - }, - { - "name": "trigger", - "type": "{\n readonly onfocusout: () => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}`\n readonly \"data-melt-tooltip-trigger\": \"\"\n readonly id: string\n readonly \"aria-describedby\": string\n readonly \"data-open\": \"\" | undefined\n readonly onpointerdown: () => void\n readonly onpointerenter: (\n e: PointerEvent & { currentTarget: EventTarget & HTMLElement },\n ) => void\n readonly onpointermove: () => void\n readonly onpointerleave: (\n e: PointerEvent & { currentTarget: EventTarget & HTMLElement },\n ) => void\n readonly onfocus: () => void\n readonly onblur: () => void\n}", - "description": "" - }, - { - "name": "content", - "type": "{\n readonly style: string\n readonly onfocusout: () => Promise\n readonly \"data-melt-tooltip-content\": \"\"\n readonly id: string\n readonly popover: \"manual\"\n readonly role: \"tooltip\"\n readonly tabindex: -1\n readonly inert: boolean\n readonly \"data-open\": \"\" | undefined\n readonly onpointerenter: () => void\n readonly onpointerleave: () => void\n readonly onpointerdown: () => void\n}", - "description": "" - }, - { - "name": "arrow", - "type": "{\n readonly \"data-melt-tooltip-arrow\": \"\"\n readonly id: string\n readonly \"data-arrow\": \"\"\n readonly \"aria-hidden\": true\n readonly \"data-open\": \"\" | undefined\n}", - "description": "" - } - ], - "propsAlt": "export type TooltipProps = {\n /**\n * If the Tooltip is open.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n * @default false\n */\n open?: MaybeGetter;\n\n /**\n * Called when the value is supposed to change.\n */\n onOpenChange?: (value: boolean) => void;\n\n /**\n * If `true`, tooltip will close if trigger is pressed.\n *\n * @default true\n */\n closeOnPointerDown?: MaybeGetter;\n\n /**\n * Tooltip open delay in milliseconds.\n *\n * @default 1000\n */\n openDelay?: MaybeGetter;\n\n /**\n * Tooltip close delay in milliseconds.\n *\n * @default 0\n */\n closeDelay?: MaybeGetter;\n\n /**\n * Config to be passed to `useFloating`\n */\n floatingConfig?: UseFloatingArgs[\"config\"];\n\n /**\n * If the popover visibility should be controlled by the user.\n *\n * @default false\n */\n forceVisible?: MaybeGetter;\n\n /**\n * If `true`, leaving trigger will close the tooltip.\n *\n * @default false\n */\n disableHoverableContent?: MaybeGetter;\n};" - }, - "Toggle": { - "constructorProps": [ - { - "name": "value", - "type": "MaybeGetter | undefined", - "description": "The value for the Toggle.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", - "defaultValue": "false", - "optional": true - }, - { - "name": "onValueChange", - "type": "((value: boolean) => void) | undefined", - "description": "Called when the value is supposed to change.", - "optional": true - }, - { - "name": "disabled", - "type": "MaybeGetter", - "description": "If `true`, prevents the user from interacting with the input.", - "defaultValue": "false", - "optional": true - } - ], - "methods": [], - "properties": [ - { - "name": "disabled", - "type": "boolean", - "description": "" - }, - { - "name": "value", - "type": "boolean", - "description": "" - }, - { - "name": "trigger", - "type": "{\n readonly \"data-melt-toggle-trigger\": \"\"\n readonly \"data-checked\": \"\" | undefined\n readonly \"aria-pressed\": boolean\n readonly disabled: true | undefined\n readonly onclick: () => void\n}", - "description": "The trigger that toggles the value." - }, - { - "name": "hiddenInput", - "type": "{\n readonly \"data-melt-toggle-hidden-input\": \"\"\n readonly type: \"hidden\"\n readonly value: \"on\" | \"off\"\n}", - "description": "A hidden input field to use within forms." - } - ], - "propsAlt": "export type ToggleProps = {\n /**\n * The value for the Toggle.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n *\n * @default false\n */\n value?: MaybeGetter;\n /**\n * Called when the value is supposed to change.\n */\n onValueChange?: (value: boolean) => void;\n\n /**\n * If `true`, prevents the user from interacting with the input.\n *\n * @default false\n */\n disabled?: MaybeGetter;\n};" - }, - "Toaster": { - "constructorProps": [ - { - "name": "closeDelay", - "type": "MaybeGetter", - "description": "The delay in milliseconds before the toast closes. Set to 0 to disable.", - "defaultValue": "5000", - "optional": true - }, - { - "name": "type", - "type": "MaybeGetter<\"assertive\" | \"polite\" | undefined>", - "description": "The sensitivity of the toast for accessibility purposes.\nhttps://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-live", - "defaultValue": "'polite'", - "optional": true - }, - { - "name": "hover", - "type": "MaybeGetter<\"pause\" | \"pause-all\" | null | undefined>", - "description": "The behaviour when a toast is hovered.\nPass in `null` to disable.", - "defaultValue": "'pause'", - "optional": true - } - ], - "methods": [], - "properties": [ - { - "name": "ids", - "type": "{ root: string }", - "description": "" - }, - { - "name": "closeDelay", - "type": "number", - "description": "" - }, - { - "name": "type", - "type": "\"assertive\" | \"polite\"", - "description": "" - }, - { - "name": "hover", - "type": "\"pause\" | \"pause-all\" | null", - "description": "" - }, - { - "name": "toasts", - "type": "Toast[]", - "description": "The active toasts." - }, - { - "name": "addToast", - "type": "(props: AddToastArgs) => Toast", - "description": "Adds a toast." - }, - { - "name": "removeToast", - "type": "(id: string) => void", - "description": "Removes the toast with the specified ID.\n@param id The id of the toast." - }, - { - "name": "updateToast", - "type": "(args: UpdateToastArgs) => void", - "description": "Updates a toast's data.\n@param id The id of the toast.\n@param data The updated data." - }, - { - "name": "root", - "type": "{\n readonly \"data-melt-toaster-root\": \"\"\n readonly id: string\n readonly popover: \"manual\"\n}", - "description": "Spread attributes for the container of the toasts." - } - ], - "propsAlt": "export type ToasterProps = {\n /**\n * The delay in milliseconds before the toast closes. Set to 0 to disable.\n * @default 5000\n */\n closeDelay?: MaybeGetter;\n\n /**\n * The sensitivity of the toast for accessibility purposes.\n * https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-live\n * @default 'polite'\n */\n type?: MaybeGetter<\"assertive\" | \"polite\" | undefined>;\n\n /**\n * The behaviour when a toast is hovered.\n * Pass in `null` to disable.\n *\n * @default 'pause'\n */\n hover?: MaybeGetter<\"pause\" | \"pause-all\" | null | undefined>;\n};" - }, - "Tabs": { - "constructorProps": [ - { - "name": "selectWhenFocused", - "type": "MaybeGetter", - "description": "If `true`, the value will be changed whenever a trigger is focused.", - "defaultValue": "true", - "optional": true - }, - { - "name": "loop", - "type": "MaybeGetter", - "description": "If the the trigger selection should loop when navigating with the arrow keys.", - "defaultValue": "true", - "optional": true - }, - { - "name": "orientation", - "type": "MaybeGetter<\"horizontal\" | \"vertical\" | undefined>", - "description": "The orientation of the tabs.", - "defaultValue": "\"horizontal\"", - "optional": true - }, - { - "name": "value", - "type": "MaybeGetter", - "description": "The default value for `tabs.value`\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that `tabs.value` only changes when the getter returns a new value.", - "optional": false - }, - { - "name": "onValueChange", - "type": "((active: T) => void) | undefined", - "description": "Called when the `Tabs` instance tries to change the active tab.", - "optional": true - } - ], - "methods": [ - { - "name": "getTrigger", - "type": "(value: T) => {\n readonly \"data-melt-tabs-trigger\": T\n readonly \"data-active\": \"\" | undefined\n readonly tabindex: 0 | -1\n readonly role: \"tab\"\n readonly \"aria-selected\": boolean\n readonly \"aria-controls\": string\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n readonly onclick: () => T\n readonly onkeydown: (e: KeyboardEvent) => void\n readonly id: string\n}", - "description": "Gets the attributes and listeners for a tab trigger. Requires an identifying tab value." - }, - { - "name": "getContent", - "type": "(value: T) => {\n readonly \"data-melt-tabs-content\": \"\"\n readonly hidden: boolean\n readonly \"data-active\": \"\" | undefined\n readonly role: \"tabpanel\"\n readonly id: string\n readonly \"aria-labelledby\": string\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n}", - "description": "Gets the attributes and listeners for the tabs contents. Requires an identifying tab value." - } - ], - "properties": [ - { - "name": "selectWhenFocused", - "type": "boolean", - "description": "" - }, - { - "name": "loop", - "type": "boolean", - "description": "" - }, - { - "name": "orientation", - "type": "\"horizontal\" | \"vertical\"", - "description": "" - }, - { - "name": "value", - "type": "T", - "description": "The current selected tab." - }, - { - "name": "triggerList", - "type": "{\n readonly \"data-melt-tabs-trigger-list\": \"\"\n readonly role: \"tablist\"\n readonly \"aria-orientation\": \"horizontal\" | \"vertical\"\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n}", - "description": "The attributes for the list that contains the tab triggers." - } - ], - "propsAlt": "export type TabsProps = {\n /**\n * If `true`, the value will be changed whenever a trigger is focused.\n *\n * @default true\n */\n selectWhenFocused?: MaybeGetter;\n /**\n * If the the trigger selection should loop when navigating with the arrow keys.\n *\n * @default true\n */\n loop?: MaybeGetter;\n /**\n * The orientation of the tabs.\n *\n * @default \"horizontal\"\n */\n orientation?: MaybeGetter<\"horizontal\" | \"vertical\" | undefined>;\n /**\n * The default value for `tabs.value`\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that `tabs.value` only changes when the getter returns a new value.\n *\n */\n value: MaybeGetter;\n /**\n * Called when the `Tabs` instance tries to change the active tab.\n */\n onValueChange?: (active: T) => void;\n};" - }, - "SpatialMenu": { - "constructorProps": [ - { - "name": "highlighted", - "type": "MaybeGetter", - "description": "The currently highlighted value.", - "optional": true - }, - { - "name": "onHighlightChange", - "type": "((highlighted: T | null) => void) | undefined", - "description": "Called when the highlighted value changes.", - "optional": true - }, - { - "name": "onSelect", - "type": "((value: T) => void) | undefined", - "optional": true - }, - { - "name": "wrap", - "type": "MaybeGetter | undefined", - "description": "Whether navigation should wrap around when reaching the edges.", - "defaultValue": "false", - "optional": true - }, - { - "name": "scrollBehavior", - "type": "MaybeGetter<\"auto\" | \"smooth\" | \"instant\" | null> | undefined", - "description": "Scroll behavior when highlighting an item with the keyboard.\n`null` to disable scrolling.", - "defaultValue": "\"smooth\"", - "optional": true - }, - { - "name": "toleranceCol", - "type": "MaybeGetter | undefined", - "description": "The maximum distance a the centerX of an item can be in relation\nto the highlighted item to be considered as being on the same column.\n\nSet to `null` to disable.", - "defaultValue": "16", - "optional": true - }, - { - "name": "toleranceRow", - "type": "MaybeGetter | undefined", - "description": "The maximum distance a the centerY of an item can be in relation\nto the highlighted item to be considered as being on the same row.\n\nSet to `null` to disable.", - "defaultValue": "16", - "optional": true - }, - { - "name": "crossAxis", - "type": "MaybeGetter | undefined", - "description": "If `true`, arrow keys will navigate cross-axis as well, if no item\nis available on the current axis.", - "defaultValue": "true", - "optional": true - } - ], - "methods": [ - { - "name": "getItem", - "type": "(\n value: T,\n options?: Pick, \"onSelect\" | \"disabled\"> | undefined,\n) => SpatialMenuItem", - "description": "" - } - ], - "properties": [ - { - "name": "onSelect", - "type": "((value: T) => void) | undefined", - "description": "" - }, - { - "name": "wrap", - "type": "boolean", - "description": "" - }, - { - "name": "scrollBehavior", - "type": "\"auto\" | \"smooth\" | \"instant\" | null", - "description": "" - }, - { - "name": "toleranceCol", - "type": "number | null", - "description": "" - }, - { - "name": "toleranceRow", - "type": "number | null", - "description": "" - }, - { - "name": "crossAxis", - "type": "boolean", - "description": "" - }, - { - "name": "selectionMode", - "type": "\"keyboard\" | \"mouse\"", - "description": "" - }, - { - "name": "highlighted", - "type": "T | null", - "description": "" - }, - { - "name": "root", - "type": "{\n readonly [x: symbol]: (node: HTMLElement) => () => void\n readonly \"data-melt-spatial-menu-root\": \"\"\n readonly tabindex: 0\n readonly onkeydown: (e: KeyboardEvent) => void\n}", - "description": "The root element." - }, - { - "name": "input", - "type": "{\n readonly [x: symbol]: (node: HTMLInputElement) => () => void\n readonly \"data-melt-spatial-menu-input\": \"\"\n readonly onkeydown: (e: KeyboardEvent) => void\n}", - "description": "" - } - ], - "propsAlt": "export type SpatialMenuProps = {\n /**\n * The currently highlighted value.\n */\n highlighted?: MaybeGetter;\n\n /**\n * Called when the highlighted value changes.\n */\n onHighlightChange?: (highlighted: T | null) => void;\n\n onSelect?: (value: T) => void;\n\n /**\n * Whether navigation should wrap around when reaching the edges.\n * @default false\n */\n wrap?: MaybeGetter;\n\n /**\n * Scroll behavior when highlighting an item with the keyboard.\n * `null` to disable scrolling.\n *\n * @default \"smooth\"\n */\n scrollBehavior?: MaybeGetter<\"smooth\" | \"instant\" | \"auto\" | null>;\n\n /**\n * The maximum distance a the centerX of an item can be in relation\n * to the highlighted item to be considered as being on the same column.\n *\n * Set to `null` to disable.\n *\n * @default 16\n */\n toleranceCol?: MaybeGetter;\n\n /**\n * The maximum distance a the centerY of an item can be in relation\n * to the highlighted item to be considered as being on the same row.\n *\n * Set to `null` to disable.\n *\n * @default 16\n */\n toleranceRow?: MaybeGetter;\n\n /**\n * If `true`, arrow keys will navigate cross-axis as well, if no item\n * is available on the current axis.\n *\n * @default true\n */\n crossAxis?: MaybeGetter;\n};" - }, - "Slider": { - "constructorProps": [ - { - "name": "min", - "type": "MaybeGetter", - "description": "The minimum value of the slider.", - "defaultValue": "0", - "optional": true - }, - { - "name": "max", - "type": "MaybeGetter", - "description": "The maximum value of the slider.", - "defaultValue": "100", - "optional": true - }, - { - "name": "orientation", - "type": "MaybeGetter<\"horizontal\" | \"vertical\" | undefined>", - "description": "The orientation of the slider.", - "defaultValue": "\"horizontal\"", - "optional": true - }, - { - "name": "step", - "type": "MaybeGetter", - "description": "The step size of the slider.", - "defaultValue": "1", - "optional": true - }, - { - "name": "value", - "type": "MaybeGetter", - "description": "The default value for `tabs.value`\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that `tabs.value` only changes when the getter returns a new value.\n\nIf omitted, it will use the first tab as default.", - "defaultValue": "undefined", - "optional": true - }, - { - "name": "onValueChange", - "type": "((active: number) => void) | undefined", - "description": "Called when the `Slider` instance tries to change the active tab.", - "optional": true - } - ], - "methods": [], - "properties": [ - { - "name": "min", - "type": "number", - "description": "" - }, - { - "name": "max", - "type": "number", - "description": "" - }, - { - "name": "orientation", - "type": "\"horizontal\" | \"vertical\"", - "description": "" - }, - { - "name": "step", - "type": "number", - "description": "" - }, - { - "name": "ids", - "type": "{ root: string; thumb: string }", - "description": "" - }, - { - "name": "value", - "type": "number", - "description": "The value of the slider." - }, - { - "name": "root", - "type": "{\n readonly \"data-dragging\": \"\" | undefined\n readonly \"data-value\": number\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n readonly \"aria-valuenow\": number\n readonly \"aria-valuemin\": number\n readonly \"aria-valuemax\": number\n readonly \"aria-orientation\": \"horizontal\" | \"vertical\"\n readonly style: `--percentage: ${string}; --percentage-inv: ${string}; touch-action: ${string}`\n readonly tabindex: 0\n readonly role: \"slider\"\n readonly \"data-melt-slider-root\": \"\"\n readonly id: string\n readonly onpointerdown: (e: PointerEvent) => void\n readonly onkeydown: (e: KeyboardEvent) => void\n}", - "description": "The root of the slider.\nAny cursor interaction along this element will change the slider's values." - }, - { - "name": "thumb", - "type": "{\n readonly \"data-dragging\": \"\" | undefined\n readonly \"data-value\": number\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n readonly \"data-melt-slider-thumb\": \"\"\n readonly id: string\n readonly tabindex: 0\n}", - "description": "The slider's thumb, positioned at the end of the range." - } - ], - "propsAlt": "export type SliderProps = {\n /**\n * The minimum value of the slider.\n *\n * @default 0\n */\n min?: MaybeGetter;\n /**\n * The maximum value of the slider.\n *\n * @default 100\n */\n max?: MaybeGetter;\n /**\n * The orientation of the slider.\n *\n * @default \"horizontal\"\n */\n orientation?: MaybeGetter<\"horizontal\" | \"vertical\" | undefined>;\n\n /**\n * The step size of the slider.\n *\n * @default 1\n */\n step?: MaybeGetter;\n\n /**\n * The default value for `tabs.value`\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that `tabs.value` only changes when the getter returns a new value.\n *\n * If omitted, it will use the first tab as default.\n *\n * @default undefined\n */\n value?: MaybeGetter;\n /**\n * Called when the `Slider` instance tries to change the active tab.\n */\n onValueChange?: (active: number) => void;\n};" - }, - "Select": { - "constructorProps": [ - { - "name": "open", - "type": "any", - "description": "If the Popover is open.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", - "defaultValue": "false", - "optional": true - }, - { - "name": "focus", - "type": "any", - "optional": true - }, - { - "name": "onOpenChange", - "type": "any", - "description": "Called when the value is supposed to change.", - "optional": true - }, - { - "name": "forceVisible", - "type": "any", - "description": "If the popover visibility should be controlled by the user.", - "defaultValue": "false", - "optional": true - }, - { - "name": "floatingConfig", - "type": "any", - "description": "Config to be passed to `useFloating`", - "optional": true - }, - { - "name": "closeOnEscape", - "type": "any", - "description": "If the popover should close when clicking escape.", - "defaultValue": "true", - "optional": true - }, - { - "name": "closeOnOutsideClick", - "type": "any", - "description": "If the popover should close when clicking outside.\nAlternatively, accepts a function that receives the clicked element,\nand returns if the popover should close.", - "defaultValue": "true", - "optional": true - }, - { - "name": "multiple", - "type": "MaybeGetter", - "description": "If `true`, multiple options can be selected at the same time.", - "defaultValue": "false", - "optional": true - }, - { - "name": "value", - "type": "MaybeMultiple | undefined", - "description": "The value for the Select.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", - "defaultValue": "false", - "optional": true - }, - { - "name": "onValueChange", - "type": "OnMultipleChange | undefined", - "description": "Called when the value is supposed to change.", - "optional": true - }, - { - "name": "highlighted", - "type": "MaybeGetter", - "description": "The currently highlighted value.", - "optional": true - }, - { - "name": "onHighlightChange", - "type": "((highlighted: T | null) => void) | undefined", - "description": "Called when the highlighted value changes.", - "optional": true - }, - { - "name": "typeaheadTimeout", - "type": "MaybeGetter", - "description": "How many time (in ms) the typeahead string is held before it is cleared", - "defaultValue": "500", - "optional": true - }, - { - "name": "sameWidth", - "type": "MaybeGetter", - "description": "If the content should have the same width as the trigger", - "defaultValue": "true", - "optional": true - }, - { - "name": "scrollAlignment", - "type": "MaybeGetter<\"nearest\" | \"center\" | null | undefined>", - "description": "Determines behavior when scrolling items into view.\nSet to null to disable auto-scrolling.", - "defaultValue": "\"nearest\"", - "optional": true - } - ], - "methods": [ - { - "name": "getOptionId", - "type": "(value: T) => string", - "description": "" - }, - { - "name": "getOption", - "type": "(\n value: T,\n label?: string | undefined,\n) => {\n readonly \"data-melt-select-option\": \"\"\n readonly \"data-value\": string\n readonly \"data-label\": string\n readonly \"aria-hidden\": true | undefined\n readonly \"aria-selected\": boolean\n readonly \"data-highlighted\": \"\" | undefined\n readonly role: \"option\"\n readonly tabindex: -1\n readonly onmouseover: () => void\n readonly onclick: () => void\n}", - "description": "" - } - ], - "properties": [ - { - "name": "multiple", - "type": "Multiple", - "description": "" - }, - { - "name": "scrollAlignment", - "type": "\"nearest\" | \"center\" | null", - "description": "" - }, - { - "name": "ids", - "type": "{ trigger: string; content: string; option: string } & {\n popover: string\n}", - "description": "" - }, - { - "name": "typeaheadTimeout", - "type": "number", - "description": "" - }, - { - "name": "typeahead", - "type": "(\n letter: string,\n) => { value: any; typeahead: string; current: boolean } | undefined", - "description": "" - }, - { - "name": "getOptionLabel", - "type": "(value: T) => string", - "description": "" - }, - { - "name": "isSelected", - "type": "(value: T) => boolean", - "description": "" - }, - { - "name": "select", - "type": "(value: T) => void", - "description": "" - }, - { - "name": "value", - "type": "SelectionStateValue", - "description": "" - }, - { - "name": "highlighted", - "type": "T | null", - "description": "" - }, - { - "name": "valueAsString", - "type": "string", - "description": "" - }, - { - "name": "label", - "type": "{\n for: string\n onclick: (\n e: MouseEvent & { currentTarget: EventTarget & HTMLLabelElement },\n ) => void\n}", - "description": "" - }, - { - "name": "trigger", - "type": "{\n readonly onfocus: (event: FocusEvent) => void\n readonly onfocusout: (event: FocusEvent) => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n readonly popovertarget: string\n readonly onclick: (e: Event) => void\n} & {\n \"data-melt-select-trigger\": string\n id: string\n role: string\n \"aria-expanded\": boolean\n \"aria-controls\": string\n \"aria-owns\": string\n onkeydown: (e: KeyboardEvent) => void\n}", - "description": "" - }, - { - "name": "content", - "type": "{\n readonly onfocus: (event: FocusEvent) => void\n readonly onfocusout: (event: FocusEvent) => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n readonly id: string\n readonly popover: \"manual\"\n readonly ontoggle: (\n e: ToggleEvent & { currentTarget: EventTarget & HTMLElement },\n ) => void\n readonly tabindex: -1\n readonly inert: boolean\n readonly \"data-open\": \"\" | undefined\n} & {\n readonly \"data-melt-select-content\": \"\"\n readonly role: \"listbox\"\n readonly \"aria-expanded\": boolean\n readonly \"aria-activedescendant\": string | undefined\n readonly onkeydown: (e: KeyboardEvent) => void\n}", - "description": "" - } - ], - "propsAlt": "export type SelectProps = Omit & {\n /**\n * If `true`, multiple options can be selected at the same time.\n *\n * @default false\n */\n multiple?: MaybeGetter;\n\n /**\n * The value for the Select.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n *\n * @default false\n */\n value?: MaybeMultiple;\n /**\n * Called when the value is supposed to change.\n */\n onValueChange?: OnMultipleChange;\n\n /**\n * The currently highlighted value.\n */\n highlighted?: MaybeGetter;\n\n /**\n * Called when the highlighted value changes.\n */\n onHighlightChange?: (highlighted: T | null) => void;\n\n /**\n * How many time (in ms) the typeahead string is held before it is cleared\n * @default 500\n */\n typeaheadTimeout?: MaybeGetter;\n\n /**\n * If the content should have the same width as the trigger\n *\n * @default true\n */\n sameWidth?: MaybeGetter;\n\n /**\n * Determines behavior when scrolling items into view.\n * Set to null to disable auto-scrolling.\n *\n * @default \"nearest\"\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#block\n */\n scrollAlignment?: MaybeGetter<\"nearest\" | \"center\" | null | undefined>;\n};" - }, - "RadioGroup": { - "constructorProps": [ - { - "name": "disabled", - "type": "MaybeGetter", - "description": "If `true`, prevents the user from interacting with the group.", - "defaultValue": "false", - "optional": true - }, - { - "name": "required", - "type": "MaybeGetter", - "description": "If `true`, indicates that the user must select a radio button before\nthe owning form can be submitted.", - "defaultValue": "false", - "optional": true - }, - { - "name": "loop", - "type": "MaybeGetter", - "description": "If the the button selection should loop when navigating with the arrow keys.", - "defaultValue": "true", - "optional": true - }, - { - "name": "selectWhenFocused", - "type": "MaybeGetter", - "description": "If `true`, the value will be changed whenever a button is focused.", - "defaultValue": "true", - "optional": true - }, - { - "name": "orientation", - "type": "MaybeGetter<\"horizontal\" | \"vertical\" | undefined>", - "description": "The orientation of the slider.", - "defaultValue": "\"vertical\"", - "optional": true - }, - { - "name": "name", - "type": "MaybeGetter", - "description": "Input name for radio group.", - "optional": true - }, - { - "name": "value", - "type": "MaybeGetter", - "description": "Default value for radio group.", - "defaultValue": "\"\"", - "optional": true - }, - { - "name": "onValueChange", - "type": "((active: string) => void) | undefined", - "description": "Called when the radio button is clicked.", - "optional": true - } - ], - "methods": [ - { - "name": "getItem", - "type": "(item: string) => RadioItem", - "description": "" - }, - { - "name": "select", - "type": "(item: string) => void", - "description": "" - } - ], - "properties": [ - { - "name": "ids", - "type": "{\n root: string\n item: string\n \"hidden-input\": string\n label: string\n}", - "description": "" - }, - { - "name": "disabled", - "type": "boolean", - "description": "" - }, - { - "name": "required", - "type": "boolean", - "description": "" - }, - { - "name": "loop", - "type": "boolean", - "description": "" - }, - { - "name": "selectWhenFocused", - "type": "boolean", - "description": "" - }, - { - "name": "orientation", - "type": "\"horizontal\" | \"vertical\"", - "description": "" - }, - { - "name": "value", - "type": "string", - "description": "" - }, - { - "name": "root", - "type": "{\n readonly \"data-melt-radio-group-root\": \"\"\n readonly id: string\n readonly role: \"radiogroup\"\n readonly \"aria-required\": boolean\n readonly \"aria-labelledby\": string\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n readonly \"data-disabled\": true | undefined\n readonly \"data-value\": string\n}", - "description": "" - }, - { - "name": "label", - "type": "{\n readonly \"data-melt-radio-group-label\": \"\"\n readonly id: string\n readonly for: string\n readonly onclick: (\n e: MouseEvent & { currentTarget: EventTarget & HTMLLabelElement },\n ) => void\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n readonly \"data-disabled\": true | undefined\n readonly \"data-value\": string\n}", - "description": "" - }, - { - "name": "hiddenInput", - "type": "{\n readonly \"data-melt-radio-group-hidden-input\": \"\"\n readonly disabled: boolean\n readonly required: boolean\n readonly hidden: true\n readonly \"aria-hidden\": true\n readonly tabindex: -1\n readonly value: string\n readonly name: string | undefined\n}", - "description": "" - } - ], - "propsAlt": "export type RadioGroupProps = {\n /**\n * If `true`, prevents the user from interacting with the group.\n *\n * @default false\n */\n disabled?: MaybeGetter;\n /**\n * If `true`, indicates that the user must select a radio button before\n * the owning form can be submitted.\n *\n * @default false\n */\n required?: MaybeGetter;\n /**\n * If the the button selection should loop when navigating with the arrow keys.\n *\n * @default true\n */\n loop?: MaybeGetter;\n /**\n * If `true`, the value will be changed whenever a button is focused.\n *\n * @default true\n */\n selectWhenFocused?: MaybeGetter;\n /**\n * The orientation of the slider.\n *\n * @default \"vertical\"\n */\n orientation?: MaybeGetter<\"horizontal\" | \"vertical\" | undefined>;\n /**\n * Input name for radio group.\n */\n name?: MaybeGetter;\n /**\n * Default value for radio group.\n *\n * @default \"\"\n */\n value?: MaybeGetter;\n /**\n * Called when the radio button is clicked.\n */\n onValueChange?: (active: string) => void;\n};" - }, - "Progress": { - "constructorProps": [ - { - "name": "value", - "type": "MaybeGetter", - "description": "The value for the progress.", - "defaultValue": "undefined", - "optional": true - }, - { - "name": "max", - "type": "MaybeGetter", - "description": "The maximum value of the progress.", - "optional": true - }, - { - "name": "onValueChange", - "type": "((value: number) => void) | undefined", - "description": "The callback invoked when the value of the progress changes.", - "optional": true - } - ], - "methods": [], - "properties": [ - { - "name": "max", - "type": "number", - "description": "" - }, - { - "name": "value", - "type": "number", - "description": "" - }, - { - "name": "root", - "type": "{\n \"data-melt-progress-root\": string\n value: number\n max: number\n role: string\n \"aria-valuemin\": number\n \"aria-valuemax\": number\n \"aria-valuenow\": number\n \"data-value\": number\n \"data-state\": string\n \"data-max\": number\n}", - "description": "Spread attributes for the Progress root element." - }, - { - "name": "progress", - "type": "{\n \"data-melt-progress-progress\": string\n style: `--progress: ${string}; --neg-progress: ${string}`\n}", - "description": "Spread attributes for the Progress percentage element.\nProvides a --progress CSS variable that can be used to style the progress:\n`transform: translateX(calc(var(--progress) * -1));`" - } - ], - "propsAlt": "export type ProgressProps = {\n /**\n * The value for the progress.\n *\n * @default undefined\n */\n value?: MaybeGetter;\n\n /**\n * The maximum value of the progress.\n *\n * @deafult 100\n */\n max?: MaybeGetter;\n\n /**\n * The callback invoked when the value of the progress changes.\n */\n onValueChange?: (value: number) => void;\n};" - }, - "Popover": { - "constructorProps": [ - { - "name": "open", - "type": "MaybeGetter", - "description": "If the Popover is open.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", - "defaultValue": "false", - "optional": true - }, - { - "name": "onOpenChange", - "type": "((value: boolean) => void) | undefined", - "description": "Called when the value is supposed to change.", - "optional": true - }, - { - "name": "forceVisible", - "type": "MaybeGetter", - "description": "If the popover visibility should be controlled by the user.", - "defaultValue": "false", - "optional": true - }, - { - "name": "floatingConfig", - "type": "UseFloatingConfig | undefined>", - "description": "Config to be passed to `useFloating`", - "optional": true - }, - { - "name": "sameWidth", - "type": "MaybeGetter", - "description": "If the popover should have the same width as the trigger", - "defaultValue": "false", - "optional": true - }, - { - "name": "closeOnEscape", - "type": "MaybeGetter", - "description": "If the popover should close when clicking escape.", - "defaultValue": "true", - "optional": true - }, - { - "name": "closeOnOutsideClick", - "type": "CloseOnOutsideClickProp", - "description": "If the popover should close when clicking outside.\nAlternatively, accepts a function that receives the clicked element,\nand returns if the popover should close.", - "defaultValue": "true", - "optional": true - }, - { - "name": "focus", - "type": "{ onOpen?: MaybeGetter } | undefined", - "optional": true - } - ], - "methods": [], - "properties": [ - { - "name": "ids", - "type": "{ popover: string } & { trigger: string; content: string }", - "description": "" - }, - { - "name": "trigger", - "type": "{\n readonly onfocus: (event: FocusEvent) => void\n readonly onfocusout: (event: FocusEvent) => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n readonly popovertarget: string\n readonly onclick: (e: Event) => void\n} & { \"data-melt-popover-trigger\": string }", - "description": "The trigger that toggles the value." - }, - { - "name": "content", - "type": "{\n readonly onfocus: (event: FocusEvent) => void\n readonly onfocusout: (event: FocusEvent) => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n readonly id: string\n readonly popover: \"manual\"\n readonly ontoggle: (\n e: ToggleEvent & { currentTarget: EventTarget & HTMLElement },\n ) => void\n readonly tabindex: -1\n readonly inert: boolean\n readonly \"data-open\": \"\" | undefined\n} & { \"data-melt-popover-content\": string }", - "description": "" - } - ], - "propsAlt": "export type PopoverProps = {\n /**\n * If the Popover is open.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n *\n * @default false\n */\n open?: MaybeGetter;\n\n /**\n * Called when the value is supposed to change.\n */\n onOpenChange?: (value: boolean) => void;\n\n /**\n * If the popover visibility should be controlled by the user.\n *\n * @default false\n */\n forceVisible?: MaybeGetter;\n\n /**\n * Config to be passed to `useFloating`\n */\n floatingConfig?: UseFloatingArgs[\"config\"];\n\n /**\n * If the popover should have the same width as the trigger\n *\n * @default false\n */\n sameWidth?: MaybeGetter;\n\n /**\n * If the popover should close when clicking escape.\n *\n * @default true\n */\n closeOnEscape?: MaybeGetter;\n\n /**\n * If the popover should close when clicking outside.\n * Alternatively, accepts a function that receives the clicked element,\n * and returns if the popover should close.\n *\n * @default true\n */\n closeOnOutsideClick?: CloseOnOutsideClickProp;\n\n focus?: {\n /**\n * Which element to focus when the popover opens.\n * Can be a selector string, an element, or a Getter for those.\n * If null, the focus remains on the trigger element.\n *\n * Defaults to the popover content element.\n */\n onOpen?: MaybeGetter;\n\n /**\n * Which element to focus when the popover closes.\n * Can be a selector string, an element, or a Getter for those.\n * If null, the focus goes to the document body.\n *\n * Defaults to the last used trigger element.\n */\n onClose?: MaybeGetter;\n\n /**\n * If focus should be trapped inside the popover content when open.\n *\n * @default false\n */\n trap?: MaybeGetter;\n };\n};" - }, - "PinInput": { - "constructorProps": [ - { - "name": "value", - "type": "MaybeGetter", - "description": "The value for the Pin Input.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", - "defaultValue": "''", - "optional": true - }, - { - "name": "onValueChange", - "type": "((value: string) => void) | undefined", - "description": "Called when the `PinInput` instance tries to change the value.", - "optional": true - }, - { - "name": "onComplete", - "type": "((value: string) => void) | undefined", - "description": "Called when the `PinInput` instance is filled.", - "optional": true - }, - { - "name": "onPaste", - "type": "((value: string) => void) | undefined", - "description": "Override the default behavior when pasting a value.", - "optional": true - }, - { - "name": "onError", - "type": "((error: PinInputError) => void) | undefined", - "description": "Called when the PinInput encounters an error.", - "optional": true - }, - { - "name": "maxLength", - "type": "MaybeGetter", - "description": "The amount of digits in the Pin Input.", - "defaultValue": "4", - "optional": true - }, - { - "name": "placeholder", - "type": "MaybeGetter", - "description": "An optional placeholder to display when the input is empty.", - "defaultValue": "'○'", - "optional": true - }, - { - "name": "disabled", - "type": "MaybeGetter", - "description": "If `true`, prevents the user from interacting with the input.", - "defaultValue": "false", - "optional": true - }, - { - "name": "mask", - "type": "MaybeGetter", - "description": "If the input should be masked like a password.", - "defaultValue": "false", - "optional": true - }, - { - "name": "type", - "type": "MaybeGetter<\"alphanumeric\" | \"numeric\" | \"text\" | undefined>", - "description": "What characters the input accepts.", - "defaultValue": "'text'", - "optional": true - }, - { - "name": "allowPaste", - "type": "MaybeGetter", - "description": "If `true`, allows pasting values from the clipboard.", - "defaultValue": "true", - "optional": true - } - ], - "methods": [], - "properties": [ - { - "name": "maxLength", - "type": "number", - "description": "" - }, - { - "name": "placeholder", - "type": "string", - "description": "" - }, - { - "name": "disabled", - "type": "boolean", - "description": "" - }, - { - "name": "mask", - "type": "boolean", - "description": "" - }, - { - "name": "type", - "type": "\"alphanumeric\" | \"numeric\" | \"text\"", - "description": "" - }, - { - "name": "allowPaste", - "type": "boolean", - "description": "" - }, - { - "name": "isFilled", - "type": "boolean", - "description": "" - }, - { - "name": "value", - "type": "string", - "description": "" - }, - { - "name": "root", - "type": "{\n readonly \"data-melt-pin-input-root\": \"\"\n readonly id: string\n readonly \"data-complete\": \"\" | undefined\n}", - "description": "The root element's props." - }, - { - "name": "inputs", - "type": "{\n readonly \"data-melt-pin-input-input\": \"\"\n readonly placeholder: string | undefined\n readonly disabled: true | undefined\n readonly type: \"text\" | \"password\"\n readonly \"data-filled\": \"\" | undefined\n readonly tabindex: 0 | -1\n readonly inputmode: \"numeric\" | \"text\"\n readonly style: \"caret-color: transparent;\" | undefined\n readonly onkeydown: (e: KeyboardEvent) => void\n readonly onpointerdown: (e: Event) => void\n readonly onpointerup: (e: Event) => void\n readonly oninput: (e: Event) => void\n readonly onfocus: () => void\n readonly onblur: () => void\n readonly onpaste: (\n e: ClipboardEvent & { currentTarget: EventTarget & HTMLInputElement },\n ) => void\n}[]", - "description": "An array of props that should be spread to the input elements." - } - ], - "propsAlt": "export type PinInputProps = {\n /**\n * The value for the Pin Input.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n *\n * @default ''\n */\n value?: MaybeGetter;\n /**\n * Called when the `PinInput` instance tries to change the value.\n */\n onValueChange?: (value: string) => void;\n\n /**\n * Called when the `PinInput` instance is filled.\n */\n onComplete?: (value: string) => void;\n\n /**\n * Override the default behavior when pasting a value.\n *\n * @param value The pasted value.\n *\n * @example ```ts\n * const pin = new PinInput({\n * onPaste(value) {\n * if (!valid(value)) {\n * // do something\n * return\n * }\n * pin.value = value\n * }\n * });\n */\n onPaste?: (value: string) => void;\n\n /**\n * Called when the PinInput encounters an error.\n */\n onError?: (error: PinInputError) => void;\n\n /**\n * The amount of digits in the Pin Input.\n *\n * @default 4\n */\n maxLength?: MaybeGetter;\n /**\n * An optional placeholder to display when the input is empty.\n *\n * @default '○'\n */\n placeholder?: MaybeGetter;\n\n /**\n * If `true`, prevents the user from interacting with the input.\n *\n * @default false\n */\n disabled?: MaybeGetter;\n\n /**\n * If the input should be masked like a password.\n *\n * @default false\n */\n mask?: MaybeGetter;\n\n /**\n * What characters the input accepts.\n *\n * @default 'text'\n */\n type?: MaybeGetter<\"alphanumeric\" | \"numeric\" | \"text\" | undefined>;\n\n /**\n * If `true`, allows pasting values from the clipboard.\n *\n * @default true\n */\n allowPaste?: MaybeGetter;\n};" - }, - "FileUpload": { - "constructorProps": [ - { - "name": "selected", - "type": "MaybeMultiple | undefined", - "description": "The currently selected files.", - "optional": true - }, - { - "name": "onSelectedChange", - "type": "| ((files: Multiple extends true ? Set : File | undefined) => void)\n | undefined", - "description": "Callback fired when selected files change", - "optional": true - }, - { - "name": "multiple", - "type": "MaybeGetter", - "description": "Whether to accept multiple files", - "defaultValue": "false", - "optional": true - }, - { - "name": "accept", - "type": "MaybeGetter", - "description": "The accepted file types. Can be a MIME type, a MIME group, or a file extension.\nSeparate multiple types with a comma.", - "optional": true - }, - { - "name": "maxSize", - "type": "MaybeGetter", - "description": "Maximum file size in bytes", - "defaultValue": "undefined", - "optional": true - }, - { - "name": "disabled", - "type": "MaybeGetter", - "description": "Whether the file upload is disabled", - "defaultValue": "false", - "optional": true - }, - { - "name": "validate", - "type": "((file: File) => boolean) | undefined", - "description": "Custom validate fn. Will be called together with the original validation,\nwhich takes into account the `accept` and `maxSize` props.", - "optional": true - }, - { - "name": "onError", - "type": "((error: FileUploadError) => void) | undefined", - "description": "Callback fired when a file fails validation", - "optional": true - }, - { - "name": "onAccept", - "type": "((file: File) => void) | undefined", - "description": "Callback fired when a file is accepted", - "optional": true - }, - { - "name": "avoidDuplicates", - "type": "MaybeGetter", - "description": "If true, checks the files contents to avoid duplicate.\nIt's performance is not tested in large files, so by default its set to false.", - "defaultValue": "false", - "optional": true - } - ], - "methods": [ - { - "name": "clear", - "type": "() => void", - "description": "Clears the currently selected files" - }, - { - "name": "remove", - "type": "(file: File) => void", - "description": "Removes a file from the selection" - }, - { - "name": "has", - "type": "(file: File) => Promise", - "description": "" - } - ], - "properties": [ - { - "name": "multiple", - "type": "Multiple", - "description": "" - }, - { - "name": "accept", - "type": "string | undefined", - "description": "" - }, - { - "name": "maxSize", - "type": "number | undefined", - "description": "" - }, - { - "name": "disabled", - "type": "boolean", - "description": "" - }, - { - "name": "avoidDuplicates", - "type": "boolean", - "description": "" - }, - { - "name": "ids", - "type": "{ input: string; dropzone: string }", - "description": "" - }, - { - "name": "isDragging", - "type": "boolean", - "description": "" - }, - { - "name": "selected", - "type": "SelectionStateValue", - "description": "Gets the currently selected files" - }, - { - "name": "dropzone", - "type": "{\n readonly \"data-melt-fileupload-dropzone\": \"\"\n readonly \"data-dragging\": \"\" | undefined\n readonly \"data-disabled\": \"\" | undefined\n readonly ondragenter: (e: DragEvent) => void\n readonly ondragleave: (e: DragEvent) => void\n readonly ondragover: (e: DragEvent) => void\n readonly ondrop: (e: DragEvent) => void\n readonly onclick: () => void\n}", - "description": "The dropzone element, where you can drag files into, or click to open the file picker." - }, - { - "name": "input", - "type": "{\n readonly \"data-melt-fileupload-input\": \"\"\n readonly id: string\n readonly type: \"file\"\n readonly accept: string | undefined\n readonly multiple: Multiple\n readonly style: \"display: none;\"\n readonly disabled: boolean\n readonly onchange: (e: Event) => void\n}", - "description": "The hidden file input element." - }, - { - "name": "trigger", - "type": "{\n readonly \"data-disabled\": \"\" | undefined\n readonly onclick: () => void\n}", - "description": "An optional trigger element, which can be used to open the file picker." - } - ], - "propsAlt": "export type FileUploadProps = {\n /**\n * The currently selected files.\n */\n selected?: MaybeMultiple;\n\n /**\n * Callback fired when selected files change\n */\n onSelectedChange?: (files: Multiple extends true ? Set : File | undefined) => void;\n\n /**\n * Whether to accept multiple files\n * @default false\n */\n multiple?: MaybeGetter;\n\n /**\n * The accepted file types. Can be a MIME type, a MIME group, or a file extension.\n * Separate multiple types with a comma.\n * @example 'image/jpeg'\n * @example 'image/*'\n * @example '.png, .jpg, .jpeg'\n */\n accept?: MaybeGetter;\n\n /**\n * Maximum file size in bytes\n * @default undefined\n */\n maxSize?: MaybeGetter;\n\n /**\n * Whether the file upload is disabled\n * @default false\n */\n disabled?: MaybeGetter;\n\n /**\n * Custom validate fn. Will be called together with the original validation,\n * which takes into account the `accept` and `maxSize` props.\n */\n validate?: (file: File) => boolean;\n\n /**\n * Callback fired when a file fails validation\n */\n onError?: (error: FileUploadError) => void;\n\n /**\n * Callback fired when a file is accepted\n */\n onAccept?: (file: File) => void;\n\n /**\n * If true, checks the files contents to avoid duplicate.\n * It's performance is not tested in large files, so by default its set to false.\n *\n * @default false\n */\n avoidDuplicates?: MaybeGetter;\n};" - }, - "Combobox": { - "constructorProps": [ - { - "name": "open", - "type": "any", - "description": "If the Popover is open.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", - "defaultValue": "false", - "optional": true - }, - { - "name": "focus", - "type": "any", - "optional": true - }, - { - "name": "onOpenChange", - "type": "any", - "description": "Called when the value is supposed to change.", - "optional": true - }, - { - "name": "forceVisible", - "type": "any", - "description": "If the popover visibility should be controlled by the user.", - "defaultValue": "false", - "optional": true - }, - { - "name": "floatingConfig", - "type": "any", - "description": "Config to be passed to `useFloating`", - "optional": true - }, - { - "name": "multiple", - "type": "MaybeGetter", - "description": "If `true`, multiple options can be selected at the same time.", - "defaultValue": "false", - "optional": true - }, - { - "name": "value", - "type": "MaybeMultiple | undefined", - "description": "The value for the Combobox.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", - "defaultValue": "false", - "optional": true - }, - { - "name": "onValueChange", - "type": "OnMultipleChange | undefined", - "description": "Called when the value is supposed to change.", - "optional": true - }, - { - "name": "inputValue", - "type": "MaybeGetter", - "description": "The inputValue for the Combobox.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", - "defaultValue": "false", - "optional": true - }, - { - "name": "onInputValueChange", - "type": "Setter | undefined", - "description": "Called when the value is supposed to change.", - "optional": true - }, - { - "name": "highlighted", - "type": "MaybeGetter", - "description": "The currently highlighted value.", - "optional": true - }, - { - "name": "onHighlightChange", - "type": "((highlighted: T | null) => void) | undefined", - "description": "Called when the highlighted value changes.", - "optional": true - }, - { - "name": "scrollAlignment", - "type": "MaybeGetter<\"nearest\" | \"center\" | null | undefined>", - "description": "Determines behavior when scrolling items into view.\nSet to null to disable auto-scrolling.", - "defaultValue": "\"nearest\"", - "optional": true - }, - { - "name": "sameWidth", - "type": "MaybeGetter", - "description": "If the content should have the same width as the trigger", - "defaultValue": "true", - "optional": true - } - ], - "methods": [ - { - "name": "select", - "type": "(value: T) => void", - "description": "" - }, - { - "name": "scrollIntoView", - "type": "(value?: T | undefined) => void", - "description": "" - }, - { - "name": "getOptionId", - "type": "(value: T) => string", - "description": "" - }, - { - "name": "getOption", - "type": "(\n value: T,\n label?: string | undefined,\n onSelect?: (() => void) | undefined,\n) => {\n readonly id: string\n readonly \"data-melt-combobox-option\": \"\"\n readonly \"data-value\": string\n readonly \"data-label\": string\n readonly \"aria-hidden\": true | undefined\n readonly \"aria-selected\": boolean\n readonly \"data-highlighted\": \"\" | undefined\n readonly tabindex: -1\n readonly role: \"option\"\n readonly onmouseover: () => void\n readonly onclick: () => void\n}", - "description": "Gets the attributes for the option element.\n@param value The value of the option.\n@param label The label to display for the option. If not provided, the value will be stringified.\n@param onSelect An optional callback to call when the option is selected, overriding the default behavior.\n@returns The attributes for the option element." - }, - { - "name": "getOptionsEls", - "type": "() => HTMLElement[]", - "description": "" - }, - { - "name": "getOptions", - "type": "() => T[]", - "description": "" - }, - { - "name": "highlight", - "type": "(value: T) => void", - "description": "" - }, - { - "name": "highlightNext", - "type": "() => void", - "description": "" - }, - { - "name": "highlightPrev", - "type": "() => void", - "description": "" - }, - { - "name": "highlightFirst", - "type": "() => void", - "description": "" - }, - { - "name": "highlightLast", - "type": "() => void", - "description": "" - } - ], - "properties": [ - { - "name": "multiple", - "type": "Multiple", - "description": "" - }, - { - "name": "scrollAlignment", - "type": "\"nearest\" | \"center\" | null", - "description": "" - }, - { - "name": "touched", - "type": "boolean", - "description": "" - }, - { - "name": "onSelectMap", - "type": "Map void>", - "description": "" - }, - { - "name": "ids", - "type": "{\n trigger: string\n content: string\n option: string\n input: string\n} & { popover: string }", - "description": "" - }, - { - "name": "isSelected", - "type": "(value: T) => boolean", - "description": "" - }, - { - "name": "getOptionLabel", - "type": "(value: T) => string", - "description": "" - }, - { - "name": "value", - "type": "SelectionStateValue", - "description": "" - }, - { - "name": "inputValue", - "type": "string", - "description": "" - }, - { - "name": "highlighted", - "type": "T | null", - "description": "" - }, - { - "name": "label", - "type": "{\n for: string\n onclick: (\n e: MouseEvent & { currentTarget: EventTarget & HTMLLabelElement },\n ) => void\n}", - "description": "" - }, - { - "name": "input", - "type": "{\n readonly \"data-melt-combobox-input\": \"\"\n readonly id: string\n readonly role: \"combobox\"\n readonly \"aria-expanded\": boolean\n readonly \"aria-controls\": string\n readonly \"aria-owns\": string\n readonly onclick: () => void\n readonly value: string\n readonly oninput: (e: Event) => void\n readonly onkeydown: (e: KeyboardEvent) => void\n readonly onfocus: (event: FocusEvent) => void\n readonly onfocusout: (event: FocusEvent) => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n readonly popovertarget: string\n}", - "description": "" - }, - { - "name": "trigger", - "type": "{\n onfocus: (event: FocusEvent) => void\n onfocusout: (event: FocusEvent) => Promise\n style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n \"data-melt-combobox-trigger\": string\n id: string\n onclick: () => void\n}", - "description": "" - }, - { - "name": "content", - "type": "{\n readonly onfocus: (event: FocusEvent) => void\n readonly onfocusout: (event: FocusEvent) => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n readonly id: string\n readonly popover: \"manual\"\n readonly ontoggle: (\n e: ToggleEvent & { currentTarget: EventTarget & HTMLElement },\n ) => void\n readonly tabindex: -1\n readonly inert: boolean\n readonly \"data-open\": \"\" | undefined\n} & {\n readonly \"data-melt-combobox-content\": \"\"\n readonly role: \"listbox\"\n readonly \"aria-expanded\": boolean\n readonly \"aria-activedescendant\": string | undefined\n}", - "description": "" - }, - { - "name": "valueAsString", - "type": "string", - "description": "" - } - ], - "propsAlt": "export type ComboboxProps = Omit<\n PopoverProps,\n \"closeOnEscape\" | \"closeOnOutsideClick\" | \"sameWidth\"\n> & {\n /**\n * If `true`, multiple options can be selected at the same time.\n *\n * @default false\n */\n multiple?: MaybeGetter;\n\n /**\n * The value for the Combobox.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n *\n * @default false\n */\n value?: MaybeMultiple;\n /**\n * Called when the value is supposed to change.\n */\n onValueChange?: OnMultipleChange;\n\n /**\n * The inputValue for the Combobox.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n *\n * @default false\n */\n inputValue?: MaybeGetter;\n /**\n * Called when the value is supposed to change.\n */\n onInputValueChange?: Setter;\n\n /**\n * The currently highlighted value.\n */\n highlighted?: MaybeGetter;\n\n /**\n * Called when the highlighted value changes.\n */\n onHighlightChange?: (highlighted: T | null) => void;\n\n /**\n * Determines behavior when scrolling items into view.\n * Set to null to disable auto-scrolling.\n *\n * @default \"nearest\"\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#block\n */\n scrollAlignment?: MaybeGetter<\"nearest\" | \"center\" | null | undefined>;\n\n /**\n * If the content should have the same width as the trigger\n *\n * @default true\n */\n sameWidth?: MaybeGetter;\n};" - }, - "Collapsible": { - "constructorProps": [ - { - "name": "disabled", - "type": "MaybeGetter", - "description": "Whether the collapsible is disabled which prevents it from being opened.", - "optional": true - }, - { - "name": "open", - "type": "MaybeGetter", - "description": "Whether the collapsible is open.", - "optional": true - }, - { - "name": "onOpenChange", - "type": "((value: boolean) => void) | undefined", - "description": "A callback called when the value of `open` changes.", - "optional": true - } - ], - "methods": [], - "properties": [ - { - "name": "disabled", - "type": "boolean", - "description": "" - }, - { - "name": "ids", - "type": "{ trigger: string; content: string }", - "description": "" - }, - { - "name": "open", - "type": "boolean", - "description": "The open state of the collapsible." - }, - { - "name": "trigger", - "type": "{\n readonly disabled: boolean\n readonly onclick: () => void\n readonly \"data-state\": string\n readonly \"data-disabled\": \"\" | undefined\n readonly \"data-melt-collapsible-trigger\": \"\"\n readonly id: string\n readonly \"aria-expanded\": boolean\n readonly \"aria-controls\": string\n}", - "description": "The spread attributes for the trigger button." - }, - { - "name": "content", - "type": "{\n readonly \"data-state\": string\n readonly \"data-disabled\": \"\" | undefined\n readonly \"data-melt-collapsible-content\": \"\"\n readonly id: string\n}", - "description": "The spread attributes for the content element." - } - ], - "propsAlt": "export type CollapsibleProps = {\n /**\n * Whether the collapsible is disabled which prevents it from being opened.\n */\n disabled?: MaybeGetter;\n\n /**\n * Whether the collapsible is open.\n */\n open?: MaybeGetter;\n\n /**\n * A callback called when the value of `open` changes.\n */\n onOpenChange?: (value: boolean) => void;\n};" - }, - "Avatar": { - "constructorProps": [ - { - "name": "src", - "type": "MaybeGetter", - "description": "The source of the image to display.", - "optional": true - }, - { - "name": "delayMs", - "type": "MaybeGetter", - "description": "The amount of time in milliseconds to wait before displaying the image.", - "defaultValue": "0", - "optional": true - }, - { - "name": "onLoadingStatusChange", - "type": "((value: ImageLoadingStatus) => void | undefined) | undefined", - "description": "A callback invoked when the loading status store of the avatar changes.", - "optional": true - } - ], - "methods": [], - "properties": [ - { - "name": "src", - "type": "string", - "description": "" - }, - { - "name": "delayMs", - "type": "number", - "description": "" - }, - { - "name": "loadingStatus", - "type": "ImageLoadingStatus", - "description": "" - }, - { - "name": "image", - "type": "{\n readonly \"data-melt-avatar-image\": \"\"\n readonly src: string\n readonly style: `display: ${string}`\n readonly onload: () => (() => void) | undefined\n readonly onerror: () => void\n}", - "description": "" - }, - { - "name": "fallback", - "type": "{\n readonly \"data-melt-avatar-fallback\": \"\"\n readonly style: `display: ${string}` | undefined\n readonly hidden: true | undefined\n}", - "description": "" - } - ], - "propsAlt": "export type AvatarProps = {\n /**\n * The source of the image to display.\n */\n src?: MaybeGetter;\n\n /**\n * The amount of time in milliseconds to wait before displaying the image.\n *\n * @default 0\n */\n delayMs?: MaybeGetter;\n\n /**\n * A callback invoked when the loading status store of the avatar changes.\n */\n onLoadingStatusChange?: (value: ImageLoadingStatus) => void | undefined;\n};" - }, - "Accordion": { - "constructorProps": [ - { - "name": "multiple", - "type": "MaybeGetter", - "description": "If `true`, multiple accordion items can be open at the same time.", - "defaultValue": "false", - "optional": true - }, - { - "name": "disabled", - "type": "MaybeGetter", - "description": "When `true`, prevents the user from interacting with the accordion.", - "defaultValue": "false", - "optional": true - }, - { - "name": "value", - "type": "MaybeMultiple | undefined", - "description": "The controlled value for the accordion.", - "optional": true - }, - { - "name": "onValueChange", - "type": "OnMultipleChange | undefined", - "description": "The callback invoked when the value of the Accordion changes.", - "optional": true - } - ], - "methods": [ - { - "name": "getItem", - "type": ">(\n item: AccordionItemMeta,\n) => AccordionItem", - "description": "Returns an Item class with the necessary\nspread attributes for an accordion item.\n@param item" - }, - { - "name": "isExpanded", - "type": "(id: string) => boolean", - "description": "Checks if an item is currently expanded.\n@param id - ID of the item to check." - }, - { - "name": "expand", - "type": "(id: string) => void", - "description": "Expands a specific item.\n@param id - ID of the item to expand." - }, - { - "name": "collapse", - "type": "(id: string) => void", - "description": "Collapses a specific item.\n@param id - ID of the item to collapse." - }, - { - "name": "toggleExpanded", - "type": "(id: string) => void", - "description": "Toggles the expanded state of an item.\n@param id - ID of the item to toggle." - } - ], - "properties": [ - { - "name": "multiple", - "type": "Multiple", - "description": "" - }, - { - "name": "disabled", - "type": "boolean", - "description": "" - }, - { - "name": "ids", - "type": "{\n root: string\n item: string\n trigger: string\n content: string\n heading: string\n}", - "description": "" - }, - { - "name": "value", - "type": "FalseIfUndefined>", - "description": "" - }, - { - "name": "root", - "type": "{ \"data-melt-accordion-root\": string; id: string }", - "description": "Spread attributes for the accordion root element." - } - ], - "propsAlt": "export type AccordionProps = {\n /**\n * If `true`, multiple accordion items can be open at the same time.\n *\n * @default false\n */\n multiple?: MaybeGetter;\n\n /**\n * When `true`, prevents the user from interacting with the accordion.\n *\n * @default false\n */\n disabled?: MaybeGetter;\n\n /**\n * The controlled value for the accordion.\n */\n value?: AccordionValue;\n\n /**\n * The callback invoked when the value of the Accordion changes.\n */\n onValueChange?: OnMultipleChange;\n};" - } -} \ No newline at end of file + "Video": { + "constructorProps": [ + { + "name": "src", + "type": "MaybeGetter", + "description": "The source URL of the video.", + "optional": true + }, + { + "name": "poster", + "type": "MaybeGetter", + "description": "The poster image URL to display before the video loads.", + "optional": true + }, + { + "name": "currentTime", + "type": "MaybeGetter", + "description": "The current time of the video in seconds.", + "defaultValue": "0", + "optional": true + }, + { + "name": "volume", + "type": "MaybeGetter", + "description": "The volume level of the video (0-1).", + "defaultValue": "1", + "optional": true + }, + { + "name": "playbackRate", + "type": "MaybeGetter", + "description": "The playback rate of the video.", + "defaultValue": "1", + "optional": true + }, + { + "name": "muted", + "type": "MaybeGetter", + "description": "Whether the video should be muted.", + "defaultValue": "false", + "optional": true + }, + { + "name": "loop", + "type": "MaybeGetter", + "description": "Whether the video should loop.", + "defaultValue": "false", + "optional": true + }, + { + "name": "autoplay", + "type": "MaybeGetter", + "description": "Whether the video should autoplay.", + "defaultValue": "false", + "optional": true + }, + { + "name": "preload", + "type": "MaybeGetter<\"none\" | \"metadata\" | \"auto\" | undefined>", + "description": "How the video should be preloaded.", + "defaultValue": "\"metadata\"", + "optional": true + }, + { + "name": "keyboardControls", + "type": "MaybeGetter", + "description": "Whether to enable keyboard controls.", + "defaultValue": "true", + "optional": true + }, + { + "name": "volumeStep", + "type": "MaybeGetter", + "description": "Volume step for keyboard controls (up/down arrows).", + "defaultValue": "0.05", + "optional": true + }, + { + "name": "seekStep", + "type": "MaybeGetter", + "description": "Seek step in seconds for keyboard controls (left/right arrows, j/l keys).", + "defaultValue": "10", + "optional": true + }, + { + "name": "onPlayingChange", + "type": "((playing: boolean) => void) | undefined", + "description": "Callback fired when the playing state changes.", + "optional": true + }, + { + "name": "onCurrentTimeChange", + "type": "((currentTime: number) => void) | undefined", + "description": "Callback fired when the current time changes.", + "optional": true + }, + { + "name": "onVolumeChange", + "type": "((volume: number) => void) | undefined", + "description": "Callback fired when the volume changes.", + "optional": true + }, + { + "name": "onMutedChange", + "type": "((muted: boolean) => void) | undefined", + "description": "Callback fired when the muted state changes.", + "optional": true + }, + { + "name": "onPlaybackRateChange", + "type": "((playbackRate: number) => void) | undefined", + "description": "Callback fired when the playback rate changes.", + "optional": true + }, + { + "name": "onEnded", + "type": "(() => void) | undefined", + "description": "Callback fired when the video ends.", + "optional": true + }, + { + "name": "onCanPlay", + "type": "(() => void) | undefined", + "description": "Callback fired when the video is ready to play.", + "optional": true + }, + { + "name": "onLoadedMetadata", + "type": "(() => void) | undefined", + "description": "Callback fired when video metadata is loaded.", + "optional": true + }, + { + "name": "onError", + "type": "((error: Event) => void) | undefined", + "description": "Callback fired when an error occurs.", + "optional": true + } + ], + "methods": [ + { + "name": "play", + "type": "() => void", + "description": "Starts playing the video." + }, + { + "name": "pause", + "type": "() => void", + "description": "Pauses the video." + }, + { + "name": "togglePlay", + "type": "() => void", + "description": "Toggles between play and pause." + }, + { + "name": "seek", + "type": "(time: number) => void", + "description": "Seeks to a specific time in seconds." + }, + { + "name": "seekBy", + "type": "(seconds: number) => void", + "description": "Seeks forward or backward by the specified number of seconds." + }, + { + "name": "setVolume", + "type": "(volume: number) => void", + "description": "Sets the volume level (0-1)." + }, + { + "name": "toggleMute", + "type": "(showFeedback?: boolean) => void", + "description": "Toggles the mute state.\n@param showFeedback - Whether to show keyboard feedback" + }, + { + "name": "setPlaybackRate", + "type": "(rate: number) => void", + "description": "Sets the playback rate (1.0 = normal speed)." + }, + { + "name": "enterFullscreen", + "type": "() => void", + "description": "Enters fullscreen mode." + }, + { + "name": "exitFullscreen", + "type": "() => void", + "description": "Exits fullscreen mode." + }, + { + "name": "toggleFullscreen", + "type": "() => void", + "description": "Toggles fullscreen mode." + }, + { + "name": "refreshDuration", + "type": "() => void", + "description": "Refreshes the video duration from the video element." + }, + { + "name": "formatTime", + "type": "(seconds: number) => string", + "description": "Formats time in seconds to MM:SS format." + } + ], + "properties": [ + { + "name": "src", + "type": "string", + "description": "" + }, + { + "name": "poster", + "type": "string", + "description": "" + }, + { + "name": "loop", + "type": "boolean", + "description": "" + }, + { + "name": "autoplay", + "type": "boolean", + "description": "" + }, + { + "name": "preload", + "type": "\"none\" | \"metadata\" | \"auto\"", + "description": "" + }, + { + "name": "playbackRate", + "type": "number", + "description": "" + }, + { + "name": "keyboardControls", + "type": "boolean", + "description": "" + }, + { + "name": "volumeStep", + "type": "number", + "description": "" + }, + { + "name": "seekStep", + "type": "number", + "description": "" + }, + { + "name": "ids", + "type": "{\n root: string\n video: string\n controls: string\n playButton: string\n muteButton: string\n volumeSlider: string\n progressBar: string\n timeDisplay: string\n fullscreenButton: string\n}", + "description": "" + }, + { + "name": "currentTime", + "type": "number", + "description": "The current playback time in seconds." + }, + { + "name": "volume", + "type": "number", + "description": "The current volume level (0-1)." + }, + { + "name": "muted", + "type": "boolean", + "description": "Whether the video is currently muted." + }, + { + "name": "playing", + "type": "boolean", + "description": "Whether the video is currently playing." + }, + { + "name": "duration", + "type": "number", + "description": "The total duration of the video in seconds." + }, + { + "name": "buffered", + "type": "number", + "description": "The amount of video buffered as a percentage (0-1)." + }, + { + "name": "loading", + "type": "boolean", + "description": "Whether the video is currently loading." + }, + { + "name": "error", + "type": "string | null", + "description": "The current error message, if any." + }, + { + "name": "fullscreen", + "type": "boolean", + "description": "Whether the video is currently in fullscreen mode." + }, + { + "name": "seeking", + "type": "boolean", + "description": "Whether the video is currently seeking." + }, + { + "name": "keyboardFeedback", + "type": "string | null", + "description": "The current keyboard feedback message being displayed." + }, + { + "name": "progress", + "type": "number", + "description": "" + }, + { + "name": "bufferedProgress", + "type": "number", + "description": "" + }, + { + "name": "root", + "type": "{\n readonly \"data-melt-video-player-root\": \"\"\n readonly id: string\n readonly tabindex: 0 | -1\n readonly \"data-playing\": \"\" | undefined\n readonly \"data-muted\": \"\" | undefined\n readonly \"data-fullscreen\": \"\" | undefined\n readonly \"data-loading\": \"\" | undefined\n readonly \"data-seeking\": \"\" | undefined\n readonly \"data-error\": \"\" | undefined\n readonly role: \"application\"\n readonly \"aria-label\": \"Video player\"\n readonly onclick: (_e: MouseEvent) => void\n readonly onkeydown:\n | ((\n e: KeyboardEvent & { currentTarget: EventTarget & HTMLDivElement },\n ) => void)\n | undefined\n}", + "description": "The spread attributes for the root video player container." + }, + { + "name": "video", + "type": "{\n readonly \"data-melt-video-player-video\": \"\"\n readonly id: string\n readonly src: string\n readonly poster: string\n readonly loop: boolean\n readonly autoplay: boolean\n readonly muted: boolean\n readonly preload: \"none\" | \"metadata\" | \"auto\"\n readonly controls: false\n readonly disablepictureinpicture: true\n readonly onkeydown: (\n e: KeyboardEvent & { currentTarget: EventTarget & HTMLVideoElement },\n ) => void\n readonly onclick: (\n e: MouseEvent & { currentTarget: EventTarget & HTMLVideoElement },\n ) => void\n readonly ondblclick: (\n e: MouseEvent & { currentTarget: EventTarget & HTMLVideoElement },\n ) => void\n readonly onloadedmetadata: (\n e: Event & { currentTarget: EventTarget & HTMLVideoElement },\n ) => void\n readonly ontimeupdate: (\n e: Event & { currentTarget: EventTarget & HTMLVideoElement },\n ) => void\n readonly onplay: () => void\n readonly onpause: () => void\n readonly onended: () => void\n readonly ondurationchange: (\n e: Event & { currentTarget: EventTarget & HTMLVideoElement },\n ) => void\n readonly oncanplay: () => void\n readonly oncanplaythrough: (\n e: Event & { currentTarget: EventTarget & HTMLVideoElement },\n ) => void\n readonly onwaiting: () => void\n readonly onerror: (\n e: Event & { currentTarget: EventTarget & Element },\n ) => void\n readonly onratechange: (\n e: Event & { currentTarget: EventTarget & HTMLVideoElement },\n ) => void\n readonly onseeking: () => void\n readonly onseeked: () => void\n}", + "description": "The spread attributes for the video element." + }, + { + "name": "controls", + "type": "{\n readonly \"data-melt-video-player-controls\": \"\"\n readonly role: \"group\"\n readonly \"aria-label\": \"Video controls\"\n}", + "description": "The spread attributes for the controls container." + }, + { + "name": "playButton", + "type": "{\n readonly \"data-melt-video-player-playButton\": \"\"\n readonly type: \"button\"\n readonly \"aria-label\": \"Pause\" | \"Play\"\n readonly \"data-state\": \"playing\" | \"paused\"\n readonly onclick: () => void\n}", + "description": "The spread attributes for the play/pause button." + }, + { + "name": "muteButton", + "type": "{\n readonly \"data-melt-video-player-muteButton\": \"\"\n readonly type: \"button\"\n readonly \"aria-label\": \"Unmute\" | \"Mute\"\n readonly \"data-state\": \"muted\" | \"unmuted\"\n readonly onclick: () => void\n}", + "description": "The spread attributes for the mute/unmute button." + }, + { + "name": "volumeSlider", + "type": "{\n readonly \"data-melt-video-player-volumeSlider\": \"\"\n readonly type: \"range\"\n readonly min: \"0\"\n readonly max: \"1\"\n readonly step: \"0.01\"\n readonly value: number\n readonly \"aria-label\": \"Volume\"\n readonly \"aria-valuemin\": 0\n readonly \"aria-valuemax\": 1\n readonly \"aria-valuenow\": number\n readonly oninput: (\n e: Event & { currentTarget: EventTarget & HTMLInputElement },\n ) => void\n}", + "description": "The spread attributes for the volume slider." + }, + { + "name": "progressBar", + "type": "{\n readonly \"data-melt-video-player-progressBar\": \"\"\n readonly type: \"range\"\n readonly min: \"0\"\n readonly max: string\n readonly step: \"0.1\"\n readonly value: number\n readonly \"aria-label\": \"Seek\"\n readonly \"aria-valuemin\": 0\n readonly \"aria-valuemax\": number\n readonly \"aria-valuenow\": number\n readonly \"aria-valuetext\": `${string} of ${string}`\n readonly style: `--progress: ${string}; --buffered: ${string}`\n readonly oninput: (\n e: Event & { currentTarget: EventTarget & HTMLInputElement },\n ) => void\n readonly onmousedown: () => void\n readonly onmouseup: () => void\n readonly onkeydown: (\n e: KeyboardEvent & { currentTarget: EventTarget & HTMLInputElement },\n ) => void\n}", + "description": "The spread attributes for the progress bar/scrubber." + }, + { + "name": "timeDisplay", + "type": "{\n readonly \"data-melt-video-player-timeDisplay\": \"\"\n readonly \"aria-live\": \"polite\"\n readonly \"aria-label\": `Current time: ${string}`\n}", + "description": "The spread attributes for the time display." + }, + { + "name": "fullscreenButton", + "type": "{\n readonly \"data-melt-video-player-fullscreenButton\": \"\"\n readonly type: \"button\"\n readonly \"aria-label\": \"Exit fullscreen\" | \"Enter fullscreen\"\n readonly \"data-state\": \"fullscreen\" | \"windowed\"\n readonly onclick: () => void\n}", + "description": "The spread attributes for the fullscreen button." + } + ], + "propsAlt": "export type VideoProps = {\n /**\n * The source URL of the video.\n */\n src?: MaybeGetter;\n\n /**\n * The poster image URL to display before the video loads.\n */\n poster?: MaybeGetter;\n\n /**\n * The current time of the video in seconds.\n *\n * @default 0\n */\n currentTime?: MaybeGetter;\n\n /**\n * The volume level of the video (0-1).\n *\n * @default 1\n */\n volume?: MaybeGetter;\n\n /**\n * The playback rate of the video.\n *\n * @default 1\n */\n playbackRate?: MaybeGetter;\n\n /**\n * Whether the video should be muted.\n *\n * @default false\n */\n muted?: MaybeGetter;\n\n /**\n * Whether the video should loop.\n *\n * @default false\n */\n loop?: MaybeGetter;\n\n /**\n * Whether the video should autoplay.\n *\n * @default false\n */\n autoplay?: MaybeGetter;\n\n /**\n * How the video should be preloaded.\n *\n * @default \"metadata\"\n */\n preload?: MaybeGetter<\"none\" | \"metadata\" | \"auto\" | undefined>;\n\n /**\n * Whether to enable keyboard controls.\n *\n * @default true\n */\n keyboardControls?: MaybeGetter;\n\n /**\n * Volume step for keyboard controls (up/down arrows).\n *\n * @default 0.05\n */\n volumeStep?: MaybeGetter;\n\n /**\n * Seek step in seconds for keyboard controls (left/right arrows, j/l keys).\n *\n * @default 10\n */\n seekStep?: MaybeGetter;\n\n /**\n * Callback fired when the playing state changes.\n */\n onPlayingChange?: (playing: boolean) => void;\n\n /**\n * Callback fired when the current time changes.\n */\n onCurrentTimeChange?: (currentTime: number) => void;\n\n /**\n * Callback fired when the volume changes.\n */\n onVolumeChange?: (volume: number) => void;\n\n /**\n * Callback fired when the muted state changes.\n */\n onMutedChange?: (muted: boolean) => void;\n\n /**\n * Callback fired when the playback rate changes.\n */\n onPlaybackRateChange?: (playbackRate: number) => void;\n\n /**\n * Callback fired when the video ends.\n */\n onEnded?: () => void;\n\n /**\n * Callback fired when the video is ready to play.\n */\n onCanPlay?: () => void;\n\n /**\n * Callback fired when video metadata is loaded.\n */\n onLoadedMetadata?: () => void;\n\n /**\n * Callback fired when an error occurs.\n */\n onError?: (error: Event) => void;\n};" + }, + "Tree": { + "constructorProps": [ + { + "name": "multiple", + "type": "MaybeGetter", + "description": "If `true`, the user can select multiple items.", + "defaultValue": "false", + "optional": true + }, + { + "name": "selected", + "type": "MaybeMultiple | undefined", + "description": "The currently selected item(s).\nIf `multiple` is `true`, this should be an `Iterable`.\nOtherwise, it'll be a `string`.", + "defaultValue": "undefined", + "optional": true + }, + { + "name": "onSelectedChange", + "type": "| ((value: Multiple extends true ? Set : string | undefined) => void)\n | undefined", + "description": "Callback fired when selection changes", + "optional": true + }, + { + "name": "expanded", + "type": "IterableProp", + "description": "The currently expanded items", + "defaultValue": "undefined", + "optional": true + }, + { + "name": "onExpandedChange", + "type": "((value: Set) => void) | undefined", + "description": "Callback fired when expanded state changes", + "optional": true + }, + { + "name": "expandOnClick", + "type": "MaybeGetter", + "description": "If `true`, groups (items with children) expand on click.", + "defaultValue": "true", + "optional": true + }, + { + "name": "items", + "type": "IterableProp", + "description": "The items contained in the tree.", + "optional": false + }, + { + "name": "typeaheadTimeout", + "type": "MaybeGetter", + "description": "How many time (in ms) the typeahead string is held before it is cleared", + "defaultValue": "500", + "optional": true + } + ], + "methods": [ + { + "name": "isSelected", + "type": "(id: string) => boolean", + "description": "Checks if an item is currently selected\n@param id - ID of the item to check" + }, + { + "name": "isExpanded", + "type": "(id: string) => boolean", + "description": "Checks if an item is currently expanded\n@param id - ID of the item to check" + }, + { + "name": "expand", + "type": "(id: string) => void", + "description": "Expands a specific item\n@param id - ID of the item to expand" + }, + { + "name": "collapse", + "type": "(id: string) => void", + "description": "Collapses a specific item\n@param id - ID of the item to collapse" + }, + { + "name": "toggleExpand", + "type": "(id: string) => void", + "description": "Toggles the expanded state of an item\n@param id - ID of the item to toggle" + }, + { + "name": "select", + "type": "(id: string) => void", + "description": "Selects a specific item\n@param id - ID of the item to select" + }, + { + "name": "deselect", + "type": "(id: string) => void", + "description": "Deselects a specific item\n@param id - ID of the item to deselect" + }, + { + "name": "clearSelection", + "type": "() => void", + "description": "Clears all current selections" + }, + { + "name": "toggleSelect", + "type": "(id: string) => void", + "description": "Toggles the selected state of an item\n@param id - ID of the item to toggle" + }, + { + "name": "selectAll", + "type": "() => void", + "description": "Selects all visible items.\nIf all items are already selected, clears the selection." + }, + { + "name": "getItemId", + "type": "(id: string) => string", + "description": "Gets the DOM ID for a specific tree item\n@param id - ID of the item" + }, + { + "name": "getItemEl", + "type": "(id: string) => HTMLElement | null", + "description": "Gets the DOM element for a specific tree item\n@param id - ID of the item" + }, + { + "name": "selectUntil", + "type": "(id: string) => void", + "description": "Selects all items between the last selected item and the specified item\n@param id - ID of the item to select until" + } + ], + "properties": [ + { + "name": "collection", + "type": "Collection", + "description": "The items contained in the tree" + }, + { + "name": "multiple", + "type": "Multiple", + "description": "If `true`, the user can select multiple items holding `Control`/`Meta` or `Shift`" + }, + { + "name": "expandOnClick", + "type": "boolean", + "description": "If `true`, groups (items with children) expand on click" + }, + { + "name": "typeaheadTimeout", + "type": "number", + "description": "" + }, + { + "name": "typeahead", + "type": "(\n letter: string,\n) =>\n | {\n readonly child: Child\n readonly value: string\n readonly typeahead: string\n readonly current: boolean\n }\n | undefined", + "description": "" + }, + { + "name": "items", + "type": "I[]", + "description": "" + }, + { + "name": "selected", + "type": "FalseIfUndefined>", + "description": "Currently selected item(s)\nFor multiple selection, returns a Set of IDs\nFor single selection, returns a single ID or undefined" + }, + { + "name": "expanded", + "type": "SvelteSet", + "description": "Set of currently expanded item IDs" + }, + { + "name": "root", + "type": "{ role: string; \"data-melt-tree-root\": string }", + "description": "Gets ARIA attributes for the root tree element" + }, + { + "name": "group", + "type": "{ role: string; \"data-melt-tree-group\": string }", + "description": "ARIA attributes for group elements" + }, + { + "name": "children", + "type": "Child[]", + "description": "Array of Child instances representing the top-level items" + } + ], + "propsAlt": "\n\nexport type TreeProps = {\n /**\n * If `true`, the user can select multiple items.\n * @default false\n */\n multiple?: MaybeGetter;\n /**\n * The currently selected item(s).\n * If `multiple` is `true`, this should be an `Iterable`.\n * Otherwise, it'll be a `string`.\n * @default undefined\n */\n selected?: MaybeMultiple;\n /**\n * Callback fired when selection changes\n * @param value - For multiple selection, a Set of selected IDs. For single selection, a single ID or undefined\n */\n onSelectedChange?: (value: Multiple extends true ? Set : string | undefined) => void;\n /**\n * The currently expanded items\n *\n * @default undefined\n */\n expanded?: MaybeMultiple;\n /**\n * Callback fired when expanded state changes\n * @param value - Set of expanded item IDs\n */\n onExpandedChange?: (value: Set) => void;\n /**\n * If `true`, groups (items with children) expand on click.\n * @default true\n */\n expandOnClick?: MaybeGetter;\n /**\n * The items contained in the tree.\n * @required\n */\n items: IterableProp;\n /**\n * How many time (in ms) the typeahead string is held before it is cleared\n * @default 500\n */\n typeaheadTimeout?: MaybeGetter;\n};" + }, + "Tooltip": { + "constructorProps": [ + { + "name": "open", + "type": "MaybeGetter", + "description": "If the Tooltip is open.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", + "defaultValue": "false", + "optional": true + }, + { + "name": "onOpenChange", + "type": "((value: boolean) => void) | undefined", + "description": "Called when the value is supposed to change.", + "optional": true + }, + { + "name": "closeOnPointerDown", + "type": "MaybeGetter", + "description": "If `true`, tooltip will close if trigger is pressed.", + "defaultValue": "true", + "optional": true + }, + { + "name": "openDelay", + "type": "MaybeGetter", + "description": "Tooltip open delay in milliseconds.", + "defaultValue": "1000", + "optional": true + }, + { + "name": "closeDelay", + "type": "MaybeGetter", + "description": "Tooltip close delay in milliseconds.", + "defaultValue": "0", + "optional": true + }, + { + "name": "floatingConfig", + "type": "UseFloatingConfig | undefined>", + "description": "Config to be passed to `useFloating`", + "optional": true + }, + { + "name": "forceVisible", + "type": "MaybeGetter", + "description": "If the popover visibility should be controlled by the user.", + "defaultValue": "false", + "optional": true + }, + { + "name": "disableHoverableContent", + "type": "MaybeGetter", + "description": "If `true`, leaving trigger will close the tooltip.", + "defaultValue": "false", + "optional": true + } + ], + "methods": [], + "properties": [ + { + "name": "ids", + "type": "{ trigger: string; content: string; arrow: string }", + "description": "" + }, + { + "name": "invokerRect", + "type": "{ x: number; y: number; width: number; height: number } | undefined", + "description": "" + }, + { + "name": "closeOnPointerDown", + "type": "boolean", + "description": "" + }, + { + "name": "openDelay", + "type": "number", + "description": "" + }, + { + "name": "closeDelay", + "type": "number", + "description": "" + }, + { + "name": "disableHoverableContent", + "type": "boolean", + "description": "" + }, + { + "name": "forceVisible", + "type": "boolean", + "description": "" + }, + { + "name": "floatingConfig", + "type": "UseFloatingConfig", + "description": "" + }, + { + "name": "isVisible", + "type": "boolean", + "description": "State" + }, + { + "name": "graceAreaPolygon", + "type": "{ x: number; y: number }[]", + "description": "" + }, + { + "name": "open", + "type": "boolean", + "description": "" + }, + { + "name": "trigger", + "type": "{\n readonly onfocusout: () => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}`\n readonly \"data-melt-tooltip-trigger\": \"\"\n readonly id: string\n readonly \"aria-describedby\": string\n readonly \"data-open\": \"\" | undefined\n readonly onpointerdown: () => void\n readonly onpointerenter: (\n e: PointerEvent & { currentTarget: EventTarget & HTMLElement },\n ) => void\n readonly onpointermove: () => void\n readonly onpointerleave: (\n e: PointerEvent & { currentTarget: EventTarget & HTMLElement },\n ) => void\n readonly onfocus: () => void\n readonly onblur: () => void\n}", + "description": "" + }, + { + "name": "content", + "type": "{\n readonly style: string\n readonly onfocusout: () => Promise\n readonly \"data-melt-tooltip-content\": \"\"\n readonly id: string\n readonly popover: \"manual\"\n readonly role: \"tooltip\"\n readonly tabindex: -1\n readonly inert: boolean\n readonly \"data-open\": \"\" | undefined\n readonly onpointerenter: () => void\n readonly onpointerleave: () => void\n readonly onpointerdown: () => void\n}", + "description": "" + }, + { + "name": "arrow", + "type": "{\n readonly \"data-melt-tooltip-arrow\": \"\"\n readonly id: string\n readonly \"data-arrow\": \"\"\n readonly \"aria-hidden\": true\n readonly \"data-open\": \"\" | undefined\n}", + "description": "" + } + ], + "propsAlt": "export type TooltipProps = {\n /**\n * If the Tooltip is open.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n * @default false\n */\n open?: MaybeGetter;\n\n /**\n * Called when the value is supposed to change.\n */\n onOpenChange?: (value: boolean) => void;\n\n /**\n * If `true`, tooltip will close if trigger is pressed.\n *\n * @default true\n */\n closeOnPointerDown?: MaybeGetter;\n\n /**\n * Tooltip open delay in milliseconds.\n *\n * @default 1000\n */\n openDelay?: MaybeGetter;\n\n /**\n * Tooltip close delay in milliseconds.\n *\n * @default 0\n */\n closeDelay?: MaybeGetter;\n\n /**\n * Config to be passed to `useFloating`\n */\n floatingConfig?: UseFloatingArgs[\"config\"];\n\n /**\n * If the popover visibility should be controlled by the user.\n *\n * @default false\n */\n forceVisible?: MaybeGetter;\n\n /**\n * If `true`, leaving trigger will close the tooltip.\n *\n * @default false\n */\n disableHoverableContent?: MaybeGetter;\n};" + }, + "Toggle": { + "constructorProps": [ + { + "name": "value", + "type": "MaybeGetter | undefined", + "description": "The value for the Toggle.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", + "defaultValue": "false", + "optional": true + }, + { + "name": "onValueChange", + "type": "((value: boolean) => void) | undefined", + "description": "Called when the value is supposed to change.", + "optional": true + }, + { + "name": "disabled", + "type": "MaybeGetter", + "description": "If `true`, prevents the user from interacting with the input.", + "defaultValue": "false", + "optional": true + } + ], + "methods": [], + "properties": [ + { + "name": "disabled", + "type": "boolean", + "description": "" + }, + { + "name": "value", + "type": "boolean", + "description": "" + }, + { + "name": "trigger", + "type": "{\n readonly \"data-melt-toggle-trigger\": \"\"\n readonly \"data-checked\": \"\" | undefined\n readonly \"aria-pressed\": boolean\n readonly disabled: true | undefined\n readonly onclick: () => void\n}", + "description": "The trigger that toggles the value." + }, + { + "name": "hiddenInput", + "type": "{\n readonly \"data-melt-toggle-hidden-input\": \"\"\n readonly type: \"hidden\"\n readonly value: \"on\" | \"off\"\n}", + "description": "A hidden input field to use within forms." + } + ], + "propsAlt": "export type ToggleProps = {\n /**\n * The value for the Toggle.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n *\n * @default false\n */\n value?: MaybeGetter;\n /**\n * Called when the value is supposed to change.\n */\n onValueChange?: (value: boolean) => void;\n\n /**\n * If `true`, prevents the user from interacting with the input.\n *\n * @default false\n */\n disabled?: MaybeGetter;\n};" + }, + "Toaster": { + "constructorProps": [ + { + "name": "closeDelay", + "type": "MaybeGetter", + "description": "The delay in milliseconds before the toast closes. Set to 0 to disable.", + "defaultValue": "5000", + "optional": true + }, + { + "name": "type", + "type": "MaybeGetter<\"polite\" | \"assertive\" | undefined>", + "description": "The sensitivity of the toast for accessibility purposes.\nhttps://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-live", + "defaultValue": "'polite'", + "optional": true + }, + { + "name": "hover", + "type": "MaybeGetter<\"pause\" | \"pause-all\" | null | undefined>", + "description": "The behaviour when a toast is hovered.\nPass in `null` to disable.", + "defaultValue": "'pause'", + "optional": true + } + ], + "methods": [], + "properties": [ + { + "name": "ids", + "type": "{ root: string }", + "description": "" + }, + { + "name": "closeDelay", + "type": "number", + "description": "" + }, + { + "name": "type", + "type": "\"polite\" | \"assertive\"", + "description": "" + }, + { + "name": "hover", + "type": "\"pause\" | \"pause-all\" | null", + "description": "" + }, + { + "name": "toasts", + "type": "Toast[]", + "description": "The active toasts." + }, + { + "name": "addToast", + "type": "(props: AddToastArgs) => Toast", + "description": "Adds a toast." + }, + { + "name": "removeToast", + "type": "(id: string) => void", + "description": "Removes the toast with the specified ID.\n@param id The id of the toast." + }, + { + "name": "updateToast", + "type": "(args: UpdateToastArgs) => void", + "description": "Updates a toast's data.\n@param id The id of the toast.\n@param data The updated data." + }, + { + "name": "root", + "type": "{\n readonly \"data-melt-toaster-root\": \"\"\n readonly id: string\n readonly popover: \"manual\"\n}", + "description": "Spread attributes for the container of the toasts." + } + ], + "propsAlt": "export type ToasterProps = {\n /**\n * The delay in milliseconds before the toast closes. Set to 0 to disable.\n * @default 5000\n */\n closeDelay?: MaybeGetter;\n\n /**\n * The sensitivity of the toast for accessibility purposes.\n * https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-live\n * @default 'polite'\n */\n type?: MaybeGetter<\"assertive\" | \"polite\" | undefined>;\n\n /**\n * The behaviour when a toast is hovered.\n * Pass in `null` to disable.\n *\n * @default 'pause'\n */\n hover?: MaybeGetter<\"pause\" | \"pause-all\" | null | undefined>;\n};" + }, + "Tabs": { + "constructorProps": [ + { + "name": "selectWhenFocused", + "type": "MaybeGetter", + "description": "If `true`, the value will be changed whenever a trigger is focused.", + "defaultValue": "true", + "optional": true + }, + { + "name": "loop", + "type": "MaybeGetter", + "description": "If the the trigger selection should loop when navigating with the arrow keys.", + "defaultValue": "true", + "optional": true + }, + { + "name": "orientation", + "type": "MaybeGetter<\"horizontal\" | \"vertical\" | undefined>", + "description": "The orientation of the tabs.", + "defaultValue": "\"horizontal\"", + "optional": true + }, + { + "name": "value", + "type": "MaybeGetter", + "description": "The default value for `tabs.value`\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that `tabs.value` only changes when the getter returns a new value.", + "optional": false + }, + { + "name": "onValueChange", + "type": "((active: T) => void) | undefined", + "description": "Called when the `Tabs` instance tries to change the active tab.", + "optional": true + } + ], + "methods": [ + { + "name": "getTrigger", + "type": "(value: T) => {\n readonly \"data-melt-tabs-trigger\": T\n readonly \"data-active\": \"\" | undefined\n readonly tabindex: 0 | -1\n readonly role: \"tab\"\n readonly \"aria-selected\": boolean\n readonly \"aria-controls\": string\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n readonly onclick: () => T\n readonly onkeydown: (e: KeyboardEvent) => void\n readonly id: string\n}", + "description": "Gets the attributes and listeners for a tab trigger. Requires an identifying tab value." + }, + { + "name": "getContent", + "type": "(value: T) => {\n readonly \"data-melt-tabs-content\": \"\"\n readonly hidden: boolean\n readonly \"data-active\": \"\" | undefined\n readonly role: \"tabpanel\"\n readonly id: string\n readonly \"aria-labelledby\": string\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n}", + "description": "Gets the attributes and listeners for the tabs contents. Requires an identifying tab value." + } + ], + "properties": [ + { + "name": "selectWhenFocused", + "type": "boolean", + "description": "" + }, + { + "name": "loop", + "type": "boolean", + "description": "" + }, + { + "name": "orientation", + "type": "\"horizontal\" | \"vertical\"", + "description": "" + }, + { + "name": "value", + "type": "T", + "description": "The current selected tab." + }, + { + "name": "triggerList", + "type": "{\n readonly \"data-melt-tabs-trigger-list\": \"\"\n readonly role: \"tablist\"\n readonly \"aria-orientation\": \"horizontal\" | \"vertical\"\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n}", + "description": "The attributes for the list that contains the tab triggers." + } + ], + "propsAlt": "export type TabsProps = {\n /**\n * If `true`, the value will be changed whenever a trigger is focused.\n *\n * @default true\n */\n selectWhenFocused?: MaybeGetter;\n /**\n * If the the trigger selection should loop when navigating with the arrow keys.\n *\n * @default true\n */\n loop?: MaybeGetter;\n /**\n * The orientation of the tabs.\n *\n * @default \"horizontal\"\n */\n orientation?: MaybeGetter<\"horizontal\" | \"vertical\" | undefined>;\n /**\n * The default value for `tabs.value`\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that `tabs.value` only changes when the getter returns a new value.\n *\n */\n value: MaybeGetter;\n /**\n * Called when the `Tabs` instance tries to change the active tab.\n */\n onValueChange?: (active: T) => void;\n};" + }, + "SpatialMenu": { + "constructorProps": [ + { + "name": "highlighted", + "type": "MaybeGetter", + "description": "The currently highlighted value.", + "optional": true + }, + { + "name": "onHighlightChange", + "type": "((highlighted: T | null) => void) | undefined", + "description": "Called when the highlighted value changes.", + "optional": true + }, + { + "name": "onSelect", + "type": "((value: T) => void) | undefined", + "optional": true + }, + { + "name": "wrap", + "type": "MaybeGetter | undefined", + "description": "Whether navigation should wrap around when reaching the edges.", + "defaultValue": "false", + "optional": true + }, + { + "name": "scrollBehavior", + "type": "MaybeGetter<\"auto\" | \"smooth\" | \"instant\" | null> | undefined", + "description": "Scroll behavior when highlighting an item with the keyboard.\n`null` to disable scrolling.", + "defaultValue": "\"smooth\"", + "optional": true + }, + { + "name": "toleranceCol", + "type": "MaybeGetter | undefined", + "description": "The maximum distance a the centerX of an item can be in relation\nto the highlighted item to be considered as being on the same column.\n\nSet to `null` to disable.", + "defaultValue": "16", + "optional": true + }, + { + "name": "toleranceRow", + "type": "MaybeGetter | undefined", + "description": "The maximum distance a the centerY of an item can be in relation\nto the highlighted item to be considered as being on the same row.\n\nSet to `null` to disable.", + "defaultValue": "16", + "optional": true + }, + { + "name": "crossAxis", + "type": "MaybeGetter | undefined", + "description": "If `true`, arrow keys will navigate cross-axis as well, if no item\nis available on the current axis.", + "defaultValue": "true", + "optional": true + } + ], + "methods": [ + { + "name": "getItem", + "type": "(\n value: T,\n options?: Pick, \"onSelect\" | \"disabled\"> | undefined,\n) => SpatialMenuItem", + "description": "" + } + ], + "properties": [ + { + "name": "onSelect", + "type": "((value: T) => void) | undefined", + "description": "" + }, + { + "name": "wrap", + "type": "boolean", + "description": "" + }, + { + "name": "scrollBehavior", + "type": "\"auto\" | \"smooth\" | \"instant\" | null", + "description": "" + }, + { + "name": "toleranceCol", + "type": "number | null", + "description": "" + }, + { + "name": "toleranceRow", + "type": "number | null", + "description": "" + }, + { + "name": "crossAxis", + "type": "boolean", + "description": "" + }, + { + "name": "selectionMode", + "type": "\"keyboard\" | \"mouse\"", + "description": "" + }, + { + "name": "highlighted", + "type": "T | null", + "description": "" + }, + { + "name": "root", + "type": "{\n readonly [x: symbol]: (node: HTMLElement) => () => void\n readonly \"data-melt-spatial-menu-root\": \"\"\n readonly tabindex: 0\n readonly onkeydown: (e: KeyboardEvent) => void\n}", + "description": "The root element." + }, + { + "name": "input", + "type": "{\n readonly [x: symbol]: (node: HTMLInputElement) => () => void\n readonly \"data-melt-spatial-menu-input\": \"\"\n readonly onkeydown: (e: KeyboardEvent) => void\n}", + "description": "" + } + ], + "propsAlt": "export type SpatialMenuProps = {\n /**\n * The currently highlighted value.\n */\n highlighted?: MaybeGetter;\n\n /**\n * Called when the highlighted value changes.\n */\n onHighlightChange?: (highlighted: T | null) => void;\n\n onSelect?: (value: T) => void;\n\n /**\n * Whether navigation should wrap around when reaching the edges.\n * @default false\n */\n wrap?: MaybeGetter;\n\n /**\n * Scroll behavior when highlighting an item with the keyboard.\n * `null` to disable scrolling.\n *\n * @default \"smooth\"\n */\n scrollBehavior?: MaybeGetter<\"smooth\" | \"instant\" | \"auto\" | null>;\n\n /**\n * The maximum distance a the centerX of an item can be in relation\n * to the highlighted item to be considered as being on the same column.\n *\n * Set to `null` to disable.\n *\n * @default 16\n */\n toleranceCol?: MaybeGetter;\n\n /**\n * The maximum distance a the centerY of an item can be in relation\n * to the highlighted item to be considered as being on the same row.\n *\n * Set to `null` to disable.\n *\n * @default 16\n */\n toleranceRow?: MaybeGetter;\n\n /**\n * If `true`, arrow keys will navigate cross-axis as well, if no item\n * is available on the current axis.\n *\n * @default true\n */\n crossAxis?: MaybeGetter;\n};" + }, + "Slider": { + "constructorProps": [ + { + "name": "min", + "type": "MaybeGetter", + "description": "The minimum value of the slider.", + "defaultValue": "0", + "optional": true + }, + { + "name": "max", + "type": "MaybeGetter", + "description": "The maximum value of the slider.", + "defaultValue": "100", + "optional": true + }, + { + "name": "orientation", + "type": "MaybeGetter<\"horizontal\" | \"vertical\" | undefined>", + "description": "The orientation of the slider.", + "defaultValue": "\"horizontal\"", + "optional": true + }, + { + "name": "step", + "type": "MaybeGetter", + "description": "The step size of the slider.", + "defaultValue": "1", + "optional": true + }, + { + "name": "value", + "type": "MaybeGetter", + "description": "The default value for `tabs.value`\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that `tabs.value` only changes when the getter returns a new value.\n\nIf omitted, it will use the first tab as default.", + "defaultValue": "undefined", + "optional": true + }, + { + "name": "onValueChange", + "type": "((active: number) => void) | undefined", + "description": "Called when the `Slider` instance tries to change the active tab.", + "optional": true + } + ], + "methods": [], + "properties": [ + { + "name": "min", + "type": "number", + "description": "" + }, + { + "name": "max", + "type": "number", + "description": "" + }, + { + "name": "orientation", + "type": "\"horizontal\" | \"vertical\"", + "description": "" + }, + { + "name": "step", + "type": "number", + "description": "" + }, + { + "name": "ids", + "type": "{ root: string; thumb: string }", + "description": "" + }, + { + "name": "value", + "type": "number", + "description": "The value of the slider." + }, + { + "name": "root", + "type": "{\n readonly \"data-dragging\": \"\" | undefined\n readonly \"data-value\": number\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n readonly \"aria-valuenow\": number\n readonly \"aria-valuemin\": number\n readonly \"aria-valuemax\": number\n readonly \"aria-orientation\": \"horizontal\" | \"vertical\"\n readonly style: `--percentage: ${string}; --percentage-inv: ${string}; touch-action: ${string}`\n readonly tabindex: 0\n readonly role: \"slider\"\n readonly \"data-melt-slider-root\": \"\"\n readonly id: string\n readonly onpointerdown: (e: PointerEvent) => void\n readonly onkeydown: (e: KeyboardEvent) => void\n}", + "description": "The root of the slider.\nAny cursor interaction along this element will change the slider's values." + }, + { + "name": "thumb", + "type": "{\n readonly \"data-dragging\": \"\" | undefined\n readonly \"data-value\": number\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n readonly \"data-melt-slider-thumb\": \"\"\n readonly id: string\n readonly tabindex: 0\n}", + "description": "The slider's thumb, positioned at the end of the range." + } + ], + "propsAlt": "export type SliderProps = {\n /**\n * The minimum value of the slider.\n *\n * @default 0\n */\n min?: MaybeGetter;\n /**\n * The maximum value of the slider.\n *\n * @default 100\n */\n max?: MaybeGetter;\n /**\n * The orientation of the slider.\n *\n * @default \"horizontal\"\n */\n orientation?: MaybeGetter<\"horizontal\" | \"vertical\" | undefined>;\n\n /**\n * The step size of the slider.\n *\n * @default 1\n */\n step?: MaybeGetter;\n\n /**\n * The default value for `tabs.value`\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that `tabs.value` only changes when the getter returns a new value.\n *\n * If omitted, it will use the first tab as default.\n *\n * @default undefined\n */\n value?: MaybeGetter;\n /**\n * Called when the `Slider` instance tries to change the active tab.\n */\n onValueChange?: (active: number) => void;\n};" + }, + "Select": { + "constructorProps": [ + { + "name": "open", + "type": "any", + "description": "If the Popover is open.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", + "defaultValue": "false", + "optional": true + }, + { + "name": "focus", + "type": "any", + "optional": true + }, + { + "name": "onOpenChange", + "type": "any", + "description": "Called when the value is supposed to change.", + "optional": true + }, + { + "name": "forceVisible", + "type": "any", + "description": "If the popover visibility should be controlled by the user.", + "defaultValue": "false", + "optional": true + }, + { + "name": "floatingConfig", + "type": "any", + "description": "Config to be passed to `useFloating`", + "optional": true + }, + { + "name": "closeOnEscape", + "type": "any", + "description": "If the popover should close when clicking escape.", + "defaultValue": "true", + "optional": true + }, + { + "name": "closeOnOutsideClick", + "type": "any", + "description": "If the popover should close when clicking outside.\nAlternatively, accepts a function that receives the clicked element,\nand returns if the popover should close.", + "defaultValue": "true", + "optional": true + }, + { + "name": "multiple", + "type": "MaybeGetter", + "description": "If `true`, multiple options can be selected at the same time.", + "defaultValue": "false", + "optional": true + }, + { + "name": "value", + "type": "MaybeMultiple | undefined", + "description": "The value for the Select.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", + "defaultValue": "false", + "optional": true + }, + { + "name": "onValueChange", + "type": "OnMultipleChange | undefined", + "description": "Called when the value is supposed to change.", + "optional": true + }, + { + "name": "highlighted", + "type": "MaybeGetter", + "description": "The currently highlighted value.", + "optional": true + }, + { + "name": "onHighlightChange", + "type": "((highlighted: T | null) => void) | undefined", + "description": "Called when the highlighted value changes.", + "optional": true + }, + { + "name": "typeaheadTimeout", + "type": "MaybeGetter", + "description": "How many time (in ms) the typeahead string is held before it is cleared", + "defaultValue": "500", + "optional": true + }, + { + "name": "sameWidth", + "type": "MaybeGetter", + "description": "If the content should have the same width as the trigger", + "defaultValue": "true", + "optional": true + }, + { + "name": "scrollAlignment", + "type": "MaybeGetter<\"nearest\" | \"center\" | null | undefined>", + "description": "Determines behavior when scrolling items into view.\nSet to null to disable auto-scrolling.", + "defaultValue": "\"nearest\"", + "optional": true + } + ], + "methods": [ + { + "name": "getOptionId", + "type": "(value: T) => string", + "description": "" + }, + { + "name": "getOption", + "type": "(\n value: T,\n label?: string | undefined,\n) => {\n readonly \"data-melt-select-option\": \"\"\n readonly \"data-value\": string\n readonly \"data-label\": string\n readonly \"aria-hidden\": true | undefined\n readonly \"aria-selected\": boolean\n readonly \"data-highlighted\": \"\" | undefined\n readonly role: \"option\"\n readonly tabindex: -1\n readonly onmouseover: () => void\n readonly onclick: () => void\n}", + "description": "" + } + ], + "properties": [ + { + "name": "multiple", + "type": "Multiple", + "description": "" + }, + { + "name": "scrollAlignment", + "type": "\"nearest\" | \"center\" | null", + "description": "" + }, + { + "name": "ids", + "type": "{ option: string; trigger: string; content: string } & {\n popover: string\n}", + "description": "" + }, + { + "name": "typeaheadTimeout", + "type": "number", + "description": "" + }, + { + "name": "typeahead", + "type": "(\n letter: string,\n) => { value: any; typeahead: string; current: boolean } | undefined", + "description": "" + }, + { + "name": "getOptionLabel", + "type": "(value: T) => string", + "description": "" + }, + { + "name": "isSelected", + "type": "(value: T) => boolean", + "description": "" + }, + { + "name": "select", + "type": "(value: T) => void", + "description": "" + }, + { + "name": "value", + "type": "SelectionStateValue", + "description": "" + }, + { + "name": "highlighted", + "type": "T | null", + "description": "" + }, + { + "name": "valueAsString", + "type": "string", + "description": "" + }, + { + "name": "label", + "type": "{\n for: string\n onclick: (\n e: MouseEvent & { currentTarget: EventTarget & HTMLLabelElement },\n ) => void\n}", + "description": "" + }, + { + "name": "trigger", + "type": "{\n readonly onfocus: (event: FocusEvent) => void\n readonly onfocusout: (event: FocusEvent) => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n readonly popovertarget: string\n readonly onclick: (e: Event) => void\n} & {\n \"data-melt-select-trigger\": string\n id: string\n role: string\n \"aria-expanded\": boolean\n \"aria-controls\": string\n \"aria-owns\": string\n onkeydown: (e: KeyboardEvent) => void\n}", + "description": "" + }, + { + "name": "content", + "type": "{\n readonly onfocus: (event: FocusEvent) => void\n readonly onfocusout: (event: FocusEvent) => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n readonly id: string\n readonly popover: \"manual\"\n readonly ontoggle: (\n e: ToggleEvent & { currentTarget: EventTarget & HTMLElement },\n ) => void\n readonly tabindex: -1\n readonly inert: boolean\n readonly \"data-open\": \"\" | undefined\n} & {\n readonly \"data-melt-select-content\": \"\"\n readonly role: \"listbox\"\n readonly \"aria-expanded\": boolean\n readonly \"aria-activedescendant\": string | undefined\n readonly onkeydown: (e: KeyboardEvent) => void\n}", + "description": "" + } + ], + "propsAlt": "export type SelectProps = Omit & {\n /**\n * If `true`, multiple options can be selected at the same time.\n *\n * @default false\n */\n multiple?: MaybeGetter;\n\n /**\n * The value for the Select.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n *\n * @default false\n */\n value?: MaybeMultiple;\n /**\n * Called when the value is supposed to change.\n */\n onValueChange?: OnMultipleChange;\n\n /**\n * The currently highlighted value.\n */\n highlighted?: MaybeGetter;\n\n /**\n * Called when the highlighted value changes.\n */\n onHighlightChange?: (highlighted: T | null) => void;\n\n /**\n * How many time (in ms) the typeahead string is held before it is cleared\n * @default 500\n */\n typeaheadTimeout?: MaybeGetter;\n\n /**\n * If the content should have the same width as the trigger\n *\n * @default true\n */\n sameWidth?: MaybeGetter;\n\n /**\n * Determines behavior when scrolling items into view.\n * Set to null to disable auto-scrolling.\n *\n * @default \"nearest\"\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#block\n */\n scrollAlignment?: MaybeGetter<\"nearest\" | \"center\" | null | undefined>;\n};" + }, + "RadioGroup": { + "constructorProps": [ + { + "name": "disabled", + "type": "MaybeGetter", + "description": "If `true`, prevents the user from interacting with the group.", + "defaultValue": "false", + "optional": true + }, + { + "name": "required", + "type": "MaybeGetter", + "description": "If `true`, indicates that the user must select a radio button before\nthe owning form can be submitted.", + "defaultValue": "false", + "optional": true + }, + { + "name": "loop", + "type": "MaybeGetter", + "description": "If the the button selection should loop when navigating with the arrow keys.", + "defaultValue": "true", + "optional": true + }, + { + "name": "selectWhenFocused", + "type": "MaybeGetter", + "description": "If `true`, the value will be changed whenever a button is focused.", + "defaultValue": "true", + "optional": true + }, + { + "name": "orientation", + "type": "MaybeGetter<\"horizontal\" | \"vertical\" | undefined>", + "description": "The orientation of the slider.", + "defaultValue": "\"vertical\"", + "optional": true + }, + { + "name": "name", + "type": "MaybeGetter", + "description": "Input name for radio group.", + "optional": true + }, + { + "name": "value", + "type": "MaybeGetter", + "description": "Default value for radio group.", + "defaultValue": "\"\"", + "optional": true + }, + { + "name": "onValueChange", + "type": "((active: string) => void) | undefined", + "description": "Called when the radio button is clicked.", + "optional": true + } + ], + "methods": [ + { + "name": "getItem", + "type": "(item: string) => RadioItem", + "description": "" + }, + { + "name": "select", + "type": "(item: string) => void", + "description": "" + } + ], + "properties": [ + { + "name": "ids", + "type": "{\n root: string\n item: string\n \"hidden-input\": string\n label: string\n}", + "description": "" + }, + { + "name": "disabled", + "type": "boolean", + "description": "" + }, + { + "name": "required", + "type": "boolean", + "description": "" + }, + { + "name": "loop", + "type": "boolean", + "description": "" + }, + { + "name": "selectWhenFocused", + "type": "boolean", + "description": "" + }, + { + "name": "orientation", + "type": "\"horizontal\" | \"vertical\"", + "description": "" + }, + { + "name": "value", + "type": "string", + "description": "" + }, + { + "name": "root", + "type": "{\n readonly \"data-melt-radio-group-root\": \"\"\n readonly id: string\n readonly role: \"radiogroup\"\n readonly \"aria-required\": boolean\n readonly \"aria-labelledby\": string\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n readonly \"data-disabled\": true | undefined\n readonly \"data-value\": string\n}", + "description": "" + }, + { + "name": "label", + "type": "{\n readonly \"data-melt-radio-group-label\": \"\"\n readonly id: string\n readonly for: string\n readonly onclick: (\n e: MouseEvent & { currentTarget: EventTarget & HTMLLabelElement },\n ) => void\n readonly \"data-orientation\": \"horizontal\" | \"vertical\"\n readonly \"data-disabled\": true | undefined\n readonly \"data-value\": string\n}", + "description": "" + }, + { + "name": "hiddenInput", + "type": "{\n readonly \"data-melt-radio-group-hidden-input\": \"\"\n readonly disabled: boolean\n readonly required: boolean\n readonly hidden: true\n readonly \"aria-hidden\": true\n readonly tabindex: -1\n readonly value: string\n readonly name: string | undefined\n}", + "description": "" + } + ], + "propsAlt": "export type RadioGroupProps = {\n /**\n * If `true`, prevents the user from interacting with the group.\n *\n * @default false\n */\n disabled?: MaybeGetter;\n /**\n * If `true`, indicates that the user must select a radio button before\n * the owning form can be submitted.\n *\n * @default false\n */\n required?: MaybeGetter;\n /**\n * If the the button selection should loop when navigating with the arrow keys.\n *\n * @default true\n */\n loop?: MaybeGetter;\n /**\n * If `true`, the value will be changed whenever a button is focused.\n *\n * @default true\n */\n selectWhenFocused?: MaybeGetter;\n /**\n * The orientation of the slider.\n *\n * @default \"vertical\"\n */\n orientation?: MaybeGetter<\"horizontal\" | \"vertical\" | undefined>;\n /**\n * Input name for radio group.\n */\n name?: MaybeGetter;\n /**\n * Default value for radio group.\n *\n * @default \"\"\n */\n value?: MaybeGetter;\n /**\n * Called when the radio button is clicked.\n */\n onValueChange?: (active: string) => void;\n};" + }, + "Progress": { + "constructorProps": [ + { + "name": "value", + "type": "MaybeGetter", + "description": "The value for the progress.", + "defaultValue": "undefined", + "optional": true + }, + { + "name": "max", + "type": "MaybeGetter", + "description": "The maximum value of the progress.", + "optional": true + }, + { + "name": "onValueChange", + "type": "((value: number) => void) | undefined", + "description": "The callback invoked when the value of the progress changes.", + "optional": true + } + ], + "methods": [], + "properties": [ + { + "name": "max", + "type": "number", + "description": "" + }, + { + "name": "value", + "type": "number", + "description": "" + }, + { + "name": "root", + "type": "{\n \"data-melt-progress-root\": string\n value: number\n max: number\n role: string\n \"aria-valuemin\": number\n \"aria-valuemax\": number\n \"aria-valuenow\": number\n \"data-value\": number\n \"data-state\": string\n \"data-max\": number\n}", + "description": "Spread attributes for the Progress root element." + }, + { + "name": "progress", + "type": "{\n \"data-melt-progress-progress\": string\n style: `--progress: ${string}; --neg-progress: ${string}`\n}", + "description": "Spread attributes for the Progress percentage element.\nProvides a --progress CSS variable that can be used to style the progress:\n`transform: translateX(calc(var(--progress) * -1));`" + } + ], + "propsAlt": "export type ProgressProps = {\n /**\n * The value for the progress.\n *\n * @default undefined\n */\n value?: MaybeGetter;\n\n /**\n * The maximum value of the progress.\n *\n * @deafult 100\n */\n max?: MaybeGetter;\n\n /**\n * The callback invoked when the value of the progress changes.\n */\n onValueChange?: (value: number) => void;\n};" + }, + "Popover": { + "constructorProps": [ + { + "name": "open", + "type": "MaybeGetter", + "description": "If the Popover is open.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", + "defaultValue": "false", + "optional": true + }, + { + "name": "onOpenChange", + "type": "((value: boolean) => void) | undefined", + "description": "Called when the value is supposed to change.", + "optional": true + }, + { + "name": "forceVisible", + "type": "MaybeGetter", + "description": "If the popover visibility should be controlled by the user.", + "defaultValue": "false", + "optional": true + }, + { + "name": "floatingConfig", + "type": "UseFloatingConfig | undefined>", + "description": "Config to be passed to `useFloating`", + "optional": true + }, + { + "name": "sameWidth", + "type": "MaybeGetter", + "description": "If the popover should have the same width as the trigger", + "defaultValue": "false", + "optional": true + }, + { + "name": "closeOnEscape", + "type": "MaybeGetter", + "description": "If the popover should close when clicking escape.", + "defaultValue": "true", + "optional": true + }, + { + "name": "closeOnOutsideClick", + "type": "CloseOnOutsideClickProp", + "description": "If the popover should close when clicking outside.\nAlternatively, accepts a function that receives the clicked element,\nand returns if the popover should close.", + "defaultValue": "true", + "optional": true + }, + { + "name": "focus", + "type": "{ onOpen?: MaybeGetter } | undefined", + "optional": true + } + ], + "methods": [], + "properties": [ + { + "name": "ids", + "type": "{ popover: string } & { trigger: string; content: string }", + "description": "" + }, + { + "name": "trigger", + "type": "{\n readonly onfocus: (event: FocusEvent) => void\n readonly onfocusout: (event: FocusEvent) => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n readonly popovertarget: string\n readonly onclick: (e: Event) => void\n} & { \"data-melt-popover-trigger\": string }", + "description": "The trigger that toggles the value." + }, + { + "name": "content", + "type": "{\n readonly onfocus: (event: FocusEvent) => void\n readonly onfocusout: (event: FocusEvent) => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n readonly id: string\n readonly popover: \"manual\"\n readonly ontoggle: (\n e: ToggleEvent & { currentTarget: EventTarget & HTMLElement },\n ) => void\n readonly tabindex: -1\n readonly inert: boolean\n readonly \"data-open\": \"\" | undefined\n} & { \"data-melt-popover-content\": string }", + "description": "" + } + ], + "propsAlt": "export type PopoverProps = {\n /**\n * If the Popover is open.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n *\n * @default false\n */\n open?: MaybeGetter;\n\n /**\n * Called when the value is supposed to change.\n */\n onOpenChange?: (value: boolean) => void;\n\n /**\n * If the popover visibility should be controlled by the user.\n *\n * @default false\n */\n forceVisible?: MaybeGetter;\n\n /**\n * Config to be passed to `useFloating`\n */\n floatingConfig?: UseFloatingArgs[\"config\"];\n\n /**\n * If the popover should have the same width as the trigger\n *\n * @default false\n */\n sameWidth?: MaybeGetter;\n\n /**\n * If the popover should close when clicking escape.\n *\n * @default true\n */\n closeOnEscape?: MaybeGetter;\n\n /**\n * If the popover should close when clicking outside.\n * Alternatively, accepts a function that receives the clicked element,\n * and returns if the popover should close.\n *\n * @default true\n */\n closeOnOutsideClick?: CloseOnOutsideClickProp;\n\n focus?: {\n /**\n * Which element to focus when the popover opens.\n * Can be a selector string, an element, or a Getter for those.\n * If null, the focus remains on the trigger element.\n *\n * Defaults to the popover content element.\n */\n onOpen?: MaybeGetter;\n\n /**\n * Which element to focus when the popover closes.\n * Can be a selector string, an element, or a Getter for those.\n * If null, the focus goes to the document body.\n *\n * Defaults to the last used trigger element.\n */\n onClose?: MaybeGetter;\n\n /**\n * If focus should be trapped inside the popover content when open.\n *\n * @default false\n */\n trap?: MaybeGetter;\n };\n};" + }, + "PinInput": { + "constructorProps": [ + { + "name": "value", + "type": "MaybeGetter", + "description": "The value for the Pin Input.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", + "defaultValue": "''", + "optional": true + }, + { + "name": "onValueChange", + "type": "((value: string) => void) | undefined", + "description": "Called when the `PinInput` instance tries to change the value.", + "optional": true + }, + { + "name": "onComplete", + "type": "((value: string) => void) | undefined", + "description": "Called when the `PinInput` instance is filled.", + "optional": true + }, + { + "name": "onPaste", + "type": "((value: string) => void) | undefined", + "description": "Override the default behavior when pasting a value.", + "optional": true + }, + { + "name": "onError", + "type": "((error: PinInputError) => void) | undefined", + "description": "Called when the PinInput encounters an error.", + "optional": true + }, + { + "name": "maxLength", + "type": "MaybeGetter", + "description": "The amount of digits in the Pin Input.", + "defaultValue": "4", + "optional": true + }, + { + "name": "placeholder", + "type": "MaybeGetter", + "description": "An optional placeholder to display when the input is empty.", + "defaultValue": "'○'", + "optional": true + }, + { + "name": "disabled", + "type": "MaybeGetter", + "description": "If `true`, prevents the user from interacting with the input.", + "defaultValue": "false", + "optional": true + }, + { + "name": "mask", + "type": "MaybeGetter", + "description": "If the input should be masked like a password.", + "defaultValue": "false", + "optional": true + }, + { + "name": "type", + "type": "MaybeGetter<\"text\" | \"alphanumeric\" | \"numeric\" | undefined>", + "description": "What characters the input accepts.", + "defaultValue": "'text'", + "optional": true + }, + { + "name": "allowPaste", + "type": "MaybeGetter", + "description": "If `true`, allows pasting values from the clipboard.", + "defaultValue": "true", + "optional": true + } + ], + "methods": [], + "properties": [ + { + "name": "maxLength", + "type": "number", + "description": "" + }, + { + "name": "placeholder", + "type": "string", + "description": "" + }, + { + "name": "disabled", + "type": "boolean", + "description": "" + }, + { + "name": "mask", + "type": "boolean", + "description": "" + }, + { + "name": "type", + "type": "\"text\" | \"alphanumeric\" | \"numeric\"", + "description": "" + }, + { + "name": "allowPaste", + "type": "boolean", + "description": "" + }, + { + "name": "isFilled", + "type": "boolean", + "description": "" + }, + { + "name": "value", + "type": "string", + "description": "" + }, + { + "name": "root", + "type": "{\n readonly \"data-melt-pin-input-root\": \"\"\n readonly id: string\n readonly \"data-complete\": \"\" | undefined\n}", + "description": "The root element's props." + }, + { + "name": "inputs", + "type": "{\n readonly \"data-melt-pin-input-input\": \"\"\n readonly placeholder: string | undefined\n readonly disabled: true | undefined\n readonly type: \"password\" | \"text\"\n readonly \"data-filled\": \"\" | undefined\n readonly tabindex: 0 | -1\n readonly inputmode: \"text\" | \"numeric\"\n readonly style: \"caret-color: transparent;\" | undefined\n readonly onkeydown: (e: KeyboardEvent) => void\n readonly onpointerdown: (e: Event) => void\n readonly onpointerup: (e: Event) => void\n readonly oninput: (e: Event) => void\n readonly onfocus: () => void\n readonly onblur: () => void\n readonly onpaste: (\n e: ClipboardEvent & { currentTarget: EventTarget & HTMLInputElement },\n ) => void\n}[]", + "description": "An array of props that should be spread to the input elements." + } + ], + "propsAlt": "export type PinInputProps = {\n /**\n * The value for the Pin Input.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n *\n * @default ''\n */\n value?: MaybeGetter;\n /**\n * Called when the `PinInput` instance tries to change the value.\n */\n onValueChange?: (value: string) => void;\n\n /**\n * Called when the `PinInput` instance is filled.\n */\n onComplete?: (value: string) => void;\n\n /**\n * Override the default behavior when pasting a value.\n *\n * @param value The pasted value.\n *\n * @example ```ts\n * const pin = new PinInput({\n * onPaste(value) {\n * if (!valid(value)) {\n * // do something\n * return\n * }\n * pin.value = value\n * }\n * });\n */\n onPaste?: (value: string) => void;\n\n /**\n * Called when the PinInput encounters an error.\n */\n onError?: (error: PinInputError) => void;\n\n /**\n * The amount of digits in the Pin Input.\n *\n * @default 4\n */\n maxLength?: MaybeGetter;\n /**\n * An optional placeholder to display when the input is empty.\n *\n * @default '○'\n */\n placeholder?: MaybeGetter;\n\n /**\n * If `true`, prevents the user from interacting with the input.\n *\n * @default false\n */\n disabled?: MaybeGetter;\n\n /**\n * If the input should be masked like a password.\n *\n * @default false\n */\n mask?: MaybeGetter;\n\n /**\n * What characters the input accepts.\n *\n * @default 'text'\n */\n type?: MaybeGetter<\"alphanumeric\" | \"numeric\" | \"text\" | undefined>;\n\n /**\n * If `true`, allows pasting values from the clipboard.\n *\n * @default true\n */\n allowPaste?: MaybeGetter;\n};" + }, + "FileUpload": { + "constructorProps": [ + { + "name": "selected", + "type": "MaybeMultiple | undefined", + "description": "The currently selected files.", + "optional": true + }, + { + "name": "onSelectedChange", + "type": "| ((files: Multiple extends true ? Set : File | undefined) => void)\n | undefined", + "description": "Callback fired when selected files change", + "optional": true + }, + { + "name": "multiple", + "type": "MaybeGetter", + "description": "Whether to accept multiple files", + "defaultValue": "false", + "optional": true + }, + { + "name": "accept", + "type": "MaybeGetter", + "description": "The accepted file types. Can be a MIME type, a MIME group, or a file extension.\nSeparate multiple types with a comma.", + "optional": true + }, + { + "name": "maxSize", + "type": "MaybeGetter", + "description": "Maximum file size in bytes", + "defaultValue": "undefined", + "optional": true + }, + { + "name": "disabled", + "type": "MaybeGetter", + "description": "Whether the file upload is disabled", + "defaultValue": "false", + "optional": true + }, + { + "name": "validate", + "type": "((file: File) => boolean) | undefined", + "description": "Custom validate fn. Will be called together with the original validation,\nwhich takes into account the `accept` and `maxSize` props.", + "optional": true + }, + { + "name": "onError", + "type": "((error: FileUploadError) => void) | undefined", + "description": "Callback fired when a file fails validation", + "optional": true + }, + { + "name": "onAccept", + "type": "((file: File) => void) | undefined", + "description": "Callback fired when a file is accepted", + "optional": true + }, + { + "name": "avoidDuplicates", + "type": "MaybeGetter", + "description": "If true, checks the files contents to avoid duplicate.\nIt's performance is not tested in large files, so by default its set to false.", + "defaultValue": "false", + "optional": true + } + ], + "methods": [ + { + "name": "clear", + "type": "() => void", + "description": "Clears the currently selected files" + }, + { + "name": "remove", + "type": "(file: File) => void", + "description": "Removes a file from the selection" + }, + { + "name": "has", + "type": "(file: File) => Promise", + "description": "" + } + ], + "properties": [ + { + "name": "multiple", + "type": "Multiple", + "description": "" + }, + { + "name": "accept", + "type": "string | undefined", + "description": "" + }, + { + "name": "maxSize", + "type": "number | undefined", + "description": "" + }, + { + "name": "disabled", + "type": "boolean", + "description": "" + }, + { + "name": "avoidDuplicates", + "type": "boolean", + "description": "" + }, + { + "name": "ids", + "type": "{ input: string; dropzone: string }", + "description": "" + }, + { + "name": "isDragging", + "type": "boolean", + "description": "" + }, + { + "name": "selected", + "type": "SelectionStateValue", + "description": "Gets the currently selected files" + }, + { + "name": "dropzone", + "type": "{\n readonly \"data-melt-fileupload-dropzone\": \"\"\n readonly \"data-dragging\": \"\" | undefined\n readonly \"data-disabled\": \"\" | undefined\n readonly ondragenter: (e: DragEvent) => void\n readonly ondragleave: (e: DragEvent) => void\n readonly ondragover: (e: DragEvent) => void\n readonly ondrop: (e: DragEvent) => void\n readonly onclick: () => void\n}", + "description": "The dropzone element, where you can drag files into, or click to open the file picker." + }, + { + "name": "input", + "type": "{\n readonly \"data-melt-fileupload-input\": \"\"\n readonly id: string\n readonly type: \"file\"\n readonly accept: string | undefined\n readonly multiple: Multiple\n readonly style: \"display: none;\"\n readonly disabled: boolean\n readonly onchange: (e: Event) => void\n}", + "description": "The hidden file input element." + }, + { + "name": "trigger", + "type": "{\n readonly \"data-disabled\": \"\" | undefined\n readonly onclick: () => void\n}", + "description": "An optional trigger element, which can be used to open the file picker." + } + ], + "propsAlt": "export type FileUploadProps = {\n /**\n * The currently selected files.\n */\n selected?: MaybeMultiple;\n\n /**\n * Callback fired when selected files change\n */\n onSelectedChange?: (files: Multiple extends true ? Set : File | undefined) => void;\n\n /**\n * Whether to accept multiple files\n * @default false\n */\n multiple?: MaybeGetter;\n\n /**\n * The accepted file types. Can be a MIME type, a MIME group, or a file extension.\n * Separate multiple types with a comma.\n * @example 'image/jpeg'\n * @example 'image/*'\n * @example '.png, .jpg, .jpeg'\n */\n accept?: MaybeGetter;\n\n /**\n * Maximum file size in bytes\n * @default undefined\n */\n maxSize?: MaybeGetter;\n\n /**\n * Whether the file upload is disabled\n * @default false\n */\n disabled?: MaybeGetter;\n\n /**\n * Custom validate fn. Will be called together with the original validation,\n * which takes into account the `accept` and `maxSize` props.\n */\n validate?: (file: File) => boolean;\n\n /**\n * Callback fired when a file fails validation\n */\n onError?: (error: FileUploadError) => void;\n\n /**\n * Callback fired when a file is accepted\n */\n onAccept?: (file: File) => void;\n\n /**\n * If true, checks the files contents to avoid duplicate.\n * It's performance is not tested in large files, so by default its set to false.\n *\n * @default false\n */\n avoidDuplicates?: MaybeGetter;\n};" + }, + "Combobox": { + "constructorProps": [ + { + "name": "open", + "type": "any", + "description": "If the Popover is open.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", + "defaultValue": "false", + "optional": true + }, + { + "name": "focus", + "type": "any", + "optional": true + }, + { + "name": "onOpenChange", + "type": "any", + "description": "Called when the value is supposed to change.", + "optional": true + }, + { + "name": "forceVisible", + "type": "any", + "description": "If the popover visibility should be controlled by the user.", + "defaultValue": "false", + "optional": true + }, + { + "name": "floatingConfig", + "type": "any", + "description": "Config to be passed to `useFloating`", + "optional": true + }, + { + "name": "multiple", + "type": "MaybeGetter", + "description": "If `true`, multiple options can be selected at the same time.", + "defaultValue": "false", + "optional": true + }, + { + "name": "value", + "type": "MaybeMultiple | undefined", + "description": "The value for the Combobox.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", + "defaultValue": "false", + "optional": true + }, + { + "name": "onValueChange", + "type": "OnMultipleChange | undefined", + "description": "Called when the value is supposed to change.", + "optional": true + }, + { + "name": "inputValue", + "type": "MaybeGetter", + "description": "The inputValue for the Combobox.\n\nWhen passing a getter, it will be used as source of truth,\nmeaning that the value only changes when the getter returns a new value.\n\nOtherwise, if passing a static value, it'll serve as the default value.", + "defaultValue": "false", + "optional": true + }, + { + "name": "onInputValueChange", + "type": "Setter | undefined", + "description": "Called when the value is supposed to change.", + "optional": true + }, + { + "name": "highlighted", + "type": "MaybeGetter", + "description": "The currently highlighted value.", + "optional": true + }, + { + "name": "onHighlightChange", + "type": "((highlighted: T | null) => void) | undefined", + "description": "Called when the highlighted value changes.", + "optional": true + }, + { + "name": "scrollAlignment", + "type": "MaybeGetter<\"nearest\" | \"center\" | null | undefined>", + "description": "Determines behavior when scrolling items into view.\nSet to null to disable auto-scrolling.", + "defaultValue": "\"nearest\"", + "optional": true + }, + { + "name": "sameWidth", + "type": "MaybeGetter", + "description": "If the content should have the same width as the trigger", + "defaultValue": "true", + "optional": true + } + ], + "methods": [ + { + "name": "select", + "type": "(value: T) => void", + "description": "" + }, + { + "name": "scrollIntoView", + "type": "(value?: T | undefined) => void", + "description": "" + }, + { + "name": "getOptionId", + "type": "(value: T) => string", + "description": "" + }, + { + "name": "getOption", + "type": "(\n value: T,\n label?: string | undefined,\n onSelect?: (() => void) | undefined,\n) => {\n readonly id: string\n readonly \"data-melt-combobox-option\": \"\"\n readonly \"data-value\": string\n readonly \"data-label\": string\n readonly \"aria-hidden\": true | undefined\n readonly \"aria-selected\": boolean\n readonly \"data-highlighted\": \"\" | undefined\n readonly tabindex: -1\n readonly role: \"option\"\n readonly onmouseover: () => void\n readonly onclick: () => void\n}", + "description": "Gets the attributes for the option element.\n@param value The value of the option.\n@param label The label to display for the option. If not provided, the value will be stringified.\n@param onSelect An optional callback to call when the option is selected, overriding the default behavior.\n@returns The attributes for the option element." + }, + { + "name": "getOptionsEls", + "type": "() => HTMLElement[]", + "description": "" + }, + { + "name": "getOptions", + "type": "() => T[]", + "description": "" + }, + { + "name": "highlight", + "type": "(value: T) => void", + "description": "" + }, + { + "name": "highlightNext", + "type": "() => void", + "description": "" + }, + { + "name": "highlightPrev", + "type": "() => void", + "description": "" + }, + { + "name": "highlightFirst", + "type": "() => void", + "description": "" + }, + { + "name": "highlightLast", + "type": "() => void", + "description": "" + } + ], + "properties": [ + { + "name": "multiple", + "type": "Multiple", + "description": "" + }, + { + "name": "scrollAlignment", + "type": "\"nearest\" | \"center\" | null", + "description": "" + }, + { + "name": "touched", + "type": "boolean", + "description": "" + }, + { + "name": "onSelectMap", + "type": "Map void>", + "description": "" + }, + { + "name": "ids", + "type": "{\n option: string\n trigger: string\n content: string\n input: string\n} & { popover: string }", + "description": "" + }, + { + "name": "isSelected", + "type": "(value: T) => boolean", + "description": "" + }, + { + "name": "getOptionLabel", + "type": "(value: T) => string", + "description": "" + }, + { + "name": "value", + "type": "SelectionStateValue", + "description": "" + }, + { + "name": "inputValue", + "type": "string", + "description": "" + }, + { + "name": "highlighted", + "type": "T | null", + "description": "" + }, + { + "name": "label", + "type": "{\n for: string\n onclick: (\n e: MouseEvent & { currentTarget: EventTarget & HTMLLabelElement },\n ) => void\n}", + "description": "" + }, + { + "name": "input", + "type": "{\n readonly \"data-melt-combobox-input\": \"\"\n readonly id: string\n readonly role: \"combobox\"\n readonly \"aria-expanded\": boolean\n readonly \"aria-controls\": string\n readonly \"aria-owns\": string\n readonly onclick: () => void\n readonly value: string\n readonly oninput: (e: Event) => void\n readonly onkeydown: (e: KeyboardEvent) => void\n readonly onfocus: (event: FocusEvent) => void\n readonly onfocusout: (event: FocusEvent) => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n readonly popovertarget: string\n}", + "description": "" + }, + { + "name": "trigger", + "type": "{\n onfocus: (event: FocusEvent) => void\n onfocusout: (event: FocusEvent) => Promise\n style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n \"data-melt-combobox-trigger\": string\n id: string\n onclick: () => void\n}", + "description": "" + }, + { + "name": "content", + "type": "{\n readonly onfocus: (event: FocusEvent) => void\n readonly onfocusout: (event: FocusEvent) => Promise\n readonly style: `--melt-invoker-width: ${string}; --melt-invoker-height: ${string}; --melt-invoker-x: ${string}; --melt-invoker-y: ${string}; --melt-popover-available-width: ${string}; --melt-popover-available-height: ${string}`\n readonly id: string\n readonly popover: \"manual\"\n readonly ontoggle: (\n e: ToggleEvent & { currentTarget: EventTarget & HTMLElement },\n ) => void\n readonly tabindex: -1\n readonly inert: boolean\n readonly \"data-open\": \"\" | undefined\n} & {\n readonly \"data-melt-combobox-content\": \"\"\n readonly role: \"listbox\"\n readonly \"aria-expanded\": boolean\n readonly \"aria-activedescendant\": string | undefined\n}", + "description": "" + }, + { + "name": "valueAsString", + "type": "string", + "description": "" + } + ], + "propsAlt": "export type ComboboxProps = Omit<\n PopoverProps,\n \"closeOnEscape\" | \"closeOnOutsideClick\" | \"sameWidth\"\n> & {\n /**\n * If `true`, multiple options can be selected at the same time.\n *\n * @default false\n */\n multiple?: MaybeGetter;\n\n /**\n * The value for the Combobox.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n *\n * @default false\n */\n value?: MaybeMultiple;\n /**\n * Called when the value is supposed to change.\n */\n onValueChange?: OnMultipleChange;\n\n /**\n * The inputValue for the Combobox.\n *\n * When passing a getter, it will be used as source of truth,\n * meaning that the value only changes when the getter returns a new value.\n *\n * Otherwise, if passing a static value, it'll serve as the default value.\n *\n *\n * @default false\n */\n inputValue?: MaybeGetter;\n /**\n * Called when the value is supposed to change.\n */\n onInputValueChange?: Setter;\n\n /**\n * The currently highlighted value.\n */\n highlighted?: MaybeGetter;\n\n /**\n * Called when the highlighted value changes.\n */\n onHighlightChange?: (highlighted: T | null) => void;\n\n /**\n * Determines behavior when scrolling items into view.\n * Set to null to disable auto-scrolling.\n *\n * @default \"nearest\"\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#block\n */\n scrollAlignment?: MaybeGetter<\"nearest\" | \"center\" | null | undefined>;\n\n /**\n * If the content should have the same width as the trigger\n *\n * @default true\n */\n sameWidth?: MaybeGetter;\n};" + }, + "Collapsible": { + "constructorProps": [ + { + "name": "disabled", + "type": "MaybeGetter", + "description": "Whether the collapsible is disabled which prevents it from being opened.", + "optional": true + }, + { + "name": "open", + "type": "MaybeGetter", + "description": "Whether the collapsible is open.", + "optional": true + }, + { + "name": "onOpenChange", + "type": "((value: boolean) => void) | undefined", + "description": "A callback called when the value of `open` changes.", + "optional": true + } + ], + "methods": [], + "properties": [ + { + "name": "disabled", + "type": "boolean", + "description": "" + }, + { + "name": "ids", + "type": "{ trigger: string; content: string }", + "description": "" + }, + { + "name": "open", + "type": "boolean", + "description": "The open state of the collapsible." + }, + { + "name": "trigger", + "type": "{\n readonly disabled: boolean\n readonly onclick: () => void\n readonly \"data-state\": string\n readonly \"data-disabled\": \"\" | undefined\n readonly \"data-melt-collapsible-trigger\": \"\"\n readonly id: string\n readonly \"aria-expanded\": boolean\n readonly \"aria-controls\": string\n}", + "description": "The spread attributes for the trigger button." + }, + { + "name": "content", + "type": "{\n readonly \"data-state\": string\n readonly \"data-disabled\": \"\" | undefined\n readonly \"data-melt-collapsible-content\": \"\"\n readonly id: string\n}", + "description": "The spread attributes for the content element." + } + ], + "propsAlt": "export type CollapsibleProps = {\n /**\n * Whether the collapsible is disabled which prevents it from being opened.\n */\n disabled?: MaybeGetter;\n\n /**\n * Whether the collapsible is open.\n */\n open?: MaybeGetter;\n\n /**\n * A callback called when the value of `open` changes.\n */\n onOpenChange?: (value: boolean) => void;\n};" + }, + "Avatar": { + "constructorProps": [ + { + "name": "src", + "type": "MaybeGetter", + "description": "The source of the image to display.", + "optional": true + }, + { + "name": "delayMs", + "type": "MaybeGetter", + "description": "The amount of time in milliseconds to wait before displaying the image.", + "defaultValue": "0", + "optional": true + }, + { + "name": "onLoadingStatusChange", + "type": "((value: ImageLoadingStatus) => void | undefined) | undefined", + "description": "A callback invoked when the loading status store of the avatar changes.", + "optional": true + } + ], + "methods": [], + "properties": [ + { + "name": "src", + "type": "string", + "description": "" + }, + { + "name": "delayMs", + "type": "number", + "description": "" + }, + { + "name": "loadingStatus", + "type": "ImageLoadingStatus", + "description": "" + }, + { + "name": "image", + "type": "{\n readonly \"data-melt-avatar-image\": \"\"\n readonly src: string\n readonly style: `display: ${string}`\n readonly onload: () => (() => void) | undefined\n readonly onerror: () => void\n}", + "description": "" + }, + { + "name": "fallback", + "type": "{\n readonly \"data-melt-avatar-fallback\": \"\"\n readonly style: `display: ${string}` | undefined\n readonly hidden: true | undefined\n}", + "description": "" + } + ], + "propsAlt": "export type AvatarProps = {\n /**\n * The source of the image to display.\n */\n src?: MaybeGetter;\n\n /**\n * The amount of time in milliseconds to wait before displaying the image.\n *\n * @default 0\n */\n delayMs?: MaybeGetter;\n\n /**\n * A callback invoked when the loading status store of the avatar changes.\n */\n onLoadingStatusChange?: (value: ImageLoadingStatus) => void | undefined;\n};" + }, + "Accordion": { + "constructorProps": [ + { + "name": "multiple", + "type": "MaybeGetter", + "description": "If `true`, multiple accordion items can be open at the same time.", + "defaultValue": "false", + "optional": true + }, + { + "name": "disabled", + "type": "MaybeGetter", + "description": "When `true`, prevents the user from interacting with the accordion.", + "defaultValue": "false", + "optional": true + }, + { + "name": "value", + "type": "MaybeMultiple | undefined", + "description": "The controlled value for the accordion.", + "optional": true + }, + { + "name": "onValueChange", + "type": "OnMultipleChange | undefined", + "description": "The callback invoked when the value of the Accordion changes.", + "optional": true + } + ], + "methods": [ + { + "name": "getItem", + "type": ">(\n item: AccordionItemMeta,\n) => AccordionItem", + "description": "Returns an Item class with the necessary\nspread attributes for an accordion item.\n@param item" + }, + { + "name": "isExpanded", + "type": "(id: string) => boolean", + "description": "Checks if an item is currently expanded.\n@param id - ID of the item to check." + }, + { + "name": "expand", + "type": "(id: string) => void", + "description": "Expands a specific item.\n@param id - ID of the item to expand." + }, + { + "name": "collapse", + "type": "(id: string) => void", + "description": "Collapses a specific item.\n@param id - ID of the item to collapse." + }, + { + "name": "toggleExpanded", + "type": "(id: string) => void", + "description": "Toggles the expanded state of an item.\n@param id - ID of the item to toggle." + } + ], + "properties": [ + { + "name": "multiple", + "type": "Multiple", + "description": "" + }, + { + "name": "disabled", + "type": "boolean", + "description": "" + }, + { + "name": "ids", + "type": "{\n root: string\n heading: string\n item: string\n trigger: string\n content: string\n}", + "description": "" + }, + { + "name": "value", + "type": "FalseIfUndefined>", + "description": "" + }, + { + "name": "root", + "type": "{ \"data-melt-accordion-root\": string; id: string }", + "description": "Spread attributes for the accordion root element." + } + ], + "propsAlt": "export type AccordionProps = {\n /**\n * If `true`, multiple accordion items can be open at the same time.\n *\n * @default false\n */\n multiple?: MaybeGetter;\n\n /**\n * When `true`, prevents the user from interacting with the accordion.\n *\n * @default false\n */\n disabled?: MaybeGetter;\n\n /**\n * The controlled value for the accordion.\n */\n value?: AccordionValue;\n\n /**\n * The callback invoked when the value of the Accordion changes.\n */\n onValueChange?: OnMultipleChange;\n};" + } +} diff --git a/docs/src/content/docs/components/video.mdx b/docs/src/content/docs/components/video.mdx new file mode 100644 index 00000000..14c42cd7 --- /dev/null +++ b/docs/src/content/docs/components/video.mdx @@ -0,0 +1,196 @@ +--- +title: Video +description: A headless video player with full control over playback, volume, and state. +--- +import ApiTable from "@components/api-table.astro"; +import Preview from "@previews/video.svelte"; +import Features from "@components/features.astro"; +import ThemedCode from "@components/themed-code.astro"; +import { Tabs, TabItem } from '@astrojs/starlight/components'; + + + +## Features + + +- 🎹 Keyboard controls +- 🎮 Play, pause, seek, volume, and fullscreen controls +- 📊 Progress and buffering indicators +- 🧠 Smart state management +- ⌛ Time formatting utilities +- 💬 Screen reader support + + +## Usage + + + +```svelte + + +
+
+``` +
+ + +```svelte + + + +``` + +
+ +## Controls + +The Video builder includes multiple ways to interact with the player: + +### Mouse Controls + +- **Click**: Play/pause +- **Double-click**: Toggle fullscreen + +### Keyboard Controls + +The Video builder includes keyboard shortcuts by default: + +- **Space / K**: Play/pause +- **Arrow Left / J**: Seek backward (default: 10 seconds) +- **Arrow Right / L**: Seek forward (default: 10 seconds) +- **Arrow Up**: Increase volume (default: 5%) +- **Arrow Down**: Decrease volume (default: 5%) +- **M**: Toggle mute +- **F**: Toggle fullscreen +- **Home**: Jump to beginning +- **End**: Jump to end +- **0-9**: Jump to 0%-90% of the video + +### Visual Feedback + +When using keyboard shortcuts or mouse controls, a brief visual indicator appears on screen showing the action performed (e.g., "Volume: 75%", "+10s", "Muted", "Playing"). This feedback is automatically displayed for 1.5 seconds and can be styled using the `keyboardFeedback` property: + +```svelte +
+
+``` + +### Customizing Keyboard Controls + +You can configure the seek and volume step values: + +```svelte + +``` + +You can also disable keyboard controls entirely: + +```svelte + +``` + +## Styling + +By default, Melt does not provide styles. This means you'll be responsible for styling your video player controls. + +To facilitate this, Melt provides CSS custom properties, `--progress` and `--buffered`. + +### Progress Bar + +The progress bar uses the `--progress` CSS property to indicate playback position: + +```css +[data-melt-video-player-progress-bar] { + background: linear-gradient( + to right, + blue 0%, + blue var(--progress), + gray var(--progress), + gray 100% + ); +} +``` + +### Buffering Progress + +You can also show buffering progress using the `--buffered` property: + +```css +[data-melt-video-player-progress-bar] { + background: linear-gradient( + to right, + blue 0%, + blue var(--progress), + lightblue var(--progress), + lightblue var(--buffered), + gray var(--buffered), + gray 100% + ); +} +``` + +## API Reference + + \ No newline at end of file diff --git a/docs/src/previews/video.svelte b/docs/src/previews/video.svelte new file mode 100644 index 00000000..926a5bb9 --- /dev/null +++ b/docs/src/previews/video.svelte @@ -0,0 +1,255 @@ + + + +
+ + +
+
+ +
+ +
+
+ + +
+ + +
+ +
+ {video.formatTime(video.currentTime)} / {video.formatTime(video.duration)} +
+
+ + +
+
+ + {#if video.loading} +
+
+
+ {/if} + + {#if video.error} +
+
+

Error loading video

+

{video.error}

+
+
+ {/if} + + {#if video.keyboardFeedback} +
+
+ {video.keyboardFeedback} +
+
+ {/if} +
+
+ + diff --git a/packages/melt/src/lib/builders/Video.svelte.ts b/packages/melt/src/lib/builders/Video.svelte.ts new file mode 100644 index 00000000..0c4f8e24 --- /dev/null +++ b/packages/melt/src/lib/builders/Video.svelte.ts @@ -0,0 +1,953 @@ +import { Synced } from "$lib/Synced.svelte"; +import type { MaybeGetter } from "$lib/types"; +import { dataAttr, styleAttr } from "$lib/utils/attribute"; +import { extract } from "$lib/utils/extract"; +import { createBuilderMetadata } from "$lib/utils/identifiers"; +import { useEventListener } from "runed"; +import type { HTMLAttributes, HTMLInputAttributes, HTMLVideoAttributes } from "svelte/elements"; + +const { createIds, dataAttrs } = createBuilderMetadata("video-player", [ + "root", + "video", + "controls", + "playButton", + "muteButton", + "volumeSlider", + "progressBar", + "timeDisplay", + "fullscreenButton", +]); + +export type VideoProps = { + /** + * The source URL of the video. + */ + src?: MaybeGetter; + + /** + * The poster image URL to display before the video loads. + */ + poster?: MaybeGetter; + + /** + * The current time of the video in seconds. + * + * @default 0 + */ + currentTime?: MaybeGetter; + + /** + * The volume level of the video (0-1). + * + * @default 1 + */ + volume?: MaybeGetter; + + /** + * The playback rate of the video. + * + * @default 1 + */ + playbackRate?: MaybeGetter; + + /** + * Whether the video should be muted. + * + * @default false + */ + muted?: MaybeGetter; + + /** + * Whether the video should loop. + * + * @default false + */ + loop?: MaybeGetter; + + /** + * Whether the video should autoplay. + * + * @default false + */ + autoplay?: MaybeGetter; + + /** + * How the video should be preloaded. + * + * @default "metadata" + */ + preload?: MaybeGetter<"none" | "metadata" | "auto" | undefined>; + + /** + * Whether to enable keyboard controls. + * + * @default true + */ + keyboardControls?: MaybeGetter; + + /** + * Volume step for keyboard controls (up/down arrows). + * + * @default 0.05 + */ + volumeStep?: MaybeGetter; + + /** + * Seek step in seconds for keyboard controls (left/right arrows, j/l keys). + * + * @default 10 + */ + seekStep?: MaybeGetter; + + /** + * Callback fired when the playing state changes. + */ + onPlayingChange?: (playing: boolean) => void; + + /** + * Callback fired when the current time changes. + */ + onCurrentTimeChange?: (currentTime: number) => void; + + /** + * Callback fired when the volume changes. + */ + onVolumeChange?: (volume: number) => void; + + /** + * Callback fired when the muted state changes. + */ + onMutedChange?: (muted: boolean) => void; + + /** + * Callback fired when the playback rate changes. + */ + onPlaybackRateChange?: (playbackRate: number) => void; + + /** + * Callback fired when the video ends. + */ + onEnded?: () => void; + + /** + * Callback fired when the video is ready to play. + */ + onCanPlay?: () => void; + + /** + * Callback fired when video metadata is loaded. + */ + onLoadedMetadata?: () => void; + + /** + * Callback fired when an error occurs. + */ + onError?: (error: Event) => void; +}; + +/** + * A headless video player component with complete state management, + * keyboard controls, and Web Audio API integration for smooth volume control. + */ +export class Video { + #props: VideoProps; + readonly src: string; + readonly poster: string; + readonly loop: boolean; + readonly autoplay: boolean; + readonly preload: "none" | "metadata" | "auto"; + readonly playbackRate: number; + readonly keyboardControls: boolean; + readonly volumeStep: number; + readonly seekStep: number; + + #currentTime: Synced; + #volume: Synced; + #muted = $state(false); + #playing: Synced; + #duration = $state(0); + #buffered = $state(0); + #loading = $state(false); + #error = $state(null); + #fullscreen = $state(false); + #seeking = $state(false); + #keyboardFeedback = $state(null); + #keyboardFeedbackTimeout: ReturnType | undefined; + #clickTimeout: ReturnType | undefined; + #audioContext: AudioContext | null = null; + #gainNode: GainNode | null = null; + #source: MediaElementAudioSourceNode | null = null; + + ids = createIds(); + + constructor(props: VideoProps = {}) { + this.#props = props; + + this.src = extract(props.src, ""); + this.poster = extract(props.poster, ""); + this.loop = extract(props.loop, false); + this.autoplay = extract(props.autoplay, false); + this.preload = extract(props.preload, "metadata"); + this.playbackRate = extract(props.playbackRate, 1); + this.keyboardControls = extract(props.keyboardControls, true); + this.volumeStep = extract(props.volumeStep, 0.05); + this.seekStep = extract(props.seekStep, 10); + + this.#currentTime = new Synced({ + value: props.currentTime, + onChange: props.onCurrentTimeChange, + defaultValue: 0, + }); + + this.#volume = new Synced({ + value: props.volume, + onChange: props.onVolumeChange, + defaultValue: 1, + }); + + this.#muted = typeof props.muted === "function" ? props.muted() ?? false : props.muted ?? false; + + this.#playing = new Synced({ + value: undefined, + onChange: props.onPlayingChange, + defaultValue: false, + }); + + this.#initWebAudio(); + } + /** + * The current playback time in seconds. + */ + get currentTime() { + return this.#currentTime.current; + } + + /** + * The current volume level (0-1). + */ + get volume() { + return this.#volume.current; + } + + /** + * Whether the video is currently muted. + */ + get muted() { + return this.#muted; + } + + /** + * Whether the video is currently playing. + */ + get playing() { + return this.#playing.current; + } + + /** + * The total duration of the video in seconds. + */ + get duration() { + return this.#duration; + } + + /** + * The amount of video buffered as a percentage (0-1). + */ + get buffered() { + return this.#buffered; + } + + /** + * Whether the video is currently loading. + */ + get loading() { + return this.#loading; + } + + /** + * The current error message, if any. + */ + get error() { + return this.#error; + } + + /** + * Whether the video is currently in fullscreen mode. + */ + get fullscreen() { + return this.#fullscreen; + } + + /** + * Whether the video is currently seeking. + */ + get seeking() { + return this.#seeking; + } + + /** + * The current keyboard feedback message being displayed. + */ + get keyboardFeedback() { + return this.#keyboardFeedback; + } + + get progress() { + return this.#duration > 0 ? (this.currentTime / this.#duration) * 100 : 0; + } + + get bufferedProgress() { + return this.#duration > 0 ? (this.#buffered / this.#duration) * 100 : 0; + } + + // Setters + set currentTime(time: number) { + this.#currentTime.current = Math.max(0, Math.min(time, this.#duration)); + this.#syncVideoElement(); + } + + set volume(volume: number) { + // Round to avoid floating point precision issues + const roundedVolume = Math.round(Math.max(0, Math.min(volume, 1)) * 100) / 100; + this.#volume.current = roundedVolume; + this.#setVolume(roundedVolume); + } + + set muted(muted: boolean) { + this.#muted = muted; + this.#setMute(muted); + this.#props.onMutedChange?.(muted); + } + + /** + * Starts playing the video. + */ + play() { + this.#playing.current = true; + // Resume audio context if suspended + if (this.#audioContext && this.#audioContext.state === "suspended") { + this.#audioContext.resume(); + } + this.#getVideoElement()?.play(); + } + + /** + * Pauses the video. + */ + pause() { + this.#playing.current = false; + this.#getVideoElement()?.pause(); + } + + /** + * Toggles between play and pause. + */ + togglePlay() { + if (this.#playing.current) { + this.pause(); + } else { + this.play(); + } + } + + /** + * Seeks to a specific time in seconds. + */ + seek(time: number) { + this.currentTime = time; + } + + /** + * Seeks forward or backward by the specified number of seconds. + */ + seekBy(seconds: number) { + this.seek(this.currentTime + seconds); + } + + /** + * Sets the volume level (0-1). + */ + setVolume(volume: number) { + this.volume = volume; + } + + /** + * Toggles the mute state. + * @param showFeedback - Whether to show keyboard feedback + */ + toggleMute(showFeedback = false) { + this.muted = !this.muted; + if (showFeedback) { + this.#showKeyboardFeedback(this.#muted ? "Muted" : "Unmuted"); + } + } + + /** + * Sets the playback rate (1.0 = normal speed). + */ + setPlaybackRate(rate: number) { + const video = this.#getVideoElement(); + if (video) { + video.playbackRate = rate; + this.#props.onPlaybackRateChange?.(rate); + } + } + + /** + * Enters fullscreen mode. + */ + enterFullscreen() { + const element = document.getElementById(this.ids.root); + if (element?.requestFullscreen) { + element.requestFullscreen(); + } + } + + /** + * Exits fullscreen mode. + */ + exitFullscreen() { + if (document.exitFullscreen) { + document.exitFullscreen(); + } + } + + /** + * Toggles fullscreen mode. + */ + toggleFullscreen() { + if (this.#fullscreen) { + this.exitFullscreen(); + } else { + this.enterFullscreen(); + } + } + + /** + * Refreshes the video duration from the video element. + */ + refreshDuration() { + const video = this.#getVideoElement(); + if (video && video.duration && !isNaN(video.duration) && video.duration !== Infinity) { + this.#duration = video.duration; + } + } + + #initWebAudio() { + if (this.#audioContext) return; + try { + this.#audioContext = new (window.AudioContext || (window as any).webkitAudioContext)(); + this.#gainNode = this.#audioContext.createGain(); + const initialGain = this.#muted ? 0 : this.volume; + this.#gainNode.gain.value = initialGain; + this.#gainNode.connect(this.#audioContext.destination); + + const video = this.#getVideoElement(); + if (video) { + this.#connectVideoSource(video); + } + } catch { + console.warn("Web Audio API not supported, falling back to video.volume"); + this.#audioContext = null; + } + } + + #connectVideoSource(video: HTMLVideoElement) { + if (!this.#audioContext || !this.#gainNode || this.#source) return; + + try { + this.#source = this.#audioContext.createMediaElementSource(video); + this.#source.connect(this.#gainNode); + video.volume = 1; + video.muted = false; + } catch { + console.warn("Failed to connect video source to Web Audio API"); + } + } + + #setVolume(volume: number) { + if (this.#gainNode) { + const targetVolume = this.#muted ? 0 : volume; + const currentTime = this.#audioContext!.currentTime; + this.#gainNode.gain.cancelScheduledValues(currentTime); + this.#gainNode.gain.setValueAtTime(this.#gainNode.gain.value, currentTime); + this.#gainNode.gain.linearRampToValueAtTime(targetVolume, currentTime + 0.01); + } + } + + #setMute(muted: boolean) { + const video = this.#getVideoElement(); + if (!video) return; + + if (this.#gainNode) { + const targetVolume = muted ? 0 : this.volume; + const currentTime = this.#audioContext!.currentTime; + this.#gainNode.gain.cancelScheduledValues(currentTime); + this.#gainNode.gain.setValueAtTime(targetVolume, currentTime); + } else { + video.muted = muted; + } + } + + #showKeyboardFeedback(message: string) { + this.#keyboardFeedback = message; + clearTimeout(this.#keyboardFeedbackTimeout); + this.#keyboardFeedbackTimeout = setTimeout(() => { + this.#keyboardFeedback = null; + }, 1000); + } + + /** + * Formats time in seconds to MM:SS format. + */ + formatTime(seconds: number): string { + // Handle invalid values + if (!seconds || isNaN(seconds) || seconds === Infinity || seconds < 0) { + return "0:00"; + } + + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + const secs = Math.floor(seconds % 60); + + if (hours > 0) { + return `${hours}:${minutes.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`; + } + return `${minutes}:${secs.toString().padStart(2, "0")}`; + } + + #getVideoElement(): HTMLVideoElement | null { + const element = document.getElementById(this.ids.video); + return element instanceof HTMLVideoElement ? element : null; + } + + #syncVideoElement() { + const video = this.#getVideoElement(); + if (!video) return; + + // Always sync duration from the native video element + if ( + video.duration && + !isNaN(video.duration) && + video.duration !== Infinity && + video.duration !== this.#duration + ) { + this.#duration = video.duration; + } + + if (Math.abs(video.currentTime - this.currentTime) > 0.1) { + video.currentTime = this.currentTime; + } + // Don't sync volume/mute if using Web Audio API + if (!this.#gainNode) { + if (Math.abs(video.volume - this.volume) > 0.01) { + video.volume = this.volume; + } + if (video.muted !== this.muted) { + video.muted = this.muted; + } + } + } + + #updateBuffered() { + const video = this.#getVideoElement(); + if (!video || !video.buffered.length) return; + + const buffered = video.buffered; + let bufferedEnd = 0; + for (let i = 0; i < buffered.length; i++) { + if (buffered.start(i) <= video.currentTime && video.currentTime <= buffered.end(i)) { + bufferedEnd = buffered.end(i); + break; + } + } + this.#buffered = bufferedEnd; + } + + /** + * The spread attributes for the root video player container. + */ + get root() { + useEventListener( + () => document, + "fullscreenchange", + () => { + this.#fullscreen = document.fullscreenElement !== null; + }, + ); + + return { + [dataAttrs.root]: "", + id: this.ids.root, + tabindex: this.keyboardControls ? 0 : -1, + "data-playing": dataAttr(this.#playing.current), + "data-muted": dataAttr(this.#muted), + "data-fullscreen": dataAttr(this.#fullscreen), + "data-loading": dataAttr(this.#loading), + "data-seeking": dataAttr(this.#seeking), + "data-error": dataAttr(this.#error !== null), + role: "application", + "aria-label": "Video player", + onclick: (_e: MouseEvent) => { + // Focus the root element to enable keyboard controls + if (this.keyboardControls) { + const rootElement = document.getElementById(this.ids.root); + rootElement?.focus(); + } + }, + + onkeydown: this.keyboardControls + ? (e) => { + // Only handle keyboard events when the video player is focused + if (document.activeElement !== document.getElementById(this.ids.root)) { + return; + } + + switch (e.key) { + case " ": + e.preventDefault(); + e.stopPropagation(); + this.togglePlay(); + this.#showKeyboardFeedback(this.#playing.current ? "Playing" : "Paused"); + break; + case "k": + e.preventDefault(); + this.togglePlay(); + this.#showKeyboardFeedback(this.#playing.current ? "Playing" : "Paused"); + break; + case "ArrowLeft": + e.preventDefault(); + this.seekBy(-this.seekStep); + this.#showKeyboardFeedback(`-${this.seekStep}s`); + break; + case "ArrowRight": + e.preventDefault(); + this.seekBy(this.seekStep); + this.#showKeyboardFeedback(`+${this.seekStep}s`); + break; + case "ArrowUp": { + e.preventDefault(); + const newVolumeUp = + Math.round(Math.min(1, this.volume + this.volumeStep) * 100) / 100; + this.setVolume(newVolumeUp); + this.#showKeyboardFeedback(`Volume: ${Math.round(newVolumeUp * 100)}%`); + break; + } + case "ArrowDown": { + e.preventDefault(); + const newVolumeDown = + Math.round(Math.max(0, this.volume - this.volumeStep) * 100) / 100; + this.setVolume(newVolumeDown); + this.#showKeyboardFeedback(`Volume: ${Math.round(newVolumeDown * 100)}%`); + break; + } + case "m": + e.preventDefault(); + this.toggleMute(true); + break; + case "f": + e.preventDefault(); + this.toggleFullscreen(); + this.#showKeyboardFeedback(this.#fullscreen ? "Fullscreen" : "Exited Fullscreen"); + break; + case "Home": + e.preventDefault(); + this.seek(0); + this.#showKeyboardFeedback("Beginning"); + break; + case "End": + e.preventDefault(); + this.seek(this.#duration); + this.#showKeyboardFeedback("End"); + break; + case "j": + e.preventDefault(); + this.seekBy(-this.seekStep); + this.#showKeyboardFeedback(`-${this.seekStep}s`); + break; + case "l": + e.preventDefault(); + this.seekBy(this.seekStep); + this.#showKeyboardFeedback(`+${this.seekStep}s`); + break; + case "0": + case "1": + case "2": + case "3": + case "4": + case "5": + case "6": + case "7": + case "8": + case "9": { + e.preventDefault(); + { + const percent = parseInt(e.key) / 10; + this.seek(this.#duration * percent); + this.#showKeyboardFeedback(`${percent * 100}%`); + } + break; + } + } + } + : undefined, + } as const satisfies HTMLAttributes; + } + + /** + * The spread attributes for the video element. + */ + get video() { + return { + [dataAttrs.video]: "", + id: this.ids.video, + src: this.src, + poster: this.poster, + loop: this.loop, + autoplay: this.autoplay, + muted: this.muted, + preload: this.preload, + controls: false, + disablepictureinpicture: true, + onkeydown: (e) => { + e.preventDefault(); + e.stopPropagation(); + }, + onclick: (e) => { + // Focus the root element to enable keyboard controls + if (this.keyboardControls) { + const rootElement = document.getElementById(this.ids.root); + rootElement?.focus(); + } + + e.preventDefault(); + + // Clear any existing click timeout + if (this.#clickTimeout) { + clearTimeout(this.#clickTimeout); + } + + // Delay the click action to allow for potential double-click + this.#clickTimeout = setTimeout(() => { + this.togglePlay(); + }, 250); + }, + ondblclick: (e) => { + e.preventDefault(); + + // Cancel the pending single-click action + if (this.#clickTimeout) { + clearTimeout(this.#clickTimeout); + this.#clickTimeout = undefined; + } + + this.toggleFullscreen(); + }, + onloadedmetadata: (e) => { + const video = e.currentTarget; + if (video.duration && !isNaN(video.duration) && video.duration !== Infinity) { + this.#duration = video.duration; + } + this.#connectVideoSource(video); + this.#props.onLoadedMetadata?.(); + }, + ontimeupdate: (e) => { + if (this.#seeking) return; + const video = e.currentTarget; + this.#currentTime.current = video.currentTime; + if ( + video.duration && + !isNaN(video.duration) && + video.duration !== Infinity && + video.duration !== this.#duration + ) { + this.#duration = video.duration; + } + this.#updateBuffered(); + }, + onplay: () => { + this.#playing.current = true; + }, + onpause: () => { + this.#playing.current = false; + }, + onended: () => { + this.#playing.current = false; + this.#props.onEnded?.(); + }, + ondurationchange: (e) => { + const video = e.currentTarget; + if (video.duration && !isNaN(video.duration) && video.duration !== Infinity) { + this.#duration = video.duration; + } + }, + oncanplay: () => { + this.#loading = false; + this.#props.onCanPlay?.(); + }, + oncanplaythrough: (e) => { + const video = e.currentTarget; + if (video.duration && !isNaN(video.duration) && video.duration !== Infinity) { + this.#duration = video.duration; + } + }, + onwaiting: () => { + this.#loading = true; + }, + onerror: (e) => { + const video = e.currentTarget; + if (video instanceof HTMLVideoElement) { + this.#error = video.error?.message || "An error occurred"; + this.#props.onError?.(e); + } + }, + + onratechange: (e) => { + const video = e.currentTarget; + this.#props.onPlaybackRateChange?.(video.playbackRate); + }, + onseeking: () => { + this.#seeking = true; + }, + onseeked: () => { + this.#seeking = false; + }, + } as const satisfies HTMLVideoAttributes; + } + + /** + * The spread attributes for the controls container. + */ + get controls() { + return { + [dataAttrs.controls]: "", + role: "group", + "aria-label": "Video controls", + } as const; + } + + /** + * The spread attributes for the play/pause button. + */ + get playButton() { + return { + [dataAttrs.playButton]: "", + type: "button", + "aria-label": this.#playing.current ? "Pause" : "Play", + "data-state": this.#playing.current ? "playing" : "paused", + onclick: () => this.togglePlay(), + } as const; + } + + /** + * The spread attributes for the mute/unmute button. + */ + get muteButton() { + return { + [dataAttrs.muteButton]: "", + type: "button", + "aria-label": this.#muted ? "Unmute" : "Mute", + "data-state": this.#muted ? "muted" : "unmuted", + onclick: () => this.toggleMute(), + } as const; + } + + /** + * The spread attributes for the volume slider. + */ + get volumeSlider() { + return { + [dataAttrs.volumeSlider]: "", + type: "range", + min: "0", + max: "1", + step: "0.01", + value: this.#volume.current, + "aria-label": "Volume", + "aria-valuemin": 0, + "aria-valuemax": 1, + "aria-valuenow": this.#volume.current, + oninput: (e) => { + const target = e.currentTarget; + this.setVolume(parseFloat(target.value)); + }, + } as const satisfies HTMLInputAttributes; + } + + /** + * The spread attributes for the progress bar/scrubber. + */ + get progressBar() { + return { + [dataAttrs.progressBar]: "", + type: "range", + min: "0", + max: this.#duration.toString(), + step: "0.1", + value: this.currentTime, + "aria-label": "Seek", + "aria-valuemin": 0, + "aria-valuemax": this.#duration, + "aria-valuenow": this.currentTime, + "aria-valuetext": `${this.formatTime(this.currentTime)} of ${this.formatTime(this.#duration)}`, + style: styleAttr({ + "--progress": `${this.progress}%`, + "--buffered": `${this.bufferedProgress}%`, + }), + oninput: (e) => { + const target = e.currentTarget; + this.seek(parseFloat(target.value)); + }, + onmousedown: () => { + this.#seeking = true; + }, + onmouseup: () => { + this.#seeking = false; + }, + onkeydown: (e) => { + switch (e.key) { + case "ArrowLeft": + e.preventDefault(); + this.seekBy(-5); + break; + case "ArrowRight": + e.preventDefault(); + this.seekBy(5); + break; + case "Home": + e.preventDefault(); + this.seek(0); + break; + case "End": + e.preventDefault(); + this.seek(this.#duration); + break; + } + }, + } as const satisfies HTMLInputAttributes; + } + + /** + * The spread attributes for the time display. + */ + get timeDisplay() { + return { + [dataAttrs.timeDisplay]: "", + "aria-live": "polite", + "aria-label": `Current time: ${this.formatTime(this.currentTime)}`, + } as const; + } + + /** + * The spread attributes for the fullscreen button. + */ + get fullscreenButton() { + return { + [dataAttrs.fullscreenButton]: "", + type: "button", + "aria-label": this.#fullscreen ? "Exit fullscreen" : "Enter fullscreen", + "data-state": this.#fullscreen ? "fullscreen" : "windowed", + onclick: () => this.toggleFullscreen(), + } as const; + } +} diff --git a/packages/melt/src/lib/builders/index.ts b/packages/melt/src/lib/builders/index.ts index 6b182c96..fdabb7f5 100644 --- a/packages/melt/src/lib/builders/index.ts +++ b/packages/melt/src/lib/builders/index.ts @@ -14,4 +14,5 @@ export * from "./Toaster.svelte"; export * from "./Toggle.svelte"; export * from "./Tooltip.svelte"; export * from "./Tree.svelte"; +export * from "./Video.svelte"; export * from "./SpatialMenu.svelte"; diff --git a/packages/melt/src/lib/builders/tests/Video.spec.svelte.ts b/packages/melt/src/lib/builders/tests/Video.spec.svelte.ts new file mode 100644 index 00000000..6cb0d8f0 --- /dev/null +++ b/packages/melt/src/lib/builders/tests/Video.spec.svelte.ts @@ -0,0 +1,134 @@ +import { testWithEffect } from "$lib/utils/test.svelte"; +import { expect, expectTypeOf } from "vitest"; +import { Video } from "../Video.svelte"; + +testWithEffect("Should have valid types", () => { + const player = new Video(); + + // Test basic properties + expectTypeOf(player.currentTime).toMatchTypeOf(); + expectTypeOf(player.volume).toMatchTypeOf(); + expectTypeOf(player.muted).toMatchTypeOf(); + expectTypeOf(player.playing).toMatchTypeOf(); + expectTypeOf(player.duration).toMatchTypeOf(); + expectTypeOf(player.buffered).toMatchTypeOf(); + expectTypeOf(player.loading).toMatchTypeOf(); + expectTypeOf(player.fullscreen).toMatchTypeOf(); + expectTypeOf(player.seeking).toMatchTypeOf(); + expectTypeOf(player.progress).toMatchTypeOf(); + expectTypeOf(player.bufferedProgress).toMatchTypeOf(); + + // Test methods + expectTypeOf(player.play).toMatchTypeOf<() => void>(); + expectTypeOf(player.pause).toMatchTypeOf<() => void>(); + expectTypeOf(player.togglePlay).toMatchTypeOf<() => void>(); + expectTypeOf(player.seek).toMatchTypeOf<(time: number) => void>(); + expectTypeOf(player.seekBy).toMatchTypeOf<(seconds: number) => void>(); + expectTypeOf(player.setVolume).toMatchTypeOf<(volume: number) => void>(); + expectTypeOf(player.toggleMute).toMatchTypeOf<(showFeedback?: boolean) => void>(); + expectTypeOf(player.setPlaybackRate).toMatchTypeOf<(rate: number) => void>(); + expectTypeOf(player.enterFullscreen).toMatchTypeOf<() => void>(); + expectTypeOf(player.exitFullscreen).toMatchTypeOf<() => void>(); + expectTypeOf(player.toggleFullscreen).toMatchTypeOf<() => void>(); + expectTypeOf(player.formatTime).toMatchTypeOf<(seconds: number) => string>(); + + // Test element getters + expectTypeOf(player.root).toMatchTypeOf>(); + expectTypeOf(player.video).toMatchTypeOf>(); + expectTypeOf(player.controls).toMatchTypeOf>(); + expectTypeOf(player.playButton).toMatchTypeOf>(); + expectTypeOf(player.muteButton).toMatchTypeOf>(); + expectTypeOf(player.volumeSlider).toMatchTypeOf>(); + expectTypeOf(player.progressBar).toMatchTypeOf>(); + expectTypeOf(player.timeDisplay).toMatchTypeOf>(); + expectTypeOf(player.fullscreenButton).toMatchTypeOf>(); +}); + +testWithEffect("Should initialize with default values", () => { + const player = new Video(); + + expect(player.currentTime).toBe(0); + expect(player.volume).toBe(1); + expect(player.muted).toBe(false); + expect(player.playing).toBe(false); + expect(player.duration).toBe(0); + expect(player.buffered).toBe(0); + expect(player.loading).toBe(false); + expect(player.fullscreen).toBe(false); + expect(player.seeking).toBe(false); + expect(player.progress).toBe(0); + expect(player.bufferedProgress).toBe(0); +}); + +testWithEffect("Should accept custom props", () => { + const player = new Video({ + currentTime: () => 30, + volume: () => 0.5, + muted: () => true, + autoplay: () => true, + loop: () => true, + preload: () => "auto", + }); + + expect(player.currentTime).toBe(30); + expect(player.volume).toBe(0.5); + expect(player.muted).toBe(true); +}); + +testWithEffect("Should format time correctly", () => { + const player = new Video(); + + expect(player.formatTime(0)).toBe("0:00"); + expect(player.formatTime(30)).toBe("0:30"); + expect(player.formatTime(90)).toBe("1:30"); + expect(player.formatTime(3661)).toBe("1:01:01"); +}); + +testWithEffect("Should handle volume constraints", () => { + const player = new Video(); + + player.setVolume(-1); + expect(player.volume).toBe(0); + + player.setVolume(2); + expect(player.volume).toBe(1); + + player.setVolume(0.5); + expect(player.volume).toBe(0.5); +}); + +testWithEffect("Should handle custom keyboard control steps", () => { + const player = new Video({ + seekStep: () => 15, + volumeStep: () => 0.1, + }); + + expect(player.seekStep).toBe(15); + expect(player.volumeStep).toBe(0.1); +}); + +testWithEffect("Should default keyboard control values", () => { + const player = new Video(); + + expect(player.seekStep).toBe(10); + expect(player.volumeStep).toBe(0.05); + expect(player.keyboardControls).toBe(true); +}); + +testWithEffect("Should allow disabling keyboard controls", () => { + const player = new Video({ + keyboardControls: () => false, + }); + + expect(player.keyboardControls).toBe(false); +}); + +testWithEffect("Should handle keyboard feedback", () => { + const player = new Video(); + + // Initially no feedback + expect(player.keyboardFeedback).toBe(null); + + // Test that feedback is accessible (actual feedback display would need DOM testing) + expectTypeOf(player.keyboardFeedback).toMatchTypeOf(); +}); diff --git a/packages/melt/src/lib/components/Video.svelte b/packages/melt/src/lib/components/Video.svelte new file mode 100644 index 00000000..30ebaf6c --- /dev/null +++ b/packages/melt/src/lib/components/Video.svelte @@ -0,0 +1,41 @@ + + +{@render children(video)} diff --git a/packages/melt/src/lib/components/index.ts b/packages/melt/src/lib/components/index.ts index ac710c40..4f3769a2 100644 --- a/packages/melt/src/lib/components/index.ts +++ b/packages/melt/src/lib/components/index.ts @@ -12,5 +12,5 @@ export { default as Slider } from "./Slider.svelte"; export { default as Tabs } from "./Tabs.svelte"; export { default as Toggle } from "./Toggle.svelte"; export { default as Tooltip } from "./Tooltip.svelte"; - +export { default as Video } from "./Video.svelte"; export { default as SpatialMenu } from "./SpatialMenu.svelte";