vueless 0.0.14 → 0.0.16

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 (40) hide show
  1. package/package.json +1 -1
  2. package/ui.button/index.vue +16 -3
  3. package/ui.button-link/index.vue +6 -3
  4. package/ui.container-page/configs/default.config.js +1 -1
  5. package/ui.data-table/index.vue +1 -1
  6. package/ui.data-table-cell/configs/default.config.js +2 -2
  7. package/ui.dropdown-badge/index.vue +11 -1
  8. package/ui.dropdown-button/index.vue +14 -2
  9. package/ui.dropdown-link/index.vue +11 -1
  10. package/ui.form-calendar/configs/default.config.js +1 -1
  11. package/ui.form-checkbox/index.vue +1 -1
  12. package/ui.form-color-picker/index.vue +1 -1
  13. package/ui.form-date-picker-range/configs/default.config.js +4 -4
  14. package/ui.form-input/configs/default.config.js +1 -1
  15. package/ui.form-input/index.vue +5 -8
  16. package/ui.form-input-file/configs/default.config.js +1 -1
  17. package/ui.form-input-file/index.vue +4 -8
  18. package/ui.form-input-rating/configs/default.config.js +1 -1
  19. package/ui.form-input-rating/index.vue +3 -7
  20. package/ui.form-label/configs/default.config.js +2 -0
  21. package/ui.form-label/index.vue +3 -3
  22. package/ui.form-radio/index.vue +5 -3
  23. package/ui.form-radio-card/composables/attrs.composable.js +3 -1
  24. package/ui.form-radio-card/configs/default.config.js +8 -2
  25. package/ui.form-radio-card/index.vue +26 -40
  26. package/ui.form-select/configs/default.config.js +3 -3
  27. package/ui.form-select/index.vue +7 -18
  28. package/ui.form-switch/index.vue +1 -1
  29. package/ui.form-textarea/index.vue +2 -2
  30. package/ui.notify/index.vue +3 -3
  31. package/ui.other-loader-top/composables/attrs.composable.js +32 -0
  32. package/ui.other-loader-top/configs/default.config.js +20 -0
  33. package/ui.other-loader-top/constants/index.js +8 -0
  34. package/ui.other-loader-top/index.vue +230 -0
  35. package/ui.other-loader-top/services/loaderTop.service.js +31 -0
  36. package/ui.text-badge/index.vue +7 -0
  37. package/web-types.json +36 -132
  38. package/ui.loader-top/components/TopProgress.vue +0 -277
  39. package/ui.loader-top/index.vue +0 -221
  40. /package/{ui.loader-top → ui.other-loader-top}/store/index.js +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueless",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "license": "MIT",
5
5
  "description": "Vue Styleless Component Framework.",
6
6
  "homepage": "https://vueless.com",
@@ -1,5 +1,12 @@
1
1
  <template>
2
- <button :id="id" :disabled="disabled" :data-cy="dataCy" v-bind="buttonAttrs" @click="onClick">
2
+ <button
3
+ :id="id"
4
+ ref="buttonRef"
5
+ :disabled="disabled"
6
+ :data-cy="dataCy"
7
+ v-bind="buttonAttrs"
8
+ @click="onClick"
9
+ >
3
10
  <!-- @slot Use it to add something before text. -->
4
11
  <slot v-if="!loading" name="left" />
5
12
 
@@ -16,11 +23,13 @@
16
23
  </template>
17
24
 
18
25
  <script setup>
19
- import ULoader from "../ui.other-loader";
26
+ import { ref } from "vue";
27
+
20
28
  import UIService, { getRandomId } from "../service.ui";
29
+ import ULoader from "../ui.other-loader";
21
30
 
22
- import { useAttrs } from "./composables/attrs.composable";
23
31
  import defaultConfig from "./configs/default.config";
32
+ import { useAttrs } from "./composables/attrs.composable";
24
33
  import { UButton } from "./constants";
25
34
 
26
35
  /* Should be a string for correct web-types gen */
@@ -140,6 +149,10 @@ const emit = defineEmits(["click"]);
140
149
 
141
150
  const { textAttrs, buttonAttrs } = useAttrs(props);
142
151
 
152
+ const buttonRef = ref(null);
153
+
154
+ defineExpose({ buttonRef });
155
+
143
156
  function onClick(event) {
144
157
  if (props.disabled) return;
145
158
 
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div tabindex="-1" v-bind="wrapperAttrs">
2
+ <div v-bind="wrapperAttrs" ref="wrapperRef" tabindex="-1">
3
3
  <div v-if="hasSlotContent(slots['left'])" v-bind="leftSlotAttrs">
4
4
  <!-- @slot Use it to add something before text. -->
5
5
  <slot name="left" />
@@ -49,8 +49,7 @@
49
49
  </template>
50
50
 
51
51
  <script setup>
52
- import { computed, useSlots } from "vue";
53
-
52
+ import { computed, useSlots, ref } from "vue";
54
53
  import UIService from "../service.ui";
55
54
 
56
55
  import { useAttrs } from "./composables/attrs.composable";
@@ -181,6 +180,10 @@ const props = defineProps({
181
180
 
182
181
  const slots = useSlots();
183
182
 
183
+ const wrapperRef = ref(null);
184
+
185
+ defineExpose({ wrapperRef });
186
+
184
187
  const { wrapperAttrs, linkAttrs, rightSlotAttrs, leftSlotAttrs, textAttrs, hasSlotContent } =
185
188
  useAttrs(props);
186
189
 
@@ -2,7 +2,7 @@ export default /*tw*/ {
2
2
  htmlBody: "bg-gray-50 group/body-gray",
3
3
  wrapperMobile: "overflow-x-hidden mb-[theme('spacing.mobile-menu-height')]",
4
4
  wrapper: {
5
- base: "min-h-screen overflow-auto",
5
+ base: "min-h-screen overflow-auto UNotifyPage",
6
6
  variants: {
7
7
  width: {
8
8
  xs: "md:w-[25rem] md:max-[500px]:!w-full",
@@ -277,7 +277,7 @@ import UIcon from "../ui.image-icon";
277
277
  import UEmpty from "../ui.text-empty";
278
278
  import UDivider from "../ui.container-divider";
279
279
  import UCheckbox from "../ui.form-checkbox";
280
- import ULoaderTop from "../ui.loader-top";
280
+ import ULoaderTop from "../ui.other-loader-top";
281
281
  import UTableCell from "../ui.data-table-cell";
282
282
 
283
283
  import UIService from "../service.ui";
@@ -1,13 +1,13 @@
1
1
  export default /*tw*/ {
2
2
  tableCell: {
3
3
  base: `
4
- p-[1.125rem] py-5 first:p-5 [&:nth-child(2)]:pl-0 group-[]/body:truncate group-[]/body:align-top
4
+ p-[1.125rem] py-5 first:p-5 [&:nth-child(2)]:pl-0 group-[]/body:truncate group-[]/body:align-top
5
5
  group-[]/body:last:p-5
6
6
  `,
7
7
  variants: {
8
8
  compact: {
9
9
  true: `
10
- group-[]/body:px-4 group-[]/body:py-3 group-[]/body:last:px-4 group-[]/body:last:py-3
10
+ group-[]/body:px-4 group-[]/body:py-3 group-[]/body:last:px-4 group-[]/body:last:py-3
11
11
  group-[]/body:first:px-4 group-[]/body:first:py-3 group-[]/footer:p-4:
12
12
  `,
13
13
  },
@@ -2,6 +2,7 @@
2
2
  <div v-bind="wrapperAttrs">
3
3
  <UBadge
4
4
  :id="id"
5
+ ref="badgeRef"
5
6
  :label="label"
6
7
  :size="size"
7
8
  :color="color"
@@ -10,6 +11,7 @@
10
11
  :data-cy="`${dataCy}-badge`"
11
12
  v-bind="badgeAttrs"
12
13
  @click.stop="onClickBadge"
14
+ @blur="onBlurBadge"
13
15
  >
14
16
  <template #right>
15
17
  <UIcon
@@ -192,6 +194,8 @@ const emit = defineEmits(["update:modelValue"]);
192
194
 
193
195
  const isShownOptions = ref(false);
194
196
 
197
+ const badgeRef = ref(null);
198
+
195
199
  const { config, listWrapperAttrs, wrapperAttrs, badgeAttrs, listAttrs, iconAttrs, hasSlotContent } =
196
200
  useAttrs(props, { isShownOptions });
197
201
 
@@ -227,7 +231,13 @@ function hideOptions() {
227
231
  }
228
232
 
229
233
  function onClickOutside(event) {
230
- if (!document.getElementById(props.id)?.contains(event.target)) {
234
+ if (!badgeRef.value?.wrapperRef?.contains(event.target)) {
235
+ hideOptions();
236
+ }
237
+ }
238
+
239
+ function onBlurBadge(event) {
240
+ if (!event.target.isEqualNode(event.relatedTarget) && event.relatedTarget) {
231
241
  hideOptions();
232
242
  }
233
243
  }
@@ -2,6 +2,7 @@
2
2
  <div v-bind="wrapperAttrs">
3
3
  <UButton
4
4
  :id="id"
5
+ ref="buttonRef"
5
6
  :label="label"
6
7
  :size="size"
7
8
  :variant="variant"
@@ -13,6 +14,7 @@
13
14
  :data-cy="`${dataCy}-button`"
14
15
  v-bind="buttonAttrs"
15
16
  @click.stop="onClickButton"
17
+ @blur="onBlurButton"
16
18
  >
17
19
  <template #right>
18
20
  <UIcon
@@ -39,7 +41,10 @@
39
41
  :value-key="valueKey"
40
42
  :label-key="labelKey"
41
43
  :data-cy="`${dataCy}-item`"
44
+ tabindex="-1"
42
45
  v-bind="listAttrs"
46
+ @mousedown.stop
47
+ @click.stop
43
48
  />
44
49
  </div>
45
50
  </template>
@@ -54,8 +59,8 @@ import UDropdownList from "../ui.dropdown-list";
54
59
  import UIService, { getRandomId } from "../service.ui";
55
60
 
56
61
  import defaultConfig from "./configs/default.config";
57
- import { UDropdownButton, BUTTON_VARIANT } from "./constants";
58
62
  import { useAttrs } from "./composables/attrs.composable";
63
+ import { UDropdownButton, BUTTON_VARIANT } from "./constants";
59
64
 
60
65
  /* Should be a string for correct web-types gen */
61
66
  defineOptions({ name: "UDropdownButton", inheritAttrs: false });
@@ -217,6 +222,7 @@ provide("hideDropdownOptions", () => hideOptions);
217
222
  const emit = defineEmits(["update:modelValue"]);
218
223
 
219
224
  const isShownOptions = ref(false);
225
+ const buttonRef = ref(null);
220
226
 
221
227
  const {
222
228
  config,
@@ -264,7 +270,13 @@ function hideOptions() {
264
270
  }
265
271
 
266
272
  function onClickOutside(event) {
267
- if (!document.getElementById(props.id)?.contains(event.target)) {
273
+ if (!buttonRef.value?.buttonRef?.contains(event.target)) {
274
+ hideOptions();
275
+ }
276
+ }
277
+
278
+ function onBlurButton(event) {
279
+ if (!event.target.isEqualNode(event.relatedTarget) && event.relatedTarget) {
268
280
  hideOptions();
269
281
  }
270
282
  }
@@ -3,6 +3,7 @@
3
3
  <div v-bind="triggerAttrs">
4
4
  <ULink
5
5
  :id="id"
6
+ ref="linkRef"
6
7
  :label="label"
7
8
  :size="size"
8
9
  :color="color"
@@ -13,6 +14,7 @@
13
14
  :data-cy="`${dataCy}-link`"
14
15
  v-bind="linkAttrs"
15
16
  @click.stop="onClickLink"
17
+ @blur="onBlurLink"
16
18
  >
17
19
  <template #right>
18
20
  <UIcon
@@ -210,6 +212,8 @@ const emit = defineEmits(["update:modelValue"]);
210
212
 
211
213
  const isShownOptions = ref(false);
212
214
 
215
+ const linkRef = ref(null);
216
+
213
217
  const {
214
218
  config,
215
219
  listWrapperAttrs,
@@ -254,7 +258,13 @@ function hideOptions() {
254
258
  }
255
259
 
256
260
  function onClickOutside(event) {
257
- if (!document.getElementById(props.id)?.contains(event.target)) {
261
+ if (!linkRef.value?.wrapperRef?.contains(event.target)) {
262
+ hideOptions();
263
+ }
264
+ }
265
+
266
+ function onBlurLink(event) {
267
+ if (!event.target.isEqualNode(event.relatedTarget) && event.relatedTarget) {
258
268
  hideOptions();
259
269
  }
260
270
  }
@@ -40,7 +40,7 @@ export default /*tw*/ {
40
40
  activeMonth: "bg-gray-100",
41
41
  yearViewWrapper: "grid w-64 grid-cols-4 items-center justify-center px-3 pt-2",
42
42
  year: `
43
- mx-auto flex h-12 w-full items-center justify-center rounded-lg text-sm hover:cursor-pointer hover:bg-gray-100
43
+ mx-auto flex h-12 w-full items-center justify-center rounded-lg text-sm hover:cursor-pointer hover:bg-gray-100
44
44
  disabled:opacity-50 disabled:cursor-not-allowed
45
45
  `,
46
46
  selectedYear: "bg-gray-900 hover:bg-gray-900 text-white",
@@ -111,7 +111,7 @@ const props = defineProps({
111
111
 
112
112
  /**
113
113
  * Label placement.
114
- * @values left, right
114
+ * @values top, topInside, topWithDesc, bottom, left, right
115
115
  */
116
116
  labelAlign: {
117
117
  type: String,
@@ -6,7 +6,7 @@
6
6
  :disabled="disabled"
7
7
  :error="error"
8
8
  :size="size"
9
- placement="topWithDesc"
9
+ align="topWithDesc"
10
10
  :data-cy="dataCy"
11
11
  v-bind="labelAttrs"
12
12
  >
@@ -7,14 +7,14 @@ export default /*tw*/ {
7
7
  },
8
8
  buttonWrapper: "flex h-full rounded-lg focus-within:ring-4 focus-within:ring-gray-600/[.15] max-md:justify-between",
9
9
  button: `
10
- shrink-0 grow rounded-none border-0 bg-zinc-100 py-2 text-base font-medium text-gray-900 shadow-none
11
- hover:bg-zinc-200 hover:ring-gray-600/[.15] focus:border-0 focus:bg-zinc-200 focus:ring-0 focus:ring-gray-600/[.15]
10
+ shrink-0 grow rounded-none border-0 bg-zinc-100 py-2 text-base font-medium text-gray-900 shadow-none
11
+ hover:bg-zinc-200 hover:ring-gray-600/[.15] focus:border-0 focus:bg-zinc-200 focus:ring-0 focus:ring-gray-600/[.15]
12
12
  active:bg-zinc-200 disabled:cursor-not-allowed
13
13
  `,
14
14
  buttonActive: "border-0 hover:bg-zinc-200 ring-0 ring-gray-600/[.15] bg-zinc-200",
15
15
  buttonWrapperActive: "ring-4 ring-gray-600/[.15]",
16
16
  shiftRangeButton: `
17
- focus:bg-bg-zinc-200 flex items-center border-0 bg-zinc-100 py-[0.71875rem] shadow-none
17
+ focus:bg-bg-zinc-200 flex items-center border-0 bg-zinc-100 py-[0.71875rem] shadow-none
18
18
  hover:bg-zinc-200 hover:ring-gray-600/[.15] focus:border-0 focus:ring-0 focus:ring-gray-600/[.15] active:bg-zinc-200
19
19
  disabled:cursor-not-allowed last:rounded-l-none last:rounded-r-lg first:rounded-l-lg first:rounded-r-none
20
20
  `,
@@ -29,7 +29,7 @@ export default /*tw*/ {
29
29
  },
30
30
  periodsRow: "mb-1 flex min-w-64 gap-1",
31
31
  periodButton: `
32
- flex h-[3.125rem] w-full cursor-pointer flex-col items-center justify-center rounded-lg bg-zinc-100
32
+ flex h-[3.125rem] w-full cursor-pointer flex-col items-center justify-center rounded-lg bg-zinc-100
33
33
  px-1.5 py-2.5 text-center text-xs font-medium text-gray-900 hover:bg-gray-200
34
34
  [&_span]:block [&_span]:font-normal [&_span]:text-gray-500
35
35
  `,
@@ -66,7 +66,7 @@ export default /*tw*/ {
66
66
  error: false,
67
67
  readonly: false,
68
68
  disabled: false,
69
- labelOutside: false,
69
+ labelAlign: "topInside",
70
70
  noAutocomplete: false,
71
71
  },
72
72
  };
@@ -123,11 +123,12 @@ const props = defineProps({
123
123
  },
124
124
 
125
125
  /**
126
- * Show label outside the input block.
126
+ * Set label placement related from the default slot.
127
+ * @values top, topInside, topWithDesc, bottom, left, right
127
128
  */
128
- labelOutside: {
129
- type: Boolean,
130
- default: UIService.get(defaultConfig, UInput).default.labelOutside,
129
+ labelAlign: {
130
+ type: String,
131
+ default: UIService.get(defaultConfig, UInput).default.labelAlign,
131
132
  },
132
133
 
133
134
  /**
@@ -285,10 +286,6 @@ const {
285
286
  hasSlotContent,
286
287
  } = useAttrs(props, { isTypePassword, inputPasswordClasses });
287
288
 
288
- const labelAlign = computed(() => {
289
- return props.labelOutside ? "top" : "topInside";
290
- });
291
-
292
289
  const passwordIconName = computed(() => {
293
290
  return isShownPassword.value
294
291
  ? config.value.passwordVisibleIconName
@@ -49,7 +49,7 @@ export default /*tw*/ {
49
49
  },
50
50
  defaultVariants: {
51
51
  size: "md",
52
- labelOutside: false,
52
+ labelAlign: "topInside",
53
53
  allowedFileTypes: [".png", ".jpg", ".jpeg", ".pdf", ".txt", ".doc", ".docx", "xls", ".xlsx"],
54
54
  maxFileSize: 1,
55
55
  maxFiles: 3,
@@ -100,11 +100,11 @@ const props = defineProps({
100
100
 
101
101
  /**
102
102
  * Set label placement related from the default slot.
103
- * @values topInside, top, left, right
103
+ * @values top, topInside, topWithDesc, bottom, left, right
104
104
  */
105
- labelOutside: {
106
- type: Boolean,
107
- default: UIService.get(defaultConfig, UInputFile).default.labelOutside,
105
+ labelAlign: {
106
+ type: String,
107
+ default: UIService.get(defaultConfig, UInputFile).default.labelAlign,
108
108
  },
109
109
 
110
110
  /**
@@ -226,10 +226,6 @@ const filesList = computed(() => {
226
226
  });
227
227
  });
228
228
 
229
- const labelAlign = computed(() => {
230
- return props.labelOutside ? "top" : "topInside";
231
- });
232
-
233
229
  const fileId = computed(() => {
234
230
  return `file-${props.id}`;
235
231
  });
@@ -20,6 +20,6 @@ export default /*tw*/ {
20
20
  starsNumber: 5,
21
21
  selectable: false,
22
22
  noCounter: false,
23
- labelOutside: false,
23
+ labelAlign: "topInside",
24
24
  },
25
25
  };
@@ -97,11 +97,11 @@ const props = defineProps({
97
97
 
98
98
  /**
99
99
  * Set label placement related from the default slot.
100
- * @values topInside, top, left, right
100
+ * @values top, topInside, topWithDesc, bottom, left, right
101
101
  */
102
- labelOutside: {
102
+ labelAlign: {
103
103
  type: String,
104
- default: UIService.get(defaultConfig, UInputRating).default.placement,
104
+ default: UIService.get(defaultConfig, UInputRating).default.labelAlign,
105
105
  },
106
106
 
107
107
  /**
@@ -152,10 +152,6 @@ const hovered = ref(null);
152
152
  const { counterAttrs, ratingAttrs, wrapperAttrs, iconsAttrs, iconsContainerAttrs, labelAttrs } =
153
153
  useAttrs(props);
154
154
 
155
- const labelAlign = computed(() => {
156
- return props.labelOutside ? "top" : "topInside";
157
- });
158
-
159
155
  const iconSize = computed(() => {
160
156
  const sizes = {
161
157
  sm: "xs",
@@ -13,6 +13,7 @@ export default /*tw*/ {
13
13
  topWithDesc: "flex-col-reverse w-fit",
14
14
  left: "flex-row w-fit",
15
15
  right: "flex-row-reverse w-fit",
16
+ bottom: "flex-col-reverse w-fit",
16
17
  },
17
18
  },
18
19
  compoundVariants: [
@@ -72,6 +73,7 @@ export default /*tw*/ {
72
73
  top: "pl-0",
73
74
  left: "pl-0",
74
75
  right: "pl-0",
76
+ bottom: "-order-1",
75
77
  },
76
78
  error: {
77
79
  true: "text-red-500",
@@ -91,7 +91,7 @@ const props = defineProps({
91
91
 
92
92
  /**
93
93
  * Set label placement related from the default slot.
94
- * @values topInside, top, topWithDesc, left, right
94
+ * @values top, topInside, topWithDesc, bottom, left, right
95
95
  */
96
96
  align: {
97
97
  type: String,
@@ -154,10 +154,10 @@ const wrapperRef = ref(null);
154
154
  const { wrapperAttrs, labelWrapperAttrs, labelAttrs, descriptionAttrs } = useAttrs(props);
155
155
 
156
156
  const isHorizontalPlacement = computed(
157
- () => props.placement === PLACEMENT.left || props.placement === PLACEMENT.right,
157
+ () => props.align === PLACEMENT.left || props.align === PLACEMENT.right,
158
158
  );
159
159
 
160
- const isTopWithDescPlacement = computed(() => props.placement === PLACEMENT.topWithDesc);
160
+ const isTopWithDescPlacement = computed(() => props.align === PLACEMENT.topWithDesc);
161
161
 
162
162
  const labelElement = computed(() => labelRef.value);
163
163
  const wrapperElement = computed(() => wrapperRef.value);
@@ -21,6 +21,8 @@
21
21
  @focus="onFocus"
22
22
  />
23
23
 
24
+ <slot />
25
+
24
26
  <template #footer>
25
27
  <slot name="footer" />
26
28
  </template>
@@ -93,7 +95,7 @@ const props = defineProps({
93
95
 
94
96
  /**
95
97
  * Set label placement related from the default slot.
96
- * @values left, right
98
+ * @values top, topInside, topWithDesc, bottom, left, right
97
99
  */
98
100
  labelAlign: {
99
101
  type: String,
@@ -142,7 +144,7 @@ const props = defineProps({
142
144
  },
143
145
  });
144
146
 
145
- const emit = defineEmits(["update:value"]);
147
+ const emit = defineEmits(["update:modelValue"]);
146
148
 
147
149
  const setRadioGroupSelectedItem = inject("setRadioGroupSelectedItem", null);
148
150
  const getRadioGroupName = inject("getRadioGroupName", null);
@@ -165,6 +167,6 @@ watchEffect(() => (radioSize.value = getRadioGroupSize ? getRadioGroupSize() : p
165
167
  function onFocus(event) {
166
168
  setRadioGroupSelectedItem && setRadioGroupSelectedItem(props.value);
167
169
 
168
- emit("update:value", event.target.value);
170
+ emit("update:modelValue", event.target.value);
169
171
  }
170
172
  </script>
@@ -17,8 +17,9 @@ export function useAttrs(props) {
17
17
  const radioClasses = computed(() => setColor(cvaRadio({ color: props.color }), props.color));
18
18
 
19
19
  const wrapperAttrsRaw = getAttrs("wrapper");
20
+ const itemsAttrs = getAttrs("items");
21
+ const labelAttrs = getAttrs("label");
20
22
  const radioAttrs = getAttrs("radio", { isComponent: true, classes: radioClasses });
21
- const labelAttrs = getAttrs("label", { isComponent: true });
22
23
  const iconAttrs = getAttrs("icon", { isComponent: true });
23
24
 
24
25
  const wrapperAttrs = computed(() => (classes) => ({
@@ -31,5 +32,6 @@ export function useAttrs(props) {
31
32
  iconAttrs,
32
33
  wrapperAttrs,
33
34
  labelAttrs,
35
+ itemsAttrs,
34
36
  };
35
37
  }
@@ -3,12 +3,18 @@ export default /*tw*/ {
3
3
  title: "text-base font-normal text-gray-900 mb-1 mt-3",
4
4
  description: "text-xs font-normal text-gray-500/[85]",
5
5
  radio: {
6
- base: "absolute right-4 top-2 !gap-0",
7
- label: "mr-1",
6
+ base: "w-full right-4 top-2 !gap-0",
7
+ radio: "absolute right-6 top-4",
8
8
  },
9
+ label: "size-full cursor-pointer",
10
+ items: `
11
+ relative mr-1 w-full cursor-pointer rounded-lg border border-solid border-gray-300 px-6 py-4
12
+ focus-within:border-gray-500 focus-within:ring-4 focus-within:ring-gray-600/[.15] hover:border-gray-400
13
+ `,
9
14
  icon: "mb-3 flex justify-center",
10
15
  defaultVariants: {
11
16
  color: "brand",
17
+ labelAlign: "top",
12
18
  gridCols: 2,
13
19
  withIcon: true,
14
20
  },
@@ -1,20 +1,25 @@
1
1
  <template>
2
2
  <div v-bind="wrapperAttrs(gridColsClass)">
3
- <template v-for="(item, index) in options" :key="id + index">
4
- <URadio
5
- :id="id + index"
6
- v-model="selectedItem"
7
- :value="item.value"
8
- :name="name"
9
- v-bind="radioAttrs"
10
- :label="item.label"
11
- :description="item.description"
12
- />
13
- <!-- @slot Use it to add icon. -->
14
- <slot v-if="withIcon" name="icon" :item="item">
15
- <UIcon :name="item.iconName" size="xl" :color="color" v-bind="iconAttrs" />
16
- </slot>
17
- </template>
3
+ <div v-for="(item, index) in options" :key="id + index" v-bind="itemsAttrs">
4
+ <label :for="id + index" v-bind="labelAttrs">
5
+ <URadio
6
+ :id="id + index"
7
+ v-model="selectedItem"
8
+ :value="item.value"
9
+ :name="name"
10
+ :label="item.label"
11
+ :checked="item.value === selectedItem"
12
+ :description="item.description"
13
+ :label-align="labelAlign"
14
+ v-bind="radioAttrs"
15
+ >
16
+ <!-- @slot Use it to add icon. -->
17
+ <slot v-if="withIcon" name="icon" :item="item">
18
+ <UIcon :name="item.iconName" size="xl" :color="color" v-bind="iconAttrs" />
19
+ </slot>
20
+ </URadio>
21
+ </label>
22
+ </div>
18
23
  </div>
19
24
  </template>
20
25
 
@@ -95,6 +100,11 @@ const props = defineProps({
95
100
  default: () => getRandomId(),
96
101
  },
97
102
 
103
+ labelAlign: {
104
+ type: String,
105
+ default: UIService.get(defaultConfig, URadioCard).default.labelAlign,
106
+ },
107
+
98
108
  /**
99
109
  * Sets component ui config object.
100
110
  */
@@ -112,33 +122,9 @@ const props = defineProps({
112
122
  },
113
123
  });
114
124
 
115
- // const labelConfig = {
116
- // wrapper: {
117
- // base: `
118
- // rounded-lg border border-solid border-gray-300 cursor-pointer relative w-full
119
- // hover:border-gray-400 focus-within:border-gray-500 focus-within:ring-4 focus-within:ring-gray-600/[.15]
120
- // px-6 py-4`,
121
- // },
122
- // label: {
123
- // base: "h-full w-full cursor-pointer",
124
- // variants: {
125
- // placement: {
126
- // topInside: "left-0 !top-0",
127
- // },
128
- // },
129
- // },
130
- // description: {
131
- // variants: {
132
- // placement: {
133
- // topInside: "pl-0",
134
- // },
135
- // },
136
- // },
137
- // };
138
-
139
125
  const emit = defineEmits(["update:modelValue"]);
140
126
 
141
- const { radioAttrs, iconAttrs, wrapperAttrs /* labelAttrs */ } = useAttrs(props);
127
+ const { radioAttrs, iconAttrs, wrapperAttrs, labelAttrs, itemsAttrs } = useAttrs(props);
142
128
 
143
129
  const isMobileDevice = computed(() => {
144
130
  return store.getters["breakpoint/isMobileDevice"];
@@ -1,8 +1,8 @@
1
1
  export default /*tw*/ {
2
- label: "relative w-full",
2
+ label: "w-full relative",
3
3
  wrapper: {
4
4
  base: `
5
- pb-2 flex flex-row-reverse justify-between w-full min-h-full static box-border
5
+ pb-2 flex flex-row-reverse justify-between w-full min-h-full box-border relative
6
6
  rounded-lg border border-gray-300 bg-white
7
7
  hover:border-gray-400 hover:transition hover:duration-100 hover:ease-in-out hover:focus-within:border-gray-500
8
8
  focus-within:border-gray-500 focus-within:ring-4 focus-within:ring-gray-600/[.15] focus-within:outline-none
@@ -133,6 +133,6 @@ export default /*tw*/ {
133
133
  searchable: true,
134
134
  noClear: false,
135
135
  addOption: false,
136
- labelOutside: false,
136
+ labelAlign: "topInside",
137
137
  },
138
138
  };