@devalok/shilp-sutra 0.49.0 → 0.49.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/badge-group.js +41 -41
- package/dist/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/block-shell.js +1 -1
- package/dist/_chunks/chart-container.js +1 -1
- package/dist/_chunks/chat.js +6 -15
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/colors.js +2 -2
- package/dist/_chunks/document-preview.js +4 -4
- package/dist/_chunks/emoji-suggestion.js +5 -5
- package/dist/_chunks/emoji-suggestion.js.map +1 -1
- package/dist/_chunks/emoji.js +1 -1
- package/dist/_chunks/field-state.js +1 -1
- package/dist/_chunks/grid-lines.js +1 -1
- package/dist/_chunks/image-preview.js +7 -7
- package/dist/_chunks/keybinding.js +1 -1
- package/dist/_chunks/link-context.js +1 -1
- package/dist/_chunks/mention-suggestion.js +2 -2
- package/dist/_chunks/mention.js +1 -1
- package/dist/_chunks/motion-provider.js +1 -1
- package/dist/_chunks/normalize-icon.js +1 -1
- package/dist/_chunks/oauth-button.js +2 -2
- package/dist/_chunks/popover.js +17 -17
- package/dist/_chunks/primitives.js +1 -1
- package/dist/_chunks/shared.js +5 -5
- package/dist/_chunks/success.js +5 -8
- package/dist/_chunks/success.js.map +1 -1
- package/dist/_chunks/tiptap.js +11 -11
- package/dist/_chunks/tooltip.js +1 -1
- package/dist/_chunks/tree-view.js +2 -2
- package/dist/_chunks/use-calendar.js +1 -1
- package/dist/_chunks/use-controllable-open.js +1 -1
- package/dist/_chunks/vendor-client.js +1 -1
- package/dist/_chunks/vendor-utils.js +1 -1
- package/dist/ai/block-renderer.js +8 -11
- package/dist/ai/block-renderer.js.map +1 -1
- package/dist/ai/blocks/error.js +1 -1
- package/dist/ai/blocks/index.js +2 -2
- package/dist/ai/blocks/text.js +1 -1
- package/dist/ai/command-bar.d.ts.map +1 -1
- package/dist/ai/command-bar.js +8 -39
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/ai/conversation.js +4 -10
- package/dist/ai/conversation.js.map +1 -1
- package/dist/ai/devadoot-icon.d.ts.map +1 -1
- package/dist/ai/index.js +10 -41
- package/dist/ai/index.js.map +1 -1
- package/dist/composed/activity-feed.js +3 -3
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/avatar-group.js +3 -3
- package/dist/composed/avatar-group.js.map +1 -1
- package/dist/composed/bulk-action-bar.js +1 -1
- package/dist/composed/command-palette.js +6 -6
- package/dist/composed/content-card.js +1 -1
- package/dist/composed/date-picker/index.js +10 -10
- package/dist/composed/emoji-picker.js +4 -4
- package/dist/composed/empty-state.d.ts.map +1 -1
- package/dist/composed/empty-state.js +23 -33
- package/dist/composed/empty-state.js.map +1 -1
- package/dist/composed/extensions/emoji-node.js +1 -1
- package/dist/composed/extensions/emoji-suggestion.js +1 -1
- package/dist/composed/file-preview.js +14 -14
- package/dist/composed/filter-bar.js +1 -1
- package/dist/composed/multi-select-popover.js +3 -3
- package/dist/composed/priority-indicator.js +1 -1
- package/dist/composed/responsive-modal.js +21 -21
- package/dist/composed/rich-chat-input.js +445 -445
- package/dist/composed/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.js +28 -28
- package/dist/composed/schedule-view.js +1 -1
- package/dist/composed/schedule-view.js.map +1 -1
- package/dist/composed/status-badge.js +1 -1
- package/dist/motion/index.js +2 -2
- package/dist/shell/bottom-navbar.js +3 -3
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/index.js +2 -2
- package/dist/shell/link-context.js +2 -2
- package/dist/shell/notification-center.js +3 -3
- package/dist/shell/sidebar.js +2 -2
- package/dist/shell/top-bar.js +1 -1
- package/dist/ui/accordion.js +14 -14
- package/dist/ui/alert-dialog.js +31 -31
- package/dist/ui/alert.js +1 -1
- package/dist/ui/aspect-ratio.js +1 -1
- package/dist/ui/autocomplete.js +7 -7
- package/dist/ui/avatar.d.ts.map +1 -1
- package/dist/ui/avatar.js +52 -67
- package/dist/ui/avatar.js.map +1 -1
- package/dist/ui/badge-group.js +1 -1
- package/dist/ui/badge.d.ts +2 -0
- package/dist/ui/badge.d.ts.map +1 -1
- package/dist/ui/badge.js +1 -1
- package/dist/ui/banner.js +1 -1
- package/dist/ui/breadcrumb.js +1 -1
- package/dist/ui/button.js +9 -9
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.js +1 -1
- package/dist/ui/charts/area-chart.js +6 -6
- package/dist/ui/charts/bar-chart.js +6 -6
- package/dist/ui/charts/chart-container.js +1 -1
- package/dist/ui/charts/gauge-chart.js +2 -2
- package/dist/ui/charts/index.js +2 -2
- package/dist/ui/charts/line-chart.js +6 -6
- package/dist/ui/charts/pie-chart.js +5 -5
- package/dist/ui/charts/radar-chart.js +5 -5
- package/dist/ui/charts/sparkline.js +2 -2
- package/dist/ui/chat/index.js +2 -2
- package/dist/ui/checkbox.js +5 -5
- package/dist/ui/collapsible.js +4 -4
- package/dist/ui/color-input.js +4 -4
- package/dist/ui/combobox.js +8 -8
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/context-menu.js +41 -41
- package/dist/ui/dialog.js +25 -25
- package/dist/ui/dot.d.ts.map +1 -1
- package/dist/ui/dot.js +24 -32
- package/dist/ui/dot.js.map +1 -1
- package/dist/ui/dropdown-menu.js +51 -51
- package/dist/ui/hover-card.js +9 -9
- package/dist/ui/icon-button.js +1 -1
- package/dist/ui/index.js +6 -6
- package/dist/ui/input.js +2 -2
- package/dist/ui/label.js +1 -1
- package/dist/ui/lib/utils.js +4 -4
- package/dist/ui/link.js +1 -1
- package/dist/ui/menubar.js +53 -53
- package/dist/ui/navigation-menu.js +27 -27
- package/dist/ui/number-input.js +2 -2
- package/dist/ui/oauth-button/index.js +2 -2
- package/dist/ui/pagination.js +1 -1
- package/dist/ui/popover.js +2 -2
- package/dist/ui/progress.js +2 -2
- package/dist/ui/radio.js +2 -2
- package/dist/ui/segmented-control.js +1 -1
- package/dist/ui/select.js +35 -35
- package/dist/ui/separator.js +1 -1
- package/dist/ui/sheet.js +22 -22
- package/dist/ui/sidebar.js +2 -2
- package/dist/ui/skeleton.js +1 -1
- package/dist/ui/slider.js +8 -8
- package/dist/ui/slider.js.map +1 -1
- package/dist/ui/split-button.js +3 -3
- package/dist/ui/stat-card.d.ts +2 -0
- package/dist/ui/stat-card.d.ts.map +1 -1
- package/dist/ui/stat-card.js +94 -126
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/stat-flash.js +1 -1
- package/dist/ui/stepper.js +1 -1
- package/dist/ui/surface.js +2 -2
- package/dist/ui/switch.js +2 -2
- package/dist/ui/table-row-link.js +1 -1
- package/dist/ui/tabs.js +13 -13
- package/dist/ui/text.js +1 -1
- package/dist/ui/textarea.js +2 -2
- package/dist/ui/toggle-group.js +1 -1
- package/dist/ui/toggle.js +2 -2
- package/dist/ui/tooltip.js +16 -16
- package/dist/ui/tree-view/index.js +2 -2
- package/llms.txt +1 -1
- package/mcp-manifest.json +1 -1
- package/package.json +1 -1
- package/skill/SKILL.md +1 -1
- package/skill/references/components.md +1 -1
package/dist/ui/combobox.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.js","names":[],"sources":["../../src/ui/combobox.tsx"],"sourcesContent":["'use client'\n\nimport * as PopoverPrimitive from '@primitives/react-popover'\nimport { IconCheck, IconChevronDown, IconSearch, IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { Icon } from './icon'\nimport { IconProvider, type IconSize } from './icon-context'\nimport { type FieldState, resolveFieldState } from './lib/field-state'\nimport type { IconInput } from './lib/icon-input'\nimport { springs, tweens } from './lib/motion'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\n\n/** Border tint per validation state, applied to the trigger. */\nconst stateBorderClasses: Record<Exclude<FieldState, 'default'>, string> = {\n error: 'border-error-7',\n warning: 'border-warning-7',\n success: 'border-success-7',\n}\n\nexport const comboboxTriggerVariants = cva(\n [\n 'flex w-full items-center justify-between whitespace-nowrap rounded-control',\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 focus-visible:border-accent-7',\n 'disabled:cursor-not-allowed disabled:opacity-action-disabled',\n ],\n {\n variants: {\n size: {\n xs: 'h-ds-xs-plus text-ds-sm px-ds-02',\n sm: 'h-ds-sm text-ds-sm px-ds-03',\n md: 'h-ds-md text-ds-md px-ds-04',\n lg: 'h-ds-lg text-ds-md px-ds-05',\n },\n },\n defaultVariants: { size: 'md' },\n },\n)\n\nexport type ComboboxSize = NonNullable<VariantProps<typeof comboboxTriggerVariants>['size']>\n\n/** Maps combobox size to Icon component size for chevron / check icons */\nconst iconSizeMap: Record<NonNullable<ComboboxSize>, IconSize> = {\n xs: 'xs',\n sm: 'sm',\n md: 'sm',\n lg: 'md',\n}\n\n/** Maps combobox size to pill text + padding classes */\nconst pillSizeMap: Record<NonNullable<ComboboxSize>, string> = {\n xs: 'px-ds-02 py-0 text-ds-xs',\n sm: 'px-ds-02 py-0 text-ds-xs',\n md: 'px-ds-03 py-[1px] text-ds-sm',\n lg: 'px-ds-03 py-[2px] text-ds-sm',\n}\n\n/** Maps combobox size to overflow text classes */\nconst overflowTextMap: Record<NonNullable<ComboboxSize>, string> = {\n xs: 'text-ds-xs',\n sm: 'text-ds-xs',\n md: 'text-ds-sm',\n lg: 'text-ds-sm',\n}\n\n/**\n * Option shape for a Combobox dropdown item.\n * `value` must be unique across all options — it is the key used in selection state.\n */\nexport interface ComboboxOption {\n value: string\n label: string\n description?: string\n icon?: IconInput\n disabled?: boolean\n}\n\n/**\n * Props for Combobox — a searchable single or multi-select dropdown with built-in keyboard\n * navigation, pill overflow (\"+ N more\"), and an optional custom option renderer.\n *\n * **Single vs multi:** `multiple={false}` (default) — `value` is a `string` and `onValueChange`\n * receives a `string`. When `multiple={true}`, `value` is `string[]`, `onValueChange` receives\n * `string[]`, and selected items appear as dismissible pills in the trigger.\n *\n * The props form a **discriminated union** on `multiple` — TypeScript will narrow `value` and\n * `onValueChange` automatically, so no manual casts are needed.\n *\n * **Custom rendering:** Use `renderOption` to return custom JSX per option (e.g. avatars, badges).\n *\n * @example\n * // Single-select country picker:\n * <Combobox\n * options={[{ value: 'in', label: 'India' }, { value: 'us', label: 'United States' }]}\n * value={country}\n * onValueChange={(v) => setCountry(v)}\n * placeholder=\"Select country\"\n * />\n *\n * @example\n * // Multi-select tag picker with pill display:\n * <Combobox\n * multiple\n * options={tagOptions}\n * value={selectedTags}\n * onValueChange={(v) => setSelectedTags(v)}\n * placeholder=\"Select tags...\"\n * />\n *\n * @example\n * // Custom option renderer (user avatars in assignee picker):\n * <Combobox\n * options={users.map(u => ({ value: u.id, label: u.name }))}\n * value={assigneeId}\n * onValueChange={(v) => setAssigneeId(v)}\n * renderOption={(option, selected) => (\n * <span className=\"flex items-center gap-ds-03\">\n * <Avatar size=\"xs\"><AvatarFallback>{option.label[0]}</AvatarFallback></Avatar>\n * {option.label}\n * </span>\n * )}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\ninterface ComboboxBaseProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n /** Available options shown in the dropdown. */\n options: ComboboxOption[]\n /** Placeholder shown in the trigger when no value is selected. */\n placeholder?: string\n /** Placeholder for the search input inside the dropdown. */\n searchPlaceholder?: string\n /** Message shown when the search yields no results. */\n emptyMessage?: string\n disabled?: boolean\n triggerClassName?: string\n /** Max visible items in the dropdown before scroll (default 6). */\n maxVisible?: number\n /** Custom renderer for each option row. Receives the option and whether it's currently selected. */\n renderOption?: (option: ComboboxOption, selected: boolean) => React.ReactNode\n /** Accessible label for the trigger button. Falls back to `placeholder` if not provided. */\n accessibleLabel?: string\n /** Size of the trigger. Controls height, text size, padding, and pill sizing. */\n size?: ComboboxSize\n /** Validation/feedback state. `'error'` also sets `aria-invalid`. Inherited from `FormField` when omitted. */\n state?: FieldState\n}\n\ninterface ComboboxSingleProps extends ComboboxBaseProps {\n multiple?: false\n value?: string\n onValueChange: (value: string) => void\n}\n\ninterface ComboboxMultipleProps extends ComboboxBaseProps {\n multiple: true\n value?: string[]\n onValueChange: (value: string[]) => void\n}\n\nexport type ComboboxProps = ComboboxSingleProps | ComboboxMultipleProps\n\n/** Max pills shown in the trigger before \"+N more\" overflow */\nconst MAX_VISIBLE_PILLS = 2\n\n/** Approximate height of a single option item in px */\nconst ITEM_HEIGHT_PX = 36\n\nconst Combobox = React.forwardRef<HTMLButtonElement, ComboboxProps>(\n (\n {\n options,\n value,\n onValueChange,\n placeholder = 'Select...',\n searchPlaceholder = 'Search...',\n emptyMessage = 'No results found',\n multiple = false,\n disabled = false,\n className,\n triggerClassName,\n maxVisible = 6,\n renderOption,\n accessibleLabel,\n size: sizeProp = 'md',\n state: stateProp,\n ...rest\n },\n ref,\n ) => {\n const size = sizeProp ?? 'md'\n const [open, setOpen] = React.useState(false)\n const [search, setSearch] = React.useState('')\n const [highlightedIndex, setHighlightedIndex] = React.useState(-1)\n const searchInputRef = React.useRef<HTMLInputElement>(null)\n const listRef = React.useRef<HTMLUListElement>(null)\n const optionIdPrefix = React.useId()\n const listboxId = React.useId()\n\n const selectedValues = React.useMemo<string[]>(() => {\n if (value === undefined || value === null) return []\n if (Array.isArray(value)) return value\n return [value]\n }, [value])\n\n const filteredOptions = React.useMemo(\n () =>\n search\n ? options.filter((o) =>\n o.label.toLowerCase().includes(search.toLowerCase()),\n )\n : options,\n [options, search],\n )\n\n const isSelected = React.useCallback(\n (optionValue: string) => selectedValues.includes(optionValue),\n [selectedValues],\n )\n\n const handleSelect = React.useCallback(\n (optionValue: string) => {\n if (multiple) {\n const newValue = selectedValues.includes(optionValue)\n ? selectedValues.filter((v) => v !== optionValue)\n : [...selectedValues, optionValue]\n ;(onValueChange as (value: string[]) => void)(newValue)\n } else {\n ;(onValueChange as (value: string) => void)(optionValue)\n setOpen(false)\n }\n },\n [multiple, selectedValues, onValueChange],\n )\n\n const handleRemovePill = React.useCallback(\n (e: React.SyntheticEvent, optionValue: string) => {\n e.stopPropagation()\n e.preventDefault()\n const newValue = selectedValues.filter((v) => v !== optionValue)\n ;(onValueChange as (value: string[]) => void)(newValue)\n },\n [selectedValues, onValueChange],\n )\n\n const handleOpenChange = React.useCallback(\n (nextOpen: boolean) => {\n if (disabled) return\n setOpen(nextOpen)\n if (!nextOpen) {\n setSearch('')\n setHighlightedIndex(-1)\n }\n },\n [disabled],\n )\n\n // Auto-focus search input when popover opens\n React.useEffect(() => {\n if (open) {\n // Use a small timeout to allow the popover to render\n const timer = setTimeout(() => {\n searchInputRef.current?.focus()\n }, 0)\n return () => clearTimeout(timer)\n }\n }, [open])\n\n const findNextEnabledIndex = React.useCallback(\n (currentIndex: number, direction: 1 | -1): number => {\n const len = filteredOptions.length\n if (len === 0) return -1\n\n let nextIndex = currentIndex + direction\n while (nextIndex >= 0 && nextIndex < len) {\n if (!filteredOptions[nextIndex].disabled) return nextIndex\n nextIndex += direction\n }\n return currentIndex\n },\n [filteredOptions],\n )\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowDown': {\n e.preventDefault()\n const nextIdx = findNextEnabledIndex(highlightedIndex, 1)\n setHighlightedIndex(nextIdx)\n break\n }\n case 'ArrowUp': {\n e.preventDefault()\n const prevIdx = findNextEnabledIndex(highlightedIndex, -1)\n setHighlightedIndex(prevIdx)\n break\n }\n case 'Home': {\n e.preventDefault()\n const firstEnabled = filteredOptions.findIndex((o) => !o.disabled)\n setHighlightedIndex(firstEnabled)\n break\n }\n case 'End': {\n e.preventDefault()\n let lastEnabled = -1\n for (let i = filteredOptions.length - 1; i >= 0; i--) {\n if (!filteredOptions[i].disabled) {\n lastEnabled = i\n break\n }\n }\n setHighlightedIndex(lastEnabled)\n break\n }\n case 'Enter': {\n e.preventDefault()\n if (\n highlightedIndex >= 0 &&\n highlightedIndex < filteredOptions.length &&\n !filteredOptions[highlightedIndex].disabled\n ) {\n handleSelect(filteredOptions[highlightedIndex].value)\n }\n break\n }\n case 'Escape': {\n e.preventDefault()\n setOpen(false)\n setSearch('')\n setHighlightedIndex(-1)\n break\n }\n }\n },\n [highlightedIndex, filteredOptions, findNextEnabledIndex, handleSelect],\n )\n\n // Scroll highlighted option into view\n React.useEffect(() => {\n if (highlightedIndex >= 0 && listRef.current) {\n const optionEl = listRef.current.children[highlightedIndex] as HTMLElement\n if (optionEl) {\n optionEl.scrollIntoView?.({ block: 'nearest' })\n }\n }\n }, [highlightedIndex])\n\n const getSelectedLabel = React.useCallback(() => {\n if (selectedValues.length === 0) return null\n const option = options.find((o) => o.value === selectedValues[0])\n return option?.label ?? null\n }, [selectedValues, options])\n\n const resolvedIconSize = iconSizeMap[size]\n const resolvedPillClasses = pillSizeMap[size]\n const resolvedOverflowText = overflowTextMap[size]\n\n const renderTriggerContent = () => {\n if (multiple && selectedValues.length > 0) {\n const visiblePills = selectedValues.slice(0, MAX_VISIBLE_PILLS)\n const remaining = selectedValues.length - MAX_VISIBLE_PILLS\n\n return (\n <span className=\"flex flex-1 flex-wrap items-center gap-ds-02 overflow-hidden\">\n {visiblePills.map((val) => {\n const option = options.find((o) => o.value === val)\n if (!option) return null\n return (\n <span\n key={val}\n className={cn('inline-flex items-center gap-ds-01 rounded-control-inner bg-accent-2', resolvedPillClasses)}\n >\n {option.label}\n <button\n type=\"button\"\n className=\"inline-flex items-center justify-center rounded-pill outline-hidden hover:scale-110 hover:bg-surface-raised-hover transition-transform duration-fast-01 ease-productive-standard\"\n onClick={(e) => handleRemovePill(e, val)}\n aria-label={`Remove ${option.label}`}\n tabIndex={-1}\n >\n <Icon icon={IconX} size={resolvedIconSize} />\n </button>\n </span>\n )\n })}\n {remaining > 0 && (\n <span className={cn('text-surface-fg-muted', resolvedOverflowText)}>\n +{remaining} more\n </span>\n )}\n </span>\n )\n }\n\n if (!multiple && selectedValues.length === 1) {\n const label = getSelectedLabel()\n if (label) {\n return <span className=\"min-w-0 flex-1 truncate text-left\">{label}</span>\n }\n }\n\n return (\n <span className=\"min-w-0 flex-1 truncate text-left text-surface-fg-subtle\">\n {placeholder}\n </span>\n )\n }\n\n const fieldCtx = useFormField()\n const state = resolveFieldState(stateProp, fieldCtx.state)\n const isError = state === 'error'\n const ariaDescribedBy = fieldCtx.helperTextId\n const ariaRequired = fieldCtx.required\n\n return (\n <PopoverPrimitive.Root open={open} onOpenChange={handleOpenChange}>\n <div className={cn('relative', className)} {...rest}>\n <PopoverPrimitive.Trigger asChild disabled={disabled}>\n <button\n ref={ref}\n type=\"button\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={listboxId}\n aria-haspopup=\"listbox\"\n aria-label={accessibleLabel ?? placeholder}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n disabled={disabled}\n className={cn(\n comboboxTriggerVariants({ size }),\n open && 'border-accent-7',\n state && stateBorderClasses[state],\n triggerClassName,\n )}\n >\n {renderTriggerContent()}\n <Icon icon={IconChevronDown} size={resolvedIconSize} className={cn(\"ml-ds-02 shrink-0 opacity-50 transition-transform duration-fast-01 ease-productive-standard\", open && 'rotate-180')} />\n </button>\n </PopoverPrimitive.Trigger>\n\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n asChild\n sideOffset={4}\n align=\"start\"\n onOpenAutoFocus={(e) => {\n e.preventDefault()\n searchInputRef.current?.focus()\n }}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n 'z-popover w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-overlay bg-surface-overlay shadow-floating',\n )}\n >\n {/* Search input */}\n <div className=\"flex items-center gap-ds-02 border-b border-surface-border px-ds-04\">\n <Icon icon={IconSearch} size=\"sm\" className=\"shrink-0 text-surface-fg-subtle\" />\n <input\n ref={searchInputRef}\n type=\"text\"\n className=\"flex-1 bg-transparent py-ds-03 text-ds-md outline-hidden placeholder:text-surface-fg-subtle\"\n placeholder={searchPlaceholder}\n value={search}\n onChange={(e) => {\n setSearch(e.target.value)\n setHighlightedIndex(-1)\n }}\n onKeyDown={handleKeyDown}\n aria-autocomplete=\"list\"\n aria-controls={listboxId}\n aria-activedescendant={\n highlightedIndex >= 0\n ? `${optionIdPrefix}-option-${highlightedIndex}`\n : undefined\n }\n aria-label=\"Search options\"\n />\n </div>\n\n {/* Options list */}\n {filteredOptions.length === 0 ? (\n <div className=\"px-ds-04 py-ds-05 text-center text-ds-md text-surface-fg-subtle\">\n {emptyMessage}\n </div>\n ) : (\n <ul\n ref={listRef}\n id={listboxId}\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n className=\"overflow-auto p-ds-02\"\n style={{ maxHeight: `${maxVisible * ITEM_HEIGHT_PX}px` }}\n >\n {filteredOptions.map((option, index) => {\n const selected = isSelected(option.value)\n return (\n <li\n key={option.value}\n id={`${optionIdPrefix}-option-${index}`}\n role=\"option\"\n aria-selected={selected}\n aria-disabled={option.disabled || undefined}\n className={cn(\n 'relative flex cursor-pointer select-none items-center gap-ds-03 rounded-control px-ds-04 py-ds-03 text-ds-md outline-hidden',\n 'transition-colors duration-fast-01 ease-productive-standard',\n highlightedIndex === index &&\n 'bg-accent-2',\n selected && 'text-accent-11',\n option.disabled &&\n 'pointer-events-none opacity-action-disabled',\n )}\n onClick={() => {\n if (!option.disabled) {\n handleSelect(option.value)\n }\n }}\n onKeyDown={(e) => {\n if (!option.disabled && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault()\n handleSelect(option.value)\n }\n }}\n onMouseEnter={() => {\n if (!option.disabled) {\n setHighlightedIndex(index)\n }\n }}\n >\n {option.icon && (\n <span className=\"flex h-ico-sm w-ico-sm items-center justify-center shrink-0\">\n <IconProvider size={resolvedIconSize}>\n {normalizeIcon(option.icon)}\n </IconProvider>\n </span>\n )}\n <span className=\"flex flex-1 flex-col\">\n {renderOption ? (\n renderOption(option, selected)\n ) : (\n <>\n <span>{option.label}</span>\n {option.description && (\n <span className=\"text-ds-sm text-surface-fg-muted\">\n {option.description}\n </span>\n )}\n </>\n )}\n </span>\n {selected && (\n <Icon icon={IconCheck} size=\"sm\" className=\"shrink-0\" />\n )}\n </li>\n )\n })}\n </ul>\n )}\n </motion.div>\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </div>\n </PopoverPrimitive.Root>\n )\n },\n)\nCombobox.displayName = 'Combobox'\n\nexport { Combobox }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"combobox.js","names":[],"sources":["../../src/ui/combobox.tsx"],"sourcesContent":["'use client'\n\nimport * as PopoverPrimitive from '@primitives/react-popover'\nimport { IconCheck, IconChevronDown, IconSearch, IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { Icon } from './icon'\nimport { IconProvider, type IconSize } from './icon-context'\nimport { type FieldState, resolveFieldState } from './lib/field-state'\nimport type { IconInput } from './lib/icon-input'\nimport { springs, tweens } from './lib/motion'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\n\n/** Border tint per validation state, applied to the trigger. */\nconst stateBorderClasses: Record<Exclude<FieldState, 'default'>, string> = {\n error: 'border-error-7',\n warning: 'border-warning-7',\n success: 'border-success-7',\n}\n\nexport const comboboxTriggerVariants = cva(\n [\n 'flex w-full items-center justify-between whitespace-nowrap rounded-control',\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 focus-visible:border-accent-7',\n 'disabled:cursor-not-allowed disabled:opacity-action-disabled',\n ],\n {\n variants: {\n size: {\n xs: 'h-ds-xs-plus text-ds-sm px-ds-02',\n sm: 'h-ds-sm text-ds-sm px-ds-03',\n md: 'h-ds-md text-ds-md px-ds-04',\n lg: 'h-ds-lg text-ds-md px-ds-05',\n },\n },\n defaultVariants: { size: 'md' },\n },\n)\n\nexport type ComboboxSize = NonNullable<VariantProps<typeof comboboxTriggerVariants>['size']>\n\n/** Maps combobox size to Icon component size for chevron / check icons */\nconst iconSizeMap: Record<NonNullable<ComboboxSize>, IconSize> = {\n xs: 'xs',\n sm: 'sm',\n md: 'sm',\n lg: 'md',\n}\n\n/** Maps combobox size to pill text + padding classes */\nconst pillSizeMap: Record<NonNullable<ComboboxSize>, string> = {\n xs: 'px-ds-02 py-0 text-ds-xs',\n sm: 'px-ds-02 py-0 text-ds-xs',\n md: 'px-ds-03 py-[1px] text-ds-sm',\n lg: 'px-ds-03 py-[2px] text-ds-sm',\n}\n\n/** Maps combobox size to overflow text classes */\nconst overflowTextMap: Record<NonNullable<ComboboxSize>, string> = {\n xs: 'text-ds-xs',\n sm: 'text-ds-xs',\n md: 'text-ds-sm',\n lg: 'text-ds-sm',\n}\n\n/**\n * Option shape for a Combobox dropdown item.\n * `value` must be unique across all options — it is the key used in selection state.\n */\nexport interface ComboboxOption {\n value: string\n label: string\n description?: string\n icon?: IconInput\n disabled?: boolean\n}\n\n/**\n * Props for Combobox — a searchable single or multi-select dropdown with built-in keyboard\n * navigation, pill overflow (\"+ N more\"), and an optional custom option renderer.\n *\n * **Single vs multi:** `multiple={false}` (default) — `value` is a `string` and `onValueChange`\n * receives a `string`. When `multiple={true}`, `value` is `string[]`, `onValueChange` receives\n * `string[]`, and selected items appear as dismissible pills in the trigger.\n *\n * The props form a **discriminated union** on `multiple` — TypeScript will narrow `value` and\n * `onValueChange` automatically, so no manual casts are needed.\n *\n * **Custom rendering:** Use `renderOption` to return custom JSX per option (e.g. avatars, badges).\n *\n * @example\n * // Single-select country picker:\n * <Combobox\n * options={[{ value: 'in', label: 'India' }, { value: 'us', label: 'United States' }]}\n * value={country}\n * onValueChange={(v) => setCountry(v)}\n * placeholder=\"Select country\"\n * />\n *\n * @example\n * // Multi-select tag picker with pill display:\n * <Combobox\n * multiple\n * options={tagOptions}\n * value={selectedTags}\n * onValueChange={(v) => setSelectedTags(v)}\n * placeholder=\"Select tags...\"\n * />\n *\n * @example\n * // Custom option renderer (user avatars in assignee picker):\n * <Combobox\n * options={users.map(u => ({ value: u.id, label: u.name }))}\n * value={assigneeId}\n * onValueChange={(v) => setAssigneeId(v)}\n * renderOption={(option, selected) => (\n * <span className=\"flex items-center gap-ds-03\">\n * <Avatar size=\"xs\"><AvatarFallback>{option.label[0]}</AvatarFallback></Avatar>\n * {option.label}\n * </span>\n * )}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\ninterface ComboboxBaseProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n /** Available options shown in the dropdown. */\n options: ComboboxOption[]\n /** Placeholder shown in the trigger when no value is selected. */\n placeholder?: string\n /** Placeholder for the search input inside the dropdown. */\n searchPlaceholder?: string\n /** Message shown when the search yields no results. */\n emptyMessage?: string\n disabled?: boolean\n triggerClassName?: string\n /** Max visible items in the dropdown before scroll (default 6). */\n maxVisible?: number\n /** Custom renderer for each option row. Receives the option and whether it's currently selected. */\n renderOption?: (option: ComboboxOption, selected: boolean) => React.ReactNode\n /** Accessible label for the trigger button. Falls back to `placeholder` if not provided. */\n accessibleLabel?: string\n /** Size of the trigger. Controls height, text size, padding, and pill sizing. */\n size?: ComboboxSize\n /** Validation/feedback state. `'error'` also sets `aria-invalid`. Inherited from `FormField` when omitted. */\n state?: FieldState\n}\n\ninterface ComboboxSingleProps extends ComboboxBaseProps {\n multiple?: false\n value?: string\n onValueChange: (value: string) => void\n}\n\ninterface ComboboxMultipleProps extends ComboboxBaseProps {\n multiple: true\n value?: string[]\n onValueChange: (value: string[]) => void\n}\n\nexport type ComboboxProps = ComboboxSingleProps | ComboboxMultipleProps\n\n/** Max pills shown in the trigger before \"+N more\" overflow */\nconst MAX_VISIBLE_PILLS = 2\n\n/** Approximate height of a single option item in px */\nconst ITEM_HEIGHT_PX = 36\n\nconst Combobox = React.forwardRef<HTMLButtonElement, ComboboxProps>(\n (\n {\n options,\n value,\n onValueChange,\n placeholder = 'Select...',\n searchPlaceholder = 'Search...',\n emptyMessage = 'No results found',\n multiple = false,\n disabled = false,\n className,\n triggerClassName,\n maxVisible = 6,\n renderOption,\n accessibleLabel,\n size: sizeProp = 'md',\n state: stateProp,\n ...rest\n },\n ref,\n ) => {\n const size = sizeProp ?? 'md'\n const [open, setOpen] = React.useState(false)\n const [search, setSearch] = React.useState('')\n const [highlightedIndex, setHighlightedIndex] = React.useState(-1)\n const searchInputRef = React.useRef<HTMLInputElement>(null)\n const listRef = React.useRef<HTMLUListElement>(null)\n const optionIdPrefix = React.useId()\n const listboxId = React.useId()\n\n const selectedValues = React.useMemo<string[]>(() => {\n if (value === undefined || value === null) return []\n if (Array.isArray(value)) return value\n return [value]\n }, [value])\n\n const filteredOptions = React.useMemo(\n () =>\n search\n ? options.filter((o) =>\n o.label.toLowerCase().includes(search.toLowerCase()),\n )\n : options,\n [options, search],\n )\n\n const isSelected = React.useCallback(\n (optionValue: string) => selectedValues.includes(optionValue),\n [selectedValues],\n )\n\n const handleSelect = React.useCallback(\n (optionValue: string) => {\n if (multiple) {\n const newValue = selectedValues.includes(optionValue)\n ? selectedValues.filter((v) => v !== optionValue)\n : [...selectedValues, optionValue]\n ;(onValueChange as (value: string[]) => void)(newValue)\n } else {\n ;(onValueChange as (value: string) => void)(optionValue)\n setOpen(false)\n }\n },\n [multiple, selectedValues, onValueChange],\n )\n\n const handleRemovePill = React.useCallback(\n (e: React.SyntheticEvent, optionValue: string) => {\n e.stopPropagation()\n e.preventDefault()\n const newValue = selectedValues.filter((v) => v !== optionValue)\n ;(onValueChange as (value: string[]) => void)(newValue)\n },\n [selectedValues, onValueChange],\n )\n\n const handleOpenChange = React.useCallback(\n (nextOpen: boolean) => {\n if (disabled) return\n setOpen(nextOpen)\n if (!nextOpen) {\n setSearch('')\n setHighlightedIndex(-1)\n }\n },\n [disabled],\n )\n\n // Auto-focus search input when popover opens\n React.useEffect(() => {\n if (open) {\n // Use a small timeout to allow the popover to render\n const timer = setTimeout(() => {\n searchInputRef.current?.focus()\n }, 0)\n return () => clearTimeout(timer)\n }\n }, [open])\n\n const findNextEnabledIndex = React.useCallback(\n (currentIndex: number, direction: 1 | -1): number => {\n const len = filteredOptions.length\n if (len === 0) return -1\n\n let nextIndex = currentIndex + direction\n while (nextIndex >= 0 && nextIndex < len) {\n if (!filteredOptions[nextIndex].disabled) return nextIndex\n nextIndex += direction\n }\n return currentIndex\n },\n [filteredOptions],\n )\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowDown': {\n e.preventDefault()\n const nextIdx = findNextEnabledIndex(highlightedIndex, 1)\n setHighlightedIndex(nextIdx)\n break\n }\n case 'ArrowUp': {\n e.preventDefault()\n const prevIdx = findNextEnabledIndex(highlightedIndex, -1)\n setHighlightedIndex(prevIdx)\n break\n }\n case 'Home': {\n e.preventDefault()\n const firstEnabled = filteredOptions.findIndex((o) => !o.disabled)\n setHighlightedIndex(firstEnabled)\n break\n }\n case 'End': {\n e.preventDefault()\n let lastEnabled = -1\n for (let i = filteredOptions.length - 1; i >= 0; i--) {\n if (!filteredOptions[i].disabled) {\n lastEnabled = i\n break\n }\n }\n setHighlightedIndex(lastEnabled)\n break\n }\n case 'Enter': {\n e.preventDefault()\n if (\n highlightedIndex >= 0 &&\n highlightedIndex < filteredOptions.length &&\n !filteredOptions[highlightedIndex].disabled\n ) {\n handleSelect(filteredOptions[highlightedIndex].value)\n }\n break\n }\n case 'Escape': {\n e.preventDefault()\n setOpen(false)\n setSearch('')\n setHighlightedIndex(-1)\n break\n }\n }\n },\n [highlightedIndex, filteredOptions, findNextEnabledIndex, handleSelect],\n )\n\n // Scroll highlighted option into view\n React.useEffect(() => {\n if (highlightedIndex >= 0 && listRef.current) {\n const optionEl = listRef.current.children[highlightedIndex] as HTMLElement\n if (optionEl) {\n optionEl.scrollIntoView?.({ block: 'nearest' })\n }\n }\n }, [highlightedIndex])\n\n const getSelectedLabel = React.useCallback(() => {\n if (selectedValues.length === 0) return null\n const option = options.find((o) => o.value === selectedValues[0])\n return option?.label ?? null\n }, [selectedValues, options])\n\n const resolvedIconSize = iconSizeMap[size]\n const resolvedPillClasses = pillSizeMap[size]\n const resolvedOverflowText = overflowTextMap[size]\n\n const renderTriggerContent = () => {\n if (multiple && selectedValues.length > 0) {\n const visiblePills = selectedValues.slice(0, MAX_VISIBLE_PILLS)\n const remaining = selectedValues.length - MAX_VISIBLE_PILLS\n\n return (\n <span className=\"flex flex-1 flex-wrap items-center gap-ds-02 overflow-hidden\">\n {visiblePills.map((val) => {\n const option = options.find((o) => o.value === val)\n if (!option) return null\n return (\n <span\n key={val}\n className={cn('inline-flex items-center gap-ds-01 rounded-control-inner bg-accent-2', resolvedPillClasses)}\n >\n {option.label}\n <button\n type=\"button\"\n className=\"inline-flex items-center justify-center rounded-pill outline-hidden hover:bg-surface-raised-hover transition-colors duration-fast-01 ease-productive-standard\"\n onClick={(e) => handleRemovePill(e, val)}\n aria-label={`Remove ${option.label}`}\n tabIndex={-1}\n >\n <Icon icon={IconX} size={resolvedIconSize} />\n </button>\n </span>\n )\n })}\n {remaining > 0 && (\n <span className={cn('text-surface-fg-muted', resolvedOverflowText)}>\n +{remaining} more\n </span>\n )}\n </span>\n )\n }\n\n if (!multiple && selectedValues.length === 1) {\n const label = getSelectedLabel()\n if (label) {\n return <span className=\"min-w-0 flex-1 truncate text-left\">{label}</span>\n }\n }\n\n return (\n <span className=\"min-w-0 flex-1 truncate text-left text-surface-fg-subtle\">\n {placeholder}\n </span>\n )\n }\n\n const fieldCtx = useFormField()\n const state = resolveFieldState(stateProp, fieldCtx.state)\n const isError = state === 'error'\n const ariaDescribedBy = fieldCtx.helperTextId\n const ariaRequired = fieldCtx.required\n\n return (\n <PopoverPrimitive.Root open={open} onOpenChange={handleOpenChange}>\n <div className={cn('relative', className)} {...rest}>\n <PopoverPrimitive.Trigger asChild disabled={disabled}>\n <button\n ref={ref}\n type=\"button\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={listboxId}\n aria-haspopup=\"listbox\"\n aria-label={accessibleLabel ?? placeholder}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n disabled={disabled}\n className={cn(\n comboboxTriggerVariants({ size }),\n open && 'border-accent-7',\n state && stateBorderClasses[state],\n triggerClassName,\n )}\n >\n {renderTriggerContent()}\n <Icon icon={IconChevronDown} size={resolvedIconSize} className={cn(\"ml-ds-02 shrink-0 opacity-50 transition-transform duration-fast-01 ease-productive-standard\", open && 'rotate-180')} />\n </button>\n </PopoverPrimitive.Trigger>\n\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n asChild\n sideOffset={4}\n align=\"start\"\n onOpenAutoFocus={(e) => {\n e.preventDefault()\n searchInputRef.current?.focus()\n }}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n 'z-popover w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-overlay bg-surface-overlay shadow-floating',\n )}\n >\n {/* Search input */}\n <div className=\"flex items-center gap-ds-02 border-b border-surface-border px-ds-04\">\n <Icon icon={IconSearch} size=\"sm\" className=\"shrink-0 text-surface-fg-subtle\" />\n <input\n ref={searchInputRef}\n type=\"text\"\n className=\"flex-1 bg-transparent py-ds-03 text-ds-md outline-hidden placeholder:text-surface-fg-subtle\"\n placeholder={searchPlaceholder}\n value={search}\n onChange={(e) => {\n setSearch(e.target.value)\n setHighlightedIndex(-1)\n }}\n onKeyDown={handleKeyDown}\n aria-autocomplete=\"list\"\n aria-controls={listboxId}\n aria-activedescendant={\n highlightedIndex >= 0\n ? `${optionIdPrefix}-option-${highlightedIndex}`\n : undefined\n }\n aria-label=\"Search options\"\n />\n </div>\n\n {/* Options list */}\n {filteredOptions.length === 0 ? (\n <div className=\"px-ds-04 py-ds-05 text-center text-ds-md text-surface-fg-subtle\">\n {emptyMessage}\n </div>\n ) : (\n <ul\n ref={listRef}\n id={listboxId}\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n className=\"overflow-auto p-ds-02\"\n style={{ maxHeight: `${maxVisible * ITEM_HEIGHT_PX}px` }}\n >\n {filteredOptions.map((option, index) => {\n const selected = isSelected(option.value)\n return (\n <li\n key={option.value}\n id={`${optionIdPrefix}-option-${index}`}\n role=\"option\"\n aria-selected={selected}\n aria-disabled={option.disabled || undefined}\n className={cn(\n 'relative flex cursor-pointer select-none items-center gap-ds-03 rounded-control px-ds-04 py-ds-03 text-ds-md outline-hidden',\n 'transition-colors duration-fast-01 ease-productive-standard',\n highlightedIndex === index &&\n 'bg-accent-2',\n selected && 'text-accent-11',\n option.disabled &&\n 'pointer-events-none opacity-action-disabled',\n )}\n onClick={() => {\n if (!option.disabled) {\n handleSelect(option.value)\n }\n }}\n onKeyDown={(e) => {\n if (!option.disabled && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault()\n handleSelect(option.value)\n }\n }}\n onMouseEnter={() => {\n if (!option.disabled) {\n setHighlightedIndex(index)\n }\n }}\n >\n {option.icon && (\n <span className=\"flex h-ico-sm w-ico-sm items-center justify-center shrink-0\">\n <IconProvider size={resolvedIconSize}>\n {normalizeIcon(option.icon)}\n </IconProvider>\n </span>\n )}\n <span className=\"flex flex-1 flex-col\">\n {renderOption ? (\n renderOption(option, selected)\n ) : (\n <>\n <span>{option.label}</span>\n {option.description && (\n <span className=\"text-ds-sm text-surface-fg-muted\">\n {option.description}\n </span>\n )}\n </>\n )}\n </span>\n {selected && (\n <Icon icon={IconCheck} size=\"sm\" className=\"shrink-0\" />\n )}\n </li>\n )\n })}\n </ul>\n )}\n </motion.div>\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </div>\n </PopoverPrimitive.Root>\n )\n },\n)\nCombobox.displayName = 'Combobox'\n\nexport { Combobox }\n"],"mappings":"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"}
|
package/dist/ui/context-menu.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { CheckboxItem2$2 as e, Content2$5 as t, Group2$2 as n, Item2$3 as r, ItemIndicator2$2 as i, Label2$2 as a, Portal2$2 as o, RadioGroup2$2 as s, RadioItem2$2 as c, Root2$7 as l, Separator2$2 as u, Sub2$2 as d, SubContent2$2 as f, SubTrigger2$2 as p, Trigger$7 as m } from "../_chunks/primitives.js";
|
|
3
3
|
import { springs as h, tweens as g } from "./lib/motion.js";
|
|
4
4
|
import { cn as _ } from "./lib/utils.js";
|
|
5
5
|
import { Icon as v } from "./icon.js";
|
|
@@ -21,32 +21,32 @@ var D = y.createContext(!1), O = y.createContext(!1), k = ({ onOpenChange: e, ..
|
|
|
21
21
|
});
|
|
22
22
|
};
|
|
23
23
|
k.displayName = "ContextMenu";
|
|
24
|
-
var A =
|
|
25
|
-
let [
|
|
26
|
-
|
|
27
|
-
}, [
|
|
24
|
+
var A = m, j = n, M = o, N = ({ open: e, defaultOpen: t = !1, onOpenChange: n, ...r }) => {
|
|
25
|
+
let [i, a] = y.useState(t), o = e !== void 0, s = o ? e : i, c = y.useCallback((e) => {
|
|
26
|
+
o || a(e), n?.(e);
|
|
27
|
+
}, [o, n]);
|
|
28
28
|
return /* @__PURE__ */ b(O.Provider, {
|
|
29
|
-
value:
|
|
30
|
-
children: /* @__PURE__ */ b(
|
|
31
|
-
open:
|
|
32
|
-
onOpenChange:
|
|
33
|
-
...
|
|
29
|
+
value: s,
|
|
30
|
+
children: /* @__PURE__ */ b(d, {
|
|
31
|
+
open: s,
|
|
32
|
+
onOpenChange: c,
|
|
33
|
+
...r
|
|
34
34
|
})
|
|
35
35
|
});
|
|
36
36
|
};
|
|
37
37
|
N.displayName = "ContextMenuSub";
|
|
38
|
-
var P =
|
|
39
|
-
ref:
|
|
38
|
+
var P = s, F = y.forwardRef(({ className: e, inset: t, children: n, ...r }, i) => /* @__PURE__ */ x(p, {
|
|
39
|
+
ref: i,
|
|
40
40
|
className: _("flex cursor-default select-none items-center rounded-control px-ds-03 py-ds-02b text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[state=open]:bg-surface-raised data-[state=open]:text-surface-fg", t && "pl-ds-07", e),
|
|
41
|
-
...
|
|
41
|
+
...r,
|
|
42
42
|
children: [n, /* @__PURE__ */ b(v, {
|
|
43
43
|
icon: C,
|
|
44
44
|
size: "sm",
|
|
45
45
|
className: "ml-auto"
|
|
46
46
|
})]
|
|
47
47
|
}));
|
|
48
|
-
F.displayName =
|
|
49
|
-
var I = y.forwardRef(({ className: e, children: t, ...n }, r) => /* @__PURE__ */ b(T, { children: y.useContext(O) && /* @__PURE__ */ b(
|
|
48
|
+
F.displayName = p.displayName;
|
|
49
|
+
var I = y.forwardRef(({ className: e, children: t, ...n }, r) => /* @__PURE__ */ b(T, { children: y.useContext(O) && /* @__PURE__ */ b(f, {
|
|
50
50
|
ref: r,
|
|
51
51
|
forceMount: !0,
|
|
52
52
|
asChild: !0,
|
|
@@ -72,14 +72,14 @@ var I = y.forwardRef(({ className: e, children: t, ...n }, r) => /* @__PURE__ */
|
|
|
72
72
|
children: t
|
|
73
73
|
})
|
|
74
74
|
}) }));
|
|
75
|
-
I.displayName =
|
|
76
|
-
var L = y.forwardRef(({ className:
|
|
75
|
+
I.displayName = f.displayName;
|
|
76
|
+
var L = y.forwardRef(({ className: e, children: n, ...r }, i) => /* @__PURE__ */ b(T, { children: y.useContext(D) && /* @__PURE__ */ b(o, {
|
|
77
77
|
forceMount: !0,
|
|
78
|
-
children: /* @__PURE__ */ b(
|
|
79
|
-
ref:
|
|
78
|
+
children: /* @__PURE__ */ b(t, {
|
|
79
|
+
ref: i,
|
|
80
80
|
forceMount: !0,
|
|
81
81
|
asChild: !0,
|
|
82
|
-
...
|
|
82
|
+
...r,
|
|
83
83
|
children: /* @__PURE__ */ b(E.div, {
|
|
84
84
|
initial: {
|
|
85
85
|
opacity: 0,
|
|
@@ -97,58 +97,58 @@ var L = y.forwardRef(({ className: t, children: r, ...i }, a) => /* @__PURE__ */
|
|
|
97
97
|
...h.snappy,
|
|
98
98
|
opacity: g.fade
|
|
99
99
|
},
|
|
100
|
-
className: _("z-popover rounded-overlay bg-surface-overlay p-ds-02 text-surface-fg shadow-floating",
|
|
101
|
-
children:
|
|
100
|
+
className: _("z-popover rounded-overlay bg-surface-overlay p-ds-02 text-surface-fg shadow-floating", e),
|
|
101
|
+
children: n
|
|
102
102
|
})
|
|
103
103
|
})
|
|
104
104
|
}) }));
|
|
105
|
-
L.displayName =
|
|
106
|
-
var R = y.forwardRef(({ className: e, inset: t, ...n },
|
|
107
|
-
ref:
|
|
105
|
+
L.displayName = t.displayName;
|
|
106
|
+
var R = y.forwardRef(({ className: e, inset: t, ...n }, i) => /* @__PURE__ */ b(r, {
|
|
107
|
+
ref: i,
|
|
108
108
|
className: _("relative flex cursor-default select-none items-center rounded-control px-ds-03 py-ds-02b text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled", t && "pl-ds-07", e),
|
|
109
109
|
...n
|
|
110
110
|
}));
|
|
111
|
-
R.displayName =
|
|
112
|
-
var z = y.forwardRef(({ className:
|
|
113
|
-
ref:
|
|
114
|
-
className: _("relative flex cursor-default select-none items-center rounded-control py-ds-02b pl-ds-07 pr-ds-03 text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled",
|
|
115
|
-
checked:
|
|
116
|
-
...
|
|
111
|
+
R.displayName = r.displayName;
|
|
112
|
+
var z = y.forwardRef(({ className: t, children: n, checked: r, ...a }, o) => /* @__PURE__ */ x(e, {
|
|
113
|
+
ref: o,
|
|
114
|
+
className: _("relative flex cursor-default select-none items-center rounded-control py-ds-02b pl-ds-07 pr-ds-03 text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled", t),
|
|
115
|
+
checked: r,
|
|
116
|
+
...a,
|
|
117
117
|
children: [/* @__PURE__ */ b("span", {
|
|
118
118
|
className: "absolute left-ds-03 flex h-ico-sm w-ico-sm items-center justify-center",
|
|
119
|
-
children: /* @__PURE__ */ b(
|
|
119
|
+
children: /* @__PURE__ */ b(i, { children: /* @__PURE__ */ b(v, {
|
|
120
120
|
icon: S,
|
|
121
121
|
size: "sm"
|
|
122
122
|
}) })
|
|
123
|
-
}),
|
|
123
|
+
}), n]
|
|
124
124
|
}));
|
|
125
|
-
z.displayName =
|
|
126
|
-
var B = y.forwardRef(({ className: e, children: t, ...n }, r) => /* @__PURE__ */ x(
|
|
125
|
+
z.displayName = e.displayName;
|
|
126
|
+
var B = y.forwardRef(({ className: e, children: t, ...n }, r) => /* @__PURE__ */ x(c, {
|
|
127
127
|
ref: r,
|
|
128
128
|
className: _("relative flex cursor-default select-none items-center rounded-control py-ds-02b pl-ds-07 pr-ds-03 text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled", e),
|
|
129
129
|
...n,
|
|
130
130
|
children: [/* @__PURE__ */ b("span", {
|
|
131
131
|
className: "absolute left-ds-03 flex h-ico-sm w-ico-sm items-center justify-center",
|
|
132
|
-
children: /* @__PURE__ */ b(
|
|
132
|
+
children: /* @__PURE__ */ b(i, { children: /* @__PURE__ */ b(v, {
|
|
133
133
|
icon: w,
|
|
134
134
|
size: "sm",
|
|
135
135
|
className: "fill-current"
|
|
136
136
|
}) })
|
|
137
137
|
}), t]
|
|
138
138
|
}));
|
|
139
|
-
B.displayName =
|
|
140
|
-
var V = y.forwardRef(({ className: e, inset: t, ...n }, r) => /* @__PURE__ */ b(
|
|
139
|
+
B.displayName = c.displayName;
|
|
140
|
+
var V = y.forwardRef(({ className: e, inset: t, ...n }, r) => /* @__PURE__ */ b(a, {
|
|
141
141
|
ref: r,
|
|
142
142
|
className: _("px-ds-03 py-ds-02b text-ds-md font-semibold text-surface-fg", t && "pl-ds-07", e),
|
|
143
143
|
...n
|
|
144
144
|
}));
|
|
145
|
-
V.displayName =
|
|
146
|
-
var H = y.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ b(
|
|
145
|
+
V.displayName = a.displayName;
|
|
146
|
+
var H = y.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ b(u, {
|
|
147
147
|
ref: n,
|
|
148
148
|
className: _("-mx-ds-01 my-ds-02 h-px bg-surface-border", e),
|
|
149
149
|
...t
|
|
150
150
|
}));
|
|
151
|
-
H.displayName =
|
|
151
|
+
H.displayName = u.displayName;
|
|
152
152
|
var U = ({ className: e, ...t }) => /* @__PURE__ */ b("span", {
|
|
153
153
|
className: _("ml-auto text-ds-sm text-surface-fg-subtle", e),
|
|
154
154
|
...t
|
package/dist/ui/dialog.js
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { Close as e, Content$2 as t, Description as n, Overlay as r, Portal$4 as i, Root$8 as a, Title as o, Trigger$9 as s } from "../_chunks/primitives.js";
|
|
3
3
|
import { springs as c, tweens as l } from "./lib/motion.js";
|
|
4
4
|
import { cn as u } from "./lib/utils.js";
|
|
5
5
|
import { Icon as d } from "./icon.js";
|
|
6
6
|
import { useIsMobile as f } from "../hooks/use-mobile.js";
|
|
7
|
-
import {
|
|
7
|
+
import { useControllableOpen as p } from "../_chunks/use-controllable-open.js";
|
|
8
8
|
import * as m from "react";
|
|
9
9
|
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
10
10
|
import { IconX as _ } from "@tabler/icons-react";
|
|
11
11
|
import { AnimatePresence as v, motion as y } from "framer-motion";
|
|
12
12
|
//#region src/ui/dialog.tsx
|
|
13
|
-
var b = m.createContext({ open: !1 }), x = () => m.useContext(b), S = ({ open:
|
|
14
|
-
let { open:
|
|
15
|
-
open:
|
|
16
|
-
defaultOpen:
|
|
17
|
-
onOpenChange:
|
|
18
|
-
}), s = m.useMemo(() => ({ open:
|
|
13
|
+
var b = m.createContext({ open: !1 }), x = () => m.useContext(b), S = ({ open: e, defaultOpen: t, onOpenChange: n, ...r }) => {
|
|
14
|
+
let { open: i, setOpen: o } = p({
|
|
15
|
+
open: e,
|
|
16
|
+
defaultOpen: t,
|
|
17
|
+
onOpenChange: n
|
|
18
|
+
}), s = m.useMemo(() => ({ open: i }), [i]);
|
|
19
19
|
return /* @__PURE__ */ h(b.Provider, {
|
|
20
20
|
value: s,
|
|
21
|
-
children: /* @__PURE__ */ h(
|
|
22
|
-
open:
|
|
21
|
+
children: /* @__PURE__ */ h(a, {
|
|
22
|
+
open: i,
|
|
23
23
|
onOpenChange: o,
|
|
24
|
-
...
|
|
24
|
+
...r
|
|
25
25
|
})
|
|
26
26
|
});
|
|
27
27
|
};
|
|
28
28
|
S.displayName = "Dialog";
|
|
29
|
-
var C =
|
|
29
|
+
var C = s, w = i, T = e, E = m.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ h(r, {
|
|
30
30
|
ref: n,
|
|
31
31
|
forceMount: !0,
|
|
32
32
|
className: u("fixed inset-0 z-overlay bg-overlay", e),
|
|
33
33
|
...t
|
|
34
34
|
}));
|
|
35
|
-
E.displayName =
|
|
36
|
-
var D = m.forwardRef(({ className:
|
|
37
|
-
let { open: s } = x(), p = f(), m =
|
|
35
|
+
E.displayName = r.displayName;
|
|
36
|
+
var D = m.forwardRef(({ className: n, children: r, responsive: i, ...a }, o) => {
|
|
37
|
+
let { open: s } = x(), p = f(), m = i !== !1 && p;
|
|
38
38
|
return /* @__PURE__ */ h(v, { children: s && /* @__PURE__ */ g(w, {
|
|
39
39
|
forceMount: !0,
|
|
40
40
|
children: [/* @__PURE__ */ h(E, {
|
|
@@ -45,11 +45,11 @@ var D = m.forwardRef(({ className: e, children: t, responsive: r, ...i }, o) =>
|
|
|
45
45
|
exit: { opacity: 0 },
|
|
46
46
|
transition: l.fade
|
|
47
47
|
})
|
|
48
|
-
}), /* @__PURE__ */ h(
|
|
48
|
+
}), /* @__PURE__ */ h(t, {
|
|
49
49
|
ref: o,
|
|
50
50
|
forceMount: !0,
|
|
51
51
|
asChild: !0,
|
|
52
|
-
...
|
|
52
|
+
...a,
|
|
53
53
|
children: /* @__PURE__ */ g(y.div, {
|
|
54
54
|
initial: m ? { y: "100%" } : {
|
|
55
55
|
opacity: 0,
|
|
@@ -73,8 +73,8 @@ var D = m.forwardRef(({ className: e, children: t, responsive: r, ...i }, o) =>
|
|
|
73
73
|
...c.smooth,
|
|
74
74
|
opacity: l.fade
|
|
75
75
|
},
|
|
76
|
-
className: u("fixed z-modal grid w-full gap-ds-05 bg-surface-overlay p-ds-06",
|
|
77
|
-
children: [
|
|
76
|
+
className: u("fixed z-modal grid w-full gap-ds-05 bg-surface-overlay p-ds-06", i === !1 ? "left-[50%] top-[50%] max-w-lg rounded-overlay-lg shadow-overlay" : "inset-0 md:inset-auto md:left-[50%] md:top-[50%] md:max-w-lg md:rounded-overlay-lg md:shadow-overlay", n),
|
|
77
|
+
children: [r, /* @__PURE__ */ g(e, {
|
|
78
78
|
title: "Close",
|
|
79
79
|
className: "absolute right-ds-05 top-ds-05 min-h-ds-xs min-w-ds-xs flex items-center justify-center rounded-control-inner text-surface-fg-subtle transition-colors duration-fast-01 ease-productive-standard hover:text-surface-fg-muted hover:bg-surface-raised-hover active:scale-90 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 disabled:pointer-events-none",
|
|
80
80
|
children: [/* @__PURE__ */ h(d, {
|
|
@@ -89,11 +89,11 @@ var D = m.forwardRef(({ className: e, children: t, responsive: r, ...i }, o) =>
|
|
|
89
89
|
})]
|
|
90
90
|
}) });
|
|
91
91
|
});
|
|
92
|
-
D.displayName =
|
|
93
|
-
var O = m.forwardRef(({ className: e, ...
|
|
92
|
+
D.displayName = t.displayName;
|
|
93
|
+
var O = m.forwardRef(({ className: e, ...n }, r) => /* @__PURE__ */ h(t, {
|
|
94
94
|
ref: r,
|
|
95
95
|
className: u(e),
|
|
96
|
-
...
|
|
96
|
+
...n
|
|
97
97
|
}));
|
|
98
98
|
O.displayName = "DialogContentRaw";
|
|
99
99
|
var k = m.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ h("div", {
|
|
@@ -114,11 +114,11 @@ var j = m.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ h(o, {
|
|
|
114
114
|
...t
|
|
115
115
|
}));
|
|
116
116
|
j.displayName = o.displayName;
|
|
117
|
-
var M = m.forwardRef(({ className: e, ...
|
|
117
|
+
var M = m.forwardRef(({ className: e, ...t }, r) => /* @__PURE__ */ h(n, {
|
|
118
118
|
ref: r,
|
|
119
119
|
className: u("text-ds-md text-surface-fg-muted", e),
|
|
120
|
-
...
|
|
120
|
+
...t
|
|
121
121
|
}));
|
|
122
|
-
M.displayName =
|
|
122
|
+
M.displayName = n.displayName;
|
|
123
123
|
//#endregion
|
|
124
124
|
export { S as Dialog, T as DialogClose, D as DialogContent, O as DialogContentRaw, M as DialogDescription, A as DialogFooter, k as DialogHeader, E as DialogOverlay, w as DialogPortal, j as DialogTitle, C as DialogTrigger };
|
package/dist/ui/dot.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../../src/ui/dot.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAmB9B,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,CAAA;AAClG,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAC/C,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../../src/ui/dot.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAmB9B,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,CAAA;AAClG,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAC/C,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAA;AAiDlD,QAAA,MAAM,WAAW;;8EAUf,CAAA;AASF;;;;;;;;GAQG;AACH,MAAM,WAAW,QACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC,EAC1D,YAAY,CAAC,OAAO,WAAW,CAAC;IAClC,6EAA6E;IAC7E,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,uGAAuG;IACvG,OAAO,CAAC,EAAE,UAAU,CAAA;IACpB,qGAAqG;IACrG,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,mEAAmE;IACnE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,qCAAqC;IACrC,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;IACvC,uDAAuD;IACvD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,mDAAmD;IACnD,aAAa,CAAC,EAAE,OAAO,GAAG,KAAK,CAAA;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,QAAA,MAAM,GAAG,kFA4DR,CAAA;AAGD,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,CAAA"}
|
package/dist/ui/dot.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { cva as e } from "../_chunks/vendor-utils.js";
|
|
3
3
|
import { cn as t } from "./lib/utils.js";
|
|
4
4
|
import * as n from "react";
|
|
5
5
|
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
@@ -29,14 +29,6 @@ var a = {
|
|
|
29
29
|
neutral: "border-neutral-8/40 bg-neutral-8/10",
|
|
30
30
|
current: "border-current/40 bg-current/10"
|
|
31
31
|
}, c = {
|
|
32
|
-
accent: "bg-accent-9/40",
|
|
33
|
-
success: "bg-success-9/40",
|
|
34
|
-
warning: "bg-warning-9/40",
|
|
35
|
-
error: "bg-error-9/40",
|
|
36
|
-
info: "bg-info-9/40",
|
|
37
|
-
neutral: "bg-neutral-8/40",
|
|
38
|
-
current: "bg-current/40"
|
|
39
|
-
}, l = {
|
|
40
32
|
accent: "text-accent-11",
|
|
41
33
|
success: "text-success-11",
|
|
42
34
|
warning: "text-warning-11",
|
|
@@ -44,11 +36,11 @@ var a = {
|
|
|
44
36
|
info: "text-info-11",
|
|
45
37
|
neutral: "text-surface-fg-muted",
|
|
46
38
|
current: ""
|
|
47
|
-
},
|
|
39
|
+
}, l = {
|
|
48
40
|
slow: "2s",
|
|
49
41
|
normal: "1s",
|
|
50
42
|
fast: "0.6s"
|
|
51
|
-
},
|
|
43
|
+
}, u = e("relative inline-flex shrink-0 rounded-pill", {
|
|
52
44
|
variants: { size: {
|
|
53
45
|
xs: "h-1 w-1",
|
|
54
46
|
sm: "h-1.5 w-1.5",
|
|
@@ -56,37 +48,37 @@ var a = {
|
|
|
56
48
|
lg: "h-2.5 w-2.5"
|
|
57
49
|
} },
|
|
58
50
|
defaultVariants: { size: "md" }
|
|
59
|
-
}),
|
|
51
|
+
}), d = {
|
|
60
52
|
xs: "text-ds-xs",
|
|
61
53
|
sm: "text-ds-xs",
|
|
62
54
|
md: "text-ds-sm",
|
|
63
55
|
lg: "text-ds-sm"
|
|
64
|
-
},
|
|
65
|
-
let
|
|
66
|
-
className: t(
|
|
67
|
-
children:
|
|
56
|
+
}, f = n.forwardRef(({ color: e = "neutral", size: n = "md", variant: f = "filled", withBorder: p = !1, pulse: m = !1, pulseSpeed: h = "normal", label: g, labelPosition: _ = "end", labelClassName: v, className: y, "aria-label": b, ...x }, S) => {
|
|
57
|
+
let C = n ?? "md", w = g != null || b != null, T = m && f !== "off", E = t(u({ size: C }), f === "filled" && a[e], f === "ring" && t("border-[1.5px] bg-transparent", o[e]), f === "off" && t("border", s[e]), p && "ring-2 ring-surface-raised"), D = g == null ? null : /* @__PURE__ */ r("span", {
|
|
58
|
+
className: t(d[C], c[e], "font-sans", v),
|
|
59
|
+
children: g
|
|
68
60
|
});
|
|
69
61
|
return /* @__PURE__ */ i("span", {
|
|
70
|
-
ref:
|
|
71
|
-
role:
|
|
72
|
-
"aria-hidden":
|
|
73
|
-
"aria-label":
|
|
74
|
-
className: t("inline-flex items-center gap-ds-02",
|
|
75
|
-
...
|
|
62
|
+
ref: S,
|
|
63
|
+
role: w ? "status" : void 0,
|
|
64
|
+
"aria-hidden": w ? void 0 : !0,
|
|
65
|
+
"aria-label": b,
|
|
66
|
+
className: t("inline-flex items-center gap-ds-02", y),
|
|
67
|
+
...x,
|
|
76
68
|
children: [
|
|
77
|
-
|
|
78
|
-
/* @__PURE__ */
|
|
69
|
+
_ === "start" && D,
|
|
70
|
+
/* @__PURE__ */ r("span", {
|
|
79
71
|
className: "relative inline-flex shrink-0",
|
|
80
|
-
children:
|
|
81
|
-
"data-pulse": "",
|
|
82
|
-
style: { animationDuration:
|
|
83
|
-
className: t(
|
|
84
|
-
})
|
|
72
|
+
children: /* @__PURE__ */ r("span", {
|
|
73
|
+
"data-pulse": T ? "" : void 0,
|
|
74
|
+
style: T ? { animationDuration: l[h] } : void 0,
|
|
75
|
+
className: t(E, T && "animate-pulse motion-reduce:animate-none")
|
|
76
|
+
})
|
|
85
77
|
}),
|
|
86
|
-
|
|
78
|
+
_ === "end" && D
|
|
87
79
|
]
|
|
88
80
|
});
|
|
89
81
|
});
|
|
90
|
-
|
|
82
|
+
f.displayName = "Dot";
|
|
91
83
|
//#endregion
|
|
92
|
-
export {
|
|
84
|
+
export { f as Dot, u as dotVariants };
|
package/dist/ui/dot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dot.js","names":[],"sources":["../../src/ui/dot.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { cn } from './lib/utils'\n\n/* ---------------------------------------------------------------------------\n * Dot — a small semantic status/indicator dot. The low-level primitive behind\n * StatusBadge, status/presence/health indicators, legend swatches, Avatar status.\n *\n * Intent-coloured, sized (xs–lg), filled / ring / off, optionally pulsing (with\n * a speed), optionally with a contrast border, and an optional label on either\n * side. Decorative by default (aria-hidden); a `label` (or `aria-label`) makes\n * it an announced status.\n *\n * For a dot/count that overlays a child element (notification badge), use\n * `BadgeIndicator` instead — that's the positioned-overlay pattern.\n *\n * API informed by Mantine `Indicator`, Ant `Badge status`, Chakra `Status`.\n * ------------------------------------------------------------------------ */\n\nexport type DotColor = 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'current'\nexport type DotSize = 'xs' | 'sm' | 'md' | 'lg'\nexport type DotVariant = 'filled' | 'ring' | 'off'\n\nconst FILL: Record<DotColor, string> = {\n accent: 'bg-accent-9',\n success: 'bg-success-9',\n warning: 'bg-warning-9',\n error: 'bg-error-9',\n info: 'bg-info-9',\n neutral: 'bg-neutral-8',\n current: 'bg-current',\n}\n\nconst RING: Record<DotColor, string> = {\n accent: 'border-accent-9',\n success: 'border-success-9',\n warning: 'border-warning-9',\n error: 'border-error-9',\n info: 'border-info-9',\n neutral: 'border-neutral-8',\n current: 'border-current',\n}\n\n// Off — \"exists but inactive\": faint same-tone fill + a light border.\nconst OFF: Record<DotColor, string> = {\n accent: 'border-accent-9/40 bg-accent-9/10',\n success: 'border-success-9/40 bg-success-9/10',\n warning: 'border-warning-9/40 bg-warning-9/10',\n error: 'border-error-9/40 bg-error-9/10',\n info: 'border-info-9/40 bg-info-9/10',\n neutral: 'border-neutral-8/40 bg-neutral-8/10',\n current: 'border-current/40 bg-current/10',\n}\n\
|
|
1
|
+
{"version":3,"file":"dot.js","names":[],"sources":["../../src/ui/dot.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { cn } from './lib/utils'\n\n/* ---------------------------------------------------------------------------\n * Dot — a small semantic status/indicator dot. The low-level primitive behind\n * StatusBadge, status/presence/health indicators, legend swatches, Avatar status.\n *\n * Intent-coloured, sized (xs–lg), filled / ring / off, optionally pulsing (with\n * a speed), optionally with a contrast border, and an optional label on either\n * side. Decorative by default (aria-hidden); a `label` (or `aria-label`) makes\n * it an announced status.\n *\n * For a dot/count that overlays a child element (notification badge), use\n * `BadgeIndicator` instead — that's the positioned-overlay pattern.\n *\n * API informed by Mantine `Indicator`, Ant `Badge status`, Chakra `Status`.\n * ------------------------------------------------------------------------ */\n\nexport type DotColor = 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'current'\nexport type DotSize = 'xs' | 'sm' | 'md' | 'lg'\nexport type DotVariant = 'filled' | 'ring' | 'off'\n\nconst FILL: Record<DotColor, string> = {\n accent: 'bg-accent-9',\n success: 'bg-success-9',\n warning: 'bg-warning-9',\n error: 'bg-error-9',\n info: 'bg-info-9',\n neutral: 'bg-neutral-8',\n current: 'bg-current',\n}\n\nconst RING: Record<DotColor, string> = {\n accent: 'border-accent-9',\n success: 'border-success-9',\n warning: 'border-warning-9',\n error: 'border-error-9',\n info: 'border-info-9',\n neutral: 'border-neutral-8',\n current: 'border-current',\n}\n\n// Off — \"exists but inactive\": faint same-tone fill + a light border.\nconst OFF: Record<DotColor, string> = {\n accent: 'border-accent-9/40 bg-accent-9/10',\n success: 'border-success-9/40 bg-success-9/10',\n warning: 'border-warning-9/40 bg-warning-9/10',\n error: 'border-error-9/40 bg-error-9/10',\n info: 'border-info-9/40 bg-info-9/10',\n neutral: 'border-neutral-8/40 bg-neutral-8/10',\n current: 'border-current/40 bg-current/10',\n}\n\nconst TEXT: Record<DotColor, string> = {\n accent: 'text-accent-11',\n success: 'text-success-11',\n warning: 'text-warning-11',\n error: 'text-error-11',\n info: 'text-info-11',\n neutral: 'text-surface-fg-muted',\n current: '',\n}\n\nconst PULSE_SPEED: Record<'slow' | 'normal' | 'fast', string> = {\n slow: '2s',\n normal: '1s',\n fast: '0.6s',\n}\n\nconst dotVariants = cva('relative inline-flex shrink-0 rounded-pill', {\n variants: {\n size: {\n xs: 'h-1 w-1',\n sm: 'h-1.5 w-1.5',\n md: 'h-2 w-2',\n lg: 'h-2.5 w-2.5',\n },\n },\n defaultVariants: { size: 'md' },\n})\n\nconst labelTextSize: Record<DotSize, string> = {\n xs: 'text-ds-xs',\n sm: 'text-ds-xs',\n md: 'text-ds-sm',\n lg: 'text-ds-sm',\n}\n\n/**\n * Props for Dot — a small semantic indicator dot.\n *\n * @example\n * <Dot color=\"success\" /> // bare dot\n * <Dot color=\"error\" pulse pulseSpeed=\"fast\" label=\"Recording\" />\n * <Dot color=\"neutral\" variant=\"off\" label=\"Offline\" /> // inactive\n * <Dot color=\"success\" withBorder /> // contrast ring on busy bg\n */\nexport interface DotProps\n extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'color'>,\n VariantProps<typeof dotVariants> {\n /** Intent colour, or `current` to inherit text colour. @default 'neutral' */\n color?: DotColor\n /** `filled` disc, hollow `ring`, or `off` (faint fill + light border = inactive). @default 'filled' */\n variant?: DotVariant\n /** A contrast ring around the dot so it stays visible on busy/colored backgrounds. @default false */\n withBorder?: boolean\n /** Animate a pulsing ripple (ignored for `off`). @default false */\n pulse?: boolean\n /** Pulse tempo. @default 'normal' */\n pulseSpeed?: 'slow' | 'normal' | 'fast'\n /** Inline label. Makes the dot an announced status. */\n label?: React.ReactNode\n /** Which side the label sits on. @default 'end' */\n labelPosition?: 'start' | 'end'\n labelClassName?: string\n}\n\nconst Dot = React.forwardRef<HTMLSpanElement, DotProps>(\n (\n {\n color = 'neutral',\n size = 'md',\n variant = 'filled',\n withBorder = false,\n pulse = false,\n pulseSpeed = 'normal',\n label,\n labelPosition = 'end',\n labelClassName,\n className,\n 'aria-label': ariaLabel,\n ...props\n },\n ref,\n ) => {\n const resolvedSize = size ?? 'md'\n // A dot with a label (or explicit aria-label) is an announced status;\n // a bare dot is decorative (the surrounding element carries the meaning).\n const isAnnounced = label != null || ariaLabel != null\n // Off dots are inactive — a pulse would contradict that.\n const showPulse = pulse && variant !== 'off'\n\n const disc = cn(\n dotVariants({ size: resolvedSize }),\n variant === 'filled' && FILL[color],\n variant === 'ring' && cn('border-[1.5px] bg-transparent', RING[color]),\n variant === 'off' && cn('border', OFF[color]),\n withBorder && 'ring-2 ring-surface-raised',\n )\n\n const labelEl =\n label != null ? (\n <span className={cn(labelTextSize[resolvedSize], TEXT[color], 'font-sans', labelClassName)}>{label}</span>\n ) : null\n\n return (\n <span\n ref={ref}\n role={isAnnounced ? 'status' : undefined}\n aria-hidden={isAnnounced ? undefined : true}\n aria-label={ariaLabel}\n className={cn('inline-flex items-center gap-ds-02', className)}\n {...props}\n >\n {labelPosition === 'start' && labelEl}\n <span className=\"relative inline-flex shrink-0\">\n {/* Contained opacity breathe on the disc itself — never an expanding halo/ring. */}\n <span\n data-pulse={showPulse ? '' : undefined}\n style={showPulse ? { animationDuration: PULSE_SPEED[pulseSpeed] } : undefined}\n className={cn(disc, showPulse && 'animate-pulse motion-reduce:animate-none')}\n />\n </span>\n {labelPosition === 'end' && labelEl}\n </span>\n )\n },\n)\nDot.displayName = 'Dot'\n\nexport { Dot, dotVariants }\n"],"mappings":";;;;;;AA0BA,IAAM,IAAiC;CACrC,QAAQ;CACR,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;CACV,EAEK,IAAiC;CACrC,QAAQ;CACR,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;CACV,EAGK,IAAgC;CACpC,QAAQ;CACR,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;CACV,EAEK,IAAiC;CACrC,QAAQ;CACR,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;CACV,EAEK,IAA0D;CAC9D,MAAM;CACN,QAAQ;CACR,MAAM;CACP,EAEK,IAAc,EAAI,8CAA8C;CACpE,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACL,EACF;CACD,iBAAiB,EAAE,MAAM,MAAM;CAChC,CAAC,EAEI,IAAyC;CAC7C,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EA+BK,IAAM,EAAM,YAEd,EACE,WAAQ,WACR,UAAO,MACP,aAAU,UACV,gBAAa,IACb,WAAQ,IACR,gBAAa,UACb,UACA,mBAAgB,OAChB,mBACA,cACA,cAAc,GACd,GAAG,KAEL,MACG;CACH,IAAM,IAAe,KAAQ,MAGvB,IAAc,KAAS,QAAQ,KAAa,MAE5C,IAAY,KAAS,MAAY,OAEjC,IAAO,EACX,EAAY,EAAE,MAAM,GAAc,CAAC,EACnC,MAAY,YAAY,EAAK,IAC7B,MAAY,UAAU,EAAG,iCAAiC,EAAK,GAAO,EACtE,MAAY,SAAS,EAAG,UAAU,EAAI,GAAO,EAC7C,KAAc,6BACf,EAEK,IACJ,KAAS,OAEL,OADF,kBAAC,QAAD;EAAM,WAAW,EAAG,EAAc,IAAe,EAAK,IAAQ,aAAa,EAAe;YAAG;EAAa,CAAA;AAG9G,QACE,kBAAC,QAAD;EACO;EACL,MAAM,IAAc,WAAW,KAAA;EAC/B,eAAa,IAAc,KAAA,IAAY;EACvC,cAAY;EACZ,WAAW,EAAG,sCAAsC,EAAU;EAC9D,GAAI;YANN;GAQG,MAAkB,WAAW;GAC9B,kBAAC,QAAD;IAAM,WAAU;cAEd,kBAAC,QAAD;KACE,cAAY,IAAY,KAAK,KAAA;KAC7B,OAAO,IAAY,EAAE,mBAAmB,EAAY,IAAa,GAAG,KAAA;KACpE,WAAW,EAAG,GAAM,KAAa,2CAA2C;KAC5E,CAAA;IACG,CAAA;GACN,MAAkB,SAAS;GACvB;;EAGZ;AACD,EAAI,cAAc"}
|