@14ch/svelte-ui 0.0.2 → 0.0.4

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.
Files changed (35) hide show
  1. package/README.md +9 -0
  2. package/dist/assets/styles/import.scss +3 -1
  3. package/dist/assets/styles/variables.scss +20 -12
  4. package/dist/components/Button.svelte +7 -5
  5. package/dist/components/Button.svelte.d.ts +1 -1
  6. package/dist/components/Checkbox.svelte +9 -3
  7. package/dist/components/CheckboxGroup.svelte +34 -11
  8. package/dist/components/CheckboxGroup.svelte.d.ts +4 -0
  9. package/dist/components/Dialog.svelte +6 -23
  10. package/dist/components/Drawer.svelte +22 -32
  11. package/dist/components/Fab.svelte +4 -0
  12. package/dist/components/FileUploader.svelte +9 -4
  13. package/dist/components/Icon.svelte +12 -2
  14. package/dist/components/IconButton.svelte +2 -2
  15. package/dist/components/IconButton.svelte.d.ts +1 -1
  16. package/dist/components/ImageUploader.svelte +21 -12
  17. package/dist/components/ImageUploader.svelte.d.ts +2 -1
  18. package/dist/components/ImageUploaderPreview.svelte +47 -18
  19. package/dist/components/ImageUploaderPreview.svelte.d.ts +5 -4
  20. package/dist/components/LoadingSpinner.svelte +22 -17
  21. package/dist/components/Popup.svelte +0 -13
  22. package/dist/components/PopupMenu.svelte +4 -4
  23. package/dist/components/PopupMenuButton.svelte +0 -13
  24. package/dist/components/Radio.svelte +14 -6
  25. package/dist/components/RadioGroup.svelte +40 -16
  26. package/dist/components/RadioGroup.svelte.d.ts +4 -0
  27. package/dist/components/Slider.svelte +0 -5
  28. package/dist/components/Snackbar.svelte +0 -4
  29. package/dist/components/SnackbarItem.svelte +39 -39
  30. package/dist/components/Switch.svelte +18 -17
  31. package/dist/components/Switch.svelte.d.ts +1 -1
  32. package/dist/components/Tab.svelte +9 -15
  33. package/dist/components/TabItem.svelte +11 -7
  34. package/dist/components/skeleton/SkeletonText.svelte +1 -1
  35. package/package.json +3 -2
package/README.md CHANGED
@@ -346,6 +346,15 @@ MIT License - see the [LICENSE](LICENSE) file for details.
346
346
 
347
347
  ## Changelog
348
348
 
349
+ ### v0.0.3
350
+
351
+ - Improved text vertical alignment in Button, Fab, TabItem, Checkbox, and Radio components using `text-box-trim`
352
+ - Text labels now appear more visually centered within their containers
353
+
354
+ ### v0.0.2
355
+
356
+ (Previous release notes...)
357
+
349
358
  ### v0.0.1
350
359
 
351
360
  - Initial release
@@ -7,5 +7,7 @@
7
7
  @use './variables';
8
8
  @use './core';
9
9
 
10
- /* Material Symbols font (required for Icon component) */
10
+ /* Material Symbols fonts (required for Icon component) */
11
11
  @import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200');
12
+ @import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200');
13
+ @import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200');
@@ -293,12 +293,13 @@
293
293
  --svelte-ui-button-height-sm: var(--svelte-ui-form-height-sm);
294
294
  --svelte-ui-button-height: var(--svelte-ui-form-height);
295
295
  --svelte-ui-button-height-lg: var(--svelte-ui-form-height-lg);
296
- --svelte-ui-button-padding-sm: 0 8px;
297
- --svelte-ui-button-padding: 0 12px;
298
- --svelte-ui-button-padding-lg: 0 16px;
296
+ --svelte-ui-button-padding-sm: 6px 8px;
297
+ --svelte-ui-button-padding: 8px 12px;
298
+ --svelte-ui-button-padding-lg: 12px 16px;
299
299
  --svelte-ui-button-font-size-sm: 14px;
300
300
  --svelte-ui-button-font-size: inherit;
301
301
  --svelte-ui-button-font-size-lg: 16px;
302
+ --svelte-ui-button-line-height: 1.2em;
302
303
  --svelte-ui-button-border-radius: var(--svelte-ui-border-radius);
303
304
  --svelte-ui-button-border-radius-rounded: var(--svelte-ui-border-radius-rounded);
304
305
  --svelte-ui-button-disabled-opacity: var(--svelte-ui-disabled-opacity);
@@ -403,15 +404,16 @@
403
404
  --svelte-ui-checkbox-size: 16px;
404
405
  --svelte-ui-checkbox-size-sm: 14px;
405
406
  --svelte-ui-checkbox-size-lg: 20px;
406
- --svelte-ui-checkbox-min-height: 20px;
407
- --svelte-ui-checkbox-min-height-sm: 16px;
408
- --svelte-ui-checkbox-min-height-lg: 24px;
407
+ --svelte-ui-checkbox-min-height: 1.8em;
408
+ --svelte-ui-checkbox-min-height-sm: 1.6em;
409
+ --svelte-ui-checkbox-min-height-lg: 2.2em;
409
410
  --svelte-ui-checkbox-border-radius: 2px;
410
411
  --svelte-ui-checkbox-border-width: 2px;
411
412
  --svelte-ui-checkbox-gap: 8px;
412
413
  --svelte-ui-checkbox-icon-size: 1rem;
413
414
  --svelte-ui-checkbox-icon-size-sm: 0.875rem;
414
415
  --svelte-ui-checkbox-icon-size-lg: 1.25rem;
416
+ --svelte-ui-checkbox-line-height: 1.2em;
415
417
  --svelte-ui-checkbox-disabled-opacity: var(--svelte-ui-disabled-opacity);
416
418
  --svelte-ui-checkbox-border-color: var(--svelte-ui-border-color);
417
419
  --svelte-ui-checkbox-bg-checked: var(--svelte-ui-checkbox-checked-color);
@@ -437,6 +439,7 @@
437
439
  var(--svelte-ui-switch-height-lg) - var(--svelte-ui-switch-thumb-margin) * 2
438
440
  );
439
441
  --svelte-ui-switch-gap: 8px;
442
+ --svelte-ui-switch-line-height: 1.2em;
440
443
  --svelte-ui-switch-disabled-opacity: var(--svelte-ui-disabled-opacity);
441
444
  --svelte-ui-switch-border-radius: var(--svelte-ui-border-radius-rounded);
442
445
  --svelte-ui-switch-thumb-border-radius: var(--svelte-ui-border-radius-rounded);
@@ -454,12 +457,17 @@
454
457
  --svelte-ui-radio-dot-size-lg: 10px;
455
458
  --svelte-ui-radio-border-radius: var(--svelte-ui-border-radius-rounded);
456
459
  --svelte-ui-radio-border-width: 2px;
457
- --svelte-ui-radio-min-height: 20px;
458
- --svelte-ui-radio-min-height-sm: 16px;
459
- --svelte-ui-radio-min-height-lg: 24px;
460
- --svelte-ui-radio-padding: 0 0 0 24px;
461
- --svelte-ui-radio-padding-sm: 0 0 0 20px;
462
- --svelte-ui-radio-padding-lg: 0 0 0 28px;
460
+ --svelte-ui-radio-min-height: 1.8em;
461
+ --svelte-ui-radio-min-height-sm: 1.6em;
462
+ --svelte-ui-radio-min-height-lg: 2.2em;
463
+ --svelte-ui-radio-gap: 8px;
464
+ --svelte-ui-radio-line-height: 1.2em;
465
+
466
+ /* CheckboxGroup */
467
+ --svelte-ui-checkbox-group-gap: 0 24px;
468
+
469
+ /* RadioGroup */
470
+ --svelte-ui-radio-group-gap: 0 24px;
463
471
  --svelte-ui-radio-disabled-opacity: var(--svelte-ui-disabled-opacity);
464
472
  --svelte-ui-radio-border-color: var(--svelte-ui-border-color);
465
473
  --svelte-ui-radio-bg-checked: var(--svelte-ui-radio-checked-color);
@@ -41,12 +41,12 @@
41
41
  // 状態/動作
42
42
  disabled = false,
43
43
  loading = false,
44
- reducedMotion = false,
45
44
 
46
45
  // ARIA/アクセシビリティ
47
46
  ariaLabel,
48
47
  ariaDescribedby,
49
48
  ariaExpanded,
49
+ reducedMotion = false,
50
50
 
51
51
  // フォーカスイベント
52
52
  onfocus = () => {}, // No params for type inference
@@ -113,12 +113,12 @@
113
113
  // 状態/動作
114
114
  disabled?: boolean;
115
115
  loading?: boolean;
116
- reducedMotion?: boolean;
117
116
 
118
117
  // ARIA/アクセシビリティ
119
118
  ariaLabel?: string;
120
119
  ariaDescribedby?: string;
121
120
  ariaExpanded?: boolean;
121
+ reducedMotion?: boolean;
122
122
 
123
123
  // フォーカスイベント
124
124
  onfocus?: Function; // No params for type inference
@@ -502,9 +502,11 @@
502
502
 
503
503
  .button__label {
504
504
  width: 100%;
505
- display: flex;
506
- align-items: center;
507
- justify-content: center;
505
+ display: block;
506
+ text-align: center;
507
+ line-height: var(--svelte-ui-button-line-height);
508
+ text-box-trim: trim-both;
509
+ text-box-edge: cap alphabetic;
508
510
  transition-property: opacity;
509
511
  transition-duration: var(--svelte-ui-transition-duration);
510
512
  }
@@ -22,10 +22,10 @@ type $$ComponentProps = {
22
22
  iconVariant?: IconVariant;
23
23
  disabled?: boolean;
24
24
  loading?: boolean;
25
- reducedMotion?: boolean;
26
25
  ariaLabel?: string;
27
26
  ariaDescribedby?: string;
28
27
  ariaExpanded?: boolean;
28
+ reducedMotion?: boolean;
29
29
  onfocus?: Function;
30
30
  onblur?: Function;
31
31
  onkeydown?: Function;
@@ -26,6 +26,8 @@
26
26
  // 状態/動作
27
27
  disabled = false,
28
28
  required = false,
29
+
30
+ // ARIA/アクセシビリティ
29
31
  reducedMotion = false,
30
32
 
31
33
  // 入力イベント
@@ -85,6 +87,8 @@
85
87
  // 状態/動作
86
88
  disabled?: boolean;
87
89
  required?: boolean;
90
+
91
+ // ARIA/アクセシビリティ
88
92
  reducedMotion?: boolean;
89
93
 
90
94
  // 入力イベント
@@ -330,6 +334,7 @@
330
334
  display: flex;
331
335
  align-items: center;
332
336
  width: fit-content;
337
+ min-height: var(--svelte-ui-checkbox-min-height);
333
338
  contain: layout;
334
339
  }
335
340
 
@@ -344,14 +349,15 @@
344
349
 
345
350
  /* Label */
346
351
  .checkbox__label {
347
- display: flex;
348
- align-items: center;
349
- min-height: var(--svelte-ui-checkbox-min-height);
352
+ display: block;
350
353
  padding-left: var(--svelte-ui-checkbox-gap);
351
354
  white-space: nowrap;
352
355
  font-size: inherit;
353
356
  color: inherit;
357
+ line-height: var(--svelte-ui-checkbox-line-height);
354
358
  cursor: pointer;
359
+ text-box-trim: trim-both;
360
+ text-box-edge: cap alphabetic;
355
361
  }
356
362
 
357
363
  /* Checkbox box */
@@ -11,9 +11,17 @@
11
11
 
12
12
  // スタイル/レイアウト
13
13
  direction = 'vertical',
14
- gap = '0',
14
+ gap,
15
15
  wrap = false,
16
16
  minOptionWidth,
17
+ size = 'medium',
18
+
19
+ // 状態/動作
20
+ disabled = false,
21
+ required = false,
22
+
23
+ // ARIA/アクセシビリティ
24
+ reducedMotion = false,
17
25
 
18
26
  // 入力イベント
19
27
  onchange = () => {} // No params for type inference
@@ -27,6 +35,14 @@
27
35
  gap?: string | number;
28
36
  wrap?: boolean;
29
37
  minOptionWidth?: string | number;
38
+ size?: 'small' | 'medium' | 'large';
39
+
40
+ // 状態/動作
41
+ disabled?: boolean;
42
+ required?: boolean;
43
+
44
+ // ARIA/アクセシビリティ
45
+ reducedMotion?: boolean;
30
46
 
31
47
  // 入力イベント
32
48
  onchange?: (value: OptionValue[]) => void;
@@ -44,23 +60,30 @@
44
60
  onchange(value);
45
61
  };
46
62
 
47
- const gapStyle = getStyleFromNumber(gap);
63
+ const gapStyle = gap !== undefined ? getStyleFromNumber(gap) : undefined;
48
64
 
49
65
  const minOptionWidthStyle = getStyleFromNumber(minOptionWidth);
50
66
  </script>
51
67
 
52
68
  <ul
53
69
  class="checkbox-group"
54
- style="--flex-direction: {direction === 'vertical' ? 'column' : 'row'};
55
- --gap: {gapStyle};
56
- --wrap: {wrap ? 'wrap' : 'none'};
57
- --min-option-width: {minOptionWidthStyle}
70
+ style="--svelte-ui-checkbox-group-flex-direction: {direction === 'vertical' ? 'column' : 'row'};
71
+ {gapStyle ? `--svelte-ui-checkbox-group-gap: ${gapStyle};` : ''}
72
+ --svelte-ui-checkbox-group-wrap: {wrap ? 'wrap' : 'none'};
73
+ --svelte-ui-checkbox-group-min-option-width: {minOptionWidthStyle}
58
74
  "
59
75
  >
60
76
  {#each options as option (option.value)}
61
77
  {#if localValues[option.value] !== undefined}
62
78
  <li class="checkbox-group__option">
63
- <Checkbox bind:value={localValues[option.value]} onchange={handleChange}>
79
+ <Checkbox
80
+ bind:value={localValues[option.value]}
81
+ {size}
82
+ {disabled}
83
+ {required}
84
+ {reducedMotion}
85
+ onchange={handleChange}
86
+ >
64
87
  {option.label}
65
88
  </Checkbox>
66
89
  </li>
@@ -71,12 +94,12 @@
71
94
  <style>
72
95
  .checkbox-group {
73
96
  display: flex;
74
- flex-direction: var(--flex-direction);
75
- gap: var(--gap);
76
- flex-wrap: var(--wrap);
97
+ flex-direction: var(--svelte-ui-checkbox-group-flex-direction);
98
+ gap: var(--svelte-ui-checkbox-group-gap);
99
+ flex-wrap: var(--svelte-ui-checkbox-group-wrap);
77
100
  }
78
101
 
79
102
  .checkbox-group__option {
80
- min-width: var(--min-option-width);
103
+ min-width: var(--svelte-ui-checkbox-group-min-option-width);
81
104
  }
82
105
  </style>
@@ -6,6 +6,10 @@ type $$ComponentProps = {
6
6
  gap?: string | number;
7
7
  wrap?: boolean;
8
8
  minOptionWidth?: string | number;
9
+ size?: 'small' | 'medium' | 'large';
10
+ disabled?: boolean;
11
+ required?: boolean;
12
+ reducedMotion?: boolean;
9
13
  onchange?: (value: OptionValue[]) => void;
10
14
  };
11
15
  declare const CheckboxGroup: import("svelte").Component<$$ComponentProps, {}, "value">;
@@ -115,7 +115,7 @@
115
115
  return styles.join('; ');
116
116
  });
117
117
 
118
- const dialogClasses = $derived(['dialog', scrollable && 'scrollable'].filter(Boolean).join(' '));
118
+ const dialogClasses = $derived([scrollable && 'scrollable'].filter(Boolean).join(' ')); // dialogクラス自体はcustomClassに含めない
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">
139
+ <div class="dialog {scrollable ? 'scrollable' : ''}">
140
140
  {#if header || title}
141
141
  <div class="dialog__header">
142
142
  {#if header}
@@ -166,11 +166,7 @@
166
166
  </div>
167
167
  </Modal>
168
168
 
169
- <style>:global(.dialog) {
170
- color: var(--svelte-ui-dialog-title-color);
171
- }
172
-
173
- .dialog {
169
+ <style>.dialog {
174
170
  display: flex;
175
171
  flex-direction: column;
176
172
  justify-content: stretch;
@@ -218,28 +214,15 @@
218
214
  border-bottom: 1px solid var(--svelte-ui-border-weak-color);
219
215
  }
220
216
 
221
- :global(.dialog.scrollable) .dialog__header {
217
+ :global(.scrollable) .dialog__header {
222
218
  margin-bottom: 0;
223
219
  border-bottom: solid var(--svelte-ui-border-width, 1px) var(--svelte-ui-border-weak-color);
224
220
  }
225
- :global(.dialog.scrollable) .dialog__body {
221
+ :global(.scrollable) .dialog__body {
226
222
  flex-shrink: 1;
227
223
  padding: var(--svelte-ui-dialog-body-padding);
228
224
  overflow: auto;
229
225
  }
230
- :global(.dialog.scrollable) .dialog__footer {
226
+ :global(.scrollable) .dialog__footer {
231
227
  border-top: solid var(--svelte-ui-border-width, 1px) var(--svelte-ui-border-weak-color);
232
- }
233
-
234
- /* Screen reader only content */
235
- :global(.sr-only) {
236
- position: absolute;
237
- width: 1px;
238
- height: 1px;
239
- padding: 0;
240
- margin: -1px;
241
- overflow: hidden;
242
- clip: rect(0, 0, 0, 0);
243
- white-space: nowrap;
244
- border: 0;
245
228
  }</style>
@@ -123,7 +123,9 @@
123
123
  });
124
124
 
125
125
  const drawerClasses = $derived(
126
- ['drawer', `drawer--${position}`, scrollable && 'drawer--scrollable'].filter(Boolean).join(' ')
126
+ ['drawer-wrapper', `drawer-wrapper--${position}`, scrollable && 'drawer-wrapper--scrollable']
127
+ .filter(Boolean)
128
+ .join(' ')
127
129
  );
128
130
 
129
131
  const ariaLabelledby = $derived(title ? 'drawer-title' : undefined);
@@ -176,7 +178,7 @@
176
178
  </Modal>
177
179
 
178
180
  <style>@charset "UTF-8";
179
- :global(.drawer) {
181
+ :global(.drawer-wrapper) {
180
182
  width: 100%;
181
183
  height: 100%;
182
184
  min-height: 100%;
@@ -186,7 +188,7 @@
186
188
  color: var(--svelte-ui-drawer-title-color);
187
189
  }
188
190
 
189
- :global(.drawer:-internal-dialog-in-top-layer) {
191
+ :global(.drawer-wrapper:-internal-dialog-in-top-layer) {
190
192
  max-height: none;
191
193
  max-width: none;
192
194
  width: 100%;
@@ -257,31 +259,31 @@
257
259
  transform: translateX(-50%);
258
260
  }
259
261
  }
260
- :global(.drawer--right.fade-in) {
262
+ :global(.drawer-wrapper--right.fade-in) {
261
263
  animation: fadeInFromRight var(--svelte-ui-transition-duration, 300ms) forwards;
262
264
  }
263
265
 
264
- :global(.drawer--right.fade-in::backdrop) {
266
+ :global(.drawer-wrapper--right.fade-in::backdrop) {
265
267
  animation: fadeIn var(--svelte-ui-transition-duration, 300ms) forwards;
266
268
  }
267
269
 
268
- :global(.drawer--left.fade-in) {
270
+ :global(.drawer-wrapper--left.fade-in) {
269
271
  animation: fadeInFromLeft var(--svelte-ui-transition-duration, 300ms) forwards;
270
272
  }
271
273
 
272
- :global(.drawer--left.fade-in::backdrop) {
274
+ :global(.drawer-wrapper--left.fade-in::backdrop) {
273
275
  animation: fadeIn var(--svelte-ui-transition-duration, 300ms) forwards;
274
276
  }
275
277
 
276
- :global(.drawer--left.fade-out) {
278
+ :global(.drawer-wrapper--left.fade-out) {
277
279
  animation: fadeOutToLeft var(--svelte-ui-transition-duration, 300ms) forwards;
278
280
  }
279
281
 
280
- :global(.drawer--right.fade-out) {
282
+ :global(.drawer-wrapper--right.fade-out) {
281
283
  animation: fadeOutToRight var(--svelte-ui-transition-duration, 300ms) forwards;
282
284
  }
283
285
 
284
- :global(.drawer.fade-out::backdrop) {
286
+ :global(.drawer-wrapper.fade-out::backdrop) {
285
287
  animation: fadeOut var(--svelte-ui-transition-duration, 300ms) forwards;
286
288
  }
287
289
 
@@ -356,28 +358,16 @@
356
358
 
357
359
  /* Reduced motion support */
358
360
  @media (prefers-reduced-motion: reduce) {
359
- :global(.drawer.fade-in),
360
- :global(.drawer.fade-in::backdrop),
361
- :global(.drawer.fade-out),
362
- :global(.drawer.fade-out::backdrop),
363
- :global(.drawer--left.fade-in),
364
- :global(.drawer--left.fade-in::backdrop),
365
- :global(.drawer--left.fade-out),
366
- :global(.drawer--right.fade-in),
367
- :global(.drawer--right.fade-in::backdrop),
368
- :global(.drawer--right.fade-out) {
361
+ :global(.drawer-wrapper.fade-in),
362
+ :global(.drawer-wrapper.fade-in::backdrop),
363
+ :global(.drawer-wrapper.fade-out),
364
+ :global(.drawer-wrapper.fade-out::backdrop),
365
+ :global(.drawer-wrapper--left.fade-in),
366
+ :global(.drawer-wrapper--left.fade-in::backdrop),
367
+ :global(.drawer-wrapper--left.fade-out),
368
+ :global(.drawer-wrapper--right.fade-in),
369
+ :global(.drawer-wrapper--right.fade-in::backdrop),
370
+ :global(.drawer-wrapper--right.fade-out) {
369
371
  animation-duration: 0.01s;
370
372
  }
371
- }
372
- /* Screen reader only content */
373
- :global(.sr-only) {
374
- position: absolute;
375
- width: 1px;
376
- height: 1px;
377
- padding: 0;
378
- margin: -1px;
379
- overflow: hidden;
380
- clip: rect(0, 0, 0, 0);
381
- white-space: nowrap;
382
- border: 0;
383
373
  }</style>
@@ -452,8 +452,12 @@
452
452
  justify-content: center;
453
453
  }
454
454
  .fab .fab__label {
455
+ display: block;
455
456
  white-space: nowrap;
456
457
  user-select: none;
458
+ text-align: center;
459
+ text-box-trim: trim-both;
460
+ text-box-edge: cap alphabetic;
457
461
  transition-property: opacity;
458
462
  transition-duration: var(--svelte-ui-transition-duration);
459
463
  }
@@ -230,6 +230,11 @@
230
230
  value = dataTransfer.files;
231
231
  onchange(value);
232
232
  }
233
+
234
+ // input要素をリセット
235
+ if (fileInputRef) {
236
+ fileInputRef.value = '';
237
+ }
233
238
  };
234
239
 
235
240
  export const reset = () => {
@@ -252,8 +257,8 @@
252
257
  class:file-uploader--hover={isHover}
253
258
  class:rounded
254
259
  style="
255
- --file-uploader-width: {widthStyle};
256
- --file-uploader-height: {height}px
260
+ --svelte-ui-file-uploader-width: {widthStyle};
261
+ --svelte-ui-file-uploader-height: {height}px
257
262
  "
258
263
  data-testid="file-uploader"
259
264
  onclick={handleClick}
@@ -365,8 +370,8 @@
365
370
  align-items: center;
366
371
  gap: 16px;
367
372
  position: relative;
368
- width: var(--file-uploader-width, 100%);
369
- height: var(--file-uploader-height);
373
+ width: var(--svelte-ui-file-uploader-width, 100%);
374
+ height: var(--svelte-ui-file-uploader-height);
370
375
  min-height: 100px;
371
376
  padding: 16px;
372
377
  background-color: var(--svelte-ui-file-uploader-bg);
@@ -111,11 +111,9 @@
111
111
 
112
112
  <style>
113
113
  .material-symbols-outlined,
114
- .material-symbols-filled,
115
114
  .material-symbols-rounded,
116
115
  .material-symbols-sharp {
117
116
  display: block;
118
- font-family: 'Material Symbols Outlined';
119
117
  font-size: inherit;
120
118
  color: inherit;
121
119
  line-height: inherit;
@@ -129,6 +127,18 @@
129
127
  transition-timing-function: ease;
130
128
  }
131
129
 
130
+ .material-symbols-outlined {
131
+ font-family: 'Material Symbols Outlined';
132
+ }
133
+
134
+ .material-symbols-rounded {
135
+ font-family: 'Material Symbols Rounded';
136
+ }
137
+
138
+ .material-symbols-sharp {
139
+ font-family: 'Material Symbols Sharp';
140
+ }
141
+
132
142
  /* font-variation-settings are controlled via inline styles for dynamic props */
133
143
 
134
144
  .icon-fallback-text {
@@ -47,12 +47,12 @@
47
47
  disabled = false,
48
48
  loading = false,
49
49
  pressed = false,
50
- reducedMotion = false,
51
50
 
52
51
  // ARIA/アクセシビリティ
53
52
  ariaLabel,
54
53
  ariaDescribedby,
55
54
  ariaPressed,
55
+ reducedMotion = false,
56
56
 
57
57
  // フォーカスイベント
58
58
  onfocus = () => {}, // No params for type inference
@@ -125,12 +125,12 @@
125
125
  disabled?: boolean;
126
126
  loading?: boolean;
127
127
  pressed?: boolean;
128
- reducedMotion?: boolean;
129
128
 
130
129
  // ARIA/アクセシビリティ
131
130
  ariaLabel: string;
132
131
  ariaDescribedby?: string;
133
132
  ariaPressed?: boolean;
133
+ reducedMotion?: boolean;
134
134
 
135
135
  // フォーカスイベント
136
136
  onfocus?: Function; // No params for type inference
@@ -26,10 +26,10 @@ type $$ComponentProps = {
26
26
  disabled?: boolean;
27
27
  loading?: boolean;
28
28
  pressed?: boolean;
29
- reducedMotion?: boolean;
30
29
  ariaLabel: string;
31
30
  ariaDescribedby?: string;
32
31
  ariaPressed?: boolean;
32
+ reducedMotion?: boolean;
33
33
  onfocus?: Function;
34
34
  onblur?: Function;
35
35
  onkeydown?: Function;
@@ -27,6 +27,7 @@
27
27
  width = '120px',
28
28
  height = '120px',
29
29
  rounded = false,
30
+ previewStyle = 'framed',
30
31
 
31
32
  // アイコン系
32
33
  icon = 'add_photo_alternate',
@@ -39,7 +40,7 @@
39
40
  removeFileAriaLabel = t('imageUploader.removeFile'),
40
41
 
41
42
  // 状態/動作
42
- adaptiveSize = false,
43
+ previewAdaptive = false,
43
44
 
44
45
  // 入力イベント
45
46
  onchange = () => {}, // No params for type inference
@@ -75,11 +76,11 @@
75
76
  accept?: string;
76
77
 
77
78
  // スタイル/レイアウト
78
-
79
79
  width?: string | number;
80
80
  height?: string | number;
81
81
  rounded?: boolean;
82
- adaptiveSize?: boolean;
82
+ previewStyle?: 'plain' | 'framed';
83
+ previewAdaptive?: boolean;
83
84
 
84
85
  // アイコン系
85
86
  icon?: string;
@@ -250,6 +251,11 @@
250
251
  value = dataTransfer.files;
251
252
  onchange(value);
252
253
  }
254
+
255
+ // input要素をリセット
256
+ if (fileInputRef) {
257
+ fileInputRef.value = '';
258
+ }
253
259
  };
254
260
 
255
261
  const removeFile = (index: number) => {
@@ -307,8 +313,9 @@
307
313
  {file}
308
314
  {width}
309
315
  {height}
310
- {adaptiveSize}
316
+ {previewAdaptive}
311
317
  {rounded}
318
+ {previewStyle}
312
319
  id={id ? `${id}-preview-${index}` : undefined}
313
320
  {removeFileAriaLabel}
314
321
  onRemove={() => removeFile(index)}
@@ -319,17 +326,19 @@
319
326
  class="image-uploader"
320
327
  class:image-uploader--multiple={multiple}
321
328
  class:image-uploader--rounded={rounded}
322
- class:image-uploader--adaptive={adaptiveSize}
329
+ class:image-uploader--adaptive={previewAdaptive}
323
330
  style="
324
- --image-uploader-button-width: {previewWidthStyle};
325
- --image-uploader-button-height: {previewHeightStyle};
331
+ --svelte-ui-image-uploader-button-width: {previewWidthStyle};
332
+ --svelte-ui-image-uploader-button-height: {previewHeightStyle};
326
333
  "
327
334
  data-testid="image-uploader"
328
335
  >
329
336
  {#if multiple}
330
- {#each value as file, index}
331
- {@render preview(file, index)}
332
- {/each}
337
+ {#if value}
338
+ {#each value as file, index}
339
+ {@render preview(file, index)}
340
+ {/each}
341
+ {/if}
333
342
  {/if}
334
343
  <button
335
344
  bind:this={dropAreaRef}
@@ -427,8 +436,8 @@
427
436
  align-items: center;
428
437
  position: relative;
429
438
  max-width: 100%;
430
- min-width: var(--image-uploader-button-width);
431
- min-height: var(--image-uploader-button-height);
439
+ min-width: var(--svelte-ui-image-uploader-button-width);
440
+ min-height: var(--svelte-ui-image-uploader-button-height);
432
441
  padding: 16px;
433
442
  background-color: var(--svelte-ui-form-bg);
434
443
  border-radius: var(--svelte-ui-border-radius);
@@ -9,7 +9,8 @@ type $$ComponentProps = {
9
9
  width?: string | number;
10
10
  height?: string | number;
11
11
  rounded?: boolean;
12
- adaptiveSize?: boolean;
12
+ previewStyle?: 'plain' | 'framed';
13
+ previewAdaptive?: boolean;
13
14
  icon?: string;
14
15
  iconSize?: number;
15
16
  iconFilled?: boolean;