compote-ui 0.61.0 → 0.62.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.
@@ -0,0 +1,45 @@
1
+ <script lang="ts">
2
+ import { Field } from '@ark-ui/svelte/field';
3
+ import { PasswordInput } from '@ark-ui/svelte/password-input';
4
+ import type { PasswordInputProps } from './types';
5
+ import { PhEye, PhEyeSlash } from '../../icons';
6
+
7
+ let {
8
+ label,
9
+ layout = 'vertical',
10
+ placeholder,
11
+ class: className,
12
+ ...restProps
13
+ }: PasswordInputProps = $props();
14
+
15
+ const rootClass = $derived(
16
+ layout === 'horizontal'
17
+ ? 'flex items-center justify-between gap-1.5 w-full data-disabled:opacity-50 data-disabled:grayscale'
18
+ : 'flex flex-col gap-1.5 w-full max-w-72 data-disabled:opacity-50 data-disabled:grayscale'
19
+ );
20
+ </script>
21
+
22
+ <PasswordInput.Root {...restProps} class={className ? `${rootClass} ${className}` : rootClass}>
23
+ {#if label}
24
+ <PasswordInput.Label class="text-sm leading-none font-medium">
25
+ {label}
26
+ <Field.RequiredIndicator />
27
+ </PasswordInput.Label>
28
+ {/if}
29
+ <PasswordInput.Control class="relative isolate">
30
+ <PasswordInput.Input
31
+ {placeholder}
32
+ class="h-9 w-full rounded-md border bg-surface-1 px-3 pr-9 text-sm shadow-sm placeholder:text-ink-dim focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none data-invalid:border-danger data-invalid:focus-visible:ring-danger"
33
+ />
34
+ <PasswordInput.VisibilityTrigger
35
+ class="absolute top-1/2 right-2 -translate-y-1/2 text-ink-dim hover:text-ink focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
36
+ >
37
+ <PasswordInput.Indicator class="flex items-center justify-center">
38
+ {#snippet fallback()}
39
+ <PhEyeSlash class="size-4" />
40
+ {/snippet}
41
+ <PhEye class="size-4" />
42
+ </PasswordInput.Indicator>
43
+ </PasswordInput.VisibilityTrigger>
44
+ </PasswordInput.Control>
45
+ </PasswordInput.Root>
@@ -0,0 +1,5 @@
1
+ import { PasswordInput } from '@ark-ui/svelte/password-input';
2
+ import type { PasswordInputProps } from './types';
3
+ declare const PasswordInput: import("svelte").Component<PasswordInputProps, {}, "">;
4
+ type PasswordInput = ReturnType<typeof PasswordInput>;
5
+ export default PasswordInput;
@@ -0,0 +1,7 @@
1
+ import type { PasswordInputRootBaseProps } from '@ark-ui/svelte/password-input';
2
+ export interface PasswordInputProps extends PasswordInputRootBaseProps {
3
+ label?: string;
4
+ layout?: 'vertical' | 'horizontal';
5
+ placeholder?: string;
6
+ class?: string;
7
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { Select } from '@ark-ui/svelte/select';
3
3
  import { Portal } from '@ark-ui/svelte/portal';
4
+ import { useFilter } from '@ark-ui/svelte/locale';
4
5
  import { TelInput, countries } from 'svelte-tel-input';
5
6
  import type { CountryCode } from 'svelte-tel-input/types';
6
7
  import type { PhoneInputProps } from './types';
@@ -22,28 +23,35 @@
22
23
  flagClass: `flag-${c.iso2.toLowerCase()}`,
23
24
  dialCode: c.dialCode
24
25
  }));
25
- const collection = createListCollection(countryItems);
26
+ const baseCollection = createListCollection(countryItems);
27
+
28
+ let filterText = $state('');
29
+ const filters = useFilter({ sensitivity: 'base' });
30
+ const collection = $derived(
31
+ filterText
32
+ ? baseCollection.filter((label) => filters().contains(label, filterText))
33
+ : baseCollection
34
+ );
26
35
 
27
36
  let {
28
37
  value = $bindable(''),
29
38
  country = $bindable(null),
30
39
  valid = $bindable(false),
31
40
  label,
32
- placeholder,
33
- name,
34
41
  layout = 'vertical',
35
42
  disabled,
36
43
  readonly,
37
44
  invalid,
38
45
  required,
39
46
  class: className,
40
- options
47
+ ...restProps
41
48
  }: PhoneInputProps = $props();
42
49
 
43
50
  const id = $props.id();
44
51
  const numberId = `${id}-number`;
45
52
 
46
53
  const selectedItem = $derived(countryItems.find((c) => c.value === country));
54
+ const showInvalid = $derived(invalid ?? (value.length > 0 && !valid));
47
55
 
48
56
  const rootClass = $derived(
49
57
  layout === 'horizontal'
@@ -63,7 +71,7 @@
63
71
  class={cn(
64
72
  'flex h-9 w-full items-center rounded-md border bg-surface-1 shadow-sm transition-shadow focus-within:ring-1 focus-within:ring-ring',
65
73
  'data-disabled:cursor-not-allowed data-disabled:opacity-50',
66
- invalid && 'border-danger focus-within:ring-danger',
74
+ showInvalid && 'border-danger focus-within:ring-danger',
67
75
  className
68
76
  )}
69
77
  data-disabled={disabled ? '' : undefined}
@@ -74,6 +82,9 @@
74
82
  onValueChange={(details) => {
75
83
  country = (details.items[0]?.value as CountryCode | undefined) ?? null;
76
84
  }}
85
+ onOpenChange={(details) => {
86
+ if (!details.open) filterText = '';
87
+ }}
77
88
  {disabled}
78
89
  readOnly={readonly}
79
90
  class="h-9 shrink-0"
@@ -87,7 +98,6 @@
87
98
  <span
88
99
  class="flag {selectedItem.flagClass} shrink-0 rounded-xs shadow-[inset_0_0_0_1px_var(--compote-border)]"
89
100
  ></span>
90
- <span class="font-medium tabular-nums">+{selectedItem.dialCode}</span>
91
101
  {:else}
92
102
  <span class="text-ink-dim">Country</span>
93
103
  {/if}
@@ -97,22 +107,33 @@
97
107
  <Portal>
98
108
  <Select.Positioner>
99
109
  <Select.Content
100
- class="z-200 max-h-60 min-w-52 overflow-auto rounded-md border bg-surface-document p-1 shadow-md data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95"
110
+ class="z-200 flex max-h-72 min-w-52 flex-col overflow-hidden rounded-md border bg-surface-document p-1 shadow-md data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95"
101
111
  >
102
- {#each countryItems as item (item.value)}
103
- <Select.Item
104
- {item}
105
- class="relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm text-ink transition-colors select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-highlighted:bg-surface-1 data-[state=checked]:bg-surface-1"
106
- >
107
- <span
108
- class="flag {item.flagClass} shrink-0 rounded-xs shadow-[inset_0_0_0_1px_var(--compote-border)]"
109
- ></span>
110
- <Select.ItemText class="flex-1 truncate">{item.label}</Select.ItemText>
111
- <Select.ItemIndicator class="absolute right-2 flex items-center justify-center">
112
- <PhCheck class="size-3.5" />
113
- </Select.ItemIndicator>
114
- </Select.Item>
115
- {/each}
112
+ <input
113
+ type="text"
114
+ bind:value={filterText}
115
+ placeholder="Search"
116
+ class="mb-1 shrink-0 rounded-sm border bg-surface-1 px-2 py-1 text-sm outline-none focus:ring-1 focus:ring-ring"
117
+ onkeydown={(e) => e.stopPropagation()}
118
+ />
119
+ <div class="overflow-auto">
120
+ {#each collection.items as item (item.value)}
121
+ <Select.Item
122
+ {item}
123
+ class="relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm text-ink transition-colors select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-highlighted:bg-surface-1 data-[state=checked]:bg-surface-1"
124
+ >
125
+ <span
126
+ class="flag {item.flagClass} shrink-0 rounded-xs shadow-[inset_0_0_0_1px_var(--compote-border)]"
127
+ ></span>
128
+ <Select.ItemText class="flex-1 truncate">{item.label}</Select.ItemText>
129
+ <Select.ItemIndicator class="absolute right-2 flex items-center justify-center">
130
+ <PhCheck class="size-3.5" />
131
+ </Select.ItemIndicator>
132
+ </Select.Item>
133
+ {:else}
134
+ <div class="py-2 text-center text-sm text-ink-dim">No results found</div>
135
+ {/each}
136
+ </div>
116
137
  </Select.Content>
117
138
  </Select.Positioner>
118
139
  </Portal>
@@ -122,12 +143,10 @@
122
143
  bind:value
123
144
  bind:country
124
145
  bind:valid
125
- {name}
126
- {placeholder}
127
146
  {disabled}
128
147
  {readonly}
129
148
  {required}
130
- {options}
149
+ {...restProps}
131
150
  class="h-full min-w-0 flex-1 bg-transparent px-3 text-sm outline-none placeholder:text-ink-dim disabled:cursor-not-allowed"
132
151
  />
133
152
  </div>
@@ -1,16 +1,9 @@
1
- import type { CountryCode, TelInputOptions } from 'svelte-tel-input/types';
2
- export interface PhoneInputProps {
1
+ import type { Props as TelInputProps } from 'svelte-tel-input/types';
2
+ export interface PhoneInputProps extends Omit<TelInputProps, 'value' | 'class' | 'id' | 'readonly'> {
3
3
  value?: string;
4
- country?: CountryCode | null;
5
- valid?: boolean;
6
4
  label?: string;
7
- placeholder?: string;
8
- name?: string;
9
5
  layout?: 'vertical' | 'horizontal';
10
- disabled?: boolean;
11
6
  readonly?: boolean;
12
7
  invalid?: boolean;
13
- required?: boolean;
14
8
  class?: string;
15
- options?: TelInputOptions;
16
9
  }
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ let { class: className = '', ...restProps } = $props();
3
+ </script>
4
+
5
+ <svg
6
+ xmlns="http://www.w3.org/2000/svg"
7
+ width="1em"
8
+ height="1em"
9
+ viewBox="0 0 256 256"
10
+ class={className}
11
+ {...restProps}
12
+ >
13
+ <path
14
+ fill="currentColor"
15
+ d="M247.31,124.76c-.35-.79-8.82-19.58-27.65-38.41C194.57,61.26,162.88,48,128,48S61.43,61.26,36.34,86.35C17.51,105.18,9.04,124,8.69,124.76a8,8,0,0,0,0,6.5c.35.79,8.82,19.57,27.65,38.4C61.43,194.74,93.12,208,128,208s66.57-13.26,91.66-38.34c18.83-18.83,27.3-37.61,27.65-38.4A8,8,0,0,0,247.31,124.76ZM128,192c-30.78,0-57.67-11.19-79.93-33.25A133.47,133.47,0,0,1,25,128,133.33,133.33,0,0,1,48.07,97.25C70.33,75.19,97.22,64,128,64s57.67,11.19,79.93,33.25A133.46,133.46,0,0,1,231.05,128C223.84,141.46,192.43,192,128,192Zm0-112a48,48,0,1,0,48,48A48.05,48.05,0,0,0,128,80Zm0,80a32,32,0,1,1,32-32A32,32,0,0,1,128,160Z"
16
+ />
17
+ </svg>
18
+
19
+ <!-- Icon from Phosphor by Phosphor Icons - https://github.com/phosphor-icons/core/blob/main/LICENSE -->
@@ -0,0 +1,5 @@
1
+ declare const PhEye: import("svelte").Component<{
2
+ class?: string;
3
+ } & Record<string, any>, {}, "">;
4
+ type PhEye = ReturnType<typeof PhEye>;
5
+ export default PhEye;
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ let { class: className = '', ...restProps } = $props();
3
+ </script>
4
+
5
+ <svg
6
+ xmlns="http://www.w3.org/2000/svg"
7
+ width="1em"
8
+ height="1em"
9
+ viewBox="0 0 256 256"
10
+ class={className}
11
+ {...restProps}
12
+ >
13
+ <path
14
+ fill="currentColor"
15
+ d="M53.92,34.62A8,8,0,1,0,42.08,45.38L61.32,66.55C25,88.84,9.38,123.2,8.69,124.76a8,8,0,0,0,0,6.5c.35.79,8.82,19.57,27.65,38.4C61.43,194.74,93.12,208,128,208a127.11,127.11,0,0,0,52.07-10.83l21.41,23.55a8,8,0,1,0,11.84-10.76Zm84.16,114.84-37.6-41.36a24,24,0,0,1,37.6,41.36ZM128,192c-30.78,0-57.67-11.19-79.93-33.25A133.47,133.47,0,0,1,25,128c4.69-8.79,19.66-33.39,47.35-49.38l18.81,20.69a40,40,0,0,0,54.75,54.75l14.6,16.07A111.59,111.59,0,0,1,128,192Zm6-95.43a8,8,0,0,1,3.07-15.72,40.07,40.07,0,0,1,32.49,32.5,8,8,0,0,1-6.6,9.2,8.1,8.1,0,0,1-1.31.11,8,8,0,0,1-7.89-6.71A24,24,0,0,0,134,96.57Zm113.28,34.69c-.42.94-10.55,23.37-33.36,43.8a8,8,0,1,1-10.59-12c17.54-15.52,26.4-32.32,28.97-37.06A133.46,133.46,0,0,0,207.93,97.25,135.05,135.05,0,0,0,128,64a121.7,121.7,0,0,0-26.15,2.93,8,8,0,1,1-3.46-15.62A137.39,137.39,0,0,1,128,48c34.88,0,66.57,13.26,91.66,38.35,18.83,18.83,27.3,37.61,27.65,38.41A8,8,0,0,1,247.31,131.26Z"
16
+ />
17
+ </svg>
18
+
19
+ <!-- Icon from Phosphor by Phosphor Icons - https://github.com/phosphor-icons/core/blob/main/LICENSE -->
@@ -0,0 +1,5 @@
1
+ declare const PhEyeSlash: import("svelte").Component<{
2
+ class?: string;
3
+ } & Record<string, any>, {}, "">;
4
+ type PhEyeSlash = ReturnType<typeof PhEyeSlash>;
5
+ export default PhEyeSlash;
@@ -9,6 +9,8 @@ export { default as PhCaretDown } from './PhCaretDown.svelte';
9
9
  export { default as PhCaretRight } from './PhCaretRight.svelte';
10
10
  export { default as PhCaretUp } from './PhCaretUp.svelte';
11
11
  export { default as PhCheck } from './PhCheck.svelte';
12
+ export { default as PhEye } from './PhEye.svelte';
13
+ export { default as PhEyeSlash } from './PhEyeSlash.svelte';
12
14
  export { default as PhFile } from './PhFile.svelte';
13
15
  export { default as PhFileArchive } from './PhFileArchive.svelte';
14
16
  export { default as PhFileText } from './PhFileText.svelte';
@@ -9,6 +9,8 @@ export { default as PhCaretDown } from './PhCaretDown.svelte';
9
9
  export { default as PhCaretRight } from './PhCaretRight.svelte';
10
10
  export { default as PhCaretUp } from './PhCaretUp.svelte';
11
11
  export { default as PhCheck } from './PhCheck.svelte';
12
+ export { default as PhEye } from './PhEye.svelte';
13
+ export { default as PhEyeSlash } from './PhEyeSlash.svelte';
12
14
  export { default as PhFile } from './PhFile.svelte';
13
15
  export { default as PhFileArchive } from './PhFileArchive.svelte';
14
16
  export { default as PhFileText } from './PhFileText.svelte';
package/dist/index.d.ts CHANGED
@@ -37,6 +37,8 @@ export { default as JsonTreeView } from './components/json-tree-view/json-tree-v
37
37
  export * as Listbox from './components/listbox';
38
38
  export { default as NumberInput } from './components/number-input/number-input.svelte';
39
39
  export type { NumberInputProps } from './components/number-input/types';
40
+ export { default as PasswordInput } from './components/password-input/password-input.svelte';
41
+ export type { PasswordInputProps } from './components/password-input/types';
40
42
  export { default as PhoneInput } from './components/phone-input/phone-input.svelte';
41
43
  export type { PhoneInputProps } from './components/phone-input/types';
42
44
  export * as Popover from './components/popover';
package/dist/index.js CHANGED
@@ -27,6 +27,7 @@ export { default as ImageCropDialog } from './components/image-crop-dialog/image
27
27
  export { default as JsonTreeView } from './components/json-tree-view/json-tree-view.svelte';
28
28
  export * as Listbox from './components/listbox';
29
29
  export { default as NumberInput } from './components/number-input/number-input.svelte';
30
+ export { default as PasswordInput } from './components/password-input/password-input.svelte';
30
31
  export { default as PhoneInput } from './components/phone-input/phone-input.svelte';
31
32
  export * as Popover from './components/popover';
32
33
  export { default as QrCode } from './components/qr-code/qr-code.svelte';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compote-ui",
3
- "version": "0.61.0",
3
+ "version": "0.62.0",
4
4
  "license": "MIT",
5
5
  "scripts": {
6
6
  "dev": "vite dev --open",