Skip to content

Commit a8f4019

Browse files
fix(form): fix error when form item not inside <Form> (#1420)
* fix(form): fix error when form item not inside `<Form>` * fix: use fieldContext error without computed cause it's a ref * fix: remove fieldItemContext check cause FormItem is always in the form Anatomy * chore: build registry * chore: build registry v4 --------- Co-authored-by: Sadegh Barati <sadeghbaratiwork@gmail.com>
1 parent 8ded757 commit a8f4019

File tree

14 files changed

+35
-35
lines changed

14 files changed

+35
-35
lines changed

apps/v4/registry/new-york-v4/ui/form/useFormField.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { FieldContextKey, useFieldError, useIsFieldDirty, useIsFieldTouched, useIsFieldValid } from "vee-validate"
2-
import { inject } from "vue"
1+
import { FieldContextKey } from "vee-validate"
2+
import { computed, inject } from "vue"
33
import { FORM_ITEM_INJECTION_KEY } from "./injectionKeys"
44

55
export function useFormField() {
@@ -9,14 +9,14 @@ export function useFormField() {
99
if (!fieldContext)
1010
throw new Error("useFormField should be used within <FormField>")
1111

12-
const { name } = fieldContext
12+
const { name, errorMessage: error, meta } = fieldContext
1313
const id = fieldItemContext
1414

1515
const fieldState = {
16-
valid: useIsFieldValid(name),
17-
isDirty: useIsFieldDirty(name),
18-
isTouched: useIsFieldTouched(name),
19-
error: useFieldError(name),
16+
valid: computed(() => meta.valid),
17+
isDirty: computed(() => meta.dirty),
18+
isTouched: computed(() => meta.touched),
19+
error,
2020
}
2121

2222
return {

apps/www/src/public/r/styles/default/form.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
},
5656
{
5757
"path": "ui/form/useFormField.ts",
58-
"content": "import { FieldContextKey, useFieldError, useIsFieldDirty, useIsFieldTouched, useIsFieldValid } from \"vee-validate\"\r\nimport { inject } from \"vue\"\r\nimport { FORM_ITEM_INJECTION_KEY } from \"./injectionKeys\"\r\n\r\nexport function useFormField() {\r\n const fieldContext = inject(FieldContextKey)\r\n const fieldItemContext = inject(FORM_ITEM_INJECTION_KEY)\r\n\r\n if (!fieldContext)\r\n throw new Error(\"useFormField should be used within <FormField>\")\r\n\r\n const { name } = fieldContext\r\n const id = fieldItemContext\r\n\r\n const fieldState = {\r\n valid: useIsFieldValid(name),\r\n isDirty: useIsFieldDirty(name),\r\n isTouched: useIsFieldTouched(name),\r\n error: useFieldError(name),\r\n }\r\n\r\n return {\r\n id,\r\n name,\r\n formItemId: `${id}-form-item`,\r\n formDescriptionId: `${id}-form-item-description`,\r\n formMessageId: `${id}-form-item-message`,\r\n ...fieldState,\r\n }\r\n}\r\n",
58+
"content": "import { FieldContextKey } from \"vee-validate\"\r\nimport { computed, inject } from \"vue\"\r\nimport { FORM_ITEM_INJECTION_KEY } from \"./injectionKeys\"\r\n\r\nexport function useFormField() {\r\n const fieldContext = inject(FieldContextKey)\r\n const fieldItemContext = inject(FORM_ITEM_INJECTION_KEY)\r\n\r\n if (!fieldContext)\r\n throw new Error(\"useFormField should be used within <FormField>\")\r\n\r\n const { name, errorMessage: error, meta } = fieldContext\r\n const id = fieldItemContext\r\n\r\n const fieldState = {\r\n valid: computed(() => meta.valid),\r\n isDirty: computed(() => meta.dirty),\r\n isTouched: computed(() => meta.touched),\r\n error,\r\n }\r\n\r\n return {\r\n id,\r\n name,\r\n formItemId: `${id}-form-item`,\r\n formDescriptionId: `${id}-form-item-description`,\r\n formMessageId: `${id}-form-item-message`,\r\n ...fieldState,\r\n }\r\n}\r\n",
5959
"type": "registry:ui",
6060
"target": ""
6161
}

apps/www/src/public/r/styles/default/navigation-menu.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
},
5858
{
5959
"path": "ui/navigation-menu/NavigationMenuViewport.vue",
60-
"content": "<script setup lang=\"ts\">\r\nimport type { NavigationMenuViewportProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport {\r\n NavigationMenuViewport,\r\n\r\n useForwardProps,\r\n} from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<NavigationMenuViewportProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n\r\nconst forwardedProps = useForwardProps(delegatedProps)\r\n</script>\r\n\r\n<template>\r\n <div class=\"absolute left-0 top-full flex justify-center\">\r\n <NavigationMenuViewport\r\n v-bind=\"forwardedProps\"\r\n :class=\"\r\n cn(\r\n 'origin-top-center relative mt-1.5 h-[--reka-navigation-menu-viewport-height] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[--reka-navigation-menu-viewport-width]',\r\n props.class,\r\n )\r\n \"\r\n />\r\n </div>\r\n</template>\r\n",
60+
"content": "<script setup lang=\"ts\">\r\nimport type { NavigationMenuViewportProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport {\r\n NavigationMenuViewport,\r\n\r\n useForwardProps,\r\n} from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<NavigationMenuViewportProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n\r\nconst forwardedProps = useForwardProps(delegatedProps)\r\n</script>\r\n\r\n<template>\r\n <div class=\"absolute left-0 top-full flex justify-center\">\r\n <NavigationMenuViewport\r\n v-bind=\"forwardedProps\"\r\n :class=\"\r\n cn(\r\n 'origin-top-center relative mt-1.5 h-[--reka-navigation-menu-viewport-height] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[--reka-navigation-menu-viewport-width] left-[var(--reka-navigation-menu-viewport-left)]',\r\n props.class,\r\n )\r\n \"\r\n />\r\n </div>\r\n</template>\r\n",
6161
"type": "registry:ui",
6262
"target": ""
6363
}

apps/www/src/public/r/styles/new-york-v4/chart-area.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"files": [
1414
{
1515
"path": "ui/chart-area/AreaChart.vue",
16-
"content": "<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\r\nimport type { BaseChartProps } from \".\"\r\nimport { type BulletLegendItemInterface, CurveType } from \"@unovis/ts\"\r\nimport { Area, Axis, Line } from \"@unovis/ts\"\r\nimport { VisArea, VisAxis, VisLine, VisXYContainer } from \"@unovis/vue\"\r\nimport { useMounted } from \"@vueuse/core\"\r\nimport { useId } from \"reka-ui\"\r\nimport { type Component, computed, ref } from \"vue\"\r\nimport { cn } from \"@/lib/utils\"\r\nimport { ChartCrosshair, ChartLegend, defaultColors } from \"@/registry/new-york/ui/chart\"\r\n\r\nconst props = withDefaults(defineProps<BaseChartProps<T> & {\r\n /**\r\n * Render custom tooltip component.\r\n */\r\n customTooltip?: Component\r\n /**\r\n * Type of curve\r\n */\r\n curveType?: CurveType\r\n /**\r\n * Controls the visibility of gradient.\r\n * @default true\r\n */\r\n showGradient?: boolean\r\n}>(), {\r\n curveType: CurveType.MonotoneX,\r\n filterOpacity: 0.2,\r\n margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),\r\n showXAxis: true,\r\n showYAxis: true,\r\n showTooltip: true,\r\n showLegend: true,\r\n showGridLine: true,\r\n showGradient: true,\r\n})\r\n\r\nconst emits = defineEmits<{\r\n legendItemClick: [d: BulletLegendItemInterface, i: number]\r\n}>()\r\n\r\ntype KeyOfT = Extract<keyof T, string>\r\ntype Data = typeof props.data[number]\r\n\r\nconst chartRef = useId()\r\n\r\nconst index = computed(() => props.index as KeyOfT)\r\nconst colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.categories.length))\r\n\r\nconst legendItems = ref<BulletLegendItemInterface[]>(props.categories.map((category, i) => ({\r\n name: category,\r\n color: colors.value[i],\r\n inactive: false,\r\n})))\r\n\r\nconst isMounted = useMounted()\r\n\r\nfunction handleLegendItemClick(d: BulletLegendItemInterface, i: number) {\r\n emits(\"legendItemClick\", d, i)\r\n}\r\n</script>\r\n\r\n<template>\r\n <div :class=\"cn('w-full h-[400px] flex flex-col items-end', $attrs.class ?? '')\">\r\n <ChartLegend v-if=\"showLegend\" v-model:items=\"legendItems\" @legend-item-click=\"handleLegendItemClick\" />\r\n\r\n <VisXYContainer :style=\"{ height: isMounted ? '100%' : 'auto' }\" :margin=\"{ left: 20, right: 20 }\" :data=\"data\">\r\n <svg width=\"0\" height=\"0\">\r\n <defs>\r\n <linearGradient v-for=\"(color, i) in colors\" :id=\"`${chartRef}-color-${i}`\" :key=\"i\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\r\n <template v-if=\"showGradient\">\r\n <stop offset=\"5%\" :stop-color=\"color\" stop-opacity=\"0.4\" />\r\n <stop offset=\"95%\" :stop-color=\"color\" stop-opacity=\"0\" />\r\n </template>\r\n <template v-else>\r\n <stop offset=\"0%\" :stop-color=\"color\" />\r\n </template>\r\n </linearGradient>\r\n </defs>\r\n </svg>\r\n\r\n <ChartCrosshair v-if=\"showTooltip\" :colors=\"colors\" :items=\"legendItems\" :index=\"index\" :custom-tooltip=\"customTooltip\" />\r\n\r\n <template v-for=\"(category, i) in categories\" :key=\"category\">\r\n <VisArea\r\n :x=\"(d: Data, i: number) => i\"\r\n :y=\"(d: Data) => d[category]\"\r\n color=\"auto\"\r\n :curve-type=\"curveType\"\r\n :attributes=\"{\r\n [Area.selectors.area]: {\r\n fill: `url(#${chartRef}-color-${i})`,\r\n },\r\n }\"\r\n :opacity=\"legendItems.find(item => item.name === category)?.inactive ? filterOpacity : 1\"\r\n />\r\n </template>\r\n\r\n <template v-for=\"(category, i) in categories\" :key=\"category\">\r\n <VisLine\r\n :x=\"(d: Data, i: number) => i\"\r\n :y=\"(d: Data) => d[category]\"\r\n :color=\"colors[i]\"\r\n :curve-type=\"curveType\"\r\n :attributes=\"{\r\n [Line.selectors.line]: {\r\n opacity: legendItems.find(item => item.name === category)?.inactive ? filterOpacity : 1,\r\n },\r\n }\"\r\n />\r\n </template>\r\n\r\n <VisAxis\r\n v-if=\"showXAxis\"\r\n type=\"x\"\r\n :tick-format=\"xFormatter ?? ((v: number) => data[v]?.[index])\"\r\n :grid-line=\"false\"\r\n :tick-line=\"false\"\r\n tick-text-color=\"hsl(var(--vis-text-color))\"\r\n />\r\n <VisAxis\r\n v-if=\"showYAxis\"\r\n type=\"y\"\r\n :tick-line=\"false\"\r\n :tick-format=\"yFormatter\"\r\n :domain-line=\"false\"\r\n :grid-line=\"showGridLine\"\r\n :attributes=\"{\r\n [Axis.selectors.grid]: {\r\n class: 'text-muted',\r\n },\r\n }\"\r\n tick-text-color=\"hsl(var(--vis-text-color))\"\r\n />\r\n\r\n <slot />\r\n </VisXYContainer>\r\n </div>\r\n</template>\r\n",
16+
"content": "<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\r\nimport type { BulletLegendItemInterface } from \"@unovis/ts\"\r\nimport type { Component } from \"vue\"\r\nimport type { BaseChartProps } from \".\"\r\nimport { Area, Axis, CurveType, Line } from \"@unovis/ts\"\r\n\r\nimport { VisArea, VisAxis, VisLine, VisXYContainer } from \"@unovis/vue\"\r\nimport { useMounted } from \"@vueuse/core\"\r\nimport { useId } from \"reka-ui\"\r\nimport { computed, ref } from \"vue\"\r\nimport { cn } from \"@/lib/utils\"\r\nimport { ChartCrosshair, ChartLegend, defaultColors } from \"@/registry/new-york/ui/chart\"\r\n\r\nconst props = withDefaults(defineProps<BaseChartProps<T> & {\r\n /**\r\n * Render custom tooltip component.\r\n */\r\n customTooltip?: Component\r\n /**\r\n * Type of curve\r\n */\r\n curveType?: CurveType\r\n /**\r\n * Controls the visibility of gradient.\r\n * @default true\r\n */\r\n showGradient?: boolean\r\n}>(), {\r\n curveType: CurveType.MonotoneX,\r\n filterOpacity: 0.2,\r\n margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),\r\n showXAxis: true,\r\n showYAxis: true,\r\n showTooltip: true,\r\n showLegend: true,\r\n showGridLine: true,\r\n showGradient: true,\r\n})\r\n\r\nconst emits = defineEmits<{\r\n legendItemClick: [d: BulletLegendItemInterface, i: number]\r\n}>()\r\n\r\ntype KeyOfT = Extract<keyof T, string>\r\ntype Data = typeof props.data[number]\r\n\r\nconst chartRef = useId()\r\n\r\nconst index = computed(() => props.index as KeyOfT)\r\nconst colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.categories.length))\r\n\r\nconst legendItems = ref<BulletLegendItemInterface[]>(props.categories.map((category, i) => ({\r\n name: category,\r\n color: colors.value[i],\r\n inactive: false,\r\n})))\r\n\r\nconst isMounted = useMounted()\r\n\r\nfunction handleLegendItemClick(d: BulletLegendItemInterface, i: number) {\r\n emits(\"legendItemClick\", d, i)\r\n}\r\n</script>\r\n\r\n<template>\r\n <div :class=\"cn('w-full h-[400px] flex flex-col items-end', $attrs.class ?? '')\">\r\n <ChartLegend v-if=\"showLegend\" v-model:items=\"legendItems\" @legend-item-click=\"handleLegendItemClick\" />\r\n\r\n <VisXYContainer :style=\"{ height: isMounted ? '100%' : 'auto' }\" :margin=\"{ left: 20, right: 20 }\" :data=\"data\">\r\n <svg width=\"0\" height=\"0\">\r\n <defs>\r\n <linearGradient v-for=\"(color, i) in colors\" :id=\"`${chartRef}-color-${i}`\" :key=\"i\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\r\n <template v-if=\"showGradient\">\r\n <stop offset=\"5%\" :stop-color=\"color\" stop-opacity=\"0.4\" />\r\n <stop offset=\"95%\" :stop-color=\"color\" stop-opacity=\"0\" />\r\n </template>\r\n <template v-else>\r\n <stop offset=\"0%\" :stop-color=\"color\" />\r\n </template>\r\n </linearGradient>\r\n </defs>\r\n </svg>\r\n\r\n <ChartCrosshair v-if=\"showTooltip\" :colors=\"colors\" :items=\"legendItems\" :index=\"index\" :custom-tooltip=\"customTooltip\" />\r\n\r\n <template v-for=\"(category, i) in categories\" :key=\"category\">\r\n <VisArea\r\n :x=\"(d: Data, i: number) => i\"\r\n :y=\"(d: Data) => d[category]\"\r\n color=\"auto\"\r\n :curve-type=\"curveType\"\r\n :attributes=\"{\r\n [Area.selectors.area]: {\r\n fill: `url(#${chartRef}-color-${i})`,\r\n },\r\n }\"\r\n :opacity=\"legendItems.find(item => item.name === category)?.inactive ? filterOpacity : 1\"\r\n />\r\n </template>\r\n\r\n <template v-for=\"(category, i) in categories\" :key=\"category\">\r\n <VisLine\r\n :x=\"(d: Data, i: number) => i\"\r\n :y=\"(d: Data) => d[category]\"\r\n :color=\"colors[i]\"\r\n :curve-type=\"curveType\"\r\n :attributes=\"{\r\n [Line.selectors.line]: {\r\n opacity: legendItems.find(item => item.name === category)?.inactive ? filterOpacity : 1,\r\n },\r\n }\"\r\n />\r\n </template>\r\n\r\n <VisAxis\r\n v-if=\"showXAxis\"\r\n type=\"x\"\r\n :tick-format=\"xFormatter ?? ((v: number) => data[v]?.[index])\"\r\n :grid-line=\"false\"\r\n :tick-line=\"false\"\r\n tick-text-color=\"hsl(var(--vis-text-color))\"\r\n />\r\n <VisAxis\r\n v-if=\"showYAxis\"\r\n type=\"y\"\r\n :tick-line=\"false\"\r\n :tick-format=\"yFormatter\"\r\n :domain-line=\"false\"\r\n :grid-line=\"showGridLine\"\r\n :attributes=\"{\r\n [Axis.selectors.grid]: {\r\n class: 'text-muted',\r\n },\r\n }\"\r\n tick-text-color=\"hsl(var(--vis-text-color))\"\r\n />\r\n\r\n <slot />\r\n </VisXYContainer>\r\n </div>\r\n</template>\r\n",
1717
"type": "registry:ui",
1818
"target": ""
1919
},

0 commit comments

Comments
 (0)