@sabrenski/spire-ui 0.0.5 → 0.0.7
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/index.d.ts +170 -4
- package/dist/spire-ui.css +1 -1
- package/dist/spire-ui.es.js +7040 -6773
- package/dist/spire-ui.umd.js +10 -10
- package/package.json +83 -70
- package/src/components/Accordion/AccordionContent.vue +5 -2
- package/src/components/Accordion/AccordionItem.vue +4 -0
- package/src/components/Accordion/AccordionRoot.vue +4 -2
- package/src/components/Accordion/AccordionTrigger.vue +4 -1
- package/src/components/Avatar/Avatar.vue +4 -0
- package/src/components/Badge/Badge.vue +4 -0
- package/src/components/BadgeContainer/BadgeContainer.vue +4 -1
- package/src/components/Breadcrumb/BreadcrumbLink.vue +4 -1
- package/src/components/Breadcrumb/BreadcrumbRoot.vue +4 -1
- package/src/components/Button/Button.vue +5 -1
- package/src/components/Callout/Callout.vue +4 -0
- package/src/components/Card/Card.vue +5 -1
- package/src/components/Card/CardContent.vue +5 -1
- package/src/components/Card/CardFooter.vue +5 -1
- package/src/components/Card/CardHeader.vue +5 -1
- package/src/components/Card/CardImage.vue +4 -2
- package/src/components/Chart/BarChart.vue +4 -0
- package/src/components/Chart/BaseChart.vue +52 -47
- package/src/components/Chart/DonutChart.vue +4 -2
- package/src/components/Chart/LineChart.vue +4 -0
- package/src/components/Checkbox/Checkbox.test.ts +94 -0
- package/src/components/Checkbox/Checkbox.vue +170 -1
- package/src/components/ChoiceChip/ChoiceChip.vue +11 -5
- package/src/components/ChoiceChipGroup/ChoiceChipGroup.vue +4 -2
- package/src/components/ColorPicker/ColorArea.vue +4 -2
- package/src/components/ColorPicker/ColorPicker.vue +4 -2
- package/src/components/ColorPicker/ColorSlider.vue +5 -1
- package/src/components/Combobox/Combobox.vue +97 -91
- package/src/components/DataTable/DataTable.vue +5 -1
- package/src/components/DatePicker/DatePicker.vue +5 -1
- package/src/components/Drawer/Drawer.vue +13 -3
- package/src/components/Dropdown/Dropdown.vue +4 -2
- package/src/components/Dropdown/DropdownItem.vue +4 -0
- package/src/components/Dropdown/DropdownSubTrigger.vue +4 -2
- package/src/components/EmptyState/EmptyState.vue +5 -1
- package/src/components/FileUpload/FileUpload.vue +12 -6
- package/src/components/Heading/Heading.vue +4 -0
- package/src/components/Icon/Icon.vue +5 -2
- package/src/components/Input/Input.vue +5 -1
- package/src/components/Layout/Container.vue +4 -0
- package/src/components/Layout/Grid.vue +4 -1
- package/src/components/Layout/GridItem.vue +4 -1
- package/src/components/Layout/Stack.vue +4 -0
- package/src/components/Modal/Modal.test.ts +68 -13
- package/src/components/Modal/Modal.vue +94 -91
- package/src/components/Pagination/Pagination.vue +5 -1
- package/src/components/Popover/Popover.vue +4 -1
- package/src/components/Progress/Progress.vue +5 -0
- package/src/components/Radio/Radio.test.ts +88 -0
- package/src/components/Radio/Radio.vue +169 -1
- package/src/components/Rating/Rating.vue +5 -1
- package/src/components/SegmentedControl/SegmentedControl.vue +5 -1
- package/src/components/Select/Select.vue +61 -55
- package/src/components/Sidebar/SidebarGroup.vue +4 -0
- package/src/components/Sidebar/SidebarItem.vue +4 -0
- package/src/components/Sidebar/SidebarLayout.vue +5 -2
- package/src/components/Sidebar/SidebarRoot.vue +4 -2
- package/src/components/Skeleton/Skeleton.vue +5 -1
- package/src/components/Slider/Slider.vue +5 -1
- package/src/components/Spinner/Spinner.vue +4 -1
- package/src/components/SpireProvider/SpireProvider.vue +4 -1
- package/src/components/Stepper/StepperItem.vue +4 -0
- package/src/components/Stepper/StepperRoot.vue +4 -2
- package/src/components/Stepper/StepperTrigger.vue +6 -2
- package/src/components/Switch/Switch.vue +5 -1
- package/src/components/Tabs/Tabs.vue +4 -1
- package/src/components/Text/Text.vue +4 -0
- package/src/components/Textarea/Textarea.vue +13 -7
- package/src/components/TimePicker/TimePicker.vue +5 -1
- package/src/components/Timeline/Timeline.vue +4 -0
- package/src/components/Timeline/TimelineItem.vue +4 -0
- package/src/components/Toast/ToastItem.vue +5 -1
- package/src/components/Toast/ToastProvider.vue +5 -3
- package/src/components/ToggleButton/ToggleButton.vue +5 -1
- package/src/components/ToggleGroup/ToggleGroup.vue +5 -1
- package/src/components/Tooltip/Tooltip.vue +9 -1
- package/src/components/TreeView/TreeView.vue +4 -1
- package/src/components/TreeView/TreeViewItem.vue +4 -0
- package/src/index.ts +3 -0
- package/src/styles/main.css +21 -21
- package/src/types/common.ts +4 -0
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
3
|
import { useId } from '../../composables'
|
|
4
|
+
import type { ClassValue } from '../../types/common'
|
|
4
5
|
|
|
5
6
|
export interface RadioProps {
|
|
7
|
+
/** Additional CSS classes */
|
|
8
|
+
class?: ClassValue
|
|
6
9
|
/** Selected value (v-model) - shared across radio group */
|
|
7
10
|
modelValue?: string | number | boolean
|
|
8
11
|
/** Value of this radio option */
|
|
9
12
|
value: string | number | boolean
|
|
13
|
+
/** Visual variant */
|
|
14
|
+
variant?: 'default' | 'pill'
|
|
10
15
|
/** Radio size */
|
|
11
16
|
size?: 'sm' | 'md' | 'lg'
|
|
12
17
|
/** Disabled state */
|
|
@@ -22,6 +27,7 @@ export interface RadioProps {
|
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
const props = withDefaults(defineProps<RadioProps>(), {
|
|
30
|
+
variant: 'default',
|
|
25
31
|
size: 'md',
|
|
26
32
|
disabled: false
|
|
27
33
|
})
|
|
@@ -44,9 +50,53 @@ function handleChange() {
|
|
|
44
50
|
</script>
|
|
45
51
|
|
|
46
52
|
<template>
|
|
53
|
+
<!-- Pill variant -->
|
|
47
54
|
<label
|
|
48
|
-
|
|
55
|
+
v-if="variant === 'pill'"
|
|
49
56
|
:class="[
|
|
57
|
+
props.class,
|
|
58
|
+
'ui-radio-pill',
|
|
59
|
+
`ui-radio-pill--${size}`,
|
|
60
|
+
{
|
|
61
|
+
'ui-radio-pill--disabled': disabled,
|
|
62
|
+
'ui-radio-pill--checked': isChecked
|
|
63
|
+
}
|
|
64
|
+
]"
|
|
65
|
+
>
|
|
66
|
+
<input
|
|
67
|
+
:id="radioId"
|
|
68
|
+
type="radio"
|
|
69
|
+
:checked="isChecked"
|
|
70
|
+
:disabled="disabled"
|
|
71
|
+
:name="name"
|
|
72
|
+
:value="value"
|
|
73
|
+
class="ui-radio-pill__input"
|
|
74
|
+
@change="handleChange"
|
|
75
|
+
/>
|
|
76
|
+
|
|
77
|
+
<span class="ui-radio-pill__indicator" aria-hidden="true">
|
|
78
|
+
<svg
|
|
79
|
+
class="ui-radio-pill__check"
|
|
80
|
+
viewBox="0 0 16 16"
|
|
81
|
+
fill="none"
|
|
82
|
+
stroke="currentColor"
|
|
83
|
+
stroke-width="2.5"
|
|
84
|
+
stroke-linecap="round"
|
|
85
|
+
stroke-linejoin="round"
|
|
86
|
+
>
|
|
87
|
+
<path d="M3.5 8.5L6.5 11L12.5 5" />
|
|
88
|
+
</svg>
|
|
89
|
+
</span>
|
|
90
|
+
|
|
91
|
+
<span v-if="label" class="ui-radio-pill__label">{{ label }}</span>
|
|
92
|
+
</label>
|
|
93
|
+
|
|
94
|
+
<!-- Default variant -->
|
|
95
|
+
<label
|
|
96
|
+
v-else
|
|
97
|
+
:class="[
|
|
98
|
+
props.class,
|
|
99
|
+
'ui-radio',
|
|
50
100
|
`ui-radio--${size}`,
|
|
51
101
|
{
|
|
52
102
|
'ui-radio--disabled': disabled,
|
|
@@ -211,4 +261,122 @@ function handleChange() {
|
|
|
211
261
|
.ui-radio--lg .ui-radio__description {
|
|
212
262
|
font-size: var(--text-sm);
|
|
213
263
|
}
|
|
264
|
+
|
|
265
|
+
/* Pill variant styles */
|
|
266
|
+
.ui-radio-pill {
|
|
267
|
+
display: inline-flex;
|
|
268
|
+
align-items: center;
|
|
269
|
+
gap: var(--space-2);
|
|
270
|
+
height: 36px;
|
|
271
|
+
padding: 0 var(--space-3);
|
|
272
|
+
background: var(--chip-bg);
|
|
273
|
+
border: 1px solid var(--chip-border);
|
|
274
|
+
border-radius: var(--radius-full);
|
|
275
|
+
font-family: var(--font-sans);
|
|
276
|
+
font-size: var(--text-sm);
|
|
277
|
+
font-weight: var(--font-medium);
|
|
278
|
+
color: var(--chip-text);
|
|
279
|
+
cursor: pointer;
|
|
280
|
+
transition:
|
|
281
|
+
background-color var(--duration-fast) var(--ease-default),
|
|
282
|
+
border-color var(--duration-fast) var(--ease-default),
|
|
283
|
+
color var(--duration-fast) var(--ease-default);
|
|
284
|
+
-webkit-tap-highlight-color: transparent;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.ui-radio-pill--sm {
|
|
288
|
+
height: 32px;
|
|
289
|
+
font-size: var(--text-xs);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.ui-radio-pill--lg {
|
|
293
|
+
height: 44px;
|
|
294
|
+
font-size: var(--text-md);
|
|
295
|
+
padding: 0 var(--space-4);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.ui-radio-pill__input {
|
|
299
|
+
position: absolute;
|
|
300
|
+
width: 1px;
|
|
301
|
+
height: 1px;
|
|
302
|
+
padding: 0;
|
|
303
|
+
margin: -1px;
|
|
304
|
+
overflow: hidden;
|
|
305
|
+
clip: rect(0, 0, 0, 0);
|
|
306
|
+
white-space: nowrap;
|
|
307
|
+
border: 0;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.ui-radio-pill:not(.ui-radio-pill--disabled):hover {
|
|
311
|
+
background: var(--chip-bg-hover);
|
|
312
|
+
border-color: var(--chip-border-hover);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.ui-radio-pill:not(.ui-radio-pill--disabled):active {
|
|
316
|
+
background: var(--chip-bg-active);
|
|
317
|
+
border-color: var(--chip-border-active);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.ui-radio-pill--checked {
|
|
321
|
+
background: var(--chip-bg-selected);
|
|
322
|
+
border-color: var(--chip-border-selected);
|
|
323
|
+
color: var(--chip-text-selected);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.ui-radio-pill--checked:not(.ui-radio-pill--disabled):hover {
|
|
327
|
+
background: var(--chip-bg-selected-hover);
|
|
328
|
+
border-color: var(--chip-border-selected-hover);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.ui-radio-pill--checked:not(.ui-radio-pill--disabled):active {
|
|
332
|
+
background: var(--chip-bg-selected-active);
|
|
333
|
+
border-color: var(--chip-border-selected-active);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.ui-radio-pill:has(.ui-radio-pill__input:focus-visible) {
|
|
337
|
+
outline: 2px solid var(--ring-color);
|
|
338
|
+
outline-offset: 2px;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.ui-radio-pill--disabled {
|
|
342
|
+
opacity: 0.5;
|
|
343
|
+
cursor: not-allowed;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.ui-radio-pill__indicator {
|
|
347
|
+
display: flex;
|
|
348
|
+
align-items: center;
|
|
349
|
+
justify-content: center;
|
|
350
|
+
width: 0;
|
|
351
|
+
margin-right: calc(-1 * var(--space-2));
|
|
352
|
+
overflow: hidden;
|
|
353
|
+
transition:
|
|
354
|
+
width var(--duration-fast) var(--ease-out-expo),
|
|
355
|
+
margin var(--duration-fast) var(--ease-out-expo);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.ui-radio-pill--checked .ui-radio-pill__indicator {
|
|
359
|
+
width: 1rem;
|
|
360
|
+
margin-right: 0;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.ui-radio-pill__check {
|
|
364
|
+
width: 0.875rem;
|
|
365
|
+
height: 0.875rem;
|
|
366
|
+
flex-shrink: 0;
|
|
367
|
+
opacity: 0;
|
|
368
|
+
transform: scale(0.5);
|
|
369
|
+
transition:
|
|
370
|
+
opacity var(--duration-fast) var(--ease-default),
|
|
371
|
+
transform var(--duration-fast) var(--ease-out-back);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.ui-radio-pill--checked .ui-radio-pill__check {
|
|
375
|
+
opacity: 1;
|
|
376
|
+
transform: scale(1);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.ui-radio-pill__label {
|
|
380
|
+
white-space: nowrap;
|
|
381
|
+
}
|
|
214
382
|
</style>
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
import { computed, ref } from 'vue'
|
|
3
3
|
import Icon from '../Icon/Icon.vue'
|
|
4
4
|
import { useInternalIcon } from '../../config/icons'
|
|
5
|
+
import type { ClassValue } from '../../types/common'
|
|
5
6
|
|
|
6
7
|
const StarIcon = useInternalIcon('star')
|
|
7
8
|
const StarFilledIcon = useInternalIcon('starFilled')
|
|
8
9
|
|
|
9
10
|
export interface RatingProps {
|
|
11
|
+
/** Additional CSS classes */
|
|
12
|
+
class?: ClassValue
|
|
10
13
|
/** Current rating value (0 to max) */
|
|
11
14
|
modelValue: number
|
|
12
15
|
/** Maximum rating value */
|
|
@@ -134,8 +137,9 @@ const iconSize = computed(() => {
|
|
|
134
137
|
|
|
135
138
|
<template>
|
|
136
139
|
<div
|
|
137
|
-
class="ui-rating"
|
|
138
140
|
:class="[
|
|
141
|
+
props.class,
|
|
142
|
+
'ui-rating',
|
|
139
143
|
`ui-rating--${size}`,
|
|
140
144
|
{ 'ui-rating--readonly': readonly }
|
|
141
145
|
]"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, computed, watch, onMounted, nextTick } from 'vue'
|
|
3
3
|
import { useId } from '../../composables'
|
|
4
|
+
import type { ClassValue } from '../../types/common'
|
|
4
5
|
|
|
5
6
|
export interface SegmentedOption {
|
|
6
7
|
label: string
|
|
@@ -9,6 +10,8 @@ export interface SegmentedOption {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export interface SegmentedControlProps {
|
|
13
|
+
/** Additional CSS classes */
|
|
14
|
+
class?: ClassValue
|
|
12
15
|
/** Array of options to display */
|
|
13
16
|
options: SegmentedOption[]
|
|
14
17
|
/** Selected value (v-model) */
|
|
@@ -146,8 +149,9 @@ function setItemRef(el: HTMLButtonElement | null, index: number) {
|
|
|
146
149
|
role="radiogroup"
|
|
147
150
|
:aria-label="label"
|
|
148
151
|
:aria-disabled="disabled || undefined"
|
|
149
|
-
class="ui-segmented"
|
|
150
152
|
:class="[
|
|
153
|
+
props.class,
|
|
154
|
+
'ui-segmented',
|
|
151
155
|
`ui-segmented--${size}`,
|
|
152
156
|
{ 'ui-segmented--disabled': disabled }
|
|
153
157
|
]"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, computed, watch, nextTick, onMounted, onBeforeUnmount } from 'vue'
|
|
3
3
|
import { useId } from '../../composables'
|
|
4
|
+
import type { ClassValue } from '../../types/common'
|
|
4
5
|
|
|
5
6
|
export interface SelectOption {
|
|
6
7
|
/** Display text shown to user */
|
|
@@ -12,6 +13,8 @@ export interface SelectOption {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export interface SelectProps {
|
|
16
|
+
/** Additional CSS classes */
|
|
17
|
+
class?: ClassValue
|
|
15
18
|
/** Selected value (v-model) */
|
|
16
19
|
modelValue?: string | number | null
|
|
17
20
|
/** Available options */
|
|
@@ -301,8 +304,9 @@ onBeforeUnmount(() => {
|
|
|
301
304
|
|
|
302
305
|
<template>
|
|
303
306
|
<div
|
|
304
|
-
class="ui-select"
|
|
305
307
|
:class="[
|
|
308
|
+
props.class,
|
|
309
|
+
'ui-select',
|
|
306
310
|
`ui-select--${size}`,
|
|
307
311
|
{
|
|
308
312
|
'ui-select--block': block,
|
|
@@ -602,65 +606,67 @@ onBeforeUnmount(() => {
|
|
|
602
606
|
</style>
|
|
603
607
|
|
|
604
608
|
<style>
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
.ui-select__option {
|
|
620
|
-
display: flex;
|
|
621
|
-
align-items: center;
|
|
622
|
-
justify-content: space-between;
|
|
623
|
-
gap: var(--space-2);
|
|
624
|
-
padding: var(--space-2) var(--space-3);
|
|
625
|
-
border-radius: var(--radius-md);
|
|
626
|
-
font-family: var(--font-sans);
|
|
627
|
-
font-size: var(--text-sm);
|
|
628
|
-
color: var(--select-option-text);
|
|
629
|
-
cursor: pointer;
|
|
630
|
-
transition: background-color var(--duration-fast) var(--ease-default);
|
|
631
|
-
}
|
|
609
|
+
@layer spire-components {
|
|
610
|
+
.ui-select__listbox {
|
|
611
|
+
z-index: 9999;
|
|
612
|
+
margin: 0;
|
|
613
|
+
padding: var(--space-1);
|
|
614
|
+
list-style: none;
|
|
615
|
+
background-color: var(--select-menu-bg);
|
|
616
|
+
border: 1px solid var(--select-menu-border);
|
|
617
|
+
border-radius: var(--radius-lg);
|
|
618
|
+
box-shadow: var(--shadow-lg);
|
|
619
|
+
max-height: 256px;
|
|
620
|
+
overflow-y: auto;
|
|
621
|
+
overscroll-behavior: contain;
|
|
622
|
+
}
|
|
632
623
|
|
|
633
|
-
.ui-select__option
|
|
634
|
-
|
|
635
|
-
|
|
624
|
+
.ui-select__option {
|
|
625
|
+
display: flex;
|
|
626
|
+
align-items: center;
|
|
627
|
+
justify-content: space-between;
|
|
628
|
+
gap: var(--space-2);
|
|
629
|
+
padding: var(--space-2) var(--space-3);
|
|
630
|
+
border-radius: var(--radius-md);
|
|
631
|
+
font-family: var(--font-sans);
|
|
632
|
+
font-size: var(--text-sm);
|
|
633
|
+
color: var(--select-option-text);
|
|
634
|
+
cursor: pointer;
|
|
635
|
+
transition: background-color var(--duration-fast) var(--ease-default);
|
|
636
|
+
}
|
|
636
637
|
|
|
637
|
-
.ui-select__option--
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
}
|
|
638
|
+
.ui-select__option--highlighted {
|
|
639
|
+
background-color: var(--select-option-hover);
|
|
640
|
+
}
|
|
641
641
|
|
|
642
|
-
.ui-select__option--
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
}
|
|
642
|
+
.ui-select__option--selected {
|
|
643
|
+
color: var(--select-option-selected);
|
|
644
|
+
font-weight: var(--font-medium);
|
|
645
|
+
}
|
|
646
646
|
|
|
647
|
-
.ui-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
color: var(--select-option-selected);
|
|
652
|
-
}
|
|
647
|
+
.ui-select__option--disabled {
|
|
648
|
+
opacity: 0.5;
|
|
649
|
+
cursor: not-allowed;
|
|
650
|
+
}
|
|
653
651
|
|
|
654
|
-
.ui-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
}
|
|
652
|
+
.ui-select__check {
|
|
653
|
+
flex-shrink: 0;
|
|
654
|
+
width: 1rem;
|
|
655
|
+
height: 1rem;
|
|
656
|
+
color: var(--select-option-selected);
|
|
657
|
+
}
|
|
660
658
|
|
|
661
|
-
.ui-select-menu-enter-
|
|
662
|
-
.ui-select-menu-leave-
|
|
663
|
-
|
|
664
|
-
|
|
659
|
+
.ui-select-menu-enter-active,
|
|
660
|
+
.ui-select-menu-leave-active {
|
|
661
|
+
transition:
|
|
662
|
+
opacity var(--duration-fast) var(--ease-default),
|
|
663
|
+
transform var(--duration-fast) var(--ease-default);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
.ui-select-menu-enter-from,
|
|
667
|
+
.ui-select-menu-leave-to {
|
|
668
|
+
opacity: 0;
|
|
669
|
+
transform: translateY(-4px);
|
|
670
|
+
}
|
|
665
671
|
}
|
|
666
672
|
</style>
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
import { computed, inject, provide } from 'vue'
|
|
3
3
|
import { useId } from '../../composables'
|
|
4
4
|
import { SidebarKey, SidebarGroupKey } from './keys'
|
|
5
|
+
import type { ClassValue } from '../../types/common'
|
|
5
6
|
|
|
6
7
|
export interface SidebarGroupProps {
|
|
8
|
+
/** Additional CSS classes */
|
|
9
|
+
class?: ClassValue
|
|
7
10
|
/** Group label displayed when expanded */
|
|
8
11
|
label?: string
|
|
9
12
|
/** Show separator line when collapsed */
|
|
@@ -26,6 +29,7 @@ const isCollapsed = computed(() => sidebar.collapsed.value)
|
|
|
26
29
|
provide(SidebarGroupKey, { groupId })
|
|
27
30
|
|
|
28
31
|
const groupClasses = computed(() => [
|
|
32
|
+
props.class,
|
|
29
33
|
'ui-sidebar-group',
|
|
30
34
|
{
|
|
31
35
|
'ui-sidebar-group--collapsed': isCollapsed.value,
|
|
@@ -3,11 +3,14 @@ import { computed, inject, type Component } from 'vue'
|
|
|
3
3
|
import { SidebarKey } from './keys'
|
|
4
4
|
import Icon from '../Icon/Icon.vue'
|
|
5
5
|
import Tooltip from '../Tooltip/Tooltip.vue'
|
|
6
|
+
import type { ClassValue } from '../../types/common'
|
|
6
7
|
|
|
7
8
|
type HugeIconData = [string, Record<string, unknown>][]
|
|
8
9
|
type IconInput = Component | HugeIconData
|
|
9
10
|
|
|
10
11
|
export interface SidebarItemProps {
|
|
12
|
+
/** Additional CSS classes */
|
|
13
|
+
class?: ClassValue
|
|
11
14
|
/** Text label for the item */
|
|
12
15
|
label: string
|
|
13
16
|
/** Icon component or HugeIcons data */
|
|
@@ -41,6 +44,7 @@ if (!sidebar) {
|
|
|
41
44
|
const isCollapsed = computed(() => sidebar.collapsed.value)
|
|
42
45
|
|
|
43
46
|
const itemClasses = computed(() => [
|
|
47
|
+
props.class,
|
|
44
48
|
'ui-sidebar-item',
|
|
45
49
|
{
|
|
46
50
|
'ui-sidebar-item--active': props.active,
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { ClassValue } from '../../types/common'
|
|
3
|
+
|
|
2
4
|
export interface SidebarLayoutProps {
|
|
5
|
+
/** Additional CSS classes */
|
|
6
|
+
class?: ClassValue
|
|
3
7
|
/** Position of the sidebar */
|
|
4
8
|
sidebarPosition?: 'left' | 'right'
|
|
5
9
|
}
|
|
@@ -11,8 +15,7 @@ const props = withDefaults(defineProps<SidebarLayoutProps>(), {
|
|
|
11
15
|
|
|
12
16
|
<template>
|
|
13
17
|
<div
|
|
14
|
-
class="ui-sidebar-layout"
|
|
15
|
-
:class="[`ui-sidebar-layout--${sidebarPosition}`]"
|
|
18
|
+
:class="[props.class, 'ui-sidebar-layout', `ui-sidebar-layout--${sidebarPosition}`]"
|
|
16
19
|
>
|
|
17
20
|
<slot name="sidebar" />
|
|
18
21
|
<main class="ui-sidebar-layout__main">
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, provide, toRef, ref, watch } from 'vue'
|
|
3
3
|
import { SidebarKey } from './keys'
|
|
4
|
+
import type { ClassValue } from '../../types/common'
|
|
4
5
|
|
|
5
6
|
export interface SidebarRootProps {
|
|
7
|
+
/** Additional CSS classes */
|
|
8
|
+
class?: ClassValue
|
|
6
9
|
/** Whether the sidebar is collapsed */
|
|
7
10
|
modelValue?: boolean
|
|
8
11
|
/** Width when expanded */
|
|
@@ -54,8 +57,7 @@ defineExpose({ toggle, collapsed })
|
|
|
54
57
|
|
|
55
58
|
<template>
|
|
56
59
|
<aside
|
|
57
|
-
class="ui-sidebar"
|
|
58
|
-
:class="{ 'ui-sidebar--collapsed': collapsed }"
|
|
60
|
+
:class="[props.class, 'ui-sidebar', { 'ui-sidebar--collapsed': collapsed }]"
|
|
59
61
|
:style="{ '--sidebar-current-width': currentWidth }"
|
|
60
62
|
role="navigation"
|
|
61
63
|
>
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
|
+
import type { ClassValue } from '../../types/common'
|
|
3
4
|
|
|
4
5
|
export type SkeletonVariant = 'text' | 'circle' | 'rect'
|
|
5
6
|
|
|
6
7
|
export interface SkeletonProps {
|
|
8
|
+
/** Additional CSS classes */
|
|
9
|
+
class?: ClassValue
|
|
7
10
|
/** Shape variant */
|
|
8
11
|
variant?: SkeletonVariant
|
|
9
12
|
/** Width (px, %, or CSS value) */
|
|
@@ -34,8 +37,9 @@ const style = computed(() => ({
|
|
|
34
37
|
|
|
35
38
|
<template>
|
|
36
39
|
<span
|
|
37
|
-
class="ui-skeleton"
|
|
38
40
|
:class="[
|
|
41
|
+
props.class,
|
|
42
|
+
'ui-skeleton',
|
|
39
43
|
`ui-skeleton--${variant}`,
|
|
40
44
|
`ui-skeleton--${animation}`
|
|
41
45
|
]"
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, ref, onUnmounted } from 'vue'
|
|
3
3
|
import { valueToPercent, getValueFromPointer, getClosestThumb, clamp, snapToStep } from './utils'
|
|
4
|
+
import type { ClassValue } from '../../types/common'
|
|
4
5
|
|
|
5
6
|
export interface SliderProps {
|
|
7
|
+
/** Additional CSS classes */
|
|
8
|
+
class?: ClassValue
|
|
6
9
|
/** Current value (number for single, [min, max] tuple for range) */
|
|
7
10
|
modelValue: number | [number, number]
|
|
8
11
|
/** Minimum value */
|
|
@@ -231,8 +234,9 @@ onUnmounted(() => {
|
|
|
231
234
|
|
|
232
235
|
<template>
|
|
233
236
|
<div
|
|
234
|
-
class="ui-slider"
|
|
235
237
|
:class="[
|
|
238
|
+
props.class,
|
|
239
|
+
'ui-slider',
|
|
236
240
|
`ui-slider--${size}`,
|
|
237
241
|
{
|
|
238
242
|
'ui-slider--disabled': disabled,
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
|
+
import type { ClassValue } from '../../types/common'
|
|
3
4
|
|
|
4
5
|
export interface SpinnerProps {
|
|
6
|
+
/** Additional CSS classes */
|
|
7
|
+
class?: ClassValue
|
|
5
8
|
/** Predefined size or custom value */
|
|
6
9
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | string
|
|
7
10
|
/** Animation speed in seconds */
|
|
@@ -30,7 +33,7 @@ const resolvedSpeed = computed(() => `${props.speed}s`)
|
|
|
30
33
|
|
|
31
34
|
<template>
|
|
32
35
|
<div
|
|
33
|
-
class="ui-spinner"
|
|
36
|
+
:class="[props.class, 'ui-spinner']"
|
|
34
37
|
role="status"
|
|
35
38
|
:aria-label="label"
|
|
36
39
|
:style="{
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { InjectionKey, ComputedRef } from 'vue'
|
|
3
|
+
import type { ClassValue } from '../../types/common'
|
|
3
4
|
|
|
4
5
|
export type Theme = 'light' | 'dark'
|
|
5
6
|
export type Mood = 'warm' | 'cool' | 'vibrant' | 'muted' | 'earthy'
|
|
@@ -16,6 +17,8 @@ export interface SpireConfig {
|
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export interface SpireProviderProps {
|
|
20
|
+
/** Additional CSS classes */
|
|
21
|
+
class?: ClassValue
|
|
19
22
|
theme?: Theme
|
|
20
23
|
mood?: Mood
|
|
21
24
|
depth?: Depth
|
|
@@ -58,7 +61,7 @@ const dataAttributes = computed(() => {
|
|
|
58
61
|
</script>
|
|
59
62
|
|
|
60
63
|
<template>
|
|
61
|
-
<component :is="tag" class="spire-provider" v-bind="dataAttributes">
|
|
64
|
+
<component :is="tag" :class="[props.class, 'spire-provider']" v-bind="dataAttributes">
|
|
62
65
|
<slot />
|
|
63
66
|
</component>
|
|
64
67
|
</template>
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
import { computed, provide, inject, onMounted } from 'vue'
|
|
3
3
|
import { useId } from '../../composables'
|
|
4
4
|
import { StepperKey, StepperItemKey } from './keys'
|
|
5
|
+
import type { ClassValue } from '../../types/common'
|
|
5
6
|
|
|
6
7
|
export interface StepperItemProps {
|
|
8
|
+
/** Additional CSS classes */
|
|
9
|
+
class?: ClassValue
|
|
7
10
|
/** Step index (0-based) */
|
|
8
11
|
index: number
|
|
9
12
|
/** Disable this step */
|
|
@@ -47,6 +50,7 @@ provide(StepperItemKey, {
|
|
|
47
50
|
})
|
|
48
51
|
|
|
49
52
|
const itemClasses = computed(() => [
|
|
53
|
+
props.class,
|
|
50
54
|
'ui-stepper__item',
|
|
51
55
|
`ui-stepper__item--${stepper.orientation.value}`,
|
|
52
56
|
`ui-stepper__item--${state.value}`,
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
import { computed, provide, toRef, ref, watch } from 'vue'
|
|
3
3
|
import { StepperKey } from './keys'
|
|
4
4
|
import type { StepperOrientation, StepState } from './keys'
|
|
5
|
+
import type { ClassValue } from '../../types/common'
|
|
5
6
|
|
|
6
7
|
export interface StepperRootProps {
|
|
8
|
+
/** Additional CSS classes */
|
|
9
|
+
class?: ClassValue
|
|
7
10
|
/** Current step index (0-based, v-model) */
|
|
8
11
|
modelValue?: number
|
|
9
12
|
/** Layout direction */
|
|
@@ -75,8 +78,7 @@ provide(StepperKey, {
|
|
|
75
78
|
|
|
76
79
|
<template>
|
|
77
80
|
<div
|
|
78
|
-
class="ui-stepper"
|
|
79
|
-
:class="[`ui-stepper--${orientation}`]"
|
|
81
|
+
:class="[props.class, 'ui-stepper', `ui-stepper--${orientation}`]"
|
|
80
82
|
role="tablist"
|
|
81
83
|
:aria-orientation="orientation"
|
|
82
84
|
>
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
import { computed, inject, h, type Component } from 'vue'
|
|
3
3
|
import { StepperKey, StepperItemKey } from './keys'
|
|
4
4
|
import { useInternalIcon } from '../../config/icons'
|
|
5
|
+
import type { ClassValue } from '../../types/common'
|
|
5
6
|
|
|
6
7
|
export interface StepperTriggerProps {
|
|
8
|
+
/** Additional CSS classes */
|
|
9
|
+
class?: ClassValue
|
|
7
10
|
/** Custom icon to display instead of step number */
|
|
8
11
|
icon?: Component
|
|
9
12
|
}
|
|
10
13
|
|
|
11
|
-
defineProps<StepperTriggerProps>()
|
|
12
|
-
|
|
13
14
|
const stepper = inject(StepperKey)
|
|
14
15
|
const stepperItem = inject(StepperItemKey)
|
|
15
16
|
|
|
@@ -19,7 +20,10 @@ if (!stepper || !stepperItem) {
|
|
|
19
20
|
|
|
20
21
|
const CheckIcon = useInternalIcon('check')
|
|
21
22
|
|
|
23
|
+
const props = defineProps<StepperTriggerProps>()
|
|
24
|
+
|
|
22
25
|
const triggerClasses = computed(() => [
|
|
26
|
+
props.class,
|
|
23
27
|
'ui-stepper__trigger',
|
|
24
28
|
`ui-stepper__trigger--${stepperItem.state.value}`
|
|
25
29
|
])
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
import { computed } from 'vue'
|
|
3
3
|
import Spinner from '../Spinner/Spinner.vue'
|
|
4
4
|
import { useId } from '../../composables'
|
|
5
|
+
import type { ClassValue } from '../../types/common'
|
|
5
6
|
|
|
6
7
|
export interface SwitchProps {
|
|
8
|
+
/** Additional CSS classes */
|
|
9
|
+
class?: ClassValue
|
|
7
10
|
/** Checked state (v-model) */
|
|
8
11
|
modelValue?: boolean
|
|
9
12
|
/** Switch size */
|
|
@@ -67,8 +70,9 @@ const spinnerSize = computed(() => spinnerSizeMap[props.size])
|
|
|
67
70
|
:aria-checked="modelValue"
|
|
68
71
|
:aria-label="label"
|
|
69
72
|
:disabled="isDisabled"
|
|
70
|
-
class="ui-switch"
|
|
71
73
|
:class="[
|
|
74
|
+
props.class,
|
|
75
|
+
'ui-switch',
|
|
72
76
|
`ui-switch--${size}`,
|
|
73
77
|
{
|
|
74
78
|
'ui-switch--checked': modelValue,
|