@devalok/shilp-sutra 0.49.3 → 0.49.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/badge-group.js +8 -7
- package/dist/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/block-shell.js.map +1 -1
- package/dist/_chunks/chart-container.js.map +1 -1
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/colors.js.map +1 -1
- package/dist/_chunks/document-preview.js.map +1 -1
- package/dist/_chunks/emoji-suggestion.js.map +1 -1
- package/dist/_chunks/emoji.js +2 -2
- package/dist/_chunks/emoji.js.map +1 -1
- package/dist/_chunks/field-state.js.map +1 -1
- package/dist/_chunks/grid-lines.js.map +1 -1
- package/dist/_chunks/image-preview.js.map +1 -1
- package/dist/_chunks/keybinding.js.map +1 -1
- package/dist/_chunks/link-context.js.map +1 -1
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/motion-provider.js.map +1 -1
- package/dist/_chunks/normalize-icon.js.map +1 -1
- package/dist/_chunks/oauth-button.js.map +1 -1
- package/dist/_chunks/popover.js.map +1 -1
- package/dist/_chunks/primitives.js +1123 -1153
- package/dist/_chunks/primitives.js.map +1 -1
- package/dist/_chunks/shared.js.map +1 -1
- package/dist/_chunks/success.js.map +1 -1
- package/dist/_chunks/tiptap.js +4283 -3460
- package/dist/_chunks/tiptap.js.map +1 -1
- package/dist/_chunks/tooltip.js.map +1 -1
- package/dist/_chunks/tree-view.js +1 -1
- package/dist/_chunks/tree-view.js.map +1 -1
- package/dist/_chunks/use-calendar.js.map +1 -1
- package/dist/_chunks/use-controllable-open.js.map +1 -1
- package/dist/_chunks/vendor-client.js +86 -59
- package/dist/_chunks/vendor-client.js.map +1 -1
- package/dist/_chunks/vendor-utils.js +555 -513
- package/dist/_chunks/vendor-utils.js.map +1 -1
- package/dist/ai/ai-command-provider.d.ts +1 -1
- package/dist/ai/ai-command-provider.d.ts.map +1 -1
- package/dist/ai/ai-command-provider.js.map +1 -1
- package/dist/ai/block-renderer.js.map +1 -1
- package/dist/ai/blocks/block-shell.d.ts +1 -1
- package/dist/ai/blocks/block-shell.d.ts.map +1 -1
- package/dist/ai/blocks/block-table.d.ts +1 -1
- package/dist/ai/blocks/block-table.d.ts.map +1 -1
- package/dist/ai/blocks/confirm.d.ts +1 -1
- package/dist/ai/blocks/confirm.d.ts.map +1 -1
- package/dist/ai/blocks/divider.d.ts +1 -1
- package/dist/ai/blocks/divider.d.ts.map +1 -1
- package/dist/ai/blocks/error.d.ts +1 -1
- package/dist/ai/blocks/error.d.ts.map +1 -1
- package/dist/ai/blocks/error.js.map +1 -1
- package/dist/ai/blocks/info.d.ts +1 -1
- package/dist/ai/blocks/info.d.ts.map +1 -1
- package/dist/ai/blocks/loading.d.ts +1 -1
- package/dist/ai/blocks/loading.d.ts.map +1 -1
- package/dist/ai/blocks/stat-row.d.ts +1 -1
- package/dist/ai/blocks/stat-row.d.ts.map +1 -1
- package/dist/ai/blocks/success.d.ts +1 -1
- package/dist/ai/blocks/success.d.ts.map +1 -1
- package/dist/ai/blocks/text.d.ts +1 -1
- package/dist/ai/blocks/text.d.ts.map +1 -1
- package/dist/ai/blocks/text.js.map +1 -1
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/ai/conversation.js.map +1 -1
- package/dist/ai/devadoot-icon.d.ts +1 -1
- package/dist/ai/devadoot-icon.d.ts.map +1 -1
- package/dist/ai/index.js.map +1 -1
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/avatar-group.js.map +1 -1
- package/dist/composed/bulk-action-bar.js.map +1 -1
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/confirm-dialog.js.map +1 -1
- package/dist/composed/content-card.js.map +1 -1
- package/dist/composed/date-picker/index.js.map +1 -1
- package/dist/composed/deadline-indicator.js.map +1 -1
- package/dist/composed/emoji-picker.d.ts +2 -2
- package/dist/composed/emoji-picker.d.ts.map +1 -1
- package/dist/composed/emoji-picker.js.map +1 -1
- package/dist/composed/empty-state.js.map +1 -1
- package/dist/composed/error-boundary.d.ts +1 -1
- package/dist/composed/error-boundary.js.map +1 -1
- package/dist/composed/extensions/emoji-node.js.map +1 -1
- package/dist/composed/file-preview/audio-preview.d.ts +2 -1
- package/dist/composed/file-preview/audio-preview.d.ts.map +1 -1
- package/dist/composed/file-preview/document-preview.d.ts +2 -1
- package/dist/composed/file-preview/document-preview.d.ts.map +1 -1
- package/dist/composed/file-preview/embed-preview.d.ts +2 -1
- package/dist/composed/file-preview/embed-preview.d.ts.map +1 -1
- package/dist/composed/file-preview/image-preview.d.ts +2 -1
- package/dist/composed/file-preview/image-preview.d.ts.map +1 -1
- package/dist/composed/file-preview/shared.d.ts +5 -5
- package/dist/composed/file-preview/shared.d.ts.map +1 -1
- package/dist/composed/file-preview/video-preview.d.ts +2 -1
- package/dist/composed/file-preview/video-preview.d.ts.map +1 -1
- package/dist/composed/file-preview.d.ts +1 -1
- package/dist/composed/file-preview.d.ts.map +1 -1
- package/dist/composed/file-preview.js.map +1 -1
- package/dist/composed/filter-bar.d.ts +2 -2
- package/dist/composed/filter-bar.d.ts.map +1 -1
- package/dist/composed/filter-bar.js.map +1 -1
- package/dist/composed/form-section.js.map +1 -1
- package/dist/composed/global-loading.js.map +1 -1
- package/dist/composed/inline-edit.js.map +1 -1
- package/dist/composed/lib/string-utils.js.map +1 -1
- package/dist/composed/loading-skeleton.js.map +1 -1
- package/dist/composed/markdown-viewer.js.map +1 -1
- package/dist/composed/master-detail.d.ts +3 -3
- package/dist/composed/master-detail.d.ts.map +1 -1
- package/dist/composed/master-detail.js.map +1 -1
- package/dist/composed/member-picker.js.map +1 -1
- package/dist/composed/multi-select-popover.js.map +1 -1
- package/dist/composed/page-header.js.map +1 -1
- package/dist/composed/page-skeletons.js.map +1 -1
- package/dist/composed/priority-indicator.js.map +1 -1
- package/dist/composed/responsive-modal.js +8 -4
- package/dist/composed/responsive-modal.js.map +1 -1
- package/dist/composed/rich-chat-input/attachment-strip.d.ts +2 -1
- package/dist/composed/rich-chat-input/attachment-strip.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/chat-toolbar.d.ts +17 -17
- package/dist/composed/rich-chat-input/chat-toolbar.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/recording-overlay.d.ts +2 -1
- package/dist/composed/rich-chat-input/recording-overlay.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/reply-banner.d.ts +2 -1
- package/dist/composed/rich-chat-input/reply-banner.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/schedule-send.d.ts +4 -3
- package/dist/composed/rich-chat-input/schedule-send.d.ts.map +1 -1
- package/dist/composed/rich-chat-input.js +2 -1
- package/dist/composed/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.js +2 -1
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/composed/schedule-view.js.map +1 -1
- package/dist/composed/simple-tooltip.js.map +1 -1
- package/dist/composed/status-badge.js.map +1 -1
- package/dist/hooks/use-color-mode.js +2 -1
- package/dist/hooks/use-color-mode.js.map +1 -1
- package/dist/hooks/use-mobile.js.map +1 -1
- package/dist/hooks/use-touch-device.js.map +1 -1
- package/dist/hooks/use-viewport-height.js.map +1 -1
- package/dist/motion/index.js.map +1 -1
- package/dist/motion/motion-provider.d.ts +1 -1
- package/dist/motion/motion-provider.d.ts.map +1 -1
- package/dist/motion/primitives-index.js.map +1 -1
- package/dist/shell/app-command-palette.js.map +1 -1
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/command-registry.d.ts +1 -1
- package/dist/shell/command-registry.d.ts.map +1 -1
- package/dist/shell/command-registry.js.map +1 -1
- package/dist/shell/notification-center.js.map +1 -1
- package/dist/shell/notification-preferences.js.map +1 -1
- package/dist/shell/sidebar.js.map +1 -1
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/ui/accordion.js.map +1 -1
- package/dist/ui/alert-dialog.js.map +1 -1
- package/dist/ui/alert.js.map +1 -1
- package/dist/ui/aspect-ratio.js.map +1 -1
- package/dist/ui/autocomplete.d.ts.map +1 -1
- package/dist/ui/autocomplete.js +8 -0
- package/dist/ui/autocomplete.js.map +1 -1
- package/dist/ui/avatar.d.ts +1 -1
- 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.map +1 -1
- package/dist/ui/breadcrumb.d.ts +2 -2
- package/dist/ui/breadcrumb.js.map +1 -1
- package/dist/ui/button-group.js.map +1 -1
- package/dist/ui/button-processing.d.ts +2 -1
- package/dist/ui/button-processing.d.ts.map +1 -1
- package/dist/ui/button-processing.js.map +1 -1
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.js +1 -1
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/charts/_internal/axes.d.ts +2 -1
- package/dist/ui/charts/_internal/axes.d.ts.map +1 -1
- package/dist/ui/charts/_internal/grid-lines.d.ts +2 -1
- package/dist/ui/charts/_internal/grid-lines.d.ts.map +1 -1
- package/dist/ui/charts/_internal/legend.d.ts +2 -1
- package/dist/ui/charts/_internal/legend.d.ts.map +1 -1
- package/dist/ui/charts/_internal/tooltip.d.ts +1 -1
- package/dist/ui/charts/_internal/tooltip.d.ts.map +1 -1
- package/dist/ui/charts/area-chart.js.map +1 -1
- package/dist/ui/charts/bar-chart.js.map +1 -1
- package/dist/ui/charts/gauge-chart.js.map +1 -1
- package/dist/ui/charts/line-chart.js.map +1 -1
- package/dist/ui/charts/pie-chart.js.map +1 -1
- package/dist/ui/charts/radar-chart.js.map +1 -1
- package/dist/ui/charts/sparkline.js +2 -2
- package/dist/ui/charts/sparkline.js.map +1 -1
- package/dist/ui/chat/date-separator.d.ts +2 -1
- package/dist/ui/chat/date-separator.d.ts.map +1 -1
- package/dist/ui/chat/message.d.ts +8 -8
- package/dist/ui/chat/message.d.ts.map +1 -1
- package/dist/ui/chat/typing-indicator.d.ts +2 -1
- package/dist/ui/chat/typing-indicator.d.ts.map +1 -1
- package/dist/ui/chat/unread-separator.d.ts +2 -1
- package/dist/ui/chat/unread-separator.d.ts.map +1 -1
- package/dist/ui/checkbox.js.map +1 -1
- package/dist/ui/code.js.map +1 -1
- package/dist/ui/collapsible.js.map +1 -1
- package/dist/ui/color-input.d.ts.map +1 -1
- package/dist/ui/color-input.js +156 -149
- package/dist/ui/color-input.js.map +1 -1
- package/dist/ui/color-swatch.js.map +1 -1
- package/dist/ui/combobox.d.ts.map +1 -1
- package/dist/ui/combobox.js +137 -127
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/container.js.map +1 -1
- package/dist/ui/context-menu.d.ts +2 -2
- package/dist/ui/context-menu.js.map +1 -1
- package/dist/ui/data-table-body.d.ts +1 -1
- package/dist/ui/data-table-body.d.ts.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.d.ts +2 -1
- package/dist/ui/data-table-bulk-actions.d.ts.map +1 -1
- package/dist/ui/data-table-bulk-actions.js.map +1 -1
- package/dist/ui/data-table-card.d.ts +1 -1
- package/dist/ui/data-table-card.d.ts.map +1 -1
- package/dist/ui/data-table-card.js.map +1 -1
- package/dist/ui/data-table-context.d.ts +1 -1
- package/dist/ui/data-table-context.d.ts.map +1 -1
- package/dist/ui/data-table-context.js.map +1 -1
- package/dist/ui/data-table-header.d.ts +2 -1
- package/dist/ui/data-table-header.d.ts.map +1 -1
- package/dist/ui/data-table-header.js.map +1 -1
- package/dist/ui/data-table-pagination.d.ts +2 -1
- package/dist/ui/data-table-pagination.d.ts.map +1 -1
- package/dist/ui/data-table-pagination.js.map +1 -1
- package/dist/ui/data-table-toolbar.d.ts +1 -1
- package/dist/ui/data-table-toolbar.d.ts.map +1 -1
- package/dist/ui/data-table-toolbar.js.map +1 -1
- package/dist/ui/data-table.d.ts +1 -1
- package/dist/ui/data-table.d.ts.map +1 -1
- package/dist/ui/data-table.js.map +1 -1
- package/dist/ui/devalok-grain.d.ts +2 -1
- package/dist/ui/devalok-grain.d.ts.map +1 -1
- package/dist/ui/devalok-grain.js.map +1 -1
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/dot.js +1 -1
- package/dist/ui/dot.js.map +1 -1
- package/dist/ui/dropdown-menu.d.ts +1 -1
- package/dist/ui/dropdown-menu.js.map +1 -1
- package/dist/ui/file-upload.js.map +1 -1
- package/dist/ui/form.js.map +1 -1
- package/dist/ui/hover-card.js.map +1 -1
- package/dist/ui/icon-button.js.map +1 -1
- package/dist/ui/icon-context.d.ts +1 -1
- package/dist/ui/icon-context.d.ts.map +1 -1
- package/dist/ui/icon-context.js.map +1 -1
- package/dist/ui/icon-group.js.map +1 -1
- package/dist/ui/icon.js.map +1 -1
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/input-otp.js.map +1 -1
- package/dist/ui/input.js.map +1 -1
- package/dist/ui/label.js.map +1 -1
- package/dist/ui/lib/bottom-sheet.d.ts +1 -1
- package/dist/ui/lib/bottom-sheet.d.ts.map +1 -1
- package/dist/ui/lib/date-utils.js.map +1 -1
- package/dist/ui/lib/link-context.d.ts +1 -1
- package/dist/ui/lib/link-context.d.ts.map +1 -1
- package/dist/ui/lib/motion.js.map +1 -1
- package/dist/ui/lib/utils.js.map +1 -1
- package/dist/ui/link.js.map +1 -1
- package/dist/ui/menubar.d.ts +1 -1
- package/dist/ui/menubar.js.map +1 -1
- package/dist/ui/navigation-menu.js +14 -9
- 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 +2 -1
- package/dist/ui/number-input.js.map +1 -1
- package/dist/ui/pagination.js.map +1 -1
- package/dist/ui/progress-ring.js.map +1 -1
- package/dist/ui/progress.js.map +1 -1
- package/dist/ui/radio.js.map +1 -1
- package/dist/ui/search-input.js.map +1 -1
- package/dist/ui/segmented-control.js.map +1 -1
- package/dist/ui/select.d.ts.map +1 -1
- package/dist/ui/select.js +1 -0
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/separator.js.map +1 -1
- package/dist/ui/sheet.js.map +1 -1
- package/dist/ui/sidebar.js +1 -1
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/skeleton.js.map +1 -1
- package/dist/ui/slider.js.map +1 -1
- package/dist/ui/spinner.js.map +1 -1
- package/dist/ui/split-button.js.map +1 -1
- package/dist/ui/stack.js.map +1 -1
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/stat-flash.d.ts +2 -1
- package/dist/ui/stat-flash.d.ts.map +1 -1
- package/dist/ui/stat-flash.js +1 -1
- package/dist/ui/stat-flash.js.map +1 -1
- package/dist/ui/stepper.d.ts +1 -1
- package/dist/ui/stepper.d.ts.map +1 -1
- package/dist/ui/stepper.js +1 -1
- package/dist/ui/stepper.js.map +1 -1
- package/dist/ui/surface.js.map +1 -1
- package/dist/ui/switch.d.ts +1 -1
- package/dist/ui/switch.js.map +1 -1
- package/dist/ui/table-row-link.js.map +1 -1
- package/dist/ui/table.js.map +1 -1
- package/dist/ui/tabs.js.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 +3 -2
- package/dist/ui/textarea.js.map +1 -1
- package/dist/ui/toast-registry.js.map +1 -1
- package/dist/ui/toast.d.ts +4 -4
- package/dist/ui/toast.d.ts.map +1 -1
- package/dist/ui/toast.js +5 -3
- package/dist/ui/toast.js.map +1 -1
- package/dist/ui/toaster.js.map +1 -1
- package/dist/ui/toggle-group.js.map +1 -1
- package/dist/ui/toggle.js.map +1 -1
- package/dist/ui/tooltip.js.map +1 -1
- package/dist/ui/truncated-text.js.map +1 -1
- package/dist/ui/visually-hidden.js.map +1 -1
- package/docs/components/ui/data-table.md +2 -2
- package/llms.txt +1 -1
- package/mcp-manifest.json +3 -3
- package/package.json +21 -21
- package/skill/SKILL.md +1 -1
- package/skill/references/components.md +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Table } from '@tanstack/react-table';
|
|
3
|
+
import { default as React } from 'react';
|
|
3
4
|
/**
|
|
4
5
|
* Pagination controls: page size selector, prev/next buttons, page info.
|
|
5
6
|
* Internal — not exported to consumers.
|
|
@@ -9,5 +10,5 @@ export declare function DataTablePagination<TData>({ table, totalRowCount, useSe
|
|
|
9
10
|
totalRowCount: number;
|
|
10
11
|
useServerPagination: boolean;
|
|
11
12
|
pageSizeOptions?: number[];
|
|
12
|
-
}):
|
|
13
|
+
}): React.JSX.Element;
|
|
13
14
|
//# sourceMappingURL=data-table-pagination.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table-pagination.d.ts","sourceRoot":"","sources":["../../src/ui/data-table-pagination.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"data-table-pagination.d.ts","sourceRoot":"","sources":["../../src/ui/data-table-pagination.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,EACzC,KAAK,EACL,aAAa,EACb,mBAAmB,EACnB,eAAe,GAChB,EAAE;IACD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;IACrB,mBAAmB,EAAE,OAAO,CAAA;IAC5B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B,qBAwEA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table-pagination.js","names":[],"sources":["../../src/ui/data-table-pagination.tsx"],"sourcesContent":["'use client'\n\nimport { IconChevronLeft, IconChevronRight } from '@tabler/icons-react'\nimport { type Table } from '@tanstack/react-table'\nimport React from 'react'\n\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\n\n/**\n * Pagination controls: page size selector, prev/next buttons, page info.\n * Internal — not exported to consumers.\n */\nexport function DataTablePagination<TData>({\n table,\n totalRowCount,\n useServerPagination,\n pageSizeOptions,\n}: {\n table: Table<TData>\n totalRowCount: number\n useServerPagination: boolean\n pageSizeOptions?: number[]\n}) {\n return (\n <div className=\"flex items-center justify-between px-ds-03 py-ds-04 border-t border-surface-border\">\n <span className=\"text-ds-sm text-surface-fg-muted\">\n {totalRowCount} total rows\n </span>\n <div className=\"flex items-center gap-ds-03\">\n {/* Page size selector */}\n {!useServerPagination && (\n <select\n value={table.getState().pagination.pageSize}\n onChange={(e) => {\n table.setPageSize(Number(e.target.value))\n }}\n aria-label=\"Rows per page\"\n className={cn(\n 'h-ds-sm rounded-control',\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'px-ds-03 text-ds-sm',\n 'text-surface-fg',\n )}\n >\n {(pageSizeOptions ?? [10, 20, 50, 100]).map((size) => (\n <option key={size} value={size}>\n {size} rows\n </option>\n ))}\n </select>\n )}\n\n {/* Previous page button */}\n <button\n type=\"button\"\n disabled={!table.getCanPreviousPage()}\n onClick={() => table.previousPage()}\n aria-label=\"Previous page\"\n className={cn(\n 'h-ds-sm w-ds-sm flex items-center justify-center',\n 'rounded-control border border-surface-border-strong',\n 'enabled:hover:bg-surface-raised',\n 'disabled:opacity-action-disabled disabled:cursor-not-allowed',\n 'transition-colors',\n )}\n >\n <Icon icon={IconChevronLeft} size=\"sm\" />\n </button>\n\n {/* Page info */}\n <span className=\"text-ds-sm text-surface-fg-muted\">\n Page {table.getState().pagination.pageIndex + 1} of{' '}\n {table.getPageCount()}\n </span>\n\n {/* Next page button */}\n <button\n type=\"button\"\n disabled={!table.getCanNextPage()}\n onClick={() => table.nextPage()}\n aria-label=\"Next page\"\n className={cn(\n 'h-ds-sm w-ds-sm flex items-center justify-center',\n 'rounded-control border border-surface-border-strong',\n 'enabled:hover:bg-surface-raised',\n 'disabled:opacity-action-disabled disabled:cursor-not-allowed',\n 'transition-colors',\n )}\n >\n <Icon icon={IconChevronRight} size=\"sm\" />\n </button>\n </div>\n </div>\n )\n}\n"],"mappings":";;;;;;;AAaA,SAAgB,EAA2B,EACzC,UACA,kBACA,wBACA,sBAMC;
|
|
1
|
+
{"version":3,"file":"data-table-pagination.js","names":[],"sources":["../../src/ui/data-table-pagination.tsx"],"sourcesContent":["'use client'\n\nimport { IconChevronLeft, IconChevronRight } from '@tabler/icons-react'\nimport { type Table } from '@tanstack/react-table'\nimport React from 'react'\n\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\n\n/**\n * Pagination controls: page size selector, prev/next buttons, page info.\n * Internal — not exported to consumers.\n */\nexport function DataTablePagination<TData>({\n table,\n totalRowCount,\n useServerPagination,\n pageSizeOptions,\n}: {\n table: Table<TData>\n totalRowCount: number\n useServerPagination: boolean\n pageSizeOptions?: number[]\n}) {\n return (\n <div className=\"flex items-center justify-between px-ds-03 py-ds-04 border-t border-surface-border\">\n <span className=\"text-ds-sm text-surface-fg-muted\">\n {totalRowCount} total rows\n </span>\n <div className=\"flex items-center gap-ds-03\">\n {/* Page size selector */}\n {!useServerPagination && (\n <select\n value={table.getState().pagination.pageSize}\n onChange={(e) => {\n table.setPageSize(Number(e.target.value))\n }}\n aria-label=\"Rows per page\"\n className={cn(\n 'h-ds-sm rounded-control',\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'px-ds-03 text-ds-sm',\n 'text-surface-fg',\n )}\n >\n {(pageSizeOptions ?? [10, 20, 50, 100]).map((size) => (\n <option key={size} value={size}>\n {size} rows\n </option>\n ))}\n </select>\n )}\n\n {/* Previous page button */}\n <button\n type=\"button\"\n disabled={!table.getCanPreviousPage()}\n onClick={() => table.previousPage()}\n aria-label=\"Previous page\"\n className={cn(\n 'h-ds-sm w-ds-sm flex items-center justify-center',\n 'rounded-control border border-surface-border-strong',\n 'enabled:hover:bg-surface-raised',\n 'disabled:opacity-action-disabled disabled:cursor-not-allowed',\n 'transition-colors',\n )}\n >\n <Icon icon={IconChevronLeft} size=\"sm\" />\n </button>\n\n {/* Page info */}\n <span className=\"text-ds-sm text-surface-fg-muted\">\n Page {table.getState().pagination.pageIndex + 1} of{' '}\n {table.getPageCount()}\n </span>\n\n {/* Next page button */}\n <button\n type=\"button\"\n disabled={!table.getCanNextPage()}\n onClick={() => table.nextPage()}\n aria-label=\"Next page\"\n className={cn(\n 'h-ds-sm w-ds-sm flex items-center justify-center',\n 'rounded-control border border-surface-border-strong',\n 'enabled:hover:bg-surface-raised',\n 'disabled:opacity-action-disabled disabled:cursor-not-allowed',\n 'transition-colors',\n )}\n >\n <Icon icon={IconChevronRight} size=\"sm\" />\n </button>\n </div>\n </div>\n )\n}\n"],"mappings":";;;;;;;AAaA,SAAgB,EAA2B,EACzC,UACA,kBACA,wBACA,sBAMC;CACD,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,QAAD;GAAM,WAAU;aAAhB,CACG,GAAc,aACX;MACN,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEG,CAAC,KACA,kBAAC,UAAD;KACE,OAAO,EAAM,SAAS,CAAC,CAAC,WAAW;KACnC,WAAW,MAAM;MACf,EAAM,YAAY,OAAO,EAAE,OAAO,KAAK,CAAC;KAC1C;KACA,cAAW;KACX,WAAW,EACT,2BACA,+DACA,uBACA,iBACF;gBAEE,KAAmB;MAAC;MAAI;MAAI;MAAI;KAAG,EAAA,CAAG,KAAK,MAC3C,kBAAC,UAAD;MAAmB,OAAO;gBAA1B,CACG,GAAK,OACA;QAFK,CAEL,CACT;IACK,CAAA;IAIV,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,CAAC,EAAM,mBAAmB;KACpC,eAAe,EAAM,aAAa;KAClC,cAAW;KACX,WAAW,EACT,oDACA,uDACA,mCACA,gEACA,mBACF;eAEA,kBAAC,GAAD;MAAM,MAAM;MAAiB,MAAK;KAAM,CAAA;IAClC,CAAA;IAGR,kBAAC,QAAD;KAAM,WAAU;eAAhB;MAAmD;MAC3C,EAAM,SAAS,CAAC,CAAC,WAAW,YAAY;MAAE;MAAI;MACnD,EAAM,aAAa;KAChB;;IAGN,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,CAAC,EAAM,eAAe;KAChC,eAAe,EAAM,SAAS;KAC9B,cAAW;KACX,WAAW,EACT,oDACA,uDACA,mCACA,gEACA,mBACF;eAEA,kBAAC,GAAD;MAAM,MAAM;MAAkB,MAAK;KAAM,CAAA;IACnC,CAAA;GACL;IACF;;AAET"}
|
|
@@ -11,7 +11,7 @@ export interface DataTableToolbarProps<TData> extends Omit<React.HTMLAttributes<
|
|
|
11
11
|
onDensityChange: (density: Density) => void;
|
|
12
12
|
enableExport?: boolean;
|
|
13
13
|
}
|
|
14
|
-
export declare function DataTableToolbar<TData>({ table, globalFilter, globalFilterValue, onGlobalFilterChange, density, onDensityChange, enableExport, className, ...props }: DataTableToolbarProps<TData>):
|
|
14
|
+
export declare function DataTableToolbar<TData>({ table, globalFilter, globalFilterValue, onGlobalFilterChange, density, onDensityChange, enableExport, className, ...props }: DataTableToolbarProps<TData>): React.JSX.Element;
|
|
15
15
|
export declare namespace DataTableToolbar {
|
|
16
16
|
var displayName: string;
|
|
17
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table-toolbar.d.ts","sourceRoot":"","sources":["../../src/ui/data-table-toolbar.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAc9B,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,aAAa,CAAA;AAc5D,MAAM,WAAW,qBAAqB,CAAC,KAAK,CAAE,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IAC1G,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IACnB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,iBAAiB,EAAE,MAAM,CAAA;IACzB,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7C,OAAO,EAAE,OAAO,CAAA;IAChB,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAC3C,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAyCD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,EACtC,KAAK,EACL,YAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,OAAO,EACP,eAAe,EACf,YAAmB,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,qBAAqB,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"data-table-toolbar.d.ts","sourceRoot":"","sources":["../../src/ui/data-table-toolbar.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAc9B,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,aAAa,CAAA;AAc5D,MAAM,WAAW,qBAAqB,CAAC,KAAK,CAAE,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IAC1G,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IACnB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,iBAAiB,EAAE,MAAM,CAAA;IACzB,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7C,OAAO,EAAE,OAAO,CAAA;IAChB,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IAC3C,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAyCD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,EACtC,KAAK,EACL,YAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,OAAO,EACP,eAAe,EACf,YAAmB,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,qBAAqB,CAAC,KAAK,CAAC,qBA8F9B;yBAxGe,gBAAgB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table-toolbar.js","names":[],"sources":["../../src/ui/data-table-toolbar.tsx"],"sourcesContent":["'use client'\n\nimport {\n IconColumns3,\n IconDownload,\n IconSearch,\n IconTextResize,\n} from '@tabler/icons-react'\nimport { type Table } from '@tanstack/react-table'\nimport * as React from 'react'\n\nimport { Button } from './button'\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from './dropdown-menu'\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\n\nexport type Density = 'compact' | 'standard' | 'comfortable'\n\nconst densityLabels: Record<Density, string> = {\n compact: 'Compact',\n standard: 'Standard',\n comfortable: 'Comfortable',\n}\n\nconst densityCycle: Record<Density, Density> = {\n compact: 'standard',\n standard: 'comfortable',\n comfortable: 'compact',\n}\n\nexport interface DataTableToolbarProps<TData> extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n table: Table<TData>\n globalFilter?: boolean\n globalFilterValue: string\n onGlobalFilterChange: (value: string) => void\n density: Density\n onDensityChange: (density: Density) => void\n enableExport?: boolean\n}\n\nconst toolbarIconClass = 'text-surface-fg-subtle'\n\nfunction exportToCsv<TData>(table: Table<TData>) {\n const headers = table\n .getAllLeafColumns()\n .filter((col) => col.getIsVisible() && col.id !== '_select')\n .map((col) => {\n const header = col.columnDef.header\n return typeof header === 'string' ? header : col.id\n })\n\n const rows = table.getFilteredRowModel().rows.map((row) =>\n table\n .getAllLeafColumns()\n .filter((col) => col.getIsVisible() && col.id !== '_select')\n .map((col) => {\n const value = row.getValue(col.id)\n const str = String(value ?? '')\n // Escape CSV: wrap in quotes if it contains comma, quote, or newline\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`\n }\n return str\n }),\n )\n\n const csvContent = [headers.join(','), ...rows.map((r) => r.join(','))].join(\n '\\n',\n )\n\n const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = 'table-export.csv'\n link.click()\n URL.revokeObjectURL(url)\n}\n\nexport function DataTableToolbar<TData>({\n table,\n globalFilter = false,\n globalFilterValue,\n onGlobalFilterChange,\n density,\n onDensityChange,\n enableExport = true,\n className,\n ...props\n}: DataTableToolbarProps<TData>) {\n const toggleableColumns = table\n .getAllColumns()\n .filter((col) => col.getCanHide() && col.id !== '_select')\n\n return (\n <div className={cn('flex items-center gap-ds-03 pb-ds-04', className)} {...props}>\n {/* Global search */}\n {globalFilter && (\n <div className=\"flex flex-1 items-center gap-ds-02\">\n <Icon icon={IconSearch} size=\"sm\" className={toolbarIconClass} />\n <input\n type=\"text\"\n value={globalFilterValue}\n onChange={(e) => onGlobalFilterChange(e.target.value)}\n placeholder=\"Search all columns...\"\n aria-label=\"Search all columns\"\n className={cn(\n 'flex-1 bg-transparent text-ds-md',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden',\n 'h-ds-sm',\n )}\n />\n </div>\n )}\n\n <div className=\"ml-auto flex items-center gap-ds-03\">\n {/* Column visibility dropdown */}\n {toggleableColumns.length > 0 && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"outline\"\n color=\"neutral\"\n size=\"sm\"\n aria-label=\"Toggle column visibility\"\n >\n <Icon icon={IconColumns3} size=\"sm\" className={toolbarIconClass} />\n Columns\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-40\">\n <DropdownMenuLabel>Toggle columns</DropdownMenuLabel>\n <DropdownMenuSeparator />\n {toggleableColumns.map((column) => {\n const headerDef = column.columnDef.header\n const label =\n typeof headerDef === 'string' ? headerDef : column.id\n return (\n <DropdownMenuCheckboxItem\n key={column.id}\n checked={column.getIsVisible()}\n onCheckedChange={(value) =>\n column.toggleVisibility(!!value)\n }\n >\n {label}\n </DropdownMenuCheckboxItem>\n )\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n\n {/* Density toggle */}\n <Button\n variant=\"outline\"\n color=\"neutral\"\n size=\"sm\"\n onClick={() => onDensityChange(densityCycle[density])}\n aria-label={`Table density: ${densityLabels[density]}. Click to change.`}\n title={`Density: ${densityLabels[density]}`}\n >\n <Icon icon={IconTextResize} size=\"sm\" className={toolbarIconClass} />\n {densityLabels[density]}\n </Button>\n\n {/* CSV Export */}\n {enableExport && (\n <Button\n variant=\"outline\"\n color=\"neutral\"\n size=\"sm\"\n onClick={() => exportToCsv(table)}\n aria-label=\"Export table as CSV\"\n >\n <Icon icon={IconDownload} size=\"sm\" className={toolbarIconClass} />\n Export\n </Button>\n )}\n </div>\n </div>\n )\n}\nDataTableToolbar.displayName = 'DataTableToolbar'\n"],"mappings":";;;;;;;;;AAyBA,IAAM,IAAyC;CAC7C,SAAS;CACT,UAAU;CACV,aAAa;
|
|
1
|
+
{"version":3,"file":"data-table-toolbar.js","names":[],"sources":["../../src/ui/data-table-toolbar.tsx"],"sourcesContent":["'use client'\n\nimport {\n IconColumns3,\n IconDownload,\n IconSearch,\n IconTextResize,\n} from '@tabler/icons-react'\nimport { type Table } from '@tanstack/react-table'\nimport * as React from 'react'\n\nimport { Button } from './button'\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from './dropdown-menu'\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\n\nexport type Density = 'compact' | 'standard' | 'comfortable'\n\nconst densityLabels: Record<Density, string> = {\n compact: 'Compact',\n standard: 'Standard',\n comfortable: 'Comfortable',\n}\n\nconst densityCycle: Record<Density, Density> = {\n compact: 'standard',\n standard: 'comfortable',\n comfortable: 'compact',\n}\n\nexport interface DataTableToolbarProps<TData> extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n table: Table<TData>\n globalFilter?: boolean\n globalFilterValue: string\n onGlobalFilterChange: (value: string) => void\n density: Density\n onDensityChange: (density: Density) => void\n enableExport?: boolean\n}\n\nconst toolbarIconClass = 'text-surface-fg-subtle'\n\nfunction exportToCsv<TData>(table: Table<TData>) {\n const headers = table\n .getAllLeafColumns()\n .filter((col) => col.getIsVisible() && col.id !== '_select')\n .map((col) => {\n const header = col.columnDef.header\n return typeof header === 'string' ? header : col.id\n })\n\n const rows = table.getFilteredRowModel().rows.map((row) =>\n table\n .getAllLeafColumns()\n .filter((col) => col.getIsVisible() && col.id !== '_select')\n .map((col) => {\n const value = row.getValue(col.id)\n const str = String(value ?? '')\n // Escape CSV: wrap in quotes if it contains comma, quote, or newline\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`\n }\n return str\n }),\n )\n\n const csvContent = [headers.join(','), ...rows.map((r) => r.join(','))].join(\n '\\n',\n )\n\n const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = 'table-export.csv'\n link.click()\n URL.revokeObjectURL(url)\n}\n\nexport function DataTableToolbar<TData>({\n table,\n globalFilter = false,\n globalFilterValue,\n onGlobalFilterChange,\n density,\n onDensityChange,\n enableExport = true,\n className,\n ...props\n}: DataTableToolbarProps<TData>) {\n const toggleableColumns = table\n .getAllColumns()\n .filter((col) => col.getCanHide() && col.id !== '_select')\n\n return (\n <div className={cn('flex items-center gap-ds-03 pb-ds-04', className)} {...props}>\n {/* Global search */}\n {globalFilter && (\n <div className=\"flex flex-1 items-center gap-ds-02\">\n <Icon icon={IconSearch} size=\"sm\" className={toolbarIconClass} />\n <input\n type=\"text\"\n value={globalFilterValue}\n onChange={(e) => onGlobalFilterChange(e.target.value)}\n placeholder=\"Search all columns...\"\n aria-label=\"Search all columns\"\n className={cn(\n 'flex-1 bg-transparent text-ds-md',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden',\n 'h-ds-sm',\n )}\n />\n </div>\n )}\n\n <div className=\"ml-auto flex items-center gap-ds-03\">\n {/* Column visibility dropdown */}\n {toggleableColumns.length > 0 && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"outline\"\n color=\"neutral\"\n size=\"sm\"\n aria-label=\"Toggle column visibility\"\n >\n <Icon icon={IconColumns3} size=\"sm\" className={toolbarIconClass} />\n Columns\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-40\">\n <DropdownMenuLabel>Toggle columns</DropdownMenuLabel>\n <DropdownMenuSeparator />\n {toggleableColumns.map((column) => {\n const headerDef = column.columnDef.header\n const label =\n typeof headerDef === 'string' ? headerDef : column.id\n return (\n <DropdownMenuCheckboxItem\n key={column.id}\n checked={column.getIsVisible()}\n onCheckedChange={(value) =>\n column.toggleVisibility(!!value)\n }\n >\n {label}\n </DropdownMenuCheckboxItem>\n )\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n\n {/* Density toggle */}\n <Button\n variant=\"outline\"\n color=\"neutral\"\n size=\"sm\"\n onClick={() => onDensityChange(densityCycle[density])}\n aria-label={`Table density: ${densityLabels[density]}. Click to change.`}\n title={`Density: ${densityLabels[density]}`}\n >\n <Icon icon={IconTextResize} size=\"sm\" className={toolbarIconClass} />\n {densityLabels[density]}\n </Button>\n\n {/* CSV Export */}\n {enableExport && (\n <Button\n variant=\"outline\"\n color=\"neutral\"\n size=\"sm\"\n onClick={() => exportToCsv(table)}\n aria-label=\"Export table as CSV\"\n >\n <Icon icon={IconDownload} size=\"sm\" className={toolbarIconClass} />\n Export\n </Button>\n )}\n </div>\n </div>\n )\n}\nDataTableToolbar.displayName = 'DataTableToolbar'\n"],"mappings":"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"}
|
package/dist/ui/data-table.d.ts
CHANGED
|
@@ -147,7 +147,7 @@ export interface DataTableProps<TData, TValue> {
|
|
|
147
147
|
/** Render rows as stacked cards on small screens (below sm breakpoint). Default 'table'. */
|
|
148
148
|
mobileView?: 'card' | 'table';
|
|
149
149
|
}
|
|
150
|
-
export declare function DataTable<TData, TValue>({ columns, data, className, noResultsText, sortable, filterable, globalFilter, paginated, pageSize: initialPageSize, pageSizeOptions, selectable, onSelectionChange, toolbar, density: initialDensity, columnPinning: initialColumnPinning, editable, onCellEdit, expandable, renderExpanded, virtualRows, virtualRowHeight, maxHeight, onSort, emptyState, loading, selectedIds, selectableFilter, getRowId: getRowIdProp, pagination: serverPagination, singleExpand, stickyHeader, onRowClick, bulkActions, mobileView, }: DataTableProps<TData, TValue>):
|
|
150
|
+
export declare function DataTable<TData, TValue>({ columns, data, className, noResultsText, sortable, filterable, globalFilter, paginated, pageSize: initialPageSize, pageSizeOptions, selectable, onSelectionChange, toolbar, density: initialDensity, columnPinning: initialColumnPinning, editable, onCellEdit, expandable, renderExpanded, virtualRows, virtualRowHeight, maxHeight, onSort, emptyState, loading, selectedIds, selectableFilter, getRowId: getRowIdProp, pagination: serverPagination, singleExpand, stickyHeader, onRowClick, bulkActions, mobileView, }: DataTableProps<TData, TValue>): React.JSX.Element;
|
|
151
151
|
export declare namespace DataTable {
|
|
152
152
|
var displayName: string;
|
|
153
153
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../src/ui/data-table.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"data-table.d.ts","sourceRoot":"","sources":["../../src/ui/data-table.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,SAAS,EAWd,KAAK,OAAO,EAOb,MAAM,uBAAuB,CAAA;AAE9B,OAAO,KAA4D,MAAM,OAAO,CAAA;AAIhF,OAAO,EAAE,KAAK,UAAU,EAAuB,MAAM,2BAA2B,CAAA;AAQhF,OAAO,EAAoB,KAAK,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAMrE,YAAY,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAE3D,OAAO,QAAQ,uBAAuB,CAAC;IAErC,UAAU,UAAU,CAAC,KAAK,SAAS,OAAO,EAAE,MAAM;QAChD,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;QACnC,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;KAC/B;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH;;;;GAIG;AACH,MAAM,WAAW,cAAc,CAAC,KAAK,EAAE,MAAM;IAC3C,mDAAmD;IACnD,OAAO,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAA;IACnC,eAAe;IACf,IAAI,EAAE,KAAK,EAAE,CAAA;IACb,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4CAA4C;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,oDAAoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,mDAAmD;IACnD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8EAA8E;IAC9E,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,2CAA2C;IAC3C,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,0CAA0C;IAC1C,iBAAiB,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,IAAI,CAAA;IACnD,wFAAwF;IACxF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,mDAAmD;IACnD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,2CAA2C;IAC3C,aAAa,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;IAGrD,wDAAwD;IACxD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAGzE,gDAAgD;IAChD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,KAAK,CAAC,SAAS,CAAA;IAGhD,mDAAmD;IACnD,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;IAGlB,gGAAgG;IAChG,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,KAAK,IAAI,CAAA;IAGjE,6EAA6E;IAC7E,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAG5B,iDAAiD;IACjD,OAAO,CAAC,EAAE,OAAO,CAAA;IAGjB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACzB,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,OAAO,CAAA;IAC1C,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,MAAM,CAAA;IAGjC,0EAA0E;IAC1E,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,EAAE,MAAM,CAAA;QAChB,KAAK,EAAE,MAAM,CAAA;QACb,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;KACrC,CAAA;IAGD,wDAAwD;IACxD,YAAY,CAAC,EAAE,OAAO,CAAA;IAGtB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,OAAO,CAAA;IAGtB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAA;IAGjC,6DAA6D;IAC7D,WAAW,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAA;IAGjC,4FAA4F;IAC5F,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAC9B;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EACvC,OAAO,EACP,IAAI,EACJ,SAAS,EACT,aAAa,EACb,QAAgB,EAChB,UAAkB,EAClB,YAAoB,EACpB,SAAiB,EACjB,QAAQ,EAAE,eAAe,EACzB,eAAe,EACf,UAAkB,EAClB,iBAAiB,EACjB,OAAe,EACf,OAAO,EAAE,cAA2B,EACpC,aAAa,EAAE,oBAAoB,EACnC,QAAgB,EAChB,UAAU,EACV,UAAkB,EAClB,cAAc,EACd,WAAmB,EACnB,gBAAqB,EACrB,SAAe,EACf,MAAM,EACN,UAAU,EACV,OAAe,EACf,WAAW,EACX,gBAAgB,EAChB,QAAQ,EAAE,YAAY,EACtB,UAAU,EAAE,gBAAgB,EAC5B,YAAoB,EACpB,YAAoB,EACpB,UAAU,EACV,WAAW,EACX,UAAoB,GACrB,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,qBA0b/B;yBA7de,SAAS"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-table.js","names":[],"sources":["../../src/ui/data-table.tsx"],"sourcesContent":["'use client'\n\nimport { IconChevronRight, IconSearch } from '@tabler/icons-react'\nimport {\n type ColumnDef,\n type ColumnFiltersState,\n type ColumnPinningState,\n type ExpandedState,\n getCoreRowModel,\n getExpandedRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type PaginationState,\n type Row,\n type RowData,\n type RowSelectionState,\n type SortingState,\n type TableState,\n type Updater,\n useReactTable,\n type VisibilityState,\n} from '@tanstack/react-table'\nimport { useVirtualizer } from '@tanstack/react-virtual'\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport { Checkbox } from './checkbox'\nimport { DataTableBody } from './data-table-body'\nimport { type BulkAction,DataTableBulkActions } from './data-table-bulk-actions'\nimport { DataTableCards } from './data-table-card'\nimport {\n DataTableProvider,\n type EditingCell,\n} from './data-table-context'\nimport { DataTableHeader } from './data-table-header'\nimport { DataTablePagination } from './data-table-pagination'\nimport { DataTableToolbar, type Density } from './data-table-toolbar'\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\nimport { Table } from './table'\n\n// Re-export public types so consumers' imports don't break\nexport type { BulkAction } from './data-table-bulk-actions'\n\ndeclare module '@tanstack/react-table' {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n interface ColumnMeta<TData extends RowData, TValue> {\n align?: 'left' | 'center' | 'right'\n hideBelow?: 'sm' | 'md' | 'lg'\n }\n}\n\n/**\n * Props for DataTable — a feature-rich TanStack Table wrapper supporting sorting, filtering,\n * pagination, row selection, inline editing, row expansion, column pinning, and virtualization.\n *\n * All features are opt-in via boolean flags. The component manages its own internal state for\n * sorting, filtering, pagination, and selection — just pass `columns` and `data`.\n *\n * **Feature flags:** `sortable` | `filterable` | `globalFilter` | `paginated` | `selectable` |\n * `toolbar` | `editable` | `expandable` | `virtualRows`\n *\n * **Columns:** Use TanStack Table's `ColumnDef<TData, TValue>` type. Set\n * `meta: { enableEditing: false }` on a column to disable cell editing for that column.\n *\n * @example\n * // Minimal read-only table:\n * const columns: ColumnDef<User, string>[] = [\n * { accessorKey: 'name', header: 'Name' },\n * { accessorKey: 'email', header: 'Email' },\n * ]\n * <DataTable columns={columns} data={users} />\n *\n * @example\n * // Full-featured admin table with sorting, pagination, and selection:\n * <DataTable\n * columns={projectColumns}\n * data={projects}\n * sortable\n * paginated\n * pageSize={20}\n * selectable\n * onSelectionChange={(rows) => setSelectedProjects(rows)}\n * toolbar\n * />\n *\n * @example\n * // Virtualized table for large datasets (10k+ rows):\n * <DataTable\n * columns={logColumns}\n * data={allLogs}\n * virtualRows\n * virtualRowHeight={40}\n * maxHeight={500}\n * />\n *\n * @example\n * // Table with expandable rows for nested detail:\n * <DataTable\n * columns={orderColumns}\n * data={orders}\n * expandable\n * renderExpanded={(order) => <OrderLineItems items={order.lineItems} />}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\n/**\n * A full-featured data table built on TanStack Table with sorting, filtering,\n * pagination, row selection, inline cell editing, expandable rows, column pinning,\n * a toolbar with density/export controls, and optional row virtualization.\n */\nexport interface DataTableProps<TData, TValue> {\n /** Column definitions passed to TanStack Table. */\n columns: ColumnDef<TData, TValue>[]\n /** Row data */\n data: TData[]\n /** Additional class name for the wrapper div */\n className?: string\n /** Text shown when the table has no rows */\n noResultsText?: string\n /** Enable column sorting (click headers to sort) */\n sortable?: boolean\n /** Enable per-column filter inputs below headers */\n filterable?: boolean\n /** Enable a global search input above the table */\n globalFilter?: boolean\n /** Enable pagination controls below the table */\n paginated?: boolean\n /** Number of rows per page when paginated (default 10) */\n pageSize?: number\n /** Options for the page size selector dropdown (default [10, 20, 50, 100]) */\n pageSizeOptions?: number[]\n /** Enable row selection with checkboxes */\n selectable?: boolean\n /** Callback when row selection changes */\n onSelectionChange?: (selectedRows: TData[]) => void\n /** Show toolbar above the table with column visibility, density, and export controls */\n toolbar?: boolean\n /** Row density — controls cell vertical padding */\n density?: Density\n /** Initial column pinning configuration */\n columnPinning?: { left?: string[]; right?: string[] }\n\n // --- Cell Editing ---\n /** Enable inline cell editing (double-click to edit) */\n editable?: boolean\n /** Callback when a cell value is edited */\n onCellEdit?: (rowIndex: number, columnId: string, value: unknown) => void\n\n // --- Row Expansion ---\n /** Enable expandable rows with detail panels */\n expandable?: boolean\n /** Render function for expanded row content */\n renderExpanded?: (row: TData) => React.ReactNode\n\n // --- Virtualization ---\n /** Enable row virtualization for large datasets */\n virtualRows?: boolean\n /** Height of each virtual row in pixels (default 48) */\n virtualRowHeight?: number\n /** Maximum height of the scrollable container in pixels (default 600) */\n maxHeight?: number\n\n // --- Server-side sorting ---\n /** Callback for server-side sorting. When provided, sorting is manual (no client-side sort). */\n onSort?: (key: string, direction: 'asc' | 'desc' | false) => void\n\n // --- Empty state ---\n /** Custom ReactNode to render when data is empty (replaces noResultsText) */\n emptyState?: React.ReactNode\n\n // --- Loading ---\n /** Show shimmer skeleton rows instead of data */\n loading?: boolean\n\n // --- Controlled selection ---\n /** Controlled set of selected row IDs — syncs internal selection state */\n selectedIds?: Set<string>\n /** Per-row filter to determine if a row is selectable */\n selectableFilter?: (row: TData) => boolean\n /** Custom row ID getter */\n getRowId?: (row: TData) => string\n\n // --- Server-side pagination ---\n /** Server-side pagination config. When provided, pagination is manual. */\n pagination?: {\n page: number\n pageSize: number\n total: number\n onPageChange: (page: number) => void\n }\n\n // --- Single-expand mode ---\n /** When true, only one row can be expanded at a time */\n singleExpand?: boolean\n\n // --- Sticky header ---\n /** When true, the table header sticks to the top on scroll */\n stickyHeader?: boolean\n\n // --- Row click ---\n /** Callback when a row is clicked (not fired from interactive elements) */\n onRowClick?: (row: TData) => void\n\n // --- Bulk actions ---\n /** Actions shown in a floating bar when rows are selected */\n bulkActions?: BulkAction<TData>[]\n\n // --- Mobile view ---\n /** Render rows as stacked cards on small screens (below sm breakpoint). Default 'table'. */\n mobileView?: 'card' | 'table'\n}\n\nexport function DataTable<TData, TValue>({\n columns,\n data,\n className,\n noResultsText,\n sortable = false,\n filterable = false,\n globalFilter = false,\n paginated = false,\n pageSize: initialPageSize,\n pageSizeOptions,\n selectable = false,\n onSelectionChange,\n toolbar = false,\n density: initialDensity = 'standard',\n columnPinning: initialColumnPinning,\n editable = false,\n onCellEdit,\n expandable = false,\n renderExpanded,\n virtualRows = false,\n virtualRowHeight = 48,\n maxHeight = 600,\n onSort,\n emptyState,\n loading = false,\n selectedIds,\n selectableFilter,\n getRowId: getRowIdProp,\n pagination: serverPagination,\n singleExpand = false,\n stickyHeader = false,\n onRowClick,\n bulkActions,\n mobileView = 'table',\n}: DataTableProps<TData, TValue>) {\n // Detect below-sm viewport (640px) for card mode — separate from useIsMobile (768px)\n const [isBelowSm, setIsBelowSm] = useState(false)\n useEffect(() => {\n const mql = window.matchMedia('(max-width: 639px)')\n const onChange = () => setIsBelowSm(mql.matches)\n mql.addEventListener('change', onChange)\n setIsBelowSm(mql.matches)\n return () => mql.removeEventListener('change', onChange)\n }, [])\n\n const showCards = mobileView === 'card' && isBelowSm\n\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [globalFilterValue, setGlobalFilterValue] = useState('')\n const [paginationState, setPaginationState] = useState<PaginationState>({\n pageIndex: serverPagination ? serverPagination.page - 1 : 0,\n pageSize: serverPagination?.pageSize ?? initialPageSize ?? 10,\n })\n const [rowSelection, setRowSelection] = useState<RowSelectionState>({})\n const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})\n const [columnPinningState, setColumnPinningState] =\n useState<ColumnPinningState>({\n left: initialColumnPinning?.left ?? [],\n right: initialColumnPinning?.right ?? [],\n })\n const [density, setDensity] = useState<Density>(initialDensity)\n const [editingCell, setEditingCell] = useState<EditingCell>(null)\n const [expanded, setExpanded] = useState<ExpandedState>({})\n\n // Ref for the virtual scroll container\n const scrollContainerRef = useRef<HTMLDivElement>(null)\n\n // Guard to prevent onSelectionChange firing when syncing from selectedIds prop\n const isSyncingFromPropRef = useRef(false)\n\n // Sync controlled selectedIds to internal rowSelection\n useEffect(() => {\n if (selectedIds) {\n isSyncingFromPropRef.current = true\n const newSelection: RowSelectionState = {}\n selectedIds.forEach((id) => {\n newSelection[id] = true\n })\n setRowSelection(newSelection)\n }\n }, [selectedIds])\n\n // Sync server pagination page to internal state\n useEffect(() => {\n if (serverPagination) {\n setPaginationState((prev) => ({\n ...prev,\n pageIndex: serverPagination.page - 1,\n pageSize: serverPagination.pageSize,\n }))\n }\n }, [serverPagination?.page, serverPagination?.pageSize]) // eslint-disable-line react-hooks/exhaustive-deps\n\n // Server-side sorting handler\n const handleSortingChange = useCallback(\n (updater: Updater<SortingState>) => {\n setSorting((prev) => {\n const next = typeof updater === 'function' ? updater(prev) : updater\n if (onSort) {\n if (next.length === 0 && prev.length > 0) {\n // Sorting cleared\n onSort(prev[0].id, false)\n } else if (next.length > 0) {\n onSort(next[0].id, next[0].desc ? 'desc' : 'asc')\n }\n }\n return next\n })\n },\n [onSort],\n )\n\n // Single-expand handler\n const handleExpandedChange = useCallback(\n (updater: Updater<ExpandedState>) => {\n setExpanded((prev) => {\n const next = typeof updater === 'function' ? updater(prev) : updater\n if (!singleExpand) return next\n // If next is boolean true (expand all), just use it\n if (next === true) return next\n if (typeof next !== 'object') return next\n // Determine which row was just toggled on\n const prevKeys = typeof prev === 'object' ? Object.keys(prev).filter((k) => (prev as Record<string, boolean>)[k]) : []\n const nextKeys = Object.keys(next).filter((k) => (next as Record<string, boolean>)[k])\n // Find newly expanded row\n const newlyExpanded = nextKeys.filter((k) => !prevKeys.includes(k))\n if (newlyExpanded.length > 0) {\n // Keep only the most recently expanded row\n return { [newlyExpanded[newlyExpanded.length - 1]]: true } as ExpandedState\n }\n // If no new rows, means a row was collapsed — return as-is\n return next\n })\n },\n [singleExpand],\n )\n\n // Stable ref for server pagination callback to avoid useCallback invalidation\n const onPageChangeRef = useRef(serverPagination?.onPageChange)\n useEffect(() => {\n onPageChangeRef.current = serverPagination?.onPageChange\n }, [serverPagination?.onPageChange])\n\n // Server-side pagination handler\n const handlePaginationChange = useCallback(\n (updater: Updater<PaginationState>) => {\n setPaginationState((prev) => {\n const next = typeof updater === 'function' ? updater(prev) : updater\n if (onPageChangeRef.current) {\n // Only call onPageChange if the page actually changed\n if (next.pageIndex !== prev.pageIndex) {\n onPageChangeRef.current(next.pageIndex + 1)\n }\n }\n return next\n })\n },\n [],\n )\n\n // Checkbox column prepended when selectable is enabled\n const selectColumn: ColumnDef<TData, unknown> = {\n id: '_select',\n header: ({ table: t }) => (\n <Checkbox\n size=\"sm\"\n checked={t.getIsAllPageRowsSelected()}\n indeterminate={t.getIsSomePageRowsSelected()}\n onCheckedChange={(v) => t.toggleAllPageRowsSelected(!!v)}\n aria-label=\"Select all rows\"\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n size=\"sm\"\n checked={row.getIsSelected()}\n disabled={!row.getCanSelect()}\n onCheckedChange={(v) => row.toggleSelected(!!v)}\n aria-label=\"Select row\"\n />\n ),\n enableSorting: false,\n enableColumnFilter: false,\n enableHiding: false,\n }\n\n // Expand toggle column — aria-expanded lives on the BUTTON (not the row),\n // in a dedicated column with a visually-hidden header (Roselli expando spec).\n const expandColumn: ColumnDef<TData, unknown> = {\n id: '_expand',\n header: () => <span className=\"sr-only\">Expand rows</span>,\n cell: ({ row }) => (\n <button\n type=\"button\"\n onClick={() => row.toggleExpanded()}\n aria-expanded={row.getIsExpanded()}\n aria-label={row.getIsExpanded() ? 'Collapse row' : 'Expand row'}\n className=\"flex items-center justify-center p-ds-01 rounded-control-inner hover:bg-surface-raised-hover transition-colors\"\n >\n <Icon\n icon={IconChevronRight}\n size=\"sm\"\n className={cn(\n 'transition-transform duration-fast-02 ease-productive-standard',\n row.getIsExpanded() && 'rotate-90',\n )}\n />\n </button>\n ),\n enableSorting: false,\n enableColumnFilter: false,\n enableHiding: false,\n }\n\n // Assemble all columns in order: select?, expand?, ...user columns\n const allColumns = [\n ...(selectable ? [selectColumn] : []),\n ...(expandable ? [expandColumn] : []),\n ...columns,\n ]\n\n // Determine if using server-side pagination\n const useServerPagination = !!serverPagination\n const showPagination = paginated || useServerPagination\n\n // Build state object once — sorting and filtering contribute independently\n const tableState: Partial<TableState> = {\n columnVisibility,\n columnPinning: columnPinningState,\n }\n if (sortable) tableState.sorting = sorting\n if (filterable || globalFilter) {\n tableState.columnFilters = columnFilters\n tableState.globalFilter = globalFilterValue\n }\n if (showPagination) tableState.pagination = paginationState\n if (selectable) tableState.rowSelection = rowSelection\n if (expandable) tableState.expanded = expanded\n\n // Determine server-side sort mode\n const isServerSort = sortable && !!onSort\n\n const table = useReactTable({\n data,\n columns: allColumns,\n state: tableState,\n onColumnVisibilityChange: setColumnVisibility,\n onColumnPinningChange: setColumnPinningState,\n getCoreRowModel: getCoreRowModel(),\n ...(sortable && {\n onSortingChange: isServerSort ? handleSortingChange : setSorting,\n ...(isServerSort\n ? { manualSorting: true }\n : { getSortedRowModel: getSortedRowModel() }),\n }),\n ...((filterable || globalFilter) && {\n onColumnFiltersChange: setColumnFilters,\n onGlobalFilterChange: setGlobalFilterValue,\n getFilteredRowModel: getFilteredRowModel(),\n }),\n ...(showPagination && {\n onPaginationChange: useServerPagination\n ? handlePaginationChange\n : setPaginationState,\n ...(useServerPagination\n ? {\n manualPagination: true,\n pageCount: Math.ceil(\n serverPagination!.total / serverPagination!.pageSize,\n ),\n }\n : { getPaginationRowModel: getPaginationRowModel() }),\n }),\n ...(selectable && {\n onRowSelectionChange: setRowSelection,\n enableRowSelection: selectableFilter\n ? (row: Row<TData>) => selectableFilter(row.original)\n : true,\n }),\n ...(expandable && {\n onExpandedChange: singleExpand ? handleExpandedChange : setExpanded,\n getExpandedRowModel: getExpandedRowModel(),\n }),\n ...(getRowIdProp && {\n getRowId: (row: TData) => getRowIdProp(row),\n }),\n })\n\n // Stable refs to avoid effect re-fires from inline callbacks\n const onSelectionChangeRef = useRef(onSelectionChange)\n const getRowIdRef = useRef(getRowIdProp)\n useEffect(() => {\n onSelectionChangeRef.current = onSelectionChange\n getRowIdRef.current = getRowIdProp\n }, [onSelectionChange, getRowIdProp])\n\n // Fire selection callback when row selection changes (skip when syncing from prop)\n useEffect(() => {\n if (isSyncingFromPropRef.current) {\n isSyncingFromPropRef.current = false\n return\n }\n if (!onSelectionChangeRef.current) return\n const selectedRowIds = Object.keys(rowSelection).filter((k) => rowSelection[k])\n const selected = data.filter((_, i) => {\n const id = getRowIdRef.current ? getRowIdRef.current(data[i]) : String(i)\n return selectedRowIds.includes(id)\n })\n onSelectionChangeRef.current(selected)\n }, [rowSelection, data])\n\n const rows = table.getRowModel().rows\n\n // Virtualizer — always called but only active when virtualRows is true\n const virtualizer = useVirtualizer({\n count: virtualRows ? rows.length : 0,\n getScrollElement: () => scrollContainerRef.current,\n estimateSize: () => virtualRowHeight,\n overscan: 10,\n })\n\n // Number of skeleton rows for loading state\n const skeletonRowCount = serverPagination?.pageSize ?? initialPageSize ?? 5\n\n // Get selected rows for bulk actions (derived from rowSelection + data, not table instance)\n const selectedRows = useMemo(() => {\n if (!bulkActions || !selectable) return []\n const selectedRowIds = Object.keys(rowSelection).filter((k) => rowSelection[k])\n return data.filter((_, i) => {\n const id = getRowIdProp ? getRowIdProp(data[i]) : String(i)\n return selectedRowIds.includes(id)\n })\n }, [bulkActions, selectable, rowSelection, data, getRowIdProp])\n\n const hasSelectedRows = selectedRows.length > 0\n\n // Total rows for pagination display\n const totalRowCount = useServerPagination\n ? serverPagination!.total\n : table.getFilteredRowModel().rows.length\n\n // Build context value for sub-components\n const contextValue = useMemo(\n () => ({\n table,\n allColumns: allColumns.map((col) => ({\n id: (col as { id?: string }).id,\n header: (col as { header?: unknown }).header,\n })),\n columnPinningState,\n sortable,\n filterable,\n editable,\n expandable,\n virtualRows,\n selectable,\n mobileView,\n editingCell,\n setEditingCell,\n onCellEdit,\n renderExpanded,\n onRowClick,\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n table,\n allColumns.length,\n columnPinningState,\n sortable,\n filterable,\n editable,\n expandable,\n virtualRows,\n selectable,\n mobileView,\n editingCell,\n onCellEdit,\n renderExpanded,\n onRowClick,\n ],\n )\n\n // Virtual items for body\n const virtualItems = virtualRows ? virtualizer.getVirtualItems() : undefined\n const totalVirtualSize = virtualRows ? virtualizer.getTotalSize() : undefined\n\n // Determine if we need a scroll wrapper for virtualization\n const tableContent = (\n <Table density={density} aria-busy={loading || undefined}>\n <DataTableHeader stickyHeader={stickyHeader} />\n <DataTableBody\n loading={loading}\n skeletonRowCount={skeletonRowCount}\n noResultsText={noResultsText}\n emptyState={emptyState}\n virtualItems={virtualItems}\n totalVirtualSize={totalVirtualSize}\n />\n </Table>\n )\n\n return (\n <DataTableProvider value={contextValue}>\n <div className={cn(className)}>\n {/* Toolbar */}\n {toolbar && (\n <DataTableToolbar\n table={table}\n globalFilter={globalFilter}\n globalFilterValue={globalFilterValue}\n onGlobalFilterChange={setGlobalFilterValue}\n density={density}\n onDensityChange={setDensity}\n />\n )}\n\n {/* Global search input — only show standalone when toolbar is disabled */}\n {globalFilter && !toolbar && (\n <div className=\"flex items-center gap-ds-03 pb-ds-04 border-b border-surface-border mb-ds-04\">\n <Icon icon={IconSearch} size=\"sm\" className=\"text-surface-fg-subtle\" />\n <input\n type=\"text\"\n value={globalFilterValue}\n onChange={(e) => setGlobalFilterValue(e.target.value)}\n placeholder=\"Search all columns...\"\n aria-label=\"Search all columns\"\n className={cn(\n 'flex-1 bg-transparent text-ds-md',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden',\n )}\n />\n </div>\n )}\n\n {/* Card view on small screens, or standard table */}\n {showCards ? (\n <DataTableCards\n loading={loading}\n skeletonRowCount={skeletonRowCount}\n noResultsText={noResultsText}\n emptyState={emptyState}\n />\n ) : virtualRows ? (\n <div\n ref={scrollContainerRef}\n style={{ maxHeight: `${maxHeight}px`, overflowY: 'auto' }}\n >\n {tableContent}\n </div>\n ) : (\n tableContent\n )}\n\n {/* Pagination controls */}\n {showPagination && (\n <DataTablePagination\n table={table}\n totalRowCount={totalRowCount}\n useServerPagination={useServerPagination}\n pageSizeOptions={pageSizeOptions}\n />\n )}\n\n {/* Bulk action bar */}\n {bulkActions && selectable && hasSelectedRows && (\n <DataTableBulkActions\n table={table}\n selectedRows={selectedRows}\n bulkActions={bulkActions}\n />\n )}\n </div>\n </DataTableProvider>\n )\n}\nDataTable.displayName = 'DataTable'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data-table.js","names":[],"sources":["../../src/ui/data-table.tsx"],"sourcesContent":["'use client'\n\nimport { IconChevronRight, IconSearch } from '@tabler/icons-react'\nimport {\n type ColumnDef,\n type ColumnFiltersState,\n type ColumnPinningState,\n type ExpandedState,\n getCoreRowModel,\n getExpandedRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type PaginationState,\n type Row,\n type RowData,\n type RowSelectionState,\n type SortingState,\n type TableState,\n type Updater,\n useReactTable,\n type VisibilityState,\n} from '@tanstack/react-table'\nimport { useVirtualizer } from '@tanstack/react-virtual'\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport { Checkbox } from './checkbox'\nimport { DataTableBody } from './data-table-body'\nimport { type BulkAction,DataTableBulkActions } from './data-table-bulk-actions'\nimport { DataTableCards } from './data-table-card'\nimport {\n DataTableProvider,\n type EditingCell,\n} from './data-table-context'\nimport { DataTableHeader } from './data-table-header'\nimport { DataTablePagination } from './data-table-pagination'\nimport { DataTableToolbar, type Density } from './data-table-toolbar'\nimport { Icon } from './icon'\nimport { cn } from './lib/utils'\nimport { Table } from './table'\n\n// Re-export public types so consumers' imports don't break\nexport type { BulkAction } from './data-table-bulk-actions'\n\ndeclare module '@tanstack/react-table' {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n interface ColumnMeta<TData extends RowData, TValue> {\n align?: 'left' | 'center' | 'right'\n hideBelow?: 'sm' | 'md' | 'lg'\n }\n}\n\n/**\n * Props for DataTable — a feature-rich TanStack Table wrapper supporting sorting, filtering,\n * pagination, row selection, inline editing, row expansion, column pinning, and virtualization.\n *\n * All features are opt-in via boolean flags. The component manages its own internal state for\n * sorting, filtering, pagination, and selection — just pass `columns` and `data`.\n *\n * **Feature flags:** `sortable` | `filterable` | `globalFilter` | `paginated` | `selectable` |\n * `toolbar` | `editable` | `expandable` | `virtualRows`\n *\n * **Columns:** Use TanStack Table's `ColumnDef<TData, TValue>` type. Set\n * `meta: { enableEditing: false }` on a column to disable cell editing for that column.\n *\n * @example\n * // Minimal read-only table:\n * const columns: ColumnDef<User, string>[] = [\n * { accessorKey: 'name', header: 'Name' },\n * { accessorKey: 'email', header: 'Email' },\n * ]\n * <DataTable columns={columns} data={users} />\n *\n * @example\n * // Full-featured admin table with sorting, pagination, and selection:\n * <DataTable\n * columns={projectColumns}\n * data={projects}\n * sortable\n * paginated\n * pageSize={20}\n * selectable\n * onSelectionChange={(rows) => setSelectedProjects(rows)}\n * toolbar\n * />\n *\n * @example\n * // Virtualized table for large datasets (10k+ rows):\n * <DataTable\n * columns={logColumns}\n * data={allLogs}\n * virtualRows\n * virtualRowHeight={40}\n * maxHeight={500}\n * />\n *\n * @example\n * // Table with expandable rows for nested detail:\n * <DataTable\n * columns={orderColumns}\n * data={orders}\n * expandable\n * renderExpanded={(order) => <OrderLineItems items={order.lineItems} />}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\n/**\n * A full-featured data table built on TanStack Table with sorting, filtering,\n * pagination, row selection, inline cell editing, expandable rows, column pinning,\n * a toolbar with density/export controls, and optional row virtualization.\n */\nexport interface DataTableProps<TData, TValue> {\n /** Column definitions passed to TanStack Table. */\n columns: ColumnDef<TData, TValue>[]\n /** Row data */\n data: TData[]\n /** Additional class name for the wrapper div */\n className?: string\n /** Text shown when the table has no rows */\n noResultsText?: string\n /** Enable column sorting (click headers to sort) */\n sortable?: boolean\n /** Enable per-column filter inputs below headers */\n filterable?: boolean\n /** Enable a global search input above the table */\n globalFilter?: boolean\n /** Enable pagination controls below the table */\n paginated?: boolean\n /** Number of rows per page when paginated (default 10) */\n pageSize?: number\n /** Options for the page size selector dropdown (default [10, 20, 50, 100]) */\n pageSizeOptions?: number[]\n /** Enable row selection with checkboxes */\n selectable?: boolean\n /** Callback when row selection changes */\n onSelectionChange?: (selectedRows: TData[]) => void\n /** Show toolbar above the table with column visibility, density, and export controls */\n toolbar?: boolean\n /** Row density — controls cell vertical padding */\n density?: Density\n /** Initial column pinning configuration */\n columnPinning?: { left?: string[]; right?: string[] }\n\n // --- Cell Editing ---\n /** Enable inline cell editing (double-click to edit) */\n editable?: boolean\n /** Callback when a cell value is edited */\n onCellEdit?: (rowIndex: number, columnId: string, value: unknown) => void\n\n // --- Row Expansion ---\n /** Enable expandable rows with detail panels */\n expandable?: boolean\n /** Render function for expanded row content */\n renderExpanded?: (row: TData) => React.ReactNode\n\n // --- Virtualization ---\n /** Enable row virtualization for large datasets */\n virtualRows?: boolean\n /** Height of each virtual row in pixels (default 48) */\n virtualRowHeight?: number\n /** Maximum height of the scrollable container in pixels (default 600) */\n maxHeight?: number\n\n // --- Server-side sorting ---\n /** Callback for server-side sorting. When provided, sorting is manual (no client-side sort). */\n onSort?: (key: string, direction: 'asc' | 'desc' | false) => void\n\n // --- Empty state ---\n /** Custom ReactNode to render when data is empty (replaces noResultsText) */\n emptyState?: React.ReactNode\n\n // --- Loading ---\n /** Show shimmer skeleton rows instead of data */\n loading?: boolean\n\n // --- Controlled selection ---\n /** Controlled set of selected row IDs — syncs internal selection state */\n selectedIds?: Set<string>\n /** Per-row filter to determine if a row is selectable */\n selectableFilter?: (row: TData) => boolean\n /** Custom row ID getter */\n getRowId?: (row: TData) => string\n\n // --- Server-side pagination ---\n /** Server-side pagination config. When provided, pagination is manual. */\n pagination?: {\n page: number\n pageSize: number\n total: number\n onPageChange: (page: number) => void\n }\n\n // --- Single-expand mode ---\n /** When true, only one row can be expanded at a time */\n singleExpand?: boolean\n\n // --- Sticky header ---\n /** When true, the table header sticks to the top on scroll */\n stickyHeader?: boolean\n\n // --- Row click ---\n /** Callback when a row is clicked (not fired from interactive elements) */\n onRowClick?: (row: TData) => void\n\n // --- Bulk actions ---\n /** Actions shown in a floating bar when rows are selected */\n bulkActions?: BulkAction<TData>[]\n\n // --- Mobile view ---\n /** Render rows as stacked cards on small screens (below sm breakpoint). Default 'table'. */\n mobileView?: 'card' | 'table'\n}\n\nexport function DataTable<TData, TValue>({\n columns,\n data,\n className,\n noResultsText,\n sortable = false,\n filterable = false,\n globalFilter = false,\n paginated = false,\n pageSize: initialPageSize,\n pageSizeOptions,\n selectable = false,\n onSelectionChange,\n toolbar = false,\n density: initialDensity = 'standard',\n columnPinning: initialColumnPinning,\n editable = false,\n onCellEdit,\n expandable = false,\n renderExpanded,\n virtualRows = false,\n virtualRowHeight = 48,\n maxHeight = 600,\n onSort,\n emptyState,\n loading = false,\n selectedIds,\n selectableFilter,\n getRowId: getRowIdProp,\n pagination: serverPagination,\n singleExpand = false,\n stickyHeader = false,\n onRowClick,\n bulkActions,\n mobileView = 'table',\n}: DataTableProps<TData, TValue>) {\n // Detect below-sm viewport (640px) for card mode — separate from useIsMobile (768px)\n const [isBelowSm, setIsBelowSm] = useState(false)\n useEffect(() => {\n const mql = window.matchMedia('(max-width: 639px)')\n const onChange = () => setIsBelowSm(mql.matches)\n mql.addEventListener('change', onChange)\n setIsBelowSm(mql.matches)\n return () => mql.removeEventListener('change', onChange)\n }, [])\n\n const showCards = mobileView === 'card' && isBelowSm\n\n const [sorting, setSorting] = useState<SortingState>([])\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])\n const [globalFilterValue, setGlobalFilterValue] = useState('')\n const [paginationState, setPaginationState] = useState<PaginationState>({\n pageIndex: serverPagination ? serverPagination.page - 1 : 0,\n pageSize: serverPagination?.pageSize ?? initialPageSize ?? 10,\n })\n const [rowSelection, setRowSelection] = useState<RowSelectionState>({})\n const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})\n const [columnPinningState, setColumnPinningState] =\n useState<ColumnPinningState>({\n left: initialColumnPinning?.left ?? [],\n right: initialColumnPinning?.right ?? [],\n })\n const [density, setDensity] = useState<Density>(initialDensity)\n const [editingCell, setEditingCell] = useState<EditingCell>(null)\n const [expanded, setExpanded] = useState<ExpandedState>({})\n\n // Ref for the virtual scroll container\n const scrollContainerRef = useRef<HTMLDivElement>(null)\n\n // Guard to prevent onSelectionChange firing when syncing from selectedIds prop\n const isSyncingFromPropRef = useRef(false)\n\n // Sync controlled selectedIds to internal rowSelection\n useEffect(() => {\n if (selectedIds) {\n isSyncingFromPropRef.current = true\n const newSelection: RowSelectionState = {}\n selectedIds.forEach((id) => {\n newSelection[id] = true\n })\n setRowSelection(newSelection)\n }\n }, [selectedIds])\n\n // Sync server pagination page to internal state\n useEffect(() => {\n if (serverPagination) {\n setPaginationState((prev) => ({\n ...prev,\n pageIndex: serverPagination.page - 1,\n pageSize: serverPagination.pageSize,\n }))\n }\n }, [serverPagination?.page, serverPagination?.pageSize]) // eslint-disable-line react-hooks/exhaustive-deps\n\n // Server-side sorting handler\n const handleSortingChange = useCallback(\n (updater: Updater<SortingState>) => {\n setSorting((prev) => {\n const next = typeof updater === 'function' ? updater(prev) : updater\n if (onSort) {\n if (next.length === 0 && prev.length > 0) {\n // Sorting cleared\n onSort(prev[0].id, false)\n } else if (next.length > 0) {\n onSort(next[0].id, next[0].desc ? 'desc' : 'asc')\n }\n }\n return next\n })\n },\n [onSort],\n )\n\n // Single-expand handler\n const handleExpandedChange = useCallback(\n (updater: Updater<ExpandedState>) => {\n setExpanded((prev) => {\n const next = typeof updater === 'function' ? updater(prev) : updater\n if (!singleExpand) return next\n // If next is boolean true (expand all), just use it\n if (next === true) return next\n if (typeof next !== 'object') return next\n // Determine which row was just toggled on\n const prevKeys = typeof prev === 'object' ? Object.keys(prev).filter((k) => (prev as Record<string, boolean>)[k]) : []\n const nextKeys = Object.keys(next).filter((k) => (next as Record<string, boolean>)[k])\n // Find newly expanded row\n const newlyExpanded = nextKeys.filter((k) => !prevKeys.includes(k))\n if (newlyExpanded.length > 0) {\n // Keep only the most recently expanded row\n return { [newlyExpanded[newlyExpanded.length - 1]]: true } as ExpandedState\n }\n // If no new rows, means a row was collapsed — return as-is\n return next\n })\n },\n [singleExpand],\n )\n\n // Stable ref for server pagination callback to avoid useCallback invalidation\n const onPageChangeRef = useRef(serverPagination?.onPageChange)\n useEffect(() => {\n onPageChangeRef.current = serverPagination?.onPageChange\n }, [serverPagination?.onPageChange])\n\n // Server-side pagination handler\n const handlePaginationChange = useCallback(\n (updater: Updater<PaginationState>) => {\n setPaginationState((prev) => {\n const next = typeof updater === 'function' ? updater(prev) : updater\n if (onPageChangeRef.current) {\n // Only call onPageChange if the page actually changed\n if (next.pageIndex !== prev.pageIndex) {\n onPageChangeRef.current(next.pageIndex + 1)\n }\n }\n return next\n })\n },\n [],\n )\n\n // Checkbox column prepended when selectable is enabled\n const selectColumn: ColumnDef<TData, unknown> = {\n id: '_select',\n header: ({ table: t }) => (\n <Checkbox\n size=\"sm\"\n checked={t.getIsAllPageRowsSelected()}\n indeterminate={t.getIsSomePageRowsSelected()}\n onCheckedChange={(v) => t.toggleAllPageRowsSelected(!!v)}\n aria-label=\"Select all rows\"\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n size=\"sm\"\n checked={row.getIsSelected()}\n disabled={!row.getCanSelect()}\n onCheckedChange={(v) => row.toggleSelected(!!v)}\n aria-label=\"Select row\"\n />\n ),\n enableSorting: false,\n enableColumnFilter: false,\n enableHiding: false,\n }\n\n // Expand toggle column — aria-expanded lives on the BUTTON (not the row),\n // in a dedicated column with a visually-hidden header (Roselli expando spec).\n const expandColumn: ColumnDef<TData, unknown> = {\n id: '_expand',\n header: () => <span className=\"sr-only\">Expand rows</span>,\n cell: ({ row }) => (\n <button\n type=\"button\"\n onClick={() => row.toggleExpanded()}\n aria-expanded={row.getIsExpanded()}\n aria-label={row.getIsExpanded() ? 'Collapse row' : 'Expand row'}\n className=\"flex items-center justify-center p-ds-01 rounded-control-inner hover:bg-surface-raised-hover transition-colors\"\n >\n <Icon\n icon={IconChevronRight}\n size=\"sm\"\n className={cn(\n 'transition-transform duration-fast-02 ease-productive-standard',\n row.getIsExpanded() && 'rotate-90',\n )}\n />\n </button>\n ),\n enableSorting: false,\n enableColumnFilter: false,\n enableHiding: false,\n }\n\n // Assemble all columns in order: select?, expand?, ...user columns\n const allColumns = [\n ...(selectable ? [selectColumn] : []),\n ...(expandable ? [expandColumn] : []),\n ...columns,\n ]\n\n // Determine if using server-side pagination\n const useServerPagination = !!serverPagination\n const showPagination = paginated || useServerPagination\n\n // Build state object once — sorting and filtering contribute independently\n const tableState: Partial<TableState> = {\n columnVisibility,\n columnPinning: columnPinningState,\n }\n if (sortable) tableState.sorting = sorting\n if (filterable || globalFilter) {\n tableState.columnFilters = columnFilters\n tableState.globalFilter = globalFilterValue\n }\n if (showPagination) tableState.pagination = paginationState\n if (selectable) tableState.rowSelection = rowSelection\n if (expandable) tableState.expanded = expanded\n\n // Determine server-side sort mode\n const isServerSort = sortable && !!onSort\n\n const table = useReactTable({\n data,\n columns: allColumns,\n state: tableState,\n onColumnVisibilityChange: setColumnVisibility,\n onColumnPinningChange: setColumnPinningState,\n getCoreRowModel: getCoreRowModel(),\n ...(sortable && {\n onSortingChange: isServerSort ? handleSortingChange : setSorting,\n ...(isServerSort\n ? { manualSorting: true }\n : { getSortedRowModel: getSortedRowModel() }),\n }),\n ...((filterable || globalFilter) && {\n onColumnFiltersChange: setColumnFilters,\n onGlobalFilterChange: setGlobalFilterValue,\n getFilteredRowModel: getFilteredRowModel(),\n }),\n ...(showPagination && {\n onPaginationChange: useServerPagination\n ? handlePaginationChange\n : setPaginationState,\n ...(useServerPagination\n ? {\n manualPagination: true,\n pageCount: Math.ceil(\n serverPagination!.total / serverPagination!.pageSize,\n ),\n }\n : { getPaginationRowModel: getPaginationRowModel() }),\n }),\n ...(selectable && {\n onRowSelectionChange: setRowSelection,\n enableRowSelection: selectableFilter\n ? (row: Row<TData>) => selectableFilter(row.original)\n : true,\n }),\n ...(expandable && {\n onExpandedChange: singleExpand ? handleExpandedChange : setExpanded,\n getExpandedRowModel: getExpandedRowModel(),\n }),\n ...(getRowIdProp && {\n getRowId: (row: TData) => getRowIdProp(row),\n }),\n })\n\n // Stable refs to avoid effect re-fires from inline callbacks\n const onSelectionChangeRef = useRef(onSelectionChange)\n const getRowIdRef = useRef(getRowIdProp)\n useEffect(() => {\n onSelectionChangeRef.current = onSelectionChange\n getRowIdRef.current = getRowIdProp\n }, [onSelectionChange, getRowIdProp])\n\n // Fire selection callback when row selection changes (skip when syncing from prop)\n useEffect(() => {\n if (isSyncingFromPropRef.current) {\n isSyncingFromPropRef.current = false\n return\n }\n if (!onSelectionChangeRef.current) return\n const selectedRowIds = Object.keys(rowSelection).filter((k) => rowSelection[k])\n const selected = data.filter((_, i) => {\n const id = getRowIdRef.current ? getRowIdRef.current(data[i]) : String(i)\n return selectedRowIds.includes(id)\n })\n onSelectionChangeRef.current(selected)\n }, [rowSelection, data])\n\n const rows = table.getRowModel().rows\n\n // Virtualizer — always called but only active when virtualRows is true\n const virtualizer = useVirtualizer({\n count: virtualRows ? rows.length : 0,\n getScrollElement: () => scrollContainerRef.current,\n estimateSize: () => virtualRowHeight,\n overscan: 10,\n })\n\n // Number of skeleton rows for loading state\n const skeletonRowCount = serverPagination?.pageSize ?? initialPageSize ?? 5\n\n // Get selected rows for bulk actions (derived from rowSelection + data, not table instance)\n const selectedRows = useMemo(() => {\n if (!bulkActions || !selectable) return []\n const selectedRowIds = Object.keys(rowSelection).filter((k) => rowSelection[k])\n return data.filter((_, i) => {\n const id = getRowIdProp ? getRowIdProp(data[i]) : String(i)\n return selectedRowIds.includes(id)\n })\n }, [bulkActions, selectable, rowSelection, data, getRowIdProp])\n\n const hasSelectedRows = selectedRows.length > 0\n\n // Total rows for pagination display\n const totalRowCount = useServerPagination\n ? serverPagination!.total\n : table.getFilteredRowModel().rows.length\n\n // Build context value for sub-components\n const contextValue = useMemo(\n () => ({\n table,\n allColumns: allColumns.map((col) => ({\n id: (col as { id?: string }).id,\n header: (col as { header?: unknown }).header,\n })),\n columnPinningState,\n sortable,\n filterable,\n editable,\n expandable,\n virtualRows,\n selectable,\n mobileView,\n editingCell,\n setEditingCell,\n onCellEdit,\n renderExpanded,\n onRowClick,\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n table,\n allColumns.length,\n columnPinningState,\n sortable,\n filterable,\n editable,\n expandable,\n virtualRows,\n selectable,\n mobileView,\n editingCell,\n onCellEdit,\n renderExpanded,\n onRowClick,\n ],\n )\n\n // Virtual items for body\n const virtualItems = virtualRows ? virtualizer.getVirtualItems() : undefined\n const totalVirtualSize = virtualRows ? virtualizer.getTotalSize() : undefined\n\n // Determine if we need a scroll wrapper for virtualization\n const tableContent = (\n <Table density={density} aria-busy={loading || undefined}>\n <DataTableHeader stickyHeader={stickyHeader} />\n <DataTableBody\n loading={loading}\n skeletonRowCount={skeletonRowCount}\n noResultsText={noResultsText}\n emptyState={emptyState}\n virtualItems={virtualItems}\n totalVirtualSize={totalVirtualSize}\n />\n </Table>\n )\n\n return (\n <DataTableProvider value={contextValue}>\n <div className={cn(className)}>\n {/* Toolbar */}\n {toolbar && (\n <DataTableToolbar\n table={table}\n globalFilter={globalFilter}\n globalFilterValue={globalFilterValue}\n onGlobalFilterChange={setGlobalFilterValue}\n density={density}\n onDensityChange={setDensity}\n />\n )}\n\n {/* Global search input — only show standalone when toolbar is disabled */}\n {globalFilter && !toolbar && (\n <div className=\"flex items-center gap-ds-03 pb-ds-04 border-b border-surface-border mb-ds-04\">\n <Icon icon={IconSearch} size=\"sm\" className=\"text-surface-fg-subtle\" />\n <input\n type=\"text\"\n value={globalFilterValue}\n onChange={(e) => setGlobalFilterValue(e.target.value)}\n placeholder=\"Search all columns...\"\n aria-label=\"Search all columns\"\n className={cn(\n 'flex-1 bg-transparent text-ds-md',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden',\n )}\n />\n </div>\n )}\n\n {/* Card view on small screens, or standard table */}\n {showCards ? (\n <DataTableCards\n loading={loading}\n skeletonRowCount={skeletonRowCount}\n noResultsText={noResultsText}\n emptyState={emptyState}\n />\n ) : virtualRows ? (\n <div\n ref={scrollContainerRef}\n style={{ maxHeight: `${maxHeight}px`, overflowY: 'auto' }}\n >\n {tableContent}\n </div>\n ) : (\n tableContent\n )}\n\n {/* Pagination controls */}\n {showPagination && (\n <DataTablePagination\n table={table}\n totalRowCount={totalRowCount}\n useServerPagination={useServerPagination}\n pageSizeOptions={pageSizeOptions}\n />\n )}\n\n {/* Bulk action bar */}\n {bulkActions && selectable && hasSelectedRows && (\n <DataTableBulkActions\n table={table}\n selectedRows={selectedRows}\n bulkActions={bulkActions}\n />\n )}\n </div>\n </DataTableProvider>\n )\n}\nDataTable.displayName = 'DataTable'\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import * as React from 'react';
|
|
2
3
|
export type GrainIntensity = 'subtle' | 'medium' | 'heavy';
|
|
3
4
|
export interface DevalokGrainProps {
|
|
4
5
|
/** Grain intensity level. Default: 'subtle' */
|
|
@@ -74,7 +75,7 @@ export interface DevalokGrainProps {
|
|
|
74
75
|
* <h1 className="relative z-[2]">Hero</h1>
|
|
75
76
|
* </div>
|
|
76
77
|
*/
|
|
77
|
-
export declare function DevalokGrain({ intensity, surface, sheen, tint, animated, hoverIntensify, }: DevalokGrainProps):
|
|
78
|
+
export declare function DevalokGrain({ intensity, surface, sheen, tint, animated, hoverIntensify, }: DevalokGrainProps): React.JSX.Element;
|
|
78
79
|
export declare namespace DevalokGrain {
|
|
79
80
|
var displayName: string;
|
|
80
81
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devalok-grain.d.ts","sourceRoot":"","sources":["../../src/ui/devalok-grain.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"devalok-grain.d.ts","sourceRoot":"","sources":["../../src/ui/devalok-grain.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAA;AAc1D,MAAM,WAAW,iBAAiB;IAChC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,cAAc,CAAA;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IAC1B;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;;;;;;;;;;OAcG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,YAAY,CAAC,EAC3B,SAAoB,EACpB,OAAiB,EACjB,KAAa,EACb,IAAI,EACJ,QAAgB,EAChB,cAAsB,GACvB,EAAE,iBAAiB,qBAsEnB;yBA7Ee,YAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devalok-grain.js","names":[],"sources":["../../src/ui/devalok-grain.tsx"],"sourcesContent":["'use client'\n\nimport { motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nconst NOISE_SVG = `url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.45' numOctaves='3' seed='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E\")`\n\nexport type GrainIntensity = 'subtle' | 'medium' | 'heavy'\n\nconst NOISE_OPACITY = {\n subtle: { solid: 0.20, soft: 0.15 },\n medium: { solid: 0.28, soft: 0.22 },\n heavy: { solid: 0.45, soft: 0.35 },\n} as const\n\nconst GRADIENT = {\n subtle: { ld: 0.06, ll: 0.08, dk: 0.08 },\n medium: { ld: 0.10, ll: 0.12, dk: 0.12 },\n heavy: { ld: 0.16, ll: 0.18, dk: 0.18 },\n} as const\n\nexport interface DevalokGrainProps {\n /** Grain intensity level. Default: 'subtle' */\n intensity?: GrainIntensity\n /**\n * Surface type hint — affects noise opacity.\n * 'solid' for filled backgrounds (higher opacity).\n * 'soft' for tinted/muted backgrounds (lower opacity).\n * Default: 'solid'\n */\n surface?: 'solid' | 'soft'\n /**\n * Add an inner highlight (top-lit emboss) for a premium 3D feel.\n * Adds an inset shadow: light highlight on top edge, dark shadow on bottom edge.\n * Works best on solid variant buttons. Default: false\n */\n sheen?: boolean\n /**\n * Animate the grain entrance (fade in on mount). Default: false\n * When true, the grain fades in over 600ms with a slight scale for a natural reveal.\n */\n animated?: boolean\n /**\n * Increase grain visibility on parent hover. Default: false\n * When the parent element is hovered, the noise opacity increases by ~40%\n * and the gradient deepens slightly, creating a tactile \"pressing into paper\" feel.\n * Requires the parent to have a `group` class for `group-hover:` to work.\n */\n hoverIntensify?: boolean\n /**\n * Tint color for the directional gradient. Accepts any CSS color value.\n * The gradient goes from a darker shade of this color to a lighter shade.\n * Default: neutral black-to-white wash.\n *\n * @example\n * // Warm pink tint (Devalok brand)\n * <DevalokGrain tint=\"oklch(0.55 0.19 360)\" />\n *\n * // Cool blue tint\n * <DevalokGrain tint=\"oklch(0.55 0.12 240)\" />\n *\n * // Use a CSS variable\n * <DevalokGrain tint=\"var(--color-accent-9)\" />\n */\n tint?: string\n}\n\n/**\n * DevalokGrain — Brand texture that adds a subtle noise grain + directional gradient\n * to any surface. The Devalok signature: warm, tactile, paper-like.\n *\n * Drop as a child of any element that has `relative overflow-hidden isolate`.\n * The grain layers are absolute-positioned at z-[1] and use `rounded-[inherit]`\n * to match the parent's border-radius.\n *\n * @example\n * // Inside a Button (Button already has relative/overflow-hidden/isolate):\n * <Button>\n * <DevalokGrain />\n * Save changes\n * </Button>\n *\n * @example\n * // Inside a Card:\n * <Card className=\"relative overflow-hidden isolate\">\n * <DevalokGrain surface=\"soft\" />\n * Card content\n * </Card>\n *\n * @example\n * // Heavier grain for a hero section:\n * <div className=\"relative overflow-hidden isolate rounded-surface bg-accent-9 p-8\">\n * <DevalokGrain intensity=\"heavy\" />\n * <h1 className=\"relative z-[2]\">Hero</h1>\n * </div>\n */\nexport function DevalokGrain({\n intensity = 'subtle',\n surface = 'solid',\n sheen = false,\n tint,\n animated = false,\n hoverIntensify = false,\n}: DevalokGrainProps) {\n const prefersReduced = useReducedMotion()\n const noise = NOISE_OPACITY[intensity][surface]\n const hoverNoise = Math.min(noise * 1.4, 0.6) // 40% more on hover, capped\n const g = GRADIENT[intensity]\n\n // Gradient adds directional dimensionality — a subtle diagonal wash that makes the\n // surface feel lit from the top-left. When tinted, the gradient carries the tint color.\n // When untinted, a neutral black→white wash still adds depth without coloring the surface.\n const lightGradient = tint\n ? `linear-gradient(135deg, color-mix(in oklch, ${tint} ${Math.round(g.ld * 100)}%, transparent), color-mix(in oklch, white ${Math.round(g.ll * 100)}%, transparent))`\n : `linear-gradient(135deg, oklch(0 0 0 / ${g.ld}), oklch(1 0 0 / ${g.ll}))`\n const darkGradient = tint\n ? `linear-gradient(135deg, transparent, color-mix(in oklch, ${tint} ${Math.round(g.dk * 100)}%, transparent))`\n : `linear-gradient(135deg, transparent, oklch(0 0 0 / ${g.dk}))`\n\n const shouldAnimate = animated && !prefersReduced\n\n const Wrapper = shouldAnimate ? motion.span : 'span'\n const wrapperProps = shouldAnimate\n ? {\n initial: { opacity: 0 },\n animate: { opacity: 1 },\n transition: { duration: 0.6, ease: [0.2, 0, 0.38, 0.9] },\n }\n : {}\n\n return (\n <Wrapper\n data-grain=\"\"\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-0 z-[1] rounded-[inherit] isolate overflow-hidden\"\n {...(wrapperProps as any)}\n >\n {/* Gradient — only when tinted (neutral gradient looks like a dark smudge on light surfaces) */}\n {lightGradient && (\n <span\n className={`absolute inset-0 dark:hidden transition-opacity duration-300 ${\n hoverIntensify ? 'group-hover:opacity-100 opacity-80' : ''\n }`}\n style={{ background: lightGradient }}\n />\n )}\n {darkGradient && (\n <span\n className={`absolute inset-0 hidden dark:block transition-opacity duration-300 ${\n hoverIntensify ? 'group-hover:opacity-100 opacity-80' : ''\n }`}\n style={{ background: darkGradient }}\n />\n )}\n {/* Noise texture */}\n <span\n className={`absolute inset-0 transition-opacity duration-300 ${\n hoverIntensify ? 'group-hover:opacity-[var(--grain-hover-opacity)]' : ''\n }`}\n style={{\n backgroundImage: NOISE_SVG,\n backgroundSize: '100px 100px',\n filter: 'contrast(250%) brightness(105%)',\n opacity: noise,\n '--grain-hover-opacity': hoverIntensify ? hoverNoise : undefined,\n } as React.CSSProperties}\n />\n {/* Sheen — inner highlight */}\n {sheen && (\n <span className=\"absolute inset-0 shadow-raised-inner\" />\n )}\n </Wrapper>\n )\n}\n\nDevalokGrain.displayName = 'DevalokGrain'\n"],"mappings":";;;;;AAKA,IAAM,IAAY,+SAIZ,IAAgB;CACpB,QAAQ;EAAE,OAAO;EAAM,MAAM;
|
|
1
|
+
{"version":3,"file":"devalok-grain.js","names":[],"sources":["../../src/ui/devalok-grain.tsx"],"sourcesContent":["'use client'\n\nimport { motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nconst NOISE_SVG = `url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.45' numOctaves='3' seed='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E\")`\n\nexport type GrainIntensity = 'subtle' | 'medium' | 'heavy'\n\nconst NOISE_OPACITY = {\n subtle: { solid: 0.20, soft: 0.15 },\n medium: { solid: 0.28, soft: 0.22 },\n heavy: { solid: 0.45, soft: 0.35 },\n} as const\n\nconst GRADIENT = {\n subtle: { ld: 0.06, ll: 0.08, dk: 0.08 },\n medium: { ld: 0.10, ll: 0.12, dk: 0.12 },\n heavy: { ld: 0.16, ll: 0.18, dk: 0.18 },\n} as const\n\nexport interface DevalokGrainProps {\n /** Grain intensity level. Default: 'subtle' */\n intensity?: GrainIntensity\n /**\n * Surface type hint — affects noise opacity.\n * 'solid' for filled backgrounds (higher opacity).\n * 'soft' for tinted/muted backgrounds (lower opacity).\n * Default: 'solid'\n */\n surface?: 'solid' | 'soft'\n /**\n * Add an inner highlight (top-lit emboss) for a premium 3D feel.\n * Adds an inset shadow: light highlight on top edge, dark shadow on bottom edge.\n * Works best on solid variant buttons. Default: false\n */\n sheen?: boolean\n /**\n * Animate the grain entrance (fade in on mount). Default: false\n * When true, the grain fades in over 600ms with a slight scale for a natural reveal.\n */\n animated?: boolean\n /**\n * Increase grain visibility on parent hover. Default: false\n * When the parent element is hovered, the noise opacity increases by ~40%\n * and the gradient deepens slightly, creating a tactile \"pressing into paper\" feel.\n * Requires the parent to have a `group` class for `group-hover:` to work.\n */\n hoverIntensify?: boolean\n /**\n * Tint color for the directional gradient. Accepts any CSS color value.\n * The gradient goes from a darker shade of this color to a lighter shade.\n * Default: neutral black-to-white wash.\n *\n * @example\n * // Warm pink tint (Devalok brand)\n * <DevalokGrain tint=\"oklch(0.55 0.19 360)\" />\n *\n * // Cool blue tint\n * <DevalokGrain tint=\"oklch(0.55 0.12 240)\" />\n *\n * // Use a CSS variable\n * <DevalokGrain tint=\"var(--color-accent-9)\" />\n */\n tint?: string\n}\n\n/**\n * DevalokGrain — Brand texture that adds a subtle noise grain + directional gradient\n * to any surface. The Devalok signature: warm, tactile, paper-like.\n *\n * Drop as a child of any element that has `relative overflow-hidden isolate`.\n * The grain layers are absolute-positioned at z-[1] and use `rounded-[inherit]`\n * to match the parent's border-radius.\n *\n * @example\n * // Inside a Button (Button already has relative/overflow-hidden/isolate):\n * <Button>\n * <DevalokGrain />\n * Save changes\n * </Button>\n *\n * @example\n * // Inside a Card:\n * <Card className=\"relative overflow-hidden isolate\">\n * <DevalokGrain surface=\"soft\" />\n * Card content\n * </Card>\n *\n * @example\n * // Heavier grain for a hero section:\n * <div className=\"relative overflow-hidden isolate rounded-surface bg-accent-9 p-8\">\n * <DevalokGrain intensity=\"heavy\" />\n * <h1 className=\"relative z-[2]\">Hero</h1>\n * </div>\n */\nexport function DevalokGrain({\n intensity = 'subtle',\n surface = 'solid',\n sheen = false,\n tint,\n animated = false,\n hoverIntensify = false,\n}: DevalokGrainProps) {\n const prefersReduced = useReducedMotion()\n const noise = NOISE_OPACITY[intensity][surface]\n const hoverNoise = Math.min(noise * 1.4, 0.6) // 40% more on hover, capped\n const g = GRADIENT[intensity]\n\n // Gradient adds directional dimensionality — a subtle diagonal wash that makes the\n // surface feel lit from the top-left. When tinted, the gradient carries the tint color.\n // When untinted, a neutral black→white wash still adds depth without coloring the surface.\n const lightGradient = tint\n ? `linear-gradient(135deg, color-mix(in oklch, ${tint} ${Math.round(g.ld * 100)}%, transparent), color-mix(in oklch, white ${Math.round(g.ll * 100)}%, transparent))`\n : `linear-gradient(135deg, oklch(0 0 0 / ${g.ld}), oklch(1 0 0 / ${g.ll}))`\n const darkGradient = tint\n ? `linear-gradient(135deg, transparent, color-mix(in oklch, ${tint} ${Math.round(g.dk * 100)}%, transparent))`\n : `linear-gradient(135deg, transparent, oklch(0 0 0 / ${g.dk}))`\n\n const shouldAnimate = animated && !prefersReduced\n\n const Wrapper = shouldAnimate ? motion.span : 'span'\n const wrapperProps = shouldAnimate\n ? {\n initial: { opacity: 0 },\n animate: { opacity: 1 },\n transition: { duration: 0.6, ease: [0.2, 0, 0.38, 0.9] },\n }\n : {}\n\n return (\n <Wrapper\n data-grain=\"\"\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-0 z-[1] rounded-[inherit] isolate overflow-hidden\"\n {...(wrapperProps as any)}\n >\n {/* Gradient — only when tinted (neutral gradient looks like a dark smudge on light surfaces) */}\n {lightGradient && (\n <span\n className={`absolute inset-0 dark:hidden transition-opacity duration-300 ${\n hoverIntensify ? 'group-hover:opacity-100 opacity-80' : ''\n }`}\n style={{ background: lightGradient }}\n />\n )}\n {darkGradient && (\n <span\n className={`absolute inset-0 hidden dark:block transition-opacity duration-300 ${\n hoverIntensify ? 'group-hover:opacity-100 opacity-80' : ''\n }`}\n style={{ background: darkGradient }}\n />\n )}\n {/* Noise texture */}\n <span\n className={`absolute inset-0 transition-opacity duration-300 ${\n hoverIntensify ? 'group-hover:opacity-[var(--grain-hover-opacity)]' : ''\n }`}\n style={{\n backgroundImage: NOISE_SVG,\n backgroundSize: '100px 100px',\n filter: 'contrast(250%) brightness(105%)',\n opacity: noise,\n '--grain-hover-opacity': hoverIntensify ? hoverNoise : undefined,\n } as React.CSSProperties}\n />\n {/* Sheen — inner highlight */}\n {sheen && (\n <span className=\"absolute inset-0 shadow-raised-inner\" />\n )}\n </Wrapper>\n )\n}\n\nDevalokGrain.displayName = 'DevalokGrain'\n"],"mappings":";;;;;AAKA,IAAM,IAAY,+SAIZ,IAAgB;CACpB,QAAQ;EAAE,OAAO;EAAM,MAAM;CAAK;CAClC,QAAQ;EAAE,OAAO;EAAM,MAAM;CAAK;CAClC,OAAQ;EAAE,OAAO;EAAM,MAAM;CAAK;AACpC,GAEM,IAAW;CACf,QAAQ;EAAE,IAAI;EAAM,IAAI;EAAM,IAAI;CAAK;CACvC,QAAQ;EAAE,IAAI;EAAM,IAAI;EAAM,IAAI;CAAK;CACvC,OAAQ;EAAE,IAAI;EAAM,IAAI;EAAM,IAAI;CAAK;AACzC;AA6EA,SAAgB,EAAa,EAC3B,eAAY,UACZ,aAAU,SACV,WAAQ,IACR,SACA,cAAW,IACX,oBAAiB,MACG;CACpB,IAAM,IAAiB,EAAiB,GAClC,IAAQ,EAAc,EAAU,CAAC,IACjC,IAAa,KAAK,IAAI,IAAQ,KAAK,EAAG,GACtC,IAAI,EAAS,IAKb,IAAgB,IAClB,+CAA+C,EAAK,GAAG,KAAK,MAAM,EAAE,KAAK,GAAG,EAAE,6CAA6C,KAAK,MAAM,EAAE,KAAK,GAAG,EAAE,oBAClJ,yCAAyC,EAAE,GAAG,mBAAmB,EAAE,GAAG,KACpE,IAAe,IACjB,4DAA4D,EAAK,GAAG,KAAK,MAAM,EAAE,KAAK,GAAG,EAAE,oBAC3F,sDAAsD,EAAE,GAAG,KAEzD,IAAgB,KAAY,CAAC;CAWnC,OACE,kBAVc,IAAgB,EAAO,OAAO,QAU5C;EACE,cAAW;EACX,eAAY;EACZ,WAAU;EACV,GAbiB,IACjB;GACE,SAAS,EAAE,SAAS,EAAE;GACtB,SAAS,EAAE,SAAS,EAAE;GACtB,YAAY;IAAE,UAAU;IAAK,MAAM;KAAC;KAAK;KAAG;KAAM;IAAG;GAAE;EACzD,IACA,CAAC;YAGH;GAOG,KACC,kBAAC,QAAD;IACE,WAAW,gEACT,IAAiB,uCAAuC;IAE1D,OAAO,EAAE,YAAY,EAAc;GACpC,CAAA;GAEF,KACC,kBAAC,QAAD;IACE,WAAW,sEACT,IAAiB,uCAAuC;IAE1D,OAAO,EAAE,YAAY,EAAa;GACnC,CAAA;GAGH,kBAAC,QAAD;IACE,WAAW,oDACT,IAAiB,qDAAqD;IAExE,OAAO;KACL,iBAAiB;KACjB,gBAAgB;KAChB,QAAQ;KACR,SAAS;KACT,yBAAyB,IAAiB,IAAa,KAAA;IACzD;GACD,CAAA;GAEA,KACC,kBAAC,QAAD,EAAM,WAAU,uCAAwC,CAAA;EAEnD;;AAEb;AAEA,EAAa,cAAc"}
|
package/dist/ui/dialog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog.js","names":[],"sources":["../../src/ui/dialog.tsx"],"sourcesContent":["'use client'\n\nimport * as DialogPrimitive from '@primitives/react-dialog'\nimport { IconX as CloseIcon } from '@tabler/icons-react'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useIsMobile } from '../hooks/use-mobile'\nimport { Icon } from './icon'\nimport { springs, tweens } from './lib/motion'\nimport { useControllableOpen } from './lib/use-controllable-open'\nimport { cn } from './lib/utils'\n\n// ── Internal context to thread `open` state to animated children ──\n\ntype DialogContextValue = { open: boolean }\nconst DialogContext = React.createContext<DialogContextValue>({ open: false })\nconst useDialogOpen = () => React.useContext(DialogContext)\n\n/**\n * Dialog compound component — accessible modal overlay with focus trap and Escape dismissal.\n *\n * **Parts (in composition order):**\n * - `Dialog` — manages open/closed state (this root)\n * - `DialogTrigger` — element that opens the dialog (use `asChild` to render your own button)\n * - `DialogContent` — the modal panel (auto-includes portal, overlay, and close button)\n * - `DialogHeader` — optional layout wrapper for title + description\n * - `DialogTitle` — required for accessibility (sets the dialog's ARIA label)\n * - `DialogDescription` — optional subtitle text\n * - `DialogFooter` — optional layout wrapper for action buttons\n * - `DialogClose` — manual close trigger (a close button is already built into DialogContent)\n * - `DialogContentRaw` — use instead of DialogContent when you need full portal/overlay control\n * - `DialogPortal` — low-level portal wrapper (exported for custom layout; used internally by DialogContent)\n * - `DialogOverlay` — the backdrop element (exported for custom overlay styling or positioning)\n *\n * @compound\n * @example\n * // Confirmation dialog:\n * <Dialog>\n * <DialogTrigger asChild>\n * <Button variant=\"solid\" color=\"error\">Delete project</Button>\n * </DialogTrigger>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Are you absolutely sure?</DialogTitle>\n * <DialogDescription>\n * This action cannot be undone. This will permanently delete your project.\n * </DialogDescription>\n * </DialogHeader>\n * <DialogFooter>\n * <DialogClose asChild><Button variant=\"outline\">Cancel</Button></DialogClose>\n * <Button variant=\"solid\" color=\"error\" onClick={handleDelete}>Delete</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n *\n * @example\n * // Controlled open state (no trigger in markup):\n * const [open, setOpen] = useState(false)\n * <Dialog open={open} onOpenChange={setOpen}>\n * <DialogContent>\n * <DialogTitle>Edit profile</DialogTitle>\n * // form fields\n * </DialogContent>\n * </Dialog>\n */\nconst Dialog: React.FC<React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root>> = ({\n open: openProp,\n defaultOpen,\n onOpenChange,\n ...props\n}) => {\n const { open, setOpen } = useControllableOpen({ open: openProp, defaultOpen, onOpenChange })\n\n const contextValue = React.useMemo(() => ({ open }), [open])\n\n return (\n <DialogContext.Provider value={contextValue}>\n <DialogPrimitive.Root open={open} onOpenChange={setOpen} {...props} />\n </DialogContext.Provider>\n )\n}\nDialog.displayName = 'Dialog'\n\nconst DialogTrigger = DialogPrimitive.Trigger\n\nconst DialogPortal = DialogPrimitive.Portal\n\nconst DialogClose = DialogPrimitive.Close\n\nconst DialogOverlay = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n forceMount\n className={cn(\n 'fixed inset-0 z-overlay bg-overlay',\n className,\n )}\n {...props}\n />\n))\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName\n\ninterface DialogContentProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n /** When true (default), Dialog fills the screen on mobile (<768px). Set false to always use centered modal. */\n responsive?: boolean\n}\n\nconst DialogContent = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Content>,\n DialogContentProps\n>(({ className, children, responsive, ...props }, ref) => {\n const { open } = useDialogOpen()\n const isMobileRaw = useIsMobile()\n const isMobile = responsive !== false && isMobileRaw\n\n return (\n <AnimatePresence>\n {open && (\n <DialogPortal forceMount>\n <DialogOverlay asChild>\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={tweens.fade}\n />\n </DialogOverlay>\n <DialogPrimitive.Content\n ref={ref}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={isMobile ? { y: '100%' } : { opacity: 0, scale: 0.95, x: '-50%', y: '-50%' }}\n animate={isMobile ? { y: 0 } : { opacity: 1, scale: 1, x: '-50%', y: '-50%' }}\n exit={isMobile ? { y: '100%' } : { opacity: 0, scale: 0.95, x: '-50%', y: '-50%' }}\n transition={isMobile\n ? springs.smooth\n : { ...springs.smooth, opacity: tweens.fade }\n }\n className={cn(\n 'fixed z-modal grid w-full gap-ds-05 bg-surface-overlay p-ds-06',\n responsive !== false\n ? 'inset-0 md:inset-auto md:left-[50%] md:top-[50%] md:max-w-lg md:rounded-overlay-lg md:shadow-overlay'\n : 'left-[50%] top-[50%] max-w-lg rounded-overlay-lg shadow-overlay',\n className,\n )}\n >\n {children}\n <DialogPrimitive.Close title=\"Close\" className=\"absolute right-ds-05 top-ds-05 min-h-ds-xs min-w-ds-xs flex items-center justify-center rounded-control-inner text-surface-fg-subtle transition-colors duration-fast-01 ease-productive-standard hover:text-surface-fg-muted hover:bg-surface-raised-hover active:scale-90 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 disabled:pointer-events-none\">\n <Icon icon={CloseIcon} size=\"lg\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n </motion.div>\n </DialogPrimitive.Content>\n </DialogPortal>\n )}\n </AnimatePresence>\n )\n})\nDialogContent.displayName = DialogPrimitive.Content.displayName\n\n/**\n * DialogContentRaw -- a minimal forwardRef wrapper around the primitive Content.\n * Unlike DialogContent, it does NOT include Portal, Overlay, or CloseButton.\n * Use this when you need full control over portal/overlay/close behaviour\n * (e.g. CommandPalette in shared/).\n */\nconst DialogContentRaw = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Content\n ref={ref}\n className={cn(className)}\n {...props}\n />\n))\nDialogContentRaw.displayName = 'DialogContentRaw'\n\nconst DialogHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col space-y-ds-02b text-center sm:text-left',\n className,\n )}\n {...props}\n />\n ),\n)\nDialogHeader.displayName = 'DialogHeader'\n\nconst DialogFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-ds-03',\n className,\n )}\n {...props}\n />\n ),\n)\nDialogFooter.displayName = 'DialogFooter'\n\nconst DialogTitle = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\n 'text-ds-lg font-semibold',\n className,\n )}\n {...props}\n />\n))\nDialogTitle.displayName = DialogPrimitive.Title.displayName\n\nconst DialogDescription = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn('text-ds-md text-surface-fg-muted', className)}\n {...props}\n />\n))\nDialogDescription.displayName = DialogPrimitive.Description.displayName\n\nexport type { DialogContentProps }\nexport type DialogTitleProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogContentRaw,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dialog.js","names":[],"sources":["../../src/ui/dialog.tsx"],"sourcesContent":["'use client'\n\nimport * as DialogPrimitive from '@primitives/react-dialog'\nimport { IconX as CloseIcon } from '@tabler/icons-react'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useIsMobile } from '../hooks/use-mobile'\nimport { Icon } from './icon'\nimport { springs, tweens } from './lib/motion'\nimport { useControllableOpen } from './lib/use-controllable-open'\nimport { cn } from './lib/utils'\n\n// ── Internal context to thread `open` state to animated children ──\n\ntype DialogContextValue = { open: boolean }\nconst DialogContext = React.createContext<DialogContextValue>({ open: false })\nconst useDialogOpen = () => React.useContext(DialogContext)\n\n/**\n * Dialog compound component — accessible modal overlay with focus trap and Escape dismissal.\n *\n * **Parts (in composition order):**\n * - `Dialog` — manages open/closed state (this root)\n * - `DialogTrigger` — element that opens the dialog (use `asChild` to render your own button)\n * - `DialogContent` — the modal panel (auto-includes portal, overlay, and close button)\n * - `DialogHeader` — optional layout wrapper for title + description\n * - `DialogTitle` — required for accessibility (sets the dialog's ARIA label)\n * - `DialogDescription` — optional subtitle text\n * - `DialogFooter` — optional layout wrapper for action buttons\n * - `DialogClose` — manual close trigger (a close button is already built into DialogContent)\n * - `DialogContentRaw` — use instead of DialogContent when you need full portal/overlay control\n * - `DialogPortal` — low-level portal wrapper (exported for custom layout; used internally by DialogContent)\n * - `DialogOverlay` — the backdrop element (exported for custom overlay styling or positioning)\n *\n * @compound\n * @example\n * // Confirmation dialog:\n * <Dialog>\n * <DialogTrigger asChild>\n * <Button variant=\"solid\" color=\"error\">Delete project</Button>\n * </DialogTrigger>\n * <DialogContent>\n * <DialogHeader>\n * <DialogTitle>Are you absolutely sure?</DialogTitle>\n * <DialogDescription>\n * This action cannot be undone. This will permanently delete your project.\n * </DialogDescription>\n * </DialogHeader>\n * <DialogFooter>\n * <DialogClose asChild><Button variant=\"outline\">Cancel</Button></DialogClose>\n * <Button variant=\"solid\" color=\"error\" onClick={handleDelete}>Delete</Button>\n * </DialogFooter>\n * </DialogContent>\n * </Dialog>\n *\n * @example\n * // Controlled open state (no trigger in markup):\n * const [open, setOpen] = useState(false)\n * <Dialog open={open} onOpenChange={setOpen}>\n * <DialogContent>\n * <DialogTitle>Edit profile</DialogTitle>\n * // form fields\n * </DialogContent>\n * </Dialog>\n */\nconst Dialog: React.FC<React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root>> = ({\n open: openProp,\n defaultOpen,\n onOpenChange,\n ...props\n}) => {\n const { open, setOpen } = useControllableOpen({ open: openProp, defaultOpen, onOpenChange })\n\n const contextValue = React.useMemo(() => ({ open }), [open])\n\n return (\n <DialogContext.Provider value={contextValue}>\n <DialogPrimitive.Root open={open} onOpenChange={setOpen} {...props} />\n </DialogContext.Provider>\n )\n}\nDialog.displayName = 'Dialog'\n\nconst DialogTrigger = DialogPrimitive.Trigger\n\nconst DialogPortal = DialogPrimitive.Portal\n\nconst DialogClose = DialogPrimitive.Close\n\nconst DialogOverlay = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n forceMount\n className={cn(\n 'fixed inset-0 z-overlay bg-overlay',\n className,\n )}\n {...props}\n />\n))\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName\n\ninterface DialogContentProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n /** When true (default), Dialog fills the screen on mobile (<768px). Set false to always use centered modal. */\n responsive?: boolean\n}\n\nconst DialogContent = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Content>,\n DialogContentProps\n>(({ className, children, responsive, ...props }, ref) => {\n const { open } = useDialogOpen()\n const isMobileRaw = useIsMobile()\n const isMobile = responsive !== false && isMobileRaw\n\n return (\n <AnimatePresence>\n {open && (\n <DialogPortal forceMount>\n <DialogOverlay asChild>\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={tweens.fade}\n />\n </DialogOverlay>\n <DialogPrimitive.Content\n ref={ref}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={isMobile ? { y: '100%' } : { opacity: 0, scale: 0.95, x: '-50%', y: '-50%' }}\n animate={isMobile ? { y: 0 } : { opacity: 1, scale: 1, x: '-50%', y: '-50%' }}\n exit={isMobile ? { y: '100%' } : { opacity: 0, scale: 0.95, x: '-50%', y: '-50%' }}\n transition={isMobile\n ? springs.smooth\n : { ...springs.smooth, opacity: tweens.fade }\n }\n className={cn(\n 'fixed z-modal grid w-full gap-ds-05 bg-surface-overlay p-ds-06',\n responsive !== false\n ? 'inset-0 md:inset-auto md:left-[50%] md:top-[50%] md:max-w-lg md:rounded-overlay-lg md:shadow-overlay'\n : 'left-[50%] top-[50%] max-w-lg rounded-overlay-lg shadow-overlay',\n className,\n )}\n >\n {children}\n <DialogPrimitive.Close title=\"Close\" className=\"absolute right-ds-05 top-ds-05 min-h-ds-xs min-w-ds-xs flex items-center justify-center rounded-control-inner text-surface-fg-subtle transition-colors duration-fast-01 ease-productive-standard hover:text-surface-fg-muted hover:bg-surface-raised-hover active:scale-90 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 disabled:pointer-events-none\">\n <Icon icon={CloseIcon} size=\"lg\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n </motion.div>\n </DialogPrimitive.Content>\n </DialogPortal>\n )}\n </AnimatePresence>\n )\n})\nDialogContent.displayName = DialogPrimitive.Content.displayName\n\n/**\n * DialogContentRaw -- a minimal forwardRef wrapper around the primitive Content.\n * Unlike DialogContent, it does NOT include Portal, Overlay, or CloseButton.\n * Use this when you need full control over portal/overlay/close behaviour\n * (e.g. CommandPalette in shared/).\n */\nconst DialogContentRaw = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Content\n ref={ref}\n className={cn(className)}\n {...props}\n />\n))\nDialogContentRaw.displayName = 'DialogContentRaw'\n\nconst DialogHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col space-y-ds-02b text-center sm:text-left',\n className,\n )}\n {...props}\n />\n ),\n)\nDialogHeader.displayName = 'DialogHeader'\n\nconst DialogFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-ds-03',\n className,\n )}\n {...props}\n />\n ),\n)\nDialogFooter.displayName = 'DialogFooter'\n\nconst DialogTitle = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\n 'text-ds-lg font-semibold',\n className,\n )}\n {...props}\n />\n))\nDialogTitle.displayName = DialogPrimitive.Title.displayName\n\nconst DialogDescription = React.forwardRef<\n React.ElementRef<typeof DialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn('text-ds-md text-surface-fg-muted', className)}\n {...props}\n />\n))\nDialogDescription.displayName = DialogPrimitive.Description.displayName\n\nexport type { DialogContentProps }\nexport type DialogTitleProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogContentRaw,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n}\n"],"mappings":"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"}
|
package/dist/ui/dot.js
CHANGED
package/dist/ui/dot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dot.js","names":[],"sources":["../../src/ui/dot.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { cn } from './lib/utils'\n\n/* ---------------------------------------------------------------------------\n * Dot — a small semantic status/indicator dot. The low-level primitive behind\n * StatusBadge, status/presence/health indicators, legend swatches, Avatar status.\n *\n * Intent-coloured, sized (xs–lg), filled / ring / off, optionally pulsing (with\n * a speed), optionally with a contrast border, and an optional label on either\n * side. Decorative by default (aria-hidden); a `label` (or `aria-label`) makes\n * it an announced status.\n *\n * For a dot/count that overlays a child element (notification badge), use\n * `BadgeIndicator` instead — that's the positioned-overlay pattern.\n *\n * API informed by Mantine `Indicator`, Ant `Badge status`, Chakra `Status`.\n * ------------------------------------------------------------------------ */\n\nexport type DotColor = 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'current'\nexport type DotSize = 'xs' | 'sm' | 'md' | 'lg'\nexport type DotVariant = 'filled' | 'ring' | 'off'\n\nconst FILL: Record<DotColor, string> = {\n accent: 'bg-accent-9',\n success: 'bg-success-9',\n warning: 'bg-warning-9',\n error: 'bg-error-9',\n info: 'bg-info-9',\n neutral: 'bg-neutral-8',\n current: 'bg-current',\n}\n\nconst RING: Record<DotColor, string> = {\n accent: 'border-accent-9',\n success: 'border-success-9',\n warning: 'border-warning-9',\n error: 'border-error-9',\n info: 'border-info-9',\n neutral: 'border-neutral-8',\n current: 'border-current',\n}\n\n// Off — \"exists but inactive\": faint same-tone fill + a light border.\nconst OFF: Record<DotColor, string> = {\n accent: 'border-accent-9/40 bg-accent-9/10',\n success: 'border-success-9/40 bg-success-9/10',\n warning: 'border-warning-9/40 bg-warning-9/10',\n error: 'border-error-9/40 bg-error-9/10',\n info: 'border-info-9/40 bg-info-9/10',\n neutral: 'border-neutral-8/40 bg-neutral-8/10',\n current: 'border-current/40 bg-current/10',\n}\n\nconst TEXT: Record<DotColor, string> = {\n accent: 'text-accent-11',\n success: 'text-success-11',\n warning: 'text-warning-11',\n error: 'text-error-11',\n info: 'text-info-11',\n neutral: 'text-surface-fg-muted',\n current: '',\n}\n\nconst PULSE_SPEED: Record<'slow' | 'normal' | 'fast', string> = {\n slow: '2s',\n normal: '1s',\n fast: '0.6s',\n}\n\nconst dotVariants = cva('relative inline-flex shrink-0 rounded-pill', {\n variants: {\n size: {\n xs: 'h-1 w-1',\n sm: 'h-1.5 w-1.5',\n md: 'h-2 w-2',\n lg: 'h-2.5 w-2.5',\n },\n },\n defaultVariants: { size: 'md' },\n})\n\nconst labelTextSize: Record<DotSize, string> = {\n xs: 'text-ds-xs',\n sm: 'text-ds-xs',\n md: 'text-ds-sm',\n lg: 'text-ds-sm',\n}\n\n/**\n * Props for Dot — a small semantic indicator dot.\n *\n * @example\n * <Dot color=\"success\" /> // bare dot\n * <Dot color=\"error\" pulse pulseSpeed=\"fast\" label=\"Recording\" />\n * <Dot color=\"neutral\" variant=\"off\" label=\"Offline\" /> // inactive\n * <Dot color=\"success\" withBorder /> // contrast ring on busy bg\n */\nexport interface DotProps\n extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'color'>,\n VariantProps<typeof dotVariants> {\n /** Intent colour, or `current` to inherit text colour. @default 'neutral' */\n color?: DotColor\n /** `filled` disc, hollow `ring`, or `off` (faint fill + light border = inactive). @default 'filled' */\n variant?: DotVariant\n /** A contrast ring around the dot so it stays visible on busy/colored backgrounds. @default false */\n withBorder?: boolean\n /** Animate a pulsing ripple (ignored for `off`). @default false */\n pulse?: boolean\n /** Pulse tempo. @default 'normal' */\n pulseSpeed?: 'slow' | 'normal' | 'fast'\n /** Inline label. Makes the dot an announced status. */\n label?: React.ReactNode\n /** Which side the label sits on. @default 'end' */\n labelPosition?: 'start' | 'end'\n labelClassName?: string\n}\n\nconst Dot = React.forwardRef<HTMLSpanElement, DotProps>(\n (\n {\n color = 'neutral',\n size = 'md',\n variant = 'filled',\n withBorder = false,\n pulse = false,\n pulseSpeed = 'normal',\n label,\n labelPosition = 'end',\n labelClassName,\n className,\n 'aria-label': ariaLabel,\n ...props\n },\n ref,\n ) => {\n const resolvedSize = size ?? 'md'\n // A dot with a label (or explicit aria-label) is an announced status;\n // a bare dot is decorative (the surrounding element carries the meaning).\n const isAnnounced = label != null || ariaLabel != null\n // Off dots are inactive — a pulse would contradict that.\n const showPulse = pulse && variant !== 'off'\n\n const disc = cn(\n dotVariants({ size: resolvedSize }),\n variant === 'filled' && FILL[color],\n variant === 'ring' && cn('border-[1.5px] bg-transparent', RING[color]),\n variant === 'off' && cn('border', OFF[color]),\n withBorder && 'ring-2 ring-surface-raised',\n )\n\n const labelEl =\n label != null ? (\n <span className={cn(labelTextSize[resolvedSize], TEXT[color], 'font-sans', labelClassName)}>{label}</span>\n ) : null\n\n return (\n <span\n ref={ref}\n role={isAnnounced ? 'status' : undefined}\n aria-hidden={isAnnounced ? undefined : true}\n aria-label={ariaLabel}\n className={cn('inline-flex items-center gap-ds-02', className)}\n {...props}\n >\n {labelPosition === 'start' && labelEl}\n <span className=\"relative inline-flex shrink-0\">\n {/* Contained opacity breathe on the disc itself — never an expanding halo/ring. */}\n <span\n data-pulse={showPulse ? '' : undefined}\n style={showPulse ? { animationDuration: PULSE_SPEED[pulseSpeed] } : undefined}\n className={cn(disc, showPulse && 'animate-pulse motion-reduce:animate-none')}\n />\n </span>\n {labelPosition === 'end' && labelEl}\n </span>\n )\n },\n)\nDot.displayName = 'Dot'\n\nexport { Dot, dotVariants }\n"],"mappings":";;;;;;AA0BA,IAAM,IAAiC;CACrC,QAAQ;CACR,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;
|
|
1
|
+
{"version":3,"file":"dot.js","names":[],"sources":["../../src/ui/dot.tsx"],"sourcesContent":["'use client'\n\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { cn } from './lib/utils'\n\n/* ---------------------------------------------------------------------------\n * Dot — a small semantic status/indicator dot. The low-level primitive behind\n * StatusBadge, status/presence/health indicators, legend swatches, Avatar status.\n *\n * Intent-coloured, sized (xs–lg), filled / ring / off, optionally pulsing (with\n * a speed), optionally with a contrast border, and an optional label on either\n * side. Decorative by default (aria-hidden); a `label` (or `aria-label`) makes\n * it an announced status.\n *\n * For a dot/count that overlays a child element (notification badge), use\n * `BadgeIndicator` instead — that's the positioned-overlay pattern.\n *\n * API informed by Mantine `Indicator`, Ant `Badge status`, Chakra `Status`.\n * ------------------------------------------------------------------------ */\n\nexport type DotColor = 'accent' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'current'\nexport type DotSize = 'xs' | 'sm' | 'md' | 'lg'\nexport type DotVariant = 'filled' | 'ring' | 'off'\n\nconst FILL: Record<DotColor, string> = {\n accent: 'bg-accent-9',\n success: 'bg-success-9',\n warning: 'bg-warning-9',\n error: 'bg-error-9',\n info: 'bg-info-9',\n neutral: 'bg-neutral-8',\n current: 'bg-current',\n}\n\nconst RING: Record<DotColor, string> = {\n accent: 'border-accent-9',\n success: 'border-success-9',\n warning: 'border-warning-9',\n error: 'border-error-9',\n info: 'border-info-9',\n neutral: 'border-neutral-8',\n current: 'border-current',\n}\n\n// Off — \"exists but inactive\": faint same-tone fill + a light border.\nconst OFF: Record<DotColor, string> = {\n accent: 'border-accent-9/40 bg-accent-9/10',\n success: 'border-success-9/40 bg-success-9/10',\n warning: 'border-warning-9/40 bg-warning-9/10',\n error: 'border-error-9/40 bg-error-9/10',\n info: 'border-info-9/40 bg-info-9/10',\n neutral: 'border-neutral-8/40 bg-neutral-8/10',\n current: 'border-current/40 bg-current/10',\n}\n\nconst TEXT: Record<DotColor, string> = {\n accent: 'text-accent-11',\n success: 'text-success-11',\n warning: 'text-warning-11',\n error: 'text-error-11',\n info: 'text-info-11',\n neutral: 'text-surface-fg-muted',\n current: '',\n}\n\nconst PULSE_SPEED: Record<'slow' | 'normal' | 'fast', string> = {\n slow: '2s',\n normal: '1s',\n fast: '0.6s',\n}\n\nconst dotVariants = cva('relative inline-flex shrink-0 rounded-pill', {\n variants: {\n size: {\n xs: 'h-1 w-1',\n sm: 'h-1.5 w-1.5',\n md: 'h-2 w-2',\n lg: 'h-2.5 w-2.5',\n },\n },\n defaultVariants: { size: 'md' },\n})\n\nconst labelTextSize: Record<DotSize, string> = {\n xs: 'text-ds-xs',\n sm: 'text-ds-xs',\n md: 'text-ds-sm',\n lg: 'text-ds-sm',\n}\n\n/**\n * Props for Dot — a small semantic indicator dot.\n *\n * @example\n * <Dot color=\"success\" /> // bare dot\n * <Dot color=\"error\" pulse pulseSpeed=\"fast\" label=\"Recording\" />\n * <Dot color=\"neutral\" variant=\"off\" label=\"Offline\" /> // inactive\n * <Dot color=\"success\" withBorder /> // contrast ring on busy bg\n */\nexport interface DotProps\n extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'color'>,\n VariantProps<typeof dotVariants> {\n /** Intent colour, or `current` to inherit text colour. @default 'neutral' */\n color?: DotColor\n /** `filled` disc, hollow `ring`, or `off` (faint fill + light border = inactive). @default 'filled' */\n variant?: DotVariant\n /** A contrast ring around the dot so it stays visible on busy/colored backgrounds. @default false */\n withBorder?: boolean\n /** Animate a pulsing ripple (ignored for `off`). @default false */\n pulse?: boolean\n /** Pulse tempo. @default 'normal' */\n pulseSpeed?: 'slow' | 'normal' | 'fast'\n /** Inline label. Makes the dot an announced status. */\n label?: React.ReactNode\n /** Which side the label sits on. @default 'end' */\n labelPosition?: 'start' | 'end'\n labelClassName?: string\n}\n\nconst Dot = React.forwardRef<HTMLSpanElement, DotProps>(\n (\n {\n color = 'neutral',\n size = 'md',\n variant = 'filled',\n withBorder = false,\n pulse = false,\n pulseSpeed = 'normal',\n label,\n labelPosition = 'end',\n labelClassName,\n className,\n 'aria-label': ariaLabel,\n ...props\n },\n ref,\n ) => {\n const resolvedSize = size ?? 'md'\n // A dot with a label (or explicit aria-label) is an announced status;\n // a bare dot is decorative (the surrounding element carries the meaning).\n const isAnnounced = label != null || ariaLabel != null\n // Off dots are inactive — a pulse would contradict that.\n const showPulse = pulse && variant !== 'off'\n\n const disc = cn(\n dotVariants({ size: resolvedSize }),\n variant === 'filled' && FILL[color],\n variant === 'ring' && cn('border-[1.5px] bg-transparent', RING[color]),\n variant === 'off' && cn('border', OFF[color]),\n withBorder && 'ring-2 ring-surface-raised',\n )\n\n const labelEl =\n label != null ? (\n <span className={cn(labelTextSize[resolvedSize], TEXT[color], 'font-sans', labelClassName)}>{label}</span>\n ) : null\n\n return (\n <span\n ref={ref}\n role={isAnnounced ? 'status' : undefined}\n aria-hidden={isAnnounced ? undefined : true}\n aria-label={ariaLabel}\n className={cn('inline-flex items-center gap-ds-02', className)}\n {...props}\n >\n {labelPosition === 'start' && labelEl}\n <span className=\"relative inline-flex shrink-0\">\n {/* Contained opacity breathe on the disc itself — never an expanding halo/ring. */}\n <span\n data-pulse={showPulse ? '' : undefined}\n style={showPulse ? { animationDuration: PULSE_SPEED[pulseSpeed] } : undefined}\n className={cn(disc, showPulse && 'animate-pulse motion-reduce:animate-none')}\n />\n </span>\n {labelPosition === 'end' && labelEl}\n </span>\n )\n },\n)\nDot.displayName = 'Dot'\n\nexport { Dot, dotVariants }\n"],"mappings":";;;;;;AA0BA,IAAM,IAAiC;CACrC,QAAQ;CACR,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;AACX,GAEM,IAAiC;CACrC,QAAQ;CACR,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;AACX,GAGM,IAAgC;CACpC,QAAQ;CACR,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;AACX,GAEM,IAAiC;CACrC,QAAQ;CACR,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;AACX,GAEM,IAA0D;CAC9D,MAAM;CACN,QAAQ;CACR,MAAM;AACR,GAEM,IAAc,EAAI,8CAA8C;CACpE,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN,EACF;CACA,iBAAiB,EAAE,MAAM,KAAK;AAChC,CAAC,GAEK,IAAyC;CAC7C,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,GA+BM,IAAM,EAAM,YAEd,EACE,WAAQ,WACR,UAAO,MACP,aAAU,UACV,gBAAa,IACb,WAAQ,IACR,gBAAa,UACb,UACA,mBAAgB,OAChB,mBACA,cACA,cAAc,GACd,GAAG,KAEL,MACG;CACH,IAAM,IAAe,KAAQ,MAGvB,IAAc,KAAS,QAAQ,KAAa,MAE5C,IAAY,KAAS,MAAY,OAEjC,IAAO,EACX,EAAY,EAAE,MAAM,EAAa,CAAC,GAClC,MAAY,YAAY,EAAK,IAC7B,MAAY,UAAU,EAAG,iCAAiC,EAAK,EAAM,GACrE,MAAY,SAAS,EAAG,UAAU,EAAI,EAAM,GAC5C,KAAc,4BAChB,GAEM,IACJ,KAAS,OAEL,OADF,kBAAC,QAAD;EAAM,WAAW,EAAG,EAAc,IAAe,EAAK,IAAQ,aAAa,CAAc;YAAI;CAAY,CAAA;CAG7G,OACE,kBAAC,QAAD;EACO;EACL,MAAM,IAAc,WAAW,KAAA;EAC/B,eAAa,MAAc,KAAA;EAC3B,cAAY;EACZ,WAAW,EAAG,sCAAsC,CAAS;EAC7D,GAAI;YANN;GAQG,MAAkB,WAAW;GAC9B,kBAAC,QAAD;IAAM,WAAU;cAEd,kBAAC,QAAD;KACE,cAAY,IAAY,KAAK,KAAA;KAC7B,OAAO,IAAY,EAAE,mBAAmB,EAAY,GAAY,IAAI,KAAA;KACpE,WAAW,EAAG,GAAM,KAAa,0CAA0C;IAC5E,CAAA;GACG,CAAA;GACL,MAAkB,SAAS;EACxB;;AAEV,CACF;AACA,EAAI,cAAc"}
|
|
@@ -82,7 +82,7 @@ declare const DropdownMenuLabel: React.ForwardRefExoticComponent<Omit<DropdownMe
|
|
|
82
82
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
83
83
|
declare const DropdownMenuSeparator: React.ForwardRefExoticComponent<Omit<DropdownMenuPrimitive.DropdownMenuSeparatorProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
84
84
|
declare const DropdownMenuShortcut: {
|
|
85
|
-
({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>):
|
|
85
|
+
({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>): React.JSX.Element;
|
|
86
86
|
displayName: string;
|
|
87
87
|
};
|
|
88
88
|
export type DropdownMenuContentProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>;
|