@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.
- package/dist/index.cjs +2 -883
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -495
- package/dist/index.js +37 -56
- package/dist/index.js.map +1 -1
- package/dist/lib/actions.d.ts +88 -0
- package/dist/lib/icons/icon-manager.d.ts +47 -0
- package/dist/lib/icons/types.d.ts +36 -0
- package/dist/lib/index.d.ts +13 -0
- package/dist/lib/manifest.d.ts +4 -0
- package/dist/lib/menu/menu-manager.d.ts +98 -0
- package/dist/lib/menu/types.d.ts +83 -0
- package/dist/lib/menu/utils.d.ts +5 -0
- package/dist/lib/reducer.d.ts +5 -0
- package/dist/lib/types.d.ts +204 -0
- package/dist/lib/ui-component.d.ts +30 -0
- package/dist/lib/ui-plugin.d.ts +24 -0
- package/dist/lib/utils.d.ts +33 -0
- package/dist/preact/adapter.d.ts +5 -0
- package/dist/preact/core.d.ts +1 -0
- package/dist/preact/index.cjs +2 -130
- package/dist/preact/index.cjs.map +1 -1
- package/dist/preact/index.d.ts +1 -70
- package/dist/preact/index.js +19 -26
- package/dist/preact/index.js.map +1 -1
- package/dist/react/adapter.d.ts +2 -0
- package/dist/react/core.d.ts +1 -0
- package/dist/react/index.cjs +2 -2
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.ts +1 -2
- package/dist/react/index.js +92 -1
- package/dist/react/index.js.map +1 -1
- package/dist/shared-preact/components/component-wrapper.d.ts +5 -0
- package/dist/shared-preact/components/index.d.ts +1 -0
- package/dist/shared-preact/components/plugin-ui-provider.d.ts +37 -0
- package/dist/shared-preact/hooks/index.d.ts +2 -0
- package/dist/shared-preact/hooks/use-icon.d.ts +15 -0
- package/dist/shared-preact/hooks/use-ui.d.ts +11 -0
- package/dist/shared-preact/index.d.ts +2 -0
- package/dist/shared-react/components/component-wrapper.d.ts +5 -0
- package/dist/shared-react/components/index.d.ts +1 -0
- package/dist/shared-react/components/plugin-ui-provider.d.ts +37 -0
- package/dist/shared-react/hooks/index.d.ts +2 -0
- package/dist/shared-react/hooks/use-icon.d.ts +15 -0
- package/dist/shared-react/hooks/use-ui.d.ts +11 -0
- package/dist/shared-react/index.d.ts +2 -0
- package/package.json +14 -11
- package/dist/index.d.cts +0 -495
- package/dist/preact/index.d.cts +0 -70
- package/dist/react/index.d.cts +0 -2
package/dist/index.cjs
CHANGED
|
@@ -1,883 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
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
|