@bitrix24/b24ui-nuxt 0.5.10 → 0.5.11

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 (190) hide show
  1. package/dist/meta.cjs +72112 -0
  2. package/dist/meta.d.cts +72110 -0
  3. package/dist/meta.d.mts +5060 -5060
  4. package/dist/meta.d.ts +72110 -0
  5. package/dist/meta.mjs +5060 -5060
  6. package/dist/module.cjs +63 -0
  7. package/dist/module.d.cts +15 -0
  8. package/dist/module.d.ts +15 -0
  9. package/dist/module.json +3 -3
  10. package/dist/module.mjs +1 -1
  11. package/dist/runtime/components/Advice.vue +54 -47
  12. package/dist/runtime/components/Alert.vue +96 -71
  13. package/dist/runtime/components/App.vue +34 -37
  14. package/dist/runtime/components/Avatar.vue +81 -69
  15. package/dist/runtime/components/AvatarGroup.vue +76 -53
  16. package/dist/runtime/components/Badge.vue +83 -83
  17. package/dist/runtime/components/Button.vue +157 -220
  18. package/dist/runtime/components/ButtonGroup.vue +51 -35
  19. package/dist/runtime/components/Calendar.vue +152 -186
  20. package/dist/runtime/components/Checkbox.vue +73 -84
  21. package/dist/runtime/components/Chip.vue +74 -59
  22. package/dist/runtime/components/Collapsible.vue +41 -44
  23. package/dist/runtime/components/Container.vue +27 -18
  24. package/dist/runtime/components/Countdown.vue +378 -198
  25. package/dist/runtime/components/DescriptionList.vue +149 -102
  26. package/dist/runtime/components/DropdownMenu.vue +139 -83
  27. package/dist/runtime/components/DropdownMenuContent.vue +84 -137
  28. package/dist/runtime/components/Form.vue +216 -162
  29. package/dist/runtime/components/FormField.vue +80 -76
  30. package/dist/runtime/components/Input.vue +179 -160
  31. package/dist/runtime/components/InputMenu.vue +380 -300
  32. package/dist/runtime/components/InputNumber.vue +175 -178
  33. package/dist/runtime/components/Kbd.vue +45 -33
  34. package/dist/runtime/components/Link.vue +173 -179
  35. package/dist/runtime/components/LinkBase.vue +42 -64
  36. package/dist/runtime/components/Modal.vue +127 -105
  37. package/dist/runtime/components/ModalDialogClose.vue +8 -4
  38. package/dist/runtime/components/Navbar.vue +33 -24
  39. package/dist/runtime/components/NavbarDivider.vue +33 -24
  40. package/dist/runtime/components/NavbarSection.vue +33 -24
  41. package/dist/runtime/components/NavbarSpacer.vue +33 -24
  42. package/dist/runtime/components/NavigationMenu.vue +210 -144
  43. package/dist/runtime/components/OverlayProvider.vue +17 -13
  44. package/dist/runtime/components/Popover.vue +81 -81
  45. package/dist/runtime/components/Progress.vue +136 -109
  46. package/dist/runtime/components/RadioGroup.vue +134 -120
  47. package/dist/runtime/components/Range.vue +85 -94
  48. package/dist/runtime/components/Select.vue +260 -212
  49. package/dist/runtime/components/SelectMenu.vue +365 -272
  50. package/dist/runtime/components/Separator.vue +71 -61
  51. package/dist/runtime/components/Sidebar.vue +33 -24
  52. package/dist/runtime/components/SidebarBody.vue +38 -30
  53. package/dist/runtime/components/SidebarFooter.vue +33 -24
  54. package/dist/runtime/components/SidebarHeader.vue +33 -24
  55. package/dist/runtime/components/SidebarHeading.vue +33 -24
  56. package/dist/runtime/components/SidebarLayout.vue +70 -40
  57. package/dist/runtime/components/SidebarSection.vue +33 -24
  58. package/dist/runtime/components/SidebarSpacer.vue +33 -24
  59. package/dist/runtime/components/Skeleton.vue +22 -17
  60. package/dist/runtime/components/Slideover.vue +131 -108
  61. package/dist/runtime/components/StackedLayout.vue +73 -40
  62. package/dist/runtime/components/Switch.vue +95 -100
  63. package/dist/runtime/components/Tabs.vue +107 -81
  64. package/dist/runtime/components/Textarea.vue +201 -177
  65. package/dist/runtime/components/Toast.vue +105 -94
  66. package/dist/runtime/components/Toaster.vue +116 -94
  67. package/dist/runtime/components/Tooltip.vue +64 -78
  68. package/dist/runtime/components/content/TableWrapper.vue +70 -58
  69. package/dist/runtime/composables/useAvatarGroup.d.ts +1 -1
  70. package/dist/runtime/composables/useButtonGroup.d.ts +2 -2
  71. package/dist/runtime/composables/useComponentIcons.d.ts +3 -3
  72. package/dist/runtime/composables/useFormField.d.ts +1 -1
  73. package/dist/runtime/prose/A.vue +23 -18
  74. package/dist/runtime/prose/Blockquote.vue +23 -18
  75. package/dist/runtime/prose/Code.vue +31 -23
  76. package/dist/runtime/prose/Em.vue +23 -18
  77. package/dist/runtime/prose/H1.vue +23 -18
  78. package/dist/runtime/prose/H2.vue +23 -18
  79. package/dist/runtime/prose/H3.vue +23 -18
  80. package/dist/runtime/prose/H4.vue +23 -18
  81. package/dist/runtime/prose/H5.vue +23 -18
  82. package/dist/runtime/prose/H6.vue +23 -18
  83. package/dist/runtime/prose/Hr.vue +19 -18
  84. package/dist/runtime/prose/Img.vue +23 -18
  85. package/dist/runtime/prose/Li.vue +23 -18
  86. package/dist/runtime/prose/Ol.vue +23 -18
  87. package/dist/runtime/prose/P.vue +23 -18
  88. package/dist/runtime/prose/Pre.vue +33 -28
  89. package/dist/runtime/prose/Strong.vue +23 -18
  90. package/dist/runtime/prose/Table.vue +54 -44
  91. package/dist/runtime/prose/Tbody.vue +23 -18
  92. package/dist/runtime/prose/Td.vue +23 -18
  93. package/dist/runtime/prose/Th.vue +23 -18
  94. package/dist/runtime/prose/Thead.vue +23 -18
  95. package/dist/runtime/prose/Tr.vue +23 -18
  96. package/dist/runtime/prose/Ul.vue +23 -18
  97. package/dist/runtime/vue/components/Link.vue +202 -201
  98. package/dist/shared/b24ui-nuxt.DrKwIWoc.cjs +7721 -0
  99. package/dist/types.d.mts +5 -3
  100. package/dist/types.d.ts +7 -0
  101. package/dist/unplugin.cjs +236 -0
  102. package/dist/unplugin.d.cts +33 -0
  103. package/dist/unplugin.d.ts +33 -0
  104. package/dist/vite.cjs +21 -0
  105. package/dist/vite.d.cts +14 -0
  106. package/dist/vite.d.ts +14 -0
  107. package/package.json +25 -13
  108. package/dist/runtime/components/Advice.vue.d.ts +0 -170
  109. package/dist/runtime/components/Alert.vue.d.ts +0 -464
  110. package/dist/runtime/components/App.vue.d.ts +0 -23
  111. package/dist/runtime/components/Avatar.vue.d.ts +0 -281
  112. package/dist/runtime/components/AvatarGroup.vue.d.ts +0 -204
  113. package/dist/runtime/components/Badge.vue.d.ts +0 -517
  114. package/dist/runtime/components/Button.vue.d.ts +0 -640
  115. package/dist/runtime/components/ButtonGroup.vue.d.ts +0 -116
  116. package/dist/runtime/components/Calendar.vue.d.ts +0 -437
  117. package/dist/runtime/components/Checkbox.vue.d.ts +0 -354
  118. package/dist/runtime/components/Chip.vue.d.ts +0 -271
  119. package/dist/runtime/components/Collapsible.vue.d.ts +0 -118
  120. package/dist/runtime/components/Container.vue.d.ts +0 -27
  121. package/dist/runtime/components/Countdown.vue.d.ts +0 -356
  122. package/dist/runtime/components/DescriptionList.vue.d.ts +0 -379
  123. package/dist/runtime/components/DropdownMenu.vue.d.ts +0 -533
  124. package/dist/runtime/components/DropdownMenuContent.vue.d.ts +0 -228
  125. package/dist/runtime/components/Form.vue.d.ts +0 -55
  126. package/dist/runtime/components/FormField.vue.d.ts +0 -282
  127. package/dist/runtime/components/Input.vue.d.ts +0 -755
  128. package/dist/runtime/components/InputMenu.vue.d.ts +0 -1504
  129. package/dist/runtime/components/InputNumber.vue.d.ts +0 -658
  130. package/dist/runtime/components/Kbd.vue.d.ts +0 -109
  131. package/dist/runtime/components/Link.vue.d.ts +0 -129
  132. package/dist/runtime/components/LinkBase.vue.d.ts +0 -48
  133. package/dist/runtime/components/Modal.vue.d.ts +0 -327
  134. package/dist/runtime/components/ModalDialogClose.vue.d.ts +0 -10
  135. package/dist/runtime/components/Navbar.vue.d.ts +0 -101
  136. package/dist/runtime/components/NavbarDivider.vue.d.ts +0 -101
  137. package/dist/runtime/components/NavbarSection.vue.d.ts +0 -101
  138. package/dist/runtime/components/NavbarSpacer.vue.d.ts +0 -101
  139. package/dist/runtime/components/NavigationMenu.vue.d.ts +0 -824
  140. package/dist/runtime/components/OverlayProvider.vue.d.ts +0 -2
  141. package/dist/runtime/components/Popover.vue.d.ts +0 -147
  142. package/dist/runtime/components/Progress.vue.d.ts +0 -592
  143. package/dist/runtime/components/RadioGroup.vue.d.ts +0 -723
  144. package/dist/runtime/components/Range.vue.d.ts +0 -417
  145. package/dist/runtime/components/Select.vue.d.ts +0 -1200
  146. package/dist/runtime/components/SelectMenu.vue.d.ts +0 -1298
  147. package/dist/runtime/components/Separator.vue.d.ts +0 -400
  148. package/dist/runtime/components/Sidebar.vue.d.ts +0 -101
  149. package/dist/runtime/components/SidebarBody.vue.d.ts +0 -90
  150. package/dist/runtime/components/SidebarFooter.vue.d.ts +0 -101
  151. package/dist/runtime/components/SidebarHeader.vue.d.ts +0 -101
  152. package/dist/runtime/components/SidebarHeading.vue.d.ts +0 -101
  153. package/dist/runtime/components/SidebarLayout.vue.d.ts +0 -222
  154. package/dist/runtime/components/SidebarSection.vue.d.ts +0 -101
  155. package/dist/runtime/components/SidebarSpacer.vue.d.ts +0 -101
  156. package/dist/runtime/components/Skeleton.vue.d.ts +0 -26
  157. package/dist/runtime/components/Slideover.vue.d.ts +0 -360
  158. package/dist/runtime/components/StackedLayout.vue.d.ts +0 -192
  159. package/dist/runtime/components/Switch.vue.d.ts +0 -587
  160. package/dist/runtime/components/Tabs.vue.d.ts +0 -453
  161. package/dist/runtime/components/Textarea.vue.d.ts +0 -601
  162. package/dist/runtime/components/Toast.vue.d.ts +0 -438
  163. package/dist/runtime/components/Toaster.vue.d.ts +0 -219
  164. package/dist/runtime/components/Tooltip.vue.d.ts +0 -186
  165. package/dist/runtime/components/content/TableWrapper.vue.d.ts +0 -237
  166. package/dist/runtime/prose/A.vue.d.ts +0 -84
  167. package/dist/runtime/prose/Blockquote.vue.d.ts +0 -84
  168. package/dist/runtime/prose/Code.vue.d.ts +0 -97
  169. package/dist/runtime/prose/Em.vue.d.ts +0 -84
  170. package/dist/runtime/prose/H1.vue.d.ts +0 -97
  171. package/dist/runtime/prose/H2.vue.d.ts +0 -123
  172. package/dist/runtime/prose/H3.vue.d.ts +0 -123
  173. package/dist/runtime/prose/H4.vue.d.ts +0 -123
  174. package/dist/runtime/prose/H5.vue.d.ts +0 -123
  175. package/dist/runtime/prose/H6.vue.d.ts +0 -123
  176. package/dist/runtime/prose/Hr.vue.d.ts +0 -74
  177. package/dist/runtime/prose/Img.vue.d.ts +0 -77
  178. package/dist/runtime/prose/Li.vue.d.ts +0 -84
  179. package/dist/runtime/prose/Ol.vue.d.ts +0 -84
  180. package/dist/runtime/prose/P.vue.d.ts +0 -84
  181. package/dist/runtime/prose/Pre.vue.d.ts +0 -117
  182. package/dist/runtime/prose/Strong.vue.d.ts +0 -84
  183. package/dist/runtime/prose/Table.vue.d.ts +0 -144
  184. package/dist/runtime/prose/Tbody.vue.d.ts +0 -84
  185. package/dist/runtime/prose/Td.vue.d.ts +0 -84
  186. package/dist/runtime/prose/Th.vue.d.ts +0 -84
  187. package/dist/runtime/prose/Thead.vue.d.ts +0 -84
  188. package/dist/runtime/prose/Tr.vue.d.ts +0 -84
  189. package/dist/runtime/prose/Ul.vue.d.ts +0 -84
  190. package/dist/runtime/vue/components/Link.vue.d.ts +0 -129
@@ -1,231 +1,285 @@
1
- <script>
2
- import _appConfig from "#build/app.config";
3
- import theme from "#build/b24ui/form";
4
- import { tv } from "../utils/tv";
5
- const appConfigForm = _appConfig;
6
- const form = tv({ extend: tv(theme), ...appConfigForm.b24ui?.form || {} });
1
+ <script lang="ts">
2
+ import type { AppConfig } from '@nuxt/schema'
3
+ import _appConfig from '#build/app.config'
4
+ import theme from '#build/b24ui/form'
5
+ import { tv } from '../utils/tv'
6
+ import type { FormSchema, FormError, FormInputEvents, FormErrorEvent, FormSubmitEvent, FormEvent, Form, FormErrorWithId } from '../types/form'
7
+ import type { DeepReadonly } from 'vue'
8
+
9
+ const appConfigForm = _appConfig as AppConfig & { b24ui: { form: Partial<typeof theme> } }
10
+
11
+ const form = tv({ extend: tv(theme), ...(appConfigForm.b24ui?.form || {}) })
12
+
13
+ export interface FormProps<T extends object> {
14
+ id?: string | number
15
+ /** Schema to validate the form state. Supports Standard Schema objects, Yup, Joi, and Superstructs. */
16
+ schema?: FormSchema<T>
17
+ /** An object representing the current state of the form. */
18
+ state: Partial<T>
19
+ /**
20
+ * Custom validation function to validate the form state.
21
+ * @param state - The current state of the form.
22
+ * @returns A promise that resolves to an array of FormError objects, or an array of FormError objects directly.
23
+ */
24
+ validate?: (state: Partial<T>) => Promise<FormError[]> | FormError[]
25
+ /**
26
+ * The list of input events that trigger the form validation.
27
+ * @defaultValue `['blur', 'change', 'input']`
28
+ */
29
+ validateOn?: FormInputEvents[]
30
+ /** Disable all inputs inside the form. */
31
+ disabled?: boolean
32
+ /**
33
+ * Delay in milliseconds before validating the form on input events.
34
+ * @defaultValue `300`
35
+ */
36
+ validateOnInputDelay?: number
37
+ /**
38
+ * If true, schema transformations will be applied to the state on submit.
39
+ * @defaultValue `true`
40
+ */
41
+ transform?: boolean
42
+ class?: any
43
+ onSubmit?: ((event: FormSubmitEvent<T>) => void | Promise<void>) | (() => void | Promise<void>)
44
+ }
45
+
46
+ export interface FormEmits<T extends object> {
47
+ (e: 'submit', payload: FormSubmitEvent<T>): void
48
+ (e: 'error', payload: FormErrorEvent): void
49
+ }
50
+
51
+ export interface FormSlots {
52
+ default(props?: { errors: FormError[] }): any
53
+ }
7
54
  </script>
8
55
 
9
- <script setup>
10
- import { provide, inject, nextTick, ref, onUnmounted, onMounted, computed, useId, readonly } from "vue";
11
- import { useEventBus } from "@vueuse/core";
12
- import { formOptionsInjectionKey, formInputsInjectionKey, formBusInjectionKey, formLoadingInjectionKey } from "../composables/useFormField";
13
- import { validateSchema } from "../utils/form";
14
- import { FormValidationException } from "../types/form";
15
- const props = defineProps({
16
- id: {
17
- type: [String, Number],
18
- required: false
19
- },
20
- schema: {
21
- type: null,
22
- required: false
23
- },
24
- state: {
25
- type: Object,
26
- required: true
27
- },
28
- validate: {
29
- type: Function,
30
- required: false
31
- },
32
- validateOn: {
33
- type: Array,
34
- required: false,
35
- default() {
36
- return ["input", "blur", "change"];
37
- }
38
- },
39
- disabled: {
40
- type: Boolean,
41
- required: false
42
- },
43
- validateOnInputDelay: {
44
- type: Number,
45
- required: false,
46
- default: 300
47
- },
48
- transform: {
49
- type: Boolean,
50
- required: false,
51
- default: true
52
- },
53
- class: {
54
- type: null,
55
- required: false
56
+ <script lang="ts" setup generic="T extends object">
57
+ import { provide, inject, nextTick, ref, onUnmounted, onMounted, computed, useId, readonly } from 'vue'
58
+ import { useEventBus } from '@vueuse/core'
59
+ import { formOptionsInjectionKey, formInputsInjectionKey, formBusInjectionKey, formLoadingInjectionKey } from '../composables/useFormField'
60
+ import { validateSchema } from '../utils/form'
61
+ import { FormValidationException } from '../types/form'
62
+
63
+ const props = withDefaults(defineProps<FormProps<T>>(), {
64
+ validateOn() {
65
+ return ['input', 'blur', 'change'] as FormInputEvents[]
56
66
  },
57
- onSubmit: {
58
- type: Function,
59
- required: false
60
- }
61
- });
62
- const emits = defineEmits(["submit", "error"]);
63
- defineSlots();
64
- const formId = props.id ?? useId();
65
- const bus = useEventBus(`form-${formId}`);
67
+ validateOnInputDelay: 300,
68
+ transform: true
69
+ })
70
+ const emits = defineEmits<FormEmits<T>>()
71
+ defineSlots<FormSlots>()
72
+
73
+ const formId = props.id ?? useId() as string
74
+
75
+ const bus = useEventBus<FormEvent<T>>(`form-${formId}`)
66
76
  const parentBus = inject(
67
77
  formBusInjectionKey,
68
- void 0
69
- );
70
- provide(formBusInjectionKey, bus);
71
- const nestedForms = ref(/* @__PURE__ */ new Map());
78
+ undefined
79
+ )
80
+
81
+ provide(formBusInjectionKey, bus)
82
+
83
+ const nestedForms = ref<Map<string | number, { validate: typeof _validate }>>(new Map())
84
+
72
85
  onMounted(async () => {
73
86
  bus.on(async (event) => {
74
- if (event.type === "attach") {
75
- nestedForms.value.set(event.formId, { validate: event.validate });
76
- } else if (event.type === "detach") {
77
- nestedForms.value.delete(event.formId);
87
+ if (event.type === 'attach') {
88
+ nestedForms.value.set(event.formId, { validate: event.validate })
89
+ } else if (event.type === 'detach') {
90
+ nestedForms.value.delete(event.formId)
78
91
  } else if (props.validateOn?.includes(event.type) && !loading.value) {
79
- if (event.type !== "input") {
80
- await _validate({ name: event.name, silent: true, nested: false });
92
+ if (event.type !== 'input') {
93
+ await _validate({ name: event.name, silent: true, nested: false })
81
94
  } else if (event.eager || blurredFields.has(event.name)) {
82
- await _validate({ name: event.name, silent: true, nested: false });
95
+ await _validate({ name: event.name, silent: true, nested: false })
83
96
  }
84
97
  }
85
- if (event.type === "blur") {
86
- blurredFields.add(event.name);
98
+
99
+ if (event.type === 'blur') {
100
+ blurredFields.add(event.name)
87
101
  }
88
- if (event.type === "change" || event.type === "input" || event.type === "blur" || event.type === "focus") {
89
- touchedFields.add(event.name);
102
+
103
+ if (event.type === 'change' || event.type === 'input' || event.type === 'blur' || event.type === 'focus') {
104
+ touchedFields.add(event.name)
90
105
  }
91
- if (event.type === "change" || event.type === "input") {
92
- dirtyFields.add(event.name);
106
+
107
+ if (event.type === 'change' || event.type === 'input') {
108
+ dirtyFields.add(event.name)
93
109
  }
94
- });
95
- });
110
+ })
111
+ })
112
+
96
113
  onUnmounted(() => {
97
- bus.reset();
98
- });
114
+ bus.reset()
115
+ })
116
+
99
117
  onMounted(async () => {
100
118
  if (parentBus) {
101
- await nextTick();
102
- parentBus.emit({ type: "attach", validate: _validate, formId });
119
+ await nextTick()
120
+ parentBus.emit({ type: 'attach', validate: _validate, formId })
103
121
  }
104
- });
122
+ })
123
+
105
124
  onUnmounted(() => {
106
125
  if (parentBus) {
107
- parentBus.emit({ type: "detach", formId });
126
+ parentBus.emit({ type: 'detach', formId })
108
127
  }
109
- });
110
- const errors = ref([]);
111
- provide("form-errors", errors);
112
- const inputs = ref({});
113
- provide(formInputsInjectionKey, inputs);
114
- const dirtyFields = /* @__PURE__ */ new Set();
115
- const touchedFields = /* @__PURE__ */ new Set();
116
- const blurredFields = /* @__PURE__ */ new Set();
117
- function resolveErrorIds(errs) {
118
- return errs.map((err) => ({
128
+ })
129
+
130
+ const errors = ref<FormErrorWithId[]>([])
131
+ provide('form-errors', errors)
132
+
133
+ const inputs = ref<{ [P in keyof T]?: { id?: string, pattern?: RegExp } }>({})
134
+ provide(formInputsInjectionKey, inputs as any)
135
+
136
+ const dirtyFields = new Set<keyof T>()
137
+ const touchedFields = new Set<keyof T>()
138
+ const blurredFields = new Set<keyof T>()
139
+
140
+ function resolveErrorIds(errs: FormError[]): FormErrorWithId[] {
141
+ return errs.map(err => ({
119
142
  ...err,
120
- id: err?.name ? inputs.value[err.name]?.id : void 0
121
- }));
143
+ id: err?.name ? inputs.value[err.name]?.id : undefined
144
+ }))
122
145
  }
123
- const transformedState = ref(null);
124
- async function getErrors() {
125
- let errs = props.validate ? await props.validate(props.state) ?? [] : [];
146
+
147
+ const transformedState = ref<T | null>(null)
148
+
149
+ async function getErrors(): Promise<FormErrorWithId[]> {
150
+ let errs = props.validate ? (await props.validate(props.state)) ?? [] : []
151
+
126
152
  if (props.schema) {
127
- const { errors: errors2, result } = await validateSchema(props.state, props.schema);
128
- if (errors2) {
129
- errs = errs.concat(errors2);
153
+ const { errors, result } = await validateSchema(props.state, props.schema as FormSchema<typeof props.state>)
154
+ if (errors) {
155
+ errs = errs.concat(errors)
130
156
  } else {
131
- transformedState.value = result;
157
+ transformedState.value = result
132
158
  }
133
159
  }
134
- return resolveErrorIds(errs);
160
+
161
+ return resolveErrorIds(errs)
135
162
  }
136
- async function _validate(opts = { silent: false, nested: true, transform: false }) {
137
- const names = opts.name && !Array.isArray(opts.name) ? [opts.name] : opts.name;
138
- const nestedValidatePromises = !names && opts.nested ? Array.from(nestedForms.value.values()).map(
139
- ({ validate }) => validate(opts).then(() => void 0).catch((error) => {
140
- if (!(error instanceof FormValidationException)) {
141
- throw error;
142
- }
143
- return error;
144
- })
145
- ) : [];
163
+
164
+ async function _validate(opts: { name?: keyof T | (keyof T)[], silent?: boolean, nested?: boolean, transform?: boolean } = { silent: false, nested: true, transform: false }): Promise<T | false> {
165
+ const names = opts.name && !Array.isArray(opts.name) ? [opts.name] : opts.name as (keyof T)[]
166
+
167
+ const nestedValidatePromises = !names && opts.nested
168
+ ? Array.from(nestedForms.value.values()).map(
169
+ ({ validate }) => validate(opts).then(() => undefined).catch((error: Error) => {
170
+ if (!(error instanceof FormValidationException)) {
171
+ throw error
172
+ }
173
+ return error
174
+ })
175
+ )
176
+ : []
177
+
146
178
  if (names) {
147
- const otherErrors = errors.value.filter((error) => !names.some((name) => {
148
- const pattern = inputs.value?.[name]?.pattern;
149
- return name === error.name || pattern && error.name?.match(pattern);
150
- }));
151
- const pathErrors = (await getErrors()).filter((error) => names.some((name) => {
152
- const pattern = inputs.value?.[name]?.pattern;
153
- return name === error.name || pattern && error.name?.match(pattern);
154
- }));
155
- errors.value = otherErrors.concat(pathErrors);
179
+ const otherErrors = errors.value.filter(error => !names.some((name) => {
180
+ const pattern = inputs.value?.[name]?.pattern
181
+ return name === error.name || (pattern && error.name?.match(pattern))
182
+ }))
183
+
184
+ const pathErrors = (await getErrors()).filter(error => names.some((name) => {
185
+ const pattern = inputs.value?.[name]?.pattern
186
+ return name === error.name || (pattern && error.name?.match(pattern))
187
+ }))
188
+
189
+ errors.value = otherErrors.concat(pathErrors)
156
190
  } else {
157
- errors.value = await getErrors();
191
+ errors.value = await getErrors()
158
192
  }
159
- const childErrors = (await Promise.all(nestedValidatePromises)).filter((val) => val !== void 0);
193
+
194
+ const childErrors = (await Promise.all(nestedValidatePromises)).filter(val => val !== undefined)
195
+
160
196
  if (errors.value.length + childErrors.length > 0) {
161
- if (opts.silent) return false;
162
- throw new FormValidationException(formId, errors.value, childErrors);
197
+ if (opts.silent) return false
198
+ throw new FormValidationException(formId, errors.value, childErrors)
163
199
  }
200
+
164
201
  if (opts.transform) {
165
- Object.assign(props.state, transformedState.value);
202
+ Object.assign(props.state, transformedState.value)
166
203
  }
167
- return props.state;
204
+
205
+ return props.state as T
168
206
  }
169
- const loading = ref(false);
170
- provide(formLoadingInjectionKey, readonly(loading));
171
- async function onSubmitWrapper(payload) {
172
- loading.value = true;
173
- const event = payload;
207
+
208
+ const loading = ref(false)
209
+ provide(formLoadingInjectionKey, readonly(loading))
210
+
211
+ async function onSubmitWrapper(payload: Event) {
212
+ loading.value = true
213
+
214
+ const event = payload as FormSubmitEvent<any>
215
+
174
216
  try {
175
- event.data = await _validate({ nested: true, transform: props.transform });
176
- await props.onSubmit?.(event);
177
- dirtyFields.clear();
217
+ event.data = await _validate({ nested: true, transform: props.transform })
218
+ await props.onSubmit?.(event)
219
+ dirtyFields.clear()
178
220
  } catch (error) {
179
221
  if (!(error instanceof FormValidationException)) {
180
- throw error;
222
+ throw error
181
223
  }
182
- const errorEvent = {
224
+
225
+ const errorEvent: FormErrorEvent = {
183
226
  ...event,
184
227
  errors: error.errors,
185
228
  children: error.children
186
- };
187
- emits("error", errorEvent);
229
+ }
230
+ emits('error', errorEvent)
188
231
  } finally {
189
- loading.value = false;
232
+ loading.value = false
190
233
  }
191
234
  }
192
- const disabled = computed(() => props.disabled || loading.value);
235
+
236
+ const disabled = computed(() => props.disabled || loading.value)
237
+
193
238
  provide(formOptionsInjectionKey, computed(() => ({
194
239
  disabled: disabled.value,
195
240
  validateOnInputDelay: props.validateOnInputDelay
196
- })));
197
- defineExpose({
241
+ })))
242
+
243
+ defineExpose<Form<T>>({
198
244
  validate: _validate,
199
245
  errors,
200
- setErrors(errs, name) {
246
+
247
+ setErrors(errs: FormError[], name?: keyof T) {
201
248
  if (name) {
202
- errors.value = errors.value.filter((error) => error.name !== name).concat(resolveErrorIds(errs));
249
+ errors.value = errors.value
250
+ .filter(error => error.name !== name)
251
+ .concat(resolveErrorIds(errs))
203
252
  } else {
204
- errors.value = resolveErrorIds(errs);
253
+ errors.value = resolveErrorIds(errs)
205
254
  }
206
255
  },
256
+
207
257
  async submit() {
208
- await onSubmitWrapper(new Event("submit"));
258
+ await onSubmitWrapper(new Event('submit'))
209
259
  },
210
- getErrors(name) {
260
+
261
+ getErrors(name?: keyof T) {
211
262
  if (name) {
212
- return errors.value.filter((err) => err.name === name);
263
+ return errors.value.filter(err => err.name === name)
213
264
  }
214
- return errors.value;
265
+ return errors.value
215
266
  },
216
- clear(name) {
267
+
268
+ clear(name?: string) {
217
269
  if (name) {
218
- errors.value = errors.value.filter((err) => err.name !== name);
270
+ errors.value = errors.value.filter(err => err.name !== name)
219
271
  } else {
220
- errors.value = [];
272
+ errors.value = []
221
273
  }
222
274
  },
275
+
223
276
  disabled,
224
277
  dirty: computed(() => !!dirtyFields.size),
225
- dirtyFields: readonly(dirtyFields),
226
- blurredFields: readonly(blurredFields),
227
- touchedFields: readonly(touchedFields)
228
- });
278
+
279
+ dirtyFields: readonly(dirtyFields) as DeepReadonly<Set<keyof T>>,
280
+ blurredFields: readonly(blurredFields) as DeepReadonly<Set<keyof T>>,
281
+ touchedFields: readonly(touchedFields) as DeepReadonly<Set<keyof T>>
282
+ })
229
283
  </script>
230
284
 
231
285
  <template>
@@ -1,83 +1,87 @@
1
- <script>
2
- import _appConfig from "#build/app.config";
3
- import theme from "#build/b24ui/form-field";
4
- import { tv } from "../utils/tv";
5
- const appConfigFormField = _appConfig;
6
- const formField = tv({ extend: tv(theme), ...appConfigFormField.b24ui?.formField || {} });
1
+ <script lang="ts">
2
+ import type { VariantProps } from 'tailwind-variants'
3
+ import type { AppConfig } from '@nuxt/schema'
4
+ import _appConfig from '#build/app.config'
5
+ import theme from '#build/b24ui/form-field'
6
+ import { tv } from '../utils/tv'
7
+
8
+ const appConfigFormField = _appConfig as AppConfig & { b24ui: { formField: Partial<typeof theme> } }
9
+
10
+ const formField = tv({ extend: tv(theme), ...(appConfigFormField.b24ui?.formField || {}) })
11
+
12
+ type FormFieldVariants = VariantProps<typeof formField>
13
+
14
+ export interface FormFieldProps {
15
+ /**
16
+ * The element or component this component should render as.
17
+ * @defaultValue 'div'
18
+ */
19
+ as?: any
20
+ /** The name of the FormField. Also used to match form errors. */
21
+ name?: string
22
+ /** A regular expression to match form error names. */
23
+ errorPattern?: RegExp
24
+ label?: string
25
+ description?: string
26
+ help?: string
27
+ error?: string | boolean
28
+ hint?: string
29
+ /**
30
+ * @defaultValue 'md'
31
+ */
32
+ size?: FormFieldVariants['size']
33
+ /**
34
+ * @defaultValue false
35
+ */
36
+ required?: boolean
37
+ /** If true, validation on input will be active immediately instead of waiting for a blur event. */
38
+ eagerValidation?: boolean
39
+ /**
40
+ * Delay in milliseconds before validating the form on input events.
41
+ * @defaultValue `300`
42
+ */
43
+ validateOnInputDelay?: number
44
+ class?: any
45
+ b24ui?: Partial<typeof formField.slots>
46
+ }
47
+
48
+ export interface FormFieldSlots {
49
+ label(props: { label?: string }): any
50
+ hint(props: { hint?: string }): any
51
+ description(props: { description?: string }): any
52
+ help(props: { help?: string }): any
53
+ error(props: { error?: string | boolean }): any
54
+ default(props: { error?: string | boolean }): any
55
+ }
7
56
  </script>
8
57
 
9
- <script setup>
10
- import { computed, ref, inject, provide, useId } from "vue";
11
- import { formFieldInjectionKey, inputIdInjectionKey } from "../composables/useFormField";
12
- const props = defineProps({
13
- as: {
14
- type: null,
15
- required: false
16
- },
17
- name: {
18
- type: String,
19
- required: false
20
- },
21
- errorPattern: {
22
- type: null,
23
- required: false
24
- },
25
- label: {
26
- type: String,
27
- required: false
28
- },
29
- description: {
30
- type: String,
31
- required: false
32
- },
33
- help: {
34
- type: String,
35
- required: false
36
- },
37
- error: {
38
- type: [String, Boolean],
39
- required: false
40
- },
41
- hint: {
42
- type: String,
43
- required: false
44
- },
45
- size: {
46
- type: null,
47
- required: false
48
- },
49
- required: {
50
- type: Boolean,
51
- required: false
52
- },
53
- eagerValidation: {
54
- type: Boolean,
55
- required: false
56
- },
57
- validateOnInputDelay: {
58
- type: Number,
59
- required: false
60
- },
61
- class: {
62
- type: null,
63
- required: false
64
- },
65
- b24ui: {
66
- type: Object,
67
- required: false
68
- }
69
- });
70
- const slots = defineSlots();
58
+ <script setup lang="ts">
59
+ import { computed, ref, inject, provide, type Ref, useId } from 'vue'
60
+ import { Primitive, Label } from 'reka-ui'
61
+ import { formFieldInjectionKey, inputIdInjectionKey } from '../composables/useFormField'
62
+ import type { FormError, FormFieldInjectedOptions } from '../types/form'
63
+ import WarningIcon from '@bitrix24/b24icons-vue/main/WarningIcon'
64
+
65
+ const props = defineProps<FormFieldProps>()
66
+ const slots = defineSlots<FormFieldSlots>()
67
+
71
68
  const b24ui = computed(() => formField({
72
69
  size: props.size,
73
70
  required: props.required,
74
71
  useDescription: Boolean(props.description) || !!slots.description
75
- }));
76
- const formErrors = inject("form-errors", null);
77
- const error = computed(() => props.error || formErrors?.value?.find((error2) => error2.name && (error2.name === props.name || props.errorPattern && error2.name.match(props.errorPattern)))?.message);
78
- const id = ref(useId());
79
- const ariaId = id.value;
80
- provide(inputIdInjectionKey, id);
72
+ }))
73
+
74
+ const formErrors = inject<Ref<FormError[]> | null>('form-errors', null)
75
+
76
+ const error = computed(() => props.error || formErrors?.value?.find(error => error.name && (error.name === props.name || (props.errorPattern && error.name.match(props.errorPattern))))?.message)
77
+
78
+ const id = ref(useId())
79
+ // Copies id's initial value to bind aria-attributes such as aria-describedby.
80
+ // This is required for the RadioGroup component which unsets the id value.
81
+ const ariaId = id.value
82
+
83
+ provide(inputIdInjectionKey, id)
84
+
81
85
  provide(formFieldInjectionKey, computed(() => ({
82
86
  error: error.value,
83
87
  name: props.name,
@@ -89,7 +93,7 @@ provide(formFieldInjectionKey, computed(() => ({
89
93
  description: props.description,
90
94
  help: props.help,
91
95
  ariaId
92
- })));
96
+ }) as FormFieldInjectedOptions<FormFieldProps>))
93
97
  </script>
94
98
 
95
99
  <template>
@@ -118,7 +122,7 @@ provide(formFieldInjectionKey, computed(() => ({
118
122
  <div :class="[(label || !!slots.label || description || !!slots.description) && b24ui.container({ class: props.b24ui?.container })]">
119
123
  <slot :error="error" />
120
124
 
121
- <div v-if="typeof error === 'string' && error || !!slots.error" :id="`${ariaId}-error`" :class="b24ui.error({ class: props.b24ui?.error })">
125
+ <div v-if="(typeof error === 'string' && error) || !!slots.error" :id="`${ariaId}-error`" :class="b24ui.error({ class: props.b24ui?.error })">
122
126
  <slot name="error" :error="error">
123
127
  <div class="flex flex-row flex-nowrap gap-0.5">
124
128
  <WarningIcon :class="b24ui.errorIcon()" />