@groundbrick/svelte-ui 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +125 -0
  2. package/dist/components/Alert.svelte +335 -0
  3. package/dist/components/Alert.svelte.d.ts +24 -0
  4. package/dist/components/AutocompleteInput.svelte +356 -0
  5. package/dist/components/AutocompleteInput.svelte.d.ts +72 -0
  6. package/dist/components/Badge.svelte +185 -0
  7. package/dist/components/Badge.svelte.d.ts +20 -0
  8. package/dist/components/Button.svelte +415 -0
  9. package/dist/components/Button.svelte.d.ts +34 -0
  10. package/dist/components/Card.svelte +181 -0
  11. package/dist/components/Card.svelte.d.ts +24 -0
  12. package/dist/components/CardBody.svelte +78 -0
  13. package/dist/components/CardBody.svelte.d.ts +12 -0
  14. package/dist/components/CardFooter.svelte +81 -0
  15. package/dist/components/CardFooter.svelte.d.ts +14 -0
  16. package/dist/components/CardHeader.svelte +186 -0
  17. package/dist/components/CardHeader.svelte.d.ts +21 -0
  18. package/dist/components/Col.svelte +172 -0
  19. package/dist/components/Col.svelte.d.ts +26 -0
  20. package/dist/components/Container.svelte +118 -0
  21. package/dist/components/Container.svelte.d.ts +14 -0
  22. package/dist/components/Drawer.svelte +233 -0
  23. package/dist/components/Drawer.svelte.d.ts +13 -0
  24. package/dist/components/Dropdown.svelte +190 -0
  25. package/dist/components/Dropdown.svelte.d.ts +26 -0
  26. package/dist/components/DropdownItem.svelte +103 -0
  27. package/dist/components/DropdownItem.svelte.d.ts +22 -0
  28. package/dist/components/DurationInput.svelte +170 -0
  29. package/dist/components/DurationInput.svelte.d.ts +27 -0
  30. package/dist/components/EditableTable.svelte +647 -0
  31. package/dist/components/EditableTable.svelte.d.ts +74 -0
  32. package/dist/components/EmptyState.svelte +192 -0
  33. package/dist/components/EmptyState.svelte.d.ts +22 -0
  34. package/dist/components/FormField.svelte +260 -0
  35. package/dist/components/FormField.svelte.d.ts +68 -0
  36. package/dist/components/GridView.svelte +1022 -0
  37. package/dist/components/GridView.svelte.d.ts +38 -0
  38. package/dist/components/GridView.types.d.ts +28 -0
  39. package/dist/components/GridView.types.js +1 -0
  40. package/dist/components/LoadingSpinner.svelte +253 -0
  41. package/dist/components/LoadingSpinner.svelte.d.ts +17 -0
  42. package/dist/components/Modal.svelte +473 -0
  43. package/dist/components/Modal.svelte.d.ts +42 -0
  44. package/dist/components/PhoneInput.svelte +406 -0
  45. package/dist/components/PhoneInput.svelte.d.ts +31 -0
  46. package/dist/components/PhotoUpload.svelte +529 -0
  47. package/dist/components/PhotoUpload.svelte.d.ts +46 -0
  48. package/dist/components/Row.svelte +153 -0
  49. package/dist/components/Row.svelte.d.ts +18 -0
  50. package/dist/icons/PawPrintIcon.svelte +41 -0
  51. package/dist/icons/PawPrintIcon.svelte.d.ts +14 -0
  52. package/dist/index.d.ts +41 -0
  53. package/dist/index.js +49 -0
  54. package/dist/styles/forms.css +182 -0
  55. package/dist/styles/tokens.css +243 -0
  56. package/dist/utils/duration.d.ts +20 -0
  57. package/dist/utils/duration.js +40 -0
  58. package/dist/utils/scrollLock.d.ts +7 -0
  59. package/dist/utils/scrollLock.js +26 -0
  60. package/package.json +66 -0
@@ -0,0 +1,356 @@
1
+ <script lang="ts" module>
2
+ import type { Snippet } from "svelte";
3
+
4
+ export interface AutocompleteSuggestion<T = unknown> {
5
+ /** Display label for the suggestion */
6
+ label: string;
7
+ /** Optional secondary text */
8
+ subtitle?: string;
9
+ /** The original data item */
10
+ data: T;
11
+ }
12
+
13
+ export interface AutocompleteInputProps<T = unknown> {
14
+ /** Current input value (bindable) */
15
+ value: string;
16
+ /** Input ID */
17
+ id?: string;
18
+ /** Label text */
19
+ label?: string;
20
+ /** Placeholder text */
21
+ placeholder?: string;
22
+ /** Disabled state */
23
+ disabled?: boolean;
24
+ /** Input type */
25
+ type?: 'text' | 'tel' | 'email' | 'search';
26
+ /** Max length */
27
+ maxlength?: number;
28
+ /** Required field */
29
+ required?: boolean;
30
+ /** Minimum characters before searching */
31
+ minChars?: number;
32
+ /** Debounce delay in ms */
33
+ debounceMs?: number;
34
+ /** Icon to show on the left side of the input */
35
+ icon?: Snippet;
36
+ /** Extra content to render on the right side of each suggestion (receives suggestion data) */
37
+ suggestionExtra?: Snippet<[AutocompleteSuggestion<T>]>;
38
+ /** Function to fetch suggestions */
39
+ fetchSuggestions: (query: string) => Promise<AutocompleteSuggestion<T>[]>;
40
+ /** Called when user selects a suggestion */
41
+ onSelect?: (suggestion: AutocompleteSuggestion<T>) => void;
42
+ /** Called when input value changes */
43
+ oninput?: (value: string) => void;
44
+ /** Optional sticky footer action shown at the bottom of the dropdown.
45
+ * Useful for "Create new" affordances. Does NOT trigger onSelect. */
46
+ footerAction?: { label: string; icon?: string; onClick: () => void };
47
+ }
48
+ </script>
49
+
50
+ <script lang="ts" generics="T">
51
+ import FormField from "./FormField.svelte";
52
+
53
+ let {
54
+ value = $bindable(""),
55
+ id = "autocomplete",
56
+ label = "",
57
+ placeholder = "",
58
+ disabled = false,
59
+ type = 'text',
60
+ maxlength,
61
+ required = false,
62
+ minChars = 2,
63
+ debounceMs = 300,
64
+ icon,
65
+ suggestionExtra,
66
+ fetchSuggestions,
67
+ onSelect,
68
+ oninput,
69
+ footerAction,
70
+ }: AutocompleteInputProps<T> = $props();
71
+
72
+ // State
73
+ let suggestions = $state<AutocompleteSuggestion<T>[]>([]);
74
+ let showDropdown = $state(false);
75
+ let isLoading = $state(false);
76
+ let highlightedIndex = $state(-1);
77
+ let inputElement: HTMLInputElement | undefined = $state();
78
+
79
+ // Debounce timer
80
+ let searchTimeout: ReturnType<typeof setTimeout> | null = null;
81
+
82
+ function handleInput(inputValue: string | number) {
83
+ value = String(inputValue);
84
+ oninput?.(value);
85
+ highlightedIndex = -1;
86
+
87
+ if (value.length >= minChars) {
88
+ debouncedSearch(value);
89
+ } else {
90
+ suggestions = [];
91
+ showDropdown = false;
92
+ }
93
+ }
94
+
95
+ function debouncedSearch(query: string) {
96
+ if (searchTimeout) {
97
+ clearTimeout(searchTimeout);
98
+ }
99
+
100
+ searchTimeout = setTimeout(async () => {
101
+ await performSearch(query);
102
+ }, debounceMs);
103
+ }
104
+
105
+ async function performSearch(query: string) {
106
+ isLoading = true;
107
+
108
+ try {
109
+ const results = await fetchSuggestions(query);
110
+ suggestions = results;
111
+ showDropdown = results.length > 0 || footerAction !== undefined;
112
+ } catch (error) {
113
+ console.error("Autocomplete search error:", error);
114
+ suggestions = [];
115
+ showDropdown = false;
116
+ } finally {
117
+ isLoading = false;
118
+ }
119
+ }
120
+
121
+ function selectSuggestion(suggestion: AutocompleteSuggestion<T>) {
122
+ value = suggestion.label;
123
+ showDropdown = false;
124
+ suggestions = [];
125
+ highlightedIndex = -1;
126
+ onSelect?.(suggestion);
127
+ oninput?.(value);
128
+ }
129
+
130
+ function handleKeydown(e: KeyboardEvent) {
131
+ if (!showDropdown) return;
132
+
133
+ const hasFooter = footerAction !== undefined;
134
+ const totalItems = suggestions.length + (hasFooter ? 1 : 0);
135
+ if (totalItems === 0) return;
136
+
137
+ switch (e.key) {
138
+ case "ArrowDown":
139
+ e.preventDefault();
140
+ highlightedIndex = Math.min(highlightedIndex + 1, totalItems - 1);
141
+ break;
142
+ case "ArrowUp":
143
+ e.preventDefault();
144
+ highlightedIndex = Math.max(highlightedIndex - 1, 0);
145
+ break;
146
+ case "Enter":
147
+ if (highlightedIndex >= 0) {
148
+ e.preventDefault();
149
+ if (highlightedIndex < suggestions.length) {
150
+ selectSuggestion(suggestions[highlightedIndex]);
151
+ } else if (hasFooter) {
152
+ handleFooterClick();
153
+ }
154
+ }
155
+ break;
156
+ case "Escape":
157
+ showDropdown = false;
158
+ highlightedIndex = -1;
159
+ break;
160
+ }
161
+ }
162
+
163
+ function handleFooterClick() {
164
+ footerAction?.onClick();
165
+ showDropdown = false;
166
+ highlightedIndex = -1;
167
+ }
168
+
169
+ function handleBlur() {
170
+ // Delay to allow click on dropdown item
171
+ setTimeout(() => {
172
+ showDropdown = false;
173
+ highlightedIndex = -1;
174
+ }, 200);
175
+ }
176
+
177
+ function handleFocus() {
178
+ if ((suggestions.length > 0 || footerAction) && value.length >= minChars) {
179
+ showDropdown = true;
180
+ }
181
+ }
182
+ </script>
183
+
184
+ <div class="autocomplete-container">
185
+ <FormField
186
+ {id}
187
+ {label}
188
+ {type}
189
+ bind:value
190
+ {placeholder}
191
+ {disabled}
192
+ {required}
193
+ {maxlength}
194
+ autocomplete="off"
195
+ oninput={handleInput}
196
+ onblur={handleBlur}
197
+ onfocus={handleFocus}
198
+ onkeydown={handleKeydown}
199
+ bind:inputRef={inputElement}
200
+ inputIcon={icon}
201
+ >
202
+ {#snippet inputAddon()}
203
+ {#if isLoading}
204
+ <div class="ap-spinner-inline" role="status">
205
+ <span class="visually-hidden">A procurar...</span>
206
+ </div>
207
+ {/if}
208
+ {/snippet}
209
+ </FormField>
210
+
211
+ {#if showDropdown && (suggestions.length > 0 || footerAction)}
212
+ <div class="suggestions-dropdown">
213
+ {#each suggestions as suggestion, index}
214
+ <button
215
+ type="button"
216
+ class="suggestion-item"
217
+ class:highlighted={index === highlightedIndex}
218
+ class:has-extra={suggestionExtra}
219
+ onclick={() => selectSuggestion(suggestion)}
220
+ onmouseenter={() => highlightedIndex = index}
221
+ >
222
+ <div class="suggestion-content">
223
+ <span class="suggestion-label">{suggestion.label}</span>
224
+ {#if suggestion.subtitle}
225
+ <span class="suggestion-subtitle">{suggestion.subtitle}</span>
226
+ {/if}
227
+ </div>
228
+ {#if suggestionExtra}
229
+ <div class="suggestion-extra">
230
+ {@render suggestionExtra(suggestion)}
231
+ </div>
232
+ {/if}
233
+ </button>
234
+ {/each}
235
+ {#if footerAction}
236
+ <button
237
+ type="button"
238
+ class="suggestion-footer"
239
+ class:highlighted={highlightedIndex === suggestions.length}
240
+ onclick={handleFooterClick}
241
+ onmouseenter={() => highlightedIndex = suggestions.length}
242
+ >
243
+ {#if footerAction.icon}
244
+ <i class="bi {footerAction.icon}"></i>
245
+ {/if}
246
+ <span>{footerAction.label}</span>
247
+ </button>
248
+ {/if}
249
+ </div>
250
+ {/if}
251
+ </div>
252
+
253
+ <style>
254
+ .autocomplete-container {
255
+ position: relative;
256
+ width: 100%;
257
+ }
258
+
259
+ /* ===== Dropdown ===== */
260
+ .suggestions-dropdown {
261
+ position: absolute;
262
+ top: 100%;
263
+ left: 0;
264
+ right: 0;
265
+ z-index: var(--z-dropdown, 1000);
266
+ margin-top: var(--spacing-xs, 0.25rem);
267
+ border: 1px solid var(--color-border-subtle);
268
+ border-radius: var(--radius-lg);
269
+ background: var(--color-bg-surface);
270
+ box-shadow: var(--shadow-lg);
271
+ max-height: 200px;
272
+ overflow-y: auto;
273
+ }
274
+
275
+ .suggestion-item {
276
+ display: flex;
277
+ flex-direction: column;
278
+ align-items: flex-start;
279
+ width: 100%;
280
+ padding: var(--spacing-sm) var(--spacing-md);
281
+ border: none;
282
+ background: transparent;
283
+ text-align: left;
284
+ cursor: pointer;
285
+ transition: background var(--transition-fast);
286
+ }
287
+
288
+ .suggestion-item.has-extra {
289
+ flex-direction: row;
290
+ align-items: center;
291
+ justify-content: space-between;
292
+ gap: var(--spacing-md);
293
+ }
294
+
295
+ .suggestion-item:hover,
296
+ .suggestion-item.highlighted {
297
+ background: var(--color-bg-surface-2);
298
+ }
299
+
300
+ .suggestion-item + .suggestion-item {
301
+ border-top: 1px solid var(--color-border-subtle);
302
+ }
303
+
304
+ .suggestion-content {
305
+ display: flex;
306
+ flex-direction: column;
307
+ align-items: flex-start;
308
+ flex: 1;
309
+ min-width: 0;
310
+ }
311
+
312
+ .suggestion-label {
313
+ font-size: var(--font-size-sm);
314
+ font-weight: var(--font-weight-medium);
315
+ color: var(--color-text);
316
+ }
317
+
318
+ .suggestion-subtitle {
319
+ font-size: var(--font-size-xs);
320
+ color: var(--color-text-muted);
321
+ }
322
+
323
+ .suggestion-extra {
324
+ display: flex;
325
+ align-items: center;
326
+ flex-shrink: 0;
327
+ }
328
+
329
+ .suggestion-footer {
330
+ position: sticky;
331
+ bottom: 0;
332
+ z-index: 1;
333
+ display: flex;
334
+ align-items: center;
335
+ gap: var(--spacing-xs, 0.375rem);
336
+ width: 100%;
337
+ padding: var(--spacing-sm) var(--spacing-md);
338
+ border: none;
339
+ background: var(--color-bg-surface);
340
+ text-align: left;
341
+ cursor: pointer;
342
+ font-size: var(--font-size-sm);
343
+ font-weight: var(--font-weight-medium);
344
+ color: var(--color-primary);
345
+ transition: background var(--transition-fast);
346
+ }
347
+
348
+ .suggestion-item + .suggestion-footer {
349
+ border-top: 1px solid var(--color-border-subtle);
350
+ }
351
+
352
+ .suggestion-footer:hover,
353
+ .suggestion-footer.highlighted {
354
+ background: var(--color-bg-surface-2);
355
+ }
356
+ </style>
@@ -0,0 +1,72 @@
1
+ import type { Snippet } from "svelte";
2
+ export interface AutocompleteSuggestion<T = unknown> {
3
+ /** Display label for the suggestion */
4
+ label: string;
5
+ /** Optional secondary text */
6
+ subtitle?: string;
7
+ /** The original data item */
8
+ data: T;
9
+ }
10
+ export interface AutocompleteInputProps<T = unknown> {
11
+ /** Current input value (bindable) */
12
+ value: string;
13
+ /** Input ID */
14
+ id?: string;
15
+ /** Label text */
16
+ label?: string;
17
+ /** Placeholder text */
18
+ placeholder?: string;
19
+ /** Disabled state */
20
+ disabled?: boolean;
21
+ /** Input type */
22
+ type?: 'text' | 'tel' | 'email' | 'search';
23
+ /** Max length */
24
+ maxlength?: number;
25
+ /** Required field */
26
+ required?: boolean;
27
+ /** Minimum characters before searching */
28
+ minChars?: number;
29
+ /** Debounce delay in ms */
30
+ debounceMs?: number;
31
+ /** Icon to show on the left side of the input */
32
+ icon?: Snippet;
33
+ /** Extra content to render on the right side of each suggestion (receives suggestion data) */
34
+ suggestionExtra?: Snippet<[AutocompleteSuggestion<T>]>;
35
+ /** Function to fetch suggestions */
36
+ fetchSuggestions: (query: string) => Promise<AutocompleteSuggestion<T>[]>;
37
+ /** Called when user selects a suggestion */
38
+ onSelect?: (suggestion: AutocompleteSuggestion<T>) => void;
39
+ /** Called when input value changes */
40
+ oninput?: (value: string) => void;
41
+ /** Optional sticky footer action shown at the bottom of the dropdown.
42
+ * Useful for "Create new" affordances. Does NOT trigger onSelect. */
43
+ footerAction?: {
44
+ label: string;
45
+ icon?: string;
46
+ onClick: () => void;
47
+ };
48
+ }
49
+ declare function $$render<T>(): {
50
+ props: AutocompleteInputProps<T>;
51
+ exports: {};
52
+ bindings: "value";
53
+ slots: {};
54
+ events: {};
55
+ };
56
+ declare class __sveltets_Render<T> {
57
+ props(): ReturnType<typeof $$render<T>>['props'];
58
+ events(): ReturnType<typeof $$render<T>>['events'];
59
+ slots(): ReturnType<typeof $$render<T>>['slots'];
60
+ bindings(): "value";
61
+ exports(): {};
62
+ }
63
+ interface $$IsomorphicComponent {
64
+ new <T>(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']>> & {
65
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
66
+ } & ReturnType<__sveltets_Render<T>['exports']>;
67
+ <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
68
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
69
+ }
70
+ declare const AutocompleteInput: $$IsomorphicComponent;
71
+ type AutocompleteInput<T> = InstanceType<typeof AutocompleteInput<T>>;
72
+ export default AutocompleteInput;
@@ -0,0 +1,185 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+
4
+ interface BadgeProps {
5
+ /** Variante de cor do badge */
6
+ variant?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'light' | 'dark' | 'gradient';
7
+ /** Tamanho do badge */
8
+ size?: 'sm' | 'md' | 'lg';
9
+ /** Estilo sólido (fundo colorido, texto branco) */
10
+ solid?: boolean;
11
+ /** @deprecated Badges are now pill-shaped by default. This prop is kept for backwards compatibility. */
12
+ pill?: boolean;
13
+ /** Conteúdo do badge */
14
+ children?: Snippet;
15
+ /** Ícone à esquerda */
16
+ icon?: Snippet;
17
+ /** Classes CSS adicionais */
18
+ class?: string;
19
+ }
20
+
21
+ let {
22
+ variant = 'primary',
23
+ size = 'md',
24
+ solid = false,
25
+ pill = true, // Kept for backwards compatibility - badges are pill by default now
26
+ children,
27
+ icon,
28
+ class: additionalClasses = ''
29
+ }: BadgeProps = $props();
30
+
31
+ const badgeClass = $derived([
32
+ 'ap-badge',
33
+ `ap-badge-${variant}`,
34
+ size !== 'md' ? `ap-badge-${size}` : '',
35
+ solid ? 'ap-badge-solid' : '',
36
+ additionalClasses
37
+ ].filter(Boolean).join(' '));
38
+ </script>
39
+
40
+ <span class={badgeClass}>
41
+ {#if icon}
42
+ <span class="ap-badge-icon">
43
+ {@render icon()}
44
+ </span>
45
+ {/if}
46
+ {@render children?.()}
47
+ </span>
48
+
49
+ <style>
50
+ /* ============================================
51
+ BADGE - AgendaPet Design System
52
+ ============================================ */
53
+ .ap-badge {
54
+ display: inline-flex;
55
+ align-items: center;
56
+ justify-content: center;
57
+ gap: 0.375rem;
58
+ padding: 0.375rem 0.75rem;
59
+ font-family: var(--font-family-base);
60
+ font-size: var(--font-size-xs);
61
+ font-weight: var(--font-weight-medium);
62
+ line-height: 1;
63
+ border-radius: var(--radius-full);
64
+ white-space: nowrap;
65
+ vertical-align: baseline;
66
+ transition: all var(--transition-fast);
67
+ }
68
+
69
+ /* ===== SIZES ===== */
70
+ .ap-badge-sm {
71
+ font-size: 0.65rem;
72
+ padding: 0.25rem 0.5rem;
73
+ gap: 0.25rem;
74
+ }
75
+
76
+ .ap-badge-lg {
77
+ font-size: var(--font-size-sm);
78
+ padding: 0.5rem 1rem;
79
+ gap: 0.5rem;
80
+ }
81
+
82
+ /* ===== DEFAULT VARIANTS (Soft/Light) ===== */
83
+ .ap-badge-primary {
84
+ background-color: rgba(123, 63, 242, 0.1);
85
+ color: var(--color-primary);
86
+ }
87
+
88
+ .ap-badge-secondary {
89
+ background-color: rgba(91, 95, 115, 0.1);
90
+ color: var(--color-secondary);
91
+ }
92
+
93
+ .ap-badge-success {
94
+ background-color: var(--color-success-bg);
95
+ color: var(--color-success-text);
96
+ }
97
+
98
+ .ap-badge-danger {
99
+ background-color: var(--color-danger-bg);
100
+ color: var(--color-danger-text);
101
+ }
102
+
103
+ .ap-badge-warning {
104
+ background-color: var(--color-warning-bg);
105
+ color: var(--color-warning-text);
106
+ }
107
+
108
+ .ap-badge-info {
109
+ background-color: var(--color-info-bg);
110
+ color: var(--color-info-text);
111
+ }
112
+
113
+ .ap-badge-light {
114
+ background-color: var(--color-bg-surface-2);
115
+ color: var(--color-text-muted);
116
+ border: 1px solid var(--color-border-subtle);
117
+ }
118
+
119
+ .ap-badge-dark {
120
+ background-color: var(--color-gray-800);
121
+ color: white;
122
+ }
123
+
124
+ .ap-badge-gradient {
125
+ background: var(--gradient-brand);
126
+ color: white;
127
+ }
128
+
129
+ /* ===== SOLID VARIANTS ===== */
130
+ .ap-badge-solid.ap-badge-primary {
131
+ background-color: var(--color-primary);
132
+ color: white;
133
+ }
134
+
135
+ .ap-badge-solid.ap-badge-secondary {
136
+ background-color: var(--color-secondary);
137
+ color: white;
138
+ }
139
+
140
+ .ap-badge-solid.ap-badge-success {
141
+ background-color: var(--color-success);
142
+ color: white;
143
+ }
144
+
145
+ .ap-badge-solid.ap-badge-danger {
146
+ background-color: var(--color-danger);
147
+ color: white;
148
+ }
149
+
150
+ .ap-badge-solid.ap-badge-warning {
151
+ background-color: var(--color-warning);
152
+ color: var(--color-warning-text);
153
+ }
154
+
155
+ .ap-badge-solid.ap-badge-info {
156
+ background-color: var(--color-info);
157
+ color: white;
158
+ }
159
+
160
+ .ap-badge-solid.ap-badge-light {
161
+ background-color: var(--color-gray-100);
162
+ color: var(--color-gray-700);
163
+ border: none;
164
+ }
165
+
166
+ .ap-badge-solid.ap-badge-dark {
167
+ background-color: var(--color-gray-900);
168
+ color: white;
169
+ }
170
+
171
+ /* ===== ICON ===== */
172
+ .ap-badge-icon {
173
+ display: inline-flex;
174
+ align-items: center;
175
+ justify-content: center;
176
+ flex-shrink: 0;
177
+ }
178
+
179
+ .ap-badge-icon :global(i),
180
+ .ap-badge-icon :global(svg) {
181
+ font-size: 0.875em;
182
+ width: 1em;
183
+ height: 1em;
184
+ }
185
+ </style>
@@ -0,0 +1,20 @@
1
+ import type { Snippet } from "svelte";
2
+ interface BadgeProps {
3
+ /** Variante de cor do badge */
4
+ variant?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'light' | 'dark' | 'gradient';
5
+ /** Tamanho do badge */
6
+ size?: 'sm' | 'md' | 'lg';
7
+ /** Estilo sólido (fundo colorido, texto branco) */
8
+ solid?: boolean;
9
+ /** @deprecated Badges are now pill-shaped by default. This prop is kept for backwards compatibility. */
10
+ pill?: boolean;
11
+ /** Conteúdo do badge */
12
+ children?: Snippet;
13
+ /** Ícone à esquerda */
14
+ icon?: Snippet;
15
+ /** Classes CSS adicionais */
16
+ class?: string;
17
+ }
18
+ declare const Badge: import("svelte").Component<BadgeProps, {}, "">;
19
+ type Badge = ReturnType<typeof Badge>;
20
+ export default Badge;