@14ch/svelte-ui 0.0.13 → 0.0.15

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 (90) hide show
  1. package/dist/assets/styles/variables.scss +3 -7
  2. package/dist/components/Button.svelte +31 -5
  3. package/dist/components/Button.svelte.d.ts +5 -3
  4. package/dist/components/Checkbox.svelte +4 -4
  5. package/dist/components/Checkbox.svelte.d.ts +1 -1
  6. package/dist/components/CheckboxGroup.svelte +6 -3
  7. package/dist/components/CheckboxGroup.svelte.d.ts +1 -1
  8. package/dist/components/ColorPicker.svelte +18 -10
  9. package/dist/components/ColorPicker.svelte.d.ts +4 -4
  10. package/dist/components/Combobox.svelte +28 -8
  11. package/dist/components/Combobox.svelte.d.ts +1 -1
  12. package/dist/components/ConfirmDialog.svelte +3 -7
  13. package/dist/components/ConfirmDialog.svelte.d.ts +1 -1
  14. package/dist/components/Datepicker.svelte +88 -24
  15. package/dist/components/Datepicker.svelte.d.ts +4 -3
  16. package/dist/components/DatepickerCalendar.svelte +1 -1
  17. package/dist/components/DatepickerCalendar.svelte.d.ts +1 -1
  18. package/dist/components/Drawer.svelte +8 -4
  19. package/dist/components/Drawer.svelte.d.ts +1 -1
  20. package/dist/components/Fab.svelte +28 -11
  21. package/dist/components/Fab.svelte.d.ts +8 -4
  22. package/dist/components/FileUploader.svelte +1 -1
  23. package/dist/components/FileUploader.svelte.d.ts +1 -1
  24. package/dist/components/Icon.svelte +20 -24
  25. package/dist/components/Icon.svelte.d.ts +1 -1
  26. package/dist/components/IconButton.svelte +4 -3
  27. package/dist/components/IconButton.svelte.d.ts +4 -3
  28. package/dist/components/ImageUploader.svelte +1 -1
  29. package/dist/components/ImageUploader.svelte.d.ts +1 -1
  30. package/dist/components/Input.svelte +110 -99
  31. package/dist/components/Input.svelte.d.ts +5 -3
  32. package/dist/components/Popup.svelte +69 -82
  33. package/dist/components/Popup.svelte.d.ts +3 -3
  34. package/dist/components/PopupMenu.svelte +40 -56
  35. package/dist/components/PopupMenu.svelte.d.ts +3 -3
  36. package/dist/components/PopupMenuButton.svelte +10 -23
  37. package/dist/components/PopupMenuButton.svelte.d.ts +5 -4
  38. package/dist/components/Radio.svelte +3 -2
  39. package/dist/components/Radio.svelte.d.ts +1 -1
  40. package/dist/components/RadioGroup.svelte +1 -1
  41. package/dist/components/RadioGroup.svelte.d.ts +1 -1
  42. package/dist/components/SegmentedControl.svelte +4 -5
  43. package/dist/components/SegmentedControl.svelte.d.ts +1 -1
  44. package/dist/components/Select.svelte +2 -2
  45. package/dist/components/Select.svelte.d.ts +1 -1
  46. package/dist/components/Slider.svelte +2 -3
  47. package/dist/components/Slider.svelte.d.ts +1 -1
  48. package/dist/components/Snackbar.svelte +3 -2
  49. package/dist/components/Snackbar.svelte.d.ts +3 -2
  50. package/dist/components/SnackbarItem.svelte +4 -3
  51. package/dist/components/SnackbarItem.svelte.d.ts +4 -3
  52. package/dist/components/Switch.svelte +2 -4
  53. package/dist/components/Switch.svelte.d.ts +1 -1
  54. package/dist/components/Tab.svelte +1 -0
  55. package/dist/components/TabItem.svelte +24 -3
  56. package/dist/components/TabItem.svelte.d.ts +1 -0
  57. package/dist/components/Textarea.svelte +74 -38
  58. package/dist/components/Textarea.svelte.d.ts +4 -3
  59. package/dist/components/skeleton/SkeletonAvatar.svelte +22 -32
  60. package/dist/components/skeleton/SkeletonAvatar.svelte.d.ts +6 -2
  61. package/dist/components/skeleton/SkeletonButton.svelte +18 -16
  62. package/dist/components/skeleton/SkeletonButton.svelte.d.ts +5 -2
  63. package/dist/components/skeleton/SkeletonHeading.svelte +15 -18
  64. package/dist/components/skeleton/SkeletonHeading.svelte.d.ts +3 -2
  65. package/dist/components/skeleton/SkeletonMedia.svelte +29 -41
  66. package/dist/components/skeleton/SkeletonMedia.svelte.d.ts +8 -2
  67. package/dist/components/skeleton/SkeletonText.svelte +12 -14
  68. package/dist/components/skeleton/SkeletonText.svelte.d.ts +4 -2
  69. package/dist/i18n/index.d.ts +143 -6
  70. package/dist/i18n/index.js +18 -40
  71. package/dist/i18n/locales/de.d.ts +35 -0
  72. package/dist/i18n/locales/de.js +35 -0
  73. package/dist/i18n/locales/es.d.ts +35 -0
  74. package/dist/i18n/locales/es.js +35 -0
  75. package/dist/i18n/locales/fr.d.ts +35 -0
  76. package/dist/i18n/locales/fr.js +35 -0
  77. package/dist/i18n/locales/zh-cn.d.ts +35 -0
  78. package/dist/i18n/locales/zh-cn.js +35 -0
  79. package/dist/index.d.ts +5 -2
  80. package/dist/index.js +1 -0
  81. package/dist/types/menuItem.d.ts +1 -1
  82. package/dist/types/propOptions.d.ts +54 -0
  83. package/dist/types/propOptions.js +5 -0
  84. package/dist/utils/formatText.d.ts +2 -2
  85. package/dist/utils/formatText.js +2 -2
  86. package/dist/utils/popupManager.d.ts +26 -0
  87. package/dist/utils/popupManager.js +34 -0
  88. package/package.json +1 -1
  89. /package/dist/types/{eventHandlers.d.ts → callbackHandlers.d.ts} +0 -0
  90. /package/dist/types/{eventHandlers.js → callbackHandlers.js} +0 -0
@@ -11,6 +11,7 @@
11
11
  export type TabItemProps = {
12
12
  // 基本プロパティ
13
13
  tabItem: MenuItem;
14
+ pathPrefix?: string;
14
15
 
15
16
  // スタイル/レイアウト
16
17
  textColor: string;
@@ -31,6 +32,7 @@
31
32
  let {
32
33
  // 基本プロパティ
33
34
  tabItem,
35
+ pathPrefix = '',
34
36
 
35
37
  // スタイル/レイアウト
36
38
  textColor,
@@ -47,10 +49,29 @@
47
49
  // 状態/動作
48
50
  isSelected = false
49
51
  }: TabItemProps = $props();
52
+
53
+ // =========================================================================
54
+ // $derived
55
+ // =========================================================================
56
+
57
+ // pathPrefixを付与したhrefを計算
58
+ const hrefWithPrefix = $derived.by(() => {
59
+ if (!tabItem.href) return undefined;
60
+ if (!pathPrefix) return tabItem.href;
61
+
62
+ // 既にpathPrefixが含まれている場合はそのまま
63
+ // pathPrefixが完全一致、またはpathPrefix + '/'で始まる場合
64
+ if (tabItem.href === pathPrefix || tabItem.href.startsWith(`${pathPrefix}/`)) {
65
+ return tabItem.href;
66
+ }
67
+
68
+ // pathPrefixを付与
69
+ return `${pathPrefix}${tabItem.href.startsWith('/') ? '' : '/'}${tabItem.href}`;
70
+ });
50
71
  </script>
51
72
 
52
73
  <a
53
- href={tabItem.href}
74
+ href={hrefWithPrefix}
54
75
  class="tab-item"
55
76
  class:tab-item--selected={isSelected}
56
77
  style="--svelte-ui-tab-item-text-color: {textColor}; --svelte-ui-tab-item-selected-text-color: {selectedTextColor}; --svelte-ui-tab-item-selected-bar-color: {selectedBarColor}"
@@ -70,9 +91,9 @@
70
91
  >
71
92
  </div>
72
93
  {/if}
73
- {#if tabItem.title}
94
+ {#if tabItem.label}
74
95
  <div class="tab-item__label">
75
- {tabItem.title}
96
+ {tabItem.label}
76
97
  </div>
77
98
  {/if}
78
99
  </a>
@@ -2,6 +2,7 @@ import type { MenuItem } from '../types/menuItem';
2
2
  import type { IconVariant, IconWeight, IconGrade, IconOpticalSize } from '../types/icon';
3
3
  export type TabItemProps = {
4
4
  tabItem: MenuItem;
5
+ pathPrefix?: string;
5
6
  textColor: string;
6
7
  selectedTextColor: string;
7
8
  selectedBarColor: string;
@@ -12,9 +12,9 @@
12
12
  KeyboardHandler,
13
13
  MouseHandler,
14
14
  TouchHandler,
15
- PointerHandler,
16
- BivariantValueHandler
17
- } from '../types/eventHandlers';
15
+ PointerHandler
16
+ } from '../types/callbackHandlers';
17
+ import type { FocusStyle } from '../types/propOptions';
18
18
 
19
19
  // =========================================================================
20
20
  // Props, States & Constants
@@ -22,7 +22,7 @@
22
22
  export type TextareaProps = {
23
23
  // 基本プロパティ
24
24
  name?: string;
25
- value: string;
25
+ value: string | null | undefined;
26
26
  placeholder?: string;
27
27
 
28
28
  // HTML属性系
@@ -40,7 +40,7 @@
40
40
  minHeight?: string | number | null;
41
41
  maxHeight?: string | number | null;
42
42
  inline?: boolean;
43
- focusStyle?: 'background' | 'outline' | 'none';
43
+ focusStyle?: FocusStyle;
44
44
  fullWidth?: boolean;
45
45
  fullHeight?: boolean;
46
46
  width?: string | number | null;
@@ -180,6 +180,8 @@
180
180
  }: TextareaProps = $props();
181
181
 
182
182
  let ref: HTMLTextAreaElement | null = null;
183
+ let displayTextRef: HTMLDivElement | null = $state(null);
184
+ let linkTextRef: HTMLDivElement | null = $state(null);
183
185
  let isFocused: boolean = $state(false);
184
186
 
185
187
  // =========================================================================
@@ -330,6 +332,18 @@
330
332
  onpointercancel?.(event);
331
333
  };
332
334
 
335
+ // スクロール同期
336
+ const handleScroll = () => {
337
+ if (!ref) return;
338
+ const scrollTop = ref.scrollTop;
339
+ if (displayTextRef) {
340
+ displayTextRef.scrollTop = scrollTop;
341
+ }
342
+ if (linkify && linkTextRef) {
343
+ linkTextRef.scrollTop = scrollTop;
344
+ }
345
+ };
346
+
333
347
  // =========================================================================
334
348
  // $derived
335
349
  // =========================================================================
@@ -339,13 +353,14 @@
339
353
 
340
354
  // HTML表示用の値(autoResize時の高さ調整用)
341
355
  const htmlValue = $derived.by(() => {
342
- if (value !== '') {
343
- const converted = convertToHtml(value);
344
- let html = typeof converted === 'string' ? converted : String(converted ?? '');
356
+ const normalizedValue = value ?? '';
357
+ if (normalizedValue !== '') {
358
+ const converted = convertToHtml(normalizedValue);
359
+ const html = String(converted ?? '');
345
360
  // 最後の行が空だったら空白を追加(高さ調整のため)
346
361
  const lines = html.split('<br />');
347
362
  if (lines.length > 0 && lines[lines.length - 1] === '') {
348
- html += '&nbsp;';
363
+ return html + '&nbsp;';
349
364
  }
350
365
  return html;
351
366
  } else {
@@ -360,11 +375,12 @@
360
375
 
361
376
  // URLをリンク化した表示用HTML(クリック検出用オーバーレイで使用)
362
377
  const linkHtmlValue = $derived.by(() => {
363
- if (!linkify || value === '') {
378
+ const normalizedValue = value ?? '';
379
+ if (!linkify || normalizedValue === '') {
364
380
  return '';
365
381
  }
366
- const result = convertToHtmlWithLink(value);
367
- return typeof result === 'string' ? result : String(result ?? '');
382
+ const result = convertToHtmlWithLink(normalizedValue);
383
+ return String(result ?? '');
368
384
  });
369
385
  </script>
370
386
 
@@ -386,13 +402,14 @@
386
402
  >
387
403
  <!-- autoResize時の表示用要素(HTMLレンダリングで高さ調整) -->
388
404
  <div
405
+ bind:this={displayTextRef}
389
406
  class="textarea__display-text"
390
407
  data-placeholder={placeholder}
391
- style="min-height: {minHeightStyle}; {customStyle}"
408
+ style="min-height: {minHeightStyle}; max-height: {maxHeightStyle}; {customStyle}"
392
409
  >
393
410
  {@html htmlValue}
394
411
  </div>
395
- <div class="textarea__input">
412
+ <div class="textarea__wrapper">
396
413
  <textarea
397
414
  {id}
398
415
  {name}
@@ -436,32 +453,37 @@
436
453
  onpointerleave={handlePointerLeave}
437
454
  onpointermove={handlePointerMove}
438
455
  onpointercancel={handlePointerCancel}
456
+ onscroll={handleScroll}
439
457
  {...textareaAttributes}
440
458
  {...restProps}
441
459
  ></textarea>
442
- <!-- クリアボタン -->
443
- {#if clearable && !disabled && !readonly}
444
- <div class="textarea__clear-button">
445
- <IconButton
446
- ariaLabel={clearButtonAriaLabel}
447
- color="var(--svelte-ui-textarea-text-color)"
448
- onclick={(event) => {
449
- event.stopPropagation();
450
- clear();
451
- }}
452
- tabindex={-1}
453
- iconFilled={true}
454
- {iconVariant}
455
- fontSize={18}>cancel</IconButton
456
- >
457
- </div>
458
- {/if}
459
460
  </div>
460
461
  {#if linkify}
461
- <div class="textarea__link-text" style="min-height: {minHeightStyle}; {customStyle}">
462
+ <div
463
+ bind:this={linkTextRef}
464
+ class="textarea__link-text"
465
+ style="min-height: {minHeightStyle}; max-height: {maxHeightStyle}; {customStyle}"
466
+ >
462
467
  {@html linkHtmlValue}
463
468
  </div>
464
469
  {/if}
470
+ <!-- クリアボタン -->
471
+ {#if clearable && !disabled && !readonly}
472
+ <div class="textarea__clear-button">
473
+ <IconButton
474
+ ariaLabel={clearButtonAriaLabel}
475
+ color="var(--svelte-ui-text-color)"
476
+ onclick={(event) => {
477
+ event.stopPropagation();
478
+ clear();
479
+ }}
480
+ tabindex={-1}
481
+ iconFilled={true}
482
+ {iconVariant}
483
+ fontSize={18}>cancel</IconButton
484
+ >
485
+ </div>
486
+ {/if}
465
487
  </div>
466
488
 
467
489
  <style>
@@ -479,7 +501,7 @@
479
501
  }
480
502
  }
481
503
 
482
- .textarea__input {
504
+ .textarea__wrapper {
483
505
  position: absolute;
484
506
  top: 0;
485
507
  left: 0;
@@ -512,6 +534,14 @@
512
534
  opacity: 1;
513
535
  transition: none;
514
536
  cursor: text !important;
537
+ overflow-y: auto;
538
+ overflow-x: hidden;
539
+ scrollbar-width: none; /* Firefox */
540
+ -ms-overflow-style: none; /* IE and Edge */
541
+
542
+ &::-webkit-scrollbar {
543
+ display: none; /* Chrome, Safari, Opera */
544
+ }
515
545
 
516
546
  &::before {
517
547
  content: '';
@@ -600,7 +630,8 @@
600
630
  * ============================================= */
601
631
  .textarea--clearable {
602
632
  textarea,
603
- .textarea__display-text {
633
+ .textarea__display-text,
634
+ .textarea__link-text {
604
635
  padding-right: var(--svelte-ui-textarea-icon-space);
605
636
  }
606
637
  }
@@ -686,9 +717,13 @@
686
717
  opacity: 0;
687
718
  }
688
719
 
689
- /* フォーカス時はリンク用オーバーレイも非表示にして(display:none)、リンクが反応しないようにする */
720
+ /* フォーカス時はリンク用オーバーレイも非表示(opacity: 0)にして、リンクが反応しないようにする */
690
721
  .textarea--focused .textarea__link-text {
691
- display: none;
722
+ opacity: 0;
723
+ }
724
+
725
+ .textarea--focused .textarea__link-text :global(a) {
726
+ pointer-events: none;
692
727
  }
693
728
 
694
729
  /* =============================================
@@ -708,11 +743,12 @@
708
743
  box-shadow: 0 0 0 var(--svelte-ui-border-width) inset var(--svelte-ui-textarea-border-color);
709
744
  border: none;
710
745
  border-radius: var(--svelte-ui-textarea-border-radius);
711
- color: var(--svelte-ui-textarea-text-color);
712
746
  }
713
747
 
714
748
  &.textarea--clearable {
715
- textarea {
749
+ textarea,
750
+ .textarea__display-text,
751
+ .textarea__link-text {
716
752
  padding-right: var(--svelte-ui-textarea-icon-space);
717
753
  }
718
754
  }
@@ -1,9 +1,10 @@
1
1
  import type { HTMLTextareaAttributes } from 'svelte/elements';
2
2
  import type { IconVariant } from '../types/icon';
3
- import type { FocusHandler, KeyboardHandler, MouseHandler, TouchHandler, PointerHandler } from '../types/eventHandlers';
3
+ import type { FocusHandler, KeyboardHandler, MouseHandler, TouchHandler, PointerHandler } from '../types/callbackHandlers';
4
+ import type { FocusStyle } from '../types/propOptions';
4
5
  export type TextareaProps = {
5
6
  name?: string;
6
- value: string;
7
+ value: string | null | undefined;
7
8
  placeholder?: string;
8
9
  id?: string | null;
9
10
  tabindex?: number | null;
@@ -17,7 +18,7 @@ export type TextareaProps = {
17
18
  minHeight?: string | number | null;
18
19
  maxHeight?: string | number | null;
19
20
  inline?: boolean;
20
- focusStyle?: 'background' | 'outline' | 'none';
21
+ focusStyle?: FocusStyle;
21
22
  fullWidth?: boolean;
22
23
  fullHeight?: boolean;
23
24
  width?: string | number | null;
@@ -4,7 +4,6 @@
4
4
  import SkeletonBox from './SkeletonBox.svelte';
5
5
  import SkeletonText from './SkeletonText.svelte';
6
6
  import { getStyleFromNumber } from '../../utils/style';
7
- import type { SkeletonAvatarConfig } from '../../types/skeleton';
8
7
  import {
9
8
  DEFAULT_AVATAR_IMAGE_CONFIG,
10
9
  DEFAULT_TEXT_CONFIG_AVATAR,
@@ -15,37 +14,35 @@
15
14
  // Props, States & Constants
16
15
  // =========================================================================
17
16
  export type SkeletonAvatarProps = {
18
- avatarConfig?: Partial<SkeletonAvatarConfig>;
17
+ avatarImageSize?: string | number;
18
+ avatarImageRadius?: string | number;
19
+ textWidth?: string | number;
20
+ lines?: number;
21
+ fontSize?: string | number;
22
+ showName?: boolean;
19
23
  animated?: boolean;
20
24
  };
21
25
 
22
26
  let {
23
- // 基本プロパティ
24
- avatarConfig = {},
27
+ avatarImageSize = DEFAULT_AVATAR_IMAGE_CONFIG.size,
28
+ avatarImageRadius = DEFAULT_AVATAR_IMAGE_CONFIG.radius,
29
+ textWidth = DEFAULT_TEXT_CONFIG_AVATAR.width,
30
+ lines = DEFAULT_TEXT_CONFIG_AVATAR.lines,
31
+ fontSize,
32
+ showName = DEFAULT_AVATAR_CONFIG.showName,
25
33
  animated = true
26
34
  }: SkeletonAvatarProps = $props();
27
35
 
28
36
  // =========================================================================
29
37
  // $derived
30
38
  // =========================================================================
31
- // マージされた設定
32
- const mergedAvatarImageConfig = $derived({
33
- ...DEFAULT_AVATAR_IMAGE_CONFIG,
34
- ...(avatarConfig.avatarImageConfig || {})
35
- });
36
-
37
- const mergedTextConfig = $derived({
38
- ...DEFAULT_TEXT_CONFIG_AVATAR,
39
- ...(avatarConfig.textConfig || {})
40
- });
41
-
42
- const mergedAvatarConfig = $derived({
43
- ...DEFAULT_AVATAR_CONFIG,
44
- ...avatarConfig
45
- });
46
-
47
- const avatarImageSizeStyle = $derived(getStyleFromNumber(mergedAvatarImageConfig.size));
48
- const nameWidthStyle = $derived(getStyleFromNumber(mergedTextConfig.width));
39
+ const avatarImageSizeStyle = $derived(getStyleFromNumber(avatarImageSize));
40
+ const avatarImageRadiusStyle = $derived(
41
+ avatarImageRadius
42
+ ? getStyleFromNumber(avatarImageRadius)
43
+ : 'var(--svelte-ui-skeleton-avatar-image-border-radius)'
44
+ );
45
+ const textWidthStyle = $derived(getStyleFromNumber(textWidth));
49
46
  </script>
50
47
 
51
48
  <div class="skeleton-avatar">
@@ -53,20 +50,13 @@
53
50
  <SkeletonBox
54
51
  width={avatarImageSizeStyle}
55
52
  height={avatarImageSizeStyle}
56
- radius="var(--svelte-ui-skeleton-avatar-image-border-radius)"
53
+ radius={avatarImageRadiusStyle}
57
54
  {animated}
58
- customStyle={mergedAvatarImageConfig.customStyle}
59
55
  />
60
56
  </div>
61
- {#if mergedAvatarConfig.showName}
57
+ {#if showName}
62
58
  <div class="skeleton-avatar__text">
63
- <SkeletonText
64
- textConfig={{
65
- width: nameWidthStyle,
66
- lines: mergedTextConfig.lines
67
- }}
68
- {animated}
69
- />
59
+ <SkeletonText width={textWidthStyle} {lines} {fontSize} {animated} />
70
60
  </div>
71
61
  {/if}
72
62
  </div>
@@ -1,6 +1,10 @@
1
- import type { SkeletonAvatarConfig } from '../../types/skeleton';
2
1
  export type SkeletonAvatarProps = {
3
- avatarConfig?: Partial<SkeletonAvatarConfig>;
2
+ avatarImageSize?: string | number;
3
+ avatarImageRadius?: string | number;
4
+ textWidth?: string | number;
5
+ lines?: number;
6
+ fontSize?: string | number;
7
+ showName?: boolean;
4
8
  animated?: boolean;
5
9
  };
6
10
  declare const SkeletonAvatar: import("svelte").Component<SkeletonAvatarProps, {}, "">;
@@ -3,38 +3,40 @@
3
3
  <script lang="ts">
4
4
  import SkeletonBox from './SkeletonBox.svelte';
5
5
  import { getStyleFromNumber } from '../../utils/style';
6
- import type { SkeletonButtonConfig } from '../../types/skeleton';
7
6
  import { DEFAULT_BUTTON_CONFIG } from '../../constants/skeleton';
8
7
 
9
8
  // =========================================================================
10
9
  // Props, States & Constants
11
10
  // =========================================================================
12
11
  export type SkeletonButtonProps = {
13
- buttonConfig?: Partial<SkeletonButtonConfig>;
12
+ width?: string | number;
13
+ height?: string | number;
14
+ radius?: string | number;
15
+ align?: 'left' | 'center' | 'right';
16
+ customStyle?: string;
14
17
  animated?: boolean;
15
18
  };
16
19
 
17
- let { buttonConfig = {}, animated = true }: SkeletonButtonProps = $props();
20
+ let {
21
+ width = DEFAULT_BUTTON_CONFIG.width,
22
+ height = DEFAULT_BUTTON_CONFIG.height,
23
+ radius = DEFAULT_BUTTON_CONFIG.radius,
24
+ align = DEFAULT_BUTTON_CONFIG.align,
25
+ customStyle = DEFAULT_BUTTON_CONFIG.customStyle,
26
+ animated = true
27
+ }: SkeletonButtonProps = $props();
18
28
 
19
29
  // =========================================================================
20
30
  // $derived
21
31
  // =========================================================================
22
- // マージされた設定
23
- const mergedButtonConfig = $derived({
24
- ...DEFAULT_BUTTON_CONFIG,
25
- ...buttonConfig
26
- });
27
-
28
- const widthStyle = $derived(getStyleFromNumber(mergedButtonConfig.width));
29
- const heightStyle = $derived(getStyleFromNumber(mergedButtonConfig.height));
32
+ const widthStyle = $derived(getStyleFromNumber(width));
33
+ const heightStyle = $derived(getStyleFromNumber(height));
30
34
  const radiusStyle = $derived(
31
- typeof mergedButtonConfig.radius === 'number'
32
- ? `${mergedButtonConfig.radius}px`
33
- : mergedButtonConfig.radius
35
+ typeof radius === 'number' ? `${radius}px` : radius
34
36
  );
35
37
 
36
38
  // alignに応じたCSSクラスを生成
37
- const alignClass = $derived(`skeleton-button--align-${mergedButtonConfig.align}`);
39
+ const alignClass = $derived(`skeleton-button--align-${align}`);
38
40
  </script>
39
41
 
40
42
  <div class="skeleton-button {alignClass}">
@@ -43,7 +45,7 @@
43
45
  height={heightStyle}
44
46
  radius={radiusStyle}
45
47
  {animated}
46
- customStyle={mergedButtonConfig.customStyle}
48
+ {customStyle}
47
49
  />
48
50
  </div>
49
51
 
@@ -1,6 +1,9 @@
1
- import type { SkeletonButtonConfig } from '../../types/skeleton';
2
1
  export type SkeletonButtonProps = {
3
- buttonConfig?: Partial<SkeletonButtonConfig>;
2
+ width?: string | number;
3
+ height?: string | number;
4
+ radius?: string | number;
5
+ align?: 'left' | 'center' | 'right';
6
+ customStyle?: string;
4
7
  animated?: boolean;
5
8
  };
6
9
  declare const SkeletonButton: import("svelte").Component<SkeletonButtonProps, {}, "">;
@@ -3,41 +3,38 @@
3
3
  <script lang="ts">
4
4
  import SkeletonText from './SkeletonText.svelte';
5
5
  import { getStyleFromNumber } from '../../utils/style';
6
- import type { SkeletonHeadingConfig } from '../../types/skeleton';
7
6
  import { DEFAULT_HEADING_CONFIG } from '../../constants/skeleton';
8
7
 
9
8
  // =========================================================================
10
9
  // Props, States & Constants
11
10
  // =========================================================================
12
11
  export type SkeletonHeadingProps = {
13
- headingConfig?: Partial<SkeletonHeadingConfig>;
12
+ width?: string | number;
13
+ fontSize?: string | number;
14
+ customStyle?: string;
14
15
  animated?: boolean;
15
16
  };
16
17
 
17
- let { headingConfig = {}, animated = true }: SkeletonHeadingProps = $props();
18
+ let {
19
+ width = DEFAULT_HEADING_CONFIG.width,
20
+ fontSize = DEFAULT_HEADING_CONFIG.fontSize,
21
+ customStyle = DEFAULT_HEADING_CONFIG.customStyle,
22
+ animated = true
23
+ }: SkeletonHeadingProps = $props();
18
24
 
19
25
  // =========================================================================
20
26
  // $derived
21
27
  // =========================================================================
22
- // マージされた設定
23
- const mergedHeadingConfig = $derived({
24
- ...DEFAULT_HEADING_CONFIG,
25
- ...headingConfig
26
- });
27
-
28
- const widthStyle = $derived(getStyleFromNumber(mergedHeadingConfig.width));
28
+ const widthStyle = $derived(getStyleFromNumber(width));
29
29
  const fontSizeStyle = $derived(
30
- mergedHeadingConfig.fontSize
31
- ? typeof mergedHeadingConfig.fontSize === 'string' &&
32
- mergedHeadingConfig.fontSize.startsWith('var(')
33
- ? mergedHeadingConfig.fontSize
34
- : getStyleFromNumber(mergedHeadingConfig.fontSize)
35
- : DEFAULT_HEADING_CONFIG.fontSize
30
+ typeof fontSize === 'string' && fontSize.startsWith('var(')
31
+ ? fontSize
32
+ : getStyleFromNumber(fontSize)
36
33
  );
37
34
  </script>
38
35
 
39
- <div class="skeleton-heading" style="font-size: {fontSizeStyle}; {mergedHeadingConfig.customStyle}">
40
- <SkeletonText textConfig={{ width: widthStyle }} {animated} />
36
+ <div class="skeleton-heading" style="font-size: {fontSizeStyle}; {customStyle}">
37
+ <SkeletonText width={widthStyle} {animated} />
41
38
  </div>
42
39
 
43
40
  <style>.skeleton-heading {
@@ -1,6 +1,7 @@
1
- import type { SkeletonHeadingConfig } from '../../types/skeleton';
2
1
  export type SkeletonHeadingProps = {
3
- headingConfig?: Partial<SkeletonHeadingConfig>;
2
+ width?: string | number;
3
+ fontSize?: string | number;
4
+ customStyle?: string;
4
5
  animated?: boolean;
5
6
  };
6
7
  declare const SkeletonHeading: import("svelte").Component<SkeletonHeadingProps, {}, "">;
@@ -4,7 +4,6 @@
4
4
  import SkeletonBox from './SkeletonBox.svelte';
5
5
  import SkeletonText from './SkeletonText.svelte';
6
6
  import { getStyleFromNumber } from '../../utils/style';
7
- import type { SkeletonMediaConfig } from '../../types/skeleton';
8
7
  import {
9
8
  DEFAULT_MEDIA_CONFIG,
10
9
  DEFAULT_THUMBNAIL_CONFIG,
@@ -16,47 +15,44 @@
16
15
  // =========================================================================
17
16
  export type SkeletonMediaProps = {
18
17
  width?: string | number;
19
- mediaConfig?: Partial<SkeletonMediaConfig>;
18
+ layout?: 'horizontal' | 'vertical';
19
+ textWidth?: string | number;
20
+ lines?: number;
21
+ fontSize?: string | number;
22
+ thumbnailWidth?: string | number;
23
+ thumbnailHeight?: string | number;
24
+ thumbnailAspectRatio?: string | number;
25
+ thumbnailRadius?: string | number;
20
26
  animated?: boolean;
21
27
  };
22
28
 
23
- let { width = '100%', mediaConfig = {}, animated = true }: SkeletonMediaProps = $props();
29
+ let {
30
+ width = '100%',
31
+ layout = DEFAULT_MEDIA_CONFIG.layout,
32
+ textWidth = DEFAULT_TEXT_CONFIG_MEDIA.width,
33
+ lines = DEFAULT_TEXT_CONFIG_MEDIA.lines,
34
+ fontSize,
35
+ thumbnailWidth = DEFAULT_THUMBNAIL_CONFIG.width,
36
+ thumbnailHeight,
37
+ thumbnailAspectRatio,
38
+ thumbnailRadius = DEFAULT_THUMBNAIL_CONFIG.radius,
39
+ animated = true
40
+ }: SkeletonMediaProps = $props();
24
41
 
25
42
  // =========================================================================
26
43
  // $derived
27
44
  // =========================================================================
28
- // マージされた設定
29
- const mergedMediaConfig = $derived({
30
- ...DEFAULT_MEDIA_CONFIG,
31
- ...mediaConfig
32
- });
33
-
34
- // レイアウト方向を取得
35
- const layoutDirection = $derived(mergedMediaConfig.layout || 'horizontal');
36
-
37
- // マージされた設定
38
- const mergedThumbnailConfig = $derived({
39
- ...DEFAULT_THUMBNAIL_CONFIG,
40
- ...(mergedMediaConfig.thumbnailConfig || {})
41
- });
42
-
43
- const mergedTextConfig = $derived({
44
- ...DEFAULT_TEXT_CONFIG_MEDIA,
45
- ...(mergedMediaConfig.textConfig || {})
46
- });
45
+ const layoutDirection = $derived(layout || 'horizontal');
47
46
 
48
47
  const widthStyle = $derived(getStyleFromNumber(width));
49
- const thumbnailWidthStyle = $derived(getStyleFromNumber(mergedThumbnailConfig.width));
50
- const thumbnailHeightStyle = $derived(
51
- mergedThumbnailConfig.height ? getStyleFromNumber(mergedThumbnailConfig.height) : ''
52
- );
53
- const textWidthStyle = $derived(getStyleFromNumber(mergedTextConfig.width));
48
+ const thumbnailWidthStyle = $derived(getStyleFromNumber(thumbnailWidth));
49
+ const thumbnailHeightStyle = $derived(thumbnailHeight ? getStyleFromNumber(thumbnailHeight) : '');
50
+ const textWidthStyle = $derived(getStyleFromNumber(textWidth));
54
51
 
55
52
  // heightとaspectRatioの優先順位を制御
56
- const finalThumbnailHeight = $derived(mergedThumbnailConfig.height ? thumbnailHeightStyle : '');
57
- const finalThumbnailAspectRatio = $derived(
58
- mergedThumbnailConfig.height ? undefined : mergedThumbnailConfig.aspectRatio
59
- );
53
+ const finalThumbnailHeight = $derived(thumbnailHeight ? thumbnailHeightStyle : '');
54
+ const finalThumbnailAspectRatio = $derived(thumbnailHeight ? undefined : thumbnailAspectRatio);
55
+ const thumbnailRadiusStyle = $derived(thumbnailRadius ? getStyleFromNumber(thumbnailRadius) : '');
60
56
  </script>
61
57
 
62
58
  <div
@@ -68,18 +64,10 @@
68
64
  width={thumbnailWidthStyle}
69
65
  {...finalThumbnailHeight && { height: finalThumbnailHeight }}
70
66
  aspectRatio={finalThumbnailAspectRatio}
71
- radius={mergedThumbnailConfig.radius}
72
- {animated}
73
- customStyle={mergedThumbnailConfig.customStyle}
74
- />
75
- <SkeletonText
76
- textConfig={{
77
- width: textWidthStyle,
78
- lines: mergedTextConfig.lines,
79
- fontSize: mergedTextConfig.fontSize
80
- }}
67
+ radius={thumbnailRadiusStyle}
81
68
  {animated}
82
69
  />
70
+ <SkeletonText width={textWidthStyle} {lines} {fontSize} {animated} />
83
71
  </div>
84
72
 
85
73
  <style>