@devalok/shilp-sutra 0.49.4 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +12 -4
- package/MIGRATION.md +6 -0
- package/dist/_chunks/badge-group.js +12 -11
- package/dist/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/block-shell.js +1 -1
- package/dist/_chunks/block-shell.js.map +1 -1
- package/dist/_chunks/chat.js +18 -18
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/document-preview.js +1 -1
- package/dist/_chunks/document-preview.js.map +1 -1
- package/dist/_chunks/emoji-suggestion.js +1 -1
- package/dist/_chunks/emoji-suggestion.js.map +1 -1
- package/dist/_chunks/grid-lines.js +2 -2
- package/dist/_chunks/grid-lines.js.map +1 -1
- package/dist/_chunks/image-preview.js +1 -1
- package/dist/_chunks/image-preview.js.map +1 -1
- package/dist/_chunks/mention-suggestion.js +2 -2
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/oauth-button.js +8 -8
- package/dist/_chunks/oauth-button.js.map +1 -1
- package/dist/_chunks/shared.js +2 -2
- package/dist/_chunks/shared.js.map +1 -1
- package/dist/_chunks/success.js +5 -5
- package/dist/_chunks/success.js.map +1 -1
- package/dist/_chunks/tiptap.js +3956 -1796
- package/dist/_chunks/tiptap.js.map +1 -1
- package/dist/_chunks/tooltip.js +2 -2
- package/dist/_chunks/tooltip.js.map +1 -1
- package/dist/_chunks/tree-view.js +2 -2
- package/dist/_chunks/tree-view.js.map +1 -1
- package/dist/_chunks/use-calendar.js +3 -3
- package/dist/_chunks/use-calendar.js.map +1 -1
- package/dist/ai/block-renderer.js +1 -1
- package/dist/ai/block-renderer.js.map +1 -1
- package/dist/ai/blocks/error.js +1 -1
- package/dist/ai/blocks/error.js.map +1 -1
- package/dist/ai/command-bar.js +15 -15
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/ai/conversation.js +6 -6
- package/dist/ai/conversation.js.map +1 -1
- package/dist/composed/activity-feed.js +4 -4
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/avatar-group.js +6 -6
- package/dist/composed/avatar-group.js.map +1 -1
- package/dist/composed/bulk-action-bar.js +1 -1
- package/dist/composed/bulk-action-bar.js.map +1 -1
- package/dist/composed/command-palette.js +12 -12
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/content-card.js +1 -1
- package/dist/composed/content-card.js.map +1 -1
- package/dist/composed/date-picker/index.js +17 -17
- package/dist/composed/date-picker/index.js.map +1 -1
- package/dist/composed/deadline-indicator.js +2 -2
- package/dist/composed/deadline-indicator.js.map +1 -1
- package/dist/composed/diff.d.ts +108 -0
- package/dist/composed/diff.d.ts.map +1 -0
- package/dist/composed/diff.js +1004 -0
- package/dist/composed/diff.js.map +1 -0
- package/dist/composed/emoji-picker.js +6 -6
- package/dist/composed/emoji-picker.js.map +1 -1
- package/dist/composed/empty-state.js +2 -2
- package/dist/composed/empty-state.js.map +1 -1
- package/dist/composed/error-boundary.js +6 -6
- package/dist/composed/error-boundary.js.map +1 -1
- package/dist/composed/file-preview.js +5 -5
- package/dist/composed/file-preview.js.map +1 -1
- package/dist/composed/filter-bar.js +3 -3
- package/dist/composed/filter-bar.js.map +1 -1
- package/dist/composed/form-section.js +2 -2
- package/dist/composed/form-section.js.map +1 -1
- package/dist/composed/inline-edit.d.ts +1 -1
- package/dist/composed/inline-edit.d.ts.map +1 -1
- package/dist/composed/inline-edit.js.map +1 -1
- package/dist/composed/loading-skeleton.js +3 -3
- package/dist/composed/loading-skeleton.js.map +1 -1
- package/dist/composed/markdown-viewer.js +11 -11
- package/dist/composed/markdown-viewer.js.map +1 -1
- package/dist/composed/master-detail.js +1 -1
- package/dist/composed/master-detail.js.map +1 -1
- package/dist/composed/member-picker.js +2 -2
- package/dist/composed/member-picker.js.map +1 -1
- package/dist/composed/multi-select-popover.js +5 -5
- package/dist/composed/multi-select-popover.js.map +1 -1
- package/dist/composed/page-header.js +3 -3
- package/dist/composed/page-header.js.map +1 -1
- package/dist/composed/page-skeletons.js +4 -4
- package/dist/composed/page-skeletons.js.map +1 -1
- package/dist/composed/priority-indicator.js +1 -1
- package/dist/composed/priority-indicator.js.map +1 -1
- package/dist/composed/responsive-modal.js +2 -2
- package/dist/composed/responsive-modal.js.map +1 -1
- package/dist/composed/rich-chat-input.js +27 -27
- package/dist/composed/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.d.ts +81 -6
- package/dist/composed/rich-text-editor.d.ts.map +1 -1
- package/dist/composed/rich-text-editor.js +365 -210
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/composed/schedule-view.js +4 -4
- package/dist/composed/schedule-view.js.map +1 -1
- package/dist/shell/bottom-navbar.js +4 -4
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/notification-center.js +13 -13
- package/dist/shell/notification-center.js.map +1 -1
- package/dist/shell/notification-preferences.js +10 -10
- package/dist/shell/notification-preferences.js.map +1 -1
- package/dist/shell/sidebar.js +9 -9
- package/dist/shell/sidebar.js.map +1 -1
- package/dist/shell/top-bar.js +8 -8
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/tokens/semantic.css +6 -1
- package/dist/tokens/typography-semantic.css +6 -6
- package/dist/tokens/utilities.css +8 -0
- package/dist/ui/accordion.js +2 -2
- package/dist/ui/accordion.js.map +1 -1
- package/dist/ui/alert-dialog.js +4 -4
- package/dist/ui/alert-dialog.js.map +1 -1
- package/dist/ui/alert.js +1 -1
- package/dist/ui/alert.js.map +1 -1
- package/dist/ui/autocomplete.d.ts.map +1 -1
- package/dist/ui/autocomplete.js +11 -3
- package/dist/ui/autocomplete.js.map +1 -1
- package/dist/ui/avatar.js +5 -5
- package/dist/ui/avatar.js.map +1 -1
- package/dist/ui/badge-group.d.ts +2 -6
- package/dist/ui/badge-group.d.ts.map +1 -1
- package/dist/ui/badge-indicator.d.ts +2 -6
- package/dist/ui/badge-indicator.d.ts.map +1 -1
- package/dist/ui/badge-indicator.js +19 -18
- package/dist/ui/badge-indicator.js.map +1 -1
- package/dist/ui/badge.d.ts +2 -4
- package/dist/ui/badge.d.ts.map +1 -1
- package/dist/ui/banner.js +1 -1
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/breadcrumb.js +1 -1
- package/dist/ui/breadcrumb.js.map +1 -1
- package/dist/ui/button.js +7 -7
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.d.ts +1 -1
- package/dist/ui/card.js +1 -1
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/charts/gauge-chart.js +2 -2
- package/dist/ui/charts/gauge-chart.js.map +1 -1
- package/dist/ui/charts/pie-chart.js +1 -1
- package/dist/ui/charts/pie-chart.js.map +1 -1
- package/dist/ui/charts/radar-chart.d.ts +19 -1
- package/dist/ui/charts/radar-chart.d.ts.map +1 -1
- package/dist/ui/charts/radar-chart.js +80 -42
- package/dist/ui/charts/radar-chart.js.map +1 -1
- package/dist/ui/code.js +2 -2
- package/dist/ui/code.js.map +1 -1
- package/dist/ui/color-input.d.ts.map +1 -1
- package/dist/ui/color-input.js +164 -157
- package/dist/ui/color-input.js.map +1 -1
- package/dist/ui/combobox.d.ts.map +1 -1
- package/dist/ui/combobox.js +143 -142
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/context-menu.js +6 -6
- package/dist/ui/context-menu.js.map +1 -1
- package/dist/ui/data-table-body.js +1 -1
- package/dist/ui/data-table-body.js.map +1 -1
- package/dist/ui/data-table-bulk-actions.js +1 -1
- package/dist/ui/data-table-bulk-actions.js.map +1 -1
- package/dist/ui/data-table-card.js +1 -1
- package/dist/ui/data-table-card.js.map +1 -1
- package/dist/ui/data-table-header.js +1 -1
- package/dist/ui/data-table-header.js.map +1 -1
- package/dist/ui/data-table-pagination.js +3 -3
- package/dist/ui/data-table-pagination.js.map +1 -1
- package/dist/ui/data-table-toolbar.js +1 -1
- package/dist/ui/data-table-toolbar.js.map +1 -1
- package/dist/ui/data-table.js +1 -1
- package/dist/ui/data-table.js.map +1 -1
- package/dist/ui/dialog.js +2 -2
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/dot.js +4 -4
- package/dist/ui/dot.js.map +1 -1
- package/dist/ui/dropdown-menu.js +6 -6
- package/dist/ui/dropdown-menu.js.map +1 -1
- package/dist/ui/file-upload.js +5 -5
- package/dist/ui/file-upload.js.map +1 -1
- package/dist/ui/form.js +1 -1
- package/dist/ui/form.js.map +1 -1
- package/dist/ui/input-otp.d.ts.map +1 -1
- package/dist/ui/input-otp.js +3 -3
- package/dist/ui/input-otp.js.map +1 -1
- package/dist/ui/input.js +8 -8
- package/dist/ui/input.js.map +1 -1
- package/dist/ui/label.js +1 -1
- package/dist/ui/label.js.map +1 -1
- package/dist/ui/lib/utils.d.ts.map +1 -1
- package/dist/ui/lib/utils.js +42 -13
- package/dist/ui/lib/utils.js.map +1 -1
- package/dist/ui/menubar.js +7 -7
- package/dist/ui/menubar.js.map +1 -1
- package/dist/ui/navigation-menu.js +1 -1
- package/dist/ui/navigation-menu.js.map +1 -1
- package/dist/ui/number-input.d.ts.map +1 -1
- package/dist/ui/number-input.js +6 -5
- package/dist/ui/number-input.js.map +1 -1
- package/dist/ui/pagination.js +1 -1
- package/dist/ui/pagination.js.map +1 -1
- package/dist/ui/progress-ring.js +3 -3
- package/dist/ui/progress-ring.js.map +1 -1
- package/dist/ui/progress.js +2 -2
- package/dist/ui/progress.js.map +1 -1
- package/dist/ui/segmented-control.js +3 -3
- package/dist/ui/segmented-control.js.map +1 -1
- package/dist/ui/select.d.ts.map +1 -1
- package/dist/ui/select.js +7 -6
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/sheet.js +2 -2
- package/dist/ui/sheet.js.map +1 -1
- package/dist/ui/sidebar.js +7 -7
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/split-button.js +6 -6
- package/dist/ui/split-button.js.map +1 -1
- package/dist/ui/stat-card.d.ts +1 -1
- package/dist/ui/stat-card.js +7 -7
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/stepper.js +3 -3
- package/dist/ui/stepper.js.map +1 -1
- package/dist/ui/table.js +3 -3
- package/dist/ui/table.js.map +1 -1
- package/dist/ui/tabs.js +3 -3
- package/dist/ui/tabs.js.map +1 -1
- package/dist/ui/text.d.ts.map +1 -1
- package/dist/ui/text.js.map +1 -1
- package/dist/ui/textarea.d.ts.map +1 -1
- package/dist/ui/textarea.js +7 -6
- package/dist/ui/textarea.js.map +1 -1
- package/dist/ui/toast.js +11 -11
- package/dist/ui/toast.js.map +1 -1
- package/dist/ui/toggle.js +3 -3
- package/dist/ui/toggle.js.map +1 -1
- package/dist/ui/tooltip.js +1 -1
- package/dist/ui/tooltip.js.map +1 -1
- package/docs/components/composed/diff.md +50 -0
- package/docs/components/ui/data-table.md +2 -2
- package/llms.txt +2 -1
- package/mcp-manifest.json +147 -3
- package/package.json +8 -1
- package/skill/SKILL.md +1 -1
- package/skill/references/components.md +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation-menu.js","names":[],"sources":["../../src/ui/navigation-menu.tsx"],"sourcesContent":["'use client'\n\nimport * as NavigationMenuPrimitive from '@primitives/react-navigation-menu'\nimport { IconChevronDown } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Icon } from './icon'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst NavigationMenu = React.forwardRef<\n React.ElementRef<typeof NavigationMenuPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>\n>(({ className, children, ...props }, ref) => (\n <NavigationMenuPrimitive.Root\n ref={ref}\n className={cn(\n 'relative z-raised flex max-w-max flex-1 items-center justify-center',\n className,\n )}\n {...props}\n >\n {children}\n <NavigationMenuViewport />\n </NavigationMenuPrimitive.Root>\n))\nNavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName\n\nconst NavigationMenuList = React.forwardRef<\n React.ElementRef<typeof NavigationMenuPrimitive.List>,\n React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>\n>(({ className, ...props }, ref) => (\n <NavigationMenuPrimitive.List\n ref={ref}\n className={cn(\n 'group flex flex-1 list-none items-center justify-center space-x-ds-02',\n className,\n )}\n {...props}\n />\n))\nNavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName\n\nconst NavigationMenuItem = NavigationMenuPrimitive.Item\n\nconst NavigationMenuTrigger = React.forwardRef<\n React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <NavigationMenuPrimitive.Trigger\n ref={ref}\n className={cn(\n 'group inline-flex h-ds-sm-plus w-max items-center justify-center rounded-control bg-transparent px-ds-05 py-ds-03 text-ds-md font-medium transition-colors hover:bg-surface-raised-hover focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 disabled:pointer-events-none disabled:opacity-action-disabled',\n className,\n )}\n {...props}\n >\n {children}{' '}\n <Icon icon={IconChevronDown} size=\"sm\" className=\"relative top-[1px] ml-ds-02 transition-transform duration-moderate-02 group-data-[state=open]:rotate-180\" />\n </NavigationMenuPrimitive.Trigger>\n))\nNavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName\n\n// ── NavigationMenuContent — directional slide using data-motion ──\n\nconst contentSlideVariants = {\n 'from-start': { x: '-13rem', opacity: 0 },\n 'from-end': { x: '13rem', opacity: 0 },\n 'to-start': { x: '-13rem', opacity: 0 },\n 'to-end': { x: '13rem', opacity: 0 },\n center: { x: 0, opacity: 1 },\n} as const\n\nconst NavigationMenuContent = React.forwardRef<\n React.ElementRef<typeof NavigationMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>\n>(({ className, ...props }, ref) => {\n const innerRef = React.useRef<HTMLDivElement>(null)\n const composedRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n (innerRef as React.MutableRefObject<HTMLDivElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n },\n [ref],\n )\n\n const [motionDir, setMotionDir] = React.useState<string | null>(null)\n\n // Observe data-motion attribute changes from Radix\n React.useEffect(() => {\n const el = innerRef.current\n if (!el) return\n\n // Read initial value\n const initial = el.getAttribute('data-motion')\n if (initial) setMotionDir(initial)\n\n const observer = new MutationObserver((mutations) => {\n for (const m of mutations) {\n if (m.attributeName === 'data-motion') {\n const val = el.getAttribute('data-motion')\n setMotionDir(val)\n }\n }\n })\n observer.observe(el, { attributes: true, attributeFilter: ['data-motion'] })\n return () => observer.disconnect()\n }, [])\n\n const initial = motionDir && motionDir.startsWith('from-')\n ? contentSlideVariants[motionDir as keyof typeof contentSlideVariants]\n : motionDir && motionDir.startsWith('to-')\n ? contentSlideVariants.center\n : { x: 0, opacity: 0 }\n\n const animate = motionDir && motionDir.startsWith('from-')\n ? contentSlideVariants.center\n : motionDir && motionDir.startsWith('to-')\n ? contentSlideVariants[motionDir as keyof typeof contentSlideVariants]\n : contentSlideVariants.center\n\n return (\n <NavigationMenuPrimitive.Content\n ref={composedRef}\n className={cn(\n 'left-0 top-0 w-full md:absolute md:w-auto',\n className,\n )}\n {...props}\n >\n <motion.div\n key={motionDir}\n initial={initial}\n animate={animate}\n transition={{ ...springs.smooth, opacity: tweens.fade }}\n className=\"w-full\"\n >\n {props.children}\n </motion.div>\n </NavigationMenuPrimitive.Content>\n )\n})\nNavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName\n\nconst NavigationMenuLink = NavigationMenuPrimitive.Link\n\n// ── NavigationMenuViewport — scale + fade with layout for size changes ──\n\nconst NavigationMenuViewport = React.forwardRef<\n React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,\n React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>\n>(({ className, ...props }, ref) => {\n const innerRef = React.useRef<HTMLDivElement>(null)\n const composedRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n (innerRef as React.MutableRefObject<HTMLDivElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n },\n [ref],\n )\n\n const [isOpen, setIsOpen] = React.useState(false)\n\n React.useEffect(() => {\n const el = innerRef.current\n if (!el) return\n\n const initial = el.getAttribute('data-state')\n setIsOpen(initial === 'open')\n\n const observer = new MutationObserver((mutations) => {\n for (const m of mutations) {\n if (m.attributeName === 'data-state') {\n setIsOpen(el.getAttribute('data-state') === 'open')\n }\n }\n })\n observer.observe(el, { attributes: true, attributeFilter: ['data-state'] })\n return () => observer.disconnect()\n }, [])\n\n return (\n <div className={cn('absolute left-0 top-full flex justify-center')}>\n <NavigationMenuPrimitive.Viewport\n className={cn(\n 'origin-top-center relative mt-ds-02b h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-overlay bg-surface-overlay shadow-floating md:w-[var(--radix-navigation-menu-viewport-width)]',\n className,\n )}\n ref={composedRef}\n {...props}\n />\n {/* Overlay motion element for scale+fade animation */}\n <motion.div\n aria-hidden\n className=\"absolute inset-0 pointer-events-none\"\n initial={false}\n animate={isOpen ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.95 }}\n transition={{ ...springs.smooth, opacity: tweens.fade }}\n />\n </div>\n )\n})\nNavigationMenuViewport.displayName =\n NavigationMenuPrimitive.Viewport.displayName\n\n// ── NavigationMenuIndicator — fade + layout position sliding ──\n\nconst NavigationMenuIndicator = React.forwardRef<\n React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,\n React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>\n>(({ className, ...props }, ref) => {\n const innerRef = React.useRef<HTMLDivElement>(null)\n const composedRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n (innerRef as React.MutableRefObject<HTMLDivElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n },\n [ref],\n )\n\n const [isVisible, setIsVisible] = React.useState(false)\n\n React.useEffect(() => {\n const el = innerRef.current\n if (!el) return\n\n const initial = el.getAttribute('data-state')\n setIsVisible(initial === 'visible')\n\n const observer = new MutationObserver((mutations) => {\n for (const m of mutations) {\n if (m.attributeName === 'data-state') {\n setIsVisible(el.getAttribute('data-state') === 'visible')\n }\n }\n })\n observer.observe(el, { attributes: true, attributeFilter: ['data-state'] })\n return () => observer.disconnect()\n }, [])\n\n return (\n <NavigationMenuPrimitive.Indicator\n ref={composedRef}\n className={cn(\n 'top-full z-base flex h-ds-02b items-end justify-center overflow-hidden',\n className,\n )}\n {...props}\n >\n <motion.div\n layout\n initial={false}\n animate={isVisible ? { opacity: 1 } : { opacity: 0 }}\n transition={tweens.fade}\n className=\"relative top-[60%] h-2 w-2 rotate-45 rounded-tl-control-inner bg-surface-border shadow-raised-hover\"\n />\n </NavigationMenuPrimitive.Indicator>\n )\n})\nNavigationMenuIndicator.displayName =\n NavigationMenuPrimitive.Indicator.displayName\n\nexport type NavigationMenuProps = React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>\nexport type NavigationMenuContentProps = React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>\n\nexport {\n NavigationMenu,\n NavigationMenuContent,\n NavigationMenuIndicator,\n NavigationMenuItem,\n NavigationMenuLink,\n NavigationMenuList,\n NavigationMenuTrigger,\n NavigationMenuViewport,\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"navigation-menu.js","names":[],"sources":["../../src/ui/navigation-menu.tsx"],"sourcesContent":["'use client'\n\nimport * as NavigationMenuPrimitive from '@primitives/react-navigation-menu'\nimport { IconChevronDown } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Icon } from './icon'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst NavigationMenu = React.forwardRef<\n React.ElementRef<typeof NavigationMenuPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>\n>(({ className, children, ...props }, ref) => (\n <NavigationMenuPrimitive.Root\n ref={ref}\n className={cn(\n 'relative z-raised flex max-w-max flex-1 items-center justify-center',\n className,\n )}\n {...props}\n >\n {children}\n <NavigationMenuViewport />\n </NavigationMenuPrimitive.Root>\n))\nNavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName\n\nconst NavigationMenuList = React.forwardRef<\n React.ElementRef<typeof NavigationMenuPrimitive.List>,\n React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>\n>(({ className, ...props }, ref) => (\n <NavigationMenuPrimitive.List\n ref={ref}\n className={cn(\n 'group flex flex-1 list-none items-center justify-center space-x-ds-02',\n className,\n )}\n {...props}\n />\n))\nNavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName\n\nconst NavigationMenuItem = NavigationMenuPrimitive.Item\n\nconst NavigationMenuTrigger = React.forwardRef<\n React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <NavigationMenuPrimitive.Trigger\n ref={ref}\n className={cn(\n 'group inline-flex h-ds-sm-plus w-max items-center justify-center rounded-control bg-transparent px-ds-05 py-ds-03 text-body-md font-medium transition-colors hover:bg-surface-raised-hover focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 disabled:pointer-events-none disabled:opacity-action-disabled',\n className,\n )}\n {...props}\n >\n {children}{' '}\n <Icon icon={IconChevronDown} size=\"sm\" className=\"relative top-[1px] ml-ds-02 transition-transform duration-moderate-02 group-data-[state=open]:rotate-180\" />\n </NavigationMenuPrimitive.Trigger>\n))\nNavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName\n\n// ── NavigationMenuContent — directional slide using data-motion ──\n\nconst contentSlideVariants = {\n 'from-start': { x: '-13rem', opacity: 0 },\n 'from-end': { x: '13rem', opacity: 0 },\n 'to-start': { x: '-13rem', opacity: 0 },\n 'to-end': { x: '13rem', opacity: 0 },\n center: { x: 0, opacity: 1 },\n} as const\n\nconst NavigationMenuContent = React.forwardRef<\n React.ElementRef<typeof NavigationMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>\n>(({ className, ...props }, ref) => {\n const innerRef = React.useRef<HTMLDivElement>(null)\n const composedRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n (innerRef as React.MutableRefObject<HTMLDivElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n },\n [ref],\n )\n\n const [motionDir, setMotionDir] = React.useState<string | null>(null)\n\n // Observe data-motion attribute changes from Radix\n React.useEffect(() => {\n const el = innerRef.current\n if (!el) return\n\n // Read initial value\n const initial = el.getAttribute('data-motion')\n if (initial) setMotionDir(initial)\n\n const observer = new MutationObserver((mutations) => {\n for (const m of mutations) {\n if (m.attributeName === 'data-motion') {\n const val = el.getAttribute('data-motion')\n setMotionDir(val)\n }\n }\n })\n observer.observe(el, { attributes: true, attributeFilter: ['data-motion'] })\n return () => observer.disconnect()\n }, [])\n\n const initial = motionDir && motionDir.startsWith('from-')\n ? contentSlideVariants[motionDir as keyof typeof contentSlideVariants]\n : motionDir && motionDir.startsWith('to-')\n ? contentSlideVariants.center\n : { x: 0, opacity: 0 }\n\n const animate = motionDir && motionDir.startsWith('from-')\n ? contentSlideVariants.center\n : motionDir && motionDir.startsWith('to-')\n ? contentSlideVariants[motionDir as keyof typeof contentSlideVariants]\n : contentSlideVariants.center\n\n return (\n <NavigationMenuPrimitive.Content\n ref={composedRef}\n className={cn(\n 'left-0 top-0 w-full md:absolute md:w-auto',\n className,\n )}\n {...props}\n >\n <motion.div\n key={motionDir}\n initial={initial}\n animate={animate}\n transition={{ ...springs.smooth, opacity: tweens.fade }}\n className=\"w-full\"\n >\n {props.children}\n </motion.div>\n </NavigationMenuPrimitive.Content>\n )\n})\nNavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName\n\nconst NavigationMenuLink = NavigationMenuPrimitive.Link\n\n// ── NavigationMenuViewport — scale + fade with layout for size changes ──\n\nconst NavigationMenuViewport = React.forwardRef<\n React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,\n React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>\n>(({ className, ...props }, ref) => {\n const innerRef = React.useRef<HTMLDivElement>(null)\n const composedRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n (innerRef as React.MutableRefObject<HTMLDivElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n },\n [ref],\n )\n\n const [isOpen, setIsOpen] = React.useState(false)\n\n React.useEffect(() => {\n const el = innerRef.current\n if (!el) return\n\n const initial = el.getAttribute('data-state')\n setIsOpen(initial === 'open')\n\n const observer = new MutationObserver((mutations) => {\n for (const m of mutations) {\n if (m.attributeName === 'data-state') {\n setIsOpen(el.getAttribute('data-state') === 'open')\n }\n }\n })\n observer.observe(el, { attributes: true, attributeFilter: ['data-state'] })\n return () => observer.disconnect()\n }, [])\n\n return (\n <div className={cn('absolute left-0 top-full flex justify-center')}>\n <NavigationMenuPrimitive.Viewport\n className={cn(\n 'origin-top-center relative mt-ds-02b h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-overlay bg-surface-overlay shadow-floating md:w-[var(--radix-navigation-menu-viewport-width)]',\n className,\n )}\n ref={composedRef}\n {...props}\n />\n {/* Overlay motion element for scale+fade animation */}\n <motion.div\n aria-hidden\n className=\"absolute inset-0 pointer-events-none\"\n initial={false}\n animate={isOpen ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.95 }}\n transition={{ ...springs.smooth, opacity: tweens.fade }}\n />\n </div>\n )\n})\nNavigationMenuViewport.displayName =\n NavigationMenuPrimitive.Viewport.displayName\n\n// ── NavigationMenuIndicator — fade + layout position sliding ──\n\nconst NavigationMenuIndicator = React.forwardRef<\n React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,\n React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>\n>(({ className, ...props }, ref) => {\n const innerRef = React.useRef<HTMLDivElement>(null)\n const composedRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n (innerRef as React.MutableRefObject<HTMLDivElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n },\n [ref],\n )\n\n const [isVisible, setIsVisible] = React.useState(false)\n\n React.useEffect(() => {\n const el = innerRef.current\n if (!el) return\n\n const initial = el.getAttribute('data-state')\n setIsVisible(initial === 'visible')\n\n const observer = new MutationObserver((mutations) => {\n for (const m of mutations) {\n if (m.attributeName === 'data-state') {\n setIsVisible(el.getAttribute('data-state') === 'visible')\n }\n }\n })\n observer.observe(el, { attributes: true, attributeFilter: ['data-state'] })\n return () => observer.disconnect()\n }, [])\n\n return (\n <NavigationMenuPrimitive.Indicator\n ref={composedRef}\n className={cn(\n 'top-full z-base flex h-ds-02b items-end justify-center overflow-hidden',\n className,\n )}\n {...props}\n >\n <motion.div\n layout\n initial={false}\n animate={isVisible ? { opacity: 1 } : { opacity: 0 }}\n transition={tweens.fade}\n className=\"relative top-[60%] h-2 w-2 rotate-45 rounded-tl-control-inner bg-surface-border shadow-raised-hover\"\n />\n </NavigationMenuPrimitive.Indicator>\n )\n})\nNavigationMenuIndicator.displayName =\n NavigationMenuPrimitive.Indicator.displayName\n\nexport type NavigationMenuProps = React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>\nexport type NavigationMenuContentProps = React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>\n\nexport {\n NavigationMenu,\n NavigationMenuContent,\n NavigationMenuIndicator,\n NavigationMenuItem,\n NavigationMenuLink,\n NavigationMenuList,\n NavigationMenuTrigger,\n NavigationMenuViewport,\n}\n"],"mappings":";;;;;;;;;;AAWA,IAAM,IAAiB,EAAM,YAG1B,EAAE,cAAW,aAAU,GAAG,KAAS,MACpC,kBAAC,GAAD;CACO;CACL,WAAW,EACT,uEACA,CACF;CACA,GAAI;WANN,CAQG,GACD,kBAAC,GAAD,CAAyB,CAAA,CACG;EAC/B;AACD,EAAe,cAAA,EAA2C;AAE1D,IAAM,IAAqB,EAAM,YAG9B,EAAE,cAAW,GAAG,KAAS,MAC1B,kBAAC,GAAD;CACO;CACL,WAAW,EACT,yEACA,CACF;CACA,GAAI;AACL,CAAA,CACF;AACD,EAAmB,cAAA,EAA2C;AAE9D,IAAM,IAAqB,GAErB,IAAwB,EAAM,YAGjC,EAAE,cAAW,aAAU,GAAG,KAAS,MACpC,kBAAC,GAAD;CACO;CACL,WAAW,EACT,0UACA,CACF;CACA,GAAI;WANN;EAQG;EAAU;EACX,kBAAC,GAAD;GAAM,MAAM;GAAiB,MAAK;GAAK,WAAU;EAA4G,CAAA;CAC9H;EAClC;AACD,EAAsB,cAAA,EAA8C;AAIpE,IAAM,IAAuB;CAC3B,cAAc;EAAE,GAAG;EAAU,SAAS;CAAE;CACxC,YAAY;EAAE,GAAG;EAAS,SAAS;CAAE;CACrC,YAAY;EAAE,GAAG;EAAU,SAAS;CAAE;CACtC,UAAU;EAAE,GAAG;EAAS,SAAS;CAAE;CACnC,QAAQ;EAAE,GAAG;EAAG,SAAS;CAAE;AAC7B,GAEM,IAAwB,EAAM,YAGjC,EAAE,cAAW,GAAG,KAAS,MAAQ;CAClC,IAAM,IAAW,EAAM,OAAuB,IAAI,GAC5C,IAAc,EAAM,aACvB,MAAgC;EAE/B,AADA,EAA4D,UAAU,GAClE,OAAO,KAAQ,aAAY,EAAI,CAAI,IAC9B,MAAK,EAAuD,UAAU;CACjF,GACA,CAAC,CAAG,CACN,GAEM,CAAC,GAAW,KAAgB,EAAM,SAAwB,IAAI;CAGpE,EAAM,gBAAgB;EACpB,IAAM,IAAK,EAAS;EACpB,IAAI,CAAC,GAAI;EAGT,IAAM,IAAU,EAAG,aAAa,aAAa;EAC7C,AAAI,KAAS,EAAa,CAAO;EAEjC,IAAM,IAAW,IAAI,kBAAkB,MAAc;GACnD,KAAK,IAAM,KAAK,GACd,IAAI,EAAE,kBAAkB,eAAe;IACrC,IAAM,IAAM,EAAG,aAAa,aAAa;IACzC,EAAa,CAAG;GAClB;EAEJ,CAAC;EAED,OADA,EAAS,QAAQ,GAAI;GAAE,YAAY;GAAM,iBAAiB,CAAC,aAAa;EAAE,CAAC,SAC9D,EAAS,WAAW;CACnC,GAAG,CAAC,CAAC;CAEL,IAAM,IAAU,KAAa,EAAU,WAAW,OAAO,IACrD,EAAqB,KACrB,KAAa,EAAU,WAAW,KAAK,IACrC,EAAqB,SACrB;EAAE,GAAG;EAAG,SAAS;CAAE,GAEnB,IAAU,KAAa,EAAU,WAAW,OAAO,IACrD,EAAqB,SACrB,KAAa,EAAU,WAAW,KAAK,IACrC,EAAqB,KACrB,EAAqB;CAE3B,OACE,kBAAC,GAAD;EACE,KAAK;EACL,WAAW,EACT,6CACA,CACF;EACA,GAAI;YAEJ,kBAAC,EAAO,KAAR;GAEW;GACA;GACT,YAAY;IAAE,GAAG,EAAQ;IAAQ,SAAS,EAAO;GAAK;GACtD,WAAU;aAET,EAAM;EACG,GAPL,CAOK;CACmB,CAAA;AAErC,CAAC;AACD,EAAsB,cAAA,EAA8C;AAEpE,IAAM,IAAqB,GAIrB,IAAyB,EAAM,YAGlC,EAAE,cAAW,GAAG,KAAS,MAAQ;CAClC,IAAM,IAAW,EAAM,OAAuB,IAAI,GAC5C,IAAc,EAAM,aACvB,MAAgC;EAE/B,AADA,EAA4D,UAAU,GAClE,OAAO,KAAQ,aAAY,EAAI,CAAI,IAC9B,MAAK,EAAuD,UAAU;CACjF,GACA,CAAC,CAAG,CACN,GAEM,CAAC,GAAQ,KAAa,EAAM,SAAS,EAAK;CAoBhD,OAlBA,EAAM,gBAAgB;EACpB,IAAM,IAAK,EAAS;EACpB,IAAI,CAAC,GAAI;EAET,IAAM,IAAU,EAAG,aAAa,YAAY;EAC5C,EAAU,MAAY,MAAM;EAE5B,IAAM,IAAW,IAAI,kBAAkB,MAAc;GACnD,KAAK,IAAM,KAAK,GACd,AAAI,EAAE,kBAAkB,gBACtB,EAAU,EAAG,aAAa,YAAY,MAAM,MAAM;EAGxD,CAAC;EAED,OADA,EAAS,QAAQ,GAAI;GAAE,YAAY;GAAM,iBAAiB,CAAC,YAAY;EAAE,CAAC,SAC7D,EAAS,WAAW;CACnC,GAAG,CAAC,CAAC,GAGH,kBAAC,OAAD;EAAK,WAAW,EAAG,8CAA8C;YAAjE,CACE,kBAAC,GAAD;GACE,WAAW,EACT,sNACA,CACF;GACA,KAAK;GACL,GAAI;EACL,CAAA,GAED,kBAAC,EAAO,KAAR;GACE,eAAA;GACA,WAAU;GACV,SAAS;GACT,SAAS,IAAS;IAAE,SAAS;IAAG,OAAO;GAAE,IAAI;IAAE,SAAS;IAAG,OAAO;GAAK;GACvE,YAAY;IAAE,GAAG,EAAQ;IAAQ,SAAS,EAAO;GAAK;EACvD,CAAA,CACE;;AAET,CAAC;AACD,EAAuB,cAAA,EACY;AAInC,IAAM,IAA0B,EAAM,YAGnC,EAAE,cAAW,GAAG,KAAS,MAAQ;CAClC,IAAM,IAAW,EAAM,OAAuB,IAAI,GAC5C,IAAc,EAAM,aACvB,MAAgC;EAE/B,AADA,EAA4D,UAAU,GAClE,OAAO,KAAQ,aAAY,EAAI,CAAI,IAC9B,MAAK,EAAuD,UAAU;CACjF,GACA,CAAC,CAAG,CACN,GAEM,CAAC,GAAW,KAAgB,EAAM,SAAS,EAAK;CAoBtD,OAlBA,EAAM,gBAAgB;EACpB,IAAM,IAAK,EAAS;EACpB,IAAI,CAAC,GAAI;EAET,IAAM,IAAU,EAAG,aAAa,YAAY;EAC5C,EAAa,MAAY,SAAS;EAElC,IAAM,IAAW,IAAI,kBAAkB,MAAc;GACnD,KAAK,IAAM,KAAK,GACd,AAAI,EAAE,kBAAkB,gBACtB,EAAa,EAAG,aAAa,YAAY,MAAM,SAAS;EAG9D,CAAC;EAED,OADA,EAAS,QAAQ,GAAI;GAAE,YAAY;GAAM,iBAAiB,CAAC,YAAY;EAAE,CAAC,SAC7D,EAAS,WAAW;CACnC,GAAG,CAAC,CAAC,GAGH,kBAAC,GAAD;EACE,KAAK;EACL,WAAW,EACT,0EACA,CACF;EACA,GAAI;YAEJ,kBAAC,EAAO,KAAR;GACE,QAAA;GACA,SAAS;GACT,SAAS,IAAY,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;GACnD,YAAY,EAAO;GACnB,WAAU;EACX,CAAA;CACgC,CAAA;AAEvC,CAAC;AACD,EAAwB,cAAA,EACY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"number-input.d.ts","sourceRoot":"","sources":["../../src/ui/number-input.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,OAAO,EAAE,KAAK,UAAU,EAAqB,MAAM,mBAAmB,CAAA;AAGtE,sFAAsF;AACtF,MAAM,MAAM,gBAAgB,GAAG,UAAU,CAAA;AAEzC,QAAA,MAAM,0BAA0B;;8EAa/B,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;AAkClG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;IACjI,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0EAA0E;IAC1E,IAAI,CAAC,EAAE,eAAe,CAAA;IACtB,iDAAiD;IACjD,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB;AAED,QAAA,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"number-input.d.ts","sourceRoot":"","sources":["../../src/ui/number-input.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,OAAO,EAAE,KAAK,UAAU,EAAqB,MAAM,mBAAmB,CAAA;AAGtE,sFAAsF;AACtF,MAAM,MAAM,gBAAgB,GAAG,UAAU,CAAA;AAEzC,QAAA,MAAM,0BAA0B;;8EAa/B,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;AAkClG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;IACjI,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0EAA0E;IAC1E,IAAI,CAAC,EAAE,eAAe,CAAA;IACtB,iDAAiD;IACjD,KAAK,CAAC,EAAE,UAAU,CAAA;CACnB;AAED,QAAA,MAAM,WAAW,2FAqHhB,CAAA;AAGD,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,CAAA"}
|
package/dist/ui/number-input.js
CHANGED
|
@@ -27,10 +27,10 @@ var u = e("flex items-center justify-between rounded-control border border-surfa
|
|
|
27
27
|
md: "sm",
|
|
28
28
|
lg: "md"
|
|
29
29
|
}, p = {
|
|
30
|
-
xs: "text-
|
|
31
|
-
sm: "text-
|
|
32
|
-
md: "text-
|
|
33
|
-
lg: "text-
|
|
30
|
+
xs: "text-body-sm w-ds-06b",
|
|
31
|
+
sm: "text-body-sm w-ds-sm-plus",
|
|
32
|
+
md: "text-body-md w-ds-sm-plus",
|
|
33
|
+
lg: "text-body-md w-ds-md"
|
|
34
34
|
}, m = {
|
|
35
35
|
default: "",
|
|
36
36
|
error: "border-error-7",
|
|
@@ -82,7 +82,8 @@ var u = e("flex items-center justify-between rounded-control border border-surfa
|
|
|
82
82
|
"aria-invalid": O === "error" || void 0,
|
|
83
83
|
"aria-describedby": C["aria-describedby"] ?? E.helperTextId,
|
|
84
84
|
className: t("bg-transparent font-semibold border-0 text-center text-surface-fg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none", P),
|
|
85
|
-
...C
|
|
85
|
+
...C,
|
|
86
|
+
id: C.id ?? E.inputId
|
|
86
87
|
}),
|
|
87
88
|
/* @__PURE__ */ o("button", {
|
|
88
89
|
type: "button",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"number-input.js","names":[],"sources":["../../src/ui/number-input.tsx"],"sourcesContent":["'use client'\n\nimport { IconMinus, IconPlus } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { Icon } from './icon'\nimport type { IconSize } from './icon-context'\nimport { type FieldState, resolveFieldState } from './lib/field-state'\nimport { cn } from './lib/utils'\n\n/** @deprecated Use `FieldState` — the shared control-state type. Kept as an alias. */\nexport type NumberInputState = FieldState\n\nconst numberInputWrapperVariants = cva(\n 'flex items-center justify-between rounded-control border border-surface-border-strong',\n {\n variants: {\n size: {\n xs: 'h-ds-xs-plus',\n sm: 'h-ds-sm',\n md: 'h-ds-md',\n lg: 'h-ds-lg',\n },\n },\n defaultVariants: { size: 'md' },\n },\n)\n\nexport type NumberInputSize = NonNullable<VariantProps<typeof numberInputWrapperVariants>['size']>\n\n/** Maps size to stepper button dimensions */\nconst buttonSizeMap: Record<NonNullable<NumberInputSize>, string> = {\n xs: 'h-[22px] w-[22px]',\n sm: 'h-ds-sm w-ds-sm',\n md: 'h-ds-sm w-ds-sm',\n lg: 'h-ds-md w-ds-md',\n}\n\n/** Maps size to Icon component size */\nconst iconSizeMap: Record<NonNullable<NumberInputSize>, IconSize> = {\n xs: 'xs',\n sm: 'sm',\n md: 'sm',\n lg: 'md',\n}\n\n/** Maps size to input text and width classes */\nconst inputSizeMap: Record<NonNullable<NumberInputSize>, string> = {\n xs: 'text-ds-sm w-ds-06b',\n sm: 'text-ds-sm w-ds-sm-plus',\n md: 'text-ds-md w-ds-sm-plus',\n lg: 'text-ds-md w-ds-md',\n}\n\n/** Maps state to border color classes */\nconst stateColorMap: Record<NonNullable<NumberInputState>, string> = {\n default: '',\n error: 'border-error-7',\n warning: 'border-warning-7',\n success: 'border-success-7',\n}\n\n/**\n * Props for NumberInput — a stepper control with \"−\" and \"+\" buttons flanking a numeric input,\n * clamped between `min` and `max`. The decrement/increment buttons are disabled when bounds are reached.\n *\n * **Controlled only:** Pass `value` + `onValueChange` for controlled usage. Uncontrolled usage is\n * possible but the buttons won't update the displayed value without `onValueChange`.\n *\n * **Step:** The `step` prop controls how much each button press increments/decrements (default 1).\n * Direct text input is also clamped to `[min, max]` on change.\n *\n * **Sizes:** `xs` (28px) | `sm` (32px) | `md` (40px, default) | `lg` (48px)\n *\n * **Validation states:** `state=\"error\"` colors the border red.\n * Use with `<FormField>` to show helper text below the input.\n *\n * @example\n * // Quantity selector with 1–99 range:\n * <NumberInput value={qty} onValueChange={setQty} min={1} max={99} />\n *\n * @example\n * // Rating input (1–10, step 1):\n * <NumberInput value={rating} onValueChange={setRating} min={1} max={10} />\n *\n * @example\n * // Fine-grained opacity control (0–100, step 5):\n * <NumberInput value={opacity} onValueChange={setOpacity} min={0} max={100} step={5} />\n *\n * @example\n * // Disabled number display (read-only-like):\n * <NumberInput value={autoCalcValue} onValueChange={() => {}} disabled />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'type' | 'size'> {\n value?: number\n onValueChange?: (value: number) => void\n min?: number\n max?: number\n step?: number\n /** Size of the number input. Controls height, button sizes, text size. */\n size?: NumberInputSize\n /** Validation state controlling border color. */\n state?: FieldState\n}\n\nconst NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(\n (\n {\n value = 0,\n onValueChange,\n min = Number.MIN_SAFE_INTEGER,\n max = Number.MAX_SAFE_INTEGER,\n step = 1,\n disabled = false,\n className,\n size: sizeProp = 'md',\n state: stateProp,\n 'aria-label': ariaLabelProp,\n ...rest\n },\n ref,\n ) => {\n const size = sizeProp ?? 'md'\n const fieldCtx = useFormField()\n // If no explicit aria-label and not inside a FormField (no id to associate with Label),\n // provide a sensible default\n const ariaLabel = ariaLabelProp ?? (rest.id || fieldCtx.helperTextId ? undefined : 'Numeric value')\n\n // Merge FormField context — explicit props always win (shared precedence)\n const state = resolveFieldState(stateProp, fieldCtx.state) ?? 'default'\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const raw = e.target.value.trim()\n if (raw === '' || raw === '-') {\n onValueChange?.(min >= 0 ? min : 0)\n return\n }\n const parsed = Number(raw)\n if (Number.isNaN(parsed)) return\n const clamped = Math.min(Math.max(parsed, min), max)\n onValueChange?.(clamped)\n }\n\n const handleIncrement = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.preventDefault() // Prevent form submission\n const newValue = value + step\n if (newValue <= max) {\n onValueChange?.(newValue)\n }\n }\n\n const handleDecrement = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.preventDefault() // Prevent form submission\n const newValue = value - step\n if (newValue >= min) {\n onValueChange?.(newValue)\n }\n }\n\n const resolvedButtonSize = buttonSizeMap[size]\n const resolvedIconSize = iconSizeMap[size]\n const resolvedInputSize = inputSizeMap[size]\n\n return (\n <div\n className={cn(\n numberInputWrapperVariants({ size }),\n stateColorMap[state],\n className,\n )}\n >\n <button\n type=\"button\"\n onClick={handleDecrement}\n disabled={disabled || value <= min}\n aria-label=\"Decrease value\"\n title=\"Decrease\"\n className={cn(\n 'flex items-center justify-center border-0 rounded-control-inner text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg-muted active:scale-90 transition-[color,background-color,transform] duration-fast-01 ease-productive-standard disabled:opacity-action-disabled disabled:pointer-events-none',\n resolvedButtonSize,\n )}\n >\n <Icon icon={IconMinus} size={resolvedIconSize} />\n </button>\n\n <input\n ref={ref}\n type=\"number\"\n value={value}\n onChange={handleInputChange}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n aria-label={ariaLabel}\n aria-invalid={state === 'error' || undefined}\n aria-describedby={rest['aria-describedby'] ?? fieldCtx.helperTextId}\n className={cn(\n 'bg-transparent font-semibold border-0 text-center text-surface-fg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none',\n resolvedInputSize,\n )}\n {...rest}\n />\n\n <button\n type=\"button\"\n onClick={handleIncrement}\n disabled={disabled || value >= max}\n aria-label=\"Increase value\"\n title=\"Increase\"\n className={cn(\n 'flex items-center justify-center border-0 rounded-control-inner text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg-muted active:scale-90 transition-[color,background-color,transform] duration-fast-01 ease-productive-standard disabled:opacity-action-disabled disabled:pointer-events-none',\n resolvedButtonSize,\n )}\n >\n <Icon icon={IconPlus} size={resolvedIconSize} />\n </button>\n </div>\n )\n },\n)\nNumberInput.displayName = 'NumberInput'\n\nexport { NumberInput, numberInputWrapperVariants }\n"],"mappings":";;;;;;;;;;AAeA,IAAM,IAA6B,EACjC,yFACA;CACE,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN,EACF;CACA,iBAAiB,EAAE,MAAM,KAAK;AAChC,CACF,GAKM,IAA8D;CAClE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,GAGM,IAA8D;CAClE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,GAGM,IAA6D;CACjE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,GAGM,IAA+D;CACnE,SAAS;CACT,OAAO;CACP,SAAS;CACT,SAAS;AACX,GA8CM,IAAc,EAAM,YAEtB,EACE,WAAQ,GACR,kBACA,SAAM,gBACN,sBACA,UAAO,GACP,cAAW,IACX,cACA,MAAM,IAAW,MACjB,OAAO,GACP,cAAc,GACd,GAAG,KAEL,MACG;CACH,IAAM,IAAO,KAAY,MACnB,IAAW,EAAa,GAGxB,IAAY,MAAkB,EAAK,MAAM,EAAS,eAAe,KAAA,IAAY,kBAG7E,IAAQ,EAAkB,GAAW,EAAS,KAAK,KAAK,WAExD,KAAqB,MAA2C;EACpE,IAAM,IAAM,EAAE,OAAO,MAAM,KAAK;EAChC,IAAI,MAAQ,MAAM,MAAQ,KAAK;GAC7B,IAAgB,KAAO,IAAI,IAAM,CAAC;GAClC;EACF;EACA,IAAM,IAAS,OAAO,CAAG;EACrB,OAAO,MAAM,CAAM,KAEvB,IADgB,KAAK,IAAI,KAAK,IAAI,GAAQ,CAAG,GAAG,CAChC,CAAO;CACzB,GAEM,KAAmB,MAA2C;EAClE,EAAE,eAAe;EACjB,IAAM,IAAW,IAAQ;EACzB,AAAI,KAAY,KACd,IAAgB,CAAQ;CAE5B,GAEM,KAAmB,MAA2C;EAClE,EAAE,eAAe;EACjB,IAAM,IAAW,IAAQ;EACzB,AAAI,KAAY,KACd,IAAgB,CAAQ;CAE5B,GAEM,IAAqB,EAAc,IACnC,IAAmB,EAAY,IAC/B,IAAoB,EAAa;CAEvC,OACE,kBAAC,OAAD;EACE,WAAW,EACT,EAA2B,EAAE,QAAK,CAAC,GACnC,EAAc,IACd,CACF;YALF;GAOE,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,UAAU,KAAY,KAAS;IAC/B,cAAW;IACX,OAAM;IACN,WAAW,EACT,0TACA,CACF;cAEA,kBAAC,GAAD;KAAM,MAAM;KAAW,MAAM;IAAmB,CAAA;GAC1C,CAAA;GAER,kBAAC,SAAD;IACO;IACL,MAAK;IACE;IACP,UAAU;IACL;IACA;IACC;IACI;IACV,cAAY;IACZ,gBAAc,MAAU,WAAW,KAAA;IACnC,oBAAkB,EAAK,uBAAuB,EAAS;IACvD,WAAW,EACT,8QACA,CACF;IACA,GAAI;GACL,CAAA;GAED,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,UAAU,KAAY,KAAS;IAC/B,cAAW;IACX,OAAM;IACN,WAAW,EACT,0TACA,CACF;cAEA,kBAAC,GAAD;KAAM,MAAM;KAAU,MAAM;IAAmB,CAAA;GACzC,CAAA;EACL;;AAET,CACF;AACA,EAAY,cAAc"}
|
|
1
|
+
{"version":3,"file":"number-input.js","names":[],"sources":["../../src/ui/number-input.tsx"],"sourcesContent":["'use client'\n\nimport { IconMinus, IconPlus } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { Icon } from './icon'\nimport type { IconSize } from './icon-context'\nimport { type FieldState, resolveFieldState } from './lib/field-state'\nimport { cn } from './lib/utils'\n\n/** @deprecated Use `FieldState` — the shared control-state type. Kept as an alias. */\nexport type NumberInputState = FieldState\n\nconst numberInputWrapperVariants = cva(\n 'flex items-center justify-between rounded-control border border-surface-border-strong',\n {\n variants: {\n size: {\n xs: 'h-ds-xs-plus',\n sm: 'h-ds-sm',\n md: 'h-ds-md',\n lg: 'h-ds-lg',\n },\n },\n defaultVariants: { size: 'md' },\n },\n)\n\nexport type NumberInputSize = NonNullable<VariantProps<typeof numberInputWrapperVariants>['size']>\n\n/** Maps size to stepper button dimensions */\nconst buttonSizeMap: Record<NonNullable<NumberInputSize>, string> = {\n xs: 'h-[22px] w-[22px]',\n sm: 'h-ds-sm w-ds-sm',\n md: 'h-ds-sm w-ds-sm',\n lg: 'h-ds-md w-ds-md',\n}\n\n/** Maps size to Icon component size */\nconst iconSizeMap: Record<NonNullable<NumberInputSize>, IconSize> = {\n xs: 'xs',\n sm: 'sm',\n md: 'sm',\n lg: 'md',\n}\n\n/** Maps size to input text and width classes */\nconst inputSizeMap: Record<NonNullable<NumberInputSize>, string> = {\n xs: 'text-body-sm w-ds-06b',\n sm: 'text-body-sm w-ds-sm-plus',\n md: 'text-body-md w-ds-sm-plus',\n lg: 'text-body-md w-ds-md',\n}\n\n/** Maps state to border color classes */\nconst stateColorMap: Record<NonNullable<NumberInputState>, string> = {\n default: '',\n error: 'border-error-7',\n warning: 'border-warning-7',\n success: 'border-success-7',\n}\n\n/**\n * Props for NumberInput — a stepper control with \"−\" and \"+\" buttons flanking a numeric input,\n * clamped between `min` and `max`. The decrement/increment buttons are disabled when bounds are reached.\n *\n * **Controlled only:** Pass `value` + `onValueChange` for controlled usage. Uncontrolled usage is\n * possible but the buttons won't update the displayed value without `onValueChange`.\n *\n * **Step:** The `step` prop controls how much each button press increments/decrements (default 1).\n * Direct text input is also clamped to `[min, max]` on change.\n *\n * **Sizes:** `xs` (28px) | `sm` (32px) | `md` (40px, default) | `lg` (48px)\n *\n * **Validation states:** `state=\"error\"` colors the border red.\n * Use with `<FormField>` to show helper text below the input.\n *\n * @example\n * // Quantity selector with 1–99 range:\n * <NumberInput value={qty} onValueChange={setQty} min={1} max={99} />\n *\n * @example\n * // Rating input (1–10, step 1):\n * <NumberInput value={rating} onValueChange={setRating} min={1} max={10} />\n *\n * @example\n * // Fine-grained opacity control (0–100, step 5):\n * <NumberInput value={opacity} onValueChange={setOpacity} min={0} max={100} step={5} />\n *\n * @example\n * // Disabled number display (read-only-like):\n * <NumberInput value={autoCalcValue} onValueChange={() => {}} disabled />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'type' | 'size'> {\n value?: number\n onValueChange?: (value: number) => void\n min?: number\n max?: number\n step?: number\n /** Size of the number input. Controls height, button sizes, text size. */\n size?: NumberInputSize\n /** Validation state controlling border color. */\n state?: FieldState\n}\n\nconst NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(\n (\n {\n value = 0,\n onValueChange,\n min = Number.MIN_SAFE_INTEGER,\n max = Number.MAX_SAFE_INTEGER,\n step = 1,\n disabled = false,\n className,\n size: sizeProp = 'md',\n state: stateProp,\n 'aria-label': ariaLabelProp,\n ...rest\n },\n ref,\n ) => {\n const size = sizeProp ?? 'md'\n const fieldCtx = useFormField()\n // If no explicit aria-label and not inside a FormField (no id to associate with Label),\n // provide a sensible default\n const ariaLabel = ariaLabelProp ?? (rest.id || fieldCtx.helperTextId ? undefined : 'Numeric value')\n\n // Merge FormField context — explicit props always win (shared precedence)\n const state = resolveFieldState(stateProp, fieldCtx.state) ?? 'default'\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const raw = e.target.value.trim()\n if (raw === '' || raw === '-') {\n onValueChange?.(min >= 0 ? min : 0)\n return\n }\n const parsed = Number(raw)\n if (Number.isNaN(parsed)) return\n const clamped = Math.min(Math.max(parsed, min), max)\n onValueChange?.(clamped)\n }\n\n const handleIncrement = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.preventDefault() // Prevent form submission\n const newValue = value + step\n if (newValue <= max) {\n onValueChange?.(newValue)\n }\n }\n\n const handleDecrement = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.preventDefault() // Prevent form submission\n const newValue = value - step\n if (newValue >= min) {\n onValueChange?.(newValue)\n }\n }\n\n const resolvedButtonSize = buttonSizeMap[size]\n const resolvedIconSize = iconSizeMap[size]\n const resolvedInputSize = inputSizeMap[size]\n\n return (\n <div\n className={cn(\n numberInputWrapperVariants({ size }),\n stateColorMap[state],\n className,\n )}\n >\n <button\n type=\"button\"\n onClick={handleDecrement}\n disabled={disabled || value <= min}\n aria-label=\"Decrease value\"\n title=\"Decrease\"\n className={cn(\n 'flex items-center justify-center border-0 rounded-control-inner text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg-muted active:scale-90 transition-[color,background-color,transform] duration-fast-01 ease-productive-standard disabled:opacity-action-disabled disabled:pointer-events-none',\n resolvedButtonSize,\n )}\n >\n <Icon icon={IconMinus} size={resolvedIconSize} />\n </button>\n\n <input\n ref={ref}\n type=\"number\"\n value={value}\n onChange={handleInputChange}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n aria-label={ariaLabel}\n aria-invalid={state === 'error' || undefined}\n aria-describedby={rest['aria-describedby'] ?? fieldCtx.helperTextId}\n className={cn(\n 'bg-transparent font-semibold border-0 text-center text-surface-fg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none',\n resolvedInputSize,\n )}\n {...rest}\n // Explicit id wins; otherwise adopt FormField's inputId so <Label htmlFor> resolves.\n id={rest.id ?? fieldCtx.inputId}\n />\n\n <button\n type=\"button\"\n onClick={handleIncrement}\n disabled={disabled || value >= max}\n aria-label=\"Increase value\"\n title=\"Increase\"\n className={cn(\n 'flex items-center justify-center border-0 rounded-control-inner text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg-muted active:scale-90 transition-[color,background-color,transform] duration-fast-01 ease-productive-standard disabled:opacity-action-disabled disabled:pointer-events-none',\n resolvedButtonSize,\n )}\n >\n <Icon icon={IconPlus} size={resolvedIconSize} />\n </button>\n </div>\n )\n },\n)\nNumberInput.displayName = 'NumberInput'\n\nexport { NumberInput, numberInputWrapperVariants }\n"],"mappings":";;;;;;;;;;AAeA,IAAM,IAA6B,EACjC,yFACA;CACE,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN,EACF;CACA,iBAAiB,EAAE,MAAM,KAAK;AAChC,CACF,GAKM,IAA8D;CAClE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,GAGM,IAA8D;CAClE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,GAGM,IAA6D;CACjE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,GAGM,IAA+D;CACnE,SAAS;CACT,OAAO;CACP,SAAS;CACT,SAAS;AACX,GA8CM,IAAc,EAAM,YAEtB,EACE,WAAQ,GACR,kBACA,SAAM,gBACN,sBACA,UAAO,GACP,cAAW,IACX,cACA,MAAM,IAAW,MACjB,OAAO,GACP,cAAc,GACd,GAAG,KAEL,MACG;CACH,IAAM,IAAO,KAAY,MACnB,IAAW,EAAa,GAGxB,IAAY,MAAkB,EAAK,MAAM,EAAS,eAAe,KAAA,IAAY,kBAG7E,IAAQ,EAAkB,GAAW,EAAS,KAAK,KAAK,WAExD,KAAqB,MAA2C;EACpE,IAAM,IAAM,EAAE,OAAO,MAAM,KAAK;EAChC,IAAI,MAAQ,MAAM,MAAQ,KAAK;GAC7B,IAAgB,KAAO,IAAI,IAAM,CAAC;GAClC;EACF;EACA,IAAM,IAAS,OAAO,CAAG;EACrB,OAAO,MAAM,CAAM,KAEvB,IADgB,KAAK,IAAI,KAAK,IAAI,GAAQ,CAAG,GAAG,CAChC,CAAO;CACzB,GAEM,KAAmB,MAA2C;EAClE,EAAE,eAAe;EACjB,IAAM,IAAW,IAAQ;EACzB,AAAI,KAAY,KACd,IAAgB,CAAQ;CAE5B,GAEM,KAAmB,MAA2C;EAClE,EAAE,eAAe;EACjB,IAAM,IAAW,IAAQ;EACzB,AAAI,KAAY,KACd,IAAgB,CAAQ;CAE5B,GAEM,IAAqB,EAAc,IACnC,IAAmB,EAAY,IAC/B,IAAoB,EAAa;CAEvC,OACE,kBAAC,OAAD;EACE,WAAW,EACT,EAA2B,EAAE,QAAK,CAAC,GACnC,EAAc,IACd,CACF;YALF;GAOE,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,UAAU,KAAY,KAAS;IAC/B,cAAW;IACX,OAAM;IACN,WAAW,EACT,0TACA,CACF;cAEA,kBAAC,GAAD;KAAM,MAAM;KAAW,MAAM;IAAmB,CAAA;GAC1C,CAAA;GAER,kBAAC,SAAD;IACO;IACL,MAAK;IACE;IACP,UAAU;IACL;IACA;IACC;IACI;IACV,cAAY;IACZ,gBAAc,MAAU,WAAW,KAAA;IACnC,oBAAkB,EAAK,uBAAuB,EAAS;IACvD,WAAW,EACT,8QACA,CACF;IACA,GAAI;IAEJ,IAAI,EAAK,MAAM,EAAS;GACzB,CAAA;GAED,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,UAAU,KAAY,KAAS;IAC/B,cAAW;IACX,OAAM;IACN,WAAW,EACT,0TACA,CACF;cAEA,kBAAC,GAAD;KAAM,MAAM;KAAU,MAAM;IAAmB,CAAA;GACzC,CAAA;EACL;;AAET,CACF;AACA,EAAY,cAAc"}
|
package/dist/ui/pagination.js
CHANGED
|
@@ -29,7 +29,7 @@ d.displayName = "PaginationItem";
|
|
|
29
29
|
var f = r.forwardRef(({ className: n, isActive: r = !1, asChild: a = !1, ...o }, s) => /* @__PURE__ */ i(a ? e : "button", {
|
|
30
30
|
ref: s,
|
|
31
31
|
"aria-current": r ? "page" : void 0,
|
|
32
|
-
className: t("inline-flex items-center justify-center h-ds-sm-plus w-ds-sm-plus rounded-control text-
|
|
32
|
+
className: t("inline-flex items-center justify-center h-ds-sm-plus w-ds-sm-plus rounded-control text-body-md font-medium tabular-nums transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-action-disabled active:scale-95", r ? "bg-accent-9 text-accent-fg" : "hover:bg-surface-raised-hover text-surface-fg", n),
|
|
33
33
|
...o
|
|
34
34
|
}));
|
|
35
35
|
f.displayName = "PaginationLink";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.js","names":[],"sources":["../../src/ui/pagination.tsx"],"sourcesContent":["'use client'\n\nimport { Slot } from '@primitives/react-slot'\nimport { IconChevronLeft, IconChevronRight, IconDots } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\n\nconst PaginationRoot = React.forwardRef<\n HTMLElement,\n React.ComponentPropsWithoutRef<'nav'>\n>(({ className, ...props }, ref) => (\n <nav\n ref={ref}\n role=\"navigation\"\n aria-label=\"pagination\"\n className={cn('mx-auto flex w-full justify-center', className)}\n {...props}\n />\n))\nPaginationRoot.displayName = 'PaginationRoot'\n\nconst PaginationContent = React.forwardRef<\n HTMLUListElement,\n React.ComponentPropsWithoutRef<'ul'>\n>(({ className, ...props }, ref) => (\n <ul\n ref={ref}\n className={cn('flex flex-row items-center gap-ds-02', className)}\n {...props}\n />\n))\nPaginationContent.displayName = 'PaginationContent'\n\nconst PaginationItem = React.forwardRef<\n HTMLLIElement,\n React.ComponentPropsWithoutRef<'li'>\n>(({ className, ...props }, ref) => (\n <li ref={ref} className={cn('', className)} {...props} />\n))\nPaginationItem.displayName = 'PaginationItem'\n\n/**\n * Props for PaginationLink — a single page number button in a pagination row.\n * When `isActive` is true, the button gets the brand interactive fill and `aria-current=\"page\"`.\n *\n * @example\n * // Active page button:\n * <PaginationLink isActive onClick={() => goToPage(3)}>3</PaginationLink>\n *\n * @example\n * // Render as a Next.js Link via asChild:\n * <PaginationLink asChild isActive={currentPage === 5}>\n * <Link href=\"/posts?page=5\">5</Link>\n * </PaginationLink>\n */\nexport interface PaginationLinkProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n isActive?: boolean\n asChild?: boolean\n}\n\nconst PaginationLink = React.forwardRef<HTMLButtonElement, PaginationLinkProps>(\n ({ className, isActive = false, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : 'button'\n return (\n <Comp\n ref={ref}\n aria-current={isActive ? 'page' : undefined}\n className={cn(\n 'inline-flex items-center justify-center h-ds-sm-plus w-ds-sm-plus rounded-control text-ds-md font-medium tabular-nums transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-action-disabled active:scale-95',\n isActive\n ? 'bg-accent-9 text-accent-fg'\n : 'hover:bg-surface-raised-hover text-surface-fg',\n className,\n )}\n {...props}\n />\n )\n },\n)\nPaginationLink.displayName = 'PaginationLink'\n\nconst PaginationPrevious = React.forwardRef<\n HTMLButtonElement,\n PaginationLinkProps\n>(({ className, ...props }, ref) => (\n <PaginationLink\n ref={ref}\n aria-label=\"Go to previous page\"\n className={cn('w-auto gap-ds-02 pl-ds-03 pr-ds-04', className)}\n {...props}\n >\n <Icon icon={IconChevronLeft} size=\"sm\" />\n <span>Previous</span>\n </PaginationLink>\n))\nPaginationPrevious.displayName = 'PaginationPrevious'\n\nconst PaginationNext = React.forwardRef<\n HTMLButtonElement,\n PaginationLinkProps\n>(({ className, ...props }, ref) => (\n <PaginationLink\n ref={ref}\n aria-label=\"Go to next page\"\n className={cn('w-auto gap-ds-02 pl-ds-04 pr-ds-03', className)}\n {...props}\n >\n <span>Next</span>\n <Icon icon={IconChevronRight} size=\"sm\" />\n </PaginationLink>\n))\nPaginationNext.displayName = 'PaginationNext'\n\nconst PaginationEllipsis = React.forwardRef<\n HTMLSpanElement,\n React.ComponentPropsWithoutRef<'span'>\n>(({ className, ...props }, ref) => (\n <span\n ref={ref}\n aria-hidden=\"true\"\n className={cn(\n 'flex h-ds-sm-plus w-ds-sm-plus items-center justify-center text-surface-fg-muted',\n className,\n )}\n {...props}\n >\n <Icon icon={IconDots} size=\"sm\" />\n <span className=\"sr-only\">More pages</span>\n </span>\n))\nPaginationEllipsis.displayName = 'PaginationEllipsis'\n\n/* ------------------------------------------------------------------ */\n/* generatePagination helper */\n/* ------------------------------------------------------------------ */\n\ntype PageItem = number | 'ellipsis'\n\n/**\n * Pure function that builds an array of page numbers and ellipsis markers.\n * Always shows first and last page, plus `siblingCount` pages around `current`.\n *\n * @example generatePagination(5, 10, 1) → [1, 'ellipsis', 4, 5, 6, 'ellipsis', 10]\n */\nfunction generatePagination(\n current: number,\n total: number,\n siblingCount: number,\n): PageItem[] {\n // When total pages fit without any ellipsis\n const totalSlots = siblingCount * 2 + 5 // first + last + current + 2*siblings + 2 ellipsis slots\n if (total <= totalSlots) {\n return Array.from({ length: total }, (_, i) => i + 1)\n }\n\n const leftSibling = Math.max(current - siblingCount, 1)\n const rightSibling = Math.min(current + siblingCount, total)\n\n const showLeftEllipsis = leftSibling > 2\n const showRightEllipsis = rightSibling < total - 1\n\n if (!showLeftEllipsis && showRightEllipsis) {\n // e.g. [1, 2, 3, 4, 5, '...', 10]\n const leftCount = siblingCount * 2 + 3\n const leftPages = Array.from({ length: leftCount }, (_, i) => i + 1)\n return [...leftPages, 'ellipsis', total]\n }\n\n if (showLeftEllipsis && !showRightEllipsis) {\n // e.g. [1, '...', 6, 7, 8, 9, 10]\n const rightCount = siblingCount * 2 + 3\n const rightPages = Array.from(\n { length: rightCount },\n (_, i) => total - rightCount + 1 + i,\n )\n return [1, 'ellipsis', ...rightPages]\n }\n\n // Both ellipses: [1, '...', 4, 5, 6, '...', 10]\n const middlePages = Array.from(\n { length: rightSibling - leftSibling + 1 },\n (_, i) => leftSibling + i,\n )\n return [1, 'ellipsis', ...middlePages, 'ellipsis', total]\n}\n\n/* ------------------------------------------------------------------ */\n/* PaginationNav — controlled convenience wrapper */\n/* ------------------------------------------------------------------ */\n\n/**\n * Props for PaginationNav — a fully self-contained controlled pagination component that renders\n * Previous / page numbers (with ellipsis) / Next — using `generatePagination` internally.\n *\n * **1-indexed:** `currentPage` starts at 1 (not 0). `onPageChange` also receives 1-indexed values.\n *\n * **`siblingCount`:** Number of page buttons shown on each side of the current page (default 1).\n * A wider `siblingCount` shows more page buttons before switching to ellipsis.\n *\n * @example\n * // Basic controlled pagination:\n * <PaginationNav\n * totalPages={24}\n * currentPage={currentPage}\n * onPageChange={setCurrentPage}\n * />\n *\n * @example\n * // Wider sibling range for a results grid (shows more page context):\n * <PaginationNav\n * totalPages={100}\n * currentPage={currentPage}\n * onPageChange={setCurrentPage}\n * siblingCount={2}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface PaginationNavProps\n extends React.HTMLAttributes<HTMLElement> {\n /** Total number of pages */\n totalPages: number\n /** Current active page (1-indexed) */\n currentPage: number\n /** Called when the user requests a different page */\n onPageChange: (page: number) => void\n /** Number of sibling page buttons shown on each side of the current page (default: 1) */\n siblingCount?: number\n}\n\nconst PaginationNav = React.forwardRef<HTMLElement, PaginationNavProps>(\n (\n {\n totalPages,\n currentPage,\n onPageChange,\n siblingCount = 1,\n className,\n ...props\n },\n ref,\n ) => {\n const pages = generatePagination(currentPage, totalPages, siblingCount)\n\n return (\n <PaginationRoot ref={ref} className={className} {...props}>\n <PaginationContent>\n <PaginationItem>\n <PaginationPrevious\n onClick={() => onPageChange(Math.max(1, currentPage - 1))}\n disabled={currentPage <= 1}\n />\n </PaginationItem>\n\n {pages.map((page, i) =>\n page === 'ellipsis' ? (\n <PaginationItem key={`e${i}`}>\n <PaginationEllipsis />\n </PaginationItem>\n ) : (\n <PaginationItem key={page}>\n <PaginationLink\n isActive={page === currentPage}\n onClick={() => onPageChange(page)}\n >\n {page}\n </PaginationLink>\n </PaginationItem>\n ),\n )}\n\n <PaginationItem>\n <PaginationNext\n onClick={() =>\n onPageChange(Math.min(totalPages, currentPage + 1))\n }\n disabled={currentPage >= totalPages}\n />\n </PaginationItem>\n </PaginationContent>\n </PaginationRoot>\n )\n },\n)\nPaginationNav.displayName = 'PaginationNav'\n\nexport {\n generatePagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNav,\n PaginationNext,\n PaginationPrevious,\n PaginationRoot,\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pagination.js","names":[],"sources":["../../src/ui/pagination.tsx"],"sourcesContent":["'use client'\n\nimport { Slot } from '@primitives/react-slot'\nimport { IconChevronLeft, IconChevronRight, IconDots } from '@tabler/icons-react'\nimport * as React from 'react'\n\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\n\nconst PaginationRoot = React.forwardRef<\n HTMLElement,\n React.ComponentPropsWithoutRef<'nav'>\n>(({ className, ...props }, ref) => (\n <nav\n ref={ref}\n role=\"navigation\"\n aria-label=\"pagination\"\n className={cn('mx-auto flex w-full justify-center', className)}\n {...props}\n />\n))\nPaginationRoot.displayName = 'PaginationRoot'\n\nconst PaginationContent = React.forwardRef<\n HTMLUListElement,\n React.ComponentPropsWithoutRef<'ul'>\n>(({ className, ...props }, ref) => (\n <ul\n ref={ref}\n className={cn('flex flex-row items-center gap-ds-02', className)}\n {...props}\n />\n))\nPaginationContent.displayName = 'PaginationContent'\n\nconst PaginationItem = React.forwardRef<\n HTMLLIElement,\n React.ComponentPropsWithoutRef<'li'>\n>(({ className, ...props }, ref) => (\n <li ref={ref} className={cn('', className)} {...props} />\n))\nPaginationItem.displayName = 'PaginationItem'\n\n/**\n * Props for PaginationLink — a single page number button in a pagination row.\n * When `isActive` is true, the button gets the brand interactive fill and `aria-current=\"page\"`.\n *\n * @example\n * // Active page button:\n * <PaginationLink isActive onClick={() => goToPage(3)}>3</PaginationLink>\n *\n * @example\n * // Render as a Next.js Link via asChild:\n * <PaginationLink asChild isActive={currentPage === 5}>\n * <Link href=\"/posts?page=5\">5</Link>\n * </PaginationLink>\n */\nexport interface PaginationLinkProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n isActive?: boolean\n asChild?: boolean\n}\n\nconst PaginationLink = React.forwardRef<HTMLButtonElement, PaginationLinkProps>(\n ({ className, isActive = false, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : 'button'\n return (\n <Comp\n ref={ref}\n aria-current={isActive ? 'page' : undefined}\n className={cn(\n 'inline-flex items-center justify-center h-ds-sm-plus w-ds-sm-plus rounded-control text-body-md font-medium tabular-nums transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-action-disabled active:scale-95',\n isActive\n ? 'bg-accent-9 text-accent-fg'\n : 'hover:bg-surface-raised-hover text-surface-fg',\n className,\n )}\n {...props}\n />\n )\n },\n)\nPaginationLink.displayName = 'PaginationLink'\n\nconst PaginationPrevious = React.forwardRef<\n HTMLButtonElement,\n PaginationLinkProps\n>(({ className, ...props }, ref) => (\n <PaginationLink\n ref={ref}\n aria-label=\"Go to previous page\"\n className={cn('w-auto gap-ds-02 pl-ds-03 pr-ds-04', className)}\n {...props}\n >\n <Icon icon={IconChevronLeft} size=\"sm\" />\n <span>Previous</span>\n </PaginationLink>\n))\nPaginationPrevious.displayName = 'PaginationPrevious'\n\nconst PaginationNext = React.forwardRef<\n HTMLButtonElement,\n PaginationLinkProps\n>(({ className, ...props }, ref) => (\n <PaginationLink\n ref={ref}\n aria-label=\"Go to next page\"\n className={cn('w-auto gap-ds-02 pl-ds-04 pr-ds-03', className)}\n {...props}\n >\n <span>Next</span>\n <Icon icon={IconChevronRight} size=\"sm\" />\n </PaginationLink>\n))\nPaginationNext.displayName = 'PaginationNext'\n\nconst PaginationEllipsis = React.forwardRef<\n HTMLSpanElement,\n React.ComponentPropsWithoutRef<'span'>\n>(({ className, ...props }, ref) => (\n <span\n ref={ref}\n aria-hidden=\"true\"\n className={cn(\n 'flex h-ds-sm-plus w-ds-sm-plus items-center justify-center text-surface-fg-muted',\n className,\n )}\n {...props}\n >\n <Icon icon={IconDots} size=\"sm\" />\n <span className=\"sr-only\">More pages</span>\n </span>\n))\nPaginationEllipsis.displayName = 'PaginationEllipsis'\n\n/* ------------------------------------------------------------------ */\n/* generatePagination helper */\n/* ------------------------------------------------------------------ */\n\ntype PageItem = number | 'ellipsis'\n\n/**\n * Pure function that builds an array of page numbers and ellipsis markers.\n * Always shows first and last page, plus `siblingCount` pages around `current`.\n *\n * @example generatePagination(5, 10, 1) → [1, 'ellipsis', 4, 5, 6, 'ellipsis', 10]\n */\nfunction generatePagination(\n current: number,\n total: number,\n siblingCount: number,\n): PageItem[] {\n // When total pages fit without any ellipsis\n const totalSlots = siblingCount * 2 + 5 // first + last + current + 2*siblings + 2 ellipsis slots\n if (total <= totalSlots) {\n return Array.from({ length: total }, (_, i) => i + 1)\n }\n\n const leftSibling = Math.max(current - siblingCount, 1)\n const rightSibling = Math.min(current + siblingCount, total)\n\n const showLeftEllipsis = leftSibling > 2\n const showRightEllipsis = rightSibling < total - 1\n\n if (!showLeftEllipsis && showRightEllipsis) {\n // e.g. [1, 2, 3, 4, 5, '...', 10]\n const leftCount = siblingCount * 2 + 3\n const leftPages = Array.from({ length: leftCount }, (_, i) => i + 1)\n return [...leftPages, 'ellipsis', total]\n }\n\n if (showLeftEllipsis && !showRightEllipsis) {\n // e.g. [1, '...', 6, 7, 8, 9, 10]\n const rightCount = siblingCount * 2 + 3\n const rightPages = Array.from(\n { length: rightCount },\n (_, i) => total - rightCount + 1 + i,\n )\n return [1, 'ellipsis', ...rightPages]\n }\n\n // Both ellipses: [1, '...', 4, 5, 6, '...', 10]\n const middlePages = Array.from(\n { length: rightSibling - leftSibling + 1 },\n (_, i) => leftSibling + i,\n )\n return [1, 'ellipsis', ...middlePages, 'ellipsis', total]\n}\n\n/* ------------------------------------------------------------------ */\n/* PaginationNav — controlled convenience wrapper */\n/* ------------------------------------------------------------------ */\n\n/**\n * Props for PaginationNav — a fully self-contained controlled pagination component that renders\n * Previous / page numbers (with ellipsis) / Next — using `generatePagination` internally.\n *\n * **1-indexed:** `currentPage` starts at 1 (not 0). `onPageChange` also receives 1-indexed values.\n *\n * **`siblingCount`:** Number of page buttons shown on each side of the current page (default 1).\n * A wider `siblingCount` shows more page buttons before switching to ellipsis.\n *\n * @example\n * // Basic controlled pagination:\n * <PaginationNav\n * totalPages={24}\n * currentPage={currentPage}\n * onPageChange={setCurrentPage}\n * />\n *\n * @example\n * // Wider sibling range for a results grid (shows more page context):\n * <PaginationNav\n * totalPages={100}\n * currentPage={currentPage}\n * onPageChange={setCurrentPage}\n * siblingCount={2}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface PaginationNavProps\n extends React.HTMLAttributes<HTMLElement> {\n /** Total number of pages */\n totalPages: number\n /** Current active page (1-indexed) */\n currentPage: number\n /** Called when the user requests a different page */\n onPageChange: (page: number) => void\n /** Number of sibling page buttons shown on each side of the current page (default: 1) */\n siblingCount?: number\n}\n\nconst PaginationNav = React.forwardRef<HTMLElement, PaginationNavProps>(\n (\n {\n totalPages,\n currentPage,\n onPageChange,\n siblingCount = 1,\n className,\n ...props\n },\n ref,\n ) => {\n const pages = generatePagination(currentPage, totalPages, siblingCount)\n\n return (\n <PaginationRoot ref={ref} className={className} {...props}>\n <PaginationContent>\n <PaginationItem>\n <PaginationPrevious\n onClick={() => onPageChange(Math.max(1, currentPage - 1))}\n disabled={currentPage <= 1}\n />\n </PaginationItem>\n\n {pages.map((page, i) =>\n page === 'ellipsis' ? (\n <PaginationItem key={`e${i}`}>\n <PaginationEllipsis />\n </PaginationItem>\n ) : (\n <PaginationItem key={page}>\n <PaginationLink\n isActive={page === currentPage}\n onClick={() => onPageChange(page)}\n >\n {page}\n </PaginationLink>\n </PaginationItem>\n ),\n )}\n\n <PaginationItem>\n <PaginationNext\n onClick={() =>\n onPageChange(Math.min(totalPages, currentPage + 1))\n }\n disabled={currentPage >= totalPages}\n />\n </PaginationItem>\n </PaginationContent>\n </PaginationRoot>\n )\n },\n)\nPaginationNav.displayName = 'PaginationNav'\n\nexport {\n generatePagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNav,\n PaginationNext,\n PaginationPrevious,\n PaginationRoot,\n}\n"],"mappings":"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"}
|
package/dist/ui/progress-ring.js
CHANGED
|
@@ -15,17 +15,17 @@ var u = {
|
|
|
15
15
|
sm: {
|
|
16
16
|
size: 32,
|
|
17
17
|
strokeWidth: 3,
|
|
18
|
-
fontSize: "text-
|
|
18
|
+
fontSize: "text-body-xs"
|
|
19
19
|
},
|
|
20
20
|
md: {
|
|
21
21
|
size: 48,
|
|
22
22
|
strokeWidth: 3.5,
|
|
23
|
-
fontSize: "text-
|
|
23
|
+
fontSize: "text-body-sm"
|
|
24
24
|
},
|
|
25
25
|
lg: {
|
|
26
26
|
size: 64,
|
|
27
27
|
strokeWidth: 4,
|
|
28
|
-
fontSize: "text-
|
|
28
|
+
fontSize: "text-body-md"
|
|
29
29
|
}
|
|
30
30
|
}, f = n.forwardRef(({ value: f, max: p = 100, size: m = "md", color: h = "default", showValue: g = !1, label: _, className: v, ...y }, b) => {
|
|
31
31
|
let x = c(), S = d[m], C = (S.size - S.strokeWidth) / 2, w = 2 * Math.PI * C, T = Math.min(Math.max(f / p, 0), 1), E = w * (1 - T), D = S.size / 2, O = Math.round(T * 100), k = s(0), A = l(k, (e) => `${Math.round(e)}%`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progress-ring.js","names":[],"sources":["../../src/ui/progress-ring.tsx"],"sourcesContent":["'use client'\n\nimport { animate, motion, useMotionValue, useReducedMotion,useTransform } from 'framer-motion'\nimport * as React from 'react'\n\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst colorMap: Record<string, string> = {\n default: 'var(--color-accent-9)',\n success: 'var(--color-success-9)',\n warning: 'var(--color-warning-9)',\n error: 'var(--color-error-9)',\n info: 'var(--color-info-9)',\n}\n\nconst sizeConfig = {\n sm: { size: 32, strokeWidth: 3, fontSize: 'text-
|
|
1
|
+
{"version":3,"file":"progress-ring.js","names":[],"sources":["../../src/ui/progress-ring.tsx"],"sourcesContent":["'use client'\n\nimport { animate, motion, useMotionValue, useReducedMotion,useTransform } from 'framer-motion'\nimport * as React from 'react'\n\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst colorMap: Record<string, string> = {\n default: 'var(--color-accent-9)',\n success: 'var(--color-success-9)',\n warning: 'var(--color-warning-9)',\n error: 'var(--color-error-9)',\n info: 'var(--color-info-9)',\n}\n\nconst sizeConfig = {\n sm: { size: 32, strokeWidth: 3, fontSize: 'text-body-xs' },\n md: { size: 48, strokeWidth: 3.5, fontSize: 'text-body-sm' },\n lg: { size: 64, strokeWidth: 4, fontSize: 'text-body-md' },\n} as const\n\n/**\n * A circular progress indicator with optional label and animated fill.\n *\n * @example\n * <ProgressRing value={75} />\n * <ProgressRing value={3} max={12} size=\"lg\" color=\"warning\" showValue />\n */\nexport interface ProgressRingProps extends Omit<React.SVGAttributes<SVGSVGElement>, 'color'> {\n /** Current progress value */\n value: number\n /** Maximum value @default 100 */\n max?: number\n /** @default 'md' */\n size?: 'sm' | 'md' | 'lg'\n /** @default 'default' */\n color?: 'default' | 'success' | 'warning' | 'error' | 'info'\n /** Show percentage text in center */\n showValue?: boolean\n /** Accessible label */\n label?: string\n}\n\nconst ProgressRing = React.forwardRef<SVGSVGElement, ProgressRingProps>(\n ({ value, max = 100, size = 'md', color = 'default', showValue = false, label, className, ...props }, ref) => {\n const prefersReducedMotion = useReducedMotion()\n const config = sizeConfig[size]\n const radius = (config.size - config.strokeWidth) / 2\n const circumference = 2 * Math.PI * radius\n const progress = Math.min(Math.max(value / max, 0), 1)\n const offset = circumference * (1 - progress)\n const center = config.size / 2\n const percentage = Math.round(progress * 100)\n\n // Animated counter — drives from 0 → target percentage in sync with the ring fill\n const motionVal = useMotionValue(0)\n const displayValue = useTransform(motionVal, (v) => `${Math.round(v)}%`)\n\n React.useEffect(() => {\n const controls = animate(motionVal, progress * 100, prefersReducedMotion\n ? { type: 'tween', duration: 0 }\n /* Intentionally slower than springs.gentle (200/25/0.8) for smooth ring fill */\n : { stiffness: 100, damping: 30, type: 'spring' },\n )\n return () => controls.stop()\n }, [progress, motionVal, prefersReducedMotion])\n\n return (\n <svg\n ref={ref}\n width={config.size}\n height={config.size}\n viewBox={`0 0 ${config.size} ${config.size}`}\n role=\"progressbar\"\n aria-valuenow={value}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-label={label ?? `${percentage}% progress`}\n className={cn('shrink-0', className)}\n {...props}\n >\n {/* Track */}\n <circle\n cx={center}\n cy={center}\n r={radius}\n fill=\"none\"\n stroke=\"var(--color-surface-raised-hover)\"\n strokeWidth={config.strokeWidth}\n />\n {/* Value */}\n <motion.circle\n cx={center}\n cy={center}\n r={radius}\n fill=\"none\"\n stroke={colorMap[color]}\n strokeWidth={config.strokeWidth}\n strokeLinecap=\"round\"\n strokeDasharray={circumference}\n initial={{ strokeDashoffset: circumference }}\n animate={{ strokeDashoffset: offset }}\n transition={prefersReducedMotion ? { duration: 0 } : springs.smooth}\n transform={`rotate(-90 ${center} ${center})`}\n />\n {showValue && (\n <motion.text\n x={center}\n y={center}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n className={cn(config.fontSize, 'fill-surface-fg font-sans font-semibold')}\n >\n {displayValue}\n </motion.text>\n )}\n </svg>\n )\n },\n)\nProgressRing.displayName = 'ProgressRing'\n\n/**\n * Multi-ring progress display (Activity Ring style).\n *\n * @example\n * <MultiProgressRing rings={[\n * { value: 80, color: 'error', label: 'Move' },\n * { value: 60, color: 'success', label: 'Exercise' },\n * ]} size=\"lg\" />\n */\nexport interface MultiProgressRingProps extends Omit<React.SVGAttributes<SVGSVGElement>, 'color'> {\n rings: Array<{\n value: number\n max?: number\n color?: 'default' | 'success' | 'warning' | 'error' | 'info'\n label?: string\n }>\n /** @default 'md' */\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst MultiProgressRing = React.forwardRef<SVGSVGElement, MultiProgressRingProps>(\n ({ rings, size = 'md', className, ...props }, ref) => {\n const prefersReducedMotion = useReducedMotion()\n const config = sizeConfig[size]\n const center = config.size / 2\n const gap = config.strokeWidth + 2\n\n return (\n <svg\n ref={ref}\n width={config.size}\n height={config.size}\n viewBox={`0 0 ${config.size} ${config.size}`}\n role=\"group\"\n aria-label=\"Progress rings\"\n className={cn('shrink-0', className)}\n {...props}\n >\n {rings.map((ring, i) => {\n const radius = (config.size - config.strokeWidth) / 2 - i * gap\n if (radius <= 0) return null\n const circumference = 2 * Math.PI * radius\n const progress = Math.min(Math.max((ring.value) / (ring.max ?? 100), 0), 1)\n const offset = circumference * (1 - progress)\n\n return (\n <React.Fragment key={i}>\n <circle\n cx={center}\n cy={center}\n r={radius}\n fill=\"none\"\n stroke=\"var(--color-surface-raised-hover)\"\n strokeWidth={config.strokeWidth}\n />\n <motion.circle\n cx={center}\n cy={center}\n r={radius}\n fill=\"none\"\n stroke={colorMap[ring.color ?? 'default']}\n strokeWidth={config.strokeWidth}\n strokeLinecap=\"round\"\n strokeDasharray={circumference}\n initial={{ strokeDashoffset: circumference }}\n animate={{ strokeDashoffset: offset }}\n transition={prefersReducedMotion ? { duration: 0 } : springs.smooth}\n transform={`rotate(-90 ${center} ${center})`}\n />\n </React.Fragment>\n )\n })}\n </svg>\n )\n },\n)\nMultiProgressRing.displayName = 'MultiProgressRing'\n\nexport { MultiProgressRing,ProgressRing }\n"],"mappings":"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"}
|
package/dist/ui/progress.js
CHANGED
|
@@ -98,7 +98,7 @@ var v = i.forwardRef(({ value: e, color: t = "accent", className: n, style: i, .
|
|
|
98
98
|
v.displayName = "Progress.Segment";
|
|
99
99
|
var y = i.forwardRef(({ className: e, ...t }, n) => (m("Label"), /* @__PURE__ */ a("span", {
|
|
100
100
|
ref: n,
|
|
101
|
-
className: r("shrink-0 text-
|
|
101
|
+
className: r("shrink-0 text-body-sm font-medium text-surface-fg", e),
|
|
102
102
|
...t
|
|
103
103
|
})));
|
|
104
104
|
y.displayName = "Progress.Label";
|
|
@@ -106,7 +106,7 @@ var b = i.forwardRef(({ className: e, format: t, children: n, ...i }, o) => {
|
|
|
106
106
|
let { value: s, max: c, indeterminate: l } = m("Value"), u = l ? 0 : f(s ?? 0, c);
|
|
107
107
|
return /* @__PURE__ */ a("span", {
|
|
108
108
|
ref: o,
|
|
109
|
-
className: r("shrink-0 text-
|
|
109
|
+
className: r("shrink-0 text-caption text-surface-fg-muted tabular-nums", e),
|
|
110
110
|
...i,
|
|
111
111
|
children: n ?? (l ? "" : t ? t(u, s, c) : `${Math.round(u)}%`)
|
|
112
112
|
});
|
package/dist/ui/progress.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progress.js","names":[],"sources":["../../src/ui/progress.tsx"],"sourcesContent":["'use client'\n\nimport * as ProgressPrimitive from '@primitives/react-progress'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\n/* ---------------------------------------------------------------------------\n * Progress — a linear progress bar.\n *\n * Two ways to use it:\n * 1. Smart all-in-one `<Progress value={70} />` — covers the common cases\n * (value, size, color, label, %-value, auto-color, indeterminate, segments).\n * 2. Compound parts `<Progress.Root>/<Progress.Track>/<Progress.Indicator>` etc.\n * — full layout control, borrowed from Ark UI / Chakra's structure, with\n * Mantine-style `<Progress.Segment>` for multi-colour bars.\n *\n * The compound parts share a context so `value`/`max`/`size` are set once on\n * `Root` and read by Track/Indicator/Segment/Value.\n * ------------------------------------------------------------------------ */\n\nexport type ProgressSize = 'sm' | 'md' | 'lg'\nexport type ProgressColor = 'accent' | 'success' | 'warning' | 'error'\n\nexport const progressTrackVariants = cva(\n 'relative w-full overflow-hidden rounded-pill bg-surface-raised',\n {\n variants: { size: { sm: 'h-1', md: 'h-2', lg: 'h-3' } },\n defaultVariants: { size: 'md' },\n },\n)\n\nconst COLOR_FILL: Record<ProgressColor, string> = {\n accent: 'bg-accent-9',\n success: 'bg-success-9',\n warning: 'bg-warning-9',\n error: 'bg-error-9',\n}\n\nexport const progressIndicatorVariants = cva(\n 'h-full transition-[width] duration-moderate-02 ease-expressive-standard',\n {\n variants: { color: COLOR_FILL },\n defaultVariants: { color: 'accent' },\n },\n)\n\n/** Auto-color by value: 0–59 accent, 60–84 warning, 85–100 success, >100 error. */\nfunction autoColorFor(value: number | null | undefined): ProgressColor {\n if (value == null) return 'accent'\n if (value > 100) return 'error'\n if (value >= 85) return 'success'\n if (value >= 60) return 'warning'\n return 'accent'\n}\n\nconst clampPct = (value: number, max: number) =>\n Math.max(0, Math.min(100, (value / max) * 100))\n\n/* ---------------------------------------------------------------------------\n * Context — set once on Root, read by Track / Indicator / Segment / Value.\n * ------------------------------------------------------------------------ */\n\ninterface ProgressContextValue {\n value: number | null\n max: number\n size: ProgressSize\n indeterminate: boolean\n}\n\nconst ProgressContext = React.createContext<ProgressContextValue | null>(null)\n\nfunction useProgressContext(part: string): ProgressContextValue {\n const ctx = React.useContext(ProgressContext)\n if (!ctx) {\n throw new Error(`<Progress.${part}> must be rendered inside <Progress.Root>.`)\n }\n return ctx\n}\n\n/* ---------------------------------------------------------------------------\n * Progress.Root — layout container + context. NOT the progressbar itself\n * (that's Track) so labels/value can sit outside the bar (Ark UI model).\n * ------------------------------------------------------------------------ */\n\nexport interface ProgressRootProps extends React.HTMLAttributes<HTMLDivElement> {\n /** 0–max. Omit (or null) for an indeterminate bar. */\n value?: number | null\n /** Scale maximum. @default 100 */\n max?: number\n /** Track thickness. @default 'md' */\n size?: ProgressSize\n}\n\nconst ProgressRoot = React.forwardRef<HTMLDivElement, ProgressRootProps>(\n ({ value = null, max = 100, size = 'md', className, children, ...props }, ref) => {\n const ctx = React.useMemo<ProgressContextValue>(\n () => ({ value, max, size, indeterminate: value == null }),\n [value, max, size],\n )\n return (\n <ProgressContext.Provider value={ctx}>\n <div ref={ref} className={cn('flex w-full items-center gap-ds-03', className)} {...props}>\n {children}\n </div>\n </ProgressContext.Provider>\n )\n },\n)\nProgressRoot.displayName = 'Progress.Root'\n\n/* ---------------------------------------------------------------------------\n * Progress.Track — the aria progressbar + track visual. Holds Indicator/Segment.\n * ------------------------------------------------------------------------ */\n\nexport type ProgressTrackProps = React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>\n\nconst ProgressTrack = React.forwardRef<\n React.ElementRef<typeof ProgressPrimitive.Root>,\n ProgressTrackProps\n>(({ className, children, ...props }, ref) => {\n const { value, max, size, indeterminate } = useProgressContext('Track')\n // Accessible name comes from the consumer's aria-label / aria-labelledby (spread\n // via ...props) — no auto-wiring, so a Track never carries a dangling reference.\n return (\n <ProgressPrimitive.Root\n ref={ref}\n value={indeterminate ? null : value}\n max={max}\n className={cn(progressTrackVariants({ size }), 'flex-1', className)}\n {...props}\n >\n {children}\n </ProgressPrimitive.Root>\n )\n})\nProgressTrack.displayName = 'Progress.Track'\n\n/* ---------------------------------------------------------------------------\n * Progress.Indicator — single fill. Determinate width from context, or the\n * indeterminate sweep animation when Root has no value.\n * ------------------------------------------------------------------------ */\n\nexport interface ProgressIndicatorProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Fill colour. Omit to auto-colour by value. */\n color?: ProgressColor\n /** Force auto-colour even when `color` is unset. @default true when color unset */\n autoColor?: boolean\n}\n\nconst ProgressIndicator = React.forwardRef<HTMLDivElement, ProgressIndicatorProps>(\n ({ color, autoColor, className, ...props }, ref) => {\n const { value, max, indeterminate } = useProgressContext('Indicator')\n const resolved = color ?? (autoColor !== false ? autoColorFor(value) : 'accent')\n\n if (indeterminate) {\n return (\n <div\n ref={ref}\n className={cn(\n progressIndicatorVariants({ color: resolved }),\n 'w-2/5 animate-progress-indeterminate motion-reduce:animate-none',\n className,\n )}\n {...props}\n />\n )\n }\n return (\n <motion.div\n ref={ref}\n className={cn(progressIndicatorVariants({ color: resolved }), 'transition-colors', className)}\n initial={false}\n animate={{ width: `${clampPct(value ?? 0, max)}%` }}\n transition={springs.smooth}\n {...(props as React.ComponentProps<typeof motion.div>)}\n />\n )\n },\n)\nProgressIndicator.displayName = 'Progress.Indicator'\n\n/* ---------------------------------------------------------------------------\n * Progress.Segment — one slice of a multi-segment bar (Mantine-style). Place\n * several inside a Track. Widths are each segment's value as a % of max.\n * ------------------------------------------------------------------------ */\n\nexport interface ProgressSegmentProps extends React.HTMLAttributes<HTMLDivElement> {\n /** This segment's portion of `max`. */\n value: number\n color?: ProgressColor\n}\n\nconst ProgressSegment = React.forwardRef<HTMLDivElement, ProgressSegmentProps>(\n ({ value, color = 'accent', className, style, ...props }, ref) => {\n const { max } = useProgressContext('Segment')\n return (\n <div\n ref={ref}\n aria-hidden=\"true\"\n className={cn('h-full first:rounded-l-pill last:rounded-r-pill', COLOR_FILL[color], className)}\n style={{ width: `${clampPct(value, max)}%`, ...style }}\n {...props}\n />\n )\n },\n)\nProgressSegment.displayName = 'Progress.Segment'\n\n/* ---------------------------------------------------------------------------\n * Progress.Label — descriptive text, associated with the bar via aria.\n * ------------------------------------------------------------------------ */\n\nexport type ProgressLabelProps = React.HTMLAttributes<HTMLSpanElement>\n\nconst ProgressLabel = React.forwardRef<HTMLSpanElement, ProgressLabelProps>(\n ({ className, ...props }, ref) => {\n useProgressContext('Label')\n return (\n <span\n ref={ref}\n className={cn('shrink-0 text-ds-sm font-medium text-surface-fg', className)}\n {...props}\n />\n )\n },\n)\nProgressLabel.displayName = 'Progress.Label'\n\n/* ---------------------------------------------------------------------------\n * Progress.Value — the \"{n}%\" readout. Custom content via children or `format`.\n * ------------------------------------------------------------------------ */\n\nexport interface ProgressValueProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'children'> {\n /** Format the percentage. Default: `${round(pct)}%`. */\n format?: (pct: number, value: number | null, max: number) => React.ReactNode\n children?: React.ReactNode\n}\n\nconst ProgressValue = React.forwardRef<HTMLSpanElement, ProgressValueProps>(\n ({ className, format, children, ...props }, ref) => {\n const { value, max, indeterminate } = useProgressContext('Value')\n const pct = indeterminate ? 0 : clampPct(value ?? 0, max)\n return (\n <span\n ref={ref}\n className={cn('shrink-0 text-ds-xs text-surface-fg-muted tabular-nums', className)}\n {...props}\n >\n {children ?? (indeterminate ? '' : format ? format(pct, value, max) : `${Math.round(pct)}%`)}\n </span>\n )\n },\n)\nProgressValue.displayName = 'Progress.Value'\n\n/* ---------------------------------------------------------------------------\n * Progress — smart all-in-one. Composes the parts for the common cases.\n * ------------------------------------------------------------------------ */\n\nexport interface ProgressProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n VariantProps<typeof progressTrackVariants> {\n /** 0–max. Omit (or null) for an indeterminate bar. */\n value?: number | null\n max?: number\n /** Fill colour. Omit + set `autoColor` to colour by value. */\n color?: ProgressColor\n /** Auto-colour the fill by value (0–59 accent · 60–84 warning · 85–100 success · >100 error). @default false */\n autoColor?: boolean\n /** Descriptive label rendered before the bar. */\n label?: React.ReactNode\n /** Show the `{n}%` readout after the bar. */\n showValue?: boolean\n /** Multi-segment bar: each slice is `value` (portion of max) + `color`. Overrides the single indicator. */\n segments?: Array<{ value: number; color?: ProgressColor }>\n /** Class for the Track element. */\n trackClassName?: string\n /** Class for the single Indicator (ignored when `segments` is set). */\n indicatorClassName?: string\n}\n\nconst ProgressBase = React.forwardRef<HTMLDivElement, ProgressProps>(\n (\n {\n value = null, max = 100, size, color, autoColor, label, showValue, segments,\n trackClassName, indicatorClassName, className,\n 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, ...props\n },\n ref,\n ) => {\n const labelId = React.useId()\n const hasLabel = label != null\n return (\n <ProgressRoot ref={ref} value={value} max={max} size={size ?? 'md'} className={className} {...props}>\n {hasLabel && <ProgressLabel id={labelId}>{label}</ProgressLabel>}\n <ProgressTrack\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby ?? (hasLabel ? labelId : undefined)}\n className={cn(segments && 'flex', trackClassName)}\n >\n {segments\n ? segments.map((s, i) => <ProgressSegment key={i} value={s.value} color={s.color} />)\n : <ProgressIndicator color={color} autoColor={autoColor} className={indicatorClassName} />}\n </ProgressTrack>\n {showValue && value != null && <ProgressValue />}\n </ProgressRoot>\n )\n },\n)\nProgressBase.displayName = 'Progress'\n\nconst Progress = Object.assign(ProgressBase, {\n Root: ProgressRoot,\n Track: ProgressTrack,\n Indicator: ProgressIndicator,\n Segment: ProgressSegment,\n Label: ProgressLabel,\n Value: ProgressValue,\n})\n\nexport {\n Progress,\n ProgressIndicator,\n ProgressLabel,\n ProgressRoot,\n ProgressSegment,\n ProgressTrack,\n ProgressValue,\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"progress.js","names":[],"sources":["../../src/ui/progress.tsx"],"sourcesContent":["'use client'\n\nimport * as ProgressPrimitive from '@primitives/react-progress'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\n/* ---------------------------------------------------------------------------\n * Progress — a linear progress bar.\n *\n * Two ways to use it:\n * 1. Smart all-in-one `<Progress value={70} />` — covers the common cases\n * (value, size, color, label, %-value, auto-color, indeterminate, segments).\n * 2. Compound parts `<Progress.Root>/<Progress.Track>/<Progress.Indicator>` etc.\n * — full layout control, borrowed from Ark UI / Chakra's structure, with\n * Mantine-style `<Progress.Segment>` for multi-colour bars.\n *\n * The compound parts share a context so `value`/`max`/`size` are set once on\n * `Root` and read by Track/Indicator/Segment/Value.\n * ------------------------------------------------------------------------ */\n\nexport type ProgressSize = 'sm' | 'md' | 'lg'\nexport type ProgressColor = 'accent' | 'success' | 'warning' | 'error'\n\nexport const progressTrackVariants = cva(\n 'relative w-full overflow-hidden rounded-pill bg-surface-raised',\n {\n variants: { size: { sm: 'h-1', md: 'h-2', lg: 'h-3' } },\n defaultVariants: { size: 'md' },\n },\n)\n\nconst COLOR_FILL: Record<ProgressColor, string> = {\n accent: 'bg-accent-9',\n success: 'bg-success-9',\n warning: 'bg-warning-9',\n error: 'bg-error-9',\n}\n\nexport const progressIndicatorVariants = cva(\n 'h-full transition-[width] duration-moderate-02 ease-expressive-standard',\n {\n variants: { color: COLOR_FILL },\n defaultVariants: { color: 'accent' },\n },\n)\n\n/** Auto-color by value: 0–59 accent, 60–84 warning, 85–100 success, >100 error. */\nfunction autoColorFor(value: number | null | undefined): ProgressColor {\n if (value == null) return 'accent'\n if (value > 100) return 'error'\n if (value >= 85) return 'success'\n if (value >= 60) return 'warning'\n return 'accent'\n}\n\nconst clampPct = (value: number, max: number) =>\n Math.max(0, Math.min(100, (value / max) * 100))\n\n/* ---------------------------------------------------------------------------\n * Context — set once on Root, read by Track / Indicator / Segment / Value.\n * ------------------------------------------------------------------------ */\n\ninterface ProgressContextValue {\n value: number | null\n max: number\n size: ProgressSize\n indeterminate: boolean\n}\n\nconst ProgressContext = React.createContext<ProgressContextValue | null>(null)\n\nfunction useProgressContext(part: string): ProgressContextValue {\n const ctx = React.useContext(ProgressContext)\n if (!ctx) {\n throw new Error(`<Progress.${part}> must be rendered inside <Progress.Root>.`)\n }\n return ctx\n}\n\n/* ---------------------------------------------------------------------------\n * Progress.Root — layout container + context. NOT the progressbar itself\n * (that's Track) so labels/value can sit outside the bar (Ark UI model).\n * ------------------------------------------------------------------------ */\n\nexport interface ProgressRootProps extends React.HTMLAttributes<HTMLDivElement> {\n /** 0–max. Omit (or null) for an indeterminate bar. */\n value?: number | null\n /** Scale maximum. @default 100 */\n max?: number\n /** Track thickness. @default 'md' */\n size?: ProgressSize\n}\n\nconst ProgressRoot = React.forwardRef<HTMLDivElement, ProgressRootProps>(\n ({ value = null, max = 100, size = 'md', className, children, ...props }, ref) => {\n const ctx = React.useMemo<ProgressContextValue>(\n () => ({ value, max, size, indeterminate: value == null }),\n [value, max, size],\n )\n return (\n <ProgressContext.Provider value={ctx}>\n <div ref={ref} className={cn('flex w-full items-center gap-ds-03', className)} {...props}>\n {children}\n </div>\n </ProgressContext.Provider>\n )\n },\n)\nProgressRoot.displayName = 'Progress.Root'\n\n/* ---------------------------------------------------------------------------\n * Progress.Track — the aria progressbar + track visual. Holds Indicator/Segment.\n * ------------------------------------------------------------------------ */\n\nexport type ProgressTrackProps = React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>\n\nconst ProgressTrack = React.forwardRef<\n React.ElementRef<typeof ProgressPrimitive.Root>,\n ProgressTrackProps\n>(({ className, children, ...props }, ref) => {\n const { value, max, size, indeterminate } = useProgressContext('Track')\n // Accessible name comes from the consumer's aria-label / aria-labelledby (spread\n // via ...props) — no auto-wiring, so a Track never carries a dangling reference.\n return (\n <ProgressPrimitive.Root\n ref={ref}\n value={indeterminate ? null : value}\n max={max}\n className={cn(progressTrackVariants({ size }), 'flex-1', className)}\n {...props}\n >\n {children}\n </ProgressPrimitive.Root>\n )\n})\nProgressTrack.displayName = 'Progress.Track'\n\n/* ---------------------------------------------------------------------------\n * Progress.Indicator — single fill. Determinate width from context, or the\n * indeterminate sweep animation when Root has no value.\n * ------------------------------------------------------------------------ */\n\nexport interface ProgressIndicatorProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Fill colour. Omit to auto-colour by value. */\n color?: ProgressColor\n /** Force auto-colour even when `color` is unset. @default true when color unset */\n autoColor?: boolean\n}\n\nconst ProgressIndicator = React.forwardRef<HTMLDivElement, ProgressIndicatorProps>(\n ({ color, autoColor, className, ...props }, ref) => {\n const { value, max, indeterminate } = useProgressContext('Indicator')\n const resolved = color ?? (autoColor !== false ? autoColorFor(value) : 'accent')\n\n if (indeterminate) {\n return (\n <div\n ref={ref}\n className={cn(\n progressIndicatorVariants({ color: resolved }),\n 'w-2/5 animate-progress-indeterminate motion-reduce:animate-none',\n className,\n )}\n {...props}\n />\n )\n }\n return (\n <motion.div\n ref={ref}\n className={cn(progressIndicatorVariants({ color: resolved }), 'transition-colors', className)}\n initial={false}\n animate={{ width: `${clampPct(value ?? 0, max)}%` }}\n transition={springs.smooth}\n {...(props as React.ComponentProps<typeof motion.div>)}\n />\n )\n },\n)\nProgressIndicator.displayName = 'Progress.Indicator'\n\n/* ---------------------------------------------------------------------------\n * Progress.Segment — one slice of a multi-segment bar (Mantine-style). Place\n * several inside a Track. Widths are each segment's value as a % of max.\n * ------------------------------------------------------------------------ */\n\nexport interface ProgressSegmentProps extends React.HTMLAttributes<HTMLDivElement> {\n /** This segment's portion of `max`. */\n value: number\n color?: ProgressColor\n}\n\nconst ProgressSegment = React.forwardRef<HTMLDivElement, ProgressSegmentProps>(\n ({ value, color = 'accent', className, style, ...props }, ref) => {\n const { max } = useProgressContext('Segment')\n return (\n <div\n ref={ref}\n aria-hidden=\"true\"\n className={cn('h-full first:rounded-l-pill last:rounded-r-pill', COLOR_FILL[color], className)}\n style={{ width: `${clampPct(value, max)}%`, ...style }}\n {...props}\n />\n )\n },\n)\nProgressSegment.displayName = 'Progress.Segment'\n\n/* ---------------------------------------------------------------------------\n * Progress.Label — descriptive text, associated with the bar via aria.\n * ------------------------------------------------------------------------ */\n\nexport type ProgressLabelProps = React.HTMLAttributes<HTMLSpanElement>\n\nconst ProgressLabel = React.forwardRef<HTMLSpanElement, ProgressLabelProps>(\n ({ className, ...props }, ref) => {\n useProgressContext('Label')\n return (\n <span\n ref={ref}\n className={cn('shrink-0 text-body-sm font-medium text-surface-fg', className)}\n {...props}\n />\n )\n },\n)\nProgressLabel.displayName = 'Progress.Label'\n\n/* ---------------------------------------------------------------------------\n * Progress.Value — the \"{n}%\" readout. Custom content via children or `format`.\n * ------------------------------------------------------------------------ */\n\nexport interface ProgressValueProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'children'> {\n /** Format the percentage. Default: `${round(pct)}%`. */\n format?: (pct: number, value: number | null, max: number) => React.ReactNode\n children?: React.ReactNode\n}\n\nconst ProgressValue = React.forwardRef<HTMLSpanElement, ProgressValueProps>(\n ({ className, format, children, ...props }, ref) => {\n const { value, max, indeterminate } = useProgressContext('Value')\n const pct = indeterminate ? 0 : clampPct(value ?? 0, max)\n return (\n <span\n ref={ref}\n className={cn('shrink-0 text-caption text-surface-fg-muted tabular-nums', className)}\n {...props}\n >\n {children ?? (indeterminate ? '' : format ? format(pct, value, max) : `${Math.round(pct)}%`)}\n </span>\n )\n },\n)\nProgressValue.displayName = 'Progress.Value'\n\n/* ---------------------------------------------------------------------------\n * Progress — smart all-in-one. Composes the parts for the common cases.\n * ------------------------------------------------------------------------ */\n\nexport interface ProgressProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n VariantProps<typeof progressTrackVariants> {\n /** 0–max. Omit (or null) for an indeterminate bar. */\n value?: number | null\n max?: number\n /** Fill colour. Omit + set `autoColor` to colour by value. */\n color?: ProgressColor\n /** Auto-colour the fill by value (0–59 accent · 60–84 warning · 85–100 success · >100 error). @default false */\n autoColor?: boolean\n /** Descriptive label rendered before the bar. */\n label?: React.ReactNode\n /** Show the `{n}%` readout after the bar. */\n showValue?: boolean\n /** Multi-segment bar: each slice is `value` (portion of max) + `color`. Overrides the single indicator. */\n segments?: Array<{ value: number; color?: ProgressColor }>\n /** Class for the Track element. */\n trackClassName?: string\n /** Class for the single Indicator (ignored when `segments` is set). */\n indicatorClassName?: string\n}\n\nconst ProgressBase = React.forwardRef<HTMLDivElement, ProgressProps>(\n (\n {\n value = null, max = 100, size, color, autoColor, label, showValue, segments,\n trackClassName, indicatorClassName, className,\n 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, ...props\n },\n ref,\n ) => {\n const labelId = React.useId()\n const hasLabel = label != null\n return (\n <ProgressRoot ref={ref} value={value} max={max} size={size ?? 'md'} className={className} {...props}>\n {hasLabel && <ProgressLabel id={labelId}>{label}</ProgressLabel>}\n <ProgressTrack\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby ?? (hasLabel ? labelId : undefined)}\n className={cn(segments && 'flex', trackClassName)}\n >\n {segments\n ? segments.map((s, i) => <ProgressSegment key={i} value={s.value} color={s.color} />)\n : <ProgressIndicator color={color} autoColor={autoColor} className={indicatorClassName} />}\n </ProgressTrack>\n {showValue && value != null && <ProgressValue />}\n </ProgressRoot>\n )\n },\n)\nProgressBase.displayName = 'Progress'\n\nconst Progress = Object.assign(ProgressBase, {\n Root: ProgressRoot,\n Track: ProgressTrack,\n Indicator: ProgressIndicator,\n Segment: ProgressSegment,\n Label: ProgressLabel,\n Value: ProgressValue,\n})\n\nexport {\n Progress,\n ProgressIndicator,\n ProgressLabel,\n ProgressRoot,\n ProgressSegment,\n ProgressTrack,\n ProgressValue,\n}\n"],"mappings":"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"}
|
|
@@ -8,15 +8,15 @@ import { LayoutGroup as o, motion as s } from "framer-motion";
|
|
|
8
8
|
//#region src/ui/segmented-control.tsx
|
|
9
9
|
var c = {
|
|
10
10
|
sm: {
|
|
11
|
-
button: "h-7 px-ds-04 text-
|
|
11
|
+
button: "h-7 px-ds-04 text-body-sm",
|
|
12
12
|
icon: "h-3.5 w-3.5"
|
|
13
13
|
},
|
|
14
14
|
md: {
|
|
15
|
-
button: "h-8 px-ds-05 text-
|
|
15
|
+
button: "h-8 px-ds-05 text-body-md",
|
|
16
16
|
icon: "h-4 w-4"
|
|
17
17
|
},
|
|
18
18
|
lg: {
|
|
19
|
-
button: "h-10 px-ds-06 text-
|
|
19
|
+
button: "h-10 px-ds-06 text-body-md",
|
|
20
20
|
icon: "h-4 w-4"
|
|
21
21
|
}
|
|
22
22
|
}, l = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"segmented-control.js","names":[],"sources":["../../src/ui/segmented-control.tsx"],"sourcesContent":["'use client'\n\nimport { LayoutGroup,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { IconProvider } from './icon-context'\nimport type { IconInput } from './lib/icon-input'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\n\n/* ── Types ─────────────────────────────────────────────────── */\n\nexport type SegmentedControlSize = 'sm' | 'md' | 'lg'\nexport type SegmentedControlVariant = 'default' | 'solid'\n\nexport interface SegmentedControlOption {\n id: string\n text: string\n /** Optional icon rendered before the text label. Accepts any `IconInput`. */\n icon?: IconInput\n}\n\nexport interface SegmentedControlProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'> {\n size?: SegmentedControlSize\n variant?: SegmentedControlVariant\n options: SegmentedControlOption[]\n selectedId: string\n onSelect: (id: string) => void\n disabled?: boolean\n}\n\n/* ── Size config ───────────────────────────────────────────── */\n\nconst sizeConfig = {\n sm: { button: 'h-7 px-ds-04 text-
|
|
1
|
+
{"version":3,"file":"segmented-control.js","names":[],"sources":["../../src/ui/segmented-control.tsx"],"sourcesContent":["'use client'\n\nimport { LayoutGroup,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { IconProvider } from './icon-context'\nimport type { IconInput } from './lib/icon-input'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\n\n/* ── Types ─────────────────────────────────────────────────── */\n\nexport type SegmentedControlSize = 'sm' | 'md' | 'lg'\nexport type SegmentedControlVariant = 'default' | 'solid'\n\nexport interface SegmentedControlOption {\n id: string\n text: string\n /** Optional icon rendered before the text label. Accepts any `IconInput`. */\n icon?: IconInput\n}\n\nexport interface SegmentedControlProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'> {\n size?: SegmentedControlSize\n variant?: SegmentedControlVariant\n options: SegmentedControlOption[]\n selectedId: string\n onSelect: (id: string) => void\n disabled?: boolean\n}\n\n/* ── Size config ───────────────────────────────────────────── */\n\nconst sizeConfig = {\n sm: { button: 'h-7 px-ds-04 text-body-sm', icon: 'h-3.5 w-3.5' },\n md: { button: 'h-8 px-ds-05 text-body-md', icon: 'h-4 w-4' },\n lg: { button: 'h-10 px-ds-06 text-body-md', icon: 'h-4 w-4' },\n} as const\n\n/* ── Pill styles per variant ───────────────────────────────── */\n\nconst pillStyles = {\n default: 'bg-surface-overlay shadow-raised',\n solid: 'bg-accent-9',\n} as const\n\nconst selectedTextStyles = {\n default: 'text-surface-fg',\n solid: 'text-accent-fg',\n} as const\n\n/* ── Spring config (snappy, minimal overshoot) ─────────────── */\n/* Intentionally softer than springs.snappy (500/30/0.5) for pill slide feel */\n\nconst pillSpring = { type: 'spring' as const, stiffness: 400, damping: 30 }\n\n/* ── SegmentedControl ──────────────────────────────────────── */\n\nconst SegmentedControl = React.forwardRef<HTMLDivElement, SegmentedControlProps>(\n function SegmentedControl(\n {\n size = 'md',\n variant = 'default',\n options,\n selectedId,\n onSelect,\n disabled = false,\n className,\n ...props\n },\n ref,\n ) {\n const instanceId = React.useId()\n const tablistRef = React.useRef<HTMLDivElement | null>(null)\n\n // Compose refs\n const mergedRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n tablistRef.current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\n },\n [ref],\n )\n\n // Keyboard navigation\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (disabled) return\n\n const currentIndex = options.findIndex((o) => o.id === selectedId)\n let nextIndex = currentIndex\n\n switch (e.key) {\n case 'ArrowLeft':\n e.preventDefault()\n nextIndex = currentIndex > 0 ? currentIndex - 1 : options.length - 1\n break\n case 'ArrowRight':\n e.preventDefault()\n nextIndex = currentIndex < options.length - 1 ? currentIndex + 1 : 0\n break\n case 'Home':\n e.preventDefault()\n nextIndex = 0\n break\n case 'End':\n e.preventDefault()\n nextIndex = options.length - 1\n break\n default:\n return\n }\n\n onSelect(options[nextIndex].id)\n requestAnimationFrame(() => {\n const buttons = tablistRef.current?.querySelectorAll<HTMLButtonElement>('[role=\"radio\"]')\n buttons?.[nextIndex]?.focus()\n })\n }\n\n const { button: buttonSize, icon: iconSize } = sizeConfig[size]\n\n return (\n <div\n ref={mergedRef}\n role=\"radiogroup\"\n tabIndex={-1}\n aria-label={props['aria-label'] ?? 'Segmented control'}\n onKeyDown={handleKeyDown}\n className={cn(\n 'inline-flex p-[3px] rounded-pill',\n 'bg-surface-raised-hover border border-surface-border-subtle shadow-inset',\n disabled && 'opacity-action-disabled pointer-events-none',\n className,\n )}\n {...props}\n >\n <LayoutGroup id={instanceId}>\n {options.map((option) => {\n const isSelected = option.id === selectedId\n\n return (\n <button\n key={option.id}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n tabIndex={isSelected ? 0 : -1}\n disabled={disabled}\n onClick={() => onSelect(option.id)}\n className={cn(\n 'relative inline-flex items-center justify-center gap-ds-02 rounded-pill',\n 'font-medium transition-colors duration-fast-02 ease-productive-standard',\n 'outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2',\n buttonSize,\n isSelected\n ? selectedTextStyles[variant]\n : 'text-surface-fg-muted hover:text-surface-fg',\n )}\n >\n {/* Sliding pill indicator */}\n {isSelected && (\n <motion.span\n layoutId=\"segment-pill\"\n className={cn(\n 'absolute inset-0 rounded-pill pointer-events-none',\n pillStyles[variant],\n )}\n transition={pillSpring}\n />\n )}\n\n {/* Content (above pill via z-index) */}\n {option.icon && (\n <span className={cn('relative z-[1] shrink-0 inline-flex items-center justify-center', iconSize)}>\n <IconProvider size={size === 'lg' ? 'sm' : 'xs'}>\n {normalizeIcon(option.icon)}\n </IconProvider>\n </span>\n )}\n <span className=\"relative z-[1]\">{option.text}</span>\n </button>\n )\n })}\n </LayoutGroup>\n </div>\n )\n },\n)\nSegmentedControl.displayName = 'SegmentedControl'\n\n/* ── Exports ───────────────────────────────────────────────── */\n\nexport { SegmentedControl }\n"],"mappings":";;;;;;;;AAiCA,IAAM,IAAa;CACjB,IAAI;EAAE,QAAQ;EAA6B,MAAM;CAAc;CAC/D,IAAI;EAAE,QAAQ;EAA6B,MAAM;CAAU;CAC3D,IAAI;EAAE,QAAQ;EAA8B,MAAM;CAAU;AAC9D,GAIM,IAAa;CACjB,SAAS;CACT,OAAO;AACT,GAEM,IAAqB;CACzB,SAAS;CACT,OAAO;AACT,GAKM,IAAa;CAAE,MAAM;CAAmB,WAAW;CAAK,SAAS;AAAG,GAIpE,IAAmB,EAAM,WAC7B,SACE,EACE,UAAO,MACP,aAAU,WACV,YACA,eACA,aACA,cAAW,IACX,cACA,GAAG,KAEL,GACA;CACA,IAAM,IAAa,EAAM,MAAM,GACzB,IAAa,EAAM,OAA8B,IAAI,GAGrD,IAAY,EAAM,aACrB,MAAgC;EAE/B,AADA,EAAW,UAAU,GACjB,OAAO,KAAQ,aAAY,EAAI,CAAI,IAC9B,MAAK,EAAuD,UAAU;CACjF,GACA,CAAC,CAAG,CACN,GAGM,KAAiB,MAA2C;EAChE,IAAI,GAAU;EAEd,IAAM,IAAe,EAAQ,WAAW,MAAM,EAAE,OAAO,CAAU,GAC7D,IAAY;EAEhB,QAAQ,EAAE,KAAV;GACE,KAAK;IAEH,AADA,EAAE,eAAe,GACjB,IAAY,IAAe,IAAI,IAAe,IAAI,EAAQ,SAAS;IACnE;GACF,KAAK;IAEH,AADA,EAAE,eAAe,GACjB,IAAY,IAAe,EAAQ,SAAS,IAAI,IAAe,IAAI;IACnE;GACF,KAAK;IAEH,AADA,EAAE,eAAe,GACjB,IAAY;IACZ;GACF,KAAK;IAEH,AADA,EAAE,eAAe,GACjB,IAAY,EAAQ,SAAS;IAC7B;GACF,SACE;EACJ;EAGA,AADA,EAAS,EAAQ,EAAU,CAAC,EAAE,GAC9B,4BAA4B;GAE1B,CADgB,EAAW,SAAS,iBAAoC,kBAAgB,EAAA,GAC9E,EAAU,EAAE,MAAM;EAC9B,CAAC;CACH,GAEM,EAAE,QAAQ,GAAY,MAAM,MAAa,EAAW;CAE1D,OACE,kBAAC,OAAD;EACE,KAAK;EACL,MAAK;EACL,UAAU;EACV,cAAY,EAAM,iBAAiB;EACnC,WAAW;EACX,WAAW,EACT,oCACA,4EACA,KAAY,+CACZ,CACF;EACA,GAAI;YAEJ,kBAAC,GAAD;GAAa,IAAI;aACd,EAAQ,KAAK,MAAW;IACvB,IAAM,IAAa,EAAO,OAAO;IAEjC,OACE,kBAAC,UAAD;KAEE,MAAK;KACL,MAAK;KACL,gBAAc;KACd,UAAU,IAAa,IAAI;KACjB;KACV,eAAe,EAAS,EAAO,EAAE;KACjC,WAAW,EACT,2EACA,2EACA,+FACA,GACA,IACI,EAAmB,KACnB,6CACN;eAhBF;MAmBG,KACC,kBAAC,EAAO,MAAR;OACE,UAAS;OACT,WAAW,EACT,qDACA,EAAW,EACb;OACA,YAAY;MACb,CAAA;MAIF,EAAO,QACN,kBAAC,QAAD;OAAM,WAAW,EAAG,mEAAmE,CAAQ;iBAC7F,kBAAC,GAAD;QAAc,MAAM,MAAS,OAAO,OAAO;kBACxC,EAAc,EAAO,IAAI;OACd,CAAA;MACV,CAAA;MAER,kBAAC,QAAD;OAAM,WAAU;iBAAkB,EAAO;MAAW,CAAA;KAC9C;OAtCD,EAAO,EAsCN;GAEZ,CAAC;EACU,CAAA;CACV,CAAA;AAET,CACF;AACA,EAAiB,cAAc"}
|
package/dist/ui/select.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../src/ui/select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,eAAe,MAAM,0BAA0B,CAAA;AAE3D,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,QAAA,MAAM,MAAM,uCAAuB,CAAA;AAEnC,QAAA,MAAM,WAAW,yGAAwB,CAAA;AAEzC,QAAA,MAAM,WAAW,0GAAwB,CAAA;AAEzC,eAAO,MAAM,qBAAqB;;;;8EA2BjC,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBACf,SAAQ,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,OAAO,eAAe,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,EACnF,YAAY,CAAC,OAAO,qBAAqB,CAAC;CAAG;AAEjD,QAAA,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../src/ui/select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,eAAe,MAAM,0BAA0B,CAAA;AAE3D,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,QAAA,MAAM,MAAM,uCAAuB,CAAA;AAEnC,QAAA,MAAM,WAAW,yGAAwB,CAAA;AAEzC,QAAA,MAAM,WAAW,0GAAwB,CAAA;AAEzC,eAAO,MAAM,qBAAqB;;;;8EA2BjC,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBACf,SAAQ,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,OAAO,eAAe,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,EACnF,YAAY,CAAC,OAAO,qBAAqB,CAAC;CAAG;AAEjD,QAAA,MAAM,aAAa,8FA2BjB,CAAA;AAGF,QAAA,MAAM,oBAAoB,qKAcxB,CAAA;AAGF,QAAA,MAAM,sBAAsB,uKAc1B,CAAA;AAIF,QAAA,MAAM,aAAa,8JAoCjB,CAAA;AAGF,QAAA,MAAM,WAAW,4JASf,CAAA;AAGF,QAAA,MAAM,UAAU,2JAmBd,CAAA;AAGF,QAAA,MAAM,eAAe,gKASnB,CAAA;AAGF,OAAO,EACL,MAAM,EACN,aAAa,EACb,WAAW,EACX,UAAU,EACV,WAAW,EACX,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,WAAW,GACZ,CAAA"}
|
package/dist/ui/select.js
CHANGED
|
@@ -25,10 +25,10 @@ var k = c, A = t, j = p, M = _("flex w-full items-center justify-between whitesp
|
|
|
25
25
|
warning: "border-warning-7"
|
|
26
26
|
},
|
|
27
27
|
size: {
|
|
28
|
-
xs: "h-ds-xs-plus text-
|
|
29
|
-
sm: "h-ds-sm text-
|
|
30
|
-
md: "h-ds-md text-
|
|
31
|
-
lg: "h-ds-lg text-
|
|
28
|
+
xs: "h-ds-xs-plus text-body-sm px-ds-02",
|
|
29
|
+
sm: "h-ds-sm text-body-sm px-ds-03",
|
|
30
|
+
md: "h-ds-md text-body-md px-ds-04",
|
|
31
|
+
lg: "h-ds-lg text-body-md px-ds-05"
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
defaultVariants: {
|
|
@@ -49,6 +49,7 @@ var k = c, A = t, j = p, M = _("flex w-full items-center justify-between whitesp
|
|
|
49
49
|
"aria-describedby": u,
|
|
50
50
|
"aria-required": d || void 0,
|
|
51
51
|
...o,
|
|
52
|
+
id: o.id ?? c.inputId,
|
|
52
53
|
children: [t, /* @__PURE__ */ C(n, {
|
|
53
54
|
asChild: !0,
|
|
54
55
|
children: /* @__PURE__ */ C(y, {
|
|
@@ -112,13 +113,13 @@ var I = S.forwardRef(({ className: t, children: n, position: r = "popper", ...i
|
|
|
112
113
|
I.displayName = e.displayName;
|
|
113
114
|
var L = S.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ C(o, {
|
|
114
115
|
ref: n,
|
|
115
|
-
className: v("px-ds-03 py-ds-02b text-
|
|
116
|
+
className: v("px-ds-03 py-ds-02b text-body-md font-semibold", e),
|
|
116
117
|
...t
|
|
117
118
|
}));
|
|
118
119
|
L.displayName = o.displayName;
|
|
119
120
|
var R = S.forwardRef(({ className: e, children: t, ...n }, o) => /* @__PURE__ */ w(r, {
|
|
120
121
|
ref: o,
|
|
121
|
-
className: v("relative flex w-full cursor-default select-none items-center rounded-control py-ds-02b pl-ds-03 pr-ds-07 text-
|
|
122
|
+
className: v("relative flex w-full cursor-default select-none items-center rounded-control py-ds-02b pl-ds-03 pr-ds-07 text-body-md outline-hidden transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled", e),
|
|
122
123
|
...n,
|
|
123
124
|
children: [/* @__PURE__ */ C("span", {
|
|
124
125
|
className: "absolute right-ds-03 flex h-ico-sm w-ico-sm items-center justify-center",
|
package/dist/ui/select.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.js","names":[],"sources":["../../src/ui/select.tsx"],"sourcesContent":["'use client'\n\nimport * as SelectPrimitive from '@primitives/react-select'\nimport { IconCheck, IconChevronDown, IconChevronUp } 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 { type FieldState, resolveFieldState } from './lib/field-state'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n/**\n * Select root — manages open/close state and selected value.\n *\n * **Important:** `size` is NOT a prop on `Select`. Set it on `SelectTrigger` instead.\n * Passing `size` directly to `Select` produces no TypeScript error but has no effect.\n *\n * @example\n * // CORRECT — size goes on SelectTrigger:\n * <Select onValueChange={setValue}>\n * <SelectTrigger size=\"lg\">\n * <SelectValue placeholder=\"Choose...\" />\n * </SelectTrigger>\n * <SelectContent>\n * <SelectItem value=\"a\">Option A</SelectItem>\n * <SelectItem value=\"b\">Option B</SelectItem>\n * </SelectContent>\n * </Select>\n *\n * // WRONG — size on Select root is silently ignored (no TypeScript error):\n * // <Select size=\"lg\">...</Select>\n */\nconst Select = SelectPrimitive.Root\n\nconst SelectGroup = SelectPrimitive.Group\n\nconst SelectValue = SelectPrimitive.Value\n\nexport const selectTriggerVariants = cva(\n 'flex w-full items-center justify-between whitespace-nowrap rounded-control placeholder:text-surface-fg-subtle focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-action-disabled [&>span]:line-clamp-1 [&>span]:min-w-0',\n {\n variants: {\n variant: {\n default:\n 'border border-surface-border-strong bg-surface-raised-hover focus-visible:border-accent-7',\n outline:\n 'border border-surface-border-strong bg-transparent focus-visible:border-accent-7',\n ghost:\n 'border border-transparent bg-transparent hover:bg-surface-raised-hover focus-visible:border-accent-7',\n },\n state: {\n default: '',\n error: 'border-error-7 text-error-11 focus-visible:ring-error-9',\n success: 'border-success-7',\n warning: 'border-warning-7',\n },\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: { variant: 'default', state: 'default', size: 'md' },\n },\n)\n\n/**\n * Props for SelectTrigger. Use `size` here (not on the `Select` root).\n *\n * @example\n * <SelectTrigger size=\"lg\" className=\"w-[200px]\">\n * <SelectValue placeholder=\"Select an option\" />\n * </SelectTrigger>\n */\nexport interface SelectTriggerProps\n extends Omit<React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>, 'color'>,\n VariantProps<typeof selectTriggerVariants> {}\n\nconst SelectTrigger = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n SelectTriggerProps\n>(({ className, children, variant, state: stateProp, size, ...props }, ref) => {\n const fieldCtx = useFormField()\n // Explicit `state` prop wins over FormField context (shared precedence).\n const state = resolveFieldState((stateProp ?? undefined) as FieldState | undefined, fieldCtx.state)\n const ariaDescribedBy = props['aria-describedby'] ?? fieldCtx.helperTextId\n const ariaRequired = props['aria-required'] ?? fieldCtx.required\n\n return (\n <SelectPrimitive.Trigger\n ref={ref}\n className={cn(selectTriggerVariants({ variant, state: state ?? 'default', size }), className)}\n aria-invalid={state === 'error' || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <Icon icon={IconChevronDown} size=\"sm\" className=\"opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n )\n})\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName\n\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollUpButton\n ref={ref}\n className={cn(\n 'flex cursor-default items-center justify-center py-ds-02',\n className,\n )}\n {...props}\n >\n <Icon icon={IconChevronUp} size=\"sm\" />\n </SelectPrimitive.ScrollUpButton>\n))\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName\n\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollDownButton\n ref={ref}\n className={cn(\n 'flex cursor-default items-center justify-center py-ds-02',\n className,\n )}\n {...props}\n >\n <Icon icon={IconChevronDown} size=\"sm\" />\n </SelectPrimitive.ScrollDownButton>\n))\nSelectScrollDownButton.displayName =\n SelectPrimitive.ScrollDownButton.displayName\n\nconst SelectContent = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>\n>(({ className, children, position = 'popper', ...props }, ref) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n position={position}\n asChild\n {...props}\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 'relative z-popover max-h-96 min-w-[8rem] overflow-hidden rounded-overlay bg-surface-overlay text-surface-fg shadow-floating',\n position === 'popper' &&\n 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',\n className,\n )}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n 'p-ds-02',\n position === 'popper' &&\n 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </motion.div>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n))\nSelectContent.displayName = SelectPrimitive.Content.displayName\n\nconst SelectLabel = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Label\n ref={ref}\n className={cn('px-ds-03 py-ds-02b text-ds-md font-semibold', className)}\n {...props}\n />\n))\nSelectLabel.displayName = SelectPrimitive.Label.displayName\n\nconst SelectItem = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex w-full cursor-default select-none items-center rounded-control py-ds-02b pl-ds-03 pr-ds-07 text-ds-md outline-hidden transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled',\n className,\n )}\n {...props}\n >\n <span className=\"absolute right-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <Icon icon={IconCheck} size=\"sm\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText className=\"min-w-0 line-clamp-1\">{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n))\nSelectItem.displayName = SelectPrimitive.Item.displayName\n\nconst SelectSeparator = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn('-mx-ds-01 my-ds-02 h-px bg-surface-border', className)}\n {...props}\n />\n))\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName\n\nexport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"select.js","names":[],"sources":["../../src/ui/select.tsx"],"sourcesContent":["'use client'\n\nimport * as SelectPrimitive from '@primitives/react-select'\nimport { IconCheck, IconChevronDown, IconChevronUp } 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 { type FieldState, resolveFieldState } from './lib/field-state'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\n/**\n * Select root — manages open/close state and selected value.\n *\n * **Important:** `size` is NOT a prop on `Select`. Set it on `SelectTrigger` instead.\n * Passing `size` directly to `Select` produces no TypeScript error but has no effect.\n *\n * @example\n * // CORRECT — size goes on SelectTrigger:\n * <Select onValueChange={setValue}>\n * <SelectTrigger size=\"lg\">\n * <SelectValue placeholder=\"Choose...\" />\n * </SelectTrigger>\n * <SelectContent>\n * <SelectItem value=\"a\">Option A</SelectItem>\n * <SelectItem value=\"b\">Option B</SelectItem>\n * </SelectContent>\n * </Select>\n *\n * // WRONG — size on Select root is silently ignored (no TypeScript error):\n * // <Select size=\"lg\">...</Select>\n */\nconst Select = SelectPrimitive.Root\n\nconst SelectGroup = SelectPrimitive.Group\n\nconst SelectValue = SelectPrimitive.Value\n\nexport const selectTriggerVariants = cva(\n 'flex w-full items-center justify-between whitespace-nowrap rounded-control placeholder:text-surface-fg-subtle focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-action-disabled [&>span]:line-clamp-1 [&>span]:min-w-0',\n {\n variants: {\n variant: {\n default:\n 'border border-surface-border-strong bg-surface-raised-hover focus-visible:border-accent-7',\n outline:\n 'border border-surface-border-strong bg-transparent focus-visible:border-accent-7',\n ghost:\n 'border border-transparent bg-transparent hover:bg-surface-raised-hover focus-visible:border-accent-7',\n },\n state: {\n default: '',\n error: 'border-error-7 text-error-11 focus-visible:ring-error-9',\n success: 'border-success-7',\n warning: 'border-warning-7',\n },\n size: {\n xs: 'h-ds-xs-plus text-body-sm px-ds-02',\n sm: 'h-ds-sm text-body-sm px-ds-03',\n md: 'h-ds-md text-body-md px-ds-04',\n lg: 'h-ds-lg text-body-md px-ds-05',\n },\n },\n defaultVariants: { variant: 'default', state: 'default', size: 'md' },\n },\n)\n\n/**\n * Props for SelectTrigger. Use `size` here (not on the `Select` root).\n *\n * @example\n * <SelectTrigger size=\"lg\" className=\"w-[200px]\">\n * <SelectValue placeholder=\"Select an option\" />\n * </SelectTrigger>\n */\nexport interface SelectTriggerProps\n extends Omit<React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>, 'color'>,\n VariantProps<typeof selectTriggerVariants> {}\n\nconst SelectTrigger = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n SelectTriggerProps\n>(({ className, children, variant, state: stateProp, size, ...props }, ref) => {\n const fieldCtx = useFormField()\n // Explicit `state` prop wins over FormField context (shared precedence).\n const state = resolveFieldState((stateProp ?? undefined) as FieldState | undefined, fieldCtx.state)\n const ariaDescribedBy = props['aria-describedby'] ?? fieldCtx.helperTextId\n const ariaRequired = props['aria-required'] ?? fieldCtx.required\n\n return (\n <SelectPrimitive.Trigger\n ref={ref}\n className={cn(selectTriggerVariants({ variant, state: state ?? 'default', size }), className)}\n aria-invalid={state === 'error' || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n {...props}\n // Explicit id wins; otherwise adopt FormField's inputId so <Label htmlFor> resolves.\n id={props.id ?? fieldCtx.inputId}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <Icon icon={IconChevronDown} size=\"sm\" className=\"opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n )\n})\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName\n\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollUpButton\n ref={ref}\n className={cn(\n 'flex cursor-default items-center justify-center py-ds-02',\n className,\n )}\n {...props}\n >\n <Icon icon={IconChevronUp} size=\"sm\" />\n </SelectPrimitive.ScrollUpButton>\n))\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName\n\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollDownButton\n ref={ref}\n className={cn(\n 'flex cursor-default items-center justify-center py-ds-02',\n className,\n )}\n {...props}\n >\n <Icon icon={IconChevronDown} size=\"sm\" />\n </SelectPrimitive.ScrollDownButton>\n))\nSelectScrollDownButton.displayName =\n SelectPrimitive.ScrollDownButton.displayName\n\nconst SelectContent = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>\n>(({ className, children, position = 'popper', ...props }, ref) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n position={position}\n asChild\n {...props}\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 'relative z-popover max-h-96 min-w-[8rem] overflow-hidden rounded-overlay bg-surface-overlay text-surface-fg shadow-floating',\n position === 'popper' &&\n 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',\n className,\n )}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n 'p-ds-02',\n position === 'popper' &&\n 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </motion.div>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n))\nSelectContent.displayName = SelectPrimitive.Content.displayName\n\nconst SelectLabel = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Label\n ref={ref}\n className={cn('px-ds-03 py-ds-02b text-body-md font-semibold', className)}\n {...props}\n />\n))\nSelectLabel.displayName = SelectPrimitive.Label.displayName\n\nconst SelectItem = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex w-full cursor-default select-none items-center rounded-control py-ds-02b pl-ds-03 pr-ds-07 text-body-md outline-hidden transition-colors duration-fast-01 ease-productive-standard hover:bg-surface-raised focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled',\n className,\n )}\n {...props}\n >\n <span className=\"absolute right-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <Icon icon={IconCheck} size=\"sm\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText className=\"min-w-0 line-clamp-1\">{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n))\nSelectItem.displayName = SelectPrimitive.Item.displayName\n\nconst SelectSeparator = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn('-mx-ds-01 my-ds-02 h-px bg-surface-border', className)}\n {...props}\n />\n))\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName\n\nexport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n}\n"],"mappings":"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"}
|