@lavalogic/scoria 0.26.0 → 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 {};
@@ -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.26.0",
4
+ "version": "0.27.0",
5
5
  "publishConfig": {
6
6
  "access": "restricted"
7
7
  },