@sveltia/ui 0.7.4 → 0.7.5
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/package/components/button/button.svelte +8 -0
- package/package/components/button/button.svelte.d.ts +5 -0
- package/package/components/button/select-button-group.svelte +3 -3
- package/package/components/checkbox/checkbox.svelte +10 -5
- package/package/components/dialog/dialog.svelte +2 -2
- package/package/components/disclosure/disclosure.svelte +0 -1
- package/package/components/drawer/drawer.svelte +2 -2
- package/package/components/drawer/drawer.svelte.d.ts +2 -2
- package/package/components/listbox/listbox.svelte +3 -3
- package/package/components/radio/radio-group.svelte +3 -3
- package/package/components/radio/radio-group.svelte.d.ts +2 -2
- package/package/components/select/combobox.svelte +46 -28
- package/package/components/select/combobox.svelte.d.ts +3 -2
- package/package/components/select/select.svelte +10 -9
- package/package/components/select/select.svelte.d.ts +4 -3
- package/package/components/slider/slider.svelte +3 -2
- package/package/components/switch/switch.svelte +6 -4
- package/package/components/text-field/markdown-editor.svelte +9 -6
- package/package/components/text-field/number-input.svelte +74 -40
- package/package/components/text-field/password-input.svelte +9 -4
- package/package/components/text-field/search-bar.svelte +4 -2
- package/package/components/text-field/text-area.svelte +6 -5
- package/package/components/text-field/text-input.svelte +16 -4
- package/package/components/text-field/text-input.svelte.d.ts +7 -2
- package/package/components/util/app-shell.svelte +8 -2
- package/package/components/util/popup.svelte +8 -3
- package/package/components/util/popup.svelte.d.ts +5 -0
- package/package/services/group.js +16 -0
- package/package/services/popup.d.ts +5 -1
- package/package/services/popup.js +22 -19
- package/package/styles/core.scss +4 -0
- package/package/styles/variables.scss +2 -2
- package/package.json +11 -11
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
*/
|
|
33
33
|
export let readonly = false;
|
|
34
34
|
/**
|
|
35
|
-
* Whether to
|
|
35
|
+
* Whether to mark the widget required. An alias of the `aria-required` attribute.
|
|
36
36
|
* @type {boolean}
|
|
37
37
|
*/
|
|
38
38
|
export let required = false;
|
|
39
39
|
/**
|
|
40
|
-
* Whether to
|
|
40
|
+
* Whether to mark the widget invalid. An alias of the `aria-invalid` attribute.
|
|
41
41
|
* @type {boolean}
|
|
42
42
|
*/
|
|
43
43
|
export let invalid = false;
|
|
@@ -61,14 +61,19 @@
|
|
|
61
61
|
*/
|
|
62
62
|
export let step = 1;
|
|
63
63
|
|
|
64
|
+
let edited = false;
|
|
65
|
+
|
|
64
66
|
$: maximumFractionDigits = String(step).split('.')[1]?.length || 0;
|
|
65
67
|
$: isMin = typeof min === 'number' && Number(value || 0) <= min;
|
|
66
68
|
$: isMax = typeof max === 'number' && Number(value || 0) >= max;
|
|
67
69
|
|
|
68
70
|
$: invalid =
|
|
69
|
-
(
|
|
70
|
-
(
|
|
71
|
-
|
|
71
|
+
(required && edited && (value === undefined || value === '')) ||
|
|
72
|
+
(value !== undefined &&
|
|
73
|
+
value !== '' &&
|
|
74
|
+
(Number.isNaN(Number(value)) ||
|
|
75
|
+
(typeof min === 'number' && Number(value || 0) < min) ||
|
|
76
|
+
(typeof max === 'number' && Number(value || 0) > max)));
|
|
72
77
|
|
|
73
78
|
let component;
|
|
74
79
|
|
|
@@ -95,7 +100,32 @@
|
|
|
95
100
|
};
|
|
96
101
|
</script>
|
|
97
102
|
|
|
98
|
-
<div
|
|
103
|
+
<div
|
|
104
|
+
class="sui number-input {className}"
|
|
105
|
+
class:disabled
|
|
106
|
+
class:readonly
|
|
107
|
+
hidden={hidden || undefined}
|
|
108
|
+
>
|
|
109
|
+
<div class="buttons">
|
|
110
|
+
<Button
|
|
111
|
+
iconic
|
|
112
|
+
disabled={disabled || readonly || Number.isNaN(Number(value)) || isMax}
|
|
113
|
+
on:click={() => {
|
|
114
|
+
increase();
|
|
115
|
+
}}
|
|
116
|
+
>
|
|
117
|
+
<Icon slot="start-icon" name="expand_less" label={$_('_sui.number_input.increase')} />
|
|
118
|
+
</Button>
|
|
119
|
+
<Button
|
|
120
|
+
iconic
|
|
121
|
+
disabled={disabled || readonly || Number.isNaN(Number(value)) || isMin}
|
|
122
|
+
on:click={() => {
|
|
123
|
+
decrease();
|
|
124
|
+
}}
|
|
125
|
+
>
|
|
126
|
+
<Icon slot="start-icon" name="expand_more" label={$_('_sui.number_input.decrease')} />
|
|
127
|
+
</Button>
|
|
128
|
+
</div>
|
|
99
129
|
<TextInput
|
|
100
130
|
bind:this={component}
|
|
101
131
|
bind:value
|
|
@@ -108,6 +138,7 @@
|
|
|
108
138
|
aria-valuenow={Number(value || 0)}
|
|
109
139
|
aria-valuemin={min}
|
|
110
140
|
aria-valuemax={max}
|
|
141
|
+
inputmode={maximumFractionDigits > 0 ? 'decimal' : 'numeric'}
|
|
111
142
|
{...$$restProps}
|
|
112
143
|
on:keydown={(event) => {
|
|
113
144
|
const { key, ctrlKey, metaKey, altKey, shiftKey } = event;
|
|
@@ -122,28 +153,14 @@
|
|
|
122
153
|
event.preventDefault();
|
|
123
154
|
increase();
|
|
124
155
|
}
|
|
156
|
+
|
|
157
|
+
if (!edited) {
|
|
158
|
+
edited = true;
|
|
159
|
+
}
|
|
125
160
|
}}
|
|
126
161
|
on:keypress
|
|
127
162
|
on:input
|
|
128
163
|
/>
|
|
129
|
-
<Button
|
|
130
|
-
iconic
|
|
131
|
-
disabled={disabled || Number.isNaN(Number(value)) || isMin}
|
|
132
|
-
on:click={() => {
|
|
133
|
-
decrease();
|
|
134
|
-
}}
|
|
135
|
-
>
|
|
136
|
-
<Icon slot="start-icon" name="arrow_downward" label={$_('_sui.number_input.decrease')} />
|
|
137
|
-
</Button>
|
|
138
|
-
<Button
|
|
139
|
-
iconic
|
|
140
|
-
disabled={disabled || Number.isNaN(Number(value)) || isMax}
|
|
141
|
-
on:click={() => {
|
|
142
|
-
increase();
|
|
143
|
-
}}
|
|
144
|
-
>
|
|
145
|
-
<Icon slot="start-icon" name={'arrow_upward'} label={$_('_sui.number_input.increase')} />
|
|
146
|
-
</Button>
|
|
147
164
|
</div>
|
|
148
165
|
|
|
149
166
|
<style>.number-input {
|
|
@@ -151,29 +168,46 @@
|
|
|
151
168
|
display: inline-flex;
|
|
152
169
|
align-items: center;
|
|
153
170
|
}
|
|
154
|
-
.number-input :global(input) {
|
|
171
|
+
.number-input :global(:not(:first-child) input) {
|
|
172
|
+
border-top-left-radius: 0;
|
|
173
|
+
border-bottom-left-radius: 0;
|
|
174
|
+
}
|
|
175
|
+
.number-input :global(:not(:last-child) input) {
|
|
155
176
|
border-top-right-radius: 0;
|
|
156
177
|
border-bottom-right-radius: 0;
|
|
157
178
|
}
|
|
158
|
-
.number-input :global(button) {
|
|
179
|
+
.number-input:not(.disabled) :global(button[aria-disabled="true"]) {
|
|
180
|
+
filter: grayscale(0) opacity(1);
|
|
181
|
+
}
|
|
182
|
+
.number-input:not(.disabled) :global(button[aria-disabled="true"]) :global(*) {
|
|
183
|
+
filter: grayscale(1) opacity(0.35);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.buttons {
|
|
187
|
+
display: flex;
|
|
188
|
+
flex-direction: column;
|
|
189
|
+
width: 24px;
|
|
190
|
+
height: var(--sui-textbox-height);
|
|
191
|
+
}
|
|
192
|
+
.buttons :global(button) {
|
|
159
193
|
flex: none;
|
|
160
194
|
border-width: 1px;
|
|
161
195
|
border-color: var(--sui-textbox-border-color);
|
|
162
|
-
width:
|
|
163
|
-
|
|
164
|
-
.number-input :global(button):first-of-type {
|
|
165
|
-
border-radius: 0;
|
|
166
|
-
border-width: 1px 0;
|
|
167
|
-
}
|
|
168
|
-
.number-input :global(button):last-of-type {
|
|
169
|
-
border-radius: 0 4px 4px 0;
|
|
196
|
+
width: 100%;
|
|
197
|
+
height: 50%;
|
|
170
198
|
}
|
|
171
|
-
.
|
|
172
|
-
|
|
199
|
+
.buttons :global(button):first-of-type {
|
|
200
|
+
border-top-right-radius: 0;
|
|
201
|
+
border-bottom-right-radius: 0;
|
|
202
|
+
border-bottom-left-radius: 0;
|
|
203
|
+
border-width: 1px 0 0 1px;
|
|
173
204
|
}
|
|
174
|
-
.
|
|
175
|
-
|
|
205
|
+
.buttons :global(button):last-of-type {
|
|
206
|
+
border-top-left-radius: 0;
|
|
207
|
+
border-top-right-radius: 0;
|
|
208
|
+
border-bottom-right-radius: 0;
|
|
209
|
+
border-width: 0 0 1px 1px;
|
|
176
210
|
}
|
|
177
|
-
.
|
|
178
|
-
|
|
211
|
+
.buttons :global(button) :global(.icon) {
|
|
212
|
+
font-size: 20px;
|
|
179
213
|
}</style>
|
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
*/
|
|
34
34
|
export let readonly = false;
|
|
35
35
|
/**
|
|
36
|
-
* Whether to
|
|
36
|
+
* Whether to mark the widget required. An alias of the `aria-required` attribute.
|
|
37
37
|
* @type {boolean}
|
|
38
38
|
*/
|
|
39
39
|
export let required = false;
|
|
40
40
|
/**
|
|
41
|
-
* Whether to
|
|
41
|
+
* Whether to mark the widget invalid. An alias of the `aria-invalid` attribute.
|
|
42
42
|
* @type {boolean}
|
|
43
43
|
*/
|
|
44
44
|
export let invalid = false;
|
|
@@ -61,7 +61,12 @@
|
|
|
61
61
|
}
|
|
62
62
|
</script>
|
|
63
63
|
|
|
64
|
-
<div
|
|
64
|
+
<div
|
|
65
|
+
class="sui password-input {className}"
|
|
66
|
+
class:disabled
|
|
67
|
+
class:readonly
|
|
68
|
+
hidden={hidden || undefined}
|
|
69
|
+
>
|
|
65
70
|
<TextInput
|
|
66
71
|
bind:this={inputComponent}
|
|
67
72
|
bind:value
|
|
@@ -78,7 +83,7 @@
|
|
|
78
83
|
/>
|
|
79
84
|
<Button
|
|
80
85
|
iconic
|
|
81
|
-
{disabled}
|
|
86
|
+
disabled={disabled || readonly}
|
|
82
87
|
pressed={passwordVisible}
|
|
83
88
|
on:click={() => {
|
|
84
89
|
passwordVisible = !passwordVisible;
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
*/
|
|
36
36
|
export let readonly = false;
|
|
37
37
|
/**
|
|
38
|
-
* Whether to
|
|
38
|
+
* Whether to mark the widget required. An alias of the `aria-required` attribute.
|
|
39
39
|
* @type {boolean}
|
|
40
40
|
*/
|
|
41
41
|
export let required = false;
|
|
42
42
|
/**
|
|
43
|
-
* Whether to
|
|
43
|
+
* Whether to mark the widget invalid. An alias of the `aria-invalid` attribute.
|
|
44
44
|
* @type {boolean}
|
|
45
45
|
*/
|
|
46
46
|
export let invalid = false;
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
<div
|
|
70
70
|
class="sui search-bar {className}"
|
|
71
71
|
class:disabled
|
|
72
|
+
class:readonly
|
|
72
73
|
role="search"
|
|
73
74
|
hidden={hidden || undefined}
|
|
74
75
|
aria-hidden={hidden}
|
|
@@ -84,6 +85,7 @@
|
|
|
84
85
|
{readonly}
|
|
85
86
|
{required}
|
|
86
87
|
{invalid}
|
|
88
|
+
inputmode="search"
|
|
87
89
|
{...$$restProps}
|
|
88
90
|
bind:this={inputComponent}
|
|
89
91
|
on:input
|
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
*/
|
|
29
29
|
export let readonly = false;
|
|
30
30
|
/**
|
|
31
|
-
* Whether to
|
|
31
|
+
* Whether to mark the widget required. An alias of the `aria-required` attribute.
|
|
32
32
|
* @type {boolean}
|
|
33
33
|
*/
|
|
34
34
|
export let required = false;
|
|
35
35
|
/**
|
|
36
|
-
* Whether to
|
|
36
|
+
* Whether to mark the widget invalid. An alias of the `aria-invalid` attribute.
|
|
37
37
|
* @type {boolean}
|
|
38
38
|
*/
|
|
39
39
|
export let invalid = false;
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
export let autoResize = false;
|
|
55
55
|
</script>
|
|
56
56
|
|
|
57
|
-
<div class="sui text-area {className}" class:disabled hidden={hidden || undefined}>
|
|
57
|
+
<div class="sui text-area {className}" class:disabled class:readonly hidden={hidden || undefined}>
|
|
58
58
|
<textarea
|
|
59
59
|
{name}
|
|
60
60
|
bind:value
|
|
@@ -107,8 +107,9 @@ textarea:focus,
|
|
|
107
107
|
.clone:focus {
|
|
108
108
|
border-color: var(--sui-primary-accent-color);
|
|
109
109
|
}
|
|
110
|
-
textarea:disabled,
|
|
111
|
-
.clone:disabled
|
|
110
|
+
textarea:disabled, textarea:read-only,
|
|
111
|
+
.clone:disabled,
|
|
112
|
+
.clone:read-only {
|
|
112
113
|
background-color: var(--sui-disabled-background-color);
|
|
113
114
|
}
|
|
114
115
|
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
*/
|
|
43
43
|
export let readonly = false;
|
|
44
44
|
/**
|
|
45
|
-
* Whether to
|
|
45
|
+
* Whether to mark the widget required. An alias of the `aria-required` attribute.
|
|
46
46
|
* @type {boolean}
|
|
47
47
|
*/
|
|
48
48
|
export let required = false;
|
|
49
49
|
/**
|
|
50
|
-
* Whether to
|
|
50
|
+
* Whether to mark the widget invalid. An alias of the `aria-invalid` attribute.
|
|
51
51
|
* @type {boolean}
|
|
52
52
|
*/
|
|
53
53
|
export let invalid = false;
|
|
@@ -73,13 +73,19 @@
|
|
|
73
73
|
* @type {boolean}
|
|
74
74
|
*/
|
|
75
75
|
export let showInlineLabel = false;
|
|
76
|
+
/**
|
|
77
|
+
* The `inputmode` attribute on the `<input>`.
|
|
78
|
+
* @type {'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url'}
|
|
79
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode
|
|
80
|
+
*/
|
|
81
|
+
export let inputmode = 'text';
|
|
76
82
|
|
|
77
83
|
const id = getRandomId('input');
|
|
78
84
|
|
|
79
85
|
$: ariaLabel = $$restProps['aria-label'];
|
|
80
86
|
</script>
|
|
81
87
|
|
|
82
|
-
<div class="sui text-input {className}" class:disabled hidden={hidden || undefined}>
|
|
88
|
+
<div class="sui text-input {className}" class:disabled class:readonly hidden={hidden || undefined}>
|
|
83
89
|
<input
|
|
84
90
|
type="text"
|
|
85
91
|
{role}
|
|
@@ -87,6 +93,7 @@
|
|
|
87
93
|
tabindex={disabled ? -1 : 0}
|
|
88
94
|
disabled={disabled || undefined}
|
|
89
95
|
readonly={readonly || undefined}
|
|
96
|
+
{inputmode}
|
|
90
97
|
aria-hidden={hidden}
|
|
91
98
|
aria-disabled={disabled}
|
|
92
99
|
aria-readonly={readonly}
|
|
@@ -116,6 +123,11 @@
|
|
|
116
123
|
align-items: center;
|
|
117
124
|
}
|
|
118
125
|
|
|
126
|
+
input:-webkit-autofill,
|
|
127
|
+
input:-webkit-autofill:focus {
|
|
128
|
+
transition: background-color 0s 600000s, color 0s 600000s;
|
|
129
|
+
}
|
|
130
|
+
|
|
119
131
|
input {
|
|
120
132
|
z-index: 1;
|
|
121
133
|
display: inline-block;
|
|
@@ -140,7 +152,7 @@ input:read-only {
|
|
|
140
152
|
color: var(--sui-tertiary-foreground-color);
|
|
141
153
|
border-color: var(--sui-textbox-border-color) !important;
|
|
142
154
|
}
|
|
143
|
-
input:disabled {
|
|
155
|
+
input:disabled, input:read-only {
|
|
144
156
|
background-color: var(--sui-disabled-background-color);
|
|
145
157
|
}
|
|
146
158
|
input[aria-invalid=true] {
|
|
@@ -17,9 +17,10 @@ export default class TextInput extends SvelteComponent<{
|
|
|
17
17
|
hidden?: boolean;
|
|
18
18
|
element?: HTMLInputElement;
|
|
19
19
|
role?: "textbox" | "searchbox" | "combobox" | "spinbutton";
|
|
20
|
-
keyShortcuts?: string;
|
|
21
20
|
readonly?: boolean;
|
|
21
|
+
keyShortcuts?: string;
|
|
22
22
|
showInlineLabel?: boolean;
|
|
23
|
+
inputmode?: "text" | "numeric" | "decimal" | "tel" | "search" | "email" | "url";
|
|
23
24
|
}, {
|
|
24
25
|
input: Event;
|
|
25
26
|
keydown: KeyboardEvent;
|
|
@@ -65,6 +66,9 @@ export default class TextInput extends SvelteComponent<{
|
|
|
65
66
|
/**accessor*/
|
|
66
67
|
set showInlineLabel(arg: boolean);
|
|
67
68
|
get showInlineLabel(): boolean;
|
|
69
|
+
/**accessor*/
|
|
70
|
+
set inputmode(arg: "text" | "numeric" | "decimal" | "tel" | "search" | "email" | "url");
|
|
71
|
+
get inputmode(): "text" | "numeric" | "decimal" | "tel" | "search" | "email" | "url";
|
|
68
72
|
}
|
|
69
73
|
export type TextInputProps = typeof __propDef.props;
|
|
70
74
|
export type TextInputEvents = typeof __propDef.events;
|
|
@@ -82,9 +86,10 @@ declare const __propDef: {
|
|
|
82
86
|
hidden?: boolean | undefined;
|
|
83
87
|
element?: HTMLInputElement | undefined;
|
|
84
88
|
role?: 'textbox' | 'searchbox' | 'combobox' | 'spinbutton';
|
|
85
|
-
keyShortcuts?: string | undefined;
|
|
86
89
|
readonly?: boolean;
|
|
90
|
+
keyShortcuts?: string | undefined;
|
|
87
91
|
showInlineLabel?: boolean;
|
|
92
|
+
inputmode?: 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';
|
|
88
93
|
};
|
|
89
94
|
events: {
|
|
90
95
|
input: Event;
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
--sui-background-color-3-hsl: var(--sui-base-hue) 5% 96%;
|
|
97
97
|
--sui-background-color-4-hsl: var(--sui-base-hue) 5% 94%;
|
|
98
98
|
--sui-background-color-5-hsl: var(--sui-base-hue) 5% 74%;
|
|
99
|
-
--sui-border-color-1-hsl: var(--sui-base-hue) 5%
|
|
99
|
+
--sui-border-color-1-hsl: var(--sui-base-hue) 5% 50%;
|
|
100
100
|
--sui-border-color-2-hsl: var(--sui-base-hue) 5% 74%;
|
|
101
101
|
--sui-border-color-3-hsl: var(--sui-base-hue) 5% 70%;
|
|
102
102
|
--sui-shadow-color: var(--sui-base-hue) 10% 0%;
|
|
@@ -129,7 +129,7 @@
|
|
|
129
129
|
--sui-background-color-3-hsl: var(--sui-base-hue) 10% 14%;
|
|
130
130
|
--sui-background-color-4-hsl: var(--sui-base-hue) 10% 16%;
|
|
131
131
|
--sui-background-color-5-hsl: var(--sui-base-hue) 10% 26%;
|
|
132
|
-
--sui-border-color-1-hsl: var(--sui-base-hue) 10%
|
|
132
|
+
--sui-border-color-1-hsl: var(--sui-base-hue) 10% 50%;
|
|
133
133
|
--sui-border-color-2-hsl: var(--sui-base-hue) 10% 26%;
|
|
134
134
|
--sui-border-color-3-hsl: var(--sui-base-hue) 10% 22%;
|
|
135
135
|
--sui-shadow-color: var(--sui-base-hue) 10% 0%;
|
|
@@ -397,7 +397,9 @@
|
|
|
397
397
|
}
|
|
398
398
|
|
|
399
399
|
:global(.disabled),
|
|
400
|
+
:global(.readonly),
|
|
400
401
|
:global([aria-disabled=true]),
|
|
402
|
+
:global([aria-readonly=true]),
|
|
401
403
|
:global([inert]) {
|
|
402
404
|
cursor: default;
|
|
403
405
|
pointer-events: none;
|
|
@@ -406,13 +408,17 @@
|
|
|
406
408
|
filter: grayscale(1) opacity(0.35);
|
|
407
409
|
}
|
|
408
410
|
:global(.disabled) :global(*),
|
|
411
|
+
:global(.readonly) :global(*),
|
|
409
412
|
:global([aria-disabled=true]) :global(*),
|
|
413
|
+
:global([aria-readonly=true]) :global(*),
|
|
410
414
|
:global([inert]) :global(*) {
|
|
411
415
|
filter: grayscale(0) opacity(1);
|
|
412
416
|
}
|
|
413
417
|
|
|
414
418
|
:global(.disabled) :global(*),
|
|
419
|
+
:global(.readonly) :global(*),
|
|
415
420
|
:global([aria-disabled=true]) :global(*),
|
|
421
|
+
:global([aria-readonly=true]) :global(*),
|
|
416
422
|
:global([inert]) :global(*) {
|
|
417
423
|
cursor: default;
|
|
418
424
|
pointer-events: none;
|
|
@@ -38,6 +38,11 @@
|
|
|
38
38
|
*/
|
|
39
39
|
export let position = 'bottom-left';
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Whether to keep the content when the dialog is not displayed.
|
|
43
|
+
*/
|
|
44
|
+
export let keepContent = false;
|
|
45
|
+
|
|
41
46
|
/**
|
|
42
47
|
* Whether to show the popup at the center of the screen on mobile/tablet and ignore the defined
|
|
43
48
|
* dropdown `position`.
|
|
@@ -155,7 +160,7 @@
|
|
|
155
160
|
style:max-height={$style.height}
|
|
156
161
|
style:visibility={$style.inset ? undefined : 'hidden'}
|
|
157
162
|
>
|
|
158
|
-
{#if showContent}
|
|
163
|
+
{#if keepContent || showContent}
|
|
159
164
|
<slot />
|
|
160
165
|
{/if}
|
|
161
166
|
</div>
|
|
@@ -207,8 +212,8 @@
|
|
|
207
212
|
outline-width: 0 !important;
|
|
208
213
|
color: var(--sui-primary-foreground-color);
|
|
209
214
|
background-color: var(--sui-secondary-background-color-translucent);
|
|
210
|
-
-webkit-backdrop-filter: blur(
|
|
211
|
-
backdrop-filter: blur(
|
|
215
|
+
-webkit-backdrop-filter: blur(32px);
|
|
216
|
+
backdrop-filter: blur(32px);
|
|
212
217
|
box-shadow: 0 8px 16px var(--sui-popup-shadow-color);
|
|
213
218
|
will-change: opacity, transform;
|
|
214
219
|
transition-property: opacity, transform;
|
|
@@ -9,6 +9,7 @@ export default class Popup extends SvelteComponent<{
|
|
|
9
9
|
position?: PopupPosition;
|
|
10
10
|
anchor?: HTMLElement;
|
|
11
11
|
content?: HTMLElement;
|
|
12
|
+
keepContent?: boolean;
|
|
12
13
|
touchOptimized?: boolean;
|
|
13
14
|
open?: import("svelte/store").Writable<boolean>;
|
|
14
15
|
}, {
|
|
@@ -32,6 +33,9 @@ export default class Popup extends SvelteComponent<{
|
|
|
32
33
|
set position(arg: PopupPosition);
|
|
33
34
|
get position(): PopupPosition;
|
|
34
35
|
/**accessor*/
|
|
36
|
+
set keepContent(arg: boolean);
|
|
37
|
+
get keepContent(): boolean;
|
|
38
|
+
/**accessor*/
|
|
35
39
|
set touchOptimized(arg: boolean);
|
|
36
40
|
get touchOptimized(): boolean;
|
|
37
41
|
/**accessor*/
|
|
@@ -50,6 +54,7 @@ declare const __propDef: {
|
|
|
50
54
|
position?: PopupPosition;
|
|
51
55
|
anchor?: HTMLElement | undefined;
|
|
52
56
|
content?: HTMLElement | undefined;
|
|
57
|
+
keepContent?: boolean;
|
|
53
58
|
touchOptimized?: boolean;
|
|
54
59
|
open?: import("svelte/store").Writable<boolean>;
|
|
55
60
|
};
|
|
@@ -118,12 +118,28 @@ class Group {
|
|
|
118
118
|
);
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
/** @type {boolean} */
|
|
122
|
+
get isDisabled() {
|
|
123
|
+
return this.parent.matches('[aria-disabled="true"]');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** @type {boolean} */
|
|
127
|
+
get isReadOnly() {
|
|
128
|
+
return this.parent.matches('[aria-readonly="true"]');
|
|
129
|
+
}
|
|
130
|
+
|
|
121
131
|
/**
|
|
122
132
|
* Select (and move focus to) the given target.
|
|
123
133
|
* @param {(MouseEvent | KeyboardEvent)} event Triggered event.
|
|
124
134
|
* @param {HTMLElement} newTarget Target element.
|
|
125
135
|
*/
|
|
126
136
|
selectTarget(event, newTarget) {
|
|
137
|
+
if (this.isDisabled || this.isReadOnly) {
|
|
138
|
+
event.preventDefault();
|
|
139
|
+
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
127
143
|
const targetParentGroup = newTarget.closest(this.parentGroupSelector);
|
|
128
144
|
|
|
129
145
|
this.activeMembers.forEach((element) => {
|
|
@@ -23,8 +23,12 @@ declare class Popup {
|
|
|
23
23
|
popupElement: HTMLDialogElement;
|
|
24
24
|
position: PopupPosition;
|
|
25
25
|
id: string;
|
|
26
|
+
/** @type {boolean} */
|
|
27
|
+
get isDisabled(): boolean;
|
|
28
|
+
/** @type {boolean} */
|
|
29
|
+
get isReadOnly(): boolean;
|
|
26
30
|
/**
|
|
27
|
-
*
|
|
31
|
+
* Check the position of the anchor element.
|
|
28
32
|
*/
|
|
29
33
|
checkPosition(): void;
|
|
30
34
|
}
|
|
@@ -48,26 +48,26 @@ class Popup {
|
|
|
48
48
|
const top = position.startsWith('bottom-')
|
|
49
49
|
? `${Math.round(intersectionRect.bottom)}px`
|
|
50
50
|
: position.endsWith('-top')
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
? `${Math.round(intersectionRect.top)}px`
|
|
52
|
+
: 'auto';
|
|
53
53
|
|
|
54
54
|
const right = position.startsWith('left-')
|
|
55
55
|
? `${Math.round(rootBounds.width - intersectionRect.left)}px`
|
|
56
56
|
: position.endsWith('-right')
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
? `${Math.round(rootBounds.width - intersectionRect.right)}px`
|
|
58
|
+
: 'auto';
|
|
59
59
|
|
|
60
60
|
const bottom = position.startsWith('top-')
|
|
61
61
|
? `${Math.round(rootBounds.height - intersectionRect.top)}px`
|
|
62
62
|
: position.endsWith('-bottom')
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
? `${Math.round(rootBounds.height - intersectionRect.bottom)}px`
|
|
64
|
+
: 'auto';
|
|
65
65
|
|
|
66
66
|
const left = position.startsWith('right-')
|
|
67
67
|
? `${Math.round(intersectionRect.right)}px`
|
|
68
68
|
: position.endsWith('-left')
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
? `${Math.round(intersectionRect.left)}px`
|
|
70
|
+
: 'auto';
|
|
71
71
|
|
|
72
72
|
const anchorPopup = /** @type {HTMLElement} */ (this.anchorElement.closest('.popup'));
|
|
73
73
|
|
|
@@ -100,7 +100,7 @@ class Popup {
|
|
|
100
100
|
this.popupElement.setAttribute('id', this.id);
|
|
101
101
|
|
|
102
102
|
this.anchorElement.addEventListener('click', () => {
|
|
103
|
-
if (!this.
|
|
103
|
+
if (!this.isDisabled && !this.isReadOnly) {
|
|
104
104
|
this.open.set(!get(this.open));
|
|
105
105
|
}
|
|
106
106
|
});
|
|
@@ -109,7 +109,7 @@ class Popup {
|
|
|
109
109
|
const { key, ctrlKey, metaKey, shiftKey, altKey } = event;
|
|
110
110
|
const hasModifier = shiftKey || altKey || ctrlKey || metaKey;
|
|
111
111
|
|
|
112
|
-
if (['Enter', ' '].includes(key) && !hasModifier) {
|
|
112
|
+
if (!this.isDisabled && !this.isReadOnly && ['Enter', ' '].includes(key) && !hasModifier) {
|
|
113
113
|
event.preventDefault();
|
|
114
114
|
event.stopPropagation();
|
|
115
115
|
this.open.set(!get(this.open));
|
|
@@ -154,19 +154,22 @@ class Popup {
|
|
|
154
154
|
});
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
/** @type {boolean} */
|
|
158
|
+
get isDisabled() {
|
|
159
|
+
return this.anchorElement.matches('[aria-disabled="true"]');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** @type {boolean} */
|
|
163
|
+
get isReadOnly() {
|
|
164
|
+
return this.anchorElement.matches('[aria-readonly="true"]');
|
|
165
|
+
}
|
|
166
|
+
|
|
157
167
|
/**
|
|
158
|
-
*
|
|
168
|
+
* Check the position of the anchor element.
|
|
159
169
|
*/
|
|
160
170
|
checkPosition() {
|
|
171
|
+
this.observer.unobserve(this.anchorElement);
|
|
161
172
|
this.observer.observe(this.anchorElement);
|
|
162
|
-
|
|
163
|
-
window.requestAnimationFrame(() => {
|
|
164
|
-
this.observer.unobserve(this.anchorElement);
|
|
165
|
-
|
|
166
|
-
if (get(this.open)) {
|
|
167
|
-
this.checkPosition();
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
173
|
}
|
|
171
174
|
}
|
|
172
175
|
|
package/package/styles/core.scss
CHANGED
|
@@ -101,7 +101,9 @@ dialog {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
.disabled,
|
|
104
|
+
.readonly,
|
|
104
105
|
[aria-disabled="true"],
|
|
106
|
+
[aria-readonly="true"],
|
|
105
107
|
[inert] {
|
|
106
108
|
cursor: default;
|
|
107
109
|
pointer-events: none;
|
|
@@ -115,7 +117,9 @@ dialog {
|
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
.disabled *,
|
|
120
|
+
.readonly *,
|
|
118
121
|
[aria-disabled="true"] *,
|
|
122
|
+
[aria-readonly="true"] *,
|
|
119
123
|
[inert] * {
|
|
120
124
|
cursor: default;
|
|
121
125
|
pointer-events: none;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
--sui-background-color-3-hsl: var(--sui-base-hue) 5% 96%; // secondary
|
|
11
11
|
--sui-background-color-4-hsl: var(--sui-base-hue) 5% 94%; // tertiary/disabled
|
|
12
12
|
--sui-background-color-5-hsl: var(--sui-base-hue) 5% 74%; // highlight
|
|
13
|
-
--sui-border-color-1-hsl: var(--sui-base-hue) 5%
|
|
13
|
+
--sui-border-color-1-hsl: var(--sui-base-hue) 5% 50%; // control
|
|
14
14
|
--sui-border-color-2-hsl: var(--sui-base-hue) 5% 74%; // primary
|
|
15
15
|
--sui-border-color-3-hsl: var(--sui-base-hue) 5% 70%; // secondary
|
|
16
16
|
--sui-shadow-color: var(--sui-base-hue) 10% 0%;
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
--sui-background-color-3-hsl: var(--sui-base-hue) 10% 14%; // secondary
|
|
46
46
|
--sui-background-color-4-hsl: var(--sui-base-hue) 10% 16%; // tertiary/disabled
|
|
47
47
|
--sui-background-color-5-hsl: var(--sui-base-hue) 10% 26%; // highlight
|
|
48
|
-
--sui-border-color-1-hsl: var(--sui-base-hue) 10%
|
|
48
|
+
--sui-border-color-1-hsl: var(--sui-base-hue) 10% 50%; // control
|
|
49
49
|
--sui-border-color-2-hsl: var(--sui-base-hue) 10% 26%; // primary
|
|
50
50
|
--sui-border-color-3-hsl: var(--sui-base-hue) 10% 22%; // secondary
|
|
51
51
|
--sui-shadow-color: var(--sui-base-hue) 10% 0%;
|