@pixerate/editor-svelte 0.22.0 → 0.24.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.
Files changed (163) hide show
  1. package/README.md +6 -2
  2. package/dist/MergePreview.svelte +201 -0
  3. package/dist/MergePreview.svelte.d.ts +25 -0
  4. package/dist/MergePreview.svelte.d.ts.map +1 -0
  5. package/dist/StylesGallery.svelte +169 -0
  6. package/dist/StylesGallery.svelte.d.ts +27 -0
  7. package/dist/StylesGallery.svelte.d.ts.map +1 -0
  8. package/dist/TemplateRenderer.svelte +4 -10
  9. package/dist/TemplateRenderer.svelte.d.ts.map +1 -1
  10. package/dist/canvas/TokenBindingPicker.svelte +93 -0
  11. package/dist/canvas/TokenBindingPicker.svelte.d.ts +20 -0
  12. package/dist/canvas/TokenBindingPicker.svelte.d.ts.map +1 -0
  13. package/dist/canvas/TokenModeSwitcher.svelte +55 -0
  14. package/dist/canvas/TokenModeSwitcher.svelte.d.ts +18 -0
  15. package/dist/canvas/TokenModeSwitcher.svelte.d.ts.map +1 -0
  16. package/dist/canvas/createCanvasArrange.svelte.d.ts +4 -0
  17. package/dist/canvas/createCanvasArrange.svelte.d.ts.map +1 -1
  18. package/dist/canvas/createCanvasAutoLayout.svelte.d.ts +68 -0
  19. package/dist/canvas/createCanvasAutoLayout.svelte.d.ts.map +1 -0
  20. package/dist/canvas/createCanvasAutoLayout.svelte.js +78 -0
  21. package/dist/canvas/createCanvasTokens.svelte.d.ts +31 -0
  22. package/dist/canvas/createCanvasTokens.svelte.d.ts.map +1 -0
  23. package/dist/canvas/createCanvasTokens.svelte.js +50 -0
  24. package/dist/canvas/index.d.ts +7 -0
  25. package/dist/canvas/index.d.ts.map +1 -1
  26. package/dist/canvas/index.js +10 -0
  27. package/dist/fileImport.svelte.d.ts +8 -1
  28. package/dist/fileImport.svelte.d.ts.map +1 -1
  29. package/dist/fileImport.svelte.js +11 -1
  30. package/dist/find-replace/FindReplaceBar.svelte +203 -0
  31. package/dist/find-replace/FindReplaceBar.svelte.d.ts +15 -0
  32. package/dist/find-replace/FindReplaceBar.svelte.d.ts.map +1 -0
  33. package/dist/find-replace/findReplace.svelte.d.ts +27 -0
  34. package/dist/find-replace/findReplace.svelte.d.ts.map +1 -0
  35. package/dist/find-replace/findReplace.svelte.js +79 -0
  36. package/dist/find-replace/index.d.ts +6 -0
  37. package/dist/find-replace/index.d.ts.map +1 -0
  38. package/dist/find-replace/index.js +2 -0
  39. package/dist/generation/AssetMentionChips.svelte +130 -0
  40. package/dist/generation/AssetMentionChips.svelte.d.ts +21 -0
  41. package/dist/generation/AssetMentionChips.svelte.d.ts.map +1 -0
  42. package/dist/generation/GenerationHistory.svelte +161 -0
  43. package/dist/generation/GenerationHistory.svelte.d.ts +28 -0
  44. package/dist/generation/GenerationHistory.svelte.d.ts.map +1 -0
  45. package/dist/generation/GenerationSettings.svelte +174 -0
  46. package/dist/generation/GenerationSettings.svelte.d.ts +23 -0
  47. package/dist/generation/GenerationSettings.svelte.d.ts.map +1 -0
  48. package/dist/generation/JobProgress.svelte +53 -0
  49. package/dist/generation/JobProgress.svelte.d.ts +17 -0
  50. package/dist/generation/JobProgress.svelte.d.ts.map +1 -0
  51. package/dist/generation/index.d.ts +17 -0
  52. package/dist/generation/index.d.ts.map +1 -0
  53. package/dist/generation/index.js +7 -0
  54. package/dist/generation/plan.svelte.d.ts +16 -0
  55. package/dist/generation/plan.svelte.d.ts.map +1 -0
  56. package/dist/generation/plan.svelte.js +26 -0
  57. package/dist/generation/progress.svelte.d.ts +25 -0
  58. package/dist/generation/progress.svelte.d.ts.map +1 -0
  59. package/dist/generation/progress.svelte.js +36 -0
  60. package/dist/generation/records.svelte.d.ts +18 -0
  61. package/dist/generation/records.svelte.d.ts.map +1 -0
  62. package/dist/generation/records.svelte.js +66 -0
  63. package/dist/image-editor/AdjustmentLayersPanel.svelte +309 -0
  64. package/dist/image-editor/AdjustmentLayersPanel.svelte.d.ts +11 -0
  65. package/dist/image-editor/AdjustmentLayersPanel.svelte.d.ts.map +1 -0
  66. package/dist/image-editor/ControlSlider.svelte +39 -0
  67. package/dist/image-editor/ControlSlider.svelte.d.ts +13 -0
  68. package/dist/image-editor/ControlSlider.svelte.d.ts.map +1 -0
  69. package/dist/image-editor/CurvesEditor.svelte +105 -0
  70. package/dist/image-editor/CurvesEditor.svelte.d.ts +13 -0
  71. package/dist/image-editor/CurvesEditor.svelte.d.ts.map +1 -0
  72. package/dist/image-editor/Histogram.svelte +49 -0
  73. package/dist/image-editor/Histogram.svelte.d.ts +12 -0
  74. package/dist/image-editor/Histogram.svelte.d.ts.map +1 -0
  75. package/dist/image-editor/ImageEditor.svelte +104 -141
  76. package/dist/image-editor/ImageEditor.svelte.d.ts.map +1 -1
  77. package/dist/image-editor/RefineEdgePanel.svelte +180 -0
  78. package/dist/image-editor/RefineEdgePanel.svelte.d.ts +13 -0
  79. package/dist/image-editor/RefineEdgePanel.svelte.d.ts.map +1 -0
  80. package/dist/image-editor/SelectionOptionsBar.svelte +135 -0
  81. package/dist/image-editor/SelectionOptionsBar.svelte.d.ts +15 -0
  82. package/dist/image-editor/SelectionOptionsBar.svelte.d.ts.map +1 -0
  83. package/dist/image-editor/imageEditorState.svelte.d.ts +14 -1
  84. package/dist/image-editor/imageEditorState.svelte.d.ts.map +1 -1
  85. package/dist/image-editor/imageEditorState.svelte.js +40 -0
  86. package/dist/image-editor/index.d.ts +18 -0
  87. package/dist/image-editor/index.d.ts.map +1 -1
  88. package/dist/image-editor/index.js +6 -0
  89. package/dist/index.d.ts +12 -1
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +7 -0
  92. package/dist/merge.svelte.d.ts +51 -0
  93. package/dist/merge.svelte.d.ts.map +1 -0
  94. package/dist/merge.svelte.js +117 -0
  95. package/dist/paragraphStyles.svelte.d.ts +30 -0
  96. package/dist/paragraphStyles.svelte.d.ts.map +1 -0
  97. package/dist/paragraphStyles.svelte.js +44 -0
  98. package/dist/persistence/RecoveryPrompt.svelte +57 -0
  99. package/dist/persistence/RecoveryPrompt.svelte.d.ts +18 -0
  100. package/dist/persistence/RecoveryPrompt.svelte.d.ts.map +1 -0
  101. package/dist/persistence/autosave.svelte.d.ts +63 -0
  102. package/dist/persistence/autosave.svelte.d.ts.map +1 -0
  103. package/dist/persistence/autosave.svelte.js +110 -0
  104. package/dist/persistence/index.d.ts +6 -0
  105. package/dist/persistence/index.d.ts.map +1 -0
  106. package/dist/persistence/index.js +2 -0
  107. package/dist/review/TrackedChangesList.svelte +67 -0
  108. package/dist/review/TrackedChangesList.svelte.d.ts +13 -0
  109. package/dist/review/TrackedChangesList.svelte.d.ts.map +1 -0
  110. package/dist/review/documentCompare.svelte.d.ts +21 -0
  111. package/dist/review/documentCompare.svelte.d.ts.map +1 -0
  112. package/dist/review/documentCompare.svelte.js +23 -0
  113. package/dist/review/index.d.ts +4 -0
  114. package/dist/review/index.d.ts.map +1 -1
  115. package/dist/review/index.js +2 -0
  116. package/dist/review/review.svelte.d.ts +6 -0
  117. package/dist/review/review.svelte.d.ts.map +1 -1
  118. package/dist/review/review.svelte.js +3 -0
  119. package/dist/spreadsheet/FormulaBar.svelte +13 -4
  120. package/dist/spreadsheet/FormulaBar.svelte.d.ts.map +1 -1
  121. package/dist/spreadsheet/FormulaHints.svelte +7 -5
  122. package/dist/spreadsheet/FormulaHints.svelte.d.ts +3 -0
  123. package/dist/spreadsheet/FormulaHints.svelte.d.ts.map +1 -1
  124. package/dist/spreadsheet/NameManager.svelte +165 -0
  125. package/dist/spreadsheet/NameManager.svelte.d.ts +11 -0
  126. package/dist/spreadsheet/NameManager.svelte.d.ts.map +1 -0
  127. package/dist/spreadsheet/SheetTabs.svelte +161 -0
  128. package/dist/spreadsheet/SheetTabs.svelte.d.ts +10 -0
  129. package/dist/spreadsheet/SheetTabs.svelte.d.ts.map +1 -0
  130. package/dist/spreadsheet/SpreadsheetConditionalFormatPanel.svelte +184 -0
  131. package/dist/spreadsheet/SpreadsheetConditionalFormatPanel.svelte.d.ts +9 -0
  132. package/dist/spreadsheet/SpreadsheetConditionalFormatPanel.svelte.d.ts.map +1 -0
  133. package/dist/spreadsheet/SpreadsheetContextMenu.svelte +13 -5
  134. package/dist/spreadsheet/SpreadsheetContextMenu.svelte.d.ts +5 -1
  135. package/dist/spreadsheet/SpreadsheetContextMenu.svelte.d.ts.map +1 -1
  136. package/dist/spreadsheet/SpreadsheetDataValidationPanel.svelte +141 -0
  137. package/dist/spreadsheet/SpreadsheetDataValidationPanel.svelte.d.ts +9 -0
  138. package/dist/spreadsheet/SpreadsheetDataValidationPanel.svelte.d.ts.map +1 -0
  139. package/dist/spreadsheet/SpreadsheetEditor.svelte +199 -11
  140. package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts +2 -0
  141. package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts.map +1 -1
  142. package/dist/spreadsheet/SpreadsheetValidationDialog.svelte +92 -0
  143. package/dist/spreadsheet/SpreadsheetValidationDialog.svelte.d.ts +9 -0
  144. package/dist/spreadsheet/SpreadsheetValidationDialog.svelte.d.ts.map +1 -0
  145. package/dist/spreadsheet/index.d.ts +9 -0
  146. package/dist/spreadsheet/index.d.ts.map +1 -1
  147. package/dist/spreadsheet/index.js +5 -0
  148. package/dist/spreadsheet/spreadsheet.svelte.d.ts +57 -2
  149. package/dist/spreadsheet/spreadsheet.svelte.d.ts.map +1 -1
  150. package/dist/spreadsheet/spreadsheet.svelte.js +105 -6
  151. package/dist/tokens/TokenSwatch.svelte +14 -0
  152. package/dist/tokens/TokenSwatch.svelte.d.ts +8 -0
  153. package/dist/tokens/TokenSwatch.svelte.d.ts.map +1 -0
  154. package/dist/tokens/TokensPanel.svelte +323 -0
  155. package/dist/tokens/TokensPanel.svelte.d.ts +14 -0
  156. package/dist/tokens/TokensPanel.svelte.d.ts.map +1 -0
  157. package/dist/tokens/createTokens.svelte.d.ts +31 -0
  158. package/dist/tokens/createTokens.svelte.d.ts.map +1 -0
  159. package/dist/tokens/createTokens.svelte.js +43 -0
  160. package/dist/tokens/index.d.ts +7 -0
  161. package/dist/tokens/index.d.ts.map +1 -0
  162. package/dist/tokens/index.js +3 -0
  163. package/package.json +26 -2
@@ -0,0 +1,110 @@
1
+ import { createAutosaveController, createRevisionTracker, } from "@pixerate/editor/persistence";
2
+ /**
3
+ * Svelte 5 rune: crash-recovery autosave bound to a history and dirty flag,
4
+ * with page lifecycle flushing and a recovery check (see
5
+ * `createAutosaveController` in `@pixerate/editor/persistence`). Render
6
+ * `<RecoveryPrompt>` with `recovery`, `restore` and `discard`.
7
+ */
8
+ export function createAutosave(options) {
9
+ const revisions = createRevisionTracker({ history: options.history, dirty: options.dirty });
10
+ const controller = createAutosaveController({
11
+ storage: options.storage,
12
+ key: options.key,
13
+ getSnapshot: options.getSnapshot,
14
+ serialize: options.serialize,
15
+ deserialize: options.deserialize,
16
+ name: options.name,
17
+ revision: revisions.revision,
18
+ savedRevision: revisions.savedRevision,
19
+ interval: options.interval,
20
+ debounceMs: options.debounceMs,
21
+ retryBaseMs: options.retryBaseMs,
22
+ retryMaxMs: options.retryMaxMs,
23
+ });
24
+ const recover = options.recover !== false;
25
+ let status = $state.raw(controller.getStatus());
26
+ let recovery = $state.raw(null);
27
+ let pendingRecovery = $state(recover);
28
+ let loaded = options.ready !== false;
29
+ let destroyed = false;
30
+ const maybeReady = () => {
31
+ if (!destroyed && loaded && !pendingRecovery)
32
+ controller.ready();
33
+ };
34
+ const unsubscribeStatus = controller.subscribe((info) => {
35
+ status = info;
36
+ });
37
+ const unsubscribeRevisions = revisions.subscribe(() => controller.notify());
38
+ const checked = recover
39
+ ? controller
40
+ .checkRecovery()
41
+ .catch(() => null)
42
+ .then((found) => {
43
+ if (destroyed)
44
+ return;
45
+ recovery = found;
46
+ pendingRecovery = found !== null;
47
+ maybeReady();
48
+ })
49
+ : Promise.resolve();
50
+ maybeReady();
51
+ let removeListeners = () => { };
52
+ if (options.flushOnHide !== false && typeof window !== "undefined") {
53
+ const flush = () => void controller.flushNow();
54
+ const onVisibility = () => {
55
+ if (document.visibilityState === "hidden")
56
+ flush();
57
+ };
58
+ window.addEventListener("pagehide", flush);
59
+ document.addEventListener("visibilitychange", onVisibility);
60
+ removeListeners = () => {
61
+ window.removeEventListener("pagehide", flush);
62
+ document.removeEventListener("visibilitychange", onVisibility);
63
+ };
64
+ }
65
+ return {
66
+ get status() {
67
+ return status;
68
+ },
69
+ get recovery() {
70
+ return recovery;
71
+ },
72
+ get pendingRecovery() {
73
+ return pendingRecovery;
74
+ },
75
+ restore() {
76
+ const snapshot = recovery?.snapshot;
77
+ recovery = null;
78
+ pendingRecovery = false;
79
+ // Deferred so the caller can apply the snapshot first.
80
+ queueMicrotask(maybeReady);
81
+ return snapshot;
82
+ },
83
+ async discard() {
84
+ await controller.discardRecovery();
85
+ recovery = null;
86
+ pendingRecovery = false;
87
+ maybeReady();
88
+ },
89
+ ready() {
90
+ loaded = true;
91
+ maybeReady();
92
+ },
93
+ flushNow: () => controller.flushNow(),
94
+ async markClean() {
95
+ revisions.markSaved();
96
+ await controller.markClean();
97
+ },
98
+ notifyChange: () => revisions.bump(),
99
+ checked,
100
+ controller,
101
+ destroy() {
102
+ destroyed = true;
103
+ removeListeners();
104
+ unsubscribeStatus();
105
+ unsubscribeRevisions();
106
+ revisions.destroy();
107
+ controller.destroy();
108
+ },
109
+ };
110
+ }
@@ -0,0 +1,6 @@
1
+ import type { ComponentProps } from "svelte";
2
+ import type RecoveryPromptComponent from "./RecoveryPrompt.svelte";
3
+ export { default as RecoveryPrompt } from "./RecoveryPrompt.svelte";
4
+ export * from "./autosave.svelte.js";
5
+ export type RecoveryPromptProps = ComponentProps<typeof RecoveryPromptComponent>;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/persistence/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,uBAAuB,MAAM,yBAAyB,CAAC;AAEnE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,cAAc,sBAAsB,CAAC;AAErC,MAAM,MAAM,mBAAmB,GAAG,cAAc,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { default as RecoveryPrompt } from "./RecoveryPrompt.svelte";
2
+ export * from "./autosave.svelte.js";
@@ -0,0 +1,67 @@
1
+ <script lang="ts">
2
+ import type { Editor } from "@tiptap/core";
3
+ import { trackedChangeLabel } from "@pixerate/editor";
4
+ import { createTrackChanges, type SvelteTrackChanges } from "./review.svelte.js";
5
+
6
+ interface Props {
7
+ editor?: Editor | null;
8
+ class?: string;
9
+ itemClass?: string;
10
+ activeItemClass?: string;
11
+ /** Text shown when there are no changes. */
12
+ emptyState?: string;
13
+ }
14
+
15
+ let {
16
+ editor = null,
17
+ class: className = "flex flex-col gap-1 text-sm",
18
+ itemClass = "flex items-center gap-2 rounded px-2 py-1 hover:bg-muted/50",
19
+ activeItemClass = "bg-primary/10",
20
+ emptyState = "No tracked changes.",
21
+ }: Props = $props();
22
+
23
+ const buttonClass =
24
+ "rounded px-1.5 py-0.5 text-xs text-foreground hover:bg-muted disabled:opacity-40";
25
+
26
+ let review = $state.raw<SvelteTrackChanges>(createTrackChanges(null));
27
+
28
+ $effect(() => {
29
+ const r = createTrackChanges(editor);
30
+ review = r;
31
+ return () => r.destroy();
32
+ });
33
+ </script>
34
+
35
+ {#if review.changes.length === 0}
36
+ <div class={className} data-tracked-changes-list="">
37
+ <div class="pixerate-changes-empty text-xs text-muted-foreground">{emptyState}</div>
38
+ </div>
39
+ {:else}
40
+ <ul class={className} role="list" aria-label="Tracked changes" data-tracked-changes-list="">
41
+ {#each review.changes as change (`${change.type}:${change.id}`)}
42
+ <li
43
+ class={change.id === review.currentChangeId ? `${itemClass} ${activeItemClass}` : itemClass}
44
+ data-change-type={change.type}
45
+ data-change-id={change.id}
46
+ >
47
+ <button
48
+ type="button"
49
+ class="min-w-0 flex-1 truncate text-left text-xs"
50
+ title={`${change.author.name}: ${change.description}`}
51
+ onclick={() => review.select(change.id)}
52
+ >
53
+ <span class="font-medium">{trackedChangeLabel(change)}</span>{change.author.name
54
+ ? ` · ${change.author.name}`
55
+ : ""}
56
+ <span class="block truncate text-muted-foreground">{change.description}</span>
57
+ </button>
58
+ <button type="button" class={buttonClass} onclick={() => review.accept(change.id)}>
59
+ Accept
60
+ </button>
61
+ <button type="button" class={buttonClass} onclick={() => review.reject(change.id)}>
62
+ Reject
63
+ </button>
64
+ </li>
65
+ {/each}
66
+ </ul>
67
+ {/if}
@@ -0,0 +1,13 @@
1
+ import type { Editor } from "@tiptap/core";
2
+ interface Props {
3
+ editor?: Editor | null;
4
+ class?: string;
5
+ itemClass?: string;
6
+ activeItemClass?: string;
7
+ /** Text shown when there are no changes. */
8
+ emptyState?: string;
9
+ }
10
+ declare const TrackedChangesList: import("svelte").Component<Props, {}, "">;
11
+ type TrackedChangesList = ReturnType<typeof TrackedChangesList>;
12
+ export default TrackedChangesList;
13
+ //# sourceMappingURL=TrackedChangesList.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TrackedChangesList.svelte.d.ts","sourceRoot":"","sources":["../../src/review/TrackedChangesList.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAKzC,UAAU,KAAK;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAsDH,QAAA,MAAM,kBAAkB,2CAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { Editor } from "@tiptap/core";
2
+ import { type CompareSource, type CompareSummary, type EditorCompareOptions } from "@pixerate/editor";
3
+ export type { CompareSource, CompareSummary, EditorCompareOptions } from "@pixerate/editor";
4
+ export interface SvelteDocumentCompare {
5
+ /** Summary of the last comparison, or `null` (reactive). */
6
+ readonly summary: CompareSummary | null;
7
+ /**
8
+ * Replaces the editor content with the comparison of two versions (nodes,
9
+ * JSON or HTML) as tracked changes, ready to review with `ReviewToolbar`.
10
+ * Returns the summary, or `null` without an editor.
11
+ */
12
+ compare(original: CompareSource, revised: CompareSource, options?: EditorCompareOptions): CompareSummary | null;
13
+ /** Forgets the last summary. */
14
+ clear(): void;
15
+ }
16
+ /**
17
+ * Compare two document versions into an editor using `TrackChanges`.
18
+ * `options` are defaults for every comparison.
19
+ */
20
+ export declare function createDocumentCompare(editor: Editor | null | undefined, options?: EditorCompareOptions): SvelteDocumentCompare;
21
+ //# sourceMappingURL=documentCompare.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"documentCompare.svelte.d.ts","sourceRoot":"","sources":["../../src/review/documentCompare.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EAC1B,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE5F,MAAM,WAAW,qBAAqB;IACpC,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IACxC;;;;OAIG;IACH,OAAO,CACL,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,cAAc,GAAG,IAAI,CAAC;IACzB,gCAAgC;IAChC,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,qBAAqB,CAgBvB"}
@@ -0,0 +1,23 @@
1
+ import { applyDocumentComparison, } from "@pixerate/editor";
2
+ /**
3
+ * Compare two document versions into an editor using `TrackChanges`.
4
+ * `options` are defaults for every comparison.
5
+ */
6
+ export function createDocumentCompare(editor, options) {
7
+ let summary = $state.raw(null);
8
+ return {
9
+ get summary() {
10
+ return summary;
11
+ },
12
+ compare(original, revised, overrides) {
13
+ if (!editor || editor.isDestroyed)
14
+ return null;
15
+ const result = applyDocumentComparison(editor, original, revised, { ...options, ...overrides });
16
+ summary = result.summary;
17
+ return result.summary;
18
+ },
19
+ clear() {
20
+ summary = null;
21
+ },
22
+ };
23
+ }
@@ -2,10 +2,14 @@ import type { ComponentProps } from "svelte";
2
2
  import type CommentsPanelComponent from "./CommentsPanel.svelte";
3
3
  import type ReviewToolbarComponent from "./ReviewToolbar.svelte";
4
4
  import type CommentButtonComponent from "./CommentButton.svelte";
5
+ import type TrackedChangesListComponent from "./TrackedChangesList.svelte";
6
+ export { default as TrackedChangesList } from "./TrackedChangesList.svelte";
7
+ export type TrackedChangesListProps = ComponentProps<typeof TrackedChangesListComponent>;
5
8
  export { default as CommentsPanel } from "./CommentsPanel.svelte";
6
9
  export { default as ReviewToolbar } from "./ReviewToolbar.svelte";
7
10
  export { default as CommentButton } from "./CommentButton.svelte";
8
11
  export * from "./review.svelte.js";
12
+ export * from "./documentCompare.svelte.js";
9
13
  export type CommentsPanelProps = ComponentProps<typeof CommentsPanelComponent>;
10
14
  export type ReviewToolbarProps = ComponentProps<typeof ReviewToolbarComponent>;
11
15
  export type CommentButtonProps = ComponentProps<typeof CommentButtonComponent>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/review/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AAEjE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,cAAc,oBAAoB,CAAC;AAEnC,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/review/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,2BAA2B,MAAM,6BAA6B,CAAC;AAE3E,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,MAAM,MAAM,uBAAuB,GAAG,cAAc,CAAC,OAAO,2BAA2B,CAAC,CAAC;AACzF,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC;AAE5C,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
@@ -1,4 +1,6 @@
1
+ export { default as TrackedChangesList } from "./TrackedChangesList.svelte";
1
2
  export { default as CommentsPanel } from "./CommentsPanel.svelte";
2
3
  export { default as ReviewToolbar } from "./ReviewToolbar.svelte";
3
4
  export { default as CommentButton } from "./CommentButton.svelte";
4
5
  export * from "./review.svelte.js";
6
+ export * from "./documentCompare.svelte.js";
@@ -29,6 +29,12 @@ export interface SvelteTrackChanges extends TrackChangesSnapshot {
29
29
  rejectAll(): void;
30
30
  next(): void;
31
31
  previous(): void;
32
+ /** Selects a change in the editor. */
33
+ select(id: string): void;
34
+ /** Accepts a tracked move (both ends). */
35
+ acceptMove(id: string): void;
36
+ /** Rejects a tracked move (both ends). */
37
+ rejectMove(id: string): void;
32
38
  subscribe(run: (value: TrackChangesSnapshot) => void): () => void;
33
39
  destroy(): void;
34
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"review.svelte.d.ts","sourceRoot":"","sources":["../../src/review/review.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAE1B,eAAO,MAAM,uBAAuB,EAAE,oBAGZ,CAAC;AAE3B,eAAO,MAAM,4BAA4B,EAAE,oBAKjB,CAAC;AAE3B,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAMpE;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,GAAG,SAAS,GAC/C,YAAY,GAAG,IAAI,CAErB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAClE,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,cAAc,CA4B/F;AAED,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,QAAQ,CAAC,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7C,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,MAAM,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,IAAI,IAAI,CAAC;IAClB,SAAS,IAAI,IAAI,CAAC;IAClB,IAAI,IAAI,IAAI,CAAC;IACb,QAAQ,IAAI,IAAI,CAAC;IACjB,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAClE,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,kBAAkB,CA+CxF"}
1
+ {"version":3,"file":"review.svelte.d.ts","sourceRoot":"","sources":["../../src/review/review.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAE1B,eAAO,MAAM,uBAAuB,EAAE,oBAGZ,CAAC;AAE3B,eAAO,MAAM,4BAA4B,EAAE,oBAKjB,CAAC;AAE3B,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAMpE;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,GAAG,SAAS,GAC/C,YAAY,GAAG,IAAI,CAErB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAClE,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,cAAc,CA4B/F;AAED,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,QAAQ,CAAC,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7C,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,MAAM,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,IAAI,IAAI,CAAC;IAClB,SAAS,IAAI,IAAI,CAAC;IAClB,IAAI,IAAI,IAAI,CAAC;IACb,QAAQ,IAAI,IAAI,CAAC;IACjB,sCAAsC;IACtC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,0CAA0C;IAC1C,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAClE,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,kBAAkB,CAkDxF"}
@@ -92,6 +92,9 @@ export function createTrackChanges(editor) {
92
92
  rejectAll: () => run((e) => e.commands.rejectAllChanges()),
93
93
  next: () => run((e) => e.chain().focus().selectNextChange().run()),
94
94
  previous: () => run((e) => e.chain().focus().selectPreviousChange().run()),
95
+ select: (id) => run((e) => e.chain().focus().selectChange(id).run()),
96
+ acceptMove: (id) => run((e) => e.commands.acceptMove(id)),
97
+ rejectMove: (id) => run((e) => e.commands.rejectMove(id)),
95
98
  subscribe(runFn) {
96
99
  if (!store) {
97
100
  runFn(EMPTY_TRACK_CHANGES_SNAPSHOT);
@@ -46,6 +46,13 @@
46
46
  return value;
47
47
  });
48
48
 
49
+ // Defined names for formula autocomplete.
50
+ let nameSuggestions = $derived.by(() => {
51
+ if (!sheetState) return [];
52
+ void sheetState.document;
53
+ return sheetState.controller.getNameSuggestions();
54
+ });
55
+
49
56
  // A spilled cell shows its anchor's formula greyed out (it has no formula of its own).
50
57
  let spillFormula = $derived.by(() => {
51
58
  if (!sheetState || sheetState.editingCell || !sheetState.activeCell || effectiveValue) return '';
@@ -63,10 +70,12 @@
63
70
  if (sheetState && sheetState.activeCell) {
64
71
  const row = sheetState.document.rows[sheetState.activeCell.row];
65
72
  const col = sheetState.document.columns[sheetState.activeCell.col];
66
- if (row && col) {
67
- sheetState.setCellValue(row.id, col.id, effectiveValue);
73
+ // Committed with data validation: invalid input waits for the alert.
74
+ if (sheetState.editingCell) {
75
+ sheetState.commitEditing(effectiveValue);
76
+ } else if (row && col) {
77
+ sheetState.commitCellInput(row.id, col.id, effectiveValue);
68
78
  }
69
- sheetState.commitEditing();
70
79
  }
71
80
  onCommit?.(effectiveValue);
72
81
  } else if (e.key === 'Escape') {
@@ -116,5 +125,5 @@
116
125
  oninput={handleInput}
117
126
  onkeydown={handleKeyDown}
118
127
  />
119
- <FormulaHints input={inputEl} value={effectiveValue} onAccept={setValue} />
128
+ <FormulaHints input={inputEl} value={effectiveValue} onAccept={setValue} names={nameSuggestions} />
120
129
  </div>
@@ -1 +1 @@
1
- {"version":3,"file":"FormulaBar.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/FormulaBar.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAIvE,UAAU,KAAK;IACb,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC;IAC1D,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAwGH,QAAA,MAAM,UAAU,gDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"FormulaBar.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/FormulaBar.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAIvE,UAAU,KAAK;IACb,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC;IAC1D,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAiHH,QAAA,MAAM,UAAU,gDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { tick } from 'svelte';
3
- import { applyFormulaSuggestion, getFormulaHints } from '@pixerate/editor/spreadsheet';
3
+ import { applyFormulaSuggestion, getFormulaHints, type FormulaNameSuggestionSource } from '@pixerate/editor/spreadsheet';
4
4
 
5
5
  interface Props {
6
6
  /** The input being edited (a cell editor or the formula bar). */
@@ -11,9 +11,11 @@
11
11
  onAccept?: (value: string) => void;
12
12
  /** Maximum number of function suggestions (default 8). */
13
13
  limit?: number;
14
+ /** Defined names to suggest too (e.g. `controller.getNameSuggestions()`). */
15
+ names?: readonly FormulaNameSuggestionSource[];
14
16
  }
15
17
 
16
- let { input = null, value = '', onAccept, limit = 8 }: Props = $props();
18
+ let { input = null, value = '', onAccept, limit = 8, names }: Props = $props();
17
19
 
18
20
  let caret = $state<number | null>(null);
19
21
  let focused = $state(false);
@@ -21,7 +23,7 @@
21
23
  let dismissed = $state(false);
22
24
  let position = $state<{ top: number; left: number; width: number } | null>(null);
23
25
 
24
- let hints = $derived(getFormulaHints(value, caret ?? value.length, { limit }));
26
+ let hints = $derived(getFormulaHints(value, caret ?? value.length, { limit, names }));
25
27
  let suggestions = $derived(dismissed ? [] : hints.suggestions);
26
28
  let selectedIndex = $derived(Math.max(0, Math.min(selected, suggestions.length - 1)));
27
29
  let visible = $derived(
@@ -31,7 +33,7 @@
31
33
  async function accept(index: number) {
32
34
  const suggestion = suggestions[index];
33
35
  if (!suggestion || !input) return;
34
- const next = applyFormulaSuggestion(value, caret ?? value.length, suggestion.name);
36
+ const next = applyFormulaSuggestion(value, caret ?? value.length, suggestion);
35
37
  caret = next.caret;
36
38
  selected = 0;
37
39
  onAccept?.(next.value);
@@ -127,7 +129,7 @@
127
129
  {/if}
128
130
  {#if suggestions.length > 0}
129
131
  <ul role="listbox" aria-label="Formula suggestions" class="max-h-64 overflow-auto m-0 list-none p-0 py-1">
130
- {#each suggestions as s, i (s.name)}
132
+ {#each suggestions as s, i (`${s.kind ?? "fn"}:${s.name}`)}
131
133
  <li
132
134
  role="option"
133
135
  aria-selected={i === selectedIndex}
@@ -1,3 +1,4 @@
1
+ import { type FormulaNameSuggestionSource } from '@pixerate/editor/spreadsheet';
1
2
  interface Props {
2
3
  /** The input being edited (a cell editor or the formula bar). */
3
4
  input?: HTMLInputElement | null;
@@ -7,6 +8,8 @@ interface Props {
7
8
  onAccept?: (value: string) => void;
8
9
  /** Maximum number of function suggestions (default 8). */
9
10
  limit?: number;
11
+ /** Defined names to suggest too (e.g. `controller.getNameSuggestions()`). */
12
+ names?: readonly FormulaNameSuggestionSource[];
10
13
  }
11
14
  declare const FormulaHints: import("svelte").Component<Props, {}, "">;
12
15
  type FormulaHints = ReturnType<typeof FormulaHints>;
@@ -1 +1 @@
1
- {"version":3,"file":"FormulaHints.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/FormulaHints.svelte.ts"],"names":[],"mappings":"AAOE,UAAU,KAAK;IACb,iEAAiE;IACjE,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAChC,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoIH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"FormulaHints.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/FormulaHints.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EAA2C,KAAK,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAGvH,UAAU,KAAK;IACb,iEAAiE;IACjE,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAChC,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,KAAK,CAAC,EAAE,SAAS,2BAA2B,EAAE,CAAC;CAChD;AAoIH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,165 @@
1
+ <script lang="ts">
2
+ import { getNameManagerRows, parseFormula, type SpreadsheetNameRow } from '@pixerate/editor/spreadsheet';
3
+ import type { createReactiveSpreadsheet } from './spreadsheet.svelte.js';
4
+
5
+ interface Props {
6
+ sheetState: ReturnType<typeof createReactiveSpreadsheet>;
7
+ readOnly?: boolean;
8
+ onClose?: () => void;
9
+ class?: string;
10
+ }
11
+
12
+ let { sheetState, readOnly = false, onClose, class: className = '' }: Props = $props();
13
+
14
+ interface Draft {
15
+ /** The name being edited (null for a new one). */
16
+ original: { name: string; sheetId?: string } | null;
17
+ name: string;
18
+ refersTo: string;
19
+ /** Sheet id, or '' for workbook scope. */
20
+ scope: string;
21
+ comment: string;
22
+ }
23
+
24
+ const EMPTY_DRAFT: Draft = { original: null, name: '', refersTo: '=', scope: '', comment: '' };
25
+
26
+ let draft = $state<Draft>({ ...EMPTY_DRAFT });
27
+ let error = $state<string | null>(null);
28
+
29
+ const rows = $derived.by(() => {
30
+ void sheetState.document;
31
+ void sheetState.names;
32
+ return getNameManagerRows(sheetState.controller);
33
+ });
34
+
35
+ function edit(row: SpreadsheetNameRow) {
36
+ error = null;
37
+ draft = {
38
+ original: { name: row.name, sheetId: row.sheetId },
39
+ name: row.name,
40
+ refersTo: row.refersTo,
41
+ scope: row.sheetId ?? '',
42
+ comment: row.comment ?? ''
43
+ };
44
+ }
45
+
46
+ function save(e: SubmitEvent) {
47
+ e.preventDefault();
48
+ const scope = draft.scope ? { sheet: draft.scope } : {};
49
+ try {
50
+ // Check before changing anything, so a failed edit keeps the old name.
51
+ const invalid = sheetState.controller.validateDefinedName(draft.name.trim());
52
+ if (invalid) throw new Error(invalid);
53
+ const formula = draft.refersTo.trim().startsWith('=') ? draft.refersTo.trim() : `=${draft.refersTo.trim()}`;
54
+ try {
55
+ parseFormula(formula);
56
+ } catch (err: any) {
57
+ throw new Error(`There's a problem with this formula: ${err?.message ?? formula}`);
58
+ }
59
+ const original = draft.original;
60
+ if (original) {
61
+ const originalScope = original.sheetId ? { sheet: original.sheetId } : {};
62
+ if ((original.sheetId ?? '') !== draft.scope) {
63
+ sheetState.deleteName(original.name, originalScope);
64
+ } else if (original.name !== draft.name.trim()) {
65
+ sheetState.renameName(original.name, draft.name.trim(), originalScope);
66
+ }
67
+ }
68
+ sheetState.defineName(draft.name.trim(), draft.refersTo, { ...scope, comment: draft.comment || undefined });
69
+ draft = { ...EMPTY_DRAFT };
70
+ error = null;
71
+ } catch (err: any) {
72
+ error = err?.message ?? String(err);
73
+ }
74
+ }
75
+
76
+ function remove(row: SpreadsheetNameRow) {
77
+ sheetState.deleteName(row.name, row.sheetId ? { sheet: row.sheetId } : {});
78
+ if (draft.original?.name === row.name && (draft.original.sheetId ?? '') === (row.sheetId ?? '')) draft = { ...EMPTY_DRAFT };
79
+ }
80
+ </script>
81
+
82
+ <!--
83
+ A simple Name Manager: lists defined names (name, current value, formula,
84
+ scope) and adds, edits, renames and deletes them. Renaming a name rewrites
85
+ the formulas that use it; deleting one leaves them showing #NAME?.
86
+ -->
87
+ <section aria-label="Name Manager" class="flex flex-col gap-2 text-xs {className}" data-name-manager="">
88
+ <div class="flex items-center justify-between">
89
+ <h3 class="m-0 text-sm font-semibold">Name Manager</h3>
90
+ {#if onClose}
91
+ <button type="button" aria-label="Close Name Manager" class="rounded px-2 hover:bg-muted" onclick={onClose}>×</button>
92
+ {/if}
93
+ </div>
94
+ <table class="w-full border-collapse">
95
+ <thead>
96
+ <tr class="text-left text-muted-foreground">
97
+ <th class="px-1 font-medium">Name</th>
98
+ <th class="px-1 font-medium">Value</th>
99
+ <th class="px-1 font-medium">Refers to</th>
100
+ <th class="px-1 font-medium">Scope</th>
101
+ {#if !readOnly}<th class="px-1"></th>{/if}
102
+ </tr>
103
+ </thead>
104
+ <tbody>
105
+ {#if rows.length === 0}
106
+ <tr><td colspan="5" class="px-1 py-2 text-muted-foreground">No names yet.</td></tr>
107
+ {/if}
108
+ {#each rows as row (`${row.sheetId ?? ''}!${row.name}`)}
109
+ <tr data-name={row.name} class="border-t border-border" title={row.comment}>
110
+ <td class="px-1 py-0.5 font-mono font-semibold">{row.name}</td>
111
+ <td class="px-1 py-0.5">{row.value}</td>
112
+ <td class="px-1 py-0.5 font-mono">{row.refersTo}</td>
113
+ <td class="px-1 py-0.5">{row.scopeLabel}</td>
114
+ {#if !readOnly}
115
+ <td class="whitespace-nowrap px-1 py-0.5 text-right">
116
+ <button type="button" aria-label="Edit {row.name}" class="rounded px-1 hover:bg-muted" onclick={() => edit(row)}>Edit</button>
117
+ <button type="button" aria-label="Delete {row.name}" class="rounded px-1 text-destructive hover:bg-muted" onclick={() => remove(row)}>
118
+ Delete
119
+ </button>
120
+ </td>
121
+ {/if}
122
+ </tr>
123
+ {/each}
124
+ </tbody>
125
+ </table>
126
+ {#if !readOnly}
127
+ <form
128
+ class="grid grid-cols-[auto_1fr] items-center gap-x-2 gap-y-1"
129
+ onsubmit={save}
130
+ aria-label={draft.original ? `Edit name ${draft.original.name}` : 'New name'}
131
+ >
132
+ <label for="pixerate-name-manager-name">Name</label>
133
+ <input id="pixerate-name-manager-name" class="rounded border border-border bg-background px-1 py-0.5" bind:value={draft.name} />
134
+ <label for="pixerate-name-manager-refers">Refers to</label>
135
+ <input id="pixerate-name-manager-refers" class="rounded border border-border bg-background px-1 py-0.5 font-mono" bind:value={draft.refersTo} />
136
+ <label for="pixerate-name-manager-scope">Scope</label>
137
+ <select id="pixerate-name-manager-scope" class="rounded border border-border bg-background px-1 py-0.5" bind:value={draft.scope}>
138
+ <option value="">Workbook</option>
139
+ {#each sheetState.sheets as sheet (sheet.id)}
140
+ <option value={sheet.id}>{sheet.name}</option>
141
+ {/each}
142
+ </select>
143
+ <label for="pixerate-name-manager-comment">Comment</label>
144
+ <input id="pixerate-name-manager-comment" class="rounded border border-border bg-background px-1 py-0.5" bind:value={draft.comment} />
145
+ <div class="col-span-2 flex gap-2">
146
+ <button type="submit" class="rounded bg-primary px-2 py-0.5 text-primary-foreground">{draft.original ? 'Save' : 'Add name'}</button>
147
+ {#if draft.original}
148
+ <button
149
+ type="button"
150
+ class="rounded px-2 py-0.5 hover:bg-muted"
151
+ onclick={() => {
152
+ draft = { ...EMPTY_DRAFT };
153
+ error = null;
154
+ }}
155
+ >
156
+ Cancel
157
+ </button>
158
+ {/if}
159
+ </div>
160
+ </form>
161
+ {/if}
162
+ {#if error}
163
+ <div role="alert" class="text-destructive">{error}</div>
164
+ {/if}
165
+ </section>
@@ -0,0 +1,11 @@
1
+ import type { createReactiveSpreadsheet } from './spreadsheet.svelte.js';
2
+ interface Props {
3
+ sheetState: ReturnType<typeof createReactiveSpreadsheet>;
4
+ readOnly?: boolean;
5
+ onClose?: () => void;
6
+ class?: string;
7
+ }
8
+ declare const NameManager: import("svelte").Component<Props, {}, "">;
9
+ type NameManager = ReturnType<typeof NameManager>;
10
+ export default NameManager;
11
+ //# sourceMappingURL=NameManager.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NameManager.svelte.d.ts","sourceRoot":"","sources":["../../src/spreadsheet/NameManager.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAGvE,UAAU,KAAK;IACb,UAAU,EAAE,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAwJH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}