@lavalogic/scoria 0.9.2 → 0.9.4

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.
@@ -28,7 +28,8 @@
28
28
  import { SelectDef } from '../Types/Columns/Definitions/Accessors/SelectDef.svelte.js';
29
29
  import { NumberInputDef } from '../Types/Columns/Definitions/Accessors/NumberInputDef.svelte.js';
30
30
  import { dev } from '$app/environment';
31
- import { QuerySelect } from '../../../index.js';
31
+ import { CheckboxDef, QuerySelect, Ternary } from '../../../index.js';
32
+ import ThreeStateRadio from '../../ThreeStateRadio.svelte';
32
33
 
33
34
  export interface QuickSearchCellProps<T extends object> {
34
35
  column: Column<T>;
@@ -79,8 +80,6 @@
79
80
  const isRemoteSelect = $derived(customFilter?.type === CustomFilterType.Select);
80
81
  const hasQuery = $derived(isRemoteSelect && customFilter?.query);
81
82
 
82
- let inputRef: HTMLInputElement | undefined = $state();
83
-
84
83
  const selectSymbol = Symbol();
85
84
 
86
85
  const openedSelect = getContext<{ value: symbol | null } | null | undefined>(
@@ -347,7 +346,7 @@
347
346
  {/if}
348
347
  {:else if isSelect}
349
348
  {#if hasQuery}
350
- {#if customFilter!.valueAsObject == false}
349
+ {#if customFilter!.valueAsObject !== true}
351
350
  {@const label =
352
351
  customFilter?.id ??
353
352
  customFilter?.label ??
@@ -408,6 +407,48 @@
408
407
  />
409
408
  {/await}
410
409
  {/if}
410
+ {:else if def instanceof CheckboxDef}
411
+ {@const value = (() => {
412
+ switch (tableContext.paginationRepo?.filtering.find((it) => it.id === def.id)?.value) {
413
+ case true: {
414
+ return Ternary.True;
415
+ }
416
+ case false: {
417
+ return Ternary.False;
418
+ }
419
+
420
+ case null:
421
+ case undefined: {
422
+ return Ternary.Neutral;
423
+ }
424
+ }
425
+ })()}
426
+ <div class="centered">
427
+ <ThreeStateRadio
428
+ {value}
429
+ yesLabel="Selected"
430
+ noLabel="Not Selected"
431
+ neutralLabel="Any"
432
+ neutralIcon={{ name: 'circle-minus' }}
433
+ onchange={(v) => {
434
+ switch (v) {
435
+ case Ternary.False: {
436
+ tableContext.paginationRepo?.filterBy(def.id, false);
437
+ return;
438
+ }
439
+ case Ternary.True: {
440
+ tableContext.paginationRepo?.filterBy(def.id, true);
441
+ return;
442
+ }
443
+ case Ternary.Neutral:
444
+ default: {
445
+ tableContext.paginationRepo?.filterBy(def.id, null);
446
+ return;
447
+ }
448
+ }
449
+ }}
450
+ />
451
+ </div>
411
452
  {:else if isNumeric}
412
453
  {#if selectedNumberFilterType.value === NumberDateFilterMode.Between}
413
454
  <div class="input-wrapper left">
@@ -438,39 +479,66 @@
438
479
  </div>
439
480
  {:else if value == null || typeof value == 'string'}
440
481
  <div class="input-wrapper right">
482
+ {#if selectedNumberFilterType?.value == NumberDateFilterMode.null}
483
+ <TextInput
484
+ data-type="quicksearch"
485
+ id={inputId}
486
+ value="is Null"
487
+ disabled
488
+ variant={InputVariant.Table}
489
+ />
490
+ {:else}
491
+ <TextInput
492
+ data-type="quicksearch"
493
+ id={inputId}
494
+ bind:value
495
+ placeholder="Filter&hellip;"
496
+ variant={InputVariant.Table}
497
+ oninput={() => {
498
+ tableContext.paginationRepo?.filterBy(def.id, [value]);
499
+ }}
500
+ onkeydown={closeOnCtrlF}
501
+ />
502
+ {/if}
503
+ </div>
504
+ {/if}
505
+ {:else if value == null || typeof value == 'string'}
506
+ <div class="input-wrapper right">
507
+ {#if selectedStringFilterType?.value == StringFilterMode.null}
441
508
  <TextInput
442
509
  data-type="quicksearch"
443
510
  id={inputId}
444
- bind:value
445
- placeholder="Filter&hellip;"
511
+ value="is Null"
512
+ disabled
446
513
  variant={InputVariant.Table}
514
+ />
515
+ {:else if selectedStringFilterType?.value == StringFilterMode.Empty}
516
+ <TextInput
517
+ data-type="quicksearch"
518
+ id={inputId}
519
+ value="is Empty"
520
+ disabled
521
+ variant={InputVariant.Table}
522
+ />
523
+ {:else}
524
+ <TextInput
525
+ data-type="quicksearch"
526
+ id={inputId}
447
527
  oninput={() => {
448
- tableContext.paginationRepo?.filterBy(def.id, [value]);
528
+ tableContext.paginationRepo?.filterBy(def.id, value);
449
529
  }}
450
- onkeydown={closeOnCtrlF}
530
+ variant={InputVariant.Table}
531
+ bind:value
532
+ placeholder="Filter&hellip;"
451
533
  />
452
- </div>
453
- {/if}
454
- {:else if value == null || typeof value == 'string'}
455
- <div class="input-wrapper right">
456
- <TextInput
457
- data-type="quicksearch"
458
- id={inputId}
459
- oninput={() => {
460
- tableContext.paginationRepo?.filterBy(def.id, value);
461
- }}
462
- variant={InputVariant.Table}
463
- bind:value
464
- bind:inputRef
465
- placeholder="Filter&hellip;"
466
- />
534
+ {/if}
467
535
  </div>
468
536
  {/if}
469
537
 
470
538
  <!-- TODO button for date, checkbox or select for checkbox -->
471
539
  </div>
472
540
 
473
- {#if !isSelect && !isDate}
541
+ {#if !isSelect && !isDate && !(def instanceof CheckboxDef)}
474
542
  <div class="stick-right">
475
543
  <Action
476
544
  data-type="quicksearch"
@@ -666,4 +734,16 @@ td {
666
734
  }
667
735
  td .input-wrapper-parent {
668
736
  width: 100%;
737
+ }
738
+
739
+ .centered {
740
+ display: flex;
741
+ width: fit-content;
742
+ flex-flow: column nowrap;
743
+ align-items: center;
744
+ justify-content: center;
745
+ margin: auto;
746
+ height: 60px;
747
+ --input-height: 60px;
748
+ background-color: #ffffff;
669
749
  }</style>
@@ -84,4 +84,6 @@ tbody {
84
84
 
85
85
  tr.sticky {
86
86
  transition: line-height 0.2s ease, height 0.2s ease;
87
+ height: 61px;
88
+ --height: 61px;
87
89
  }</style>
@@ -242,7 +242,7 @@
242
242
  typeof filteringStateValue == 'number'
243
243
  ) {
244
244
  value = filteringStateValue;
245
- } else {
245
+ } else if (typeof filteringStateValue !== 'boolean') {
246
246
  console.warn('unknown value type:', $state.snapshot(filteringStateValue));
247
247
  value = filteringStateValue as string; // HACK attempt to keep production running
248
248
  }
@@ -266,8 +266,8 @@
266
266
  const gotValue = filterOption.value;
267
267
  if (gotValue == null || typeof gotValue == 'string' || typeof gotValue == 'number') {
268
268
  value = gotValue;
269
- } else {
270
- console.warn('unknown value type:', gotValue);
269
+ } else if (typeof filteringStateValue !== 'boolean') {
270
+ console.warn('unknown value type:', $state.snapshot(gotValue));
271
271
  value = gotValue as string; // HACK attempt to keep production running
272
272
  }
273
273
  }
@@ -400,7 +400,7 @@
400
400
  <div class="contents">
401
401
  {#await options then options}
402
402
  {#if hasQuery}
403
- {#if customFilter!.valueAsObject == false}
403
+ {#if customFilter!.valueAsObject !== true}
404
404
  {@const label =
405
405
  customFilter?.id ??
406
406
  customFilter?.label ??
@@ -4,7 +4,7 @@ import { ToolbarPosition } from '../Toolbar/ToolbarPosition.js';
4
4
  import { RowSelectionDef } from '../Columns/Definitions/RowSelection/RowSelectionDef.svelte.js';
5
5
  import { tick } from 'svelte';
6
6
  import { PaginationType } from '../Pagination/PaginationType.js';
7
- import { asyncAll, asyncFilter, asyncFilterIndices, asyncSleep, asyncSome, getCanvasContext, getErrorMessage } from '../../../../Helpers/Helpers.svelte.js';
7
+ import { asyncAll, asyncFilterIndices, asyncSleep, getCanvasContext, getErrorMessage } from '../../../../Helpers/Helpers.svelte.js';
8
8
  import { AccessorDef } from '../Columns/Definitions/Accessors/AccessorDef.svelte.js';
9
9
  import { NumberInputDef } from '../Columns/Definitions/Accessors/NumberInputDef.svelte.js';
10
10
  import { SelectDef } from '../Columns/Definitions/Accessors/SelectDef.svelte.js';
@@ -14,8 +14,8 @@ import { DateInputDef } from '../Columns/Definitions/Accessors/DateInputDef.svel
14
14
  import { ProgressBarDef } from '../Columns/Definitions/Display/ProgressBarDef.svelte.js';
15
15
  import { DisplayDef } from '../Columns/Definitions/Display/DisplayDef.svelte.js';
16
16
  import { browser, dev } from '$app/environment';
17
- import { ActionsDef } from '../Columns/Definitions/Actions/ActionsDef.svelte.js';
18
17
  import { BubbleDef } from '../Columns/Definitions/Display/BubbleDef.svelte.js';
18
+ import { allowedEmptyFilterModes } from '../DataRepository/LocalTableDataRepository.svelte.js';
19
19
  const SORTING_ICON_WIDTH = 24;
20
20
  const InternalSymbol = Symbol();
21
21
  const uncopyableColumns = new Set([
@@ -153,8 +153,29 @@ export class TableContext {
153
153
  const abortController = new AbortController();
154
154
  try {
155
155
  if (this.paginationRepo?.paginationType == PaginationType.Local) {
156
- const filterState = this.dataRepo?.filtering ?? [];
156
+ const checkedIds = new Set();
157
+ const filterState = this.dataRepo?.filtering?.filter((filter) => {
158
+ const snapshot = $state.snapshot(filter.value);
159
+ checkedIds.add(filter.id);
160
+ const x = this.dataRepo.filterModes.get(filter.id);
161
+ return (allowedEmptyFilterModes.has(x) ||
162
+ (snapshot !== '' && (!Array.isArray(snapshot) || snapshot[0] !== '')));
163
+ }) ?? [];
157
164
  const data = this.dataRepo?.data ?? [];
165
+ // HACK add filter state for filters that don't require a value to function
166
+ // this.dataRepo?.filterModes?.entries().forEach(([key, value]) => {
167
+ // if (!checkedIds.has(key)) {
168
+ // checkedIds.add(key);
169
+ // if (allowedEmptyFilterModes.has(value)) {
170
+ // filterState.push({
171
+ // id: key,
172
+ // value: ''
173
+ // });
174
+ // }
175
+ // } else {
176
+ // console.warn(`key ${key} was already checked, new value:`, value);
177
+ // }
178
+ // });
158
179
  if (!filterState.length) {
159
180
  this.filteredIndices = data.map((_, index) => index) ?? [];
160
181
  }
@@ -1,12 +1,16 @@
1
1
  import type { RefWrapper } from '../../../../Types/Internal/RefWrapper.js';
2
+ import { SvelteSet } from 'svelte/reactivity';
2
3
  import type { Row } from '../Context/Row.js';
3
4
  import type { ColumnFiltersState } from '../Filtering/ColumnFiltersState.js';
4
5
  import type { BoolFilterValueType, NumberFilterValueType, SelectFilterValueType, StringFilterValueType } from '../Filtering/FilterFn.js';
5
6
  import type { FilterMode } from '../Filtering/FilterMode.js';
7
+ import { NumberDateFilterMode } from '../Filtering/NumberDateFilterMode.js';
8
+ import { StringFilterMode } from '../Filtering/StringFilterMode.js';
6
9
  import type { OnChangeFn } from '../OnChangeFn.js';
7
10
  import type { ILocalDataRepository } from './ILocalDataRepository.js';
8
11
  import type { SortingState } from './SortingState.js';
9
12
  import { TableDataRepository } from './TableDataRepository.svelte.js';
13
+ export declare const allowedEmptyFilterModes: SvelteSet<StringFilterMode | NumberDateFilterMode>;
10
14
  export declare class LocalTableDataRepository<T extends object> extends TableDataRepository<T> implements ILocalDataRepository<T> {
11
15
  addEmptyRow?: (() => void) | undefined;
12
16
  readonly filterType: "Real";
@@ -48,5 +52,5 @@ export declare class LocalTableDataRepository<T extends object> extends TableDat
48
52
  readonly boolFilter: (row: Row<T>, columnId: string, // & keyof T,
49
53
  filterValue: BoolFilterValueType) => Promise<boolean>;
50
54
  readonly stringFilter: (row: Row<T>, columnId: string, // & keyof T,
51
- filterValue: StringFilterValueType) => Promise<any>;
55
+ filterValue: StringFilterValueType) => Promise<boolean>;
52
56
  }
@@ -1,9 +1,15 @@
1
1
  import { Delay } from '../../../../Delay/Delay.js';
2
+ import { SvelteSet } from 'svelte/reactivity';
2
3
  import { FilterType } from '../Filtering/FilterType.js';
3
4
  import { NumberDateFilterMode } from '../Filtering/NumberDateFilterMode.js';
4
5
  import { StringFilterMode } from '../Filtering/StringFilterMode.js';
5
6
  import { PaginationType } from '../Pagination/PaginationType.js';
6
7
  import { TableDataRepository } from './TableDataRepository.svelte.js';
8
+ export const allowedEmptyFilterModes = new SvelteSet([
9
+ StringFilterMode.Empty,
10
+ StringFilterMode.null,
11
+ NumberDateFilterMode.null
12
+ ]);
7
13
  export class LocalTableDataRepository extends TableDataRepository {
8
14
  addEmptyRow;
9
15
  filterType = FilterType.Real;
@@ -60,6 +66,10 @@ export class LocalTableDataRepository extends TableDataRepository {
60
66
  setFilterMode = (id, mode) => {
61
67
  if (mode != undefined) {
62
68
  this.filterModes.set(id, mode);
69
+ //add stub filtering in empty cases
70
+ if (allowedEmptyFilterModes.has(mode) && !this.filtering.some((it) => it.id === id)) {
71
+ this.filterBy(id, '');
72
+ }
63
73
  }
64
74
  else {
65
75
  this.filterModes.delete(id);
@@ -69,16 +79,18 @@ export class LocalTableDataRepository extends TableDataRepository {
69
79
  if (typeof value === 'string') {
70
80
  value = value.trim();
71
81
  }
82
+ // add stub filter value here if filter mode is empty, not empty, null, or not null
72
83
  const oldIndex = this.filtering.findIndex((it) => it.id === id);
73
84
  const newFiltering = this.filtering.concat();
74
85
  if (oldIndex === -1 || newFiltering[oldIndex].value != value) {
75
86
  if (oldIndex > -1) {
76
87
  newFiltering.splice(oldIndex, 1);
77
88
  }
78
- const hasNoValue = value == null ||
79
- (typeof value === 'object' && Array.isArray(value) && value.length === 0) ||
80
- (typeof value === 'string' && value.length === 0);
81
- if (!hasNoValue) {
89
+ const hasValue = allowedEmptyFilterModes.has(this.filterModes.get(id)) ||
90
+ !(value == null ||
91
+ (typeof value === 'object' && Array.isArray(value) && value.length === 0) ||
92
+ (typeof value === 'string' && value.length === 0));
93
+ if (hasValue) {
82
94
  newFiltering.push({ id, value });
83
95
  }
84
96
  }
@@ -162,10 +174,13 @@ export class LocalTableDataRepository extends TableDataRepository {
162
174
  numberFilter = async (row, columnId, // & keyof T,
163
175
  values) => {
164
176
  const columnValue = await row.getValue(columnId);
177
+ const filterType = this.filterModes.get(columnId) ?? NumberDateFilterMode.In;
178
+ if (filterType == NumberDateFilterMode.null) {
179
+ return columnValue == null || isNaN(columnValue);
180
+ }
165
181
  if (!columnValue) {
166
182
  return false;
167
183
  }
168
- const filterType = this.filterModes.get(columnId) ?? NumberDateFilterMode.In;
169
184
  switch (filterType) {
170
185
  case NumberDateFilterMode.Equals: {
171
186
  const [min] = TableDataRepository.getMinMax(values);
@@ -224,10 +239,6 @@ export class LocalTableDataRepository extends TableDataRepository {
224
239
  }
225
240
  return !valueSet.has(columnValue);
226
241
  }
227
- case NumberDateFilterMode.null: {
228
- // TODO yes or no setting here
229
- return columnValue == null || isNaN(columnValue);
230
- }
231
242
  case StringFilterMode.ImplicitEquals:
232
243
  case StringFilterMode.Equals:
233
244
  case StringFilterMode.NotEquals:
@@ -271,15 +282,27 @@ export class LocalTableDataRepository extends TableDataRepository {
271
282
  };
272
283
  stringFilter = async (row, columnId, // & keyof T,
273
284
  filterValue) => {
285
+ const filterType = this.filterModes.get(columnId) ?? StringFilterMode.Contains;
286
+ if (filterType == StringFilterMode.Empty) {
287
+ const columnValue = (await row.getValue(columnId))?.toString();
288
+ return !columnValue;
289
+ }
290
+ if (filterType == StringFilterMode.null) {
291
+ const columnValue = await row.getValue(columnId);
292
+ return columnValue == null;
293
+ }
274
294
  if (!filterValue) {
295
+ console.log('empty search value');
275
296
  return true;
276
297
  }
277
298
  filterValue = filterValue.trim().toLocaleLowerCase();
278
- const columnValue = (await row.getValue(columnId))?.toString().trim().toLocaleLowerCase();
299
+ const columnValue = (await row.getValue(columnId))
300
+ ?.toString()
301
+ .trim()
302
+ .toLocaleLowerCase();
279
303
  if (!columnValue) {
280
304
  return true;
281
305
  }
282
- const filterType = this.filterModes.get(columnId) ?? StringFilterMode.Contains;
283
306
  if (filterType === StringFilterMode.EndsWith) {
284
307
  return columnValue.endsWith(filterValue);
285
308
  }
@@ -292,10 +315,24 @@ export class LocalTableDataRepository extends TableDataRepository {
292
315
  if (filterType === StringFilterMode.NotEquals) {
293
316
  return columnValue !== filterValue;
294
317
  }
295
- //last ditch effort and fallback
296
- if (filterType !== StringFilterMode.Contains) {
297
- console.warn(`unhandled filter type value ${filterType}`);
318
+ if (filterType == StringFilterMode.NotEndsWith) {
319
+ return !columnValue.endsWith(filterValue);
320
+ }
321
+ if (filterType == StringFilterMode.Contains) {
322
+ return columnValue.includes(filterValue);
323
+ }
324
+ if (filterType == StringFilterMode.NotContains) {
325
+ return !columnValue.includes(filterValue);
298
326
  }
299
- return columnValue.includes(filterValue);
327
+ if (filterType == StringFilterMode.In) {
328
+ const filterValues = filterValue.split(',');
329
+ return filterValues.some((v) => columnValue === v);
330
+ }
331
+ if (filterType == StringFilterMode.NotIn) {
332
+ const filterValues = filterValue.split(',');
333
+ return !filterValues.some((v) => columnValue === v);
334
+ }
335
+ console.warn(`unhandled filter type value ${filterType}`);
336
+ return true;
300
337
  };
301
338
  }
@@ -8,6 +8,6 @@ export interface CustomFilter {
8
8
  multiSelect?: boolean;
9
9
  objectName?: string;
10
10
  label?: string;
11
- valueAsObject: boolean;
11
+ valueAsObject?: boolean;
12
12
  query?: (value: unknown) => Promise<Array<SelectOption<number>>>;
13
13
  }
@@ -7,22 +7,29 @@
7
7
  import { generateShortUUID } from '../Helpers/Helpers.svelte.js';
8
8
  import { Colour, ColourSet } from '../scss/colours.js';
9
9
  import { Ternary } from '../Types/Internal/Ternary.js';
10
+ import type { PartialIconProps } from './Icon.svelte';
10
11
  export interface ThreeStateRadioProps {
11
- label: string;
12
- value: Ternary;
13
- onchange?: ChangeEventHandler<HTMLInputElement>;
12
+ label?: string;
13
+ value?: Ternary;
14
+ onchange?: (value: Ternary) => void;
14
15
  id?: string;
15
16
  disabled?: boolean;
16
17
  isValid?: boolean;
17
18
  noDisabled?: boolean;
18
19
  yesDisabled?: boolean;
19
20
  neutralDisabled?: boolean;
21
+ noLabel?: string;
22
+ yesLabel?: string;
23
+ neutralLabel?: string;
24
+ noIcon?: PartialIconProps;
25
+ yesIcon?: PartialIconProps;
26
+ neutralIcon?: PartialIconProps;
20
27
  }
21
28
  </script>
22
29
 
23
30
  <script lang="ts">
24
31
  let {
25
- value = $bindable(),
32
+ value = $bindable(Ternary.Neutral),
26
33
  id = generateShortUUID(),
27
34
  label,
28
35
  disabled,
@@ -30,11 +37,15 @@
30
37
  onchange,
31
38
  noDisabled = false,
32
39
  yesDisabled = false,
33
- neutralDisabled = false
40
+ neutralDisabled = false,
41
+ noLabel,
42
+ yesLabel,
43
+ neutralLabel,
44
+ noIcon,
45
+ yesIcon,
46
+ neutralIcon
34
47
  }: ThreeStateRadioProps = $props();
35
48
 
36
- let ref: HTMLInputElement | undefined = $state();
37
-
38
49
  let textValue = $state('');
39
50
 
40
51
  $effect(() => {
@@ -55,17 +66,22 @@
55
66
  untrack(() => {
56
67
  if (textValue === '0' && value !== Ternary.False) {
57
68
  value = Ternary.False;
69
+ onchange?.(Ternary.False);
58
70
  } else if (textValue === '-1' && value !== Ternary.Neutral) {
59
71
  value = Ternary.Neutral;
72
+ onchange?.(Ternary.Neutral);
60
73
  } else if (textValue === '1' && value !== Ternary.True) {
61
74
  value = Ternary.True;
75
+ onchange?.(Ternary.True);
62
76
  }
63
77
  });
64
78
  });
65
79
  </script>
66
80
 
67
81
  <div class="text-label" class:invalid={isValid === false}>
68
- <span>{label}</span>
82
+ {#if label != undefined}
83
+ <span>{label}</span>
84
+ {/if}
69
85
 
70
86
  <div class="radios">
71
87
  <label>
@@ -74,9 +90,10 @@
74
90
  colourSet={value === Ternary.False ? ColourSet.Primary : ColourSet.Auxiliary}
75
91
  icon={{
76
92
  name: 'circle-cross',
93
+ ...noIcon,
77
94
  colour: value === Ternary.False ? undefined : Colour['$ui-blue-5']
78
95
  }}
79
- label="No"
96
+ label={noLabel ?? 'No'}
80
97
  onclick={() => {
81
98
  textValue = '0';
82
99
  }}
@@ -89,9 +106,10 @@
89
106
  colourSet={value === Ternary.Neutral ? ColourSet.Primary : ColourSet.Auxiliary}
90
107
  icon={{
91
108
  name: 'database',
109
+ ...neutralIcon,
92
110
  colour: value === Ternary.Neutral ? undefined : Colour['$ui-blue-5']
93
111
  }}
94
- label="Allow system to decide"
112
+ label={neutralLabel ?? 'Allow system to decide'}
95
113
  onclick={() => {
96
114
  textValue = '-1';
97
115
  }}
@@ -109,9 +127,10 @@
109
127
  colourSet={value === Ternary.True ? ColourSet.Primary : ColourSet.Auxiliary}
110
128
  icon={{
111
129
  name: 'circle-tick',
130
+ ...yesIcon,
112
131
  colour: value === Ternary.True ? undefined : Colour['$ui-blue-5']
113
132
  }}
114
- label="Yes"
133
+ label={yesLabel ?? 'Yes'}
115
134
  onclick={() => {
116
135
  textValue = '1';
117
136
  }}
@@ -122,6 +141,7 @@
122
141
  </div>
123
142
 
124
143
  <style>.text-label {
144
+ box-sizing: border-box;
125
145
  height: max(var(--input-height, 3rem), 2rem);
126
146
  width: var(--input-width, 100%);
127
147
  color: #3a4952;
@@ -139,6 +159,7 @@
139
159
  transition: border-color ease-out 0.15s 0s, background-color ease-out 0.15s 0s, color ease-out 0.15s 0s, fill ease-out 0.15s 0s;
140
160
  }
141
161
  .text-label .radios {
162
+ overflow: hidden;
142
163
  display: flex;
143
164
  flex-flow: row nowrap;
144
165
  height: 100%;
@@ -1,15 +1,21 @@
1
- import type { ChangeEventHandler } from 'svelte/elements';
2
1
  import { Ternary } from '../Types/Internal/Ternary.js';
2
+ import type { PartialIconProps } from './Icon.svelte';
3
3
  export interface ThreeStateRadioProps {
4
- label: string;
5
- value: Ternary;
6
- onchange?: ChangeEventHandler<HTMLInputElement>;
4
+ label?: string;
5
+ value?: Ternary;
6
+ onchange?: (value: Ternary) => void;
7
7
  id?: string;
8
8
  disabled?: boolean;
9
9
  isValid?: boolean;
10
10
  noDisabled?: boolean;
11
11
  yesDisabled?: boolean;
12
12
  neutralDisabled?: boolean;
13
+ noLabel?: string;
14
+ yesLabel?: string;
15
+ neutralLabel?: string;
16
+ noIcon?: PartialIconProps;
17
+ yesIcon?: PartialIconProps;
18
+ neutralIcon?: PartialIconProps;
13
19
  }
14
20
  declare const ThreeStateRadio: import("svelte").Component<ThreeStateRadioProps, {}, "value">;
15
21
  type ThreeStateRadio = ReturnType<typeof ThreeStateRadio>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lavalogic/scoria",
3
3
  "description": "Svelte components used for the FloWMS Web Frontend",
4
- "version": "0.9.2",
4
+ "version": "0.9.4",
5
5
  "publishConfig": {
6
6
  "access": "restricted"
7
7
  },
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "devDependencies": {
32
32
  "@chromatic-com/storybook": "^4.1.3",
33
- "@eslint/compat": "^2.0.0",
33
+ "@eslint/compat": "^2.0.1",
34
34
  "@eslint/js": "^9.39.2",
35
35
  "@playwright/test": "^1.57.0",
36
36
  "@storybook/addon-a11y": "^10.1.11",
@@ -38,20 +38,20 @@
38
38
  "@storybook/addon-svelte-csf": "^5.0.10",
39
39
  "@storybook/addon-vitest": "^10.1.11",
40
40
  "@storybook/sveltekit": "^10.1.11",
41
- "@sveltejs/adapter-node": "^5.4.0",
42
- "@sveltejs/kit": "^2.49.3",
41
+ "@sveltejs/adapter-node": "^5.5.0",
42
+ "@sveltejs/kit": "^2.49.4",
43
43
  "@sveltejs/package": "^2.5.7",
44
- "@sveltejs/vite-plugin-svelte": "^6.2.3",
44
+ "@sveltejs/vite-plugin-svelte": "^6.2.4",
45
45
  "@types/eslint": "^9.6.1",
46
- "@types/node": "^24.10.4",
47
- "@typescript-eslint/eslint-plugin": "^8.52.0",
48
- "@typescript-eslint/parser": "^8.52.0",
49
- "@vitest/browser": "^4.0.16",
46
+ "@types/node": "^25.0.7",
47
+ "@typescript-eslint/eslint-plugin": "^8.53.0",
48
+ "@typescript-eslint/parser": "^8.53.0",
49
+ "@vitest/browser": "^4.0.17",
50
50
  "eslint": "^9.39.2",
51
51
  "eslint-config-prettier": "^10.1.8",
52
- "eslint-plugin-storybook": "10.1.4",
52
+ "eslint-plugin-storybook": "^10.1.11",
53
53
  "eslint-plugin-svelte": "^3.14.0",
54
- "globals": "^16.5.0",
54
+ "globals": "^17.0.0",
55
55
  "mdsvex": "^0.12.6",
56
56
  "playwright": "^1.57.0",
57
57
  "prettier": "^3.7.4",
@@ -59,14 +59,14 @@
59
59
  "publint": "^0.3.16",
60
60
  "sass-embedded": "^1.97.2",
61
61
  "storybook": "^10.1.11",
62
- "svelte": "^5.46.1",
62
+ "svelte": "^5.46.3",
63
63
  "svelte-check": "^4.3.5",
64
64
  "svelte-render-scan": "^1.1.0",
65
65
  "typescript": "^5.9.3",
66
- "typescript-eslint": "^8.52.0",
66
+ "typescript-eslint": "^8.53.0",
67
67
  "vite": "^7.3.1",
68
68
  "vite-plugin-devtools-json": "^1.0.0",
69
- "vitest": "^4.0.16",
69
+ "vitest": "^4.0.17",
70
70
  "vitest-browser-svelte": "^2.0.1"
71
71
  },
72
72
  "keywords": [