@hywax/cms 0.0.22 → 0.0.23

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.
@@ -2,5 +2,12 @@ export default {
2
2
  "slots": {
3
3
  "root": "h-full w-full relative",
4
4
  "editor": "min-h-full w-full focus:outline-none editor-content-full relative"
5
+ },
6
+ "variants": {
7
+ "disabled": {
8
+ "true": {
9
+ "root": "cursor-not-allowed opacity-75"
10
+ }
11
+ }
5
12
  }
6
13
  }
@@ -2,5 +2,12 @@ export default {
2
2
  "slots": {
3
3
  "root": "relative",
4
4
  "editor": "w-full focus:outline-none editor-content-light relative"
5
+ },
6
+ "variants": {
7
+ "disabled": {
8
+ "true": {
9
+ "root": "cursor-not-allowed opacity-75"
10
+ }
11
+ }
5
12
  }
6
13
  }
@@ -11,5 +11,12 @@ export default {
11
11
  "uploaderIdleExtensions": "mt-2 text-xs text-muted uppercase",
12
12
  "uploaderErrorText": "text-center font-medium",
13
13
  "uploaderErrorActions": "flex gap-2 mt-4"
14
+ },
15
+ "variants": {
16
+ "disabled": {
17
+ "true": {
18
+ "root": "cursor-not-allowed opacity-75"
19
+ }
20
+ }
14
21
  }
15
22
  }
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hywax/cms",
3
- "version": "0.0.22",
3
+ "version": "0.0.23",
4
4
  "configKey": "cms",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.1",
package/dist/module.mjs CHANGED
@@ -6,7 +6,7 @@ import { snakeCase, kebabCase } from 'scule';
6
6
  import { readFile, writeFile } from 'node:fs/promises';
7
7
 
8
8
  const name = "@hywax/cms";
9
- const version = "0.0.22";
9
+ const version = "0.0.23";
10
10
 
11
11
  function createContext(options, nuxt) {
12
12
  const { resolve } = createResolver(import.meta.url);
@@ -228,6 +228,13 @@ const editorContentFull = {
228
228
  slots: {
229
229
  root: "h-full w-full relative",
230
230
  editor: "min-h-full w-full focus:outline-none editor-content-full relative"
231
+ },
232
+ variants: {
233
+ disabled: {
234
+ true: {
235
+ root: "cursor-not-allowed opacity-75"
236
+ }
237
+ }
231
238
  }
232
239
  };
233
240
 
@@ -235,6 +242,13 @@ const editorContentLight = {
235
242
  slots: {
236
243
  root: "relative",
237
244
  editor: "w-full focus:outline-none editor-content-light relative"
245
+ },
246
+ variants: {
247
+ disabled: {
248
+ true: {
249
+ root: "cursor-not-allowed opacity-75"
250
+ }
251
+ }
238
252
  }
239
253
  };
240
254
 
@@ -298,6 +312,13 @@ const inputUploraImage = {
298
312
  uploaderIdleExtensions: "mt-2 text-xs text-muted uppercase",
299
313
  uploaderErrorText: "text-center font-medium",
300
314
  uploaderErrorActions: "flex gap-2 mt-4"
315
+ },
316
+ variants: {
317
+ disabled: {
318
+ true: {
319
+ root: "cursor-not-allowed opacity-75"
320
+ }
321
+ }
301
322
  }
302
323
  };
303
324
 
@@ -1,7 +1,12 @@
1
1
  <template>
2
2
  <Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
3
3
  <ProseKit :editor="editor">
4
- <div ref="editorRef" :class="ui.editor({ class: [props.ui?.editor, 'pl-14'] })" />
4
+ <div
5
+ :id="id"
6
+ ref="editorRef"
7
+ :class="ui.editor({ class: [props.ui?.editor, 'pl-14'] })"
8
+ v-bind="ariaAttrs"
9
+ />
5
10
 
6
11
  <BlockMenu />
7
12
  <SlashCommand />
@@ -12,7 +17,7 @@
12
17
 
13
18
  <script>
14
19
  import theme from "#build/cms/editor-content-full";
15
- import { computed, useAppConfig, useTemplateRef, watchPostEffect } from "#imports";
20
+ import { computed, useAppConfig, useFormField, useId, useTemplateRef, watchPostEffect } from "#imports";
16
21
  import { createEditor } from "prosekit/core";
17
22
  import { ProseKit, useDocChange } from "prosekit/vue";
18
23
  import { Primitive } from "reka-ui";
@@ -27,6 +32,9 @@ import "prosekit/basic/style.css";
27
32
 
28
33
  <script setup>
29
34
  const props = defineProps({
35
+ id: { type: String, required: false },
36
+ name: { type: String, required: false },
37
+ disabled: { type: Boolean, required: false },
30
38
  as: { type: null, required: false },
31
39
  class: { type: null, required: false },
32
40
  ui: { type: null, required: false }
@@ -38,14 +46,20 @@ const editor = createEditor({
38
46
  defaultContent: await markdownToDoc(modelValue.value)
39
47
  });
40
48
  const editorRef = useTemplateRef("editorRef");
49
+ const { id: _id, disabled, emitFormChange, emitFormInput, ariaAttrs } = useFormField(props);
50
+ const id = _id.value ?? useId();
41
51
  useDocChange(async () => {
42
52
  modelValue.value = await docToMarkdown(editor.getDocJSON());
53
+ emitFormChange();
54
+ emitFormInput();
43
55
  }, { editor });
44
56
  watchPostEffect((onCleanup) => {
45
57
  editor.mount(editorRef.value);
46
58
  onCleanup(() => editor.unmount());
47
59
  });
48
- const ui = computed(() => tv({ extend: tv(theme), ...appConfig.cms?.editorContentFull || {} })());
60
+ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.cms?.editorContentFull || {} })({
61
+ disabled: disabled.value
62
+ }));
49
63
  </script>
50
64
 
51
65
  <style scoped>
@@ -4,6 +4,9 @@ import theme from '#build/cms/editor-content-full';
4
4
  import 'prosekit/basic/style.css';
5
5
  type EditorContentFull = ComponentConfig<typeof theme, AppConfig, 'editorContentFull'>;
6
6
  export interface EditorContentFullProps {
7
+ id?: string;
8
+ name?: string;
9
+ disabled?: boolean;
7
10
  as?: any;
8
11
  class?: any;
9
12
  ui?: EditorContentFull['slots'];
@@ -1,14 +1,19 @@
1
1
  <template>
2
2
  <Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
3
3
  <ProseKit :editor="editor">
4
- <div ref="editorRef" :class="ui.editor({ class: props.ui?.editor })" />
4
+ <div
5
+ :id="id"
6
+ ref="editorRef"
7
+ :class="ui.editor({ class: props.ui?.editor })"
8
+ v-bind="ariaAttrs"
9
+ />
5
10
  </ProseKit>
6
11
  </Primitive>
7
12
  </template>
8
13
 
9
14
  <script>
10
15
  import theme from "#build/cms/editor-content-light";
11
- import { computed, useAppConfig, useTemplateRef, watchPostEffect } from "#imports";
16
+ import { computed, useAppConfig, useFormField, useId, useTemplateRef, watchPostEffect } from "#imports";
12
17
  import { createEditor } from "prosekit/core";
13
18
  import { ProseKit, useDocChange } from "prosekit/vue";
14
19
  import { Primitive } from "reka-ui";
@@ -20,6 +25,9 @@ import "prosekit/basic/style.css";
20
25
 
21
26
  <script setup>
22
27
  const props = defineProps({
28
+ id: { type: String, required: false },
29
+ name: { type: String, required: false },
30
+ disabled: { type: Boolean, required: false },
23
31
  as: { type: null, required: false },
24
32
  class: { type: null, required: false },
25
33
  ui: { type: null, required: false }
@@ -31,14 +39,20 @@ const editor = createEditor({
31
39
  defaultContent: await markdownToDoc(modelValue.value)
32
40
  });
33
41
  const editorRef = useTemplateRef("editorRef");
42
+ const { id: _id, disabled, emitFormChange, emitFormInput, ariaAttrs } = useFormField(props);
43
+ const id = _id.value ?? useId();
34
44
  useDocChange(async () => {
35
45
  modelValue.value = await docToMarkdown(editor.getDocJSON());
46
+ emitFormChange();
47
+ emitFormInput();
36
48
  }, { editor });
37
49
  watchPostEffect((onCleanup) => {
38
50
  editor.mount(editorRef.value);
39
51
  onCleanup(() => editor.unmount());
40
52
  });
41
- const ui = computed(() => tv({ extend: tv(theme), ...appConfig.cms?.editorContentLight || {} })());
53
+ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.cms?.editorContentLight || {} })({
54
+ disabled: disabled.value
55
+ }));
42
56
  </script>
43
57
 
44
58
  <style scoped>
@@ -4,6 +4,9 @@ import theme from '#build/cms/editor-content-light';
4
4
  import 'prosekit/basic/style.css';
5
5
  type EditorContentLight = ComponentConfig<typeof theme, AppConfig, 'editorContentLight'>;
6
6
  export interface EditorContentLightProps {
7
+ id?: string;
8
+ name?: string;
9
+ disabled?: boolean;
7
10
  as?: any;
8
11
  class?: any;
9
12
  ui?: EditorContentLight['slots'];
@@ -9,6 +9,13 @@
9
9
  />
10
10
 
11
11
  <div :class="ui.imageActions({ class: [props.ui?.imageActions] })">
12
+ <UBadge
13
+ v-if="!modelValue.alt"
14
+ label="Alt"
15
+ color="error"
16
+ :icon="appConfig.ui.icons.warning"
17
+ />
18
+
12
19
  <ButtonDelete
13
20
  :icon="appConfig.ui.icons.trash"
14
21
  color="neutral"
@@ -35,14 +42,16 @@
35
42
  </UPopover>
36
43
  </div>
37
44
  </template>
38
- <div v-else :class="ui.uploader({ class: [props.ui?.uploader] })">
45
+ <div v-else :id="id" :class="ui.uploader({ class: [props.ui?.uploader] })">
39
46
  <template v-if="uploadStatus === 'pending'">
40
47
  <UIcon :name="appConfig.ui.icons.loading" :class="ui.uploaderPendingIcon({ class: [props.ui?.uploaderPendingIcon] })" />
41
48
  </template>
42
49
  <template v-else-if="uploadStatus === 'idle'">
43
50
  <button
44
- :class="ui.uploaderIdleButton({ class: [props.ui?.uploaderIdleButton] })"
45
51
  type="button"
52
+ :class="ui.uploaderIdleButton({ class: [props.ui?.uploaderIdleButton] })"
53
+ :disabled="disabled"
54
+ v-bind="ariaAttrs"
46
55
  @click="open"
47
56
  >
48
57
  <UIcon :name="appConfig.ui.icons.imageUp" :class="ui.uploaderIdleIcon({ class: [props.ui?.uploaderIdleIcon] })" />
@@ -79,7 +88,7 @@
79
88
 
80
89
  <script>
81
90
  import theme from "#build/cms/input-uplora-image";
82
- import { computed, reactive, useAppConfig } from "#imports";
91
+ import { computed, reactive, useAppConfig, useFormField, useId } from "#imports";
83
92
  import { imagesExtensions } from "@uplora/formats";
84
93
  import { Primitive } from "reka-ui";
85
94
  import { useUploraDelete, useUploraUpload } from "../composables/useUplora";
@@ -91,6 +100,9 @@ import UploraImage from "./UploraImage.vue";
91
100
  <script setup>
92
101
  const props = defineProps({
93
102
  showExtensions: { type: Boolean, required: false, default: true },
103
+ id: { type: String, required: false },
104
+ name: { type: String, required: false },
105
+ disabled: { type: Boolean, required: false },
94
106
  as: { type: null, required: false },
95
107
  class: { type: null, required: false },
96
108
  ui: { type: null, required: false }
@@ -106,6 +118,8 @@ const appConfig = useAppConfig();
106
118
  const state = reactive({
107
119
  alt: modelValue.value.alt
108
120
  });
121
+ const { id: _id, disabled, emitFormChange, emitFormInput, ariaAttrs } = useFormField(props);
122
+ const id = _id.value ?? useId();
109
123
  const { open, execute: uploadExecute, status: uploadStatus, reset: resetUpload, onUploaded } = useUploraUpload({
110
124
  accept: "image/*"
111
125
  });
@@ -117,6 +131,8 @@ onUploaded((file) => {
117
131
  lqip: file.lqip
118
132
  };
119
133
  emit("upload", modelValue.value);
134
+ emitFormChange();
135
+ emitFormInput();
120
136
  });
121
137
  onDeleted(() => {
122
138
  resetUpload();
@@ -125,6 +141,8 @@ onDeleted(() => {
125
141
  alt: ""
126
142
  };
127
143
  emit("delete");
144
+ emitFormChange();
145
+ emitFormInput();
128
146
  });
129
147
  function syncState() {
130
148
  modelValue.value = {
@@ -132,5 +150,7 @@ function syncState() {
132
150
  alt: state.alt
133
151
  };
134
152
  }
135
- const ui = computed(() => tv({ extend: tv(theme), ...appConfig.cms?.inputUploraImage || {} })());
153
+ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.cms?.inputUploraImage || {} })({
154
+ disabled: disabled.value
155
+ }));
136
156
  </script>
@@ -4,6 +4,9 @@ import theme from '#build/cms/input-uplora-image';
4
4
  type InputUploraImage = ComponentConfig<typeof theme, AppConfig, 'inputUploraImage'>;
5
5
  export interface InputUploraImageProps {
6
6
  showExtensions?: boolean;
7
+ id?: string;
8
+ name?: string;
9
+ disabled?: boolean;
7
10
  as?: any;
8
11
  class?: any;
9
12
  ui?: InputUploraImage['slots'];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hywax/cms",
3
3
  "type": "module",
4
- "version": "0.0.22",
4
+ "version": "0.0.23",
5
5
  "description": "Hywax CMS. ⚠️ This package is intended for internal use only.",
6
6
  "repository": {
7
7
  "type": "git",