@meeovi/directus-client 1.0.0 → 1.0.2
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.
- package/README.md +238 -0
- package/dist/client/createClient.d.ts +14 -0
- package/dist/client/createClient.js +18 -0
- package/dist/generators/form-engine.d.ts +13 -0
- package/dist/generators/form-engine.js +22 -0
- package/dist/generators/table-engine.d.ts +6 -0
- package/dist/generators/table-engine.js +9 -0
- package/dist/generators/validation-engine.d.ts +2 -0
- package/dist/generators/validation-engine.js +25 -0
- package/dist/generators/widget-registry.d.ts +9 -0
- package/dist/generators/widget-registry.js +54 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +17 -0
- package/dist/react/DirectusProvider.d.ts +7 -0
- package/dist/react/DirectusProvider.js +6 -0
- package/dist/react/useDirectus.d.ts +2 -0
- package/dist/react/useDirectus.js +9 -0
- package/dist/schema/introspect.d.ts +5 -0
- package/dist/schema/introspect.js +30 -0
- package/dist/schema/types.d.ts +47 -0
- package/dist/schema/types.js +1 -0
- package/dist/utils/collections.d.ts +5 -0
- package/dist/utils/collections.js +13 -0
- package/dist/utils/fields.d.ts +4 -0
- package/dist/utils/fields.js +40 -0
- package/dist/utils/livePreview.d.ts +11 -0
- package/dist/utils/livePreview.js +11 -0
- package/dist/utils/useDirectusField.d.ts +10 -0
- package/dist/utils/useDirectusField.js +119 -0
- package/dist/utils/useDirectusRequest.d.ts +7 -0
- package/dist/utils/useDirectusRequest.js +33 -0
- package/dist/utils/useLivePreview.d.ts +1 -0
- package/dist/utils/useLivePreview.js +16 -0
- package/dist/utils/useVisualEditing.d.ts +18 -0
- package/dist/utils/useVisualEditing.js +27 -0
- package/dist/utils/visualEditing.d.ts +21 -0
- package/dist/utils/visualEditing.js +25 -0
- package/dist/vue/DirectusProvider.d.ts +15 -0
- package/dist/vue/DirectusProvider.js +12 -0
- package/dist/vue/useDirectus.d.ts +2 -0
- package/dist/vue/useDirectus.js +9 -0
- package/package.json +16 -5
- package/src/client/createClient.ts +5 -4
- package/src/generators/form-engine.ts +31 -81
- package/src/generators/widget-registry.ts +71 -4
- package/src/react/useDirectus.ts +1 -1
- package/src/utils/livePreview.ts +24 -0
- package/src/utils/visualEditing.ts +46 -0
- package/src/vue/useDirectus.ts +1 -1
- package/tsconfig.json +15 -0
- package/src/utils/useDirectusField.ts +0 -144
- package/src/utils/useDirectusRequest.ts +0 -32
- package/src/utils/useDirectusSchema.js +0 -9
- package/src/utils/useLivePreview.ts +0 -17
- package/src/utils/useVisualEditing.ts +0 -38
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { apply as applyVisualEditing, setAttr } from '@directus/visual-editing';
|
|
2
|
+
import type { PrimaryKey } from '@directus/types';
|
|
3
|
+
|
|
4
|
+
export interface VisualEditingOptions {
|
|
5
|
+
enableVisualEditing?: boolean;
|
|
6
|
+
directusUrl: string;
|
|
7
|
+
query?: Record<string, string | undefined>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ApplyOptions {
|
|
11
|
+
elements?: HTMLElement[] | HTMLElement;
|
|
12
|
+
onSaved?: (data: {
|
|
13
|
+
collection?: string;
|
|
14
|
+
item?: PrimaryKey | null;
|
|
15
|
+
payload?: Record<string, any>;
|
|
16
|
+
}) => void;
|
|
17
|
+
customClass?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function createVisualEditing(options: VisualEditingOptions) {
|
|
21
|
+
const { enableVisualEditing = false, directusUrl, query = {} } = options;
|
|
22
|
+
|
|
23
|
+
let isEnabled = false;
|
|
24
|
+
|
|
25
|
+
// Determine if visual editing should be active
|
|
26
|
+
if (query['visual-editing'] === 'true' && enableVisualEditing) {
|
|
27
|
+
isEnabled = true;
|
|
28
|
+
} else if (query['visual-editing'] === 'false') {
|
|
29
|
+
isEnabled = false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const apply = (opts: ApplyOptions) => {
|
|
33
|
+
if (!isEnabled) return;
|
|
34
|
+
|
|
35
|
+
applyVisualEditing({
|
|
36
|
+
...opts,
|
|
37
|
+
directusUrl,
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
isEnabled,
|
|
43
|
+
apply,
|
|
44
|
+
setAttr,
|
|
45
|
+
};
|
|
46
|
+
}
|
package/src/vue/useDirectus.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { inject } from 'vue';
|
|
|
2
2
|
import { DirectusKey } from './DirectusProvider';
|
|
3
3
|
import type { MeeoviDirectusClient } from '../client/createClient';
|
|
4
4
|
|
|
5
|
-
export function
|
|
5
|
+
export function useVueDirectus<Schema>() {
|
|
6
6
|
const client = inject<MeeoviDirectusClient<Schema>>(DirectusKey);
|
|
7
7
|
|
|
8
8
|
if (!client) {
|
package/tsconfig.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"declaration": true,
|
|
4
|
+
"emitDeclarationOnly": false,
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"target": "ESNext",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"jsx": "react-jsx",
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"noEmitOnError": false
|
|
13
|
+
},
|
|
14
|
+
"include": ["src"]
|
|
15
|
+
}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { ref, computed, watch } from "vue"
|
|
2
|
-
import Input from "~/components/ui/forms/TextInput.vue"
|
|
3
|
-
import TextArea from "~/components/ui/forms/TextArea.vue"
|
|
4
|
-
import Select from "~/components/ui/forms/SelectInput.vue"
|
|
5
|
-
import DateTime from "~/components/ui/forms/DateTime.vue"
|
|
6
|
-
import FileInput from "~/components/ui/forms/FileInput.vue"
|
|
7
|
-
import BooleanInput from "~/components/ui/forms/BooleanInput.vue"
|
|
8
|
-
import RelationSelect from "~/components/ui/forms/RelationSelect.vue"
|
|
9
|
-
import RepeaterInput from "~/components/ui/forms/RepeaterInput.vue"
|
|
10
|
-
import TiptapEditor from "~/components/ui/forms/TiptapEditor.vue"
|
|
11
|
-
|
|
12
|
-
export function useDirectusField(field: any, modelValue: any, emit: any, formContext?: any) {
|
|
13
|
-
const internalValue = computed({
|
|
14
|
-
get: () => modelValue,
|
|
15
|
-
set: (v) => emit("update:modelValue", v),
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
const previousAuto = ref<string | null>(null)
|
|
19
|
-
const internalAuto = computed(() => {
|
|
20
|
-
return previousAuto.value != null && internalValue.value === previousAuto.value
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
const slugify = (val: string) =>
|
|
24
|
-
String(val || "")
|
|
25
|
-
.toLowerCase()
|
|
26
|
-
.normalize("NFKD")
|
|
27
|
-
.replace(/\s+/g, "-")
|
|
28
|
-
.replace(/[^a-z0-9\-]/g, "")
|
|
29
|
-
.replace(/-+/g, "-")
|
|
30
|
-
.replace(/^-|-$/g, "")
|
|
31
|
-
|
|
32
|
-
const isAliasField = computed(() => {
|
|
33
|
-
const meta = field?.meta ?? {}
|
|
34
|
-
return (
|
|
35
|
-
meta.interface === "alias" ||
|
|
36
|
-
(meta.options && (meta.options.source || meta.options.from))
|
|
37
|
-
)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
if (isAliasField.value && formContext && formContext.form) {
|
|
41
|
-
const meta = field?.meta ?? {}
|
|
42
|
-
let sourceField: string | null = meta?.options?.source ?? meta?.options?.from ?? null
|
|
43
|
-
|
|
44
|
-
if (!sourceField && formContext.fields) {
|
|
45
|
-
const candidates = ["name", "title"]
|
|
46
|
-
sourceField =
|
|
47
|
-
candidates.find((c: string) =>
|
|
48
|
-
formContext.fields.value.some((f: any) => f.field === c)
|
|
49
|
-
) ?? null
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (sourceField) {
|
|
53
|
-
watch(
|
|
54
|
-
() => formContext.form.value?.[sourceField as string],
|
|
55
|
-
(newVal) => {
|
|
56
|
-
const target = field.field
|
|
57
|
-
const current = formContext.form.value?.[target] ?? ""
|
|
58
|
-
const generated = slugify(String(newVal ?? ""))
|
|
59
|
-
|
|
60
|
-
if (!generated) return
|
|
61
|
-
|
|
62
|
-
// Case 1: Empty or previously auto‑generated → regenerate
|
|
63
|
-
if (!current || current === previousAuto.value) {
|
|
64
|
-
formContext.form.value[target] = generated
|
|
65
|
-
internalValue.value = generated
|
|
66
|
-
previousAuto.value = generated
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
{ immediate: true }
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
// Watch the target itself: if cleared, regenerate
|
|
73
|
-
watch(
|
|
74
|
-
() => formContext.form.value?.[field.field],
|
|
75
|
-
(newVal) => {
|
|
76
|
-
if (!newVal) {
|
|
77
|
-
const sourceVal = formContext.form.value?.[sourceField as string] ?? ""
|
|
78
|
-
const regenerated = slugify(String(sourceVal))
|
|
79
|
-
if (regenerated) {
|
|
80
|
-
formContext.form.value[field.field] = regenerated
|
|
81
|
-
internalValue.value = regenerated
|
|
82
|
-
previousAuto.value = regenerated
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// --- Label prettifier ---
|
|
91
|
-
const prettify = (s: string) =>
|
|
92
|
-
s.replace(/_/g, " ")
|
|
93
|
-
.split(" ")
|
|
94
|
-
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
95
|
-
.join(" ")
|
|
96
|
-
|
|
97
|
-
const label = computed(() => {
|
|
98
|
-
const raw = field?.meta?.field ?? field?.field ?? ""
|
|
99
|
-
return prettify(raw)
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
// --- Field lookup ---
|
|
103
|
-
const fieldLookup = computed(() => {
|
|
104
|
-
const iface = field?.meta?.interface
|
|
105
|
-
const name = String(iface ?? "").toLowerCase()
|
|
106
|
-
|
|
107
|
-
if (["input", "string"].includes(name)) return Input
|
|
108
|
-
if (
|
|
109
|
-
["textarea", "wysiwyg", "rich-text", "input-multiline", "input-rich-text", "input-rich-text-md"].includes(name)
|
|
110
|
-
)
|
|
111
|
-
return TiptapEditor
|
|
112
|
-
if (["select", "select-dropdown", "select-multiple"].includes(name)) return Select
|
|
113
|
-
if (name === "datetime") return DateTime
|
|
114
|
-
if (["file", "files", "file-image"].includes(name)) return FileInput
|
|
115
|
-
if (name === "boolean") return BooleanInput
|
|
116
|
-
if (name.includes("many") || name.includes("one") || name.includes("to")) return RelationSelect
|
|
117
|
-
return Input
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
const required = computed(() => {
|
|
121
|
-
const meta = field?.meta ?? {}
|
|
122
|
-
return Boolean(meta?.validation?.required ?? meta?.required ?? false)
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
const safeOptions = computed(() => field?.meta?.options ?? null)
|
|
126
|
-
const defaultValue = computed(() => field?.schema?.default_value ?? null)
|
|
127
|
-
const isMultiple = computed(() => {
|
|
128
|
-
const name = String(field?.meta?.interface ?? "").toLowerCase()
|
|
129
|
-
if (name === "select-multiple") return true
|
|
130
|
-
if (name.includes("many")) return true
|
|
131
|
-
return Boolean(field?.meta?.options?.multiple || false)
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
internalValue,
|
|
136
|
-
internalAuto,
|
|
137
|
-
label,
|
|
138
|
-
fieldLookup,
|
|
139
|
-
required,
|
|
140
|
-
safeOptions,
|
|
141
|
-
defaultValue,
|
|
142
|
-
isMultiple,
|
|
143
|
-
}
|
|
144
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { useNuxtApp } from '#imports'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Centralized safe wrapper around `$directus.request`.
|
|
5
|
-
* Shows a toast error when the Directus client or `.request` is not available.
|
|
6
|
-
*/
|
|
7
|
-
export default function useDirectusRequest() {
|
|
8
|
-
const nuxt = useNuxtApp() as any
|
|
9
|
-
|
|
10
|
-
async function request(config: any) {
|
|
11
|
-
try {
|
|
12
|
-
const client = nuxt?.$directus
|
|
13
|
-
if (!client || typeof client.request !== 'function') {
|
|
14
|
-
try {
|
|
15
|
-
const toast = nuxt?.$toast
|
|
16
|
-
if (toast && typeof toast.error === 'function') toast.error('Directus client unavailable')
|
|
17
|
-
} catch (_) {}
|
|
18
|
-
throw new Error('Directus client.request is not available')
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return await client.request(config)
|
|
22
|
-
} catch (e) {
|
|
23
|
-
try {
|
|
24
|
-
const toast = nuxt?.$toast
|
|
25
|
-
if (toast && typeof toast.error === 'function') toast.error('Request failed')
|
|
26
|
-
} catch (_) {}
|
|
27
|
-
throw e
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return { request }
|
|
32
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export function useLivePreview() {
|
|
2
|
-
return usePreviewMode({
|
|
3
|
-
// Enable preview mode when both preview and token params exist in URL
|
|
4
|
-
shouldEnable: () => {
|
|
5
|
-
const route = useRoute();
|
|
6
|
-
return !!route.query.preview && !!route.query.token;
|
|
7
|
-
},
|
|
8
|
-
|
|
9
|
-
// Store the token from the URL for use in API calls
|
|
10
|
-
getState: (currentState) => {
|
|
11
|
-
const route = useRoute();
|
|
12
|
-
return {
|
|
13
|
-
token: route.query.token || currentState.token,
|
|
14
|
-
};
|
|
15
|
-
},
|
|
16
|
-
});
|
|
17
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { apply as applyVisualEditing, setAttr } from '@directus/visual-editing';
|
|
2
|
-
import type { PrimaryKey } from '@directus/types';
|
|
3
|
-
|
|
4
|
-
interface ApplyOptions {
|
|
5
|
-
directusUrl: string;
|
|
6
|
-
elements?: HTMLElement[] | HTMLElement;
|
|
7
|
-
onSaved?: (data: { collection?: string; item?: PrimaryKey | null; payload?: Record<string, any> }) => void;
|
|
8
|
-
customClass?: string;
|
|
9
|
-
}
|
|
10
|
-
export default function useVisualEditing() {
|
|
11
|
-
// Use useState for state that persists across navigation
|
|
12
|
-
const isVisualEditingEnabled = useState('visual-editing-enabled', () => false);
|
|
13
|
-
const route = useRoute();
|
|
14
|
-
const {
|
|
15
|
-
public: { enableVisualEditing, directusUrl },
|
|
16
|
-
} = useRuntimeConfig();
|
|
17
|
-
|
|
18
|
-
// Check query param on composable initialization.
|
|
19
|
-
if (route.query['visual-editing'] === 'true' && enableVisualEditing) {
|
|
20
|
-
isVisualEditingEnabled.value = true;
|
|
21
|
-
} else if (route.query['visual-editing'] === 'false') {
|
|
22
|
-
isVisualEditingEnabled.value = false;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const apply = (options: Pick<ApplyOptions, 'elements' | 'onSaved' | 'customClass'>) => {
|
|
26
|
-
if (!isVisualEditingEnabled.value) return;
|
|
27
|
-
applyVisualEditing({
|
|
28
|
-
...options,
|
|
29
|
-
directusUrl,
|
|
30
|
-
});
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
isVisualEditingEnabled,
|
|
35
|
-
apply,
|
|
36
|
-
setAttr,
|
|
37
|
-
};
|
|
38
|
-
}
|