kirbyuse
Version:
Collection of Vue Composition utilities for Kirby CMS
424 lines (408 loc) • 13.1 kB
JavaScript
//#region src/vue.ts
const globalVue = window.Vue;
//#endregion
//#region src/composables/panel.ts
/**
* Returns the reactive Kirby Panel object.
*
* @remarks
* This composable is a simple shortcut to `window.panel`.
*/
function usePanel() {
return window.panel;
}
//#endregion
//#region src/composables/api.ts
/**
* Returns Kirby's Panel API for making HTTP requests to the backend.
*
* @remarks
* This composable is a simple shortcut to `window.panel.api`.
*/
function useApi() {
return usePanel().api;
}
//#endregion
//#region src/composables/app.ts
/**
* Returns the main Panel Vue instance.
*
* @remarks
* This composable is a simple shortcut to `window.panel.app`.
*/
function useApp() {
return usePanel().app;
}
//#endregion
//#region src/composables/block.ts
/**
* Provides block methods exposed by the default block component (Options API), which all custom blocks are extending.
* Since Options API methods are not avaiable in Composition API, we need to extract them into a composable.
*
* @see https://github.com/getkirby/kirby/blob/f9f00b16a22fe9dbbbddc2bfd4719ca3437cbee9/panel/src/components/Forms/Blocks/Types/Default.vue#L37
*
* @example
* ```vue
* <script setup>
* import { computed, ref, useApi, usePanel, watch } from "kirbyuse";
*
* // Will inherit props from extended default block
* const props = defineProps({});
* const emit = defineEmits([]);
*
* const { field, open, update } = useBlock(props, emit);
* ```
*/
function useBlock(props, emit) {
const field = (name, fallback = null) => {
let field$1 = null;
for (const tab of Object.values(props.fieldset.tabs ?? {})) if (tab.fields[name]) field$1 = tab.fields[name];
return field$1 ?? fallback;
};
const open = () => {
emit?.("open");
};
const update = (content) => {
emit?.("update", {
...props.content,
...content
});
};
return {
field,
open,
update
};
}
//#endregion
//#region src/composables/compatibility.ts
const isKirby5 = () => window.panel.plugins.viewButtons !== void 0;
const isKirby4 = () => !isKirby5();
//#endregion
//#region src/composables/store.ts
/**
* Returns the Vuex store of the Panel app.
*
* @deprecated The Vuex store is removed in Kirby 5. Use the `useContent` composable instead.
*/
function useStore() {
if (isKirby5()) return new Proxy({}, { get() {
throw new Error("Vuex store is not available. Are you using Kirby 5? Use the `useContent` composable instead.");
} });
return usePanel().app.$store;
}
//#endregion
//#region src/composables/content.ts
/**
* Reactive getters and methods to work with content of the current view.
*
* @remarks
* This composable follows the Kirby 5 content API while staying compatible with Kirby 4 (falling back to the Vuex store of Kirby 4).
*/
function useContent() {
const panel = usePanel();
const store = useStore();
const _isKirby5 = isKirby5();
if (_isKirby5 && !("diff" in panel.content)) throw new Error("This plugin requires Kirby 5.0.0-rc.1 or higher. Please update your Kirby installation.");
const currentContent = _isKirby5 ? computed(() => panel.content.version("changes")) : computed(() => store.getters["content/values"]());
const contentChanges = _isKirby5 ? computed(() => panel.content.diff()) : computed(() => store.getters["content/changes"]());
const hasChanges = _isKirby5 ? computed(() => panel.content.hasDiff()) : computed(() => store.getters["content/hasChanges"]());
const content = _isKirby5 ? panel.content : new Proxy({}, { get() {
return () => {};
} });
/**
* Updates the form values of the current view.
*
* @remarks
* In Kirby 5, the native `window.panel.content.update()` method immediately saves the changes to the backend storage. This can be prevented by passing `false` as the second argument.
* In Kirby 4, content changes are only stored in the Vuex store and do not need to be saved explicitly.
*/
const update = async (values, save = true) => {
if (!_isKirby5 && values) for (const [key, value] of Object.entries(values)) store.dispatch("content/update", [key, value]);
const viewContent = content.merge(values);
if (save) await content.save(viewContent);
};
return {
content,
currentContent,
contentChanges,
hasChanges,
update
};
}
//#endregion
//#region src/composables/dialog.ts
/**
* Provides methods to open different types of dialogs.
*/
function useDialog() {
/**
* Returns a promise that resolves when the dialog is closed.
*
* @example
* ```ts
* const { openTextDialog } = useDialog()
*
* const result = await openTextDialog("Are you sure?")
* console.log(result) // -> true or false
* ```
*/
function openTextDialog(text) {
let result = false;
return new Promise((resolve) => {
const panel = usePanel();
panel.dialog.open({
component: "k-text-dialog",
props: { text },
on: {
close: () => {
setTimeout(() => {
resolve(result);
}, 25);
},
submit: () => {
result = true;
panel.dialog.close();
}
}
});
});
}
/**
* Returns a promise that resolves when the dialog is closed.
*
* @example
* ```ts
* const { openFieldsDialog } = useDialog()
*
* const fields = {
* email: {
* type: "email",
* label: "Email",
* }
* }
*
* const result = await openFieldsDialog({ fields })
* console.log(result) // -> { email: "..." }
* ```
*/
function openFieldsDialog(props) {
let result;
return new Promise((resolve) => {
const panel = usePanel();
panel.dialog.open({
component: "k-form-dialog",
props,
on: {
close: () => {
setTimeout(() => {
resolve(result);
}, 25);
},
submit: (event) => {
result = event;
panel.dialog.close();
}
}
});
});
}
return {
openTextDialog,
openFieldsDialog
};
}
//#endregion
//#region src/composables/helpers.ts
/**
* Returns the internal Fiber helpers.
*
* @see https://lab.getkirby.com/public/lab/internals/helpers/
*
* @remarks
* This composable is a simple shortcut to `window.panel.app.$helper`.
*/
function useHelpers() {
return useApp().$helper;
}
//#endregion
//#region src/composables/i18n.ts
/**
* Returns translation utility functions.
*
* @remarks
* In most cases, use `window.panel.t` for Kirby's built-in translation function. This composable is useful for custom translation objects, such as those returned by a section's `label` property.
*
* @example
* ```ts
* const { t } = useI18n()
*
* // Simple string
* t("Hello") // -> "Hello"
*
* // Translation object
* t({ en: "Hello", de: "Hallo" }) // -> Returns value based on current Panel language
* ```
*/
function useI18n() {
const panel = usePanel();
function t(value) {
if (!value || typeof value === "string") return value;
return value[panel.translation.code] ?? Object.values(value)[0];
}
return { t };
}
//#endregion
//#region src/composables/library.ts
/**
* Returns the internal Kirby Panel libraries (dayjs, colors and autosize).
*
* @see https://lab.getkirby.com/public/lab/internals/library.colors
* @see https://lab.getkirby.com/public/lab/internals/library.dayjs
*
* @remarks
* This composable is a simple shortcut to `window.panel.app.$library`.
*/
function useLibrary() {
return useApp().$library;
}
//#endregion
//#region src/composables/section.ts
/**
* Provides section methods for loading section data.
*/
function useSection() {
const api = useApi();
const load = ({ parent, name }) => api.get(`${parent}/sections/${name}`);
return { load };
}
//#endregion
//#region src/utils/logger.ts
const LOG_LEVELS = {
error: 0,
warn: 1,
log: 2,
info: 3,
success: 3
};
function createLogger(tag) {
const reporter = new BrowserReporter();
return new Proxy({}, { get(target, prop) {
return (...args) => {
reporter.log({
level: LOG_LEVELS[prop],
type: prop,
tag,
args
});
};
} });
}
var BrowserReporter = class {
defaultColor = "#7f8c8d";
levelColorMap = {
0: "#c0392b",
1: "#f39c12",
3: "#00BCD4"
};
typeColorMap = { success: "#2ecc71" };
constructor() {}
log(logEvent) {
const consoleLogFn = resolveLogFn(logEvent.level);
const type = logEvent.type === "log" ? "" : logEvent.type;
const tag = logEvent.tag || "";
const style = `
background: ${this.typeColorMap[logEvent.type] || this.levelColorMap[logEvent.level] || this.defaultColor};
border-radius: 0.5em;
color: white;
font-weight: bold;
padding: 2px 0.5em;
`.trimStart();
const badge = `%c${[tag, type].filter(Boolean).join(":")}`;
if (typeof logEvent.args[0] === "string") consoleLogFn(`${badge}%c ${logEvent.args[0]}`, style, "", ...logEvent.args.slice(1));
else consoleLogFn(badge, style, ...logEvent.args);
}
};
function resolveLogFn(level) {
if (level < 1) return console.error;
return console.log;
}
//#endregion
//#region src/utils/plugin.ts
const registeredAssets = [];
const moduleCache = /* @__PURE__ */ new Map();
async function registerPluginAssets(assets) {
if (!Array.isArray(assets)) throw new TypeError(`Expected an array, got ${typeof assets}`);
for (const asset of assets) if (!registeredAssets.some((existing) => existing.filename === asset.filename)) registeredAssets.push(asset);
}
function resolvePluginAsset(filename) {
if (registeredAssets.length === 0) throw new Error("Plugin assets not registered");
const asset = registeredAssets.find((asset$1) => asset$1.filename === filename);
if (!asset) throw new Error(`Plugin asset "${filename}" not found`);
return asset;
}
async function loadPluginModule(filename) {
if (!filename.endsWith(".js")) filename += ".js";
if (moduleCache.has(filename)) return moduleCache.get(filename);
const mod = await import(
/* @vite-ignore */
resolvePluginAsset(filename).url
);
moduleCache.set(filename, mod);
return mod;
}
//#endregion
//#region src/index.ts
const computed = globalVue.computed;
const customRef = globalVue.customRef;
const defineAsyncComponent = globalVue.defineAsyncComponent;
const defineComponent = globalVue.defineComponent;
const effectScope = globalVue.effectScope;
const getCurrentInstance = globalVue.getCurrentInstance;
const getCurrentScope = globalVue.getCurrentScope;
const h = globalVue.h;
const inject = globalVue.inject;
const isProxy = globalVue.isProxy;
const isReactive = globalVue.isReactive;
const isReadonly = globalVue.isReadonly;
const isRef = globalVue.isRef;
const isShallow = globalVue.isShallow;
const markRaw = globalVue.markRaw;
const nextTick = globalVue.nextTick;
const onActivated = globalVue.onActivated;
const onBeforeMount = globalVue.onBeforeMount;
const onBeforeUnmount = globalVue.onBeforeUnmount;
const onBeforeUpdate = globalVue.onBeforeUpdate;
const onDeactivated = globalVue.onDeactivated;
const onErrorCaptured = globalVue.onErrorCaptured;
const onMounted = globalVue.onMounted;
const onRenderTracked = globalVue.onRenderTracked;
const onRenderTriggered = globalVue.onRenderTriggered;
const onScopeDispose = globalVue.onScopeDispose;
const onServerPrefetch = globalVue.onServerPrefetch;
const onUnmounted = globalVue.onUnmounted;
const onUpdated = globalVue.onUpdated;
const provide = globalVue.provide;
const proxyRefs = globalVue.proxyRefs;
const reactive = globalVue.reactive;
const readonly = globalVue.readonly;
const ref = globalVue.ref;
const shallowReactive = globalVue.shallowReactive;
const shallowReadonly = globalVue.shallowReadonly;
const shallowRef = globalVue.shallowRef;
const toRaw = globalVue.toRaw;
const toRef = globalVue.toRef;
const toRefs = globalVue.toRefs;
const triggerRef = globalVue.triggerRef;
const unref = globalVue.unref;
const useAttrs = globalVue.useAttrs;
const useCssModule = globalVue.useCssModule;
const useCssVars = globalVue.useCssVars;
const useListeners = globalVue.useListeners;
const useSlots = globalVue.useSlots;
const watch = globalVue.watch;
const watchEffect = globalVue.watchEffect;
const watchPostEffect = globalVue.watchPostEffect;
const watchSyncEffect = globalVue.watchSyncEffect;
//#endregion
export { registerPluginAssets as $, provide as A, toRefs as B, onMounted as C, onServerPrefetch as D, onScopeDispose as E, shallowReactive as F, useCssVars as G, unref as H, shallowReadonly as I, watch as J, useListeners as K, shallowRef as L, reactive as M, readonly as N, onUnmounted as O, ref as P, loadPluginModule as Q, toRaw as R, onErrorCaptured as S, onRenderTriggered as T, useAttrs as U, triggerRef as V, useCssModule as W, watchPostEffect as X, watchEffect as Y, watchSyncEffect as Z, onActivated as _, effectScope as a, useHelpers as at, onBeforeUpdate as b, h as c, useStore as ct, isReactive as d, useBlock as dt, resolvePluginAsset as et, isReadonly as f, useApp as ft, nextTick as g, markRaw as h, globalVue as ht, defineComponent as i, useI18n as it, proxyRefs as j, onUpdated as k, inject as l, isKirby4 as lt, isShallow as m, usePanel as mt, customRef as n, useSection as nt, getCurrentInstance as o, useDialog as ot, isRef as p, useApi as pt, useSlots as q, defineAsyncComponent as r, useLibrary as rt, getCurrentScope as s, useContent as st, computed as t, createLogger as tt, isProxy as u, isKirby5 as ut, onBeforeMount as v, onRenderTracked as w, onDeactivated as x, onBeforeUnmount as y, toRef as z };