@immich/ui 0.65.3 → 0.67.0
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/components/PinInput/PinInput.svelte +124 -0
- package/dist/components/PinInput/PinInput.svelte.d.ts +5 -0
- package/dist/components/Toast/Toast.svelte +12 -2
- package/dist/components/Toast/ToastContainer.svelte +1 -1
- package/dist/components/Toast/ToastContent.svelte +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/types.d.ts +15 -2
- package/package.json +1 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getFieldContext } from '../../common/context.svelte.js';
|
|
3
|
+
import Label from '../Label/Label.svelte';
|
|
4
|
+
import { styleVariants } from '../../styles.js';
|
|
5
|
+
import type { PinInputProps } from '../../types.js';
|
|
6
|
+
import { cleanClass } from '../../utilities/internal.js';
|
|
7
|
+
import { PinInput, REGEXP_ONLY_DIGITS } from 'bits-ui';
|
|
8
|
+
import { tv } from 'tailwind-variants';
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
shape = 'semi-round',
|
|
12
|
+
size: initialSize,
|
|
13
|
+
value = $bindable<string>(''),
|
|
14
|
+
length = 6,
|
|
15
|
+
password,
|
|
16
|
+
onComplete,
|
|
17
|
+
class: className,
|
|
18
|
+
...props
|
|
19
|
+
}: PinInputProps = $props();
|
|
20
|
+
|
|
21
|
+
const context = getFieldContext();
|
|
22
|
+
|
|
23
|
+
const { label, disabled, ...labelProps } = $derived(context());
|
|
24
|
+
const size = $derived(initialSize ?? labelProps.size ?? 'large');
|
|
25
|
+
|
|
26
|
+
const inputStyles = tv({
|
|
27
|
+
base: 'group-has-disabled:text-dark data-active:border-primary dark:data-active:border-primary flex items-center justify-center border-2 bg-gray-100 font-mono transition-all duration-75 group-has-disabled:bg-gray-300 data-active:border-3 dark:bg-gray-800 dark:group-not-has-disabled:border-gray-700 dark:group-has-disabled:bg-gray-900 dark:group-has-disabled:text-gray-200',
|
|
28
|
+
variants: {
|
|
29
|
+
shape: styleVariants.shape,
|
|
30
|
+
size: {
|
|
31
|
+
tiny: 'h-9 w-7',
|
|
32
|
+
small: 'h-10 w-8',
|
|
33
|
+
medium: 'h-11 w-9',
|
|
34
|
+
large: 'h-12 w-10',
|
|
35
|
+
giant: 'h-14 w-12',
|
|
36
|
+
},
|
|
37
|
+
textSize: styleVariants.textSize,
|
|
38
|
+
roundedSize: {
|
|
39
|
+
tiny: 'rounded-lg',
|
|
40
|
+
small: 'rounded-lg',
|
|
41
|
+
medium: 'rounded-xl',
|
|
42
|
+
large: 'rounded-xl',
|
|
43
|
+
giant: 'rounded-2xl',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const caretStyles = tv({
|
|
49
|
+
base: 'caret bg-dark h-1/2',
|
|
50
|
+
variants: {
|
|
51
|
+
size: {
|
|
52
|
+
tiny: 'w-px',
|
|
53
|
+
small: 'w-px',
|
|
54
|
+
medium: 'w-[1.5px]',
|
|
55
|
+
large: 'w-[1.5px]',
|
|
56
|
+
giant: 'w-0.5',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const id = $props.id();
|
|
62
|
+
const inputId = `input-${id}`;
|
|
63
|
+
const labelId = `label-${id}`;
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<div class={cleanClass('flex flex-col gap-1', className)}>
|
|
67
|
+
{#if label}
|
|
68
|
+
<Label id={labelId} for={inputId} {label} {...labelProps} {size} />
|
|
69
|
+
{/if}
|
|
70
|
+
|
|
71
|
+
<PinInput.Root
|
|
72
|
+
{inputId}
|
|
73
|
+
aria-labelledby={label && labelId}
|
|
74
|
+
{disabled}
|
|
75
|
+
aria-disabled={disabled}
|
|
76
|
+
class="group flex w-fit items-center gap-2"
|
|
77
|
+
maxlength={length}
|
|
78
|
+
pattern={REGEXP_ONLY_DIGITS}
|
|
79
|
+
type={password ? 'password' : 'text'}
|
|
80
|
+
{onComplete}
|
|
81
|
+
bind:value
|
|
82
|
+
{...props}
|
|
83
|
+
>
|
|
84
|
+
{#snippet children({ cells })}
|
|
85
|
+
{#each cells as cell, i (i)}
|
|
86
|
+
<PinInput.Cell
|
|
87
|
+
{cell}
|
|
88
|
+
class={inputStyles({
|
|
89
|
+
shape,
|
|
90
|
+
size,
|
|
91
|
+
textSize: size,
|
|
92
|
+
roundedSize: shape === 'semi-round' ? size : undefined,
|
|
93
|
+
})}
|
|
94
|
+
>
|
|
95
|
+
{#if cell.char !== null}
|
|
96
|
+
<div>
|
|
97
|
+
{password ? '●' : cell.char}
|
|
98
|
+
</div>
|
|
99
|
+
{/if}
|
|
100
|
+
{#if cell.hasFakeCaret}
|
|
101
|
+
<div class="absolute flex h-full items-center justify-center">
|
|
102
|
+
<div class={caretStyles({ size })}></div>
|
|
103
|
+
</div>
|
|
104
|
+
{/if}
|
|
105
|
+
</PinInput.Cell>
|
|
106
|
+
{/each}
|
|
107
|
+
{/snippet}
|
|
108
|
+
</PinInput.Root>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<style>
|
|
112
|
+
.caret {
|
|
113
|
+
animation: blink 1.5s step-end infinite;
|
|
114
|
+
}
|
|
115
|
+
@keyframes blink {
|
|
116
|
+
0%,
|
|
117
|
+
100% {
|
|
118
|
+
opacity: 1;
|
|
119
|
+
}
|
|
120
|
+
50% {
|
|
121
|
+
opacity: 0;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
</style>
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import Button from '../Button/Button.svelte';
|
|
2
3
|
import ToastContainer from './ToastContainer.svelte';
|
|
3
4
|
import ToastContent from './ToastContent.svelte';
|
|
4
5
|
import type { ToastProps } from '../../types.js';
|
|
5
6
|
|
|
6
|
-
let { children, title, description, icon, onClose, ...props }: ToastProps = $props();
|
|
7
|
+
let { children, title, description, icon, onClose, button, ...props }: ToastProps = $props();
|
|
7
8
|
</script>
|
|
8
9
|
|
|
9
10
|
<ToastContainer {...props}>
|
|
10
11
|
{#if children}
|
|
11
12
|
{@render children()}
|
|
12
13
|
{:else if title}
|
|
13
|
-
<ToastContent {title} {description} {icon} {onClose} {...props}
|
|
14
|
+
<ToastContent {title} {description} {icon} {onClose} {...props}>
|
|
15
|
+
{#if button}
|
|
16
|
+
{@const { label, ...rest } = button}
|
|
17
|
+
<div class="flex justify-end px-3 pt-2">
|
|
18
|
+
<Button color="secondary" size="small" {...rest}>
|
|
19
|
+
{label}
|
|
20
|
+
</Button>
|
|
21
|
+
</div>
|
|
22
|
+
{/if}
|
|
23
|
+
</ToastContent>
|
|
14
24
|
{/if}
|
|
15
25
|
</ToastContainer>
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
}: ToastContainerProps = $props();
|
|
16
16
|
|
|
17
17
|
const containerStyles = tv({
|
|
18
|
-
base: 'bg-light text-dark overflow-hidden border py-
|
|
18
|
+
base: 'bg-light text-dark overflow-hidden border py-3 shadow-xs transition-all',
|
|
19
19
|
variants: {
|
|
20
20
|
color: {
|
|
21
21
|
primary: 'border-primary-100 bg-primary-50 dark:bg-primary-100 dark:border-primary-200',
|
package/dist/index.d.ts
CHANGED
|
@@ -70,6 +70,7 @@ export { default as NavbarGroup } from './components/Navbar/NavbarGroup.svelte';
|
|
|
70
70
|
export { default as NavbarItem } from './components/Navbar/NavbarItem.svelte';
|
|
71
71
|
export { default as NumberInput } from './components/NumberInput/NumberInput.svelte';
|
|
72
72
|
export { default as PasswordInput } from './components/PasswordInput/PasswordInput.svelte';
|
|
73
|
+
export { default as PinInput } from './components/PinInput/PinInput.svelte';
|
|
73
74
|
export { default as ProgressBar } from './components/ProgressBar/ProgressBar.svelte';
|
|
74
75
|
export { default as Scrollable } from './components/Scrollable/Scrollable.svelte';
|
|
75
76
|
export { default as Select } from './components/Select/Select.svelte';
|
|
@@ -103,9 +104,9 @@ export * from './services/theme.svelte.js';
|
|
|
103
104
|
export * from './services/toast-manager.svelte.js';
|
|
104
105
|
export * from './services/translation.svelte.js';
|
|
105
106
|
export * from './state/locale-state.svelte.js';
|
|
107
|
+
export { isModalOpen } from './state/modal-state.svelte.js';
|
|
106
108
|
export * from './types.js';
|
|
107
109
|
export * from './utilities/byte-units.js';
|
|
108
110
|
export * from './utilities/common.js';
|
|
109
|
-
export { isModalOpen } from './state/modal-state.svelte.js';
|
|
110
111
|
export * from './site/constants.js';
|
|
111
112
|
export { default as SiteFooter } from './site/SiteFooter.svelte';
|
package/dist/index.js
CHANGED
|
@@ -72,6 +72,7 @@ export { default as NavbarGroup } from './components/Navbar/NavbarGroup.svelte';
|
|
|
72
72
|
export { default as NavbarItem } from './components/Navbar/NavbarItem.svelte';
|
|
73
73
|
export { default as NumberInput } from './components/NumberInput/NumberInput.svelte';
|
|
74
74
|
export { default as PasswordInput } from './components/PasswordInput/PasswordInput.svelte';
|
|
75
|
+
export { default as PinInput } from './components/PinInput/PinInput.svelte';
|
|
75
76
|
export { default as ProgressBar } from './components/ProgressBar/ProgressBar.svelte';
|
|
76
77
|
export { default as Scrollable } from './components/Scrollable/Scrollable.svelte';
|
|
77
78
|
export { default as Select } from './components/Select/Select.svelte';
|
|
@@ -106,10 +107,10 @@ export * from './services/theme.svelte.js';
|
|
|
106
107
|
export * from './services/toast-manager.svelte.js';
|
|
107
108
|
export * from './services/translation.svelte.js';
|
|
108
109
|
export * from './state/locale-state.svelte.js';
|
|
110
|
+
export { isModalOpen } from './state/modal-state.svelte.js';
|
|
109
111
|
export * from './types.js';
|
|
110
112
|
export * from './utilities/byte-units.js';
|
|
111
113
|
export * from './utilities/common.js';
|
|
112
|
-
export { isModalOpen } from './state/modal-state.svelte.js';
|
|
113
114
|
// site
|
|
114
115
|
export * from './site/constants.js';
|
|
115
116
|
export { default as SiteFooter } from './site/SiteFooter.svelte';
|
package/dist/types.d.ts
CHANGED
|
@@ -156,6 +156,17 @@ export type PasswordInputProps = BaseInputProps<string> & {
|
|
|
156
156
|
translations?: TranslationProps<'show_password' | 'hide_password'>;
|
|
157
157
|
isVisible?: boolean;
|
|
158
158
|
};
|
|
159
|
+
export type PinInputProps = {
|
|
160
|
+
ref?: HTMLInputElement | null;
|
|
161
|
+
class?: string;
|
|
162
|
+
size?: Size;
|
|
163
|
+
value?: string;
|
|
164
|
+
shape?: Shape;
|
|
165
|
+
disabled?: boolean;
|
|
166
|
+
length?: number;
|
|
167
|
+
password?: boolean;
|
|
168
|
+
onComplete?: (value: string) => void;
|
|
169
|
+
};
|
|
159
170
|
export type TextareaProps = {
|
|
160
171
|
ref?: HTMLTextAreaElement | null;
|
|
161
172
|
containerRef?: HTMLElement | null;
|
|
@@ -188,7 +199,7 @@ export type MultiSelectProps<T extends string> = SelectCommonProps<T> & {
|
|
|
188
199
|
onChange?: (values: T[]) => void;
|
|
189
200
|
onSelect?: (options: SelectOption<T>[]) => void;
|
|
190
201
|
};
|
|
191
|
-
export type
|
|
202
|
+
export type ToastWithId = ToastItem & {
|
|
192
203
|
id: string;
|
|
193
204
|
};
|
|
194
205
|
type ToastCommonProps = {
|
|
@@ -200,13 +211,14 @@ export type ToastContentProps = ToastCommonProps & {
|
|
|
200
211
|
icon?: IconLike | false;
|
|
201
212
|
onClose?: () => void;
|
|
202
213
|
children?: Snippet;
|
|
214
|
+
button?: ToastButton;
|
|
203
215
|
};
|
|
204
216
|
export type ToastContainerProps = ToastCommonProps & {
|
|
205
217
|
shape?: Shape;
|
|
206
218
|
size?: ContainerSize;
|
|
207
219
|
} & Omit<HTMLAttributes<HTMLElement>, 'title' | 'color' | 'size'>;
|
|
208
220
|
export type ToastPanelProps = {
|
|
209
|
-
items: Array<
|
|
221
|
+
items: Array<ToastWithId>;
|
|
210
222
|
} & HTMLAttributes<HTMLDivElement>;
|
|
211
223
|
export type ToastProps = ToastContentProps & ToastContainerProps;
|
|
212
224
|
type Closable = {
|
|
@@ -223,6 +235,7 @@ export type ToastShow = {
|
|
|
223
235
|
shape?: Shape;
|
|
224
236
|
icon?: IconLike | false;
|
|
225
237
|
size?: ContainerSize;
|
|
238
|
+
button?: ToastButton;
|
|
226
239
|
};
|
|
227
240
|
export type ToastOptions = {
|
|
228
241
|
id?: string;
|