@poirazis/supercomponents-shared 1.1.8 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/index.js +21416 -40369
  2. package/dist/index.umd.cjs +19 -26
  3. package/dist/style.css +1 -1
  4. package/package.json +3 -3
  5. package/src/index.js +4 -0
  6. package/src/index.ts +3 -0
  7. package/src/lib/Actions/index.js +3 -3
  8. package/src/lib/SuperButton/SuperButton.svelte +34 -3
  9. package/src/lib/SuperForm/InnerForm.svelte +1 -1
  10. package/src/lib/SuperList/SuperList.svelte +2 -2
  11. package/src/lib/SuperList/drag-handle.svelte +8 -8
  12. package/src/lib/SuperTable/SuperTable.css +8 -3
  13. package/src/lib/SuperTable/SuperTable.svelte +3 -3
  14. package/src/lib/SuperTable/controls/PaginationLimitOffset.svelte +2 -0
  15. package/src/lib/SuperTable/controls/SelectionColumn.svelte +18 -49
  16. package/src/lib/SuperTable/controls/SuperTableWelcome.svelte +1 -1
  17. package/src/lib/SuperTable/overlays/AddNewRowOverlay.svelte +3 -3
  18. package/src/lib/SuperTable/overlays/EmptyResultSetOverlay.svelte +1 -1
  19. package/src/lib/SuperTable/overlays/ScrollbarsOverlay.svelte +43 -43
  20. package/src/lib/SuperTableCells/CellAttachmentExpanded.svelte +1 -1
  21. package/src/lib/SuperTableCells/CellAttachmentSlider.svelte +2 -3
  22. package/src/lib/SuperTableCells/CellBoolean.svelte +1 -1
  23. package/src/lib/SuperTableCells/CellColor.svelte +7 -7
  24. package/src/lib/SuperTableCells/CellCommon.css +1 -1
  25. package/src/lib/SuperTableCells/CellIcon.svelte +7 -7
  26. package/src/lib/SuperTableCells/CellJSON.svelte +2 -2
  27. package/src/lib/SuperTableCells/CellLink.svelte +50 -43
  28. package/src/lib/SuperTableCells/CellLinkAdvanced.svelte +2 -15
  29. package/src/lib/SuperTableCells/CellLinkPickerSelect.svelte +10 -11
  30. package/src/lib/SuperTableCells/CellLinkPickerTree.svelte +4 -2
  31. package/src/lib/SuperTableCells/CellNumber.svelte +24 -5
  32. package/src/lib/SuperTableCells/CellOptions.svelte +11 -23
  33. package/src/lib/SuperTableCells/CellOptionsAdvanced.svelte +5 -5
  34. package/src/lib/SuperTableCells/CellSQLLink.svelte +0 -11
  35. package/src/lib/SuperTableCells/CellSQLLinkPicker.svelte +9 -9
  36. package/src/lib/SuperTableCells/CellString.svelte +3 -3
  37. package/src/lib/SuperTableCells/CellStringMask.svelte +1 -1
  38. package/src/lib/SuperTableCells/CellTags.svelte +151 -108
  39. package/src/lib/SuperTableCells/JSDOC_GUIDE.md +163 -3
  40. package/src/lib/SuperTableCells/types.js +141 -192
  41. package/src/lib/SuperTableColumn/SuperTableColumn.svelte +1 -1
  42. package/src/lib/SuperTableColumn/parts/SuperColumnHeader.svelte +2 -2
  43. package/src/lib/SuperTableColumn/parts/SuperColumnRow.svelte +5 -3
  44. package/src/lib/SuperTabs/SuperTabs.svelte +2 -2
  45. package/src/lib/SuperTree/SuperTree.svelte +84 -38
  46. package/src/lib/UI/elements/Checkbox.svelte +36 -6
  47. package/src/lib/UI/elements/IconButton.svelte +115 -0
  48. package/src/lib/UI/elements/Tooltip.svelte +65 -0
@@ -13,7 +13,7 @@
13
13
 
14
14
  export let cellOptions;
15
15
  export let value;
16
- export let fieldSchema;
16
+
17
17
  export let autofocus;
18
18
 
19
19
  let anchor;
@@ -35,6 +35,33 @@
35
35
 
36
36
  let searchInput;
37
37
 
38
+ // Helper function to add tags while preventing duplicates (case-insensitive comparison)
39
+ const addUniqueTags = (tagsToAdd) => {
40
+ if (!tagsToAdd || !tagsToAdd.length) return;
41
+
42
+ const existingLower = new Set(
43
+ (localValue || []).map((t) =>
44
+ String(t || "")
45
+ .toLowerCase()
46
+ .trim()
47
+ )
48
+ );
49
+
50
+ const newTags = [];
51
+ tagsToAdd.forEach((tag) => {
52
+ const trimmedTag = String(tag || "").trim();
53
+ if (trimmedTag && !existingLower.has(trimmedTag.toLowerCase())) {
54
+ newTags.push(trimmedTag);
55
+ existingLower.add(trimmedTag.toLowerCase());
56
+ }
57
+ });
58
+
59
+ if (newTags.length) {
60
+ localValue = [...(localValue || []), ...newTags];
61
+ cellState.change();
62
+ }
63
+ };
64
+
38
65
  const colors = derivedMemo(options, ($options) => {
39
66
  let obj = {};
40
67
  $options.forEach(
@@ -179,16 +206,25 @@
179
206
  },
180
207
  Editing: {
181
208
  _enter() {
182
- originalValue = JSON.stringify(value);
209
+ originalValue = JSON.stringify(
210
+ Array.isArray(value) ? value : value ? [value] : []
211
+ );
183
212
  this.clearFilters();
213
+ editorState.open();
184
214
  dispatch("enteredit");
185
215
  },
186
216
  _exit() {
187
217
  editorState.close();
188
218
  dispatch("exitedit");
189
219
  },
220
+ focus() {
221
+ anchor?.focus();
222
+ },
190
223
  focusout(e) {
191
- if ($editorState == "Open" || anchor?.contains(e.relatedTarget)) {
224
+ if (
225
+ anchor?.contains(e.relatedTarget) ||
226
+ editor?.contains(e.relatedTarget)
227
+ ) {
192
228
  return;
193
229
  } else {
194
230
  this.submit();
@@ -215,6 +251,8 @@
215
251
  this.submit();
216
252
  },
217
253
  cancel() {
254
+ editorState.close();
255
+ localValue = JSON.parse(originalValue);
218
256
  anchor?.blur();
219
257
  return "View";
220
258
  },
@@ -238,8 +276,8 @@
238
276
  localValue.splice(pos, 1);
239
277
  localValue = [...localValue];
240
278
  } else {
241
- // Add if not selected
242
- localValue = [...localValue, option];
279
+ // Add only if not already in localValue
280
+ addUniqueTags([option]);
243
281
  }
244
282
  cellState.change();
245
283
  // Check if we need to fetch more options
@@ -254,8 +292,8 @@
254
292
  localValue.splice(pos, 1);
255
293
  localValue = [...localValue];
256
294
  } else {
257
- // Add if not selected
258
- localValue = [...localValue, option];
295
+ // Add only if not already in localValue
296
+ addUniqueTags([option]);
259
297
  }
260
298
  cellState.change();
261
299
  // Check if we need to fetch more options
@@ -277,8 +315,7 @@
277
315
  .split(",")
278
316
  .map((tag) => tag.trim())
279
317
  .filter((tag) => tag);
280
- localValue = [...localValue, ...tags];
281
- cellState.change();
318
+ addUniqueTags(tags);
282
319
  }
283
320
  searchTerm = "";
284
321
  newTag = null;
@@ -329,14 +366,11 @@
329
366
  if (e.key == "Enter") {
330
367
  // Add new tag if exists
331
368
  if (newTag?.trim()) {
332
- localValue = [
333
- ...localValue,
334
- ...newTag
335
- .split(",")
336
- .map((tag) => tag.trim())
337
- .filter((tag) => tag),
338
- ];
339
- cellState.change();
369
+ const tags = newTag
370
+ .split(",")
371
+ .map((tag) => tag.trim())
372
+ .filter((tag) => tag);
373
+ addUniqueTags(tags);
340
374
  newTag = null;
341
375
  searchTerm = "";
342
376
  // Refocus input
@@ -353,16 +387,29 @@
353
387
  // If no focused option, allow space to be input into the search box
354
388
  }
355
389
  if (e.key == "Tab") {
356
- if (focusedOptionIdx > -1 && filteredOptions[focusedOptionIdx])
357
- this.toggleOption(focusedOptionIdx);
390
+ anchor?.focus();
391
+ editorState.close();
392
+ e.preventDefault();
393
+ return;
394
+ }
358
395
 
359
- // Keep popup open - no submit/close
396
+ if (e.key == "Escape") {
397
+ newTag = null;
398
+
399
+ editorState.close();
400
+ anchor?.focus();
401
+
402
+ e.preventDefault();
403
+ e.stopPropagation();
404
+ return;
360
405
  }
361
406
 
362
407
  if (e.key == "ArrowDown") this.highlightNext(e.stopPropagation());
363
408
  if (e.key == "ArrowUp")
364
409
  this.highlightPrevious(e.preventDefault(), e.stopPropagation());
365
- if (e.key == "Escape") this.close();
410
+ if (e.key == "Escape") {
411
+ cellState.cancel();
412
+ }
366
413
  },
367
414
 
368
415
  handleKeyboard(e) {
@@ -389,8 +436,6 @@
389
436
  if (e.key == "ArrowDown") this.highlightNext();
390
437
  if (e.key == "ArrowUp") this.highlightPrevious(e.preventDefault());
391
438
 
392
- if (e.key == "Escape") this.close();
393
-
394
439
  if (controlType != "inputSelect") search = true;
395
440
  },
396
441
  highlightNext() {
@@ -526,19 +571,16 @@
526
571
  class:multirow={true}
527
572
  style:color
528
573
  style:background
529
- style:font-weight={cellOptions.fontWeight}
530
574
  class:inline={role == "inlineInput"}
531
575
  class:tableCell={role == "tableCell"}
532
576
  class:formInput={role == "formInput"}
533
577
  on:focusin={cellState.focus}
534
- on:focusout={(e) => {
535
- setTimeout(() => cellState.focusout(e), 50);
536
- }}
578
+ on:focusout={cellState.focusout}
537
579
  on:keydown={editorState.handleKeyboard}
538
580
  >
539
581
  <div class="value" class:placeholder={isEmpty} tabindex="-1">
540
582
  {#if isEmpty && !inEdit}
541
- <span>{cellOptions.placeholder || "No Tags"}</span>
583
+ <span>{cellOptions.placeholder || "Add some Tags"}</span>
542
584
  {/if}
543
585
 
544
586
  <div
@@ -553,7 +595,6 @@
553
595
  class="tag"
554
596
  style:--option-color={$colors[tag] ||
555
597
  colorsArray[idx % colorsArray.length]}
556
- tabindex="-1"
557
598
  >
558
599
  <span class="tag-wrap">
559
600
  <span> {tag} </span>
@@ -565,7 +606,7 @@
565
606
  style:z-index={2}
566
607
  on:mousedown|preventDefault|stopPropagation={() =>
567
608
  editorState.toggleOption(tag)}
568
- />
609
+ ></i>
569
610
  {/if}
570
611
  </div>
571
612
  {/each}
@@ -573,8 +614,8 @@
573
614
 
574
615
  {#if inEdit}
575
616
  <i
576
- class="ph ph-plus-circle actionIcon"
577
- on:mousedown|preventDefault|stopPropagation={editorState.toggle}
617
+ class="ph ph-plus actionIcon"
618
+ on:mouseup|preventDefault|stopPropagation={editorState.toggle}
578
619
  ></i>
579
620
  {/if}
580
621
  </div>
@@ -589,83 +630,78 @@
589
630
  useAnchorWidth
590
631
  maxHeight={250}
591
632
  open={$editorState == "Open"}
592
- on:close={(e) => {
593
- editorState.close();
594
- cellState.focusout({});
595
- }}
596
633
  >
597
- <div class="searchControl" on:keydown={editorState.handleInputKeyboard}>
598
- <i
599
- class={suggestions ? "ph ph-magnifying-glass" : "ph ph-pencil-simple"}
600
- class:actionIcon={true}
601
- ></i>
602
- <input
603
- type="text"
604
- placeholder={suggestions ? "Search or Add" : "Enter tag..."}
605
- class="searchInput"
606
- bind:value={searchTerm}
607
- bind:this={searchInput}
608
- on:input={(e) => editorState.filterOptions(e.target.value)}
609
- on:focusout={(e) => {
610
- editorState.close();
611
- anchor?.focus();
612
- }}
613
- use:focus
614
- />
615
- </div>
634
+ <div bind:this={editor} class="editor" tabindex="-1">
635
+ <div class="searchControl" on:keydown={editorState.handleInputKeyboard}>
636
+ <i
637
+ class={suggestions ? "ph ph-magnifying-glass" : "ph ph-pencil-simple"}
638
+ class:actionIcon={true}
639
+ ></i>
640
+ <input
641
+ type="text"
642
+ placeholder={suggestions ? "Search or Add" : "Enter tag..."}
643
+ class="searchInput"
644
+ bind:value={searchTerm}
645
+ bind:this={searchInput}
646
+ on:input={(e) => editorState.filterOptions(e.target.value)}
647
+ on:focusout={cellState.focusout}
648
+ />
649
+ </div>
616
650
 
617
- {#if suggestions}
618
- <div
619
- bind:this={picker}
620
- class="options"
621
- on:wheel={(e) => e.stopPropagation()}
622
- on:mouseleave={() => (focusedOptionIdx = -1)}
623
- on:scroll={suggestions ? handleScroll : null}
624
- >
625
- {#if suggestions}
626
- {#if $fetch?.loading && !$fetch?.rows?.length}
627
- <div class="option loading">
628
- <i class="ri-loader-2-line rotating" />
629
- Loading...
630
- </div>
631
- {:else if filteredOptions?.length}
632
- {#each filteredOptions as option, idx (idx)}
633
- {#if !localValue?.includes(option)}
634
- <div
635
- class="option"
636
- class:text={optionsViewMode == "text"}
637
- class:focused={focusedOptionIdx === idx}
638
- style:--option-color={$colors[option]}
639
- on:mousedown|preventDefault={(e) =>
640
- editorState.toggleOption(idx)}
641
- on:mouseenter={() => (focusedOptionIdx = idx)}
642
- >
643
- <span>
644
- {#if cellOptions.optionsViewMode !== "text"}
645
- <i class="ri-checkbox-blank-fill" />
646
- {/if}
647
- {option}
648
- </span>
651
+ {#if suggestions}
652
+ <div
653
+ bind:this={picker}
654
+ class="options"
655
+ on:wheel={(e) => e.stopPropagation()}
656
+ on:mouseleave={() => (focusedOptionIdx = -1)}
657
+ on:scroll={suggestions ? handleScroll : null}
658
+ on:mousedown|preventDefault|stopPropagation
659
+ >
660
+ {#if suggestions}
661
+ {#if $fetch?.loading && !$fetch?.rows?.length}
662
+ <div class="option loading">
663
+ <i class="ri-loader-2-line rotating"></i>
664
+ Loading...
665
+ </div>
666
+ {:else if filteredOptions?.length}
667
+ {#each filteredOptions as option, idx (idx)}
668
+ {#if !localValue?.includes(option)}
669
+ <div
670
+ class="option"
671
+ class:text={optionsViewMode == "text"}
672
+ class:focused={focusedOptionIdx === idx}
673
+ style:--option-color={$colors[option]}
674
+ on:mousedown|preventDefault={(e) =>
675
+ editorState.toggleOption(idx)}
676
+ on:mouseenter={() => (focusedOptionIdx = idx)}
677
+ >
678
+ <span>
679
+ {#if cellOptions.optionsViewMode !== "text"}
680
+ <i class="ri-checkbox-blank-fill"></i>
681
+ {/if}
682
+ {option}
683
+ </span>
684
+ </div>
685
+ {/if}
686
+ {/each}
687
+ {#if $fetch?.loading}
688
+ <div class="option loading">
689
+ <i class="ri-loader-2-line rotating"></i>
690
+ Loading more...
649
691
  </div>
650
692
  {/if}
651
- {/each}
652
- {#if $fetch?.loading}
653
- <div class="option loading">
654
- <i class="ri-loader-2-line rotating" />
655
- Loading more...
693
+ {:else}
694
+ <div class="option not-found">
695
+ <span>
696
+ <i class="ri-close-line"></i>
697
+ No matches found, Tag will be added as new
698
+ </span>
656
699
  </div>
657
700
  {/if}
658
- {:else}
659
- <div class="option not-found">
660
- <span>
661
- <i class="ri-close-line" />
662
- No matches found, Tag will be added as new
663
- </span>
664
- </div>
665
701
  {/if}
666
- {/if}
667
- </div>
668
- {/if}
702
+ </div>
703
+ {/if}
704
+ </div>
669
705
  </SuperPopover>
670
706
  {/if}
671
707
 
@@ -697,9 +733,15 @@
697
733
  text-transform: uppercase;
698
734
  outline: none;
699
735
  max-width: 7rem;
736
+ transition: all 0.2s ease-in-out;
700
737
 
701
738
  &:hover {
702
739
  filter: brightness(0.9);
740
+
741
+ & > i {
742
+ display: block;
743
+ cursor: pointer;
744
+ }
703
745
  }
704
746
 
705
747
  & > span {
@@ -707,6 +749,12 @@
707
749
  text-overflow: ellipsis;
708
750
  white-space: nowrap;
709
751
  }
752
+
753
+ & > i {
754
+ display: none;
755
+ cursor: pointer;
756
+ transition: all 0.2s ease-in-out;
757
+ }
710
758
  }
711
759
 
712
760
  .searchControl {
@@ -745,11 +793,6 @@
745
793
  cursor: pointer;
746
794
  }
747
795
 
748
- &.selected {
749
- color: var(--spectrum-global-color-gray-800);
750
- font-weight: 600;
751
- }
752
-
753
796
  &.focused {
754
797
  background-color: var(--spectrum-global-color-gray-75);
755
798
  color: var(--spectrum-global-color-gray-800);
@@ -805,7 +848,7 @@
805
848
  display: flex;
806
849
  justify-content: center;
807
850
  align-items: center;
808
- font-size: 1rem;
851
+ font-size: 0.85rem;
809
852
  color: var(--spectrum-global-color-gray-600);
810
853
  }
811
854
  .actionIcon:hover {
@@ -26,7 +26,167 @@ This guide demonstrates how to use JSDoc annotations for **type definitions only
26
26
 
27
27
  ## Type Definitions
28
28
 
29
- All types are defined in `types.js` using JSDoc `@typedef` syntax.
29
+ All types are defined in `types.js` using a **unified CellOptions type**:
30
+
31
+ - `CellOptions` - Single type with common base properties + optional type-specific extensions
32
+ - `CellApi` - Standard API interface exported by all cells
33
+ - `CellRole`, `CellState`, `CellAlign` - Enum types
34
+ - `FieldSchema` - Budibase field schema type
35
+
36
+ ### CellOptions Structure
37
+
38
+ The unified `CellOptions` type contains:
39
+
40
+ - **Common properties** (role, readonly, disabled, placeholder, etc.) - used by all cells
41
+ - **Type-specific properties** organized by category (Number, Boolean, Options, Datetime, etc.)
42
+
43
+ All properties are optional except where noted. Components only use the properties relevant to them.
44
+
45
+ ## Cell FSM State Machine
46
+
47
+ All cell components use a finite state machine (FSM) managed by `svelte-fsm` to handle user interactions and data loading states. The FSM provides a clean, declarative way to manage component state transitions.
48
+
49
+ ### Core States
50
+
51
+ The cell FSM supports three core reachable states:
52
+
53
+ | State | Usage | Transitions |
54
+ | ----------- | --------------------------------------- | --------------------------------------- |
55
+ | **View** | Default display state, read-only | → Editing (on focus) |
56
+ | **Editing** | User is actively editing the cell value | → View (on focusout, submit, or cancel) |
57
+ | **Loading** | Data is being fetched or processed | → View (when data loads) |
58
+
59
+ ### State Diagram
60
+
61
+ ```
62
+ ┌──────────────────────────────────┐
63
+ │ │
64
+ │ View (Display Mode) │
65
+ │ - Shows formatted value │
66
+ │ - Read-only or ready to edit │
67
+ │ │
68
+ └──────────────────────────────────┘
69
+
70
+ │ focusout()
71
+ │ submit()
72
+ │ cancel()
73
+
74
+
75
+ ┌──────────────────────────────────┐
76
+ │ │
77
+ │ Editing (Edit Mode) │
78
+ │ - Input field active │
79
+ │ - User can modify value │
80
+ │ - Dispatch change events │
81
+ │ │
82
+ └──────────────────────────────────┘
83
+
84
+ │ focus()
85
+ │ (when not readonly)
86
+
87
+ ┌──────────────────────────────────┐
88
+ │ │
89
+ │ Loading (Async Mode) │
90
+ │ - Fetching data from server │
91
+ │ - Data-dependent cells only │
92
+ │ - Auto-transitions to View │
93
+ │ │
94
+ └──────────────────────────────────┘
95
+ ```
96
+
97
+ ### Global Transitions (Available in All States)
98
+
99
+ All states support these global methods via the `"*"` state:
100
+
101
+ ```javascript
102
+ export const cellState = fsm("View", {
103
+ "*": {
104
+ goTo(state) {
105
+ // Manual state transition (for external control)
106
+ return state;
107
+ },
108
+ reset(value) {
109
+ // Reset to initial value and View state
110
+ localValue = undefined;
111
+ },
112
+ },
113
+ // ... state-specific transitions
114
+ });
115
+ ```
116
+
117
+ ### Lifecycle Hooks
118
+
119
+ State transitions can trigger lifecycle methods:
120
+
121
+ - **`_enter()`** - Called when entering a state
122
+ - **`_exit()`** - Called when exiting a state
123
+
124
+ Example from CellString:
125
+
126
+ ```javascript
127
+ Editing: {
128
+ _enter() {
129
+ originalValue = JSON.stringify(localValue); // Save for rollback
130
+ dispatch("enteredit"); // Notify parent
131
+ },
132
+ _exit() {
133
+ dispatch("exitedit"); // Cleanup
134
+ },
135
+ focusout() {
136
+ this.submit(); // Submit on blur
137
+ },
138
+ submit() {
139
+ dispatch("change", localValue);
140
+ return "View"; // Transition back to View
141
+ },
142
+ },
143
+ ```
144
+
145
+ ### Usage Pattern
146
+
147
+ ```javascript
148
+ // Declare FSM with initial state
149
+ export const cellState = fsm(cellOptions.initialState ?? "View", {
150
+ View: {
151
+ /* ... */
152
+ },
153
+ Editing: {
154
+ /* ... */
155
+ },
156
+ Loading: {
157
+ /* ... */
158
+ }, // Optional, for data-dependent cells
159
+ });
160
+
161
+ // Subscribe to state changes in component
162
+ $: inEdit = $cellState === "Editing";
163
+ $: isDirty = inEdit && originalValue !== JSON.stringify(localValue);
164
+
165
+ // Trigger transitions from event handlers
166
+ const handleFocus = () => cellState.focus();
167
+ const handleBlur = () => cellState.focusout();
168
+ ```
169
+
170
+ ### Data-Dependent Cells
171
+
172
+ Cells that fetch data (CellOptions, CellTags, CellOptionsAdvanced) use the Loading state:
173
+
174
+ ```javascript
175
+ Loading: {
176
+ _enter() {
177
+ // Fetch data from server
178
+ loadOptions();
179
+ },
180
+ syncFetch(fetch) {
181
+ // Handle synchronous fetch results
182
+ return "View"; // Auto-transition when done
183
+ },
184
+ focus() {
185
+ // Allow editing while loading
186
+ return "Editing";
187
+ },
188
+ },
189
+ ```
30
190
 
31
191
  ## JavaScript Example: CellString.svelte (Reference Implementation)
32
192
 
@@ -36,7 +196,7 @@ All types are defined in `types.js` using JSDoc `@typedef` syntax.
36
196
  import fsm from "svelte-fsm";
37
197
 
38
198
  /**
39
- * @typedef {import('./types.js').CellStringOptions} CellStringOptions
199
+ * @typedef {import('./types.js').CellOptions} CellOptions
40
200
  * @typedef {import('./types.js').CellApi} CellApi
41
201
  */
42
202
 
@@ -49,7 +209,7 @@ All types are defined in `types.js` using JSDoc `@typedef` syntax.
49
209
  /** @type {string | undefined} */
50
210
  export let formattedValue = undefined;
51
211
 
52
- /** @type {CellStringOptions} */
212
+ /** @type {CellOptions} */
53
213
  export let cellOptions = {
54
214
  role: "formInput",
55
215
  initialState: "Editing",