@rozie-ui/data-table-lit 0.2.4 → 0.2.6
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/README.md +2 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +3 -2
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +1 -0
- package/package.json +2 -2
- package/src/Column.ts +13 -4
- package/src/DataTable.ts +1404 -1
- package/src/DetailPanel.ts +3 -0
- package/src/EditorCheckbox.ts +2 -0
- package/src/EditorNumber.ts +3 -0
- package/src/EditorSelect.ts +2 -2
- package/src/EditorText.ts +3 -3
- package/src/FilterNumberRange.ts +5 -2
- package/src/FilterSelect.ts +6 -0
- package/src/FilterText.ts +3 -3
- package/src/GroupBar.ts +18 -0
- package/src/themes/base.css +15 -0
package/src/DetailPanel.ts
CHANGED
|
@@ -42,6 +42,9 @@ export default class DetailPanel extends SignalWatcher(LitElement) {
|
|
|
42
42
|
`;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
// Plain setup-once helper (NOT $computed — a $computed can't be aliased; the
|
|
46
|
+
// EditorSelect plain-function lesson). Build `[{ key, value }]` from the row's own
|
|
47
|
+
// enumerable keys, String-coercing each value. A null row yields an empty list.
|
|
45
48
|
entries = () => {
|
|
46
49
|
const r = this.row;
|
|
47
50
|
if (!r) return [];
|
package/src/EditorCheckbox.ts
CHANGED
|
@@ -54,6 +54,8 @@ export default class EditorCheckbox extends SignalWatcher(LitElement) {
|
|
|
54
54
|
`;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
// Immediate-commit-on-change: read .checked the global-filter way, coerce to a
|
|
58
|
+
// real boolean, and commit it directly.
|
|
57
59
|
onChange = (e: any) => {
|
|
58
60
|
this.commit && this.commit(!!(e && e.target ? e.target.checked : false));
|
|
59
61
|
};
|
package/src/EditorNumber.ts
CHANGED
|
@@ -64,6 +64,9 @@ export default class EditorNumber extends SignalWatcher(LitElement) {
|
|
|
64
64
|
this._draft.value = e && e.target ? e.target.value : '';
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
+
// Coerce to a Number at commit time. Defensive guard: an empty/whitespace draft
|
|
68
|
+
// commits null rather than NaN (Number('') === 0 is a silent footgun); a
|
|
69
|
+
// non-numeric draft also commits null. Otherwise commit the coerced number.
|
|
67
70
|
doCommit = () => {
|
|
68
71
|
if (!this.commit) return;
|
|
69
72
|
const raw = this._draft.value;
|
package/src/EditorSelect.ts
CHANGED
|
@@ -49,8 +49,6 @@ export default class EditorSelect extends SignalWatcher(LitElement) {
|
|
|
49
49
|
// Seed the draft once from the incoming value (setup-once). Normalize null/undefined
|
|
50
50
|
// to '' so the <select> binds to a string.
|
|
51
51
|
this._draft.value = this.value != null ? String(this.value) : '';
|
|
52
|
-
|
|
53
|
-
// Picking/arrow-cycling an option updates the draft only — no commit.
|
|
54
52
|
}
|
|
55
53
|
|
|
56
54
|
disconnectedCallback(): void {
|
|
@@ -71,10 +69,12 @@ export default class EditorSelect extends SignalWatcher(LitElement) {
|
|
|
71
69
|
`;
|
|
72
70
|
}
|
|
73
71
|
|
|
72
|
+
// Picking/arrow-cycling an option updates the draft only — no commit.
|
|
74
73
|
onChange = (e: any) => {
|
|
75
74
|
this._draft.value = e && e.target ? e.target.value : '';
|
|
76
75
|
};
|
|
77
76
|
|
|
77
|
+
// commit/cancel are Function props (default null) — guard before calling.
|
|
78
78
|
doCommit = () => {
|
|
79
79
|
this.commit && this.commit(this._draft.value);
|
|
80
80
|
};
|
package/src/EditorText.ts
CHANGED
|
@@ -50,9 +50,6 @@ private __rozieFirstUpdateDone = false;
|
|
|
50
50
|
// template). Normalize null/undefined to '' so the input value binds to a string.
|
|
51
51
|
this._draft.value = this.value != null ? String(this.value) : '';
|
|
52
52
|
|
|
53
|
-
// Untyped handler param neutralizes to `any`, so reading e.target.value typechecks
|
|
54
|
-
// ×6 (the global-filter idiom). Never inline `$data.x = $event.target.value`.
|
|
55
|
-
|
|
56
53
|
if (this.autofocus) this._refInputEl?.focus();
|
|
57
54
|
}
|
|
58
55
|
|
|
@@ -79,10 +76,13 @@ private __rozieFirstUpdateDone = false;
|
|
|
79
76
|
`;
|
|
80
77
|
}
|
|
81
78
|
|
|
79
|
+
// Untyped handler param neutralizes to `any`, so reading e.target.value typechecks
|
|
80
|
+
// ×6 (the global-filter idiom). Never inline `$data.x = $event.target.value`.
|
|
82
81
|
onInput = (e: any) => {
|
|
83
82
|
this._draft.value = e && e.target ? e.target.value : '';
|
|
84
83
|
};
|
|
85
84
|
|
|
85
|
+
// commit/cancel are Function props (default null) — guard before calling.
|
|
86
86
|
doCommit = () => {
|
|
87
87
|
this.commit && this.commit(this._draft.value);
|
|
88
88
|
};
|
package/src/FilterNumberRange.ts
CHANGED
|
@@ -41,8 +41,6 @@ export default class FilterNumberRange extends SignalWatcher(LitElement) {
|
|
|
41
41
|
// Seed both drafts once at setup from the incoming [min,max] tuple (setup-once).
|
|
42
42
|
this._minDraft.value = Array.isArray(this.value) && this.value[0] != null ? String(this.value[0]) : '';
|
|
43
43
|
this._maxDraft.value = Array.isArray(this.value) && this.value[1] != null ? String(this.value[1]) : '';
|
|
44
|
-
|
|
45
|
-
// Untyped handler params neutralize to `any` (the global-filter idiom).
|
|
46
44
|
}
|
|
47
45
|
|
|
48
46
|
disconnectedCallback(): void {
|
|
@@ -65,6 +63,7 @@ export default class FilterNumberRange extends SignalWatcher(LitElement) {
|
|
|
65
63
|
`;
|
|
66
64
|
}
|
|
67
65
|
|
|
66
|
+
// Untyped handler params neutralize to `any` (the global-filter idiom).
|
|
68
67
|
onMinInput = (e: any) => {
|
|
69
68
|
this._minDraft.value = e && e.target ? e.target.value : '';
|
|
70
69
|
};
|
|
@@ -73,10 +72,14 @@ export default class FilterNumberRange extends SignalWatcher(LitElement) {
|
|
|
73
72
|
this._maxDraft.value = e && e.target ? e.target.value : '';
|
|
74
73
|
};
|
|
75
74
|
|
|
75
|
+
// Plain string-coercion functions for the placeholders (NOT $computed — the
|
|
76
|
+
// EditorSelect/listbox lesson; opaque slot-scope props rejected by strict leaf tsc).
|
|
76
77
|
minPlaceholder = () => Array.isArray(this.minMax) && this.minMax[0] != null ? String(this.minMax[0]) : '';
|
|
77
78
|
|
|
78
79
|
maxPlaceholder = () => Array.isArray(this.minMax) && this.minMax[1] != null ? String(this.minMax[1]) : '';
|
|
79
80
|
|
|
81
|
+
// Convert a draft to a Number or undefined (empty string → undefined so a
|
|
82
|
+
// one-sided range works). Both undefined → clear the filter.
|
|
80
83
|
applyRange = () => {
|
|
81
84
|
const minNum = this._minDraft.value === '' ? undefined : Number(this._minDraft.value);
|
|
82
85
|
const maxNum = this._maxDraft.value === '' ? undefined : Number(this._maxDraft.value);
|
package/src/FilterSelect.ts
CHANGED
|
@@ -55,8 +55,14 @@ export default class FilterSelect extends SignalWatcher(LitElement) {
|
|
|
55
55
|
`;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
// The <select> value binding coerced to a string. $props.value is typed `unknown`
|
|
59
|
+
// (opaque slot-scope), which the strict bundled-leaf tsc rejects against the native
|
|
60
|
+
// select `value` type on React/Solid — the fix is a plain function returning a
|
|
61
|
+
// string (uniform ×6, NOT a $computed; the EditorSelect/listbox value lesson).
|
|
58
62
|
selectValue = () => this.value != null ? String(this.value) : '';
|
|
59
63
|
|
|
64
|
+
// Immediate-apply-on-change: read the selected value the global-filter way. An
|
|
65
|
+
// empty value (the leading "All" option) clears the column filter.
|
|
60
66
|
onChange = (e: any) => {
|
|
61
67
|
const v = e && e.target ? e.target.value : '';
|
|
62
68
|
if (v === '') {
|
package/src/FilterText.ts
CHANGED
|
@@ -35,9 +35,6 @@ export default class FilterText extends SignalWatcher(LitElement) {
|
|
|
35
35
|
// Seed the draft once at setup from the incoming value (setup-once, NOT in the
|
|
36
36
|
// template). Normalize null/undefined to '' so the input value binds to a string.
|
|
37
37
|
this._draft.value = this.value != null ? String(this.value) : '';
|
|
38
|
-
|
|
39
|
-
// Untyped handler param neutralizes to `any`, so reading e.target.value typechecks
|
|
40
|
-
// ×6 (the global-filter idiom). Never inline `$data.x = $event.target.value`.
|
|
41
38
|
}
|
|
42
39
|
|
|
43
40
|
disconnectedCallback(): void {
|
|
@@ -56,10 +53,13 @@ export default class FilterText extends SignalWatcher(LitElement) {
|
|
|
56
53
|
`;
|
|
57
54
|
}
|
|
58
55
|
|
|
56
|
+
// Untyped handler param neutralizes to `any`, so reading e.target.value typechecks
|
|
57
|
+
// ×6 (the global-filter idiom). Never inline `$data.x = $event.target.value`.
|
|
59
58
|
onInput = (e: any) => {
|
|
60
59
|
this._draft.value = e && e.target ? e.target.value : '';
|
|
61
60
|
};
|
|
62
61
|
|
|
62
|
+
// setFilter is a Function prop (default null) — guard before calling.
|
|
63
63
|
applyFilter = () => {
|
|
64
64
|
this.setFilter && this.setFilter(this.columnId, this._draft.value);
|
|
65
65
|
};
|
package/src/GroupBar.ts
CHANGED
|
@@ -123,34 +123,49 @@ export default class GroupBar extends SignalWatcher(LitElement) {
|
|
|
123
123
|
`;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
// Untyped handler params neutralize to `any` so the native drag-event shapes
|
|
127
|
+
// (dataTransfer / preventDefault) typecheck across all six strict leaves — the
|
|
128
|
+
// global-filter idiom (see FilterText.rozie). NEVER annotate these params.
|
|
129
|
+
// A palette CHIP started dragging → this is an ADD-a-new-column drag.
|
|
126
130
|
onChipDragStart = (e: any, id: any) => {
|
|
127
131
|
this._draggingId.value = id;
|
|
128
132
|
this._dragKind.value = 'chip';
|
|
129
133
|
if (e && e.dataTransfer) e.dataTransfer.setData('text/plain', id);
|
|
130
134
|
};
|
|
131
135
|
|
|
136
|
+
// An active TOKEN started dragging → this is a REORDER drag.
|
|
132
137
|
onTokenDragStart = (e: any, gk: any) => {
|
|
133
138
|
this._draggingId.value = gk;
|
|
134
139
|
this._dragKind.value = 'token';
|
|
135
140
|
if (e && e.dataTransfer) e.dataTransfer.setData('text/plain', gk);
|
|
136
141
|
};
|
|
137
142
|
|
|
143
|
+
// MUST preventDefault — native HTML5 DnD never fires @drop on a zone that does not
|
|
144
|
+
// cancel the dragover default. Also raises the drop-target highlight.
|
|
138
145
|
onDragOver = (e: any) => {
|
|
139
146
|
if (e) e.preventDefault();
|
|
140
147
|
this._isOver.value = true;
|
|
141
148
|
};
|
|
142
149
|
|
|
150
|
+
// While reordering, record the token under the pointer as the insertion anchor
|
|
151
|
+
// (we drop BEFORE it). preventDefault so the zone still accepts the drop. Ignored
|
|
152
|
+
// for chip drags — those just append at the end.
|
|
143
153
|
onTokenDragOver = (e: any, gk: any) => {
|
|
144
154
|
if (e) e.preventDefault();
|
|
145
155
|
if (this._dragKind.value === 'token') this._dropKey.value = gk;
|
|
146
156
|
};
|
|
147
157
|
|
|
158
|
+
// Clear the highlight only on a REAL leave: dragleave ALSO fires when the pointer
|
|
159
|
+
// crosses onto a child token, so ignore leaves whose relatedTarget is still inside
|
|
160
|
+
// the zone (prevents flicker as you hover over existing grouping tokens).
|
|
148
161
|
onDragLeave = (e: any) => {
|
|
149
162
|
if (e && e.currentTarget && e.relatedTarget && e.currentTarget.contains(e.relatedTarget)) return;
|
|
150
163
|
this._isOver.value = false;
|
|
151
164
|
this._dropKey.value = '';
|
|
152
165
|
};
|
|
153
166
|
|
|
167
|
+
// Single reset for all ephemeral drag bookkeeping — called on drop AND on dragend
|
|
168
|
+
// (so an aborted drag, dropped outside the zone, still clears the marker/highlight).
|
|
154
169
|
resetDrag = () => {
|
|
155
170
|
this._draggingId.value = '';
|
|
156
171
|
this._dragKind.value = '';
|
|
@@ -199,6 +214,9 @@ export default class GroupBar extends SignalWatcher(LitElement) {
|
|
|
199
214
|
this.clearGrouping && this.clearGrouping();
|
|
200
215
|
};
|
|
201
216
|
|
|
217
|
+
// Resolve a grouping key to its column's friendly label (falls back to the raw
|
|
218
|
+
// key). Used for both the token text and the remove button's aria-label so the
|
|
219
|
+
// bar reads in human terms, not internal column ids. Untyped like the handlers.
|
|
202
220
|
labelFor = (key: any) => {
|
|
203
221
|
const col = this.groupableColumns.find((c: any) => c.id === key);
|
|
204
222
|
return col && col.label || key;
|
package/src/themes/base.css
CHANGED
|
@@ -24,6 +24,13 @@
|
|
|
24
24
|
*/
|
|
25
25
|
.rozie-data-table-wrap,
|
|
26
26
|
.rozie-data-table {
|
|
27
|
+
/* NOTE (see file-head comment): most of the tokens below are declared but
|
|
28
|
+
never read via a CSS var() inside THIS component's own scoped <style> —
|
|
29
|
+
that is by design. This is the public surface; the "Wire the PUBLIC
|
|
30
|
+
tokens..." block further down assigns each one onto the short internal
|
|
31
|
+
--rdt-* custom property the component actually reads. A future audit
|
|
32
|
+
must not delete these as dead — they are the intended public API. */
|
|
33
|
+
|
|
27
34
|
/* ── palette (the few values most consumers will set) ───────────────────── */
|
|
28
35
|
--rozie-data-table-fg: inherit;
|
|
29
36
|
--rozie-data-table-accent: #0066cc;
|
|
@@ -62,6 +69,14 @@
|
|
|
62
69
|
/* ── disabled pagination controls ──────────────────────────────────────── */
|
|
63
70
|
--rozie-data-table-disabled-opacity: 0.4;
|
|
64
71
|
|
|
72
|
+
/* ── virtual scroll (row windowing, req-3/D-06) ─────────────────────────── */
|
|
73
|
+
/* Read with NO fallback at its one use site (`max-height: var(--rozie-data-table-max-height);`
|
|
74
|
+
on `.rdt-scroll`) — when unset the property is invalid at computed-value
|
|
75
|
+
time and the rule behaves as if `max-height` were never declared there,
|
|
76
|
+
i.e. `none` (unbounded). Declaring `none` here is the render-neutral
|
|
77
|
+
equivalent of that unset behavior, made explicit and overridable. */
|
|
78
|
+
--rozie-data-table-max-height: none;
|
|
79
|
+
|
|
65
80
|
/* ─────────────────────────────────────────────────────────────────────────
|
|
66
81
|
* Wire the PUBLIC tokens onto the INTERNAL `--rdt-*` the component reads. A
|
|
67
82
|
* bridge only needs to remap the public tokens above; these passthroughs do
|