@osamash/floor-planner 1.2.2 → 1.2.4

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 (74) hide show
  1. package/dist/floor-planner.css +1 -1
  2. package/dist/floor-planner.es.js +43937 -37765
  3. package/dist/floor-planner.umd.js +59 -49
  4. package/dist/types/index.d.ts +3 -1
  5. package/dist/types/react-planner/ReactPlanner.d.ts +3 -1
  6. package/dist/types/react-planner/ai-chat/AIChatBubble.d.ts +6 -0
  7. package/dist/types/react-planner/ai-chat/AIChatPanel.d.ts +8 -0
  8. package/dist/types/react-planner/ai-chat/SelectionChips.d.ts +2 -0
  9. package/dist/types/react-planner/ai-chat/ThinkingIndicator.d.ts +5 -0
  10. package/dist/types/react-planner/ai-chat/aiService.d.ts +327 -0
  11. package/dist/types/react-planner/ai-chat/imageUpload.d.ts +6 -0
  12. package/dist/types/react-planner/ai-chat/plannerActions.d.ts +3 -0
  13. package/dist/types/react-planner/ai-chat/streamingClient.d.ts +32 -0
  14. package/dist/types/react-planner/ai-chat/useTypewriter.d.ts +19 -0
  15. package/dist/types/react-planner/catalog/catalog.d.ts +4 -0
  16. package/dist/types/react-planner/catalog/factories/AreaFactory.d.ts +1 -24
  17. package/dist/types/react-planner/catalog/factories/WallFactory.d.ts +1 -26
  18. package/dist/types/react-planner/catalog/factories/area-factory-3d.d.ts +2 -2
  19. package/dist/types/react-planner/catalog/factories/area-patterns.d.ts +42 -0
  20. package/dist/types/react-planner/catalog/factories/room-types.d.ts +22 -0
  21. package/dist/types/react-planner/catalog/factories/wall-factory-3d.d.ts +1 -1
  22. package/dist/types/react-planner/class/area.d.ts +23 -0
  23. package/dist/types/react-planner/class/hole.d.ts +13 -0
  24. package/dist/types/react-planner/class/index.d.ts +3 -1
  25. package/dist/types/react-planner/class/item.d.ts +22 -0
  26. package/dist/types/react-planner/class/line.d.ts +12 -3
  27. package/dist/types/react-planner/class/room.d.ts +18 -0
  28. package/dist/types/react-planner/components/ErrorBoundary.d.ts +19 -0
  29. package/dist/types/react-planner/components/SearchInput.d.ts +2 -1
  30. package/dist/types/react-planner/constants.d.ts +3 -0
  31. package/dist/types/react-planner/footer-bar/Footerbar.d.ts +1 -1
  32. package/dist/types/react-planner/models.d.ts +7 -0
  33. package/dist/types/react-planner/plugins/autosave.d.ts +1 -1
  34. package/dist/types/react-planner/plugins/keyboard.d.ts +1 -1
  35. package/dist/types/react-planner/sidebar/Panel.d.ts +2 -1
  36. package/dist/types/react-planner/sidebar/panel-element-editor/AreaAttributesEditor.d.ts +8 -0
  37. package/dist/types/react-planner/sidebar/panel-element-editor/AttributesEditor.d.ts +4 -1
  38. package/dist/types/react-planner/sidebar/panel-element-editor/HoleAttributesEditor.d.ts +3 -4
  39. package/dist/types/react-planner/sidebar/panel-element-editor/ItemAttributesEditor.d.ts +3 -4
  40. package/dist/types/react-planner/sidebar/panel-element-editor/SimilarElements.d.ts +15 -0
  41. package/dist/types/react-planner/sidebar/panel-element-editor/WallAttributesEditor.d.ts +8 -0
  42. package/dist/types/react-planner/sidebar/panel-element-editor/editor-ui.d.ts +42 -0
  43. package/dist/types/react-planner/toolbar/CatalogPicker.d.ts +8 -0
  44. package/dist/types/react-planner/toolbar/NumberStepper.d.ts +11 -0
  45. package/dist/types/react-planner/toolbar/ProjectMiniMap.d.ts +11 -0
  46. package/dist/types/react-planner/toolbar/ProjectPanel.d.ts +2 -0
  47. package/dist/types/react-planner/toolbar/ToolbarRail.d.ts +15 -0
  48. package/dist/types/react-planner/toolbar/ToolbarSubPanel.d.ts +23 -0
  49. package/dist/types/react-planner/toolbar/ZoomControls.d.ts +5 -0
  50. package/dist/types/react-planner/utils/angle.d.ts +9 -0
  51. package/dist/types/react-planner/utils/geometry.d.ts +15 -0
  52. package/dist/types/react-planner/utils/image-trim.d.ts +25 -0
  53. package/dist/types/react-planner/utils/item-footprint.d.ts +23 -0
  54. package/dist/types/react-planner/utils/item-snap.d.ts +56 -0
  55. package/dist/types/react-planner/utils/item-transform.d.ts +9 -0
  56. package/dist/types/react-planner/utils/name-generator.d.ts +1 -1
  57. package/dist/types/react-planner/utils/three-cache.d.ts +17 -0
  58. package/dist/types/react-planner/utils/three-materials.d.ts +33 -0
  59. package/dist/types/react-planner/utils/threeCSG.es6.d.ts +1 -1
  60. package/dist/types/react-planner/utils/wall-miter.d.ts +53 -0
  61. package/dist/types/react-planner/utils/zoom.d.ts +2 -2
  62. package/dist/types/react-planner/viewer2d/Grids.d.ts +1 -1
  63. package/dist/types/react-planner/viewer2d/Ruler.d.ts +6 -1
  64. package/dist/types/react-planner/viewer2d/SelectionToolbar.d.ts +12 -0
  65. package/dist/types/react-planner/viewer2d/WallHoverHandles.d.ts +13 -0
  66. package/dist/types/react-planner/viewer3d/selection-gizmo.d.ts +57 -0
  67. package/dist/types/react-planner/viewer3d/viewer3d.d.ts +61 -0
  68. package/dist/types/shared-style.d.ts +6 -0
  69. package/dist/types/store/ReactPlannerStore.d.ts +102 -1
  70. package/package.json +1 -1
  71. package/dist/types/react-planner/components/PropertyString.d.ts +0 -10
  72. package/dist/types/react-planner/toolbar/Popup.d.ts +0 -11
  73. package/dist/types/react-planner/viewer2d/GridHorizontalStreak.d.ts +0 -7
  74. package/dist/types/react-planner/viewer2d/GridVerticalStreak.d.ts +0 -7
@@ -7,8 +7,9 @@ import Vertex from "./vertex";
7
7
  import Area from "./area";
8
8
  import Item from "./item";
9
9
  import Surface from "./surface";
10
+ import Room from "./room";
10
11
  import { HorizontalGuide, VerticalGuide } from "./guide";
11
- export { Project, Group, Layer, Line, Hole, Vertex, Area, Item, HorizontalGuide, VerticalGuide, Surface, };
12
+ export { Project, Group, Layer, Line, Hole, Vertex, Area, Item, HorizontalGuide, VerticalGuide, Surface, Room, };
12
13
  declare const _default: {
13
14
  Project: typeof Project;
14
15
  Group: typeof Group;
@@ -19,6 +20,7 @@ declare const _default: {
19
20
  Area: typeof Area;
20
21
  Item: typeof Item;
21
22
  Surface: typeof Surface;
23
+ Room: typeof Room;
22
24
  HorizontalGuide: typeof HorizontalGuide;
23
25
  VerticalGuide: typeof VerticalGuide;
24
26
  };
@@ -39,6 +39,28 @@ declare class Item {
39
39
  static endRotatingItem(state: any, x: any, y: any): {
40
40
  updatedState: any;
41
41
  };
42
+ static beginResizingItem(state: any, layerID: any, itemID: any, x: number, y: number): {
43
+ updatedState: any;
44
+ };
45
+ static updateResizingItem(state: any, x: number, y: number): {
46
+ updatedState: any;
47
+ };
48
+ static endResizingItem(state: any, x: number, y: number): {
49
+ updatedState: any;
50
+ };
51
+ static rotate(state: any, layerID: any, itemID: any, delta: number): {
52
+ updatedState: any;
53
+ };
54
+ static flip(state: any, layerID: any, itemID: any, axis: "x" | "y"): {
55
+ updatedState: any;
56
+ };
57
+ static duplicate(state: any, layerID: any, itemID: any): {
58
+ updatedState: any;
59
+ item?: undefined;
60
+ } | {
61
+ updatedState: any;
62
+ item: any;
63
+ };
42
64
  static setProperties(state: any, layerID: any, itemID: any, properties: any): {
43
65
  updatedState: any;
44
66
  };
@@ -33,9 +33,18 @@ declare class Line {
33
33
  line: any;
34
34
  vertex: any;
35
35
  };
36
- static selectToolDrawingLine(state: any, sceneComponentType: string): {
37
- updatedState: any;
38
- };
36
+ static selectToolDrawingLine(state: any, sceneComponentType: string, options?: {
37
+ thickness?: number;
38
+ height?: number;
39
+ }): {
40
+ updatedState: any;
41
+ };
42
+ /** Thickness/height the toolbar's steppers are currently set to, kept on
43
+ * `drawingSupport` for as long as the tool is active (same place
44
+ * `Room.selectToolDrawingRoom` keeps them). Returns undefined when the tool
45
+ * was selected without them — e.g. picking a line element straight out of
46
+ * the catalog — so the catalog element's own defaults apply. */
47
+ static drawingProperties(drawingSupport: any): any;
39
48
  static beginDrawingLine(state: any, layerID: string, x: number, y: number): {
40
49
  updatedState: any;
41
50
  };
@@ -0,0 +1,18 @@
1
+ declare class Room {
2
+ static selectToolDrawingRoom(state: any, options?: {
3
+ thickness?: number;
4
+ height?: number;
5
+ }): {
6
+ updatedState: any;
7
+ };
8
+ static beginDrawingRoom(state: any, layerID: string, x: number, y: number): {
9
+ updatedState: any;
10
+ };
11
+ static updateDrawingRoom(state: any, x: number, y: number): {
12
+ updatedState: any;
13
+ };
14
+ static endDrawingRoom(state: any, x: number, y: number): {
15
+ updatedState: any;
16
+ };
17
+ }
18
+ export default Room;
@@ -0,0 +1,19 @@
1
+ import { Component, type ReactNode } from "react";
2
+ interface ErrorBoundaryProps {
3
+ children: ReactNode;
4
+ onReset?: () => void;
5
+ }
6
+ interface ErrorBoundaryState {
7
+ error: Error | null;
8
+ }
9
+ export declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
10
+ state: ErrorBoundaryState;
11
+ static getDerivedStateFromError(error: Error): {
12
+ error: Error;
13
+ };
14
+ componentDidCatch(error: Error, info: {
15
+ componentStack?: string | null;
16
+ }): void;
17
+ render(): string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
18
+ }
19
+ export default ErrorBoundary;
@@ -6,8 +6,9 @@ interface SearchFieldInterface {
6
6
  onClick?: () => false;
7
7
  isStatic?: boolean;
8
8
  className?: string;
9
+ inputClassName?: string;
9
10
  hasDropDown?: boolean;
10
11
  onSearch: (term: string, event: React.ChangeEvent<HTMLInputElement>) => void;
11
12
  }
12
- declare const SearchInput: ({ term, placeholder, noSpacing, onClick, isStatic, hasDropDown, onSearch, className, value, }: SearchFieldInterface) => import("react/jsx-runtime").JSX.Element;
13
+ declare const SearchInput: ({ term, placeholder, noSpacing, onClick, isStatic, hasDropDown, onSearch, className, value, inputClassName, }: SearchFieldInterface) => import("react/jsx-runtime").JSX.Element;
13
14
  export default SearchInput;
@@ -203,6 +203,8 @@ export declare const MODE_3D_VIEW = "MODE_3D_VIEW";
203
203
  export declare const MODE_3D_FIRST_PERSON = "MODE_3D_FIRST_PERSON";
204
204
  export declare const MODE_WAITING_DRAWING_LINE = "MODE_WAITING_DRAWING_LINE";
205
205
  export declare const MODE_WAITING_DRAWING_SURFACE = "MODE_WAITING_DRAWING_SURFACE";
206
+ export declare const MODE_WAITING_DRAWING_ROOM = "MODE_WAITING_DRAWING_ROOM";
207
+ export declare const MODE_DRAWING_ROOM = "MODE_DRAWING_ROOM";
206
208
  export declare const MODE_DRAGGING_LINE = "MODE_DRAGGING_LINE";
207
209
  export declare const MODE_DRAGGING_VERTEX = "MODE_DRAGGING_VERTEX";
208
210
  export declare const MODE_DRAGGING_ITEM = "MODE_DRAGGING_ITEM";
@@ -212,6 +214,7 @@ export declare const MODE_DRAWING_HOLE = "MODE_DRAWING_HOLE";
212
214
  export declare const MODE_DRAWING_ITEM = "MODE_DRAWING_ITEM";
213
215
  export declare const MODE_DRAWING_SURFACE = "MODE_DRAWING_SURFACE";
214
216
  export declare const MODE_ROTATING_ITEM = "MODE_ROTATING_ITEM";
217
+ export declare const MODE_RESIZING_ITEM = "MODE_RESIZING_ITEM";
215
218
  export declare const MODE_UPLOADING_IMAGE = "MODE_UPLOADING_IMAGE";
216
219
  export declare const MODE_FITTING_IMAGE = "MODE_FITTING_IMAGE";
217
220
  export declare const MODE_VIEWING_CATALOG = "MODE_VIEWING_CATALOG";
@@ -1,2 +1,2 @@
1
- declare const Footerbar: () => import("react/jsx-runtime").JSX.Element | undefined;
1
+ declare const Footerbar: () => null;
2
2
  export default Footerbar;
@@ -57,6 +57,7 @@ declare const Hole_base: Record.Factory<{
57
57
  prototype: string;
58
58
  offset: number;
59
59
  line: string;
60
+ flipAlongWall: boolean;
60
61
  id: string;
61
62
  type: string;
62
63
  name: string;
@@ -89,6 +90,9 @@ declare const Item_base: Record.Factory<{
89
90
  y: number;
90
91
  rotation: number;
91
92
  altitude: number;
93
+ scale: number;
94
+ flipHorizontal: boolean;
95
+ flipVertical: boolean;
92
96
  id: string;
93
97
  type: string;
94
98
  name: string;
@@ -156,6 +160,7 @@ declare const CatalogElement_base: Record.Factory<{
156
160
  prototype: string;
157
161
  info: Map<unknown, unknown>;
158
162
  properties: Map<unknown, unknown>;
163
+ textures: Map<unknown, unknown>;
159
164
  }>;
160
165
  export declare class CatalogElement extends CatalogElement_base {
161
166
  constructor(json?: any);
@@ -202,6 +207,8 @@ declare const State_base: Record.Factory<{
202
207
  drawingSupport: Map<unknown, unknown>;
203
208
  draggingSupport: Map<unknown, unknown>;
204
209
  rotatingSupport: Map<unknown, unknown>;
210
+ resizingSupport: Map<unknown, unknown>;
211
+ itemSnapGuides: null;
205
212
  errors: List<unknown>;
206
213
  warnings: List<unknown>;
207
214
  clipboardProperties: Map<unknown, unknown>;
@@ -1,2 +1,2 @@
1
1
  import { type Plan, type ReactPlannerStore } from "../../store/ReactPlannerStore";
2
- export default function autosave(autosaveKey: string, delay?: number): (store: ReactPlannerStore, plan: Plan, onSave?: (data: any) => void) => void;
2
+ export default function autosave(autosaveKey: string, delay?: number): (store: ReactPlannerStore, plan: Plan, onSave?: (data: any) => void) => (() => void) | undefined;
@@ -1,2 +1,2 @@
1
1
  import type { ReactPlannerStore } from "../../store/ReactPlannerStore";
2
- export default function keyboard(): (store: ReactPlannerStore) => void;
2
+ export default function keyboard(): (store: ReactPlannerStore) => () => void;
@@ -2,7 +2,8 @@ import React from "react";
2
2
  interface PanelProps {
3
3
  opened?: boolean;
4
4
  name: string;
5
+ subtitle?: string;
5
6
  children: React.ReactNode;
6
7
  }
7
- declare const Panel: ({ children, name, ...props }: PanelProps) => import("react/jsx-runtime").JSX.Element;
8
+ declare const Panel: ({ children, name, subtitle, ...props }: PanelProps) => import("react/jsx-runtime").JSX.Element;
8
9
  export default Panel;
@@ -0,0 +1,8 @@
1
+ import type Catalog from "../../catalog/catalog";
2
+ interface AreaAttributesEditorProps {
3
+ element: any;
4
+ layer: any;
5
+ catalog: Catalog;
6
+ }
7
+ declare const AreaAttributesEditor: ({ element, layer, catalog, }: AreaAttributesEditorProps) => import("react/jsx-runtime").JSX.Element;
8
+ export default AreaAttributesEditor;
@@ -1,8 +1,11 @@
1
+ import type Catalog from "../../catalog/catalog";
1
2
  interface AttributesEditorProps {
2
3
  element: any;
4
+ layer: any;
5
+ catalog: Catalog;
3
6
  onUpdate: (k: string, v: any) => void;
4
7
  onValid: () => void;
5
8
  attributeFormData: any;
6
9
  }
7
- declare const AttributesEditor: ({ element, onUpdate, onValid, attributeFormData, ...props }: AttributesEditorProps) => import("react/jsx-runtime").JSX.Element | null;
10
+ declare const AttributesEditor: ({ element, layer, catalog, onUpdate, onValid, attributeFormData, ...props }: AttributesEditorProps) => import("react/jsx-runtime").JSX.Element | null;
8
11
  export default AttributesEditor;
@@ -1,8 +1,7 @@
1
+ import type Catalog from "../../catalog/catalog";
1
2
  interface HoleAttributesEditorProps {
2
3
  element: any;
3
- onUpdate: (k: string, v: any) => void;
4
- attributeFormData: any;
5
- onValid?: (event: Event) => void;
4
+ catalog: Catalog;
6
5
  }
7
- declare const HoleAttributesEditor: ({ element, attributeFormData, onUpdate, ...props }: HoleAttributesEditorProps) => import("react/jsx-runtime").JSX.Element;
6
+ declare const HoleAttributesEditor: ({ element, catalog, }: HoleAttributesEditorProps) => import("react/jsx-runtime").JSX.Element;
8
7
  export default HoleAttributesEditor;
@@ -1,8 +1,7 @@
1
+ import type Catalog from "../../catalog/catalog";
1
2
  interface ItemAttributesEditorProps {
2
3
  element: any;
3
- onUpdate: (k: string, v: any) => void;
4
- attributeFormData: any;
5
- onValid?: (event: Event) => void;
4
+ catalog: Catalog;
6
5
  }
7
- declare const ItemAttributesEditor: ({ element, onUpdate, attributeFormData, ...props }: ItemAttributesEditorProps) => import("react/jsx-runtime").JSX.Element;
6
+ declare const ItemAttributesEditor: ({ element, catalog, }: ItemAttributesEditorProps) => import("react/jsx-runtime").JSX.Element;
8
7
  export default ItemAttributesEditor;
@@ -0,0 +1,15 @@
1
+ import type Catalog from "../../catalog/catalog";
2
+ import type { CatalogElement } from "../../catalog/catalog";
3
+ export declare function findSimilarElements(catalog: Catalog, element: any): CatalogElement[];
4
+ interface SimilarElementsGridProps {
5
+ elements: CatalogElement[];
6
+ /** Panel the pointer has to leave for the drag to become a placement. */
7
+ containerSelector?: string;
8
+ }
9
+ /**
10
+ * A browse-and-place list: press an entry and drag it out of the sidebar to
11
+ * start placing one, exactly like the catalog picker in the toolbar. Nothing
12
+ * here touches the selected element — these are additions, not swaps.
13
+ */
14
+ export declare const SimilarElementsGrid: ({ elements, containerSelector, }: SimilarElementsGridProps) => import("react/jsx-runtime").JSX.Element;
15
+ export {};
@@ -0,0 +1,8 @@
1
+ import type Catalog from "../../catalog/catalog";
2
+ interface WallAttributesEditorProps {
3
+ element: any;
4
+ layer: any;
5
+ catalog: Catalog;
6
+ }
7
+ declare const WallAttributesEditor: ({ element, layer, catalog, }: WallAttributesEditorProps) => import("react/jsx-runtime").JSX.Element;
8
+ export default WallAttributesEditor;
@@ -0,0 +1,42 @@
1
+ import type React from "react";
2
+ export declare const BackHeader: ({ title, subtitle, onBack, }: {
3
+ title: string;
4
+ subtitle?: string;
5
+ onBack: () => void;
6
+ }) => import("react/jsx-runtime").JSX.Element;
7
+ interface RowButtonProps {
8
+ swatchColor?: string;
9
+ textureUri?: string;
10
+ icon?: React.ReactNode;
11
+ label: string;
12
+ value?: string;
13
+ onClick: () => void;
14
+ }
15
+ export declare const RowButton: ({ swatchColor, textureUri, icon, label, value, onClick, }: RowButtonProps) => import("react/jsx-runtime").JSX.Element;
16
+ interface MeasureStepperProps {
17
+ value: number;
18
+ onChange: (next: number) => void;
19
+ step?: number;
20
+ min?: number;
21
+ max?: number;
22
+ /** Suffix shown inside the field. Lengths are stored in cm throughout. */
23
+ unit?: string;
24
+ }
25
+ export declare const MeasureStepper: ({ value, onChange, step, min, max, unit, }: MeasureStepperProps) => import("react/jsx-runtime").JSX.Element;
26
+ export interface EditorAction {
27
+ key: string;
28
+ label: string;
29
+ icon: React.ReactNode;
30
+ danger?: boolean;
31
+ onClick: () => void;
32
+ }
33
+ /** Round icon buttons under the preview — duplicate, rotate, flip, delete. */
34
+ export declare const ActionRow: ({ actions }: {
35
+ actions: EditorAction[];
36
+ }) => import("react/jsx-runtime").JSX.Element;
37
+ /** Catalog thumbnail, falling back to a neutral tile when there is no image. */
38
+ export declare const ElementPreview: ({ imageUri, alt, }: {
39
+ imageUri?: string;
40
+ alt: string;
41
+ }) => import("react/jsx-runtime").JSX.Element;
42
+ export {};
@@ -0,0 +1,8 @@
1
+ import Catalog from "../catalog/catalog";
2
+ interface CatalogPickerProps {
3
+ catalog: Catalog;
4
+ page: string;
5
+ containerSelector?: string;
6
+ }
7
+ declare const CatalogPicker: ({ catalog, page, containerSelector, }: CatalogPickerProps) => import("react/jsx-runtime").JSX.Element;
8
+ export default CatalogPicker;
@@ -0,0 +1,11 @@
1
+ interface NumberStepperProps {
2
+ label: string;
3
+ value: number;
4
+ unit?: string;
5
+ step?: number;
6
+ min?: number;
7
+ max?: number;
8
+ onChange: (value: number) => void;
9
+ }
10
+ declare const NumberStepper: ({ label, value, unit, step, min, max, onChange, }: NumberStepperProps) => import("react/jsx-runtime").JSX.Element;
11
+ export default NumberStepper;
@@ -0,0 +1,11 @@
1
+ export interface HoveredArea {
2
+ layerID: string;
3
+ areaID: string;
4
+ label: string;
5
+ area: number;
6
+ }
7
+ interface ProjectMiniMapProps {
8
+ onHoverChange?: (info: HoveredArea | null) => void;
9
+ }
10
+ declare const ProjectMiniMap: ({ onHoverChange }: ProjectMiniMapProps) => import("react/jsx-runtime").JSX.Element;
11
+ export default ProjectMiniMap;
@@ -0,0 +1,2 @@
1
+ declare const ProjectPanel: () => import("react/jsx-runtime").JSX.Element;
2
+ export default ProjectPanel;
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from "react";
2
+ export type RailSection = "project" | "build" | "info" | "objects" | "styleboards" | "finishes" | "help";
3
+ export interface RailItem {
4
+ key: RailSection;
5
+ label: string;
6
+ icon: ReactNode;
7
+ disabled?: boolean;
8
+ }
9
+ interface ToolbarRailProps {
10
+ items: RailItem[];
11
+ active: RailSection | null;
12
+ onChange: (section: RailSection) => void;
13
+ }
14
+ declare const ToolbarRail: ({ items, active, onChange }: ToolbarRailProps) => import("react/jsx-runtime").JSX.Element;
15
+ export default ToolbarRail;
@@ -0,0 +1,23 @@
1
+ import type { ReactNode } from "react";
2
+ import type Catalog from "../catalog/catalog";
3
+ export interface SubPanelOption {
4
+ key: string;
5
+ label: string;
6
+ icon: ReactNode;
7
+ active?: boolean;
8
+ disabled?: boolean;
9
+ hasChildren?: boolean;
10
+ onClick?: () => void;
11
+ }
12
+ interface ToolbarSubPanelProps {
13
+ title: string;
14
+ options?: SubPanelOption[];
15
+ cta?: string;
16
+ emptyState?: ReactNode;
17
+ catalog?: Catalog;
18
+ catalogPage?: string | null;
19
+ onBack?: () => void;
20
+ headerExtras?: ReactNode;
21
+ }
22
+ declare const ToolbarSubPanel: ({ title, options, cta, emptyState, catalog, catalogPage, onBack, headerExtras, }: ToolbarSubPanelProps) => import("react/jsx-runtime").JSX.Element;
23
+ export default ToolbarSubPanel;
@@ -0,0 +1,5 @@
1
+ interface ZoomControlsProps {
2
+ subPanelOpen?: boolean;
3
+ }
4
+ declare const ZoomControls: ({ subPanelOpen }: ZoomControlsProps) => import("react/jsx-runtime").JSX.Element;
5
+ export default ZoomControls;
@@ -0,0 +1,9 @@
1
+ export declare const RIGHT_ANGLE_TOLERANCE = 5;
2
+ /** Normalize to (-180, 180], the range the rest of the planner uses. */
3
+ export declare const normalizeAngle: (degrees: number) => number;
4
+ /**
5
+ * Pull an angle onto the nearest quarter turn if it is already close to one.
6
+ * Shared so that rotating an item feels the same however it is done — the 2D
7
+ * handle, the 3D gizmo, or anything added later.
8
+ */
9
+ export declare const snapToRightAngle: (degrees: number) => number;
@@ -141,6 +141,21 @@ export declare function extendLine(x1: number, y1: number, x2: number, y2: numbe
141
141
  y: number;
142
142
  };
143
143
  export declare function roundVertex(vertex: Map<string, number>, precision?: number): Map<string, number>;
144
+ /** Is (pointX, pointY) strictly inside `polygon` (a flat [x0,y0,x1,y1,…] ring)?
145
+ *
146
+ * A point *on* the boundary counts as outside. Callers depend on that: the
147
+ * hole detection in `Layer.detectAndUpdateAreas` asks whether one area sits
148
+ * inside another by testing one of its vertices, and neighbouring rooms
149
+ * always share corners — a shared corner has to answer "no".
150
+ *
151
+ * This used to be PolyK's `ContainsPoint`, whose "hit vertex" correction
152
+ * decremented the crossing count for a polygon vertex level with the query
153
+ * point *even when that vertex sat to the left of it and had therefore never
154
+ * been counted*, leaving the count at -1 and reporting a point far outside as
155
+ * inside. Floor plans are axis-aligned and grid-snapped, so points level with
156
+ * a vertex are the common case, not a corner case — every room in a grid of
157
+ * rooms is level with its neighbours' corners. Rewritten as a plain
158
+ * crossing-number test with an explicit boundary check up front. */
144
159
  export declare function ContainsPoint(polygon: number[], pointX: number, pointY: number): boolean;
145
160
  export declare function cosWithThreshold(alpha: number, threshold: number): number;
146
161
  export declare function sinWithThreshold(alpha: number, threshold: number): number;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Where an image's visible pixels actually are inside the rectangle it is
3
+ * drawn in.
4
+ *
5
+ * Catalog artwork is usually a PNG with transparent margin around the object,
6
+ * and `<image>` letterboxes it on top of that when the file's proportions
7
+ * don't match the rectangle. Both leave empty space that nothing in the DOM
8
+ * reports — `getBBox()` returns the rectangle as declared — so an item snapped
9
+ * flush by its bounding box still looks like it is floating off the wall.
10
+ *
11
+ * The scan is done once per URL and cached for the life of the page.
12
+ */
13
+ export interface Rect {
14
+ x: number;
15
+ y: number;
16
+ width: number;
17
+ height: number;
18
+ }
19
+ /**
20
+ * The rectangle an image's visible pixels occupy, in the same coordinates
21
+ * `rect` is given in. Null when it can't be worked out — a cross-origin asset
22
+ * without CORS headers, a `slice` fit, an image that failed to load — in which
23
+ * case the caller should stay with the declared rectangle.
24
+ */
25
+ export declare function visibleImageRect(src: string, rect: Rect, preserveAspectRatio: string): Promise<Rect | null>;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * What each item actually measures on the plan.
3
+ *
4
+ * Catalog elements draw themselves at whatever size they like and the `Item`
5
+ * record carries no width or height, so an item's footprint is only knowable
6
+ * from what it rendered. `viewer2d/Item` measures that anyway — for handle and
7
+ * label placement — and files the result here so the rest of the planner can
8
+ * reason about item geometry without touching the DOM.
9
+ *
10
+ * The box is in the item's own frame, after per-instance scaling and
11
+ * mirroring, before rotation: `x`/`y` are its corner relative to the item's
12
+ * origin, which is not necessarily its centre.
13
+ */
14
+ export interface ItemFootprint {
15
+ x: number;
16
+ y: number;
17
+ width: number;
18
+ height: number;
19
+ }
20
+ export declare function rememberItemFootprint(itemID: string, box: ItemFootprint): void;
21
+ export declare function forgetItemFootprint(itemID: string): void;
22
+ /** Null for an item that hasn't been drawn in 2D yet. */
23
+ export declare function getItemFootprint(itemID: string): ItemFootprint | null;
@@ -0,0 +1,56 @@
1
+ import { type ItemFootprint } from "./item-footprint";
2
+ export declare const ITEM_WALL_SNAP_DISTANCE = 25;
3
+ export declare const ITEM_ITEM_SNAP_DISTANCE = 25;
4
+ /** The face an item snapped against, for the viewer to draw a guide along. */
5
+ export interface ItemSnapGuide {
6
+ x1: number;
7
+ y1: number;
8
+ x2: number;
9
+ y2: number;
10
+ }
11
+ export interface ItemWallSnap {
12
+ x: number;
13
+ y: number;
14
+ rotation: number;
15
+ lineID: string;
16
+ guides: ItemSnapGuide[];
17
+ /**
18
+ * The world direction the item is still free to slide along after the snap —
19
+ * the wall's own direction, since going flush only fixes the axis across it.
20
+ * Null once a corner snap has fixed that one too. What is left here is what
21
+ * a neighbouring item is allowed to move the item on.
22
+ */
23
+ free: {
24
+ x: number;
25
+ y: number;
26
+ } | null;
27
+ }
28
+ /**
29
+ * Where the item would sit if it snapped to a wall, or null if none is close
30
+ * enough.
31
+ *
32
+ * The item goes flush against the nearest wall face and squares up with it,
33
+ * then — if it is also near the wall at the other end — slides along until it
34
+ * sits in the corner. It stays free on any axis it hasn't snapped on, so the
35
+ * pointer still leads there.
36
+ */
37
+ export declare function snapItemToWalls(layer: any, catalog: any, footprint: ItemFootprint | null, x: number, y: number, rotation: number): ItemWallSnap | null;
38
+ /** Where the item lands, or null if nothing was close enough to snap to. */
39
+ export interface ItemSnap {
40
+ x: number;
41
+ y: number;
42
+ rotation: number;
43
+ guides: ItemSnapGuide[];
44
+ }
45
+ /**
46
+ * Everything a dragged item snaps to: the walls first, then the items already
47
+ * placed.
48
+ *
49
+ * The two compose rather than compete. A wall snap fixes the axis across the
50
+ * wall and squares the item up; the items on the layer then get to decide
51
+ * where along that wall it sits — so a nightstand pushed towards a corner goes
52
+ * flush against the wall *and* flush against the bed in one gesture. Once a
53
+ * corner snap has fixed the second axis too there is nothing left to offer and
54
+ * the walls have it. With no wall in range, both axes are the items' to claim.
55
+ */
56
+ export declare function snapItem(layer: any, catalog: any, itemID: string, footprint: ItemFootprint | null, x: number, y: number, rotation: number): ItemSnap | null;
@@ -0,0 +1,9 @@
1
+ export declare const ITEM_MIN_SCALE = 0.2;
2
+ export declare const ITEM_MAX_SCALE = 8;
3
+ export interface ItemTransform {
4
+ scale: number;
5
+ flipHorizontal: boolean;
6
+ flipVertical: boolean;
7
+ }
8
+ export declare function getItemTransform(item: any): ItemTransform;
9
+ export declare function clampItemScale(scale: number): number;
@@ -1,3 +1,3 @@
1
1
  export default class NameGenerator {
2
- static generateName(_: any, type: string): string;
2
+ static generateName(_: any, type: unknown): string;
3
3
  }
@@ -0,0 +1,17 @@
1
+ import { Texture } from "three";
2
+ import type { ColorSpace } from "three";
3
+ /**
4
+ * One decoded image per URL, handed out as clones.
5
+ *
6
+ * Callers set their own `repeat`/`wrap` — a wall tiles differently from a
7
+ * floor — and those live on the Texture, so a single shared object won't do.
8
+ * A clone carries its own settings but shares `source` with the base, and the
9
+ * renderer keys GPU uploads on `source` (refcounted, so disposing a clone is
10
+ * safe): the bytes are fetched, decoded and uploaded once no matter how many
11
+ * walls ask for them.
12
+ *
13
+ * `colorSpace` defaults to sRGB because most callers want an albedo map, and
14
+ * one left in the renderer's linear working space comes out visibly washed
15
+ * out. Data maps — normals, roughness — must pass `NoColorSpace`.
16
+ */
17
+ export declare function loadTexture(uri: string, colorSpace?: ColorSpace): Texture;
@@ -0,0 +1,33 @@
1
+ import { Object3D, Texture } from "three";
2
+ /**
3
+ * Mark a texture as holding colour rather than data.
4
+ *
5
+ * Image files store colour sRGB-encoded, but lighting has to happen in linear
6
+ * space — the renderer only knows to convert if the texture says so. Left at
7
+ * the default, an albedo map renders washed out and the wrong brightness.
8
+ * Normal/roughness/metalness maps are numbers, not colour, and must stay
9
+ * linear: those get `NoColorSpace`.
10
+ */
11
+ export declare function asColorMap<T extends Texture>(texture: T): T;
12
+ export declare function asDataMap<T extends Texture>(texture: T): T;
13
+ /**
14
+ * Bring a freshly imported model in line with how the viewer lights the scene.
15
+ *
16
+ * Model files describe their materials in whatever the exporting tool used,
17
+ * and the loaders reproduce that faithfully — which is why an .obj arrives
18
+ * Phong and a .glb arrives Standard. Anything already physically based is left
19
+ * alone beyond its colour spaces; the rest is converted so one lighting rig
20
+ * can light all of it consistently.
21
+ */
22
+ export declare function normalizeImportedMaterials<T extends Object3D>(object: T): T;
23
+ interface ShadowOptions {
24
+ cast?: boolean;
25
+ receive?: boolean;
26
+ }
27
+ /**
28
+ * Contact shadows are most of what makes furniture look like it's standing on
29
+ * the floor rather than pasted over it. Floors only receive — a flat surface
30
+ * casting onto itself is all acne and no shadow.
31
+ */
32
+ export declare function enableShadows<T extends Object3D>(object: T, { cast, receive }?: ShadowOptions): T;
33
+ export {};
@@ -21,7 +21,7 @@ declare class Polygon {
21
21
  clone(): Polygon;
22
22
  flip(): this;
23
23
  classifyVertex(vertex: THREE.Vector3Like): 0 | 1 | 2;
24
- classifySide(polygon: Polygon): 0 | 1 | 2 | 3;
24
+ classifySide(polygon: Polygon): 0 | 1 | 3 | 2;
25
25
  splitPolygon(polygon: Polygon, coplanar_front: any, coplanar_back: any, front: any, back: any): void;
26
26
  }
27
27
  declare class Node {