@unityevolv/ofiskit-ui-builder 0.1.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 (79) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +30 -0
  3. package/dist/BuilderSteps.d.ts +35 -0
  4. package/dist/BuilderSteps.d.ts.map +1 -0
  5. package/dist/BuilderSteps.js +104 -0
  6. package/dist/BuilderSteps.js.map +1 -0
  7. package/dist/OfficeBuilder.d.ts +30 -0
  8. package/dist/OfficeBuilder.d.ts.map +1 -0
  9. package/dist/OfficeBuilder.js +55 -0
  10. package/dist/OfficeBuilder.js.map +1 -0
  11. package/dist/background/BackgroundStep.d.ts +35 -0
  12. package/dist/background/BackgroundStep.d.ts.map +1 -0
  13. package/dist/background/BackgroundStep.js +104 -0
  14. package/dist/background/BackgroundStep.js.map +1 -0
  15. package/dist/background/darkVersion.d.ts +25 -0
  16. package/dist/background/darkVersion.d.ts.map +1 -0
  17. package/dist/background/darkVersion.js +124 -0
  18. package/dist/background/darkVersion.js.map +1 -0
  19. package/dist/canvas/BuilderCanvas.d.ts +32 -0
  20. package/dist/canvas/BuilderCanvas.d.ts.map +1 -0
  21. package/dist/canvas/BuilderCanvas.js +40 -0
  22. package/dist/canvas/BuilderCanvas.js.map +1 -0
  23. package/dist/canvas/RoomShape.d.ts +27 -0
  24. package/dist/canvas/RoomShape.d.ts.map +1 -0
  25. package/dist/canvas/RoomShape.js +45 -0
  26. package/dist/canvas/RoomShape.js.map +1 -0
  27. package/dist/canvas/geometry.d.ts +115 -0
  28. package/dist/canvas/geometry.d.ts.map +1 -0
  29. package/dist/canvas/geometry.js +222 -0
  30. package/dist/canvas/geometry.js.map +1 -0
  31. package/dist/canvas/types.d.ts +47 -0
  32. package/dist/canvas/types.d.ts.map +1 -0
  33. package/dist/canvas/types.js +2 -0
  34. package/dist/canvas/types.js.map +1 -0
  35. package/dist/canvas/useCanvasDrag.d.ts +35 -0
  36. package/dist/canvas/useCanvasDrag.d.ts.map +1 -0
  37. package/dist/canvas/useCanvasDrag.js +138 -0
  38. package/dist/canvas/useCanvasDrag.js.map +1 -0
  39. package/dist/canvas/useCanvasKeys.d.ts +11 -0
  40. package/dist/canvas/useCanvasKeys.d.ts.map +1 -0
  41. package/dist/canvas/useCanvasKeys.js +43 -0
  42. package/dist/canvas/useCanvasKeys.js.map +1 -0
  43. package/dist/history.d.ts +31 -0
  44. package/dist/history.d.ts.map +1 -0
  45. package/dist/history.js +49 -0
  46. package/dist/history.js.map +1 -0
  47. package/dist/index.d.ts +21 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +20 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/panel/AreaInspector.d.ts +10 -0
  52. package/dist/panel/AreaInspector.d.ts.map +1 -0
  53. package/dist/panel/AreaInspector.js +30 -0
  54. package/dist/panel/AreaInspector.js.map +1 -0
  55. package/dist/panel/RoomInspector.d.ts +16 -0
  56. package/dist/panel/RoomInspector.d.ts.map +1 -0
  57. package/dist/panel/RoomInspector.js +26 -0
  58. package/dist/panel/RoomInspector.js.map +1 -0
  59. package/dist/panel/SaveBar.d.ts +7 -0
  60. package/dist/panel/SaveBar.d.ts.map +1 -0
  61. package/dist/panel/SaveBar.js +16 -0
  62. package/dist/panel/SaveBar.js.map +1 -0
  63. package/dist/panel/TemplateDetails.d.ts +16 -0
  64. package/dist/panel/TemplateDetails.d.ts.map +1 -0
  65. package/dist/panel/TemplateDetails.js +16 -0
  66. package/dist/panel/TemplateDetails.js.map +1 -0
  67. package/dist/panel/ToolBar.d.ts +34 -0
  68. package/dist/panel/ToolBar.d.ts.map +1 -0
  69. package/dist/panel/ToolBar.js +8 -0
  70. package/dist/panel/ToolBar.js.map +1 -0
  71. package/dist/prompt/PromptStep.d.ts +23 -0
  72. package/dist/prompt/PromptStep.d.ts.map +1 -0
  73. package/dist/prompt/PromptStep.js +24 -0
  74. package/dist/prompt/PromptStep.js.map +1 -0
  75. package/dist/prompt/prompt.d.ts +59 -0
  76. package/dist/prompt/prompt.d.ts.map +1 -0
  77. package/dist/prompt/prompt.js +40 -0
  78. package/dist/prompt/prompt.js.map +1 -0
  79. package/package.json +23 -0
@@ -0,0 +1,138 @@
1
+ import { usableRect } from '@unityevolv/ofiskit-template';
2
+ import { useState } from 'react';
3
+ import { MIN_DRAWN, addArea, addRoom, areaAt, clamp, moveArea, moveRoom, onResizeCorner, placeArea, resizeRoom, roomAt, snapRoom, } from './geometry.js';
4
+ export function useCanvasDrag(options) {
5
+ const { template, tool, unit, surface, onSelect, onChange, onToolDone } = options;
6
+ const [drag, setDrag] = useState(null);
7
+ const [preview, setPreview] = useState(null);
8
+ const [guides, setGuides] = useState({ x: [], y: [] });
9
+ /** Pointer position as a fraction of the canvas. */
10
+ const pointAt = (event) => {
11
+ const rect = surface.current?.getBoundingClientRect();
12
+ if (!rect)
13
+ return { x: 0, y: 0 };
14
+ return {
15
+ x: clamp((event.clientX - rect.left) / rect.width, 0, 1),
16
+ y: clamp((event.clientY - rect.top) / rect.height, 0, 1),
17
+ };
18
+ };
19
+ const onPointerDown = (event) => {
20
+ if (event.button !== 0)
21
+ return;
22
+ const from = pointAt(event);
23
+ event.currentTarget.setPointerCapture(event.pointerId);
24
+ if (tool === 'room') {
25
+ setDrag({ kind: 'draw-room', from, before: template });
26
+ setPreview({ x: from.x, y: from.y, width: 0, height: 0 });
27
+ return;
28
+ }
29
+ if (tool === 'area') {
30
+ const room = roomAt(template, from);
31
+ if (!room)
32
+ return;
33
+ setDrag({ kind: 'draw-area', roomId: room.id, from, before: template });
34
+ setPreview({ x: from.x, y: from.y, width: 0, height: 0 });
35
+ return;
36
+ }
37
+ // Select: clicking an area selects it, clicking a room selects the room,
38
+ // clicking the background clears the selection.
39
+ const hit = areaAt(template, from);
40
+ if (hit) {
41
+ onSelect({ kind: 'area', roomId: hit.room.id, areaId: hit.area.id });
42
+ setDrag({
43
+ kind: 'move-area',
44
+ roomId: hit.room.id,
45
+ areaId: hit.area.id,
46
+ from,
47
+ before: template,
48
+ grab: { x: from.x - hit.area.x, y: from.y - hit.area.y },
49
+ });
50
+ return;
51
+ }
52
+ const room = roomAt(template, from);
53
+ if (!room) {
54
+ onSelect({ kind: 'none' });
55
+ return;
56
+ }
57
+ onSelect({ kind: 'room', roomId: room.id });
58
+ // The bottom-right corner resizes; anywhere else moves.
59
+ const corner = onResizeCorner(room, from);
60
+ setDrag({
61
+ kind: corner ? 'resize-room' : 'move-room',
62
+ roomId: room.id,
63
+ from,
64
+ before: template,
65
+ ...(corner
66
+ ? { handle: 'se' }
67
+ : { grab: { x: from.x - room.rect.x, y: from.y - room.rect.y } }),
68
+ });
69
+ };
70
+ const onPointerMove = (event) => {
71
+ if (!drag)
72
+ return;
73
+ const at = pointAt(event);
74
+ if (drag.kind === 'draw-room') {
75
+ const [x, gx] = snapRoom(template, Math.min(drag.from.x, at.x), 'x');
76
+ const [y, gy] = snapRoom(template, Math.min(drag.from.y, at.y), 'y');
77
+ const [right] = snapRoom(template, Math.max(drag.from.x, at.x), 'x');
78
+ const [bottom] = snapRoom(template, Math.max(drag.from.y, at.y), 'y');
79
+ setGuides({ x: gx === null ? [] : [gx], y: gy === null ? [] : [gy] });
80
+ setPreview({ x, y, width: Math.max(0, right - x), height: Math.max(0, bottom - y) });
81
+ return;
82
+ }
83
+ if (drag.kind === 'draw-area' && drag.roomId) {
84
+ const room = template.rooms.find((candidate) => candidate.id === drag.roomId);
85
+ if (!room)
86
+ return;
87
+ // Whole units on both axes, always. A fractional area is not refused here;
88
+ // it is impossible to draw. Where it sits is the author's business.
89
+ const columns = Math.max(1, Math.round(Math.abs(at.x - drag.from.x) / unit.width));
90
+ const rows = Math.max(1, Math.round(Math.abs(at.y - drag.from.y) / unit.height));
91
+ const corner = placeArea({ x: Math.min(drag.from.x, at.x), y: Math.min(drag.from.y, at.y) }, { columns, rows }, usableRect(room, template.canvas), unit);
92
+ setPreview({ ...corner, width: columns * unit.width, height: rows * unit.height });
93
+ return;
94
+ }
95
+ if (drag.kind === 'move-room' && drag.grab && drag.roomId) {
96
+ const [x] = snapRoom(template, at.x - drag.grab.x, 'x', drag.roomId);
97
+ const [y] = snapRoom(template, at.y - drag.grab.y, 'y', drag.roomId);
98
+ onChange(moveRoom(template, drag.roomId, { x, y }), { transient: true });
99
+ return;
100
+ }
101
+ if (drag.kind === 'resize-room' && drag.roomId) {
102
+ const [right] = snapRoom(template, at.x, 'x', drag.roomId);
103
+ const [bottom] = snapRoom(template, at.y, 'y', drag.roomId);
104
+ onChange(resizeRoom(template, drag.roomId, { x: right, y: bottom }, unit), {
105
+ transient: true,
106
+ });
107
+ return;
108
+ }
109
+ if (drag.kind === 'move-area' && drag.grab && drag.roomId && drag.areaId) {
110
+ const wanted = { x: at.x - drag.grab.x, y: at.y - drag.grab.y };
111
+ onChange(moveArea(template, drag.roomId, drag.areaId, wanted, unit), { transient: true });
112
+ }
113
+ };
114
+ const onPointerUp = () => {
115
+ if (!drag)
116
+ return;
117
+ if (drag.kind === 'draw-room' && preview) {
118
+ // A click rather than a drag: too small to be a room anybody meant.
119
+ if (preview.width > MIN_DRAWN && preview.height > MIN_DRAWN) {
120
+ onChange(addRoom(template, preview, unit), { before: drag.before });
121
+ }
122
+ onToolDone();
123
+ }
124
+ if (drag.kind === 'draw-area' && preview && drag.roomId) {
125
+ onChange(addArea(template, drag.roomId, preview, unit), { before: drag.before });
126
+ onToolDone();
127
+ }
128
+ if (drag.kind === 'move-room' || drag.kind === 'resize-room' || drag.kind === 'move-area') {
129
+ // One undo step for the whole drag, not one per pointer move.
130
+ onChange(template, { before: drag.before });
131
+ }
132
+ setDrag(null);
133
+ setPreview(null);
134
+ setGuides({ x: [], y: [] });
135
+ };
136
+ return { preview, guides, onPointerDown, onPointerMove, onPointerUp };
137
+ }
138
+ //# sourceMappingURL=useCanvasDrag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCanvasDrag.js","sourceRoot":"","sources":["../../src/canvas/useCanvasDrag.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Template } from '@unityevolv/ofiskit-template';
2
+ import type { KeyboardEvent as ReactKeyboardEvent } from 'react';
3
+ import { type Unit } from './geometry.js';
4
+ import type { OnChange, Selection } from './types.js';
5
+ export declare function useCanvasKeys(options: {
6
+ template: Template;
7
+ selection: Selection;
8
+ unit: Unit;
9
+ onChange: OnChange;
10
+ }): (event: ReactKeyboardEvent) => void;
11
+ //# sourceMappingURL=useCanvasKeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCanvasKeys.d.ts","sourceRoot":"","sources":["../../src/canvas/useCanvasKeys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAC5D,OAAO,KAAK,EAAE,aAAa,IAAI,kBAAkB,EAAE,MAAM,OAAO,CAAA;AAEhE,OAAO,EAA8C,KAAK,IAAI,EAAE,MAAM,eAAe,CAAA;AACrF,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAyBrD,wBAAgB,aAAa,CAAC,OAAO,EAAE;IACrC,QAAQ,EAAE,QAAQ,CAAA;IAClB,SAAS,EAAE,SAAS,CAAA;IACpB,IAAI,EAAE,IAAI,CAAA;IACV,QAAQ,EAAE,QAAQ,CAAA;CACnB,GAAG,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAsBtC"}
@@ -0,0 +1,43 @@
1
+ import { GRID, nudgeArea, nudgeRoom } from './geometry.js';
2
+ /**
3
+ * The keyboard half of the tool.
4
+ *
5
+ * A step of five grid cells, and one cell with shift held down for the last pixel
6
+ * of alignment — the same two speeds every drawing tool has, because the coarse
7
+ * step is what somebody wants ninety times and the fine one is what they want when
8
+ * a room is nearly right. Alt resizes instead of moving.
9
+ *
10
+ * Not a courtesy. Drawing a rectangle is a pointer gesture with no honest keyboard
11
+ * equivalent, but adjusting one is a different matter: an author who can select a
12
+ * room in the panel and then cannot move it has a tool they cannot use.
13
+ *
14
+ * A user area moves the same way under the keyboard as under a pointer — on the
15
+ * grid rather than on the avatar lattice, and never out of the room it belongs to.
16
+ */
17
+ const NUDGES = {
18
+ ArrowLeft: { x: -1, y: 0 },
19
+ ArrowRight: { x: 1, y: 0 },
20
+ ArrowUp: { x: 0, y: -1 },
21
+ ArrowDown: { x: 0, y: 1 },
22
+ };
23
+ export function useCanvasKeys(options) {
24
+ const { template, selection, unit, onChange } = options;
25
+ return (event) => {
26
+ if (selection.kind === 'none')
27
+ return;
28
+ const direction = NUDGES[event.key];
29
+ if (!direction)
30
+ return;
31
+ event.preventDefault();
32
+ const room = template.rooms.find((candidate) => candidate.id === selection.roomId);
33
+ if (!room)
34
+ return;
35
+ const step = event.shiftKey ? GRID : GRID * 5;
36
+ if (selection.kind === 'area') {
37
+ onChange(nudgeArea(template, room.id, selection.areaId, direction, step, unit));
38
+ return;
39
+ }
40
+ onChange(nudgeRoom(template, room.id, direction, step, { resize: event.altKey }));
41
+ };
42
+ }
43
+ //# sourceMappingURL=useCanvasKeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCanvasKeys.js","sourceRoot":"","sources":["../../src/canvas/useCanvasKeys.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAA6B,MAAM,eAAe,CAAA;AAGrF;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,GAA8B;IACxC,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;IAC1B,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;IAC1B,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE;IACxB,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;CAC1B,CAAA;AAED,MAAM,UAAU,aAAa,CAAC,OAK7B;IACC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAA;IAEvD,OAAO,CAAC,KAAyB,EAAE,EAAE;QACnC,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM;YAAE,OAAM;QAErC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QACnC,IAAI,CAAC,SAAS;YAAE,OAAM;QACtB,KAAK,CAAC,cAAc,EAAE,CAAA;QAEtB,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,SAAS,CAAC,MAAM,CAAC,CAAA;QAClF,IAAI,CAAC,IAAI;YAAE,OAAM;QAEjB,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAA;QAE7C,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC9B,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;YAC/E,OAAM;QACR,CAAC;QAED,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IACnF,CAAC,CAAA;AACH,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Undo and redo.
3
+ *
4
+ * Drawing a layout is fiddly and the author will make mistakes; a tool that
5
+ * cannot take one back gets used cautiously, which is exactly the wrong way to
6
+ * use a drawing tool.
7
+ *
8
+ * Whole snapshots rather than a command log. A template is small, the number of
9
+ * edits in a session is in the hundreds, and a command log would mean writing an
10
+ * inverse for every operation and getting one of them subtly wrong.
11
+ */
12
+ export interface History<T> {
13
+ value: T;
14
+ /** Replace the value and push the previous one onto the undo stack. */
15
+ set(next: T): void;
16
+ /**
17
+ * Replace without recording a step.
18
+ *
19
+ * For the middle of a drag: dragging a room across the canvas is one edit, not
20
+ * sixty, and an undo stack full of one-pixel moves is useless.
21
+ */
22
+ replace(next: T): void;
23
+ /** Close the current drag, recording where it started. */
24
+ commit(before: T): void;
25
+ undo(): void;
26
+ redo(): void;
27
+ canUndo: boolean;
28
+ canRedo: boolean;
29
+ }
30
+ export declare function useHistory<T>(initial: T): History<T>;
31
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,OAAO,CAAC,CAAC;IACxB,KAAK,EAAE,CAAC,CAAA;IACR,uEAAuE;IACvE,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IAClB;;;;;OAKG;IACH,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACtB,0DAA0D;IAC1D,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAAA;IACvB,IAAI,IAAI,IAAI,CAAA;IACZ,IAAI,IAAI,IAAI,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAqDpD"}
@@ -0,0 +1,49 @@
1
+ import { useCallback, useState } from 'react';
2
+ export function useHistory(initial) {
3
+ const [past, setPast] = useState([]);
4
+ const [value, setValue] = useState(initial);
5
+ const [future, setFuture] = useState([]);
6
+ const set = useCallback((next) => {
7
+ setPast((stack) => [...stack.slice(-49), value]);
8
+ setValue(next);
9
+ // A new edit after an undo abandons the redo branch, which is what every
10
+ // editor does and what everybody expects.
11
+ setFuture([]);
12
+ }, [value]);
13
+ const replace = useCallback((next) => setValue(next), []);
14
+ const commit = useCallback((before) => {
15
+ setPast((stack) => [...stack.slice(-49), before]);
16
+ setFuture([]);
17
+ }, []);
18
+ const undo = useCallback(() => {
19
+ setPast((stack) => {
20
+ const previous = stack[stack.length - 1];
21
+ if (previous === undefined)
22
+ return stack;
23
+ setFuture((forward) => [value, ...forward]);
24
+ setValue(previous);
25
+ return stack.slice(0, -1);
26
+ });
27
+ }, [value]);
28
+ const redo = useCallback(() => {
29
+ setFuture((stack) => {
30
+ const next = stack[0];
31
+ if (next === undefined)
32
+ return stack;
33
+ setPast((backward) => [...backward, value]);
34
+ setValue(next);
35
+ return stack.slice(1);
36
+ });
37
+ }, [value]);
38
+ return {
39
+ value,
40
+ set,
41
+ replace,
42
+ commit,
43
+ undo,
44
+ redo,
45
+ canUndo: past.length > 0,
46
+ canRedo: future.length > 0,
47
+ };
48
+ }
49
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAgC7C,MAAM,UAAU,UAAU,CAAI,OAAU;IACtC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAM,EAAE,CAAC,CAAA;IACzC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAA;IAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAM,EAAE,CAAC,CAAA;IAE7C,MAAM,GAAG,GAAG,WAAW,CACrB,CAAC,IAAO,EAAE,EAAE;QACV,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAA;QAChD,QAAQ,CAAC,IAAI,CAAC,CAAA;QACd,yEAAyE;QACzE,0CAA0C;QAC1C,SAAS,CAAC,EAAE,CAAC,CAAA;IACf,CAAC,EACD,CAAC,KAAK,CAAC,CACR,CAAA;IAED,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,IAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;IAE5D,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,MAAS,EAAE,EAAE;QACvC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;QACjD,SAAS,CAAC,EAAE,CAAC,CAAA;IACf,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE;QAC5B,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YAChB,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;YACxC,IAAI,QAAQ,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAA;YACxC,SAAS,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,OAAO,CAAC,CAAC,CAAA;YAC3C,QAAQ,CAAC,QAAQ,CAAC,CAAA;YAClB,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAC3B,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE;QAC5B,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;YAClB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;YACrB,IAAI,IAAI,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAA;YACpC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAA;YAC3C,QAAQ,CAAC,IAAI,CAAC,CAAA;YACd,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACvB,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,OAAO;QACL,KAAK;QACL,GAAG;QACH,OAAO;QACP,MAAM;QACN,IAAI;QACJ,IAAI;QACJ,OAAO,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC;QACxB,OAAO,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC;KAC3B,CAAA;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The office builder: draw a layout on a background image and emit a template.
3
+ *
4
+ * Built once and used three ways — as a standalone page in the free app, where
5
+ * it exports template.json for a host to drop into a config folder, and in the
6
+ * two wrapper apps, where it saves a catalog or org template. Same component,
7
+ * three hosts, and it does not know which one it is in.
8
+ *
9
+ * React DOM throughout, so it lives here and never in a package a phone
10
+ * imports. There is no builder on mobile.
11
+ */
12
+ export { OfficeBuilder, type OfficeBuilderProps } from './OfficeBuilder.js';
13
+ export { BuilderCanvas, type BuilderCanvasProps } from './canvas/BuilderCanvas.js';
14
+ export type { ChangeOptions, OnChange, Selection, Tool } from './canvas/types.js';
15
+ export { BuilderSteps, type BuilderStepsProps } from './BuilderSteps.js';
16
+ export { PromptStep, type PromptStepProps } from './prompt/PromptStep.js';
17
+ export { BackgroundStep, backgroundFileName, type BackgroundImages, type BackgroundStepProps, } from './background/BackgroundStep.js';
18
+ export { darkVersion } from './background/darkVersion.js';
19
+ export { useHistory, type History } from './history.js';
20
+ export { applyPreset, defaultSlots, loadPromptDocument, renderPrompt, type PromptDocument, type PromptPreset, type PromptSlot, type SlotValues, } from './prompt/prompt.js';
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAClF,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AACjF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACxE,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACzE,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AACvD,OAAO,EACL,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,oBAAoB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The office builder: draw a layout on a background image and emit a template.
3
+ *
4
+ * Built once and used three ways — as a standalone page in the free app, where
5
+ * it exports template.json for a host to drop into a config folder, and in the
6
+ * two wrapper apps, where it saves a catalog or org template. Same component,
7
+ * three hosts, and it does not know which one it is in.
8
+ *
9
+ * React DOM throughout, so it lives here and never in a package a phone
10
+ * imports. There is no builder on mobile.
11
+ */
12
+ export { OfficeBuilder } from './OfficeBuilder.js';
13
+ export { BuilderCanvas } from './canvas/BuilderCanvas.js';
14
+ export { BuilderSteps } from './BuilderSteps.js';
15
+ export { PromptStep } from './prompt/PromptStep.js';
16
+ export { BackgroundStep, backgroundFileName, } from './background/BackgroundStep.js';
17
+ export { darkVersion } from './background/darkVersion.js';
18
+ export { useHistory } from './history.js';
19
+ export { applyPreset, defaultSlots, loadPromptDocument, renderPrompt, } from './prompt/prompt.js';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,aAAa,EAA2B,MAAM,oBAAoB,CAAA;AAC3E,OAAO,EAAE,aAAa,EAA2B,MAAM,2BAA2B,CAAA;AAElF,OAAO,EAAE,YAAY,EAA0B,MAAM,mBAAmB,CAAA;AACxE,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAA;AACzE,OAAO,EACL,cAAc,EACd,kBAAkB,GAGnB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AACzD,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAA;AACvD,OAAO,EACL,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,YAAY,GAKb,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,10 @@
1
+ import type { Room, Template, UserArea } from '@unityevolv/ofiskit-template';
2
+ import type { Selection } from '../canvas/types.js';
3
+ export declare function AreaInspector(props: {
4
+ template: Template;
5
+ room: Room;
6
+ area: UserArea;
7
+ onChange(template: Template): void;
8
+ onSelect(selection: Selection): void;
9
+ }): import("react").JSX.Element;
10
+ //# sourceMappingURL=AreaInspector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AreaInspector.d.ts","sourceRoot":"","sources":["../../src/panel/AreaInspector.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAG5E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAanD,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,QAAQ,EAAE,QAAQ,CAAA;IAClB,IAAI,EAAE,IAAI,CAAA;IACV,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;CACrC,+BAkDA"}
@@ -0,0 +1,30 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Button, Icon, Input } from '@unityevolv/unitykit';
3
+ import { mapRoom } from '../canvas/geometry.js';
4
+ /**
5
+ * How many people a user area holds.
6
+ *
7
+ * Two numbers, and they are whole ones. A fractional area is not something the
8
+ * author is warned about; it is something they cannot make — emptying the field
9
+ * resolves to one cell rather than to nothing, because a half-typed number should
10
+ * not make the layout invalid while somebody is still typing it.
11
+ */
12
+ const LIMIT = 12;
13
+ export function AreaInspector(props) {
14
+ const { template, room, area } = props;
15
+ const setCells = (axis, value) => {
16
+ const next = Math.max(1, Math.min(LIMIT, Number(value) || 1));
17
+ props.onChange(mapRoom(template, room.id, (one) => ({
18
+ ...one,
19
+ areas: one.areas.map((candidate) => candidate.id === area.id ? { ...candidate, [axis]: next } : candidate),
20
+ })));
21
+ };
22
+ return (_jsxs("div", { className: "space-y-2", children: [_jsxs("h3", { className: "text-sm font-semibold", children: ["User area in ", room.name] }), _jsx("div", { className: "flex gap-2", children: ['columns', 'rows'].map((axis) => (_jsx(Input, { label: axis === 'columns' ? 'Across' : 'Down', type: "number", min: 1, max: LIMIT, value: area[axis], onChange: (event) => setCells(axis, event.target.value) }, axis))) }), _jsxs(Button, { size: "sm", variant: "ghost", onClick: () => {
23
+ props.onChange(mapRoom(template, room.id, (one) => ({
24
+ ...one,
25
+ areas: one.areas.filter((candidate) => candidate.id !== area.id),
26
+ })));
27
+ props.onSelect({ kind: 'room', roomId: room.id });
28
+ }, children: [_jsx(Icon, { name: "trash", size: "sm" }), " Delete area"] })] }));
29
+ }
30
+ //# sourceMappingURL=AreaInspector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AreaInspector.js","sourceRoot":"","sources":["../../src/panel/AreaInspector.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAG1D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAG/C;;;;;;;GAOG;AAEH,MAAM,KAAK,GAAG,EAAE,CAAA;AAEhB,MAAM,UAAU,aAAa,CAAC,KAM7B;IACC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;IAEtC,MAAM,QAAQ,GAAG,CAAC,IAAwB,EAAE,KAAa,EAAE,EAAE;QAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC7D,KAAK,CAAC,QAAQ,CACZ,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACnC,GAAG,GAAG;YACN,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CACjC,SAAS,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CACtE;SACF,CAAC,CAAC,CACJ,CAAA;IACH,CAAC,CAAA;IAED,OAAO,CACL,eAAK,SAAS,EAAC,WAAW,aACxB,cAAI,SAAS,EAAC,uBAAuB,8BAAe,IAAI,CAAC,IAAI,IAAM,EAEnE,cAAK,SAAS,EAAC,YAAY,YACvB,CAAC,SAAS,EAAE,MAAM,CAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAC5C,KAAC,KAAK,IAEJ,KAAK,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAC7C,IAAI,EAAC,QAAQ,EACb,GAAG,EAAE,CAAC,EACN,GAAG,EAAE,KAAK,EACV,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,EACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IANlD,IAAI,CAOT,CACH,CAAC,GACE,EAEN,MAAC,MAAM,IACL,IAAI,EAAC,IAAI,EACT,OAAO,EAAC,OAAO,EACf,OAAO,EAAE,GAAG,EAAE;oBACZ,KAAK,CAAC,QAAQ,CACZ,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;wBACnC,GAAG,GAAG;wBACN,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;qBACjE,CAAC,CAAC,CACJ,CAAA;oBACD,KAAK,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;gBACnD,CAAC,aAED,KAAC,IAAI,IAAC,IAAI,EAAC,OAAO,EAAC,IAAI,EAAC,IAAI,GAAG,oBACxB,IACL,CACP,CAAA;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { type Room, type Template } from '@unityevolv/ofiskit-template';
2
+ import type { Selection } from '../canvas/types.js';
3
+ /**
4
+ * The selected room's own settings.
5
+ *
6
+ * Its name, what kind of room it is, which edge its control bar sits on, and the
7
+ * user areas in it. Nothing about geometry: a room is moved and resized on the
8
+ * canvas, where the author can see what they are doing to it.
9
+ */
10
+ export declare function RoomInspector(props: {
11
+ template: Template;
12
+ room: Room;
13
+ onChange(template: Template): void;
14
+ onSelect(selection: Selection): void;
15
+ }): import("react").JSX.Element;
16
+ //# sourceMappingURL=RoomInspector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoomInspector.d.ts","sourceRoot":"","sources":["../../src/panel/RoomInspector.tsx"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAGnF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAEnD;;;;;;GAMG;AAEH,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,QAAQ,EAAE,QAAQ,CAAA;IAClB,IAAI,EAAE,IAAI,CAAA;IACV,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;CACrC,+BA4EA"}
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, Icon, Input, Select } from '@unityevolv/unitykit';
3
+ import { isRequired } from '@unityevolv/ofiskit-template';
4
+ import { mapRoom } from '../canvas/geometry.js';
5
+ /**
6
+ * The selected room's own settings.
7
+ *
8
+ * Its name, what kind of room it is, which edge its control bar sits on, and the
9
+ * user areas in it. Nothing about geometry: a room is moved and resized on the
10
+ * canvas, where the author can see what they are doing to it.
11
+ */
12
+ export function RoomInspector(props) {
13
+ const { template, room } = props;
14
+ const edit = (change) => props.onChange(mapRoom(template, room.id, change));
15
+ return (_jsxs("div", { className: "space-y-2", children: [_jsx("h3", { className: "text-sm font-semibold", children: room.name }), _jsx(Input, { label: "Name", value: room.name, onChange: (event) => edit((one) => ({ ...one, name: event.target.value })) }), _jsxs(Select, { label: "Type", value: room.type,
16
+ // Reception and the break room are structural: there is exactly one of
17
+ // each, so their type is not a choice.
18
+ disabled: isRequired(room.type), onChange: (event) => edit((one) => ({ ...one, type: event.target.value })), children: [_jsx("option", { value: "workspace", children: "Workspace" }), _jsx("option", { value: "meeting", children: "Meeting" }), isRequired(room.type) && _jsx("option", { value: room.type, children: room.type })] }), _jsxs(Select, { label: "Control bar", help: "Put it on whichever edge is clearer in your picture.", value: room.bar, onChange: (event) => edit((one) => ({ ...one, bar: event.target.value })), children: [_jsx("option", { value: "top", children: "Top" }), _jsx("option", { value: "bottom", children: "Bottom" })] }), _jsxs("div", { children: [_jsx("p", { className: "text-xs font-medium text-base-content/70", children: "User areas" }), _jsx("ul", { className: "mt-1 space-y-1", children: room.areas.map((one) => (_jsx("li", { children: _jsxs("button", { type: "button", onClick: () => props.onSelect({ kind: 'area', roomId: room.id, areaId: one.id }), className: "w-full rounded px-2 py-1 text-left text-xs hover:bg-base-200", children: [one.columns, "x", one.rows, " cells"] }) }, one.id))) })] }), !isRequired(room.type) && (_jsxs(Button, { size: "sm", variant: "ghost", onClick: () => {
19
+ props.onChange({
20
+ ...template,
21
+ rooms: template.rooms.filter((one) => one.id !== room.id),
22
+ });
23
+ props.onSelect({ kind: 'none' });
24
+ }, children: [_jsx(Icon, { name: "trash", size: "sm" }), " Delete room"] }))] }));
25
+ }
26
+ //# sourceMappingURL=RoomInspector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoomInspector.js","sourceRoot":"","sources":["../../src/panel/RoomInspector.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { TemplateIssue } from '@unityevolv/ofiskit-template';
2
+ export declare function SaveBar(props: {
3
+ issues: TemplateIssue[];
4
+ saveLabel: string;
5
+ onSave(): void;
6
+ }): import("react").JSX.Element;
7
+ //# sourceMappingURL=SaveBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SaveBar.d.ts","sourceRoot":"","sources":["../../src/panel/SaveBar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAajE,wBAAgB,OAAO,CAAC,KAAK,EAAE;IAC7B,MAAM,EAAE,aAAa,EAAE,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,IAAI,IAAI,CAAA;CACf,+BAwBA"}
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Alert, Button, Icon } from '@unityevolv/unitykit';
3
+ /**
4
+ * Whether the layout is valid, and the one button that ends the job.
5
+ *
6
+ * Live, with the reasons visible: an author finds out while they are causing a
7
+ * problem rather than when they try to save. Saving is refused while anything is
8
+ * wrong, because the template is going somewhere that will have to render it.
9
+ */
10
+ /** Enough to show what kind of trouble it is in without filling the panel. */
11
+ const SHOWN = 6;
12
+ export function SaveBar(props) {
13
+ const { issues } = props;
14
+ return (_jsxs("section", { className: "border-t border-base-300 pt-3", children: [issues.length === 0 ? (_jsxs("p", { className: "flex items-center gap-1 text-sm text-success", children: [_jsx(Icon, { name: "check", size: "sm" }), " This layout is valid."] })) : (_jsx(Alert, { variant: "warn", title: `${issues.length} to fix`, children: _jsx("ul", { className: "mt-1 space-y-1 text-xs", children: issues.slice(0, SHOWN).map((issue, index) => (_jsx("li", { children: issue.message }, `${issue.code}-${index}`))) }) })), _jsxs(Button, { className: "mt-3 w-full", disabled: issues.length > 0, onClick: props.onSave, children: [_jsx(Icon, { name: "download", size: "sm" }), " ", props.saveLabel] })] }));
15
+ }
16
+ //# sourceMappingURL=SaveBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SaveBar.js","sourceRoot":"","sources":["../../src/panel/SaveBar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAG1D;;;;;;GAMG;AAEH,8EAA8E;AAC9E,MAAM,KAAK,GAAG,CAAC,CAAA;AAEf,MAAM,UAAU,OAAO,CAAC,KAIvB;IACC,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;IAExB,OAAO,CACL,mBAAS,SAAS,EAAC,+BAA+B,aAC/C,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACrB,aAAG,SAAS,EAAC,8CAA8C,aACzD,KAAC,IAAI,IAAC,IAAI,EAAC,OAAO,EAAC,IAAI,EAAC,IAAI,GAAG,8BAC7B,CACL,CAAC,CAAC,CAAC,CACF,KAAC,KAAK,IAAC,OAAO,EAAC,MAAM,EAAC,KAAK,EAAE,GAAG,MAAM,CAAC,MAAM,SAAS,YACpD,aAAI,SAAS,EAAC,wBAAwB,YACnC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAC5C,uBAAoC,KAAK,CAAC,OAAO,IAAxC,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,EAAE,CAAsB,CACxD,CAAC,GACC,GACC,CACT,EAED,MAAC,MAAM,IAAC,SAAS,EAAC,aAAa,EAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,aAChF,KAAC,IAAI,IAAC,IAAI,EAAC,UAAU,EAAC,IAAI,EAAC,IAAI,GAAG,OAAE,KAAK,CAAC,SAAS,IAC5C,IACD,CACX,CAAA;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { type Template } from '@unityevolv/ofiskit-template';
2
+ import type { Selection } from '../canvas/types.js';
3
+ /**
4
+ * The whole template, shown when nothing in particular is selected.
5
+ *
6
+ * Its name and description, and every room as a button. That list is how a room is
7
+ * selected without a pointer, which is the difference between a tool somebody can
8
+ * use from the keyboard and one where the canvas is the only way in — and it is
9
+ * faster anyway than hunting for a small room in a busy picture.
10
+ */
11
+ export declare function TemplateDetails(props: {
12
+ template: Template;
13
+ onChange(template: Template): void;
14
+ onSelect(selection: Selection): void;
15
+ }): import("react").JSX.Element;
16
+ //# sourceMappingURL=TemplateDetails.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateDetails.d.ts","sourceRoot":"","sources":["../../src/panel/TemplateDetails.tsx"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAEvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAEnD;;;;;;;GAOG;AAEH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,QAAQ,EAAE,QAAQ,CAAA;IAClB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;CACrC,+BAsCA"}
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Input, Textarea } from '@unityevolv/unitykit';
3
+ import { MAX_ROOMS } from '@unityevolv/ofiskit-template';
4
+ /**
5
+ * The whole template, shown when nothing in particular is selected.
6
+ *
7
+ * Its name and description, and every room as a button. That list is how a room is
8
+ * selected without a pointer, which is the difference between a tool somebody can
9
+ * use from the keyboard and one where the canvas is the only way in — and it is
10
+ * faster anyway than hunting for a small room in a busy picture.
11
+ */
12
+ export function TemplateDetails(props) {
13
+ const { template } = props;
14
+ return (_jsxs("div", { className: "space-y-2", children: [_jsx(Input, { label: "Template name", value: template.name, onChange: (event) => props.onChange({ ...template, name: event.target.value }) }), _jsx(Textarea, { label: "Description", rows: 2, value: template.description ?? '', onChange: (event) => props.onChange({ ...template, description: event.target.value }) }), _jsxs("p", { className: "text-xs text-base-content/70", children: [template.rooms.length, " of ", MAX_ROOMS, " rooms."] }), _jsx("ul", { className: "space-y-1", "aria-label": "Rooms", children: template.rooms.map((one) => (_jsx("li", { children: _jsxs("button", { type: "button", onClick: () => props.onSelect({ kind: 'room', roomId: one.id }), className: "w-full rounded px-2 py-1 text-left text-xs hover:bg-base-200", children: [one.name, _jsx("span", { className: "ml-1 text-base-content/60", children: one.type })] }) }, one.id))) })] }));
15
+ }
16
+ //# sourceMappingURL=TemplateDetails.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateDetails.js","sourceRoot":"","sources":["../../src/panel/TemplateDetails.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,SAAS,EAAiB,MAAM,8BAA8B,CAAA;AAIvE;;;;;;;GAOG;AAEH,MAAM,UAAU,eAAe,CAAC,KAI/B;IACC,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAA;IAE1B,OAAO,CACL,eAAK,SAAS,EAAC,WAAW,aACxB,KAAC,KAAK,IACJ,KAAK,EAAC,eAAe,EACrB,KAAK,EAAE,QAAQ,CAAC,IAAI,EACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,GAAG,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GAC9E,EAEF,KAAC,QAAQ,IACP,KAAK,EAAC,aAAa,EACnB,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,QAAQ,CAAC,WAAW,IAAI,EAAE,EACjC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,GAAG,QAAQ,EAAE,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,GACrF,EAEF,aAAG,SAAS,EAAC,8BAA8B,aACxC,QAAQ,CAAC,KAAK,CAAC,MAAM,UAAM,SAAS,eACnC,EAEJ,aAAI,SAAS,EAAC,WAAW,gBAAY,OAAO,YACzC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAC3B,uBACE,kBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,EAC/D,SAAS,EAAC,8DAA8D,aAEvE,GAAG,CAAC,IAAI,EACT,eAAM,SAAS,EAAC,2BAA2B,YAAE,GAAG,CAAC,IAAI,GAAQ,IACtD,IARF,GAAG,CAAC,EAAE,CASV,CACN,CAAC,GACC,IACD,CACP,CAAA;AACH,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { type AvatarSize, type Template } from '@unityevolv/ofiskit-template';
2
+ import type { Selection, Tool } from '../canvas/types.js';
3
+ /**
4
+ * What the author reaches for constantly: the two drawing tools, undo, and the
5
+ * settings that apply to the whole template.
6
+ *
7
+ * Always visible and never behind a menu. Drawing a layout is a loop of draw, look,
8
+ * adjust, and a menu in the middle of that loop is felt on every iteration.
9
+ */
10
+ export interface UnfittedArea {
11
+ roomId: string;
12
+ roomName: string;
13
+ areaId: string;
14
+ }
15
+ export declare function ToolBar(props: {
16
+ template: Template;
17
+ tool: Tool;
18
+ onTool(tool: Tool): void;
19
+ onUndo(): void;
20
+ onRedo(): void;
21
+ canUndo: boolean;
22
+ canRedo: boolean;
23
+ onAvatarSize(size: AvatarSize): void;
24
+ /** Areas that no longer fit after an avatar size change, named so they can be found. */
25
+ unfitted: UnfittedArea[];
26
+ onSelect(selection: Selection): void;
27
+ showGhosts: boolean;
28
+ onShowGhosts(next: boolean): void;
29
+ /** Only offered when the host supplied a dark image to preview. */
30
+ showDark?: boolean;
31
+ onShowDark?(next: boolean): void;
32
+ onPickImage?(which: 'light' | 'dark'): void;
33
+ }): import("react").JSX.Element;
34
+ //# sourceMappingURL=ToolBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolBar.d.ts","sourceRoot":"","sources":["../../src/panel/ToolBar.tsx"],"names":[],"mappings":"AACA,OAAO,EAA2B,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAEtG,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAEzD;;;;;;GAMG;AAEH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE;IAC7B,QAAQ,EAAE,QAAQ,CAAA;IAClB,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;IACxB,MAAM,IAAI,IAAI,CAAA;IACd,MAAM,IAAI,IAAI,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;IACpC,wFAAwF;IACxF,QAAQ,EAAE,YAAY,EAAE,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;IACpC,UAAU,EAAE,OAAO,CAAA;IACnB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACjC,mEAAmE;IACnE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,CAAC,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IAChC,WAAW,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAAA;CAC5C,+BA2FA"}
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Alert, Button, Icon, Select, Toggle } from '@unityevolv/unitykit';
3
+ import { AVATAR_SIZES, MAX_ROOMS } from '@unityevolv/ofiskit-template';
4
+ export function ToolBar(props) {
5
+ const { template, tool } = props;
6
+ return (_jsxs("section", { className: "space-y-2", children: [_jsxs("div", { className: "flex flex-wrap gap-1", children: [_jsxs(Button, { size: "sm", variant: tool === 'room' ? 'primary' : 'ghost', onClick: () => props.onTool(tool === 'room' ? 'select' : 'room'), disabled: template.rooms.length >= MAX_ROOMS, children: [_jsx(Icon, { name: "plus", size: "sm" }), " Room"] }), _jsxs(Button, { size: "sm", variant: tool === 'area' ? 'primary' : 'ghost', onClick: () => props.onTool(tool === 'area' ? 'select' : 'area'), children: [_jsx(Icon, { name: "plus", size: "sm" }), " User area"] }), _jsx(Button, { size: "sm", variant: "ghost", onClick: props.onUndo, disabled: !props.canUndo, children: "Undo" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: props.onRedo, disabled: !props.canRedo, children: "Redo" })] }), _jsx(Select, { label: "Avatar size", help: "Sets the cell size for the whole template.", value: template.avatarSize, onChange: (event) => props.onAvatarSize(event.target.value), children: AVATAR_SIZES.map((size) => (_jsx("option", { value: size, children: size }, size))) }), props.unfitted.length > 0 && (_jsx(Alert, { variant: "warn", title: "Some user areas no longer fit", children: _jsx("ul", { className: "mt-1 space-y-1 text-xs", children: props.unfitted.map((entry) => (_jsx("li", { children: _jsx("button", { type: "button", className: "underline", onClick: () => props.onSelect({ kind: 'area', roomId: entry.roomId, areaId: entry.areaId }), children: entry.roomName }) }, entry.areaId))) }) })), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Toggle, { checked: props.showGhosts, onChange: (event) => props.onShowGhosts(event.target.checked), label: "Show ghost avatars" }), props.onShowDark && (_jsx(Toggle, { checked: props.showDark ?? false, onChange: (event) => props.onShowDark?.(event.target.checked), label: "Preview the dark image" }))] }), props.onPickImage && (_jsxs("div", { className: "flex gap-1", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: () => props.onPickImage?.('light'), children: "Replace image" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => props.onPickImage?.('dark'), children: "Dark version" })] }))] }));
7
+ }
8
+ //# sourceMappingURL=ToolBar.js.map