nuxt-ui-elements 0.1.34 → 0.1.35

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/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-ui-elements",
3
3
  "configKey": "uiElements",
4
- "version": "0.1.34",
4
+ "version": "0.1.35",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { addTemplate, defineNuxtModule, createResolver, addImportsDir } from '@nuxt/kit';
1
+ import { addTemplate, defineNuxtModule, createResolver, addImportsDir, addComponentsDir } from '@nuxt/kit';
2
2
  import { kebabCase } from 'scule';
3
3
 
4
4
  const dialogConfirm = (options) => ({
@@ -136,10 +136,41 @@ const dialogAlert = (options) => ({
136
136
  }
137
137
  });
138
138
 
139
+ const toggleGroup = (_options) => ({
140
+ slots: {
141
+ root: "flex flex-wrap gap-2",
142
+ item: [
143
+ "relative inline-flex items-center justify-center cursor-pointer select-none",
144
+ "transition-all duration-200",
145
+ "focus:outline-none focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-primary",
146
+ "disabled:cursor-not-allowed disabled:opacity-50"
147
+ ]
148
+ },
149
+ variants: {
150
+ orientation: {
151
+ horizontal: {
152
+ root: "flex-row"
153
+ },
154
+ vertical: {
155
+ root: "flex-col"
156
+ }
157
+ },
158
+ disabled: {
159
+ true: {
160
+ item: "cursor-not-allowed opacity-50"
161
+ }
162
+ }
163
+ },
164
+ defaultVariants: {
165
+ orientation: "horizontal"
166
+ }
167
+ });
168
+
139
169
  const theme = {
140
170
  __proto__: null,
141
171
  dialogAlert: dialogAlert,
142
- dialogConfirm: dialogConfirm
172
+ dialogConfirm: dialogConfirm,
173
+ toggleGroup: toggleGroup
143
174
  };
144
175
 
145
176
  function addTemplates(options, _nuxt) {
@@ -253,6 +284,10 @@ const module$1 = defineNuxtModule({
253
284
  addImportsDir(resolver.resolve("./runtime/composables"));
254
285
  nuxt.options.alias["#std"] = resolver.resolve("./runtime/utils/std");
255
286
  nuxt.options.alias["#ui-elements"] = resolver.resolve("./runtime");
287
+ addComponentsDir({
288
+ path: resolver.resolve("./runtime/components"),
289
+ prefix: options.prefix
290
+ });
256
291
  }
257
292
  });
258
293
 
@@ -0,0 +1,72 @@
1
+ import type { ToggleGroupRootProps } from "reka-ui";
2
+ import type { AppConfig } from "@nuxt/schema";
3
+ import theme from "#build/ui-elements/toggle-group";
4
+ import type { ComponentConfig, GetItemKeys, GetModelValue, NestedItem } from "../types/index.js";
5
+ type ToggleGroup = ComponentConfig<typeof theme, AppConfig, "toggleGroup">;
6
+ /**
7
+ * Base type for toggle group items. Can be a primitive or an object.
8
+ */
9
+ export type ToggleGroupItem = string | number | Record<string, any>;
10
+ export interface ToggleGroupProps<T extends ToggleGroupItem[] = ToggleGroupItem[], VK extends GetItemKeys<T> | undefined = "value", M extends boolean = true> extends Pick<ToggleGroupRootProps, "loop" | "disabled" | "name" | "required"> {
11
+ /**
12
+ * The items to display
13
+ */
14
+ items?: T;
15
+ /**
16
+ * When `items` is an array of objects, select the field to use as the value.
17
+ * When undefined, the whole object is used as the value.
18
+ * @defaultValue 'value'
19
+ */
20
+ valueKey?: VK;
21
+ /**
22
+ * The controlled value of the ToggleGroup. Can be bound with `v-model`.
23
+ * When `multiple` is true, this is an array. Otherwise, it's a single value.
24
+ */
25
+ modelValue?: GetModelValue<T, VK, M>;
26
+ /**
27
+ * The value when initially rendered. Use when you do not need to control state.
28
+ */
29
+ defaultValue?: GetModelValue<T, VK, M>;
30
+ /**
31
+ * Allow multiple items to be selected.
32
+ * @defaultValue true
33
+ */
34
+ multiple?: M;
35
+ /**
36
+ * The orientation the toggle items are laid out.
37
+ * @defaultValue 'horizontal'
38
+ */
39
+ orientation?: "horizontal" | "vertical";
40
+ ui?: ToggleGroup["slots"];
41
+ }
42
+ export interface ToggleGroupEmits<T extends ToggleGroupItem[] = ToggleGroupItem[], VK extends GetItemKeys<T> | undefined = "value", M extends boolean = true> {
43
+ "update:modelValue": [value: GetModelValue<T, VK, M>];
44
+ change: [event: Event];
45
+ }
46
+ export interface ToggleGroupSlots<T extends ToggleGroupItem[] = ToggleGroupItem[], I extends NestedItem<T> = NestedItem<T>> {
47
+ default(props: {
48
+ item: I;
49
+ selected: boolean;
50
+ }): any;
51
+ }
52
+ declare const _default: typeof __VLS_export;
53
+ export default _default;
54
+ declare const __VLS_export: <T extends ToggleGroupItem[], VK extends GetItemKeys<T> | undefined = "value", M extends boolean = true>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
55
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<ToggleGroupProps<T, VK, M> & {
56
+ onChange?: ((event: Event) => any) | undefined;
57
+ "onUpdate:modelValue"?: ((value: GetModelValue<T, VK, M>) => any) | undefined;
58
+ }> & (typeof globalThis extends {
59
+ __VLS_PROPS_FALLBACK: infer P;
60
+ } ? P : {});
61
+ expose: (exposed: {}) => void;
62
+ attrs: any;
63
+ slots: ToggleGroupSlots<T, NestedItem<T>>;
64
+ emit: ((evt: "change", event: Event) => void) & ((evt: "update:modelValue", value: GetModelValue<T, VK, M>) => void);
65
+ }>) => import("vue").VNode & {
66
+ __ctx?: Awaited<typeof __VLS_setup>;
67
+ };
68
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
69
+ [K in keyof T]: T[K];
70
+ } : {
71
+ [K in keyof T as K]: T[K];
72
+ }) & {};
@@ -0,0 +1,130 @@
1
+ <script>
2
+ import theme from "#build/ui-elements/toggle-group";
3
+ import { computed } from "vue";
4
+ import { ToggleGroupRoot, ToggleGroupItem as RekaToggleGroupItem } from "reka-ui";
5
+ import { tv } from "../utils/tv";
6
+ import { useFormField } from "@nuxt/ui/composables/useFormField";
7
+ </script>
8
+
9
+ <script setup>
10
+ const {
11
+ multiple = true,
12
+ valueKey = "value",
13
+ orientation = "horizontal",
14
+ loop = true,
15
+ disabled = false,
16
+ required = false,
17
+ ui: propUi,
18
+ ...props
19
+ } = defineProps({
20
+ items: { type: null, required: false },
21
+ valueKey: { type: null, required: false },
22
+ modelValue: { type: null, required: false },
23
+ defaultValue: { type: null, required: false },
24
+ multiple: { type: null, required: false },
25
+ orientation: { type: String, required: false },
26
+ ui: { type: null, required: false },
27
+ loop: { type: Boolean, required: false },
28
+ disabled: { type: Boolean, required: false },
29
+ name: { type: String, required: false },
30
+ required: { type: Boolean, required: false }
31
+ });
32
+ const emit = defineEmits(["update:modelValue", "change"]);
33
+ defineSlots();
34
+ const {
35
+ emitFormChange,
36
+ emitFormInput,
37
+ name: formFieldName,
38
+ disabled: formDisabled
39
+ } = useFormField({ name: props.name, disabled }, { bind: false });
40
+ const ui = computed(
41
+ () => tv({
42
+ extend: tv(theme)
43
+ })({
44
+ orientation,
45
+ disabled: formDisabled.value
46
+ })
47
+ );
48
+ function get(obj, key) {
49
+ if (obj === void 0 || obj === null) return void 0;
50
+ return obj[key];
51
+ }
52
+ function getItemValue(item, index) {
53
+ if (item === null || item === void 0) return index;
54
+ if (typeof item === "string" || typeof item === "number") return item;
55
+ if (valueKey === void 0) return item;
56
+ const val = get(item, valueKey);
57
+ return val !== void 0 ? val : index;
58
+ }
59
+ function getKeyValue(item, index) {
60
+ if (item === null || item === void 0) return index;
61
+ if (typeof item === "string" || typeof item === "number") return item;
62
+ if (valueKey !== void 0) {
63
+ const val = get(item, valueKey);
64
+ return val !== void 0 ? val : index;
65
+ }
66
+ return index;
67
+ }
68
+ const internalValue = computed(() => {
69
+ if (valueKey !== void 0) {
70
+ return props.modelValue;
71
+ }
72
+ if (props.modelValue === void 0 || props.modelValue === null) {
73
+ return multiple ? [] : void 0;
74
+ }
75
+ if (!multiple) {
76
+ const idx = props.items?.findIndex((item) => item === props.modelValue);
77
+ return idx !== void 0 && idx >= 0 ? idx : void 0;
78
+ }
79
+ const values = props.modelValue;
80
+ return values.map((val) => {
81
+ const idx = props.items?.findIndex((item) => item === val);
82
+ return idx !== void 0 && idx >= 0 ? idx : -1;
83
+ }).filter((idx) => idx >= 0);
84
+ });
85
+ function onUpdate(value) {
86
+ if (value === null || value === void 0) return;
87
+ if (valueKey !== void 0) {
88
+ emit("update:modelValue", value);
89
+ } else {
90
+ if (!multiple) {
91
+ const item = props.items?.[value];
92
+ emit("update:modelValue", item);
93
+ } else {
94
+ const indices = value;
95
+ const objects = indices.map((idx) => props.items?.[idx]).filter(Boolean);
96
+ emit("update:modelValue", objects);
97
+ }
98
+ }
99
+ const event = new Event("change", { target: { value } });
100
+ emit("change", event);
101
+ emitFormChange();
102
+ emitFormInput();
103
+ }
104
+ </script>
105
+
106
+ <template>
107
+ <ToggleGroupRoot
108
+ :type="multiple ? 'multiple' : 'single'"
109
+ :model-value="internalValue"
110
+ :default-value="defaultValue"
111
+ :orientation="orientation"
112
+ :loop="loop"
113
+ :disabled="formDisabled"
114
+ :name="formFieldName"
115
+ :required="required"
116
+ data-slot="root"
117
+ :class="ui.root({ class: [propUi?.root] })"
118
+ @update:model-value="onUpdate">
119
+ <RekaToggleGroupItem
120
+ v-for="(item, index) in items"
121
+ :key="getKeyValue(item, index)"
122
+ :value="valueKey === void 0 ? index : getItemValue(item, index)"
123
+ :disabled="formDisabled"
124
+ data-slot="item"
125
+ :class="ui.item({ class: propUi?.item })"
126
+ #="{ pressed }">
127
+ <slot v-if="item" :item="item" :selected="pressed" />
128
+ </RekaToggleGroupItem>
129
+ </ToggleGroupRoot>
130
+ </template>
@@ -0,0 +1,72 @@
1
+ import type { ToggleGroupRootProps } from "reka-ui";
2
+ import type { AppConfig } from "@nuxt/schema";
3
+ import theme from "#build/ui-elements/toggle-group";
4
+ import type { ComponentConfig, GetItemKeys, GetModelValue, NestedItem } from "../types/index.js";
5
+ type ToggleGroup = ComponentConfig<typeof theme, AppConfig, "toggleGroup">;
6
+ /**
7
+ * Base type for toggle group items. Can be a primitive or an object.
8
+ */
9
+ export type ToggleGroupItem = string | number | Record<string, any>;
10
+ export interface ToggleGroupProps<T extends ToggleGroupItem[] = ToggleGroupItem[], VK extends GetItemKeys<T> | undefined = "value", M extends boolean = true> extends Pick<ToggleGroupRootProps, "loop" | "disabled" | "name" | "required"> {
11
+ /**
12
+ * The items to display
13
+ */
14
+ items?: T;
15
+ /**
16
+ * When `items` is an array of objects, select the field to use as the value.
17
+ * When undefined, the whole object is used as the value.
18
+ * @defaultValue 'value'
19
+ */
20
+ valueKey?: VK;
21
+ /**
22
+ * The controlled value of the ToggleGroup. Can be bound with `v-model`.
23
+ * When `multiple` is true, this is an array. Otherwise, it's a single value.
24
+ */
25
+ modelValue?: GetModelValue<T, VK, M>;
26
+ /**
27
+ * The value when initially rendered. Use when you do not need to control state.
28
+ */
29
+ defaultValue?: GetModelValue<T, VK, M>;
30
+ /**
31
+ * Allow multiple items to be selected.
32
+ * @defaultValue true
33
+ */
34
+ multiple?: M;
35
+ /**
36
+ * The orientation the toggle items are laid out.
37
+ * @defaultValue 'horizontal'
38
+ */
39
+ orientation?: "horizontal" | "vertical";
40
+ ui?: ToggleGroup["slots"];
41
+ }
42
+ export interface ToggleGroupEmits<T extends ToggleGroupItem[] = ToggleGroupItem[], VK extends GetItemKeys<T> | undefined = "value", M extends boolean = true> {
43
+ "update:modelValue": [value: GetModelValue<T, VK, M>];
44
+ change: [event: Event];
45
+ }
46
+ export interface ToggleGroupSlots<T extends ToggleGroupItem[] = ToggleGroupItem[], I extends NestedItem<T> = NestedItem<T>> {
47
+ default(props: {
48
+ item: I;
49
+ selected: boolean;
50
+ }): any;
51
+ }
52
+ declare const _default: typeof __VLS_export;
53
+ export default _default;
54
+ declare const __VLS_export: <T extends ToggleGroupItem[], VK extends GetItemKeys<T> | undefined = "value", M extends boolean = true>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
55
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<ToggleGroupProps<T, VK, M> & {
56
+ onChange?: ((event: Event) => any) | undefined;
57
+ "onUpdate:modelValue"?: ((value: GetModelValue<T, VK, M>) => any) | undefined;
58
+ }> & (typeof globalThis extends {
59
+ __VLS_PROPS_FALLBACK: infer P;
60
+ } ? P : {});
61
+ expose: (exposed: {}) => void;
62
+ attrs: any;
63
+ slots: ToggleGroupSlots<T, NestedItem<T>>;
64
+ emit: ((evt: "change", event: Event) => void) & ((evt: "update:modelValue", value: GetModelValue<T, VK, M>) => void);
65
+ }>) => import("vue").VNode & {
66
+ __ctx?: Awaited<typeof __VLS_setup>;
67
+ };
68
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
69
+ [K in keyof T]: T[K];
70
+ } : {
71
+ [K in keyof T as K]: T[K];
72
+ }) & {};
@@ -1,3 +1,5 @@
1
1
  export * from "../components/DialogConfirm.vue.js";
2
2
  export * from "../components/DialogAlert.vue.js";
3
+ export * from "../components/ToggleGroup.vue.js";
3
4
  export * from "./tv.js";
5
+ export * from "./utils.js";
@@ -1,3 +1,5 @@
1
1
  export * from "../components/DialogConfirm.vue";
2
2
  export * from "../components/DialogAlert.vue";
3
+ export * from "../components/ToggleGroup.vue";
3
4
  export * from "./tv.js";
5
+ export * from "./utils.js";
@@ -0,0 +1,50 @@
1
+ import type { AcceptableValue as _AcceptableValue } from "reka-ui";
2
+ /**
3
+ * Excludes plain objects from reka-ui's AcceptableValue to keep primitives separate.
4
+ * Boolean is added as it's commonly used as a value type.
5
+ */
6
+ export type AcceptableValue = Exclude<_AcceptableValue, Record<string, any>> | boolean;
7
+ /**
8
+ * Represents either a flat array or a nested array (for grouped items).
9
+ */
10
+ export type ArrayOrNested<T> = T[] | T[][];
11
+ /**
12
+ * Extracts the inner item type from an array, handling nested arrays.
13
+ */
14
+ export type NestedItem<T> = T extends Array<infer I> ? NestedItem<I> : T;
15
+ /**
16
+ * Gets all possible keys from an item type, including nested object keys.
17
+ * Works with arrays of objects to extract the keys of the inner object type.
18
+ */
19
+ export type GetItemKeys<I> = keyof Extract<NestedItem<I>, object>;
20
+ /**
21
+ * Determines the value type based on the item type and valueKey.
22
+ * - When VK is undefined, returns the whole object type T
23
+ * - When VK is a key of T, returns the type of that property
24
+ *
25
+ * @template I The items array type
26
+ * @template VK The valueKey (keyof item or undefined)
27
+ * @template T The nested item type (extracted from I)
28
+ */
29
+ export type GetItemValue<I, VK extends GetItemKeys<I> | undefined, T extends NestedItem<I> = NestedItem<I>> = T extends object ? VK extends undefined ? T : VK extends keyof T ? T[VK] : never : T;
30
+ /**
31
+ * Determines the modelValue type based on item type, valueKey, and selection mode.
32
+ * - For single selection (M = false): returns GetItemValue<T, VK>
33
+ * - For multiple selection (M = true): returns GetItemValue<T, VK>[]
34
+ *
35
+ * @template T The items array type
36
+ * @template VK The valueKey (keyof item or undefined)
37
+ * @template M Whether multiple selection is enabled
38
+ */
39
+ export type GetModelValue<T, VK extends GetItemKeys<T> | undefined, M extends boolean> = M extends true ? GetItemValue<T, VK>[] : GetItemValue<T, VK>;
40
+ /**
41
+ * Defines the emit type for modelValue updates.
42
+ *
43
+ * @template T The items array type
44
+ * @template VK The valueKey (keyof item or undefined)
45
+ * @template M Whether multiple selection is enabled
46
+ */
47
+ export type GetModelValueEmits<T, VK extends GetItemKeys<T> | undefined, M extends boolean> = {
48
+ /** Event handler called when the value changes. */
49
+ "update:modelValue": [value: GetModelValue<T, VK, M>];
50
+ };
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-ui-elements",
3
- "version": "0.1.34",
3
+ "version": "0.1.35",
4
4
  "description": "A collection of beautiful, animated UI components for Nuxt applications",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/genu/nuxt-ui-elements.git",