@streamscloud/kit 0.15.0 → 0.15.1

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.
@@ -41,6 +41,7 @@ const handleClear = () => {
41
41
  handleChange();
42
42
  inputEl.focus();
43
43
  };
44
+ export const clear = () => handleClear();
44
45
  const handlePasswordToggle = () => {
45
46
  passwordRevealed = !passwordRevealed;
46
47
  inputEl?.focus();
@@ -109,7 +110,8 @@ const focusInput = () => inputEl?.focus();
109
110
  oninput={handleInput}
110
111
  onchange={handleChange}
111
112
  onblur={handleBlur}
112
- onfocus={() => on?.focus?.()} />
113
+ onfocus={() => on?.focus?.()}
114
+ onkeydown={(event) => on?.keydown?.(event)} />
113
115
 
114
116
  {#if suffix}
115
117
  <span class="input__suffix">{@render suffix()}</span>
@@ -141,7 +143,7 @@ Text input field with leading/trailing icon slots, clear button, emoji picker, a
141
143
  focus underline. Discriminated `type` selects native input mode (`text` / `password` / `email` /
142
144
  `search` / `url` / `tel`). Set `inert` for display mode (no focus, no animations), `readonly`
143
145
  for non-editable but selectable, `error` for the visual + a11y error state. Imperative
144
- `focus()` / `select()` exposed via `bind:this`.
146
+ `focus()` / `select()` / `clear()` exposed via `bind:this`.
145
147
 
146
148
  Two snippet slots widen the chrome: `prefix` for a full-height segmented leading addon (see
147
149
  `WebsiteInput`), and `suffix` for a free-form trailing addon rendered before any trailing icons
@@ -4,7 +4,7 @@ import type { InputProps } from './types';
4
4
  * focus underline. Discriminated `type` selects native input mode (`text` / `password` / `email` /
5
5
  * `search` / `url` / `tel`). Set `inert` for display mode (no focus, no animations), `readonly`
6
6
  * for non-editable but selectable, `error` for the visual + a11y error state. Imperative
7
- * `focus()` / `select()` exposed via `bind:this`.
7
+ * `focus()` / `select()` / `clear()` exposed via `bind:this`.
8
8
  *
9
9
  * Two snippet slots widen the chrome: `prefix` for a full-height segmented leading addon (see
10
10
  * `WebsiteInput`), and `suffix` for a free-form trailing addon rendered before any trailing icons
@@ -33,6 +33,7 @@ import type { InputProps } from './types';
33
33
  declare const Cmp: import("svelte").Component<InputProps, {
34
34
  /** Imperative API exposed via `bind:this` on `<Input>`. */ focus: () => void;
35
35
  select: () => void;
36
+ clear: () => void;
36
37
  }, "">;
37
38
  type Cmp = ReturnType<typeof Cmp>;
38
39
  export default Cmp;
@@ -1,2 +1,8 @@
1
1
  export { default as Input } from './cmp.input.svelte';
2
2
  export type { InputForwardedProps, InputProps, InputSize, InputType } from './types';
3
+ /** Imperative API exposed via `bind:this={instance}` on `<Input>`. */
4
+ export type InputInstance = {
5
+ focus: () => void;
6
+ select: () => void;
7
+ clear: () => void;
8
+ };
@@ -44,6 +44,7 @@ export type InputProps = {
44
44
  }) => void;
45
45
  blur?: () => void;
46
46
  focus?: () => void;
47
+ keydown?: (event: KeyboardEvent) => void;
47
48
  };
48
49
  /** Primary icon — string SVG source, `{ src, color?, size? }` object, or custom snippet. */
49
50
  icon?: IconProp;
@@ -2,7 +2,8 @@
2
2
  import { CONTROL_ICON_SIZE, scaleUp } from '../icon';
3
3
  import { Input } from '../input';
4
4
  import IconSearch from '@fluentui/svg-icons/icons/search_20_regular.svg?raw';
5
- const { value, collapsedIconColor, collapsedIconSize, placeholder = '', size = 'sm', debounce = 0, on } = $props();
5
+ const { value, collapsedIconColor, collapsedIconSize, placeholder = '', size = 'sm', debounce = 0, shortcut = false, clearOnEscape = false, on } = $props();
6
+ let inputRef = $state.raw(undefined);
6
7
  let focused = $state(false);
7
8
  const expanded = $derived(focused || !!value);
8
9
  const collapsedSize = $derived(collapsedIconSize ?? scaleUp(CONTROL_ICON_SIZE[size]));
@@ -10,24 +11,46 @@ const onInput = (v) => {
10
11
  on?.input?.(v);
11
12
  };
12
13
  const onInputDebounced = $derived(debounce > 0 ? Utils.debounce(onInput, debounce) : onInput);
14
+ $effect(() => {
15
+ if (!shortcut) {
16
+ return;
17
+ }
18
+ const onShortcut = (event) => {
19
+ if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'k') {
20
+ event.preventDefault();
21
+ inputRef?.focus();
22
+ inputRef?.select();
23
+ }
24
+ };
25
+ document.addEventListener('keydown', onShortcut);
26
+ return () => document.removeEventListener('keydown', onShortcut);
27
+ });
28
+ const handleKeydown = (event) => {
29
+ if (clearOnEscape && event.key === 'Escape' && !!value) {
30
+ event.stopPropagation();
31
+ inputRef?.clear();
32
+ }
33
+ };
13
34
  </script>
14
35
 
15
36
  <div class="toolbar-search-input toolbar-search-input--{size}" class:toolbar-search-input--expanded={expanded}>
16
37
  <Input
38
+ bind:this={inputRef}
17
39
  value={value}
18
40
  size={size}
19
41
  placeholder={placeholder}
20
42
  icon={{ src: IconSearch, color: expanded ? undefined : (collapsedIconColor ?? 'accent'), size: expanded ? undefined : collapsedSize }}
21
43
  clearable
22
44
  borderless={!expanded}
23
- on={{ input: onInputDebounced, change: onInputDebounced, focus: () => (focused = true), blur: () => (focused = false) }} />
45
+ on={{ input: onInputDebounced, change: onInputDebounced, focus: () => (focused = true), blur: () => (focused = false), keydown: handleKeydown }} />
24
46
  </div>
25
47
 
26
48
  <!--
27
49
  @component
28
50
  A collapsible search input for toolbars. Collapsed to an icon-only square at the chosen field height
29
51
  when empty + unfocused; expands to the full input width when focused or when a value is present.
30
- Shares Input's size preset so it lines up with other field-shaped controls.
52
+ Shares Input's size preset so it lines up with other field-shaped controls. Opt into `shortcut`
53
+ for a document-wide Cmd/Ctrl+K focus-and-select, and `clearOnEscape` to clear on Escape.
31
54
 
32
55
  ### CSS Custom Properties
33
56
  | Property | Description | Default |
@@ -9,6 +9,10 @@ type Props = {
9
9
  size?: 'sm' | 'md' | 'lg';
10
10
  /** Debounce delay in ms @default 0 */
11
11
  debounce?: number;
12
+ /** Bind Cmd/Ctrl+K document-wide to focus the input and select its text. Enable on a single instance per view. @default false */
13
+ shortcut?: boolean;
14
+ /** Clear the value on Escape while focused (swallowing the keystroke); an already-empty input lets Escape bubble. @default false */
15
+ clearOnEscape?: boolean;
12
16
  on?: {
13
17
  input?: (value: string) => void;
14
18
  };
@@ -16,7 +20,8 @@ type Props = {
16
20
  /**
17
21
  * A collapsible search input for toolbars. Collapsed to an icon-only square at the chosen field height
18
22
  * when empty + unfocused; expands to the full input width when focused or when a value is present.
19
- * Shares Input's size preset so it lines up with other field-shaped controls.
23
+ * Shares Input's size preset so it lines up with other field-shaped controls. Opt into `shortcut`
24
+ * for a document-wide Cmd/Ctrl+K focus-and-select, and `clearOnEscape` to clear on Escape.
20
25
  *
21
26
  * ### CSS Custom Properties
22
27
  * | Property | Description | Default |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/kit",
3
- "version": "0.15.0",
3
+ "version": "0.15.1",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",