lutra 0.1.69 → 0.1.73
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/components/Callout.svelte +85 -0
- package/dist/components/Callout.svelte.d.ts +14 -0
- package/dist/components/DataList.svelte +111 -0
- package/dist/components/DataList.svelte.d.ts +10 -0
- package/dist/components/DataListTypes.d.ts +14 -0
- package/dist/components/DataListTypes.js +1 -0
- package/dist/components/IconButton.svelte +12 -4
- package/dist/components/IconButton.svelte.d.ts +2 -0
- package/dist/components/Layout.svelte +1 -1
- package/dist/components/Popover.svelte +4 -1
- package/dist/components/Tabs.svelte +13 -1
- package/dist/components/Tabs.svelte.d.ts +2 -0
- package/dist/components/Tag.svelte +11 -3
- package/dist/components/Tag.svelte.d.ts +2 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.js +3 -0
- package/dist/css/1-props.css +157 -136
- package/dist/css/2-init.css +39 -23
- package/dist/css/themes/DefaultTheme.css +10 -0
- package/dist/form/Button.svelte +4 -4
- package/dist/form/Button.svelte.d.ts +1 -1
- package/dist/form/FieldContent.svelte +11 -3
- package/dist/form/FieldContent.svelte.d.ts +2 -0
- package/dist/form/FieldGroup.svelte +84 -0
- package/dist/form/FieldGroup.svelte.d.ts +20 -0
- package/dist/form/Input.svelte +4 -0
- package/dist/form/Input.svelte.d.ts +2 -0
- package/dist/form/SegmentedControl.svelte +273 -0
- package/dist/form/SegmentedControl.svelte.d.ts +33 -0
- package/dist/form/SegmentedControlTypes.d.ts +8 -0
- package/dist/form/SegmentedControlTypes.js +1 -0
- package/dist/form/Select.svelte +4 -0
- package/dist/form/Select.svelte.d.ts +2 -0
- package/dist/form/Textarea.svelte +4 -0
- package/dist/form/Textarea.svelte.d.ts +2 -0
- package/dist/form/Toggle.svelte +166 -0
- package/dist/form/Toggle.svelte.d.ts +33 -17
- package/dist/form/index.d.ts +3 -0
- package/dist/form/index.js +3 -0
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@ type $$ComponentProps = {
|
|
|
7
7
|
/** Visual style variant. */
|
|
8
8
|
kind?: 'default' | 'outlined' | 'secondary' | 'warn';
|
|
9
9
|
/** Size variant. */
|
|
10
|
-
|
|
10
|
+
scale?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
11
11
|
/** Additional CSS class names. */
|
|
12
12
|
class?: string;
|
|
13
13
|
/** Whether the button is disabled. Also disabled automatically when the parent form is loading. */
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
help,
|
|
28
28
|
type = "text",
|
|
29
29
|
direction = 'column', // 'row' | 'column'
|
|
30
|
+
scale = 'md',
|
|
30
31
|
required,
|
|
31
32
|
children,
|
|
32
33
|
field,
|
|
@@ -42,6 +43,8 @@
|
|
|
42
43
|
labelTip?: string | Snippet;
|
|
43
44
|
labelHelp?: string | Snippet;
|
|
44
45
|
direction?: 'row' | 'column';
|
|
46
|
+
/** Size variant controlling font-size. Em-based tokens cascade automatically. */
|
|
47
|
+
scale?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
45
48
|
required?: boolean;
|
|
46
49
|
children: Snippet;
|
|
47
50
|
field?: FormField;
|
|
@@ -63,7 +66,7 @@
|
|
|
63
66
|
</div>
|
|
64
67
|
{/snippet}
|
|
65
68
|
|
|
66
|
-
<div class="FieldContentContainer">
|
|
69
|
+
<div class="FieldContentContainer {scale}">
|
|
67
70
|
<div class="FieldContent {type} {direction}" class:contained>
|
|
68
71
|
<Label {label} tip={labelTip} help={labelHelp} {id} {required} />
|
|
69
72
|
{#if contained}
|
|
@@ -179,9 +182,14 @@
|
|
|
179
182
|
border-radius: calc(var(--field-border-radius) - 2px);
|
|
180
183
|
}
|
|
181
184
|
.Help {
|
|
182
|
-
font-size:
|
|
185
|
+
font-size: var(--font-size-sm);
|
|
183
186
|
line-height: var(--font-line-height-tight);
|
|
184
187
|
color: var(--text-color-p-subtle);
|
|
185
|
-
font-weight: var(--font-weight-
|
|
188
|
+
font-weight: var(--font-weight-light);
|
|
186
189
|
}
|
|
190
|
+
|
|
191
|
+
.FieldContentContainer.xs { font-size: var(--font-size-xs); }
|
|
192
|
+
.FieldContentContainer.sm { font-size: var(--font-size-sm); }
|
|
193
|
+
.FieldContentContainer.lg { font-size: var(--font-size-h5); }
|
|
194
|
+
.FieldContentContainer.xl { font-size: var(--font-size-h4); }
|
|
187
195
|
</style>
|
|
@@ -11,6 +11,8 @@ type $$ComponentProps = {
|
|
|
11
11
|
labelTip?: string | Snippet;
|
|
12
12
|
labelHelp?: string | Snippet;
|
|
13
13
|
direction?: 'row' | 'column';
|
|
14
|
+
/** Size variant controlling font-size. Em-based tokens cascade automatically. */
|
|
15
|
+
scale?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
14
16
|
required?: boolean;
|
|
15
17
|
children: Snippet;
|
|
16
18
|
field?: FormField;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import Label from "./Label.svelte";
|
|
4
|
+
import StringOrSnippet from "../util/StringOrSnippet.svelte";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @description
|
|
8
|
+
* Groups related form fields (checkboxes, radios, toggles) under a shared label
|
|
9
|
+
* with a tighter gap than the default form field spacing.
|
|
10
|
+
*
|
|
11
|
+
* @cssprop --field-group-gap -- Gap between items within the group.
|
|
12
|
+
* @cssprop --form-label-gap -- Gap between the group label and the items.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <FieldGroup label="Permissions">
|
|
16
|
+
* <Input name="read" type="checkbox" label="Read" />
|
|
17
|
+
* <Input name="write" type="checkbox" label="Write" />
|
|
18
|
+
* <Input name="admin" type="checkbox" label="Admin" />
|
|
19
|
+
* </FieldGroup>
|
|
20
|
+
*/
|
|
21
|
+
let {
|
|
22
|
+
id = crypto.randomUUID(),
|
|
23
|
+
label,
|
|
24
|
+
labelHelp,
|
|
25
|
+
labelTip,
|
|
26
|
+
help,
|
|
27
|
+
required,
|
|
28
|
+
children,
|
|
29
|
+
}: {
|
|
30
|
+
/** A unique id for the group. Auto-generated if not provided. */
|
|
31
|
+
id?: string;
|
|
32
|
+
/** The group label. */
|
|
33
|
+
label?: string | Snippet;
|
|
34
|
+
/** Help text to display alongside the label. */
|
|
35
|
+
labelHelp?: string | Snippet;
|
|
36
|
+
/** Context tooltip for the label. */
|
|
37
|
+
labelTip?: string | Snippet;
|
|
38
|
+
/** Help text to display below the group. */
|
|
39
|
+
help?: string | Snippet;
|
|
40
|
+
/** Whether the group is required. */
|
|
41
|
+
required?: boolean;
|
|
42
|
+
/** The grouped fields to render. */
|
|
43
|
+
children: Snippet;
|
|
44
|
+
} = $props();
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<div
|
|
48
|
+
class="FieldGroup"
|
|
49
|
+
role="group"
|
|
50
|
+
aria-labelledby={label ? `fg-${id}` : undefined}
|
|
51
|
+
>
|
|
52
|
+
{#if label}
|
|
53
|
+
<div id="fg-{id}">
|
|
54
|
+
<Label {label} tip={labelTip} help={labelHelp} {required} />
|
|
55
|
+
</div>
|
|
56
|
+
{/if}
|
|
57
|
+
<div class="FieldGroupContent">
|
|
58
|
+
{@render children()}
|
|
59
|
+
</div>
|
|
60
|
+
{#if help}
|
|
61
|
+
<div class="Help">
|
|
62
|
+
<StringOrSnippet content={help} />
|
|
63
|
+
</div>
|
|
64
|
+
{/if}
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<style>
|
|
68
|
+
.FieldGroup {
|
|
69
|
+
display: flex;
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
gap: var(--form-label-gap, var(--space-xs));
|
|
72
|
+
}
|
|
73
|
+
.FieldGroupContent {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
gap: var(--field-group-gap);
|
|
77
|
+
}
|
|
78
|
+
.Help {
|
|
79
|
+
font-size: var(--font-size-sm);
|
|
80
|
+
line-height: var(--font-line-height-tight);
|
|
81
|
+
color: var(--text-color-p-subtle);
|
|
82
|
+
font-weight: var(--font-weight-light);
|
|
83
|
+
}
|
|
84
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
/** A unique id for the group. Auto-generated if not provided. */
|
|
4
|
+
id?: string;
|
|
5
|
+
/** The group label. */
|
|
6
|
+
label?: string | Snippet;
|
|
7
|
+
/** Help text to display alongside the label. */
|
|
8
|
+
labelHelp?: string | Snippet;
|
|
9
|
+
/** Context tooltip for the label. */
|
|
10
|
+
labelTip?: string | Snippet;
|
|
11
|
+
/** Help text to display below the group. */
|
|
12
|
+
help?: string | Snippet;
|
|
13
|
+
/** Whether the group is required. */
|
|
14
|
+
required?: boolean;
|
|
15
|
+
/** The grouped fields to render. */
|
|
16
|
+
children: Snippet;
|
|
17
|
+
};
|
|
18
|
+
declare const FieldGroup: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
19
|
+
type FieldGroup = ReturnType<typeof FieldGroup>;
|
|
20
|
+
export default FieldGroup;
|
package/dist/form/Input.svelte
CHANGED
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
readonly,
|
|
70
70
|
required,
|
|
71
71
|
shape = 'rounded',
|
|
72
|
+
scale = 'md',
|
|
72
73
|
size,
|
|
73
74
|
src,
|
|
74
75
|
step,
|
|
@@ -162,6 +163,8 @@
|
|
|
162
163
|
required?: boolean;
|
|
163
164
|
/** The shape of the input element. */
|
|
164
165
|
shape?: 'default' | 'rounded' | 'pill' | 'circle';
|
|
166
|
+
/** Size variant controlling font-size. Em-based tokens cascade automatically. */
|
|
167
|
+
scale?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
165
168
|
/** The size of the input element. */
|
|
166
169
|
size?: number;
|
|
167
170
|
/** Source URL for the image type. */
|
|
@@ -350,6 +353,7 @@
|
|
|
350
353
|
{prefix}
|
|
351
354
|
{suffix}
|
|
352
355
|
{required}
|
|
356
|
+
{scale}
|
|
353
357
|
>
|
|
354
358
|
|
|
355
359
|
{#if type === "checkbox" || type === "radio"}
|
|
@@ -83,6 +83,8 @@ type $$ComponentProps = {
|
|
|
83
83
|
required?: boolean;
|
|
84
84
|
/** The shape of the input element. */
|
|
85
85
|
shape?: 'default' | 'rounded' | 'pill' | 'circle';
|
|
86
|
+
/** Size variant controlling font-size. Em-based tokens cascade automatically. */
|
|
87
|
+
scale?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
86
88
|
/** The size of the input element. */
|
|
87
89
|
size?: number;
|
|
88
90
|
/** Source URL for the image type. */
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getContext, onMount, type Snippet } from "svelte";
|
|
3
|
+
import { BROWSER } from "esm-env";
|
|
4
|
+
import type { LutraForm } from "./types.js";
|
|
5
|
+
import { fieldChange } from "./client.svelte.js";
|
|
6
|
+
import FieldContent from "./FieldContent.svelte";
|
|
7
|
+
import { getFromObjWithStringPath } from "./form.js";
|
|
8
|
+
import { ZodType } from "zod";
|
|
9
|
+
import type { SegmentedControlOption } from "./SegmentedControlTypes.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @description
|
|
13
|
+
* A segmented control that functions as a styled radio group. Works both as a
|
|
14
|
+
* standalone control (with `onchange` callback and bindable `value`) and as a
|
|
15
|
+
* form-integrated field via the Lutra form system.
|
|
16
|
+
*
|
|
17
|
+
* Options can be passed as `string[]` (each string used as both label and value)
|
|
18
|
+
* or as `SegmentedControlOption[]` for more control.
|
|
19
|
+
*
|
|
20
|
+
* @cssprop --segmented-background - Track background. (Default: var(--tab-background-color, var(--menu-background-color)))
|
|
21
|
+
* @cssprop --segmented-background-active - Selected segment background. (Default: var(--tab-background-color-active, var(--background-selected)))
|
|
22
|
+
* @cssprop --segmented-text-color - Text color. (Default: var(--tab-text-color, var(--menu-text-color)))
|
|
23
|
+
* @cssprop --segmented-text-color-active - Selected text color. (Default: var(--tab-text-color-active, var(--text-color-heading)))
|
|
24
|
+
* @cssprop --segmented-border-size - Border width. (Default: var(--tab-border-size, var(--menu-border-size)))
|
|
25
|
+
* @cssprop --segmented-border-style - Border style. (Default: var(--tab-border-style, var(--menu-border-style)))
|
|
26
|
+
* @cssprop --segmented-border-color - Border color. (Default: var(--tab-border-color, var(--menu-border-color)))
|
|
27
|
+
* @cssprop --segmented-border-radius - Border radius. (Default: var(--tab-border-radius, var(--menu-border-radius)))
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* <SegmentedControl name="view" options={['List', 'Grid', 'Board']} />
|
|
31
|
+
* <SegmentedControl name="tab" options={[{ label: 'Inbox', value: 'inbox' }, { label: 'Sent', value: 'sent' }]} />
|
|
32
|
+
*/
|
|
33
|
+
let {
|
|
34
|
+
disabled,
|
|
35
|
+
help,
|
|
36
|
+
id = $bindable(crypto.randomUUID()),
|
|
37
|
+
label,
|
|
38
|
+
labelHelp,
|
|
39
|
+
labelTip,
|
|
40
|
+
name,
|
|
41
|
+
onchange,
|
|
42
|
+
options,
|
|
43
|
+
required,
|
|
44
|
+
shape = "rounded",
|
|
45
|
+
scale = "md",
|
|
46
|
+
value = $bindable(""),
|
|
47
|
+
}: {
|
|
48
|
+
/** Whether the entire control is disabled. */
|
|
49
|
+
disabled?: boolean;
|
|
50
|
+
/** Help text to display below the control. */
|
|
51
|
+
help?: string | Snippet;
|
|
52
|
+
/** A random id is generated if not provided. */
|
|
53
|
+
id?: string;
|
|
54
|
+
/** The label for the control. */
|
|
55
|
+
label?: string | Snippet;
|
|
56
|
+
/** Help text to display below the label. */
|
|
57
|
+
labelHelp?: string | Snippet;
|
|
58
|
+
/** Context tooltip for the label. Renders with a questionmark using ContextTip. */
|
|
59
|
+
labelTip?: string | Snippet;
|
|
60
|
+
/** The name of the field (used as the radio group name). */
|
|
61
|
+
name: string;
|
|
62
|
+
/** Change event handler. */
|
|
63
|
+
onchange?: (e: Event) => void;
|
|
64
|
+
/** Segment options. Accepts `string[]` or `SegmentedControlOption[]`. */
|
|
65
|
+
options: string[] | SegmentedControlOption[];
|
|
66
|
+
/** Whether the field is required. */
|
|
67
|
+
required?: boolean;
|
|
68
|
+
/** The shape of the control. */
|
|
69
|
+
shape?: "rounded" | "pill" | "rectangle";
|
|
70
|
+
/** Size variant controlling padding and font-size. */
|
|
71
|
+
scale?: "xs" | "sm" | "md" | "lg" | "xl";
|
|
72
|
+
/** The currently selected value (bindable). */
|
|
73
|
+
value?: string;
|
|
74
|
+
} = $props();
|
|
75
|
+
|
|
76
|
+
/** Normalise string[] options into SegmentedControlOption[]. */
|
|
77
|
+
const normalised = $derived(
|
|
78
|
+
options.map((o): SegmentedControlOption =>
|
|
79
|
+
typeof o === "string" ? { label: o, value: o } : o
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
let els: HTMLInputElement[] = $state([]);
|
|
84
|
+
let segmentEls: HTMLLabelElement[] = $state([]);
|
|
85
|
+
let loaded = $state(false);
|
|
86
|
+
|
|
87
|
+
const form = getContext<LutraForm<any>>("form");
|
|
88
|
+
const field = $derived(form?.fields[name]);
|
|
89
|
+
const issue = $derived(form?.issues?.find((issue) => issue.name === name));
|
|
90
|
+
const validator = getContext<Record<string, ZodType>>("form.validators")?.[name];
|
|
91
|
+
const data = form?.data;
|
|
92
|
+
const originalData = form?.originalData;
|
|
93
|
+
|
|
94
|
+
if (!value) {
|
|
95
|
+
const formValue = form
|
|
96
|
+
? (getFromObjWithStringPath(Object.assign(originalData ?? {}, data ?? {}), name) as string)
|
|
97
|
+
: undefined;
|
|
98
|
+
if (formValue) value = formValue;
|
|
99
|
+
else if (normalised.length) value = normalised[0].value;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const selectedIndex = $derived(
|
|
103
|
+
normalised.findIndex((o) => o.value === value)
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const indicatorStyle = $derived.by(() => {
|
|
107
|
+
if (!BROWSER || !loaded || selectedIndex < 0) return "opacity: 0;";
|
|
108
|
+
const el = segmentEls[selectedIndex];
|
|
109
|
+
if (!el) return "opacity: 0;";
|
|
110
|
+
return `opacity: 1; width: ${el.offsetWidth}px; translate: ${el.offsetLeft}px 0;`;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
onMount(async () => {
|
|
114
|
+
if (value) {
|
|
115
|
+
const checkedEl = els.find((el) => el?.value === value);
|
|
116
|
+
if (checkedEl) fieldChange(form, name, () => checkedEl)({} as any);
|
|
117
|
+
}
|
|
118
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
119
|
+
loaded = true;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
function handleChange(e: Event, index: number) {
|
|
123
|
+
fieldChange(form, name, () => els[index], validator, onchange)(e);
|
|
124
|
+
}
|
|
125
|
+
</script>
|
|
126
|
+
|
|
127
|
+
<FieldContent
|
|
128
|
+
{id}
|
|
129
|
+
{label}
|
|
130
|
+
{labelHelp}
|
|
131
|
+
{labelTip}
|
|
132
|
+
contained={false}
|
|
133
|
+
{field}
|
|
134
|
+
{issue}
|
|
135
|
+
type="segmented"
|
|
136
|
+
{help}
|
|
137
|
+
{required}
|
|
138
|
+
>
|
|
139
|
+
<div class="SegmentedControl {shape} {scale}" role="radiogroup">
|
|
140
|
+
{#each normalised as option, i}
|
|
141
|
+
<label
|
|
142
|
+
bind:this={segmentEls[i]}
|
|
143
|
+
class="Segment"
|
|
144
|
+
class:selected={value === option.value}
|
|
145
|
+
class:disabled={disabled || option.disabled}
|
|
146
|
+
>
|
|
147
|
+
<input
|
|
148
|
+
type="radio"
|
|
149
|
+
bind:this={els[i]}
|
|
150
|
+
{name}
|
|
151
|
+
value={option.value}
|
|
152
|
+
disabled={disabled || option.disabled}
|
|
153
|
+
required={i === 0 ? (required || field?.required) : undefined}
|
|
154
|
+
bind:group={value}
|
|
155
|
+
onchange={(e) => handleChange(e, i)}
|
|
156
|
+
/>
|
|
157
|
+
{option.label}
|
|
158
|
+
</label>
|
|
159
|
+
{/each}
|
|
160
|
+
<div class="Indicator" style={indicatorStyle}></div>
|
|
161
|
+
</div>
|
|
162
|
+
</FieldContent>
|
|
163
|
+
|
|
164
|
+
<svelte:window onresize={() => { loaded = false; loaded = true; }} />
|
|
165
|
+
|
|
166
|
+
<style>
|
|
167
|
+
.SegmentedControl {
|
|
168
|
+
position: relative;
|
|
169
|
+
display: inline-flex;
|
|
170
|
+
background: var(--segmented-background, var(--tab-background-color, var(--menu-background-color)));
|
|
171
|
+
border: var(--segmented-border-size, var(--tab-border-size, var(--menu-border-size)))
|
|
172
|
+
var(--segmented-border-style, var(--tab-border-style, var(--menu-border-style)))
|
|
173
|
+
var(--segmented-border-color, var(--tab-border-color, var(--menu-border-color)));
|
|
174
|
+
border-radius: var(--segmented-border-radius, var(--tab-border-radius, var(--menu-border-radius)));
|
|
175
|
+
overflow: clip;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.SegmentedControl.pill {
|
|
179
|
+
border-radius: calc(infinity * 1px);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.SegmentedControl.rectangle {
|
|
183
|
+
border-radius: 0;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.Segment {
|
|
187
|
+
position: relative;
|
|
188
|
+
z-index: 1;
|
|
189
|
+
display: flex;
|
|
190
|
+
align-items: center;
|
|
191
|
+
justify-content: center;
|
|
192
|
+
border-radius: inherit;
|
|
193
|
+
cursor: pointer;
|
|
194
|
+
color: var(--segmented-text-color, var(--tab-text-color, var(--menu-text-color)));
|
|
195
|
+
font-weight: var(--font-weight-medium);
|
|
196
|
+
letter-spacing: var(--tab-letter-spacing, -0.05ch);
|
|
197
|
+
user-select: none;
|
|
198
|
+
transition: color var(--transition-duration-fast) var(--transition-timing-function);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.Segment:hover:not(.disabled):not(.selected) {
|
|
202
|
+
background: var(--tab-background-color-hover, var(--menu-background-color-hover));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.Segment.selected {
|
|
206
|
+
color: var(--segmented-text-color-active, var(--tab-text-color-active, var(--text-color-heading)));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.Segment.disabled {
|
|
210
|
+
opacity: 0.5;
|
|
211
|
+
cursor: not-allowed;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.Segment:has(input:focus-visible) {
|
|
215
|
+
outline: var(--focus-ring-size) solid var(--focus-ring-color);
|
|
216
|
+
outline-offset: calc(-1 * var(--focus-ring-size));
|
|
217
|
+
z-index: 2;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.Segment input {
|
|
221
|
+
position: absolute;
|
|
222
|
+
opacity: 0;
|
|
223
|
+
pointer-events: none;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.Indicator {
|
|
227
|
+
position: absolute;
|
|
228
|
+
inset-block: 0;
|
|
229
|
+
inset-inline-start: 0;
|
|
230
|
+
background: var(--segmented-background-active, var(--tab-background-color-active, var(--background-selected)));
|
|
231
|
+
border-radius: inherit;
|
|
232
|
+
transition:
|
|
233
|
+
translate var(--transition-duration-fast) ease-out,
|
|
234
|
+
width var(--transition-duration-fast) ease-out;
|
|
235
|
+
opacity: 0;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
@media (prefers-reduced-motion: reduce) {
|
|
239
|
+
.Indicator {
|
|
240
|
+
transition: none;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* Size: xs */
|
|
245
|
+
.SegmentedControl.xs .Segment {
|
|
246
|
+
padding: 0.125em 0.375em;
|
|
247
|
+
font-size: var(--font-size-xs);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* Size: sm */
|
|
251
|
+
.SegmentedControl.sm .Segment {
|
|
252
|
+
padding: var(--space-xxs) var(--space-sm);
|
|
253
|
+
font-size: var(--font-size-sm);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* Size: md */
|
|
257
|
+
.SegmentedControl.md .Segment {
|
|
258
|
+
padding: var(--space-xs) var(--space-md);
|
|
259
|
+
font-size: var(--font-size-sm);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/* Size: lg */
|
|
263
|
+
.SegmentedControl.lg .Segment {
|
|
264
|
+
padding: var(--space-sm) var(--space-lg);
|
|
265
|
+
font-size: 1em;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/* Size: xl */
|
|
269
|
+
.SegmentedControl.xl .Segment {
|
|
270
|
+
padding: var(--space-md) var(--space-xl);
|
|
271
|
+
font-size: var(--font-size-h5);
|
|
272
|
+
}
|
|
273
|
+
</style>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type Snippet } from "svelte";
|
|
2
|
+
import type { SegmentedControlOption } from "./SegmentedControlTypes.js";
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
/** Whether the entire control is disabled. */
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
/** Help text to display below the control. */
|
|
7
|
+
help?: string | Snippet;
|
|
8
|
+
/** A random id is generated if not provided. */
|
|
9
|
+
id?: string;
|
|
10
|
+
/** The label for the control. */
|
|
11
|
+
label?: string | Snippet;
|
|
12
|
+
/** Help text to display below the label. */
|
|
13
|
+
labelHelp?: string | Snippet;
|
|
14
|
+
/** Context tooltip for the label. Renders with a questionmark using ContextTip. */
|
|
15
|
+
labelTip?: string | Snippet;
|
|
16
|
+
/** The name of the field (used as the radio group name). */
|
|
17
|
+
name: string;
|
|
18
|
+
/** Change event handler. */
|
|
19
|
+
onchange?: (e: Event) => void;
|
|
20
|
+
/** Segment options. Accepts `string[]` or `SegmentedControlOption[]`. */
|
|
21
|
+
options: string[] | SegmentedControlOption[];
|
|
22
|
+
/** Whether the field is required. */
|
|
23
|
+
required?: boolean;
|
|
24
|
+
/** The shape of the control. */
|
|
25
|
+
shape?: "rounded" | "pill" | "rectangle";
|
|
26
|
+
/** Size variant controlling padding and font-size. */
|
|
27
|
+
scale?: "xs" | "sm" | "md" | "lg" | "xl";
|
|
28
|
+
/** The currently selected value (bindable). */
|
|
29
|
+
value?: string;
|
|
30
|
+
};
|
|
31
|
+
declare const SegmentedControl: import("svelte").Component<$$ComponentProps, {}, "id" | "value">;
|
|
32
|
+
type SegmentedControl = ReturnType<typeof SegmentedControl>;
|
|
33
|
+
export default SegmentedControl;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/form/Select.svelte
CHANGED
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
required,
|
|
41
41
|
results,
|
|
42
42
|
shape = 'default',
|
|
43
|
+
scale = 'md',
|
|
43
44
|
tabindex,
|
|
44
45
|
value = $bindable(),
|
|
45
46
|
}: {
|
|
@@ -87,6 +88,8 @@
|
|
|
87
88
|
results?: number;
|
|
88
89
|
/** The shape of the input element. */
|
|
89
90
|
shape?: 'default' | 'rounded' | 'pill' | 'circle';
|
|
91
|
+
/** Size variant controlling font-size. Em-based tokens cascade automatically. */
|
|
92
|
+
scale?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
90
93
|
/** Source URL for the image type. */
|
|
91
94
|
src?: string;
|
|
92
95
|
/** An integer attribute indicating if the element can take input focus (is focusable), if it should participate to sequential keyboard navigation. */
|
|
@@ -120,6 +123,7 @@
|
|
|
120
123
|
{field}
|
|
121
124
|
{issue}
|
|
122
125
|
{required}
|
|
126
|
+
{scale}
|
|
123
127
|
contained
|
|
124
128
|
>
|
|
125
129
|
<div class="SelectContainer">
|
|
@@ -47,6 +47,8 @@ type $$ComponentProps = {
|
|
|
47
47
|
results?: number;
|
|
48
48
|
/** The shape of the input element. */
|
|
49
49
|
shape?: 'default' | 'rounded' | 'pill' | 'circle';
|
|
50
|
+
/** Size variant controlling font-size. Em-based tokens cascade automatically. */
|
|
51
|
+
scale?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
50
52
|
/** Source URL for the image type. */
|
|
51
53
|
src?: string;
|
|
52
54
|
/** An integer attribute indicating if the element can take input focus (is focusable), if it should participate to sequential keyboard navigation. */
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
required,
|
|
56
56
|
resize,
|
|
57
57
|
shape = 'rounded',
|
|
58
|
+
scale = 'md',
|
|
58
59
|
step,
|
|
59
60
|
style,
|
|
60
61
|
tabindex,
|
|
@@ -138,6 +139,8 @@
|
|
|
138
139
|
resize?: boolean | 'both' | 'horizontal' | 'vertical' | 'none';
|
|
139
140
|
/** The shape of the input element. */
|
|
140
141
|
shape?: 'default' | 'rounded' | 'pill' | 'circle';
|
|
142
|
+
/** Size variant controlling font-size. Em-based tokens cascade automatically. */
|
|
143
|
+
scale?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
141
144
|
/** Spellcheck the input. */
|
|
142
145
|
spellcheck?: boolean;
|
|
143
146
|
/** A number that specifies the granularity that the value must adhere to. Valid for date, month, week, time, datetime-local, number, and range. */
|
|
@@ -221,6 +224,7 @@
|
|
|
221
224
|
{help}
|
|
222
225
|
{suffix}
|
|
223
226
|
{required}
|
|
227
|
+
{scale}
|
|
224
228
|
>
|
|
225
229
|
<textarea
|
|
226
230
|
class="{resizeClass}"
|
|
@@ -77,6 +77,8 @@ type $$ComponentProps = {
|
|
|
77
77
|
resize?: boolean | 'both' | 'horizontal' | 'vertical' | 'none';
|
|
78
78
|
/** The shape of the input element. */
|
|
79
79
|
shape?: 'default' | 'rounded' | 'pill' | 'circle';
|
|
80
|
+
/** Size variant controlling font-size. Em-based tokens cascade automatically. */
|
|
81
|
+
scale?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
80
82
|
/** Spellcheck the input. */
|
|
81
83
|
spellcheck?: boolean;
|
|
82
84
|
/** A number that specifies the granularity that the value must adhere to. Valid for date, month, week, time, datetime-local, number, and range. */
|