@poirazis/supercomponents-shared 1.0.26 → 1.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +19311 -18109
- package/dist/index.umd.cjs +12 -12
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/lib/SuperButton/SuperButton.svelte +20 -5
- package/src/lib/SuperField/SuperField.svelte +10 -1
- package/src/lib/SuperTable/SuperTable.css +14 -10
- package/src/lib/SuperTable/SuperTable.svelte +39 -30
- package/src/lib/SuperTable/controls/ColumnsSection.svelte +1 -1
- package/src/lib/SuperTable/controls/RowButtonsColumn.svelte +16 -11
- package/src/lib/SuperTable/controls/SelectionColumn.svelte +85 -60
- package/src/lib/SuperTable/overlays/ScrollbarsOverlay.svelte +1 -1
- package/src/lib/SuperTableCells/CellBoolean.svelte +36 -28
- package/src/lib/SuperTableCells/CellCommon.css +84 -19
- package/src/lib/SuperTableCells/CellDateRange.svelte +597 -0
- package/src/lib/SuperTableCells/CellDatetime.svelte +161 -8
- package/src/lib/SuperTableCells/CellLink.svelte +36 -14
- package/src/lib/SuperTableCells/CellLinkPickerSelect.svelte +9 -9
- package/src/lib/SuperTableCells/CellNumber.svelte +67 -40
- package/src/lib/SuperTableCells/CellOptions.svelte +12 -9
- package/src/lib/SuperTableCells/CellString.svelte +12 -8
- package/src/lib/SuperTableCells/index.js +1 -1
- package/src/lib/SuperTableColumn/SuperTableColumn.svelte +4 -0
- package/src/lib/SuperTableColumn/parts/SuperColumnRow.svelte +36 -23
- package/src/lib/SuperTree/SuperTree.svelte +2 -2
- package/src/lib/SuperTableCells/CellLinkPickerTable.svelte +0 -91
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
const { processStringSync } = getContext("sdk");
|
|
7
7
|
import fsm from "svelte-fsm";
|
|
8
8
|
|
|
9
|
-
const context = getContext("context");
|
|
10
|
-
|
|
11
9
|
export let value;
|
|
12
10
|
export let formattedValue;
|
|
13
11
|
export let cellOptions;
|
|
@@ -54,7 +52,10 @@
|
|
|
54
52
|
}
|
|
55
53
|
},
|
|
56
54
|
focusout(e) {
|
|
57
|
-
|
|
55
|
+
const isInPicker = picker?.contains(e.relatedTarget);
|
|
56
|
+
const isInTimePicker = timePicker?.contains(e.relatedTarget);
|
|
57
|
+
|
|
58
|
+
if (!isInPicker && !isInTimePicker) {
|
|
58
59
|
open = false;
|
|
59
60
|
if (value != originalValue) {
|
|
60
61
|
dispatch("change", value);
|
|
@@ -73,10 +74,81 @@
|
|
|
73
74
|
|
|
74
75
|
let anchor;
|
|
75
76
|
let picker;
|
|
77
|
+
let timePicker;
|
|
76
78
|
let open;
|
|
77
79
|
|
|
80
|
+
// Current date format and showTime - extracted to ensure reactivity
|
|
81
|
+
$: currentDateFormat = cellOptions?.dateFormat;
|
|
82
|
+
$: currentShowTime = cellOptions?.showTime;
|
|
83
|
+
|
|
84
|
+
// Time value (format: HH:mm)
|
|
85
|
+
$: timeValue = currentShowTime && value ? getTimeFromValue() : "00:00";
|
|
86
|
+
|
|
78
87
|
$: innerDate = value ? new Date(value) : new Date();
|
|
79
88
|
|
|
89
|
+
// Extract time from current value if it exists
|
|
90
|
+
function getTimeFromValue() {
|
|
91
|
+
if (!value) return "00:00";
|
|
92
|
+
const date = new Date(value);
|
|
93
|
+
return `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Date formatting helper function
|
|
97
|
+
function formatDate(date, dateFormat) {
|
|
98
|
+
if (!dateFormat || dateFormat === "default") {
|
|
99
|
+
return date.toDateString();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Manual formatting for specific formats to ensure exact order
|
|
103
|
+
if (dateFormat === "MM/DD/YYYY") {
|
|
104
|
+
return `${(date.getMonth() + 1).toString().padStart(2, "0")}/${date.getDate().toString().padStart(2, "0")}/${date.getFullYear()}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (dateFormat === "DD/MM/YYYY") {
|
|
108
|
+
return `${date.getDate().toString().padStart(2, "0")}/${(date.getMonth() + 1).toString().padStart(2, "0")}/${date.getFullYear()}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (dateFormat === "YYYY-MM-DD") {
|
|
112
|
+
return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// For shorter formats, still use locale-specific formatting
|
|
116
|
+
const options = {
|
|
117
|
+
"MMM DD, YYYY": {
|
|
118
|
+
month: "short",
|
|
119
|
+
day: "numeric",
|
|
120
|
+
year: "numeric",
|
|
121
|
+
timeZone: "UTC",
|
|
122
|
+
},
|
|
123
|
+
"DD MMM YYYY": {
|
|
124
|
+
day: "numeric",
|
|
125
|
+
month: "short",
|
|
126
|
+
year: "numeric",
|
|
127
|
+
timeZone: "UTC",
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const formatOption = options[dateFormat];
|
|
132
|
+
if (formatOption) {
|
|
133
|
+
return date.toLocaleDateString("en-US", formatOption);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Fallback to default
|
|
137
|
+
return date.toDateString();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// DateTime formatting helper function
|
|
141
|
+
function formatDateTime(date, dateFormat, showTime) {
|
|
142
|
+
if (!showTime) {
|
|
143
|
+
return formatDate(date, dateFormat);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const formattedDate = formatDate(date, dateFormat);
|
|
147
|
+
const timeString = `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`;
|
|
148
|
+
|
|
149
|
+
return `${formattedDate} ${timeString}`;
|
|
150
|
+
}
|
|
151
|
+
|
|
80
152
|
$: formattedValue =
|
|
81
153
|
cellOptions.template && value
|
|
82
154
|
? processStringSync(cellOptions.template, { value })
|
|
@@ -98,6 +170,22 @@
|
|
|
98
170
|
editor?.focus();
|
|
99
171
|
}, 30);
|
|
100
172
|
});
|
|
173
|
+
|
|
174
|
+
// Handle time picker changes
|
|
175
|
+
const handleTimeChange = (e) => {
|
|
176
|
+
if (!value || !currentShowTime) return;
|
|
177
|
+
|
|
178
|
+
const newTime = e.target.value;
|
|
179
|
+
const currentDate = new Date(value);
|
|
180
|
+
const [hours, minutes] = newTime.split(":").map(Number);
|
|
181
|
+
|
|
182
|
+
// Update the date with the new time
|
|
183
|
+
currentDate.setHours(hours, minutes, 0, 0);
|
|
184
|
+
value = currentDate.toISOString();
|
|
185
|
+
|
|
186
|
+
// Keep the popover open for time changes
|
|
187
|
+
dispatch("change", value);
|
|
188
|
+
};
|
|
101
189
|
</script>
|
|
102
190
|
|
|
103
191
|
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
|
@@ -131,11 +219,19 @@
|
|
|
131
219
|
class="editor"
|
|
132
220
|
class:with-icon={cellOptions.icon}
|
|
133
221
|
class:placeholder={!value && !formattedValue}
|
|
134
|
-
{value}
|
|
135
|
-
placeholder={cellOptions?.placeholder ?? ""}
|
|
136
222
|
on:click={() => (open = !open)}
|
|
137
223
|
>
|
|
138
|
-
{formattedValue
|
|
224
|
+
{#if formattedValue}
|
|
225
|
+
{formattedValue}
|
|
226
|
+
{:else if value}
|
|
227
|
+
{currentDateFormat
|
|
228
|
+
? formatDateTime(innerDate, currentDateFormat, currentShowTime)
|
|
229
|
+
: currentShowTime
|
|
230
|
+
? innerDate?.toDateString() + " " + timeValue
|
|
231
|
+
: innerDate?.toDateString()}
|
|
232
|
+
{:else}
|
|
233
|
+
{cellOptions?.placeholder}
|
|
234
|
+
{/if}
|
|
139
235
|
<i
|
|
140
236
|
class="ri-calendar-line"
|
|
141
237
|
style="font-size: 16px; justify-self: flex-end"
|
|
@@ -152,7 +248,11 @@
|
|
|
152
248
|
{formattedValue
|
|
153
249
|
? formattedValue
|
|
154
250
|
: value
|
|
155
|
-
?
|
|
251
|
+
? currentDateFormat
|
|
252
|
+
? formatDateTime(innerDate, currentDateFormat, currentShowTime)
|
|
253
|
+
: currentShowTime
|
|
254
|
+
? innerDate?.toDateString() + " " + timeValue
|
|
255
|
+
: innerDate?.toDateString()
|
|
156
256
|
: placeholder}
|
|
157
257
|
</span>
|
|
158
258
|
</div>
|
|
@@ -163,7 +263,8 @@
|
|
|
163
263
|
<SuperPopover {anchor} dismissible={false} {open} align="right">
|
|
164
264
|
<div
|
|
165
265
|
bind:this={picker}
|
|
166
|
-
|
|
266
|
+
class="datetime-picker-container"
|
|
267
|
+
style:--date-picker-background="var(--spectrum-global-color-gray-75)"
|
|
167
268
|
style:--date-picker-foreground="var(--spectrum-global-color-gray-800)"
|
|
168
269
|
style:--date-picker-selected-background="var(--accent-color)"
|
|
169
270
|
>
|
|
@@ -175,6 +276,58 @@
|
|
|
175
276
|
open = false;
|
|
176
277
|
}}
|
|
177
278
|
/>
|
|
279
|
+
|
|
280
|
+
{#if currentShowTime}
|
|
281
|
+
<div class="time-section">
|
|
282
|
+
<!-- svelte-ignore a11y-label-has-associated-control -->
|
|
283
|
+
<input
|
|
284
|
+
bind:this={timePicker}
|
|
285
|
+
type="time"
|
|
286
|
+
bind:value={timeValue}
|
|
287
|
+
on:change={handleTimeChange}
|
|
288
|
+
class="time-input"
|
|
289
|
+
step="900"
|
|
290
|
+
/>
|
|
291
|
+
</div>
|
|
292
|
+
{/if}
|
|
178
293
|
</div>
|
|
179
294
|
</SuperPopover>
|
|
180
295
|
{/if}
|
|
296
|
+
|
|
297
|
+
<style>
|
|
298
|
+
.datetime-picker-container {
|
|
299
|
+
display: flex;
|
|
300
|
+
flex-direction: column;
|
|
301
|
+
gap: 8px;
|
|
302
|
+
padding: 0.5rem;
|
|
303
|
+
border-radius: 8px;
|
|
304
|
+
z-index: 1000;
|
|
305
|
+
}
|
|
306
|
+
.time-section {
|
|
307
|
+
display: flex;
|
|
308
|
+
flex-direction: column;
|
|
309
|
+
gap: 4px;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.time-label {
|
|
313
|
+
font-size: 12px;
|
|
314
|
+
font-weight: 500;
|
|
315
|
+
color: var(--spectrum-global-color-gray-700);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.time-input {
|
|
319
|
+
padding: 6px 8px;
|
|
320
|
+
border: 1px solid var(--spectrum-global-color-gray-300);
|
|
321
|
+
border-radius: 4px;
|
|
322
|
+
font-size: 14px;
|
|
323
|
+
min-width: 120px;
|
|
324
|
+
background: var(--spectrum-global-color-gray-50);
|
|
325
|
+
color: var(--spectrum-global-color-gray-800);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.time-input:focus {
|
|
329
|
+
outline: none;
|
|
330
|
+
border-color: var(--spectrum-global-color-blue-500);
|
|
331
|
+
box-shadow: 0 0 0 2px rgba(var(--accent-rgb), 0.2);
|
|
332
|
+
}
|
|
333
|
+
</style>
|
|
@@ -28,6 +28,9 @@
|
|
|
28
28
|
goTo(state) {
|
|
29
29
|
return state;
|
|
30
30
|
},
|
|
31
|
+
reset(val) {
|
|
32
|
+
localValue = undefined;
|
|
33
|
+
},
|
|
31
34
|
},
|
|
32
35
|
View: {
|
|
33
36
|
_enter() {},
|
|
@@ -57,6 +60,8 @@
|
|
|
57
60
|
dispatch("exitedit");
|
|
58
61
|
},
|
|
59
62
|
focusout(e) {
|
|
63
|
+
console.log("Focus out", e, popup);
|
|
64
|
+
|
|
60
65
|
if (popup?.contains(e?.relatedTarget)) return;
|
|
61
66
|
this.submit();
|
|
62
67
|
},
|
|
@@ -106,6 +111,7 @@
|
|
|
106
111
|
$: links = cellOptions.relViewMode == "links" && !isUser;
|
|
107
112
|
|
|
108
113
|
$: localValue = enrichValue(value);
|
|
114
|
+
|
|
109
115
|
$: inEdit = $cellState == "Editing";
|
|
110
116
|
$: isDirty = inEdit && originalValue != JSON.stringify(localValue);
|
|
111
117
|
$: simpleView = cellOptions.relViewMode == "text";
|
|
@@ -118,10 +124,7 @@
|
|
|
118
124
|
!multi;
|
|
119
125
|
|
|
120
126
|
$: returnSingle = isUser && !multi;
|
|
121
|
-
$: placeholder =
|
|
122
|
-
cellOptions.disabled || cellOptions.readonly
|
|
123
|
-
? ""
|
|
124
|
-
: cellOptions.placeholder || "";
|
|
127
|
+
$: placeholder = cellOptions.placeholder || "";
|
|
125
128
|
|
|
126
129
|
const handleKeyboard = (e) => {
|
|
127
130
|
if (e.key == "Escape" && $editorState == "Open") {
|
|
@@ -146,13 +149,18 @@
|
|
|
146
149
|
};
|
|
147
150
|
|
|
148
151
|
const enrichValue = (x) => {
|
|
149
|
-
if (fieldSchema.relationshipType == "self" && x) {
|
|
152
|
+
if (fieldSchema.relationshipType == "self" && x && !Array.isArray(x)) {
|
|
150
153
|
API.fetchRow(fieldSchema.tableId, x).then((row) => {
|
|
151
154
|
localValue = [
|
|
152
|
-
{
|
|
155
|
+
{
|
|
156
|
+
_id: row.id,
|
|
157
|
+
primaryDisplay: fieldSchema.primaryDisplay
|
|
158
|
+
? row[fieldSchema.primaryDisplay]
|
|
159
|
+
: row.name || row.id,
|
|
160
|
+
},
|
|
153
161
|
];
|
|
154
162
|
});
|
|
155
|
-
return [];
|
|
163
|
+
return localValue || [];
|
|
156
164
|
} else if (multi) {
|
|
157
165
|
return value ? [...value] : [];
|
|
158
166
|
} else {
|
|
@@ -194,10 +202,17 @@
|
|
|
194
202
|
class:with-icon={cellOptions?.icon}
|
|
195
203
|
class:placeholder={localValue?.length < 1}
|
|
196
204
|
>
|
|
197
|
-
{#if localValue?.length < 1
|
|
205
|
+
{#if localValue?.length < 1}
|
|
198
206
|
<span> {placeholder} </span>
|
|
199
|
-
{:else}
|
|
200
|
-
<div
|
|
207
|
+
{:else if pills || links}
|
|
208
|
+
<div
|
|
209
|
+
class="items"
|
|
210
|
+
class:pills
|
|
211
|
+
class:links
|
|
212
|
+
class:isUser
|
|
213
|
+
class:withCount={localValue.length > 5}
|
|
214
|
+
class:inEdit
|
|
215
|
+
>
|
|
201
216
|
{#each localValue as val, idx}
|
|
202
217
|
{#if idx < 5}
|
|
203
218
|
<div
|
|
@@ -213,13 +228,19 @@
|
|
|
213
228
|
</div>
|
|
214
229
|
{/if}
|
|
215
230
|
{/each}
|
|
216
|
-
|
|
217
231
|
{#if localValue.length > 5}
|
|
218
|
-
<span class="
|
|
219
|
-
{localValue.length}
|
|
232
|
+
<span class="count">
|
|
233
|
+
(+ {localValue.length - 5})
|
|
220
234
|
</span>
|
|
221
235
|
{/if}
|
|
222
236
|
</div>
|
|
237
|
+
{:else}
|
|
238
|
+
<span>
|
|
239
|
+
{#if cellOptions.role == "formInput"}
|
|
240
|
+
({localValue.length})
|
|
241
|
+
{/if}
|
|
242
|
+
{localValue.map((v) => v.primaryDisplay).join(", ")}
|
|
243
|
+
</span>
|
|
223
244
|
{/if}
|
|
224
245
|
|
|
225
246
|
{#if inEdit && localValue?.length}
|
|
@@ -229,6 +250,7 @@
|
|
|
229
250
|
on:mousedown|preventDefault={cellState.clear}
|
|
230
251
|
></i>
|
|
231
252
|
{/if}
|
|
253
|
+
|
|
232
254
|
{#if !cellOptions.readonly && (cellOptions.role == "formInput" || inEdit)}
|
|
233
255
|
<i class="ri-arrow-down-s-line controlIcon"></i>
|
|
234
256
|
{/if}
|
|
@@ -242,7 +264,7 @@
|
|
|
242
264
|
bind:popup
|
|
243
265
|
open={$editorState == "Open"}
|
|
244
266
|
>
|
|
245
|
-
{#if fieldSchema.recursiveTable
|
|
267
|
+
{#if fieldSchema.recursiveTable}
|
|
246
268
|
<CellLinkPickerTree
|
|
247
269
|
{fieldSchema}
|
|
248
270
|
filter={filter ?? []}
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
/>
|
|
146
146
|
</div>
|
|
147
147
|
|
|
148
|
-
{#if $fetch?.
|
|
148
|
+
{#if $fetch?.rows}
|
|
149
149
|
{#if wide}
|
|
150
150
|
<div class="listWrapper" on:mousedown|preventDefault={() => {}}>
|
|
151
151
|
<div class="list">
|
|
@@ -159,7 +159,9 @@
|
|
|
159
159
|
class:highlighted={focusIdx == idx}
|
|
160
160
|
on:mouseenter={() => (focusIdx = idx)}
|
|
161
161
|
on:mouseleave={() => (focusIdx = -1)}
|
|
162
|
-
on:mousedown|preventDefault={selectRow(
|
|
162
|
+
on:mousedown|preventDefault|stopPropagation={selectRow(
|
|
163
|
+
row
|
|
164
|
+
)}
|
|
163
165
|
>
|
|
164
166
|
{row[primaryDisplay]}
|
|
165
167
|
<i class="ri-add-line" />
|
|
@@ -200,7 +202,7 @@
|
|
|
200
202
|
<div class="list">
|
|
201
203
|
<div class="options">
|
|
202
204
|
{#key localValue}
|
|
203
|
-
{#if $fetch?.rows
|
|
205
|
+
{#if $fetch?.rows?.length}
|
|
204
206
|
{#each $fetch?.rows as row, idx (idx)}
|
|
205
207
|
<div
|
|
206
208
|
class="option"
|
|
@@ -208,10 +210,10 @@
|
|
|
208
210
|
class:highlighted={focusIdx == idx}
|
|
209
211
|
on:mouseenter={() => (focusIdx = idx)}
|
|
210
212
|
on:mouseleave={() => (focusIdx = -1)}
|
|
211
|
-
on:mousedown|preventDefault={selectRow(row)}
|
|
213
|
+
on:mousedown|preventDefault|stopPropagation={selectRow(row)}
|
|
212
214
|
>
|
|
213
215
|
{row[primaryDisplay]}
|
|
214
|
-
<i class="ri-
|
|
216
|
+
<i class="ri-check-line" />
|
|
215
217
|
</div>
|
|
216
218
|
{/each}
|
|
217
219
|
{:else}
|
|
@@ -325,8 +327,6 @@
|
|
|
325
327
|
}
|
|
326
328
|
|
|
327
329
|
&.selected {
|
|
328
|
-
background-color: var(--spectrum-global-color-gray-75);
|
|
329
|
-
color: var(--spectrum-global-color-gray-900);
|
|
330
330
|
& > i {
|
|
331
331
|
visibility: visible;
|
|
332
332
|
color: var(--spectrum-global-color-green-500);
|
|
@@ -334,7 +334,7 @@
|
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
&.highlighted {
|
|
337
|
-
background-color: var(--spectrum-global-color-gray-
|
|
337
|
+
background-color: var(--spectrum-global-color-gray-75);
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
340
|
|
|
@@ -348,7 +348,7 @@
|
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
.option:hover {
|
|
351
|
-
background-color: var(--spectrum-global-color-gray-
|
|
351
|
+
background-color: var(--spectrum-global-color-gray-75);
|
|
352
352
|
border-radius: 4px;
|
|
353
353
|
cursor: pointer;
|
|
354
354
|
}
|
|
@@ -32,13 +32,23 @@
|
|
|
32
32
|
View: {
|
|
33
33
|
_enter() {
|
|
34
34
|
localValue = value;
|
|
35
|
+
originalValue = value;
|
|
36
|
+
lastEdit = undefined;
|
|
35
37
|
},
|
|
36
38
|
reset() {
|
|
37
|
-
originalValue = value;
|
|
38
39
|
localValue = value;
|
|
40
|
+
originalValue = value;
|
|
39
41
|
lastEdit = undefined;
|
|
42
|
+
formattedValue = cellOptions.template
|
|
43
|
+
? processStringSync(cellOptions.template, {
|
|
44
|
+
...$context,
|
|
45
|
+
value: localValue,
|
|
46
|
+
})
|
|
47
|
+
: value || localValue || cellOptions.placeholder;
|
|
48
|
+
|
|
40
49
|
return cellOptions.initialState ?? "View";
|
|
41
50
|
},
|
|
51
|
+
|
|
42
52
|
focus() {
|
|
43
53
|
if (!cellOptions.readonly && !cellOptions.disabled) return "Editing";
|
|
44
54
|
},
|
|
@@ -63,6 +73,7 @@
|
|
|
63
73
|
this.submit();
|
|
64
74
|
},
|
|
65
75
|
submit() {
|
|
76
|
+
localValue = editor.value;
|
|
66
77
|
if (isDirty) {
|
|
67
78
|
dispatch("change", localValue);
|
|
68
79
|
}
|
|
@@ -74,18 +85,53 @@
|
|
|
74
85
|
return "View";
|
|
75
86
|
},
|
|
76
87
|
debounce(e: KeyboardEvent) {
|
|
88
|
+
lastEdit = new Date();
|
|
89
|
+
if (cellOptions?.debounce) {
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
timer = setTimeout(() => {
|
|
92
|
+
dispatch("change", localValue);
|
|
93
|
+
}, cellOptions.debounce ?? 0);
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
handleKeyboard(e: KeyboardEvent) {
|
|
97
|
+
const input = e.target as HTMLInputElement;
|
|
98
|
+
const key = e.key;
|
|
99
|
+
|
|
100
|
+
// Handle control keys
|
|
77
101
|
if (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
102
|
+
["Enter", "Escape", "ArrowLeft", "ArrowRight", "Tab"].includes(key)
|
|
103
|
+
) {
|
|
104
|
+
if (key === "Enter") return this.submit();
|
|
105
|
+
if (key === "Escape") return this.cancel();
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Prevent non-numeric input, except one decimal point and negative sign at start
|
|
110
|
+
if (
|
|
111
|
+
(key.length === 1 && !/[\d.-]/.test(key)) || // Allow digits, decimal, negative sign
|
|
112
|
+
(key === "." && input.value.includes(".")) || // Prevent multiple decimal points
|
|
113
|
+
(key === "-" &&
|
|
114
|
+
(input.value.includes("-") || input.selectionStart !== 0)) // Negative sign only at start
|
|
84
115
|
) {
|
|
85
116
|
e.preventDefault();
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
handleInput(e: Event) {
|
|
120
|
+
const input = e.target as HTMLInputElement;
|
|
121
|
+
const newValue = input.value;
|
|
122
|
+
|
|
123
|
+
// Validate full input
|
|
124
|
+
if (
|
|
125
|
+
newValue !== "" &&
|
|
126
|
+
newValue !== "-" &&
|
|
127
|
+
!/^-?\d*\.?\d*$/.test(newValue)
|
|
128
|
+
) {
|
|
129
|
+
input.value = localValue?.toString() ?? ""; // Revert to last valid value
|
|
86
130
|
return;
|
|
87
131
|
}
|
|
88
|
-
|
|
132
|
+
|
|
133
|
+
localValue =
|
|
134
|
+
newValue === "" || newValue === "-" ? null : Number(newValue);
|
|
89
135
|
lastEdit = new Date();
|
|
90
136
|
if (cellOptions?.debounce) {
|
|
91
137
|
clearTimeout(timer);
|
|
@@ -94,27 +140,19 @@
|
|
|
94
140
|
}, cellOptions.debounce ?? 0);
|
|
95
141
|
}
|
|
96
142
|
},
|
|
97
|
-
handleKeyboard(e: KeyboardEvent) {
|
|
98
|
-
if (e.key == "Enter") this.submit();
|
|
99
|
-
if (e.key == "Escape") this.cancel();
|
|
100
|
-
},
|
|
101
143
|
},
|
|
102
144
|
});
|
|
103
145
|
|
|
104
146
|
$: inEdit = $cellState == "Editing";
|
|
105
147
|
$: inline = cellOptions.role == "inlineInput";
|
|
106
|
-
$: isDirty =
|
|
148
|
+
$: isDirty = lastEdit && originalValue != localValue;
|
|
149
|
+
|
|
107
150
|
$: formattedValue = cellOptions.template
|
|
108
151
|
? processStringSync(cellOptions.template, {
|
|
109
152
|
...$context,
|
|
110
153
|
value: localValue,
|
|
111
154
|
})
|
|
112
|
-
:
|
|
113
|
-
|
|
114
|
-
$: placeholder =
|
|
115
|
-
cellOptions.readonly || cellOptions.disabled
|
|
116
|
-
? ""
|
|
117
|
-
: cellOptions.placeholder || "";
|
|
155
|
+
: value || localValue || cellOptions.placeholder;
|
|
118
156
|
|
|
119
157
|
$: cellState.reset(value);
|
|
120
158
|
|
|
@@ -145,7 +183,7 @@
|
|
|
145
183
|
class:readonly={cellOptions.readonly}
|
|
146
184
|
class:disabled={cellOptions.disabled}
|
|
147
185
|
class:inEdit
|
|
148
|
-
class:isDirty
|
|
186
|
+
class:isDirty={isDirty && cellOptions?.showDirty}
|
|
149
187
|
class:inline
|
|
150
188
|
class:tableCell={cellOptions?.role == "tableCell"}
|
|
151
189
|
class:formInput={cellOptions?.role == "formInput"}
|
|
@@ -164,19 +202,20 @@
|
|
|
164
202
|
{#if $cellState == "Editing"}
|
|
165
203
|
<input
|
|
166
204
|
class="editor"
|
|
205
|
+
bind:this={editor}
|
|
167
206
|
class:placeholder={!localValue}
|
|
168
|
-
type="text"
|
|
169
207
|
style:padding-right={"32px"}
|
|
208
|
+
class:with-icon={cellOptions.icon}
|
|
170
209
|
style:text-align={cellOptions.align == "flex-start"
|
|
171
210
|
? "left"
|
|
172
211
|
: cellOptions.align == "center"
|
|
173
212
|
? "center"
|
|
174
213
|
: "right "}
|
|
175
214
|
placeholder={cellOptions?.placeholder}
|
|
176
|
-
|
|
177
|
-
on:keydown={(e) => cellState.
|
|
215
|
+
value={localValue || null}
|
|
216
|
+
on:keydown={(e) => cellState.handleKeyboard(e)}
|
|
217
|
+
on:input={(e) => cellState.handleInput(e)}
|
|
178
218
|
on:focusout={(e) => cellState.focusout(e)}
|
|
179
|
-
on:keyup={(e) => cellState.handleKeyboard(e)}
|
|
180
219
|
use:focus
|
|
181
220
|
/>
|
|
182
221
|
<i class="ri-close-line clearIcon" on:mousedown|self={cellState.clear}> </i>
|
|
@@ -184,23 +223,11 @@
|
|
|
184
223
|
<div
|
|
185
224
|
class="value"
|
|
186
225
|
style:padding-right={"12px"}
|
|
187
|
-
class:placeholder={!value
|
|
188
|
-
|
|
226
|
+
class:placeholder={!value}
|
|
227
|
+
class:with-icon={cellOptions.icon}
|
|
228
|
+
style:justify-content={cellOptions.align ?? "flex-end"}
|
|
189
229
|
>
|
|
190
|
-
{formattedValue
|
|
230
|
+
{formattedValue ?? ""}
|
|
191
231
|
</div>
|
|
192
232
|
{/if}
|
|
193
233
|
</div>
|
|
194
|
-
|
|
195
|
-
<style>
|
|
196
|
-
.value {
|
|
197
|
-
flex: auto;
|
|
198
|
-
display: flex;
|
|
199
|
-
align-items: center;
|
|
200
|
-
justify-content: flex-end;
|
|
201
|
-
box-sizing: border-box;
|
|
202
|
-
white-space: nowrap;
|
|
203
|
-
text-overflow: ellipsis;
|
|
204
|
-
overflow: hidden;
|
|
205
|
-
}
|
|
206
|
-
</style>
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
let obj = {};
|
|
29
29
|
$options.forEach(
|
|
30
30
|
(option, index) =>
|
|
31
|
-
(obj[option] = optionColors[option]
|
|
31
|
+
(obj[option] = optionColors[option] ?? colorsArray[index % 14])
|
|
32
32
|
);
|
|
33
33
|
return obj;
|
|
34
34
|
});
|
|
@@ -112,9 +112,8 @@
|
|
|
112
112
|
$: inEdit = $cellState == "Editing";
|
|
113
113
|
$: pills = optionsViewMode == "pills";
|
|
114
114
|
$: multi =
|
|
115
|
-
fieldSchema && fieldSchema.type
|
|
116
|
-
|
|
117
|
-
: multi;
|
|
115
|
+
fieldSchema && fieldSchema.type ? fieldSchema.type == "array" : multi;
|
|
116
|
+
|
|
118
117
|
$: placeholder = disabled || readonly ? "" : cellOptions.placeholder || "";
|
|
119
118
|
|
|
120
119
|
export let cellState = fsm("Loading", {
|
|
@@ -499,7 +498,7 @@
|
|
|
499
498
|
{:else if optionsViewMode == "text"}
|
|
500
499
|
<div style:flex={"auto"}>
|
|
501
500
|
<span>
|
|
502
|
-
{multi
|
|
501
|
+
{multi || localValue.length > 1
|
|
503
502
|
? localValue.join(", ")
|
|
504
503
|
: labels[localValue[0]] || localValue[0]}
|
|
505
504
|
</span>
|
|
@@ -511,8 +510,12 @@
|
|
|
511
510
|
class:colorText={optionsViewMode == "colorText"}
|
|
512
511
|
style:justify-content={cellOptions.align ?? "flex-start"}
|
|
513
512
|
>
|
|
514
|
-
{#each localValue as val (val)}
|
|
515
|
-
<div
|
|
513
|
+
{#each localValue as val, idx (val)}
|
|
514
|
+
<div
|
|
515
|
+
class="item"
|
|
516
|
+
style:--option-color={$colors[val] ||
|
|
517
|
+
colorsArray[idx % colorsArray.length]}
|
|
518
|
+
>
|
|
516
519
|
<i class="ri-checkbox-blank-fill" />
|
|
517
520
|
<span> {isObjects ? "JSON" : labels[val] || val} </span>
|
|
518
521
|
</div>
|
|
@@ -634,7 +637,7 @@
|
|
|
634
637
|
}
|
|
635
638
|
|
|
636
639
|
&.focused {
|
|
637
|
-
background-color: var(--spectrum-global-color-gray-
|
|
640
|
+
background-color: var(--spectrum-global-color-gray-75);
|
|
638
641
|
color: var(--spectrum-global-color-gray-800);
|
|
639
642
|
}
|
|
640
643
|
|
|
@@ -652,7 +655,7 @@
|
|
|
652
655
|
|
|
653
656
|
& > i {
|
|
654
657
|
font-size: 16px;
|
|
655
|
-
color: var(--option-color);
|
|
658
|
+
color: var(--option-color, var(--spectrum-global-color-gray-300));
|
|
656
659
|
}
|
|
657
660
|
}
|
|
658
661
|
}
|