snice 7.6.0 → 7.7.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 (183) hide show
  1. package/adapters/react/SniceProvider.js +1 -1
  2. package/adapters/react/SniceRouter.js +1 -1
  3. package/adapters/react/matchRoute.js +1 -1
  4. package/adapters/react/useRequestHandler.js +1 -1
  5. package/custom-elements.json +10 -0
  6. package/dist/cdn/accordion/snice-accordion.js +1 -1
  7. package/dist/cdn/action-bar/snice-action-bar.js +1 -1
  8. package/dist/cdn/activity-feed/snice-activity-feed.js +1 -1
  9. package/dist/cdn/alert/snice-alert.js +1 -1
  10. package/dist/cdn/app-tiles/snice-app-tiles.js +1 -1
  11. package/dist/cdn/approval-flow/snice-approval-flow.js +1 -1
  12. package/dist/cdn/audio-recorder/snice-audio-recorder.js +1 -1
  13. package/dist/cdn/availability/snice-availability.js +1 -1
  14. package/dist/cdn/avatar/snice-avatar.js +1 -1
  15. package/dist/cdn/avatar-group/snice-avatar-group.js +1 -1
  16. package/dist/cdn/badge/snice-badge.js +1 -1
  17. package/dist/cdn/banner/snice-banner.js +1 -1
  18. package/dist/cdn/binpack/snice-binpack.js +1 -1
  19. package/dist/cdn/book/snice-book.js +1 -1
  20. package/dist/cdn/booking/snice-booking.js +1 -1
  21. package/dist/cdn/breadcrumbs/snice-breadcrumbs.js +1 -1
  22. package/dist/cdn/button/snice-button.js +2 -2
  23. package/dist/cdn/button/snice-button.js.map +1 -1
  24. package/dist/cdn/button/snice-button.min.js +1 -1
  25. package/dist/cdn/button/snice-button.min.js.map +1 -1
  26. package/dist/cdn/calendar/snice-calendar.js +1 -1
  27. package/dist/cdn/camera/snice-camera.js +1 -1
  28. package/dist/cdn/camera-annotate/snice-camera-annotate.js +1 -1
  29. package/dist/cdn/candlestick/snice-candlestick.js +1 -1
  30. package/dist/cdn/card/snice-card.js +1 -1
  31. package/dist/cdn/carousel/snice-carousel.js +1 -1
  32. package/dist/cdn/cart/snice-cart.js +1 -1
  33. package/dist/cdn/chart/snice-chart.js +1 -1
  34. package/dist/cdn/chat/snice-chat.js +1 -1
  35. package/dist/cdn/checkbox/snice-checkbox.js +1 -1
  36. package/dist/cdn/chip/snice-chip.js +1 -1
  37. package/dist/cdn/code-block/snice-code-block.js +1 -1
  38. package/dist/cdn/color-display/snice-color-display.js +1 -1
  39. package/dist/cdn/color-picker/snice-color-picker.js +1 -1
  40. package/dist/cdn/command-palette/snice-command-palette.js +1 -1
  41. package/dist/cdn/comments/snice-comments.js +1 -1
  42. package/dist/cdn/countdown/snice-countdown.js +1 -1
  43. package/dist/cdn/cropper/snice-cropper.js +1 -1
  44. package/dist/cdn/data-card/snice-data-card.js +1 -1
  45. package/dist/cdn/date-picker/snice-date-picker.js +1 -1
  46. package/dist/cdn/date-range-picker/snice-date-range-picker.js +1 -1
  47. package/dist/cdn/date-time-picker/snice-date-time-picker.js +1 -1
  48. package/dist/cdn/diff/snice-diff.js +1 -1
  49. package/dist/cdn/divider/snice-divider.js +1 -1
  50. package/dist/cdn/doc/snice-doc.js +1 -1
  51. package/dist/cdn/draw/snice-draw.js +1 -1
  52. package/dist/cdn/drawer/snice-drawer.js +1 -1
  53. package/dist/cdn/empty-state/snice-empty-state.js +1 -1
  54. package/dist/cdn/estimate/snice-estimate.js +1 -1
  55. package/dist/cdn/file-gallery/snice-file-gallery.js +1 -1
  56. package/dist/cdn/file-upload/snice-file-upload.js +1 -1
  57. package/dist/cdn/flip-card/snice-flip-card.js +1 -1
  58. package/dist/cdn/flow/snice-flow.js +1 -1
  59. package/dist/cdn/form-layout/snice-form-layout.js +1 -1
  60. package/dist/cdn/funnel/snice-funnel.js +1 -1
  61. package/dist/cdn/gantt/snice-gantt.js +1 -1
  62. package/dist/cdn/gauge/snice-gauge.js +1 -1
  63. package/dist/cdn/grid/snice-grid.js +1 -1
  64. package/dist/cdn/heatmap/snice-heatmap.js +1 -1
  65. package/dist/cdn/image/snice-image.js +1 -1
  66. package/dist/cdn/input/snice-input.js +1 -1
  67. package/dist/cdn/invoice/snice-invoice.js +1 -1
  68. package/dist/cdn/kanban/snice-kanban.js +1 -1
  69. package/dist/cdn/key-value/snice-key-value.js +1 -1
  70. package/dist/cdn/kpi/snice-kpi.js +1 -1
  71. package/dist/cdn/layout/snice-layout.js +1 -1
  72. package/dist/cdn/leaderboard/snice-leaderboard.js +1 -1
  73. package/dist/cdn/link/snice-link.js +1 -1
  74. package/dist/cdn/link-preview/snice-link-preview.js +1 -1
  75. package/dist/cdn/list/snice-list.js +1 -1
  76. package/dist/cdn/location/snice-location.js +1 -1
  77. package/dist/cdn/login/README.md +1 -1
  78. package/dist/cdn/login/snice-login.js +2 -2
  79. package/dist/cdn/login/snice-login.js.map +1 -1
  80. package/dist/cdn/login/snice-login.min.js +1 -1
  81. package/dist/cdn/login/snice-login.min.js.map +1 -1
  82. package/dist/cdn/map/snice-map.js +1 -1
  83. package/dist/cdn/markdown/snice-markdown.js +1 -1
  84. package/dist/cdn/masonry/snice-masonry.js +1 -1
  85. package/dist/cdn/menu/snice-menu.js +1 -1
  86. package/dist/cdn/message-strip/snice-message-strip.js +1 -1
  87. package/dist/cdn/modal/snice-modal.js +1 -1
  88. package/dist/cdn/music-player/snice-music-player.js +1 -1
  89. package/dist/cdn/nav/snice-nav.js +1 -1
  90. package/dist/cdn/network-graph/snice-network-graph.js +1 -1
  91. package/dist/cdn/notification-center/snice-notification-center.js +1 -1
  92. package/dist/cdn/order-tracker/snice-order-tracker.js +1 -1
  93. package/dist/cdn/org-chart/snice-org-chart.js +1 -1
  94. package/dist/cdn/pagination/snice-pagination.js +1 -1
  95. package/dist/cdn/paint/snice-paint.js +1 -1
  96. package/dist/cdn/pdf-viewer/snice-pdf-viewer.js +1 -1
  97. package/dist/cdn/permission-matrix/snice-permission-matrix.js +1 -1
  98. package/dist/cdn/podcast-player/snice-podcast-player.js +1 -1
  99. package/dist/cdn/popover/snice-popover.js +1 -1
  100. package/dist/cdn/pricing-table/snice-pricing-table.js +1 -1
  101. package/dist/cdn/product-card/snice-product-card.js +1 -1
  102. package/dist/cdn/progress/snice-progress.js +1 -1
  103. package/dist/cdn/progress-ring/snice-progress-ring.js +1 -1
  104. package/dist/cdn/qr-code/snice-qr-code.js +1 -1
  105. package/dist/cdn/qr-reader/snice-qr-reader.js +1 -1
  106. package/dist/cdn/radio/snice-radio.js +1 -1
  107. package/dist/cdn/range-slider/snice-range-slider.js +1 -1
  108. package/dist/cdn/rating/snice-rating.js +1 -1
  109. package/dist/cdn/receipt/snice-receipt.js +1 -1
  110. package/dist/cdn/recipe/snice-recipe.js +1 -1
  111. package/dist/cdn/runtime/snice-runtime.esm.js +4 -4
  112. package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
  113. package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
  114. package/dist/cdn/runtime/snice-runtime.js +4 -4
  115. package/dist/cdn/runtime/snice-runtime.js.map +1 -1
  116. package/dist/cdn/runtime/snice-runtime.min.js.map +1 -1
  117. package/dist/cdn/sankey/snice-sankey.js +1 -1
  118. package/dist/cdn/segmented-control/snice-segmented-control.js +1 -1
  119. package/dist/cdn/select/snice-select.js +1 -1
  120. package/dist/cdn/skeleton/snice-skeleton.js +1 -1
  121. package/dist/cdn/slider/snice-slider.js +1 -1
  122. package/dist/cdn/sortable/snice-sortable.js +1 -1
  123. package/dist/cdn/sparkline/snice-sparkline.js +1 -1
  124. package/dist/cdn/spinner/snice-spinner.js +1 -1
  125. package/dist/cdn/split-button/snice-split-button.js +1 -1
  126. package/dist/cdn/split-pane/snice-split-pane.js +1 -1
  127. package/dist/cdn/spotlight/snice-spotlight.js +1 -1
  128. package/dist/cdn/stat-group/snice-stat-group.js +1 -1
  129. package/dist/cdn/step-input/snice-step-input.js +1 -1
  130. package/dist/cdn/stepper/snice-stepper.js +1 -1
  131. package/dist/cdn/switch/snice-switch.js +1 -1
  132. package/dist/cdn/table/README.md +2 -2
  133. package/dist/cdn/table/snice-table.esm.js +71 -4
  134. package/dist/cdn/table/snice-table.esm.js.map +1 -1
  135. package/dist/cdn/table/snice-table.esm.min.js +68 -47
  136. package/dist/cdn/table/snice-table.esm.min.js.map +1 -1
  137. package/dist/cdn/table/snice-table.js +70 -3
  138. package/dist/cdn/table/snice-table.js.map +1 -1
  139. package/dist/cdn/table/snice-table.min.js +53 -32
  140. package/dist/cdn/table/snice-table.min.js.map +1 -1
  141. package/dist/cdn/tabs/snice-tabs.js +1 -1
  142. package/dist/cdn/tag/snice-tag.js +1 -1
  143. package/dist/cdn/tag-input/snice-tag-input.js +1 -1
  144. package/dist/cdn/terminal/snice-terminal.js +1 -1
  145. package/dist/cdn/testimonial/snice-testimonial.js +1 -1
  146. package/dist/cdn/textarea/snice-textarea.js +1 -1
  147. package/dist/cdn/time-picker/snice-time-picker.js +1 -1
  148. package/dist/cdn/time-range-picker/snice-time-range-picker.js +1 -1
  149. package/dist/cdn/timeline/snice-timeline.js +1 -1
  150. package/dist/cdn/timer/snice-timer.js +1 -1
  151. package/dist/cdn/toast/snice-toast.js +1 -1
  152. package/dist/cdn/tooltip/snice-tooltip.js +1 -1
  153. package/dist/cdn/tree/snice-tree.js +1 -1
  154. package/dist/cdn/treemap/snice-treemap.js +1 -1
  155. package/dist/cdn/user-card/snice-user-card.js +1 -1
  156. package/dist/cdn/video-player/snice-video-player.js +1 -1
  157. package/dist/cdn/virtual-scroller/snice-virtual-scroller.js +1 -1
  158. package/dist/cdn/waterfall/snice-waterfall.js +1 -1
  159. package/dist/cdn/weather/snice-weather.js +1 -1
  160. package/dist/cdn/work-order/snice-work-order.js +1 -1
  161. package/dist/components/button/snice-button.js +1 -1
  162. package/dist/components/button/snice-button.js.map +1 -1
  163. package/dist/components/table/snice-table.d.ts +9 -0
  164. package/dist/components/table/snice-table.js +68 -1
  165. package/dist/components/table/snice-table.js.map +1 -1
  166. package/dist/components/table/table-keyboard.js +1 -1
  167. package/dist/components/table/table-keyboard.js.map +1 -1
  168. package/dist/index.cjs +1 -1
  169. package/dist/index.esm.js +1 -1
  170. package/dist/index.iife.js +1 -1
  171. package/dist/react/SniceProvider.js +1 -1
  172. package/dist/react/SniceRouter.js +1 -1
  173. package/dist/react/index.js +1 -1
  174. package/dist/react/matchRoute.js +1 -1
  175. package/dist/react/useRequestHandler.js +1 -1
  176. package/dist/symbols.cjs +1 -1
  177. package/dist/symbols.esm.js +1 -1
  178. package/dist/testing-dom.cjs +1 -1
  179. package/dist/testing-dom.esm.js +1 -1
  180. package/dist/transitions.cjs +1 -1
  181. package/dist/transitions.esm.js +1 -1
  182. package/docs/ai/DEVELOPMENT.md +1 -1
  183. package/package.json +1 -1
@@ -122,7 +122,7 @@ class TableKeyboard {
122
122
  });
123
123
  }
124
124
  // Body rows
125
- const bodyRows = table.querySelectorAll('tbody tr:not(.virtual-spacer)');
125
+ const bodyRows = table.querySelectorAll('tbody tr:not(.virtual-spacer):not(.table-fill-row)');
126
126
  bodyRows.forEach((row, i) => {
127
127
  row.setAttribute('role', 'row');
128
128
  row.setAttribute('aria-rowindex', String(this.ariaRowOffset + i + 2)); // +2 for 1-based + header
@@ -1 +1 @@
1
- {"version":3,"file":"table-keyboard.js","sources":["../../../../components/table/table-keyboard.ts"],"sourcesContent":["/**\n * Keyboard navigation and ARIA for snice-table.\n * Full WAI-ARIA grid pattern with arrow key navigation.\n */\n\nexport interface KeyboardOptions {\n /** The shadow root containing the table */\n shadowRoot: ShadowRoot;\n /** Callback when a cell is activated (Enter) */\n onCellActivate?: (rowIndex: number, columnKey: string) => void;\n /** Callback when selection changes via keyboard */\n onSelectionToggle?: (rowIndex: number) => void;\n /** Callback for select-all (Ctrl+A) */\n onSelectAll?: () => void;\n /** Tab navigation mode */\n tabMode: 'none' | 'content' | 'header' | 'all';\n /**\n * Total data rows. A getter callback keeps bounds live as the dataset is\n * loaded / filtered / paginated; a plain number is accepted for callers that\n * re-attach on every change.\n */\n totalRows: number | (() => number);\n /** Total columns. Getter callback or plain number — see `totalRows`. */\n totalColumns: number | (() => number);\n /**\n * Total rows exposed to assistive technology. This may exceed the keyboard\n * navigation count when the body also contains non-focusable group and\n * aggregate rows. Defaults to totalRows.\n */\n ariaRows?: number | (() => number);\n /** Zero-based logical offset of the first rendered body row (virtual grids). */\n ariaRowOffset?: number | (() => number);\n /**\n * Resolve a keyboard-navigation row to its rendered <tr>. Grouping/filtering\n * can make navigation order differ from raw data-index order.\n */\n getRowElement?: (rowIndex: number) => HTMLElement | null;\n /**\n * Bring a logical (data-index) row into the rendered window before focus\n * lands on it. Under virtualization only the current window is in the DOM;\n * the host scrolls the row's range into view and renders it synchronously.\n */\n ensureRowVisible?: (rowIndex: number) => void;\n /** Whether editing is active */\n isEditing: () => boolean;\n}\n\nexport class TableKeyboard {\n private options: KeyboardOptions;\n private focusedRow = -1; // -1 = header\n /** True after the first real user keydown — no focus paint at rest. */\n private hasUserInteracted = false;\n private focusedCol = 0;\n // EventListener-typed: ShadowRoot's TS event map only knows 'slotchange',\n // so a KeyboardEvent-typed handler fails the addEventListener overloads.\n private keyHandler: EventListener;\n private attached = false;\n\n constructor() {\n this.options = {} as KeyboardOptions;\n this.keyHandler = (e: Event) => this.handleKeyDown(e as KeyboardEvent);\n }\n\n attach(options: KeyboardOptions) {\n this.options = options;\n const root = options.shadowRoot;\n if (!root) return;\n\n // Delegate keydown at the shadow root — a stable ancestor that always\n // exists (even before the first render) and survives every <table> rebuild.\n // Every keydown inside the shadow tree bubbles here, so navigation works no\n // matter when data/columns arrive or how often renderHeader/renderBody\n // replace the table structure. Binding to the inner <table> instead meant a\n // table built after @ready was never listened to, and a rebuilt table\n // silently dropped the listener.\n root.addEventListener('keydown', this.keyHandler);\n this.attached = true;\n this.syncGridRole();\n this.applyARIA();\n }\n\n detach() {\n this.options.shadowRoot?.removeEventListener('keydown', this.keyHandler);\n this.attached = false;\n }\n\n /**\n * (Re)apply the grid identity to the current <table>: role=grid, a focusable\n * tabindex, and live row/col counts. Cheap, idempotent, and safe to call\n * before the table exists (no-op). A structural rebuild that swaps the\n * <table> node drops these attributes, so they must be re-applied afterwards.\n */\n private syncGridRole() {\n const table = this.getTable();\n if (!table) return;\n\n table.setAttribute('role', 'grid');\n table.setAttribute('tabindex', '0');\n table.setAttribute('aria-rowcount', String(this.ariaRowCount + 1)); // +1 header\n table.setAttribute('aria-colcount', String(this.totalColCount));\n }\n\n /**\n * Host hook: called after renderHeader/renderBody rebuild the table. The\n * delegated keydown listener lives on the shadow root so it survives on its\n * own; this restores the grid role and the roving tabindex on the focused\n * cell, both of which a wiped thead/tbody (or a swapped <table>) would lose.\n */\n refresh() {\n if (!this.attached) return;\n\n this.syncGridRole();\n this.applyARIA();\n }\n\n private getTable(): HTMLElement | null {\n return this.options.shadowRoot?.querySelector('table') ?? null;\n }\n\n /** Resolve a bound that may be a live getter or a static number. */\n private resolveBound(v: number | (() => number) | undefined): number {\n return typeof v === 'function' ? v() : (v ?? 0);\n }\n\n private get totalRowCount(): number {\n return this.resolveBound(this.options.totalRows);\n }\n\n private get totalColCount(): number {\n return this.resolveBound(this.options.totalColumns);\n }\n\n private get ariaRowCount(): number {\n return this.resolveBound(this.options.ariaRows ?? this.options.totalRows);\n }\n\n private get ariaRowOffset(): number {\n return Math.max(0, this.resolveBound(this.options.ariaRowOffset));\n }\n\n /** Resolve a body row by its logical data-index (not its DOM position). */\n private getBodyRow(index: number): HTMLElement | null {\n if (this.options.getRowElement) return this.options.getRowElement(index);\n const table = this.getTable();\n if (!table) return null;\n return table.querySelector(`tbody tr[data-index=\"${index}\"]`);\n }\n\n /** Apply ARIA attributes to the grid */\n applyARIA() {\n const table = this.getTable();\n if (!table) return;\n\n table.setAttribute('aria-rowcount', String(this.ariaRowCount + 1)); // +1 for header\n table.setAttribute('aria-colcount', String(this.totalColCount));\n\n // Header row\n const headerRow = table.querySelector('thead tr.column-header-row')\n ?? table.querySelector('thead tr:not(.column-group-row):not(.header-filter-row)');\n if (headerRow) {\n headerRow.setAttribute('role', 'row');\n headerRow.setAttribute('aria-rowindex', '1');\n const ths = headerRow.querySelectorAll('th');\n ths.forEach((th, i) => {\n th.setAttribute('role', 'columnheader');\n th.setAttribute('aria-colindex', String(i + 1));\n\n // Sort state\n if (th.classList.contains('sortable')) {\n const sortIndicator = th.querySelector('.sort-indicator.active');\n if (sortIndicator) {\n const text = sortIndicator.textContent?.trim() || '';\n if (text.includes('▲')) th.setAttribute('aria-sort', 'ascending');\n else if (text.includes('▼')) th.setAttribute('aria-sort', 'descending');\n } else {\n th.setAttribute('aria-sort', 'none');\n }\n }\n });\n }\n\n // Body rows\n const bodyRows = table.querySelectorAll('tbody tr:not(.virtual-spacer)');\n bodyRows.forEach((row, i) => {\n row.setAttribute('role', 'row');\n row.setAttribute('aria-rowindex', String(this.ariaRowOffset + i + 2)); // +2 for 1-based + header\n\n const isSelected = row.getAttribute('data-selected') === 'true';\n if (isSelected) row.setAttribute('aria-selected', 'true');\n else row.removeAttribute('aria-selected');\n\n const cells = row.querySelectorAll('td');\n cells.forEach((cell, j) => {\n cell.setAttribute('role', 'gridcell');\n cell.setAttribute('aria-colindex', String(j + 1));\n });\n });\n\n // Set roving tabindex on focused cell\n this.updateFocusIndicator();\n }\n\n /** Set focus position */\n setFocus(row: number, col: number) {\n this.focusedRow = row;\n this.focusedCol = col;\n this.updateFocusIndicator();\n }\n\n /** Get current focus position */\n getFocus(): { row: number; col: number } {\n return { row: this.focusedRow, col: this.focusedCol };\n }\n\n private updateFocusIndicator() {\n // A grid that was never keyboard-focused must not wear focus styling —\n // refresh() runs after every renderBody, and painting the default header\n // position (focusedRow=-1) put a stuck blue ring on every table at rest.\n if (!this.hasUserInteracted) return;\n\n const table = this.getTable();\n if (!table) return;\n\n // Remove previous focus\n table.querySelectorAll('[data-grid-focus]').forEach(el => {\n el.removeAttribute('data-grid-focus');\n el.removeAttribute('tabindex');\n });\n\n // Find target cell\n let targetCell: HTMLElement | null = null;\n if (this.focusedRow === -1) {\n // Header\n const ths = table.querySelectorAll('thead th');\n targetCell = ths[this.focusedCol] as HTMLElement;\n } else {\n // Resolve by logical data-index, not DOM position: under virtualization\n // only the current window is in the DOM.\n let row = this.getBodyRow(this.focusedRow);\n if (!row) {\n // Outside the rendered window — ask the host to scroll it into view,\n // then look again.\n this.options.ensureRowVisible?.(this.focusedRow);\n row = this.getBodyRow(this.focusedRow);\n }\n if (row) {\n const cells = row.querySelectorAll('td');\n targetCell = cells[this.focusedCol] as HTMLElement;\n }\n }\n\n if (targetCell) {\n targetCell.setAttribute('data-grid-focus', 'true');\n targetCell.setAttribute('tabindex', '0');\n }\n }\n\n private handleKeyDown(e: KeyboardEvent) {\n // Don't handle when editing\n if (this.options.isEditing()) return;\n\n // Let controls inside the grid keep their native keyboard contract. This\n // includes group/tree toggle buttons (Enter/Space must click them), row\n // checkboxes, links, and form controls rendered by custom cells. Inspect\n // the composed path so controls nested in another component's shadow root\n // are recognized too.\n const interactiveSelector = 'button, a, input, select, textarea, [contenteditable=\"true\"], snice-button, snice-checkbox, snice-input, snice-select';\n const fromInteractiveControl = e.composedPath().some((node) =>\n node instanceof Element && node.matches(interactiveSelector)\n );\n if (fromInteractiveControl) return;\n\n this.hasUserInteracted = true;\n\n const totalRows = this.totalRowCount;\n const totalColumns = this.totalColCount;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n this.focusedRow = Math.min(totalRows - 1, this.focusedRow + 1);\n this.updateFocusIndicator();\n this.scrollIntoView();\n break;\n\n case 'ArrowUp':\n e.preventDefault();\n this.focusedRow = Math.max(-1, this.focusedRow - 1);\n this.updateFocusIndicator();\n this.scrollIntoView();\n break;\n\n case 'ArrowRight':\n e.preventDefault();\n this.focusedCol = Math.min(totalColumns - 1, this.focusedCol + 1);\n this.updateFocusIndicator();\n break;\n\n case 'ArrowLeft':\n e.preventDefault();\n this.focusedCol = Math.max(0, this.focusedCol - 1);\n this.updateFocusIndicator();\n break;\n\n case 'Home':\n e.preventDefault();\n if (e.ctrlKey) {\n this.focusedRow = -1;\n this.focusedCol = 0;\n } else {\n this.focusedCol = 0;\n }\n this.updateFocusIndicator();\n this.scrollIntoView();\n break;\n\n case 'End':\n e.preventDefault();\n if (e.ctrlKey) {\n this.focusedRow = totalRows - 1;\n this.focusedCol = totalColumns - 1;\n } else {\n this.focusedCol = totalColumns - 1;\n }\n this.updateFocusIndicator();\n this.scrollIntoView();\n break;\n\n case 'PageDown':\n e.preventDefault();\n this.focusedRow = Math.min(totalRows - 1, this.focusedRow + 10);\n this.updateFocusIndicator();\n this.scrollIntoView();\n break;\n\n case 'PageUp':\n e.preventDefault();\n this.focusedRow = Math.max(0, this.focusedRow - 10);\n this.updateFocusIndicator();\n this.scrollIntoView();\n break;\n\n case ' ':\n if (this.focusedRow >= 0) {\n e.preventDefault();\n this.options.onSelectionToggle?.(this.focusedRow);\n }\n break;\n\n case 'Enter':\n if (this.focusedRow >= 0 && this.focusedCol >= 0) {\n e.preventDefault();\n const row = this.getBodyRow(this.focusedRow);\n const cells = row?.querySelectorAll('td');\n const cell = cells?.[this.focusedCol];\n const columnKey = cell?.getAttribute('data-key') || '';\n this.options.onCellActivate?.(this.focusedRow, columnKey);\n }\n break;\n\n case 'a':\n if (e.ctrlKey || e.metaKey) {\n e.preventDefault();\n this.options.onSelectAll?.();\n }\n break;\n\n case 'Escape':\n // Let this bubble up to cancel editing\n break;\n }\n }\n\n private scrollIntoView() {\n const table = this.getTable();\n if (!table) return;\n\n const focusedEl = table.querySelector('[data-grid-focus]') as HTMLElement;\n if (focusedEl) {\n // Guard: layout APIs are not implemented in some non-browser DOMs.\n if (typeof focusedEl.scrollIntoView === 'function') {\n focusedEl.scrollIntoView({ block: 'nearest', inline: 'nearest' });\n }\n if (typeof focusedEl.focus === 'function') {\n focusedEl.focus({ preventScroll: true });\n }\n }\n }\n\n isAttached(): boolean {\n return this.attached;\n }\n}\n"],"names":[],"mappings":"AAAA;;;AAGG;MA4CU,aAAa,CAAA;AAWxB,IAAA,WAAA,GAAA;AATQ,QAAA,IAAA,CAAA,UAAU,GAAG,EAAE,CAAC;;QAEhB,IAAA,CAAA,iBAAiB,GAAG,KAAK;QACzB,IAAA,CAAA,UAAU,GAAG,CAAC;QAId,IAAA,CAAA,QAAQ,GAAG,KAAK;AAGtB,QAAA,IAAI,CAAC,OAAO,GAAG,EAAqB;AACpC,QAAA,IAAI,CAAC,UAAU,GAAG,CAAC,CAAQ,KAAK,IAAI,CAAC,aAAa,CAAC,CAAkB,CAAC;IACxE;AAEA,IAAA,MAAM,CAAC,OAAwB,EAAA;AAC7B,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO;AACtB,QAAA,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU;AAC/B,QAAA,IAAI,CAAC,IAAI;YAAE;;;;;;;;QASX,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC;AACjD,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI;QACpB,IAAI,CAAC,YAAY,EAAE;QACnB,IAAI,CAAC,SAAS,EAAE;IAClB;IAEA,MAAM,GAAA;AACJ,QAAA,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC;AACxE,QAAA,IAAI,CAAC,QAAQ,GAAG,KAAK;IACvB;AAEA;;;;;AAKG;IACK,YAAY,GAAA;AAClB,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC7B,QAAA,IAAI,CAAC,KAAK;YAAE;AAEZ,QAAA,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC;AAClC,QAAA,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC;AACnC,QAAA,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC;AACnE,QAAA,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjE;AAEA;;;;;AAKG;IACH,OAAO,GAAA;QACL,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE;QAEpB,IAAI,CAAC,YAAY,EAAE;QACnB,IAAI,CAAC,SAAS,EAAE;IAClB;IAEQ,QAAQ,GAAA;AACd,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,aAAa,CAAC,OAAO,CAAC,IAAI,IAAI;IAChE;;AAGQ,IAAA,YAAY,CAAC,CAAsC,EAAA;AACzD,QAAA,OAAO,OAAO,CAAC,KAAK,UAAU,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD;AAEA,IAAA,IAAY,aAAa,GAAA;QACvB,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;IAClD;AAEA,IAAA,IAAY,aAAa,GAAA;QACvB,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;IACrD;AAEA,IAAA,IAAY,YAAY,GAAA;AACtB,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;IAC3E;AAEA,IAAA,IAAY,aAAa,GAAA;AACvB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACnE;;AAGQ,IAAA,UAAU,CAAC,KAAa,EAAA;AAC9B,QAAA,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC;AACxE,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC7B,QAAA,IAAI,CAAC,KAAK;AAAE,YAAA,OAAO,IAAI;QACvB,OAAO,KAAK,CAAC,aAAa,CAAC,wBAAwB,KAAK,CAAA,EAAA,CAAI,CAAC;IAC/D;;IAGA,SAAS,GAAA;AACP,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC7B,QAAA,IAAI,CAAC,KAAK;YAAE;AAEZ,QAAA,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC;AACnE,QAAA,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;;AAG/D,QAAA,MAAM,SAAS,GAAG,KAAK,CAAC,aAAa,CAAC,4BAA4B;AAC7D,eAAA,KAAK,CAAC,aAAa,CAAC,yDAAyD,CAAC;QACnF,IAAI,SAAS,EAAE;AACb,YAAA,SAAS,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;AACrC,YAAA,SAAS,CAAC,YAAY,CAAC,eAAe,EAAE,GAAG,CAAC;YAC5C,MAAM,GAAG,GAAG,SAAS,CAAC,gBAAgB,CAAC,IAAI,CAAC;YAC5C,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,KAAI;AACpB,gBAAA,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,cAAc,CAAC;AACvC,gBAAA,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;;gBAG/C,IAAI,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;oBACrC,MAAM,aAAa,GAAG,EAAE,CAAC,aAAa,CAAC,wBAAwB,CAAC;oBAChE,IAAI,aAAa,EAAE;wBACjB,MAAM,IAAI,GAAG,aAAa,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE;AACpD,wBAAA,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;AAAE,4BAAA,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,WAAW,CAAC;AAC5D,6BAAA,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;AAAE,4BAAA,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,YAAY,CAAC;oBACzE;yBAAO;AACL,wBAAA,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC;oBACtC;gBACF;AACF,YAAA,CAAC,CAAC;QACJ;;QAGA,MAAM,QAAQ,GAAG,KAAK,CAAC,gBAAgB,CAAC,+BAA+B,CAAC;QACxE,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,KAAI;AAC1B,YAAA,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;AAC/B,YAAA,GAAG,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAEtE,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,CAAC,eAAe,CAAC,KAAK,MAAM;AAC/D,YAAA,IAAI,UAAU;AAAE,gBAAA,GAAG,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC;;AACpD,gBAAA,GAAG,CAAC,eAAe,CAAC,eAAe,CAAC;YAEzC,MAAM,KAAK,GAAG,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC;YACxC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,KAAI;AACxB,gBAAA,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC;AACrC,gBAAA,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACnD,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;;QAGF,IAAI,CAAC,oBAAoB,EAAE;IAC7B;;IAGA,QAAQ,CAAC,GAAW,EAAE,GAAW,EAAA;AAC/B,QAAA,IAAI,CAAC,UAAU,GAAG,GAAG;AACrB,QAAA,IAAI,CAAC,UAAU,GAAG,GAAG;QACrB,IAAI,CAAC,oBAAoB,EAAE;IAC7B;;IAGA,QAAQ,GAAA;AACN,QAAA,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE;IACvD;IAEQ,oBAAoB,GAAA;;;;QAI1B,IAAI,CAAC,IAAI,CAAC,iBAAiB;YAAE;AAE7B,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC7B,QAAA,IAAI,CAAC,KAAK;YAAE;;QAGZ,KAAK,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,EAAE,IAAG;AACvD,YAAA,EAAE,CAAC,eAAe,CAAC,iBAAiB,CAAC;AACrC,YAAA,EAAE,CAAC,eAAe,CAAC,UAAU,CAAC;AAChC,QAAA,CAAC,CAAC;;QAGF,IAAI,UAAU,GAAuB,IAAI;AACzC,QAAA,IAAI,IAAI,CAAC,UAAU,KAAK,EAAE,EAAE;;YAE1B,MAAM,GAAG,GAAG,KAAK,CAAC,gBAAgB,CAAC,UAAU,CAAC;AAC9C,YAAA,UAAU,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,CAAgB;QAClD;aAAO;;;YAGL,IAAI,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;YAC1C,IAAI,CAAC,GAAG,EAAE;;;gBAGR,IAAI,CAAC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,UAAU,CAAC;gBAChD,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;YACxC;YACA,IAAI,GAAG,EAAE;gBACP,MAAM,KAAK,GAAG,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC;AACxC,gBAAA,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAgB;YACpD;QACF;QAEA,IAAI,UAAU,EAAE;AACd,YAAA,UAAU,CAAC,YAAY,CAAC,iBAAiB,EAAE,MAAM,CAAC;AAClD,YAAA,UAAU,CAAC,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC;QAC1C;IACF;AAEQ,IAAA,aAAa,CAAC,CAAgB,EAAA;;AAEpC,QAAA,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;YAAE;;;;;;QAO9B,MAAM,mBAAmB,GAAG,uHAAuH;QACnJ,MAAM,sBAAsB,GAAG,CAAC,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KACxD,IAAI,YAAY,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAC7D;AACD,QAAA,IAAI,sBAAsB;YAAE;AAE5B,QAAA,IAAI,CAAC,iBAAiB,GAAG,IAAI;AAE7B,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa;AACpC,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa;AAEvC,QAAA,QAAQ,CAAC,CAAC,GAAG;AACX,YAAA,KAAK,WAAW;gBACd,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;gBAC9D,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,cAAc,EAAE;gBACrB;AAEF,YAAA,KAAK,SAAS;gBACZ,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;gBACnD,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,cAAc,EAAE;gBACrB;AAEF,YAAA,KAAK,YAAY;gBACf,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;gBACjE,IAAI,CAAC,oBAAoB,EAAE;gBAC3B;AAEF,YAAA,KAAK,WAAW;gBACd,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;gBAClD,IAAI,CAAC,oBAAoB,EAAE;gBAC3B;AAEF,YAAA,KAAK,MAAM;gBACT,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,CAAC,OAAO,EAAE;AACb,oBAAA,IAAI,CAAC,UAAU,GAAG,EAAE;AACpB,oBAAA,IAAI,CAAC,UAAU,GAAG,CAAC;gBACrB;qBAAO;AACL,oBAAA,IAAI,CAAC,UAAU,GAAG,CAAC;gBACrB;gBACA,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,cAAc,EAAE;gBACrB;AAEF,YAAA,KAAK,KAAK;gBACR,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,CAAC,OAAO,EAAE;AACb,oBAAA,IAAI,CAAC,UAAU,GAAG,SAAS,GAAG,CAAC;AAC/B,oBAAA,IAAI,CAAC,UAAU,GAAG,YAAY,GAAG,CAAC;gBACpC;qBAAO;AACL,oBAAA,IAAI,CAAC,UAAU,GAAG,YAAY,GAAG,CAAC;gBACpC;gBACA,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,cAAc,EAAE;gBACrB;AAEF,YAAA,KAAK,UAAU;gBACb,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;gBAC/D,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,cAAc,EAAE;gBACrB;AAEF,YAAA,KAAK,QAAQ;gBACX,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;gBACnD,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,cAAc,EAAE;gBACrB;AAEF,YAAA,KAAK,GAAG;AACN,gBAAA,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE;oBACxB,CAAC,CAAC,cAAc,EAAE;oBAClB,IAAI,CAAC,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,UAAU,CAAC;gBACnD;gBACA;AAEF,YAAA,KAAK,OAAO;AACV,gBAAA,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE;oBAChD,CAAC,CAAC,cAAc,EAAE;oBAClB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;oBAC5C,MAAM,KAAK,GAAG,GAAG,EAAE,gBAAgB,CAAC,IAAI,CAAC;oBACzC,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC;oBACrC,MAAM,SAAS,GAAG,IAAI,EAAE,YAAY,CAAC,UAAU,CAAC,IAAI,EAAE;AACtD,oBAAA,IAAI,CAAC,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC;gBAC3D;gBACA;AAEF,YAAA,KAAK,GAAG;gBACN,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,EAAE;oBAC1B,CAAC,CAAC,cAAc,EAAE;AAClB,oBAAA,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI;gBAC9B;gBACA;;IAMN;IAEQ,cAAc,GAAA;AACpB,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC7B,QAAA,IAAI,CAAC,KAAK;YAAE;QAEZ,MAAM,SAAS,GAAG,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAgB;QACzE,IAAI,SAAS,EAAE;;AAEb,YAAA,IAAI,OAAO,SAAS,CAAC,cAAc,KAAK,UAAU,EAAE;AAClD,gBAAA,SAAS,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YACnE;AACA,YAAA,IAAI,OAAO,SAAS,CAAC,KAAK,KAAK,UAAU,EAAE;gBACzC,SAAS,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;YAC1C;QACF;IACF;IAEA,UAAU,GAAA;QACR,OAAO,IAAI,CAAC,QAAQ;IACtB;AACD;;;;"}
1
+ {"version":3,"file":"table-keyboard.js","sources":["../../../../components/table/table-keyboard.ts"],"sourcesContent":["/**\n * Keyboard navigation and ARIA for snice-table.\n * Full WAI-ARIA grid pattern with arrow key navigation.\n */\n\nexport interface KeyboardOptions {\n /** The shadow root containing the table */\n shadowRoot: ShadowRoot;\n /** Callback when a cell is activated (Enter) */\n onCellActivate?: (rowIndex: number, columnKey: string) => void;\n /** Callback when selection changes via keyboard */\n onSelectionToggle?: (rowIndex: number) => void;\n /** Callback for select-all (Ctrl+A) */\n onSelectAll?: () => void;\n /** Tab navigation mode */\n tabMode: 'none' | 'content' | 'header' | 'all';\n /**\n * Total data rows. A getter callback keeps bounds live as the dataset is\n * loaded / filtered / paginated; a plain number is accepted for callers that\n * re-attach on every change.\n */\n totalRows: number | (() => number);\n /** Total columns. Getter callback or plain number — see `totalRows`. */\n totalColumns: number | (() => number);\n /**\n * Total rows exposed to assistive technology. This may exceed the keyboard\n * navigation count when the body also contains non-focusable group and\n * aggregate rows. Defaults to totalRows.\n */\n ariaRows?: number | (() => number);\n /** Zero-based logical offset of the first rendered body row (virtual grids). */\n ariaRowOffset?: number | (() => number);\n /**\n * Resolve a keyboard-navigation row to its rendered <tr>. Grouping/filtering\n * can make navigation order differ from raw data-index order.\n */\n getRowElement?: (rowIndex: number) => HTMLElement | null;\n /**\n * Bring a logical (data-index) row into the rendered window before focus\n * lands on it. Under virtualization only the current window is in the DOM;\n * the host scrolls the row's range into view and renders it synchronously.\n */\n ensureRowVisible?: (rowIndex: number) => void;\n /** Whether editing is active */\n isEditing: () => boolean;\n}\n\nexport class TableKeyboard {\n private options: KeyboardOptions;\n private focusedRow = -1; // -1 = header\n /** True after the first real user keydown — no focus paint at rest. */\n private hasUserInteracted = false;\n private focusedCol = 0;\n // EventListener-typed: ShadowRoot's TS event map only knows 'slotchange',\n // so a KeyboardEvent-typed handler fails the addEventListener overloads.\n private keyHandler: EventListener;\n private attached = false;\n\n constructor() {\n this.options = {} as KeyboardOptions;\n this.keyHandler = (e: Event) => this.handleKeyDown(e as KeyboardEvent);\n }\n\n attach(options: KeyboardOptions) {\n this.options = options;\n const root = options.shadowRoot;\n if (!root) return;\n\n // Delegate keydown at the shadow root — a stable ancestor that always\n // exists (even before the first render) and survives every <table> rebuild.\n // Every keydown inside the shadow tree bubbles here, so navigation works no\n // matter when data/columns arrive or how often renderHeader/renderBody\n // replace the table structure. Binding to the inner <table> instead meant a\n // table built after @ready was never listened to, and a rebuilt table\n // silently dropped the listener.\n root.addEventListener('keydown', this.keyHandler);\n this.attached = true;\n this.syncGridRole();\n this.applyARIA();\n }\n\n detach() {\n this.options.shadowRoot?.removeEventListener('keydown', this.keyHandler);\n this.attached = false;\n }\n\n /**\n * (Re)apply the grid identity to the current <table>: role=grid, a focusable\n * tabindex, and live row/col counts. Cheap, idempotent, and safe to call\n * before the table exists (no-op). A structural rebuild that swaps the\n * <table> node drops these attributes, so they must be re-applied afterwards.\n */\n private syncGridRole() {\n const table = this.getTable();\n if (!table) return;\n\n table.setAttribute('role', 'grid');\n table.setAttribute('tabindex', '0');\n table.setAttribute('aria-rowcount', String(this.ariaRowCount + 1)); // +1 header\n table.setAttribute('aria-colcount', String(this.totalColCount));\n }\n\n /**\n * Host hook: called after renderHeader/renderBody rebuild the table. The\n * delegated keydown listener lives on the shadow root so it survives on its\n * own; this restores the grid role and the roving tabindex on the focused\n * cell, both of which a wiped thead/tbody (or a swapped <table>) would lose.\n */\n refresh() {\n if (!this.attached) return;\n\n this.syncGridRole();\n this.applyARIA();\n }\n\n private getTable(): HTMLElement | null {\n return this.options.shadowRoot?.querySelector('table') ?? null;\n }\n\n /** Resolve a bound that may be a live getter or a static number. */\n private resolveBound(v: number | (() => number) | undefined): number {\n return typeof v === 'function' ? v() : (v ?? 0);\n }\n\n private get totalRowCount(): number {\n return this.resolveBound(this.options.totalRows);\n }\n\n private get totalColCount(): number {\n return this.resolveBound(this.options.totalColumns);\n }\n\n private get ariaRowCount(): number {\n return this.resolveBound(this.options.ariaRows ?? this.options.totalRows);\n }\n\n private get ariaRowOffset(): number {\n return Math.max(0, this.resolveBound(this.options.ariaRowOffset));\n }\n\n /** Resolve a body row by its logical data-index (not its DOM position). */\n private getBodyRow(index: number): HTMLElement | null {\n if (this.options.getRowElement) return this.options.getRowElement(index);\n const table = this.getTable();\n if (!table) return null;\n return table.querySelector(`tbody tr[data-index=\"${index}\"]`);\n }\n\n /** Apply ARIA attributes to the grid */\n applyARIA() {\n const table = this.getTable();\n if (!table) return;\n\n table.setAttribute('aria-rowcount', String(this.ariaRowCount + 1)); // +1 for header\n table.setAttribute('aria-colcount', String(this.totalColCount));\n\n // Header row\n const headerRow = table.querySelector('thead tr.column-header-row')\n ?? table.querySelector('thead tr:not(.column-group-row):not(.header-filter-row)');\n if (headerRow) {\n headerRow.setAttribute('role', 'row');\n headerRow.setAttribute('aria-rowindex', '1');\n const ths = headerRow.querySelectorAll('th');\n ths.forEach((th, i) => {\n th.setAttribute('role', 'columnheader');\n th.setAttribute('aria-colindex', String(i + 1));\n\n // Sort state\n if (th.classList.contains('sortable')) {\n const sortIndicator = th.querySelector('.sort-indicator.active');\n if (sortIndicator) {\n const text = sortIndicator.textContent?.trim() || '';\n if (text.includes('▲')) th.setAttribute('aria-sort', 'ascending');\n else if (text.includes('▼')) th.setAttribute('aria-sort', 'descending');\n } else {\n th.setAttribute('aria-sort', 'none');\n }\n }\n });\n }\n\n // Body rows\n const bodyRows = table.querySelectorAll('tbody tr:not(.virtual-spacer):not(.table-fill-row)');\n bodyRows.forEach((row, i) => {\n row.setAttribute('role', 'row');\n row.setAttribute('aria-rowindex', String(this.ariaRowOffset + i + 2)); // +2 for 1-based + header\n\n const isSelected = row.getAttribute('data-selected') === 'true';\n if (isSelected) row.setAttribute('aria-selected', 'true');\n else row.removeAttribute('aria-selected');\n\n const cells = row.querySelectorAll('td');\n cells.forEach((cell, j) => {\n cell.setAttribute('role', 'gridcell');\n cell.setAttribute('aria-colindex', String(j + 1));\n });\n });\n\n // Set roving tabindex on focused cell\n this.updateFocusIndicator();\n }\n\n /** Set focus position */\n setFocus(row: number, col: number) {\n this.focusedRow = row;\n this.focusedCol = col;\n this.updateFocusIndicator();\n }\n\n /** Get current focus position */\n getFocus(): { row: number; col: number } {\n return { row: this.focusedRow, col: this.focusedCol };\n }\n\n private updateFocusIndicator() {\n // A grid that was never keyboard-focused must not wear focus styling —\n // refresh() runs after every renderBody, and painting the default header\n // position (focusedRow=-1) put a stuck blue ring on every table at rest.\n if (!this.hasUserInteracted) return;\n\n const table = this.getTable();\n if (!table) return;\n\n // Remove previous focus\n table.querySelectorAll('[data-grid-focus]').forEach(el => {\n el.removeAttribute('data-grid-focus');\n el.removeAttribute('tabindex');\n });\n\n // Find target cell\n let targetCell: HTMLElement | null = null;\n if (this.focusedRow === -1) {\n // Header\n const ths = table.querySelectorAll('thead th');\n targetCell = ths[this.focusedCol] as HTMLElement;\n } else {\n // Resolve by logical data-index, not DOM position: under virtualization\n // only the current window is in the DOM.\n let row = this.getBodyRow(this.focusedRow);\n if (!row) {\n // Outside the rendered window — ask the host to scroll it into view,\n // then look again.\n this.options.ensureRowVisible?.(this.focusedRow);\n row = this.getBodyRow(this.focusedRow);\n }\n if (row) {\n const cells = row.querySelectorAll('td');\n targetCell = cells[this.focusedCol] as HTMLElement;\n }\n }\n\n if (targetCell) {\n targetCell.setAttribute('data-grid-focus', 'true');\n targetCell.setAttribute('tabindex', '0');\n }\n }\n\n private handleKeyDown(e: KeyboardEvent) {\n // Don't handle when editing\n if (this.options.isEditing()) return;\n\n // Let controls inside the grid keep their native keyboard contract. This\n // includes group/tree toggle buttons (Enter/Space must click them), row\n // checkboxes, links, and form controls rendered by custom cells. Inspect\n // the composed path so controls nested in another component's shadow root\n // are recognized too.\n const interactiveSelector = 'button, a, input, select, textarea, [contenteditable=\"true\"], snice-button, snice-checkbox, snice-input, snice-select';\n const fromInteractiveControl = e.composedPath().some((node) =>\n node instanceof Element && node.matches(interactiveSelector)\n );\n if (fromInteractiveControl) return;\n\n this.hasUserInteracted = true;\n\n const totalRows = this.totalRowCount;\n const totalColumns = this.totalColCount;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n this.focusedRow = Math.min(totalRows - 1, this.focusedRow + 1);\n this.updateFocusIndicator();\n this.scrollIntoView();\n break;\n\n case 'ArrowUp':\n e.preventDefault();\n this.focusedRow = Math.max(-1, this.focusedRow - 1);\n this.updateFocusIndicator();\n this.scrollIntoView();\n break;\n\n case 'ArrowRight':\n e.preventDefault();\n this.focusedCol = Math.min(totalColumns - 1, this.focusedCol + 1);\n this.updateFocusIndicator();\n break;\n\n case 'ArrowLeft':\n e.preventDefault();\n this.focusedCol = Math.max(0, this.focusedCol - 1);\n this.updateFocusIndicator();\n break;\n\n case 'Home':\n e.preventDefault();\n if (e.ctrlKey) {\n this.focusedRow = -1;\n this.focusedCol = 0;\n } else {\n this.focusedCol = 0;\n }\n this.updateFocusIndicator();\n this.scrollIntoView();\n break;\n\n case 'End':\n e.preventDefault();\n if (e.ctrlKey) {\n this.focusedRow = totalRows - 1;\n this.focusedCol = totalColumns - 1;\n } else {\n this.focusedCol = totalColumns - 1;\n }\n this.updateFocusIndicator();\n this.scrollIntoView();\n break;\n\n case 'PageDown':\n e.preventDefault();\n this.focusedRow = Math.min(totalRows - 1, this.focusedRow + 10);\n this.updateFocusIndicator();\n this.scrollIntoView();\n break;\n\n case 'PageUp':\n e.preventDefault();\n this.focusedRow = Math.max(0, this.focusedRow - 10);\n this.updateFocusIndicator();\n this.scrollIntoView();\n break;\n\n case ' ':\n if (this.focusedRow >= 0) {\n e.preventDefault();\n this.options.onSelectionToggle?.(this.focusedRow);\n }\n break;\n\n case 'Enter':\n if (this.focusedRow >= 0 && this.focusedCol >= 0) {\n e.preventDefault();\n const row = this.getBodyRow(this.focusedRow);\n const cells = row?.querySelectorAll('td');\n const cell = cells?.[this.focusedCol];\n const columnKey = cell?.getAttribute('data-key') || '';\n this.options.onCellActivate?.(this.focusedRow, columnKey);\n }\n break;\n\n case 'a':\n if (e.ctrlKey || e.metaKey) {\n e.preventDefault();\n this.options.onSelectAll?.();\n }\n break;\n\n case 'Escape':\n // Let this bubble up to cancel editing\n break;\n }\n }\n\n private scrollIntoView() {\n const table = this.getTable();\n if (!table) return;\n\n const focusedEl = table.querySelector('[data-grid-focus]') as HTMLElement;\n if (focusedEl) {\n // Guard: layout APIs are not implemented in some non-browser DOMs.\n if (typeof focusedEl.scrollIntoView === 'function') {\n focusedEl.scrollIntoView({ block: 'nearest', inline: 'nearest' });\n }\n if (typeof focusedEl.focus === 'function') {\n focusedEl.focus({ preventScroll: true });\n }\n }\n }\n\n isAttached(): boolean {\n return this.attached;\n }\n}\n"],"names":[],"mappings":"AAAA;;;AAGG;MA4CU,aAAa,CAAA;AAWxB,IAAA,WAAA,GAAA;AATQ,QAAA,IAAA,CAAA,UAAU,GAAG,EAAE,CAAC;;QAEhB,IAAA,CAAA,iBAAiB,GAAG,KAAK;QACzB,IAAA,CAAA,UAAU,GAAG,CAAC;QAId,IAAA,CAAA,QAAQ,GAAG,KAAK;AAGtB,QAAA,IAAI,CAAC,OAAO,GAAG,EAAqB;AACpC,QAAA,IAAI,CAAC,UAAU,GAAG,CAAC,CAAQ,KAAK,IAAI,CAAC,aAAa,CAAC,CAAkB,CAAC;IACxE;AAEA,IAAA,MAAM,CAAC,OAAwB,EAAA;AAC7B,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO;AACtB,QAAA,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU;AAC/B,QAAA,IAAI,CAAC,IAAI;YAAE;;;;;;;;QASX,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC;AACjD,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI;QACpB,IAAI,CAAC,YAAY,EAAE;QACnB,IAAI,CAAC,SAAS,EAAE;IAClB;IAEA,MAAM,GAAA;AACJ,QAAA,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC;AACxE,QAAA,IAAI,CAAC,QAAQ,GAAG,KAAK;IACvB;AAEA;;;;;AAKG;IACK,YAAY,GAAA;AAClB,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC7B,QAAA,IAAI,CAAC,KAAK;YAAE;AAEZ,QAAA,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC;AAClC,QAAA,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC;AACnC,QAAA,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC;AACnE,QAAA,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjE;AAEA;;;;;AAKG;IACH,OAAO,GAAA;QACL,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE;QAEpB,IAAI,CAAC,YAAY,EAAE;QACnB,IAAI,CAAC,SAAS,EAAE;IAClB;IAEQ,QAAQ,GAAA;AACd,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,aAAa,CAAC,OAAO,CAAC,IAAI,IAAI;IAChE;;AAGQ,IAAA,YAAY,CAAC,CAAsC,EAAA;AACzD,QAAA,OAAO,OAAO,CAAC,KAAK,UAAU,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD;AAEA,IAAA,IAAY,aAAa,GAAA;QACvB,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;IAClD;AAEA,IAAA,IAAY,aAAa,GAAA;QACvB,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;IACrD;AAEA,IAAA,IAAY,YAAY,GAAA;AACtB,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;IAC3E;AAEA,IAAA,IAAY,aAAa,GAAA;AACvB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACnE;;AAGQ,IAAA,UAAU,CAAC,KAAa,EAAA;AAC9B,QAAA,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC;AACxE,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC7B,QAAA,IAAI,CAAC,KAAK;AAAE,YAAA,OAAO,IAAI;QACvB,OAAO,KAAK,CAAC,aAAa,CAAC,wBAAwB,KAAK,CAAA,EAAA,CAAI,CAAC;IAC/D;;IAGA,SAAS,GAAA;AACP,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC7B,QAAA,IAAI,CAAC,KAAK;YAAE;AAEZ,QAAA,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC;AACnE,QAAA,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;;AAG/D,QAAA,MAAM,SAAS,GAAG,KAAK,CAAC,aAAa,CAAC,4BAA4B;AAC7D,eAAA,KAAK,CAAC,aAAa,CAAC,yDAAyD,CAAC;QACnF,IAAI,SAAS,EAAE;AACb,YAAA,SAAS,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;AACrC,YAAA,SAAS,CAAC,YAAY,CAAC,eAAe,EAAE,GAAG,CAAC;YAC5C,MAAM,GAAG,GAAG,SAAS,CAAC,gBAAgB,CAAC,IAAI,CAAC;YAC5C,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,KAAI;AACpB,gBAAA,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,cAAc,CAAC;AACvC,gBAAA,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;;gBAG/C,IAAI,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;oBACrC,MAAM,aAAa,GAAG,EAAE,CAAC,aAAa,CAAC,wBAAwB,CAAC;oBAChE,IAAI,aAAa,EAAE;wBACjB,MAAM,IAAI,GAAG,aAAa,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE;AACpD,wBAAA,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;AAAE,4BAAA,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,WAAW,CAAC;AAC5D,6BAAA,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;AAAE,4BAAA,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,YAAY,CAAC;oBACzE;yBAAO;AACL,wBAAA,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC;oBACtC;gBACF;AACF,YAAA,CAAC,CAAC;QACJ;;QAGA,MAAM,QAAQ,GAAG,KAAK,CAAC,gBAAgB,CAAC,oDAAoD,CAAC;QAC7F,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,KAAI;AAC1B,YAAA,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;AAC/B,YAAA,GAAG,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAEtE,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,CAAC,eAAe,CAAC,KAAK,MAAM;AAC/D,YAAA,IAAI,UAAU;AAAE,gBAAA,GAAG,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC;;AACpD,gBAAA,GAAG,CAAC,eAAe,CAAC,eAAe,CAAC;YAEzC,MAAM,KAAK,GAAG,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC;YACxC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,KAAI;AACxB,gBAAA,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC;AACrC,gBAAA,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACnD,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;;QAGF,IAAI,CAAC,oBAAoB,EAAE;IAC7B;;IAGA,QAAQ,CAAC,GAAW,EAAE,GAAW,EAAA;AAC/B,QAAA,IAAI,CAAC,UAAU,GAAG,GAAG;AACrB,QAAA,IAAI,CAAC,UAAU,GAAG,GAAG;QACrB,IAAI,CAAC,oBAAoB,EAAE;IAC7B;;IAGA,QAAQ,GAAA;AACN,QAAA,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE;IACvD;IAEQ,oBAAoB,GAAA;;;;QAI1B,IAAI,CAAC,IAAI,CAAC,iBAAiB;YAAE;AAE7B,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC7B,QAAA,IAAI,CAAC,KAAK;YAAE;;QAGZ,KAAK,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,EAAE,IAAG;AACvD,YAAA,EAAE,CAAC,eAAe,CAAC,iBAAiB,CAAC;AACrC,YAAA,EAAE,CAAC,eAAe,CAAC,UAAU,CAAC;AAChC,QAAA,CAAC,CAAC;;QAGF,IAAI,UAAU,GAAuB,IAAI;AACzC,QAAA,IAAI,IAAI,CAAC,UAAU,KAAK,EAAE,EAAE;;YAE1B,MAAM,GAAG,GAAG,KAAK,CAAC,gBAAgB,CAAC,UAAU,CAAC;AAC9C,YAAA,UAAU,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,CAAgB;QAClD;aAAO;;;YAGL,IAAI,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;YAC1C,IAAI,CAAC,GAAG,EAAE;;;gBAGR,IAAI,CAAC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,UAAU,CAAC;gBAChD,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;YACxC;YACA,IAAI,GAAG,EAAE;gBACP,MAAM,KAAK,GAAG,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC;AACxC,gBAAA,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAgB;YACpD;QACF;QAEA,IAAI,UAAU,EAAE;AACd,YAAA,UAAU,CAAC,YAAY,CAAC,iBAAiB,EAAE,MAAM,CAAC;AAClD,YAAA,UAAU,CAAC,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC;QAC1C;IACF;AAEQ,IAAA,aAAa,CAAC,CAAgB,EAAA;;AAEpC,QAAA,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;YAAE;;;;;;QAO9B,MAAM,mBAAmB,GAAG,uHAAuH;QACnJ,MAAM,sBAAsB,GAAG,CAAC,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KACxD,IAAI,YAAY,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAC7D;AACD,QAAA,IAAI,sBAAsB;YAAE;AAE5B,QAAA,IAAI,CAAC,iBAAiB,GAAG,IAAI;AAE7B,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa;AACpC,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa;AAEvC,QAAA,QAAQ,CAAC,CAAC,GAAG;AACX,YAAA,KAAK,WAAW;gBACd,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;gBAC9D,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,cAAc,EAAE;gBACrB;AAEF,YAAA,KAAK,SAAS;gBACZ,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;gBACnD,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,cAAc,EAAE;gBACrB;AAEF,YAAA,KAAK,YAAY;gBACf,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;gBACjE,IAAI,CAAC,oBAAoB,EAAE;gBAC3B;AAEF,YAAA,KAAK,WAAW;gBACd,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;gBAClD,IAAI,CAAC,oBAAoB,EAAE;gBAC3B;AAEF,YAAA,KAAK,MAAM;gBACT,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,CAAC,OAAO,EAAE;AACb,oBAAA,IAAI,CAAC,UAAU,GAAG,EAAE;AACpB,oBAAA,IAAI,CAAC,UAAU,GAAG,CAAC;gBACrB;qBAAO;AACL,oBAAA,IAAI,CAAC,UAAU,GAAG,CAAC;gBACrB;gBACA,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,cAAc,EAAE;gBACrB;AAEF,YAAA,KAAK,KAAK;gBACR,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,CAAC,OAAO,EAAE;AACb,oBAAA,IAAI,CAAC,UAAU,GAAG,SAAS,GAAG,CAAC;AAC/B,oBAAA,IAAI,CAAC,UAAU,GAAG,YAAY,GAAG,CAAC;gBACpC;qBAAO;AACL,oBAAA,IAAI,CAAC,UAAU,GAAG,YAAY,GAAG,CAAC;gBACpC;gBACA,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,cAAc,EAAE;gBACrB;AAEF,YAAA,KAAK,UAAU;gBACb,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;gBAC/D,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,cAAc,EAAE;gBACrB;AAEF,YAAA,KAAK,QAAQ;gBACX,CAAC,CAAC,cAAc,EAAE;AAClB,gBAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;gBACnD,IAAI,CAAC,oBAAoB,EAAE;gBAC3B,IAAI,CAAC,cAAc,EAAE;gBACrB;AAEF,YAAA,KAAK,GAAG;AACN,gBAAA,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE;oBACxB,CAAC,CAAC,cAAc,EAAE;oBAClB,IAAI,CAAC,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,UAAU,CAAC;gBACnD;gBACA;AAEF,YAAA,KAAK,OAAO;AACV,gBAAA,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE;oBAChD,CAAC,CAAC,cAAc,EAAE;oBAClB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;oBAC5C,MAAM,KAAK,GAAG,GAAG,EAAE,gBAAgB,CAAC,IAAI,CAAC;oBACzC,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC;oBACrC,MAAM,SAAS,GAAG,IAAI,EAAE,YAAY,CAAC,UAAU,CAAC,IAAI,EAAE;AACtD,oBAAA,IAAI,CAAC,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC;gBAC3D;gBACA;AAEF,YAAA,KAAK,GAAG;gBACN,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,EAAE;oBAC1B,CAAC,CAAC,cAAc,EAAE;AAClB,oBAAA,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI;gBAC9B;gBACA;;IAMN;IAEQ,cAAc,GAAA;AACpB,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC7B,QAAA,IAAI,CAAC,KAAK;YAAE;QAEZ,MAAM,SAAS,GAAG,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAgB;QACzE,IAAI,SAAS,EAAE;;AAEb,YAAA,IAAI,OAAO,SAAS,CAAC,cAAc,KAAK,UAAU,EAAE;AAClD,gBAAA,SAAS,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YACnE;AACA,YAAA,IAAI,OAAO,SAAS,CAAC,KAAK,KAAK,UAAU,EAAE;gBACzC,SAAS,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;YAC1C;QACF;IACF;IAEA,UAAU,GAAA;QACR,OAAO,IAAI,CAAC,QAAQ;IACtB;AACD;;;;"}
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
package/dist/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
package/dist/symbols.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.6.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -140,7 +140,7 @@ All CDN builds use the shared runtime (external `snice` imports). Load `snice-ru
140
140
  - IIFE: `.js` + `.min.js`
141
141
  - Sourcemaps + README
142
142
 
143
- **Size:** Runtime ~34KB gzip, components ~1-110KB each
143
+ **Size:** Runtime ~34KB gzip, components ~1-111KB each
144
144
 
145
145
  **Features:**
146
146
  - Shared runtime (external snice imports)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snice",
3
- "version": "7.6.0",
3
+ "version": "7.7.0",
4
4
  "type": "module",
5
5
  "description": "A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.",
6
6
  "main": "dist/index.cjs",