@lavalogic/scoria 0.25.2 → 0.27.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.
@@ -0,0 +1,79 @@
1
+ <svelte:options runes />
2
+
3
+ <script
4
+ lang="ts"
5
+ module
6
+ >
7
+ import type { Snippet } from 'svelte';
8
+
9
+ export interface PageHeadingProps {
10
+ children: Snippet;
11
+ subtitle?: Snippet | undefined;
12
+ extras?: Snippet | undefined;
13
+ }
14
+ </script>
15
+
16
+ <script lang="ts">
17
+ let { children, subtitle, extras }: PageHeadingProps = $props();
18
+ </script>
19
+
20
+ <div class="outer">
21
+ <div class="column">
22
+ <h1>{@render children()}</h1>
23
+ <div class="one-line">
24
+ {#if subtitle}
25
+ {@render subtitle()}
26
+ {/if}
27
+ </div>
28
+ </div>
29
+ {#if extras}
30
+ <div class="buttons">
31
+ {@render extras()}
32
+ </div>
33
+ {/if}
34
+ </div>
35
+
36
+ <style>.outer {
37
+ padding: 1.5rem;
38
+ display: flex;
39
+ flex-flow: row nowrap;
40
+ width: 100%;
41
+ background-color: #ffffff;
42
+ border-bottom: solid 1px #cbd4da;
43
+ }
44
+ .outer .buttons {
45
+ display: flex;
46
+ flex-flow: row-reverse nowrap;
47
+ align-items: center;
48
+ justify-content: flex-end;
49
+ gap: 0.75rem;
50
+ flex-grow: 1;
51
+ justify-content: flex-start;
52
+ }
53
+ .outer .column {
54
+ flex-grow: 2;
55
+ display: flex;
56
+ flex-flow: column nowrap;
57
+ background-color: #ffffff;
58
+ }
59
+ .outer .column h1 {
60
+ margin-top: 0.25rem;
61
+ margin-bottom: 0.25rem;
62
+ color: #455661;
63
+ font-weight: 600;
64
+ font-size: 1.4rem;
65
+ }
66
+ .outer .column .one-line {
67
+ display: inline-flex;
68
+ flex-flow: row;
69
+ gap: 1rem;
70
+ }
71
+ .outer .column .one-line span {
72
+ display: inline-flex;
73
+ flex-flow: row;
74
+ align-items: center;
75
+ gap: 0.1875rem;
76
+ fill: #647d8e;
77
+ color: #647d8e;
78
+ font-size: 0.875rem;
79
+ }</style>
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ export interface PageHeadingProps {
3
+ children: Snippet;
4
+ subtitle?: Snippet | undefined;
5
+ extras?: Snippet | undefined;
6
+ }
7
+ declare const PageHeading: import("svelte").Component<PageHeadingProps, {}, "">;
8
+ type PageHeading = ReturnType<typeof PageHeading>;
9
+ export default PageHeading;
@@ -0,0 +1,160 @@
1
+ <svelte:options runes />
2
+
3
+ <script
4
+ lang="ts"
5
+ generics="Args"
6
+ >
7
+ import { TooltipContext } from '../Contexts/TooltipContext.svelte.js';
8
+
9
+ import { Delay } from '../Delay/Delay.js';
10
+ import { devCatch } from '../Helpers/Helpers.svelte.js';
11
+ import { Colour } from '../scss/colours.js';
12
+ import { Side } from '../Types/Internal/Side.js';
13
+ import { Size } from '../Types/Internal/Size.js';
14
+ import { getContext } from 'svelte';
15
+ import Icon from './Icon.svelte';
16
+ import type { StepButtonProps } from './StepButtonProps.js';
17
+
18
+ let { option, selected, index }: StepButtonProps<Args> = $props();
19
+
20
+ let disabled = $state(true);
21
+ let visible = $state(true);
22
+ let isValid = $state(true);
23
+
24
+ const tooltipContext = getContext<TooltipContext>(TooltipContext.identifier);
25
+
26
+ $effect(() => {
27
+ if (typeof option.isValid === 'boolean') {
28
+ isValid = option.isValid;
29
+ } else {
30
+ option.isValid
31
+ ?.then((v) => {
32
+ isValid = v;
33
+ })
34
+ .catch(devCatch);
35
+ }
36
+ });
37
+ $effect(() => {
38
+ if (typeof option.disabled === 'boolean') {
39
+ disabled = option.disabled;
40
+ } else if (option.disabled == undefined) {
41
+ disabled = false;
42
+ } else {
43
+ option.disabled
44
+ .then((v) => {
45
+ disabled = v;
46
+ })
47
+ .catch(devCatch);
48
+ }
49
+ });
50
+
51
+ $effect(() => {
52
+ if (typeof option.visible === 'boolean') {
53
+ visible = option.visible;
54
+ } else if (option.visible == undefined) {
55
+ visible = true;
56
+ } else {
57
+ option.visible
58
+ .then((v) => {
59
+ visible = v;
60
+ })
61
+ .catch(devCatch);
62
+ }
63
+ });
64
+ </script>
65
+
66
+ <button
67
+ class:selected
68
+ {disabled}
69
+ onclick={() => {
70
+ option.onclick();
71
+ }}
72
+ type="button"
73
+ class="tab"
74
+ class:invalid={!isValid}
75
+ class:hidden={!visible}
76
+ onmouseenter={(e) => {
77
+ if (option.label) {
78
+ const rect = (e.target as HTMLButtonElement).getBoundingClientRect();
79
+ tooltipContext.showTooltip({
80
+ text: option.label,
81
+ arrow: Side.Top,
82
+ delay: Delay.Default,
83
+ rect,
84
+ });
85
+ }
86
+ }}
87
+ onmouseleave={() => {
88
+ if (option.label) {
89
+ tooltipContext.hideTooltip(option.label);
90
+ }
91
+ }}
92
+ >
93
+ <div
94
+ class="bordered"
95
+ class:invalid={!isValid}
96
+ >
97
+ {#if option.iconLeft}
98
+ <Icon
99
+ {...option.iconLeft}
100
+ colour={Colour['$brand-primary']}
101
+ />
102
+ {/if}
103
+ {index + 1}
104
+ {#if !isValid}
105
+ <Icon
106
+ name="error"
107
+ colour={Colour['$error-border']}
108
+ size={Size.Small}
109
+ />
110
+ {:else if option.iconRight}
111
+ <Icon
112
+ colour={Colour['$brand-primary']}
113
+ size={Size.Small}
114
+ {...option.iconRight}
115
+ />
116
+ {/if}
117
+ </div>
118
+ </button>
119
+
120
+ <style>button.tab.hidden {
121
+ display: none !important;
122
+ }
123
+
124
+ .tab {
125
+ cursor: pointer;
126
+ font-size: 0.875rem;
127
+ font-weight: 600;
128
+ aspect-ratio: 1;
129
+ background-color: transparent;
130
+ border: solid 1px #cbd4da;
131
+ border-radius: 50%;
132
+ 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;
133
+ }
134
+ .tab:not([disabled]) {
135
+ color: #3a4952;
136
+ }
137
+ .tab:not([disabled]):hover, .tab:not([disabled]).selected:hover {
138
+ background-color: #f4f7f9;
139
+ }
140
+ .tab .bordered {
141
+ white-space: nowrap;
142
+ display: flex;
143
+ flex-flow: row nowrap;
144
+ align-items: center;
145
+ justify-content: center;
146
+ gap: 0.5rem;
147
+ }
148
+ .tab .bordered.invalid {
149
+ color: #aa1414;
150
+ background-color: #f9e9e9;
151
+ }
152
+ .tab.selected {
153
+ color: #259fc7;
154
+ border-color: #259fc7;
155
+ }
156
+ .tab.selected.invalid {
157
+ color: #aa1414;
158
+ border-color: #aa1414;
159
+ background-color: #f9e9e9;
160
+ }</style>
@@ -0,0 +1,25 @@
1
+ import type { StepButtonProps } from './StepButtonProps.js';
2
+ declare function $$render<Args>(): {
3
+ props: StepButtonProps<Args>;
4
+ exports: {};
5
+ bindings: "";
6
+ slots: {};
7
+ events: {};
8
+ };
9
+ declare class __sveltets_Render<Args> {
10
+ props(): ReturnType<typeof $$render<Args>>['props'];
11
+ events(): ReturnType<typeof $$render<Args>>['events'];
12
+ slots(): ReturnType<typeof $$render<Args>>['slots'];
13
+ bindings(): "";
14
+ exports(): {};
15
+ }
16
+ interface $$IsomorphicComponent {
17
+ new <Args>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<Args>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<Args>['props']>, ReturnType<__sveltets_Render<Args>['events']>, ReturnType<__sveltets_Render<Args>['slots']>> & {
18
+ $$bindings?: ReturnType<__sveltets_Render<Args>['bindings']>;
19
+ } & ReturnType<__sveltets_Render<Args>['exports']>;
20
+ <Args>(internal: unknown, props: ReturnType<__sveltets_Render<Args>['props']> & {}): ReturnType<__sveltets_Render<Args>['exports']>;
21
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
22
+ }
23
+ declare const StepButton: $$IsomorphicComponent;
24
+ type StepButton<Args> = InstanceType<typeof StepButton<Args>>;
25
+ export default StepButton;
@@ -0,0 +1,4 @@
1
+ import type { TabGroupButtonProps } from './TabGroupButtonProps.js';
2
+ export interface StepButtonProps<Args> extends TabGroupButtonProps<Args> {
3
+ index: number;
4
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,188 @@
1
+ <svelte:options runes />
2
+
3
+ <script
4
+ lang="ts"
5
+ generics="CommonDenominator"
6
+ >
7
+ import { ColourSet } from '../scss/colours.js';
8
+ import { Size } from '../Types/Internal/Size.js';
9
+ import { onMount, untrack } from 'svelte';
10
+ import Button from './Button.svelte';
11
+ import StepButton from './StepButton.svelte';
12
+ import type { StepFormProps } from './StepFormProps.js';
13
+
14
+ let { name, steps, currentStep }: StepFormProps<CommonDenominator> = $props();
15
+
16
+ onMount(() => {
17
+ if (name) {
18
+ const tabName = sessionStorage.getItem(`${name}-active-tab`);
19
+ if (tabName) {
20
+ steps.find((it) => it.label === tabName)?.onclick();
21
+ }
22
+ }
23
+ });
24
+
25
+ const indexOfCurrent = $derived(currentStep ? steps.indexOf(currentStep) : -1);
26
+
27
+ const previous = $derived.by(() => {
28
+ for (let i = indexOfCurrent - 1; i > -1; i--) {
29
+ const next = steps.at(i);
30
+
31
+ if (next == null || !next.disabled || next.visible != false) {
32
+ return next ?? null;
33
+ }
34
+ }
35
+ return null;
36
+ });
37
+
38
+ const next = $derived.by(() => {
39
+ for (let i = indexOfCurrent + 1; i < steps.length; i++) {
40
+ const next = steps.at(i);
41
+
42
+ if (next == null || !next.disabled || next.visible != false) {
43
+ return next ?? null;
44
+ }
45
+ }
46
+ return null;
47
+ });
48
+
49
+ $effect(() => {
50
+ if (name && currentStep) {
51
+ untrack(() => {
52
+ sessionStorage.setItem(`${name}-active-tab`, currentStep.label);
53
+ });
54
+ }
55
+ });
56
+ </script>
57
+
58
+ <div class="wrapper noscroll">
59
+ <div class="tabs">
60
+ {#each steps as option, index (index)}
61
+ <StepButton
62
+ {option}
63
+ {index}
64
+ selected={currentStep?.label === option.label}
65
+ />
66
+ {/each}
67
+ <div class="divider"></div>
68
+
69
+ <div class="steps">
70
+ <Button
71
+ size={Size.Small}
72
+ fullWidth
73
+ disabled={!previous}
74
+ onclick={() => {
75
+ previous?.onclick();
76
+ }}
77
+ colourSet={ColourSet.Secondary}>Previous</Button
78
+ >
79
+ <Button
80
+ size={Size.Small}
81
+ fullWidth
82
+ onclick={() => {
83
+ next?.onclick();
84
+ }}
85
+ disabled={!next}
86
+ colourSet={ColourSet.Primary}>Next</Button
87
+ >
88
+ </div>
89
+ </div>
90
+
91
+ <div class="content noscroll">
92
+ {#if currentStep}
93
+ {@render currentStep.content(currentStep.args)}
94
+ {:else}
95
+ <div class="wrapper bg">
96
+ <span class="red">No Step Selected</span>
97
+ </div>
98
+ {/if}
99
+ </div>
100
+ </div>
101
+
102
+ <style>.bg {
103
+ padding: 1.5rem;
104
+ background-color: #f9e9e9;
105
+ color: #c31818;
106
+ }
107
+
108
+ .divider {
109
+ flex-grow: 1;
110
+ }
111
+
112
+ .steps {
113
+ display: flex;
114
+ flex-flow: row nowrap;
115
+ width: 252px;
116
+ padding: 4px;
117
+ justify-content: center;
118
+ gap: 1rem;
119
+ }
120
+
121
+ .wrapper {
122
+ display: flex;
123
+ flex-flow: column nowrap;
124
+ flex: 1;
125
+ overflow: auto;
126
+ }
127
+ .wrapper.noscroll {
128
+ overflow: visible;
129
+ }
130
+ .wrapper .tabs {
131
+ border-radius: 0 4px 0 0;
132
+ display: flex;
133
+ flex-flow: row nowrap;
134
+ overflow-x: auto;
135
+ max-width: 100%;
136
+ gap: 1rem;
137
+ padding-top: 0.5rem;
138
+ padding-bottom: 0.5rem;
139
+ padding-left: 1.25rem;
140
+ padding-right: 1.25rem;
141
+ flex-basis: 64px;
142
+ flex-shrink: 0;
143
+ background-color: #ffffff;
144
+ border-bottom: solid 1px #cbd4da;
145
+ border-top: solid 2px transparent;
146
+ }
147
+ .wrapper .tabs .tab {
148
+ color: #3a4952;
149
+ cursor: pointer;
150
+ font-size: 0.875rem;
151
+ padding: 0;
152
+ background-color: transparent;
153
+ border: none;
154
+ }
155
+ .wrapper .tabs .tab .bordered {
156
+ border-radius: 4px;
157
+ padding: 0.25rem 0.75rem;
158
+ margin-bottom: 0.25rem;
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;
160
+ white-space: nowrap;
161
+ display: flex;
162
+ flex-flow: row nowrap;
163
+ align-items: center;
164
+ gap: 0.5rem;
165
+ }
166
+ .wrapper .tabs .tab .bordered.invalid {
167
+ color: #aa1414;
168
+ background-color: #f9e9e9;
169
+ }
170
+ .wrapper .tabs .tab.selected {
171
+ border-bottom-color: #259fc7;
172
+ }
173
+ .wrapper .tabs .tab.selected.invalid {
174
+ border-bottom-color: #aa1414;
175
+ }
176
+ .wrapper .tabs .tab:hover .bordered, .wrapper .tabs .tab.selected:hover .bordered {
177
+ background-color: #f4f7f9;
178
+ }
179
+ .wrapper .content {
180
+ background-color: #f4f7f9;
181
+ flex-grow: 1;
182
+ display: flex;
183
+ flex-flow: column nowrap;
184
+ overflow: auto;
185
+ }
186
+ .wrapper .content.noscroll {
187
+ overflow: visible;
188
+ }</style>
@@ -0,0 +1,25 @@
1
+ import type { StepFormProps } from './StepFormProps.js';
2
+ declare function $$render<CommonDenominator>(): {
3
+ props: StepFormProps<CommonDenominator>;
4
+ exports: {};
5
+ bindings: "";
6
+ slots: {};
7
+ events: {};
8
+ };
9
+ declare class __sveltets_Render<CommonDenominator> {
10
+ props(): ReturnType<typeof $$render<CommonDenominator>>['props'];
11
+ events(): ReturnType<typeof $$render<CommonDenominator>>['events'];
12
+ slots(): ReturnType<typeof $$render<CommonDenominator>>['slots'];
13
+ bindings(): "";
14
+ exports(): {};
15
+ }
16
+ interface $$IsomorphicComponent {
17
+ new <CommonDenominator>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<CommonDenominator>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<CommonDenominator>['props']>, ReturnType<__sveltets_Render<CommonDenominator>['events']>, ReturnType<__sveltets_Render<CommonDenominator>['slots']>> & {
18
+ $$bindings?: ReturnType<__sveltets_Render<CommonDenominator>['bindings']>;
19
+ } & ReturnType<__sveltets_Render<CommonDenominator>['exports']>;
20
+ <CommonDenominator>(internal: unknown, props: ReturnType<__sveltets_Render<CommonDenominator>['props']> & {}): ReturnType<__sveltets_Render<CommonDenominator>['exports']>;
21
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
22
+ }
23
+ declare const StepForm: $$IsomorphicComponent;
24
+ type StepForm<CommonDenominator> = InstanceType<typeof StepForm<CommonDenominator>>;
25
+ export default StepForm;
@@ -0,0 +1,6 @@
1
+ import type { TabOption } from '../Types/Internal/TabOption.js';
2
+ export interface StepFormProps<CommonDenominator> {
3
+ name?: string;
4
+ steps: Array<TabOption<CommonDenominator>>;
5
+ currentStep: TabOption<CommonDenominator> | undefined;
6
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,4 @@
1
- import { asyncSleep } from '../../../Helpers/Helpers.svelte.js';
1
+ import { asyncSleep, generateShortUUID, getAccessorSortingFn, } from '../../../Helpers/Helpers.svelte.js';
2
2
  import { Colour } from '../../../scss/colours.js';
3
3
  import { ExampleSelectEnum } from '../../../Types/Examples/ExampleSelectEnum.js';
4
4
  import { Validity } from '../../../Types/Internal/Validity.js';
@@ -55,6 +55,16 @@ export function generateExampleItemColumnDefs(modal) {
55
55
  isEnabled: () => true,
56
56
  isValid,
57
57
  }));
58
+ const uuidByIndex = new Map();
59
+ const statusAccessorFn = async (item) => {
60
+ const foundByIndex = uuidByIndex.get(item.id);
61
+ if (foundByIndex) {
62
+ return foundByIndex;
63
+ }
64
+ const newlyMade = generateShortUUID();
65
+ uuidByIndex.set(item.id, newlyMade);
66
+ return newlyMade;
67
+ };
58
68
  let defs = $state([
59
69
  expandDef,
60
70
  new ValidityDef({
@@ -64,6 +74,26 @@ export function generateExampleItemColumnDefs(modal) {
64
74
  isValid,
65
75
  modal,
66
76
  }),
77
+ new DisplayDef({
78
+ id: 'orderLineStatus',
79
+ header: 'Order Line Status',
80
+ allowSorting: true,
81
+ debug: true,
82
+ accessorFn: statusAccessorFn,
83
+ filterValueType: 'Select',
84
+ getOptions: async () => {
85
+ void uuidByIndex.size;
86
+ const mapped = [
87
+ { label: 'Pending', value: 'Pending' },
88
+ ...[...uuidByIndex.values()].map((it) => {
89
+ return { label: it, value: it };
90
+ }),
91
+ ];
92
+ return mapped;
93
+ },
94
+ getSortingFn: (desc) => getAccessorSortingFn(statusAccessorFn, desc),
95
+ allowFiltering: true,
96
+ }),
67
97
  new DisplayDef({
68
98
  header: 'ID',
69
99
  id: 'id',
@@ -4,7 +4,6 @@ import { AccessorDef, type AccessorDefProps } from './AccessorDef.svelte.js';
4
4
  export interface SelectDefProps<T extends object, in FilterValueType, out SelectValueType> extends AccessorDefProps<T, FilterValueType, SelectValueType> {
5
5
  getOptions: () => Array<SelectOption<SelectValueType>> | Promise<Array<SelectOption<SelectValueType>>>;
6
6
  getDisplayValue: (item: T, index: number) => string | null | Promise<string | null>;
7
- sortingFn?: (a: T, b: T) => 1 | -1 | 0;
8
7
  getSpecificOptions?: (item: T, index: number) => Array<SelectOption<SelectValueType>> | Promise<Array<SelectOption<SelectValueType>>>;
9
8
  optional?: boolean;
10
9
  clearable?: boolean;
@@ -15,7 +14,6 @@ export declare class SelectDef<T extends object, in FilterValueType, out SelectV
15
14
  private _filterFn;
16
15
  get filterFn(): FilterFn<T, FilterValueType> | undefined;
17
16
  set filterFn(v: FilterFn<T, FilterValueType> | undefined);
18
- readonly sortingFn?: (a: T, b: T) => 1 | -1 | 0;
19
17
  readonly optional: boolean;
20
18
  readonly clearable: boolean;
21
19
  readonly getSpecificOptions?: (item: T, index: number) => Array<SelectOption<SelectValueType>> | Promise<Array<SelectOption<SelectValueType>>>;
@@ -5,7 +5,6 @@ export class SelectDef extends AccessorDef {
5
5
  super(props);
6
6
  this.getSpecificOptions = $derived(props.getSpecificOptions); //done in the base class now
7
7
  // this.getOptions = $derived(props.getOptions); // done in the base class now
8
- this.sortingFn = $derived(props.sortingFn);
9
8
  this.optional = $derived(props.optional ?? false);
10
9
  this.clearable = $derived(props.clearable ?? true);
11
10
  // this.getDisplayValue = $derived(props.getDisplayValue); //done in the base class now
@@ -19,7 +18,6 @@ export class SelectDef extends AccessorDef {
19
18
  set filterFn(v) {
20
19
  this._filterFn = v;
21
20
  }
22
- sortingFn;
23
21
  optional;
24
22
  clearable;
25
23
  getSpecificOptions;
@@ -21,6 +21,7 @@ export interface ColumnDefProps<T extends object, in FilterFnType, out OptionsTy
21
21
  resizable?: boolean;
22
22
  isValid?: ValidationFn<T>;
23
23
  filterFn?: FilterFn<T, FilterFnType>;
24
+ getSortingFn?: (desc: boolean) => (a: T, b: T) => 1 | -1 | 0;
24
25
  filterValueType?: FilterValueType;
25
26
  getOptions?: () => Array<SelectOption<OptionsType>> | Promise<Array<SelectOption<OptionsType>>>;
26
27
  accessorFn?: AccessorFn<T>;
@@ -57,6 +58,7 @@ export declare abstract class ColumnDef<T extends object, in FilterFnType = neve
57
58
  set filterValueType(v: FilterValueType | undefined);
58
59
  readonly getDisplayValue: ((item: T, index: number) => string | null | Promise<string | null>) | undefined;
59
60
  toJSON(): ColumnJSONRepresentation;
61
+ readonly getSortingFn: ((desc: boolean) => (a: T, b: T) => 1 | -1 | 0) | undefined;
60
62
  readonly isEditable: (item: T, index: number) => boolean | Promise<boolean>;
61
63
  readonly resizable: boolean;
62
64
  readonly header: string | Snippet;
@@ -16,6 +16,7 @@ export class ColumnDef {
16
16
  this._filterValueType = $derived(props.filterValueType);
17
17
  this.getDisplayValue = $derived(props.getDisplayValue);
18
18
  this.debug = $derived(props.debug ?? false);
19
+ this.getSortingFn = $derived(props.getSortingFn);
19
20
  this.getOptions = $derived(props.getOptions);
20
21
  }
21
22
  id;
@@ -84,6 +85,7 @@ export class ColumnDef {
84
85
  filterValueType: this.filterValueType,
85
86
  };
86
87
  }
88
+ getSortingFn;
87
89
  isEditable;
88
90
  resizable;
89
91
  header;
@@ -725,6 +725,9 @@ export class TableContext {
725
725
  if (!def) {
726
726
  return undefined;
727
727
  }
728
+ if (def.getSortingFn != undefined) {
729
+ return def.getSortingFn(desc);
730
+ }
728
731
  if (def instanceof DisplayDef ||
729
732
  def instanceof TextInputDef ||
730
733
  def instanceof NumberInputDef ||
@@ -735,7 +738,7 @@ export class TableContext {
735
738
  return checkboxSortingFn(id, desc);
736
739
  }
737
740
  if (def instanceof SelectDef) {
738
- return def.sortingFn ?? comparableSortingFn(id, desc);
741
+ return comparableSortingFn(id, desc);
739
742
  }
740
743
  if (def instanceof ProgressBarDef) {
741
744
  return progressSortingFn(id, desc);
@@ -64,3 +64,4 @@ export interface ICreateTableArgs<T extends object, RowIdType extends Primitive>
64
64
  selectionExtractor: (item: T) => RowIdType | Promise<RowIdType>;
65
65
  }
66
66
  export declare function createLocalTable<T extends object, RowIdType extends Primitive>(args: ICreateTableArgs<T, RowIdType>): TableContext<T, RowIdType>;
67
+ export declare function getAccessorSortingFn<T, V>(accessorFn: (item: T) => V, desc: boolean): (a: T, b: T) => 1 | 0 | -1;
@@ -421,3 +421,40 @@ export function createLocalTable(args) {
421
421
  getUserId: args.getUserId,
422
422
  });
423
423
  }
424
+ export function getAccessorSortingFn(accessorFn, desc) {
425
+ return desc
426
+ ? (_a, _b) => {
427
+ const a = accessorFn(_a);
428
+ const b = accessorFn(_b);
429
+ if (a == undefined && b != undefined) {
430
+ return 1;
431
+ }
432
+ if (b == undefined && a != undefined) {
433
+ return -1;
434
+ }
435
+ if (a < b) {
436
+ return 1;
437
+ }
438
+ if (a > b) {
439
+ return -1;
440
+ }
441
+ return 0;
442
+ }
443
+ : (_a, _b) => {
444
+ const a = accessorFn(_a);
445
+ const b = accessorFn(_b);
446
+ if (a == undefined && b != undefined) {
447
+ return 1;
448
+ }
449
+ if (b == undefined && a != undefined) {
450
+ return -1;
451
+ }
452
+ if (a < b) {
453
+ return -1;
454
+ }
455
+ if (a > b) {
456
+ return 1;
457
+ }
458
+ return 0;
459
+ };
460
+ }
package/dist/index.d.ts CHANGED
@@ -132,7 +132,7 @@ export { TooltipContext } from './Contexts/TooltipContext.svelte.js';
132
132
  export { UntypedInputContext } from './Contexts/UntypedInputContext.svelte.js';
133
133
  export { Delay } from './Delay/Delay.js';
134
134
  export { DATAMatrix } from './Helpers/Datamatrix.js';
135
- export { asyncAll, asyncEvery, asyncFilter, asyncFilterIndices, asyncFlatMap, asyncForEach, asyncMap, asyncSleep, asyncSome, autoPluralise, createLocalTable, devCatch, generateShortUUID, generateUUID, getCanvasContext, getErrorMessage, gridItem, isDateTuple, isNumericArray, isValidEmailAddress, loadingText, localTimeFormat, passthrough, refWrapper, SQLFriendly, SQLFriendlyWithLocalTime, vowels, type ICreateTableArgs, } from './Helpers/Helpers.svelte.js';
135
+ export { asyncAll, asyncEvery, asyncFilter, asyncFilterIndices, asyncFlatMap, asyncForEach, asyncMap, asyncSleep, asyncSome, autoPluralise, createLocalTable, devCatch, generateShortUUID, generateUUID, getAccessorSortingFn, getCanvasContext, getErrorMessage, gridItem, isDateTuple, isNumericArray, isValidEmailAddress, loadingText, localTimeFormat, passthrough, refWrapper, SQLFriendly, SQLFriendlyWithLocalTime, vowels, type ICreateTableArgs, } from './Helpers/Helpers.svelte.js';
136
136
  export { type INamed } from './Helpers/INamed.js';
137
137
  export { AttributeOperation } from './Types/Internal/AttributeOperation.js';
138
138
  export { type BigRadioOption } from './Types/Internal/BigRadioOption.js';
package/dist/index.js CHANGED
@@ -132,7 +132,7 @@ export { TooltipContext } from './Contexts/TooltipContext.svelte.js';
132
132
  export { UntypedInputContext } from './Contexts/UntypedInputContext.svelte.js';
133
133
  export { Delay } from './Delay/Delay.js';
134
134
  export { DATAMatrix } from './Helpers/Datamatrix.js';
135
- export { asyncAll, asyncEvery, asyncFilter, asyncFilterIndices, asyncFlatMap, asyncForEach, asyncMap, asyncSleep, asyncSome, autoPluralise, createLocalTable, devCatch, generateShortUUID, generateUUID, getCanvasContext, getErrorMessage, gridItem, isDateTuple, isNumericArray, isValidEmailAddress, loadingText, localTimeFormat, passthrough, refWrapper, SQLFriendly, SQLFriendlyWithLocalTime, vowels, } from './Helpers/Helpers.svelte.js';
135
+ export { asyncAll, asyncEvery, asyncFilter, asyncFilterIndices, asyncFlatMap, asyncForEach, asyncMap, asyncSleep, asyncSome, autoPluralise, createLocalTable, devCatch, generateShortUUID, generateUUID, getAccessorSortingFn, getCanvasContext, getErrorMessage, gridItem, isDateTuple, isNumericArray, isValidEmailAddress, loadingText, localTimeFormat, passthrough, refWrapper, SQLFriendly, SQLFriendlyWithLocalTime, vowels, } from './Helpers/Helpers.svelte.js';
136
136
  export {} from './Helpers/INamed.js';
137
137
  export { AttributeOperation } from './Types/Internal/AttributeOperation.js';
138
138
  export {} from './Types/Internal/BigRadioOption.js';
@@ -2594,20 +2594,25 @@
2594
2594
  flex-flow: row;
2595
2595
  // align-items: flex-start;
2596
2596
  gap: 1rem;
2597
- span {
2598
- display: inline-flex;
2599
- flex-flow: row;
2600
- align-items: center;
2601
- gap: 0.1875rem;
2602
- fill: colours.$font-secondary;
2603
- color: colours.$font-secondary;
2604
- font-size: #{sizing.$text-small-small-medium};
2605
- }
2597
+
2598
+ @include heading-subtitle;
2606
2599
  }
2607
2600
  }
2608
2601
  }
2609
2602
  }
2610
2603
 
2604
+ @mixin heading-subtitle {
2605
+ span {
2606
+ display: inline-flex;
2607
+ flex-flow: row;
2608
+ align-items: center;
2609
+ gap: 0.1875rem;
2610
+ fill: colours.$font-secondary;
2611
+ color: colours.$font-secondary;
2612
+ font-size: #{sizing.$text-small-small-medium};
2613
+ }
2614
+ }
2615
+
2611
2616
  @mixin attributes-modal-inner {
2612
2617
  .flex {
2613
2618
  display: flex;
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.25.2",
4
+ "version": "0.27.0",
5
5
  "publishConfig": {
6
6
  "access": "restricted"
7
7
  },