@14ch/svelte-ui 0.0.6 → 0.0.8

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.
@@ -341,6 +341,25 @@
341
341
  --svelte-ui-iconbutton-hover-overlay: var(--svelte-ui-hover-overlay);
342
342
  --svelte-ui-iconbutton-focus-color: var(--svelte-ui-focus-color);
343
343
 
344
+ /* SegmentedControl */
345
+ --svelte-ui-segmented-control-base-padding: 4px;
346
+ --svelte-ui-segmented-control-base-border-radius: var(--svelte-ui-border-radius);
347
+ --svelte-ui-segmented-control-gap: 4px;
348
+ --svelte-ui-segmented-control-button-radius: calc(var(--svelte-ui-border-radius) - 1px);
349
+ --svelte-ui-segmented-control-button-height-sm: 24px;
350
+ --svelte-ui-segmented-control-button-height: 32px;
351
+ --svelte-ui-segmented-control-button-height-lg: 40px;
352
+ --svelte-ui-segmented-control-font-size-sm: 12px;
353
+ --svelte-ui-segmented-control-font-size: 14px;
354
+ --svelte-ui-segmented-control-font-size-lg: 16px;
355
+ --svelte-ui-segmented-control-button-padding-sm: 4px 8px;
356
+ --svelte-ui-segmented-control-button-padding: 6px 12px;
357
+ --svelte-ui-segmented-control-button-padding-lg: 8px 16px;
358
+ --svelte-ui-segmented-control-base-bg: var(--svelte-ui-surface-accent-color);
359
+ --svelte-ui-segmented-control-selected-bg: var(--svelte-ui-primary-color);
360
+ --svelte-ui-segmented-control-selected-text-color: var(--svelte-ui-text-on-filled-color);
361
+ --svelte-ui-segmented-control-hover-overlay: var(--svelte-ui-hover-overlay);
362
+
344
363
  /* Input */
345
364
  --svelte-ui-input-height: var(--svelte-ui-form-height);
346
365
  --svelte-ui-input-padding: var(--svelte-ui-form-padding);
@@ -490,7 +509,7 @@
490
509
  /* ColorPicker */
491
510
  --svelte-ui-colorpicker-trigger-size: 28px;
492
511
  --svelte-ui-colorpicker-text-padding-left: 40px;
493
- --svelte-ui-colorpicker-trigger-border-radius: calc(var(--svelte-ui-border-radius) - 2px);
512
+ --svelte-ui-colorpicker-trigger-border-radius: calc(var(--svelte-ui-border-radius) - 1px);
494
513
  --svelte-ui-colorpicker-trigger-border-style: dashed;
495
514
  --svelte-ui-colorpicker-trigger-border-width: 1px;
496
515
  --svelte-ui-colorpicker-trigger-offset: 4px;
@@ -494,7 +494,7 @@
494
494
  }
495
495
 
496
496
  .button__icon {
497
- margin-left: -4px;
497
+ margin: -12px 0 -12px -4px;
498
498
  display: flex;
499
499
  align-items: center;
500
500
  justify-content: center;
@@ -167,11 +167,6 @@
167
167
  // Methods
168
168
  // =========================================================================
169
169
 
170
- const handleSubmit = (event: SubmitEvent) => {
171
- event?.preventDefault?.();
172
- handleChange();
173
- };
174
-
175
170
  const handleChange = (event?: Event): void => {
176
171
  // 空文字列の場合はそのまま処理
177
172
  if (localValue && !localValue.startsWith('#')) {
@@ -207,6 +202,11 @@
207
202
  onclick?.(event);
208
203
  };
209
204
  const handleKeydown = (event: KeyboardEvent) => {
205
+ // Enterキーで色の変更を確定
206
+ if (event.key === 'Enter' && !disabled && !readonly) {
207
+ event.preventDefault();
208
+ handleChange();
209
+ }
210
210
  if (disabled) return;
211
211
  onkeydown(event);
212
212
  };
@@ -361,7 +361,6 @@
361
361
  onpointerleave={handlePointerLeave}
362
362
  onpointermove={handlePointerMove}
363
363
  onpointercancel={handlePointerCancel}
364
- onsubmit={handleSubmit}
365
364
  {...restProps}
366
365
  />
367
366
 
@@ -155,7 +155,6 @@
155
155
  let popupRef = $state<any>();
156
156
  let highlightedIndex = $state(-1);
157
157
  let isFocused = $state(false);
158
- let comboboxRef = $state<HTMLDivElement>();
159
158
 
160
159
  // 各要素のIDを生成
161
160
  const inputId = `${id}-input`;
@@ -479,9 +478,9 @@
479
478
  type="button"
480
479
  class="combobox__option"
481
480
  class:combobox__option--highlighted={index === highlightedIndex}
482
- class:combobox__option--selected={option === value}
481
+ class:combobox__option--selected={option === inputValue}
483
482
  role="option"
484
- aria-selected={option === value}
483
+ aria-selected={option === inputValue}
485
484
  onmousedown={(event) => {
486
485
  event?.preventDefault?.();
487
486
  event?.stopPropagation?.();
@@ -115,7 +115,7 @@
115
115
  return styles.join('; ');
116
116
  });
117
117
 
118
- const dialogClasses = $derived([scrollable && 'scrollable'].filter(Boolean).join(' ')); // dialogクラス自体はcustomClassに含めない
118
+ const dialogClasses = $derived('');
119
119
 
120
120
  const ariaLabelledby = $derived(title ? 'dialog-title' : undefined);
121
121
  const ariaDescribedbyValue = $derived(
@@ -136,7 +136,7 @@
136
136
  customStyles={dialogStyles}
137
137
  id={id ? `${id}-modal` : undefined}
138
138
  >
139
- <div class="dialog {scrollable ? 'scrollable' : ''}">
139
+ <div class="dialog {scrollable ? 'dialog--scrollable' : ''}">
140
140
  {#if header || title}
141
141
  <div class="dialog__header">
142
142
  {#if header}
@@ -166,14 +166,15 @@
166
166
  </div>
167
167
  </Modal>
168
168
 
169
- <style>.dialog {
169
+ <style>@charset "UTF-8";
170
+ .dialog {
170
171
  display: flex;
171
172
  flex-direction: column;
172
173
  justify-content: stretch;
173
- max-height: calc(100dvh - 2em - 6px);
174
174
  border: var(--svelte-ui-dialog-border);
175
175
  border-radius: var(--svelte-ui-dialog-border-radius);
176
- overflow: hidden;
176
+ max-height: calc(100dvh - 2em - 6px);
177
+ overflow: auto;
177
178
  }
178
179
 
179
180
  .dialog__header {
@@ -183,7 +184,6 @@
183
184
  justify-content: stretch;
184
185
  min-height: var(--svelte-ui-dialog-header-height);
185
186
  padding: var(--svelte-ui-dialog-padding);
186
- margin-bottom: calc(0px - var(--svelte-ui-dialog-body-padding));
187
187
  }
188
188
  .dialog__header .dialog__title {
189
189
  flex-grow: 1;
@@ -214,15 +214,26 @@
214
214
  border-bottom: 1px solid var(--svelte-ui-border-weak-color);
215
215
  }
216
216
 
217
- :global(.scrollable) .dialog__header {
217
+ /* scrollable=true 時: ヘッダー/フッター固定 + bodyのみスクロール */
218
+ .dialog--scrollable {
219
+ overflow: hidden;
220
+ }
221
+
222
+ .dialog--scrollable .dialog__header {
218
223
  margin-bottom: 0;
219
224
  border-bottom: solid var(--svelte-ui-border-width, 1px) var(--svelte-ui-border-weak-color);
220
225
  }
221
- :global(.scrollable) .dialog__body {
226
+
227
+ .dialog--scrollable .dialog__body {
222
228
  flex-shrink: 1;
223
229
  padding: var(--svelte-ui-dialog-body-padding);
224
230
  overflow: auto;
225
231
  }
226
- :global(.scrollable) .dialog__footer {
232
+
233
+ .dialog:not(.dialog--scrollable) .dialog__body {
234
+ padding-top: 0;
235
+ }
236
+
237
+ .dialog--scrollable .dialog__footer {
227
238
  border-top: solid var(--svelte-ui-border-width, 1px) var(--svelte-ui-border-weak-color);
228
239
  }</style>
@@ -123,9 +123,7 @@
123
123
  });
124
124
 
125
125
  const drawerClasses = $derived(
126
- ['drawer-wrapper', `drawer-wrapper--${position}`, scrollable && 'drawer-wrapper--scrollable']
127
- .filter(Boolean)
128
- .join(' ')
126
+ ['drawer-wrapper', `drawer-wrapper--${position}`].filter(Boolean).join(' ')
129
127
  );
130
128
 
131
129
  const ariaLabelledby = $derived(title ? 'drawer-title' : undefined);
@@ -95,11 +95,6 @@
95
95
  // 入力イベント
96
96
  onchange = () => {}, // No params for type inference
97
97
  oninput = () => {}, // No params for type inference
98
- onsubmit = () => {}, // No params for type inference
99
-
100
- // IMEイベント
101
- oncompositionstart = () => {}, // No params for type inference
102
- oncompositionend = () => {}, // No params for type inference
103
98
 
104
99
  // アイコンイベント
105
100
  onRightIconClick,
@@ -190,11 +185,6 @@
190
185
  // 入力イベント
191
186
  onchange?: (value: any) => void;
192
187
  oninput?: (value: any) => void;
193
- onsubmit?: (value: any) => void;
194
-
195
- // IMEイベント
196
- oncompositionstart?: Function; // No params for type inference
197
- oncompositionend?: Function; // No params for type inference
198
188
 
199
189
  // アイコンイベント
200
190
  onRightIconClick?: Function; // No params for type inference
@@ -206,6 +196,7 @@
206
196
 
207
197
  let ref: HTMLInputElement | undefined = $state();
208
198
  let isFocused: boolean = $state(false);
199
+ let isComposing: boolean = $state(false);
209
200
 
210
201
  // =========================================================================
211
202
  // Methods
@@ -243,6 +234,10 @@
243
234
 
244
235
  // キーボードイベント
245
236
  const handleKeydown = (event: KeyboardEvent) => {
237
+ // Enterキーで入力確定(blur)する(IME変換中は除く)
238
+ if (event.key === 'Enter' && !disabled && !readonly && !isComposing) {
239
+ ref?.blur();
240
+ }
246
241
  onkeydown?.(event);
247
242
  };
248
243
 
@@ -251,12 +246,6 @@
251
246
  };
252
247
 
253
248
  // 入力イベント
254
- const handleSubmit = (event: SubmitEvent) => {
255
- if (disabled || readonly) return;
256
- event?.preventDefault?.();
257
- ref?.blur();
258
- onsubmit?.(value);
259
- };
260
249
 
261
250
  const handleChange = () => {
262
251
  if (disabled || readonly) return;
@@ -366,6 +355,15 @@
366
355
  onpointercancel?.(event);
367
356
  };
368
357
 
358
+ // IMEイベント
359
+ const handleCompositionStart = () => {
360
+ isComposing = true;
361
+ };
362
+
363
+ const handleCompositionEnd = () => {
364
+ isComposing = false;
365
+ };
366
+
369
367
  // =========================================================================
370
368
  // $derived
371
369
  // =========================================================================
@@ -405,8 +403,8 @@
405
403
  {getDisplayValue()}
406
404
  </div>
407
405
  {/if}
408
- <!-- 入力用フォーム -->
409
- <form onsubmit={handleSubmit}>
406
+ <!-- 入力用要素 -->
407
+ <div class="input__wrapper">
410
408
  <input
411
409
  {id}
412
410
  {name}
@@ -452,10 +450,12 @@
452
450
  onpointerleave={handlePointerLeave}
453
451
  onpointermove={handlePointerMove}
454
452
  onpointercancel={handlePointerCancel}
453
+ oncompositionstart={handleCompositionStart}
454
+ oncompositionend={handleCompositionEnd}
455
455
  {...inputAttributes}
456
456
  {...restProps}
457
457
  />
458
- </form>
458
+ </div>
459
459
  <!-- クリアボタン -->
460
460
  {#if clearable && !disabled && !readonly}
461
461
  <div class="input__clear-button">
@@ -546,7 +546,7 @@
546
546
  height: inherit;
547
547
  }
548
548
 
549
- form {
549
+ .input__wrapper {
550
550
  padding: inherit;
551
551
  border: none;
552
552
  font-size: inherit;
@@ -688,7 +688,7 @@
688
688
  * デザインバリアント:default
689
689
  * ============================================= */
690
690
  .input:not(.input--inline) {
691
- form {
691
+ .input__wrapper {
692
692
  position: static;
693
693
  opacity: 1;
694
694
  }
@@ -749,7 +749,7 @@
749
749
  text-align: right;
750
750
  }
751
751
 
752
- form {
752
+ .input__wrapper {
753
753
  position: absolute;
754
754
  top: 0;
755
755
  left: 0;
@@ -790,7 +790,7 @@
790
790
  opacity: 0;
791
791
  }
792
792
 
793
- form {
793
+ .input__wrapper {
794
794
  opacity: 1;
795
795
  }
796
796
  }
@@ -62,9 +62,6 @@ type $$ComponentProps = {
62
62
  onpointercancel?: Function;
63
63
  onchange?: (value: any) => void;
64
64
  oninput?: (value: any) => void;
65
- onsubmit?: (value: any) => void;
66
- oncompositionstart?: Function;
67
- oncompositionend?: Function;
68
65
  onRightIconClick?: Function;
69
66
  onLeftIconClick?: Function;
70
67
  [key: string]: any;
@@ -0,0 +1,626 @@
1
+ <!-- SegmentedControl.svelte -->
2
+
3
+ <script lang="ts">
4
+ import Icon from './Icon.svelte';
5
+ import type { IconVariant, IconWeight, IconGrade, IconOpticalSize } from '../types/icon';
6
+ import type { SegmentedControlItem } from '../types/segmentedControlItem';
7
+
8
+ // =========================================================================
9
+ // Props, States & Constants
10
+ // =========================================================================
11
+ let {
12
+ // 基本プロパティ
13
+ items = [],
14
+ value = $bindable(''),
15
+
16
+ // HTML属性系
17
+ id,
18
+ name = `segmented-control-${Math.random().toString(36).substring(2, 15)}`,
19
+
20
+ // スタイル/レイアウト
21
+ size = 'medium',
22
+ fullWidth = false,
23
+ color,
24
+ rounded = false,
25
+
26
+ // アイコン関連
27
+ iconFilled = false,
28
+ iconWeight = 300,
29
+ iconGrade = 0,
30
+ iconOpticalSize,
31
+ iconVariant = 'outlined',
32
+
33
+ // 状態/動作
34
+ disabled = false,
35
+
36
+ // ARIA/アクセシビリティ
37
+ ariaLabel,
38
+ ariaLabelledby,
39
+ reducedMotion = false,
40
+
41
+ // 入力イベント
42
+ onchange = () => {}, // No params for type inference
43
+
44
+ // フォーカスイベント
45
+ onfocus = () => {}, // No params for type inference
46
+ onblur = () => {}, // No params for type inference
47
+
48
+ // キーボードイベント
49
+ onkeydown = () => {}, // No params for type inference
50
+ onkeyup = () => {}, // No params for type inference
51
+
52
+ // マウスイベント
53
+ onclick = () => {}, // No params for type inference
54
+ onmousedown = () => {}, // No params for type inference
55
+ onmouseup = () => {}, // No params for type inference
56
+ onmouseenter = () => {}, // No params for type inference
57
+ onmouseleave = () => {}, // No params for type inference
58
+ onmouseover = () => {}, // No params for type inference
59
+ onmouseout = () => {}, // No params for type inference
60
+ oncontextmenu = () => {}, // No params for type inference
61
+ onauxclick = () => {}, // No params for type inference
62
+
63
+ // タッチイベント
64
+ ontouchstart = () => {}, // No params for type inference
65
+ ontouchend = () => {}, // No params for type inference
66
+ ontouchmove = () => {}, // No params for type inference
67
+ ontouchcancel = () => {}, // No params for type inference
68
+
69
+ // ポインターイベント
70
+ onpointerdown = () => {}, // No params for type inference
71
+ onpointerup = () => {}, // No params for type inference
72
+ onpointerenter = () => {}, // No params for type inference
73
+ onpointerleave = () => {}, // No params for type inference
74
+ onpointermove = () => {}, // No params for type inference
75
+ onpointercancel = () => {}, // No params for type inference
76
+
77
+ // その他
78
+ ...restProps
79
+ }: {
80
+ // 基本プロパティ
81
+ items: SegmentedControlItem[];
82
+ value: string;
83
+
84
+ // HTML属性系
85
+ id?: string;
86
+ name?: string;
87
+
88
+ // スタイル/レイアウト
89
+ size?: 'small' | 'medium' | 'large';
90
+ fullWidth?: boolean;
91
+ color?: string;
92
+ rounded?: boolean;
93
+
94
+ // アイコン関連
95
+ iconFilled?: boolean;
96
+ iconWeight?: IconWeight;
97
+ iconGrade?: IconGrade;
98
+ iconOpticalSize?: IconOpticalSize;
99
+ iconVariant?: IconVariant;
100
+
101
+ // 状態/動作
102
+ disabled?: boolean;
103
+
104
+ // ARIA/アクセシビリティ
105
+ ariaLabel?: string;
106
+ ariaLabelledby?: string;
107
+ reducedMotion?: boolean;
108
+
109
+ // 入力イベント
110
+ onchange?: (value: string) => void;
111
+
112
+ // フォーカスイベント
113
+ onfocus?: Function; // No params for type inference
114
+ onblur?: Function; // No params for type inference
115
+
116
+ // キーボードイベント
117
+ onkeydown?: Function; // No params for type inference
118
+ onkeyup?: Function; // No params for type inference
119
+
120
+ // マウスイベント
121
+ onclick?: Function; // No params for type inference
122
+ onmousedown?: Function; // No params for type inference
123
+ onmouseup?: Function; // No params for type inference
124
+ onmouseenter?: Function; // No params for type inference
125
+ onmouseleave?: Function; // No params for type inference
126
+ onmouseover?: Function; // No params for type inference
127
+ onmouseout?: Function; // No params for type inference
128
+ oncontextmenu?: Function; // No params for type inference
129
+ onauxclick?: Function; // No params for type inference
130
+
131
+ // タッチイベント
132
+ ontouchstart?: Function; // No params for type inference
133
+ ontouchend?: Function; // No params for type inference
134
+ ontouchmove?: Function; // No params for type inference
135
+ ontouchcancel?: Function; // No params for type inference
136
+
137
+ // ポインターイベント
138
+ onpointerdown?: Function; // No params for type inference
139
+ onpointerup?: Function; // No params for type inference
140
+ onpointerenter?: Function; // No params for type inference
141
+ onpointerleave?: Function; // No params for type inference
142
+ onpointermove?: Function; // No params for type inference
143
+ onpointercancel?: Function; // No params for type inference
144
+
145
+ // その他
146
+ [key: string]: any;
147
+ } = $props();
148
+
149
+ // =========================================================================
150
+ // Methods
151
+ // =========================================================================
152
+ const handleChange = (item: SegmentedControlItem, event: Event) => {
153
+ if (disabled || item.disabled) return;
154
+
155
+ const target = event.target as HTMLInputElement;
156
+ if (target.checked) {
157
+ value = item.value;
158
+ onchange(item.value);
159
+ }
160
+ };
161
+
162
+ const handleFocus = (event: FocusEvent) => {
163
+ onfocus(event);
164
+ };
165
+
166
+ const handleBlur = (event: FocusEvent) => {
167
+ onblur(event);
168
+ };
169
+
170
+ const handleKeydown = (event: KeyboardEvent) => {
171
+ if (disabled || items.length === 0) {
172
+ onkeydown(event);
173
+ return;
174
+ }
175
+
176
+ // Radioコンポーネントと同じキーボードナビゲーション
177
+ if (
178
+ event.key === 'ArrowUp' ||
179
+ event.key === 'ArrowDown' ||
180
+ event.key === 'ArrowLeft' ||
181
+ event.key === 'ArrowRight'
182
+ ) {
183
+ const radioInputs = document.querySelectorAll(
184
+ `input[type="radio"][name="${name}"]`
185
+ ) as NodeListOf<HTMLInputElement>;
186
+ const currentIndex = Array.from(radioInputs).findIndex((input) => input === event.target);
187
+
188
+ if (currentIndex !== -1) {
189
+ event.preventDefault();
190
+ let nextIndex;
191
+
192
+ if (event.key === 'ArrowUp' || event.key === 'ArrowLeft') {
193
+ // 前の有効なアイテムを探す
194
+ for (let i = currentIndex - 1; i >= 0; i--) {
195
+ if (!items[i]?.disabled && !radioInputs[i].disabled) {
196
+ nextIndex = i;
197
+ break;
198
+ }
199
+ }
200
+ // 見つからなければ最後の有効なアイテムへ
201
+ if (nextIndex === undefined) {
202
+ for (let i = items.length - 1; i > currentIndex; i--) {
203
+ if (!items[i]?.disabled && !radioInputs[i].disabled) {
204
+ nextIndex = i;
205
+ break;
206
+ }
207
+ }
208
+ }
209
+ } else {
210
+ // 次の有効なアイテムを探す
211
+ for (let i = currentIndex + 1; i < items.length; i++) {
212
+ if (!items[i]?.disabled && !radioInputs[i].disabled) {
213
+ nextIndex = i;
214
+ break;
215
+ }
216
+ }
217
+ // 見つからなければ最初の有効なアイテムへ
218
+ if (nextIndex === undefined) {
219
+ for (let i = 0; i < currentIndex; i++) {
220
+ if (!items[i]?.disabled && !radioInputs[i].disabled) {
221
+ nextIndex = i;
222
+ break;
223
+ }
224
+ }
225
+ }
226
+ }
227
+
228
+ if (nextIndex !== undefined) {
229
+ const nextInput = radioInputs[nextIndex];
230
+ if (nextInput && !nextInput.disabled) {
231
+ nextInput.focus();
232
+ nextInput.click();
233
+ }
234
+ }
235
+ }
236
+ } else if (event.key === 'Home') {
237
+ event.preventDefault();
238
+ const radioInputs = document.querySelectorAll(
239
+ `input[type="radio"][name="${name}"]`
240
+ ) as NodeListOf<HTMLInputElement>;
241
+ for (let i = 0; i < items.length; i++) {
242
+ if (!items[i]?.disabled && !radioInputs[i].disabled) {
243
+ radioInputs[i].focus();
244
+ radioInputs[i].click();
245
+ break;
246
+ }
247
+ }
248
+ } else if (event.key === 'End') {
249
+ event.preventDefault();
250
+ const radioInputs = document.querySelectorAll(
251
+ `input[type="radio"][name="${name}"]`
252
+ ) as NodeListOf<HTMLInputElement>;
253
+ for (let i = items.length - 1; i >= 0; i--) {
254
+ if (!items[i]?.disabled && !radioInputs[i].disabled) {
255
+ radioInputs[i].focus();
256
+ radioInputs[i].click();
257
+ break;
258
+ }
259
+ }
260
+ }
261
+
262
+ onkeydown(event);
263
+ };
264
+
265
+ const handleKeyup = (event: KeyboardEvent) => {
266
+ onkeyup(event);
267
+ };
268
+
269
+ // マウスイベント
270
+ const handleClick = (event: MouseEvent) => {
271
+ if (disabled) return;
272
+ onclick(event);
273
+ };
274
+
275
+ const handleMouseDown = (event: MouseEvent) => {
276
+ if (disabled) return;
277
+ onmousedown(event);
278
+ };
279
+
280
+ const handleMouseUp = (event: MouseEvent) => {
281
+ if (disabled) return;
282
+ onmouseup(event);
283
+ };
284
+
285
+ const handleMouseEnter = (event: MouseEvent) => {
286
+ if (disabled) return;
287
+ onmouseenter(event);
288
+ };
289
+
290
+ const handleMouseLeave = (event: MouseEvent) => {
291
+ if (disabled) return;
292
+ onmouseleave(event);
293
+ };
294
+
295
+ const handleMouseOver = (event: MouseEvent) => {
296
+ if (disabled) return;
297
+ onmouseover(event);
298
+ };
299
+
300
+ const handleMouseOut = (event: MouseEvent) => {
301
+ if (disabled) return;
302
+ onmouseout(event);
303
+ };
304
+
305
+ const handleContextMenu = (event: MouseEvent) => {
306
+ if (disabled) return;
307
+ oncontextmenu(event);
308
+ };
309
+
310
+ const handleAuxClick = (event: MouseEvent) => {
311
+ if (disabled) return;
312
+ onauxclick(event);
313
+ };
314
+
315
+ // タッチイベント
316
+ const handleTouchStart = (event: TouchEvent) => {
317
+ if (disabled) return;
318
+ ontouchstart(event);
319
+ };
320
+
321
+ const handleTouchEnd = (event: TouchEvent) => {
322
+ if (disabled) return;
323
+ ontouchend(event);
324
+ };
325
+
326
+ const handleTouchMove = (event: TouchEvent) => {
327
+ if (disabled) return;
328
+ ontouchmove(event);
329
+ };
330
+
331
+ const handleTouchCancel = (event: TouchEvent) => {
332
+ if (disabled) return;
333
+ ontouchcancel(event);
334
+ };
335
+
336
+ // ポインターイベント
337
+ const handlePointerDown = (event: PointerEvent) => {
338
+ if (disabled) return;
339
+ onpointerdown(event);
340
+ };
341
+
342
+ const handlePointerUp = (event: PointerEvent) => {
343
+ if (disabled) return;
344
+ onpointerup(event);
345
+ };
346
+
347
+ const handlePointerEnter = (event: PointerEvent) => {
348
+ if (disabled) return;
349
+ onpointerenter(event);
350
+ };
351
+
352
+ const handlePointerLeave = (event: PointerEvent) => {
353
+ if (disabled) return;
354
+ onpointerleave(event);
355
+ };
356
+
357
+ const handlePointerMove = (event: PointerEvent) => {
358
+ if (disabled) return;
359
+ onpointermove(event);
360
+ };
361
+
362
+ const handlePointerCancel = (event: PointerEvent) => {
363
+ if (disabled) return;
364
+ onpointercancel(event);
365
+ };
366
+
367
+ // =========================================================================
368
+ // $derived
369
+ // =========================================================================
370
+ const effectiveIconSize = $derived(
371
+ iconOpticalSize || (size === 'small' ? 16 : size === 'large' ? 24 : 20)
372
+ );
373
+
374
+ const containerClasses = $derived(
375
+ [
376
+ 'segmented-control',
377
+ `segmented-control--${size}`,
378
+ fullWidth && 'segmented-control--full-width',
379
+ rounded && 'segmented-control--rounded',
380
+ disabled && 'segmented-control--disabled',
381
+ reducedMotion && 'segmented-control--no-motion'
382
+ ]
383
+ .filter(Boolean)
384
+ .join(' ')
385
+ );
386
+ </script>
387
+
388
+ <div
389
+ class={containerClasses}
390
+ role="radiogroup"
391
+ aria-label={ariaLabelledby ? undefined : ariaLabel}
392
+ aria-labelledby={ariaLabelledby}
393
+ style="--svelte-ui-segmented-control-selected-bg: {color || 'var(--svelte-ui-primary-color)'};"
394
+ {id}
395
+ data-testid="segmented-control"
396
+ {...restProps}
397
+ >
398
+ {#each items as item, index}
399
+ {@const isSelected = value === item.value}
400
+ {@const isDisabled = disabled || item.disabled}
401
+ {@const inputId = `${name}-${index}`}
402
+ <div class="segmented-control__item">
403
+ <input
404
+ type="radio"
405
+ id={inputId}
406
+ {name}
407
+ value={item.value}
408
+ checked={isSelected}
409
+ disabled={isDisabled}
410
+ class="segmented-control__input"
411
+ onchange={(e) => handleChange(item, e)}
412
+ onfocus={handleFocus}
413
+ onblur={handleBlur}
414
+ onkeydown={handleKeydown}
415
+ onkeyup={handleKeyup}
416
+ onclick={handleClick}
417
+ onmousedown={handleMouseDown}
418
+ onmouseup={handleMouseUp}
419
+ onmouseenter={handleMouseEnter}
420
+ onmouseleave={handleMouseLeave}
421
+ onmouseover={handleMouseOver}
422
+ onmouseout={handleMouseOut}
423
+ oncontextmenu={handleContextMenu}
424
+ onauxclick={handleAuxClick}
425
+ ontouchstart={handleTouchStart}
426
+ ontouchend={handleTouchEnd}
427
+ ontouchmove={handleTouchMove}
428
+ ontouchcancel={handleTouchCancel}
429
+ onpointerdown={handlePointerDown}
430
+ onpointerup={handlePointerUp}
431
+ onpointerenter={handlePointerEnter}
432
+ onpointerleave={handlePointerLeave}
433
+ onpointermove={handlePointerMove}
434
+ onpointercancel={handlePointerCancel}
435
+ data-testid="segmented-control-input"
436
+ data-value={item.value}
437
+ />
438
+ <label
439
+ for={inputId}
440
+ class="segmented-control__label"
441
+ class:segmented-control__label--selected={isSelected}
442
+ class:segmented-control__label--first={index === 0}
443
+ class:segmented-control__label--last={index === items.length - 1}
444
+ aria-label={item.ariaLabel || item.label || undefined}
445
+ >
446
+ {#if item.icon}
447
+ <span class="segmented-control__icon">
448
+ <Icon
449
+ filled={iconFilled || isSelected}
450
+ weight={iconWeight}
451
+ grade={iconGrade}
452
+ opticalSize={effectiveIconSize}
453
+ variant={iconVariant}
454
+ >
455
+ {item.icon}
456
+ </Icon>
457
+ </span>
458
+ {/if}
459
+ {#if item.label}
460
+ <span class="segmented-control__label-text">{item.label}</span>
461
+ {/if}
462
+ </label>
463
+ </div>
464
+ {/each}
465
+ </div>
466
+
467
+ <style>.segmented-control {
468
+ display: inline-flex;
469
+ position: relative;
470
+ padding: var(--svelte-ui-segmented-control-base-padding);
471
+ background-color: var(--svelte-ui-segmented-control-base-bg);
472
+ border-radius: var(--svelte-ui-segmented-control-base-border-radius);
473
+ gap: var(--svelte-ui-segmented-control-gap);
474
+ box-sizing: border-box;
475
+ width: fit-content;
476
+ max-width: 100%;
477
+ overflow-x: auto;
478
+ overflow-y: visible;
479
+ -ms-overflow-style: none;
480
+ overscroll-behavior: contain;
481
+ }
482
+
483
+ .segmented-control::-webkit-scrollbar {
484
+ display: none;
485
+ }
486
+
487
+ .segmented-control--full-width {
488
+ width: 100%;
489
+ }
490
+
491
+ .segmented-control--full-width .segmented-control__item {
492
+ flex: 1;
493
+ }
494
+
495
+ .segmented-control--rounded {
496
+ border-radius: var(--svelte-ui-border-radius-rounded, 9999px);
497
+ }
498
+
499
+ .segmented-control--disabled {
500
+ opacity: var(--svelte-ui-button-disabled-opacity);
501
+ pointer-events: none;
502
+ }
503
+
504
+ .segmented-control__item {
505
+ position: relative;
506
+ flex: 0 1 auto;
507
+ display: flex;
508
+ align-items: stretch;
509
+ }
510
+
511
+ .segmented-control__input {
512
+ position: absolute;
513
+ width: 0;
514
+ height: 0;
515
+ margin: 0;
516
+ opacity: 0;
517
+ pointer-events: none;
518
+ }
519
+
520
+ .segmented-control__label {
521
+ display: flex;
522
+ align-items: center;
523
+ justify-content: center;
524
+ gap: 6px;
525
+ position: relative;
526
+ border: none;
527
+ background-color: transparent;
528
+ color: var(--svelte-ui-text-subtle-color, var(--svelte-ui-text-color));
529
+ white-space: nowrap;
530
+ cursor: pointer;
531
+ user-select: none;
532
+ -webkit-user-select: none;
533
+ -moz-user-select: none;
534
+ -ms-user-select: none;
535
+ transition-property: background-color, color;
536
+ transition-duration: var(--svelte-ui-transition-duration, 0.2s);
537
+ transition-timing-function: ease;
538
+ outline: none;
539
+ font-family: inherit;
540
+ font-weight: 500;
541
+ line-height: 1;
542
+ box-sizing: border-box;
543
+ width: 100%;
544
+ text-align: center;
545
+ border-radius: var(--svelte-ui-segmented-control-button-radius);
546
+ }
547
+
548
+ .segmented-control--small .segmented-control__label {
549
+ height: var(--svelte-ui-segmented-control-button-height-sm);
550
+ font-size: var(--svelte-ui-segmented-control-font-size-sm);
551
+ padding: var(--svelte-ui-segmented-control-button-padding-sm);
552
+ }
553
+
554
+ .segmented-control--small .segmented-control__label:not(:has(.segmented-control__label-text)) {
555
+ width: var(--svelte-ui-segmented-control-button-height-sm);
556
+ }
557
+
558
+ .segmented-control--medium .segmented-control__label {
559
+ height: var(--svelte-ui-segmented-control-button-height);
560
+ font-size: var(--svelte-ui-segmented-control-font-size);
561
+ padding: var(--svelte-ui-segmented-control-button-padding);
562
+ }
563
+
564
+ .segmented-control--medium .segmented-control__label:not(:has(.segmented-control__label-text)) {
565
+ width: var(--svelte-ui-segmented-control-button-height);
566
+ }
567
+
568
+ .segmented-control--large .segmented-control__label {
569
+ height: var(--svelte-ui-segmented-control-button-height-lg);
570
+ font-size: var(--svelte-ui-segmented-control-font-size-lg);
571
+ padding: var(--svelte-ui-segmented-control-button-padding-lg);
572
+ }
573
+
574
+ .segmented-control--large .segmented-control__label:not(:has(.segmented-control__label-text)) {
575
+ width: var(--svelte-ui-segmented-control-button-height-lg);
576
+ }
577
+
578
+ .segmented-control--rounded .segmented-control__label {
579
+ border-radius: calc(var(--svelte-ui-border-radius-rounded, 9999px) - 2px);
580
+ }
581
+
582
+ @media (hover: hover) {
583
+ .segmented-control__input:not(:disabled) + .segmented-control__label:hover:not(.segmented-control__label--selected) {
584
+ background-color: var(--svelte-ui-segmented-control-hover-overlay);
585
+ color: var(--svelte-ui-text-color);
586
+ }
587
+ }
588
+ .segmented-control__input:focus-visible + .segmented-control__label {
589
+ outline: var(--svelte-ui-focus-outline-inner, 2px solid currentColor);
590
+ outline-offset: var(--svelte-ui-focus-outline-offset-inner, 2px);
591
+ }
592
+
593
+ .segmented-control__input:checked + .segmented-control__label,
594
+ .segmented-control__label--selected {
595
+ background-color: var(--svelte-ui-segmented-control-selected-bg);
596
+ color: var(--svelte-ui-segmented-control-selected-text-color, white);
597
+ }
598
+
599
+ .segmented-control:not(.segmented-control--disabled) .segmented-control__input:disabled + .segmented-control__label {
600
+ opacity: var(--svelte-ui-button-disabled-opacity);
601
+ cursor: not-allowed;
602
+ }
603
+
604
+ .segmented-control__icon {
605
+ display: flex;
606
+ align-items: center;
607
+ justify-content: center;
608
+ }
609
+
610
+ .segmented-control__label-text {
611
+ text-box-trim: trim-both;
612
+ text-box-edge: cap alphabetic;
613
+ }
614
+
615
+ /* Reduced motion */
616
+ .segmented-control--no-motion,
617
+ .segmented-control--no-motion .segmented-control__label {
618
+ transition-duration: 0.01s;
619
+ }
620
+
621
+ @media (prefers-reduced-motion: reduce) {
622
+ .segmented-control,
623
+ .segmented-control__label {
624
+ transition-duration: 0.01s;
625
+ }
626
+ }</style>
@@ -0,0 +1,49 @@
1
+ import type { IconVariant, IconWeight, IconGrade, IconOpticalSize } from '../types/icon';
2
+ import type { SegmentedControlItem } from '../types/segmentedControlItem';
3
+ type $$ComponentProps = {
4
+ items: SegmentedControlItem[];
5
+ value: string;
6
+ id?: string;
7
+ name?: string;
8
+ size?: 'small' | 'medium' | 'large';
9
+ fullWidth?: boolean;
10
+ color?: string;
11
+ rounded?: boolean;
12
+ iconFilled?: boolean;
13
+ iconWeight?: IconWeight;
14
+ iconGrade?: IconGrade;
15
+ iconOpticalSize?: IconOpticalSize;
16
+ iconVariant?: IconVariant;
17
+ disabled?: boolean;
18
+ ariaLabel?: string;
19
+ ariaLabelledby?: string;
20
+ reducedMotion?: boolean;
21
+ onchange?: (value: string) => void;
22
+ onfocus?: Function;
23
+ onblur?: Function;
24
+ onkeydown?: Function;
25
+ onkeyup?: Function;
26
+ onclick?: Function;
27
+ onmousedown?: Function;
28
+ onmouseup?: Function;
29
+ onmouseenter?: Function;
30
+ onmouseleave?: Function;
31
+ onmouseover?: Function;
32
+ onmouseout?: Function;
33
+ oncontextmenu?: Function;
34
+ onauxclick?: Function;
35
+ ontouchstart?: Function;
36
+ ontouchend?: Function;
37
+ ontouchmove?: Function;
38
+ ontouchcancel?: Function;
39
+ onpointerdown?: Function;
40
+ onpointerup?: Function;
41
+ onpointerenter?: Function;
42
+ onpointerleave?: Function;
43
+ onpointermove?: Function;
44
+ onpointercancel?: Function;
45
+ [key: string]: any;
46
+ };
47
+ declare const SegmentedControl: import("svelte").Component<$$ComponentProps, {}, "value">;
48
+ type SegmentedControl = ReturnType<typeof SegmentedControl>;
49
+ export default SegmentedControl;
@@ -112,7 +112,10 @@
112
112
  );
113
113
  const requiredMargin = -containerHeight;
114
114
 
115
- snackbarRef.style.setProperty('--svelte-ui-snackbar-item-collapse-margin', `${requiredMargin}px`);
115
+ snackbarRef.style.setProperty(
116
+ '--svelte-ui-snackbar-item-collapse-margin',
117
+ `${requiredMargin}px`
118
+ );
116
119
 
117
120
  // CSSカスタムプロパティが確実に設定されるまで少し待つ
118
121
  requestAnimationFrame(() => {
@@ -149,7 +152,8 @@
149
152
  class="snackbar-item__content snackbar-item__content--{type} snackbar-item__content--{variant} snackbar-item__content--{position} {visible
150
153
  ? 'snackbar-item__content--visible'
151
154
  : ''}"
152
- style="--svelte-ui-snackbar-item-custom-color: {color ?? 'unset'}; --svelte-ui-snackbar-item-custom-text-color: {textColor ?? 'unset'};"
155
+ style="--svelte-ui-snackbar-item-custom-color: {color ??
156
+ 'unset'}; --svelte-ui-snackbar-item-custom-text-color: {textColor ?? 'unset'};"
153
157
  role={type === 'error' || type === 'warning' ? 'alert' : 'status'}
154
158
  aria-live={type === 'error' || type === 'warning' ? 'assertive' : 'polite'}
155
159
  aria-atomic="true"
@@ -321,103 +325,208 @@
321
325
 
322
326
  /* Type variants - filled */
323
327
  .snackbar-item__content--filled.snackbar-item__content--info {
324
- background-color: var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-info-filled-bg));
325
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-info-filled-text-color));
328
+ background-color: var(
329
+ --svelte-ui-snackbar-item-custom-color,
330
+ var(--svelte-ui-snackbar-info-filled-bg)
331
+ );
332
+ color: var(
333
+ --svelte-ui-snackbar-item-custom-text-color,
334
+ var(--svelte-ui-snackbar-info-filled-text-color)
335
+ );
326
336
  }
327
337
 
328
338
  .snackbar-item__content--filled.snackbar-item__content--info .snackbar-item__icon {
329
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-info-filled-text-color));
339
+ color: var(
340
+ --svelte-ui-snackbar-item-custom-text-color,
341
+ var(--svelte-ui-snackbar-info-filled-text-color)
342
+ );
330
343
  }
331
344
 
332
345
  .snackbar-item__content--filled.snackbar-item__content--success {
333
- background-color: var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-success-filled-bg));
334
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-success-filled-text-color));
346
+ background-color: var(
347
+ --svelte-ui-snackbar-item-custom-color,
348
+ var(--svelte-ui-snackbar-success-filled-bg)
349
+ );
350
+ color: var(
351
+ --svelte-ui-snackbar-item-custom-text-color,
352
+ var(--svelte-ui-snackbar-success-filled-text-color)
353
+ );
335
354
  }
336
355
 
337
356
  .snackbar-item__content--filled.snackbar-item__content--success .snackbar-item__icon {
338
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-success-filled-text-color));
357
+ color: var(
358
+ --svelte-ui-snackbar-item-custom-text-color,
359
+ var(--svelte-ui-snackbar-success-filled-text-color)
360
+ );
339
361
  }
340
362
 
341
363
  .snackbar-item__content--filled.snackbar-item__content--warning {
342
- background-color: var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-warning-filled-bg));
343
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-warning-filled-text-color));
364
+ background-color: var(
365
+ --svelte-ui-snackbar-item-custom-color,
366
+ var(--svelte-ui-snackbar-warning-filled-bg)
367
+ );
368
+ color: var(
369
+ --svelte-ui-snackbar-item-custom-text-color,
370
+ var(--svelte-ui-snackbar-warning-filled-text-color)
371
+ );
344
372
  }
345
373
 
346
374
  .snackbar-item__content--filled.snackbar-item__content--warning .snackbar-item__icon {
347
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-warning-filled-text-color));
375
+ color: var(
376
+ --svelte-ui-snackbar-item-custom-text-color,
377
+ var(--svelte-ui-snackbar-warning-filled-text-color)
378
+ );
348
379
  }
349
380
 
350
381
  .snackbar-item__content--filled.snackbar-item__content--error {
351
- background-color: var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-error-filled-bg));
352
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-error-filled-text-color));
382
+ background-color: var(
383
+ --svelte-ui-snackbar-item-custom-color,
384
+ var(--svelte-ui-snackbar-error-filled-bg)
385
+ );
386
+ color: var(
387
+ --svelte-ui-snackbar-item-custom-text-color,
388
+ var(--svelte-ui-snackbar-error-filled-text-color)
389
+ );
353
390
  }
354
391
 
355
392
  .snackbar-item__content--filled.snackbar-item__content--error .snackbar-item__icon {
356
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-error-filled-text-color));
393
+ color: var(
394
+ --svelte-ui-snackbar-item-custom-text-color,
395
+ var(--svelte-ui-snackbar-error-filled-text-color)
396
+ );
357
397
  }
358
398
 
359
399
  .snackbar-item__content--filled.snackbar-item__content--default {
360
- background-color: var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-default-filled-bg));
361
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-default-filled-text-color));
400
+ background-color: var(
401
+ --svelte-ui-snackbar-item-custom-color,
402
+ var(--svelte-ui-snackbar-default-filled-bg)
403
+ );
404
+ color: var(
405
+ --svelte-ui-snackbar-item-custom-text-color,
406
+ var(--svelte-ui-snackbar-default-filled-text-color)
407
+ );
362
408
  }
363
409
 
364
410
  .snackbar-item__content--filled.snackbar-item__content--default .snackbar-item__icon {
365
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-default-filled-text-color));
411
+ color: var(
412
+ --svelte-ui-snackbar-item-custom-text-color,
413
+ var(--svelte-ui-snackbar-default-filled-text-color)
414
+ );
366
415
  }
367
416
 
368
417
  /* Type variants - outlined */
369
418
  .snackbar-item__content--outlined.snackbar-item__content--info {
370
- background-color: var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-info-outlined-bg));
371
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-info-outlined-text-color));
419
+ background-color: var(
420
+ --svelte-ui-snackbar-item-custom-color,
421
+ var(--svelte-ui-snackbar-info-outlined-bg)
422
+ );
423
+ color: var(
424
+ --svelte-ui-snackbar-item-custom-text-color,
425
+ var(--svelte-ui-snackbar-info-outlined-text-color)
426
+ );
372
427
  box-shadow: inset 0 0 0 1px
373
- var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-info-outlined-border-color));
428
+ var(
429
+ --svelte-ui-snackbar-item-custom-color,
430
+ var(--svelte-ui-snackbar-info-outlined-border-color)
431
+ );
374
432
  }
375
433
 
376
434
  .snackbar-item__content--outlined.snackbar-item__content--info .snackbar-item__icon {
377
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-info-outlined-text-color));
435
+ color: var(
436
+ --svelte-ui-snackbar-item-custom-text-color,
437
+ var(--svelte-ui-snackbar-info-outlined-text-color)
438
+ );
378
439
  }
379
440
 
380
441
  .snackbar-item__content--outlined.snackbar-item__content--success {
381
- background-color: var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-success-outlined-bg));
382
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-success-outlined-text-color));
442
+ background-color: var(
443
+ --svelte-ui-snackbar-item-custom-color,
444
+ var(--svelte-ui-snackbar-success-outlined-bg)
445
+ );
446
+ color: var(
447
+ --svelte-ui-snackbar-item-custom-text-color,
448
+ var(--svelte-ui-snackbar-success-outlined-text-color)
449
+ );
383
450
  box-shadow: inset 0 0 0 1px
384
- var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-success-outlined-border-color));
451
+ var(
452
+ --svelte-ui-snackbar-item-custom-color,
453
+ var(--svelte-ui-snackbar-success-outlined-border-color)
454
+ );
385
455
  }
386
456
 
387
457
  .snackbar-item__content--outlined.snackbar-item__content--success .snackbar-item__icon {
388
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-success-outlined-text-color));
458
+ color: var(
459
+ --svelte-ui-snackbar-item-custom-text-color,
460
+ var(--svelte-ui-snackbar-success-outlined-text-color)
461
+ );
389
462
  }
390
463
 
391
464
  .snackbar-item__content--outlined.snackbar-item__content--warning {
392
- background-color: var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-warning-outlined-bg));
393
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-warning-outlined-text-color));
465
+ background-color: var(
466
+ --svelte-ui-snackbar-item-custom-color,
467
+ var(--svelte-ui-snackbar-warning-outlined-bg)
468
+ );
469
+ color: var(
470
+ --svelte-ui-snackbar-item-custom-text-color,
471
+ var(--svelte-ui-snackbar-warning-outlined-text-color)
472
+ );
394
473
  box-shadow: inset 0 0 0 1px
395
- var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-warning-outlined-border-color));
474
+ var(
475
+ --svelte-ui-snackbar-item-custom-color,
476
+ var(--svelte-ui-snackbar-warning-outlined-border-color)
477
+ );
396
478
  }
397
479
 
398
480
  .snackbar-item__content--outlined.snackbar-item__content--warning .snackbar-item__icon {
399
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-warning-outlined-text-color));
481
+ color: var(
482
+ --svelte-ui-snackbar-item-custom-text-color,
483
+ var(--svelte-ui-snackbar-warning-outlined-text-color)
484
+ );
400
485
  }
401
486
 
402
487
  .snackbar-item__content--outlined.snackbar-item__content--error {
403
- background-color: var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-error-outlined-bg));
404
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-error-outlined-text-color));
488
+ background-color: var(
489
+ --svelte-ui-snackbar-item-custom-color,
490
+ var(--svelte-ui-snackbar-error-outlined-bg)
491
+ );
492
+ color: var(
493
+ --svelte-ui-snackbar-item-custom-text-color,
494
+ var(--svelte-ui-snackbar-error-outlined-text-color)
495
+ );
405
496
  box-shadow: inset 0 0 0 1px
406
- var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-error-outlined-border-color));
497
+ var(
498
+ --svelte-ui-snackbar-item-custom-color,
499
+ var(--svelte-ui-snackbar-error-outlined-border-color)
500
+ );
407
501
  }
408
502
 
409
503
  .snackbar-item__content--outlined.snackbar-item__content--error .snackbar-item__icon {
410
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-error-outlined-text-color));
504
+ color: var(
505
+ --svelte-ui-snackbar-item-custom-text-color,
506
+ var(--svelte-ui-snackbar-error-outlined-text-color)
507
+ );
411
508
  }
412
509
 
413
510
  .snackbar-item__content--outlined.snackbar-item__content--default {
414
- background-color: var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-default-outlined-bg));
415
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-default-outlined-text-color));
511
+ background-color: var(
512
+ --svelte-ui-snackbar-item-custom-color,
513
+ var(--svelte-ui-snackbar-default-outlined-bg)
514
+ );
515
+ color: var(
516
+ --svelte-ui-snackbar-item-custom-text-color,
517
+ var(--svelte-ui-snackbar-default-outlined-text-color)
518
+ );
416
519
  box-shadow: inset 0 0 0 1px
417
- var(--svelte-ui-snackbar-item-custom-color, var(--svelte-ui-snackbar-default-outlined-border-color));
520
+ var(
521
+ --svelte-ui-snackbar-item-custom-color,
522
+ var(--svelte-ui-snackbar-default-outlined-border-color)
523
+ );
418
524
  }
419
525
 
420
526
  .snackbar-item__content--outlined.snackbar-item__content--default .snackbar-item__icon {
421
- color: var(--svelte-ui-snackbar-item-custom-text-color, var(--svelte-ui-snackbar-default-outlined-text-color));
527
+ color: var(
528
+ --svelte-ui-snackbar-item-custom-text-color,
529
+ var(--svelte-ui-snackbar-default-outlined-text-color)
530
+ );
422
531
  }
423
532
  </style>
package/dist/index.d.ts CHANGED
@@ -23,6 +23,7 @@ export { default as PopupMenuButton } from './components/PopupMenuButton.svelte'
23
23
  export { default as Radio } from './components/Radio.svelte';
24
24
  export { default as RadioGroup } from './components/RadioGroup.svelte';
25
25
  export { default as Select } from './components/Select.svelte';
26
+ export { default as SegmentedControl } from './components/SegmentedControl.svelte';
26
27
  export { default as Slider } from './components/Slider.svelte';
27
28
  export { default as Snackbar } from './components/Snackbar.svelte';
28
29
  export { default as SnackbarItem } from './components/SnackbarItem.svelte';
@@ -40,3 +41,4 @@ export * from './utils/mobile';
40
41
  export * from './utils/snackbar.svelte';
41
42
  export * from './utils/style';
42
43
  export type { MenuItem } from './types/menuItem';
44
+ export type { SegmentedControlItem } from './types/segmentedControlItem';
package/dist/index.js CHANGED
@@ -24,6 +24,7 @@ export { default as PopupMenuButton } from './components/PopupMenuButton.svelte'
24
24
  export { default as Radio } from './components/Radio.svelte';
25
25
  export { default as RadioGroup } from './components/RadioGroup.svelte';
26
26
  export { default as Select } from './components/Select.svelte';
27
+ export { default as SegmentedControl } from './components/SegmentedControl.svelte';
27
28
  export { default as Slider } from './components/Slider.svelte';
28
29
  export { default as Snackbar } from './components/Snackbar.svelte';
29
30
  export { default as SnackbarItem } from './components/SnackbarItem.svelte';
@@ -0,0 +1,13 @@
1
+ export type SegmentedControlItem = {
2
+ label: string;
3
+ value: string;
4
+ icon?: string;
5
+ disabled?: boolean;
6
+ ariaLabel?: string;
7
+ } | {
8
+ label?: never;
9
+ value: string;
10
+ icon: string;
11
+ disabled?: boolean;
12
+ ariaLabel: string;
13
+ };
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@14ch/svelte-ui",
3
3
  "description": "Modern Svelte UI components library with TypeScript support",
4
4
  "private": false,
5
- "version": "0.0.6",
5
+ "version": "0.0.8",
6
6
  "type": "module",
7
7
  "keywords": [
8
8
  "svelte",