@abraca/nuxt 0.1.0 → 0.2.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.
@@ -1,53 +1,18 @@
1
- import type { AbracadabraLocale } from '../locale.js';
2
1
  type __VLS_Props = {
3
- showTrash?: boolean;
4
- allowFileDrop?: boolean;
5
- draggable?: boolean;
2
+ collapsed?: boolean;
3
+ editable?: boolean;
6
4
  selectedId?: string | null;
7
- labels?: Partial<AbracadabraLocale['documentTree']>;
8
5
  };
9
- interface FlatItem {
10
- id: string;
11
- label: string;
12
- type?: string;
13
- meta?: Record<string, any>;
14
- depth: number;
15
- parentId: string | null;
16
- order: number;
17
- isExpanded: boolean;
18
- hasChildren: boolean;
19
- }
20
- declare var __VLS_1: {}, __VLS_20: {
21
- entry: FlatItem;
22
- depth: number;
23
- isExpanded: boolean;
24
- }, __VLS_42: {}, __VLS_85: {};
25
- type __VLS_Slots = {} & {
26
- header?: (props: typeof __VLS_1) => any;
27
- } & {
28
- item?: (props: typeof __VLS_20) => any;
29
- } & {
30
- empty?: (props: typeof __VLS_42) => any;
31
- } & {
32
- footer?: (props: typeof __VLS_85) => any;
33
- };
34
- declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
35
- select: (docId: string) => any;
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {
7
+ handleExternalDrop: (e: DragEvent, parentId?: string | null) => any;
8
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
9
+ navigate: (id: string) => any;
36
10
  create: (parentId: string | null) => any;
37
11
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
38
- onSelect?: ((docId: string) => any) | undefined;
12
+ onNavigate?: ((id: string) => any) | undefined;
39
13
  onCreate?: ((parentId: string | null) => any) | undefined;
40
14
  }>, {
41
- draggable: boolean;
42
- showTrash: boolean;
43
- allowFileDrop: boolean;
44
- selectedId: string | null;
15
+ editable: boolean;
45
16
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
46
- declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
47
17
  declare const _default: typeof __VLS_export;
48
18
  export default _default;
49
- type __VLS_WithSlots<T, S> = T & {
50
- new (): {
51
- $slots: S;
52
- };
53
- };
@@ -1,3 +1,4 @@
1
+ import type { DocPageMeta } from '../types.js';
1
2
  type __VLS_Props = {
2
3
  /** Y.Doc ID to load as a child document */
3
4
  docId: string;
@@ -15,6 +16,8 @@ type __VLS_Props = {
15
16
  showSuggestionMenu?: boolean;
16
17
  /** Whether to show the drag handle (plus + grip buttons). Set false to use slot. */
17
18
  showDragHandle?: boolean;
19
+ /** Current document metadata from the doc-tree — written into MetaField storage */
20
+ docMeta?: DocPageMeta;
18
21
  };
19
22
  type __VLS_ModelProps = {
20
23
  modelValue?: any;
@@ -38,11 +41,13 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
38
41
  rename: (label: string) => any;
39
42
  ready: () => any;
40
43
  update: (content: any) => any;
44
+ updateMeta: (patch: Partial<DocPageMeta>) => any;
41
45
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
42
46
  "onUpdate:modelValue"?: ((value: any) => any) | undefined;
43
47
  onRename?: ((label: string) => any) | undefined;
44
48
  onReady?: (() => any) | undefined;
45
49
  onUpdate?: ((content: any) => any) | undefined;
50
+ onUpdateMeta?: ((patch: Partial<DocPageMeta>) => any) | undefined;
46
51
  }>, {
47
52
  contentType: "json" | "html" | "markdown";
48
53
  editable: boolean;
@@ -1,5 +1,5 @@
1
1
  <script setup>
2
- import { shallowRef, ref, watch, computed, nextTick } from "vue";
2
+ import { shallowRef, ref, watch, watchEffect, computed, nextTick } from "vue";
3
3
  import { useEditor } from "../composables/useEditor";
4
4
  import { useEditorToolbar } from "../composables/useEditorToolbar";
5
5
  import { useEditorSuggestions } from "../composables/useEditorSuggestions";
@@ -12,11 +12,13 @@ const props = defineProps({
12
12
  placeholder: { type: String, required: false },
13
13
  showToolbar: { type: Boolean, required: false, default: true },
14
14
  showSuggestionMenu: { type: Boolean, required: false, default: true },
15
- showDragHandle: { type: Boolean, required: false, default: true }
15
+ showDragHandle: { type: Boolean, required: false, default: true },
16
+ docMeta: { type: Object, required: false }
16
17
  });
17
- const emit = defineEmits(["ready", "update", "rename"]);
18
+ const emit = defineEmits(["ready", "update", "rename", "updateMeta"]);
18
19
  const model = defineModel({ type: null });
19
- const { provider, registry } = useNuxtApp().$abracadabra;
20
+ const { doc, provider, registry } = useNuxtApp().$abracadabra;
21
+ const _treeMap = useSyncedMap(doc, "doc-tree");
20
22
  const childProvider = shallowRef(null);
21
23
  watch(provider, async (prov) => {
22
24
  if (!prov || !props.docId) return;
@@ -34,43 +36,96 @@ watch(ready, (val) => {
34
36
  if (val) emit("ready");
35
37
  });
36
38
  const editorRef = ref(null);
37
- const currentEditor = shallowRef(null);
38
39
  const { items: toolbarItems } = useEditorToolbar({ docId: props.docId });
39
40
  const { items: suggestionItems } = useEditorSuggestions({ docId: props.docId });
40
41
  const dragHandle = useEditorDragHandle();
41
- const _syncingFromDocLabel = ref(false);
42
- const _lastEmittedHeader = ref("");
43
- watch(model, (val) => {
44
- if (_syncingFromDocLabel.value) return;
45
- if (!val || typeof val !== "object" || !val.content?.length) return;
46
- const headerNode = val.content[0];
47
- if (headerNode?.type !== "documentHeader") return;
48
- const text = (headerNode.content ?? []).map((n) => n.text ?? "").join("");
49
- if (text !== _lastEmittedHeader.value) {
50
- _lastEmittedHeader.value = text;
51
- emit("rename", text || "Untitled");
52
- }
42
+ watchEffect(() => {
43
+ const isReady = ready.value;
44
+ const editorInstance = editorRef.value;
45
+ const docMeta = props.docMeta;
46
+ if (!isReady || !editorInstance) return;
47
+ const storage = editorInstance.editor?.storage?.metaField;
48
+ if (!storage) return;
49
+ storage.pageMeta = docMeta ?? null;
50
+ storage.updateMeta = (patch) => emit("updateMeta", patch);
53
51
  });
54
- watch(() => props.docLabel, (newLabel) => {
55
- if (!newLabel || _syncingFromDocLabel.value) return;
56
- const editor = editorRef.value?.editor;
57
- if (!editor) return;
58
- const first = editor.state.doc.firstChild;
52
+ let syncingFromEditor = false;
53
+ const _lastEmittedHeader = ref("");
54
+ function getHeaderText(ed) {
55
+ const first = ed.state.doc.firstChild;
56
+ if (!first || first.type.name !== "documentHeader") return "";
57
+ return first.textContent;
58
+ }
59
+ function setHeaderText(ed, text) {
60
+ const first = ed.state.doc.firstChild;
59
61
  if (!first || first.type.name !== "documentHeader") return;
60
- if (first.textContent === newLabel) return;
61
- _syncingFromDocLabel.value = true;
62
- const { tr, schema } = editor.state;
62
+ if (first.textContent === text) return;
63
+ const { tr, schema } = ed.state;
63
64
  const to = 1 + first.content.size;
64
- if (newLabel) {
65
- tr.replaceWith(1, to, schema.text(newLabel));
65
+ if (text) {
66
+ tr.replaceWith(1, to, schema.text(text));
66
67
  } else {
67
68
  tr.delete(1, to);
68
69
  }
69
- editor.view.dispatch(tr);
70
+ ed.view.dispatch(tr);
71
+ }
72
+ function syncHeaderToTree(ed) {
73
+ const text = getHeaderText(ed);
74
+ if (text === _lastEmittedHeader.value) return;
75
+ _lastEmittedHeader.value = text;
76
+ syncingFromEditor = true;
77
+ emit("rename", text || "Untitled");
70
78
  nextTick(() => {
71
- _syncingFromDocLabel.value = false;
79
+ syncingFromEditor = false;
72
80
  });
81
+ }
82
+ watchEffect((onCleanup) => {
83
+ const ed = editorRef.value?.editor;
84
+ if (!ed || !ready.value) return;
85
+ let initialSyncDone = false;
86
+ function doInitialSync() {
87
+ if (initialSyncDone) return;
88
+ initialSyncDone = true;
89
+ const headerText = getHeaderText(ed);
90
+ const treeLabel = props.docLabel ?? "";
91
+ if (headerText !== treeLabel) {
92
+ const treeMeansEmpty = !treeLabel || treeLabel === "Untitled";
93
+ const headerMeansEmpty = !headerText;
94
+ if (treeMeansEmpty && headerMeansEmpty) return;
95
+ if (!treeMeansEmpty && headerMeansEmpty) {
96
+ setHeaderText(ed, treeLabel);
97
+ return;
98
+ }
99
+ _lastEmittedHeader.value = headerText;
100
+ syncingFromEditor = true;
101
+ emit("rename", headerText);
102
+ nextTick(() => {
103
+ syncingFromEditor = false;
104
+ });
105
+ }
106
+ }
107
+ function onUpdate() {
108
+ syncHeaderToTree(ed);
109
+ }
110
+ nextTick(() => doInitialSync());
111
+ ed.on("update", onUpdate);
112
+ onCleanup(() => ed.off("update", onUpdate));
73
113
  });
114
+ watch(() => props.docLabel, (newLabel) => {
115
+ if (syncingFromEditor) return;
116
+ if (newLabel === _lastEmittedHeader.value) return;
117
+ if (!_treeMap.lastUpdateLocal.value) return;
118
+ const ed = editorRef.value?.editor;
119
+ if (!ed || !ready.value) return;
120
+ setHeaderText(ed, newLabel || "");
121
+ });
122
+ const editorHandlers = {
123
+ insertMetaField: {
124
+ canExecute: () => true,
125
+ execute: (editor, item) => editor.chain().focus().insertMetaField(item.attrs),
126
+ isActive: () => false
127
+ }
128
+ };
74
129
  const mentionItems = computed(
75
130
  () => registry.getAllMentionProviders().flatMap((p) => p.label ? [p] : [])
76
131
  );
@@ -101,6 +156,7 @@ function onPlusClick(e, onClick) {
101
156
  :editable="editable"
102
157
  :extensions="extensions"
103
158
  :starter-kit="{ undoRedo: false, codeBlock: false, document: false }"
159
+ :handlers="editorHandlers"
104
160
  :placeholder="placeholder"
105
161
  v-slot="{ editor }"
106
162
  @update:model-value="emit('update', $event)"
@@ -1,3 +1,4 @@
1
+ import type { DocPageMeta } from '../types.js';
1
2
  type __VLS_Props = {
2
3
  /** Y.Doc ID to load as a child document */
3
4
  docId: string;
@@ -15,6 +16,8 @@ type __VLS_Props = {
15
16
  showSuggestionMenu?: boolean;
16
17
  /** Whether to show the drag handle (plus + grip buttons). Set false to use slot. */
17
18
  showDragHandle?: boolean;
19
+ /** Current document metadata from the doc-tree — written into MetaField storage */
20
+ docMeta?: DocPageMeta;
18
21
  };
19
22
  type __VLS_ModelProps = {
20
23
  modelValue?: any;
@@ -38,11 +41,13 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
38
41
  rename: (label: string) => any;
39
42
  ready: () => any;
40
43
  update: (content: any) => any;
44
+ updateMeta: (patch: Partial<DocPageMeta>) => any;
41
45
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
42
46
  "onUpdate:modelValue"?: ((value: any) => any) | undefined;
43
47
  onRename?: ((label: string) => any) | undefined;
44
48
  onReady?: (() => any) | undefined;
45
49
  onUpdate?: ((content: any) => any) | undefined;
50
+ onUpdateMeta?: ((patch: Partial<DocPageMeta>) => any) | undefined;
46
51
  }>, {
47
52
  contentType: "json" | "html" | "markdown";
48
53
  editable: boolean;
@@ -19,7 +19,7 @@ const {
19
19
  moveWindow,
20
20
  resizeWindow
21
21
  } = useWindowManager();
22
- const win = computed(() => windows.value.get(props.windowId));
22
+ const win = computed(() => windows.get(props.windowId));
23
23
  const isAnimatingOut = ref(false);
24
24
  const animStyle = ref({});
25
25
  watch(() => win.value?.minimized, (minimized, wasMinimized) => {
@@ -379,7 +379,7 @@ const addFieldMenuItems = computed(
379
379
 
380
380
  <!-- Toggle -->
381
381
  <template v-if="field.type === 'toggle'">
382
- <UToggle
382
+ <USwitch
383
383
  :model-value="!!getCustomFieldValue(field)"
384
384
  @update:model-value="setCustomFieldValue(field, $event)"
385
385
  />
@@ -1,7 +1,7 @@
1
1
  <script setup>
2
2
  import { computed } from "vue";
3
3
  const { windows } = useWindowManager();
4
- const windowIds = computed(() => [...windows.value.keys()]);
4
+ const windowIds = computed(() => [...windows.keys()]);
5
5
  </script>
6
6
 
7
7
  <template>
@@ -3,6 +3,10 @@ type ConnectionStatusValue = 'disconnected' | 'connecting' | 'connected' | 'offl
3
3
  /**
4
4
  * Maps connection status + synced state to UI-ready label, color, and icon.
5
5
  *
6
+ * Includes a stabilization delay: when the status flickers between connecting
7
+ * and disconnected rapidly (server not reachable), waits 4 seconds before
8
+ * downgrading to "Offline" to avoid UI flashing.
9
+ *
6
10
  * If `status` and `synced` are not provided, reads from `useAbracadabra()` globals.
7
11
  *
8
12
  * Usage:
@@ -12,6 +16,6 @@ type ConnectionStatusValue = 'disconnected' | 'connecting' | 'connected' | 'offl
12
16
  export declare function useConnectionStatus(status?: MaybeRef<ConnectionStatusValue | string | undefined>, synced?: MaybeRef<boolean | undefined>): {
13
17
  label: import("vue").ComputedRef<string>;
14
18
  color: import("vue").ComputedRef<"success" | "warning" | "error">;
15
- icon: import("vue").ComputedRef<"i-lucide-cloud-check" | "i-lucide-cloud-upload" | "i-lucide-cloud" | "i-lucide-cloud-off">;
19
+ icon: import("vue").ComputedRef<"i-lucide-cloud-check" | "i-lucide-cloud" | "i-lucide-cloud-off">;
16
20
  };
17
21
  export {};
@@ -1,4 +1,4 @@
1
- import { computed, toValue } from "vue";
1
+ import { computed, ref, toValue, watch } from "vue";
2
2
  import { useAbraLocale } from "./useAbraLocale.js";
3
3
  import { useAbracadabra } from "./useAbracadabra.js";
4
4
  export function useConnectionStatus(status, synced) {
@@ -10,26 +10,51 @@ export function useConnectionStatus(status, synced) {
10
10
  });
11
11
  const resolvedSynced = computed(() => {
12
12
  if (synced !== void 0) return toValue(synced) ?? false;
13
- return abra.synced?.value ?? false;
13
+ const isSynced = abra.synced?.value ?? false;
14
+ if (isSynced) return true;
15
+ const isReady = abra.isReady?.value ?? false;
16
+ const isConnected = abra.status?.value === "connected";
17
+ return isReady && isConnected;
14
18
  });
19
+ const stableStatus = ref(resolvedStatus.value);
20
+ let offlineTimer = null;
21
+ watch(resolvedStatus, (next, prev) => {
22
+ if (offlineTimer) {
23
+ clearTimeout(offlineTimer);
24
+ offlineTimer = null;
25
+ }
26
+ if (next === "connected") {
27
+ stableStatus.value = "connected";
28
+ } else if (next === "connecting") {
29
+ stableStatus.value = "connecting";
30
+ } else if (next === "disconnected" || next === "offline") {
31
+ if (prev === "connecting" || prev === "connected") {
32
+ offlineTimer = setTimeout(() => {
33
+ stableStatus.value = resolvedStatus.value;
34
+ offlineTimer = null;
35
+ }, 4e3);
36
+ } else {
37
+ stableStatus.value = next;
38
+ }
39
+ } else {
40
+ stableStatus.value = next;
41
+ }
42
+ }, { immediate: true });
15
43
  const label = computed(() => {
16
- const s = resolvedStatus.value;
17
- if (s === "connected" && resolvedSynced.value) return locale.connected;
18
- if (s === "connected") return locale.syncing;
44
+ const s = stableStatus.value;
45
+ if (s === "connected") return locale.connected;
19
46
  if (s === "connecting") return locale.connecting;
20
47
  return locale.offline;
21
48
  });
22
49
  const color = computed(() => {
23
- const s = resolvedStatus.value;
24
- if (s === "connected" && resolvedSynced.value) return "success";
25
- if (s === "connected") return "warning";
50
+ const s = stableStatus.value;
51
+ if (s === "connected") return "success";
26
52
  if (s === "connecting") return "warning";
27
53
  return "error";
28
54
  });
29
55
  const icon = computed(() => {
30
- const s = resolvedStatus.value;
31
- if (s === "connected" && resolvedSynced.value) return "i-lucide-cloud-check";
32
- if (s === "connected") return "i-lucide-cloud-upload";
56
+ const s = stableStatus.value;
57
+ if (s === "connected") return "i-lucide-cloud-check";
33
58
  if (s === "connecting") return "i-lucide-cloud";
34
59
  return "i-lucide-cloud-off";
35
60
  });
@@ -1,3 +1,4 @@
1
+ import { META_FIELD_DEFINITIONS } from "../utils/metaFieldDefinitions.js";
1
2
  export function useEditorSuggestions(options = {}) {
2
3
  const registry = usePluginRegistry();
3
4
  const items = computed(() => {
@@ -21,6 +22,15 @@ export function useEditorSuggestions(options = {}) {
21
22
  { kind: "table", label: "Table", icon: "i-lucide-table" },
22
23
  { kind: "horizontalRule", label: "Divider", icon: "i-lucide-minus" }
23
24
  ],
25
+ [
26
+ { type: "label", label: "Properties" },
27
+ ...META_FIELD_DEFINITIONS.map((def) => ({
28
+ label: def.label,
29
+ icon: def.icon,
30
+ kind: "insertMetaField",
31
+ attrs: def.buildAttrs()
32
+ }))
33
+ ],
24
34
  [
25
35
  { type: "label", label: "Components" },
26
36
  { kind: "callout", label: "Callout", icon: "i-lucide-info" },
@@ -0,0 +1,16 @@
1
+ import { Node } from '@tiptap/core';
2
+ /**
3
+ * MetaField — an inline atomic chip node that lives inside documentMeta.
4
+ *
5
+ * - inline: true so documentMeta (content: 'inline*') can contain it and the
6
+ * cursor can be placed before/after chips, enabling the slash menu.
7
+ * - atom: true so it renders as a single NodeView unit.
8
+ * - stopEvent: true so TipTap never intercepts mouse/drag events inside the
9
+ * chip (prevents drag-handle hijacking USlider drags etc.).
10
+ *
11
+ * Values live in tree meta (Y.Map). The storage.metaField reactive object is
12
+ * the bridge: AEditor writes to it via watchEffect, MetaFieldView reads it.
13
+ */
14
+ export declare const MetaField: Node<any, any>;
15
+ export declare function schemaFieldToAttrs(field: any): Record<string, unknown>;
16
+ export declare function userFieldToAttrs(f: any): Record<string, unknown>;
@@ -0,0 +1,110 @@
1
+ import { Node, mergeAttributes } from "@tiptap/core";
2
+ import { VueNodeViewRenderer } from "@tiptap/vue-3";
3
+ import { reactive } from "vue";
4
+ import MetaFieldView from "./views/MetaFieldView.vue";
5
+ export const MetaField = Node.create({
6
+ name: "metaField",
7
+ inline: true,
8
+ group: "inline",
9
+ atom: true,
10
+ selectable: true,
11
+ addStorage() {
12
+ return reactive({
13
+ pageMeta: null,
14
+ updateMeta: null
15
+ });
16
+ },
17
+ addAttributes() {
18
+ return {
19
+ fieldType: { default: "colorPreset" },
20
+ fieldLabel: { default: "" },
21
+ userDefined: { default: false },
22
+ metaKey: { default: "" },
23
+ startKey: { default: "" },
24
+ endKey: { default: "" },
25
+ allDayKey: { default: "" },
26
+ latKey: { default: "" },
27
+ lngKey: { default: "" },
28
+ presets: { default: "[]" },
29
+ iconOptions: { default: "[]" },
30
+ options: { default: "[]" },
31
+ sliderMin: { default: 0 },
32
+ sliderMax: { default: 100 },
33
+ sliderStep: { default: 1 },
34
+ unit: { default: "" }
35
+ };
36
+ },
37
+ parseHTML() {
38
+ return [{ tag: 'span[data-type="meta-field"]' }];
39
+ },
40
+ renderHTML({ HTMLAttributes }) {
41
+ return ["span", mergeAttributes(HTMLAttributes, { "data-type": "meta-field" })];
42
+ },
43
+ addNodeView() {
44
+ return VueNodeViewRenderer(MetaFieldView, {
45
+ // Block ALL events from reaching TipTap — popovers, sliders etc.
46
+ // handle their own interactions; TipTap must not intercept them.
47
+ stopEvent: () => true
48
+ });
49
+ },
50
+ addCommands() {
51
+ return {
52
+ insertMetaField: (attrs) => ({ state, dispatch }) => {
53
+ const { doc, tr, schema } = state;
54
+ const metaFieldType = schema.nodes.metaField;
55
+ if (!metaFieldType) return false;
56
+ let metaPos = -1;
57
+ let metaNode = null;
58
+ doc.forEach((node, offset) => {
59
+ if (node.type.name === "documentMeta") {
60
+ metaPos = offset;
61
+ metaNode = node;
62
+ }
63
+ });
64
+ if (metaPos === -1) return false;
65
+ const insertPos = metaPos + 1 + (metaNode?.content.size ?? 0);
66
+ const newNode = metaFieldType.create(attrs);
67
+ if (dispatch) dispatch(tr.insert(insertPos, newNode));
68
+ return true;
69
+ }
70
+ };
71
+ }
72
+ });
73
+ export function schemaFieldToAttrs(field) {
74
+ const t = field.type;
75
+ if (t === "datetimerange") return { fieldType: "datetimerange", fieldLabel: field.label ?? "", userDefined: false, startKey: String(field.startKey), endKey: String(field.endKey), allDayKey: String(field.allDayKey ?? "") };
76
+ if (t === "daterange") return { fieldType: "daterange", fieldLabel: field.label ?? "", userDefined: false, startKey: String(field.startKey), endKey: String(field.endKey) };
77
+ if (t === "timerange") return { fieldType: "timerange", fieldLabel: field.label ?? "", userDefined: false, startKey: String(field.startKey), endKey: String(field.endKey) };
78
+ if (t === "datetime") return { fieldType: "datetime", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key) };
79
+ if (t === "date") return { fieldType: "date", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key) };
80
+ if (t === "time") return { fieldType: "time", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key) };
81
+ if (t === "slider") return { fieldType: "slider", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key), sliderMin: field.min ?? 0, sliderMax: field.max ?? 100 };
82
+ if (t === "number") return { fieldType: "number", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key), sliderMin: field.min ?? 0, sliderMax: field.max ?? 999999, sliderStep: field.step ?? 1, unit: field.unit ?? "" };
83
+ if (t === "toggle") return { fieldType: "toggle", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key) };
84
+ if (t === "select") return { fieldType: "select", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key), options: JSON.stringify(field.options ?? []) };
85
+ if (t === "multiselect") return { fieldType: "multiselect", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key), options: JSON.stringify(field.options ?? []) };
86
+ if (t === "url") return { fieldType: "url", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key) };
87
+ if (t === "rating") return { fieldType: "rating", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key), sliderMax: field.max ?? 5 };
88
+ if (t === "tags") return { fieldType: "tags", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key), options: JSON.stringify(field.options ?? []) };
89
+ if (t === "textarea") return { fieldType: "textarea", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key) };
90
+ if (t === "colorPreset") return { fieldType: "colorPreset", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key), presets: JSON.stringify(field.presets ?? []) };
91
+ if (t === "colorPicker") return { fieldType: "colorPicker", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key) };
92
+ if (t === "location") return { fieldType: "location", fieldLabel: field.label ?? "", userDefined: false, latKey: String(field.latKey), lngKey: String(field.lngKey) };
93
+ if (t === "icon") return { fieldType: "icon", fieldLabel: field.label ?? "", userDefined: false, metaKey: String(field.key), iconOptions: JSON.stringify(field.options ?? []) };
94
+ return { fieldType: "colorPreset", fieldLabel: "" };
95
+ }
96
+ export function userFieldToAttrs(f) {
97
+ const base = { fieldType: f.type, fieldLabel: f.label ?? "", userDefined: true };
98
+ if (f.type === "datetimerange") return { ...base, startKey: f.startKey ?? "", endKey: f.endKey ?? "", allDayKey: f.allDayKey ?? "" };
99
+ if (f.type === "daterange") return { ...base, startKey: f.startKey ?? "", endKey: f.endKey ?? "" };
100
+ if (f.type === "timerange") return { ...base, startKey: f.startKey ?? "", endKey: f.endKey ?? "" };
101
+ if (["datetime", "date", "time", "toggle", "url", "textarea", "colorPicker"].includes(f.type)) return { ...base, metaKey: f.key ?? "" };
102
+ if (f.type === "slider") return { ...base, metaKey: f.key ?? "", sliderMin: f.min ?? 0, sliderMax: f.max ?? 100 };
103
+ if (f.type === "number") return { ...base, metaKey: f.key ?? "", sliderMin: f.min ?? 0, sliderMax: f.max ?? 999999, sliderStep: f.step ?? 1, unit: f.unit ?? "" };
104
+ if (f.type === "rating") return { ...base, metaKey: f.key ?? "", sliderMax: f.max ?? 5 };
105
+ if (f.type === "colorPreset") return { ...base, metaKey: f.key ?? "", presets: JSON.stringify(f.presets ?? []) };
106
+ if (["select", "multiselect", "tags"].includes(f.type)) return { ...base, metaKey: f.key ?? "", options: JSON.stringify(f.options ?? []) };
107
+ if (f.type === "location") return { ...base, latKey: f.latKey ?? "", lngKey: f.lngKey ?? "" };
108
+ if (f.type === "icon") return { ...base, metaKey: f.key ?? "", iconOptions: JSON.stringify(f.options ?? []) };
109
+ return base;
110
+ }
@@ -0,0 +1,4 @@
1
+ import type { NodeViewProps } from '@tiptap/vue-3';
2
+ declare const __VLS_export: import("vue").DefineComponent<NodeViewProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<NodeViewProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
3
+ declare const _default: typeof __VLS_export;
4
+ export default _default;