@fastwork/xosmoz-svelte 0.0.31 → 0.0.32

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.
@@ -0,0 +1,183 @@
1
+ <script lang="ts" module>
2
+ export type BadgeVariant =
3
+ | 'primary'
4
+ | 'primary-solid'
5
+ | 'success'
6
+ | 'success-solid'
7
+ | 'danger'
8
+ | 'danger-solid'
9
+ | 'warning'
10
+ | 'warning-solid'
11
+ | 'info'
12
+ | 'info-solid'
13
+ | 'neutral'
14
+ | 'neutral-solid'
15
+
16
+ export type BadgeSize = 'small' | 'medium' | 'large'
17
+
18
+ export interface BadgeProps {
19
+ /** Badge variant style */
20
+ variant?: BadgeVariant
21
+ /** Badge size */
22
+ size?: BadgeSize
23
+ /** Whether the badge has pill-shaped border radius */
24
+ isPill?: boolean
25
+ /** Whether the badge should take full width */
26
+ isFluid?: boolean
27
+ /** Icon class name (e.g. for icon fonts) */
28
+ iconClass?: string
29
+ /** Additional CSS classes */
30
+ class?: string
31
+ }
32
+ </script>
33
+
34
+ <script lang="ts">
35
+ import type { Snippet } from 'svelte'
36
+
37
+ interface Props extends BadgeProps {
38
+ /** Main badge content */
39
+ children: Snippet
40
+ /** Icon snippet */
41
+ icon?: Snippet
42
+ }
43
+
44
+ let {
45
+ children,
46
+ variant = 'neutral',
47
+ size = 'medium',
48
+ isPill = false,
49
+ isFluid = false,
50
+ icon,
51
+ iconClass,
52
+ class: className = '',
53
+ }: Props = $props()
54
+
55
+ const badgeClasses = $derived.by(() => {
56
+ const classes = ['xz-badge']
57
+
58
+ // Variant (only add class if not neutral, which is the default)
59
+ if (variant !== 'neutral') {
60
+ classes.push(`is-variant-${variant}`)
61
+ }
62
+
63
+ // Size (only add class if not medium, which is the default)
64
+ if (size !== 'medium') {
65
+ classes.push(`is-size-${size}`)
66
+ }
67
+
68
+ // Modifiers
69
+ if (isPill) classes.push('is-pill')
70
+ if (isFluid) classes.push('is-fluid')
71
+
72
+ // Custom classes
73
+ if (className) classes.push(className)
74
+
75
+ return classes.join(' ')
76
+ })
77
+ </script>
78
+
79
+ <div class={badgeClasses}>
80
+ {#if iconClass}
81
+ <span class="icon">
82
+ <i class={iconClass}></i>
83
+ </span>
84
+ {/if}
85
+
86
+ {#if icon}
87
+ <span class="icon">
88
+ {@render icon()}
89
+ </span>
90
+ {/if}
91
+
92
+ {@render children()}
93
+ </div>
94
+
95
+ <style>.xz-badge {
96
+ display: inline-flex;
97
+ gap: 0.25rem;
98
+ justify-content: center;
99
+ align-items: center;
100
+ padding: 0.25rem 0.625rem;
101
+ border-radius: 0.375rem;
102
+ background: var(--xz-color-neutral-soft-100);
103
+ color: var(--xz-color-neutral-fg-100);
104
+ font-weight: 500;
105
+ font-size: var(--xz-font-size-300, 0.75rem);
106
+ font-family: var(--xz-font-family-primary, system-ui, sans-serif);
107
+ line-height: 1.4;
108
+ }
109
+ .xz-badge .icon {
110
+ display: flex;
111
+ justify-content: flex-start;
112
+ align-items: center;
113
+ width: 1rem;
114
+ height: 1rem;
115
+ }
116
+ .xz-badge.is-size-small {
117
+ padding: 0.1875rem 0.5rem;
118
+ border-radius: 0.25rem;
119
+ font-size: 0.75rem;
120
+ }
121
+ .xz-badge.is-size-large {
122
+ padding: 0.5rem 1rem;
123
+ font-size: 0.875rem;
124
+ }
125
+ .xz-badge.is-variant-primary {
126
+ background: var(--xz-color-primary-soft-100);
127
+ color: var(--xz-color-primary-fg-100);
128
+ }
129
+ .xz-badge.is-variant-success {
130
+ background: var(--xz-color-success-soft-100);
131
+ color: var(--xz-color-success-fg-100);
132
+ }
133
+ .xz-badge.is-variant-danger {
134
+ background: var(--xz-color-danger-soft-100);
135
+ color: var(--xz-color-danger-fg-100);
136
+ }
137
+ .xz-badge.is-variant-warning {
138
+ background: var(--xz-color-warning-soft-100);
139
+ color: var(--xz-color-warning-fg-100);
140
+ }
141
+ .xz-badge.is-variant-info {
142
+ background: var(--xz-color-info-soft-100);
143
+ color: var(--xz-color-info-fg-100);
144
+ }
145
+ .xz-badge.is-variant-primary-solid {
146
+ background: var(--xz-color-primary-bg-100);
147
+ color: var(--xz-color-primary-fg-50);
148
+ }
149
+ .xz-badge.is-variant-success-solid {
150
+ background: var(--xz-color-success-bg-100);
151
+ color: var(--xz-color-success-fg-50, #fff);
152
+ }
153
+ .xz-badge.is-variant-danger-solid {
154
+ background: var(--xz-color-danger-bg-100);
155
+ color: var(--xz-color-danger-fg-50, #fff);
156
+ }
157
+ .xz-badge.is-variant-warning-solid {
158
+ background: var(--xz-color-warning-bg-100);
159
+ color: var(--xz-color-warning-fg-50, #fff);
160
+ }
161
+ .xz-badge.is-variant-info-solid {
162
+ background: var(--xz-color-info-bg-100);
163
+ color: var(--xz-color-info-fg-50, #fff);
164
+ }
165
+ .xz-badge.is-variant-neutral-solid {
166
+ background: var(--xz-color-neutral-bg-100);
167
+ color: var(--xz-color-neutral-fg-50, #fff);
168
+ }
169
+ .xz-badge.is-fluid {
170
+ width: 100%;
171
+ }
172
+ .xz-badge.is-pill {
173
+ border-radius: 999px;
174
+ }
175
+ .xz-badge.is-pill.is-size-small {
176
+ padding: 0.1875rem 0.5625rem;
177
+ }
178
+ .xz-badge.is-pill.is-size-medium {
179
+ padding: 0.375rem 0.875rem;
180
+ }
181
+ .xz-badge.is-pill.is-size-large {
182
+ padding: 0.5rem 1rem;
183
+ }</style>
@@ -0,0 +1,26 @@
1
+ export type BadgeVariant = 'primary' | 'primary-solid' | 'success' | 'success-solid' | 'danger' | 'danger-solid' | 'warning' | 'warning-solid' | 'info' | 'info-solid' | 'neutral' | 'neutral-solid';
2
+ export type BadgeSize = 'small' | 'medium' | 'large';
3
+ export interface BadgeProps {
4
+ /** Badge variant style */
5
+ variant?: BadgeVariant;
6
+ /** Badge size */
7
+ size?: BadgeSize;
8
+ /** Whether the badge has pill-shaped border radius */
9
+ isPill?: boolean;
10
+ /** Whether the badge should take full width */
11
+ isFluid?: boolean;
12
+ /** Icon class name (e.g. for icon fonts) */
13
+ iconClass?: string;
14
+ /** Additional CSS classes */
15
+ class?: string;
16
+ }
17
+ import type { Snippet } from 'svelte';
18
+ interface Props extends BadgeProps {
19
+ /** Main badge content */
20
+ children: Snippet;
21
+ /** Icon snippet */
22
+ icon?: Snippet;
23
+ }
24
+ declare const Badge: import("svelte").Component<Props, {}, "">;
25
+ type Badge = ReturnType<typeof Badge>;
26
+ export default Badge;
@@ -0,0 +1,94 @@
1
+ <script lang="ts">
2
+ import Badge from './Badge.svelte'
3
+ </script>
4
+
5
+ <div class="badge-showcase">
6
+ <section>
7
+ <h3>Soft Variants</h3>
8
+ <div class="badge-row">
9
+ <Badge variant="primary">Primary</Badge>
10
+ <Badge variant="success">Success</Badge>
11
+ <Badge variant="danger">Danger</Badge>
12
+ <Badge variant="warning">Warning</Badge>
13
+ <Badge variant="info">Info</Badge>
14
+ <Badge variant="neutral">Neutral</Badge>
15
+ </div>
16
+ </section>
17
+
18
+ <section>
19
+ <h3>Solid Variants</h3>
20
+ <div class="badge-row">
21
+ <Badge variant="primary-solid">Primary Solid</Badge>
22
+ <Badge variant="success-solid">Success Solid</Badge>
23
+ <Badge variant="danger-solid">Danger Solid</Badge>
24
+ <Badge variant="warning-solid">Warning Solid</Badge>
25
+ <Badge variant="info-solid">Info Solid</Badge>
26
+ <Badge variant="neutral-solid">Neutral Solid</Badge>
27
+ </div>
28
+ </section>
29
+
30
+ <section>
31
+ <h3>Sizes</h3>
32
+ <div class="badge-row">
33
+ <Badge size="small">Small</Badge>
34
+ <Badge size="medium">Medium</Badge>
35
+ <Badge size="large">Large</Badge>
36
+ </div>
37
+ </section>
38
+
39
+ <section>
40
+ <h3>Modifiers</h3>
41
+ <div class="badge-row">
42
+ <Badge isPill>Pill</Badge>
43
+ <Badge variant="primary" isPill>Primary Pill</Badge>
44
+ <Badge variant="success" isPill>Success Pill</Badge>
45
+ </div>
46
+ <div class="badge-row" style="width: 100%; max-width: 400px;">
47
+ <Badge isFluid>Fluid</Badge>
48
+ </div>
49
+ </section>
50
+
51
+ <section>
52
+ <h3>Variant + Sizes</h3>
53
+ <div class="badge-row">
54
+ <Badge variant="primary" size="small">Primary Small</Badge>
55
+ <Badge variant="primary" size="medium">Primary Medium</Badge>
56
+ <Badge variant="primary" size="large">Primary Large</Badge>
57
+ </div>
58
+ <div class="badge-row">
59
+ <Badge variant="danger" size="small">Danger Small</Badge>
60
+ <Badge variant="danger" size="medium">Danger Medium</Badge>
61
+ <Badge variant="danger" size="large">Danger Large</Badge>
62
+ </div>
63
+ </section>
64
+ </div>
65
+
66
+ <style>
67
+ .badge-showcase {
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: 2rem;
71
+ padding: 2rem;
72
+ font-family: var(--xz-font-family-primary, system-ui);
73
+ }
74
+
75
+ section {
76
+ display: flex;
77
+ flex-direction: column;
78
+ gap: 1rem;
79
+ }
80
+
81
+ h3 {
82
+ margin: 0;
83
+ color: var(--xz-color-fg-100);
84
+ font-weight: 600;
85
+ font-size: 1rem;
86
+ }
87
+
88
+ .badge-row {
89
+ display: flex;
90
+ flex-wrap: wrap;
91
+ gap: 0.75rem;
92
+ align-items: center;
93
+ }
94
+ </style>
@@ -0,0 +1,18 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const BadgeAllVariants: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type BadgeAllVariants = InstanceType<typeof BadgeAllVariants>;
18
+ export default BadgeAllVariants;
@@ -0,0 +1,24 @@
1
+ <script lang="ts">
2
+ import Badge from './Badge.svelte'
3
+ import type { BadgeVariant, BadgeSize } from './Badge.svelte'
4
+
5
+ interface Props {
6
+ variant?: BadgeVariant
7
+ size?: BadgeSize
8
+ isPill?: boolean
9
+ isFluid?: boolean
10
+ label?: string
11
+ }
12
+
13
+ let {
14
+ variant = 'neutral',
15
+ size = 'medium',
16
+ isPill = false,
17
+ isFluid = false,
18
+ label = 'Badge',
19
+ }: Props = $props()
20
+ </script>
21
+
22
+ <Badge {variant} {size} {isPill} {isFluid}>
23
+ {label}
24
+ </Badge>
@@ -0,0 +1,11 @@
1
+ import type { BadgeVariant, BadgeSize } from './Badge.svelte';
2
+ interface Props {
3
+ variant?: BadgeVariant;
4
+ size?: BadgeSize;
5
+ isPill?: boolean;
6
+ isFluid?: boolean;
7
+ label?: string;
8
+ }
9
+ declare const BadgeShowcase: import("svelte").Component<Props, {}, "">;
10
+ type BadgeShowcase = ReturnType<typeof BadgeShowcase>;
11
+ export default BadgeShowcase;
@@ -0,0 +1,2 @@
1
+ export { default as Badge } from './Badge.svelte';
2
+ export type { BadgeProps, BadgeVariant, BadgeSize } from './Badge.svelte';
@@ -0,0 +1 @@
1
+ export { default as Badge } from './Badge.svelte';
@@ -0,0 +1,376 @@
1
+ <script lang="ts" module>
2
+ export type ButtonVariant =
3
+ | 'primary'
4
+ | 'secondary'
5
+ | 'outline'
6
+ | 'tertiary'
7
+ | 'ghost'
8
+ | 'danger'
9
+ | 'success'
10
+ | 'white'
11
+ | 'white-secondary'
12
+
13
+ export type ButtonSize = 'small' | 'medium' | 'large'
14
+
15
+ export interface ButtonProps {
16
+ /** Button variant style */
17
+ variant?: ButtonVariant
18
+ /** Button size */
19
+ size?: ButtonSize
20
+ /** Whether the button is disabled */
21
+ disabled?: boolean
22
+ /** Whether the button is in loading state */
23
+ loading?: boolean
24
+ /** Whether the button should take full width */
25
+ fluid?: boolean
26
+ /** Whether the button has pill-shaped border radius */
27
+ pill?: boolean
28
+ /** Whether the button should be square (1:1 aspect ratio) */
29
+ square?: boolean
30
+ /** Button type attribute */
31
+ type?: 'button' | 'submit' | 'reset'
32
+ /** Additional CSS classes */
33
+ class?: string
34
+ /** Click handler */
35
+ onclick?: (event: MouseEvent) => void
36
+ }
37
+ </script>
38
+
39
+ <script lang="ts">
40
+ import type { Snippet } from 'svelte'
41
+
42
+ interface Props extends ButtonProps {
43
+ /** Content before the main text */
44
+ startIcon?: Snippet
45
+ /** Main button content */
46
+ children: Snippet
47
+ /** Content after the main text */
48
+ endIcon?: Snippet
49
+ }
50
+
51
+ let {
52
+ variant = 'primary',
53
+ size = 'medium',
54
+ disabled = false,
55
+ loading = false,
56
+ fluid = false,
57
+ pill = false,
58
+ square = false,
59
+ type = 'button',
60
+ class: className = '',
61
+ onclick,
62
+ startIcon,
63
+ children,
64
+ endIcon,
65
+ }: Props = $props()
66
+
67
+ const buttonClasses = $derived.by(() => {
68
+ const classes = ['xz-button']
69
+
70
+ // Variant (only add class if not primary, which is the default)
71
+ if (variant !== 'primary') {
72
+ classes.push(`is-variant-${variant}`)
73
+ }
74
+
75
+ // Size (only add class if not medium, which is the default)
76
+ if (size !== 'medium') {
77
+ classes.push(`is-size-${size}`)
78
+ }
79
+
80
+ // States
81
+ if (loading) classes.push('is-loading')
82
+ if (disabled) classes.push('is-disabled')
83
+
84
+ // Modifiers
85
+ if (fluid) classes.push('is-fluid')
86
+ if (pill) classes.push('is-pill')
87
+ if (square) classes.push('is-square')
88
+
89
+ // Custom classes
90
+ if (className) classes.push(className)
91
+
92
+ return classes.join(' ')
93
+ })
94
+ </script>
95
+
96
+ <button
97
+ class={buttonClasses}
98
+ {type}
99
+ disabled={disabled || loading}
100
+ aria-disabled={disabled || loading}
101
+ aria-busy={loading}
102
+ {onclick}
103
+ >
104
+ {#if startIcon}
105
+ <span class="start-icon">
106
+ {@render startIcon()}
107
+ </span>
108
+ {/if}
109
+ <span>
110
+ {@render children()}
111
+ </span>
112
+ {#if endIcon}
113
+ <span class="end-icon">
114
+ {@render endIcon()}
115
+ </span>
116
+ {/if}
117
+ </button>
118
+
119
+ <style>.xz-button {
120
+ --button-font-family: var(
121
+ --xz-font-family-primary,
122
+ system-ui,
123
+ sans-serif
124
+ );
125
+ --button-font-weight: 600;
126
+ --button-border-radius: 0.5rem;
127
+ --button-small-height: 2rem;
128
+ --button-small-font-size: 0.8125rem;
129
+ --button-medium-height: 2.5rem;
130
+ --button-medium-font-size: 0.875rem;
131
+ --button-large-height: 3rem;
132
+ --button-large-font-size: 1rem;
133
+ position: relative;
134
+ display: inline-flex;
135
+ justify-content: center;
136
+ align-items: center;
137
+ overflow: hidden;
138
+ min-height: var(--button-medium-height);
139
+ padding: 0 1.125rem;
140
+ border: none;
141
+ border-radius: var(--button-border-radius);
142
+ background: var(--xz-color-primary-bg-100);
143
+ color: var(--xz-color-primary-fg-50);
144
+ outline: none;
145
+ font-weight: var(--button-font-weight);
146
+ font-size: var(--button-medium-font-size);
147
+ font-family: var(--button-font-family);
148
+ line-height: 100%;
149
+ cursor: pointer;
150
+ user-select: none;
151
+ transition: all 0.16s ease-in-out;
152
+ }
153
+ @media (hover: hover) {
154
+ .xz-button:hover::before {
155
+ background: var(--xz-color-black-alpha-100);
156
+ }
157
+ .xz-button:focus {
158
+ box-shadow: 0 0 0 0.175rem var(--xz-color-primary-line-200);
159
+ }
160
+ }
161
+ .xz-button > span {
162
+ z-index: 1;
163
+ }
164
+ .xz-button .start-icon,
165
+ .xz-button .end-icon {
166
+ display: flex;
167
+ align-items: center;
168
+ min-width: 1.375rem;
169
+ }
170
+ .xz-button .end-icon {
171
+ justify-content: flex-end;
172
+ }
173
+ .xz-button::before {
174
+ content: "";
175
+ position: absolute;
176
+ inset: 0;
177
+ z-index: 0;
178
+ pointer-events: none;
179
+ transition: all 0.16s ease-in-out;
180
+ }
181
+ .xz-button.is-size-small {
182
+ min-height: var(--button-small-height);
183
+ padding: 0 1rem;
184
+ font-size: var(--button-small-font-size);
185
+ }
186
+ .xz-button.is-size-small .start-icon,
187
+ .xz-button.is-size-small .end-icon {
188
+ min-width: 1.125rem;
189
+ }
190
+ .xz-button.is-size-medium {
191
+ min-height: var(--button-medium-height);
192
+ padding: 0 1.125rem;
193
+ font-size: var(--button-medium-font-size);
194
+ }
195
+ .xz-button.is-size-medium .start-icon,
196
+ .xz-button.is-size-medium .end-icon {
197
+ min-width: 1.375rem;
198
+ }
199
+ .xz-button.is-size-large {
200
+ min-height: var(--button-large-height);
201
+ padding: 0 1.25rem;
202
+ font-size: var(--button-large-font-size);
203
+ }
204
+ .xz-button.is-size-large .start-icon,
205
+ .xz-button.is-size-large .end-icon {
206
+ min-width: 1.625rem;
207
+ }
208
+ .xz-button.is-variant-danger {
209
+ background: var(--xz-color-danger-bg-100);
210
+ }
211
+ @media (hover: hover) {
212
+ .xz-button.is-variant-danger:focus {
213
+ box-shadow: 0 0 0 0.175rem var(--xz-color-danger-line-200);
214
+ }
215
+ }
216
+ .xz-button.is-variant-danger.is-loading::after {
217
+ border-top-color: var(--xz-color-danger-fg-50);
218
+ border-right-color: var(--xz-color-danger-fg-50);
219
+ }
220
+ .xz-button.is-variant-success {
221
+ background: var(--xz-color-success-bg-100);
222
+ }
223
+ @media (hover: hover) {
224
+ .xz-button.is-variant-success:focus {
225
+ box-shadow: 0 0 0 0.175rem var(--xz-color-success-line-200);
226
+ }
227
+ }
228
+ .xz-button.is-variant-success.is-loading::after {
229
+ border-top-color: var(--xz-color-success-fg-50);
230
+ border-right-color: var(--xz-color-success-fg-50);
231
+ }
232
+ .xz-button.is-variant-secondary {
233
+ border: 1px solid var(--xz-color-line-100);
234
+ background: transparent;
235
+ color: var(--xz-color-primary-fg-100);
236
+ }
237
+ @media (hover: hover) {
238
+ .xz-button.is-variant-secondary:focus {
239
+ box-shadow: 0 0 0 0.175rem var(--xz-color-primary-line-200);
240
+ }
241
+ .xz-button.is-variant-secondary:hover {
242
+ border: 1px solid var(--xz-color-line-200);
243
+ color: var(--xz-color-primary-fg-100);
244
+ }
245
+ .xz-button.is-variant-secondary:hover::before {
246
+ background: var(--xz-color-black-alpha-100);
247
+ }
248
+ }
249
+ .xz-button.is-variant-secondary.is-loading::after {
250
+ border-top-color: var(--xz-color-primary-fg-100);
251
+ border-right-color: var(--xz-color-primary-fg-100);
252
+ }
253
+ .xz-button.is-variant-outline {
254
+ border: 1px solid var(--xz-color-line-100);
255
+ background: transparent;
256
+ color: var(--xz-color-fg-200);
257
+ }
258
+ @media (hover: hover) {
259
+ .xz-button.is-variant-outline:focus {
260
+ box-shadow: 0 0 0 0.175rem var(--xz-color-primary-line-200);
261
+ }
262
+ .xz-button.is-variant-outline:hover {
263
+ border: 1px solid var(--xz-color-line-200);
264
+ color: var(--xz-color-fg-100);
265
+ }
266
+ .xz-button.is-variant-outline:hover::before {
267
+ background: var(--xz-color-black-alpha-100);
268
+ }
269
+ }
270
+ .xz-button.is-variant-outline.is-loading::after {
271
+ border-top-color: var(--xz-color-fg-200);
272
+ border-right-color: var(--xz-color-fg-200);
273
+ }
274
+ .xz-button.is-variant-tertiary {
275
+ border: unset;
276
+ background: var(--xz-color-neutral-soft-100);
277
+ color: var(--xz-color-fg-100);
278
+ }
279
+ @media (hover: hover) {
280
+ .xz-button.is-variant-tertiary:focus {
281
+ box-shadow: 0 0 0 0.175rem var(--xz-color-primary-line-200);
282
+ }
283
+ }
284
+ .xz-button.is-variant-tertiary.is-loading::after {
285
+ border-top-color: var(--xz-color-fg-200);
286
+ border-right-color: var(--xz-color-fg-200);
287
+ }
288
+ .xz-button.is-variant-ghost {
289
+ border: unset;
290
+ background: transparent;
291
+ color: var(--xz-color-fg-200);
292
+ }
293
+ @media (hover: hover) {
294
+ .xz-button.is-variant-ghost:focus {
295
+ box-shadow: 0 0 0 0.175rem var(--xz-color-primary-line-200);
296
+ }
297
+ }
298
+ .xz-button.is-variant-ghost.is-loading::after {
299
+ border-top-color: var(--xz-color-fg-200);
300
+ border-right-color: var(--xz-color-fg-200);
301
+ }
302
+ .xz-button.is-variant-white {
303
+ border: 1px solid var(--xz-color-line-100);
304
+ background: var(--xz-color-bg-100);
305
+ color: var(--xz-color-primary-fg-100);
306
+ }
307
+ @media (hover: hover) {
308
+ .xz-button.is-variant-white:focus {
309
+ box-shadow: 0 0 0 0.175rem var(--xz-color-primary-line-200);
310
+ }
311
+ }
312
+ .xz-button.is-variant-white.is-loading::after {
313
+ border-top-color: var(--xz-color-primary-fg-100);
314
+ border-right-color: var(--xz-color-primary-fg-100);
315
+ }
316
+ .xz-button.is-variant-white-secondary {
317
+ border: 1px solid var(--xz-color-white-alpha-1000);
318
+ background: transparent;
319
+ color: var(--xz-color-white-alpha-1000);
320
+ }
321
+ @media (hover: hover) {
322
+ .xz-button.is-variant-white-secondary:focus {
323
+ box-shadow: 0 0 0 0.175rem var(--xz-color-primary-line-200);
324
+ }
325
+ .xz-button.is-variant-white-secondary:hover {
326
+ border: 1px solid var(--xz-color-line-200);
327
+ color: var(--xz-color-white-alpha-1000);
328
+ }
329
+ .xz-button.is-variant-white-secondary:hover::before {
330
+ background: var(--xz-color-black-alpha-100);
331
+ }
332
+ }
333
+ .xz-button.is-variant-white-secondary.is-loading::after {
334
+ border-top-color: var(--xz-color-white-alpha-1000);
335
+ border-right-color: var(--xz-color-white-alpha-1000);
336
+ }
337
+ .xz-button.is-loading {
338
+ color: transparent;
339
+ pointer-events: none;
340
+ }
341
+ .xz-button.is-loading::after {
342
+ content: "";
343
+ position: absolute;
344
+ right: 0;
345
+ left: 0;
346
+ width: 1em;
347
+ height: 1em;
348
+ margin: auto;
349
+ border: 2px solid;
350
+ border-top-color: var(--xz-color-primary-fg-50);
351
+ border-right-color: var(--xz-color-primary-fg-50);
352
+ border-radius: 999px;
353
+ animation: button-loading-spin 0.48s infinite linear;
354
+ }
355
+ .xz-button[disabled], .xz-button.is-disabled {
356
+ opacity: 0.6;
357
+ cursor: not-allowed;
358
+ }
359
+ .xz-button.is-fluid {
360
+ width: 100%;
361
+ }
362
+ .xz-button.is-pill {
363
+ border-radius: 999px;
364
+ }
365
+ .xz-button.is-square {
366
+ aspect-ratio: 1/1;
367
+ }
368
+
369
+ @keyframes button-loading-spin {
370
+ from {
371
+ transform: rotate(0deg);
372
+ }
373
+ to {
374
+ transform: rotate(359deg);
375
+ }
376
+ }</style>
@@ -0,0 +1,2 @@
1
+ export { default as Button } from './Button.svelte';
2
+ export type { ButtonProps, ButtonVariant, ButtonSize } from './Button.svelte';
@@ -0,0 +1 @@
1
+ export { default as Button } from './Button.svelte';
package/dist/index.d.ts CHANGED
@@ -17,5 +17,7 @@
17
17
  * import '@fastwork/xosmoz-svelte/styles.css';
18
18
  * ```
19
19
  */
20
- export { default as Button } from './components/Button.svelte';
21
- export type { ButtonProps, ButtonVariant, ButtonSize } from './components/Button.svelte';
20
+ export { default as Button } from './components/button/Button.svelte';
21
+ export { default as Badge } from './components/badge/Badge.svelte';
22
+ export type { ButtonProps, ButtonVariant, ButtonSize } from './components/button/Button.svelte';
23
+ export type { BadgeProps, BadgeVariant, BadgeSize } from './components/badge/Badge.svelte';
package/dist/index.js CHANGED
@@ -18,4 +18,5 @@
18
18
  * ```
19
19
  */
20
20
  // Components
21
- export { default as Button } from './components/Button.svelte';
21
+ export { default as Button } from './components/button/Button.svelte';
22
+ export { default as Badge } from './components/badge/Badge.svelte';
@@ -0,0 +1,9 @@
1
+ @use 'sass:math';
2
+
3
+ @function toRem($px) {
4
+ @return math.div($px, 16) + rem;
5
+ }
6
+
7
+ @function toEm($px) {
8
+ @return math.div($px, 16) + em;
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastwork/xosmoz-svelte",
3
- "version": "0.0.31",
3
+ "version": "0.0.32",
4
4
  "description": "Svelte 5 components for Xosmoz design system",
5
5
  "type": "module",
6
6
  "svelte": "./dist/index.js",
@@ -59,8 +59,15 @@
59
59
  "eslint-config-prettier": "^10.1.8",
60
60
  "eslint-plugin-svelte": "^3.12.4",
61
61
  "globals": "^16.4.0",
62
+ "postcss-html": "^1.8.1",
63
+ "postcss-scss": "^4.0.9",
62
64
  "prettier": "^3.6.2",
63
65
  "prettier-plugin-svelte": "^3.4.0",
66
+ "sass": "^1.97.3",
67
+ "stylelint": "^16.26.1",
68
+ "stylelint-config-standard-scss": "^17.0.0",
69
+ "stylelint-order": "^7.0.1",
70
+ "stylelint-prettier": "^5.0.3",
64
71
  "svelte": "^5.41.0",
65
72
  "svelte-check": "^4.3.3",
66
73
  "typescript": "^5.9.3",
@@ -1,117 +0,0 @@
1
- <script lang="ts" module>
2
- export type ButtonVariant =
3
- | 'primary'
4
- | 'secondary'
5
- | 'outline'
6
- | 'tertiary'
7
- | 'ghost'
8
- | 'danger'
9
- | 'success'
10
- | 'white'
11
- | 'white-secondary'
12
-
13
- export type ButtonSize = 'small' | 'medium' | 'large'
14
-
15
- export interface ButtonProps {
16
- /** Button variant style */
17
- variant?: ButtonVariant
18
- /** Button size */
19
- size?: ButtonSize
20
- /** Whether the button is disabled */
21
- disabled?: boolean
22
- /** Whether the button is in loading state */
23
- loading?: boolean
24
- /** Whether the button should take full width */
25
- fluid?: boolean
26
- /** Whether the button has pill-shaped border radius */
27
- pill?: boolean
28
- /** Whether the button should be square (1:1 aspect ratio) */
29
- square?: boolean
30
- /** Button type attribute */
31
- type?: 'button' | 'submit' | 'reset'
32
- /** Additional CSS classes */
33
- class?: string
34
- /** Click handler */
35
- onclick?: (event: MouseEvent) => void
36
- }
37
- </script>
38
-
39
- <script lang="ts">
40
- import type { Snippet } from 'svelte'
41
-
42
- interface Props extends ButtonProps {
43
- /** Content before the main text */
44
- startIcon?: Snippet
45
- /** Main button content */
46
- children: Snippet
47
- /** Content after the main text */
48
- endIcon?: Snippet
49
- }
50
-
51
- let {
52
- variant = 'primary',
53
- size = 'medium',
54
- disabled = false,
55
- loading = false,
56
- fluid = false,
57
- pill = false,
58
- square = false,
59
- type = 'button',
60
- class: className = '',
61
- onclick,
62
- startIcon,
63
- children,
64
- endIcon,
65
- }: Props = $props()
66
-
67
- const buttonClasses = $derived.by(() => {
68
- const classes = ['xz-button']
69
-
70
- // Variant (only add class if not primary, which is the default)
71
- if (variant !== 'primary') {
72
- classes.push(`is-variant-${variant}`)
73
- }
74
-
75
- // Size (only add class if not medium, which is the default)
76
- if (size !== 'medium') {
77
- classes.push(`is-size-${size}`)
78
- }
79
-
80
- // States
81
- if (loading) classes.push('is-loading')
82
- if (disabled) classes.push('is-disabled')
83
-
84
- // Modifiers
85
- if (fluid) classes.push('is-fluid')
86
- if (pill) classes.push('is-pill')
87
- if (square) classes.push('is-square')
88
-
89
- // Custom classes
90
- if (className) classes.push(className)
91
-
92
- return classes.join(' ')
93
- })
94
- </script>
95
-
96
- <button
97
- class={buttonClasses}
98
- {type}
99
- disabled={disabled || loading}
100
- aria-disabled={disabled || loading}
101
- aria-busy={loading}
102
- {onclick}
103
- >
104
- {#if startIcon}
105
- <span class="start-icon">
106
- {@render startIcon()}
107
- </span>
108
- {/if}
109
- <span>
110
- {@render children()}
111
- </span>
112
- {#if endIcon}
113
- <span class="end-icon">
114
- {@render endIcon()}
115
- </span>
116
- {/if}
117
- </button>