@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.
Files changed (37) hide show
  1. package/LICENSE +129 -0
  2. package/README.md +58 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/components/CommentThread.d.ts +82 -0
  5. package/dist/components/CommentThread.d.ts.map +1 -0
  6. package/dist/components/CommentThread.js +55 -0
  7. package/dist/components/CommentThread.js.map +1 -0
  8. package/dist/components/StylePanel.d.ts +39 -0
  9. package/dist/components/StylePanel.d.ts.map +1 -0
  10. package/dist/components/StylePanel.js +53 -0
  11. package/dist/components/StylePanel.js.map +1 -0
  12. package/dist/components/TextDialog.d.ts +59 -0
  13. package/dist/components/TextDialog.d.ts.map +1 -0
  14. package/dist/components/TextDialog.js +45 -0
  15. package/dist/components/TextDialog.js.map +1 -0
  16. package/dist/components/TransformHandles.d.ts +39 -0
  17. package/dist/components/TransformHandles.d.ts.map +1 -0
  18. package/dist/components/TransformHandles.js +40 -0
  19. package/dist/components/TransformHandles.js.map +1 -0
  20. package/dist/components/Whiteboard.d.ts +68 -0
  21. package/dist/components/Whiteboard.d.ts.map +1 -0
  22. package/dist/components/Whiteboard.js +356 -0
  23. package/dist/components/Whiteboard.js.map +1 -0
  24. package/dist/components/WhiteboardShape.d.ts +49 -0
  25. package/dist/components/WhiteboardShape.d.ts.map +1 -0
  26. package/dist/components/WhiteboardShape.js +69 -0
  27. package/dist/components/WhiteboardShape.js.map +1 -0
  28. package/dist/index.d.ts +18 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +18 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/styles/index.css +1 -0
  33. package/dist/types.d.ts +15 -0
  34. package/dist/types.d.ts.map +1 -0
  35. package/dist/types.js +2 -0
  36. package/dist/types.js.map +1 -0
  37. 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"}