@immich/ui 0.61.3 → 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.
@@ -1,3 +1,4 @@
1
+ import { on } from 'svelte/events';
1
2
  export const shortcutLabel = (shortcut) => {
2
3
  let label = '';
3
4
  if (shortcut.ctrl) {
@@ -71,6 +72,9 @@ export const shortcut = (node, option) => {
71
72
  /** Binds multiple keyboard shortcuts to node */
72
73
  export const shortcuts = (node, options) => {
73
74
  function onKeydown(event) {
75
+ if (event.defaultPrevented) {
76
+ return;
77
+ }
74
78
  const ignoreShortcut = shouldIgnoreEvent(event);
75
79
  for (const { shortcut, onShortcut, ignoreInputFields = true, preventDefault = true } of options) {
76
80
  if (ignoreInputFields && ignoreShortcut) {
@@ -85,13 +89,13 @@ export const shortcuts = (node, options) => {
85
89
  }
86
90
  }
87
91
  }
88
- node.addEventListener('keydown', onKeydown);
92
+ const off = on(node, 'keydown', onKeydown);
89
93
  return {
90
94
  update(newOptions) {
91
95
  options = newOptions;
92
96
  },
93
97
  destroy() {
94
- node.removeEventListener('keydown', onKeydown);
98
+ off();
95
99
  },
96
100
  };
97
101
  };
@@ -58,12 +58,6 @@ export declare const getFieldContext: () => () => {
58
58
  'bind:focused'?: boolean | undefined | null;
59
59
  'bind:offsetWidth'?: number | undefined | null;
60
60
  'bind:offsetHeight'?: number | undefined | null;
61
- 'data-sveltekit-keepfocus'?: true | "" | "off" | undefined | null;
62
- 'data-sveltekit-noscroll'?: true | "" | "off" | undefined | null;
63
- 'data-sveltekit-preload-code'?: true | "" | "eager" | "viewport" | "hover" | "tap" | "off" | undefined | null;
64
- 'data-sveltekit-preload-data'?: true | "" | "hover" | "tap" | "off" | undefined | null;
65
- 'data-sveltekit-reload'?: true | "" | "off" | undefined | null;
66
- 'data-sveltekit-replacestate'?: true | "" | "off" | undefined | null;
67
61
  'aria-activedescendant'?: string | undefined | null;
68
62
  'aria-atomic'?: import("svelte/elements").Booleanish | undefined | null;
69
63
  'aria-autocomplete'?: "none" | "inline" | "list" | "both" | undefined | null;
@@ -89,6 +89,11 @@
89
89
  }
90
90
  };
91
91
 
92
+ const handleEscapeKeydown = (event: KeyboardEvent) => {
93
+ event.stopImmediatePropagation();
94
+ onEscapeKeydown?.(event);
95
+ };
96
+
92
97
  onMount(() => {
93
98
  layer = modalState.incrementLayer();
94
99
 
@@ -100,7 +105,7 @@
100
105
  <Dialog.Portal>
101
106
  <Dialog.Overlay class="{zIndex.ModalBackdrop} fixed start-0 top-0 flex h-dvh max-h-dvh w-screen bg-black/30" />
102
107
  <Dialog.Content
103
- {onEscapeKeydown}
108
+ onEscapeKeydown={handleEscapeKeydown}
104
109
  {escapeKeydownBehavior}
105
110
  {interactOutsideBehavior}
106
111
  class={cleanClass(modalContentStyles({ size }))}
@@ -2,7 +2,6 @@
2
2
  import { zIndex } from '../../constants.js';
3
3
  import { Tooltip } from 'bits-ui';
4
4
  import type { Snippet } from 'svelte';
5
- import { fly } from 'svelte/transition';
6
5
 
7
6
  type Props = Tooltip.RootProps & {
8
7
  text?: string | null;
@@ -18,21 +17,30 @@
18
17
  <Tooltip.Portal>
19
18
  <Tooltip.Content
20
19
  sideOffset={8}
21
- forceMount
22
- class="bg-light-800 text-light {zIndex.Tooltip} rounded-lg px-3.5 py-2 text-xs shadow-lg"
20
+ class="tooltip-content bg-light-800 text-light {zIndex.Tooltip} rounded-lg px-3.5 py-2 text-xs shadow-lg"
23
21
  >
24
- {#snippet child({ wrapperProps, props, open })}
25
- {#if open}
26
- <div {...wrapperProps}>
27
- <div {...props} transition:fly={{ y: 4, duration: 150 }}>
28
- {text}
29
- </div>
30
- </div>
31
- {/if}
32
- {/snippet}
22
+ {text}
33
23
  </Tooltip.Content>
34
24
  </Tooltip.Portal>
35
25
  </Tooltip.Root>
36
26
  {:else}
37
27
  {@render child({ props: {} })}
38
28
  {/if}
29
+
30
+ <style>
31
+ :global(.tooltip-content[data-state='delayed-open']),
32
+ :global(.tooltip-content[data-state='instant-open']) {
33
+ animation: tooltip-enter 150ms ease-out;
34
+ }
35
+
36
+ @keyframes tooltip-enter {
37
+ from {
38
+ opacity: 0;
39
+ transform: translateY(4px);
40
+ }
41
+ to {
42
+ opacity: 1;
43
+ transform: translateY(0);
44
+ }
45
+ }
46
+ </style>
package/dist/index.d.ts CHANGED
@@ -102,8 +102,10 @@ export * from './services/modal-manager.svelte.js';
102
102
  export * from './services/theme.svelte.js';
103
103
  export * from './services/toast-manager.svelte.js';
104
104
  export * from './services/translation.svelte.js';
105
+ export * from './state/locale-state.svelte.js';
105
106
  export * from './types.js';
106
107
  export * from './utilities/byte-units.js';
107
108
  export * from './utilities/common.js';
109
+ export { isModalOpen } from './state/modal-state.svelte.js';
108
110
  export * from './site/constants.js';
109
111
  export { default as SiteFooter } from './site/SiteFooter.svelte';
package/dist/index.js CHANGED
@@ -105,9 +105,11 @@ export * from './services/modal-manager.svelte.js';
105
105
  export * from './services/theme.svelte.js';
106
106
  export * from './services/toast-manager.svelte.js';
107
107
  export * from './services/translation.svelte.js';
108
+ export * from './state/locale-state.svelte.js';
108
109
  export * from './types.js';
109
110
  export * from './utilities/byte-units.js';
110
111
  export * from './utilities/common.js';
112
+ export { isModalOpen } from './state/modal-state.svelte.js';
111
113
  // site
112
114
  export * from './site/constants.js';
113
115
  export { default as SiteFooter } from './site/SiteFooter.svelte';
@@ -4,6 +4,7 @@
4
4
  import IconButton from '../components/IconButton/IconButton.svelte';
5
5
  import Label from '../components/Label/Label.svelte';
6
6
  import { zIndex } from '../constants.js';
7
+ import { getLocale } from '../state/locale-state.svelte.js';
7
8
  import { styleVariants } from '../styles.js';
8
9
  import type { Shape, Size } from '../types.js';
9
10
  import { cleanClass, generateId } from '../utilities/internal.js';
@@ -75,6 +76,7 @@
75
76
  maxValue={maxDate}
76
77
  bind:value={date}
77
78
  readonly={readOnly}
79
+ locale={getLocale()}
78
80
  {disabled}
79
81
  >
80
82
  <DatePicker.Input
@@ -1,8 +1,10 @@
1
1
  import { matchesShortcut, shortcuts, shouldIgnoreEvent } from '../actions/shortcut.js';
2
2
  import CommandPaletteModal from '../internal/CommandPaletteModal.svelte';
3
3
  import { modalManager } from './modal-manager.svelte.js';
4
+ import { isModalOpen } from '../state/modal-state.svelte.js';
4
5
  import { isEnabled } from '../utilities/common.js';
5
6
  import { asArray, generateId, getSearchString } from '../utilities/internal.js';
7
+ import { on } from 'svelte/events';
6
8
  export const defaultProvider = ({ name, actions }) => ({
7
9
  name,
8
10
  onSearch: (query) => query ? actions.filter((action) => getSearchString(action).includes(query.toLowerCase())) : actions,
@@ -30,7 +32,7 @@ class CommandPaletteManager {
30
32
  { shortcut: { key: 'k', ctrl: true }, onShortcut: () => this.open() },
31
33
  { shortcut: { key: '/' }, preventDefault: true, onShortcut: () => this.open() },
32
34
  ]);
33
- document.body.addEventListener('keydown', (event) => this.#handleKeydown(event));
35
+ on(document.body, 'keydown', (event) => this.#handleKeydown(event));
34
36
  }
35
37
  }
36
38
  setTranslations(translations = {}) {
@@ -51,6 +53,9 @@ class CommandPaletteManager {
51
53
  void this.#onSearch(query);
52
54
  }
53
55
  async #handleKeydown(event) {
56
+ if (event.defaultPrevented || isModalOpen()) {
57
+ return;
58
+ }
54
59
  const actions = await Promise.all(this.#providers.map((provider) => Promise.resolve(provider.onSearch())));
55
60
  for (const action of actions.flat()) {
56
61
  if (!asArray(action.shortcuts).some((shortcut) => matchesShortcut(event, shortcut))) {
@@ -67,6 +72,7 @@ class CommandPaletteManager {
67
72
  event.preventDefault();
68
73
  }
69
74
  action?.onAction(action);
75
+ return;
70
76
  }
71
77
  }
72
78
  async #onClose(action) {
@@ -0,0 +1,2 @@
1
+ export declare const getLocale: () => string | undefined;
2
+ export declare const setLocale: (newLocale: string) => void;
@@ -0,0 +1,5 @@
1
+ let locale = $state();
2
+ export const getLocale = () => locale;
3
+ export const setLocale = (newLocale) => {
4
+ locale = newLocale;
5
+ };
@@ -5,4 +5,5 @@ declare class ModalState {
5
5
  decrementLayer(): number;
6
6
  }
7
7
  export declare const modalState: ModalState;
8
+ export declare const isModalOpen: () => boolean;
8
9
  export {};
@@ -14,3 +14,4 @@ class ModalState {
14
14
  }
15
15
  }
16
16
  export const modalState = new ModalState();
17
+ export const isModalOpen = () => modalState.layer > 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immich/ui",
3
- "version": "0.61.3",
3
+ "version": "0.62.0",
4
4
  "license": "GNU Affero General Public License version 3",
5
5
  "repository": {
6
6
  "type": "git",