@dragonworks/ngx-dashboard 21.1.2 → 21.2.2
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.
|
@@ -23,7 +23,7 @@ import { isPlatformBrowser } from '@angular/common';
|
|
|
23
23
|
|
|
24
24
|
// Auto-generated by scripts/generate-versions.js
|
|
25
25
|
// Do not edit manually
|
|
26
|
-
const NGX_DASHBOARD_VERSION = '21.
|
|
26
|
+
const NGX_DASHBOARD_VERSION = '21.2.2';
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Maximum number of columns supported by the grid.
|
|
@@ -1638,6 +1638,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1638
1638
|
}, template: "<!-- cell.component.html -->\n<div\n class=\"cell\"\n [class.is-resizing]=\"isResizing()\"\n [class.flat]=\"flat() === true\"\n [draggable]=\"draggable()\"\n (dragstart)=\"onDragStart($event)\"\n (dragend)=\"onDragEnd()\"\n (contextmenu)=\"onContextMenu($event)\"\n>\n <div class=\"content-area\">\n <ng-template #container></ng-template>\n </div>\n @if (isEditMode() && !isDragging()) {\n <!-- Right resize handle -->\n <div\n class=\"resize-handle resize-handle--right\"\n (mousedown)=\"onResizeStart($event, 'horizontal')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n <!-- Bottom resize handle -->\n <div\n class=\"resize-handle resize-handle--bottom\"\n (mousedown)=\"onResizeStart($event, 'vertical')\"\n >\n <div class=\"resize-handle-line\"></div>\n </div>\n }\n</div>\n\n@if (isResizing()) {\n<div class=\"resize-preview\" i18n=\"@@ngx.dashboard.cell.resize.dimensions\">\n {{ resizeData()?.previewColSpan ?? colSpan() }} \u00D7\n {{ resizeData()?.previewRowSpan ?? rowSpan() }}\n</div>\n}\n", styles: [":host{display:block;width:100%;height:100%;position:relative;z-index:1;container-type:inline-size}:host(.drag-active):not(.is-dragging){pointer-events:none}:host(.is-dragging){z-index:100;opacity:.5;pointer-events:none}:host(.is-dragging) .content-area{pointer-events:none}:host(:hover) .resize-handle{opacity:1}.cell{width:100%;height:100%;border-radius:4px;box-shadow:0 2px 6px #0000001a;padding:0;box-sizing:border-box;overflow:hidden;position:relative;container-type:inline-size}.cell:hover{box-shadow:0 4px 10px #00000026;transform:translateY(-2px)}.cell.flat{box-shadow:none;border:none}.cell.flat:hover{box-shadow:none;transform:none;border-color:#bdbdbd}.cell.resizing{-webkit-user-select:none;user-select:none}.content-area{width:100%;height:100%;overflow:auto;pointer-events:auto;position:relative;z-index:1}.content-area:hover{transform:initial}:host(:not(.is-dragging)) .cell.flat .content-area{pointer-events:auto}:host(:not(.is-dragging)) .cell.flat .content-area:hover{transform:initial}.resize-handle{position:absolute;z-index:20}.resize-handle--right{cursor:col-resize;width:16px;height:100%;right:-8px;top:0;display:flex;align-items:center;justify-content:center;opacity:0}.resize-handle--right:hover{opacity:1}.resize-handle--right:hover .resize-handle-line{background-color:var(--mat-sys-primary-container)}.resize-handle--bottom{cursor:row-resize;width:100%;height:16px;bottom:-8px;left:0;display:flex;align-items:center;justify-content:center;opacity:0}.resize-handle--bottom:hover{opacity:1}.resize-handle--bottom:hover .resize-handle-line{background-color:var(--mat-sys-primary-container)}.resize-handle-line{background-color:#0000001a}.resize-handle--right .resize-handle-line{width:8px;height:40px;border-radius:2px}.resize-handle--bottom .resize-handle-line{width:40px;height:8px;border-radius:2px}.resize-preview{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary);padding:4px 12px;border-radius:4px;font-size:14px;font-weight:500;pointer-events:none;z-index:30}.cell.is-resizing{opacity:.6}.cell.is-resizing .resize-handle{background-color:#2196f380}:root .cursor-col-resize{cursor:col-resize!important}:root .cursor-row-resize{cursor:row-resize!important}\n"] }]
|
|
1639
1639
|
}], ctorParameters: () => [], propDecorators: { widgetId: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetId", required: true }] }], cellId: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellId", required: true }] }], widgetFactory: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetFactory", required: false }] }], widgetState: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetState", required: false }] }], isEditMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditMode", required: false }] }], flat: [{ type: i0.Input, args: [{ isSignal: true, alias: "flat", required: false }] }], row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: true }] }, { type: i0.Output, args: ["rowChange"] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }, { type: i0.Output, args: ["columnChange"] }], rowSpan: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowSpan", required: false }] }], colSpan: [{ type: i0.Input, args: [{ isSignal: true, alias: "colSpan", required: false }] }], draggable: [{ type: i0.Input, args: [{ isSignal: true, alias: "draggable", required: false }] }], dragStart: [{ type: i0.Output, args: ["dragStart"] }], dragEnd: [{ type: i0.Output, args: ["dragEnd"] }], edit: [{ type: i0.Output, args: ["edit"] }], delete: [{ type: i0.Output, args: ["delete"] }], settings: [{ type: i0.Output, args: ["settings"] }], resizeStart: [{ type: i0.Output, args: ["resizeStart"] }], resizeMove: [{ type: i0.Output, args: ["resizeMove"] }], resizeEnd: [{ type: i0.Output, args: ["resizeEnd"] }], container: [{ type: i0.ViewChild, args: ['container', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
|
|
1640
1640
|
|
|
1641
|
+
/**
|
|
1642
|
+
* Map SelectionModifier values to KeyboardEvent.key values. Compared against
|
|
1643
|
+
* `event.key` directly (rather than the boolean `*Key` flags) so unrelated
|
|
1644
|
+
* keypresses while a modifier is held don't flip the modifier-held state.
|
|
1645
|
+
*/
|
|
1646
|
+
const MODIFIER_KEY = {
|
|
1647
|
+
shift: 'Shift',
|
|
1648
|
+
ctrl: 'Control',
|
|
1649
|
+
alt: 'Alt',
|
|
1650
|
+
meta: 'Meta',
|
|
1651
|
+
};
|
|
1641
1652
|
class DashboardViewerComponent {
|
|
1642
1653
|
#store = inject(DashboardStore);
|
|
1643
1654
|
#renderer = inject(Renderer2);
|
|
@@ -1650,6 +1661,16 @@ class DashboardViewerComponent {
|
|
|
1650
1661
|
gutters = computed(() => this.columns() + 1, ...(ngDevMode ? [{ debugName: "gutters" }] : /* istanbul ignore next */ []));
|
|
1651
1662
|
// Selection feature
|
|
1652
1663
|
enableSelection = input(false, ...(ngDevMode ? [{ debugName: "enableSelection" }] : /* istanbul ignore next */ []));
|
|
1664
|
+
selectionModifier = input(null, ...(ngDevMode ? [{ debugName: "selectionModifier" }] : /* istanbul ignore next */ []));
|
|
1665
|
+
/**
|
|
1666
|
+
* Minimum pointer movement (in CSS pixels) between pointerdown and
|
|
1667
|
+
* pointerup required to emit `selectionComplete`. Below the threshold,
|
|
1668
|
+
* the gesture is treated as a click and no event is emitted.
|
|
1669
|
+
*
|
|
1670
|
+
* Default 4 — matches OS-native click-vs-drag thresholds. Set to 0 to
|
|
1671
|
+
* preserve the legacy behavior where every pointerup emits.
|
|
1672
|
+
*/
|
|
1673
|
+
dragThreshold = input(4, ...(ngDevMode ? [{ debugName: "dragThreshold" }] : /* istanbul ignore next */ []));
|
|
1653
1674
|
selectionComplete = output();
|
|
1654
1675
|
// store signals - read-only
|
|
1655
1676
|
cells = this.#store.cells;
|
|
@@ -1657,6 +1678,23 @@ class DashboardViewerComponent {
|
|
|
1657
1678
|
isSelecting = signal(false, ...(ngDevMode ? [{ debugName: "isSelecting" }] : /* istanbul ignore next */ []));
|
|
1658
1679
|
selectionStart = signal(null, ...(ngDevMode ? [{ debugName: "selectionStart" }] : /* istanbul ignore next */ []));
|
|
1659
1680
|
selectionCurrent = signal(null, ...(ngDevMode ? [{ debugName: "selectionCurrent" }] : /* istanbul ignore next */ []));
|
|
1681
|
+
// Modifier-key gating state for selectionModifier
|
|
1682
|
+
#modifierHeld = signal(false, ...(ngDevMode ? [{ debugName: "#modifierHeld" }] : /* istanbul ignore next */ []));
|
|
1683
|
+
/**
|
|
1684
|
+
* Whether the selection overlay is currently interactive (intercepts
|
|
1685
|
+
* pointer events). Always false when `enableSelection` is false.
|
|
1686
|
+
* When `selectionModifier` is null, true whenever selection is enabled
|
|
1687
|
+
* (legacy behavior). Otherwise, true only while the configured modifier
|
|
1688
|
+
* is held or a drag is in progress (which keeps the overlay armed
|
|
1689
|
+
* across mid-drag modifier release).
|
|
1690
|
+
*/
|
|
1691
|
+
armed = computed(() => {
|
|
1692
|
+
if (!this.enableSelection())
|
|
1693
|
+
return false;
|
|
1694
|
+
if (this.selectionModifier() === null)
|
|
1695
|
+
return true;
|
|
1696
|
+
return this.#modifierHeld() || this.isSelecting();
|
|
1697
|
+
}, ...(ngDevMode ? [{ debugName: "armed" }] : /* istanbul ignore next */ []));
|
|
1660
1698
|
// Computed selection bounds (normalized)
|
|
1661
1699
|
selectionBounds = computed(() => {
|
|
1662
1700
|
const start = this.selectionStart();
|
|
@@ -1673,9 +1711,11 @@ class DashboardViewerComponent {
|
|
|
1673
1711
|
// Generate array for template iteration
|
|
1674
1712
|
rowNumbers = computed(() => Array.from({ length: this.rows() }, (_, i) => i + 1), ...(ngDevMode ? [{ debugName: "rowNumbers" }] : /* istanbul ignore next */ []));
|
|
1675
1713
|
colNumbers = computed(() => Array.from({ length: this.columns() }, (_, i) => i + 1), ...(ngDevMode ? [{ debugName: "colNumbers" }] : /* istanbul ignore next */ []));
|
|
1676
|
-
// Document-level
|
|
1677
|
-
#
|
|
1678
|
-
#
|
|
1714
|
+
// Document-level pointer listeners (cleanup needed)
|
|
1715
|
+
#pointerMoveListener;
|
|
1716
|
+
#pointerUpListener;
|
|
1717
|
+
// Pointer position at the start of a drag, for dragThreshold checks
|
|
1718
|
+
#pointerDownPos = signal(null, ...(ngDevMode ? [{ debugName: "#pointerDownPos" }] : /* istanbul ignore next */ []));
|
|
1679
1719
|
constructor() {
|
|
1680
1720
|
// Sync grid configuration with store when inputs change
|
|
1681
1721
|
effect(() => {
|
|
@@ -1688,11 +1728,41 @@ class DashboardViewerComponent {
|
|
|
1688
1728
|
// Clear selection when selection mode is disabled
|
|
1689
1729
|
effect(() => {
|
|
1690
1730
|
if (!this.enableSelection()) {
|
|
1691
|
-
this.
|
|
1692
|
-
this.selectionCurrent.set(null);
|
|
1693
|
-
this.isSelecting.set(false);
|
|
1731
|
+
this.clearSelection();
|
|
1694
1732
|
}
|
|
1695
1733
|
});
|
|
1734
|
+
// Modifier-key tracking. Only registers document/window listeners when a
|
|
1735
|
+
// modifier is configured, so dashboards using the default (null) pay no
|
|
1736
|
+
// global keystroke cost. Cleans up listeners and resets state on
|
|
1737
|
+
// modifier change or component teardown.
|
|
1738
|
+
effect((onCleanup) => {
|
|
1739
|
+
const modifier = this.selectionModifier();
|
|
1740
|
+
if (modifier === null) {
|
|
1741
|
+
this.#modifierHeld.set(false);
|
|
1742
|
+
return;
|
|
1743
|
+
}
|
|
1744
|
+
const keyName = MODIFIER_KEY[modifier];
|
|
1745
|
+
const offKeyDown = this.#renderer.listen('document', 'keydown', (event) => {
|
|
1746
|
+
if (event.key === keyName) {
|
|
1747
|
+
this.#modifierHeld.set(true);
|
|
1748
|
+
}
|
|
1749
|
+
});
|
|
1750
|
+
const offKeyUp = this.#renderer.listen('document', 'keyup', (event) => {
|
|
1751
|
+
if (event.key === keyName) {
|
|
1752
|
+
this.#modifierHeld.set(false);
|
|
1753
|
+
}
|
|
1754
|
+
});
|
|
1755
|
+
// Cover focus-loss cases where keyup may never fire (Alt-Tab, etc.)
|
|
1756
|
+
const offBlur = this.#renderer.listen('window', 'blur', () => {
|
|
1757
|
+
this.#modifierHeld.set(false);
|
|
1758
|
+
});
|
|
1759
|
+
onCleanup(() => {
|
|
1760
|
+
offKeyDown();
|
|
1761
|
+
offKeyUp();
|
|
1762
|
+
offBlur();
|
|
1763
|
+
this.#modifierHeld.set(false);
|
|
1764
|
+
});
|
|
1765
|
+
});
|
|
1696
1766
|
}
|
|
1697
1767
|
// Selection methods
|
|
1698
1768
|
/**
|
|
@@ -1708,78 +1778,116 @@ class DashboardViewerComponent {
|
|
|
1708
1778
|
col <= bounds.endCol);
|
|
1709
1779
|
}
|
|
1710
1780
|
/**
|
|
1711
|
-
* Handle
|
|
1781
|
+
* Handle pointer down on a ghost cell to start a selection. Uses
|
|
1782
|
+
* PointerEvent so mouse / touch / pen all work uniformly.
|
|
1712
1783
|
*/
|
|
1713
|
-
|
|
1714
|
-
if (!this.
|
|
1784
|
+
onGhostCellPointerDown(event, row, col) {
|
|
1785
|
+
if (!this.armed())
|
|
1786
|
+
return;
|
|
1787
|
+
if (event.pointerType === 'mouse' && event.button !== 0)
|
|
1715
1788
|
return;
|
|
1716
|
-
if (event.button !== 0)
|
|
1717
|
-
return; // Only left button
|
|
1718
1789
|
event.preventDefault();
|
|
1719
1790
|
event.stopPropagation();
|
|
1720
1791
|
this.isSelecting.set(true);
|
|
1721
1792
|
this.selectionStart.set({ row, col });
|
|
1722
1793
|
this.selectionCurrent.set({ row, col });
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1794
|
+
this.#pointerDownPos.set({ x: event.clientX, y: event.clientY });
|
|
1795
|
+
const target = event.target;
|
|
1796
|
+
if (target instanceof Element &&
|
|
1797
|
+
typeof target.setPointerCapture === 'function') {
|
|
1798
|
+
try {
|
|
1799
|
+
target.setPointerCapture(event.pointerId);
|
|
1800
|
+
}
|
|
1801
|
+
catch {
|
|
1802
|
+
// Capture may be rejected for synthetic / invalid pointer ids;
|
|
1803
|
+
// document-level listeners still receive bubbled events.
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
this.#pointerMoveListener = this.#renderer.listen('document', 'pointermove', (e) => this.onDocumentPointerMove(e));
|
|
1807
|
+
this.#pointerUpListener = this.#renderer.listen('document', 'pointerup', (e) => this.onDocumentPointerUp(e));
|
|
1727
1808
|
this.#destroyRef.onDestroy(() => {
|
|
1728
1809
|
this.cleanupListeners();
|
|
1729
1810
|
});
|
|
1730
1811
|
}
|
|
1731
1812
|
/**
|
|
1732
|
-
*
|
|
1813
|
+
* Track the pointer across cell boundaries during a drag.
|
|
1814
|
+
*
|
|
1815
|
+
* Replaces the old per-cell `mouseenter` handler. Necessary because
|
|
1816
|
+
* pointer capture and (on touch) coalesced events make boundary
|
|
1817
|
+
* crossings unreliable when relying on per-element enter events.
|
|
1733
1818
|
*/
|
|
1734
|
-
|
|
1819
|
+
onDocumentPointerMove(event) {
|
|
1735
1820
|
if (!this.isSelecting())
|
|
1736
1821
|
return;
|
|
1822
|
+
const el = document.elementFromPoint(event.clientX, event.clientY);
|
|
1823
|
+
const cell = el?.closest('.selection-ghost-cell');
|
|
1824
|
+
if (!cell)
|
|
1825
|
+
return;
|
|
1826
|
+
const row = Number(cell.dataset['row']);
|
|
1827
|
+
const col = Number(cell.dataset['col']);
|
|
1828
|
+
if (!Number.isFinite(row) || !Number.isFinite(col))
|
|
1829
|
+
return;
|
|
1830
|
+
// Skip updates while still inside the same cell — otherwise pointermove
|
|
1831
|
+
// (60–120 Hz) would re-emit a fresh object reference every frame and
|
|
1832
|
+
// trigger downstream rerenders across the whole overlay grid.
|
|
1833
|
+
const cur = this.selectionCurrent();
|
|
1834
|
+
if (cur && cur.row === row && cur.col === col)
|
|
1835
|
+
return;
|
|
1737
1836
|
this.selectionCurrent.set({ row, col });
|
|
1738
1837
|
}
|
|
1739
1838
|
/**
|
|
1740
|
-
*
|
|
1839
|
+
* Complete a selection on pointerup. Emits `selectionComplete` only when
|
|
1840
|
+
* total pointer movement meets `dragThreshold` — sub-threshold gestures
|
|
1841
|
+
* are treated as clicks and discarded.
|
|
1741
1842
|
*/
|
|
1742
|
-
|
|
1843
|
+
onDocumentPointerUp(event) {
|
|
1743
1844
|
if (!this.isSelecting())
|
|
1744
1845
|
return;
|
|
1745
|
-
|
|
1746
|
-
|
|
1846
|
+
this.isSelecting.set(false);
|
|
1847
|
+
const start = this.#pointerDownPos();
|
|
1848
|
+
const moved = start === null ||
|
|
1849
|
+
Math.hypot(event.clientX - start.x, event.clientY - start.y) >=
|
|
1850
|
+
this.dragThreshold();
|
|
1851
|
+
if (moved) {
|
|
1852
|
+
const bounds = this.selectionBounds();
|
|
1853
|
+
if (bounds) {
|
|
1854
|
+
this.selectionComplete.emit({
|
|
1855
|
+
topLeft: { row: bounds.startRow, col: bounds.startCol },
|
|
1856
|
+
bottomRight: { row: bounds.endRow, col: bounds.endCol },
|
|
1857
|
+
});
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
this.#pointerDownPos.set(null);
|
|
1861
|
+
this.cleanupListeners();
|
|
1862
|
+
// Don't clear selection - let the parent control when to clear.
|
|
1863
|
+
// Selection remains visible until enableSelection becomes false.
|
|
1747
1864
|
}
|
|
1748
1865
|
/**
|
|
1749
|
-
*
|
|
1866
|
+
* Drop the visible selection rectangle. After `selectionComplete` emits,
|
|
1867
|
+
* the viewer leaves `selectionStart`/`selectionCurrent` set so consumers
|
|
1868
|
+
* can render a confirm UX with the rectangle still visible. Call this
|
|
1869
|
+
* once that UX is done. No-op if no selection is active.
|
|
1750
1870
|
*/
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1871
|
+
clearSelection() {
|
|
1872
|
+
this.selectionStart.set(null);
|
|
1873
|
+
this.selectionCurrent.set(null);
|
|
1754
1874
|
this.isSelecting.set(false);
|
|
1755
|
-
// Emit selection event
|
|
1756
|
-
const bounds = this.selectionBounds();
|
|
1757
|
-
if (bounds) {
|
|
1758
|
-
this.selectionComplete.emit({
|
|
1759
|
-
topLeft: { row: bounds.startRow, col: bounds.startCol },
|
|
1760
|
-
bottomRight: { row: bounds.endRow, col: bounds.endCol },
|
|
1761
|
-
});
|
|
1762
|
-
}
|
|
1763
|
-
// Clean up listeners
|
|
1764
|
-
this.cleanupListeners();
|
|
1765
|
-
// Don't clear selection - let the parent control when to clear
|
|
1766
|
-
// Selection remains visible until enableSelection becomes false
|
|
1767
1875
|
}
|
|
1768
1876
|
/**
|
|
1769
1877
|
* Clean up document-level event listeners
|
|
1770
1878
|
*/
|
|
1771
1879
|
cleanupListeners() {
|
|
1772
|
-
if (this.#
|
|
1773
|
-
this.#
|
|
1774
|
-
this.#
|
|
1880
|
+
if (this.#pointerMoveListener) {
|
|
1881
|
+
this.#pointerMoveListener();
|
|
1882
|
+
this.#pointerMoveListener = undefined;
|
|
1775
1883
|
}
|
|
1776
|
-
if (this.#
|
|
1777
|
-
this.#
|
|
1778
|
-
this.#
|
|
1884
|
+
if (this.#pointerUpListener) {
|
|
1885
|
+
this.#pointerUpListener();
|
|
1886
|
+
this.#pointerUpListener = undefined;
|
|
1779
1887
|
}
|
|
1780
1888
|
}
|
|
1781
1889
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1782
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: DashboardViewerComponent, isStandalone: true, selector: "ngx-dashboard-viewer", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, gutterSize: { classPropertyName: "gutterSize", publicName: "gutterSize", isSignal: true, isRequired: false, transformFunction: null }, enableSelection: { classPropertyName: "enableSelection", publicName: "enableSelection", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionComplete: "selectionComplete" }, host: { properties: { "style.--rows": "rows()", "style.--columns": "columns()", "style.--gutter-size": "gutterSize()", "style.--gutters": "gutters()" } }, viewQueries: [{ propertyName: "cellComponents", predicate: CellComponent, descendants: true, isSignal: true }, { propertyName: "gridElement", first: true, predicate: ["gridElement"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Dashboard viewer - read-only grid -->\n<div class=\"grid top-grid\" #gridElement>\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"false\"\n [draggable]=\"false\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n >\n </lib-cell>\n }\n</div>\n\n<!-- Selection overlay grid - mirror of main grid for cell selection -->\n@if (enableSelection()) {\n <div class=\"selection-overlay-grid\">\n @for (row of rowNumbers(); track row) {\n @for (col of colNumbers(); track col) {\n <div\n class=\"selection-ghost-cell\"\n [class.selected]=\"isCellSelected(row, col)\"\n [class.selecting]=\"isSelecting()\"\n [style.grid-row]=\"row\"\n [style.grid-column]=\"col\"\n
|
|
1890
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: DashboardViewerComponent, isStandalone: true, selector: "ngx-dashboard-viewer", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, gutterSize: { classPropertyName: "gutterSize", publicName: "gutterSize", isSignal: true, isRequired: false, transformFunction: null }, enableSelection: { classPropertyName: "enableSelection", publicName: "enableSelection", isSignal: true, isRequired: false, transformFunction: null }, selectionModifier: { classPropertyName: "selectionModifier", publicName: "selectionModifier", isSignal: true, isRequired: false, transformFunction: null }, dragThreshold: { classPropertyName: "dragThreshold", publicName: "dragThreshold", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionComplete: "selectionComplete" }, host: { properties: { "style.--rows": "rows()", "style.--columns": "columns()", "style.--gutter-size": "gutterSize()", "style.--gutters": "gutters()" } }, viewQueries: [{ propertyName: "cellComponents", predicate: CellComponent, descendants: true, isSignal: true }, { propertyName: "gridElement", first: true, predicate: ["gridElement"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Dashboard viewer - read-only grid -->\n<div class=\"grid top-grid\" #gridElement>\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"false\"\n [draggable]=\"false\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n >\n </lib-cell>\n }\n</div>\n\n<!-- Selection overlay grid - mirror of main grid for cell selection -->\n@if (enableSelection()) {\n <div class=\"selection-overlay-grid\" [class.armed]=\"armed()\">\n @for (row of rowNumbers(); track row) {\n @for (col of colNumbers(); track col) {\n <div\n class=\"selection-ghost-cell\"\n [class.selected]=\"isCellSelected(row, col)\"\n [class.selecting]=\"isSelecting()\"\n [style.grid-row]=\"row\"\n [style.grid-column]=\"col\"\n [attr.data-row]=\"row\"\n [attr.data-col]=\"col\"\n (pointerdown)=\"onGhostCellPointerDown($event, row, col)\"\n ></div>\n }\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{--cell-size: calc( 100cqi / var(--columns) - var(--gutter-size) * var(--gutters) / var(--columns) );--tile-size: calc(var(--cell-size) + var(--gutter-size));--tile-offset: calc( var(--gutter-size) + var(--cell-size) + var(--gutter-size) / 2 );display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto;position:relative;background-color:var(--mat-sys-surface-container)}.grid{display:grid;gap:var(--gutter-size);padding:var(--gutter-size);width:100%;height:100%;box-sizing:border-box;grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size))}.grid-cell{pointer-events:none}.grid-cell:not(.flat){pointer-events:auto;cursor:default}.grid-cell:not(.flat) .content-area{pointer-events:none}.top-grid{z-index:2;pointer-events:none}.selection-overlay-grid{position:absolute;top:0;left:0;width:100%;height:100%;display:grid;gap:var(--gutter-size);padding:var(--gutter-size);grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size));z-index:5;pointer-events:none;-webkit-user-select:none;user-select:none}.selection-overlay-grid.armed{pointer-events:auto}.selection-ghost-cell{transition:background-color .1s ease,border-radius .1s ease;border-radius:2px}.selection-ghost-cell.selected{background-color:color-mix(in srgb,var(--mat-sys-primary) 25%,transparent);border-radius:4px}.selection-overlay-grid.armed .selection-ghost-cell{cursor:crosshair}.selection-overlay-grid.armed .selection-ghost-cell:hover:not(.selecting){background-color:color-mix(in srgb,var(--mat-sys-primary) 8%,transparent)}.selection-overlay-grid.armed .selection-ghost-cell.selecting{cursor:crosshair}\n"], dependencies: [{ kind: "component", type: CellComponent, selector: "lib-cell", inputs: ["widgetId", "cellId", "widgetFactory", "widgetState", "isEditMode", "flat", "row", "column", "rowSpan", "colSpan", "draggable"], outputs: ["rowChange", "columnChange", "dragStart", "dragEnd", "edit", "delete", "settings", "resizeStart", "resizeMove", "resizeEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1783
1891
|
}
|
|
1784
1892
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardViewerComponent, decorators: [{
|
|
1785
1893
|
type: Component,
|
|
@@ -1788,8 +1896,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1788
1896
|
'[style.--columns]': 'columns()',
|
|
1789
1897
|
'[style.--gutter-size]': 'gutterSize()',
|
|
1790
1898
|
'[style.--gutters]': 'gutters()',
|
|
1791
|
-
}, template: "<!-- Dashboard viewer - read-only grid -->\n<div class=\"grid top-grid\" #gridElement>\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"false\"\n [draggable]=\"false\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n >\n </lib-cell>\n }\n</div>\n\n<!-- Selection overlay grid - mirror of main grid for cell selection -->\n@if (enableSelection()) {\n <div class=\"selection-overlay-grid\">\n @for (row of rowNumbers(); track row) {\n @for (col of colNumbers(); track col) {\n <div\n class=\"selection-ghost-cell\"\n [class.selected]=\"isCellSelected(row, col)\"\n [class.selecting]=\"isSelecting()\"\n [style.grid-row]=\"row\"\n [style.grid-column]=\"col\"\n
|
|
1792
|
-
}], ctorParameters: () => [], propDecorators: { cellComponents: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => CellComponent), { isSignal: true }] }], gridElement: [{ type: i0.ViewChild, args: ['gridElement', { isSignal: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], gutterSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "gutterSize", required: false }] }], enableSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSelection", required: false }] }], selectionComplete: [{ type: i0.Output, args: ["selectionComplete"] }] } });
|
|
1899
|
+
}, template: "<!-- Dashboard viewer - read-only grid -->\n<div class=\"grid top-grid\" #gridElement>\n @for (cell of cells(); track cell.widgetId) {\n <lib-cell\n class=\"grid-cell\"\n [widgetId]=\"cell.widgetId\"\n [cellId]=\"cell.cellId\"\n [isEditMode]=\"false\"\n [draggable]=\"false\"\n [row]=\"cell.row\"\n [column]=\"cell.col\"\n [rowSpan]=\"cell.rowSpan\"\n [colSpan]=\"cell.colSpan\"\n [flat]=\"cell.flat\"\n [widgetFactory]=\"cell.widgetFactory\"\n [widgetState]=\"cell.widgetState\"\n >\n </lib-cell>\n }\n</div>\n\n<!-- Selection overlay grid - mirror of main grid for cell selection -->\n@if (enableSelection()) {\n <div class=\"selection-overlay-grid\" [class.armed]=\"armed()\">\n @for (row of rowNumbers(); track row) {\n @for (col of colNumbers(); track col) {\n <div\n class=\"selection-ghost-cell\"\n [class.selected]=\"isCellSelected(row, col)\"\n [class.selecting]=\"isSelecting()\"\n [style.grid-row]=\"row\"\n [style.grid-column]=\"col\"\n [attr.data-row]=\"row\"\n [attr.data-col]=\"col\"\n (pointerdown)=\"onGhostCellPointerDown($event, row, col)\"\n ></div>\n }\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{--cell-size: calc( 100cqi / var(--columns) - var(--gutter-size) * var(--gutters) / var(--columns) );--tile-size: calc(var(--cell-size) + var(--gutter-size));--tile-offset: calc( var(--gutter-size) + var(--cell-size) + var(--gutter-size) / 2 );display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto;position:relative;background-color:var(--mat-sys-surface-container)}.grid{display:grid;gap:var(--gutter-size);padding:var(--gutter-size);width:100%;height:100%;box-sizing:border-box;grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size))}.grid-cell{pointer-events:none}.grid-cell:not(.flat){pointer-events:auto;cursor:default}.grid-cell:not(.flat) .content-area{pointer-events:none}.top-grid{z-index:2;pointer-events:none}.selection-overlay-grid{position:absolute;top:0;left:0;width:100%;height:100%;display:grid;gap:var(--gutter-size);padding:var(--gutter-size);grid-template-columns:repeat(var(--columns),var(--cell-size));grid-template-rows:repeat(var(--rows),var(--cell-size));z-index:5;pointer-events:none;-webkit-user-select:none;user-select:none}.selection-overlay-grid.armed{pointer-events:auto}.selection-ghost-cell{transition:background-color .1s ease,border-radius .1s ease;border-radius:2px}.selection-ghost-cell.selected{background-color:color-mix(in srgb,var(--mat-sys-primary) 25%,transparent);border-radius:4px}.selection-overlay-grid.armed .selection-ghost-cell{cursor:crosshair}.selection-overlay-grid.armed .selection-ghost-cell:hover:not(.selecting){background-color:color-mix(in srgb,var(--mat-sys-primary) 8%,transparent)}.selection-overlay-grid.armed .selection-ghost-cell.selecting{cursor:crosshair}\n"] }]
|
|
1900
|
+
}], ctorParameters: () => [], propDecorators: { cellComponents: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => CellComponent), { isSignal: true }] }], gridElement: [{ type: i0.ViewChild, args: ['gridElement', { isSignal: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], gutterSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "gutterSize", required: false }] }], enableSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSelection", required: false }] }], selectionModifier: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionModifier", required: false }] }], dragThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragThreshold", required: false }] }], selectionComplete: [{ type: i0.Output, args: ["selectionComplete"] }] } });
|
|
1793
1901
|
|
|
1794
1902
|
class CellContextMenuComponent {
|
|
1795
1903
|
menuTrigger = viewChild.required('menuTrigger', { read: MatMenuTrigger });
|
|
@@ -2942,6 +3050,8 @@ class DashboardComponent {
|
|
|
2942
3050
|
editMode = input(false, ...(ngDevMode ? [{ debugName: "editMode" }] : /* istanbul ignore next */ []));
|
|
2943
3051
|
reservedSpace = input(...(ngDevMode ? [undefined, { debugName: "reservedSpace" }] : /* istanbul ignore next */ []));
|
|
2944
3052
|
enableSelection = input(false, ...(ngDevMode ? [{ debugName: "enableSelection" }] : /* istanbul ignore next */ []));
|
|
3053
|
+
selectionModifier = input(null, ...(ngDevMode ? [{ debugName: "selectionModifier" }] : /* istanbul ignore next */ []));
|
|
3054
|
+
dragThreshold = input(4, ...(ngDevMode ? [{ debugName: "dragThreshold" }] : /* istanbul ignore next */ []));
|
|
2945
3055
|
// Component outputs
|
|
2946
3056
|
selectionComplete = output();
|
|
2947
3057
|
// Store signals - shared by both child components
|
|
@@ -3042,6 +3152,13 @@ class DashboardComponent {
|
|
|
3042
3152
|
clearDashboard() {
|
|
3043
3153
|
this.#store.clearDashboard();
|
|
3044
3154
|
}
|
|
3155
|
+
/**
|
|
3156
|
+
* Forwards to the active viewer. No-op in edit mode.
|
|
3157
|
+
* See `DashboardViewerComponent.clearSelection()`.
|
|
3158
|
+
*/
|
|
3159
|
+
clearSelection() {
|
|
3160
|
+
this.dashboardViewer()?.clearSelection();
|
|
3161
|
+
}
|
|
3045
3162
|
/**
|
|
3046
3163
|
* Preserve widget states before switching modes by collecting live states
|
|
3047
3164
|
* from the currently active component and updating the store.
|
|
@@ -3079,7 +3196,7 @@ class DashboardComponent {
|
|
|
3079
3196
|
}
|
|
3080
3197
|
}
|
|
3081
3198
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3082
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: DashboardComponent, isStandalone: true, selector: "ngx-dashboard", inputs: { dashboardData: { classPropertyName: "dashboardData", publicName: "dashboardData", isSignal: true, isRequired: true, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null }, reservedSpace: { classPropertyName: "reservedSpace", publicName: "reservedSpace", isSignal: true, isRequired: false, transformFunction: null }, enableSelection: { classPropertyName: "enableSelection", publicName: "enableSelection", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionComplete: "selectionComplete" }, host: { properties: { "style.--rows": "store.rows()", "style.--columns": "store.columns()", "style.--gutter-size": "store.gutterSize()", "style.--gutters": "store.columns() + 1", "class.is-edit-mode": "editMode()", "style.max-width.px": "viewport.constraints().maxWidth", "style.max-height.px": "viewport.constraints().maxHeight" } }, providers: [DashboardStore, DashboardViewportService], viewQueries: [{ propertyName: "dashboardEditor", first: true, predicate: DashboardEditorComponent, descendants: true, isSignal: true }, { propertyName: "dashboardViewer", first: true, predicate: DashboardViewerComponent, descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<!-- dashboard.component.html -->\n<div class=\"grid-container\">\n @if (editMode()) {\n <!-- Full editor with drag & drop capabilities -->\n <ngx-dashboard-editor\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n ></ngx-dashboard-editor>\n } @else {\n <!-- Read-only viewer -->\n <ngx-dashboard-viewer\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n [enableSelection]=\"enableSelection()\"\n (selectionComplete)=\"selectionComplete.emit($event)\"\n ></ngx-dashboard-viewer>\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}.grid-container{position:relative;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: DashboardViewerComponent, selector: "ngx-dashboard-viewer", inputs: ["rows", "columns", "gutterSize", "enableSelection"], outputs: ["selectionComplete"] }, { kind: "component", type: DashboardEditorComponent, selector: "ngx-dashboard-editor", inputs: ["rows", "columns", "gutterSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3199
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: DashboardComponent, isStandalone: true, selector: "ngx-dashboard", inputs: { dashboardData: { classPropertyName: "dashboardData", publicName: "dashboardData", isSignal: true, isRequired: true, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null }, reservedSpace: { classPropertyName: "reservedSpace", publicName: "reservedSpace", isSignal: true, isRequired: false, transformFunction: null }, enableSelection: { classPropertyName: "enableSelection", publicName: "enableSelection", isSignal: true, isRequired: false, transformFunction: null }, selectionModifier: { classPropertyName: "selectionModifier", publicName: "selectionModifier", isSignal: true, isRequired: false, transformFunction: null }, dragThreshold: { classPropertyName: "dragThreshold", publicName: "dragThreshold", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionComplete: "selectionComplete" }, host: { properties: { "style.--rows": "store.rows()", "style.--columns": "store.columns()", "style.--gutter-size": "store.gutterSize()", "style.--gutters": "store.columns() + 1", "class.is-edit-mode": "editMode()", "style.max-width.px": "viewport.constraints().maxWidth", "style.max-height.px": "viewport.constraints().maxHeight" } }, providers: [DashboardStore, DashboardViewportService], viewQueries: [{ propertyName: "dashboardEditor", first: true, predicate: DashboardEditorComponent, descendants: true, isSignal: true }, { propertyName: "dashboardViewer", first: true, predicate: DashboardViewerComponent, descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<!-- dashboard.component.html -->\n<div class=\"grid-container\">\n @if (editMode()) {\n <!-- Full editor with drag & drop capabilities -->\n <ngx-dashboard-editor\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n ></ngx-dashboard-editor>\n } @else {\n <!-- Read-only viewer -->\n <ngx-dashboard-viewer\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n [enableSelection]=\"enableSelection()\"\n [selectionModifier]=\"selectionModifier()\"\n [dragThreshold]=\"dragThreshold()\"\n (selectionComplete)=\"selectionComplete.emit($event)\"\n ></ngx-dashboard-viewer>\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}.grid-container{position:relative;width:100%;height:100%}\n"], dependencies: [{ kind: "component", type: DashboardViewerComponent, selector: "ngx-dashboard-viewer", inputs: ["rows", "columns", "gutterSize", "enableSelection", "selectionModifier", "dragThreshold"], outputs: ["selectionComplete"] }, { kind: "component", type: DashboardEditorComponent, selector: "ngx-dashboard-editor", inputs: ["rows", "columns", "gutterSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3083
3200
|
}
|
|
3084
3201
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: DashboardComponent, decorators: [{
|
|
3085
3202
|
type: Component,
|
|
@@ -3091,8 +3208,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
3091
3208
|
'[class.is-edit-mode]': 'editMode()',
|
|
3092
3209
|
'[style.max-width.px]': 'viewport.constraints().maxWidth',
|
|
3093
3210
|
'[style.max-height.px]': 'viewport.constraints().maxHeight',
|
|
3094
|
-
}, template: "<!-- dashboard.component.html -->\n<div class=\"grid-container\">\n @if (editMode()) {\n <!-- Full editor with drag & drop capabilities -->\n <ngx-dashboard-editor\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n ></ngx-dashboard-editor>\n } @else {\n <!-- Read-only viewer -->\n <ngx-dashboard-viewer\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n [enableSelection]=\"enableSelection()\"\n (selectionComplete)=\"selectionComplete.emit($event)\"\n ></ngx-dashboard-viewer>\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}.grid-container{position:relative;width:100%;height:100%}\n"] }]
|
|
3095
|
-
}], ctorParameters: () => [], propDecorators: { dashboardData: [{ type: i0.Input, args: [{ isSignal: true, alias: "dashboardData", required: true }] }], editMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editMode", required: false }] }], reservedSpace: [{ type: i0.Input, args: [{ isSignal: true, alias: "reservedSpace", required: false }] }], enableSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSelection", required: false }] }], selectionComplete: [{ type: i0.Output, args: ["selectionComplete"] }], dashboardEditor: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DashboardEditorComponent), { isSignal: true }] }], dashboardViewer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DashboardViewerComponent), { isSignal: true }] }] } });
|
|
3211
|
+
}, template: "<!-- dashboard.component.html -->\n<div class=\"grid-container\">\n @if (editMode()) {\n <!-- Full editor with drag & drop capabilities -->\n <ngx-dashboard-editor\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n ></ngx-dashboard-editor>\n } @else {\n <!-- Read-only viewer -->\n <ngx-dashboard-viewer\n [rows]=\"store.rows()\"\n [columns]=\"store.columns()\"\n [gutterSize]=\"store.gutterSize()\"\n [enableSelection]=\"enableSelection()\"\n [selectionModifier]=\"selectionModifier()\"\n [dragThreshold]=\"dragThreshold()\"\n (selectionComplete)=\"selectionComplete.emit($event)\"\n ></ngx-dashboard-viewer>\n }\n</div>\n", styles: [":host{display:block;container-type:inline-size;box-sizing:border-box;aspect-ratio:var(--columns)/var(--rows);width:100%;height:auto}.grid-container{position:relative;width:100%;height:100%}\n"] }]
|
|
3212
|
+
}], ctorParameters: () => [], propDecorators: { dashboardData: [{ type: i0.Input, args: [{ isSignal: true, alias: "dashboardData", required: true }] }], editMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editMode", required: false }] }], reservedSpace: [{ type: i0.Input, args: [{ isSignal: true, alias: "reservedSpace", required: false }] }], enableSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSelection", required: false }] }], selectionModifier: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionModifier", required: false }] }], dragThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragThreshold", required: false }] }], selectionComplete: [{ type: i0.Output, args: ["selectionComplete"] }], dashboardEditor: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DashboardEditorComponent), { isSignal: true }] }], dashboardViewer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DashboardViewerComponent), { isSignal: true }] }] } });
|
|
3096
3213
|
|
|
3097
3214
|
// widget-list.component.ts
|
|
3098
3215
|
class WidgetListComponent {
|