@poirazis/supercomponents-shared 0.0.1

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 (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +66 -0
  3. package/dist/index.js +30635 -0
  4. package/dist/index.umd.cjs +12 -0
  5. package/dist/style.css +1 -0
  6. package/package.json +117 -0
  7. package/src/index.js +29 -0
  8. package/src/index.ts +31 -0
  9. package/src/lib/Actions/autoresize_textarea.js +14 -0
  10. package/src/lib/Actions/click_outside.js +80 -0
  11. package/src/lib/Actions/index.js +4 -0
  12. package/src/lib/Actions/position_dropdown.js +129 -0
  13. package/src/lib/SuperButton/SuperButton.svelte +341 -0
  14. package/src/lib/SuperFieldLabel/SuperFieldLabel.svelte +91 -0
  15. package/src/lib/SuperFieldsCommon.css +54 -0
  16. package/src/lib/SuperList/SuperList.svelte +308 -0
  17. package/src/lib/SuperList/drag-handle.svelte +31 -0
  18. package/src/lib/SuperPopover/SuperPopover.svelte +134 -0
  19. package/src/lib/SuperTable/SuperTable.css +410 -0
  20. package/src/lib/SuperTable/SuperTable.svelte +1332 -0
  21. package/src/lib/SuperTable/constants.js +85 -0
  22. package/src/lib/SuperTable/controls/ColumnsSection.svelte +34 -0
  23. package/src/lib/SuperTable/controls/ControlSection.svelte +3 -0
  24. package/src/lib/SuperTable/controls/RowButtonsColumn.svelte +169 -0
  25. package/src/lib/SuperTable/controls/SelectionColumn.svelte +174 -0
  26. package/src/lib/SuperTable/controls/SuperTableWelcome.svelte +58 -0
  27. package/src/lib/SuperTable/overlays/AddNewRowOverlay.svelte +52 -0
  28. package/src/lib/SuperTable/overlays/EmptyResultSetOverlay.svelte +13 -0
  29. package/src/lib/SuperTable/overlays/LoadingOverlay.svelte +3 -0
  30. package/src/lib/SuperTable/overlays/RowContextMenu copy.svelte +57 -0
  31. package/src/lib/SuperTable/overlays/RowContextMenu.svelte +58 -0
  32. package/src/lib/SuperTable/overlays/ScrollbarsOverlay.svelte +184 -0
  33. package/src/lib/SuperTable/overlays/SelectedActionsOverlay.svelte +64 -0
  34. package/src/lib/SuperTable/state/API.js +0 -0
  35. package/src/lib/SuperTable/state/SuperTableStateMachine.js +0 -0
  36. package/src/lib/SuperTable/types.js +0 -0
  37. package/src/lib/SuperTableCells/CellAttachment.svelte +288 -0
  38. package/src/lib/SuperTableCells/CellBoolean.svelte +158 -0
  39. package/src/lib/SuperTableCells/CellColor.svelte +460 -0
  40. package/src/lib/SuperTableCells/CellCommon.css +319 -0
  41. package/src/lib/SuperTableCells/CellDatetime.svelte +180 -0
  42. package/src/lib/SuperTableCells/CellIcon.svelte +627 -0
  43. package/src/lib/SuperTableCells/CellJSON.svelte +297 -0
  44. package/src/lib/SuperTableCells/CellLink.svelte +274 -0
  45. package/src/lib/SuperTableCells/CellLinkAdvanced.svelte +298 -0
  46. package/src/lib/SuperTableCells/CellLinkPickerSelect.svelte +355 -0
  47. package/src/lib/SuperTableCells/CellLinkPickerTable.svelte +91 -0
  48. package/src/lib/SuperTableCells/CellLinkPickerTree.svelte +226 -0
  49. package/src/lib/SuperTableCells/CellNumber.svelte +179 -0
  50. package/src/lib/SuperTableCells/CellNumberSimple.svelte +56 -0
  51. package/src/lib/SuperTableCells/CellOptions.svelte +631 -0
  52. package/src/lib/SuperTableCells/CellOptionsAdvanced.svelte +684 -0
  53. package/src/lib/SuperTableCells/CellSkeleton.svelte +59 -0
  54. package/src/lib/SuperTableCells/CellString.svelte +178 -0
  55. package/src/lib/SuperTableCells/CellStringSimple.svelte +55 -0
  56. package/src/lib/SuperTableCells/index.js +21 -0
  57. package/src/lib/SuperTableCells/remixIcons.js +6772 -0
  58. package/src/lib/SuperTableColumn/SuperTableColumn.svelte +392 -0
  59. package/src/lib/SuperTableColumn/index.js +9 -0
  60. package/src/lib/SuperTableColumn/parts/SuperColumnBody.svelte +57 -0
  61. package/src/lib/SuperTableColumn/parts/SuperColumnFooter.svelte +14 -0
  62. package/src/lib/SuperTableColumn/parts/SuperColumnHeader.svelte +228 -0
  63. package/src/lib/SuperTableColumn/parts/SuperColumnRow.svelte +142 -0
  64. package/src/lib/SuperTableColumn/parts/SuperColumnRowNew.svelte +34 -0
  65. package/src/lib/SuperTree/SuperTree.svelte +117 -0
  66. package/src/types/svelte-portal.d.ts +1 -0
@@ -0,0 +1,297 @@
1
+ <script>
2
+ import { createEventDispatcher, getContext, onMount } from "svelte";
3
+ import fsm from "svelte-fsm";
4
+ const dispatch = createEventDispatcher();
5
+ const { processStringSync } = getContext("sdk");
6
+ const context = getContext("context");
7
+
8
+ export let value = null;
9
+ export let formattedValue;
10
+ export let cellOptions = {
11
+ role: "formInput",
12
+ initialState: "Editing",
13
+ debounce: 250,
14
+ multiline: true,
15
+ };
16
+ export let autofocus;
17
+
18
+ let timer;
19
+ let originalValue;
20
+ let localValue = null;
21
+ let isValidJson = true;
22
+
23
+ let editor;
24
+ let lastEdit;
25
+
26
+ // Validate JSON string or object
27
+ const validateJson = (input) => {
28
+ if (input === null || input === undefined || input === "") return true; // Allow empty/null/undefined
29
+ try {
30
+ if (typeof input === "string") {
31
+ JSON.parse(input);
32
+ } else {
33
+ // If it's an object, ensure it can be stringified and parsed
34
+ JSON.parse(JSON.stringify(input));
35
+ }
36
+ return true;
37
+ } catch {
38
+ return false;
39
+ }
40
+ };
41
+
42
+ // Convert value to JSON string for internal use
43
+ $: normalizedValue =
44
+ value && validateJson(value) && typeof value !== "string"
45
+ ? JSON.stringify(value)
46
+ : value;
47
+
48
+ // Format JSON for display
49
+ $: displayValue = (() => {
50
+ if (!normalizedValue || normalizedValue === "") return "";
51
+ if (!validateJson(normalizedValue)) return "Invalid JSON";
52
+ return cellOptions.multiline
53
+ ? JSON.stringify(JSON.parse(normalizedValue), null, 2)
54
+ : JSON.stringify(JSON.parse(normalizedValue));
55
+ })();
56
+
57
+ export let cellState = fsm(cellOptions?.initialState ?? "View", {
58
+ "*": {
59
+ goTo(state) {
60
+ return state;
61
+ },
62
+ reset() {
63
+ localValue = normalizedValue;
64
+ lastEdit = undefined;
65
+ isValidJson = true;
66
+ },
67
+ },
68
+ Loading: {},
69
+ View: {
70
+ _enter() {
71
+ localValue = normalizedValue;
72
+ isValidJson = validateJson(value);
73
+ },
74
+ focus() {
75
+ if (!cellOptions.readonly && !cellOptions.disabled) return "Editing";
76
+ else return "Flashing";
77
+ },
78
+ },
79
+ Flashing: {
80
+ _enter() {
81
+ this.returnToView.debounce(230);
82
+ },
83
+ returnToView() {
84
+ return "View";
85
+ },
86
+ },
87
+ Disabled: {},
88
+ Focused: {},
89
+ Error: {
90
+ _enter() {
91
+ this.check.debounce(230);
92
+ },
93
+ check() {
94
+ return "View";
95
+ },
96
+ },
97
+ Readonly: {
98
+ _enter() {
99
+ this.check.debounce(230);
100
+ },
101
+ check() {
102
+ return "View";
103
+ },
104
+ },
105
+ Editing: {
106
+ _enter() {
107
+ originalValue = normalizedValue;
108
+ localValue = normalizedValue;
109
+ isValidJson = validateJson(value);
110
+ dispatch("enteredit");
111
+ },
112
+ _exit() {
113
+ originalValue = undefined;
114
+ dispatch("exitedit");
115
+ dispatch("focusout");
116
+ },
117
+ clear() {
118
+ if (cellOptions.debounce) dispatch("change", null);
119
+ value = null;
120
+ localValue = null;
121
+ isValidJson = true;
122
+ },
123
+ focusout(e) {
124
+ this.submit();
125
+ },
126
+ submit() {
127
+ if (isDirty && isValidJson) {
128
+ dispatch("change", localValue);
129
+ }
130
+ return "View";
131
+ },
132
+ cancel() {
133
+ value = originalValue;
134
+ dispatch("cancel");
135
+ return "View";
136
+ },
137
+ handleKeyboard(e) {
138
+ if (e.key == "Enter" && !cellOptions.multiline) this.submit();
139
+ if (e.key == "Escape") this.cancel();
140
+ },
141
+ },
142
+ });
143
+
144
+ $: cellState.reset(normalizedValue);
145
+ $: inEdit = $cellState == "Editing";
146
+ $: isDirty = lastEdit && originalValue !== localValue;
147
+ $: formattedValue =
148
+ !formattedValue && cellOptions?.template
149
+ ? processStringSync(cellOptions.template, { value: normalizedValue })
150
+ : formattedValue;
151
+
152
+ $: placeholder =
153
+ cellOptions.readonly || cellOptions.disabled
154
+ ? ""
155
+ : cellOptions.placeholder || "";
156
+
157
+ const debounce = (e) => {
158
+ const newValue = e.target.value;
159
+ isValidJson = validateJson(newValue);
160
+ localValue = newValue;
161
+ lastEdit = new Date();
162
+ if (cellOptions?.debounce && isValidJson) {
163
+ clearTimeout(timer);
164
+ timer = setTimeout(() => {
165
+ dispatch("change", localValue);
166
+ }, cellOptions.debounce ?? 0);
167
+ }
168
+ };
169
+
170
+ const focus = (node) => {
171
+ node?.focus();
172
+ };
173
+
174
+ onMount(() => {
175
+ if (autofocus)
176
+ setTimeout(() => {
177
+ cellState.focus();
178
+ }, 50);
179
+ });
180
+ </script>
181
+
182
+ <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
183
+ <!-- svelte-ignore a11y-no-static-element-interactions -->
184
+ <!-- svelte-ignore a11y-click-events-have-key-events -->
185
+ <div
186
+ class="superCell multirow"
187
+ class:inEdit
188
+ class:isDirty={isDirty && cellOptions.showDirty}
189
+ class:focused={inEdit}
190
+ class:inline={cellOptions.role == "inlineInput"}
191
+ class:tableCell={cellOptions.role == "tableCell"}
192
+ class:formInput={cellOptions.role == "formInput"}
193
+ class:disabled={cellOptions.disabled}
194
+ class:readonly={cellOptions.readonly}
195
+ class:error={cellOptions.error || !isValidJson}
196
+ class:multirow={cellOptions.multiline}
197
+ style:color={cellOptions.color}
198
+ style:background={cellOptions.background}
199
+ style:font-weight={cellOptions.fontWeight}
200
+ >
201
+ {#if cellOptions.icon && !cellOptions.multiline}
202
+ <i class={cellOptions.icon + " icon"}></i>
203
+ {/if}
204
+
205
+ {#if inEdit}
206
+ {#if cellOptions.multiline}
207
+ <textarea
208
+ bind:this={editor}
209
+ tabindex="0"
210
+ class="editor"
211
+ class:with-icon={cellOptions.icon}
212
+ class:placeholder={!value && !formattedValue && !localValue}
213
+ value={displayValue}
214
+ placeholder={cellOptions?.placeholder ?? ""}
215
+ style:text-align={cellOptions.align == "center"
216
+ ? "center"
217
+ : cellOptions.align == "flex-end"
218
+ ? "right"
219
+ : "left"}
220
+ style:padding-right={cellOptions.align != "flex-start"
221
+ ? "2rem"
222
+ : "0.75rem"}
223
+ style:white-space="pre-wrap"
224
+ style:overflow-wrap="break-word"
225
+ style:min-height="8rem"
226
+ style:overflow-y="auto"
227
+ style:resize="vertical"
228
+ on:input={debounce}
229
+ on:focusout={cellState.focusout}
230
+ on:keydown={cellState.handleKeyboard}
231
+ use:focus
232
+ />
233
+ {:else}
234
+ <input
235
+ bind:this={editor}
236
+ tabindex="0"
237
+ class="editor"
238
+ class:with-icon={cellOptions.icon}
239
+ class:placeholder={!value && !formattedValue && !localValue}
240
+ value={localValue ?? ""}
241
+ placeholder={cellOptions?.placeholder ?? ""}
242
+ style:text-align={cellOptions.align == "center"
243
+ ? "center"
244
+ : cellOptions.align == "flex-end"
245
+ ? "right"
246
+ : "left"}
247
+ style:padding-right={cellOptions.align != "flex-start"
248
+ ? "2rem"
249
+ : "0.75rem"}
250
+ on:input={debounce}
251
+ on:focusout={cellState.focusout}
252
+ on:keydown={cellState.handleKeyboard}
253
+ use:focus
254
+ />
255
+ {/if}
256
+ {#if localValue && cellOptions?.clearIcon !== false}
257
+ <i
258
+ class="ri-close-line clearIcon"
259
+ on:mousedown|self|preventDefault={cellState.clear}
260
+ />
261
+ {/if}
262
+ {:else}
263
+ <div
264
+ class="value"
265
+ class:multiline={cellOptions.multiline}
266
+ tabindex={cellOptions.readonly || cellOptions.disabled ? "-1" : "0"}
267
+ class:with-icon={cellOptions.icon}
268
+ class:placeholder={!value}
269
+ style:justify-content={cellOptions.align}
270
+ on:focusin={cellState.focus}
271
+ >
272
+ <span>
273
+ {displayValue}
274
+ </span>
275
+ </div>
276
+ {/if}
277
+ </div>
278
+
279
+ <style>
280
+ .superCell .value.multiline {
281
+ white-space: pre-wrap !important;
282
+ text-overflow: unset !important;
283
+ overflow: auto !important;
284
+ font-family: monospace;
285
+ }
286
+ .superCell .value.multiline span {
287
+ white-space: pre-wrap !important;
288
+ text-overflow: unset !important;
289
+ overflow: visible !important;
290
+ height: 8rem;
291
+ width: 100%;
292
+ }
293
+ .superCell .editor {
294
+ width: 100%;
295
+ box-sizing: border-box;
296
+ }
297
+ </style>
@@ -0,0 +1,274 @@
1
+ <script>
2
+ import { createEventDispatcher, getContext } from "svelte";
3
+ import fsm from "svelte-fsm";
4
+ import SuperPopover from "../SuperPopover/SuperPopover.svelte";
5
+ import CellLinkPickerSelect from "./CellLinkPickerSelect.svelte";
6
+ import CellLinkPickerTree from "./CellLinkPickerTree.svelte";
7
+ const dispatch = createEventDispatcher();
8
+ const { API } = getContext("sdk");
9
+
10
+ export let value;
11
+ export let fieldSchema;
12
+ export let cellOptions;
13
+ export let simpleView = true;
14
+ export let filter = [];
15
+ export let limit = 100;
16
+
17
+ // In case of a self referencing relationship, the current row cannot be the parent of itself
18
+ export let ownId;
19
+
20
+ let originalValue = JSON.stringify(value);
21
+ let anchor;
22
+ let popup;
23
+ let search;
24
+ let pickerApi;
25
+
26
+ export let cellState = fsm(cellOptions.initialState ?? "View", {
27
+ "*": {
28
+ goTo(state) {
29
+ return state;
30
+ },
31
+ },
32
+ View: {
33
+ _enter() {},
34
+ focus() {
35
+ if (!cellOptions.readonly && !cellOptions.disabled) return "Editing";
36
+ },
37
+ },
38
+ Hovered: {
39
+ cancel: () => {
40
+ return "View";
41
+ },
42
+ },
43
+ Focused: {
44
+ unfocus() {
45
+ return "View";
46
+ },
47
+ },
48
+ Error: { check: "View" },
49
+ Editing: {
50
+ _enter() {
51
+ originalValue = JSON.stringify(localValue);
52
+ editorState.open();
53
+ dispatch("enteredit");
54
+ },
55
+ _exit() {
56
+ editorState.close();
57
+ dispatch("exitedit");
58
+ },
59
+ focusout(e) {
60
+ if (popup?.contains(e?.relatedTarget)) return;
61
+ this.submit();
62
+ },
63
+
64
+ clear() {
65
+ localValue = [];
66
+ },
67
+ submit() {
68
+ if (isDirty)
69
+ dispatch(
70
+ "change",
71
+ returnSingle && localValue ? localValue[0] : localValue
72
+ );
73
+
74
+ return "View";
75
+ },
76
+ cancel() {
77
+ return "View";
78
+ },
79
+ },
80
+ });
81
+
82
+ const editorState = fsm("Closed", {
83
+ Open: {
84
+ close() {
85
+ return "Closed";
86
+ },
87
+ toggle() {
88
+ return "Closed";
89
+ },
90
+ },
91
+ Closed: {
92
+ open() {
93
+ return "Open";
94
+ },
95
+ toggle() {
96
+ return "Open";
97
+ },
98
+ },
99
+ });
100
+
101
+ $: multi = !fieldSchema?.type?.includes("_single");
102
+ $: isUser = fieldSchema?.type?.includes("bb_reference");
103
+ $: pills = cellOptions.relViewMode == "pills" && !isUser;
104
+ $: valueIcon =
105
+ fieldSchema.type == "link" ? "ri-edit-box-line" : "ri-user-line";
106
+ $: links = cellOptions.relViewMode == "links" && !isUser;
107
+
108
+ $: localValue = enrichValue(value);
109
+ $: inEdit = $cellState == "Editing";
110
+ $: isDirty = inEdit && originalValue != JSON.stringify(localValue);
111
+ $: simpleView = cellOptions.relViewMode == "text";
112
+ $: inline = cellOptions.role == "inlineInput";
113
+ $: multirow =
114
+ cellOptions.controlType == "expanded" && (localValue?.length > 1 || inEdit);
115
+ $: singleSelect =
116
+ fieldSchema?.relationshipType == "one-to-many" ||
117
+ fieldSchema?.relationshipType == "self" ||
118
+ !multi;
119
+
120
+ $: returnSingle = isUser && !multi;
121
+ $: placeholder =
122
+ cellOptions.disabled || cellOptions.readonly
123
+ ? ""
124
+ : cellOptions.placeholder || "";
125
+
126
+ const handleKeyboard = (e) => {
127
+ if (e.key == "Escape" && $editorState == "Open") {
128
+ editorState.close();
129
+ } else if (e.key == "Escape") {
130
+ cellState.cancel();
131
+ } else if (e.keyCode == 32 && $cellState == "Editing") {
132
+ editorState.toggle();
133
+ } else if (e.key == "Tab" && $editorState == "Open") {
134
+ cellState.focusout();
135
+ } else if ($editorState == "Open") {
136
+ pickerApi?.focus();
137
+ }
138
+ };
139
+
140
+ const handleChange = (e) => {
141
+ localValue = e.detail;
142
+
143
+ if (singleSelect) {
144
+ editorState.close();
145
+ }
146
+ };
147
+
148
+ const enrichValue = (x) => {
149
+ if (fieldSchema.relationshipType == "self" && x) {
150
+ API.fetchRow(fieldSchema.tableId, x).then((row) => {
151
+ localValue = [
152
+ { _id: row.id, primaryDisplay: row.name ?? Object.values(row)[0] },
153
+ ];
154
+ });
155
+ return [];
156
+ } else if (multi) {
157
+ return value ? [...value] : [];
158
+ } else {
159
+ return value ? [value] : [];
160
+ }
161
+ };
162
+ </script>
163
+
164
+ <!-- svelte-ignore a11y-click-events-have-key-events -->
165
+ <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
166
+ <!-- svelte-ignore a11y-no-static-element-interactions -->
167
+ <div
168
+ class="superCell"
169
+ tabindex={cellOptions?.disabled ? "-1" : "0"}
170
+ bind:this={anchor}
171
+ class:isDirty={isDirty && cellOptions.showDirty}
172
+ class:inEdit
173
+ class:inline
174
+ class:multirow
175
+ class:tableCell={cellOptions.role == "tableCell"}
176
+ class:formInput={cellOptions.role == "formInput"}
177
+ class:disabled={cellOptions.disabled}
178
+ class:readonly={cellOptions.readonly}
179
+ class:error={cellOptions.error}
180
+ style:color={cellOptions.color}
181
+ style:background={cellOptions.background}
182
+ style:font-weight={cellOptions.fontWeight}
183
+ on:mousedown={editorState.toggle}
184
+ on:focusin={cellState.focus}
185
+ on:keydown|self={handleKeyboard}
186
+ on:focusout={cellState.focusout}
187
+ >
188
+ {#if cellOptions?.icon}
189
+ <i class={cellOptions.icon + " icon"}></i>
190
+ {/if}
191
+
192
+ <div
193
+ class="value"
194
+ class:with-icon={cellOptions?.icon}
195
+ class:placeholder={localValue?.length < 1}
196
+ >
197
+ {#if localValue?.length < 1 && placeholder}
198
+ <span> {placeholder} </span>
199
+ {:else}
200
+ <div class="items" class:pills class:links class:isUser>
201
+ {#each localValue as val, idx}
202
+ {#if idx < 5}
203
+ <div
204
+ class="item"
205
+ on:click={links
206
+ ? () => {
207
+ dispatch("linkClick", val);
208
+ }
209
+ : null}
210
+ >
211
+ <i class={valueIcon} />
212
+ <span>{val.primaryDisplay}</span>
213
+ </div>
214
+ {/if}
215
+ {/each}
216
+
217
+ {#if localValue.length > 5}
218
+ <span class="item-count">
219
+ {localValue.length}
220
+ </span>
221
+ {/if}
222
+ </div>
223
+ {/if}
224
+
225
+ {#if inEdit && localValue?.length}
226
+ <i
227
+ class="ri-close-line clearIcon"
228
+ style:right={"28px"}
229
+ on:mousedown|preventDefault={cellState.clear}
230
+ ></i>
231
+ {/if}
232
+ {#if !cellOptions.readonly && (cellOptions.role == "formInput" || inEdit)}
233
+ <i class="ri-arrow-down-s-line controlIcon"></i>
234
+ {/if}
235
+ </div>
236
+ </div>
237
+
238
+ {#if inEdit}
239
+ <SuperPopover
240
+ {anchor}
241
+ useAnchorWidth
242
+ bind:popup
243
+ open={$editorState == "Open"}
244
+ >
245
+ {#if fieldSchema.recursiveTable || ownId}
246
+ <CellLinkPickerTree
247
+ {fieldSchema}
248
+ filter={filter ?? []}
249
+ {search}
250
+ {limit}
251
+ joinColumn={cellOptions.joinColumn}
252
+ value={localValue}
253
+ {ownId}
254
+ multi={fieldSchema.relationshipType == "many-to-many" ||
255
+ fieldSchema.relationshipType == "many-to-one"}
256
+ on:change={handleChange}
257
+ />
258
+ {:else}
259
+ <CellLinkPickerSelect
260
+ bind:api={pickerApi}
261
+ {fieldSchema}
262
+ filter={filter ?? []}
263
+ {singleSelect}
264
+ value={localValue}
265
+ {search}
266
+ wide={cellOptions.wide && !singleSelect}
267
+ on:change={handleChange}
268
+ on:close={() => {
269
+ cellState.focusout();
270
+ }}
271
+ />
272
+ {/if}
273
+ </SuperPopover>
274
+ {/if}