@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.
- package/dist/styles/_input.scss +98 -0
- package/dist/styles/_mixins.scss +2 -2
- package/dist/styles/reset.css +1 -1
- package/dist/ui/color-picker/cmp.color-picker.svelte +3 -12
- package/dist/ui/color-picker/cmp.color-picker.svelte.d.ts +3 -9
- package/dist/ui/dialog/cmp.dialog.svelte +1 -1
- package/dist/ui/dropdown/cmp.dropdown-item.svelte +93 -0
- package/dist/ui/dropdown/cmp.dropdown-item.svelte.d.ts +32 -0
- package/dist/ui/dropdown/cmp.dropdown-panel.svelte +29 -0
- package/dist/ui/dropdown/cmp.dropdown-panel.svelte.d.ts +18 -0
- package/dist/ui/dropdown/cmp.dropdown.svelte +72 -7
- package/dist/ui/dropdown/cmp.dropdown.svelte.d.ts +3 -1
- package/dist/ui/dropdown/index.d.ts +2 -0
- package/dist/ui/dropdown/index.js +2 -0
- package/dist/ui/dynamic-component/cmp.dynamic-component.svelte +0 -5
- package/dist/ui/dynamic-component/cmp.dynamic-component.svelte.d.ts +2 -8
- package/dist/ui/emoji-picker/cmp.emoji-panel.svelte +186 -0
- package/dist/ui/emoji-picker/cmp.emoji-panel.svelte.d.ts +21 -0
- package/dist/ui/emoji-picker/cmp.emoji-picker.svelte +35 -0
- package/dist/ui/emoji-picker/cmp.emoji-picker.svelte.d.ts +15 -0
- package/dist/ui/emoji-picker/emoji-list.d.ts +2 -0
- package/dist/ui/emoji-picker/emoji-list.js +1754 -0
- package/dist/ui/emoji-picker/emoji-picker-localization.d.ts +5 -0
- package/dist/ui/emoji-picker/emoji-picker-localization.js +40 -0
- package/dist/ui/emoji-picker/index.d.ts +2 -0
- package/dist/ui/emoji-picker/index.js +2 -0
- package/dist/ui/emoji-picker/types.d.ts +8 -0
- package/dist/ui/emoji-picker/types.js +1 -0
- package/dist/ui/form-group/cmp.form-group-label.svelte.d.ts +1 -0
- package/dist/ui/form-group/cmp.form-group.svelte.d.ts +1 -0
- package/dist/ui/icon-text/cmp.icon-text.svelte +0 -9
- package/dist/ui/icon-text/cmp.icon-text.svelte.d.ts +4 -9
- package/dist/ui/inputs/index.d.ts +6 -0
- package/dist/ui/inputs/index.js +5 -0
- package/dist/ui/inputs/input/cmp.input-validatable.svelte +57 -0
- package/dist/ui/inputs/input/cmp.input-validatable.svelte.d.ts +56 -0
- package/dist/ui/inputs/input/cmp.input.svelte +235 -0
- package/dist/ui/inputs/input/cmp.input.svelte.d.ts +60 -0
- package/dist/ui/inputs/input/index.d.ts +2 -0
- package/dist/ui/inputs/input/index.js +2 -0
- package/dist/ui/inputs/input-emoji-picker/cmp.input-emoji-picker.svelte +44 -0
- package/dist/ui/inputs/input-emoji-picker/cmp.input-emoji-picker.svelte.d.ts +9 -0
- package/dist/ui/inputs/input-emoji-picker/index.d.ts +2 -0
- package/dist/ui/inputs/input-emoji-picker/index.js +2 -0
- package/dist/ui/inputs/input-emoji-picker/input-emoji-picker-container.d.ts +2 -0
- package/dist/ui/inputs/input-emoji-picker/input-emoji-picker-container.js +16 -0
- package/dist/ui/inputs/numeral-input/cmp.numeral-input-validatable.svelte +55 -0
- package/dist/ui/inputs/numeral-input/cmp.numeral-input-validatable.svelte.d.ts +62 -0
- package/dist/ui/inputs/numeral-input/cmp.numeral-input.svelte +248 -0
- package/dist/ui/inputs/numeral-input/cmp.numeral-input.svelte.d.ts +66 -0
- package/dist/ui/inputs/numeral-input/index.d.ts +2 -0
- package/dist/ui/inputs/numeral-input/index.js +2 -0
- package/dist/ui/inputs/pin-input/cmp.pin-input.svelte +58 -0
- package/dist/ui/inputs/pin-input/cmp.pin-input.svelte.d.ts +23 -0
- package/dist/ui/inputs/pin-input/index.d.ts +1 -0
- package/dist/ui/inputs/pin-input/index.js +1 -0
- package/dist/ui/inputs/pin-input/pin-input-generator.d.ts +27 -0
- package/dist/ui/inputs/pin-input/pin-input-generator.js +114 -0
- package/dist/ui/inputs/rich-text-input/cmp.rich-text-input.svelte +55 -0
- package/dist/ui/inputs/rich-text-input/cmp.rich-text-input.svelte.d.ts +43 -0
- package/dist/ui/inputs/rich-text-input/index.d.ts +2 -0
- package/dist/ui/inputs/rich-text-input/index.js +1 -0
- package/dist/ui/inputs/rich-text-input/rich-text-input-localization.d.ts +12 -0
- package/dist/ui/inputs/rich-text-input/rich-text-input-localization.js +48 -0
- package/dist/ui/inputs/rich-text-input/tinymce-input.svelte +250 -0
- package/dist/ui/inputs/rich-text-input/tinymce-input.svelte.d.ts +25 -0
- package/dist/ui/inputs/rich-text-input/tinymce.declarations.d.ts +7 -0
- package/dist/ui/inputs/rich-text-input/types.d.ts +4 -0
- package/dist/ui/inputs/rich-text-input/types.js +1 -0
- package/dist/ui/inputs/rich-text-input/validated-link-button.d.ts +3 -0
- package/dist/ui/inputs/rich-text-input/validated-link-button.js +78 -0
- package/dist/ui/inputs/textarea/cmp.textarea-validatable.svelte +35 -0
- package/dist/ui/inputs/textarea/cmp.textarea-validatable.svelte.d.ts +53 -0
- package/dist/ui/inputs/textarea/cmp.textarea.svelte +247 -0
- package/dist/ui/inputs/textarea/cmp.textarea.svelte.d.ts +57 -0
- package/dist/ui/inputs/textarea/index.d.ts +2 -0
- package/dist/ui/inputs/textarea/index.js +2 -0
- package/dist/ui/media-viewer-dialog/cmp.media-viewer-dialog.svelte.d.ts +2 -0
- package/dist/ui/selects/_multiselect.scss +282 -0
- package/dist/ui/selects/_singleselect.scss +175 -0
- package/dist/ui/selects/cmp.multiselect.svelte +530 -0
- package/dist/ui/selects/cmp.multiselect.svelte.d.ts +85 -0
- package/dist/ui/selects/cmp.search-multiselect.svelte +532 -0
- package/dist/ui/selects/cmp.search-multiselect.svelte.d.ts +67 -0
- package/dist/ui/selects/cmp.singleselect.svelte +381 -0
- package/dist/ui/selects/cmp.singleselect.svelte.d.ts +78 -0
- package/dist/ui/selects/index.d.ts +5 -0
- package/dist/ui/selects/index.js +4 -0
- package/dist/ui/selects/select-localization.d.ts +6 -0
- package/dist/ui/selects/select-localization.js +27 -0
- package/dist/ui/selects/types.d.ts +29 -0
- package/dist/ui/selects/types.js +1 -0
- package/dist/ui/time-ago/cmp.time-ago.svelte +0 -6
- package/dist/ui/time-ago/cmp.time-ago.svelte.d.ts +2 -6
- package/dist/ui/validatable/_validatable.scss +34 -0
- package/dist/ui/validatable/cmp.validatable.svelte +57 -0
- package/dist/ui/validatable/cmp.validatable.svelte.d.ts +49 -0
- package/dist/ui/validatable/cmp.validation-error.svelte +52 -0
- package/dist/ui/validatable/cmp.validation-error.svelte.d.ts +42 -0
- package/dist/ui/validatable/index.d.ts +2 -0
- package/dist/ui/validatable/index.js +2 -0
- package/package.json +31 -5
- package/dist/ui/color-picker/cmp.input-stub.svelte +0 -98
- package/dist/ui/color-picker/cmp.input-stub.svelte.d.ts +0 -40
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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,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,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
|
+
};
|