@embedpdf/plugin-ui 1.4.1 → 2.0.0-next.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.
Files changed (127) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +1313 -655
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/actions.d.ts +110 -74
  6. package/dist/lib/index.d.ts +8 -7
  7. package/dist/lib/reducer.d.ts +5 -5
  8. package/dist/lib/schema.d.ts +257 -0
  9. package/dist/lib/selectors.d.ts +16 -0
  10. package/dist/lib/types.d.ts +185 -202
  11. package/dist/lib/ui-plugin.d.ts +66 -18
  12. package/dist/lib/utils/consts.d.ts +25 -0
  13. package/dist/lib/utils/index.d.ts +5 -0
  14. package/dist/lib/utils/responsive-utils.d.ts +10 -0
  15. package/dist/lib/utils/schema-merger.d.ts +15 -0
  16. package/dist/lib/utils/stylesheet-generator.d.ts +40 -0
  17. package/dist/lib/utils/ui-props.d.ts +14 -0
  18. package/dist/preact/adapter.d.ts +4 -2
  19. package/dist/preact/index.cjs +1 -1
  20. package/dist/preact/index.cjs.map +1 -1
  21. package/dist/preact/index.js +450 -49
  22. package/dist/preact/index.js.map +1 -1
  23. package/dist/preact/utils.d.ts +1 -0
  24. package/dist/react/adapter.d.ts +2 -2
  25. package/dist/react/index.cjs +1 -1
  26. package/dist/react/index.cjs.map +1 -1
  27. package/dist/react/index.js +449 -48
  28. package/dist/react/index.js.map +1 -1
  29. package/dist/react/utils.d.ts +1 -0
  30. package/dist/shared/auto-menu-renderer.d.ts +13 -0
  31. package/dist/shared/hooks/index.d.ts +4 -0
  32. package/dist/shared/hooks/use-item-renderer.d.ts +14 -0
  33. package/dist/shared/hooks/use-register-anchor.d.ts +17 -0
  34. package/dist/shared/hooks/use-schema-renderer.d.ts +61 -0
  35. package/dist/shared/hooks/use-selection-menu.d.ts +11 -0
  36. package/dist/shared/hooks/use-ui.d.ts +13 -5
  37. package/dist/shared/index.d.ts +4 -1
  38. package/dist/shared/provider.d.ts +68 -0
  39. package/dist/shared/registries/anchor-registry.d.ts +16 -0
  40. package/dist/shared/registries/component-registry.d.ts +20 -0
  41. package/dist/shared/registries/index.d.ts +3 -0
  42. package/dist/shared/registries/renderers-registry.d.ts +8 -0
  43. package/dist/shared/root.d.ts +12 -0
  44. package/dist/shared/types.d.ts +67 -0
  45. package/dist/shared-preact/auto-menu-renderer.d.ts +13 -0
  46. package/dist/shared-preact/hooks/index.d.ts +4 -0
  47. package/dist/shared-preact/hooks/use-item-renderer.d.ts +14 -0
  48. package/dist/shared-preact/hooks/use-register-anchor.d.ts +17 -0
  49. package/dist/shared-preact/hooks/use-schema-renderer.d.ts +61 -0
  50. package/dist/shared-preact/hooks/use-selection-menu.d.ts +11 -0
  51. package/dist/shared-preact/hooks/use-ui.d.ts +13 -5
  52. package/dist/shared-preact/index.d.ts +4 -1
  53. package/dist/shared-preact/provider.d.ts +68 -0
  54. package/dist/shared-preact/registries/anchor-registry.d.ts +16 -0
  55. package/dist/shared-preact/registries/component-registry.d.ts +20 -0
  56. package/dist/shared-preact/registries/index.d.ts +3 -0
  57. package/dist/shared-preact/registries/renderers-registry.d.ts +8 -0
  58. package/dist/shared-preact/root.d.ts +12 -0
  59. package/dist/shared-preact/types.d.ts +67 -0
  60. package/dist/shared-react/auto-menu-renderer.d.ts +13 -0
  61. package/dist/shared-react/hooks/index.d.ts +4 -0
  62. package/dist/shared-react/hooks/use-item-renderer.d.ts +14 -0
  63. package/dist/shared-react/hooks/use-register-anchor.d.ts +17 -0
  64. package/dist/shared-react/hooks/use-schema-renderer.d.ts +61 -0
  65. package/dist/shared-react/hooks/use-selection-menu.d.ts +11 -0
  66. package/dist/shared-react/hooks/use-ui.d.ts +13 -5
  67. package/dist/shared-react/index.d.ts +4 -1
  68. package/dist/shared-react/provider.d.ts +68 -0
  69. package/dist/shared-react/registries/anchor-registry.d.ts +16 -0
  70. package/dist/shared-react/registries/component-registry.d.ts +20 -0
  71. package/dist/shared-react/registries/index.d.ts +3 -0
  72. package/dist/shared-react/registries/renderers-registry.d.ts +8 -0
  73. package/dist/shared-react/root.d.ts +12 -0
  74. package/dist/shared-react/types.d.ts +67 -0
  75. package/dist/svelte/auto-menu-renderer.svelte.d.ts +15 -0
  76. package/dist/svelte/hooks/index.d.ts +5 -0
  77. package/dist/svelte/hooks/use-item-renderer.svelte.d.ts +24 -0
  78. package/dist/svelte/hooks/use-register-anchor.svelte.d.ts +18 -0
  79. package/dist/svelte/hooks/use-schema-renderer.svelte.d.ts +78 -0
  80. package/dist/svelte/hooks/use-selection-menu.svelte.d.ts +9 -0
  81. package/dist/svelte/hooks/use-ui.svelte.d.ts +34 -0
  82. package/dist/svelte/index.cjs +2 -0
  83. package/dist/svelte/index.cjs.map +1 -0
  84. package/dist/svelte/index.d.ts +6 -0
  85. package/dist/svelte/index.js +553 -0
  86. package/dist/svelte/index.js.map +1 -0
  87. package/dist/svelte/provider.svelte.d.ts +33 -0
  88. package/dist/svelte/registries/anchor-registry.svelte.d.ts +14 -0
  89. package/dist/svelte/registries/component-registry.svelte.d.ts +17 -0
  90. package/dist/svelte/registries/index.d.ts +3 -0
  91. package/dist/svelte/registries/renderers-registry.svelte.d.ts +3 -0
  92. package/dist/svelte/root.svelte.d.ts +8 -0
  93. package/dist/svelte/types.d.ts +67 -0
  94. package/dist/vue/auto-menu-renderer.vue.d.ts +15 -0
  95. package/dist/vue/hooks/index.d.ts +5 -0
  96. package/dist/vue/hooks/use-item-renderer.d.ts +16 -0
  97. package/dist/vue/hooks/use-register-anchor.d.ts +19 -0
  98. package/dist/vue/hooks/use-schema-renderer.d.ts +63 -0
  99. package/dist/vue/hooks/use-selection-menu.d.ts +28 -0
  100. package/dist/vue/hooks/use-ui.d.ts +940 -0
  101. package/dist/vue/index.cjs +2 -0
  102. package/dist/vue/index.cjs.map +1 -0
  103. package/dist/vue/index.d.ts +6 -0
  104. package/dist/vue/index.js +544 -0
  105. package/dist/vue/index.js.map +1 -0
  106. package/dist/vue/provider.vue.d.ts +43 -0
  107. package/dist/vue/registries/anchor-registry.d.ts +14 -0
  108. package/dist/vue/registries/component-registry.d.ts +17 -0
  109. package/dist/vue/registries/index.d.ts +3 -0
  110. package/dist/vue/registries/renderers-registry.d.ts +3 -0
  111. package/dist/vue/root.vue.d.ts +13 -0
  112. package/dist/vue/types.d.ts +67 -0
  113. package/package.json +32 -9
  114. package/dist/lib/menu/menu-manager.d.ts +0 -98
  115. package/dist/lib/menu/types.d.ts +0 -91
  116. package/dist/lib/menu/utils.d.ts +0 -6
  117. package/dist/lib/ui-component.d.ts +0 -30
  118. package/dist/lib/utils.d.ts +0 -33
  119. package/dist/shared/components/component-wrapper.d.ts +0 -5
  120. package/dist/shared/components/index.d.ts +0 -1
  121. package/dist/shared/components/plugin-ui-provider.d.ts +0 -37
  122. package/dist/shared-preact/components/component-wrapper.d.ts +0 -5
  123. package/dist/shared-preact/components/index.d.ts +0 -1
  124. package/dist/shared-preact/components/plugin-ui-provider.d.ts +0 -37
  125. package/dist/shared-react/components/component-wrapper.d.ts +0 -5
  126. package/dist/shared-react/components/index.d.ts +0 -1
  127. package/dist/shared-react/components/plugin-ui-provider.d.ts +0 -37
@@ -0,0 +1,67 @@
1
+ import { ComponentType } from '../preact/adapter.ts';
2
+ import { ToolbarSchema, PanelSchema, MenuSchema, SelectionMenuSchema } from '../lib/index.ts';
3
+ import { SelectionMenuPropsBase } from '../preact/utils.ts';
4
+ export type { SelectionMenuPropsBase };
5
+ export type UIComponents = Record<string, ComponentType<BaseComponentProps>>;
6
+ /**
7
+ * Base props that all custom components must accept
8
+ */
9
+ export interface BaseComponentProps {
10
+ documentId: string;
11
+ [key: string]: any;
12
+ }
13
+ /**
14
+ * Props for toolbar renderer
15
+ * The app provides a component matching this contract
16
+ */
17
+ export interface ToolbarRendererProps {
18
+ schema: ToolbarSchema;
19
+ documentId: string;
20
+ isOpen: boolean;
21
+ onClose?: () => void;
22
+ className?: string;
23
+ }
24
+ export type ToolbarRenderer = ComponentType<ToolbarRendererProps>;
25
+ /**
26
+ * Props for panel renderer
27
+ * The app provides a component matching this contract
28
+ */
29
+ export interface PanelRendererProps {
30
+ schema: PanelSchema;
31
+ documentId: string;
32
+ isOpen: boolean;
33
+ onClose: () => void;
34
+ className?: string;
35
+ }
36
+ export type PanelRenderer = ComponentType<PanelRendererProps>;
37
+ /**
38
+ * Props for menu renderer
39
+ * The app provides a component matching this contract
40
+ */
41
+ export interface MenuRendererProps {
42
+ schema: MenuSchema;
43
+ documentId: string;
44
+ anchorEl: HTMLElement | null;
45
+ onClose: () => void;
46
+ container?: HTMLElement | null;
47
+ }
48
+ export type MenuRenderer = ComponentType<MenuRendererProps>;
49
+ /**
50
+ * Props for the selection menu renderer component
51
+ */
52
+ export interface SelectionMenuRendererProps {
53
+ schema: SelectionMenuSchema;
54
+ documentId: string;
55
+ /** Full props from the layer including context */
56
+ props: SelectionMenuPropsBase;
57
+ }
58
+ export type SelectionMenuRenderer = ComponentType<SelectionMenuRendererProps>;
59
+ /**
60
+ * All renderers the app must provide
61
+ */
62
+ export interface UIRenderers {
63
+ toolbar: ToolbarRenderer;
64
+ panel: PanelRenderer;
65
+ menu: MenuRenderer;
66
+ selectionMenu: SelectionMenuRenderer;
67
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Automatically renders menus when opened
3
+ *
4
+ * This component:
5
+ * 1. Listens to UI plugin state for open menus
6
+ * 2. Looks up anchor elements from the anchor registry
7
+ * 3. Renders menus using the user-provided menu renderer
8
+ */
9
+ export interface AutoMenuRendererProps {
10
+ container?: HTMLElement | null;
11
+ documentId: string;
12
+ }
13
+ export declare function AutoMenuRenderer({ container, documentId }: AutoMenuRendererProps): import("react/jsx-runtime").JSX.Element | null;
@@ -1 +1,5 @@
1
1
  export * from './use-ui';
2
+ export * from './use-register-anchor';
3
+ export * from './use-item-renderer';
4
+ export * from './use-schema-renderer';
5
+ export * from './use-selection-menu';
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Helper utilities for building renderers
3
+ */
4
+ export declare function useItemRenderer(): {
5
+ /**
6
+ * Render a custom component by ID
7
+ *
8
+ * @param componentId - Component ID from schema
9
+ * @param documentId - Document ID
10
+ * @param props - Additional props to pass to component
11
+ * @returns Rendered component or null if not found
12
+ */
13
+ renderCustomComponent: (componentId: string, documentId: string, props?: any) => import("react/jsx-runtime").JSX.Element | null;
14
+ };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Register a DOM element as an anchor for menus
3
+ *
4
+ * @param documentId - Document ID
5
+ * @param itemId - Item ID (typically matches the toolbar/menu item ID)
6
+ * @returns Ref callback to attach to the element
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * function ZoomButton({ documentId }: Props) {
11
+ * const anchorRef = useRegisterAnchor(documentId, 'zoom-button');
12
+ *
13
+ * return <button ref={anchorRef}>Zoom</button>;
14
+ * }
15
+ * ```
16
+ */
17
+ export declare function useRegisterAnchor(documentId: string, itemId: string): (element: HTMLElement | null) => void;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * High-level hook for rendering UI from schema
3
+ *
4
+ * Provides simple functions to render toolbars and panels by placement+slot.
5
+ * Always passes isOpen state to renderers so they can control animations.
6
+ *
7
+ * Automatically subscribes to UI state changes for the given document.
8
+ */
9
+ export declare function useSchemaRenderer(documentId: string): {
10
+ /**
11
+ * Render a toolbar by placement and slot
12
+ *
13
+ * Always renders with isOpen state when toolbar exists in slot.
14
+ *
15
+ * @param placement - 'top' | 'bottom' | 'left' | 'right'
16
+ * @param slot - Slot name (e.g. 'main', 'secondary')
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * {renderToolbar('top', 'main')}
21
+ * {renderToolbar('top', 'secondary')}
22
+ * ```
23
+ */
24
+ renderToolbar: (placement: "top" | "bottom" | "left" | "right", slot: string) => import("react/jsx-runtime").JSX.Element | null;
25
+ /**
26
+ * Render a panel by placement and slot
27
+ *
28
+ * ALWAYS renders (when panel exists in slot) with isOpen state.
29
+ * Your renderer controls whether to display or animate.
30
+ *
31
+ * @param placement - 'left' | 'right' | 'top' | 'bottom'
32
+ * @param slot - Slot name (e.g. 'main', 'secondary', 'inspector')
33
+ *
34
+ * @example
35
+ * ```tsx
36
+ * {renderPanel('left', 'main')}
37
+ * {renderPanel('right', 'main')}
38
+ * ```
39
+ */
40
+ renderPanel: (placement: "left" | "right" | "top" | "bottom", slot: string) => import("react/jsx-runtime").JSX.Element | null;
41
+ /**
42
+ * Helper: Get all active toolbars for this document
43
+ * Useful for batch rendering or debugging
44
+ */
45
+ getActiveToolbars: () => {
46
+ placement: string;
47
+ slot: string;
48
+ toolbarId: string;
49
+ isOpen: boolean;
50
+ }[];
51
+ /**
52
+ * Helper: Get all active panels for this document
53
+ * Useful for batch rendering or debugging
54
+ */
55
+ getActivePanels: () => {
56
+ placement: string;
57
+ slot: string;
58
+ panelId: string;
59
+ isOpen: boolean;
60
+ }[];
61
+ };
@@ -0,0 +1,11 @@
1
+ import { SelectionMenuRenderFn } from '../../react/utils.ts';
2
+ /**
3
+ * Creates a render function for a selection menu from the schema
4
+ *
5
+ * @param menuId - The selection menu ID from schema
6
+ * @param documentId - Document ID
7
+ * @returns A render function compatible with layer selectionMenu props
8
+ */
9
+ export declare function useSelectionMenu<TContext extends {
10
+ type: string;
11
+ }>(menuId: string, documentId: string): SelectionMenuRenderFn<TContext> | undefined;
@@ -1,11 +1,19 @@
1
- import { UIPlugin } from '../../lib/index.ts';
2
- export declare const useUIPlugin: () => {
3
- plugin: UIPlugin | null;
1
+ import { UIPlugin, UIDocumentState, UISchema } from '../../lib/index.ts';
2
+ export declare const useUICapability: () => {
3
+ provides: Readonly<import('../../lib/index.ts').UICapability> | null;
4
4
  isLoading: boolean;
5
5
  ready: Promise<void>;
6
6
  };
7
- export declare const useUICapability: () => {
8
- provides: Readonly<import('../../lib/index.ts').UICapability> | null;
7
+ export declare const useUIPlugin: () => {
8
+ plugin: UIPlugin | null;
9
9
  isLoading: boolean;
10
10
  ready: Promise<void>;
11
11
  };
12
+ /**
13
+ * Get UI state for a document
14
+ */
15
+ export declare const useUIState: (documentId: string) => UIDocumentState | null;
16
+ /**
17
+ * Get UI schema
18
+ */
19
+ export declare const useUISchema: () => UISchema | null;
@@ -1,3 +1,6 @@
1
- export * from './components';
2
1
  export * from './hooks';
2
+ export * from './registries';
3
+ export { UIProvider } from './provider';
4
+ export type { UIProviderProps } from './provider';
5
+ export * from './types';
3
6
  export * from '../lib/index.ts';
@@ -0,0 +1,68 @@
1
+ import { ReactNode, ComponentType, HTMLAttributes } from '../react/adapter.ts';
2
+ import { BaseComponentProps, UIRenderers } from './types';
3
+ /**
4
+ * UIProvider Props
5
+ */
6
+ export interface UIProviderProps extends HTMLAttributes<HTMLDivElement> {
7
+ children: ReactNode;
8
+ /**
9
+ * Document ID for this UI context
10
+ * Required for menu rendering
11
+ */
12
+ documentId: string;
13
+ /**
14
+ * Custom component registry
15
+ * Maps component IDs to components
16
+ */
17
+ components?: Record<string, ComponentType<BaseComponentProps>>;
18
+ /**
19
+ * REQUIRED: User-provided renderers
20
+ * These define how toolbars, panels, and menus are displayed
21
+ */
22
+ renderers: UIRenderers;
23
+ /**
24
+ * Optional: Container for menu portal
25
+ * Defaults to document.body
26
+ */
27
+ menuContainer?: HTMLElement | null;
28
+ }
29
+ /**
30
+ * UIProvider - Single provider for all UI plugin functionality
31
+ *
32
+ * Manages:
33
+ * - Anchor registry for menu positioning
34
+ * - Component registry for custom components
35
+ * - Renderers for toolbars, panels, and menus
36
+ * - Automatic menu rendering
37
+ *
38
+ * @example
39
+ * ```tsx
40
+ * <EmbedPDF engine={engine} plugins={plugins}>
41
+ * {({ pluginsReady }) => (
42
+ * pluginsReady && (
43
+ * <DocumentContext>
44
+ * {({ activeDocumentId }) => (
45
+ * activeDocumentId && (
46
+ * <UIProvider
47
+ * documentId={activeDocumentId}
48
+ * components={{
49
+ * 'thumbnail-panel': ThumbnailPanel,
50
+ * 'bookmark-panel': BookmarkPanel,
51
+ * }}
52
+ * renderers={{
53
+ * toolbar: ToolbarRenderer,
54
+ * panel: PanelRenderer,
55
+ * menu: MenuRenderer,
56
+ * }}
57
+ * >
58
+ * <ViewerLayout />
59
+ * </UIProvider>
60
+ * )
61
+ * )}
62
+ * </DocumentContext>
63
+ * )
64
+ * )}
65
+ * </EmbedPDF>
66
+ * ```
67
+ */
68
+ export declare function UIProvider({ children, documentId, components, renderers, menuContainer, ...restProps }: UIProviderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,16 @@
1
+ import { ReactNode } from '../../react/adapter.ts';
2
+ /**
3
+ * Anchor Registry
4
+ *
5
+ * Tracks DOM elements for menu positioning.
6
+ * Each anchor is scoped by documentId and itemId.
7
+ */
8
+ export interface AnchorRegistry {
9
+ register(documentId: string, itemId: string, element: HTMLElement): void;
10
+ unregister(documentId: string, itemId: string): void;
11
+ getAnchor(documentId: string, itemId: string): HTMLElement | null;
12
+ }
13
+ export declare function AnchorRegistryProvider({ children }: {
14
+ children: ReactNode;
15
+ }): import("react/jsx-runtime").JSX.Element;
16
+ export declare function useAnchorRegistry(): AnchorRegistry;
@@ -0,0 +1,20 @@
1
+ import { ComponentType, ReactNode } from '../../react/adapter.ts';
2
+ import { BaseComponentProps } from '../types';
3
+ /**
4
+ * Component Registry
5
+ *
6
+ * Stores custom components that can be referenced in the UI schema.
7
+ */
8
+ export interface ComponentRegistry {
9
+ register(id: string, component: ComponentType<BaseComponentProps>): void;
10
+ unregister(id: string): void;
11
+ get(id: string): ComponentType<BaseComponentProps> | undefined;
12
+ has(id: string): boolean;
13
+ getRegisteredIds(): string[];
14
+ }
15
+ export interface ComponentRegistryProviderProps {
16
+ children: ReactNode;
17
+ initialComponents?: Record<string, ComponentType<BaseComponentProps>>;
18
+ }
19
+ export declare function ComponentRegistryProvider({ children, initialComponents, }: ComponentRegistryProviderProps): import("react/jsx-runtime").JSX.Element;
20
+ export declare function useComponentRegistry(): ComponentRegistry;
@@ -0,0 +1,3 @@
1
+ export * from './anchor-registry';
2
+ export * from './component-registry';
3
+ export * from './renderers-registry';
@@ -0,0 +1,8 @@
1
+ import { ReactNode } from '../../react/adapter.ts';
2
+ import { UIRenderers } from '../types';
3
+ export interface RenderersProviderProps {
4
+ children: ReactNode;
5
+ renderers: UIRenderers;
6
+ }
7
+ export declare function RenderersProvider({ children, renderers }: RenderersProviderProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function useRenderers(): UIRenderers;
@@ -0,0 +1,12 @@
1
+ import { ReactNode, HTMLAttributes } from '../react/adapter.ts';
2
+ interface UIRootProps extends HTMLAttributes<HTMLDivElement> {
3
+ children: ReactNode;
4
+ }
5
+ /**
6
+ * Internal component that handles:
7
+ * 1. Injecting the generated stylesheet (into shadow root or document.head)
8
+ * 2. Managing the data-disabled-categories attribute
9
+ * 3. Updating styles on locale changes
10
+ */
11
+ export declare function UIRoot({ children, ...restProps }: UIRootProps): import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -0,0 +1,67 @@
1
+ import { ComponentType } from '../react/adapter.ts';
2
+ import { ToolbarSchema, PanelSchema, MenuSchema, SelectionMenuSchema } from '../lib/index.ts';
3
+ import { SelectionMenuPropsBase } from '../react/utils.ts';
4
+ export type { SelectionMenuPropsBase };
5
+ export type UIComponents = Record<string, ComponentType<BaseComponentProps>>;
6
+ /**
7
+ * Base props that all custom components must accept
8
+ */
9
+ export interface BaseComponentProps {
10
+ documentId: string;
11
+ [key: string]: any;
12
+ }
13
+ /**
14
+ * Props for toolbar renderer
15
+ * The app provides a component matching this contract
16
+ */
17
+ export interface ToolbarRendererProps {
18
+ schema: ToolbarSchema;
19
+ documentId: string;
20
+ isOpen: boolean;
21
+ onClose?: () => void;
22
+ className?: string;
23
+ }
24
+ export type ToolbarRenderer = ComponentType<ToolbarRendererProps>;
25
+ /**
26
+ * Props for panel renderer
27
+ * The app provides a component matching this contract
28
+ */
29
+ export interface PanelRendererProps {
30
+ schema: PanelSchema;
31
+ documentId: string;
32
+ isOpen: boolean;
33
+ onClose: () => void;
34
+ className?: string;
35
+ }
36
+ export type PanelRenderer = ComponentType<PanelRendererProps>;
37
+ /**
38
+ * Props for menu renderer
39
+ * The app provides a component matching this contract
40
+ */
41
+ export interface MenuRendererProps {
42
+ schema: MenuSchema;
43
+ documentId: string;
44
+ anchorEl: HTMLElement | null;
45
+ onClose: () => void;
46
+ container?: HTMLElement | null;
47
+ }
48
+ export type MenuRenderer = ComponentType<MenuRendererProps>;
49
+ /**
50
+ * Props for the selection menu renderer component
51
+ */
52
+ export interface SelectionMenuRendererProps {
53
+ schema: SelectionMenuSchema;
54
+ documentId: string;
55
+ /** Full props from the layer including context */
56
+ props: SelectionMenuPropsBase;
57
+ }
58
+ export type SelectionMenuRenderer = ComponentType<SelectionMenuRendererProps>;
59
+ /**
60
+ * All renderers the app must provide
61
+ */
62
+ export interface UIRenderers {
63
+ toolbar: ToolbarRenderer;
64
+ panel: PanelRenderer;
65
+ menu: MenuRenderer;
66
+ selectionMenu: SelectionMenuRenderer;
67
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Automatically renders menus when opened
3
+ *
4
+ * This component:
5
+ * 1. Listens to UI plugin state for open menus
6
+ * 2. Looks up anchor elements from the anchor registry
7
+ * 3. Renders menus using the user-provided menu renderer
8
+ */
9
+ interface Props {
10
+ documentId: string;
11
+ container?: HTMLElement | null;
12
+ }
13
+ declare const AutoMenuRenderer: import('svelte', { with: { "resolution-mode": "import" } }).Component<Props, {}, "">;
14
+ type AutoMenuRenderer = ReturnType<typeof AutoMenuRenderer>;
15
+ export default AutoMenuRenderer;
@@ -0,0 +1,5 @@
1
+ export * from './use-ui.svelte';
2
+ export * from './use-register-anchor.svelte';
3
+ export * from './use-item-renderer.svelte';
4
+ export * from './use-schema-renderer.svelte';
5
+ export * from './use-selection-menu.svelte';
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Helper utilities for building renderers
3
+ */
4
+ export declare function useItemRenderer(): {
5
+ /**
6
+ * Get a custom component by ID
7
+ *
8
+ * @param componentId - Component ID from schema
9
+ * @returns Component constructor or undefined if not found
10
+ *
11
+ * @example
12
+ * ```svelte
13
+ * <script lang="ts">
14
+ * const { getCustomComponent } = useItemRenderer();
15
+ * const MyComponent = getCustomComponent('my-component-id');
16
+ * </script>
17
+ *
18
+ * {#if MyComponent}
19
+ * <MyComponent {documentId} {...props} />
20
+ * {/if}
21
+ * ```
22
+ */
23
+ getCustomComponent: (componentId: string) => import('svelte').Component<import('..').BaseComponentProps, {}, string> | undefined;
24
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Register a DOM element as an anchor for menus
3
+ *
4
+ * @param getDocumentId - Function returning document ID
5
+ * @param getItemId - Function returning item ID (typically matches the toolbar/menu item ID)
6
+ * @returns Function to attach to the element via use:action
7
+ *
8
+ * @example
9
+ *
10
+ * <script lang="ts">
11
+ * const registerAnchor = useRegisterAnchor(() => documentId, () => 'zoom-button');
12
+ * </script>
13
+ *
14
+ * <button use:registerAnchor>Zoom</button>
15
+ * */
16
+ export declare function useRegisterAnchor(getDocumentId: () => string | null, getItemId: () => string): (element: HTMLElement) => {
17
+ destroy(): void;
18
+ };
@@ -0,0 +1,78 @@
1
+ /**
2
+ * High-level hook for rendering UI from schema
3
+ *
4
+ * Provides information about active toolbars and panels by placement+slot.
5
+ * Always includes isOpen state so renderers can control animations.
6
+ *
7
+ * Use with Svelte's component binding to render toolbars and panels.
8
+ *
9
+ * @example
10
+ * ```svelte
11
+ * <script lang="ts">
12
+ * const { getToolbarInfo, getPanelInfo } = useSchemaRenderer(() => documentId);
13
+ *
14
+ * const topMainToolbar = $derived(getToolbarInfo('top', 'main'));
15
+ * const leftMainPanel = $derived(getPanelInfo('left', 'main'));
16
+ * </script>
17
+ *
18
+ * {#if topMainToolbar}
19
+ * {@const ToolbarRenderer = topMainToolbar.renderer}
20
+ * <ToolbarRenderer
21
+ * schema={topMainToolbar.schema}
22
+ * documentId={topMainToolbar.documentId}
23
+ * isOpen={topMainToolbar.isOpen}
24
+ * onClose={topMainToolbar.onClose}
25
+ * />
26
+ * {/if}
27
+ * ```
28
+ */
29
+ export declare function useSchemaRenderer(getDocumentId: () => string | null): {
30
+ /**
31
+ * Get toolbar information by placement and slot
32
+ *
33
+ * @param placement - 'top' | 'bottom' | 'left' | 'right'
34
+ * @param slot - Slot name (e.g. 'main', 'secondary')
35
+ * @returns Toolbar info or null if no toolbar in slot
36
+ */
37
+ getToolbarInfo: (placement: "top" | "bottom" | "left" | "right", slot: string) => {
38
+ renderer: import('..').ToolbarRenderer;
39
+ schema: import('../../lib').ToolbarSchema;
40
+ documentId: string;
41
+ isOpen: boolean;
42
+ onClose: (() => void) | undefined;
43
+ } | null;
44
+ /**
45
+ * Get panel information by placement and slot
46
+ *
47
+ * @param placement - 'left' | 'right' | 'top' | 'bottom'
48
+ * @param slot - Slot name (e.g. 'main', 'secondary', 'inspector')
49
+ * @returns Panel info or null if no panel in slot
50
+ */
51
+ getPanelInfo: (placement: "left" | "right" | "top" | "bottom", slot: string) => {
52
+ renderer: import('..').PanelRenderer;
53
+ schema: import('../../lib').PanelSchema;
54
+ documentId: string;
55
+ isOpen: boolean;
56
+ onClose: () => void;
57
+ } | null;
58
+ /**
59
+ * Helper: Get all active toolbars for this document
60
+ * Useful for batch rendering or debugging
61
+ */
62
+ getActiveToolbars: () => {
63
+ placement: string;
64
+ slot: string;
65
+ toolbarId: string;
66
+ isOpen: boolean;
67
+ }[];
68
+ /**
69
+ * Helper: Get all active panels for this document
70
+ * Useful for batch rendering or debugging
71
+ */
72
+ getActivePanels: () => {
73
+ placement: string;
74
+ slot: string;
75
+ panelId: string;
76
+ isOpen: boolean;
77
+ }[];
78
+ };
@@ -0,0 +1,9 @@
1
+ import { SelectionMenuRenderFn } from '@embedpdf/utils/svelte';
2
+ /**
3
+ * Hook for schema-driven selection menus
4
+ */
5
+ export declare function useSelectionMenu<TContext extends {
6
+ type: string;
7
+ }>(menuId: string | (() => string), getDocumentId: () => string): {
8
+ readonly renderFn: SelectionMenuRenderFn<TContext> | undefined;
9
+ };
@@ -0,0 +1,34 @@
1
+ import { UIPlugin, UIDocumentState, UISchema, UIScope } from '../../lib';
2
+ /**
3
+ * Hook to get the raw UI plugin instance.
4
+ */
5
+ export declare const useUIPlugin: () => {
6
+ plugin: UIPlugin | null;
7
+ isLoading: boolean;
8
+ ready: Promise<void>;
9
+ };
10
+ /**
11
+ * Hook to get the UI plugin's capability API.
12
+ */
13
+ export declare const useUICapability: () => {
14
+ provides: Readonly<import('../../lib').UICapability> | null;
15
+ isLoading: boolean;
16
+ ready: Promise<void>;
17
+ };
18
+ interface UseUIStateReturn {
19
+ provides: UIScope | null;
20
+ state: UIDocumentState | null;
21
+ }
22
+ /**
23
+ * Hook for UI state for a specific document
24
+ * @param getDocumentId Function that returns the document ID
25
+ */
26
+ export declare const useUIState: (getDocumentId: () => string | null) => UseUIStateReturn;
27
+ /**
28
+ * Hook to get UI schema
29
+ * Returns an object with a reactive getter for the schema
30
+ */
31
+ export declare const useUISchema: () => {
32
+ readonly schema: UISchema | null;
33
+ };
34
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/plugin-ui"),t=require("svelte/internal/client"),n=require("@embedpdf/core/svelte"),r=require("svelte");function o(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const n in e)if("default"!==n){const r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:()=>e[n]})}return t.default=e,Object.freeze(t)}require("svelte/internal/disclose-version");const s=o(t),i=()=>n.usePlugin(e.UIPlugin.id),l=()=>n.useCapability(e.UIPlugin.id),u=e=>{const t=l();let n=s.state(null);const r=s.derived(e),o=s.derived(()=>t.provides&&s.get(r)?t.provides.forDocument(s.get(r)):null);return s.user_effect(()=>{const e=t.provides,o=s.get(r);if(!e||!o)return void s.set(n,null);const i=e.forDocument(o);s.set(n,i.getState(),!0);const l=i.onToolbarChanged(()=>{s.set(n,i.getState(),!0)}),u=i.onPanelChanged(()=>{s.set(n,i.getState(),!0)}),c=i.onModalChanged(()=>{s.set(n,i.getState(),!0)}),d=i.onMenuChanged(()=>{s.set(n,i.getState(),!0)});return()=>{l(),u(),c(),d()}}),{get provides(){return s.get(o)},get state(){return s.get(n)}}},c=Symbol("AnchorRegistry");function d(){const e=new Map;return{register(t,n,r){const o=`${t}:${n}`;e.set(o,r)},unregister(t,n){const r=`${t}:${n}`;e.delete(r)},getAnchor(t,n){const r=`${t}:${n}`;return e.get(r)||null}}}function a(){const e=d();return r.setContext(c,e),e}function p(){const e=r.getContext(c);if(!e)throw new Error("useAnchorRegistry must be used within UIProvider");return e}const g=Symbol("ComponentRegistry");function f(e={}){const t=new Map(Object.entries(e));return{register(e,n){t.set(e,n)},unregister(e){t.delete(e)},get:e=>t.get(e),has:e=>t.has(e),getRegisteredIds:()=>Array.from(t.keys())}}function v(e={}){const t=f(e);return r.setContext(g,t),t}function m(){const e=r.getContext(g);if(!e)throw new Error("useComponentRegistry must be used within UIProvider");return e}const h=Symbol("Renderers");function I(e){r.setContext(h,e)}function b(){const e=r.getContext(h);if(!e)throw new Error("useRenderers must be used within UIProvider");return e}function y(e,t){s.push(t,!0);let n=s.prop(t,"container",3,null);const r=u(()=>t.documentId),o=l(),i=p(),c=b(),d=s.derived(()=>{var e;const n=(null==(e=r.state)?void 0:e.openMenus)||{},o=Object.keys(n);if(0===o.length)return null;const s=o[0];if(!s)return null;const l=n[s];if(!l||!l.triggeredByItemId)return null;return{menuId:s,anchorEl:i.getAnchor(t.documentId,l.triggeredByItemId)}}),a=s.derived(()=>{var e;return null==(e=o.provides)?void 0:e.getSchema()}),g=s.derived(()=>{if(!s.get(d)||!s.get(a))return null;const e=s.get(a).menus[s.get(d).menuId];return e||(console.warn(`Menu "${s.get(d).menuId}" not found in schema`),null)}),f=()=>{var e;s.get(d)&&(null==(e=r.provides)||e.closeMenu(s.get(d).menuId))},v=c.menu;var m=s.comment(),h=s.first_child(m),I=e=>{v(e,{get schema(){return s.get(g)},get documentId(){return t.documentId},get anchorEl(){return s.get(d).anchorEl},onClose:f,get container(){return n()}})};s.if(h,e=>{s.get(d)&&s.get(g)&&v&&e(I)}),s.append(e,m),s.pop()}var S=s.from_html("<div><!></div>");function C(t,n){s.push(n,!0);let r=s.rest_props(n,["$$slots","$$events","$$legacy","children","class"]);const{plugin:o}=i(),{provides:u}=l();let c=s.state(s.proxy([])),d=s.state(null),a=null,p=null;s.user_effect(()=>{if(!s.get(d)||!o)return void(p=null);p=function(e){const t=e.getRootNode();return t instanceof ShadowRoot?t:document.head}(s.get(d));const t=p.querySelector(e.UI_SELECTORS.STYLES);if(t)return a=t,void(t.textContent=o.getStylesheet());const n=o.getStylesheet(),r=document.createElement("style");return r.setAttribute(e.UI_ATTRIBUTES.STYLES,""),r.textContent=n,p instanceof ShadowRoot?p.insertBefore(r,p.firstChild):p.appendChild(r),a=r,()=>{(null==a?void 0:a.parentNode)&&a.remove(),a=null,p=null}}),s.user_effect(()=>{if(o)return o.onStylesheetInvalidated(()=>{a&&(a.textContent=o.getStylesheet())})}),s.user_effect(()=>{if(u)return s.set(c,u.getDisabledCategories(),!0),u.onCategoryChanged(e=>{s.set(c,e.disabledCategories,!0)})});const g=s.derived(()=>s.get(c).length>0?s.get(c).join(" "):void 0);var f=S();s.attribute_effect(f,()=>({...r,[e.UI_ATTRIBUTES.ROOT]:"",...s.get(g)?{[e.UI_ATTRIBUTES.DISABLED_CATEGORIES]:s.get(g)}:{},class:n.class,[s.STYLE]:{"container-type":"inline-size"}}));var v=s.child(f),m=e=>{var t=s.comment(),r=s.first_child(t);s.snippet(r,()=>n.children),s.append(e,t)};s.if(v,e=>{n.children&&e(m)}),s.reset(f),s.bind_this(f,e=>s.set(d,e),()=>s.get(d)),s.append(t,f),s.pop()}var x=s.from_html("<!> <!>",1);exports.AutoMenuRenderer=y,exports.UIProvider=function(e,t){s.push(t,!0);let n=s.prop(t,"components",19,()=>({})),r=s.prop(t,"menuContainer",3,null),o=s.rest_props(t,["$$slots","$$events","$$legacy","children","documentId","components","renderers","menuContainer","class"]);a(),v(n()),I(t.renderers),C(e,s.spread_props({get class(){return t.class}},()=>o,{children:(e,n)=>{var o=x(),i=s.first_child(o);s.snippet(i,()=>t.children),y(s.sibling(i,2),{get documentId(){return t.documentId},get container(){return r()}}),s.append(e,o)},$$slots:{default:!0}})),s.pop()},exports.createAnchorRegistry=d,exports.createComponentRegistry=f,exports.provideAnchorRegistry=a,exports.provideComponentRegistry=v,exports.provideRenderers=I,exports.useAnchorRegistry=p,exports.useComponentRegistry=m,exports.useItemRenderer=function(){const e=m();return{getCustomComponent:t=>{const n=e.get(t);if(n)return n;console.error(`Component "${t}" not found in registry`)}}},exports.useRegisterAnchor=function(e,t){const n=p();let r=s.state(null);const o=s.derived(e),i=s.derived(t);return s.user_effect(()=>{const e=s.get(o),t=s.get(i),l=s.get(r);if(l&&e&&t)return n.register(e,t,l),()=>{n.unregister(e,t)}}),e=>(s.set(r,e,!0),{destroy(){s.set(r,null)}})},exports.useRenderers=b,exports.useSchemaRenderer=function(e){const t=b(),n=l(),r=u(e);return{getToolbarInfo:(o,s)=>{var i;const l=null==(i=n.provides)?void 0:i.getSchema(),u=e();if(!(l&&r.provides&&r.state&&u))return null;const c=`${o}-${s}`,d=r.state.activeToolbars[c];if(!d)return null;const a=l.toolbars[d.toolbarId];if(!a)return console.warn(`Toolbar "${d.toolbarId}" not found in schema`),null;const p=!a.permanent?()=>{var e;null==(e=r.provides)||e.closeToolbarSlot(o,s)}:void 0;return{renderer:t.toolbar,schema:a,documentId:u,isOpen:d.isOpen,onClose:p}},getPanelInfo:(o,s)=>{var i;const l=null==(i=n.provides)?void 0:i.getSchema(),u=e();if(!(l&&r.provides&&r.state&&u))return null;const c=`${o}-${s}`,d=r.state.activePanels[c];if(!d)return null;const a=l.panels[d.panelId];if(!a)return console.warn(`Panel "${d.panelId}" not found in schema`),null;return{renderer:t.panel,schema:a,documentId:u,isOpen:d.isOpen,onClose:()=>{var e;null==(e=r.provides)||e.closePanelSlot(o,s)}}},getActiveToolbars:()=>r.state?Object.entries(r.state.activeToolbars).map(([e,t])=>{const[n,r]=e.split("-");return{placement:n,slot:r,toolbarId:t.toolbarId,isOpen:t.isOpen}}):[],getActivePanels:()=>r.state?Object.entries(r.state.activePanels).map(([e,t])=>{const[n,r]=e.split("-");return{placement:n,slot:r,panelId:t.panelId,isOpen:t.isOpen}}):[]}},exports.useSelectionMenu=function(e,t){const n=l(),r=b(),o="function"==typeof e?e:()=>e,i=s.derived(o),u=s.derived(t),c=s.derived(()=>{var e;return null==(e=n.provides)?void 0:e.getSchema()}),d=s.derived(()=>{var e,t;return null==(t=null==(e=s.get(c))?void 0:e.selectionMenus)?void 0:t[s.get(i)]}),a=s.derived(()=>{if(!s.get(d))return;const e=s.get(d),t=s.get(u),n=r.selectionMenu;return r=>r.selected?{component:n,props:{schema:e,documentId:t,props:r}}:null});return{get renderFn(){return s.get(a)}}},exports.useUICapability=l,exports.useUIPlugin=i,exports.useUISchema=()=>{const e=l();return{get schema(){var t;return(null==(t=e.provides)?void 0:t.getSchema())??null}}},exports.useUIState=u,Object.keys(e).forEach(t=>{"default"===t||Object.prototype.hasOwnProperty.call(exports,t)||Object.defineProperty(exports,t,{enumerable:!0,get:()=>e[t]})});
2
+ //# sourceMappingURL=index.cjs.map