@baklavue/ui 1.0.0-preview.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 (83) hide show
  1. package/.releaserc.json +14 -0
  2. package/CHANGELOG.md +40 -0
  3. package/README.md +15 -0
  4. package/index.ts +1 -0
  5. package/package.json +45 -0
  6. package/src/accordion/Accordion.vue +206 -0
  7. package/src/accordion/accordion.types.ts +109 -0
  8. package/src/accordion/index.ts +3 -0
  9. package/src/alert/Alert.vue +199 -0
  10. package/src/alert/alert.types.ts +58 -0
  11. package/src/alert/index.ts +2 -0
  12. package/src/badge/Badge.vue +20 -0
  13. package/src/badge/badge.types.ts +7 -0
  14. package/src/badge/index.ts +2 -0
  15. package/src/button/Button.vue +45 -0
  16. package/src/button/button.types.ts +30 -0
  17. package/src/button/index.ts +3 -0
  18. package/src/checkbox/Checkbox.vue +148 -0
  19. package/src/checkbox/checkbox.types.ts +108 -0
  20. package/src/checkbox/index.ts +2 -0
  21. package/src/datepicker/Datepicker.vue +172 -0
  22. package/src/datepicker/datepicker.types.ts +39 -0
  23. package/src/datepicker/index.ts +2 -0
  24. package/src/dialog/Dialog.vue +178 -0
  25. package/src/dialog/dialog.types.ts +17 -0
  26. package/src/dialog/index.ts +2 -0
  27. package/src/drawer/Drawer.vue +162 -0
  28. package/src/drawer/drawer.types.ts +17 -0
  29. package/src/drawer/index.ts +2 -0
  30. package/src/dropdown/Dropdown.vue +231 -0
  31. package/src/dropdown/dropdown.types.ts +110 -0
  32. package/src/dropdown/index.ts +2 -0
  33. package/src/icon/Icon.vue +102 -0
  34. package/src/icon/icon.types.ts +25 -0
  35. package/src/icon/index.ts +2 -0
  36. package/src/index.ts +37 -0
  37. package/src/input/Input.vue +148 -0
  38. package/src/input/index.ts +3 -0
  39. package/src/input/input.types.ts +156 -0
  40. package/src/link/Link.vue +133 -0
  41. package/src/link/index.ts +2 -0
  42. package/src/link/link.types.ts +42 -0
  43. package/src/notification/Notification.vue +57 -0
  44. package/src/notification/index.ts +2 -0
  45. package/src/notification/notification.types.ts +25 -0
  46. package/src/pagination/Pagination.vue +137 -0
  47. package/src/pagination/index.ts +2 -0
  48. package/src/pagination/pagination.types.ts +61 -0
  49. package/src/radio/Radio.vue +205 -0
  50. package/src/radio/index.ts +2 -0
  51. package/src/radio/radio.types.ts +95 -0
  52. package/src/select/Select.vue +147 -0
  53. package/src/select/index.ts +2 -0
  54. package/src/select/select.types.ts +53 -0
  55. package/src/spinner/Spinner.vue +49 -0
  56. package/src/spinner/index.ts +2 -0
  57. package/src/spinner/spinner.types.ts +11 -0
  58. package/src/split-button/SplitButton.vue +73 -0
  59. package/src/split-button/index.ts +2 -0
  60. package/src/split-button/split-button.types.ts +19 -0
  61. package/src/stepper/Stepper.vue +100 -0
  62. package/src/stepper/index.ts +2 -0
  63. package/src/stepper/stepper.types.ts +29 -0
  64. package/src/switch/Switch.vue +80 -0
  65. package/src/switch/index.ts +2 -0
  66. package/src/switch/switch.types.ts +13 -0
  67. package/src/tab/Tab.vue +99 -0
  68. package/src/tab/index.ts +2 -0
  69. package/src/tab/tab.types.ts +17 -0
  70. package/src/table/Table.vue +264 -0
  71. package/src/table/index.ts +7 -0
  72. package/src/table/table.types.ts +62 -0
  73. package/src/tag/Tag.vue +83 -0
  74. package/src/tag/index.ts +2 -0
  75. package/src/tag/tag.types.ts +24 -0
  76. package/src/textarea/Textarea.vue +84 -0
  77. package/src/textarea/index.ts +2 -0
  78. package/src/textarea/textarea.types.ts +37 -0
  79. package/src/tooltip/Tooltip.vue +81 -0
  80. package/src/tooltip/index.ts +3 -0
  81. package/src/tooltip/tooltip.types.ts +29 -0
  82. package/src/utils/loadBaklavaResources.ts +24 -0
  83. package/tsconfig.json +28 -0
@@ -0,0 +1,133 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Link Component
4
+ *
5
+ * A Vue UI kit component for Baklava's `bl-link` web component for navigation links.
6
+ * Supports inline (text within content) and standalone (button-like) variants with
7
+ * full TypeScript support and HTML anchor attributes (href, target, rel, etc.).
8
+ *
9
+ * @component
10
+ * @example
11
+ * ```vue
12
+ * <!-- Basic usage -->
13
+ * <template>
14
+ * <BvLink href="/about">About</BvLink>
15
+ * </template>
16
+ * ```
17
+ *
18
+ * @example
19
+ * ```vue
20
+ * <!-- Inline variant (default) -->
21
+ * <template>
22
+ * <p>Visit our <BvLink href="/docs">documentation</BvLink> for more info.</p>
23
+ * </template>
24
+ * ```
25
+ *
26
+ * @example
27
+ * ```vue
28
+ * <!-- Standalone variant with size -->
29
+ * <template>
30
+ * <BvLink href="/signup" variant="standalone" size="large">
31
+ * Sign up
32
+ * </BvLink>
33
+ * </template>
34
+ * ```
35
+ *
36
+ * @example
37
+ * ```vue
38
+ * <!-- With icon slot -->
39
+ * <template>
40
+ * <BvLink href="/settings" variant="standalone">
41
+ * <template #icon><BvIcon name="settings" /></template>
42
+ * Settings
43
+ * </BvLink>
44
+ * </template>
45
+ * ```
46
+ *
47
+ * @example
48
+ * ```vue
49
+ * <!-- External link with target -->
50
+ * <template>
51
+ * <BvLink href="https://example.com" target="_blank" rel="noopener noreferrer">
52
+ * External site
53
+ * </BvLink>
54
+ * </template>
55
+ * ```
56
+ *
57
+ * @example
58
+ * ```vue
59
+ * <!-- Disabled state -->
60
+ * <template>
61
+ * <BvLink href="/disabled" :disabled="true">Disabled link</BvLink>
62
+ * </template>
63
+ * ```
64
+ */
65
+ import { computed, onMounted } from "vue";
66
+ import { loadBaklavaResources } from "../utils/loadBaklavaResources";
67
+ import type { LinkProps } from "./link.types";
68
+
69
+ const props = withDefaults(defineProps<LinkProps>(), {
70
+ href: undefined,
71
+ target: undefined,
72
+ disabled: undefined,
73
+ variant: undefined,
74
+ size: undefined,
75
+ kind: undefined,
76
+ ariaLabel: undefined,
77
+ rel: undefined,
78
+ hreflang: undefined,
79
+ type: undefined,
80
+ referrerPolicy: undefined,
81
+ download: undefined,
82
+ ping: undefined,
83
+ });
84
+
85
+ const emit = defineEmits<{
86
+ /** Emitted when the link is clicked. */
87
+ click: [event: CustomEvent];
88
+ }>();
89
+
90
+ /** Props to pass to bl-link. When disabled, omit href so navigation is prevented. */
91
+ const linkBindings = computed(() => {
92
+ const { disabled, href, ...rest } = props;
93
+ return {
94
+ ...rest,
95
+ href: disabled ? undefined : href,
96
+ "aria-disabled": disabled ? "true" : undefined,
97
+ tabindex: disabled ? -1 : undefined,
98
+ };
99
+ });
100
+
101
+ /** Prevents navigation and click when disabled. */
102
+ function handleClick(event: CustomEvent) {
103
+ if (props.disabled) {
104
+ event.preventDefault();
105
+ event.stopPropagation();
106
+ return;
107
+ }
108
+ emit("click", event);
109
+ }
110
+
111
+ onMounted(() => {
112
+ loadBaklavaResources();
113
+ });
114
+ </script>
115
+
116
+ <template>
117
+ <bl-link
118
+ v-bind="linkBindings"
119
+ :class="{ 'bv-link--disabled': disabled }"
120
+ @bl-click="handleClick"
121
+ >
122
+ <slot v-if="$slots['icon']" name="icon" />
123
+ <slot />
124
+ </bl-link>
125
+ </template>
126
+
127
+ <style scoped>
128
+ .bv-link--disabled {
129
+ pointer-events: none;
130
+ opacity: 0.5;
131
+ cursor: not-allowed;
132
+ }
133
+ </style>
@@ -0,0 +1,2 @@
1
+ export { default as BvLink } from "./Link.vue";
2
+ export type { LinkProps, LinkVariant, LinkSize, LinkKind } from "./link.types";
@@ -0,0 +1,42 @@
1
+ /** Link variant - inline (text within content) or standalone (button-like). */
2
+ export type LinkVariant = "inline" | "standalone";
3
+
4
+ /** Link size - only applies to standalone variant. */
5
+ export type LinkSize = "small" | "medium" | "large";
6
+
7
+ /** Link kind - only applies to standalone variant. */
8
+ export type LinkKind = "primary" | "neutral";
9
+
10
+ /**
11
+ * Props for the Link component.
12
+ *
13
+ * @interface LinkProps
14
+ */
15
+ export interface LinkProps {
16
+ /** URL that the hyperlink points to. */
17
+ href?: string;
18
+ /** Where to display the linked URL (e.g. "_self", "_blank"). */
19
+ target?: string;
20
+ /** Whether the link is disabled. */
21
+ disabled?: boolean;
22
+ /** Link variant - inline or standalone. */
23
+ variant?: LinkVariant;
24
+ /** Link size - only applies to standalone variant. */
25
+ size?: LinkSize;
26
+ /** Link kind - only applies to standalone variant. */
27
+ kind?: LinkKind;
28
+ /** Aria label for the link. */
29
+ ariaLabel?: string;
30
+ /** Relationship between the current document and the linked document (e.g. "noopener noreferrer"). */
31
+ rel?: string;
32
+ /** Language of the linked document. */
33
+ hreflang?: string;
34
+ /** MIME type of the linked document. */
35
+ type?: string;
36
+ /** Referrer policy for the link. */
37
+ referrerPolicy?: string;
38
+ /** Whether to download the resource instead of navigating to it. */
39
+ download?: string;
40
+ /** Ping URLs to be notified when following the link. */
41
+ ping?: string;
42
+ }
@@ -0,0 +1,57 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Notification Component
4
+ *
5
+ * A Vue UI kit component for Baklava's `bl-notification` web component for toast notifications.
6
+ * Place this component once in your app (typically at root or layout level). Notifications
7
+ * are triggered programmatically via the `useNotification` composable.
8
+ *
9
+ * @component
10
+ * @example
11
+ * ```vue
12
+ * <!-- Basic usage: place in app root -->
13
+ * <template>
14
+ * <div>
15
+ * <RouterView />
16
+ * <BvNotification />
17
+ * </div>
18
+ * </template>
19
+ * ```
20
+ *
21
+ * @example
22
+ * ```vue
23
+ * <!-- With useNotification composable -->
24
+ * <template>
25
+ * <div>
26
+ * <BvButton @click="showSuccess">Show Success</BvButton>
27
+ * <BvNotification />
28
+ * </div>
29
+ * </template>
30
+ * ```
31
+ */
32
+ import { onMounted } from "vue";
33
+ import { loadBaklavaResources } from "../utils/loadBaklavaResources";
34
+ import type { NotificationProps } from "./notification.types";
35
+
36
+ /**
37
+ * Component props with default values.
38
+ */
39
+ const props = withDefaults(defineProps<NotificationProps>(), {
40
+ duration: 7,
41
+ noAnimation: false,
42
+ });
43
+
44
+ /**
45
+ * Lifecycle hook: Component mounted.
46
+ * Loads Baklava resources required for the web component.
47
+ */
48
+ onMounted(() => {
49
+ loadBaklavaResources();
50
+ });
51
+ </script>
52
+
53
+ <template>
54
+ <bl-notification v-bind="props" />
55
+ </template>
56
+
57
+ <style lang="css" scoped></style>
@@ -0,0 +1,2 @@
1
+ export { default as BvNotification } from "./Notification.vue";
2
+ export type { NotificationProps } from "./notification.types";
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Props for the Notification component.
3
+ *
4
+ * The Notification component is a Vue UI kit component for Baklava's `bl-notification` web component.
5
+ * It acts as a container for toast notifications triggered via the `useNotification` composable.
6
+ *
7
+ * @interface NotificationProps
8
+ */
9
+ export interface NotificationProps {
10
+ /**
11
+ * Default duration of notifications in seconds.
12
+ * Individual notifications can override this via the `useNotification` options.
13
+ *
14
+ * @default 7
15
+ */
16
+ duration?: number;
17
+
18
+ /**
19
+ * Whether to disable animations.
20
+ * Respects user's reduced-motion preferences.
21
+ *
22
+ * @default false
23
+ */
24
+ noAnimation?: boolean;
25
+ }
@@ -0,0 +1,137 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Pagination Component
4
+ *
5
+ * A Vue UI kit component for Baklava's `bl-pagination` web component for page navigation.
6
+ * Supports v-model:currentPage for two-way binding and emits change events when
7
+ * the user navigates to a different page.
8
+ *
9
+ * @component
10
+ * @example
11
+ * ```vue
12
+ * <!-- Basic pagination -->
13
+ * <template>
14
+ * <BvPagination
15
+ * v-model:current-page="currentPage"
16
+ * :total-items="100"
17
+ * :page-size="10"
18
+ * @change="handlePageChange"
19
+ * />
20
+ * </template>
21
+ * ```
22
+ *
23
+ * @example
24
+ * ```vue
25
+ * <!-- With jumper - jump directly to a page -->
26
+ * <template>
27
+ * <BvPagination
28
+ * v-model:current-page="currentPage"
29
+ * :total-items="250"
30
+ * :page-size="25"
31
+ * :has-jumper="true"
32
+ * jumper-label="Go to page"
33
+ * />
34
+ * </template>
35
+ * ```
36
+ *
37
+ * @example
38
+ * ```vue
39
+ * <!-- With items-per-page select -->
40
+ * <template>
41
+ * <BvPagination
42
+ * v-model:current-page="currentPage"
43
+ * :total-items="100"
44
+ * :page-size="10"
45
+ * :has-select="true"
46
+ * select-label="Items per page"
47
+ * :items-per-page-options="[
48
+ * { text: '10 Items', value: 10 },
49
+ * { text: '25 Items', value: 25 },
50
+ * { text: '50 Items', value: 50 }
51
+ * ]"
52
+ * />
53
+ * </template>
54
+ * ```
55
+ */
56
+ import { onMounted } from "vue";
57
+ import { loadBaklavaResources } from "../utils/loadBaklavaResources";
58
+ import type { PaginationProps } from "./pagination.types";
59
+
60
+ /**
61
+ * Component props with default values.
62
+ */
63
+ const props = withDefaults(defineProps<PaginationProps>(), {
64
+ currentPage: undefined,
65
+ totalItems: undefined,
66
+ pageSize: undefined,
67
+ hasJumper: false,
68
+ jumperLabel: undefined,
69
+ hasSelect: false,
70
+ selectLabel: undefined,
71
+ itemsPerPageOptions: undefined,
72
+ });
73
+
74
+ /**
75
+ * Component events.
76
+ */
77
+ const emit = defineEmits<{
78
+ /**
79
+ * Emitted when the current page changes.
80
+ * Use v-model:currentPage for two-way binding.
81
+ *
82
+ * @param {number} page - The new current page number.
83
+ */
84
+ "update:currentPage": [page: number];
85
+
86
+ /**
87
+ * Emitted when the user navigates to a different page.
88
+ * Payload contains selectedPage, prevPage, and itemsPerPage.
89
+ *
90
+ * @param {CustomEvent<{ selectedPage: number; prevPage: number; itemsPerPage: number }>} event - The change event from bl-pagination.
91
+ */
92
+ change: [event: CustomEvent];
93
+ }>();
94
+
95
+ /**
96
+ * Handles the bl-change event from the underlying bl-pagination component.
97
+ * Extracts selectedPage from event.detail and emits update:currentPage and change.
98
+ *
99
+ * @param {CustomEvent} event - The bl-change event from bl-pagination.
100
+ */
101
+ const handleChange = (event: CustomEvent) => {
102
+ emit("change", event);
103
+ const detail = event.detail as
104
+ | { selectedPage?: number; prevPage?: number; itemsPerPage?: number }
105
+ | undefined;
106
+ const page = detail?.selectedPage;
107
+ if (page !== undefined) {
108
+ emit("update:currentPage", page);
109
+ }
110
+ };
111
+
112
+ /**
113
+ * Lifecycle hook: Component mounted.
114
+ * Loads Baklava resources required for bl-pagination.
115
+ */
116
+ onMounted(() => {
117
+ loadBaklavaResources();
118
+ });
119
+ </script>
120
+
121
+ <template>
122
+ <bl-pagination
123
+ v-bind="{
124
+ 'current-page': props.currentPage,
125
+ 'total-items': props.totalItems,
126
+ 'items-per-page': props.pageSize,
127
+ 'has-jumper': props.hasJumper === true ? true : undefined,
128
+ 'jumper-label': props.jumperLabel,
129
+ 'has-select': props.hasSelect === true ? true : undefined,
130
+ 'select-label': props.selectLabel,
131
+ 'items-per-page-options': props.itemsPerPageOptions,
132
+ }"
133
+ @bl-change="handleChange"
134
+ >
135
+ <slot />
136
+ </bl-pagination>
137
+ </template>
@@ -0,0 +1,2 @@
1
+ export { default as BvPagination } from "./Pagination.vue";
2
+ export type { PaginationProps, ItemsPerPageOption } from "./pagination.types";
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Options for the items-per-page select element.
3
+ */
4
+ export interface ItemsPerPageOption {
5
+ /** Display text for the option */
6
+ text: string;
7
+ /** Numeric value for the option */
8
+ value: number;
9
+ }
10
+
11
+ /**
12
+ * Props for the Pagination component.
13
+ * Maps to Baklava's bl-pagination attributes.
14
+ *
15
+ * @see https://github.com/Trendyol/baklava
16
+ */
17
+ export interface PaginationProps {
18
+ /**
19
+ * Current page number (1-based).
20
+ * Supports v-model:currentPage.
21
+ */
22
+ currentPage?: number;
23
+
24
+ /**
25
+ * Total number of items to be paginated.
26
+ * Baklava uses this to compute the total number of pages.
27
+ */
28
+ totalItems?: number;
29
+
30
+ /**
31
+ * Number of items per page.
32
+ * Maps to Baklava's items-per-page attribute.
33
+ */
34
+ pageSize?: number;
35
+
36
+ /**
37
+ * When true, adds a jumper input to jump directly to a page.
38
+ */
39
+ hasJumper?: boolean;
40
+
41
+ /**
42
+ * Label for the jumper input.
43
+ */
44
+ jumperLabel?: string;
45
+
46
+ /**
47
+ * When true, adds a select element to choose items per page.
48
+ */
49
+ hasSelect?: boolean;
50
+
51
+ /**
52
+ * Label for the items-per-page select.
53
+ */
54
+ selectLabel?: string;
55
+
56
+ /**
57
+ * Options for the items-per-page select element.
58
+ * Each option has `text` (display) and `value` (number).
59
+ */
60
+ itemsPerPageOptions?: ItemsPerPageOption[];
61
+ }
@@ -0,0 +1,205 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Radio Component
4
+ *
5
+ * A Vue UI kit component for Baklava's `bl-radio` and `bl-radio-group` web components.
6
+ * Can be used as either a single radio option or as a group container for multiple radios.
7
+ *
8
+ * @component
9
+ * @example
10
+ * ```vue
11
+ * <!-- Single radio in a group -->
12
+ * <template>
13
+ * <bl-radio-group :value="choice" @bl-radio-change="choice = $event.detail">
14
+ * <BvRadio v-model="choice" value="yes" label="Yes" name="choice" />
15
+ * <BvRadio v-model="choice" value="no" label="No" name="choice" />
16
+ * </bl-radio-group>
17
+ * </template>
18
+ * ```
19
+ *
20
+ * @example
21
+ * ```vue
22
+ * <!-- Radio group with items -->
23
+ * <template>
24
+ * <BvRadio v-model="choice" :items="items">
25
+ * <template #item="{ item }">{{ item.label }}</template>
26
+ * </BvRadio>
27
+ * </template>
28
+ * ```
29
+ *
30
+ * @example
31
+ * ```vue
32
+ * <!-- Explicit checked control -->
33
+ * <template>
34
+ * <BvRadio :checked="isSelected" @update:checked="isSelected = $event" label="Option" />
35
+ * </template>
36
+ * ```
37
+ */
38
+ import { computed, onMounted } from "vue";
39
+ import { loadBaklavaResources } from "../utils/loadBaklavaResources";
40
+ import type { RadioProps } from "./radio.types";
41
+
42
+ /**
43
+ * Component props with default values.
44
+ */
45
+ const props = withDefaults(defineProps<RadioProps>(), {
46
+ modelValue: undefined,
47
+ value: undefined,
48
+ name: undefined,
49
+ label: undefined,
50
+ checked: undefined,
51
+ disabled: undefined,
52
+ required: undefined,
53
+ items: undefined,
54
+ });
55
+
56
+ /**
57
+ * Component events.
58
+ */
59
+ const emit = defineEmits<{
60
+ /**
61
+ * Emitted when selection changes (for v-model with modelValue).
62
+ * Payload is this radio's value when it becomes selected (single mode) or the selected value (group mode).
63
+ *
64
+ * @param {string | number} value - The selected value.
65
+ */
66
+ "update:modelValue": [value: string | number];
67
+
68
+ /**
69
+ * Emitted when checked state changes (for explicit checked control).
70
+ *
71
+ * @param {boolean} checked - The new checked state.
72
+ */
73
+ "update:checked": [checked: boolean];
74
+
75
+ /**
76
+ * Emitted when the radio state changes (native bl-change / bl-radio-change event).
77
+ *
78
+ * @param {CustomEvent} event - The change event from bl-radio or bl-radio-group.
79
+ */
80
+ change: [event: CustomEvent];
81
+
82
+ /**
83
+ * Emitted on input (native bl-input event).
84
+ *
85
+ * @param {CustomEvent} event - The bl-input event from bl-radio.
86
+ */
87
+ input: [event: CustomEvent];
88
+ }>();
89
+
90
+ /**
91
+ * Determines if the component should act as a group container.
92
+ * When `items` prop is provided and is an array, it acts as a group.
93
+ */
94
+ const isGroupMode = computed(
95
+ () => props.items !== undefined && Array.isArray(props.items),
96
+ );
97
+
98
+ /**
99
+ * Normalized model value for group mode (string for bl-radio-group).
100
+ */
101
+ const groupValue = computed(() => {
102
+ const val = props.modelValue;
103
+ if (val === undefined || val === null) return "";
104
+ return String(val);
105
+ });
106
+
107
+ /**
108
+ * Computed checked state for bl-radio (single mode).
109
+ * Uses explicit checked prop when provided, otherwise modelValue === value for v-model.
110
+ */
111
+ const computedChecked = computed(() => {
112
+ if (props.checked === true || props.checked === false) {
113
+ return props.checked;
114
+ }
115
+ if (props.modelValue !== undefined && props.value !== undefined) {
116
+ return String(props.modelValue) === String(props.value);
117
+ }
118
+ return undefined;
119
+ });
120
+
121
+ /**
122
+ * Handles the bl-change event from the underlying bl-radio (single mode).
123
+ * Emits update:modelValue with this radio's value when selected, or update:checked.
124
+ */
125
+ const handleSingleChange = (event: CustomEvent) => {
126
+ emit("change", event);
127
+ const target = event.target as { checked?: boolean; value?: string | number };
128
+ const checked = target?.checked;
129
+ if (checked === true && props.value !== undefined) {
130
+ emit("update:modelValue", props.value);
131
+ }
132
+ if (checked === true || checked === false) {
133
+ emit("update:checked", checked);
134
+ }
135
+ };
136
+
137
+ /**
138
+ * Handles the bl-radio-change event from the underlying bl-radio-group (group mode).
139
+ * Emits update:modelValue with the selected value (preserves original type from items).
140
+ */
141
+ const handleGroupChange = (event: CustomEvent) => {
142
+ emit("change", event);
143
+ const detail = event.detail as string | undefined;
144
+ if (detail === undefined || detail === "") return;
145
+ const item = props.items?.find(
146
+ (i) => String(i.value) === String(detail),
147
+ );
148
+ const newValue = item !== undefined ? item.value : detail;
149
+ emit("update:modelValue", newValue);
150
+ };
151
+
152
+ /**
153
+ * Lifecycle hook: Component mounted.
154
+ * Loads Baklava resources for bl-radio and bl-radio-group.
155
+ */
156
+ onMounted(() => {
157
+ loadBaklavaResources();
158
+ });
159
+ </script>
160
+
161
+ <template>
162
+ <!-- Group mode: render as bl-radio-group -->
163
+ <bl-radio-group
164
+ v-if="isGroupMode"
165
+ :value="groupValue"
166
+ :required="props.required === true ? true : undefined"
167
+ :label="props.label"
168
+ @bl-radio-change="handleGroupChange"
169
+ >
170
+ <bl-radio
171
+ v-for="(item, index) in props.items"
172
+ :key="String(item.value)"
173
+ v-bind="{
174
+ value: String(item.value),
175
+ disabled: item.disabled === true ? true : undefined,
176
+ name: item.name ?? props.name,
177
+ }"
178
+ >
179
+ <slot name="item" :item="item" :index="index">
180
+ {{ item.label }}
181
+ </slot>
182
+ </bl-radio>
183
+ </bl-radio-group>
184
+
185
+ <!-- Single radio mode: render as bl-radio -->
186
+ <bl-radio
187
+ v-else
188
+ v-bind="{
189
+ value: props.value !== undefined ? String(props.value) : undefined,
190
+ name: props.name,
191
+ disabled: props.disabled === true ? true : undefined,
192
+ required: props.required === true ? true : undefined,
193
+ checked:
194
+ computedChecked === true
195
+ ? true
196
+ : computedChecked === false
197
+ ? false
198
+ : undefined,
199
+ }"
200
+ @bl-change="handleSingleChange"
201
+ @bl-input="emit('input', $event)"
202
+ >
203
+ <slot>{{ label }}</slot>
204
+ </bl-radio>
205
+ </template>
@@ -0,0 +1,2 @@
1
+ export { default as BvRadio } from "./Radio.vue";
2
+ export type { RadioProps, RadioItem } from "./radio.types";