@revisium/schema-toolkit-ui 0.2.2 → 0.3.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/dist/index.mjs CHANGED
@@ -1,12 +1,12 @@
1
1
  import * as mobx from "mobx";
2
2
  import { makeAutoObservable, observable, reaction, runInAction } from "mobx";
3
- import { FIELD_NAME_ERROR_MESSAGE, JsonSchemaTypeName, SystemSchemaIds, createRowModel, createTableModel, createTableModel as createTableModel$1, fileSchema, generateDefaultValue, isValidFieldName, jsonPointerToSimplePath, rowCreatedAtSchema, rowCreatedIdSchema, rowHashSchema, rowIdSchema, rowPublishedAtSchema, rowSchemaHashSchema, rowUpdatedAtSchema, rowVersionIdSchema, validateFormulaAgainstSchema } from "@revisium/schema-toolkit";
3
+ import { FIELD_NAME_ERROR_MESSAGE, SystemSchemaIds, createRowModel, createTableModel, fileSchema, generateDefaultValue, isForeignKeyValueNode, isValidFieldName, jsonPointerToSimplePath, rowCreatedAtSchema, rowCreatedIdSchema, rowHashSchema, rowIdSchema, rowPublishedAtSchema, rowSchemaHashSchema, rowUpdatedAtSchema, rowVersionIdSchema, validateFormulaAgainstSchema } from "@revisium/schema-toolkit";
4
4
  import { createMobxProvider, setReactivityProvider } from "@revisium/schema-toolkit/core";
5
- import { Badge, Box, Button, Flex, Icon, IconButton, Input, Menu, Popover, Portal, SegmentGroup, Text, Textarea, Tooltip as Tooltip$1, VStack } from "@chakra-ui/react";
5
+ import { Badge, Box, Button, Flex, HStack, HoverCard, Icon, IconButton, Image, Input, Menu, Popover, Portal, SegmentGroup, Spinner, Text, Textarea, Tooltip as Tooltip$1, VStack } from "@chakra-ui/react";
6
6
  import { observer } from "mobx-react-lite";
7
7
  import * as React$1 from "react";
8
8
  import React, { Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
9
- import { PiArrowCounterClockwiseBold, PiArrowRight, PiArrowsLeftRightLight, PiBracketsCurlyThin, PiCaretDownLight, PiCaretLeft, PiCaretRight, PiCopy, PiDotOutlineFill, PiDotsSixVerticalBold, PiEquals, PiFunction, PiGear, PiLinkThin, PiMinusLight, PiPencilSimpleLight, PiPlusBold, PiPlusLight, PiTextT, PiTrash, PiTreeViewThin, PiWarning, PiWarningCircle, PiX } from "react-icons/pi";
9
+ import { PiArrowCounterClockwiseBold, PiArrowRight, PiArrowSquareUpRightThin, PiArrowsLeftRightLight, PiBracketsCurlyThin, PiCaretDownLight, PiCaretLeft, PiCaretRight, PiCopy, PiDotOutlineFill, PiDotsSixVerticalBold, PiDotsThreeVerticalBold, PiEquals, PiFile, PiFunction, PiFunctionLight, PiGear, PiInfo, PiLinkThin, PiMagnifyingGlassBold, PiMinusLight, PiPencilSimpleLight, PiPlusBold, PiPlusLight, PiTextT, PiTrash, PiTreeViewThin, PiUploadThin, PiWarning, PiWarningCircle, PiX, PiXBold } from "react-icons/pi";
10
10
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
11
  import { githubLight } from "@uiw/codemirror-theme-github";
12
12
  import CodeMirror, { EditorView } from "@uiw/react-codemirror";
@@ -16,6 +16,9 @@ import { Menu as Menu$1 } from "@chakra-ui/react/menu";
16
16
  import { LuChevronRight } from "react-icons/lu";
17
17
  import { draggable, dropTargetForElements, monitorForElements } from "@atlaskit/drag-and-drop/adapter/element";
18
18
  import { DialogBackdrop, DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogPositioner, DialogRoot, DialogTitle } from "@chakra-ui/react/dialog";
19
+ import { Virtuoso } from "react-virtuoso";
20
+
21
+ export * from "@revisium/schema-toolkit"
19
22
 
20
23
  //#region src/schema-editor/model/state/TreeState.ts
21
24
  var TreeState = class {
@@ -1680,7 +1683,7 @@ var SchemaEditorCore = class {
1680
1683
  keyboard;
1681
1684
  constructor(jsonSchema, options = {}, accessorFactory = new NodeAccessorFactory()) {
1682
1685
  ensureReactivityProvider();
1683
- this._tableModel = createTableModel$1({
1686
+ this._tableModel = createTableModel({
1684
1687
  tableId: options.tableId ?? "",
1685
1688
  schema: jsonSchema,
1686
1689
  refSchemas: options.refSchemas ?? defaultRefSchemas
@@ -4585,5 +4588,1969 @@ const UpdatingSchemaEditor = observer(({ vm }) => {
4585
4588
  });
4586
4589
 
4587
4590
  //#endregion
4588
- export { BackButton, CloseButton, ContentEditable, CopyButton, CreateButton, CreatingEditorVM, CreatingSchemaEditor, GrayButton, JsonCard, JsonSchemaTypeName, SchemaEditorCore, SchemaTypeIds, SettingsButton, Tooltip, UpdatingEditorVM, UpdatingSchemaEditor, ViewerSwitcher, ViewerSwitcherMode, createRowModel, createTableModel, ensureReactivityProvider, getLabelByRef, typeMenuGroups, useContentEditable };
4591
+ //#region src/row-editor/vm/flattenNodes.ts
4592
+ function traverse(node, result) {
4593
+ result.push({
4594
+ type: "node",
4595
+ node
4596
+ });
4597
+ if (node.showChildren) for (const child of node.childNodes) traverse(child, result);
4598
+ if (node.isArray() && node.showAddButton) result.push({
4599
+ type: "add-button",
4600
+ array: node,
4601
+ guides: [...node.guides, false]
4602
+ });
4603
+ }
4604
+ function flattenNodes(root) {
4605
+ const result = [];
4606
+ if (root.isObject()) for (const child of root.children) traverse(child, result);
4607
+ else traverse(root, result);
4608
+ return result;
4609
+ }
4610
+
4611
+ //#endregion
4612
+ //#region src/row-editor/vm/state/RowTreeState.ts
4613
+ var RowTreeState = class {
4614
+ _expanded = observable.map();
4615
+ _focused = observable.map();
4616
+ constructor() {
4617
+ makeAutoObservable(this, {}, { autoBind: true });
4618
+ }
4619
+ isExpanded(nodeId) {
4620
+ return this._expanded.get(nodeId) ?? true;
4621
+ }
4622
+ setExpanded(nodeId, value) {
4623
+ this._expanded.set(nodeId, value);
4624
+ }
4625
+ toggleExpanded(nodeId) {
4626
+ this._expanded.set(nodeId, !this.isExpanded(nodeId));
4627
+ }
4628
+ isFocused(nodeId) {
4629
+ return this._focused.get(nodeId) ?? false;
4630
+ }
4631
+ setFocused(nodeId, value) {
4632
+ this._focused.set(nodeId, value);
4633
+ }
4634
+ expandAll(nodeIds) {
4635
+ for (const nodeId of nodeIds) this._expanded.set(nodeId, true);
4636
+ }
4637
+ collapseAll(nodeIds) {
4638
+ for (const nodeId of nodeIds) this._expanded.set(nodeId, false);
4639
+ }
4640
+ reset() {
4641
+ this._expanded.clear();
4642
+ this._focused.clear();
4643
+ }
4644
+ };
4645
+
4646
+ //#endregion
4647
+ //#region src/row-editor/vm/accessor/RowNodeAccessor.ts
4648
+ var RowNodeAccessor = class {
4649
+ _menu;
4650
+ _layout;
4651
+ constructor(node, parent, _state, _tree, editorContext, _childResolver) {
4652
+ this.node = node;
4653
+ this.parent = parent;
4654
+ this._state = _state;
4655
+ this._tree = _tree;
4656
+ this.editorContext = editorContext;
4657
+ this._childResolver = _childResolver;
4658
+ makeAutoObservable(this, {}, { autoBind: true });
4659
+ }
4660
+ setMenu(menu) {
4661
+ this._menu = menu;
4662
+ }
4663
+ setLayout(layout) {
4664
+ this._layout = layout;
4665
+ }
4666
+ get id() {
4667
+ return this.node.id;
4668
+ }
4669
+ get name() {
4670
+ return this.node.name;
4671
+ }
4672
+ get displayName() {
4673
+ if (this.parent) return this.node.name;
4674
+ return this._rootDisplayName();
4675
+ }
4676
+ get testId() {
4677
+ if (!this.parent) return "root";
4678
+ const parentId = this.parent.testId;
4679
+ if (parentId === "root" && this.parent.isObject()) return this.name;
4680
+ return `${parentId}-${this.name}`;
4681
+ }
4682
+ isPrimitive() {
4683
+ return this.node.isPrimitive();
4684
+ }
4685
+ isObject() {
4686
+ return this.node.isObject();
4687
+ }
4688
+ isArray() {
4689
+ return this.node.isArray();
4690
+ }
4691
+ get isExpanded() {
4692
+ return this._state.isExpanded;
4693
+ }
4694
+ set isExpanded(value) {
4695
+ this._state.setExpanded(value);
4696
+ }
4697
+ get isFocused() {
4698
+ return this._state.isFocused;
4699
+ }
4700
+ expand() {
4701
+ this._state.setExpanded(true);
4702
+ }
4703
+ collapse() {
4704
+ this._state.setExpanded(false);
4705
+ }
4706
+ toggleExpanded() {
4707
+ this._state.toggleExpanded();
4708
+ }
4709
+ setFocused(focused) {
4710
+ this._state.setFocused(focused);
4711
+ }
4712
+ get depth() {
4713
+ return this._layout.depth;
4714
+ }
4715
+ get guides() {
4716
+ return this._layout.guides;
4717
+ }
4718
+ get isCollapsible() {
4719
+ return this._layout.isCollapsible;
4720
+ }
4721
+ get isCollapsibleTree() {
4722
+ return this._layout.isCollapsibleTree;
4723
+ }
4724
+ get rendererType() {
4725
+ return this._layout.rendererType;
4726
+ }
4727
+ get isContainer() {
4728
+ return this._layout.isContainer;
4729
+ }
4730
+ get childNodes() {
4731
+ return this._childResolver.getChildren(this);
4732
+ }
4733
+ get showChildren() {
4734
+ return this._layout.showChildren;
4735
+ }
4736
+ get collapsedLabel() {
4737
+ return this._layout.collapsedLabel;
4738
+ }
4739
+ get isLongText() {
4740
+ return this._layout.isLongText;
4741
+ }
4742
+ expandAll() {
4743
+ this._layout.expandAll();
4744
+ }
4745
+ collapseAll() {
4746
+ this._layout.collapseAll();
4747
+ }
4748
+ get menu() {
4749
+ return this._menu.menu;
4750
+ }
4751
+ get formula() {
4752
+ if (this.node.isPrimitive()) return this.node.formula?.expression;
4753
+ }
4754
+ get isEditorReadOnly() {
4755
+ return this.editorContext?.isReadOnly ?? false;
4756
+ }
4757
+ get path() {
4758
+ return this._tree.pathOf(this.node).asString();
4759
+ }
4760
+ get isDirty() {
4761
+ return this.node.isDirty;
4762
+ }
4763
+ get value() {
4764
+ return this.node.value;
4765
+ }
4766
+ get defaultValue() {
4767
+ return this.node.defaultValue;
4768
+ }
4769
+ get isReadOnly() {
4770
+ return this.node.isReadOnly;
4771
+ }
4772
+ get isFieldReadOnly() {
4773
+ return this.isReadOnly || this.isEditorReadOnly;
4774
+ }
4775
+ setValue(value) {
4776
+ this.node.setValue(value);
4777
+ }
4778
+ get children() {
4779
+ if (!this.node.isObject()) return [];
4780
+ return this._childResolver.getChildren(this);
4781
+ }
4782
+ child(name) {
4783
+ return this.children.find((c) => c.name === name);
4784
+ }
4785
+ get items() {
4786
+ if (!this.node.isArray()) return [];
4787
+ return this._childResolver.getChildren(this);
4788
+ }
4789
+ get length() {
4790
+ if (!this.node.isArray()) return 0;
4791
+ return this.node.length;
4792
+ }
4793
+ at(index) {
4794
+ const allItems = this.items;
4795
+ if (index < 0 || index >= allItems.length) return;
4796
+ return allItems[index];
4797
+ }
4798
+ pushValue(value) {
4799
+ this.node.pushValue(value);
4800
+ }
4801
+ removeAt(index) {
4802
+ this.node.removeAt(index);
4803
+ }
4804
+ move(fromIndex, toIndex) {
4805
+ this.node.move(fromIndex, toIndex);
4806
+ }
4807
+ insertAt(index) {
4808
+ this.node.pushValue(null);
4809
+ const lastIndex = this.length - 1;
4810
+ if (index < lastIndex) this.node.move(lastIndex, index);
4811
+ }
4812
+ get showAddButton() {
4813
+ return this.isExpanded && !this.isEditorReadOnly;
4814
+ }
4815
+ isForeignKey() {
4816
+ return isForeignKeyValueNode(this.node);
4817
+ }
4818
+ get foreignKeyTableId() {
4819
+ return this.node.foreignKey;
4820
+ }
4821
+ isFile() {
4822
+ return this.rendererType === "file";
4823
+ }
4824
+ get fileStatus() {
4825
+ return this._getFileChildValue("status", "");
4826
+ }
4827
+ get fileId() {
4828
+ return this._getFileChildValue("fileId", "");
4829
+ }
4830
+ get fileUrl() {
4831
+ return this._getFileChildValue("url", "");
4832
+ }
4833
+ get fileMimeType() {
4834
+ return this._getFileChildValue("mimeType", "");
4835
+ }
4836
+ get fileWidth() {
4837
+ return this._getFileChildNumericValue("width");
4838
+ }
4839
+ get fileHeight() {
4840
+ return this._getFileChildNumericValue("height");
4841
+ }
4842
+ get callbacks() {
4843
+ return this.editorContext?.callbacks ?? null;
4844
+ }
4845
+ getChildAccessors() {
4846
+ return this._childResolver.getChildren(this);
4847
+ }
4848
+ _getFileChildValue(name, fallback) {
4849
+ if (!this.node.isObject()) return fallback;
4850
+ const child = this.node.child(name);
4851
+ if (child?.isPrimitive()) return String(child.value);
4852
+ return fallback;
4853
+ }
4854
+ _rootDisplayName() {
4855
+ const schema = this.node.schema;
4856
+ if (!("type" in schema)) return this.node.name;
4857
+ return `<${schema.type}>`;
4858
+ }
4859
+ _getFileChildNumericValue(name) {
4860
+ if (!this.node.isObject()) return 0;
4861
+ const child = this.node.child(name);
4862
+ if (child?.isPrimitive()) return Number(child.value) || 0;
4863
+ return 0;
4864
+ }
4865
+ };
4866
+
4867
+ //#endregion
4868
+ //#region src/row-editor/vm/accessor/RowNodeState.ts
4869
+ var RowNodeState = class {
4870
+ constructor(_nodeId, _treeState) {
4871
+ this._nodeId = _nodeId;
4872
+ this._treeState = _treeState;
4873
+ makeAutoObservable(this, {}, { autoBind: true });
4874
+ }
4875
+ get isExpanded() {
4876
+ return this._treeState.isExpanded(this._nodeId);
4877
+ }
4878
+ setExpanded(value) {
4879
+ this._treeState.setExpanded(this._nodeId, value);
4880
+ }
4881
+ toggleExpanded() {
4882
+ this._treeState.toggleExpanded(this._nodeId);
4883
+ }
4884
+ get isFocused() {
4885
+ return this._treeState.isFocused(this._nodeId);
4886
+ }
4887
+ setFocused(value) {
4888
+ this._treeState.setFocused(this._nodeId, value);
4889
+ }
4890
+ };
4891
+
4892
+ //#endregion
4893
+ //#region src/row-editor/vm/accessor/RowNodeMenu.ts
4894
+ var RowNodeMenu = class {
4895
+ constructor(_accessor) {
4896
+ this._accessor = _accessor;
4897
+ makeAutoObservable(this, {}, { autoBind: true });
4898
+ }
4899
+ get menu() {
4900
+ return [
4901
+ ...this.topMenu,
4902
+ ...this.arrayOwnMenu,
4903
+ ...this.arrayItemMenu,
4904
+ ...this.bottomMenu
4905
+ ];
4906
+ }
4907
+ get arrayItemContext() {
4908
+ const parent = this._accessor.parent;
4909
+ if (!parent || !parent.node.isArray()) return null;
4910
+ const arrayNode = parent.node;
4911
+ const index = arrayNode.value.indexOf(this._accessor.node);
4912
+ if (index === -1) return null;
4913
+ return {
4914
+ index,
4915
+ arrayLength: arrayNode.value.length,
4916
+ insertAt: (i) => parent.insertAt(i),
4917
+ removeAt: (i) => parent.removeAt(i),
4918
+ move: (from, to) => parent.move(from, to)
4919
+ };
4920
+ }
4921
+ get topMenu() {
4922
+ if (!this._accessor.isCollapsibleTree) return [];
4923
+ return [{
4924
+ value: "expand",
4925
+ label: "Expand",
4926
+ handler: () => this._accessor.expandAll()
4927
+ }, {
4928
+ value: "collapse",
4929
+ label: "Collapse",
4930
+ handler: () => this._accessor.collapseAll(),
4931
+ afterSeparator: true
4932
+ }];
4933
+ }
4934
+ get arrayOwnMenu() {
4935
+ if (!this._accessor.node.isArray()) return [];
4936
+ return [{
4937
+ value: "array",
4938
+ label: "Array",
4939
+ children: [...this._accessor.length > 0 ? [{
4940
+ value: "add-first",
4941
+ label: "Add item to start",
4942
+ handler: () => this._accessor.insertAt(0)
4943
+ }] : [], {
4944
+ value: "add-last",
4945
+ label: "Add item to end",
4946
+ handler: () => this._accessor.pushValue(null)
4947
+ }]
4948
+ }];
4949
+ }
4950
+ get arrayItemMenu() {
4951
+ const ctx = this.arrayItemContext;
4952
+ if (!ctx) return [];
4953
+ const moveMenuItem = ctx.arrayLength > 1 ? this.buildMoveMenuItem(ctx) : null;
4954
+ return [
4955
+ ...moveMenuItem ? [moveMenuItem] : [],
4956
+ {
4957
+ value: "item",
4958
+ label: "Item",
4959
+ children: [{
4960
+ value: "add-before",
4961
+ label: "Add before",
4962
+ handler: () => ctx.insertAt(ctx.index)
4963
+ }, {
4964
+ value: "add-after",
4965
+ label: "Add after",
4966
+ handler: () => ctx.insertAt(ctx.index + 1)
4967
+ }]
4968
+ },
4969
+ {
4970
+ value: "delete",
4971
+ label: "Delete",
4972
+ handler: () => ctx.removeAt(ctx.index),
4973
+ afterSeparator: true
4974
+ }
4975
+ ];
4976
+ }
4977
+ buildMoveMenuItem(ctx) {
4978
+ const { index, arrayLength } = ctx;
4979
+ const isFirst = index === 0;
4980
+ const isLast = index === arrayLength - 1;
4981
+ return {
4982
+ value: "move",
4983
+ label: "Move",
4984
+ children: [
4985
+ ...arrayLength > 2 && index > 1 ? [{
4986
+ value: "move-to-start",
4987
+ label: "to start",
4988
+ handler: () => ctx.move(index, 0)
4989
+ }] : [],
4990
+ ...!isFirst ? [{
4991
+ value: "move-up",
4992
+ label: "up",
4993
+ handler: () => ctx.move(index, index - 1)
4994
+ }] : [],
4995
+ ...!isLast ? [{
4996
+ value: "move-down",
4997
+ label: "down",
4998
+ handler: () => ctx.move(index, index + 1)
4999
+ }] : [],
5000
+ ...arrayLength > 2 && index < arrayLength - 2 ? [{
5001
+ value: "move-to-end",
5002
+ label: "to end",
5003
+ handler: () => ctx.move(index, arrayLength - 1)
5004
+ }] : []
5005
+ ]
5006
+ };
5007
+ }
5008
+ get bottomMenu() {
5009
+ const copyChildren = [{
5010
+ value: "json",
5011
+ label: "json",
5012
+ handler: () => this.copyJson()
5013
+ }];
5014
+ if (this._accessor.path) copyChildren.push({
5015
+ value: "path",
5016
+ label: "path",
5017
+ handler: () => this.copyPath()
5018
+ });
5019
+ return [{
5020
+ value: "copy",
5021
+ label: "Copy",
5022
+ children: copyChildren
5023
+ }];
5024
+ }
5025
+ async copyJson() {
5026
+ const json = JSON.stringify(this._accessor.node.getPlainValue(), null, 2);
5027
+ await navigator.clipboard.writeText(json);
5028
+ }
5029
+ async copyPath() {
5030
+ await navigator.clipboard.writeText(this._accessor.path);
5031
+ }
5032
+ };
5033
+
5034
+ //#endregion
5035
+ //#region src/row-editor/vm/accessor/RowNodeLayout.ts
5036
+ const STRING_COLLAPSE_THRESHOLD = 64;
5037
+ var RowNodeLayout = class {
5038
+ constructor(_accessor) {
5039
+ this._accessor = _accessor;
5040
+ makeAutoObservable(this, {}, { autoBind: true });
5041
+ }
5042
+ get depth() {
5043
+ let d = 0;
5044
+ let current = this._accessor.parent;
5045
+ while (current) {
5046
+ d++;
5047
+ current = current.parent;
5048
+ }
5049
+ return d;
5050
+ }
5051
+ get guides() {
5052
+ const result = [];
5053
+ let current = this._accessor.parent;
5054
+ while (current) {
5055
+ if (current.parent) {
5056
+ const isLastSibling = current.parent.getChildAccessors().at(-1)?.id === current.id;
5057
+ result.unshift(!isLastSibling);
5058
+ } else if (!current.isObject()) result.unshift(false);
5059
+ current = current.parent;
5060
+ }
5061
+ return result;
5062
+ }
5063
+ get isCollapsible() {
5064
+ return this._accessor.getChildAccessors().length > 0;
5065
+ }
5066
+ get isCollapsibleTree() {
5067
+ return this.isCollapsible || this._accessor.getChildAccessors().some((c) => c.isCollapsible);
5068
+ }
5069
+ get rendererType() {
5070
+ if (this._accessor.node.isObject()) {
5071
+ const schema = this._accessor.node.schema;
5072
+ if ("$ref" in schema && schema.$ref === SystemSchemaIds.File) return "file";
5073
+ return "container";
5074
+ }
5075
+ if (this._accessor.node.isArray()) return "container";
5076
+ if (isForeignKeyValueNode(this._accessor.node)) return "foreignKey";
5077
+ if (this._accessor.node.isPrimitive()) {
5078
+ const v = this._accessor.value;
5079
+ if (typeof v === "boolean") return "boolean";
5080
+ if (typeof v === "number") return "number";
5081
+ }
5082
+ return "string";
5083
+ }
5084
+ get isContainer() {
5085
+ return this._accessor.node.isObject() || this._accessor.node.isArray();
5086
+ }
5087
+ get isRefNode() {
5088
+ return "$ref" in this._accessor.node.schema && this.isContainer;
5089
+ }
5090
+ get showChildren() {
5091
+ return this.isContainer && this._accessor.isExpanded && this._accessor.getChildAccessors().length > 0;
5092
+ }
5093
+ get collapsedLabel() {
5094
+ if (this._accessor.node.isPrimitive()) return this.primitiveCollapsedLabel;
5095
+ if (this._accessor.node.isObject()) return formatCount(this._accessor.children.length, "key", "keys");
5096
+ if (this._accessor.node.isArray()) return formatCount(this._accessor.length, "item", "items");
5097
+ return "";
5098
+ }
5099
+ get primitiveCollapsedLabel() {
5100
+ const v = this._accessor.value;
5101
+ if (typeof v !== "string") return "";
5102
+ if (!v.trim()) return "<empty text>";
5103
+ const wordCount = v.trim().split(/\s+/).length;
5104
+ return formatCount(wordCount, "word", "words", "text: ");
5105
+ }
5106
+ get isLongText() {
5107
+ const v = this._accessor.value;
5108
+ return typeof v === "string" && v.length > STRING_COLLAPSE_THRESHOLD;
5109
+ }
5110
+ expandAll() {
5111
+ this._accessor.expand();
5112
+ for (const child of this._accessor.getChildAccessors()) if (child.isCollapsible) child.expandAll();
5113
+ }
5114
+ collapseAll() {
5115
+ this._accessor.collapse();
5116
+ for (const child of this._accessor.getChildAccessors()) if (child.isCollapsible) child.collapseAll();
5117
+ }
5118
+ };
5119
+ function formatCount(count, singular, plural, prefix = "") {
5120
+ return `<${prefix}${count} ${count === 1 ? singular : plural}>`;
5121
+ }
5122
+
5123
+ //#endregion
5124
+ //#region src/row-editor/vm/accessor/RowAccessorFactory.ts
5125
+ var RowAccessorFactory = class {
5126
+ constructor(_tree, _treeState, _editorContext) {
5127
+ this._tree = _tree;
5128
+ this._treeState = _treeState;
5129
+ this._editorContext = _editorContext;
5130
+ }
5131
+ create(node, parent, childResolver) {
5132
+ const accessor = new RowNodeAccessor(node, parent, new RowNodeState(node.id, this._treeState), this._tree, this._editorContext, childResolver);
5133
+ const layout = new RowNodeLayout(accessor);
5134
+ const menu = new RowNodeMenu(accessor);
5135
+ accessor.setLayout(layout);
5136
+ accessor.setMenu(menu);
5137
+ if (layout.isRefNode) this._treeState.setExpanded(node.id, false);
5138
+ return accessor;
5139
+ }
5140
+ };
5141
+
5142
+ //#endregion
5143
+ //#region src/row-editor/vm/accessor/RowAccessorCache.ts
5144
+ var RowAccessorCache = class {
5145
+ _cache = observable.map();
5146
+ constructor(_factory) {
5147
+ this._factory = _factory;
5148
+ }
5149
+ getOrCreate(node, parent) {
5150
+ const cached = this._cache.get(node.id);
5151
+ if (cached) return cached;
5152
+ const accessor = this._factory.create(node, parent, this);
5153
+ this._cache.set(node.id, accessor);
5154
+ return accessor;
5155
+ }
5156
+ getChildren(accessor) {
5157
+ const node = accessor.node;
5158
+ if (node.isObject()) return node.children.map((childNode) => this.getOrCreate(childNode, accessor));
5159
+ if (node.isArray()) return node.value.map((itemNode) => this.getOrCreate(itemNode, accessor));
5160
+ return [];
5161
+ }
5162
+ clear() {
5163
+ this._cache.clear();
5164
+ }
5165
+ };
5166
+
5167
+ //#endregion
5168
+ //#region src/row-editor/vm/RowEditorCore.ts
5169
+ var RowEditorCore = class {
5170
+ treeState = new RowTreeState();
5171
+ _cache;
5172
+ _root;
5173
+ constructor(tree, editorContext, options) {
5174
+ this._cache = new RowAccessorCache(new RowAccessorFactory(tree, this.treeState, editorContext));
5175
+ this._root = this._cache.getOrCreate(tree.root, null);
5176
+ if (options?.collapseComplexity) this._collapseIfComplex(options.collapseComplexity);
5177
+ makeAutoObservable(this, { treeState: false }, { autoBind: true });
5178
+ }
5179
+ get root() {
5180
+ return this._root;
5181
+ }
5182
+ get flattenedNodes() {
5183
+ return flattenNodes(this._root);
5184
+ }
5185
+ dispose() {
5186
+ this._cache.clear();
5187
+ this.treeState.reset();
5188
+ }
5189
+ _collapseIfComplex(threshold) {
5190
+ const nodeIds = this._collectAllNodeIds(this._root);
5191
+ if (nodeIds.length >= threshold) {
5192
+ this.treeState.collapseAll(nodeIds);
5193
+ this.treeState.setExpanded(this._root.id, true);
5194
+ }
5195
+ }
5196
+ _collectAllNodeIds(accessor, ids = []) {
5197
+ ids.push(accessor.id);
5198
+ for (const child of accessor.getChildAccessors()) this._collectAllNodeIds(child, ids);
5199
+ return ids;
5200
+ }
5201
+ };
5202
+
5203
+ //#endregion
5204
+ //#region src/row-editor/vm/RowEditorVM.ts
5205
+ var RowEditorVM = class {
5206
+ _rowModel;
5207
+ _core;
5208
+ _mode;
5209
+ _callbacks;
5210
+ _onChange;
5211
+ _onSave;
5212
+ _onCancel;
5213
+ _disposeReaction;
5214
+ _prevPatchCount = 0;
5215
+ _rowId;
5216
+ _initialRowId;
5217
+ constructor(schema, initialValue, options) {
5218
+ ensureReactivityProvider();
5219
+ this._mode = options?.mode ?? "editing";
5220
+ this._rowId = options?.rowId ?? "";
5221
+ this._initialRowId = this._rowId;
5222
+ this._callbacks = options?.callbacks ?? null;
5223
+ this._onChange = options?.onChange ?? null;
5224
+ this._onSave = options?.onSave ?? null;
5225
+ this._onCancel = options?.onCancel ?? null;
5226
+ this._rowModel = createRowModel({
5227
+ rowId: "editor",
5228
+ schema,
5229
+ data: initialValue,
5230
+ refSchemas: options?.refSchemas
5231
+ });
5232
+ this._core = new RowEditorCore(this._rowModel.tree, this, { collapseComplexity: options?.collapseComplexity });
5233
+ makeAutoObservable(this, {}, { autoBind: true });
5234
+ this._disposeReaction = this._onChange ? reaction(() => this.patches, () => this._emitChange()) : null;
5235
+ }
5236
+ get root() {
5237
+ return this._core.root;
5238
+ }
5239
+ get flattenedNodes() {
5240
+ return this._core.flattenedNodes;
5241
+ }
5242
+ get rowModel() {
5243
+ return this._rowModel;
5244
+ }
5245
+ get mode() {
5246
+ return this._mode;
5247
+ }
5248
+ get rowId() {
5249
+ return this._rowId;
5250
+ }
5251
+ get initialRowId() {
5252
+ return this._initialRowId;
5253
+ }
5254
+ get isRowIdChanged() {
5255
+ return this._rowId !== this._initialRowId;
5256
+ }
5257
+ setRowId(value) {
5258
+ this._rowId = value;
5259
+ }
5260
+ get isDirty() {
5261
+ return this._rowModel.isDirty;
5262
+ }
5263
+ get hasChanges() {
5264
+ return this.isDirty || this.isRowIdChanged;
5265
+ }
5266
+ get isValid() {
5267
+ return this._rowModel.isValid;
5268
+ }
5269
+ get errors() {
5270
+ return this._rowModel.errors;
5271
+ }
5272
+ get isReadOnly() {
5273
+ return this._mode === "reading";
5274
+ }
5275
+ get callbacks() {
5276
+ return this._callbacks;
5277
+ }
5278
+ get patches() {
5279
+ return this._rowModel.patches;
5280
+ }
5281
+ getValue() {
5282
+ return this._rowModel.getPlainValue();
5283
+ }
5284
+ save() {
5285
+ const value = this.getValue();
5286
+ const patches = this.patches;
5287
+ this.commit();
5288
+ this._onSave?.(this._rowId, value, patches);
5289
+ }
5290
+ markAsSaved() {
5291
+ this.commit();
5292
+ }
5293
+ cancel() {
5294
+ this._onCancel?.();
5295
+ }
5296
+ commit() {
5297
+ this._rowModel.commit();
5298
+ this._prevPatchCount = 0;
5299
+ this._initialRowId = this._rowId;
5300
+ }
5301
+ revert() {
5302
+ this._rowModel.revert();
5303
+ this._prevPatchCount = 0;
5304
+ }
5305
+ dispose() {
5306
+ this._disposeReaction?.();
5307
+ this._core.dispose();
5308
+ this._rowModel.dispose();
5309
+ }
5310
+ _emitChange() {
5311
+ if (!this._onChange || !this.isValid) return;
5312
+ const all = this.patches;
5313
+ const newPatches = all.slice(this._prevPatchCount);
5314
+ this._prevPatchCount = all.length;
5315
+ if (newPatches.length > 0) this._onChange(newPatches);
5316
+ }
5317
+ };
5318
+
5319
+ //#endregion
5320
+ //#region src/row-editor/ui/components/Guides.tsx
5321
+ function toGuideItems(guides) {
5322
+ return guides.map((showLine, i) => ({
5323
+ key: `d${i}`,
5324
+ showLine
5325
+ }));
5326
+ }
5327
+ const Guides = ({ guides }) => {
5328
+ const items = toGuideItems(guides);
5329
+ return /* @__PURE__ */ jsxs(Flex, {
5330
+ position: "relative",
5331
+ alignItems: "center",
5332
+ children: [/* @__PURE__ */ jsx(Box, {
5333
+ left: "-48px",
5334
+ width: "48px",
5335
+ height: "100%",
5336
+ position: "absolute"
5337
+ }), items.map((item) => /* @__PURE__ */ jsx(Box, {
5338
+ position: "relative",
5339
+ width: "24px",
5340
+ height: "100%",
5341
+ _before: item.showLine ? {
5342
+ content: "\"\"",
5343
+ position: "absolute",
5344
+ left: "8px",
5345
+ top: 0,
5346
+ bottom: 0,
5347
+ width: "1px",
5348
+ backgroundColor: "blackAlpha.200"
5349
+ } : void 0
5350
+ }, item.key))]
5351
+ });
5352
+ };
5353
+
5354
+ //#endregion
5355
+ //#region src/row-editor/ui/components/Dot.tsx
5356
+ const getDotTestId = (testId, isCollapsed) => {
5357
+ if (!testId) return;
5358
+ return isCollapsed ? `${testId}-expand` : `${testId}-collapse`;
5359
+ };
5360
+ const Dot = ({ isCollapsed, isCollapsible, toggleCollapsed, testId }) => {
5361
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [!isCollapsed && /* @__PURE__ */ jsx(Flex, {
5362
+ color: "gray.300",
5363
+ width: "16px",
5364
+ height: "28px",
5365
+ _groupHover: { display: isCollapsible ? "none" : "flex" },
5366
+ alignItems: "center",
5367
+ justifyContent: "center",
5368
+ children: /* @__PURE__ */ jsx(PiDotOutlineFill, {})
5369
+ }), isCollapsible && /* @__PURE__ */ jsx(Flex, {
5370
+ _groupHover: {
5371
+ display: "inline-flex",
5372
+ color: "gray.500"
5373
+ },
5374
+ display: isCollapsed ? "inline-flex" : "none",
5375
+ _hover: { backgroundColor: "transparent" },
5376
+ color: "gray.400",
5377
+ onClick: toggleCollapsed,
5378
+ width: "16px",
5379
+ height: "28px",
5380
+ alignItems: "center",
5381
+ justifyContent: "center",
5382
+ cursor: "pointer",
5383
+ "data-testid": getDotTestId(testId, isCollapsed),
5384
+ children: /* @__PURE__ */ jsx(Box, {
5385
+ transform: isCollapsed ? "rotate(0deg)" : "rotate(90deg)",
5386
+ children: /* @__PURE__ */ jsx(MdOutlineChevronRight, { size: 16 })
5387
+ })
5388
+ })] });
5389
+ };
5390
+
5391
+ //#endregion
5392
+ //#region src/row-editor/ui/components/Field.tsx
5393
+ const Field = ({ name, formula, description, isDeprecated }) => {
5394
+ const getTooltipContent = () => {
5395
+ if (formula && description) return /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsxs(Flex, {
5396
+ alignItems: "center",
5397
+ gap: "4px",
5398
+ marginBottom: "4px",
5399
+ fontWeight: "medium",
5400
+ children: [/* @__PURE__ */ jsx(PiFunctionLight, { size: 14 }), /* @__PURE__ */ jsx("span", { children: formula })]
5401
+ }), /* @__PURE__ */ jsx(Box, {
5402
+ color: "gray.300",
5403
+ children: description
5404
+ })] });
5405
+ if (formula) return /* @__PURE__ */ jsxs(Flex, {
5406
+ alignItems: "center",
5407
+ gap: "4px",
5408
+ children: [/* @__PURE__ */ jsx(PiFunctionLight, { size: 14 }), /* @__PURE__ */ jsx("span", { children: formula })]
5409
+ });
5410
+ if (description) return description;
5411
+ return null;
5412
+ };
5413
+ const tooltipContent = getTooltipContent();
5414
+ const fieldContent = /* @__PURE__ */ jsxs(Flex, {
5415
+ alignItems: "center",
5416
+ gap: "4px",
5417
+ color: "gray.400",
5418
+ children: [/* @__PURE__ */ jsxs(Text, {
5419
+ textDecoration: isDeprecated ? "line-through" : void 0,
5420
+ children: [name, ":"]
5421
+ }), formula && /* @__PURE__ */ jsx(PiFunctionLight, { size: 14 })]
5422
+ });
5423
+ return /* @__PURE__ */ jsx(Flex, {
5424
+ height: "28px",
5425
+ alignItems: "center",
5426
+ children: tooltipContent ? /* @__PURE__ */ jsx(Tooltip, {
5427
+ openDelay: 350,
5428
+ content: tooltipContent,
5429
+ positioning: { placement: "right-end" },
5430
+ showArrow: true,
5431
+ children: fieldContent
5432
+ }) : fieldContent
5433
+ });
5434
+ };
5435
+
5436
+ //#endregion
5437
+ //#region src/row-editor/ui/components/More.tsx
5438
+ const More = ({ onClick, label }) => {
5439
+ return /* @__PURE__ */ jsx(Text, {
5440
+ ml: "8px",
5441
+ color: "gray.300",
5442
+ onClick,
5443
+ cursor: "pointer",
5444
+ children: label
5445
+ });
5446
+ };
5447
+
5448
+ //#endregion
5449
+ //#region src/row-editor/ui/components/NodeMenu/NodeMenu.tsx
5450
+ const NodeMenu = observer(({ node }) => {
5451
+ const [isOpen, setIsOpen] = useState(false);
5452
+ if (node.menu.length === 0) return null;
5453
+ return /* @__PURE__ */ jsxs(Menu.Root, {
5454
+ lazyMount: true,
5455
+ unmountOnExit: true,
5456
+ onOpenChange: ({ open }) => setIsOpen(open),
5457
+ children: [/* @__PURE__ */ jsx(Menu.Trigger, {
5458
+ asChild: true,
5459
+ children: /* @__PURE__ */ jsx(Flex, {
5460
+ width: "24px",
5461
+ left: "-24px",
5462
+ position: "absolute",
5463
+ zIndex: 1,
5464
+ alignItems: "center",
5465
+ justifyContent: "center",
5466
+ cursor: "pointer",
5467
+ children: /* @__PURE__ */ jsx(Flex, {
5468
+ alignItems: "center",
5469
+ justifyContent: "center",
5470
+ mt: "2px",
5471
+ height: "24px",
5472
+ width: "12px",
5473
+ borderRadius: "4px",
5474
+ bg: "blackAlpha.50",
5475
+ backdropFilter: "blur(4px)",
5476
+ boxShadow: "0 0 0 1px rgba(0,0,0,0.06), 0 1px 1px rgba(0,0,0,0.08)",
5477
+ opacity: isOpen ? 1 : 0,
5478
+ transition: isOpen ? "opacity 1s ease 0s" : void 0,
5479
+ _groupHover: {
5480
+ opacity: 1,
5481
+ transition: "opacity 0.5s ease 0s"
5482
+ },
5483
+ _hover: { boxShadow: "0 0 0 1px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.1)" },
5484
+ children: /* @__PURE__ */ jsx(Icon, {
5485
+ size: "md",
5486
+ color: "gray.400",
5487
+ as: PiDotsThreeVerticalBold
5488
+ })
5489
+ })
5490
+ })
5491
+ }), /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, { children: /* @__PURE__ */ jsx(Menu.Content, { children: node.menu.map((item) => item.children ? /* @__PURE__ */ jsxs(Menu.Root, {
5492
+ positioning: {
5493
+ placement: "right-start",
5494
+ gutter: 2
5495
+ },
5496
+ children: [
5497
+ item.beforeSeparator && /* @__PURE__ */ jsx(Menu.Separator, {}),
5498
+ /* @__PURE__ */ jsxs(Menu.TriggerItem, {
5499
+ width: "100%",
5500
+ justifyContent: "space-between",
5501
+ children: [
5502
+ item.label,
5503
+ " ",
5504
+ /* @__PURE__ */ jsx(LuChevronRight, {})
5505
+ ]
5506
+ }),
5507
+ item.afterSeparator && /* @__PURE__ */ jsx(Menu.Separator, {}),
5508
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, { children: /* @__PURE__ */ jsx(Menu.Content, { children: item.children.map((childItem) => /* @__PURE__ */ jsxs(Fragment, { children: [
5509
+ childItem.beforeSeparator && /* @__PURE__ */ jsx(Menu.Separator, {}),
5510
+ /* @__PURE__ */ jsx(Menu.Item, {
5511
+ value: childItem.value,
5512
+ onClick: childItem.handler,
5513
+ children: /* @__PURE__ */ jsx(Box, {
5514
+ flex: 1,
5515
+ children: childItem.label
5516
+ })
5517
+ }),
5518
+ childItem.afterSeparator && /* @__PURE__ */ jsx(Menu.Separator, {})
5519
+ ] }, childItem.value)) }) }) })
5520
+ ]
5521
+ }, item.value) : /* @__PURE__ */ jsxs(Fragment, { children: [
5522
+ item.beforeSeparator && /* @__PURE__ */ jsx(Menu.Separator, {}),
5523
+ /* @__PURE__ */ jsx(Menu.Item, {
5524
+ value: item.value,
5525
+ onClick: item.handler,
5526
+ children: /* @__PURE__ */ jsx(Box, {
5527
+ flex: 1,
5528
+ children: item.label
5529
+ })
5530
+ }),
5531
+ item.afterSeparator && /* @__PURE__ */ jsx(Menu.Separator, {})
5532
+ ] }, item.value)) }) }) })]
5533
+ });
5534
+ });
5535
+
5536
+ //#endregion
5537
+ //#region src/row-editor/ui/components/Row.tsx
5538
+ const Row = ({ node, name, guides, isCollapsible = false, isExpanded = true, onToggle, formula, description, isDeprecated, skipDot, skipField, skipMore, collapsedLabel, isReadOnly, testId, onMouseEnter, onMouseLeave, children }) => {
5539
+ const isCollapsed = isCollapsible && !isExpanded;
5540
+ const showMenu = node && !isReadOnly;
5541
+ return /* @__PURE__ */ jsxs(Flex, {
5542
+ width: "100%",
5543
+ onMouseEnter,
5544
+ onMouseLeave,
5545
+ position: "relative",
5546
+ className: "group",
5547
+ "data-testid": testId,
5548
+ children: [
5549
+ /* @__PURE__ */ jsx(Guides, { guides }),
5550
+ showMenu && /* @__PURE__ */ jsx(NodeMenu, { node }),
5551
+ /* @__PURE__ */ jsxs(Flex, {
5552
+ width: "100%",
5553
+ alignItems: "center",
5554
+ children: [/* @__PURE__ */ jsxs(Flex, { children: [
5555
+ !skipDot && /* @__PURE__ */ jsx(Dot, {
5556
+ isCollapsed,
5557
+ isCollapsible,
5558
+ toggleCollapsed: onToggle,
5559
+ testId
5560
+ }),
5561
+ !skipField && /* @__PURE__ */ jsx(Field, {
5562
+ name,
5563
+ formula,
5564
+ description,
5565
+ isDeprecated
5566
+ }),
5567
+ children
5568
+ ] }), !skipMore && isCollapsed && collapsedLabel && /* @__PURE__ */ jsx(More, {
5569
+ onClick: onToggle,
5570
+ label: collapsedLabel
5571
+ })]
5572
+ })
5573
+ ]
5574
+ });
5575
+ };
5576
+
5577
+ //#endregion
5578
+ //#region src/row-editor/ui/renderers/ContainerRenderer.tsx
5579
+ const ContainerRendererComponent = observer(({ node }) => {
5580
+ const handleToggle = useCallback(() => {
5581
+ node.toggleExpanded();
5582
+ }, [node]);
5583
+ return /* @__PURE__ */ jsx(Row, {
5584
+ node,
5585
+ name: node.displayName,
5586
+ guides: node.guides,
5587
+ isCollapsible: node.isCollapsible,
5588
+ isExpanded: node.isExpanded,
5589
+ onToggle: handleToggle,
5590
+ collapsedLabel: node.collapsedLabel,
5591
+ isReadOnly: node.isEditorReadOnly,
5592
+ testId: node.testId
5593
+ });
5594
+ });
5595
+
5596
+ //#endregion
5597
+ //#region src/row-editor/ui/editors/PrimitiveBox.tsx
5598
+ const PrimitiveBox = observer(({ value, readonly, prefix = "", postfix = "", restrict, dataTestId, onChange, onFocus, onBlur }) => {
5599
+ const [focused, setFocused] = useState(false);
5600
+ const handleFocus = useCallback(() => {
5601
+ setFocused(true);
5602
+ onFocus?.();
5603
+ }, [onFocus]);
5604
+ const handleBlur = useCallback(() => {
5605
+ setFocused(false);
5606
+ onBlur?.();
5607
+ }, [onBlur]);
5608
+ return /* @__PURE__ */ jsx(Box, {
5609
+ borderRadius: "4px",
5610
+ bgColor: focused ? "gray.100" : void 0,
5611
+ _hover: { bgColor: readonly ? void 0 : "gray.100" },
5612
+ mt: "2px",
5613
+ ml: "2px",
5614
+ pl: "4px",
5615
+ pr: "4px",
5616
+ minHeight: "24px",
5617
+ minWidth: "15px",
5618
+ cursor: readonly ? "text" : void 0,
5619
+ children: readonly ? `${prefix}${value}${postfix}` : /* @__PURE__ */ jsx(ContentEditable, {
5620
+ dataTestId,
5621
+ prefix,
5622
+ postfix,
5623
+ initValue: value,
5624
+ onChange,
5625
+ onFocus: handleFocus,
5626
+ onBlur: handleBlur,
5627
+ restrict
5628
+ })
5629
+ });
5630
+ });
5631
+
5632
+ //#endregion
5633
+ //#region src/row-editor/ui/editors/StringEditor.tsx
5634
+ const StringEditor = ({ value, setValue, readonly, dataTestId }) => {
5635
+ const [internalValue, setInternalValue] = useState(value);
5636
+ useEffect(() => {
5637
+ setInternalValue(value);
5638
+ }, [value]);
5639
+ const handleChange = useCallback((newValue) => {
5640
+ setInternalValue(newValue);
5641
+ }, []);
5642
+ const handleBlur = useCallback(() => {
5643
+ setValue(internalValue);
5644
+ }, [internalValue, setValue]);
5645
+ const prefix = internalValue ? "" : "\"";
5646
+ return /* @__PURE__ */ jsx(PrimitiveBox, {
5647
+ prefix,
5648
+ postfix: prefix,
5649
+ value: internalValue,
5650
+ readonly,
5651
+ dataTestId,
5652
+ onChange: handleChange,
5653
+ onBlur: handleBlur
5654
+ });
5655
+ };
5656
+
5657
+ //#endregion
5658
+ //#region src/row-editor/ui/renderers/StringRenderer.tsx
5659
+ const StringRendererComponent = observer(({ node }) => {
5660
+ const value = String(node.value);
5661
+ const handleSetValue = useCallback((newValue) => {
5662
+ node.setValue(newValue);
5663
+ }, [node]);
5664
+ const handleToggle = useCallback(() => {
5665
+ node.toggleExpanded();
5666
+ }, [node]);
5667
+ if (node.isLongText) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Row, {
5668
+ node,
5669
+ name: node.displayName,
5670
+ guides: node.guides,
5671
+ formula: node.formula,
5672
+ isCollapsible: true,
5673
+ isExpanded: node.isExpanded,
5674
+ onToggle: handleToggle,
5675
+ collapsedLabel: node.collapsedLabel,
5676
+ isReadOnly: node.isEditorReadOnly,
5677
+ testId: node.testId
5678
+ }), node.isExpanded && /* @__PURE__ */ jsx(Row, {
5679
+ name: "",
5680
+ guides: [...node.guides, true],
5681
+ skipDot: true,
5682
+ skipField: true,
5683
+ children: /* @__PURE__ */ jsx(StringEditor, {
5684
+ value,
5685
+ setValue: handleSetValue,
5686
+ readonly: node.isFieldReadOnly,
5687
+ dataTestId: `${node.testId}-editor`
5688
+ })
5689
+ })] });
5690
+ return /* @__PURE__ */ jsx(Row, {
5691
+ node,
5692
+ name: node.displayName,
5693
+ guides: node.guides,
5694
+ formula: node.formula,
5695
+ isReadOnly: node.isEditorReadOnly,
5696
+ testId: node.testId,
5697
+ children: /* @__PURE__ */ jsx(StringEditor, {
5698
+ value,
5699
+ setValue: handleSetValue,
5700
+ readonly: node.isFieldReadOnly,
5701
+ dataTestId: `${node.testId}-editor`
5702
+ })
5703
+ });
5704
+ });
5705
+
5706
+ //#endregion
5707
+ //#region src/row-editor/ui/editors/NumberEditor.tsx
5708
+ const NUMERIC_CHARS = /^[\d.eE+-]+$/;
5709
+ const NumberEditor = ({ value, setValue, readonly, dataTestId }) => {
5710
+ const stringValue = value.toString();
5711
+ const lastValidValue = useRef(stringValue);
5712
+ const [state, setState] = useState(stringValue);
5713
+ useEffect(() => {
5714
+ setState(stringValue);
5715
+ lastValidValue.current = stringValue;
5716
+ }, [stringValue]);
5717
+ return /* @__PURE__ */ jsx(PrimitiveBox, {
5718
+ value: state,
5719
+ readonly,
5720
+ dataTestId,
5721
+ onChange: useCallback((newValue) => {
5722
+ setState(newValue);
5723
+ }, []),
5724
+ onBlur: useCallback(() => {
5725
+ const trimmed = state.trim();
5726
+ const parsedValue = Number(trimmed);
5727
+ if (trimmed !== "" && Number.isFinite(parsedValue)) {
5728
+ setValue(parsedValue);
5729
+ setState(parsedValue.toString());
5730
+ lastValidValue.current = parsedValue.toString();
5731
+ } else setState(lastValidValue.current);
5732
+ }, [setValue, state]),
5733
+ restrict: NUMERIC_CHARS
5734
+ });
5735
+ };
5736
+
5737
+ //#endregion
5738
+ //#region src/row-editor/ui/renderers/NumberRenderer.tsx
5739
+ const NumberRendererComponent = observer(({ node }) => {
5740
+ const handleSetValue = useCallback((value) => {
5741
+ node.setValue(value);
5742
+ }, [node]);
5743
+ return /* @__PURE__ */ jsx(Row, {
5744
+ node,
5745
+ name: node.displayName,
5746
+ guides: node.guides,
5747
+ formula: node.formula,
5748
+ isReadOnly: node.isEditorReadOnly,
5749
+ testId: node.testId,
5750
+ children: /* @__PURE__ */ jsx(NumberEditor, {
5751
+ value: Number(node.value),
5752
+ setValue: handleSetValue,
5753
+ readonly: node.isFieldReadOnly,
5754
+ dataTestId: `${node.testId}-editor`
5755
+ })
5756
+ });
5757
+ });
5758
+
5759
+ //#endregion
5760
+ //#region src/row-editor/ui/editors/FocusPopover.tsx
5761
+ const FocusPopover = ({ isOpen, setIsOpen, trigger, children, disabled, width }) => {
5762
+ const triggerRef = useRef(null);
5763
+ const lastRectRef = useRef(null);
5764
+ const getAnchorRect = useCallback(() => {
5765
+ const rect = triggerRef.current?.getBoundingClientRect();
5766
+ if (rect && rect.width > 0) lastRectRef.current = rect;
5767
+ return lastRectRef.current;
5768
+ }, []);
5769
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Box, {
5770
+ ref: triggerRef,
5771
+ onFocus: useCallback(() => {
5772
+ if (!disabled) setIsOpen(true);
5773
+ }, [disabled, setIsOpen]),
5774
+ children: trigger
5775
+ }), !disabled && /* @__PURE__ */ jsx(Popover.Root, {
5776
+ lazyMount: true,
5777
+ unmountOnExit: true,
5778
+ open: isOpen,
5779
+ onOpenChange: ({ open }) => setIsOpen(open),
5780
+ autoFocus: false,
5781
+ closeOnInteractOutside: true,
5782
+ modal: false,
5783
+ positioning: {
5784
+ placement: "bottom-start",
5785
+ getAnchorRect
5786
+ },
5787
+ children: /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, { children: /* @__PURE__ */ jsx(Popover.Content, {
5788
+ width,
5789
+ p: 1,
5790
+ children
5791
+ }) }) })
5792
+ })] });
5793
+ };
5794
+
5795
+ //#endregion
5796
+ //#region src/row-editor/ui/editors/FocusPopoverItem.tsx
5797
+ const FocusPopoverItem = ({ children, onClick }) => {
5798
+ return /* @__PURE__ */ jsx(Box, {
5799
+ px: 2,
5800
+ py: 1.5,
5801
+ cursor: "pointer",
5802
+ borderRadius: "md",
5803
+ fontSize: "sm",
5804
+ _hover: { bg: "gray.100" },
5805
+ onClick,
5806
+ children
5807
+ });
5808
+ };
5809
+
5810
+ //#endregion
5811
+ //#region src/row-editor/ui/editors/BooleanMenu.tsx
5812
+ const BooleanMenu = ({ children, onChange, disabled }) => {
5813
+ const [isOpen, setIsOpen] = useState(false);
5814
+ const handleSelect = useCallback((value) => {
5815
+ onChange(value === "true");
5816
+ setIsOpen(false);
5817
+ }, [onChange]);
5818
+ return /* @__PURE__ */ jsxs(FocusPopover, {
5819
+ width: "60px",
5820
+ isOpen,
5821
+ setIsOpen,
5822
+ trigger: children,
5823
+ disabled,
5824
+ children: [/* @__PURE__ */ jsx(FocusPopoverItem, {
5825
+ onClick: () => handleSelect("true"),
5826
+ children: "true"
5827
+ }), /* @__PURE__ */ jsx(FocusPopoverItem, {
5828
+ onClick: () => handleSelect("false"),
5829
+ children: "false"
5830
+ })]
5831
+ });
5832
+ };
5833
+
5834
+ //#endregion
5835
+ //#region src/row-editor/ui/editors/BooleanEditor.tsx
5836
+ const BooleanEditor = ({ value, setValue, readonly, dataTestId }) => {
5837
+ const stringValue = value.toString();
5838
+ const [state, setState] = useState(stringValue);
5839
+ useEffect(() => {
5840
+ setState(stringValue);
5841
+ }, [stringValue]);
5842
+ const handleChange = useCallback((value) => {
5843
+ setState(value);
5844
+ }, []);
5845
+ const handleBlur = useCallback(() => {
5846
+ const trimmed = state.trim();
5847
+ const boolValue = trimmed.toLowerCase() === "false" || trimmed === "0" ? false : Boolean(trimmed);
5848
+ setState(boolValue.toString());
5849
+ setValue(boolValue);
5850
+ }, [setValue, state]);
5851
+ return /* @__PURE__ */ jsx(BooleanMenu, {
5852
+ onChange: useCallback((boolValue) => {
5853
+ setState(boolValue.toString());
5854
+ setValue(boolValue);
5855
+ }, [setValue]),
5856
+ disabled: readonly,
5857
+ children: /* @__PURE__ */ jsx(PrimitiveBox, {
5858
+ value: state,
5859
+ readonly,
5860
+ dataTestId,
5861
+ onChange: handleChange,
5862
+ onBlur: handleBlur
5863
+ })
5864
+ });
5865
+ };
5866
+
5867
+ //#endregion
5868
+ //#region src/row-editor/ui/renderers/BooleanRenderer.tsx
5869
+ const BooleanRendererComponent = observer(({ node }) => {
5870
+ const handleSetValue = useCallback((value) => {
5871
+ node.setValue(value);
5872
+ }, [node]);
5873
+ return /* @__PURE__ */ jsx(Row, {
5874
+ node,
5875
+ name: node.displayName,
5876
+ guides: node.guides,
5877
+ formula: node.formula,
5878
+ isReadOnly: node.isEditorReadOnly,
5879
+ testId: node.testId,
5880
+ children: /* @__PURE__ */ jsx(BooleanEditor, {
5881
+ value: Boolean(node.value),
5882
+ setValue: handleSetValue,
5883
+ readonly: node.isFieldReadOnly,
5884
+ dataTestId: `${node.testId}-editor`
5885
+ })
5886
+ });
5887
+ });
5888
+
5889
+ //#endregion
5890
+ //#region src/row-editor/ui/editors/ForeignKeyActions.tsx
5891
+ const ForeignKeyActions = observer(({ node }) => {
5892
+ const value = String(node.value);
5893
+ const showNavigate = Boolean(value) && Boolean(node.callbacks?.onNavigateToForeignKey);
5894
+ const showWarning = !value && !node.isEditorReadOnly;
5895
+ const handleNavigate = useCallback(() => {
5896
+ node.callbacks?.onNavigateToForeignKey?.(node.foreignKeyTableId, value);
5897
+ }, [node, value]);
5898
+ return /* @__PURE__ */ jsxs(Flex, {
5899
+ alignItems: "center",
5900
+ gap: "4px",
5901
+ children: [showNavigate && /* @__PURE__ */ jsx(IconButton, {
5902
+ "aria-label": "Navigate to foreign key",
5903
+ variant: "ghost",
5904
+ size: "2xs",
5905
+ color: "gray.500",
5906
+ _hover: {
5907
+ color: "black",
5908
+ bg: "gray.100"
5909
+ },
5910
+ onClick: handleNavigate,
5911
+ "data-testid": `${node.testId}-fk-navigate`,
5912
+ children: /* @__PURE__ */ jsx(PiArrowSquareUpRightThin, {})
5913
+ }), showWarning && /* @__PURE__ */ jsx(Tooltip, {
5914
+ openDelay: 50,
5915
+ closeDelay: 50,
5916
+ content: "This field requires a valid foreign key ID",
5917
+ children: /* @__PURE__ */ jsx(Flex, {
5918
+ width: "24px",
5919
+ height: "24px",
5920
+ alignItems: "center",
5921
+ justifyContent: "center",
5922
+ color: "gray.400",
5923
+ children: /* @__PURE__ */ jsx(PiInfo, {})
5924
+ })
5925
+ })]
5926
+ });
5927
+ });
5928
+
5929
+ //#endregion
5930
+ //#region src/lib/Debounce.ts
5931
+ var Debounce = class {
5932
+ _timer = null;
5933
+ constructor(_delay) {
5934
+ this._delay = _delay;
5935
+ }
5936
+ schedule(fn) {
5937
+ if (this._timer) clearTimeout(this._timer);
5938
+ this._timer = setTimeout(fn, this._delay);
5939
+ }
5940
+ dispose() {
5941
+ if (this._timer) {
5942
+ clearTimeout(this._timer);
5943
+ this._timer = null;
5944
+ }
5945
+ }
5946
+ };
5947
+
5948
+ //#endregion
5949
+ //#region src/search-foreign-key/vm/SearchForeignKeyVM.ts
5950
+ var SearchForeignKeyVM = class {
5951
+ _search = "";
5952
+ _state = "loading";
5953
+ _ids = [];
5954
+ _hasMore = false;
5955
+ _initialized = false;
5956
+ _disposeReaction = null;
5957
+ _debounce = new Debounce(300);
5958
+ constructor(_tableId, _onSearch) {
5959
+ this._tableId = _tableId;
5960
+ this._onSearch = _onSearch;
5961
+ makeAutoObservable(this, {}, { autoBind: true });
5962
+ }
5963
+ get search() {
5964
+ return this._search;
5965
+ }
5966
+ get state() {
5967
+ return this._state;
5968
+ }
5969
+ get ids() {
5970
+ return this._ids;
5971
+ }
5972
+ get hasMore() {
5973
+ return this._hasMore;
5974
+ }
5975
+ get showInput() {
5976
+ return this._state === "list" || this._state === "notFound" || this._state === "loading" && this._initialized;
5977
+ }
5978
+ get showFooter() {
5979
+ return this._state === "list" || this._state === "notFound" || this._state === "error" || this._state === "empty";
5980
+ }
5981
+ get showLoading() {
5982
+ return this._state === "loading";
5983
+ }
5984
+ get showNotFound() {
5985
+ return this._state === "notFound";
5986
+ }
5987
+ get showError() {
5988
+ return this._state === "error";
5989
+ }
5990
+ get showEmpty() {
5991
+ return this._state === "empty";
5992
+ }
5993
+ get showList() {
5994
+ return this._state === "list";
5995
+ }
5996
+ get tableId() {
5997
+ return this._tableId;
5998
+ }
5999
+ init() {
6000
+ this._performSearch();
6001
+ this._disposeReaction = reaction(() => this._search, () => this._debouncedSearch());
6002
+ }
6003
+ setSearch(value) {
6004
+ this._search = value;
6005
+ }
6006
+ dispose() {
6007
+ this._disposeReaction?.();
6008
+ this._disposeReaction = null;
6009
+ this._debounce.dispose();
6010
+ }
6011
+ _debouncedSearch() {
6012
+ this._debounce.schedule(() => {
6013
+ this._performSearch();
6014
+ });
6015
+ }
6016
+ _resolveState(ids, search) {
6017
+ if (ids.length === 0 && !search) return "empty";
6018
+ if (ids.length === 0) return "notFound";
6019
+ return "list";
6020
+ }
6021
+ async _performSearch() {
6022
+ if (!this._onSearch) {
6023
+ this._state = "error";
6024
+ return;
6025
+ }
6026
+ const searchTerm = this._search;
6027
+ try {
6028
+ this._state = "loading";
6029
+ const result = await this._onSearch(this._tableId, searchTerm);
6030
+ runInAction(() => {
6031
+ if (this._search !== searchTerm) return;
6032
+ this._initialized = true;
6033
+ this._ids = result.ids;
6034
+ this._hasMore = result.hasMore;
6035
+ this._state = this._resolveState(result.ids, searchTerm);
6036
+ });
6037
+ } catch {
6038
+ runInAction(() => {
6039
+ if (this._search !== searchTerm) return;
6040
+ this._state = "error";
6041
+ });
6042
+ }
6043
+ }
6044
+ };
6045
+
6046
+ //#endregion
6047
+ //#region src/search-foreign-key/ui/Header.tsx
6048
+ const Header = ({ tableId, onClose }) => {
6049
+ return /* @__PURE__ */ jsxs(Flex, {
6050
+ p: "4px",
6051
+ alignItems: "center",
6052
+ justifyContent: "space-between",
6053
+ children: [/* @__PURE__ */ jsxs(Text, {
6054
+ fontSize: "xs",
6055
+ color: "gray.600",
6056
+ fontWeight: "medium",
6057
+ children: [
6058
+ "Select from \"",
6059
+ tableId,
6060
+ "\""
6061
+ ]
6062
+ }), onClose && /* @__PURE__ */ jsx(IconButton, {
6063
+ "aria-label": "Close",
6064
+ variant: "ghost",
6065
+ size: "2xs",
6066
+ color: "gray.500",
6067
+ _hover: { color: "black" },
6068
+ onClick: onClose,
6069
+ children: /* @__PURE__ */ jsx(PiXBold, {})
6070
+ })]
6071
+ });
6072
+ };
6073
+
6074
+ //#endregion
6075
+ //#region src/search-foreign-key/ui/SearchInput.tsx
6076
+ const SearchInput = ({ value, onChange }) => {
6077
+ const handleChange = useCallback((e) => {
6078
+ onChange(e.target.value);
6079
+ }, [onChange]);
6080
+ const handleClear = useCallback(() => {
6081
+ onChange("");
6082
+ }, [onChange]);
6083
+ return /* @__PURE__ */ jsxs(Box, {
6084
+ px: "4px",
6085
+ pb: "4px",
6086
+ position: "relative",
6087
+ children: [/* @__PURE__ */ jsx(Input, {
6088
+ value,
6089
+ onChange: handleChange,
6090
+ placeholder: "Search by ID...",
6091
+ size: "sm",
6092
+ "data-testid": "fk-search-input",
6093
+ autoFocus: true
6094
+ }), value && /* @__PURE__ */ jsx(IconButton, {
6095
+ "aria-label": "Clear",
6096
+ variant: "ghost",
6097
+ size: "2xs",
6098
+ position: "absolute",
6099
+ right: "8px",
6100
+ top: "50%",
6101
+ transform: "translateY(-50%)",
6102
+ onClick: handleClear,
6103
+ color: "gray.400",
6104
+ _hover: { color: "black" },
6105
+ children: /* @__PURE__ */ jsx(PiXBold, {})
6106
+ })]
6107
+ });
6108
+ };
6109
+
6110
+ //#endregion
6111
+ //#region src/search-foreign-key/ui/Item.tsx
6112
+ const Item = ({ id, onSelect }) => {
6113
+ return /* @__PURE__ */ jsx(Box, {
6114
+ px: 2,
6115
+ py: 1.5,
6116
+ mr: "12px",
6117
+ cursor: "pointer",
6118
+ borderRadius: "md",
6119
+ fontSize: "sm",
6120
+ _hover: { bg: "gray.100" },
6121
+ onClick: useCallback(() => {
6122
+ onSelect(id);
6123
+ }, [id, onSelect]),
6124
+ "data-testid": `fk-item-${id}`,
6125
+ children: id
6126
+ });
6127
+ };
6128
+
6129
+ //#endregion
6130
+ //#region src/search-foreign-key/ui/List.tsx
6131
+ const List = ({ ids, onSelect }) => {
6132
+ return /* @__PURE__ */ jsx(Box, {
6133
+ flex: 1,
6134
+ overflowY: "auto",
6135
+ "data-testid": "fk-list",
6136
+ children: ids.map((id) => /* @__PURE__ */ jsx(Item, {
6137
+ id,
6138
+ onSelect
6139
+ }, id))
6140
+ });
6141
+ };
6142
+
6143
+ //#endregion
6144
+ //#region src/search-foreign-key/ui/Empty.tsx
6145
+ const Empty = () => {
6146
+ return /* @__PURE__ */ jsx(Flex, {
6147
+ flex: 1,
6148
+ justifyContent: "center",
6149
+ alignItems: "center",
6150
+ "data-testid": "fk-empty",
6151
+ children: /* @__PURE__ */ jsx(Text, {
6152
+ fontSize: "sm",
6153
+ color: "gray.500",
6154
+ children: "No rows found in this table"
6155
+ })
6156
+ });
6157
+ };
6158
+
6159
+ //#endregion
6160
+ //#region src/search-foreign-key/ui/Footer.tsx
6161
+ const Footer = ({ onOpenTableSearch, onCreateAndConnect }) => {
6162
+ if (!(onOpenTableSearch || onCreateAndConnect)) return null;
6163
+ return /* @__PURE__ */ jsxs(HStack, {
6164
+ mt: "4px",
6165
+ p: "4px",
6166
+ gap: 2,
6167
+ borderTopWidth: "1px",
6168
+ borderColor: "gray.200",
6169
+ children: [onOpenTableSearch && /* @__PURE__ */ jsxs(Button, {
6170
+ size: "xs",
6171
+ variant: "ghost",
6172
+ color: "gray.500",
6173
+ onClick: onOpenTableSearch,
6174
+ "data-testid": "fk-open-table-search",
6175
+ children: [/* @__PURE__ */ jsx(PiMagnifyingGlassBold, {}), "Open Table Search"]
6176
+ }), onCreateAndConnect && /* @__PURE__ */ jsxs(Button, {
6177
+ size: "xs",
6178
+ variant: "ghost",
6179
+ color: "gray.500",
6180
+ onClick: onCreateAndConnect,
6181
+ "data-testid": "fk-create-and-connect",
6182
+ children: [/* @__PURE__ */ jsx(PiPlusBold, {}), "Create & Connect"]
6183
+ })]
6184
+ });
6185
+ };
6186
+
6187
+ //#endregion
6188
+ //#region src/search-foreign-key/ui/SearchForeignKey.tsx
6189
+ const SearchForeignKey = observer(({ tableId, onSearch, onSelect, onClose, onOpenTableSearch, onCreateAndConnect }) => {
6190
+ const [model] = useState(() => new SearchForeignKeyVM(tableId, onSearch));
6191
+ useEffect(() => {
6192
+ model.init();
6193
+ return () => model.dispose();
6194
+ }, [model]);
6195
+ return /* @__PURE__ */ jsxs(Flex, {
6196
+ flexDirection: "column",
6197
+ height: "290px",
6198
+ width: "100%",
6199
+ "data-testid": "fk-picker",
6200
+ children: [
6201
+ /* @__PURE__ */ jsx(Header, {
6202
+ tableId,
6203
+ onClose
6204
+ }),
6205
+ model.showInput && /* @__PURE__ */ jsx(SearchInput, {
6206
+ value: model.search,
6207
+ onChange: model.setSearch
6208
+ }),
6209
+ model.showLoading && /* @__PURE__ */ jsx(Flex, {
6210
+ flex: 1,
6211
+ justifyContent: "center",
6212
+ alignItems: "center",
6213
+ children: /* @__PURE__ */ jsx(Spinner, {
6214
+ size: "sm",
6215
+ color: "gray.400"
6216
+ })
6217
+ }),
6218
+ model.showNotFound && /* @__PURE__ */ jsx(Flex, {
6219
+ flex: 1,
6220
+ justifyContent: "center",
6221
+ alignItems: "center",
6222
+ children: /* @__PURE__ */ jsx(Text, {
6223
+ fontSize: "sm",
6224
+ color: "gray.500",
6225
+ children: "No results found"
6226
+ })
6227
+ }),
6228
+ model.showError && /* @__PURE__ */ jsx(Flex, {
6229
+ flex: 1,
6230
+ justifyContent: "center",
6231
+ alignItems: "center",
6232
+ children: /* @__PURE__ */ jsx(Text, {
6233
+ fontSize: "sm",
6234
+ color: "gray.500",
6235
+ children: "Could not load data"
6236
+ })
6237
+ }),
6238
+ model.showEmpty && /* @__PURE__ */ jsx(Empty, {}),
6239
+ model.showList && /* @__PURE__ */ jsx(List, {
6240
+ ids: model.ids,
6241
+ onSelect
6242
+ }),
6243
+ model.showFooter && /* @__PURE__ */ jsx(Footer, {
6244
+ onOpenTableSearch,
6245
+ onCreateAndConnect
6246
+ })
6247
+ ]
6248
+ });
6249
+ });
6250
+
6251
+ //#endregion
6252
+ //#region src/row-editor/ui/editors/ForeignKeyMenu.tsx
6253
+ const ForeignKeyMenu = ({ node, onSelect, disabled, children }) => {
6254
+ const [isOpen, setIsOpen] = useState(false);
6255
+ const onSearchForeignKey = node.callbacks?.onSearchForeignKey;
6256
+ const handleSelect = useCallback((id) => {
6257
+ onSelect(id);
6258
+ setIsOpen(false);
6259
+ }, [onSelect]);
6260
+ const handleClose = useCallback(() => {
6261
+ setIsOpen(false);
6262
+ }, []);
6263
+ const handleOpenTableSearch = useCallback(async () => {
6264
+ if (!node.callbacks?.onOpenTableSearch) return;
6265
+ const selectedId = await node.callbacks.onOpenTableSearch(node.foreignKeyTableId);
6266
+ if (selectedId) handleSelect(selectedId);
6267
+ }, [
6268
+ node.callbacks,
6269
+ node.foreignKeyTableId,
6270
+ handleSelect
6271
+ ]);
6272
+ const handleCreateAndConnect = useCallback(async () => {
6273
+ if (!node.callbacks?.onCreateAndConnect) return;
6274
+ const createdId = await node.callbacks.onCreateAndConnect(node.foreignKeyTableId);
6275
+ if (createdId) handleSelect(createdId);
6276
+ }, [
6277
+ node.callbacks,
6278
+ node.foreignKeyTableId,
6279
+ handleSelect
6280
+ ]);
6281
+ if (!onSearchForeignKey) return /* @__PURE__ */ jsx(Fragment$1, { children });
6282
+ return /* @__PURE__ */ jsx(FocusPopover, {
6283
+ isOpen,
6284
+ setIsOpen,
6285
+ trigger: children,
6286
+ disabled,
6287
+ width: "320px",
6288
+ children: /* @__PURE__ */ jsx(SearchForeignKey, {
6289
+ tableId: node.foreignKeyTableId,
6290
+ onSearch: onSearchForeignKey,
6291
+ onSelect: handleSelect,
6292
+ onClose: handleClose,
6293
+ onOpenTableSearch: node.callbacks?.onOpenTableSearch ? handleOpenTableSearch : void 0,
6294
+ onCreateAndConnect: node.callbacks?.onCreateAndConnect ? handleCreateAndConnect : void 0
6295
+ })
6296
+ });
6297
+ };
6298
+
6299
+ //#endregion
6300
+ //#region src/row-editor/ui/renderers/ForeignKeyRenderer.tsx
6301
+ const ForeignKeyRendererComponent = observer(({ node }) => {
6302
+ const value = String(node.value);
6303
+ const handleSetValue = useCallback((newValue) => {
6304
+ node.setValue(newValue);
6305
+ }, [node]);
6306
+ const handleSelect = useCallback((id) => {
6307
+ node.setValue(id);
6308
+ }, [node]);
6309
+ return /* @__PURE__ */ jsx(Row, {
6310
+ node,
6311
+ name: node.displayName,
6312
+ guides: node.guides,
6313
+ formula: node.formula,
6314
+ isReadOnly: node.isEditorReadOnly,
6315
+ testId: node.testId,
6316
+ children: /* @__PURE__ */ jsxs(Flex, {
6317
+ alignItems: "center",
6318
+ gap: "2px",
6319
+ children: [/* @__PURE__ */ jsx(ForeignKeyMenu, {
6320
+ node,
6321
+ onSelect: handleSelect,
6322
+ disabled: node.isFieldReadOnly,
6323
+ children: /* @__PURE__ */ jsx(StringEditor, {
6324
+ value,
6325
+ setValue: handleSetValue,
6326
+ readonly: node.isFieldReadOnly,
6327
+ dataTestId: `${node.testId}-editor`
6328
+ })
6329
+ }), /* @__PURE__ */ jsx(ForeignKeyActions, { node })]
6330
+ })
6331
+ });
6332
+ });
6333
+
6334
+ //#endregion
6335
+ //#region src/row-editor/ui/editors/FileHoverCard.tsx
6336
+ const FileIcon = ({ onClick, dataTestId }) => {
6337
+ return /* @__PURE__ */ jsx(IconButton, {
6338
+ "data-testid": dataTestId,
6339
+ "aria-label": "Open file",
6340
+ variant: "ghost",
6341
+ size: "2xs",
6342
+ color: "gray.400",
6343
+ _hover: {
6344
+ bg: "gray.100",
6345
+ color: "black"
6346
+ },
6347
+ onClick,
6348
+ children: /* @__PURE__ */ jsx(PiFile, {})
6349
+ });
6350
+ };
6351
+ const FileHoverCard = ({ url, availablePreview, width, height, onClick, dataTestId }) => {
6352
+ if (!availablePreview) return /* @__PURE__ */ jsx(FileIcon, {
6353
+ onClick,
6354
+ dataTestId
6355
+ });
6356
+ return /* @__PURE__ */ jsxs(HoverCard.Root, {
6357
+ lazyMount: true,
6358
+ unmountOnExit: true,
6359
+ openDelay: 350,
6360
+ closeDelay: 100,
6361
+ positioning: { gutter: 16 },
6362
+ children: [/* @__PURE__ */ jsx(HoverCard.Trigger, {
6363
+ asChild: true,
6364
+ children: /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(FileIcon, {
6365
+ onClick,
6366
+ dataTestId
6367
+ }) })
6368
+ }), /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(HoverCard.Positioner, { children: /* @__PURE__ */ jsxs(HoverCard.Content, { children: [/* @__PURE__ */ jsx(HoverCard.Arrow, { children: /* @__PURE__ */ jsx(HoverCard.ArrowTip, {}) }), /* @__PURE__ */ jsx(Image, {
6369
+ aspectRatio: height > 0 ? width / height : 1,
6370
+ width: "400px",
6371
+ src: url,
6372
+ alt: "File preview"
6373
+ })] }) }) })]
6374
+ });
6375
+ };
6376
+
6377
+ //#endregion
6378
+ //#region src/row-editor/ui/editors/FileActions.tsx
6379
+ const FileActions = observer(({ node }) => {
6380
+ const fileInputRef = useRef(null);
6381
+ const url = node.fileUrl;
6382
+ const fileId = node.fileId;
6383
+ const status = node.fileStatus;
6384
+ const mimeType = node.fileMimeType;
6385
+ const width = node.fileWidth;
6386
+ const height = node.fileHeight;
6387
+ const readonly = node.isEditorReadOnly;
6388
+ const availablePreview = mimeType.startsWith("image/");
6389
+ const showViewFile = Boolean(url);
6390
+ const showUploadFile = !readonly && Boolean(node.callbacks?.onUploadFile) && (status === "ready" || status === "uploaded");
6391
+ const showInfo = !showViewFile && !showUploadFile;
6392
+ const handleFileChange = useCallback(async (event) => {
6393
+ const file = event.target.files?.[0];
6394
+ if (!file) return;
6395
+ event.target.value = "";
6396
+ await node.callbacks?.onUploadFile?.(fileId, file);
6397
+ }, [node, fileId]);
6398
+ const handleOpenFile = useCallback(() => {
6399
+ if (node.callbacks?.onOpenFile) node.callbacks.onOpenFile(url);
6400
+ else window.open(url, "_blank", "noopener,noreferrer");
6401
+ }, [node, url]);
6402
+ const handleUploadClick = useCallback(() => {
6403
+ fileInputRef.current?.click();
6404
+ }, []);
6405
+ return /* @__PURE__ */ jsxs(Flex, {
6406
+ alignItems: "center",
6407
+ children: [
6408
+ showInfo && /* @__PURE__ */ jsx(Tooltip, {
6409
+ openDelay: 50,
6410
+ closeDelay: 50,
6411
+ content: readonly ? "The file was not uploaded in this revision" : "Save the row first, then upload the file",
6412
+ children: /* @__PURE__ */ jsx(Flex, {
6413
+ width: "24px",
6414
+ height: "24px",
6415
+ alignItems: "center",
6416
+ justifyContent: "center",
6417
+ color: "gray.400",
6418
+ children: /* @__PURE__ */ jsx(PiInfo, {})
6419
+ })
6420
+ }),
6421
+ showViewFile && /* @__PURE__ */ jsx(FileHoverCard, {
6422
+ url,
6423
+ availablePreview,
6424
+ width,
6425
+ height,
6426
+ onClick: handleOpenFile,
6427
+ dataTestId: `${node.testId}-open-file`
6428
+ }),
6429
+ showUploadFile && /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx("input", {
6430
+ ref: fileInputRef,
6431
+ type: "file",
6432
+ onChange: handleFileChange,
6433
+ style: { display: "none" },
6434
+ "data-testid": `${node.testId}-file-input`
6435
+ }), /* @__PURE__ */ jsx(IconButton, {
6436
+ "aria-label": "Upload file",
6437
+ variant: "ghost",
6438
+ size: "2xs",
6439
+ color: showViewFile ? "gray.300" : "gray.500",
6440
+ _hover: {
6441
+ bg: "gray.100",
6442
+ color: "black"
6443
+ },
6444
+ onClick: handleUploadClick,
6445
+ "data-testid": `${node.testId}-upload-file`,
6446
+ children: /* @__PURE__ */ jsx(PiUploadThin, {})
6447
+ })] })
6448
+ ]
6449
+ });
6450
+ });
6451
+
6452
+ //#endregion
6453
+ //#region src/row-editor/ui/renderers/FileRenderer.tsx
6454
+ const FileRendererComponent = observer(({ node }) => {
6455
+ const handleToggle = useCallback(() => {
6456
+ node.toggleExpanded();
6457
+ }, [node]);
6458
+ return /* @__PURE__ */ jsx(Row, {
6459
+ node,
6460
+ name: node.displayName,
6461
+ guides: node.guides,
6462
+ isCollapsible: node.isCollapsible,
6463
+ isExpanded: node.isExpanded,
6464
+ onToggle: handleToggle,
6465
+ collapsedLabel: node.collapsedLabel,
6466
+ isReadOnly: node.isEditorReadOnly,
6467
+ testId: node.testId,
6468
+ skipMore: true,
6469
+ children: /* @__PURE__ */ jsx(FileActions, { node })
6470
+ });
6471
+ });
6472
+
6473
+ //#endregion
6474
+ //#region src/row-editor/ui/renderers/NodeRenderers.ts
6475
+ const NODE_RENDERERS = {
6476
+ container: ContainerRendererComponent,
6477
+ string: StringRendererComponent,
6478
+ number: NumberRendererComponent,
6479
+ boolean: BooleanRendererComponent,
6480
+ foreignKey: ForeignKeyRendererComponent,
6481
+ file: FileRendererComponent
6482
+ };
6483
+
6484
+ //#endregion
6485
+ //#region src/row-editor/ui/RowEditor/FlatItemView.tsx
6486
+ const FlatItemView = observer(({ item }) => {
6487
+ if (item.type === "node") {
6488
+ const Renderer = NODE_RENDERERS[item.node.rendererType];
6489
+ return /* @__PURE__ */ jsx(Renderer, { node: item.node });
6490
+ }
6491
+ const handleAddItem = () => {
6492
+ item.array.pushValue(null);
6493
+ };
6494
+ return /* @__PURE__ */ jsx(Row, {
6495
+ name: "",
6496
+ guides: item.guides,
6497
+ skipDot: true,
6498
+ skipField: true,
6499
+ skipMore: true,
6500
+ children: /* @__PURE__ */ jsx(CreateButton, {
6501
+ title: "Item",
6502
+ onClick: handleAddItem,
6503
+ dataTestId: `${item.array.testId}-add-button`
6504
+ })
6505
+ });
6506
+ });
6507
+
6508
+ //#endregion
6509
+ //#region src/row-editor/ui/RowEditor/RowEditor.tsx
6510
+ const RowEditor = observer(({ viewModel }) => {
6511
+ const itemContent = useCallback((_index, item) => /* @__PURE__ */ jsx(FlatItemView, { item }), []);
6512
+ return /* @__PURE__ */ jsx(Virtuoso, {
6513
+ data: viewModel.flattenedNodes,
6514
+ itemContent,
6515
+ useWindowScroll: true,
6516
+ style: {
6517
+ width: "100%",
6518
+ height: "100%"
6519
+ }
6520
+ });
6521
+ });
6522
+
6523
+ //#endregion
6524
+ //#region src/row-editor/ui/NodeView/NodeView.tsx
6525
+ const NodeView = observer(({ viewModel }) => {
6526
+ const Renderer = NODE_RENDERERS[viewModel.rendererType];
6527
+ const { showChildren, childNodes } = viewModel;
6528
+ const showAddButton = viewModel.isArray() && viewModel.showAddButton;
6529
+ const handleAddItem = useCallback(() => {
6530
+ if (viewModel.isArray()) viewModel.pushValue(null);
6531
+ }, [viewModel]);
6532
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
6533
+ /* @__PURE__ */ jsx(Renderer, { node: viewModel }),
6534
+ showChildren && /* @__PURE__ */ jsx(VStack, {
6535
+ align: "stretch",
6536
+ gap: 0,
6537
+ children: childNodes.map((child) => /* @__PURE__ */ jsx(NodeView, { viewModel: child }, child.id))
6538
+ }),
6539
+ showAddButton && /* @__PURE__ */ jsx(Row, {
6540
+ name: "",
6541
+ guides: [...viewModel.guides, false],
6542
+ skipDot: true,
6543
+ skipField: true,
6544
+ skipMore: true,
6545
+ children: /* @__PURE__ */ jsx(CreateButton, {
6546
+ title: "Item",
6547
+ onClick: handleAddItem,
6548
+ dataTestId: `${viewModel.testId}-add-button`
6549
+ })
6550
+ })
6551
+ ] });
6552
+ });
6553
+
6554
+ //#endregion
6555
+ export { BackButton, CloseButton, ContentEditable, CopyButton, CreateButton, CreatingEditorVM, CreatingSchemaEditor, GrayButton, JsonCard, RowEditor, RowEditorVM, SchemaEditorCore, SchemaTypeIds, SearchForeignKey, SearchForeignKeyVM, SettingsButton, Tooltip, UpdatingEditorVM, UpdatingSchemaEditor, ViewerSwitcher, ViewerSwitcherMode, ensureReactivityProvider, getLabelByRef, typeMenuGroups, useContentEditable };
4589
6556
  //# sourceMappingURL=index.mjs.map