@bimetal/whiteboard-vue-components 0.29.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/LICENSE +129 -0
- package/README.md +58 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/components/CommentThread.d.ts +82 -0
- package/dist/components/CommentThread.d.ts.map +1 -0
- package/dist/components/CommentThread.js +55 -0
- package/dist/components/CommentThread.js.map +1 -0
- package/dist/components/StylePanel.d.ts +39 -0
- package/dist/components/StylePanel.d.ts.map +1 -0
- package/dist/components/StylePanel.js +53 -0
- package/dist/components/StylePanel.js.map +1 -0
- package/dist/components/TextDialog.d.ts +59 -0
- package/dist/components/TextDialog.d.ts.map +1 -0
- package/dist/components/TextDialog.js +45 -0
- package/dist/components/TextDialog.js.map +1 -0
- package/dist/components/TransformHandles.d.ts +39 -0
- package/dist/components/TransformHandles.d.ts.map +1 -0
- package/dist/components/TransformHandles.js +40 -0
- package/dist/components/TransformHandles.js.map +1 -0
- package/dist/components/Whiteboard.d.ts +68 -0
- package/dist/components/Whiteboard.d.ts.map +1 -0
- package/dist/components/Whiteboard.js +356 -0
- package/dist/components/Whiteboard.js.map +1 -0
- package/dist/components/WhiteboardShape.d.ts +49 -0
- package/dist/components/WhiteboardShape.d.ts.map +1 -0
- package/dist/components/WhiteboardShape.js +69 -0
- package/dist/components/WhiteboardShape.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/styles/index.css +1 -0
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { defineComponent, h } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* The style editor for the current selection. The inputs forward RAW string
|
|
4
|
+
* values (`StyleInput`); the controller parses/clamps/validates and batches the
|
|
5
|
+
* change into ONE `SetShapesStyle` (one undo). No `Number(...)`, cast or min/max
|
|
6
|
+
* policy here — the DOM min/max are UX hints only. Labels come from the locale.
|
|
7
|
+
* 1:1 with the React reference.
|
|
8
|
+
*/
|
|
9
|
+
export const StylePanel = defineComponent({
|
|
10
|
+
name: 'StylePanel',
|
|
11
|
+
props: {
|
|
12
|
+
style: { type: Object, required: true },
|
|
13
|
+
locale: { type: Object, required: true },
|
|
14
|
+
onInput: { type: Function, required: true },
|
|
15
|
+
},
|
|
16
|
+
setup(props) {
|
|
17
|
+
const val = (e) => e.target.value;
|
|
18
|
+
return () => {
|
|
19
|
+
const { style, locale, onInput } = props;
|
|
20
|
+
return h('div', { class: 'bm-wb__panel', 'data-testid': 'wb-style-panel' }, [
|
|
21
|
+
h('div', { class: 'bm-wb__field' }, [
|
|
22
|
+
h('label', { for: 'bmw-fill' }, locale.styleFill),
|
|
23
|
+
h('input', { id: 'bmw-fill', type: 'color', 'data-style': 'fill', value: style.fill ?? '#ffffff', onChange: (e) => onInput({ fill: val(e) }) }),
|
|
24
|
+
]),
|
|
25
|
+
h('div', { class: 'bm-wb__field' }, [
|
|
26
|
+
h('label', { for: 'bmw-stroke' }, locale.styleStroke),
|
|
27
|
+
h('input', { id: 'bmw-stroke', type: 'color', 'data-style': 'stroke', value: style.stroke, onChange: (e) => onInput({ stroke: val(e) }) }),
|
|
28
|
+
]),
|
|
29
|
+
h('div', { class: 'bm-wb__field' }, [
|
|
30
|
+
h('label', { for: 'bmw-strokeWidth' }, locale.styleWidth),
|
|
31
|
+
h('input', { id: 'bmw-strokeWidth', type: 'range', min: 1, max: 12, 'data-style': 'strokeWidth', value: style.strokeWidth, onChange: (e) => onInput({ strokeWidth: val(e) }) }),
|
|
32
|
+
]),
|
|
33
|
+
h('div', { class: 'bm-wb__field' }, [
|
|
34
|
+
h('label', { for: 'bmw-dash' }, locale.styleDash),
|
|
35
|
+
h('select', { id: 'bmw-dash', 'data-style': 'dash', value: style.dash, onChange: (e) => onInput({ dash: val(e) }) }, [
|
|
36
|
+
h('option', { value: 'solid' }, locale.dashSolid),
|
|
37
|
+
h('option', { value: 'dashed' }, locale.dashDashed),
|
|
38
|
+
h('option', { value: 'dotted' }, locale.dashDotted),
|
|
39
|
+
]),
|
|
40
|
+
]),
|
|
41
|
+
h('div', { class: 'bm-wb__field' }, [
|
|
42
|
+
h('label', { for: 'bmw-opacity' }, locale.styleOpacity),
|
|
43
|
+
h('input', { id: 'bmw-opacity', type: 'range', min: 0.1, max: 1, step: 0.1, 'data-style': 'opacity', value: style.opacity, onChange: (e) => onInput({ opacity: val(e) }) }),
|
|
44
|
+
]),
|
|
45
|
+
h('div', { class: 'bm-wb__field' }, [
|
|
46
|
+
h('label', { for: 'bmw-fontSize' }, locale.styleFont),
|
|
47
|
+
h('input', { id: 'bmw-fontSize', type: 'number', min: 8, max: 96, 'data-style': 'fontSize', value: style.fontSize, onChange: (e) => onInput({ fontSize: val(e) }) }),
|
|
48
|
+
]),
|
|
49
|
+
]);
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=StylePanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StylePanel.js","sourceRoot":"","sources":["../../src/components/StylePanel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type PropType } from 'vue';
|
|
2
|
+
export interface TextDialogLocale {
|
|
3
|
+
save: string;
|
|
4
|
+
cancel: string;
|
|
5
|
+
delete: string;
|
|
6
|
+
editShape: string;
|
|
7
|
+
titlePlaceholder: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The double-click edit dialog for a shape's text. Mounted with a `key` per shape
|
|
11
|
+
* so the draft resets. Controlled draft via a local `ref`. 1:1 with the React
|
|
12
|
+
* reference.
|
|
13
|
+
*/
|
|
14
|
+
export declare const TextDialog: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
15
|
+
initial: {
|
|
16
|
+
type: StringConstructor;
|
|
17
|
+
required: true;
|
|
18
|
+
};
|
|
19
|
+
locale: {
|
|
20
|
+
type: PropType<TextDialogLocale>;
|
|
21
|
+
required: true;
|
|
22
|
+
};
|
|
23
|
+
onSave: {
|
|
24
|
+
type: PropType<(text: string) => void>;
|
|
25
|
+
required: true;
|
|
26
|
+
};
|
|
27
|
+
onClose: {
|
|
28
|
+
type: PropType<() => void>;
|
|
29
|
+
required: true;
|
|
30
|
+
};
|
|
31
|
+
onDelete: {
|
|
32
|
+
type: PropType<() => void>;
|
|
33
|
+
required: true;
|
|
34
|
+
};
|
|
35
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
36
|
+
[key: string]: any;
|
|
37
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
38
|
+
initial: {
|
|
39
|
+
type: StringConstructor;
|
|
40
|
+
required: true;
|
|
41
|
+
};
|
|
42
|
+
locale: {
|
|
43
|
+
type: PropType<TextDialogLocale>;
|
|
44
|
+
required: true;
|
|
45
|
+
};
|
|
46
|
+
onSave: {
|
|
47
|
+
type: PropType<(text: string) => void>;
|
|
48
|
+
required: true;
|
|
49
|
+
};
|
|
50
|
+
onClose: {
|
|
51
|
+
type: PropType<() => void>;
|
|
52
|
+
required: true;
|
|
53
|
+
};
|
|
54
|
+
onDelete: {
|
|
55
|
+
type: PropType<() => void>;
|
|
56
|
+
required: true;
|
|
57
|
+
};
|
|
58
|
+
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
59
|
+
//# sourceMappingURL=TextDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TextDialog.d.ts","sourceRoot":"","sources":["../../src/components/TextDialog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,QAAQ,EAAK,MAAM,KAAK,CAAC;AAG7D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;;;;cAIO,QAAQ,CAAC,gBAAgB,CAAC;;;;cACxB,QAAQ,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;;;;cAC/B,QAAQ,CAAC,MAAM,IAAI,CAAC;;;;cACnB,QAAQ,CAAC,MAAM,IAAI,CAAC;;;;;;;;;;;cAHxB,QAAQ,CAAC,gBAAgB,CAAC;;;;cACxB,QAAQ,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;;;;cAC/B,QAAQ,CAAC,MAAM,IAAI,CAAC;;;;cACnB,QAAQ,CAAC,MAAM,IAAI,CAAC;;;iGA6BpD,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { defineComponent, ref, h } from 'vue';
|
|
2
|
+
import { useFocusTrap } from '@bimetal/vue';
|
|
3
|
+
/**
|
|
4
|
+
* The double-click edit dialog for a shape's text. Mounted with a `key` per shape
|
|
5
|
+
* so the draft resets. Controlled draft via a local `ref`. 1:1 with the React
|
|
6
|
+
* reference.
|
|
7
|
+
*/
|
|
8
|
+
export const TextDialog = defineComponent({
|
|
9
|
+
name: 'WhiteboardTextDialog',
|
|
10
|
+
props: {
|
|
11
|
+
initial: { type: String, required: true },
|
|
12
|
+
locale: { type: Object, required: true },
|
|
13
|
+
onSave: { type: Function, required: true },
|
|
14
|
+
onClose: { type: Function, required: true },
|
|
15
|
+
onDelete: { type: Function, required: true },
|
|
16
|
+
},
|
|
17
|
+
setup(props) {
|
|
18
|
+
const text = ref(props.initial);
|
|
19
|
+
// v0.29 Tastatur: modal focus lifecycle on the shared primitive (contract §3).
|
|
20
|
+
// Escape is element-scoped (redundant with the board root's handler, idempotent);
|
|
21
|
+
// focus restores to the `.bm-wb` root via the trap's closest()-anchor.
|
|
22
|
+
const dialogRef = ref(null);
|
|
23
|
+
useFocusTrap(dialogRef, { onEscape: () => props.onClose() });
|
|
24
|
+
return () => {
|
|
25
|
+
const { locale, onSave, onClose, onDelete } = props;
|
|
26
|
+
return h('div', { class: 'bm-wb__dialog-backdrop', onPointerdown: () => onClose() }, [
|
|
27
|
+
h('div', { ref: dialogRef, class: 'bm-wb__dialog', role: 'dialog', 'aria-modal': 'true', 'aria-label': locale.editShape, onPointerdown: (e) => e.stopPropagation() }, [
|
|
28
|
+
h('strong', locale.editShape),
|
|
29
|
+
h('textarea', {
|
|
30
|
+
value: text.value,
|
|
31
|
+
placeholder: locale.titlePlaceholder,
|
|
32
|
+
onInput: (e) => { text.value = e.target.value; },
|
|
33
|
+
}),
|
|
34
|
+
h('div', { class: 'bm-wb__dialog-actions' }, [
|
|
35
|
+
h('button', { type: 'button', class: 'bm-wb__btn', onClick: () => onDelete() }, locale.delete),
|
|
36
|
+
h('span', { style: { flex: 1 } }),
|
|
37
|
+
h('button', { type: 'button', class: 'bm-wb__btn', onClick: () => onClose() }, locale.cancel),
|
|
38
|
+
h('button', { type: 'button', class: 'bm-wb__tool bm-wb__tool--active', onClick: () => onSave(text.value) }, locale.save),
|
|
39
|
+
]),
|
|
40
|
+
]),
|
|
41
|
+
]);
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=TextDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TextDialog.js","sourceRoot":"","sources":["../../src/components/TextDialog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type PropType } from 'vue';
|
|
2
|
+
import type { ShapeView, ResizeHandle } from '@bimetal/whiteboard-headless';
|
|
3
|
+
/**
|
|
4
|
+
* The selection overlay for a SINGLE shape: a box at the shape's bounds (in board
|
|
5
|
+
* coords, inside the pan/zoom scene), rotated with the shape, carrying eight
|
|
6
|
+
* resize handles + a rotate knob. Each handle only emits a gesture intent — the
|
|
7
|
+
* controller owns the rotation-aware math. Locked shapes show no handles.
|
|
8
|
+
* 1:1 with the React reference.
|
|
9
|
+
*/
|
|
10
|
+
export declare const TransformHandles: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
11
|
+
view: {
|
|
12
|
+
type: PropType<ShapeView>;
|
|
13
|
+
required: true;
|
|
14
|
+
};
|
|
15
|
+
onResize: {
|
|
16
|
+
type: PropType<(handle: ResizeHandle, e: PointerEvent) => void>;
|
|
17
|
+
required: true;
|
|
18
|
+
};
|
|
19
|
+
onRotate: {
|
|
20
|
+
type: PropType<(e: PointerEvent) => void>;
|
|
21
|
+
required: true;
|
|
22
|
+
};
|
|
23
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
24
|
+
[key: string]: any;
|
|
25
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
26
|
+
view: {
|
|
27
|
+
type: PropType<ShapeView>;
|
|
28
|
+
required: true;
|
|
29
|
+
};
|
|
30
|
+
onResize: {
|
|
31
|
+
type: PropType<(handle: ResizeHandle, e: PointerEvent) => void>;
|
|
32
|
+
required: true;
|
|
33
|
+
};
|
|
34
|
+
onRotate: {
|
|
35
|
+
type: PropType<(e: PointerEvent) => void>;
|
|
36
|
+
required: true;
|
|
37
|
+
};
|
|
38
|
+
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
39
|
+
//# sourceMappingURL=TransformHandles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TransformHandles.d.ts","sourceRoot":"","sources":["../../src/components/TransformHandles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,QAAQ,EAAyB,MAAM,KAAK,CAAC;AAC5E,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAI5E;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB;;cAGD,QAAQ,CAAC,SAAS,CAAC;;;;cACb,QAAQ,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC;;;;cACzD,QAAQ,CAAC,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC;;;;;;;cAFzC,QAAQ,CAAC,SAAS,CAAC;;;;cACb,QAAQ,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC;;;;cACzD,QAAQ,CAAC,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC;;;iGAyBnE,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { defineComponent, h } from 'vue';
|
|
2
|
+
const HANDLES = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];
|
|
3
|
+
/**
|
|
4
|
+
* The selection overlay for a SINGLE shape: a box at the shape's bounds (in board
|
|
5
|
+
* coords, inside the pan/zoom scene), rotated with the shape, carrying eight
|
|
6
|
+
* resize handles + a rotate knob. Each handle only emits a gesture intent — the
|
|
7
|
+
* controller owns the rotation-aware math. Locked shapes show no handles.
|
|
8
|
+
* 1:1 with the React reference.
|
|
9
|
+
*/
|
|
10
|
+
export const TransformHandles = defineComponent({
|
|
11
|
+
name: 'TransformHandles',
|
|
12
|
+
props: {
|
|
13
|
+
view: { type: Object, required: true },
|
|
14
|
+
onResize: { type: Function, required: true },
|
|
15
|
+
onRotate: { type: Function, required: true },
|
|
16
|
+
},
|
|
17
|
+
setup(props) {
|
|
18
|
+
return () => {
|
|
19
|
+
const s = props.view.shape;
|
|
20
|
+
// Visibility (lone/non-group/transformable) is the controller's transformHandleId.
|
|
21
|
+
const style = {
|
|
22
|
+
left: `${s.x}px`,
|
|
23
|
+
top: `${s.y}px`,
|
|
24
|
+
width: `${s.width}px`,
|
|
25
|
+
height: `${s.height}px`,
|
|
26
|
+
transform: s.rotation ? `rotate(${s.rotation}deg)` : undefined,
|
|
27
|
+
};
|
|
28
|
+
return h('div', { class: 'bm-wb__handles', style, 'data-testid': 'wb-handles' }, [
|
|
29
|
+
h('div', { class: 'bm-wb__rotate', 'data-rotate': '', onPointerdown: props.onRotate }),
|
|
30
|
+
...HANDLES.map((handle) => h('div', {
|
|
31
|
+
key: handle,
|
|
32
|
+
class: `bm-wb__handle bm-wb__handle--${handle}`,
|
|
33
|
+
'data-handle': handle,
|
|
34
|
+
onPointerdown: (e) => props.onResize(handle, e),
|
|
35
|
+
})),
|
|
36
|
+
]);
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=TransformHandles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TransformHandles.js","sourceRoot":"","sources":["../../src/components/TransformHandles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAqC,CAAC,EAAE,MAAM,KAAK,CAAC;AAG5E,MAAM,OAAO,GAA4B,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;AAEtF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,eAAe,CAAC;IAC9C,IAAI,EAAE,kBAAkB;IACxB,KAAK,EAAE;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,MAA6B,EAAE,QAAQ,EAAE,IAAI,EAAE;QAC7D,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAqE,EAAE,QAAQ,EAAE,IAAI,EAAE;QACzG,QAAQ,EAAE,EAAE,IAAI,EAAE,QAA+C,EAAE,QAAQ,EAAE,IAAI,EAAE;KACpF;IACD,KAAK,CAAC,KAAK;QACT,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;YAC3B,mFAAmF;YACnF,MAAM,KAAK,GAAkB;gBAC3B,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI;gBAChB,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI;gBACf,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI;gBACrB,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,IAAI;gBACvB,SAAS,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,SAAS;aAC/D,CAAC;YACF,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,EAAE;gBAC/E,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,EAAE,EAAE,aAAa,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACtF,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CACxB,CAAC,CAAC,KAAK,EAAE;oBACP,GAAG,EAAE,MAAM;oBACX,KAAK,EAAE,gCAAgC,MAAM,EAAE;oBAC/C,aAAa,EAAE,MAAM;oBACrB,aAAa,EAAE,CAAC,CAAe,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;iBAC9D,CAAC,CAAC;aACN,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type PropType, type VNode } from 'vue';
|
|
2
|
+
import type { WhiteboardStore } from '@bimetal/whiteboard-data';
|
|
3
|
+
import type { WhiteboardConfigInput } from '@bimetal/whiteboard-headless';
|
|
4
|
+
export interface WhiteboardProps {
|
|
5
|
+
store: WhiteboardStore;
|
|
6
|
+
canvasId: string;
|
|
7
|
+
config?: WhiteboardConfigInput;
|
|
8
|
+
darkMode?: boolean;
|
|
9
|
+
onError?: (err: unknown) => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The Vue whiteboard — a thin binding over `@bimetal/whiteboard-headless`. Owns
|
|
13
|
+
* DOM only: it converts `clientX/Y → boardPoint` through the controller's viewport
|
|
14
|
+
* (`screenToBoard` — the binding's ONE piece of geometry), wires window pointer +
|
|
15
|
+
* wheel events, and renders the snapshot. Every interaction decision (tool FSM,
|
|
16
|
+
* create/drag/marquee, pan/zoom math, input policy) lives in the controller. 1:1
|
|
17
|
+
* with the React reference.
|
|
18
|
+
*/
|
|
19
|
+
export declare const Whiteboard: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
20
|
+
store: {
|
|
21
|
+
type: PropType<WhiteboardStore>;
|
|
22
|
+
required: true;
|
|
23
|
+
};
|
|
24
|
+
canvasId: {
|
|
25
|
+
type: StringConstructor;
|
|
26
|
+
required: true;
|
|
27
|
+
};
|
|
28
|
+
config: {
|
|
29
|
+
type: PropType<WhiteboardConfigInput>;
|
|
30
|
+
default: undefined;
|
|
31
|
+
};
|
|
32
|
+
darkMode: {
|
|
33
|
+
type: BooleanConstructor;
|
|
34
|
+
default: boolean;
|
|
35
|
+
};
|
|
36
|
+
onError: {
|
|
37
|
+
type: PropType<(err: unknown) => void>;
|
|
38
|
+
default: undefined;
|
|
39
|
+
};
|
|
40
|
+
}>, () => VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
41
|
+
[key: string]: any;
|
|
42
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
43
|
+
store: {
|
|
44
|
+
type: PropType<WhiteboardStore>;
|
|
45
|
+
required: true;
|
|
46
|
+
};
|
|
47
|
+
canvasId: {
|
|
48
|
+
type: StringConstructor;
|
|
49
|
+
required: true;
|
|
50
|
+
};
|
|
51
|
+
config: {
|
|
52
|
+
type: PropType<WhiteboardConfigInput>;
|
|
53
|
+
default: undefined;
|
|
54
|
+
};
|
|
55
|
+
darkMode: {
|
|
56
|
+
type: BooleanConstructor;
|
|
57
|
+
default: boolean;
|
|
58
|
+
};
|
|
59
|
+
onError: {
|
|
60
|
+
type: PropType<(err: unknown) => void>;
|
|
61
|
+
default: undefined;
|
|
62
|
+
};
|
|
63
|
+
}>> & Readonly<{}>, {
|
|
64
|
+
onError: (err: unknown) => void;
|
|
65
|
+
config: WhiteboardConfigInput;
|
|
66
|
+
darkMode: boolean;
|
|
67
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
68
|
+
//# sourceMappingURL=Whiteboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Whiteboard.d.ts","sourceRoot":"","sources":["../../src/components/Whiteboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoE,KAAK,QAAQ,EAAsB,KAAK,KAAK,EAAK,MAAM,KAAK,CAAC;AAIzI,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAO1E,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,eAAe,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAClC;AAUD;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU;;cAGM,QAAQ,CAAC,eAAe,CAAC;;;;;;;;cAExB,QAAQ,CAAC,qBAAqB,CAAC;;;;;;;;cAE5B,QAAQ,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;;;;;;;cAJpC,QAAQ,CAAC,eAAe,CAAC;;;;;;;;cAExB,QAAQ,CAAC,qBAAqB,CAAC;;;;;;;;cAE5B,QAAQ,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;;;;mBAAjB,OAAO,KAAK,IAAI;;;4EA6U9D,CAAC"}
|