ui-thing 0.1.18 → 0.1.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ui-thing",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "CLI used to add Nuxt 3 components to a project",
5
5
  "keywords": [
6
6
  "cli",
@@ -41,31 +41,31 @@
41
41
  "axios": "^1.7.2",
42
42
  "boxen": "^7.1.1",
43
43
  "build": "^0.1.4",
44
- "c12": "^1.10.0",
44
+ "c12": "^1.11.1",
45
45
  "commander": "^12.1.0",
46
46
  "defu": "^6.1.4",
47
- "execa": "^9.1.0",
47
+ "execa": "^9.3.0",
48
48
  "figlet": "^1.7.0",
49
49
  "fs-extra": "^11.2.0",
50
50
  "kleur": "^4.1.5",
51
51
  "lodash": "^4.17.21",
52
- "nypm": "^0.3.8",
52
+ "nypm": "^0.3.9",
53
53
  "ora": "^8.0.1",
54
54
  "prompts": "^2.4.2"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@gmrchk/cli-testing-library": "^0.1.2",
58
- "@ianvs/prettier-plugin-sort-imports": "^4.2.1",
58
+ "@ianvs/prettier-plugin-sort-imports": "^4.3.0",
59
59
  "@types/figlet": "^1.5.8",
60
60
  "@types/fs-extra": "^11.0.4",
61
- "@types/lodash": "^4.17.4",
62
- "@types/node": "^20.14.2",
61
+ "@types/lodash": "^4.17.6",
62
+ "@types/node": "^20.14.10",
63
63
  "@types/prompts": "^2.4.9",
64
- "@vitest/coverage-v8": "^1.6.0",
64
+ "@vitest/coverage-v8": "^2.0.1",
65
65
  "magicast": "^0.3.4",
66
66
  "tsup": "^8.1.0",
67
- "typescript": "^5.4.5",
68
- "vitest": "^1.6.0"
67
+ "typescript": "^5.5.3",
68
+ "vitest": "^2.0.1"
69
69
  },
70
70
  "publishConfig": {
71
71
  "access": "public"
@@ -233,7 +233,11 @@ export const add = new Command()
233
233
  // add plugins attached to the component
234
234
  loop5: for (let j = 0; j < component.plugins.length; j++) {
235
235
  const plugin = component.plugins[j];
236
- const filePath = path.join(currentDirectory, plugin.dirPath, plugin.fileName);
236
+ const filePath = path.join(
237
+ currentDirectory,
238
+ uiConfig.pluginsLocation ?? plugin.dirPath,
239
+ plugin.fileName
240
+ );
237
241
  // Check if the file exists
238
242
  const exists = await fileExists(filePath);
239
243
  if (exists && !uiConfig.force) {
package/src/comps.ts CHANGED
@@ -388,7 +388,7 @@ export default [
388
388
  fileName: "Card/Footer.vue",
389
389
  dirPath: "components/UI",
390
390
  fileContent:
391
- '<template>\n <Primitive :class="styles({ class: props.class })" :as="as" :as-child="asChild">\n <slot />\n </Primitive>\n</template>\n\n<script lang="ts" setup>\n import { Primitive } from "radix-vue";\n import type { PrimitiveProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n PrimitiveProps & {\n /** Custom class(es) to add to the element */\n class?: any;\n }\n >(),\n { as: "div" }\n );\n\n const styles = tv({\n base: "flex items-center p-6 ",\n });\n</script>\n',
391
+ '<template>\n <Primitive :class="styles({ class: props.class })" :as="as" :as-child="asChild">\n <slot />\n </Primitive>\n</template>\n\n<script lang="ts" setup>\n import { Primitive } from "radix-vue";\n import type { PrimitiveProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n PrimitiveProps & {\n /** Custom class(es) to add to the element */\n class?: any;\n }\n >(),\n { as: "div" }\n );\n\n const styles = tv({\n base: "flex items-center p-6",\n });\n</script>\n',
392
392
  },
393
393
  {
394
394
  fileName: "Card/Header.vue",
@@ -1030,7 +1030,7 @@ export default [
1030
1030
  fileName: "FancyIcon.vue",
1031
1031
  dirPath: "components/UI",
1032
1032
  fileContent:
1033
- '<template>\n <div :class="styles().base({ class: props.class, color, type, size, circle })">\n <slot :styles="styles().icon({ color, type, size, circle })">\n <Icon :name="icon" :class="styles().icon({ color, type, size, circle })" />\n </slot>\n </div>\n</template>\n\n<script lang="ts" setup>\n const props = withDefaults(\n defineProps<{\n class?: any;\n icon: string;\n color?: VariantProps<typeof styles>["color"];\n type?: VariantProps<typeof styles>["type"];\n size?: VariantProps<typeof styles>["size"];\n circle?: boolean;\n }>(),\n {\n color: "primary",\n type: "modern",\n size: "lg",\n circle: false,\n }\n );\n\n const styles = tv({\n slots: {\n base: "flex shrink-0 items-center justify-center",\n icon: "",\n },\n\n variants: {\n color: {\n primary: {\n base: "",\n icon: "",\n },\n success: {\n base: "",\n icon: "",\n },\n warning: {\n base: "",\n icon: "",\n },\n error: {\n base: "",\n icon: "",\n },\n info: {\n base: "",\n icon: "",\n },\n },\n type: {\n light: {\n base: "",\n icon: "",\n },\n dark: {\n base: "",\n icon: "",\n },\n modern: {\n base: "",\n icon: "",\n },\n },\n size: {\n sm: {\n base: "size-8",\n icon: "size-4",\n },\n md: {\n base: "size-10",\n icon: "size-5",\n },\n lg: {\n base: "size-12",\n icon: "size-6",\n },\n xl: {\n base: "size-14",\n icon: "size-7",\n },\n },\n circle: {\n true: {\n base: "rounded-full",\n },\n false: {\n base: "rounded-lg",\n },\n },\n },\n compoundVariants: [\n {\n color: "primary",\n type: "light",\n class: { base: "bg-primary/5 ", icon: "text-primary" },\n },\n {\n color: "success",\n type: "light",\n class: {\n base: "bg-green-500/10",\n icon: "text-green-600",\n },\n },\n {\n color: "warning",\n type: "light",\n class: { base: "bg-amber-500/10", icon: "text-amber-600" },\n },\n {\n color: "error",\n type: "light",\n class: { base: "bg-destructive/10", icon: "text-destructive" },\n },\n {\n color: "info",\n type: "light",\n class: { base: "bg-blue-500/10", icon: "text-blue-600" },\n },\n // Dark\n {\n color: "primary",\n type: "dark",\n class: { base: "bg-primary", icon: "text-primary-foreground" },\n },\n {\n color: "success",\n type: "dark",\n class: { base: "bg-green-600", icon: "text-green-50" },\n },\n {\n color: "warning",\n type: "dark",\n class: { base: "bg-amber-600", icon: "text-amber-50" },\n },\n {\n color: "error",\n type: "dark",\n class: { base: "bg-destructive", icon: "text-destructive-foreground" },\n },\n {\n color: "info",\n type: "dark",\n class: { base: "bg-blue-500", icon: "text-blue-50" },\n },\n // Modern\n {\n type: "modern",\n class: { base: "border bg-background", icon: "text-muted-foreground" },\n },\n ],\n defaultVariants: {\n color: "primary",\n type: "modern",\n size: "lg",\n circle: false,\n },\n });\n</script>\n',
1033
+ '<template>\n <div :class="styles().base({ class: props.class, color, type, size, circle })">\n <slot :styles="styles().icon({ color, type, size, circle })">\n <Icon :name="icon" :class="styles().icon({ color, type, size, circle })" />\n </slot>\n </div>\n</template>\n\n<script lang="ts" setup>\n const props = withDefaults(\n defineProps<{\n class?: any;\n icon: string;\n color?: VariantProps<typeof styles>["color"];\n type?: VariantProps<typeof styles>["type"];\n size?: VariantProps<typeof styles>["size"];\n circle?: boolean;\n }>(),\n {\n color: "primary",\n type: "modern",\n size: "lg",\n circle: false,\n }\n );\n\n const styles = tv({\n slots: {\n base: "flex shrink-0 items-center justify-center",\n icon: "",\n },\n\n variants: {\n color: {\n primary: {\n base: "",\n icon: "",\n },\n success: {\n base: "",\n icon: "",\n },\n warning: {\n base: "",\n icon: "",\n },\n error: {\n base: "",\n icon: "",\n },\n info: {\n base: "",\n icon: "",\n },\n },\n type: {\n light: {\n base: "",\n icon: "",\n },\n dark: {\n base: "",\n icon: "",\n },\n modern: {\n base: "",\n icon: "",\n },\n },\n size: {\n sm: {\n base: "size-8",\n icon: "size-4",\n },\n md: {\n base: "size-10",\n icon: "size-5",\n },\n lg: {\n base: "size-12",\n icon: "size-6",\n },\n xl: {\n base: "size-14",\n icon: "size-7",\n },\n },\n circle: {\n true: {\n base: "rounded-full",\n },\n false: {\n base: "rounded-lg",\n },\n },\n },\n compoundVariants: [\n {\n color: "primary",\n type: "light",\n class: { base: "bg-primary/5", icon: "text-primary" },\n },\n {\n color: "success",\n type: "light",\n class: {\n base: "bg-green-500/10",\n icon: "text-green-600",\n },\n },\n {\n color: "warning",\n type: "light",\n class: { base: "bg-amber-500/10", icon: "text-amber-600" },\n },\n {\n color: "error",\n type: "light",\n class: { base: "bg-destructive/10", icon: "text-destructive" },\n },\n {\n color: "info",\n type: "light",\n class: { base: "bg-blue-500/10", icon: "text-blue-600" },\n },\n // Dark\n {\n color: "primary",\n type: "dark",\n class: { base: "bg-primary", icon: "text-primary-foreground" },\n },\n {\n color: "success",\n type: "dark",\n class: { base: "bg-green-600", icon: "text-green-50" },\n },\n {\n color: "warning",\n type: "dark",\n class: { base: "bg-amber-600", icon: "text-amber-50" },\n },\n {\n color: "error",\n type: "dark",\n class: { base: "bg-destructive", icon: "text-destructive-foreground" },\n },\n {\n color: "info",\n type: "dark",\n class: { base: "bg-blue-500", icon: "text-blue-50" },\n },\n // Modern\n {\n type: "modern",\n class: { base: "border bg-background", icon: "text-muted-foreground" },\n },\n ],\n defaultVariants: {\n color: "primary",\n type: "modern",\n size: "lg",\n circle: false,\n },\n });\n</script>\n',
1034
1034
  },
1035
1035
  ],
1036
1036
  utils: [],
@@ -1108,7 +1108,7 @@ export default [
1108
1108
  fileName: "HoverCard/Arrow.vue",
1109
1109
  dirPath: "components/UI",
1110
1110
  fileContent:
1111
- '<template>\n <HoverCardArrow :class="styles({ class: props.class })" v-bind="reactiveOmit(props, \'class\')" />\n</template>\n\n<script lang="ts" setup>\n import { HoverCardArrow } from "radix-vue";\n import type { HoverCardArrowProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n HoverCardArrowProps & {\n /** Custom class(es) to add to the parent */\n class?: any;\n }\n >(),\n {\n height: 5,\n width: 10,\n }\n );\n\n const styles = tv({\n base: " fill-popover",\n });\n</script>\n',
1111
+ '<template>\n <HoverCardArrow :class="styles({ class: props.class })" v-bind="reactiveOmit(props, \'class\')" />\n</template>\n\n<script lang="ts" setup>\n import { HoverCardArrow } from "radix-vue";\n import type { HoverCardArrowProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n HoverCardArrowProps & {\n /** Custom class(es) to add to the parent */\n class?: any;\n }\n >(),\n {\n height: 5,\n width: 10,\n }\n );\n\n const styles = tv({\n base: "fill-popover",\n });\n</script>\n',
1112
1112
  },
1113
1113
  {
1114
1114
  fileName: "HoverCard/Content.vue",
@@ -1148,7 +1148,7 @@ export default [
1148
1148
  fileName: "Input.vue",
1149
1149
  dirPath: "components/UI",
1150
1150
  fileContent:
1151
- '<template>\n <input v-bind="props" v-model="localModel" :class="styles({ class: props.class })" />\n</template>\n\n<script lang="ts" setup>\n const props = withDefaults(\n defineProps<{\n class?: any;\n id?: string;\n name?: string;\n placeholder?: string;\n disabled?: boolean;\n required?: boolean;\n type?: string;\n modelValue?: any;\n }>(),\n { type: "text" }\n );\n const emits = defineEmits<{\n "update:modelValue": [value: any];\n }>();\n const localModel = useVModel(props, "modelValue", emits);\n\n const styles = tv({\n base: "form-input h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:px-1 file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground file:hover:cursor-pointer focus:border-input focus:ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm",\n });\n</script>\n',
1151
+ '<template>\n <input v-bind="props" v-model="localModel" :class="styles({ class: props.class })" >\n</template>\n\n<script lang="ts" setup>\n const props = withDefaults(\n defineProps<{\n class?: any;\n id?: string;\n name?: string;\n placeholder?: string;\n disabled?: boolean;\n required?: boolean;\n type?: string;\n modelValue?: any;\n }>(),\n { type: "text" }\n );\n const emits = defineEmits<{\n "update:modelValue": [value: any];\n }>();\n const localModel = useVModel(props, "modelValue", emits);\n\n const styles = tv({\n base: "form-input h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:px-1 file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground file:hover:cursor-pointer focus:border-input focus:ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm",\n });\n</script>\n',
1152
1152
  },
1153
1153
  ],
1154
1154
  utils: [],
@@ -1407,7 +1407,7 @@ export default [
1407
1407
  fileName: "NativeSelect.vue",
1408
1408
  dirPath: "components/UI",
1409
1409
  fileContent:
1410
- '<template>\n <div class="relative">\n <select\n :id="id"\n ref="select"\n v-model="localModel"\n :multiple="multiple"\n :name="name"\n :size="size"\n :placeholder="placeholder"\n :disabled="disabled"\n :required="required"\n :class="styles({ class: props.class })"\n >\n <slot />\n </select>\n <span class="pointer-events-none absolute inset-y-0 right-3 flex items-center justify-center">\n <slot name="trailingIcon">\n <Icon\n :name="trailingIcon || \'lucide:chevrons-up-down\'"\n class="h-4 w-4 text-muted-foreground"\n />\n </slot>\n </span>\n </div>\n</template>\n\n<script lang="ts" setup>\n const props = defineProps<{\n class?: any;\n id?: string;\n name?: string;\n placeholder?: string;\n disabled?: boolean;\n required?: boolean;\n modelValue?: any;\n multiple?: boolean;\n size?: number;\n autofocus?: boolean;\n trailingIcon?: string;\n }>();\n const styles = tv({\n base: "h-10 w-full appearance-none rounded-md border border-input bg-background px-3 py-2 pr-10 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm",\n });\n\n const select = ref<HTMLSelectElement | null>(null);\n const emits = defineEmits<{\n "update:modelValue": [value: any];\n }>();\n\n const localModel = useVModel(props, "modelValue", emits);\n\n onMounted(() => {\n if (props.autofocus) {\n select.value?.focus();\n }\n });\n</script>\n',
1410
+ '<template>\n <div class="relative">\n <select\n :id="id"\n ref="select"\n v-model="localModel"\n :multiple="multiple"\n :name="name"\n :size="size"\n :placeholder="placeholder"\n :disabled="disabled"\n :required="required"\n :class="styles({ class: props.class })"\n >\n <slot />\n </select>\n <span class="pointer-events-none absolute inset-y-0 right-3 flex items-center justify-center">\n <slot name="trailingIcon">\n <Icon\n :name="trailingIcon || \'lucide:chevrons-up-down\'"\n class="h-4 w-4 text-muted-foreground"\n />\n </slot>\n </span>\n </div>\n</template>\n\n<script lang="ts" setup>\n const props = defineProps<{\n class?: any;\n id?: string;\n name?: string;\n placeholder?: string;\n disabled?: boolean;\n required?: boolean;\n modelValue?: any;\n multiple?: boolean;\n size?: number;\n autofocus?: boolean;\n trailingIcon?: string;\n }>();\n const styles = tv({\n base: "h-10 w-full appearance-none rounded-md border border-input bg-background px-3 py-2 pr-10 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm",\n });\n\n const select = ref<HTMLSelectElement | null>(null);\n const emits = defineEmits<{\n "update:modelValue": [value: any];\n }>();\n\n const localModel = useVModel(props, "modelValue", emits);\n\n onMounted(() => {\n if (props.autofocus) {\n select.value?.focus();\n }\n });\n</script>\n',
1411
1411
  },
1412
1412
  ],
1413
1413
  utils: [],
@@ -1492,6 +1492,40 @@ export default [
1492
1492
  composables: [],
1493
1493
  plugins: [],
1494
1494
  },
1495
+ {
1496
+ name: "Number Field",
1497
+ value: "number-field",
1498
+ deps: ["@internationalized/number"],
1499
+ files: [
1500
+ {
1501
+ fileName: "NumberField/Decrement.vue",
1502
+ dirPath: "components/UI",
1503
+ fileContent:
1504
+ '<template>\n <NumberFieldDecrement v-bind="forwarded" :class="styles({ class: props.class })">\n <slot>\n <Icon :name="props.icon" />\n </slot>\n </NumberFieldDecrement>\n</template>\n\n<script lang="ts" setup>\n import { NumberFieldDecrement, useForwardProps } from "radix-vue";\n import type { NumberFieldDecrementProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n NumberFieldDecrementProps & {\n class?: any;\n icon?: string;\n }\n >(),\n { icon: "lucide:minus" }\n );\n\n const forwarded = useForwardProps(reactiveOmit(props, "class"));\n\n const styles = tv({\n base: "flex h-full shrink-0 items-center justify-center bg-transparent p-3 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50",\n });\n</script>\n',
1505
+ },
1506
+ {
1507
+ fileName: "NumberField/Increment.vue",
1508
+ dirPath: "components/UI",
1509
+ fileContent:
1510
+ '<template>\n <NumberFieldIncrement v-bind="forwarded" :class="styles({ class: props.class })">\n <slot>\n <Icon :name="props.icon" />\n </slot>\n </NumberFieldIncrement>\n</template>\n\n<script lang="ts" setup>\n import { NumberFieldIncrement, useForwardProps } from "radix-vue";\n import type { NumberFieldIncrementProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n NumberFieldIncrementProps & {\n class?: any;\n icon?: string;\n }\n >(),\n { icon: "lucide:plus" }\n );\n\n const forwarded = useForwardProps(reactiveOmit(props, "class"));\n\n const styles = tv({\n base: "flex h-full shrink-0 items-center justify-center bg-transparent p-3 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50",\n });\n</script>\n',
1511
+ },
1512
+ {
1513
+ fileName: "NumberField/Input.vue",
1514
+ dirPath: "components/UI",
1515
+ fileContent:
1516
+ '<template>\n <NumberFieldInput v-bind="forwarded" :class="styles({ class: props.class })" />\n</template>\n\n<script lang="ts" setup>\n import { NumberFieldInput, useForwardProps } from "radix-vue";\n import type { NumberFieldInputProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n NumberFieldInputProps & {\n class?: any;\n }\n >(),\n {}\n );\n\n const forwarded = useForwardProps(reactiveOmit(props, "class"));\n\n const styles = tv({\n base: "h-full w-full grow bg-transparent text-center text-base placeholder:text-muted-foreground/80 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm",\n });\n</script>\n',
1517
+ },
1518
+ {
1519
+ fileName: "NumberField/NumberField.vue",
1520
+ dirPath: "components/UI",
1521
+ fileContent:
1522
+ '<template>\n <NumberFieldRoot\n v-slot="rootSlotProps"\n v-bind="forwarded"\n :class="styles({ class: props.class })"\n >\n <slot v-bind="rootSlotProps">\n <slot name="decrement">\n <UiNumberFieldDecrement />\n </slot>\n <slot name="input">\n <UiNumberFieldInput />\n </slot>\n <slot name="increment">\n <UiNumberFieldIncrement />\n </slot>\n </slot>\n </NumberFieldRoot>\n</template>\n\n<script lang="ts" setup>\n import { NumberFieldRoot, useForwardPropsEmits } from "radix-vue";\n import type { NumberFieldRootEmits, NumberFieldRootProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n NumberFieldRootProps & {\n class?: any;\n }\n >(),\n {}\n );\n\n const emit = defineEmits<NumberFieldRootEmits>();\n const forwarded = useForwardPropsEmits(reactiveOmit(props, "class"), emit);\n\n const styles = tv({\n base: "flex h-10 w-full items-center gap-1 rounded-md border border-input bg-background text-base focus-within:border-input focus-within:outline-none focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 focus-within:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm",\n });\n</script>\n',
1523
+ },
1524
+ ],
1525
+ utils: [],
1526
+ composables: [],
1527
+ plugins: [],
1528
+ },
1495
1529
  {
1496
1530
  name: "Pagination",
1497
1531
  value: "pagination",
@@ -1848,7 +1882,7 @@ export default [
1848
1882
  fileName: "Sheet/Content.vue",
1849
1883
  dirPath: "components/UI",
1850
1884
  fileContent:
1851
- '<template>\n <UiSheetPortal :to="to">\n <slot name="overlay">\n <UiSheetOverlay />\n </slot>\n <DialogContent\n :class="styles({ side, class: props.class })"\n v-bind="{ ...forwarded, ...$attrs }"\n >\n <slot>\n <slot name="header">\n <UiSheetHeader>\n <slot name="title">\n <UiSheetTitle v-if="title" :title="title" />\n </slot>\n <slot name="description">\n <UiSheetDescription v-if="description" :description="description" />\n </slot>\n </UiSheetHeader>\n </slot>\n <slot name="content" />\n <slot name="footer" />\n </slot>\n <slot name="close">\n <UiSheetClose :icon="icon" />\n </slot>\n </DialogContent>\n </UiSheetPortal>\n</template>\n\n<script lang="ts" setup>\n import { DialogContent, useForwardPropsEmits } from "radix-vue";\n import type { DialogContentEmits, DialogContentProps } from "radix-vue";\n\n defineOptions({ inheritAttrs: false });\n\n const props = defineProps<\n DialogContentProps & {\n icon?: string;\n title?: string;\n description?: string;\n class?: any;\n side?: VariantProps<typeof styles>["side"];\n to?: string | HTMLElement;\n }\n >();\n const emits = defineEmits<DialogContentEmits>();\n const forwarded = useForwardPropsEmits(\n reactiveOmit(props, "icon", "title", "description", "class", "to", "side"),\n emits\n );\n\n const styles = tv({\n base: "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",\n variants: {\n side: {\n top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",\n bottom:\n "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",\n left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",\n right:\n "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",\n },\n },\n defaultVariants: {\n side: "left",\n },\n });\n</script>\n',
1885
+ '<template>\n <UiSheetPortal :to="to">\n <slot name="overlay">\n <UiSheetOverlay />\n </slot>\n <DialogContent\n :class="styles({ side, class: props.class })"\n v-bind="{ ...forwarded, ...$attrs }"\n >\n <slot>\n <slot name="header">\n <UiSheetHeader>\n <slot name="title">\n <UiSheetTitle v-if="title" :title="title" />\n </slot>\n <slot name="description">\n <UiSheetDescription v-if="description" :description="description" />\n </slot>\n </UiSheetHeader>\n </slot>\n <slot name="content" />\n <slot name="footer" />\n </slot>\n <slot name="close">\n <UiSheetClose :icon="icon" />\n </slot>\n </DialogContent>\n </UiSheetPortal>\n</template>\n\n<script lang="ts" setup>\n import { DialogContent, useForwardPropsEmits } from "radix-vue";\n import type { DialogContentEmits, DialogContentProps } from "radix-vue";\n\n defineOptions({ inheritAttrs: false });\n\n const props = defineProps<\n DialogContentProps & {\n icon?: string;\n title?: string;\n description?: string;\n class?: any;\n side?: VariantProps<typeof styles>["side"];\n to?: string | HTMLElement;\n }\n >();\n const emits = defineEmits<DialogContentEmits>();\n const forwarded = useForwardPropsEmits(\n reactiveOmit(props, "icon", "title", "description", "class", "to", "side"),\n emits\n );\n\n const styles = tv({\n base: "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",\n variants: {\n side: {\n top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",\n bottom:\n "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",\n left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",\n right:\n "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",\n },\n },\n defaultVariants: {\n side: "left",\n },\n });\n</script>\n',
1852
1886
  },
1853
1887
  {
1854
1888
  fileName: "Sheet/Description.vue",
@@ -2088,7 +2122,7 @@ export default [
2088
2122
  fileName: "Tabs/List.vue",
2089
2123
  dirPath: "components/UI",
2090
2124
  fileContent:
2091
- '<template>\n <TabsList :class="styles({ pill, class: props.class })" v-bind="reactiveOmit(props, \'class\')">\n <slot />\n </TabsList>\n</template>\n\n<script lang="ts" setup>\n import { TabsList } from "radix-vue";\n import type { TabsListProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n TabsListProps & {\n /** Custom class(es) to add to parent element */\n class?: any;\n pill?: boolean;\n }\n >(),\n { pill: true }\n );\n\n const styles = tv({\n base: "inline-flex h-10 items-center justify-center rounded-md p-1 text-muted-foreground",\n variants: {\n pill: {\n true: "bg-muted",\n false: "",\n },\n },\n });\n</script>\n',
2125
+ '<template>\n <TabsList :class="styles({ pill, class: props.class })" v-bind="reactiveOmit(props, \'class\')">\n <slot />\n </TabsList>\n</template>\n\n<script lang="ts" setup>\n import { TabsList } from "radix-vue";\n import type { TabsListProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n TabsListProps & {\n /** Custom class(es) to add to parent element */\n class?: any;\n pill?: boolean;\n }\n >(),\n { pill: true }\n );\n\n const styles = tv({\n base: "inline-flex h-10 items-center justify-center rounded-md p-1 text-muted-foreground",\n variants: {\n pill: {\n true: "bg-muted",\n false: "",\n },\n },\n });\n</script>\n',
2092
2126
  },
2093
2127
  {
2094
2128
  fileName: "Tabs/Tabs.vue",
@@ -2100,7 +2134,7 @@ export default [
2100
2134
  fileName: "Tabs/Trigger.vue",
2101
2135
  dirPath: "components/UI",
2102
2136
  fileContent:
2103
- '<template>\n <TabsTrigger v-bind="reactiveOmit(props, \'class\')" :class="styles({ pill, class: props.class })">\n <slot />\n </TabsTrigger>\n</template>\n\n<script lang="ts" setup>\n import { TabsTrigger } from "radix-vue";\n import type { TabsTriggerProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n TabsTriggerProps & {\n /** Custom class(es) to add to parent element */\n class?: any;\n /** Whether the trigger should be pill-shaped */\n pill?: boolean;\n }\n >(),\n {\n pill: true,\n }\n );\n\n const styles = tv({\n base: "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 ",\n variants: {\n pill: {\n true: "data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",\n false:\n "data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none",\n },\n },\n });\n</script>\n',
2137
+ '<template>\n <TabsTrigger v-bind="reactiveOmit(props, \'class\')" :class="styles({ pill, class: props.class })">\n <slot />\n </TabsTrigger>\n</template>\n\n<script lang="ts" setup>\n import { TabsTrigger } from "radix-vue";\n import type { TabsTriggerProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n TabsTriggerProps & {\n /** Custom class(es) to add to parent element */\n class?: any;\n /** Whether the trigger should be pill-shaped */\n pill?: boolean;\n }\n >(),\n {\n pill: true,\n }\n );\n\n const styles = tv({\n base: "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",\n variants: {\n pill: {\n true: "data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",\n false:\n "data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none",\n },\n },\n });\n</script>\n',
2104
2138
  },
2105
2139
  ],
2106
2140
  utils: [],
@@ -2202,13 +2236,13 @@ export default [
2202
2236
  fileName: "Toast/Action.vue",
2203
2237
  dirPath: "components/UI",
2204
2238
  fileContent:
2205
- '<template>\n <ToastAction :class="styles({ class: props.class })" v-bind="reactiveOmit(props, \'class\')">\n <slot />\n </ToastAction>\n</template>\n\n<script lang="ts" setup>\n import { ToastAction } from "radix-vue";\n import type { ToastActionProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n ToastActionProps & {\n /**\n * Custom class names to add to the button.\n */\n class?: any;\n }\n >(),\n {\n altText: "Action button",\n }\n );\n\n const styles = tv({\n base: "inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-xs font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",\n });\n</script>\n',
2239
+ '<template>\n <ToastAction :class="styles({ class: props.class })" v-bind="reactiveOmit(props, \'class\')">\n <slot />\n </ToastAction>\n</template>\n\n<script lang="ts" setup>\n import { ToastAction } from "radix-vue";\n import type { ToastActionProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n ToastActionProps & {\n /**\n * Custom class names to add to the button.\n */\n class?: any;\n }\n >(),\n {\n altText: "Action button",\n }\n );\n\n const styles = tv({\n base: "inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-xs font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",\n });\n</script>\n',
2206
2240
  },
2207
2241
  {
2208
2242
  fileName: "Toast/Close.vue",
2209
2243
  dirPath: "components/UI",
2210
2244
  fileContent:
2211
- '<template>\n <ToastClose :class="styles({ class: props.class })" v-bind="reactiveOmit(props, \'class\', \'icon\')">\n <slot>\n <Icon :name="icon || \'lucide:x\'" class="h-4 w-4" />\n </slot>\n </ToastClose>\n</template>\n\n<script lang="ts" setup>\n import { ToastClose } from "radix-vue";\n import type { ToastCloseProps } from "radix-vue";\n\n const props = defineProps<\n ToastCloseProps & {\n /**\n * Custom class names to add to the button.\n */\n class?: any;\n /**\n * The icon to render.\n */\n icon?: string;\n }\n >();\n\n const styles = tv({\n base: "absolute right-2 top-2 inline-flex items-center justify-center rounded-md p-1 text-foreground/50 opacity-50 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 focus-visible:ring-ring group-hover:opacity-100",\n });\n</script>\n',
2245
+ '<template>\n <ToastClose :class="styles({ class: props.class })" v-bind="reactiveOmit(props, \'class\', \'icon\')">\n <slot>\n <Icon :name="icon || \'lucide:x\'" class="h-4 w-4" />\n </slot>\n </ToastClose>\n</template>\n\n<script lang="ts" setup>\n import { ToastClose } from "radix-vue";\n import type { ToastCloseProps } from "radix-vue";\n\n const props = defineProps<\n ToastCloseProps & {\n /**\n * Custom class names to add to the button.\n */\n class?: any;\n /**\n * The icon to render.\n */\n icon?: string;\n }\n >();\n\n const styles = tv({\n base: "absolute right-2 top-2 inline-flex items-center justify-center rounded-md p-1 text-foreground/50 opacity-50 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 focus-visible:ring-ring group-hover:opacity-100",\n });\n</script>\n',
2212
2246
  },
2213
2247
  {
2214
2248
  fileName: "Toast/Description.vue",
@@ -2244,7 +2278,7 @@ export default [
2244
2278
  fileName: "Toast/Viewport.vue",
2245
2279
  dirPath: "components/UI",
2246
2280
  fileContent:
2247
- '<template>\n <ToastViewport :class="styles({ class: props.class })" v-bind="reactiveOmit(props, \'class\')">\n <slot />\n </ToastViewport>\n</template>\n\n<script lang="ts" setup>\n import { ToastViewport } from "radix-vue";\n import type { ToastViewportProps } from "radix-vue";\n\n const props = defineProps<\n ToastViewportProps & {\n /**\n * Custom class names to add to the button.\n */\n class?: any;\n }\n >();\n\n const styles = tv({\n base: "fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse gap-2 p-4 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring sm:bottom-auto sm:right-0 sm:flex-col md:max-w-[420px]",\n });\n</script>\n\n<style>\n [aria-label~="Notifications"] {\n display: grid;\n }\n</style>\n',
2281
+ '<template>\n <ToastViewport :class="styles({ class: props.class })" v-bind="reactiveOmit(props, \'class\')">\n <slot />\n </ToastViewport>\n</template>\n\n<script lang="ts" setup>\n import { ToastViewport } from "radix-vue";\n import type { ToastViewportProps } from "radix-vue";\n\n const props = defineProps<\n ToastViewportProps & {\n /**\n * Custom class names to add to the button.\n */\n class?: any;\n }\n >();\n\n const styles = tv({\n base: "fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse gap-2 p-4 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring sm:bottom-auto sm:right-0 sm:flex-col md:max-w-[420px]",\n });\n</script>\n\n<style>\n [aria-label~="Notifications"] {\n display: grid;\n }\n</style>\n',
2248
2282
  },
2249
2283
  ],
2250
2284
  utils: [],
@@ -2331,6 +2365,33 @@ export default [
2331
2365
  composables: [],
2332
2366
  plugins: [],
2333
2367
  },
2368
+ {
2369
+ name: "Tree",
2370
+ value: "tree",
2371
+ files: [
2372
+ {
2373
+ fileName: "Tree/Item.vue",
2374
+ dirPath: "components/UI",
2375
+ fileContent:
2376
+ '<template>\n <TreeItem v-slot="slotProps" v-bind="forwarded">\n <slot v-bind="slotProps" />\n </TreeItem>\n</template>\n\n<script lang="ts" setup generic="T extends Record<string, any>">\n import { TreeItem, useForwardPropsEmits } from "radix-vue";\n import type { TreeItemProps } from "radix-vue";\n\n // Remove this when the type is properly exported from radix-vue\n type TreeItemEmits = {\n /**\n * Event handler called when the selecting item.\n *\n * It can be prevented by calling `event.preventDefault`.\n */\n select: [event: any];\n /**\n * Event handler called when the selecting item.\n *\n * It can be prevented by calling `event.preventDefault`.\n */\n toggle: [event: any];\n };\n\n const props = defineProps<TreeItemProps<T>>();\n\n const emit = defineEmits<TreeItemEmits>();\n\n const forwarded = useForwardPropsEmits(props, emit);\n</script>\n',
2377
+ },
2378
+ {
2379
+ fileName: "Tree/Tree.vue",
2380
+ dirPath: "components/UI",
2381
+ fileContent:
2382
+ '<template>\n <TreeRoot v-slot="slotProps" v-bind="forwarded">\n <slot v-bind="slotProps" />\n </TreeRoot>\n</template>\n\n<script lang="ts" setup>\n import { TreeRoot, useForwardPropsEmits } from "radix-vue";\n import type { TreeRootEmits, TreeRootProps } from "radix-vue";\n\n const props = defineProps<TreeRootProps>();\n const emit = defineEmits<TreeRootEmits>();\n\n const forwarded = useForwardPropsEmits(props, emit);\n</script>\n',
2383
+ },
2384
+ {
2385
+ fileName: "Tree/Virtualizer.vue",
2386
+ dirPath: "components/UI",
2387
+ fileContent:
2388
+ '<template>\n <TreeVirtualizer v-slot="slotProps" v-bind="forwarded">\n <slot v-bind="slotProps" />\n </TreeVirtualizer>\n</template>\n\n<script lang="ts" setup>\n import { TreeVirtualizer, useForwardPropsEmits } from "radix-vue";\n import type { TreeVirtualizerProps } from "radix-vue";\n\n const props = defineProps<TreeVirtualizerProps>();\n\n const forwarded = useForwardPropsEmits(props);\n</script>\n',
2389
+ },
2390
+ ],
2391
+ utils: [],
2392
+ composables: [],
2393
+ plugins: [],
2394
+ },
2334
2395
  {
2335
2396
  name: "VeeCheckbox",
2336
2397
  value: "vee-checkbox",
@@ -2464,6 +2525,25 @@ export default [
2464
2525
  composables: [],
2465
2526
  plugins: [],
2466
2527
  },
2528
+ {
2529
+ name: "VeeNumberField",
2530
+ value: "vee-number-field",
2531
+ deps: ["@vee-validate/nuxt", "@morev/vue-transitions", "@internationalized/number"],
2532
+ askValidator: true,
2533
+ nuxtModules: ["@vee-validate/nuxt", "@morev/vue-transitions/nuxt"],
2534
+ components: ["label", "number-field"],
2535
+ files: [
2536
+ {
2537
+ fileName: "Vee/NumberField.vue",
2538
+ dirPath: "components/UI",
2539
+ fileContent:
2540
+ '<template>\n <div class="w-full">\n <UiLabel\n v-if="label"\n :for="inputId"\n :hint="labelHint"\n :class="[disabled && \'text-muted-foreground\', errorMessage && \'text-destructive\', \'mb-2\']"\n ><span>{{ label }} <span v-if="required" class="text-destructive">*</span></span></UiLabel\n >\n <div class="relative">\n <UiNumberField\n v-bind="($attrs, props)"\n :id="inputId"\n v-model="value"\n :disabled="disabled"\n :required="required"\n :name="name"\n >\n <template v-for="(_, slotName) in $slots" #[slotName]="scope">\n <slot :name="slotName" v-bind="scope" />\n </template>\n </UiNumberField>\n </div>\n <TransitionSlide group tag="div">\n <p v-if="hint && !errorMessage" key="hint" class="mt-1.5 text-sm text-muted-foreground">\n {{ hint }}\n </p>\n\n <p v-if="errorMessage" key="errorMessage" class="mt-1.5 text-sm text-destructive">\n {{ errorMessage }}\n </p>\n </TransitionSlide>\n </div>\n</template>\n\n<script lang="ts" setup>\n import type { NumberFieldRootProps } from "radix-vue";\n\n interface Props extends NumberFieldRootProps {\n label?: string;\n labelHint?: string;\n hint?: string;\n disabled?: boolean;\n name?: string;\n id?: string;\n rules?: any;\n validateOnMount?: boolean;\n required?: boolean;\n }\n const props = defineProps<Props>();\n\n const inputId = computed(() => props.id || useId());\n\n const { errorMessage, value } = useField(() => props.name || inputId.value, props.rules, {\n initialValue: props.modelValue,\n label: props.label,\n validateOnMount: props.validateOnMount,\n syncVModel: true,\n });\n</script>\n',
2541
+ },
2542
+ ],
2543
+ utils: [],
2544
+ composables: [],
2545
+ plugins: [],
2546
+ },
2467
2547
  {
2468
2548
  name: "Vee Pin Input",
2469
2549
  value: "vee-pin-input",
package/src/types.ts CHANGED
@@ -4,6 +4,7 @@ export type UIConfig = {
4
4
  tailwindConfigLocation: string;
5
5
  componentsLocation: string;
6
6
  composablesLocation: string;
7
+ pluginsLocation?: string;
7
8
  utilsLocation: string;
8
9
  force: boolean;
9
10
  useDefaultFilename: boolean;
@@ -18,6 +18,7 @@ const defaultConfig = {
18
18
  tailwindConfigLocation: "tailwind.config.js",
19
19
  componentsLocation: "components/Ui",
20
20
  composablesLocation: "composables",
21
+ pluginsLocation: "plugins",
21
22
  utilsLocation: "utils",
22
23
  force: true,
23
24
  useDefaultFilename: true,
@@ -81,6 +82,7 @@ export const getUIConfig = async (options?: InitOptions) => {
81
82
  export const createConfigPaths = (uiConfig: UIConfig) => {
82
83
  // Esnure files exists
83
84
  if (uiConfig.tailwindCSSLocation) fse.ensureFileSync(uiConfig.tailwindConfigLocation);
85
+ if (uiConfig.pluginsLocation) fse.ensureDirSync(uiConfig.pluginsLocation);
84
86
  if (uiConfig.tailwindConfigLocation) fse.ensureFileSync(uiConfig.tailwindCSSLocation);
85
87
  if (uiConfig.componentsLocation) fse.ensureDirSync(uiConfig.componentsLocation);
86
88
  if (uiConfig.composablesLocation) fse.ensureDirSync(uiConfig.composablesLocation);
@@ -35,6 +35,12 @@ export const initPrompts = async () => {
35
35
  message: "Where should your composables be stored?",
36
36
  initial: "composables",
37
37
  },
38
+ {
39
+ name: "pluginsLocation",
40
+ type: "text",
41
+ message: "Where should your plugins be stored?",
42
+ initial: "plugins",
43
+ },
38
44
  {
39
45
  name: "utilsLocation",
40
46
  type: "text",