@vielzeug/refine 2.2.5 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/dist/accordion-item.cjs +1 -1
  2. package/dist/accordion-item.cjs.map +1 -1
  3. package/dist/accordion-item.js +1 -1
  4. package/dist/accordion-item.js.map +1 -1
  5. package/dist/card.cjs +1 -1
  6. package/dist/card.cjs.map +1 -1
  7. package/dist/card.js +1 -1
  8. package/dist/card.js.map +1 -1
  9. package/dist/carousel.cjs +1 -1
  10. package/dist/carousel.cjs.map +1 -1
  11. package/dist/carousel.js +1 -1
  12. package/dist/carousel.js.map +1 -1
  13. package/dist/chat-message.cjs +9 -9
  14. package/dist/chat-message.cjs.map +1 -1
  15. package/dist/chat-message.js +41 -38
  16. package/dist/chat-message.js.map +1 -1
  17. package/dist/combobox.cjs +9 -7
  18. package/dist/combobox.cjs.map +1 -1
  19. package/dist/combobox.js +55 -48
  20. package/dist/combobox.js.map +1 -1
  21. package/dist/command-palette.cjs +1 -1
  22. package/dist/command-palette.cjs.map +1 -1
  23. package/dist/command-palette.js +1 -1
  24. package/dist/command-palette.js.map +1 -1
  25. package/dist/content/index.d.ts +2 -0
  26. package/dist/content/index.d.ts.map +1 -1
  27. package/dist/content/list/list-item.css.cjs +1 -1
  28. package/dist/content/list/list-item.css.cjs.map +1 -1
  29. package/dist/content/list/list-item.css.js +1 -1
  30. package/dist/content/list/list-item.css.js.map +1 -1
  31. package/dist/content/list/list-item.d.ts +9 -0
  32. package/dist/content/list/list-item.d.ts.map +1 -1
  33. package/dist/content/stats/stats.css.cjs +2 -0
  34. package/dist/content/stats/stats.css.cjs.map +1 -0
  35. package/dist/content/stats/stats.css.js +6 -0
  36. package/dist/content/stats/stats.css.js.map +1 -0
  37. package/dist/content/stats/stats.d.ts +72 -0
  38. package/dist/content/stats/stats.d.ts.map +1 -0
  39. package/dist/core/announcer.cjs +1 -1
  40. package/dist/core/announcer.cjs.map +1 -1
  41. package/dist/core/announcer.d.ts +13 -3
  42. package/dist/core/announcer.d.ts.map +1 -1
  43. package/dist/core/announcer.js +16 -9
  44. package/dist/core/announcer.js.map +1 -1
  45. package/dist/core/auto-resize.cjs +1 -1
  46. package/dist/core/auto-resize.cjs.map +1 -1
  47. package/dist/core/auto-resize.js +1 -1
  48. package/dist/core/auto-resize.js.map +1 -1
  49. package/dist/custom-elements.json +4457 -4161
  50. package/dist/datagrid.cjs +199 -179
  51. package/dist/datagrid.cjs.map +1 -1
  52. package/dist/datagrid.js +435 -321
  53. package/dist/datagrid.js.map +1 -1
  54. package/dist/disclosure/tab-item/tab-item.css.cjs +1 -1
  55. package/dist/disclosure/tab-item/tab-item.css.cjs.map +1 -1
  56. package/dist/disclosure/tab-item/tab-item.css.js +1 -1
  57. package/dist/disclosure/tab-item/tab-item.css.js.map +1 -1
  58. package/dist/disclosure/tab-item/tab-item.d.ts +3 -0
  59. package/dist/disclosure/tab-item/tab-item.d.ts.map +1 -1
  60. package/dist/disclosure/tabs/tabs.css.cjs +1 -1
  61. package/dist/disclosure/tabs/tabs.css.cjs.map +1 -1
  62. package/dist/disclosure/tabs/tabs.css.js +1 -1
  63. package/dist/disclosure/tabs/tabs.css.js.map +1 -1
  64. package/dist/disclosure/tabs/tabs.d.ts +4 -0
  65. package/dist/disclosure/tabs/tabs.d.ts.map +1 -1
  66. package/dist/feedback/typing-indicator/typing-indicator.d.ts +2 -2
  67. package/dist/file-input.cjs +49 -49
  68. package/dist/file-input.cjs.map +1 -1
  69. package/dist/file-input.js +128 -127
  70. package/dist/file-input.js.map +1 -1
  71. package/dist/frameworks/elements.d.ts +2 -1
  72. package/dist/icon.cjs +1 -1
  73. package/dist/icon.cjs.map +1 -1
  74. package/dist/icon.js +1 -1
  75. package/dist/icon.js.map +1 -1
  76. package/dist/input.cjs +5 -4
  77. package/dist/input.cjs.map +1 -1
  78. package/dist/input.js +14 -8
  79. package/dist/input.js.map +1 -1
  80. package/dist/inputs/combobox/combobox-options.cjs +1 -1
  81. package/dist/inputs/combobox/combobox-options.cjs.map +1 -1
  82. package/dist/inputs/combobox/combobox-options.d.ts.map +1 -1
  83. package/dist/inputs/combobox/combobox-options.js +1 -0
  84. package/dist/inputs/combobox/combobox-options.js.map +1 -1
  85. package/dist/inputs/combobox/combobox.css.cjs +1 -1
  86. package/dist/inputs/combobox/combobox.css.cjs.map +1 -1
  87. package/dist/inputs/combobox/combobox.css.js +1 -1
  88. package/dist/inputs/combobox/combobox.css.js.map +1 -1
  89. package/dist/inputs/combobox/combobox.d.ts +1 -0
  90. package/dist/inputs/combobox/combobox.d.ts.map +1 -1
  91. package/dist/inputs/combobox/combobox.types.d.ts +7 -0
  92. package/dist/inputs/combobox/combobox.types.d.ts.map +1 -1
  93. package/dist/inputs/datagrid/datagrid-model.cjs +1 -1
  94. package/dist/inputs/datagrid/datagrid-model.cjs.map +1 -1
  95. package/dist/inputs/datagrid/datagrid-model.d.ts +17 -3
  96. package/dist/inputs/datagrid/datagrid-model.d.ts.map +1 -1
  97. package/dist/inputs/datagrid/datagrid-model.js +93 -70
  98. package/dist/inputs/datagrid/datagrid-model.js.map +1 -1
  99. package/dist/inputs/datagrid/datagrid.css.cjs +1 -1
  100. package/dist/inputs/datagrid/datagrid.css.cjs.map +1 -1
  101. package/dist/inputs/datagrid/datagrid.css.js +1 -1
  102. package/dist/inputs/datagrid/datagrid.css.js.map +1 -1
  103. package/dist/inputs/datagrid/datagrid.d.ts +54 -4
  104. package/dist/inputs/datagrid/datagrid.d.ts.map +1 -1
  105. package/dist/inputs/file-input/file-input-upload.cjs +1 -1
  106. package/dist/inputs/file-input/file-input-upload.cjs.map +1 -1
  107. package/dist/inputs/file-input/file-input-upload.d.ts +2 -0
  108. package/dist/inputs/file-input/file-input-upload.d.ts.map +1 -1
  109. package/dist/inputs/file-input/file-input-upload.js +5 -2
  110. package/dist/inputs/file-input/file-input-upload.js.map +1 -1
  111. package/dist/inputs/file-input/file-input.d.ts.map +1 -1
  112. package/dist/inputs/index.d.ts +1 -1
  113. package/dist/inputs/index.d.ts.map +1 -1
  114. package/dist/inputs/input/input.css.cjs +1 -1
  115. package/dist/inputs/input/input.css.cjs.map +1 -1
  116. package/dist/inputs/input/input.css.js +1 -1
  117. package/dist/inputs/input/input.css.js.map +1 -1
  118. package/dist/inputs/input/input.d.ts +3 -0
  119. package/dist/inputs/input/input.d.ts.map +1 -1
  120. package/dist/inputs/select/select.css.cjs +1 -1
  121. package/dist/inputs/select/select.css.cjs.map +1 -1
  122. package/dist/inputs/select/select.css.js +1 -1
  123. package/dist/inputs/select/select.css.js.map +1 -1
  124. package/dist/inputs/select/select.d.ts +5 -0
  125. package/dist/inputs/select/select.d.ts.map +1 -1
  126. package/dist/layout/navbar/navbar.d.ts +2 -0
  127. package/dist/layout/navbar/navbar.d.ts.map +1 -1
  128. package/dist/layout/sidebar/sidebar.css.cjs +1 -1
  129. package/dist/layout/sidebar/sidebar.css.cjs.map +1 -1
  130. package/dist/layout/sidebar/sidebar.css.js +1 -1
  131. package/dist/layout/sidebar/sidebar.css.js.map +1 -1
  132. package/dist/layout/sidebar/sidebar.d.ts +8 -0
  133. package/dist/layout/sidebar/sidebar.d.ts.map +1 -1
  134. package/dist/list-item.cjs +6 -5
  135. package/dist/list-item.cjs.map +1 -1
  136. package/dist/list-item.js +23 -17
  137. package/dist/list-item.js.map +1 -1
  138. package/dist/list.cjs +1 -1
  139. package/dist/list.cjs.map +1 -1
  140. package/dist/list.js +1 -1
  141. package/dist/list.js.map +1 -1
  142. package/dist/menu.cjs +1 -1
  143. package/dist/menu.cjs.map +1 -1
  144. package/dist/menu.js +1 -1
  145. package/dist/menu.js.map +1 -1
  146. package/dist/navbar.cjs +2 -2
  147. package/dist/navbar.cjs.map +1 -1
  148. package/dist/navbar.js +7 -5
  149. package/dist/navbar.js.map +1 -1
  150. package/dist/navigation-menu.cjs +1 -1
  151. package/dist/navigation-menu.cjs.map +1 -1
  152. package/dist/navigation-menu.js +1 -1
  153. package/dist/navigation-menu.js.map +1 -1
  154. package/dist/overlay/popover/popover.css.cjs +1 -1
  155. package/dist/overlay/popover/popover.css.cjs.map +1 -1
  156. package/dist/overlay/popover/popover.css.js +1 -1
  157. package/dist/overlay/popover/popover.css.js.map +1 -1
  158. package/dist/overlay/popover/popover.d.ts +1 -0
  159. package/dist/overlay/popover/popover.d.ts.map +1 -1
  160. package/dist/overlay/shared/use-dialog.cjs +1 -1
  161. package/dist/overlay/shared/use-dialog.cjs.map +1 -1
  162. package/dist/overlay/shared/use-dialog.js +1 -1
  163. package/dist/overlay/shared/use-dialog.js.map +1 -1
  164. package/dist/overlay/shared/use-floating-trigger.cjs +1 -1
  165. package/dist/overlay/shared/use-floating-trigger.cjs.map +1 -1
  166. package/dist/overlay/shared/use-floating-trigger.js +1 -1
  167. package/dist/overlay/shared/use-floating-trigger.js.map +1 -1
  168. package/dist/popover.cjs.map +1 -1
  169. package/dist/popover.js.map +1 -1
  170. package/dist/radio.cjs +1 -1
  171. package/dist/radio.cjs.map +1 -1
  172. package/dist/radio.js +10 -8
  173. package/dist/radio.js.map +1 -1
  174. package/dist/rating.cjs +1 -1
  175. package/dist/rating.cjs.map +1 -1
  176. package/dist/rating.js +1 -1
  177. package/dist/rating.js.map +1 -1
  178. package/dist/refine.cjs +428 -379
  179. package/dist/refine.cjs.map +1 -1
  180. package/dist/refine.iife.js +428 -379
  181. package/dist/refine.iife.js.map +1 -1
  182. package/dist/refine.js +458 -409
  183. package/dist/refine.js.map +1 -1
  184. package/dist/select.cjs +16 -14
  185. package/dist/select.cjs.map +1 -1
  186. package/dist/select.js +118 -112
  187. package/dist/select.js.map +1 -1
  188. package/dist/sidebar.cjs +28 -23
  189. package/dist/sidebar.cjs.map +1 -1
  190. package/dist/sidebar.js +112 -77
  191. package/dist/sidebar.js.map +1 -1
  192. package/dist/slider.cjs +1 -1
  193. package/dist/slider.cjs.map +1 -1
  194. package/dist/slider.js +1 -1
  195. package/dist/slider.js.map +1 -1
  196. package/dist/stats.cjs +18 -0
  197. package/dist/stats.cjs.map +1 -0
  198. package/dist/stats.js +88 -0
  199. package/dist/stats.js.map +1 -0
  200. package/dist/stepper.cjs +1 -1
  201. package/dist/stepper.cjs.map +1 -1
  202. package/dist/stepper.js +1 -1
  203. package/dist/stepper.js.map +1 -1
  204. package/dist/styles/mixins/animation.css.cjs +2 -0
  205. package/dist/styles/mixins/animation.css.cjs.map +1 -1
  206. package/dist/styles/mixins/animation.css.d.ts.map +1 -1
  207. package/dist/styles/mixins/animation.css.js +2 -0
  208. package/dist/styles/mixins/animation.css.js.map +1 -1
  209. package/dist/tab-item.cjs +1 -1
  210. package/dist/tab-item.cjs.map +1 -1
  211. package/dist/tab-item.js +3 -2
  212. package/dist/tab-item.js.map +1 -1
  213. package/dist/tabs.cjs +1 -1
  214. package/dist/tabs.cjs.map +1 -1
  215. package/dist/tabs.js +3 -1
  216. package/dist/tabs.js.map +1 -1
  217. package/dist/toast.cjs.map +1 -1
  218. package/dist/toast.js.map +1 -1
  219. package/dist/typing-indicator.cjs +1 -1
  220. package/dist/typing-indicator.cjs.map +1 -1
  221. package/dist/typing-indicator.js +8 -7
  222. package/dist/typing-indicator.js.map +1 -1
  223. package/package.json +66 -58
@@ -1 +1 @@
1
- {"version":3,"file":"datagrid.js","names":[],"sources":["../src/inputs/datagrid/datagrid.ts"],"sourcesContent":["import { debounce } from '@vielzeug/arsenal/function';\nimport { define, getHost, html, onCleanup, onMounted, prop, unsafeHtml, useEmit, useSlots } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport { warn } from '../../_dev';\nimport '../../content/icon/icon';\nimport '../../inputs/button/button';\nimport '../../inputs/checkbox/checkbox';\nimport '../../inputs/combobox/combobox';\nimport '../../inputs/select/select';\nimport '../../overlay/popover/popover';\nimport { disablableBundle, loadableBundle } from '../../shared';\nimport { tableBaseMixin } from '../../styles';\nimport componentStyles from './datagrid.css?inline';\nimport { COLUMN_OBSERVED_ATTRS, parseColumnChildren } from './datagrid-column';\nimport {\n createDataGridModel,\n type DataGridColumn,\n type DataGridModel,\n type DataGridView,\n type FilterOperator,\n type FilterOption,\n type SelectionMode,\n type SortDirection,\n type SortState,\n} from './datagrid-model';\nimport { createGridNav, type GridNavHandle } from './datagrid-nav';\n\ntype SortMode = 'client' | 'server';\n\nexport { COLUMN_TAG } from './datagrid-column';\nexport type { DataGridView, FilterOperator, FilterOption } from './datagrid-model';\n\n// ── Pure module-level helpers ─────────────────────────────────────────────────\n\n/**\n * Returns the Lucide icon name for a column's sort state.\n * Pure function — no closure dependency on the grid model.\n */\nexport function sortIconName(state: SortState, key: string): string {\n if (state.key !== key || state.direction === 'none') return 'chevrons-up-down';\n\n return state.direction === 'asc' ? 'chevron-up' : 'chevron-down';\n}\n\n/**\n * Returns the WAI-ARIA `aria-sort` value for a column.\n * Pure function — independently unit-testable.\n */\nexport function ariaSortValue(state: SortState, key: string): 'ascending' | 'descending' | 'none' {\n if (state.key !== key || state.direction === 'none') return 'none';\n\n return state.direction === 'asc' ? 'ascending' : 'descending';\n}\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\nexport type OreDataGridEvents<T = Record<string, unknown>> = {\n /** Fired when the user cycles the density via the toolbar button. */\n 'density-change': { density: 'compact' | 'cozy' | 'comfortable' };\n /** Fired when the active page changes. */\n 'page-change': { pageIndex: number; pageSize: number };\n /** Fired when a row is expanded or collapsed. */\n 'row-expand': { expanded: boolean; key: string };\n /** Fired when row selection changes. */\n 'selection-change': { keys: string[]; rows: T[] };\n /** Fired when the sort column or direction changes. */\n 'sort-change': { direction: SortDirection; key: string };\n /** Fired when the active view tab changes. detail: { id, label } */\n 'view-change': { id: string; label: string };\n};\n\nexport type OreDataGridProps<T = Record<string, unknown>> = {\n /**\n * The ID of the currently active view. Must match an `id` in `views`.\n * When omitted, no view is active (all data shown).\n * @example `grid.activeView = 'open'`\n */\n activeView?: string;\n /**\n * Column definitions (imperative API). Takes precedence over `<ore-column>` children.\n * Passing `[]` explicitly clears declarative children.\n * Pass `undefined` (or omit) to use `<ore-column>` children instead.\n * @example\n * ```js\n * grid.columns = [\n * { key: 'name', label: 'Name', sortable: true },\n * { key: 'email', label: 'Email' },\n * ];\n * ```\n */\n columns?: DataGridColumn<T>[];\n /** Cell density: `'compact'` | `'cozy'` (default) | `'comfortable'` */\n density?: 'compact' | 'cozy' | 'comfortable';\n /** Disable all interaction. */\n disabled?: boolean;\n /** Text shown when there are no rows. */\n emptyText?: string;\n /**\n * Enable row expansion. When set, each row gets a toggle button.\n * Requires at least one column to have a `renderExpanded` function.\n *\n * @security The `renderExpanded` callback's returned HTML string is inserted through\n * Ore's `unsafeHtml()` directive. If data originates from untrusted user input, sanitize\n * it before returning (for example, with DOMPurify or your CSP-compliant sanitizer).\n */\n expandable?: boolean;\n /**\n * Pre-defined filter option definitions per column key.\n * When provided, these options replace the auto-derived ones in the Filter popover.\n * @example\n * ```js\n * grid.filterOptions = [\n * { key: 'role', label: 'Role', options: [{ value: 'Admin' }, { value: 'Editor' }] },\n * ];\n * ```\n */\n filterOptions?: FilterOption[];\n /** Stretch the grid to fill its container's width. */\n fullwidth?: boolean;\n /**\n * Function that returns a unique string key per row.\n * Defaults to `(row) => String(row['id'])`.\n */\n getRowKey?: (row: T) => string;\n /** Accessible label for the grid. Recommended for screen readers. */\n label?: string;\n /** Show a busy/loading state with reduced opacity. */\n loading?: boolean;\n /** Number of rows per page. Defaults to `10`. Set to `0` to disable pagination. */\n pageSize?: number;\n /**\n * Options for the per-page size selector rendered in the footer.\n * When provided, a `ore-select` is shown next to the pagination controls.\n * @example `grid.pageSizeOptions = [10, 25, 50, 100]`\n */\n pageSizeOptions?: number[];\n /**\n * Row data. Pass as a JS property — not serialisable to an HTML attribute.\n * @example\n * ```js\n * grid.rows = [{ id: '1', name: 'Alice', email: 'alice@example.com' }];\n * ```\n */\n rows?: T[];\n /**\n * Accessible label for the search toggle button. Supports localization.\n * Defaults to `'Search'` (open) and `'Close search'` (close).\n * Pass a tuple `[openLabel, closeLabel]` to override both.\n * @example `grid.searchLabel = ['Suchen', 'Suche schließen']`\n */\n searchLabel?: [open: string, close: string];\n /** Placeholder text for the inline search input in the controls bar. */\n searchPlaceholder?: string;\n /**\n * Pre-selected row keys. Setting this from outside will update the internal selection.\n * @example `grid.selectedKeys = ['1', '3']`\n */\n selectedKeys?: string[];\n /** Row selection mode. */\n selectionMode?: SelectionMode;\n /**\n * Whether sorting is client-side (default) or server-side.\n * When `'server'`, `sort-change` fires but items are not sorted by the control.\n */\n sortMode?: SortMode;\n /**\n * A reactive data source from `@vielzeug/sourcerer` (or any compatible object).\n * When set, the source drives row data, pagination, and search — the `rows` prop is ignored.\n * Client-side sort and filter are bypassed; wire `sort-change` to `source.setQuery()` externally.\n * @example\n * ```js\n * import { createPageSource } from '@vielzeug/sourcerer';\n * const source = createPageSource({ load: ({ query, signal }) => api.users(query, { signal }) });\n * grid.source = source;\n * ```\n */\n source?: DataGridSource<T>;\n /** Apply alternating row backgrounds. */\n striped?: boolean;\n /**\n * Named view definitions for the controls bar tab strip.\n * Each view is a label displayed as a tab; switching tabs fires `view-change`.\n * The consumer is responsible for restoring filter/sort state per view.\n * @example\n * ```js\n * grid.views = [\n * { id: 'all', label: 'All' },\n * { id: 'open', label: 'Open' },\n * { id: 'mine', label: 'Mine' },\n * ];\n * grid.activeView = 'all';\n * ```\n */\n views?: DataGridView[];\n};\n\n/**\n * An accessible, keyboard-navigable data grid with sorting, pagination,\n * single/multi row selection, inline search, filter, and named views.\n *\n * @element ore-datagrid\n * @element ore-column - Optional declarative column definition child\n *\n * @attr {boolean} disabled - Disable all interaction\n * @attr {boolean} loading - Show busy/loading state\n * @attr {boolean} striped - Apply alternating row backgrounds\n * @attr {boolean} fullwidth - Stretch the grid to fill its container's width\n * @attr {data} search-label - Tuple [openLabel, closeLabel] for the search toggle button\n * @attr {string} search-placeholder - Placeholder for the inline search input\n * @attr {number} page-size - Rows per page (0 = no pagination, default 10)\n * @attr {string} selection-mode - Row selection: 'none' | 'single' | 'multi'\n * @attr {string} sort-mode - Sorting: 'client' (default) | 'server'\n * @attr {string} density - Cell density: compact | cozy (default) | comfortable\n * @attr {string} empty-text - Text shown when there are no rows\n * @attr {string} label - Accessible label for the grid\n * @attr {string} active-view - ID of the currently active view tab\n *\n * @fires selection-change - Fired when row selection changes. detail: { keys: string[], rows: T[] }\n * @fires sort-change - Fired when sort state changes. detail: { key: string, direction: SortDirection }\n * @fires page-change - Fired when page changes. detail: { pageIndex: number, pageSize: number }\n * @fires row-expand - Fired when a row is expanded or collapsed. detail: { expanded: boolean; key: string }\n * @fires view-change - Fired when the active view tab changes. detail: { id: string, label: string }\n *\n * @cssprop --datagrid-bg - Grid background color\n * @cssprop --datagrid-border-color - Grid and cell border color\n * @cssprop --datagrid-radius - Grid border radius\n * @cssprop --datagrid-shadow - Grid box shadow\n * @cssprop --datagrid-header-bg - Column header background\n * @cssprop --datagrid-row-hover-bg - Row hover background\n * @cssprop --datagrid-row-selected-bg - Selected row background\n * @cssprop --datagrid-stripe-bg - Even-row stripe background\n * @cssprop --datagrid-cell-padding-x - Cell horizontal padding\n * @cssprop --datagrid-cell-padding-y - Cell vertical padding\n * @cssprop --datagrid-cell-max-width - Maximum cell content width before truncating\n * @cssprop --datagrid-max-height - Max scrollable height of the table area\n * @cssprop --datagrid-font-size - Base font size for cells\n *\n * @part controls - The controls bar (tabs + action row)\n * @part table - The `<table>` element\n * @part thead - The `<thead>` element\n * @part tbody - The `<tbody>` element\n * @part row - A body `<tr>` element\n * @part cell - A body `<td>` element\n * @part footer - The pagination footer bar\n *\n * @example\n * ```html\n * <ore-datagrid id=\"grid\" label=\"Users\" selection-mode=\"multi\"></ore-datagrid>\n * <script>\n * const grid = document.getElementById('grid');\n * grid.columns = [\n * { key: 'name', label: 'Name', sortable: true },\n * { key: 'role', label: 'Role' },\n * ];\n * grid.rows = [\n * { id: '1', name: 'Alice', role: 'Admin' },\n * { id: '2', name: 'Bob', role: 'Viewer' },\n * ];\n * grid.views = [{ id: 'all', label: 'All' }, { id: 'open', label: 'Open' }];\n * grid.activeView = 'all';\n * </script>\n * ```\n */\n/**\n * Minimal structural interface for a reactive data source accepted by `ore-datagrid`.\n *\n * Any page-shaped `@vielzeug/sourcerer` source satisfies this interface automatically — no direct\n * sourcerer import is required in refine.\n *\n * When `source` is set on the grid:\n * - `rows` prop is ignored; `source.snapshot.data` drives displayed items.\n * - Pagination reads `source.snapshot.pagination`.\n * - Prev/next buttons call `source.page.previous()` / `source.page.next()`.\n * - Search calls `source.setQuery({ search })`.\n * - `source.snapshot.isFetching` contributes to the grid's `aria-busy` state.\n * - Client-side sort and filter are bypassed; wire `sort-change` to `source.setQuery()` externally.\n *\n * @example\n * ```ts\n * import { createPageSource } from '@vielzeug/sourcerer';\n *\n * const source = createPageSource({\n * load: ({ query, signal }) =>\n * fetch(`/api/users?page=${query.page}&limit=${query.pageSize}&search=${query.search}`, { signal })\n * .then(r => r.json()),\n * });\n *\n * const grid = document.querySelector('ore-datagrid');\n * grid.source = source;\n * ```\n */\nexport type DataGridSource<T = Record<string, unknown>> = {\n readonly page?: {\n next(): Promise<void> | void;\n previous(): Promise<void> | void;\n };\n setQuery?(changes: { search?: string }): Promise<void> | void;\n readonly snapshot: {\n readonly data: readonly T[];\n readonly error: { message: string } | null;\n readonly isFetching: boolean;\n readonly pagination: {\n readonly count: number;\n readonly hasNext: boolean;\n readonly hasPrevious: boolean;\n readonly index: number;\n readonly kind: 'page';\n readonly size: number;\n readonly total: number;\n };\n readonly query: { readonly search?: string };\n };\n subscribe(listener: (snapshot: DataGridSource<T>['snapshot']) => void): () => void;\n};\n\nexport const DATAGRID_TAG = 'ore-datagrid' as const;\n\ndefine<OreDataGridProps>(DATAGRID_TAG, {\n props: {\n activeView: prop.string(),\n density: prop.string<'compact' | 'cozy' | 'comfortable'>(),\n ...disablableBundle,\n ...loadableBundle,\n columns: prop.data<DataGridColumn[]>(),\n emptyText: prop.string('No data'),\n expandable: prop.bool(false),\n filterOptions: prop.data<FilterOption[]>(),\n fullwidth: prop.bool(false),\n getRowKey: prop.data<(row: Record<string, unknown>) => string>(),\n label: prop.string(),\n pageSize: prop.number(10),\n pageSizeOptions: prop.data<number[]>(),\n rows: prop.data<Record<string, unknown>[]>(),\n searchLabel: prop.data<[string, string]>(),\n searchPlaceholder: prop.string('Search…'),\n selectedKeys: prop.data<string[]>(),\n selectionMode: prop.string<SelectionMode>('none'),\n sortMode: prop.string<SortMode>('client'),\n source: prop.data<DataGridSource>(),\n striped: prop.bool(false),\n views: prop.data<DataGridView[]>(),\n },\n\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreDataGridEvents>();\n const slots = useSlots();\n\n const isDisabled = computed(() => props.disabled.value === true);\n const selectionMode = computed(() => props.selectionMode.value ?? 'none');\n\n // ── Row expansion (hoisted — needed by checkOffset + effectiveColCount) ──\n const expandedKeys = signal(new Set<string>());\n\n // resolvedColumns is declared further below; this callback is lazy and only\n // evaluates when .value is first read (after setup completes), so the\n // forward closure reference is safe at runtime.\n const hasExpander = computed(\n () =>\n props.expandable.value === true && resolvedColumns.value.some((c) => typeof c.renderExpanded === 'function'),\n );\n\n const checkOffset = computed(() => (selectionMode.value === 'multi' ? 1 : 0));\n\n // ── Page size ────────────────────────────────────────────────────────\n // Signal driven by the `page-size` prop. Stays in sync with prop changes\n // so consumers can set grid.pageSize = n reactively after mount.\n // The per-page size selector also writes to this signal directly.\n const pageSize = signal<number>(props.pageSize.value ?? 10);\n\n watch(props.pageSize, (n) => {\n if (n != null) pageSize.value = n;\n });\n\n // ── Declarative ore-column children ─────────────────────────────────────\n // A writable signal holding columns parsed from <ore-column> children.\n // Updated on mount and whenever children change. The JS `columns` prop\n // takes precedence when explicitly set (non-empty).\n const declarativeColumns = signal<DataGridColumn[]>([]);\n\n onMounted(() => {\n declarativeColumns.value = parseColumnChildren(el);\n\n const columnObserver = new MutationObserver(() => {\n declarativeColumns.value = parseColumnChildren(el);\n });\n\n columnObserver.observe(el, {\n attributeFilter: COLUMN_OBSERVED_ATTRS as unknown as string[],\n attributes: true,\n childList: true,\n subtree: true,\n });\n\n return () => columnObserver.disconnect();\n });\n\n // Resolved columns: prop wins when explicitly set (even to []); undefined = not set → use declarative children.\n const resolvedColumns = computed<DataGridColumn[]>(() => {\n const propCols = props.columns.value;\n\n return propCols !== undefined ? propCols : declarativeColumns.value;\n });\n\n // ── Key resolution ─────────────────────────────────────────────────────────\n // Reads getRowKey prop dynamically so changes after mount are reflected.\n\n const resolveKey = (item: Record<string, unknown>): string => {\n const fn = props.getRowKey.value;\n\n if (fn) return fn(item);\n\n const id = item.id;\n\n if (id == null) {\n warn('ore-datagrid: row missing `id` — keys will collide. Provide `getRowKey` or add a unique `id` field.');\n\n return `__missing_${Math.random().toString(36).slice(2)}`;\n }\n\n return String(id);\n };\n\n // ── Reactive source bridge ────────────────────────────────────────────────\n // When `source` is provided it drives rows, pagination, and search.\n // The `rows` prop and client-side filter pipeline are bypassed.\n\n type SourceMetaState = {\n error: { message: string } | null;\n isLoading: boolean;\n pageCount: number;\n pageNumber: number;\n pageSize: number;\n totalItems: number;\n };\n\n const hasSource = computed(() => props.source.value != null);\n const sourceItems = signal<Record<string, unknown>[]>([]);\n const sourceMeta = signal<SourceMetaState>({\n error: null,\n isLoading: false,\n pageCount: 1,\n pageNumber: 1,\n pageSize: pageSize.value,\n totalItems: 0,\n });\n\n let _sourceUnsub: (() => void) | null = null;\n\n onCleanup(() => {\n _sourceUnsub?.();\n _sourceUnsub = null;\n });\n\n watch(\n props.source,\n (src) => {\n _sourceUnsub?.();\n _sourceUnsub = null;\n\n if (!src) {\n sourceItems.value = [];\n sourceMeta.value = {\n error: null,\n isLoading: false,\n pageCount: 1,\n pageNumber: 1,\n pageSize: pageSize.value,\n totalItems: 0,\n };\n\n return;\n }\n\n const update = (snapshot: DataGridSource['snapshot'] = src.snapshot): void => {\n sourceItems.value = snapshot.data as Record<string, unknown>[];\n sourceMeta.value = {\n error: snapshot.error,\n isLoading: snapshot.isFetching,\n pageCount: snapshot.pagination.count,\n pageNumber: snapshot.pagination.index,\n pageSize: snapshot.pagination.size,\n totalItems: snapshot.pagination.total,\n };\n };\n\n update();\n _sourceUnsub = src.subscribe(update);\n },\n { immediate: true },\n );\n\n // ── Feature model ─────────────────────────────────────────────────────────\n // One model owns every client-side grid transform and interaction state.\n // Source-backed grids retain source-owned filtering, sorting, and pagination.\n\n const model: DataGridModel = createDataGridModel({\n clientSide: computed(() => !hasSource.value),\n columns: resolvedColumns,\n filterOptions: props.filterOptions,\n getRowKey: resolveKey,\n items: computed<Record<string, unknown>[]>(() =>\n hasSource.value ? sourceItems.value : (props.rows.value ?? []),\n ),\n onSelectionChange: (keys) => {\n emit('selection-change', { keys: [...keys], rows: model.selectedRows.value });\n },\n onSortChange: (sort) => {\n emit('sort-change', sort);\n },\n pageSize: computed(() => (hasSource.value ? 0 : pageSize.value)),\n selectionMode,\n sortMode: computed(() => props.sortMode.value ?? 'client'),\n });\n\n const debouncedSearch = debounce((query: unknown) => {\n const source = props.source.value;\n\n if (source?.setQuery) void source.setQuery({ search: query as string });\n else model.setSearchQuery(query as string);\n }, 250);\n\n // ── Sync external selected-keys prop into the feature model ───────────────\n\n watch(\n props.selectedKeys,\n (keys) => {\n if (Array.isArray(keys)) model.setSelection(new Set(keys));\n },\n { immediate: true },\n );\n\n // ── Column resize (F4) ───────────────────────────────────────────────────\n // Stores user-dragged widths as { key → px } so they survive re-renders.\n // Only columns with `resizable: true` get a drag handle.\n\n const colWidths = signal<Record<string, number>>({});\n\n const createColResizeHandler =\n (key: string, th: HTMLElement): ((e: PointerEvent) => void) =>\n (e: PointerEvent): void => {\n e.preventDefault();\n\n const startX = e.clientX;\n const startW = th.getBoundingClientRect().width;\n // AbortController ensures listeners are removed even if the component\n // is destroyed mid-drag (e.g. during SPA navigation).\n const ac = new AbortController();\n const { signal: sig } = ac;\n\n window.addEventListener(\n 'pointermove',\n (mv: PointerEvent) => {\n colWidths.value = { ...colWidths.value, [key]: Math.max(40, startW + mv.clientX - startX) };\n },\n { signal: sig },\n );\n\n window.addEventListener('pointerup', () => ac.abort(), { signal: sig });\n };\n\n // ── Visible columns (respects hide/show from column menu) ────────────────\n\n const visibleColumns = model.visibleColumns;\n\n // ── Cell value helper ────────────────────────────────────────────────────\n\n const getCellValue = (col: DataGridColumn, item: Record<string, unknown>): string => {\n if (col.cell) return col.cell(item);\n\n const v = item[col.key];\n\n return v == null ? '' : String(v);\n };\n\n // ── Pagination handlers ───────────────────────────────────────────────────\n\n function handlePage(direction: 'next' | 'prev'): void {\n const src = props.source.value;\n\n if (src) {\n if (direction === 'prev') void src.page?.previous();\n else void src.page?.next();\n\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n direction === 'prev' ? model.prevPage() : model.nextPage();\n emit('page-change', { pageIndex: model.pageIndex.value, pageSize: pageSize.value });\n }\n\n // ── Select-all helpers ────────────────────────────────\n\n const isSomeSelected = computed(() => {\n const page = model.currentPageItems.value;\n\n if (!page.length || model.isAllSelected()) return false;\n\n return page.some((item) => model.selectedKeys.value.has(resolveKey(item as Record<string, unknown>)));\n });\n\n // ── Column count (used in keyboard nav + empty colspan) ───────────────────\n\n const effectiveColCount = computed(\n () => visibleColumns.value.length + (selectionMode.value === 'multi' ? 1 : 0) + (hasExpander.value ? 1 : 0),\n );\n\n // ── Pagination info text ──────────────────────────────────────────────────\n\n const paginationEnabled = computed(() => {\n if (hasSource.value) return sourceMeta.value.pageCount > 1;\n\n return pageSize.value > 0;\n });\n\n const paginationInfo = computed(() => {\n if (hasSource.value) {\n const { pageNumber, pageSize: pSize, totalItems } = sourceMeta.value;\n const safePSize = Math.max(1, pSize);\n\n if (!paginationEnabled.value) return `${totalItems} row${totalItems !== 1 ? 's' : ''}`;\n\n if (totalItems === 0) return '0 to 0 of 0';\n\n const start = (pageNumber - 1) * safePSize + 1;\n const end = Math.min(start + safePSize - 1, totalItems);\n\n return `${start} to ${end} of ${totalItems}`;\n }\n\n const total = model.totalItems.value;\n\n if (!paginationEnabled.value) return `${total} row${total !== 1 ? 's' : ''}`;\n\n if (total === 0) return '0 to 0 of 0';\n\n const start = model.pageIndex.value * pageSize.value + 1;\n const end = Math.min(start + pageSize.value - 1, total);\n\n return `${start} to ${end} of ${total}`;\n });\n\n // ── Source-aware loading and pagination helpers ───────────────────────────\n\n const isLoading = computed(() => props.loading.value === true || (hasSource.value && sourceMeta.value.isLoading));\n\n const effectiveHasPrev = computed(() =>\n hasSource.value ? sourceMeta.value.pageNumber > 1 : model.hasPrevPage.value,\n );\n\n const effectiveHasNext = computed(() =>\n hasSource.value ? sourceMeta.value.pageNumber < sourceMeta.value.pageCount : model.hasNextPage.value,\n );\n\n const effectivePageLabel = computed(() => {\n if (hasSource.value) {\n return sourceMeta.value.totalItems === 0\n ? '0 / 0'\n : `${sourceMeta.value.pageNumber} / ${sourceMeta.value.pageCount}`;\n }\n\n return `${model.pageIndex.value + 1} / ${model.pageCount.value}`;\n });\n\n // ── Density toggle (E5) ──────────────────────────────────────────────────\n // Local signal so the toolbar button can cycle density without requiring\n // the consumer to wire up an external prop. Stays in sync with the `density`\n // prop: prop changes win; button clicks write back to the host attribute so\n // the CSS layer picks them up immediately.\n\n type Density = 'compact' | 'cozy' | 'comfortable';\n\n const DENSITY_CYCLE: Density[] = ['compact', 'cozy', 'comfortable'];\n const DENSITY_ICONS: Record<Density, string> = {\n comfortable: 'rows-2',\n compact: 'rows-4',\n cozy: 'rows-3',\n };\n const DENSITY_LABELS: Record<Density, string> = {\n comfortable: 'Density: Comfortable',\n compact: 'Density: Compact',\n cozy: 'Density: Cozy',\n };\n\n const densitySignal = signal<Density>(props.density.value ?? 'cozy');\n\n watch(props.density, (d) => {\n if (d) densitySignal.value = d;\n });\n\n const cycleDensity = (): void => {\n const idx = DENSITY_CYCLE.indexOf(densitySignal.value);\n const next = DENSITY_CYCLE[(idx + 1) % DENSITY_CYCLE.length]!;\n\n densitySignal.value = next;\n el.setAttribute('density', next);\n emit('density-change', { density: next });\n };\n\n // ── Filter badge hover state ────────────────────────────────────────────\n // Drives the dot↔count toggle on the filter toolbar badge: dot at rest,\n // count on hover/focus so the number is revealed on interaction only.\n const filterBadgeActive = signal(false);\n\n // ── Row expansion (toggle handler) ───────────────────────────────────────\n\n const toggleExpand = (key: string): void => {\n const next = new Set(expandedKeys.value);\n const expanded = !next.has(key);\n\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n expanded ? next.add(key) : next.delete(key);\n expandedKeys.value = next;\n emit('row-expand', { expanded, key });\n };\n\n // ── Keyboard cell navigation (roving tabindex — extracted to datagrid-nav.ts) ──\n // navHandle is initialised with a real sentinel signal so the first render\n // produces correct tabindex values (row=0, col=0 → '0') before onMounted.\n // onMounted replaces it with the live handle from createGridNav.\n\n let navHandle: GridNavHandle = {\n activeCell: signal({ col: 0, row: 0 }),\n focusCell: () => {},\n };\n\n onMounted(() => {\n const shadow = el.shadowRoot!;\n const table = shadow.querySelector<HTMLElement>('.dg-table');\n\n if (!table) return;\n\n const { cleanup, handle } = createGridNav(table, shadow);\n\n navHandle = handle;\n\n return cleanup;\n });\n\n // Expose programmatic focusCell API on the host element (F6)\n (el as HTMLElement & { focusCell: (pos: { col: number; row: number }) => void }).focusCell = (pos) =>\n navHandle.focusCell(pos);\n\n // ── Render helpers ────────────────────────────────────────────────────────\n // Each helper renders one self-contained region, closing only over the\n // signals it actually needs. This keeps the root template readable.\n\n const renderViewTabs = (): unknown => {\n const views = props.views.value ?? [];\n const activeId = props.activeView.value;\n\n return html`\n <div\n class=\"dg-tabs\"\n role=\"tablist\"\n aria-label=\"Views\"\n aria-controls=\"dg-tabpanel\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(e.key)) return;\n\n const tabs = Array.from((e.currentTarget as HTMLElement).querySelectorAll('.dg-tab'));\n const activeIdx = tabs.findIndex((t) => t.classList.contains('dg-tab--active'));\n\n let nextIdx = activeIdx;\n\n if (e.key === 'ArrowLeft') nextIdx = Math.max(0, activeIdx - 1);\n else if (e.key === 'ArrowRight') nextIdx = Math.min(tabs.length - 1, activeIdx + 1);\n else if (e.key === 'Home') nextIdx = 0;\n else if (e.key === 'End') nextIdx = tabs.length - 1;\n\n if (nextIdx !== activeIdx) {\n e.preventDefault();\n\n const nextTab = tabs[nextIdx] as HTMLElement;\n\n nextTab.focus();\n nextTab.click();\n }\n }}\">\n ${views.map(\n (view) => html`\n <ore-button\n class=\"${() => `dg-tab${activeId === view.id ? ' dg-tab--active' : ''}`}\"\n role=\"tab\"\n variant=\"ghost\"\n rounded=\"full\"\n size=\"sm\"\n tabindex=\"${() => (activeId === view.id ? '0' : '-1')}\"\n aria-selected=\"${() => String(activeId === view.id)}\"\n aria-controls=\"dg-tabpanel\"\n @click=\"${() => {\n emit('view-change', { id: view.id, label: view.label });\n }}\">\n ${view.label}\n </ore-button>\n `,\n )}\n </div>\n `;\n };\n\n const renderSortPopover = (): unknown => html`\n <ore-popover class=\"dg-action-popover\" placement=\"bottom-end\" label=\"Sort\" style=\"--popover-min-width:18rem\">\n <ore-button variant=\"ghost\" size=\"sm\" icon-only label=\"Sort\">\n <ore-icon name=\"arrow-up-down\" size=\"15\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <div slot=\"content\" class=\"dg-pop-sort\">\n <div class=\"dg-pop-header\">\n <span class=\"dg-pop-title\">Sort by</span>\n <ore-button\n class=\"dg-icon-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"Clear sort\"\n disabled=\"${() => model.sortState.value.direction === 'none' || undefined}\"\n @click=\"${() => model.sortTo('', 'none')}\">\n <ore-icon name=\"trash-2\" size=\"14\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n <div class=\"dg-pop-sort-row\">\n <ore-select\n class=\"dg-pop-select\"\n variant=\"flat\"\n size=\"sm\"\n rounded=\"lg\"\n placeholder=\"Property\"\n fullwidth\n value=\"${() => model.sortState.value.key}\"\n options=\"${() => resolvedColumns.value.map((c) => ({ label: c.label, value: c.key }))}\"\n @change=\"${(e: CustomEvent<{ values: string[] }>) => {\n const key = e.detail.values[0] ?? '';\n const dir = model.sortState.value.direction === 'none' ? 'asc' : model.sortState.value.direction;\n\n model.sortTo(key, dir);\n }}\"></ore-select>\n <ore-select\n class=\"dg-pop-dir-select\"\n variant=\"flat\"\n size=\"sm\"\n rounded=\"lg\"\n fullwidth\n disabled=\"${() => !model.sortState.value.key || undefined}\"\n value=\"${() => (model.sortState.value.direction === 'none' ? 'asc' : model.sortState.value.direction)}\"\n options=\"${() => [\n { label: 'A → Z', value: 'asc' },\n { label: 'Z → A', value: 'desc' },\n ]}\"\n @change=\"${(e: CustomEvent<{ values: string[] }>) => {\n if (model.sortState.value.key) {\n model.sortTo(model.sortState.value.key, (e.detail.values[0] ?? 'asc') as 'asc' | 'desc');\n }\n }}\"></ore-select>\n </div>\n </div>\n </ore-popover>\n `;\n\n const renderFilterPopover = (): unknown => html`\n <ore-popover\n class=\"dg-action-popover\"\n placement=\"bottom-end\"\n label=\"Filter\"\n style=\"--popover-min-width:16rem;--popover-max-height:min(90vh,48rem)\">\n ${() =>\n model.filterDefs.value.length\n ? html`\n <ore-badge\n anchor=\"top-end\"\n color=\"primary\"\n size=\"xs\"\n count=\"${() => (filterBadgeActive.value ? model.filterDefs.value.length : undefined)}\"\n dot=\"${() => !filterBadgeActive.value || undefined}\"\n label=\"${() =>\n `${model.filterDefs.value.length} active filter${model.filterDefs.value.length > 1 ? 's' : ''}`}\"\n aria-hidden=\"true\"\n @mouseenter=\"${() => (filterBadgeActive.value = true)}\"\n @mouseleave=\"${() => (filterBadgeActive.value = false)}\"\n @focusin=\"${() => (filterBadgeActive.value = true)}\"\n @focusout=\"${() => (filterBadgeActive.value = false)}\">\n <ore-button slot=\"target\" variant=\"ghost\" size=\"sm\" icon-only label=\"Filter\">\n <ore-icon name=\"filter\" size=\"15\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </ore-badge>\n `\n : html`\n <ore-button class=\"dg-icon-btn\" variant=\"ghost\" size=\"sm\" icon-only label=\"Filter\">\n <ore-icon name=\"filter\" size=\"15\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n `}\n <div slot=\"content\" class=\"dg-pop-filter\">\n <div class=\"dg-pop-header\">\n <span class=\"dg-pop-title\">Filter by</span>\n ${() =>\n model.filterDefs.value.length\n ? html`\n <ore-button\n class=\"dg-icon-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"Clear all filters\"\n @click=\"${() => model.clearAllFilters()}\">\n <ore-icon name=\"trash-2\" size=\"14\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n `\n : html``}\n </div>\n\n <!-- Always-visible field picker: select columns to add filter rules -->\n <div class=\"dg-pop-filter-fields\">\n <ore-combobox\n placeholder=\"Add filter…\"\n multiple\n fullwidth\n autoclose\n options=\"${() =>\n resolvedColumns.value.map((col) => ({\n label: col.label,\n value: col.key,\n }))}\"\n value=\"${() => model.filterDefs.value.map((f) => f.key)}\"\n @change=\"${(e: CustomEvent<{ values: string[] }>) => {\n model.setActiveFilterKeys(e.detail.values);\n }}\"></ore-combobox>\n </div>\n\n <!-- Active filter rules (appear below the field picker as rules are added) -->\n <div class=\"dg-pop-filter-rules\" ?hidden=\"${() => !model.filterDefs.value.length}\">\n ${() =>\n model.filterDefs.value.map(\n (f) => html`\n <div class=\"dg-pop-filter-rule\">\n <div class=\"dg-pop-filter-rule-header\">\n <span class=\"dg-pop-filter-field\">${f.label}</span>\n <ore-select\n class=\"dg-pop-filter-op-select\"\n variant=\"ghost\"\n size=\"sm\"\n fullwidth\n value=\"${() => model.filterValues.value.get(f.key)?.operator ?? 'contains'}\"\n options=\"${() => f.operators ?? []}\"\n @change=\"${(e: CustomEvent<{ values: string[] }>) => {\n model.setFilterOperator(f.key, e.detail.values[0] as FilterOperator);\n }}\"></ore-select>\n <ore-button\n class=\"dg-icon-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"Remove filter\"\n @click=\"${() => model.removeFilter(f.key)}\">\n <ore-icon name=\"trash-2\" size=\"13\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n <ore-combobox\n class=\"dg-filter\"\n placeholder=\"${() => f.label}\"\n options=\"${() => f.options}\"\n value=\"${() => [...(model.filterValues.value.get(f.key)?.values ?? [])]}\"\n disabled=\"${() => isDisabled.value || undefined}\"\n multiple\n fullwidth\n autoclose\n @change=\"${(e: CustomEvent<{ values: string[] }>) => {\n model.setFilter(f.key, e.detail.values);\n }}\"></ore-combobox>\n </div>\n `,\n )}\n </div>\n </div>\n </ore-popover>\n `;\n\n const renderColumnMenu = (): unknown => html`\n <ore-popover\n class=\"dg-action-popover\"\n placement=\"bottom-end\"\n label=\"Column options\"\n style=\"--popover-min-width:18rem\">\n <ore-button class=\"dg-icon-btn\" variant=\"ghost\" size=\"sm\" icon-only label=\"Column options\">\n <ore-icon name=\"columns-2\" size=\"15\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <div slot=\"content\" class=\"dg-pop-col-list\" role=\"menu\" aria-label=\"Column visibility\">\n ${() =>\n resolvedColumns.value.map(\n (col) => html`\n <ore-button\n class=\"dg-pop-col-item\"\n role=\"menuitemcheckbox\"\n variant=\"ghost\"\n size=\"sm\"\n aria-checked=\"${() => String(!model.hiddenColumns.value.has(col.key))}\"\n @click=\"${() => model.toggleColumnVisibility(col.key)}\">\n <ore-icon\n slot=\"prefix\"\n name=\"${() => (model.hiddenColumns.value.has(col.key) ? 'eye-off' : 'eye')}\"\n size=\"13\"\n stroke-width=\"2\"\n aria-hidden=\"true\"></ore-icon>\n ${col.label}\n </ore-button>\n `,\n )}\n </div>\n </ore-popover>\n `;\n\n // ── Template ──────────────────────────────────────────────────────────────\n\n return html`\n <!-- ── Controls Bar ────────────────────────────────────────────────── -->\n <div class=\"dg-controls\" part=\"controls\">\n <!-- Left: view tabs -->\n ${() => renderViewTabs()}\n\n <!-- Right: Action bar -->\n <div class=\"dg-actions\">\n ${() => renderSortPopover()} ${() => renderFilterPopover()} ${() => renderColumnMenu()}\n\n <!-- Density toggle -->\n <ore-button\n class=\"dg-icon-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"${() => DENSITY_LABELS[densitySignal.value]}\"\n @click=\"${cycleDensity}\">\n <ore-icon\n name=\"${() => DENSITY_ICONS[densitySignal.value]}\"\n size=\"15\"\n stroke-width=\"1.75\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n\n <span class=\"dg-action-divider\" aria-hidden=\"true\" ?hidden=\"${() => !slots.has('actions').value}\"></span>\n\n <slot name=\"actions\"></slot>\n\n <!-- Search toggle: rightmost, expands in-place -->\n <div class=\"${() => `dg-search${model.searchActive.value ? ' dg-search--open' : ''}`}\">\n ${() =>\n model.searchActive.value\n ? html`\n <ore-input\n class=\"dg-search-input\"\n type=\"search\"\n variant=\"flat\"\n size=\"sm\"\n rounded=\"full\"\n placeholder=\"${() => props.searchPlaceholder.value ?? 'Search…'}\"\n disabled=\"${() => isDisabled.value || undefined}\"\n ref=\"${(inputEl: HTMLElement | null) => {\n if (inputEl) requestAnimationFrame(() => (inputEl as HTMLElement).focus());\n }}\"\n @input=\"${(e: CustomEvent<{ value: string }>) => {\n debouncedSearch(e.detail.value);\n }}\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n const src = props.source.value;\n\n if (src?.setQuery) void src.setQuery({ search: '' });\n\n model.toggleSearch();\n }\n }}\">\n <ore-icon slot=\"prefix\" name=\"search\" size=\"13\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-input>\n `\n : html``}\n <ore-button\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"${() => {\n const [open, close] = props.searchLabel.value ?? ['Search', 'Close search'];\n\n return model.searchActive.value ? close : open;\n }}\"\n @click=\"${() => {\n const src = props.source.value;\n\n if (src?.setQuery && model.searchActive.value) void src.setQuery({ search: '' });\n\n model.toggleSearch();\n }}\">\n <ore-icon\n name=\"${() => (model.searchActive.value ? 'x' : 'search')}\"\n size=\"15\"\n stroke-width=\"1.75\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n </div>\n </div>\n\n <div id=\"dg-tabpanel\" class=\"dg-scroll\" role=\"tabpanel\" aria-label=\"Data\">\n <div class=\"dg-loading-overlay\">\n <ore-icon name=\"loader-2\" size=\"24\" class=\"dg-spin\" aria-hidden=\"true\"></ore-icon>\n </div>\n <table\n class=\"dg-table\"\n part=\"table\"\n role=\"grid\"\n aria-label=\"${() => props.label.value ?? undefined}\"\n aria-busy=\"${() => (isLoading.value ? 'true' : null)}\"\n aria-disabled=\"${() => (isDisabled.value ? 'true' : null)}\">\n <!-- Head -->\n <thead class=\"dg-head\" part=\"thead\">\n <tr role=\"row\">\n ${() =>\n selectionMode.value === 'multi'\n ? html`\n <th\n class=\"dg-th dg-th-check\"\n role=\"columnheader\"\n scope=\"col\"\n tabindex=\"${() =>\n navHandle.activeCell.value.row === 0 &&\n navHandle.activeCell.value.col === 0 &&\n checkOffset.value >= 1\n ? '0'\n : '-1'}\">\n <ore-checkbox\n class=\"dg-check\"\n checked=\"${() => model.isAllSelected()}\"\n indeterminate=\"${isSomeSelected}\"\n ?disabled=\"${isDisabled}\"\n aria-label=\"Select all rows on this page\"\n @change=\"${() => {\n if (!isDisabled.value) model.selectAll();\n }}\"></ore-checkbox>\n </th>\n `\n : html``}\n ${() =>\n visibleColumns.value.map((col: DataGridColumn, colIdx: number) => {\n const isLast = colIdx === visibleColumns.value.length - 1;\n\n return html`\n <th\n class=\"${`dg-th${isLast && hasExpander.value ? ' dg-th-last' : ''}`}\"\n role=\"columnheader\"\n scope=\"col\"\n tabindex=\"${() => {\n const ac = navHandle.activeCell.value;\n\n return ac.row === 0 && ac.col === colIdx + checkOffset.value ? '0' : '-1';\n }}\"\n data-align=\"${col.align ?? 'left'}\"\n aria-sort=\"${() => (col.sortable ? ariaSortValue(model.sortState.value, col.key) : undefined)}\"\n aria-label=\"${col.sortable ? undefined : (col.headerLabel ?? col.label)}\"\n style=\"${() => {\n const dragged = colWidths.value[col.key];\n\n return dragged ? `width:${dragged}px` : col.width ? `width:${col.width}` : '';\n }}\">\n <div class=\"dg-th-inner\">\n ${() =>\n col.sortable\n ? html`\n <ore-button\n class=\"dg-sort-btn\"\n variant=\"text\"\n size=\"sm\"\n fullwidth\n label=\"${col.headerLabel ?? col.label}\"\n disabled=\"${() => isDisabled.value || undefined}\"\n @click=\"${() => {\n if (!isDisabled.value) model.sortBy(col.key);\n }}\">\n ${col.label}\n <ore-icon\n slot=\"suffix\"\n class=\"dg-sort-icon\"\n name=\"${() => sortIconName(model.sortState.value, col.key)}\"\n size=\"14\"\n stroke-width=\"2\"></ore-icon>\n </ore-button>\n `\n : col.label}\n ${\n col.resizable\n ? html`\n <span\n class=\"dg-col-resize\"\n aria-hidden=\"true\"\n ref=\"${(handleEl: HTMLElement | null) => {\n if (!handleEl) return;\n\n const th = handleEl.closest('th') as HTMLElement | null;\n\n if (th)\n handleEl.addEventListener('pointerdown', createColResizeHandler(col.key, th));\n }}\"></span>\n `\n : html``\n }\n </div>\n </th>\n `;\n })}\n ${() =>\n hasExpander.value\n ? html`\n <th\n class=\"dg-th dg-th-expand\"\n role=\"columnheader\"\n scope=\"col\"\n aria-label=\"Row details\"\n tabindex=\"-1\"></th>\n `\n : html``}\n </tr>\n </thead>\n\n <!-- Body -->\n <tbody class=\"dg-body\" part=\"tbody\">\n ${() =>\n model.currentPageItems.value.length === 0\n ? html`\n <tr role=\"row\">\n <td class=\"dg-empty\" role=\"gridcell\" colspan=\"${() => String(effectiveColCount.value)}\">\n <div class=\"dg-empty-content\">\n ${() => props.emptyText.value ?? 'No data'}\n ${() =>\n model.searchQuery.value || model.filterValues.value.size\n ? html`\n <div class=\"dg-empty-actions\">\n <ore-button\n variant=\"text\"\n size=\"sm\"\n @click=\"${() => {\n model.resetSearch();\n model.resetFilters();\n }}\">\n Clear all filters & search\n </ore-button>\n </div>\n `\n : html``}\n </div>\n </td>\n </tr>\n `\n : model.currentPageItems.value.map((item: Record<string, unknown>, itemIdx: number) => {\n const key = resolveKey(item);\n const isSelectable = selectionMode.value !== 'none' && !isDisabled.value;\n const rowIdx = itemIdx + 1;\n\n return html`\n <tr\n class=\"dg-tr\"\n part=\"row\"\n role=\"row\"\n aria-selected=\"${() =>\n selectionMode.value !== 'none' ? String(model.selectedKeys.value.has(key)) : null}\"\n aria-expanded=\"${() => (hasExpander.value ? String(expandedKeys.value.has(key)) : null)}\"\n ?data-selectable=\"${isSelectable}\"\n ?data-disabled=\"${isDisabled}\"\n @click=\"${() => {\n if (isSelectable && selectionMode.value === 'single') model.toggleRow(key);\n }}\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (\n (e.key === 'Enter' || e.key === ' ') &&\n isSelectable &&\n selectionMode.value === 'single'\n ) {\n e.preventDefault();\n model.toggleRow(key);\n }\n }}\">\n ${() =>\n selectionMode.value === 'multi'\n ? html`\n <td\n class=\"dg-td dg-td-check\"\n role=\"gridcell\"\n tabindex=\"${() => {\n const ac = navHandle.activeCell.value;\n\n return ac.row === rowIdx && ac.col === 0 ? '0' : '-1';\n }}\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n\n if (!isDisabled.value) model.toggleRow(key);\n }\n }}\">\n <ore-checkbox\n class=\"dg-check\"\n checked=\"${() => model.selectedKeys.value.has(key)}\"\n ?disabled=\"${isDisabled}\"\n aria-label=\"Select row\"\n tabindex=\"-1\"\n @click=\"${(e: MouseEvent) => e.stopPropagation()}\"\n @change=\"${() => {\n if (!isDisabled.value) model.toggleRow(key);\n }}\"></ore-checkbox>\n </td>\n `\n : html``}\n ${visibleColumns.value.map((col: DataGridColumn, colIdx: number) => {\n const value = getCellValue(col, item as Record<string, unknown>);\n\n const isLastCol = colIdx === visibleColumns.value.length - 1;\n\n return html`\n <td\n class=\"${`dg-td${isLastCol && hasExpander.value ? ' dg-td-last' : ''}`}\"\n part=\"cell\"\n role=\"gridcell\"\n data-align=\"${col.align ?? 'left'}\"\n tabindex=\"${() => {\n const ac = navHandle.activeCell.value;\n\n return ac.row === rowIdx && ac.col === colIdx + checkOffset.value ? '0' : '-1';\n }}\"\n title=\"${value}\">\n ${value}\n </td>\n `;\n })}\n ${() =>\n hasExpander.value\n ? html`\n <td\n class=\"dg-td dg-td-expand\"\n role=\"gridcell\"\n tabindex=\"${() => {\n const ac = navHandle.activeCell.value;\n\n return ac.row === rowIdx && ac.col === effectiveColCount.value - 1 ? '0' : '-1';\n }}\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n\n if (!isDisabled.value) toggleExpand(key);\n }\n }}\">\n <ore-button\n class=\"dg-expand-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n tabindex=\"-1\"\n label=\"${() => (expandedKeys.value.has(key) ? 'Collapse row' : 'Expand row')}\"\n aria-expanded=\"${() => String(expandedKeys.value.has(key))}\"\n disabled=\"${() => isDisabled.value || undefined}\"\n @click=\"${(e: MouseEvent) => {\n e.stopPropagation();\n\n if (!isDisabled.value) toggleExpand(key);\n }}\">\n <ore-icon\n name=\"${() => (expandedKeys.value.has(key) ? 'chevron-up' : 'chevron-down')}\"\n size=\"14\"\n stroke-width=\"2\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </td>\n `\n : html``}\n </tr>\n ${() =>\n hasExpander.value && expandedKeys.value.has(key)\n ? html`\n <tr class=\"dg-tr-expanded\" role=\"row\">\n <td\n class=\"dg-td-expanded\"\n role=\"gridcell\"\n colspan=\"${() => String(effectiveColCount.value)}\">\n ${\n // This deliberately marks the HTML sink. Callers must\n // sanitize untrusted content inside renderExpanded().\n unsafeHtml(() => {\n const renderer = resolvedColumns.value.find(\n (c) => typeof c.renderExpanded === 'function',\n );\n\n return renderer?.renderExpanded?.(item) ?? '';\n })\n }\n </td>\n </tr>\n `\n : html``}\n `;\n })}\n </tbody>\n </table>\n </div>\n\n <!-- Footer / Pagination -->\n ${() =>\n paginationEnabled.value\n ? html`\n <div class=\"dg-footer\" part=\"footer\" role=\"navigation\" aria-label=\"Pagination\">\n ${() =>\n !(props.pageSizeOptions.value ?? []).length\n ? html`\n <span class=\"dg-footer-info\" dir=\"ltr\" aria-live=\"polite\" aria-atomic=\"true\">\n ${paginationInfo}\n </span>\n `\n : html``}\n <div class=\"dg-footer-end\">\n ${() => {\n const opts = props.pageSizeOptions.value ?? [];\n\n return opts.length\n ? html`\n <div class=\"dg-page-size-wrap\">\n <ore-select\n class=\"dg-page-size-select\"\n fullwidth\n aria-label=\"Rows per page\"\n value=\"${() => String(pageSize.value)}\"\n options=\"${() => opts.map((n) => ({ label: String(n), value: String(n) }))}\"\n disabled=\"${() => isDisabled.value || undefined}\"\n @change=\"${(e: CustomEvent<{ values: string[] }>) => {\n const n = parseInt(e.detail.values[0], 10);\n\n if (!Number.isNaN(n)) {\n pageSize.value = n;\n model.goToPage(0);\n emit('page-change', { pageIndex: 0, pageSize: n });\n }\n }}\"></ore-select>\n </div>\n `\n : html``;\n }}\n <div class=\"dg-pagination\" role=\"group\" aria-label=\"Page navigation\">\n <ore-button\n class=\"dg-page-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"Previous page\"\n disabled=\"${() => !effectiveHasPrev.value || isDisabled.value}\"\n @click=\"${() => handlePage('prev')}\">\n <ore-icon name=\"chevron-left\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <span\n class=\"dg-page-label\"\n dir=\"ltr\"\n aria-current=\"page\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\">\n ${() => effectivePageLabel.value}\n </span>\n <ore-button\n class=\"dg-page-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"Next page\"\n disabled=\"${() => !effectiveHasNext.value || isDisabled.value}\"\n @click=\"${() => handlePage('next')}\">\n <ore-icon name=\"chevron-right\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n </div>\n </div>\n `\n : html``}\n `;\n },\n\n shadow: { delegatesFocus: true },\n styles: [tableBaseMixin('datagrid'), componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"datagrid.js","names":[],"sources":["../src/inputs/datagrid/datagrid.ts"],"sourcesContent":["import { debounce } from '@vielzeug/arsenal/function';\nimport {\n define,\n getHost,\n type HTMLResult,\n html,\n onCleanup,\n onMounted,\n prop,\n unsafeHtml,\n useEmit,\n useSlots,\n} from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\n\nimport { warn } from '../../_dev';\nimport '../../content/icon/icon';\nimport '../../inputs/button/button';\nimport '../../inputs/checkbox/checkbox';\nimport '../../inputs/combobox/combobox';\nimport '../../inputs/select/select';\nimport '../../overlay/popover/popover';\nimport { disablableBundle, loadableBundle } from '../../shared';\nimport { tableBaseMixin } from '../../styles';\nimport componentStyles from './datagrid.css?inline';\nimport { COLUMN_OBSERVED_ATTRS, parseColumnChildren } from './datagrid-column';\nimport {\n createDataGridModel,\n type DataGridColumn,\n type DataGridModel,\n type DataGridView,\n type FilterOperator,\n type FilterOption,\n type SelectionMode,\n type SortDirection,\n type SortState,\n} from './datagrid-model';\nimport { createGridNav, type GridNavHandle } from './datagrid-nav';\n\ntype SortMode = 'client' | 'server';\n\nexport type DataGridLabels = {\n activeFilters: (count: number) => string;\n addFilter: string;\n ascending: string;\n clearAllFilters: string;\n clearFiltersAndSearch: string;\n clearSort: string;\n closeSearch: string;\n collapseRow: string;\n columnOptions: string;\n columnVisibility: string;\n comfortableDensity: string;\n compactDensity: string;\n contains: string;\n cozyDensity: string;\n data: string;\n descending: string;\n emptyValue: string;\n equals: string;\n expandRow: string;\n filter: string;\n filterBy: string;\n filterOperator: (field: string) => string;\n greaterThan: string;\n hiddenColumns: (count: number) => string;\n lessThan: string;\n nextPage: string;\n numericAscending: string;\n numericDescending: string;\n pageNavigation: string;\n pagination: string;\n previousPage: string;\n property: string;\n range: (start: number, end: number, total: number) => string;\n removeFilter: string;\n resetColumns: string;\n rowDetails: string;\n rows: (count: number) => string;\n rowsPerPage: string;\n search: string;\n selectAllRows: string;\n selectRow: string;\n sort: string;\n sortBy: string;\n views: string;\n visibleColumns: (count: number, total: number) => string;\n};\n\nconst DEFAULT_LABELS: DataGridLabels = {\n activeFilters: (count) => `${count} active filter${count === 1 ? '' : 's'}`,\n addFilter: 'Add filter…',\n ascending: 'A → Z',\n clearAllFilters: 'Clear all filters',\n clearFiltersAndSearch: 'Clear all filters & search',\n clearSort: 'Clear sort',\n closeSearch: 'Close search',\n collapseRow: 'Collapse row',\n columnOptions: 'Column options',\n columnVisibility: 'Column visibility',\n comfortableDensity: 'Density: Comfortable',\n compactDensity: 'Density: Compact',\n contains: 'Contains',\n cozyDensity: 'Density: Cozy',\n data: 'Data',\n descending: 'Z → A',\n emptyValue: '(empty)',\n equals: 'Equals',\n expandRow: 'Expand row',\n filter: 'Filter',\n filterBy: 'Filter by',\n filterOperator: (field) => `${field} operator`,\n greaterThan: 'Greater than',\n hiddenColumns: (count) => `${count} hidden column${count === 1 ? '' : 's'}`,\n lessThan: 'Less than',\n nextPage: 'Next page',\n numericAscending: '0 → 9',\n numericDescending: '9 → 0',\n pageNavigation: 'Page navigation',\n pagination: 'Pagination',\n previousPage: 'Previous page',\n property: 'Property',\n range: (start, end, total) => `${start} to ${end} of ${total}`,\n removeFilter: 'Remove filter',\n resetColumns: 'Reset',\n rowDetails: 'Row details',\n rows: (count) => `${count} row${count === 1 ? '' : 's'}`,\n rowsPerPage: 'Rows per page',\n search: 'Search',\n selectAllRows: 'Select all rows on this page',\n selectRow: 'Select row',\n sort: 'Sort',\n sortBy: 'Sort by',\n views: 'Views',\n visibleColumns: (count, total) => `${count} of ${total} visible`,\n};\n\nexport { COLUMN_TAG } from './datagrid-column';\nexport type { DataGridColumn, DataGridView, FilterOperator, FilterOption } from './datagrid-model';\n\n// ── Pure module-level helpers ─────────────────────────────────────────────────\n\n/**\n * Returns the Lucide icon name for a column's sort state.\n * Pure function — no closure dependency on the grid model.\n */\nexport function sortIconName(state: SortState, key: string): string {\n if (state.key !== key || state.direction === 'none') return 'chevrons-up-down';\n\n return state.direction === 'asc' ? 'chevron-up' : 'chevron-down';\n}\n\n/**\n * Returns the WAI-ARIA `aria-sort` value for a column.\n * Pure function — independently unit-testable.\n */\nexport function ariaSortValue(state: SortState, key: string): 'ascending' | 'descending' | 'none' {\n if (state.key !== key || state.direction === 'none') return 'none';\n\n return state.direction === 'asc' ? 'ascending' : 'descending';\n}\n\nfunction controlValues(event: Event): string[] {\n const detail = (event as CustomEvent<{ values?: string[] }>).detail;\n\n if (Array.isArray(detail?.values)) return detail.values;\n\n const value = (event.target as HTMLElement & { value?: string }).value ?? '';\n return value.split(',').filter(Boolean);\n}\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\nexport type OreDataGridEvents<T = Record<string, unknown>> = {\n /** Fired when the user cycles the density via the toolbar button. */\n 'density-change': { density: 'compact' | 'cozy' | 'comfortable' };\n /** Fired when the active page changes. */\n 'page-change': { pageIndex: number; pageSize: number };\n /** Fired when a row is expanded or collapsed. */\n 'row-expand': { expanded: boolean; key: string };\n /** Fired when row selection changes. */\n 'selection-change': { keys: string[]; rows: T[] };\n /** Fired when the sort column or direction changes. */\n 'sort-change': { direction: SortDirection; key: string };\n /** Fired when the active view tab changes. detail: { id, label } */\n 'view-change': { id: string; label: string };\n};\n\nexport type OreDataGridProps<T = Record<string, unknown>> = {\n /**\n * The ID of the currently active view. Must match an `id` in `views`.\n * When omitted, no view is active (all data shown).\n * @example `grid.activeView = 'open'`\n */\n activeView?: string;\n /**\n * Column definitions (imperative API). Takes precedence over `<ore-column>` children.\n * Passing `[]` explicitly clears declarative children.\n * Pass `undefined` (or omit) to use `<ore-column>` children instead.\n * @example\n * ```js\n * grid.columns = [\n * { key: 'name', label: 'Name', sortable: true },\n * { key: 'email', label: 'Email' },\n * ];\n * ```\n */\n columns?: DataGridColumn<T>[];\n /** Cell density: `'compact'` | `'cozy'` (default) | `'comfortable'` */\n density?: 'compact' | 'cozy' | 'comfortable';\n /** Disable all interaction. */\n disabled?: boolean;\n /** Text shown when there are no rows. */\n emptyText?: string;\n /**\n * Enable row expansion. When set, each row gets a toggle button.\n * Requires at least one column to have a `renderExpanded` function.\n *\n * @security The `renderExpanded` callback's returned HTML string is inserted through\n * Ore's `unsafeHtml()` directive. If data originates from untrusted user input, sanitize\n * it before returning (for example, with DOMPurify or your CSP-compliant sanitizer).\n */\n expandable?: boolean;\n /**\n * Pre-defined filter option definitions per column key.\n * When provided, these options replace the auto-derived ones in the Filter popover.\n * @example\n * ```js\n * grid.filterOptions = [\n * { key: 'role', label: 'Role', options: [{ value: 'Admin' }, { value: 'Editor' }] },\n * ];\n * ```\n */\n filterOptions?: FilterOption[];\n /** Stretch the grid to fill its container's width. */\n fullwidth?: boolean;\n /**\n * Function that returns a unique string key per row.\n * Defaults to `(row) => String(row['id'])`.\n */\n getRowKey?: (row: T) => string;\n /** Accessible label for the grid. Recommended for screen readers. */\n label?: string;\n /** Localized labels for built-in controls, filters, selection, and pagination. */\n labels?: Partial<DataGridLabels>;\n /** Show a busy/loading state with reduced opacity. */\n loading?: boolean;\n /** Number of rows per page. Defaults to `10`. Set to `0` to disable pagination. */\n pageSize?: number;\n /**\n * Options for the per-page size selector rendered in the footer.\n * When provided, a `ore-select` is shown next to the pagination controls.\n * @example `grid.pageSizeOptions = [10, 25, 50, 100]`\n */\n pageSizeOptions?: number[];\n /**\n * Row data. Pass as a JS property — not serialisable to an HTML attribute.\n * @example\n * ```js\n * grid.rows = [{ id: '1', name: 'Alice', email: 'alice@example.com' }];\n * ```\n */\n rows?: T[];\n /**\n * Accessible label for the search toggle button. Supports localization.\n * Defaults to `'Search'` (open) and `'Close search'` (close).\n * Pass a tuple `[openLabel, closeLabel]` to override both.\n * @example `grid.searchLabel = ['Suchen', 'Suche schließen']`\n */\n searchLabel?: [open: string, close: string];\n /** Placeholder text for the inline search input in the controls bar. */\n searchPlaceholder?: string;\n /**\n * Pre-selected row keys. Setting this from outside will update the internal selection.\n * @example `grid.selectedKeys = ['1', '3']`\n */\n selectedKeys?: string[];\n /** Row selection mode. */\n selectionMode?: SelectionMode;\n /**\n * Whether sorting is client-side (default) or server-side.\n * When `'server'`, `sort-change` fires but items are not sorted by the control.\n */\n sortMode?: SortMode;\n /**\n * A reactive data source from `@vielzeug/sourcerer` (or any compatible object).\n * When set, the source drives row data, pagination, and search — the `rows` prop is ignored.\n * Client-side sort and filter are bypassed; wire `sort-change` to `source.setQuery()` externally.\n * @example\n * ```js\n * import { createPageSource } from '@vielzeug/sourcerer';\n * const source = createPageSource({ load: ({ query, signal }) => api.users(query, { signal }) });\n * grid.source = source;\n * ```\n */\n source?: DataGridSource<T>;\n /** Apply alternating row backgrounds. */\n striped?: boolean;\n /**\n * Named view definitions for the controls bar tab strip.\n * Each view is displayed as a tab and may provide a client-side row filter.\n * Switching tabs fires `view-change`; the consumer keeps `activeView` controlled.\n * @example\n * ```js\n * grid.views = [\n * { id: 'all', label: 'All' },\n * { id: 'open', label: 'Open' },\n * { id: 'mine', label: 'Mine' },\n * ];\n * grid.activeView = 'all';\n * ```\n */\n views?: DataGridView<T>[];\n};\n\n/**\n * An accessible, keyboard-navigable data grid with sorting, pagination,\n * single/multi row selection, inline search, filter, and named views.\n *\n * @element ore-datagrid\n * @element ore-column - Optional declarative column definition child\n *\n * @attr {boolean} disabled - Disable all interaction\n * @attr {boolean} loading - Show busy/loading state\n * @attr {boolean} striped - Apply alternating row backgrounds\n * @attr {boolean} fullwidth - Stretch the grid to fill its container's width\n * @attr {data} search-label - Tuple [openLabel, closeLabel] for the search toggle button\n * @attr {string} search-placeholder - Placeholder for the inline search input\n * @attr {number} page-size - Rows per page (0 = no pagination, default 10)\n * @attr {string} selection-mode - Row selection: 'none' | 'single' | 'multi'\n * @attr {string} sort-mode - Sorting: 'client' (default) | 'server'\n * @attr {string} density - Cell density: compact | cozy (default) | comfortable\n * @attr {string} empty-text - Text shown when there are no rows\n * @attr {string} label - Accessible label for the grid\n * @attr {data} labels - Localized built-in control labels and formatters\n * @attr {string} active-view - ID of the currently active view tab\n *\n * @fires selection-change - Fired when row selection changes. detail: { keys: string[], rows: T[] }\n * @fires sort-change - Fired when sort state changes. detail: { key: string, direction: SortDirection }\n * @fires page-change - Fired when page changes. detail: { pageIndex: number, pageSize: number }\n * @fires row-expand - Fired when a row is expanded or collapsed. detail: { expanded: boolean; key: string }\n * @fires view-change - Fired when the active view tab changes. detail: { id: string, label: string }\n *\n * @cssprop --datagrid-bg - Grid background color\n * @cssprop --datagrid-border-color - Grid and cell border color\n * @cssprop --datagrid-radius - Grid border radius\n * @cssprop --datagrid-shadow - Grid box shadow\n * @cssprop --datagrid-header-bg - Column header background\n * @cssprop --datagrid-row-hover-bg - Row hover background\n * @cssprop --datagrid-row-selected-bg - Selected row background\n * @cssprop --datagrid-stripe-bg - Even-row stripe background\n * @cssprop --datagrid-cell-padding-x - Cell horizontal padding\n * @cssprop --datagrid-cell-padding-y - Cell vertical padding\n * @cssprop --datagrid-cell-max-width - Maximum cell content width before truncating\n * @cssprop --datagrid-max-height - Max scrollable height of the table area\n * @cssprop --datagrid-font-size - Base font size for cells\n *\n * @part controls - The controls bar (tabs + action row)\n * @part table - The `<table>` element\n * @part thead - The `<thead>` element\n * @part tbody - The `<tbody>` element\n * @part row - A body `<tr>` element\n * @part cell - A body `<td>` element\n * @part footer - The pagination footer bar\n *\n * @example\n * ```html\n * <ore-datagrid id=\"grid\" label=\"Users\" selection-mode=\"multi\"></ore-datagrid>\n * <script>\n * const grid = document.getElementById('grid');\n * grid.columns = [\n * { key: 'name', label: 'Name', sortable: true },\n * { key: 'role', label: 'Role' },\n * ];\n * grid.rows = [\n * { id: '1', name: 'Alice', role: 'Admin' },\n * { id: '2', name: 'Bob', role: 'Viewer' },\n * ];\n * grid.views = [{ id: 'all', label: 'All' }, { id: 'open', label: 'Open' }];\n * grid.activeView = 'all';\n * </script>\n * ```\n */\n/**\n * Minimal structural interface for a reactive data source accepted by `ore-datagrid`.\n *\n * Any page-shaped `@vielzeug/sourcerer` source satisfies this interface automatically — no direct\n * sourcerer import is required in refine.\n *\n * When `source` is set on the grid:\n * - `rows` prop is ignored; `source.snapshot.data` drives displayed items.\n * - Pagination reads `source.snapshot.pagination`.\n * - Prev/next buttons call `source.page.previous()` / `source.page.next()`.\n * - Search calls `source.setQuery({ search })`.\n * - `source.snapshot.isFetching` contributes to the grid's `aria-busy` state.\n * - Client-side sort and filter are bypassed; wire `sort-change` to `source.setQuery()` externally.\n *\n * @example\n * ```ts\n * import { createPageSource } from '@vielzeug/sourcerer';\n *\n * const source = createPageSource({\n * load: ({ query, signal }) =>\n * fetch(`/api/users?page=${query.page}&limit=${query.pageSize}&search=${query.search}`, { signal })\n * .then(r => r.json()),\n * });\n *\n * const grid = document.querySelector('ore-datagrid');\n * grid.source = source;\n * ```\n */\nexport type DataGridSource<T = Record<string, unknown>> = {\n readonly page?: {\n next(): Promise<void> | void;\n previous(): Promise<void> | void;\n };\n setQuery?(changes: { search?: string }): Promise<void> | void;\n readonly snapshot: {\n readonly data: readonly T[];\n readonly error: { message: string } | null;\n readonly isFetching: boolean;\n readonly pagination: {\n readonly count: number;\n readonly hasNext: boolean;\n readonly hasPrevious: boolean;\n readonly index: number;\n readonly kind: 'page';\n readonly size: number;\n readonly total: number;\n };\n readonly query: { readonly search?: string };\n };\n subscribe(listener: (snapshot: DataGridSource<T>['snapshot']) => void): () => void;\n};\n\nexport const DATAGRID_TAG = 'ore-datagrid' as const;\n\ndefine<OreDataGridProps>(DATAGRID_TAG, {\n props: {\n activeView: prop.string(),\n density: prop.string<'compact' | 'cozy' | 'comfortable'>(),\n ...disablableBundle,\n ...loadableBundle,\n columns: prop.data<DataGridColumn[]>(),\n emptyText: prop.string('No data'),\n expandable: prop.bool(false),\n filterOptions: prop.data<FilterOption[]>(),\n fullwidth: prop.bool(false),\n getRowKey: prop.data<(row: Record<string, unknown>) => string>(),\n label: prop.string(),\n labels: prop.data<Partial<DataGridLabels>>(),\n pageSize: prop.number(10),\n pageSizeOptions: prop.data<number[]>(),\n rows: prop.data<Record<string, unknown>[]>(),\n searchLabel: prop.data<[string, string]>(),\n searchPlaceholder: prop.string(),\n selectedKeys: prop.data<string[]>(),\n selectionMode: prop.string<SelectionMode>('none'),\n sortMode: prop.string<SortMode>('client'),\n source: prop.data<DataGridSource>(),\n striped: prop.bool(false),\n views: prop.data<DataGridView[]>(),\n },\n\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreDataGridEvents>();\n const slots = useSlots();\n const labels = computed<DataGridLabels>(() => ({ ...DEFAULT_LABELS, ...props.labels.value }));\n\n const isDisabled = computed(() => props.disabled.value === true);\n const selectionMode = computed(() => props.selectionMode.value ?? 'none');\n\n // ── Row expansion (hoisted — needed by checkOffset + effectiveColCount) ──\n const expandedKeys = signal(new Set<string>());\n\n // resolvedColumns is declared further below; this callback is lazy and only\n // evaluates when .value is first read (after setup completes), so the\n // forward closure reference is safe at runtime.\n const hasExpander = computed(\n () =>\n props.expandable.value === true && resolvedColumns.value.some((c) => typeof c.renderExpanded === 'function'),\n );\n\n const checkOffset = computed(() => (selectionMode.value === 'multi' ? 1 : 0));\n\n // ── Page size ────────────────────────────────────────────────────────\n // Signal driven by the `page-size` prop. Stays in sync with prop changes\n // so consumers can set grid.pageSize = n reactively after mount.\n // The per-page size selector also writes to this signal directly.\n const pageSize = signal<number>(props.pageSize.value ?? 10);\n\n watch(props.pageSize, (n) => {\n if (n != null) pageSize.value = n;\n });\n\n // ── Declarative ore-column children ─────────────────────────────────────\n // A writable signal holding columns parsed from <ore-column> children.\n // Updated on mount and whenever children change. The JS `columns` prop\n // takes precedence when explicitly set (non-empty).\n const declarativeColumns = signal<DataGridColumn[]>([]);\n\n onMounted(() => {\n declarativeColumns.value = parseColumnChildren(el);\n\n const columnObserver = new MutationObserver(() => {\n declarativeColumns.value = parseColumnChildren(el);\n });\n\n columnObserver.observe(el, {\n attributeFilter: COLUMN_OBSERVED_ATTRS as unknown as string[],\n attributes: true,\n childList: true,\n subtree: true,\n });\n\n return () => columnObserver.disconnect();\n });\n\n // Resolved columns: prop wins when explicitly set (even to []); undefined = not set → use declarative children.\n const resolvedColumns = computed<DataGridColumn[]>(() => {\n const propCols = props.columns.value;\n\n return propCols !== undefined ? propCols : declarativeColumns.value;\n });\n const availableFilterFields = computed(() => {\n const fields = resolvedColumns.value.map((column) => ({ label: column.label, value: column.key }));\n const seen = new Set(fields.map((field) => field.value));\n\n for (const filter of props.filterOptions.value ?? []) {\n if (!seen.has(filter.key)) fields.push({ label: filter.label, value: filter.key });\n }\n\n return fields;\n });\n\n // ── Key resolution ─────────────────────────────────────────────────────────\n // Reads getRowKey prop dynamically so changes after mount are reflected.\n\n const resolveKey = (item: Record<string, unknown>): string => {\n const fn = props.getRowKey.value;\n\n if (fn) return fn(item);\n\n const id = item.id;\n\n if (id == null) {\n warn('ore-datagrid: row missing `id` — keys will collide. Provide `getRowKey` or add a unique `id` field.');\n\n return `__missing_${Math.random().toString(36).slice(2)}`;\n }\n\n return String(id);\n };\n\n // ── Reactive source bridge ────────────────────────────────────────────────\n // When `source` is provided it drives rows, pagination, and search.\n // The `rows` prop and client-side filter pipeline are bypassed.\n\n type SourceMetaState = {\n error: { message: string } | null;\n isLoading: boolean;\n pageCount: number;\n pageNumber: number;\n pageSize: number;\n totalItems: number;\n };\n\n const hasSource = computed(() => props.source.value != null);\n const sourceItems = signal<Record<string, unknown>[]>([]);\n const sourceMeta = signal<SourceMetaState>({\n error: null,\n isLoading: false,\n pageCount: 1,\n pageNumber: 1,\n pageSize: pageSize.value,\n totalItems: 0,\n });\n\n let _sourceUnsub: (() => void) | null = null;\n\n onCleanup(() => {\n _sourceUnsub?.();\n _sourceUnsub = null;\n });\n\n watch(\n props.source,\n (src) => {\n _sourceUnsub?.();\n _sourceUnsub = null;\n\n if (!src) {\n sourceItems.value = [];\n sourceMeta.value = {\n error: null,\n isLoading: false,\n pageCount: 1,\n pageNumber: 1,\n pageSize: pageSize.value,\n totalItems: 0,\n };\n\n return;\n }\n\n const update = (snapshot: DataGridSource['snapshot'] = src.snapshot): void => {\n sourceItems.value = snapshot.data as Record<string, unknown>[];\n sourceMeta.value = {\n error: snapshot.error,\n isLoading: snapshot.isFetching,\n pageCount: snapshot.pagination.count,\n pageNumber: snapshot.pagination.index,\n pageSize: snapshot.pagination.size,\n totalItems: snapshot.pagination.total,\n };\n };\n\n update();\n _sourceUnsub = src.subscribe(update);\n },\n { immediate: true },\n );\n\n // ── Feature model ─────────────────────────────────────────────────────────\n // One model owns every client-side grid transform and interaction state.\n // Source-backed grids retain source-owned filtering, sorting, and pagination.\n\n const model: DataGridModel = createDataGridModel({\n activeView: computed(() => (props.views.value ?? []).find((view) => view.id === props.activeView.value)),\n clientSide: computed(() => !hasSource.value),\n columns: resolvedColumns,\n emptyValueLabel: computed(() => labels.value.emptyValue),\n filterOperators: computed<Array<{ label: string; value: FilterOperator }>>(() => [\n { label: labels.value.contains, value: 'contains' },\n { label: labels.value.equals, value: 'equals' },\n { label: labels.value.greaterThan, value: 'gt' },\n { label: labels.value.lessThan, value: 'lt' },\n ]),\n filterOptions: props.filterOptions,\n getRowKey: resolveKey,\n items: computed<Record<string, unknown>[]>(() =>\n hasSource.value ? sourceItems.value : (props.rows.value ?? []),\n ),\n onSelectionChange: (keys) => {\n emit('selection-change', { keys: [...keys], rows: model.selectedRows.value });\n },\n onSortChange: (sort) => {\n emit('sort-change', sort);\n },\n pageSize: computed(() => (hasSource.value ? 0 : pageSize.value)),\n selectionMode,\n sortMode: computed(() => props.sortMode.value ?? 'client'),\n });\n\n const activeSortType = computed<'number' | 'text'>(() => {\n const column = resolvedColumns.value.find((candidate) => candidate.key === model.sortState.value.key);\n\n if (column?.sortType) return column.sortType;\n\n const row = model.filteredRows.value.find((item) => item[column?.key ?? ''] != null);\n return row && typeof row[column?.key ?? ''] === 'number' ? 'number' : 'text';\n });\n const sortDirectionOptions = computed(() =>\n activeSortType.value === 'number'\n ? [\n { label: labels.value.numericAscending, value: 'asc' },\n { label: labels.value.numericDescending, value: 'desc' },\n ]\n : [\n { label: labels.value.ascending, value: 'asc' },\n { label: labels.value.descending, value: 'desc' },\n ],\n );\n\n const debouncedSearch = debounce((query: unknown) => {\n const source = props.source.value;\n\n if (source?.setQuery) void source.setQuery({ search: query as string });\n else model.setSearchQuery(query as string);\n }, 250);\n\n // ── Sync external selected-keys prop into the feature model ───────────────\n\n watch(\n props.selectedKeys,\n (keys) => {\n if (Array.isArray(keys)) model.setSelection(new Set(keys));\n },\n { immediate: true },\n );\n\n // ── Column resize (F4) ───────────────────────────────────────────────────\n // Stores user-dragged widths as { key → px } so they survive re-renders.\n // Only columns with `resizable: true` get a drag handle.\n\n const colWidths = signal<Record<string, number>>({});\n\n const createColResizeHandler =\n (key: string, th: HTMLElement): ((e: PointerEvent) => void) =>\n (e: PointerEvent): void => {\n e.preventDefault();\n\n const startX = e.clientX;\n const startW = th.getBoundingClientRect().width;\n // AbortController ensures listeners are removed even if the component\n // is destroyed mid-drag (e.g. during SPA navigation).\n const ac = new AbortController();\n const { signal: sig } = ac;\n\n window.addEventListener(\n 'pointermove',\n (mv: PointerEvent) => {\n colWidths.value = { ...colWidths.value, [key]: Math.max(40, startW + mv.clientX - startX) };\n },\n { signal: sig },\n );\n\n window.addEventListener('pointerup', () => ac.abort(), { signal: sig });\n };\n\n // ── Visible columns (respects hide/show from column menu) ────────────────\n\n const visibleColumns = model.visibleColumns;\n\n // ── Cell value helper ────────────────────────────────────────────────────\n\n const getCellValue = (col: DataGridColumn, item: Record<string, unknown>): string => {\n if (col.cell) return col.cell(item);\n\n const v = item[col.key];\n\n return v == null ? '' : String(v);\n };\n\n // ── Pagination handlers ───────────────────────────────────────────────────\n\n function handlePage(direction: 'next' | 'prev'): void {\n const src = props.source.value;\n\n if (src) {\n if (direction === 'prev') void src.page?.previous();\n else void src.page?.next();\n\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n direction === 'prev' ? model.prevPage() : model.nextPage();\n emit('page-change', { pageIndex: model.pageIndex.value, pageSize: pageSize.value });\n }\n\n // ── Select-all helpers ────────────────────────────────\n\n const isSomeSelected = computed(() => {\n const page = model.currentPageItems.value;\n\n if (!page.length || model.isAllSelected()) return false;\n\n return page.some((item) => model.selectedKeys.value.has(resolveKey(item as Record<string, unknown>)));\n });\n\n // ── Column count (used in keyboard nav + empty colspan) ───────────────────\n\n const effectiveColCount = computed(\n () => visibleColumns.value.length + (selectionMode.value === 'multi' ? 1 : 0) + (hasExpander.value ? 1 : 0),\n );\n\n // ── Pagination info text ──────────────────────────────────────────────────\n\n const paginationEnabled = computed(() => {\n if (hasSource.value) return sourceMeta.value.pageCount > 1;\n\n return pageSize.value > 0;\n });\n\n const paginationInfo = computed(() => {\n if (hasSource.value) {\n const { pageNumber, pageSize: pSize, totalItems } = sourceMeta.value;\n const safePSize = Math.max(1, pSize);\n\n if (!paginationEnabled.value) return labels.value.rows(totalItems);\n\n if (totalItems === 0) return labels.value.range(0, 0, 0);\n\n const start = (pageNumber - 1) * safePSize + 1;\n const end = Math.min(start + safePSize - 1, totalItems);\n\n return labels.value.range(start, end, totalItems);\n }\n\n const total = model.totalItems.value;\n\n if (!paginationEnabled.value) return labels.value.rows(total);\n\n if (total === 0) return labels.value.range(0, 0, 0);\n\n const start = model.pageIndex.value * pageSize.value + 1;\n const end = Math.min(start + pageSize.value - 1, total);\n\n return labels.value.range(start, end, total);\n });\n\n // ── Source-aware loading and pagination helpers ───────────────────────────\n\n const isLoading = computed(() => props.loading.value === true || (hasSource.value && sourceMeta.value.isLoading));\n\n const effectiveHasPrev = computed(() =>\n hasSource.value ? sourceMeta.value.pageNumber > 1 : model.hasPrevPage.value,\n );\n\n const effectiveHasNext = computed(() =>\n hasSource.value ? sourceMeta.value.pageNumber < sourceMeta.value.pageCount : model.hasNextPage.value,\n );\n\n const effectivePageLabel = computed(() => {\n if (hasSource.value) {\n return sourceMeta.value.totalItems === 0\n ? '0 / 0'\n : `${sourceMeta.value.pageNumber} / ${sourceMeta.value.pageCount}`;\n }\n\n return `${model.pageIndex.value + 1} / ${model.pageCount.value}`;\n });\n\n // ── Density toggle (E5) ──────────────────────────────────────────────────\n // Local signal so the toolbar button can cycle density without requiring\n // the consumer to wire up an external prop. Stays in sync with the `density`\n // prop: prop changes win; button clicks write back to the host attribute so\n // the CSS layer picks them up immediately.\n\n type Density = 'compact' | 'cozy' | 'comfortable';\n\n const DENSITY_CYCLE: Density[] = ['compact', 'cozy', 'comfortable'];\n const DENSITY_ICONS: Record<Density, string> = {\n comfortable: 'rows-2',\n compact: 'rows-4',\n cozy: 'rows-3',\n };\n const densityLabels = computed<Record<Density, string>>(() => ({\n comfortable: labels.value.comfortableDensity,\n compact: labels.value.compactDensity,\n cozy: labels.value.cozyDensity,\n }));\n\n const densitySignal = signal<Density>(props.density.value ?? 'cozy');\n\n watch(props.density, (d) => {\n if (d) densitySignal.value = d;\n });\n\n const cycleDensity = (): void => {\n const idx = DENSITY_CYCLE.indexOf(densitySignal.value);\n const next = DENSITY_CYCLE[(idx + 1) % DENSITY_CYCLE.length]!;\n\n densitySignal.value = next;\n el.setAttribute('density', next);\n emit('density-change', { density: next });\n };\n\n // ── Row expansion (toggle handler) ───────────────────────────────────────\n\n const toggleExpand = (key: string): void => {\n const next = new Set(expandedKeys.value);\n const expanded = !next.has(key);\n\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n expanded ? next.add(key) : next.delete(key);\n expandedKeys.value = next;\n emit('row-expand', { expanded, key });\n };\n\n // ── Keyboard cell navigation (roving tabindex — extracted to datagrid-nav.ts) ──\n // navHandle is initialised with a real sentinel signal so the first render\n // produces correct tabindex values (row=0, col=0 → '0') before onMounted.\n // onMounted replaces it with the live handle from createGridNav.\n\n let navHandle: GridNavHandle = {\n activeCell: signal({ col: 0, row: 0 }),\n focusCell: () => {},\n };\n\n onMounted(() => {\n const shadow = el.shadowRoot!;\n const table = shadow.querySelector<HTMLElement>('.dg-table');\n\n if (!table) return;\n\n const { cleanup, handle } = createGridNav(table, shadow);\n\n navHandle = handle;\n\n return cleanup;\n });\n\n // Expose programmatic focusCell API on the host element (F6)\n (el as HTMLElement & { focusCell: (pos: { col: number; row: number }) => void }).focusCell = (pos) =>\n navHandle.focusCell(pos);\n\n // ── Render helpers ────────────────────────────────────────────────────────\n // Each helper renders one self-contained region, closing only over the\n // signals it actually needs. This keeps the root template readable.\n\n const renderViewTabs = (): unknown => {\n const views = props.views.value ?? [];\n const activeId = props.activeView.value;\n\n return html`\n <div\n class=\"dg-tabs\"\n role=\"tablist\"\n aria-label=\"${() => labels.value.views}\"\n aria-controls=\"dg-tabpanel\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(e.key)) return;\n\n const tabs = Array.from((e.currentTarget as HTMLElement).querySelectorAll('.dg-tab'));\n const activeIdx = tabs.findIndex((t) => t.classList.contains('dg-tab--active'));\n\n let nextIdx = activeIdx;\n\n if (e.key === 'ArrowLeft') nextIdx = Math.max(0, activeIdx - 1);\n else if (e.key === 'ArrowRight') nextIdx = Math.min(tabs.length - 1, activeIdx + 1);\n else if (e.key === 'Home') nextIdx = 0;\n else if (e.key === 'End') nextIdx = tabs.length - 1;\n\n if (nextIdx !== activeIdx) {\n e.preventDefault();\n\n const nextTab = tabs[nextIdx] as HTMLElement;\n\n nextTab.focus();\n nextTab.click();\n }\n }}\">\n ${views.map(\n (view) => html`\n <ore-button\n class=\"${() => `dg-tab${activeId === view.id ? ' dg-tab--active' : ''}`}\"\n role=\"tab\"\n variant=\"ghost\"\n rounded=\"full\"\n size=\"sm\"\n tabindex=\"${() => (activeId === view.id ? '0' : '-1')}\"\n aria-selected=\"${() => String(activeId === view.id)}\"\n aria-controls=\"dg-tabpanel\"\n @click=\"${() => {\n emit('view-change', { id: view.id, label: view.label });\n }}\">\n ${view.label}\n </ore-button>\n `,\n )}\n </div>\n `;\n };\n\n const renderSortPopover = (): unknown => html`\n <ore-popover class=\"dg-action-popover\" placement=\"bottom-end\" label=\"${() => labels.value.sort}\" style=\"--popover-min-width:18rem;--popover-overflow:visible\">\n <ore-button\n class=\"dg-icon-btn dg-state-trigger\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n ?data-customized=\"${() => model.sortState.value.direction !== 'none'}\"\n label=\"${() => labels.value.sort}\">\n <ore-icon name=\"arrow-up-down\" size=\"15\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <div slot=\"content\" class=\"dg-pop-sort\">\n <div class=\"dg-pop-header\">\n <span class=\"dg-pop-title\">${() => labels.value.sortBy}</span>\n ${() =>\n model.sortState.value.direction !== 'none'\n ? html`\n <ore-button\n class=\"dg-icon-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"${() => labels.value.clearSort}\"\n @click=\"${() => model.sortTo('', 'none')}\">\n <ore-icon name=\"trash-2\" size=\"14\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n `\n : html``}\n </div>\n <div class=\"dg-pop-sort-row\">\n <ore-select\n class=\"dg-pop-select\"\n hide-label\n variant=\"flat\"\n size=\"sm\"\n rounded=\"lg\"\n label=\"${() => labels.value.property}\"\n placeholder=\"${() => labels.value.property}\"\n fullwidth\n value=\"${() => model.sortState.value.key}\"\n options=\"${() => resolvedColumns.value.map((c) => ({ label: c.label, value: c.key }))}\"\n @change=\"${(event: Event) => {\n const key = controlValues(event)[0] ?? '';\n const dir = model.sortState.value.direction === 'none' ? 'asc' : model.sortState.value.direction;\n\n model.sortTo(key, dir);\n }}\"></ore-select>\n <ore-select\n class=\"dg-pop-dir-select\"\n hide-label\n variant=\"flat\"\n size=\"sm\"\n rounded=\"lg\"\n label=\"${() => labels.value.sort}\"\n fullwidth\n disabled=\"${() => !model.sortState.value.key || undefined}\"\n value=\"${() => (model.sortState.value.direction === 'none' ? 'asc' : model.sortState.value.direction)}\"\n options=\"${sortDirectionOptions}\"\n @change=\"${(event: Event) => {\n if (model.sortState.value.key) {\n model.sortTo(model.sortState.value.key, (controlValues(event)[0] ?? 'asc') as 'asc' | 'desc');\n }\n }}\"></ore-select>\n </div>\n </div>\n </ore-popover>\n `;\n\n const renderFilterPopover = (): unknown => html`\n <ore-popover\n class=\"dg-action-popover\"\n placement=\"bottom-end\"\n label=\"${() => labels.value.filter}\"\n style=\"--popover-min-width:18rem;--popover-max-height:min(90vh,48rem)\">\n <ore-button\n class=\"dg-icon-btn dg-state-trigger\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n ?data-customized=\"${() => model.filterDefs.value.length > 0}\"\n label=\"${() =>\n model.filterDefs.value.length\n ? `${labels.value.filter}: ${labels.value.activeFilters(model.filterDefs.value.length)}`\n : labels.value.filter}\">\n <ore-icon name=\"filter\" size=\"15\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <div slot=\"content\" class=\"dg-pop-filter\">\n <div class=\"dg-pop-header\">\n <span class=\"dg-pop-title\">${() => labels.value.filterBy}</span>\n ${() =>\n model.filterDefs.value.length\n ? html`\n <ore-button\n class=\"dg-icon-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"${() => labels.value.clearAllFilters}\"\n @click=\"${() => model.clearAllFilters()}\">\n <ore-icon name=\"trash-2\" size=\"14\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n `\n : html``}\n </div>\n\n <!-- Always-visible field picker: select columns to add filter rules -->\n <div class=\"dg-pop-filter-fields\">\n <ore-combobox\n hide-label\n label=\"${() => labels.value.addFilter}\"\n placeholder=\"${() => labels.value.addFilter}\"\n multiple\n fullwidth\n autoclose\n size=\"sm\"\n variant=\"flat\"\n options=\"${availableFilterFields}\"\n value=\"${() => model.filterDefs.value.map((f) => f.key)}\"\n @change=\"${(event: Event) => {\n model.setActiveFilterKeys(controlValues(event));\n }}\"></ore-combobox>\n </div>\n\n <!-- Active filter rules (appear below the field picker as rules are added) -->\n <div class=\"dg-pop-filter-rules\" ?hidden=\"${() => !model.filterDefs.value.length}\">\n ${() =>\n model.filterDefs.value.map(\n (f) => html`\n <div class=\"dg-pop-filter-rule\">\n <div class=\"dg-pop-filter-rule-header\">\n <span class=\"dg-pop-filter-field\">${f.label}</span>\n <ore-select\n class=\"dg-pop-filter-op-select\"\n hide-label\n variant=\"ghost\"\n size=\"sm\"\n label=\"${() => labels.value.filterOperator(f.label)}\"\n fullwidth\n value=\"${() => model.filterValues.value.get(f.key)?.operator ?? 'contains'}\"\n options=\"${() => f.operators ?? []}\"\n @change=\"${(event: Event) => {\n const operator = controlValues(event)[0] as FilterOperator | undefined;\n\n if (operator) model.setFilterOperator(f.key, operator);\n }}\"></ore-select>\n <ore-button\n class=\"dg-icon-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"${() => labels.value.removeFilter}\"\n @click=\"${() => model.removeFilter(f.key)}\">\n <ore-icon name=\"trash-2\" size=\"13\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n <ore-combobox\n class=\"dg-filter\"\n hide-label\n size=\"sm\"\n variant=\"flat\"\n label=\"${() => f.label}\"\n placeholder=\"${() => f.label}\"\n options=\"${() => f.options}\"\n value=\"${() => [...(model.filterValues.value.get(f.key)?.values ?? [])]}\"\n disabled=\"${() => isDisabled.value || undefined}\"\n multiple\n fullwidth\n autoclose\n @change=\"${(event: Event) => {\n model.setFilter(f.key, controlValues(event));\n }}\"></ore-combobox>\n </div>\n `,\n )}\n </div>\n </div>\n </ore-popover>\n `;\n\n const renderColumnMenu = (): unknown => html`\n <ore-popover\n class=\"dg-action-popover\"\n placement=\"bottom-end\"\n label=\"${() => labels.value.columnOptions}\"\n style=\"--popover-min-width:18rem\">\n <ore-button\n class=\"dg-icon-btn dg-state-trigger dg-column-trigger\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n ?data-customized=\"${() => model.hiddenColumns.value.size > 0}\"\n label=\"${() =>\n model.hiddenColumns.value.size\n ? `${labels.value.columnOptions}: ${labels.value.hiddenColumns(model.hiddenColumns.value.size)}`\n : labels.value.columnOptions}\">\n <ore-icon name=\"columns-2\" size=\"15\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <div slot=\"content\" class=\"dg-pop-col\">\n <div class=\"dg-pop-header\">\n <span class=\"dg-pop-heading\"><strong class=\"dg-pop-title\">${() =>\n labels.value.columnVisibility}</strong><small>${() =>\n labels.value.visibleColumns(\n model.visibleColumns.value.length,\n resolvedColumns.value.length,\n )}</small></span>\n ${() =>\n model.hiddenColumns.value.size\n ? html`\n <ore-button\n class=\"dg-icon-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"${() => labels.value.resetColumns}\"\n @click=\"${() => model.resetColumnVisibility()}\">\n <ore-icon name=\"trash-2\" size=\"14\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n `\n : html``}\n </div>\n <div class=\"dg-pop-col-list\" role=\"group\" aria-label=\"${() => labels.value.columnVisibility}\">\n ${() =>\n resolvedColumns.value.map(\n (col) => html`\n <ore-checkbox\n class=\"dg-pop-col-item\"\n checked=\"${() => !model.hiddenColumns.value.has(col.key)}\"\n disabled=\"${() =>\n !model.hiddenColumns.value.has(col.key) && model.visibleColumns.value.length === 1\n ? true\n : undefined}\"\n @change=\"${() => model.toggleColumnVisibility(col.key)}\">${col.label}</ore-checkbox>\n `,\n )}\n </div>\n </div>\n </ore-popover>\n `;\n\n // ── Template ──────────────────────────────────────────────────────────────\n\n return html`\n <!-- ── Controls Bar ────────────────────────────────────────────────── -->\n <div class=\"dg-controls\" part=\"controls\">\n <!-- Left: view tabs -->\n ${() => renderViewTabs()}\n\n <!-- Right: Action bar -->\n <div class=\"dg-actions\">\n ${() => renderSortPopover()} ${() => renderFilterPopover()} ${() => renderColumnMenu()}\n\n <!-- Density toggle -->\n <ore-button\n class=\"dg-icon-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"${() => densityLabels.value[densitySignal.value]}\"\n @click=\"${cycleDensity}\">\n <ore-icon\n name=\"${() => DENSITY_ICONS[densitySignal.value]}\"\n size=\"15\"\n stroke-width=\"1.75\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n\n <span class=\"dg-action-divider\" aria-hidden=\"true\" ?hidden=\"${() => !slots.has('actions').value}\"></span>\n\n <slot name=\"actions\"></slot>\n\n <!-- Search toggle: rightmost, expands in-place -->\n <div class=\"${() => `dg-search${model.searchActive.value ? ' dg-search--open' : ''}`}\">\n ${() =>\n model.searchActive.value\n ? html`\n <ore-input\n class=\"dg-search-input\"\n type=\"search\"\n variant=\"flat\"\n size=\"sm\"\n rounded=\"full\"\n aria-label=\"${() => labels.value.search}\"\n placeholder=\"${() => props.searchPlaceholder.value ?? `${labels.value.search}…`}\"\n disabled=\"${() => isDisabled.value || undefined}\"\n ref=\"${(inputEl: HTMLElement | null) => {\n if (inputEl) requestAnimationFrame(() => (inputEl as HTMLElement).focus());\n }}\"\n @input=\"${(event: Event) => {\n debouncedSearch((event.currentTarget as HTMLElement & { value: string }).value);\n }}\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n const src = props.source.value;\n\n if (src?.setQuery) void src.setQuery({ search: '' });\n\n model.toggleSearch();\n }\n }}\">\n <ore-icon slot=\"prefix\" name=\"search\" size=\"13\" stroke-width=\"1.75\" aria-hidden=\"true\"></ore-icon>\n </ore-input>\n `\n : html``}\n <ore-button\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"${() => {\n const [open, close] = props.searchLabel.value ?? [labels.value.search, labels.value.closeSearch];\n\n return model.searchActive.value ? close : open;\n }}\"\n @click=\"${() => {\n const src = props.source.value;\n\n if (src?.setQuery && model.searchActive.value) void src.setQuery({ search: '' });\n\n model.toggleSearch();\n }}\">\n <ore-icon\n name=\"${() => (model.searchActive.value ? 'x' : 'search')}\"\n size=\"15\"\n stroke-width=\"1.75\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n </div>\n </div>\n\n <div id=\"dg-tabpanel\" class=\"dg-scroll\" role=\"tabpanel\" aria-label=\"${() => labels.value.data}\">\n <div class=\"dg-loading-overlay\">\n <ore-icon name=\"loader-2\" size=\"24\" class=\"dg-spin\" aria-hidden=\"true\"></ore-icon>\n </div>\n <table\n class=\"dg-table\"\n part=\"table\"\n role=\"grid\"\n aria-label=\"${() => props.label.value ?? undefined}\"\n aria-busy=\"${() => (isLoading.value ? 'true' : null)}\"\n aria-disabled=\"${() => (isDisabled.value ? 'true' : null)}\">\n <!-- Head -->\n <thead class=\"dg-head\" part=\"thead\">\n <tr role=\"row\">\n ${() =>\n selectionMode.value === 'multi'\n ? html`\n <th\n class=\"dg-th dg-th-check\"\n role=\"columnheader\"\n scope=\"col\"\n tabindex=\"${() =>\n navHandle.activeCell.value.row === 0 &&\n navHandle.activeCell.value.col === 0 &&\n checkOffset.value >= 1\n ? '0'\n : '-1'}\">\n <ore-checkbox\n class=\"dg-check\"\n checked=\"${() => model.isAllSelected()}\"\n indeterminate=\"${isSomeSelected}\"\n ?disabled=\"${isDisabled}\"\n aria-label=\"${() => labels.value.selectAllRows}\"\n @change=\"${() => {\n if (!isDisabled.value) model.selectAll();\n }}\"></ore-checkbox>\n </th>\n `\n : html``}\n ${() =>\n visibleColumns.value.map((col: DataGridColumn, colIdx: number) => {\n const isLast = colIdx === visibleColumns.value.length - 1;\n\n return html`\n <th\n class=\"${`dg-th${isLast && hasExpander.value ? ' dg-th-last' : ''}`}\"\n role=\"columnheader\"\n scope=\"col\"\n tabindex=\"${() => {\n const ac = navHandle.activeCell.value;\n\n return ac.row === 0 && ac.col === colIdx + checkOffset.value ? '0' : '-1';\n }}\"\n data-align=\"${col.align ?? 'left'}\"\n aria-sort=\"${() => (col.sortable ? ariaSortValue(model.sortState.value, col.key) : undefined)}\"\n aria-label=\"${col.sortable ? undefined : (col.headerLabel ?? col.label)}\"\n style=\"${() => {\n const dragged = colWidths.value[col.key];\n\n return dragged ? `width:${dragged}px` : col.width ? `width:${col.width}` : '';\n }}\">\n <div class=\"dg-th-inner\">\n ${() =>\n col.sortable\n ? html`\n <ore-button\n class=\"dg-sort-btn\"\n variant=\"text\"\n size=\"sm\"\n fullwidth\n label=\"${col.headerLabel ?? col.label}\"\n disabled=\"${() => isDisabled.value || undefined}\"\n @click=\"${() => {\n if (!isDisabled.value) model.sortBy(col.key);\n }}\">\n ${col.label}\n <ore-icon\n slot=\"suffix\"\n class=\"dg-sort-icon\"\n name=\"${() => sortIconName(model.sortState.value, col.key)}\"\n size=\"14\"\n stroke-width=\"2\"></ore-icon>\n </ore-button>\n `\n : col.label}\n ${\n col.resizable\n ? html`\n <span\n class=\"dg-col-resize\"\n aria-hidden=\"true\"\n ref=\"${(handleEl: HTMLElement | null) => {\n if (!handleEl) return;\n\n const th = handleEl.closest('th') as HTMLElement | null;\n\n if (th)\n handleEl.addEventListener('pointerdown', createColResizeHandler(col.key, th));\n }}\"></span>\n `\n : html``\n }\n </div>\n </th>\n `;\n })}\n ${() =>\n hasExpander.value\n ? html`\n <th\n class=\"dg-th dg-th-expand\"\n role=\"columnheader\"\n scope=\"col\"\n aria-label=\"${() => labels.value.rowDetails}\"\n tabindex=\"-1\"></th>\n `\n : html``}\n </tr>\n </thead>\n\n <!-- Body -->\n <tbody class=\"dg-body\" part=\"tbody\">\n ${() =>\n model.currentPageItems.value.length === 0\n ? html`\n <tr role=\"row\">\n <td class=\"dg-empty\" role=\"gridcell\" colspan=\"${() => String(effectiveColCount.value)}\">\n <div class=\"dg-empty-content\">\n ${() => props.emptyText.value ?? 'No data'}\n ${() =>\n model.searchQuery.value || model.filterValues.value.size\n ? html`\n <div class=\"dg-empty-actions\">\n <ore-button\n variant=\"text\"\n size=\"sm\"\n @click=\"${() => {\n model.resetSearch();\n model.resetFilters();\n }}\">\n ${() => labels.value.clearFiltersAndSearch}\n </ore-button>\n </div>\n `\n : html``}\n </div>\n </td>\n </tr>\n `\n : model.currentPageItems.value.map((item: Record<string, unknown>, itemIdx: number) => {\n const key = resolveKey(item);\n const isSelectable = selectionMode.value !== 'none' && !isDisabled.value;\n const rowIdx = itemIdx + 1;\n\n return html`\n <tr\n class=\"dg-tr\"\n part=\"row\"\n role=\"row\"\n aria-selected=\"${() =>\n selectionMode.value !== 'none' ? String(model.selectedKeys.value.has(key)) : null}\"\n aria-expanded=\"${() => (hasExpander.value ? String(expandedKeys.value.has(key)) : null)}\"\n ?data-selectable=\"${isSelectable}\"\n ?data-disabled=\"${isDisabled}\"\n @click=\"${() => {\n if (isSelectable && selectionMode.value === 'single') model.toggleRow(key);\n }}\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (\n (e.key === 'Enter' || e.key === ' ') &&\n isSelectable &&\n selectionMode.value === 'single'\n ) {\n e.preventDefault();\n model.toggleRow(key);\n }\n }}\">\n ${() =>\n selectionMode.value === 'multi'\n ? html`\n <td\n class=\"dg-td dg-td-check\"\n role=\"gridcell\"\n tabindex=\"${() => {\n const ac = navHandle.activeCell.value;\n\n return ac.row === rowIdx && ac.col === 0 ? '0' : '-1';\n }}\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n\n if (!isDisabled.value) model.toggleRow(key);\n }\n }}\">\n <ore-checkbox\n class=\"dg-check\"\n checked=\"${() => model.selectedKeys.value.has(key)}\"\n ?disabled=\"${isDisabled}\"\n aria-label=\"${() => labels.value.selectRow}\"\n tabindex=\"-1\"\n @click=\"${(e: MouseEvent) => e.stopPropagation()}\"\n @change=\"${() => {\n if (!isDisabled.value) model.toggleRow(key);\n }}\"></ore-checkbox>\n </td>\n `\n : html``}\n ${visibleColumns.value.map((col: DataGridColumn, colIdx: number) => {\n const row = item as Record<string, unknown>;\n const value = getCellValue(col, row);\n const content: HTMLResult | string = col.renderCell?.(row) ?? value;\n\n const isLastCol = colIdx === visibleColumns.value.length - 1;\n\n return html`\n <td\n class=\"${`dg-td${isLastCol && hasExpander.value ? ' dg-td-last' : ''}`}\"\n part=\"cell\"\n role=\"gridcell\"\n data-align=\"${col.align ?? 'left'}\"\n tabindex=\"${() => {\n const ac = navHandle.activeCell.value;\n\n return ac.row === rowIdx && ac.col === colIdx + checkOffset.value ? '0' : '-1';\n }}\"\n title=\"${value}\">\n ${content}\n </td>\n `;\n })}\n ${() =>\n hasExpander.value\n ? html`\n <td\n class=\"dg-td dg-td-expand\"\n role=\"gridcell\"\n tabindex=\"${() => {\n const ac = navHandle.activeCell.value;\n\n return ac.row === rowIdx && ac.col === effectiveColCount.value - 1 ? '0' : '-1';\n }}\"\n @keydown=\"${(e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n\n if (!isDisabled.value) toggleExpand(key);\n }\n }}\">\n <ore-button\n class=\"dg-expand-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n tabindex=\"-1\"\n label=\"${() => (expandedKeys.value.has(key) ? labels.value.collapseRow : labels.value.expandRow)}\"\n aria-expanded=\"${() => String(expandedKeys.value.has(key))}\"\n disabled=\"${() => isDisabled.value || undefined}\"\n @click=\"${(e: MouseEvent) => {\n e.stopPropagation();\n\n if (!isDisabled.value) toggleExpand(key);\n }}\">\n <ore-icon\n name=\"${() => (expandedKeys.value.has(key) ? 'chevron-up' : 'chevron-down')}\"\n size=\"14\"\n stroke-width=\"2\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </td>\n `\n : html``}\n </tr>\n ${() =>\n hasExpander.value && expandedKeys.value.has(key)\n ? html`\n <tr class=\"dg-tr-expanded\" role=\"row\">\n <td\n class=\"dg-td-expanded\"\n role=\"gridcell\"\n colspan=\"${() => String(effectiveColCount.value)}\">\n ${\n // This deliberately marks the HTML sink. Callers must\n // sanitize untrusted content inside renderExpanded().\n unsafeHtml(() => {\n const renderer = resolvedColumns.value.find(\n (c) => typeof c.renderExpanded === 'function',\n );\n\n return renderer?.renderExpanded?.(item) ?? '';\n })\n }\n </td>\n </tr>\n `\n : html``}\n `;\n })}\n </tbody>\n </table>\n </div>\n\n <!-- Footer / Pagination -->\n ${() =>\n paginationEnabled.value\n ? html`\n <div class=\"dg-footer\" part=\"footer\" role=\"navigation\" aria-label=\"${() => labels.value.pagination}\">\n <div class=\"dg-footer-start\">\n <span class=\"dg-footer-info\" dir=\"ltr\" aria-live=\"polite\" aria-atomic=\"true\">\n ${paginationInfo}\n </span>\n ${() => {\n const opts = props.pageSizeOptions.value ?? [];\n\n return opts.length\n ? html`\n <div class=\"dg-page-size-wrap\">\n <ore-select\n class=\"dg-page-size-select\"\n fullwidth\n hide-label\n label=\"${() => labels.value.rowsPerPage}\"\n value=\"${() => String(pageSize.value)}\"\n options=\"${() => opts.map((n) => ({ label: String(n), value: String(n) }))}\"\n disabled=\"${() => isDisabled.value || undefined}\"\n @change=\"${(event: Event) => {\n const n = parseInt(controlValues(event)[0] ?? '', 10);\n\n if (!Number.isNaN(n)) {\n pageSize.value = n;\n model.goToPage(0);\n emit('page-change', { pageIndex: 0, pageSize: n });\n }\n }}\"></ore-select>\n </div>\n `\n : html``;\n }}\n </div>\n <div class=\"dg-pagination\" role=\"group\" aria-label=\"${() => labels.value.pageNavigation}\">\n <ore-button\n class=\"dg-page-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"${() => labels.value.previousPage}\"\n disabled=\"${() => !effectiveHasPrev.value || isDisabled.value}\"\n @click=\"${() => handlePage('prev')}\">\n <ore-icon name=\"chevron-left\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <span\n class=\"dg-page-label\"\n dir=\"ltr\"\n aria-current=\"page\"\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\">\n ${() => effectivePageLabel.value}\n </span>\n <ore-button\n class=\"dg-page-btn\"\n variant=\"ghost\"\n size=\"sm\"\n icon-only\n label=\"${() => labels.value.nextPage}\"\n disabled=\"${() => !effectiveHasNext.value || isDisabled.value}\"\n @click=\"${() => handlePage('next')}\">\n <ore-icon name=\"chevron-right\" size=\"14\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n </div>\n `\n : html``}\n `;\n },\n\n shadow: { delegatesFocus: true },\n styles: [tableBaseMixin('datagrid'), componentStyles],\n});\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var e=`@layer refine.base{:host{--tab-item-transition:var(--transition-normal);--tab-item-radius:var(--rounded-lg);outline:none;display:inline-flex}button{gap:var(--size-2);width:100%;min-height:var(--_touch-target);padding:var(--tab-item-padding,var(--size-1-5) var(--size-4));font-family:inherit;font-size:var(--tab-item-font-size,var(--text-sm));font-weight:var(--font-medium);color:var(--tab-item-color,var(--text-color-secondary));white-space:nowrap;cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:var(--tab-item-radius);transition:background var(--tab-item-transition), color var(--tab-item-transition), box-shadow var(--tab-item-transition);background:0 0;border:none;justify-content:center;align-items:center;display:inline-flex;position:relative}button:focus{outline:none}:host(:focus-visible) button,button:focus-visible{outline:var(--border-2) solid var(--_theme-focus);outline-offset:2px;box-shadow:0 0 0 3px var(--_theme-shadow)}}@layer refine.variants{:host,:host([variant=solid]),:host([variant=flat]){--_hover-bg:var(--tab-item-hover-bg,var(--color-contrast-200));--_active-bg:var(--tab-item-active-bg,var(--color-contrast-0,var(--color-canvas)));--_active-color:var(--tab-item-active-color,var(--text-color-heading));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs), var(--inset-shadow-xs))}:host([variant=bordered]){--_hover-bg:var(--tab-item-hover-bg,var(--color-contrast-200));--_active-bg:var(--tab-item-active-bg,var(--color-contrast-0,var(--color-canvas)));--_active-color:var(--tab-item-active-color,var(--text-color-heading));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs))}:host([variant=ghost]){--_hover-bg:var(--tab-item-hover-bg,var(--color-contrast-100));--_active-bg:var(--tab-item-active-bg,var(--_theme-base));--_active-color:var(--tab-item-active-color,var(--_theme-contrast))}:host([variant=glass]){--_color:var(--tab-item-color,color-mix(in oklch, var(--color-secondary-contrast) 70%, transparent));--_hover-bg:var(--tab-item-hover-bg,color-mix(in oklch, var(--color-secondary-contrast) 10%, transparent));--_active-bg:var(--tab-item-active-bg,color-mix(in oklch, var(--color-secondary-contrast) 15%, transparent));--_active-color:var(--tab-item-active-color,var(--color-secondary-contrast));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs), var(--inset-shadow-xs))}:host([variant=glass]) button{color:var(--_color);text-shadow:var(--text-shadow-2xs)}:host([variant=glass]) button:hover{color:var(--tab-item-active-color,var(--color-secondary-contrast))}:host([variant=frost]){--_hover-bg:var(--tab-item-hover-bg,color-mix(in oklch, var(--color-contrast) 10%, transparent));--_active-bg:var(--tab-item-active-bg,color-mix(in oklch, var(--color-canvas) 60%, transparent));--_active-color:var(--tab-item-active-color,var(--text-color-heading));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs), var(--inset-shadow-xs))}:host([variant=frost]) button{color:var(--text-color-secondary)}:host button:hover{color:var(--tab-item-active-color,var(--text-color-heading));background:var(--_hover-bg)}:host([active]) button{color:var(--_active-color);background:var(--_active-bg);box-shadow:var(--_active-shadow)}:host([size=sm]){--tab-item-font-size:var(--text-xs);--tab-item-padding:var(--size-1) var(--size-3)}:host(:not([size])),:host([size=md]){--tab-item-font-size:var(--text-sm);--tab-item-padding:var(--size-1-5) var(--size-4)}:host([size=lg]){--tab-item-font-size:var(--text-base);--tab-item-padding:var(--size-2) var(--size-5)}@media (pointer:coarse){:host,:host([size=md]){--tab-item-font-size:var(--text-base);--tab-item-padding:var(--size-2) var(--size-5)}:host([size=sm]){--tab-item-font-size:var(--text-sm);--tab-item-padding:var(--size-1-5) var(--size-4)}}:host([disabled]){pointer-events:none;opacity:.5}@media (forced-colors:active){button:focus-visible{box-shadow:none;outline:2px solid highlight}:host([active]) button{outline-offset:-2px;outline:2px solid highlight}}}`;exports.default=e;
1
+ var e=`@layer refine.base{:host{--tab-item-transition:var(--transition-normal);--tab-item-radius:var(--rounded-lg);outline:none;display:inline-flex}button{gap:var(--size-2);width:100%;min-height:var(--_touch-target);padding:var(--tab-item-padding,var(--size-1-5) var(--size-4));font-family:inherit;font-size:var(--tab-item-font-size,var(--text-sm));font-weight:var(--font-medium);color:var(--tab-item-color,var(--text-color-secondary));white-space:nowrap;cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:var(--tab-item-radius);transition:background var(--tab-item-transition), color var(--tab-item-transition), box-shadow var(--tab-item-transition);background:0 0;border:none;justify-content:center;align-items:center;display:inline-flex;position:relative}button:focus{outline:none}:host(:focus-visible) button,button:focus-visible{outline:var(--border-2) solid var(--_theme-focus);outline-offset:2px;box-shadow:0 0 0 3px var(--_theme-shadow)}}@layer refine.variants{:host,:host([variant=solid]),:host([variant=flat]){--_hover-bg:var(--tab-item-hover-bg,var(--color-contrast-200));--_active-bg:var(--tab-item-active-bg,var(--color-contrast-0,var(--color-canvas)));--_active-color:var(--tab-item-active-color,var(--text-color-heading));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs), var(--inset-shadow-xs))}:host([variant=bordered]){--_hover-bg:var(--tab-item-hover-bg,var(--color-contrast-200));--_active-bg:var(--tab-item-active-bg,var(--color-contrast-0,var(--color-canvas)));--_active-color:var(--tab-item-active-color,var(--text-color-heading));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs))}:host([variant=ghost]){--_hover-bg:var(--tab-item-hover-bg,var(--color-contrast-100));--_active-bg:var(--tab-item-active-bg,var(--_theme-base));--_active-color:var(--tab-item-active-color,var(--_theme-contrast))}:host([variant=glass]){--_color:var(--tab-item-color,color-mix(in oklch, var(--color-secondary-contrast) 70%, transparent));--_hover-bg:var(--tab-item-hover-bg,color-mix(in oklch, var(--color-secondary-contrast) 10%, transparent));--_active-bg:var(--tab-item-active-bg,color-mix(in oklch, var(--color-secondary-contrast) 15%, transparent));--_active-color:var(--tab-item-active-color,var(--color-secondary-contrast));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs), var(--inset-shadow-xs))}:host([variant=glass]) button{color:var(--_color);text-shadow:var(--text-shadow-2xs)}:host([variant=glass]) button:hover{color:var(--tab-item-active-color,var(--color-secondary-contrast))}:host([variant=frost]){--_hover-bg:var(--tab-item-hover-bg,color-mix(in oklch, var(--color-contrast) 10%, transparent));--_active-bg:var(--tab-item-active-bg,color-mix(in oklch, var(--color-canvas) 60%, transparent));--_active-color:var(--tab-item-active-color,var(--text-color-heading));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs), var(--inset-shadow-xs))}:host([variant=frost]) button{color:var(--text-color-secondary)}:host button:hover{color:var(--tab-item-active-color,var(--text-color-heading));background:var(--_hover-bg)}:host([active]) button{color:var(--_active-color);background:var(--_active-bg);box-shadow:var(--_active-shadow)}:host([size=sm]){--tab-item-font-size:var(--text-xs);--tab-item-padding:var(--size-1) var(--size-3)}:host(:not([size])),:host([size=md]){--tab-item-font-size:var(--text-sm);--tab-item-padding:var(--size-1-5) var(--size-4)}:host([size=lg]){--tab-item-font-size:var(--text-base);--tab-item-padding:var(--size-2) var(--size-5)}@media (pointer:coarse){:host,:host([size=md]){--tab-item-font-size:var(--text-base);--tab-item-padding:var(--size-2) var(--size-5)}:host([size=sm]){--tab-item-font-size:var(--text-sm);--tab-item-padding:var(--size-1-5) var(--size-4)}}:host([disabled]){pointer-events:none;opacity:.5}@media (forced-colors:active){button:focus-visible{box-shadow:none;outline:2px solid highlight}:host([active]) button{outline-offset:-2px;outline:2px solid highlight}}}@layer refine.density{:host([density=compact]){--tab-item-radius:var(--rounded-md);--tab-item-font-size:var(--text-xs);--tab-item-padding:var(--size-1) var(--size-2)}:host([density=compact]) button{gap:var(--size-1);min-height:var(--size-6)}}`;exports.default=e;
2
2
  //# sourceMappingURL=tab-item.css.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"tab-item.css.cjs","names":[],"sources":["../../../src/disclosure/tab-item/tab-item.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --tab-item-transition: var(--transition-normal);\n --tab-item-radius: var(--rounded-lg);\n display: inline-flex;\n outline: none;\n }\n\n button {\n position: relative;\n display: inline-flex;\n gap: var(--size-2);\n align-items: center;\n justify-content: center;\n width: 100%;\n min-height: var(--_touch-target);\n padding: var(--tab-item-padding, var(--size-1-5) var(--size-4));\n font-family: inherit;\n font-size: var(--tab-item-font-size, var(--text-sm));\n font-weight: var(--font-medium);\n color: var(--tab-item-color, var(--text-color-secondary));\n white-space: nowrap;\n cursor: pointer;\n user-select: none;\n background: transparent;\n border: none;\n border-radius: var(--tab-item-radius);\n transition:\n background var(--tab-item-transition),\n color var(--tab-item-transition),\n box-shadow var(--tab-item-transition);\n }\n\n button:focus {\n outline: none;\n }\n\n :host(:focus-visible) button,\n button:focus-visible {\n outline: var(--border-2) solid var(--_theme-focus);\n outline-offset: 2px;\n box-shadow: 0 0 0 3px var(--_theme-shadow);\n }\n}\n\n@layer refine.variants {\n /* ─── solid / default ─── */\n :host,\n :host([variant='solid']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n /* ─── flat ─── */\n :host([variant='flat']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n /* ─── bordered ─── */\n :host([variant='bordered']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs));\n }\n\n /* ─── ghost ─── */\n :host([variant='ghost']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-100));\n --_active-bg: var(--tab-item-active-bg, var(--_theme-base));\n --_active-color: var(--tab-item-active-color, var(--_theme-contrast));\n }\n\n /* ─── glass ─── */\n :host([variant='glass']) {\n --_color: var(--tab-item-color, color-mix(in oklch, var(--color-secondary-contrast) 70%, transparent));\n --_hover-bg: var(--tab-item-hover-bg, color-mix(in oklch, var(--color-secondary-contrast) 10%, transparent));\n --_active-bg: var(--tab-item-active-bg, color-mix(in oklch, var(--color-secondary-contrast) 15%, transparent));\n --_active-color: var(--tab-item-active-color, var(--color-secondary-contrast));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n :host([variant='glass']) button {\n color: var(--_color);\n text-shadow: var(--text-shadow-2xs);\n }\n\n :host([variant='glass']) button:hover {\n color: var(--tab-item-active-color, var(--color-secondary-contrast));\n }\n\n /* ─── frost ─── */\n :host([variant='frost']) {\n --_hover-bg: var(--tab-item-hover-bg, color-mix(in oklch, var(--color-contrast) 10%, transparent));\n --_active-bg: var(--tab-item-active-bg, color-mix(in oklch, var(--color-canvas) 60%, transparent));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n :host([variant='frost']) button {\n color: var(--text-color-secondary);\n }\n\n /* ─── Shared interactive states (read per-variant --_* tokens) ─── */\n\n :host button:hover {\n color: var(--tab-item-active-color, var(--text-color-heading));\n background: var(--_hover-bg);\n }\n\n :host([active]) button {\n color: var(--_active-color);\n background: var(--_active-bg);\n box-shadow: var(--_active-shadow);\n }\n\n /* ─── sizes ─── */\n :host([size='sm']) {\n --tab-item-font-size: var(--text-xs);\n --tab-item-padding: var(--size-1) var(--size-3);\n }\n\n :host(:not([size])),\n :host([size='md']) {\n --tab-item-font-size: var(--text-sm);\n --tab-item-padding: var(--size-1-5) var(--size-4);\n }\n\n :host([size='lg']) {\n --tab-item-font-size: var(--text-base);\n --tab-item-padding: var(--size-2) var(--size-5);\n }\n\n /* ─── coarse pointer: promote one size tier for proportional scaling ─── */\n @media (pointer: coarse) {\n :host,\n :host([size='md']) {\n --tab-item-font-size: var(--text-base);\n --tab-item-padding: var(--size-2) var(--size-5);\n }\n\n :host([size='sm']) {\n --tab-item-font-size: var(--text-sm);\n --tab-item-padding: var(--size-1-5) var(--size-4);\n }\n }\n\n /* ─── disabled ─── */\n :host([disabled]) {\n pointer-events: none;\n opacity: 0.5;\n }\n\n @media (forced-colors: active) {\n /* Ensure focus ring is visible regardless of variant theme color */\n button:focus-visible {\n outline: 2px solid Highlight;\n box-shadow: none;\n }\n\n /* Active tab: box-shadow raised indicator is stripped; use outline inste\n ad so the selected tab remains distinguishable */\n :host([active]) button {\n outline: 2px solid Highlight;\n outline-offset: -2px;\n }\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"tab-item.css.cjs","names":[],"sources":["../../../src/disclosure/tab-item/tab-item.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --tab-item-transition: var(--transition-normal);\n --tab-item-radius: var(--rounded-lg);\n display: inline-flex;\n outline: none;\n }\n\n button {\n position: relative;\n display: inline-flex;\n gap: var(--size-2);\n align-items: center;\n justify-content: center;\n width: 100%;\n min-height: var(--_touch-target);\n padding: var(--tab-item-padding, var(--size-1-5) var(--size-4));\n font-family: inherit;\n font-size: var(--tab-item-font-size, var(--text-sm));\n font-weight: var(--font-medium);\n color: var(--tab-item-color, var(--text-color-secondary));\n white-space: nowrap;\n cursor: pointer;\n user-select: none;\n background: transparent;\n border: none;\n border-radius: var(--tab-item-radius);\n transition:\n background var(--tab-item-transition),\n color var(--tab-item-transition),\n box-shadow var(--tab-item-transition);\n }\n\n button:focus {\n outline: none;\n }\n\n :host(:focus-visible) button,\n button:focus-visible {\n outline: var(--border-2) solid var(--_theme-focus);\n outline-offset: 2px;\n box-shadow: 0 0 0 3px var(--_theme-shadow);\n }\n}\n\n@layer refine.variants {\n /* ─── solid / default ─── */\n :host,\n :host([variant='solid']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n /* ─── flat ─── */\n :host([variant='flat']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n /* ─── bordered ─── */\n :host([variant='bordered']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs));\n }\n\n /* ─── ghost ─── */\n :host([variant='ghost']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-100));\n --_active-bg: var(--tab-item-active-bg, var(--_theme-base));\n --_active-color: var(--tab-item-active-color, var(--_theme-contrast));\n }\n\n /* ─── glass ─── */\n :host([variant='glass']) {\n --_color: var(--tab-item-color, color-mix(in oklch, var(--color-secondary-contrast) 70%, transparent));\n --_hover-bg: var(--tab-item-hover-bg, color-mix(in oklch, var(--color-secondary-contrast) 10%, transparent));\n --_active-bg: var(--tab-item-active-bg, color-mix(in oklch, var(--color-secondary-contrast) 15%, transparent));\n --_active-color: var(--tab-item-active-color, var(--color-secondary-contrast));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n :host([variant='glass']) button {\n color: var(--_color);\n text-shadow: var(--text-shadow-2xs);\n }\n\n :host([variant='glass']) button:hover {\n color: var(--tab-item-active-color, var(--color-secondary-contrast));\n }\n\n /* ─── frost ─── */\n :host([variant='frost']) {\n --_hover-bg: var(--tab-item-hover-bg, color-mix(in oklch, var(--color-contrast) 10%, transparent));\n --_active-bg: var(--tab-item-active-bg, color-mix(in oklch, var(--color-canvas) 60%, transparent));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n :host([variant='frost']) button {\n color: var(--text-color-secondary);\n }\n\n /* ─── Shared interactive states (read per-variant --_* tokens) ─── */\n\n :host button:hover {\n color: var(--tab-item-active-color, var(--text-color-heading));\n background: var(--_hover-bg);\n }\n\n :host([active]) button {\n color: var(--_active-color);\n background: var(--_active-bg);\n box-shadow: var(--_active-shadow);\n }\n\n /* ─── sizes ─── */\n :host([size='sm']) {\n --tab-item-font-size: var(--text-xs);\n --tab-item-padding: var(--size-1) var(--size-3);\n }\n\n :host(:not([size])),\n :host([size='md']) {\n --tab-item-font-size: var(--text-sm);\n --tab-item-padding: var(--size-1-5) var(--size-4);\n }\n\n :host([size='lg']) {\n --tab-item-font-size: var(--text-base);\n --tab-item-padding: var(--size-2) var(--size-5);\n }\n\n /* ─── coarse pointer: promote one size tier for proportional scaling ─── */\n @media (pointer: coarse) {\n :host,\n :host([size='md']) {\n --tab-item-font-size: var(--text-base);\n --tab-item-padding: var(--size-2) var(--size-5);\n }\n\n :host([size='sm']) {\n --tab-item-font-size: var(--text-sm);\n --tab-item-padding: var(--size-1-5) var(--size-4);\n }\n }\n\n /* ─── disabled ─── */\n :host([disabled]) {\n pointer-events: none;\n opacity: 0.5;\n }\n\n @media (forced-colors: active) {\n /* Ensure focus ring is visible regardless of variant theme color */\n button:focus-visible {\n outline: 2px solid Highlight;\n box-shadow: none;\n }\n\n /* Active tab: box-shadow raised indicator is stripped; use outline inste\n ad so the selected tab remains distinguishable */\n :host([active]) button {\n outline: 2px solid Highlight;\n outline-offset: -2px;\n }\n }\n}\n\n@layer refine.density {\n :host([density='compact']) {\n --tab-item-radius: var(--rounded-md);\n --tab-item-font-size: var(--text-xs);\n --tab-item-padding: var(--size-1) var(--size-2);\n }\n\n :host([density='compact']) button {\n gap: var(--size-1);\n min-height: var(--size-6);\n }\n}\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  //#region src/disclosure/tab-item/tab-item.css?inline
2
- var e = "@layer refine.base{:host{--tab-item-transition:var(--transition-normal);--tab-item-radius:var(--rounded-lg);outline:none;display:inline-flex}button{gap:var(--size-2);width:100%;min-height:var(--_touch-target);padding:var(--tab-item-padding,var(--size-1-5) var(--size-4));font-family:inherit;font-size:var(--tab-item-font-size,var(--text-sm));font-weight:var(--font-medium);color:var(--tab-item-color,var(--text-color-secondary));white-space:nowrap;cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:var(--tab-item-radius);transition:background var(--tab-item-transition), color var(--tab-item-transition), box-shadow var(--tab-item-transition);background:0 0;border:none;justify-content:center;align-items:center;display:inline-flex;position:relative}button:focus{outline:none}:host(:focus-visible) button,button:focus-visible{outline:var(--border-2) solid var(--_theme-focus);outline-offset:2px;box-shadow:0 0 0 3px var(--_theme-shadow)}}@layer refine.variants{:host,:host([variant=solid]),:host([variant=flat]){--_hover-bg:var(--tab-item-hover-bg,var(--color-contrast-200));--_active-bg:var(--tab-item-active-bg,var(--color-contrast-0,var(--color-canvas)));--_active-color:var(--tab-item-active-color,var(--text-color-heading));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs), var(--inset-shadow-xs))}:host([variant=bordered]){--_hover-bg:var(--tab-item-hover-bg,var(--color-contrast-200));--_active-bg:var(--tab-item-active-bg,var(--color-contrast-0,var(--color-canvas)));--_active-color:var(--tab-item-active-color,var(--text-color-heading));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs))}:host([variant=ghost]){--_hover-bg:var(--tab-item-hover-bg,var(--color-contrast-100));--_active-bg:var(--tab-item-active-bg,var(--_theme-base));--_active-color:var(--tab-item-active-color,var(--_theme-contrast))}:host([variant=glass]){--_color:var(--tab-item-color,color-mix(in oklch, var(--color-secondary-contrast) 70%, transparent));--_hover-bg:var(--tab-item-hover-bg,color-mix(in oklch, var(--color-secondary-contrast) 10%, transparent));--_active-bg:var(--tab-item-active-bg,color-mix(in oklch, var(--color-secondary-contrast) 15%, transparent));--_active-color:var(--tab-item-active-color,var(--color-secondary-contrast));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs), var(--inset-shadow-xs))}:host([variant=glass]) button{color:var(--_color);text-shadow:var(--text-shadow-2xs)}:host([variant=glass]) button:hover{color:var(--tab-item-active-color,var(--color-secondary-contrast))}:host([variant=frost]){--_hover-bg:var(--tab-item-hover-bg,color-mix(in oklch, var(--color-contrast) 10%, transparent));--_active-bg:var(--tab-item-active-bg,color-mix(in oklch, var(--color-canvas) 60%, transparent));--_active-color:var(--tab-item-active-color,var(--text-color-heading));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs), var(--inset-shadow-xs))}:host([variant=frost]) button{color:var(--text-color-secondary)}:host button:hover{color:var(--tab-item-active-color,var(--text-color-heading));background:var(--_hover-bg)}:host([active]) button{color:var(--_active-color);background:var(--_active-bg);box-shadow:var(--_active-shadow)}:host([size=sm]){--tab-item-font-size:var(--text-xs);--tab-item-padding:var(--size-1) var(--size-3)}:host(:not([size])),:host([size=md]){--tab-item-font-size:var(--text-sm);--tab-item-padding:var(--size-1-5) var(--size-4)}:host([size=lg]){--tab-item-font-size:var(--text-base);--tab-item-padding:var(--size-2) var(--size-5)}@media (pointer:coarse){:host,:host([size=md]){--tab-item-font-size:var(--text-base);--tab-item-padding:var(--size-2) var(--size-5)}:host([size=sm]){--tab-item-font-size:var(--text-sm);--tab-item-padding:var(--size-1-5) var(--size-4)}}:host([disabled]){pointer-events:none;opacity:.5}@media (forced-colors:active){button:focus-visible{box-shadow:none;outline:2px solid highlight}:host([active]) button{outline-offset:-2px;outline:2px solid highlight}}}";
2
+ var e = "@layer refine.base{:host{--tab-item-transition:var(--transition-normal);--tab-item-radius:var(--rounded-lg);outline:none;display:inline-flex}button{gap:var(--size-2);width:100%;min-height:var(--_touch-target);padding:var(--tab-item-padding,var(--size-1-5) var(--size-4));font-family:inherit;font-size:var(--tab-item-font-size,var(--text-sm));font-weight:var(--font-medium);color:var(--tab-item-color,var(--text-color-secondary));white-space:nowrap;cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:var(--tab-item-radius);transition:background var(--tab-item-transition), color var(--tab-item-transition), box-shadow var(--tab-item-transition);background:0 0;border:none;justify-content:center;align-items:center;display:inline-flex;position:relative}button:focus{outline:none}:host(:focus-visible) button,button:focus-visible{outline:var(--border-2) solid var(--_theme-focus);outline-offset:2px;box-shadow:0 0 0 3px var(--_theme-shadow)}}@layer refine.variants{:host,:host([variant=solid]),:host([variant=flat]){--_hover-bg:var(--tab-item-hover-bg,var(--color-contrast-200));--_active-bg:var(--tab-item-active-bg,var(--color-contrast-0,var(--color-canvas)));--_active-color:var(--tab-item-active-color,var(--text-color-heading));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs), var(--inset-shadow-xs))}:host([variant=bordered]){--_hover-bg:var(--tab-item-hover-bg,var(--color-contrast-200));--_active-bg:var(--tab-item-active-bg,var(--color-contrast-0,var(--color-canvas)));--_active-color:var(--tab-item-active-color,var(--text-color-heading));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs))}:host([variant=ghost]){--_hover-bg:var(--tab-item-hover-bg,var(--color-contrast-100));--_active-bg:var(--tab-item-active-bg,var(--_theme-base));--_active-color:var(--tab-item-active-color,var(--_theme-contrast))}:host([variant=glass]){--_color:var(--tab-item-color,color-mix(in oklch, var(--color-secondary-contrast) 70%, transparent));--_hover-bg:var(--tab-item-hover-bg,color-mix(in oklch, var(--color-secondary-contrast) 10%, transparent));--_active-bg:var(--tab-item-active-bg,color-mix(in oklch, var(--color-secondary-contrast) 15%, transparent));--_active-color:var(--tab-item-active-color,var(--color-secondary-contrast));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs), var(--inset-shadow-xs))}:host([variant=glass]) button{color:var(--_color);text-shadow:var(--text-shadow-2xs)}:host([variant=glass]) button:hover{color:var(--tab-item-active-color,var(--color-secondary-contrast))}:host([variant=frost]){--_hover-bg:var(--tab-item-hover-bg,color-mix(in oklch, var(--color-contrast) 10%, transparent));--_active-bg:var(--tab-item-active-bg,color-mix(in oklch, var(--color-canvas) 60%, transparent));--_active-color:var(--tab-item-active-color,var(--text-color-heading));--_active-shadow:var(--tab-item-active-shadow,var(--shadow-xs), var(--inset-shadow-xs))}:host([variant=frost]) button{color:var(--text-color-secondary)}:host button:hover{color:var(--tab-item-active-color,var(--text-color-heading));background:var(--_hover-bg)}:host([active]) button{color:var(--_active-color);background:var(--_active-bg);box-shadow:var(--_active-shadow)}:host([size=sm]){--tab-item-font-size:var(--text-xs);--tab-item-padding:var(--size-1) var(--size-3)}:host(:not([size])),:host([size=md]){--tab-item-font-size:var(--text-sm);--tab-item-padding:var(--size-1-5) var(--size-4)}:host([size=lg]){--tab-item-font-size:var(--text-base);--tab-item-padding:var(--size-2) var(--size-5)}@media (pointer:coarse){:host,:host([size=md]){--tab-item-font-size:var(--text-base);--tab-item-padding:var(--size-2) var(--size-5)}:host([size=sm]){--tab-item-font-size:var(--text-sm);--tab-item-padding:var(--size-1-5) var(--size-4)}}:host([disabled]){pointer-events:none;opacity:.5}@media (forced-colors:active){button:focus-visible{box-shadow:none;outline:2px solid highlight}:host([active]) button{outline-offset:-2px;outline:2px solid highlight}}}@layer refine.density{:host([density=compact]){--tab-item-radius:var(--rounded-md);--tab-item-font-size:var(--text-xs);--tab-item-padding:var(--size-1) var(--size-2)}:host([density=compact]) button{gap:var(--size-1);min-height:var(--size-6)}}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"tab-item.css.js","names":[],"sources":["../../../src/disclosure/tab-item/tab-item.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --tab-item-transition: var(--transition-normal);\n --tab-item-radius: var(--rounded-lg);\n display: inline-flex;\n outline: none;\n }\n\n button {\n position: relative;\n display: inline-flex;\n gap: var(--size-2);\n align-items: center;\n justify-content: center;\n width: 100%;\n min-height: var(--_touch-target);\n padding: var(--tab-item-padding, var(--size-1-5) var(--size-4));\n font-family: inherit;\n font-size: var(--tab-item-font-size, var(--text-sm));\n font-weight: var(--font-medium);\n color: var(--tab-item-color, var(--text-color-secondary));\n white-space: nowrap;\n cursor: pointer;\n user-select: none;\n background: transparent;\n border: none;\n border-radius: var(--tab-item-radius);\n transition:\n background var(--tab-item-transition),\n color var(--tab-item-transition),\n box-shadow var(--tab-item-transition);\n }\n\n button:focus {\n outline: none;\n }\n\n :host(:focus-visible) button,\n button:focus-visible {\n outline: var(--border-2) solid var(--_theme-focus);\n outline-offset: 2px;\n box-shadow: 0 0 0 3px var(--_theme-shadow);\n }\n}\n\n@layer refine.variants {\n /* ─── solid / default ─── */\n :host,\n :host([variant='solid']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n /* ─── flat ─── */\n :host([variant='flat']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n /* ─── bordered ─── */\n :host([variant='bordered']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs));\n }\n\n /* ─── ghost ─── */\n :host([variant='ghost']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-100));\n --_active-bg: var(--tab-item-active-bg, var(--_theme-base));\n --_active-color: var(--tab-item-active-color, var(--_theme-contrast));\n }\n\n /* ─── glass ─── */\n :host([variant='glass']) {\n --_color: var(--tab-item-color, color-mix(in oklch, var(--color-secondary-contrast) 70%, transparent));\n --_hover-bg: var(--tab-item-hover-bg, color-mix(in oklch, var(--color-secondary-contrast) 10%, transparent));\n --_active-bg: var(--tab-item-active-bg, color-mix(in oklch, var(--color-secondary-contrast) 15%, transparent));\n --_active-color: var(--tab-item-active-color, var(--color-secondary-contrast));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n :host([variant='glass']) button {\n color: var(--_color);\n text-shadow: var(--text-shadow-2xs);\n }\n\n :host([variant='glass']) button:hover {\n color: var(--tab-item-active-color, var(--color-secondary-contrast));\n }\n\n /* ─── frost ─── */\n :host([variant='frost']) {\n --_hover-bg: var(--tab-item-hover-bg, color-mix(in oklch, var(--color-contrast) 10%, transparent));\n --_active-bg: var(--tab-item-active-bg, color-mix(in oklch, var(--color-canvas) 60%, transparent));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n :host([variant='frost']) button {\n color: var(--text-color-secondary);\n }\n\n /* ─── Shared interactive states (read per-variant --_* tokens) ─── */\n\n :host button:hover {\n color: var(--tab-item-active-color, var(--text-color-heading));\n background: var(--_hover-bg);\n }\n\n :host([active]) button {\n color: var(--_active-color);\n background: var(--_active-bg);\n box-shadow: var(--_active-shadow);\n }\n\n /* ─── sizes ─── */\n :host([size='sm']) {\n --tab-item-font-size: var(--text-xs);\n --tab-item-padding: var(--size-1) var(--size-3);\n }\n\n :host(:not([size])),\n :host([size='md']) {\n --tab-item-font-size: var(--text-sm);\n --tab-item-padding: var(--size-1-5) var(--size-4);\n }\n\n :host([size='lg']) {\n --tab-item-font-size: var(--text-base);\n --tab-item-padding: var(--size-2) var(--size-5);\n }\n\n /* ─── coarse pointer: promote one size tier for proportional scaling ─── */\n @media (pointer: coarse) {\n :host,\n :host([size='md']) {\n --tab-item-font-size: var(--text-base);\n --tab-item-padding: var(--size-2) var(--size-5);\n }\n\n :host([size='sm']) {\n --tab-item-font-size: var(--text-sm);\n --tab-item-padding: var(--size-1-5) var(--size-4);\n }\n }\n\n /* ─── disabled ─── */\n :host([disabled]) {\n pointer-events: none;\n opacity: 0.5;\n }\n\n @media (forced-colors: active) {\n /* Ensure focus ring is visible regardless of variant theme color */\n button:focus-visible {\n outline: 2px solid Highlight;\n box-shadow: none;\n }\n\n /* Active tab: box-shadow raised indicator is stripped; use outline inste\n ad so the selected tab remains distinguishable */\n :host([active]) button {\n outline: 2px solid Highlight;\n outline-offset: -2px;\n }\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"tab-item.css.js","names":[],"sources":["../../../src/disclosure/tab-item/tab-item.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --tab-item-transition: var(--transition-normal);\n --tab-item-radius: var(--rounded-lg);\n display: inline-flex;\n outline: none;\n }\n\n button {\n position: relative;\n display: inline-flex;\n gap: var(--size-2);\n align-items: center;\n justify-content: center;\n width: 100%;\n min-height: var(--_touch-target);\n padding: var(--tab-item-padding, var(--size-1-5) var(--size-4));\n font-family: inherit;\n font-size: var(--tab-item-font-size, var(--text-sm));\n font-weight: var(--font-medium);\n color: var(--tab-item-color, var(--text-color-secondary));\n white-space: nowrap;\n cursor: pointer;\n user-select: none;\n background: transparent;\n border: none;\n border-radius: var(--tab-item-radius);\n transition:\n background var(--tab-item-transition),\n color var(--tab-item-transition),\n box-shadow var(--tab-item-transition);\n }\n\n button:focus {\n outline: none;\n }\n\n :host(:focus-visible) button,\n button:focus-visible {\n outline: var(--border-2) solid var(--_theme-focus);\n outline-offset: 2px;\n box-shadow: 0 0 0 3px var(--_theme-shadow);\n }\n}\n\n@layer refine.variants {\n /* ─── solid / default ─── */\n :host,\n :host([variant='solid']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n /* ─── flat ─── */\n :host([variant='flat']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n /* ─── bordered ─── */\n :host([variant='bordered']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-200));\n --_active-bg: var(--tab-item-active-bg, var(--color-contrast-0, var(--color-canvas)));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs));\n }\n\n /* ─── ghost ─── */\n :host([variant='ghost']) {\n --_hover-bg: var(--tab-item-hover-bg, var(--color-contrast-100));\n --_active-bg: var(--tab-item-active-bg, var(--_theme-base));\n --_active-color: var(--tab-item-active-color, var(--_theme-contrast));\n }\n\n /* ─── glass ─── */\n :host([variant='glass']) {\n --_color: var(--tab-item-color, color-mix(in oklch, var(--color-secondary-contrast) 70%, transparent));\n --_hover-bg: var(--tab-item-hover-bg, color-mix(in oklch, var(--color-secondary-contrast) 10%, transparent));\n --_active-bg: var(--tab-item-active-bg, color-mix(in oklch, var(--color-secondary-contrast) 15%, transparent));\n --_active-color: var(--tab-item-active-color, var(--color-secondary-contrast));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n :host([variant='glass']) button {\n color: var(--_color);\n text-shadow: var(--text-shadow-2xs);\n }\n\n :host([variant='glass']) button:hover {\n color: var(--tab-item-active-color, var(--color-secondary-contrast));\n }\n\n /* ─── frost ─── */\n :host([variant='frost']) {\n --_hover-bg: var(--tab-item-hover-bg, color-mix(in oklch, var(--color-contrast) 10%, transparent));\n --_active-bg: var(--tab-item-active-bg, color-mix(in oklch, var(--color-canvas) 60%, transparent));\n --_active-color: var(--tab-item-active-color, var(--text-color-heading));\n --_active-shadow: var(--tab-item-active-shadow, var(--shadow-xs), var(--inset-shadow-xs));\n }\n\n :host([variant='frost']) button {\n color: var(--text-color-secondary);\n }\n\n /* ─── Shared interactive states (read per-variant --_* tokens) ─── */\n\n :host button:hover {\n color: var(--tab-item-active-color, var(--text-color-heading));\n background: var(--_hover-bg);\n }\n\n :host([active]) button {\n color: var(--_active-color);\n background: var(--_active-bg);\n box-shadow: var(--_active-shadow);\n }\n\n /* ─── sizes ─── */\n :host([size='sm']) {\n --tab-item-font-size: var(--text-xs);\n --tab-item-padding: var(--size-1) var(--size-3);\n }\n\n :host(:not([size])),\n :host([size='md']) {\n --tab-item-font-size: var(--text-sm);\n --tab-item-padding: var(--size-1-5) var(--size-4);\n }\n\n :host([size='lg']) {\n --tab-item-font-size: var(--text-base);\n --tab-item-padding: var(--size-2) var(--size-5);\n }\n\n /* ─── coarse pointer: promote one size tier for proportional scaling ─── */\n @media (pointer: coarse) {\n :host,\n :host([size='md']) {\n --tab-item-font-size: var(--text-base);\n --tab-item-padding: var(--size-2) var(--size-5);\n }\n\n :host([size='sm']) {\n --tab-item-font-size: var(--text-sm);\n --tab-item-padding: var(--size-1-5) var(--size-4);\n }\n }\n\n /* ─── disabled ─── */\n :host([disabled]) {\n pointer-events: none;\n opacity: 0.5;\n }\n\n @media (forced-colors: active) {\n /* Ensure focus ring is visible regardless of variant theme color */\n button:focus-visible {\n outline: 2px solid Highlight;\n box-shadow: none;\n }\n\n /* Active tab: box-shadow raised indicator is stripped; use outline inste\n ad so the selected tab remains distinguishable */\n :host([active]) button {\n outline: 2px solid Highlight;\n outline-offset: -2px;\n }\n }\n}\n\n@layer refine.density {\n :host([density='compact']) {\n --tab-item-radius: var(--rounded-md);\n --tab-item-font-size: var(--text-xs);\n --tab-item-padding: var(--size-1) var(--size-2);\n }\n\n :host([density='compact']) button {\n gap: var(--size-1);\n min-height: var(--size-6);\n }\n}\n"],"mappings":""}
@@ -6,6 +6,8 @@ export type OreTabItemProps = {
6
6
  color?: ThemeColor;
7
7
  /** Disable this tab */
8
8
  disabled?: boolean;
9
+ /** Spatial density (inherited from ore-tabs) */
10
+ density?: 'compact' | 'default';
9
11
  /** Size (inherited from ore-tabs) */
10
12
  size?: ComponentSize;
11
13
  /** Unique value identifier — must match a ore-tab-panel value */
@@ -21,6 +23,7 @@ export type OreTabItemProps = {
21
23
  * @attr {string} value - Unique identifier, matches the corresponding ore-tab-panel value
22
24
  * @attr {boolean} active - Set by the parent ore-tabs when this tab is selected
23
25
  * @attr {boolean} disabled - Prevents selection
26
+ * @attr {string} density - Inherited spatial density: 'default' | 'compact'
24
27
  * @attr {string} size - 'sm' | 'md' | 'lg'
25
28
  * @attr {string} variant - Inherited from ore-tabs: 'solid' | 'flat' | 'bordered' | 'ghost' | 'glass' | 'frost'
26
29
  * @attr {string} color - Inherited from ore-tabs: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'
@@ -1 +1 @@
1
- {"version":3,"file":"tab-item.d.ts","sourceRoot":"","sources":["../../../src/disclosure/tab-item/tab-item.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI7E,MAAM,MAAM,eAAe,GAAG;IAC5B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,uBAAuB;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qCAAqC;IACrC,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,YAAY,EAAG,cAAuB,CAAC"}
1
+ {"version":3,"file":"tab-item.d.ts","sourceRoot":"","sources":["../../../src/disclosure/tab-item/tab-item.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI7E,MAAM,MAAM,eAAe,GAAG;IAC5B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,uBAAuB;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAChC,qCAAqC;IACrC,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,YAAY,EAAG,cAAuB,CAAC"}