@streamscloud/kit 0.2.1 → 0.2.2

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.
Files changed (104) hide show
  1. package/dist/styles/_input.scss +98 -0
  2. package/dist/styles/_mixins.scss +2 -2
  3. package/dist/styles/reset.css +1 -1
  4. package/dist/ui/color-picker/cmp.color-picker.svelte +3 -12
  5. package/dist/ui/color-picker/cmp.color-picker.svelte.d.ts +3 -9
  6. package/dist/ui/dialog/cmp.dialog.svelte +1 -1
  7. package/dist/ui/dropdown/cmp.dropdown-item.svelte +93 -0
  8. package/dist/ui/dropdown/cmp.dropdown-item.svelte.d.ts +32 -0
  9. package/dist/ui/dropdown/cmp.dropdown-panel.svelte +29 -0
  10. package/dist/ui/dropdown/cmp.dropdown-panel.svelte.d.ts +18 -0
  11. package/dist/ui/dropdown/cmp.dropdown.svelte +72 -7
  12. package/dist/ui/dropdown/cmp.dropdown.svelte.d.ts +3 -1
  13. package/dist/ui/dropdown/index.d.ts +2 -0
  14. package/dist/ui/dropdown/index.js +2 -0
  15. package/dist/ui/dynamic-component/cmp.dynamic-component.svelte +0 -5
  16. package/dist/ui/dynamic-component/cmp.dynamic-component.svelte.d.ts +2 -8
  17. package/dist/ui/emoji-picker/cmp.emoji-panel.svelte +186 -0
  18. package/dist/ui/emoji-picker/cmp.emoji-panel.svelte.d.ts +21 -0
  19. package/dist/ui/emoji-picker/cmp.emoji-picker.svelte +35 -0
  20. package/dist/ui/emoji-picker/cmp.emoji-picker.svelte.d.ts +15 -0
  21. package/dist/ui/emoji-picker/emoji-list.d.ts +2 -0
  22. package/dist/ui/emoji-picker/emoji-list.js +1754 -0
  23. package/dist/ui/emoji-picker/emoji-picker-localization.d.ts +5 -0
  24. package/dist/ui/emoji-picker/emoji-picker-localization.js +40 -0
  25. package/dist/ui/emoji-picker/index.d.ts +2 -0
  26. package/dist/ui/emoji-picker/index.js +2 -0
  27. package/dist/ui/emoji-picker/types.d.ts +8 -0
  28. package/dist/ui/emoji-picker/types.js +1 -0
  29. package/dist/ui/form-group/cmp.form-group-label.svelte.d.ts +1 -0
  30. package/dist/ui/form-group/cmp.form-group.svelte.d.ts +1 -0
  31. package/dist/ui/icon-text/cmp.icon-text.svelte +0 -9
  32. package/dist/ui/icon-text/cmp.icon-text.svelte.d.ts +4 -9
  33. package/dist/ui/inputs/index.d.ts +6 -0
  34. package/dist/ui/inputs/index.js +5 -0
  35. package/dist/ui/inputs/input/cmp.input-validatable.svelte +57 -0
  36. package/dist/ui/inputs/input/cmp.input-validatable.svelte.d.ts +56 -0
  37. package/dist/ui/inputs/input/cmp.input.svelte +235 -0
  38. package/dist/ui/inputs/input/cmp.input.svelte.d.ts +60 -0
  39. package/dist/ui/inputs/input/index.d.ts +2 -0
  40. package/dist/ui/inputs/input/index.js +2 -0
  41. package/dist/ui/inputs/input-emoji-picker/cmp.input-emoji-picker.svelte +44 -0
  42. package/dist/ui/inputs/input-emoji-picker/cmp.input-emoji-picker.svelte.d.ts +9 -0
  43. package/dist/ui/inputs/input-emoji-picker/index.d.ts +2 -0
  44. package/dist/ui/inputs/input-emoji-picker/index.js +2 -0
  45. package/dist/ui/inputs/input-emoji-picker/input-emoji-picker-container.d.ts +2 -0
  46. package/dist/ui/inputs/input-emoji-picker/input-emoji-picker-container.js +16 -0
  47. package/dist/ui/inputs/numeral-input/cmp.numeral-input-validatable.svelte +55 -0
  48. package/dist/ui/inputs/numeral-input/cmp.numeral-input-validatable.svelte.d.ts +62 -0
  49. package/dist/ui/inputs/numeral-input/cmp.numeral-input.svelte +248 -0
  50. package/dist/ui/inputs/numeral-input/cmp.numeral-input.svelte.d.ts +66 -0
  51. package/dist/ui/inputs/numeral-input/index.d.ts +2 -0
  52. package/dist/ui/inputs/numeral-input/index.js +2 -0
  53. package/dist/ui/inputs/pin-input/cmp.pin-input.svelte +58 -0
  54. package/dist/ui/inputs/pin-input/cmp.pin-input.svelte.d.ts +23 -0
  55. package/dist/ui/inputs/pin-input/index.d.ts +1 -0
  56. package/dist/ui/inputs/pin-input/index.js +1 -0
  57. package/dist/ui/inputs/pin-input/pin-input-generator.d.ts +27 -0
  58. package/dist/ui/inputs/pin-input/pin-input-generator.js +114 -0
  59. package/dist/ui/inputs/rich-text-input/cmp.rich-text-input.svelte +55 -0
  60. package/dist/ui/inputs/rich-text-input/cmp.rich-text-input.svelte.d.ts +43 -0
  61. package/dist/ui/inputs/rich-text-input/index.d.ts +2 -0
  62. package/dist/ui/inputs/rich-text-input/index.js +1 -0
  63. package/dist/ui/inputs/rich-text-input/rich-text-input-localization.d.ts +12 -0
  64. package/dist/ui/inputs/rich-text-input/rich-text-input-localization.js +48 -0
  65. package/dist/ui/inputs/rich-text-input/tinymce-input.svelte +250 -0
  66. package/dist/ui/inputs/rich-text-input/tinymce-input.svelte.d.ts +25 -0
  67. package/dist/ui/inputs/rich-text-input/tinymce.declarations.d.ts +7 -0
  68. package/dist/ui/inputs/rich-text-input/types.d.ts +4 -0
  69. package/dist/ui/inputs/rich-text-input/types.js +1 -0
  70. package/dist/ui/inputs/rich-text-input/validated-link-button.d.ts +3 -0
  71. package/dist/ui/inputs/rich-text-input/validated-link-button.js +78 -0
  72. package/dist/ui/inputs/textarea/cmp.textarea-validatable.svelte +35 -0
  73. package/dist/ui/inputs/textarea/cmp.textarea-validatable.svelte.d.ts +53 -0
  74. package/dist/ui/inputs/textarea/cmp.textarea.svelte +247 -0
  75. package/dist/ui/inputs/textarea/cmp.textarea.svelte.d.ts +57 -0
  76. package/dist/ui/inputs/textarea/index.d.ts +2 -0
  77. package/dist/ui/inputs/textarea/index.js +2 -0
  78. package/dist/ui/media-viewer-dialog/cmp.media-viewer-dialog.svelte.d.ts +2 -0
  79. package/dist/ui/selects/_multiselect.scss +282 -0
  80. package/dist/ui/selects/_singleselect.scss +175 -0
  81. package/dist/ui/selects/cmp.multiselect.svelte +530 -0
  82. package/dist/ui/selects/cmp.multiselect.svelte.d.ts +85 -0
  83. package/dist/ui/selects/cmp.search-multiselect.svelte +532 -0
  84. package/dist/ui/selects/cmp.search-multiselect.svelte.d.ts +67 -0
  85. package/dist/ui/selects/cmp.singleselect.svelte +381 -0
  86. package/dist/ui/selects/cmp.singleselect.svelte.d.ts +78 -0
  87. package/dist/ui/selects/index.d.ts +5 -0
  88. package/dist/ui/selects/index.js +4 -0
  89. package/dist/ui/selects/select-localization.d.ts +6 -0
  90. package/dist/ui/selects/select-localization.js +27 -0
  91. package/dist/ui/selects/types.d.ts +29 -0
  92. package/dist/ui/selects/types.js +1 -0
  93. package/dist/ui/time-ago/cmp.time-ago.svelte +0 -6
  94. package/dist/ui/time-ago/cmp.time-ago.svelte.d.ts +2 -6
  95. package/dist/ui/validatable/_validatable.scss +34 -0
  96. package/dist/ui/validatable/cmp.validatable.svelte +57 -0
  97. package/dist/ui/validatable/cmp.validatable.svelte.d.ts +49 -0
  98. package/dist/ui/validatable/cmp.validation-error.svelte +52 -0
  99. package/dist/ui/validatable/cmp.validation-error.svelte.d.ts +42 -0
  100. package/dist/ui/validatable/index.d.ts +2 -0
  101. package/dist/ui/validatable/index.js +2 -0
  102. package/package.json +31 -5
  103. package/dist/ui/color-picker/cmp.input-stub.svelte +0 -98
  104. package/dist/ui/color-picker/cmp.input-stub.svelte.d.ts +0 -40
@@ -0,0 +1,5 @@
1
+ export declare class EmojiPickerLocalization {
2
+ get searchPlaceholder(): string;
3
+ get notFound(): string;
4
+ get categories(): Record<string, string>;
5
+ }
@@ -0,0 +1,40 @@
1
+ import { AppLocale } from '../../core/locale';
2
+ const loc = {
3
+ searchPlaceholder: { en: 'Search emoji...', no: 'Sok etter emoji...' },
4
+ notFound: { en: 'No emoji found', no: 'Ingen emoji funnet' }
5
+ };
6
+ const categories = {
7
+ emotions: { en: 'Smileys & Emotion', no: 'Smileys og folelser' },
8
+ people: { en: 'People & Body', no: 'Mennesker og kropp' },
9
+ nature: { en: 'Animals & Nature', no: 'Dyr og natur' },
10
+ food: { en: 'Food & Drink', no: 'Mat og drikke' },
11
+ travel: { en: 'Travel & Places', no: 'Reise og steder' },
12
+ activities: { en: 'Activities', no: 'Aktiviteter' },
13
+ objects: { en: 'Objects', no: 'Objekter' },
14
+ symbols: { en: 'Symbols', no: 'Symboler' },
15
+ flags: { en: 'Flags', no: 'Flagg' },
16
+ search: { en: 'Search Results', no: 'Sokeresultater' }
17
+ };
18
+ export class EmojiPickerLocalization {
19
+ get searchPlaceholder() {
20
+ return loc.searchPlaceholder[AppLocale.current];
21
+ }
22
+ get notFound() {
23
+ return loc.notFound[AppLocale.current];
24
+ }
25
+ get categories() {
26
+ const l = AppLocale.current;
27
+ return {
28
+ emotions: categories.emotions[l],
29
+ people: categories.people[l],
30
+ nature: categories.nature[l],
31
+ food: categories.food[l],
32
+ travel: categories.travel[l],
33
+ activities: categories.activities[l],
34
+ objects: categories.objects[l],
35
+ symbols: categories.symbols[l],
36
+ flags: categories.flags[l],
37
+ search: categories.search[l]
38
+ };
39
+ }
40
+ }
@@ -0,0 +1,2 @@
1
+ export { default as EmojiPanel } from './cmp.emoji-panel.svelte';
2
+ export { default as EmojiPicker } from './cmp.emoji-picker.svelte';
@@ -0,0 +1,2 @@
1
+ export { default as EmojiPanel } from './cmp.emoji-panel.svelte';
2
+ export { default as EmojiPicker } from './cmp.emoji-picker.svelte';
@@ -0,0 +1,8 @@
1
+ export type Emoji = {
2
+ text: string;
3
+ unicode: string;
4
+ };
5
+ export type EmojiCategory = {
6
+ name: string;
7
+ emojis: Emoji[];
8
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  type Props = {
3
+ /** Enable flex layout for label + tooltip icon */
3
4
  withTooltip?: boolean;
4
5
  children: Snippet;
5
6
  };
@@ -1,5 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  type Props = {
3
+ /** Remove bottom margin */
3
4
  noMargin?: boolean;
4
5
  children: Snippet;
5
6
  };
@@ -25,15 +25,6 @@ Displays an icon alongside text in a horizontal layout. The icon can be an SVG s
25
25
  (rendered via `Icon`) or a custom `Snippet`. Use `iconPosition` to place the icon
26
26
  before or after the text.
27
27
 
28
- ### Props
29
- | Prop | Type | Default | Description |
30
- |---|---|---|---|
31
- | `icon` | `string \| Snippet` | — | SVG string or custom snippet for the icon |
32
- | `iconColor` | `IconColor \| null` | `null` | Color preset passed to `Icon` |
33
- | `iconPosition` | `'left' \| 'right'` | `'left'` | Icon placement relative to text |
34
- | `trimText` | `boolean` | `false` | Truncate text with ellipsis when overflowing |
35
- | `children` | `Snippet` | — | Text content |
36
-
37
28
  ### CSS Custom Properties
38
29
  | Property | Description | Default |
39
30
  |---|---|---|
@@ -1,9 +1,13 @@
1
1
  import { type IconColor } from '../icon';
2
2
  import type { Snippet } from 'svelte';
3
3
  type Props = {
4
+ /** SVG string or custom snippet for the icon */
4
5
  icon?: string | Snippet;
6
+ /** Color preset passed to the Icon component */
5
7
  iconColor?: IconColor | null;
8
+ /** Icon placement relative to text @default 'left' */
6
9
  iconPosition?: 'left' | 'right';
10
+ /** Truncate text with ellipsis on overflow */
7
11
  trimText?: boolean;
8
12
  children?: Snippet;
9
13
  };
@@ -12,15 +16,6 @@ type Props = {
12
16
  * (rendered via `Icon`) or a custom `Snippet`. Use `iconPosition` to place the icon
13
17
  * before or after the text.
14
18
  *
15
- * ### Props
16
- * | Prop | Type | Default | Description |
17
- * |---|---|---|---|
18
- * | `icon` | `string \| Snippet` | — | SVG string or custom snippet for the icon |
19
- * | `iconColor` | `IconColor \| null` | `null` | Color preset passed to `Icon` |
20
- * | `iconPosition` | `'left' \| 'right'` | `'left'` | Icon placement relative to text |
21
- * | `trimText` | `boolean` | `false` | Truncate text with ellipsis when overflowing |
22
- * | `children` | `Snippet` | — | Text content |
23
- *
24
19
  * ### CSS Custom Properties
25
20
  * | Property | Description | Default |
26
21
  * |---|---|---|
@@ -0,0 +1,6 @@
1
+ export { Input, InputValidatable } from './input';
2
+ export { NumeralInput, NumeralInputValidatable } from './numeral-input';
3
+ export { PinInput } from './pin-input';
4
+ export { RichTextInput } from './rich-text-input';
5
+ export type { RichTextInputOptions } from './rich-text-input';
6
+ export { Textarea, TextareaValidatable } from './textarea';
@@ -0,0 +1,5 @@
1
+ export { Input, InputValidatable } from './input';
2
+ export { NumeralInput, NumeralInputValidatable } from './numeral-input';
3
+ export { PinInput } from './pin-input';
4
+ export { RichTextInput } from './rich-text-input';
5
+ export { Textarea, TextareaValidatable } from './textarea';
@@ -0,0 +1,57 @@
1
+ <script lang="ts" generics="T extends Record<string, unknown>">import { Utils } from '../../../core/utils';
2
+ import { FormValidationHandler } from '../../../core/validation';
3
+ import { Validatable } from '../../validatable';
4
+ import { default as Input } from './cmp.input.svelte';
5
+ let { name, handler, id = undefined, type = 'text', debounce = 0, disabled = false, autofocus = false, placeholder = '', maxLength = null, clearable = false, validateOnChange = false, on, icon, clearButton } = $props();
6
+ let inputRef = null;
7
+ const onInput = (value) => {
8
+ if (!validateOnChange) {
9
+ handler.updateValidateField(name, value);
10
+ }
11
+ on?.input?.(value);
12
+ };
13
+ const onChange = (value) => {
14
+ if (validateOnChange) {
15
+ handler.updateValidateField(name, value);
16
+ }
17
+ on?.change?.(value);
18
+ };
19
+ const onBlur = () => {
20
+ if (inputRef) {
21
+ handler.updateValidateField(name, inputRef.value);
22
+ }
23
+ };
24
+ const handleMounted = (input) => {
25
+ inputRef = input;
26
+ on?.mounted?.({ input });
27
+ };
28
+ const handleInputDebounced = $derived(debounce ? Utils.debounce(onInput, debounce) : onInput);
29
+ const handleChangeDebounced = $derived(debounce ? Utils.debounce(onChange, debounce) : onChange);
30
+ </script>
31
+
32
+ <Validatable handler={handler} name={name}>
33
+ <Input
34
+ value={handler.form[name] as string | null | undefined}
35
+ name={name}
36
+ id={id}
37
+ type={type}
38
+ autofocus={autofocus}
39
+ disabled={disabled}
40
+ placeholder={placeholder}
41
+ maxLength={maxLength}
42
+ clearable={clearable}
43
+ title={!!handler.touched[name] && !!handler.errors[name] ? handler.errors[name] : ''}
44
+ on={{
45
+ input: handleInputDebounced,
46
+ change: handleChangeDebounced,
47
+ mounted: (e) => handleMounted(e.input),
48
+ blur: onBlur
49
+ }}
50
+ icon={icon}
51
+ clearButton={clearButton} />
52
+ </Validatable>
53
+
54
+ <!--
55
+ @component
56
+ Input wrapped with form validation. Validates on input or change based on `validateOnChange` prop.
57
+ -->
@@ -0,0 +1,56 @@
1
+ import { FormValidationHandler } from '../../../core/validation';
2
+ import type { Snippet } from 'svelte';
3
+ declare function $$render<T extends Record<string, unknown>>(): {
4
+ props: {
5
+ /** Field name in the form handler */
6
+ name: keyof T & string;
7
+ /** Form validation handler instance */
8
+ handler: FormValidationHandler<T>;
9
+ id?: string;
10
+ type?: "text" | "password";
11
+ /** Debounce delay in ms for input/change handlers @default 0 */
12
+ debounce?: number;
13
+ disabled?: boolean;
14
+ autofocus?: boolean;
15
+ placeholder?: string;
16
+ maxLength?: number | null;
17
+ /** Show clear button when value is present */
18
+ clearable?: boolean;
19
+ /** Validate on change event instead of input @default false */
20
+ validateOnChange?: boolean;
21
+ on?: {
22
+ input?: (value: string) => void;
23
+ change?: (value: string) => void;
24
+ /** Fires after mount, provides the input element ref */
25
+ mounted?: (data: {
26
+ input: HTMLInputElement;
27
+ }) => void;
28
+ };
29
+ /** Left icon snippet */
30
+ icon?: Snippet;
31
+ /** Custom clear button snippet */
32
+ clearButton?: Snippet;
33
+ };
34
+ exports: {};
35
+ bindings: "";
36
+ slots: {};
37
+ events: {};
38
+ };
39
+ declare class __sveltets_Render<T extends Record<string, unknown>> {
40
+ props(): ReturnType<typeof $$render<T>>['props'];
41
+ events(): ReturnType<typeof $$render<T>>['events'];
42
+ slots(): ReturnType<typeof $$render<T>>['slots'];
43
+ bindings(): "";
44
+ exports(): {};
45
+ }
46
+ interface $$IsomorphicComponent {
47
+ new <T extends Record<string, unknown>>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
48
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
49
+ } & ReturnType<__sveltets_Render<T>['exports']>;
50
+ <T extends Record<string, unknown>>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
51
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
52
+ }
53
+ /** Input wrapped with form validation. Validates on input or change based on `validateOnChange` prop. */
54
+ declare const Cmp: $$IsomorphicComponent;
55
+ type Cmp<T extends Record<string, unknown>> = InstanceType<typeof Cmp<T>>;
56
+ export default Cmp;
@@ -0,0 +1,235 @@
1
+ <script lang="ts">import { HtmlHelper } from '../../../core/utils';
2
+ import { Icon } from '../../icon';
3
+ import { InputEmojiPicker, inputEmojiPickerContainer } from '../input-emoji-picker';
4
+ import IconDismiss from '@fluentui/svg-icons/icons/dismiss_20_regular.svg?raw';
5
+ let { value, type = 'text', name = '', id = null, placeholder = '', disabled = false, inert = false, autofocus = false, clearable = false, emoji = false, borderless = false, title = '', maxLength = null, on, icon, clearButton } = $props();
6
+ let inputRef = $state(undefined);
7
+ const valueParsed = $derived(value ?? '');
8
+ const initInput = (node) => {
9
+ inputRef = node;
10
+ if (autofocus) {
11
+ node.focus();
12
+ }
13
+ on?.mounted?.({ input: node });
14
+ };
15
+ const clearButtonVisible = $derived(!disabled && clearable && !!value);
16
+ const onInput = () => {
17
+ if (!inputRef) {
18
+ return;
19
+ }
20
+ on?.input?.(inputRef.value);
21
+ };
22
+ const onChange = () => {
23
+ if (!inputRef) {
24
+ return;
25
+ }
26
+ on?.change?.(inputRef.value);
27
+ };
28
+ const clearValue = (e) => {
29
+ e.preventDefault();
30
+ if (!inputRef) {
31
+ return;
32
+ }
33
+ inputRef.value = '';
34
+ onInput();
35
+ onChange();
36
+ inputRef.focus();
37
+ };
38
+ const focusInput = () => {
39
+ inputRef?.focus();
40
+ };
41
+ const onBlur = () => {
42
+ if (inputRef) {
43
+ inputRef.value = valueParsed;
44
+ }
45
+ on?.blur?.();
46
+ };
47
+ const onEmojiSelected = (emojiChar) => {
48
+ if (inputRef) {
49
+ HtmlHelper.pasteIntoInput(emojiChar, inputRef);
50
+ }
51
+ };
52
+ </script>
53
+
54
+ <div
55
+ class="input"
56
+ class:input--disabled={disabled}
57
+ class:input--inert={inert}
58
+ class:input--borderless={borderless}
59
+ class:input--has-emoji={emoji}
60
+ use:inputEmojiPickerContainer
61
+ onclick={focusInput}
62
+ onkeydown={() => ({})}
63
+ role="none">
64
+ {#if icon}
65
+ <div class="input__icon">
66
+ {@render icon()}
67
+ </div>
68
+ {/if}
69
+ <input
70
+ use:initInput
71
+ inert={inert}
72
+ type={type}
73
+ name={name}
74
+ id={id}
75
+ placeholder={placeholder}
76
+ class="input__input"
77
+ value={valueParsed}
78
+ disabled={disabled}
79
+ title={title}
80
+ maxlength={maxLength}
81
+ oninput={onInput}
82
+ onchange={onChange}
83
+ onblur={() => onBlur()}
84
+ onfocus={() => on?.focus?.()} />
85
+ {#if clearButtonVisible || clearButton}
86
+ <div class="input__clear-wrapper">
87
+ {#if clearButton}
88
+ {@render clearButton()}
89
+ {:else}
90
+ <button type="button" class="input__clear-button" onclick={clearValue}>
91
+ <Icon src={IconDismiss} />
92
+ </button>
93
+ {/if}
94
+ </div>
95
+ {/if}
96
+ {#if emoji}
97
+ <InputEmojiPicker on={{ select: onEmojiSelected }} />
98
+ {/if}
99
+ </div>
100
+
101
+ <!--
102
+ @component
103
+ Text/password input with optional clear button, icon, and emoji picker.
104
+
105
+ ### CSS Custom Properties
106
+ | Property | Description | Default |
107
+ |---|---|---|
108
+ | `--sc-kit--input--root--font-size` | Root font size for em scaling | `1rem` |
109
+ | `--sc-kit--input--height` | Container height | `2em` |
110
+ | `--sc-kit--input--width` | Container width | `100%` |
111
+ | `--sc-kit--input--padding--block` | Block (vertical) padding | `0` |
112
+ | `--sc-kit--input--padding--inline` | Inline (horizontal) padding | `0.5em` |
113
+ | `--sc-kit--input--accent-color` | Focus accent color | light-dark primary-500/primary-400 |
114
+ | `--sc-kit--input--background` | Background color | light-dark white/gray-900 |
115
+ | `--sc-kit--input--background--disabled` | Disabled background | light-dark neutral-50/neutral-800 |
116
+ | `--sc-kit--input--border-color` | Border color | light-dark neutral-300/neutral-600 |
117
+ | `--sc-kit--input--border-radius` | Border radius | `0.25em` |
118
+ | `--sc-kit--input--text--font-size` | Text font size | `0.875em` |
119
+ | `--sc-kit--input--text--color` | Text color | light-dark gray-800/white |
120
+ | `--sc-kit--input--placeholder--color` | Placeholder text color | inherited from border |
121
+ | `--sc-kit--input--icon--size` | Icon size | `1em` |
122
+ | `--sc-kit--input--icon--color` | Icon color | inherited from border |
123
+ | `--sc-kit--input--cursor--inert` | Cursor when inert | `default` |
124
+ -->
125
+
126
+ <style>.input {
127
+ --_--input--root--font-size: var(--sc-kit--input--root--font-size);
128
+ --_--input--height: var(--sc-kit--input--height);
129
+ --_--input--width: var(--sc-kit--input--width);
130
+ --_--input--background: var(--sc-kit--input--background);
131
+ --_--input--background--disabled: var(--sc-kit--input--background--disabled);
132
+ --_--input--border-color: var(--sc-kit--input--border-color);
133
+ --_--input--border-radius: var(--sc-kit--input--border-radius);
134
+ --_--input--icon--size: var(--sc-kit--input--icon--size);
135
+ --_--input--icon--color: var(--sc-kit--input--icon--color);
136
+ --_--input--text--font-size: var(--sc-kit--input--text--font-size);
137
+ --_--input--text--color: var(--sc-kit--input--text--color);
138
+ --_--input--placeholder--color: var(--sc-kit--input--placeholder--color);
139
+ --_--input--accent-color: var(--sc-kit--input--accent-color);
140
+ --_--input--padding--inline: var(--sc-kit--input--padding--inline);
141
+ --_--input--padding--block: var(--sc-kit--input--padding--block);
142
+ --_input--cursor--inert: var(--sc-kit--input--cursor--inert);
143
+ --_input--root--font-size: var(--_--input--root--font-size, 1rem);
144
+ --_input--height: var(--_--input--height, 2em);
145
+ --_input--width: var(--_--input--width, 100%);
146
+ --_input--background: var(--_--input--background, light-dark(#ffffff, #1c1c1c));
147
+ --_input--background--disabled: var(--_--input--background--disabled, light-dark(#f9fafb, #1f2937));
148
+ --_input--border-color: var(--_--input--border-color, light-dark(#d1d5db, #4b5563));
149
+ --_input--border-radius: var(--_--input--border-radius, 0.25em);
150
+ --_input--icon--size: var(--_--input--icon--size, 1em);
151
+ --_input--icon--color: var(--_--input--icon--color, var(--_input--border-color));
152
+ --_input--text--font-size: var(--_--input--text--font-size, 0.875em);
153
+ --_input--text--color: var(--_--input--text--color, light-dark(#2e2e2e, #ffffff));
154
+ --_input--placeholder--color: var(--_--input--placeholder--color, var(--_input--border-color));
155
+ --_input--accent-color: var(--_--input--accent-color, light-dark(#144ab0, #5a8dec));
156
+ --_input--padding--inline: var(--_--input--padding--inline, 0.5em);
157
+ --_input--padding--block: var(--_--input--padding--block, 0);
158
+ --_input--padding-top: var(--_--input--padding-top, var(--_input--padding--block));
159
+ --_input--padding-right: var(--_--input--padding-right, var(--_input--padding--inline));
160
+ --_input--padding-bottom: var(--_--input--padding-bottom, var(--_input--padding--block));
161
+ --_input--padding-left: var(--_--input--padding-left, var(--_input--padding--inline));
162
+ font-size: var(--_input--root--font-size);
163
+ height: var(--_input--height);
164
+ color: var(--_input--text--color);
165
+ border: 1px solid var(--_input--border-color);
166
+ border-radius: var(--_input--border-radius);
167
+ width: var(--_input--width);
168
+ min-width: var(--_input--width);
169
+ background: var(--_input--background);
170
+ padding-top: var(--_input--padding-top);
171
+ padding-right: var(--_input--padding-right);
172
+ padding-bottom: var(--_input--padding-bottom);
173
+ padding-left: var(--_input--padding-left);
174
+ --_input--default-shadow-color: transparent;
175
+ --_input--accent-shadow: var(--_input--explicit-shadow-color, var(--_input--default-shadow-color));
176
+ position: relative;
177
+ box-shadow: inset 0 -0.13em var(--_input--accent-shadow);
178
+ transition: box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1);
179
+ }
180
+ .input:focus, .input:focus-within {
181
+ --_input--default-shadow-color: var(--_input--accent-color);
182
+ }
183
+ .input--disabled {
184
+ background-color: var(--_input--background--disabled);
185
+ cursor: default;
186
+ }
187
+ .input {
188
+ display: flex;
189
+ align-items: center;
190
+ cursor: text;
191
+ position: relative;
192
+ }
193
+ .input--inert {
194
+ cursor: var(--_input--cursor--inert);
195
+ }
196
+ .input--borderless {
197
+ --_input--border-color: transparent;
198
+ --_input--background: transparent;
199
+ --_input--background--disabled: transparent;
200
+ --_input--accent-color: transparent;
201
+ --_input--explicit-shadow-color: transparent;
202
+ --_input--height: auto;
203
+ }
204
+ .input--has-emoji {
205
+ --_--input--padding-right: 1.5em;
206
+ }
207
+ .input__input {
208
+ flex: 1;
209
+ height: 100%;
210
+ padding: 0;
211
+ background-color: transparent !important;
212
+ font-size: var(--_input--text--font-size);
213
+ color: var(--_input--text--color);
214
+ }
215
+ .input__input::placeholder {
216
+ color: var(--_input--placeholder--color);
217
+ }
218
+ .input__input:-webkit-autofill {
219
+ -webkit-text-fill-color: var(--_input--text--color) !important;
220
+ }
221
+ .input__icon {
222
+ margin-right: 0.625em;
223
+ color: var(--_input--icon--color);
224
+ font-size: var(--_input--icon--size);
225
+ }
226
+ :global(.input__icon:not(:has(*))) {
227
+ margin-right: 0 !important;
228
+ }
229
+ .input__clear-wrapper {
230
+ color: var(--_input--icon--color);
231
+ font-size: var(--_input--icon--size);
232
+ }
233
+ .input__clear-button {
234
+ margin-left: 0.625em;
235
+ }</style>
@@ -0,0 +1,60 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Props = {
3
+ value: string | null | undefined;
4
+ type?: 'text' | 'password';
5
+ name?: string;
6
+ id?: string | null;
7
+ placeholder?: string;
8
+ disabled?: boolean;
9
+ /** Make input non-interactive (visual display only) */
10
+ inert?: boolean;
11
+ autofocus?: boolean;
12
+ /** Show clear button when value is present */
13
+ clearable?: boolean;
14
+ /** Show emoji picker trigger */
15
+ emoji?: boolean;
16
+ /** Remove border, background, and accent shadow */
17
+ borderless?: boolean;
18
+ title?: string;
19
+ maxLength?: number | null;
20
+ on: {
21
+ input?: (value: string) => void;
22
+ change?: (value: string) => void;
23
+ /** Fires after mount, provides the input element ref */
24
+ mounted?: (data: {
25
+ input: HTMLInputElement;
26
+ }) => void;
27
+ blur?: () => void;
28
+ focus?: () => void;
29
+ };
30
+ /** Left icon snippet */
31
+ icon?: Snippet;
32
+ /** Custom clear button snippet */
33
+ clearButton?: Snippet;
34
+ };
35
+ /**
36
+ * Text/password input with optional clear button, icon, and emoji picker.
37
+ *
38
+ * ### CSS Custom Properties
39
+ * | Property | Description | Default |
40
+ * |---|---|---|
41
+ * | `--sc-kit--input--root--font-size` | Root font size for em scaling | `1rem` |
42
+ * | `--sc-kit--input--height` | Container height | `2em` |
43
+ * | `--sc-kit--input--width` | Container width | `100%` |
44
+ * | `--sc-kit--input--padding--block` | Block (vertical) padding | `0` |
45
+ * | `--sc-kit--input--padding--inline` | Inline (horizontal) padding | `0.5em` |
46
+ * | `--sc-kit--input--accent-color` | Focus accent color | light-dark primary-500/primary-400 |
47
+ * | `--sc-kit--input--background` | Background color | light-dark white/gray-900 |
48
+ * | `--sc-kit--input--background--disabled` | Disabled background | light-dark neutral-50/neutral-800 |
49
+ * | `--sc-kit--input--border-color` | Border color | light-dark neutral-300/neutral-600 |
50
+ * | `--sc-kit--input--border-radius` | Border radius | `0.25em` |
51
+ * | `--sc-kit--input--text--font-size` | Text font size | `0.875em` |
52
+ * | `--sc-kit--input--text--color` | Text color | light-dark gray-800/white |
53
+ * | `--sc-kit--input--placeholder--color` | Placeholder text color | inherited from border |
54
+ * | `--sc-kit--input--icon--size` | Icon size | `1em` |
55
+ * | `--sc-kit--input--icon--color` | Icon color | inherited from border |
56
+ * | `--sc-kit--input--cursor--inert` | Cursor when inert | `default` |
57
+ */
58
+ declare const Cmp: import("svelte").Component<Props, {}, "">;
59
+ type Cmp = ReturnType<typeof Cmp>;
60
+ export default Cmp;
@@ -0,0 +1,2 @@
1
+ export { default as Input } from './cmp.input.svelte';
2
+ export { default as InputValidatable } from './cmp.input-validatable.svelte';
@@ -0,0 +1,2 @@
1
+ export { default as Input } from './cmp.input.svelte';
2
+ export { default as InputValidatable } from './cmp.input-validatable.svelte';
@@ -0,0 +1,44 @@
1
+ <script lang="ts">import { Dropdown } from '../../dropdown';
2
+ import { EmojiPanel } from '../../emoji-picker';
3
+ import { Icon } from '../../icon';
4
+ import IconEmoji from '@fluentui/svg-icons/icons/emoji_20_regular.svg?raw';
5
+ let toggleDropdown = $state();
6
+ let { on } = $props();
7
+ </script>
8
+
9
+ <button type="button" class="input-emoji-picker-trigger" onclick={() => toggleDropdown?.()}>
10
+ <Icon src={IconEmoji} />
11
+ </button>
12
+
13
+ <div class="input-emoji-picker">
14
+ <Dropdown position="bottom-end" matchTriggerWidth on={{ mounted: (e) => (toggleDropdown = e.toggleOpen) }} keepDropdownOpen={true}>
15
+ {#snippet trigger()}
16
+ <div class="input-emoji-picker__trigger-stub"></div>
17
+ {/snippet}
18
+ <EmojiPanel on={{ select: on.select }} />
19
+ </Dropdown>
20
+ </div>
21
+
22
+ <!--
23
+ @component
24
+ Emoji picker dropdown with trigger icon. Wraps EmojiPanel in a Dropdown for positioning.
25
+ -->
26
+
27
+ <style>.input-emoji-picker-trigger {
28
+ --_input-emoji-picker--trigger--opacity: var(--input-emoji-picker--trigger--opacity, 0);
29
+ --sc-kit--icon--size: 1em;
30
+ --sc-kit--icon--color: light-dark(#9ca3af, #6b7280);
31
+ opacity: var(--_input-emoji-picker--trigger--opacity);
32
+ position: absolute;
33
+ right: 0.25rem;
34
+ bottom: 0.25rem;
35
+ transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);
36
+ }
37
+
38
+ .input-emoji-picker {
39
+ --sc-kit--dropdown--width: 100%;
40
+ position: absolute;
41
+ bottom: 0;
42
+ left: 0;
43
+ right: 0;
44
+ }</style>
@@ -0,0 +1,9 @@
1
+ type Props = {
2
+ on: {
3
+ select: (value: string) => void;
4
+ };
5
+ };
6
+ /** Emoji picker dropdown with trigger icon. Wraps EmojiPanel in a Dropdown for positioning. */
7
+ declare const Cmp: import("svelte").Component<Props, {}, "">;
8
+ type Cmp = ReturnType<typeof Cmp>;
9
+ export default Cmp;
@@ -0,0 +1,2 @@
1
+ export { default as InputEmojiPicker } from './cmp.input-emoji-picker.svelte';
2
+ export { inputEmojiPickerContainer } from './input-emoji-picker-container';
@@ -0,0 +1,2 @@
1
+ export { default as InputEmojiPicker } from './cmp.input-emoji-picker.svelte';
2
+ export { inputEmojiPickerContainer } from './input-emoji-picker-container';
@@ -0,0 +1,2 @@
1
+ import type { Action } from 'svelte/action';
2
+ export declare const inputEmojiPickerContainer: Action;
@@ -0,0 +1,16 @@
1
+ export const inputEmojiPickerContainer = (node) => {
2
+ const handleHover = () => {
3
+ node.style.setProperty('--input-emoji-picker--trigger--opacity', '1');
4
+ };
5
+ const handleHoverOut = () => {
6
+ node.style.setProperty('--input-emoji-picker--trigger--opacity', '');
7
+ };
8
+ node.addEventListener('mouseenter', handleHover);
9
+ node.addEventListener('mouseleave', handleHoverOut);
10
+ return {
11
+ destroy() {
12
+ node.removeEventListener('mouseenter', handleHover);
13
+ node.removeEventListener('mouseleave', handleHoverOut);
14
+ }
15
+ };
16
+ };