@14ch/svelte-ui 0.0.36 → 0.0.38
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/assets/styles/variables.scss +4 -0
- package/dist/components/Checkbox.svelte +39 -13
- package/dist/components/Checkbox.svelte.d.ts +3 -0
- package/dist/components/Combobox.svelte +11 -3
- package/dist/components/Input.svelte +12 -3
- package/dist/components/MultiSelect.svelte +379 -0
- package/dist/components/MultiSelect.svelte.d.ts +30 -0
- package/dist/components/Popup.svelte +2 -1
- package/dist/components/Radio.svelte +45 -18
- package/dist/components/Radio.svelte.d.ts +3 -0
- package/dist/components/Switch.svelte +62 -11
- package/dist/components/Switch.svelte.d.ts +3 -0
- package/dist/components/Textarea.svelte +14 -6
- package/dist/i18n/index.d.ts +24 -0
- package/dist/i18n/locales/de.d.ts +4 -0
- package/dist/i18n/locales/de.js +4 -0
- package/dist/i18n/locales/en.d.ts +4 -0
- package/dist/i18n/locales/en.js +4 -0
- package/dist/i18n/locales/es.d.ts +4 -0
- package/dist/i18n/locales/es.js +4 -0
- package/dist/i18n/locales/fr.d.ts +4 -0
- package/dist/i18n/locales/fr.js +4 -0
- package/dist/i18n/locales/ja.d.ts +4 -0
- package/dist/i18n/locales/ja.js +4 -0
- package/dist/i18n/locales/zh-cn.d.ts +4 -0
- package/dist/i18n/locales/zh-cn.js +4 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
|
@@ -498,6 +498,9 @@
|
|
|
498
498
|
--svelte-ui-switch-thumb-size-lg: calc(
|
|
499
499
|
var(--svelte-ui-switch-height-lg) - var(--svelte-ui-switch-thumb-margin) * 2
|
|
500
500
|
);
|
|
501
|
+
--svelte-ui-switch-min-height: 1.8em;
|
|
502
|
+
--svelte-ui-switch-min-height-sm: 1.6em;
|
|
503
|
+
--svelte-ui-switch-min-height-lg: 2.2em;
|
|
501
504
|
--svelte-ui-switch-gap: 8px;
|
|
502
505
|
--svelte-ui-switch-line-height: 1.2em;
|
|
503
506
|
--svelte-ui-switch-disabled-opacity: var(--svelte-ui-disabled-opacity);
|
|
@@ -629,6 +632,7 @@
|
|
|
629
632
|
--svelte-ui-datepicker-selected-text-color: var(--svelte-ui-text-on-filled-color);
|
|
630
633
|
|
|
631
634
|
/* Popup */
|
|
635
|
+
--svelte-ui-popup-border-radius: var(--svelte-ui-border-radius);
|
|
632
636
|
--svelte-ui-popup-mobile-margin: 16px;
|
|
633
637
|
--svelte-ui-popup-mobile-border-radius: 12px;
|
|
634
638
|
--svelte-ui-popup-focus-color: var(--svelte-ui-primary-color);
|
|
@@ -28,13 +28,17 @@
|
|
|
28
28
|
|
|
29
29
|
// HTML属性系
|
|
30
30
|
id?: string;
|
|
31
|
+
|
|
31
32
|
// スタイル/レイアウト
|
|
32
33
|
/** Checkbox size. @default 'medium' */
|
|
33
34
|
size?: 'small' | 'medium' | 'large';
|
|
35
|
+
customStyle?: string;
|
|
34
36
|
|
|
35
37
|
// 状態/動作
|
|
36
38
|
/** Disables the checkbox. @default false */
|
|
37
39
|
disabled?: boolean;
|
|
40
|
+
/** Stretches the checkbox to fill its container width. @default false */
|
|
41
|
+
fullWidth?: boolean;
|
|
38
42
|
required?: boolean;
|
|
39
43
|
|
|
40
44
|
// ARIA/アクセシビリティ
|
|
@@ -95,9 +99,11 @@
|
|
|
95
99
|
|
|
96
100
|
// スタイル/レイアウト
|
|
97
101
|
size = 'medium',
|
|
102
|
+
customStyle = '',
|
|
98
103
|
|
|
99
104
|
// 状態/動作
|
|
100
105
|
disabled = false,
|
|
106
|
+
fullWidth = false,
|
|
101
107
|
required = false,
|
|
102
108
|
|
|
103
109
|
// ARIA/アクセシビリティ
|
|
@@ -281,6 +287,7 @@
|
|
|
281
287
|
'checkbox',
|
|
282
288
|
`checkbox--${size}`,
|
|
283
289
|
disabled && 'checkbox--disabled',
|
|
290
|
+
fullWidth && 'checkbox--full-width',
|
|
284
291
|
reducedMotion && 'checkbox--no-motion'
|
|
285
292
|
]
|
|
286
293
|
.filter(Boolean)
|
|
@@ -288,7 +295,7 @@
|
|
|
288
295
|
);
|
|
289
296
|
</script>
|
|
290
297
|
|
|
291
|
-
<
|
|
298
|
+
<label class={containerClasses} style={customStyle} data-testid="checkbox">
|
|
292
299
|
<input
|
|
293
300
|
type="checkbox"
|
|
294
301
|
bind:checked={value}
|
|
@@ -326,14 +333,14 @@
|
|
|
326
333
|
onchange={handleChange}
|
|
327
334
|
{...restProps}
|
|
328
335
|
/>
|
|
329
|
-
<
|
|
336
|
+
<span class="checkbox__icon"></span>
|
|
330
337
|
|
|
331
338
|
{#if children}
|
|
332
|
-
<
|
|
339
|
+
<span class="checkbox__label">
|
|
333
340
|
{@render children()}
|
|
334
|
-
</
|
|
341
|
+
</span>
|
|
335
342
|
{/if}
|
|
336
|
-
</
|
|
343
|
+
</label>
|
|
337
344
|
|
|
338
345
|
<style>
|
|
339
346
|
/* =========================================================================
|
|
@@ -342,11 +349,12 @@
|
|
|
342
349
|
|
|
343
350
|
.checkbox {
|
|
344
351
|
display: inline-flex;
|
|
345
|
-
align-items:
|
|
352
|
+
align-items: flex-start;
|
|
346
353
|
width: fit-content;
|
|
347
354
|
min-height: var(--svelte-ui-checkbox-min-height);
|
|
348
355
|
vertical-align: top;
|
|
349
356
|
contain: layout;
|
|
357
|
+
cursor: pointer;
|
|
350
358
|
}
|
|
351
359
|
|
|
352
360
|
.checkbox input[type='checkbox'] {
|
|
@@ -355,20 +363,18 @@
|
|
|
355
363
|
height: 16px;
|
|
356
364
|
margin: 0;
|
|
357
365
|
opacity: 0;
|
|
358
|
-
cursor: pointer;
|
|
359
366
|
}
|
|
360
367
|
|
|
361
368
|
/* Label */
|
|
362
369
|
.checkbox__label {
|
|
363
370
|
display: block;
|
|
364
371
|
padding-left: var(--svelte-ui-checkbox-gap);
|
|
365
|
-
white-space: nowrap;
|
|
366
372
|
font-size: inherit;
|
|
367
373
|
color: inherit;
|
|
368
374
|
line-height: var(--svelte-ui-checkbox-line-height);
|
|
369
|
-
cursor: pointer;
|
|
370
375
|
text-box-trim: trim-both;
|
|
371
376
|
text-box-edge: cap alphabetic;
|
|
377
|
+
margin-block: calc((var(--svelte-ui-checkbox-min-height) - 1cap) / 2);
|
|
372
378
|
}
|
|
373
379
|
|
|
374
380
|
/* Checkbox box */
|
|
@@ -382,7 +388,7 @@
|
|
|
382
388
|
transition-property: background-color, border-color, opacity;
|
|
383
389
|
transition-duration: var(--svelte-ui-transition-duration);
|
|
384
390
|
flex-shrink: 0;
|
|
385
|
-
|
|
391
|
+
margin-block: calc((var(--svelte-ui-checkbox-min-height) - var(--svelte-ui-checkbox-size)) / 2);
|
|
386
392
|
}
|
|
387
393
|
|
|
388
394
|
/* Check mark */
|
|
@@ -420,13 +426,19 @@
|
|
|
420
426
|
========================================================================= */
|
|
421
427
|
|
|
422
428
|
/* Disabled state */
|
|
429
|
+
.checkbox--full-width {
|
|
430
|
+
width: 100%;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.checkbox--full-width .checkbox__label {
|
|
434
|
+
flex: 1;
|
|
435
|
+
}
|
|
436
|
+
|
|
423
437
|
.checkbox--disabled {
|
|
424
438
|
opacity: var(--svelte-ui-button-disabled-opacity);
|
|
425
439
|
}
|
|
426
440
|
|
|
427
|
-
.checkbox--disabled
|
|
428
|
-
.checkbox--disabled .checkbox__icon,
|
|
429
|
-
.checkbox--disabled .checkbox__label {
|
|
441
|
+
.checkbox--disabled {
|
|
430
442
|
cursor: not-allowed;
|
|
431
443
|
}
|
|
432
444
|
|
|
@@ -480,12 +492,19 @@
|
|
|
480
492
|
.checkbox--small .checkbox__icon {
|
|
481
493
|
width: var(--svelte-ui-checkbox-size-sm);
|
|
482
494
|
height: var(--svelte-ui-checkbox-size-sm);
|
|
495
|
+
margin-block: calc(
|
|
496
|
+
(var(--svelte-ui-checkbox-min-height-sm) - var(--svelte-ui-checkbox-size-sm)) / 2
|
|
497
|
+
);
|
|
483
498
|
}
|
|
484
499
|
|
|
485
500
|
.checkbox--small .checkbox__icon::after {
|
|
486
501
|
font-size: var(--svelte-ui-checkbox-icon-size-sm);
|
|
487
502
|
}
|
|
488
503
|
|
|
504
|
+
.checkbox--small .checkbox__label {
|
|
505
|
+
margin-block: calc((var(--svelte-ui-checkbox-min-height-sm) - 1cap) / 2);
|
|
506
|
+
}
|
|
507
|
+
|
|
489
508
|
.checkbox--large {
|
|
490
509
|
font-size: inherit;
|
|
491
510
|
}
|
|
@@ -493,12 +512,19 @@
|
|
|
493
512
|
.checkbox--large .checkbox__icon {
|
|
494
513
|
width: var(--svelte-ui-checkbox-size-lg);
|
|
495
514
|
height: var(--svelte-ui-checkbox-size-lg);
|
|
515
|
+
margin-block: calc(
|
|
516
|
+
(var(--svelte-ui-checkbox-min-height-lg) - var(--svelte-ui-checkbox-size-lg)) / 2
|
|
517
|
+
);
|
|
496
518
|
}
|
|
497
519
|
|
|
498
520
|
.checkbox--large .checkbox__icon::after {
|
|
499
521
|
font-size: var(--svelte-ui-checkbox-icon-size-lg);
|
|
500
522
|
}
|
|
501
523
|
|
|
524
|
+
.checkbox--large .checkbox__label {
|
|
525
|
+
margin-block: calc((var(--svelte-ui-checkbox-min-height-lg) - 1cap) / 2);
|
|
526
|
+
}
|
|
527
|
+
|
|
502
528
|
/* =========================================================================
|
|
503
529
|
* Motion & Media Queries
|
|
504
530
|
* ========================================================================= */
|
|
@@ -12,8 +12,11 @@ export type CheckboxProps = {
|
|
|
12
12
|
id?: string;
|
|
13
13
|
/** Checkbox size. @default 'medium' */
|
|
14
14
|
size?: 'small' | 'medium' | 'large';
|
|
15
|
+
customStyle?: string;
|
|
15
16
|
/** Disables the checkbox. @default false */
|
|
16
17
|
disabled?: boolean;
|
|
18
|
+
/** Stretches the checkbox to fill its container width. @default false */
|
|
19
|
+
fullWidth?: boolean;
|
|
17
20
|
required?: boolean;
|
|
18
21
|
/** Disables animations for users who prefer reduced motion. @default false */
|
|
19
22
|
reducedMotion?: boolean;
|
|
@@ -163,7 +163,7 @@
|
|
|
163
163
|
...restProps
|
|
164
164
|
}: ComboboxProps = $props();
|
|
165
165
|
|
|
166
|
-
let inputValue = $state('');
|
|
166
|
+
let inputValue = $state(value != null ? String(value) : '');
|
|
167
167
|
let inputRef = $state<any>();
|
|
168
168
|
let listElement = $state<HTMLDivElement>();
|
|
169
169
|
let comboboxElement = $state<HTMLDivElement>();
|
|
@@ -173,6 +173,15 @@
|
|
|
173
173
|
let isFocused = $state(false);
|
|
174
174
|
let isKeyboardNavigation = $state(false);
|
|
175
175
|
|
|
176
|
+
// =========================================================================
|
|
177
|
+
// Effects
|
|
178
|
+
// =========================================================================
|
|
179
|
+
$effect(() => {
|
|
180
|
+
if (!isFocused) {
|
|
181
|
+
inputValue = value != null ? String(value) : '';
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
176
185
|
// =========================================================================
|
|
177
186
|
// Methods
|
|
178
187
|
// =========================================================================
|
|
@@ -447,7 +456,7 @@
|
|
|
447
456
|
{readonly}
|
|
448
457
|
{required}
|
|
449
458
|
{clearable}
|
|
450
|
-
rightIcon=
|
|
459
|
+
rightIcon="arrow_drop_down"
|
|
451
460
|
{tabindex}
|
|
452
461
|
{maxlength}
|
|
453
462
|
{rounded}
|
|
@@ -553,7 +562,6 @@
|
|
|
553
562
|
width: max-content;
|
|
554
563
|
max-width: var(--svelte-ui-combobox-max-width);
|
|
555
564
|
background: var(--svelte-ui-combobox-bg);
|
|
556
|
-
border-radius: var(--svelte-ui-combobox-border-radius);
|
|
557
565
|
max-height: var(--svelte-ui-combobox-options-max-height);
|
|
558
566
|
overflow-y: auto;
|
|
559
567
|
margin: 0;
|
|
@@ -919,15 +919,20 @@
|
|
|
919
919
|
color: inherit;
|
|
920
920
|
line-height: inherit;
|
|
921
921
|
text-align: inherit;
|
|
922
|
-
white-space: nowrap;
|
|
923
|
-
overflow: hidden;
|
|
924
|
-
text-overflow: ellipsis;
|
|
925
922
|
opacity: 1;
|
|
926
923
|
transition: none;
|
|
927
924
|
}
|
|
928
925
|
|
|
929
926
|
.input__display-text-content {
|
|
930
927
|
width: 100%;
|
|
928
|
+
overflow: hidden;
|
|
929
|
+
white-space: nowrap;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
.input__link-text-content {
|
|
933
|
+
width: 100%;
|
|
934
|
+
overflow: hidden;
|
|
935
|
+
white-space: nowrap;
|
|
931
936
|
}
|
|
932
937
|
|
|
933
938
|
.input__link-text {
|
|
@@ -1199,6 +1204,10 @@
|
|
|
1199
1204
|
.input__link-text {
|
|
1200
1205
|
padding-right: var(--svelte-ui-input-icon-space-inline);
|
|
1201
1206
|
}
|
|
1207
|
+
|
|
1208
|
+
.input__icon-right {
|
|
1209
|
+
right: 0;
|
|
1210
|
+
}
|
|
1202
1211
|
}
|
|
1203
1212
|
|
|
1204
1213
|
&.input--clearable {
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
<!-- MultiSelect.svelte -->
|
|
2
|
+
|
|
3
|
+
<script lang="ts">
|
|
4
|
+
import Popup from './Popup.svelte';
|
|
5
|
+
import Checkbox from './Checkbox.svelte';
|
|
6
|
+
import Icon from './Icon.svelte';
|
|
7
|
+
import { t } from '../i18n';
|
|
8
|
+
import type { Option, OptionValue } from '../types/options';
|
|
9
|
+
import type { BivariantValueHandler, FocusHandler } from '../types/callbackHandlers';
|
|
10
|
+
import type { PopupPosition } from '../types/propOptions';
|
|
11
|
+
|
|
12
|
+
// =========================================================================
|
|
13
|
+
// Props, States & Constants
|
|
14
|
+
// =========================================================================
|
|
15
|
+
export type MultiSelectProps = {
|
|
16
|
+
// 基本プロパティ
|
|
17
|
+
name?: string;
|
|
18
|
+
/** Selected values array. Supports `bind:values`. */
|
|
19
|
+
values: OptionValue[];
|
|
20
|
+
/** `{ label, value, disabled? }[]` */
|
|
21
|
+
options: Option[];
|
|
22
|
+
|
|
23
|
+
// HTML属性系
|
|
24
|
+
id?: string | null;
|
|
25
|
+
ariaLabel?: string;
|
|
26
|
+
tabindex?: number | null;
|
|
27
|
+
placeholder?: string;
|
|
28
|
+
|
|
29
|
+
// スタイル/レイアウト
|
|
30
|
+
/** Renders inline. @default false */
|
|
31
|
+
inline?: boolean;
|
|
32
|
+
/** @default 'outline' */
|
|
33
|
+
focusStyle?: 'background' | 'outline' | 'none';
|
|
34
|
+
fullWidth?: boolean;
|
|
35
|
+
rounded?: boolean;
|
|
36
|
+
|
|
37
|
+
// 状態/動作
|
|
38
|
+
disabled?: boolean;
|
|
39
|
+
required?: boolean;
|
|
40
|
+
|
|
41
|
+
// ポップアップ
|
|
42
|
+
/** @default 'bottom-left' */
|
|
43
|
+
position?: PopupPosition;
|
|
44
|
+
|
|
45
|
+
// イベントハンドラ
|
|
46
|
+
onfocus?: FocusHandler;
|
|
47
|
+
onblur?: FocusHandler;
|
|
48
|
+
onchange?: BivariantValueHandler<OptionValue[]>;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
let {
|
|
52
|
+
name,
|
|
53
|
+
values = $bindable([]),
|
|
54
|
+
options = [],
|
|
55
|
+
|
|
56
|
+
id = `multi-select-${Math.random().toString(36).substring(2, 15)}`,
|
|
57
|
+
ariaLabel,
|
|
58
|
+
tabindex = null,
|
|
59
|
+
placeholder = '',
|
|
60
|
+
|
|
61
|
+
inline = false,
|
|
62
|
+
focusStyle = 'outline',
|
|
63
|
+
fullWidth = false,
|
|
64
|
+
rounded = false,
|
|
65
|
+
|
|
66
|
+
disabled = false,
|
|
67
|
+
required = false,
|
|
68
|
+
|
|
69
|
+
position = 'bottom-left',
|
|
70
|
+
|
|
71
|
+
onfocus = () => {},
|
|
72
|
+
onblur = () => {},
|
|
73
|
+
onchange = () => {}
|
|
74
|
+
}: MultiSelectProps = $props();
|
|
75
|
+
|
|
76
|
+
let popupRef = $state<any>();
|
|
77
|
+
let triggerEl = $state<HTMLButtonElement>();
|
|
78
|
+
let isPopupOpen = $state(false);
|
|
79
|
+
let triggerWidth = $state(0);
|
|
80
|
+
let isFocused = $state(false);
|
|
81
|
+
|
|
82
|
+
// =========================================================================
|
|
83
|
+
// $derived
|
|
84
|
+
// =========================================================================
|
|
85
|
+
const listboxId = $derived(`${id}-listbox`);
|
|
86
|
+
|
|
87
|
+
const selectedLabels = $derived(
|
|
88
|
+
options.filter((o) => values.includes(o.value)).map((o) => o.label)
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// =========================================================================
|
|
92
|
+
// Methods
|
|
93
|
+
// =========================================================================
|
|
94
|
+
const toggleOption = (optionValue: OptionValue) => {
|
|
95
|
+
if (values.includes(optionValue)) {
|
|
96
|
+
values = values.filter((v) => v !== optionValue);
|
|
97
|
+
} else {
|
|
98
|
+
values = [...values, optionValue];
|
|
99
|
+
}
|
|
100
|
+
onchange(values);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const handleTriggerClick = () => {
|
|
104
|
+
if (disabled) return;
|
|
105
|
+
popupRef?.toggle();
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const handleTriggerKeydown = (event: KeyboardEvent) => {
|
|
109
|
+
if (disabled) return;
|
|
110
|
+
if (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown') {
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
popupRef?.open();
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const handleFocus = (event: FocusEvent) => {
|
|
117
|
+
if (disabled) return;
|
|
118
|
+
isFocused = true;
|
|
119
|
+
onfocus(event);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const handleBlur = (event: FocusEvent) => {
|
|
123
|
+
if (disabled) return;
|
|
124
|
+
isFocused = false;
|
|
125
|
+
onblur(event);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const handlePopupOpen = () => {
|
|
129
|
+
triggerWidth = triggerEl?.offsetWidth ?? 0;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const handlePopupClose = () => {
|
|
133
|
+
triggerEl?.focus();
|
|
134
|
+
};
|
|
135
|
+
</script>
|
|
136
|
+
|
|
137
|
+
<div
|
|
138
|
+
class="multi-select multi-select--focus-{focusStyle}"
|
|
139
|
+
class:multi-select--inline={inline}
|
|
140
|
+
class:multi-select--full-width={fullWidth}
|
|
141
|
+
class:multi-select--disabled={disabled}
|
|
142
|
+
class:multi-select--focused={isFocused}
|
|
143
|
+
class:multi-select--rounded={rounded}
|
|
144
|
+
data-testid="multi-select"
|
|
145
|
+
>
|
|
146
|
+
<button
|
|
147
|
+
bind:this={triggerEl}
|
|
148
|
+
{id}
|
|
149
|
+
type="button"
|
|
150
|
+
class="multi-select__trigger"
|
|
151
|
+
role="combobox"
|
|
152
|
+
aria-expanded={isPopupOpen}
|
|
153
|
+
aria-haspopup="listbox"
|
|
154
|
+
aria-controls={isPopupOpen ? listboxId : undefined}
|
|
155
|
+
aria-label={ariaLabel ?? t('multiSelect.accessibleName')}
|
|
156
|
+
aria-required={required ? 'true' : undefined}
|
|
157
|
+
{tabindex}
|
|
158
|
+
{disabled}
|
|
159
|
+
onfocus={handleFocus}
|
|
160
|
+
onblur={handleBlur}
|
|
161
|
+
onclick={handleTriggerClick}
|
|
162
|
+
onkeydown={handleTriggerKeydown}
|
|
163
|
+
>
|
|
164
|
+
{#if selectedLabels.length > 0}
|
|
165
|
+
<span class="multi-select__display-text">
|
|
166
|
+
{#each selectedLabels as label, i}
|
|
167
|
+
<span>{label}{#if i < selectedLabels.length - 1},{/if}</span>
|
|
168
|
+
{/each}
|
|
169
|
+
</span>
|
|
170
|
+
{:else if placeholder}
|
|
171
|
+
<span class="multi-select__placeholder">{placeholder}</span>
|
|
172
|
+
{/if}
|
|
173
|
+
</button>
|
|
174
|
+
<div class="multi-select__dropdown-icon" aria-hidden="true">
|
|
175
|
+
<Icon>arrow_drop_down</Icon>
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
<Popup
|
|
179
|
+
bind:this={popupRef}
|
|
180
|
+
bind:isOpen={isPopupOpen}
|
|
181
|
+
anchorElement={triggerEl}
|
|
182
|
+
{position}
|
|
183
|
+
mobileFullscreen={true}
|
|
184
|
+
onOpen={handlePopupOpen}
|
|
185
|
+
onClose={handlePopupClose}
|
|
186
|
+
margin={4}
|
|
187
|
+
>
|
|
188
|
+
<ul
|
|
189
|
+
id={listboxId}
|
|
190
|
+
class="multi-select__options"
|
|
191
|
+
role="listbox"
|
|
192
|
+
aria-multiselectable="true"
|
|
193
|
+
aria-label={ariaLabel ?? t('multiSelect.accessibleName')}
|
|
194
|
+
style:min-width="{triggerWidth}px"
|
|
195
|
+
>
|
|
196
|
+
{#each options as option, i (option.value)}
|
|
197
|
+
<li role="presentation" class="multi-select__item">
|
|
198
|
+
<Checkbox
|
|
199
|
+
value={values.includes(option.value)}
|
|
200
|
+
disabled={option.disabled}
|
|
201
|
+
fullWidth
|
|
202
|
+
customStyle="padding: 8px 12px"
|
|
203
|
+
onchange={() => toggleOption(option.value)}
|
|
204
|
+
>
|
|
205
|
+
{option.label}
|
|
206
|
+
</Checkbox>
|
|
207
|
+
</li>
|
|
208
|
+
{/each}
|
|
209
|
+
</ul>
|
|
210
|
+
</Popup>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<style>@charset "UTF-8";
|
|
214
|
+
/* =============================================
|
|
215
|
+
* 基本構造・レイアウト
|
|
216
|
+
* ============================================= */
|
|
217
|
+
.multi-select {
|
|
218
|
+
display: inline-block;
|
|
219
|
+
position: relative;
|
|
220
|
+
width: auto;
|
|
221
|
+
max-width: 100%;
|
|
222
|
+
vertical-align: top;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/* =============================================
|
|
226
|
+
* トリガーボタン
|
|
227
|
+
* ============================================= */
|
|
228
|
+
.multi-select__trigger {
|
|
229
|
+
width: 100%;
|
|
230
|
+
min-height: var(--svelte-ui-select-height);
|
|
231
|
+
padding: var(--svelte-ui-select-padding);
|
|
232
|
+
padding-right: var(--svelte-ui-select-icon-space);
|
|
233
|
+
background: transparent;
|
|
234
|
+
border: none;
|
|
235
|
+
font-family: inherit;
|
|
236
|
+
font-size: inherit;
|
|
237
|
+
font-weight: inherit;
|
|
238
|
+
color: inherit;
|
|
239
|
+
line-height: inherit;
|
|
240
|
+
text-align: left;
|
|
241
|
+
cursor: pointer;
|
|
242
|
+
display: flex;
|
|
243
|
+
align-items: center;
|
|
244
|
+
}
|
|
245
|
+
.multi-select__trigger:focus, .multi-select__trigger:focus-visible {
|
|
246
|
+
outline: var(--svelte-ui-focus-outline-inner);
|
|
247
|
+
outline-offset: var(--svelte-ui-focus-outline-offset-inner);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.multi-select__display-text {
|
|
251
|
+
display: flex;
|
|
252
|
+
flex-wrap: wrap;
|
|
253
|
+
align-items: baseline;
|
|
254
|
+
gap: 0 0.5em;
|
|
255
|
+
flex: 1;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.multi-select__placeholder {
|
|
259
|
+
color: var(--svelte-ui-select-placeholder-color);
|
|
260
|
+
display: block;
|
|
261
|
+
overflow: hidden;
|
|
262
|
+
text-overflow: ellipsis;
|
|
263
|
+
white-space: nowrap;
|
|
264
|
+
flex: 1;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.multi-select__dropdown-icon {
|
|
268
|
+
display: flex;
|
|
269
|
+
justify-content: center;
|
|
270
|
+
align-items: center;
|
|
271
|
+
position: absolute;
|
|
272
|
+
top: 50%;
|
|
273
|
+
right: 4px;
|
|
274
|
+
width: 32px;
|
|
275
|
+
height: 32px;
|
|
276
|
+
transform: translateY(-50%);
|
|
277
|
+
font-size: var(--svelte-ui-select-dropdown-icon-size);
|
|
278
|
+
color: var(--svelte-ui-select-dropdown-icon-color);
|
|
279
|
+
pointer-events: none;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* =============================================
|
|
283
|
+
* レイアウトバリエーション
|
|
284
|
+
* ============================================= */
|
|
285
|
+
.multi-select--full-width {
|
|
286
|
+
width: 100%;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* =============================================
|
|
290
|
+
* フォーカス効果バリエーション
|
|
291
|
+
* ============================================= */
|
|
292
|
+
.multi-select--focus-outline .multi-select__trigger:focus {
|
|
293
|
+
outline: var(--svelte-ui-focus-outline-inner);
|
|
294
|
+
outline-offset: var(--svelte-ui-focus-outline-offset-inner);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.multi-select--focus-background .multi-select__trigger:focus {
|
|
298
|
+
background: var(--svelte-ui-hover-overlay);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/* =============================================
|
|
302
|
+
* 状態管理
|
|
303
|
+
* ============================================= */
|
|
304
|
+
.multi-select--disabled {
|
|
305
|
+
opacity: var(--svelte-ui-input-disabled-opacity);
|
|
306
|
+
cursor: not-allowed;
|
|
307
|
+
}
|
|
308
|
+
.multi-select--disabled .multi-select__trigger {
|
|
309
|
+
cursor: not-allowed;
|
|
310
|
+
pointer-events: none;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/* =============================================
|
|
314
|
+
* デザインバリアント:default
|
|
315
|
+
* ============================================= */
|
|
316
|
+
.multi-select:not(.multi-select--inline) .multi-select__trigger {
|
|
317
|
+
min-height: var(--svelte-ui-select-height);
|
|
318
|
+
background-color: var(--svelte-ui-select-bg);
|
|
319
|
+
box-shadow: 0 0 0 var(--svelte-ui-border-width) inset var(--svelte-ui-select-border-color);
|
|
320
|
+
border: none;
|
|
321
|
+
border-radius: var(--svelte-ui-select-border-radius);
|
|
322
|
+
font-size: 1rem;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* =============================================
|
|
326
|
+
* デザインバリアント:inline
|
|
327
|
+
* ============================================= */
|
|
328
|
+
.multi-select.multi-select--inline .multi-select__trigger {
|
|
329
|
+
padding: inherit;
|
|
330
|
+
padding-right: var(--svelte-ui-input-icon-space-inline);
|
|
331
|
+
background: transparent;
|
|
332
|
+
border: none;
|
|
333
|
+
border-radius: 0;
|
|
334
|
+
color: inherit;
|
|
335
|
+
min-height: auto;
|
|
336
|
+
line-height: inherit;
|
|
337
|
+
}
|
|
338
|
+
.multi-select.multi-select--inline .multi-select__dropdown-icon {
|
|
339
|
+
right: 0;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/* =============================================
|
|
343
|
+
* デザインバリアント:rounded
|
|
344
|
+
* ============================================= */
|
|
345
|
+
.multi-select--rounded:not(.multi-select--inline) .multi-select__trigger {
|
|
346
|
+
border-radius: var(--svelte-ui-select-border-radius-rounded);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/* =============================================
|
|
350
|
+
* オプションリスト(ポップアップ内)
|
|
351
|
+
* ============================================= */
|
|
352
|
+
.multi-select__options {
|
|
353
|
+
list-style: none;
|
|
354
|
+
margin: 0;
|
|
355
|
+
padding: 0;
|
|
356
|
+
min-width: 160px;
|
|
357
|
+
max-height: var(--svelte-ui-combobox-options-max-height);
|
|
358
|
+
overflow-y: auto;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.multi-select__item {
|
|
362
|
+
position: relative;
|
|
363
|
+
padding: 0;
|
|
364
|
+
margin: 0;
|
|
365
|
+
}
|
|
366
|
+
@media (hover: hover) {
|
|
367
|
+
.multi-select__item:hover :global(.checkbox:not(.checkbox--disabled)) {
|
|
368
|
+
background-color: var(--svelte-ui-hover-overlay);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.multi-select__option-cover {
|
|
373
|
+
position: absolute;
|
|
374
|
+
inset: 0;
|
|
375
|
+
cursor: pointer;
|
|
376
|
+
}
|
|
377
|
+
.multi-select__option-cover--disabled {
|
|
378
|
+
cursor: not-allowed;
|
|
379
|
+
}</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Option, OptionValue } from '../types/options';
|
|
2
|
+
import type { BivariantValueHandler, FocusHandler } from '../types/callbackHandlers';
|
|
3
|
+
import type { PopupPosition } from '../types/propOptions';
|
|
4
|
+
export type MultiSelectProps = {
|
|
5
|
+
name?: string;
|
|
6
|
+
/** Selected values array. Supports `bind:values`. */
|
|
7
|
+
values: OptionValue[];
|
|
8
|
+
/** `{ label, value, disabled? }[]` */
|
|
9
|
+
options: Option[];
|
|
10
|
+
id?: string | null;
|
|
11
|
+
ariaLabel?: string;
|
|
12
|
+
tabindex?: number | null;
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
/** Renders inline. @default false */
|
|
15
|
+
inline?: boolean;
|
|
16
|
+
/** @default 'outline' */
|
|
17
|
+
focusStyle?: 'background' | 'outline' | 'none';
|
|
18
|
+
fullWidth?: boolean;
|
|
19
|
+
rounded?: boolean;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
required?: boolean;
|
|
22
|
+
/** @default 'bottom-left' */
|
|
23
|
+
position?: PopupPosition;
|
|
24
|
+
onfocus?: FocusHandler;
|
|
25
|
+
onblur?: FocusHandler;
|
|
26
|
+
onchange?: BivariantValueHandler<OptionValue[]>;
|
|
27
|
+
};
|
|
28
|
+
declare const MultiSelect: import("svelte").Component<MultiSelectProps, {}, "values">;
|
|
29
|
+
type MultiSelect = ReturnType<typeof MultiSelect>;
|
|
30
|
+
export default MultiSelect;
|
|
@@ -553,9 +553,10 @@
|
|
|
553
553
|
<style>@charset "UTF-8";
|
|
554
554
|
:popover-open {
|
|
555
555
|
border: solid 1px var(--svelte-ui-border-weak-color);
|
|
556
|
-
border-radius:
|
|
556
|
+
border-radius: var(--svelte-ui-popup-border-radius);
|
|
557
557
|
box-shadow: 0 11px 15px -7px rgba(0, 0, 0, 0.2), 0 24px 38px 3px rgba(0, 0, 0, 0.14), 0 9px 46px 8px rgba(0, 0, 0, 0.12);
|
|
558
558
|
background: var(--svelte-ui-surface-color);
|
|
559
|
+
color: var(--svelte-ui-text-color);
|
|
559
560
|
z-index: 1000; /* Popupを最前面に表示 */
|
|
560
561
|
}
|
|
561
562
|
|