@1771technologies/lytenyte-pro 2.0.4-dev.2 → 2.0.4-dev.4
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/css/components/expression-editor.css +105 -0
- package/dist/components/column-manager/column-manager.d.ts +6 -1
- package/dist/components/column-manager/column-manager.js +23 -2
- package/dist/components/expressions-editor/(expressions)/expression.play.d.ts +4 -0
- package/dist/components/expressions-editor/(expressions)/expression.play.js +69 -0
- package/dist/components/expressions-editor/create-completion-provider.d.ts +3 -0
- package/dist/components/expressions-editor/create-completion-provider.js +161 -0
- package/dist/components/expressions-editor/create-key-down-handler.d.ts +18 -0
- package/dist/components/expressions-editor/create-key-down-handler.js +49 -0
- package/dist/components/expressions-editor/cursor-position/measure-cursor-at-pointer.d.ts +2 -0
- package/dist/components/expressions-editor/cursor-position/measure-cursor-at-pointer.js +56 -0
- package/dist/components/expressions-editor/cursor-position/use-cursor-position.d.ts +5 -0
- package/dist/components/expressions-editor/cursor-position/use-cursor-position.js +17 -0
- package/dist/components/expressions-editor/expression-editor.d.ts +3 -0
- package/dist/components/expressions-editor/expression-editor.js +138 -0
- package/dist/components/expressions-editor/get-indentation.d.ts +1 -0
- package/dist/components/expressions-editor/get-indentation.js +7 -0
- package/dist/components/expressions-editor/handle-completion-key-down.d.ts +2 -0
- package/dist/components/expressions-editor/handle-completion-key-down.js +22 -0
- package/dist/components/expressions-editor/handle-enter-key.d.ts +4 -0
- package/dist/components/expressions-editor/handle-enter-key.js +11 -0
- package/dist/components/expressions-editor/handle-manual-trigger.d.ts +2 -0
- package/dist/components/expressions-editor/handle-manual-trigger.js +3 -0
- package/dist/components/expressions-editor/index.d.ts +17 -0
- package/dist/components/expressions-editor/index.js +11 -0
- package/dist/components/expressions-editor/intellisence/completion-context.d.ts +16 -0
- package/dist/components/expressions-editor/intellisence/completion-context.js +7 -0
- package/dist/components/expressions-editor/intellisence/completion-item.d.ts +5 -0
- package/dist/components/expressions-editor/intellisence/completion-item.js +11 -0
- package/dist/components/expressions-editor/intellisence/completion-list.d.ts +8 -0
- package/dist/components/expressions-editor/intellisence/completion-list.js +18 -0
- package/dist/components/expressions-editor/intellisence/completion-popover.d.ts +1 -0
- package/dist/components/expressions-editor/intellisence/completion-popover.js +30 -0
- package/dist/components/expressions-editor/intellisence/filter-completions-by-prefix.d.ts +2 -0
- package/dist/components/expressions-editor/intellisence/filter-completions-by-prefix.js +6 -0
- package/dist/components/expressions-editor/intellisence/get-word-at-cursor.d.ts +2 -0
- package/dist/components/expressions-editor/intellisence/get-word-at-cursor.js +12 -0
- package/dist/components/expressions-editor/intellisence/use-complete-trigger.d.ts +13 -0
- package/dist/components/expressions-editor/intellisence/use-complete-trigger.js +41 -0
- package/dist/components/expressions-editor/intellisence/use-completions.d.ts +14 -0
- package/dist/components/expressions-editor/intellisence/use-completions.js +78 -0
- package/dist/components/expressions-editor/replace-word-at-cursor.d.ts +5 -0
- package/dist/components/expressions-editor/replace-word-at-cursor.js +7 -0
- package/dist/components/expressions-editor/token-highlighter-default.d.ts +4 -0
- package/dist/components/expressions-editor/token-highlighter-default.js +18 -0
- package/dist/components/expressions-editor/types.d.ts +47 -0
- package/dist/components/expressions-editor/types.js +1 -0
- package/dist/components/expressions-editor/use-keyboard-navigation.d.ts +10 -0
- package/dist/components/expressions-editor/use-keyboard-navigation.js +16 -0
- package/dist/components/pill-manager/container.js +55 -9
- package/dist/components/pill-manager/item.js +15 -1
- package/dist/components/select-all.js +1 -1
- package/dist/components/tree-view/root.d.ts +9 -0
- package/dist/components/tree-view/root.js +4 -2
- package/dist/data-source-client/hooks/use-flattened-groups.js +2 -2
- package/dist/expressions/compiler/compile.d.ts +3 -0
- package/dist/expressions/compiler/compile.js +4 -0
- package/dist/expressions/compiler/eval-constant.d.ts +2 -0
- package/dist/expressions/compiler/eval-constant.js +19 -0
- package/dist/expressions/compiler/is-constant.d.ts +2 -0
- package/dist/expressions/compiler/is-constant.js +6 -0
- package/dist/expressions/compiler/make-constant.d.ts +2 -0
- package/dist/expressions/compiler/make-constant.js +11 -0
- package/dist/expressions/compiler/optimize.d.ts +3 -0
- package/dist/expressions/compiler/optimize.js +47 -0
- package/dist/expressions/compiler/value-of.d.ts +2 -0
- package/dist/expressions/compiler/value-of.js +11 -0
- package/dist/expressions/errors/clamp-offset.d.ts +1 -0
- package/dist/expressions/errors/clamp-offset.js +3 -0
- package/dist/expressions/errors/expression-error.d.ts +10 -0
- package/dist/expressions/errors/expression-error.js +19 -0
- package/dist/expressions/errors/format-error.d.ts +3 -0
- package/dist/expressions/errors/format-error.js +27 -0
- package/dist/expressions/errors/get-line-end.d.ts +1 -0
- package/dist/expressions/errors/get-line-end.js +8 -0
- package/dist/expressions/errors/get-line-start.d.ts +1 -0
- package/dist/expressions/errors/get-line-start.js +8 -0
- package/dist/expressions/errors/index.d.ts +7 -0
- package/dist/expressions/errors/index.js +6 -0
- package/dist/expressions/errors/offset-to-position.d.ts +2 -0
- package/dist/expressions/errors/offset-to-position.js +17 -0
- package/dist/expressions/errors/types.d.ts +10 -0
- package/dist/expressions/errors/types.js +1 -0
- package/dist/expressions/evaluator/evaluate-binary.d.ts +4 -0
- package/dist/expressions/evaluator/evaluate-binary.js +21 -0
- package/dist/expressions/evaluator/evaluate-unary.d.ts +2 -0
- package/dist/expressions/evaluator/evaluate-unary.js +10 -0
- package/dist/expressions/evaluator/evaluate.d.ts +15 -0
- package/dist/expressions/evaluator/evaluate.js +62 -0
- package/dist/expressions/index.d.ts +5 -0
- package/dist/expressions/index.js +3 -0
- package/dist/expressions/lexer/predicates/is-alpha-numeric.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-alpha-numeric.js +5 -0
- package/dist/expressions/lexer/predicates/is-alpha.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-alpha.js +3 -0
- package/dist/expressions/lexer/predicates/is-binary-digit.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-binary-digit.js +3 -0
- package/dist/expressions/lexer/predicates/is-digit.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-digit.js +3 -0
- package/dist/expressions/lexer/predicates/is-hex-digit.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-hex-digit.js +4 -0
- package/dist/expressions/lexer/predicates/is-octal-digit.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-octal-digit.js +3 -0
- package/dist/expressions/lexer/tokenize/consume-digits.d.ts +1 -0
- package/dist/expressions/lexer/tokenize/consume-digits.js +5 -0
- package/dist/expressions/lexer/tokenize/scan-identifier.d.ts +6 -0
- package/dist/expressions/lexer/tokenize/scan-identifier.js +20 -0
- package/dist/expressions/lexer/tokenize/scan-number.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/scan-number.js +32 -0
- package/dist/expressions/lexer/tokenize/scan-operator.d.ts +6 -0
- package/dist/expressions/lexer/tokenize/scan-operator.js +71 -0
- package/dist/expressions/lexer/tokenize/scan-string-literal.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/scan-string-literal.js +22 -0
- package/dist/expressions/lexer/tokenize/scan-string.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/scan-string.js +98 -0
- package/dist/expressions/lexer/tokenize/scan-template-literal.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/scan-template-literal.js +51 -0
- package/dist/expressions/lexer/tokenize/tokenize.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/tokenize.js +99 -0
- package/dist/expressions/lexer/types.d.ts +12 -0
- package/dist/expressions/lexer/types.js +1 -0
- package/dist/expressions/parser/parse-array-literal.d.ts +3 -0
- package/dist/expressions/parser/parse-array-literal.js +15 -0
- package/dist/expressions/parser/parse-expression.d.ts +3 -0
- package/dist/expressions/parser/parse-expression.js +74 -0
- package/dist/expressions/parser/parse-object-literal.d.ts +3 -0
- package/dist/expressions/parser/parse-object-literal.js +69 -0
- package/dist/expressions/parser/parse-pipe-transform.d.ts +3 -0
- package/dist/expressions/parser/parse-pipe-transform.js +26 -0
- package/dist/expressions/parser/parse-postfix.d.ts +3 -0
- package/dist/expressions/parser/parse-postfix.js +23 -0
- package/dist/expressions/parser/parse-primary.d.ts +3 -0
- package/dist/expressions/parser/parse-primary.js +35 -0
- package/dist/expressions/parser/parse-template-literal.d.ts +3 -0
- package/dist/expressions/parser/parse-template-literal.js +41 -0
- package/dist/expressions/parser/parse-unary.d.ts +3 -0
- package/dist/expressions/parser/parse-unary.js +28 -0
- package/dist/expressions/parser/parse.d.ts +3 -0
- package/dist/expressions/parser/parse.js +26 -0
- package/dist/expressions/parser/parser-context.d.ts +12 -0
- package/dist/expressions/parser/parser-context.js +14 -0
- package/dist/expressions/parser/precedence.d.ts +1 -0
- package/dist/expressions/parser/precedence.js +8 -0
- package/dist/expressions/parser/types.d.ts +97 -0
- package/dist/expressions/parser/types.js +1 -0
- package/dist/expressions/plugin.d.ts +20 -0
- package/dist/expressions/plugin.js +1 -0
- package/dist/expressions/plugins/access.d.ts +2 -0
- package/dist/expressions/plugins/access.js +138 -0
- package/dist/expressions/plugins/arrows.d.ts +2 -0
- package/dist/expressions/plugins/arrows.js +83 -0
- package/dist/expressions/plugins/booleans.d.ts +2 -0
- package/dist/expressions/plugins/booleans.js +34 -0
- package/dist/expressions/plugins/collections.d.ts +2 -0
- package/dist/expressions/plugins/collections.js +70 -0
- package/dist/expressions/plugins/comparison.d.ts +2 -0
- package/dist/expressions/plugins/comparison.js +51 -0
- package/dist/expressions/plugins/logical.d.ts +2 -0
- package/dist/expressions/plugins/logical.js +103 -0
- package/dist/expressions/plugins/membership.d.ts +2 -0
- package/dist/expressions/plugins/membership.js +71 -0
- package/dist/expressions/plugins/pipe.d.ts +2 -0
- package/dist/expressions/plugins/pipe.js +57 -0
- package/dist/expressions/plugins/resolved-identifier.d.ts +5 -0
- package/dist/expressions/plugins/resolved-identifier.js +19 -0
- package/dist/expressions/plugins/standard.d.ts +13 -0
- package/dist/expressions/plugins/standard.js +23 -0
- package/dist/expressions/plugins/strings.d.ts +2 -0
- package/dist/expressions/plugins/strings.js +44 -0
- package/dist/expressions/plugins/ternary.d.ts +2 -0
- package/dist/expressions/plugins/ternary.js +58 -0
- package/dist/expressions.d.ts +2 -0
- package/dist/expressions.js +2 -0
- package/dist/index.d.ts +1 -0
- package/package.json +11 -5
|
@@ -3,14 +3,20 @@ import { forwardRef, memo, useEffect, useRef, useState } from "react";
|
|
|
3
3
|
import { usePillRoot } from "./root.context.js";
|
|
4
4
|
import { usePillRow } from "./pill-row.context.js";
|
|
5
5
|
import { dragX, dragY, getDragData, useCombinedRefs, useSelector, } from "@1771technologies/lytenyte-core/internal";
|
|
6
|
-
import { getFocusables } from "@1771technologies/lytenyte-shared";
|
|
6
|
+
import { equal, getFocusables } from "@1771technologies/lytenyte-shared";
|
|
7
7
|
function ContainerBase(props, forwarded) {
|
|
8
|
-
const { setCloned, orientation, rows, movedRef } = usePillRoot();
|
|
8
|
+
const { setCloned, cloned, orientation, rows, movedRef, onPillRowChange, onPillItemActiveChange } = usePillRoot();
|
|
9
9
|
const { row } = usePillRow();
|
|
10
10
|
const [over, setOver] = useState(false);
|
|
11
|
+
const [external, setExternal] = useState(false);
|
|
11
12
|
const x = useSelector(dragX);
|
|
12
13
|
const y = useSelector(dragY);
|
|
13
14
|
const [container, setContainer] = useState(null);
|
|
15
|
+
const ds = getDragData();
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (!ds)
|
|
18
|
+
setExternal(false);
|
|
19
|
+
}, [ds]);
|
|
14
20
|
const wasOver = useRef(false);
|
|
15
21
|
useEffect(() => {
|
|
16
22
|
if (!container)
|
|
@@ -20,12 +26,26 @@ function ContainerBase(props, forwarded) {
|
|
|
20
26
|
setOver(false);
|
|
21
27
|
return;
|
|
22
28
|
}
|
|
23
|
-
|
|
29
|
+
let { item: dragged, id } = ds.pill.data;
|
|
30
|
+
// We resolve the external item to a dragged item here.
|
|
31
|
+
const originalId = id;
|
|
32
|
+
if (id === "__external__") {
|
|
33
|
+
const d = dragged;
|
|
34
|
+
if (!d[row.id])
|
|
35
|
+
return;
|
|
36
|
+
id = row.id;
|
|
37
|
+
dragged = row.pills.find((x) => x.id === d[row.id]);
|
|
38
|
+
if (!dragged) {
|
|
39
|
+
console.error("Specified an external item, but that item is not in the pill group.");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
24
43
|
const bb = container.getBoundingClientRect();
|
|
25
44
|
const isOver = bb.left < x && bb.right > x && bb.top < y && bb.bottom > y;
|
|
26
45
|
// The current drag is from the current row.
|
|
27
46
|
if (id === row.id) {
|
|
28
47
|
movedRef.current = !isOver ? { id: row.id, pillId: dragged.id } : null;
|
|
48
|
+
setExternal(isOver && originalId === "__external__");
|
|
29
49
|
return;
|
|
30
50
|
}
|
|
31
51
|
const thisRow = rows.findIndex((x) => x.id === row.id);
|
|
@@ -43,11 +63,11 @@ function ContainerBase(props, forwarded) {
|
|
|
43
63
|
setCloned((prev) => {
|
|
44
64
|
if (!prev)
|
|
45
65
|
throw new Error("Can't call drag function without cloning nodes.");
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
return
|
|
66
|
+
const newPillSpec = { ...prev[thisRow] };
|
|
67
|
+
newPillSpec.pills = newPills;
|
|
68
|
+
const newPillRows = [...prev];
|
|
69
|
+
newPillRows[thisRow] = newPillSpec;
|
|
70
|
+
return newPillRows;
|
|
51
71
|
});
|
|
52
72
|
}
|
|
53
73
|
else {
|
|
@@ -80,7 +100,7 @@ function ContainerBase(props, forwarded) {
|
|
|
80
100
|
}, [container, movedRef, over, row, rows, setCloned, x, y]);
|
|
81
101
|
const combined = useCombinedRefs(forwarded, setContainer);
|
|
82
102
|
const rtl = useRef(null);
|
|
83
|
-
return (_jsx("div", { ...props, ref: combined, "data-ln-over": over, "data-ln-orientation": orientation, "data-ln-pill-container": true, "data-ln-pill-type": row.type, tabIndex: 0, onKeyDown: (ev) => {
|
|
103
|
+
return (_jsx("div", { ...props, ref: combined, "data-ln-over": over, "data-ln-external-over": external, "data-ln-orientation": orientation, "data-ln-pill-container": true, "data-ln-pill-type": row.type, tabIndex: 0, onKeyDown: (ev) => {
|
|
84
104
|
if (rtl.current == null) {
|
|
85
105
|
const dir = getComputedStyle(ev.currentTarget).direction;
|
|
86
106
|
rtl.current = dir === "rtl";
|
|
@@ -118,6 +138,32 @@ function ContainerBase(props, forwarded) {
|
|
|
118
138
|
}, onDrop: (e) => {
|
|
119
139
|
e.preventDefault();
|
|
120
140
|
e.stopPropagation();
|
|
141
|
+
const ds = getDragData();
|
|
142
|
+
if (!ds?.pill?.data || ds.pill.data.id != "__external__")
|
|
143
|
+
return;
|
|
144
|
+
let { item: dragged } = ds.pill.data;
|
|
145
|
+
// We resolve the external item to a dragged item here.
|
|
146
|
+
const d = dragged;
|
|
147
|
+
if (!d[row.id])
|
|
148
|
+
return;
|
|
149
|
+
dragged = row.pills.find((x) => x.id === d[row.id]);
|
|
150
|
+
const changed = cloned?.filter((x, i) => {
|
|
151
|
+
return !equal(x, rows[i]);
|
|
152
|
+
});
|
|
153
|
+
if (!dragged.active) {
|
|
154
|
+
const next = true;
|
|
155
|
+
const nextPill = { ...dragged, active: next };
|
|
156
|
+
const nextPills = [...row.pills];
|
|
157
|
+
nextPills.splice(nextPills.indexOf(dragged), 1, nextPill);
|
|
158
|
+
const nextRow = { ...row, pills: nextPills };
|
|
159
|
+
const index = rows.indexOf(row);
|
|
160
|
+
onPillItemActiveChange({ index, item: nextPill, row: nextRow });
|
|
161
|
+
}
|
|
162
|
+
dragged.active = true;
|
|
163
|
+
if (changed?.length) {
|
|
164
|
+
onPillRowChange({ changed, full: cloned });
|
|
165
|
+
}
|
|
166
|
+
setCloned(null);
|
|
121
167
|
}, onDragOver: (e) => {
|
|
122
168
|
e.dataTransfer.dropEffect = "move";
|
|
123
169
|
e.preventDefault();
|
|
@@ -53,7 +53,18 @@ function PillItemBase({ item, elementEnd, ...props }, ref) {
|
|
|
53
53
|
const ds = getDragData();
|
|
54
54
|
if (!ds?.pill?.data)
|
|
55
55
|
return;
|
|
56
|
-
|
|
56
|
+
let { item: dragged, id: dragRowId } = ds.pill.data;
|
|
57
|
+
const original = dragRowId;
|
|
58
|
+
// We resolve the external item to a dragged item here.
|
|
59
|
+
if (dragRowId === "__external__") {
|
|
60
|
+
const d = dragged;
|
|
61
|
+
if (!d[row.id])
|
|
62
|
+
return;
|
|
63
|
+
dragRowId = row.id;
|
|
64
|
+
dragged = row.pills.find((x) => x.id === d[row.id]);
|
|
65
|
+
if (!dragged)
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
57
68
|
const accepts = new Set([...(row.accepts ?? []), row.id]);
|
|
58
69
|
if (!accepts.has(dragRowId) && !item.tags?.some((x) => accepts.has(x)))
|
|
59
70
|
return;
|
|
@@ -93,6 +104,9 @@ function PillItemBase({ item, elementEnd, ...props }, ref) {
|
|
|
93
104
|
prevSwapId.current = currentSwapId;
|
|
94
105
|
prevRowId.current = currentRowId;
|
|
95
106
|
setCloned((prev) => {
|
|
107
|
+
if (original === "__external__" && !prev) {
|
|
108
|
+
prev = structuredClone(rows);
|
|
109
|
+
}
|
|
96
110
|
if (!prev)
|
|
97
111
|
throw new Error("Can't call drag function without cloning nodes.");
|
|
98
112
|
const thisRow = prev.findIndex((x) => x.id === row.id);
|
|
@@ -6,7 +6,7 @@ export function SelectAll({ api, slot, }) {
|
|
|
6
6
|
const s = api.useSelectionState();
|
|
7
7
|
const selected = useMemo(() => {
|
|
8
8
|
const selected = s.kind === "isolated" ? s.selected && s.exceptions.size === 0 : s.selected && s.children.size === 0;
|
|
9
|
-
return selected;
|
|
9
|
+
return !!selected;
|
|
10
10
|
}, [s]);
|
|
11
11
|
const indeterminate = useMemo(() => {
|
|
12
12
|
if (s.kind === "isolated")
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
2
|
import { type RowGroup, type RowLeaf, type RowSelectionLinked } from "@1771technologies/lytenyte-shared";
|
|
3
3
|
import type { TreeViewChildParams, TreeViewItem, TreeViewSelectAllParams } from "./types.js";
|
|
4
|
+
import type { DragItem, RowNode } from "../../types.js";
|
|
4
5
|
export interface TreeViewProps<T extends TreeViewItem> {
|
|
5
6
|
readonly items: T[];
|
|
6
7
|
readonly children?: (props: TreeViewChildParams<T>) => ReactNode;
|
|
@@ -22,6 +23,14 @@ export interface TreeViewProps<T extends TreeViewItem> {
|
|
|
22
23
|
* and drag is still being prototyped.
|
|
23
24
|
*/
|
|
24
25
|
readonly draggable?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* @alpha
|
|
28
|
+
* @internal
|
|
29
|
+
*
|
|
30
|
+
* Do not use this property unless you know what you are doing. Support for tree view drag
|
|
31
|
+
* and drag is still being prototyped.
|
|
32
|
+
*/
|
|
33
|
+
readonly getDragTags?: (row: RowNode<T>, leafs: RowLeaf<T>[]) => Record<string, DragItem>;
|
|
25
34
|
/**
|
|
26
35
|
* @alpha
|
|
27
36
|
* @internal
|
|
@@ -7,7 +7,7 @@ import { useClientDataSource } from "../../data-source-client/use-client-data-so
|
|
|
7
7
|
import { usePiece } from "@1771technologies/lytenyte-core/internal";
|
|
8
8
|
import { Root } from "../../root/root.js";
|
|
9
9
|
import { Grid } from "@1771technologies/lytenyte-core";
|
|
10
|
-
function TreeViewBase({ items, rowSelectAllShow: rowSelectAll = true, defaultExpansion, rowHeight = 28, children = TreeChildren, branchJoinSeparator = "/", rowSelectionEnabled = true, rowSelection, onRowSelectionChange, rowGroupExpansions, onRowGroupExpansionChange, selectAllSlot, draggable, onItemsReordered, }, forwarded) {
|
|
10
|
+
function TreeViewBase({ items, rowSelectAllShow: rowSelectAll = true, defaultExpansion, rowHeight = 28, children = TreeChildren, branchJoinSeparator = "/", rowSelectionEnabled = true, rowSelection, onRowSelectionChange, rowGroupExpansions, onRowGroupExpansionChange, selectAllSlot, draggable, getDragTags, onItemsReordered, }, forwarded) {
|
|
11
11
|
const groupFn = useMemo(() => {
|
|
12
12
|
return (x) => x.data.path;
|
|
13
13
|
}, []);
|
|
@@ -46,8 +46,10 @@ function TreeViewBase({ items, rowSelectAllShow: rowSelectAll = true, defaultExp
|
|
|
46
46
|
width: 20,
|
|
47
47
|
widthMin: 20,
|
|
48
48
|
cellRenderer: ({ row, rowIndex, api, indeterminate, selected }) => {
|
|
49
|
+
const tags = getDragTags?.(row, api.rowLeafs(row.id).map((x) => api.rowById(x)));
|
|
49
50
|
const { props, isDragActive } = api.useRowDrag({
|
|
50
51
|
rowIndex,
|
|
52
|
+
tags,
|
|
51
53
|
});
|
|
52
54
|
const over = over$.useValue();
|
|
53
55
|
const isBefore = isBefore$.useValue();
|
|
@@ -76,7 +78,7 @@ function TreeViewBase({ items, rowSelectAllShow: rowSelectAll = true, defaultExp
|
|
|
76
78
|
});
|
|
77
79
|
},
|
|
78
80
|
};
|
|
79
|
-
}, [children, draggable, isBefore$, itemLookup, over$, rowSelectionEnabled, selectAllSlot]);
|
|
81
|
+
}, [children, draggable, getDragTags, isBefore$, itemLookup, over$, rowSelectionEnabled, selectAllSlot]);
|
|
80
82
|
useImperativeHandle(forwarded, () => {
|
|
81
83
|
return {
|
|
82
84
|
rowsSelected: () => (api?.rowsSelected().rows ?? []).filter((x) => x.id !== "__ln_select_all"),
|
|
@@ -39,7 +39,7 @@ export function useFlattenedGroups(root, agg, leafs, workingSet, sort, expandedF
|
|
|
39
39
|
}, [agg, expandedFn, ignoreIsLast, leafs, root, sort, sortFallback, suppressLeafExpansion, workingSet]);
|
|
40
40
|
return flat;
|
|
41
41
|
}
|
|
42
|
-
const nodeChildrenToRows = (root, agg, leafs, workingSet, sort,
|
|
42
|
+
const nodeChildrenToRows = (root, agg, leafs, workingSet, sort, _) => {
|
|
43
43
|
const values = root.values();
|
|
44
44
|
const rows = [];
|
|
45
45
|
for (const v of values) {
|
|
@@ -57,7 +57,7 @@ const nodeChildrenToRows = (root, agg, leafs, workingSet, sort, isLast) => {
|
|
|
57
57
|
rows.push(row);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
if (
|
|
60
|
+
if (sort)
|
|
61
61
|
return rows.sort(sort);
|
|
62
62
|
return rows;
|
|
63
63
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function evalConstant(op, left, right) {
|
|
2
|
+
if (typeof left === "number" && typeof right === "number") {
|
|
3
|
+
switch (op) {
|
|
4
|
+
case "+":
|
|
5
|
+
return left + right;
|
|
6
|
+
case "-":
|
|
7
|
+
return left - right;
|
|
8
|
+
case "*":
|
|
9
|
+
return left * right;
|
|
10
|
+
case "/":
|
|
11
|
+
return left / right;
|
|
12
|
+
case "%":
|
|
13
|
+
return left % right;
|
|
14
|
+
case "**":
|
|
15
|
+
return left ** right;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function makeConstant(value, start, end) {
|
|
2
|
+
if (typeof value === "number")
|
|
3
|
+
return { type: "NumberLiteral", value, start, end };
|
|
4
|
+
if (typeof value === "string")
|
|
5
|
+
return { type: "StringLiteral", value, start, end };
|
|
6
|
+
if (typeof value === "boolean")
|
|
7
|
+
return { type: "BooleanLiteral", value, start, end };
|
|
8
|
+
if (value === null)
|
|
9
|
+
return { type: "NullLiteral", value: null, start, end };
|
|
10
|
+
return { type: "UndefinedLiteral", value: undefined, start, end };
|
|
11
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { isConstant } from "./is-constant.js";
|
|
2
|
+
import { valueOf } from "./value-of.js";
|
|
3
|
+
import { evalConstant } from "./eval-constant.js";
|
|
4
|
+
import { makeConstant } from "./make-constant.js";
|
|
5
|
+
export function optimize(node, plugins) {
|
|
6
|
+
const opt = (n) => optimize(n, plugins);
|
|
7
|
+
// Try plugin optimization first
|
|
8
|
+
if (plugins) {
|
|
9
|
+
for (const plugin of plugins) {
|
|
10
|
+
if (plugin.optimize) {
|
|
11
|
+
const result = plugin.optimize(node, opt);
|
|
12
|
+
if (result)
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
switch (node.type) {
|
|
18
|
+
case "BinaryExpression": {
|
|
19
|
+
const left = opt(node.left);
|
|
20
|
+
const right = opt(node.right);
|
|
21
|
+
if (isConstant(left) && isConstant(right)) {
|
|
22
|
+
const result = evalConstant(node.operator, valueOf(left), valueOf(right));
|
|
23
|
+
if (result !== undefined) {
|
|
24
|
+
return makeConstant(result, node.start, node.end);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return { ...node, left, right };
|
|
28
|
+
}
|
|
29
|
+
case "UnaryExpression": {
|
|
30
|
+
const operand = opt(node.operand);
|
|
31
|
+
if (isConstant(operand)) {
|
|
32
|
+
const val = valueOf(operand);
|
|
33
|
+
if (node.operator === "-" && typeof val === "number") {
|
|
34
|
+
return {
|
|
35
|
+
type: "NumberLiteral",
|
|
36
|
+
value: -val,
|
|
37
|
+
start: node.start,
|
|
38
|
+
end: node.end,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return { ...node, operand };
|
|
43
|
+
}
|
|
44
|
+
default:
|
|
45
|
+
return node;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function valueOf(node) {
|
|
2
|
+
if (node.type === "NumberLiteral")
|
|
3
|
+
return node.value;
|
|
4
|
+
if (node.type === "StringLiteral")
|
|
5
|
+
return node.value;
|
|
6
|
+
if (node.type === "BooleanLiteral")
|
|
7
|
+
return node.value;
|
|
8
|
+
if (node.type === "NullLiteral")
|
|
9
|
+
return null;
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function clampOffset(source: string, offset: number): number;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ErrorLocation } from "./types.js";
|
|
2
|
+
/** Syntax error thrown during parsing. Contains source location and formatted caret display. */
|
|
3
|
+
export declare class ExpressionError extends Error {
|
|
4
|
+
readonly rawMessage: string;
|
|
5
|
+
readonly start: number;
|
|
6
|
+
readonly end: number;
|
|
7
|
+
readonly source: string;
|
|
8
|
+
readonly suggestion?: string;
|
|
9
|
+
constructor(message: string, location: ErrorLocation, suggestion?: string);
|
|
10
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { formatError } from "./format-error.js";
|
|
2
|
+
/** Syntax error thrown during parsing. Contains source location and formatted caret display. */
|
|
3
|
+
export class ExpressionError extends Error {
|
|
4
|
+
rawMessage;
|
|
5
|
+
start;
|
|
6
|
+
end;
|
|
7
|
+
source;
|
|
8
|
+
suggestion;
|
|
9
|
+
constructor(message, location, suggestion) {
|
|
10
|
+
const formatted = formatError(message, location, suggestion);
|
|
11
|
+
super(formatted);
|
|
12
|
+
this.name = "ExpressionError";
|
|
13
|
+
this.rawMessage = message;
|
|
14
|
+
this.start = location.start;
|
|
15
|
+
this.end = location.end;
|
|
16
|
+
this.source = location.source;
|
|
17
|
+
this.suggestion = suggestion;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { clampOffset } from "./clamp-offset.js";
|
|
2
|
+
import { getLineStart } from "./get-line-start.js";
|
|
3
|
+
import { getLineEnd } from "./get-line-end.js";
|
|
4
|
+
import { offsetToPosition } from "./offset-to-position.js";
|
|
5
|
+
/** Format an error message with source context, caret display, and position info. */
|
|
6
|
+
export function formatError(message, location, suggestion) {
|
|
7
|
+
const { source } = location;
|
|
8
|
+
const start = clampOffset(source, location.start);
|
|
9
|
+
const rawEnd = clampOffset(source, location.end);
|
|
10
|
+
const end = Math.max(start + 1, rawEnd);
|
|
11
|
+
const startPos = offsetToPosition(source, start);
|
|
12
|
+
const lineStart = getLineStart(source, start);
|
|
13
|
+
const lineEnd = getLineEnd(source, start);
|
|
14
|
+
const lineText = source.slice(lineStart, lineEnd);
|
|
15
|
+
const caretStart = start - lineStart;
|
|
16
|
+
const caretEnd = Math.min(end, lineEnd);
|
|
17
|
+
const caretLength = Math.max(1, caretEnd - start);
|
|
18
|
+
const gutter = `${startPos.line} | `;
|
|
19
|
+
const padding = " ".repeat(gutter.length + caretStart);
|
|
20
|
+
const carets = "^".repeat(caretLength);
|
|
21
|
+
let result = `${message}\n\n${gutter}${lineText}\n${padding}${carets}`;
|
|
22
|
+
if (suggestion) {
|
|
23
|
+
result += ` Did you mean "${suggestion}"?`;
|
|
24
|
+
}
|
|
25
|
+
result += `\n\nat line ${startPos.line}, column ${startPos.column} (offset ${start}-${end})`;
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getLineEnd(source: string, offset: number): number;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { clampOffset } from "./clamp-offset.js";
|
|
2
|
+
const NEWLINE_CODE = 10;
|
|
3
|
+
export function getLineEnd(source, offset) {
|
|
4
|
+
let index = clampOffset(source, offset);
|
|
5
|
+
while (index < source.length && source.charCodeAt(index) !== NEWLINE_CODE)
|
|
6
|
+
index++;
|
|
7
|
+
return index;
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getLineStart(source: string, offset: number): number;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { clampOffset } from "./clamp-offset.js";
|
|
2
|
+
const NEWLINE_CODE = 10;
|
|
3
|
+
export function getLineStart(source, offset) {
|
|
4
|
+
let index = clampOffset(source, offset);
|
|
5
|
+
while (index > 0 && source.charCodeAt(index - 1) !== NEWLINE_CODE)
|
|
6
|
+
index--;
|
|
7
|
+
return index;
|
|
8
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { SourcePosition, ErrorLocation } from "./types.js";
|
|
2
|
+
export { clampOffset } from "./clamp-offset.js";
|
|
3
|
+
export { getLineStart } from "./get-line-start.js";
|
|
4
|
+
export { getLineEnd } from "./get-line-end.js";
|
|
5
|
+
export { offsetToPosition } from "./offset-to-position.js";
|
|
6
|
+
export { formatError } from "./format-error.js";
|
|
7
|
+
export { ExpressionError } from "./expression-error.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { clampOffset } from "./clamp-offset.js";
|
|
2
|
+
export { getLineStart } from "./get-line-start.js";
|
|
3
|
+
export { getLineEnd } from "./get-line-end.js";
|
|
4
|
+
export { offsetToPosition } from "./offset-to-position.js";
|
|
5
|
+
export { formatError } from "./format-error.js";
|
|
6
|
+
export { ExpressionError } from "./expression-error.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { clampOffset } from "./clamp-offset.js";
|
|
2
|
+
const NEWLINE_CODE = 10;
|
|
3
|
+
export function offsetToPosition(source, offset) {
|
|
4
|
+
const safeOffset = clampOffset(source, offset);
|
|
5
|
+
let line = 1;
|
|
6
|
+
let column = 1;
|
|
7
|
+
for (let index = 0; index < safeOffset; index++) {
|
|
8
|
+
if (source.charCodeAt(index) === NEWLINE_CODE) {
|
|
9
|
+
line++;
|
|
10
|
+
column = 1;
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
column++;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return { line, column, offset: safeOffset };
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BinaryExpression } from "../parser/types.js";
|
|
2
|
+
import type { Plugin } from "../plugin.js";
|
|
3
|
+
import type { RunOptions } from "./evaluate.js";
|
|
4
|
+
export declare function evaluateBinary(node: BinaryExpression, context: Record<string, unknown>, depth: number, plugins?: Plugin[], options?: RunOptions): unknown;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { evaluateNode } from "./evaluate.js";
|
|
2
|
+
export function evaluateBinary(node, context, depth, plugins, options) {
|
|
3
|
+
const left = evaluateNode(node.left, context, depth + 1, plugins, options);
|
|
4
|
+
const right = evaluateNode(node.right, context, depth + 1, plugins, options);
|
|
5
|
+
switch (node.operator) {
|
|
6
|
+
case "+":
|
|
7
|
+
return left + right;
|
|
8
|
+
case "-":
|
|
9
|
+
return left - right;
|
|
10
|
+
case "*":
|
|
11
|
+
return left * right;
|
|
12
|
+
case "/":
|
|
13
|
+
return left / right;
|
|
14
|
+
case "%":
|
|
15
|
+
return left % right;
|
|
16
|
+
case "**":
|
|
17
|
+
return left ** right;
|
|
18
|
+
default:
|
|
19
|
+
throw new Error(`Unknown binary operator: ${node.operator}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ASTNode } from "../parser/types.js";
|
|
2
|
+
import type { Token } from "../lexer/types.js";
|
|
3
|
+
import type { Plugin } from "../plugin.js";
|
|
4
|
+
export interface RunOptions {
|
|
5
|
+
undefinedIdentifierFallback?: unknown;
|
|
6
|
+
}
|
|
7
|
+
export declare class Evaluator {
|
|
8
|
+
private plugins?;
|
|
9
|
+
constructor(plugins?: Plugin[]);
|
|
10
|
+
run: (input: string | ASTNode, context?: Record<string, unknown>, options?: RunOptions) => unknown;
|
|
11
|
+
ast: (input: string) => ASTNode;
|
|
12
|
+
tokens: (input: string, tokensizeWhitespace?: boolean) => Token[];
|
|
13
|
+
tokensSafe: (input: string, tokensizeWhitespace?: boolean) => Token[];
|
|
14
|
+
}
|
|
15
|
+
export declare function evaluateNode(node: ASTNode, context: Record<string, unknown>, depth: number, plugins?: Plugin[], options?: RunOptions): unknown;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { parse } from "../parser/parse.js";
|
|
2
|
+
import { compile } from "../compiler/compile.js";
|
|
3
|
+
import { tokenize, tokenizeSafe } from "../lexer/tokenize/tokenize.js";
|
|
4
|
+
import { evaluateBinary } from "./evaluate-binary.js";
|
|
5
|
+
import { evaluateUnary } from "./evaluate-unary.js";
|
|
6
|
+
const MAX_DEPTH = 1000;
|
|
7
|
+
export class Evaluator {
|
|
8
|
+
plugins;
|
|
9
|
+
constructor(plugins) {
|
|
10
|
+
this.plugins = plugins;
|
|
11
|
+
}
|
|
12
|
+
run = (input, context = {}, options) => {
|
|
13
|
+
const node = typeof input === "string" ? compile(parse(input, 0, this.plugins), this.plugins) : input;
|
|
14
|
+
return evaluateNode(node, context, 0, this.plugins, options);
|
|
15
|
+
};
|
|
16
|
+
ast = (input) => {
|
|
17
|
+
return compile(parse(input, 0, this.plugins), this.plugins);
|
|
18
|
+
};
|
|
19
|
+
tokens = (input, tokensizeWhitespace) => {
|
|
20
|
+
return tokenize(input, this.plugins, tokensizeWhitespace);
|
|
21
|
+
};
|
|
22
|
+
tokensSafe = (input, tokensizeWhitespace) => {
|
|
23
|
+
return tokenizeSafe(input, this.plugins, tokensizeWhitespace);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function evaluateNode(node, context, depth, plugins, options) {
|
|
27
|
+
if (depth > MAX_DEPTH) {
|
|
28
|
+
throw new Error("Maximum evaluation depth exceeded");
|
|
29
|
+
}
|
|
30
|
+
// Try plugin evaluation first
|
|
31
|
+
if (plugins) {
|
|
32
|
+
const evalFn = (n, ctx) => evaluateNode(n, ctx, depth + 1, plugins, options);
|
|
33
|
+
for (const plugin of plugins) {
|
|
34
|
+
if (plugin.evaluate) {
|
|
35
|
+
const result = plugin.evaluate(node, context, evalFn);
|
|
36
|
+
if (result !== null)
|
|
37
|
+
return result.value;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Core built-in evaluation
|
|
42
|
+
switch (node.type) {
|
|
43
|
+
case "NumberLiteral":
|
|
44
|
+
return node.value;
|
|
45
|
+
case "Identifier": {
|
|
46
|
+
if (!(node.name in context)) {
|
|
47
|
+
if (options && "undefinedIdentifierFallback" in options)
|
|
48
|
+
return options.undefinedIdentifierFallback;
|
|
49
|
+
throw new Error(`Identifier "${node.name}" is not defined`);
|
|
50
|
+
}
|
|
51
|
+
return context[node.name];
|
|
52
|
+
}
|
|
53
|
+
case "BinaryExpression":
|
|
54
|
+
return evaluateBinary(node, context, depth, plugins, options);
|
|
55
|
+
case "UnaryExpression":
|
|
56
|
+
return evaluateUnary(node.operator, evaluateNode(node.operand, context, depth + 1, plugins, options));
|
|
57
|
+
case "SpreadElement":
|
|
58
|
+
throw new Error("Unexpected spread element outside of array literal");
|
|
59
|
+
default:
|
|
60
|
+
throw new Error(`Unknown node type: ${node.type}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Evaluator } from "./evaluator/evaluate.js";
|
|
2
|
+
export type { Plugin, EvalFn } from "./plugin.js";
|
|
3
|
+
export type { Token } from "./lexer/types.js";
|
|
4
|
+
export { accessPlugin, arrowsPlugin, booleansPlugin, collectionsPlugin, comparisonPlugin, logicalPlugin, membershipPlugin, pipePlugin, standardPlugins, stringsPlugin, ternaryPlugin, } from "./plugins/standard.js";
|
|
5
|
+
export { createResolvedIdentifierPlugin } from "./plugins/resolved-identifier.js";
|