snice 7.7.0 → 7.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapters/react/SniceProvider.js +1 -1
- package/adapters/react/SniceRouter.js +1 -1
- package/adapters/react/calendar.d.ts +1 -0
- package/adapters/react/calendar.d.ts.map +1 -1
- package/adapters/react/calendar.js +1 -1
- package/adapters/react/calendar.js.map +1 -1
- package/adapters/react/calendar.tsx +2 -1
- package/adapters/react/matchRoute.js +1 -1
- package/adapters/react/useRequestHandler.js +1 -1
- package/bin/analyzer-contracts.js +8 -2
- package/custom-elements.json +5 -1
- package/dist/cdn/accordion/snice-accordion.js +1 -1
- package/dist/cdn/action-bar/snice-action-bar.js +1 -1
- package/dist/cdn/activity-feed/snice-activity-feed.js +1 -1
- package/dist/cdn/alert/snice-alert.js +1 -1
- package/dist/cdn/app-tiles/snice-app-tiles.js +1 -1
- package/dist/cdn/approval-flow/snice-approval-flow.js +1 -1
- package/dist/cdn/audio-recorder/snice-audio-recorder.js +1 -1
- package/dist/cdn/availability/snice-availability.js +1 -1
- package/dist/cdn/avatar/snice-avatar.js +1 -1
- package/dist/cdn/avatar-group/snice-avatar-group.js +1 -1
- package/dist/cdn/badge/snice-badge.js +1 -1
- package/dist/cdn/banner/snice-banner.js +1 -1
- package/dist/cdn/binpack/snice-binpack.js +1 -1
- package/dist/cdn/book/snice-book.js +1 -1
- package/dist/cdn/booking/snice-booking.js +1 -1
- package/dist/cdn/breadcrumbs/snice-breadcrumbs.js +1 -1
- package/dist/cdn/button/snice-button.js +1 -1
- package/dist/cdn/calendar/README.md +2 -2
- package/dist/cdn/calendar/snice-calendar.js +26 -2
- package/dist/cdn/calendar/snice-calendar.js.map +1 -1
- package/dist/cdn/calendar/snice-calendar.min.js +2 -2
- package/dist/cdn/calendar/snice-calendar.min.js.map +1 -1
- package/dist/cdn/camera/snice-camera.js +1 -1
- package/dist/cdn/camera-annotate/snice-camera-annotate.js +1 -1
- package/dist/cdn/candlestick/snice-candlestick.js +1 -1
- package/dist/cdn/card/snice-card.js +1 -1
- package/dist/cdn/carousel/snice-carousel.js +1 -1
- package/dist/cdn/cart/snice-cart.js +1 -1
- package/dist/cdn/chart/snice-chart.js +1 -1
- package/dist/cdn/chat/snice-chat.js +1 -1
- package/dist/cdn/checkbox/snice-checkbox.js +1 -1
- package/dist/cdn/chip/snice-chip.js +1 -1
- package/dist/cdn/code-block/snice-code-block.js +1 -1
- package/dist/cdn/color-display/snice-color-display.js +1 -1
- package/dist/cdn/color-picker/snice-color-picker.js +1 -1
- package/dist/cdn/command-palette/snice-command-palette.js +1 -1
- package/dist/cdn/comments/snice-comments.js +1 -1
- package/dist/cdn/countdown/snice-countdown.js +1 -1
- package/dist/cdn/cropper/snice-cropper.js +1 -1
- package/dist/cdn/data-card/snice-data-card.js +1 -1
- package/dist/cdn/date-picker/snice-date-picker.js +1 -1
- package/dist/cdn/date-range-picker/snice-date-range-picker.js +1 -1
- package/dist/cdn/date-time-picker/snice-date-time-picker.js +1 -1
- package/dist/cdn/diff/snice-diff.js +1 -1
- package/dist/cdn/divider/snice-divider.js +1 -1
- package/dist/cdn/doc/snice-doc.js +1 -1
- package/dist/cdn/draw/snice-draw.js +1 -1
- package/dist/cdn/drawer/snice-drawer.js +1 -1
- package/dist/cdn/empty-state/snice-empty-state.js +1 -1
- package/dist/cdn/estimate/snice-estimate.js +1 -1
- package/dist/cdn/file-gallery/snice-file-gallery.js +1 -1
- package/dist/cdn/file-upload/snice-file-upload.js +1 -1
- package/dist/cdn/flip-card/snice-flip-card.js +1 -1
- package/dist/cdn/flow/snice-flow.js +1 -1
- package/dist/cdn/form-layout/snice-form-layout.js +1 -1
- package/dist/cdn/funnel/snice-funnel.js +1 -1
- package/dist/cdn/gantt/snice-gantt.js +1 -1
- package/dist/cdn/gauge/snice-gauge.js +1 -1
- package/dist/cdn/grid/snice-grid.js +1 -1
- package/dist/cdn/heatmap/snice-heatmap.js +1 -1
- package/dist/cdn/image/snice-image.js +1 -1
- package/dist/cdn/input/snice-input.js +1 -1
- package/dist/cdn/invoice/snice-invoice.js +1 -1
- package/dist/cdn/kanban/snice-kanban.js +1 -1
- package/dist/cdn/key-value/snice-key-value.js +1 -1
- package/dist/cdn/kpi/snice-kpi.js +1 -1
- package/dist/cdn/layout/snice-layout.js +1 -1
- package/dist/cdn/leaderboard/snice-leaderboard.js +1 -1
- package/dist/cdn/link/snice-link.js +1 -1
- package/dist/cdn/link-preview/snice-link-preview.js +1 -1
- package/dist/cdn/list/snice-list.js +1 -1
- package/dist/cdn/location/snice-location.js +1 -1
- package/dist/cdn/login/snice-login.js +1 -1
- package/dist/cdn/map/snice-map.js +1 -1
- package/dist/cdn/markdown/snice-markdown.js +1 -1
- package/dist/cdn/masonry/snice-masonry.js +1 -1
- package/dist/cdn/menu/snice-menu.js +1 -1
- package/dist/cdn/message-strip/snice-message-strip.js +1 -1
- package/dist/cdn/modal/snice-modal.js +1 -1
- package/dist/cdn/music-player/snice-music-player.js +1 -1
- package/dist/cdn/nav/snice-nav.js +1 -1
- package/dist/cdn/network-graph/snice-network-graph.js +1 -1
- package/dist/cdn/notification-center/snice-notification-center.js +1 -1
- package/dist/cdn/order-tracker/snice-order-tracker.js +1 -1
- package/dist/cdn/org-chart/snice-org-chart.js +1 -1
- package/dist/cdn/pagination/snice-pagination.js +1 -1
- package/dist/cdn/paint/snice-paint.js +1 -1
- package/dist/cdn/pdf-viewer/snice-pdf-viewer.js +1 -1
- package/dist/cdn/permission-matrix/snice-permission-matrix.js +1 -1
- package/dist/cdn/podcast-player/snice-podcast-player.js +1 -1
- package/dist/cdn/popover/snice-popover.js +1 -1
- package/dist/cdn/pricing-table/snice-pricing-table.js +1 -1
- package/dist/cdn/product-card/snice-product-card.js +1 -1
- package/dist/cdn/progress/snice-progress.js +1 -1
- package/dist/cdn/progress-ring/snice-progress-ring.js +1 -1
- package/dist/cdn/qr-code/snice-qr-code.js +1 -1
- package/dist/cdn/qr-reader/snice-qr-reader.js +1 -1
- package/dist/cdn/radio/snice-radio.js +1 -1
- package/dist/cdn/range-slider/snice-range-slider.js +1 -1
- package/dist/cdn/rating/snice-rating.js +1 -1
- package/dist/cdn/receipt/snice-receipt.js +1 -1
- package/dist/cdn/recipe/snice-recipe.js +1 -1
- package/dist/cdn/runtime/README.md +2 -2
- package/dist/cdn/runtime/snice-runtime.esm.js +130 -31
- package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.esm.min.js +1 -1
- package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.js +130 -31
- package/dist/cdn/runtime/snice-runtime.js.map +1 -1
- package/dist/cdn/runtime/snice-runtime.min.js +1 -1
- package/dist/cdn/runtime/snice-runtime.min.js.map +1 -1
- package/dist/cdn/sankey/snice-sankey.js +1 -1
- package/dist/cdn/segmented-control/snice-segmented-control.js +1 -1
- package/dist/cdn/select/snice-select.js +1 -1
- package/dist/cdn/skeleton/snice-skeleton.js +1 -1
- package/dist/cdn/slider/snice-slider.js +1 -1
- package/dist/cdn/sortable/snice-sortable.js +1 -1
- package/dist/cdn/sparkline/snice-sparkline.js +1 -1
- package/dist/cdn/spinner/snice-spinner.js +1 -1
- package/dist/cdn/split-button/snice-split-button.js +1 -1
- package/dist/cdn/split-pane/snice-split-pane.js +1 -1
- package/dist/cdn/spotlight/snice-spotlight.js +1 -1
- package/dist/cdn/stat-group/snice-stat-group.js +1 -1
- package/dist/cdn/step-input/snice-step-input.js +1 -1
- package/dist/cdn/stepper/snice-stepper.js +1 -1
- package/dist/cdn/switch/snice-switch.js +1 -1
- package/dist/cdn/table/README.md +2 -2
- package/dist/cdn/table/snice-table.esm.js +157 -33
- package/dist/cdn/table/snice-table.esm.js.map +1 -1
- package/dist/cdn/table/snice-table.esm.min.js +4 -4
- package/dist/cdn/table/snice-table.esm.min.js.map +1 -1
- package/dist/cdn/table/snice-table.js +157 -33
- package/dist/cdn/table/snice-table.js.map +1 -1
- package/dist/cdn/table/snice-table.min.js +33 -33
- package/dist/cdn/table/snice-table.min.js.map +1 -1
- package/dist/cdn/tabs/snice-tabs.js +1 -1
- package/dist/cdn/tag/snice-tag.js +1 -1
- package/dist/cdn/tag-input/README.md +2 -2
- package/dist/cdn/tag-input/snice-tag-input.js +10 -16
- package/dist/cdn/tag-input/snice-tag-input.js.map +1 -1
- package/dist/cdn/tag-input/snice-tag-input.min.js +2 -2
- package/dist/cdn/tag-input/snice-tag-input.min.js.map +1 -1
- package/dist/cdn/terminal/snice-terminal.js +1 -1
- package/dist/cdn/testimonial/snice-testimonial.js +1 -1
- package/dist/cdn/textarea/snice-textarea.js +1 -1
- package/dist/cdn/time-picker/snice-time-picker.js +1 -1
- package/dist/cdn/time-range-picker/snice-time-range-picker.js +1 -1
- package/dist/cdn/timeline/snice-timeline.js +1 -1
- package/dist/cdn/timer/snice-timer.js +1 -1
- package/dist/cdn/toast/snice-toast.js +1 -1
- package/dist/cdn/tooltip/snice-tooltip.js +1 -1
- package/dist/cdn/tree/snice-tree.js +1 -1
- package/dist/cdn/treemap/snice-treemap.js +1 -1
- package/dist/cdn/user-card/snice-user-card.js +1 -1
- package/dist/cdn/video-player/snice-video-player.js +1 -1
- package/dist/cdn/virtual-scroller/snice-virtual-scroller.js +1 -1
- package/dist/cdn/waterfall/snice-waterfall.js +1 -1
- package/dist/cdn/weather/snice-weather.js +1 -1
- package/dist/cdn/work-order/snice-work-order.js +1 -1
- package/dist/components/calendar/snice-calendar.d.ts +2 -0
- package/dist/components/calendar/snice-calendar.js +25 -1
- package/dist/components/calendar/snice-calendar.js.map +1 -1
- package/dist/components/table/snice-row.d.ts +6 -0
- package/dist/components/table/snice-row.js +11 -3
- package/dist/components/table/snice-row.js.map +1 -1
- package/dist/components/table/snice-table.d.ts +31 -3
- package/dist/components/table/snice-table.js +89 -16
- package/dist/components/table/snice-table.js.map +1 -1
- package/dist/components/table/table-cell-presentation.d.ts +11 -0
- package/dist/components/table/table-cell-presentation.js +25 -8
- package/dist/components/table/table-cell-presentation.js.map +1 -1
- package/dist/components/table/table-export.d.ts +6 -0
- package/dist/components/table/table-export.js +11 -2
- package/dist/components/table/table-export.js.map +1 -1
- package/dist/components/table/table-master-detail.d.ts +11 -2
- package/dist/components/table/table-master-detail.js +20 -3
- package/dist/components/table/table-master-detail.js.map +1 -1
- package/dist/components/tag-input/snice-tag-input.d.ts +2 -2
- package/dist/components/tag-input/snice-tag-input.js +9 -15
- package/dist/components/tag-input/snice-tag-input.js.map +1 -1
- package/dist/index.cjs +127 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +127 -28
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +127 -28
- package/dist/index.iife.js.map +1 -1
- package/dist/react/SniceProvider.js +1 -1
- package/dist/react/SniceRouter.js +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/matchRoute.js +1 -1
- package/dist/react/useRequestHandler.js +1 -1
- package/dist/request-response.d.ts +24 -1
- package/dist/symbols.cjs +1 -1
- package/dist/symbols.esm.js +1 -1
- package/dist/testing-dom.cjs +1 -1
- package/dist/testing-dom.esm.js +1 -1
- package/dist/transitions.cjs +1 -1
- package/dist/transitions.esm.js +1 -1
- package/docs/ai/components/calendar.md +8 -0
- package/docs/ai/components/tag-input.md +4 -0
- package/docs/ai/controllers.md +22 -6
- package/docs/components/calendar.md +24 -0
- package/docs/components/tag-input.md +6 -1
- package/docs/controllers.md +57 -6
- package/package.json +1 -1
|
@@ -3,6 +3,17 @@ import type { ColumnDefinition } from './snice-table.types';
|
|
|
3
3
|
* Give every standalone specialized table cell the common ColumnDefinition
|
|
4
4
|
* presentation contract. The observer reapplies after Snice's differential
|
|
5
5
|
* renderer changes shadow content; equality guards prevent mutation loops.
|
|
6
|
+
*
|
|
7
|
+
* Display formatters
|
|
8
|
+
* ------------------
|
|
9
|
+
* `formatter` is the column's display formatter and `valueFormatter` its
|
|
10
|
+
* fallback, so `formatter` wins. `formatterOverride` says the cell does NOT
|
|
11
|
+
* apply `column.formatter` itself, so this module owns both formatters for it.
|
|
12
|
+
*
|
|
13
|
+
* A host marked `formatted` was handed its display text as `value` by the
|
|
14
|
+
* table, which already resolved the pipeline. Its content is that text
|
|
15
|
+
* verbatim — the marker exists so a rating/progress/link/tag cell, which
|
|
16
|
+
* renders structure rather than text, still shows the formatted string.
|
|
6
17
|
*/
|
|
7
18
|
export declare function installCellPresentation(host: HTMLElement & {
|
|
8
19
|
column?: ColumnDefinition | null;
|
|
@@ -12,6 +12,17 @@ const appliedClasses = new WeakMap();
|
|
|
12
12
|
* Give every standalone specialized table cell the common ColumnDefinition
|
|
13
13
|
* presentation contract. The observer reapplies after Snice's differential
|
|
14
14
|
* renderer changes shadow content; equality guards prevent mutation loops.
|
|
15
|
+
*
|
|
16
|
+
* Display formatters
|
|
17
|
+
* ------------------
|
|
18
|
+
* `formatter` is the column's display formatter and `valueFormatter` its
|
|
19
|
+
* fallback, so `formatter` wins. `formatterOverride` says the cell does NOT
|
|
20
|
+
* apply `column.formatter` itself, so this module owns both formatters for it.
|
|
21
|
+
*
|
|
22
|
+
* A host marked `formatted` was handed its display text as `value` by the
|
|
23
|
+
* table, which already resolved the pipeline. Its content is that text
|
|
24
|
+
* verbatim — the marker exists so a rating/progress/link/tag cell, which
|
|
25
|
+
* renders structure rather than text, still shows the formatted string.
|
|
15
26
|
*/
|
|
16
27
|
function installCellPresentation(host, formatterOverride = false) {
|
|
17
28
|
if (installed.has(host))
|
|
@@ -58,15 +69,21 @@ function installCellPresentation(host, formatterOverride = false) {
|
|
|
58
69
|
? column.tooltip(host.value, host.rowData)
|
|
59
70
|
: (host.value == null ? '' : String(host.value));
|
|
60
71
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
72
|
+
// `formatter` beats `valueFormatter`. A cell that applies `formatter`
|
|
73
|
+
// itself has already painted it, so the fallback must not overwrite that
|
|
74
|
+
// content — only a formatter-less column falls through to valueFormatter.
|
|
75
|
+
const formatter = column.formatter
|
|
76
|
+
? (formatterOverride ? column.formatter : null)
|
|
77
|
+
: column.valueFormatter;
|
|
78
|
+
// Pre-formatted hosts read the attribute, not the property: a cell whose
|
|
79
|
+
// value property is typed (boolean, number) coerces the display string.
|
|
80
|
+
const display = host.hasAttribute('formatted')
|
|
81
|
+
? (host.getAttribute('value') ?? '')
|
|
82
|
+
: (formatter ? String(formatter(host.value, host.rowData) ?? '') : null);
|
|
83
|
+
if (display !== null) {
|
|
65
84
|
const content = host.shadowRoot?.querySelector('[part~="content"]');
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
if (content.textContent !== value || content.childElementCount > 0)
|
|
69
|
-
content.textContent = value;
|
|
85
|
+
if (content && (content.textContent !== display || content.childElementCount > 0)) {
|
|
86
|
+
content.textContent = display;
|
|
70
87
|
}
|
|
71
88
|
}
|
|
72
89
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-cell-presentation.js","sources":["../../../../components/table/table-cell-presentation.ts"],"sourcesContent":["import type { ColumnDefinition, CellStyle } from './snice-table.types';\n\nconst presentationProperties: Array<keyof CellStyle> = [\n 'backgroundColor',\n 'color',\n 'fontWeight',\n 'fontStyle',\n 'fontSize',\n 'textDecoration',\n];\n\nconst installed = new WeakMap<HTMLElement, MutationObserver>();\nconst appliedClasses = new WeakMap<HTMLElement, string[]>();\n\n/**\n * Give every standalone specialized table cell the common ColumnDefinition\n * presentation contract. The observer reapplies after Snice's differential\n * renderer changes shadow content; equality guards prevent mutation loops.\n */\nexport function installCellPresentation(\n host: HTMLElement & { column?: ColumnDefinition | null; value?: any; rowData?: any },\n formatterOverride = false,\n) {\n if (installed.has(host)) return;\n let observer: MutationObserver | null = null;\n let syncing = false;\n\n const sync = () => {\n if (syncing) return;\n syncing = true;\n observer?.disconnect();\n try {\n const column = host.column;\n for (const className of appliedClasses.get(host) || []) host.classList.remove(className);\n appliedClasses.set(host, []);\n for (const property of presentationProperties) (host.style as any)[property] = '';\n host.removeAttribute('title');\n if (!column) return;\n\n const applyStyle = (style?: CellStyle) => {\n if (!style) return;\n for (const property of presentationProperties) {\n const value = style[property];\n if (value) (host.style as any)[property] = value;\n }\n };\n\n applyStyle(column.style);\n for (const rule of column.conditionalFormats || []) {\n if (!rule.condition(host.value, host.rowData)) continue;\n applyStyle(rule.style);\n if (rule.className) {\n host.classList.add(rule.className);\n appliedClasses.set(host, [rule.className]);\n }\n break;\n }\n\n if (column.tooltip) {\n host.title = typeof column.tooltip === 'function'\n ? column.tooltip(host.value, host.rowData)\n : (host.value == null ? '' : String(host.value));\n }\n\n
|
|
1
|
+
{"version":3,"file":"table-cell-presentation.js","sources":["../../../../components/table/table-cell-presentation.ts"],"sourcesContent":["import type { ColumnDefinition, CellStyle } from './snice-table.types';\n\nconst presentationProperties: Array<keyof CellStyle> = [\n 'backgroundColor',\n 'color',\n 'fontWeight',\n 'fontStyle',\n 'fontSize',\n 'textDecoration',\n];\n\nconst installed = new WeakMap<HTMLElement, MutationObserver>();\nconst appliedClasses = new WeakMap<HTMLElement, string[]>();\n\n/**\n * Give every standalone specialized table cell the common ColumnDefinition\n * presentation contract. The observer reapplies after Snice's differential\n * renderer changes shadow content; equality guards prevent mutation loops.\n *\n * Display formatters\n * ------------------\n * `formatter` is the column's display formatter and `valueFormatter` its\n * fallback, so `formatter` wins. `formatterOverride` says the cell does NOT\n * apply `column.formatter` itself, so this module owns both formatters for it.\n *\n * A host marked `formatted` was handed its display text as `value` by the\n * table, which already resolved the pipeline. Its content is that text\n * verbatim — the marker exists so a rating/progress/link/tag cell, which\n * renders structure rather than text, still shows the formatted string.\n */\nexport function installCellPresentation(\n host: HTMLElement & { column?: ColumnDefinition | null; value?: any; rowData?: any },\n formatterOverride = false,\n) {\n if (installed.has(host)) return;\n let observer: MutationObserver | null = null;\n let syncing = false;\n\n const sync = () => {\n if (syncing) return;\n syncing = true;\n observer?.disconnect();\n try {\n const column = host.column;\n for (const className of appliedClasses.get(host) || []) host.classList.remove(className);\n appliedClasses.set(host, []);\n for (const property of presentationProperties) (host.style as any)[property] = '';\n host.removeAttribute('title');\n if (!column) return;\n\n const applyStyle = (style?: CellStyle) => {\n if (!style) return;\n for (const property of presentationProperties) {\n const value = style[property];\n if (value) (host.style as any)[property] = value;\n }\n };\n\n applyStyle(column.style);\n for (const rule of column.conditionalFormats || []) {\n if (!rule.condition(host.value, host.rowData)) continue;\n applyStyle(rule.style);\n if (rule.className) {\n host.classList.add(rule.className);\n appliedClasses.set(host, [rule.className]);\n }\n break;\n }\n\n if (column.tooltip) {\n host.title = typeof column.tooltip === 'function'\n ? column.tooltip(host.value, host.rowData)\n : (host.value == null ? '' : String(host.value));\n }\n\n // `formatter` beats `valueFormatter`. A cell that applies `formatter`\n // itself has already painted it, so the fallback must not overwrite that\n // content — only a formatter-less column falls through to valueFormatter.\n const formatter = column.formatter\n ? (formatterOverride ? column.formatter : null)\n : column.valueFormatter;\n // Pre-formatted hosts read the attribute, not the property: a cell whose\n // value property is typed (boolean, number) coerces the display string.\n const display = host.hasAttribute('formatted')\n ? (host.getAttribute('value') ?? '')\n : (formatter ? String(formatter(host.value, host.rowData) ?? '') : null);\n if (display !== null) {\n const content = host.shadowRoot?.querySelector('[part~=\"content\"]') as HTMLElement | null;\n if (content && (content.textContent !== display || content.childElementCount > 0)) {\n content.textContent = display;\n }\n }\n } finally {\n syncing = false;\n if (observer && host.shadowRoot) {\n observer.observe(host.shadowRoot, { childList: true, subtree: true, characterData: true });\n }\n }\n };\n\n observer = new MutationObserver(sync);\n if (host.shadowRoot) observer.observe(host.shadowRoot, { childList: true, subtree: true, characterData: true });\n installed.set(host, observer);\n queueMicrotask(sync);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -51,6 +51,12 @@ export declare class TableExport {
|
|
|
51
51
|
*/
|
|
52
52
|
copyToClipboard(data: any[], columns: ColumnDefinition[], options?: ClipboardOptions): Promise<boolean>;
|
|
53
53
|
private escapeCSV;
|
|
54
|
+
/**
|
|
55
|
+
* The column's working value for a row: `valueGetter` "runs for display,
|
|
56
|
+
* sort, aggregation" — and for export, which must ship what the table shows,
|
|
57
|
+
* not a row field the column may not even have.
|
|
58
|
+
*/
|
|
59
|
+
private cellValue;
|
|
54
60
|
private rawValue;
|
|
55
61
|
private formatValue;
|
|
56
62
|
private escapeHTML;
|
|
@@ -17,7 +17,7 @@ class TableExport {
|
|
|
17
17
|
// Data rows
|
|
18
18
|
for (const row of data) {
|
|
19
19
|
const cells = exportColumns.map(c => {
|
|
20
|
-
const value = row
|
|
20
|
+
const value = this.cellValue(row, c);
|
|
21
21
|
return this.escapeCSV(value == null ? '' : String(value), delimiter);
|
|
22
22
|
});
|
|
23
23
|
rows.push(cells.join(delimiter));
|
|
@@ -129,7 +129,7 @@ class TableExport {
|
|
|
129
129
|
if (rows.length === 0)
|
|
130
130
|
return false;
|
|
131
131
|
const text = rows.map(row => columns.map(c => {
|
|
132
|
-
const value = row
|
|
132
|
+
const value = this.cellValue(row, c);
|
|
133
133
|
return useFormatted ? this.formatValue(value, row, c) : this.rawValue(value);
|
|
134
134
|
}).join(delimiter)).join('\n');
|
|
135
135
|
try {
|
|
@@ -154,6 +154,15 @@ class TableExport {
|
|
|
154
154
|
}
|
|
155
155
|
return value;
|
|
156
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* The column's working value for a row: `valueGetter` "runs for display,
|
|
159
|
+
* sort, aggregation" — and for export, which must ship what the table shows,
|
|
160
|
+
* not a row field the column may not even have.
|
|
161
|
+
*/
|
|
162
|
+
cellValue(row, column) {
|
|
163
|
+
const raw = row?.[column.key];
|
|
164
|
+
return column.valueGetter ? column.valueGetter(raw, row) : raw;
|
|
165
|
+
}
|
|
157
166
|
rawValue(value) {
|
|
158
167
|
if (value == null)
|
|
159
168
|
return '';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-export.js","sources":["../../../../components/table/table-export.ts"],"sourcesContent":["/**\n * Export and clipboard functionality for snice-table.\n * Handles: CSV export, print, clipboard copy.\n */\nimport type { ColumnDefinition } from './snice-table.types';\n\nexport interface CSVExportOptions {\n /** CSV delimiter. Default: ',' */\n delimiter?: string;\n /** Filename for download. Default: 'export.csv' */\n filename?: string;\n /** Include column headers. Default: true */\n includeHeaders?: boolean;\n /** Export only selected rows. Default: false */\n selectedOnly?: boolean;\n /** Specific column keys to export. Default: all visible */\n columns?: string[];\n /** Add UTF-8 BOM for Excel compatibility. Default: true */\n utf8BOM?: boolean;\n}\n\nexport interface PrintOptions {\n /** Hide footer in print. Default: false */\n hideFooter?: boolean;\n /** Hide toolbar in print. Default: false */\n hideToolbar?: boolean;\n /** Include selection checkboxes. Default: false */\n includeCheckboxes?: boolean;\n /** Custom page CSS. */\n pageStyles?: string;\n}\n\nexport interface ClipboardOptions {\n /** Delimiter for copied cells. Default: '\\t' */\n delimiter?: string;\n /** Use formatted values or raw. Default: true (formatted) */\n useFormatted?: boolean;\n}\n\nexport class TableExport {\n /**\n * Export data to CSV and trigger download.\n */\n exportCSV(\n data: any[],\n columns: { key: string; label: string; exportable?: boolean }[],\n options: CSVExportOptions = {}\n ) {\n const {\n delimiter = ',',\n filename = 'export.csv',\n includeHeaders = true,\n columns: columnKeys,\n utf8BOM = true,\n } = options;\n\n // Filter columns\n let exportColumns = columns.filter(c => (c as any).exportable !== false);\n if (columnKeys) {\n exportColumns = exportColumns.filter(c => columnKeys.includes(c.key));\n }\n\n const rows: string[] = [];\n\n // Header row\n if (includeHeaders) {\n rows.push(exportColumns.map(c => this.escapeCSV(c.label, delimiter)).join(delimiter));\n }\n\n // Data rows\n for (const row of data) {\n const cells = exportColumns.map(c => {\n const value = row[c.key];\n return this.escapeCSV(value == null ? '' : String(value), delimiter);\n });\n rows.push(cells.join(delimiter));\n }\n\n const csv = rows.join('\\n');\n const bom = utf8BOM ? '\\ufeff' : '';\n const blob = new Blob([bom + csv], { type: 'text/csv;charset=utf-8;' });\n\n // Download\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.style.display = 'none';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n }\n\n /**\n * Open browser print dialog with table content.\n */\n print(\n tableElement: HTMLElement,\n options: PrintOptions = {}\n ) {\n const {\n hideFooter = false,\n hideToolbar = false,\n includeCheckboxes = false,\n pageStyles = '',\n } = options;\n\n // Clone the table content\n const shadowRoot = tableElement.shadowRoot;\n if (!shadowRoot) return;\n\n const table = shadowRoot.querySelector('table');\n if (!table) return;\n\n const tableClone = table.cloneNode(true) as HTMLTableElement;\n\n // Shadow-root cell contents are not included by outerHTML. Flatten each\n // rendered custom cell into plain print text so the printout contains what\n // the user actually sees rather than empty custom-element tags.\n const originalCells = Array.from(table.querySelectorAll('snice-cell, [in-table], snice-checkbox'));\n const clonedCells = Array.from(tableClone.querySelectorAll('snice-cell, [in-table], snice-checkbox'));\n originalCells.forEach((original: any, index) => {\n const clone = clonedCells[index] as HTMLElement | undefined;\n if (!clone) return;\n if (original.localName === 'snice-checkbox') {\n clone.replaceWith(document.createTextNode(original.checked ? '☑' : '☐'));\n return;\n }\n const content = original.shadowRoot?.querySelector('[part~=\"content\"]');\n clone.replaceWith(document.createTextNode((content?.textContent || original.textContent || '').trim()));\n });\n\n if (!includeCheckboxes) {\n tableClone.querySelectorAll('.select-column').forEach((cell) => cell.remove());\n }\n\n const plainSection = (selector: string, className: string): string => {\n const source = shadowRoot.querySelector(selector);\n if (!source) return '';\n const clone = source.cloneNode(true) as HTMLElement;\n clone.querySelectorAll('style').forEach((style) => style.remove());\n clone.querySelectorAll('button').forEach((button) => {\n if (!button.textContent?.trim()) button.textContent = button.getAttribute('aria-label') || '';\n });\n const text = clone.textContent?.replace(/\\s+/g, ' ').trim();\n return text ? `<div class=\"${className}\">${this.escapeHTML(text)}</div>` : '';\n };\n const toolbarHTML = hideToolbar ? '' : plainSection('.table-controls-container', 'print-toolbar');\n const footerHTML = hideFooter ? '' : plainSection('.table-pagination-container', 'print-footer');\n\n const printWindow = window.open('', '_blank');\n if (!printWindow) return;\n\n const html = `\n <!DOCTYPE html>\n <html>\n <head>\n <title>Print</title>\n <style>\n body { font-family: system-ui, -apple-system, sans-serif; margin: 1rem; }\n table { width: 100%; border-collapse: collapse; }\n th, td { padding: 8px 12px; border: 1px solid #ddd; text-align: left; }\n th { background: #f5f5f5; font-weight: 600; }\n .print-toolbar, .print-footer { margin: 0 0 0.75rem; color: #444; }\n .print-footer { margin: 0.75rem 0 0; }\n @media print {\n body { margin: 0; }\n table { page-break-inside: auto; }\n tr { page-break-inside: avoid; }\n }\n ${pageStyles}\n </style>\n </head>\n <body>\n ${toolbarHTML}\n ${tableClone.outerHTML}\n ${footerHTML}\n </body>\n </html>\n `;\n\n printWindow.document.write(html);\n printWindow.document.close();\n printWindow.onload = () => {\n printWindow.print();\n printWindow.close();\n };\n }\n\n /**\n * Copy cells to clipboard as tab-separated text.\n */\n async copyToClipboard(\n data: any[],\n columns: ColumnDefinition[],\n options: ClipboardOptions = {}\n ): Promise<boolean> {\n const { delimiter = '\\t', useFormatted = true } = options;\n const rows = data;\n\n if (rows.length === 0) return false;\n\n const text = rows.map(row =>\n columns.map(c => {\n const value = row[c.key];\n return useFormatted ? this.formatValue(value, row, c) : this.rawValue(value);\n }).join(delimiter)\n ).join('\\n');\n\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n // Fallback for older browsers\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.cssText = 'position:fixed;left:-9999px;';\n document.body.appendChild(textarea);\n textarea.select();\n const success = document.execCommand('copy');\n document.body.removeChild(textarea);\n return success;\n }\n }\n\n private escapeCSV(value: string, delimiter: string): string {\n if (value.includes(delimiter) || value.includes('\"') || value.includes('\\n') || value.includes('\\r')) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n }\n\n private rawValue(value: any): string {\n if (value == null) return '';\n if (typeof value === 'object') {\n try { return JSON.stringify(value); } catch { return String(value); }\n }\n return String(value);\n }\n\n private formatValue(value: any, row: any, column: ColumnDefinition): string {\n const override = column.formatter || column.valueFormatter;\n if (override) return String(override(value, row) ?? '');\n if (value == null) return '';\n\n const num = Number(value);\n switch (column.type) {\n case 'number':\n case 'accounting': {\n if (!Number.isFinite(num)) return this.rawValue(value);\n const format = column.numberFormat || {};\n const decimals = format.decimals ?? (column.type === 'accounting' ? 2 : 0);\n const grouped = new Intl.NumberFormat('en-US', {\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n useGrouping: format.thousandsSeparator ?? false,\n }).format(Math.abs(num));\n let output = num < 0 && (format.negativeStyle === 'parentheses' || column.type === 'accounting')\n ? `(${grouped})`\n : `${num < 0 ? '-' : ''}${grouped}`;\n if (format.prefix) output = format.prefix + output;\n if (format.suffix) output += format.suffix;\n return output;\n }\n case 'currency': {\n if (!Number.isFinite(num)) return this.rawValue(value);\n const format = column.currencyFormat || {};\n const decimals = format.decimals ?? 2;\n const display = format.currencyDisplay || format.display || 'symbol';\n const output = new Intl.NumberFormat(format.locale || 'en-US', {\n style: 'currency',\n currency: format.currency || 'USD',\n currencyDisplay: display,\n useGrouping: format.thousandsSeparator ?? true,\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n }).format(Math.abs(num));\n if (num >= 0) return output;\n return format.negativeStyle === 'parentheses' ? `(${output})` : `-${output}`;\n }\n case 'percent':\n case 'percentage': {\n if (!Number.isFinite(num)) return this.rawValue(value);\n return `${num.toFixed(column.percentageFormat?.decimals ?? 2)}%`;\n }\n case 'date': {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return this.rawValue(value);\n const format = column.dateFormat || {};\n const dateStyle = format.format === 'custom' ? undefined : (format.format || 'short');\n return new Intl.DateTimeFormat(format.locale || 'en-US', dateStyle ? { dateStyle } : {}).format(date);\n }\n case 'boolean': {\n const format = column.booleanFormat || {};\n const truthy = value === true || String(value) === String(format.trueValue ?? 'true');\n return truthy ? (format.trueSymbol || format.trueValue || 'true') : (format.falseSymbol || format.falseValue || 'false');\n }\n case 'scientific':\n return Number.isFinite(num) ? num.toExponential(column.numberFormat?.decimals ?? 2) : this.rawValue(value);\n default:\n return this.rawValue(value);\n }\n }\n\n private escapeHTML(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"table-export.js","sources":["../../../../components/table/table-export.ts"],"sourcesContent":["/**\n * Export and clipboard functionality for snice-table.\n * Handles: CSV export, print, clipboard copy.\n */\nimport type { ColumnDefinition } from './snice-table.types';\n\nexport interface CSVExportOptions {\n /** CSV delimiter. Default: ',' */\n delimiter?: string;\n /** Filename for download. Default: 'export.csv' */\n filename?: string;\n /** Include column headers. Default: true */\n includeHeaders?: boolean;\n /** Export only selected rows. Default: false */\n selectedOnly?: boolean;\n /** Specific column keys to export. Default: all visible */\n columns?: string[];\n /** Add UTF-8 BOM for Excel compatibility. Default: true */\n utf8BOM?: boolean;\n}\n\nexport interface PrintOptions {\n /** Hide footer in print. Default: false */\n hideFooter?: boolean;\n /** Hide toolbar in print. Default: false */\n hideToolbar?: boolean;\n /** Include selection checkboxes. Default: false */\n includeCheckboxes?: boolean;\n /** Custom page CSS. */\n pageStyles?: string;\n}\n\nexport interface ClipboardOptions {\n /** Delimiter for copied cells. Default: '\\t' */\n delimiter?: string;\n /** Use formatted values or raw. Default: true (formatted) */\n useFormatted?: boolean;\n}\n\nexport class TableExport {\n /**\n * Export data to CSV and trigger download.\n */\n exportCSV(\n data: any[],\n columns: { key: string; label: string; exportable?: boolean }[],\n options: CSVExportOptions = {}\n ) {\n const {\n delimiter = ',',\n filename = 'export.csv',\n includeHeaders = true,\n columns: columnKeys,\n utf8BOM = true,\n } = options;\n\n // Filter columns\n let exportColumns = columns.filter(c => (c as any).exportable !== false);\n if (columnKeys) {\n exportColumns = exportColumns.filter(c => columnKeys.includes(c.key));\n }\n\n const rows: string[] = [];\n\n // Header row\n if (includeHeaders) {\n rows.push(exportColumns.map(c => this.escapeCSV(c.label, delimiter)).join(delimiter));\n }\n\n // Data rows\n for (const row of data) {\n const cells = exportColumns.map(c => {\n const value = this.cellValue(row, c);\n return this.escapeCSV(value == null ? '' : String(value), delimiter);\n });\n rows.push(cells.join(delimiter));\n }\n\n const csv = rows.join('\\n');\n const bom = utf8BOM ? '\\ufeff' : '';\n const blob = new Blob([bom + csv], { type: 'text/csv;charset=utf-8;' });\n\n // Download\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.style.display = 'none';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n }\n\n /**\n * Open browser print dialog with table content.\n */\n print(\n tableElement: HTMLElement,\n options: PrintOptions = {}\n ) {\n const {\n hideFooter = false,\n hideToolbar = false,\n includeCheckboxes = false,\n pageStyles = '',\n } = options;\n\n // Clone the table content\n const shadowRoot = tableElement.shadowRoot;\n if (!shadowRoot) return;\n\n const table = shadowRoot.querySelector('table');\n if (!table) return;\n\n const tableClone = table.cloneNode(true) as HTMLTableElement;\n\n // Shadow-root cell contents are not included by outerHTML. Flatten each\n // rendered custom cell into plain print text so the printout contains what\n // the user actually sees rather than empty custom-element tags.\n const originalCells = Array.from(table.querySelectorAll('snice-cell, [in-table], snice-checkbox'));\n const clonedCells = Array.from(tableClone.querySelectorAll('snice-cell, [in-table], snice-checkbox'));\n originalCells.forEach((original: any, index) => {\n const clone = clonedCells[index] as HTMLElement | undefined;\n if (!clone) return;\n if (original.localName === 'snice-checkbox') {\n clone.replaceWith(document.createTextNode(original.checked ? '☑' : '☐'));\n return;\n }\n const content = original.shadowRoot?.querySelector('[part~=\"content\"]');\n clone.replaceWith(document.createTextNode((content?.textContent || original.textContent || '').trim()));\n });\n\n if (!includeCheckboxes) {\n tableClone.querySelectorAll('.select-column').forEach((cell) => cell.remove());\n }\n\n const plainSection = (selector: string, className: string): string => {\n const source = shadowRoot.querySelector(selector);\n if (!source) return '';\n const clone = source.cloneNode(true) as HTMLElement;\n clone.querySelectorAll('style').forEach((style) => style.remove());\n clone.querySelectorAll('button').forEach((button) => {\n if (!button.textContent?.trim()) button.textContent = button.getAttribute('aria-label') || '';\n });\n const text = clone.textContent?.replace(/\\s+/g, ' ').trim();\n return text ? `<div class=\"${className}\">${this.escapeHTML(text)}</div>` : '';\n };\n const toolbarHTML = hideToolbar ? '' : plainSection('.table-controls-container', 'print-toolbar');\n const footerHTML = hideFooter ? '' : plainSection('.table-pagination-container', 'print-footer');\n\n const printWindow = window.open('', '_blank');\n if (!printWindow) return;\n\n const html = `\n <!DOCTYPE html>\n <html>\n <head>\n <title>Print</title>\n <style>\n body { font-family: system-ui, -apple-system, sans-serif; margin: 1rem; }\n table { width: 100%; border-collapse: collapse; }\n th, td { padding: 8px 12px; border: 1px solid #ddd; text-align: left; }\n th { background: #f5f5f5; font-weight: 600; }\n .print-toolbar, .print-footer { margin: 0 0 0.75rem; color: #444; }\n .print-footer { margin: 0.75rem 0 0; }\n @media print {\n body { margin: 0; }\n table { page-break-inside: auto; }\n tr { page-break-inside: avoid; }\n }\n ${pageStyles}\n </style>\n </head>\n <body>\n ${toolbarHTML}\n ${tableClone.outerHTML}\n ${footerHTML}\n </body>\n </html>\n `;\n\n printWindow.document.write(html);\n printWindow.document.close();\n printWindow.onload = () => {\n printWindow.print();\n printWindow.close();\n };\n }\n\n /**\n * Copy cells to clipboard as tab-separated text.\n */\n async copyToClipboard(\n data: any[],\n columns: ColumnDefinition[],\n options: ClipboardOptions = {}\n ): Promise<boolean> {\n const { delimiter = '\\t', useFormatted = true } = options;\n const rows = data;\n\n if (rows.length === 0) return false;\n\n const text = rows.map(row =>\n columns.map(c => {\n const value = this.cellValue(row, c);\n return useFormatted ? this.formatValue(value, row, c) : this.rawValue(value);\n }).join(delimiter)\n ).join('\\n');\n\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n // Fallback for older browsers\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.cssText = 'position:fixed;left:-9999px;';\n document.body.appendChild(textarea);\n textarea.select();\n const success = document.execCommand('copy');\n document.body.removeChild(textarea);\n return success;\n }\n }\n\n private escapeCSV(value: string, delimiter: string): string {\n if (value.includes(delimiter) || value.includes('\"') || value.includes('\\n') || value.includes('\\r')) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n }\n\n /**\n * The column's working value for a row: `valueGetter` \"runs for display,\n * sort, aggregation\" — and for export, which must ship what the table shows,\n * not a row field the column may not even have.\n */\n private cellValue(row: any, column: ColumnDefinition): any {\n const raw = row?.[column.key];\n return column.valueGetter ? column.valueGetter(raw, row) : raw;\n }\n\n private rawValue(value: any): string {\n if (value == null) return '';\n if (typeof value === 'object') {\n try { return JSON.stringify(value); } catch { return String(value); }\n }\n return String(value);\n }\n\n private formatValue(value: any, row: any, column: ColumnDefinition): string {\n const override = column.formatter || column.valueFormatter;\n if (override) return String(override(value, row) ?? '');\n if (value == null) return '';\n\n const num = Number(value);\n switch (column.type) {\n case 'number':\n case 'accounting': {\n if (!Number.isFinite(num)) return this.rawValue(value);\n const format = column.numberFormat || {};\n const decimals = format.decimals ?? (column.type === 'accounting' ? 2 : 0);\n const grouped = new Intl.NumberFormat('en-US', {\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n useGrouping: format.thousandsSeparator ?? false,\n }).format(Math.abs(num));\n let output = num < 0 && (format.negativeStyle === 'parentheses' || column.type === 'accounting')\n ? `(${grouped})`\n : `${num < 0 ? '-' : ''}${grouped}`;\n if (format.prefix) output = format.prefix + output;\n if (format.suffix) output += format.suffix;\n return output;\n }\n case 'currency': {\n if (!Number.isFinite(num)) return this.rawValue(value);\n const format = column.currencyFormat || {};\n const decimals = format.decimals ?? 2;\n const display = format.currencyDisplay || format.display || 'symbol';\n const output = new Intl.NumberFormat(format.locale || 'en-US', {\n style: 'currency',\n currency: format.currency || 'USD',\n currencyDisplay: display,\n useGrouping: format.thousandsSeparator ?? true,\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n }).format(Math.abs(num));\n if (num >= 0) return output;\n return format.negativeStyle === 'parentheses' ? `(${output})` : `-${output}`;\n }\n case 'percent':\n case 'percentage': {\n if (!Number.isFinite(num)) return this.rawValue(value);\n return `${num.toFixed(column.percentageFormat?.decimals ?? 2)}%`;\n }\n case 'date': {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return this.rawValue(value);\n const format = column.dateFormat || {};\n const dateStyle = format.format === 'custom' ? undefined : (format.format || 'short');\n return new Intl.DateTimeFormat(format.locale || 'en-US', dateStyle ? { dateStyle } : {}).format(date);\n }\n case 'boolean': {\n const format = column.booleanFormat || {};\n const truthy = value === true || String(value) === String(format.trueValue ?? 'true');\n return truthy ? (format.trueSymbol || format.trueValue || 'true') : (format.falseSymbol || format.falseValue || 'false');\n }\n case 'scientific':\n return Number.isFinite(num) ? num.toExponential(column.numberFormat?.decimals ?? 2) : this.rawValue(value);\n default:\n return this.rawValue(value);\n }\n }\n\n private escapeHTML(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -19,12 +19,21 @@ export declare class TableMasterDetail {
|
|
|
19
19
|
private options;
|
|
20
20
|
private tableElement;
|
|
21
21
|
private contentCache;
|
|
22
|
+
/** Last value signature seen per row, so in-place mutations evict the cache. */
|
|
23
|
+
private fingerprints;
|
|
22
24
|
private rowByIndex;
|
|
23
25
|
private measuredHeights;
|
|
24
26
|
onHeightChange: (() => void) | null;
|
|
25
27
|
attach(tableEl: HTMLElement, options: DetailPanelOptions): void;
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Eagerly construct detail content when lazy=false.
|
|
30
|
+
*
|
|
31
|
+
* `fingerprint` (the table's per-row value signature) also evicts rows whose
|
|
32
|
+
* fields were mutated in place: the cache is keyed by row identity, so an
|
|
33
|
+
* unchanged identity would otherwise keep serving a panel built from the
|
|
34
|
+
* pre-mutation values.
|
|
35
|
+
*/
|
|
36
|
+
prepare(rows: any[], fingerprint?: (row: any) => string): void;
|
|
28
37
|
/** Check if a row is expanded */
|
|
29
38
|
isExpanded(rowIndex: number): boolean;
|
|
30
39
|
/** Toggle expansion of a row */
|
|
@@ -8,6 +8,8 @@ class TableMasterDetail {
|
|
|
8
8
|
this.options = null;
|
|
9
9
|
this.tableElement = null;
|
|
10
10
|
this.contentCache = new Map();
|
|
11
|
+
/** Last value signature seen per row, so in-place mutations evict the cache. */
|
|
12
|
+
this.fingerprints = new Map();
|
|
11
13
|
this.rowByIndex = new Map();
|
|
12
14
|
this.measuredHeights = new Map();
|
|
13
15
|
this.onHeightChange = null;
|
|
@@ -16,18 +18,33 @@ class TableMasterDetail {
|
|
|
16
18
|
this.tableElement = tableEl;
|
|
17
19
|
this.options = options;
|
|
18
20
|
this.contentCache.clear();
|
|
21
|
+
this.fingerprints.clear();
|
|
19
22
|
this.rowByIndex.clear();
|
|
20
23
|
this.measuredHeights.clear();
|
|
21
24
|
}
|
|
22
|
-
/**
|
|
23
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Eagerly construct detail content when lazy=false.
|
|
27
|
+
*
|
|
28
|
+
* `fingerprint` (the table's per-row value signature) also evicts rows whose
|
|
29
|
+
* fields were mutated in place: the cache is keyed by row identity, so an
|
|
30
|
+
* unchanged identity would otherwise keep serving a panel built from the
|
|
31
|
+
* pre-mutation values.
|
|
32
|
+
*/
|
|
33
|
+
prepare(rows, fingerprint) {
|
|
24
34
|
if (!this.options)
|
|
25
35
|
return;
|
|
26
36
|
this.rowByIndex = new Map(rows.map((row, index) => [index, row]));
|
|
27
37
|
const currentRows = new Set(rows);
|
|
28
|
-
for (const row of this.contentCache.keys()) {
|
|
38
|
+
for (const row of [...this.contentCache.keys()]) {
|
|
29
39
|
if (!currentRows.has(row))
|
|
30
40
|
this.contentCache.delete(row);
|
|
41
|
+
else if (fingerprint && this.fingerprints.get(row) !== fingerprint(row)) {
|
|
42
|
+
this.contentCache.delete(row);
|
|
43
|
+
this.measuredHeights.delete(row);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (fingerprint) {
|
|
47
|
+
this.fingerprints = new Map(rows.map(row => [row, fingerprint(row)]));
|
|
31
48
|
}
|
|
32
49
|
for (const row of this.measuredHeights.keys()) {
|
|
33
50
|
if (!currentRows.has(row))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-master-detail.js","sources":["../../../../components/table/table-master-detail.ts"],"sourcesContent":["/**\n * Master-detail (row expansion) for snice-table.\n * Expand a row to reveal a detail panel below it.\n */\n\nexport interface DetailPanelOptions {\n /** Render detail content for a row. Return HTML string or HTMLElement. */\n getDetailContent: (row: any, rowIndex: number) => string | HTMLElement;\n /** Detail panel height. 'auto' for content-based. Default: 'auto' */\n detailHeight?: string | number;\n /** Lazy: create on expand, destroy on collapse. Default: true */\n lazy?: boolean;\n /** Expand icon (collapsed state) */\n expandIcon?: string;\n /** Collapse icon (expanded state) */\n collapseIcon?: string;\n}\n\nexport class TableMasterDetail {\n private expandedRows: Set<number> = new Set();\n private options: DetailPanelOptions | null = null;\n private tableElement: HTMLElement | null = null;\n private contentCache = new Map<any, string | HTMLElement>();\n private rowByIndex = new Map<number, any>();\n private measuredHeights = new Map<any, number>();\n onHeightChange: (() => void) | null = null;\n\n attach(tableEl: HTMLElement, options: DetailPanelOptions) {\n this.tableElement = tableEl;\n this.options = options;\n this.contentCache.clear();\n this.rowByIndex.clear();\n this.measuredHeights.clear();\n }\n\n /** Eagerly construct detail content when lazy=false. */\n prepare(rows: any[]) {\n if (!this.options) return;\n this.rowByIndex = new Map(rows.map((row, index) => [index, row]));\n const currentRows = new Set(rows);\n for (const row of this.contentCache.keys()) {\n if (!currentRows.has(row)) this.contentCache.delete(row);\n }\n for (const row of this.measuredHeights.keys()) {\n if (!currentRows.has(row)) this.measuredHeights.delete(row);\n }\n if (this.options.lazy === false) rows.forEach((row, index) => this.getContent(row, index));\n }\n\n /** Check if a row is expanded */\n isExpanded(rowIndex: number): boolean {\n return this.expandedRows.has(rowIndex);\n }\n\n /** Toggle expansion of a row */\n toggle(rowIndex: number) {\n if (this.expandedRows.has(rowIndex)) {\n this.collapse(rowIndex);\n } else {\n this.expand(rowIndex);\n }\n }\n\n /** Expand a row */\n expand(rowIndex: number) {\n this.expandedRows.add(rowIndex);\n this.tableElement?.dispatchEvent(new CustomEvent('row-expand', {\n detail: { rowIndex },\n bubbles: true,\n composed: true,\n }));\n }\n\n /** Collapse a row */\n collapse(rowIndex: number) {\n this.expandedRows.delete(rowIndex);\n if (this.options?.lazy !== false) {\n const row = this.rowByIndex.get(rowIndex);\n if (row !== undefined) {\n this.contentCache.delete(row);\n this.measuredHeights.delete(row);\n }\n }\n this.tableElement?.dispatchEvent(new CustomEvent('row-collapse', {\n detail: { rowIndex },\n bubbles: true,\n composed: true,\n }));\n }\n\n /** Expand all rows */\n expandAll(totalRows: number) {\n for (let i = 0; i < totalRows; i++) {\n this.expandedRows.add(i);\n }\n }\n\n /** Collapse all rows */\n collapseAll() {\n this.expandedRows.clear();\n if (this.options?.lazy !== false) {\n this.contentCache.clear();\n this.measuredHeights.clear();\n }\n }\n\n /** Get set of expanded row indices */\n getExpandedRows(): Set<number> {\n return new Set(this.expandedRows);\n }\n\n /** Replace expansion indices without emitting user-action events. */\n setExpandedRows(rowIndices: Iterable<number>) {\n const next = new Set(rowIndices);\n if (this.options?.lazy !== false) {\n for (const index of this.expandedRows) {\n if (next.has(index)) continue;\n const row = this.rowByIndex.get(index);\n if (row !== undefined) {\n this.contentCache.delete(row);\n this.measuredHeights.delete(row);\n }\n }\n }\n this.expandedRows = next;\n }\n\n /** Create the expand/collapse toggle button — uses same chevron SVG as snice-accordion */\n createToggleButton(rowIndex: number): HTMLElement {\n const expanded = this.isExpanded(rowIndex);\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = `detail-toggle${expanded ? ' detail-toggle--expanded' : ''}`;\n btn.setAttribute('aria-expanded', String(expanded));\n btn.setAttribute('aria-label', expanded ? 'Collapse row' : 'Expand row');\n const customIcon = expanded ? this.options?.collapseIcon : this.options?.expandIcon;\n if (customIcon) {\n if (customIcon.trim().startsWith('<')) btn.innerHTML = customIcon;\n else btn.textContent = customIcon;\n } else {\n btn.innerHTML = `<svg class=\"detail-toggle-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M6 9l6 6 6-6\"/></svg>`;\n }\n\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.toggle(rowIndex);\n this.tableElement?.dispatchEvent(new CustomEvent('detail-toggle', {\n detail: { rowIndex, expanded: this.isExpanded(rowIndex) },\n bubbles: true,\n composed: true,\n }));\n });\n\n return btn;\n }\n\n /** Create the detail panel row (a <tr> with a single <td> spanning all columns) */\n createDetailRow(row: any, rowIndex: number, colSpan: number): HTMLTableRowElement | null {\n if (!this.options || !this.isExpanded(rowIndex)) return null;\n\n const tr = document.createElement('tr');\n tr.className = 'detail-row';\n tr.setAttribute('data-detail-for', String(rowIndex));\n\n const td = document.createElement('td');\n td.colSpan = colSpan;\n td.className = 'detail-cell';\n td.style.padding = '0';\n td.style.border = 'none';\n\n // Animated wrapper — same pattern as snice-accordion\n const wrapper = document.createElement('div');\n wrapper.className = 'detail-content';\n\n const inner = document.createElement('div');\n inner.className = 'detail-content-inner';\n\n const content = this.getContent(row, rowIndex);\n if (typeof content === 'string') {\n inner.innerHTML = content;\n } else if (content instanceof HTMLElement) {\n inner.appendChild(content);\n }\n\n wrapper.appendChild(inner);\n td.appendChild(wrapper);\n\n // Trigger animation after insertion\n requestAnimationFrame(() => {\n const configuredHeight = this.options?.detailHeight;\n const height = configuredHeight === undefined || configuredHeight === 'auto'\n ? `${inner.scrollHeight}px`\n : (typeof configuredHeight === 'number' ? `${configuredHeight}px` : configuredHeight);\n if (configuredHeight !== undefined && configuredHeight !== 'auto') {\n inner.style.height = height;\n inner.style.overflow = 'auto';\n }\n wrapper.style.setProperty('--detail-max-height', height);\n wrapper.classList.add('detail-content--open');\n const measuredHeight = inner.getBoundingClientRect().height || inner.scrollHeight;\n const previousHeight = this.measuredHeights.get(row);\n if (measuredHeight > 0 && measuredHeight !== previousHeight) {\n this.measuredHeights.set(row, measuredHeight);\n this.onHeightChange?.();\n }\n });\n\n tr.appendChild(td);\n return tr;\n }\n\n isEnabled(): boolean {\n return this.options !== null;\n }\n\n /** Extra height contributed by an expanded detail row. Auto/non-pixel\n * panels use the most recent browser measurement. */\n getFixedAdditionalHeight(rowIndex: number): number {\n if (!this.isExpanded(rowIndex)) return 0;\n const configured = this.options?.detailHeight;\n if (typeof configured === 'number') return Math.max(0, configured);\n if (typeof configured === 'string' && /^\\d+(?:\\.\\d+)?px$/.test(configured.trim())) {\n return Math.max(0, Number.parseFloat(configured));\n }\n const row = this.rowByIndex.get(rowIndex);\n return row === undefined ? 0 : (this.measuredHeights.get(row) || 0);\n }\n\n private getContent(row: any, rowIndex: number): string | HTMLElement {\n if (!this.options) return '';\n this.rowByIndex.set(rowIndex, row);\n if (!this.contentCache.has(row)) {\n this.contentCache.set(row, this.options.getDetailContent(row, rowIndex));\n }\n return this.contentCache.get(row)!;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"table-master-detail.js","sources":["../../../../components/table/table-master-detail.ts"],"sourcesContent":["/**\n * Master-detail (row expansion) for snice-table.\n * Expand a row to reveal a detail panel below it.\n */\n\nexport interface DetailPanelOptions {\n /** Render detail content for a row. Return HTML string or HTMLElement. */\n getDetailContent: (row: any, rowIndex: number) => string | HTMLElement;\n /** Detail panel height. 'auto' for content-based. Default: 'auto' */\n detailHeight?: string | number;\n /** Lazy: create on expand, destroy on collapse. Default: true */\n lazy?: boolean;\n /** Expand icon (collapsed state) */\n expandIcon?: string;\n /** Collapse icon (expanded state) */\n collapseIcon?: string;\n}\n\nexport class TableMasterDetail {\n private expandedRows: Set<number> = new Set();\n private options: DetailPanelOptions | null = null;\n private tableElement: HTMLElement | null = null;\n private contentCache = new Map<any, string | HTMLElement>();\n /** Last value signature seen per row, so in-place mutations evict the cache. */\n private fingerprints = new Map<any, string>();\n private rowByIndex = new Map<number, any>();\n private measuredHeights = new Map<any, number>();\n onHeightChange: (() => void) | null = null;\n\n attach(tableEl: HTMLElement, options: DetailPanelOptions) {\n this.tableElement = tableEl;\n this.options = options;\n this.contentCache.clear();\n this.fingerprints.clear();\n this.rowByIndex.clear();\n this.measuredHeights.clear();\n }\n\n /**\n * Eagerly construct detail content when lazy=false.\n *\n * `fingerprint` (the table's per-row value signature) also evicts rows whose\n * fields were mutated in place: the cache is keyed by row identity, so an\n * unchanged identity would otherwise keep serving a panel built from the\n * pre-mutation values.\n */\n prepare(rows: any[], fingerprint?: (row: any) => string) {\n if (!this.options) return;\n this.rowByIndex = new Map(rows.map((row, index) => [index, row]));\n const currentRows = new Set(rows);\n for (const row of [...this.contentCache.keys()]) {\n if (!currentRows.has(row)) this.contentCache.delete(row);\n else if (fingerprint && this.fingerprints.get(row) !== fingerprint(row)) {\n this.contentCache.delete(row);\n this.measuredHeights.delete(row);\n }\n }\n if (fingerprint) {\n this.fingerprints = new Map(rows.map(row => [row, fingerprint(row)]));\n }\n for (const row of this.measuredHeights.keys()) {\n if (!currentRows.has(row)) this.measuredHeights.delete(row);\n }\n if (this.options.lazy === false) rows.forEach((row, index) => this.getContent(row, index));\n }\n\n /** Check if a row is expanded */\n isExpanded(rowIndex: number): boolean {\n return this.expandedRows.has(rowIndex);\n }\n\n /** Toggle expansion of a row */\n toggle(rowIndex: number) {\n if (this.expandedRows.has(rowIndex)) {\n this.collapse(rowIndex);\n } else {\n this.expand(rowIndex);\n }\n }\n\n /** Expand a row */\n expand(rowIndex: number) {\n this.expandedRows.add(rowIndex);\n this.tableElement?.dispatchEvent(new CustomEvent('row-expand', {\n detail: { rowIndex },\n bubbles: true,\n composed: true,\n }));\n }\n\n /** Collapse a row */\n collapse(rowIndex: number) {\n this.expandedRows.delete(rowIndex);\n if (this.options?.lazy !== false) {\n const row = this.rowByIndex.get(rowIndex);\n if (row !== undefined) {\n this.contentCache.delete(row);\n this.measuredHeights.delete(row);\n }\n }\n this.tableElement?.dispatchEvent(new CustomEvent('row-collapse', {\n detail: { rowIndex },\n bubbles: true,\n composed: true,\n }));\n }\n\n /** Expand all rows */\n expandAll(totalRows: number) {\n for (let i = 0; i < totalRows; i++) {\n this.expandedRows.add(i);\n }\n }\n\n /** Collapse all rows */\n collapseAll() {\n this.expandedRows.clear();\n if (this.options?.lazy !== false) {\n this.contentCache.clear();\n this.measuredHeights.clear();\n }\n }\n\n /** Get set of expanded row indices */\n getExpandedRows(): Set<number> {\n return new Set(this.expandedRows);\n }\n\n /** Replace expansion indices without emitting user-action events. */\n setExpandedRows(rowIndices: Iterable<number>) {\n const next = new Set(rowIndices);\n if (this.options?.lazy !== false) {\n for (const index of this.expandedRows) {\n if (next.has(index)) continue;\n const row = this.rowByIndex.get(index);\n if (row !== undefined) {\n this.contentCache.delete(row);\n this.measuredHeights.delete(row);\n }\n }\n }\n this.expandedRows = next;\n }\n\n /** Create the expand/collapse toggle button — uses same chevron SVG as snice-accordion */\n createToggleButton(rowIndex: number): HTMLElement {\n const expanded = this.isExpanded(rowIndex);\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = `detail-toggle${expanded ? ' detail-toggle--expanded' : ''}`;\n btn.setAttribute('aria-expanded', String(expanded));\n btn.setAttribute('aria-label', expanded ? 'Collapse row' : 'Expand row');\n const customIcon = expanded ? this.options?.collapseIcon : this.options?.expandIcon;\n if (customIcon) {\n if (customIcon.trim().startsWith('<')) btn.innerHTML = customIcon;\n else btn.textContent = customIcon;\n } else {\n btn.innerHTML = `<svg class=\"detail-toggle-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M6 9l6 6 6-6\"/></svg>`;\n }\n\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.toggle(rowIndex);\n this.tableElement?.dispatchEvent(new CustomEvent('detail-toggle', {\n detail: { rowIndex, expanded: this.isExpanded(rowIndex) },\n bubbles: true,\n composed: true,\n }));\n });\n\n return btn;\n }\n\n /** Create the detail panel row (a <tr> with a single <td> spanning all columns) */\n createDetailRow(row: any, rowIndex: number, colSpan: number): HTMLTableRowElement | null {\n if (!this.options || !this.isExpanded(rowIndex)) return null;\n\n const tr = document.createElement('tr');\n tr.className = 'detail-row';\n tr.setAttribute('data-detail-for', String(rowIndex));\n\n const td = document.createElement('td');\n td.colSpan = colSpan;\n td.className = 'detail-cell';\n td.style.padding = '0';\n td.style.border = 'none';\n\n // Animated wrapper — same pattern as snice-accordion\n const wrapper = document.createElement('div');\n wrapper.className = 'detail-content';\n\n const inner = document.createElement('div');\n inner.className = 'detail-content-inner';\n\n const content = this.getContent(row, rowIndex);\n if (typeof content === 'string') {\n inner.innerHTML = content;\n } else if (content instanceof HTMLElement) {\n inner.appendChild(content);\n }\n\n wrapper.appendChild(inner);\n td.appendChild(wrapper);\n\n // Trigger animation after insertion\n requestAnimationFrame(() => {\n const configuredHeight = this.options?.detailHeight;\n const height = configuredHeight === undefined || configuredHeight === 'auto'\n ? `${inner.scrollHeight}px`\n : (typeof configuredHeight === 'number' ? `${configuredHeight}px` : configuredHeight);\n if (configuredHeight !== undefined && configuredHeight !== 'auto') {\n inner.style.height = height;\n inner.style.overflow = 'auto';\n }\n wrapper.style.setProperty('--detail-max-height', height);\n wrapper.classList.add('detail-content--open');\n const measuredHeight = inner.getBoundingClientRect().height || inner.scrollHeight;\n const previousHeight = this.measuredHeights.get(row);\n if (measuredHeight > 0 && measuredHeight !== previousHeight) {\n this.measuredHeights.set(row, measuredHeight);\n this.onHeightChange?.();\n }\n });\n\n tr.appendChild(td);\n return tr;\n }\n\n isEnabled(): boolean {\n return this.options !== null;\n }\n\n /** Extra height contributed by an expanded detail row. Auto/non-pixel\n * panels use the most recent browser measurement. */\n getFixedAdditionalHeight(rowIndex: number): number {\n if (!this.isExpanded(rowIndex)) return 0;\n const configured = this.options?.detailHeight;\n if (typeof configured === 'number') return Math.max(0, configured);\n if (typeof configured === 'string' && /^\\d+(?:\\.\\d+)?px$/.test(configured.trim())) {\n return Math.max(0, Number.parseFloat(configured));\n }\n const row = this.rowByIndex.get(rowIndex);\n return row === undefined ? 0 : (this.measuredHeights.get(row) || 0);\n }\n\n private getContent(row: any, rowIndex: number): string | HTMLElement {\n if (!this.options) return '';\n this.rowByIndex.set(rowIndex, row);\n if (!this.contentCache.has(row)) {\n this.contentCache.set(row, this.options.getDetailContent(row, rowIndex));\n }\n return this.contentCache.get(row)!;\n }\n}\n"],"names":[],"mappings":"AAAA;;;AAGG;MAeU,iBAAiB,CAAA;AAA9B,IAAA,WAAA,GAAA;AACU,QAAA,IAAA,CAAA,YAAY,GAAgB,IAAI,GAAG,EAAE;QACrC,IAAA,CAAA,OAAO,GAA8B,IAAI;QACzC,IAAA,CAAA,YAAY,GAAuB,IAAI;AACvC,QAAA,IAAA,CAAA,YAAY,GAAG,IAAI,GAAG,EAA6B;;AAEnD,QAAA,IAAA,CAAA,YAAY,GAAG,IAAI,GAAG,EAAe;AACrC,QAAA,IAAA,CAAA,UAAU,GAAG,IAAI,GAAG,EAAe;AACnC,QAAA,IAAA,CAAA,eAAe,GAAG,IAAI,GAAG,EAAe;QAChD,IAAA,CAAA,cAAc,GAAwB,IAAI;IAkO5C;IAhOE,MAAM,CAAC,OAAoB,EAAE,OAA2B,EAAA;AACtD,QAAA,IAAI,CAAC,YAAY,GAAG,OAAO;AAC3B,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO;AACtB,QAAA,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE;AACzB,QAAA,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE;AACzB,QAAA,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE;AACvB,QAAA,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE;IAC9B;AAEA;;;;;;;AAOG;IACH,OAAO,CAAC,IAAW,EAAE,WAAkC,EAAA;QACrD,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE;QACnB,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;AACjE,QAAA,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC;AACjC,QAAA,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,EAAE;AAC/C,YAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;AAAE,gBAAA,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC;AACnD,iBAAA,IAAI,WAAW,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,WAAW,CAAC,GAAG,CAAC,EAAE;AACvE,gBAAA,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC;AAC7B,gBAAA,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC;YAClC;QACF;QACA,IAAI,WAAW,EAAE;YACf,IAAI,CAAC,YAAY,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACvE;QACA,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE;AAC7C,YAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;AAAE,gBAAA,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC;QAC7D;AACA,QAAA,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,KAAK;AAAE,YAAA,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC5F;;AAGA,IAAA,UAAU,CAAC,QAAgB,EAAA;QACzB,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC;IACxC;;AAGA,IAAA,MAAM,CAAC,QAAgB,EAAA;QACrB,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;AACnC,YAAA,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACzB;aAAO;AACL,YAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;QACvB;IACF;;AAGA,IAAA,MAAM,CAAC,QAAgB,EAAA;AACrB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC/B,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,IAAI,WAAW,CAAC,YAAY,EAAE;YAC7D,MAAM,EAAE,EAAE,QAAQ,EAAE;AACpB,YAAA,OAAO,EAAE,IAAI;AACb,YAAA,QAAQ,EAAE,IAAI;AACf,SAAA,CAAC,CAAC;IACL;;AAGA,IAAA,QAAQ,CAAC,QAAgB,EAAA;AACvB,QAAA,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC;QAClC,IAAI,IAAI,CAAC,OAAO,EAAE,IAAI,KAAK,KAAK,EAAE;YAChC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC;AACzC,YAAA,IAAI,GAAG,KAAK,SAAS,EAAE;AACrB,gBAAA,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC;AAC7B,gBAAA,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC;YAClC;QACF;QACA,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,IAAI,WAAW,CAAC,cAAc,EAAE;YAC/D,MAAM,EAAE,EAAE,QAAQ,EAAE;AACpB,YAAA,OAAO,EAAE,IAAI;AACb,YAAA,QAAQ,EAAE,IAAI;AACf,SAAA,CAAC,CAAC;IACL;;AAGA,IAAA,SAAS,CAAC,SAAiB,EAAA;AACzB,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE;AAClC,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1B;IACF;;IAGA,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE;QACzB,IAAI,IAAI,CAAC,OAAO,EAAE,IAAI,KAAK,KAAK,EAAE;AAChC,YAAA,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE;AACzB,YAAA,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE;QAC9B;IACF;;IAGA,eAAe,GAAA;AACb,QAAA,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC;IACnC;;AAGA,IAAA,eAAe,CAAC,UAA4B,EAAA;AAC1C,QAAA,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC;QAChC,IAAI,IAAI,CAAC,OAAO,EAAE,IAAI,KAAK,KAAK,EAAE;AAChC,YAAA,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,YAAY,EAAE;AACrC,gBAAA,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;oBAAE;gBACrB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;AACtC,gBAAA,IAAI,GAAG,KAAK,SAAS,EAAE;AACrB,oBAAA,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC;AAC7B,oBAAA,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC;gBAClC;YACF;QACF;AACA,QAAA,IAAI,CAAC,YAAY,GAAG,IAAI;IAC1B;;AAGA,IAAA,kBAAkB,CAAC,QAAgB,EAAA;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAC1C,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;AAC5C,QAAA,GAAG,CAAC,IAAI,GAAG,QAAQ;AACnB,QAAA,GAAG,CAAC,SAAS,GAAG,CAAA,aAAA,EAAgB,QAAQ,GAAG,0BAA0B,GAAG,EAAE,EAAE;QAC5E,GAAG,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;AACnD,QAAA,GAAG,CAAC,YAAY,CAAC,YAAY,EAAE,QAAQ,GAAG,cAAc,GAAG,YAAY,CAAC;AACxE,QAAA,MAAM,UAAU,GAAG,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,UAAU;QACnF,IAAI,UAAU,EAAE;YACd,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;AAAE,gBAAA,GAAG,CAAC,SAAS,GAAG,UAAU;;AAC5D,gBAAA,GAAG,CAAC,WAAW,GAAG,UAAU;QACnC;aAAO;AACL,YAAA,GAAG,CAAC,SAAS,GAAG,CAAA,qIAAA,CAAuI;QACzJ;QAEA,GAAG,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,KAAI;YAClC,CAAC,CAAC,eAAe,EAAE;AACnB,YAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;YACrB,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,IAAI,WAAW,CAAC,eAAe,EAAE;AAChE,gBAAA,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;AACzD,gBAAA,OAAO,EAAE,IAAI;AACb,gBAAA,QAAQ,EAAE,IAAI;AACf,aAAA,CAAC,CAAC;AACL,QAAA,CAAC,CAAC;AAEF,QAAA,OAAO,GAAG;IACZ;;AAGA,IAAA,eAAe,CAAC,GAAQ,EAAE,QAAgB,EAAE,OAAe,EAAA;QACzD,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;AAAE,YAAA,OAAO,IAAI;QAE5D,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACvC,QAAA,EAAE,CAAC,SAAS,GAAG,YAAY;QAC3B,EAAE,CAAC,YAAY,CAAC,iBAAiB,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAEpD,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC;AACvC,QAAA,EAAE,CAAC,OAAO,GAAG,OAAO;AACpB,QAAA,EAAE,CAAC,SAAS,GAAG,aAAa;AAC5B,QAAA,EAAE,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG;AACtB,QAAA,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM;;QAGxB,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;AAC7C,QAAA,OAAO,CAAC,SAAS,GAAG,gBAAgB;QAEpC,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;AAC3C,QAAA,KAAK,CAAC,SAAS,GAAG,sBAAsB;QAExC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;AAC9C,QAAA,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE;AAC/B,YAAA,KAAK,CAAC,SAAS,GAAG,OAAO;QAC3B;AAAO,aAAA,IAAI,OAAO,YAAY,WAAW,EAAE;AACzC,YAAA,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC;QAC5B;AAEA,QAAA,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC;AAC1B,QAAA,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC;;QAGvB,qBAAqB,CAAC,MAAK;AACzB,YAAA,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY;YACnD,MAAM,MAAM,GAAG,gBAAgB,KAAK,SAAS,IAAI,gBAAgB,KAAK;AACpE,kBAAE,CAAA,EAAG,KAAK,CAAC,YAAY,CAAA,EAAA;AACvB,mBAAG,OAAO,gBAAgB,KAAK,QAAQ,GAAG,CAAA,EAAG,gBAAgB,CAAA,EAAA,CAAI,GAAG,gBAAgB,CAAC;YACvF,IAAI,gBAAgB,KAAK,SAAS,IAAI,gBAAgB,KAAK,MAAM,EAAE;AACjE,gBAAA,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM;AAC3B,gBAAA,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG,MAAM;YAC/B;YACA,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,qBAAqB,EAAE,MAAM,CAAC;AACxD,YAAA,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,sBAAsB,CAAC;AAC7C,YAAA,MAAM,cAAc,GAAG,KAAK,CAAC,qBAAqB,EAAE,CAAC,MAAM,IAAI,KAAK,CAAC,YAAY;YACjF,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC;YACpD,IAAI,cAAc,GAAG,CAAC,IAAI,cAAc,KAAK,cAAc,EAAE;gBAC3D,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC;AAC7C,gBAAA,IAAI,CAAC,cAAc,IAAI;YACzB;AACF,QAAA,CAAC,CAAC;AAEF,QAAA,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;AAClB,QAAA,OAAO,EAAE;IACX;IAEA,SAAS,GAAA;AACP,QAAA,OAAO,IAAI,CAAC,OAAO,KAAK,IAAI;IAC9B;AAEA;AACqD;AACrD,IAAA,wBAAwB,CAAC,QAAgB,EAAA;AACvC,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;AAAE,YAAA,OAAO,CAAC;AACxC,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY;QAC7C,IAAI,OAAO,UAAU,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AAClE,QAAA,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,EAAE;AACjF,YAAA,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QACnD;QACA,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC;QACzC,OAAO,GAAG,KAAK,SAAS,GAAG,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrE;IAEQ,UAAU,CAAC,GAAQ,EAAE,QAAgB,EAAA;QAC3C,IAAI,CAAC,IAAI,CAAC,OAAO;AAAE,YAAA,OAAO,EAAE;QAC5B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AAC/B,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAC1E;QACA,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAE;IACpC;AACD;;;;"}
|
|
@@ -2,7 +2,6 @@ import type { SniceTagInputElement } from './snice-tag-input.types';
|
|
|
2
2
|
export declare class SniceTagInput extends HTMLElement implements SniceTagInputElement {
|
|
3
3
|
internals: ElementInternals;
|
|
4
4
|
private dirtyValue;
|
|
5
|
-
private suppressValueEvent;
|
|
6
5
|
private customValidationMessage;
|
|
7
6
|
private readonly labelAssociation;
|
|
8
7
|
private validationInput?;
|
|
@@ -11,7 +10,8 @@ export declare class SniceTagInput extends HTMLElement implements SniceTagInputE
|
|
|
11
10
|
private constraintInvalid;
|
|
12
11
|
constructor();
|
|
13
12
|
/**
|
|
14
|
-
* Live tags. Assignments do not rewrite the authored reset default
|
|
13
|
+
* Live tags. Assignments do not rewrite the authored reset default and do
|
|
14
|
+
* not emit `tag-change`; only tag edits do.
|
|
15
15
|
* @public
|
|
16
16
|
*/
|
|
17
17
|
get value(): string[];
|
|
@@ -153,7 +153,6 @@ let SniceTagInput = (() => {
|
|
|
153
153
|
super();
|
|
154
154
|
this.internals = __runInitializers(this, _instanceExtraInitializers);
|
|
155
155
|
this.dirtyValue = false;
|
|
156
|
-
this.suppressValueEvent = false;
|
|
157
156
|
this.customValidationMessage = '';
|
|
158
157
|
this.valueState = __runInitializers(this, _valueState_initializers, []);
|
|
159
158
|
this.formDisabled = (__runInitializers(this, _valueState_extraInitializers), __runInitializers(this, _formDisabled_initializers, false));
|
|
@@ -186,14 +185,15 @@ let SniceTagInput = (() => {
|
|
|
186
185
|
this.labelAssociation = new FormLabelAssociation(this, () => this.internals, () => this.interactionDisabled ? undefined : this.validationAnchor, () => this.label || 'Tags');
|
|
187
186
|
}
|
|
188
187
|
/**
|
|
189
|
-
* Live tags. Assignments do not rewrite the authored reset default
|
|
188
|
+
* Live tags. Assignments do not rewrite the authored reset default and do
|
|
189
|
+
* not emit `tag-change`; only tag edits do.
|
|
190
190
|
* @public
|
|
191
191
|
*/
|
|
192
192
|
get value() {
|
|
193
193
|
return this.valueState;
|
|
194
194
|
}
|
|
195
195
|
set value(value) {
|
|
196
|
-
this.setValue(value, true
|
|
196
|
+
this.setValue(value, true);
|
|
197
197
|
}
|
|
198
198
|
formAssociatedCallback() {
|
|
199
199
|
this.syncFormState();
|
|
@@ -213,7 +213,7 @@ let SniceTagInput = (() => {
|
|
|
213
213
|
try {
|
|
214
214
|
const value = JSON.parse(state);
|
|
215
215
|
if (Array.isArray(value)) {
|
|
216
|
-
this.setValue(value.map(String), true
|
|
216
|
+
this.setValue(value.map(String), true);
|
|
217
217
|
this.clearDraft();
|
|
218
218
|
}
|
|
219
219
|
}
|
|
@@ -253,20 +253,14 @@ let SniceTagInput = (() => {
|
|
|
253
253
|
return this.disabled || this.formDisabled;
|
|
254
254
|
}
|
|
255
255
|
applyDefaultValue() {
|
|
256
|
-
this.setValue(this.defaultValue, false
|
|
256
|
+
this.setValue(this.defaultValue, false);
|
|
257
257
|
}
|
|
258
|
-
setValue(value, dirty
|
|
258
|
+
setValue(value, dirty) {
|
|
259
259
|
if (!Array.isArray(value))
|
|
260
260
|
return;
|
|
261
261
|
if (dirty)
|
|
262
262
|
this.dirtyValue = true;
|
|
263
|
-
this.
|
|
264
|
-
try {
|
|
265
|
-
this.valueState = value.map(String);
|
|
266
|
-
}
|
|
267
|
-
finally {
|
|
268
|
-
this.suppressValueEvent = false;
|
|
269
|
-
}
|
|
263
|
+
this.valueState = value.map(String);
|
|
270
264
|
this.syncFormState();
|
|
271
265
|
}
|
|
272
266
|
syncFormValue() {
|
|
@@ -329,8 +323,6 @@ let SniceTagInput = (() => {
|
|
|
329
323
|
handleValueChange() {
|
|
330
324
|
this.syncFormState();
|
|
331
325
|
this.syncValidityAfterRender();
|
|
332
|
-
if (!this.suppressValueEvent)
|
|
333
|
-
this.emitChange();
|
|
334
326
|
}
|
|
335
327
|
handleDefaultValueChange() {
|
|
336
328
|
if (!this.dirtyValue)
|
|
@@ -421,6 +413,7 @@ let SniceTagInput = (() => {
|
|
|
421
413
|
return;
|
|
422
414
|
this.value = [...this.value, trimmed];
|
|
423
415
|
this.emitAdd(trimmed);
|
|
416
|
+
this.emitChange();
|
|
424
417
|
}
|
|
425
418
|
removeTag(index) {
|
|
426
419
|
if (index < 0 || index >= this.value.length)
|
|
@@ -428,6 +421,7 @@ let SniceTagInput = (() => {
|
|
|
428
421
|
const removed = this.value[index];
|
|
429
422
|
this.value = this.value.filter((_, i) => i !== index);
|
|
430
423
|
this.emitRemove(removed, index);
|
|
424
|
+
this.emitChange();
|
|
431
425
|
}
|
|
432
426
|
clear() {
|
|
433
427
|
this.value = [];
|