payload-better-editor 1.2.2 → 1.3.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.
- package/dist/admin/ErrorBoundary.d.ts +1 -10
- package/dist/admin/ErrorBoundary.js +14 -5
- package/dist/admin/ErrorBoundary.js.map +1 -1
- package/dist/admin/LiveEditorOverlay.js +4 -2
- package/dist/admin/LiveEditorOverlay.js.map +1 -1
- package/dist/admin/LiveEditorToggle.d.ts +2 -0
- package/dist/admin/LiveEditorToggle.js +14 -9
- package/dist/admin/LiveEditorToggle.js.map +1 -1
- package/dist/admin/PreviewFrame.js +6 -4
- package/dist/admin/PreviewFrame.js.map +1 -1
- package/dist/admin/PreviewToolbar.js +20 -13
- package/dist/admin/PreviewToolbar.js.map +1 -1
- package/dist/admin/SettingsBanner.js +10 -5
- package/dist/admin/SettingsBanner.js.map +1 -1
- package/dist/admin/ViewportToggle.js +30 -25
- package/dist/admin/ViewportToggle.js.map +1 -1
- package/dist/admin/blocks/AddBlockDrawer.js +7 -3
- package/dist/admin/blocks/AddBlockDrawer.js.map +1 -1
- package/dist/admin/blocks/BlockActionsToolbar.js +13 -11
- package/dist/admin/blocks/BlockActionsToolbar.js.map +1 -1
- package/dist/admin/blocks/BlockEmptyState.js +7 -3
- package/dist/admin/blocks/BlockEmptyState.js.map +1 -1
- package/dist/admin/blocks/BlockHeader.d.ts +1 -0
- package/dist/admin/blocks/BlockHeader.js +9 -8
- package/dist/admin/blocks/BlockHeader.js.map +1 -1
- package/dist/admin/blocks/schema.js +38 -7
- package/dist/admin/blocks/schema.js.map +1 -1
- package/dist/admin/sidebar/BlockSettingsTab.js +19 -4
- package/dist/admin/sidebar/BlockSettingsTab.js.map +1 -1
- package/dist/admin/sidebar/DocumentMetaTab.js +6 -2
- package/dist/admin/sidebar/DocumentMetaTab.js.map +1 -1
- package/dist/admin/sidebar/DocumentSettingsTab.js +6 -2
- package/dist/admin/sidebar/DocumentSettingsTab.js.map +1 -1
- package/dist/admin/sidebar/Sidebar.js +21 -16
- package/dist/admin/sidebar/Sidebar.js.map +1 -1
- package/dist/admin/sidebar/ValidationSummary.js +5 -2
- package/dist/admin/sidebar/ValidationSummary.js.map +1 -1
- package/dist/global.js +55 -39
- package/dist/global.js.map +1 -1
- package/dist/hooks/usePreviewBinding.js +6 -2
- package/dist/hooks/usePreviewBinding.js.map +1 -1
- package/dist/hooks/usePreviewSettingsSync.js +8 -3
- package/dist/hooks/usePreviewSettingsSync.js.map +1 -1
- package/dist/i18n/de.d.ts +2 -0
- package/dist/i18n/de.js +135 -0
- package/dist/i18n/de.js.map +1 -0
- package/dist/i18n/en.d.ts +2 -0
- package/dist/i18n/en.js +135 -0
- package/dist/i18n/en.js.map +1 -0
- package/dist/i18n/merge.d.ts +8 -0
- package/dist/i18n/merge.js +22 -0
- package/dist/i18n/merge.js.map +1 -0
- package/dist/i18n/types.d.ts +133 -0
- package/dist/i18n/types.js +3 -0
- package/dist/i18n/types.js.map +1 -0
- package/dist/i18n/useBetterEditorT.d.ts +2 -0
- package/dist/i18n/useBetterEditorT.js +10 -0
- package/dist/i18n/useBetterEditorT.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +21 -2
- package/dist/index.js.map +1 -1
- package/dist/preview/HoverToolbar.d.ts +8 -0
- package/dist/preview/HoverToolbar.js +31 -29
- package/dist/preview/HoverToolbar.js.map +1 -1
- package/dist/preview/HoverToolbarController.d.ts +6 -0
- package/dist/preview/HoverToolbarController.js +20 -5
- package/dist/preview/HoverToolbarController.js.map +1 -1
- package/dist/styles/blocks-tab.css +1 -7
- package/dist/styles/overlay.css +2 -0
- package/dist/styles/sidebar.css +1 -0
- package/dist/styles/toggle.css +17 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +13 -14
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/i18n/useBetterEditorT.ts"],"sourcesContent":["'use client'\n\nimport { useTranslation } from '@payloadcms/ui'\nimport type { BetterEditorTranslations } from './types'\nimport { en } from './en'\n\nexport const useBetterEditorT = (): BetterEditorTranslations => {\n const { i18n } = useTranslation()\n const custom = (i18n.translations as Record<string, unknown>)?.betterEditor\n return (custom as BetterEditorTranslations | undefined) ?? en\n}\n"],"names":["useTranslation","en","useBetterEditorT","i18n","custom","translations","betterEditor"],"mappings":"AAAA;AAEA,SAASA,cAAc,QAAQ,iBAAgB;AAE/C,SAASC,EAAE,QAAQ,OAAM;AAEzB,OAAO,MAAMC,mBAAmB;IAC9B,MAAM,EAAEC,IAAI,EAAE,GAAGH;IACjB,MAAMI,SAAUD,KAAKE,YAAY,EAA8BC;IAC/D,OAAO,AAACF,UAAmDH;AAC7D,EAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,8 @@ import type { BetterEditorConfig } from './types';
|
|
|
3
3
|
export type { BetterEditorConfig };
|
|
4
4
|
export type { BetterEditorSettings, HoverToolbarPosition } from './state/useBetterEditorSettings';
|
|
5
5
|
export type { SidebarPosition } from './internal/constants';
|
|
6
|
-
export {
|
|
6
|
+
export type { BetterEditorTranslations } from './i18n/types';
|
|
7
|
+
export { BETTER_EDITOR_SETTINGS_SLUG, betterEditorSettingsGlobal } from './global';
|
|
7
8
|
/** Plugin signature — handy for typing plugin lists in consumer code. */
|
|
8
9
|
export type BetterEditorPlugin = (config: Config) => Config;
|
|
9
10
|
export { VERSION } from './version';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { BETTER_EDITOR_SETTINGS_BANNER_FIELD, betterEditorSettingsGlobal } from './global';
|
|
2
2
|
import { normalizeEntities } from './internal/entities';
|
|
3
|
-
|
|
3
|
+
import { en } from './i18n/en';
|
|
4
|
+
import { de } from './i18n/de';
|
|
5
|
+
import { mergeTranslations } from './i18n/merge';
|
|
6
|
+
export { BETTER_EDITOR_SETTINGS_SLUG, betterEditorSettingsGlobal } from './global';
|
|
4
7
|
export { VERSION } from './version';
|
|
5
8
|
const DEFAULT_BLOCKS_FIELD = 'layout';
|
|
6
9
|
const TOGGLE_COMPONENT_PATH = 'payload-better-editor/client#LiveEditorToggle';
|
|
@@ -79,7 +82,8 @@ const warnMissingBlocksField = (kind, slug, blocksField)=>{
|
|
|
79
82
|
const toggleClientProps = (blocksField)=>({
|
|
80
83
|
blocksField,
|
|
81
84
|
adminPortalSelector: pluginOptions?.adminPortalSelector,
|
|
82
|
-
storageNamespace: pluginOptions?.storageNamespace
|
|
85
|
+
storageNamespace: pluginOptions?.storageNamespace,
|
|
86
|
+
hideToggleLabel: pluginOptions?.hideToggleLabel
|
|
83
87
|
});
|
|
84
88
|
const showBanner = pluginOptions?.showSettingsBanner !== false;
|
|
85
89
|
const settingsGlobal = showBanner ? betterEditorSettingsGlobal : {
|
|
@@ -92,6 +96,21 @@ const warnMissingBlocksField = (kind, slug, blocksField)=>{
|
|
|
92
96
|
...existingGlobals,
|
|
93
97
|
settingsGlobal
|
|
94
98
|
];
|
|
99
|
+
const existingTranslations = config.i18n?.translations ?? {};
|
|
100
|
+
config.i18n = {
|
|
101
|
+
...config.i18n,
|
|
102
|
+
translations: {
|
|
103
|
+
...existingTranslations,
|
|
104
|
+
en: {
|
|
105
|
+
...existingTranslations.en ?? {},
|
|
106
|
+
betterEditor: mergeTranslations(en, existingTranslations.en)
|
|
107
|
+
},
|
|
108
|
+
de: {
|
|
109
|
+
...existingTranslations.de ?? {},
|
|
110
|
+
betterEditor: mergeTranslations(de, existingTranslations.de)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
95
114
|
if (collectionMap.size === 0 && globalMap.size === 0) {
|
|
96
115
|
if (isDev) {
|
|
97
116
|
console.warn('[better-editor] plugin loaded with empty `collections` and `globals` — toggle button will not appear anywhere. Pass `collections: ["pages"]` (or similar) to BetterEditorConfig.');
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { CollectionConfig, Config, Field, GlobalConfig } from 'payload'\nimport type { BetterEditorConfig } from './types'\nimport { BETTER_EDITOR_SETTINGS_BANNER_FIELD, betterEditorSettingsGlobal } from './global'\nimport { normalizeEntities } from './internal/entities'\n\nexport type { BetterEditorConfig }\nexport type { BetterEditorSettings, HoverToolbarPosition } from './state/useBetterEditorSettings'\nexport type { SidebarPosition } from './internal/constants'\nexport { BETTER_EDITOR_SETTINGS_SLUG } from './global'\n\n/** Plugin signature — handy for typing plugin lists in consumer code. */\nexport type BetterEditorPlugin = (config: Config) => Config\n\nexport { VERSION } from './version'\n\nconst DEFAULT_BLOCKS_FIELD = 'layout'\nconst TOGGLE_COMPONENT_PATH = 'payload-better-editor/client#LiveEditorToggle'\nconst isDev = process.env.NODE_ENV !== 'production'\n\n/**\n * Checks whether a field with the given `name` exists at the document's\n * top-level data path. Recurses into presentational containers that do\n * not introduce a path segment (`tabs` without a name, `row`, `collapsible`)\n * but stops at `group` and named tabs, since those namespace their children.\n */\nconst hasBlocksField = (fields: Field[] | undefined, name: string): boolean => {\n if (!Array.isArray(fields)) return false\n return fields.some((field) => {\n if ('name' in field && field.name === name) return true\n if (field.type === 'row' || field.type === 'collapsible') {\n return hasBlocksField(field.fields, name)\n }\n if (field.type === 'tabs') {\n return field.tabs.some((tab) =>\n 'name' in tab && tab.name ? false : hasBlocksField(tab.fields, name),\n )\n }\n return false\n })\n}\n\ntype ToggleSlot = 'edit' | 'elements'\n\ntype ToggleClientProps = {\n blocksField: string\n adminPortalSelector?: string\n storageNamespace?: string\n}\n\nconst withToggleInjected = <T extends CollectionConfig | GlobalConfig>(\n entity: T,\n slot: ToggleSlot,\n clientProps: ToggleClientProps,\n): T => {\n const admin = { ...(entity.admin ?? {}) } as NonNullable<T['admin']>\n const components = { ...(admin.components ?? {}) } as Record<string, unknown>\n const target = { ...((components[slot] as Record<string, unknown>) ?? {}) }\n const before = (target.beforeDocumentControls as unknown[]) ?? []\n return {\n ...entity,\n admin: {\n ...admin,\n components: {\n ...components,\n [slot]: {\n ...target,\n beforeDocumentControls: [\n ...before,\n { path: TOGGLE_COMPONENT_PATH, clientProps },\n ],\n },\n },\n },\n }\n}\n\nconst warnMissingBlocksField = (kind: 'collection' | 'global', slug: string, blocksField: string) => {\n\n console.warn(\n `[better-editor] ${kind} \"${slug}\" has no top-level field named \"${blocksField}\" — the sidebar Blocks tab will be empty. Set \\`blocksField\\` to the actual blocks field name.`,\n )\n}\n\n/**\n * Payload CMS plugin factory for the Better Editor overlay. Adds an\n * \"Open Better Editor\" toggle to the configured collections / globals\n * and registers a `BetterEditorSettings` global with editor-wide options.\n *\n * @example\n * import { betterEditor } from 'payload-better-editor'\n *\n * export default buildConfig({\n * plugins: [betterEditor({ collections: ['pages'] })],\n * // ...\n * })\n *\n * @see {@link BetterEditorConfig} for all options.\n */\nexport const betterEditor =\n (pluginOptions?: BetterEditorConfig): BetterEditorPlugin =>\n (config: Config): Config => {\n if (pluginOptions?.disabled) return config\n\n const defaultBlocksField = pluginOptions?.blocksField || DEFAULT_BLOCKS_FIELD\n const collectionMap = normalizeEntities(pluginOptions?.collections, defaultBlocksField)\n const globalMap = normalizeEntities(pluginOptions?.globals, defaultBlocksField)\n const toggleClientProps = (blocksField: string): ToggleClientProps => ({\n blocksField,\n adminPortalSelector: pluginOptions?.adminPortalSelector,\n storageNamespace: pluginOptions?.storageNamespace,\n })\n\n const showBanner = pluginOptions?.showSettingsBanner !== false\n const settingsGlobal: GlobalConfig = showBanner\n ? betterEditorSettingsGlobal\n : {\n ...betterEditorSettingsGlobal,\n fields: betterEditorSettingsGlobal.fields.filter(\n (f) => !('name' in f && f.name === BETTER_EDITOR_SETTINGS_BANNER_FIELD),\n ),\n }\n\n const existingGlobals = config.globals ?? []\n const hasSettingsGlobal = existingGlobals.some((g) => g.slug === settingsGlobal.slug)\n config.globals = hasSettingsGlobal\n ? existingGlobals\n : [...existingGlobals, settingsGlobal]\n\n if (collectionMap.size === 0 && globalMap.size === 0) {\n if (isDev) {\n\n console.warn(\n '[better-editor] plugin loaded with empty `collections` and `globals` — toggle button will not appear anywhere. Pass `collections: [\"pages\"]` (or similar) to BetterEditorConfig.',\n )\n }\n return config\n }\n\n if (collectionMap.size > 0 && config.collections) {\n config.collections = config.collections.map((collection) => {\n const blocksField = collectionMap.get(collection.slug)\n if (blocksField === undefined) return collection\n if (isDev && !hasBlocksField(collection.fields, blocksField)) {\n warnMissingBlocksField('collection', collection.slug, blocksField)\n }\n return withToggleInjected(collection, 'edit', toggleClientProps(blocksField))\n })\n }\n\n if (globalMap.size > 0) {\n config.globals = (config.globals ?? []).map((global) => {\n const blocksField = globalMap.get(global.slug)\n if (blocksField === undefined) return global\n if (isDev && !hasBlocksField(global.fields, blocksField)) {\n warnMissingBlocksField('global', global.slug, blocksField)\n }\n return withToggleInjected(global, 'elements', toggleClientProps(blocksField))\n })\n }\n\n return config\n }\n"],"names":["BETTER_EDITOR_SETTINGS_BANNER_FIELD","betterEditorSettingsGlobal","normalizeEntities","BETTER_EDITOR_SETTINGS_SLUG","VERSION","DEFAULT_BLOCKS_FIELD","TOGGLE_COMPONENT_PATH","isDev","process","env","NODE_ENV","hasBlocksField","fields","name","Array","isArray","some","field","type","tabs","tab","withToggleInjected","entity","slot","clientProps","admin","components","target","before","beforeDocumentControls","path","warnMissingBlocksField","kind","slug","blocksField","console","warn","betterEditor","pluginOptions","config","disabled","defaultBlocksField","collectionMap","collections","globalMap","globals","toggleClientProps","adminPortalSelector","storageNamespace","showBanner","showSettingsBanner","settingsGlobal","filter","f","existingGlobals","hasSettingsGlobal","g","size","map","collection","get","undefined","global"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { CollectionConfig, Config, Field, GlobalConfig } from 'payload'\nimport type { BetterEditorConfig } from './types'\nimport { BETTER_EDITOR_SETTINGS_BANNER_FIELD, betterEditorSettingsGlobal } from './global'\nimport { normalizeEntities } from './internal/entities'\nimport { en } from './i18n/en'\nimport { de } from './i18n/de'\nimport { mergeTranslations } from './i18n/merge'\n\nexport type { BetterEditorConfig }\nexport type { BetterEditorSettings, HoverToolbarPosition } from './state/useBetterEditorSettings'\nexport type { SidebarPosition } from './internal/constants'\nexport type { BetterEditorTranslations } from './i18n/types'\nexport { BETTER_EDITOR_SETTINGS_SLUG, betterEditorSettingsGlobal } from './global'\n\n/** Plugin signature — handy for typing plugin lists in consumer code. */\nexport type BetterEditorPlugin = (config: Config) => Config\n\nexport { VERSION } from './version'\n\nconst DEFAULT_BLOCKS_FIELD = 'layout'\nconst TOGGLE_COMPONENT_PATH = 'payload-better-editor/client#LiveEditorToggle'\nconst isDev = process.env.NODE_ENV !== 'production'\n\n/**\n * Checks whether a field with the given `name` exists at the document's\n * top-level data path. Recurses into presentational containers that do\n * not introduce a path segment (`tabs` without a name, `row`, `collapsible`)\n * but stops at `group` and named tabs, since those namespace their children.\n */\nconst hasBlocksField = (fields: Field[] | undefined, name: string): boolean => {\n if (!Array.isArray(fields)) return false\n return fields.some((field) => {\n if ('name' in field && field.name === name) return true\n if (field.type === 'row' || field.type === 'collapsible') {\n return hasBlocksField(field.fields, name)\n }\n if (field.type === 'tabs') {\n return field.tabs.some((tab) =>\n 'name' in tab && tab.name ? false : hasBlocksField(tab.fields, name),\n )\n }\n return false\n })\n}\n\ntype ToggleSlot = 'edit' | 'elements'\n\ntype ToggleClientProps = {\n blocksField: string\n adminPortalSelector?: string\n storageNamespace?: string\n hideToggleLabel?: boolean\n}\n\nconst withToggleInjected = <T extends CollectionConfig | GlobalConfig>(\n entity: T,\n slot: ToggleSlot,\n clientProps: ToggleClientProps,\n): T => {\n const admin = { ...(entity.admin ?? {}) } as NonNullable<T['admin']>\n const components = { ...(admin.components ?? {}) } as Record<string, unknown>\n const target = { ...((components[slot] as Record<string, unknown>) ?? {}) }\n const before = (target.beforeDocumentControls as unknown[]) ?? []\n return {\n ...entity,\n admin: {\n ...admin,\n components: {\n ...components,\n [slot]: {\n ...target,\n beforeDocumentControls: [\n ...before,\n { path: TOGGLE_COMPONENT_PATH, clientProps },\n ],\n },\n },\n },\n }\n}\n\nconst warnMissingBlocksField = (kind: 'collection' | 'global', slug: string, blocksField: string) => {\n\n console.warn(\n `[better-editor] ${kind} \"${slug}\" has no top-level field named \"${blocksField}\" — the sidebar Blocks tab will be empty. Set \\`blocksField\\` to the actual blocks field name.`,\n )\n}\n\n/**\n * Payload CMS plugin factory for the Better Editor overlay. Adds an\n * \"Open Better Editor\" toggle to the configured collections / globals\n * and registers a `BetterEditorSettings` global with editor-wide options.\n *\n * @example\n * import { betterEditor } from 'payload-better-editor'\n *\n * export default buildConfig({\n * plugins: [betterEditor({ collections: ['pages'] })],\n * // ...\n * })\n *\n * @see {@link BetterEditorConfig} for all options.\n */\nexport const betterEditor =\n (pluginOptions?: BetterEditorConfig): BetterEditorPlugin =>\n (config: Config): Config => {\n if (pluginOptions?.disabled) return config\n\n const defaultBlocksField = pluginOptions?.blocksField || DEFAULT_BLOCKS_FIELD\n const collectionMap = normalizeEntities(pluginOptions?.collections, defaultBlocksField)\n const globalMap = normalizeEntities(pluginOptions?.globals, defaultBlocksField)\n const toggleClientProps = (blocksField: string): ToggleClientProps => ({\n blocksField,\n adminPortalSelector: pluginOptions?.adminPortalSelector,\n storageNamespace: pluginOptions?.storageNamespace,\n hideToggleLabel: pluginOptions?.hideToggleLabel,\n })\n\n const showBanner = pluginOptions?.showSettingsBanner !== false\n const settingsGlobal: GlobalConfig = showBanner\n ? betterEditorSettingsGlobal\n : {\n ...betterEditorSettingsGlobal,\n fields: betterEditorSettingsGlobal.fields.filter(\n (f) => !('name' in f && f.name === BETTER_EDITOR_SETTINGS_BANNER_FIELD),\n ),\n }\n\n const existingGlobals = config.globals ?? []\n const hasSettingsGlobal = existingGlobals.some((g) => g.slug === settingsGlobal.slug)\n config.globals = hasSettingsGlobal\n ? existingGlobals\n : [...existingGlobals, settingsGlobal]\n\n const existingTranslations = config.i18n?.translations ?? {}\n config.i18n = {\n ...config.i18n,\n translations: {\n ...existingTranslations,\n en: {\n ...(existingTranslations.en as object ?? {}),\n betterEditor: mergeTranslations(en, existingTranslations.en),\n },\n de: {\n ...(existingTranslations.de as object ?? {}),\n betterEditor: mergeTranslations(de, existingTranslations.de),\n },\n },\n }\n\n if (collectionMap.size === 0 && globalMap.size === 0) {\n if (isDev) {\n\n console.warn(\n '[better-editor] plugin loaded with empty `collections` and `globals` — toggle button will not appear anywhere. Pass `collections: [\"pages\"]` (or similar) to BetterEditorConfig.',\n )\n }\n return config\n }\n\n if (collectionMap.size > 0 && config.collections) {\n config.collections = config.collections.map((collection) => {\n const blocksField = collectionMap.get(collection.slug)\n if (blocksField === undefined) return collection\n if (isDev && !hasBlocksField(collection.fields, blocksField)) {\n warnMissingBlocksField('collection', collection.slug, blocksField)\n }\n return withToggleInjected(collection, 'edit', toggleClientProps(blocksField))\n })\n }\n\n if (globalMap.size > 0) {\n config.globals = (config.globals ?? []).map((global) => {\n const blocksField = globalMap.get(global.slug)\n if (blocksField === undefined) return global\n if (isDev && !hasBlocksField(global.fields, blocksField)) {\n warnMissingBlocksField('global', global.slug, blocksField)\n }\n return withToggleInjected(global, 'elements', toggleClientProps(blocksField))\n })\n }\n\n return config\n }\n"],"names":["BETTER_EDITOR_SETTINGS_BANNER_FIELD","betterEditorSettingsGlobal","normalizeEntities","en","de","mergeTranslations","BETTER_EDITOR_SETTINGS_SLUG","VERSION","DEFAULT_BLOCKS_FIELD","TOGGLE_COMPONENT_PATH","isDev","process","env","NODE_ENV","hasBlocksField","fields","name","Array","isArray","some","field","type","tabs","tab","withToggleInjected","entity","slot","clientProps","admin","components","target","before","beforeDocumentControls","path","warnMissingBlocksField","kind","slug","blocksField","console","warn","betterEditor","pluginOptions","config","disabled","defaultBlocksField","collectionMap","collections","globalMap","globals","toggleClientProps","adminPortalSelector","storageNamespace","hideToggleLabel","showBanner","showSettingsBanner","settingsGlobal","filter","f","existingGlobals","hasSettingsGlobal","g","existingTranslations","i18n","translations","size","map","collection","get","undefined","global"],"mappings":"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"}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { BlockActionMessage } from './protocol';
|
|
3
3
|
type Action = BlockActionMessage['action'];
|
|
4
|
+
export type HoverToolbarLabels = {
|
|
5
|
+
moveUp: string;
|
|
6
|
+
moveDown: string;
|
|
7
|
+
duplicate: string;
|
|
8
|
+
addBelow: string;
|
|
9
|
+
delete: string;
|
|
10
|
+
};
|
|
4
11
|
export type HoverToolbarProps = {
|
|
5
12
|
onAction: (action: Action) => void;
|
|
13
|
+
labels: HoverToolbarLabels;
|
|
6
14
|
};
|
|
7
15
|
export declare const HoverToolbar: React.FC<HoverToolbarProps>;
|
|
8
16
|
export {};
|
|
@@ -2,35 +2,36 @@
|
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { ChevronDown, ChevronUp, CopyIcon, PlusIcon, TrashIcon } from '../admin/icons';
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
5
|
+
export const HoverToolbar = ({ onAction, labels })=>{
|
|
6
|
+
const buttons = [
|
|
7
|
+
{
|
|
8
|
+
action: 'move-up',
|
|
9
|
+
Icon: ChevronUp,
|
|
10
|
+
label: labels.moveUp
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
action: 'move-down',
|
|
14
|
+
Icon: ChevronDown,
|
|
15
|
+
label: labels.moveDown
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
action: 'duplicate',
|
|
19
|
+
Icon: CopyIcon,
|
|
20
|
+
label: labels.duplicate
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
action: 'add',
|
|
24
|
+
Icon: PlusIcon,
|
|
25
|
+
label: labels.addBelow
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
action: 'delete',
|
|
29
|
+
Icon: TrashIcon,
|
|
30
|
+
label: labels.delete
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
return /*#__PURE__*/ _jsx(_Fragment, {
|
|
34
|
+
children: buttons.map(({ action, Icon, label })=>/*#__PURE__*/ _jsx("button", {
|
|
34
35
|
type: "button",
|
|
35
36
|
"aria-label": label,
|
|
36
37
|
title: label,
|
|
@@ -44,5 +45,6 @@ export const HoverToolbar = ({ onAction })=>/*#__PURE__*/ _jsx(_Fragment, {
|
|
|
44
45
|
})
|
|
45
46
|
}, action))
|
|
46
47
|
});
|
|
48
|
+
};
|
|
47
49
|
|
|
48
50
|
//# sourceMappingURL=HoverToolbar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/preview/HoverToolbar.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\nimport { ChevronDown, ChevronUp, CopyIcon, PlusIcon, TrashIcon } from '../admin/icons'\nimport type { BlockActionMessage } from './protocol'\n\ntype Action = BlockActionMessage['action']\n\
|
|
1
|
+
{"version":3,"sources":["../../src/preview/HoverToolbar.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\nimport { ChevronDown, ChevronUp, CopyIcon, PlusIcon, TrashIcon } from '../admin/icons'\nimport type { BlockActionMessage } from './protocol'\n\ntype Action = BlockActionMessage['action']\n\nexport type HoverToolbarLabels = {\n moveUp: string\n moveDown: string\n duplicate: string\n addBelow: string\n delete: string\n}\n\nexport type HoverToolbarProps = {\n onAction: (action: Action) => void\n labels: HoverToolbarLabels\n}\n\nexport const HoverToolbar: React.FC<HoverToolbarProps> = ({ onAction, labels }) => {\n const buttons: ReadonlyArray<{ action: Action; Icon: React.ComponentType<{ size?: number }>; label: string }> = [\n { action: 'move-up', Icon: ChevronUp, label: labels.moveUp },\n { action: 'move-down', Icon: ChevronDown, label: labels.moveDown },\n { action: 'duplicate', Icon: CopyIcon, label: labels.duplicate },\n { action: 'add', Icon: PlusIcon, label: labels.addBelow },\n { action: 'delete', Icon: TrashIcon, label: labels.delete },\n ]\n\n return (\n <>\n {buttons.map(({ action, Icon, label }) => (\n <button\n key={action}\n type=\"button\"\n aria-label={label}\n title={label}\n data-action={action}\n onClick={(e) => {\n e.stopPropagation()\n onAction(action)\n }}\n >\n <Icon size={14} />\n </button>\n ))}\n </>\n )\n}\n"],"names":["React","ChevronDown","ChevronUp","CopyIcon","PlusIcon","TrashIcon","HoverToolbar","onAction","labels","buttons","action","Icon","label","moveUp","moveDown","duplicate","addBelow","delete","map","button","type","aria-label","title","data-action","onClick","e","stopPropagation","size"],"mappings":"AAAA;;AAEA,OAAOA,WAAW,QAAO;AACzB,SAASC,WAAW,EAAEC,SAAS,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,SAAS,QAAQ,iBAAgB;AAkBtF,OAAO,MAAMC,eAA4C,CAAC,EAAEC,QAAQ,EAAEC,MAAM,EAAE;IAC5E,MAAMC,UAA0G;QAC9G;YAAEC,QAAQ;YAAWC,MAAMT;YAAWU,OAAOJ,OAAOK,MAAM;QAAC;QAC3D;YAAEH,QAAQ;YAAaC,MAAMV;YAAaW,OAAOJ,OAAOM,QAAQ;QAAC;QACjE;YAAEJ,QAAQ;YAAaC,MAAMR;YAAUS,OAAOJ,OAAOO,SAAS;QAAC;QAC/D;YAAEL,QAAQ;YAAOC,MAAMP;YAAUQ,OAAOJ,OAAOQ,QAAQ;QAAC;QACxD;YAAEN,QAAQ;YAAUC,MAAMN;YAAWO,OAAOJ,OAAOS,MAAM;QAAC;KAC3D;IAED,qBACE;kBACGR,QAAQS,GAAG,CAAC,CAAC,EAAER,MAAM,EAAEC,IAAI,EAAEC,KAAK,EAAE,iBACnC,KAACO;gBAECC,MAAK;gBACLC,cAAYT;gBACZU,OAAOV;gBACPW,eAAab;gBACbc,SAAS,CAACC;oBACRA,EAAEC,eAAe;oBACjBnB,SAASG;gBACX;0BAEA,cAAA,KAACC;oBAAKgB,MAAM;;eAVPjB;;AAef,EAAC"}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import type { HoverToolbarPosition } from '../internal/constants';
|
|
2
2
|
import type { BlockActionMessage } from './protocol';
|
|
3
|
+
import { type HoverToolbarLabels } from './HoverToolbar';
|
|
4
|
+
import type { BetterEditorTranslations } from '../i18n/types';
|
|
3
5
|
export type HoverToolbarOptions = {
|
|
4
6
|
position: HoverToolbarPosition;
|
|
5
7
|
outlineWidth: number;
|
|
6
8
|
onAction: (id: string, action: BlockActionMessage['action']) => void;
|
|
9
|
+
labels: HoverToolbarLabels;
|
|
7
10
|
};
|
|
11
|
+
export type { HoverToolbarLabels };
|
|
12
|
+
export declare const toHoverToolbarLabels: (actions: BetterEditorTranslations["blocks"]["actions"]) => HoverToolbarLabels;
|
|
8
13
|
export declare class HoverToolbarController {
|
|
9
14
|
private readonly doc;
|
|
10
15
|
private opts;
|
|
@@ -21,6 +26,7 @@ export declare class HoverToolbarController {
|
|
|
21
26
|
constructor(doc: Document, opts: HoverToolbarOptions);
|
|
22
27
|
private scheduleReselect;
|
|
23
28
|
update(opts: HoverToolbarOptions): void;
|
|
29
|
+
private renderToolbar;
|
|
24
30
|
select(id: string): void;
|
|
25
31
|
deselect(): void;
|
|
26
32
|
destroy(): void;
|
|
@@ -4,6 +4,16 @@ import { ACTIVE_CLASS, BLOCK_ID_ATTR, BLOCK_ID_SELECTOR } from '../internal/dom'
|
|
|
4
4
|
import { TOOLBAR_ID } from './hover-css';
|
|
5
5
|
import { HoverToolbar } from './HoverToolbar';
|
|
6
6
|
import { calculateToolbarPosition } from './toolbar-position';
|
|
7
|
+
// The toolbar only needs the five short action labels, not the longer `*Label`
|
|
8
|
+
// aria variants in `blocks.actions` — pick them in one place so the two preview
|
|
9
|
+
// hooks that build a controller stay in sync.
|
|
10
|
+
export const toHoverToolbarLabels = (actions)=>({
|
|
11
|
+
moveUp: actions.moveUp,
|
|
12
|
+
moveDown: actions.moveDown,
|
|
13
|
+
duplicate: actions.duplicate,
|
|
14
|
+
addBelow: actions.addBelow,
|
|
15
|
+
delete: actions.delete
|
|
16
|
+
});
|
|
7
17
|
const FALLBACK_TB_WIDTH = 120;
|
|
8
18
|
const FALLBACK_TB_HEIGHT = 32;
|
|
9
19
|
export class HoverToolbarController {
|
|
@@ -28,11 +38,7 @@ export class HoverToolbarController {
|
|
|
28
38
|
doc.body.appendChild(toolbar);
|
|
29
39
|
this.toolbar = toolbar;
|
|
30
40
|
this.root = createRoot(toolbar);
|
|
31
|
-
this.
|
|
32
|
-
onAction: (action)=>{
|
|
33
|
-
if (this.currentBlockId) this.opts.onAction(this.currentBlockId, action);
|
|
34
|
-
}
|
|
35
|
-
}));
|
|
41
|
+
this.renderToolbar();
|
|
36
42
|
this.onScroll = ()=>this.scheduleReposition();
|
|
37
43
|
doc.defaultView?.addEventListener('scroll', this.onScroll, true);
|
|
38
44
|
this.observer = new MutationObserver(()=>{
|
|
@@ -57,8 +63,17 @@ export class HoverToolbarController {
|
|
|
57
63
|
}
|
|
58
64
|
update(opts) {
|
|
59
65
|
this.opts = opts;
|
|
66
|
+
this.renderToolbar();
|
|
60
67
|
if (this.currentBlockEl) this.scheduleReposition();
|
|
61
68
|
}
|
|
69
|
+
renderToolbar() {
|
|
70
|
+
this.root.render(React.createElement(HoverToolbar, {
|
|
71
|
+
labels: this.opts.labels,
|
|
72
|
+
onAction: (action)=>{
|
|
73
|
+
if (this.currentBlockId) this.opts.onAction(this.currentBlockId, action);
|
|
74
|
+
}
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
62
77
|
select(id) {
|
|
63
78
|
if (this.destroyed) return;
|
|
64
79
|
const escaped = typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(id) : id.replace(/["\\]/g, '\\$&');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/preview/HoverToolbarController.ts"],"sourcesContent":["import React from 'react'\nimport { createRoot, type Root } from 'react-dom/client'\nimport type { HoverToolbarPosition } from '../internal/constants'\nimport { ACTIVE_CLASS, BLOCK_ID_ATTR, BLOCK_ID_SELECTOR } from '../internal/dom'\nimport type { BlockActionMessage } from './protocol'\nimport { TOOLBAR_ID } from './hover-css'\nimport { HoverToolbar } from './HoverToolbar'\nimport { calculateToolbarPosition } from './toolbar-position'\n\nexport type HoverToolbarOptions = {\n position: HoverToolbarPosition\n outlineWidth: number\n onAction: (id: string, action: BlockActionMessage['action']) => void\n}\n\nconst FALLBACK_TB_WIDTH = 120\nconst FALLBACK_TB_HEIGHT = 32\n\nexport class HoverToolbarController {\n private readonly doc: Document\n private opts: HoverToolbarOptions\n private readonly toolbar: HTMLDivElement\n private readonly root: Root\n private destroyed = false\n private currentBlockId: string | null = null\n private currentBlockEl: HTMLElement | null = null\n private activeChain: HTMLElement[] = []\n private positionRaf = 0\n private observerRaf = 0\n private readonly onScroll: () => void\n private readonly observer: MutationObserver\n\n constructor(doc: Document, opts: HoverToolbarOptions) {\n this.doc = doc\n this.opts = opts\n\n doc.getElementById(TOOLBAR_ID)?.remove()\n const toolbar = doc.createElement('div')\n toolbar.id = TOOLBAR_ID\n doc.body.appendChild(toolbar)\n this.toolbar = toolbar\n\n this.root = createRoot(toolbar)\n this.root.render(\n React.createElement(HoverToolbar, {\n onAction: (action) => {\n if (this.currentBlockId) this.opts.onAction(this.currentBlockId, action)\n },\n }),\n )\n\n this.onScroll = () => this.scheduleReposition()\n doc.defaultView?.addEventListener('scroll', this.onScroll, true)\n\n this.observer = new MutationObserver(() => {\n if (this.destroyed || !this.currentBlockId) return\n // Coalesce mutation bursts into a single re-select on the next paint.\n // Re-using positionRaf avoids the previous two-tier RAF pyramid.\n this.scheduleReselect()\n })\n this.observer.observe(doc.body, { childList: true, subtree: true })\n }\n\n private scheduleReselect(): void {\n const view = this.doc.defaultView\n if (!view || this.observerRaf) return\n this.observerRaf = view.requestAnimationFrame(() => {\n this.observerRaf = 0\n if (this.destroyed || !this.currentBlockId) return\n this.select(this.currentBlockId)\n })\n }\n\n update(opts: HoverToolbarOptions): void {\n this.opts = opts\n if (this.currentBlockEl) this.scheduleReposition()\n }\n\n select(id: string): void {\n if (this.destroyed) return\n const escaped = typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(id) : id.replace(/[\"\\\\]/g, '\\\\$&')\n const el = this.doc.querySelector<HTMLElement>(`[${BLOCK_ID_ATTR}=\"${escaped}\"]`)\n if (!el) {\n // Block not in DOM (yet) — keep id but hide the toolbar; a later\n // select(id) call after the iframe re-render will resolve it.\n this.currentBlockId = id\n this.currentBlockEl = null\n this.clearActive()\n this.toolbar.classList.remove('is-visible')\n return\n }\n this.currentBlockId = id\n this.currentBlockEl = el\n this.markActiveChain(el)\n const isNested = this.activeChain.length > 1\n this.toolbar.dataset.nested = isNested ? '1' : '0'\n this.toolbar.classList.add('is-visible')\n this.scheduleReposition()\n }\n\n deselect(): void {\n if (this.destroyed) return\n if (!this.currentBlockId) return\n this.clearActive()\n this.currentBlockId = null\n this.currentBlockEl = null\n this.toolbar.classList.remove('is-visible')\n }\n\n destroy(): void {\n if (this.destroyed) return\n this.destroyed = true\n this.observer.disconnect()\n const view = this.doc.defaultView\n view?.removeEventListener('scroll', this.onScroll, true)\n if (this.positionRaf) view?.cancelAnimationFrame(this.positionRaf)\n if (this.observerRaf) view?.cancelAnimationFrame(this.observerRaf)\n this.positionRaf = 0\n this.observerRaf = 0\n this.clearActive()\n this.currentBlockId = null\n this.currentBlockEl = null\n // Defer unmount — React 19 throws if it lands synchronously mid-render of\n // another tree; StrictMode also double-invokes us, so only remove the\n // toolbar node if we still own it.\n const { root, toolbar } = this\n queueMicrotask(() => {\n try { root.unmount() } catch { /* already unmounted */ }\n if (toolbar.isConnected) toolbar.remove()\n })\n }\n\n private scheduleReposition(): void {\n const view = this.doc.defaultView\n if (!view) {\n this.positionToolbar()\n return\n }\n if (this.positionRaf) view.cancelAnimationFrame(this.positionRaf)\n this.positionRaf = view.requestAnimationFrame(() => {\n this.positionRaf = 0\n this.positionToolbar()\n })\n }\n\n private positionToolbar(): void {\n const el = this.currentBlockEl\n if (!el || !el.isConnected) return\n const view = this.doc.defaultView\n if (!view) return\n const { top, left } = calculateToolbarPosition(\n el.getBoundingClientRect(),\n {\n width: this.toolbar.offsetWidth || FALLBACK_TB_WIDTH,\n height: this.toolbar.offsetHeight || FALLBACK_TB_HEIGHT,\n },\n { scrollX: view.scrollX, scrollY: view.scrollY },\n this.opts.position,\n this.opts.outlineWidth,\n )\n const { style } = this.toolbar\n style.top = `${top}px`\n style.left = `${left}px`\n style.right = 'auto'\n }\n\n // Only clears the chain we marked, avoiding a full-document scan.\n private clearActive(): void {\n for (const node of this.activeChain) node.classList.remove(ACTIVE_CLASS)\n this.activeChain = []\n }\n\n private markActiveChain(el: HTMLElement): void {\n this.clearActive()\n const chain: HTMLElement[] = []\n for (\n let cur: HTMLElement | null = el;\n cur;\n cur = cur.parentElement?.closest<HTMLElement>(BLOCK_ID_SELECTOR) ?? null\n ) {\n cur.classList.add(ACTIVE_CLASS)\n chain.push(cur)\n }\n this.activeChain = chain\n }\n}\n"],"names":["React","createRoot","ACTIVE_CLASS","BLOCK_ID_ATTR","BLOCK_ID_SELECTOR","TOOLBAR_ID","HoverToolbar","calculateToolbarPosition","FALLBACK_TB_WIDTH","FALLBACK_TB_HEIGHT","HoverToolbarController","doc","opts","toolbar","root","destroyed","currentBlockId","currentBlockEl","activeChain","positionRaf","observerRaf","onScroll","observer","constructor","getElementById","remove","createElement","id","body","appendChild","render","onAction","action","scheduleReposition","defaultView","addEventListener","MutationObserver","scheduleReselect","observe","childList","subtree","view","requestAnimationFrame","select","update","escaped","CSS","escape","replace","el","querySelector","clearActive","classList","markActiveChain","isNested","length","dataset","nested","add","deselect","destroy","disconnect","removeEventListener","cancelAnimationFrame","queueMicrotask","unmount","isConnected","positionToolbar","top","left","getBoundingClientRect","width","offsetWidth","height","offsetHeight","scrollX","scrollY","position","outlineWidth","style","right","node","chain","cur","parentElement","closest","push"],"mappings":"AAAA,OAAOA,WAAW,QAAO;AACzB,SAASC,UAAU,QAAmB,mBAAkB;AAExD,SAASC,YAAY,EAAEC,aAAa,EAAEC,iBAAiB,QAAQ,kBAAiB;AAEhF,SAASC,UAAU,QAAQ,cAAa;AACxC,SAASC,YAAY,QAAQ,iBAAgB;AAC7C,SAASC,wBAAwB,QAAQ,qBAAoB;AAQ7D,MAAMC,oBAAoB;AAC1B,MAAMC,qBAAqB;AAE3B,OAAO,MAAMC;IACMC,IAAa;IACtBC,KAAyB;IAChBC,QAAuB;IACvBC,KAAU;IACnBC,YAAY,MAAK;IACjBC,iBAAgC,KAAI;IACpCC,iBAAqC,KAAI;IACzCC,cAA6B,EAAE,CAAA;IAC/BC,cAAc,EAAC;IACfC,cAAc,EAAC;IACNC,SAAoB;IACpBC,SAA0B;IAE3CC,YAAYZ,GAAa,EAAEC,IAAyB,CAAE;QACpD,IAAI,CAACD,GAAG,GAAGA;QACX,IAAI,CAACC,IAAI,GAAGA;QAEZD,IAAIa,cAAc,CAACnB,aAAaoB;QAChC,MAAMZ,UAAUF,IAAIe,aAAa,CAAC;QAClCb,QAAQc,EAAE,GAAGtB;QACbM,IAAIiB,IAAI,CAACC,WAAW,CAAChB;QACrB,IAAI,CAACA,OAAO,GAAGA;QAEf,IAAI,CAACC,IAAI,GAAGb,WAAWY;QACvB,IAAI,CAACC,IAAI,CAACgB,MAAM,CACd9B,MAAM0B,aAAa,CAACpB,cAAc;YAChCyB,UAAU,CAACC;gBACT,IAAI,IAAI,CAAChB,cAAc,EAAE,IAAI,CAACJ,IAAI,CAACmB,QAAQ,CAAC,IAAI,CAACf,cAAc,EAAEgB;YACnE;QACF;QAGF,IAAI,CAACX,QAAQ,GAAG,IAAM,IAAI,CAACY,kBAAkB;QAC7CtB,IAAIuB,WAAW,EAAEC,iBAAiB,UAAU,IAAI,CAACd,QAAQ,EAAE;QAE3D,IAAI,CAACC,QAAQ,GAAG,IAAIc,iBAAiB;YACnC,IAAI,IAAI,CAACrB,SAAS,IAAI,CAAC,IAAI,CAACC,cAAc,EAAE;YAC5C,sEAAsE;YACtE,iEAAiE;YACjE,IAAI,CAACqB,gBAAgB;QACvB;QACA,IAAI,CAACf,QAAQ,CAACgB,OAAO,CAAC3B,IAAIiB,IAAI,EAAE;YAAEW,WAAW;YAAMC,SAAS;QAAK;IACnE;IAEQH,mBAAyB;QAC/B,MAAMI,OAAO,IAAI,CAAC9B,GAAG,CAACuB,WAAW;QACjC,IAAI,CAACO,QAAQ,IAAI,CAACrB,WAAW,EAAE;QAC/B,IAAI,CAACA,WAAW,GAAGqB,KAAKC,qBAAqB,CAAC;YAC5C,IAAI,CAACtB,WAAW,GAAG;YACnB,IAAI,IAAI,CAACL,SAAS,IAAI,CAAC,IAAI,CAACC,cAAc,EAAE;YAC5C,IAAI,CAAC2B,MAAM,CAAC,IAAI,CAAC3B,cAAc;QACjC;IACF;IAEA4B,OAAOhC,IAAyB,EAAQ;QACtC,IAAI,CAACA,IAAI,GAAGA;QACZ,IAAI,IAAI,CAACK,cAAc,EAAE,IAAI,CAACgB,kBAAkB;IAClD;IAEAU,OAAOhB,EAAU,EAAQ;QACvB,IAAI,IAAI,CAACZ,SAAS,EAAE;QACpB,MAAM8B,UAAU,OAAOC,QAAQ,eAAeA,IAAIC,MAAM,GAAGD,IAAIC,MAAM,CAACpB,MAAMA,GAAGqB,OAAO,CAAC,UAAU;QACjG,MAAMC,KAAK,IAAI,CAACtC,GAAG,CAACuC,aAAa,CAAc,CAAC,CAAC,EAAE/C,cAAc,EAAE,EAAE0C,QAAQ,EAAE,CAAC;QAChF,IAAI,CAACI,IAAI;YACP,iEAAiE;YACjE,8DAA8D;YAC9D,IAAI,CAACjC,cAAc,GAAGW;YACtB,IAAI,CAACV,cAAc,GAAG;YACtB,IAAI,CAACkC,WAAW;YAChB,IAAI,CAACtC,OAAO,CAACuC,SAAS,CAAC3B,MAAM,CAAC;YAC9B;QACF;QACA,IAAI,CAACT,cAAc,GAAGW;QACtB,IAAI,CAACV,cAAc,GAAGgC;QACtB,IAAI,CAACI,eAAe,CAACJ;QACrB,MAAMK,WAAW,IAAI,CAACpC,WAAW,CAACqC,MAAM,GAAG;QAC3C,IAAI,CAAC1C,OAAO,CAAC2C,OAAO,CAACC,MAAM,GAAGH,WAAW,MAAM;QAC/C,IAAI,CAACzC,OAAO,CAACuC,SAAS,CAACM,GAAG,CAAC;QAC3B,IAAI,CAACzB,kBAAkB;IACzB;IAEA0B,WAAiB;QACf,IAAI,IAAI,CAAC5C,SAAS,EAAE;QACpB,IAAI,CAAC,IAAI,CAACC,cAAc,EAAE;QAC1B,IAAI,CAACmC,WAAW;QAChB,IAAI,CAACnC,cAAc,GAAG;QACtB,IAAI,CAACC,cAAc,GAAG;QACtB,IAAI,CAACJ,OAAO,CAACuC,SAAS,CAAC3B,MAAM,CAAC;IAChC;IAEAmC,UAAgB;QACd,IAAI,IAAI,CAAC7C,SAAS,EAAE;QACpB,IAAI,CAACA,SAAS,GAAG;QACjB,IAAI,CAACO,QAAQ,CAACuC,UAAU;QACxB,MAAMpB,OAAO,IAAI,CAAC9B,GAAG,CAACuB,WAAW;QACjCO,MAAMqB,oBAAoB,UAAU,IAAI,CAACzC,QAAQ,EAAE;QACnD,IAAI,IAAI,CAACF,WAAW,EAAEsB,MAAMsB,qBAAqB,IAAI,CAAC5C,WAAW;QACjE,IAAI,IAAI,CAACC,WAAW,EAAEqB,MAAMsB,qBAAqB,IAAI,CAAC3C,WAAW;QACjE,IAAI,CAACD,WAAW,GAAG;QACnB,IAAI,CAACC,WAAW,GAAG;QACnB,IAAI,CAAC+B,WAAW;QAChB,IAAI,CAACnC,cAAc,GAAG;QACtB,IAAI,CAACC,cAAc,GAAG;QACtB,0EAA0E;QAC1E,sEAAsE;QACtE,mCAAmC;QACnC,MAAM,EAAEH,IAAI,EAAED,OAAO,EAAE,GAAG,IAAI;QAC9BmD,eAAe;YACb,IAAI;gBAAElD,KAAKmD,OAAO;YAAG,EAAE,OAAM,CAA0B;YACvD,IAAIpD,QAAQqD,WAAW,EAAErD,QAAQY,MAAM;QACzC;IACF;IAEQQ,qBAA2B;QACjC,MAAMQ,OAAO,IAAI,CAAC9B,GAAG,CAACuB,WAAW;QACjC,IAAI,CAACO,MAAM;YACT,IAAI,CAAC0B,eAAe;YACpB;QACF;QACA,IAAI,IAAI,CAAChD,WAAW,EAAEsB,KAAKsB,oBAAoB,CAAC,IAAI,CAAC5C,WAAW;QAChE,IAAI,CAACA,WAAW,GAAGsB,KAAKC,qBAAqB,CAAC;YAC5C,IAAI,CAACvB,WAAW,GAAG;YACnB,IAAI,CAACgD,eAAe;QACtB;IACF;IAEQA,kBAAwB;QAC9B,MAAMlB,KAAK,IAAI,CAAChC,cAAc;QAC9B,IAAI,CAACgC,MAAM,CAACA,GAAGiB,WAAW,EAAE;QAC5B,MAAMzB,OAAO,IAAI,CAAC9B,GAAG,CAACuB,WAAW;QACjC,IAAI,CAACO,MAAM;QACX,MAAM,EAAE2B,GAAG,EAAEC,IAAI,EAAE,GAAG9D,yBACpB0C,GAAGqB,qBAAqB,IACxB;YACEC,OAAO,IAAI,CAAC1D,OAAO,CAAC2D,WAAW,IAAIhE;YACnCiE,QAAQ,IAAI,CAAC5D,OAAO,CAAC6D,YAAY,IAAIjE;QACvC,GACA;YAAEkE,SAASlC,KAAKkC,OAAO;YAAEC,SAASnC,KAAKmC,OAAO;QAAC,GAC/C,IAAI,CAAChE,IAAI,CAACiE,QAAQ,EAClB,IAAI,CAACjE,IAAI,CAACkE,YAAY;QAExB,MAAM,EAAEC,KAAK,EAAE,GAAG,IAAI,CAAClE,OAAO;QAC9BkE,MAAMX,GAAG,GAAG,GAAGA,IAAI,EAAE,CAAC;QACtBW,MAAMV,IAAI,GAAG,GAAGA,KAAK,EAAE,CAAC;QACxBU,MAAMC,KAAK,GAAG;IAChB;IAEA,kEAAkE;IAC1D7B,cAAoB;QAC1B,KAAK,MAAM8B,QAAQ,IAAI,CAAC/D,WAAW,CAAE+D,KAAK7B,SAAS,CAAC3B,MAAM,CAACvB;QAC3D,IAAI,CAACgB,WAAW,GAAG,EAAE;IACvB;IAEQmC,gBAAgBJ,EAAe,EAAQ;QAC7C,IAAI,CAACE,WAAW;QAChB,MAAM+B,QAAuB,EAAE;QAC/B,IACE,IAAIC,MAA0BlC,IAC9BkC,KACAA,MAAMA,IAAIC,aAAa,EAAEC,QAAqBjF,sBAAsB,KACpE;YACA+E,IAAI/B,SAAS,CAACM,GAAG,CAACxD;YAClBgF,MAAMI,IAAI,CAACH;QACb;QACA,IAAI,CAACjE,WAAW,GAAGgE;IACrB;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../src/preview/HoverToolbarController.ts"],"sourcesContent":["import React from 'react'\nimport { createRoot, type Root } from 'react-dom/client'\nimport type { HoverToolbarPosition } from '../internal/constants'\nimport { ACTIVE_CLASS, BLOCK_ID_ATTR, BLOCK_ID_SELECTOR } from '../internal/dom'\nimport type { BlockActionMessage } from './protocol'\nimport { TOOLBAR_ID } from './hover-css'\nimport { HoverToolbar, type HoverToolbarLabels } from './HoverToolbar'\nimport { calculateToolbarPosition } from './toolbar-position'\nimport type { BetterEditorTranslations } from '../i18n/types'\n\nexport type HoverToolbarOptions = {\n position: HoverToolbarPosition\n outlineWidth: number\n onAction: (id: string, action: BlockActionMessage['action']) => void\n labels: HoverToolbarLabels\n}\n\nexport type { HoverToolbarLabels }\n\n// The toolbar only needs the five short action labels, not the longer `*Label`\n// aria variants in `blocks.actions` — pick them in one place so the two preview\n// hooks that build a controller stay in sync.\nexport const toHoverToolbarLabels = (\n actions: BetterEditorTranslations['blocks']['actions'],\n): HoverToolbarLabels => ({\n moveUp: actions.moveUp,\n moveDown: actions.moveDown,\n duplicate: actions.duplicate,\n addBelow: actions.addBelow,\n delete: actions.delete,\n})\n\nconst FALLBACK_TB_WIDTH = 120\nconst FALLBACK_TB_HEIGHT = 32\n\nexport class HoverToolbarController {\n private readonly doc: Document\n private opts: HoverToolbarOptions\n private readonly toolbar: HTMLDivElement\n private readonly root: Root\n private destroyed = false\n private currentBlockId: string | null = null\n private currentBlockEl: HTMLElement | null = null\n private activeChain: HTMLElement[] = []\n private positionRaf = 0\n private observerRaf = 0\n private readonly onScroll: () => void\n private readonly observer: MutationObserver\n\n constructor(doc: Document, opts: HoverToolbarOptions) {\n this.doc = doc\n this.opts = opts\n\n doc.getElementById(TOOLBAR_ID)?.remove()\n const toolbar = doc.createElement('div')\n toolbar.id = TOOLBAR_ID\n doc.body.appendChild(toolbar)\n this.toolbar = toolbar\n\n this.root = createRoot(toolbar)\n this.renderToolbar()\n\n this.onScroll = () => this.scheduleReposition()\n doc.defaultView?.addEventListener('scroll', this.onScroll, true)\n\n this.observer = new MutationObserver(() => {\n if (this.destroyed || !this.currentBlockId) return\n // Coalesce mutation bursts into a single re-select on the next paint.\n // Re-using positionRaf avoids the previous two-tier RAF pyramid.\n this.scheduleReselect()\n })\n this.observer.observe(doc.body, { childList: true, subtree: true })\n }\n\n private scheduleReselect(): void {\n const view = this.doc.defaultView\n if (!view || this.observerRaf) return\n this.observerRaf = view.requestAnimationFrame(() => {\n this.observerRaf = 0\n if (this.destroyed || !this.currentBlockId) return\n this.select(this.currentBlockId)\n })\n }\n\n update(opts: HoverToolbarOptions): void {\n this.opts = opts\n this.renderToolbar()\n if (this.currentBlockEl) this.scheduleReposition()\n }\n\n private renderToolbar(): void {\n this.root.render(\n React.createElement(HoverToolbar, {\n labels: this.opts.labels,\n onAction: (action) => {\n if (this.currentBlockId) this.opts.onAction(this.currentBlockId, action)\n },\n }),\n )\n }\n\n select(id: string): void {\n if (this.destroyed) return\n const escaped = typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(id) : id.replace(/[\"\\\\]/g, '\\\\$&')\n const el = this.doc.querySelector<HTMLElement>(`[${BLOCK_ID_ATTR}=\"${escaped}\"]`)\n if (!el) {\n // Block not in DOM (yet) — keep id but hide the toolbar; a later\n // select(id) call after the iframe re-render will resolve it.\n this.currentBlockId = id\n this.currentBlockEl = null\n this.clearActive()\n this.toolbar.classList.remove('is-visible')\n return\n }\n this.currentBlockId = id\n this.currentBlockEl = el\n this.markActiveChain(el)\n const isNested = this.activeChain.length > 1\n this.toolbar.dataset.nested = isNested ? '1' : '0'\n this.toolbar.classList.add('is-visible')\n this.scheduleReposition()\n }\n\n deselect(): void {\n if (this.destroyed) return\n if (!this.currentBlockId) return\n this.clearActive()\n this.currentBlockId = null\n this.currentBlockEl = null\n this.toolbar.classList.remove('is-visible')\n }\n\n destroy(): void {\n if (this.destroyed) return\n this.destroyed = true\n this.observer.disconnect()\n const view = this.doc.defaultView\n view?.removeEventListener('scroll', this.onScroll, true)\n if (this.positionRaf) view?.cancelAnimationFrame(this.positionRaf)\n if (this.observerRaf) view?.cancelAnimationFrame(this.observerRaf)\n this.positionRaf = 0\n this.observerRaf = 0\n this.clearActive()\n this.currentBlockId = null\n this.currentBlockEl = null\n // Defer unmount — React 19 throws if it lands synchronously mid-render of\n // another tree; StrictMode also double-invokes us, so only remove the\n // toolbar node if we still own it.\n const { root, toolbar } = this\n queueMicrotask(() => {\n try { root.unmount() } catch { /* already unmounted */ }\n if (toolbar.isConnected) toolbar.remove()\n })\n }\n\n private scheduleReposition(): void {\n const view = this.doc.defaultView\n if (!view) {\n this.positionToolbar()\n return\n }\n if (this.positionRaf) view.cancelAnimationFrame(this.positionRaf)\n this.positionRaf = view.requestAnimationFrame(() => {\n this.positionRaf = 0\n this.positionToolbar()\n })\n }\n\n private positionToolbar(): void {\n const el = this.currentBlockEl\n if (!el || !el.isConnected) return\n const view = this.doc.defaultView\n if (!view) return\n const { top, left } = calculateToolbarPosition(\n el.getBoundingClientRect(),\n {\n width: this.toolbar.offsetWidth || FALLBACK_TB_WIDTH,\n height: this.toolbar.offsetHeight || FALLBACK_TB_HEIGHT,\n },\n { scrollX: view.scrollX, scrollY: view.scrollY },\n this.opts.position,\n this.opts.outlineWidth,\n )\n const { style } = this.toolbar\n style.top = `${top}px`\n style.left = `${left}px`\n style.right = 'auto'\n }\n\n // Only clears the chain we marked, avoiding a full-document scan.\n private clearActive(): void {\n for (const node of this.activeChain) node.classList.remove(ACTIVE_CLASS)\n this.activeChain = []\n }\n\n private markActiveChain(el: HTMLElement): void {\n this.clearActive()\n const chain: HTMLElement[] = []\n for (\n let cur: HTMLElement | null = el;\n cur;\n cur = cur.parentElement?.closest<HTMLElement>(BLOCK_ID_SELECTOR) ?? null\n ) {\n cur.classList.add(ACTIVE_CLASS)\n chain.push(cur)\n }\n this.activeChain = chain\n }\n}\n"],"names":["React","createRoot","ACTIVE_CLASS","BLOCK_ID_ATTR","BLOCK_ID_SELECTOR","TOOLBAR_ID","HoverToolbar","calculateToolbarPosition","toHoverToolbarLabels","actions","moveUp","moveDown","duplicate","addBelow","delete","FALLBACK_TB_WIDTH","FALLBACK_TB_HEIGHT","HoverToolbarController","doc","opts","toolbar","root","destroyed","currentBlockId","currentBlockEl","activeChain","positionRaf","observerRaf","onScroll","observer","constructor","getElementById","remove","createElement","id","body","appendChild","renderToolbar","scheduleReposition","defaultView","addEventListener","MutationObserver","scheduleReselect","observe","childList","subtree","view","requestAnimationFrame","select","update","render","labels","onAction","action","escaped","CSS","escape","replace","el","querySelector","clearActive","classList","markActiveChain","isNested","length","dataset","nested","add","deselect","destroy","disconnect","removeEventListener","cancelAnimationFrame","queueMicrotask","unmount","isConnected","positionToolbar","top","left","getBoundingClientRect","width","offsetWidth","height","offsetHeight","scrollX","scrollY","position","outlineWidth","style","right","node","chain","cur","parentElement","closest","push"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Blocks tab — header (kicker / heading /
|
|
1
|
+
/* Blocks tab — header (kicker / heading / Deselect),
|
|
2
2
|
action toolbar, dividers, Block Name input, empty-state CTA. */
|
|
3
3
|
|
|
4
4
|
.better-editor-tab__header {
|
|
@@ -24,12 +24,6 @@
|
|
|
24
24
|
line-height: 1.2;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
.better-editor-tab__path {
|
|
28
|
-
font-family: var(--font-mono, ui-monospace, monospace);
|
|
29
|
-
font-size: 11px;
|
|
30
|
-
color: var(--theme-elevation-500);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
27
|
.better-editor-tab__clear {
|
|
34
28
|
flex-shrink: 0;
|
|
35
29
|
padding: 6px 10px;
|
package/dist/styles/overlay.css
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
inset: 0;
|
|
7
7
|
z-index: var(--better-editor-z-overlay, 50);
|
|
8
8
|
background: var(--theme-bg, #fff);
|
|
9
|
+
border-top: 1px solid var(--theme-elevation-100);
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
/* While fullscreen the overlay covers the whole screen via the
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
.better-editor__resize-handle {
|
|
32
33
|
cursor: col-resize;
|
|
33
34
|
background: transparent;
|
|
35
|
+
border-left: 1px solid var(--theme-elevation-100);
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
.better-editor__resize-handle:hover,
|
package/dist/styles/sidebar.css
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* Editor toggle button — visible label + open-state emphasis layered on top
|
|
2
|
+
of Payload's own .preview-btn. */
|
|
3
|
+
|
|
4
|
+
.better-editor-toggle {
|
|
5
|
+
width: auto;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.better-editor-toggle[aria-pressed='true'] {
|
|
9
|
+
border-color: var(--theme-elevation-300);
|
|
10
|
+
background-color: var(--theme-elevation-100);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.better-editor-toggle__label {
|
|
14
|
+
display: inline-block;
|
|
15
|
+
margin-right: 0.5em;
|
|
16
|
+
color: var(--theme-elevation-700);
|
|
17
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -46,4 +46,10 @@ export type BetterEditorConfig = {
|
|
|
46
46
|
* hide it for end users. Defaults to `true`.
|
|
47
47
|
*/
|
|
48
48
|
showSettingsBanner?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Hide the "Open/Close Better Editor" text next to the toggle button's icon,
|
|
51
|
+
* leaving an icon-only button. The accessible label (`aria-label`/`title`)
|
|
52
|
+
* is kept either way. Defaults to `false` (label shown).
|
|
53
|
+
*/
|
|
54
|
+
hideToggleLabel?: boolean;
|
|
49
55
|
};
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { CollectionSlug, GlobalSlug } from 'payload'\n\n/** Per-entity overrides for a collection/global. */\nexport type BetterEditorEntityOptions = {\n /** Blocks-field name for this entity; falls back to the top-level `blocksField`. */\n blocksField?: string\n}\n\nexport type BetterEditorConfig = {\n /** Skip plugin installation entirely (e.g. behind a feature flag). */\n disabled?: boolean\n /**\n * Collections that get the \"Open Better Editor\" toggle. Either a list of\n * slugs, or a slug → options record for per-collection settings (e.g. a\n * different `blocksField`). Each collection needs `admin.preview` configured\n * for the preview to render and the toggle to appear.\n */\n collections?: string[] | Partial<Record<CollectionSlug, BetterEditorEntityOptions>>\n /**\n * Globals that get the \"Open Better Editor\" toggle — a list of slugs or a\n * slug → options record. Each global needs `admin.preview` configured for the\n * toggle to appear.\n */\n globals?: string[] | Partial<Record<GlobalSlug, BetterEditorEntityOptions>>\n /**\n * Default name of the `blocks` field the sidebar targets. Top-level only;\n * nested paths (e.g. `content.layout`) are not supported. Per-collection\n * overrides via the `collections`/`globals` record take precedence.\n * Defaults to `'layout'`.\n */\n blocksField?: string\n /**\n * CSS selector for the Payload admin element the overlay portals into.\n * Override only if the default selector breaks against a future Payload\n * version. The plugin falls back to `<main>` and finally `<body>`.\n */\n adminPortalSelector?: string\n /**\n * Prefix for all `localStorage` keys the editor writes (sidebar width,\n * responsive viewport width, …). Set this if multiple Better Editor\n * instances share the same origin and would otherwise collide.\n * Defaults to `'better-editor'`.\n */\n storageNamespace?: string\n /**\n * Show the plugin info banner (version, GitHub links, \"Report a bug\")\n * at the top of the `BetterEditorSettings` global. Set to `false` to\n * hide it for end users. Defaults to `true`.\n */\n showSettingsBanner?: boolean\n}\n"],"names":[],"mappings":"AAQA,
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { CollectionSlug, GlobalSlug } from 'payload'\n\n/** Per-entity overrides for a collection/global. */\nexport type BetterEditorEntityOptions = {\n /** Blocks-field name for this entity; falls back to the top-level `blocksField`. */\n blocksField?: string\n}\n\nexport type BetterEditorConfig = {\n /** Skip plugin installation entirely (e.g. behind a feature flag). */\n disabled?: boolean\n /**\n * Collections that get the \"Open Better Editor\" toggle. Either a list of\n * slugs, or a slug → options record for per-collection settings (e.g. a\n * different `blocksField`). Each collection needs `admin.preview` configured\n * for the preview to render and the toggle to appear.\n */\n collections?: string[] | Partial<Record<CollectionSlug, BetterEditorEntityOptions>>\n /**\n * Globals that get the \"Open Better Editor\" toggle — a list of slugs or a\n * slug → options record. Each global needs `admin.preview` configured for the\n * toggle to appear.\n */\n globals?: string[] | Partial<Record<GlobalSlug, BetterEditorEntityOptions>>\n /**\n * Default name of the `blocks` field the sidebar targets. Top-level only;\n * nested paths (e.g. `content.layout`) are not supported. Per-collection\n * overrides via the `collections`/`globals` record take precedence.\n * Defaults to `'layout'`.\n */\n blocksField?: string\n /**\n * CSS selector for the Payload admin element the overlay portals into.\n * Override only if the default selector breaks against a future Payload\n * version. The plugin falls back to `<main>` and finally `<body>`.\n */\n adminPortalSelector?: string\n /**\n * Prefix for all `localStorage` keys the editor writes (sidebar width,\n * responsive viewport width, …). Set this if multiple Better Editor\n * instances share the same origin and would otherwise collide.\n * Defaults to `'better-editor'`.\n */\n storageNamespace?: string\n /**\n * Show the plugin info banner (version, GitHub links, \"Report a bug\")\n * at the top of the `BetterEditorSettings` global. Set to `false` to\n * hide it for end users. Defaults to `true`.\n */\n showSettingsBanner?: boolean\n /**\n * Hide the \"Open/Close Better Editor\" text next to the toggle button's icon,\n * leaving an icon-only button. The accessible label (`aria-label`/`title`)\n * is kept either way. Defaults to `false` (label shown).\n */\n hideToggleLabel?: boolean\n}\n"],"names":[],"mappings":"AAQA,WAgDC"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "1.
|
|
1
|
+
export declare const VERSION = "1.3.0";
|
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// Package version, re-exported as VERSION; read by the settings banner without\n// pulling the server entry into the client bundle.\nexport const VERSION = '1.
|
|
1
|
+
{"version":3,"sources":["../src/version.ts"],"sourcesContent":["// Package version, re-exported as VERSION; read by the settings banner without\n// pulling the server entry into the client bundle.\nexport const VERSION = '1.3.0'\n"],"names":["VERSION"],"mappings":"AAAA,+EAA+E;AAC/E,mDAAmD;AACnD,OAAO,MAAMA,UAAU,QAAO"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payload-better-editor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Block editor plugin for Payload CMS that adds a side-by-side live-preview iframe and sidebar to the edit view.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "scorpio-99",
|
|
@@ -52,18 +52,6 @@
|
|
|
52
52
|
"files": [
|
|
53
53
|
"dist"
|
|
54
54
|
],
|
|
55
|
-
"scripts": {
|
|
56
|
-
"build": "pnpm copyfiles && pnpm build:types && pnpm build:swc",
|
|
57
|
-
"build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
|
|
58
|
-
"build:types": "tsc --outDir dist --rootDir ./src",
|
|
59
|
-
"clean": "rimraf dist *.tsbuildinfo",
|
|
60
|
-
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
|
|
61
|
-
"lint": "eslint ./src",
|
|
62
|
-
"lint:fix": "eslint ./src --fix",
|
|
63
|
-
"test": "vitest run",
|
|
64
|
-
"test:watch": "vitest",
|
|
65
|
-
"prepublishOnly": "pnpm clean && pnpm build"
|
|
66
|
-
},
|
|
67
55
|
"peerDependencies": {
|
|
68
56
|
"payload": ">=3.81.0",
|
|
69
57
|
"react": "^19.0.0",
|
|
@@ -98,5 +86,16 @@
|
|
|
98
86
|
"publishConfig": {
|
|
99
87
|
"access": "public",
|
|
100
88
|
"registry": "https://registry.npmjs.org/"
|
|
89
|
+
},
|
|
90
|
+
"scripts": {
|
|
91
|
+
"build": "pnpm copyfiles && pnpm build:types && pnpm build:swc",
|
|
92
|
+
"build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
|
|
93
|
+
"build:types": "tsc --outDir dist --rootDir ./src",
|
|
94
|
+
"clean": "rimraf dist *.tsbuildinfo",
|
|
95
|
+
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
|
|
96
|
+
"lint": "eslint ./src",
|
|
97
|
+
"lint:fix": "eslint ./src --fix",
|
|
98
|
+
"test": "vitest run",
|
|
99
|
+
"test:watch": "vitest"
|
|
101
100
|
}
|
|
102
|
-
}
|
|
101
|
+
}
|