design-system-next 2.23.0 → 2.24.2

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 (28) hide show
  1. package/dist/design-system-next.es.d.ts +28 -6
  2. package/dist/design-system-next.es.js +7544 -7332
  3. package/dist/design-system-next.es.js.gz +0 -0
  4. package/dist/design-system-next.umd.js +12 -12
  5. package/dist/design-system-next.umd.js.gz +0 -0
  6. package/dist/main.css +1 -1
  7. package/dist/main.css.gz +0 -0
  8. package/package.json +1 -1
  9. package/src/App.vue +89 -1
  10. package/src/components/date-picker/date-picker.vue +2 -2
  11. package/src/components/date-picker/use-date-picker.ts +41 -33
  12. package/src/components/dropdown/dropdown.ts +6 -2
  13. package/src/components/dropdown/dropdown.vue +8 -1
  14. package/src/components/dropdown/use-dropdown.ts +13 -0
  15. package/src/components/list/list-item/list-item.ts +60 -60
  16. package/src/components/radio-grouped/radio-grouped.ts +65 -65
  17. package/src/components/radio-grouped/use-radio-grouped.ts +62 -62
  18. package/src/components/sidepanel/sidepanel.ts +4 -0
  19. package/src/components/sidepanel/sidepanel.vue +3 -1
  20. package/src/components/sidepanel/use-sidepanel.ts +3 -2
  21. package/src/components/table/table-header-dropdown/table-header-dropdown.ts +48 -0
  22. package/src/components/table/table-header-dropdown/table-header-dropdown.vue +84 -0
  23. package/src/components/table/table-pagination/table-pagination.ts +4 -0
  24. package/src/components/table/table-pagination/table-pagination.vue +9 -1
  25. package/src/components/table/table-pagination/use-table-pagination.ts +4 -3
  26. package/src/components/table/table.ts +9 -1
  27. package/src/components/table/table.vue +17 -2
  28. package/src/components/table/use-table.ts +6 -1
package/src/App.vue CHANGED
@@ -1,3 +1,91 @@
1
1
  <template>
2
- <div>Test Component Here</div>
2
+ <div class="spr-h-[600px] spr-w-[75%]">
3
+ <spr-table
4
+ action
5
+ :headers="headers"
6
+ :data-table="data"
7
+ is-multi-select
8
+ :selected-key-id="'name'"
9
+ show-header-filter
10
+ @on-apply-filter="(filters) => console.log(filters)"
11
+ />
12
+ </div>
3
13
  </template>
14
+
15
+ <script setup lang="ts">
16
+ import SprTable from './components/table/table.vue';
17
+ import { ref } from 'vue';
18
+ import { Header } from './components/table/table';
19
+
20
+ const headers = ref<Header[]>([
21
+ { field: 'name', name: 'Role Name', sort: false, hasAvatar: true, hasSubtext: true, width: '250px',
22
+ filterList: [
23
+ { text: 'Role 11', value: 'role11' },
24
+ { text: 'Role 12', value: 'role12' },
25
+ { text: 'Role 13', value: 'role13' },
26
+ { text: 'Role 14', value: 'role14' },
27
+ { text: 'Role 15', value: 'role15' }
28
+ ]
29
+ },
30
+ { field: 'firstUpdate', name: 'Date', sort: false, hasAvatar: false, hasSubtext: false, width: '150px',
31
+ filterList: [
32
+ { text: 'Jan 10, 2025', value: 'jan10' },
33
+ { text: 'Jan 11, 2025', value: 'jan11' },
34
+ { text: 'Jan 12, 2025', value: 'jan12' },
35
+ { text: 'Jan 13, 2025', value: 'jan13' },
36
+ { text: 'Jan 14, 2025', value: 'jan14' }
37
+ ]
38
+ },
39
+ { field: 'lastUpdate', name: 'Date', sort: false, hasAvatar: false, hasSubtext: false, width: '150px',
40
+ filterList: [
41
+ { text: 'Dec 10, 2025', value: 'dec10' },
42
+ { text: 'Dec 11, 2025', value: 'dec11' },
43
+ { text: 'Dec 12, 2025', value: 'dec12' },
44
+ { text: 'Dec 13, 2025', value: 'dec13' },
45
+ { text: 'Dec 14, 2025', value: 'dec14' }
46
+ ]
47
+ },
48
+ { field: 'note', name: 'Note', sort: false, hasAvatar: false, hasSubtext: true, width: '300px',
49
+ filterList: [
50
+ { text: 'Note 11', value: 'note11' },
51
+ { text: 'Note 12', value: 'note12' },
52
+ { text: 'Note 13', value: 'note13' },
53
+ { text: 'Note 14', value: 'note14' },
54
+ { text: 'Note 15', value: 'note15' }
55
+ ]
56
+ },
57
+ { field: 'status', name: 'Status', sort: false, hasAvatar: false, hasSubtext: true, width: '200px',
58
+ filterList: [
59
+ { text: 'Success', value: 'success' },
60
+ { text: 'Pending', value: 'pending' },
61
+ { text: 'Error', value: 'error' }
62
+ ]
63
+ },
64
+ ]);
65
+
66
+ const data = ref([
67
+ // 40 more elements
68
+ ...Array.from({ length: 50 }, (_, i) => ({
69
+ name: {
70
+ title: `Role ${i + 11}`,
71
+ subtext: `Subtext for role ${i + 11}`,
72
+ },
73
+ firstUpdate: {
74
+ title: `Jan ${10 + i}, 2025`,
75
+ subtext: `Subtext for date ${10 + i}`,
76
+ },
77
+ lastUpdate: {
78
+ title: `Dec ${10 + i}, 2025`,
79
+ subtext: `Subtext for date ${10 + i}`,
80
+ },
81
+ note: {
82
+ title: `Note ${i + 11}`,
83
+ subtext: `Subtext for role ${i + 11}`,
84
+ },
85
+ status: {
86
+ title: ['Success', 'Pending', 'Error'][(i + 1) % 3],
87
+ subtext: `Status subtext ${i + 11}`,
88
+ },
89
+ })),
90
+ ]);
91
+ </script>
@@ -7,7 +7,7 @@
7
7
  :placement="props.placement"
8
8
  :triggers="[]"
9
9
  :popper-hide-triggers="[]"
10
- :auto-hide="false"
10
+ :auto-hide="true"
11
11
  :disabled="isDatePickerPopperDisabled"
12
12
  :container="props.popperContainer ? props.popperContainer : `#${props.id}`"
13
13
  :strategy="
@@ -26,7 +26,7 @@
26
26
  <slot :handle-click="handleSlotClick">
27
27
  <div
28
28
  ref="datePickerRef"
29
- :class="datePickerClasses.datePickerBaseInputClasses"
29
+ :class="[datePickerClasses.datePickerBaseInputClasses, 'spr-relative spr-z-10']"
30
30
  @click="datePopperState = true"
31
31
  >
32
32
  <div class="spr-flex spr-h-full spr-items-center spr-gap-1.5">
@@ -494,6 +494,7 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
494
494
  handleConvertMonthIfValid();
495
495
  calendarTabUpdateCalendar();
496
496
  emitDateFormats();
497
+ emitPartialInputValue();
497
498
 
498
499
  datePickerErrors.value = [];
499
500
 
@@ -563,6 +564,7 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
563
564
  handleConvertMonthIfValid();
564
565
  calendarTabUpdateCalendar();
565
566
  emitDateFormats();
567
+ emitPartialInputValue();
566
568
 
567
569
  datePickerErrors.value = [];
568
570
 
@@ -696,14 +698,8 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
696
698
 
697
699
  handleValidateDate();
698
700
 
699
- // Do not set yearInput when typing monthInput
700
- if (!monthInput.value && !dateInput.value && !yearInput.value) {
701
- emit('getInputValue', null);
702
- }
703
-
704
- if (monthInput.value && dateInput.value && yearInput.value) {
705
- emitInputValue();
706
- }
701
+ // Emit the partial date value as user types
702
+ emitPartialInputValue();
707
703
  };
708
704
 
709
705
  const handleDateInput = () => {
@@ -717,14 +713,8 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
717
713
 
718
714
  handleValidateDate();
719
715
 
720
- // Do not set yearInput when typing dateInput
721
- if (!monthInput.value && !dateInput.value && !yearInput.value) {
722
- emit('getInputValue', null);
723
- }
724
-
725
- if (monthInput.value && dateInput.value && yearInput.value) {
726
- emitInputValue();
727
- }
716
+ // Emit the partial date value as user types
717
+ emitPartialInputValue();
728
718
  };
729
719
 
730
720
  const handleYearInput = () => {
@@ -736,20 +726,8 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
736
726
 
737
727
  emit('getDateErrors', datePickerErrors.value);
738
728
 
739
- // Only validate year, do not set monthInput or dateInput
740
- // Only emit year-related changes
741
- // Only validate if yearInput is 4 digits (full year)
742
- if (yearInput.value.length === 4) {
743
- handleValidateDate();
744
-
745
- if (!monthInput.value && !dateInput.value && !yearInput.value) {
746
- emit('getInputValue', null);
747
- }
748
-
749
- if (monthInput.value && dateInput.value && yearInput.value) {
750
- emitInputValue();
751
- }
752
- }
729
+ // Emit the partial date value as user types
730
+ emitPartialInputValue();
753
731
  };
754
732
 
755
733
  const handleConvertMonthIfValid = () => {
@@ -846,6 +824,36 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
846
824
  }
847
825
  };
848
826
 
827
+ const emitPartialInputValue = () => {
828
+ // Convert month to numeric format if it's text
829
+ let emittedMonth = monthInput.value;
830
+
831
+ if (monthInput.value) {
832
+ const isNumeric = !isNaN(Number(monthInput.value)) && !isNaN(parseFloat(monthInput.value));
833
+
834
+ if (!isNumeric) {
835
+ const monthIsValid = monthsList.value.find(
836
+ (_month: MonthsList) => _month.text.toLowerCase() === monthInput.value.toLowerCase(),
837
+ );
838
+
839
+ if (monthIsValid) {
840
+ emittedMonth =
841
+ monthIsValid.monthValue < 10 ? `0${monthIsValid.monthValue + 1}` : `${monthIsValid.monthValue + 1}`;
842
+ }
843
+ }
844
+ }
845
+
846
+ // Build the partial date string with zeros for empty fields
847
+ const partialMonth = emittedMonth || '0';
848
+ const partialDate = dateInput.value || '0';
849
+ const partialYear = yearInput.value || '0';
850
+
851
+ const partialDateString = `${partialMonth}-${partialDate}-${partialYear}`;
852
+
853
+ // Emit the partial date string
854
+ emit('getInputValue', partialDateString);
855
+ };
856
+
849
857
  const emitDateFormats = () => {
850
858
  if (monthInput.value && dateInput.value && yearInput.value) {
851
859
  const monthIsValid = monthsList.value.find(
@@ -934,8 +942,8 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
934
942
  };
935
943
 
936
944
  const handleSlotClick = () => {
937
- if(disabled.value || readonly.value) return;
938
- datePopperState.value = true;
945
+ if (disabled.value || readonly.value) return;
946
+ datePopperState.value = true;
939
947
  };
940
948
 
941
949
  watch(datePopperState, (newValue) => {
@@ -1037,6 +1045,6 @@ export const useDatePicker = (props: DatePickerPropTypes, emit: SetupContext<Dat
1037
1045
  handleTabClick,
1038
1046
  handleBackspace,
1039
1047
  clearDate,
1040
- handleSlotClick
1048
+ handleSlotClick,
1041
1049
  };
1042
1050
  };
@@ -141,13 +141,17 @@ export const dropdownPropTypes = {
141
141
  type: Boolean,
142
142
  default: false,
143
143
  },
144
+ noPadding: {
145
+ type: Boolean,
146
+ default: false,
147
+ }
144
148
  };
145
149
 
146
150
  export const dropdownEmitTypes = {
147
- 'infinite-scroll-trigger': Boolean,
151
+ 'infinite-scroll-trigger': (value: boolean) => typeof value === 'boolean',
148
152
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
149
153
  'update:modelValue': (_value: unknown) => true, // Accept any type of value
150
- 'popper-state': Boolean,
154
+ 'popper-state': (state: boolean) => typeof state === 'boolean',
151
155
  };
152
156
 
153
157
  export type DropdownPropTypes = ExtractPropTypes<typeof dropdownPropTypes>;
@@ -32,7 +32,7 @@
32
32
  <template #popper>
33
33
  <template v-if="$slots.popper">
34
34
  <div
35
- class="spr-overflow-y-auto spr-overflow-x-hidden spr-p-4"
35
+ :class="['spr-overflow-y-auto spr-overflow-x-hidden', !props.noPadding && 'spr-p-4']"
36
36
  :style="{
37
37
  width: props.popperInnerWidth,
38
38
  }"
@@ -111,5 +111,12 @@ const {
111
111
  dropdownValue,
112
112
  removeCurrentLevelInBackLabel,
113
113
  isLadderizedSearch,
114
+ showDropdown,
115
+ hideDropdown,
114
116
  } = useDropdown(props, emit);
117
+
118
+ defineExpose({
119
+ showDropdown,
120
+ hideDropdown,
121
+ });
115
122
  </script>
@@ -82,6 +82,17 @@ export const useDropdown = (props: DropdownPropTypes, emit: SetupContext<Dropdow
82
82
  const dropdownPopperState = ref<boolean>(false);
83
83
  const isDropdownPopperDisabled = computed(() => disabled.value);
84
84
 
85
+ // Exposed methods to show/hide dropdown. This is for custom trigger handling for custom dropdown.
86
+ // To use these methods, set :triggers="[]" on the SprDropdown component to disable default triggers. (reference: https://floating-vue.starpad.dev/api/#shown)
87
+ /* #region - Exposed Methods */
88
+ const showDropdown = () => {
89
+ dropdownPopperState.value = true;
90
+ };
91
+ const hideDropdown = () => {
92
+ dropdownPopperState.value = false;
93
+ };
94
+ /* #endregion - Exposed Methods */
95
+
85
96
  const isLadderizedSearch = computed(
86
97
  () => ladderized.value && searchString.value !== '' && normalizedValue.value.length === 0,
87
98
  );
@@ -503,5 +514,7 @@ export const useDropdown = (props: DropdownPropTypes, emit: SetupContext<Dropdow
503
514
  dropdownValue: compatPreSelectedItems, // Use compatible format for lists
504
515
  removeCurrentLevelInBackLabel,
505
516
  isLadderizedSearch,
517
+ showDropdown,
518
+ hideDropdown,
506
519
  };
507
520
  };
@@ -1,60 +1,60 @@
1
- import type { PropType, ExtractPropTypes } from 'vue';
2
- import type { MenuListType } from '../list';
3
-
4
- export const listItemPropTypes = {
5
- item: {
6
- type: Object as PropType<MenuListType>,
7
- required: true,
8
- },
9
- isSelected: {
10
- type: Boolean,
11
- required: true,
12
- },
13
- classes: {
14
- type: [String, Array, Object] as PropType<string | string[] | Record<string, boolean>>,
15
- required: true,
16
- },
17
- multiSelect: {
18
- type: Boolean,
19
- default: false,
20
- },
21
- lozenge: {
22
- type: Boolean,
23
- default: false,
24
- },
25
- ladderized: {
26
- type: Boolean,
27
- default: false,
28
- },
29
- noCheck: {
30
- type: Boolean,
31
- default: false,
32
- },
33
- itemIcon: {
34
- type: String,
35
- default: '',
36
- },
37
- itemIconTone: {
38
- type: String,
39
- default: 'plain',
40
- },
41
- itemIconFill: {
42
- type: Boolean,
43
- default: false,
44
- },
45
- disabledUnselectedItems: {
46
- type: Boolean,
47
- default: false,
48
- },
49
- radioList: {
50
- type: Boolean,
51
- default: false,
52
- },
53
- };
54
-
55
- export const listItemEmitTypes = {
56
- select: () => true,
57
- };
58
-
59
- export type ListItemPropTypes = ExtractPropTypes<typeof listItemPropTypes>;
60
- export type ListItemEmitTypes = typeof listItemEmitTypes;
1
+ import type { PropType, ExtractPropTypes } from 'vue';
2
+ import type { MenuListType } from '../list';
3
+
4
+ export const listItemPropTypes = {
5
+ item: {
6
+ type: Object as PropType<MenuListType>,
7
+ required: true,
8
+ },
9
+ isSelected: {
10
+ type: Boolean,
11
+ required: true,
12
+ },
13
+ classes: {
14
+ type: [String, Array, Object] as PropType<string | string[] | Record<string, boolean>>,
15
+ required: true,
16
+ },
17
+ multiSelect: {
18
+ type: Boolean,
19
+ default: false,
20
+ },
21
+ lozenge: {
22
+ type: Boolean,
23
+ default: false,
24
+ },
25
+ ladderized: {
26
+ type: Boolean,
27
+ default: false,
28
+ },
29
+ noCheck: {
30
+ type: Boolean,
31
+ default: false,
32
+ },
33
+ itemIcon: {
34
+ type: String,
35
+ default: '',
36
+ },
37
+ itemIconTone: {
38
+ type: String,
39
+ default: 'plain',
40
+ },
41
+ itemIconFill: {
42
+ type: Boolean,
43
+ default: false,
44
+ },
45
+ disabledUnselectedItems: {
46
+ type: Boolean,
47
+ default: false,
48
+ },
49
+ radioList: {
50
+ type: Boolean,
51
+ default: false,
52
+ },
53
+ };
54
+
55
+ export const listItemEmitTypes = {
56
+ select: () => true,
57
+ };
58
+
59
+ export type ListItemPropTypes = ExtractPropTypes<typeof listItemPropTypes>;
60
+ export type ListItemEmitTypes = typeof listItemEmitTypes;
@@ -1,65 +1,65 @@
1
- import type { PropType, ExtractPropTypes } from 'vue';
2
-
3
- export const definePropType = <T>(val: unknown): PropType<T> => val as PropType<T>;
4
-
5
- export interface RadioOption {
6
- text: string;
7
- value: string | number | boolean;
8
- disabled?: boolean;
9
- }
10
-
11
- export const radioGroupedPropTypes = {
12
- id: {
13
- type: String,
14
- required: true,
15
- },
16
- modelValue: {
17
- type: [String, Number, Boolean],
18
- },
19
- name: {
20
- type: String,
21
- required: true,
22
- },
23
- options: {
24
- type: Array as PropType<RadioOption[]>,
25
- required: true,
26
- default: () => [],
27
- },
28
- disabled: {
29
- type: Boolean,
30
- default: false,
31
- },
32
- description: {
33
- type: String,
34
- },
35
- bordered: {
36
- type: Boolean,
37
- default: false,
38
- },
39
- displayHelper: {
40
- type: Boolean,
41
- default: false,
42
- },
43
- helperIcon: {
44
- type: String,
45
- default: null,
46
- },
47
- helperText: {
48
- type: String,
49
- default: '',
50
- },
51
- error: {
52
- type: Boolean,
53
- default: false,
54
- },
55
- horizontalAlign: {
56
- type: String as PropType<'left' | 'center' | 'right'>,
57
- default: 'left',
58
- },
59
- };
60
-
61
- export const radioGroupedEmitTypes = ['update:modelValue'];
62
-
63
- export type RadioGroupedPropTypes = ExtractPropTypes<typeof radioGroupedPropTypes>;
64
-
65
- export type RadioGroupedEmitTypes = typeof radioGroupedEmitTypes;
1
+ import type { PropType, ExtractPropTypes } from 'vue';
2
+
3
+ export const definePropType = <T>(val: unknown): PropType<T> => val as PropType<T>;
4
+
5
+ export interface RadioOption {
6
+ text: string;
7
+ value: string | number | boolean;
8
+ disabled?: boolean;
9
+ }
10
+
11
+ export const radioGroupedPropTypes = {
12
+ id: {
13
+ type: String,
14
+ required: true,
15
+ },
16
+ modelValue: {
17
+ type: [String, Number, Boolean],
18
+ },
19
+ name: {
20
+ type: String,
21
+ required: true,
22
+ },
23
+ options: {
24
+ type: Array as PropType<RadioOption[]>,
25
+ required: true,
26
+ default: () => [],
27
+ },
28
+ disabled: {
29
+ type: Boolean,
30
+ default: false,
31
+ },
32
+ description: {
33
+ type: String,
34
+ },
35
+ bordered: {
36
+ type: Boolean,
37
+ default: false,
38
+ },
39
+ displayHelper: {
40
+ type: Boolean,
41
+ default: false,
42
+ },
43
+ helperIcon: {
44
+ type: String,
45
+ default: null,
46
+ },
47
+ helperText: {
48
+ type: String,
49
+ default: '',
50
+ },
51
+ error: {
52
+ type: Boolean,
53
+ default: false,
54
+ },
55
+ horizontalAlign: {
56
+ type: String as PropType<'left' | 'center' | 'right'>,
57
+ default: 'left',
58
+ },
59
+ };
60
+
61
+ export const radioGroupedEmitTypes = ['update:modelValue'];
62
+
63
+ export type RadioGroupedPropTypes = ExtractPropTypes<typeof radioGroupedPropTypes>;
64
+
65
+ export type RadioGroupedEmitTypes = typeof radioGroupedEmitTypes;
@@ -1,62 +1,62 @@
1
- import { toRefs, computed, ComputedRef } from 'vue';
2
- import { useVModel } from '@vueuse/core';
3
-
4
- import classNames from 'classnames';
5
-
6
- import type { SetupContext } from 'vue';
7
- import type { RadioGroupedPropTypes, RadioGroupedEmitTypes, RadioOption } from './radio-grouped';
8
-
9
- interface RadioGroupedClasses {
10
- containerClasses: string;
11
- helperClasses: string;
12
- }
13
-
14
- export const useRadioGrouped = (props: RadioGroupedPropTypes, emit: SetupContext<RadioGroupedEmitTypes>['emit']) => {
15
- const { disabled, horizontalAlign, displayHelper, error } = toRefs(props);
16
-
17
- const radioGroupedClasses: ComputedRef<RadioGroupedClasses> = computed(() => {
18
- const alignmentMap = {
19
- left: 'spr-justify-start',
20
- center: 'spr-justify-center',
21
- right: 'spr-justify-end',
22
- };
23
-
24
- const containerClasses = classNames('spr-flex spr-flex-col spr-gap-2', {
25
- [alignmentMap[horizontalAlign.value as keyof typeof alignmentMap]]: true,
26
- });
27
-
28
- const helperClasses = classNames(
29
- 'spr-flex spr-items-center spr-gap-1 spr-mt-size-spacing-2xs spr-body-sm-regular',
30
- {
31
- 'spr-text-mushroom-600': !error.value,
32
- 'spr-text-color-danger-base': error.value,
33
- },
34
- );
35
-
36
- return {
37
- containerClasses,
38
- helperClasses,
39
- };
40
- });
41
-
42
- const proxyValue = useVModel(props, 'modelValue', emit);
43
-
44
- const renderOptions = (): RadioOption[] => {
45
- return props.options || [];
46
- };
47
-
48
- const isOptionDisabled = (option: RadioOption): boolean => {
49
- return disabled.value || (option.disabled ?? false);
50
- };
51
-
52
- return {
53
- radioGroupedClasses,
54
- proxyValue,
55
- renderOptions,
56
- isOptionDisabled,
57
- disabled,
58
- displayHelper,
59
- horizontalAlign,
60
- error,
61
- };
62
- };
1
+ import { toRefs, computed, ComputedRef } from 'vue';
2
+ import { useVModel } from '@vueuse/core';
3
+
4
+ import classNames from 'classnames';
5
+
6
+ import type { SetupContext } from 'vue';
7
+ import type { RadioGroupedPropTypes, RadioGroupedEmitTypes, RadioOption } from './radio-grouped';
8
+
9
+ interface RadioGroupedClasses {
10
+ containerClasses: string;
11
+ helperClasses: string;
12
+ }
13
+
14
+ export const useRadioGrouped = (props: RadioGroupedPropTypes, emit: SetupContext<RadioGroupedEmitTypes>['emit']) => {
15
+ const { disabled, horizontalAlign, displayHelper, error } = toRefs(props);
16
+
17
+ const radioGroupedClasses: ComputedRef<RadioGroupedClasses> = computed(() => {
18
+ const alignmentMap = {
19
+ left: 'spr-justify-start',
20
+ center: 'spr-justify-center',
21
+ right: 'spr-justify-end',
22
+ };
23
+
24
+ const containerClasses = classNames('spr-flex spr-flex-col spr-gap-2', {
25
+ [alignmentMap[horizontalAlign.value as keyof typeof alignmentMap]]: true,
26
+ });
27
+
28
+ const helperClasses = classNames(
29
+ 'spr-flex spr-items-center spr-gap-1 spr-mt-size-spacing-2xs spr-body-sm-regular',
30
+ {
31
+ 'spr-text-mushroom-600': !error.value,
32
+ 'spr-text-color-danger-base': error.value,
33
+ },
34
+ );
35
+
36
+ return {
37
+ containerClasses,
38
+ helperClasses,
39
+ };
40
+ });
41
+
42
+ const proxyValue = useVModel(props, 'modelValue', emit);
43
+
44
+ const renderOptions = (): RadioOption[] => {
45
+ return props.options || [];
46
+ };
47
+
48
+ const isOptionDisabled = (option: RadioOption): boolean => {
49
+ return disabled.value || (option.disabled ?? false);
50
+ };
51
+
52
+ return {
53
+ radioGroupedClasses,
54
+ proxyValue,
55
+ renderOptions,
56
+ isOptionDisabled,
57
+ disabled,
58
+ displayHelper,
59
+ horizontalAlign,
60
+ error,
61
+ };
62
+ };