@celar-ui/svelte 1.2.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,12 +20,12 @@
20
20
  :global([data-breadcrumb] > a) {
21
21
  padding: 0;
22
22
  margin: 0;
23
- color: var(--color-onInfo);
23
+ color: var(--color-info);
24
24
  text-decoration: none;
25
25
  }
26
26
  :global([data-breadcrumb] > a):not(:last-child)::after {
27
27
  content: "/";
28
- color: var(--color-onInfo);
28
+ color: currentColor;
29
29
  padding: 0 var(--gap--half);
30
30
  }
31
31
  :global([data-breadcrumb] > a):last-child {
package/dist/index.d.ts CHANGED
@@ -20,6 +20,7 @@ export { default as Gap } from './misc/Gap.svelte';
20
20
  export { default as DuckSpinner } from './misc/DuckSpinner.svelte';
21
21
  export { default as DotSpinner } from './misc/DotSpinner.svelte';
22
22
  export { default as LinearProgressIndicator } from './misc/LinearProgressIndicator.svelte';
23
+ export { default as Badge } from './misc/Badge.svelte';
23
24
  export { default as TextInput } from './inputs/TextInput.svelte';
24
25
  export { default as FileInput } from './inputs/FileInput.svelte';
25
26
  export { default as ColorInput } from './inputs/ColorInput.svelte';
@@ -28,6 +29,7 @@ export { default as RadioGroup } from './inputs/RadioGroup.svelte';
28
29
  export { default as RadioItem } from './inputs/RadioItem.svelte';
29
30
  export { default as Switch } from './inputs/Switch.svelte';
30
31
  export { default as Slider } from './inputs/Slider.svelte';
32
+ export { default as TagInput } from './inputs/TagInput.svelte';
31
33
  export { default as AppBar } from './navigation/AppBar.svelte';
32
34
  export { default as NavigationBar } from './navigation/NavigationBar.svelte';
33
35
  export { default as NavigationBarButton } from './navigation/NavigationBarButton.svelte';
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ export { default as Gap } from './misc/Gap.svelte';
21
21
  export { default as DuckSpinner } from './misc/DuckSpinner.svelte';
22
22
  export { default as DotSpinner } from './misc/DotSpinner.svelte';
23
23
  export { default as LinearProgressIndicator } from './misc/LinearProgressIndicator.svelte';
24
+ export { default as Badge } from './misc/Badge.svelte';
24
25
  export { default as TextInput } from './inputs/TextInput.svelte';
25
26
  export { default as FileInput } from './inputs/FileInput.svelte';
26
27
  export { default as ColorInput } from './inputs/ColorInput.svelte';
@@ -29,6 +30,7 @@ export { default as RadioGroup } from './inputs/RadioGroup.svelte';
29
30
  export { default as RadioItem } from './inputs/RadioItem.svelte';
30
31
  export { default as Switch } from './inputs/Switch.svelte';
31
32
  export { default as Slider } from './inputs/Slider.svelte';
33
+ export { default as TagInput } from './inputs/TagInput.svelte';
32
34
  export { default as AppBar } from './navigation/AppBar.svelte';
33
35
  export { default as NavigationBar } from './navigation/NavigationBar.svelte';
34
36
  export { default as NavigationBarButton } from './navigation/NavigationBarButton.svelte';
@@ -0,0 +1,174 @@
1
+ <script lang="ts">
2
+ import Badge from '../misc/Badge.svelte';
3
+ import type { HTMLInputAttributes } from 'svelte/elements';
4
+
5
+ interface TagInputProps extends Omit<HTMLInputAttributes, 'value'> {
6
+ tags?: string[];
7
+ placeholder?: string;
8
+ maxTags?: number;
9
+ allowDuplicates?: boolean;
10
+ onTagAdd?: (tag: string) => void;
11
+ onTagRemove?: (tag: string, index: number) => void;
12
+ }
13
+
14
+ let {
15
+ tags = $bindable([]),
16
+ placeholder = 'Add tags...',
17
+ maxTags,
18
+ allowDuplicates = false,
19
+ onTagAdd,
20
+ onTagRemove,
21
+ ...rest
22
+ }: TagInputProps = $props();
23
+
24
+ let inputValue = $state('');
25
+
26
+ let inputElement: HTMLInputElement;
27
+
28
+ const addTag = (tag: string) => {
29
+ const trimmedTag = tag.trim();
30
+ if (!trimmedTag) return;
31
+
32
+ if (maxTags !== undefined && tags.length >= maxTags) return;
33
+ if (!allowDuplicates && tags.includes(trimmedTag)) return;
34
+
35
+ tags.push(trimmedTag);
36
+ onTagAdd?.(trimmedTag);
37
+ inputValue = '';
38
+ };
39
+
40
+ const removeTag = (index: number) => {
41
+ const removedTag = tags[index];
42
+ tags.splice(index, 1);
43
+ onTagRemove?.(removedTag, index);
44
+ };
45
+
46
+ const handleKeydown = (event: KeyboardEvent) => {
47
+ if (event.key === 'Enter' || event.key === ',') {
48
+ event.preventDefault();
49
+ addTag(inputValue);
50
+ } else if (event.key === 'Backspace' && !inputValue && tags.length > 0) {
51
+ removeTag(tags.length - 1);
52
+ }
53
+ };
54
+
55
+ const handleInputBlur = () => {
56
+ if (inputValue) {
57
+ addTag(inputValue);
58
+ }
59
+ };
60
+
61
+ const focusInputElement = () => {
62
+ inputElement?.focus();
63
+ };
64
+ </script>
65
+
66
+ <div
67
+ data-tag-input
68
+ onclick={focusInputElement}
69
+ onkeyup={focusInputElement}
70
+ role="button"
71
+ tabindex="0"
72
+ >
73
+ {#each tags as tag, index (index)}
74
+ <Badge size="large">
75
+ {tag}
76
+
77
+ <button
78
+ type="button"
79
+ data-tag-remove
80
+ onclick={() => removeTag(index)}
81
+ aria-label="Remove {tag}"
82
+ >
83
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24">
84
+ <path
85
+ fill="none"
86
+ stroke="currentColor"
87
+ stroke-linecap="round"
88
+ stroke-linejoin="round"
89
+ stroke-width="2"
90
+ d="M18 6L6 18M6 6l12 12"
91
+ />
92
+ </svg>
93
+ </button>
94
+ </Badge>
95
+ {/each}
96
+
97
+ <input
98
+ {...rest}
99
+ bind:this={inputElement}
100
+ bind:value={inputValue}
101
+ {placeholder}
102
+ onkeydown={handleKeydown}
103
+ onblur={handleInputBlur}
104
+ disabled={maxTags !== undefined && tags.length >= maxTags}
105
+ />
106
+ </div>
107
+
108
+ <style>[data-tag-input] {
109
+ --color-background: transparent;
110
+ display: flex;
111
+ align-items: center;
112
+ flex-wrap: wrap;
113
+ gap: var(--gap--sm);
114
+ position: relative;
115
+ width: 100%;
116
+ box-sizing: border-box;
117
+ transition-duration: var(--transition-dur);
118
+ transition-property: border-color;
119
+ transition-timing-function: ease-in-out;
120
+ border: 1px solid var(--color-border);
121
+ border-radius: var(--radius);
122
+ background-color: var(--color-background);
123
+ padding: var(--gap--md);
124
+ cursor: text;
125
+ }
126
+ [data-tag-input]:focus-within {
127
+ border: 1px solid var(--color-primary);
128
+ }
129
+ [data-tag-input] input {
130
+ flex: 1;
131
+ border: none;
132
+ outline: none;
133
+ background: transparent;
134
+ font-size: inherit;
135
+ font-family: inherit;
136
+ color: inherit;
137
+ }
138
+ [data-tag-input] input::-moz-placeholder {
139
+ opacity: 1;
140
+ color: rgba(var(--color-onSurface--rgb), 0.7);
141
+ }
142
+ [data-tag-input] input::placeholder {
143
+ opacity: 1;
144
+ color: rgba(var(--color-onSurface--rgb), 0.7);
145
+ }
146
+ [data-tag-input] input:disabled {
147
+ opacity: 0.5;
148
+ cursor: not-allowed;
149
+ }
150
+ [data-tag-input] [data-tag-remove] {
151
+ display: inline-flex;
152
+ justify-content: center;
153
+ align-items: center;
154
+ background-color: transparent;
155
+ border: none;
156
+ color: inherit;
157
+ cursor: pointer;
158
+ padding: var(--gap--xs);
159
+ border-radius: 50%;
160
+ aspect-ratio: 1;
161
+ transition-duration: var(--transition-dur);
162
+ transition-property: background-color;
163
+ transition-timing-function: ease-in-out;
164
+ margin-left: var(--gap--sm);
165
+ }
166
+ [data-tag-input] [data-tag-remove]:hover {
167
+ background-color: var(--color-surfaceContainer);
168
+ }
169
+ [data-tag-input] [data-tag-remove]:focus {
170
+ outline: 1px solid var(--color-border);
171
+ }
172
+ [data-tag-input] [data-tag-remove] svg {
173
+ width: var(--gap);
174
+ }</style>
@@ -0,0 +1,12 @@
1
+ import type { HTMLInputAttributes } from 'svelte/elements';
2
+ interface TagInputProps extends Omit<HTMLInputAttributes, 'value'> {
3
+ tags?: string[];
4
+ placeholder?: string;
5
+ maxTags?: number;
6
+ allowDuplicates?: boolean;
7
+ onTagAdd?: (tag: string) => void;
8
+ onTagRemove?: (tag: string, index: number) => void;
9
+ }
10
+ declare const TagInput: import("svelte").Component<TagInputProps, {}, "tags">;
11
+ type TagInput = ReturnType<typeof TagInput>;
12
+ export default TagInput;
@@ -0,0 +1,55 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+
4
+ interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
5
+ color?: 'success' | 'info' | 'warning' | 'error' | 'surface';
6
+ size?: 'small' | 'medium' | 'large';
7
+ }
8
+
9
+ let { children, color = 'surface', size = 'small', ...rest }: BadgeProps = $props();
10
+ </script>
11
+
12
+ <span {...rest} data-badge data-color={color} data-size={size}>
13
+ {@render children?.()}
14
+ </span>
15
+
16
+ <style>[data-badge] {
17
+ box-sizing: border-box;
18
+ border-radius: var(--gap);
19
+ line-height: 1;
20
+ display: inline-flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ }
24
+ [data-badge][data-color=surface] {
25
+ background-color: var(--color-surfaceContainerHighest);
26
+ color: var(--color-onSurface);
27
+ }
28
+ [data-badge][data-color=info] {
29
+ background-color: var(--color-info);
30
+ color: var(--color-onInfo);
31
+ }
32
+ [data-badge][data-color=success] {
33
+ background-color: var(--color-success);
34
+ color: var(--color-onSuccess);
35
+ }
36
+ [data-badge][data-color=warning] {
37
+ background-color: var(--color-warning);
38
+ color: var(--color-onWarning);
39
+ }
40
+ [data-badge][data-color=error] {
41
+ background-color: var(--color-error);
42
+ color: var(--color-onError);
43
+ }
44
+ [data-badge][data-size=small] {
45
+ font-size: 0.8em;
46
+ padding: var(--gap--sm) var(--gap--half);
47
+ }
48
+ [data-badge][data-size=medium] {
49
+ font-size: 0.9em;
50
+ padding: var(--gap--sm) var(--gap--half);
51
+ }
52
+ [data-badge][data-size=large] {
53
+ font-size: 1em;
54
+ padding: var(--gap--sm) var(--gap--md);
55
+ }</style>
@@ -0,0 +1,8 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
3
+ color?: 'success' | 'info' | 'warning' | 'error' | 'surface';
4
+ size?: 'small' | 'medium' | 'large';
5
+ }
6
+ declare const Badge: import("svelte").Component<BadgeProps, {}, "">;
7
+ type Badge = ReturnType<typeof Badge>;
8
+ export default Badge;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@celar-ui/svelte",
3
- "version": "1.2.3",
3
+ "version": "1.4.0",
4
4
  "license": "MIT",
5
5
  "author": {
6
6
  "name": "cuikho210",
@@ -51,32 +51,32 @@
51
51
  "svelte": "^5.0.0"
52
52
  },
53
53
  "devDependencies": {
54
- "@eslint/compat": "^1.2.8",
55
- "@eslint/js": "^9.24.0",
56
- "@iconify-json/hugeicons": "^1.2.4",
54
+ "@eslint/compat": "^1.4.0",
55
+ "@eslint/js": "^9.36.0",
56
+ "@iconify-json/hugeicons": "^1.2.16",
57
57
  "@sveltejs/adapter-auto": "^4.0.0",
58
- "@sveltejs/kit": "^2.20.5",
59
- "@sveltejs/package": "^2.3.10",
60
- "@sveltejs/vite-plugin-svelte": "^5.0.3",
61
- "@types/bun": "^1.2.20",
58
+ "@sveltejs/kit": "^2.43.1",
59
+ "@sveltejs/package": "^2.5.3",
60
+ "@sveltejs/vite-plugin-svelte": "^5.1.1",
61
+ "@types/bun": "^1.2.22",
62
62
  "autoprefixer": "^10.4.21",
63
- "bits-ui": "^2.8.8",
63
+ "bits-ui": "^2.11.0",
64
64
  "csstype": "^3.1.3",
65
- "eslint": "^9.24.0",
66
- "eslint-config-prettier": "^10.1.2",
67
- "eslint-plugin-svelte": "^3.5.1",
68
- "globals": "^16.0.0",
65
+ "eslint": "^9.36.0",
66
+ "eslint-config-prettier": "^10.1.8",
67
+ "eslint-plugin-svelte": "^3.12.4",
68
+ "globals": "^16.4.0",
69
69
  "material-dynamic-colors": "^1.1.2",
70
- "prettier": "^3.5.3",
71
- "prettier-plugin-svelte": "^3.3.3",
72
- "publint": "^0.3.11",
73
- "sass": "^1.86.3",
74
- "svelte": "^5.34.7",
75
- "svelte-check": "^4.1.5",
76
- "typescript": "^5.8.3",
77
- "typescript-eslint": "^8.29.1",
78
- "unplugin-icons": "^22.1.0",
79
- "vite": "^6.2.6"
70
+ "prettier": "^3.6.2",
71
+ "prettier-plugin-svelte": "^3.4.0",
72
+ "publint": "^0.3.13",
73
+ "sass": "^1.93.1",
74
+ "svelte": "^5.39.4",
75
+ "svelte-check": "^4.3.2",
76
+ "typescript": "^5.9.2",
77
+ "typescript-eslint": "^8.44.1",
78
+ "unplugin-icons": "^22.3.0",
79
+ "vite": "^6.3.6"
80
80
  },
81
81
  "keywords": [
82
82
  "svelte"
@@ -3,21 +3,21 @@
3
3
  @use './scheme.scss';
4
4
 
5
5
  $ext-colors-light: (
6
- color-info: #e2ffff,
7
- color-onInfo: #1a3baa,
8
- color-success: #e8fef5,
9
- color-onSuccess: #2b5f50,
10
- color-warning: #fff8ec,
11
- color-onWarning: #8a5a00
6
+ color-info: #1a3baa,
7
+ color-onInfo: #e2ffff,
8
+ color-success: #2b5f50,
9
+ color-onSuccess: #e8fef5,
10
+ color-warning: #8a5a00,
11
+ color-onWarning: #fff8ec
12
12
  ) !default;
13
13
 
14
14
  $ext-colors-dark: (
15
- color-info: #101a3b,
16
- color-onInfo: #008eff,
17
- color-success: #184d3a,
18
- color-onSuccess: #9bdac7,
19
- color-warning: #4a3700,
20
- color-onWarning: #bfa060
15
+ color-info: #008eff,
16
+ color-onInfo: #101a3b,
17
+ color-success: #9bdac7,
18
+ color-onSuccess: #184d3a,
19
+ color-warning: #bfa060,
20
+ color-onWarning: #4a3700
21
21
  ) !default;
22
22
 
23
23
  $colors-misc: (