@ablogcms/plugins 3.2.37 → 3.2.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,9 +15,11 @@ register('acms-plugin-sample', {
15
15
  version: '1.0.0',
16
16
  setup(ctx) {
17
17
  // ゲート: アップロード前の確認
18
- ctx.events.on('media.upload.before', async (event) => {
18
+ ctx.events.on('media.upload.before', async (payload, gate) => {
19
19
  const ok = await ACMS.Library.dialog.confirm('確認…');
20
- return ok ? event : false;
20
+ if (!ok) {
21
+ gate.cancel('アップロードを取り消しました');
22
+ }
21
23
  });
22
24
 
23
25
  // 通知: アップロード完了後の処理
@@ -36,3 +38,9 @@ register('acms-plugin-sample', {
36
38
  - `unregister(name)`: `setup(ctx)` 内で行ったイベント購読・レジストリ登録・Fill をすべて自動解除する。
37
39
  - `get(name)` / `getAll()`: 登録済みプラグインを取得する(デバッグ用)。
38
40
  - `setup()` が同期的に throw した場合、途中まで行われた登録は自動でロールバックされる。
41
+
42
+ ## プラグインで使えるグローバルと externals
43
+
44
+ プラグインに同梱してはいけない依存(React・react-dom・Tiptap など)と、`@ablogcms/components` の公開部品の
45
+ 一覧・externals の書き方は [HOOKS.md「プラグイン側のビルド設定」](./HOOKS.md) を参照。
46
+ 管理画面の初期化前に実行された場合の待ち方(`ACMS.adminReady`)も同節にある。
@@ -95,9 +95,9 @@ function createPluginRegistry(options = {}) {
95
95
  let hasI18nCleanup = false;
96
96
  const onEvent = (type, handler) => {
97
97
  const label = toEventLabel(type);
98
- const wrapped = async (event) => {
98
+ const wrapped = async (event, gateCtx) => {
99
99
  try {
100
- return await handler(event);
100
+ return await handler(event, gateCtx);
101
101
  } catch (err) {
102
102
  logHandlerError(plugin.name, label, err);
103
103
  throw err;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/create-plugin-registry.ts","../../src/core/create-registry.ts","../../src/core/create-viewed-registry.ts","../../src/core/resolve-fill-entry.ts","../../src/core/merge-registry-entries.ts","../../src/core/global-singletons.ts"],"sourcesContent":["import type { AcmsEventType, AcmsEvents, AcmsLooseEvent, Unsubscribe } from '@ablogcms/events';\nimport { createEventBus } from '@ablogcms/events/core';\nimport { createSlotFillStore, type SlotFillStore, type FillRenderer } from '@ablogcms/components/slot-fill';\nimport type { Action, BulkAction, ColumnTypeDef, Menu, RowData } from '@ablogcms/components/dataview/types';\nimport type { UnitDefInterface } from '@ablogcms/unit-editor/core/types/unit';\nimport { createKeyboardShortcutRegistry } from '@ablogcms/keyboard-shortcut';\nimport type { KeyboardShortcutRegistry } from '@ablogcms/keyboard-shortcut';\nimport { createI18nResourceRegistry, type I18nResourceRegistry } from '@ablogcms/i18n/core';\nimport { createRegistry } from './create-registry';\nimport { createViewedRegistry, type ViewedRegistry } from './create-viewed-registry';\nimport { resolveFillEntry } from './resolve-fill-entry';\nimport { withFillProps } from './with-fill-props';\nimport type { BlockDefinitionFactory, BlockExtensionFactory } from './global-singletons';\nimport type {\n AcmsPlugins,\n FillEntry,\n PluginContext,\n PluginDefinition,\n RegisteredEntry,\n RegisteredPlugin,\n Registry,\n} from './types';\n\nexport interface CreatePluginRegistryOptions {\n /** 委譲先のイベントバス。省略時は自己完結したインスタンスを新規作成する(テスト用の既定値) */\n eventsBus?: AcmsEvents;\n /** `ctx.ui.fill` の書き込み先。省略時は自己完結したインスタンスを新規作成する(テスト用の既定値) */\n fillStore?: SlotFillStore;\n /** `ctx.unitEditor.registerUnitDefinition` の登録先。省略時は自己完結したインスタンスを新規作成する */\n unitDefinitionRegistry?: Registry<UnitDefInterface>;\n /** `ctx.dataview.registerColumnType` の登録先。省略時は自己完結したインスタンスを新規作成する */\n columnTypeRegistry?: Registry<ColumnTypeDef>;\n /** `ctx.blockEditor.registerBlockDefinition` の登録先。省略時は自己完結したインスタンスを新規作成する */\n blockDefinitionRegistry?: Registry<BlockDefinitionFactory>;\n /** `ctx.blockEditor.registerExtension` の登録先。省略時は自己完結したインスタンスを新規作成する */\n blockExtensionRegistry?: Registry<BlockExtensionFactory>;\n /** `ctx.keyboardShortcuts` の登録先。省略時は自己完結したインスタンスを新規作成する */\n keyboardShortcutRegistry?: KeyboardShortcutRegistry;\n\n /** `ctx.i18n` の登録先。省略時は自己完結したインスタンスを新規作成する */\n i18nResourceRegistry?: I18nResourceRegistry;\n /** `ctx.dataview.registerAction` の登録先。省略時は自己完結したインスタンスを新規作成する */\n dataviewActionRegistry?: ViewedRegistry<Action<RowData>>;\n /** `ctx.dataview.registerBulkAction` の登録先。省略時は自己完結したインスタンスを新規作成する */\n dataviewBulkActionRegistry?: ViewedRegistry<BulkAction<RowData>>;\n /** `ctx.dataview.registerMenu` の登録先。省略時は自己完結したインスタンスを新規作成する */\n dataviewMenuRegistry?: ViewedRegistry<Menu<RowData>>;\n}\n\ninterface InternalPlugin {\n name: string;\n version?: string;\n registrations: RegisteredEntry[];\n subscriptions: Unsubscribe[];\n}\n\n// AcmsEvents#on は型引数 K ごとにハンドラの戻り値を絞り込むため、type がユニオン\n// (AcmsEventType | AcmsEventType[])のまま渡すとハンドラの戻り値を厳密に検証できない。\n// create-event-bus.ts と同じく、内部では緩い型で扱い、公開 API の境界(PluginContext)でのみ\n// 厳密な型へキャストする。\ntype LooseOn = (type: AcmsEventType | AcmsEventType[], handler: (event: AcmsLooseEvent) => unknown) => Unsubscribe;\n\n// プラグイン起因の例外をどのプラグインが投げたか特定できるよう帰属を明示する。\n// イベントバス自身も汎用メッセージで同じ例外をログするため、この行は「どのプラグインか」を示す追加の帰属ログになる。\nconst logHandlerError = (pluginName: string, eventLabel: string, err: unknown): void => {\n console.error(`[@ablogcms/plugins] プラグイン \"${pluginName}\" のハンドラ(\"${eventLabel}\")が例外を投げました。`, err);\n};\n\nconst toEventLabel = (type: AcmsEventType | AcmsEventType[]): string => (Array.isArray(type) ? type.join(',') : type);\n\nconst toKeyboardShortcutRegistrationId = (pluginName: string, id: string): string => `plugin:${pluginName}:${id}`;\n\n/**\n * `window.ACMS.Config` からプラグインの設定値を読む。プラグイン名は `-`/`_` 区切りのことが多いため、\n * `jsModule()` 側の慣例(キャメルケースキー)に合わせて変換する。未初期化・未設定時は空オブジェクトを返し、\n * `setup(ctx)` 内で `ctx.config` を参照しただけで例外にならないようにする。\n */\nconst readConfig = (pluginName: string): Record<string, unknown> => {\n if (typeof window === 'undefined') {\n return {};\n }\n const camelName = pluginName.replace(/[-_](\\w)/g, (_match, chr: string) => chr.toUpperCase());\n const config = (window as unknown as { ACMS?: { Config?: Record<string, unknown> } }).ACMS?.Config;\n const value = config?.[camelName];\n return typeof value === 'object' && value !== null ? (value as Record<string, unknown>) : {};\n};\n\n/**\n * `ACMS.plugins` の純粋実装(グローバル非依存)。VS Code の `activate(context)` +\n * `context.subscriptions` を範に、`setup(ctx)` 内でのイベント購読・レジストリ登録・UI 差し込みを\n * すべて内部の subscriptions 配列に集約し、`unregister(name)` で一括自動回収する。\n *\n * 依存(イベントバス・Fill ブリッジ・各レジストリ)はすべて注入可能で、省略時は自己完結した\n * インスタンスを新規作成する(`@ablogcms/events` の `createEventBus()` と同じ設計。グローバル\n * シングルトンへの結線は本番の bootstrap(admin.js)が `global-singletons.ts` 経由で明示的に行う)。\n */\nexport function createPluginRegistry(options: CreatePluginRegistryOptions = {}): AcmsPlugins {\n const eventsBus = options.eventsBus ?? createEventBus();\n const fillStore = options.fillStore ?? createSlotFillStore();\n const unitDefinitionRegistry = options.unitDefinitionRegistry ?? createRegistry<UnitDefInterface>('unit-definition');\n const columnTypeRegistry = options.columnTypeRegistry ?? createRegistry<ColumnTypeDef>('column-type');\n const blockDefinitionRegistry =\n options.blockDefinitionRegistry ?? createRegistry<BlockDefinitionFactory>('block-definition');\n const blockExtensionRegistry = options.blockExtensionRegistry ?? createRegistry<BlockExtensionFactory>('extension');\n const keyboardShortcutRegistry = options.keyboardShortcutRegistry ?? createKeyboardShortcutRegistry();\n const i18nResourceRegistry = options.i18nResourceRegistry ?? createI18nResourceRegistry();\n const dataviewActionRegistry =\n options.dataviewActionRegistry ?? createViewedRegistry<Action<RowData>>('dataview-action');\n const dataviewBulkActionRegistry =\n options.dataviewBulkActionRegistry ?? createViewedRegistry<BulkAction<RowData>>('dataview-bulk-action');\n const dataviewMenuRegistry = options.dataviewMenuRegistry ?? createViewedRegistry<Menu<RowData>>('dataview-menu');\n\n const plugins = new Map<string, InternalPlugin>();\n let fillIdCounter = 0;\n\n const createContext = (plugin: InternalPlugin): PluginContext => {\n /** そのプラグインの i18n 後始末を subscriptions へ積んだか(積むのは初回の addResources だけ) */\n let hasI18nCleanup = false;\n const onEvent = (\n type: AcmsEventType | AcmsEventType[],\n handler: (event: AcmsLooseEvent) => unknown\n ): Unsubscribe => {\n const label = toEventLabel(type);\n const wrapped = async (event: AcmsLooseEvent) => {\n try {\n return await handler(event);\n } catch (err) {\n logHandlerError(plugin.name, label, err);\n throw err;\n }\n };\n const unsubscribe = (eventsBus.on as LooseOn)(type, wrapped);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'event', key: label });\n return unsubscribe;\n };\n\n return {\n name: plugin.name,\n config: readConfig(plugin.name),\n events: {\n on: onEvent as PluginContext['events']['on'],\n },\n unitEditor: {\n registerUnitDefinition: (name, def) => {\n const unsubscribe = unitDefinitionRegistry.add(name, def);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'unit-definition', key: name });\n return unsubscribe;\n },\n },\n blockEditor: {\n registerBlockDefinition: (name, factory) => {\n const unsubscribe = blockDefinitionRegistry.add(name, factory);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'block-definition', key: name });\n return unsubscribe;\n },\n registerExtension: (name, factory) => {\n const unsubscribe = blockExtensionRegistry.add(name, factory);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'extension', key: name });\n return unsubscribe;\n },\n },\n keyboardShortcuts: {\n registerCategory: (id, category) => {\n const unsubscribe = keyboardShortcutRegistry.registerCategory(\n toKeyboardShortcutRegistrationId(plugin.name, id),\n category\n );\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'keyboard-shortcut-category', key: id });\n return unsubscribe;\n },\n registerShortcut: (id, shortcut) => {\n const unsubscribe = keyboardShortcutRegistry.registerShortcut(\n toKeyboardShortcutRegistrationId(plugin.name, id),\n {\n ...shortcut,\n categoryId: toKeyboardShortcutRegistrationId(plugin.name, shortcut.categoryId),\n }\n );\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'keyboard-shortcut', key: id });\n return unsubscribe;\n },\n },\n dataview: {\n registerColumnType: (name, type) => {\n const unsubscribe = columnTypeRegistry.add(name, type);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'column-type', key: name });\n return unsubscribe;\n },\n registerAction: (view, name, def) => {\n const unsubscribe = dataviewActionRegistry.add(view, name, def);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'dataview-action', key: `${view}:${name}` });\n return unsubscribe;\n },\n registerBulkAction: (view, name, def) => {\n const unsubscribe = dataviewBulkActionRegistry.add(view, name, def);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'dataview-bulk-action', key: `${view}:${name}` });\n return unsubscribe;\n },\n registerMenu: (view, name, def) => {\n const unsubscribe = dataviewMenuRegistry.add(view, name, def);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'dataview-menu', key: `${view}:${name}` });\n return unsubscribe;\n },\n },\n i18n: {\n // 名前空間をプラグイン名に固定する。プラグイン側で自由に決められると、コアの\n // `translation` や他プラグインとキーが衝突しうるため、名乗りは registry 側で与える。\n addResources: (lng, resources) => {\n i18nResourceRegistry.add(plugin.name, lng, resources);\n plugin.registrations.push({ kind: 'i18n', key: lng });\n // 破棄は名前空間(=プラグイン名)単位なので、何度 addResources しても後始末は 1 つでよい。\n // 呼び出し回数ぶん積むと unregister 時に remove が空振りで複数回走り、購読側の\n // forget(i18next の removeResourceBundle)も無駄に繰り返されるため、初回だけ積む。\n if (!hasI18nCleanup) {\n hasI18nCleanup = true;\n plugin.subscriptions.push(() => i18nResourceRegistry.remove(plugin.name));\n }\n },\n },\n ui: {\n fill: <T>(slotName: string, entry: FillEntry<T>) => {\n fillIdCounter += 1;\n const id = `plugin:${plugin.name}:${slotName}:${fillIdCounter}`;\n // fillStore(Slot 名ごとに異なる T を型消去した FillRenderer = FillRenderer<unknown> で\n // 保持する)へ渡す境界。Fill コンポーネント(@ablogcms/components/slot-fill)の\n // eraseFillRendererType と同じ理由・同じ境界でここでも明示キャストする。\n const render = resolveFillEntry<T>(entry) as FillRenderer;\n fillStore.upsertFill(slotName, id, render);\n const unsubscribe = () => fillStore.removeFill(slotName, id);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'fill', key: slotName });\n return unsubscribe;\n },\n },\n };\n };\n\n const register = (name: string, definition: PluginDefinition): void => {\n if (plugins.has(name)) {\n throw new Error(`[@ablogcms/plugins] プラグイン名 \"${name}\" は既に登録されています。`);\n }\n\n const plugin: InternalPlugin = { name, version: definition.version, registrations: [], subscriptions: [] };\n // setup() 実行前に登録しておく。setup() の途中で ctx 経由の登録(例: 名前衝突での throw)が\n // 失敗した場合に catch 節でロールバックできるようにするため。\n plugins.set(name, plugin);\n\n try {\n definition.setup(createContext(plugin));\n } catch (err) {\n // 途中まで行われた登録(イベント購読・レジストリ登録・Fill)をすべて解除し、ゾンビ状態の\n // 半登録プラグインを残さない。呼び出し元は同じ名前で再度 register し直せる。\n plugin.subscriptions.forEach((unsubscribe) => unsubscribe());\n plugins.delete(name);\n throw err;\n }\n };\n\n const unregister = (name: string): boolean => {\n const plugin = plugins.get(name);\n if (!plugin) {\n return false;\n }\n plugin.subscriptions.forEach((unsubscribe) => unsubscribe());\n plugins.delete(name);\n return true;\n };\n\n const toRegisteredPlugin = (plugin: InternalPlugin): RegisteredPlugin => ({\n name: plugin.name,\n version: plugin.version,\n registrations: plugin.registrations,\n });\n\n const get = (name: string): RegisteredPlugin | undefined => {\n const plugin = plugins.get(name);\n return plugin ? toRegisteredPlugin(plugin) : undefined;\n };\n\n const getAll = (): RegisteredPlugin[] => Array.from(plugins.values()).map(toRegisteredPlugin);\n\n return { register, unregister, get, getAll, withFillProps };\n}\n","import type { Registry, Unsubscribe } from './types';\n\n/**\n * 名前衝突を検知する汎用レジストリの純粋実装。`ctx.unitEditor.registerUnitDefinition` /\n * `ctx.dataview.registerColumnType` の土台(Directus の `defineInterface` 等と同型)。\n *\n * `add()` が返す `Unsubscribe` は、登録時点の値を閉じ込めて比較してから削除する。\n * 「解除 → 同名で再登録」の後に古い `Unsubscribe` が誤って新しい登録を消してしまう事故を防ぐ\n * (`name` は一意だが、`Unsubscribe` のライフサイクルは呼び出し側が保持し続けるため)。\n */\nexport function createRegistry<T>(label: string): Registry<T> {\n const items = new Map<string, T>();\n\n const add = (name: string, item: T): Unsubscribe => {\n if (items.has(name)) {\n throw new Error(`[@ablogcms/plugins] ${label} \"${name}\" は既に登録されています。`);\n }\n items.set(name, item);\n return () => {\n if (items.get(name) === item) {\n items.delete(name);\n }\n };\n };\n\n const remove = (name: string): boolean => items.delete(name);\n\n const get = (name: string): T | undefined => items.get(name);\n\n const getAll = (): Record<string, T> => Object.fromEntries(items);\n\n return { add, remove, get, getAll };\n}\n","import type { Registry, Unsubscribe } from './types';\nimport { createRegistry } from './create-registry';\n\n/**\n * `view`(`'entry' | 'module'` 等、将来拡張可能な文字列)ごとに独立した名前空間を持つレジストリ。\n * `ctx.dataview.registerAction(view, name, def)` の土台(design.md Q4「view キー方式」)。\n *\n * 内部では `view` ごとに素の {@link createRegistry} インスタンスを遅延生成して保持する\n * (文字列連結キー方式にしない理由: view 名に区切り文字が含まれた場合の衝突を避けるため)。\n */\nexport interface ViewedRegistry<T> {\n /** `view` 内で `name` が既に登録済みの場合は throw する */\n add(view: string, name: string, item: T): Unsubscribe;\n remove(view: string, name: string): boolean;\n get(view: string, name: string): T | undefined;\n /** 指定した `view` に登録された項目のみを返す。未登録の `view` は空オブジェクト */\n getAll(view: string): Record<string, T>;\n}\n\nexport function createViewedRegistry<T>(label: string): ViewedRegistry<T> {\n const registries = new Map<string, Registry<T>>();\n\n const registryFor = (view: string): Registry<T> => {\n let registry = registries.get(view);\n if (!registry) {\n registry = createRegistry<T>(`${label}(${view})`);\n registries.set(view, registry);\n }\n return registry;\n };\n\n return {\n add: (view, name, item) => registryFor(view).add(name, item),\n remove: (view, name) => registryFor(view).remove(name),\n get: (view, name) => registryFor(view).get(name),\n getAll: (view) => registries.get(view)?.getAll() ?? {},\n };\n}\n","import { createElement, type ComponentType, type FunctionComponent, type ReactNode } from 'react';\nimport { DomFillMount } from '@ablogcms/components/slot-fill';\nimport type { FillRenderer } from '@ablogcms/components/slot-fill';\nimport { isFillComponentEntry } from './with-fill-props';\nimport type { DomFill, FillEntry } from './types';\n\n/**\n * `ctx.ui.fill(slotName, entry)` の `entry` を、Fill ストア(`@ablogcms/components/slot-fill`)に\n * そのまま渡せる `FillRenderer`(`ReactNode`、または `Slot` の `fillProps` を受け取る render-prop\n * 関数)に変換する。\n *\n * 判別は 3 種類:\n * 1. `withFillProps(Component)` が返すマーカーオブジェクト(`FillComponentEntry`)→ `fillProps` を\n * 受け取る render-prop 関数を返す(下記参照)。\n * 2. 仮引数 1 個以上の関数 → `DomFill` として `DomFillMount` でラップする。\n * 3. それ以外(仮引数 0 個の関数)→ props なしの React コンポーネントとして描画する。\n *\n * 2/3 の判別は Why not: 実行時には両者とも「関数」という点で構造的に区別できず\n * (`React.ComponentType` も `DomFill` も型注釈はコンパイル時に消える)、関数名(`.name`)も\n * 拠り所にならない(`vi.fn()` 等のラッパーを経由すると `.name` が `\"Mock\"` 等に上書きされ、\n * テストのモックが大文字始まりになって誤判定するのを実測で確認した)。代わりに\n * `Function.prototype.length`(宣言された仮引数の個数)で判別する(`vi.fn()` 等でラップされても\n * 元関数の `.length` は保たれる)。この 0/1 個の判別は既存の後方互換のため変更しない。\n *\n * 1 のケースをこの判別の外に出している Why not: props を要求するコンポーネント\n * (`({ editor, unit }) => ...`)は仮引数が 1 個になり、`DomFill`(`(el) => ...`)と実行時に\n * 区別できない。`withFillProps` はオブジェクトでラップするため、`typeof entry === 'function'` の\n * 分岐に到達する前に見分けがつき、既存の 0/1 個判別と衝突しない。\n */\nexport function resolveFillEntry(entry: ComponentType | DomFill): ReactNode;\nexport function resolveFillEntry<T>(entry: FillEntry<T>): FillRenderer<T>;\nexport function resolveFillEntry<T>(entry: FillEntry<T>): FillRenderer<T> {\n if (isFillComponentEntry<T>(entry)) {\n // createElement<P>(FunctionComponent<P>, props) はここで P=T を推論できない(T は\n // resolveFillEntry 自身のジェネリックで、createElement 側から見ると「{} と無関係かもしれない\n // 任意の型」にしか見えないため、TS2769 になる。呼び出し境界でのみ型消去する\n // (fill.tsx の eraseFillRendererType と同じ「型消去の境界であることを明示するキャスト」)。\n const Component = entry.Component as FunctionComponent<Record<string, unknown>>;\n // Slot 側(renderFill)は render が関数なら fillProps を渡して呼ぶ実装を既に持つため、\n // ここでは呼び出しを fillProps が判明する Slot の描画タイミングまで遅延させるだけでよい。\n // eslint-disable-next-line react/display-name -- コンポーネント定義ではなく FillRenderer を返す関数(createElement 呼び出しを含むアロー関数がヒューリスティックに誤検知される)\n return (fillProps: T) => createElement(Component, fillProps as Record<string, unknown>);\n }\n if (typeof entry === 'function' && entry.length > 0) {\n return createElement(DomFillMount, { mount: entry as DomFill });\n }\n return createElement(entry as ComponentType);\n}\n","import type { Registry } from './types';\n\n/**\n * コア側の組み込み定義(`core`)と、プラグインが `Registry.add`(`ctx.unitEditor.registerUnitDefinition` /\n * `ctx.dataview.registerColumnType` 経由)で登録した内容をマージする。\n *\n * react-19-migration フェーズ3-1a/3-1b で設計した `unitDefs` / `columnTypes` prop の値計算を\n * レジストリ経由に変える配線(design.md「レジストリ(機能登録)」節)の共通実装。\n * キー衝突時はレジストリ(プラグイン)側を優先する(design.md の例\n * `{ ...coreUnitDefs, ...unitDefinitionRegistry.getAll() }` と同じマージ順)。\n */\nexport function mergeRegistryEntries<T>(core: Record<string, T>, registry: Registry<T>): Record<string, T> {\n return { ...core, ...registry.getAll() };\n}\n","/**\n * ページ全体で 1 つだけ存在するべきシングルトン群。\n *\n * 管理画面は dispatcher ごとに独立した React ルートを `createRoot` する構成\n * (`@ablogcms/react-utils` の `render()`)のため、単一の `<SlotFillProvider>` でページ全体を\n * 包むことができない。`ctx.ui.fill` が書き込む Fill ブリッジをここでシングルトン化しておき、\n * 各ツリーの `<SlotFillProvider store={getGlobalFillBridge()}>` がこれを購読することで、\n * どの独立ツリーの `<Slot>` にも同じ登録内容が届く(design.md「グローバル Fill ブリッジ」節)。\n *\n * `unitDefs` / `columnTypes` prop の値計算(react-19-migration フェーズ3-1a/3-1b)も同じ理由で\n * dispatch 側の複数箇所から同一レジストリを参照する必要があるため、ここでシングルトン化する\n * (実際の prop 配線はフェーズD)。\n *\n * `createPluginRegistry()` 自体は各テストが独立したインスタンスで動かせるよう、これらに依存しない\n * 素の工場関数のまま保つ(`@ablogcms/events` の `createEventBus()` と同じ設計)。\n * 本番の結線(admin.js)でのみ、ここのシングルトンを明示的に注入する。\n */\nimport { createSlotFillStore, type SlotFillStore } from '@ablogcms/components/slot-fill';\nimport type { Action, BulkAction, ColumnTypeDef, Menu, RowData } from '@ablogcms/components/dataview/types';\nimport type { UnitDefInterface } from '@ablogcms/unit-editor/core/types/unit';\nimport type { BlockDefinition } from '@ablogcms/block-editor/types';\nimport type { AnyExtension } from '@ablogcms/block-editor/tiptap/core';\nimport type { Tiptap } from '@ablogcms/block-editor/tiptap';\nimport { createRegistry } from './create-registry';\nimport { createViewedRegistry, type ViewedRegistry } from './create-viewed-registry';\nimport type { Registry } from './types';\n\n/**\n * `ctx.blockEditor.registerBlockDefinition` / `registerExtension` が登録するファクトリの型。\n *\n * Promise を返してもよい(解決側 `features/block-editor/block-definitions.ts` が await する)。\n * 公式 Tiptap 拡張(`@tiptap/extension-*`)はモジュール評価時に Tiptap のクラスを使うため、\n * プラグインはファクトリの中で `await import(...)` して評価自体をチャンクロード後まで遅らせる。\n */\nexport type BlockDefinitionFactory = (tiptap: Tiptap) => BlockDefinition | Promise<BlockDefinition>;\nexport type BlockExtensionFactory = (\n tiptap: Tiptap\n) => AnyExtension | AnyExtension[] | Promise<AnyExtension | AnyExtension[]>;\n\nlet fillBridge: SlotFillStore | undefined;\n\nexport function getGlobalFillBridge(): SlotFillStore {\n if (!fillBridge) {\n fillBridge = createSlotFillStore();\n }\n return fillBridge;\n}\n\nlet unitDefinitionRegistry: Registry<UnitDefInterface> | undefined;\n\nexport function getUnitDefinitionRegistry(): Registry<UnitDefInterface> {\n if (!unitDefinitionRegistry) {\n unitDefinitionRegistry = createRegistry<UnitDefInterface>('unit-definition');\n }\n return unitDefinitionRegistry;\n}\n\nlet columnTypeRegistry: Registry<ColumnTypeDef> | undefined;\n\nexport function getColumnTypeRegistry(): Registry<ColumnTypeDef> {\n if (!columnTypeRegistry) {\n columnTypeRegistry = createRegistry<ColumnTypeDef>('column-type');\n }\n return columnTypeRegistry;\n}\n\nlet blockDefinitionRegistry: Registry<BlockDefinitionFactory> | undefined;\n\nexport function getBlockDefinitionRegistry(): Registry<BlockDefinitionFactory> {\n if (!blockDefinitionRegistry) {\n blockDefinitionRegistry = createRegistry<BlockDefinitionFactory>('block-definition');\n }\n return blockDefinitionRegistry;\n}\n\nlet blockExtensionRegistry: Registry<BlockExtensionFactory> | undefined;\n\nexport function getBlockExtensionRegistry(): Registry<BlockExtensionFactory> {\n if (!blockExtensionRegistry) {\n blockExtensionRegistry = createRegistry<BlockExtensionFactory>('extension');\n }\n return blockExtensionRegistry;\n}\n\nlet dataviewActionRegistry: ViewedRegistry<Action<RowData>> | undefined;\n\nexport function getDataviewActionRegistry(): ViewedRegistry<Action<RowData>> {\n if (!dataviewActionRegistry) {\n dataviewActionRegistry = createViewedRegistry<Action<RowData>>('dataview-action');\n }\n return dataviewActionRegistry;\n}\n\nlet dataviewBulkActionRegistry: ViewedRegistry<BulkAction<RowData>> | undefined;\n\nexport function getDataviewBulkActionRegistry(): ViewedRegistry<BulkAction<RowData>> {\n if (!dataviewBulkActionRegistry) {\n dataviewBulkActionRegistry = createViewedRegistry<BulkAction<RowData>>('dataview-bulk-action');\n }\n return dataviewBulkActionRegistry;\n}\n\nlet dataviewMenuRegistry: ViewedRegistry<Menu<RowData>> | undefined;\n\nexport function getDataviewMenuRegistry(): ViewedRegistry<Menu<RowData>> {\n if (!dataviewMenuRegistry) {\n dataviewMenuRegistry = createViewedRegistry<Menu<RowData>>('dataview-menu');\n }\n return dataviewMenuRegistry;\n}\n"],"mappings":";;;;;;AACA,SAAS,sBAAsB;AAC/B,SAAS,2BAAkE;AAG3E,SAAS,sCAAsC;AAE/C,SAAS,kCAA6D;;;ACG/D,SAAS,eAAkB,OAA4B;AAC5D,QAAM,QAAQ,oBAAI,IAAe;AAEjC,QAAM,MAAM,CAAC,MAAc,SAAyB;AAClD,QAAI,MAAM,IAAI,IAAI,GAAG;AACnB,YAAM,IAAI,MAAM,uBAAuB,KAAK,KAAK,IAAI,4EAAgB;AAAA,IACvE;AACA,UAAM,IAAI,MAAM,IAAI;AACpB,WAAO,MAAM;AACX,UAAI,MAAM,IAAI,IAAI,MAAM,MAAM;AAC5B,cAAM,OAAO,IAAI;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,CAAC,SAA0B,MAAM,OAAO,IAAI;AAE3D,QAAM,MAAM,CAAC,SAAgC,MAAM,IAAI,IAAI;AAE3D,QAAM,SAAS,MAAyB,OAAO,YAAY,KAAK;AAEhE,SAAO,EAAE,KAAK,QAAQ,KAAK,OAAO;AACpC;;;ACbO,SAAS,qBAAwB,OAAkC;AACxE,QAAM,aAAa,oBAAI,IAAyB;AAEhD,QAAM,cAAc,CAAC,SAA8B;AACjD,QAAI,WAAW,WAAW,IAAI,IAAI;AAClC,QAAI,CAAC,UAAU;AACb,iBAAW,eAAkB,GAAG,KAAK,IAAI,IAAI,GAAG;AAChD,iBAAW,IAAI,MAAM,QAAQ;AAAA,IAC/B;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,KAAK,CAAC,MAAM,MAAM,SAAS,YAAY,IAAI,EAAE,IAAI,MAAM,IAAI;AAAA,IAC3D,QAAQ,CAAC,MAAM,SAAS,YAAY,IAAI,EAAE,OAAO,IAAI;AAAA,IACrD,KAAK,CAAC,MAAM,SAAS,YAAY,IAAI,EAAE,IAAI,IAAI;AAAA,IAC/C,QAAQ,CAAC,SAAS,WAAW,IAAI,IAAI,GAAG,OAAO,KAAK,CAAC;AAAA,EACvD;AACF;;;ACrCA,SAAS,qBAAiF;AAC1F,SAAS,oBAAoB;AA8BtB,SAAS,iBAAoB,OAAsC;AACxE,MAAI,qBAAwB,KAAK,GAAG;AAKlC,UAAM,YAAY,MAAM;AAIxB,WAAO,CAAC,cAAiB,cAAc,WAAW,SAAoC;AAAA,EACxF;AACA,MAAI,OAAO,UAAU,cAAc,MAAM,SAAS,GAAG;AACnD,WAAO,cAAc,cAAc,EAAE,OAAO,MAAiB,CAAC;AAAA,EAChE;AACA,SAAO,cAAc,KAAsB;AAC7C;;;AHiBA,IAAM,kBAAkB,CAAC,YAAoB,YAAoB,QAAuB;AACtF,UAAQ,MAAM,uDAA8B,UAAU,qCAAY,UAAU,kEAAgB,GAAG;AACjG;AAEA,IAAM,eAAe,CAAC,SAAmD,MAAM,QAAQ,IAAI,IAAI,KAAK,KAAK,GAAG,IAAI;AAEhH,IAAM,mCAAmC,CAAC,YAAoB,OAAuB,UAAU,UAAU,IAAI,EAAE;AAO/G,IAAM,aAAa,CAAC,eAAgD;AAClE,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,CAAC;AAAA,EACV;AACA,QAAM,YAAY,WAAW,QAAQ,aAAa,CAAC,QAAQ,QAAgB,IAAI,YAAY,CAAC;AAC5F,QAAM,SAAU,OAAsE,MAAM;AAC5F,QAAM,QAAQ,SAAS,SAAS;AAChC,SAAO,OAAO,UAAU,YAAY,UAAU,OAAQ,QAAoC,CAAC;AAC7F;AAWO,SAAS,qBAAqB,UAAuC,CAAC,GAAgB;AAC3F,QAAM,YAAY,QAAQ,aAAa,eAAe;AACtD,QAAM,YAAY,QAAQ,aAAa,oBAAoB;AAC3D,QAAMA,0BAAyB,QAAQ,0BAA0B,eAAiC,iBAAiB;AACnH,QAAMC,sBAAqB,QAAQ,sBAAsB,eAA8B,aAAa;AACpG,QAAMC,2BACJ,QAAQ,2BAA2B,eAAuC,kBAAkB;AAC9F,QAAMC,0BAAyB,QAAQ,0BAA0B,eAAsC,WAAW;AAClH,QAAM,2BAA2B,QAAQ,4BAA4B,+BAA+B;AACpG,QAAM,uBAAuB,QAAQ,wBAAwB,2BAA2B;AACxF,QAAMC,0BACJ,QAAQ,0BAA0B,qBAAsC,iBAAiB;AAC3F,QAAMC,8BACJ,QAAQ,8BAA8B,qBAA0C,sBAAsB;AACxG,QAAMC,wBAAuB,QAAQ,wBAAwB,qBAAoC,eAAe;AAEhH,QAAM,UAAU,oBAAI,IAA4B;AAChD,MAAI,gBAAgB;AAEpB,QAAM,gBAAgB,CAAC,WAA0C;AAE/D,QAAI,iBAAiB;AACrB,UAAM,UAAU,CACd,MACA,YACgB;AAChB,YAAM,QAAQ,aAAa,IAAI;AAC/B,YAAM,UAAU,OAAO,UAA0B;AAC/C,YAAI;AACF,iBAAO,MAAM,QAAQ,KAAK;AAAA,QAC5B,SAAS,KAAK;AACZ,0BAAgB,OAAO,MAAM,OAAO,GAAG;AACvC,gBAAM;AAAA,QACR;AAAA,MACF;AACA,YAAM,cAAe,UAAU,GAAe,MAAM,OAAO;AAC3D,aAAO,cAAc,KAAK,WAAW;AACrC,aAAO,cAAc,KAAK,EAAE,MAAM,SAAS,KAAK,MAAM,CAAC;AACvD,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,MAAM,OAAO;AAAA,MACb,QAAQ,WAAW,OAAO,IAAI;AAAA,MAC9B,QAAQ;AAAA,QACN,IAAI;AAAA,MACN;AAAA,MACA,YAAY;AAAA,QACV,wBAAwB,CAAC,MAAM,QAAQ;AACrC,gBAAM,cAAcN,wBAAuB,IAAI,MAAM,GAAG;AACxD,iBAAO,cAAc,KAAK,WAAW;AACrC,iBAAO,cAAc,KAAK,EAAE,MAAM,mBAAmB,KAAK,KAAK,CAAC;AAChE,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,aAAa;AAAA,QACX,yBAAyB,CAAC,MAAM,YAAY;AAC1C,gBAAM,cAAcE,yBAAwB,IAAI,MAAM,OAAO;AAC7D,iBAAO,cAAc,KAAK,WAAW;AACrC,iBAAO,cAAc,KAAK,EAAE,MAAM,oBAAoB,KAAK,KAAK,CAAC;AACjE,iBAAO;AAAA,QACT;AAAA,QACA,mBAAmB,CAAC,MAAM,YAAY;AACpC,gBAAM,cAAcC,wBAAuB,IAAI,MAAM,OAAO;AAC5D,iBAAO,cAAc,KAAK,WAAW;AACrC,iBAAO,cAAc,KAAK,EAAE,MAAM,aAAa,KAAK,KAAK,CAAC;AAC1D,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,mBAAmB;AAAA,QACjB,kBAAkB,CAAC,IAAI,aAAa;AAClC,gBAAM,cAAc,yBAAyB;AAAA,YAC3C,iCAAiC,OAAO,MAAM,EAAE;AAAA,YAChD;AAAA,UACF;AACA,iBAAO,cAAc,KAAK,WAAW;AACrC,iBAAO,cAAc,KAAK,EAAE,MAAM,8BAA8B,KAAK,GAAG,CAAC;AACzE,iBAAO;AAAA,QACT;AAAA,QACA,kBAAkB,CAAC,IAAI,aAAa;AAClC,gBAAM,cAAc,yBAAyB;AAAA,YAC3C,iCAAiC,OAAO,MAAM,EAAE;AAAA,YAChD;AAAA,cACE,GAAG;AAAA,cACH,YAAY,iCAAiC,OAAO,MAAM,SAAS,UAAU;AAAA,YAC/E;AAAA,UACF;AACA,iBAAO,cAAc,KAAK,WAAW;AACrC,iBAAO,cAAc,KAAK,EAAE,MAAM,qBAAqB,KAAK,GAAG,CAAC;AAChE,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,UAAU;AAAA,QACR,oBAAoB,CAAC,MAAM,SAAS;AAClC,gBAAM,cAAcF,oBAAmB,IAAI,MAAM,IAAI;AACrD,iBAAO,cAAc,KAAK,WAAW;AACrC,iBAAO,cAAc,KAAK,EAAE,MAAM,eAAe,KAAK,KAAK,CAAC;AAC5D,iBAAO;AAAA,QACT;AAAA,QACA,gBAAgB,CAAC,MAAM,MAAM,QAAQ;AACnC,gBAAM,cAAcG,wBAAuB,IAAI,MAAM,MAAM,GAAG;AAC9D,iBAAO,cAAc,KAAK,WAAW;AACrC,iBAAO,cAAc,KAAK,EAAE,MAAM,mBAAmB,KAAK,GAAG,IAAI,IAAI,IAAI,GAAG,CAAC;AAC7E,iBAAO;AAAA,QACT;AAAA,QACA,oBAAoB,CAAC,MAAM,MAAM,QAAQ;AACvC,gBAAM,cAAcC,4BAA2B,IAAI,MAAM,MAAM,GAAG;AAClE,iBAAO,cAAc,KAAK,WAAW;AACrC,iBAAO,cAAc,KAAK,EAAE,MAAM,wBAAwB,KAAK,GAAG,IAAI,IAAI,IAAI,GAAG,CAAC;AAClF,iBAAO;AAAA,QACT;AAAA,QACA,cAAc,CAAC,MAAM,MAAM,QAAQ;AACjC,gBAAM,cAAcC,sBAAqB,IAAI,MAAM,MAAM,GAAG;AAC5D,iBAAO,cAAc,KAAK,WAAW;AACrC,iBAAO,cAAc,KAAK,EAAE,MAAM,iBAAiB,KAAK,GAAG,IAAI,IAAI,IAAI,GAAG,CAAC;AAC3E,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MACA,MAAM;AAAA;AAAA;AAAA,QAGJ,cAAc,CAAC,KAAK,cAAc;AAChC,+BAAqB,IAAI,OAAO,MAAM,KAAK,SAAS;AACpD,iBAAO,cAAc,KAAK,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAIpD,cAAI,CAAC,gBAAgB;AACnB,6BAAiB;AACjB,mBAAO,cAAc,KAAK,MAAM,qBAAqB,OAAO,OAAO,IAAI,CAAC;AAAA,UAC1E;AAAA,QACF;AAAA,MACF;AAAA,MACA,IAAI;AAAA,QACF,MAAM,CAAI,UAAkB,UAAwB;AAClD,2BAAiB;AACjB,gBAAM,KAAK,UAAU,OAAO,IAAI,IAAI,QAAQ,IAAI,aAAa;AAI7D,gBAAM,SAAS,iBAAoB,KAAK;AACxC,oBAAU,WAAW,UAAU,IAAI,MAAM;AACzC,gBAAM,cAAc,MAAM,UAAU,WAAW,UAAU,EAAE;AAC3D,iBAAO,cAAc,KAAK,WAAW;AACrC,iBAAO,cAAc,KAAK,EAAE,MAAM,QAAQ,KAAK,SAAS,CAAC;AACzD,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,CAAC,MAAc,eAAuC;AACrE,QAAI,QAAQ,IAAI,IAAI,GAAG;AACrB,YAAM,IAAI,MAAM,6DAA+B,IAAI,4EAAgB;AAAA,IACrE;AAEA,UAAM,SAAyB,EAAE,MAAM,SAAS,WAAW,SAAS,eAAe,CAAC,GAAG,eAAe,CAAC,EAAE;AAGzG,YAAQ,IAAI,MAAM,MAAM;AAExB,QAAI;AACF,iBAAW,MAAM,cAAc,MAAM,CAAC;AAAA,IACxC,SAAS,KAAK;AAGZ,aAAO,cAAc,QAAQ,CAAC,gBAAgB,YAAY,CAAC;AAC3D,cAAQ,OAAO,IAAI;AACnB,YAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,aAAa,CAAC,SAA0B;AAC5C,UAAM,SAAS,QAAQ,IAAI,IAAI;AAC/B,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,IACT;AACA,WAAO,cAAc,QAAQ,CAAC,gBAAgB,YAAY,CAAC;AAC3D,YAAQ,OAAO,IAAI;AACnB,WAAO;AAAA,EACT;AAEA,QAAM,qBAAqB,CAAC,YAA8C;AAAA,IACxE,MAAM,OAAO;AAAA,IACb,SAAS,OAAO;AAAA,IAChB,eAAe,OAAO;AAAA,EACxB;AAEA,QAAM,MAAM,CAAC,SAA+C;AAC1D,UAAM,SAAS,QAAQ,IAAI,IAAI;AAC/B,WAAO,SAAS,mBAAmB,MAAM,IAAI;AAAA,EAC/C;AAEA,QAAM,SAAS,MAA0B,MAAM,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,kBAAkB;AAE5F,SAAO,EAAE,UAAU,YAAY,KAAK,QAAQ,cAAc;AAC5D;;;AIzRO,SAAS,qBAAwB,MAAyB,UAA0C;AACzG,SAAO,EAAE,GAAG,MAAM,GAAG,SAAS,OAAO,EAAE;AACzC;;;ACIA,SAAS,uBAAAC,4BAA+C;AAsBxD,IAAI;AAEG,SAAS,sBAAqC;AACnD,MAAI,CAAC,YAAY;AACf,iBAAaC,qBAAoB;AAAA,EACnC;AACA,SAAO;AACT;AAEA,IAAI;AAEG,SAAS,4BAAwD;AACtE,MAAI,CAAC,wBAAwB;AAC3B,6BAAyB,eAAiC,iBAAiB;AAAA,EAC7E;AACA,SAAO;AACT;AAEA,IAAI;AAEG,SAAS,wBAAiD;AAC/D,MAAI,CAAC,oBAAoB;AACvB,yBAAqB,eAA8B,aAAa;AAAA,EAClE;AACA,SAAO;AACT;AAEA,IAAI;AAEG,SAAS,6BAA+D;AAC7E,MAAI,CAAC,yBAAyB;AAC5B,8BAA0B,eAAuC,kBAAkB;AAAA,EACrF;AACA,SAAO;AACT;AAEA,IAAI;AAEG,SAAS,4BAA6D;AAC3E,MAAI,CAAC,wBAAwB;AAC3B,6BAAyB,eAAsC,WAAW;AAAA,EAC5E;AACA,SAAO;AACT;AAEA,IAAI;AAEG,SAAS,4BAA6D;AAC3E,MAAI,CAAC,wBAAwB;AAC3B,6BAAyB,qBAAsC,iBAAiB;AAAA,EAClF;AACA,SAAO;AACT;AAEA,IAAI;AAEG,SAAS,gCAAqE;AACnF,MAAI,CAAC,4BAA4B;AAC/B,iCAA6B,qBAA0C,sBAAsB;AAAA,EAC/F;AACA,SAAO;AACT;AAEA,IAAI;AAEG,SAAS,0BAAyD;AACvE,MAAI,CAAC,sBAAsB;AACzB,2BAAuB,qBAAoC,eAAe;AAAA,EAC5E;AACA,SAAO;AACT;","names":["unitDefinitionRegistry","columnTypeRegistry","blockDefinitionRegistry","blockExtensionRegistry","dataviewActionRegistry","dataviewBulkActionRegistry","dataviewMenuRegistry","createSlotFillStore","createSlotFillStore"]}
1
+ {"version":3,"sources":["../../src/core/create-plugin-registry.ts","../../src/core/create-registry.ts","../../src/core/create-viewed-registry.ts","../../src/core/resolve-fill-entry.ts","../../src/core/merge-registry-entries.ts","../../src/core/global-singletons.ts"],"sourcesContent":["import type { AcmsEventType, AcmsEvents, AcmsGateContext, AcmsLooseEvent, Unsubscribe } from '@ablogcms/events';\nimport { createEventBus } from '@ablogcms/events/core';\nimport { createSlotFillStore, type SlotFillStore, type FillRenderer } from '@ablogcms/components/slot-fill';\nimport type { Action, BulkAction, ColumnTypeDef, Menu, RowData } from '@ablogcms/components/dataview/types';\nimport type { UnitDefInterface } from '@ablogcms/unit-editor/core/types/unit';\nimport { createKeyboardShortcutRegistry } from '@ablogcms/keyboard-shortcut';\nimport type { KeyboardShortcutRegistry } from '@ablogcms/keyboard-shortcut';\nimport { createI18nResourceRegistry, type I18nResourceRegistry } from '@ablogcms/i18n/core';\nimport { createRegistry } from './create-registry';\nimport { createViewedRegistry, type ViewedRegistry } from './create-viewed-registry';\nimport { resolveFillEntry } from './resolve-fill-entry';\nimport { withFillProps } from './with-fill-props';\nimport type { BlockDefinitionFactory, BlockExtensionFactory } from './global-singletons';\nimport type {\n AcmsPlugins,\n FillEntry,\n PluginContext,\n PluginDefinition,\n RegisteredEntry,\n RegisteredPlugin,\n Registry,\n} from './types';\n\nexport interface CreatePluginRegistryOptions {\n /** 委譲先のイベントバス。省略時は自己完結したインスタンスを新規作成する(テスト用の既定値) */\n eventsBus?: AcmsEvents;\n /** `ctx.ui.fill` の書き込み先。省略時は自己完結したインスタンスを新規作成する(テスト用の既定値) */\n fillStore?: SlotFillStore;\n /** `ctx.unitEditor.registerUnitDefinition` の登録先。省略時は自己完結したインスタンスを新規作成する */\n unitDefinitionRegistry?: Registry<UnitDefInterface>;\n /** `ctx.dataview.registerColumnType` の登録先。省略時は自己完結したインスタンスを新規作成する */\n columnTypeRegistry?: Registry<ColumnTypeDef>;\n /** `ctx.blockEditor.registerBlockDefinition` の登録先。省略時は自己完結したインスタンスを新規作成する */\n blockDefinitionRegistry?: Registry<BlockDefinitionFactory>;\n /** `ctx.blockEditor.registerExtension` の登録先。省略時は自己完結したインスタンスを新規作成する */\n blockExtensionRegistry?: Registry<BlockExtensionFactory>;\n /** `ctx.keyboardShortcuts` の登録先。省略時は自己完結したインスタンスを新規作成する */\n keyboardShortcutRegistry?: KeyboardShortcutRegistry;\n\n /** `ctx.i18n` の登録先。省略時は自己完結したインスタンスを新規作成する */\n i18nResourceRegistry?: I18nResourceRegistry;\n /** `ctx.dataview.registerAction` の登録先。省略時は自己完結したインスタンスを新規作成する */\n dataviewActionRegistry?: ViewedRegistry<Action<RowData>>;\n /** `ctx.dataview.registerBulkAction` の登録先。省略時は自己完結したインスタンスを新規作成する */\n dataviewBulkActionRegistry?: ViewedRegistry<BulkAction<RowData>>;\n /** `ctx.dataview.registerMenu` の登録先。省略時は自己完結したインスタンスを新規作成する */\n dataviewMenuRegistry?: ViewedRegistry<Menu<RowData>>;\n}\n\ninterface InternalPlugin {\n name: string;\n version?: string;\n registrations: RegisteredEntry[];\n subscriptions: Unsubscribe[];\n}\n\n// AcmsEvents#on は型引数 K ごとにハンドラの戻り値を絞り込むため、type がユニオン\n// (AcmsEventType | AcmsEventType[])のまま渡すとハンドラの戻り値を厳密に検証できない。\n// create-event-bus.ts と同じく、内部では緩い型で扱い、公開 API の境界(PluginContext)でのみ\n// 厳密な型へキャストする。\ntype LooseHandler = (event: AcmsLooseEvent, gateCtx?: AcmsGateContext) => unknown;\ntype LooseOn = (type: AcmsEventType | AcmsEventType[], handler: LooseHandler) => Unsubscribe;\n\n// プラグイン起因の例外をどのプラグインが投げたか特定できるよう帰属を明示する。\n// イベントバス自身も汎用メッセージで同じ例外をログするため、この行は「どのプラグインか」を示す追加の帰属ログになる。\nconst logHandlerError = (pluginName: string, eventLabel: string, err: unknown): void => {\n console.error(`[@ablogcms/plugins] プラグイン \"${pluginName}\" のハンドラ(\"${eventLabel}\")が例外を投げました。`, err);\n};\n\nconst toEventLabel = (type: AcmsEventType | AcmsEventType[]): string => (Array.isArray(type) ? type.join(',') : type);\n\nconst toKeyboardShortcutRegistrationId = (pluginName: string, id: string): string => `plugin:${pluginName}:${id}`;\n\n/**\n * `window.ACMS.Config` からプラグインの設定値を読む。プラグイン名は `-`/`_` 区切りのことが多いため、\n * `jsModule()` 側の慣例(キャメルケースキー)に合わせて変換する。未初期化・未設定時は空オブジェクトを返し、\n * `setup(ctx)` 内で `ctx.config` を参照しただけで例外にならないようにする。\n */\nconst readConfig = (pluginName: string): Record<string, unknown> => {\n if (typeof window === 'undefined') {\n return {};\n }\n const camelName = pluginName.replace(/[-_](\\w)/g, (_match, chr: string) => chr.toUpperCase());\n const config = (window as unknown as { ACMS?: { Config?: Record<string, unknown> } }).ACMS?.Config;\n const value = config?.[camelName];\n return typeof value === 'object' && value !== null ? (value as Record<string, unknown>) : {};\n};\n\n/**\n * `ACMS.plugins` の純粋実装(グローバル非依存)。VS Code の `activate(context)` +\n * `context.subscriptions` を範に、`setup(ctx)` 内でのイベント購読・レジストリ登録・UI 差し込みを\n * すべて内部の subscriptions 配列に集約し、`unregister(name)` で一括自動回収する。\n *\n * 依存(イベントバス・Fill ブリッジ・各レジストリ)はすべて注入可能で、省略時は自己完結した\n * インスタンスを新規作成する(`@ablogcms/events` の `createEventBus()` と同じ設計。グローバル\n * シングルトンへの結線は本番の bootstrap(admin.js)が `global-singletons.ts` 経由で明示的に行う)。\n */\nexport function createPluginRegistry(options: CreatePluginRegistryOptions = {}): AcmsPlugins {\n const eventsBus = options.eventsBus ?? createEventBus();\n const fillStore = options.fillStore ?? createSlotFillStore();\n const unitDefinitionRegistry = options.unitDefinitionRegistry ?? createRegistry<UnitDefInterface>('unit-definition');\n const columnTypeRegistry = options.columnTypeRegistry ?? createRegistry<ColumnTypeDef>('column-type');\n const blockDefinitionRegistry =\n options.blockDefinitionRegistry ?? createRegistry<BlockDefinitionFactory>('block-definition');\n const blockExtensionRegistry = options.blockExtensionRegistry ?? createRegistry<BlockExtensionFactory>('extension');\n const keyboardShortcutRegistry = options.keyboardShortcutRegistry ?? createKeyboardShortcutRegistry();\n const i18nResourceRegistry = options.i18nResourceRegistry ?? createI18nResourceRegistry();\n const dataviewActionRegistry =\n options.dataviewActionRegistry ?? createViewedRegistry<Action<RowData>>('dataview-action');\n const dataviewBulkActionRegistry =\n options.dataviewBulkActionRegistry ?? createViewedRegistry<BulkAction<RowData>>('dataview-bulk-action');\n const dataviewMenuRegistry = options.dataviewMenuRegistry ?? createViewedRegistry<Menu<RowData>>('dataview-menu');\n\n const plugins = new Map<string, InternalPlugin>();\n let fillIdCounter = 0;\n\n const createContext = (plugin: InternalPlugin): PluginContext => {\n /** そのプラグインの i18n 後始末を subscriptions へ積んだか(積むのは初回の addResources だけ) */\n let hasI18nCleanup = false;\n const onEvent = (type: AcmsEventType | AcmsEventType[], handler: LooseHandler): Unsubscribe => {\n const label = toEventLabel(type);\n // ゲートイベントでは cancel(reason) を持つ gateCtx が第2引数で渡る。通知イベントでは undefined のまま\n const wrapped = async (event: AcmsLooseEvent, gateCtx?: AcmsGateContext) => {\n try {\n return await handler(event, gateCtx);\n } catch (err) {\n logHandlerError(plugin.name, label, err);\n throw err;\n }\n };\n const unsubscribe = (eventsBus.on as LooseOn)(type, wrapped);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'event', key: label });\n return unsubscribe;\n };\n\n return {\n name: plugin.name,\n config: readConfig(plugin.name),\n events: {\n on: onEvent as PluginContext['events']['on'],\n },\n unitEditor: {\n registerUnitDefinition: (name, def) => {\n const unsubscribe = unitDefinitionRegistry.add(name, def);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'unit-definition', key: name });\n return unsubscribe;\n },\n },\n blockEditor: {\n registerBlockDefinition: (name, factory) => {\n const unsubscribe = blockDefinitionRegistry.add(name, factory);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'block-definition', key: name });\n return unsubscribe;\n },\n registerExtension: (name, factory) => {\n const unsubscribe = blockExtensionRegistry.add(name, factory);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'extension', key: name });\n return unsubscribe;\n },\n },\n keyboardShortcuts: {\n registerCategory: (id, category) => {\n const unsubscribe = keyboardShortcutRegistry.registerCategory(\n toKeyboardShortcutRegistrationId(plugin.name, id),\n category\n );\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'keyboard-shortcut-category', key: id });\n return unsubscribe;\n },\n registerShortcut: (id, shortcut) => {\n const unsubscribe = keyboardShortcutRegistry.registerShortcut(\n toKeyboardShortcutRegistrationId(plugin.name, id),\n {\n ...shortcut,\n categoryId: toKeyboardShortcutRegistrationId(plugin.name, shortcut.categoryId),\n }\n );\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'keyboard-shortcut', key: id });\n return unsubscribe;\n },\n },\n dataview: {\n registerColumnType: (name, type) => {\n const unsubscribe = columnTypeRegistry.add(name, type);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'column-type', key: name });\n return unsubscribe;\n },\n registerAction: (view, name, def) => {\n const unsubscribe = dataviewActionRegistry.add(view, name, def);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'dataview-action', key: `${view}:${name}` });\n return unsubscribe;\n },\n registerBulkAction: (view, name, def) => {\n const unsubscribe = dataviewBulkActionRegistry.add(view, name, def);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'dataview-bulk-action', key: `${view}:${name}` });\n return unsubscribe;\n },\n registerMenu: (view, name, def) => {\n const unsubscribe = dataviewMenuRegistry.add(view, name, def);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'dataview-menu', key: `${view}:${name}` });\n return unsubscribe;\n },\n },\n i18n: {\n // 名前空間をプラグイン名に固定する。プラグイン側で自由に決められると、コアの\n // `translation` や他プラグインとキーが衝突しうるため、名乗りは registry 側で与える。\n addResources: (lng, resources) => {\n i18nResourceRegistry.add(plugin.name, lng, resources);\n plugin.registrations.push({ kind: 'i18n', key: lng });\n // 破棄は名前空間(=プラグイン名)単位なので、何度 addResources しても後始末は 1 つでよい。\n // 呼び出し回数ぶん積むと unregister 時に remove が空振りで複数回走り、購読側の\n // forget(i18next の removeResourceBundle)も無駄に繰り返されるため、初回だけ積む。\n if (!hasI18nCleanup) {\n hasI18nCleanup = true;\n plugin.subscriptions.push(() => i18nResourceRegistry.remove(plugin.name));\n }\n },\n },\n ui: {\n fill: <T>(slotName: string, entry: FillEntry<T>) => {\n fillIdCounter += 1;\n const id = `plugin:${plugin.name}:${slotName}:${fillIdCounter}`;\n // fillStore(Slot 名ごとに異なる T を型消去した FillRenderer = FillRenderer<unknown> で\n // 保持する)へ渡す境界。Fill コンポーネント(@ablogcms/components/slot-fill)の\n // eraseFillRendererType と同じ理由・同じ境界でここでも明示キャストする。\n const render = resolveFillEntry<T>(entry) as FillRenderer;\n fillStore.upsertFill(slotName, id, render);\n const unsubscribe = () => fillStore.removeFill(slotName, id);\n plugin.subscriptions.push(unsubscribe);\n plugin.registrations.push({ kind: 'fill', key: slotName });\n return unsubscribe;\n },\n },\n };\n };\n\n const register = (name: string, definition: PluginDefinition): void => {\n if (plugins.has(name)) {\n throw new Error(`[@ablogcms/plugins] プラグイン名 \"${name}\" は既に登録されています。`);\n }\n\n const plugin: InternalPlugin = { name, version: definition.version, registrations: [], subscriptions: [] };\n // setup() 実行前に登録しておく。setup() の途中で ctx 経由の登録(例: 名前衝突での throw)が\n // 失敗した場合に catch 節でロールバックできるようにするため。\n plugins.set(name, plugin);\n\n try {\n definition.setup(createContext(plugin));\n } catch (err) {\n // 途中まで行われた登録(イベント購読・レジストリ登録・Fill)をすべて解除し、ゾンビ状態の\n // 半登録プラグインを残さない。呼び出し元は同じ名前で再度 register し直せる。\n plugin.subscriptions.forEach((unsubscribe) => unsubscribe());\n plugins.delete(name);\n throw err;\n }\n };\n\n const unregister = (name: string): boolean => {\n const plugin = plugins.get(name);\n if (!plugin) {\n return false;\n }\n plugin.subscriptions.forEach((unsubscribe) => unsubscribe());\n plugins.delete(name);\n return true;\n };\n\n const toRegisteredPlugin = (plugin: InternalPlugin): RegisteredPlugin => ({\n name: plugin.name,\n version: plugin.version,\n registrations: plugin.registrations,\n });\n\n const get = (name: string): RegisteredPlugin | undefined => {\n const plugin = plugins.get(name);\n return plugin ? toRegisteredPlugin(plugin) : undefined;\n };\n\n const getAll = (): RegisteredPlugin[] => Array.from(plugins.values()).map(toRegisteredPlugin);\n\n return { register, unregister, get, getAll, withFillProps };\n}\n","import type { Registry, Unsubscribe } from './types';\n\n/**\n * 名前衝突を検知する汎用レジストリの純粋実装。`ctx.unitEditor.registerUnitDefinition` /\n * `ctx.dataview.registerColumnType` の土台(Directus の `defineInterface` 等と同型)。\n *\n * `add()` が返す `Unsubscribe` は、登録時点の値を閉じ込めて比較してから削除する。\n * 「解除 → 同名で再登録」の後に古い `Unsubscribe` が誤って新しい登録を消してしまう事故を防ぐ\n * (`name` は一意だが、`Unsubscribe` のライフサイクルは呼び出し側が保持し続けるため)。\n */\nexport function createRegistry<T>(label: string): Registry<T> {\n const items = new Map<string, T>();\n\n const add = (name: string, item: T): Unsubscribe => {\n if (items.has(name)) {\n throw new Error(`[@ablogcms/plugins] ${label} \"${name}\" は既に登録されています。`);\n }\n items.set(name, item);\n return () => {\n if (items.get(name) === item) {\n items.delete(name);\n }\n };\n };\n\n const remove = (name: string): boolean => items.delete(name);\n\n const get = (name: string): T | undefined => items.get(name);\n\n const getAll = (): Record<string, T> => Object.fromEntries(items);\n\n return { add, remove, get, getAll };\n}\n","import type { Registry, Unsubscribe } from './types';\nimport { createRegistry } from './create-registry';\n\n/**\n * `view`(`'entry' | 'module'` 等、将来拡張可能な文字列)ごとに独立した名前空間を持つレジストリ。\n * `ctx.dataview.registerAction(view, name, def)` の土台(design.md Q4「view キー方式」)。\n *\n * 内部では `view` ごとに素の {@link createRegistry} インスタンスを遅延生成して保持する\n * (文字列連結キー方式にしない理由: view 名に区切り文字が含まれた場合の衝突を避けるため)。\n */\nexport interface ViewedRegistry<T> {\n /** `view` 内で `name` が既に登録済みの場合は throw する */\n add(view: string, name: string, item: T): Unsubscribe;\n remove(view: string, name: string): boolean;\n get(view: string, name: string): T | undefined;\n /** 指定した `view` に登録された項目のみを返す。未登録の `view` は空オブジェクト */\n getAll(view: string): Record<string, T>;\n}\n\nexport function createViewedRegistry<T>(label: string): ViewedRegistry<T> {\n const registries = new Map<string, Registry<T>>();\n\n const registryFor = (view: string): Registry<T> => {\n let registry = registries.get(view);\n if (!registry) {\n registry = createRegistry<T>(`${label}(${view})`);\n registries.set(view, registry);\n }\n return registry;\n };\n\n return {\n add: (view, name, item) => registryFor(view).add(name, item),\n remove: (view, name) => registryFor(view).remove(name),\n get: (view, name) => registryFor(view).get(name),\n getAll: (view) => registries.get(view)?.getAll() ?? {},\n };\n}\n","import { createElement, type ComponentType, type FunctionComponent, type ReactNode } from 'react';\nimport { DomFillMount } from '@ablogcms/components/slot-fill';\nimport type { FillRenderer } from '@ablogcms/components/slot-fill';\nimport { isFillComponentEntry } from './with-fill-props';\nimport type { DomFill, FillEntry } from './types';\n\n/**\n * `ctx.ui.fill(slotName, entry)` の `entry` を、Fill ストア(`@ablogcms/components/slot-fill`)に\n * そのまま渡せる `FillRenderer`(`ReactNode`、または `Slot` の `fillProps` を受け取る render-prop\n * 関数)に変換する。\n *\n * 判別は 3 種類:\n * 1. `withFillProps(Component)` が返すマーカーオブジェクト(`FillComponentEntry`)→ `fillProps` を\n * 受け取る render-prop 関数を返す(下記参照)。\n * 2. 仮引数 1 個以上の関数 → `DomFill` として `DomFillMount` でラップする。\n * 3. それ以外(仮引数 0 個の関数)→ props なしの React コンポーネントとして描画する。\n *\n * 2/3 の判別は Why not: 実行時には両者とも「関数」という点で構造的に区別できず\n * (`React.ComponentType` も `DomFill` も型注釈はコンパイル時に消える)、関数名(`.name`)も\n * 拠り所にならない(`vi.fn()` 等のラッパーを経由すると `.name` が `\"Mock\"` 等に上書きされ、\n * テストのモックが大文字始まりになって誤判定するのを実測で確認した)。代わりに\n * `Function.prototype.length`(宣言された仮引数の個数)で判別する(`vi.fn()` 等でラップされても\n * 元関数の `.length` は保たれる)。この 0/1 個の判別は既存の後方互換のため変更しない。\n *\n * 1 のケースをこの判別の外に出している Why not: props を要求するコンポーネント\n * (`({ editor, unit }) => ...`)は仮引数が 1 個になり、`DomFill`(`(el) => ...`)と実行時に\n * 区別できない。`withFillProps` はオブジェクトでラップするため、`typeof entry === 'function'` の\n * 分岐に到達する前に見分けがつき、既存の 0/1 個判別と衝突しない。\n */\nexport function resolveFillEntry(entry: ComponentType | DomFill): ReactNode;\nexport function resolveFillEntry<T>(entry: FillEntry<T>): FillRenderer<T>;\nexport function resolveFillEntry<T>(entry: FillEntry<T>): FillRenderer<T> {\n if (isFillComponentEntry<T>(entry)) {\n // createElement<P>(FunctionComponent<P>, props) はここで P=T を推論できない(T は\n // resolveFillEntry 自身のジェネリックで、createElement 側から見ると「{} と無関係かもしれない\n // 任意の型」にしか見えないため、TS2769 になる。呼び出し境界でのみ型消去する\n // (fill.tsx の eraseFillRendererType と同じ「型消去の境界であることを明示するキャスト」)。\n const Component = entry.Component as FunctionComponent<Record<string, unknown>>;\n // Slot 側(renderFill)は render が関数なら fillProps を渡して呼ぶ実装を既に持つため、\n // ここでは呼び出しを fillProps が判明する Slot の描画タイミングまで遅延させるだけでよい。\n // eslint-disable-next-line react/display-name -- コンポーネント定義ではなく FillRenderer を返す関数(createElement 呼び出しを含むアロー関数がヒューリスティックに誤検知される)\n return (fillProps: T) => createElement(Component, fillProps as Record<string, unknown>);\n }\n if (typeof entry === 'function' && entry.length > 0) {\n return createElement(DomFillMount, { mount: entry as DomFill });\n }\n return createElement(entry as ComponentType);\n}\n","import type { Registry } from './types';\n\n/**\n * コア側の組み込み定義(`core`)と、プラグインが `Registry.add`(`ctx.unitEditor.registerUnitDefinition` /\n * `ctx.dataview.registerColumnType` 経由)で登録した内容をマージする。\n *\n * react-19-migration フェーズ3-1a/3-1b で設計した `unitDefs` / `columnTypes` prop の値計算を\n * レジストリ経由に変える配線(design.md「レジストリ(機能登録)」節)の共通実装。\n * キー衝突時はレジストリ(プラグイン)側を優先する(design.md の例\n * `{ ...coreUnitDefs, ...unitDefinitionRegistry.getAll() }` と同じマージ順)。\n */\nexport function mergeRegistryEntries<T>(core: Record<string, T>, registry: Registry<T>): Record<string, T> {\n return { ...core, ...registry.getAll() };\n}\n","/**\n * ページ全体で 1 つだけ存在するべきシングルトン群。\n *\n * 管理画面は dispatcher ごとに独立した React ルートを `createRoot` する構成\n * (`@ablogcms/react-utils` の `render()`)のため、単一の `<SlotFillProvider>` でページ全体を\n * 包むことができない。`ctx.ui.fill` が書き込む Fill ブリッジをここでシングルトン化しておき、\n * 各ツリーの `<SlotFillProvider store={getGlobalFillBridge()}>` がこれを購読することで、\n * どの独立ツリーの `<Slot>` にも同じ登録内容が届く(design.md「グローバル Fill ブリッジ」節)。\n *\n * `unitDefs` / `columnTypes` prop の値計算(react-19-migration フェーズ3-1a/3-1b)も同じ理由で\n * dispatch 側の複数箇所から同一レジストリを参照する必要があるため、ここでシングルトン化する\n * (実際の prop 配線はフェーズD)。\n *\n * `createPluginRegistry()` 自体は各テストが独立したインスタンスで動かせるよう、これらに依存しない\n * 素の工場関数のまま保つ(`@ablogcms/events` の `createEventBus()` と同じ設計)。\n * 本番の結線(admin.js)でのみ、ここのシングルトンを明示的に注入する。\n */\nimport { createSlotFillStore, type SlotFillStore } from '@ablogcms/components/slot-fill';\nimport type { Action, BulkAction, ColumnTypeDef, Menu, RowData } from '@ablogcms/components/dataview/types';\nimport type { UnitDefInterface } from '@ablogcms/unit-editor/core/types/unit';\nimport type { BlockDefinition } from '@ablogcms/block-editor/types';\nimport type { AnyExtension } from '@ablogcms/block-editor/tiptap/core';\nimport type { Tiptap } from '@ablogcms/block-editor/tiptap';\nimport { createRegistry } from './create-registry';\nimport { createViewedRegistry, type ViewedRegistry } from './create-viewed-registry';\nimport type { Registry } from './types';\n\n/**\n * `ctx.blockEditor.registerBlockDefinition` / `registerExtension` が登録するファクトリの型。\n *\n * Promise を返してもよい(解決側 `features/block-editor/block-definitions.ts` が await する)。\n * 公式 Tiptap 拡張(`@tiptap/extension-*`)はモジュール評価時に Tiptap のクラスを使うため、\n * プラグインはファクトリの中で `await import(...)` して評価自体をチャンクロード後まで遅らせる。\n */\nexport type BlockDefinitionFactory = (tiptap: Tiptap) => BlockDefinition | Promise<BlockDefinition>;\nexport type BlockExtensionFactory = (\n tiptap: Tiptap\n) => AnyExtension | AnyExtension[] | Promise<AnyExtension | AnyExtension[]>;\n\nlet fillBridge: SlotFillStore | undefined;\n\nexport function getGlobalFillBridge(): SlotFillStore {\n if (!fillBridge) {\n fillBridge = createSlotFillStore();\n }\n return fillBridge;\n}\n\nlet unitDefinitionRegistry: Registry<UnitDefInterface> | undefined;\n\nexport function getUnitDefinitionRegistry(): Registry<UnitDefInterface> {\n if (!unitDefinitionRegistry) {\n unitDefinitionRegistry = createRegistry<UnitDefInterface>('unit-definition');\n }\n return unitDefinitionRegistry;\n}\n\nlet columnTypeRegistry: Registry<ColumnTypeDef> | undefined;\n\nexport function getColumnTypeRegistry(): Registry<ColumnTypeDef> {\n if (!columnTypeRegistry) {\n columnTypeRegistry = createRegistry<ColumnTypeDef>('column-type');\n }\n return columnTypeRegistry;\n}\n\nlet blockDefinitionRegistry: Registry<BlockDefinitionFactory> | undefined;\n\nexport function getBlockDefinitionRegistry(): Registry<BlockDefinitionFactory> {\n if (!blockDefinitionRegistry) {\n blockDefinitionRegistry = createRegistry<BlockDefinitionFactory>('block-definition');\n }\n return blockDefinitionRegistry;\n}\n\nlet blockExtensionRegistry: Registry<BlockExtensionFactory> | undefined;\n\nexport function getBlockExtensionRegistry(): Registry<BlockExtensionFactory> {\n if (!blockExtensionRegistry) {\n blockExtensionRegistry = createRegistry<BlockExtensionFactory>('extension');\n }\n return blockExtensionRegistry;\n}\n\nlet dataviewActionRegistry: ViewedRegistry<Action<RowData>> | undefined;\n\nexport function getDataviewActionRegistry(): ViewedRegistry<Action<RowData>> {\n if (!dataviewActionRegistry) {\n dataviewActionRegistry = createViewedRegistry<Action<RowData>>('dataview-action');\n }\n return dataviewActionRegistry;\n}\n\nlet dataviewBulkActionRegistry: ViewedRegistry<BulkAction<RowData>> | undefined;\n\nexport function getDataviewBulkActionRegistry(): ViewedRegistry<BulkAction<RowData>> {\n if (!dataviewBulkActionRegistry) {\n dataviewBulkActionRegistry = createViewedRegistry<BulkAction<RowData>>('dataview-bulk-action');\n }\n return dataviewBulkActionRegistry;\n}\n\nlet dataviewMenuRegistry: ViewedRegistry<Menu<RowData>> | undefined;\n\nexport function getDataviewMenuRegistry(): ViewedRegistry<Menu<RowData>> {\n if (!dataviewMenuRegistry) {\n dataviewMenuRegistry = createViewedRegistry<Menu<RowData>>('dataview-menu');\n }\n return dataviewMenuRegistry;\n}\n"],"mappings":"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","names":["unitDefinitionRegistry","columnTypeRegistry","blockDefinitionRegistry","blockExtensionRegistry","dataviewActionRegistry","dataviewBulkActionRegistry","dataviewMenuRegistry","createSlotFillStore","createSlotFillStore"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ablogcms/plugins",
3
- "version": "3.2.37",
3
+ "version": "3.2.39",
4
4
  "type": "module",
5
5
  "description": "Plugin registry for the a-blog cms admin JS extension platform",
6
6
  "license": "MIT",
@@ -12,17 +12,17 @@
12
12
  },
13
13
  "sideEffects": false,
14
14
  "dependencies": {
15
- "@ablogcms/block-editor": "3.2.37",
16
- "@ablogcms/components": "3.2.37",
17
- "@ablogcms/events": "3.2.37",
18
- "@ablogcms/i18n": "3.2.37",
19
- "@ablogcms/keyboard-shortcut": "3.2.37",
20
- "@ablogcms/types": "3.2.37",
21
- "@ablogcms/unit-editor": "3.2.37"
15
+ "@ablogcms/block-editor": "3.2.39",
16
+ "@ablogcms/components": "3.2.39",
17
+ "@ablogcms/events": "3.2.39",
18
+ "@ablogcms/i18n": "3.2.39",
19
+ "@ablogcms/keyboard-shortcut": "3.2.39",
20
+ "@ablogcms/types": "3.2.39",
21
+ "@ablogcms/unit-editor": "3.2.39"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@testing-library/react": "^16.3.3",
25
- "vitest": "^4.1.11"
25
+ "vitest": "^5.0.5"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "react": "^19",
@@ -54,7 +54,8 @@
54
54
  "access": "public"
55
55
  },
56
56
  "files": [
57
- "dist"
57
+ "dist",
58
+ "HOOKS.md"
58
59
  ],
59
60
  "scripts": {
60
61
  "build": "node ../../../tools/build-package.mjs"