@7365admin1/layer-common 4.49.0 → 4.51.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.
@@ -4,9 +4,11 @@
4
4
  * components only draw what these return.
5
5
  *
6
6
  * A floor plan is an image stored privately in the building map (never the
7
- * public file store) and placed in the HERO plan frame (40 x 26 m, the same
8
- * frame every drawn wall, door and lift uses): its top-left corner at
9
- * (`tx`, `ty`) metres, `metersPerPixel` from a measured distance.
7
+ * public file store): its top-left corner at world (`tx`, -`ty`) metres (for
8
+ * a map drawn in the old 40 x 26 m frame: simply metres from the plan's
9
+ * top-left), `metersPerPixel` from a measured distance, turned `yawRad`.
10
+ * The editor's own placement maths is in `rmf-editor.ts` (any frame size);
11
+ * `planBox` / `fitPlan` here keep the 40 x 26 m frame for older callers.
10
12
  */
11
13
 
12
14
  /** The HERO plan frame - `utils/robot-building.ts` PLAN_W_M / PLAN_H_M (decision 30). */
@@ -18,7 +20,7 @@ export const FLOOR_PLAN_MAX_BYTES = 1_000_000;
18
20
  export const FLOOR_PLAN_MAX_PX = 2400;
19
21
  export const FLOOR_PLAN_TYPES = ["image/png", "image/jpeg", "image/webp"];
20
22
 
21
- export type TFloorPlan = { floorNo: number; widthPx: number; heightPx: number; metersPerPixel: number; tx: number; ty: number; updatedAt?: string };
23
+ export type TFloorPlan = { floorNo: number; widthPx: number; heightPx: number; metersPerPixel: number; tx: number; ty: number; yawRad?: number; updatedAt?: string };
22
24
  export type TPlanPoint = { x: number; y: number };
23
25
 
24
26
  const r6 = (v: number) => Math.round(v * 1e6) / 1e6;
@@ -70,14 +72,13 @@ export function rescaleByMeasure(p: TFloorPlan, a: TPlanPoint, b: TPlanPoint, re
70
72
  return { plan: { ...p, metersPerPixel } };
71
73
  }
72
74
 
73
- /** "1 px = 4.2 cm · plan 33.6 x 25.2 m" */
74
- export function scaleText(p: TFloorPlan | null) {
75
+ /** "1 px = 4.2 cm · plan 33.6 x 25.2 m" - the drawing area grows to take in a bigger plan, so nothing is cut off. */
76
+ export function scaleText(p: Pick<TFloorPlan, "widthPx" | "heightPx" | "metersPerPixel"> | null) {
75
77
  if (!p) return "";
76
78
  const cm = p.metersPerPixel * 100;
77
79
  const w = p.widthPx * p.metersPerPixel;
78
80
  const h = p.heightPx * p.metersPerPixel;
79
- const big = w > FRAME_W_M + 0.05 || h > FRAME_H_M + 0.05;
80
- return `1 px = ${cm >= 10 ? cm.toFixed(0) : cm.toFixed(1)} cm · plan ${w.toFixed(1)} × ${h.toFixed(1)} m${big ? " (larger than the 40 × 26 m drawing area - the edge is cut off)" : ""}`;
81
+ return `1 px = ${cm >= 10 ? cm.toFixed(0) : cm.toFixed(1)} cm · plan ${w.toFixed(1)} × ${h.toFixed(1)} m`;
81
82
  }
82
83
 
83
84
  /** Plain-language reason a picked file cannot be used, or null. */
package/utils/role.ts CHANGED
@@ -60,3 +60,16 @@ export function memberRoleChip(item: {
60
60
  return name ? { text: name, tone: "info" } : null;
61
61
  }
62
62
  }
63
+
64
+ /**
65
+ * The Members banner (owner decision 2026-09-25: keep the warning, companies
66
+ * re-assign a role for the right site, nobody's access is cut). `null` at 0 so
67
+ * the banner disappears once every member here has this site's role.
68
+ */
69
+ export function otherSiteBannerText(count: unknown): string | null {
70
+ const n = typeof count === "number" && Number.isFinite(count) ? Math.floor(count) : 0;
71
+ if (n <= 0) return null;
72
+ return n === 1
73
+ ? "1 member here has a role from another site. Assign them a role for this site."
74
+ : `${n} members here have a role from another site. Assign each one a role for this site.`;
75
+ }