@draftably/vue 0.2.1 → 0.4.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/README.md CHANGED
@@ -8,5 +8,10 @@ cleanup when it unmounts. Any number of diagrams can share a page.
8
8
  pnpm add @draftably/vue
9
9
  ```
10
10
 
11
- See [Frameworks](https://draftably.dev/docs/frameworks) for the component, server
12
- rendering with the `svg` prop, and a complete example.
11
+ Import `@draftably/runtime/host.css` once in your client entry: it reserves each element's height
12
+ and hides slot content until the element loads. With Vite, add
13
+ `optimizeDeps: { exclude: ['@draftably/runtime', '@draftably/editor'] }` to `vite.config`.
14
+
15
+ The [Vue recipe](https://draftably.dev/docs/frameworks#vue) is a complete, type-checked app: both
16
+ components, an event, your content on a node, a dark theme and server rendering with the `svg`
17
+ prop. CI compiles it from the packed packages.
package/dist/editor.d.ts CHANGED
@@ -1,22 +1,78 @@
1
1
  /** `<DraftEditor>` for Vue 3: drag boxes and lines, and get the `.draft` source back. */
2
- import type { DraftEditorElement } from '@draftably/editor/element';
3
- export type { DraftEditorElement };
2
+ import type { DraftEditorElement, EditorOptions } from '@draftably/editor/element';
3
+ import { type PropType } from 'vue';
4
+ export type { DraftEditorElement, EditorOptions };
4
5
  export declare const DraftEditor: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
5
- /** `.draft` source. Passing back the text from `change` does not redraw. */
6
+ /** `.draft` source. Passing back the source from `change` does not redraw. */
6
7
  source: {
7
8
  type: StringConstructor;
8
9
  required: true;
9
10
  };
11
+ /** Every `mountEditor` option but `source` and `onChange`. Callbacks apply live. */
12
+ options: {
13
+ type: PropType<EditorOptions>;
14
+ default: undefined;
15
+ };
10
16
  }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
11
17
  [key: string]: any;
12
- }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
13
- change: (_source: string) => true;
14
- }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
15
- /** `.draft` source. Passing back the text from `change` does not redraw. */
18
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, import("./events.js").HostEmits, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
19
+ /** `.draft` source. Passing back the source from `change` does not redraw. */
16
20
  source: {
17
21
  type: StringConstructor;
18
22
  required: true;
19
23
  };
24
+ /** Every `mountEditor` option but `source` and `onChange`. Callbacks apply live. */
25
+ options: {
26
+ type: PropType<EditorOptions>;
27
+ default: undefined;
28
+ };
20
29
  }>> & Readonly<{
21
- onChange?: ((_source: string) => any) | undefined;
22
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
30
+ onAnchors?: ((detail: {
31
+ anchors: readonly import("@draftably/runtime/viewer").Anchor[];
32
+ }) => any) | undefined;
33
+ onUpdate?: ((detail: import("@draftably/runtime/viewer").UpdateResult) => any) | undefined;
34
+ onRender?: ((detail: {
35
+ revision: number;
36
+ value: Extract<import("@draftably/runtime").RenderResult, {
37
+ ok: true;
38
+ }>["value"];
39
+ geometry: import("@draftably/runtime").Geometry | null;
40
+ }) => any) | undefined;
41
+ onDiagnostics?: ((detail: {
42
+ revision: number;
43
+ diagnostics: readonly import("@draftably/runtime").Diagnostic[];
44
+ stale: boolean;
45
+ }) => any) | undefined;
46
+ onCamera?: ((detail: {
47
+ camera: import("@draftably/runtime/viewer").Camera;
48
+ reason: import("@draftably/runtime/viewer").CameraReason;
49
+ }) => any) | undefined;
50
+ onItemactivate?: ((detail: {
51
+ id: string;
52
+ kind: "node" | "group" | "edge";
53
+ input: "pointer" | "keyboard";
54
+ revision: number;
55
+ }) => any) | undefined;
56
+ onLink?: ((detail: Omit<{
57
+ itemId: string;
58
+ href: string;
59
+ target: "_self" | "_blank";
60
+ preventDefault(): void;
61
+ }, "preventDefault">) => any) | undefined;
62
+ onContextmenu?: ((detail: Omit<{
63
+ id: string | null;
64
+ kind?: import("@draftably/runtime/viewer").ItemKind;
65
+ clientX: number;
66
+ clientY: number;
67
+ preventDefault(): void;
68
+ }, "preventDefault">) => any) | undefined;
69
+ onSelect?: ((detail: {
70
+ ids: readonly string[];
71
+ reason: "user" | "api";
72
+ }) => any) | undefined;
73
+ onChange?: ((detail: {
74
+ source: string;
75
+ }) => any) | undefined;
76
+ }>, {
77
+ options: EditorOptions;
78
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
package/dist/editor.js CHANGED
@@ -1,21 +1,31 @@
1
- import { defineComponent, h, onBeforeUnmount, onMounted, ref } from 'vue';
1
+ import { defineComponent, h, onMounted, ref } from 'vue';
2
+ import { hostEmits, listenHostEvents } from './events.js';
2
3
  export const DraftEditor = defineComponent({
3
4
  name: 'DraftEditor',
4
5
  props: {
5
- /** `.draft` source. Passing back the text from `change` does not redraw. */
6
+ /** `.draft` source. Passing back the source from `change` does not redraw. */
6
7
  source: { type: String, required: true },
8
+ /** Every `mountEditor` option but `source` and `onChange`. Callbacks apply live. */
9
+ options: { type: Object, default: undefined },
7
10
  },
8
- emits: { change: (_source) => true },
9
- setup(props, { emit, expose }) {
11
+ emits: hostEmits,
12
+ setup(props, { emit, expose, slots }) {
10
13
  const el = ref();
11
- const listen = (event) => emit('change', event.detail);
12
14
  onMounted(() => {
15
+ listenHostEvents(el.value, emit);
13
16
  // The editor loads in the browser only, so server rendering and viewer-only pages skip it.
14
- void import('@draftably/editor/element');
15
- el.value?.addEventListener('draft-change', listen);
17
+ import('@draftably/editor/element').catch((error) => {
18
+ el.value?.setAttribute('status', 'error');
19
+ el.value?.setAttribute('data-error', String(error));
20
+ });
16
21
  });
17
- onBeforeUnmount(() => el.value?.removeEventListener('draft-change', listen));
18
22
  expose({ element: el });
19
- return () => h('draft-editor', { ref: el, source: props.source });
23
+ // The default slot holds slot content: children marked `data-draft-slot`.
24
+ return () => h('draft-editor', {
25
+ ref: el,
26
+ source: props.source,
27
+ // Only when set, so options a host set through the ref survive.
28
+ ...(props.options === undefined ? {} : { '.options': props.options }),
29
+ }, slots.default?.());
20
30
  },
21
31
  });
@@ -0,0 +1,10 @@
1
+ /** Emits from the runtime's one list of events: a new event adds no lines here. */
2
+ import { type HostEventName, type HostEvents } from '@draftably/runtime/host';
3
+ export type { HostEventName, HostEvents };
4
+ /** `@camera`, `@select`, … : each receives the event's `detail`. */
5
+ export type HostEmits = {
6
+ [K in HostEventName]: (detail: HostEvents[K]) => true;
7
+ };
8
+ export declare const hostEmits: HostEmits;
9
+ /** Re-emit every host event from `node`. */
10
+ export declare function listenHostEvents(node: HTMLElement, emit: (name: HostEventName, detail: unknown) => void): void;
package/dist/events.js ADDED
@@ -0,0 +1,8 @@
1
+ /** Emits from the runtime's one list of events: a new event adds no lines here. */
2
+ import { HOST_EVENTS } from '@draftably/runtime/host';
3
+ export const hostEmits = Object.fromEntries(HOST_EVENTS.map(name => [name, null]));
4
+ /** Re-emit every host event from `node`. */
5
+ export function listenHostEvents(node, emit) {
6
+ for (const name of HOST_EVENTS)
7
+ node.addEventListener(`draft-${name}`, event => emit(name, event.detail));
8
+ }
package/dist/index.d.ts CHANGED
@@ -1,8 +1,11 @@
1
- /** `<DraftDiagram>` for Vue 3: the `<draft-diagram>` element with Vue props and an `update` event. */
1
+ /** `<DraftDiagram>` for Vue 3: the `<draft-diagram>` element with Vue props and events. */
2
2
  import '@draftably/runtime/element';
3
3
  import type { DraftDiagramElement } from '@draftably/runtime/element';
4
4
  import type { UpdateResult, ViewerOptions } from '@draftably/runtime/viewer';
5
5
  import { type PropType } from 'vue';
6
+ export { renderSvg } from '@draftably/runtime';
7
+ export { HOST_EVENTS } from '@draftably/runtime/host';
8
+ export type { HostEmits, HostEventName, HostEvents } from './events.js';
6
9
  export type { DraftDiagramElement, UpdateResult, ViewerOptions };
7
10
  export declare const DraftDiagram: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
8
11
  /** `.draft` source. A change redraws the diagram and keeps the camera. */
@@ -30,15 +33,14 @@ export declare const DraftDiagram: import("vue").DefineComponent<import("vue").E
30
33
  type: StringConstructor;
31
34
  default: undefined;
32
35
  };
36
+ /** Every `mountViewer` option. A new object with the same values does nothing. */
33
37
  options: {
34
38
  type: PropType<ViewerOptions>;
35
39
  default: undefined;
36
40
  };
37
41
  }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
38
42
  [key: string]: any;
39
- }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
40
- update: (_result: UpdateResult) => true;
41
- }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
43
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, import("./events.js").HostEmits, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
42
44
  /** `.draft` source. A change redraws the diagram and keeps the camera. */
43
45
  source: {
44
46
  type: StringConstructor;
@@ -64,17 +66,63 @@ export declare const DraftDiagram: import("vue").DefineComponent<import("vue").E
64
66
  type: StringConstructor;
65
67
  default: undefined;
66
68
  };
69
+ /** Every `mountViewer` option. A new object with the same values does nothing. */
67
70
  options: {
68
71
  type: PropType<ViewerOptions>;
69
72
  default: undefined;
70
73
  };
71
74
  }>> & Readonly<{
72
- onUpdate?: ((_result: UpdateResult) => any) | undefined;
75
+ onAnchors?: ((detail: {
76
+ anchors: readonly import("@draftably/runtime/viewer").Anchor[];
77
+ }) => any) | undefined;
78
+ onUpdate?: ((detail: UpdateResult) => any) | undefined;
79
+ onRender?: ((detail: {
80
+ revision: number;
81
+ value: Extract<import("@draftably/runtime").RenderResult, {
82
+ ok: true;
83
+ }>["value"];
84
+ geometry: import("@draftably/runtime").Geometry | null;
85
+ }) => any) | undefined;
86
+ onDiagnostics?: ((detail: {
87
+ revision: number;
88
+ diagnostics: readonly import("@draftably/runtime").Diagnostic[];
89
+ stale: boolean;
90
+ }) => any) | undefined;
91
+ onCamera?: ((detail: {
92
+ camera: import("@draftably/runtime/viewer").Camera;
93
+ reason: import("@draftably/runtime/viewer").CameraReason;
94
+ }) => any) | undefined;
95
+ onItemactivate?: ((detail: {
96
+ id: string;
97
+ kind: "node" | "group" | "edge";
98
+ input: "pointer" | "keyboard";
99
+ revision: number;
100
+ }) => any) | undefined;
101
+ onLink?: ((detail: Omit<{
102
+ itemId: string;
103
+ href: string;
104
+ target: "_self" | "_blank";
105
+ preventDefault(): void;
106
+ }, "preventDefault">) => any) | undefined;
107
+ onContextmenu?: ((detail: Omit<{
108
+ id: string | null;
109
+ kind?: import("@draftably/runtime/viewer").ItemKind;
110
+ clientX: number;
111
+ clientY: number;
112
+ preventDefault(): void;
113
+ }, "preventDefault">) => any) | undefined;
114
+ onSelect?: ((detail: {
115
+ ids: readonly string[];
116
+ reason: "user" | "api";
117
+ }) => any) | undefined;
118
+ onChange?: ((detail: {
119
+ source: string;
120
+ }) => any) | undefined;
73
121
  }>, {
122
+ options: ViewerOptions;
74
123
  label: string;
75
124
  state: string | null;
76
125
  outline: "visible" | "hidden";
77
126
  svg: string;
78
- options: ViewerOptions;
79
127
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
80
128
  export default DraftDiagram;
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
- /** `<DraftDiagram>` for Vue 3: the `<draft-diagram>` element with Vue props and an `update` event. */
1
+ /** `<DraftDiagram>` for Vue 3: the `<draft-diagram>` element with Vue props and events. */
2
2
  import '@draftably/runtime/element';
3
- import { defineComponent, h, onBeforeUnmount, onMounted, ref, watchEffect, } from 'vue';
3
+ import { defineComponent, h, onMounted, ref } from 'vue';
4
+ import { hostEmits, listenHostEvents } from './events.js';
5
+ export { renderSvg } from '@draftably/runtime';
6
+ export { HOST_EVENTS } from '@draftably/runtime/host';
4
7
  export const DraftDiagram = defineComponent({
5
8
  name: 'DraftDiagram',
6
9
  props: {
@@ -14,18 +17,13 @@ export const DraftDiagram = defineComponent({
14
17
  outline: { type: String, default: undefined },
15
18
  /** Static SVG from `renderSvg(source, { target: 'inline', idPrefix })`, shown until the viewer draws. */
16
19
  svg: { type: String, default: undefined },
20
+ /** Every `mountViewer` option. A new object with the same values does nothing. */
17
21
  options: { type: Object, default: undefined },
18
22
  },
19
- emits: { update: (_result) => true },
20
- setup(props, { emit, expose }) {
23
+ emits: hostEmits,
24
+ setup(props, { emit, expose, slots }) {
21
25
  const el = ref();
22
- const listen = (event) => emit('update', event.detail);
23
- onMounted(() => el.value?.addEventListener('draft-update', listen));
24
- onBeforeUnmount(() => el.value?.removeEventListener('draft-update', listen));
25
- watchEffect(() => {
26
- if (el.value && props.options)
27
- el.value.options = props.options;
28
- });
26
+ onMounted(() => listenHostEvents(el.value, emit));
29
27
  expose({ element: el });
30
28
  return () => h('draft-diagram', {
31
29
  ref: el,
@@ -33,7 +31,11 @@ export const DraftDiagram = defineComponent({
33
31
  state: props.state ?? undefined,
34
32
  label: props.label,
35
33
  outline: props.outline,
36
- }, props.svg ? [h('div', { innerHTML: props.svg })] : []);
34
+ // Only when set, so options a host set through the ref survive.
35
+ ...(props.options === undefined ? {} : { '.options': props.options }),
36
+ },
37
+ // The default slot holds slot content: children marked `data-draft-slot`.
38
+ [...(props.svg ? [h('div', { innerHTML: props.svg })] : []), ...(slots.default?.() ?? [])]);
37
39
  },
38
40
  });
39
41
  export default DraftDiagram;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@draftably/vue",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "Vue components for Draftably diagrams.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,8 +23,8 @@
23
23
  },
24
24
  "sideEffects": false,
25
25
  "dependencies": {
26
- "@draftably/runtime": "0.3.0",
27
- "@draftably/editor": "0.3.0"
26
+ "@draftably/runtime": "0.4.0",
27
+ "@draftably/editor": "0.4.0"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "vue": "^3.4"