@hywax/cms 3.6.0 → 3.7.0

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 (68) hide show
  1. package/.nuxt/cms/config.ts +1 -1
  2. package/.nuxt/cms/prose/index.ts +2 -1
  3. package/.nuxt/cms/prose/uplora-image-gallery.ts +15 -0
  4. package/.nuxt/cms/uplora-image.ts +12 -1
  5. package/dist/module.json +1 -1
  6. package/dist/module.mjs +37 -7
  7. package/dist/runtime/components/EditorFull.vue +18 -3
  8. package/dist/runtime/components/FormSeo.d.vue.ts +4 -4
  9. package/dist/runtime/components/FormSeo.vue +25 -13
  10. package/dist/runtime/components/FormSeo.vue.d.ts +4 -4
  11. package/dist/runtime/components/FormUploraImage.d.vue.ts +7 -9
  12. package/dist/runtime/components/FormUploraImage.vue +70 -46
  13. package/dist/runtime/components/FormUploraImage.vue.d.ts +7 -9
  14. package/dist/runtime/components/UploraImage.d.vue.ts +4 -0
  15. package/dist/runtime/components/UploraImage.vue +15 -4
  16. package/dist/runtime/components/UploraImage.vue.d.ts +4 -0
  17. package/dist/runtime/components/prose/UploraImage.d.vue.ts +4 -7
  18. package/dist/runtime/components/prose/UploraImage.vue +15 -9
  19. package/dist/runtime/components/prose/UploraImage.vue.d.ts +4 -7
  20. package/dist/runtime/components/prose/UploraImageGallery.d.vue.ts +19 -0
  21. package/dist/runtime/components/prose/UploraImageGallery.vue +24 -0
  22. package/dist/runtime/components/prose/UploraImageGallery.vue.d.ts +19 -0
  23. package/dist/runtime/composables/useEditorSuggestions.d.ts +29 -6
  24. package/dist/runtime/composables/useEditorSuggestions.js +7 -3
  25. package/dist/runtime/editor/caution/EditorCaution.d.ts +18 -0
  26. package/dist/runtime/editor/caution/EditorCaution.js +36 -0
  27. package/dist/runtime/editor/caution/EditorCautionNode.d.vue.ts +4 -0
  28. package/dist/runtime/editor/caution/EditorCautionNode.vue +22 -0
  29. package/dist/runtime/editor/caution/EditorCautionNode.vue.d.ts +4 -0
  30. package/dist/runtime/editor/note/EditorNote.d.ts +18 -0
  31. package/dist/runtime/editor/note/EditorNote.js +36 -0
  32. package/dist/runtime/editor/note/EditorNoteNode.d.vue.ts +4 -0
  33. package/dist/runtime/editor/note/EditorNoteNode.vue +22 -0
  34. package/dist/runtime/editor/note/EditorNoteNode.vue.d.ts +4 -0
  35. package/dist/runtime/editor/tip/EditorTip.d.ts +18 -0
  36. package/dist/runtime/editor/tip/EditorTip.js +36 -0
  37. package/dist/runtime/editor/tip/EditorTipNode.d.vue.ts +4 -0
  38. package/dist/runtime/editor/tip/EditorTipNode.vue +22 -0
  39. package/dist/runtime/editor/tip/EditorTipNode.vue.d.ts +4 -0
  40. package/dist/runtime/editor/uplora-image/EditorUploraImage.js +10 -4
  41. package/dist/runtime/editor/uplora-image/EditorUploraImageNode.d.vue.ts +0 -5
  42. package/dist/runtime/editor/uplora-image/EditorUploraImageNode.vue +2 -2
  43. package/dist/runtime/editor/uplora-image/EditorUploraImageNode.vue.d.ts +0 -5
  44. package/dist/runtime/editor/uplora-image-gallery/EditorUploraImageGallery.d.ts +18 -0
  45. package/dist/runtime/editor/uplora-image-gallery/EditorUploraImageGallery.js +71 -0
  46. package/dist/runtime/editor/uplora-image-gallery/EditorUploraImageGalleryNode.d.vue.ts +4 -0
  47. package/dist/runtime/editor/uplora-image-gallery/EditorUploraImageGalleryNode.vue +93 -0
  48. package/dist/runtime/editor/uplora-image-gallery/EditorUploraImageGalleryNode.vue.d.ts +4 -0
  49. package/dist/runtime/editor/utils/attributes.d.ts +2 -0
  50. package/dist/runtime/editor/{utils.js → utils/attributes.js} +0 -29
  51. package/dist/runtime/editor/utils/createAtomBlockMarkdownSpec.d.ts +10 -0
  52. package/dist/runtime/editor/utils/createAtomBlockMarkdownSpec.js +32 -0
  53. package/dist/runtime/editor/utils/createBlockMarkdownSpec.d.ts +12 -0
  54. package/dist/runtime/editor/utils/createBlockMarkdownSpec.js +99 -0
  55. package/dist/runtime/editor/utils/index.d.ts +3 -0
  56. package/dist/runtime/editor/utils/index.js +3 -0
  57. package/dist/runtime/editor/warning/EditorWarning.d.ts +18 -0
  58. package/dist/runtime/editor/warning/EditorWarning.js +36 -0
  59. package/dist/runtime/editor/warning/EditorWarningNode.d.vue.ts +4 -0
  60. package/dist/runtime/editor/warning/EditorWarningNode.vue +22 -0
  61. package/dist/runtime/editor/warning/EditorWarningNode.vue.d.ts +4 -0
  62. package/dist/runtime/server/utils/pagination.d.ts +4 -0
  63. package/dist/runtime/server/utils/pagination.js +2 -2
  64. package/dist/runtime/utils/auth.js +2 -2
  65. package/dist/runtime/utils/date.js +2 -2
  66. package/dist/runtime/utils/storage.js +2 -2
  67. package/package.json +1 -1
  68. package/dist/runtime/editor/utils.d.ts +0 -13
@@ -15,4 +15,4 @@ const cmsConfig = {
15
15
  }
16
16
  }
17
17
 
18
- export const getCmsConfig = () => cmsConfig
18
+ export const useCmsConfig = () => cmsConfig
@@ -1 +1,2 @@
1
- export { default as uploraImage } from './uplora-image'
1
+ export { default as uploraImage } from './uplora-image'
2
+ export { default as uploraImageGallery } from './uplora-image-gallery'
@@ -0,0 +1,15 @@
1
+ export default {
2
+ "slots": {
3
+ "base": "grid gap-4"
4
+ },
5
+ "variants": {
6
+ "columns": {
7
+ "two-columns": {
8
+ "base": "grid-cols-2"
9
+ },
10
+ "three-columns": {
11
+ "base": "grid-cols-3"
12
+ }
13
+ }
14
+ }
15
+ }
@@ -2,7 +2,18 @@ export default {
2
2
  "slots": {
3
3
  "root": "relative grid grid-cols-[100%] grid-rows-[100%] overflow-hidden",
4
4
  "lqip": "bg-cover bg-no-repeat bg-center col-[1] row-[1]",
5
- "picture": "aspect-3/2 col-[1] row-[1]",
5
+ "picture": "col-[1] row-[1]",
6
6
  "img": "w-full h-full block object-cover"
7
+ },
8
+ "variants": {
9
+ "aspect": {
10
+ "horizontal": {
11
+ "picture": "aspect-3/2"
12
+ },
13
+ "vertical": {
14
+ "picture": "aspect-2/3"
15
+ },
16
+ "dynamic": {}
17
+ }
7
18
  }
8
19
  }
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hywax/cms",
3
- "version": "3.6.0",
3
+ "version": "3.7.0",
4
4
  "configKey": "cms",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
package/dist/module.mjs CHANGED
@@ -7,7 +7,7 @@ import { pascalCase, kebabCase, camelCase } from 'scule';
7
7
  import { globSync } from 'tinyglobby';
8
8
 
9
9
  const name = "@hywax/cms";
10
- const version = "3.6.0";
10
+ const version = "3.7.0";
11
11
 
12
12
  function createContext(options, nuxt) {
13
13
  const { resolve } = createResolver(import.meta.url);
@@ -114,14 +114,14 @@ async function prepareAutoImports({ resolve, options, nuxt }) {
114
114
  addPlugin(resolve("./runtime/plugins/api"));
115
115
  addPlugin(resolve("./runtime/plugins/zod"));
116
116
  addImports([
117
- { name: "getCmsConfig", from: cmsConfigPath }
117
+ { name: "useCmsConfig", from: cmsConfigPath }
118
118
  ]);
119
119
  addImportsDir([
120
120
  resolve("./runtime/utils"),
121
121
  resolve("./runtime/composables")
122
122
  ]);
123
123
  addServerImports([
124
- { name: "getCmsConfig", from: cmsConfigPath }
124
+ { name: "useCmsConfig", from: cmsConfigPath }
125
125
  ]);
126
126
  addServerImportsDir([
127
127
  resolve("./runtime/utils"),
@@ -181,6 +181,7 @@ const icons = {
181
181
  strikethrough: "i-lucide-strikethrough",
182
182
  code: "i-lucide-code",
183
183
  image: "i-lucide-image",
184
+ images: "i-lucide-images",
184
185
  editLine: "i-lucide-pen-line",
185
186
  save: "i-lucide-cloud-check",
186
187
  toc: "i-lucide-text-align-start"
@@ -356,7 +357,8 @@ async function prepareMergeConfigs({ nuxt, options, resolve, detectedComponents:
356
357
  nuxt.options.mdc = defu(nuxt.options.mdc || {}, {
357
358
  components: {
358
359
  map: {
359
- "uplora-image": "ProseUploraImage"
360
+ "uplora-image": "ProseUploraImage",
361
+ "uplora-image-gallery": "ProseUploraImageGallery"
360
362
  }
361
363
  }
362
364
  });
@@ -563,8 +565,19 @@ const uploraImage$1 = {
563
565
  slots: {
564
566
  root: "relative grid grid-cols-[100%] grid-rows-[100%] overflow-hidden",
565
567
  lqip: "bg-cover bg-no-repeat bg-center col-[1] row-[1]",
566
- picture: "aspect-3/2 col-[1] row-[1]",
568
+ picture: "col-[1] row-[1]",
567
569
  img: "w-full h-full block object-cover"
570
+ },
571
+ variants: {
572
+ aspect: {
573
+ horizontal: {
574
+ picture: "aspect-3/2"
575
+ },
576
+ vertical: {
577
+ picture: "aspect-2/3"
578
+ },
579
+ dynamic: {}
580
+ }
568
581
  }
569
582
  };
570
583
 
@@ -601,9 +614,26 @@ const uploraImage = {
601
614
  }
602
615
  };
603
616
 
617
+ const uploraImageGallery = {
618
+ slots: {
619
+ base: "grid gap-4"
620
+ },
621
+ variants: {
622
+ columns: {
623
+ "two-columns": {
624
+ base: "grid-cols-2"
625
+ },
626
+ "three-columns": {
627
+ base: "grid-cols-3"
628
+ }
629
+ }
630
+ }
631
+ };
632
+
604
633
  const themeProse = {
605
634
  __proto__: null,
606
- uploraImage: uploraImage
635
+ uploraImage: uploraImage,
636
+ uploraImageGallery: uploraImageGallery
607
637
  };
608
638
 
609
639
  async function getAppTemplates({ options, resolve, nuxt, detectedComponents: contextDetectedComponents }) {
@@ -782,7 +812,7 @@ export {}
782
812
  };
783
813
  return `const cmsConfig = ${JSON.stringify(config, null, 2)}
784
814
 
785
- export const getCmsConfig = () => cmsConfig`;
815
+ export const useCmsConfig = () => cmsConfig`;
786
816
  }
787
817
  });
788
818
  return templates;
@@ -16,8 +16,8 @@
16
16
  v-bind="forwardedEditor"
17
17
  class="min-h-screen"
18
18
  content-type="markdown"
19
- placeholder="Введите '/' для выбора блока..."
20
19
  autofocus
20
+ :placeholder="{ placeholder: '\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u0435\u043A\u0441\u0442...', includeChildren: true }"
21
21
  :extensions="extensions"
22
22
  :handlers="customHandlers"
23
23
  >
@@ -64,7 +64,7 @@
64
64
  :editor="editor"
65
65
  :items="bubbleToolbarItems"
66
66
  :should-show="({ view, state }) => {
67
- if (editor.isActive('uplora-image')) {
67
+ if (editor.isActive('uplora-image') || editor.isActive('uplora-image-gallery')) {
68
68
  return false;
69
69
  }
70
70
  const { selection } = state;
@@ -92,7 +92,12 @@ import { computed } from "vue";
92
92
  import { useEditorDragHandle } from "../composables/useEditorDragHandle";
93
93
  import { useEditorSuggestions } from "../composables/useEditorSuggestions";
94
94
  import { useEditorToolbar } from "../composables/useEditorToolbar";
95
+ import { Caution as CautionExtension, CautionHandlers } from "../editor/caution/EditorCaution";
96
+ import { Note as NoteExtension, NoteHandlers } from "../editor/note/EditorNote";
97
+ import { Tip as TipExtension, TipHandlers } from "../editor/tip/EditorTip";
98
+ import { UploraImageGallery as UploraImageGalleryExtension, UploraImageGalleryHandlers } from "../editor/uplora-image-gallery/EditorUploraImageGallery";
95
99
  import { UploraImage as UploraImageExtension, UploraImageHandlers } from "../editor/uplora-image/EditorUploraImage";
100
+ import { Warning as WarningExtension, WarningHandlers } from "../editor/warning/EditorWarning";
96
101
  import CEditorLinkPopover from "./EditorLinkPopover.vue";
97
102
  </script>
98
103
 
@@ -143,11 +148,21 @@ const forwardedTextarea = useForwardPropsEmits(reactivePick(props, "modelValue")
143
148
  const appConfig = useAppConfig();
144
149
  const extensions = computed(() => [
145
150
  UploraImageExtension,
151
+ UploraImageGalleryExtension,
152
+ NoteExtension,
153
+ TipExtension,
154
+ WarningExtension,
155
+ CautionExtension,
146
156
  ...props.extensions || []
147
157
  ]);
148
158
  const customHandlers = computed(() => ({
149
159
  ...props.customHandlers || {},
150
- ...UploraImageHandlers
160
+ ...UploraImageHandlers,
161
+ ...UploraImageGalleryHandlers,
162
+ ...NoteHandlers,
163
+ ...TipHandlers,
164
+ ...WarningHandlers,
165
+ ...CautionHandlers
151
166
  }));
152
167
  const appendToBody = false ? () => document.body : void 0;
153
168
  const { items: suggestionItems } = useEditorSuggestions(customHandlers);
@@ -10,13 +10,13 @@ export interface FormSeoProps {
10
10
  declare const _default: typeof __VLS_export;
11
11
  export default _default;
12
12
  declare const __VLS_export: import("vue").DefineComponent<FormSeoProps & {
13
- modelValue?: SEO;
13
+ modelValue?: SEO | null;
14
14
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
15
- "update:modelValue": (value: SEO) => any;
15
+ "update:modelValue": (value: SEO | null | undefined) => any;
16
16
  }, string, import("vue").PublicProps, Readonly<FormSeoProps & {
17
- modelValue?: SEO;
17
+ modelValue?: SEO | null;
18
18
  }> & Readonly<{
19
- "onUpdate:modelValue"?: ((value: SEO) => any) | undefined;
19
+ "onUpdate:modelValue"?: ((value: SEO | null | undefined) => any) | undefined;
20
20
  }>, {
21
21
  name: string;
22
22
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -9,10 +9,15 @@
9
9
  <UFormField
10
10
  name="title"
11
11
  label="Заголовок"
12
- :hint="`${model.title.length}/60`"
12
+ :hint="`${state.title.length}/60`"
13
13
  :ui="{ hint: 'text-xs' }"
14
14
  >
15
- <UInput v-model="model.title" placeholder="Введите заголовок..." class="w-full" />
15
+ <UInput
16
+ :model-value="state.title"
17
+ placeholder="Введите заголовок..."
18
+ class="w-full"
19
+ @update:model-value="state = { ...state, title: $event }"
20
+ />
16
21
 
17
22
  <template #help>
18
23
  <p class="text-xs mb-2">
@@ -29,14 +34,15 @@
29
34
  <UFormField
30
35
  name="description"
31
36
  label="Описание"
32
- :hint="`${model.description.length}/160`"
37
+ :hint="`${state.description.length}/160`"
33
38
  :ui="{ hint: 'text-xs' }"
34
39
  >
35
40
  <UTextarea
36
- v-model="model.description"
41
+ :model-value="state.description"
37
42
  placeholder="Введите описание..."
38
43
  class="w-full"
39
44
  autoresize
45
+ @update:model-value="state = { ...state, description: $event }"
40
46
  />
41
47
 
42
48
  <template #help>
@@ -68,17 +74,23 @@ const props = defineProps({
68
74
  name: { type: String, required: false, default: "seo" },
69
75
  ui: { type: null, required: false }
70
76
  });
71
- const model = defineModel({ type: Object, ...{
72
- default: () => ({
73
- title: "",
74
- description: ""
75
- })
76
- } });
77
+ const model = defineModel({ type: [Object, null] });
78
+ const state = computed({
79
+ get: () => {
80
+ return model.value ?? {
81
+ title: "",
82
+ description: ""
83
+ };
84
+ },
85
+ set: (value) => {
86
+ model.value = value;
87
+ }
88
+ });
77
89
  const appConfig = useAppConfig();
78
90
  const schema = z.object({
79
- title: z.string().min(1),
80
- description: z.string().min(1)
91
+ title: z.string(),
92
+ description: z.string()
81
93
  });
82
- const { title, description } = useSeoStats(model);
94
+ const { title, description } = useSeoStats(() => state.value);
83
95
  const ui = computed(() => tv({ extend: tv(theme), ...appConfig.cms?.formSeo || {} })());
84
96
  </script>
@@ -10,13 +10,13 @@ export interface FormSeoProps {
10
10
  declare const _default: typeof __VLS_export;
11
11
  export default _default;
12
12
  declare const __VLS_export: import("vue").DefineComponent<FormSeoProps & {
13
- modelValue?: SEO;
13
+ modelValue?: SEO | null;
14
14
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
15
- "update:modelValue": (value: SEO) => any;
15
+ "update:modelValue": (value: SEO | null | undefined) => any;
16
16
  }, string, import("vue").PublicProps, Readonly<FormSeoProps & {
17
- modelValue?: SEO;
17
+ modelValue?: SEO | null;
18
18
  }> & Readonly<{
19
- "onUpdate:modelValue"?: ((value: SEO) => any) | undefined;
19
+ "onUpdate:modelValue"?: ((value: SEO | null | undefined) => any) | undefined;
20
20
  }>, {
21
21
  name: string;
22
22
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -1,16 +1,13 @@
1
1
  import type { AppConfig } from '@nuxt/schema';
2
2
  import type { ComponentConfig } from '../types';
3
+ import type { UploraImageProps } from './UploraImage.vue';
3
4
  import theme from '#build/cms/form-uplora-image';
4
5
  type FormUploraImage = ComponentConfig<typeof theme, AppConfig, 'formUploraImage'>;
5
- export interface FormUploraImageModelValue {
6
+ export interface FormUploraImageModelValue extends Pick<UploraImageProps, 'alt' | 'lqip' | 'color' | 'aspect' | 'width' | 'height'> {
6
7
  image?: string;
7
- alt?: string;
8
- color?: string;
9
- lqip?: string;
10
8
  }
11
9
  export interface FormUploraImageProps {
12
10
  showExtensions?: boolean;
13
- id?: string;
14
11
  name?: string;
15
12
  label?: string;
16
13
  disabled?: boolean;
@@ -26,18 +23,19 @@ export interface FormUploraImageEmits {
26
23
  declare const _default: typeof __VLS_export;
27
24
  export default _default;
28
25
  declare const __VLS_export: import("vue").DefineComponent<FormUploraImageProps & {
29
- modelValue?: FormUploraImageModelValue;
26
+ modelValue?: FormUploraImageModelValue | null;
30
27
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
28
  delete: () => any;
32
- "update:modelValue": (value: FormUploraImageModelValue) => any;
29
+ "update:modelValue": (value: FormUploraImageModelValue | null | undefined) => any;
33
30
  upload: (args_0: FormUploraImageModelValue) => any;
34
31
  }, string, import("vue").PublicProps, Readonly<FormUploraImageProps & {
35
- modelValue?: FormUploraImageModelValue;
32
+ modelValue?: FormUploraImageModelValue | null;
36
33
  }> & Readonly<{
37
34
  onDelete?: (() => any) | undefined;
38
- "onUpdate:modelValue"?: ((value: FormUploraImageModelValue) => any) | undefined;
35
+ "onUpdate:modelValue"?: ((value: FormUploraImageModelValue | null | undefined) => any) | undefined;
39
36
  onUpload?: ((args_0: FormUploraImageModelValue) => any) | undefined;
40
37
  }>, {
38
+ name: string;
41
39
  showExtensions: boolean;
42
40
  nested: boolean;
43
41
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -8,17 +8,34 @@
8
8
  >
9
9
  <UFormField name="image" :label="label">
10
10
  <div :class="ui.base({ class: [props.ui?.base] })">
11
- <template v-if="modelValue.image">
12
- <UPopover :content="{ align: 'center', side: 'top', sideOffset: 8 }" :ui="{ content: 'p-1' }">
11
+ <template v-if="state.image">
12
+ <UPopover
13
+ :content="{ align: 'center', side: 'top', sideOffset: 8 }"
14
+ :ui="{ content: 'p-1' }"
15
+ mode="click"
16
+ >
13
17
  <CUploraImage
14
- :image="modelValue.image"
15
- :alt="modelValue.alt"
16
- :color="modelValue.color"
17
- :lqip="modelValue.lqip"
18
+ :image="state.image"
19
+ :alt="state.alt"
20
+ :color="state.color"
21
+ :lqip="state.lqip"
22
+ :aspect="state.aspect"
23
+ :width="state.width"
24
+ :height="state.height"
18
25
  />
19
26
 
20
27
  <template #content>
21
28
  <div class="flex items-center gap-0.5">
29
+ <USelect
30
+ variant="ghost"
31
+ color="neutral"
32
+ size="sm"
33
+ :items="aspectItems"
34
+ :model-value="state.aspect"
35
+ default-value="horizontal"
36
+ @update:model-value="state = { ...state, aspect: $event === 'horizontal' ? void 0 : $event }"
37
+ />
38
+
22
39
  <UButton
23
40
  color="neutral"
24
41
  size="sm"
@@ -33,13 +50,13 @@
33
50
  variant="ghost"
34
51
  label=""
35
52
  :icon="appConfig.ui.icons.trash"
36
- @confirm="deleteExecute(modelValue.image)"
53
+ @confirm="deleteExecute(state.image)"
37
54
  />
38
55
  </div>
39
56
  </template>
40
57
  </UPopover>
41
58
  </template>
42
- <div v-else :id="id" :class="ui.uploader({ class: [props.ui?.uploader] })">
59
+ <div v-else :class="ui.uploader({ class: [props.ui?.uploader] })">
43
60
  <template v-if="uploadStatus === 'pending'">
44
61
  <UIcon :name="appConfig.ui.icons.loading" :class="ui.uploaderPendingIcon({ class: [props.ui?.uploaderPendingIcon] })" />
45
62
  </template>
@@ -48,7 +65,6 @@
48
65
  type="button"
49
66
  :class="ui.uploaderIdleButton({ class: [props.ui?.uploaderIdleButton] })"
50
67
  :disabled="disabled"
51
- v-bind="ariaAttrs"
52
68
  @click="open"
53
69
  >
54
70
  <UAvatar :icon="appConfig.ui.icons.image" size="lg" />
@@ -85,12 +101,12 @@
85
101
  </UFormField>
86
102
  <UFormField name="alt">
87
103
  <UInput
88
- v-model="modelValue.alt"
89
104
  placeholder="Введите описание..."
90
105
  variant="none"
91
106
  size="xs"
107
+ :model-value="state.alt"
92
108
  :ui="{ base: 'text-center text-toned' }"
93
- @update:model-value="onAltInput"
109
+ @update:model-value="state = { ...state, alt: $event || void 0 }"
94
110
  />
95
111
  </UFormField>
96
112
  </UForm>
@@ -98,9 +114,9 @@
98
114
 
99
115
  <script>
100
116
  import theme from "#build/cms/form-uplora-image";
101
- import { useAppConfig, useFormField, useUploraDelete, useUploraUpload } from "#imports";
117
+ import { useAppConfig, useUploraDelete, useUploraUpload } from "#imports";
102
118
  import { imagesExtensions } from "@uplora/formats";
103
- import { computed, useId } from "vue";
119
+ import { computed } from "vue";
104
120
  import { z } from "zod";
105
121
  import { tv } from "../tv";
106
122
  import CButtonDeleteConfirm from "./ButtonDeleteConfirm.vue";
@@ -109,8 +125,7 @@ import CButtonDeleteConfirm from "./ButtonDeleteConfirm.vue";
109
125
  <script setup>
110
126
  const props = defineProps({
111
127
  showExtensions: { type: Boolean, required: false, default: true },
112
- id: { type: String, required: false },
113
- name: { type: String, required: false },
128
+ name: { type: String, required: false, default: "image" },
114
129
  label: { type: String, required: false },
115
130
  disabled: { type: Boolean, required: false },
116
131
  as: { type: null, required: false },
@@ -119,63 +134,72 @@ const props = defineProps({
119
134
  ui: { type: null, required: false }
120
135
  });
121
136
  const emit = defineEmits(["upload", "delete"]);
122
- const modelValue = defineModel({ type: Object, ...{
123
- default: () => ({
124
- image: void 0,
125
- alt: void 0,
126
- lqip: void 0,
127
- color: void 0
128
- })
129
- } });
137
+ const model = defineModel({ type: [Object, null] });
138
+ const state = computed({
139
+ get: () => {
140
+ return model.value ?? {
141
+ image: void 0,
142
+ width: void 0,
143
+ height: void 0,
144
+ alt: void 0,
145
+ lqip: void 0,
146
+ color: void 0,
147
+ aspect: void 0
148
+ };
149
+ },
150
+ set: (value) => {
151
+ model.value = value;
152
+ }
153
+ });
130
154
  const appConfig = useAppConfig();
131
155
  const schema = z.object({
132
156
  image: z.string().min(1),
133
157
  alt: z.string().min(1),
158
+ width: z.number(),
159
+ height: z.number(),
134
160
  lqip: z.string().min(1).optional(),
135
- color: z.string().min(1).optional()
161
+ color: z.string().min(1).optional(),
162
+ aspect: z.union([z.literal("horizontal"), z.literal("vertical"), z.literal("dynamic")]).optional()
136
163
  });
137
164
  const extensions = computed(() => imagesExtensions.filter((extension) => extension !== "jpeg").join(", "));
138
- const { id: _id, disabled, emitFormChange, emitFormInput, ariaAttrs } = useFormField(props);
139
- const id = _id.value ?? useId();
165
+ const aspectItems = [
166
+ { value: "horizontal", label: "\u0413\u043E\u0440\u0438\u0437\u043E\u043D\u0442\u0430\u043B\u044C\u043D\u044B\u0439" },
167
+ { value: "vertical", label: "\u0412\u0435\u0440\u0442\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439" },
168
+ { value: "dynamic", label: "\u0414\u0438\u043D\u0430\u043C\u0438\u0447\u0435\u0441\u043A\u0438\u0439" }
169
+ ];
140
170
  const { open, execute: uploadExecute, status: uploadStatus, reset: resetUpload, onUploaded } = useUploraUpload({
141
171
  accept: "image/*"
142
172
  });
143
173
  const { execute: deleteExecute, onDeleted } = useUploraDelete();
144
- function onAltInput(alt) {
145
- modelValue.value = {
146
- ...modelValue.value,
147
- alt: alt || void 0
148
- };
149
- emitFormChange();
150
- emitFormInput();
151
- }
152
174
  function resetState() {
153
- modelValue.value = {
175
+ resetUpload();
176
+ state.value = {
154
177
  image: void 0,
178
+ width: void 0,
179
+ height: void 0,
155
180
  alt: void 0,
156
181
  lqip: void 0,
157
- color: void 0
182
+ color: void 0,
183
+ aspect: void 0
158
184
  };
159
- emitFormChange();
160
- emitFormInput();
161
185
  }
162
186
  onUploaded((file) => {
163
- modelValue.value = {
164
- ...modelValue.value,
187
+ state.value = {
165
188
  image: file.id,
189
+ width: file.width,
190
+ height: file.height,
191
+ alt: void 0,
166
192
  lqip: file.lqip,
167
- color: file.color
193
+ color: file.color,
194
+ aspect: void 0
168
195
  };
169
- emit("upload", modelValue.value);
170
- emitFormChange();
171
- emitFormInput();
196
+ emit("upload", state.value);
172
197
  });
173
198
  onDeleted(() => {
174
- resetUpload();
175
199
  resetState();
176
200
  emit("delete");
177
201
  });
178
202
  const ui = computed(() => tv({ extend: tv(theme), ...appConfig.cms?.formUploraImage || {} })({
179
- disabled: disabled.value
203
+ disabled: props.disabled
180
204
  }));
181
205
  </script>
@@ -1,16 +1,13 @@
1
1
  import type { AppConfig } from '@nuxt/schema';
2
2
  import type { ComponentConfig } from '../types';
3
+ import type { UploraImageProps } from './UploraImage.vue';
3
4
  import theme from '#build/cms/form-uplora-image';
4
5
  type FormUploraImage = ComponentConfig<typeof theme, AppConfig, 'formUploraImage'>;
5
- export interface FormUploraImageModelValue {
6
+ export interface FormUploraImageModelValue extends Pick<UploraImageProps, 'alt' | 'lqip' | 'color' | 'aspect' | 'width' | 'height'> {
6
7
  image?: string;
7
- alt?: string;
8
- color?: string;
9
- lqip?: string;
10
8
  }
11
9
  export interface FormUploraImageProps {
12
10
  showExtensions?: boolean;
13
- id?: string;
14
11
  name?: string;
15
12
  label?: string;
16
13
  disabled?: boolean;
@@ -26,18 +23,19 @@ export interface FormUploraImageEmits {
26
23
  declare const _default: typeof __VLS_export;
27
24
  export default _default;
28
25
  declare const __VLS_export: import("vue").DefineComponent<FormUploraImageProps & {
29
- modelValue?: FormUploraImageModelValue;
26
+ modelValue?: FormUploraImageModelValue | null;
30
27
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
28
  delete: () => any;
32
- "update:modelValue": (value: FormUploraImageModelValue) => any;
29
+ "update:modelValue": (value: FormUploraImageModelValue | null | undefined) => any;
33
30
  upload: (args_0: FormUploraImageModelValue) => any;
34
31
  }, string, import("vue").PublicProps, Readonly<FormUploraImageProps & {
35
- modelValue?: FormUploraImageModelValue;
32
+ modelValue?: FormUploraImageModelValue | null;
36
33
  }> & Readonly<{
37
34
  onDelete?: (() => any) | undefined;
38
- "onUpdate:modelValue"?: ((value: FormUploraImageModelValue) => any) | undefined;
35
+ "onUpdate:modelValue"?: ((value: FormUploraImageModelValue | null | undefined) => any) | undefined;
39
36
  onUpload?: ((args_0: FormUploraImageModelValue) => any) | undefined;
40
37
  }>, {
38
+ name: string;
41
39
  showExtensions: boolean;
42
40
  nested: boolean;
43
41
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -11,6 +11,9 @@ export interface UploraImageProps {
11
11
  sizes?: ImageSize[];
12
12
  lqip?: string;
13
13
  color?: string;
14
+ aspect?: 'horizontal' | 'vertical' | 'dynamic';
15
+ width?: number | string;
16
+ height?: number | string;
14
17
  loading?: 'lazy' | 'eager';
15
18
  preload?: boolean | {
16
19
  fetchPriority: 'auto' | 'high' | 'low';
@@ -34,4 +37,5 @@ declare const __VLS_export: import("vue").DefineComponent<UploraImageProps, {},
34
37
  onLoad?: ((args_0: Event) => any) | undefined;
35
38
  }>, {
36
39
  loading: "lazy" | "eager";
40
+ aspect: "horizontal" | "vertical" | "dynamic";
37
41
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;