@embedpdf/plugin-commands 2.2.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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:{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;
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","ui"],defaultConfig:{commands:{}}},o="COMMANDS/SET_DISABLED_CATEGORIES",i=e=>({type:o,payload:e}),a=class extends e.BasePlugin{constructor(t,s,o){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=o.disabledCategories)?void 0:a.length)&&this.dispatch(i(o.disabledCategories)),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.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(i(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(i(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(i(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,...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(),a=this.resolveLabel(o,i,s),r=o.shortcuts?Array.isArray(o.shortcuts)?o.shortcuts:[o.shortcuts]:void 0,n=this.resolveDynamic(o.disabled,i,s)??!1,d=this.isCommandCategoryDisabled(o),m=n||d;return{id:o.id,label:a,icon:this.resolveDynamic(o.icon,i,s),iconProps:this.resolveDynamic(o.iconProps,i,s),active:this.resolveDynamic(o.active,i,s)??!1,disabled:m,visible:this.resolveDynamic(o.visible,i,s)??!0,shortcuts:r,shortcutLabel:o.shortcutLabel,categories:o.categories,description:o.description,execute:()=>o.action({registry:this.registry,state:i,documentId:s,logger:this.logger})}}resolveLabel(e,t,s){const o=this.resolveDynamic(e.labelKey,t,s);if(o&&this.i18n){const i=this.resolveDynamic(e.labelParams,t,s);return this.i18n.t(o,{params:i,documentId:s})}return e.label?e.label:e.id}resolveDynamic(e,t,s){if(void 0!==e)return"function"==typeof e?e({registry:this.registry,state:t,documentId:s,logger:this.logger}):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=>{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 o=s.core.documents[t];if(!o||"loaded"!==o.status)return;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),r.icon!==a.icon&&(n.icon=a.icon),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===o?{...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/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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"}
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', 'ui'],\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 { Logger } from '@embedpdf/models';\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: () =>\n command.action({\n registry: this.registry,\n state,\n documentId: resolvedDocId,\n logger: this.logger,\n }),\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 const labelKey = this.resolveDynamic(command.labelKey, state, documentId);\n if (labelKey && this.i18n) {\n const params = this.resolveDynamic(command.labelParams, state, documentId);\n return this.i18n.t(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 (\n value as (context: {\n registry: PluginRegistry;\n state: StoreState<any>;\n documentId: string;\n logger: Logger;\n }) => T\n )({\n registry: this.registry,\n state,\n documentId,\n logger: this.logger,\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 // Skip if document isn't fully loaded yet\n const coreDoc = newState.core.documents[documentId];\n if (!coreDoc || coreDoc.status !== 'loaded') return;\n\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 (prevResolved.icon !== newResolved.icon) {\n changes.icon = newResolved.icon;\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","coreDoc","status","previousCache","newResolved","prevResolved","changes","arePropsEqual","CommandsPlugin","initialState","CommandsPluginPackage","create","reducer"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ const manifest = {
6
6
  version: "1.0.0",
7
7
  provides: ["commands"],
8
8
  requires: [],
9
- optional: ["i18n"],
9
+ optional: ["i18n", "ui"],
10
10
  defaultConfig: {
11
11
  commands: {}
12
12
  }
@@ -171,13 +171,19 @@ const _CommandsPlugin = class _CommandsPlugin extends BasePlugin {
171
171
  shortcutLabel: command.shortcutLabel,
172
172
  categories: command.categories,
173
173
  description: command.description,
174
- execute: () => command.action({ registry: this.registry, state, documentId: resolvedDocId })
174
+ execute: () => command.action({
175
+ registry: this.registry,
176
+ state,
177
+ documentId: resolvedDocId,
178
+ logger: this.logger
179
+ })
175
180
  };
176
181
  }
177
182
  resolveLabel(command, state, documentId) {
178
- if (command.labelKey && this.i18n) {
183
+ const labelKey = this.resolveDynamic(command.labelKey, state, documentId);
184
+ if (labelKey && this.i18n) {
179
185
  const params = this.resolveDynamic(command.labelParams, state, documentId);
180
- return this.i18n.t(command.labelKey, { params, documentId });
186
+ return this.i18n.t(labelKey, { params, documentId });
181
187
  }
182
188
  if (command.label) {
183
189
  return command.label;
@@ -188,8 +194,10 @@ const _CommandsPlugin = class _CommandsPlugin extends BasePlugin {
188
194
  if (value === void 0) return void 0;
189
195
  if (typeof value === "function") {
190
196
  return value({
197
+ registry: this.registry,
191
198
  state,
192
- documentId
199
+ documentId,
200
+ logger: this.logger
193
201
  });
194
202
  }
195
203
  return value;
@@ -301,6 +309,8 @@ const _CommandsPlugin = class _CommandsPlugin extends BasePlugin {
301
309
  });
302
310
  }
303
311
  detectCommandChanges(documentId, newState) {
312
+ const coreDoc = newState.core.documents[documentId];
313
+ if (!coreDoc || coreDoc.status !== "loaded") return;
304
314
  const previousCache = this.previousStates.get(documentId) ?? /* @__PURE__ */ new Map();
305
315
  this.commands.forEach((command, commandId) => {
306
316
  const newResolved = this.resolve(commandId, documentId);
@@ -322,6 +332,9 @@ const _CommandsPlugin = class _CommandsPlugin extends BasePlugin {
322
332
  if (prevResolved.label !== newResolved.label) {
323
333
  changes.label = newResolved.label;
324
334
  }
335
+ if (prevResolved.icon !== newResolved.icon) {
336
+ changes.icon = newResolved.icon;
337
+ }
325
338
  if (!arePropsEqual(prevResolved.iconProps, newResolved.iconProps)) {
326
339
  changes.iconProps = newResolved.iconProps;
327
340
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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
+ {"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', 'ui'],\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 { Logger } from '@embedpdf/models';\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: () =>\n command.action({\n registry: this.registry,\n state,\n documentId: resolvedDocId,\n logger: this.logger,\n }),\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 const labelKey = this.resolveDynamic(command.labelKey, state, documentId);\n if (labelKey && this.i18n) {\n const params = this.resolveDynamic(command.labelParams, state, documentId);\n return this.i18n.t(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 (\n value as (context: {\n registry: PluginRegistry;\n state: StoreState<any>;\n documentId: string;\n logger: Logger;\n }) => T\n )({\n registry: this.registry,\n state,\n documentId,\n logger: this.logger,\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 // Skip if document isn't fully loaded yet\n const coreDoc = newState.core.documents[documentId];\n if (!coreDoc || coreDoc.status !== 'loaded') return;\n\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 (prevResolved.icon !== newResolved.icon) {\n changes.icon = newResolved.icon;\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,8 +1,11 @@
1
1
  import { BasePluginConfig, CoreState, EventHook, PluginRegistry } from '@embedpdf/core';
2
+ import { Logger } from '@embedpdf/models';
2
3
  import { TranslationKey } from '@embedpdf/plugin-i18n';
3
4
  export type Dynamic<TStore, T> = T | ((context: {
5
+ registry: PluginRegistry;
4
6
  state: TStore;
5
7
  documentId: string;
8
+ logger: Logger;
6
9
  }) => T);
7
10
  export interface IconProps {
8
11
  primaryColor?: string;
@@ -13,7 +16,7 @@ export interface IconProps {
13
16
  export interface Command<TStore = any> {
14
17
  id: string;
15
18
  label?: string;
16
- labelKey?: TranslationKey;
19
+ labelKey?: Dynamic<TStore, TranslationKey>;
17
20
  labelParams?: Dynamic<TStore, Record<string, string | number>>;
18
21
  icon?: Dynamic<TStore, string>;
19
22
  iconProps?: Dynamic<TStore, IconProps>;
@@ -21,6 +24,7 @@ export interface Command<TStore = any> {
21
24
  registry: PluginRegistry;
22
25
  state: TStore;
23
26
  documentId: string;
27
+ logger: Logger;
24
28
  }) => void;
25
29
  active?: Dynamic<TStore, boolean>;
26
30
  disabled?: Dynamic<TStore, boolean>;
@@ -70,6 +74,7 @@ export interface CommandStateChangedEvent {
70
74
  disabled?: boolean;
71
75
  visible?: boolean;
72
76
  label?: string;
77
+ icon?: string;
73
78
  iconProps?: IconProps;
74
79
  };
75
80
  }
@@ -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 // 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","$","state","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,QAEf2B,EAAUqB,EAAAC,MAA+B,MAGvC,MAAAC,YAAqBL,GACrBM,YAAsBL,UAE5BE,EAAAI,uBACQ9C,EAAWyC,EAAWzC,SACtB+C,QAAQH,GACRI,QAAQH,GAET,GAAA7C,GAAa+C,GAAUC,EAOrB,OAFPN,EAAAO,IAAA5B,EAAUrB,EAASwB,QAAQuB,EAAOC,IAAK,GAEhChD,EAASkD,sBAAuB/C,IACjCA,EAAMyC,YAAcG,GAAS5C,EAAM0C,aAAeG,GACpDN,EAAAO,IAAA5B,EAAUrB,EAASwB,QAAQuB,EAAOC,IAAK,KARzCN,EAAAO,IAAA5B,EAAU,SAcR,WAAA8B,gBACK9B,EACT,8DA9CS,IAA0B+B,YAA0BxD,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","$","state","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,qBAEjD,CEND,MAAMgC,EAAwBC,EAAAA,oBAAoBC,EAAAA,uBACtDC,WAAWC,GACXC,uFHKU,CACXC,EACAC,KAEM,MAAAC,EAAa/C,QAEf2B,EAAUqB,EAAAC,MAA+B,MAGvC,MAAAC,YAAqBL,GACrBM,YAAsBL,UAE5BE,EAAAI,uBACQ9C,EAAWyC,EAAWzC,SACtB+C,QAAQH,GACRI,QAAQH,GAET,GAAA7C,GAAa+C,GAAUC,EAOrB,OAFPN,EAAAO,IAAA5B,EAAUrB,EAASwB,QAAQuB,EAAOC,IAAK,GAEhChD,EAASkD,sBAAuB/C,IACjCA,EAAMyC,YAAcG,GAAS5C,EAAM0C,aAAeG,GACpDN,EAAAO,IAAA5B,EAAUrB,EAASwB,QAAQuB,EAAOC,IAAK,KARzCN,EAAAO,IAAA5B,EAAU,SAcR,WAAA8B,gBACK9B,EACT,8DA9CS,IAA0B+B,YAA0BxD,EAAAA,eAAeC"}
@@ -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 // 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;MAEf,UAAU,EAAA,MAA+B,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;"}
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;MAEf,UAAU,EAAA,MAA+B,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;;;AACK;ACND,MAAM,wBAAwB,oBAAoBA,uBAAmB,EACzE,WAAW,iBAAiB,EAC5B,MAAA;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embedpdf/plugin-commands",
3
- "version": "2.2.0",
3
+ "version": "2.4.0",
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.2.0"
38
+ "@embedpdf/models": "2.4.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/react": "^18.2.0",
42
42
  "typescript": "^5.0.0",
43
- "@embedpdf/core": "2.2.0",
44
- "@embedpdf/plugin-i18n": "2.2.0",
45
- "@embedpdf/build": "1.1.0"
43
+ "@embedpdf/build": "1.1.0",
44
+ "@embedpdf/plugin-i18n": "2.4.0",
45
+ "@embedpdf/core": "2.4.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.2.0"
53
+ "@embedpdf/core": "2.4.0"
54
54
  },
55
55
  "files": [
56
56
  "dist",