@14ch/svelte-ui 0.0.15 → 0.0.16
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.
- package/dist/assets/styles/variables.scss +5 -7
- package/dist/components/Combobox.svelte +2 -2
- package/dist/components/IconButton.svelte +1 -1
- package/dist/components/Input.svelte +456 -234
- package/dist/components/Input.svelte.d.ts +16 -0
- package/dist/components/Textarea.svelte +234 -161
- package/dist/components/Textarea.svelte.d.ts +7 -3
- package/dist/components/skeleton/Skeleton.svelte +48 -6
- package/dist/i18n/index.d.ts +48 -0
- package/dist/i18n/locales/de.d.ts +8 -0
- package/dist/i18n/locales/de.js +10 -2
- package/dist/i18n/locales/en.d.ts +8 -0
- package/dist/i18n/locales/en.js +10 -2
- package/dist/i18n/locales/es.d.ts +8 -0
- package/dist/i18n/locales/es.js +10 -2
- package/dist/i18n/locales/fr.d.ts +8 -0
- package/dist/i18n/locales/fr.js +10 -2
- package/dist/i18n/locales/ja.d.ts +8 -0
- package/dist/i18n/locales/ja.js +10 -2
- package/dist/i18n/locales/zh-cn.d.ts +8 -0
- package/dist/i18n/locales/zh-cn.js +10 -2
- package/package.json +1 -1
|
@@ -14,6 +14,8 @@ export type InputProps = {
|
|
|
14
14
|
max?: number | null;
|
|
15
15
|
step?: number | null;
|
|
16
16
|
size?: number | null;
|
|
17
|
+
decimalPlaces?: number | null;
|
|
18
|
+
enableThousandsSeparator?: boolean;
|
|
17
19
|
autocomplete?: HTMLInputElement['autocomplete'] | null;
|
|
18
20
|
spellcheck?: boolean | null;
|
|
19
21
|
inputAttributes?: HTMLInputAttributes | undefined;
|
|
@@ -41,6 +43,8 @@ export type InputProps = {
|
|
|
41
43
|
required?: boolean;
|
|
42
44
|
clearable?: boolean;
|
|
43
45
|
linkify?: boolean;
|
|
46
|
+
enablePasswordVisibilityToggle?: boolean;
|
|
47
|
+
enableNumberStepper?: boolean;
|
|
44
48
|
onfocus?: FocusHandler;
|
|
45
49
|
onblur?: FocusHandler;
|
|
46
50
|
onkeydown?: KeyboardHandler;
|
|
@@ -68,6 +72,18 @@ export type InputProps = {
|
|
|
68
72
|
oninput?: BivariantValueHandler<string | number>;
|
|
69
73
|
onRightIconClick?: MouseHandler;
|
|
70
74
|
onLeftIconClick?: MouseHandler;
|
|
75
|
+
onRightIconMouseDown?: MouseHandler;
|
|
76
|
+
onLeftIconMouseDown?: MouseHandler;
|
|
77
|
+
onRightIconMouseUp?: MouseHandler;
|
|
78
|
+
onLeftIconMouseUp?: MouseHandler;
|
|
79
|
+
onRightIconMouseLeave?: MouseHandler;
|
|
80
|
+
onLeftIconMouseLeave?: MouseHandler;
|
|
81
|
+
onRightIconTouchStart?: TouchHandler;
|
|
82
|
+
onLeftIconTouchStart?: TouchHandler;
|
|
83
|
+
onRightIconTouchEnd?: TouchHandler;
|
|
84
|
+
onLeftIconTouchEnd?: TouchHandler;
|
|
85
|
+
onRightIconTouchCancel?: TouchHandler;
|
|
86
|
+
onLeftIconTouchCancel?: TouchHandler;
|
|
71
87
|
[key: string]: any;
|
|
72
88
|
};
|
|
73
89
|
declare const Input: import("svelte").Component<InputProps, {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { t } from '../i18n';
|
|
7
7
|
import { convertToHtml, convertToHtmlWithLink } from '../utils/formatText';
|
|
8
8
|
import type { HTMLTextareaAttributes } from 'svelte/elements';
|
|
9
|
-
import type { IconVariant } from '../types/icon';
|
|
9
|
+
import type { IconVariant, IconWeight, IconGrade, IconOpticalSize } from '../types/icon';
|
|
10
10
|
import type {
|
|
11
11
|
FocusHandler,
|
|
12
12
|
KeyboardHandler,
|
|
@@ -47,15 +47,21 @@
|
|
|
47
47
|
rounded?: boolean;
|
|
48
48
|
customStyle?: string;
|
|
49
49
|
|
|
50
|
+
// アイコン関連
|
|
51
|
+
clearButtonAriaLabel?: string;
|
|
52
|
+
iconFilled?: boolean;
|
|
53
|
+
iconWeight?: IconWeight;
|
|
54
|
+
iconGrade?: IconGrade;
|
|
55
|
+
iconOpticalSize?: IconOpticalSize;
|
|
56
|
+
iconVariant?: IconVariant;
|
|
57
|
+
|
|
50
58
|
// 状態/動作
|
|
51
59
|
disabled?: boolean;
|
|
52
60
|
autoResize?: boolean;
|
|
53
61
|
resizable?: boolean;
|
|
54
62
|
clearable?: boolean;
|
|
55
|
-
clearButtonAriaLabel?: string;
|
|
56
63
|
readonly?: boolean;
|
|
57
64
|
required?: boolean;
|
|
58
|
-
iconVariant?: IconVariant;
|
|
59
65
|
linkify?: boolean;
|
|
60
66
|
|
|
61
67
|
// フォーカスイベント
|
|
@@ -127,15 +133,21 @@
|
|
|
127
133
|
rounded = false,
|
|
128
134
|
customStyle = '',
|
|
129
135
|
|
|
136
|
+
// アイコン関連
|
|
137
|
+
clearButtonAriaLabel = t('input.clear'),
|
|
138
|
+
iconFilled = false,
|
|
139
|
+
iconWeight = 300,
|
|
140
|
+
iconGrade = 0,
|
|
141
|
+
iconOpticalSize = 24,
|
|
142
|
+
iconVariant = 'outlined',
|
|
143
|
+
|
|
130
144
|
// 状態/動作
|
|
131
145
|
disabled = false,
|
|
132
146
|
autoResize = true,
|
|
133
147
|
resizable = false,
|
|
134
148
|
clearable = false,
|
|
135
|
-
clearButtonAriaLabel = t('input.clear'),
|
|
136
149
|
readonly = false,
|
|
137
150
|
required = false,
|
|
138
|
-
iconVariant = 'outlined',
|
|
139
151
|
linkify = false,
|
|
140
152
|
|
|
141
153
|
// フォーカスイベント
|
|
@@ -179,10 +191,38 @@
|
|
|
179
191
|
...restProps
|
|
180
192
|
}: TextareaProps = $props();
|
|
181
193
|
|
|
182
|
-
let
|
|
194
|
+
let textareaRef: HTMLTextAreaElement | null = null;
|
|
195
|
+
let containerRef: HTMLDivElement | null = null;
|
|
183
196
|
let displayTextRef: HTMLDivElement | null = $state(null);
|
|
184
197
|
let linkTextRef: HTMLDivElement | null = $state(null);
|
|
185
198
|
let isFocused: boolean = $state(false);
|
|
199
|
+
let resizeObserver: ResizeObserver | null = null;
|
|
200
|
+
|
|
201
|
+
// =========================================================================
|
|
202
|
+
// $effect
|
|
203
|
+
// =========================================================================
|
|
204
|
+
// autoResize=false のとき、コンポーネント全体のサイズに display-text / link-text を合わせる
|
|
205
|
+
$effect(() => {
|
|
206
|
+
if (!containerRef || !displayTextRef || !textareaRef) {
|
|
207
|
+
cleanupSizeSync();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// autoResize=true のときは、サイズ同期を行わず従来の挙動を維持
|
|
212
|
+
if (autoResize) {
|
|
213
|
+
cleanupSizeSync();
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// 初期同期
|
|
218
|
+
syncSizeFromTextarea();
|
|
219
|
+
// resizable=true のときにのみ ResizeObserver をセットアップ
|
|
220
|
+
setupResizeObserver();
|
|
221
|
+
|
|
222
|
+
return () => {
|
|
223
|
+
cleanupSizeSync();
|
|
224
|
+
};
|
|
225
|
+
});
|
|
186
226
|
|
|
187
227
|
// =========================================================================
|
|
188
228
|
// Methods
|
|
@@ -190,16 +230,16 @@
|
|
|
190
230
|
const clear = (): void => {
|
|
191
231
|
if (disabled || readonly) return;
|
|
192
232
|
value = '';
|
|
193
|
-
|
|
233
|
+
textareaRef?.focus();
|
|
194
234
|
onchange?.('');
|
|
195
235
|
};
|
|
196
236
|
|
|
197
237
|
// 外部からフォーカスを当てる(キャレットを先頭に移動)
|
|
198
238
|
export const focus = () => {
|
|
199
|
-
if (
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
239
|
+
if (textareaRef) {
|
|
240
|
+
textareaRef.focus();
|
|
241
|
+
textareaRef.setSelectionRange(0, 0);
|
|
242
|
+
textareaRef.scrollTop = 0;
|
|
203
243
|
}
|
|
204
244
|
};
|
|
205
245
|
|
|
@@ -334,8 +374,8 @@
|
|
|
334
374
|
|
|
335
375
|
// スクロール同期
|
|
336
376
|
const handleScroll = () => {
|
|
337
|
-
if (!
|
|
338
|
-
const scrollTop =
|
|
377
|
+
if (!textareaRef) return;
|
|
378
|
+
const scrollTop = textareaRef.scrollTop;
|
|
339
379
|
if (displayTextRef) {
|
|
340
380
|
displayTextRef.scrollTop = scrollTop;
|
|
341
381
|
}
|
|
@@ -344,15 +384,89 @@
|
|
|
344
384
|
}
|
|
345
385
|
};
|
|
346
386
|
|
|
387
|
+
// resizable=true のときに textarea のサイズ変更を監視
|
|
388
|
+
const setupResizeObserver = () => {
|
|
389
|
+
if (!textareaRef) return;
|
|
390
|
+
|
|
391
|
+
// resizable でなければ監視は不要
|
|
392
|
+
if (!resizable) {
|
|
393
|
+
if (resizeObserver) {
|
|
394
|
+
resizeObserver.disconnect();
|
|
395
|
+
resizeObserver = null;
|
|
396
|
+
}
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// 既存のオブザーバがあれば一旦解除
|
|
401
|
+
if (resizeObserver) {
|
|
402
|
+
resizeObserver.disconnect();
|
|
403
|
+
resizeObserver = null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
resizeObserver = new ResizeObserver(() => {
|
|
407
|
+
// ユーザーのリサイズ後は textarea の幅でコンテナ幅を上書きする
|
|
408
|
+
syncSizeFromTextarea({ forceWidth: true });
|
|
409
|
+
});
|
|
410
|
+
resizeObserver.observe(textareaRef);
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// --------------------------------
|
|
414
|
+
// display-text / link-text と textarea のサイズ同期
|
|
415
|
+
// --------------------------------
|
|
416
|
+
// サイズ同期
|
|
417
|
+
const syncSizeFromTextarea = ({ forceWidth = false }: { forceWidth?: boolean } = {}) => {
|
|
418
|
+
if (!containerRef || !displayTextRef || !textareaRef) return;
|
|
419
|
+
const rect = textareaRef.getBoundingClientRect();
|
|
420
|
+
const height = rect.height;
|
|
421
|
+
const width = rect.width;
|
|
422
|
+
if (!height || !width) return;
|
|
423
|
+
|
|
424
|
+
// コンポーネント全体の高さは textarea に合わせる
|
|
425
|
+
containerRef.style.height = `${height}px`;
|
|
426
|
+
|
|
427
|
+
// 幅は、初期状態では width プロップを優先し、
|
|
428
|
+
// ユーザーがリサイズ(ResizeObserver 経由)したあとは textarea の幅で上書きする
|
|
429
|
+
if (forceWidth || !widthStyle) {
|
|
430
|
+
containerRef.style.width = `${width}px`;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// display-text / link-text はコンテナにフィットさせる
|
|
434
|
+
displayTextRef.style.height = '100%';
|
|
435
|
+
displayTextRef.style.width = '100%';
|
|
436
|
+
if (linkTextRef) {
|
|
437
|
+
linkTextRef.style.height = '100%';
|
|
438
|
+
linkTextRef.style.width = '100%';
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
// サイズ同期を解除
|
|
443
|
+
const cleanupSizeSync = () => {
|
|
444
|
+
if (resizeObserver) {
|
|
445
|
+
resizeObserver.disconnect();
|
|
446
|
+
resizeObserver = null;
|
|
447
|
+
}
|
|
448
|
+
if (containerRef) {
|
|
449
|
+
containerRef.style.removeProperty('height');
|
|
450
|
+
// width は width プロップで制御されるため、ここでは削除しない
|
|
451
|
+
}
|
|
452
|
+
if (displayTextRef) {
|
|
453
|
+
displayTextRef.style.removeProperty('height');
|
|
454
|
+
displayTextRef.style.removeProperty('width');
|
|
455
|
+
}
|
|
456
|
+
if (linkTextRef) {
|
|
457
|
+
linkTextRef.style.removeProperty('height');
|
|
458
|
+
linkTextRef.style.removeProperty('width');
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
|
|
347
462
|
// =========================================================================
|
|
348
463
|
// $derived
|
|
349
464
|
// =========================================================================
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
465
|
+
// --------------------------------
|
|
466
|
+
// display & link value
|
|
467
|
+
// --------------------------------
|
|
354
468
|
// HTML表示用の値(autoResize時の高さ調整用)
|
|
355
|
-
const
|
|
469
|
+
const displayValue = $derived.by(() => {
|
|
356
470
|
const normalizedValue = value ?? '';
|
|
357
471
|
if (normalizedValue !== '') {
|
|
358
472
|
const converted = convertToHtml(normalizedValue);
|
|
@@ -364,9 +478,9 @@
|
|
|
364
478
|
}
|
|
365
479
|
return html;
|
|
366
480
|
} else {
|
|
367
|
-
// inline かつ value
|
|
481
|
+
// inline かつ value が空のとき
|
|
368
482
|
// 1行分の高さを確保するためにダミーの を入れる
|
|
369
|
-
if (inline
|
|
483
|
+
if (inline) {
|
|
370
484
|
return ' ';
|
|
371
485
|
}
|
|
372
486
|
return '';
|
|
@@ -382,9 +496,17 @@
|
|
|
382
496
|
const result = convertToHtmlWithLink(normalizedValue);
|
|
383
497
|
return String(result ?? '');
|
|
384
498
|
});
|
|
499
|
+
|
|
500
|
+
// --------------------------------
|
|
501
|
+
// style from number
|
|
502
|
+
// --------------------------------
|
|
503
|
+
const minHeightStyle = $derived(getStyleFromNumber(minHeight));
|
|
504
|
+
const maxHeightStyle = $derived(getStyleFromNumber(maxHeight));
|
|
505
|
+
const widthStyle = $derived(getStyleFromNumber(width));
|
|
385
506
|
</script>
|
|
386
507
|
|
|
387
508
|
<div
|
|
509
|
+
bind:this={containerRef}
|
|
388
510
|
class="textarea
|
|
389
511
|
textarea--focus-{focusStyle}"
|
|
390
512
|
class:textarea--inline={inline}
|
|
@@ -398,23 +520,21 @@
|
|
|
398
520
|
class:textarea--readonly={readonly}
|
|
399
521
|
class:textarea--focused={isFocused}
|
|
400
522
|
data-testid="textarea"
|
|
401
|
-
style={!inline ? `max-height: ${maxHeightStyle};` : ''}
|
|
523
|
+
style="width: {widthStyle}; {!inline ? `max-height: ${maxHeightStyle};` : ''}"
|
|
402
524
|
>
|
|
403
|
-
<!-- autoResize時の表示用要素(HTMLレンダリングで高さ調整) -->
|
|
404
525
|
<div
|
|
405
526
|
bind:this={displayTextRef}
|
|
406
527
|
class="textarea__display-text"
|
|
407
|
-
data-placeholder={placeholder}
|
|
408
528
|
style="min-height: {minHeightStyle}; max-height: {maxHeightStyle}; {customStyle}"
|
|
409
529
|
>
|
|
410
|
-
{@html
|
|
530
|
+
{@html displayValue}
|
|
411
531
|
</div>
|
|
412
532
|
<div class="textarea__wrapper">
|
|
413
533
|
<textarea
|
|
414
534
|
{id}
|
|
415
535
|
{name}
|
|
416
536
|
bind:value
|
|
417
|
-
bind:this={
|
|
537
|
+
bind:this={textareaRef}
|
|
418
538
|
{rows}
|
|
419
539
|
{placeholder}
|
|
420
540
|
{disabled}
|
|
@@ -427,7 +547,7 @@
|
|
|
427
547
|
{spellcheck}
|
|
428
548
|
{autocapitalize}
|
|
429
549
|
class:resizable
|
|
430
|
-
style="min-height: {minHeightStyle};
|
|
550
|
+
style="min-height: {minHeightStyle}; {customStyle}"
|
|
431
551
|
onchange={handleChange}
|
|
432
552
|
oninput={handleInput}
|
|
433
553
|
onfocus={handleFocus}
|
|
@@ -472,13 +592,13 @@
|
|
|
472
592
|
<div class="textarea__clear-button">
|
|
473
593
|
<IconButton
|
|
474
594
|
ariaLabel={clearButtonAriaLabel}
|
|
475
|
-
color="var(--svelte-ui-
|
|
595
|
+
color="var(--svelte-ui-textarea-icon-color)"
|
|
476
596
|
onclick={(event) => {
|
|
477
597
|
event.stopPropagation();
|
|
478
598
|
clear();
|
|
479
599
|
}}
|
|
480
600
|
tabindex={-1}
|
|
481
|
-
iconFilled
|
|
601
|
+
{iconFilled}
|
|
482
602
|
{iconVariant}
|
|
483
603
|
fontSize={18}>cancel</IconButton
|
|
484
604
|
>
|
|
@@ -519,10 +639,35 @@
|
|
|
519
639
|
/* =============================================
|
|
520
640
|
* 基本コンポーネント
|
|
521
641
|
* ============================================= */
|
|
642
|
+
textarea {
|
|
643
|
+
width: 100%;
|
|
644
|
+
height: auto;
|
|
645
|
+
min-height: var(--svelte-ui-textarea-min-height);
|
|
646
|
+
padding: var(--svelte-ui-textarea-padding);
|
|
647
|
+
background-color: var(--svelte-ui-textarea-bg);
|
|
648
|
+
box-shadow: 0 0 0 var(--svelte-ui-border-width) inset var(--svelte-ui-textarea-border-color);
|
|
649
|
+
border: none;
|
|
650
|
+
border-radius: var(--svelte-ui-textarea-border-radius);
|
|
651
|
+
font-size: inherit;
|
|
652
|
+
font-weight: inherit;
|
|
653
|
+
color: inherit;
|
|
654
|
+
line-height: inherit;
|
|
655
|
+
text-align: inherit;
|
|
656
|
+
-webkit-appearance: none;
|
|
657
|
+
-moz-appearance: none;
|
|
658
|
+
appearance: none;
|
|
659
|
+
|
|
660
|
+
&:not(.resizable) {
|
|
661
|
+
resize: none;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
522
665
|
.textarea__display-text,
|
|
523
666
|
.textarea__link-text {
|
|
524
667
|
display: block;
|
|
525
668
|
width: 100%;
|
|
669
|
+
min-height: var(--svelte-ui-textarea-min-height);
|
|
670
|
+
padding: var(--svelte-ui-textarea-padding);
|
|
526
671
|
background: inherit;
|
|
527
672
|
border: inherit;
|
|
528
673
|
font-size: inherit;
|
|
@@ -559,40 +704,10 @@
|
|
|
559
704
|
left: 0;
|
|
560
705
|
width: 100%;
|
|
561
706
|
height: 100%;
|
|
562
|
-
padding: inherit;
|
|
563
707
|
pointer-events: none;
|
|
564
708
|
z-index: 1;
|
|
565
709
|
}
|
|
566
710
|
|
|
567
|
-
.textarea__link-text :global(a) {
|
|
568
|
-
pointer-events: auto;
|
|
569
|
-
text-decoration: underline;
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
textarea {
|
|
573
|
-
position: absolute;
|
|
574
|
-
top: 0;
|
|
575
|
-
left: 0;
|
|
576
|
-
width: 100%;
|
|
577
|
-
height: 100%;
|
|
578
|
-
padding: inherit;
|
|
579
|
-
background: transparent;
|
|
580
|
-
border: none;
|
|
581
|
-
font-size: inherit;
|
|
582
|
-
font-weight: inherit;
|
|
583
|
-
color: inherit;
|
|
584
|
-
line-height: inherit;
|
|
585
|
-
text-align: inherit;
|
|
586
|
-
opacity: 0;
|
|
587
|
-
-webkit-appearance: none;
|
|
588
|
-
-moz-appearance: none;
|
|
589
|
-
appearance: none;
|
|
590
|
-
|
|
591
|
-
&:not(.resizable) {
|
|
592
|
-
resize: none;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
711
|
.textarea--clearable .textarea__clear-button {
|
|
597
712
|
position: absolute;
|
|
598
713
|
top: var(--svelte-ui-textarea-icon-top);
|
|
@@ -610,44 +725,11 @@
|
|
|
610
725
|
|
|
611
726
|
.textarea--auto-resize {
|
|
612
727
|
textarea {
|
|
728
|
+
height: 100%;
|
|
613
729
|
overflow-y: auto;
|
|
614
730
|
}
|
|
615
731
|
}
|
|
616
732
|
|
|
617
|
-
.textarea:not(.textarea--auto-resize) {
|
|
618
|
-
.textarea__display-text {
|
|
619
|
-
display: none;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
textarea {
|
|
623
|
-
position: static;
|
|
624
|
-
height: auto;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
/* =============================================
|
|
629
|
-
* 機能バリエーション
|
|
630
|
-
* ============================================= */
|
|
631
|
-
.textarea--clearable {
|
|
632
|
-
textarea,
|
|
633
|
-
.textarea__display-text,
|
|
634
|
-
.textarea__link-text {
|
|
635
|
-
padding-right: var(--svelte-ui-textarea-icon-space);
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
@media (hover: hover) {
|
|
640
|
-
.textarea--clearable:hover .textarea__clear-button {
|
|
641
|
-
opacity: 1;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
@media (hover: none) {
|
|
646
|
-
.textarea--clearable .textarea__clear-button {
|
|
647
|
-
opacity: 1;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
733
|
/* =============================================
|
|
652
734
|
* プレースホルダー・テキスト表示
|
|
653
735
|
* ============================================= */
|
|
@@ -699,112 +781,103 @@
|
|
|
699
781
|
}
|
|
700
782
|
|
|
701
783
|
/* =============================================
|
|
702
|
-
*
|
|
784
|
+
* 表示切り替え
|
|
703
785
|
* ============================================= */
|
|
704
|
-
.textarea--focused
|
|
705
|
-
|
|
786
|
+
.textarea:not(.textarea--focused) textarea {
|
|
787
|
+
color: transparent;
|
|
788
|
+
caret-color: transparent;
|
|
789
|
+
text-shadow: none;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
.textarea--focused {
|
|
706
793
|
.textarea__display-text {
|
|
707
794
|
opacity: 0;
|
|
708
795
|
}
|
|
709
|
-
|
|
710
|
-
textarea {
|
|
711
|
-
opacity: 1;
|
|
712
|
-
}
|
|
713
796
|
}
|
|
714
797
|
|
|
715
|
-
/*
|
|
716
|
-
|
|
717
|
-
|
|
798
|
+
/* =============================================
|
|
799
|
+
* 機能バリエーション
|
|
800
|
+
* ============================================= */
|
|
801
|
+
/* clearable */
|
|
802
|
+
.textarea--clearable {
|
|
803
|
+
textarea,
|
|
804
|
+
.textarea__display-text,
|
|
805
|
+
.textarea__link-text {
|
|
806
|
+
padding-right: var(--svelte-ui-textarea-icon-space);
|
|
807
|
+
}
|
|
718
808
|
}
|
|
719
809
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
810
|
+
@media (hover: hover) {
|
|
811
|
+
.textarea--clearable:hover .textarea__clear-button {
|
|
812
|
+
opacity: 1;
|
|
813
|
+
}
|
|
723
814
|
}
|
|
724
815
|
|
|
725
|
-
|
|
726
|
-
|
|
816
|
+
@media (hover: none) {
|
|
817
|
+
.textarea--clearable .textarea__clear-button {
|
|
818
|
+
opacity: 1;
|
|
819
|
+
}
|
|
727
820
|
}
|
|
728
821
|
|
|
729
|
-
/*
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
.textarea__display-text,
|
|
734
|
-
.textarea__link-text,
|
|
735
|
-
textarea {
|
|
736
|
-
min-height: var(--svelte-ui-textarea-min-height);
|
|
737
|
-
padding: var(--svelte-ui-textarea-padding);
|
|
822
|
+
/* linkify */
|
|
823
|
+
.textarea--linkify {
|
|
824
|
+
.textarea__display-text {
|
|
825
|
+
opacity: 0;
|
|
738
826
|
}
|
|
739
827
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
background-color: var(--svelte-ui-textarea-bg);
|
|
743
|
-
box-shadow: 0 0 0 var(--svelte-ui-border-width) inset var(--svelte-ui-textarea-border-color);
|
|
744
|
-
border: none;
|
|
745
|
-
border-radius: var(--svelte-ui-textarea-border-radius);
|
|
828
|
+
.textarea__link-text :global(a) {
|
|
829
|
+
pointer-events: auto;
|
|
746
830
|
}
|
|
747
831
|
|
|
748
|
-
&.textarea--
|
|
749
|
-
textarea,
|
|
750
|
-
.textarea__display-text,
|
|
832
|
+
&.textarea--focused {
|
|
751
833
|
.textarea__link-text {
|
|
752
|
-
|
|
834
|
+
opacity: 0;
|
|
753
835
|
}
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
836
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
color: transparent;
|
|
762
|
-
caret-color: transparent;
|
|
763
|
-
text-shadow: none;
|
|
837
|
+
:global(a) {
|
|
838
|
+
pointer-events: none;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
764
841
|
}
|
|
765
842
|
|
|
766
843
|
/* =============================================
|
|
767
|
-
*
|
|
844
|
+
* デザインバリエーション
|
|
768
845
|
* ============================================= */
|
|
846
|
+
/* rounded */
|
|
769
847
|
.textarea--rounded:not(.textarea--inline) {
|
|
770
848
|
textarea {
|
|
771
849
|
border-radius: var(--svelte-ui-textarea-border-radius-rounded);
|
|
772
850
|
}
|
|
773
851
|
}
|
|
774
852
|
|
|
775
|
-
/*
|
|
776
|
-
* デザインバリアント:inline
|
|
777
|
-
* ============================================= */
|
|
853
|
+
/* inline */
|
|
778
854
|
.textarea--inline {
|
|
779
|
-
.textarea__display-text
|
|
780
|
-
|
|
781
|
-
}
|
|
782
|
-
|
|
855
|
+
.textarea__display-text,
|
|
856
|
+
.textarea__link-text,
|
|
783
857
|
textarea {
|
|
784
|
-
|
|
858
|
+
min-height: auto;
|
|
859
|
+
padding-top: inherit;
|
|
860
|
+
padding-bottom: inherit;
|
|
861
|
+
padding-left: inherit;
|
|
785
862
|
}
|
|
786
863
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
864
|
+
textarea {
|
|
865
|
+
padding: inherit;
|
|
866
|
+
background: transparent;
|
|
867
|
+
box-shadow: none;
|
|
868
|
+
border-radius: 0;
|
|
869
|
+
font-size: inherit;
|
|
870
|
+
font-weight: inherit;
|
|
871
|
+
color: inherit;
|
|
872
|
+
line-height: inherit;
|
|
873
|
+
text-align: inherit;
|
|
874
|
+
-webkit-appearance: none;
|
|
875
|
+
-moz-appearance: none;
|
|
876
|
+
appearance: none;
|
|
795
877
|
}
|
|
796
878
|
|
|
797
879
|
&.textarea--clearable .textarea__clear-button {
|
|
798
880
|
top: var(--svelte-ui-textarea-icon-top-inline);
|
|
799
881
|
}
|
|
800
882
|
}
|
|
801
|
-
|
|
802
|
-
/* inline + linkify のときは、display-text を常に隠し、textarea を常に表示 */
|
|
803
|
-
.textarea--inline.textarea--linkify .textarea__display-text {
|
|
804
|
-
opacity: 0;
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
.textarea--inline.textarea--linkify textarea {
|
|
808
|
-
opacity: 1;
|
|
809
|
-
}
|
|
810
883
|
</style>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { HTMLTextareaAttributes } from 'svelte/elements';
|
|
2
|
-
import type { IconVariant } from '../types/icon';
|
|
2
|
+
import type { IconVariant, IconWeight, IconGrade, IconOpticalSize } from '../types/icon';
|
|
3
3
|
import type { FocusHandler, KeyboardHandler, MouseHandler, TouchHandler, PointerHandler } from '../types/callbackHandlers';
|
|
4
4
|
import type { FocusStyle } from '../types/propOptions';
|
|
5
5
|
export type TextareaProps = {
|
|
@@ -24,14 +24,18 @@ export type TextareaProps = {
|
|
|
24
24
|
width?: string | number | null;
|
|
25
25
|
rounded?: boolean;
|
|
26
26
|
customStyle?: string;
|
|
27
|
+
clearButtonAriaLabel?: string;
|
|
28
|
+
iconFilled?: boolean;
|
|
29
|
+
iconWeight?: IconWeight;
|
|
30
|
+
iconGrade?: IconGrade;
|
|
31
|
+
iconOpticalSize?: IconOpticalSize;
|
|
32
|
+
iconVariant?: IconVariant;
|
|
27
33
|
disabled?: boolean;
|
|
28
34
|
autoResize?: boolean;
|
|
29
35
|
resizable?: boolean;
|
|
30
36
|
clearable?: boolean;
|
|
31
|
-
clearButtonAriaLabel?: string;
|
|
32
37
|
readonly?: boolean;
|
|
33
38
|
required?: boolean;
|
|
34
|
-
iconVariant?: IconVariant;
|
|
35
39
|
linkify?: boolean;
|
|
36
40
|
onfocus?: FocusHandler;
|
|
37
41
|
onblur?: FocusHandler;
|