@signalsafe/tree-spec-editor 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +186 -59
  3. package/dist/index.d.ts +10 -2
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +5 -1
  6. package/dist/lib/PanelHeaderCollapseCarets.d.ts +1 -1
  7. package/dist/lib/PanelHeaderCollapseCarets.d.ts.map +1 -1
  8. package/dist/lib/buildDefaultToolbarSpec.d.ts +3 -79
  9. package/dist/lib/buildDefaultToolbarSpec.d.ts.map +1 -1
  10. package/dist/lib/buildDefaultToolbarSpec.js +9 -155
  11. package/dist/lib/panelNodeLink.d.ts +13 -0
  12. package/dist/lib/panelNodeLink.d.ts.map +1 -0
  13. package/dist/lib/panelNodeLink.js +12 -0
  14. package/dist/lib/selectionStyles.d.ts +9 -0
  15. package/dist/lib/selectionStyles.d.ts.map +1 -0
  16. package/dist/lib/selectionStyles.js +8 -0
  17. package/dist/lib/toolbar/defaultToolbarTypes.d.ts +89 -0
  18. package/dist/lib/toolbar/defaultToolbarTypes.d.ts.map +1 -0
  19. package/dist/lib/toolbar/defaultToolbarTypes.js +1 -0
  20. package/dist/lib/toolbar/toolbarSectionBuilders.d.ts +10 -0
  21. package/dist/lib/toolbar/toolbarSectionBuilders.d.ts.map +1 -0
  22. package/dist/lib/toolbar/toolbarSectionBuilders.js +153 -0
  23. package/dist/modals/AuditLogModal.d.ts +1 -1
  24. package/dist/modals/AuditLogModal.d.ts.map +1 -1
  25. package/dist/modals/AuditLogModal.js +1 -1
  26. package/dist/modals/DraftHistoryModal.d.ts +1 -1
  27. package/dist/modals/DraftHistoryModal.d.ts.map +1 -1
  28. package/dist/modals/DraftHistoryModal.js +1 -1
  29. package/dist/modals/PublishReviewModal.d.ts +1 -1
  30. package/dist/modals/PublishReviewModal.d.ts.map +1 -1
  31. package/dist/panels/AdvancedJsonPanel.d.ts +1 -1
  32. package/dist/panels/AdvancedJsonPanel.d.ts.map +1 -1
  33. package/dist/panels/AppearancePanel.d.ts +26 -0
  34. package/dist/panels/AppearancePanel.d.ts.map +1 -0
  35. package/dist/panels/AppearancePanel.js +76 -0
  36. package/dist/panels/ChoiceEdgeAppearanceFields.d.ts +10 -0
  37. package/dist/panels/ChoiceEdgeAppearanceFields.d.ts.map +1 -0
  38. package/dist/panels/ChoiceEdgeAppearanceFields.js +13 -0
  39. package/dist/panels/ChoiceTemplatesPanel.d.ts +27 -0
  40. package/dist/panels/ChoiceTemplatesPanel.d.ts.map +1 -0
  41. package/dist/panels/ChoiceTemplatesPanel.js +9 -0
  42. package/dist/panels/GraphEditorInfoPanel.d.ts +5 -2
  43. package/dist/panels/GraphEditorInfoPanel.d.ts.map +1 -1
  44. package/dist/panels/GraphEditorInfoPanel.js +6 -6
  45. package/dist/panels/InspectorPanel.d.ts +3 -78
  46. package/dist/panels/InspectorPanel.d.ts.map +1 -1
  47. package/dist/panels/InspectorPanel.js +20 -60
  48. package/dist/panels/IssuesPanel.d.ts +6 -2
  49. package/dist/panels/IssuesPanel.d.ts.map +1 -1
  50. package/dist/panels/IssuesPanel.js +15 -3
  51. package/dist/panels/NodesPanel.d.ts +3 -1
  52. package/dist/panels/NodesPanel.d.ts.map +1 -1
  53. package/dist/panels/NodesPanel.js +12 -6
  54. package/dist/panels/SelectedEdgePanel.d.ts +10 -3
  55. package/dist/panels/SelectedEdgePanel.d.ts.map +1 -1
  56. package/dist/panels/SelectedEdgePanel.js +5 -6
  57. package/dist/panels/ToolbarPanel.d.ts +1 -1
  58. package/dist/panels/ToolbarPanel.d.ts.map +1 -1
  59. package/dist/panels/ToolbarPanel.js +2 -4
  60. package/dist/panels/inspector/ChoiceEditorCard.d.ts +28 -0
  61. package/dist/panels/inspector/ChoiceEditorCard.d.ts.map +1 -0
  62. package/dist/panels/inspector/ChoiceEditorCard.js +36 -0
  63. package/dist/panels/inspector/ChoiceEditorList.d.ts +25 -0
  64. package/dist/panels/inspector/ChoiceEditorList.d.ts.map +1 -0
  65. package/dist/panels/inspector/ChoiceEditorList.js +10 -0
  66. package/dist/panels/inspector/NodeTypeField.d.ts +8 -0
  67. package/dist/panels/inspector/NodeTypeField.d.ts.map +1 -0
  68. package/dist/panels/inspector/NodeTypeField.js +12 -0
  69. package/dist/panels/inspector/RequiredNodeCard.d.ts +14 -0
  70. package/dist/panels/inspector/RequiredNodeCard.d.ts.map +1 -0
  71. package/dist/panels/inspector/RequiredNodeCard.js +16 -0
  72. package/dist/panels/inspector/choiceActionIconProps.d.ts +12 -0
  73. package/dist/panels/inspector/choiceActionIconProps.d.ts.map +1 -0
  74. package/dist/panels/inspector/choiceActionIconProps.js +26 -0
  75. package/dist/panels/inspector/types.d.ts +77 -0
  76. package/dist/panels/inspector/types.d.ts.map +1 -0
  77. package/dist/panels/inspector/types.js +11 -0
  78. package/package.json +83 -65
@@ -1 +1 @@
1
- {"version":3,"file":"SelectedEdgePanel.d.ts","sourceRoot":"","sources":["../../src/panels/SelectedEdgePanel.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,MAAM,WAAW,sBAAsB;IACnC,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACtC,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,SAAS,CAAC;CACzD;AAUD,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EACtC,YAAY,EACZ,KAAuB,EACvB,aAAoC,GACvC,EAAE,QAAQ,CAAC,sBAAsB,CAAC,kDAWlC"}
1
+ {"version":3,"file":"SelectedEdgePanel.d.ts","sourceRoot":"","sources":["../../src/panels/SelectedEdgePanel.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,OAAO,EAA+B,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE9F,MAAM,MAAM,0BAA0B,GAAG,oBAAoB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,WAAW,sBAAsB;IACnC,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACtC,wEAAwE;IACxE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE,0BAA0B,KAAK,SAAS,CAAC;CAC1F;AAED,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EACtC,YAAY,EACZ,YAAY,EACZ,KAAuB,EACvB,aAA2C,GAC9C,EAAE,QAAQ,CAAC,sBAAsB,CAAC,sCAalC"}
@@ -1,9 +1,8 @@
1
- import { Fragment as _Fragment, jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- function defaultRenderDetails(edge) {
3
- return (_jsxs(_Fragment, { children: [edge.fromNodeId, " \u00B7 ", edge.fromChoiceId, " \u2192 ", edge.toNodeId] }));
4
- }
5
- export default function SelectedEdgePanel({ selectedEdge, title = 'Selected Edge', renderDetails = defaultRenderDetails, }) {
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { renderDefaultEdgeBreadcrumb } from '../lib/panelNodeLink';
3
+ export { PanelNodeLink } from '../lib/panelNodeLink';
4
+ export default function SelectedEdgePanel({ selectedEdge, onNodeSelect, title = 'Selected Edge', renderDetails = renderDefaultEdgeBreadcrumb, }) {
6
5
  if (!selectedEdge)
7
6
  return null;
8
- return (_jsx("div", { className: "card mt-3", children: _jsxs("div", { className: "card-body", children: [_jsx("div", { className: "fw-bold", children: title }), _jsx("div", { className: "text-muted font-size-12", children: renderDetails(selectedEdge) })] }) }));
7
+ return (_jsx("div", { className: "card mt-3", children: _jsxs("div", { className: "card-body", children: [_jsx("div", { className: "fw-bold", children: title }), _jsx("div", { className: "text-muted font-size-12", children: renderDetails(selectedEdge, { onNodeSelect }) })] }) }));
9
8
  }
@@ -84,5 +84,5 @@ export interface ToolbarPanelProps {
84
84
  /** Override the outer wrapper className. Default: `"d-flex gap-2 align-items-center flex-wrap"`. */
85
85
  className?: string;
86
86
  }
87
- export default function ToolbarPanel({ items, className, }: Readonly<ToolbarPanelProps>): import("react/jsx-runtime").JSX.Element;
87
+ export default function ToolbarPanel({ items, className, }: Readonly<ToolbarPanelProps>): import("react").JSX.Element;
88
88
  //# sourceMappingURL=ToolbarPanel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToolbarPanel.d.ts","sourceRoot":"","sources":["../../src/panels/ToolbarPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGjD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;;;CAMpB,CAAC;AAEX,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC;AAEzF,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,OAAO,iBAAiB,CAAC,MAAM,CAAC;IACtC,+EAA+E;IAC/E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,iDAAiD;AACjD,MAAM,WAAW,oBAAoB;IACjC,+EAA+E;IAC/E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,OAAO,iBAAiB,CAAC,QAAQ,CAAC;IACxC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,OAAO,iBAAiB,CAAC,KAAK,CAAC;IACrC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,yFAAyF;IACzF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,OAAO,iBAAiB,CAAC,IAAI,CAAC;IACpC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,SAAS,CAAC;IACnB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,OAAO,iBAAiB,CAAC,MAAM,CAAC;IACtC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,oFAAoF;IACpF,MAAM,EAAE,MAAM,SAAS,CAAC;CAC3B;AAED,MAAM,MAAM,WAAW,GACjB,iBAAiB,GACjB,mBAAmB,GACnB,gBAAgB,GAChB,eAAe,GACf,iBAAiB,CAAC;AAExB,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,oGAAoG;IACpG,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAyED,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACjC,KAAK,EACL,SAAiC,GACpC,EAAE,QAAQ,CAAC,iBAAiB,CAAC,2CAQ7B"}
1
+ {"version":3,"file":"ToolbarPanel.d.ts","sourceRoot":"","sources":["../../src/panels/ToolbarPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGjD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;;;CAMpB,CAAC;AAEX,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC;AAEzF,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,OAAO,iBAAiB,CAAC,MAAM,CAAC;IACtC,+EAA+E;IAC/E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,iDAAiD;AACjD,MAAM,WAAW,oBAAoB;IACjC,+EAA+E;IAC/E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,OAAO,iBAAiB,CAAC,QAAQ,CAAC;IACxC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,OAAO,iBAAiB,CAAC,KAAK,CAAC;IACrC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,yFAAyF;IACzF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,OAAO,iBAAiB,CAAC,IAAI,CAAC;IACpC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,SAAS,CAAC;IACnB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,OAAO,iBAAiB,CAAC,MAAM,CAAC;IACtC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,oFAAoF;IACpF,MAAM,EAAE,MAAM,SAAS,CAAC;CAC3B;AAED,MAAM,MAAM,WAAW,GACjB,iBAAiB,GACjB,mBAAmB,GACnB,gBAAgB,GAChB,eAAe,GACf,iBAAiB,CAAC;AAExB,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,oGAAoG;IACpG,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAuED,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACjC,KAAK,EACL,SAAiC,GACpC,EAAE,QAAQ,CAAC,iBAAiB,CAAC,+BAQ7B"}
@@ -48,10 +48,8 @@ function renderItem(item) {
48
48
  return (_jsx("span", { className: item.className ?? DEFAULT_TEXT_CLASS, children: item.content }));
49
49
  case TOOLBAR_ITEM_KIND.CUSTOM:
50
50
  return item.render();
51
- default: {
52
- const exhaustive = item;
53
- return exhaustive;
54
- }
51
+ default:
52
+ return null;
55
53
  }
56
54
  }
57
55
  export default function ToolbarPanel({ items, className = DEFAULT_WRAPPER_CLASS, }) {
@@ -0,0 +1,28 @@
1
+ import type { ReactNode } from 'react';
2
+ import { type EditorChoice, type EditorNode, type EditorTree } from '@signalsafe/tree-spec-editor-core';
3
+ import type { ChoiceTypeOption, InspectorChoiceRenderContext } from './types';
4
+ export default function ChoiceEditorCard({ choice, tree, selectedNode, focusChoiceId, isPublished, canMoveUp, canMoveDown, usedChoiceTypeIds, onUpdateSelectedNode, onDeleteChoice, onMoveChoice, onSetChoiceTarget, onSetChoiceOutcome, onSetChoiceType, choiceTypes, outcomeOptions, hideOutcomeField, renderExtraChoiceFields, onFocusChoice, }: Readonly<{
5
+ choice: EditorChoice;
6
+ tree: EditorTree;
7
+ selectedNode: EditorNode;
8
+ focusChoiceId: string | null;
9
+ isPublished: boolean;
10
+ canMoveUp: boolean;
11
+ canMoveDown: boolean;
12
+ usedChoiceTypeIds: Set<string>;
13
+ onUpdateSelectedNode: (patch: Partial<EditorNode>) => void;
14
+ onDeleteChoice: (choiceId: string) => void;
15
+ onMoveChoice?: (choiceId: string, direction: 'up' | 'down') => void;
16
+ onSetChoiceTarget: (choiceId: string, targetNodeId: string) => void;
17
+ onSetChoiceOutcome: (choiceId: string, outcome: string) => void;
18
+ onSetChoiceType?: (choiceId: string, typeId: string, defaultLabel?: string) => void;
19
+ choiceTypes?: ReadonlyArray<ChoiceTypeOption>;
20
+ outcomeOptions: ReadonlyArray<{
21
+ value: string;
22
+ label: string;
23
+ }>;
24
+ hideOutcomeField: boolean;
25
+ renderExtraChoiceFields?: (ctx: InspectorChoiceRenderContext) => ReactNode;
26
+ onFocusChoice?: (choiceId: string) => void;
27
+ }>): import("react").JSX.Element;
28
+ //# sourceMappingURL=ChoiceEditorCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChoiceEditorCard.d.ts","sourceRoot":"","sources":["../../../src/panels/inspector/ChoiceEditorCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,SAAS,EAAE,MAAM,OAAO,CAAC;AAGpD,OAAO,EAGH,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,UAAU,EAClB,MAAM,mCAAmC,CAAC;AAI3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,SAAS,CAAC;AAE9E,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACrC,MAAM,EACN,IAAI,EACJ,YAAY,EACZ,aAAa,EACb,WAAW,EACX,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,uBAAuB,EACvB,aAAa,GAChB,EAAE,QAAQ,CAAC;IACR,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,YAAY,EAAE,UAAU,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,oBAAoB,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IAC3D,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;IACpE,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACpE,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACpF,WAAW,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC9C,cAAc,EAAE,aAAa,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChE,gBAAgB,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,CAAC,GAAG,EAAE,4BAA4B,KAAK,SAAS,CAAC;IAC3E,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C,CAAC,+BAsJD"}
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Form } from 'react-bootstrap';
3
+ import { END_NODE_ID, getTransition, } from '@signalsafe/tree-spec-editor-core';
4
+ import { LIST_SELECTION_CLASS, LIST_SELECTION_TEXT_CLASS } from '../../lib/selectionStyles';
5
+ import { choiceActionIconProps } from './choiceActionIconProps';
6
+ export default function ChoiceEditorCard({ choice, tree, selectedNode, focusChoiceId, isPublished, canMoveUp, canMoveDown, usedChoiceTypeIds, onUpdateSelectedNode, onDeleteChoice, onMoveChoice, onSetChoiceTarget, onSetChoiceOutcome, onSetChoiceType, choiceTypes, outcomeOptions, hideOutcomeField, renderExtraChoiceFields, onFocusChoice, }) {
7
+ const transition = getTransition(tree, selectedNode.id, choice.id);
8
+ const targetNodeId = transition?.toNodeId ?? '';
9
+ const outcomeValue = transition?.outcome ?? outcomeOptions[0]?.value ?? '';
10
+ const isFocused = focusChoiceId === choice.id;
11
+ const showOutcome = !hideOutcomeField && targetNodeId === END_NODE_ID;
12
+ const knownTypeIds = new Set((choiceTypes ?? []).map((type) => type.id));
13
+ const showTypeSelect = Boolean(choiceTypes?.length && onSetChoiceType);
14
+ const isCustomType = showTypeSelect && !knownTypeIds.has(choice.id);
15
+ return (_jsxs("div", { id: `choice-editor-${selectedNode.id}-${choice.id}`, className: `list-group-item py-3 px-3${isFocused ? ` ${LIST_SELECTION_CLASS} ${LIST_SELECTION_TEXT_CLASS}` : ''}`, onFocusCapture: () => onFocusChoice?.(choice.id), children: [_jsxs("div", { className: "d-flex w-100 justify-content-between align-items-end gap-2 mb-2", children: [_jsxs("div", { className: "d-flex flex-grow-1 min-w-0 gap-2", children: [showTypeSelect ? (_jsxs(Form.Group, { className: "mb-0 flex-fill min-w-0", children: [_jsx(Form.Label, { className: "mb-1", children: "Type" }), _jsxs(Form.Select, { value: isCustomType ? '__custom__' : choice.id, disabled: isPublished, "aria-label": `Choice type for ${choice.id}`, onChange: (event) => {
16
+ const nextTypeId = event.target.value;
17
+ if (nextTypeId && nextTypeId !== '__custom__') {
18
+ const type = choiceTypes.find((item) => item.id === nextTypeId);
19
+ onSetChoiceType(choice.id, nextTypeId, type?.label);
20
+ }
21
+ }, children: [choiceTypes.map((type) => (_jsx("option", { value: type.id, disabled: type.id !== choice.id && usedChoiceTypeIds.has(type.id), title: type.label, children: type.id }, type.id))), isCustomType ? (_jsxs("option", { value: "__custom__", children: [choice.id, " (custom)"] })) : null] })] })) : (_jsxs(Form.Group, { className: "mb-0 flex-fill min-w-0", children: [_jsx(Form.Label, { className: "mb-1", children: "Type" }), _jsx(Form.Control, { plaintext: true, readOnly: true, className: "text-uppercase fw-semibold", value: choice.id })] })), hideOutcomeField ? null : (_jsxs(Form.Group, { className: "mb-0 flex-fill min-w-0", children: [_jsx(Form.Label, { className: "mb-1", children: "Outcome" }), showOutcome ? (_jsx(Form.Select, { value: outcomeValue, disabled: isPublished, "aria-label": `Outcome for ${choice.id}`, onChange: (e) => onSetChoiceOutcome(choice.id, e.target.value), children: outcomeOptions.map((opt) => (_jsx("option", { value: opt.value, children: opt.label }, opt.value))) })) : (_jsx(Form.Select, { disabled: true, "aria-label": `Outcome for ${choice.id}`, value: "", children: _jsx("option", { value: "", children: "When Next is END" }) }))] }))] }), _jsxs("div", { className: "d-flex align-items-center gap-2 flex-shrink-0", children: [onMoveChoice ? (_jsxs(_Fragment, { children: [_jsx("i", { ...choiceActionIconProps(() => onMoveChoice(choice.id, 'up'), 'Move choice up', 'bi bi-chevron-up text-secondary', isPublished || !canMoveUp) }), _jsx("i", { ...choiceActionIconProps(() => onMoveChoice(choice.id, 'down'), 'Move choice down', 'bi bi-chevron-down text-secondary', isPublished || !canMoveDown) })] })) : null, _jsx("i", { ...choiceActionIconProps(() => onDeleteChoice(choice.id), 'Delete choice', 'bi bi-trash text-danger') })] })] }), _jsx(Form.Label, { className: "mt-0", children: "Label" }), _jsx(Form.Control, { value: choice.label, onChange: (event) => {
22
+ const updatedChoices = (selectedNode.choices ?? []).map((existingChoice) => existingChoice.id === choice.id
23
+ ? { ...existingChoice, label: event.target.value }
24
+ : existingChoice);
25
+ onUpdateSelectedNode({ choices: updatedChoices });
26
+ } }), _jsx(Form.Label, { className: "mt-2", children: "Next" }), _jsxs(Form.Select, { value: targetNodeId, onChange: (e) => onSetChoiceTarget(choice.id, e.target.value), children: [_jsx("option", { value: "", children: "(not connected)" }), Object.values(tree.nodes).map((n) => (_jsxs("option", { value: n.id, children: [n.id, " \u00B7 ", n.prompt?.slice(0, 40) || n.type] }, n.id))), _jsx("option", { value: END_NODE_ID, children: "END" })] }), renderExtraChoiceFields
27
+ ? renderExtraChoiceFields({
28
+ tree,
29
+ node: selectedNode,
30
+ choice,
31
+ transition,
32
+ isPublished,
33
+ onUpdateNode: onUpdateSelectedNode,
34
+ })
35
+ : null] }));
36
+ }
@@ -0,0 +1,25 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { EditorNode, EditorTree } from '@signalsafe/tree-spec-editor-core';
3
+ import type { ChoiceTypeOption, InspectorChoiceRenderContext } from './types';
4
+ export default function ChoiceEditorList({ tree, selectedNode, focusChoiceId, isPublished, onAddChoice, onUpdateSelectedNode, onDeleteChoice, onMoveChoice, onSetChoiceTarget, onSetChoiceOutcome, onSetChoiceType, choiceTypes, outcomeOptions, hideOutcomeField, renderExtraChoiceFields, onFocusChoice, }: Readonly<{
5
+ tree: EditorTree;
6
+ selectedNode: EditorNode;
7
+ focusChoiceId: string | null;
8
+ isPublished: boolean;
9
+ onAddChoice: () => void;
10
+ onUpdateSelectedNode: (patch: Partial<EditorNode>) => void;
11
+ onDeleteChoice: (choiceId: string) => void;
12
+ onMoveChoice?: (choiceId: string, direction: 'up' | 'down') => void;
13
+ onSetChoiceTarget: (choiceId: string, targetNodeId: string) => void;
14
+ onSetChoiceOutcome: (choiceId: string, outcome: string) => void;
15
+ onSetChoiceType?: (choiceId: string, typeId: string, defaultLabel?: string) => void;
16
+ choiceTypes?: ReadonlyArray<ChoiceTypeOption>;
17
+ outcomeOptions: ReadonlyArray<{
18
+ value: string;
19
+ label: string;
20
+ }>;
21
+ hideOutcomeField: boolean;
22
+ renderExtraChoiceFields?: (ctx: InspectorChoiceRenderContext) => ReactNode;
23
+ onFocusChoice?: (choiceId: string) => void;
24
+ }>): import("react").JSX.Element;
25
+ //# sourceMappingURL=ChoiceEditorList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChoiceEditorList.d.ts","sourceRoot":"","sources":["../../../src/panels/inspector/ChoiceEditorList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAIhF,OAAO,KAAK,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,SAAS,CAAC;AAE9E,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACrC,IAAI,EACJ,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,oBAAoB,EACpB,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,uBAAuB,EACvB,aAAa,GAChB,EAAE,QAAQ,CAAC;IACR,IAAI,EAAE,UAAU,CAAC;IACjB,YAAY,EAAE,UAAU,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,oBAAoB,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IAC3D,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;IACpE,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACpE,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACpF,WAAW,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC9C,cAAc,EAAE,aAAa,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChE,gBAAgB,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,CAAC,GAAG,EAAE,4BAA4B,KAAK,SAAS,CAAC;IAC3E,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C,CAAC,+BAqED"}
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import PanelHeaderCollapseCarets from '../../lib/PanelHeaderCollapseCarets';
4
+ import ChoiceEditorCard from './ChoiceEditorCard';
5
+ export default function ChoiceEditorList({ tree, selectedNode, focusChoiceId, isPublished, onAddChoice, onUpdateSelectedNode, onDeleteChoice, onMoveChoice, onSetChoiceTarget, onSetChoiceOutcome, onSetChoiceType, choiceTypes, outcomeOptions, hideOutcomeField, renderExtraChoiceFields, onFocusChoice, }) {
6
+ const choices = selectedNode.choices ?? [];
7
+ const [choicesExpanded, setChoicesExpanded] = useState(true);
8
+ const usedChoiceTypeIds = new Set(choices.map((choice) => choice.id));
9
+ return (_jsxs("div", { className: "card mt-3", children: [_jsxs("div", { className: "card-header bg-body-secondary py-2 px-2 d-flex justify-content-between align-items-center gap-2", children: [_jsxs("div", { className: "d-flex align-items-center min-w-0", children: [_jsx("span", { className: "fw-semibold", children: "Choices" }), _jsx(PanelHeaderCollapseCarets, { expanded: choicesExpanded, onToggle: () => setChoicesExpanded((v) => !v) })] }), _jsx("div", { className: "d-flex align-items-center gap-1 flex-shrink-0", children: _jsx("button", { type: "button", className: "btn p-0 border-0 bg-transparent flex-shrink-0", "aria-label": "Add choice", title: "Add choice", disabled: isPublished, onClick: onAddChoice, children: _jsx("i", { className: `bi bi-plus-lg action-icon${isPublished ? ' text-secondary opacity-50' : ' text-primary cursor-pointer'}`, "aria-hidden": true }) }) })] }), _jsx("div", { className: `card-body p-0${choicesExpanded ? '' : ' d-none'}`, "aria-hidden": !choicesExpanded, children: choices.length === 0 ? (_jsx("div", { className: "text-muted small py-3 px-3", children: _jsx("em", { children: "No choices" }) })) : (_jsx("div", { className: "list-group list-group-flush overflow-auto-max-h-320", children: choices.map((choice, index) => (_jsx(ChoiceEditorCard, { choice: choice, tree: tree, selectedNode: selectedNode, focusChoiceId: focusChoiceId, isPublished: isPublished, canMoveUp: index > 0, canMoveDown: index < choices.length - 1, usedChoiceTypeIds: usedChoiceTypeIds, onUpdateSelectedNode: onUpdateSelectedNode, onDeleteChoice: onDeleteChoice, onMoveChoice: onMoveChoice, onSetChoiceTarget: onSetChoiceTarget, onSetChoiceOutcome: onSetChoiceOutcome, onSetChoiceType: onSetChoiceType, choiceTypes: choiceTypes, outcomeOptions: outcomeOptions, hideOutcomeField: hideOutcomeField, renderExtraChoiceFields: renderExtraChoiceFields, onFocusChoice: onFocusChoice }, choice.id))) })) })] }));
10
+ }
@@ -0,0 +1,8 @@
1
+ import { type EditorNode } from '@signalsafe/tree-spec-editor-core';
2
+ export default function NodeTypeField({ selectedNode, isPublished, onUpdateSelectedNode, typeHelperText, }: Readonly<{
3
+ selectedNode: EditorNode;
4
+ isPublished: boolean;
5
+ onUpdateSelectedNode: (patch: Partial<EditorNode>) => void;
6
+ typeHelperText: string;
7
+ }>): import("react").JSX.Element;
8
+ //# sourceMappingURL=NodeTypeField.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeTypeField.d.ts","sourceRoot":"","sources":["../../../src/panels/inspector/NodeTypeField.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEH,KAAK,UAAU,EAClB,MAAM,mCAAmC,CAAC;AAE3C,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EAClC,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,cAAc,GACjB,EAAE,QAAQ,CAAC;IACR,YAAY,EAAE,UAAU,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,oBAAoB,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IAC3D,cAAc,EAAE,MAAM,CAAC;CAC1B,CAAC,+BAkCD"}
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Form } from 'react-bootstrap';
3
+ import { TREE_SPEC_NODE_TYPE_PRESETS, } from '@signalsafe/tree-spec-editor-core';
4
+ export default function NodeTypeField({ selectedNode, isPublished, onUpdateSelectedNode, typeHelperText, }) {
5
+ const isPreset = TREE_SPEC_NODE_TYPE_PRESETS.includes(selectedNode.type);
6
+ return (_jsxs(Form.Group, { className: "mb-2", children: [_jsx(Form.Label, { children: "Type" }), _jsxs(Form.Select, { value: isPreset ? selectedNode.type : '__custom__', onChange: (e) => {
7
+ const nextType = e.target.value;
8
+ if (nextType === '__custom__')
9
+ return;
10
+ onUpdateSelectedNode({ type: nextType });
11
+ }, disabled: isPublished, children: [TREE_SPEC_NODE_TYPE_PRESETS.map((t) => (_jsx("option", { value: t, children: t }, t))), _jsx("option", { value: "__custom__", children: "custom\u2026" })] }), isPreset ? null : (_jsx(Form.Control, { className: "mt-2", value: selectedNode.type, onChange: (e) => onUpdateSelectedNode({ type: e.target.value }), placeholder: "Enter custom type\u2026", disabled: isPublished })), _jsx("div", { className: "text-muted mt-1 font-size-12", children: typeHelperText })] }));
12
+ }
@@ -0,0 +1,14 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { EditorNode, EditorTree } from '@signalsafe/tree-spec-editor-core';
3
+ import type { InspectorNodeRenderContext } from './types';
4
+ export default function RequiredNodeCard({ tree, selectedNode, isPublished, title, typeHelperText, onUpdateSelectedNode, onDeleteSelectedNode, renderExtraNodeFields, }: Readonly<{
5
+ tree: EditorTree;
6
+ selectedNode: EditorNode;
7
+ isPublished: boolean;
8
+ title: string;
9
+ typeHelperText: string;
10
+ onUpdateSelectedNode: (patch: Partial<EditorNode>) => void;
11
+ onDeleteSelectedNode?: () => void;
12
+ renderExtraNodeFields?: (ctx: InspectorNodeRenderContext) => ReactNode;
13
+ }>): import("react").JSX.Element;
14
+ //# sourceMappingURL=RequiredNodeCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequiredNodeCard.d.ts","sourceRoot":"","sources":["../../../src/panels/inspector/RequiredNodeCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,SAAS,EAAE,MAAM,OAAO,CAAC;AAIpD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAIhF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AAE1D,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACrC,IAAI,EACJ,YAAY,EACZ,WAAW,EACX,KAAK,EACL,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,GACxB,EAAE,QAAQ,CAAC;IACR,IAAI,EAAE,UAAU,CAAC;IACjB,YAAY,EAAE,UAAU,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IAC3D,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,qBAAqB,CAAC,EAAE,CAAC,GAAG,EAAE,0BAA0B,KAAK,SAAS,CAAC;CAC1E,CAAC,+BA4DD"}
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { Form } from 'react-bootstrap';
4
+ import PanelHeaderCollapseCarets from '../../lib/PanelHeaderCollapseCarets';
5
+ import NodeTypeField from './NodeTypeField';
6
+ export default function RequiredNodeCard({ tree, selectedNode, isPublished, title, typeHelperText, onUpdateSelectedNode, onDeleteSelectedNode, renderExtraNodeFields, }) {
7
+ const [requiredExpanded, setRequiredExpanded] = useState(true);
8
+ return (_jsxs("div", { className: "card", children: [_jsxs("div", { className: "card-header bg-body-secondary py-2 px-2 d-flex justify-content-between align-items-center gap-2", children: [_jsxs("div", { className: "d-flex align-items-center min-w-0", children: [_jsx("span", { className: "fw-semibold", children: title }), _jsx(PanelHeaderCollapseCarets, { expanded: requiredExpanded, onToggle: () => setRequiredExpanded((v) => !v) })] }), onDeleteSelectedNode ? (_jsx("button", { type: "button", className: "btn p-0 border-0 bg-transparent flex-shrink-0", "aria-label": "Delete node", title: "Delete node", disabled: isPublished, onClick: onDeleteSelectedNode, children: _jsx("i", { className: `bi bi-trash action-icon cursor-pointer${isPublished ? ' text-secondary opacity-50' : ' text-danger'}`, "aria-hidden": true }) })) : null] }), _jsxs("div", { className: `card-body${requiredExpanded ? '' : ' d-none'}`, "aria-hidden": !requiredExpanded, children: [_jsx(NodeTypeField, { selectedNode: selectedNode, isPublished: isPublished, onUpdateSelectedNode: onUpdateSelectedNode, typeHelperText: typeHelperText }), _jsxs(Form.Group, { className: "mb-2", children: [_jsx(Form.Label, { children: "Prompt" }), _jsx(Form.Control, { as: "textarea", rows: 4, value: selectedNode.prompt, onChange: (e) => onUpdateSelectedNode({ prompt: e.target.value }) })] }), renderExtraNodeFields
9
+ ? renderExtraNodeFields({
10
+ tree,
11
+ node: selectedNode,
12
+ isPublished,
13
+ onUpdateNode: onUpdateSelectedNode,
14
+ })
15
+ : null] })] }));
16
+ }
@@ -0,0 +1,12 @@
1
+ import type { KeyboardEvent, MouseEvent } from 'react';
2
+ export declare function choiceActionIconProps(onClick: () => void, title: string, className: string, disabled?: boolean): {
3
+ role: "button";
4
+ tabIndex: number;
5
+ title: string;
6
+ 'aria-label': string;
7
+ 'aria-disabled': boolean | undefined;
8
+ className: string;
9
+ onClick: ((event: MouseEvent<HTMLElement>) => void) | undefined;
10
+ onKeyDown: ((event: KeyboardEvent<HTMLElement>) => void) | undefined;
11
+ };
12
+ //# sourceMappingURL=choiceActionIconProps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"choiceActionIconProps.d.ts","sourceRoot":"","sources":["../../../src/panels/inspector/choiceActionIconProps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAEvD,wBAAgB,qBAAqB,CACjC,OAAO,EAAE,MAAM,IAAI,EACnB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,QAAQ,UAAQ;;;;;;;sBAaE,UAAU,CAAC,WAAW,CAAC;wBAOvB,aAAa,CAAC,WAAW,CAAC;EAQ/C"}
@@ -0,0 +1,26 @@
1
+ export function choiceActionIconProps(onClick, title, className, disabled = false) {
2
+ return {
3
+ role: 'button',
4
+ tabIndex: disabled ? -1 : 0,
5
+ title,
6
+ 'aria-label': title,
7
+ 'aria-disabled': disabled ? true : undefined,
8
+ className: `${className} action-icon flex-shrink-0${disabled ? ' text-secondary opacity-50' : ' cursor-pointer'}`,
9
+ onClick: disabled
10
+ ? undefined
11
+ : (event) => {
12
+ event.preventDefault();
13
+ event.stopPropagation();
14
+ onClick();
15
+ },
16
+ onKeyDown: disabled
17
+ ? undefined
18
+ : (event) => {
19
+ if (event.key === 'Enter' || event.key === ' ') {
20
+ event.preventDefault();
21
+ event.stopPropagation();
22
+ onClick();
23
+ }
24
+ },
25
+ };
26
+ }
@@ -0,0 +1,77 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { EditorChoice, EditorNode, EditorTransition, EditorTree } from '@signalsafe/tree-spec-editor-core';
3
+ /** Host-provided choice type (stable id + default label). */
4
+ export type ChoiceTypeOption = {
5
+ id: string;
6
+ label: string;
7
+ };
8
+ /**
9
+ * Canonical outcome values from the `@signalsafe/tree-spec` wire contract.
10
+ * Hosts can override via the `outcomeOptions` prop.
11
+ */
12
+ export declare const DEFAULT_OUTCOME_OPTIONS: ReadonlyArray<{
13
+ value: string;
14
+ label: string;
15
+ }>;
16
+ export interface InspectorNodeRenderContext {
17
+ tree: EditorTree;
18
+ node: EditorNode;
19
+ isPublished: boolean;
20
+ onUpdateNode: (patch: Partial<EditorNode>) => void;
21
+ }
22
+ export interface InspectorChoiceRenderContext {
23
+ tree: EditorTree;
24
+ node: EditorNode;
25
+ choice: EditorChoice;
26
+ transition: EditorTransition | undefined;
27
+ isPublished: boolean;
28
+ onUpdateNode: (patch: Partial<EditorNode>) => void;
29
+ }
30
+ export interface InspectorPanelProps {
31
+ tree: EditorTree;
32
+ selectedNode: EditorNode | null;
33
+ focusChoiceId?: string | null;
34
+ isPublished?: boolean;
35
+ /** Sync canvas / sidebar highlight when the user focuses a choice field. */
36
+ onFocusChoice?: (choiceId: string) => void;
37
+ onUpdateSelectedNode: (patch: Partial<EditorNode>) => void;
38
+ onAddChoice: () => void;
39
+ onDeleteChoice: (choiceId: string) => void;
40
+ /** Move a choice up or down in the node's choice list. When omitted, reorder controls are hidden. */
41
+ onMoveChoice?: (choiceId: string, direction: 'up' | 'down') => void;
42
+ onSetChoiceTarget: (choiceId: string, targetNodeId: string) => void;
43
+ onSetChoiceOutcome: (choiceId: string, outcome: string) => void;
44
+ /**
45
+ * Override the END-transition outcome `<select>` options.
46
+ * Defaults to the canonical TreeSpec `TerminalOutcome` values.
47
+ */
48
+ outcomeOptions?: ReadonlyArray<{
49
+ value: string;
50
+ label: string;
51
+ }>;
52
+ /** Hide the outcome selector entirely. Useful when the host manages outcomes elsewhere. */
53
+ hideOutcomeField?: boolean;
54
+ /** Render extra UI below the prompt textarea, scoped to the current node. */
55
+ renderExtraNodeFields?: (ctx: InspectorNodeRenderContext) => ReactNode;
56
+ /** Render extra UI below each choice card (after Next/Outcome). */
57
+ renderExtraChoiceFields?: (ctx: InspectorChoiceRenderContext) => ReactNode;
58
+ /** Host-defined choice types (stable ids) for the Type selector on each choice. */
59
+ choiceTypes?: ReadonlyArray<ChoiceTypeOption>;
60
+ onSetChoiceType?: (choiceId: string, typeId: string, defaultLabel?: string) => void;
61
+ /**
62
+ * When set, shows a delete control in the Required card header (grid-style icon button).
63
+ * Typical host: `editor.actions.deleteSelectedNode`. Disabled when `isPublished` is true.
64
+ */
65
+ onDeleteSelectedNode?: () => void;
66
+ /** Override the Required card header (default "Required"). */
67
+ title?: string;
68
+ /** Override the empty-state message (default "Select a node to edit it."). */
69
+ emptyStateText?: string;
70
+ /**
71
+ * Override the muted helper text under the Type field.
72
+ * Defaults to: "Type is stored as a string in tree_spec. You can use presets or any custom value."
73
+ */
74
+ typeHelperText?: string;
75
+ }
76
+ export declare const DEFAULT_TYPE_HELPER_TEXT = "Type is stored as a string in tree_spec. You can use presets or any custom value.";
77
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/panels/inspector/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { TERMINAL_OUTCOME } from '@signalsafe/tree-spec';
2
+ /**
3
+ * Canonical outcome values from the `@signalsafe/tree-spec` wire contract.
4
+ * Hosts can override via the `outcomeOptions` prop.
5
+ */
6
+ export const DEFAULT_OUTCOME_OPTIONS = [
7
+ { value: TERMINAL_OUTCOME.SAFE, label: TERMINAL_OUTCOME.SAFE },
8
+ { value: TERMINAL_OUTCOME.AT_RISK, label: TERMINAL_OUTCOME.AT_RISK },
9
+ { value: TERMINAL_OUTCOME.COMPROMISED, label: TERMINAL_OUTCOME.COMPROMISED },
10
+ ];
11
+ export const DEFAULT_TYPE_HELPER_TEXT = 'Type is stored as a string in tree_spec. You can use presets or any custom value.';
package/package.json CHANGED
@@ -1,69 +1,87 @@
1
1
  {
2
2
  "name": "@signalsafe/tree-spec-editor",
3
- "version": "0.2.1",
4
- "private": false,
5
- "type": "module",
6
- "description": "Reusable TreeSpec graph editor (React Flow) and authoring helpers (no API or routing)",
7
- "license": "UNLICENSED",
8
- "keywords": [
9
- "tree-spec",
10
- "react-flow",
11
- "editor",
12
- "signalsafe"
13
- ],
14
- "sideEffects": false,
15
- "main": "./dist/index.js",
16
- "types": "./dist/index.d.ts",
17
- "exports": {
18
- ".": {
19
- "types": "./dist/index.d.ts",
20
- "import": "./dist/index.js",
21
- "default": "./dist/index.js"
3
+ "version": "0.2.2",
4
+ "type": "module",
5
+ "description": "Reusable TreeSpec graph editor (React Flow) and authoring helpers (no API or routing).",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/SignalSafeSoftware/tree-spec-editor.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/SignalSafeSoftware/tree-spec-editor/issues"
13
+ },
14
+ "homepage": "https://github.com/SignalSafeSoftware/tree-spec-editor#readme",
15
+ "keywords": [
16
+ "tree-spec",
17
+ "react-flow",
18
+ "editor",
19
+ "graph-editor",
20
+ "decision-tree",
21
+ "react-bootstrap",
22
+ "typescript",
23
+ "signalsafe"
24
+ ],
25
+ "sideEffects": false,
26
+ "main": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js",
32
+ "default": "./dist/index.js"
33
+ }
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "docs",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "engines": {
42
+ "node": ">=18"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "scripts": {
48
+ "build": "tsc -p tsconfig.build.json",
49
+ "typecheck": "tsc --noEmit",
50
+ "pack:local": "npm pack --pack-destination ../../dist/reusable-npm",
51
+ "release:check": "node ../../scripts/run-private-package-release-checks.mjs --mode prepublish",
52
+ "release:verify": "node ../../scripts/run-private-package-release-checks.mjs --mode postpublish",
53
+ "publish:preflight": "node ../../scripts/check-private-registry-preflight.mjs --scope @signalsafe",
54
+ "publish:dry-run": "npm publish --dry-run",
55
+ "publish:verify": "node ../../scripts/check-private-package-postpublish.mjs --scope @signalsafe --package @signalsafe/tree-spec-editor --version $npm_package_version",
56
+ "pack:check": "node ../../scripts/check-package-tarball.mjs --tgz \"../../dist/reusable-npm/signalsafe-tree-spec-editor-$npm_package_version.tgz\" --expect package/dist/index.js --expect package/dist/index.d.ts --expect package/package.json --expect package/README.md",
57
+ "smoke:external": "node ../../scripts/smoke-tree-spec-editor-external-consumer.mjs",
58
+ "smoke:published": "node ../../scripts/smoke-tree-spec-editor-external-consumer.mjs --source registry",
59
+ "prepublishOnly": "npm run build",
60
+ "prepare": "npm run build",
61
+ "test": "vitest run",
62
+ "test:monorepo": "cd ../../frontend && yarn vitest run --config vitest.tree-spec-editor.config.ts"
63
+ },
64
+ "dependencies": {
65
+ "@signalsafe/tree-spec": "^0.3.1",
66
+ "@signalsafe/tree-spec-editor-core": "^0.1.2",
67
+ "@signalsafe/tree-spec-editor-react": "^0.1.2"
68
+ },
69
+ "peerDependencies": {
70
+ "react": "^18.0.0",
71
+ "react-bootstrap": "^2.10.0",
72
+ "react-dom": "^18.0.0",
73
+ "reactflow": "^11.0.0"
74
+ },
75
+ "devDependencies": {
76
+ "@types/react": "^18.2.66",
77
+ "@types/react-dom": "^18.2.22",
78
+ "@types/react-test-renderer": "^18.3.0",
79
+ "react": "^18.3.1",
80
+ "react-bootstrap": "^2.10.2",
81
+ "react-dom": "^18.3.1",
82
+ "react-test-renderer": "^18.3.1",
83
+ "reactflow": "^11.11.4",
84
+ "typescript": "^5.4.2",
85
+ "vitest": "^3.2.4"
22
86
  }
23
- },
24
- "files": [
25
- "dist",
26
- "docs",
27
- "README.md"
28
- ],
29
- "publishConfig": {
30
- "access": "restricted"
31
- },
32
- "scripts": {
33
- "build": "tsc -p tsconfig.build.json",
34
- "typecheck": "tsc --noEmit",
35
- "pack:local": "npm pack --pack-destination ../../dist/reusable-npm",
36
- "release:check": "node ../../scripts/run-private-package-release-checks.mjs --mode prepublish",
37
- "release:verify": "node ../../scripts/run-private-package-release-checks.mjs --mode postpublish",
38
- "publish:preflight": "node ../../scripts/check-private-registry-preflight.mjs --scope @signalsafe",
39
- "publish:dry-run": "npm publish --dry-run",
40
- "publish:verify": "node ../../scripts/check-private-package-postpublish.mjs --scope @signalsafe --package @signalsafe/tree-spec-editor --version $npm_package_version",
41
- "pack:check": "node ../../scripts/check-package-tarball.mjs --tgz \"../../dist/reusable-npm/signalsafe-tree-spec-editor-$npm_package_version.tgz\" --expect package/dist/index.js --expect package/dist/index.d.ts --expect package/package.json --expect package/README.md",
42
- "smoke:external": "node ../../scripts/smoke-tree-spec-editor-external-consumer.mjs",
43
- "smoke:published": "node ../../scripts/smoke-tree-spec-editor-external-consumer.mjs --source registry",
44
- "prepublishOnly": "npm run build",
45
- "prepare": "npm run build",
46
- "test": "cd ../../frontend && yarn vitest run --config vitest.tree-spec-editor.config.ts"
47
- },
48
- "dependencies": {
49
- "@signalsafe/tree-spec": "^0.1.4",
50
- "@signalsafe/tree-spec-editor-core": "^0.1.1",
51
- "@signalsafe/tree-spec-editor-react": "^0.1.1"
52
- },
53
- "peerDependencies": {
54
- "react": "^18.0.0",
55
- "react-bootstrap": "^2.10.0",
56
- "react-dom": "^18.0.0",
57
- "reactflow": "^11.0.0"
58
- },
59
- "devDependencies": {
60
- "@types/react": "^18.2.66",
61
- "@types/react-dom": "^18.2.22",
62
- "react": "^18.3.1",
63
- "react-bootstrap": "^2.10.2",
64
- "react-dom": "^18.3.1",
65
- "react-test-renderer": "18.3.1",
66
- "reactflow": "^11.11.4",
67
- "typescript": "^5.4.2"
68
- }
69
87
  }