milk-lib 0.0.14 → 0.0.16

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 (36) hide show
  1. package/README.md +8 -0
  2. package/dist/components/ButtonMilk/ButtonMilk.scss +23 -21
  3. package/dist/components/Command/Command.types.d.ts +29 -0
  4. package/dist/components/Command/Command.types.js +1 -0
  5. package/dist/components/Command/Command.utils.d.ts +9 -0
  6. package/dist/components/Command/Command.utils.js +8 -0
  7. package/dist/components/Command/CommandGroup.svelte +43 -0
  8. package/dist/components/Command/CommandGroup.svelte.d.ts +4 -0
  9. package/dist/components/Command/CommandInput.svelte +60 -0
  10. package/dist/components/Command/CommandInput.svelte.d.ts +9 -0
  11. package/dist/components/Command/CommandItem.svelte +102 -0
  12. package/dist/components/Command/CommandItem.svelte.d.ts +4 -0
  13. package/dist/components/Command/CommandList.svelte +13 -0
  14. package/dist/components/Command/CommandList.svelte.d.ts +4 -0
  15. package/dist/components/Command/CommandRoot.svelte +107 -0
  16. package/dist/components/Command/CommandRoot.svelte.d.ts +4 -0
  17. package/dist/components/Command/index.d.ts +6 -0
  18. package/dist/components/Command/index.js +6 -0
  19. package/dist/components/TextInputBlock/TextInputBlock.svelte +109 -0
  20. package/dist/components/TextInputBlock/TextInputBlock.svelte.d.ts +6 -0
  21. package/dist/components/TextInputBlock/TextInputBlock.types.d.ts +8 -0
  22. package/dist/components/TextInputBlock/TextInputBlock.types.js +1 -0
  23. package/dist/components/TextInputBlock/index.d.ts +2 -0
  24. package/dist/components/TextInputBlock/index.js +2 -0
  25. package/dist/components/TextInputMilk/TextInputMilk.scss +81 -0
  26. package/dist/components/TextInputMilk/TextInputMilk.svelte +39 -0
  27. package/dist/components/TextInputMilk/TextInputMilk.svelte.d.ts +7 -0
  28. package/dist/components/TextInputMilk/TextInputMilk.types.d.ts +7 -0
  29. package/dist/components/TextInputMilk/TextInputMilk.types.js +1 -0
  30. package/dist/components/TextInputMilk/index.d.ts +2 -0
  31. package/dist/components/TextInputMilk/index.js +2 -0
  32. package/dist/components/ThemeProvider/ThemeDefault.js +11 -6
  33. package/dist/components/ThemeProvider/ThemeProvider.types.d.ts +6 -0
  34. package/dist/components/index.d.ts +4 -1
  35. package/dist/components/index.js +4 -1
  36. package/package.json +1 -1
package/README.md CHANGED
@@ -1,3 +1,11 @@
1
1
  # MilkLib Sveltekit components library
2
2
 
3
3
  Sveltekit library, powered by [`sv`](https://npmjs.com/package/sv).
4
+
5
+ ## Todo
6
+ - Sync ButtonMilk and TextInputMilk css variables with global theme
7
+
8
+ ## Roadmap
9
+ + TextInput Milk
10
+ + TextInput Box
11
+ - Command
@@ -46,39 +46,41 @@
46
46
  --color: var(--text-base-main);
47
47
  }
48
48
 
49
- .Button.Button-lg[data-variant="milk"] {
50
- --padding-y: 7px;
51
- --padding-x: 20px;
52
- --font-size: 16px;
53
- --line-height: 24px;
54
- --border-radius: 8px;
55
- --inner-gap: 6px;
49
+ .Button.Button-sm[data-variant="milk"] {
50
+ --padding-y: 5px;
51
+ --padding-x: 10px;
52
+ --font-size: var(--font-size-sm);
53
+ --line-height: var(--line-height-sm);
54
+ --border-radius: var(--border-radius-button-sm);
55
+ --inner-gap: 3px;
56
56
  &.Button-icon {
57
- --padding-y: 11px;
58
- --padding-x: 11px;
57
+ --padding-y: 6px;
58
+ --padding-x: 6px;
59
59
  }
60
60
  }
61
+
61
62
  .Button.Button-md[data-variant="milk"] {
62
63
  --padding-y: 5px;
63
64
  --padding-x: 16px;
64
- --font-size: 14px;
65
- --line-height: 20px;
66
- --border-radius: 8px;
65
+ --font-size: var(--font-size-md);
66
+ --line-height: var(--line-height-md);
67
+ --border-radius: var(--border-radius-button);
67
68
  --inner-gap: 5px;
68
69
  &.Button-icon {
69
70
  --padding-y: 8px;
70
71
  --padding-x: 8px;
71
72
  }
72
73
  }
73
- .Button.Button-sm[data-variant="milk"] {
74
- --padding-y: 5px;
75
- --padding-x: 10px;
76
- --font-size: 12px;
77
- --line-height: 14px;
78
- --border-radius: 6px;
79
- --inner-gap: 3px;
74
+
75
+ .Button.Button-lg[data-variant="milk"] {
76
+ --padding-y: 7px;
77
+ --padding-x: 20px;
78
+ --font-size: var(--font-size-lg);
79
+ --line-height: var(--line-height-lg);
80
+ --border-radius: var(--border-radius-button);
81
+ --inner-gap: 6px;
80
82
  &.Button-icon {
81
- --padding-y: 6px;
82
- --padding-x: 6px;
83
+ --padding-y: 11px;
84
+ --padding-x: 11px;
83
85
  }
84
86
  }
@@ -0,0 +1,29 @@
1
+ import type { Snippet } from 'svelte';
2
+ import { type Writable } from 'svelte/store';
3
+ export interface ICommandRootProps {
4
+ classNames?: string;
5
+ children: Snippet;
6
+ maxHeight?: number;
7
+ }
8
+ export interface ICommandListProps {
9
+ children: Snippet;
10
+ }
11
+ export interface ICommandGroupProps {
12
+ heading?: string;
13
+ children: Snippet;
14
+ }
15
+ export interface ICommandItemProps {
16
+ disabled?: boolean;
17
+ onClick?: (e: MouseEvent | null) => void;
18
+ children: Snippet;
19
+ }
20
+ export type CommandItemEntry = {
21
+ el: HTMLElement;
22
+ id: symbol;
23
+ disabled?: boolean;
24
+ };
25
+ export interface ICommandItems {
26
+ items: Writable<CommandItemEntry[]>;
27
+ activeItemId: Writable<symbol>;
28
+ searchQuery: Writable<string>;
29
+ }
@@ -0,0 +1 @@
1
+ import {} from 'svelte/store';
@@ -0,0 +1,9 @@
1
+ import type { CommandItemEntry } from './Command.types';
2
+ export declare function sortItemsByDOMPosition(list: {
3
+ el: HTMLElement;
4
+ id: symbol;
5
+ }[]): {
6
+ el: HTMLElement;
7
+ id: symbol;
8
+ }[];
9
+ export declare function addItemSorted(list: CommandItemEntry[], entry: CommandItemEntry): CommandItemEntry[];
@@ -0,0 +1,8 @@
1
+ export function sortItemsByDOMPosition(list) {
2
+ return list.slice().sort((a, b) => a.el.compareDocumentPosition(b.el) & Node.DOCUMENT_POSITION_FOLLOWING
3
+ ? -1
4
+ : 1);
5
+ }
6
+ export function addItemSorted(list, entry) {
7
+ return sortItemsByDOMPosition([...list, entry]);
8
+ }
@@ -0,0 +1,43 @@
1
+ <script lang="ts">
2
+ import { setContext } from 'svelte';
3
+ import { writable } from 'svelte/store';
4
+ import type { ICommandGroupProps } from './Command.types';
5
+ let { heading, children } : ICommandGroupProps = $props();
6
+
7
+ let commandGroupItemsVisibility = writable<Record<symbol, boolean>>({});
8
+ setContext('command-group-visibility', { commandGroupItemsVisibility });
9
+ let allFalse = $derived(Object.getOwnPropertySymbols($commandGroupItemsVisibility)
10
+ .every(sym => $commandGroupItemsVisibility[sym] === false));
11
+
12
+
13
+
14
+ </script>
15
+
16
+
17
+
18
+ <div class="CommandGroup" class:hidden={allFalse} >
19
+ {#if heading}
20
+ <div class="CommandGroup-heading">{heading}</div>
21
+ {/if}
22
+ {@render children()}
23
+ </div>
24
+
25
+
26
+
27
+ <style>.CommandGroup {
28
+ padding: var(--group-padding-y) var(--group-padding-x);
29
+ border-bottom: 1px solid var(--border-color);
30
+ }
31
+ .CommandGroup.hidden {
32
+ display: none;
33
+ }
34
+ .CommandGroup:last-of-type {
35
+ border-bottom: none;
36
+ padding: 0 var(--group-padding-x);
37
+ }
38
+
39
+ .CommandGroup .CommandGroup-heading {
40
+ padding: var(--padding-y) var(--padding-x);
41
+ color: var(--group-heading-color);
42
+ font-size: 0.875em;
43
+ }</style>
@@ -0,0 +1,4 @@
1
+ import type { ICommandGroupProps } from './Command.types';
2
+ declare const CommandGroup: import("svelte").Component<ICommandGroupProps, {}, "">;
3
+ type CommandGroup = ReturnType<typeof CommandGroup>;
4
+ export default CommandGroup;
@@ -0,0 +1,60 @@
1
+ <script lang="ts">
2
+ import { TextInputBlock } from '../..';
3
+ import type { ITextInputBlockProps } from '../TextInputBlock/TextInputBlock.types';
4
+ import { Search2LineSystem } from 'svelte-remix';
5
+ import { getContext } from 'svelte';
6
+ import { type Writable } from 'svelte/store';
7
+
8
+ const { searchQuery } = getContext<{ searchQuery: Writable<string> }>('command-items');
9
+
10
+ let value = $state('');
11
+
12
+ function onInput(e: Event) {
13
+ searchQuery.set(value.toLowerCase().trim());
14
+ }
15
+
16
+ interface ICommandInputProps extends ITextInputBlockProps {
17
+ autoFocus?: boolean;
18
+ visible?: boolean;
19
+ placeholder?: string;
20
+ }
21
+
22
+ let { autoFocus, visible=true, placeholder, ...rest }: ICommandInputProps = $props();
23
+
24
+ </script>
25
+
26
+
27
+ <div class={`CommandInput ${visible ? 'visible' : ''}`}>
28
+ <TextInputBlock
29
+ readonly={!visible}
30
+ {autoFocus}
31
+ size='lg'
32
+ {placeholder}
33
+ variant="text"
34
+ onKeyUp={onInput}
35
+ bind:value type="text"
36
+ {...rest}
37
+ >
38
+ {#snippet prefix()}
39
+ <Search2LineSystem size="1em"/>
40
+ {/snippet}
41
+ </TextInputBlock>
42
+ </div>
43
+
44
+
45
+ <style>.CommandInput {
46
+ --border-color: var(--line-base);
47
+ margin-bottom: 0.25rem;
48
+ }
49
+
50
+ .CommandInput {
51
+ border-bottom: 1px solid var(--border-color);
52
+ opacity: 0;
53
+ position: absolute;
54
+ z-index: -1;
55
+ }
56
+ .CommandInput.visible {
57
+ opacity: 1;
58
+ position: relative;
59
+ z-index: 0;
60
+ }</style>
@@ -0,0 +1,9 @@
1
+ import type { ITextInputBlockProps } from '../TextInputBlock/TextInputBlock.types';
2
+ interface ICommandInputProps extends ITextInputBlockProps {
3
+ autoFocus?: boolean;
4
+ visible?: boolean;
5
+ placeholder?: string;
6
+ }
7
+ declare const CommandInput: import("svelte").Component<ICommandInputProps, {}, "">;
8
+ type CommandInput = ReturnType<typeof CommandInput>;
9
+ export default CommandInput;
@@ -0,0 +1,102 @@
1
+ <script lang="ts">
2
+ import { getContext, onMount, onDestroy } from 'svelte';
3
+ import { derived, type Writable } from 'svelte/store';
4
+ import type { ICommandItemProps, ICommandItems } from './Command.types';
5
+ import { addItemSorted } from './Command.utils';
6
+
7
+ let { disabled, onClick, children } : ICommandItemProps = $props();
8
+ let el: HTMLElement;
9
+ const itemId = Symbol();
10
+ let textContent = $state('');
11
+ let shouldShow = $state(true);
12
+ const { items, activeItemId, searchQuery }: ICommandItems = getContext('command-items');
13
+ const { commandGroupItemsVisibility }: { commandGroupItemsVisibility: Writable<Record<symbol, boolean>>} = getContext('command-group-visibility');
14
+
15
+ // Определяем нужно ли отображать элемент согласно searchQueryshad
16
+ $effect(() => {
17
+ textContent = el?.textContent?.toLowerCase().trim() || '';
18
+ shouldShow = !$searchQuery || textContent.includes($searchQuery);
19
+ // Этот блок передает в группу объект со значениями [id]: visible (для каждого CommandItem)
20
+ commandGroupItemsVisibility.update((recs) => ({ ...recs, [itemId]: shouldShow }));
21
+ });
22
+
23
+ onMount(() => {
24
+ // Добавляем элемент в Root state
25
+ items.update(list => addItemSorted(list, { el, id: itemId, disabled: !!disabled }));
26
+ });
27
+
28
+ onDestroy(() => {
29
+ // Непонятно нахрена это здесь. Это обновляет Root state зачем-то
30
+ items.update(list => list.filter(item => item.id !== itemId));
31
+ });
32
+
33
+ // Вычисляем активный это элемент или нет
34
+ const isActive = derived(activeItemId, $itemId => $itemId === itemId);
35
+
36
+ function handleClick(e: MouseEvent) {
37
+ if (disabled) return;
38
+ activeItemId.set(itemId);
39
+ onClick?.(e);
40
+ }
41
+
42
+ // Это не тестировалось еще TODO: to test
43
+ $effect(() => {
44
+ if ($isActive) {
45
+ el.scrollIntoView({ block: 'nearest' });
46
+ }
47
+ });
48
+
49
+ const handleKeyDown = (e: KeyboardEvent) => {
50
+ let key = (e.key);
51
+ if (key === 'Enter') {
52
+ onClick?.(null);
53
+ }
54
+ }
55
+
56
+ </script>
57
+
58
+ <div
59
+ bind:this={el}
60
+ onclick={handleClick}
61
+ onkeydown={handleKeyDown}
62
+ class={`CommandItem ${disabled ? 'disabled' : ''}`}
63
+ class:active={$isActive}
64
+ class:hidden={!shouldShow}
65
+ role="option"
66
+ tabindex="-1"
67
+ aria-selected={$isActive}
68
+ data-command-item
69
+ data-selected
70
+ >
71
+ {@render children()}
72
+ </div>
73
+
74
+ <style>.CommandItem {
75
+ display: flex;
76
+ flex-direction: row;
77
+ align-items: center;
78
+ padding: var(--padding-y) var(--padding-x);
79
+ gap: var(--inner-gap);
80
+ cursor: pointer;
81
+ border-radius: var(--item-border-radius);
82
+ transition: background 0.3s ease-in-out;
83
+ }
84
+ .CommandItem.hidden {
85
+ display: none;
86
+ }
87
+ .CommandItem:focus-visible, .CommandItem:focus-within {
88
+ outline: none;
89
+ }
90
+ .CommandItem.active {
91
+ background: var(--item-active);
92
+ }
93
+ .CommandItem.active:not(.disabled):hover {
94
+ background: var(--item-active);
95
+ }
96
+ .CommandItem.disabled {
97
+ opacity: var(--opacity-item-disabled);
98
+ cursor: not-allowed;
99
+ }
100
+ .CommandItem:not(.disabled):hover {
101
+ background: var(--item-hover);
102
+ }</style>
@@ -0,0 +1,4 @@
1
+ import type { ICommandItemProps } from './Command.types';
2
+ declare const CommandItem: import("svelte").Component<ICommandItemProps, {}, "">;
3
+ type CommandItem = ReturnType<typeof CommandItem>;
4
+ export default CommandItem;
@@ -0,0 +1,13 @@
1
+ <script lang="ts">
2
+ import type { ICommandListProps } from './Command.types';
3
+ let { children } : ICommandListProps = $props();
4
+ </script>
5
+
6
+ <div class="CommandList" role="listbox">
7
+ {@render children()}
8
+ </div>
9
+
10
+ <style>.CommandList {
11
+ display: flex;
12
+ flex-direction: column;
13
+ }</style>
@@ -0,0 +1,4 @@
1
+ import type { ICommandListProps } from './Command.types';
2
+ declare const CommandList: import("svelte").Component<ICommandListProps, {}, "">;
3
+ type CommandList = ReturnType<typeof CommandList>;
4
+ export default CommandList;
@@ -0,0 +1,107 @@
1
+ <script lang="ts">
2
+ import { setContext } from 'svelte';
3
+ import { writable, get } from 'svelte/store';
4
+ import type { ICommandRootProps, CommandItemEntry, ICommandItems } from './Command.types';
5
+
6
+ let { classNames, maxHeight, children }: ICommandRootProps = $props();
7
+
8
+ let rootEl: HTMLDivElement;
9
+ const items = writable<CommandItemEntry[]>([]);
10
+ let visibleItems = $derived($items.filter(i => {
11
+ const text = i.el.textContent?.toLowerCase() || '';
12
+ return text.includes($searchQuery);
13
+ }));
14
+ const activeItemId = writable<symbol>();
15
+ const searchQuery = writable('');
16
+ setContext<ICommandItems>('command-items', {
17
+ items, // список всех зарегистрированных children CommandItem
18
+ activeItemId, // ID текущего выбранного
19
+ searchQuery // строка поиска
20
+ });
21
+
22
+ function handleKeydown(e: KeyboardEvent) {
23
+
24
+ if (!visibleItems.length) return;
25
+
26
+ const index = visibleItems.findIndex(i => i.id === get(activeItemId));
27
+ const currentIndex = index === -1 ? 0 : index;
28
+
29
+ const findNext = (start: number) => {
30
+ for (let i = start + 1; i < visibleItems.length; i++) {
31
+ if (!visibleItems[i].disabled) return i;
32
+ }
33
+ return currentIndex;
34
+ };
35
+
36
+ const findPrev = (start: number) => {
37
+ for (let i = start - 1; i >= 0; i--) {
38
+ if (!visibleItems[i].disabled) return i;
39
+ }
40
+ return currentIndex;
41
+ };
42
+
43
+ if (e.key === 'ArrowDown') {
44
+ e.preventDefault();
45
+ const next = findNext(currentIndex);
46
+ activeItemId.set(visibleItems[next].id);
47
+
48
+ }
49
+
50
+ if (e.key === 'ArrowUp') {
51
+ e.preventDefault();
52
+ const prev = findPrev(currentIndex);
53
+ activeItemId.set(visibleItems[prev].id);
54
+ }
55
+
56
+ if (e.key === 'Enter') {
57
+ const id = get(activeItemId);
58
+ const current = get(items).find(item => item.id === id);
59
+ if (current && current.el && !current.disabled) {
60
+ current.el.click(); // Имитируем клик по активному CommandItem
61
+ }
62
+ }
63
+ }
64
+
65
+ </script>
66
+
67
+ <div
68
+ class={`CommandRoot ${classNames}`}
69
+ bind:this={rootEl}
70
+ tabindex="0"
71
+ onkeydown={handleKeydown}
72
+ role="listbox"
73
+ style={`${maxHeight ? `max-height: ${maxHeight}px; overflow-y: auto;` : ''}`}
74
+ >
75
+ {@render children()}
76
+ </div>
77
+
78
+ <style>.CommandRoot {
79
+ --border-color: var(--line-base);
80
+ --border-color-focus: var(--line-control-100);
81
+ --background-color: var(--bg-base);
82
+ --outter-padding: 4px;
83
+ --border-radius: var(--border-radius-panel);
84
+ --font-size: 1em;
85
+ --padding-y: 7px;
86
+ --padding-x: 12px;
87
+ --inner-gap: 7px;
88
+ --item-hover: var(--bg-base-100);
89
+ --item-active: var(--bg-base-200);
90
+ --item-border-radius: var(--border-radius-button);
91
+ --opacity-item-disabled: 0.6;
92
+ --group-heading-color: var(--text-base-muted);
93
+ --group-padding-y: 0;
94
+ --group-padding-x: 0;
95
+ }
96
+
97
+ .CommandRoot {
98
+ padding: var(--outter-padding);
99
+ border: 1px solid var(--border-color);
100
+ border-radius: var(--border-radius);
101
+ font-size: var(--font-size);
102
+ background: var(--background-color);
103
+ }
104
+ .CommandRoot:focus-visible, .CommandRoot:focus-within {
105
+ outline: none;
106
+ border-color: var(--line-control-100);
107
+ }</style>
@@ -0,0 +1,4 @@
1
+ import type { ICommandRootProps } from './Command.types';
2
+ declare const CommandRoot: import("svelte").Component<ICommandRootProps, {}, "">;
3
+ type CommandRoot = ReturnType<typeof CommandRoot>;
4
+ export default CommandRoot;
@@ -0,0 +1,6 @@
1
+ export { default as CommandRoot } from './CommandRoot.svelte';
2
+ export { default as CommandInput } from './CommandInput.svelte';
3
+ export { default as CommandList } from './CommandList.svelte';
4
+ export { default as CommandGroup } from './CommandGroup.svelte';
5
+ export { default as CommandItem } from './CommandItem.svelte';
6
+ export * from './Command.types';
@@ -0,0 +1,6 @@
1
+ export { default as CommandRoot } from './CommandRoot.svelte';
2
+ export { default as CommandInput } from './CommandInput.svelte';
3
+ export { default as CommandList } from './CommandList.svelte';
4
+ export { default as CommandGroup } from './CommandGroup.svelte';
5
+ export { default as CommandItem } from './CommandItem.svelte';
6
+ export * from './Command.types';
@@ -0,0 +1,109 @@
1
+ <script lang="ts">
2
+ import { TextInputMilk, type TextInputInstance } from '../..';
3
+ import type { ITextInputBlockProps } from './TextInputBlock.types';
4
+ import { CloseCircleFillSystem } from 'svelte-remix';
5
+
6
+ let {
7
+ prefix,
8
+ suffix,
9
+ disabled,
10
+ value = $bindable(),
11
+ placeholder,
12
+ variant = 'contained',
13
+ onClear,
14
+ pseudoFocus,
15
+ ...rest
16
+ }: ITextInputBlockProps = $props();
17
+
18
+ // Calculate suffix and prefix width
19
+ let prefixEl = $state<HTMLDivElement | null>(null);
20
+ let prefixWidth = $derived(prefixEl?.getBoundingClientRect().width || 0);
21
+
22
+ let suffixEl = $state<HTMLDivElement | null>(null);
23
+ let suffixWidth = $derived<number>(suffixEl?.getBoundingClientRect().width || 0);
24
+
25
+ // Прокидываем фокус примитива
26
+ let textInputRef: TextInputInstance;
27
+ export const focus = () => textInputRef.focus();
28
+
29
+ const handleClear = () => {
30
+ value = "";
31
+ textInputRef.focus();
32
+ onClear?.();
33
+ }
34
+
35
+ </script>
36
+
37
+ <div class="TextInputBlock">
38
+ {#if prefix}
39
+ <div class="prefix" bind:this={prefixEl}>
40
+ {@render prefix()}
41
+ </div>
42
+ {/if}
43
+
44
+ <TextInputMilk
45
+ placeholder={prefix ? (prefixWidth !== 0 ? placeholder : '') : placeholder}
46
+ {variant}
47
+ {disabled}
48
+ bind:this={textInputRef}
49
+ style={`
50
+ ${prefix ? `padding-left: ${prefixWidth + 4}px; padding-right: ${suffixWidth + 4}px;` : ``}
51
+ ${pseudoFocus ? `border-color: var(--border-color-focus)` : ``}
52
+ `}
53
+ bind:value
54
+ {...rest}
55
+ />
56
+
57
+
58
+ {#if onClear && !disabled && value !== ''}
59
+ <!-- I deliberately excluded this button from tabindex -->
60
+ <button tabindex="-1" type="button" class="clear-value" style={`right: ${suffixWidth + 12}px;`} onmouseup={handleClear}>
61
+ <CloseCircleFillSystem size="1em" />
62
+ </button>
63
+ {/if}
64
+
65
+ {#if suffix}
66
+ <div class="suffix" bind:this={suffixEl}>
67
+ {@render suffix()}
68
+ </div>
69
+ {/if}
70
+ </div>
71
+
72
+ <style>.TextInputBlock {
73
+ position: relative;
74
+ display: flex;
75
+ width: 100%;
76
+ }
77
+ .TextInputBlock .prefix, .TextInputBlock .suffix {
78
+ position: absolute;
79
+ z-index: 1;
80
+ top: 0;
81
+ bottom: 0;
82
+ height: 100%;
83
+ display: flex;
84
+ align-items: center;
85
+ }
86
+ .TextInputBlock .prefix {
87
+ left: 0;
88
+ padding-left: 0.75em;
89
+ }
90
+ .TextInputBlock .suffix {
91
+ right: 0;
92
+ padding-right: 0.75em;
93
+ }
94
+ .TextInputBlock .clear-value {
95
+ position: absolute;
96
+ z-index: 1;
97
+ top: 4px;
98
+ bottom: 4px;
99
+ height: calc(100% - 8px);
100
+ cursor: pointer;
101
+ border: 1px solid transparent;
102
+ border-radius: 8px;
103
+ padding: 0 4px;
104
+ }
105
+ .TextInputBlock .clear-value:focus {
106
+ outline: none;
107
+ background-color: #EDEEF0;
108
+ border-color: #D3D5DC;
109
+ }</style>
@@ -0,0 +1,6 @@
1
+ import type { ITextInputBlockProps } from './TextInputBlock.types';
2
+ declare const TextInputBlock: import("svelte").Component<ITextInputBlockProps, {
3
+ focus: () => void;
4
+ }, "value">;
5
+ type TextInputBlock = ReturnType<typeof TextInputBlock>;
6
+ export default TextInputBlock;
@@ -0,0 +1,8 @@
1
+ import type { ITextInputMilkProps } from '../..';
2
+ import type { Snippet } from 'svelte';
3
+ export interface ITextInputBlockProps extends ITextInputMilkProps {
4
+ prefix?: Snippet;
5
+ suffix?: Snippet;
6
+ onClear?: () => void;
7
+ pseudoFocus?: boolean;
8
+ }
@@ -0,0 +1,2 @@
1
+ export { default as TextInputBlock } from './TextInputBlock.svelte';
2
+ export * from './TextInputBlock.types';
@@ -0,0 +1,2 @@
1
+ export { default as TextInputBlock } from './TextInputBlock.svelte';
2
+ export * from './TextInputBlock.types';
@@ -0,0 +1,81 @@
1
+ .TextInput.TextInput-sm {
2
+ --padding-y: 5px;
3
+ --padding-x: 5px;
4
+ --font-size: var(--font-size-sm);
5
+ --line-height: var(--line-height-sm);
6
+ --border-radius: var(--border-radius-button-sm);
7
+ }
8
+
9
+ .TextInput.TextInput-md {
10
+ --padding-y: 5px;
11
+ --padding-x: 6px;
12
+ --font-size: var(--font-size-md);
13
+ --line-height: var(--line-height-md);
14
+ --border-radius: var(--border-radius-button);
15
+ }
16
+
17
+ .TextInput.TextInput-lg {
18
+ --padding-y: 7px;
19
+ --padding-x: 12px;
20
+ --font-size: var(--font-size-lg);
21
+ --line-height: var(--line-height-lg);
22
+ --border-radius: var(--border-radius-button);
23
+ }
24
+
25
+ .TextInput.TextInput-text {
26
+ --padding-x: 0px;
27
+ --border-radius: 0;
28
+ --border-width: 0px;
29
+ --background-color: transparent;
30
+ --border-color: transparent;
31
+ --border-color-focus: transparent;
32
+ }
33
+ .TextInput.TextInput-underlined {
34
+ --padding-x: 0px;
35
+
36
+ --border-radius: 0;
37
+ --border-style: solid;
38
+ --border-width: var(--stroke-base);
39
+ --border-top-width: 0px;
40
+ --border-bottom-width: var(--border-width);
41
+ --border-left-width: 0px;
42
+ --border-right-width: 0px;
43
+
44
+ --background-color: #fff;
45
+ --border-color: #D3D5DC;
46
+ --border-color-focus: #151617;
47
+
48
+ --background-disabled: var(--background-color);
49
+ --border-color-disabled: var(--border-color);
50
+ --opacity-disabled: 0.6;
51
+
52
+ --border-style-disabled: dashed;
53
+ --border-width-disabled: var(--border-width);
54
+ --border-top-width-disabled: 0px;
55
+ --border-bottom-width-disabled: var(--border-width-disabled);
56
+ --border-left-width-disabled: 0px;
57
+ --border-right-width-disabled: 0px;
58
+
59
+ --background-readonly: var(--background-disabled);
60
+ --border-color-readonly: var(--border-color);
61
+ --opacity-readonly: var(--opacity-disabled);
62
+
63
+ --border-style-readonly: dashed;
64
+ --border-width-readonly: var(--border-width);
65
+ --border-top-width-readonly: 0px;
66
+ --border-bottom-width-readonly: var(--border-width);
67
+ --border-left-width-readonly: 0px;
68
+ --border-right-width-readonly: 0px;
69
+
70
+ --border-color-invalid: #EA6D60;
71
+ --background-invalid: var(--background-color);
72
+ --border-style-invalid: var(--border-style);
73
+ --border-width-invalid: var(--border-width);
74
+ --border-top-width-invalid: 0px;
75
+ --border-bottom-width-invalid: var(--border-width);
76
+ --border-left-width-invalid: 0px;
77
+ --border-right-width-invalid: 0px;
78
+ }
79
+ .TextInput.TextInput-contained {
80
+ // Default
81
+ }
@@ -0,0 +1,39 @@
1
+ <script lang="ts">
2
+ import { TextInput, type TextInputInstance } from '../..';
3
+ import type { ITextInputMilkProps } from './TextInputMilk.types';
4
+
5
+ import "./TextInputMilk.scss";
6
+
7
+ let {
8
+ size = 'sm',
9
+ variant = 'contained',
10
+ value = $bindable(),
11
+ ...rest
12
+ }: ITextInputMilkProps = $props();
13
+
14
+ // Прокидываем фокус примитива
15
+ let textInputRef: TextInputInstance;
16
+ export const focus = () => textInputRef.focus();
17
+
18
+ let sizeClassName =
19
+ size === "sm" ? "TextInput-sm"
20
+ : size === "md" ? "TextInput-md"
21
+ : size === "lg" ? "TextInput-lg"
22
+ : "";
23
+
24
+ let variantClassname =
25
+ variant === "text" ? "TextInput-text"
26
+ : variant === "underlined" ? "TextInput-underlined"
27
+ : variant === "contained" ? "TextInput-contained" : ""
28
+
29
+ let classNames = `${sizeClassName} ${variantClassname}`;
30
+
31
+ </script>
32
+
33
+
34
+ <TextInput
35
+ bind:value
36
+ bind:this={textInputRef}
37
+ {classNames}
38
+ {...rest}
39
+ />
@@ -0,0 +1,7 @@
1
+ import type { ITextInputMilkProps } from './TextInputMilk.types';
2
+ import "./TextInputMilk.scss";
3
+ declare const TextInputMilk: import("svelte").Component<ITextInputMilkProps, {
4
+ focus: () => void;
5
+ }, "value">;
6
+ type TextInputMilk = ReturnType<typeof TextInputMilk>;
7
+ export default TextInputMilk;
@@ -0,0 +1,7 @@
1
+ import type { ITextInputProps } from '../TextInput/TextInput.types';
2
+ export type TextInputMilkSizes = 'sm' | 'md' | 'lg';
3
+ export type TextInputMilkVariants = 'underlined' | 'contained' | 'text';
4
+ export interface ITextInputMilkProps extends ITextInputProps {
5
+ size?: TextInputMilkSizes;
6
+ variant?: TextInputMilkVariants;
7
+ }
@@ -0,0 +1,2 @@
1
+ export { default as TextInputMilk } from './TextInputMilk.svelte';
2
+ export * from './TextInputMilk.types';
@@ -0,0 +1,2 @@
1
+ export { default as TextInputMilk } from './TextInputMilk.svelte';
2
+ export * from './TextInputMilk.types';
@@ -12,7 +12,6 @@ export const themeDefault = {
12
12
  '--line-success': '#B6F7CB',
13
13
  '--line-danger': '#FBC4BF',
14
14
  '--line-secondary': '#BEB6F9',
15
- // Add line-emp
16
15
  '--bg-base': '#fff',
17
16
  '--bg-base-100': '#EDEEF0',
18
17
  '--bg-base-200': '#E2E4E8',
@@ -64,10 +63,10 @@ export const themeDefault = {
64
63
  '--icon-primary-main': '#C29B09',
65
64
  '--icon-success-main': '#077129',
66
65
  '--icon-danger-main': '#C42A1A',
67
- '--border-radius-button-sm': '5',
68
- '--border-radius-button': '8',
69
- '--border-radius-panel': '12',
70
- '--border-radius-window': '20',
66
+ '--border-radius-button-sm': '5px',
67
+ '--border-radius-button': '8px',
68
+ '--border-radius-panel': '12px',
69
+ '--border-radius-window': '20px',
71
70
  '--stroke-base': '1px',
72
71
  '--stroke-button': 'var(--stroke-base)',
73
72
  '--spacing-xs-1': '4',
@@ -86,5 +85,11 @@ export const themeDefault = {
86
85
  '--zindex-modal': '1055',
87
86
  '--zindex-popover': '1070',
88
87
  '--zindex-tooltip': '1080',
89
- '--zindex-toast': '1090'
88
+ '--zindex-toast': '1090',
89
+ '--font-size-sm': '12px',
90
+ '--line-height-sm': '14px',
91
+ '--font-size-md': '14px',
92
+ '--line-height-md': '20px',
93
+ '--font-size-lg': '16px',
94
+ '--line-height-lg': '24px',
90
95
  };
@@ -87,4 +87,10 @@ export interface ITheme {
87
87
  '--zindex-popover': string;
88
88
  '--zindex-tooltip': string;
89
89
  '--zindex-toast': string;
90
+ '--font-size-sm': string;
91
+ '--line-height-sm': string;
92
+ '--font-size-md': string;
93
+ '--line-height-md': string;
94
+ '--font-size-lg': string;
95
+ '--line-height-lg': string;
90
96
  }
@@ -6,5 +6,8 @@ export * from './ThemeProvider';
6
6
  export * from './Button';
7
7
  export * from './ButtonMilk';
8
8
  export * from './Badge';
9
- export * from './TextInput';
10
9
  export * from './Label';
10
+ export * from './TextInput';
11
+ export * from './TextInputMilk';
12
+ export * from './TextInputBlock';
13
+ export * from './Command';
@@ -6,5 +6,8 @@ export * from './ThemeProvider';
6
6
  export * from './Button';
7
7
  export * from './ButtonMilk';
8
8
  export * from './Badge';
9
- export * from './TextInput';
10
9
  export * from './Label';
10
+ export * from './TextInput';
11
+ export * from './TextInputMilk';
12
+ export * from './TextInputBlock';
13
+ export * from './Command';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "milk-lib",
3
3
  "license": "MIT",
4
- "version": "0.0.14",
4
+ "version": "0.0.16",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
7
7
  "build": "vite build && npm run prepack",