@mapomodule/form 2.0.0-beta.1 → 2.0.0-beta.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 (202) hide show
  1. package/README.md +37 -118
  2. package/dist/__tests__/__mocks__/nuxt-imports.d.ts +4 -0
  3. package/dist/__tests__/__mocks__/nuxt-imports.d.ts.map +1 -0
  4. package/dist/__tests__/camomillaRoundTrip.test.d.ts +2 -0
  5. package/dist/__tests__/camomillaRoundTrip.test.d.ts.map +1 -0
  6. package/dist/__tests__/registry.test.d.ts +2 -0
  7. package/dist/__tests__/registry.test.d.ts.map +1 -0
  8. package/dist/__tests__/tabVisibility.test.d.ts +2 -0
  9. package/dist/__tests__/tabVisibility.test.d.ts.map +1 -0
  10. package/dist/__tests__/useFormFromSchema.test.d.ts +2 -0
  11. package/dist/__tests__/useFormFromSchema.test.d.ts.map +1 -0
  12. package/dist/__tests__/useMapoForm.test.d.ts +2 -0
  13. package/dist/__tests__/useMapoForm.test.d.ts.map +1 -0
  14. package/dist/index.d.mts +9 -1
  15. package/dist/index.d.ts +15 -1
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.mjs +7 -34
  18. package/dist/module.d.mts +20 -2
  19. package/dist/module.d.ts +12 -2
  20. package/dist/module.d.ts.map +1 -0
  21. package/dist/module.json +1 -1
  22. package/dist/module.mjs +187 -13
  23. package/dist/runtime/components/MapoFocusPortal.vue +115 -0
  24. package/dist/runtime/components/MapoFocusPortal.vue.d.ts +4 -0
  25. package/dist/runtime/components/MapoFocusPortal.vue.d.ts.map +1 -0
  26. package/dist/runtime/components/MapoForm.vue +177 -0
  27. package/dist/runtime/components/MapoForm.vue.d.ts +47 -0
  28. package/dist/runtime/components/MapoForm.vue.d.ts.map +1 -0
  29. package/dist/runtime/components/MapoFormField.vue +269 -0
  30. package/dist/runtime/components/MapoFormField.vue.d.ts +46 -0
  31. package/dist/runtime/components/MapoFormField.vue.d.ts.map +1 -0
  32. package/dist/runtime/components/MapoFormFlatSection.vue +149 -0
  33. package/dist/runtime/components/MapoFormFlatSection.vue.d.ts +15 -0
  34. package/dist/runtime/components/MapoFormFlatSection.vue.d.ts.map +1 -0
  35. package/dist/runtime/components/MapoFormGroup.vue +247 -0
  36. package/dist/runtime/components/MapoFormGroup.vue.d.ts +44 -0
  37. package/dist/runtime/components/MapoFormGroup.vue.d.ts.map +1 -0
  38. package/dist/runtime/components/MapoFormTabs.vue +122 -0
  39. package/dist/runtime/components/MapoFormTabs.vue.d.ts +15 -0
  40. package/dist/runtime/components/MapoFormTabs.vue.d.ts.map +1 -0
  41. package/dist/runtime/components/MapoUnknownField.vue +62 -0
  42. package/dist/runtime/components/MapoUnknownField.vue.d.ts +16 -0
  43. package/dist/runtime/components/MapoUnknownField.vue.d.ts.map +1 -0
  44. package/dist/runtime/components/fields/MapoDateField.vue +88 -0
  45. package/dist/runtime/components/fields/MapoDateField.vue.d.ts +17 -0
  46. package/dist/runtime/components/fields/MapoDateField.vue.d.ts.map +1 -0
  47. package/dist/runtime/components/fields/MapoDateTimeField.vue +159 -0
  48. package/dist/runtime/components/fields/MapoDateTimeField.vue.d.ts +17 -0
  49. package/dist/runtime/components/fields/MapoDateTimeField.vue.d.ts.map +1 -0
  50. package/dist/runtime/components/fields/MapoEnhancedMediaField.vue +130 -0
  51. package/dist/runtime/components/fields/MapoEnhancedMediaField.vue.d.ts +16 -0
  52. package/dist/runtime/components/fields/MapoEnhancedMediaField.vue.d.ts.map +1 -0
  53. package/dist/runtime/components/fields/MapoFileField.vue +99 -0
  54. package/dist/runtime/components/fields/MapoFileField.vue.d.ts +16 -0
  55. package/dist/runtime/components/fields/MapoFileField.vue.d.ts.map +1 -0
  56. package/dist/runtime/components/fields/MapoFksField.vue +122 -0
  57. package/dist/runtime/components/fields/MapoFksField.vue.d.ts +16 -0
  58. package/dist/runtime/components/fields/MapoFksField.vue.d.ts.map +1 -0
  59. package/dist/runtime/components/fields/MapoMapField.vue +99 -0
  60. package/dist/runtime/components/fields/MapoMapField.vue.d.ts +22 -0
  61. package/dist/runtime/components/fields/MapoMapField.vue.d.ts.map +1 -0
  62. package/dist/runtime/components/fields/MapoMapFieldClient.vue +67 -0
  63. package/dist/runtime/components/fields/MapoMapFieldClient.vue.d.ts +20 -0
  64. package/dist/runtime/components/fields/MapoMapFieldClient.vue.d.ts.map +1 -0
  65. package/dist/runtime/components/fields/MapoMediaField.vue +93 -0
  66. package/dist/runtime/components/fields/MapoMediaField.vue.d.ts +16 -0
  67. package/dist/runtime/components/fields/MapoMediaField.vue.d.ts.map +1 -0
  68. package/dist/runtime/components/fields/MapoMediaM2mField.vue +111 -0
  69. package/dist/runtime/components/fields/MapoMediaM2mField.vue.d.ts +16 -0
  70. package/dist/runtime/components/fields/MapoMediaM2mField.vue.d.ts.map +1 -0
  71. package/dist/runtime/components/fields/MapoMediaUnavailable.vue +15 -0
  72. package/dist/runtime/components/fields/MapoMediaUnavailable.vue.d.ts +4 -0
  73. package/dist/runtime/components/fields/MapoMediaUnavailable.vue.d.ts.map +1 -0
  74. package/dist/runtime/components/fields/MapoRepeater.vue +459 -0
  75. package/dist/runtime/components/fields/MapoRepeater.vue.d.ts +16 -0
  76. package/dist/runtime/components/fields/MapoRepeater.vue.d.ts.map +1 -0
  77. package/dist/runtime/components/fields/MapoRepeaterItem.vue +346 -0
  78. package/dist/runtime/components/fields/MapoRepeaterItem.vue.d.ts +55 -0
  79. package/dist/runtime/components/fields/MapoRepeaterItem.vue.d.ts.map +1 -0
  80. package/dist/runtime/components/fields/MapoSeoPreview.vue +122 -0
  81. package/dist/runtime/components/fields/MapoSeoPreview.vue.d.ts +22 -0
  82. package/dist/runtime/components/fields/MapoSeoPreview.vue.d.ts.map +1 -0
  83. package/dist/runtime/components/fields/MapoTimeField.vue +44 -0
  84. package/dist/runtime/components/fields/MapoTimeField.vue.d.ts +17 -0
  85. package/dist/runtime/components/fields/MapoTimeField.vue.d.ts.map +1 -0
  86. package/dist/runtime/components/fields/MapoWygEditor.vue +258 -0
  87. package/dist/runtime/components/fields/MapoWygEditor.vue.d.ts +16 -0
  88. package/dist/runtime/components/fields/MapoWygEditor.vue.d.ts.map +1 -0
  89. package/dist/runtime/components/fields/nui/NuiCheckbox.vue +9 -0
  90. package/dist/runtime/components/fields/nui/NuiCheckbox.vue.d.ts +4 -0
  91. package/dist/runtime/components/fields/nui/NuiCheckbox.vue.d.ts.map +1 -0
  92. package/dist/runtime/components/fields/nui/NuiInput.vue +9 -0
  93. package/dist/runtime/components/fields/nui/NuiInput.vue.d.ts +4 -0
  94. package/dist/runtime/components/fields/nui/NuiInput.vue.d.ts.map +1 -0
  95. package/dist/runtime/components/fields/nui/NuiSelectMenu.vue +18 -0
  96. package/dist/runtime/components/fields/nui/NuiSelectMenu.vue.d.ts +4 -0
  97. package/dist/runtime/components/fields/nui/NuiSelectMenu.vue.d.ts.map +1 -0
  98. package/dist/runtime/components/fields/nui/NuiSlider.vue +9 -0
  99. package/dist/runtime/components/fields/nui/NuiSlider.vue.d.ts +4 -0
  100. package/dist/runtime/components/fields/nui/NuiSlider.vue.d.ts.map +1 -0
  101. package/dist/runtime/components/fields/nui/NuiSwitch.vue +9 -0
  102. package/dist/runtime/components/fields/nui/NuiSwitch.vue.d.ts +4 -0
  103. package/dist/runtime/components/fields/nui/NuiSwitch.vue.d.ts.map +1 -0
  104. package/dist/runtime/components/fields/nui/NuiTextarea.vue +9 -0
  105. package/dist/runtime/components/fields/nui/NuiTextarea.vue.d.ts +4 -0
  106. package/dist/runtime/components/fields/nui/NuiTextarea.vue.d.ts.map +1 -0
  107. package/dist/runtime/components/fields/nui/useNuiFieldAttrs.d.ts +13 -0
  108. package/dist/runtime/components/fields/nui/useNuiFieldAttrs.d.ts.map +1 -0
  109. package/dist/runtime/components/fields/nui/useNuiFieldAttrs.js +19 -0
  110. package/dist/runtime/composables/defineFormField.d.ts +25 -0
  111. package/dist/runtime/composables/defineFormField.d.ts.map +1 -0
  112. package/dist/runtime/composables/defineFormField.js +27 -0
  113. package/dist/runtime/composables/useCurrentLang.d.ts +6 -0
  114. package/dist/runtime/composables/useCurrentLang.d.ts.map +1 -0
  115. package/dist/runtime/composables/useCurrentLang.js +9 -0
  116. package/dist/runtime/composables/useFocusMode.d.ts +40 -0
  117. package/dist/runtime/composables/useFocusMode.d.ts.map +1 -0
  118. package/dist/runtime/composables/useFocusMode.js +31 -0
  119. package/dist/runtime/composables/useFormDraft.d.ts +60 -0
  120. package/dist/runtime/composables/useFormDraft.d.ts.map +1 -0
  121. package/dist/runtime/composables/useFormDraft.js +52 -0
  122. package/dist/runtime/composables/useFormFromSchema.d.ts +21 -0
  123. package/dist/runtime/composables/useFormFromSchema.d.ts.map +1 -0
  124. package/dist/runtime/composables/useFormFromSchema.js +145 -0
  125. package/dist/runtime/composables/useMapoForm.d.ts +96 -0
  126. package/dist/runtime/composables/useMapoForm.d.ts.map +1 -0
  127. package/dist/runtime/composables/useMapoForm.js +325 -0
  128. package/dist/runtime/composables/useMediaManager.d.ts +17 -0
  129. package/dist/runtime/composables/useMediaManager.d.ts.map +1 -0
  130. package/dist/runtime/composables/useMediaManager.js +6 -0
  131. package/dist/runtime/composables/useProgressiveDisclosure.d.ts +44 -0
  132. package/dist/runtime/composables/useProgressiveDisclosure.d.ts.map +1 -0
  133. package/dist/runtime/composables/useProgressiveDisclosure.js +23 -0
  134. package/dist/runtime/composables/useUnsavedChangesGuard.d.ts +24 -0
  135. package/dist/runtime/composables/useUnsavedChangesGuard.d.ts.map +1 -0
  136. package/dist/runtime/composables/useUnsavedChangesGuard.js +28 -0
  137. package/dist/runtime/devtools/DevtoolsFormsPage.vue +235 -0
  138. package/dist/runtime/devtools/DevtoolsFormsPage.vue.d.ts +4 -0
  139. package/dist/runtime/devtools/DevtoolsFormsPage.vue.d.ts.map +1 -0
  140. package/dist/runtime/plugins/form-registry.d.ts +18 -0
  141. package/dist/runtime/plugins/form-registry.d.ts.map +1 -0
  142. package/dist/runtime/plugins/form-registry.js +19 -0
  143. package/dist/runtime/registry/defaults.d.ts +3 -0
  144. package/dist/runtime/registry/defaults.d.ts.map +1 -0
  145. package/dist/runtime/registry/defaults.js +93 -0
  146. package/dist/runtime/types/descriptor.d.ts +373 -0
  147. package/dist/runtime/types/descriptor.d.ts.map +1 -0
  148. package/dist/runtime/types/descriptor.js +26 -0
  149. package/dist/runtime/types/index.d.ts +12 -0
  150. package/dist/runtime/types/index.d.ts.map +1 -0
  151. package/dist/runtime/types/index.js +6 -0
  152. package/dist/runtime/types/layout.d.ts +21 -0
  153. package/dist/runtime/types/layout.d.ts.map +1 -0
  154. package/dist/runtime/types/layout.js +0 -0
  155. package/dist/runtime/types/media.d.ts +43 -0
  156. package/dist/runtime/types/media.d.ts.map +1 -0
  157. package/dist/runtime/types/media.js +0 -0
  158. package/dist/runtime/types/registry.d.ts +62 -0
  159. package/dist/runtime/types/registry.d.ts.map +1 -0
  160. package/dist/runtime/types/registry.js +19 -0
  161. package/dist/runtime/utils/flattenFieldGroups.d.ts +50 -0
  162. package/dist/runtime/utils/flattenFieldGroups.d.ts.map +1 -0
  163. package/dist/runtime/utils/flattenFieldGroups.js +24 -0
  164. package/dist/runtime/utils/tabVisibility.d.ts +18 -0
  165. package/dist/runtime/utils/tabVisibility.d.ts.map +1 -0
  166. package/dist/runtime/utils/tabVisibility.js +18 -0
  167. package/dist/types.d.mts +6 -10
  168. package/package.json +10 -8
  169. package/src/__tests__/article.schema.json +193 -0
  170. package/src/__tests__/camomillaRoundTrip.test.ts +73 -0
  171. package/src/__tests__/tabVisibility.test.ts +102 -0
  172. package/src/__tests__/useFormFromSchema.test.ts +24 -0
  173. package/src/__tests__/useMapoForm.test.ts +5 -0
  174. package/src/index.ts +5 -0
  175. package/src/module.ts +34 -0
  176. package/src/runtime/components/MapoFocusPortal.vue +3 -1
  177. package/src/runtime/components/MapoForm.vue +17 -4
  178. package/src/runtime/components/MapoFormTabs.vue +29 -6
  179. package/src/runtime/components/fields/MapoDateField.vue +3 -1
  180. package/src/runtime/components/fields/MapoDateTimeField.vue +3 -1
  181. package/src/runtime/components/fields/MapoEnhancedMediaField.vue +153 -0
  182. package/src/runtime/components/fields/MapoFileField.vue +3 -1
  183. package/src/runtime/components/fields/MapoFksField.vue +7 -2
  184. package/src/runtime/components/fields/MapoMapField.vue +5 -2
  185. package/src/runtime/components/fields/MapoMediaField.vue +106 -0
  186. package/src/runtime/components/fields/MapoMediaM2mField.vue +131 -0
  187. package/src/runtime/components/fields/MapoMediaUnavailable.vue +19 -0
  188. package/src/runtime/components/fields/MapoRepeater.vue +33 -26
  189. package/src/runtime/components/fields/MapoRepeaterItem.vue +14 -8
  190. package/src/runtime/components/fields/MapoSeoPreview.vue +17 -13
  191. package/src/runtime/components/fields/MapoWygEditor.vue +55 -7
  192. package/src/runtime/composables/useFormFromSchema.ts +4 -1
  193. package/src/runtime/composables/useMapoForm.ts +4 -2
  194. package/src/runtime/composables/useMediaManager.ts +21 -0
  195. package/src/runtime/composables/useUnsavedChangesGuard.ts +3 -3
  196. package/src/runtime/registry/defaults.ts +9 -1
  197. package/src/runtime/types/descriptor.ts +22 -7
  198. package/src/runtime/types/index.ts +4 -0
  199. package/src/runtime/types/media.ts +44 -0
  200. package/src/runtime/utils/tabVisibility.ts +44 -0
  201. package/dist/index.d.cts +0 -1
  202. package/dist/module.d.cts +0 -2
@@ -0,0 +1,115 @@
1
+ <script setup>
2
+ import { computed, ref, onMounted, onUnmounted } from "vue";
3
+ import { watch } from "vue";
4
+ import { useI18n } from "vue-i18n";
5
+ import { useFocusMode } from "../composables/useFocusMode.js";
6
+ import MapoForm from "./MapoForm.vue";
7
+ const { t } = useI18n();
8
+ const { focusTarget, exit } = useFocusMode();
9
+ const isOpen = computed(() => focusTarget.value !== null);
10
+ const canUseDocument = typeof document !== "undefined";
11
+ function onKeyDown(e) {
12
+ if (e.key === "Escape" && isOpen.value) exit();
13
+ }
14
+ onMounted(() => window.addEventListener("keydown", onKeyDown));
15
+ onUnmounted(() => window.removeEventListener("keydown", onKeyDown));
16
+ watch(isOpen, (open) => {
17
+ if (!canUseDocument) return;
18
+ document.body.style.overflow = open ? "hidden" : "";
19
+ });
20
+ const localModel = ref({});
21
+ watch(
22
+ () => focusTarget.value?.model,
23
+ (val) => {
24
+ if (val) localModel.value = { ...val };
25
+ },
26
+ { immediate: true }
27
+ );
28
+ function onUpdate(val) {
29
+ localModel.value = val;
30
+ focusTarget.value?.onUpdate(val);
31
+ }
32
+ </script>
33
+
34
+ <template>
35
+ <Teleport to="body">
36
+ <Transition name="mapo-focus-portal">
37
+ <div
38
+ v-if="isOpen && focusTarget"
39
+ class="mapo-focus-portal fixed inset-0 z-[9999] flex flex-col bg-white"
40
+ role="dialog"
41
+ aria-modal="true"
42
+ >
43
+ <!-- ── Header ────────────────────────────────────────────────────── -->
44
+ <div
45
+ class="flex shrink-0 items-center gap-3 border-b border-gray-200 px-6 py-3"
46
+ >
47
+ <!-- Breadcrumb -->
48
+ <nav class="flex min-w-0 flex-1 items-center gap-1 text-sm">
49
+ <template v-for="(crumb, i) in focusTarget.breadcrumb" :key="i">
50
+ <span
51
+ :class="
52
+ i < focusTarget.breadcrumb.length - 1 ? 'text-gray-400' : 'font-semibold text-gray-800'
53
+ "
54
+ class="truncate"
55
+ >
56
+ {{ crumb }}
57
+ </span>
58
+ <UIcon
59
+ v-if="i < focusTarget.breadcrumb.length - 1"
60
+ name="i-lucide-chevron-right"
61
+ class="h-3.5 w-3.5 shrink-0 text-gray-300"
62
+ />
63
+ </template>
64
+ </nav>
65
+
66
+ <!-- Close button -->
67
+ <UButton
68
+ variant="ghost"
69
+ color="neutral"
70
+ icon="i-lucide-x"
71
+ :label="t('mapo.close')"
72
+ size="sm"
73
+ @click="exit"
74
+ />
75
+ </div>
76
+
77
+ <!-- ── Body: scrollable sub-form ────────────────────────────────── -->
78
+ <div class="min-h-0 flex-1 overflow-y-auto">
79
+ <div class="mx-auto max-w-3xl px-6 py-8">
80
+ <MapoForm
81
+ :model-value="localModel"
82
+ :fields="focusTarget.fields"
83
+ :errors="focusTarget.errors.value"
84
+ :languages="focusTarget.languages"
85
+ :current-lang="focusTarget.currentLang"
86
+ :registry="focusTarget.registry"
87
+ @update:model-value="onUpdate"
88
+ />
89
+ </div>
90
+ </div>
91
+
92
+ <!-- ── Footer ───────────────────────────────────────────────────── -->
93
+ <div
94
+ class="flex shrink-0 items-center justify-end gap-3 border-t border-gray-200 px-6 py-3"
95
+ >
96
+ <p class="mr-auto text-xs text-gray-400">
97
+ <UIcon name="i-lucide-keyboard" class="mr-1 inline h-3 w-3" />
98
+ Press
99
+ <kbd class="rounded bg-gray-100 px-1 py-0.5 font-mono text-xs"
100
+ >ESC</kbd
101
+ >
102
+ to return to the form
103
+ </p>
104
+ <UButton variant="ghost" color="neutral" @click="exit">
105
+ Close
106
+ </UButton>
107
+ </div>
108
+ </div>
109
+ </Transition>
110
+ </Teleport>
111
+ </template>
112
+
113
+ <style scoped>
114
+ .mapo-focus-portal-enter-active{transition:opacity .2s ease,transform .2s ease}.mapo-focus-portal-leave-active{transition:opacity .15s ease,transform .15s ease}.mapo-focus-portal-enter-from,.mapo-focus-portal-leave-to{opacity:0;transform:scale(.98)}.mapo-focus-portal-enter-to,.mapo-focus-portal-leave-from{opacity:1;transform:scale(1)}
115
+ </style>
@@ -0,0 +1,4 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
4
+ //# sourceMappingURL=MapoFocusPortal.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapoFocusPortal.vue.d.ts","sourceRoot":"","sources":["../../../src/runtime/components/MapoFocusPortal.vue"],"names":[],"mappings":"AAudA,QAAA,MAAM,YAAY,+QAChB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -0,0 +1,177 @@
1
+ <script setup>
2
+ import { computed, useSlots, watchEffect, inject, onUnmounted } from "vue";
3
+ import { useNuxtApp, useRuntimeConfig } from "#app";
4
+ import { useI18n } from "vue-i18n";
5
+ import { useMapoForm, injectMapoForm } from "../composables/useMapoForm.js";
6
+ import { provideCurrentLang } from "../composables/useCurrentLang.js";
7
+ import MapoFormGroup from "./MapoFormGroup.vue";
8
+ import MapoFormTabs from "./MapoFormTabs.vue";
9
+ import MapoFormFlatSection from "./MapoFormFlatSection.vue";
10
+ const props = defineProps({
11
+ modelValue: { type: null, required: true },
12
+ fields: { type: Array, required: true },
13
+ errors: { type: Object, required: false, default: () => ({}) },
14
+ languages: { type: Array, required: false, default: () => [] },
15
+ currentLang: { type: String, required: false, default: "" },
16
+ readonly: { type: Boolean, required: false, default: false },
17
+ immediate: { type: Boolean, required: false, default: false },
18
+ registry: { type: Object, required: false, default: void 0 }
19
+ });
20
+ const injectedRegistry = computed(() => {
21
+ if (props.registry) return props.registry;
22
+ const nuxt = useNuxtApp();
23
+ if (!nuxt.$mapoFormRegistry) {
24
+ throw new Error(
25
+ "[MapoForm] No registry available: pass the `registry` prop or make sure the @mapomodule/form module is installed."
26
+ );
27
+ }
28
+ return nuxt.$mapoFormRegistry;
29
+ });
30
+ const emit = defineEmits(["update:modelValue"]);
31
+ defineSlots();
32
+ const model = computed({
33
+ get: () => props.modelValue,
34
+ set: (val) => emit("update:modelValue", val)
35
+ });
36
+ const currentLangRef = computed(() => props.currentLang);
37
+ const errorsRef = computed(() => props.errors);
38
+ const globalDebounce = useRuntimeConfig().public.mapoForm?.debounce ?? 300;
39
+ const form = useMapoForm({
40
+ model,
41
+ fields: computed(() => props.fields),
42
+ errors: errorsRef,
43
+ languages: props.languages,
44
+ currentLang: currentLangRef,
45
+ immediate: props.immediate,
46
+ debounce: globalDebounce,
47
+ registry: injectedRegistry.value
48
+ });
49
+ const parentCtx = injectMapoForm();
50
+ watchEffect(() => {
51
+ form.readonly.value = props.readonly;
52
+ if (parentCtx) form.ctx.submitted.value = parentCtx.submitted.value;
53
+ });
54
+ defineExpose({
55
+ submit: form.submit,
56
+ validateClient: form.validateClient,
57
+ resetDirty: form.resetDirty,
58
+ getPatch: form.getPatch,
59
+ isDirty: form.isDirty,
60
+ isLoading: form.isLoading
61
+ });
62
+ const registerValidator = inject(
63
+ "mapoDetailRegisterValidator",
64
+ null
65
+ );
66
+ if (registerValidator) {
67
+ const unregister = registerValidator(form.validateClient);
68
+ onUnmounted(unregister);
69
+ }
70
+ const slots = useSlots();
71
+ const fieldSlotNames = computed(
72
+ () => Object.keys(slots).filter(
73
+ (name) => name.startsWith("field.") || name.startsWith("group.") || name.startsWith("tab.") || name === "tab-bar-end"
74
+ )
75
+ );
76
+ provideCurrentLang(currentLangRef);
77
+ const { t } = useI18n();
78
+ const DEFAULT_TAB = "__default__";
79
+ function getOrCreateTab(map, name) {
80
+ if (!map.has(name)) {
81
+ map.set(name, { name, groups: /* @__PURE__ */ new Map(), children: /* @__PURE__ */ new Map() });
82
+ }
83
+ return map.get(name);
84
+ }
85
+ const grouped = computed(() => {
86
+ const tabs = /* @__PURE__ */ new Map();
87
+ for (const field of props.fields) {
88
+ const rawTab = field.tab;
89
+ const tabPath = !rawTab ? [DEFAULT_TAB] : Array.isArray(rawTab) ? rawTab : rawTab.split("/");
90
+ const groupName = field.group ?? "__flat__";
91
+ let currentMap = tabs;
92
+ for (let i = 0; i < tabPath.length - 1; i++) {
93
+ const parent = getOrCreateTab(currentMap, tabPath[i]);
94
+ currentMap = parent.children;
95
+ }
96
+ const leaf = getOrCreateTab(currentMap, tabPath[tabPath.length - 1]);
97
+ if (!leaf.groups.has(groupName)) {
98
+ leaf.groups.set(groupName, { fields: [], subtabs: /* @__PURE__ */ new Map() });
99
+ }
100
+ const grp = leaf.groups.get(groupName);
101
+ if (field.subtab) {
102
+ if (!grp.subtabs.has(field.subtab)) {
103
+ grp.subtabs.set(field.subtab, []);
104
+ }
105
+ grp.subtabs.get(field.subtab).push(field);
106
+ } else {
107
+ grp.fields.push(field);
108
+ }
109
+ }
110
+ const defaultTab = tabs.get(DEFAULT_TAB);
111
+ if (defaultTab) defaultTab.label = t("mapo.form.defaultTab");
112
+ return tabs;
113
+ });
114
+ const hasTabs = computed(() => {
115
+ const keys = [...grouped.value.keys()];
116
+ const hasFields = keys.length > 0;
117
+ if (!hasFields) return false;
118
+ const hasSeveralTabs = keys.length > 1;
119
+ const hasNamedTab = keys[0] !== DEFAULT_TAB;
120
+ return hasSeveralTabs || hasNamedTab;
121
+ });
122
+ const defaultGroups = computed(
123
+ () => grouped.value.get(DEFAULT_TAB)?.groups ?? /* @__PURE__ */ new Map()
124
+ );
125
+ const tabList = computed(() => [...grouped.value.values()]);
126
+ </script>
127
+
128
+ <template>
129
+ <div class="mapo-form space-y-5">
130
+ <!-- All field slots (field.<key>, field.<key>.append, .prepend, .label, …)
131
+ are forwarded generically to inner layers (Tabs → Group → Field). -->
132
+ <MapoFormTabs v-if="hasTabs" :tabs="tabList">
133
+ <template
134
+ v-for="slotName in fieldSlotNames"
135
+ :key="slotName"
136
+ #[slotName]="slotProps"
137
+ >
138
+ <slot :name="slotName" v-bind="slotProps ?? {}" />
139
+ </template>
140
+ </MapoFormTabs>
141
+
142
+ <template v-else>
143
+ <template v-for="[groupName, group] of defaultGroups" :key="groupName">
144
+ <template v-if="groupName !== '__flat__'">
145
+ <slot :name="`group.${groupName}.before`" />
146
+ <MapoFormGroup
147
+ :name="groupName"
148
+ :fields="group.fields"
149
+ :subtabs="group.subtabs"
150
+ >
151
+ <template
152
+ v-for="slotName in fieldSlotNames"
153
+ :key="slotName"
154
+ #[slotName]="slotProps"
155
+ >
156
+ <slot :name="slotName" v-bind="slotProps ?? {}" />
157
+ </template>
158
+ </MapoFormGroup>
159
+ <slot :name="`group.${groupName}.after`" />
160
+ </template>
161
+
162
+ <MapoFormFlatSection
163
+ v-else
164
+ :fields="group.fields"
165
+ >
166
+ <template
167
+ v-for="slotName in fieldSlotNames"
168
+ :key="slotName"
169
+ #[slotName]="slotProps"
170
+ >
171
+ <slot :name="slotName" v-bind="slotProps ?? {}" />
172
+ </template>
173
+ </MapoFormFlatSection>
174
+ </template>
175
+ </template>
176
+ </div>
177
+ </template>
@@ -0,0 +1,47 @@
1
+ import type { Ref } from "vue";
2
+ import type { AnyFieldDescriptor, FieldRegistry } from "../types/index.js";
3
+ declare const __VLS_export: <T extends object>(__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<{
4
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<{
5
+ modelValue: T;
6
+ fields: AnyFieldDescriptor<T>[];
7
+ errors?: Record<string, string[]>;
8
+ languages?: string[];
9
+ currentLang?: string;
10
+ readonly?: boolean;
11
+ immediate?: boolean;
12
+ /**
13
+ * Field component registry. When omitted, it is auto-injected from
14
+ * `$mapoFormRegistry` (provided by the `@mapomodule/form` plugin).
15
+ * Pass it explicitly only for headless forms or one-off registry swaps.
16
+ */
17
+ registry?: FieldRegistry;
18
+ } & {
19
+ "onUpdate:modelValue"?: ((value: T) => any) | undefined;
20
+ }> & (typeof globalThis extends {
21
+ __VLS_PROPS_FALLBACK: infer P;
22
+ } ? P : {});
23
+ expose: (exposed: import("vue").ShallowUnwrapRef<{
24
+ submit: (handler: (model: T | Partial<T>, isNew: boolean) => Promise<void>, isNew?: boolean) => Promise<void>;
25
+ validateClient: () => {
26
+ valid: boolean;
27
+ errors: Record<string, string>;
28
+ };
29
+ resetDirty: () => void;
30
+ getPatch: () => Partial<T>;
31
+ isDirty: import("vue").ComputedRef<boolean>;
32
+ isLoading: Ref<boolean, boolean>;
33
+ }>) => void;
34
+ attrs: any;
35
+ slots: Record<string, (props: Record<string, any>) => unknown>;
36
+ emit: (evt: "update:modelValue", value: T) => void;
37
+ }>) => import("vue").VNode & {
38
+ __ctx?: Awaited<typeof __VLS_setup>;
39
+ };
40
+ declare const _default: typeof __VLS_export;
41
+ export default _default;
42
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
43
+ [K in keyof T]: T[K];
44
+ } : {
45
+ [K in keyof T as K]: T[K];
46
+ }) & {};
47
+ //# sourceMappingURL=MapoForm.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapoForm.vue.d.ts","sourceRoot":"","sources":["../../../src/runtime/components/MapoForm.vue"],"names":[],"mappings":"AAwQA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAG/B,OAAO,KAAK,EACV,kBAAkB,EAClB,aAAa,EAEd,MAAM,mBAAmB,CAAC;AAQ3B,QAAA,MAAM,YAAY,GAAK,CAAC,SAAS,MAAM,EACtC,aAAa,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAC9D,YAAY,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,EAC3G,gBAAgB,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAClE;WA+UO,OAAO,KAAK,EAAE,WAAW,GAAG,mBAAmB,CAAC;oBA7UxC,CAAC;gBACL,kBAAkB,CAAC,CAAC,CAAC,EAAE;iBACtB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;oBACrB,MAAM,EAAE;sBACN,MAAM;mBACT,OAAO;oBACN,OAAO;QACnB;;;;WAIG;mBACQ,aAAa;;;KAiU+D,CAAC,GAAG,CAAC,OAAO,UAAU,SAAS;QAAE,oBAAoB,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAC5J,CAAC,OAAO,EAAE,OAAO,KAAK,EAAE,gBAAgB;;;;;;;;;;MAAsB,KAAK,IAAI;WACxE,GAAG;kCA/R+B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO;;EAmSrE,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,WAAW,CAAC,CAAA;CAAI,CAAC;wBACvD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,CAAC,GAAG,EAAE,CAAC"}
@@ -0,0 +1,269 @@
1
+ <script setup>
2
+ import { computed, defineAsyncComponent, inject, ref, watch } from "vue";
3
+ import {
4
+ resolveFieldComponent,
5
+ resolveFieldAttrs,
6
+ resolveFieldAccessor
7
+ } from "../types/index.js";
8
+ import { injectMapoForm } from "../composables/useMapoForm.js";
9
+ import { getNestedValue, debounce } from "@mapomodule/utils";
10
+ import MapoUnknownField from "./MapoUnknownField.vue";
11
+ const props = defineProps({
12
+ descriptor: { type: Object, required: true }
13
+ });
14
+ const form = injectMapoForm();
15
+ const registry = form.registry;
16
+ const currentLang = form.currentLang;
17
+ const model = form.model;
18
+ const isVisible = computed(() => {
19
+ if (props.descriptor.visible && !props.descriptor.visible({ model: model.value }))
20
+ return false;
21
+ return true;
22
+ });
23
+ const showField = computed(() => {
24
+ if (props.descriptor.show && !props.descriptor.show({ model: model.value }))
25
+ return false;
26
+ return true;
27
+ });
28
+ const path = computed(() => {
29
+ const lang = currentLang.value;
30
+ if (props.descriptor.translatable && lang) {
31
+ return `translations.${lang}.${props.descriptor.key}`;
32
+ }
33
+ return props.descriptor.key;
34
+ });
35
+ const accessor = computed(
36
+ () => resolveFieldAccessor(props.descriptor, registry)
37
+ );
38
+ const modelValue = computed(() => {
39
+ const raw = getNestedValue(model.value, path.value);
40
+ return accessor.value.get ? accessor.value.get({
41
+ model: model.value,
42
+ val: raw,
43
+ lang: currentLang.value
44
+ }) : raw;
45
+ });
46
+ function doUpdate(val) {
47
+ form.setFieldValue(props.descriptor.key, val);
48
+ }
49
+ const debounceMs = form.immediate ? 0 : props.descriptor.debounce ?? form.debounce;
50
+ const onUpdate = debounceMs > 0 ? debounce(doUpdate, debounceMs) : doUpdate;
51
+ const asyncState = ref("idle");
52
+ const asyncError = ref(null);
53
+ const asyncCache = /* @__PURE__ */ new Map();
54
+ const asyncValidationDebounceMs = props.descriptor.validateAsync ? props.descriptor.validateAsyncDebounce ?? 600 : 0;
55
+ const runAsyncValidation = props.descriptor.validateAsync ? debounce(async (val) => {
56
+ const cacheKey = JSON.stringify(val);
57
+ if (asyncCache.has(cacheKey)) {
58
+ asyncError.value = asyncCache.get(cacheKey);
59
+ asyncState.value = asyncError.value ? "invalid" : "valid";
60
+ return;
61
+ }
62
+ asyncState.value = "pending";
63
+ try {
64
+ const result = await props.descriptor.validateAsync(val, {
65
+ model: model.value
66
+ });
67
+ asyncCache.set(cacheKey, result);
68
+ asyncError.value = result;
69
+ asyncState.value = result ? "invalid" : "valid";
70
+ } catch {
71
+ asyncState.value = "idle";
72
+ }
73
+ }, asyncValidationDebounceMs) : null;
74
+ if (runAsyncValidation) {
75
+ watch(modelValue, (val, old) => {
76
+ if (val === old) return;
77
+ runAsyncValidation(val);
78
+ });
79
+ }
80
+ function onBlur() {
81
+ form.markTouched(props.descriptor.key);
82
+ }
83
+ const asyncTrailingIcon = computed(
84
+ () => ({
85
+ idle: void 0,
86
+ pending: "i-lucide-loader-2",
87
+ valid: "i-lucide-check-circle",
88
+ invalid: "i-lucide-x-circle"
89
+ })[asyncState.value]
90
+ );
91
+ const asyncTrailingIconClass = computed(
92
+ () => ({
93
+ idle: "",
94
+ pending: "text-gray-400 animate-spin",
95
+ valid: "text-green-500",
96
+ invalid: "text-red-500"
97
+ })[asyncState.value]
98
+ );
99
+ const fieldComponent = computed(() => {
100
+ const entry = resolveFieldComponent(props.descriptor, registry);
101
+ if (!entry) return MapoUnknownField;
102
+ if (typeof entry === "function")
103
+ return defineAsyncComponent(entry);
104
+ return entry;
105
+ });
106
+ const fieldAttrs = computed(
107
+ () => resolveFieldAttrs(props.descriptor, registry)
108
+ );
109
+ function resolveErrors(errorsMap, dotPath) {
110
+ const segments = dotPath.split(".");
111
+ const result = [];
112
+ let current = "";
113
+ for (const seg of segments) {
114
+ current = current ? `${current}.${seg}` : seg;
115
+ const errs = errorsMap[current];
116
+ if (errs) result.push(...errs);
117
+ }
118
+ return result;
119
+ }
120
+ const errors = computed(() => resolveErrors(form.errors.value, path.value));
121
+ const clientError = computed(
122
+ () => form.getClientError(props.descriptor.key)
123
+ );
124
+ const allErrors = computed(() => {
125
+ const errs = [...errors.value];
126
+ if (clientError.value) errs.unshift(clientError.value);
127
+ if (asyncError.value && asyncState.value === "invalid")
128
+ errs.push(asyncError.value);
129
+ return errs;
130
+ });
131
+ const hasError = computed(() => allErrors.value.length > 0);
132
+ const errorColor = computed(() => hasError.value ? "error" : void 0);
133
+ function autoLabel(key) {
134
+ const stripped = key.replace(/^translations\.[^.]+\./, "");
135
+ return stripped.replace(/[_.-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
136
+ }
137
+ const label = computed(
138
+ () => props.descriptor.label ?? autoLabel(props.descriptor.key)
139
+ );
140
+ const fieldId = computed(() => `field-${props.descriptor.key}`);
141
+ const groupExpand = inject("mapoGroupExpand", null);
142
+ const isExpanded = computed(
143
+ () => groupExpand ? groupExpand.expandedFieldKey.value === props.descriptor.key : false
144
+ );
145
+ function toggleExpand() {
146
+ if (!groupExpand) return;
147
+ if (isExpanded.value) groupExpand.collapseField();
148
+ else groupExpand.expandField(props.descriptor.key);
149
+ }
150
+ </script>
151
+
152
+ <template>
153
+ <div
154
+ v-if="isVisible"
155
+ v-show="showField"
156
+ class="mapo-form-field group flex flex-col gap-1"
157
+ :class="[
158
+ descriptor.class,
159
+ hasError && 'mapo-form-field--error',
160
+ isExpanded && 'flex-1 min-h-0'
161
+ ]"
162
+ >
163
+ <!-- Label -->
164
+ <slot
165
+ :name="`field.${descriptor.key}.label`"
166
+ :descriptor="descriptor"
167
+ :label="label"
168
+ >
169
+ <label
170
+ :for="fieldId"
171
+ class="flex shrink-0 items-center gap-1 text-sm font-medium text-gray-700"
172
+ >
173
+ <span>{{ label }}</span>
174
+ <span v-if="descriptor.required" class="text-red-500" aria-hidden="true"
175
+ >*</span
176
+ >
177
+ <UIcon
178
+ v-if="asyncTrailingIcon"
179
+ :name="asyncTrailingIcon"
180
+ class="ml-auto h-3.5 w-3.5"
181
+ :class="asyncTrailingIconClass"
182
+ />
183
+ <!-- Expand button — visible on hover or while expanded -->
184
+ <button
185
+ v-if="descriptor.expandable && groupExpand"
186
+ type="button"
187
+ :class="
188
+ isExpanded ? 'ml-auto text-primary-500' : 'ml-auto text-gray-300 opacity-0 group-hover:opacity-100 focus:opacity-100'
189
+ "
190
+ class="rounded p-0.5 transition-all hover:bg-gray-100 hover:text-gray-600"
191
+ :title="isExpanded ? 'Collapse field' : 'Expand field'"
192
+ @click.prevent="toggleExpand"
193
+ >
194
+ <UIcon
195
+ :name="isExpanded ? 'i-lucide-minimize-2' : 'i-lucide-expand'"
196
+ class="h-3.5 w-3.5"
197
+ />
198
+ </button>
199
+ </label>
200
+ </slot>
201
+
202
+ <!-- Slot before -->
203
+ <slot
204
+ :name="`field.${descriptor.key}.before`"
205
+ :descriptor="descriptor"
206
+ :model="model"
207
+ />
208
+
209
+ <div
210
+ class="flex items-start gap-2"
211
+ :class="isExpanded && 'flex-1 min-h-0'"
212
+ :style="isExpanded ? 'height: 100%; overflow: hidden;' : ''"
213
+ >
214
+ <!-- Slot prepend -->
215
+ <slot
216
+ :name="`field.${descriptor.key}.prepend`"
217
+ :descriptor="descriptor"
218
+ :model="model"
219
+ />
220
+
221
+ <component
222
+ :is="fieldComponent"
223
+ :id="fieldId"
224
+ v-bind="fieldAttrs"
225
+ :class="isExpanded ? 'flex-1 min-h-0' : 'flex-1'"
226
+ :style="isExpanded ? 'height: 100%;' : ''"
227
+ :model-value="modelValue"
228
+ :readonly="descriptor.readonly || form.readonly.value"
229
+ :disabled="descriptor.readonly || form.readonly.value"
230
+ :descriptor="descriptor"
231
+ :errors="allErrors"
232
+ :color="errorColor"
233
+ @update:model-value="onUpdate"
234
+ @blur="onBlur"
235
+ />
236
+
237
+ <!-- Slot append -->
238
+ <slot
239
+ :name="`field.${descriptor.key}.append`"
240
+ :descriptor="descriptor"
241
+ :model="model"
242
+ />
243
+ </div>
244
+
245
+ <!-- Slot hint -->
246
+ <slot
247
+ :name="`field.${descriptor.key}.hint`"
248
+ :descriptor="descriptor"
249
+ :model="model"
250
+ />
251
+
252
+ <!-- Errori -->
253
+ <p
254
+ v-for="err in allErrors"
255
+ :key="err"
256
+ class="text-xs text-red-500"
257
+ role="alert"
258
+ >
259
+ {{ err }}
260
+ </p>
261
+
262
+ <!-- Slot after -->
263
+ <slot
264
+ :name="`field.${descriptor.key}.after`"
265
+ :descriptor="descriptor"
266
+ :model="model"
267
+ />
268
+ </div>
269
+ </template>
@@ -0,0 +1,46 @@
1
+ import type { AnyFieldDescriptor } from "../types/index.js";
2
+ type __VLS_Props = {
3
+ descriptor: AnyFieldDescriptor<any>;
4
+ };
5
+ declare var __VLS_2: `field.${string}.label`, __VLS_3: {
6
+ descriptor: AnyFieldDescriptor<any>;
7
+ label: string;
8
+ }, __VLS_16: `field.${string}.before`, __VLS_17: {
9
+ descriptor: AnyFieldDescriptor<any>;
10
+ model: Record<string, unknown>;
11
+ }, __VLS_20: `field.${string}.prepend`, __VLS_21: {
12
+ descriptor: AnyFieldDescriptor<any>;
13
+ model: Record<string, unknown>;
14
+ }, __VLS_31: `field.${string}.append`, __VLS_32: {
15
+ descriptor: AnyFieldDescriptor<any>;
16
+ model: Record<string, unknown>;
17
+ }, __VLS_35: `field.${string}.hint`, __VLS_36: {
18
+ descriptor: AnyFieldDescriptor<any>;
19
+ model: Record<string, unknown>;
20
+ }, __VLS_39: `field.${string}.after`, __VLS_40: {
21
+ descriptor: AnyFieldDescriptor<any>;
22
+ model: Record<string, unknown>;
23
+ };
24
+ type __VLS_Slots = {} & {
25
+ [K in NonNullable<typeof __VLS_2>]?: (props: typeof __VLS_3) => any;
26
+ } & {
27
+ [K in NonNullable<typeof __VLS_16>]?: (props: typeof __VLS_17) => any;
28
+ } & {
29
+ [K in NonNullable<typeof __VLS_20>]?: (props: typeof __VLS_21) => any;
30
+ } & {
31
+ [K in NonNullable<typeof __VLS_31>]?: (props: typeof __VLS_32) => any;
32
+ } & {
33
+ [K in NonNullable<typeof __VLS_35>]?: (props: typeof __VLS_36) => any;
34
+ } & {
35
+ [K in NonNullable<typeof __VLS_39>]?: (props: typeof __VLS_40) => any;
36
+ };
37
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
38
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
39
+ declare const _default: typeof __VLS_export;
40
+ export default _default;
41
+ type __VLS_WithSlots<T, S> = T & {
42
+ new (): {
43
+ $slots: S;
44
+ };
45
+ };
46
+ //# sourceMappingURL=MapoFormField.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapoFormField.vue.d.ts","sourceRoot":"","sources":["../../../src/runtime/components/MapoFormField.vue"],"names":[],"mappings":"AAmWA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAa5D,KAAK,WAAW,GAAG;IAAE,UAAU,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAA;CAAE,CAAC;AA2a3D,QAAA,IAAI,OAAO,yBAAU,EAAE,OAAO;;;CAAU,EAAE,QAAQ,0BAAW,EAAE,QAAQ;;;CAAW,EAAE,QAAQ,2BAAW,EAAE,QAAQ;;;CAAW,EAAE,QAAQ,0BAAW,EAAE,QAAQ;;;CAAW,EAAE,QAAQ,wBAAW,EAAE,QAAQ;;;CAAW,EAAE,QAAQ,yBAAW,EAAE,QAAQ;;;CAAY,CAAE;AAC7P,KAAK,WAAW,GAAG,EAAE,GACnB;KAAG,CAAC,IAAI,WAAW,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG;CAAE,GACvE;KAAG,CAAC,IAAI,WAAW,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG;CAAE,GACzE;KAAG,CAAC,IAAI,WAAW,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG;CAAE,GACzE;KAAG,CAAC,IAAI,WAAW,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG;CAAE,GACzE;KAAG,CAAC,IAAI,WAAW,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG;CAAE,GACzE;KAAG,CAAC,IAAI,WAAW,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,GAAG;CAAE,CAAC;AAK5E,QAAA,MAAM,UAAU,kSAEd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}