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.
Files changed (77) hide show
  1. package/dist/admin/ErrorBoundary.d.ts +1 -10
  2. package/dist/admin/ErrorBoundary.js +14 -5
  3. package/dist/admin/ErrorBoundary.js.map +1 -1
  4. package/dist/admin/LiveEditorOverlay.js +4 -2
  5. package/dist/admin/LiveEditorOverlay.js.map +1 -1
  6. package/dist/admin/LiveEditorToggle.d.ts +2 -0
  7. package/dist/admin/LiveEditorToggle.js +14 -9
  8. package/dist/admin/LiveEditorToggle.js.map +1 -1
  9. package/dist/admin/PreviewFrame.js +6 -4
  10. package/dist/admin/PreviewFrame.js.map +1 -1
  11. package/dist/admin/PreviewToolbar.js +20 -13
  12. package/dist/admin/PreviewToolbar.js.map +1 -1
  13. package/dist/admin/SettingsBanner.js +10 -5
  14. package/dist/admin/SettingsBanner.js.map +1 -1
  15. package/dist/admin/ViewportToggle.js +30 -25
  16. package/dist/admin/ViewportToggle.js.map +1 -1
  17. package/dist/admin/blocks/AddBlockDrawer.js +7 -3
  18. package/dist/admin/blocks/AddBlockDrawer.js.map +1 -1
  19. package/dist/admin/blocks/BlockActionsToolbar.js +13 -11
  20. package/dist/admin/blocks/BlockActionsToolbar.js.map +1 -1
  21. package/dist/admin/blocks/BlockEmptyState.js +7 -3
  22. package/dist/admin/blocks/BlockEmptyState.js.map +1 -1
  23. package/dist/admin/blocks/BlockHeader.d.ts +1 -0
  24. package/dist/admin/blocks/BlockHeader.js +9 -8
  25. package/dist/admin/blocks/BlockHeader.js.map +1 -1
  26. package/dist/admin/blocks/schema.js +38 -7
  27. package/dist/admin/blocks/schema.js.map +1 -1
  28. package/dist/admin/sidebar/BlockSettingsTab.js +19 -4
  29. package/dist/admin/sidebar/BlockSettingsTab.js.map +1 -1
  30. package/dist/admin/sidebar/DocumentMetaTab.js +6 -2
  31. package/dist/admin/sidebar/DocumentMetaTab.js.map +1 -1
  32. package/dist/admin/sidebar/DocumentSettingsTab.js +6 -2
  33. package/dist/admin/sidebar/DocumentSettingsTab.js.map +1 -1
  34. package/dist/admin/sidebar/Sidebar.js +21 -16
  35. package/dist/admin/sidebar/Sidebar.js.map +1 -1
  36. package/dist/admin/sidebar/ValidationSummary.js +5 -2
  37. package/dist/admin/sidebar/ValidationSummary.js.map +1 -1
  38. package/dist/global.js +55 -39
  39. package/dist/global.js.map +1 -1
  40. package/dist/hooks/usePreviewBinding.js +6 -2
  41. package/dist/hooks/usePreviewBinding.js.map +1 -1
  42. package/dist/hooks/usePreviewSettingsSync.js +8 -3
  43. package/dist/hooks/usePreviewSettingsSync.js.map +1 -1
  44. package/dist/i18n/de.d.ts +2 -0
  45. package/dist/i18n/de.js +135 -0
  46. package/dist/i18n/de.js.map +1 -0
  47. package/dist/i18n/en.d.ts +2 -0
  48. package/dist/i18n/en.js +135 -0
  49. package/dist/i18n/en.js.map +1 -0
  50. package/dist/i18n/merge.d.ts +8 -0
  51. package/dist/i18n/merge.js +22 -0
  52. package/dist/i18n/merge.js.map +1 -0
  53. package/dist/i18n/types.d.ts +133 -0
  54. package/dist/i18n/types.js +3 -0
  55. package/dist/i18n/types.js.map +1 -0
  56. package/dist/i18n/useBetterEditorT.d.ts +2 -0
  57. package/dist/i18n/useBetterEditorT.js +10 -0
  58. package/dist/i18n/useBetterEditorT.js.map +1 -0
  59. package/dist/index.d.ts +2 -1
  60. package/dist/index.js +21 -2
  61. package/dist/index.js.map +1 -1
  62. package/dist/preview/HoverToolbar.d.ts +8 -0
  63. package/dist/preview/HoverToolbar.js +31 -29
  64. package/dist/preview/HoverToolbar.js.map +1 -1
  65. package/dist/preview/HoverToolbarController.d.ts +6 -0
  66. package/dist/preview/HoverToolbarController.js +20 -5
  67. package/dist/preview/HoverToolbarController.js.map +1 -1
  68. package/dist/styles/blocks-tab.css +1 -7
  69. package/dist/styles/overlay.css +2 -0
  70. package/dist/styles/sidebar.css +1 -0
  71. package/dist/styles/toggle.css +17 -0
  72. package/dist/types.d.ts +6 -0
  73. package/dist/types.js.map +1 -1
  74. package/dist/version.d.ts +1 -1
  75. package/dist/version.js +1 -1
  76. package/dist/version.js.map +1 -1
  77. package/package.json +13 -14
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/sidebar/BlockSettingsTab.tsx"],"sourcesContent":["'use client'\n\nimport React, { useMemo } from 'react'\nimport {\n RenderFields,\n useAllFormFields,\n useConfig,\n useDrawerSlug,\n useField,\n useModal,\n} from '@payloadcms/ui'\nimport { useDocConfig } from '../../hooks/useDocConfig'\nimport { useAddBlockDrawer } from '../../hooks/useAddBlockDrawer'\nimport { AddBlockDrawer } from '../blocks/AddBlockDrawer'\nimport { BlockActionsToolbar } from '../blocks/BlockActionsToolbar'\nimport { useBlockActions } from '../blocks/useBlockActions'\nimport { findNamedField, resolveBlockSchema, resolveFieldBlocks } from '../blocks/schema'\nimport type { ClientBlock } from 'payload'\nimport { BlockEmptyState } from '../blocks/BlockEmptyState'\nimport { BlockHeader } from '../blocks/BlockHeader'\n\nexport type BlockSettingsTabProps = {\n selectedBlockPath: string | null\n onClearSelection: () => void\n onSelectPath: (path: string | null) => void\n blocksField: string\n /** Bump to open the add-after drawer externally (iframe `+` button). */\n addBelowRequestId?: number\n}\n\nexport const BlockSettingsTab: React.FC<BlockSettingsTabProps> = ({\n selectedBlockPath,\n onClearSelection,\n onSelectPath,\n blocksField,\n addBelowRequestId = 0,\n}) => {\n const { fields: docFields, slug: docSlug } = useDocConfig()\n const [fields] = useAllFormFields()\n const { config } = useConfig()\n const blocksMap = config.blocksMap\n const { toggleModal } = useModal()\n const addBlockDrawerSlug = useDrawerSlug('better-editor-add-block')\n const addAfterDrawerSlug = useDrawerSlug('better-editor-add-after')\n\n const actions = useBlockActions({\n selectedBlockPath,\n onSelectPath,\n onClearSelection,\n })\n\n useAddBlockDrawer({\n drawerSlug: addAfterDrawerSlug,\n requestId: addBelowRequestId,\n selectedBlockPath,\n })\n\n const blocksFieldInfo = useMemo(() => {\n if (!docFields) return null\n return findNamedField(docFields, blocksField, docSlug || '')\n }, [docFields, blocksField, docSlug])\n\n const blocksFieldField = blocksFieldInfo?.field\n const availableBlocks: ClientBlock[] =\n blocksFieldField && blocksFieldField.type === 'blocks'\n ? resolveFieldBlocks(blocksFieldField, blocksMap)\n : []\n const blocksSchemaPath = blocksFieldInfo?.schemaPath || ''\n const topLevelRows = fields[blocksField]?.rows\n const addRowIndex = Array.isArray(topLevelRows) ? topLevelRows.length : 0\n\n if (!selectedBlockPath) {\n return (\n <>\n <BlockEmptyState\n canAdd={availableBlocks.length > 0}\n onAddClick={() => toggleModal(addBlockDrawerSlug)}\n />\n {availableBlocks.length > 0 ? (\n <AddBlockDrawer\n slug={addBlockDrawerSlug}\n blocks={availableBlocks}\n addRow={(index, blockType) =>\n actions.addAfter({\n blockType,\n schemaPath: blocksSchemaPath,\n containerPath: blocksField,\n index,\n })\n }\n addRowIndex={addRowIndex}\n />\n ) : null}\n </>\n )\n }\n\n const resolved = docFields\n ? resolveBlockSchema(\n { docFields, docSlug: docSlug || '', formFields: fields, blocksMap },\n selectedBlockPath,\n )\n : null\n\n return (\n <div className=\"better-editor-tab better-editor-tab--native\">\n <BlockHeader\n blockType={resolved?.blockType || 'unknown'}\n path={selectedBlockPath}\n onClearSelection={onClearSelection}\n />\n\n <hr className=\"better-editor-tab__divider\" aria-hidden=\"true\" />\n\n <BlockActionsToolbar\n canMoveUp={actions.canMoveUp}\n canMoveDown={actions.canMoveDown}\n canMutate={actions.canMutate}\n canAddBelow={!!resolved}\n onMoveUp={actions.moveUp}\n onMoveDown={actions.moveDown}\n onDuplicate={actions.duplicate}\n onAddBelow={() => toggleModal(addAfterDrawerSlug)}\n onDelete={actions.remove}\n />\n\n {actions.canMutate && resolved && resolved.blocksFieldBlocks.length > 0 ? (\n <AddBlockDrawer\n slug={addAfterDrawerSlug}\n blocks={resolved.blocksFieldBlocks}\n addRow={(index, blockType) =>\n actions.addAfter({\n blockType,\n schemaPath: resolved.blocksFieldSchemaPath,\n containerPath: actions.parentPath,\n index,\n })\n }\n addRowIndex={actions.rowIndex + 1}\n />\n ) : null}\n\n {!resolved ? (\n <div className=\"better-editor-tab__empty\">\n Could not resolve block schema for this path.\n </div>\n ) : (\n <>\n <BlockNameInput path={`${selectedBlockPath}.blockName`} />\n <hr className=\"better-editor-tab__divider\" aria-hidden=\"true\" />\n <RenderFields\n fields={resolved.blockFields}\n parentPath={resolved.parentPath}\n parentIndexPath=\"\"\n parentSchemaPath={resolved.schemaPath}\n // RenderFields' client read-gate is bypassed; the server-side\n // write check still runs on save.\n permissions={true}\n />\n </>\n )}\n </div>\n )\n}\n\nconst BlockNameInput: React.FC<{ path: string }> = ({ path }) => {\n const { value, setValue } = useField<string>({ path })\n const inputId = `be-blockname-${path}`\n return (\n <div className=\"better-editor-tab__block-name\">\n <label className=\"better-editor-tab__block-name-label\" htmlFor={inputId}>\n Block Name\n </label>\n <input\n id={inputId}\n className=\"better-editor-tab__block-name-input\"\n type=\"text\"\n value={value || ''}\n onChange={(e) => setValue(e.target.value)}\n placeholder=\"Optional label for this block\"\n />\n </div>\n )\n}\n"],"names":["React","useMemo","RenderFields","useAllFormFields","useConfig","useDrawerSlug","useField","useModal","useDocConfig","useAddBlockDrawer","AddBlockDrawer","BlockActionsToolbar","useBlockActions","findNamedField","resolveBlockSchema","resolveFieldBlocks","BlockEmptyState","BlockHeader","BlockSettingsTab","selectedBlockPath","onClearSelection","onSelectPath","blocksField","addBelowRequestId","fields","docFields","slug","docSlug","config","blocksMap","toggleModal","addBlockDrawerSlug","addAfterDrawerSlug","actions","drawerSlug","requestId","blocksFieldInfo","blocksFieldField","field","availableBlocks","type","blocksSchemaPath","schemaPath","topLevelRows","rows","addRowIndex","Array","isArray","length","canAdd","onAddClick","blocks","addRow","index","blockType","addAfter","containerPath","resolved","formFields","div","className","path","hr","aria-hidden","canMoveUp","canMoveDown","canMutate","canAddBelow","onMoveUp","moveUp","onMoveDown","moveDown","onDuplicate","duplicate","onAddBelow","onDelete","remove","blocksFieldBlocks","blocksFieldSchemaPath","parentPath","rowIndex","BlockNameInput","blockFields","parentIndexPath","parentSchemaPath","permissions","value","setValue","inputId","label","htmlFor","input","id","onChange","e","target","placeholder"],"mappings":"AAAA;;AAEA,OAAOA,SAASC,OAAO,QAAQ,QAAO;AACtC,SACEC,YAAY,EACZC,gBAAgB,EAChBC,SAAS,EACTC,aAAa,EACbC,QAAQ,EACRC,QAAQ,QACH,iBAAgB;AACvB,SAASC,YAAY,QAAQ,2BAA0B;AACvD,SAASC,iBAAiB,QAAQ,gCAA+B;AACjE,SAASC,cAAc,QAAQ,2BAA0B;AACzD,SAASC,mBAAmB,QAAQ,gCAA+B;AACnE,SAASC,eAAe,QAAQ,4BAA2B;AAC3D,SAASC,cAAc,EAAEC,kBAAkB,EAAEC,kBAAkB,QAAQ,mBAAkB;AAEzF,SAASC,eAAe,QAAQ,4BAA2B;AAC3D,SAASC,WAAW,QAAQ,wBAAuB;AAWnD,OAAO,MAAMC,mBAAoD,CAAC,EAChEC,iBAAiB,EACjBC,gBAAgB,EAChBC,YAAY,EACZC,WAAW,EACXC,oBAAoB,CAAC,EACtB;IACC,MAAM,EAAEC,QAAQC,SAAS,EAAEC,MAAMC,OAAO,EAAE,GAAGnB;IAC7C,MAAM,CAACgB,OAAO,GAAGrB;IACjB,MAAM,EAAEyB,MAAM,EAAE,GAAGxB;IACnB,MAAMyB,YAAYD,OAAOC,SAAS;IAClC,MAAM,EAAEC,WAAW,EAAE,GAAGvB;IACxB,MAAMwB,qBAAqB1B,cAAc;IACzC,MAAM2B,qBAAqB3B,cAAc;IAEzC,MAAM4B,UAAUrB,gBAAgB;QAC9BO;QACAE;QACAD;IACF;IAEAX,kBAAkB;QAChByB,YAAYF;QACZG,WAAWZ;QACXJ;IACF;IAEA,MAAMiB,kBAAkBnC,QAAQ;QAC9B,IAAI,CAACwB,WAAW,OAAO;QACvB,OAAOZ,eAAeY,WAAWH,aAAaK,WAAW;IAC3D,GAAG;QAACF;QAAWH;QAAaK;KAAQ;IAEpC,MAAMU,mBAAmBD,iBAAiBE;IAC1C,MAAMC,kBACJF,oBAAoBA,iBAAiBG,IAAI,KAAK,WAC1CzB,mBAAmBsB,kBAAkBR,aACrC,EAAE;IACR,MAAMY,mBAAmBL,iBAAiBM,cAAc;IACxD,MAAMC,eAAenB,MAAM,CAACF,YAAY,EAAEsB;IAC1C,MAAMC,cAAcC,MAAMC,OAAO,CAACJ,gBAAgBA,aAAaK,MAAM,GAAG;IAExE,IAAI,CAAC7B,mBAAmB;QACtB,qBACE;;8BACE,KAACH;oBACCiC,QAAQV,gBAAgBS,MAAM,GAAG;oBACjCE,YAAY,IAAMpB,YAAYC;;gBAE/BQ,gBAAgBS,MAAM,GAAG,kBACxB,KAACtC;oBACCgB,MAAMK;oBACNoB,QAAQZ;oBACRa,QAAQ,CAACC,OAAOC,YACdrB,QAAQsB,QAAQ,CAAC;4BACfD;4BACAZ,YAAYD;4BACZe,eAAelC;4BACf+B;wBACF;oBAEFR,aAAaA;qBAEb;;;IAGV;IAEA,MAAMY,WAAWhC,YACbX,mBACE;QAAEW;QAAWE,SAASA,WAAW;QAAI+B,YAAYlC;QAAQK;IAAU,GACnEV,qBAEF;IAEJ,qBACE,MAACwC;QAAIC,WAAU;;0BACb,KAAC3C;gBACCqC,WAAWG,UAAUH,aAAa;gBAClCO,MAAM1C;gBACNC,kBAAkBA;;0BAGpB,KAAC0C;gBAAGF,WAAU;gBAA6BG,eAAY;;0BAEvD,KAACpD;gBACCqD,WAAW/B,QAAQ+B,SAAS;gBAC5BC,aAAahC,QAAQgC,WAAW;gBAChCC,WAAWjC,QAAQiC,SAAS;gBAC5BC,aAAa,CAAC,CAACV;gBACfW,UAAUnC,QAAQoC,MAAM;gBACxBC,YAAYrC,QAAQsC,QAAQ;gBAC5BC,aAAavC,QAAQwC,SAAS;gBAC9BC,YAAY,IAAM5C,YAAYE;gBAC9B2C,UAAU1C,QAAQ2C,MAAM;;YAGzB3C,QAAQiC,SAAS,IAAIT,YAAYA,SAASoB,iBAAiB,CAAC7B,MAAM,GAAG,kBACpE,KAACtC;gBACCgB,MAAMM;gBACNmB,QAAQM,SAASoB,iBAAiB;gBAClCzB,QAAQ,CAACC,OAAOC,YACdrB,QAAQsB,QAAQ,CAAC;wBACfD;wBACAZ,YAAYe,SAASqB,qBAAqB;wBAC1CtB,eAAevB,QAAQ8C,UAAU;wBACjC1B;oBACF;gBAEFR,aAAaZ,QAAQ+C,QAAQ,GAAG;iBAEhC;YAEH,CAACvB,yBACA,KAACE;gBAAIC,WAAU;0BAA2B;+BAI1C;;kCACE,KAACqB;wBAAepB,MAAM,GAAG1C,kBAAkB,UAAU,CAAC;;kCACtD,KAAC2C;wBAAGF,WAAU;wBAA6BG,eAAY;;kCACvD,KAAC7D;wBACCsB,QAAQiC,SAASyB,WAAW;wBAC5BH,YAAYtB,SAASsB,UAAU;wBAC/BI,iBAAgB;wBAChBC,kBAAkB3B,SAASf,UAAU;wBACrC,8DAA8D;wBAC9D,kCAAkC;wBAClC2C,aAAa;;;;;;AAMzB,EAAC;AAED,MAAMJ,iBAA6C,CAAC,EAAEpB,IAAI,EAAE;IAC1D,MAAM,EAAEyB,KAAK,EAAEC,QAAQ,EAAE,GAAGjF,SAAiB;QAAEuD;IAAK;IACpD,MAAM2B,UAAU,CAAC,aAAa,EAAE3B,MAAM;IACtC,qBACE,MAACF;QAAIC,WAAU;;0BACb,KAAC6B;gBAAM7B,WAAU;gBAAsC8B,SAASF;0BAAS;;0BAGzE,KAACG;gBACCC,IAAIJ;gBACJ5B,WAAU;gBACVpB,MAAK;gBACL8C,OAAOA,SAAS;gBAChBO,UAAU,CAACC,IAAMP,SAASO,EAAEC,MAAM,CAACT,KAAK;gBACxCU,aAAY;;;;AAIpB"}
1
+ {"version":3,"sources":["../../../src/admin/sidebar/BlockSettingsTab.tsx"],"sourcesContent":["'use client'\n\nimport React, { useMemo } from 'react'\nimport {\n RenderFields,\n useAllFormFields,\n useConfig,\n useDrawerSlug,\n useField,\n useModal,\n useTranslation,\n} from '@payloadcms/ui'\nimport { useDocConfig } from '../../hooks/useDocConfig'\nimport { useAddBlockDrawer } from '../../hooks/useAddBlockDrawer'\nimport { AddBlockDrawer } from '../blocks/AddBlockDrawer'\nimport { BlockActionsToolbar } from '../blocks/BlockActionsToolbar'\nimport { useBlockActions } from '../blocks/useBlockActions'\nimport { findNamedField, resolveBlockSchema, resolveFieldBlocks } from '../blocks/schema'\nimport type { ClientBlock } from 'payload'\nimport { BlockEmptyState } from '../blocks/BlockEmptyState'\nimport { BlockHeader } from '../blocks/BlockHeader'\nimport { useBetterEditorT } from '../../i18n/useBetterEditorT'\n\nexport type BlockSettingsTabProps = {\n selectedBlockPath: string | null\n onClearSelection: () => void\n onSelectPath: (path: string | null) => void\n blocksField: string\n /** Bump to open the add-after drawer externally (iframe `+` button). */\n addBelowRequestId?: number\n}\n\nexport const BlockSettingsTab: React.FC<BlockSettingsTabProps> = ({\n selectedBlockPath,\n onClearSelection,\n onSelectPath,\n blocksField,\n addBelowRequestId = 0,\n}) => {\n const t = useBetterEditorT()\n const { i18n } = useTranslation()\n const { fields: docFields, slug: docSlug } = useDocConfig()\n const [fields] = useAllFormFields()\n const { config } = useConfig()\n const blocksMap = config.blocksMap\n const { toggleModal } = useModal()\n const addBlockDrawerSlug = useDrawerSlug('better-editor-add-block')\n const addAfterDrawerSlug = useDrawerSlug('better-editor-add-after')\n\n const actions = useBlockActions({\n selectedBlockPath,\n onSelectPath,\n onClearSelection,\n })\n\n useAddBlockDrawer({\n drawerSlug: addAfterDrawerSlug,\n requestId: addBelowRequestId,\n selectedBlockPath,\n })\n\n const blocksFieldInfo = useMemo(() => {\n if (!docFields) return null\n return findNamedField(docFields, blocksField, docSlug || '')\n }, [docFields, blocksField, docSlug])\n\n const blocksFieldField = blocksFieldInfo?.field\n const availableBlocks: ClientBlock[] =\n blocksFieldField && blocksFieldField.type === 'blocks'\n ? resolveFieldBlocks(blocksFieldField, blocksMap)\n : []\n const blocksSchemaPath = blocksFieldInfo?.schemaPath || ''\n const topLevelRows = fields[blocksField]?.rows\n const addRowIndex = Array.isArray(topLevelRows) ? topLevelRows.length : 0\n\n if (!selectedBlockPath) {\n return (\n <>\n <BlockEmptyState\n canAdd={availableBlocks.length > 0}\n onAddClick={() => toggleModal(addBlockDrawerSlug)}\n />\n {availableBlocks.length > 0 ? (\n <AddBlockDrawer\n slug={addBlockDrawerSlug}\n blocks={availableBlocks}\n addRow={(index, blockType) =>\n actions.addAfter({\n blockType,\n schemaPath: blocksSchemaPath,\n containerPath: blocksField,\n index,\n })\n }\n addRowIndex={addRowIndex}\n />\n ) : null}\n </>\n )\n }\n\n const resolved = docFields\n ? resolveBlockSchema(\n { docFields, docSlug: docSlug || '', formFields: fields, blocksMap },\n selectedBlockPath,\n )\n : null\n\n const blockLabel = (() => {\n if (!resolved) return undefined\n const cfg = resolved.blocksFieldBlocks.find((b) => b.slug === resolved.blockType)\n const singular = cfg?.labels?.singular\n if (typeof singular === 'string') return singular\n if (singular && typeof singular === 'object') {\n return (singular as Record<string, string>)[i18n.language] ?? Object.values(singular)[0] as string | undefined\n }\n return undefined\n })()\n\n return (\n <div className=\"better-editor-tab better-editor-tab--native\">\n <BlockHeader\n blockType={resolved?.blockType || 'unknown'}\n blockLabel={blockLabel}\n path={selectedBlockPath}\n onClearSelection={onClearSelection}\n />\n\n <hr className=\"better-editor-tab__divider\" aria-hidden=\"true\" />\n\n <BlockActionsToolbar\n canMoveUp={actions.canMoveUp}\n canMoveDown={actions.canMoveDown}\n canMutate={actions.canMutate}\n canAddBelow={!!resolved}\n onMoveUp={actions.moveUp}\n onMoveDown={actions.moveDown}\n onDuplicate={actions.duplicate}\n onAddBelow={() => toggleModal(addAfterDrawerSlug)}\n onDelete={actions.remove}\n />\n\n {actions.canMutate && resolved && resolved.blocksFieldBlocks.length > 0 ? (\n <AddBlockDrawer\n slug={addAfterDrawerSlug}\n blocks={resolved.blocksFieldBlocks}\n addRow={(index, blockType) =>\n actions.addAfter({\n blockType,\n schemaPath: resolved.blocksFieldSchemaPath,\n containerPath: actions.parentPath,\n index,\n })\n }\n addRowIndex={actions.rowIndex + 1}\n />\n ) : null}\n\n {!resolved ? (\n <div className=\"better-editor-tab__empty\">{t.blocks.schemaError}</div>\n ) : (\n <>\n <BlockNameInput path={`${selectedBlockPath}.blockName`} />\n <hr className=\"better-editor-tab__divider\" aria-hidden=\"true\" />\n <RenderFields\n fields={resolved.blockFields}\n parentPath={resolved.parentPath}\n parentIndexPath=\"\"\n parentSchemaPath={resolved.schemaPath}\n // RenderFields' client read-gate is bypassed; the server-side\n // write check still runs on save.\n permissions={true}\n />\n </>\n )}\n </div>\n )\n}\n\nconst BlockNameInput: React.FC<{ path: string }> = ({ path }) => {\n const { value, setValue } = useField<string>({ path })\n const t = useBetterEditorT()\n const inputId = `be-blockname-${path}`\n return (\n <div className=\"better-editor-tab__block-name\">\n <label className=\"better-editor-tab__block-name-label\" htmlFor={inputId}>\n {t.blocks.blockName}\n </label>\n <input\n id={inputId}\n className=\"better-editor-tab__block-name-input\"\n type=\"text\"\n value={value || ''}\n onChange={(e) => setValue(e.target.value)}\n placeholder={t.blocks.blockNamePlaceholder}\n />\n </div>\n )\n}\n"],"names":["React","useMemo","RenderFields","useAllFormFields","useConfig","useDrawerSlug","useField","useModal","useTranslation","useDocConfig","useAddBlockDrawer","AddBlockDrawer","BlockActionsToolbar","useBlockActions","findNamedField","resolveBlockSchema","resolveFieldBlocks","BlockEmptyState","BlockHeader","useBetterEditorT","BlockSettingsTab","selectedBlockPath","onClearSelection","onSelectPath","blocksField","addBelowRequestId","t","i18n","fields","docFields","slug","docSlug","config","blocksMap","toggleModal","addBlockDrawerSlug","addAfterDrawerSlug","actions","drawerSlug","requestId","blocksFieldInfo","blocksFieldField","field","availableBlocks","type","blocksSchemaPath","schemaPath","topLevelRows","rows","addRowIndex","Array","isArray","length","canAdd","onAddClick","blocks","addRow","index","blockType","addAfter","containerPath","resolved","formFields","blockLabel","undefined","cfg","blocksFieldBlocks","find","b","singular","labels","language","Object","values","div","className","path","hr","aria-hidden","canMoveUp","canMoveDown","canMutate","canAddBelow","onMoveUp","moveUp","onMoveDown","moveDown","onDuplicate","duplicate","onAddBelow","onDelete","remove","blocksFieldSchemaPath","parentPath","rowIndex","schemaError","BlockNameInput","blockFields","parentIndexPath","parentSchemaPath","permissions","value","setValue","inputId","label","htmlFor","blockName","input","id","onChange","e","target","placeholder","blockNamePlaceholder"],"mappings":"AAAA;;AAEA,OAAOA,SAASC,OAAO,QAAQ,QAAO;AACtC,SACEC,YAAY,EACZC,gBAAgB,EAChBC,SAAS,EACTC,aAAa,EACbC,QAAQ,EACRC,QAAQ,EACRC,cAAc,QACT,iBAAgB;AACvB,SAASC,YAAY,QAAQ,2BAA0B;AACvD,SAASC,iBAAiB,QAAQ,gCAA+B;AACjE,SAASC,cAAc,QAAQ,2BAA0B;AACzD,SAASC,mBAAmB,QAAQ,gCAA+B;AACnE,SAASC,eAAe,QAAQ,4BAA2B;AAC3D,SAASC,cAAc,EAAEC,kBAAkB,EAAEC,kBAAkB,QAAQ,mBAAkB;AAEzF,SAASC,eAAe,QAAQ,4BAA2B;AAC3D,SAASC,WAAW,QAAQ,wBAAuB;AACnD,SAASC,gBAAgB,QAAQ,8BAA6B;AAW9D,OAAO,MAAMC,mBAAoD,CAAC,EAChEC,iBAAiB,EACjBC,gBAAgB,EAChBC,YAAY,EACZC,WAAW,EACXC,oBAAoB,CAAC,EACtB;IACC,MAAMC,IAAIP;IACV,MAAM,EAAEQ,IAAI,EAAE,GAAGnB;IACjB,MAAM,EAAEoB,QAAQC,SAAS,EAAEC,MAAMC,OAAO,EAAE,GAAGtB;IAC7C,MAAM,CAACmB,OAAO,GAAGzB;IACjB,MAAM,EAAE6B,MAAM,EAAE,GAAG5B;IACnB,MAAM6B,YAAYD,OAAOC,SAAS;IAClC,MAAM,EAAEC,WAAW,EAAE,GAAG3B;IACxB,MAAM4B,qBAAqB9B,cAAc;IACzC,MAAM+B,qBAAqB/B,cAAc;IAEzC,MAAMgC,UAAUxB,gBAAgB;QAC9BQ;QACAE;QACAD;IACF;IAEAZ,kBAAkB;QAChB4B,YAAYF;QACZG,WAAWd;QACXJ;IACF;IAEA,MAAMmB,kBAAkBvC,QAAQ;QAC9B,IAAI,CAAC4B,WAAW,OAAO;QACvB,OAAOf,eAAee,WAAWL,aAAaO,WAAW;IAC3D,GAAG;QAACF;QAAWL;QAAaO;KAAQ;IAEpC,MAAMU,mBAAmBD,iBAAiBE;IAC1C,MAAMC,kBACJF,oBAAoBA,iBAAiBG,IAAI,KAAK,WAC1C5B,mBAAmByB,kBAAkBR,aACrC,EAAE;IACR,MAAMY,mBAAmBL,iBAAiBM,cAAc;IACxD,MAAMC,eAAenB,MAAM,CAACJ,YAAY,EAAEwB;IAC1C,MAAMC,cAAcC,MAAMC,OAAO,CAACJ,gBAAgBA,aAAaK,MAAM,GAAG;IAExE,IAAI,CAAC/B,mBAAmB;QACtB,qBACE;;8BACE,KAACJ;oBACCoC,QAAQV,gBAAgBS,MAAM,GAAG;oBACjCE,YAAY,IAAMpB,YAAYC;;gBAE/BQ,gBAAgBS,MAAM,GAAG,kBACxB,KAACzC;oBACCmB,MAAMK;oBACNoB,QAAQZ;oBACRa,QAAQ,CAACC,OAAOC,YACdrB,QAAQsB,QAAQ,CAAC;4BACfD;4BACAZ,YAAYD;4BACZe,eAAepC;4BACfiC;wBACF;oBAEFR,aAAaA;qBAEb;;;IAGV;IAEA,MAAMY,WAAWhC,YACbd,mBACE;QAAEc;QAAWE,SAASA,WAAW;QAAI+B,YAAYlC;QAAQK;IAAU,GACnEZ,qBAEF;IAEJ,MAAM0C,aAAa,AAAC,CAAA;QAClB,IAAI,CAACF,UAAU,OAAOG;QACtB,MAAMC,MAAMJ,SAASK,iBAAiB,CAACC,IAAI,CAAC,CAACC,IAAMA,EAAEtC,IAAI,KAAK+B,SAASH,SAAS;QAChF,MAAMW,WAAWJ,KAAKK,QAAQD;QAC9B,IAAI,OAAOA,aAAa,UAAU,OAAOA;QACzC,IAAIA,YAAY,OAAOA,aAAa,UAAU;YAC5C,OAAO,AAACA,QAAmC,CAAC1C,KAAK4C,QAAQ,CAAC,IAAIC,OAAOC,MAAM,CAACJ,SAAS,CAAC,EAAE;QAC1F;QACA,OAAOL;IACT,CAAA;IAEA,qBACE,MAACU;QAAIC,WAAU;;0BACb,KAACzD;gBACCwC,WAAWG,UAAUH,aAAa;gBAClCK,YAAYA;gBACZa,MAAMvD;gBACNC,kBAAkBA;;0BAGpB,KAACuD;gBAAGF,WAAU;gBAA6BG,eAAY;;0BAEvD,KAAClE;gBACCmE,WAAW1C,QAAQ0C,SAAS;gBAC5BC,aAAa3C,QAAQ2C,WAAW;gBAChCC,WAAW5C,QAAQ4C,SAAS;gBAC5BC,aAAa,CAAC,CAACrB;gBACfsB,UAAU9C,QAAQ+C,MAAM;gBACxBC,YAAYhD,QAAQiD,QAAQ;gBAC5BC,aAAalD,QAAQmD,SAAS;gBAC9BC,YAAY,IAAMvD,YAAYE;gBAC9BsD,UAAUrD,QAAQsD,MAAM;;YAGzBtD,QAAQ4C,SAAS,IAAIpB,YAAYA,SAASK,iBAAiB,CAACd,MAAM,GAAG,kBACpE,KAACzC;gBACCmB,MAAMM;gBACNmB,QAAQM,SAASK,iBAAiB;gBAClCV,QAAQ,CAACC,OAAOC,YACdrB,QAAQsB,QAAQ,CAAC;wBACfD;wBACAZ,YAAYe,SAAS+B,qBAAqB;wBAC1ChC,eAAevB,QAAQwD,UAAU;wBACjCpC;oBACF;gBAEFR,aAAaZ,QAAQyD,QAAQ,GAAG;iBAEhC;YAEH,CAACjC,yBACA,KAACa;gBAAIC,WAAU;0BAA4BjD,EAAE6B,MAAM,CAACwC,WAAW;+BAE/D;;kCACE,KAACC;wBAAepB,MAAM,GAAGvD,kBAAkB,UAAU,CAAC;;kCACtD,KAACwD;wBAAGF,WAAU;wBAA6BG,eAAY;;kCACvD,KAAC5E;wBACC0B,QAAQiC,SAASoC,WAAW;wBAC5BJ,YAAYhC,SAASgC,UAAU;wBAC/BK,iBAAgB;wBAChBC,kBAAkBtC,SAASf,UAAU;wBACrC,8DAA8D;wBAC9D,kCAAkC;wBAClCsD,aAAa;;;;;;AAMzB,EAAC;AAED,MAAMJ,iBAA6C,CAAC,EAAEpB,IAAI,EAAE;IAC1D,MAAM,EAAEyB,KAAK,EAAEC,QAAQ,EAAE,GAAGhG,SAAiB;QAAEsE;IAAK;IACpD,MAAMlD,IAAIP;IACV,MAAMoF,UAAU,CAAC,aAAa,EAAE3B,MAAM;IACtC,qBACE,MAACF;QAAIC,WAAU;;0BACb,KAAC6B;gBAAM7B,WAAU;gBAAsC8B,SAASF;0BAC7D7E,EAAE6B,MAAM,CAACmD,SAAS;;0BAErB,KAACC;gBACCC,IAAIL;gBACJ5B,WAAU;gBACV/B,MAAK;gBACLyD,OAAOA,SAAS;gBAChBQ,UAAU,CAACC,IAAMR,SAASQ,EAAEC,MAAM,CAACV,KAAK;gBACxCW,aAAatF,EAAE6B,MAAM,CAAC0D,oBAAoB;;;;AAIlD"}
@@ -2,10 +2,14 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import React from 'react';
4
4
  import { DocumentFieldsTab } from './DocumentFieldsTab';
5
+ import { useBetterEditorT } from '../../i18n/useBetterEditorT';
5
6
  const isSidebarField = (f)=>'admin' in f && f.admin?.position === 'sidebar';
6
- export const DocumentMetaTab = ()=>/*#__PURE__*/ _jsx(DocumentFieldsTab, {
7
+ export const DocumentMetaTab = ()=>{
8
+ const t = useBetterEditorT();
9
+ return /*#__PURE__*/ _jsx(DocumentFieldsTab, {
7
10
  filter: isSidebarField,
8
- emptyText: "No document settings."
11
+ emptyText: t.documentFields.noSettings
9
12
  });
13
+ };
10
14
 
11
15
  //# sourceMappingURL=DocumentMetaTab.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/sidebar/DocumentMetaTab.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\nimport type { ClientField } from 'payload'\nimport { DocumentFieldsTab } from './DocumentFieldsTab'\n\nconst isSidebarField = (f: ClientField): boolean =>\n 'admin' in f && f.admin?.position === 'sidebar'\n\nexport const DocumentMetaTab: React.FC = () => (\n <DocumentFieldsTab\n filter={isSidebarField}\n emptyText=\"No document settings.\"\n />\n)\n"],"names":["React","DocumentFieldsTab","isSidebarField","f","admin","position","DocumentMetaTab","filter","emptyText"],"mappings":"AAAA;;AAEA,OAAOA,WAAW,QAAO;AAEzB,SAASC,iBAAiB,QAAQ,sBAAqB;AAEvD,MAAMC,iBAAiB,CAACC,IACtB,WAAWA,KAAKA,EAAEC,KAAK,EAAEC,aAAa;AAExC,OAAO,MAAMC,kBAA4B,kBACvC,KAACL;QACCM,QAAQL;QACRM,WAAU;OAEb"}
1
+ {"version":3,"sources":["../../../src/admin/sidebar/DocumentMetaTab.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\nimport type { ClientField } from 'payload'\nimport { DocumentFieldsTab } from './DocumentFieldsTab'\nimport { useBetterEditorT } from '../../i18n/useBetterEditorT'\n\nconst isSidebarField = (f: ClientField): boolean =>\n 'admin' in f && f.admin?.position === 'sidebar'\n\nexport const DocumentMetaTab: React.FC = () => {\n const t = useBetterEditorT()\n return <DocumentFieldsTab filter={isSidebarField} emptyText={t.documentFields.noSettings} />\n}\n"],"names":["React","DocumentFieldsTab","useBetterEditorT","isSidebarField","f","admin","position","DocumentMetaTab","t","filter","emptyText","documentFields","noSettings"],"mappings":"AAAA;;AAEA,OAAOA,WAAW,QAAO;AAEzB,SAASC,iBAAiB,QAAQ,sBAAqB;AACvD,SAASC,gBAAgB,QAAQ,8BAA6B;AAE9D,MAAMC,iBAAiB,CAACC,IACtB,WAAWA,KAAKA,EAAEC,KAAK,EAAEC,aAAa;AAExC,OAAO,MAAMC,kBAA4B;IACvC,MAAMC,IAAIN;IACV,qBAAO,KAACD;QAAkBQ,QAAQN;QAAgBO,WAAWF,EAAEG,cAAc,CAACC,UAAU;;AAC1F,EAAC"}
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import React from 'react';
4
4
  import { DocumentFieldsTab } from './DocumentFieldsTab';
5
+ import { useBetterEditorT } from '../../i18n/useBetterEditorT';
5
6
  const isNotSidebar = (f)=>!('admin' in f) || f.admin?.position !== 'sidebar';
6
7
  // The blocks tab owns layout-block editing; stripping `blocks` fields here
7
8
  // avoids rendering them twice and keeps this tab focused on document meta.
@@ -39,10 +40,13 @@ const stripBlocks = (fields)=>{
39
40
  }
40
41
  return result;
41
42
  };
42
- export const DocumentSettingsTab = ()=>/*#__PURE__*/ _jsx(DocumentFieldsTab, {
43
+ export const DocumentSettingsTab = ()=>{
44
+ const t = useBetterEditorT();
45
+ return /*#__PURE__*/ _jsx(DocumentFieldsTab, {
43
46
  filter: isNotSidebar,
44
47
  transform: stripBlocks,
45
- emptyText: "No document-level fields found."
48
+ emptyText: t.documentFields.noFields
46
49
  });
50
+ };
47
51
 
48
52
  //# sourceMappingURL=DocumentSettingsTab.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/sidebar/DocumentSettingsTab.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\nimport type { ClientField, ClientTab } from 'payload'\nimport { DocumentFieldsTab } from './DocumentFieldsTab'\n\nconst isNotSidebar = (f: ClientField): boolean =>\n !('admin' in f) || f.admin?.position !== 'sidebar'\n\n// The blocks tab owns layout-block editing; stripping `blocks` fields here\n// avoids rendering them twice and keeps this tab focused on document meta.\nconst stripBlocks = (fields: ClientField[]): ClientField[] => {\n const result: ClientField[] = []\n for (const field of fields) {\n const type = field.type\n\n if (type === 'blocks') continue\n\n if (type === 'tabs') {\n const newTabs: ClientTab[] = []\n for (const tab of field.tabs) {\n const inner = stripBlocks(tab.fields ?? [])\n if (inner.length > 0) newTabs.push({ ...tab, fields: inner })\n }\n if (newTabs.length === 0) continue\n result.push({ ...field, tabs: newTabs })\n continue\n }\n\n if (type === 'collapsible' || type === 'row' || type === 'group') {\n const inner = stripBlocks(field.fields)\n if (inner.length === 0) continue\n result.push({ ...field, fields: inner })\n continue\n }\n\n result.push(field)\n }\n return result\n}\n\nexport const DocumentSettingsTab: React.FC = () => (\n <DocumentFieldsTab\n filter={isNotSidebar}\n transform={stripBlocks}\n emptyText=\"No document-level fields found.\"\n />\n)\n"],"names":["React","DocumentFieldsTab","isNotSidebar","f","admin","position","stripBlocks","fields","result","field","type","newTabs","tab","tabs","inner","length","push","DocumentSettingsTab","filter","transform","emptyText"],"mappings":"AAAA;;AAEA,OAAOA,WAAW,QAAO;AAEzB,SAASC,iBAAiB,QAAQ,sBAAqB;AAEvD,MAAMC,eAAe,CAACC,IACpB,CAAE,CAAA,WAAWA,CAAAA,KAAMA,EAAEC,KAAK,EAAEC,aAAa;AAE3C,2EAA2E;AAC3E,2EAA2E;AAC3E,MAAMC,cAAc,CAACC;IACnB,MAAMC,SAAwB,EAAE;IAChC,KAAK,MAAMC,SAASF,OAAQ;QAC1B,MAAMG,OAAOD,MAAMC,IAAI;QAEvB,IAAIA,SAAS,UAAU;QAEvB,IAAIA,SAAS,QAAQ;YACnB,MAAMC,UAAuB,EAAE;YAC/B,KAAK,MAAMC,OAAOH,MAAMI,IAAI,CAAE;gBAC5B,MAAMC,QAAQR,YAAYM,IAAIL,MAAM,IAAI,EAAE;gBAC1C,IAAIO,MAAMC,MAAM,GAAG,GAAGJ,QAAQK,IAAI,CAAC;oBAAE,GAAGJ,GAAG;oBAAEL,QAAQO;gBAAM;YAC7D;YACA,IAAIH,QAAQI,MAAM,KAAK,GAAG;YAC1BP,OAAOQ,IAAI,CAAC;gBAAE,GAAGP,KAAK;gBAAEI,MAAMF;YAAQ;YACtC;QACF;QAEA,IAAID,SAAS,iBAAiBA,SAAS,SAASA,SAAS,SAAS;YAChE,MAAMI,QAAQR,YAAYG,MAAMF,MAAM;YACtC,IAAIO,MAAMC,MAAM,KAAK,GAAG;YACxBP,OAAOQ,IAAI,CAAC;gBAAE,GAAGP,KAAK;gBAAEF,QAAQO;YAAM;YACtC;QACF;QAEAN,OAAOQ,IAAI,CAACP;IACd;IACA,OAAOD;AACT;AAEA,OAAO,MAAMS,sBAAgC,kBAC3C,KAAChB;QACCiB,QAAQhB;QACRiB,WAAWb;QACXc,WAAU;OAEb"}
1
+ {"version":3,"sources":["../../../src/admin/sidebar/DocumentSettingsTab.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\nimport type { ClientField, ClientTab } from 'payload'\nimport { DocumentFieldsTab } from './DocumentFieldsTab'\nimport { useBetterEditorT } from '../../i18n/useBetterEditorT'\n\nconst isNotSidebar = (f: ClientField): boolean =>\n !('admin' in f) || f.admin?.position !== 'sidebar'\n\n// The blocks tab owns layout-block editing; stripping `blocks` fields here\n// avoids rendering them twice and keeps this tab focused on document meta.\nconst stripBlocks = (fields: ClientField[]): ClientField[] => {\n const result: ClientField[] = []\n for (const field of fields) {\n const type = field.type\n\n if (type === 'blocks') continue\n\n if (type === 'tabs') {\n const newTabs: ClientTab[] = []\n for (const tab of field.tabs) {\n const inner = stripBlocks(tab.fields ?? [])\n if (inner.length > 0) newTabs.push({ ...tab, fields: inner })\n }\n if (newTabs.length === 0) continue\n result.push({ ...field, tabs: newTabs })\n continue\n }\n\n if (type === 'collapsible' || type === 'row' || type === 'group') {\n const inner = stripBlocks(field.fields)\n if (inner.length === 0) continue\n result.push({ ...field, fields: inner })\n continue\n }\n\n result.push(field)\n }\n return result\n}\n\nexport const DocumentSettingsTab: React.FC = () => {\n const t = useBetterEditorT()\n return (\n <DocumentFieldsTab\n filter={isNotSidebar}\n transform={stripBlocks}\n emptyText={t.documentFields.noFields}\n />\n )\n}\n"],"names":["React","DocumentFieldsTab","useBetterEditorT","isNotSidebar","f","admin","position","stripBlocks","fields","result","field","type","newTabs","tab","tabs","inner","length","push","DocumentSettingsTab","t","filter","transform","emptyText","documentFields","noFields"],"mappings":"AAAA;;AAEA,OAAOA,WAAW,QAAO;AAEzB,SAASC,iBAAiB,QAAQ,sBAAqB;AACvD,SAASC,gBAAgB,QAAQ,8BAA6B;AAE9D,MAAMC,eAAe,CAACC,IACpB,CAAE,CAAA,WAAWA,CAAAA,KAAMA,EAAEC,KAAK,EAAEC,aAAa;AAE3C,2EAA2E;AAC3E,2EAA2E;AAC3E,MAAMC,cAAc,CAACC;IACnB,MAAMC,SAAwB,EAAE;IAChC,KAAK,MAAMC,SAASF,OAAQ;QAC1B,MAAMG,OAAOD,MAAMC,IAAI;QAEvB,IAAIA,SAAS,UAAU;QAEvB,IAAIA,SAAS,QAAQ;YACnB,MAAMC,UAAuB,EAAE;YAC/B,KAAK,MAAMC,OAAOH,MAAMI,IAAI,CAAE;gBAC5B,MAAMC,QAAQR,YAAYM,IAAIL,MAAM,IAAI,EAAE;gBAC1C,IAAIO,MAAMC,MAAM,GAAG,GAAGJ,QAAQK,IAAI,CAAC;oBAAE,GAAGJ,GAAG;oBAAEL,QAAQO;gBAAM;YAC7D;YACA,IAAIH,QAAQI,MAAM,KAAK,GAAG;YAC1BP,OAAOQ,IAAI,CAAC;gBAAE,GAAGP,KAAK;gBAAEI,MAAMF;YAAQ;YACtC;QACF;QAEA,IAAID,SAAS,iBAAiBA,SAAS,SAASA,SAAS,SAAS;YAChE,MAAMI,QAAQR,YAAYG,MAAMF,MAAM;YACtC,IAAIO,MAAMC,MAAM,KAAK,GAAG;YACxBP,OAAOQ,IAAI,CAAC;gBAAE,GAAGP,KAAK;gBAAEF,QAAQO;YAAM;YACtC;QACF;QAEAN,OAAOQ,IAAI,CAACP;IACd;IACA,OAAOD;AACT;AAEA,OAAO,MAAMS,sBAAgC;IAC3C,MAAMC,IAAIjB;IACV,qBACE,KAACD;QACCmB,QAAQjB;QACRkB,WAAWd;QACXe,WAAWH,EAAEI,cAAc,CAACC,QAAQ;;AAG1C,EAAC"}
@@ -5,20 +5,7 @@ import { DocumentSettingsTab } from './DocumentSettingsTab';
5
5
  import { DocumentMetaTab } from './DocumentMetaTab';
6
6
  import { BlockSettingsTab } from './BlockSettingsTab';
7
7
  import { ValidationSummary } from './ValidationSummary';
8
- const TABS = [
9
- {
10
- key: 'page',
11
- label: 'Page'
12
- },
13
- {
14
- key: 'block',
15
- label: 'Blocks'
16
- },
17
- {
18
- key: 'settings',
19
- label: 'Settings'
20
- }
21
- ];
8
+ import { useBetterEditorT } from '../../i18n/useBetterEditorT';
22
9
  const ROOT_CLASS = 'better-editor-sidebar';
23
10
  const TAB_CLASS = `${ROOT_CLASS}__tab`;
24
11
  const tabId = (key)=>`better-editor-tab-${key}`;
@@ -36,6 +23,21 @@ const SidebarTab = ({ tabKey, label, active, onSelect })=>/*#__PURE__*/ _jsx("bu
36
23
  });
37
24
  // Memoized so resize-drag re-renders of the overlay skip the field tree.
38
25
  export const Sidebar = /*#__PURE__*/ React.memo(function Sidebar({ selectedBlockPath, onClearSelection, onSelectPath, forceFullWidthFields, blocksField, addBelowRequestId = 0 }) {
26
+ const t = useBetterEditorT();
27
+ const TABS = [
28
+ {
29
+ key: 'page',
30
+ label: t.sidebar.tabs.page
31
+ },
32
+ {
33
+ key: 'block',
34
+ label: t.sidebar.tabs.block
35
+ },
36
+ {
37
+ key: 'settings',
38
+ label: t.sidebar.tabs.settings
39
+ }
40
+ ];
39
41
  const [tab, setTab] = useState('page');
40
42
  // Auto-jump to the block tab when the iframe selects a new block.
41
43
  useEffect(()=>{
@@ -87,12 +89,15 @@ export const Sidebar = /*#__PURE__*/ React.memo(function Sidebar({ selectedBlock
87
89
  });
88
90
  // Off-screen live region announces block-selection changes to screen
89
91
  // readers; visible UI updates handle sighted users via the tab switch.
90
- const SelectionAnnouncer = ({ selectedBlockPath })=>/*#__PURE__*/ _jsx("div", {
92
+ const SelectionAnnouncer = ({ selectedBlockPath })=>{
93
+ const t = useBetterEditorT();
94
+ return /*#__PURE__*/ _jsx("div", {
91
95
  role: "status",
92
96
  "aria-live": "polite",
93
97
  "aria-atomic": "true",
94
98
  className: "better-editor-sr-only",
95
- children: selectedBlockPath ? `Block selected: ${selectedBlockPath}` : 'No block selected'
99
+ children: selectedBlockPath ? `${t.sidebar.blockSelected}${selectedBlockPath}` : t.sidebar.noBlockSelected
96
100
  });
101
+ };
97
102
 
98
103
  //# sourceMappingURL=Sidebar.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/sidebar/Sidebar.tsx"],"sourcesContent":["'use client'\n\nimport React, { useEffect, useState } from 'react'\nimport { DocumentSettingsTab } from './DocumentSettingsTab'\nimport { DocumentMetaTab } from './DocumentMetaTab'\nimport { BlockSettingsTab } from './BlockSettingsTab'\nimport { ValidationSummary } from './ValidationSummary'\n\nexport type SidebarProps = {\n selectedBlockPath: string | null\n onClearSelection: () => void\n onSelectPath: (path: string | null) => void\n forceFullWidthFields: boolean\n blocksField: string\n addBelowRequestId?: number\n}\n\ntype TabKey = 'page' | 'block' | 'settings'\n\nconst TABS: ReadonlyArray<{ key: TabKey; label: string }> = [\n { key: 'page', label: 'Page' },\n { key: 'block', label: 'Blocks' },\n { key: 'settings', label: 'Settings' },\n]\n\nconst ROOT_CLASS = 'better-editor-sidebar'\nconst TAB_CLASS = `${ROOT_CLASS}__tab`\n\nconst tabId = (key: TabKey) => `better-editor-tab-${key}`\nconst panelId = (key: TabKey) => `better-editor-panel-${key}`\n\ntype SidebarTabProps = {\n tabKey: TabKey\n label: string\n active: boolean\n onSelect: (key: TabKey) => void\n}\n\nconst SidebarTab: React.FC<SidebarTabProps> = ({ tabKey, label, active, onSelect }) => (\n <button\n type=\"button\"\n role=\"tab\"\n id={tabId(tabKey)}\n aria-selected={active}\n aria-controls={panelId(tabKey)}\n tabIndex={active ? 0 : -1}\n className={active ? `${TAB_CLASS} ${TAB_CLASS}--active` : TAB_CLASS}\n onClick={() => onSelect(tabKey)}\n >\n {label}\n </button>\n)\n\n// Memoized so resize-drag re-renders of the overlay skip the field tree.\nexport const Sidebar = React.memo(function Sidebar({\n selectedBlockPath,\n onClearSelection,\n onSelectPath,\n forceFullWidthFields,\n blocksField,\n addBelowRequestId = 0,\n}: SidebarProps) {\n const [tab, setTab] = useState<TabKey>('page')\n\n // Auto-jump to the block tab when the iframe selects a new block.\n useEffect(() => {\n if (selectedBlockPath) setTab('block')\n }, [selectedBlockPath])\n\n const className = forceFullWidthFields\n ? `${ROOT_CLASS} ${ROOT_CLASS}--force-full-width`\n : ROOT_CLASS\n\n return (\n <div className={className}>\n <div role=\"tablist\" className={`${ROOT_CLASS}__tabs`}>\n {TABS.map((t) => (\n <SidebarTab\n key={t.key}\n tabKey={t.key}\n label={t.label}\n active={tab === t.key}\n onSelect={setTab}\n />\n ))}\n </div>\n\n <ValidationSummary blocksField={blocksField} onSelectPath={onSelectPath} />\n\n <div\n className={`${ROOT_CLASS}__content`}\n role=\"tabpanel\"\n id={panelId(tab)}\n aria-labelledby={tabId(tab)}\n tabIndex={0}\n >\n {tab === 'page' && <DocumentSettingsTab />}\n {tab === 'block' && (\n <BlockSettingsTab\n selectedBlockPath={selectedBlockPath}\n onClearSelection={onClearSelection}\n onSelectPath={onSelectPath}\n blocksField={blocksField}\n addBelowRequestId={addBelowRequestId}\n />\n )}\n {tab === 'settings' && <DocumentMetaTab />}\n </div>\n\n <SelectionAnnouncer selectedBlockPath={selectedBlockPath} />\n </div>\n )\n})\n\n// Off-screen live region announces block-selection changes to screen\n// readers; visible UI updates handle sighted users via the tab switch.\nconst SelectionAnnouncer: React.FC<{ selectedBlockPath: string | null }> = ({\n selectedBlockPath,\n}) => (\n <div role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" className=\"better-editor-sr-only\">\n {selectedBlockPath ? `Block selected: ${selectedBlockPath}` : 'No block selected'}\n </div>\n)\n"],"names":["React","useEffect","useState","DocumentSettingsTab","DocumentMetaTab","BlockSettingsTab","ValidationSummary","TABS","key","label","ROOT_CLASS","TAB_CLASS","tabId","panelId","SidebarTab","tabKey","active","onSelect","button","type","role","id","aria-selected","aria-controls","tabIndex","className","onClick","Sidebar","memo","selectedBlockPath","onClearSelection","onSelectPath","forceFullWidthFields","blocksField","addBelowRequestId","tab","setTab","div","map","t","aria-labelledby","SelectionAnnouncer","aria-live","aria-atomic"],"mappings":"AAAA;;AAEA,OAAOA,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAClD,SAASC,mBAAmB,QAAQ,wBAAuB;AAC3D,SAASC,eAAe,QAAQ,oBAAmB;AACnD,SAASC,gBAAgB,QAAQ,qBAAoB;AACrD,SAASC,iBAAiB,QAAQ,sBAAqB;AAavD,MAAMC,OAAsD;IAC1D;QAAEC,KAAK;QAAQC,OAAO;IAAO;IAC7B;QAAED,KAAK;QAASC,OAAO;IAAS;IAChC;QAAED,KAAK;QAAYC,OAAO;IAAW;CACtC;AAED,MAAMC,aAAa;AACnB,MAAMC,YAAY,GAAGD,WAAW,KAAK,CAAC;AAEtC,MAAME,QAAQ,CAACJ,MAAgB,CAAC,kBAAkB,EAAEA,KAAK;AACzD,MAAMK,UAAU,CAACL,MAAgB,CAAC,oBAAoB,EAAEA,KAAK;AAS7D,MAAMM,aAAwC,CAAC,EAAEC,MAAM,EAAEN,KAAK,EAAEO,MAAM,EAAEC,QAAQ,EAAE,iBAChF,KAACC;QACCC,MAAK;QACLC,MAAK;QACLC,IAAIT,MAAMG;QACVO,iBAAeN;QACfO,iBAAeV,QAAQE;QACvBS,UAAUR,SAAS,IAAI,CAAC;QACxBS,WAAWT,SAAS,GAAGL,UAAU,CAAC,EAAEA,UAAU,QAAQ,CAAC,GAAGA;QAC1De,SAAS,IAAMT,SAASF;kBAEvBN;;AAIL,yEAAyE;AACzE,OAAO,MAAMkB,wBAAU3B,MAAM4B,IAAI,CAAC,SAASD,QAAQ,EACjDE,iBAAiB,EACjBC,gBAAgB,EAChBC,YAAY,EACZC,oBAAoB,EACpBC,WAAW,EACXC,oBAAoB,CAAC,EACR;IACb,MAAM,CAACC,KAAKC,OAAO,GAAGlC,SAAiB;IAEvC,kEAAkE;IAClED,UAAU;QACR,IAAI4B,mBAAmBO,OAAO;IAChC,GAAG;QAACP;KAAkB;IAEtB,MAAMJ,YAAYO,uBACd,GAAGtB,WAAW,CAAC,EAAEA,WAAW,kBAAkB,CAAC,GAC/CA;IAEJ,qBACE,MAAC2B;QAAIZ,WAAWA;;0BACd,KAACY;gBAAIjB,MAAK;gBAAUK,WAAW,GAAGf,WAAW,MAAM,CAAC;0BACjDH,KAAK+B,GAAG,CAAC,CAACC,kBACT,KAACzB;wBAECC,QAAQwB,EAAE/B,GAAG;wBACbC,OAAO8B,EAAE9B,KAAK;wBACdO,QAAQmB,QAAQI,EAAE/B,GAAG;wBACrBS,UAAUmB;uBAJLG,EAAE/B,GAAG;;0BAShB,KAACF;gBAAkB2B,aAAaA;gBAAaF,cAAcA;;0BAE3D,MAACM;gBACCZ,WAAW,GAAGf,WAAW,SAAS,CAAC;gBACnCU,MAAK;gBACLC,IAAIR,QAAQsB;gBACZK,mBAAiB5B,MAAMuB;gBACvBX,UAAU;;oBAETW,QAAQ,wBAAU,KAAChC;oBACnBgC,QAAQ,yBACP,KAAC9B;wBACCwB,mBAAmBA;wBACnBC,kBAAkBA;wBAClBC,cAAcA;wBACdE,aAAaA;wBACbC,mBAAmBA;;oBAGtBC,QAAQ,4BAAc,KAAC/B;;;0BAG1B,KAACqC;gBAAmBZ,mBAAmBA;;;;AAG7C,GAAE;AAEF,qEAAqE;AACrE,uEAAuE;AACvE,MAAMY,qBAAqE,CAAC,EAC1EZ,iBAAiB,EAClB,iBACC,KAACQ;QAAIjB,MAAK;QAASsB,aAAU;QAASC,eAAY;QAAOlB,WAAU;kBAChEI,oBAAoB,CAAC,gBAAgB,EAAEA,mBAAmB,GAAG"}
1
+ {"version":3,"sources":["../../../src/admin/sidebar/Sidebar.tsx"],"sourcesContent":["'use client'\n\nimport React, { useEffect, useState } from 'react'\nimport { DocumentSettingsTab } from './DocumentSettingsTab'\nimport { DocumentMetaTab } from './DocumentMetaTab'\nimport { BlockSettingsTab } from './BlockSettingsTab'\nimport { ValidationSummary } from './ValidationSummary'\nimport { useBetterEditorT } from '../../i18n/useBetterEditorT'\n\nexport type SidebarProps = {\n selectedBlockPath: string | null\n onClearSelection: () => void\n onSelectPath: (path: string | null) => void\n forceFullWidthFields: boolean\n blocksField: string\n addBelowRequestId?: number\n}\n\ntype TabKey = 'page' | 'block' | 'settings'\n\nconst ROOT_CLASS = 'better-editor-sidebar'\nconst TAB_CLASS = `${ROOT_CLASS}__tab`\n\nconst tabId = (key: TabKey) => `better-editor-tab-${key}`\nconst panelId = (key: TabKey) => `better-editor-panel-${key}`\n\ntype SidebarTabProps = {\n tabKey: TabKey\n label: string\n active: boolean\n onSelect: (key: TabKey) => void\n}\n\nconst SidebarTab: React.FC<SidebarTabProps> = ({ tabKey, label, active, onSelect }) => (\n <button\n type=\"button\"\n role=\"tab\"\n id={tabId(tabKey)}\n aria-selected={active}\n aria-controls={panelId(tabKey)}\n tabIndex={active ? 0 : -1}\n className={active ? `${TAB_CLASS} ${TAB_CLASS}--active` : TAB_CLASS}\n onClick={() => onSelect(tabKey)}\n >\n {label}\n </button>\n)\n\n// Memoized so resize-drag re-renders of the overlay skip the field tree.\nexport const Sidebar = React.memo(function Sidebar({\n selectedBlockPath,\n onClearSelection,\n onSelectPath,\n forceFullWidthFields,\n blocksField,\n addBelowRequestId = 0,\n}: SidebarProps) {\n const t = useBetterEditorT()\n const TABS: ReadonlyArray<{ key: TabKey; label: string }> = [\n { key: 'page', label: t.sidebar.tabs.page },\n { key: 'block', label: t.sidebar.tabs.block },\n { key: 'settings', label: t.sidebar.tabs.settings },\n ]\n const [tab, setTab] = useState<TabKey>('page')\n\n // Auto-jump to the block tab when the iframe selects a new block.\n useEffect(() => {\n if (selectedBlockPath) setTab('block')\n }, [selectedBlockPath])\n\n const className = forceFullWidthFields\n ? `${ROOT_CLASS} ${ROOT_CLASS}--force-full-width`\n : ROOT_CLASS\n\n return (\n <div className={className}>\n <div role=\"tablist\" className={`${ROOT_CLASS}__tabs`}>\n {TABS.map((t) => (\n <SidebarTab\n key={t.key}\n tabKey={t.key}\n label={t.label}\n active={tab === t.key}\n onSelect={setTab}\n />\n ))}\n </div>\n\n <ValidationSummary blocksField={blocksField} onSelectPath={onSelectPath} />\n\n <div\n className={`${ROOT_CLASS}__content`}\n role=\"tabpanel\"\n id={panelId(tab)}\n aria-labelledby={tabId(tab)}\n tabIndex={0}\n >\n {tab === 'page' && <DocumentSettingsTab />}\n {tab === 'block' && (\n <BlockSettingsTab\n selectedBlockPath={selectedBlockPath}\n onClearSelection={onClearSelection}\n onSelectPath={onSelectPath}\n blocksField={blocksField}\n addBelowRequestId={addBelowRequestId}\n />\n )}\n {tab === 'settings' && <DocumentMetaTab />}\n </div>\n\n <SelectionAnnouncer selectedBlockPath={selectedBlockPath} />\n </div>\n )\n})\n\n// Off-screen live region announces block-selection changes to screen\n// readers; visible UI updates handle sighted users via the tab switch.\nconst SelectionAnnouncer: React.FC<{ selectedBlockPath: string | null }> = ({\n selectedBlockPath,\n}) => {\n const t = useBetterEditorT()\n return (\n <div role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" className=\"better-editor-sr-only\">\n {selectedBlockPath\n ? `${t.sidebar.blockSelected}${selectedBlockPath}`\n : t.sidebar.noBlockSelected}\n </div>\n )\n}\n"],"names":["React","useEffect","useState","DocumentSettingsTab","DocumentMetaTab","BlockSettingsTab","ValidationSummary","useBetterEditorT","ROOT_CLASS","TAB_CLASS","tabId","key","panelId","SidebarTab","tabKey","label","active","onSelect","button","type","role","id","aria-selected","aria-controls","tabIndex","className","onClick","Sidebar","memo","selectedBlockPath","onClearSelection","onSelectPath","forceFullWidthFields","blocksField","addBelowRequestId","t","TABS","sidebar","tabs","page","block","settings","tab","setTab","div","map","aria-labelledby","SelectionAnnouncer","aria-live","aria-atomic","blockSelected","noBlockSelected"],"mappings":"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"}
@@ -3,22 +3,25 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React, { useMemo } from 'react';
4
4
  import { useAllFormFields } from '@payloadcms/ui';
5
5
  import { collectFieldErrors } from './validation';
6
+ import { useBetterEditorT } from '../../i18n/useBetterEditorT';
6
7
  // Sidebar banner listing invalid fields across all blocks.
7
8
  export const ValidationSummary = ({ blocksField, onSelectPath })=>{
9
+ const t = useBetterEditorT();
8
10
  const [fields] = useAllFormFields();
9
11
  const errors = useMemo(()=>collectFieldErrors(fields, blocksField), [
10
12
  fields,
11
13
  blocksField
12
14
  ]);
13
15
  if (errors.length === 0) return null;
16
+ const countLabel = errors.length === 1 ? t.sidebar.validationSingular : `${errors.length}${t.sidebar.validationPlural}`;
14
17
  return /*#__PURE__*/ _jsxs("div", {
15
18
  className: "better-editor-sidebar__errors",
16
19
  role: "region",
17
- "aria-label": "Validation errors",
20
+ "aria-label": t.sidebar.validationLabel,
18
21
  children: [
19
22
  /*#__PURE__*/ _jsx("p", {
20
23
  className: "better-editor-sidebar__errors-title",
21
- children: errors.length === 1 ? '1 field needs attention' : `${errors.length} fields need attention`
24
+ children: countLabel
22
25
  }),
23
26
  /*#__PURE__*/ _jsx("ul", {
24
27
  className: "better-editor-sidebar__errors-list",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/sidebar/ValidationSummary.tsx"],"sourcesContent":["'use client'\n\nimport React, { useMemo } from 'react'\nimport { useAllFormFields } from '@payloadcms/ui'\nimport type { FormState } from 'payload'\nimport { collectFieldErrors } from './validation'\n\nexport type ValidationSummaryProps = {\n blocksField: string\n onSelectPath: (path: string | null) => void\n}\n\n// Sidebar banner listing invalid fields across all blocks.\nexport const ValidationSummary: React.FC<ValidationSummaryProps> = ({\n blocksField,\n onSelectPath,\n}) => {\n const [fields] = useAllFormFields()\n const errors = useMemo(\n () => collectFieldErrors(fields as FormState, blocksField),\n [fields, blocksField],\n )\n\n if (errors.length === 0) return null\n\n return (\n <div className=\"better-editor-sidebar__errors\" role=\"region\" aria-label=\"Validation errors\">\n <p className=\"better-editor-sidebar__errors-title\">\n {errors.length === 1 ? '1 field needs attention' : `${errors.length} fields need attention`}\n </p>\n <ul className=\"better-editor-sidebar__errors-list\">\n {errors.map((error) => (\n <li key={error.path} className=\"better-editor-sidebar__errors-item\">\n {error.blockPath ? (\n <button\n type=\"button\"\n className=\"better-editor-sidebar__errors-jump\"\n onClick={() => onSelectPath(error.blockPath)}\n >\n {error.label}\n </button>\n ) : (\n <span className=\"better-editor-sidebar__errors-label\">{error.label}</span>\n )}\n <span className=\"better-editor-sidebar__errors-message\">{error.message}</span>\n </li>\n ))}\n </ul>\n </div>\n )\n}\n"],"names":["React","useMemo","useAllFormFields","collectFieldErrors","ValidationSummary","blocksField","onSelectPath","fields","errors","length","div","className","role","aria-label","p","ul","map","error","li","blockPath","button","type","onClick","label","span","message","path"],"mappings":"AAAA;;AAEA,OAAOA,SAASC,OAAO,QAAQ,QAAO;AACtC,SAASC,gBAAgB,QAAQ,iBAAgB;AAEjD,SAASC,kBAAkB,QAAQ,eAAc;AAOjD,2DAA2D;AAC3D,OAAO,MAAMC,oBAAsD,CAAC,EAClEC,WAAW,EACXC,YAAY,EACb;IACC,MAAM,CAACC,OAAO,GAAGL;IACjB,MAAMM,SAASP,QACb,IAAME,mBAAmBI,QAAqBF,cAC9C;QAACE;QAAQF;KAAY;IAGvB,IAAIG,OAAOC,MAAM,KAAK,GAAG,OAAO;IAEhC,qBACE,MAACC;QAAIC,WAAU;QAAgCC,MAAK;QAASC,cAAW;;0BACtE,KAACC;gBAAEH,WAAU;0BACVH,OAAOC,MAAM,KAAK,IAAI,4BAA4B,GAAGD,OAAOC,MAAM,CAAC,sBAAsB,CAAC;;0BAE7F,KAACM;gBAAGJ,WAAU;0BACXH,OAAOQ,GAAG,CAAC,CAACC,sBACX,MAACC;wBAAoBP,WAAU;;4BAC5BM,MAAME,SAAS,iBACd,KAACC;gCACCC,MAAK;gCACLV,WAAU;gCACVW,SAAS,IAAMhB,aAAaW,MAAME,SAAS;0CAE1CF,MAAMM,KAAK;+CAGd,KAACC;gCAAKb,WAAU;0CAAuCM,MAAMM,KAAK;;0CAEpE,KAACC;gCAAKb,WAAU;0CAAyCM,MAAMQ,OAAO;;;uBAZ/DR,MAAMS,IAAI;;;;AAkB7B,EAAC"}
1
+ {"version":3,"sources":["../../../src/admin/sidebar/ValidationSummary.tsx"],"sourcesContent":["'use client'\n\nimport React, { useMemo } from 'react'\nimport { useAllFormFields } from '@payloadcms/ui'\nimport type { FormState } from 'payload'\nimport { collectFieldErrors } from './validation'\nimport { useBetterEditorT } from '../../i18n/useBetterEditorT'\n\nexport type ValidationSummaryProps = {\n blocksField: string\n onSelectPath: (path: string | null) => void\n}\n\n// Sidebar banner listing invalid fields across all blocks.\nexport const ValidationSummary: React.FC<ValidationSummaryProps> = ({\n blocksField,\n onSelectPath,\n}) => {\n const t = useBetterEditorT()\n const [fields] = useAllFormFields()\n const errors = useMemo(\n () => collectFieldErrors(fields as FormState, blocksField),\n [fields, blocksField],\n )\n\n if (errors.length === 0) return null\n\n const countLabel =\n errors.length === 1\n ? t.sidebar.validationSingular\n : `${errors.length}${t.sidebar.validationPlural}`\n\n return (\n <div\n className=\"better-editor-sidebar__errors\"\n role=\"region\"\n aria-label={t.sidebar.validationLabel}\n >\n <p className=\"better-editor-sidebar__errors-title\">{countLabel}</p>\n <ul className=\"better-editor-sidebar__errors-list\">\n {errors.map((error) => (\n <li key={error.path} className=\"better-editor-sidebar__errors-item\">\n {error.blockPath ? (\n <button\n type=\"button\"\n className=\"better-editor-sidebar__errors-jump\"\n onClick={() => onSelectPath(error.blockPath)}\n >\n {error.label}\n </button>\n ) : (\n <span className=\"better-editor-sidebar__errors-label\">{error.label}</span>\n )}\n <span className=\"better-editor-sidebar__errors-message\">{error.message}</span>\n </li>\n ))}\n </ul>\n </div>\n )\n}\n"],"names":["React","useMemo","useAllFormFields","collectFieldErrors","useBetterEditorT","ValidationSummary","blocksField","onSelectPath","t","fields","errors","length","countLabel","sidebar","validationSingular","validationPlural","div","className","role","aria-label","validationLabel","p","ul","map","error","li","blockPath","button","type","onClick","label","span","message","path"],"mappings":"AAAA;;AAEA,OAAOA,SAASC,OAAO,QAAQ,QAAO;AACtC,SAASC,gBAAgB,QAAQ,iBAAgB;AAEjD,SAASC,kBAAkB,QAAQ,eAAc;AACjD,SAASC,gBAAgB,QAAQ,8BAA6B;AAO9D,2DAA2D;AAC3D,OAAO,MAAMC,oBAAsD,CAAC,EAClEC,WAAW,EACXC,YAAY,EACb;IACC,MAAMC,IAAIJ;IACV,MAAM,CAACK,OAAO,GAAGP;IACjB,MAAMQ,SAAST,QACb,IAAME,mBAAmBM,QAAqBH,cAC9C;QAACG;QAAQH;KAAY;IAGvB,IAAII,OAAOC,MAAM,KAAK,GAAG,OAAO;IAEhC,MAAMC,aACJF,OAAOC,MAAM,KAAK,IACdH,EAAEK,OAAO,CAACC,kBAAkB,GAC5B,GAAGJ,OAAOC,MAAM,GAAGH,EAAEK,OAAO,CAACE,gBAAgB,EAAE;IAErD,qBACE,MAACC;QACCC,WAAU;QACVC,MAAK;QACLC,cAAYX,EAAEK,OAAO,CAACO,eAAe;;0BAErC,KAACC;gBAAEJ,WAAU;0BAAuCL;;0BACpD,KAACU;gBAAGL,WAAU;0BACXP,OAAOa,GAAG,CAAC,CAACC,sBACX,MAACC;wBAAoBR,WAAU;;4BAC5BO,MAAME,SAAS,iBACd,KAACC;gCACCC,MAAK;gCACLX,WAAU;gCACVY,SAAS,IAAMtB,aAAaiB,MAAME,SAAS;0CAE1CF,MAAMM,KAAK;+CAGd,KAACC;gCAAKd,WAAU;0CAAuCO,MAAMM,KAAK;;0CAEpE,KAACC;gCAAKd,WAAU;0CAAyCO,MAAMQ,OAAO;;;uBAZ/DR,MAAMS,IAAI;;;;AAkB7B,EAAC"}
package/dist/global.js CHANGED
@@ -1,33 +1,49 @@
1
1
  import { DEFAULT_BETTER_EDITOR_SETTINGS as D } from './internal/constants';
2
2
  import { HOVER_OUTLINE_MAX, HOVER_OUTLINE_MIN, MOBILE_WIDTH_MAX, MOBILE_WIDTH_MIN, TABLET_WIDTH_MAX, TABLET_WIDTH_MIN } from './internal/limits';
3
+ import { en } from './i18n/en';
4
+ import { de } from './i18n/de';
3
5
  export const BETTER_EDITOR_SETTINGS_SLUG = 'better-editor-settings';
4
6
  export const BETTER_EDITOR_SETTINGS_BANNER_FIELD = 'betterEditorSettingsBanner';
5
7
  // Mirrors the runtime regex in `preview/hover-css.ts` so the admin UI rejects
6
8
  // values that would silently be skipped at render time.
7
9
  const HOVER_COLOR_RE = /^(?:#[0-9a-fA-F]{3,8}|rgba?\([^()\n\r]*\))$/i;
8
- const validateHoverColor = (value)=>{
9
- if (typeof value !== 'string' || value.length === 0) return 'Color is required';
10
- if (!HOVER_COLOR_RE.test(value.trim())) {
11
- return 'Must be a hex color (e.g. #3b82f6) or rgb()/rgba()';
12
- }
10
+ const settingsKey = (path)=>`betterEditor:settings.${path}`;
11
+ // Locales the plugin ships built-in translations for.
12
+ const SETTINGS_TRANSLATIONS = {
13
+ en: en.settings,
14
+ de: de.settings
15
+ };
16
+ const lookupSetting = (settings, path)=>path.split('.').reduce((value, key)=>value?.[key], settings);
17
+ // Entity/field labels and descriptions are serialized into the admin RootLayout
18
+ // (a Client Component), so they must be plain data — a function (e.g. `({ t }) => …`)
19
+ // can't cross that RSC boundary. Return a Payload locale map built from our bundled
20
+ // translations; Payload selects the entry for the admin UI language. (Runtime `t()`
21
+ // stays available for `validate`, which Payload strips before client serialization.)
22
+ const translatedLabel = (path)=>Object.fromEntries(Object.entries(SETTINGS_TRANSLATIONS).map(([locale, settings])=>[
23
+ locale,
24
+ lookupSetting(settings, path)
25
+ ]));
26
+ const validateHoverColor = (value, args)=>{
27
+ const t = args?.t ?? ((k)=>k);
28
+ if (typeof value !== 'string' || value.length === 0) return t(settingsKey('validation.colorRequired'));
29
+ if (!HOVER_COLOR_RE.test(value.trim())) return t(settingsKey('validation.colorInvalid'));
13
30
  return true;
14
31
  };
15
- const validateHoverOutline = (value)=>{
16
- if (typeof value !== 'number' || !Number.isFinite(value)) return 'Must be a number';
17
- if (value < HOVER_OUTLINE_MIN || value > HOVER_OUTLINE_MAX) {
18
- return `Must be between ${HOVER_OUTLINE_MIN} and ${HOVER_OUTLINE_MAX}`;
19
- }
32
+ const validateHoverOutline = (value, args)=>{
33
+ const t = args?.t ?? ((k)=>k);
34
+ if (typeof value !== 'number' || !Number.isFinite(value)) return t(settingsKey('validation.mustBeNumber'));
35
+ if (value < HOVER_OUTLINE_MIN || value > HOVER_OUTLINE_MAX) return t(settingsKey('validation.outlineRange'));
20
36
  return true;
21
37
  };
22
38
  export const betterEditorSettingsGlobal = {
23
39
  slug: BETTER_EDITOR_SETTINGS_SLUG,
24
- label: 'Settings',
40
+ label: translatedLabel('globalLabel'),
25
41
  access: {
26
42
  read: ()=>true
27
43
  },
28
44
  admin: {
29
45
  group: 'Better Editor',
30
- description: 'Editor-wide preferences for the Better Editor overlay.'
46
+ description: translatedLabel('globalDescription')
31
47
  },
32
48
  fields: [
33
49
  {
@@ -43,21 +59,21 @@ export const betterEditorSettingsGlobal = {
43
59
  type: 'tabs',
44
60
  tabs: [
45
61
  {
46
- label: 'Sidebar',
47
- description: 'Where the sidebar sits and how its fields are stacked.',
62
+ label: translatedLabel('sidebar.tabLabel'),
63
+ description: translatedLabel('sidebar.tabDescription'),
48
64
  fields: [
49
65
  {
50
66
  name: 'sidebarPosition',
51
67
  type: 'select',
52
- label: 'Position',
68
+ label: translatedLabel('sidebar.position'),
53
69
  defaultValue: D.sidebarPosition,
54
70
  options: [
55
71
  {
56
- label: 'Right',
72
+ label: translatedLabel('sidebar.positionRight'),
57
73
  value: 'right'
58
74
  },
59
75
  {
60
- label: 'Left',
76
+ label: translatedLabel('sidebar.positionLeft'),
61
77
  value: 'left'
62
78
  }
63
79
  ]
@@ -65,17 +81,17 @@ export const betterEditorSettingsGlobal = {
65
81
  {
66
82
  name: 'forceFullWidthFields',
67
83
  type: 'checkbox',
68
- label: 'Stack fields full-width',
84
+ label: translatedLabel('sidebar.forceFullWidth'),
69
85
  defaultValue: D.forceFullWidthFields,
70
86
  admin: {
71
- description: 'Override admin.width on sidebar fields so they always span the full row.'
87
+ description: translatedLabel('sidebar.forceFullWidthDesc')
72
88
  }
73
89
  }
74
90
  ]
75
91
  },
76
92
  {
77
- label: 'Viewport',
78
- description: 'Pixel widths for the Tablet and Mobile preview modes.',
93
+ label: translatedLabel('viewport.tabLabel'),
94
+ description: translatedLabel('viewport.tabDescription'),
79
95
  fields: [
80
96
  {
81
97
  type: 'row',
@@ -83,7 +99,7 @@ export const betterEditorSettingsGlobal = {
83
99
  {
84
100
  name: 'tabletWidth',
85
101
  type: 'number',
86
- label: 'Tablet (px)',
102
+ label: translatedLabel('viewport.tabletWidth'),
87
103
  defaultValue: D.tabletWidth,
88
104
  min: TABLET_WIDTH_MIN,
89
105
  max: TABLET_WIDTH_MAX,
@@ -95,7 +111,7 @@ export const betterEditorSettingsGlobal = {
95
111
  {
96
112
  name: 'mobileWidth',
97
113
  type: 'number',
98
- label: 'Mobile (px)',
114
+ label: translatedLabel('viewport.mobileWidth'),
99
115
  defaultValue: D.mobileWidth,
100
116
  min: MOBILE_WIDTH_MIN,
101
117
  max: MOBILE_WIDTH_MAX,
@@ -109,8 +125,8 @@ export const betterEditorSettingsGlobal = {
109
125
  ]
110
126
  },
111
127
  {
112
- label: 'Outline',
113
- description: 'Outline + tint shown on the hovered or selected block.',
128
+ label: translatedLabel('outline.tabLabel'),
129
+ description: translatedLabel('outline.tabDescription'),
114
130
  fields: [
115
131
  {
116
132
  type: 'row',
@@ -118,25 +134,25 @@ export const betterEditorSettingsGlobal = {
118
134
  {
119
135
  name: 'hoverColorTopLevel',
120
136
  type: 'text',
121
- label: 'Top-level color',
137
+ label: translatedLabel('outline.topLevelColor'),
122
138
  defaultValue: D.hoverColorTopLevel,
123
139
  validate: validateHoverColor,
124
140
  admin: {
125
141
  width: '50%',
126
142
  placeholder: D.hoverColorTopLevel,
127
- description: 'Hex color (e.g. `#3b82f6`).'
143
+ description: translatedLabel('outline.topLevelColorDesc')
128
144
  }
129
145
  },
130
146
  {
131
147
  name: 'hoverColorNested',
132
148
  type: 'text',
133
- label: 'Nested color',
149
+ label: translatedLabel('outline.nestedColor'),
134
150
  defaultValue: D.hoverColorNested,
135
151
  validate: validateHoverColor,
136
152
  admin: {
137
153
  width: '50%',
138
154
  placeholder: D.hoverColorNested,
139
- description: 'Hex color for blocks nested inside another block.'
155
+ description: translatedLabel('outline.nestedColorDesc')
140
156
  }
141
157
  }
142
158
  ]
@@ -144,48 +160,48 @@ export const betterEditorSettingsGlobal = {
144
160
  {
145
161
  name: 'hoverOutlineWidth',
146
162
  type: 'number',
147
- label: 'Outline width (px)',
163
+ label: translatedLabel('outline.outlineWidth'),
148
164
  defaultValue: D.hoverOutlineWidth,
149
165
  min: HOVER_OUTLINE_MIN,
150
166
  max: HOVER_OUTLINE_MAX,
151
167
  validate: validateHoverOutline,
152
168
  admin: {
153
169
  placeholder: String(D.hoverOutlineWidth),
154
- description: `Outline thickness in pixels (${HOVER_OUTLINE_MIN}–${HOVER_OUTLINE_MAX}).`
170
+ description: translatedLabel('outline.outlineWidthDesc')
155
171
  }
156
172
  }
157
173
  ]
158
174
  },
159
175
  {
160
- label: 'Toolbar',
161
- description: 'Floating Move / Duplicate / Delete toolbar that appears on the selected block.',
176
+ label: translatedLabel('toolbar.tabLabel'),
177
+ description: translatedLabel('toolbar.tabDescription'),
162
178
  fields: [
163
179
  {
164
180
  name: 'showHoverToolbar',
165
181
  type: 'checkbox',
166
- label: 'Enabled',
182
+ label: translatedLabel('toolbar.enabled'),
167
183
  defaultValue: D.showHoverToolbar
168
184
  },
169
185
  {
170
186
  name: 'hoverToolbarPosition',
171
187
  type: 'select',
172
- label: 'Anchor corner',
188
+ label: translatedLabel('toolbar.anchorCorner'),
173
189
  defaultValue: D.hoverToolbarPosition,
174
190
  options: [
175
191
  {
176
- label: 'Top right',
192
+ label: translatedLabel('toolbar.topRight'),
177
193
  value: 'top-right'
178
194
  },
179
195
  {
180
- label: 'Top left',
196
+ label: translatedLabel('toolbar.topLeft'),
181
197
  value: 'top-left'
182
198
  },
183
199
  {
184
- label: 'Bottom right',
200
+ label: translatedLabel('toolbar.bottomRight'),
185
201
  value: 'bottom-right'
186
202
  },
187
203
  {
188
- label: 'Bottom left',
204
+ label: translatedLabel('toolbar.bottomLeft'),
189
205
  value: 'bottom-left'
190
206
  }
191
207
  ]
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/global.ts"],"sourcesContent":["import type { GlobalConfig } from 'payload'\nimport { DEFAULT_BETTER_EDITOR_SETTINGS as D } from './internal/constants'\nimport {\n HOVER_OUTLINE_MAX,\n HOVER_OUTLINE_MIN,\n MOBILE_WIDTH_MAX,\n MOBILE_WIDTH_MIN,\n TABLET_WIDTH_MAX,\n TABLET_WIDTH_MIN,\n} from './internal/limits'\n\nexport const BETTER_EDITOR_SETTINGS_SLUG = 'better-editor-settings'\n\nexport const BETTER_EDITOR_SETTINGS_BANNER_FIELD = 'betterEditorSettingsBanner'\n\n// Mirrors the runtime regex in `preview/hover-css.ts` so the admin UI rejects\n// values that would silently be skipped at render time.\nconst HOVER_COLOR_RE = /^(?:#[0-9a-fA-F]{3,8}|rgba?\\([^()\\n\\r]*\\))$/i\n\nconst validateHoverColor = (value: unknown): string | true => {\n if (typeof value !== 'string' || value.length === 0) return 'Color is required'\n if (!HOVER_COLOR_RE.test(value.trim())) {\n return 'Must be a hex color (e.g. #3b82f6) or rgb()/rgba()'\n }\n return true\n}\n\nconst validateHoverOutline = (value: unknown): string | true => {\n if (typeof value !== 'number' || !Number.isFinite(value)) return 'Must be a number'\n if (value < HOVER_OUTLINE_MIN || value > HOVER_OUTLINE_MAX) {\n return `Must be between ${HOVER_OUTLINE_MIN} and ${HOVER_OUTLINE_MAX}`\n }\n return true\n}\n\nexport const betterEditorSettingsGlobal: GlobalConfig = {\n slug: BETTER_EDITOR_SETTINGS_SLUG,\n label: 'Settings',\n access: {\n read: () => true,\n },\n admin: {\n group: 'Better Editor',\n description: 'Editor-wide preferences for the Better Editor overlay.',\n },\n\n fields: [\n {\n name: 'betterEditorSettingsBanner',\n type: 'ui',\n admin: {\n components: {\n Field: 'payload-better-editor/client#SettingsBanner',\n },\n },\n },\n {\n type: 'tabs',\n tabs: [\n {\n label: 'Sidebar',\n description: 'Where the sidebar sits and how its fields are stacked.',\n fields: [\n {\n name: 'sidebarPosition',\n type: 'select',\n label: 'Position',\n defaultValue: D.sidebarPosition,\n options: [\n { label: 'Right', value: 'right' },\n { label: 'Left', value: 'left' },\n ],\n },\n {\n name: 'forceFullWidthFields',\n type: 'checkbox',\n label: 'Stack fields full-width',\n defaultValue: D.forceFullWidthFields,\n admin: {\n description:\n 'Override admin.width on sidebar fields so they always span the full row.',\n },\n },\n ],\n },\n {\n label: 'Viewport',\n description: 'Pixel widths for the Tablet and Mobile preview modes.',\n fields: [\n {\n type: 'row',\n fields: [\n {\n name: 'tabletWidth',\n type: 'number',\n label: 'Tablet (px)',\n defaultValue: D.tabletWidth,\n min: TABLET_WIDTH_MIN,\n max: TABLET_WIDTH_MAX,\n admin: { width: '50%', placeholder: String(D.tabletWidth) },\n },\n {\n name: 'mobileWidth',\n type: 'number',\n label: 'Mobile (px)',\n defaultValue: D.mobileWidth,\n min: MOBILE_WIDTH_MIN,\n max: MOBILE_WIDTH_MAX,\n admin: { width: '50%', placeholder: String(D.mobileWidth) },\n },\n ],\n },\n ],\n },\n {\n label: 'Outline',\n description: 'Outline + tint shown on the hovered or selected block.',\n fields: [\n {\n type: 'row',\n fields: [\n {\n name: 'hoverColorTopLevel',\n type: 'text',\n label: 'Top-level color',\n defaultValue: D.hoverColorTopLevel,\n validate: validateHoverColor,\n admin: {\n width: '50%',\n placeholder: D.hoverColorTopLevel,\n description: 'Hex color (e.g. `#3b82f6`).',\n },\n },\n {\n name: 'hoverColorNested',\n type: 'text',\n label: 'Nested color',\n defaultValue: D.hoverColorNested,\n validate: validateHoverColor,\n admin: {\n width: '50%',\n placeholder: D.hoverColorNested,\n description: 'Hex color for blocks nested inside another block.',\n },\n },\n ],\n },\n {\n name: 'hoverOutlineWidth',\n type: 'number',\n label: 'Outline width (px)',\n defaultValue: D.hoverOutlineWidth,\n min: HOVER_OUTLINE_MIN,\n max: HOVER_OUTLINE_MAX,\n validate: validateHoverOutline,\n admin: {\n placeholder: String(D.hoverOutlineWidth),\n description: `Outline thickness in pixels (${HOVER_OUTLINE_MIN}–${HOVER_OUTLINE_MAX}).`,\n },\n },\n ],\n },\n {\n label: 'Toolbar',\n description:\n 'Floating Move / Duplicate / Delete toolbar that appears on the selected block.',\n fields: [\n {\n name: 'showHoverToolbar',\n type: 'checkbox',\n label: 'Enabled',\n defaultValue: D.showHoverToolbar,\n },\n {\n name: 'hoverToolbarPosition',\n type: 'select',\n label: 'Anchor corner',\n defaultValue: D.hoverToolbarPosition,\n options: [\n { label: 'Top right', value: 'top-right' },\n { label: 'Top left', value: 'top-left' },\n { label: 'Bottom right', value: 'bottom-right' },\n { label: 'Bottom left', value: 'bottom-left' },\n ],\n },\n ],\n },\n ],\n },\n ],\n}\n"],"names":["DEFAULT_BETTER_EDITOR_SETTINGS","D","HOVER_OUTLINE_MAX","HOVER_OUTLINE_MIN","MOBILE_WIDTH_MAX","MOBILE_WIDTH_MIN","TABLET_WIDTH_MAX","TABLET_WIDTH_MIN","BETTER_EDITOR_SETTINGS_SLUG","BETTER_EDITOR_SETTINGS_BANNER_FIELD","HOVER_COLOR_RE","validateHoverColor","value","length","test","trim","validateHoverOutline","Number","isFinite","betterEditorSettingsGlobal","slug","label","access","read","admin","group","description","fields","name","type","components","Field","tabs","defaultValue","sidebarPosition","options","forceFullWidthFields","tabletWidth","min","max","width","placeholder","String","mobileWidth","hoverColorTopLevel","validate","hoverColorNested","hoverOutlineWidth","showHoverToolbar","hoverToolbarPosition"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/global.ts"],"sourcesContent":["import type { GlobalConfig } from 'payload'\nimport { DEFAULT_BETTER_EDITOR_SETTINGS as D } from './internal/constants'\nimport {\n HOVER_OUTLINE_MAX,\n HOVER_OUTLINE_MIN,\n MOBILE_WIDTH_MAX,\n MOBILE_WIDTH_MIN,\n TABLET_WIDTH_MAX,\n TABLET_WIDTH_MIN,\n} from './internal/limits'\nimport type { BetterEditorTranslations } from './i18n/types'\nimport { en } from './i18n/en'\nimport { de } from './i18n/de'\n\nexport const BETTER_EDITOR_SETTINGS_SLUG = 'better-editor-settings'\n\nexport const BETTER_EDITOR_SETTINGS_BANNER_FIELD = 'betterEditorSettingsBanner'\n\n// Mirrors the runtime regex in `preview/hover-css.ts` so the admin UI rejects\n// values that would silently be skipped at render time.\nconst HOVER_COLOR_RE = /^(?:#[0-9a-fA-F]{3,8}|rgba?\\([^()\\n\\r]*\\))$/i\n\n// Payload's TFunction is strictly typed to known keys — cast to allow custom plugin keys.\ntype AnyT = (key: string) => string\n\nconst settingsKey = (path: string) => `betterEditor:settings.${path}`\n\n// Locales the plugin ships built-in translations for.\nconst SETTINGS_TRANSLATIONS: Record<string, BetterEditorTranslations['settings']> = {\n en: en.settings,\n de: de.settings,\n}\n\nconst lookupSetting = (settings: BetterEditorTranslations['settings'], path: string): string =>\n path\n .split('.')\n .reduce<unknown>((value, key) => (value as Record<string, unknown> | undefined)?.[key], settings) as string\n\n// Entity/field labels and descriptions are serialized into the admin RootLayout\n// (a Client Component), so they must be plain data — a function (e.g. `({ t }) => …`)\n// can't cross that RSC boundary. Return a Payload locale map built from our bundled\n// translations; Payload selects the entry for the admin UI language. (Runtime `t()`\n// stays available for `validate`, which Payload strips before client serialization.)\nconst translatedLabel = (path: string): Record<string, string> =>\n Object.fromEntries(\n Object.entries(SETTINGS_TRANSLATIONS).map(([locale, settings]) => [locale, lookupSetting(settings, path)]),\n )\n\nconst validateHoverColor = (value: unknown, args: unknown): string | true => {\n const t: AnyT = (args as { t?: AnyT })?.t ?? ((k) => k)\n if (typeof value !== 'string' || value.length === 0) return t(settingsKey('validation.colorRequired'))\n if (!HOVER_COLOR_RE.test(value.trim())) return t(settingsKey('validation.colorInvalid'))\n return true\n}\n\nconst validateHoverOutline = (value: unknown, args: unknown): string | true => {\n const t: AnyT = (args as { t?: AnyT })?.t ?? ((k) => k)\n if (typeof value !== 'number' || !Number.isFinite(value)) return t(settingsKey('validation.mustBeNumber'))\n if (value < HOVER_OUTLINE_MIN || value > HOVER_OUTLINE_MAX) return t(settingsKey('validation.outlineRange'))\n return true\n}\n\nexport const betterEditorSettingsGlobal: GlobalConfig = {\n slug: BETTER_EDITOR_SETTINGS_SLUG,\n label: translatedLabel('globalLabel'),\n access: {\n read: () => true,\n },\n admin: {\n group: 'Better Editor',\n description: translatedLabel('globalDescription'),\n },\n\n fields: [\n {\n name: 'betterEditorSettingsBanner',\n type: 'ui',\n admin: {\n components: {\n Field: 'payload-better-editor/client#SettingsBanner',\n },\n },\n },\n {\n type: 'tabs',\n tabs: [\n {\n label: translatedLabel('sidebar.tabLabel'),\n description: translatedLabel('sidebar.tabDescription'),\n fields: [\n {\n name: 'sidebarPosition',\n type: 'select',\n label: translatedLabel('sidebar.position'),\n defaultValue: D.sidebarPosition,\n options: [\n { label: translatedLabel('sidebar.positionRight'), value: 'right' },\n { label: translatedLabel('sidebar.positionLeft'), value: 'left' },\n ],\n },\n {\n name: 'forceFullWidthFields',\n type: 'checkbox',\n label: translatedLabel('sidebar.forceFullWidth'),\n defaultValue: D.forceFullWidthFields,\n admin: {\n description: translatedLabel('sidebar.forceFullWidthDesc'),\n },\n },\n ],\n },\n {\n label: translatedLabel('viewport.tabLabel'),\n description: translatedLabel('viewport.tabDescription'),\n fields: [\n {\n type: 'row',\n fields: [\n {\n name: 'tabletWidth',\n type: 'number',\n label: translatedLabel('viewport.tabletWidth'),\n defaultValue: D.tabletWidth,\n min: TABLET_WIDTH_MIN,\n max: TABLET_WIDTH_MAX,\n admin: { width: '50%', placeholder: String(D.tabletWidth) },\n },\n {\n name: 'mobileWidth',\n type: 'number',\n label: translatedLabel('viewport.mobileWidth'),\n defaultValue: D.mobileWidth,\n min: MOBILE_WIDTH_MIN,\n max: MOBILE_WIDTH_MAX,\n admin: { width: '50%', placeholder: String(D.mobileWidth) },\n },\n ],\n },\n ],\n },\n {\n label: translatedLabel('outline.tabLabel'),\n description: translatedLabel('outline.tabDescription'),\n fields: [\n {\n type: 'row',\n fields: [\n {\n name: 'hoverColorTopLevel',\n type: 'text',\n label: translatedLabel('outline.topLevelColor'),\n defaultValue: D.hoverColorTopLevel,\n validate: validateHoverColor,\n admin: {\n width: '50%',\n placeholder: D.hoverColorTopLevel,\n description: translatedLabel('outline.topLevelColorDesc'),\n },\n },\n {\n name: 'hoverColorNested',\n type: 'text',\n label: translatedLabel('outline.nestedColor'),\n defaultValue: D.hoverColorNested,\n validate: validateHoverColor,\n admin: {\n width: '50%',\n placeholder: D.hoverColorNested,\n description: translatedLabel('outline.nestedColorDesc'),\n },\n },\n ],\n },\n {\n name: 'hoverOutlineWidth',\n type: 'number',\n label: translatedLabel('outline.outlineWidth'),\n defaultValue: D.hoverOutlineWidth,\n min: HOVER_OUTLINE_MIN,\n max: HOVER_OUTLINE_MAX,\n validate: validateHoverOutline,\n admin: {\n placeholder: String(D.hoverOutlineWidth),\n description: translatedLabel('outline.outlineWidthDesc'),\n },\n },\n ],\n },\n {\n label: translatedLabel('toolbar.tabLabel'),\n description: translatedLabel('toolbar.tabDescription'),\n fields: [\n {\n name: 'showHoverToolbar',\n type: 'checkbox',\n label: translatedLabel('toolbar.enabled'),\n defaultValue: D.showHoverToolbar,\n },\n {\n name: 'hoverToolbarPosition',\n type: 'select',\n label: translatedLabel('toolbar.anchorCorner'),\n defaultValue: D.hoverToolbarPosition,\n options: [\n { label: translatedLabel('toolbar.topRight'), value: 'top-right' },\n { label: translatedLabel('toolbar.topLeft'), value: 'top-left' },\n { label: translatedLabel('toolbar.bottomRight'), value: 'bottom-right' },\n { label: translatedLabel('toolbar.bottomLeft'), value: 'bottom-left' },\n ],\n },\n ],\n },\n ],\n },\n ],\n}\n"],"names":["DEFAULT_BETTER_EDITOR_SETTINGS","D","HOVER_OUTLINE_MAX","HOVER_OUTLINE_MIN","MOBILE_WIDTH_MAX","MOBILE_WIDTH_MIN","TABLET_WIDTH_MAX","TABLET_WIDTH_MIN","en","de","BETTER_EDITOR_SETTINGS_SLUG","BETTER_EDITOR_SETTINGS_BANNER_FIELD","HOVER_COLOR_RE","settingsKey","path","SETTINGS_TRANSLATIONS","settings","lookupSetting","split","reduce","value","key","translatedLabel","Object","fromEntries","entries","map","locale","validateHoverColor","args","t","k","length","test","trim","validateHoverOutline","Number","isFinite","betterEditorSettingsGlobal","slug","label","access","read","admin","group","description","fields","name","type","components","Field","tabs","defaultValue","sidebarPosition","options","forceFullWidthFields","tabletWidth","min","max","width","placeholder","String","mobileWidth","hoverColorTopLevel","validate","hoverColorNested","hoverOutlineWidth","showHoverToolbar","hoverToolbarPosition"],"mappings":"AACA,SAASA,kCAAkCC,CAAC,QAAQ,uBAAsB;AAC1E,SACEC,iBAAiB,EACjBC,iBAAiB,EACjBC,gBAAgB,EAChBC,gBAAgB,EAChBC,gBAAgB,EAChBC,gBAAgB,QACX,oBAAmB;AAE1B,SAASC,EAAE,QAAQ,YAAW;AAC9B,SAASC,EAAE,QAAQ,YAAW;AAE9B,OAAO,MAAMC,8BAA8B,yBAAwB;AAEnE,OAAO,MAAMC,sCAAsC,6BAA4B;AAE/E,8EAA8E;AAC9E,wDAAwD;AACxD,MAAMC,iBAAiB;AAKvB,MAAMC,cAAc,CAACC,OAAiB,CAAC,sBAAsB,EAAEA,MAAM;AAErE,sDAAsD;AACtD,MAAMC,wBAA8E;IAClFP,IAAIA,GAAGQ,QAAQ;IACfP,IAAIA,GAAGO,QAAQ;AACjB;AAEA,MAAMC,gBAAgB,CAACD,UAAgDF,OACrEA,KACGI,KAAK,CAAC,KACNC,MAAM,CAAU,CAACC,OAAOC,MAASD,OAA+C,CAACC,IAAI,EAAEL;AAE5F,gFAAgF;AAChF,sFAAsF;AACtF,oFAAoF;AACpF,oFAAoF;AACpF,qFAAqF;AACrF,MAAMM,kBAAkB,CAACR,OACvBS,OAAOC,WAAW,CAChBD,OAAOE,OAAO,CAACV,uBAAuBW,GAAG,CAAC,CAAC,CAACC,QAAQX,SAAS,GAAK;YAACW;YAAQV,cAAcD,UAAUF;SAAM;AAG7G,MAAMc,qBAAqB,CAACR,OAAgBS;IAC1C,MAAMC,IAAU,AAACD,MAAuBC,KAAM,CAAA,CAACC,IAAMA,CAAAA;IACrD,IAAI,OAAOX,UAAU,YAAYA,MAAMY,MAAM,KAAK,GAAG,OAAOF,EAAEjB,YAAY;IAC1E,IAAI,CAACD,eAAeqB,IAAI,CAACb,MAAMc,IAAI,KAAK,OAAOJ,EAAEjB,YAAY;IAC7D,OAAO;AACT;AAEA,MAAMsB,uBAAuB,CAACf,OAAgBS;IAC5C,MAAMC,IAAU,AAACD,MAAuBC,KAAM,CAAA,CAACC,IAAMA,CAAAA;IACrD,IAAI,OAAOX,UAAU,YAAY,CAACgB,OAAOC,QAAQ,CAACjB,QAAQ,OAAOU,EAAEjB,YAAY;IAC/E,IAAIO,QAAQjB,qBAAqBiB,QAAQlB,mBAAmB,OAAO4B,EAAEjB,YAAY;IACjF,OAAO;AACT;AAEA,OAAO,MAAMyB,6BAA2C;IACtDC,MAAM7B;IACN8B,OAAOlB,gBAAgB;IACvBmB,QAAQ;QACNC,MAAM,IAAM;IACd;IACAC,OAAO;QACLC,OAAO;QACPC,aAAavB,gBAAgB;IAC/B;IAEAwB,QAAQ;QACN;YACEC,MAAM;YACNC,MAAM;YACNL,OAAO;gBACLM,YAAY;oBACVC,OAAO;gBACT;YACF;QACF;QACA;YACEF,MAAM;YACNG,MAAM;gBACJ;oBACEX,OAAOlB,gBAAgB;oBACvBuB,aAAavB,gBAAgB;oBAC7BwB,QAAQ;wBACN;4BACEC,MAAM;4BACNC,MAAM;4BACNR,OAAOlB,gBAAgB;4BACvB8B,cAAcnD,EAAEoD,eAAe;4BAC/BC,SAAS;gCACP;oCAAEd,OAAOlB,gBAAgB;oCAA0BF,OAAO;gCAAQ;gCAClE;oCAAEoB,OAAOlB,gBAAgB;oCAAyBF,OAAO;gCAAO;6BACjE;wBACH;wBACA;4BACE2B,MAAM;4BACNC,MAAM;4BACNR,OAAOlB,gBAAgB;4BACvB8B,cAAcnD,EAAEsD,oBAAoB;4BACpCZ,OAAO;gCACLE,aAAavB,gBAAgB;4BAC/B;wBACF;qBACD;gBACH;gBACA;oBACEkB,OAAOlB,gBAAgB;oBACvBuB,aAAavB,gBAAgB;oBAC7BwB,QAAQ;wBACN;4BACEE,MAAM;4BACNF,QAAQ;gCACN;oCACEC,MAAM;oCACNC,MAAM;oCACNR,OAAOlB,gBAAgB;oCACvB8B,cAAcnD,EAAEuD,WAAW;oCAC3BC,KAAKlD;oCACLmD,KAAKpD;oCACLqC,OAAO;wCAAEgB,OAAO;wCAAOC,aAAaC,OAAO5D,EAAEuD,WAAW;oCAAE;gCAC5D;gCACA;oCACET,MAAM;oCACNC,MAAM;oCACNR,OAAOlB,gBAAgB;oCACvB8B,cAAcnD,EAAE6D,WAAW;oCAC3BL,KAAKpD;oCACLqD,KAAKtD;oCACLuC,OAAO;wCAAEgB,OAAO;wCAAOC,aAAaC,OAAO5D,EAAE6D,WAAW;oCAAE;gCAC5D;6BACD;wBACH;qBACD;gBACH;gBACA;oBACEtB,OAAOlB,gBAAgB;oBACvBuB,aAAavB,gBAAgB;oBAC7BwB,QAAQ;wBACN;4BACEE,MAAM;4BACNF,QAAQ;gCACN;oCACEC,MAAM;oCACNC,MAAM;oCACNR,OAAOlB,gBAAgB;oCACvB8B,cAAcnD,EAAE8D,kBAAkB;oCAClCC,UAAUpC;oCACVe,OAAO;wCACLgB,OAAO;wCACPC,aAAa3D,EAAE8D,kBAAkB;wCACjClB,aAAavB,gBAAgB;oCAC/B;gCACF;gCACA;oCACEyB,MAAM;oCACNC,MAAM;oCACNR,OAAOlB,gBAAgB;oCACvB8B,cAAcnD,EAAEgE,gBAAgB;oCAChCD,UAAUpC;oCACVe,OAAO;wCACLgB,OAAO;wCACPC,aAAa3D,EAAEgE,gBAAgB;wCAC/BpB,aAAavB,gBAAgB;oCAC/B;gCACF;6BACD;wBACH;wBACA;4BACEyB,MAAM;4BACNC,MAAM;4BACNR,OAAOlB,gBAAgB;4BACvB8B,cAAcnD,EAAEiE,iBAAiB;4BACjCT,KAAKtD;4BACLuD,KAAKxD;4BACL8D,UAAU7B;4BACVQ,OAAO;gCACLiB,aAAaC,OAAO5D,EAAEiE,iBAAiB;gCACvCrB,aAAavB,gBAAgB;4BAC/B;wBACF;qBACD;gBACH;gBACA;oBACEkB,OAAOlB,gBAAgB;oBACvBuB,aAAavB,gBAAgB;oBAC7BwB,QAAQ;wBACN;4BACEC,MAAM;4BACNC,MAAM;4BACNR,OAAOlB,gBAAgB;4BACvB8B,cAAcnD,EAAEkE,gBAAgB;wBAClC;wBACA;4BACEpB,MAAM;4BACNC,MAAM;4BACNR,OAAOlB,gBAAgB;4BACvB8B,cAAcnD,EAAEmE,oBAAoB;4BACpCd,SAAS;gCACP;oCAAEd,OAAOlB,gBAAgB;oCAAqBF,OAAO;gCAAY;gCACjE;oCAAEoB,OAAOlB,gBAAgB;oCAAoBF,OAAO;gCAAW;gCAC/D;oCAAEoB,OAAOlB,gBAAgB;oCAAwBF,OAAO;gCAAe;gCACvE;oCAAEoB,OAAOlB,gBAAgB;oCAAuBF,OAAO;gCAAc;6BACtE;wBACH;qBACD;gBACH;aACD;QACH;KACD;AACH,EAAC"}
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
  import { useCallback, useEffect, useRef } from 'react';
3
- import { HoverToolbarController } from '../preview/HoverToolbarController';
3
+ import { HoverToolbarController, toHoverToolbarLabels } from '../preview/HoverToolbarController';
4
+ import { useBetterEditorT } from '../i18n/useBetterEditorT';
4
5
  import { installClickToFocus } from '../preview/installClickToFocus';
5
6
  import { installHoverStyles } from '../preview/installHoverStyles';
6
7
  import { BLOCK_ID_SELECTOR } from '../internal/dom';
@@ -11,6 +12,8 @@ import { useLatestRef } from './useLatestRef';
11
12
  * lifecycle. Idempotent: tears down previous bindings before installing
12
13
  * new ones, and unbinds on unmount.
13
14
  */ export const usePreviewBinding = ({ iframeRef, settings, interactModeRef, onFocusBlock, onBlockAction, onLoadingChange })=>{
15
+ const t = useBetterEditorT();
16
+ const labelsRef = useLatestRef(t.blocks.actions);
14
17
  const teardownRef = useRef(null);
15
18
  const controllerRef = useRef(null);
16
19
  const isBoundRef = useRef(false);
@@ -39,7 +42,8 @@ import { useLatestRef } from './useLatestRef';
39
42
  controllerRef.current = new HoverToolbarController(doc, {
40
43
  position: s.hoverToolbarPosition,
41
44
  outlineWidth: s.hoverOutlineWidth,
42
- onAction: (id, action)=>onBlockActionRef.current(id, action)
45
+ onAction: (id, action)=>onBlockActionRef.current(id, action),
46
+ labels: toHoverToolbarLabels(labelsRef.current)
43
47
  });
44
48
  }
45
49
  // Dev-only sanity check: zero [data-better-editor-id] elements means