@sabrenski/spire-ui 0.0.6 → 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 +167 -4
- package/dist/spire-ui.css +1 -1
- package/dist/spire-ui.es.js +7005 -6741
- 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 +4 -1
- 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,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, computed, watch, nextTick, onBeforeUnmount } from 'vue'
|
|
3
3
|
import { useId } from '../../composables'
|
|
4
|
+
import type { ClassValue } from '../../types/common'
|
|
4
5
|
|
|
5
6
|
export interface ComboboxOption {
|
|
6
7
|
/** Display text shown to user */
|
|
@@ -12,6 +13,8 @@ export interface ComboboxOption {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export interface ComboboxProps {
|
|
16
|
+
/** Additional CSS classes */
|
|
17
|
+
class?: ClassValue
|
|
15
18
|
/** Selected value(s) - single value or array for multiple */
|
|
16
19
|
modelValue?: string | number | (string | number)[] | null
|
|
17
20
|
/** Available options */
|
|
@@ -411,8 +414,9 @@ onBeforeUnmount(() => {
|
|
|
411
414
|
|
|
412
415
|
<template>
|
|
413
416
|
<div
|
|
414
|
-
class="ui-combobox"
|
|
415
417
|
:class="[
|
|
418
|
+
props.class,
|
|
419
|
+
'ui-combobox',
|
|
416
420
|
`ui-combobox--${size}`,
|
|
417
421
|
{
|
|
418
422
|
'ui-combobox--block': block,
|
|
@@ -827,108 +831,110 @@ onBeforeUnmount(() => {
|
|
|
827
831
|
</style>
|
|
828
832
|
|
|
829
833
|
<style>
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
.ui-combobox__option {
|
|
845
|
-
display: flex;
|
|
846
|
-
align-items: center;
|
|
847
|
-
gap: var(--space-2);
|
|
848
|
-
padding: var(--space-2) var(--space-3);
|
|
849
|
-
border-radius: var(--radius-md);
|
|
850
|
-
font-family: var(--font-sans);
|
|
851
|
-
font-size: var(--text-sm);
|
|
852
|
-
color: var(--select-option-text);
|
|
853
|
-
cursor: pointer;
|
|
854
|
-
transition: background-color var(--duration-fast) var(--ease-default);
|
|
855
|
-
}
|
|
834
|
+
@layer spire-components {
|
|
835
|
+
.ui-combobox__listbox {
|
|
836
|
+
z-index: 9999;
|
|
837
|
+
margin: 0;
|
|
838
|
+
padding: var(--space-1);
|
|
839
|
+
list-style: none;
|
|
840
|
+
background-color: var(--select-menu-bg);
|
|
841
|
+
border: 1px solid var(--select-menu-border);
|
|
842
|
+
border-radius: var(--radius-lg);
|
|
843
|
+
box-shadow: var(--shadow-lg);
|
|
844
|
+
max-height: 256px;
|
|
845
|
+
overflow-y: auto;
|
|
846
|
+
overscroll-behavior: contain;
|
|
847
|
+
}
|
|
856
848
|
|
|
857
|
-
.ui-combobox__option
|
|
858
|
-
|
|
859
|
-
|
|
849
|
+
.ui-combobox__option {
|
|
850
|
+
display: flex;
|
|
851
|
+
align-items: center;
|
|
852
|
+
gap: var(--space-2);
|
|
853
|
+
padding: var(--space-2) var(--space-3);
|
|
854
|
+
border-radius: var(--radius-md);
|
|
855
|
+
font-family: var(--font-sans);
|
|
856
|
+
font-size: var(--text-sm);
|
|
857
|
+
color: var(--select-option-text);
|
|
858
|
+
cursor: pointer;
|
|
859
|
+
transition: background-color var(--duration-fast) var(--ease-default);
|
|
860
|
+
}
|
|
860
861
|
|
|
861
|
-
.ui-combobox__option--
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
}
|
|
862
|
+
.ui-combobox__option--highlighted {
|
|
863
|
+
background-color: var(--select-option-hover);
|
|
864
|
+
}
|
|
865
865
|
|
|
866
|
-
.ui-combobox__option--
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
}
|
|
866
|
+
.ui-combobox__option--selected {
|
|
867
|
+
color: var(--select-option-selected);
|
|
868
|
+
font-weight: var(--font-medium);
|
|
869
|
+
}
|
|
870
870
|
|
|
871
|
-
.ui-combobox__option--
|
|
872
|
-
|
|
873
|
-
|
|
871
|
+
.ui-combobox__option--disabled {
|
|
872
|
+
opacity: 0.5;
|
|
873
|
+
cursor: not-allowed;
|
|
874
|
+
}
|
|
874
875
|
|
|
875
|
-
.ui-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
justify-content: center;
|
|
879
|
-
width: 1rem;
|
|
880
|
-
height: 1rem;
|
|
881
|
-
border: 1.5px solid var(--checkbox-border);
|
|
882
|
-
border-radius: var(--radius-sm);
|
|
883
|
-
background-color: var(--checkbox-bg);
|
|
884
|
-
flex-shrink: 0;
|
|
885
|
-
}
|
|
876
|
+
.ui-combobox__option--create {
|
|
877
|
+
color: var(--action-primary);
|
|
878
|
+
}
|
|
886
879
|
|
|
887
|
-
.ui-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
880
|
+
.ui-combobox__checkbox {
|
|
881
|
+
display: flex;
|
|
882
|
+
align-items: center;
|
|
883
|
+
justify-content: center;
|
|
884
|
+
width: 1rem;
|
|
885
|
+
height: 1rem;
|
|
886
|
+
border: 1.5px solid var(--checkbox-border);
|
|
887
|
+
border-radius: var(--radius-sm);
|
|
888
|
+
background-color: var(--checkbox-bg);
|
|
889
|
+
flex-shrink: 0;
|
|
890
|
+
}
|
|
892
891
|
|
|
893
|
-
.ui-combobox__checkbox
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
892
|
+
.ui-combobox__option--selected .ui-combobox__checkbox {
|
|
893
|
+
background-color: var(--checkbox-checked-bg);
|
|
894
|
+
border-color: var(--checkbox-checked-bg);
|
|
895
|
+
color: var(--checkbox-check);
|
|
896
|
+
}
|
|
897
897
|
|
|
898
|
-
.ui-
|
|
899
|
-
|
|
900
|
-
|
|
898
|
+
.ui-combobox__checkbox svg {
|
|
899
|
+
width: 0.75rem;
|
|
900
|
+
height: 0.75rem;
|
|
901
|
+
}
|
|
901
902
|
|
|
902
|
-
.ui-combobox__option-label
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
font-weight: var(--font-semibold);
|
|
906
|
-
}
|
|
903
|
+
.ui-combobox__option-label {
|
|
904
|
+
flex: 1;
|
|
905
|
+
}
|
|
907
906
|
|
|
908
|
-
.ui-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
}
|
|
907
|
+
.ui-combobox__option-label mark {
|
|
908
|
+
background-color: transparent;
|
|
909
|
+
color: var(--action-primary);
|
|
910
|
+
font-weight: var(--font-semibold);
|
|
911
|
+
}
|
|
914
912
|
|
|
915
|
-
.ui-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
}
|
|
913
|
+
.ui-combobox__check {
|
|
914
|
+
flex-shrink: 0;
|
|
915
|
+
width: 1rem;
|
|
916
|
+
height: 1rem;
|
|
917
|
+
color: var(--select-option-selected);
|
|
918
|
+
}
|
|
921
919
|
|
|
922
|
-
.ui-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
}
|
|
920
|
+
.ui-combobox__empty {
|
|
921
|
+
padding: var(--space-3);
|
|
922
|
+
text-align: center;
|
|
923
|
+
font-size: var(--text-sm);
|
|
924
|
+
color: var(--input-placeholder);
|
|
925
|
+
}
|
|
928
926
|
|
|
929
|
-
.ui-combobox-menu-enter-
|
|
930
|
-
.ui-combobox-menu-leave-
|
|
931
|
-
|
|
932
|
-
|
|
927
|
+
.ui-combobox-menu-enter-active,
|
|
928
|
+
.ui-combobox-menu-leave-active {
|
|
929
|
+
transition:
|
|
930
|
+
opacity var(--duration-fast) var(--ease-default),
|
|
931
|
+
transform var(--duration-fast) var(--ease-default);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
.ui-combobox-menu-enter-from,
|
|
935
|
+
.ui-combobox-menu-leave-to {
|
|
936
|
+
opacity: 0;
|
|
937
|
+
transform: translateY(-4px);
|
|
938
|
+
}
|
|
933
939
|
}
|
|
934
940
|
</style>
|
|
@@ -10,6 +10,7 @@ import Input from '../Input/Input.vue'
|
|
|
10
10
|
import { getNestedValue } from '../../utils/object'
|
|
11
11
|
import { useInternalIcon } from '../../config/icons'
|
|
12
12
|
import { useId } from '../../composables'
|
|
13
|
+
import type { ClassValue } from '../../types/common'
|
|
13
14
|
|
|
14
15
|
const skeletonWidths = ['60%', '75%', '90%', '70%', '85%', '65%', '80%', '55%']
|
|
15
16
|
function getSkeletonWidth(rowIndex: number, colIndex: number): string {
|
|
@@ -66,6 +67,8 @@ export interface PaginationConfig {
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
export interface DataTableProps {
|
|
70
|
+
/** Additional CSS classes */
|
|
71
|
+
class?: ClassValue
|
|
69
72
|
/** Data array */
|
|
70
73
|
data: Record<string, unknown>[]
|
|
71
74
|
/** Column definitions */
|
|
@@ -548,8 +551,9 @@ const skeletonArray = computed(() => Array.from({ length: props.skeletonRows }))
|
|
|
548
551
|
<template>
|
|
549
552
|
<div
|
|
550
553
|
ref="tableRef"
|
|
551
|
-
class="ui-table"
|
|
552
554
|
:class="[
|
|
555
|
+
props.class,
|
|
556
|
+
'ui-table',
|
|
553
557
|
`ui-table--${size}`,
|
|
554
558
|
{
|
|
555
559
|
'ui-table--striped': striped,
|
|
@@ -20,10 +20,13 @@ import {
|
|
|
20
20
|
type CalendarDay,
|
|
21
21
|
type RangeState
|
|
22
22
|
} from '../../utils'
|
|
23
|
+
import type { ClassValue } from '../../types/common'
|
|
23
24
|
|
|
24
25
|
export type ViewMode = 'day' | 'month' | 'year'
|
|
25
26
|
|
|
26
27
|
export interface DatePickerProps {
|
|
28
|
+
/** Additional CSS classes */
|
|
29
|
+
class?: ClassValue
|
|
27
30
|
/** Selected date in ISO format (single mode) or [start, end] tuple (range mode) */
|
|
28
31
|
modelValue?: string | [string, string]
|
|
29
32
|
/** Selection mode */
|
|
@@ -602,8 +605,9 @@ defineExpose({
|
|
|
602
605
|
|
|
603
606
|
<template>
|
|
604
607
|
<div
|
|
605
|
-
class="ui-datepicker-field"
|
|
606
608
|
:class="[
|
|
609
|
+
props.class,
|
|
610
|
+
'ui-datepicker-field',
|
|
607
611
|
`ui-datepicker-field--${size}`,
|
|
608
612
|
{
|
|
609
613
|
'ui-datepicker-field--block': block,
|
|
@@ -8,12 +8,15 @@ import {
|
|
|
8
8
|
nextTick
|
|
9
9
|
} from 'vue'
|
|
10
10
|
import { useId, useScrollLock } from '../../composables'
|
|
11
|
+
import type { ClassValue } from '../../types/common'
|
|
11
12
|
|
|
12
13
|
export type DrawerPlacement = 'right' | 'left' | 'bottom'
|
|
13
14
|
export type DrawerVariant = 'default' | 'floating'
|
|
14
15
|
export type DrawerSize = 'sm' | 'md' | 'lg' | 'xl' | 'full'
|
|
15
16
|
|
|
16
17
|
export interface DrawerProps {
|
|
18
|
+
/** Additional CSS classes */
|
|
19
|
+
class?: ClassValue
|
|
17
20
|
/** Controls visibility (v-model) */
|
|
18
21
|
modelValue?: boolean
|
|
19
22
|
/** Drawer title */
|
|
@@ -184,7 +187,7 @@ defineExpose({
|
|
|
184
187
|
<Transition :name="transitionName">
|
|
185
188
|
<div
|
|
186
189
|
v-if="isOpen"
|
|
187
|
-
:class="['ui-drawer', { 'ui-drawer--force-placement': forcePlacement }]"
|
|
190
|
+
:class="[props.class, 'ui-drawer', { 'ui-drawer--force-placement': forcePlacement }]"
|
|
188
191
|
@keydown="handleKeydown"
|
|
189
192
|
>
|
|
190
193
|
<div
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { InjectionKey, Ref } from 'vue'
|
|
3
|
+
import type { ClassValue } from '../../types/common'
|
|
3
4
|
|
|
4
5
|
export type DropdownPlacement =
|
|
5
6
|
| 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'
|
|
6
7
|
| 'right-start' | 'right-end' | 'left-start' | 'left-end'
|
|
7
8
|
|
|
8
9
|
export interface DropdownProps {
|
|
10
|
+
/** Additional CSS classes */
|
|
11
|
+
class?: ClassValue
|
|
9
12
|
/** Menu placement relative to trigger */
|
|
10
13
|
placement?: DropdownPlacement
|
|
11
14
|
/** Offset from trigger (px) */
|
|
@@ -585,8 +588,7 @@ const showMobileDrilldown = computed(() => {
|
|
|
585
588
|
|
|
586
589
|
<template>
|
|
587
590
|
<div
|
|
588
|
-
class="ui-dropdown"
|
|
589
|
-
:class="{ 'ui-dropdown--submenu': isSubmenu }"
|
|
591
|
+
:class="[props.class, 'ui-dropdown', { 'ui-dropdown--submenu': isSubmenu }]"
|
|
590
592
|
>
|
|
591
593
|
<div
|
|
592
594
|
ref="triggerRef"
|
|
@@ -8,8 +8,11 @@ import {
|
|
|
8
8
|
type Component
|
|
9
9
|
} from 'vue'
|
|
10
10
|
import { dropdownContextKey, type DropdownContext } from './Dropdown.vue'
|
|
11
|
+
import type { ClassValue } from '../../types/common'
|
|
11
12
|
|
|
12
13
|
export interface DropdownItemProps {
|
|
14
|
+
/** Additional CSS classes */
|
|
15
|
+
class?: ClassValue
|
|
13
16
|
/** Renders as RouterLink when provided */
|
|
14
17
|
to?: string | Record<string, unknown>
|
|
15
18
|
/** Renders as anchor when provided */
|
|
@@ -51,6 +54,7 @@ const componentType = computed(() => {
|
|
|
51
54
|
const componentProps = computed(() => {
|
|
52
55
|
const base: Record<string, unknown> = {
|
|
53
56
|
class: [
|
|
57
|
+
props.class,
|
|
54
58
|
'ui-dropdown-item',
|
|
55
59
|
{
|
|
56
60
|
'ui-dropdown-item--disabled': props.disabled,
|
|
@@ -8,8 +8,11 @@ import {
|
|
|
8
8
|
} from 'vue'
|
|
9
9
|
import { dropdownContextKey } from './Dropdown.vue'
|
|
10
10
|
import { dropdownSubContextKey } from './DropdownSub.vue'
|
|
11
|
+
import type { ClassValue } from '../../types/common'
|
|
11
12
|
|
|
12
13
|
export interface DropdownSubTriggerProps {
|
|
14
|
+
/** Additional CSS classes */
|
|
15
|
+
class?: ClassValue
|
|
13
16
|
/** Disabled state */
|
|
14
17
|
disabled?: boolean
|
|
15
18
|
/** Leading icon */
|
|
@@ -60,8 +63,7 @@ onUnmounted(() => {
|
|
|
60
63
|
<button
|
|
61
64
|
ref="triggerRef"
|
|
62
65
|
type="button"
|
|
63
|
-
class="ui-dropdown-sub-trigger"
|
|
64
|
-
:class="{ 'ui-dropdown-sub-trigger--disabled': disabled }"
|
|
66
|
+
:class="[props.class, 'ui-dropdown-sub-trigger', { 'ui-dropdown-sub-trigger--disabled': disabled }]"
|
|
65
67
|
role="menuitem"
|
|
66
68
|
:aria-haspopup="true"
|
|
67
69
|
:aria-expanded="subContext?.isOpen.value"
|
|
@@ -3,10 +3,13 @@ import { computed, useSlots } from 'vue'
|
|
|
3
3
|
import Icon from '../Icon/Icon.vue'
|
|
4
4
|
import type { IconInput } from '../Icon/Icon.vue'
|
|
5
5
|
import { useInternalIcon } from '../../config/icons'
|
|
6
|
+
import type { ClassValue } from '../../types/common'
|
|
6
7
|
|
|
7
8
|
export type EmptyStateVariant = 'default' | 'search' | 'error'
|
|
8
9
|
|
|
9
10
|
export interface EmptyStateProps {
|
|
11
|
+
/** Additional CSS classes */
|
|
12
|
+
class?: ClassValue
|
|
10
13
|
/** Title text */
|
|
11
14
|
title?: string
|
|
12
15
|
/** Description text */
|
|
@@ -43,8 +46,9 @@ const hasAction = computed(() => !!slots.default)
|
|
|
43
46
|
|
|
44
47
|
<template>
|
|
45
48
|
<div
|
|
46
|
-
class="ui-empty-state"
|
|
47
49
|
:class="[
|
|
50
|
+
props.class,
|
|
51
|
+
'ui-empty-state',
|
|
48
52
|
`ui-empty-state--${variant}`,
|
|
49
53
|
{ 'ui-empty-state--compact': compact }
|
|
50
54
|
]"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'
|
|
3
3
|
import Button from '../Button/Button.vue'
|
|
4
4
|
import { useId } from '../../composables'
|
|
5
|
+
import type { ClassValue } from '../../types/common'
|
|
5
6
|
|
|
6
7
|
export interface UploadFile {
|
|
7
8
|
/** Unique identifier */
|
|
@@ -25,6 +26,8 @@ export interface UploadFile {
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
export interface FileUploadProps {
|
|
29
|
+
/** Additional CSS classes */
|
|
30
|
+
class?: ClassValue
|
|
28
31
|
/** Currently selected files (v-model) */
|
|
29
32
|
modelValue?: UploadFile[]
|
|
30
33
|
/** Accepted file types (MIME types or extensions) */
|
|
@@ -479,12 +482,15 @@ function getFileIcon(type: string): string {
|
|
|
479
482
|
|
|
480
483
|
<template>
|
|
481
484
|
<div
|
|
482
|
-
class="
|
|
483
|
-
|
|
484
|
-
'ui-file-upload
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
485
|
+
:class="[
|
|
486
|
+
props.class,
|
|
487
|
+
'ui-file-upload',
|
|
488
|
+
{
|
|
489
|
+
'ui-file-upload--disabled': disabled,
|
|
490
|
+
'ui-file-upload--error': error,
|
|
491
|
+
'ui-file-upload--compact': compact
|
|
492
|
+
}
|
|
493
|
+
]"
|
|
488
494
|
>
|
|
489
495
|
<label
|
|
490
496
|
v-if="label"
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
|
+
import type { ClassValue } from '../../types/common'
|
|
3
4
|
|
|
4
5
|
type HeadingTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'div' | 'span'
|
|
5
6
|
type HeadingSize = '4xl' | '3xl' | '2xl' | 'xl' | 'lg' | 'md'
|
|
6
7
|
|
|
7
8
|
export interface HeadingProps {
|
|
9
|
+
/** Additional CSS classes */
|
|
10
|
+
class?: ClassValue
|
|
8
11
|
/** Semantic HTML tag */
|
|
9
12
|
as?: HeadingTag
|
|
10
13
|
/** Visual hierarchy size */
|
|
@@ -22,6 +25,7 @@ const props = withDefaults(defineProps<HeadingProps>(), {
|
|
|
22
25
|
})
|
|
23
26
|
|
|
24
27
|
const classes = computed(() => [
|
|
28
|
+
props.class,
|
|
25
29
|
'ui-heading',
|
|
26
30
|
`ui-heading--${props.size}`,
|
|
27
31
|
`ui-heading--${props.align}`,
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, h, type Component, type VNode } from 'vue'
|
|
3
|
+
import type { ClassValue } from '../../types/common'
|
|
3
4
|
|
|
4
5
|
type HugeIconData = [string, Record<string, unknown>][]
|
|
5
6
|
|
|
6
7
|
export type IconInput = Component | HugeIconData
|
|
7
8
|
|
|
8
9
|
export interface IconProps {
|
|
10
|
+
/** Additional CSS classes */
|
|
11
|
+
class?: ClassValue
|
|
9
12
|
/** The icon - Vue component OR HugeIcons data array */
|
|
10
13
|
icon: IconInput
|
|
11
14
|
/** Predefined size or custom value */
|
|
@@ -51,7 +54,7 @@ function renderHugeIcon(): VNode {
|
|
|
51
54
|
xmlns: 'http://www.w3.org/2000/svg',
|
|
52
55
|
viewBox: '0 0 24 24',
|
|
53
56
|
fill: 'none',
|
|
54
|
-
class: 'ui-icon',
|
|
57
|
+
class: [props.class, 'ui-icon'],
|
|
55
58
|
style: { '--icon-size': resolvedSize.value },
|
|
56
59
|
'aria-label': props.label,
|
|
57
60
|
'aria-hidden': ariaHidden.value,
|
|
@@ -64,7 +67,7 @@ function renderHugeIcon(): VNode {
|
|
|
64
67
|
<component
|
|
65
68
|
v-if="!isHugeIconData"
|
|
66
69
|
:is="icon"
|
|
67
|
-
class="ui-icon"
|
|
70
|
+
:class="[props.class, 'ui-icon']"
|
|
68
71
|
:style="{ '--icon-size': resolvedSize }"
|
|
69
72
|
:stroke-width="strokeWidth"
|
|
70
73
|
:aria-label="label"
|
|
@@ -4,8 +4,11 @@ import Icon from '../Icon/Icon.vue'
|
|
|
4
4
|
import Spinner from '../Spinner/Spinner.vue'
|
|
5
5
|
import type { IconInput } from '../Icon/Icon.vue'
|
|
6
6
|
import { useId } from '../../composables'
|
|
7
|
+
import type { ClassValue } from '../../types/common'
|
|
7
8
|
|
|
8
9
|
export interface InputProps {
|
|
10
|
+
/** Additional CSS classes */
|
|
11
|
+
class?: ClassValue
|
|
9
12
|
/** Input value (v-model) */
|
|
10
13
|
modelValue?: string | number
|
|
11
14
|
/** Input type */
|
|
@@ -100,8 +103,9 @@ function handleBlur(event: FocusEvent) {
|
|
|
100
103
|
|
|
101
104
|
<template>
|
|
102
105
|
<div
|
|
103
|
-
class="ui-input-field"
|
|
104
106
|
:class="[
|
|
107
|
+
props.class,
|
|
108
|
+
'ui-input-field',
|
|
105
109
|
`ui-input-field--${size}`,
|
|
106
110
|
{
|
|
107
111
|
'ui-input-field--block': block,
|
|
@@ -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 ContainerProps {
|
|
6
|
+
/** Additional CSS classes */
|
|
7
|
+
class?: ClassValue
|
|
5
8
|
/** If true, width is 100%. If false, max-width snaps to breakpoints. */
|
|
6
9
|
fluid?: boolean
|
|
7
10
|
/** Auto margins (mx-auto). Default: true */
|
|
@@ -17,6 +20,7 @@ const props = withDefaults(defineProps<ContainerProps>(), {
|
|
|
17
20
|
})
|
|
18
21
|
|
|
19
22
|
const containerClasses = computed(() => [
|
|
23
|
+
props.class,
|
|
20
24
|
'ui-container',
|
|
21
25
|
{
|
|
22
26
|
'ui-container--fluid': props.fluid,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { computed, provide, toRef } from 'vue'
|
|
3
3
|
import { GridKey } from './keys'
|
|
4
4
|
import type { SpacingToken } from './Stack.vue'
|
|
5
|
+
import type { ClassValue } from '../../types/common'
|
|
5
6
|
|
|
6
7
|
export type ColumnCount = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
|
|
7
8
|
|
|
@@ -14,6 +15,8 @@ export interface ResponsiveColumns {
|
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export interface GridProps {
|
|
18
|
+
/** Additional CSS classes */
|
|
19
|
+
class?: ClassValue
|
|
17
20
|
/** Number of columns (or responsive object) */
|
|
18
21
|
columns?: ColumnCount | ResponsiveColumns
|
|
19
22
|
/** Grid gap using spacing tokens */
|
|
@@ -35,7 +38,7 @@ const props = withDefaults(defineProps<GridProps>(), {
|
|
|
35
38
|
const isResponsive = computed(() => typeof props.columns === 'object')
|
|
36
39
|
|
|
37
40
|
const gridClasses = computed(() => {
|
|
38
|
-
const classes = ['ui-grid']
|
|
41
|
+
const classes: (string | undefined | null | boolean | ClassValue)[] = [props.class, 'ui-grid']
|
|
39
42
|
|
|
40
43
|
if (isResponsive.value) {
|
|
41
44
|
const cols = props.columns as ResponsiveColumns
|
|
@@ -1,5 +1,6 @@
|
|
|
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 SpanCount = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 'full'
|
|
5
6
|
|
|
@@ -12,6 +13,8 @@ export interface ResponsiveSpan {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export interface GridItemProps {
|
|
16
|
+
/** Additional CSS classes */
|
|
17
|
+
class?: ClassValue
|
|
15
18
|
/** Number of columns to span (or responsive object) */
|
|
16
19
|
span?: SpanCount | ResponsiveSpan
|
|
17
20
|
/** Grid column start */
|
|
@@ -32,7 +35,7 @@ const props = withDefaults(defineProps<GridItemProps>(), {
|
|
|
32
35
|
const isResponsive = computed(() => typeof props.span === 'object')
|
|
33
36
|
|
|
34
37
|
const itemClasses = computed(() => {
|
|
35
|
-
const classes = ['ui-grid-item']
|
|
38
|
+
const classes: (string | undefined | null | boolean | ClassValue)[] = [props.class, 'ui-grid-item']
|
|
36
39
|
|
|
37
40
|
if (isResponsive.value) {
|
|
38
41
|
const span = props.span as ResponsiveSpan
|
|
@@ -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 SpacingToken = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12
|
|
5
6
|
|
|
6
7
|
export interface StackProps {
|
|
8
|
+
/** Additional CSS classes */
|
|
9
|
+
class?: ClassValue
|
|
7
10
|
/** Flex direction */
|
|
8
11
|
direction?: 'row' | 'column' | 'row-reverse' | 'column-reverse'
|
|
9
12
|
/** Gap using spacing tokens (maps to var(--space-X)) */
|
|
@@ -31,6 +34,7 @@ const props = withDefaults(defineProps<StackProps>(), {
|
|
|
31
34
|
})
|
|
32
35
|
|
|
33
36
|
const stackClasses = computed(() => [
|
|
37
|
+
props.class,
|
|
34
38
|
'ui-stack',
|
|
35
39
|
`ui-stack--${props.direction}`,
|
|
36
40
|
`ui-stack--align-${props.align}`,
|