@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
- grow,
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 styles = tv({
26
- base: 'focus-within:ring-primary dark:focus-within:ring-primary w-full bg-gray-100 ring-1 ring-gray-200 outline-none focus-within:ring-1 disabled:cursor-not-allowed 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
+ 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
- grow: {
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
- element.style.height = `${element.scrollHeight}px`;
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 = Number.parseFloat(getComputedStyle(element).maxHeight);
97
+ const maxHeight = parseStyleNumber(style.maxHeight);
65
98
  const hasMaxHeight = maxHeight !== undefined;
66
- if (hasMaxHeight && element.scrollHeight > maxHeight) {
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
- styles({
104
- shape,
105
- textSize: size,
106
- padding: shape === 'round' ? 'round' : 'base',
107
- grow,
108
- roundedSize: shape === 'semi-round' ? size : undefined,
109
- invalid,
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 class="mr-2 rounded-full">
106
- <IconButton
107
- variant="ghost"
108
- shape="round"
109
- color="secondary"
110
- {size}
111
- icon={mdiCalendar}
112
- {disabled}
113
- aria-label={t('open_calendar')}
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immich/ui",
3
- "version": "0.65.1",
3
+ "version": "0.65.3",
4
4
  "license": "GNU Affero General Public License version 3",
5
5
  "repository": {
6
6
  "type": "git",