vueless 0.0.556 → 0.0.558

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.
@@ -19,9 +19,10 @@ import type {
19
19
  NestedComponent,
20
20
  ComponentNames,
21
21
  CVA,
22
+ UseUI,
22
23
  KeyAttrs,
23
- ExtendedKeyClasses,
24
24
  KeysAttrs,
25
+ ExtendedKeyClasses,
25
26
  } from "../types.ts";
26
27
 
27
28
  /**
@@ -35,7 +36,8 @@ export default function useUI<T>(
35
36
  defaultConfig: T & Component,
36
37
  propsConfigGetter?: () => (T & Component) | undefined,
37
38
  topLevelClassKey?: string,
38
- ) {
39
+ mutatedProps?: ComputedRef,
40
+ ): UseUI<T> {
39
41
  const { type, props } = getCurrentInstance() as ComponentInternalInstance;
40
42
  const componentName = type.__name as ComponentNames;
41
43
  const globalConfig = vuelessConfig?.component?.[componentName] || {};
@@ -48,7 +50,7 @@ export default function useUI<T>(
48
50
  : (STRATEGY_TYPE.merge as Strategies);
49
51
 
50
52
  const firstClassKey = defaultConfig ? Object.keys(defaultConfig)[0] : "";
51
- const config = ref({} as T);
53
+ const config = ref({} as T & Component);
52
54
  const attrs = useAttrs();
53
55
 
54
56
  watchEffect(() => {
@@ -191,7 +193,7 @@ export default function useUI<T>(
191
193
  return vuelessAttrs;
192
194
  }
193
195
 
194
- return { config, getKeysAttrs };
196
+ return { config, getKeysAttrs, ...getKeysAttrs(mutatedProps) };
195
197
  }
196
198
 
197
199
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueless",
3
- "version": "0.0.556",
3
+ "version": "0.0.558",
4
4
  "license": "MIT",
5
5
  "description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
6
6
  "keywords": [
package/types.ts CHANGED
@@ -43,8 +43,11 @@ import UCheckboxGroupConfig from "./ui.form-checkbox-group/config.ts";
43
43
  import UCheckboxMultiStateConfig from "./ui.form-checkbox-multi-state/config.ts";
44
44
  import URadioConfig from "./ui.form-radio/config.ts";
45
45
  import URadioGroupConfig from "./ui.form-radio-group/config.ts";
46
+ import USwitchConfig from "./ui.form-switch/config.ts";
47
+ import UTextareaConfig from "./ui.form-textarea/config.ts";
48
+ import ULabelConfig from "./ui.form-label/config.ts";
46
49
 
47
- import type { MaybeRef, Ref } from "vue";
50
+ import type { ComputedRef, MaybeRef, Ref, UnwrapRef } from "vue";
48
51
  import type { Props } from "tippy.js";
49
52
  import type { LocaleOptions } from "./adatper.locale/vueless.ts";
50
53
 
@@ -201,6 +204,9 @@ export interface Components {
201
204
  UCheckboxMultiState?: Partial<typeof UCheckboxMultiStateConfig>;
202
205
  URadio?: Partial<typeof URadioConfig>;
203
206
  URadioGroup?: Partial<typeof URadioGroupConfig>;
207
+ USwitch?: Partial<typeof USwitchConfig>;
208
+ UTextarea?: Partial<typeof UTextareaConfig>;
209
+ ULabel?: Partial<typeof ULabelConfig>;
204
210
  }
205
211
 
206
212
  export interface Directives {
@@ -227,6 +233,19 @@ export interface NestedComponent {
227
233
  [key: string]: Record<string, string | object> | string;
228
234
  }
229
235
 
236
+ export type ComponentConfig<T> = [T & Component] extends [Ref]
237
+ ? Ref<T & Component>
238
+ : Ref<UnwrapRef<T & Component>, T & Component>;
239
+
240
+ export interface UseUI<T> {
241
+ config: ComponentConfig<T>;
242
+ getKeysAttrs: (mutatedProps?: ComputedRef) => KeysAttrs;
243
+ [key: string]:
244
+ | ComputedRef<KeyAttrs>
245
+ | ComponentConfig<T>
246
+ | ((mutatedProps?: ComputedRef) => KeysAttrs);
247
+ }
248
+
230
249
  export interface Transition {
231
250
  enterFromClass?: string;
232
251
  enterActiveClass?: string;
@@ -106,16 +106,18 @@ defineExpose({
106
106
  * Get element / nested component attributes for each config token ✨
107
107
  * Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
108
108
  */
109
- const { getKeysAttrs } = useUI<Config>(defaultConfig, () => props.config);
110
-
111
109
  const mutatedProps = computed(() => ({
112
110
  leftIcon: Boolean(props.leftIcon) || hasSlotContent(slots["left"]),
113
111
  rightIcon: Boolean(props.rightIcon) || hasSlotContent(slots["right"]),
114
112
  label: Boolean(props.label),
115
113
  }));
116
114
 
117
- const { buttonAttrs, loaderAttrs, leftIconAttrs, rightIconAttrs, centerIconAttrs } =
118
- getKeysAttrs(mutatedProps);
115
+ const { buttonAttrs, loaderAttrs, leftIconAttrs, rightIconAttrs, centerIconAttrs } = useUI<Config>(
116
+ defaultConfig,
117
+ () => props.config,
118
+ "",
119
+ mutatedProps,
120
+ );
119
121
  </script>
120
122
 
121
123
  <template>
@@ -1,3 +1,71 @@
1
+ <script setup lang="ts">
2
+ import { computed, ref } from "vue";
3
+
4
+ import { getDefault } from "../utils/ui.ts";
5
+
6
+ import defaultConfig from "./config.ts";
7
+ import { ULabel, PLACEMENT } from "./constants.ts";
8
+ import useAttrs from "./useAttrs.ts";
9
+
10
+ import type { ULabelProps } from "./types.ts";
11
+
12
+ defineOptions({ inheritAttrs: false });
13
+
14
+ const props = withDefaults(defineProps<ULabelProps>(), {
15
+ align: getDefault<ULabelProps>(defaultConfig, ULabel).align,
16
+ size: getDefault<ULabelProps>(defaultConfig, ULabel).size,
17
+ disabled: getDefault<ULabelProps>(defaultConfig, ULabel).disabled,
18
+ centred: getDefault<ULabelProps>(defaultConfig, ULabel).centred,
19
+ dataTest: "",
20
+ });
21
+
22
+ const emit = defineEmits([
23
+ /**
24
+ * Triggers when the label is clicked.
25
+ */
26
+ "click",
27
+ ]);
28
+
29
+ const labelRef = ref(null);
30
+ const wrapperRef = ref(null);
31
+
32
+ const { wrapperAttrs, contentAttrs, labelAttrs, descriptionAttrs } = useAttrs(props);
33
+
34
+ const isHorizontalPlacement = computed(() => {
35
+ return props.align === PLACEMENT.left || props.align === PLACEMENT.right;
36
+ });
37
+
38
+ const isTopWithDescPlacement = computed(() => {
39
+ return props.align === PLACEMENT.topWithDesc;
40
+ });
41
+
42
+ const labelElement = computed(() => {
43
+ return labelRef.value;
44
+ });
45
+
46
+ const wrapperElement = computed(() => {
47
+ return wrapperRef.value;
48
+ });
49
+
50
+ function onClick(event: MouseEvent) {
51
+ emit("click", event);
52
+ }
53
+
54
+ defineExpose({
55
+ /**
56
+ * Reference to the label element.
57
+ * @property {HTMLElement}
58
+ */
59
+ labelElement,
60
+
61
+ /**
62
+ * Reference to the wrapper element containing the label and content.
63
+ * @property {HTMLElement}
64
+ */
65
+ wrapperElement,
66
+ });
67
+ </script>
68
+
1
69
  <template>
2
70
  <div
3
71
  v-if="isHorizontalPlacement || isTopWithDescPlacement"
@@ -62,145 +130,3 @@
62
130
  <slot name="bottom" />
63
131
  </div>
64
132
  </template>
65
-
66
- <script setup>
67
- import { computed, ref } from "vue";
68
-
69
- import { getDefault } from "../utils/ui.ts";
70
-
71
- import defaultConfig from "./config.js";
72
- import { ULabel, PLACEMENT } from "./constants.js";
73
- import useAttrs from "./useAttrs.js";
74
-
75
- defineOptions({ inheritAttrs: false });
76
-
77
- const emit = defineEmits([
78
- /**
79
- * Triggers when the label is clicked.
80
- */
81
- "click",
82
- ]);
83
-
84
- const props = defineProps({
85
- /**
86
- * Label text.
87
- */
88
- label: {
89
- type: String,
90
- default: "",
91
- },
92
-
93
- /**
94
- * Label description.
95
- */
96
- description: {
97
- type: String,
98
- default: "",
99
- },
100
-
101
- /**
102
- * Label error message.
103
- */
104
- error: {
105
- type: String,
106
- default: "",
107
- },
108
-
109
- /**
110
- * Label align.
111
- * @values top, topInside, topWithDesc, left, right
112
- */
113
- align: {
114
- type: String,
115
- default: getDefault(defaultConfig, ULabel).align,
116
- },
117
-
118
- /**
119
- * Label size.
120
- * @values sm, md, lg
121
- */
122
- size: {
123
- type: String,
124
- default: getDefault(defaultConfig, ULabel).size,
125
- },
126
-
127
- /**
128
- * Make label disabled.
129
- */
130
- disabled: {
131
- type: Boolean,
132
- default: getDefault(defaultConfig, ULabel).disabled,
133
- },
134
-
135
- /**
136
- * Centre label horizontally.
137
- */
138
- centred: {
139
- type: Boolean,
140
- default: getDefault(defaultConfig, ULabel).centred,
141
- },
142
-
143
- /**
144
- * Set input id for label `for` attribute.
145
- */
146
- for: {
147
- type: String,
148
- default: "",
149
- },
150
-
151
- /**
152
- * Component config object.
153
- */
154
- config: {
155
- type: Object,
156
- default: () => ({}),
157
- },
158
-
159
- /**
160
- * Data-test attribute for automated testing.
161
- */
162
- dataTest: {
163
- type: String,
164
- default: "",
165
- },
166
- });
167
-
168
- const labelRef = ref(null);
169
- const wrapperRef = ref(null);
170
-
171
- const { wrapperAttrs, contentAttrs, labelAttrs, descriptionAttrs } = useAttrs(props);
172
-
173
- const isHorizontalPlacement = computed(() => {
174
- return props.align === PLACEMENT.left || props.align === PLACEMENT.right;
175
- });
176
-
177
- const isTopWithDescPlacement = computed(() => {
178
- return props.align === PLACEMENT.topWithDesc;
179
- });
180
-
181
- const labelElement = computed(() => {
182
- return labelRef.value;
183
- });
184
-
185
- const wrapperElement = computed(() => {
186
- return wrapperRef.value;
187
- });
188
-
189
- function onClick(event) {
190
- emit("click", event);
191
- }
192
-
193
- defineExpose({
194
- /**
195
- * Reference to the label element.
196
- * @property {HTMLElement}
197
- */
198
- labelElement,
199
-
200
- /**
201
- * Reference to the wrapper element containing the label and content.
202
- * @property {HTMLElement}
203
- */
204
- wrapperElement,
205
- });
206
- </script>
@@ -1,8 +1,8 @@
1
1
  import { Meta, Title, Subtitle, Description, Primary, Controls, Stories, Source } from "@storybook/blocks";
2
2
  import { getSource } from "../../utils/storybook.ts";
3
3
 
4
- import * as stories from "./stories.js";
5
- import defaultConfig from "../config.js?raw"
4
+ import * as stories from "./stories.ts";
5
+ import defaultConfig from "../config.ts?raw"
6
6
 
7
7
  <Meta of={stories} />
8
8
  <Title of={stories} />
@@ -5,6 +5,14 @@ import UCol from "../../ui.container-col/UCol.vue";
5
5
  import UText from "../../ui.text-block/UText.vue";
6
6
  import UIcon from "../../ui.image-icon/UIcon.vue";
7
7
 
8
+ import type { Meta, StoryFn } from "@storybook/vue3";
9
+ import type { ULabelProps } from "../types.ts";
10
+
11
+ interface ULabelArgs extends ULabelProps {
12
+ slotTemplate?: string;
13
+ enum: "align" | "size";
14
+ }
15
+
8
16
  /**
9
17
  * The `ULabel` component. | [View on GitHub](https://github.com/vuelessjs/vueless/tree/main/src/ui.form-label)
10
18
  */
@@ -19,11 +27,11 @@ export default {
19
27
  argTypes: {
20
28
  ...getArgTypes(ULabel.__name),
21
29
  },
22
- };
30
+ } as Meta;
23
31
 
24
32
  const defaultTemplate = "This is plain text";
25
33
 
26
- const DefaultTemplate = (args) => ({
34
+ const DefaultTemplate: StoryFn<ULabelArgs> = (args: ULabelArgs) => ({
27
35
  components: { ULabel, UText, UIcon },
28
36
  setup() {
29
37
  const slots = getSlotNames(ULabel.__name);
@@ -38,19 +46,26 @@ const DefaultTemplate = (args) => ({
38
46
  `,
39
47
  });
40
48
 
41
- const EnumVariantTemplate = (args, { argTypes }) => ({
49
+ const EnumVariantTemplate: StoryFn<ULabelArgs> = (args: ULabelArgs, { argTypes }) => ({
42
50
  components: { ULabel, UCol, UText },
43
51
  setup() {
44
- function getText(value, name) {
52
+ function getText(value: string, name: string) {
45
53
  return name === "size" ? `This is ${value} size.` : `This is ${value} label placement.`;
46
54
  }
47
55
 
48
- const { name, options } = argTypes[args.enum];
49
- const prefixedOptions = options.map((option) => getText(option, name));
56
+ let prefixedOptions;
57
+
58
+ const enumArgType = argTypes?.[args.enum];
59
+
60
+ if (enumArgType && "name" in enumArgType && "options" in enumArgType) {
61
+ const { name, options } = enumArgType;
62
+
63
+ prefixedOptions = options?.map((option: string) => getText(option, name));
64
+ }
50
65
 
51
66
  return {
52
67
  args,
53
- options: argTypes[args.enum].options,
68
+ options: argTypes?.[args.enum]?.options,
54
69
  prefixedOptions,
55
70
  };
56
71
  },
@@ -0,0 +1,55 @@
1
+ import defaultConfig from "./config.ts";
2
+
3
+ export type Config = Partial<typeof defaultConfig>;
4
+
5
+ export interface ULabelProps {
6
+ /**
7
+ * Label text.
8
+ */
9
+ label?: string;
10
+
11
+ /**
12
+ * Label description.
13
+ */
14
+ description?: string;
15
+
16
+ /**
17
+ * Label error message.
18
+ */
19
+ error?: string;
20
+
21
+ /**
22
+ * Label align.
23
+ */
24
+ align?: "top" | "topInside" | "topWithDesc" | "left" | "right";
25
+
26
+ /**
27
+ * Label size.
28
+ */
29
+ size?: "sm" | "md" | "lg";
30
+
31
+ /**
32
+ * Make label disabled.
33
+ */
34
+ disabled?: boolean;
35
+
36
+ /**
37
+ * Centre label horizontally.
38
+ */
39
+ centred?: boolean;
40
+
41
+ /**
42
+ * Set input id for label `for` attribute.
43
+ */
44
+ for?: string;
45
+
46
+ /**
47
+ * Component config object.
48
+ */
49
+ config?: Config;
50
+
51
+ /**
52
+ * Data-test attribute for automated testing.
53
+ */
54
+ dataTest?: string;
55
+ }
@@ -0,0 +1,20 @@
1
+ import { computed } from "vue";
2
+ import useUI from "../composables/useUI.ts";
3
+
4
+ import defaultConfig from "./config.ts";
5
+
6
+ import type { UseAttrs } from "../types.ts";
7
+ import type { ULabelProps, Config } from "./types.ts";
8
+
9
+ export default function useAttrs(props: ULabelProps): UseAttrs<Config> {
10
+ const { config, getKeysAttrs } = useUI<Config>(defaultConfig, () => props.config);
11
+
12
+ const mutatedProps = computed(() => ({
13
+ error: Boolean(props.error),
14
+ }));
15
+
16
+ return {
17
+ config,
18
+ ...getKeysAttrs(mutatedProps),
19
+ };
20
+ }