@immich/ui 0.65.1 → 0.65.3
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.
|
@@ -12,8 +12,10 @@
|
|
|
12
12
|
containerRef = $bindable(null),
|
|
13
13
|
shape = 'semi-round',
|
|
14
14
|
size: initialSize,
|
|
15
|
+
variant = 'input',
|
|
15
16
|
class: className,
|
|
16
|
-
|
|
17
|
+
rows = variant === 'ghost' ? 1 : undefined,
|
|
18
|
+
grow = variant === 'ghost',
|
|
17
19
|
value = $bindable<string>(),
|
|
18
20
|
...restProps
|
|
19
21
|
}: TextareaProps = $props();
|
|
@@ -22,18 +24,35 @@
|
|
|
22
24
|
const { label, description, readOnly, required, invalid, disabled, ...labelProps } = $derived(context());
|
|
23
25
|
const size = $derived(initialSize ?? labelProps.size ?? 'small');
|
|
24
26
|
|
|
25
|
-
const
|
|
26
|
-
base: '
|
|
27
|
+
const commonStyles = tv({
|
|
28
|
+
base: 'w-full outline-none disabled:cursor-not-allowed',
|
|
29
|
+
variants: {
|
|
30
|
+
textSize: styleVariants.textSize,
|
|
31
|
+
grow: { true: 'resize-none', false: '' },
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const ghostStyles = tv({
|
|
36
|
+
base: 'pb-2',
|
|
37
|
+
variants: {
|
|
38
|
+
state: {
|
|
39
|
+
active:
|
|
40
|
+
'hover:border-b-light-200 focus-within:hover:border-primary focus-within:border-primary focus-within:border-b-2 hover:border-b-2',
|
|
41
|
+
error: 'border-b-danger border-b-2',
|
|
42
|
+
disabled: '',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const inputStyles = tv({
|
|
48
|
+
base: 'focus-within:ring-primary dark:focus-within:ring-primary bg-gray-100 ring-1 ring-gray-200 focus-within:ring-1 disabled:bg-gray-300 disabled:text-gray-400 dark:bg-gray-800 dark:ring-black dark:disabled:bg-gray-800 dark:disabled:text-gray-200',
|
|
27
49
|
variants: {
|
|
28
50
|
shape: styleVariants.shape,
|
|
29
51
|
padding: {
|
|
30
52
|
base: 'px-4 py-3',
|
|
31
53
|
round: 'px-5 py-3',
|
|
32
54
|
},
|
|
33
|
-
|
|
34
|
-
true: 'resize-none',
|
|
35
|
-
false: '',
|
|
36
|
-
},
|
|
55
|
+
invalid: { true: 'border-danger/80 border', false: '' },
|
|
37
56
|
roundedSize: {
|
|
38
57
|
tiny: 'rounded-xl',
|
|
39
58
|
small: 'rounded-xl',
|
|
@@ -41,11 +60,6 @@
|
|
|
41
60
|
large: 'rounded-2xl',
|
|
42
61
|
giant: 'rounded-2xl',
|
|
43
62
|
},
|
|
44
|
-
textSize: styleVariants.textSize,
|
|
45
|
-
invalid: {
|
|
46
|
-
true: 'border-danger/80 border',
|
|
47
|
-
false: '',
|
|
48
|
-
},
|
|
49
63
|
},
|
|
50
64
|
});
|
|
51
65
|
|
|
@@ -54,21 +68,38 @@
|
|
|
54
68
|
const labelId = `label-${id}`;
|
|
55
69
|
const descriptionId = $derived(description ? `description-${id}` : undefined);
|
|
56
70
|
|
|
71
|
+
const parseStyleNumber = (raw: string) => {
|
|
72
|
+
if (raw === 'none') {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const value = Number.parseFloat(raw);
|
|
77
|
+
if (Number.isNaN(value)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return value;
|
|
82
|
+
};
|
|
83
|
+
|
|
57
84
|
const autogrow = (element: HTMLTextAreaElement | null) => {
|
|
58
85
|
if (element && grow) {
|
|
59
86
|
element.style.minHeight = '0';
|
|
60
87
|
element.style.height = 'auto';
|
|
61
|
-
|
|
88
|
+
|
|
89
|
+
const style = getComputedStyle(element);
|
|
90
|
+
const borderTopWidth = parseStyleNumber(style.borderTopWidth) ?? 0;
|
|
91
|
+
const borderBottomWidth = parseStyleNumber(style.borderBottomWidth) ?? 0;
|
|
92
|
+
const height = element.scrollHeight + borderTopWidth + borderBottomWidth;
|
|
93
|
+
|
|
94
|
+
element.style.height = `${height}px`;
|
|
62
95
|
|
|
63
96
|
// Show scrollbar only if there is a max-height and content exceeds it
|
|
64
|
-
const maxHeight =
|
|
97
|
+
const maxHeight = parseStyleNumber(style.maxHeight);
|
|
65
98
|
const hasMaxHeight = maxHeight !== undefined;
|
|
66
|
-
if (hasMaxHeight &&
|
|
99
|
+
if (hasMaxHeight && height > maxHeight) {
|
|
67
100
|
element.style.overflow = 'auto';
|
|
68
|
-
} else if (hasMaxHeight && element.scrollHeight <= maxHeight) {
|
|
69
|
-
element.style.overflow = 'hidden';
|
|
70
101
|
} else {
|
|
71
|
-
element.style.overflow = '';
|
|
102
|
+
element.style.overflow = 'hidden';
|
|
72
103
|
}
|
|
73
104
|
}
|
|
74
105
|
};
|
|
@@ -99,15 +130,17 @@
|
|
|
99
130
|
aria-describedby={descriptionId}
|
|
100
131
|
readonly={readOnly}
|
|
101
132
|
aria-readonly={readOnly}
|
|
133
|
+
{rows}
|
|
102
134
|
class={cleanClass(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
135
|
+
commonStyles({ textSize: size, grow }),
|
|
136
|
+
variant === 'input' &&
|
|
137
|
+
inputStyles({
|
|
138
|
+
shape,
|
|
139
|
+
invalid,
|
|
140
|
+
padding: shape === 'round' ? 'round' : 'base',
|
|
141
|
+
roundedSize: shape === 'semi-round' ? size : undefined,
|
|
142
|
+
}),
|
|
143
|
+
variant === 'ghost' && ghostStyles({ state: invalid ? 'error' : disabled || readOnly ? 'disabled' : 'active' }),
|
|
111
144
|
className,
|
|
112
145
|
)}
|
|
113
146
|
bind:this={ref}
|
|
@@ -102,16 +102,20 @@
|
|
|
102
102
|
</DatePicker.Segment>
|
|
103
103
|
{/each}
|
|
104
104
|
</div>
|
|
105
|
-
<DatePicker.Trigger
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
105
|
+
<DatePicker.Trigger>
|
|
106
|
+
{#snippet child({ props })}
|
|
107
|
+
<IconButton
|
|
108
|
+
{...props}
|
|
109
|
+
class="me-2 shrink-0 rounded-full"
|
|
110
|
+
variant="ghost"
|
|
111
|
+
shape="round"
|
|
112
|
+
color="secondary"
|
|
113
|
+
{size}
|
|
114
|
+
icon={mdiCalendar}
|
|
115
|
+
{disabled}
|
|
116
|
+
aria-label={t('open_calendar')}
|
|
117
|
+
/>
|
|
118
|
+
{/snippet}
|
|
115
119
|
</DatePicker.Trigger>
|
|
116
120
|
{/snippet}
|
|
117
121
|
</DatePicker.Input>
|
package/dist/types.d.ts
CHANGED
|
@@ -159,6 +159,7 @@ export type PasswordInputProps = BaseInputProps<string> & {
|
|
|
159
159
|
export type TextareaProps = {
|
|
160
160
|
ref?: HTMLTextAreaElement | null;
|
|
161
161
|
containerRef?: HTMLElement | null;
|
|
162
|
+
variant?: 'input' | 'ghost';
|
|
162
163
|
class?: string;
|
|
163
164
|
value?: string;
|
|
164
165
|
size?: Size;
|