@densedash/core 0.1.1 → 0.2.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/README.md +59 -0
- package/dist/bare.d.ts +3 -3
- package/dist/bare.js +2 -2
- package/dist/collections/types.d.ts +0 -46
- package/dist/commands/index.d.ts +3 -3
- package/dist/commands/index.js +152 -39
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/keys.js +4 -3
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/scopes.js +30 -3
- package/dist/commands/scopes.js.map +1 -1
- package/dist/commands/trading-preset.d.ts +5 -1
- package/dist/commands/trading-preset.js +22 -43
- package/dist/commands/trading-preset.js.map +1 -1
- package/dist/commands/types.d.ts +32 -5
- package/dist/defaults/keyboard.js +55 -10
- package/dist/defaults/keyboard.js.map +1 -1
- package/dist/index.d.ts +7 -10
- package/dist/index.js +3 -7
- package/dist/index.js.map +1 -1
- package/dist/kernel.d.ts +4 -4
- package/dist/kernel.js.map +1 -1
- package/dist/navigation/commands.js +200 -0
- package/dist/navigation/commands.js.map +1 -0
- package/dist/navigation/index.d.ts +31 -0
- package/dist/navigation/index.js +148 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/{collections → navigation}/move.js +1 -1
- package/dist/navigation/move.js.map +1 -0
- package/dist/{tree → navigation}/props.js +25 -9
- package/dist/navigation/props.js.map +1 -0
- package/dist/{collections → navigation}/reconcile.js +1 -1
- package/dist/navigation/reconcile.js.map +1 -0
- package/dist/navigation/selection.js +21 -0
- package/dist/navigation/selection.js.map +1 -0
- package/dist/navigation/state.d.ts +3 -0
- package/dist/navigation/state.js +265 -0
- package/dist/navigation/state.js.map +1 -0
- package/dist/navigation/types.d.ts +86 -0
- package/dist/ports/keyboard.d.ts +3 -2
- package/dist/ports/keyboard.js +9 -0
- package/dist/ports/keyboard.js.map +1 -0
- package/dist/tree/types.d.ts +7 -36
- package/package.json +3 -2
- package/dist/collections/flatten.d.ts +0 -8
- package/dist/collections/flatten.js +0 -59
- package/dist/collections/flatten.js.map +0 -1
- package/dist/collections/move.d.ts +0 -7
- package/dist/collections/move.js.map +0 -1
- package/dist/collections/reconcile.d.ts +0 -9
- package/dist/collections/reconcile.js.map +0 -1
- package/dist/collections/selection.d.ts +0 -12
- package/dist/collections/selection.js +0 -39
- package/dist/collections/selection.js.map +0 -1
- package/dist/tree/commands.js +0 -119
- package/dist/tree/commands.js.map +0 -1
- package/dist/tree/index.d.ts +0 -6
- package/dist/tree/index.js +0 -71
- package/dist/tree/index.js.map +0 -1
- package/dist/tree/props.js.map +0 -1
- package/dist/tree/state.js +0 -126
- package/dist/tree/state.js.map +0 -1
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
// src/collections/selection.ts
|
|
2
|
-
/** Toggle a visible enabled key, preserving the caller's selected set. */
|
|
3
|
-
function toggleSelection(rows, selected, key) {
|
|
4
|
-
const row = rows.find((candidate) => candidate.key === key);
|
|
5
|
-
if (!row || row.disabled) return selected;
|
|
6
|
-
const next = new Set(selected);
|
|
7
|
-
if (next.has(key)) next.delete(key);
|
|
8
|
-
else next.add(key);
|
|
9
|
-
return next;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Replace selection with an inclusive visible range, excluding disabled rows.
|
|
13
|
-
* A missing anchor selects only the target; a missing target yields an empty set.
|
|
14
|
-
*/
|
|
15
|
-
function selectRange(rows, anchor, to) {
|
|
16
|
-
const targetIndex = rows.findIndex((row) => row.key === to);
|
|
17
|
-
const selected = /* @__PURE__ */ new Set();
|
|
18
|
-
if (targetIndex < 0) return selected;
|
|
19
|
-
const anchorIndex = anchor === null ? -1 : rows.findIndex((row) => row.key === anchor);
|
|
20
|
-
const start = anchorIndex < 0 ? targetIndex : Math.min(anchorIndex, targetIndex);
|
|
21
|
-
const end = Math.max(anchorIndex, targetIndex);
|
|
22
|
-
for (let index = start; index <= end; index++) {
|
|
23
|
-
const row = rows[index];
|
|
24
|
-
if (!row.disabled) selected.add(row.key);
|
|
25
|
-
}
|
|
26
|
-
return selected;
|
|
27
|
-
}
|
|
28
|
-
/** Select every visible enabled row. */
|
|
29
|
-
function selectAll(rows) {
|
|
30
|
-
const selected = /* @__PURE__ */ new Set();
|
|
31
|
-
for (const row of rows) if (!row.disabled) selected.add(row.key);
|
|
32
|
-
return selected;
|
|
33
|
-
}
|
|
34
|
-
function clearSelection() {
|
|
35
|
-
return /* @__PURE__ */ new Set();
|
|
36
|
-
}
|
|
37
|
-
export { clearSelection, selectAll, selectRange, toggleSelection };
|
|
38
|
-
|
|
39
|
-
//# sourceMappingURL=selection.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"selection.js","names":[],"sources":["../../src/collections/selection.ts"],"sourcesContent":["import type { Key, TreeRow } from \"./types.js\";\n\n/** Toggle a visible enabled key, preserving the caller's selected set. */\nexport function toggleSelection<T>(\n rows: readonly TreeRow<T>[],\n selected: ReadonlySet<Key>,\n key: Key,\n): ReadonlySet<Key> {\n const row = rows.find((candidate) => candidate.key === key);\n if (!row || row.disabled) return selected;\n const next = new Set(selected);\n if (next.has(key)) next.delete(key);\n else next.add(key);\n return next;\n}\n\n/**\n * Replace selection with an inclusive visible range, excluding disabled rows.\n * A missing anchor selects only the target; a missing target yields an empty set.\n */\nexport function selectRange<T>(\n rows: readonly TreeRow<T>[],\n anchor: Key | null,\n to: Key,\n): ReadonlySet<Key> {\n const targetIndex = rows.findIndex((row) => row.key === to);\n const selected = new Set<Key>();\n if (targetIndex < 0) return selected;\n const anchorIndex = anchor === null ? -1 : rows.findIndex((row) => row.key === anchor);\n const start = anchorIndex < 0 ? targetIndex : Math.min(anchorIndex, targetIndex);\n const end = Math.max(anchorIndex, targetIndex);\n for (let index = start; index <= end; index++) {\n const row = rows[index]!;\n if (!row.disabled) selected.add(row.key);\n }\n return selected;\n}\n\n/** Select every visible enabled row. */\nexport function selectAll<T>(rows: readonly TreeRow<T>[]): ReadonlySet<Key> {\n const selected = new Set<Key>();\n for (const row of rows) {\n if (!row.disabled) selected.add(row.key);\n }\n return selected;\n}\n\nexport function clearSelection(): ReadonlySet<Key> {\n return new Set<Key>();\n}\n"],"mappings":";;AAGA,SAAgB,gBACd,MACA,UACA,KACkB;CAClB,MAAM,MAAM,KAAK,MAAM,cAAc,UAAU,QAAQ,GAAG;CAC1D,IAAI,CAAC,OAAO,IAAI,UAAU,OAAO;CACjC,MAAM,OAAO,IAAI,IAAI,QAAQ;CAC7B,IAAI,KAAK,IAAI,GAAG,GAAG,KAAK,OAAO,GAAG;MAC7B,KAAK,IAAI,GAAG;CACjB,OAAO;AACT;;;;;AAMA,SAAgB,YACd,MACA,QACA,IACkB;CAClB,MAAM,cAAc,KAAK,WAAW,QAAQ,IAAI,QAAQ,EAAE;CAC1D,MAAM,2BAAW,IAAI,IAAS;CAC9B,IAAI,cAAc,GAAG,OAAO;CAC5B,MAAM,cAAc,WAAW,OAAO,KAAK,KAAK,WAAW,QAAQ,IAAI,QAAQ,MAAM;CACrF,MAAM,QAAQ,cAAc,IAAI,cAAc,KAAK,IAAI,aAAa,WAAW;CAC/E,MAAM,MAAM,KAAK,IAAI,aAAa,WAAW;CAC7C,KAAK,IAAI,QAAQ,OAAO,SAAS,KAAK,SAAS;EAC7C,MAAM,MAAM,KAAK;EACjB,IAAI,CAAC,IAAI,UAAU,SAAS,IAAI,IAAI,GAAG;CACzC;CACA,OAAO;AACT;;AAGA,SAAgB,UAAa,MAA+C;CAC1E,MAAM,2BAAW,IAAI,IAAS;CAC9B,KAAK,MAAM,OAAO,MAChB,IAAI,CAAC,IAAI,UAAU,SAAS,IAAI,IAAI,GAAG;CAEzC,OAAO;AACT;AAEA,SAAgB,iBAAmC;CACjD,uBAAO,IAAI,IAAS;AACtB"}
|
package/dist/tree/commands.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { move } from "../collections/move.js";
|
|
2
|
-
import { selectRange, toggleSelection } from "../collections/selection.js";
|
|
3
|
-
import { changeDetails } from "./state.js";
|
|
4
|
-
// src/tree/commands.ts
|
|
5
|
-
function createTreeCommands(model) {
|
|
6
|
-
function target(action) {
|
|
7
|
-
const state = model.get();
|
|
8
|
-
const key = action.key ?? state.highlighted;
|
|
9
|
-
return state.rows.find((row) => row.key === key && !row.disabled);
|
|
10
|
-
}
|
|
11
|
-
function navigate(movement, action = {}) {
|
|
12
|
-
if (!model.active()) return;
|
|
13
|
-
const state = model.get();
|
|
14
|
-
const highlighted = move(state.rows, action.key ?? state.highlighted, movement, { loop: model.options().loop ?? false });
|
|
15
|
-
if (action.event && "shiftKey" in action.event && action.event.shiftKey && model.options().selectionMode === "multiple" && highlighted !== null) {
|
|
16
|
-
const anchor = state.anchor ?? state.highlighted ?? highlighted;
|
|
17
|
-
model.change({
|
|
18
|
-
highlighted,
|
|
19
|
-
anchor,
|
|
20
|
-
selected: selectRange(state.rows, anchor, highlighted)
|
|
21
|
-
}, action);
|
|
22
|
-
} else model.change({ highlighted }, action);
|
|
23
|
-
}
|
|
24
|
-
function setExpanded(expanded, action = {}) {
|
|
25
|
-
if (!model.active()) return;
|
|
26
|
-
const row = target(action);
|
|
27
|
-
if (!row?.hasChildren) return;
|
|
28
|
-
const next = new Set(model.get().expanded);
|
|
29
|
-
if (expanded) next.add(row.key);
|
|
30
|
-
else next.delete(row.key);
|
|
31
|
-
model.change({ expanded: next }, action);
|
|
32
|
-
}
|
|
33
|
-
const commands = {
|
|
34
|
-
next: (action) => navigate({ type: "next" }, action),
|
|
35
|
-
prev: (action) => navigate({ type: "prev" }, action),
|
|
36
|
-
first: (action) => navigate({ type: "first" }, action),
|
|
37
|
-
last: (action) => navigate({ type: "last" }, action),
|
|
38
|
-
page: (direction, action) => navigate({
|
|
39
|
-
type: "page",
|
|
40
|
-
direction,
|
|
41
|
-
size: model.options().pageSize ?? 10
|
|
42
|
-
}, action),
|
|
43
|
-
parent: (action) => navigate({ type: "parent" }, action),
|
|
44
|
-
expand(action = {}) {
|
|
45
|
-
if (!model.active()) return;
|
|
46
|
-
if (target(action)?.expanded) navigate({ type: "firstChild" }, action);
|
|
47
|
-
else setExpanded(true, action);
|
|
48
|
-
},
|
|
49
|
-
collapse(action = {}) {
|
|
50
|
-
if (!model.active()) return;
|
|
51
|
-
if (target(action)?.expanded) setExpanded(false, action);
|
|
52
|
-
else navigate({ type: "parent" }, action);
|
|
53
|
-
},
|
|
54
|
-
toggle(action = {}) {
|
|
55
|
-
setExpanded(!target(action)?.expanded, action);
|
|
56
|
-
},
|
|
57
|
-
select(action = {}) {
|
|
58
|
-
if (!model.active()) return;
|
|
59
|
-
const row = target(action);
|
|
60
|
-
if (!row) return;
|
|
61
|
-
const selected = model.options().selectionMode === "multiple" ? toggleSelection(model.get().rows, model.get().selected, row.key) : /* @__PURE__ */ new Set([row.key]);
|
|
62
|
-
model.change({
|
|
63
|
-
selected,
|
|
64
|
-
anchor: row.key
|
|
65
|
-
}, action);
|
|
66
|
-
},
|
|
67
|
-
extendSelection(action = {}) {
|
|
68
|
-
if (!model.active()) return;
|
|
69
|
-
const row = target(action);
|
|
70
|
-
if (!row) return;
|
|
71
|
-
if (model.options().selectionMode !== "multiple") {
|
|
72
|
-
commands.select(action);
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
const state = model.get();
|
|
76
|
-
const anchor = state.anchor ?? state.highlighted ?? row.key;
|
|
77
|
-
model.change({
|
|
78
|
-
anchor,
|
|
79
|
-
selected: selectRange(state.rows, anchor, row.key)
|
|
80
|
-
}, action);
|
|
81
|
-
},
|
|
82
|
-
open(action = {}) {
|
|
83
|
-
if (!model.active()) return;
|
|
84
|
-
const row = target(action);
|
|
85
|
-
if (row) model.options().onOpen?.(row.item, changeDetails(action));
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
function define(id, label, run) {
|
|
89
|
-
return {
|
|
90
|
-
id,
|
|
91
|
-
label,
|
|
92
|
-
run: ({ event }) => run(event ? {
|
|
93
|
-
reason: "keyboard",
|
|
94
|
-
event
|
|
95
|
-
} : { reason: "programmatic" })
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
commands,
|
|
100
|
-
definitions: [
|
|
101
|
-
define("tree.next", "Next row", commands.next),
|
|
102
|
-
define("tree.prev", "Previous row", commands.prev),
|
|
103
|
-
define("tree.first", "First row", commands.first),
|
|
104
|
-
define("tree.last", "Last row", commands.last),
|
|
105
|
-
define("tree.page-up", "Previous page", (action) => commands.page(-1, action)),
|
|
106
|
-
define("tree.page-down", "Next page", (action) => commands.page(1, action)),
|
|
107
|
-
define("tree.parent", "Parent row", commands.parent),
|
|
108
|
-
define("tree.expand", "Expand row", commands.expand),
|
|
109
|
-
define("tree.collapse", "Collapse row", commands.collapse),
|
|
110
|
-
define("tree.toggle", "Toggle expansion", commands.toggle),
|
|
111
|
-
define("tree.select", "Select row", commands.select),
|
|
112
|
-
define("tree.extend-selection", "Extend selection", commands.extendSelection),
|
|
113
|
-
define("tree.open", "Open row", commands.open)
|
|
114
|
-
]
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
export { createTreeCommands };
|
|
118
|
-
|
|
119
|
-
//# sourceMappingURL=commands.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"commands.js","names":[],"sources":["../../src/tree/commands.ts"],"sourcesContent":["import { move } from \"../collections/move.js\";\nimport { selectRange, toggleSelection } from \"../collections/selection.js\";\nimport type { Move } from \"../collections/types.js\";\nimport type { Command } from \"../commands/types.js\";\nimport { changeDetails } from \"./state.js\";\nimport type { TreeModel } from \"./state.js\";\nimport type { TreeAction, TreeCommands } from \"./types.js\";\n\nexport function createTreeCommands<T>(model: TreeModel<T>) {\n function target(action: TreeAction) {\n const state = model.get();\n const key = action.key ?? state.highlighted;\n return state.rows.find((row) => row.key === key && !row.disabled);\n }\n\n function navigate(movement: Move, action: TreeAction = {}): void {\n if (!model.active()) return;\n const state = model.get();\n const highlighted = move(state.rows, action.key ?? state.highlighted, movement, {\n loop: model.options().loop ?? false,\n });\n if (\n action.event &&\n \"shiftKey\" in action.event &&\n action.event.shiftKey &&\n model.options().selectionMode === \"multiple\" &&\n highlighted !== null\n ) {\n const anchor = state.anchor ?? state.highlighted ?? highlighted;\n model.change(\n { highlighted, anchor, selected: selectRange(state.rows, anchor, highlighted) },\n action,\n );\n } else model.change({ highlighted }, action);\n }\n\n function setExpanded(expanded: boolean, action: TreeAction = {}): void {\n if (!model.active()) return;\n const row = target(action);\n if (!row?.hasChildren) return;\n const next = new Set(model.get().expanded);\n if (expanded) next.add(row.key);\n else next.delete(row.key);\n model.change({ expanded: next }, action);\n }\n\n const commands: TreeCommands = {\n next: (action) => navigate({ type: \"next\" }, action),\n prev: (action) => navigate({ type: \"prev\" }, action),\n first: (action) => navigate({ type: \"first\" }, action),\n last: (action) => navigate({ type: \"last\" }, action),\n page: (direction, action) =>\n navigate({ type: \"page\", direction, size: model.options().pageSize ?? 10 }, action),\n parent: (action) => navigate({ type: \"parent\" }, action),\n expand(action = {}) {\n if (!model.active()) return;\n if (target(action)?.expanded) navigate({ type: \"firstChild\" }, action);\n else setExpanded(true, action);\n },\n collapse(action = {}) {\n if (!model.active()) return;\n if (target(action)?.expanded) setExpanded(false, action);\n else navigate({ type: \"parent\" }, action);\n },\n toggle(action = {}) {\n setExpanded(!target(action)?.expanded, action);\n },\n select(action = {}) {\n if (!model.active()) return;\n const row = target(action);\n if (!row) return;\n const selected =\n model.options().selectionMode === \"multiple\"\n ? toggleSelection(model.get().rows, model.get().selected, row.key)\n : new Set([row.key]);\n model.change({ selected, anchor: row.key }, action);\n },\n extendSelection(action = {}) {\n if (!model.active()) return;\n const row = target(action);\n if (!row) return;\n if (model.options().selectionMode !== \"multiple\") {\n commands.select(action);\n return;\n }\n const state = model.get();\n const anchor = state.anchor ?? state.highlighted ?? row.key;\n model.change({ anchor, selected: selectRange(state.rows, anchor, row.key) }, action);\n },\n open(action = {}) {\n if (!model.active()) return;\n const row = target(action);\n if (row) model.options().onOpen?.(row.item, changeDetails(action));\n },\n };\n\n function define(id: Command[\"id\"], label: string, run: (action: TreeAction) => void): Command {\n return {\n id,\n label,\n run: ({ event }) => run(event ? { reason: \"keyboard\", event } : { reason: \"programmatic\" }),\n };\n }\n\n const definitions = [\n define(\"tree.next\", \"Next row\", commands.next),\n define(\"tree.prev\", \"Previous row\", commands.prev),\n define(\"tree.first\", \"First row\", commands.first),\n define(\"tree.last\", \"Last row\", commands.last),\n define(\"tree.page-up\", \"Previous page\", (action) => commands.page(-1, action)),\n define(\"tree.page-down\", \"Next page\", (action) => commands.page(1, action)),\n define(\"tree.parent\", \"Parent row\", commands.parent),\n define(\"tree.expand\", \"Expand row\", commands.expand),\n define(\"tree.collapse\", \"Collapse row\", commands.collapse),\n define(\"tree.toggle\", \"Toggle expansion\", commands.toggle),\n define(\"tree.select\", \"Select row\", commands.select),\n define(\"tree.extend-selection\", \"Extend selection\", commands.extendSelection),\n define(\"tree.open\", \"Open row\", commands.open),\n ];\n return { commands, definitions };\n}\n"],"mappings":";;;;AAQA,SAAgB,mBAAsB,OAAqB;CACzD,SAAS,OAAO,QAAoB;EAClC,MAAM,QAAQ,MAAM,IAAI;EACxB,MAAM,MAAM,OAAO,OAAO,MAAM;EAChC,OAAO,MAAM,KAAK,MAAM,QAAQ,IAAI,QAAQ,OAAO,CAAC,IAAI,QAAQ;CAClE;CAEA,SAAS,SAAS,UAAgB,SAAqB,CAAC,GAAS;EAC/D,IAAI,CAAC,MAAM,OAAO,GAAG;EACrB,MAAM,QAAQ,MAAM,IAAI;EACxB,MAAM,cAAc,KAAK,MAAM,MAAM,OAAO,OAAO,MAAM,aAAa,UAAU,EAC9E,MAAM,MAAM,QAAQ,CAAC,CAAC,QAAQ,MAChC,CAAC;EACD,IACE,OAAO,SACP,cAAc,OAAO,SACrB,OAAO,MAAM,YACb,MAAM,QAAQ,CAAC,CAAC,kBAAkB,cAClC,gBAAgB,MAChB;GACA,MAAM,SAAS,MAAM,UAAU,MAAM,eAAe;GACpD,MAAM,OACJ;IAAE;IAAa;IAAQ,UAAU,YAAY,MAAM,MAAM,QAAQ,WAAW;GAAE,GAC9E,MACF;EACF,OAAO,MAAM,OAAO,EAAE,YAAY,GAAG,MAAM;CAC7C;CAEA,SAAS,YAAY,UAAmB,SAAqB,CAAC,GAAS;EACrE,IAAI,CAAC,MAAM,OAAO,GAAG;EACrB,MAAM,MAAM,OAAO,MAAM;EACzB,IAAI,CAAC,KAAK,aAAa;EACvB,MAAM,OAAO,IAAI,IAAI,MAAM,IAAI,CAAC,CAAC,QAAQ;EACzC,IAAI,UAAU,KAAK,IAAI,IAAI,GAAG;OACzB,KAAK,OAAO,IAAI,GAAG;EACxB,MAAM,OAAO,EAAE,UAAU,KAAK,GAAG,MAAM;CACzC;CAEA,MAAM,WAAyB;EAC7B,OAAO,WAAW,SAAS,EAAE,MAAM,OAAO,GAAG,MAAM;EACnD,OAAO,WAAW,SAAS,EAAE,MAAM,OAAO,GAAG,MAAM;EACnD,QAAQ,WAAW,SAAS,EAAE,MAAM,QAAQ,GAAG,MAAM;EACrD,OAAO,WAAW,SAAS,EAAE,MAAM,OAAO,GAAG,MAAM;EACnD,OAAO,WAAW,WAChB,SAAS;GAAE,MAAM;GAAQ;GAAW,MAAM,MAAM,QAAQ,CAAC,CAAC,YAAY;EAAG,GAAG,MAAM;EACpF,SAAS,WAAW,SAAS,EAAE,MAAM,SAAS,GAAG,MAAM;EACvD,OAAO,SAAS,CAAC,GAAG;GAClB,IAAI,CAAC,MAAM,OAAO,GAAG;GACrB,IAAI,OAAO,MAAM,CAAC,EAAE,UAAU,SAAS,EAAE,MAAM,aAAa,GAAG,MAAM;QAChE,YAAY,MAAM,MAAM;EAC/B;EACA,SAAS,SAAS,CAAC,GAAG;GACpB,IAAI,CAAC,MAAM,OAAO,GAAG;GACrB,IAAI,OAAO,MAAM,CAAC,EAAE,UAAU,YAAY,OAAO,MAAM;QAClD,SAAS,EAAE,MAAM,SAAS,GAAG,MAAM;EAC1C;EACA,OAAO,SAAS,CAAC,GAAG;GAClB,YAAY,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,MAAM;EAC/C;EACA,OAAO,SAAS,CAAC,GAAG;GAClB,IAAI,CAAC,MAAM,OAAO,GAAG;GACrB,MAAM,MAAM,OAAO,MAAM;GACzB,IAAI,CAAC,KAAK;GACV,MAAM,WACJ,MAAM,QAAQ,CAAC,CAAC,kBAAkB,aAC9B,gBAAgB,MAAM,IAAI,CAAC,CAAC,MAAM,MAAM,IAAI,CAAC,CAAC,UAAU,IAAI,GAAG,oBAC/D,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC;GACvB,MAAM,OAAO;IAAE;IAAU,QAAQ,IAAI;GAAI,GAAG,MAAM;EACpD;EACA,gBAAgB,SAAS,CAAC,GAAG;GAC3B,IAAI,CAAC,MAAM,OAAO,GAAG;GACrB,MAAM,MAAM,OAAO,MAAM;GACzB,IAAI,CAAC,KAAK;GACV,IAAI,MAAM,QAAQ,CAAC,CAAC,kBAAkB,YAAY;IAChD,SAAS,OAAO,MAAM;IACtB;GACF;GACA,MAAM,QAAQ,MAAM,IAAI;GACxB,MAAM,SAAS,MAAM,UAAU,MAAM,eAAe,IAAI;GACxD,MAAM,OAAO;IAAE;IAAQ,UAAU,YAAY,MAAM,MAAM,QAAQ,IAAI,GAAG;GAAE,GAAG,MAAM;EACrF;EACA,KAAK,SAAS,CAAC,GAAG;GAChB,IAAI,CAAC,MAAM,OAAO,GAAG;GACrB,MAAM,MAAM,OAAO,MAAM;GACzB,IAAI,KAAK,MAAM,QAAQ,CAAC,CAAC,SAAS,IAAI,MAAM,cAAc,MAAM,CAAC;EACnE;CACF;CAEA,SAAS,OAAO,IAAmB,OAAe,KAA4C;EAC5F,OAAO;GACL;GACA;GACA,MAAM,EAAE,YAAY,IAAI,QAAQ;IAAE,QAAQ;IAAY;GAAM,IAAI,EAAE,QAAQ,eAAe,CAAC;EAC5F;CACF;CAiBA,OAAO;EAAE;EAAU,aAAA;GAdjB,OAAO,aAAa,YAAY,SAAS,IAAI;GAC7C,OAAO,aAAa,gBAAgB,SAAS,IAAI;GACjD,OAAO,cAAc,aAAa,SAAS,KAAK;GAChD,OAAO,aAAa,YAAY,SAAS,IAAI;GAC7C,OAAO,gBAAgB,kBAAkB,WAAW,SAAS,KAAK,IAAI,MAAM,CAAC;GAC7E,OAAO,kBAAkB,cAAc,WAAW,SAAS,KAAK,GAAG,MAAM,CAAC;GAC1E,OAAO,eAAe,cAAc,SAAS,MAAM;GACnD,OAAO,eAAe,cAAc,SAAS,MAAM;GACnD,OAAO,iBAAiB,gBAAgB,SAAS,QAAQ;GACzD,OAAO,eAAe,oBAAoB,SAAS,MAAM;GACzD,OAAO,eAAe,cAAc,SAAS,MAAM;GACnD,OAAO,yBAAyB,oBAAoB,SAAS,eAAe;GAC5E,OAAO,aAAa,YAAY,SAAS,IAAI;EAElB;CAAE;AACjC"}
|
package/dist/tree/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { Kernel } from "../kernel.js";
|
|
2
|
-
import { Tree, TreeAction, TreeChangeReason, TreeCommands, TreeFocusStrategy, TreeMode, TreeOptions, TreePartProps, TreeRootProps, TreeRowProps, TreeSnapshot, TreeToggleProps } from "./types.js";
|
|
3
|
-
/** Framework-neutral tree, listbox or treegrid. Dispose the tree before its kernel. */
|
|
4
|
-
export declare function createTree<T>(kernel: Kernel, options: TreeOptions<T>): Tree<T>;
|
|
5
|
-
export type { Tree, TreeAction, TreeChangeReason, TreeCommands, TreeFocusStrategy, TreeMode, TreeOptions, TreePartProps, TreeRootProps, TreeRowProps, TreeSnapshot, TreeToggleProps };
|
|
6
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/tree/index.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { createTreeCommands } from "./commands.js";
|
|
2
|
-
import { createTreeProps } from "./props.js";
|
|
3
|
-
import { createTreeState } from "./state.js";
|
|
4
|
-
// src/tree/index.ts
|
|
5
|
-
let nextTree = 0;
|
|
6
|
-
/** Framework-neutral tree, listbox or treegrid. Dispose the tree before its kernel. */
|
|
7
|
-
function createTree(kernel, options) {
|
|
8
|
-
const instance = nextTree++;
|
|
9
|
-
const id = options.id ?? `dd-tree-${instance}`;
|
|
10
|
-
const scope = `densedash:tree:${instance}`;
|
|
11
|
-
const model = createTreeState(kernel.ports.store, options);
|
|
12
|
-
const { commands, definitions } = createTreeCommands(model);
|
|
13
|
-
let root;
|
|
14
|
-
let unregister;
|
|
15
|
-
function register() {
|
|
16
|
-
unregister?.();
|
|
17
|
-
unregister = void 0;
|
|
18
|
-
unregister = kernel.commands.register(scope, definitions, {
|
|
19
|
-
...model.options().scope,
|
|
20
|
-
...root === void 0 ? {} : { target: root }
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
const props = createTreeProps({
|
|
24
|
-
model,
|
|
25
|
-
commands,
|
|
26
|
-
clock: kernel.ports.clock,
|
|
27
|
-
id,
|
|
28
|
-
mount(element) {
|
|
29
|
-
if (root === element) return;
|
|
30
|
-
root = element;
|
|
31
|
-
register();
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
try {
|
|
35
|
-
register();
|
|
36
|
-
} catch (cause) {
|
|
37
|
-
model.dispose();
|
|
38
|
-
props.dispose();
|
|
39
|
-
throw cause;
|
|
40
|
-
}
|
|
41
|
-
return {
|
|
42
|
-
get rows() {
|
|
43
|
-
return model.get().rows;
|
|
44
|
-
},
|
|
45
|
-
state: {
|
|
46
|
-
get: model.get,
|
|
47
|
-
subscribe: model.subscribe
|
|
48
|
-
},
|
|
49
|
-
commands,
|
|
50
|
-
scope,
|
|
51
|
-
getRootProps: props.getRootProps,
|
|
52
|
-
getRowProps: props.getRowProps,
|
|
53
|
-
getToggleProps: props.getToggleProps,
|
|
54
|
-
update(next) {
|
|
55
|
-
if (!model.active()) return;
|
|
56
|
-
model.update(next);
|
|
57
|
-
if (model.active() && next.scope !== void 0) register();
|
|
58
|
-
},
|
|
59
|
-
dispose() {
|
|
60
|
-
if (!model.active()) return;
|
|
61
|
-
model.dispose();
|
|
62
|
-
props.dispose();
|
|
63
|
-
root = void 0;
|
|
64
|
-
unregister?.();
|
|
65
|
-
unregister = void 0;
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
export { createTree };
|
|
70
|
-
|
|
71
|
-
//# sourceMappingURL=index.js.map
|
package/dist/tree/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/tree/index.ts"],"sourcesContent":["import type { Kernel } from \"../kernel.js\";\nimport { createTreeCommands } from \"./commands.js\";\nimport { createTreeProps } from \"./props.js\";\nimport { createTreeState } from \"./state.js\";\nimport type { Tree, TreeOptions } from \"./types.js\";\n\nexport type {\n Tree,\n TreeAction,\n TreeChangeReason,\n TreeCommands,\n TreeFocusStrategy,\n TreeMode,\n TreeOptions,\n TreePartProps,\n TreeRootProps,\n TreeRowProps,\n TreeSnapshot,\n TreeToggleProps,\n} from \"./types.js\";\n\nlet nextTree = 0;\n\n/** Framework-neutral tree, listbox or treegrid. Dispose the tree before its kernel. */\nexport function createTree<T>(kernel: Kernel, options: TreeOptions<T>): Tree<T> {\n const instance = nextTree++;\n const id = options.id ?? `dd-tree-${instance}`;\n const scope = `densedash:tree:${instance}`;\n const model = createTreeState(kernel.ports.store, options);\n const { commands, definitions } = createTreeCommands(model);\n let root: HTMLElement | undefined;\n let unregister: (() => void) | undefined;\n\n function register(): void {\n unregister?.();\n unregister = undefined;\n unregister = kernel.commands.register(scope, definitions, {\n ...model.options().scope,\n ...(root === undefined ? {} : { target: root }),\n });\n }\n\n const props = createTreeProps({\n model,\n commands,\n clock: kernel.ports.clock,\n id,\n mount(element) {\n if (root === element) return;\n root = element;\n register();\n },\n });\n try {\n register();\n } catch (cause) {\n model.dispose();\n props.dispose();\n throw cause;\n }\n\n return {\n get rows() {\n return model.get().rows;\n },\n state: { get: model.get, subscribe: model.subscribe },\n commands,\n scope,\n getRootProps: props.getRootProps,\n getRowProps: props.getRowProps,\n getToggleProps: props.getToggleProps,\n update(next) {\n if (!model.active()) return;\n model.update(next);\n if (model.active() && next.scope !== undefined) register();\n },\n dispose() {\n if (!model.active()) return;\n model.dispose();\n props.dispose();\n root = undefined;\n unregister?.();\n unregister = undefined;\n },\n };\n}\n"],"mappings":";;;;AAqBA,IAAI,WAAW;;AAGf,SAAgB,WAAc,QAAgB,SAAkC;CAC9E,MAAM,WAAW;CACjB,MAAM,KAAK,QAAQ,MAAM,WAAW;CACpC,MAAM,QAAQ,kBAAkB;CAChC,MAAM,QAAQ,gBAAgB,OAAO,MAAM,OAAO,OAAO;CACzD,MAAM,EAAE,UAAU,gBAAgB,mBAAmB,KAAK;CAC1D,IAAI;CACJ,IAAI;CAEJ,SAAS,WAAiB;EACxB,aAAa;EACb,aAAa,KAAA;EACb,aAAa,OAAO,SAAS,SAAS,OAAO,aAAa;GACxD,GAAG,MAAM,QAAQ,CAAC,CAAC;GACnB,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,KAAK;EAC/C,CAAC;CACH;CAEA,MAAM,QAAQ,gBAAgB;EAC5B;EACA;EACA,OAAO,OAAO,MAAM;EACpB;EACA,MAAM,SAAS;GACb,IAAI,SAAS,SAAS;GACtB,OAAO;GACP,SAAS;EACX;CACF,CAAC;CACD,IAAI;EACF,SAAS;CACX,SAAS,OAAO;EACd,MAAM,QAAQ;EACd,MAAM,QAAQ;EACd,MAAM;CACR;CAEA,OAAO;EACL,IAAI,OAAO;GACT,OAAO,MAAM,IAAI,CAAC,CAAC;EACrB;EACA,OAAO;GAAE,KAAK,MAAM;GAAK,WAAW,MAAM;EAAU;EACpD;EACA;EACA,cAAc,MAAM;EACpB,aAAa,MAAM;EACnB,gBAAgB,MAAM;EACtB,OAAO,MAAM;GACX,IAAI,CAAC,MAAM,OAAO,GAAG;GACrB,MAAM,OAAO,IAAI;GACjB,IAAI,MAAM,OAAO,KAAK,KAAK,UAAU,KAAA,GAAW,SAAS;EAC3D;EACA,UAAU;GACR,IAAI,CAAC,MAAM,OAAO,GAAG;GACrB,MAAM,QAAQ;GACd,MAAM,QAAQ;GACd,OAAO,KAAA;GACP,aAAa;GACb,aAAa,KAAA;EACf;CACF;AACF"}
|
package/dist/tree/props.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"props.js","names":[],"sources":["../../src/tree/props.ts"],"sourcesContent":["import { move } from \"../collections/move.js\";\nimport type { Key, TreeRow } from \"../collections/types.js\";\nimport type { ClockPort } from \"../ports/clock.js\";\nimport type { TreeModel } from \"./state.js\";\nimport type {\n TreeCommands,\n TreePartProps,\n TreeRootProps,\n TreeRowProps,\n TreeToggleProps,\n} from \"./types.js\";\n\nexport function createTreeProps<T>({\n model,\n commands,\n clock,\n id,\n mount,\n}: {\n model: TreeModel<T>;\n commands: TreeCommands;\n clock: ClockPort;\n id: string;\n mount(root: HTMLElement): void;\n}) {\n let root: HTMLElement | undefined;\n let text = \"\";\n let lastTyped = -Infinity;\n const rowId = (key: Key) =>\n `${id}-row-${Array.from(key, (character) => character.codePointAt(0)!.toString(16)).join(\"-\")}`;\n const roving = () => model.options().focusStrategy === \"roving\";\n const mode = () => model.options().mode ?? \"tree\";\n const grid = () => mode() === \"grid\" || mode() === \"treegrid\";\n const slot = (part: \"root\" | \"row\" | \"toggle\"): TreePartProps[\"data-slot\"] =>\n grid() ? `table-${part}` : `tree-${part}`;\n const rootSelector = () => `[data-slot=\"${slot(\"root\")}\"]`;\n // Prop getters run once per visible row, so look rows up by key in O(1) per snapshot.\n const indexes = new WeakMap<readonly TreeRow<T>[], Map<Key, TreeRow<T>>>();\n const current = (key: Key) => {\n const rows = model.get().rows;\n let index = indexes.get(rows);\n if (index === undefined) {\n index = new Map(rows.map((row) => [row.key, row]));\n indexes.set(rows, index);\n }\n return index.get(key);\n };\n const enabledHighlight = () => {\n const key = model.get().highlighted;\n const row = key === null ? undefined : current(key);\n return row?.disabled === false ? row : undefined;\n };\n const interactive = (key: Key) => model.active() && current(key)?.disabled === false;\n\n function focusHighlighted(): void {\n if (!model.active() || !roving() || !root?.contains(root.ownerDocument.activeElement)) return;\n const key = model.get().highlighted;\n const element = key === null ? null : root.ownerDocument.getElementById(rowId(key));\n if (element && root.contains(element) && element !== root.ownerDocument.activeElement)\n element.focus();\n }\n model.subscribe(focusHighlighted);\n\n function focusFromPointer(event: MouseEvent): void {\n const target = event.currentTarget;\n if (target && \"closest\" in target && typeof target.closest === \"function\") {\n const element = target.closest(rootSelector());\n if (element && \"focus\" in element) {\n root = element as HTMLElement;\n mount(root);\n }\n }\n if (!root) return;\n if (!roving() || !root.contains(root.ownerDocument.activeElement)) root.focus();\n focusHighlighted();\n }\n\n function part(slot: TreePartProps[\"data-slot\"], row?: TreeRow<T>): TreePartProps {\n const state = model.get();\n const depth = row?.depth ?? 0;\n return {\n \"data-slot\": slot,\n \"data-highlighted\": (row ? state.highlighted === row.key : state.highlighted !== null)\n ? \"\"\n : undefined,\n \"data-selected\": (row ? state.selected.has(row.key) : state.selected.size > 0)\n ? \"\"\n : undefined,\n \"data-expanded\": (row ? row.expanded : state.expanded.size > 0) ? \"\" : undefined,\n \"data-depth\": depth,\n \"data-disabled\": row?.disabled ? \"\" : undefined,\n \"data-leaf\": row && !row.hasChildren ? \"\" : undefined,\n style: { \"--dd-depth\": depth },\n };\n }\n\n function onKeyDown(event: KeyboardEvent): void {\n if (\n !model.active() ||\n event.defaultPrevented ||\n event.isComposing ||\n event.ctrlKey ||\n event.metaKey ||\n event.altKey ||\n event.key.length !== 1 ||\n event.key.trim() === \"\"\n )\n return;\n const target = event.target;\n if (target && \"closest\" in target && typeof target.closest === \"function\") {\n if (\n target.closest('input, textarea, select, [contenteditable]:not([contenteditable=\"false\"])')\n )\n return;\n if (target.closest(rootSelector()) !== event.currentTarget) return;\n }\n const at = clock.now();\n const character = event.key;\n // The keyboard port handles bubbling events first. A consumed preset key must not also type ahead.\n queueMicrotask(() => {\n if (!model.active() || event.defaultPrevented) return;\n text = at - lastTyped <= (model.options().typeaheadMs ?? 500) ? text + character : character;\n lastTyped = at;\n const state = model.get();\n const highlighted = move(\n state.rows,\n state.highlighted,\n { type: \"typeahead\", text },\n { loop: true },\n );\n model.change({ highlighted }, { reason: \"typeahead\", event });\n });\n }\n\n return {\n getRootProps(): TreeRootProps {\n const state = model.get();\n const highlighted = enabledHighlight();\n return {\n ...part(slot(\"root\")),\n id,\n role: mode(),\n tabIndex: roving() && state.rows.some((row) => !row.disabled) ? -1 : 0,\n \"aria-activedescendant\": !roving() && highlighted ? rowId(highlighted.key) : undefined,\n \"aria-multiselectable\": model.options().selectionMode === \"multiple\",\n onKeyDown,\n onFocus(event) {\n if (!model.active()) return;\n const target = event.currentTarget;\n if (target && \"ownerDocument\" in target && \"focus\" in target) {\n root = target as HTMLElement;\n mount(root);\n }\n if (model.get().highlighted === null) commands.first();\n focusHighlighted();\n },\n };\n },\n getRowProps(key: Key): TreeRowProps {\n const state = model.get();\n const row = current(key);\n const rowMode = mode();\n // Flat grids have no levels, sets or expansion; their rows are plain grid rows.\n const leveled = rowMode === \"tree\" || rowMode === \"treegrid\";\n const focused =\n enabledHighlight()?.key ?? state.rows.find((candidate) => !candidate.disabled)?.key;\n return {\n ...part(slot(\"row\"), row),\n id: rowId(key),\n role: rowMode === \"listbox\" ? \"option\" : grid() ? \"row\" : \"treeitem\",\n tabIndex: roving() && row && !row.disabled && focused === key ? 0 : -1,\n \"aria-level\": leveled && row ? row.depth + 1 : undefined,\n \"aria-posinset\": rowMode === \"grid\" ? undefined : row?.posInSet,\n \"aria-setsize\": rowMode === \"grid\" ? undefined : row?.setSize,\n \"aria-rowindex\": grid() && row ? row.index + 1 : undefined,\n \"aria-expanded\": leveled && row?.hasChildren ? row.expanded : undefined,\n \"aria-selected\": state.selected.has(key),\n \"aria-disabled\": row?.disabled ?? true,\n onPointerMove(event) {\n if (interactive(key) && !event.defaultPrevented && event.pointerType !== \"touch\")\n model.change({ highlighted: key }, { reason: \"pointer\", event });\n },\n onClick(event) {\n if (!interactive(key) || event.defaultPrevented) return;\n const before = model.get();\n model.change(\n {\n highlighted: key,\n ...(event.shiftKey && before.anchor === null ? { anchor: before.highlighted } : {}),\n },\n { reason: \"pointer\", event },\n );\n const action = { key, reason: \"pointer\" as const, event };\n if (event.shiftKey) commands.extendSelection(action);\n else commands.select(action);\n if (model.active()) focusFromPointer(event);\n },\n onDoubleClick(event) {\n if (interactive(key) && !event.defaultPrevented)\n commands.open({ key, reason: \"pointer\", event });\n },\n onFocus(event) {\n if (interactive(key) && roving())\n model.change({ highlighted: key }, { reason: \"programmatic\", event });\n },\n };\n },\n getToggleProps(key: Key): TreeToggleProps {\n const row = current(key);\n return {\n ...part(slot(\"toggle\"), row),\n type: \"button\",\n tabIndex: -1,\n disabled: !row || row.disabled || !row.hasChildren,\n \"aria-label\": row?.expanded ? \"Collapse\" : \"Expand\",\n \"aria-expanded\": row?.hasChildren ? row.expanded : undefined,\n onClick(event) {\n if (!interactive(key) || !current(key)?.hasChildren || event.defaultPrevented) return;\n event.stopPropagation();\n commands.toggle({ key, reason: \"pointer\", event });\n if (model.active()) focusFromPointer(event);\n },\n };\n },\n dispose() {\n root = undefined;\n text = \"\";\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/tree/state.js
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import { flatten } from "../collections/flatten.js";
|
|
2
|
-
import { reconcile } from "../collections/reconcile.js";
|
|
3
|
-
// src/tree/state.ts
|
|
4
|
-
function changeDetails({ reason = "programmatic", event } = {}) {
|
|
5
|
-
let canceled = false;
|
|
6
|
-
return {
|
|
7
|
-
reason,
|
|
8
|
-
event,
|
|
9
|
-
cancel() {
|
|
10
|
-
canceled = true;
|
|
11
|
-
},
|
|
12
|
-
get canceled() {
|
|
13
|
-
return canceled;
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
function sameKeys(left, right) {
|
|
18
|
-
if (left.size !== right.size) return false;
|
|
19
|
-
for (const key of left) if (!right.has(key)) return false;
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
function controlled(state, options) {
|
|
23
|
-
return {
|
|
24
|
-
...state,
|
|
25
|
-
highlighted: options.highlighted?.value !== void 0 ? options.highlighted.value : state.highlighted,
|
|
26
|
-
selected: options.selected?.value ?? state.selected,
|
|
27
|
-
expanded: options.expanded?.value ?? state.expanded
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
/** Owns publication, controlled authority, cancellation and subscription cleanup. */
|
|
31
|
-
function createTreeState(port, initial) {
|
|
32
|
-
let options = initial;
|
|
33
|
-
const state = controlled({
|
|
34
|
-
highlighted: initial.highlighted?.defaultValue ?? null,
|
|
35
|
-
selected: initial.selected?.defaultValue ?? /* @__PURE__ */ new Set(),
|
|
36
|
-
expanded: initial.expanded?.defaultValue ?? /* @__PURE__ */ new Set(),
|
|
37
|
-
anchor: null
|
|
38
|
-
}, initial);
|
|
39
|
-
const rows = flatten(initial, state.expanded);
|
|
40
|
-
const reconciled = controlled(reconcile([], rows, state), initial);
|
|
41
|
-
const store = port.create({
|
|
42
|
-
...reconciled,
|
|
43
|
-
rows
|
|
44
|
-
});
|
|
45
|
-
const subscriptions = /* @__PURE__ */ new Set();
|
|
46
|
-
let disposed = false;
|
|
47
|
-
let revision = 0;
|
|
48
|
-
let notifying = false;
|
|
49
|
-
let queuedUpdates = [];
|
|
50
|
-
function publish(patch, action, update) {
|
|
51
|
-
if (disposed) return;
|
|
52
|
-
const version = ++revision;
|
|
53
|
-
const previous = store.get();
|
|
54
|
-
const nextOptions = update === void 0 ? options : {
|
|
55
|
-
...options,
|
|
56
|
-
...update
|
|
57
|
-
};
|
|
58
|
-
const baseline = update === void 0 ? previous : controlled(previous, nextOptions);
|
|
59
|
-
const requested = {
|
|
60
|
-
...baseline,
|
|
61
|
-
...patch
|
|
62
|
-
};
|
|
63
|
-
const expanded = nextOptions.expanded?.value ?? requested.expanded;
|
|
64
|
-
const nextRows = update === void 0 && sameKeys(previous.expanded, expanded) ? previous.rows : flatten(nextOptions, expanded);
|
|
65
|
-
const next = reconcile(previous.rows, nextRows, requested);
|
|
66
|
-
const wasNotifying = notifying;
|
|
67
|
-
notifying = true;
|
|
68
|
-
try {
|
|
69
|
-
const details = changeDetails(action);
|
|
70
|
-
if (!sameKeys(baseline.expanded, next.expanded)) nextOptions.expanded?.onChange?.(next.expanded, details);
|
|
71
|
-
if (disposed || revision !== version) return;
|
|
72
|
-
if (!details.canceled && baseline.highlighted !== next.highlighted) nextOptions.highlighted?.onChange?.(next.highlighted, details);
|
|
73
|
-
if (disposed || revision !== version) return;
|
|
74
|
-
if (!details.canceled && !sameKeys(baseline.selected, next.selected)) nextOptions.selected?.onChange?.(next.selected, details);
|
|
75
|
-
if (disposed || revision !== version) return;
|
|
76
|
-
if (details.canceled && update === void 0) return;
|
|
77
|
-
options = nextOptions;
|
|
78
|
-
const accepted = controlled(details.canceled ? previous : next, options);
|
|
79
|
-
const visible = accepted.expanded === expanded ? nextRows : flatten(options, accepted.expanded);
|
|
80
|
-
store.set({
|
|
81
|
-
...accepted,
|
|
82
|
-
rows: visible
|
|
83
|
-
});
|
|
84
|
-
} finally {
|
|
85
|
-
notifying = wasNotifying;
|
|
86
|
-
if (!notifying) {
|
|
87
|
-
const updates = queuedUpdates;
|
|
88
|
-
queuedUpdates = [];
|
|
89
|
-
for (const nextOptions of updates) publish({}, { reason: "items-changed" }, nextOptions);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return {
|
|
94
|
-
get: () => store.get(),
|
|
95
|
-
options: () => options,
|
|
96
|
-
active: () => !disposed,
|
|
97
|
-
change: (patch, action = {}) => publish(patch, action),
|
|
98
|
-
update(next) {
|
|
99
|
-
if (disposed) return;
|
|
100
|
-
if (notifying) queuedUpdates.push(next);
|
|
101
|
-
else publish({}, { reason: "items-changed" }, next);
|
|
102
|
-
},
|
|
103
|
-
subscribe(listener) {
|
|
104
|
-
if (disposed) return () => {};
|
|
105
|
-
const unsubscribe = store.subscribe((next) => {
|
|
106
|
-
if (!disposed) listener(next);
|
|
107
|
-
});
|
|
108
|
-
const release = () => {
|
|
109
|
-
if (!subscriptions.delete(release)) return;
|
|
110
|
-
unsubscribe();
|
|
111
|
-
};
|
|
112
|
-
subscriptions.add(release);
|
|
113
|
-
return release;
|
|
114
|
-
},
|
|
115
|
-
dispose() {
|
|
116
|
-
if (disposed) return;
|
|
117
|
-
disposed = true;
|
|
118
|
-
queuedUpdates = [];
|
|
119
|
-
for (const release of subscriptions) release();
|
|
120
|
-
subscriptions.clear();
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
export { changeDetails, createTreeState };
|
|
125
|
-
|
|
126
|
-
//# sourceMappingURL=state.js.map
|
package/dist/tree/state.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","names":[],"sources":["../../src/tree/state.ts"],"sourcesContent":["import { flatten } from \"../collections/flatten.js\";\nimport { reconcile } from \"../collections/reconcile.js\";\nimport type { Key, TreeState } from \"../collections/types.js\";\nimport type { ChangeDetails } from \"../controllable.js\";\nimport type { StorePort } from \"../ports/store.js\";\nimport type { TreeAction, TreeChangeReason, TreeOptions, TreeSnapshot } from \"./types.js\";\n\nexport function changeDetails({\n reason = \"programmatic\",\n event,\n}: TreeAction = {}): ChangeDetails<TreeChangeReason> {\n let canceled = false;\n return {\n reason,\n event,\n cancel() {\n canceled = true;\n },\n get canceled() {\n return canceled;\n },\n };\n}\n\nfunction sameKeys(left: ReadonlySet<Key>, right: ReadonlySet<Key>): boolean {\n if (left.size !== right.size) return false;\n for (const key of left) if (!right.has(key)) return false;\n return true;\n}\n\nfunction controlled<T>(state: TreeState, options: TreeOptions<T>): TreeState {\n return {\n ...state,\n highlighted:\n options.highlighted?.value !== undefined ? options.highlighted.value : state.highlighted,\n selected: options.selected?.value ?? state.selected,\n expanded: options.expanded?.value ?? state.expanded,\n };\n}\n\n/** Owns publication, controlled authority, cancellation and subscription cleanup. */\nexport function createTreeState<T>(port: StorePort, initial: TreeOptions<T>) {\n let options = initial;\n const defaults: TreeState = {\n highlighted: initial.highlighted?.defaultValue ?? null,\n selected: initial.selected?.defaultValue ?? new Set(),\n expanded: initial.expanded?.defaultValue ?? new Set(),\n anchor: null,\n };\n const state = controlled(defaults, initial);\n const rows = flatten(initial, state.expanded);\n const reconciled = controlled(reconcile([], rows, state), initial);\n const store = port.create<TreeSnapshot<T>>({ ...reconciled, rows });\n const subscriptions = new Set<() => void>();\n let disposed = false;\n let revision = 0;\n let notifying = false;\n let queuedUpdates: Partial<TreeOptions<T>>[] = [];\n\n function publish(\n patch: Partial<TreeState>,\n action: TreeAction,\n update?: Partial<TreeOptions<T>>,\n ): void {\n if (disposed) return;\n const version = ++revision;\n const previous = store.get();\n const nextOptions = update === undefined ? options : { ...options, ...update };\n const baseline = update === undefined ? previous : controlled(previous, nextOptions);\n const requested = { ...baseline, ...patch };\n // Controlled expansion governs visibility even when an unacknowledged request asks otherwise.\n const expanded = nextOptions.expanded?.value ?? requested.expanded;\n const nextRows =\n update === undefined && sameKeys(previous.expanded, expanded)\n ? previous.rows\n : flatten(nextOptions, expanded);\n const next = reconcile(previous.rows, nextRows, requested);\n const wasNotifying = notifying;\n notifying = true;\n try {\n const details = changeDetails(action);\n if (!sameKeys(baseline.expanded, next.expanded))\n nextOptions.expanded?.onChange?.(next.expanded, details);\n if (disposed || revision !== version) return;\n if (!details.canceled && baseline.highlighted !== next.highlighted)\n nextOptions.highlighted?.onChange?.(next.highlighted, details);\n if (disposed || revision !== version) return;\n if (!details.canceled && !sameKeys(baseline.selected, next.selected))\n nextOptions.selected?.onChange?.(next.selected, details);\n if (disposed || revision !== version) return;\n if (details.canceled && update === undefined) return;\n options = nextOptions;\n const accepted = controlled(details.canceled ? previous : next, options);\n // Data updates still publish their rows when a state-change callback cancels reconciliation.\n const visible =\n accepted.expanded === expanded ? nextRows : flatten(options, accepted.expanded);\n store.set({ ...accepted, rows: visible });\n } finally {\n notifying = wasNotifying;\n if (!notifying) {\n const updates = queuedUpdates;\n queuedUpdates = [];\n for (const nextOptions of updates) publish({}, { reason: \"items-changed\" }, nextOptions);\n }\n }\n }\n\n return {\n get: () => store.get(),\n options: () => options,\n active: () => !disposed,\n change: (patch: Partial<TreeState>, action: TreeAction = {}) => publish(patch, action),\n update(next: Partial<TreeOptions<T>>) {\n if (disposed) return;\n // Finish all fields and the anchor before publishing synchronous owner acknowledgements.\n if (notifying) queuedUpdates.push(next);\n else publish({}, { reason: \"items-changed\" }, next);\n },\n subscribe(listener: (state: TreeSnapshot<T>) => void): () => void {\n if (disposed) return () => {};\n const unsubscribe = store.subscribe((next) => {\n if (!disposed) listener(next);\n });\n const release = () => {\n if (!subscriptions.delete(release)) return;\n unsubscribe();\n };\n subscriptions.add(release);\n return release;\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n queuedUpdates = [];\n for (const release of subscriptions) release();\n subscriptions.clear();\n },\n };\n}\n\nexport type TreeModel<T> = ReturnType<typeof createTreeState<T>>;\n"],"mappings":"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"}
|