@14ch/svelte-ui 0.0.41 → 0.0.43

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 (51) hide show
  1. package/dist/assets/styles/import.css +900 -0
  2. package/dist/assets/styles/variables.scss +5 -0
  3. package/dist/components/Checkbox.svelte +12 -8
  4. package/dist/components/Checkbox.svelte.d.ts +8 -5
  5. package/dist/components/CheckboxGroup.svelte +5 -6
  6. package/dist/components/CheckboxGroup.svelte.d.ts +2 -1
  7. package/dist/components/ColorPicker.svelte +4 -3
  8. package/dist/components/ColorPicker.svelte.d.ts +3 -3
  9. package/dist/components/Combobox.svelte +4 -3
  10. package/dist/components/Datepicker.svelte +2 -1
  11. package/dist/components/Dialog.svelte +1 -1
  12. package/dist/components/Drawer.svelte +1 -1
  13. package/dist/components/FileUploader.svelte +2 -8
  14. package/dist/components/ImageUploader.svelte +2 -8
  15. package/dist/components/ImageUploaderPreview.svelte +1 -0
  16. package/dist/components/Input.svelte +8 -2
  17. package/dist/components/Input.svelte.d.ts +2 -0
  18. package/dist/components/LoadingSpinner.svelte +3 -3
  19. package/dist/components/Modal.svelte +7 -7
  20. package/dist/components/Modal.svelte.d.ts +1 -1
  21. package/dist/components/MultiSelect.svelte +2 -2
  22. package/dist/components/Nav.svelte +15 -0
  23. package/dist/components/Nav.svelte.d.ts +6 -0
  24. package/dist/components/NavItem.svelte +22 -4
  25. package/dist/components/NavItem.svelte.d.ts +6 -0
  26. package/dist/components/Pagination.svelte +3 -2
  27. package/dist/components/Pagination.svelte.d.ts +2 -1
  28. package/dist/components/Popup.svelte +1 -0
  29. package/dist/components/PopupMenu.svelte +1 -0
  30. package/dist/components/PopupMenuButton.svelte +6 -6
  31. package/dist/components/PopupMenuButton.svelte.d.ts +1 -1
  32. package/dist/components/Radio.svelte +9 -4
  33. package/dist/components/Radio.svelte.d.ts +6 -3
  34. package/dist/components/RadioGroup.svelte +5 -6
  35. package/dist/components/RadioGroup.svelte.d.ts +2 -1
  36. package/dist/components/SegmentedControl.svelte +5 -3
  37. package/dist/components/SegmentedControl.svelte.d.ts +4 -3
  38. package/dist/components/Select.svelte +0 -1
  39. package/dist/components/Slider.svelte +4 -3
  40. package/dist/components/Slider.svelte.d.ts +3 -3
  41. package/dist/components/SnackbarItem.svelte +3 -3
  42. package/dist/components/Switch.svelte +12 -6
  43. package/dist/components/Switch.svelte.d.ts +7 -4
  44. package/dist/components/Tab.svelte +4 -7
  45. package/dist/components/Textarea.svelte +23 -18
  46. package/dist/components/Textarea.svelte.d.ts +5 -3
  47. package/dist/index.d.ts +4 -1
  48. package/dist/index.js +3 -0
  49. package/dist/types/propOptions.d.ts +7 -2
  50. package/dist/utils/formatText.js +1 -1
  51. package/package.json +3 -3
@@ -4,6 +4,7 @@
4
4
  import Icon from './Icon.svelte';
5
5
  import { announceToScreenReader } from '../utils/accessibility';
6
6
  import { t } from '../i18n';
7
+ import type { BivariantValueHandler } from '../types/callbackHandlers';
7
8
 
8
9
  // =========================================================================
9
10
  // Props, States & Constants
@@ -31,7 +32,7 @@
31
32
  showTotal?: boolean;
32
33
 
33
34
  // イベントハンドラー
34
- onchange: (pageNum: number) => void;
35
+ onchange?: BivariantValueHandler<number>;
35
36
  };
36
37
 
37
38
  let {
@@ -151,7 +152,7 @@
151
152
  });
152
153
  </script>
153
154
 
154
- <div class="pagination" {id}>
155
+ <div class="pagination" {id} data-testid="pagination">
155
156
  {#if showCount && rangeText}
156
157
  <div class="pagination__count">{rangeText}</div>
157
158
  {/if}
@@ -1,3 +1,4 @@
1
+ import type { BivariantValueHandler } from '../types/callbackHandlers';
1
2
  export type PaginationProps = {
2
3
  /** Total number of items. */
3
4
  total: number;
@@ -14,7 +15,7 @@ export type PaginationProps = {
14
15
  showRange?: boolean;
15
16
  /** Shows total count. @default true */
16
17
  showTotal?: boolean;
17
- onchange: (pageNum: number) => void;
18
+ onchange?: BivariantValueHandler<number>;
18
19
  };
19
20
  declare const Pagination: import("svelte").Component<PaginationProps, {}, "">;
20
21
  type Pagination = ReturnType<typeof Pagination>;
@@ -551,6 +551,7 @@
551
551
  aria-describedby={ariaDescribedby}
552
552
  aria-modal={undefined}
553
553
  id={popupId}
554
+ data-testid="popup"
554
555
  use:clickOutside={() => {
555
556
  close('outside');
556
557
  }}
@@ -250,6 +250,7 @@
250
250
  aria-activedescendant={activeIndex >= 0 ? getMenuItemId(activeIndex) : undefined}
251
251
  tabindex="-1"
252
252
  {id}
253
+ data-testid="popup-menu"
253
254
  onclick={cancelParentEvent}
254
255
  onkeydown={handleKeyDown}
255
256
  >
@@ -47,6 +47,9 @@
47
47
  /** Stops click event propagation to parent elements. @default false */
48
48
  cancelParentClick?: boolean;
49
49
 
50
+ // ARIA/アクセシビリティ
51
+ ariaLabel?: string;
52
+
50
53
  // フォーカスイベント
51
54
  onfocus?: FocusHandler;
52
55
  onblur?: FocusHandler;
@@ -79,9 +82,6 @@
79
82
  onpointerleave?: PointerHandler;
80
83
  onpointermove?: PointerHandler;
81
84
  onpointercancel?: PointerHandler;
82
-
83
- // ARIA/アクセシビリティ
84
- ariaLabel?: string;
85
85
  };
86
86
 
87
87
  let {
@@ -106,6 +106,9 @@
106
106
  mobileFullscreen = true,
107
107
  cancelParentClick = false,
108
108
 
109
+ // ARIA/アクセシビリティ
110
+ ariaLabel,
111
+
109
112
  // フォーカスイベント
110
113
  onfocus = () => {}, // No params for type inference
111
114
  onblur = () => {}, // No params for type inference
@@ -138,9 +141,6 @@
138
141
  onpointerleave = () => {}, // No params for type inference
139
142
  onpointermove = () => {}, // No params for type inference
140
143
  onpointercancel = () => {}, // No params for type inference
141
-
142
- // ARIA/アクセシビリティ
143
- ariaLabel
144
144
  }: PopupMenuButtonProps = $props();
145
145
 
146
146
  let anchorRef: HTMLElement | undefined = $state();
@@ -21,6 +21,7 @@ export type PopupMenuButtonProps = {
21
21
  mobileFullscreen?: boolean;
22
22
  /** Stops click event propagation to parent elements. @default false */
23
23
  cancelParentClick?: boolean;
24
+ ariaLabel?: string;
24
25
  onfocus?: FocusHandler;
25
26
  onblur?: FocusHandler;
26
27
  onkeydown?: KeyboardHandler;
@@ -44,7 +45,6 @@ export type PopupMenuButtonProps = {
44
45
  onpointerleave?: PointerHandler;
45
46
  onpointermove?: PointerHandler;
46
47
  onpointercancel?: PointerHandler;
47
- ariaLabel?: string;
48
48
  };
49
49
  declare const PopupMenuButton: import("svelte").Component<PopupMenuButtonProps, {}, "">;
50
50
  type PopupMenuButton = ReturnType<typeof PopupMenuButton>;
@@ -11,6 +11,7 @@
11
11
  BivariantValueHandler
12
12
  } from '../types/callbackHandlers';
13
13
  import type { OptionValue } from '../types/options';
14
+ import type { ComponentSize } from '../types/propOptions';
14
15
 
15
16
  // =========================================================================
16
17
  // Props, States & Constants
@@ -33,17 +34,19 @@
33
34
 
34
35
  // スタイル/レイアウト
35
36
  /** Radio button size. @default 'medium' */
36
- size?: 'small' | 'medium' | 'large';
37
+ size?: ComponentSize;
37
38
  customStyle?: string;
39
+ /** Stretches the radio to fill its container width. @default false */
40
+ fullWidth?: boolean;
38
41
 
39
42
  // 状態/動作
40
43
  /** Disables this radio button. @default false */
41
44
  disabled?: boolean;
42
- /** Stretches the radio to fill its container width. @default false */
43
- fullWidth?: boolean;
44
45
  required?: boolean;
45
46
 
46
47
  // ARIA/アクセシビリティ
48
+ /** Accessible label, used when no visible label (children) is provided. */
49
+ ariaLabel?: string;
47
50
  /** Disables animations for users who prefer reduced motion. @default false */
48
51
  reducedMotion?: boolean;
49
52
 
@@ -102,13 +105,14 @@
102
105
  // スタイル/レイアウト
103
106
  size = 'medium',
104
107
  customStyle = '',
108
+ fullWidth = false,
105
109
 
106
110
  // 状態/動作
107
111
  disabled = false,
108
- fullWidth = false,
109
112
  required = false,
110
113
 
111
114
  // ARIA/アクセシビリティ
115
+ ariaLabel,
112
116
  reducedMotion = false,
113
117
 
114
118
  // フォーカスイベント
@@ -337,6 +341,7 @@
337
341
  {value}
338
342
  {disabled}
339
343
  {required}
344
+ aria-label={ariaLabel}
340
345
  aria-describedby={undefined}
341
346
  onfocus={handleFocus}
342
347
  onblur={handleBlur}
@@ -1,6 +1,7 @@
1
1
  import { type Snippet } from 'svelte';
2
2
  import type { FocusHandler, KeyboardHandler, MouseHandler, TouchHandler, PointerHandler, BivariantValueHandler } from '../types/callbackHandlers';
3
3
  import type { OptionValue } from '../types/options';
4
+ import type { ComponentSize } from '../types/propOptions';
4
5
  export type RadioProps = {
5
6
  /** Label content displayed next to the radio button. */
6
7
  children?: Snippet;
@@ -12,13 +13,15 @@ export type RadioProps = {
12
13
  currentValue: OptionValue;
13
14
  id?: string;
14
15
  /** Radio button size. @default 'medium' */
15
- size?: 'small' | 'medium' | 'large';
16
+ size?: ComponentSize;
16
17
  customStyle?: string;
17
- /** Disables this radio button. @default false */
18
- disabled?: boolean;
19
18
  /** Stretches the radio to fill its container width. @default false */
20
19
  fullWidth?: boolean;
20
+ /** Disables this radio button. @default false */
21
+ disabled?: boolean;
21
22
  required?: boolean;
23
+ /** Accessible label, used when no visible label (children) is provided. */
24
+ ariaLabel?: string;
22
25
  /** Disables animations for users who prefer reduced motion. @default false */
23
26
  reducedMotion?: boolean;
24
27
  onfocus?: FocusHandler;
@@ -5,6 +5,7 @@
5
5
  import Radio from './Radio.svelte';
6
6
  import { getStyleFromNumber } from '../utils/style';
7
7
  import type { BivariantValueHandler } from '../types/callbackHandlers';
8
+ import type { ComponentSize } from '../types/propOptions';
8
9
 
9
10
  // =========================================================================
10
11
  // Props, States & Constants
@@ -24,7 +25,7 @@
24
25
  wrap?: boolean;
25
26
  minOptionWidth?: string | number;
26
27
  /** @default 'medium' */
27
- size?: 'small' | 'medium' | 'large';
28
+ size?: ComponentSize;
28
29
 
29
30
  // 状態/動作
30
31
  disabled?: boolean;
@@ -82,6 +83,7 @@
82
83
  style:--internal-radio-group-gap={gapStyle}
83
84
  style:--internal-radio-group-wrap={wrap ? 'wrap' : 'none'}
84
85
  style:--internal-radio-group-min-option-width={minOptionWidthStyle}
86
+ data-testid="radio-group"
85
87
  >
86
88
  {#each options as option (option.value)}
87
89
  <li class="radio-group__option">
@@ -104,12 +106,9 @@
104
106
  <style>
105
107
  .radio-group {
106
108
  display: flex;
107
- flex-direction: var(
108
- --internal-radio-group-flex-direction,
109
- var(--svelte-ui-radio-group-flex-direction)
110
- );
109
+ flex-direction: var(--internal-radio-group-flex-direction);
111
110
  gap: var(--internal-radio-group-gap, var(--svelte-ui-radio-group-gap));
112
- flex-wrap: var(--internal-radio-group-wrap, var(--svelte-ui-radio-group-wrap));
111
+ flex-wrap: var(--internal-radio-group-wrap);
113
112
  }
114
113
 
115
114
  .radio-group__option {
@@ -1,5 +1,6 @@
1
1
  import type { Option, OptionValue } from '../types/options';
2
2
  import type { BivariantValueHandler } from '../types/callbackHandlers';
3
+ import type { ComponentSize } from '../types/propOptions';
3
4
  export type RadioGroupProps = {
4
5
  name?: string;
5
6
  /** `{ label, value, disabled? }[]` */
@@ -12,7 +13,7 @@ export type RadioGroupProps = {
12
13
  wrap?: boolean;
13
14
  minOptionWidth?: string | number;
14
15
  /** @default 'medium' */
15
- size?: 'small' | 'medium' | 'large';
16
+ size?: ComponentSize;
16
17
  disabled?: boolean;
17
18
  required?: boolean;
18
19
  /** Disables animations for accessibility. @default false */
@@ -9,8 +9,10 @@
9
9
  KeyboardHandler,
10
10
  MouseHandler,
11
11
  TouchHandler,
12
- PointerHandler
12
+ PointerHandler,
13
+ BivariantValueHandler
13
14
  } from '../types/callbackHandlers';
15
+ import type { ComponentSize } from '../types/propOptions';
14
16
 
15
17
  // =========================================================================
16
18
  // Props, States & Constants
@@ -28,7 +30,7 @@
28
30
 
29
31
  // スタイル/レイアウト
30
32
  /** @default 'medium' */
31
- size?: 'small' | 'medium' | 'large';
33
+ size?: ComponentSize;
32
34
  fullWidth?: boolean;
33
35
  /** Custom CSS color value. Overrides the theme color. */
34
36
  color?: string;
@@ -51,7 +53,7 @@
51
53
  reducedMotion?: boolean;
52
54
 
53
55
  // 入力イベント
54
- onchange?: (value: string) => void;
56
+ onchange?: BivariantValueHandler<string>;
55
57
 
56
58
  // フォーカスイベント
57
59
  onfocus?: FocusHandler;
@@ -1,6 +1,7 @@
1
1
  import type { IconVariant, IconWeight, IconGrade, IconOpticalSize } from '../types/icon';
2
2
  import type { SegmentedControlItem } from '../types/segmentedControlItem';
3
- import type { FocusHandler, KeyboardHandler, MouseHandler, TouchHandler, PointerHandler } from '../types/callbackHandlers';
3
+ import type { FocusHandler, KeyboardHandler, MouseHandler, TouchHandler, PointerHandler, BivariantValueHandler } from '../types/callbackHandlers';
4
+ import type { ComponentSize } from '../types/propOptions';
4
5
  export type SegmentedControlProps = {
5
6
  /** `{ label, value, icon?, disabled? }[]` */
6
7
  items: SegmentedControlItem[];
@@ -9,7 +10,7 @@ export type SegmentedControlProps = {
9
10
  id?: string;
10
11
  name?: string;
11
12
  /** @default 'medium' */
12
- size?: 'small' | 'medium' | 'large';
13
+ size?: ComponentSize;
13
14
  fullWidth?: boolean;
14
15
  /** Custom CSS color value. Overrides the theme color. */
15
16
  color?: string;
@@ -24,7 +25,7 @@ export type SegmentedControlProps = {
24
25
  ariaLabelledby?: string;
25
26
  /** Disables animations for accessibility. @default false */
26
27
  reducedMotion?: boolean;
27
- onchange?: (value: string) => void;
28
+ onchange?: BivariantValueHandler<string>;
28
29
  onfocus?: FocusHandler;
29
30
  onblur?: FocusHandler;
30
31
  onkeydown?: KeyboardHandler;
@@ -400,7 +400,6 @@ select--focus-{focusStyle}"
400
400
  width: 32px;
401
401
  height: 32px;
402
402
  transform: translateY(-50%);
403
- font-size: var(--svelte-ui-select-dropdown-icon-size);
404
403
  color: var(--svelte-ui-select-dropdown-icon-color);
405
404
  pointer-events: none;
406
405
  }
@@ -8,7 +8,8 @@
8
8
  KeyboardHandler,
9
9
  MouseHandler,
10
10
  TouchHandler,
11
- PointerHandler
11
+ PointerHandler,
12
+ BivariantValueHandler
12
13
  } from '../types/callbackHandlers';
13
14
 
14
15
  // =========================================================================
@@ -75,8 +76,8 @@
75
76
  onpointercancel?: PointerHandler;
76
77
 
77
78
  // 入力イベント
78
- onchange?: (value: number) => void;
79
- oninput?: (value: number) => void;
79
+ onchange?: BivariantValueHandler<number>;
80
+ oninput?: BivariantValueHandler<number>;
80
81
 
81
82
  // その他
82
83
  [key: string]: any;
@@ -1,4 +1,4 @@
1
- import type { FocusHandler, KeyboardHandler, MouseHandler, TouchHandler, PointerHandler } from '../types/callbackHandlers';
1
+ import type { FocusHandler, KeyboardHandler, MouseHandler, TouchHandler, PointerHandler, BivariantValueHandler } from '../types/callbackHandlers';
2
2
  export type SliderProps = {
3
3
  /** Supports `bind:value`. */
4
4
  value: number;
@@ -42,8 +42,8 @@ export type SliderProps = {
42
42
  onpointerleave?: PointerHandler;
43
43
  onpointermove?: PointerHandler;
44
44
  onpointercancel?: PointerHandler;
45
- onchange?: (value: number) => void;
46
- oninput?: (value: number) => void;
45
+ onchange?: BivariantValueHandler<number>;
46
+ oninput?: BivariantValueHandler<number>;
47
47
  [key: string]: any;
48
48
  };
49
49
  declare const Slider: import("svelte").Component<SliderProps, {}, "value">;
@@ -114,7 +114,7 @@
114
114
  const requiredMargin = -containerHeight;
115
115
 
116
116
  snackbarRef.style.setProperty(
117
- '--svelte-ui-snackbar-item-collapse-margin',
117
+ '--internal-snackbar-item-collapse-margin',
118
118
  `${requiredMargin}px`
119
119
  );
120
120
 
@@ -237,7 +237,7 @@
237
237
  }
238
238
  100% {
239
239
  opacity: 0;
240
- margin-bottom: var(--svelte-ui-snackbar-item-collapse-margin);
240
+ margin-bottom: var(--internal-snackbar-item-collapse-margin);
241
241
  }
242
242
  }
243
243
 
@@ -248,7 +248,7 @@
248
248
  }
249
249
  100% {
250
250
  opacity: 0;
251
- margin-top: var(--svelte-ui-snackbar-item-collapse-margin);
251
+ margin-top: var(--internal-snackbar-item-collapse-margin);
252
252
  }
253
253
  }
254
254
 
@@ -7,8 +7,10 @@
7
7
  KeyboardHandler,
8
8
  MouseHandler,
9
9
  TouchHandler,
10
- PointerHandler
10
+ PointerHandler,
11
+ BivariantValueHandler
11
12
  } from '../types/callbackHandlers';
13
+ import type { ComponentSize } from '../types/propOptions';
12
14
 
13
15
  // =========================================================================
14
16
  // Props, States & Constants
@@ -25,16 +27,18 @@
25
27
  id?: string;
26
28
  // スタイル/レイアウト
27
29
  /** @default 'medium' */
28
- size?: 'small' | 'medium' | 'large';
30
+ size?: ComponentSize;
29
31
  customStyle?: string;
32
+ /** Stretches the switch to fill its container width. @default false */
33
+ fullWidth?: boolean;
30
34
 
31
35
  // 状態/動作
32
36
  disabled?: boolean;
33
- /** Stretches the switch to fill its container width. @default false */
34
- fullWidth?: boolean;
35
37
  required?: boolean;
36
38
 
37
39
  // ARIA/アクセシビリティ
40
+ /** Accessible label, used when no visible label (children) is provided. */
41
+ ariaLabel?: string;
38
42
  /** Disables animations for accessibility. @default false */
39
43
  reducedMotion?: boolean;
40
44
 
@@ -72,7 +76,7 @@
72
76
  onpointercancel?: PointerHandler;
73
77
 
74
78
  // 入力イベント
75
- onchange?: (value: boolean) => void;
79
+ onchange?: BivariantValueHandler<boolean>;
76
80
 
77
81
  // その他
78
82
  [key: string]: any;
@@ -91,13 +95,14 @@
91
95
  // スタイル/レイアウト
92
96
  size = 'medium',
93
97
  customStyle = '',
98
+ fullWidth = false,
94
99
 
95
100
  // 状態/動作
96
101
  disabled = false,
97
- fullWidth = false,
98
102
  required = false,
99
103
 
100
104
  // ARIA/アクセシビリティ
105
+ ariaLabel,
101
106
  reducedMotion = false,
102
107
 
103
108
  // フォーカスイベント
@@ -296,6 +301,7 @@
296
301
  {disabled}
297
302
  {required}
298
303
  {id}
304
+ aria-label={ariaLabel}
299
305
  onchange={handleChange}
300
306
  onfocus={handleFocus}
301
307
  onblur={handleBlur}
@@ -1,17 +1,20 @@
1
1
  import type { Snippet } from 'svelte';
2
- import type { FocusHandler, KeyboardHandler, MouseHandler, TouchHandler, PointerHandler } from '../types/callbackHandlers';
2
+ import type { FocusHandler, KeyboardHandler, MouseHandler, TouchHandler, PointerHandler, BivariantValueHandler } from '../types/callbackHandlers';
3
+ import type { ComponentSize } from '../types/propOptions';
3
4
  export type SwitchProps = {
4
5
  children?: Snippet;
5
6
  /** Supports `bind:value`. */
6
7
  value: boolean;
7
8
  id?: string;
8
9
  /** @default 'medium' */
9
- size?: 'small' | 'medium' | 'large';
10
+ size?: ComponentSize;
10
11
  customStyle?: string;
11
- disabled?: boolean;
12
12
  /** Stretches the switch to fill its container width. @default false */
13
13
  fullWidth?: boolean;
14
+ disabled?: boolean;
14
15
  required?: boolean;
16
+ /** Accessible label, used when no visible label (children) is provided. */
17
+ ariaLabel?: string;
15
18
  /** Disables animations for accessibility. @default false */
16
19
  reducedMotion?: boolean;
17
20
  onfocus?: FocusHandler;
@@ -37,7 +40,7 @@ export type SwitchProps = {
37
40
  onpointerleave?: PointerHandler;
38
41
  onpointermove?: PointerHandler;
39
42
  onpointercancel?: PointerHandler;
40
- onchange?: (value: boolean) => void;
43
+ onchange?: BivariantValueHandler<boolean>;
41
44
  [key: string]: any;
42
45
  };
43
46
  declare const Switch: import("svelte").Component<SwitchProps, {}, "value">;
@@ -82,13 +82,7 @@
82
82
  }: TabProps = $props();
83
83
  </script>
84
84
 
85
- <div
86
- class="tab"
87
- style:--svelte-ui-nav-item-underline-text-color={textColor}
88
- style:--svelte-ui-nav-item-underline-selected-text-color={selectedTextColor}
89
- style:--svelte-ui-nav-item-underline-bar-color={selectedBarColor}
90
- data-testid="tab"
91
- >
85
+ <div class="tab" data-testid="tab">
92
86
  <Nav
93
87
  navItems={tabItems}
94
88
  variant="horizontal"
@@ -102,6 +96,9 @@
102
96
  {iconGrade}
103
97
  {iconOpticalSize}
104
98
  {iconVariant}
99
+ {textColor}
100
+ {selectedTextColor}
101
+ {selectedBarColor}
105
102
  {customContainerStyle}
106
103
  {customItemStyle}
107
104
  {customChildrenContainerStyle}
@@ -4,7 +4,7 @@
4
4
  import IconButton from './IconButton.svelte';
5
5
  import { getStyleFromNumber } from '../utils/style';
6
6
  import { t } from '../i18n';
7
- import { convertToHtml, convertToHtmlWithLink } from '../utils/formatText';
7
+ import { escapeHtml, convertToLink } from '../utils/formatText';
8
8
  import type { HTMLTextareaAttributes } from 'svelte/elements';
9
9
  import type { IconVariant, IconWeight, IconGrade, IconOpticalSize } from '../types/icon';
10
10
  import type {
@@ -12,7 +12,8 @@
12
12
  KeyboardHandler,
13
13
  MouseHandler,
14
14
  TouchHandler,
15
- PointerHandler
15
+ PointerHandler,
16
+ BivariantValueHandler
16
17
  } from '../types/callbackHandlers';
17
18
  import type { FocusStyle } from '../types/propOptions';
18
19
 
@@ -71,6 +72,10 @@
71
72
  /** Converts URLs in the value to clickable links (non-focused view). @default false */
72
73
  linkify?: boolean;
73
74
 
75
+ // ARIA/アクセシビリティ
76
+ /** Accessible label for the textarea, used when no associated visible label exists. */
77
+ ariaLabel?: string;
78
+
74
79
  // フォーカスイベント
75
80
  onfocus?: FocusHandler;
76
81
  onblur?: FocusHandler;
@@ -105,8 +110,8 @@
105
110
  onpointercancel?: PointerHandler;
106
111
 
107
112
  // 入力イベント
108
- onchange?: (value: string) => void;
109
- oninput?: (value: string) => void;
113
+ onchange?: BivariantValueHandler<string>;
114
+ oninput?: BivariantValueHandler<string>;
110
115
 
111
116
  // その他
112
117
  [key: string]: any;
@@ -156,6 +161,9 @@
156
161
  required = false,
157
162
  linkify = false,
158
163
 
164
+ // ARIA/アクセシビリティ
165
+ ariaLabel,
166
+
159
167
  // フォーカスイベント
160
168
  onfocus = () => {}, // No params for type inference
161
169
  onblur = () => {}, // No params for type inference
@@ -475,21 +483,14 @@
475
483
  value !== null && value !== undefined && !(typeof value === 'string' && value === '')
476
484
  );
477
485
 
478
- // HTML表示用の値(autoResize時の高さ調整用)
486
+ // HTML表示用の値(pre-wrap で表示するため HTML エスケープのみ行う)
479
487
  const displayValue = $derived.by(() => {
480
488
  const normalizedValue = value ?? '';
481
489
  if (normalizedValue !== '') {
482
- const converted = convertToHtml(normalizedValue);
483
- const html = String(converted ?? '');
484
- // 最後の行が空だったら空白を追加(高さ調整のため)
485
- const lines = html.split('<br />');
486
- if (lines.length > 0 && lines[lines.length - 1] === '') {
487
- return html + '&nbsp;';
488
- }
489
- return html;
490
+ return escapeHtml(normalizedValue);
490
491
  }
491
492
  // 値が空のとき: placeholder があればその幅・高さを確保して表示、なければ inline 時のみ &nbsp;
492
- return placeholder ? convertToHtml(placeholder) : inline ? '&nbsp;' : '';
493
+ return placeholder ? escapeHtml(placeholder) : inline ? '&nbsp;' : '';
493
494
  });
494
495
 
495
496
  // URLをリンク化した表示用HTML(クリック検出用オーバーレイで使用)
@@ -498,8 +499,7 @@
498
499
  if (!linkify || normalizedValue === '') {
499
500
  return '';
500
501
  }
501
- const result = convertToHtmlWithLink(normalizedValue);
502
- return String(result ?? '');
502
+ return convertToLink(escapeHtml(normalizedValue));
503
503
  });
504
504
 
505
505
  // --------------------------------
@@ -555,6 +555,7 @@
555
555
  {readonly}
556
556
  {required}
557
557
  {maxlength}
558
+ aria-label={ariaLabel}
558
559
  {tabindex}
559
560
  {autocomplete}
560
561
  {wrap}
@@ -631,6 +632,7 @@
631
632
  position: relative;
632
633
  width: auto;
633
634
  max-width: 100%;
635
+ overflow: hidden;
634
636
 
635
637
  &.textarea--full-height {
636
638
  height: 100%;
@@ -699,6 +701,7 @@
699
701
  transition: none;
700
702
  overflow-y: auto;
701
703
  overflow-x: hidden;
704
+ max-height: 100%;
702
705
 
703
706
  &::before {
704
707
  content: '';
@@ -709,13 +712,15 @@
709
712
  }
710
713
  }
711
714
 
712
- /* display-text: スクロールバーの幅を確保しつつ透明にする(textarea と幅を一致させる) */
715
+ /* display-text: textarea white-space: pre-wrap に合わせて空白・改行を同じルールで扱う */
713
716
  .textarea__display-text {
717
+ white-space: pre-wrap;
714
718
  scrollbar-color: transparent transparent;
715
719
  }
716
720
 
717
- /* link-text: 絶対配置のオーバーレイなのでスクロールバーを完全に非表示 */
721
+ /* link-text: 絶対配置オーバーレイ。pre-wrap で textarea と空白・改行を同じルールで扱う */
718
722
  .textarea__link-text {
723
+ white-space: pre-wrap;
719
724
  scrollbar-width: none;
720
725
 
721
726
  &::-webkit-scrollbar {
@@ -1,6 +1,6 @@
1
1
  import type { HTMLTextareaAttributes } from 'svelte/elements';
2
2
  import type { IconVariant, IconWeight, IconGrade, IconOpticalSize } from '../types/icon';
3
- import type { FocusHandler, KeyboardHandler, MouseHandler, TouchHandler, PointerHandler } from '../types/callbackHandlers';
3
+ import type { FocusHandler, KeyboardHandler, MouseHandler, TouchHandler, PointerHandler, BivariantValueHandler } from '../types/callbackHandlers';
4
4
  import type { FocusStyle } from '../types/propOptions';
5
5
  export type TextareaProps = {
6
6
  name?: string;
@@ -45,6 +45,8 @@ export type TextareaProps = {
45
45
  required?: boolean;
46
46
  /** Converts URLs in the value to clickable links (non-focused view). @default false */
47
47
  linkify?: boolean;
48
+ /** Accessible label for the textarea, used when no associated visible label exists. */
49
+ ariaLabel?: string;
48
50
  onfocus?: FocusHandler;
49
51
  onblur?: FocusHandler;
50
52
  onkeydown?: KeyboardHandler;
@@ -68,8 +70,8 @@ export type TextareaProps = {
68
70
  onpointerleave?: PointerHandler;
69
71
  onpointermove?: PointerHandler;
70
72
  onpointercancel?: PointerHandler;
71
- onchange?: (value: string) => void;
72
- oninput?: (value: string) => void;
73
+ onchange?: BivariantValueHandler<string>;
74
+ oninput?: BivariantValueHandler<string>;
73
75
  [key: string]: any;
74
76
  };
75
77
  declare const Textarea: import("svelte").Component<TextareaProps, {