@abinnovision/payloadcms-viewfinder 1.0.0-beta.1
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/LICENSE +201 -0
- package/README.md +148 -0
- package/dist/admin/bridge.d.mts +19 -0
- package/dist/admin/bridge.mjs +111 -0
- package/dist/admin/element-id.mjs +48 -0
- package/dist/admin/index.d.mts +2 -0
- package/dist/admin/index.mjs +3 -0
- package/dist/admin/reveal.mjs +108 -0
- package/dist/admin/row-button.mjs +90 -0
- package/dist/admin/rows.mjs +59 -0
- package/dist/attributes.d.mts +35 -0
- package/dist/attributes.mjs +26 -0
- package/dist/client/bridge.d.mts +23 -0
- package/dist/client/bridge.mjs +119 -0
- package/dist/client/geometry.mjs +41 -0
- package/dist/client/index.d.mts +5 -0
- package/dist/client/index.mjs +5 -0
- package/dist/client/marked.d.mts +38 -0
- package/dist/client/marked.mjs +44 -0
- package/dist/client/overlay.mjs +58 -0
- package/dist/client/target.mjs +33 -0
- package/dist/config/index.d.mts +2 -0
- package/dist/config/index.mjs +2 -0
- package/dist/config/plugin.d.mts +18 -0
- package/dist/config/plugin.mjs +73 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.mjs +4 -0
- package/dist/protocol.d.mts +51 -0
- package/dist/protocol.mjs +63 -0
- package/dist/resolve-path.d.mts +46 -0
- package/dist/resolve-path.mjs +63 -0
- package/package.json +102 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//#region src/config/plugin.ts
|
|
2
|
+
/**
|
|
3
|
+
* Payload resolves admin components by import path, so this string has to
|
|
4
|
+
* match the `./admin` export. Consumers must run
|
|
5
|
+
* `payload generate:importmap` after adding the plugin, as for any plugin
|
|
6
|
+
* that contributes admin components.
|
|
7
|
+
*/ const BRIDGE_COMPONENT = "@abinnovision/payloadcms-viewfinder/admin#ViewfinderFormBridge";
|
|
8
|
+
const append = (existing) => {
|
|
9
|
+
const components = existing ?? [];
|
|
10
|
+
return components.includes(BRIDGE_COMPONENT) ? void 0 : [...components, BRIDGE_COMPONENT];
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* `beforeDocumentControls` is the mount point because it renders inside the
|
|
14
|
+
* document `<Form>`, which is what gives the bridge access to form state. The
|
|
15
|
+
* global `admin.components.providers` slot wraps the dashboard from outside
|
|
16
|
+
* every form, so a provider mounted there could never resolve a field path.
|
|
17
|
+
*
|
|
18
|
+
* Collections nest that slot under `components.edit` and globals under
|
|
19
|
+
* `components.elements`, hence the two shapes.
|
|
20
|
+
*/ const withCollectionBridge = (entity) => {
|
|
21
|
+
const edit = entity.admin?.components?.edit;
|
|
22
|
+
const beforeDocumentControls = append(edit?.beforeDocumentControls);
|
|
23
|
+
if (!beforeDocumentControls) return entity;
|
|
24
|
+
return {
|
|
25
|
+
...entity,
|
|
26
|
+
admin: {
|
|
27
|
+
...entity.admin,
|
|
28
|
+
components: {
|
|
29
|
+
...entity.admin?.components,
|
|
30
|
+
edit: {
|
|
31
|
+
...edit,
|
|
32
|
+
beforeDocumentControls
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const withGlobalBridge = (entity) => {
|
|
39
|
+
const elements = entity.admin?.components?.elements;
|
|
40
|
+
const beforeDocumentControls = append(elements?.beforeDocumentControls);
|
|
41
|
+
if (!beforeDocumentControls) return entity;
|
|
42
|
+
return {
|
|
43
|
+
...entity,
|
|
44
|
+
admin: {
|
|
45
|
+
...entity.admin,
|
|
46
|
+
components: {
|
|
47
|
+
...entity.admin?.components,
|
|
48
|
+
elements: {
|
|
49
|
+
...elements,
|
|
50
|
+
beforeDocumentControls
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
const apply = (entities, slugs, transform) => (entities ?? []).map((entity) => slugs === void 0 || slugs.includes(entity.slug) ? transform(entity) : entity);
|
|
57
|
+
/**
|
|
58
|
+
* Makes documents addressable from their live preview.
|
|
59
|
+
*
|
|
60
|
+
* The bridge it mounts is inert until a framed page announces itself, so
|
|
61
|
+
* enabling it for a collection that has no live preview configured costs
|
|
62
|
+
* nothing beyond the component itself.
|
|
63
|
+
*/ const viewfinderPlugin = (args = {}) => {
|
|
64
|
+
const plugin = (config) => ({
|
|
65
|
+
...config,
|
|
66
|
+
collections: apply(config.collections, args.collections, withCollectionBridge),
|
|
67
|
+
globals: apply(config.globals, args.globals, withGlobalBridge)
|
|
68
|
+
});
|
|
69
|
+
plugin.slug = "viewfinder";
|
|
70
|
+
return plugin;
|
|
71
|
+
};
|
|
72
|
+
//#endregion
|
|
73
|
+
export { viewfinderPlugin };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { BLOCK_ID_ATTRIBUTE, BLOCK_TYPE_ATTRIBUTE, BlockMarkerAttributes, FIELD_ATTRIBUTE, FieldMarkerAttributes, markBlock, markField } from "./attributes.mjs";
|
|
2
|
+
import { AdminMessage, BlockAddress, PreviewMessage, VIEWFINDER_PROTOCOL_VERSION, VIEWFINDER_SOURCE, adminMessage, isAdminMessage, isPreviewMessage, previewMessage } from "./protocol.mjs";
|
|
3
|
+
import { FormStateLike, resolveAddressForPath, resolveAddressPath, resolveBlockIdForPath, resolveBlockPath, resolveFieldPath } from "./resolve-path.mjs";
|
|
4
|
+
export { type AdminMessage, BLOCK_ID_ATTRIBUTE, BLOCK_TYPE_ATTRIBUTE, type BlockAddress, type BlockMarkerAttributes, FIELD_ATTRIBUTE, type FieldMarkerAttributes, type FormStateLike, type PreviewMessage, VIEWFINDER_PROTOCOL_VERSION, VIEWFINDER_SOURCE, adminMessage, isAdminMessage, isPreviewMessage, markBlock, markField, previewMessage, resolveAddressForPath, resolveAddressPath, resolveBlockIdForPath, resolveBlockPath, resolveFieldPath };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { BLOCK_ID_ATTRIBUTE, BLOCK_TYPE_ATTRIBUTE, FIELD_ATTRIBUTE, markBlock, markField } from "./attributes.mjs";
|
|
2
|
+
import { VIEWFINDER_PROTOCOL_VERSION, VIEWFINDER_SOURCE, adminMessage, isAdminMessage, isPreviewMessage, previewMessage } from "./protocol.mjs";
|
|
3
|
+
import { resolveAddressForPath, resolveAddressPath, resolveBlockIdForPath, resolveBlockPath, resolveFieldPath } from "./resolve-path.mjs";
|
|
4
|
+
export { BLOCK_ID_ATTRIBUTE, BLOCK_TYPE_ATTRIBUTE, FIELD_ATTRIBUTE, VIEWFINDER_PROTOCOL_VERSION, VIEWFINDER_SOURCE, adminMessage, isAdminMessage, isPreviewMessage, markBlock, markField, previewMessage, resolveAddressForPath, resolveAddressPath, resolveBlockIdForPath, resolveBlockPath, resolveFieldPath };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//#region src/protocol.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Both windows are untrusted from the other's point of view: the preview is a
|
|
4
|
+
* consumer page and the admin is a separate origin. Every message therefore
|
|
5
|
+
* carries a source tag and a version, and is validated structurally on
|
|
6
|
+
* arrival rather than cast.
|
|
7
|
+
*/
|
|
8
|
+
declare const VIEWFINDER_SOURCE = "viewfinder";
|
|
9
|
+
/**
|
|
10
|
+
* Bumped only on a breaking envelope change. A mismatched version is dropped
|
|
11
|
+
* silently, so a stale frontend deployment cannot drive a newer admin.
|
|
12
|
+
*/
|
|
13
|
+
declare const VIEWFINDER_PROTOCOL_VERSION = 1;
|
|
14
|
+
/**
|
|
15
|
+
* What one message points at. `field` is relative to the block, which is what
|
|
16
|
+
* lets the same address survive the block moving to a different index.
|
|
17
|
+
*/
|
|
18
|
+
interface BlockAddress {
|
|
19
|
+
id: string;
|
|
20
|
+
blockType?: string;
|
|
21
|
+
field?: string;
|
|
22
|
+
}
|
|
23
|
+
interface Envelope<TType extends string> {
|
|
24
|
+
source: typeof VIEWFINDER_SOURCE;
|
|
25
|
+
version: typeof VIEWFINDER_PROTOCOL_VERSION;
|
|
26
|
+
type: TType;
|
|
27
|
+
}
|
|
28
|
+
interface AddressedEnvelope<TType extends string> extends Envelope<TType> {
|
|
29
|
+
address: BlockAddress;
|
|
30
|
+
}
|
|
31
|
+
/** Sent by the rendered page, in the iframe, up to the admin. */
|
|
32
|
+
type PreviewMessage = AddressedEnvelope<"hover"> | AddressedEnvelope<"select"> | Envelope<"leave"> | Envelope<"ready">;
|
|
33
|
+
/** Sent by the admin down into the preview iframe. */
|
|
34
|
+
type AdminMessage = AddressedEnvelope<"highlight"> | AddressedEnvelope<"scrollTo"> | Envelope<"clear">;
|
|
35
|
+
/** Narrows the untrusted `event.data` of a `message` event from the iframe. */
|
|
36
|
+
declare const isPreviewMessage: (value: unknown) => value is PreviewMessage;
|
|
37
|
+
/** Narrows the untrusted `event.data` of a `message` event from the admin. */
|
|
38
|
+
declare const isAdminMessage: (value: unknown) => value is AdminMessage;
|
|
39
|
+
declare const previewMessage: {
|
|
40
|
+
readonly ready: () => PreviewMessage;
|
|
41
|
+
readonly leave: () => PreviewMessage;
|
|
42
|
+
readonly hover: (address: BlockAddress) => PreviewMessage;
|
|
43
|
+
readonly select: (address: BlockAddress) => PreviewMessage;
|
|
44
|
+
};
|
|
45
|
+
declare const adminMessage: {
|
|
46
|
+
readonly clear: () => AdminMessage;
|
|
47
|
+
readonly highlight: (address: BlockAddress) => AdminMessage;
|
|
48
|
+
readonly scrollTo: (address: BlockAddress) => AdminMessage;
|
|
49
|
+
};
|
|
50
|
+
//#endregion
|
|
51
|
+
export { AdminMessage, BlockAddress, PreviewMessage, VIEWFINDER_PROTOCOL_VERSION, VIEWFINDER_SOURCE, adminMessage, isAdminMessage, isPreviewMessage, previewMessage };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
//#region src/protocol.ts
|
|
2
|
+
/**
|
|
3
|
+
* Both windows are untrusted from the other's point of view: the preview is a
|
|
4
|
+
* consumer page and the admin is a separate origin. Every message therefore
|
|
5
|
+
* carries a source tag and a version, and is validated structurally on
|
|
6
|
+
* arrival rather than cast.
|
|
7
|
+
*/ const VIEWFINDER_SOURCE = "viewfinder";
|
|
8
|
+
/**
|
|
9
|
+
* Bumped only on a breaking envelope change. A mismatched version is dropped
|
|
10
|
+
* silently, so a stale frontend deployment cannot drive a newer admin.
|
|
11
|
+
*/ const VIEWFINDER_PROTOCOL_VERSION = 1;
|
|
12
|
+
const PREVIEW_TYPES = /* @__PURE__ */ new Set([
|
|
13
|
+
"hover",
|
|
14
|
+
"select",
|
|
15
|
+
"leave",
|
|
16
|
+
"ready"
|
|
17
|
+
]);
|
|
18
|
+
const ADMIN_TYPES = /* @__PURE__ */ new Set([
|
|
19
|
+
"highlight",
|
|
20
|
+
"scrollTo",
|
|
21
|
+
"clear"
|
|
22
|
+
]);
|
|
23
|
+
const ADDRESSED_TYPES = /* @__PURE__ */ new Set([
|
|
24
|
+
"hover",
|
|
25
|
+
"select",
|
|
26
|
+
"highlight",
|
|
27
|
+
"scrollTo"
|
|
28
|
+
]);
|
|
29
|
+
const isAddress = (value) => {
|
|
30
|
+
if (typeof value !== "object" || value === null) return false;
|
|
31
|
+
const candidate = value;
|
|
32
|
+
return typeof candidate["id"] === "string" && candidate["id"].length > 0 && (candidate["blockType"] === void 0 || typeof candidate["blockType"] === "string") && (candidate["field"] === void 0 || typeof candidate["field"] === "string");
|
|
33
|
+
};
|
|
34
|
+
const isEnvelope = (value, types) => {
|
|
35
|
+
if (typeof value !== "object" || value === null) return false;
|
|
36
|
+
const candidate = value;
|
|
37
|
+
if (candidate["source"] !== "viewfinder" || candidate["version"] !== 1 || typeof candidate["type"] !== "string" || !types.has(candidate["type"])) return false;
|
|
38
|
+
return !ADDRESSED_TYPES.has(candidate["type"]) || isAddress(candidate["address"]);
|
|
39
|
+
};
|
|
40
|
+
/** Narrows the untrusted `event.data` of a `message` event from the iframe. */ const isPreviewMessage = (value) => isEnvelope(value, PREVIEW_TYPES);
|
|
41
|
+
/** Narrows the untrusted `event.data` of a `message` event from the admin. */ const isAdminMessage = (value) => isEnvelope(value, ADMIN_TYPES);
|
|
42
|
+
const bare = (type) => ({
|
|
43
|
+
source: VIEWFINDER_SOURCE,
|
|
44
|
+
version: 1,
|
|
45
|
+
type
|
|
46
|
+
});
|
|
47
|
+
const addressed = (type, address) => ({
|
|
48
|
+
...bare(type),
|
|
49
|
+
address
|
|
50
|
+
});
|
|
51
|
+
const previewMessage = {
|
|
52
|
+
ready: () => bare("ready"),
|
|
53
|
+
leave: () => bare("leave"),
|
|
54
|
+
hover: (address) => addressed("hover", address),
|
|
55
|
+
select: (address) => addressed("select", address)
|
|
56
|
+
};
|
|
57
|
+
const adminMessage = {
|
|
58
|
+
clear: () => bare("clear"),
|
|
59
|
+
highlight: (address) => addressed("highlight", address),
|
|
60
|
+
scrollTo: (address) => addressed("scrollTo", address)
|
|
61
|
+
};
|
|
62
|
+
//#endregion
|
|
63
|
+
export { VIEWFINDER_PROTOCOL_VERSION, VIEWFINDER_SOURCE, adminMessage, isAdminMessage, isPreviewMessage, previewMessage };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { BlockAddress } from "./protocol.mjs";
|
|
2
|
+
//#region src/resolve-path.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* The single place this package assumes anything about Payload internals.
|
|
5
|
+
*
|
|
6
|
+
* Payload's admin form state is already flat-keyed by field path — a block
|
|
7
|
+
* three levels deep appears as discrete `layout.0.modules.2.heading` entries,
|
|
8
|
+
* not as a nested document. That is what makes id lookup a scan rather than a
|
|
9
|
+
* tree walk, and it is why nothing here needs to reconstruct the document or
|
|
10
|
+
* know the collection's schema. If a Payload upgrade changes the key shape,
|
|
11
|
+
* this file is the only one that has to move.
|
|
12
|
+
*/
|
|
13
|
+
type FormStateLike = Readonly<Record<string, {
|
|
14
|
+
value?: unknown;
|
|
15
|
+
} | undefined>>;
|
|
16
|
+
/**
|
|
17
|
+
* Resolves a Payload row `id` to its form path (`layout.0.modules.2`).
|
|
18
|
+
*
|
|
19
|
+
* Ids are unique in practice; if two rows somehow carry the same one, the
|
|
20
|
+
* shallowest path wins so the result stays deterministic rather than
|
|
21
|
+
* depending on key order.
|
|
22
|
+
*/
|
|
23
|
+
declare const resolveBlockPath: (formState: FormStateLike, id: string) => string | undefined;
|
|
24
|
+
/** Joins a block path and a block-relative field name into a form path. */
|
|
25
|
+
declare const resolveFieldPath: (blockPath: string, field: string) => string;
|
|
26
|
+
/**
|
|
27
|
+
* Resolves a whole address to the form path the admin should reveal: the
|
|
28
|
+
* block itself, or a field inside it when the preview named one.
|
|
29
|
+
*/
|
|
30
|
+
declare const resolveAddressPath: (formState: FormStateLike, address: BlockAddress) => string | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* The inverse, for the admin-to-preview direction: given any form path, finds
|
|
33
|
+
* the id of the nearest enclosing block.
|
|
34
|
+
*
|
|
35
|
+
* Walks ancestors deepest-first and requires a sibling `blockType`, which is
|
|
36
|
+
* what distinguishes a block row from a plain array row — array rows also
|
|
37
|
+
* carry an `id`, but the preview knows nothing about them.
|
|
38
|
+
*/
|
|
39
|
+
declare const resolveBlockIdForPath: (formState: FormStateLike, path: string) => string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* The address to send into the preview for a form path, carrying the field
|
|
42
|
+
* suffix when the path pointed inside a block rather than at it.
|
|
43
|
+
*/
|
|
44
|
+
declare const resolveAddressForPath: (formState: FormStateLike, path: string) => BlockAddress | undefined;
|
|
45
|
+
//#endregion
|
|
46
|
+
export { FormStateLike, resolveAddressForPath, resolveAddressPath, resolveBlockIdForPath, resolveBlockPath, resolveFieldPath };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
//#region src/resolve-path.ts
|
|
2
|
+
const ID_SUFFIX = ".id";
|
|
3
|
+
const BLOCK_TYPE_SUFFIX = ".blockType";
|
|
4
|
+
/**
|
|
5
|
+
* The document's own `id` lives at the bare key `"id"`, which has no dot and
|
|
6
|
+
* so is never a candidate. Every other `*.id` is a block row or an array row.
|
|
7
|
+
*/ const isRowIdKey = (key) => key.endsWith(ID_SUFFIX);
|
|
8
|
+
/**
|
|
9
|
+
* Resolves a Payload row `id` to its form path (`layout.0.modules.2`).
|
|
10
|
+
*
|
|
11
|
+
* Ids are unique in practice; if two rows somehow carry the same one, the
|
|
12
|
+
* shallowest path wins so the result stays deterministic rather than
|
|
13
|
+
* depending on key order.
|
|
14
|
+
*/ const resolveBlockPath = (formState, id) => {
|
|
15
|
+
let best;
|
|
16
|
+
for (const key of Object.keys(formState)) {
|
|
17
|
+
if (!isRowIdKey(key) || formState[key]?.value !== id) continue;
|
|
18
|
+
const path = key.slice(0, -3);
|
|
19
|
+
if (best === void 0 || path.length < best.length) best = path;
|
|
20
|
+
}
|
|
21
|
+
return best;
|
|
22
|
+
};
|
|
23
|
+
/** Joins a block path and a block-relative field name into a form path. */ const resolveFieldPath = (blockPath, field) => `${blockPath}.${field}`;
|
|
24
|
+
/**
|
|
25
|
+
* Resolves a whole address to the form path the admin should reveal: the
|
|
26
|
+
* block itself, or a field inside it when the preview named one.
|
|
27
|
+
*/ const resolveAddressPath = (formState, address) => {
|
|
28
|
+
const blockPath = resolveBlockPath(formState, address.id);
|
|
29
|
+
if (blockPath === void 0 || address.field === void 0) return blockPath;
|
|
30
|
+
return resolveFieldPath(blockPath, address.field);
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* The inverse, for the admin-to-preview direction: given any form path, finds
|
|
34
|
+
* the id of the nearest enclosing block.
|
|
35
|
+
*
|
|
36
|
+
* Walks ancestors deepest-first and requires a sibling `blockType`, which is
|
|
37
|
+
* what distinguishes a block row from a plain array row — array rows also
|
|
38
|
+
* carry an `id`, but the preview knows nothing about them.
|
|
39
|
+
*/ const resolveBlockIdForPath = (formState, path) => {
|
|
40
|
+
const segments = path.split(".");
|
|
41
|
+
for (let end = segments.length; end > 0; end--) {
|
|
42
|
+
const prefix = segments.slice(0, end).join(".");
|
|
43
|
+
if (formState[`${prefix}${BLOCK_TYPE_SUFFIX}`] === void 0) continue;
|
|
44
|
+
const id = formState[`${prefix}${ID_SUFFIX}`]?.value;
|
|
45
|
+
if (typeof id === "string" && id.length > 0) return id;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* The address to send into the preview for a form path, carrying the field
|
|
50
|
+
* suffix when the path pointed inside a block rather than at it.
|
|
51
|
+
*/ const resolveAddressForPath = (formState, path) => {
|
|
52
|
+
const id = resolveBlockIdForPath(formState, path);
|
|
53
|
+
if (id === void 0) return;
|
|
54
|
+
const blockPath = resolveBlockPath(formState, id);
|
|
55
|
+
const blockType = formState[`${blockPath ?? path}${BLOCK_TYPE_SUFFIX}`]?.value;
|
|
56
|
+
return {
|
|
57
|
+
id,
|
|
58
|
+
...typeof blockType === "string" ? { blockType } : {},
|
|
59
|
+
...blockPath === void 0 || blockPath === path ? {} : { field: path.slice(blockPath.length + 1) }
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
//#endregion
|
|
63
|
+
export { resolveAddressForPath, resolveAddressPath, resolveBlockIdForPath, resolveBlockPath, resolveFieldPath };
|
package/package.json
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
+
"name": "@abinnovision/payloadcms-viewfinder",
|
|
4
|
+
"version": "1.0.0-beta.1",
|
|
5
|
+
"description": "Two-way block addressing between a rendered frontend and the Payload CMS admin form.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"payload",
|
|
8
|
+
"payloadcms",
|
|
9
|
+
"live-preview",
|
|
10
|
+
"visual-editing",
|
|
11
|
+
"blocks"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/abinnovision/payloadcms-commons.git",
|
|
16
|
+
"directory": "packages/viewfinder"
|
|
17
|
+
},
|
|
18
|
+
"license": "Apache-2.0",
|
|
19
|
+
"author": {
|
|
20
|
+
"name": "abi group GmbH",
|
|
21
|
+
"email": "info@abigroup.io",
|
|
22
|
+
"url": "https://abigroup.io"
|
|
23
|
+
},
|
|
24
|
+
"type": "module",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.mts",
|
|
28
|
+
"default": "./dist/index.mjs"
|
|
29
|
+
},
|
|
30
|
+
"./client": {
|
|
31
|
+
"types": "./dist/client/index.d.mts",
|
|
32
|
+
"default": "./dist/client/index.mjs"
|
|
33
|
+
},
|
|
34
|
+
"./config": {
|
|
35
|
+
"types": "./dist/config/index.d.mts",
|
|
36
|
+
"default": "./dist/config/index.mjs"
|
|
37
|
+
},
|
|
38
|
+
"./admin": {
|
|
39
|
+
"types": "./dist/admin/index.d.mts",
|
|
40
|
+
"default": "./dist/admin/index.mjs"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist",
|
|
45
|
+
"LICENSE",
|
|
46
|
+
"README.md"
|
|
47
|
+
],
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsdown",
|
|
50
|
+
"format:check": "prettier --check 'src/**/*.{ts,tsx}' 'test/**/*.ts' '*.{json{,5},md,y{,a}ml}'",
|
|
51
|
+
"format:fix": "prettier --write 'src/**/*.{ts,tsx}' 'test/**/*.ts' '*.{json{,5},md,y{,a}ml}'",
|
|
52
|
+
"lint:check": "eslint 'src/**/*.{ts,tsx}' 'test/**/*.ts'",
|
|
53
|
+
"lint:fix": "eslint 'src/**/*.{ts,tsx}' 'test/**/*.ts' --fix",
|
|
54
|
+
"test-unit": "vitest --run --coverage --config vitest.config.mts",
|
|
55
|
+
"test-unit:watch": "vitest --config vitest.config.mts",
|
|
56
|
+
"typecheck": "tsc --noEmit"
|
|
57
|
+
},
|
|
58
|
+
"lint-staged": {
|
|
59
|
+
"src/**/*.{ts,tsx}": [
|
|
60
|
+
"eslint --fix",
|
|
61
|
+
"prettier --write"
|
|
62
|
+
],
|
|
63
|
+
"*.{json{,5},md,y{,a}ml}": "prettier --write"
|
|
64
|
+
},
|
|
65
|
+
"prettier": "@abinnovision/prettier-config",
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@abinnovision/eslint-config-base": "^3.4.2",
|
|
68
|
+
"@abinnovision/prettier-config": "^2.2.0",
|
|
69
|
+
"@arethetypeswrong/core": "^0.18.5",
|
|
70
|
+
"@payloadcms/ui": "3.88.0",
|
|
71
|
+
"@swc/core": "^1.16.1",
|
|
72
|
+
"@types/node": "^26.3.0",
|
|
73
|
+
"@types/react": "^19.2.18",
|
|
74
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
75
|
+
"eslint": "^10.9.1",
|
|
76
|
+
"payload": "3.88.0",
|
|
77
|
+
"prettier": "^3.9.5",
|
|
78
|
+
"publint": "^0.3.24",
|
|
79
|
+
"react": "^19.2.8",
|
|
80
|
+
"react-dom": "^19.2.8",
|
|
81
|
+
"tsdown": "^0.22.14",
|
|
82
|
+
"typescript": "^6.0.3",
|
|
83
|
+
"unplugin-swc": "^1.5.11",
|
|
84
|
+
"vitest": "^4.1.10"
|
|
85
|
+
},
|
|
86
|
+
"peerDependencies": {
|
|
87
|
+
"@payloadcms/ui": ">=3.88.0 <4",
|
|
88
|
+
"payload": ">=3.88.0 <4",
|
|
89
|
+
"react": "^19",
|
|
90
|
+
"react-dom": "^19"
|
|
91
|
+
},
|
|
92
|
+
"peerDependenciesMeta": {
|
|
93
|
+
"@payloadcms/ui": {
|
|
94
|
+
"optional": true
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"publishConfig": {
|
|
98
|
+
"ghpr": true,
|
|
99
|
+
"npm": true,
|
|
100
|
+
"npmAccess": "public"
|
|
101
|
+
}
|
|
102
|
+
}
|