@embedpdf/plugin-ui 1.0.11 → 1.0.13

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 (50) hide show
  1. package/dist/index.cjs +2 -883
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.ts +1 -495
  4. package/dist/index.js +37 -56
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/actions.d.ts +88 -0
  7. package/dist/lib/icons/icon-manager.d.ts +47 -0
  8. package/dist/lib/icons/types.d.ts +36 -0
  9. package/dist/lib/index.d.ts +13 -0
  10. package/dist/lib/manifest.d.ts +4 -0
  11. package/dist/lib/menu/menu-manager.d.ts +98 -0
  12. package/dist/lib/menu/types.d.ts +83 -0
  13. package/dist/lib/menu/utils.d.ts +5 -0
  14. package/dist/lib/reducer.d.ts +5 -0
  15. package/dist/lib/types.d.ts +204 -0
  16. package/dist/lib/ui-component.d.ts +30 -0
  17. package/dist/lib/ui-plugin.d.ts +24 -0
  18. package/dist/lib/utils.d.ts +33 -0
  19. package/dist/preact/adapter.d.ts +5 -0
  20. package/dist/preact/core.d.ts +1 -0
  21. package/dist/preact/index.cjs +2 -130
  22. package/dist/preact/index.cjs.map +1 -1
  23. package/dist/preact/index.d.ts +1 -70
  24. package/dist/preact/index.js +19 -26
  25. package/dist/preact/index.js.map +1 -1
  26. package/dist/react/adapter.d.ts +2 -0
  27. package/dist/react/core.d.ts +1 -0
  28. package/dist/react/index.cjs +2 -2
  29. package/dist/react/index.cjs.map +1 -1
  30. package/dist/react/index.d.ts +1 -2
  31. package/dist/react/index.js +92 -1
  32. package/dist/react/index.js.map +1 -1
  33. package/dist/shared-preact/components/component-wrapper.d.ts +5 -0
  34. package/dist/shared-preact/components/index.d.ts +1 -0
  35. package/dist/shared-preact/components/plugin-ui-provider.d.ts +37 -0
  36. package/dist/shared-preact/hooks/index.d.ts +2 -0
  37. package/dist/shared-preact/hooks/use-icon.d.ts +15 -0
  38. package/dist/shared-preact/hooks/use-ui.d.ts +11 -0
  39. package/dist/shared-preact/index.d.ts +2 -0
  40. package/dist/shared-react/components/component-wrapper.d.ts +5 -0
  41. package/dist/shared-react/components/index.d.ts +1 -0
  42. package/dist/shared-react/components/plugin-ui-provider.d.ts +37 -0
  43. package/dist/shared-react/hooks/index.d.ts +2 -0
  44. package/dist/shared-react/hooks/use-icon.d.ts +15 -0
  45. package/dist/shared-react/hooks/use-ui.d.ts +11 -0
  46. package/dist/shared-react/index.d.ts +2 -0
  47. package/package.json +14 -11
  48. package/dist/index.d.cts +0 -495
  49. package/dist/preact/index.d.cts +0 -70
  50. package/dist/react/index.d.cts +0 -2
package/dist/index.cjs CHANGED
@@ -1,883 +1,2 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- UIComponent: () => UIComponent,
24
- UIPlugin: () => UIPlugin,
25
- UIPluginPackage: () => UIPluginPackage,
26
- UI_PLUGIN_ID: () => UI_PLUGIN_ID,
27
- createEventController: () => createEventController,
28
- defineComponent: () => defineComponent,
29
- hasActive: () => hasActive,
30
- isActive: () => isActive,
31
- isDisabled: () => isDisabled,
32
- isVisible: () => isVisible,
33
- manifest: () => manifest,
34
- resolveMenuItem: () => resolveMenuItem
35
- });
36
- module.exports = __toCommonJS(index_exports);
37
-
38
- // src/lib/ui-plugin.ts
39
- var import_core = require("@embedpdf/core");
40
-
41
- // src/lib/ui-component.ts
42
- var UIComponent = class {
43
- constructor(componentConfig, registry) {
44
- this.children = [];
45
- this.updateCallbacks = [];
46
- this.hadUpdateBeforeListeners = false;
47
- this.componentConfig = componentConfig;
48
- const props = componentConfig.props || {};
49
- if (typeof props === "function") {
50
- const initialProps = props(componentConfig.initialState);
51
- this.props = { ...initialProps, id: componentConfig.id };
52
- } else {
53
- this.props = { ...props, id: componentConfig.id };
54
- }
55
- this.type = componentConfig.type;
56
- this.registry = registry;
57
- }
58
- addChild(id, child, priority = 0, className) {
59
- this.children.push({ id, component: child, priority, className });
60
- this.sortChildren();
61
- }
62
- // Helper to sort children by priority
63
- sortChildren() {
64
- this.children.sort((a, b) => a.priority - b.priority);
65
- }
66
- removeChild(child) {
67
- this.children = this.children.filter((c) => c.component !== child);
68
- }
69
- clearChildren() {
70
- this.children = [];
71
- }
72
- get getRenderType() {
73
- return this.componentConfig.render || this.type;
74
- }
75
- getRenderer() {
76
- return this.registry[this.getRenderType];
77
- }
78
- getChildren() {
79
- return this.children;
80
- }
81
- // Optionally, a component can provide a function to extend the context for its children.
82
- // For instance, a header could supply a "direction" based on its position.
83
- getChildContext(context) {
84
- const childContextProp = this.componentConfig.getChildContext;
85
- if (typeof childContextProp === "function") {
86
- return { ...context, ...childContextProp(this.props) };
87
- } else if (childContextProp && typeof childContextProp === "object") {
88
- return { ...context, ...childContextProp };
89
- }
90
- return context;
91
- }
92
- update(newProps) {
93
- const { id, ...otherProps } = newProps;
94
- this.props = { ...this.props, ...otherProps };
95
- if (this.updateCallbacks.length === 0) {
96
- this.hadUpdateBeforeListeners = true;
97
- }
98
- this.notifyUpdate();
99
- }
100
- onUpdate(callback) {
101
- this.updateCallbacks.push(callback);
102
- return this.hadUpdateBeforeListeners;
103
- }
104
- offUpdate(callback) {
105
- this.updateCallbacks = this.updateCallbacks.filter((cb) => cb !== callback);
106
- }
107
- notifyUpdate() {
108
- this.updateCallbacks.forEach((cb) => cb());
109
- }
110
- };
111
-
112
- // src/lib/actions.ts
113
- var UI_INIT_COMPONENTS = "UI_INIT_COMPONENTS";
114
- var UI_SET_HEADER_VISIBLE = "UI_SET_HEADER_VISIBLE";
115
- var UI_TOGGLE_PANEL = "UI_TOGGLE_PANEL";
116
- var UI_SHOW_COMMAND_MENU = "UI_SHOW_COMMAND_MENU";
117
- var UI_HIDE_COMMAND_MENU = "UI_HIDE_COMMAND_MENU";
118
- var UI_UPDATE_COMPONENT_STATE = "UI_UPDATE_COMPONENT_STATE";
119
- var uiInitComponents = (state) => ({
120
- type: UI_INIT_COMPONENTS,
121
- payload: state
122
- });
123
- var uiTogglePanel = (payload) => ({
124
- type: UI_TOGGLE_PANEL,
125
- payload
126
- });
127
- var uiSetHeaderVisible = (payload) => ({
128
- type: UI_SET_HEADER_VISIBLE,
129
- payload
130
- });
131
- var uiShowCommandMenu = (payload) => ({
132
- type: UI_SHOW_COMMAND_MENU,
133
- payload
134
- });
135
- var uiHideCommandMenu = (payload) => ({
136
- type: UI_HIDE_COMMAND_MENU,
137
- payload
138
- });
139
- var uiUpdateComponentState = (payload) => ({
140
- type: UI_UPDATE_COMPONENT_STATE,
141
- payload
142
- });
143
-
144
- // src/lib/reducer.ts
145
- var initialState = {
146
- panel: {},
147
- header: {},
148
- groupedItems: {},
149
- divider: {},
150
- iconButton: {},
151
- tabButton: {},
152
- selectButton: {},
153
- custom: {},
154
- floating: {},
155
- commandMenu: {}
156
- };
157
- var uiReducer = (state = initialState, action) => {
158
- switch (action.type) {
159
- case UI_INIT_COMPONENTS:
160
- return {
161
- ...state,
162
- ...action.payload
163
- };
164
- case UI_TOGGLE_PANEL: {
165
- const prevPanel = state.panel[action.payload.id] || {};
166
- const { open: nextOpen, visibleChild: nextVisibleChild } = action.payload;
167
- const prevVisibleChild = prevPanel.visibleChild;
168
- let open = prevPanel.open;
169
- let visibleChild = prevPanel.visibleChild;
170
- if (nextVisibleChild === prevVisibleChild) {
171
- open = nextOpen !== void 0 ? nextOpen : !prevPanel.open;
172
- } else {
173
- visibleChild = nextVisibleChild;
174
- open = true;
175
- }
176
- return {
177
- ...state,
178
- panel: {
179
- ...state.panel,
180
- [action.payload.id]: {
181
- ...prevPanel,
182
- open,
183
- visibleChild
184
- }
185
- }
186
- };
187
- }
188
- case UI_SET_HEADER_VISIBLE:
189
- return {
190
- ...state,
191
- header: {
192
- ...state.header,
193
- [action.payload.id]: {
194
- ...state.header[action.payload.id],
195
- visible: action.payload.visible,
196
- visibleChild: action.payload.visibleChild
197
- }
198
- }
199
- };
200
- case UI_SHOW_COMMAND_MENU:
201
- return {
202
- ...state,
203
- commandMenu: {
204
- ...state.commandMenu,
205
- [action.payload.id]: {
206
- activeCommand: action.payload.commandId,
207
- triggerElement: action.payload.triggerElement,
208
- position: action.payload.position,
209
- open: true,
210
- flatten: action.payload.flatten
211
- }
212
- }
213
- };
214
- case UI_HIDE_COMMAND_MENU:
215
- return {
216
- ...state,
217
- commandMenu: {
218
- ...state.commandMenu,
219
- [action.payload.id]: {
220
- ...state.commandMenu[action.payload.id],
221
- open: false,
222
- activeCommand: null,
223
- triggerElement: void 0,
224
- position: void 0,
225
- flatten: false
226
- }
227
- }
228
- };
229
- case UI_UPDATE_COMPONENT_STATE: {
230
- const { componentType, componentId, patch } = action.payload;
231
- if (!state[componentType] || !state[componentType][componentId]) return state;
232
- const current = state[componentType][componentId];
233
- const filteredPatch = Object.fromEntries(Object.entries(patch).filter(([k]) => k in current));
234
- if (Object.keys(filteredPatch).length === 0) return state;
235
- return {
236
- ...state,
237
- [componentType]: {
238
- ...state[componentType],
239
- [componentId]: {
240
- ...current,
241
- ...filteredPatch
242
- }
243
- }
244
- };
245
- }
246
- default:
247
- return state;
248
- }
249
- };
250
-
251
- // src/lib/utils.ts
252
- function defineComponent() {
253
- return (c) => c;
254
- }
255
- function createEventController() {
256
- const eventMap = /* @__PURE__ */ new Map();
257
- return {
258
- emit(eventType, data) {
259
- const callbacks = eventMap.get(eventType);
260
- if (callbacks) {
261
- callbacks.forEach((callback) => callback(data));
262
- }
263
- },
264
- on(eventType, callback) {
265
- if (!eventMap.has(eventType)) {
266
- eventMap.set(eventType, /* @__PURE__ */ new Set());
267
- }
268
- const callbacks = eventMap.get(eventType);
269
- callbacks.add(callback);
270
- return () => this.off(eventType, callback);
271
- },
272
- off(eventType, callback) {
273
- const callbacks = eventMap.get(eventType);
274
- if (callbacks) {
275
- callbacks.delete(callback);
276
- if (callbacks.size === 0) {
277
- eventMap.delete(eventType);
278
- }
279
- }
280
- }
281
- };
282
- }
283
-
284
- // src/lib/menu/utils.ts
285
- function resolveMenuItem(item, state) {
286
- const dyn = (v) => typeof v === "function" ? v(state) : v;
287
- if (item.type === "group") {
288
- return {
289
- ...item,
290
- label: dyn(item.label) ?? ""
291
- };
292
- }
293
- return {
294
- ...item,
295
- icon: dyn(item.icon) ?? "",
296
- label: dyn(item.label) ?? "",
297
- visible: dyn(item.visible) ?? true,
298
- active: dyn(item.active) ?? false,
299
- disabled: dyn(item.disabled) ?? false
300
- };
301
- }
302
- function isActive(item, state) {
303
- const resolved = resolveMenuItem(item, state);
304
- if (resolved.type === "group") {
305
- return false;
306
- }
307
- return resolved.active ? true : false;
308
- }
309
- function isVisible(item, state) {
310
- const resolved = resolveMenuItem(item, state);
311
- if (resolved.type === "group") {
312
- return false;
313
- }
314
- return resolved.visible ? true : false;
315
- }
316
- function isDisabled(item, state) {
317
- const resolved = resolveMenuItem(item, state);
318
- if (resolved.type === "group") {
319
- return false;
320
- }
321
- return resolved.disabled ? true : false;
322
- }
323
-
324
- // src/lib/menu/menu-manager.ts
325
- var _MenuManager = class _MenuManager {
326
- constructor(items = {}, pluginRegistry) {
327
- this.registry = {};
328
- this.shortcutMap = {};
329
- // maps shortcut to menu item id
330
- this.eventController = createEventController();
331
- this.pluginRegistry = pluginRegistry;
332
- this.registerItems(items);
333
- this.setupKeyboardListeners();
334
- }
335
- /**
336
- * Get the current state of the plugin registry
337
- */
338
- get state() {
339
- return this.pluginRegistry.getStore().getState();
340
- }
341
- /**
342
- * Register a single menu item
343
- */
344
- registerItem(item) {
345
- if (this.registry[item.id]) {
346
- console.warn(`Menu item with ID ${item.id} already exists and will be overwritten`);
347
- }
348
- this.registry[item.id] = item;
349
- if ("shortcut" in item && item.shortcut) {
350
- this.shortcutMap[this.normalizeShortcut(item.shortcut)] = item.id;
351
- }
352
- }
353
- /**
354
- * Register multiple menu items at once
355
- */
356
- registerItems(items) {
357
- Object.values(items).forEach((item) => {
358
- this.registerItem(item);
359
- });
360
- }
361
- /**
362
- * Resolve a menu item by ID
363
- */
364
- resolve(id) {
365
- const raw = this.registry[id];
366
- return resolveMenuItem(raw, this.state);
367
- }
368
- /**
369
- * Get a menu item by ID with type information
370
- */
371
- getMenuItem(id) {
372
- const item = this.resolve(id);
373
- if (!item) return void 0;
374
- return {
375
- item,
376
- isGroup: item.type === "group",
377
- isMenu: item.type === "menu",
378
- isAction: item.type === "action"
379
- };
380
- }
381
- /**
382
- * Get a action by ID (only returns Action type items)
383
- */
384
- getAction(id) {
385
- const resolved = this.getMenuItem(id);
386
- if (!resolved || !resolved.isAction) return void 0;
387
- return resolved.item;
388
- }
389
- /**
390
- * Get menu or action by ID
391
- */
392
- getMenuOrAction(id) {
393
- const resolved = this.getMenuItem(id);
394
- if (!resolved) return void 0;
395
- return resolved.item;
396
- }
397
- /**
398
- * Get all registered menu items
399
- */
400
- getAllItems() {
401
- return { ...this.registry };
402
- }
403
- /**
404
- * Get menu items by their IDs
405
- */
406
- getItemsByIds(ids) {
407
- return ids.map((id) => this.resolve(id)).filter((item) => item !== void 0);
408
- }
409
- /**
410
- * Get child items for a given menu ID
411
- * If flatten is true, it will recursively include submenu children but not groups
412
- */
413
- getChildItems(menuId, options = {}) {
414
- const item = this.resolve(menuId);
415
- if (!item || !("children" in item) || !item.children?.length) {
416
- return [];
417
- }
418
- const children = this.getItemsByIds(item.children);
419
- if (!options.flatten) {
420
- return children;
421
- }
422
- const flattened = [];
423
- for (const child of children) {
424
- if (child.type === "group") {
425
- flattened.push(child);
426
- } else if (child.type === "menu") {
427
- const menuChildren = this.getChildItems(child.id, { flatten: true });
428
- flattened.push(...menuChildren);
429
- } else {
430
- flattened.push(child);
431
- }
432
- }
433
- return flattened;
434
- }
435
- /**
436
- * Execute a command by ID
437
- */
438
- executeCommand(id, options = {}) {
439
- const resolved = this.getMenuItem(id);
440
- if (!resolved) {
441
- console.warn(`Menu item '${id}' not found`);
442
- return;
443
- }
444
- if (resolved.item.type === "group") {
445
- console.warn(`Cannot execute group '${id}'`);
446
- return;
447
- }
448
- const { item } = resolved;
449
- if (item.disabled) {
450
- console.warn(`Menu item '${id}' is disabled`);
451
- return;
452
- }
453
- if (resolved.isAction) {
454
- item.action(this.pluginRegistry, this.state);
455
- this.eventController.emit(_MenuManager.EVENTS.COMMAND_EXECUTED, {
456
- command: item,
457
- source: options.source || "api"
458
- });
459
- } else if ("children" in item && item.children?.length) {
460
- this.handleSubmenu(item, options);
461
- }
462
- }
463
- /**
464
- * Execute a command from a keyboard shortcut
465
- */
466
- executeShortcut(shortcut) {
467
- const normalizedShortcut = this.normalizeShortcut(shortcut);
468
- const itemId = this.shortcutMap[normalizedShortcut];
469
- if (itemId) {
470
- this.executeCommand(itemId, { source: "shortcut" });
471
- this.eventController.emit(_MenuManager.EVENTS.SHORTCUT_EXECUTED, {
472
- shortcut: normalizedShortcut,
473
- itemId
474
- });
475
- return true;
476
- }
477
- return false;
478
- }
479
- /**
480
- * Subscribe to menu events
481
- */
482
- on(eventType, callback) {
483
- return this.eventController.on(eventType, callback);
484
- }
485
- /**
486
- * Remove an event subscription
487
- */
488
- off(eventType, callback) {
489
- this.eventController.off(eventType, callback);
490
- }
491
- /**
492
- * Handle a menu item that has children (showing a submenu)
493
- */
494
- handleSubmenu(menuItem, options) {
495
- this.eventController.emit(_MenuManager.EVENTS.MENU_REQUESTED, {
496
- menuId: menuItem.id,
497
- triggerElement: options.triggerElement,
498
- position: options.position,
499
- flatten: options.flatten || false
500
- });
501
- }
502
- /**
503
- * Set up keyboard listeners for shortcuts
504
- */
505
- setupKeyboardListeners() {
506
- if (typeof window === "undefined") return;
507
- const handleKeyDown = (event) => {
508
- const target = event.target;
509
- if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) {
510
- return;
511
- }
512
- const shortcut = this.buildShortcutString(event);
513
- if (shortcut && this.executeShortcut(shortcut)) {
514
- event.preventDefault();
515
- }
516
- };
517
- document.addEventListener("keydown", handleKeyDown);
518
- }
519
- /**
520
- * Convert a KeyboardEvent to a shortcut string
521
- */
522
- buildShortcutString(event) {
523
- const modifiers = [];
524
- if (event.ctrlKey) modifiers.push("Ctrl");
525
- if (event.shiftKey) modifiers.push("Shift");
526
- if (event.altKey) modifiers.push("Alt");
527
- if (event.metaKey) modifiers.push("Meta");
528
- const key = event.key;
529
- const isModifier = ["Control", "Shift", "Alt", "Meta"].includes(key);
530
- if (!isModifier) {
531
- const displayKey = key.length === 1 ? key.toUpperCase() : key;
532
- return [...modifiers, displayKey].join("+");
533
- }
534
- return null;
535
- }
536
- /**
537
- * Normalize a shortcut string for consistent comparison
538
- */
539
- normalizeShortcut(shortcut) {
540
- return shortcut.split("+").map((part) => part.trim()).join("+");
541
- }
542
- /**
543
- * Get capabilities for the MenuManager
544
- */
545
- capabilities() {
546
- return {
547
- registerItem: this.registerItem.bind(this),
548
- registerItems: this.registerItems.bind(this),
549
- executeCommand: this.executeCommand.bind(this),
550
- getAction: this.getAction.bind(this),
551
- getMenuOrAction: this.getMenuOrAction.bind(this),
552
- getChildItems: this.getChildItems.bind(this),
553
- getItemsByIds: this.getItemsByIds.bind(this),
554
- getAllItems: this.getAllItems.bind(this)
555
- };
556
- }
557
- };
558
- // Event types
559
- _MenuManager.EVENTS = {
560
- COMMAND_EXECUTED: "menu:command_executed",
561
- MENU_REQUESTED: "menu:requested",
562
- SHORTCUT_EXECUTED: "menu:shortcut_executed"
563
- };
564
- var MenuManager = _MenuManager;
565
-
566
- // src/lib/icons/icon-manager.ts
567
- var IconManager = class {
568
- constructor(icons) {
569
- this.icons = {};
570
- this.registerIcons(icons);
571
- }
572
- /**
573
- * Register a single icon
574
- */
575
- registerIcon(icon) {
576
- if (this.icons[icon.id]) {
577
- console.warn(`Icon with ID ${icon.id} already exists and will be overwritten`);
578
- }
579
- this.icons[icon.id] = icon;
580
- }
581
- /**
582
- * Register multiple icons at once
583
- */
584
- registerIcons(icons) {
585
- if (Array.isArray(icons)) {
586
- icons.forEach((icon) => this.registerIcon(icon));
587
- } else {
588
- Object.entries(icons).forEach(([id, icon]) => this.registerIcon(icon));
589
- }
590
- }
591
- /**
592
- * Get all registered icons
593
- */
594
- getAllIcons() {
595
- return { ...this.icons };
596
- }
597
- /**
598
- * Get an icon by its ID
599
- */
600
- getIcon(id) {
601
- return this.icons[id];
602
- }
603
- /**
604
- * Check if an identifier is an SVG string
605
- */
606
- isSvgString(identifier) {
607
- return identifier.trim().startsWith("<svg") && identifier.includes("</svg>");
608
- }
609
- /**
610
- * Check if a string is an SVG data URI
611
- */
612
- isSvgDataUri(value) {
613
- return value.startsWith("data:image/svg+xml;base64,");
614
- }
615
- /**
616
- * Get the SVG string for an icon identifier
617
- * If the identifier is a raw SVG string, it is returned as is
618
- * If the identifier is an icon ID, the registered SVG is returned
619
- */
620
- getSvgString(identifier) {
621
- if (this.isSvgString(identifier)) {
622
- return identifier;
623
- }
624
- if (this.isSvgDataUri(identifier)) {
625
- return this.dataUriToSvgString(identifier);
626
- }
627
- return this.getIcon(identifier)?.svg;
628
- }
629
- /**
630
- * Utility method to parse a data URI
631
- */
632
- dataUriToSvgString(dataUri) {
633
- const base64 = dataUri.substring("data:image/svg+xml;base64,".length);
634
- return atob(base64);
635
- }
636
- /**
637
- * Convert an SVG string to a data URI
638
- */
639
- svgStringToDataUri(svgString) {
640
- const base64 = btoa(svgString);
641
- return `data:image/svg+xml;base64,${base64}`;
642
- }
643
- capabilities() {
644
- return {
645
- registerIcon: this.registerIcon.bind(this),
646
- registerIcons: this.registerIcons.bind(this),
647
- getIcon: this.getIcon.bind(this),
648
- getAllIcons: this.getAllIcons.bind(this),
649
- getSvgString: this.getSvgString.bind(this),
650
- isSvgString: this.isSvgString.bind(this),
651
- isSvgDataUri: this.isSvgDataUri.bind(this),
652
- dataUriToSvgString: this.dataUriToSvgString.bind(this),
653
- svgStringToDataUri: this.svgStringToDataUri.bind(this)
654
- };
655
- }
656
- };
657
-
658
- // src/lib/ui-plugin.ts
659
- var UIPlugin = class extends import_core.BasePlugin {
660
- constructor(id, registry, config) {
661
- super(id, registry);
662
- this.componentRenderers = {};
663
- this.components = {};
664
- this.mapStateCallbacks = {};
665
- this.globalStoreSubscription = () => {
666
- };
667
- this.config = config;
668
- this.menuManager = new MenuManager(config.menuItems || {}, this.registry);
669
- this.iconManager = new IconManager(config.icons || []);
670
- this.setupCommandEventHandlers();
671
- this.globalStoreSubscription = this.registry.getStore().subscribe((_action, newState) => {
672
- this.onGlobalStoreChange(newState);
673
- });
674
- }
675
- async initialize() {
676
- this.buildComponents();
677
- this.linkGroupedItems();
678
- this.setInitialStateUIComponents();
679
- }
680
- // Set up handlers for command events
681
- setupCommandEventHandlers() {
682
- this.menuManager.on(MenuManager.EVENTS.MENU_REQUESTED, (data) => {
683
- const { menuId, triggerElement, position, flatten } = data;
684
- const isOpen = this.state.commandMenu.commandMenu?.activeCommand === menuId;
685
- if (isOpen) {
686
- return this.dispatch(uiHideCommandMenu({ id: "commandMenu" }));
687
- }
688
- this.dispatch(
689
- uiShowCommandMenu({
690
- id: "commandMenu",
691
- commandId: menuId,
692
- triggerElement,
693
- position,
694
- flatten
695
- })
696
- );
697
- });
698
- this.menuManager.on(MenuManager.EVENTS.COMMAND_EXECUTED, (data) => {
699
- console.log("Command executed:", data.command.id, "source:", data.source);
700
- });
701
- }
702
- addComponent(id, componentConfig) {
703
- if (this.components[id]) {
704
- console.warn(`Component with ID ${id} already exists and will be overwritten`);
705
- }
706
- const component = new UIComponent(componentConfig, this.componentRenderers);
707
- this.components[id] = component;
708
- if (typeof componentConfig.mapStateToProps === "function") {
709
- this.mapStateCallbacks[id] = componentConfig.mapStateToProps;
710
- }
711
- return component;
712
- }
713
- buildComponents() {
714
- Object.entries(this.config.components).forEach(([id, componentConfig]) => {
715
- this.addComponent(id, componentConfig);
716
- });
717
- }
718
- linkGroupedItems() {
719
- Object.values(this.components).forEach((component) => {
720
- if (isItemWithSlots(component)) {
721
- const props = component.componentConfig;
722
- props.slots?.forEach((slot) => {
723
- const child = this.components[slot.componentId];
724
- if (child) {
725
- component.addChild(slot.componentId, child, slot.priority, slot.className);
726
- } else {
727
- console.warn(
728
- `Child component ${slot.componentId} not found for GroupedItems ${props.id}`
729
- );
730
- }
731
- });
732
- }
733
- });
734
- }
735
- setInitialStateUIComponents() {
736
- const defaultState = initialState;
737
- Object.entries(this.config.components).forEach(([componentId, definition]) => {
738
- if (definition.initialState) {
739
- defaultState[definition.type][componentId] = definition.initialState;
740
- } else {
741
- defaultState[definition.type][componentId] = {};
742
- }
743
- });
744
- this.dispatch(uiInitComponents(defaultState));
745
- }
746
- onGlobalStoreChange(state) {
747
- for (const [id, uiComponent] of Object.entries(this.components)) {
748
- const mapFn = this.mapStateCallbacks[id];
749
- if (!mapFn) continue;
750
- const { id: _id, ...ownProps } = uiComponent.props;
751
- const partial = mapFn(state, ownProps);
752
- const merged = { ...ownProps, ...partial };
753
- if (!(0, import_core.arePropsEqual)(ownProps, merged)) {
754
- uiComponent.update(partial);
755
- }
756
- }
757
- }
758
- addSlot(parentId, slotId, priority, className) {
759
- const parentComponent = this.components[parentId];
760
- if (!parentComponent) {
761
- console.error(`Parent component ${parentId} not found`);
762
- return;
763
- }
764
- if (!isItemWithSlots(parentComponent)) {
765
- console.error(`Parent component ${parentId} does not support slots`);
766
- return;
767
- }
768
- const childComponent = this.components[slotId];
769
- if (!childComponent) {
770
- console.error(`Child component ${slotId} not found`);
771
- return;
772
- }
773
- const parentChildren = parentComponent.getChildren();
774
- let slotPriority = priority;
775
- if (slotPriority === void 0) {
776
- const maxPriority = parentChildren.length > 0 ? Math.max(...parentChildren.map((child) => child.priority)) : 0;
777
- slotPriority = maxPriority + 10;
778
- }
779
- parentComponent.addChild(slotId, childComponent, slotPriority, className);
780
- }
781
- buildCapability() {
782
- return {
783
- registerComponentRenderer: (type, renderer) => {
784
- this.componentRenderers[type] = renderer;
785
- },
786
- getComponent: (id) => {
787
- return this.components[id];
788
- },
789
- registerComponent: this.addComponent.bind(this),
790
- getCommandMenu: () => Object.values(this.components).find((component) => isCommandMenuComponent(component)),
791
- hideCommandMenu: () => this.debouncedDispatch(uiHideCommandMenu({ id: "commandMenu" }), 100),
792
- getFloatingComponents: (scrollerPosition) => Object.values(this.components).filter((component) => isFloatingComponent(component)).filter(
793
- (component) => !scrollerPosition || component.props.scrollerPosition === scrollerPosition
794
- ),
795
- getHeadersByPlacement: (placement) => Object.values(this.components).filter((component) => isHeaderComponent(component)).filter((component) => component.props.placement === placement),
796
- getPanelsByLocation: (location) => Object.values(this.components).filter((component) => isPanelComponent(component)).filter((component) => component.props.location === location),
797
- addSlot: this.addSlot.bind(this),
798
- togglePanel: (payload) => {
799
- this.dispatch(uiTogglePanel(payload));
800
- },
801
- setHeaderVisible: (payload) => {
802
- this.dispatch(uiSetHeaderVisible(payload));
803
- },
804
- updateComponentState: (payload) => {
805
- this.dispatch(uiUpdateComponentState(payload));
806
- },
807
- ...this.iconManager.capabilities(),
808
- ...this.menuManager.capabilities()
809
- };
810
- }
811
- async destroy() {
812
- this.globalStoreSubscription();
813
- this.components = {};
814
- this.componentRenderers = {};
815
- this.mapStateCallbacks = {};
816
- }
817
- };
818
- UIPlugin.id = "ui";
819
- function isItemWithSlots(component) {
820
- return isGroupedItemsComponent(component) || isHeaderComponent(component) || isPanelComponent(component) || isFloatingComponent(component) || isCustomComponent(component);
821
- }
822
- function isGroupedItemsComponent(component) {
823
- return component.type === "groupedItems";
824
- }
825
- function isHeaderComponent(component) {
826
- return component.type === "header";
827
- }
828
- function isPanelComponent(component) {
829
- return component.type === "panel";
830
- }
831
- function isFloatingComponent(component) {
832
- return component.type === "floating";
833
- }
834
- function isCommandMenuComponent(component) {
835
- return component.type === "commandMenu";
836
- }
837
- function isCustomComponent(component) {
838
- return component.type === "custom";
839
- }
840
-
841
- // src/lib/manifest.ts
842
- var UI_PLUGIN_ID = "ui";
843
- var manifest = {
844
- id: UI_PLUGIN_ID,
845
- name: "UI Plugin",
846
- version: "1.0.0",
847
- provides: ["ui"],
848
- requires: [],
849
- optional: [],
850
- defaultConfig: {
851
- enabled: true,
852
- components: {}
853
- }
854
- };
855
-
856
- // src/lib/menu/types.ts
857
- function hasActive(command) {
858
- return "active" in command;
859
- }
860
-
861
- // src/lib/index.ts
862
- var UIPluginPackage = {
863
- manifest,
864
- create: (registry, _engine, config) => new UIPlugin(UI_PLUGIN_ID, registry, config),
865
- reducer: uiReducer,
866
- initialState
867
- };
868
- // Annotate the CommonJS export names for ESM import in node:
869
- 0 && (module.exports = {
870
- UIComponent,
871
- UIPlugin,
872
- UIPluginPackage,
873
- UI_PLUGIN_ID,
874
- createEventController,
875
- defineComponent,
876
- hasActive,
877
- isActive,
878
- isDisabled,
879
- isVisible,
880
- manifest,
881
- resolveMenuItem
882
- });
883
- //# sourceMappingURL=index.cjs.map
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("@embedpdf/core");class e{constructor(t,e){this.children=[],this.updateCallbacks=[],this.hadUpdateBeforeListeners=!1,this.componentConfig=t;const i=t.props||{};if("function"==typeof i){const e=i(t.initialState);this.props={...e,id:t.id}}else this.props={...i,id:t.id};this.type=t.type,this.registry=e}addChild(t,e,i=0,n){this.children.push({id:t,component:e,priority:i,className:n}),this.sortChildren()}sortChildren(){this.children.sort(((t,e)=>t.priority-e.priority))}removeChild(t){this.children=this.children.filter((e=>e.component!==t))}clearChildren(){this.children=[]}get getRenderType(){return this.componentConfig.render||this.type}getRenderer(){return this.registry[this.getRenderType]}getChildren(){return this.children}getChildContext(t){const e=this.componentConfig.getChildContext;return"function"==typeof e?{...t,...e(this.props)}:e&&"object"==typeof e?{...t,...e}:t}update(t){const{id:e,...i}=t;this.props={...this.props,...i},0===this.updateCallbacks.length&&(this.hadUpdateBeforeListeners=!0),this.notifyUpdate()}onUpdate(t){return this.updateCallbacks.push(t),this.hadUpdateBeforeListeners}offUpdate(t){this.updateCallbacks=this.updateCallbacks.filter((e=>e!==t))}notifyUpdate(){this.updateCallbacks.forEach((t=>t()))}}const i="UI_INIT_COMPONENTS",n="UI_SET_HEADER_VISIBLE",s="UI_TOGGLE_PANEL",o="UI_SHOW_COMMAND_MENU",r="UI_HIDE_COMMAND_MENU",a="UI_UPDATE_COMPONENT_STATE",c=t=>({type:r,payload:t}),l={panel:{},header:{},groupedItems:{},divider:{},iconButton:{},tabButton:{},selectButton:{},custom:{},floating:{},commandMenu:{}};function d(){const t=new Map;return{emit(e,i){const n=t.get(e);n&&n.forEach((t=>t(i)))},on(e,i){t.has(e)||t.set(e,new Set);return t.get(e).add(i),()=>this.off(e,i)},off(e,i){const n=t.get(e);n&&(n.delete(i),0===n.size&&t.delete(e))}}}function h(t,e){const i=t=>"function"==typeof t?t(e):t;return"group"===t.type?{...t,label:i(t.label)??""}:{...t,icon:i(t.icon)??"",label:i(t.label)??"",visible:i(t.visible)??!0,active:i(t.active)??!1,disabled:i(t.disabled)??!1}}const p=class t{constructor(t={},e){this.registry={},this.shortcutMap={},this.eventController=d(),this.pluginRegistry=e,this.registerItems(t),this.setupKeyboardListeners()}get state(){return this.pluginRegistry.getStore().getState()}registerItem(t){this.registry[t.id]&&console.warn(`Menu item with ID ${t.id} already exists and will be overwritten`),this.registry[t.id]=t,"shortcut"in t&&t.shortcut&&(this.shortcutMap[this.normalizeShortcut(t.shortcut)]=t.id)}registerItems(t){Object.values(t).forEach((t=>{this.registerItem(t)}))}resolve(t){return h(this.registry[t],this.state)}getMenuItem(t){const e=this.resolve(t);if(e)return{item:e,isGroup:"group"===e.type,isMenu:"menu"===e.type,isAction:"action"===e.type}}getAction(t){const e=this.getMenuItem(t);if(e&&e.isAction)return e.item}getMenuOrAction(t){const e=this.getMenuItem(t);if(e)return e.item}getAllItems(){return{...this.registry}}getItemsByIds(t){return t.map((t=>this.resolve(t))).filter((t=>void 0!==t))}getChildItems(t,e={}){var i;const n=this.resolve(t);if(!n||!("children"in n)||!(null==(i=n.children)?void 0:i.length))return[];const s=this.getItemsByIds(n.children);if(!e.flatten)return s;const o=[];for(const r of s)if("group"===r.type)o.push(r);else if("menu"===r.type){const t=this.getChildItems(r.id,{flatten:!0});o.push(...t)}else o.push(r);return o}executeCommand(e,i={}){var n;const s=this.getMenuItem(e);if(!s)return void console.warn(`Menu item '${e}' not found`);if("group"===s.item.type)return void console.warn(`Cannot execute group '${e}'`);const{item:o}=s;o.disabled?console.warn(`Menu item '${e}' is disabled`):s.isAction?(o.action(this.pluginRegistry,this.state),this.eventController.emit(t.EVENTS.COMMAND_EXECUTED,{command:o,source:i.source||"api"})):"children"in o&&(null==(n=o.children)?void 0:n.length)&&this.handleSubmenu(o,i)}executeShortcut(e){const i=this.normalizeShortcut(e),n=this.shortcutMap[i];return!!n&&(this.executeCommand(n,{source:"shortcut"}),this.eventController.emit(t.EVENTS.SHORTCUT_EXECUTED,{shortcut:i,itemId:n}),!0)}on(t,e){return this.eventController.on(t,e)}off(t,e){this.eventController.off(t,e)}handleSubmenu(e,i){this.eventController.emit(t.EVENTS.MENU_REQUESTED,{menuId:e.id,triggerElement:i.triggerElement,position:i.position,flatten:i.flatten||!1})}setupKeyboardListeners(){if("undefined"==typeof window)return;document.addEventListener("keydown",(t=>{const e=t.target;if("INPUT"===e.tagName||"TEXTAREA"===e.tagName||e.isContentEditable)return;const i=this.buildShortcutString(t);i&&this.executeShortcut(i)&&t.preventDefault()}))}buildShortcutString(t){const e=[];t.ctrlKey&&e.push("Ctrl"),t.shiftKey&&e.push("Shift"),t.altKey&&e.push("Alt"),t.metaKey&&e.push("Meta");const i=t.key;if(!["Control","Shift","Alt","Meta"].includes(i)){const t=1===i.length?i.toUpperCase():i;return[...e,t].join("+")}return null}normalizeShortcut(t){return t.split("+").map((t=>t.trim())).join("+")}capabilities(){return{registerItem:this.registerItem.bind(this),registerItems:this.registerItems.bind(this),executeCommand:this.executeCommand.bind(this),getAction:this.getAction.bind(this),getMenuOrAction:this.getMenuOrAction.bind(this),getChildItems:this.getChildItems.bind(this),getItemsByIds:this.getItemsByIds.bind(this),getAllItems:this.getAllItems.bind(this)}}};p.EVENTS={COMMAND_EXECUTED:"menu:command_executed",MENU_REQUESTED:"menu:requested",SHORTCUT_EXECUTED:"menu:shortcut_executed"};let u=p;class m{constructor(t){this.icons={},this.registerIcons(t)}registerIcon(t){this.icons[t.id]&&console.warn(`Icon with ID ${t.id} already exists and will be overwritten`),this.icons[t.id]=t}registerIcons(t){Array.isArray(t)?t.forEach((t=>this.registerIcon(t))):Object.entries(t).forEach((([t,e])=>this.registerIcon(e)))}getAllIcons(){return{...this.icons}}getIcon(t){return this.icons[t]}isSvgString(t){return t.trim().startsWith("<svg")&&t.includes("</svg>")}isSvgDataUri(t){return t.startsWith("data:image/svg+xml;base64,")}getSvgString(t){var e;return this.isSvgString(t)?t:this.isSvgDataUri(t)?this.dataUriToSvgString(t):null==(e=this.getIcon(t))?void 0:e.svg}dataUriToSvgString(t){const e=t.substring(26);return atob(e)}svgStringToDataUri(t){return`data:image/svg+xml;base64,${btoa(t)}`}capabilities(){return{registerIcon:this.registerIcon.bind(this),registerIcons:this.registerIcons.bind(this),getIcon:this.getIcon.bind(this),getAllIcons:this.getAllIcons.bind(this),getSvgString:this.getSvgString.bind(this),isSvgString:this.isSvgString.bind(this),isSvgDataUri:this.isSvgDataUri.bind(this),dataUriToSvgString:this.dataUriToSvgString.bind(this),svgStringToDataUri:this.svgStringToDataUri.bind(this)}}}const g=class extends t.BasePlugin{constructor(t,e,i){super(t,e),this.componentRenderers={},this.components={},this.mapStateCallbacks={},this.globalStoreSubscription=()=>{},this.config=i,this.menuManager=new u(i.menuItems||{},this.registry),this.iconManager=new m(i.icons||[]),this.setupCommandEventHandlers(),this.globalStoreSubscription=this.registry.getStore().subscribe(((t,e)=>{this.onGlobalStoreChange(e)}))}async initialize(){this.buildComponents(),this.linkGroupedItems(),this.setInitialStateUIComponents()}setupCommandEventHandlers(){this.menuManager.on(u.EVENTS.MENU_REQUESTED,(t=>{var e;const{menuId:i,triggerElement:n,position:s,flatten:r}=t;if((null==(e=this.state.commandMenu.commandMenu)?void 0:e.activeCommand)===i)return this.dispatch(c({id:"commandMenu"}));this.dispatch({type:o,payload:{id:"commandMenu",commandId:i,triggerElement:n,position:s,flatten:r}})})),this.menuManager.on(u.EVENTS.COMMAND_EXECUTED,(t=>{console.log("Command executed:",t.command.id,"source:",t.source)}))}addComponent(t,i){this.components[t]&&console.warn(`Component with ID ${t} already exists and will be overwritten`);const n=new e(i,this.componentRenderers);return this.components[t]=n,"function"==typeof i.mapStateToProps&&(this.mapStateCallbacks[t]=i.mapStateToProps),n}buildComponents(){Object.entries(this.config.components).forEach((([t,e])=>{this.addComponent(t,e)}))}linkGroupedItems(){Object.values(this.components).forEach((t=>{var e;if(b(t)){const i=t.componentConfig;null==(e=i.slots)||e.forEach((e=>{const n=this.components[e.componentId];n?t.addChild(e.componentId,n,e.priority,e.className):console.warn(`Child component ${e.componentId} not found for GroupedItems ${i.id}`)}))}}))}setInitialStateUIComponents(){const t=l;Object.entries(this.config.components).forEach((([e,i])=>{i.initialState?t[i.type][e]=i.initialState:t[i.type][e]={}})),this.dispatch({type:i,payload:t})}onGlobalStoreChange(e){for(const[i,n]of Object.entries(this.components)){const s=this.mapStateCallbacks[i];if(!s)continue;const{id:o,...r}=n.props,a=s(e,r),c={...r,...a};t.arePropsEqual(r,c)||n.update(a)}}addSlot(t,e,i,n){const s=this.components[t];if(!s)return void console.error(`Parent component ${t} not found`);if(!b(s))return void console.error(`Parent component ${t} does not support slots`);const o=this.components[e];if(!o)return void console.error(`Child component ${e} not found`);const r=s.getChildren();let a=i;if(void 0===a){a=(r.length>0?Math.max(...r.map((t=>t.priority))):0)+10}s.addChild(e,o,a,n)}buildCapability(){return{registerComponentRenderer:(t,e)=>{this.componentRenderers[t]=e},getComponent:t=>this.components[t],registerComponent:this.addComponent.bind(this),getCommandMenu:()=>Object.values(this.components).find((t=>function(t){return"commandMenu"===t.type}(t))),hideCommandMenu:()=>this.debouncedDispatch(c({id:"commandMenu"}),100),getFloatingComponents:t=>Object.values(this.components).filter((t=>v(t))).filter((e=>!t||e.props.scrollerPosition===t)),getHeadersByPlacement:t=>Object.values(this.components).filter((t=>y(t))).filter((e=>e.props.placement===t)),getPanelsByLocation:t=>Object.values(this.components).filter((t=>C(t))).filter((e=>e.props.location===t)),addSlot:this.addSlot.bind(this),togglePanel:t=>{this.dispatch((t=>({type:s,payload:t}))(t))},setHeaderVisible:t=>{this.dispatch((t=>({type:n,payload:t}))(t))},updateComponentState:t=>{this.dispatch((t=>({type:a,payload:t}))(t))},...this.iconManager.capabilities(),...this.menuManager.capabilities()}}async destroy(){this.globalStoreSubscription(),this.components={},this.componentRenderers={},this.mapStateCallbacks={}}};g.id="ui";let f=g;function b(t){return function(t){return"groupedItems"===t.type}(t)||y(t)||C(t)||v(t)||function(t){return"custom"===t.type}(t)}function y(t){return"header"===t.type}function C(t){return"panel"===t.type}function v(t){return"floating"===t.type}const S="ui",I={id:S,name:"UI Plugin",version:"1.0.0",provides:["ui"],requires:[],optional:[],defaultConfig:{enabled:!0,components:{}}};const E={manifest:I,create:(t,e,i)=>new f(S,t,i),reducer:(t=l,e)=>{switch(e.type){case i:return{...t,...e.payload};case s:{const i=t.panel[e.payload.id]||{},{open:n,visibleChild:s}=e.payload,o=i.visibleChild;let r=i.open,a=i.visibleChild;return s===o?r=void 0!==n?n:!i.open:(a=s,r=!0),{...t,panel:{...t.panel,[e.payload.id]:{...i,open:r,visibleChild:a}}}}case n:return{...t,header:{...t.header,[e.payload.id]:{...t.header[e.payload.id],visible:e.payload.visible,visibleChild:e.payload.visibleChild}}};case o:return{...t,commandMenu:{...t.commandMenu,[e.payload.id]:{activeCommand:e.payload.commandId,triggerElement:e.payload.triggerElement,position:e.payload.position,open:!0,flatten:e.payload.flatten}}};case r:return{...t,commandMenu:{...t.commandMenu,[e.payload.id]:{...t.commandMenu[e.payload.id],open:!1,activeCommand:null,triggerElement:void 0,position:void 0,flatten:!1}}};case a:{const{componentType:i,componentId:n,patch:s}=e.payload;if(!t[i]||!t[i][n])return t;const o=t[i][n],r=Object.fromEntries(Object.entries(s).filter((([t])=>t in o)));return 0===Object.keys(r).length?t:{...t,[i]:{...t[i],[n]:{...o,...r}}}}default:return t}},initialState:l};exports.UIComponent=e,exports.UIPlugin=f,exports.UIPluginPackage=E,exports.UI_PLUGIN_ID=S,exports.createEventController=d,exports.defineComponent=function(){return t=>t},exports.hasActive=function(t){return"active"in t},exports.isActive=function(t,e){const i=h(t,e);return"group"!==i.type&&!!i.active},exports.isDisabled=function(t,e){const i=h(t,e);return"group"!==i.type&&!!i.disabled},exports.isVisible=function(t,e){const i=h(t,e);return"group"!==i.type&&!!i.visible},exports.manifest=I,exports.resolveMenuItem=h;
2
+ //# sourceMappingURL=index.cjs.map