@14ch/svelte-ui 0.0.1

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 (109) hide show
  1. package/README.md +359 -0
  2. package/dist/assets/styles/README.md +144 -0
  3. package/dist/assets/styles/core.scss +61 -0
  4. package/dist/assets/styles/import.scss +11 -0
  5. package/dist/assets/styles/optional/fonts.scss +23 -0
  6. package/dist/assets/styles/optional/reset.scss +230 -0
  7. package/dist/assets/styles/variables.scss +805 -0
  8. package/dist/components/Button.svelte +574 -0
  9. package/dist/components/Button.svelte.d.ts +56 -0
  10. package/dist/components/COMPONENT_DESIGN_GUIDELINES.md +127 -0
  11. package/dist/components/Checkbox.svelte +523 -0
  12. package/dist/components/Checkbox.svelte.d.ts +42 -0
  13. package/dist/components/CheckboxGroup.svelte +82 -0
  14. package/dist/components/CheckboxGroup.svelte.d.ts +13 -0
  15. package/dist/components/ColorPicker.svelte +496 -0
  16. package/dist/components/ColorPicker.svelte.d.ts +45 -0
  17. package/dist/components/Combobox.svelte +576 -0
  18. package/dist/components/Combobox.svelte.d.ts +52 -0
  19. package/dist/components/ConfirmDialog.svelte +116 -0
  20. package/dist/components/ConfirmDialog.svelte.d.ts +20 -0
  21. package/dist/components/Datepicker.svelte +578 -0
  22. package/dist/components/Datepicker.svelte.d.ts +72 -0
  23. package/dist/components/DatepickerCalendar.svelte +925 -0
  24. package/dist/components/DatepickerCalendar.svelte.d.ts +31 -0
  25. package/dist/components/Dialog.svelte +245 -0
  26. package/dist/components/Dialog.svelte.d.ts +38 -0
  27. package/dist/components/Drawer.svelte +383 -0
  28. package/dist/components/Drawer.svelte.d.ts +39 -0
  29. package/dist/components/Fab.svelte +486 -0
  30. package/dist/components/Fab.svelte.d.ts +51 -0
  31. package/dist/components/FileUploader.svelte +456 -0
  32. package/dist/components/FileUploader.svelte.d.ts +36 -0
  33. package/dist/components/Icon.svelte +167 -0
  34. package/dist/components/Icon.svelte.d.ts +21 -0
  35. package/dist/components/IconButton.svelte +557 -0
  36. package/dist/components/IconButton.svelte.d.ts +60 -0
  37. package/dist/components/ImageUploader.svelte +516 -0
  38. package/dist/components/ImageUploader.svelte.d.ts +37 -0
  39. package/dist/components/ImageUploaderPreview.svelte +157 -0
  40. package/dist/components/ImageUploaderPreview.svelte.d.ts +13 -0
  41. package/dist/components/Input.svelte +885 -0
  42. package/dist/components/Input.svelte.d.ts +75 -0
  43. package/dist/components/LoadingSpinner.svelte +116 -0
  44. package/dist/components/LoadingSpinner.svelte.d.ts +10 -0
  45. package/dist/components/Modal.svelte +313 -0
  46. package/dist/components/Modal.svelte.d.ts +34 -0
  47. package/dist/components/Pagination.svelte +276 -0
  48. package/dist/components/Pagination.svelte.d.ts +14 -0
  49. package/dist/components/Popup.svelte +676 -0
  50. package/dist/components/Popup.svelte.d.ts +40 -0
  51. package/dist/components/PopupMenu.svelte +421 -0
  52. package/dist/components/PopupMenu.svelte.d.ts +24 -0
  53. package/dist/components/PopupMenuButton.svelte +365 -0
  54. package/dist/components/PopupMenuButton.svelte.d.ts +42 -0
  55. package/dist/components/Radio.svelte +548 -0
  56. package/dist/components/Radio.svelte.d.ts +42 -0
  57. package/dist/components/RadioGroup.svelte +74 -0
  58. package/dist/components/RadioGroup.svelte.d.ts +14 -0
  59. package/dist/components/Select.svelte +479 -0
  60. package/dist/components/Select.svelte.d.ts +47 -0
  61. package/dist/components/Slider.svelte +473 -0
  62. package/dist/components/Slider.svelte.d.ts +46 -0
  63. package/dist/components/Snackbar.svelte +124 -0
  64. package/dist/components/Snackbar.svelte.d.ts +9 -0
  65. package/dist/components/SnackbarItem.svelte +423 -0
  66. package/dist/components/SnackbarItem.svelte.d.ts +21 -0
  67. package/dist/components/Switch.svelte +454 -0
  68. package/dist/components/Switch.svelte.d.ts +40 -0
  69. package/dist/components/Tab.svelte +193 -0
  70. package/dist/components/Tab.svelte.d.ts +14 -0
  71. package/dist/components/TabItem.svelte +140 -0
  72. package/dist/components/TabItem.svelte.d.ts +17 -0
  73. package/dist/components/Textarea.svelte +702 -0
  74. package/dist/components/Textarea.svelte.d.ts +64 -0
  75. package/dist/components/skeleton/Skeleton.svelte +235 -0
  76. package/dist/components/skeleton/Skeleton.svelte.d.ts +13 -0
  77. package/dist/components/skeleton/SkeletonAvatar.svelte +97 -0
  78. package/dist/components/skeleton/SkeletonAvatar.svelte.d.ts +8 -0
  79. package/dist/components/skeleton/SkeletonBox.svelte +105 -0
  80. package/dist/components/skeleton/SkeletonBox.svelte.d.ts +12 -0
  81. package/dist/components/skeleton/SkeletonButton.svelte +71 -0
  82. package/dist/components/skeleton/SkeletonButton.svelte.d.ts +8 -0
  83. package/dist/components/skeleton/SkeletonHeading.svelte +49 -0
  84. package/dist/components/skeleton/SkeletonHeading.svelte.d.ts +8 -0
  85. package/dist/components/skeleton/SkeletonMedia.svelte +115 -0
  86. package/dist/components/skeleton/SkeletonMedia.svelte.d.ts +9 -0
  87. package/dist/components/skeleton/SkeletonText.svelte +75 -0
  88. package/dist/components/skeleton/SkeletonText.svelte.d.ts +8 -0
  89. package/dist/index.d.ts +42 -0
  90. package/dist/index.js +43 -0
  91. package/dist/types/icon.d.ts +4 -0
  92. package/dist/types/icon.js +2 -0
  93. package/dist/types/menuItem.d.ts +8 -0
  94. package/dist/types/menuItem.js +1 -0
  95. package/dist/types/options.d.ts +6 -0
  96. package/dist/types/options.js +4 -0
  97. package/dist/types/skeleton.d.ts +77 -0
  98. package/dist/types/skeleton.js +19 -0
  99. package/dist/utils/accessibility.d.ts +48 -0
  100. package/dist/utils/accessibility.js +87 -0
  101. package/dist/utils/formatText.d.ts +4 -0
  102. package/dist/utils/formatText.js +44 -0
  103. package/dist/utils/mobile.d.ts +9 -0
  104. package/dist/utils/mobile.js +47 -0
  105. package/dist/utils/snackbar.svelte.d.ts +51 -0
  106. package/dist/utils/snackbar.svelte.js +107 -0
  107. package/dist/utils/style.d.ts +17 -0
  108. package/dist/utils/style.js +22 -0
  109. package/package.json +102 -0
@@ -0,0 +1,702 @@
1
+ <!-- Textarea.svelte -->
2
+
3
+ <script lang="ts">
4
+ import IconButton from './IconButton.svelte';
5
+ import { getStyleFromNumber } from '../utils/style';
6
+ import { t } from '../i18n';
7
+ import type { HTMLTextareaAttributes } from 'svelte/elements';
8
+ import type { IconVariant } from '../types/icon';
9
+
10
+ // =========================================================================
11
+ // Props, States & Constants
12
+ // =========================================================================
13
+
14
+ let {
15
+ // 基本プロパティ
16
+ name = '',
17
+ value = $bindable(),
18
+ placeholder = '',
19
+
20
+ // HTML属性系
21
+ id = null,
22
+ tabindex = null,
23
+ maxlength = null,
24
+ autocomplete = null,
25
+ wrap = null,
26
+ spellcheck = null,
27
+ autocapitalize = null,
28
+ textareaAttributes,
29
+
30
+ // スタイル/レイアウト
31
+ rows = 3,
32
+ minHeight = 36,
33
+ maxHeight = null,
34
+ inline = false,
35
+ focusStyle = 'outline',
36
+ fullWidth = false,
37
+ fullHeight = false,
38
+ width = null,
39
+ rounded = false,
40
+ customStyle = '',
41
+
42
+ // 状態/動作
43
+ disabled = false,
44
+ autoResize = true,
45
+ resizable = false,
46
+ clearable = false,
47
+ clearButtonAriaLabel = t('input.clear'),
48
+ readonly = false,
49
+ required = false,
50
+ iconVariant = 'outlined',
51
+
52
+ // フォーカスイベント
53
+ onfocus = () => {}, // No params for type inference
54
+ onblur = () => {}, // No params for type inference
55
+
56
+ // キーボードイベント
57
+ onkeydown = () => {}, // No params for type inference
58
+ onkeyup = () => {}, // No params for type inference
59
+
60
+ // マウスイベント
61
+ onclick = () => {}, // No params for type inference
62
+ onmousedown = () => {}, // No params for type inference
63
+ onmouseup = () => {}, // No params for type inference
64
+ onmouseenter = () => {}, // No params for type inference
65
+ onmouseleave = () => {}, // No params for type inference
66
+ onmouseover = () => {}, // No params for type inference
67
+ onmouseout = () => {}, // No params for type inference
68
+ oncontextmenu = () => {}, // No params for type inference
69
+ onauxclick = () => {}, // No params for type inference
70
+
71
+ // タッチイベント
72
+ ontouchstart = () => {}, // No params for type inference
73
+ ontouchend = () => {}, // No params for type inference
74
+ ontouchmove = () => {}, // No params for type inference
75
+ ontouchcancel = () => {}, // No params for type inference
76
+
77
+ // ポインターイベント
78
+ onpointerdown = () => {}, // No params for type inference
79
+ onpointerup = () => {}, // No params for type inference
80
+ onpointerenter = () => {}, // No params for type inference
81
+ onpointerleave = () => {}, // No params for type inference
82
+ onpointermove = () => {}, // No params for type inference
83
+ onpointercancel = () => {}, // No params for type inference
84
+
85
+ // 入力イベント
86
+ onchange = () => {}, // No params for type inference
87
+ oninput = () => {}, // No params for type inference
88
+
89
+ // その他
90
+ ...restProps
91
+ }: {
92
+ // 基本プロパティ
93
+ name?: string;
94
+ value: string | undefined;
95
+ placeholder?: string;
96
+
97
+ // HTML属性系
98
+ id?: string | null;
99
+ tabindex?: number | null;
100
+ maxlength?: number | null;
101
+ autocomplete?: HTMLTextareaAttributes['autocomplete'];
102
+ wrap?: 'soft' | 'hard' | null;
103
+ spellcheck?: boolean | null;
104
+ autocapitalize?: 'off' | 'none' | 'on' | 'sentences' | 'words' | 'characters' | null;
105
+ textareaAttributes?: HTMLTextareaAttributes | undefined;
106
+
107
+ // スタイル/レイアウト
108
+ rows?: number;
109
+ minHeight?: number | null;
110
+ maxHeight?: string | number | null;
111
+ inline?: boolean;
112
+ focusStyle?: 'background' | 'outline' | 'none';
113
+ fullWidth?: boolean;
114
+ fullHeight?: boolean;
115
+ width?: string | number | null;
116
+ rounded?: boolean;
117
+ customStyle?: string;
118
+
119
+ // 状態/動作
120
+ disabled?: boolean;
121
+ autoResize?: boolean;
122
+ resizable?: boolean;
123
+ clearable?: boolean;
124
+ clearButtonAriaLabel?: string;
125
+ readonly?: boolean;
126
+ required?: boolean;
127
+ iconVariant?: IconVariant;
128
+
129
+ // フォーカスイベント
130
+ onfocus?: Function; // No params for type inference
131
+ onblur?: Function; // No params for type inference
132
+
133
+ // キーボードイベント
134
+ onkeydown?: Function; // No params for type inference
135
+ onkeyup?: Function; // No params for type inference
136
+
137
+ // マウスイベント
138
+ onclick?: Function; // No params for type inference
139
+ onmousedown?: Function; // No params for type inference
140
+ onmouseup?: Function; // No params for type inference
141
+ onmouseenter?: Function; // No params for type inference
142
+ onmouseleave?: Function; // No params for type inference
143
+ onmouseover?: Function; // No params for type inference
144
+ onmouseout?: Function; // No params for type inference
145
+ oncontextmenu?: Function; // No params for type inference
146
+ onauxclick?: Function; // No params for type inference
147
+
148
+ // タッチイベント
149
+ ontouchstart?: Function; // No params for type inference
150
+ ontouchend?: Function; // No params for type inference
151
+ ontouchmove?: Function; // No params for type inference
152
+ ontouchcancel?: Function; // No params for type inference
153
+
154
+ // ポインターイベント
155
+ onpointerdown?: Function; // No params for type inference
156
+ onpointerup?: Function; // No params for type inference
157
+ onpointerenter?: Function; // No params for type inference
158
+ onpointerleave?: Function; // No params for type inference
159
+ onpointermove?: Function; // No params for type inference
160
+ onpointercancel?: Function; // No params for type inference
161
+
162
+ // 入力イベント
163
+ onchange?: (value: any) => void;
164
+ oninput?: (value: any) => void;
165
+
166
+ // その他
167
+ [key: string]: any;
168
+ } = $props();
169
+
170
+ let ref: HTMLTextAreaElement | null = null;
171
+ let isFocused: boolean = $state(false);
172
+
173
+ // =========================================================================
174
+
175
+ // Methods
176
+ // =========================================================================
177
+
178
+ const clear = (): void => {
179
+ if (disabled || readonly) return;
180
+ value = undefined;
181
+ ref?.focus();
182
+ onchange?.(value);
183
+ };
184
+
185
+ // 外部からフォーカスを当てる(キャレットを先頭に移動)
186
+ export const focus = () => {
187
+ if (ref) {
188
+ ref.focus();
189
+ ref.setSelectionRange(0, 0);
190
+ ref.scrollTop = 0;
191
+ }
192
+ };
193
+
194
+ const handleChange = () => {
195
+ if (disabled || readonly) return;
196
+ onchange?.(value);
197
+ };
198
+ const handleInput = () => {
199
+ if (disabled || readonly) return;
200
+ oninput?.(value);
201
+ };
202
+ const handleFocus = (event: FocusEvent) => {
203
+ if (disabled) return;
204
+ isFocused = true;
205
+ onfocus?.(event);
206
+ };
207
+
208
+ const handleBlur = (event: FocusEvent) => {
209
+ if (disabled) return;
210
+ isFocused = false;
211
+ onblur?.(event);
212
+ };
213
+
214
+ // キーボードイベント
215
+ const handleKeydown = (event: KeyboardEvent) => {
216
+ if (disabled) return;
217
+ onkeydown?.(event);
218
+ };
219
+
220
+ const handleKeyup = (event: KeyboardEvent) => {
221
+ if (disabled) return;
222
+ onkeyup?.(event);
223
+ };
224
+
225
+ // マウスイベント
226
+ const handleClick = (event: MouseEvent) => {
227
+ if (disabled) return;
228
+ onclick?.(event);
229
+ };
230
+
231
+ const handleMouseDown = (event: MouseEvent) => {
232
+ if (disabled) return;
233
+ onmousedown?.(event);
234
+ };
235
+
236
+ const handleMouseUp = (event: MouseEvent) => {
237
+ if (disabled) return;
238
+ onmouseup?.(event);
239
+ };
240
+
241
+ const handleMouseEnter = (event: MouseEvent) => {
242
+ if (disabled) return;
243
+ onmouseenter?.(event);
244
+ };
245
+
246
+ const handleMouseLeave = (event: MouseEvent) => {
247
+ if (disabled) return;
248
+ onmouseleave?.(event);
249
+ };
250
+
251
+ const handleMouseOver = (event: MouseEvent) => {
252
+ if (disabled) return;
253
+ onmouseover?.(event);
254
+ };
255
+
256
+ const handleMouseOut = (event: MouseEvent) => {
257
+ if (disabled) return;
258
+ onmouseout?.(event);
259
+ };
260
+
261
+ const handleContextMenu = (event: MouseEvent) => {
262
+ if (disabled) return;
263
+ oncontextmenu?.(event);
264
+ };
265
+
266
+ const handleAuxClick = (event: MouseEvent) => {
267
+ if (disabled) return;
268
+ onauxclick?.(event);
269
+ };
270
+
271
+ // タッチイベント
272
+ const handleTouchStart = (event: TouchEvent) => {
273
+ if (disabled) return;
274
+ ontouchstart?.(event);
275
+ };
276
+
277
+ const handleTouchEnd = (event: TouchEvent) => {
278
+ if (disabled) return;
279
+ ontouchend?.(event);
280
+ };
281
+
282
+ const handleTouchMove = (event: TouchEvent) => {
283
+ if (disabled) return;
284
+ ontouchmove?.(event);
285
+ };
286
+
287
+ const handleTouchCancel = (event: TouchEvent) => {
288
+ if (disabled) return;
289
+ ontouchcancel?.(event);
290
+ };
291
+
292
+ // ポインターイベント
293
+ const handlePointerDown = (event: PointerEvent) => {
294
+ if (disabled) return;
295
+ onpointerdown?.(event);
296
+ };
297
+
298
+ const handlePointerUp = (event: PointerEvent) => {
299
+ if (disabled) return;
300
+ onpointerup?.(event);
301
+ };
302
+
303
+ const handlePointerEnter = (event: PointerEvent) => {
304
+ if (disabled) return;
305
+ onpointerenter?.(event);
306
+ };
307
+
308
+ const handlePointerLeave = (event: PointerEvent) => {
309
+ if (disabled) return;
310
+ onpointerleave?.(event);
311
+ };
312
+
313
+ const handlePointerMove = (event: PointerEvent) => {
314
+ if (disabled) return;
315
+ onpointermove?.(event);
316
+ };
317
+
318
+ const handlePointerCancel = (event: PointerEvent) => {
319
+ if (disabled) return;
320
+ onpointercancel?.(event);
321
+ };
322
+
323
+ // =========================================================================
324
+ // $derived
325
+ // =========================================================================
326
+
327
+ // min-heightスタイルの計算
328
+ const minHeightStyle = $derived(
329
+ inline ? 'min-height: 1.6em; min-height: 1lh;' : `min-height: ${minHeight}px;`
330
+ );
331
+
332
+ const maxHeightStyle = $derived(getStyleFromNumber(maxHeight));
333
+ const widthStyle = $derived(getStyleFromNumber(width));
334
+
335
+ // HTML表示用の値(autoResize時の高さ調整用)
336
+ const htmlValue = $derived.by(() => {
337
+ if (typeof value === 'string' && value !== '') {
338
+ let html = value
339
+ .replace(/ +/g, (match) => '&nbsp;'.repeat(match.length))
340
+ .replace(/\n/g, '<br />');
341
+ // 最後の行が空だったら空白を追加(高さ調整のため)
342
+ const lines = html.split('<br />');
343
+ if (lines.length > 0 && lines[lines.length - 1] === '') {
344
+ html += '&nbsp;';
345
+ }
346
+ return html;
347
+ } else {
348
+ return value ?? '';
349
+ }
350
+ });
351
+ </script>
352
+
353
+ <div
354
+ class="textarea
355
+ textarea--focus-{focusStyle}"
356
+ class:textarea--inline={inline}
357
+ class:textarea--full-width={fullWidth}
358
+ class:textarea--full-height={fullHeight}
359
+ class:textarea--auto-resize={autoResize}
360
+ class:textarea--clearable={clearable}
361
+ class:textarea--rounded={rounded}
362
+ class:textarea--disabled={disabled}
363
+ class:textarea--readonly={readonly}
364
+ class:textarea--focused={isFocused}
365
+ data-testid="textarea"
366
+ style={!inline ? `max-height: ${maxHeightStyle};` : ''}
367
+ >
368
+ <!-- autoResize時の表示用要素(HTMLレンダリングで高さ調整) -->
369
+ <div
370
+ class="textarea__display-text"
371
+ data-placeholder={placeholder}
372
+ style="{minHeightStyle} {customStyle}"
373
+ >
374
+ {@html htmlValue}
375
+ </div>
376
+ <div class="textarea__input">
377
+ <textarea
378
+ {id}
379
+ {name}
380
+ bind:value
381
+ bind:this={ref}
382
+ {rows}
383
+ {placeholder}
384
+ {disabled}
385
+ {readonly}
386
+ {required}
387
+ {maxlength}
388
+ {tabindex}
389
+ {autocomplete}
390
+ {wrap}
391
+ {spellcheck}
392
+ {autocapitalize}
393
+ class:resizable
394
+ style="width: {widthStyle}; {minHeightStyle} {customStyle}"
395
+ onchange={handleChange}
396
+ oninput={handleInput}
397
+ onfocus={handleFocus}
398
+ onblur={handleBlur}
399
+ onkeydown={handleKeydown}
400
+ onkeyup={handleKeyup}
401
+ onclick={handleClick}
402
+ onmousedown={handleMouseDown}
403
+ onmouseup={handleMouseUp}
404
+ onmouseenter={handleMouseEnter}
405
+ onmouseleave={handleMouseLeave}
406
+ onmouseover={handleMouseOver}
407
+ onmouseout={handleMouseOut}
408
+ oncontextmenu={handleContextMenu}
409
+ onauxclick={handleAuxClick}
410
+ ontouchstart={handleTouchStart}
411
+ ontouchend={handleTouchEnd}
412
+ ontouchmove={handleTouchMove}
413
+ ontouchcancel={handleTouchCancel}
414
+ onpointerdown={handlePointerDown}
415
+ onpointerup={handlePointerUp}
416
+ onpointerenter={handlePointerEnter}
417
+ onpointerleave={handlePointerLeave}
418
+ onpointermove={handlePointerMove}
419
+ onpointercancel={handlePointerCancel}
420
+ {...textareaAttributes}
421
+ {...restProps}
422
+ ></textarea>
423
+ <!-- クリアボタン -->
424
+ {#if clearable && !disabled && !readonly}
425
+ <div class="textarea__clear-button">
426
+ <IconButton
427
+ ariaLabel={clearButtonAriaLabel}
428
+ color="var(--svelte-ui-textarea-text-color)"
429
+ onclick={(event) => {
430
+ event.stopPropagation();
431
+ clear();
432
+ }}
433
+ tabindex={-1}
434
+ iconFilled={true}
435
+ {iconVariant}
436
+ fontSize={18}>cancel</IconButton
437
+ >
438
+ </div>
439
+ {/if}
440
+ </div>
441
+ </div>
442
+
443
+ <style>
444
+ /* =============================================
445
+ * 基本構造・レイアウト
446
+ * ============================================= */
447
+ .textarea {
448
+ display: block;
449
+ position: relative;
450
+ width: auto;
451
+ max-width: 100%;
452
+
453
+ &.textarea--full-height {
454
+ height: 100%;
455
+ }
456
+ }
457
+
458
+ .textarea__input {
459
+ position: absolute;
460
+ top: 0;
461
+ left: 0;
462
+ width: 100%;
463
+ height: 100%;
464
+ padding: inherit;
465
+ border: none;
466
+ font-size: inherit;
467
+ font-weight: inherit;
468
+ color: inherit;
469
+ line-height: inherit;
470
+ text-align: inherit;
471
+ }
472
+
473
+ /* =============================================
474
+ * 基本コンポーネント
475
+ * ============================================= */
476
+ .textarea__display-text {
477
+ display: flex;
478
+ align-items: start; /* テーブルの他の列に合わせて高さが高くなっているときに、上寄せになるようにするための措置 */
479
+ width: 100%;
480
+ background: inherit;
481
+ border: inherit;
482
+ font-size: inherit;
483
+ font-weight: inherit;
484
+ color: inherit;
485
+ line-height: inherit;
486
+ text-align: inherit;
487
+ word-break: inherit;
488
+ opacity: 1;
489
+ transition: none;
490
+ cursor: text !important;
491
+
492
+ &::before {
493
+ content: '';
494
+ }
495
+
496
+ &:empty::before {
497
+ content: attr(data-placeholder);
498
+ }
499
+ }
500
+
501
+ textarea {
502
+ position: absolute;
503
+ top: 0;
504
+ left: 0;
505
+ width: 100%;
506
+ height: 100%;
507
+ padding: inherit;
508
+ background: transparent;
509
+ border: none;
510
+ font-size: inherit;
511
+ font-weight: inherit;
512
+ color: inherit;
513
+ line-height: inherit;
514
+ text-align: inherit;
515
+ opacity: 0;
516
+ -webkit-appearance: none;
517
+ -moz-appearance: none;
518
+ appearance: none;
519
+
520
+ &:not(.resizable) {
521
+ resize: none;
522
+ }
523
+ }
524
+
525
+ .textarea--clearable .textarea__clear-button {
526
+ position: absolute;
527
+ top: var(--svelte-ui-textarea-icon-top);
528
+ right: 4px;
529
+ opacity: 0;
530
+ transition: var(--svelte-ui-transition-duration);
531
+ }
532
+
533
+ /* =============================================
534
+ * レイアウトバリエーション
535
+ * ============================================= */
536
+ .textarea--full-width {
537
+ width: 100%;
538
+ }
539
+
540
+ .textarea--auto-resize {
541
+ textarea {
542
+ overflow-y: auto;
543
+ }
544
+ }
545
+
546
+ .textarea:not(.textarea--auto-resize) {
547
+ .textarea__display-text {
548
+ display: none;
549
+ }
550
+
551
+ textarea {
552
+ position: static;
553
+ height: auto;
554
+ }
555
+ }
556
+
557
+ /* =============================================
558
+ * 機能バリエーション
559
+ * ============================================= */
560
+ .textarea--clearable {
561
+ textarea,
562
+ .textarea__display-text {
563
+ padding-right: var(--svelte-ui-textarea-icon-space);
564
+ }
565
+ }
566
+
567
+ @media (hover: hover) {
568
+ .textarea--clearable:hover .textarea__clear-button {
569
+ opacity: 1;
570
+ }
571
+ }
572
+
573
+ @media (hover: none) {
574
+ .textarea--clearable .textarea__clear-button {
575
+ opacity: 1;
576
+ }
577
+ }
578
+
579
+ /* =============================================
580
+ * プレースホルダー・テキスト表示
581
+ * ============================================= */
582
+ textarea::placeholder,
583
+ .textarea__display-text:empty::before {
584
+ color: var(--svelte-ui-textarea-placeholder-color);
585
+ }
586
+
587
+ /* =============================================
588
+ * フォーカス効果バリエーション
589
+ * ============================================= */
590
+ .textarea--focus-outline textarea:focus {
591
+ outline: var(--svelte-ui-focus-outline-inner);
592
+ outline-offset: var(--svelte-ui-focus-outline-offset-inner);
593
+ }
594
+
595
+ .textarea--focus-background textarea:focus {
596
+ background: var(--svelte-ui-hover-overlay);
597
+ outline: none;
598
+ }
599
+
600
+ .textarea--focus-none textarea:focus {
601
+ outline: none;
602
+ }
603
+
604
+ /* =============================================
605
+ * 状態管理(disabled, readonly等)
606
+ * ============================================= */
607
+ .textarea--disabled {
608
+ opacity: var(--svelte-ui-input-disabled-opacity);
609
+ pointer-events: none;
610
+ }
611
+
612
+ .textarea--readonly {
613
+ textarea {
614
+ cursor: default;
615
+ }
616
+ }
617
+
618
+ textarea:disabled {
619
+ opacity: var(--svelte-ui-button-disabled-opacity);
620
+ cursor: not-allowed;
621
+ }
622
+
623
+ textarea[readonly] {
624
+ background-color: var(--svelte-ui-input-readonly-bg);
625
+ cursor: default;
626
+ }
627
+
628
+ /* =============================================
629
+ * 表示切り替え(フォーカス時・非autoResize時)
630
+ * ============================================= */
631
+ .textarea--focused,
632
+ .textarea:not(.textarea--inline) {
633
+ .textarea__display-text {
634
+ opacity: 0;
635
+ }
636
+
637
+ textarea {
638
+ opacity: 1;
639
+ }
640
+ }
641
+
642
+ /* =============================================
643
+ * デザインバリアント:default
644
+ * ============================================= */
645
+ .textarea:not(.textarea--inline) {
646
+ .textarea__display-text {
647
+ padding: var(--svelte-ui-textarea-padding);
648
+ }
649
+
650
+ textarea {
651
+ position: static;
652
+ padding: var(--svelte-ui-textarea-padding);
653
+ background-color: var(--svelte-ui-textarea-bg);
654
+ box-shadow: 0 0 0 var(--svelte-ui-border-width) inset var(--svelte-ui-textarea-border-color);
655
+ border: none;
656
+ border-radius: var(--svelte-ui-textarea-border-radius);
657
+ color: var(--svelte-ui-textarea-text-color);
658
+ }
659
+
660
+ &.textarea--clearable {
661
+ textarea {
662
+ padding-right: var(--svelte-ui-textarea-icon-space);
663
+ }
664
+ }
665
+ }
666
+
667
+ /* =============================================
668
+ * デザインバリアント:rounded
669
+ * ============================================= */
670
+ .textarea--rounded:not(.textarea--inline) {
671
+ textarea {
672
+ border-radius: var(--svelte-ui-textarea-border-radius-rounded);
673
+ }
674
+ }
675
+
676
+ /* =============================================
677
+ * デザインバリアント:inline
678
+ * ============================================= */
679
+ .textarea--inline {
680
+ .textarea__display-text {
681
+ opacity: 1;
682
+ }
683
+
684
+ textarea {
685
+ opacity: 0;
686
+ }
687
+
688
+ &.textarea--focused {
689
+ .textarea__display-text {
690
+ opacity: 0;
691
+ }
692
+
693
+ textarea {
694
+ opacity: 1;
695
+ }
696
+ }
697
+
698
+ &.textarea--clearable .textarea__clear-button {
699
+ top: var(--svelte-ui-textarea-icon-top-inline);
700
+ }
701
+ }
702
+ </style>