@openpen/module-api 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/_chunks/AppButtonDropdown.vue_vue_type_style_index_0_lang-DBVFUpxc.js +245 -0
- package/dist/_chunks/AppButtonDropdown.vue_vue_type_style_index_0_lang-DBVFUpxc.js.map +1 -0
- package/dist/_chunks/inject-keys-CRXCpN-M.js +196 -0
- package/dist/_chunks/inject-keys-CRXCpN-M.js.map +1 -0
- package/dist/_chunks/module-context-registry-Cn1IWYu9.js +16 -0
- package/dist/_chunks/module-context-registry-Cn1IWYu9.js.map +1 -0
- package/dist/_chunks/passthrough-DKU7JYuQ.js +6 -0
- package/dist/_chunks/passthrough-DKU7JYuQ.js.map +1 -0
- package/dist/cursors.d.ts +83 -0
- package/dist/define-module.d.ts +17 -0
- package/dist/host/color-utils.d.ts +11 -0
- package/{src/host/event-bus.ts → dist/host/event-bus.d.ts} +7 -5
- package/dist/host/host-commands.d.ts +1 -0
- package/dist/host/index.d.ts +24 -0
- package/dist/host/index.js +49 -0
- package/dist/host/index.js.map +1 -0
- package/{src/host/module-context-registry.ts → dist/host/module-context-registry.d.ts} +5 -19
- package/dist/host/passthrough.d.ts +2 -0
- package/dist/host/popup-anchor.d.ts +3 -0
- package/dist/host/registry.d.ts +39 -0
- package/dist/host/registry.js +37 -0
- package/dist/host/registry.js.map +1 -0
- package/dist/host/slot-entries.d.ts +2 -0
- package/dist/host/stroke-store.d.ts +5 -0
- package/dist/host/stroke-style.d.ts +3 -0
- package/dist/host/types.d.ts +164 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +349 -0
- package/dist/index.js.map +1 -0
- package/{src/inject-keys.ts → dist/inject-keys.d.ts} +37 -66
- package/{src/locale.ts → dist/locale.d.ts} +3 -22
- package/dist/slots.d.ts +57 -0
- package/dist/types/contributions.d.ts +288 -0
- package/dist/types/control-bar-layout.d.ts +227 -0
- package/dist/types/module.d.ts +208 -0
- package/{src/types/notification.ts → dist/types/notification.d.ts} +12 -14
- package/dist/types/tool.d.ts +77 -0
- package/dist/uikit/components/AppBanner.vue.d.ts +34 -0
- package/dist/uikit/components/AppButton.vue.d.ts +30 -0
- package/dist/uikit/components/AppButtonDropdown.vue.d.ts +52 -0
- package/dist/uikit/components/AppDialog.vue.d.ts +53 -0
- package/dist/uikit/components/AppPopover.vue.d.ts +43 -0
- package/dist/uikit/components/AppSegmented.vue.d.ts +19 -0
- package/dist/uikit/components/AppSelect.vue.d.ts +26 -0
- package/dist/uikit/components/AppSlider.vue.d.ts +43 -0
- package/dist/uikit/components/AppTabs.vue.d.ts +35 -0
- package/dist/uikit/components/AppToggle.vue.d.ts +13 -0
- package/dist/uikit/components/AppTooltip.vue.d.ts +27 -0
- package/dist/uikit/components/DialogHost.vue.d.ts +3 -0
- package/{src/uikit/composables/dialog-internal-keys.ts → dist/uikit/composables/dialog-internal-keys.d.ts} +3 -5
- package/dist/uikit/composables/useDialog.d.ts +399 -0
- package/dist/uikit/composables/useDialogPluginComponent.d.ts +9 -0
- package/dist/uikit/index.d.ts +42 -0
- package/dist/uikit/index.js +884 -0
- package/dist/uikit/index.js.map +1 -0
- package/{src/uikit/internal.ts → dist/uikit/internal.d.ts} +1 -1
- package/dist/uikit/internal.js +157 -0
- package/dist/uikit/internal.js.map +1 -0
- package/dist/uikit/module-api.css +851 -0
- package/dist/uikit/primitives.d.ts +42 -0
- package/{src/use-module-context.ts → dist/use-module-context.d.ts} +2 -15
- package/{src/validation.ts → dist/validation.d.ts} +2 -6
- package/package.json +26 -12
- package/src/cursors.ts +0 -369
- package/src/define-module.ts +0 -55
- package/src/host/color-utils.ts +0 -18
- package/src/host/host-commands.ts +0 -9
- package/src/host/index.ts +0 -53
- package/src/host/passthrough.ts +0 -10
- package/src/host/popup-anchor.ts +0 -14
- package/src/host/slot-entries.ts +0 -9
- package/src/host/stroke-store.ts +0 -20
- package/src/host/stroke-style.ts +0 -15
- package/src/index.ts +0 -131
- package/src/slots.ts +0 -135
- package/src/types/contributions.ts +0 -333
- package/src/types/control-bar-layout.ts +0 -174
- package/src/types/module.ts +0 -225
- package/src/types/tool.ts +0 -82
- package/src/uikit/components/.gitkeep +0 -0
- package/src/uikit/components/AppBanner.vue +0 -131
- package/src/uikit/components/AppButton.vue +0 -135
- package/src/uikit/components/AppDialog.vue +0 -393
- package/src/uikit/components/AppPopover.vue +0 -268
- package/src/uikit/components/AppSegmented.vue +0 -128
- package/src/uikit/components/AppSelect.vue +0 -235
- package/src/uikit/components/AppSlider.vue +0 -204
- package/src/uikit/components/AppTabs.vue +0 -163
- package/src/uikit/components/AppToggle.vue +0 -96
- package/src/uikit/components/AppTooltip.vue +0 -118
- package/src/uikit/components/DialogHost.vue +0 -272
- package/src/uikit/composables/useDialog.ts +0 -141
- package/src/uikit/composables/useDialogPluginComponent.ts +0 -27
- package/src/uikit/index.ts +0 -79
- package/src/uikit/primitives.ts +0 -150
- /package/{src → dist}/uikit/tokens.css +0 -0
package/src/host/popup-anchor.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @openpen/module-api/host — Popup Anchor
|
|
3
|
-
*
|
|
4
|
-
* Re-exports the usePopupAnchor composable and its pure helper
|
|
5
|
-
* calculatePopupAnchor for module components that need anchor-relative
|
|
6
|
-
* popup positioning.
|
|
7
|
-
*
|
|
8
|
-
* Exposed here so module code can import without cross-layer relative paths.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
export {
|
|
12
|
-
usePopupAnchor,
|
|
13
|
-
calculatePopupAnchor,
|
|
14
|
-
} from '../../../../src/composables/usePopupAnchor'
|
package/src/host/slot-entries.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @openpen/module-api/host — Slot Entries Reader
|
|
3
|
-
*
|
|
4
|
-
* Re-exports getSlotEntries so module components can render UI driven
|
|
5
|
-
* by other modules' contributions to the same slot (for example,
|
|
6
|
-
* the shape-picker rendering all canvas.shapes contributions).
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
export { getSlotEntries } from '../../../../src/core/runtime/contribution-store'
|
package/src/host/stroke-store.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @openpen/module-api/host — Stroke Store
|
|
3
|
-
*
|
|
4
|
-
* Re-exports the stroke store APIs that module tools need.
|
|
5
|
-
* Only the minimum surface required by stroke-eraser (and similar tools)
|
|
6
|
-
* is exposed: getAllStrokes, removeStrokeById, pushCommand.
|
|
7
|
-
*
|
|
8
|
-
* Host-internal state mutation helpers (clearAll, addStroke, undo, redo)
|
|
9
|
-
* are intentionally NOT exported — modules must use hostCommands for
|
|
10
|
-
* undo/redo and canvas clear.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
export {
|
|
14
|
-
getAllStrokes,
|
|
15
|
-
removeStrokeById,
|
|
16
|
-
pushCommand,
|
|
17
|
-
} from '../../../../src/services/stroke-store'
|
|
18
|
-
|
|
19
|
-
// Re-export Stroke type via the public SDK types, not host internals.
|
|
20
|
-
export type { Stroke } from '../types/tool'
|
package/src/host/stroke-style.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @openpen/module-api/host — Stroke Style
|
|
3
|
-
*
|
|
4
|
-
* Re-exports the public API of the host useStrokeStyle composable.
|
|
5
|
-
* Module components MUST import from here, not from src/composables directly.
|
|
6
|
-
*
|
|
7
|
-
* Exposed here so module components can access it without cross-layer imports.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
// Re-export the public API functions that modules need.
|
|
11
|
-
// initStrokeStyleFromSettings is host-boot-only and intentionally NOT exported here.
|
|
12
|
-
export { useStrokeStyle } from '../../../../src/composables/useStrokeStyle'
|
|
13
|
-
|
|
14
|
-
// Re-export the StrokeColor type via the public SDK types (not host internals).
|
|
15
|
-
export type { StrokeColor } from '../types/tool'
|
package/src/index.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @openpen/module-api — public contract surface for OpenPen modules.
|
|
3
|
-
*
|
|
4
|
-
* This is the **only** import path that built-in modules and plugins
|
|
5
|
-
* are allowed to use, alongside relative imports, `node:*`, and
|
|
6
|
-
* third-party npm packages. Boundary tests in the OpenPen main repo
|
|
7
|
-
* enforce this rule on `src/core/modules/**` and on plugin code.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
// Core helpers
|
|
11
|
-
export { defineModule } from './define-module'
|
|
12
|
-
export { useModuleContext } from './use-module-context'
|
|
13
|
-
export { isValidModuleId, MODULE_ID_RE } from './validation'
|
|
14
|
-
export { resolveLabel, sanitizeIdForI18n } from './locale'
|
|
15
|
-
export type { LocaleMap } from './locale'
|
|
16
|
-
|
|
17
|
-
// Slot catalogue
|
|
18
|
-
export {
|
|
19
|
-
ALL_SLOTS,
|
|
20
|
-
V1_ACTIVE_SLOTS,
|
|
21
|
-
V1_RESERVED_SLOTS,
|
|
22
|
-
CONTRIBUTION_KEY_TO_SLOT_ID,
|
|
23
|
-
isKnownSlot,
|
|
24
|
-
getSlot,
|
|
25
|
-
} from './slots'
|
|
26
|
-
export type { SlotDefinition, SlotCategory, SlotStatus } from './slots'
|
|
27
|
-
|
|
28
|
-
// Tool primitives (Point, Stroke, StrokeStyle, Tool, …)
|
|
29
|
-
export type {
|
|
30
|
-
Point,
|
|
31
|
-
StrokeColor,
|
|
32
|
-
StrokeStyle,
|
|
33
|
-
Stroke,
|
|
34
|
-
PointerModifiers,
|
|
35
|
-
Tool,
|
|
36
|
-
} from './types/tool'
|
|
37
|
-
|
|
38
|
-
// Control bar layout types + helpers
|
|
39
|
-
export type { ControlBarLayout, LayoutGroup, GroupInset, ControlBarContribution } from './types/control-bar-layout'
|
|
40
|
-
export {
|
|
41
|
-
ControlBarLayoutSchema,
|
|
42
|
-
LayoutGroupSchema,
|
|
43
|
-
GroupInsetSchema,
|
|
44
|
-
DEFAULT_CONTROL_BAR_LAYOUT,
|
|
45
|
-
repairLayoutL3a,
|
|
46
|
-
repairLayoutL3b,
|
|
47
|
-
} from './types/control-bar-layout'
|
|
48
|
-
|
|
49
|
-
// Notification types
|
|
50
|
-
export type { NotifyPayload, NotifyHandle } from './types/notification'
|
|
51
|
-
|
|
52
|
-
// Module + Contribution types
|
|
53
|
-
export type { OpenPenModule, ModuleSetupContext } from './types/module'
|
|
54
|
-
export type {
|
|
55
|
-
ModuleContributions,
|
|
56
|
-
ToolContribution,
|
|
57
|
-
ShapeContribution,
|
|
58
|
-
StrokeStyleContribution,
|
|
59
|
-
HistoryCommandContribution,
|
|
60
|
-
CanvasLayerContribution,
|
|
61
|
-
HtmlOverlayContribution,
|
|
62
|
-
StrokeTransformerContribution,
|
|
63
|
-
SettingsTabContribution,
|
|
64
|
-
SettingsPanelContribution,
|
|
65
|
-
CursorContribution,
|
|
66
|
-
CursorSpec,
|
|
67
|
-
SvgCursorSpec,
|
|
68
|
-
PngCursorSpec,
|
|
69
|
-
Hotspot,
|
|
70
|
-
StatusContribution,
|
|
71
|
-
ModalContribution,
|
|
72
|
-
TrayMenuContribution,
|
|
73
|
-
ContextMenuContribution,
|
|
74
|
-
ThemeTokenContribution,
|
|
75
|
-
ShortcutContribution,
|
|
76
|
-
WindowBehaviorContribution,
|
|
77
|
-
LocaleContribution,
|
|
78
|
-
EventSubscriptionContribution,
|
|
79
|
-
LifecycleContribution,
|
|
80
|
-
StorageContribution,
|
|
81
|
-
MainHandlerContribution,
|
|
82
|
-
FileDropContribution,
|
|
83
|
-
} from './types/contributions'
|
|
84
|
-
|
|
85
|
-
// Host ↔ module inject keys (Vue provide/inject bridge)
|
|
86
|
-
export {
|
|
87
|
-
STROKE_STYLE_CONTEXT_KEY,
|
|
88
|
-
SNAP_EDGE_KEY,
|
|
89
|
-
IS_VERTICAL_KEY,
|
|
90
|
-
MODAL_MANAGER_KEY,
|
|
91
|
-
WRAPPER_EL_KEY,
|
|
92
|
-
ANCHOR_EL_KEY,
|
|
93
|
-
CONTROL_BAR_ANIMATING_KEY,
|
|
94
|
-
HOST_DIALOG_OPEN_COUNT_KEY,
|
|
95
|
-
POPOVER_PLACEMENT_HINT_KEY,
|
|
96
|
-
ACTIVE_TOOL_KEY,
|
|
97
|
-
} from './inject-keys'
|
|
98
|
-
export type { StrokeStyleContext, SnapEdge, ModalManager, PopoverPlacementHint } from './inject-keys'
|
|
99
|
-
|
|
100
|
-
// Cursor compilation + sanitisation (used by host runtime; helpers
|
|
101
|
-
// re-exported so plugins can validate cursor specs in their own tests).
|
|
102
|
-
export {
|
|
103
|
-
compileCursor,
|
|
104
|
-
sanitizeSvgMarkup,
|
|
105
|
-
sanitizeCursorContributions,
|
|
106
|
-
isSafeRelativePath,
|
|
107
|
-
pluginHostname,
|
|
108
|
-
pluginAssetUrl,
|
|
109
|
-
SAFE_CURSOR_KEYWORDS,
|
|
110
|
-
} from './cursors'
|
|
111
|
-
export type {
|
|
112
|
-
CompiledCursor,
|
|
113
|
-
CursorResolutionContext,
|
|
114
|
-
CursorSanitizeRule,
|
|
115
|
-
CursorSanitizeDiagnostic,
|
|
116
|
-
CursorSanitizeOptions,
|
|
117
|
-
CursorSanitizeResult,
|
|
118
|
-
} from './cursors'
|
|
119
|
-
|
|
120
|
-
// Re-export zod so modules don't need a separate import path.
|
|
121
|
-
export { z } from 'zod'
|
|
122
|
-
|
|
123
|
-
// Host-internal registry writers — re-exported here so the host's module
|
|
124
|
-
// loader pulls them through the SAME externalised entry point
|
|
125
|
-
// (`@openpen/module-api`, runtime bundle: openpen-runtime/module-api.js)
|
|
126
|
-
// that `useModuleContext` reads from. Importing them via
|
|
127
|
-
// `@openpen/module-api/host` instead would inline a duplicate
|
|
128
|
-
// module-context-registry into the host bundle, breaking state-sharing
|
|
129
|
-
// between writers and readers in production builds (see
|
|
130
|
-
// project_dev_prod_parity.md). Plugin authors MUST NOT use these.
|
|
131
|
-
export { setModuleContext, clearModuleContext } from './host/module-context-registry'
|
package/src/slots.ts
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OpenPen Contribution Slot catalogue.
|
|
3
|
-
*
|
|
4
|
-
* Slots are the only places where modules can affect the host app.
|
|
5
|
-
* Adding a slot is an architectural change — it usually requires a
|
|
6
|
-
* new adapter on the OpenPen side and a minor version bump of this
|
|
7
|
-
* package. Removing a slot is a breaking change.
|
|
8
|
-
*
|
|
9
|
-
* `status: 'v1'` slots are wired through to runtime adapters.
|
|
10
|
-
* `status: 'reserved'` slots accept registrations and pass validation;
|
|
11
|
-
* no runtime adapter is active yet so contributions are stored but
|
|
12
|
-
* inert. Forward-compatible: modules can ship against reserved slots
|
|
13
|
-
* without any plugin-side changes once an adapter lands.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
export type SlotCategory = 'canvas' | 'ui' | 'system'
|
|
17
|
-
export type SlotStatus = 'v1' | 'reserved'
|
|
18
|
-
|
|
19
|
-
export interface SlotDefinition {
|
|
20
|
-
/** Dotted slot id, e.g. `'canvas.tools'`. */
|
|
21
|
-
id: string
|
|
22
|
-
/** Implementation status — see file header. */
|
|
23
|
-
status: SlotStatus
|
|
24
|
-
/** High-level grouping for documentation and UI. */
|
|
25
|
-
category: SlotCategory
|
|
26
|
-
/** One-sentence purpose, shown in `docs/reference/slots.md`. */
|
|
27
|
-
description: string
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* v1 active slots (16). Wired through to runtime adapters.
|
|
32
|
-
*/
|
|
33
|
-
export const V1_ACTIVE_SLOTS: readonly SlotDefinition[] = [
|
|
34
|
-
// Canvas
|
|
35
|
-
{ id: 'canvas.tools', status: 'v1', category: 'canvas', description: 'Drawing tools driven by pointer events.' },
|
|
36
|
-
{ id: 'canvas.shapes', status: 'v1', category: 'canvas', description: 'Shape primitives consumed by the shape tool.' },
|
|
37
|
-
{ id: 'canvas.stroke.style', status: 'v1', category: 'canvas', description: 'Writers into the shared stroke style store.' },
|
|
38
|
-
{ id: 'canvas.layers.background', status: 'v1', category: 'canvas', description: 'Render below strokes (grids, watermarks).' },
|
|
39
|
-
{ id: 'canvas.layers.overlay', status: 'v1', category: 'canvas', description: 'Render above strokes (rulers, guides).' },
|
|
40
|
-
{ id: 'canvas.html.overlay', status: 'v1', category: 'canvas', description: 'Mount HTML elements above the canvas (text, stickers).' },
|
|
41
|
-
// UI
|
|
42
|
-
{ id: 'ui.control-bar', status: 'v1', category: 'ui', description: 'Control bar item slot (groups and ordering managed by layout config).' },
|
|
43
|
-
{ id: 'ui.settings.tabs', status: 'v1', category: 'ui', description: 'Tabs in the settings window.' },
|
|
44
|
-
{ id: 'ui.settings.panels', status: 'v1', category: 'ui', description: 'Sections inside the Features settings tab, grouped by module.' },
|
|
45
|
-
{ id: 'ui.cursors', status: 'v1', category: 'ui', description: 'Drawing-mode cursor styles.' },
|
|
46
|
-
{ id: 'ui.status', status: 'v1', category: 'ui', description: 'Ephemeral status badges on the control bar.' },
|
|
47
|
-
{ id: 'ui.modals', status: 'v1', category: 'ui', description: 'Registered modals managed by the global modal stack.' },
|
|
48
|
-
// System
|
|
49
|
-
{ id: 'system.shortcuts', status: 'v1', category: 'system', description: 'Global and drawing-mode keyboard shortcuts.' },
|
|
50
|
-
{ id: 'system.locales', status: 'v1', category: 'system', description: 'i18n dictionary contributions.' },
|
|
51
|
-
{ id: 'system.main.handlers', status: 'v1', category: 'system', description: 'Node-side IPC handlers for main process capabilities.' },
|
|
52
|
-
{ id: 'system.events', status: 'v1', category: 'system', description: 'Subscribers and emitters on the domain event bus.' },
|
|
53
|
-
{ id: 'system.lifecycle', status: 'v1', category: 'system', description: 'App lifecycle hooks (onReady / onSuspend / onQuit).' },
|
|
54
|
-
] as const
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* v1 reserved slots. Registrations pass validation but no runtime
|
|
58
|
-
* adapter is active yet.
|
|
59
|
-
*/
|
|
60
|
-
export const V1_RESERVED_SLOTS: readonly SlotDefinition[] = [
|
|
61
|
-
{ id: 'canvas.history.commands', status: 'reserved', category: 'canvas', description: 'Undo/redo history commands. Adapter not yet active; built-in command types are used internally.' },
|
|
62
|
-
{ id: 'canvas.stroke.transformers', status: 'reserved', category: 'canvas', description: 'Post-process strokes after creation (smooth, simplify).' },
|
|
63
|
-
{ id: 'ui.tray.menu', status: 'reserved', category: 'ui', description: 'System tray menu items. Adapter not yet active.' },
|
|
64
|
-
{ id: 'ui.context.menu', status: 'reserved', category: 'ui', description: 'Right-click context menu items on canvas / control bar.' },
|
|
65
|
-
{ id: 'ui.theme.tokens', status: 'reserved', category: 'ui', description: 'CSS custom property contributions (colour swatches, spacing tokens).' },
|
|
66
|
-
{ id: 'system.window.behaviors', status: 'reserved', category: 'system', description: 'Window behavior customizations. Adapter not yet active.' },
|
|
67
|
-
{ id: 'system.storage', status: 'reserved', category: 'system', description: 'Per-plugin isolated storage at ~/.openpen/plugins/<id>/data/. Adapter not yet active; first real consumer will drive the storage backend design.' },
|
|
68
|
-
{ id: 'system.file.drop', status: 'reserved', category: 'system', description: 'Handlers for files dropped onto the canvas.' },
|
|
69
|
-
] as const
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* All slots (active + reserved). Source of truth for validation.
|
|
73
|
-
*/
|
|
74
|
-
export const ALL_SLOTS: readonly SlotDefinition[] = [
|
|
75
|
-
...V1_ACTIVE_SLOTS,
|
|
76
|
-
...V1_RESERVED_SLOTS,
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
const SLOT_BY_ID = new Map<string, SlotDefinition>(
|
|
80
|
-
ALL_SLOTS.map((s) => [s.id, s])
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
/** Returns `true` when `id` matches a slot in {@link ALL_SLOTS} (active or reserved). */
|
|
84
|
-
export function isKnownSlot(id: string): boolean {
|
|
85
|
-
return SLOT_BY_ID.has(id)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Returns the {@link SlotDefinition} for a known slot id, or `undefined` if
|
|
90
|
-
* the id is not registered in {@link ALL_SLOTS}.
|
|
91
|
-
*/
|
|
92
|
-
export function getSlot(id: string): SlotDefinition | undefined {
|
|
93
|
-
return SLOT_BY_ID.get(id)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Mapping from `contributes` field name (camelCase) to slot id (dotted).
|
|
98
|
-
*
|
|
99
|
-
* Modules express contributions via the ergonomic camelCase keys on
|
|
100
|
-
* `contributes` (e.g. `historyCommands`); the validator maps them
|
|
101
|
-
* back to slot ids (`canvas.history.commands`) before checking against
|
|
102
|
-
* `ALL_SLOTS`.
|
|
103
|
-
*
|
|
104
|
-
* Adding a new field here is part of adding a new slot.
|
|
105
|
-
*/
|
|
106
|
-
export const CONTRIBUTION_KEY_TO_SLOT_ID: Record<string, string> = {
|
|
107
|
-
// Canvas
|
|
108
|
-
tools: 'canvas.tools',
|
|
109
|
-
shapes: 'canvas.shapes',
|
|
110
|
-
strokeStyle: 'canvas.stroke.style',
|
|
111
|
-
historyCommands: 'canvas.history.commands',
|
|
112
|
-
backgroundLayers: 'canvas.layers.background',
|
|
113
|
-
overlayLayers: 'canvas.layers.overlay',
|
|
114
|
-
htmlOverlays: 'canvas.html.overlay',
|
|
115
|
-
strokeTransformers: 'canvas.stroke.transformers',
|
|
116
|
-
// UI
|
|
117
|
-
controlBar: 'ui.control-bar',
|
|
118
|
-
settingsTabs: 'ui.settings.tabs',
|
|
119
|
-
settingsPanels: 'ui.settings.panels',
|
|
120
|
-
cursors: 'ui.cursors',
|
|
121
|
-
status: 'ui.status',
|
|
122
|
-
modals: 'ui.modals',
|
|
123
|
-
trayMenu: 'ui.tray.menu',
|
|
124
|
-
contextMenu: 'ui.context.menu',
|
|
125
|
-
themeTokens: 'ui.theme.tokens',
|
|
126
|
-
// System
|
|
127
|
-
shortcuts: 'system.shortcuts',
|
|
128
|
-
windowBehaviors: 'system.window.behaviors',
|
|
129
|
-
locales: 'system.locales',
|
|
130
|
-
events: 'system.events',
|
|
131
|
-
lifecycle: 'system.lifecycle',
|
|
132
|
-
storage: 'system.storage',
|
|
133
|
-
mainHandlers: 'system.main.handlers',
|
|
134
|
-
fileDrop: 'system.file.drop',
|
|
135
|
-
}
|
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
import type { Component } from 'vue'
|
|
2
|
-
import type { LocaleMap } from '../locale'
|
|
3
|
-
import type { Stroke, Tool } from './tool'
|
|
4
|
-
import type { ControlBarContribution } from './control-bar-layout'
|
|
5
|
-
|
|
6
|
-
export type { ControlBarContribution }
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* The shape of `OpenPenModule.contributes`. Every field is optional;
|
|
10
|
-
* `defineModule` requires at least one field to be present and rejects
|
|
11
|
-
* any unknown field at module-author boundary time.
|
|
12
|
-
*
|
|
13
|
-
* Each field corresponds to a slot in {@link import('../slots').ALL_SLOTS}.
|
|
14
|
-
* The mapping from camelCase field name to dotted slot id lives in
|
|
15
|
-
* `CONTRIBUTION_KEY_TO_SLOT_ID`.
|
|
16
|
-
*/
|
|
17
|
-
export interface ModuleContributions {
|
|
18
|
-
// ── Canvas ──────────────────────────────────────────────────────────────
|
|
19
|
-
tools?: ToolContribution[]
|
|
20
|
-
shapes?: ShapeContribution[]
|
|
21
|
-
strokeStyle?: StrokeStyleContribution
|
|
22
|
-
historyCommands?: HistoryCommandContribution[]
|
|
23
|
-
backgroundLayers?: CanvasLayerContribution[]
|
|
24
|
-
overlayLayers?: CanvasLayerContribution[]
|
|
25
|
-
htmlOverlays?: HtmlOverlayContribution[]
|
|
26
|
-
/** ⏳ Reserved slot — accepts registrations, adapter not yet wired. */
|
|
27
|
-
strokeTransformers?: StrokeTransformerContribution[]
|
|
28
|
-
|
|
29
|
-
// ── UI ──────────────────────────────────────────────────────────────────
|
|
30
|
-
controlBar?: ControlBarContribution[]
|
|
31
|
-
settingsTabs?: SettingsTabContribution[]
|
|
32
|
-
settingsPanels?: SettingsPanelContribution[]
|
|
33
|
-
cursors?: CursorContribution[]
|
|
34
|
-
status?: StatusContribution[]
|
|
35
|
-
modals?: ModalContribution[]
|
|
36
|
-
trayMenu?: TrayMenuContribution[]
|
|
37
|
-
/** ⏳ Reserved slot — accepts registrations, adapter not yet wired. */
|
|
38
|
-
contextMenu?: ContextMenuContribution[]
|
|
39
|
-
/** ⏳ Reserved slot — accepts registrations, adapter not yet wired. */
|
|
40
|
-
themeTokens?: ThemeTokenContribution
|
|
41
|
-
|
|
42
|
-
// ── System ──────────────────────────────────────────────────────────────
|
|
43
|
-
shortcuts?: ShortcutContribution[]
|
|
44
|
-
windowBehaviors?: WindowBehaviorContribution[]
|
|
45
|
-
locales?: LocaleContribution
|
|
46
|
-
events?: EventSubscriptionContribution[]
|
|
47
|
-
lifecycle?: LifecycleContribution
|
|
48
|
-
storage?: StorageContribution
|
|
49
|
-
mainHandlers?: MainHandlerContribution
|
|
50
|
-
/** ⏳ Reserved slot — accepts registrations, adapter not yet wired. */
|
|
51
|
-
fileDrop?: FileDropContribution[]
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// ════════════════════════════════════════════════════════════════════════
|
|
55
|
-
// Below: per-slot contribution shapes. These are the locked public-facing
|
|
56
|
-
// names referenced by docs and the validator; their internals can extend
|
|
57
|
-
// without breaking modules.
|
|
58
|
-
// ════════════════════════════════════════════════════════════════════════
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Drawing tool driven by pointer events. Implements the full `Tool`
|
|
62
|
-
* interface (onPointerDown / Move / Up) plus optional metadata for
|
|
63
|
-
* the toolbar UI and an optional `renderStroke` for tools whose
|
|
64
|
-
* strokes need custom redraw semantics (shapes, erasers, anything
|
|
65
|
-
* beyond a simple polyline).
|
|
66
|
-
*/
|
|
67
|
-
export interface ToolContribution extends Tool {
|
|
68
|
-
id: string
|
|
69
|
-
label?: string | LocaleMap
|
|
70
|
-
/**
|
|
71
|
-
* SVG markup string for this tool's icon in the control-bar button.
|
|
72
|
-
*
|
|
73
|
-
* The host renders tool icons via `v-html`, so only raw SVG strings are
|
|
74
|
-
* accepted (not Vue components or CSS class names). Recommended size is
|
|
75
|
-
* `width="16" height="16"` with `stroke="currentColor"` so the icon
|
|
76
|
-
* inherits the button's colour automatically.
|
|
77
|
-
*
|
|
78
|
-
* @example
|
|
79
|
-
* icon: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 17c3-3 6-6 9-3s6 0 9-3"/></svg>'
|
|
80
|
-
*
|
|
81
|
-
* Note: built-in tools (freehand, line, eraser) use their own Vue button
|
|
82
|
-
* components rather than this field — `icon` is the lightweight path for
|
|
83
|
-
* plugin-contributed tools that do not need a custom button component.
|
|
84
|
-
*/
|
|
85
|
-
icon?: string
|
|
86
|
-
/**
|
|
87
|
-
* Custom redraw renderer. When omitted, canvas-engine falls back
|
|
88
|
-
* to a polyline render through `stroke.points` — sufficient for
|
|
89
|
-
* freehand- and line-style tools.
|
|
90
|
-
*/
|
|
91
|
-
renderStroke?: (canvasCtx: CanvasRenderingContext2D, stroke: Stroke) => void
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** Shape primitive used by the shape tool. */
|
|
95
|
-
export interface ShapeContribution {
|
|
96
|
-
id: string
|
|
97
|
-
label?: string | LocaleMap
|
|
98
|
-
/**
|
|
99
|
-
* Vue component or SVG string for the shape icon in control-bar / sub-panel.
|
|
100
|
-
* Host renders via `<component :is="icon">`.
|
|
101
|
-
* Component icons MAY accept an optional `filled?: boolean` prop —
|
|
102
|
-
* the host passes the current fill-toggle state so icons can mirror it
|
|
103
|
-
* (e.g. solid vs outline rendering). Plugin icons that ignore the prop
|
|
104
|
-
* still work; they just won't reflect fill state visually.
|
|
105
|
-
*/
|
|
106
|
-
icon?: Component | string
|
|
107
|
-
draw: (...args: unknown[]) => void
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Stroke style writer. Modules declare which keys of the shared
|
|
112
|
-
* stroke style store they write to; collision detection happens at
|
|
113
|
-
* module-validator time.
|
|
114
|
-
*/
|
|
115
|
-
export interface StrokeStyleContribution {
|
|
116
|
-
/** Keys this module writes (e.g. `['lineWidth']`, `['color']`). */
|
|
117
|
-
provides: string[]
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Undo/redo command handler for the `canvas.history.commands` slot.
|
|
122
|
-
*
|
|
123
|
-
* The host calls `undo` / `redo` with whatever `payload` was stored when the
|
|
124
|
-
* command was pushed onto the history stack. The contributing module decides
|
|
125
|
-
* the payload shape — the host treats it as `unknown` and passes it through
|
|
126
|
-
* without inspection.
|
|
127
|
-
*/
|
|
128
|
-
export interface HistoryCommandContribution {
|
|
129
|
-
type: string
|
|
130
|
-
undo: (payload: unknown) => void
|
|
131
|
-
redo: (payload: unknown) => void
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export interface CanvasLayerContribution {
|
|
135
|
-
id: string
|
|
136
|
-
/** Render priority within the layer; higher = drawn later (on top). */
|
|
137
|
-
order?: number
|
|
138
|
-
render: (ctx: CanvasRenderingContext2D) => void
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export interface HtmlOverlayContribution {
|
|
142
|
-
id: string
|
|
143
|
-
component: Component
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export interface StrokeTransformerContribution {
|
|
147
|
-
id: string
|
|
148
|
-
/** Receives a stroke, returns a transformed stroke. Slot ⏳ reserved. */
|
|
149
|
-
transform: (stroke: unknown) => unknown
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export interface SettingsTabContribution {
|
|
153
|
-
id: string
|
|
154
|
-
label: string | LocaleMap
|
|
155
|
-
component: Component
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export interface SettingsPanelContribution {
|
|
159
|
-
id: string
|
|
160
|
-
label: string | LocaleMap
|
|
161
|
-
component: Component
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/** Hotspot offset in CSS pixels relative to the cursor image's top-left. */
|
|
165
|
-
export interface Hotspot {
|
|
166
|
-
x: number
|
|
167
|
-
y: number
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Vector cursor: inline SVG markup OR a plugin-internal relative path
|
|
172
|
-
* to a `.svg` file. URL-shaped strings, absolute paths, and `..` segments
|
|
173
|
-
* are rejected at contribution-validation time.
|
|
174
|
-
*/
|
|
175
|
-
export interface SvgCursorSpec {
|
|
176
|
-
svg: string
|
|
177
|
-
hotspot?: Hotspot
|
|
178
|
-
/** CSS keyword fallback for legacy / non-overlay contexts. Defaults to `'crosshair'`. */
|
|
179
|
-
fallback?: string
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Raster cursor: plugin-internal relative path to a `.png` file. Inline
|
|
184
|
-
* form is not supported — PNG payload comes through `openpen-plugin://`.
|
|
185
|
-
*/
|
|
186
|
-
export interface PngCursorSpec {
|
|
187
|
-
png: string
|
|
188
|
-
hotspot?: Hotspot
|
|
189
|
-
fallback?: string
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Cursor specification. The legacy `string` form must be one of the
|
|
194
|
-
* whitelisted CSS keywords (see `SAFE_CURSOR_KEYWORDS` in cursors.ts);
|
|
195
|
-
* any string containing `url(` / `image-set(` / `-webkit-image-set(` is
|
|
196
|
-
* rejected to keep the asset trust boundary closed.
|
|
197
|
-
*/
|
|
198
|
-
export type CursorSpec = string | SvgCursorSpec | PngCursorSpec
|
|
199
|
-
|
|
200
|
-
export interface CursorContribution {
|
|
201
|
-
id: string
|
|
202
|
-
cursor: CursorSpec
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
export interface StatusContribution {
|
|
206
|
-
id: string
|
|
207
|
-
component: Component
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export interface ModalContribution {
|
|
211
|
-
id: string
|
|
212
|
-
component: Component
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
export interface TrayMenuContribution {
|
|
216
|
-
id: string
|
|
217
|
-
label: string | LocaleMap
|
|
218
|
-
click: () => void
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export interface ContextMenuContribution {
|
|
222
|
-
id: string
|
|
223
|
-
label: string | LocaleMap
|
|
224
|
-
/** Where the menu may appear; runtime filters by context at open time. */
|
|
225
|
-
context: 'canvas' | 'toolbar' | 'tray'
|
|
226
|
-
click: () => void
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* CSS custom property contributions for the `ui.theme.tokens` slot.
|
|
231
|
-
*
|
|
232
|
-
* Keys are CSS custom property names (e.g. `'--my-plugin-accent'`).
|
|
233
|
-
* Values are CSS color or length values (e.g. `'#ff6600'`, `'4px'`).
|
|
234
|
-
* The host merges all contributions into `:root` at startup.
|
|
235
|
-
*/
|
|
236
|
-
export type ThemeTokenContribution = Record<string, string>
|
|
237
|
-
|
|
238
|
-
export interface ShortcutContribution {
|
|
239
|
-
id: string
|
|
240
|
-
/** Accelerator string; tinykeys-style or Electron globalShortcut format. */
|
|
241
|
-
keys: string
|
|
242
|
-
/** `'global'` registers OS-wide; `'drawing'` only when overlay is active. */
|
|
243
|
-
scope: 'global' | 'drawing'
|
|
244
|
-
handler: () => void
|
|
245
|
-
/** Human-readable name. Omit to hide this shortcut from the user-visible shortcuts list. */
|
|
246
|
-
label?: string | LocaleMap
|
|
247
|
-
/** Optional secondary description shown below the label in the shortcuts settings panel. */
|
|
248
|
-
sublabel?: string | LocaleMap
|
|
249
|
-
/** When true, the user can rebind this key. The chosen key is persisted under `config.json → customShortcuts`. */
|
|
250
|
-
userCustomizable?: boolean
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export interface WindowBehaviorContribution {
|
|
254
|
-
id: string
|
|
255
|
-
/** Reserved — concrete behaviour API not yet defined. */
|
|
256
|
-
[key: string]: unknown
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/** Leaf or branch in a locale dictionary. Leaves must be strings. */
|
|
260
|
-
type LocaleDictValue = string | LocaleDict
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Recursive locale dictionary.
|
|
264
|
-
* Leaves are translated strings; branches are nested sub-dictionaries.
|
|
265
|
-
* Use the `interface` form (not `type`) to allow self-reference without
|
|
266
|
-
* triggering TypeScript's circular-type restrictions.
|
|
267
|
-
*/
|
|
268
|
-
interface LocaleDict {
|
|
269
|
-
[key: string]: LocaleDictValue
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* A locale dictionary keyed by BCP-47 tag (e.g. `'en'`, `'zh-Hant'`).
|
|
274
|
-
*
|
|
275
|
-
* Values are per-locale message dictionaries. Supports both flat and nested
|
|
276
|
-
* layouts — vue-i18n treats `.` in ctx.t(key) as a nested path separator,
|
|
277
|
-
* so keys like `'notif.ready'` must use a nested object dict
|
|
278
|
-
* `{ notif: { ready: '...' } }`, not a flat key `{ 'notif.ready': '...' }`.
|
|
279
|
-
*
|
|
280
|
-
* Non-string leaves are rejected at compile time; use ctx.t() to resolve
|
|
281
|
-
* keys to strings before passing them to runtime APIs.
|
|
282
|
-
*/
|
|
283
|
-
export type LocaleContribution = Record<string, LocaleDict>
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Subscription to a named domain event on the `system.events` slot.
|
|
287
|
-
*
|
|
288
|
-
* `event` must match the event name emitted by another module (or the host)
|
|
289
|
-
* via `system.events`. The host routes each emitted event to all registered
|
|
290
|
-
* handlers whose `event` string matches.
|
|
291
|
-
*/
|
|
292
|
-
export interface EventSubscriptionContribution {
|
|
293
|
-
event: string
|
|
294
|
-
handler: (payload: unknown) => void
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* App lifecycle hooks for the `system.lifecycle` slot.
|
|
299
|
-
*
|
|
300
|
-
* Call order: `setup` (from `OpenPenModule.setup`) → `onReady` (host fully
|
|
301
|
-
* booted) → `onSuspend` (overlay hidden) → `onQuit` (app shutting down).
|
|
302
|
-
* All hooks may return a Promise; the host awaits each before advancing.
|
|
303
|
-
*/
|
|
304
|
-
export interface LifecycleContribution {
|
|
305
|
-
onReady?: () => void | Promise<void>
|
|
306
|
-
onSuspend?: () => void | Promise<void>
|
|
307
|
-
onQuit?: () => void | Promise<void>
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Marker that this module wants an isolated storage area at
|
|
312
|
-
* `~/.openpen/plugins/<id>/data/`. Capacity / quota policy is defined
|
|
313
|
-
* by the host runtime.
|
|
314
|
-
*/
|
|
315
|
-
export interface StorageContribution {
|
|
316
|
-
/** If true, the host pre-creates the data directory at module load. */
|
|
317
|
-
preCreate?: boolean
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Map of action name to async handler. Routed from the renderer via
|
|
322
|
-
* `window.openPenApi.moduleCall(moduleId, action, payload)`.
|
|
323
|
-
*/
|
|
324
|
-
export type MainHandlerContribution = Record<
|
|
325
|
-
string,
|
|
326
|
-
(payload: unknown) => unknown | Promise<unknown>
|
|
327
|
-
>
|
|
328
|
-
|
|
329
|
-
export interface FileDropContribution {
|
|
330
|
-
/** MIME types this handler accepts (e.g. `['image/png']`). */
|
|
331
|
-
accept: string[]
|
|
332
|
-
handle: (files: File[]) => void | Promise<void>
|
|
333
|
-
}
|