@embedpdf/plugin-commands 2.0.0-next.1 → 2.0.0-next.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t="commands",s={id:t,name:"Commands Plugin",version:"1.0.0",provides:["commands"],requires:[],optional:["i18n"],defaultConfig:{enabled:!0,commands:{}}},o=class extends e.BasePlugin{constructor(t,s,o){super(t,s),this.commands=new Map,this.i18n=null,this.shortcutMap=new Map,this.commandExecuted$=e.createEmitter(),this.commandStateChanged$=e.createEmitter(),this.shortcutExecuted$=e.createEmitter(),this.previousStates=new Map;const i=s.getPlugin("i18n");this.i18n=(null==i?void 0:i.provides())??null,Object.values(o.commands).forEach(e=>{this.registerCommand(e)}),this.registry.getStore().subscribe((e,t)=>{this.onGlobalStoreChange(t)})}onDocumentClosed(e){this.previousStates.delete(e),this.logger.debug("CommandsPlugin","DocumentClosed",`Cleaned up command state cache for document: ${e}`)}async initialize(){this.logger.info("CommandsPlugin","Initialize","Commands plugin initialized")}async destroy(){this.commandExecuted$.clear(),this.commandStateChanged$.clear(),this.shortcutExecuted$.clear(),this.commands.clear(),this.shortcutMap.clear(),this.previousStates.clear(),super.destroy()}buildCapability(){return{resolve:(e,t)=>this.resolve(e,t),execute:(e,t,s="ui")=>this.execute(e,t,s),getAllCommands:e=>this.getAllCommands(e),getCommandsByCategory:(e,t)=>this.getCommandsByCategory(e,t),getCommandByShortcut:e=>this.getCommandByShortcut(e),getAllShortcuts:()=>new Map(this.shortcutMap),forDocument:e=>this.createCommandScope(e),registerCommand:e=>this.registerCommand(e),unregisterCommand:e=>this.unregisterCommand(e),onCommandExecuted:this.commandExecuted$.on,onCommandStateChanged:this.commandStateChanged$.on,onShortcutExecuted:this.shortcutExecuted$.on}}createCommandScope(e){return{resolve:t=>this.resolve(t,e),execute:(t,s="ui")=>this.execute(t,e,s),getAllCommands:()=>this.getAllCommands(e),getCommandsByCategory:t=>this.getCommandsByCategory(t,e),onCommandStateChanged:t=>this.commandStateChanged$.on(s=>{if(s.documentId===e){const{documentId:e,...o}=s;t(o)}})}}resolve(e,t){const s=t??this.getActiveDocumentId(),o=this.commands.get(e);if(!o)throw new Error(`Command not found: ${e}`);const i=this.registry.getStore().getState(),n=this.resolveLabel(o,i,s),a=o.shortcuts?Array.isArray(o.shortcuts)?o.shortcuts:[o.shortcuts]:void 0;return{id:o.id,label:n,icon:this.resolveDynamic(o.icon,i,s),iconProps:this.resolveDynamic(o.iconProps,i,s),active:this.resolveDynamic(o.active,i,s)??!1,disabled:this.resolveDynamic(o.disabled,i,s)??!1,visible:this.resolveDynamic(o.visible,i,s)??!0,shortcuts:a,shortcutLabel:o.shortcutLabel,category:o.category,description:o.description,execute:()=>o.action({registry:this.registry,state:i,documentId:s})}}resolveLabel(e,t,s){if(e.labelKey&&this.i18n){const o=this.resolveDynamic(e.labelParams,t,s);return this.i18n.t(e.labelKey,{params:o,documentId:s})}return e.label?e.label:e.id}resolveDynamic(e,t,s){if(void 0!==e)return"function"==typeof e?e({state:t,documentId:s}):e}execute(e,t,s="ui"){const o=t??this.getActiveDocumentId(),i=this.resolve(e,o);i.disabled?this.logger.warn("CommandsPlugin","ExecutionBlocked",`Command '${e}' is disabled for document '${o}'`):i.visible?(i.execute(),this.commandExecuted$.emit({commandId:e,documentId:o,source:s}),this.logger.debug("CommandsPlugin","CommandExecuted",`Command '${e}' executed for document '${o}' (source: ${s})`)):this.logger.warn("CommandsPlugin","ExecutionBlocked",`Command '${e}' is not visible for document '${o}'`)}registerCommand(e){if(this.commands.has(e.id)&&this.logger.warn("CommandsPlugin","CommandOverwrite",`Command '${e.id}' already exists and will be overwritten`),this.commands.set(e.id,e),e.shortcuts){(Array.isArray(e.shortcuts)?e.shortcuts:[e.shortcuts]).forEach(t=>{const s=this.normalizeShortcut(t);this.shortcutMap.set(s,e.id)})}this.logger.debug("CommandsPlugin","CommandRegistered",`Command '${e.id}' registered`)}unregisterCommand(e){const t=this.commands.get(e);if(t){if(t.shortcuts){(Array.isArray(t.shortcuts)?t.shortcuts:[t.shortcuts]).forEach(e=>{const t=this.normalizeShortcut(e);this.shortcutMap.delete(t)})}this.commands.delete(e),this.logger.debug("CommandsPlugin","CommandUnregistered",`Command '${e}' unregistered`)}}getCommandByShortcut(e){const t=this.normalizeShortcut(e),s=this.shortcutMap.get(t);return s?this.commands.get(s)??null:null}normalizeShortcut(e){return e.toLowerCase().split("+").sort().join("+")}getAllCommands(e){const t=e??this.getActiveDocumentId();return Array.from(this.commands.keys()).map(e=>this.resolve(e,t))}getCommandsByCategory(e,t){const s=t??this.getActiveDocumentId();return Array.from(this.commands.values()).filter(t=>t.category===e).map(e=>this.resolve(e.id,s))}onGlobalStoreChange(e){Object.keys(e.core.documents).forEach(t=>{this.detectCommandChanges(t,e)})}detectCommandChanges(t,s){const o=this.previousStates.get(t)??new Map;this.commands.forEach((s,i)=>{const n=this.resolve(i,t),a=o.get(i);if(!a)return void o.set(i,n);const r={};a.active!==n.active&&(r.active=n.active),a.disabled!==n.disabled&&(r.disabled=n.disabled),a.visible!==n.visible&&(r.visible=n.visible),a.label!==n.label&&(r.label=n.label),e.arePropsEqual(a.iconProps,n.iconProps)||(r.iconProps=n.iconProps),Object.keys(r).length>0&&(o.set(i,n),this.commandStateChanged$.emit({commandId:i,documentId:t,changes:r}))}),this.previousStates.set(t,o)}};o.id="commands";let i=o;const n={changedCommands:new Set},a={manifest:s,create:(e,s)=>new i(t,e,s),reducer:(e=n,t)=>{switch(t.type){case"COMMANDS/MARK_CHANGED":{const s=new Set(e.changedCommands);return t.payload.forEach(e=>s.add(e)),{...e,changedCommands:s}}case"COMMANDS/CLEAR_CHANGED":return{...e,changedCommands:new Set};default:return e}},initialState:n};exports.COMMANDS_PLUGIN_ID=t,exports.CommandsPlugin=i,exports.CommandsPluginPackage=a,exports.manifest=s;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t="commands",s={id:t,name:"Commands Plugin",version:"1.0.0",provides:["commands"],requires:[],optional:["i18n"],defaultConfig:{commands:{}}},i="COMMANDS/SET_DISABLED_CATEGORIES",o=e=>({type:i,payload:e}),a=class extends e.BasePlugin{constructor(t,s,i){var a;super(t,s),this.commands=new Map,this.i18n=null,this.shortcutMap=new Map,this.commandExecuted$=e.createEmitter(),this.commandStateChanged$=e.createEmitter(),this.shortcutExecuted$=e.createEmitter(),this.categoryChanged$=e.createBehaviorEmitter(),this.previousStates=new Map;const r=s.getPlugin("i18n");this.i18n=(null==r?void 0:r.provides())??null,(null==(a=i.disabledCategories)?void 0:a.length)&&this.dispatch(o(i.disabledCategories)),Object.values(i.commands).forEach(e=>{this.registerCommand(e)}),this.registry.getStore().subscribe((e,t)=>{this.onGlobalStoreChange(t)})}onDocumentClosed(e){this.previousStates.delete(e),this.logger.debug("CommandsPlugin","DocumentClosed",`Cleaned up command state cache for document: ${e}`)}async initialize(){this.logger.info("CommandsPlugin","Initialize","Commands plugin initialized")}async destroy(){this.commandExecuted$.clear(),this.commandStateChanged$.clear(),this.shortcutExecuted$.clear(),this.categoryChanged$.clear(),this.commands.clear(),this.shortcutMap.clear(),this.previousStates.clear(),super.destroy()}disableCategoryImpl(e){const t=new Set(this.state.disabledCategories);t.has(e)||(t.add(e),this.dispatch(o(Array.from(t))),this.categoryChanged$.emit({disabledCategories:Array.from(t)}))}enableCategoryImpl(e){const t=new Set(this.state.disabledCategories);t.has(e)&&(t.delete(e),this.dispatch(o(Array.from(t))),this.categoryChanged$.emit({disabledCategories:Array.from(t)}))}toggleCategoryImpl(e){this.state.disabledCategories.includes(e)?this.enableCategoryImpl(e):this.disableCategoryImpl(e)}setDisabledCategoriesImpl(e){this.dispatch(o(e)),this.categoryChanged$.emit({disabledCategories:e})}isCommandCategoryDisabled(e){var t;return!!(null==(t=e.categories)?void 0:t.length)&&e.categories.some(e=>this.state.disabledCategories.includes(e))}buildCapability(){return{resolve:(e,t)=>this.resolve(e,t),execute:(e,t,s="ui")=>this.execute(e,t,s),getAllCommands:e=>this.getAllCommands(e),getCommandsByCategory:(e,t)=>this.getCommandsByCategory(e,t),getCommandByShortcut:e=>this.getCommandByShortcut(e),getAllShortcuts:()=>new Map(this.shortcutMap),forDocument:e=>this.createCommandScope(e),registerCommand:e=>this.registerCommand(e),unregisterCommand:e=>this.unregisterCommand(e),disableCategory:e=>this.disableCategoryImpl(e),enableCategory:e=>this.enableCategoryImpl(e),toggleCategory:e=>this.toggleCategoryImpl(e),setDisabledCategories:e=>this.setDisabledCategoriesImpl(e),getDisabledCategories:()=>this.state.disabledCategories,isCategoryDisabled:e=>this.state.disabledCategories.includes(e),onCommandExecuted:this.commandExecuted$.on,onCommandStateChanged:this.commandStateChanged$.on,onShortcutExecuted:this.shortcutExecuted$.on,onCategoryChanged:this.categoryChanged$.on}}createCommandScope(e){return{resolve:t=>this.resolve(t,e),execute:(t,s="ui")=>this.execute(t,e,s),getAllCommands:()=>this.getAllCommands(e),getCommandsByCategory:t=>this.getCommandsByCategory(t,e),onCommandStateChanged:t=>this.commandStateChanged$.on(s=>{if(s.documentId===e){const{documentId:e,...i}=s;t(i)}})}}resolve(e,t){const s=t??this.getActiveDocumentId(),i=this.commands.get(e);if(!i)throw new Error(`Command not found: ${e}`);const o=this.registry.getStore().getState(),a=this.resolveLabel(i,o,s),r=i.shortcuts?Array.isArray(i.shortcuts)?i.shortcuts:[i.shortcuts]:void 0,n=this.resolveDynamic(i.disabled,o,s)??!1,d=this.isCommandCategoryDisabled(i),m=n||d;return{id:i.id,label:a,icon:this.resolveDynamic(i.icon,o,s),iconProps:this.resolveDynamic(i.iconProps,o,s),active:this.resolveDynamic(i.active,o,s)??!1,disabled:m,visible:this.resolveDynamic(i.visible,o,s)??!0,shortcuts:r,shortcutLabel:i.shortcutLabel,categories:i.categories,description:i.description,execute:()=>i.action({registry:this.registry,state:o,documentId:s})}}resolveLabel(e,t,s){if(e.labelKey&&this.i18n){const i=this.resolveDynamic(e.labelParams,t,s);return this.i18n.t(e.labelKey,{params:i,documentId:s})}return e.label?e.label:e.id}resolveDynamic(e,t,s){if(void 0!==e)return"function"==typeof e?e({state:t,documentId:s}):e}execute(e,t,s="ui"){const i=t??this.getActiveDocumentId(),o=this.resolve(e,i);o.disabled?this.logger.warn("CommandsPlugin","ExecutionBlocked",`Command '${e}' is disabled for document '${i}'`):o.visible?(o.execute(),this.commandExecuted$.emit({commandId:e,documentId:i,source:s}),this.logger.debug("CommandsPlugin","CommandExecuted",`Command '${e}' executed for document '${i}' (source: ${s})`)):this.logger.warn("CommandsPlugin","ExecutionBlocked",`Command '${e}' is not visible for document '${i}'`)}registerCommand(e){if(this.commands.has(e.id)&&this.logger.warn("CommandsPlugin","CommandOverwrite",`Command '${e.id}' already exists and will be overwritten`),this.commands.set(e.id,e),e.shortcuts){(Array.isArray(e.shortcuts)?e.shortcuts:[e.shortcuts]).forEach(t=>{const s=this.normalizeShortcut(t);this.shortcutMap.set(s,e.id)})}this.logger.debug("CommandsPlugin","CommandRegistered",`Command '${e.id}' registered`)}unregisterCommand(e){const t=this.commands.get(e);if(t){if(t.shortcuts){(Array.isArray(t.shortcuts)?t.shortcuts:[t.shortcuts]).forEach(e=>{const t=this.normalizeShortcut(e);this.shortcutMap.delete(t)})}this.commands.delete(e),this.logger.debug("CommandsPlugin","CommandUnregistered",`Command '${e}' unregistered`)}}getCommandByShortcut(e){const t=this.normalizeShortcut(e),s=this.shortcutMap.get(t);return s?this.commands.get(s)??null:null}normalizeShortcut(e){return e.toLowerCase().split("+").sort().join("+")}getAllCommands(e){const t=e??this.getActiveDocumentId();return Array.from(this.commands.keys()).map(e=>this.resolve(e,t))}getCommandsByCategory(e,t){const s=t??this.getActiveDocumentId();return Array.from(this.commands.values()).filter(t=>{var s;return null==(s=t.categories)?void 0:s.includes(e)}).map(e=>this.resolve(e.id,s))}onGlobalStoreChange(e){Object.keys(e.core.documents).forEach(t=>{this.detectCommandChanges(t,e)})}detectCommandChanges(t,s){const i=this.previousStates.get(t)??new Map;this.commands.forEach((s,o)=>{const a=this.resolve(o,t),r=i.get(o);if(!r)return void i.set(o,a);const n={};r.active!==a.active&&(n.active=a.active),r.disabled!==a.disabled&&(n.disabled=a.disabled),r.visible!==a.visible&&(n.visible=a.visible),r.label!==a.label&&(n.label=a.label),e.arePropsEqual(r.iconProps,a.iconProps)||(n.iconProps=a.iconProps),Object.keys(n).length>0&&(i.set(o,a),this.commandStateChanged$.emit({commandId:o,documentId:t,changes:n}))}),this.previousStates.set(t,i)}};a.id="commands";let r=a;const n={disabledCategories:[]},d={manifest:s,create:(e,s)=>new r(t,e,s),reducer:(e=n,t)=>t.type===i?{...e,disabledCategories:t.payload}:e,initialState:n};exports.COMMANDS_PLUGIN_ID=t,exports.CommandsPlugin=r,exports.CommandsPluginPackage=d,exports.manifest=s;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/lib/manifest.ts","../src/lib/commands-plugin.ts","../src/lib/actions.ts","../src/lib/reducer.ts","../src/lib/index.ts"],"sourcesContent":["import { PluginManifest } from '@embedpdf/core';\nimport { CommandsPluginConfig } from './types';\n\nexport const COMMANDS_PLUGIN_ID = 'commands';\n\nexport const manifest: PluginManifest<CommandsPluginConfig> = {\n id: COMMANDS_PLUGIN_ID,\n name: 'Commands Plugin',\n version: '1.0.0',\n provides: ['commands'],\n requires: [],\n optional: ['i18n'],\n defaultConfig: {\n enabled: true,\n commands: {},\n },\n};\n","import {\n BasePlugin,\n PluginRegistry,\n StoreState,\n createEmitter,\n Listener,\n arePropsEqual,\n} from '@embedpdf/core';\nimport { I18nCapability, I18nPlugin } from '@embedpdf/plugin-i18n';\nimport {\n CommandsCapability,\n CommandsPluginConfig,\n CommandsState,\n Command,\n ResolvedCommand,\n CommandExecutedEvent,\n CommandStateChangedEvent,\n ShortcutExecutedEvent,\n CommandScope,\n Dynamic,\n} from './types';\nimport { CommandsAction } from './actions';\n\nexport class CommandsPlugin extends BasePlugin<\n CommandsPluginConfig,\n CommandsCapability,\n CommandsState,\n CommandsAction\n> {\n static readonly id = 'commands' as const;\n\n private commands = new Map<string, Command>();\n private i18n: I18nCapability | null = null;\n private shortcutMap = new Map<string, string>(); // shortcut -> commandId\n\n private readonly commandExecuted$ = createEmitter<CommandExecutedEvent>();\n private readonly commandStateChanged$ = createEmitter<CommandStateChangedEvent>();\n private readonly shortcutExecuted$ = createEmitter<ShortcutExecutedEvent>();\n\n // Cache previous resolved states per document to detect changes\n private previousStates = new Map<string, Map<string, ResolvedCommand>>();\n\n constructor(id: string, registry: PluginRegistry, config: CommandsPluginConfig) {\n super(id, registry);\n\n // Check if i18n plugin is available (optional dependency)\n const i18nPlugin = registry.getPlugin<I18nPlugin>('i18n');\n this.i18n = i18nPlugin?.provides() ?? null;\n\n // Register all commands from config\n Object.values(config.commands).forEach((command) => {\n this.registerCommand(command);\n });\n\n // Subscribe to global store changes\n this.registry.getStore().subscribe((_action, newState) => {\n this.onGlobalStoreChange(newState);\n });\n }\n\n protected override onDocumentClosed(documentId: string): void {\n // Cleanup previous states cache\n this.previousStates.delete(documentId);\n\n this.logger.debug(\n 'CommandsPlugin',\n 'DocumentClosed',\n `Cleaned up command state cache for document: ${documentId}`,\n );\n }\n\n async initialize(): Promise<void> {\n this.logger.info('CommandsPlugin', 'Initialize', 'Commands plugin initialized');\n }\n\n async destroy(): Promise<void> {\n this.commandExecuted$.clear();\n this.commandStateChanged$.clear();\n this.shortcutExecuted$.clear();\n this.commands.clear();\n this.shortcutMap.clear();\n this.previousStates.clear();\n super.destroy();\n }\n\n // ─────────────────────────────────────────────────────────\n // Capability\n // ─────────────────────────────────────────────────────────\n\n protected buildCapability(): CommandsCapability {\n return {\n resolve: (commandId, documentId) => this.resolve(commandId, documentId),\n execute: (commandId, documentId, source = 'ui') =>\n this.execute(commandId, documentId, source),\n getAllCommands: (documentId) => this.getAllCommands(documentId),\n getCommandsByCategory: (category, documentId) =>\n this.getCommandsByCategory(category, documentId),\n getCommandByShortcut: (shortcut) => this.getCommandByShortcut(shortcut),\n getAllShortcuts: () => new Map(this.shortcutMap),\n forDocument: (documentId) => this.createCommandScope(documentId),\n registerCommand: (command) => this.registerCommand(command),\n unregisterCommand: (commandId) => this.unregisterCommand(commandId),\n onCommandExecuted: this.commandExecuted$.on,\n onCommandStateChanged: this.commandStateChanged$.on,\n onShortcutExecuted: this.shortcutExecuted$.on,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Scoping\n // ─────────────────────────────────────────────────────────\n\n private createCommandScope(documentId: string): CommandScope {\n return {\n resolve: (commandId) => this.resolve(commandId, documentId),\n execute: (commandId, source = 'ui') => this.execute(commandId, documentId, source),\n getAllCommands: () => this.getAllCommands(documentId),\n getCommandsByCategory: (category) => this.getCommandsByCategory(category, documentId),\n onCommandStateChanged: (listener: Listener<Omit<CommandStateChangedEvent, 'documentId'>>) =>\n this.commandStateChanged$.on((event) => {\n if (event.documentId === documentId) {\n const { documentId: _, ...rest } = event;\n listener(rest);\n }\n }),\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Command Resolution\n // ─────────────────────────────────────────────────────────\n\n private resolve(commandId: string, documentId?: string): ResolvedCommand {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n\n const command = this.commands.get(commandId);\n if (!command) {\n throw new Error(`Command not found: ${commandId}`);\n }\n\n const state = this.registry.getStore().getState();\n\n // Resolve label with i18n if available\n const label = this.resolveLabel(command, state, resolvedDocId);\n\n // Resolve shortcuts\n const shortcuts = command.shortcuts\n ? Array.isArray(command.shortcuts)\n ? command.shortcuts\n : [command.shortcuts]\n : undefined;\n\n return {\n id: command.id,\n label,\n icon: this.resolveDynamic(command.icon, state, resolvedDocId),\n iconProps: this.resolveDynamic(command.iconProps, state, resolvedDocId),\n active: this.resolveDynamic(command.active, state, resolvedDocId) ?? false,\n disabled: this.resolveDynamic(command.disabled, state, resolvedDocId) ?? false,\n visible: this.resolveDynamic(command.visible, state, resolvedDocId) ?? true,\n shortcuts,\n shortcutLabel: command.shortcutLabel,\n category: command.category,\n description: command.description,\n execute: () => command.action({ registry: this.registry, state, documentId: resolvedDocId }),\n };\n }\n\n private resolveLabel(command: Command, state: StoreState<any>, documentId: string): string {\n // Priority: labelKey (with i18n) > label (plain string) > id (fallback)\n if (command.labelKey && this.i18n) {\n const params = this.resolveDynamic(command.labelParams, state, documentId);\n return this.i18n.t(command.labelKey, { params, documentId });\n }\n\n if (command.label) {\n return command.label;\n }\n\n return command.id; // Fallback to ID\n }\n\n private resolveDynamic<T>(\n value: Dynamic<any, T> | undefined,\n state: StoreState<any>,\n documentId: string,\n ): T | undefined {\n if (value === undefined) return undefined;\n\n // Check if it's a function (the dynamic evaluator)\n if (typeof value === 'function') {\n return (value as (context: { state: StoreState<any>; documentId: string }) => T)({\n state,\n documentId,\n });\n }\n\n // Otherwise it's the static value\n return value as T;\n }\n\n // ─────────────────────────────────────────────────────────\n // Command Execution\n // ─────────────────────────────────────────────────────────\n\n private execute(\n commandId: string,\n documentId?: string,\n source: 'keyboard' | 'ui' | 'api' = 'ui',\n ): void {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n const resolved = this.resolve(commandId, resolvedDocId);\n\n if (resolved.disabled) {\n this.logger.warn(\n 'CommandsPlugin',\n 'ExecutionBlocked',\n `Command '${commandId}' is disabled for document '${resolvedDocId}'`,\n );\n return;\n }\n\n if (!resolved.visible) {\n this.logger.warn(\n 'CommandsPlugin',\n 'ExecutionBlocked',\n `Command '${commandId}' is not visible for document '${resolvedDocId}'`,\n );\n return;\n }\n\n resolved.execute();\n\n this.commandExecuted$.emit({\n commandId,\n documentId: resolvedDocId,\n source,\n });\n\n this.logger.debug(\n 'CommandsPlugin',\n 'CommandExecuted',\n `Command '${commandId}' executed for document '${resolvedDocId}' (source: ${source})`,\n );\n }\n\n // ─────────────────────────────────────────────────────────\n // Command Registration\n // ─────────────────────────────────────────────────────────\n\n private registerCommand(command: Command): void {\n if (this.commands.has(command.id)) {\n this.logger.warn(\n 'CommandsPlugin',\n 'CommandOverwrite',\n `Command '${command.id}' already exists and will be overwritten`,\n );\n }\n\n this.commands.set(command.id, command);\n\n // Register shortcuts\n if (command.shortcuts) {\n const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];\n\n shortcuts.forEach((shortcut) => {\n const normalized = this.normalizeShortcut(shortcut);\n this.shortcutMap.set(normalized, command.id);\n });\n }\n\n this.logger.debug('CommandsPlugin', 'CommandRegistered', `Command '${command.id}' registered`);\n }\n\n private unregisterCommand(commandId: string): void {\n const command = this.commands.get(commandId);\n if (!command) return;\n\n // Remove shortcuts\n if (command.shortcuts) {\n const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];\n\n shortcuts.forEach((shortcut) => {\n const normalized = this.normalizeShortcut(shortcut);\n this.shortcutMap.delete(normalized);\n });\n }\n\n this.commands.delete(commandId);\n this.logger.debug(\n 'CommandsPlugin',\n 'CommandUnregistered',\n `Command '${commandId}' unregistered`,\n );\n }\n\n // ─────────────────────────────────────────────────────────\n // Shortcuts\n // ─────────────────────────────────────────────────────────\n\n private getCommandByShortcut(shortcut: string): Command | null {\n const normalized = this.normalizeShortcut(shortcut);\n const commandId = this.shortcutMap.get(normalized);\n return commandId ? (this.commands.get(commandId) ?? null) : null;\n }\n\n private normalizeShortcut(shortcut: string): string {\n // Normalize: \"Ctrl+Shift+A\" -> \"ctrl+shift+a\"\n return shortcut.toLowerCase().split('+').sort().join('+');\n }\n\n // ─────────────────────────────────────────────────────────\n // Query Methods\n // ─────────────────────────────────────────────────────────\n\n private getAllCommands(documentId?: string): ResolvedCommand[] {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n return Array.from(this.commands.keys()).map((id) => this.resolve(id, resolvedDocId));\n }\n\n private getCommandsByCategory(category: string, documentId?: string): ResolvedCommand[] {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n return Array.from(this.commands.values())\n .filter((cmd) => cmd.category === category)\n .map((cmd) => this.resolve(cmd.id, resolvedDocId));\n }\n\n // ─────────────────────────────────────────────────────────\n // State Change Detection\n // ─────────────────────────────────────────────────────────\n\n private onGlobalStoreChange(newState: StoreState<any>): void {\n // Get all documents from core state\n const documentIds = Object.keys(newState.core.documents);\n\n // Check each document for command state changes\n documentIds.forEach((documentId) => {\n this.detectCommandChanges(documentId, newState);\n });\n }\n\n private detectCommandChanges(documentId: string, newState: StoreState<any>): void {\n const previousCache = this.previousStates.get(documentId) ?? new Map();\n const changedCommandIds: string[] = [];\n\n this.commands.forEach((command, commandId) => {\n const newResolved = this.resolve(commandId, documentId);\n const prevResolved = previousCache.get(commandId);\n\n if (!prevResolved) {\n // First time resolving for this document\n previousCache.set(commandId, newResolved);\n return;\n }\n\n // Check for changes\n const changes: CommandStateChangedEvent['changes'] = {};\n\n if (prevResolved.active !== newResolved.active) {\n changes.active = newResolved.active;\n }\n if (prevResolved.disabled !== newResolved.disabled) {\n changes.disabled = newResolved.disabled;\n }\n if (prevResolved.visible !== newResolved.visible) {\n changes.visible = newResolved.visible;\n }\n if (prevResolved.label !== newResolved.label) {\n changes.label = newResolved.label;\n }\n if (!arePropsEqual(prevResolved.iconProps, newResolved.iconProps)) {\n changes.iconProps = newResolved.iconProps;\n }\n\n if (Object.keys(changes).length > 0) {\n changedCommandIds.push(commandId);\n previousCache.set(commandId, newResolved);\n\n this.commandStateChanged$.emit({\n commandId,\n documentId,\n changes,\n });\n }\n });\n\n this.previousStates.set(documentId, previousCache);\n }\n}\n","import { Action } from '@embedpdf/core';\n\nexport const REGISTER_COMMAND = 'COMMANDS/REGISTER';\nexport const UNREGISTER_COMMAND = 'COMMANDS/UNREGISTER';\nexport const MARK_COMMANDS_CHANGED = 'COMMANDS/MARK_CHANGED';\nexport const CLEAR_CHANGED_COMMANDS = 'COMMANDS/CLEAR_CHANGED';\n\nexport interface RegisterCommandAction extends Action {\n type: typeof REGISTER_COMMAND;\n payload: string; // commandId\n}\n\nexport interface UnregisterCommandAction extends Action {\n type: typeof UNREGISTER_COMMAND;\n payload: string; // commandId\n}\n\nexport interface MarkCommandsChangedAction extends Action {\n type: typeof MARK_COMMANDS_CHANGED;\n payload: string[]; // commandIds\n}\n\nexport interface ClearChangedCommandsAction extends Action {\n type: typeof CLEAR_CHANGED_COMMANDS;\n}\n\nexport type CommandsAction =\n | RegisterCommandAction\n | UnregisterCommandAction\n | MarkCommandsChangedAction\n | ClearChangedCommandsAction;\n\nexport const registerCommand = (commandId: string): RegisterCommandAction => ({\n type: REGISTER_COMMAND,\n payload: commandId,\n});\n\nexport const unregisterCommand = (commandId: string): UnregisterCommandAction => ({\n type: UNREGISTER_COMMAND,\n payload: commandId,\n});\n\nexport const markCommandsChanged = (commandIds: string[]): MarkCommandsChangedAction => ({\n type: MARK_COMMANDS_CHANGED,\n payload: commandIds,\n});\n\nexport const clearChangedCommands = (): ClearChangedCommandsAction => ({\n type: CLEAR_CHANGED_COMMANDS,\n});\n","import { Reducer } from '@embedpdf/core';\nimport { CommandsState } from './types';\nimport { CommandsAction, MARK_COMMANDS_CHANGED, CLEAR_CHANGED_COMMANDS } from './actions';\n\nexport const initialState: CommandsState = {\n changedCommands: new Set(),\n};\n\nexport const commandsReducer: Reducer<CommandsState, CommandsAction> = (\n state = initialState,\n action,\n) => {\n switch (action.type) {\n case MARK_COMMANDS_CHANGED: {\n const newSet = new Set(state.changedCommands);\n action.payload.forEach((id) => newSet.add(id));\n return {\n ...state,\n changedCommands: newSet,\n };\n }\n\n case CLEAR_CHANGED_COMMANDS: {\n return {\n ...state,\n changedCommands: new Set(),\n };\n }\n\n default:\n return state;\n }\n};\n","import { PluginPackage } from '@embedpdf/core';\nimport { manifest, COMMANDS_PLUGIN_ID } from './manifest';\nimport { CommandsPluginConfig, CommandsState } from './types';\nimport { CommandsPlugin } from './commands-plugin';\nimport { CommandsAction } from './actions';\nimport { commandsReducer, initialState } from './reducer';\n\nexport const CommandsPluginPackage: PluginPackage<\n CommandsPlugin,\n CommandsPluginConfig,\n CommandsState,\n CommandsAction\n> = {\n manifest,\n create: (registry, config) => new CommandsPlugin(COMMANDS_PLUGIN_ID, registry, config),\n reducer: commandsReducer,\n initialState,\n};\n\nexport * from './commands-plugin';\nexport * from './types';\nexport * from './manifest';\n"],"names":["COMMANDS_PLUGIN_ID","manifest","id","name","version","provides","requires","optional","defaultConfig","enabled","commands","_CommandsPlugin","BasePlugin","constructor","registry","config","super","this","Map","i18n","shortcutMap","commandExecuted$","createEmitter","commandStateChanged$","shortcutExecuted$","previousStates","i18nPlugin","getPlugin","Object","values","forEach","command","registerCommand","getStore","subscribe","_action","newState","onGlobalStoreChange","onDocumentClosed","documentId","delete","logger","debug","initialize","info","destroy","clear","buildCapability","resolve","commandId","execute","source","getAllCommands","getCommandsByCategory","category","getCommandByShortcut","shortcut","getAllShortcuts","forDocument","createCommandScope","unregisterCommand","onCommandExecuted","on","onCommandStateChanged","onShortcutExecuted","listener","event","_","rest","resolvedDocId","getActiveDocumentId","get","Error","state","getState","label","resolveLabel","shortcuts","Array","isArray","icon","resolveDynamic","iconProps","active","disabled","visible","shortcutLabel","description","action","labelKey","params","labelParams","t","value","resolved","warn","emit","has","set","normalized","normalizeShortcut","toLowerCase","split","sort","join","from","keys","map","filter","cmd","core","documents","detectCommandChanges","previousCache","newResolved","prevResolved","changes","arePropsEqual","length","CommandsPlugin","initialState","changedCommands","Set","CommandsPluginPackage","create","reducer","type","newSet","payload","add"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/lib/manifest.ts","../src/lib/actions.ts","../src/lib/commands-plugin.ts","../src/lib/reducer.ts","../src/lib/index.ts"],"sourcesContent":["import { PluginManifest } from '@embedpdf/core';\nimport { CommandsPluginConfig } from './types';\n\nexport const COMMANDS_PLUGIN_ID = 'commands';\n\nexport const manifest: PluginManifest<CommandsPluginConfig> = {\n id: COMMANDS_PLUGIN_ID,\n name: 'Commands Plugin',\n version: '1.0.0',\n provides: ['commands'],\n requires: [],\n optional: ['i18n'],\n defaultConfig: {\n commands: {},\n },\n};\n","import { Action } from '@embedpdf/core';\n\nexport const SET_DISABLED_CATEGORIES = 'COMMANDS/SET_DISABLED_CATEGORIES';\n\nexport interface SetDisabledCategoriesAction extends Action {\n type: typeof SET_DISABLED_CATEGORIES;\n payload: string[];\n}\n\nexport type CommandsAction = SetDisabledCategoriesAction;\n\nexport const setDisabledCategories = (categories: string[]): SetDisabledCategoriesAction => ({\n type: SET_DISABLED_CATEGORIES,\n payload: categories,\n});\n","import {\n BasePlugin,\n PluginRegistry,\n StoreState,\n createEmitter,\n createBehaviorEmitter,\n Listener,\n arePropsEqual,\n} from '@embedpdf/core';\nimport { I18nCapability, I18nPlugin } from '@embedpdf/plugin-i18n';\nimport {\n CommandsCapability,\n CommandsPluginConfig,\n CommandsState,\n Command,\n ResolvedCommand,\n CommandExecutedEvent,\n CommandStateChangedEvent,\n ShortcutExecutedEvent,\n CategoryChangedEvent,\n CommandScope,\n Dynamic,\n} from './types';\nimport { CommandsAction, setDisabledCategories } from './actions';\n\nexport class CommandsPlugin extends BasePlugin<\n CommandsPluginConfig,\n CommandsCapability,\n CommandsState,\n CommandsAction\n> {\n static readonly id = 'commands' as const;\n\n private commands = new Map<string, Command>();\n private i18n: I18nCapability | null = null;\n private shortcutMap = new Map<string, string>(); // shortcut -> commandId\n\n private readonly commandExecuted$ = createEmitter<CommandExecutedEvent>();\n private readonly commandStateChanged$ = createEmitter<CommandStateChangedEvent>();\n private readonly shortcutExecuted$ = createEmitter<ShortcutExecutedEvent>();\n private readonly categoryChanged$ = createBehaviorEmitter<CategoryChangedEvent>();\n\n // Cache previous resolved states per document to detect changes\n private previousStates = new Map<string, Map<string, ResolvedCommand>>();\n\n constructor(id: string, registry: PluginRegistry, config: CommandsPluginConfig) {\n super(id, registry);\n\n // Check if i18n plugin is available (optional dependency)\n const i18nPlugin = registry.getPlugin<I18nPlugin>('i18n');\n this.i18n = i18nPlugin?.provides() ?? null;\n\n // Initialize disabled categories from config\n if (config.disabledCategories?.length) {\n this.dispatch(setDisabledCategories(config.disabledCategories));\n }\n\n // Register all commands from config\n Object.values(config.commands).forEach((command) => {\n this.registerCommand(command);\n });\n\n // Subscribe to global store changes\n this.registry.getStore().subscribe((_action, newState) => {\n this.onGlobalStoreChange(newState);\n });\n }\n\n protected override onDocumentClosed(documentId: string): void {\n // Cleanup previous states cache\n this.previousStates.delete(documentId);\n\n this.logger.debug(\n 'CommandsPlugin',\n 'DocumentClosed',\n `Cleaned up command state cache for document: ${documentId}`,\n );\n }\n\n async initialize(): Promise<void> {\n this.logger.info('CommandsPlugin', 'Initialize', 'Commands plugin initialized');\n }\n\n async destroy(): Promise<void> {\n this.commandExecuted$.clear();\n this.commandStateChanged$.clear();\n this.shortcutExecuted$.clear();\n this.categoryChanged$.clear();\n this.commands.clear();\n this.shortcutMap.clear();\n this.previousStates.clear();\n super.destroy();\n }\n\n // ─────────────────────────────────────────────────────────\n // Category Management\n // ─────────────────────────────────────────────────────────\n\n private disableCategoryImpl(category: string): void {\n const current = new Set(this.state.disabledCategories);\n if (!current.has(category)) {\n current.add(category);\n this.dispatch(setDisabledCategories(Array.from(current)));\n this.categoryChanged$.emit({ disabledCategories: Array.from(current) });\n }\n }\n\n private enableCategoryImpl(category: string): void {\n const current = new Set(this.state.disabledCategories);\n if (current.has(category)) {\n current.delete(category);\n this.dispatch(setDisabledCategories(Array.from(current)));\n this.categoryChanged$.emit({ disabledCategories: Array.from(current) });\n }\n }\n\n private toggleCategoryImpl(category: string): void {\n if (this.state.disabledCategories.includes(category)) {\n this.enableCategoryImpl(category);\n } else {\n this.disableCategoryImpl(category);\n }\n }\n\n private setDisabledCategoriesImpl(categories: string[]): void {\n this.dispatch(setDisabledCategories(categories));\n this.categoryChanged$.emit({ disabledCategories: categories });\n }\n\n /**\n * Check if command has any disabled category\n */\n private isCommandCategoryDisabled(command: Command): boolean {\n if (!command.categories?.length) return false;\n return command.categories.some((cat) => this.state.disabledCategories.includes(cat));\n }\n\n // ─────────────────────────────────────────────────────────\n // Capability\n // ─────────────────────────────────────────────────────────\n\n protected buildCapability(): CommandsCapability {\n return {\n resolve: (commandId, documentId) => this.resolve(commandId, documentId),\n execute: (commandId, documentId, source = 'ui') =>\n this.execute(commandId, documentId, source),\n getAllCommands: (documentId) => this.getAllCommands(documentId),\n getCommandsByCategory: (category, documentId) =>\n this.getCommandsByCategory(category, documentId),\n getCommandByShortcut: (shortcut) => this.getCommandByShortcut(shortcut),\n getAllShortcuts: () => new Map(this.shortcutMap),\n forDocument: (documentId) => this.createCommandScope(documentId),\n registerCommand: (command) => this.registerCommand(command),\n unregisterCommand: (commandId) => this.unregisterCommand(commandId),\n\n // Category management\n disableCategory: (category) => this.disableCategoryImpl(category),\n enableCategory: (category) => this.enableCategoryImpl(category),\n toggleCategory: (category) => this.toggleCategoryImpl(category),\n setDisabledCategories: (categories) => this.setDisabledCategoriesImpl(categories),\n getDisabledCategories: () => this.state.disabledCategories,\n isCategoryDisabled: (category) => this.state.disabledCategories.includes(category),\n\n // Events\n onCommandExecuted: this.commandExecuted$.on,\n onCommandStateChanged: this.commandStateChanged$.on,\n onShortcutExecuted: this.shortcutExecuted$.on,\n onCategoryChanged: this.categoryChanged$.on,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Scoping\n // ─────────────────────────────────────────────────────────\n\n private createCommandScope(documentId: string): CommandScope {\n return {\n resolve: (commandId) => this.resolve(commandId, documentId),\n execute: (commandId, source = 'ui') => this.execute(commandId, documentId, source),\n getAllCommands: () => this.getAllCommands(documentId),\n getCommandsByCategory: (category) => this.getCommandsByCategory(category, documentId),\n onCommandStateChanged: (listener: Listener<Omit<CommandStateChangedEvent, 'documentId'>>) =>\n this.commandStateChanged$.on((event) => {\n if (event.documentId === documentId) {\n const { documentId: _, ...rest } = event;\n listener(rest);\n }\n }),\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Command Resolution\n // ─────────────────────────────────────────────────────────\n\n private resolve(commandId: string, documentId?: string): ResolvedCommand {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n\n const command = this.commands.get(commandId);\n if (!command) {\n throw new Error(`Command not found: ${commandId}`);\n }\n\n const state = this.registry.getStore().getState();\n\n // Resolve label with i18n if available\n const label = this.resolveLabel(command, state, resolvedDocId);\n\n // Resolve shortcuts\n const shortcuts = command.shortcuts\n ? Array.isArray(command.shortcuts)\n ? command.shortcuts\n : [command.shortcuts]\n : undefined;\n\n // Check if disabled via categories OR explicit disabled predicate\n const explicitDisabled = this.resolveDynamic(command.disabled, state, resolvedDocId) ?? false;\n const categoryDisabled = this.isCommandCategoryDisabled(command);\n const isDisabled = explicitDisabled || categoryDisabled;\n\n return {\n id: command.id,\n label,\n icon: this.resolveDynamic(command.icon, state, resolvedDocId),\n iconProps: this.resolveDynamic(command.iconProps, state, resolvedDocId),\n active: this.resolveDynamic(command.active, state, resolvedDocId) ?? false,\n disabled: isDisabled,\n visible: this.resolveDynamic(command.visible, state, resolvedDocId) ?? true,\n shortcuts,\n shortcutLabel: command.shortcutLabel,\n categories: command.categories,\n description: command.description,\n execute: () => command.action({ registry: this.registry, state, documentId: resolvedDocId }),\n };\n }\n\n private resolveLabel(command: Command, state: StoreState<any>, documentId: string): string {\n // Priority: labelKey (with i18n) > label (plain string) > id (fallback)\n if (command.labelKey && this.i18n) {\n const params = this.resolveDynamic(command.labelParams, state, documentId);\n return this.i18n.t(command.labelKey, { params, documentId });\n }\n\n if (command.label) {\n return command.label;\n }\n\n return command.id; // Fallback to ID\n }\n\n private resolveDynamic<T>(\n value: Dynamic<any, T> | undefined,\n state: StoreState<any>,\n documentId: string,\n ): T | undefined {\n if (value === undefined) return undefined;\n\n // Check if it's a function (the dynamic evaluator)\n if (typeof value === 'function') {\n return (value as (context: { state: StoreState<any>; documentId: string }) => T)({\n state,\n documentId,\n });\n }\n\n // Otherwise it's the static value\n return value as T;\n }\n\n // ─────────────────────────────────────────────────────────\n // Command Execution\n // ─────────────────────────────────────────────────────────\n\n private execute(\n commandId: string,\n documentId?: string,\n source: 'keyboard' | 'ui' | 'api' = 'ui',\n ): void {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n const resolved = this.resolve(commandId, resolvedDocId);\n\n if (resolved.disabled) {\n this.logger.warn(\n 'CommandsPlugin',\n 'ExecutionBlocked',\n `Command '${commandId}' is disabled for document '${resolvedDocId}'`,\n );\n return;\n }\n\n if (!resolved.visible) {\n this.logger.warn(\n 'CommandsPlugin',\n 'ExecutionBlocked',\n `Command '${commandId}' is not visible for document '${resolvedDocId}'`,\n );\n return;\n }\n\n resolved.execute();\n\n this.commandExecuted$.emit({\n commandId,\n documentId: resolvedDocId,\n source,\n });\n\n this.logger.debug(\n 'CommandsPlugin',\n 'CommandExecuted',\n `Command '${commandId}' executed for document '${resolvedDocId}' (source: ${source})`,\n );\n }\n\n // ─────────────────────────────────────────────────────────\n // Command Registration\n // ─────────────────────────────────────────────────────────\n\n private registerCommand(command: Command): void {\n if (this.commands.has(command.id)) {\n this.logger.warn(\n 'CommandsPlugin',\n 'CommandOverwrite',\n `Command '${command.id}' already exists and will be overwritten`,\n );\n }\n\n this.commands.set(command.id, command);\n\n // Register shortcuts\n if (command.shortcuts) {\n const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];\n\n shortcuts.forEach((shortcut) => {\n const normalized = this.normalizeShortcut(shortcut);\n this.shortcutMap.set(normalized, command.id);\n });\n }\n\n this.logger.debug('CommandsPlugin', 'CommandRegistered', `Command '${command.id}' registered`);\n }\n\n private unregisterCommand(commandId: string): void {\n const command = this.commands.get(commandId);\n if (!command) return;\n\n // Remove shortcuts\n if (command.shortcuts) {\n const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];\n\n shortcuts.forEach((shortcut) => {\n const normalized = this.normalizeShortcut(shortcut);\n this.shortcutMap.delete(normalized);\n });\n }\n\n this.commands.delete(commandId);\n this.logger.debug(\n 'CommandsPlugin',\n 'CommandUnregistered',\n `Command '${commandId}' unregistered`,\n );\n }\n\n // ─────────────────────────────────────────────────────────\n // Shortcuts\n // ─────────────────────────────────────────────────────────\n\n private getCommandByShortcut(shortcut: string): Command | null {\n const normalized = this.normalizeShortcut(shortcut);\n const commandId = this.shortcutMap.get(normalized);\n return commandId ? (this.commands.get(commandId) ?? null) : null;\n }\n\n private normalizeShortcut(shortcut: string): string {\n // Normalize: \"Ctrl+Shift+A\" -> \"ctrl+shift+a\"\n return shortcut.toLowerCase().split('+').sort().join('+');\n }\n\n // ─────────────────────────────────────────────────────────\n // Query Methods\n // ─────────────────────────────────────────────────────────\n\n private getAllCommands(documentId?: string): ResolvedCommand[] {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n return Array.from(this.commands.keys()).map((id) => this.resolve(id, resolvedDocId));\n }\n\n private getCommandsByCategory(category: string, documentId?: string): ResolvedCommand[] {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n return Array.from(this.commands.values())\n .filter((cmd) => cmd.categories?.includes(category))\n .map((cmd) => this.resolve(cmd.id, resolvedDocId));\n }\n\n // ─────────────────────────────────────────────────────────\n // State Change Detection\n // ─────────────────────────────────────────────────────────\n\n private onGlobalStoreChange(newState: StoreState<any>): void {\n // Get all documents from core state\n const documentIds = Object.keys(newState.core.documents);\n\n // Check each document for command state changes\n documentIds.forEach((documentId) => {\n this.detectCommandChanges(documentId, newState);\n });\n }\n\n private detectCommandChanges(documentId: string, newState: StoreState<any>): void {\n const previousCache = this.previousStates.get(documentId) ?? new Map();\n const changedCommandIds: string[] = [];\n\n this.commands.forEach((command, commandId) => {\n const newResolved = this.resolve(commandId, documentId);\n const prevResolved = previousCache.get(commandId);\n\n if (!prevResolved) {\n // First time resolving for this document\n previousCache.set(commandId, newResolved);\n return;\n }\n\n // Check for changes\n const changes: CommandStateChangedEvent['changes'] = {};\n\n if (prevResolved.active !== newResolved.active) {\n changes.active = newResolved.active;\n }\n if (prevResolved.disabled !== newResolved.disabled) {\n changes.disabled = newResolved.disabled;\n }\n if (prevResolved.visible !== newResolved.visible) {\n changes.visible = newResolved.visible;\n }\n if (prevResolved.label !== newResolved.label) {\n changes.label = newResolved.label;\n }\n if (!arePropsEqual(prevResolved.iconProps, newResolved.iconProps)) {\n changes.iconProps = newResolved.iconProps;\n }\n\n if (Object.keys(changes).length > 0) {\n changedCommandIds.push(commandId);\n previousCache.set(commandId, newResolved);\n\n this.commandStateChanged$.emit({\n commandId,\n documentId,\n changes,\n });\n }\n });\n\n this.previousStates.set(documentId, previousCache);\n }\n}\n","import { Reducer } from '@embedpdf/core';\nimport { CommandsState } from './types';\nimport { CommandsAction, SET_DISABLED_CATEGORIES } from './actions';\n\nexport const initialState: CommandsState = {\n disabledCategories: [],\n};\n\nexport const commandsReducer: Reducer<CommandsState, CommandsAction> = (\n state = initialState,\n action,\n) => {\n switch (action.type) {\n case SET_DISABLED_CATEGORIES:\n return {\n ...state,\n disabledCategories: action.payload,\n };\n\n default:\n return state;\n }\n};\n","import { PluginPackage } from '@embedpdf/core';\nimport { manifest, COMMANDS_PLUGIN_ID } from './manifest';\nimport { CommandsPluginConfig, CommandsState } from './types';\nimport { CommandsPlugin } from './commands-plugin';\nimport { CommandsAction } from './actions';\nimport { commandsReducer, initialState } from './reducer';\n\nexport const CommandsPluginPackage: PluginPackage<\n CommandsPlugin,\n CommandsPluginConfig,\n CommandsState,\n CommandsAction\n> = {\n manifest,\n create: (registry, config) => new CommandsPlugin(COMMANDS_PLUGIN_ID, registry, config),\n reducer: commandsReducer,\n initialState,\n};\n\nexport * from './commands-plugin';\nexport * from './types';\nexport * from './manifest';\n"],"names":["COMMANDS_PLUGIN_ID","manifest","id","name","version","provides","requires","optional","defaultConfig","commands","SET_DISABLED_CATEGORIES","setDisabledCategories","categories","type","payload","_CommandsPlugin","BasePlugin","constructor","registry","config","super","this","Map","i18n","shortcutMap","commandExecuted$","createEmitter","commandStateChanged$","shortcutExecuted$","categoryChanged$","createBehaviorEmitter","previousStates","i18nPlugin","getPlugin","_a","disabledCategories","length","dispatch","Object","values","forEach","command","registerCommand","getStore","subscribe","_action","newState","onGlobalStoreChange","onDocumentClosed","documentId","delete","logger","debug","initialize","info","destroy","clear","disableCategoryImpl","category","current","Set","state","has","add","Array","from","emit","enableCategoryImpl","toggleCategoryImpl","includes","setDisabledCategoriesImpl","isCommandCategoryDisabled","some","cat","buildCapability","resolve","commandId","execute","source","getAllCommands","getCommandsByCategory","getCommandByShortcut","shortcut","getAllShortcuts","forDocument","createCommandScope","unregisterCommand","disableCategory","enableCategory","toggleCategory","getDisabledCategories","isCategoryDisabled","onCommandExecuted","on","onCommandStateChanged","onShortcutExecuted","onCategoryChanged","listener","event","_","rest","resolvedDocId","getActiveDocumentId","get","Error","getState","label","resolveLabel","shortcuts","isArray","explicitDisabled","resolveDynamic","disabled","categoryDisabled","isDisabled","icon","iconProps","active","visible","shortcutLabel","description","action","labelKey","params","labelParams","t","value","resolved","warn","set","normalized","normalizeShortcut","toLowerCase","split","sort","join","keys","map","filter","cmd","core","documents","detectCommandChanges","previousCache","newResolved","prevResolved","changes","arePropsEqual","CommandsPlugin","initialState","CommandsPluginPackage","create","reducer"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { BasePlugin, createEmitter, arePropsEqual } from "@embedpdf/core";
1
+ import { BasePlugin, createEmitter, createBehaviorEmitter, arePropsEqual } from "@embedpdf/core";
2
2
  const COMMANDS_PLUGIN_ID = "commands";
3
3
  const manifest = {
4
4
  id: COMMANDS_PLUGIN_ID,
@@ -8,12 +8,17 @@ const manifest = {
8
8
  requires: [],
9
9
  optional: ["i18n"],
10
10
  defaultConfig: {
11
- enabled: true,
12
11
  commands: {}
13
12
  }
14
13
  };
14
+ const SET_DISABLED_CATEGORIES = "COMMANDS/SET_DISABLED_CATEGORIES";
15
+ const setDisabledCategories = (categories) => ({
16
+ type: SET_DISABLED_CATEGORIES,
17
+ payload: categories
18
+ });
15
19
  const _CommandsPlugin = class _CommandsPlugin extends BasePlugin {
16
20
  constructor(id, registry, config) {
21
+ var _a;
17
22
  super(id, registry);
18
23
  this.commands = /* @__PURE__ */ new Map();
19
24
  this.i18n = null;
@@ -21,9 +26,13 @@ const _CommandsPlugin = class _CommandsPlugin extends BasePlugin {
21
26
  this.commandExecuted$ = createEmitter();
22
27
  this.commandStateChanged$ = createEmitter();
23
28
  this.shortcutExecuted$ = createEmitter();
29
+ this.categoryChanged$ = createBehaviorEmitter();
24
30
  this.previousStates = /* @__PURE__ */ new Map();
25
31
  const i18nPlugin = registry.getPlugin("i18n");
26
32
  this.i18n = (i18nPlugin == null ? void 0 : i18nPlugin.provides()) ?? null;
33
+ if ((_a = config.disabledCategories) == null ? void 0 : _a.length) {
34
+ this.dispatch(setDisabledCategories(config.disabledCategories));
35
+ }
27
36
  Object.values(config.commands).forEach((command) => {
28
37
  this.registerCommand(command);
29
38
  });
@@ -46,12 +55,51 @@ const _CommandsPlugin = class _CommandsPlugin extends BasePlugin {
46
55
  this.commandExecuted$.clear();
47
56
  this.commandStateChanged$.clear();
48
57
  this.shortcutExecuted$.clear();
58
+ this.categoryChanged$.clear();
49
59
  this.commands.clear();
50
60
  this.shortcutMap.clear();
51
61
  this.previousStates.clear();
52
62
  super.destroy();
53
63
  }
54
64
  // ─────────────────────────────────────────────────────────
65
+ // Category Management
66
+ // ─────────────────────────────────────────────────────────
67
+ disableCategoryImpl(category) {
68
+ const current = new Set(this.state.disabledCategories);
69
+ if (!current.has(category)) {
70
+ current.add(category);
71
+ this.dispatch(setDisabledCategories(Array.from(current)));
72
+ this.categoryChanged$.emit({ disabledCategories: Array.from(current) });
73
+ }
74
+ }
75
+ enableCategoryImpl(category) {
76
+ const current = new Set(this.state.disabledCategories);
77
+ if (current.has(category)) {
78
+ current.delete(category);
79
+ this.dispatch(setDisabledCategories(Array.from(current)));
80
+ this.categoryChanged$.emit({ disabledCategories: Array.from(current) });
81
+ }
82
+ }
83
+ toggleCategoryImpl(category) {
84
+ if (this.state.disabledCategories.includes(category)) {
85
+ this.enableCategoryImpl(category);
86
+ } else {
87
+ this.disableCategoryImpl(category);
88
+ }
89
+ }
90
+ setDisabledCategoriesImpl(categories) {
91
+ this.dispatch(setDisabledCategories(categories));
92
+ this.categoryChanged$.emit({ disabledCategories: categories });
93
+ }
94
+ /**
95
+ * Check if command has any disabled category
96
+ */
97
+ isCommandCategoryDisabled(command) {
98
+ var _a;
99
+ if (!((_a = command.categories) == null ? void 0 : _a.length)) return false;
100
+ return command.categories.some((cat) => this.state.disabledCategories.includes(cat));
101
+ }
102
+ // ─────────────────────────────────────────────────────────
55
103
  // Capability
56
104
  // ─────────────────────────────────────────────────────────
57
105
  buildCapability() {
@@ -65,9 +113,18 @@ const _CommandsPlugin = class _CommandsPlugin extends BasePlugin {
65
113
  forDocument: (documentId) => this.createCommandScope(documentId),
66
114
  registerCommand: (command) => this.registerCommand(command),
67
115
  unregisterCommand: (commandId) => this.unregisterCommand(commandId),
116
+ // Category management
117
+ disableCategory: (category) => this.disableCategoryImpl(category),
118
+ enableCategory: (category) => this.enableCategoryImpl(category),
119
+ toggleCategory: (category) => this.toggleCategoryImpl(category),
120
+ setDisabledCategories: (categories) => this.setDisabledCategoriesImpl(categories),
121
+ getDisabledCategories: () => this.state.disabledCategories,
122
+ isCategoryDisabled: (category) => this.state.disabledCategories.includes(category),
123
+ // Events
68
124
  onCommandExecuted: this.commandExecuted$.on,
69
125
  onCommandStateChanged: this.commandStateChanged$.on,
70
- onShortcutExecuted: this.shortcutExecuted$.on
126
+ onShortcutExecuted: this.shortcutExecuted$.on,
127
+ onCategoryChanged: this.categoryChanged$.on
71
128
  };
72
129
  }
73
130
  // ─────────────────────────────────────────────────────────
@@ -99,17 +156,20 @@ const _CommandsPlugin = class _CommandsPlugin extends BasePlugin {
99
156
  const state = this.registry.getStore().getState();
100
157
  const label = this.resolveLabel(command, state, resolvedDocId);
101
158
  const shortcuts = command.shortcuts ? Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts] : void 0;
159
+ const explicitDisabled = this.resolveDynamic(command.disabled, state, resolvedDocId) ?? false;
160
+ const categoryDisabled = this.isCommandCategoryDisabled(command);
161
+ const isDisabled = explicitDisabled || categoryDisabled;
102
162
  return {
103
163
  id: command.id,
104
164
  label,
105
165
  icon: this.resolveDynamic(command.icon, state, resolvedDocId),
106
166
  iconProps: this.resolveDynamic(command.iconProps, state, resolvedDocId),
107
167
  active: this.resolveDynamic(command.active, state, resolvedDocId) ?? false,
108
- disabled: this.resolveDynamic(command.disabled, state, resolvedDocId) ?? false,
168
+ disabled: isDisabled,
109
169
  visible: this.resolveDynamic(command.visible, state, resolvedDocId) ?? true,
110
170
  shortcuts,
111
171
  shortcutLabel: command.shortcutLabel,
112
- category: command.category,
172
+ categories: command.categories,
113
173
  description: command.description,
114
174
  execute: () => command.action({ registry: this.registry, state, documentId: resolvedDocId })
115
175
  };
@@ -226,7 +286,10 @@ const _CommandsPlugin = class _CommandsPlugin extends BasePlugin {
226
286
  }
227
287
  getCommandsByCategory(category, documentId) {
228
288
  const resolvedDocId = documentId ?? this.getActiveDocumentId();
229
- return Array.from(this.commands.values()).filter((cmd) => cmd.category === category).map((cmd) => this.resolve(cmd.id, resolvedDocId));
289
+ return Array.from(this.commands.values()).filter((cmd) => {
290
+ var _a;
291
+ return (_a = cmd.categories) == null ? void 0 : _a.includes(category);
292
+ }).map((cmd) => this.resolve(cmd.id, resolvedDocId));
230
293
  }
231
294
  // ─────────────────────────────────────────────────────────
232
295
  // State Change Detection
@@ -276,27 +339,16 @@ const _CommandsPlugin = class _CommandsPlugin extends BasePlugin {
276
339
  };
277
340
  _CommandsPlugin.id = "commands";
278
341
  let CommandsPlugin = _CommandsPlugin;
279
- const MARK_COMMANDS_CHANGED = "COMMANDS/MARK_CHANGED";
280
- const CLEAR_CHANGED_COMMANDS = "COMMANDS/CLEAR_CHANGED";
281
342
  const initialState = {
282
- changedCommands: /* @__PURE__ */ new Set()
343
+ disabledCategories: []
283
344
  };
284
345
  const commandsReducer = (state = initialState, action) => {
285
346
  switch (action.type) {
286
- case MARK_COMMANDS_CHANGED: {
287
- const newSet = new Set(state.changedCommands);
288
- action.payload.forEach((id) => newSet.add(id));
289
- return {
290
- ...state,
291
- changedCommands: newSet
292
- };
293
- }
294
- case CLEAR_CHANGED_COMMANDS: {
347
+ case SET_DISABLED_CATEGORIES:
295
348
  return {
296
349
  ...state,
297
- changedCommands: /* @__PURE__ */ new Set()
350
+ disabledCategories: action.payload
298
351
  };
299
- }
300
352
  default:
301
353
  return state;
302
354
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/lib/manifest.ts","../src/lib/commands-plugin.ts","../src/lib/actions.ts","../src/lib/reducer.ts","../src/lib/index.ts"],"sourcesContent":["import { PluginManifest } from '@embedpdf/core';\nimport { CommandsPluginConfig } from './types';\n\nexport const COMMANDS_PLUGIN_ID = 'commands';\n\nexport const manifest: PluginManifest<CommandsPluginConfig> = {\n id: COMMANDS_PLUGIN_ID,\n name: 'Commands Plugin',\n version: '1.0.0',\n provides: ['commands'],\n requires: [],\n optional: ['i18n'],\n defaultConfig: {\n enabled: true,\n commands: {},\n },\n};\n","import {\n BasePlugin,\n PluginRegistry,\n StoreState,\n createEmitter,\n Listener,\n arePropsEqual,\n} from '@embedpdf/core';\nimport { I18nCapability, I18nPlugin } from '@embedpdf/plugin-i18n';\nimport {\n CommandsCapability,\n CommandsPluginConfig,\n CommandsState,\n Command,\n ResolvedCommand,\n CommandExecutedEvent,\n CommandStateChangedEvent,\n ShortcutExecutedEvent,\n CommandScope,\n Dynamic,\n} from './types';\nimport { CommandsAction } from './actions';\n\nexport class CommandsPlugin extends BasePlugin<\n CommandsPluginConfig,\n CommandsCapability,\n CommandsState,\n CommandsAction\n> {\n static readonly id = 'commands' as const;\n\n private commands = new Map<string, Command>();\n private i18n: I18nCapability | null = null;\n private shortcutMap = new Map<string, string>(); // shortcut -> commandId\n\n private readonly commandExecuted$ = createEmitter<CommandExecutedEvent>();\n private readonly commandStateChanged$ = createEmitter<CommandStateChangedEvent>();\n private readonly shortcutExecuted$ = createEmitter<ShortcutExecutedEvent>();\n\n // Cache previous resolved states per document to detect changes\n private previousStates = new Map<string, Map<string, ResolvedCommand>>();\n\n constructor(id: string, registry: PluginRegistry, config: CommandsPluginConfig) {\n super(id, registry);\n\n // Check if i18n plugin is available (optional dependency)\n const i18nPlugin = registry.getPlugin<I18nPlugin>('i18n');\n this.i18n = i18nPlugin?.provides() ?? null;\n\n // Register all commands from config\n Object.values(config.commands).forEach((command) => {\n this.registerCommand(command);\n });\n\n // Subscribe to global store changes\n this.registry.getStore().subscribe((_action, newState) => {\n this.onGlobalStoreChange(newState);\n });\n }\n\n protected override onDocumentClosed(documentId: string): void {\n // Cleanup previous states cache\n this.previousStates.delete(documentId);\n\n this.logger.debug(\n 'CommandsPlugin',\n 'DocumentClosed',\n `Cleaned up command state cache for document: ${documentId}`,\n );\n }\n\n async initialize(): Promise<void> {\n this.logger.info('CommandsPlugin', 'Initialize', 'Commands plugin initialized');\n }\n\n async destroy(): Promise<void> {\n this.commandExecuted$.clear();\n this.commandStateChanged$.clear();\n this.shortcutExecuted$.clear();\n this.commands.clear();\n this.shortcutMap.clear();\n this.previousStates.clear();\n super.destroy();\n }\n\n // ─────────────────────────────────────────────────────────\n // Capability\n // ─────────────────────────────────────────────────────────\n\n protected buildCapability(): CommandsCapability {\n return {\n resolve: (commandId, documentId) => this.resolve(commandId, documentId),\n execute: (commandId, documentId, source = 'ui') =>\n this.execute(commandId, documentId, source),\n getAllCommands: (documentId) => this.getAllCommands(documentId),\n getCommandsByCategory: (category, documentId) =>\n this.getCommandsByCategory(category, documentId),\n getCommandByShortcut: (shortcut) => this.getCommandByShortcut(shortcut),\n getAllShortcuts: () => new Map(this.shortcutMap),\n forDocument: (documentId) => this.createCommandScope(documentId),\n registerCommand: (command) => this.registerCommand(command),\n unregisterCommand: (commandId) => this.unregisterCommand(commandId),\n onCommandExecuted: this.commandExecuted$.on,\n onCommandStateChanged: this.commandStateChanged$.on,\n onShortcutExecuted: this.shortcutExecuted$.on,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Scoping\n // ─────────────────────────────────────────────────────────\n\n private createCommandScope(documentId: string): CommandScope {\n return {\n resolve: (commandId) => this.resolve(commandId, documentId),\n execute: (commandId, source = 'ui') => this.execute(commandId, documentId, source),\n getAllCommands: () => this.getAllCommands(documentId),\n getCommandsByCategory: (category) => this.getCommandsByCategory(category, documentId),\n onCommandStateChanged: (listener: Listener<Omit<CommandStateChangedEvent, 'documentId'>>) =>\n this.commandStateChanged$.on((event) => {\n if (event.documentId === documentId) {\n const { documentId: _, ...rest } = event;\n listener(rest);\n }\n }),\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Command Resolution\n // ─────────────────────────────────────────────────────────\n\n private resolve(commandId: string, documentId?: string): ResolvedCommand {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n\n const command = this.commands.get(commandId);\n if (!command) {\n throw new Error(`Command not found: ${commandId}`);\n }\n\n const state = this.registry.getStore().getState();\n\n // Resolve label with i18n if available\n const label = this.resolveLabel(command, state, resolvedDocId);\n\n // Resolve shortcuts\n const shortcuts = command.shortcuts\n ? Array.isArray(command.shortcuts)\n ? command.shortcuts\n : [command.shortcuts]\n : undefined;\n\n return {\n id: command.id,\n label,\n icon: this.resolveDynamic(command.icon, state, resolvedDocId),\n iconProps: this.resolveDynamic(command.iconProps, state, resolvedDocId),\n active: this.resolveDynamic(command.active, state, resolvedDocId) ?? false,\n disabled: this.resolveDynamic(command.disabled, state, resolvedDocId) ?? false,\n visible: this.resolveDynamic(command.visible, state, resolvedDocId) ?? true,\n shortcuts,\n shortcutLabel: command.shortcutLabel,\n category: command.category,\n description: command.description,\n execute: () => command.action({ registry: this.registry, state, documentId: resolvedDocId }),\n };\n }\n\n private resolveLabel(command: Command, state: StoreState<any>, documentId: string): string {\n // Priority: labelKey (with i18n) > label (plain string) > id (fallback)\n if (command.labelKey && this.i18n) {\n const params = this.resolveDynamic(command.labelParams, state, documentId);\n return this.i18n.t(command.labelKey, { params, documentId });\n }\n\n if (command.label) {\n return command.label;\n }\n\n return command.id; // Fallback to ID\n }\n\n private resolveDynamic<T>(\n value: Dynamic<any, T> | undefined,\n state: StoreState<any>,\n documentId: string,\n ): T | undefined {\n if (value === undefined) return undefined;\n\n // Check if it's a function (the dynamic evaluator)\n if (typeof value === 'function') {\n return (value as (context: { state: StoreState<any>; documentId: string }) => T)({\n state,\n documentId,\n });\n }\n\n // Otherwise it's the static value\n return value as T;\n }\n\n // ─────────────────────────────────────────────────────────\n // Command Execution\n // ─────────────────────────────────────────────────────────\n\n private execute(\n commandId: string,\n documentId?: string,\n source: 'keyboard' | 'ui' | 'api' = 'ui',\n ): void {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n const resolved = this.resolve(commandId, resolvedDocId);\n\n if (resolved.disabled) {\n this.logger.warn(\n 'CommandsPlugin',\n 'ExecutionBlocked',\n `Command '${commandId}' is disabled for document '${resolvedDocId}'`,\n );\n return;\n }\n\n if (!resolved.visible) {\n this.logger.warn(\n 'CommandsPlugin',\n 'ExecutionBlocked',\n `Command '${commandId}' is not visible for document '${resolvedDocId}'`,\n );\n return;\n }\n\n resolved.execute();\n\n this.commandExecuted$.emit({\n commandId,\n documentId: resolvedDocId,\n source,\n });\n\n this.logger.debug(\n 'CommandsPlugin',\n 'CommandExecuted',\n `Command '${commandId}' executed for document '${resolvedDocId}' (source: ${source})`,\n );\n }\n\n // ─────────────────────────────────────────────────────────\n // Command Registration\n // ─────────────────────────────────────────────────────────\n\n private registerCommand(command: Command): void {\n if (this.commands.has(command.id)) {\n this.logger.warn(\n 'CommandsPlugin',\n 'CommandOverwrite',\n `Command '${command.id}' already exists and will be overwritten`,\n );\n }\n\n this.commands.set(command.id, command);\n\n // Register shortcuts\n if (command.shortcuts) {\n const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];\n\n shortcuts.forEach((shortcut) => {\n const normalized = this.normalizeShortcut(shortcut);\n this.shortcutMap.set(normalized, command.id);\n });\n }\n\n this.logger.debug('CommandsPlugin', 'CommandRegistered', `Command '${command.id}' registered`);\n }\n\n private unregisterCommand(commandId: string): void {\n const command = this.commands.get(commandId);\n if (!command) return;\n\n // Remove shortcuts\n if (command.shortcuts) {\n const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];\n\n shortcuts.forEach((shortcut) => {\n const normalized = this.normalizeShortcut(shortcut);\n this.shortcutMap.delete(normalized);\n });\n }\n\n this.commands.delete(commandId);\n this.logger.debug(\n 'CommandsPlugin',\n 'CommandUnregistered',\n `Command '${commandId}' unregistered`,\n );\n }\n\n // ─────────────────────────────────────────────────────────\n // Shortcuts\n // ─────────────────────────────────────────────────────────\n\n private getCommandByShortcut(shortcut: string): Command | null {\n const normalized = this.normalizeShortcut(shortcut);\n const commandId = this.shortcutMap.get(normalized);\n return commandId ? (this.commands.get(commandId) ?? null) : null;\n }\n\n private normalizeShortcut(shortcut: string): string {\n // Normalize: \"Ctrl+Shift+A\" -> \"ctrl+shift+a\"\n return shortcut.toLowerCase().split('+').sort().join('+');\n }\n\n // ─────────────────────────────────────────────────────────\n // Query Methods\n // ─────────────────────────────────────────────────────────\n\n private getAllCommands(documentId?: string): ResolvedCommand[] {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n return Array.from(this.commands.keys()).map((id) => this.resolve(id, resolvedDocId));\n }\n\n private getCommandsByCategory(category: string, documentId?: string): ResolvedCommand[] {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n return Array.from(this.commands.values())\n .filter((cmd) => cmd.category === category)\n .map((cmd) => this.resolve(cmd.id, resolvedDocId));\n }\n\n // ─────────────────────────────────────────────────────────\n // State Change Detection\n // ─────────────────────────────────────────────────────────\n\n private onGlobalStoreChange(newState: StoreState<any>): void {\n // Get all documents from core state\n const documentIds = Object.keys(newState.core.documents);\n\n // Check each document for command state changes\n documentIds.forEach((documentId) => {\n this.detectCommandChanges(documentId, newState);\n });\n }\n\n private detectCommandChanges(documentId: string, newState: StoreState<any>): void {\n const previousCache = this.previousStates.get(documentId) ?? new Map();\n const changedCommandIds: string[] = [];\n\n this.commands.forEach((command, commandId) => {\n const newResolved = this.resolve(commandId, documentId);\n const prevResolved = previousCache.get(commandId);\n\n if (!prevResolved) {\n // First time resolving for this document\n previousCache.set(commandId, newResolved);\n return;\n }\n\n // Check for changes\n const changes: CommandStateChangedEvent['changes'] = {};\n\n if (prevResolved.active !== newResolved.active) {\n changes.active = newResolved.active;\n }\n if (prevResolved.disabled !== newResolved.disabled) {\n changes.disabled = newResolved.disabled;\n }\n if (prevResolved.visible !== newResolved.visible) {\n changes.visible = newResolved.visible;\n }\n if (prevResolved.label !== newResolved.label) {\n changes.label = newResolved.label;\n }\n if (!arePropsEqual(prevResolved.iconProps, newResolved.iconProps)) {\n changes.iconProps = newResolved.iconProps;\n }\n\n if (Object.keys(changes).length > 0) {\n changedCommandIds.push(commandId);\n previousCache.set(commandId, newResolved);\n\n this.commandStateChanged$.emit({\n commandId,\n documentId,\n changes,\n });\n }\n });\n\n this.previousStates.set(documentId, previousCache);\n }\n}\n","import { Action } from '@embedpdf/core';\n\nexport const REGISTER_COMMAND = 'COMMANDS/REGISTER';\nexport const UNREGISTER_COMMAND = 'COMMANDS/UNREGISTER';\nexport const MARK_COMMANDS_CHANGED = 'COMMANDS/MARK_CHANGED';\nexport const CLEAR_CHANGED_COMMANDS = 'COMMANDS/CLEAR_CHANGED';\n\nexport interface RegisterCommandAction extends Action {\n type: typeof REGISTER_COMMAND;\n payload: string; // commandId\n}\n\nexport interface UnregisterCommandAction extends Action {\n type: typeof UNREGISTER_COMMAND;\n payload: string; // commandId\n}\n\nexport interface MarkCommandsChangedAction extends Action {\n type: typeof MARK_COMMANDS_CHANGED;\n payload: string[]; // commandIds\n}\n\nexport interface ClearChangedCommandsAction extends Action {\n type: typeof CLEAR_CHANGED_COMMANDS;\n}\n\nexport type CommandsAction =\n | RegisterCommandAction\n | UnregisterCommandAction\n | MarkCommandsChangedAction\n | ClearChangedCommandsAction;\n\nexport const registerCommand = (commandId: string): RegisterCommandAction => ({\n type: REGISTER_COMMAND,\n payload: commandId,\n});\n\nexport const unregisterCommand = (commandId: string): UnregisterCommandAction => ({\n type: UNREGISTER_COMMAND,\n payload: commandId,\n});\n\nexport const markCommandsChanged = (commandIds: string[]): MarkCommandsChangedAction => ({\n type: MARK_COMMANDS_CHANGED,\n payload: commandIds,\n});\n\nexport const clearChangedCommands = (): ClearChangedCommandsAction => ({\n type: CLEAR_CHANGED_COMMANDS,\n});\n","import { Reducer } from '@embedpdf/core';\nimport { CommandsState } from './types';\nimport { CommandsAction, MARK_COMMANDS_CHANGED, CLEAR_CHANGED_COMMANDS } from './actions';\n\nexport const initialState: CommandsState = {\n changedCommands: new Set(),\n};\n\nexport const commandsReducer: Reducer<CommandsState, CommandsAction> = (\n state = initialState,\n action,\n) => {\n switch (action.type) {\n case MARK_COMMANDS_CHANGED: {\n const newSet = new Set(state.changedCommands);\n action.payload.forEach((id) => newSet.add(id));\n return {\n ...state,\n changedCommands: newSet,\n };\n }\n\n case CLEAR_CHANGED_COMMANDS: {\n return {\n ...state,\n changedCommands: new Set(),\n };\n }\n\n default:\n return state;\n }\n};\n","import { PluginPackage } from '@embedpdf/core';\nimport { manifest, COMMANDS_PLUGIN_ID } from './manifest';\nimport { CommandsPluginConfig, CommandsState } from './types';\nimport { CommandsPlugin } from './commands-plugin';\nimport { CommandsAction } from './actions';\nimport { commandsReducer, initialState } from './reducer';\n\nexport const CommandsPluginPackage: PluginPackage<\n CommandsPlugin,\n CommandsPluginConfig,\n CommandsState,\n CommandsAction\n> = {\n manifest,\n create: (registry, config) => new CommandsPlugin(COMMANDS_PLUGIN_ID, registry, config),\n reducer: commandsReducer,\n initialState,\n};\n\nexport * from './commands-plugin';\nexport * from './types';\nexport * from './manifest';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/lib/manifest.ts","../src/lib/actions.ts","../src/lib/commands-plugin.ts","../src/lib/reducer.ts","../src/lib/index.ts"],"sourcesContent":["import { PluginManifest } from '@embedpdf/core';\nimport { CommandsPluginConfig } from './types';\n\nexport const COMMANDS_PLUGIN_ID = 'commands';\n\nexport const manifest: PluginManifest<CommandsPluginConfig> = {\n id: COMMANDS_PLUGIN_ID,\n name: 'Commands Plugin',\n version: '1.0.0',\n provides: ['commands'],\n requires: [],\n optional: ['i18n'],\n defaultConfig: {\n commands: {},\n },\n};\n","import { Action } from '@embedpdf/core';\n\nexport const SET_DISABLED_CATEGORIES = 'COMMANDS/SET_DISABLED_CATEGORIES';\n\nexport interface SetDisabledCategoriesAction extends Action {\n type: typeof SET_DISABLED_CATEGORIES;\n payload: string[];\n}\n\nexport type CommandsAction = SetDisabledCategoriesAction;\n\nexport const setDisabledCategories = (categories: string[]): SetDisabledCategoriesAction => ({\n type: SET_DISABLED_CATEGORIES,\n payload: categories,\n});\n","import {\n BasePlugin,\n PluginRegistry,\n StoreState,\n createEmitter,\n createBehaviorEmitter,\n Listener,\n arePropsEqual,\n} from '@embedpdf/core';\nimport { I18nCapability, I18nPlugin } from '@embedpdf/plugin-i18n';\nimport {\n CommandsCapability,\n CommandsPluginConfig,\n CommandsState,\n Command,\n ResolvedCommand,\n CommandExecutedEvent,\n CommandStateChangedEvent,\n ShortcutExecutedEvent,\n CategoryChangedEvent,\n CommandScope,\n Dynamic,\n} from './types';\nimport { CommandsAction, setDisabledCategories } from './actions';\n\nexport class CommandsPlugin extends BasePlugin<\n CommandsPluginConfig,\n CommandsCapability,\n CommandsState,\n CommandsAction\n> {\n static readonly id = 'commands' as const;\n\n private commands = new Map<string, Command>();\n private i18n: I18nCapability | null = null;\n private shortcutMap = new Map<string, string>(); // shortcut -> commandId\n\n private readonly commandExecuted$ = createEmitter<CommandExecutedEvent>();\n private readonly commandStateChanged$ = createEmitter<CommandStateChangedEvent>();\n private readonly shortcutExecuted$ = createEmitter<ShortcutExecutedEvent>();\n private readonly categoryChanged$ = createBehaviorEmitter<CategoryChangedEvent>();\n\n // Cache previous resolved states per document to detect changes\n private previousStates = new Map<string, Map<string, ResolvedCommand>>();\n\n constructor(id: string, registry: PluginRegistry, config: CommandsPluginConfig) {\n super(id, registry);\n\n // Check if i18n plugin is available (optional dependency)\n const i18nPlugin = registry.getPlugin<I18nPlugin>('i18n');\n this.i18n = i18nPlugin?.provides() ?? null;\n\n // Initialize disabled categories from config\n if (config.disabledCategories?.length) {\n this.dispatch(setDisabledCategories(config.disabledCategories));\n }\n\n // Register all commands from config\n Object.values(config.commands).forEach((command) => {\n this.registerCommand(command);\n });\n\n // Subscribe to global store changes\n this.registry.getStore().subscribe((_action, newState) => {\n this.onGlobalStoreChange(newState);\n });\n }\n\n protected override onDocumentClosed(documentId: string): void {\n // Cleanup previous states cache\n this.previousStates.delete(documentId);\n\n this.logger.debug(\n 'CommandsPlugin',\n 'DocumentClosed',\n `Cleaned up command state cache for document: ${documentId}`,\n );\n }\n\n async initialize(): Promise<void> {\n this.logger.info('CommandsPlugin', 'Initialize', 'Commands plugin initialized');\n }\n\n async destroy(): Promise<void> {\n this.commandExecuted$.clear();\n this.commandStateChanged$.clear();\n this.shortcutExecuted$.clear();\n this.categoryChanged$.clear();\n this.commands.clear();\n this.shortcutMap.clear();\n this.previousStates.clear();\n super.destroy();\n }\n\n // ─────────────────────────────────────────────────────────\n // Category Management\n // ─────────────────────────────────────────────────────────\n\n private disableCategoryImpl(category: string): void {\n const current = new Set(this.state.disabledCategories);\n if (!current.has(category)) {\n current.add(category);\n this.dispatch(setDisabledCategories(Array.from(current)));\n this.categoryChanged$.emit({ disabledCategories: Array.from(current) });\n }\n }\n\n private enableCategoryImpl(category: string): void {\n const current = new Set(this.state.disabledCategories);\n if (current.has(category)) {\n current.delete(category);\n this.dispatch(setDisabledCategories(Array.from(current)));\n this.categoryChanged$.emit({ disabledCategories: Array.from(current) });\n }\n }\n\n private toggleCategoryImpl(category: string): void {\n if (this.state.disabledCategories.includes(category)) {\n this.enableCategoryImpl(category);\n } else {\n this.disableCategoryImpl(category);\n }\n }\n\n private setDisabledCategoriesImpl(categories: string[]): void {\n this.dispatch(setDisabledCategories(categories));\n this.categoryChanged$.emit({ disabledCategories: categories });\n }\n\n /**\n * Check if command has any disabled category\n */\n private isCommandCategoryDisabled(command: Command): boolean {\n if (!command.categories?.length) return false;\n return command.categories.some((cat) => this.state.disabledCategories.includes(cat));\n }\n\n // ─────────────────────────────────────────────────────────\n // Capability\n // ─────────────────────────────────────────────────────────\n\n protected buildCapability(): CommandsCapability {\n return {\n resolve: (commandId, documentId) => this.resolve(commandId, documentId),\n execute: (commandId, documentId, source = 'ui') =>\n this.execute(commandId, documentId, source),\n getAllCommands: (documentId) => this.getAllCommands(documentId),\n getCommandsByCategory: (category, documentId) =>\n this.getCommandsByCategory(category, documentId),\n getCommandByShortcut: (shortcut) => this.getCommandByShortcut(shortcut),\n getAllShortcuts: () => new Map(this.shortcutMap),\n forDocument: (documentId) => this.createCommandScope(documentId),\n registerCommand: (command) => this.registerCommand(command),\n unregisterCommand: (commandId) => this.unregisterCommand(commandId),\n\n // Category management\n disableCategory: (category) => this.disableCategoryImpl(category),\n enableCategory: (category) => this.enableCategoryImpl(category),\n toggleCategory: (category) => this.toggleCategoryImpl(category),\n setDisabledCategories: (categories) => this.setDisabledCategoriesImpl(categories),\n getDisabledCategories: () => this.state.disabledCategories,\n isCategoryDisabled: (category) => this.state.disabledCategories.includes(category),\n\n // Events\n onCommandExecuted: this.commandExecuted$.on,\n onCommandStateChanged: this.commandStateChanged$.on,\n onShortcutExecuted: this.shortcutExecuted$.on,\n onCategoryChanged: this.categoryChanged$.on,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Scoping\n // ─────────────────────────────────────────────────────────\n\n private createCommandScope(documentId: string): CommandScope {\n return {\n resolve: (commandId) => this.resolve(commandId, documentId),\n execute: (commandId, source = 'ui') => this.execute(commandId, documentId, source),\n getAllCommands: () => this.getAllCommands(documentId),\n getCommandsByCategory: (category) => this.getCommandsByCategory(category, documentId),\n onCommandStateChanged: (listener: Listener<Omit<CommandStateChangedEvent, 'documentId'>>) =>\n this.commandStateChanged$.on((event) => {\n if (event.documentId === documentId) {\n const { documentId: _, ...rest } = event;\n listener(rest);\n }\n }),\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Command Resolution\n // ─────────────────────────────────────────────────────────\n\n private resolve(commandId: string, documentId?: string): ResolvedCommand {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n\n const command = this.commands.get(commandId);\n if (!command) {\n throw new Error(`Command not found: ${commandId}`);\n }\n\n const state = this.registry.getStore().getState();\n\n // Resolve label with i18n if available\n const label = this.resolveLabel(command, state, resolvedDocId);\n\n // Resolve shortcuts\n const shortcuts = command.shortcuts\n ? Array.isArray(command.shortcuts)\n ? command.shortcuts\n : [command.shortcuts]\n : undefined;\n\n // Check if disabled via categories OR explicit disabled predicate\n const explicitDisabled = this.resolveDynamic(command.disabled, state, resolvedDocId) ?? false;\n const categoryDisabled = this.isCommandCategoryDisabled(command);\n const isDisabled = explicitDisabled || categoryDisabled;\n\n return {\n id: command.id,\n label,\n icon: this.resolveDynamic(command.icon, state, resolvedDocId),\n iconProps: this.resolveDynamic(command.iconProps, state, resolvedDocId),\n active: this.resolveDynamic(command.active, state, resolvedDocId) ?? false,\n disabled: isDisabled,\n visible: this.resolveDynamic(command.visible, state, resolvedDocId) ?? true,\n shortcuts,\n shortcutLabel: command.shortcutLabel,\n categories: command.categories,\n description: command.description,\n execute: () => command.action({ registry: this.registry, state, documentId: resolvedDocId }),\n };\n }\n\n private resolveLabel(command: Command, state: StoreState<any>, documentId: string): string {\n // Priority: labelKey (with i18n) > label (plain string) > id (fallback)\n if (command.labelKey && this.i18n) {\n const params = this.resolveDynamic(command.labelParams, state, documentId);\n return this.i18n.t(command.labelKey, { params, documentId });\n }\n\n if (command.label) {\n return command.label;\n }\n\n return command.id; // Fallback to ID\n }\n\n private resolveDynamic<T>(\n value: Dynamic<any, T> | undefined,\n state: StoreState<any>,\n documentId: string,\n ): T | undefined {\n if (value === undefined) return undefined;\n\n // Check if it's a function (the dynamic evaluator)\n if (typeof value === 'function') {\n return (value as (context: { state: StoreState<any>; documentId: string }) => T)({\n state,\n documentId,\n });\n }\n\n // Otherwise it's the static value\n return value as T;\n }\n\n // ─────────────────────────────────────────────────────────\n // Command Execution\n // ─────────────────────────────────────────────────────────\n\n private execute(\n commandId: string,\n documentId?: string,\n source: 'keyboard' | 'ui' | 'api' = 'ui',\n ): void {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n const resolved = this.resolve(commandId, resolvedDocId);\n\n if (resolved.disabled) {\n this.logger.warn(\n 'CommandsPlugin',\n 'ExecutionBlocked',\n `Command '${commandId}' is disabled for document '${resolvedDocId}'`,\n );\n return;\n }\n\n if (!resolved.visible) {\n this.logger.warn(\n 'CommandsPlugin',\n 'ExecutionBlocked',\n `Command '${commandId}' is not visible for document '${resolvedDocId}'`,\n );\n return;\n }\n\n resolved.execute();\n\n this.commandExecuted$.emit({\n commandId,\n documentId: resolvedDocId,\n source,\n });\n\n this.logger.debug(\n 'CommandsPlugin',\n 'CommandExecuted',\n `Command '${commandId}' executed for document '${resolvedDocId}' (source: ${source})`,\n );\n }\n\n // ─────────────────────────────────────────────────────────\n // Command Registration\n // ─────────────────────────────────────────────────────────\n\n private registerCommand(command: Command): void {\n if (this.commands.has(command.id)) {\n this.logger.warn(\n 'CommandsPlugin',\n 'CommandOverwrite',\n `Command '${command.id}' already exists and will be overwritten`,\n );\n }\n\n this.commands.set(command.id, command);\n\n // Register shortcuts\n if (command.shortcuts) {\n const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];\n\n shortcuts.forEach((shortcut) => {\n const normalized = this.normalizeShortcut(shortcut);\n this.shortcutMap.set(normalized, command.id);\n });\n }\n\n this.logger.debug('CommandsPlugin', 'CommandRegistered', `Command '${command.id}' registered`);\n }\n\n private unregisterCommand(commandId: string): void {\n const command = this.commands.get(commandId);\n if (!command) return;\n\n // Remove shortcuts\n if (command.shortcuts) {\n const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];\n\n shortcuts.forEach((shortcut) => {\n const normalized = this.normalizeShortcut(shortcut);\n this.shortcutMap.delete(normalized);\n });\n }\n\n this.commands.delete(commandId);\n this.logger.debug(\n 'CommandsPlugin',\n 'CommandUnregistered',\n `Command '${commandId}' unregistered`,\n );\n }\n\n // ─────────────────────────────────────────────────────────\n // Shortcuts\n // ─────────────────────────────────────────────────────────\n\n private getCommandByShortcut(shortcut: string): Command | null {\n const normalized = this.normalizeShortcut(shortcut);\n const commandId = this.shortcutMap.get(normalized);\n return commandId ? (this.commands.get(commandId) ?? null) : null;\n }\n\n private normalizeShortcut(shortcut: string): string {\n // Normalize: \"Ctrl+Shift+A\" -> \"ctrl+shift+a\"\n return shortcut.toLowerCase().split('+').sort().join('+');\n }\n\n // ─────────────────────────────────────────────────────────\n // Query Methods\n // ─────────────────────────────────────────────────────────\n\n private getAllCommands(documentId?: string): ResolvedCommand[] {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n return Array.from(this.commands.keys()).map((id) => this.resolve(id, resolvedDocId));\n }\n\n private getCommandsByCategory(category: string, documentId?: string): ResolvedCommand[] {\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\n return Array.from(this.commands.values())\n .filter((cmd) => cmd.categories?.includes(category))\n .map((cmd) => this.resolve(cmd.id, resolvedDocId));\n }\n\n // ─────────────────────────────────────────────────────────\n // State Change Detection\n // ─────────────────────────────────────────────────────────\n\n private onGlobalStoreChange(newState: StoreState<any>): void {\n // Get all documents from core state\n const documentIds = Object.keys(newState.core.documents);\n\n // Check each document for command state changes\n documentIds.forEach((documentId) => {\n this.detectCommandChanges(documentId, newState);\n });\n }\n\n private detectCommandChanges(documentId: string, newState: StoreState<any>): void {\n const previousCache = this.previousStates.get(documentId) ?? new Map();\n const changedCommandIds: string[] = [];\n\n this.commands.forEach((command, commandId) => {\n const newResolved = this.resolve(commandId, documentId);\n const prevResolved = previousCache.get(commandId);\n\n if (!prevResolved) {\n // First time resolving for this document\n previousCache.set(commandId, newResolved);\n return;\n }\n\n // Check for changes\n const changes: CommandStateChangedEvent['changes'] = {};\n\n if (prevResolved.active !== newResolved.active) {\n changes.active = newResolved.active;\n }\n if (prevResolved.disabled !== newResolved.disabled) {\n changes.disabled = newResolved.disabled;\n }\n if (prevResolved.visible !== newResolved.visible) {\n changes.visible = newResolved.visible;\n }\n if (prevResolved.label !== newResolved.label) {\n changes.label = newResolved.label;\n }\n if (!arePropsEqual(prevResolved.iconProps, newResolved.iconProps)) {\n changes.iconProps = newResolved.iconProps;\n }\n\n if (Object.keys(changes).length > 0) {\n changedCommandIds.push(commandId);\n previousCache.set(commandId, newResolved);\n\n this.commandStateChanged$.emit({\n commandId,\n documentId,\n changes,\n });\n }\n });\n\n this.previousStates.set(documentId, previousCache);\n }\n}\n","import { Reducer } from '@embedpdf/core';\nimport { CommandsState } from './types';\nimport { CommandsAction, SET_DISABLED_CATEGORIES } from './actions';\n\nexport const initialState: CommandsState = {\n disabledCategories: [],\n};\n\nexport const commandsReducer: Reducer<CommandsState, CommandsAction> = (\n state = initialState,\n action,\n) => {\n switch (action.type) {\n case SET_DISABLED_CATEGORIES:\n return {\n ...state,\n disabledCategories: action.payload,\n };\n\n default:\n return state;\n }\n};\n","import { PluginPackage } from '@embedpdf/core';\nimport { manifest, COMMANDS_PLUGIN_ID } from './manifest';\nimport { CommandsPluginConfig, CommandsState } from './types';\nimport { CommandsPlugin } from './commands-plugin';\nimport { CommandsAction } from './actions';\nimport { commandsReducer, initialState } from './reducer';\n\nexport const CommandsPluginPackage: PluginPackage<\n CommandsPlugin,\n CommandsPluginConfig,\n CommandsState,\n CommandsAction\n> = {\n manifest,\n create: (registry, config) => new CommandsPlugin(COMMANDS_PLUGIN_ID, registry, config),\n reducer: commandsReducer,\n initialState,\n};\n\nexport * from './commands-plugin';\nexport * from './types';\nexport * from './manifest';\n"],"names":[],"mappings":"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"}
@@ -1,25 +1,8 @@
1
1
  import { Action } from '@embedpdf/core';
2
- export declare const REGISTER_COMMAND = "COMMANDS/REGISTER";
3
- export declare const UNREGISTER_COMMAND = "COMMANDS/UNREGISTER";
4
- export declare const MARK_COMMANDS_CHANGED = "COMMANDS/MARK_CHANGED";
5
- export declare const CLEAR_CHANGED_COMMANDS = "COMMANDS/CLEAR_CHANGED";
6
- export interface RegisterCommandAction extends Action {
7
- type: typeof REGISTER_COMMAND;
8
- payload: string;
9
- }
10
- export interface UnregisterCommandAction extends Action {
11
- type: typeof UNREGISTER_COMMAND;
12
- payload: string;
13
- }
14
- export interface MarkCommandsChangedAction extends Action {
15
- type: typeof MARK_COMMANDS_CHANGED;
2
+ export declare const SET_DISABLED_CATEGORIES = "COMMANDS/SET_DISABLED_CATEGORIES";
3
+ export interface SetDisabledCategoriesAction extends Action {
4
+ type: typeof SET_DISABLED_CATEGORIES;
16
5
  payload: string[];
17
6
  }
18
- export interface ClearChangedCommandsAction extends Action {
19
- type: typeof CLEAR_CHANGED_COMMANDS;
20
- }
21
- export type CommandsAction = RegisterCommandAction | UnregisterCommandAction | MarkCommandsChangedAction | ClearChangedCommandsAction;
22
- export declare const registerCommand: (commandId: string) => RegisterCommandAction;
23
- export declare const unregisterCommand: (commandId: string) => UnregisterCommandAction;
24
- export declare const markCommandsChanged: (commandIds: string[]) => MarkCommandsChangedAction;
25
- export declare const clearChangedCommands: () => ClearChangedCommandsAction;
7
+ export type CommandsAction = SetDisabledCategoriesAction;
8
+ export declare const setDisabledCategories: (categories: string[]) => SetDisabledCategoriesAction;
@@ -9,11 +9,20 @@ export declare class CommandsPlugin extends BasePlugin<CommandsPluginConfig, Com
9
9
  private readonly commandExecuted$;
10
10
  private readonly commandStateChanged$;
11
11
  private readonly shortcutExecuted$;
12
+ private readonly categoryChanged$;
12
13
  private previousStates;
13
14
  constructor(id: string, registry: PluginRegistry, config: CommandsPluginConfig);
14
15
  protected onDocumentClosed(documentId: string): void;
15
16
  initialize(): Promise<void>;
16
17
  destroy(): Promise<void>;
18
+ private disableCategoryImpl;
19
+ private enableCategoryImpl;
20
+ private toggleCategoryImpl;
21
+ private setDisabledCategoriesImpl;
22
+ /**
23
+ * Check if command has any disabled category
24
+ */
25
+ private isCommandCategoryDisabled;
17
26
  protected buildCapability(): CommandsCapability;
18
27
  private createCommandScope;
19
28
  private resolve;
@@ -27,7 +27,7 @@ export interface Command<TStore = any> {
27
27
  visible?: Dynamic<TStore, boolean>;
28
28
  shortcuts?: string | string[];
29
29
  shortcutLabel?: string;
30
- category?: string;
30
+ categories?: string[];
31
31
  description?: string;
32
32
  }
33
33
  export interface ResolvedCommand {
@@ -40,7 +40,7 @@ export interface ResolvedCommand {
40
40
  visible: boolean;
41
41
  shortcuts?: string[];
42
42
  shortcutLabel?: string;
43
- category?: string;
43
+ categories?: string[];
44
44
  description?: string;
45
45
  execute: () => void;
46
46
  }
@@ -50,9 +50,12 @@ export interface GlobalStoreState<TPlugins extends Record<string, any> = {}> {
50
50
  }
51
51
  export interface CommandsPluginConfig extends BasePluginConfig {
52
52
  commands: Record<string, Command>;
53
+ /** Categories to disable at initialization */
54
+ disabledCategories?: string[];
53
55
  }
54
56
  export interface CommandsState {
55
- changedCommands: Set<string>;
57
+ /** Globally disabled command categories */
58
+ disabledCategories: string[];
56
59
  }
57
60
  export interface CommandExecutedEvent {
58
61
  commandId: string;
@@ -75,6 +78,9 @@ export interface ShortcutExecutedEvent {
75
78
  commandId: string;
76
79
  documentId: string;
77
80
  }
81
+ export interface CategoryChangedEvent {
82
+ disabledCategories: string[];
83
+ }
78
84
  export interface CommandScope {
79
85
  resolve(commandId: string): ResolvedCommand;
80
86
  execute(commandId: string, source?: 'keyboard' | 'ui' | 'api'): void;
@@ -92,7 +98,14 @@ export interface CommandsCapability {
92
98
  forDocument(documentId: string): CommandScope;
93
99
  registerCommand(command: Command): void;
94
100
  unregisterCommand(commandId: string): void;
101
+ disableCategory(category: string): void;
102
+ enableCategory(category: string): void;
103
+ toggleCategory(category: string): void;
104
+ setDisabledCategories(categories: string[]): void;
105
+ getDisabledCategories(): string[];
106
+ isCategoryDisabled(category: string): boolean;
95
107
  onCommandExecuted: EventHook<CommandExecutedEvent>;
96
108
  onCommandStateChanged: EventHook<CommandStateChangedEvent>;
97
109
  onShortcutExecuted: EventHook<ShortcutExecutedEvent>;
110
+ onCategoryChanged: EventHook<CategoryChangedEvent>;
98
111
  }
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-commands");require("preact");const r=require("preact/hooks"),o=require("@embedpdf/core/preact"),n=()=>o.useCapability(t.CommandsPlugin.id);function s(){const{provides:e}=n();return r.useEffect(()=>{if(!e)return;const t=function(e){return t=>{const r=t.target;if("INPUT"===r.tagName||"TEXTAREA"===r.tagName||r.isContentEditable)return;const o=function(e){const t=[];e.ctrlKey&&t.push("ctrl"),e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.metaKey&&t.push("meta");const r=e.key.toLowerCase();return["control","shift","alt","meta"].includes(r)?null:[...t,r].sort().join("+")}(t);if(!o)return;const n=e.getCommandByShortcut(o);if(!n)return;const s=e.resolve(n.id);!s.disabled&&s.visible&&(t.preventDefault(),t.stopPropagation(),e.execute(n.id,void 0,"keyboard"))}}(e);return document.addEventListener("keydown",t),()=>document.removeEventListener("keydown",t)},[e]),null}const u=e.createPluginPackage(t.CommandsPluginPackage).addUtility(s).build();exports.CommandsPluginPackage=u,exports.KeyboardShortcuts=s,exports.useCommand=(e,t)=>{const{provides:o}=n(),[s,u]=r.useState(()=>o?o.resolve(e,t):null);return r.useEffect(()=>{if(!o)return void u(null);u(o.resolve(e,t));return o.onCommandStateChanged(r=>{r.commandId===e&&r.documentId===t&&u(o.resolve(e,t))})},[o,e,t]),s},exports.useCommandExecutor=e=>{const{provides:t}=n();return r=>{t&&t.execute(r,e,"ui")}},exports.useCommandsCapability=n,exports.useCommandsPlugin=()=>o.usePlugin(t.CommandsPlugin.id),Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-commands");require("preact");const o=require("preact/hooks"),r=require("@embedpdf/core/preact"),n=()=>r.useCapability(t.CommandsPlugin.id);function s(){const{provides:e}=n();return o.useEffect(()=>{if(!e)return;const t=function(e){return t=>{const o=t.composedPath()[0]||t.target;if("INPUT"===o.tagName||"TEXTAREA"===o.tagName||o.isContentEditable)return;const r=function(e){const t=[];e.ctrlKey&&t.push("ctrl"),e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.metaKey&&t.push("meta");const o=e.key.toLowerCase();return["control","shift","alt","meta"].includes(o)?null:[...t,o].sort().join("+")}(t);if(!r)return;const n=e.getCommandByShortcut(r);if(!n)return;const s=e.resolve(n.id);!s.disabled&&s.visible&&(t.preventDefault(),t.stopPropagation(),e.execute(n.id,void 0,"keyboard"))}}(e);return document.addEventListener("keydown",t),()=>document.removeEventListener("keydown",t)},[e]),null}const u=e.createPluginPackage(t.CommandsPluginPackage).addUtility(s).build();exports.CommandsPluginPackage=u,exports.KeyboardShortcuts=s,exports.useCommand=(e,t)=>{const{provides:r}=n(),[s,u]=o.useState(()=>r?r.resolve(e,t):null);return o.useEffect(()=>{if(!r)return void u(null);u(r.resolve(e,t));return r.onCommandStateChanged(o=>{o.commandId===e&&o.documentId===t&&u(r.resolve(e,t))})},[r,e,t]),s},exports.useCommandExecutor=e=>{const{provides:t}=n();return o=>{t&&t.execute(o,e,"ui")}},exports.useCommandsCapability=n,exports.useCommandsPlugin=()=>r.usePlugin(t.CommandsPlugin.id),Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/utils/keyboard-handler.ts","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\nimport { useState, useEffect } from '@framework';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * Automatically updates when command state changes\n * @param commandId Command ID\n * @param documentId Document ID\n * @returns ResolvedCommand or null if not available\n */\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\n const { provides } = useCommandsCapability();\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\n provides ? provides.resolve(commandId, documentId) : null,\n );\n\n useEffect(() => {\n if (!provides) {\n setCommand(null);\n return;\n }\n\n // Initial resolve\n setCommand(provides.resolve(commandId, documentId));\n\n // Subscribe to state changes for this command + document\n const unsubscribe = provides.onCommandStateChanged((event) => {\n if (event.commandId === commandId && event.documentId === documentId) {\n setCommand(provides.resolve(commandId, documentId));\n }\n });\n\n return unsubscribe;\n }, [provides, commandId, documentId]);\n\n return command;\n};\n\n/**\n * Hook to execute a command\n */\nexport const useCommandExecutor = (documentId: string) => {\n const { provides } = useCommandsCapability();\n\n return (commandId: string) => {\n if (provides) {\n provides.execute(commandId, documentId, 'ui');\n }\n };\n};\n","import { useEffect } from '@framework';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../utils';\n\n/**\n * Utility component that listens to keyboard events\n * and executes commands based on shortcuts.\n * This component doesn't render anything, it just sets up keyboard shortcuts.\n */\nexport function KeyboardShortcuts() {\n const { provides: commands } = useCommandsCapability();\n\n useEffect(() => {\n if (!commands) return;\n\n const handleKeyDown = createKeyDownHandler(commands);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [commands]);\n\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\n return null;\n}\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n const target = event.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["useCommandsCapability","useCapability","CommandsPlugin","id","KeyboardShortcuts","provides","commands","useEffect","handleKeyDown","event","target","tagName","isContentEditable","shortcut","modifiers","ctrlKey","push","shiftKey","altKey","metaKey","key","toLowerCase","includes","sort","join","buildShortcutString","command","getCommandByShortcut","resolved","resolve","disabled","visible","preventDefault","stopPropagation","execute","createKeyDownHandler","document","addEventListener","removeEventListener","CommandsPluginPackage","createPluginPackage","BaseCommandsPackage","addUtility","build","commandId","documentId","setCommand","useState","onCommandStateChanged","usePlugin"],"mappings":"8OAIaA,EAAwB,IAAMC,gBAA8BC,EAAAA,eAAeC,ICKjF,SAASC,IACd,MAAQC,SAAUC,GAAaN,IAY/B,OAVAO,EAAAA,UAAU,KACR,IAAKD,EAAU,OAEf,MAAME,ECcH,SAA8BF,GACnC,OAAQG,IAEN,MAAMC,EAASD,EAAMC,OACrB,GAAuB,UAAnBA,EAAOC,SAA0C,aAAnBD,EAAOC,SAA0BD,EAAOE,kBACxE,OAGF,MAAMC,EA/BH,SAA6BJ,GAClC,MAAMK,EAAsB,GAExBL,EAAMM,SAASD,EAAUE,KAAK,QAC9BP,EAAMQ,UAAUH,EAAUE,KAAK,SAC/BP,EAAMS,QAAQJ,EAAUE,KAAK,OAC7BP,EAAMU,SAASL,EAAUE,KAAK,QAGlC,MAAMI,EAAMX,EAAMW,IAAIC,cAGtB,MAFmB,CAAC,UAAW,QAAS,MAAO,QAAQC,SAASF,GAGvD,KAGK,IAAIN,EAAWM,GAChBG,OAAOC,KAAK,IAC3B,CAaqBC,CAAoBhB,GACrC,IAAKI,EAAU,OAEf,MAAMa,EAAUpB,EAASqB,qBAAqBd,GAC9C,IAAKa,EAAS,OAGd,MAAME,EAAWtB,EAASuB,QAAQH,EAAQvB,KAEtCyB,EAASE,UAAaF,EAASG,UAKnCtB,EAAMuB,iBACNvB,EAAMwB,kBACN3B,EAAS4B,QAAQR,EAAQvB,QAAI,EAAW,aAE5C,CDxC0BgC,CAAqB7B,GAG3C,OADA8B,SAASC,iBAAiB,UAAW7B,GAC9B,IAAM4B,SAASE,oBAAoB,UAAW9B,IACpD,CAACF,IAGG,IACT,CEdO,MAAMiC,EAAwBC,EAAAA,oBAAoBC,EAAAA,uBACtDC,WAAWtC,GACXuC,uFHGuB,CAACC,EAAmBC,KAC5C,MAAMxC,SAAEA,GAAaL,KACd0B,EAASoB,GAAcC,EAAAA,SAAiC,IAC7D1C,EAAWA,EAASwB,QAAQe,EAAWC,GAAc,MAsBvD,OAnBAtC,EAAAA,UAAU,KACR,IAAKF,EAEH,YADAyC,EAAW,MAKbA,EAAWzC,EAASwB,QAAQe,EAAWC,IASvC,OANoBxC,EAAS2C,sBAAuBvC,IAC9CA,EAAMmC,YAAcA,GAAanC,EAAMoC,aAAeA,GACxDC,EAAWzC,EAASwB,QAAQe,EAAWC,OAK1C,CAACxC,EAAUuC,EAAWC,IAElBnB,8BAM0BmB,IACjC,MAAMxC,SAAEA,GAAaL,IAErB,OAAQ4C,IACFvC,GACFA,EAAS6B,QAAQU,EAAWC,EAAY,kEA7Cb,IAAMI,YAA0B/C,EAAAA,eAAeC"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/utils/keyboard-handler.ts","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\nimport { useState, useEffect } from '@framework';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * Automatically updates when command state changes\n * @param commandId Command ID\n * @param documentId Document ID\n * @returns ResolvedCommand or null if not available\n */\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\n const { provides } = useCommandsCapability();\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\n provides ? provides.resolve(commandId, documentId) : null,\n );\n\n useEffect(() => {\n if (!provides) {\n setCommand(null);\n return;\n }\n\n // Initial resolve\n setCommand(provides.resolve(commandId, documentId));\n\n // Subscribe to state changes for this command + document\n const unsubscribe = provides.onCommandStateChanged((event) => {\n if (event.commandId === commandId && event.documentId === documentId) {\n setCommand(provides.resolve(commandId, documentId));\n }\n });\n\n return unsubscribe;\n }, [provides, commandId, documentId]);\n\n return command;\n};\n\n/**\n * Hook to execute a command\n */\nexport const useCommandExecutor = (documentId: string) => {\n const { provides } = useCommandsCapability();\n\n return (commandId: string) => {\n if (provides) {\n provides.execute(commandId, documentId, 'ui');\n }\n };\n};\n","import { useEffect } from '@framework';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../utils';\n\n/**\n * Utility component that listens to keyboard events\n * and executes commands based on shortcuts.\n * This component doesn't render anything, it just sets up keyboard shortcuts.\n */\nexport function KeyboardShortcuts() {\n const { provides: commands } = useCommandsCapability();\n\n useEffect(() => {\n if (!commands) return;\n\n const handleKeyDown = createKeyDownHandler(commands);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [commands]);\n\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\n return null;\n}\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Use composedPath to get the actual target element, even inside Shadow DOM\n const composedPath = event.composedPath();\n const target = (composedPath[0] || event.target) as HTMLElement;\n\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["useCommandsCapability","useCapability","CommandsPlugin","id","KeyboardShortcuts","provides","commands","useEffect","handleKeyDown","event","target","composedPath","tagName","isContentEditable","shortcut","modifiers","ctrlKey","push","shiftKey","altKey","metaKey","key","toLowerCase","includes","sort","join","buildShortcutString","command","getCommandByShortcut","resolved","resolve","disabled","visible","preventDefault","stopPropagation","execute","createKeyDownHandler","document","addEventListener","removeEventListener","CommandsPluginPackage","createPluginPackage","BaseCommandsPackage","addUtility","build","commandId","documentId","setCommand","useState","onCommandStateChanged","usePlugin"],"mappings":"8OAIaA,EAAwB,IAAMC,gBAA8BC,EAAAA,eAAeC,ICKjF,SAASC,IACd,MAAQC,SAAUC,GAAaN,IAY/B,OAVAO,EAAAA,UAAU,KACR,IAAKD,EAAU,OAEf,MAAME,ECcH,SAA8BF,GACnC,OAAQG,IAEN,MACMC,EADeD,EAAME,eACE,IAAMF,EAAMC,OAGzC,GAAuB,UAAnBA,EAAOE,SAA0C,aAAnBF,EAAOE,SAA0BF,EAAOG,kBACxE,OAGF,MAAMC,EAlCH,SAA6BL,GAClC,MAAMM,EAAsB,GAExBN,EAAMO,SAASD,EAAUE,KAAK,QAC9BR,EAAMS,UAAUH,EAAUE,KAAK,SAC/BR,EAAMU,QAAQJ,EAAUE,KAAK,OAC7BR,EAAMW,SAASL,EAAUE,KAAK,QAGlC,MAAMI,EAAMZ,EAAMY,IAAIC,cAGtB,MAFmB,CAAC,UAAW,QAAS,MAAO,QAAQC,SAASF,GAGvD,KAGK,IAAIN,EAAWM,GAChBG,OAAOC,KAAK,IAC3B,CAgBqBC,CAAoBjB,GACrC,IAAKK,EAAU,OAEf,MAAMa,EAAUrB,EAASsB,qBAAqBd,GAC9C,IAAKa,EAAS,OAGd,MAAME,EAAWvB,EAASwB,QAAQH,EAAQxB,KAEtC0B,EAASE,UAAaF,EAASG,UAKnCvB,EAAMwB,iBACNxB,EAAMyB,kBACN5B,EAAS6B,QAAQR,EAAQxB,QAAI,EAAW,aAE5C,CD3C0BiC,CAAqB9B,GAG3C,OADA+B,SAASC,iBAAiB,UAAW9B,GAC9B,IAAM6B,SAASE,oBAAoB,UAAW/B,IACpD,CAACF,IAGG,IACT,CEdO,MAAMkC,EAAwBC,EAAAA,oBAAoBC,EAAAA,uBACtDC,WAAWvC,GACXwC,uFHGuB,CAACC,EAAmBC,KAC5C,MAAMzC,SAAEA,GAAaL,KACd2B,EAASoB,GAAcC,EAAAA,SAAiC,IAC7D3C,EAAWA,EAASyB,QAAQe,EAAWC,GAAc,MAsBvD,OAnBAvC,EAAAA,UAAU,KACR,IAAKF,EAEH,YADA0C,EAAW,MAKbA,EAAW1C,EAASyB,QAAQe,EAAWC,IASvC,OANoBzC,EAAS4C,sBAAuBxC,IAC9CA,EAAMoC,YAAcA,GAAapC,EAAMqC,aAAeA,GACxDC,EAAW1C,EAASyB,QAAQe,EAAWC,OAK1C,CAACzC,EAAUwC,EAAWC,IAElBnB,8BAM0BmB,IACjC,MAAMzC,SAAEA,GAAaL,IAErB,OAAQ6C,IACFxC,GACFA,EAAS8B,QAAQU,EAAWC,EAAY,kEA7Cb,IAAMI,YAA0BhD,EAAAA,eAAeC"}
@@ -50,7 +50,8 @@ function buildShortcutString(event) {
50
50
  }
51
51
  function createKeyDownHandler(commands) {
52
52
  return (event) => {
53
- const target = event.target;
53
+ const composedPath = event.composedPath();
54
+ const target = composedPath[0] || event.target;
54
55
  if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) {
55
56
  return;
56
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/utils/keyboard-handler.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\nimport { useState, useEffect } from '@framework';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * Automatically updates when command state changes\n * @param commandId Command ID\n * @param documentId Document ID\n * @returns ResolvedCommand or null if not available\n */\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\n const { provides } = useCommandsCapability();\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\n provides ? provides.resolve(commandId, documentId) : null,\n );\n\n useEffect(() => {\n if (!provides) {\n setCommand(null);\n return;\n }\n\n // Initial resolve\n setCommand(provides.resolve(commandId, documentId));\n\n // Subscribe to state changes for this command + document\n const unsubscribe = provides.onCommandStateChanged((event) => {\n if (event.commandId === commandId && event.documentId === documentId) {\n setCommand(provides.resolve(commandId, documentId));\n }\n });\n\n return unsubscribe;\n }, [provides, commandId, documentId]);\n\n return command;\n};\n\n/**\n * Hook to execute a command\n */\nexport const useCommandExecutor = (documentId: string) => {\n const { provides } = useCommandsCapability();\n\n return (commandId: string) => {\n if (provides) {\n provides.execute(commandId, documentId, 'ui');\n }\n };\n};\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n const target = event.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { useEffect } from '@framework';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../utils';\n\n/**\n * Utility component that listens to keyboard events\n * and executes commands based on shortcuts.\n * This component doesn't render anything, it just sets up keyboard shortcuts.\n */\nexport function KeyboardShortcuts() {\n const { provides: commands } = useCommandsCapability();\n\n useEffect(() => {\n if (!commands) return;\n\n const handleKeyDown = createKeyDownHandler(commands);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [commands]);\n\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\n return null;\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["BaseCommandsPackage"],"mappings":";;;;;;AAIO,MAAM,wBAAwB,MAAM,cAA8B,eAAe,EAAE;AACnF,MAAM,oBAAoB,MAAM,UAA0B,eAAe,EAAE;AAS3E,MAAM,aAAa,CAAC,WAAmB,eAA+C;AAC3F,QAAM,EAAE,SAAA,IAAa,sBAAA;AACrB,QAAM,CAAC,SAAS,UAAU,IAAI;AAAA,IAAiC,MAC7D,WAAW,SAAS,QAAQ,WAAW,UAAU,IAAI;AAAA,EAAA;AAGvD,YAAU,MAAM;AACd,QAAI,CAAC,UAAU;AACb,iBAAW,IAAI;AACf;AAAA,IACF;AAGA,eAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAGlD,UAAM,cAAc,SAAS,sBAAsB,CAAC,UAAU;AAC5D,UAAI,MAAM,cAAc,aAAa,MAAM,eAAe,YAAY;AACpE,mBAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAAA,MACpD;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,WAAW,UAAU,CAAC;AAEpC,SAAO;AACT;AAKO,MAAM,qBAAqB,CAAC,eAAuB;AACxD,QAAM,EAAE,SAAA,IAAa,sBAAA;AAErB,SAAO,CAAC,cAAsB;AAC5B,QAAI,UAAU;AACZ,eAAS,QAAQ,WAAW,YAAY,IAAI;AAAA,IAC9C;AAAA,EACF;AACF;AC/CO,SAAS,oBAAoB,OAAqC;AACvE,QAAM,YAAsB,CAAA;AAE5B,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AACxC,MAAI,MAAM,SAAU,WAAU,KAAK,OAAO;AAC1C,MAAI,MAAM,OAAQ,WAAU,KAAK,KAAK;AACtC,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AAGxC,QAAM,MAAM,MAAM,IAAI,YAAA;AACtB,QAAM,aAAa,CAAC,WAAW,SAAS,OAAO,MAAM,EAAE,SAAS,GAAG;AAEnE,MAAI,YAAY;AACd,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,CAAC,GAAG,WAAW,GAAG;AAChC,SAAO,MAAM,OAAO,KAAK,GAAG;AAC9B;AAKO,SAAS,qBAAqB,UAA8B;AACjE,SAAO,CAAC,UAAyB;AAE/B,UAAM,SAAS,MAAM;AACrB,QAAI,OAAO,YAAY,WAAW,OAAO,YAAY,cAAc,OAAO,mBAAmB;AAC3F;AAAA,IACF;AAEA,UAAM,WAAW,oBAAoB,KAAK;AAC1C,QAAI,CAAC,SAAU;AAEf,UAAM,UAAU,SAAS,qBAAqB,QAAQ;AACtD,QAAI,CAAC,QAAS;AAGd,UAAM,WAAW,SAAS,QAAQ,QAAQ,EAAE;AAE5C,QAAI,SAAS,YAAY,CAAC,SAAS,SAAS;AAC1C;AAAA,IACF;AAGA,UAAM,eAAA;AACN,UAAM,gBAAA;AACN,aAAS,QAAQ,QAAQ,IAAI,QAAW,UAAU;AAAA,EACpD;AACF;AC9CO,SAAS,oBAAoB;AAClC,QAAM,EAAE,UAAU,SAAA,IAAa,sBAAA;AAE/B,YAAU,MAAM;AACd,QAAI,CAAC,SAAU;AAEf,UAAM,gBAAgB,qBAAqB,QAAQ;AAEnD,aAAS,iBAAiB,WAAW,aAAa;AAClD,WAAO,MAAM,SAAS,oBAAoB,WAAW,aAAa;AAAA,EACpE,GAAG,CAAC,QAAQ,CAAC;AAGb,SAAO;AACT;ACdO,MAAM,wBAAwB,oBAAoBA,uBAAmB,EACzE,WAAW,iBAAiB,EAC5B,MAAA;"}
1
+ {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/utils/keyboard-handler.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\nimport { useState, useEffect } from '@framework';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * Automatically updates when command state changes\n * @param commandId Command ID\n * @param documentId Document ID\n * @returns ResolvedCommand or null if not available\n */\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\n const { provides } = useCommandsCapability();\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\n provides ? provides.resolve(commandId, documentId) : null,\n );\n\n useEffect(() => {\n if (!provides) {\n setCommand(null);\n return;\n }\n\n // Initial resolve\n setCommand(provides.resolve(commandId, documentId));\n\n // Subscribe to state changes for this command + document\n const unsubscribe = provides.onCommandStateChanged((event) => {\n if (event.commandId === commandId && event.documentId === documentId) {\n setCommand(provides.resolve(commandId, documentId));\n }\n });\n\n return unsubscribe;\n }, [provides, commandId, documentId]);\n\n return command;\n};\n\n/**\n * Hook to execute a command\n */\nexport const useCommandExecutor = (documentId: string) => {\n const { provides } = useCommandsCapability();\n\n return (commandId: string) => {\n if (provides) {\n provides.execute(commandId, documentId, 'ui');\n }\n };\n};\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Use composedPath to get the actual target element, even inside Shadow DOM\n const composedPath = event.composedPath();\n const target = (composedPath[0] || event.target) as HTMLElement;\n\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { useEffect } from '@framework';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../utils';\n\n/**\n * Utility component that listens to keyboard events\n * and executes commands based on shortcuts.\n * This component doesn't render anything, it just sets up keyboard shortcuts.\n */\nexport function KeyboardShortcuts() {\n const { provides: commands } = useCommandsCapability();\n\n useEffect(() => {\n if (!commands) return;\n\n const handleKeyDown = createKeyDownHandler(commands);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [commands]);\n\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\n return null;\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["BaseCommandsPackage"],"mappings":";;;;;;AAIO,MAAM,wBAAwB,MAAM,cAA8B,eAAe,EAAE;AACnF,MAAM,oBAAoB,MAAM,UAA0B,eAAe,EAAE;AAS3E,MAAM,aAAa,CAAC,WAAmB,eAA+C;AAC3F,QAAM,EAAE,SAAA,IAAa,sBAAA;AACrB,QAAM,CAAC,SAAS,UAAU,IAAI;AAAA,IAAiC,MAC7D,WAAW,SAAS,QAAQ,WAAW,UAAU,IAAI;AAAA,EAAA;AAGvD,YAAU,MAAM;AACd,QAAI,CAAC,UAAU;AACb,iBAAW,IAAI;AACf;AAAA,IACF;AAGA,eAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAGlD,UAAM,cAAc,SAAS,sBAAsB,CAAC,UAAU;AAC5D,UAAI,MAAM,cAAc,aAAa,MAAM,eAAe,YAAY;AACpE,mBAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAAA,MACpD;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,WAAW,UAAU,CAAC;AAEpC,SAAO;AACT;AAKO,MAAM,qBAAqB,CAAC,eAAuB;AACxD,QAAM,EAAE,SAAA,IAAa,sBAAA;AAErB,SAAO,CAAC,cAAsB;AAC5B,QAAI,UAAU;AACZ,eAAS,QAAQ,WAAW,YAAY,IAAI;AAAA,IAC9C;AAAA,EACF;AACF;AC/CO,SAAS,oBAAoB,OAAqC;AACvE,QAAM,YAAsB,CAAA;AAE5B,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AACxC,MAAI,MAAM,SAAU,WAAU,KAAK,OAAO;AAC1C,MAAI,MAAM,OAAQ,WAAU,KAAK,KAAK;AACtC,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AAGxC,QAAM,MAAM,MAAM,IAAI,YAAA;AACtB,QAAM,aAAa,CAAC,WAAW,SAAS,OAAO,MAAM,EAAE,SAAS,GAAG;AAEnE,MAAI,YAAY;AACd,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,CAAC,GAAG,WAAW,GAAG;AAChC,SAAO,MAAM,OAAO,KAAK,GAAG;AAC9B;AAKO,SAAS,qBAAqB,UAA8B;AACjE,SAAO,CAAC,UAAyB;AAE/B,UAAM,eAAe,MAAM,aAAA;AAC3B,UAAM,SAAU,aAAa,CAAC,KAAK,MAAM;AAGzC,QAAI,OAAO,YAAY,WAAW,OAAO,YAAY,cAAc,OAAO,mBAAmB;AAC3F;AAAA,IACF;AAEA,UAAM,WAAW,oBAAoB,KAAK;AAC1C,QAAI,CAAC,SAAU;AAEf,UAAM,UAAU,SAAS,qBAAqB,QAAQ;AACtD,QAAI,CAAC,QAAS;AAGd,UAAM,WAAW,SAAS,QAAQ,QAAQ,EAAE;AAE5C,QAAI,SAAS,YAAY,CAAC,SAAS,SAAS;AAC1C;AAAA,IACF;AAGA,UAAM,eAAA;AACN,UAAM,gBAAA;AACN,aAAS,QAAQ,QAAQ,IAAI,QAAW,UAAU;AAAA,EACpD;AACF;ACjDO,SAAS,oBAAoB;AAClC,QAAM,EAAE,UAAU,SAAA,IAAa,sBAAA;AAE/B,YAAU,MAAM;AACd,QAAI,CAAC,SAAU;AAEf,UAAM,gBAAgB,qBAAqB,QAAQ;AAEnD,aAAS,iBAAiB,WAAW,aAAa;AAClD,WAAO,MAAM,SAAS,oBAAoB,WAAW,aAAa;AAAA,EACpE,GAAG,CAAC,QAAQ,CAAC;AAGb,SAAO;AACT;ACdO,MAAM,wBAAwB,oBAAoBA,uBAAmB,EACzE,WAAW,iBAAiB,EAC5B,MAAA;"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-commands"),r=require("react"),o=require("@embedpdf/core/react"),n=()=>o.useCapability(t.CommandsPlugin.id);function s(){const{provides:e}=n();return r.useEffect(()=>{if(!e)return;const t=function(e){return t=>{const r=t.target;if("INPUT"===r.tagName||"TEXTAREA"===r.tagName||r.isContentEditable)return;const o=function(e){const t=[];e.ctrlKey&&t.push("ctrl"),e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.metaKey&&t.push("meta");const r=e.key.toLowerCase();return["control","shift","alt","meta"].includes(r)?null:[...t,r].sort().join("+")}(t);if(!o)return;const n=e.getCommandByShortcut(o);if(!n)return;const s=e.resolve(n.id);!s.disabled&&s.visible&&(t.preventDefault(),t.stopPropagation(),e.execute(n.id,void 0,"keyboard"))}}(e);return document.addEventListener("keydown",t),()=>document.removeEventListener("keydown",t)},[e]),null}const u=e.createPluginPackage(t.CommandsPluginPackage).addUtility(s).build();exports.CommandsPluginPackage=u,exports.KeyboardShortcuts=s,exports.useCommand=(e,t)=>{const{provides:o}=n(),[s,u]=r.useState(()=>o?o.resolve(e,t):null);return r.useEffect(()=>{if(!o)return void u(null);u(o.resolve(e,t));return o.onCommandStateChanged(r=>{r.commandId===e&&r.documentId===t&&u(o.resolve(e,t))})},[o,e,t]),s},exports.useCommandExecutor=e=>{const{provides:t}=n();return r=>{t&&t.execute(r,e,"ui")}},exports.useCommandsCapability=n,exports.useCommandsPlugin=()=>o.usePlugin(t.CommandsPlugin.id),Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-commands"),o=require("react"),r=require("@embedpdf/core/react"),n=()=>r.useCapability(t.CommandsPlugin.id);function s(){const{provides:e}=n();return o.useEffect(()=>{if(!e)return;const t=function(e){return t=>{const o=t.composedPath()[0]||t.target;if("INPUT"===o.tagName||"TEXTAREA"===o.tagName||o.isContentEditable)return;const r=function(e){const t=[];e.ctrlKey&&t.push("ctrl"),e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.metaKey&&t.push("meta");const o=e.key.toLowerCase();return["control","shift","alt","meta"].includes(o)?null:[...t,o].sort().join("+")}(t);if(!r)return;const n=e.getCommandByShortcut(r);if(!n)return;const s=e.resolve(n.id);!s.disabled&&s.visible&&(t.preventDefault(),t.stopPropagation(),e.execute(n.id,void 0,"keyboard"))}}(e);return document.addEventListener("keydown",t),()=>document.removeEventListener("keydown",t)},[e]),null}const u=e.createPluginPackage(t.CommandsPluginPackage).addUtility(s).build();exports.CommandsPluginPackage=u,exports.KeyboardShortcuts=s,exports.useCommand=(e,t)=>{const{provides:r}=n(),[s,u]=o.useState(()=>r?r.resolve(e,t):null);return o.useEffect(()=>{if(!r)return void u(null);u(r.resolve(e,t));return r.onCommandStateChanged(o=>{o.commandId===e&&o.documentId===t&&u(r.resolve(e,t))})},[r,e,t]),s},exports.useCommandExecutor=e=>{const{provides:t}=n();return o=>{t&&t.execute(o,e,"ui")}},exports.useCommandsCapability=n,exports.useCommandsPlugin=()=>r.usePlugin(t.CommandsPlugin.id),Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/utils/keyboard-handler.ts","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\nimport { useState, useEffect } from '@framework';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * Automatically updates when command state changes\n * @param commandId Command ID\n * @param documentId Document ID\n * @returns ResolvedCommand or null if not available\n */\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\n const { provides } = useCommandsCapability();\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\n provides ? provides.resolve(commandId, documentId) : null,\n );\n\n useEffect(() => {\n if (!provides) {\n setCommand(null);\n return;\n }\n\n // Initial resolve\n setCommand(provides.resolve(commandId, documentId));\n\n // Subscribe to state changes for this command + document\n const unsubscribe = provides.onCommandStateChanged((event) => {\n if (event.commandId === commandId && event.documentId === documentId) {\n setCommand(provides.resolve(commandId, documentId));\n }\n });\n\n return unsubscribe;\n }, [provides, commandId, documentId]);\n\n return command;\n};\n\n/**\n * Hook to execute a command\n */\nexport const useCommandExecutor = (documentId: string) => {\n const { provides } = useCommandsCapability();\n\n return (commandId: string) => {\n if (provides) {\n provides.execute(commandId, documentId, 'ui');\n }\n };\n};\n","import { useEffect } from '@framework';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../utils';\n\n/**\n * Utility component that listens to keyboard events\n * and executes commands based on shortcuts.\n * This component doesn't render anything, it just sets up keyboard shortcuts.\n */\nexport function KeyboardShortcuts() {\n const { provides: commands } = useCommandsCapability();\n\n useEffect(() => {\n if (!commands) return;\n\n const handleKeyDown = createKeyDownHandler(commands);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [commands]);\n\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\n return null;\n}\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n const target = event.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["useCommandsCapability","useCapability","CommandsPlugin","id","KeyboardShortcuts","provides","commands","useEffect","handleKeyDown","event","target","tagName","isContentEditable","shortcut","modifiers","ctrlKey","push","shiftKey","altKey","metaKey","key","toLowerCase","includes","sort","join","buildShortcutString","command","getCommandByShortcut","resolved","resolve","disabled","visible","preventDefault","stopPropagation","execute","createKeyDownHandler","document","addEventListener","removeEventListener","CommandsPluginPackage","createPluginPackage","BaseCommandsPackage","addUtility","build","commandId","documentId","setCommand","useState","onCommandStateChanged","usePlugin"],"mappings":"8MAIaA,EAAwB,IAAMC,gBAA8BC,EAAAA,eAAeC,ICKjF,SAASC,IACd,MAAQC,SAAUC,GAAaN,IAY/B,OAVAO,EAAAA,UAAU,KACR,IAAKD,EAAU,OAEf,MAAME,ECcH,SAA8BF,GACnC,OAAQG,IAEN,MAAMC,EAASD,EAAMC,OACrB,GAAuB,UAAnBA,EAAOC,SAA0C,aAAnBD,EAAOC,SAA0BD,EAAOE,kBACxE,OAGF,MAAMC,EA/BH,SAA6BJ,GAClC,MAAMK,EAAsB,GAExBL,EAAMM,SAASD,EAAUE,KAAK,QAC9BP,EAAMQ,UAAUH,EAAUE,KAAK,SAC/BP,EAAMS,QAAQJ,EAAUE,KAAK,OAC7BP,EAAMU,SAASL,EAAUE,KAAK,QAGlC,MAAMI,EAAMX,EAAMW,IAAIC,cAGtB,MAFmB,CAAC,UAAW,QAAS,MAAO,QAAQC,SAASF,GAGvD,KAGK,IAAIN,EAAWM,GAChBG,OAAOC,KAAK,IAC3B,CAaqBC,CAAoBhB,GACrC,IAAKI,EAAU,OAEf,MAAMa,EAAUpB,EAASqB,qBAAqBd,GAC9C,IAAKa,EAAS,OAGd,MAAME,EAAWtB,EAASuB,QAAQH,EAAQvB,KAEtCyB,EAASE,UAAaF,EAASG,UAKnCtB,EAAMuB,iBACNvB,EAAMwB,kBACN3B,EAAS4B,QAAQR,EAAQvB,QAAI,EAAW,aAE5C,CDxC0BgC,CAAqB7B,GAG3C,OADA8B,SAASC,iBAAiB,UAAW7B,GAC9B,IAAM4B,SAASE,oBAAoB,UAAW9B,IACpD,CAACF,IAGG,IACT,CEdO,MAAMiC,EAAwBC,EAAAA,oBAAoBC,EAAAA,uBACtDC,WAAWtC,GACXuC,uFHGuB,CAACC,EAAmBC,KAC5C,MAAMxC,SAAEA,GAAaL,KACd0B,EAASoB,GAAcC,EAAAA,SAAiC,IAC7D1C,EAAWA,EAASwB,QAAQe,EAAWC,GAAc,MAsBvD,OAnBAtC,EAAAA,UAAU,KACR,IAAKF,EAEH,YADAyC,EAAW,MAKbA,EAAWzC,EAASwB,QAAQe,EAAWC,IASvC,OANoBxC,EAAS2C,sBAAuBvC,IAC9CA,EAAMmC,YAAcA,GAAanC,EAAMoC,aAAeA,GACxDC,EAAWzC,EAASwB,QAAQe,EAAWC,OAK1C,CAACxC,EAAUuC,EAAWC,IAElBnB,8BAM0BmB,IACjC,MAAMxC,SAAEA,GAAaL,IAErB,OAAQ4C,IACFvC,GACFA,EAAS6B,QAAQU,EAAWC,EAAY,kEA7Cb,IAAMI,YAA0B/C,EAAAA,eAAeC"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/utils/keyboard-handler.ts","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\nimport { useState, useEffect } from '@framework';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * Automatically updates when command state changes\n * @param commandId Command ID\n * @param documentId Document ID\n * @returns ResolvedCommand or null if not available\n */\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\n const { provides } = useCommandsCapability();\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\n provides ? provides.resolve(commandId, documentId) : null,\n );\n\n useEffect(() => {\n if (!provides) {\n setCommand(null);\n return;\n }\n\n // Initial resolve\n setCommand(provides.resolve(commandId, documentId));\n\n // Subscribe to state changes for this command + document\n const unsubscribe = provides.onCommandStateChanged((event) => {\n if (event.commandId === commandId && event.documentId === documentId) {\n setCommand(provides.resolve(commandId, documentId));\n }\n });\n\n return unsubscribe;\n }, [provides, commandId, documentId]);\n\n return command;\n};\n\n/**\n * Hook to execute a command\n */\nexport const useCommandExecutor = (documentId: string) => {\n const { provides } = useCommandsCapability();\n\n return (commandId: string) => {\n if (provides) {\n provides.execute(commandId, documentId, 'ui');\n }\n };\n};\n","import { useEffect } from '@framework';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../utils';\n\n/**\n * Utility component that listens to keyboard events\n * and executes commands based on shortcuts.\n * This component doesn't render anything, it just sets up keyboard shortcuts.\n */\nexport function KeyboardShortcuts() {\n const { provides: commands } = useCommandsCapability();\n\n useEffect(() => {\n if (!commands) return;\n\n const handleKeyDown = createKeyDownHandler(commands);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [commands]);\n\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\n return null;\n}\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Use composedPath to get the actual target element, even inside Shadow DOM\n const composedPath = event.composedPath();\n const target = (composedPath[0] || event.target) as HTMLElement;\n\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["useCommandsCapability","useCapability","CommandsPlugin","id","KeyboardShortcuts","provides","commands","useEffect","handleKeyDown","event","target","composedPath","tagName","isContentEditable","shortcut","modifiers","ctrlKey","push","shiftKey","altKey","metaKey","key","toLowerCase","includes","sort","join","buildShortcutString","command","getCommandByShortcut","resolved","resolve","disabled","visible","preventDefault","stopPropagation","execute","createKeyDownHandler","document","addEventListener","removeEventListener","CommandsPluginPackage","createPluginPackage","BaseCommandsPackage","addUtility","build","commandId","documentId","setCommand","useState","onCommandStateChanged","usePlugin"],"mappings":"8MAIaA,EAAwB,IAAMC,gBAA8BC,EAAAA,eAAeC,ICKjF,SAASC,IACd,MAAQC,SAAUC,GAAaN,IAY/B,OAVAO,EAAAA,UAAU,KACR,IAAKD,EAAU,OAEf,MAAME,ECcH,SAA8BF,GACnC,OAAQG,IAEN,MACMC,EADeD,EAAME,eACE,IAAMF,EAAMC,OAGzC,GAAuB,UAAnBA,EAAOE,SAA0C,aAAnBF,EAAOE,SAA0BF,EAAOG,kBACxE,OAGF,MAAMC,EAlCH,SAA6BL,GAClC,MAAMM,EAAsB,GAExBN,EAAMO,SAASD,EAAUE,KAAK,QAC9BR,EAAMS,UAAUH,EAAUE,KAAK,SAC/BR,EAAMU,QAAQJ,EAAUE,KAAK,OAC7BR,EAAMW,SAASL,EAAUE,KAAK,QAGlC,MAAMI,EAAMZ,EAAMY,IAAIC,cAGtB,MAFmB,CAAC,UAAW,QAAS,MAAO,QAAQC,SAASF,GAGvD,KAGK,IAAIN,EAAWM,GAChBG,OAAOC,KAAK,IAC3B,CAgBqBC,CAAoBjB,GACrC,IAAKK,EAAU,OAEf,MAAMa,EAAUrB,EAASsB,qBAAqBd,GAC9C,IAAKa,EAAS,OAGd,MAAME,EAAWvB,EAASwB,QAAQH,EAAQxB,KAEtC0B,EAASE,UAAaF,EAASG,UAKnCvB,EAAMwB,iBACNxB,EAAMyB,kBACN5B,EAAS6B,QAAQR,EAAQxB,QAAI,EAAW,aAE5C,CD3C0BiC,CAAqB9B,GAG3C,OADA+B,SAASC,iBAAiB,UAAW9B,GAC9B,IAAM6B,SAASE,oBAAoB,UAAW/B,IACpD,CAACF,IAGG,IACT,CEdO,MAAMkC,EAAwBC,EAAAA,oBAAoBC,EAAAA,uBACtDC,WAAWvC,GACXwC,uFHGuB,CAACC,EAAmBC,KAC5C,MAAMzC,SAAEA,GAAaL,KACd2B,EAASoB,GAAcC,EAAAA,SAAiC,IAC7D3C,EAAWA,EAASyB,QAAQe,EAAWC,GAAc,MAsBvD,OAnBAvC,EAAAA,UAAU,KACR,IAAKF,EAEH,YADA0C,EAAW,MAKbA,EAAW1C,EAASyB,QAAQe,EAAWC,IASvC,OANoBzC,EAAS4C,sBAAuBxC,IAC9CA,EAAMoC,YAAcA,GAAapC,EAAMqC,aAAeA,GACxDC,EAAW1C,EAASyB,QAAQe,EAAWC,OAK1C,CAACzC,EAAUwC,EAAWC,IAElBnB,8BAM0BmB,IACjC,MAAMzC,SAAEA,GAAaL,IAErB,OAAQ6C,IACFxC,GACFA,EAAS8B,QAAQU,EAAWC,EAAY,kEA7Cb,IAAMI,YAA0BhD,EAAAA,eAAeC"}
@@ -49,7 +49,8 @@ function buildShortcutString(event) {
49
49
  }
50
50
  function createKeyDownHandler(commands) {
51
51
  return (event) => {
52
- const target = event.target;
52
+ const composedPath = event.composedPath();
53
+ const target = composedPath[0] || event.target;
53
54
  if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) {
54
55
  return;
55
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/utils/keyboard-handler.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\nimport { useState, useEffect } from '@framework';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * Automatically updates when command state changes\n * @param commandId Command ID\n * @param documentId Document ID\n * @returns ResolvedCommand or null if not available\n */\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\n const { provides } = useCommandsCapability();\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\n provides ? provides.resolve(commandId, documentId) : null,\n );\n\n useEffect(() => {\n if (!provides) {\n setCommand(null);\n return;\n }\n\n // Initial resolve\n setCommand(provides.resolve(commandId, documentId));\n\n // Subscribe to state changes for this command + document\n const unsubscribe = provides.onCommandStateChanged((event) => {\n if (event.commandId === commandId && event.documentId === documentId) {\n setCommand(provides.resolve(commandId, documentId));\n }\n });\n\n return unsubscribe;\n }, [provides, commandId, documentId]);\n\n return command;\n};\n\n/**\n * Hook to execute a command\n */\nexport const useCommandExecutor = (documentId: string) => {\n const { provides } = useCommandsCapability();\n\n return (commandId: string) => {\n if (provides) {\n provides.execute(commandId, documentId, 'ui');\n }\n };\n};\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n const target = event.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { useEffect } from '@framework';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../utils';\n\n/**\n * Utility component that listens to keyboard events\n * and executes commands based on shortcuts.\n * This component doesn't render anything, it just sets up keyboard shortcuts.\n */\nexport function KeyboardShortcuts() {\n const { provides: commands } = useCommandsCapability();\n\n useEffect(() => {\n if (!commands) return;\n\n const handleKeyDown = createKeyDownHandler(commands);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [commands]);\n\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\n return null;\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["BaseCommandsPackage"],"mappings":";;;;;AAIO,MAAM,wBAAwB,MAAM,cAA8B,eAAe,EAAE;AACnF,MAAM,oBAAoB,MAAM,UAA0B,eAAe,EAAE;AAS3E,MAAM,aAAa,CAAC,WAAmB,eAA+C;AAC3F,QAAM,EAAE,SAAA,IAAa,sBAAA;AACrB,QAAM,CAAC,SAAS,UAAU,IAAI;AAAA,IAAiC,MAC7D,WAAW,SAAS,QAAQ,WAAW,UAAU,IAAI;AAAA,EAAA;AAGvD,YAAU,MAAM;AACd,QAAI,CAAC,UAAU;AACb,iBAAW,IAAI;AACf;AAAA,IACF;AAGA,eAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAGlD,UAAM,cAAc,SAAS,sBAAsB,CAAC,UAAU;AAC5D,UAAI,MAAM,cAAc,aAAa,MAAM,eAAe,YAAY;AACpE,mBAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAAA,MACpD;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,WAAW,UAAU,CAAC;AAEpC,SAAO;AACT;AAKO,MAAM,qBAAqB,CAAC,eAAuB;AACxD,QAAM,EAAE,SAAA,IAAa,sBAAA;AAErB,SAAO,CAAC,cAAsB;AAC5B,QAAI,UAAU;AACZ,eAAS,QAAQ,WAAW,YAAY,IAAI;AAAA,IAC9C;AAAA,EACF;AACF;AC/CO,SAAS,oBAAoB,OAAqC;AACvE,QAAM,YAAsB,CAAA;AAE5B,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AACxC,MAAI,MAAM,SAAU,WAAU,KAAK,OAAO;AAC1C,MAAI,MAAM,OAAQ,WAAU,KAAK,KAAK;AACtC,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AAGxC,QAAM,MAAM,MAAM,IAAI,YAAA;AACtB,QAAM,aAAa,CAAC,WAAW,SAAS,OAAO,MAAM,EAAE,SAAS,GAAG;AAEnE,MAAI,YAAY;AACd,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,CAAC,GAAG,WAAW,GAAG;AAChC,SAAO,MAAM,OAAO,KAAK,GAAG;AAC9B;AAKO,SAAS,qBAAqB,UAA8B;AACjE,SAAO,CAAC,UAAyB;AAE/B,UAAM,SAAS,MAAM;AACrB,QAAI,OAAO,YAAY,WAAW,OAAO,YAAY,cAAc,OAAO,mBAAmB;AAC3F;AAAA,IACF;AAEA,UAAM,WAAW,oBAAoB,KAAK;AAC1C,QAAI,CAAC,SAAU;AAEf,UAAM,UAAU,SAAS,qBAAqB,QAAQ;AACtD,QAAI,CAAC,QAAS;AAGd,UAAM,WAAW,SAAS,QAAQ,QAAQ,EAAE;AAE5C,QAAI,SAAS,YAAY,CAAC,SAAS,SAAS;AAC1C;AAAA,IACF;AAGA,UAAM,eAAA;AACN,UAAM,gBAAA;AACN,aAAS,QAAQ,QAAQ,IAAI,QAAW,UAAU;AAAA,EACpD;AACF;AC9CO,SAAS,oBAAoB;AAClC,QAAM,EAAE,UAAU,SAAA,IAAa,sBAAA;AAE/B,YAAU,MAAM;AACd,QAAI,CAAC,SAAU;AAEf,UAAM,gBAAgB,qBAAqB,QAAQ;AAEnD,aAAS,iBAAiB,WAAW,aAAa;AAClD,WAAO,MAAM,SAAS,oBAAoB,WAAW,aAAa;AAAA,EACpE,GAAG,CAAC,QAAQ,CAAC;AAGb,SAAO;AACT;ACdO,MAAM,wBAAwB,oBAAoBA,uBAAmB,EACzE,WAAW,iBAAiB,EAC5B,MAAA;"}
1
+ {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/utils/keyboard-handler.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\nimport { useState, useEffect } from '@framework';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * Automatically updates when command state changes\n * @param commandId Command ID\n * @param documentId Document ID\n * @returns ResolvedCommand or null if not available\n */\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\n const { provides } = useCommandsCapability();\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\n provides ? provides.resolve(commandId, documentId) : null,\n );\n\n useEffect(() => {\n if (!provides) {\n setCommand(null);\n return;\n }\n\n // Initial resolve\n setCommand(provides.resolve(commandId, documentId));\n\n // Subscribe to state changes for this command + document\n const unsubscribe = provides.onCommandStateChanged((event) => {\n if (event.commandId === commandId && event.documentId === documentId) {\n setCommand(provides.resolve(commandId, documentId));\n }\n });\n\n return unsubscribe;\n }, [provides, commandId, documentId]);\n\n return command;\n};\n\n/**\n * Hook to execute a command\n */\nexport const useCommandExecutor = (documentId: string) => {\n const { provides } = useCommandsCapability();\n\n return (commandId: string) => {\n if (provides) {\n provides.execute(commandId, documentId, 'ui');\n }\n };\n};\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Use composedPath to get the actual target element, even inside Shadow DOM\n const composedPath = event.composedPath();\n const target = (composedPath[0] || event.target) as HTMLElement;\n\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { useEffect } from '@framework';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../utils';\n\n/**\n * Utility component that listens to keyboard events\n * and executes commands based on shortcuts.\n * This component doesn't render anything, it just sets up keyboard shortcuts.\n */\nexport function KeyboardShortcuts() {\n const { provides: commands } = useCommandsCapability();\n\n useEffect(() => {\n if (!commands) return;\n\n const handleKeyDown = createKeyDownHandler(commands);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [commands]);\n\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\n return null;\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["BaseCommandsPackage"],"mappings":";;;;;AAIO,MAAM,wBAAwB,MAAM,cAA8B,eAAe,EAAE;AACnF,MAAM,oBAAoB,MAAM,UAA0B,eAAe,EAAE;AAS3E,MAAM,aAAa,CAAC,WAAmB,eAA+C;AAC3F,QAAM,EAAE,SAAA,IAAa,sBAAA;AACrB,QAAM,CAAC,SAAS,UAAU,IAAI;AAAA,IAAiC,MAC7D,WAAW,SAAS,QAAQ,WAAW,UAAU,IAAI;AAAA,EAAA;AAGvD,YAAU,MAAM;AACd,QAAI,CAAC,UAAU;AACb,iBAAW,IAAI;AACf;AAAA,IACF;AAGA,eAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAGlD,UAAM,cAAc,SAAS,sBAAsB,CAAC,UAAU;AAC5D,UAAI,MAAM,cAAc,aAAa,MAAM,eAAe,YAAY;AACpE,mBAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAAA,MACpD;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,WAAW,UAAU,CAAC;AAEpC,SAAO;AACT;AAKO,MAAM,qBAAqB,CAAC,eAAuB;AACxD,QAAM,EAAE,SAAA,IAAa,sBAAA;AAErB,SAAO,CAAC,cAAsB;AAC5B,QAAI,UAAU;AACZ,eAAS,QAAQ,WAAW,YAAY,IAAI;AAAA,IAC9C;AAAA,EACF;AACF;AC/CO,SAAS,oBAAoB,OAAqC;AACvE,QAAM,YAAsB,CAAA;AAE5B,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AACxC,MAAI,MAAM,SAAU,WAAU,KAAK,OAAO;AAC1C,MAAI,MAAM,OAAQ,WAAU,KAAK,KAAK;AACtC,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AAGxC,QAAM,MAAM,MAAM,IAAI,YAAA;AACtB,QAAM,aAAa,CAAC,WAAW,SAAS,OAAO,MAAM,EAAE,SAAS,GAAG;AAEnE,MAAI,YAAY;AACd,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,CAAC,GAAG,WAAW,GAAG;AAChC,SAAO,MAAM,OAAO,KAAK,GAAG;AAC9B;AAKO,SAAS,qBAAqB,UAA8B;AACjE,SAAO,CAAC,UAAyB;AAE/B,UAAM,eAAe,MAAM,aAAA;AAC3B,UAAM,SAAU,aAAa,CAAC,KAAK,MAAM;AAGzC,QAAI,OAAO,YAAY,WAAW,OAAO,YAAY,cAAc,OAAO,mBAAmB;AAC3F;AAAA,IACF;AAEA,UAAM,WAAW,oBAAoB,KAAK;AAC1C,QAAI,CAAC,SAAU;AAEf,UAAM,UAAU,SAAS,qBAAqB,QAAQ;AACtD,QAAI,CAAC,QAAS;AAGd,UAAM,WAAW,SAAS,QAAQ,QAAQ,EAAE;AAE5C,QAAI,SAAS,YAAY,CAAC,SAAS,SAAS;AAC1C;AAAA,IACF;AAGA,UAAM,eAAA;AACN,UAAM,gBAAA;AACN,aAAS,QAAQ,QAAQ,IAAI,QAAW,UAAU;AAAA,EACpD;AACF;ACjDO,SAAS,oBAAoB;AAClC,QAAM,EAAE,UAAU,SAAA,IAAa,sBAAA;AAE/B,YAAU,MAAM;AACd,QAAI,CAAC,SAAU;AAEf,UAAM,gBAAgB,qBAAqB,QAAQ;AAEnD,aAAS,iBAAiB,WAAW,aAAa;AAClD,WAAO,MAAM,SAAS,oBAAoB,WAAW,aAAa;AAAA,EACpE,GAAG,CAAC,QAAQ,CAAC;AAGb,SAAO;AACT;ACdO,MAAM,wBAAwB,oBAAoBA,uBAAmB,EACzE,WAAW,iBAAiB,EAC5B,MAAA;"}
@@ -1,4 +1,4 @@
1
1
  export * from './hooks';
2
2
  export * from './components';
3
3
  export * from '../index.ts';
4
- export declare const CommandsPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../index.ts').CommandsPlugin, import('../index.ts').CommandsPluginConfig, import('../index.ts').CommandsState, import('../lib/actions').CommandsAction>>;
4
+ export declare const CommandsPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../index.ts').CommandsPlugin, import('../index.ts').CommandsPluginConfig, import('../index.ts').CommandsState, import('../lib/actions').SetDisabledCategoriesAction>>;
@@ -1,4 +1,4 @@
1
1
  export * from './hooks';
2
2
  export * from './components';
3
3
  export * from '../lib/index.ts';
4
- export declare const CommandsPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../lib/index.ts').CommandsPlugin, import('../lib/index.ts').CommandsPluginConfig, import('../lib/index.ts').CommandsState, import('../lib/actions').CommandsAction>>;
4
+ export declare const CommandsPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../lib/index.ts').CommandsPlugin, import('../lib/index.ts').CommandsPluginConfig, import('../lib/index.ts').CommandsState, import('../lib/actions').SetDisabledCategoriesAction>>;
@@ -1,4 +1,4 @@
1
1
  export * from './hooks';
2
2
  export * from './components';
3
3
  export * from '../lib/index.ts';
4
- export declare const CommandsPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../lib/index.ts').CommandsPlugin, import('../lib/index.ts').CommandsPluginConfig, import('../lib/index.ts').CommandsState, import('../lib/actions').CommandsAction>>;
4
+ export declare const CommandsPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../lib/index.ts').CommandsPlugin, import('../lib/index.ts').CommandsPluginConfig, import('../lib/index.ts').CommandsState, import('../lib/actions').SetDisabledCategoriesAction>>;
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-commands");require("svelte/internal/disclose-version"),require("svelte/internal/flags/legacy");const r=require("svelte/internal/client"),n=require("svelte"),o=require("@embedpdf/core/svelte");function s(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const r in e)if("default"!==r){const n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:()=>e[r]})}return t.default=e,Object.freeze(t)}const i=s(r),a=()=>o.useCapability(t.CommandsPlugin.id);function u(e,t){i.push(t,!1);const r=a();n.onMount(()=>{if(!r.provides)return;const e=(t=r.provides,e=>{const r=e.target;if("INPUT"===r.tagName||"TEXTAREA"===r.tagName||r.isContentEditable)return;const n=function(e){const t=[];e.ctrlKey&&t.push("ctrl"),e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.metaKey&&t.push("meta");const r=e.key.toLowerCase();return["control","shift","alt","meta"].includes(r)?null:[...t,r].sort().join("+")}(e);if(!n)return;const o=t.getCommandByShortcut(n);if(!o)return;const s=t.resolve(o.id);!s.disabled&&s.visible&&(e.preventDefault(),e.stopPropagation(),t.execute(o.id,void 0,"keyboard"))});var t;return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)}),i.init(),i.pop()}const l=e.createPluginPackage(t.CommandsPluginPackage).addUtility(u).build();exports.CommandsPluginPackage=l,exports.KeyboardShortcuts=u,exports.useCommand=(e,t)=>{const r=a();let n=i.state(null);const o=i.derived(e),s=i.derived(t);return i.user_effect(()=>{const e=r.provides,t=i.get(o),a=i.get(s);if(e&&t&&a)return i.set(n,e.resolve(t,a),!0),e.onCommandStateChanged(r=>{r.commandId===t&&r.documentId===a&&i.set(n,e.resolve(t,a),!0)});i.set(n,null)}),{get current(){return i.get(n)}}},exports.useCommandsCapability=a,exports.useCommandsPlugin=()=>o.usePlugin(t.CommandsPlugin.id),Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-commands");require("svelte/internal/disclose-version"),require("svelte/internal/flags/legacy");const r=require("svelte/internal/client"),n=require("svelte"),o=require("@embedpdf/core/svelte");function s(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const r in e)if("default"!==r){const n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:()=>e[r]})}return t.default=e,Object.freeze(t)}const i=s(r),a=()=>o.useCapability(t.CommandsPlugin.id);function u(e,t){i.push(t,!1);const r=a();n.onMount(()=>{if(!r.provides)return;const e=(t=r.provides,e=>{const r=e.composedPath()[0]||e.target;if("INPUT"===r.tagName||"TEXTAREA"===r.tagName||r.isContentEditable)return;const n=function(e){const t=[];e.ctrlKey&&t.push("ctrl"),e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.metaKey&&t.push("meta");const r=e.key.toLowerCase();return["control","shift","alt","meta"].includes(r)?null:[...t,r].sort().join("+")}(e);if(!n)return;const o=t.getCommandByShortcut(n);if(!o)return;const s=t.resolve(o.id);!s.disabled&&s.visible&&(e.preventDefault(),e.stopPropagation(),t.execute(o.id,void 0,"keyboard"))});var t;return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)}),i.init(),i.pop()}const l=e.createPluginPackage(t.CommandsPluginPackage).addUtility(u).build();exports.CommandsPluginPackage=l,exports.KeyboardShortcuts=u,exports.useCommand=(e,t)=>{const r=a();let n=i.state(null);const o=i.derived(e),s=i.derived(t);return i.user_effect(()=>{const e=r.provides,t=i.get(o),a=i.get(s);if(e&&t&&a)return i.set(n,e.resolve(t,a),!0),e.onCommandStateChanged(r=>{r.commandId===t&&r.documentId===a&&i.set(n,e.resolve(t,a),!0)});i.set(n,null)}),{get current(){return i.get(n)}}},exports.useCommandsCapability=a,exports.useCommandsPlugin=()=>o.usePlugin(t.CommandsPlugin.id),Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/svelte/hooks/use-commands.svelte.ts","../../src/svelte/components/KeyboardShortcuts.svelte","../../src/shared/utils/keyboard-handler.ts","../../src/svelte/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n// Define the return type explicitly to maintain type safety\ninterface UseCommandReturn {\n current: ResolvedCommand | null;\n}\n\n/**\n * Hook to get a reactive command for a specific document\n * @param getCommandId Function that returns the command ID\n * @param getDocumentId Function that returns the document ID\n */\nexport const useCommand = (\n getCommandId: () => string,\n getDocumentId: () => string,\n): UseCommandReturn => {\n const capability = useCommandsCapability();\n\n let command = $state<ResolvedCommand | null>(null);\n\n // Reactive commandId and documentId\n const commandId = $derived(getCommandId());\n const documentId = $derived(getDocumentId());\n\n $effect(() => {\n const provides = capability.provides;\n const cmdId = commandId;\n const docId = documentId;\n\n if (!provides || !cmdId || !docId) {\n command = null;\n return;\n }\n\n command = provides.resolve(cmdId, docId);\n\n return provides.onCommandStateChanged((event) => {\n if (event.commandId === cmdId && event.documentId === docId) {\n command = provides.resolve(cmdId, docId);\n }\n });\n });\n\n return {\n get current() {\n return command;\n },\n };\n};\n","<script lang=\"ts\">\n import { onMount } from 'svelte';\n import { useCommandsCapability } from '../hooks';\n import { createKeyDownHandler } from '../../shared/utils';\n\n const commandsCapability = useCommandsCapability();\n\n onMount(() => {\n if (!commandsCapability.provides) return;\n\n const handleKeyDown = createKeyDownHandler(commandsCapability.provides);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n });\n</script>\n\n<!-- This component is only used to set up keyboard shortcuts when the plugin is initialized. -->\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n const target = event.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["useCommandsCapability","useCapability","CommandsPlugin","id","commandsCapability","onMount","provides","handleKeyDown","commands","event","target","tagName","isContentEditable","shortcut","modifiers","ctrlKey","push","shiftKey","altKey","metaKey","key","toLowerCase","includes","sort","join","buildShortcutString","command","getCommandByShortcut","resolved","resolve","disabled","visible","preventDefault","stopPropagation","execute","document","addEventListener","removeEventListener","CommandsPluginPackage","createPluginPackage","BaseCommandsPackage","addUtility","KeyboardShortcuts","build","getCommandId","getDocumentId","capability","commandId","documentId","$","user_effect","cmdId","docId","set","onCommandStateChanged","current","usePlugin"],"mappings":"smBAGaA,EAAA,IAA8BC,gBAA8BC,EAAAA,eAAeC,iCCEhF,MAAAC,EAAqBJ,IAE3BK,EAAAA,QAAO,KACA,IAAAD,EAAmBE,SAAQ,OAE1B,MAAAC,GCmB2BC,EDnBUJ,EAAmBE,SCoBxDG,IAEN,MAAMC,EAASD,EAAMC,OACrB,GAAuB,UAAnBA,EAAOC,SAA0C,aAAnBD,EAAOC,SAA0BD,EAAOE,kBACxE,OAGF,MAAMC,EA/BH,SAA6BJ,GAClC,MAAMK,EAAsB,GAExBL,EAAMM,SAASD,EAAUE,KAAK,QAC9BP,EAAMQ,UAAUH,EAAUE,KAAK,SAC/BP,EAAMS,QAAQJ,EAAUE,KAAK,OAC7BP,EAAMU,SAASL,EAAUE,KAAK,QAGlC,MAAMI,EAAMX,EAAMW,IAAIC,cAGtB,MAFmB,CAAC,UAAW,QAAS,MAAO,QAAQC,SAASF,GAGvD,KAGK,IAAIN,EAAWM,GAChBG,OAAOC,KAAK,IAC3B,CAaqBC,CAAoBhB,GACrC,IAAKI,EAAU,OAEf,MAAMa,EAAUlB,EAASmB,qBAAqBd,GAC9C,IAAKa,EAAS,OAGd,MAAME,EAAWpB,EAASqB,QAAQH,EAAQvB,KAEtCyB,EAASE,UAAaF,EAASG,UAKnCtB,EAAMuB,iBACNvB,EAAMwB,kBACNzB,EAAS0B,QAAQR,EAAQvB,QAAI,EAAW,eAxBrC,IAA8BK,EDhBpB,OADb2B,SAASC,iBAAiB,UAAW7B,GACxB,IAAA4B,SAASE,oBAAoB,UAAW9B,qBAEzD,CENO,MAAM+B,EAAwBC,EAAAA,oBAAoBC,EAAAA,uBACtDC,WAAWC,GACXC,uFHKU,CACXC,EACAC,KAEM,MAAAC,EAAa9C,IAEf,IAAA0B,UAAyC,MAGvC,MAAAqB,YAAqBH,GACrBI,YAAsBH,UAE5BI,EAAAC,uBACQ5C,EAAWwC,EAAWxC,SACtB6C,QAAQJ,GACRK,QAAQJ,GAET,GAAA1C,GAAa6C,GAAUC,EAOrB,OAFPH,EAAAI,IAAA3B,EAAUpB,EAASuB,QAAQsB,EAAOC,IAAK,GAEhC9C,EAASgD,sBAAuB7C,IACjCA,EAAMsC,YAAcI,GAAS1C,EAAMuC,aAAeI,GACpDH,EAAAI,IAAA3B,EAAUpB,EAASuB,QAAQsB,EAAOC,IAAK,KARzCH,EAAAI,IAAA3B,EAAU,SAcR,WAAA6B,gBACK7B,EACT,8DA9CS,IAA0B8B,YAA0BtD,EAAAA,eAAeC"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/svelte/hooks/use-commands.svelte.ts","../../src/svelte/components/KeyboardShortcuts.svelte","../../src/shared/utils/keyboard-handler.ts","../../src/svelte/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n// Define the return type explicitly to maintain type safety\ninterface UseCommandReturn {\n current: ResolvedCommand | null;\n}\n\n/**\n * Hook to get a reactive command for a specific document\n * @param getCommandId Function that returns the command ID\n * @param getDocumentId Function that returns the document ID\n */\nexport const useCommand = (\n getCommandId: () => string,\n getDocumentId: () => string,\n): UseCommandReturn => {\n const capability = useCommandsCapability();\n\n let command = $state<ResolvedCommand | null>(null);\n\n // Reactive commandId and documentId\n const commandId = $derived(getCommandId());\n const documentId = $derived(getDocumentId());\n\n $effect(() => {\n const provides = capability.provides;\n const cmdId = commandId;\n const docId = documentId;\n\n if (!provides || !cmdId || !docId) {\n command = null;\n return;\n }\n\n command = provides.resolve(cmdId, docId);\n\n return provides.onCommandStateChanged((event) => {\n if (event.commandId === cmdId && event.documentId === docId) {\n command = provides.resolve(cmdId, docId);\n }\n });\n });\n\n return {\n get current() {\n return command;\n },\n };\n};\n","<script lang=\"ts\">\n import { onMount } from 'svelte';\n import { useCommandsCapability } from '../hooks';\n import { createKeyDownHandler } from '../../shared/utils';\n\n const commandsCapability = useCommandsCapability();\n\n onMount(() => {\n if (!commandsCapability.provides) return;\n\n const handleKeyDown = createKeyDownHandler(commandsCapability.provides);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n });\n</script>\n\n<!-- This component is only used to set up keyboard shortcuts when the plugin is initialized. -->\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Use composedPath to get the actual target element, even inside Shadow DOM\n const composedPath = event.composedPath();\n const target = (composedPath[0] || event.target) as HTMLElement;\n\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["useCommandsCapability","useCapability","CommandsPlugin","id","commandsCapability","onMount","provides","handleKeyDown","commands","event","target","composedPath","tagName","isContentEditable","shortcut","modifiers","ctrlKey","push","shiftKey","altKey","metaKey","key","toLowerCase","includes","sort","join","buildShortcutString","command","getCommandByShortcut","resolved","resolve","disabled","visible","preventDefault","stopPropagation","execute","document","addEventListener","removeEventListener","CommandsPluginPackage","createPluginPackage","BaseCommandsPackage","addUtility","KeyboardShortcuts","build","getCommandId","getDocumentId","capability","commandId","documentId","$","user_effect","cmdId","docId","set","onCommandStateChanged","current","usePlugin"],"mappings":"smBAGaA,EAAA,IAA8BC,gBAA8BC,EAAAA,eAAeC,iCCEhF,MAAAC,EAAqBJ,IAE3BK,EAAAA,QAAO,KACA,IAAAD,EAAmBE,SAAQ,OAE1B,MAAAC,GCmB2BC,EDnBUJ,EAAmBE,SCoBxDG,IAEN,MACMC,EADeD,EAAME,eACE,IAAMF,EAAMC,OAGzC,GAAuB,UAAnBA,EAAOE,SAA0C,aAAnBF,EAAOE,SAA0BF,EAAOG,kBACxE,OAGF,MAAMC,EAlCH,SAA6BL,GAClC,MAAMM,EAAsB,GAExBN,EAAMO,SAASD,EAAUE,KAAK,QAC9BR,EAAMS,UAAUH,EAAUE,KAAK,SAC/BR,EAAMU,QAAQJ,EAAUE,KAAK,OAC7BR,EAAMW,SAASL,EAAUE,KAAK,QAGlC,MAAMI,EAAMZ,EAAMY,IAAIC,cAGtB,MAFmB,CAAC,UAAW,QAAS,MAAO,QAAQC,SAASF,GAGvD,KAGK,IAAIN,EAAWM,GAChBG,OAAOC,KAAK,IAC3B,CAgBqBC,CAAoBjB,GACrC,IAAKK,EAAU,OAEf,MAAMa,EAAUnB,EAASoB,qBAAqBd,GAC9C,IAAKa,EAAS,OAGd,MAAME,EAAWrB,EAASsB,QAAQH,EAAQxB,KAEtC0B,EAASE,UAAaF,EAASG,UAKnCvB,EAAMwB,iBACNxB,EAAMyB,kBACN1B,EAAS2B,QAAQR,EAAQxB,QAAI,EAAW,eA3BrC,IAA8BK,EDhBpB,OADb4B,SAASC,iBAAiB,UAAW9B,GACxB,IAAA6B,SAASE,oBAAoB,UAAW/B,qBAEzD,CENO,MAAMgC,EAAwBC,EAAAA,oBAAoBC,EAAAA,uBACtDC,WAAWC,GACXC,uFHKU,CACXC,EACAC,KAEM,MAAAC,EAAa/C,IAEf,IAAA2B,UAAyC,MAGvC,MAAAqB,YAAqBH,GACrBI,YAAsBH,UAE5BI,EAAAC,uBACQ7C,EAAWyC,EAAWzC,SACtB8C,QAAQJ,GACRK,QAAQJ,GAET,GAAA3C,GAAa8C,GAAUC,EAOrB,OAFPH,EAAAI,IAAA3B,EAAUrB,EAASwB,QAAQsB,EAAOC,IAAK,GAEhC/C,EAASiD,sBAAuB9C,IACjCA,EAAMuC,YAAcI,GAAS3C,EAAMwC,aAAeI,GACpDH,EAAAI,IAAA3B,EAAUrB,EAASwB,QAAQsB,EAAOC,IAAK,KARzCH,EAAAI,IAAA3B,EAAU,SAcR,WAAA6B,gBACK7B,EACT,8DA9CS,IAA0B8B,YAA0BvD,EAAAA,eAAeC"}
@@ -1,4 +1,4 @@
1
1
  export * from './hooks';
2
2
  export * from './components';
3
3
  export * from '../lib/index.ts';
4
- export declare const CommandsPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../lib/index.ts').CommandsPlugin, import('../lib/index.ts').CommandsPluginConfig, import('../lib/index.ts').CommandsState, import('src/lib/actions').CommandsAction>>;
4
+ export declare const CommandsPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../lib/index.ts').CommandsPlugin, import('../lib/index.ts').CommandsPluginConfig, import('../lib/index.ts').CommandsState, import('src/lib/actions').SetDisabledCategoriesAction>>;
@@ -50,7 +50,8 @@ function buildShortcutString(event) {
50
50
  }
51
51
  function createKeyDownHandler(commands) {
52
52
  return (event) => {
53
- const target = event.target;
53
+ const composedPath = event.composedPath();
54
+ const target = composedPath[0] || event.target;
54
55
  if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) {
55
56
  return;
56
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/svelte/hooks/use-commands.svelte.ts","../../src/shared/utils/keyboard-handler.ts","../../src/svelte/components/KeyboardShortcuts.svelte","../../src/svelte/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n// Define the return type explicitly to maintain type safety\ninterface UseCommandReturn {\n current: ResolvedCommand | null;\n}\n\n/**\n * Hook to get a reactive command for a specific document\n * @param getCommandId Function that returns the command ID\n * @param getDocumentId Function that returns the document ID\n */\nexport const useCommand = (\n getCommandId: () => string,\n getDocumentId: () => string,\n): UseCommandReturn => {\n const capability = useCommandsCapability();\n\n let command = $state<ResolvedCommand | null>(null);\n\n // Reactive commandId and documentId\n const commandId = $derived(getCommandId());\n const documentId = $derived(getDocumentId());\n\n $effect(() => {\n const provides = capability.provides;\n const cmdId = commandId;\n const docId = documentId;\n\n if (!provides || !cmdId || !docId) {\n command = null;\n return;\n }\n\n command = provides.resolve(cmdId, docId);\n\n return provides.onCommandStateChanged((event) => {\n if (event.commandId === cmdId && event.documentId === docId) {\n command = provides.resolve(cmdId, docId);\n }\n });\n });\n\n return {\n get current() {\n return command;\n },\n };\n};\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n const target = event.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","<script lang=\"ts\">\n import { onMount } from 'svelte';\n import { useCommandsCapability } from '../hooks';\n import { createKeyDownHandler } from '../../shared/utils';\n\n const commandsCapability = useCommandsCapability();\n\n onMount(() => {\n if (!commandsCapability.provides) return;\n\n const handleKeyDown = createKeyDownHandler(commandsCapability.provides);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n });\n</script>\n\n<!-- This component is only used to set up keyboard shortcuts when the plugin is initialized. -->\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["BaseCommandsPackage"],"mappings":";;;;;;;;AAGa,MAAA,wBAAA,MAA8B,cAA8B,eAAe,EAAE;AAC7E,MAAA,oBAAA,MAA0B,UAA0B,eAAe,EAAE;AAYrE,MAAA,aAAA,CACX,cACA,kBACqB;AACf,QAAA,aAAa,sBAAA;AAEf,MAAA,kBAAyC,IAAI;AAG3C,QAAA,sBAAqB,YAAA;AACrB,QAAA,uBAAsB,aAAA;AAE5B,IAAA,kBAAc;UACN,WAAW,WAAW;AACtB,UAAA,cAAQ,SAAA;AACR,UAAA,cAAQ,UAAA;AAET,QAAA,CAAA,YAAA,CAAa,SAAA,CAAU,OAAO;AACjC,QAAA,IAAA,SAAU,IAAA;;IAEZ;AAEA,MAAA,IAAA,SAAU,SAAS,QAAQ,OAAO,KAAK,GAAA,IAAA;AAEhC,WAAA,SAAS,sBAAA,CAAuB,UAAU;UAC3C,MAAM,cAAc,SAAS,MAAM,eAAe,OAAO;AAC3D,UAAA,IAAA,SAAU,SAAS,QAAQ,OAAO,KAAK,GAAA,IAAA;AAAA,MACzC;AAAA,IACF,CAAC;AAAA,EACH,CAAC;;IAGK,IAAA,UAAU;mBACL,OAAA;AAAA,IACT;AAAA;AAEJ;AC9CO,SAAS,oBAAoB,OAAqC;AACvE,QAAM,YAAsB,CAAA;AAE5B,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AACxC,MAAI,MAAM,SAAU,WAAU,KAAK,OAAO;AAC1C,MAAI,MAAM,OAAQ,WAAU,KAAK,KAAK;AACtC,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AAGxC,QAAM,MAAM,MAAM,IAAI,YAAA;AACtB,QAAM,aAAa,CAAC,WAAW,SAAS,OAAO,MAAM,EAAE,SAAS,GAAG;AAEnE,MAAI,YAAY;AACd,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,CAAC,GAAG,WAAW,GAAG;AAChC,SAAO,MAAM,OAAO,KAAK,GAAG;AAC9B;AAKO,SAAS,qBAAqB,UAA8B;AACjE,SAAO,CAAC,UAAyB;AAE/B,UAAM,SAAS,MAAM;AACrB,QAAI,OAAO,YAAY,WAAW,OAAO,YAAY,cAAc,OAAO,mBAAmB;AAC3F;AAAA,IACF;AAEA,UAAM,WAAW,oBAAoB,KAAK;AAC1C,QAAI,CAAC,SAAU;AAEf,UAAM,UAAU,SAAS,qBAAqB,QAAQ;AACtD,QAAI,CAAC,QAAS;AAGd,UAAM,WAAW,SAAS,QAAQ,QAAQ,EAAE;AAE5C,QAAI,SAAS,YAAY,CAAC,SAAS,SAAS;AAC1C;AAAA,IACF;AAGA,UAAM,eAAA;AACN,UAAM,gBAAA;AACN,aAAS,QAAQ,QAAQ,IAAI,QAAW,UAAU;AAAA,EACpD;AACF;8CCvDA;;AAKQ,QAAA,qBAAqB,sBAAqB;AAEhD,UAAO,MAAO;AACP,QAAA,CAAA,mBAAmB,SAAQ;AAE1B,UAAA,gBAAgB,qBAAqB,mBAAmB,QAAQ;AAEtE,aAAS,iBAAiB,WAAW,aAAa;AACrC,WAAA,MAAA,SAAS,oBAAoB,WAAW,aAAa;AAAA,EACpE,CAAC;;;AACH;ACNO,MAAM,wBAAwB,oBAAoBA,uBAAmB,EACzE,WAAW,iBAAiB,EAC5B,MAAA;"}
1
+ {"version":3,"file":"index.js","sources":["../../src/svelte/hooks/use-commands.svelte.ts","../../src/shared/utils/keyboard-handler.ts","../../src/svelte/components/KeyboardShortcuts.svelte","../../src/svelte/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n// Define the return type explicitly to maintain type safety\ninterface UseCommandReturn {\n current: ResolvedCommand | null;\n}\n\n/**\n * Hook to get a reactive command for a specific document\n * @param getCommandId Function that returns the command ID\n * @param getDocumentId Function that returns the document ID\n */\nexport const useCommand = (\n getCommandId: () => string,\n getDocumentId: () => string,\n): UseCommandReturn => {\n const capability = useCommandsCapability();\n\n let command = $state<ResolvedCommand | null>(null);\n\n // Reactive commandId and documentId\n const commandId = $derived(getCommandId());\n const documentId = $derived(getDocumentId());\n\n $effect(() => {\n const provides = capability.provides;\n const cmdId = commandId;\n const docId = documentId;\n\n if (!provides || !cmdId || !docId) {\n command = null;\n return;\n }\n\n command = provides.resolve(cmdId, docId);\n\n return provides.onCommandStateChanged((event) => {\n if (event.commandId === cmdId && event.documentId === docId) {\n command = provides.resolve(cmdId, docId);\n }\n });\n });\n\n return {\n get current() {\n return command;\n },\n };\n};\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Use composedPath to get the actual target element, even inside Shadow DOM\n const composedPath = event.composedPath();\n const target = (composedPath[0] || event.target) as HTMLElement;\n\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","<script lang=\"ts\">\n import { onMount } from 'svelte';\n import { useCommandsCapability } from '../hooks';\n import { createKeyDownHandler } from '../../shared/utils';\n\n const commandsCapability = useCommandsCapability();\n\n onMount(() => {\n if (!commandsCapability.provides) return;\n\n const handleKeyDown = createKeyDownHandler(commandsCapability.provides);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n });\n</script>\n\n<!-- This component is only used to set up keyboard shortcuts when the plugin is initialized. -->\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["BaseCommandsPackage"],"mappings":";;;;;;;;AAGa,MAAA,wBAAA,MAA8B,cAA8B,eAAe,EAAE;AAC7E,MAAA,oBAAA,MAA0B,UAA0B,eAAe,EAAE;AAYrE,MAAA,aAAA,CACX,cACA,kBACqB;AACf,QAAA,aAAa,sBAAA;AAEf,MAAA,kBAAyC,IAAI;AAG3C,QAAA,sBAAqB,YAAA;AACrB,QAAA,uBAAsB,aAAA;AAE5B,IAAA,kBAAc;UACN,WAAW,WAAW;AACtB,UAAA,cAAQ,SAAA;AACR,UAAA,cAAQ,UAAA;AAET,QAAA,CAAA,YAAA,CAAa,SAAA,CAAU,OAAO;AACjC,QAAA,IAAA,SAAU,IAAA;;IAEZ;AAEA,MAAA,IAAA,SAAU,SAAS,QAAQ,OAAO,KAAK,GAAA,IAAA;AAEhC,WAAA,SAAS,sBAAA,CAAuB,UAAU;UAC3C,MAAM,cAAc,SAAS,MAAM,eAAe,OAAO;AAC3D,UAAA,IAAA,SAAU,SAAS,QAAQ,OAAO,KAAK,GAAA,IAAA;AAAA,MACzC;AAAA,IACF,CAAC;AAAA,EACH,CAAC;;IAGK,IAAA,UAAU;mBACL,OAAA;AAAA,IACT;AAAA;AAEJ;AC9CO,SAAS,oBAAoB,OAAqC;AACvE,QAAM,YAAsB,CAAA;AAE5B,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AACxC,MAAI,MAAM,SAAU,WAAU,KAAK,OAAO;AAC1C,MAAI,MAAM,OAAQ,WAAU,KAAK,KAAK;AACtC,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AAGxC,QAAM,MAAM,MAAM,IAAI,YAAA;AACtB,QAAM,aAAa,CAAC,WAAW,SAAS,OAAO,MAAM,EAAE,SAAS,GAAG;AAEnE,MAAI,YAAY;AACd,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,CAAC,GAAG,WAAW,GAAG;AAChC,SAAO,MAAM,OAAO,KAAK,GAAG;AAC9B;AAKO,SAAS,qBAAqB,UAA8B;AACjE,SAAO,CAAC,UAAyB;AAE/B,UAAM,eAAe,MAAM,aAAA;AAC3B,UAAM,SAAU,aAAa,CAAC,KAAK,MAAM;AAGzC,QAAI,OAAO,YAAY,WAAW,OAAO,YAAY,cAAc,OAAO,mBAAmB;AAC3F;AAAA,IACF;AAEA,UAAM,WAAW,oBAAoB,KAAK;AAC1C,QAAI,CAAC,SAAU;AAEf,UAAM,UAAU,SAAS,qBAAqB,QAAQ;AACtD,QAAI,CAAC,QAAS;AAGd,UAAM,WAAW,SAAS,QAAQ,QAAQ,EAAE;AAE5C,QAAI,SAAS,YAAY,CAAC,SAAS,SAAS;AAC1C;AAAA,IACF;AAGA,UAAM,eAAA;AACN,UAAM,gBAAA;AACN,aAAS,QAAQ,QAAQ,IAAI,QAAW,UAAU;AAAA,EACpD;AACF;8CC1DA;;AAKQ,QAAA,qBAAqB,sBAAqB;AAEhD,UAAO,MAAO;AACP,QAAA,CAAA,mBAAmB,SAAQ;AAE1B,UAAA,gBAAgB,qBAAqB,mBAAmB,QAAQ;AAEtE,aAAS,iBAAiB,WAAW,aAAa;AACrC,WAAA,MAAA,SAAS,oBAAoB,WAAW,aAAa;AAAA,EACpE,CAAC;;;AACH;ACNO,MAAM,wBAAwB,oBAAoBA,uBAAmB,EACzE,WAAW,iBAAiB,EAC5B,MAAA;"}
@@ -22,7 +22,7 @@ export declare const useCommand: (commandId: MaybeRefOrGetter<string>, documentI
22
22
  readonly visible: boolean;
23
23
  readonly shortcuts?: readonly string[] | undefined;
24
24
  readonly shortcutLabel?: string | undefined;
25
- readonly category?: string | undefined;
25
+ readonly categories?: readonly string[] | undefined;
26
26
  readonly description?: string | undefined;
27
27
  readonly execute: () => void;
28
28
  } | null, {
@@ -40,7 +40,7 @@ export declare const useCommand: (commandId: MaybeRefOrGetter<string>, documentI
40
40
  readonly visible: boolean;
41
41
  readonly shortcuts?: readonly string[] | undefined;
42
42
  readonly shortcutLabel?: string | undefined;
43
- readonly category?: string | undefined;
43
+ readonly categories?: readonly string[] | undefined;
44
44
  readonly description?: string | undefined;
45
45
  readonly execute: () => void;
46
46
  } | null>>;
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-commands"),n=require("vue"),o=require("@embedpdf/core/vue"),r=()=>o.useCapability(t.CommandsPlugin.id);const u=n.defineComponent({__name:"keyboard-shortcuts",setup(e){const{provides:t}=r();let o=null;return n.onMounted(()=>{if(!t.value)return;const e=function(e){return t=>{const n=t.target;if("INPUT"===n.tagName||"TEXTAREA"===n.tagName||n.isContentEditable)return;const o=function(e){const t=[];e.ctrlKey&&t.push("ctrl"),e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.metaKey&&t.push("meta");const n=e.key.toLowerCase();return["control","shift","alt","meta"].includes(n)?null:[...t,n].sort().join("+")}(t);if(!o)return;const r=e.getCommandByShortcut(o);if(!r)return;const u=e.resolve(r.id);!u.disabled&&u.visible&&(t.preventDefault(),t.stopPropagation(),e.execute(r.id,void 0,"keyboard"))}}(t.value);document.addEventListener("keydown",e),o=()=>document.removeEventListener("keydown",e)}),n.onUnmounted(()=>{null==o||o()}),(e,t)=>null}}),a=e.createPluginPackage(t.CommandsPluginPackage).addUtility(u).build();exports.CommandsPluginPackage=a,exports.KeyboardShortcuts=u,exports.useCommand=(e,t)=>{const{provides:o}=r(),u=n.ref(null);return n.watch([o,()=>n.toValue(e),()=>n.toValue(t)],([e,t,n],o,r)=>{if(!e)return void(u.value=null);u.value=e.resolve(t,n);r(e.onCommandStateChanged(o=>{o.commandId===t&&o.documentId===n&&(u.value=e.resolve(t,n))}))},{immediate:!0}),n.readonly(u)},exports.useCommandsCapability=r,exports.useCommandsPlugin=()=>o.usePlugin(t.CommandsPlugin.id),Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-commands"),o=require("vue"),n=require("@embedpdf/core/vue"),r=()=>n.useCapability(t.CommandsPlugin.id);const a=o.defineComponent({__name:"keyboard-shortcuts",setup(e){const{provides:t}=r();let n=null;return o.onMounted(()=>{if(!t.value)return;const e=function(e){return t=>{const o=t.composedPath()[0]||t.target;if("INPUT"===o.tagName||"TEXTAREA"===o.tagName||o.isContentEditable)return;const n=function(e){const t=[];e.ctrlKey&&t.push("ctrl"),e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.metaKey&&t.push("meta");const o=e.key.toLowerCase();return["control","shift","alt","meta"].includes(o)?null:[...t,o].sort().join("+")}(t);if(!n)return;const r=e.getCommandByShortcut(n);if(!r)return;const a=e.resolve(r.id);!a.disabled&&a.visible&&(t.preventDefault(),t.stopPropagation(),e.execute(r.id,void 0,"keyboard"))}}(t.value);document.addEventListener("keydown",e),n=()=>document.removeEventListener("keydown",e)}),o.onUnmounted(()=>{null==n||n()}),(e,t)=>null}}),u=e.createPluginPackage(t.CommandsPluginPackage).addUtility(a).build();exports.CommandsPluginPackage=u,exports.KeyboardShortcuts=a,exports.useCommand=(e,t)=>{const{provides:n}=r(),a=o.ref(null);return o.watch([n,()=>o.toValue(e),()=>o.toValue(t)],([e,t,o],n,r)=>{if(!e)return void(a.value=null);a.value=e.resolve(t,o);r(e.onCommandStateChanged(n=>{n.commandId===t&&n.documentId===o&&(a.value=e.resolve(t,o))}))},{immediate:!0}),o.readonly(a)},exports.useCommandsCapability=r,exports.useCommandsPlugin=()=>n.usePlugin(t.CommandsPlugin.id),Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/vue/hooks/use-commands.ts","../../src/vue/components/keyboard-shortcuts.vue","../../src/shared/utils/keyboard-handler.ts","../../src/vue/index.ts"],"sourcesContent":["import { ref, watch, readonly, toValue, type MaybeRefOrGetter } from 'vue';\nimport { useCapability, usePlugin } from '@embedpdf/core/vue';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * @param commandId Command ID (can be ref, computed, getter, or plain value)\n * @param documentId Document ID (can be ref, computed, getter, or plain value)\n */\nexport const useCommand = (\n commandId: MaybeRefOrGetter<string>,\n documentId: MaybeRefOrGetter<string>,\n) => {\n const { provides } = useCommandsCapability();\n const command = ref<ResolvedCommand | null>(null);\n\n watch(\n [provides, () => toValue(commandId), () => toValue(documentId)],\n ([providesValue, cmdId, docId], _, onCleanup) => {\n if (!providesValue) {\n command.value = null;\n return;\n }\n\n command.value = providesValue.resolve(cmdId, docId);\n\n const unsubscribe = providesValue.onCommandStateChanged((event) => {\n if (event.commandId === cmdId && event.documentId === docId) {\n command.value = providesValue.resolve(cmdId, docId);\n }\n });\n\n onCleanup(unsubscribe);\n },\n { immediate: true },\n );\n\n return readonly(command);\n};\n","<template>\n <!-- This component is only used to set up keyboard shortcuts when the plugin is initialized -->\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted, onUnmounted } from 'vue';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../../shared/utils';\n\nconst { provides: commands } = useCommandsCapability();\n\nlet cleanup: (() => void) | null = null;\n\nonMounted(() => {\n if (!commands.value) return;\n\n const handleKeyDown = createKeyDownHandler(commands.value);\n\n document.addEventListener('keydown', handleKeyDown);\n cleanup = () => document.removeEventListener('keydown', handleKeyDown);\n});\n\nonUnmounted(() => {\n cleanup?.();\n});\n</script>\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n const target = event.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["useCommandsCapability","useCapability","CommandsPlugin","id","provides","commands","cleanup","onMounted","value","handleKeyDown","event","target","tagName","isContentEditable","shortcut","modifiers","ctrlKey","push","shiftKey","altKey","metaKey","key","toLowerCase","includes","sort","join","buildShortcutString","command","getCommandByShortcut","resolved","resolve","disabled","visible","preventDefault","stopPropagation","execute","createKeyDownHandler","document","addEventListener","removeEventListener","onUnmounted","CommandsPluginPackage","createPluginPackage","BaseCommandsPackage","addUtility","KeyboardShortcuts","build","commandId","documentId","ref","watch","toValue","providesValue","cmdId","docId","_","onCleanup","onCommandStateChanged","immediate","readonly","usePlugin"],"mappings":"0MAIaA,EAAwB,IAAMC,gBAA8BC,EAAAA,eAAeC,oECKxF,MAAQC,SAAUC,GAAaL,IAE/B,IAAIM,EAA+B,YAEnCC,EAAAA,UAAU,KACR,IAAKF,EAASG,MAAO,OAErB,MAAMC,ECaD,SAA8BJ,GACnC,OAAQK,IAEN,MAAMC,EAASD,EAAMC,OACrB,GAAuB,UAAnBA,EAAOC,SAA0C,aAAnBD,EAAOC,SAA0BD,EAAOE,kBACxE,OAGF,MAAMC,EA/BH,SAA6BJ,GAClC,MAAMK,EAAsB,GAExBL,EAAMM,SAASD,EAAUE,KAAK,QAC9BP,EAAMQ,UAAUH,EAAUE,KAAK,SAC/BP,EAAMS,QAAQJ,EAAUE,KAAK,OAC7BP,EAAMU,SAASL,EAAUE,KAAK,QAGlC,MAAMI,EAAMX,EAAMW,IAAIC,cAGtB,MAFmB,CAAC,UAAW,QAAS,MAAO,QAAQC,SAASF,GAGvD,KAGK,IAAIN,EAAWM,GAChBG,OAAOC,KAAK,IAC3B,CAaqBC,CAAoBhB,GACrC,IAAKI,EAAU,OAEf,MAAMa,EAAUtB,EAASuB,qBAAqBd,GAC9C,IAAKa,EAAS,OAGd,MAAME,EAAWxB,EAASyB,QAAQH,EAAQxB,KAEtC0B,EAASE,UAAaF,EAASG,UAKnCtB,EAAMuB,iBACNvB,EAAMwB,kBACN7B,EAAS8B,QAAQR,EAAQxB,QAAI,EAAW,aAE5C,CDvCwBiC,CAAqB/B,EAASG,OAEpD6B,SAASC,iBAAiB,UAAW7B,GACrCH,EAAU,IAAM+B,SAASE,oBAAoB,UAAW9B,KAG1D+B,EAAAA,YAAY,KACV,MAAAlC,GAAAA,qBEdWmC,EAAwBC,EAAAA,oBAAoBC,EAAAA,uBACtDC,WAAWC,GACXC,uFHCuB,CACxBC,EACAC,KAEA,MAAM5C,SAAEA,GAAaJ,IACf2B,EAAUsB,EAAAA,IAA4B,MAuB5C,OArBAC,EAAAA,MACE,CAAC9C,EAAU,IAAM+C,UAAQJ,GAAY,IAAMI,EAAAA,QAAQH,IACnD,EAAEI,EAAeC,EAAOC,GAAQC,EAAGC,KACjC,IAAKJ,EAEH,YADAzB,EAAQnB,MAAQ,MAIlBmB,EAAQnB,MAAQ4C,EAActB,QAAQuB,EAAOC,GAQ7CE,EANoBJ,EAAcK,sBAAuB/C,IACnDA,EAAMqC,YAAcM,GAAS3C,EAAMsC,aAAeM,IACpD3B,EAAQnB,MAAQ4C,EAActB,QAAQuB,EAAOC,QAMnD,CAAEI,WAAW,IAGRC,EAAAA,SAAShC,8DAnCe,IAAMiC,YAA0B1D,EAAAA,eAAeC"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/vue/hooks/use-commands.ts","../../src/vue/components/keyboard-shortcuts.vue","../../src/shared/utils/keyboard-handler.ts","../../src/vue/index.ts"],"sourcesContent":["import { ref, watch, readonly, toValue, type MaybeRefOrGetter } from 'vue';\nimport { useCapability, usePlugin } from '@embedpdf/core/vue';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * @param commandId Command ID (can be ref, computed, getter, or plain value)\n * @param documentId Document ID (can be ref, computed, getter, or plain value)\n */\nexport const useCommand = (\n commandId: MaybeRefOrGetter<string>,\n documentId: MaybeRefOrGetter<string>,\n) => {\n const { provides } = useCommandsCapability();\n const command = ref<ResolvedCommand | null>(null);\n\n watch(\n [provides, () => toValue(commandId), () => toValue(documentId)],\n ([providesValue, cmdId, docId], _, onCleanup) => {\n if (!providesValue) {\n command.value = null;\n return;\n }\n\n command.value = providesValue.resolve(cmdId, docId);\n\n const unsubscribe = providesValue.onCommandStateChanged((event) => {\n if (event.commandId === cmdId && event.documentId === docId) {\n command.value = providesValue.resolve(cmdId, docId);\n }\n });\n\n onCleanup(unsubscribe);\n },\n { immediate: true },\n );\n\n return readonly(command);\n};\n","<template>\n <!-- This component is only used to set up keyboard shortcuts when the plugin is initialized -->\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted, onUnmounted } from 'vue';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../../shared/utils';\n\nconst { provides: commands } = useCommandsCapability();\n\nlet cleanup: (() => void) | null = null;\n\nonMounted(() => {\n if (!commands.value) return;\n\n const handleKeyDown = createKeyDownHandler(commands.value);\n\n document.addEventListener('keydown', handleKeyDown);\n cleanup = () => document.removeEventListener('keydown', handleKeyDown);\n});\n\nonUnmounted(() => {\n cleanup?.();\n});\n</script>\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Use composedPath to get the actual target element, even inside Shadow DOM\n const composedPath = event.composedPath();\n const target = (composedPath[0] || event.target) as HTMLElement;\n\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["useCommandsCapability","useCapability","CommandsPlugin","id","provides","commands","cleanup","onMounted","value","handleKeyDown","event","target","composedPath","tagName","isContentEditable","shortcut","modifiers","ctrlKey","push","shiftKey","altKey","metaKey","key","toLowerCase","includes","sort","join","buildShortcutString","command","getCommandByShortcut","resolved","resolve","disabled","visible","preventDefault","stopPropagation","execute","createKeyDownHandler","document","addEventListener","removeEventListener","onUnmounted","CommandsPluginPackage","createPluginPackage","BaseCommandsPackage","addUtility","KeyboardShortcuts","build","commandId","documentId","ref","watch","toValue","providesValue","cmdId","docId","_","onCleanup","onCommandStateChanged","immediate","readonly","usePlugin"],"mappings":"0MAIaA,EAAwB,IAAMC,gBAA8BC,EAAAA,eAAeC,oECKxF,MAAQC,SAAUC,GAAaL,IAE/B,IAAIM,EAA+B,YAEnCC,EAAAA,UAAU,KACR,IAAKF,EAASG,MAAO,OAErB,MAAMC,ECaD,SAA8BJ,GACnC,OAAQK,IAEN,MACMC,EADeD,EAAME,eACE,IAAMF,EAAMC,OAGzC,GAAuB,UAAnBA,EAAOE,SAA0C,aAAnBF,EAAOE,SAA0BF,EAAOG,kBACxE,OAGF,MAAMC,EAlCH,SAA6BL,GAClC,MAAMM,EAAsB,GAExBN,EAAMO,SAASD,EAAUE,KAAK,QAC9BR,EAAMS,UAAUH,EAAUE,KAAK,SAC/BR,EAAMU,QAAQJ,EAAUE,KAAK,OAC7BR,EAAMW,SAASL,EAAUE,KAAK,QAGlC,MAAMI,EAAMZ,EAAMY,IAAIC,cAGtB,MAFmB,CAAC,UAAW,QAAS,MAAO,QAAQC,SAASF,GAGvD,KAGK,IAAIN,EAAWM,GAChBG,OAAOC,KAAK,IAC3B,CAgBqBC,CAAoBjB,GACrC,IAAKK,EAAU,OAEf,MAAMa,EAAUvB,EAASwB,qBAAqBd,GAC9C,IAAKa,EAAS,OAGd,MAAME,EAAWzB,EAAS0B,QAAQH,EAAQzB,KAEtC2B,EAASE,UAAaF,EAASG,UAKnCvB,EAAMwB,iBACNxB,EAAMyB,kBACN9B,EAAS+B,QAAQR,EAAQzB,QAAI,EAAW,aAE5C,CD1CwBkC,CAAqBhC,EAASG,OAEpD8B,SAASC,iBAAiB,UAAW9B,GACrCH,EAAU,IAAMgC,SAASE,oBAAoB,UAAW/B,KAG1DgC,EAAAA,YAAY,KACV,MAAAnC,GAAAA,qBEdWoC,EAAwBC,EAAAA,oBAAoBC,EAAAA,uBACtDC,WAAWC,GACXC,uFHCuB,CACxBC,EACAC,KAEA,MAAM7C,SAAEA,GAAaJ,IACf4B,EAAUsB,EAAAA,IAA4B,MAuB5C,OArBAC,EAAAA,MACE,CAAC/C,EAAU,IAAMgD,UAAQJ,GAAY,IAAMI,EAAAA,QAAQH,IACnD,EAAEI,EAAeC,EAAOC,GAAQC,EAAGC,KACjC,IAAKJ,EAEH,YADAzB,EAAQpB,MAAQ,MAIlBoB,EAAQpB,MAAQ6C,EAActB,QAAQuB,EAAOC,GAQ7CE,EANoBJ,EAAcK,sBAAuBhD,IACnDA,EAAMsC,YAAcM,GAAS5C,EAAMuC,aAAeM,IACpD3B,EAAQpB,MAAQ6C,EAActB,QAAQuB,EAAOC,QAMnD,CAAEI,WAAW,IAGRC,EAAAA,SAAShC,8DAnCe,IAAMiC,YAA0B3D,EAAAA,eAAeC"}
@@ -1,4 +1,4 @@
1
1
  export * from './hooks';
2
2
  export * from './components';
3
3
  export * from '../lib/index.ts';
4
- export declare const CommandsPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../lib/index.ts').CommandsPlugin, import('../lib/index.ts').CommandsPluginConfig, import('../lib/index.ts').CommandsState, import('src/lib/actions').CommandsAction>>;
4
+ export declare const CommandsPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../lib/index.ts').CommandsPlugin, import('../lib/index.ts').CommandsPluginConfig, import('../lib/index.ts').CommandsState, import('src/lib/actions').SetDisabledCategoriesAction>>;
package/dist/vue/index.js CHANGED
@@ -43,7 +43,8 @@ function buildShortcutString(event) {
43
43
  }
44
44
  function createKeyDownHandler(commands) {
45
45
  return (event) => {
46
- const target = event.target;
46
+ const composedPath = event.composedPath();
47
+ const target = composedPath[0] || event.target;
47
48
  if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) {
48
49
  return;
49
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/vue/hooks/use-commands.ts","../../src/shared/utils/keyboard-handler.ts","../../src/vue/components/keyboard-shortcuts.vue","../../src/vue/index.ts"],"sourcesContent":["import { ref, watch, readonly, toValue, type MaybeRefOrGetter } from 'vue';\nimport { useCapability, usePlugin } from '@embedpdf/core/vue';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * @param commandId Command ID (can be ref, computed, getter, or plain value)\n * @param documentId Document ID (can be ref, computed, getter, or plain value)\n */\nexport const useCommand = (\n commandId: MaybeRefOrGetter<string>,\n documentId: MaybeRefOrGetter<string>,\n) => {\n const { provides } = useCommandsCapability();\n const command = ref<ResolvedCommand | null>(null);\n\n watch(\n [provides, () => toValue(commandId), () => toValue(documentId)],\n ([providesValue, cmdId, docId], _, onCleanup) => {\n if (!providesValue) {\n command.value = null;\n return;\n }\n\n command.value = providesValue.resolve(cmdId, docId);\n\n const unsubscribe = providesValue.onCommandStateChanged((event) => {\n if (event.commandId === cmdId && event.documentId === docId) {\n command.value = providesValue.resolve(cmdId, docId);\n }\n });\n\n onCleanup(unsubscribe);\n },\n { immediate: true },\n );\n\n return readonly(command);\n};\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n const target = event.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","<template>\n <!-- This component is only used to set up keyboard shortcuts when the plugin is initialized -->\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted, onUnmounted } from 'vue';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../../shared/utils';\n\nconst { provides: commands } = useCommandsCapability();\n\nlet cleanup: (() => void) | null = null;\n\nonMounted(() => {\n if (!commands.value) return;\n\n const handleKeyDown = createKeyDownHandler(commands.value);\n\n document.addEventListener('keydown', handleKeyDown);\n cleanup = () => document.removeEventListener('keydown', handleKeyDown);\n});\n\nonUnmounted(() => {\n cleanup?.();\n});\n</script>\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["BaseCommandsPackage","KeyboardShortcuts"],"mappings":";;;;;AAIO,MAAM,wBAAwB,MAAM,cAA8B,eAAe,EAAE;AACnF,MAAM,oBAAoB,MAAM,UAA0B,eAAe,EAAE;AAO3E,MAAM,aAAa,CACxB,WACA,eACG;AACH,QAAM,EAAE,SAAA,IAAa,sBAAA;AACrB,QAAM,UAAU,IAA4B,IAAI;AAEhD;AAAA,IACE,CAAC,UAAU,MAAM,QAAQ,SAAS,GAAG,MAAM,QAAQ,UAAU,CAAC;AAAA,IAC9D,CAAC,CAAC,eAAe,OAAO,KAAK,GAAG,GAAG,cAAc;AAC/C,UAAI,CAAC,eAAe;AAClB,gBAAQ,QAAQ;AAChB;AAAA,MACF;AAEA,cAAQ,QAAQ,cAAc,QAAQ,OAAO,KAAK;AAElD,YAAM,cAAc,cAAc,sBAAsB,CAAC,UAAU;AACjE,YAAI,MAAM,cAAc,SAAS,MAAM,eAAe,OAAO;AAC3D,kBAAQ,QAAQ,cAAc,QAAQ,OAAO,KAAK;AAAA,QACpD;AAAA,MACF,CAAC;AAED,gBAAU,WAAW;AAAA,IACvB;AAAA,IACA,EAAE,WAAW,KAAA;AAAA,EAAK;AAGpB,SAAO,SAAS,OAAO;AACzB;ACnCO,SAAS,oBAAoB,OAAqC;AACvE,QAAM,YAAsB,CAAA;AAE5B,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AACxC,MAAI,MAAM,SAAU,WAAU,KAAK,OAAO;AAC1C,MAAI,MAAM,OAAQ,WAAU,KAAK,KAAK;AACtC,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AAGxC,QAAM,MAAM,MAAM,IAAI,YAAA;AACtB,QAAM,aAAa,CAAC,WAAW,SAAS,OAAO,MAAM,EAAE,SAAS,GAAG;AAEnE,MAAI,YAAY;AACd,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,CAAC,GAAG,WAAW,GAAG;AAChC,SAAO,MAAM,OAAO,KAAK,GAAG;AAC9B;AAKO,SAAS,qBAAqB,UAA8B;AACjE,SAAO,CAAC,UAAyB;AAE/B,UAAM,SAAS,MAAM;AACrB,QAAI,OAAO,YAAY,WAAW,OAAO,YAAY,cAAc,OAAO,mBAAmB;AAC3F;AAAA,IACF;AAEA,UAAM,WAAW,oBAAoB,KAAK;AAC1C,QAAI,CAAC,SAAU;AAEf,UAAM,UAAU,SAAS,qBAAqB,QAAQ;AACtD,QAAI,CAAC,QAAS;AAGd,UAAM,WAAW,SAAS,QAAQ,QAAQ,EAAE;AAE5C,QAAI,SAAS,YAAY,CAAC,SAAS,SAAS;AAC1C;AAAA,IACF;AAGA,UAAM,eAAA;AACN,UAAM,gBAAA;AACN,aAAS,QAAQ,QAAQ,IAAI,QAAW,UAAU;AAAA,EACpD;AACF;;;;AC9CA,UAAM,EAAE,UAAU,SAAA,IAAa,sBAAA;AAE/B,QAAI,UAA+B;AAEnC,cAAU,MAAM;AACd,UAAI,CAAC,SAAS,MAAO;AAErB,YAAM,gBAAgB,qBAAqB,SAAS,KAAK;AAEzD,eAAS,iBAAiB,WAAW,aAAa;AAClD,gBAAU,MAAM,SAAS,oBAAoB,WAAW,aAAa;AAAA,IACvE,CAAC;AAED,gBAAY,MAAM;AAChB;AAAA,IACF,CAAC;;;;;;ACfM,MAAM,wBAAwB,oBAAoBA,uBAAmB,EACzE,WAAWC,SAAiB,EAC5B,MAAA;"}
1
+ {"version":3,"file":"index.js","sources":["../../src/vue/hooks/use-commands.ts","../../src/shared/utils/keyboard-handler.ts","../../src/vue/components/keyboard-shortcuts.vue","../../src/vue/index.ts"],"sourcesContent":["import { ref, watch, readonly, toValue, type MaybeRefOrGetter } from 'vue';\nimport { useCapability, usePlugin } from '@embedpdf/core/vue';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * @param commandId Command ID (can be ref, computed, getter, or plain value)\n * @param documentId Document ID (can be ref, computed, getter, or plain value)\n */\nexport const useCommand = (\n commandId: MaybeRefOrGetter<string>,\n documentId: MaybeRefOrGetter<string>,\n) => {\n const { provides } = useCommandsCapability();\n const command = ref<ResolvedCommand | null>(null);\n\n watch(\n [provides, () => toValue(commandId), () => toValue(documentId)],\n ([providesValue, cmdId, docId], _, onCleanup) => {\n if (!providesValue) {\n command.value = null;\n return;\n }\n\n command.value = providesValue.resolve(cmdId, docId);\n\n const unsubscribe = providesValue.onCommandStateChanged((event) => {\n if (event.commandId === cmdId && event.documentId === docId) {\n command.value = providesValue.resolve(cmdId, docId);\n }\n });\n\n onCleanup(unsubscribe);\n },\n { immediate: true },\n );\n\n return readonly(command);\n};\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n const key = event.key.toLowerCase();\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\n\n if (isModifier) {\n return null; // Just a modifier, no command\n }\n\n const parts = [...modifiers, key];\n return parts.sort().join('+');\n}\n\n/**\n * Handle keyboard events and execute commands based on shortcuts\n */\nexport function createKeyDownHandler(commands: CommandsCapability) {\n return (event: KeyboardEvent) => {\n // Use composedPath to get the actual target element, even inside Shadow DOM\n const composedPath = event.composedPath();\n const target = (composedPath[0] || event.target) as HTMLElement;\n\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","<template>\n <!-- This component is only used to set up keyboard shortcuts when the plugin is initialized -->\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted, onUnmounted } from 'vue';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../../shared/utils';\n\nconst { provides: commands } = useCommandsCapability();\n\nlet cleanup: (() => void) | null = null;\n\nonMounted(() => {\n if (!commands.value) return;\n\n const handleKeyDown = createKeyDownHandler(commands.value);\n\n document.addEventListener('keydown', handleKeyDown);\n cleanup = () => document.removeEventListener('keydown', handleKeyDown);\n});\n\nonUnmounted(() => {\n cleanup?.();\n});\n</script>\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["BaseCommandsPackage","KeyboardShortcuts"],"mappings":";;;;;AAIO,MAAM,wBAAwB,MAAM,cAA8B,eAAe,EAAE;AACnF,MAAM,oBAAoB,MAAM,UAA0B,eAAe,EAAE;AAO3E,MAAM,aAAa,CACxB,WACA,eACG;AACH,QAAM,EAAE,SAAA,IAAa,sBAAA;AACrB,QAAM,UAAU,IAA4B,IAAI;AAEhD;AAAA,IACE,CAAC,UAAU,MAAM,QAAQ,SAAS,GAAG,MAAM,QAAQ,UAAU,CAAC;AAAA,IAC9D,CAAC,CAAC,eAAe,OAAO,KAAK,GAAG,GAAG,cAAc;AAC/C,UAAI,CAAC,eAAe;AAClB,gBAAQ,QAAQ;AAChB;AAAA,MACF;AAEA,cAAQ,QAAQ,cAAc,QAAQ,OAAO,KAAK;AAElD,YAAM,cAAc,cAAc,sBAAsB,CAAC,UAAU;AACjE,YAAI,MAAM,cAAc,SAAS,MAAM,eAAe,OAAO;AAC3D,kBAAQ,QAAQ,cAAc,QAAQ,OAAO,KAAK;AAAA,QACpD;AAAA,MACF,CAAC;AAED,gBAAU,WAAW;AAAA,IACvB;AAAA,IACA,EAAE,WAAW,KAAA;AAAA,EAAK;AAGpB,SAAO,SAAS,OAAO;AACzB;ACnCO,SAAS,oBAAoB,OAAqC;AACvE,QAAM,YAAsB,CAAA;AAE5B,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AACxC,MAAI,MAAM,SAAU,WAAU,KAAK,OAAO;AAC1C,MAAI,MAAM,OAAQ,WAAU,KAAK,KAAK;AACtC,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AAGxC,QAAM,MAAM,MAAM,IAAI,YAAA;AACtB,QAAM,aAAa,CAAC,WAAW,SAAS,OAAO,MAAM,EAAE,SAAS,GAAG;AAEnE,MAAI,YAAY;AACd,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,CAAC,GAAG,WAAW,GAAG;AAChC,SAAO,MAAM,OAAO,KAAK,GAAG;AAC9B;AAKO,SAAS,qBAAqB,UAA8B;AACjE,SAAO,CAAC,UAAyB;AAE/B,UAAM,eAAe,MAAM,aAAA;AAC3B,UAAM,SAAU,aAAa,CAAC,KAAK,MAAM;AAGzC,QAAI,OAAO,YAAY,WAAW,OAAO,YAAY,cAAc,OAAO,mBAAmB;AAC3F;AAAA,IACF;AAEA,UAAM,WAAW,oBAAoB,KAAK;AAC1C,QAAI,CAAC,SAAU;AAEf,UAAM,UAAU,SAAS,qBAAqB,QAAQ;AACtD,QAAI,CAAC,QAAS;AAGd,UAAM,WAAW,SAAS,QAAQ,QAAQ,EAAE;AAE5C,QAAI,SAAS,YAAY,CAAC,SAAS,SAAS;AAC1C;AAAA,IACF;AAGA,UAAM,eAAA;AACN,UAAM,gBAAA;AACN,aAAS,QAAQ,QAAQ,IAAI,QAAW,UAAU;AAAA,EACpD;AACF;;;;ACjDA,UAAM,EAAE,UAAU,SAAA,IAAa,sBAAA;AAE/B,QAAI,UAA+B;AAEnC,cAAU,MAAM;AACd,UAAI,CAAC,SAAS,MAAO;AAErB,YAAM,gBAAgB,qBAAqB,SAAS,KAAK;AAEzD,eAAS,iBAAiB,WAAW,aAAa;AAClD,gBAAU,MAAM,SAAS,oBAAoB,WAAW,aAAa;AAAA,IACvE,CAAC;AAED,gBAAY,MAAM;AAChB;AAAA,IACF,CAAC;;;;;;ACfM,MAAM,wBAAwB,oBAAoBA,uBAAmB,EACzE,WAAWC,SAAiB,EAC5B,MAAA;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embedpdf/plugin-commands",
3
- "version": "2.0.0-next.1",
3
+ "version": "2.0.0-next.3",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.cjs",
@@ -35,14 +35,14 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@embedpdf/models": "2.0.0-next.1"
38
+ "@embedpdf/models": "2.0.0-next.3"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/react": "^18.2.0",
42
42
  "typescript": "^5.0.0",
43
- "@embedpdf/build": "1.1.0",
44
- "@embedpdf/core": "2.0.0-next.1",
45
- "@embedpdf/plugin-i18n": "2.0.0-next.1"
43
+ "@embedpdf/core": "2.0.0-next.3",
44
+ "@embedpdf/plugin-i18n": "2.0.0-next.3",
45
+ "@embedpdf/build": "1.1.0"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "react": ">=16.8.0",
@@ -50,7 +50,7 @@
50
50
  "preact": "^10.26.4",
51
51
  "vue": ">=3.2.0",
52
52
  "svelte": ">=5 <6",
53
- "@embedpdf/core": "2.0.0-next.1"
53
+ "@embedpdf/core": "2.0.0-next.3"
54
54
  },
55
55
  "files": [
56
56
  "dist",