@lofcz/embedpdf-plugin-commands 2.14.5 → 2.14.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/react/index.cjs.map +1 -1
  5. package/dist/react/index.js.map +1 -1
  6. package/dist/shared/hooks/use-commands.d.ts +11 -3
  7. package/dist/shared-react/components/index.d.ts +1 -0
  8. package/dist/shared-react/components/keyboard-shortcuts.d.ts +6 -0
  9. package/dist/{svelte/hooks/use-commands.svelte.d.ts → shared-react/hooks/use-commands.d.ts} +9 -7
  10. package/dist/{vue → shared-react}/index.d.ts +1 -1
  11. package/dist/shared-react/utils/index.d.ts +1 -0
  12. package/dist/shared-react/utils/keyboard-handler.d.ts +10 -0
  13. package/package.json +20 -20
  14. package/dist/preact/adapter.d.ts +0 -5
  15. package/dist/preact/core.d.ts +0 -1
  16. package/dist/preact/index.cjs +0 -2
  17. package/dist/preact/index.cjs.map +0 -1
  18. package/dist/preact/index.d.ts +0 -1
  19. package/dist/preact/index.js +0 -91
  20. package/dist/preact/index.js.map +0 -1
  21. package/dist/svelte/components/KeyboardShortcuts.svelte.d.ts +0 -18
  22. package/dist/svelte/components/index.d.ts +0 -1
  23. package/dist/svelte/hooks/index.d.ts +0 -1
  24. package/dist/svelte/index.cjs +0 -2
  25. package/dist/svelte/index.cjs.map +0 -1
  26. package/dist/svelte/index.d.ts +0 -4
  27. package/dist/svelte/index.js +0 -92
  28. package/dist/svelte/index.js.map +0 -1
  29. package/dist/vue/components/index.d.ts +0 -1
  30. package/dist/vue/components/keyboard-shortcuts.vue.d.ts +0 -3
  31. package/dist/vue/hooks/use-commands.d.ts +0 -46
  32. package/dist/vue/index.cjs +0 -2
  33. package/dist/vue/index.cjs.map +0 -1
  34. package/dist/vue/index.js +0 -92
  35. package/dist/vue/index.js.map +0 -1
  36. /package/dist/{vue → shared-react}/hooks/index.d.ts +0 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 CloudPDF
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -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';\r\nimport { CommandsPluginConfig } from './types';\r\n\r\nexport const COMMANDS_PLUGIN_ID = 'commands';\r\n\r\nexport const manifest: PluginManifest<CommandsPluginConfig> = {\r\n id: COMMANDS_PLUGIN_ID,\r\n name: 'Commands Plugin',\r\n version: '1.0.0',\r\n provides: ['commands'],\r\n requires: [],\r\n optional: ['i18n', 'ui'],\r\n defaultConfig: {\r\n commands: {},\r\n },\r\n};\r\n","import { Action } from '@embedpdf/core';\r\n\r\nexport const SET_DISABLED_CATEGORIES = 'COMMANDS/SET_DISABLED_CATEGORIES';\r\n\r\nexport interface SetDisabledCategoriesAction extends Action {\r\n type: typeof SET_DISABLED_CATEGORIES;\r\n payload: string[];\r\n}\r\n\r\nexport type CommandsAction = SetDisabledCategoriesAction;\r\n\r\nexport const setDisabledCategories = (categories: string[]): SetDisabledCategoriesAction => ({\r\n type: SET_DISABLED_CATEGORIES,\r\n payload: categories,\r\n});\r\n","import {\r\n BasePlugin,\r\n PluginRegistry,\r\n StoreState,\r\n createEmitter,\r\n createBehaviorEmitter,\r\n Listener,\r\n arePropsEqual,\r\n} from '@embedpdf/core';\r\nimport { Logger } from '@embedpdf/models';\r\nimport { I18nCapability, I18nPlugin } from '@embedpdf/plugin-i18n';\r\nimport {\r\n CommandsCapability,\r\n CommandsPluginConfig,\r\n CommandsState,\r\n Command,\r\n ResolvedCommand,\r\n CommandExecutedEvent,\r\n CommandStateChangedEvent,\r\n ShortcutExecutedEvent,\r\n CategoryChangedEvent,\r\n CommandScope,\r\n Dynamic,\r\n} from './types';\r\nimport { CommandsAction, setDisabledCategories } from './actions';\r\n\r\nexport class CommandsPlugin extends BasePlugin<\r\n CommandsPluginConfig,\r\n CommandsCapability,\r\n CommandsState,\r\n CommandsAction\r\n> {\r\n static readonly id = 'commands' as const;\r\n\r\n private commands = new Map<string, Command>();\r\n private i18n: I18nCapability | null = null;\r\n private shortcutMap = new Map<string, string>(); // shortcut -> commandId\r\n\r\n private readonly commandExecuted$ = createEmitter<CommandExecutedEvent>();\r\n private readonly commandStateChanged$ = createEmitter<CommandStateChangedEvent>();\r\n private readonly shortcutExecuted$ = createEmitter<ShortcutExecutedEvent>();\r\n private readonly categoryChanged$ = createBehaviorEmitter<CategoryChangedEvent>();\r\n\r\n // Cache previous resolved states per document to detect changes\r\n private previousStates = new Map<string, Map<string, ResolvedCommand>>();\r\n\r\n constructor(id: string, registry: PluginRegistry, config: CommandsPluginConfig) {\r\n super(id, registry);\r\n\r\n // Check if i18n plugin is available (optional dependency)\r\n const i18nPlugin = registry.getPlugin<I18nPlugin>('i18n');\r\n this.i18n = i18nPlugin?.provides() ?? null;\r\n\r\n // Initialize disabled categories from config\r\n if (config.disabledCategories?.length) {\r\n this.dispatch(setDisabledCategories(config.disabledCategories));\r\n }\r\n\r\n // Register all commands from config\r\n Object.values(config.commands).forEach((command) => {\r\n this.registerCommand(command);\r\n });\r\n\r\n // Subscribe to global store changes\r\n this.registry.getStore().subscribe((_action, newState) => {\r\n this.onGlobalStoreChange(newState);\r\n });\r\n }\r\n\r\n protected override onDocumentClosed(documentId: string): void {\r\n // Cleanup previous states cache\r\n this.previousStates.delete(documentId);\r\n\r\n this.logger.debug(\r\n 'CommandsPlugin',\r\n 'DocumentClosed',\r\n `Cleaned up command state cache for document: ${documentId}`,\r\n );\r\n }\r\n\r\n async initialize(): Promise<void> {\r\n this.logger.info('CommandsPlugin', 'Initialize', 'Commands plugin initialized');\r\n }\r\n\r\n async destroy(): Promise<void> {\r\n this.commandExecuted$.clear();\r\n this.commandStateChanged$.clear();\r\n this.shortcutExecuted$.clear();\r\n this.categoryChanged$.clear();\r\n this.commands.clear();\r\n this.shortcutMap.clear();\r\n this.previousStates.clear();\r\n super.destroy();\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Category Management\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private disableCategoryImpl(category: string): void {\r\n const current = new Set(this.state.disabledCategories);\r\n if (!current.has(category)) {\r\n current.add(category);\r\n this.dispatch(setDisabledCategories(Array.from(current)));\r\n this.categoryChanged$.emit({ disabledCategories: Array.from(current) });\r\n }\r\n }\r\n\r\n private enableCategoryImpl(category: string): void {\r\n const current = new Set(this.state.disabledCategories);\r\n if (current.has(category)) {\r\n current.delete(category);\r\n this.dispatch(setDisabledCategories(Array.from(current)));\r\n this.categoryChanged$.emit({ disabledCategories: Array.from(current) });\r\n }\r\n }\r\n\r\n private toggleCategoryImpl(category: string): void {\r\n if (this.state.disabledCategories.includes(category)) {\r\n this.enableCategoryImpl(category);\r\n } else {\r\n this.disableCategoryImpl(category);\r\n }\r\n }\r\n\r\n private setDisabledCategoriesImpl(categories: string[]): void {\r\n this.dispatch(setDisabledCategories(categories));\r\n this.categoryChanged$.emit({ disabledCategories: categories });\r\n }\r\n\r\n /**\r\n * Check if command has any disabled category\r\n */\r\n private isCommandCategoryDisabled(command: Command): boolean {\r\n if (!command.categories?.length) return false;\r\n return command.categories.some((cat) => this.state.disabledCategories.includes(cat));\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Capability\r\n // ─────────────────────────────────────────────────────────\r\n\r\n protected buildCapability(): CommandsCapability {\r\n return {\r\n resolve: (commandId, documentId) => this.resolve(commandId, documentId),\r\n execute: (commandId, documentId, source = 'ui') =>\r\n this.execute(commandId, documentId, source),\r\n getAllCommands: (documentId) => this.getAllCommands(documentId),\r\n getCommandsByCategory: (category, documentId) =>\r\n this.getCommandsByCategory(category, documentId),\r\n getCommandByShortcut: (shortcut) => this.getCommandByShortcut(shortcut),\r\n getAllShortcuts: () => new Map(this.shortcutMap),\r\n forDocument: (documentId) => this.createCommandScope(documentId),\r\n registerCommand: (command) => this.registerCommand(command),\r\n unregisterCommand: (commandId) => this.unregisterCommand(commandId),\r\n\r\n // Category management\r\n disableCategory: (category) => this.disableCategoryImpl(category),\r\n enableCategory: (category) => this.enableCategoryImpl(category),\r\n toggleCategory: (category) => this.toggleCategoryImpl(category),\r\n setDisabledCategories: (categories) => this.setDisabledCategoriesImpl(categories),\r\n getDisabledCategories: () => this.state.disabledCategories,\r\n isCategoryDisabled: (category) => this.state.disabledCategories.includes(category),\r\n\r\n // Events\r\n onCommandExecuted: this.commandExecuted$.on,\r\n onCommandStateChanged: this.commandStateChanged$.on,\r\n onShortcutExecuted: this.shortcutExecuted$.on,\r\n onCategoryChanged: this.categoryChanged$.on,\r\n };\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Document Scoping\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private createCommandScope(documentId: string): CommandScope {\r\n return {\r\n resolve: (commandId) => this.resolve(commandId, documentId),\r\n execute: (commandId, source = 'ui') => this.execute(commandId, documentId, source),\r\n getAllCommands: () => this.getAllCommands(documentId),\r\n getCommandsByCategory: (category) => this.getCommandsByCategory(category, documentId),\r\n onCommandStateChanged: (listener: Listener<Omit<CommandStateChangedEvent, 'documentId'>>) =>\r\n this.commandStateChanged$.on((event) => {\r\n if (event.documentId === documentId) {\r\n const { documentId: _, ...rest } = event;\r\n listener(rest);\r\n }\r\n }),\r\n };\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Command Resolution\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private resolve(commandId: string, documentId?: string): ResolvedCommand {\r\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\r\n\r\n const command = this.commands.get(commandId);\r\n if (!command) {\r\n throw new Error(`Command not found: ${commandId}`);\r\n }\r\n\r\n const state = this.registry.getStore().getState();\r\n\r\n // Resolve label with i18n if available\r\n const label = this.resolveLabel(command, state, resolvedDocId);\r\n\r\n // Resolve shortcuts\r\n const shortcuts = command.shortcuts\r\n ? Array.isArray(command.shortcuts)\r\n ? command.shortcuts\r\n : [command.shortcuts]\r\n : undefined;\r\n\r\n // Check if disabled via categories OR explicit disabled predicate\r\n const explicitDisabled = this.resolveDynamic(command.disabled, state, resolvedDocId) ?? false;\r\n const categoryDisabled = this.isCommandCategoryDisabled(command);\r\n const isDisabled = explicitDisabled || categoryDisabled;\r\n\r\n return {\r\n id: command.id,\r\n label,\r\n icon: this.resolveDynamic(command.icon, state, resolvedDocId),\r\n iconProps: this.resolveDynamic(command.iconProps, state, resolvedDocId),\r\n active: this.resolveDynamic(command.active, state, resolvedDocId) ?? false,\r\n disabled: isDisabled,\r\n visible: this.resolveDynamic(command.visible, state, resolvedDocId) ?? true,\r\n shortcuts,\r\n shortcutLabel: command.shortcutLabel,\r\n categories: command.categories,\r\n description: command.description,\r\n execute: () =>\r\n command.action({\r\n registry: this.registry,\r\n state,\r\n documentId: resolvedDocId,\r\n logger: this.logger,\r\n }),\r\n };\r\n }\r\n\r\n private resolveLabel(command: Command, state: StoreState<any>, documentId: string): string {\r\n // Priority: labelKey (with i18n) > label (plain string) > id (fallback)\r\n const labelKey = this.resolveDynamic(command.labelKey, state, documentId);\r\n if (labelKey && this.i18n) {\r\n const params = this.resolveDynamic(command.labelParams, state, documentId);\r\n return this.i18n.t(labelKey, { params, documentId });\r\n }\r\n\r\n if (command.label) {\r\n return command.label;\r\n }\r\n\r\n return command.id; // Fallback to ID\r\n }\r\n\r\n private resolveDynamic<T>(\r\n value: Dynamic<any, T> | undefined,\r\n state: StoreState<any>,\r\n documentId: string,\r\n ): T | undefined {\r\n if (value === undefined) return undefined;\r\n\r\n // Check if it's a function (the dynamic evaluator)\r\n if (typeof value === 'function') {\r\n return (\r\n value as (context: {\r\n registry: PluginRegistry;\r\n state: StoreState<any>;\r\n documentId: string;\r\n logger: Logger;\r\n }) => T\r\n )({\r\n registry: this.registry,\r\n state,\r\n documentId,\r\n logger: this.logger,\r\n });\r\n }\r\n\r\n // Otherwise it's the static value\r\n return value as T;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Command Execution\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private execute(\r\n commandId: string,\r\n documentId?: string,\r\n source: 'keyboard' | 'ui' | 'api' = 'ui',\r\n ): void {\r\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\r\n const resolved = this.resolve(commandId, resolvedDocId);\r\n\r\n if (resolved.disabled) {\r\n this.logger.warn(\r\n 'CommandsPlugin',\r\n 'ExecutionBlocked',\r\n `Command '${commandId}' is disabled for document '${resolvedDocId}'`,\r\n );\r\n return;\r\n }\r\n\r\n if (!resolved.visible) {\r\n this.logger.warn(\r\n 'CommandsPlugin',\r\n 'ExecutionBlocked',\r\n `Command '${commandId}' is not visible for document '${resolvedDocId}'`,\r\n );\r\n return;\r\n }\r\n\r\n resolved.execute();\r\n\r\n this.commandExecuted$.emit({\r\n commandId,\r\n documentId: resolvedDocId,\r\n source,\r\n });\r\n\r\n this.logger.debug(\r\n 'CommandsPlugin',\r\n 'CommandExecuted',\r\n `Command '${commandId}' executed for document '${resolvedDocId}' (source: ${source})`,\r\n );\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Command Registration\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private registerCommand(command: Command): void {\r\n if (this.commands.has(command.id)) {\r\n this.logger.warn(\r\n 'CommandsPlugin',\r\n 'CommandOverwrite',\r\n `Command '${command.id}' already exists and will be overwritten`,\r\n );\r\n }\r\n\r\n this.commands.set(command.id, command);\r\n\r\n // Register shortcuts\r\n if (command.shortcuts) {\r\n const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];\r\n\r\n shortcuts.forEach((shortcut) => {\r\n const normalized = this.normalizeShortcut(shortcut);\r\n this.shortcutMap.set(normalized, command.id);\r\n });\r\n }\r\n\r\n this.logger.debug('CommandsPlugin', 'CommandRegistered', `Command '${command.id}' registered`);\r\n }\r\n\r\n private unregisterCommand(commandId: string): void {\r\n const command = this.commands.get(commandId);\r\n if (!command) return;\r\n\r\n // Remove shortcuts\r\n if (command.shortcuts) {\r\n const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];\r\n\r\n shortcuts.forEach((shortcut) => {\r\n const normalized = this.normalizeShortcut(shortcut);\r\n this.shortcutMap.delete(normalized);\r\n });\r\n }\r\n\r\n this.commands.delete(commandId);\r\n this.logger.debug(\r\n 'CommandsPlugin',\r\n 'CommandUnregistered',\r\n `Command '${commandId}' unregistered`,\r\n );\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Shortcuts\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private getCommandByShortcut(shortcut: string): Command | null {\r\n const normalized = this.normalizeShortcut(shortcut);\r\n const commandId = this.shortcutMap.get(normalized);\r\n return commandId ? (this.commands.get(commandId) ?? null) : null;\r\n }\r\n\r\n private normalizeShortcut(shortcut: string): string {\r\n // Normalize: \"Ctrl+Shift+A\" -> \"ctrl+shift+a\"\r\n return shortcut.toLowerCase().split('+').sort().join('+');\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Query Methods\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private getAllCommands(documentId?: string): ResolvedCommand[] {\r\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\r\n return Array.from(this.commands.keys()).map((id) => this.resolve(id, resolvedDocId));\r\n }\r\n\r\n private getCommandsByCategory(category: string, documentId?: string): ResolvedCommand[] {\r\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\r\n return Array.from(this.commands.values())\r\n .filter((cmd) => cmd.categories?.includes(category))\r\n .map((cmd) => this.resolve(cmd.id, resolvedDocId));\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // State Change Detection\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private onGlobalStoreChange(newState: StoreState<any>): void {\r\n // Get all documents from core state\r\n const documentIds = Object.keys(newState.core.documents);\r\n\r\n // Check each document for command state changes\r\n documentIds.forEach((documentId) => {\r\n this.detectCommandChanges(documentId, newState);\r\n });\r\n }\r\n\r\n private detectCommandChanges(documentId: string, newState: StoreState<any>): void {\r\n // Skip if document isn't fully loaded yet\r\n const coreDoc = newState.core.documents[documentId];\r\n if (!coreDoc || coreDoc.status !== 'loaded') return;\r\n\r\n const previousCache = this.previousStates.get(documentId) ?? new Map();\r\n const changedCommandIds: string[] = [];\r\n\r\n this.commands.forEach((command, commandId) => {\r\n const newResolved = this.resolve(commandId, documentId);\r\n const prevResolved = previousCache.get(commandId);\r\n\r\n if (!prevResolved) {\r\n // First time resolving for this document\r\n previousCache.set(commandId, newResolved);\r\n return;\r\n }\r\n\r\n // Check for changes\r\n const changes: CommandStateChangedEvent['changes'] = {};\r\n\r\n if (prevResolved.active !== newResolved.active) {\r\n changes.active = newResolved.active;\r\n }\r\n if (prevResolved.disabled !== newResolved.disabled) {\r\n changes.disabled = newResolved.disabled;\r\n }\r\n if (prevResolved.visible !== newResolved.visible) {\r\n changes.visible = newResolved.visible;\r\n }\r\n if (prevResolved.label !== newResolved.label) {\r\n changes.label = newResolved.label;\r\n }\r\n if (prevResolved.icon !== newResolved.icon) {\r\n changes.icon = newResolved.icon;\r\n }\r\n if (!arePropsEqual(prevResolved.iconProps, newResolved.iconProps)) {\r\n changes.iconProps = newResolved.iconProps;\r\n }\r\n\r\n if (Object.keys(changes).length > 0) {\r\n changedCommandIds.push(commandId);\r\n previousCache.set(commandId, newResolved);\r\n\r\n this.commandStateChanged$.emit({\r\n commandId,\r\n documentId,\r\n changes,\r\n });\r\n }\r\n });\r\n\r\n this.previousStates.set(documentId, previousCache);\r\n }\r\n}\r\n","import { Reducer } from '@embedpdf/core';\r\nimport { CommandsState } from './types';\r\nimport { CommandsAction, SET_DISABLED_CATEGORIES } from './actions';\r\n\r\nexport const initialState: CommandsState = {\r\n disabledCategories: [],\r\n};\r\n\r\nexport const commandsReducer: Reducer<CommandsState, CommandsAction> = (\r\n state = initialState,\r\n action,\r\n) => {\r\n switch (action.type) {\r\n case SET_DISABLED_CATEGORIES:\r\n return {\r\n ...state,\r\n disabledCategories: action.payload,\r\n };\r\n\r\n default:\r\n return state;\r\n }\r\n};\r\n","import { PluginPackage } from '@embedpdf/core';\r\nimport { manifest, COMMANDS_PLUGIN_ID } from './manifest';\r\nimport { CommandsPluginConfig, CommandsState } from './types';\r\nimport { CommandsPlugin } from './commands-plugin';\r\nimport { CommandsAction } from './actions';\r\nimport { commandsReducer, initialState } from './reducer';\r\n\r\nexport const CommandsPluginPackage: PluginPackage<\r\n CommandsPlugin,\r\n CommandsPluginConfig,\r\n CommandsState,\r\n CommandsAction\r\n> = {\r\n manifest,\r\n create: (registry, config) => new CommandsPlugin(COMMANDS_PLUGIN_ID, registry, config),\r\n reducer: commandsReducer,\r\n initialState,\r\n};\r\n\r\nexport * from './commands-plugin';\r\nexport * from './types';\r\nexport * from './manifest';\r\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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"}
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.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';\r\nimport { CommandsPluginConfig } from './types';\r\n\r\nexport const COMMANDS_PLUGIN_ID = 'commands';\r\n\r\nexport const manifest: PluginManifest<CommandsPluginConfig> = {\r\n id: COMMANDS_PLUGIN_ID,\r\n name: 'Commands Plugin',\r\n version: '1.0.0',\r\n provides: ['commands'],\r\n requires: [],\r\n optional: ['i18n', 'ui'],\r\n defaultConfig: {\r\n commands: {},\r\n },\r\n};\r\n","import { Action } from '@embedpdf/core';\r\n\r\nexport const SET_DISABLED_CATEGORIES = 'COMMANDS/SET_DISABLED_CATEGORIES';\r\n\r\nexport interface SetDisabledCategoriesAction extends Action {\r\n type: typeof SET_DISABLED_CATEGORIES;\r\n payload: string[];\r\n}\r\n\r\nexport type CommandsAction = SetDisabledCategoriesAction;\r\n\r\nexport const setDisabledCategories = (categories: string[]): SetDisabledCategoriesAction => ({\r\n type: SET_DISABLED_CATEGORIES,\r\n payload: categories,\r\n});\r\n","import {\r\n BasePlugin,\r\n PluginRegistry,\r\n StoreState,\r\n createEmitter,\r\n createBehaviorEmitter,\r\n Listener,\r\n arePropsEqual,\r\n} from '@embedpdf/core';\r\nimport { Logger } from '@embedpdf/models';\r\nimport { I18nCapability, I18nPlugin } from '@embedpdf/plugin-i18n';\r\nimport {\r\n CommandsCapability,\r\n CommandsPluginConfig,\r\n CommandsState,\r\n Command,\r\n ResolvedCommand,\r\n CommandExecutedEvent,\r\n CommandStateChangedEvent,\r\n ShortcutExecutedEvent,\r\n CategoryChangedEvent,\r\n CommandScope,\r\n Dynamic,\r\n} from './types';\r\nimport { CommandsAction, setDisabledCategories } from './actions';\r\n\r\nexport class CommandsPlugin extends BasePlugin<\r\n CommandsPluginConfig,\r\n CommandsCapability,\r\n CommandsState,\r\n CommandsAction\r\n> {\r\n static readonly id = 'commands' as const;\r\n\r\n private commands = new Map<string, Command>();\r\n private i18n: I18nCapability | null = null;\r\n private shortcutMap = new Map<string, string>(); // shortcut -> commandId\r\n\r\n private readonly commandExecuted$ = createEmitter<CommandExecutedEvent>();\r\n private readonly commandStateChanged$ = createEmitter<CommandStateChangedEvent>();\r\n private readonly shortcutExecuted$ = createEmitter<ShortcutExecutedEvent>();\r\n private readonly categoryChanged$ = createBehaviorEmitter<CategoryChangedEvent>();\r\n\r\n // Cache previous resolved states per document to detect changes\r\n private previousStates = new Map<string, Map<string, ResolvedCommand>>();\r\n\r\n constructor(id: string, registry: PluginRegistry, config: CommandsPluginConfig) {\r\n super(id, registry);\r\n\r\n // Check if i18n plugin is available (optional dependency)\r\n const i18nPlugin = registry.getPlugin<I18nPlugin>('i18n');\r\n this.i18n = i18nPlugin?.provides() ?? null;\r\n\r\n // Initialize disabled categories from config\r\n if (config.disabledCategories?.length) {\r\n this.dispatch(setDisabledCategories(config.disabledCategories));\r\n }\r\n\r\n // Register all commands from config\r\n Object.values(config.commands).forEach((command) => {\r\n this.registerCommand(command);\r\n });\r\n\r\n // Subscribe to global store changes\r\n this.registry.getStore().subscribe((_action, newState) => {\r\n this.onGlobalStoreChange(newState);\r\n });\r\n }\r\n\r\n protected override onDocumentClosed(documentId: string): void {\r\n // Cleanup previous states cache\r\n this.previousStates.delete(documentId);\r\n\r\n this.logger.debug(\r\n 'CommandsPlugin',\r\n 'DocumentClosed',\r\n `Cleaned up command state cache for document: ${documentId}`,\r\n );\r\n }\r\n\r\n async initialize(): Promise<void> {\r\n this.logger.info('CommandsPlugin', 'Initialize', 'Commands plugin initialized');\r\n }\r\n\r\n async destroy(): Promise<void> {\r\n this.commandExecuted$.clear();\r\n this.commandStateChanged$.clear();\r\n this.shortcutExecuted$.clear();\r\n this.categoryChanged$.clear();\r\n this.commands.clear();\r\n this.shortcutMap.clear();\r\n this.previousStates.clear();\r\n super.destroy();\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Category Management\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private disableCategoryImpl(category: string): void {\r\n const current = new Set(this.state.disabledCategories);\r\n if (!current.has(category)) {\r\n current.add(category);\r\n this.dispatch(setDisabledCategories(Array.from(current)));\r\n this.categoryChanged$.emit({ disabledCategories: Array.from(current) });\r\n }\r\n }\r\n\r\n private enableCategoryImpl(category: string): void {\r\n const current = new Set(this.state.disabledCategories);\r\n if (current.has(category)) {\r\n current.delete(category);\r\n this.dispatch(setDisabledCategories(Array.from(current)));\r\n this.categoryChanged$.emit({ disabledCategories: Array.from(current) });\r\n }\r\n }\r\n\r\n private toggleCategoryImpl(category: string): void {\r\n if (this.state.disabledCategories.includes(category)) {\r\n this.enableCategoryImpl(category);\r\n } else {\r\n this.disableCategoryImpl(category);\r\n }\r\n }\r\n\r\n private setDisabledCategoriesImpl(categories: string[]): void {\r\n this.dispatch(setDisabledCategories(categories));\r\n this.categoryChanged$.emit({ disabledCategories: categories });\r\n }\r\n\r\n /**\r\n * Check if command has any disabled category\r\n */\r\n private isCommandCategoryDisabled(command: Command): boolean {\r\n if (!command.categories?.length) return false;\r\n return command.categories.some((cat) => this.state.disabledCategories.includes(cat));\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Capability\r\n // ─────────────────────────────────────────────────────────\r\n\r\n protected buildCapability(): CommandsCapability {\r\n return {\r\n resolve: (commandId, documentId) => this.resolve(commandId, documentId),\r\n execute: (commandId, documentId, source = 'ui') =>\r\n this.execute(commandId, documentId, source),\r\n getAllCommands: (documentId) => this.getAllCommands(documentId),\r\n getCommandsByCategory: (category, documentId) =>\r\n this.getCommandsByCategory(category, documentId),\r\n getCommandByShortcut: (shortcut) => this.getCommandByShortcut(shortcut),\r\n getAllShortcuts: () => new Map(this.shortcutMap),\r\n forDocument: (documentId) => this.createCommandScope(documentId),\r\n registerCommand: (command) => this.registerCommand(command),\r\n unregisterCommand: (commandId) => this.unregisterCommand(commandId),\r\n\r\n // Category management\r\n disableCategory: (category) => this.disableCategoryImpl(category),\r\n enableCategory: (category) => this.enableCategoryImpl(category),\r\n toggleCategory: (category) => this.toggleCategoryImpl(category),\r\n setDisabledCategories: (categories) => this.setDisabledCategoriesImpl(categories),\r\n getDisabledCategories: () => this.state.disabledCategories,\r\n isCategoryDisabled: (category) => this.state.disabledCategories.includes(category),\r\n\r\n // Events\r\n onCommandExecuted: this.commandExecuted$.on,\r\n onCommandStateChanged: this.commandStateChanged$.on,\r\n onShortcutExecuted: this.shortcutExecuted$.on,\r\n onCategoryChanged: this.categoryChanged$.on,\r\n };\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Document Scoping\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private createCommandScope(documentId: string): CommandScope {\r\n return {\r\n resolve: (commandId) => this.resolve(commandId, documentId),\r\n execute: (commandId, source = 'ui') => this.execute(commandId, documentId, source),\r\n getAllCommands: () => this.getAllCommands(documentId),\r\n getCommandsByCategory: (category) => this.getCommandsByCategory(category, documentId),\r\n onCommandStateChanged: (listener: Listener<Omit<CommandStateChangedEvent, 'documentId'>>) =>\r\n this.commandStateChanged$.on((event) => {\r\n if (event.documentId === documentId) {\r\n const { documentId: _, ...rest } = event;\r\n listener(rest);\r\n }\r\n }),\r\n };\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Command Resolution\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private resolve(commandId: string, documentId?: string): ResolvedCommand {\r\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\r\n\r\n const command = this.commands.get(commandId);\r\n if (!command) {\r\n throw new Error(`Command not found: ${commandId}`);\r\n }\r\n\r\n const state = this.registry.getStore().getState();\r\n\r\n // Resolve label with i18n if available\r\n const label = this.resolveLabel(command, state, resolvedDocId);\r\n\r\n // Resolve shortcuts\r\n const shortcuts = command.shortcuts\r\n ? Array.isArray(command.shortcuts)\r\n ? command.shortcuts\r\n : [command.shortcuts]\r\n : undefined;\r\n\r\n // Check if disabled via categories OR explicit disabled predicate\r\n const explicitDisabled = this.resolveDynamic(command.disabled, state, resolvedDocId) ?? false;\r\n const categoryDisabled = this.isCommandCategoryDisabled(command);\r\n const isDisabled = explicitDisabled || categoryDisabled;\r\n\r\n return {\r\n id: command.id,\r\n label,\r\n icon: this.resolveDynamic(command.icon, state, resolvedDocId),\r\n iconProps: this.resolveDynamic(command.iconProps, state, resolvedDocId),\r\n active: this.resolveDynamic(command.active, state, resolvedDocId) ?? false,\r\n disabled: isDisabled,\r\n visible: this.resolveDynamic(command.visible, state, resolvedDocId) ?? true,\r\n shortcuts,\r\n shortcutLabel: command.shortcutLabel,\r\n categories: command.categories,\r\n description: command.description,\r\n execute: () =>\r\n command.action({\r\n registry: this.registry,\r\n state,\r\n documentId: resolvedDocId,\r\n logger: this.logger,\r\n }),\r\n };\r\n }\r\n\r\n private resolveLabel(command: Command, state: StoreState<any>, documentId: string): string {\r\n // Priority: labelKey (with i18n) > label (plain string) > id (fallback)\r\n const labelKey = this.resolveDynamic(command.labelKey, state, documentId);\r\n if (labelKey && this.i18n) {\r\n const params = this.resolveDynamic(command.labelParams, state, documentId);\r\n return this.i18n.t(labelKey, { params, documentId });\r\n }\r\n\r\n if (command.label) {\r\n return command.label;\r\n }\r\n\r\n return command.id; // Fallback to ID\r\n }\r\n\r\n private resolveDynamic<T>(\r\n value: Dynamic<any, T> | undefined,\r\n state: StoreState<any>,\r\n documentId: string,\r\n ): T | undefined {\r\n if (value === undefined) return undefined;\r\n\r\n // Check if it's a function (the dynamic evaluator)\r\n if (typeof value === 'function') {\r\n return (\r\n value as (context: {\r\n registry: PluginRegistry;\r\n state: StoreState<any>;\r\n documentId: string;\r\n logger: Logger;\r\n }) => T\r\n )({\r\n registry: this.registry,\r\n state,\r\n documentId,\r\n logger: this.logger,\r\n });\r\n }\r\n\r\n // Otherwise it's the static value\r\n return value as T;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Command Execution\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private execute(\r\n commandId: string,\r\n documentId?: string,\r\n source: 'keyboard' | 'ui' | 'api' = 'ui',\r\n ): void {\r\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\r\n const resolved = this.resolve(commandId, resolvedDocId);\r\n\r\n if (resolved.disabled) {\r\n this.logger.warn(\r\n 'CommandsPlugin',\r\n 'ExecutionBlocked',\r\n `Command '${commandId}' is disabled for document '${resolvedDocId}'`,\r\n );\r\n return;\r\n }\r\n\r\n if (!resolved.visible) {\r\n this.logger.warn(\r\n 'CommandsPlugin',\r\n 'ExecutionBlocked',\r\n `Command '${commandId}' is not visible for document '${resolvedDocId}'`,\r\n );\r\n return;\r\n }\r\n\r\n resolved.execute();\r\n\r\n this.commandExecuted$.emit({\r\n commandId,\r\n documentId: resolvedDocId,\r\n source,\r\n });\r\n\r\n this.logger.debug(\r\n 'CommandsPlugin',\r\n 'CommandExecuted',\r\n `Command '${commandId}' executed for document '${resolvedDocId}' (source: ${source})`,\r\n );\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Command Registration\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private registerCommand(command: Command): void {\r\n if (this.commands.has(command.id)) {\r\n this.logger.warn(\r\n 'CommandsPlugin',\r\n 'CommandOverwrite',\r\n `Command '${command.id}' already exists and will be overwritten`,\r\n );\r\n }\r\n\r\n this.commands.set(command.id, command);\r\n\r\n // Register shortcuts\r\n if (command.shortcuts) {\r\n const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];\r\n\r\n shortcuts.forEach((shortcut) => {\r\n const normalized = this.normalizeShortcut(shortcut);\r\n this.shortcutMap.set(normalized, command.id);\r\n });\r\n }\r\n\r\n this.logger.debug('CommandsPlugin', 'CommandRegistered', `Command '${command.id}' registered`);\r\n }\r\n\r\n private unregisterCommand(commandId: string): void {\r\n const command = this.commands.get(commandId);\r\n if (!command) return;\r\n\r\n // Remove shortcuts\r\n if (command.shortcuts) {\r\n const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];\r\n\r\n shortcuts.forEach((shortcut) => {\r\n const normalized = this.normalizeShortcut(shortcut);\r\n this.shortcutMap.delete(normalized);\r\n });\r\n }\r\n\r\n this.commands.delete(commandId);\r\n this.logger.debug(\r\n 'CommandsPlugin',\r\n 'CommandUnregistered',\r\n `Command '${commandId}' unregistered`,\r\n );\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Shortcuts\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private getCommandByShortcut(shortcut: string): Command | null {\r\n const normalized = this.normalizeShortcut(shortcut);\r\n const commandId = this.shortcutMap.get(normalized);\r\n return commandId ? (this.commands.get(commandId) ?? null) : null;\r\n }\r\n\r\n private normalizeShortcut(shortcut: string): string {\r\n // Normalize: \"Ctrl+Shift+A\" -> \"ctrl+shift+a\"\r\n return shortcut.toLowerCase().split('+').sort().join('+');\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // Query Methods\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private getAllCommands(documentId?: string): ResolvedCommand[] {\r\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\r\n return Array.from(this.commands.keys()).map((id) => this.resolve(id, resolvedDocId));\r\n }\r\n\r\n private getCommandsByCategory(category: string, documentId?: string): ResolvedCommand[] {\r\n const resolvedDocId = documentId ?? this.getActiveDocumentId();\r\n return Array.from(this.commands.values())\r\n .filter((cmd) => cmd.categories?.includes(category))\r\n .map((cmd) => this.resolve(cmd.id, resolvedDocId));\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────\r\n // State Change Detection\r\n // ─────────────────────────────────────────────────────────\r\n\r\n private onGlobalStoreChange(newState: StoreState<any>): void {\r\n // Get all documents from core state\r\n const documentIds = Object.keys(newState.core.documents);\r\n\r\n // Check each document for command state changes\r\n documentIds.forEach((documentId) => {\r\n this.detectCommandChanges(documentId, newState);\r\n });\r\n }\r\n\r\n private detectCommandChanges(documentId: string, newState: StoreState<any>): void {\r\n // Skip if document isn't fully loaded yet\r\n const coreDoc = newState.core.documents[documentId];\r\n if (!coreDoc || coreDoc.status !== 'loaded') return;\r\n\r\n const previousCache = this.previousStates.get(documentId) ?? new Map();\r\n const changedCommandIds: string[] = [];\r\n\r\n this.commands.forEach((command, commandId) => {\r\n const newResolved = this.resolve(commandId, documentId);\r\n const prevResolved = previousCache.get(commandId);\r\n\r\n if (!prevResolved) {\r\n // First time resolving for this document\r\n previousCache.set(commandId, newResolved);\r\n return;\r\n }\r\n\r\n // Check for changes\r\n const changes: CommandStateChangedEvent['changes'] = {};\r\n\r\n if (prevResolved.active !== newResolved.active) {\r\n changes.active = newResolved.active;\r\n }\r\n if (prevResolved.disabled !== newResolved.disabled) {\r\n changes.disabled = newResolved.disabled;\r\n }\r\n if (prevResolved.visible !== newResolved.visible) {\r\n changes.visible = newResolved.visible;\r\n }\r\n if (prevResolved.label !== newResolved.label) {\r\n changes.label = newResolved.label;\r\n }\r\n if (prevResolved.icon !== newResolved.icon) {\r\n changes.icon = newResolved.icon;\r\n }\r\n if (!arePropsEqual(prevResolved.iconProps, newResolved.iconProps)) {\r\n changes.iconProps = newResolved.iconProps;\r\n }\r\n\r\n if (Object.keys(changes).length > 0) {\r\n changedCommandIds.push(commandId);\r\n previousCache.set(commandId, newResolved);\r\n\r\n this.commandStateChanged$.emit({\r\n commandId,\r\n documentId,\r\n changes,\r\n });\r\n }\r\n });\r\n\r\n this.previousStates.set(documentId, previousCache);\r\n }\r\n}\r\n","import { Reducer } from '@embedpdf/core';\r\nimport { CommandsState } from './types';\r\nimport { CommandsAction, SET_DISABLED_CATEGORIES } from './actions';\r\n\r\nexport const initialState: CommandsState = {\r\n disabledCategories: [],\r\n};\r\n\r\nexport const commandsReducer: Reducer<CommandsState, CommandsAction> = (\r\n state = initialState,\r\n action,\r\n) => {\r\n switch (action.type) {\r\n case SET_DISABLED_CATEGORIES:\r\n return {\r\n ...state,\r\n disabledCategories: action.payload,\r\n };\r\n\r\n default:\r\n return state;\r\n }\r\n};\r\n","import { PluginPackage } from '@embedpdf/core';\r\nimport { manifest, COMMANDS_PLUGIN_ID } from './manifest';\r\nimport { CommandsPluginConfig, CommandsState } from './types';\r\nimport { CommandsPlugin } from './commands-plugin';\r\nimport { CommandsAction } from './actions';\r\nimport { commandsReducer, initialState } from './reducer';\r\n\r\nexport const CommandsPluginPackage: PluginPackage<\r\n CommandsPlugin,\r\n CommandsPluginConfig,\r\n CommandsState,\r\n CommandsAction\r\n> = {\r\n manifest,\r\n create: (registry, config) => new CommandsPlugin(COMMANDS_PLUGIN_ID, registry, config),\r\n reducer: commandsReducer,\r\n initialState,\r\n};\r\n\r\nexport * from './commands-plugin';\r\nexport * from './types';\r\nexport * from './manifest';\r\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 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/utils/keyboard-handler.ts","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\r\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\r\nimport { useState, useEffect } from '@framework';\r\n\r\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\r\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\r\n\r\n/**\r\n * Hook to get a reactive command for a specific document\r\n * Automatically updates when command state changes\r\n * @param commandId Command ID\r\n * @param documentId Document ID\r\n * @returns ResolvedCommand or null if not available\r\n */\r\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\r\n const { provides } = useCommandsCapability();\r\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\r\n provides ? provides.resolve(commandId, documentId) : null,\r\n );\r\n\r\n useEffect(() => {\r\n if (!provides) {\r\n setCommand(null);\r\n return;\r\n }\r\n\r\n // Initial resolve\r\n setCommand(provides.resolve(commandId, documentId));\r\n\r\n // Subscribe to state changes for this command + document\r\n const unsubscribe = provides.onCommandStateChanged((event) => {\r\n if (event.commandId === commandId && event.documentId === documentId) {\r\n setCommand(provides.resolve(commandId, documentId));\r\n }\r\n });\r\n\r\n return unsubscribe;\r\n }, [provides, commandId, documentId]);\r\n\r\n return command;\r\n};\r\n\r\n/**\r\n * Hook to execute a command\r\n */\r\nexport const useCommandExecutor = (documentId: string) => {\r\n const { provides } = useCommandsCapability();\r\n\r\n return (commandId: string) => {\r\n if (provides) {\r\n provides.execute(commandId, documentId, 'ui');\r\n }\r\n };\r\n};\r\n","import { useEffect } from '@framework';\r\nimport { useCommandsCapability } from '../hooks';\r\nimport { createKeyDownHandler } from '../utils';\r\n\r\n/**\r\n * Utility component that listens to keyboard events\r\n * and executes commands based on shortcuts.\r\n * This component doesn't render anything, it just sets up keyboard shortcuts.\r\n */\r\nexport function KeyboardShortcuts() {\r\n const { provides: commands } = useCommandsCapability();\r\n\r\n useEffect(() => {\r\n if (!commands) return;\r\n\r\n const handleKeyDown = createKeyDownHandler(commands);\r\n\r\n document.addEventListener('keydown', handleKeyDown);\r\n return () => document.removeEventListener('keydown', handleKeyDown);\r\n }, [commands]);\r\n\r\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\r\n return null;\r\n}\r\n","import { CommandsCapability } from '../../lib/types';\r\n\r\n/**\r\n * Build a shortcut string from a keyboard event\r\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\r\n */\r\nexport function buildShortcutString(event: KeyboardEvent): string | null {\r\n const modifiers: string[] = [];\r\n\r\n if (event.ctrlKey) modifiers.push('ctrl');\r\n if (event.shiftKey) modifiers.push('shift');\r\n if (event.altKey) modifiers.push('alt');\r\n if (event.metaKey) modifiers.push('meta');\r\n\r\n // Only add non-modifier keys\r\n let key = event.key.toLowerCase();\r\n if (key === ' ') key = 'space';\r\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\r\n\r\n if (isModifier) {\r\n return null; // Just a modifier, no command\r\n }\r\n\r\n const parts = [...modifiers, key];\r\n return parts.sort().join('+');\r\n}\r\n\r\n/**\r\n * Handle keyboard events and execute commands based on shortcuts\r\n */\r\nexport function createKeyDownHandler(commands: CommandsCapability) {\r\n return (event: KeyboardEvent) => {\r\n // Use composedPath to get the actual target element, even inside Shadow DOM\r\n const composedPath = event.composedPath();\r\n const target = (composedPath[0] || event.target) as HTMLElement;\r\n\r\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\r\n // Exception: allow Tab/Shift+Tab through for form field navigation\r\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\r\n if (event.key !== 'Tab') return;\r\n }\r\n\r\n const shortcut = buildShortcutString(event);\r\n if (!shortcut) return;\r\n\r\n const command = commands.getCommandByShortcut(shortcut);\r\n if (!command) return;\r\n\r\n // Resolve without document ID - will use active document\r\n const resolved = commands.resolve(command.id);\r\n\r\n if (resolved.disabled || !resolved.visible) {\r\n return;\r\n }\r\n\r\n // Execute and prevent default (documentId is optional now)\r\n event.preventDefault();\r\n event.stopPropagation();\r\n commands.execute(command.id, undefined, 'keyboard');\r\n };\r\n}\r\n","import { createPluginPackage } from '@embedpdf/core';\r\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\r\n\r\nimport { KeyboardShortcuts } from './components';\r\n\r\nexport * from './hooks';\r\nexport * from './components';\r\nexport * from '@embedpdf/plugin-commands';\r\n\r\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\r\n .addUtility(KeyboardShortcuts)\r\n .build();\r\n"],"names":["useCommandsCapability","useCapability","CommandsPlugin","id","KeyboardShortcuts","provides","commands","useEffect","handleKeyDown","event","target","composedPath","tagName","isContentEditable","key","shortcut","modifiers","ctrlKey","push","shiftKey","altKey","metaKey","toLowerCase","includes","sort","join","buildShortcutString","command","getCommandByShortcut","resolved","resolve","disabled","visible","preventDefault","stopPropagation","execute","createKeyDownHandler","document","addEventListener","removeEventListener","CommandsPluginPackage","createPluginPackage","BaseCommandsPackage","addUtility","build","commandId","documentId","setCommand","useState","onCommandStateChanged","usePlugin"],"mappings":"8MAIaA,EAAwB,IAAMC,gBAA8BC,EAAAA,eAAeC,ICKjF,SAASC,IACd,MAAQC,SAAUC,GAAaN,IAY/B,OAVAO,EAAAA,UAAU,KACR,IAAKD,EAAU,OAEf,MAAME,ECeH,SAA8BF,GACnC,OAAQG,IAEN,MACMC,EADeD,EAAME,eACE,IAAMF,EAAMC,OAIzC,IAAuB,UAAnBA,EAAOE,SAA0C,aAAnBF,EAAOE,SAA0BF,EAAOG,oBACtD,QAAdJ,EAAMK,IAAe,OAG3B,MAAMC,EApCH,SAA6BN,GAClC,MAAMO,EAAsB,GAExBP,EAAMQ,SAASD,EAAUE,KAAK,QAC9BT,EAAMU,UAAUH,EAAUE,KAAK,SAC/BT,EAAMW,QAAQJ,EAAUE,KAAK,OAC7BT,EAAMY,SAASL,EAAUE,KAAK,QAGlC,IAAIJ,EAAML,EAAMK,IAAIQ,cAIpB,MAHY,MAARR,IAAaA,EAAM,SACJ,CAAC,UAAW,QAAS,MAAO,QAAQS,SAAST,GAGvD,KAGK,IAAIE,EAAWF,GAChBU,OAAOC,KAAK,IAC3B,CAiBqBC,CAAoBjB,GACrC,IAAKM,EAAU,OAEf,MAAMY,EAAUrB,EAASsB,qBAAqBb,GAC9C,IAAKY,EAAS,OAGd,MAAME,EAAWvB,EAASwB,QAAQH,EAAQxB,KAEtC0B,EAASE,UAAaF,EAASG,UAKnCvB,EAAMwB,iBACNxB,EAAMyB,kBACN5B,EAAS6B,QAAQR,EAAQxB,QAAI,EAAW,aAE5C,CD7C0BiC,CAAqB9B,GAG3C,OADA+B,SAASC,iBAAiB,UAAW9B,GAC9B,IAAM6B,SAASE,oBAAoB,UAAW/B,IACpD,CAACF,IAGG,IACT,CEdO,MAAMkC,EAAwBC,EAAAA,oBAAoBC,EAAAA,uBACtDC,WAAWvC,GACXwC,uFHGuB,CAACC,EAAmBC,KAC5C,MAAMzC,SAAEA,GAAaL,KACd2B,EAASoB,GAAcC,EAAAA,SAAiC,IAC7D3C,EAAWA,EAASyB,QAAQe,EAAWC,GAAc,MAsBvD,OAnBAvC,EAAAA,UAAU,KACR,IAAKF,EAEH,YADA0C,EAAW,MAKbA,EAAW1C,EAASyB,QAAQe,EAAWC,IASvC,OANoBzC,EAAS4C,sBAAuBxC,IAC9CA,EAAMoC,YAAcA,GAAapC,EAAMqC,aAAeA,GACxDC,EAAW1C,EAASyB,QAAQe,EAAWC,OAK1C,CAACzC,EAAUwC,EAAWC,IAElBnB,8BAM0BmB,IACjC,MAAMzC,SAAEA,GAAaL,IAErB,OAAQ6C,IACFxC,GACFA,EAAS8B,QAAQU,EAAWC,EAAY,kEA7Cb,IAAMI,YAA0BhD,EAAAA,eAAeC"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/utils/keyboard-handler.ts","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\nimport { useState, useEffect } from '@framework';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * Automatically updates when command state changes\n * @param commandId Command ID\n * @param documentId Document ID\n * @returns ResolvedCommand or null if not available\n */\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\n const { provides } = useCommandsCapability();\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\n provides ? provides.resolve(commandId, documentId) : null,\n );\n\n useEffect(() => {\n if (!provides) {\n setCommand(null);\n return;\n }\n\n // Initial resolve\n setCommand(provides.resolve(commandId, documentId));\n\n // Subscribe to state changes for this command + document\n const unsubscribe = provides.onCommandStateChanged((event) => {\n if (event.commandId === commandId && event.documentId === documentId) {\n setCommand(provides.resolve(commandId, documentId));\n }\n });\n\n return unsubscribe;\n }, [provides, commandId, documentId]);\n\n return command;\n};\n\n/**\n * Hook to execute a command\n */\nexport const useCommandExecutor = (documentId: string) => {\n const { provides } = useCommandsCapability();\n\n return (commandId: string) => {\n if (provides) {\n provides.execute(commandId, documentId, 'ui');\n }\n };\n};\n","import { useEffect } from '@framework';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../utils';\n\n/**\n * Utility component that listens to keyboard events\n * and executes commands based on shortcuts.\n * This component doesn't render anything, it just sets up keyboard shortcuts.\n */\nexport function KeyboardShortcuts() {\n const { provides: commands } = useCommandsCapability();\n\n useEffect(() => {\n if (!commands) return;\n\n const handleKeyDown = createKeyDownHandler(commands);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [commands]);\n\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\n return null;\n}\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n let key = event.key.toLowerCase();\n if (key === ' ') key = 'space';\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 // Exception: allow Tab/Shift+Tab through for form field navigation\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n if (event.key !== 'Tab') return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["useCommandsCapability","useCapability","CommandsPlugin","id","KeyboardShortcuts","provides","commands","useEffect","handleKeyDown","event","target","composedPath","tagName","isContentEditable","key","shortcut","modifiers","ctrlKey","push","shiftKey","altKey","metaKey","toLowerCase","includes","sort","join","buildShortcutString","command","getCommandByShortcut","resolved","resolve","disabled","visible","preventDefault","stopPropagation","execute","createKeyDownHandler","document","addEventListener","removeEventListener","CommandsPluginPackage","createPluginPackage","BaseCommandsPackage","addUtility","build","commandId","documentId","setCommand","useState","onCommandStateChanged","usePlugin"],"mappings":"8MAIaA,EAAwB,IAAMC,gBAA8BC,EAAAA,eAAeC,ICKjF,SAASC,IACd,MAAQC,SAAUC,GAAaN,IAY/B,OAVAO,EAAAA,UAAU,KACR,IAAKD,EAAU,OAEf,MAAME,ECeH,SAA8BF,GACnC,OAAQG,IAEN,MACMC,EADeD,EAAME,eACE,IAAMF,EAAMC,OAIzC,IAAuB,UAAnBA,EAAOE,SAA0C,aAAnBF,EAAOE,SAA0BF,EAAOG,oBACtD,QAAdJ,EAAMK,IAAe,OAG3B,MAAMC,EApCH,SAA6BN,GAClC,MAAMO,EAAsB,GAExBP,EAAMQ,SAASD,EAAUE,KAAK,QAC9BT,EAAMU,UAAUH,EAAUE,KAAK,SAC/BT,EAAMW,QAAQJ,EAAUE,KAAK,OAC7BT,EAAMY,SAASL,EAAUE,KAAK,QAGlC,IAAIJ,EAAML,EAAMK,IAAIQ,cAIpB,MAHY,MAARR,IAAaA,EAAM,SACJ,CAAC,UAAW,QAAS,MAAO,QAAQS,SAAST,GAGvD,KAGK,IAAIE,EAAWF,GAChBU,OAAOC,KAAK,IAC3B,CAiBqBC,CAAoBjB,GACrC,IAAKM,EAAU,OAEf,MAAMY,EAAUrB,EAASsB,qBAAqBb,GAC9C,IAAKY,EAAS,OAGd,MAAME,EAAWvB,EAASwB,QAAQH,EAAQxB,KAEtC0B,EAASE,UAAaF,EAASG,UAKnCvB,EAAMwB,iBACNxB,EAAMyB,kBACN5B,EAAS6B,QAAQR,EAAQxB,QAAI,EAAW,aAE5C,CD7C0BiC,CAAqB9B,GAG3C,OADA+B,SAASC,iBAAiB,UAAW9B,GAC9B,IAAM6B,SAASE,oBAAoB,UAAW/B,IACpD,CAACF,IAGG,IACT,CEdO,MAAMkC,EAAwBC,EAAAA,oBAAoBC,EAAAA,uBACtDC,WAAWvC,GACXwC,uFHGuB,CAACC,EAAmBC,KAC5C,MAAMzC,SAAEA,GAAaL,KACd2B,EAASoB,GAAcC,EAAAA,SAAiC,IAC7D3C,EAAWA,EAASyB,QAAQe,EAAWC,GAAc,MAsBvD,OAnBAvC,EAAAA,UAAU,KACR,IAAKF,EAEH,YADA0C,EAAW,MAKbA,EAAW1C,EAASyB,QAAQe,EAAWC,IASvC,OANoBzC,EAAS4C,sBAAuBxC,IAC9CA,EAAMoC,YAAcA,GAAapC,EAAMqC,aAAeA,GACxDC,EAAW1C,EAASyB,QAAQe,EAAWC,OAK1C,CAACzC,EAAUwC,EAAWC,IAElBnB,8BAM0BmB,IACjC,MAAMzC,SAAEA,GAAaL,IAErB,OAAQ6C,IACFxC,GACFA,EAAS8B,QAAQU,EAAWC,EAAY,kEA7Cb,IAAMI,YAA0BhD,EAAAA,eAAeC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/utils/keyboard-handler.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\r\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\r\nimport { useState, useEffect } from '@framework';\r\n\r\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\r\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\r\n\r\n/**\r\n * Hook to get a reactive command for a specific document\r\n * Automatically updates when command state changes\r\n * @param commandId Command ID\r\n * @param documentId Document ID\r\n * @returns ResolvedCommand or null if not available\r\n */\r\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\r\n const { provides } = useCommandsCapability();\r\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\r\n provides ? provides.resolve(commandId, documentId) : null,\r\n );\r\n\r\n useEffect(() => {\r\n if (!provides) {\r\n setCommand(null);\r\n return;\r\n }\r\n\r\n // Initial resolve\r\n setCommand(provides.resolve(commandId, documentId));\r\n\r\n // Subscribe to state changes for this command + document\r\n const unsubscribe = provides.onCommandStateChanged((event) => {\r\n if (event.commandId === commandId && event.documentId === documentId) {\r\n setCommand(provides.resolve(commandId, documentId));\r\n }\r\n });\r\n\r\n return unsubscribe;\r\n }, [provides, commandId, documentId]);\r\n\r\n return command;\r\n};\r\n\r\n/**\r\n * Hook to execute a command\r\n */\r\nexport const useCommandExecutor = (documentId: string) => {\r\n const { provides } = useCommandsCapability();\r\n\r\n return (commandId: string) => {\r\n if (provides) {\r\n provides.execute(commandId, documentId, 'ui');\r\n }\r\n };\r\n};\r\n","import { CommandsCapability } from '../../lib/types';\r\n\r\n/**\r\n * Build a shortcut string from a keyboard event\r\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\r\n */\r\nexport function buildShortcutString(event: KeyboardEvent): string | null {\r\n const modifiers: string[] = [];\r\n\r\n if (event.ctrlKey) modifiers.push('ctrl');\r\n if (event.shiftKey) modifiers.push('shift');\r\n if (event.altKey) modifiers.push('alt');\r\n if (event.metaKey) modifiers.push('meta');\r\n\r\n // Only add non-modifier keys\r\n let key = event.key.toLowerCase();\r\n if (key === ' ') key = 'space';\r\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\r\n\r\n if (isModifier) {\r\n return null; // Just a modifier, no command\r\n }\r\n\r\n const parts = [...modifiers, key];\r\n return parts.sort().join('+');\r\n}\r\n\r\n/**\r\n * Handle keyboard events and execute commands based on shortcuts\r\n */\r\nexport function createKeyDownHandler(commands: CommandsCapability) {\r\n return (event: KeyboardEvent) => {\r\n // Use composedPath to get the actual target element, even inside Shadow DOM\r\n const composedPath = event.composedPath();\r\n const target = (composedPath[0] || event.target) as HTMLElement;\r\n\r\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\r\n // Exception: allow Tab/Shift+Tab through for form field navigation\r\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\r\n if (event.key !== 'Tab') return;\r\n }\r\n\r\n const shortcut = buildShortcutString(event);\r\n if (!shortcut) return;\r\n\r\n const command = commands.getCommandByShortcut(shortcut);\r\n if (!command) return;\r\n\r\n // Resolve without document ID - will use active document\r\n const resolved = commands.resolve(command.id);\r\n\r\n if (resolved.disabled || !resolved.visible) {\r\n return;\r\n }\r\n\r\n // Execute and prevent default (documentId is optional now)\r\n event.preventDefault();\r\n event.stopPropagation();\r\n commands.execute(command.id, undefined, 'keyboard');\r\n };\r\n}\r\n","import { useEffect } from '@framework';\r\nimport { useCommandsCapability } from '../hooks';\r\nimport { createKeyDownHandler } from '../utils';\r\n\r\n/**\r\n * Utility component that listens to keyboard events\r\n * and executes commands based on shortcuts.\r\n * This component doesn't render anything, it just sets up keyboard shortcuts.\r\n */\r\nexport function KeyboardShortcuts() {\r\n const { provides: commands } = useCommandsCapability();\r\n\r\n useEffect(() => {\r\n if (!commands) return;\r\n\r\n const handleKeyDown = createKeyDownHandler(commands);\r\n\r\n document.addEventListener('keydown', handleKeyDown);\r\n return () => document.removeEventListener('keydown', handleKeyDown);\r\n }, [commands]);\r\n\r\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\r\n return null;\r\n}\r\n","import { createPluginPackage } from '@embedpdf/core';\r\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\r\n\r\nimport { KeyboardShortcuts } from './components';\r\n\r\nexport * from './hooks';\r\nexport * from './components';\r\nexport * from '@embedpdf/plugin-commands';\r\n\r\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\r\n .addUtility(KeyboardShortcuts)\r\n .build();\r\n"],"names":["BaseCommandsPackage"],"mappings":";;;;;AAIO,MAAM,wBAAwB,MAAM,cAA8B,eAAe,EAAE;AACnF,MAAM,oBAAoB,MAAM,UAA0B,eAAe,EAAE;AAS3E,MAAM,aAAa,CAAC,WAAmB,eAA+C;AAC3F,QAAM,EAAE,SAAA,IAAa,sBAAA;AACrB,QAAM,CAAC,SAAS,UAAU,IAAI;AAAA,IAAiC,MAC7D,WAAW,SAAS,QAAQ,WAAW,UAAU,IAAI;AAAA,EAAA;AAGvD,YAAU,MAAM;AACd,QAAI,CAAC,UAAU;AACb,iBAAW,IAAI;AACf;AAAA,IACF;AAGA,eAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAGlD,UAAM,cAAc,SAAS,sBAAsB,CAAC,UAAU;AAC5D,UAAI,MAAM,cAAc,aAAa,MAAM,eAAe,YAAY;AACpE,mBAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAAA,MACpD;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,WAAW,UAAU,CAAC;AAEpC,SAAO;AACT;AAKO,MAAM,qBAAqB,CAAC,eAAuB;AACxD,QAAM,EAAE,SAAA,IAAa,sBAAA;AAErB,SAAO,CAAC,cAAsB;AAC5B,QAAI,UAAU;AACZ,eAAS,QAAQ,WAAW,YAAY,IAAI;AAAA,IAC9C;AAAA,EACF;AACF;AC/CO,SAAS,oBAAoB,OAAqC;AACvE,QAAM,YAAsB,CAAA;AAE5B,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AACxC,MAAI,MAAM,SAAU,WAAU,KAAK,OAAO;AAC1C,MAAI,MAAM,OAAQ,WAAU,KAAK,KAAK;AACtC,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AAGxC,MAAI,MAAM,MAAM,IAAI,YAAA;AACpB,MAAI,QAAQ,IAAK,OAAM;AACvB,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;AAIzC,QAAI,OAAO,YAAY,WAAW,OAAO,YAAY,cAAc,OAAO,mBAAmB;AAC3F,UAAI,MAAM,QAAQ,MAAO;AAAA,IAC3B;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;ACnDO,SAAS,oBAAoB;AAClC,QAAM,EAAE,UAAU,SAAA,IAAa,sBAAA;AAE/B,YAAU,MAAM;AACd,QAAI,CAAC,SAAU;AAEf,UAAM,gBAAgB,qBAAqB,QAAQ;AAEnD,aAAS,iBAAiB,WAAW,aAAa;AAClD,WAAO,MAAM,SAAS,oBAAoB,WAAW,aAAa;AAAA,EACpE,GAAG,CAAC,QAAQ,CAAC;AAGb,SAAO;AACT;ACdO,MAAM,wBAAwB,oBAAoBA,uBAAmB,EACzE,WAAW,iBAAiB,EAC5B,MAAA;"}
1
+ {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/utils/keyboard-handler.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\nimport { useState, useEffect } from '@framework';\n\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\n\n/**\n * Hook to get a reactive command for a specific document\n * Automatically updates when command state changes\n * @param commandId Command ID\n * @param documentId Document ID\n * @returns ResolvedCommand or null if not available\n */\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\n const { provides } = useCommandsCapability();\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\n provides ? provides.resolve(commandId, documentId) : null,\n );\n\n useEffect(() => {\n if (!provides) {\n setCommand(null);\n return;\n }\n\n // Initial resolve\n setCommand(provides.resolve(commandId, documentId));\n\n // Subscribe to state changes for this command + document\n const unsubscribe = provides.onCommandStateChanged((event) => {\n if (event.commandId === commandId && event.documentId === documentId) {\n setCommand(provides.resolve(commandId, documentId));\n }\n });\n\n return unsubscribe;\n }, [provides, commandId, documentId]);\n\n return command;\n};\n\n/**\n * Hook to execute a command\n */\nexport const useCommandExecutor = (documentId: string) => {\n const { provides } = useCommandsCapability();\n\n return (commandId: string) => {\n if (provides) {\n provides.execute(commandId, documentId, 'ui');\n }\n };\n};\n","import { CommandsCapability } from '../../lib/types';\n\n/**\n * Build a shortcut string from a keyboard event\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\n */\nexport function buildShortcutString(event: KeyboardEvent): string | null {\n const modifiers: string[] = [];\n\n if (event.ctrlKey) modifiers.push('ctrl');\n if (event.shiftKey) modifiers.push('shift');\n if (event.altKey) modifiers.push('alt');\n if (event.metaKey) modifiers.push('meta');\n\n // Only add non-modifier keys\n let key = event.key.toLowerCase();\n if (key === ' ') key = 'space';\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 // Exception: allow Tab/Shift+Tab through for form field navigation\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n if (event.key !== 'Tab') return;\n }\n\n const shortcut = buildShortcutString(event);\n if (!shortcut) return;\n\n const command = commands.getCommandByShortcut(shortcut);\n if (!command) return;\n\n // Resolve without document ID - will use active document\n const resolved = commands.resolve(command.id);\n\n if (resolved.disabled || !resolved.visible) {\n return;\n }\n\n // Execute and prevent default (documentId is optional now)\n event.preventDefault();\n event.stopPropagation();\n commands.execute(command.id, undefined, 'keyboard');\n };\n}\n","import { useEffect } from '@framework';\nimport { useCommandsCapability } from '../hooks';\nimport { createKeyDownHandler } from '../utils';\n\n/**\n * Utility component that listens to keyboard events\n * and executes commands based on shortcuts.\n * This component doesn't render anything, it just sets up keyboard shortcuts.\n */\nexport function KeyboardShortcuts() {\n const { provides: commands } = useCommandsCapability();\n\n useEffect(() => {\n if (!commands) return;\n\n const handleKeyDown = createKeyDownHandler(commands);\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [commands]);\n\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\n return null;\n}\n","import { createPluginPackage } from '@embedpdf/core';\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\n\nimport { KeyboardShortcuts } from './components';\n\nexport * from './hooks';\nexport * from './components';\nexport * from '@embedpdf/plugin-commands';\n\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\n .addUtility(KeyboardShortcuts)\n .build();\n"],"names":["BaseCommandsPackage"],"mappings":";;;;;AAIO,MAAM,wBAAwB,MAAM,cAA8B,eAAe,EAAE;AACnF,MAAM,oBAAoB,MAAM,UAA0B,eAAe,EAAE;AAS3E,MAAM,aAAa,CAAC,WAAmB,eAA+C;AAC3F,QAAM,EAAE,SAAA,IAAa,sBAAA;AACrB,QAAM,CAAC,SAAS,UAAU,IAAI;AAAA,IAAiC,MAC7D,WAAW,SAAS,QAAQ,WAAW,UAAU,IAAI;AAAA,EAAA;AAGvD,YAAU,MAAM;AACd,QAAI,CAAC,UAAU;AACb,iBAAW,IAAI;AACf;AAAA,IACF;AAGA,eAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAGlD,UAAM,cAAc,SAAS,sBAAsB,CAAC,UAAU;AAC5D,UAAI,MAAM,cAAc,aAAa,MAAM,eAAe,YAAY;AACpE,mBAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAAA,MACpD;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,WAAW,UAAU,CAAC;AAEpC,SAAO;AACT;AAKO,MAAM,qBAAqB,CAAC,eAAuB;AACxD,QAAM,EAAE,SAAA,IAAa,sBAAA;AAErB,SAAO,CAAC,cAAsB;AAC5B,QAAI,UAAU;AACZ,eAAS,QAAQ,WAAW,YAAY,IAAI;AAAA,IAC9C;AAAA,EACF;AACF;AC/CO,SAAS,oBAAoB,OAAqC;AACvE,QAAM,YAAsB,CAAA;AAE5B,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AACxC,MAAI,MAAM,SAAU,WAAU,KAAK,OAAO;AAC1C,MAAI,MAAM,OAAQ,WAAU,KAAK,KAAK;AACtC,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AAGxC,MAAI,MAAM,MAAM,IAAI,YAAA;AACpB,MAAI,QAAQ,IAAK,OAAM;AACvB,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;AAIzC,QAAI,OAAO,YAAY,WAAW,OAAO,YAAY,cAAc,OAAO,mBAAmB;AAC3F,UAAI,MAAM,QAAQ,MAAO;AAAA,IAC3B;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;ACnDO,SAAS,oBAAoB;AAClC,QAAM,EAAE,UAAU,SAAA,IAAa,sBAAA;AAE/B,YAAU,MAAM;AACd,QAAI,CAAC,SAAU;AAEf,UAAM,gBAAgB,qBAAqB,QAAQ;AAEnD,aAAS,iBAAiB,WAAW,aAAa;AAClD,WAAO,MAAM,SAAS,oBAAoB,WAAW,aAAa;AAAA,EACpE,GAAG,CAAC,QAAQ,CAAC;AAGb,SAAO;AACT;ACdO,MAAM,wBAAwB,oBAAoBA,uBAAmB,EACzE,WAAW,iBAAiB,EAC5B,MAAA;"}
@@ -1,6 +1,14 @@
1
- import { ResolvedCommand } from '../../index.ts';
2
- export declare const useCommandsCapability: () => any;
3
- export declare const useCommandsPlugin: () => any;
1
+ import { CommandsPlugin, ResolvedCommand } from '../../index.ts';
2
+ export declare const useCommandsCapability: () => {
3
+ provides: Readonly<import('../../index.ts').CommandsCapability> | null;
4
+ isLoading: boolean;
5
+ ready: Promise<void>;
6
+ };
7
+ export declare const useCommandsPlugin: () => {
8
+ plugin: CommandsPlugin | null;
9
+ isLoading: boolean;
10
+ ready: Promise<void>;
11
+ };
4
12
  /**
5
13
  * Hook to get a reactive command for a specific document
6
14
  * Automatically updates when command state changes
@@ -0,0 +1 @@
1
+ export { KeyboardShortcuts } from './keyboard-shortcuts';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Utility component that listens to keyboard events
3
+ * and executes commands based on shortcuts.
4
+ * This component doesn't render anything, it just sets up keyboard shortcuts.
5
+ */
6
+ export declare function KeyboardShortcuts(): null;
@@ -9,13 +9,15 @@ export declare const useCommandsPlugin: () => {
9
9
  isLoading: boolean;
10
10
  ready: Promise<void>;
11
11
  };
12
- interface UseCommandReturn {
13
- current: ResolvedCommand | null;
14
- }
15
12
  /**
16
13
  * Hook to get a reactive command for a specific document
17
- * @param getCommandId Function that returns the command ID
18
- * @param getDocumentId Function that returns the document ID
14
+ * Automatically updates when command state changes
15
+ * @param commandId Command ID
16
+ * @param documentId Document ID
17
+ * @returns ResolvedCommand or null if not available
19
18
  */
20
- export declare const useCommand: (getCommandId: () => string, getDocumentId: () => string) => UseCommandReturn;
21
- export {};
19
+ export declare const useCommand: (commandId: string, documentId: string) => ResolvedCommand | null;
20
+ /**
21
+ * Hook to execute a command
22
+ */
23
+ export declare const useCommandExecutor: (documentId: string) => (commandId: string) => void;
@@ -1,4 +1,4 @@
1
1
  export * from './hooks';
2
2
  export * from './components';
3
3
  export * from '../lib/index.ts';
4
- export declare const CommandsPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../lib/index.ts').CommandsPlugin, import('../lib/index.ts').CommandsPluginConfig, import('../lib/index.ts').CommandsState, import('src/lib/actions').SetDisabledCategoriesAction>>;
4
+ export declare const CommandsPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../lib/index.ts').CommandsPlugin, import('../lib/index.ts').CommandsPluginConfig, import('../lib/index.ts').CommandsState, import('../lib/actions').SetDisabledCategoriesAction>>;
@@ -0,0 +1 @@
1
+ export * from './keyboard-handler';
@@ -0,0 +1,10 @@
1
+ import { CommandsCapability } from '../../lib/types';
2
+ /**
3
+ * Build a shortcut string from a keyboard event
4
+ * @example Ctrl+Shift+A -> "ctrl+shift+a"
5
+ */
6
+ export declare function buildShortcutString(event: KeyboardEvent): string | null;
7
+ /**
8
+ * Handle keyboard events and execute commands based on shortcuts
9
+ */
10
+ export declare function createKeyDownHandler(commands: CommandsCapability): (event: KeyboardEvent) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lofcz/embedpdf-plugin-commands",
3
- "version": "2.14.5",
3
+ "version": "2.14.6",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.cjs",
@@ -18,31 +18,20 @@
18
18
  "require": "./dist/react/index.cjs"
19
19
  }
20
20
  },
21
- "scripts": {
22
- "build:base": "vite build --mode base",
23
- "build:react": "vite build --mode react",
24
- "build:preact": "vite build --mode preact",
25
- "build:vue": "vite build --mode vue",
26
- "build:svelte": "vite build --mode svelte",
27
- "build": "pnpm run clean && concurrently -c auto -n base,react \"vite build --mode base\" \"vite build --mode react\"",
28
- "clean": "rimraf dist",
29
- "lint": "eslint src --color",
30
- "lint:fix": "eslint src --color --fix"
31
- },
32
21
  "dependencies": {
33
- "@embedpdf/models": "workspace:@lofcz/embedpdf-models@*"
22
+ "@embedpdf/models": "npm:@lofcz/embedpdf-models@2.14.6"
34
23
  },
35
24
  "devDependencies": {
36
- "@embedpdf/build": "workspace:@lofcz/embedpdf-build@*",
37
- "@embedpdf/core": "workspace:@lofcz/embedpdf-core@*",
38
- "@embedpdf/plugin-i18n": "workspace:@lofcz/embedpdf-plugin-i18n@*",
39
25
  "@types/react": "^18.2.0",
40
- "typescript": "^5.0.0"
26
+ "typescript": "^5.0.0",
27
+ "@embedpdf/build": "npm:@lofcz/embedpdf-build@1.1.0",
28
+ "@embedpdf/plugin-i18n": "npm:@lofcz/embedpdf-plugin-i18n@2.14.6",
29
+ "@embedpdf/core": "npm:@lofcz/embedpdf-core@2.14.6"
41
30
  },
42
31
  "peerDependencies": {
43
- "@embedpdf/core": "workspace:@lofcz/embedpdf-core@*",
44
32
  "react": ">=16.8.0",
45
- "react-dom": ">=16.8.0"
33
+ "react-dom": ">=16.8.0",
34
+ "@embedpdf/core": "2.14.6@lofcz/embedpdf-core@*"
46
35
  },
47
36
  "files": [
48
37
  "dist",
@@ -59,5 +48,16 @@
59
48
  },
60
49
  "publishConfig": {
61
50
  "access": "public"
51
+ },
52
+ "scripts": {
53
+ "build:base": "vite build --mode base",
54
+ "build:react": "vite build --mode react",
55
+ "build:preact": "vite build --mode preact",
56
+ "build:vue": "vite build --mode vue",
57
+ "build:svelte": "vite build --mode svelte",
58
+ "build": "pnpm run clean && concurrently -c auto -n base,react \"vite build --mode base\" \"vite build --mode react\"",
59
+ "clean": "rimraf dist",
60
+ "lint": "eslint src --color",
61
+ "lint:fix": "eslint src --color --fix"
62
62
  }
63
- }
63
+ }
@@ -1,5 +0,0 @@
1
- export { Fragment } from 'preact';
2
- export { useEffect, useRef, useState, useCallback, useMemo } from 'preact/hooks';
3
- export type { ComponentChildren as ReactNode } from 'preact';
4
- export type CSSProperties = import('preact').JSX.CSSProperties;
5
- export type HTMLAttributes<T = any> = import('preact').JSX.HTMLAttributes<T extends EventTarget ? T : never>;
@@ -1 +0,0 @@
1
- export * from '@embedpdf/core/preact';
@@ -1,2 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-commands");require("preact");const r=require("preact/hooks"),o=require("@embedpdf/core/preact"),n=()=>o.useCapability(t.CommandsPlugin.id);function s(){const{provides:e}=n();return r.useEffect(()=>{if(!e)return;const t=function(e){return t=>{const r=t.composedPath()[0]||t.target;if(("INPUT"===r.tagName||"TEXTAREA"===r.tagName||r.isContentEditable)&&"Tab"!==t.key)return;const o=function(e){const t=[];e.ctrlKey&&t.push("ctrl"),e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.metaKey&&t.push("meta");let r=e.key.toLowerCase();return" "===r&&(r="space"),["control","shift","alt","meta"].includes(r)?null:[...t,r].sort().join("+")}(t);if(!o)return;const n=e.getCommandByShortcut(o);if(!n)return;const s=e.resolve(n.id);!s.disabled&&s.visible&&(t.preventDefault(),t.stopPropagation(),e.execute(n.id,void 0,"keyboard"))}}(e);return document.addEventListener("keydown",t),()=>document.removeEventListener("keydown",t)},[e]),null}const u=e.createPluginPackage(t.CommandsPluginPackage).addUtility(s).build();exports.CommandsPluginPackage=u,exports.KeyboardShortcuts=s,exports.useCommand=(e,t)=>{const{provides:o}=n(),[s,u]=r.useState(()=>o?o.resolve(e,t):null);return r.useEffect(()=>{if(!o)return void u(null);u(o.resolve(e,t));return o.onCommandStateChanged(r=>{r.commandId===e&&r.documentId===t&&u(o.resolve(e,t))})},[o,e,t]),s},exports.useCommandExecutor=e=>{const{provides:t}=n();return r=>{t&&t.execute(r,e,"ui")}},exports.useCommandsCapability=n,exports.useCommandsPlugin=()=>o.usePlugin(t.CommandsPlugin.id),Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
2
- //# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/utils/keyboard-handler.ts","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\r\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\r\nimport { useState, useEffect } from '@framework';\r\n\r\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\r\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\r\n\r\n/**\r\n * Hook to get a reactive command for a specific document\r\n * Automatically updates when command state changes\r\n * @param commandId Command ID\r\n * @param documentId Document ID\r\n * @returns ResolvedCommand or null if not available\r\n */\r\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\r\n const { provides } = useCommandsCapability();\r\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\r\n provides ? provides.resolve(commandId, documentId) : null,\r\n );\r\n\r\n useEffect(() => {\r\n if (!provides) {\r\n setCommand(null);\r\n return;\r\n }\r\n\r\n // Initial resolve\r\n setCommand(provides.resolve(commandId, documentId));\r\n\r\n // Subscribe to state changes for this command + document\r\n const unsubscribe = provides.onCommandStateChanged((event) => {\r\n if (event.commandId === commandId && event.documentId === documentId) {\r\n setCommand(provides.resolve(commandId, documentId));\r\n }\r\n });\r\n\r\n return unsubscribe;\r\n }, [provides, commandId, documentId]);\r\n\r\n return command;\r\n};\r\n\r\n/**\r\n * Hook to execute a command\r\n */\r\nexport const useCommandExecutor = (documentId: string) => {\r\n const { provides } = useCommandsCapability();\r\n\r\n return (commandId: string) => {\r\n if (provides) {\r\n provides.execute(commandId, documentId, 'ui');\r\n }\r\n };\r\n};\r\n","import { useEffect } from '@framework';\r\nimport { useCommandsCapability } from '../hooks';\r\nimport { createKeyDownHandler } from '../utils';\r\n\r\n/**\r\n * Utility component that listens to keyboard events\r\n * and executes commands based on shortcuts.\r\n * This component doesn't render anything, it just sets up keyboard shortcuts.\r\n */\r\nexport function KeyboardShortcuts() {\r\n const { provides: commands } = useCommandsCapability();\r\n\r\n useEffect(() => {\r\n if (!commands) return;\r\n\r\n const handleKeyDown = createKeyDownHandler(commands);\r\n\r\n document.addEventListener('keydown', handleKeyDown);\r\n return () => document.removeEventListener('keydown', handleKeyDown);\r\n }, [commands]);\r\n\r\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\r\n return null;\r\n}\r\n","import { CommandsCapability } from '../../lib/types';\r\n\r\n/**\r\n * Build a shortcut string from a keyboard event\r\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\r\n */\r\nexport function buildShortcutString(event: KeyboardEvent): string | null {\r\n const modifiers: string[] = [];\r\n\r\n if (event.ctrlKey) modifiers.push('ctrl');\r\n if (event.shiftKey) modifiers.push('shift');\r\n if (event.altKey) modifiers.push('alt');\r\n if (event.metaKey) modifiers.push('meta');\r\n\r\n // Only add non-modifier keys\r\n let key = event.key.toLowerCase();\r\n if (key === ' ') key = 'space';\r\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\r\n\r\n if (isModifier) {\r\n return null; // Just a modifier, no command\r\n }\r\n\r\n const parts = [...modifiers, key];\r\n return parts.sort().join('+');\r\n}\r\n\r\n/**\r\n * Handle keyboard events and execute commands based on shortcuts\r\n */\r\nexport function createKeyDownHandler(commands: CommandsCapability) {\r\n return (event: KeyboardEvent) => {\r\n // Use composedPath to get the actual target element, even inside Shadow DOM\r\n const composedPath = event.composedPath();\r\n const target = (composedPath[0] || event.target) as HTMLElement;\r\n\r\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\r\n // Exception: allow Tab/Shift+Tab through for form field navigation\r\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\r\n if (event.key !== 'Tab') return;\r\n }\r\n\r\n const shortcut = buildShortcutString(event);\r\n if (!shortcut) return;\r\n\r\n const command = commands.getCommandByShortcut(shortcut);\r\n if (!command) return;\r\n\r\n // Resolve without document ID - will use active document\r\n const resolved = commands.resolve(command.id);\r\n\r\n if (resolved.disabled || !resolved.visible) {\r\n return;\r\n }\r\n\r\n // Execute and prevent default (documentId is optional now)\r\n event.preventDefault();\r\n event.stopPropagation();\r\n commands.execute(command.id, undefined, 'keyboard');\r\n };\r\n}\r\n","import { createPluginPackage } from '@embedpdf/core';\r\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\r\n\r\nimport { KeyboardShortcuts } from './components';\r\n\r\nexport * from './hooks';\r\nexport * from './components';\r\nexport * from '@embedpdf/plugin-commands';\r\n\r\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\r\n .addUtility(KeyboardShortcuts)\r\n .build();\r\n"],"names":["useCommandsCapability","useCapability","CommandsPlugin","id","KeyboardShortcuts","provides","commands","useEffect","handleKeyDown","event","target","composedPath","tagName","isContentEditable","key","shortcut","modifiers","ctrlKey","push","shiftKey","altKey","metaKey","toLowerCase","includes","sort","join","buildShortcutString","command","getCommandByShortcut","resolved","resolve","disabled","visible","preventDefault","stopPropagation","execute","createKeyDownHandler","document","addEventListener","removeEventListener","CommandsPluginPackage","createPluginPackage","BaseCommandsPackage","addUtility","build","commandId","documentId","setCommand","useState","onCommandStateChanged","usePlugin"],"mappings":"8OAIaA,EAAwB,IAAMC,gBAA8BC,EAAAA,eAAeC,ICKjF,SAASC,IACd,MAAQC,SAAUC,GAAaN,IAY/B,OAVAO,EAAAA,UAAU,KACR,IAAKD,EAAU,OAEf,MAAME,ECeH,SAA8BF,GACnC,OAAQG,IAEN,MACMC,EADeD,EAAME,eACE,IAAMF,EAAMC,OAIzC,IAAuB,UAAnBA,EAAOE,SAA0C,aAAnBF,EAAOE,SAA0BF,EAAOG,oBACtD,QAAdJ,EAAMK,IAAe,OAG3B,MAAMC,EApCH,SAA6BN,GAClC,MAAMO,EAAsB,GAExBP,EAAMQ,SAASD,EAAUE,KAAK,QAC9BT,EAAMU,UAAUH,EAAUE,KAAK,SAC/BT,EAAMW,QAAQJ,EAAUE,KAAK,OAC7BT,EAAMY,SAASL,EAAUE,KAAK,QAGlC,IAAIJ,EAAML,EAAMK,IAAIQ,cAIpB,MAHY,MAARR,IAAaA,EAAM,SACJ,CAAC,UAAW,QAAS,MAAO,QAAQS,SAAST,GAGvD,KAGK,IAAIE,EAAWF,GAChBU,OAAOC,KAAK,IAC3B,CAiBqBC,CAAoBjB,GACrC,IAAKM,EAAU,OAEf,MAAMY,EAAUrB,EAASsB,qBAAqBb,GAC9C,IAAKY,EAAS,OAGd,MAAME,EAAWvB,EAASwB,QAAQH,EAAQxB,KAEtC0B,EAASE,UAAaF,EAASG,UAKnCvB,EAAMwB,iBACNxB,EAAMyB,kBACN5B,EAAS6B,QAAQR,EAAQxB,QAAI,EAAW,aAE5C,CD7C0BiC,CAAqB9B,GAG3C,OADA+B,SAASC,iBAAiB,UAAW9B,GAC9B,IAAM6B,SAASE,oBAAoB,UAAW/B,IACpD,CAACF,IAGG,IACT,CEdO,MAAMkC,EAAwBC,EAAAA,oBAAoBC,EAAAA,uBACtDC,WAAWvC,GACXwC,uFHGuB,CAACC,EAAmBC,KAC5C,MAAMzC,SAAEA,GAAaL,KACd2B,EAASoB,GAAcC,EAAAA,SAAiC,IAC7D3C,EAAWA,EAASyB,QAAQe,EAAWC,GAAc,MAsBvD,OAnBAvC,EAAAA,UAAU,KACR,IAAKF,EAEH,YADA0C,EAAW,MAKbA,EAAW1C,EAASyB,QAAQe,EAAWC,IASvC,OANoBzC,EAAS4C,sBAAuBxC,IAC9CA,EAAMoC,YAAcA,GAAapC,EAAMqC,aAAeA,GACxDC,EAAW1C,EAASyB,QAAQe,EAAWC,OAK1C,CAACzC,EAAUwC,EAAWC,IAElBnB,8BAM0BmB,IACjC,MAAMzC,SAAEA,GAAaL,IAErB,OAAQ6C,IACFxC,GACFA,EAAS8B,QAAQU,EAAWC,EAAY,kEA7Cb,IAAMI,YAA0BhD,EAAAA,eAAeC"}
@@ -1 +0,0 @@
1
- export * from '../shared-preact';
@@ -1,91 +0,0 @@
1
- import { createPluginPackage } from "@embedpdf/core";
2
- import { CommandsPlugin, CommandsPluginPackage as CommandsPluginPackage$1 } from "@embedpdf/plugin-commands";
3
- export * from "@embedpdf/plugin-commands";
4
- import "preact";
5
- import { useState, useEffect } from "preact/hooks";
6
- import { useCapability, usePlugin } from "@embedpdf/core/preact";
7
- const useCommandsCapability = () => useCapability(CommandsPlugin.id);
8
- const useCommandsPlugin = () => usePlugin(CommandsPlugin.id);
9
- const useCommand = (commandId, documentId) => {
10
- const { provides } = useCommandsCapability();
11
- const [command, setCommand] = useState(
12
- () => provides ? provides.resolve(commandId, documentId) : null
13
- );
14
- useEffect(() => {
15
- if (!provides) {
16
- setCommand(null);
17
- return;
18
- }
19
- setCommand(provides.resolve(commandId, documentId));
20
- const unsubscribe = provides.onCommandStateChanged((event) => {
21
- if (event.commandId === commandId && event.documentId === documentId) {
22
- setCommand(provides.resolve(commandId, documentId));
23
- }
24
- });
25
- return unsubscribe;
26
- }, [provides, commandId, documentId]);
27
- return command;
28
- };
29
- const useCommandExecutor = (documentId) => {
30
- const { provides } = useCommandsCapability();
31
- return (commandId) => {
32
- if (provides) {
33
- provides.execute(commandId, documentId, "ui");
34
- }
35
- };
36
- };
37
- function buildShortcutString(event) {
38
- const modifiers = [];
39
- if (event.ctrlKey) modifiers.push("ctrl");
40
- if (event.shiftKey) modifiers.push("shift");
41
- if (event.altKey) modifiers.push("alt");
42
- if (event.metaKey) modifiers.push("meta");
43
- let key = event.key.toLowerCase();
44
- if (key === " ") key = "space";
45
- const isModifier = ["control", "shift", "alt", "meta"].includes(key);
46
- if (isModifier) {
47
- return null;
48
- }
49
- const parts = [...modifiers, key];
50
- return parts.sort().join("+");
51
- }
52
- function createKeyDownHandler(commands) {
53
- return (event) => {
54
- const composedPath = event.composedPath();
55
- const target = composedPath[0] || event.target;
56
- if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) {
57
- if (event.key !== "Tab") return;
58
- }
59
- const shortcut = buildShortcutString(event);
60
- if (!shortcut) return;
61
- const command = commands.getCommandByShortcut(shortcut);
62
- if (!command) return;
63
- const resolved = commands.resolve(command.id);
64
- if (resolved.disabled || !resolved.visible) {
65
- return;
66
- }
67
- event.preventDefault();
68
- event.stopPropagation();
69
- commands.execute(command.id, void 0, "keyboard");
70
- };
71
- }
72
- function KeyboardShortcuts() {
73
- const { provides: commands } = useCommandsCapability();
74
- useEffect(() => {
75
- if (!commands) return;
76
- const handleKeyDown = createKeyDownHandler(commands);
77
- document.addEventListener("keydown", handleKeyDown);
78
- return () => document.removeEventListener("keydown", handleKeyDown);
79
- }, [commands]);
80
- return null;
81
- }
82
- const CommandsPluginPackage = createPluginPackage(CommandsPluginPackage$1).addUtility(KeyboardShortcuts).build();
83
- export {
84
- CommandsPluginPackage,
85
- KeyboardShortcuts,
86
- useCommand,
87
- useCommandExecutor,
88
- useCommandsCapability,
89
- useCommandsPlugin
90
- };
91
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-commands.ts","../../src/shared/utils/keyboard-handler.ts","../../src/shared/components/keyboard-shortcuts.tsx","../../src/shared/index.ts"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\r\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\r\nimport { useState, useEffect } from '@framework';\r\n\r\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\r\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\r\n\r\n/**\r\n * Hook to get a reactive command for a specific document\r\n * Automatically updates when command state changes\r\n * @param commandId Command ID\r\n * @param documentId Document ID\r\n * @returns ResolvedCommand or null if not available\r\n */\r\nexport const useCommand = (commandId: string, documentId: string): ResolvedCommand | null => {\r\n const { provides } = useCommandsCapability();\r\n const [command, setCommand] = useState<ResolvedCommand | null>(() =>\r\n provides ? provides.resolve(commandId, documentId) : null,\r\n );\r\n\r\n useEffect(() => {\r\n if (!provides) {\r\n setCommand(null);\r\n return;\r\n }\r\n\r\n // Initial resolve\r\n setCommand(provides.resolve(commandId, documentId));\r\n\r\n // Subscribe to state changes for this command + document\r\n const unsubscribe = provides.onCommandStateChanged((event) => {\r\n if (event.commandId === commandId && event.documentId === documentId) {\r\n setCommand(provides.resolve(commandId, documentId));\r\n }\r\n });\r\n\r\n return unsubscribe;\r\n }, [provides, commandId, documentId]);\r\n\r\n return command;\r\n};\r\n\r\n/**\r\n * Hook to execute a command\r\n */\r\nexport const useCommandExecutor = (documentId: string) => {\r\n const { provides } = useCommandsCapability();\r\n\r\n return (commandId: string) => {\r\n if (provides) {\r\n provides.execute(commandId, documentId, 'ui');\r\n }\r\n };\r\n};\r\n","import { CommandsCapability } from '../../lib/types';\r\n\r\n/**\r\n * Build a shortcut string from a keyboard event\r\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\r\n */\r\nexport function buildShortcutString(event: KeyboardEvent): string | null {\r\n const modifiers: string[] = [];\r\n\r\n if (event.ctrlKey) modifiers.push('ctrl');\r\n if (event.shiftKey) modifiers.push('shift');\r\n if (event.altKey) modifiers.push('alt');\r\n if (event.metaKey) modifiers.push('meta');\r\n\r\n // Only add non-modifier keys\r\n let key = event.key.toLowerCase();\r\n if (key === ' ') key = 'space';\r\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\r\n\r\n if (isModifier) {\r\n return null; // Just a modifier, no command\r\n }\r\n\r\n const parts = [...modifiers, key];\r\n return parts.sort().join('+');\r\n}\r\n\r\n/**\r\n * Handle keyboard events and execute commands based on shortcuts\r\n */\r\nexport function createKeyDownHandler(commands: CommandsCapability) {\r\n return (event: KeyboardEvent) => {\r\n // Use composedPath to get the actual target element, even inside Shadow DOM\r\n const composedPath = event.composedPath();\r\n const target = (composedPath[0] || event.target) as HTMLElement;\r\n\r\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\r\n // Exception: allow Tab/Shift+Tab through for form field navigation\r\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\r\n if (event.key !== 'Tab') return;\r\n }\r\n\r\n const shortcut = buildShortcutString(event);\r\n if (!shortcut) return;\r\n\r\n const command = commands.getCommandByShortcut(shortcut);\r\n if (!command) return;\r\n\r\n // Resolve without document ID - will use active document\r\n const resolved = commands.resolve(command.id);\r\n\r\n if (resolved.disabled || !resolved.visible) {\r\n return;\r\n }\r\n\r\n // Execute and prevent default (documentId is optional now)\r\n event.preventDefault();\r\n event.stopPropagation();\r\n commands.execute(command.id, undefined, 'keyboard');\r\n };\r\n}\r\n","import { useEffect } from '@framework';\r\nimport { useCommandsCapability } from '../hooks';\r\nimport { createKeyDownHandler } from '../utils';\r\n\r\n/**\r\n * Utility component that listens to keyboard events\r\n * and executes commands based on shortcuts.\r\n * This component doesn't render anything, it just sets up keyboard shortcuts.\r\n */\r\nexport function KeyboardShortcuts() {\r\n const { provides: commands } = useCommandsCapability();\r\n\r\n useEffect(() => {\r\n if (!commands) return;\r\n\r\n const handleKeyDown = createKeyDownHandler(commands);\r\n\r\n document.addEventListener('keydown', handleKeyDown);\r\n return () => document.removeEventListener('keydown', handleKeyDown);\r\n }, [commands]);\r\n\r\n // This component is only used to set up keyboard shortcuts when the plugin is initialized.\r\n return null;\r\n}\r\n","import { createPluginPackage } from '@embedpdf/core';\r\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\r\n\r\nimport { KeyboardShortcuts } from './components';\r\n\r\nexport * from './hooks';\r\nexport * from './components';\r\nexport * from '@embedpdf/plugin-commands';\r\n\r\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\r\n .addUtility(KeyboardShortcuts)\r\n .build();\r\n"],"names":["BaseCommandsPackage"],"mappings":";;;;;;AAIO,MAAM,wBAAwB,MAAM,cAA8B,eAAe,EAAE;AACnF,MAAM,oBAAoB,MAAM,UAA0B,eAAe,EAAE;AAS3E,MAAM,aAAa,CAAC,WAAmB,eAA+C;AAC3F,QAAM,EAAE,SAAA,IAAa,sBAAA;AACrB,QAAM,CAAC,SAAS,UAAU,IAAI;AAAA,IAAiC,MAC7D,WAAW,SAAS,QAAQ,WAAW,UAAU,IAAI;AAAA,EAAA;AAGvD,YAAU,MAAM;AACd,QAAI,CAAC,UAAU;AACb,iBAAW,IAAI;AACf;AAAA,IACF;AAGA,eAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAGlD,UAAM,cAAc,SAAS,sBAAsB,CAAC,UAAU;AAC5D,UAAI,MAAM,cAAc,aAAa,MAAM,eAAe,YAAY;AACpE,mBAAW,SAAS,QAAQ,WAAW,UAAU,CAAC;AAAA,MACpD;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,WAAW,UAAU,CAAC;AAEpC,SAAO;AACT;AAKO,MAAM,qBAAqB,CAAC,eAAuB;AACxD,QAAM,EAAE,SAAA,IAAa,sBAAA;AAErB,SAAO,CAAC,cAAsB;AAC5B,QAAI,UAAU;AACZ,eAAS,QAAQ,WAAW,YAAY,IAAI;AAAA,IAC9C;AAAA,EACF;AACF;AC/CO,SAAS,oBAAoB,OAAqC;AACvE,QAAM,YAAsB,CAAA;AAE5B,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AACxC,MAAI,MAAM,SAAU,WAAU,KAAK,OAAO;AAC1C,MAAI,MAAM,OAAQ,WAAU,KAAK,KAAK;AACtC,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AAGxC,MAAI,MAAM,MAAM,IAAI,YAAA;AACpB,MAAI,QAAQ,IAAK,OAAM;AACvB,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;AAIzC,QAAI,OAAO,YAAY,WAAW,OAAO,YAAY,cAAc,OAAO,mBAAmB;AAC3F,UAAI,MAAM,QAAQ,MAAO;AAAA,IAC3B;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;ACnDO,SAAS,oBAAoB;AAClC,QAAM,EAAE,UAAU,SAAA,IAAa,sBAAA;AAE/B,YAAU,MAAM;AACd,QAAI,CAAC,SAAU;AAEf,UAAM,gBAAgB,qBAAqB,QAAQ;AAEnD,aAAS,iBAAiB,WAAW,aAAa;AAClD,WAAO,MAAM,SAAS,oBAAoB,WAAW,aAAa;AAAA,EACpE,GAAG,CAAC,QAAQ,CAAC;AAGb,SAAO;AACT;ACdO,MAAM,wBAAwB,oBAAoBA,uBAAmB,EACzE,WAAW,iBAAiB,EAC5B,MAAA;"}
@@ -1,18 +0,0 @@
1
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
- $$bindings?: Bindings;
4
- } & Exports;
5
- (internal: unknown, props: {
6
- $$events?: Events;
7
- $$slots?: Slots;
8
- }): Exports & {
9
- $set?: any;
10
- $on?: any;
11
- };
12
- z_$$bindings?: Bindings;
13
- }
14
- declare const KeyboardShortcuts: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
- [evt: string]: CustomEvent<any>;
16
- }, {}, {}, string>;
17
- type KeyboardShortcuts = InstanceType<typeof KeyboardShortcuts>;
18
- export default KeyboardShortcuts;
@@ -1 +0,0 @@
1
- export { default as KeyboardShortcuts } from './KeyboardShortcuts.svelte';
@@ -1 +0,0 @@
1
- export * from './use-commands.svelte';
@@ -1,2 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-commands");require("svelte/internal/disclose-version"),require("svelte/internal/flags/legacy");const r=require("svelte/internal/client"),n=require("svelte"),o=require("@embedpdf/core/svelte");function s(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const r in e)if("default"!==r){const n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:()=>e[r]})}return t.default=e,Object.freeze(t)}const i=s(r),a=()=>o.useCapability(t.CommandsPlugin.id);function u(e,t){i.push(t,!1);const r=a();n.onMount(()=>{if(!r.provides)return;const e=(t=r.provides,e=>{const r=e.composedPath()[0]||e.target;if(("INPUT"===r.tagName||"TEXTAREA"===r.tagName||r.isContentEditable)&&"Tab"!==e.key)return;const n=function(e){const t=[];e.ctrlKey&&t.push("ctrl"),e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.metaKey&&t.push("meta");let r=e.key.toLowerCase();return" "===r&&(r="space"),["control","shift","alt","meta"].includes(r)?null:[...t,r].sort().join("+")}(e);if(!n)return;const o=t.getCommandByShortcut(n);if(!o)return;const s=t.resolve(o.id);!s.disabled&&s.visible&&(e.preventDefault(),e.stopPropagation(),t.execute(o.id,void 0,"keyboard"))});var t;return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)}),i.init(),i.pop()}const l=e.createPluginPackage(t.CommandsPluginPackage).addUtility(u).build();exports.CommandsPluginPackage=l,exports.KeyboardShortcuts=u,exports.useCommand=(e,t)=>{const r=a();let n=i.state(null);const o=i.derived(e),s=i.derived(t);return i.user_effect(()=>{const e=r.provides,t=i.get(o),a=i.get(s);if(e&&t&&a)return i.set(n,e.resolve(t,a),!0),e.onCommandStateChanged(r=>{r.commandId===t&&r.documentId===a&&i.set(n,e.resolve(t,a),!0)});i.set(n,null)}),{get current(){return i.get(n)}}},exports.useCommandsCapability=a,exports.useCommandsPlugin=()=>o.usePlugin(t.CommandsPlugin.id),Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
2
- //# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
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';\r\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\r\n\r\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\r\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\r\n\r\n// Define the return type explicitly to maintain type safety\r\ninterface UseCommandReturn {\r\n current: ResolvedCommand | null;\r\n}\r\n\r\n/**\r\n * Hook to get a reactive command for a specific document\r\n * @param getCommandId Function that returns the command ID\r\n * @param getDocumentId Function that returns the document ID\r\n */\r\nexport const useCommand = (\r\n getCommandId: () => string,\r\n getDocumentId: () => string,\r\n): UseCommandReturn => {\r\n const capability = useCommandsCapability();\r\n\r\n let command = $state<ResolvedCommand | null>(null);\r\n\r\n // Reactive commandId and documentId\r\n const commandId = $derived(getCommandId());\r\n const documentId = $derived(getDocumentId());\r\n\r\n $effect(() => {\r\n const provides = capability.provides;\r\n const cmdId = commandId;\r\n const docId = documentId;\r\n\r\n if (!provides || !cmdId || !docId) {\r\n command = null;\r\n return;\r\n }\r\n\r\n command = provides.resolve(cmdId, docId);\r\n\r\n return provides.onCommandStateChanged((event) => {\r\n if (event.commandId === cmdId && event.documentId === docId) {\r\n command = provides.resolve(cmdId, docId);\r\n }\r\n });\r\n });\r\n\r\n return {\r\n get current() {\r\n return command;\r\n },\r\n };\r\n};\r\n","<script lang=\"ts\">\r\n import { onMount } from 'svelte';\r\n import { useCommandsCapability } from '../hooks';\r\n import { createKeyDownHandler } from '../../shared/utils';\r\n\r\n const commandsCapability = useCommandsCapability();\r\n\r\n onMount(() => {\r\n if (!commandsCapability.provides) return;\r\n\r\n const handleKeyDown = createKeyDownHandler(commandsCapability.provides);\r\n\r\n document.addEventListener('keydown', handleKeyDown);\r\n return () => document.removeEventListener('keydown', handleKeyDown);\r\n });\r\n</script>\r\n\r\n<!-- This component is only used to set up keyboard shortcuts when the plugin is initialized. -->\r\n","import { CommandsCapability } from '../../lib/types';\r\n\r\n/**\r\n * Build a shortcut string from a keyboard event\r\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\r\n */\r\nexport function buildShortcutString(event: KeyboardEvent): string | null {\r\n const modifiers: string[] = [];\r\n\r\n if (event.ctrlKey) modifiers.push('ctrl');\r\n if (event.shiftKey) modifiers.push('shift');\r\n if (event.altKey) modifiers.push('alt');\r\n if (event.metaKey) modifiers.push('meta');\r\n\r\n // Only add non-modifier keys\r\n let key = event.key.toLowerCase();\r\n if (key === ' ') key = 'space';\r\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\r\n\r\n if (isModifier) {\r\n return null; // Just a modifier, no command\r\n }\r\n\r\n const parts = [...modifiers, key];\r\n return parts.sort().join('+');\r\n}\r\n\r\n/**\r\n * Handle keyboard events and execute commands based on shortcuts\r\n */\r\nexport function createKeyDownHandler(commands: CommandsCapability) {\r\n return (event: KeyboardEvent) => {\r\n // Use composedPath to get the actual target element, even inside Shadow DOM\r\n const composedPath = event.composedPath();\r\n const target = (composedPath[0] || event.target) as HTMLElement;\r\n\r\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\r\n // Exception: allow Tab/Shift+Tab through for form field navigation\r\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\r\n if (event.key !== 'Tab') return;\r\n }\r\n\r\n const shortcut = buildShortcutString(event);\r\n if (!shortcut) return;\r\n\r\n const command = commands.getCommandByShortcut(shortcut);\r\n if (!command) return;\r\n\r\n // Resolve without document ID - will use active document\r\n const resolved = commands.resolve(command.id);\r\n\r\n if (resolved.disabled || !resolved.visible) {\r\n return;\r\n }\r\n\r\n // Execute and prevent default (documentId is optional now)\r\n event.preventDefault();\r\n event.stopPropagation();\r\n commands.execute(command.id, undefined, 'keyboard');\r\n };\r\n}\r\n","import { createPluginPackage } from '@embedpdf/core';\r\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\r\n\r\nimport { KeyboardShortcuts } from './components';\r\n\r\nexport * from './hooks';\r\nexport * from './components';\r\nexport * from '@embedpdf/plugin-commands';\r\n\r\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\r\n .addUtility(KeyboardShortcuts)\r\n .build();\r\n"],"names":["useCommandsCapability","useCapability","CommandsPlugin","id","commandsCapability","onMount","provides","handleKeyDown","commands","event","target","composedPath","tagName","isContentEditable","key","shortcut","modifiers","ctrlKey","push","shiftKey","altKey","metaKey","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,aACO,IAAAD,EAAmBE,SAAQ,OAE1B,MAAAC,GCoB2BC,EDpBUJ,EAAmBE,SCqBxDG,IAEN,MACMC,EADeD,EAAME,eACE,IAAMF,EAAMC,OAIzC,IAAuB,UAAnBA,EAAOE,SAA0C,aAAnBF,EAAOE,SAA0BF,EAAOG,oBACtD,QAAdJ,EAAMK,IAAe,OAG3B,MAAMC,EApCH,SAA6BN,GAClC,MAAMO,EAAsB,GAExBP,EAAMQ,SAASD,EAAUE,KAAK,QAC9BT,EAAMU,UAAUH,EAAUE,KAAK,SAC/BT,EAAMW,QAAQJ,EAAUE,KAAK,OAC7BT,EAAMY,SAASL,EAAUE,KAAK,QAGlC,IAAIJ,EAAML,EAAMK,IAAIQ,cAIpB,MAHY,MAARR,IAAaA,EAAM,SACJ,CAAC,UAAW,QAAS,MAAO,QAAQS,SAAST,GAGvD,KAGK,IAAIE,EAAWF,GAChBU,OAAOC,KAAK,IAC3B,CAiBqBC,CAAoBjB,GACrC,IAAKM,EAAU,OAEf,MAAMY,EAAUnB,EAASoB,qBAAqBb,GAC9C,IAAKY,EAAS,OAGd,MAAME,EAAWrB,EAASsB,QAAQH,EAAQxB,KAEtC0B,EAASE,UAAaF,EAASG,UAKnCvB,EAAMwB,iBACNxB,EAAMyB,kBACN1B,EAAS2B,QAAQR,EAAQxB,QAAI,EAAW,eA5BrC,IAA8BK,EDjBpB,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,4 +0,0 @@
1
- export * from './hooks';
2
- export * from './components';
3
- export * from '../lib/index.ts';
4
- export declare const CommandsPluginPackage: import('@embedpdf/core').WithAutoMount<import('@embedpdf/core').PluginPackage<import('../lib/index.ts').CommandsPlugin, import('../lib/index.ts').CommandsPluginConfig, import('../lib/index.ts').CommandsState, import('src/lib/actions').SetDisabledCategoriesAction>>;
@@ -1,92 +0,0 @@
1
- import { createPluginPackage } from "@embedpdf/core";
2
- import { CommandsPlugin, CommandsPluginPackage as CommandsPluginPackage$1 } from "@embedpdf/plugin-commands";
3
- export * from "@embedpdf/plugin-commands";
4
- import "svelte/internal/disclose-version";
5
- import "svelte/internal/flags/legacy";
6
- import * as $ from "svelte/internal/client";
7
- import { onMount } from "svelte";
8
- import { useCapability, usePlugin } from "@embedpdf/core/svelte";
9
- const useCommandsCapability = () => useCapability(CommandsPlugin.id);
10
- const useCommandsPlugin = () => usePlugin(CommandsPlugin.id);
11
- const useCommand = (getCommandId, getDocumentId) => {
12
- const capability = useCommandsCapability();
13
- let command = $.state(null);
14
- const commandId = $.derived(getCommandId);
15
- const documentId = $.derived(getDocumentId);
16
- $.user_effect(() => {
17
- const provides = capability.provides;
18
- const cmdId = $.get(commandId);
19
- const docId = $.get(documentId);
20
- if (!provides || !cmdId || !docId) {
21
- $.set(command, null);
22
- return;
23
- }
24
- $.set(command, provides.resolve(cmdId, docId), true);
25
- return provides.onCommandStateChanged((event) => {
26
- if (event.commandId === cmdId && event.documentId === docId) {
27
- $.set(command, provides.resolve(cmdId, docId), true);
28
- }
29
- });
30
- });
31
- return {
32
- get current() {
33
- return $.get(command);
34
- }
35
- };
36
- };
37
- function buildShortcutString(event) {
38
- const modifiers = [];
39
- if (event.ctrlKey) modifiers.push("ctrl");
40
- if (event.shiftKey) modifiers.push("shift");
41
- if (event.altKey) modifiers.push("alt");
42
- if (event.metaKey) modifiers.push("meta");
43
- let key = event.key.toLowerCase();
44
- if (key === " ") key = "space";
45
- const isModifier = ["control", "shift", "alt", "meta"].includes(key);
46
- if (isModifier) {
47
- return null;
48
- }
49
- const parts = [...modifiers, key];
50
- return parts.sort().join("+");
51
- }
52
- function createKeyDownHandler(commands) {
53
- return (event) => {
54
- const composedPath = event.composedPath();
55
- const target = composedPath[0] || event.target;
56
- if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) {
57
- if (event.key !== "Tab") return;
58
- }
59
- const shortcut = buildShortcutString(event);
60
- if (!shortcut) return;
61
- const command = commands.getCommandByShortcut(shortcut);
62
- if (!command) return;
63
- const resolved = commands.resolve(command.id);
64
- if (resolved.disabled || !resolved.visible) {
65
- return;
66
- }
67
- event.preventDefault();
68
- event.stopPropagation();
69
- commands.execute(command.id, void 0, "keyboard");
70
- };
71
- }
72
- function KeyboardShortcuts($$anchor, $$props) {
73
- $.push($$props, false);
74
- const commandsCapability = useCommandsCapability();
75
- onMount(() => {
76
- if (!commandsCapability.provides) return;
77
- const handleKeyDown = createKeyDownHandler(commandsCapability.provides);
78
- document.addEventListener("keydown", handleKeyDown);
79
- return () => document.removeEventListener("keydown", handleKeyDown);
80
- });
81
- $.init();
82
- $.pop();
83
- }
84
- const CommandsPluginPackage = createPluginPackage(CommandsPluginPackage$1).addUtility(KeyboardShortcuts).build();
85
- export {
86
- CommandsPluginPackage,
87
- KeyboardShortcuts,
88
- useCommand,
89
- useCommandsCapability,
90
- useCommandsPlugin
91
- };
92
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
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';\r\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\r\n\r\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\r\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\r\n\r\n// Define the return type explicitly to maintain type safety\r\ninterface UseCommandReturn {\r\n current: ResolvedCommand | null;\r\n}\r\n\r\n/**\r\n * Hook to get a reactive command for a specific document\r\n * @param getCommandId Function that returns the command ID\r\n * @param getDocumentId Function that returns the document ID\r\n */\r\nexport const useCommand = (\r\n getCommandId: () => string,\r\n getDocumentId: () => string,\r\n): UseCommandReturn => {\r\n const capability = useCommandsCapability();\r\n\r\n let command = $state<ResolvedCommand | null>(null);\r\n\r\n // Reactive commandId and documentId\r\n const commandId = $derived(getCommandId());\r\n const documentId = $derived(getDocumentId());\r\n\r\n $effect(() => {\r\n const provides = capability.provides;\r\n const cmdId = commandId;\r\n const docId = documentId;\r\n\r\n if (!provides || !cmdId || !docId) {\r\n command = null;\r\n return;\r\n }\r\n\r\n command = provides.resolve(cmdId, docId);\r\n\r\n return provides.onCommandStateChanged((event) => {\r\n if (event.commandId === cmdId && event.documentId === docId) {\r\n command = provides.resolve(cmdId, docId);\r\n }\r\n });\r\n });\r\n\r\n return {\r\n get current() {\r\n return command;\r\n },\r\n };\r\n};\r\n","import { CommandsCapability } from '../../lib/types';\r\n\r\n/**\r\n * Build a shortcut string from a keyboard event\r\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\r\n */\r\nexport function buildShortcutString(event: KeyboardEvent): string | null {\r\n const modifiers: string[] = [];\r\n\r\n if (event.ctrlKey) modifiers.push('ctrl');\r\n if (event.shiftKey) modifiers.push('shift');\r\n if (event.altKey) modifiers.push('alt');\r\n if (event.metaKey) modifiers.push('meta');\r\n\r\n // Only add non-modifier keys\r\n let key = event.key.toLowerCase();\r\n if (key === ' ') key = 'space';\r\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\r\n\r\n if (isModifier) {\r\n return null; // Just a modifier, no command\r\n }\r\n\r\n const parts = [...modifiers, key];\r\n return parts.sort().join('+');\r\n}\r\n\r\n/**\r\n * Handle keyboard events and execute commands based on shortcuts\r\n */\r\nexport function createKeyDownHandler(commands: CommandsCapability) {\r\n return (event: KeyboardEvent) => {\r\n // Use composedPath to get the actual target element, even inside Shadow DOM\r\n const composedPath = event.composedPath();\r\n const target = (composedPath[0] || event.target) as HTMLElement;\r\n\r\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\r\n // Exception: allow Tab/Shift+Tab through for form field navigation\r\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\r\n if (event.key !== 'Tab') return;\r\n }\r\n\r\n const shortcut = buildShortcutString(event);\r\n if (!shortcut) return;\r\n\r\n const command = commands.getCommandByShortcut(shortcut);\r\n if (!command) return;\r\n\r\n // Resolve without document ID - will use active document\r\n const resolved = commands.resolve(command.id);\r\n\r\n if (resolved.disabled || !resolved.visible) {\r\n return;\r\n }\r\n\r\n // Execute and prevent default (documentId is optional now)\r\n event.preventDefault();\r\n event.stopPropagation();\r\n commands.execute(command.id, undefined, 'keyboard');\r\n };\r\n}\r\n","<script lang=\"ts\">\r\n import { onMount } from 'svelte';\r\n import { useCommandsCapability } from '../hooks';\r\n import { createKeyDownHandler } from '../../shared/utils';\r\n\r\n const commandsCapability = useCommandsCapability();\r\n\r\n onMount(() => {\r\n if (!commandsCapability.provides) return;\r\n\r\n const handleKeyDown = createKeyDownHandler(commandsCapability.provides);\r\n\r\n document.addEventListener('keydown', handleKeyDown);\r\n return () => document.removeEventListener('keydown', handleKeyDown);\r\n });\r\n</script>\r\n\r\n<!-- This component is only used to set up keyboard shortcuts when the plugin is initialized. -->\r\n","import { createPluginPackage } from '@embedpdf/core';\r\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\r\n\r\nimport { KeyboardShortcuts } from './components';\r\n\r\nexport * from './hooks';\r\nexport * from './components';\r\nexport * from '@embedpdf/plugin-commands';\r\n\r\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\r\n .addUtility(KeyboardShortcuts)\r\n .build();\r\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,MAAI,MAAM,MAAM,IAAI,YAAA;AACpB,MAAI,QAAQ,IAAK,OAAM;AACvB,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;AAIzC,QAAI,OAAO,YAAY,WAAW,OAAO,YAAY,cAAc,OAAO,mBAAmB;AAC3F,UAAI,MAAM,QAAQ,MAAO;AAAA,IAC3B;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;8CC5DA;;AAKQ,QAAA,qBAAqB,sBAAqB;AAEhD,gBAAc;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;"}
@@ -1 +0,0 @@
1
- export { default as KeyboardShortcuts } from './keyboard-shortcuts.vue';
@@ -1,3 +0,0 @@
1
- declare const __VLS_export: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
2
- declare const _default: typeof __VLS_export;
3
- export default _default;
@@ -1,46 +0,0 @@
1
- import { MaybeRefOrGetter } from 'vue';
2
- import { CommandsPlugin } from '../../lib/index.ts';
3
- export declare const useCommandsCapability: () => import('@embedpdf/core/vue').CapabilityState<Readonly<import('../../lib/index.ts').CommandsCapability>>;
4
- export declare const useCommandsPlugin: () => import('@embedpdf/core/vue').PluginState<CommandsPlugin>;
5
- /**
6
- * Hook to get a reactive command for a specific document
7
- * @param commandId Command ID (can be ref, computed, getter, or plain value)
8
- * @param documentId Document ID (can be ref, computed, getter, or plain value)
9
- */
10
- export declare const useCommand: (commandId: MaybeRefOrGetter<string>, documentId: MaybeRefOrGetter<string>) => Readonly<import('vue').Ref<{
11
- readonly id: string;
12
- readonly label: string;
13
- readonly icon?: string | undefined;
14
- readonly iconProps?: {
15
- readonly primaryColor?: string | undefined;
16
- readonly secondaryColor?: string | undefined;
17
- readonly className?: string | undefined;
18
- readonly title?: string | undefined;
19
- } | undefined;
20
- readonly active: boolean;
21
- readonly disabled: boolean;
22
- readonly visible: boolean;
23
- readonly shortcuts?: readonly string[] | undefined;
24
- readonly shortcutLabel?: string | undefined;
25
- readonly categories?: readonly string[] | undefined;
26
- readonly description?: string | undefined;
27
- readonly execute: () => void;
28
- } | null, {
29
- readonly id: string;
30
- readonly label: string;
31
- readonly icon?: string | undefined;
32
- readonly iconProps?: {
33
- readonly primaryColor?: string | undefined;
34
- readonly secondaryColor?: string | undefined;
35
- readonly className?: string | undefined;
36
- readonly title?: string | undefined;
37
- } | undefined;
38
- readonly active: boolean;
39
- readonly disabled: boolean;
40
- readonly visible: boolean;
41
- readonly shortcuts?: readonly string[] | undefined;
42
- readonly shortcutLabel?: string | undefined;
43
- readonly categories?: readonly string[] | undefined;
44
- readonly description?: string | undefined;
45
- readonly execute: () => void;
46
- } | null>>;
@@ -1,2 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/plugin-commands"),o=require("vue"),n=require("@embedpdf/core/vue"),r=()=>n.useCapability(t.CommandsPlugin.id);const a=o.defineComponent({__name:"keyboard-shortcuts",setup(e){const{provides:t}=r();let n=null;return o.onMounted(()=>{if(!t.value)return;const e=function(e){return t=>{const o=t.composedPath()[0]||t.target;if(("INPUT"===o.tagName||"TEXTAREA"===o.tagName||o.isContentEditable)&&"Tab"!==t.key)return;const n=function(e){const t=[];e.ctrlKey&&t.push("ctrl"),e.shiftKey&&t.push("shift"),e.altKey&&t.push("alt"),e.metaKey&&t.push("meta");let o=e.key.toLowerCase();return" "===o&&(o="space"),["control","shift","alt","meta"].includes(o)?null:[...t,o].sort().join("+")}(t);if(!n)return;const r=e.getCommandByShortcut(n);if(!r)return;const a=e.resolve(r.id);!a.disabled&&a.visible&&(t.preventDefault(),t.stopPropagation(),e.execute(r.id,void 0,"keyboard"))}}(t.value);document.addEventListener("keydown",e),n=()=>document.removeEventListener("keydown",e)}),o.onUnmounted(()=>{null==n||n()}),(e,t)=>null}}),u=e.createPluginPackage(t.CommandsPluginPackage).addUtility(a).build();exports.CommandsPluginPackage=u,exports.KeyboardShortcuts=a,exports.useCommand=(e,t)=>{const{provides:n}=r(),a=o.ref(null);return o.watch([n,()=>o.toValue(e),()=>o.toValue(t)],([e,t,o],n,r)=>{if(!e)return void(a.value=null);a.value=e.resolve(t,o);r(e.onCommandStateChanged(n=>{n.commandId===t&&n.documentId===o&&(a.value=e.resolve(t,o))}))},{immediate:!0}),o.readonly(a)},exports.useCommandsCapability=r,exports.useCommandsPlugin=()=>n.usePlugin(t.CommandsPlugin.id),Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
2
- //# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/vue/hooks/use-commands.ts","../../src/vue/components/keyboard-shortcuts.vue","../../src/shared/utils/keyboard-handler.ts","../../src/vue/index.ts"],"sourcesContent":["import { ref, watch, readonly, toValue, type MaybeRefOrGetter } from 'vue';\r\nimport { useCapability, usePlugin } from '@embedpdf/core/vue';\r\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\r\n\r\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\r\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\r\n\r\n/**\r\n * Hook to get a reactive command for a specific document\r\n * @param commandId Command ID (can be ref, computed, getter, or plain value)\r\n * @param documentId Document ID (can be ref, computed, getter, or plain value)\r\n */\r\nexport const useCommand = (\r\n commandId: MaybeRefOrGetter<string>,\r\n documentId: MaybeRefOrGetter<string>,\r\n) => {\r\n const { provides } = useCommandsCapability();\r\n const command = ref<ResolvedCommand | null>(null);\r\n\r\n watch(\r\n [provides, () => toValue(commandId), () => toValue(documentId)],\r\n ([providesValue, cmdId, docId], _, onCleanup) => {\r\n if (!providesValue) {\r\n command.value = null;\r\n return;\r\n }\r\n\r\n command.value = providesValue.resolve(cmdId, docId);\r\n\r\n const unsubscribe = providesValue.onCommandStateChanged((event) => {\r\n if (event.commandId === cmdId && event.documentId === docId) {\r\n command.value = providesValue.resolve(cmdId, docId);\r\n }\r\n });\r\n\r\n onCleanup(unsubscribe);\r\n },\r\n { immediate: true },\r\n );\r\n\r\n return readonly(command);\r\n};\r\n","<template>\r\n <!-- This component is only used to set up keyboard shortcuts when the plugin is initialized -->\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { onMounted, onUnmounted } from 'vue';\r\nimport { useCommandsCapability } from '../hooks';\r\nimport { createKeyDownHandler } from '../../shared/utils';\r\n\r\nconst { provides: commands } = useCommandsCapability();\r\n\r\nlet cleanup: (() => void) | null = null;\r\n\r\nonMounted(() => {\r\n if (!commands.value) return;\r\n\r\n const handleKeyDown = createKeyDownHandler(commands.value);\r\n\r\n document.addEventListener('keydown', handleKeyDown);\r\n cleanup = () => document.removeEventListener('keydown', handleKeyDown);\r\n});\r\n\r\nonUnmounted(() => {\r\n cleanup?.();\r\n});\r\n</script>\r\n","import { CommandsCapability } from '../../lib/types';\r\n\r\n/**\r\n * Build a shortcut string from a keyboard event\r\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\r\n */\r\nexport function buildShortcutString(event: KeyboardEvent): string | null {\r\n const modifiers: string[] = [];\r\n\r\n if (event.ctrlKey) modifiers.push('ctrl');\r\n if (event.shiftKey) modifiers.push('shift');\r\n if (event.altKey) modifiers.push('alt');\r\n if (event.metaKey) modifiers.push('meta');\r\n\r\n // Only add non-modifier keys\r\n let key = event.key.toLowerCase();\r\n if (key === ' ') key = 'space';\r\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\r\n\r\n if (isModifier) {\r\n return null; // Just a modifier, no command\r\n }\r\n\r\n const parts = [...modifiers, key];\r\n return parts.sort().join('+');\r\n}\r\n\r\n/**\r\n * Handle keyboard events and execute commands based on shortcuts\r\n */\r\nexport function createKeyDownHandler(commands: CommandsCapability) {\r\n return (event: KeyboardEvent) => {\r\n // Use composedPath to get the actual target element, even inside Shadow DOM\r\n const composedPath = event.composedPath();\r\n const target = (composedPath[0] || event.target) as HTMLElement;\r\n\r\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\r\n // Exception: allow Tab/Shift+Tab through for form field navigation\r\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\r\n if (event.key !== 'Tab') return;\r\n }\r\n\r\n const shortcut = buildShortcutString(event);\r\n if (!shortcut) return;\r\n\r\n const command = commands.getCommandByShortcut(shortcut);\r\n if (!command) return;\r\n\r\n // Resolve without document ID - will use active document\r\n const resolved = commands.resolve(command.id);\r\n\r\n if (resolved.disabled || !resolved.visible) {\r\n return;\r\n }\r\n\r\n // Execute and prevent default (documentId is optional now)\r\n event.preventDefault();\r\n event.stopPropagation();\r\n commands.execute(command.id, undefined, 'keyboard');\r\n };\r\n}\r\n","import { createPluginPackage } from '@embedpdf/core';\r\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\r\n\r\nimport { KeyboardShortcuts } from './components';\r\n\r\nexport * from './hooks';\r\nexport * from './components';\r\nexport * from '@embedpdf/plugin-commands';\r\n\r\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\r\n .addUtility(KeyboardShortcuts)\r\n .build();\r\n"],"names":["useCommandsCapability","useCapability","CommandsPlugin","id","provides","commands","cleanup","onMounted","value","handleKeyDown","event","target","composedPath","tagName","isContentEditable","key","shortcut","modifiers","ctrlKey","push","shiftKey","altKey","metaKey","toLowerCase","includes","sort","join","buildShortcutString","command","getCommandByShortcut","resolved","resolve","disabled","visible","preventDefault","stopPropagation","execute","createKeyDownHandler","document","addEventListener","removeEventListener","onUnmounted","CommandsPluginPackage","createPluginPackage","BaseCommandsPackage","addUtility","KeyboardShortcuts","build","commandId","documentId","ref","watch","toValue","providesValue","cmdId","docId","_","onCleanup","onCommandStateChanged","immediate","readonly","usePlugin"],"mappings":"0MAIaA,EAAwB,IAAMC,gBAA8BC,EAAAA,eAAeC,oECKxF,MAAQC,SAAUC,GAAaL,IAE/B,IAAIM,EAA+B,YAEnCC,EAAAA,UAAU,KACR,IAAKF,EAASG,MAAO,OAErB,MAAMC,ECcD,SAA8BJ,GACnC,OAAQK,IAEN,MACMC,EADeD,EAAME,eACE,IAAMF,EAAMC,OAIzC,IAAuB,UAAnBA,EAAOE,SAA0C,aAAnBF,EAAOE,SAA0BF,EAAOG,oBACtD,QAAdJ,EAAMK,IAAe,OAG3B,MAAMC,EApCH,SAA6BN,GAClC,MAAMO,EAAsB,GAExBP,EAAMQ,SAASD,EAAUE,KAAK,QAC9BT,EAAMU,UAAUH,EAAUE,KAAK,SAC/BT,EAAMW,QAAQJ,EAAUE,KAAK,OAC7BT,EAAMY,SAASL,EAAUE,KAAK,QAGlC,IAAIJ,EAAML,EAAMK,IAAIQ,cAIpB,MAHY,MAARR,IAAaA,EAAM,SACJ,CAAC,UAAW,QAAS,MAAO,QAAQS,SAAST,GAGvD,KAGK,IAAIE,EAAWF,GAChBU,OAAOC,KAAK,IAC3B,CAiBqBC,CAAoBjB,GACrC,IAAKM,EAAU,OAEf,MAAMY,EAAUvB,EAASwB,qBAAqBb,GAC9C,IAAKY,EAAS,OAGd,MAAME,EAAWzB,EAAS0B,QAAQH,EAAQzB,KAEtC2B,EAASE,UAAaF,EAASG,UAKnCvB,EAAMwB,iBACNxB,EAAMyB,kBACN9B,EAAS+B,QAAQR,EAAQzB,QAAI,EAAW,aAE5C,CD5CwBkC,CAAqBhC,EAASG,OAEpD8B,SAASC,iBAAiB,UAAW9B,GACrCH,EAAU,IAAMgC,SAASE,oBAAoB,UAAW/B,KAG1DgC,EAAAA,YAAY,KACV,MAAAnC,GAAAA,qBEdWoC,EAAwBC,EAAAA,oBAAoBC,EAAAA,uBACtDC,WAAWC,GACXC,uFHCuB,CACxBC,EACAC,KAEA,MAAM7C,SAAEA,GAAaJ,IACf4B,EAAUsB,EAAAA,IAA4B,MAuB5C,OArBAC,EAAAA,MACE,CAAC/C,EAAU,IAAMgD,UAAQJ,GAAY,IAAMI,EAAAA,QAAQH,IACnD,EAAEI,EAAeC,EAAOC,GAAQC,EAAGC,KACjC,IAAKJ,EAEH,YADAzB,EAAQpB,MAAQ,MAIlBoB,EAAQpB,MAAQ6C,EAActB,QAAQuB,EAAOC,GAQ7CE,EANoBJ,EAAcK,sBAAuBhD,IACnDA,EAAMsC,YAAcM,GAAS5C,EAAMuC,aAAeM,IACpD3B,EAAQpB,MAAQ6C,EAActB,QAAQuB,EAAOC,QAMnD,CAAEI,WAAW,IAGRC,EAAAA,SAAShC,8DAnCe,IAAMiC,YAA0B3D,EAAAA,eAAeC"}
package/dist/vue/index.js DELETED
@@ -1,92 +0,0 @@
1
- import { createPluginPackage } from "@embedpdf/core";
2
- import { CommandsPlugin, CommandsPluginPackage as CommandsPluginPackage$1 } from "@embedpdf/plugin-commands";
3
- export * from "@embedpdf/plugin-commands";
4
- import { ref, watch, toValue, readonly, defineComponent, onMounted, onUnmounted } from "vue";
5
- import { useCapability, usePlugin } from "@embedpdf/core/vue";
6
- const useCommandsCapability = () => useCapability(CommandsPlugin.id);
7
- const useCommandsPlugin = () => usePlugin(CommandsPlugin.id);
8
- const useCommand = (commandId, documentId) => {
9
- const { provides } = useCommandsCapability();
10
- const command = ref(null);
11
- watch(
12
- [provides, () => toValue(commandId), () => toValue(documentId)],
13
- ([providesValue, cmdId, docId], _, onCleanup) => {
14
- if (!providesValue) {
15
- command.value = null;
16
- return;
17
- }
18
- command.value = providesValue.resolve(cmdId, docId);
19
- const unsubscribe = providesValue.onCommandStateChanged((event) => {
20
- if (event.commandId === cmdId && event.documentId === docId) {
21
- command.value = providesValue.resolve(cmdId, docId);
22
- }
23
- });
24
- onCleanup(unsubscribe);
25
- },
26
- { immediate: true }
27
- );
28
- return readonly(command);
29
- };
30
- function buildShortcutString(event) {
31
- const modifiers = [];
32
- if (event.ctrlKey) modifiers.push("ctrl");
33
- if (event.shiftKey) modifiers.push("shift");
34
- if (event.altKey) modifiers.push("alt");
35
- if (event.metaKey) modifiers.push("meta");
36
- let key = event.key.toLowerCase();
37
- if (key === " ") key = "space";
38
- const isModifier = ["control", "shift", "alt", "meta"].includes(key);
39
- if (isModifier) {
40
- return null;
41
- }
42
- const parts = [...modifiers, key];
43
- return parts.sort().join("+");
44
- }
45
- function createKeyDownHandler(commands) {
46
- return (event) => {
47
- const composedPath = event.composedPath();
48
- const target = composedPath[0] || event.target;
49
- if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) {
50
- if (event.key !== "Tab") return;
51
- }
52
- const shortcut = buildShortcutString(event);
53
- if (!shortcut) return;
54
- const command = commands.getCommandByShortcut(shortcut);
55
- if (!command) return;
56
- const resolved = commands.resolve(command.id);
57
- if (resolved.disabled || !resolved.visible) {
58
- return;
59
- }
60
- event.preventDefault();
61
- event.stopPropagation();
62
- commands.execute(command.id, void 0, "keyboard");
63
- };
64
- }
65
- const _sfc_main = /* @__PURE__ */ defineComponent({
66
- __name: "keyboard-shortcuts",
67
- setup(__props) {
68
- const { provides: commands } = useCommandsCapability();
69
- let cleanup = null;
70
- onMounted(() => {
71
- if (!commands.value) return;
72
- const handleKeyDown = createKeyDownHandler(commands.value);
73
- document.addEventListener("keydown", handleKeyDown);
74
- cleanup = () => document.removeEventListener("keydown", handleKeyDown);
75
- });
76
- onUnmounted(() => {
77
- cleanup == null ? void 0 : cleanup();
78
- });
79
- return (_ctx, _cache) => {
80
- return null;
81
- };
82
- }
83
- });
84
- const CommandsPluginPackage = createPluginPackage(CommandsPluginPackage$1).addUtility(_sfc_main).build();
85
- export {
86
- CommandsPluginPackage,
87
- _sfc_main as KeyboardShortcuts,
88
- useCommand,
89
- useCommandsCapability,
90
- useCommandsPlugin
91
- };
92
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":["../../src/vue/hooks/use-commands.ts","../../src/shared/utils/keyboard-handler.ts","../../src/vue/components/keyboard-shortcuts.vue","../../src/vue/index.ts"],"sourcesContent":["import { ref, watch, readonly, toValue, type MaybeRefOrGetter } from 'vue';\r\nimport { useCapability, usePlugin } from '@embedpdf/core/vue';\r\nimport { CommandsPlugin, ResolvedCommand } from '@embedpdf/plugin-commands';\r\n\r\nexport const useCommandsCapability = () => useCapability<CommandsPlugin>(CommandsPlugin.id);\r\nexport const useCommandsPlugin = () => usePlugin<CommandsPlugin>(CommandsPlugin.id);\r\n\r\n/**\r\n * Hook to get a reactive command for a specific document\r\n * @param commandId Command ID (can be ref, computed, getter, or plain value)\r\n * @param documentId Document ID (can be ref, computed, getter, or plain value)\r\n */\r\nexport const useCommand = (\r\n commandId: MaybeRefOrGetter<string>,\r\n documentId: MaybeRefOrGetter<string>,\r\n) => {\r\n const { provides } = useCommandsCapability();\r\n const command = ref<ResolvedCommand | null>(null);\r\n\r\n watch(\r\n [provides, () => toValue(commandId), () => toValue(documentId)],\r\n ([providesValue, cmdId, docId], _, onCleanup) => {\r\n if (!providesValue) {\r\n command.value = null;\r\n return;\r\n }\r\n\r\n command.value = providesValue.resolve(cmdId, docId);\r\n\r\n const unsubscribe = providesValue.onCommandStateChanged((event) => {\r\n if (event.commandId === cmdId && event.documentId === docId) {\r\n command.value = providesValue.resolve(cmdId, docId);\r\n }\r\n });\r\n\r\n onCleanup(unsubscribe);\r\n },\r\n { immediate: true },\r\n );\r\n\r\n return readonly(command);\r\n};\r\n","import { CommandsCapability } from '../../lib/types';\r\n\r\n/**\r\n * Build a shortcut string from a keyboard event\r\n * @example Ctrl+Shift+A -> \"ctrl+shift+a\"\r\n */\r\nexport function buildShortcutString(event: KeyboardEvent): string | null {\r\n const modifiers: string[] = [];\r\n\r\n if (event.ctrlKey) modifiers.push('ctrl');\r\n if (event.shiftKey) modifiers.push('shift');\r\n if (event.altKey) modifiers.push('alt');\r\n if (event.metaKey) modifiers.push('meta');\r\n\r\n // Only add non-modifier keys\r\n let key = event.key.toLowerCase();\r\n if (key === ' ') key = 'space';\r\n const isModifier = ['control', 'shift', 'alt', 'meta'].includes(key);\r\n\r\n if (isModifier) {\r\n return null; // Just a modifier, no command\r\n }\r\n\r\n const parts = [...modifiers, key];\r\n return parts.sort().join('+');\r\n}\r\n\r\n/**\r\n * Handle keyboard events and execute commands based on shortcuts\r\n */\r\nexport function createKeyDownHandler(commands: CommandsCapability) {\r\n return (event: KeyboardEvent) => {\r\n // Use composedPath to get the actual target element, even inside Shadow DOM\r\n const composedPath = event.composedPath();\r\n const target = (composedPath[0] || event.target) as HTMLElement;\r\n\r\n // Don't handle shortcuts if target is an input, textarea, or contentEditable\r\n // Exception: allow Tab/Shift+Tab through for form field navigation\r\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\r\n if (event.key !== 'Tab') return;\r\n }\r\n\r\n const shortcut = buildShortcutString(event);\r\n if (!shortcut) return;\r\n\r\n const command = commands.getCommandByShortcut(shortcut);\r\n if (!command) return;\r\n\r\n // Resolve without document ID - will use active document\r\n const resolved = commands.resolve(command.id);\r\n\r\n if (resolved.disabled || !resolved.visible) {\r\n return;\r\n }\r\n\r\n // Execute and prevent default (documentId is optional now)\r\n event.preventDefault();\r\n event.stopPropagation();\r\n commands.execute(command.id, undefined, 'keyboard');\r\n };\r\n}\r\n","<template>\r\n <!-- This component is only used to set up keyboard shortcuts when the plugin is initialized -->\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { onMounted, onUnmounted } from 'vue';\r\nimport { useCommandsCapability } from '../hooks';\r\nimport { createKeyDownHandler } from '../../shared/utils';\r\n\r\nconst { provides: commands } = useCommandsCapability();\r\n\r\nlet cleanup: (() => void) | null = null;\r\n\r\nonMounted(() => {\r\n if (!commands.value) return;\r\n\r\n const handleKeyDown = createKeyDownHandler(commands.value);\r\n\r\n document.addEventListener('keydown', handleKeyDown);\r\n cleanup = () => document.removeEventListener('keydown', handleKeyDown);\r\n});\r\n\r\nonUnmounted(() => {\r\n cleanup?.();\r\n});\r\n</script>\r\n","import { createPluginPackage } from '@embedpdf/core';\r\nimport { CommandsPluginPackage as BaseCommandsPackage } from '@embedpdf/plugin-commands';\r\n\r\nimport { KeyboardShortcuts } from './components';\r\n\r\nexport * from './hooks';\r\nexport * from './components';\r\nexport * from '@embedpdf/plugin-commands';\r\n\r\nexport const CommandsPluginPackage = createPluginPackage(BaseCommandsPackage)\r\n .addUtility(KeyboardShortcuts)\r\n .build();\r\n"],"names":["BaseCommandsPackage","KeyboardShortcuts"],"mappings":";;;;;AAIO,MAAM,wBAAwB,MAAM,cAA8B,eAAe,EAAE;AACnF,MAAM,oBAAoB,MAAM,UAA0B,eAAe,EAAE;AAO3E,MAAM,aAAa,CACxB,WACA,eACG;AACH,QAAM,EAAE,SAAA,IAAa,sBAAA;AACrB,QAAM,UAAU,IAA4B,IAAI;AAEhD;AAAA,IACE,CAAC,UAAU,MAAM,QAAQ,SAAS,GAAG,MAAM,QAAQ,UAAU,CAAC;AAAA,IAC9D,CAAC,CAAC,eAAe,OAAO,KAAK,GAAG,GAAG,cAAc;AAC/C,UAAI,CAAC,eAAe;AAClB,gBAAQ,QAAQ;AAChB;AAAA,MACF;AAEA,cAAQ,QAAQ,cAAc,QAAQ,OAAO,KAAK;AAElD,YAAM,cAAc,cAAc,sBAAsB,CAAC,UAAU;AACjE,YAAI,MAAM,cAAc,SAAS,MAAM,eAAe,OAAO;AAC3D,kBAAQ,QAAQ,cAAc,QAAQ,OAAO,KAAK;AAAA,QACpD;AAAA,MACF,CAAC;AAED,gBAAU,WAAW;AAAA,IACvB;AAAA,IACA,EAAE,WAAW,KAAA;AAAA,EAAK;AAGpB,SAAO,SAAS,OAAO;AACzB;ACnCO,SAAS,oBAAoB,OAAqC;AACvE,QAAM,YAAsB,CAAA;AAE5B,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AACxC,MAAI,MAAM,SAAU,WAAU,KAAK,OAAO;AAC1C,MAAI,MAAM,OAAQ,WAAU,KAAK,KAAK;AACtC,MAAI,MAAM,QAAS,WAAU,KAAK,MAAM;AAGxC,MAAI,MAAM,MAAM,IAAI,YAAA;AACpB,MAAI,QAAQ,IAAK,OAAM;AACvB,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;AAIzC,QAAI,OAAO,YAAY,WAAW,OAAO,YAAY,cAAc,OAAO,mBAAmB;AAC3F,UAAI,MAAM,QAAQ,MAAO;AAAA,IAC3B;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;;;;ACnDA,UAAM,EAAE,UAAU,SAAA,IAAa,sBAAA;AAE/B,QAAI,UAA+B;AAEnC,cAAU,MAAM;AACd,UAAI,CAAC,SAAS,MAAO;AAErB,YAAM,gBAAgB,qBAAqB,SAAS,KAAK;AAEzD,eAAS,iBAAiB,WAAW,aAAa;AAClD,gBAAU,MAAM,SAAS,oBAAoB,WAAW,aAAa;AAAA,IACvE,CAAC;AAED,gBAAY,MAAM;AAChB;AAAA,IACF,CAAC;;;;;;ACfM,MAAM,wBAAwB,oBAAoBA,uBAAmB,EACzE,WAAWC,SAAiB,EAC5B,MAAA;"}
File without changes