@camstack/ui-library 1.2.179 → 1.2.180
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/composites/cap-settings/camera-grid-layout.d.ts +6 -2
- package/dist/index.cjs +63 -65
- package/dist/index.js +63 -65
- package/package.json +1 -1
|
@@ -32,13 +32,17 @@ export interface GridProfileOffer {
|
|
|
32
32
|
readonly profile: 'high' | 'mid' | 'low';
|
|
33
33
|
readonly offered: boolean;
|
|
34
34
|
readonly missingSources: readonly number[];
|
|
35
|
+
/**
|
|
36
|
+
* The canvas this profile composes onto, `WxH`, or empty when it is not
|
|
37
|
+
* offered. DERIVED — the operator no longer types a resolution, so this is
|
|
38
|
+
* the only place the grid's actual size is ever stated.
|
|
39
|
+
*/
|
|
40
|
+
readonly canvas: string;
|
|
35
41
|
}
|
|
36
42
|
export interface GridLayoutView {
|
|
37
43
|
readonly instanceId: string;
|
|
38
44
|
readonly deviceId: number;
|
|
39
45
|
readonly name: string;
|
|
40
|
-
readonly width: number;
|
|
41
|
-
readonly height: number;
|
|
42
46
|
readonly fps: number;
|
|
43
47
|
readonly cells: readonly GridLayoutCell[];
|
|
44
48
|
readonly profiles: readonly GridProfileOffer[];
|
package/dist/index.cjs
CHANGED
|
@@ -16641,7 +16641,8 @@ function readProfileOffer(value) {
|
|
|
16641
16641
|
return {
|
|
16642
16642
|
profile,
|
|
16643
16643
|
offered,
|
|
16644
|
-
missingSources
|
|
16644
|
+
missingSources,
|
|
16645
|
+
canvas: typeof value["canvas"] === "string" ? value["canvas"] : ""
|
|
16645
16646
|
};
|
|
16646
16647
|
}
|
|
16647
16648
|
/**
|
|
@@ -16655,8 +16656,8 @@ function readProfileOffer(value) {
|
|
|
16655
16656
|
function parseGridView(raw) {
|
|
16656
16657
|
if (raw === null) return null;
|
|
16657
16658
|
if (!isRecord(raw)) return "unreadable";
|
|
16658
|
-
const { instanceId, deviceId, name,
|
|
16659
|
-
if (typeof instanceId !== "string" || typeof deviceId !== "number" || typeof name !== "string" || typeof
|
|
16659
|
+
const { instanceId, deviceId, name, fps, cells, profiles } = raw;
|
|
16660
|
+
if (typeof instanceId !== "string" || typeof deviceId !== "number" || typeof name !== "string" || typeof fps !== "number" || !Array.isArray(cells) || !Array.isArray(profiles)) return "unreadable";
|
|
16660
16661
|
const parsed = [];
|
|
16661
16662
|
for (const entry of cells) {
|
|
16662
16663
|
const cell = readCell(entry);
|
|
@@ -16673,8 +16674,6 @@ function parseGridView(raw) {
|
|
|
16673
16674
|
instanceId,
|
|
16674
16675
|
deviceId,
|
|
16675
16676
|
name,
|
|
16676
|
-
width,
|
|
16677
|
-
height,
|
|
16678
16677
|
fps,
|
|
16679
16678
|
cells: parsed,
|
|
16680
16679
|
profiles: offers
|
|
@@ -16896,8 +16895,6 @@ function CameraGridLayoutEditor({ deviceId }) {
|
|
|
16896
16895
|
try {
|
|
16897
16896
|
const outcome = parseGridView(await layout.saveLayout({
|
|
16898
16897
|
name: draft.name,
|
|
16899
|
-
width: draft.width,
|
|
16900
|
-
height: draft.height,
|
|
16901
16898
|
fps: draft.fps,
|
|
16902
16899
|
cells: draft.cells.map((cell) => ({ ...cell }))
|
|
16903
16900
|
}));
|
|
@@ -16920,7 +16917,27 @@ function CameraGridLayoutEditor({ deviceId }) {
|
|
|
16920
16917
|
} : cell)
|
|
16921
16918
|
});
|
|
16922
16919
|
}, []);
|
|
16923
|
-
|
|
16920
|
+
/**
|
|
16921
|
+
* The shape the grid will actually come out as.
|
|
16922
|
+
*
|
|
16923
|
+
* The canvas is no longer a field: each profile derives its own from the
|
|
16924
|
+
* cells and the sources' dimensions, and the server reports what it came out
|
|
16925
|
+
* as. Drawing at that aspect is the only way the editor shows the truth —
|
|
16926
|
+
* before, it drew at whatever two numbers had been typed, which is exactly
|
|
16927
|
+
* how a layout could look right here and wrong on screen.
|
|
16928
|
+
*
|
|
16929
|
+
* 16:9 while nothing is offered yet: a grid with no cells has no shape, and
|
|
16930
|
+
* an empty editor has to be drawn at something.
|
|
16931
|
+
*/
|
|
16932
|
+
const canvasAspect = (0, react$1.useMemo)(() => {
|
|
16933
|
+
const offered = loaded === void 0 || loaded === null || loaded === "unreadable" ? [] : loaded.profiles;
|
|
16934
|
+
for (const row of offered) {
|
|
16935
|
+
if (!row.offered) continue;
|
|
16936
|
+
const [width, height] = row.canvas.split("x").map(Number);
|
|
16937
|
+
if (width !== void 0 && height !== void 0 && width > 0 && height > 0) return width / height;
|
|
16938
|
+
}
|
|
16939
|
+
return 16 / 9;
|
|
16940
|
+
}, [loaded]);
|
|
16924
16941
|
if (loaded === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WidgetPanel, {
|
|
16925
16942
|
title: "Grid layout",
|
|
16926
16943
|
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Grid2x2, { className: "h-3.5 w-3.5" }),
|
|
@@ -17031,62 +17048,39 @@ function CameraGridLayoutEditor({ deviceId }) {
|
|
|
17031
17048
|
}),
|
|
17032
17049
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
17033
17050
|
className: "grid grid-cols-4 gap-2 text-[10.5px]",
|
|
17034
|
-
children: [
|
|
17035
|
-
|
|
17036
|
-
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17040
|
-
|
|
17041
|
-
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
17046
|
-
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
|
|
17052
|
-
|
|
17053
|
-
|
|
17054
|
-
|
|
17055
|
-
|
|
17056
|
-
|
|
17057
|
-
|
|
17058
|
-
|
|
17059
|
-
|
|
17060
|
-
|
|
17061
|
-
|
|
17062
|
-
|
|
17063
|
-
|
|
17064
|
-
|
|
17065
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
17066
|
-
|
|
17067
|
-
disabled: draft.cells.length >= MAX_CELLS,
|
|
17068
|
-
onClick: () => {
|
|
17069
|
-
const first = cameras.find((camera) => camera.id !== deviceId);
|
|
17070
|
-
if (!first) return;
|
|
17071
|
-
setDraft({
|
|
17072
|
-
...draft,
|
|
17073
|
-
cells: [...draft.cells, {
|
|
17074
|
-
deviceId: first.id,
|
|
17075
|
-
source: FULL_FRAME,
|
|
17076
|
-
cell: clampNormalizedRect({
|
|
17077
|
-
x: .1,
|
|
17078
|
-
y: .1,
|
|
17079
|
-
width: .4,
|
|
17080
|
-
height: .4
|
|
17081
|
-
})
|
|
17082
|
-
}]
|
|
17083
|
-
});
|
|
17084
|
-
setSelected(draft.cells.length);
|
|
17085
|
-
},
|
|
17086
|
-
className: "flex items-center justify-center gap-1 self-end rounded border border-border px-2 py-1 uppercase",
|
|
17087
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Plus, { className: "h-3 w-3" }), " Cell"]
|
|
17088
|
-
})
|
|
17089
|
-
]
|
|
17051
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(LabelledNumber, {
|
|
17052
|
+
label: "FPS",
|
|
17053
|
+
value: draft.fps,
|
|
17054
|
+
onChange: (fps) => {
|
|
17055
|
+
setDraft({
|
|
17056
|
+
...draft,
|
|
17057
|
+
fps
|
|
17058
|
+
});
|
|
17059
|
+
}
|
|
17060
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
17061
|
+
type: "button",
|
|
17062
|
+
disabled: draft.cells.length >= MAX_CELLS,
|
|
17063
|
+
onClick: () => {
|
|
17064
|
+
const first = cameras.find((camera) => camera.id !== deviceId);
|
|
17065
|
+
if (!first) return;
|
|
17066
|
+
setDraft({
|
|
17067
|
+
...draft,
|
|
17068
|
+
cells: [...draft.cells, {
|
|
17069
|
+
deviceId: first.id,
|
|
17070
|
+
source: FULL_FRAME,
|
|
17071
|
+
cell: clampNormalizedRect({
|
|
17072
|
+
x: .1,
|
|
17073
|
+
y: .1,
|
|
17074
|
+
width: .4,
|
|
17075
|
+
height: .4
|
|
17076
|
+
})
|
|
17077
|
+
}]
|
|
17078
|
+
});
|
|
17079
|
+
setSelected(draft.cells.length);
|
|
17080
|
+
},
|
|
17081
|
+
className: "flex items-center justify-center gap-1 self-end rounded border border-border px-2 py-1 uppercase",
|
|
17082
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Plus, { className: "h-3 w-3" }), " Cell"]
|
|
17083
|
+
})]
|
|
17090
17084
|
}),
|
|
17091
17085
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GridProfileReport, {
|
|
17092
17086
|
offers: loaded.profiles,
|
|
@@ -17134,7 +17128,11 @@ function GridProfileReport({ offers, cameras }) {
|
|
|
17134
17128
|
children: offer.profile
|
|
17135
17129
|
}), offer.offered ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
17136
17130
|
className: "text-foreground-subtle",
|
|
17137
|
-
children: [
|
|
17131
|
+
children: [
|
|
17132
|
+
offer.canvas,
|
|
17133
|
+
" — composed from every source’s ",
|
|
17134
|
+
offer.profile
|
|
17135
|
+
]
|
|
17138
17136
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
17139
17137
|
className: "text-danger",
|
|
17140
17138
|
children: offer.missingSources.length === 0 ? "not offered — this grid has no cells yet" : `not offered — no ${offer.profile} on ${offer.missingSources.map(nameOf).join(", ")}`
|
package/dist/index.js
CHANGED
|
@@ -16617,7 +16617,8 @@ function readProfileOffer(value) {
|
|
|
16617
16617
|
return {
|
|
16618
16618
|
profile,
|
|
16619
16619
|
offered,
|
|
16620
|
-
missingSources
|
|
16620
|
+
missingSources,
|
|
16621
|
+
canvas: typeof value["canvas"] === "string" ? value["canvas"] : ""
|
|
16621
16622
|
};
|
|
16622
16623
|
}
|
|
16623
16624
|
/**
|
|
@@ -16631,8 +16632,8 @@ function readProfileOffer(value) {
|
|
|
16631
16632
|
function parseGridView(raw) {
|
|
16632
16633
|
if (raw === null) return null;
|
|
16633
16634
|
if (!isRecord(raw)) return "unreadable";
|
|
16634
|
-
const { instanceId, deviceId, name,
|
|
16635
|
-
if (typeof instanceId !== "string" || typeof deviceId !== "number" || typeof name !== "string" || typeof
|
|
16635
|
+
const { instanceId, deviceId, name, fps, cells, profiles } = raw;
|
|
16636
|
+
if (typeof instanceId !== "string" || typeof deviceId !== "number" || typeof name !== "string" || typeof fps !== "number" || !Array.isArray(cells) || !Array.isArray(profiles)) return "unreadable";
|
|
16636
16637
|
const parsed = [];
|
|
16637
16638
|
for (const entry of cells) {
|
|
16638
16639
|
const cell = readCell(entry);
|
|
@@ -16649,8 +16650,6 @@ function parseGridView(raw) {
|
|
|
16649
16650
|
instanceId,
|
|
16650
16651
|
deviceId,
|
|
16651
16652
|
name,
|
|
16652
|
-
width,
|
|
16653
|
-
height,
|
|
16654
16653
|
fps,
|
|
16655
16654
|
cells: parsed,
|
|
16656
16655
|
profiles: offers
|
|
@@ -16872,8 +16871,6 @@ function CameraGridLayoutEditor({ deviceId }) {
|
|
|
16872
16871
|
try {
|
|
16873
16872
|
const outcome = parseGridView(await layout.saveLayout({
|
|
16874
16873
|
name: draft.name,
|
|
16875
|
-
width: draft.width,
|
|
16876
|
-
height: draft.height,
|
|
16877
16874
|
fps: draft.fps,
|
|
16878
16875
|
cells: draft.cells.map((cell) => ({ ...cell }))
|
|
16879
16876
|
}));
|
|
@@ -16896,7 +16893,27 @@ function CameraGridLayoutEditor({ deviceId }) {
|
|
|
16896
16893
|
} : cell)
|
|
16897
16894
|
});
|
|
16898
16895
|
}, []);
|
|
16899
|
-
|
|
16896
|
+
/**
|
|
16897
|
+
* The shape the grid will actually come out as.
|
|
16898
|
+
*
|
|
16899
|
+
* The canvas is no longer a field: each profile derives its own from the
|
|
16900
|
+
* cells and the sources' dimensions, and the server reports what it came out
|
|
16901
|
+
* as. Drawing at that aspect is the only way the editor shows the truth —
|
|
16902
|
+
* before, it drew at whatever two numbers had been typed, which is exactly
|
|
16903
|
+
* how a layout could look right here and wrong on screen.
|
|
16904
|
+
*
|
|
16905
|
+
* 16:9 while nothing is offered yet: a grid with no cells has no shape, and
|
|
16906
|
+
* an empty editor has to be drawn at something.
|
|
16907
|
+
*/
|
|
16908
|
+
const canvasAspect = useMemo(() => {
|
|
16909
|
+
const offered = loaded === void 0 || loaded === null || loaded === "unreadable" ? [] : loaded.profiles;
|
|
16910
|
+
for (const row of offered) {
|
|
16911
|
+
if (!row.offered) continue;
|
|
16912
|
+
const [width, height] = row.canvas.split("x").map(Number);
|
|
16913
|
+
if (width !== void 0 && height !== void 0 && width > 0 && height > 0) return width / height;
|
|
16914
|
+
}
|
|
16915
|
+
return 16 / 9;
|
|
16916
|
+
}, [loaded]);
|
|
16900
16917
|
if (loaded === void 0) return /* @__PURE__ */ jsx(WidgetPanel, {
|
|
16901
16918
|
title: "Grid layout",
|
|
16902
16919
|
icon: /* @__PURE__ */ jsx(Grid2x2, { className: "h-3.5 w-3.5" }),
|
|
@@ -17007,62 +17024,39 @@ function CameraGridLayoutEditor({ deviceId }) {
|
|
|
17007
17024
|
}),
|
|
17008
17025
|
/* @__PURE__ */ jsxs("div", {
|
|
17009
17026
|
className: "grid grid-cols-4 gap-2 text-[10.5px]",
|
|
17010
|
-
children: [
|
|
17011
|
-
|
|
17012
|
-
|
|
17013
|
-
|
|
17014
|
-
|
|
17015
|
-
|
|
17016
|
-
|
|
17017
|
-
|
|
17018
|
-
|
|
17019
|
-
|
|
17020
|
-
|
|
17021
|
-
|
|
17022
|
-
|
|
17023
|
-
|
|
17024
|
-
|
|
17025
|
-
|
|
17026
|
-
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
|
|
17030
|
-
|
|
17031
|
-
|
|
17032
|
-
|
|
17033
|
-
|
|
17034
|
-
|
|
17035
|
-
|
|
17036
|
-
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17040
|
-
|
|
17041
|
-
/* @__PURE__ */
|
|
17042
|
-
|
|
17043
|
-
disabled: draft.cells.length >= MAX_CELLS,
|
|
17044
|
-
onClick: () => {
|
|
17045
|
-
const first = cameras.find((camera) => camera.id !== deviceId);
|
|
17046
|
-
if (!first) return;
|
|
17047
|
-
setDraft({
|
|
17048
|
-
...draft,
|
|
17049
|
-
cells: [...draft.cells, {
|
|
17050
|
-
deviceId: first.id,
|
|
17051
|
-
source: FULL_FRAME,
|
|
17052
|
-
cell: clampNormalizedRect({
|
|
17053
|
-
x: .1,
|
|
17054
|
-
y: .1,
|
|
17055
|
-
width: .4,
|
|
17056
|
-
height: .4
|
|
17057
|
-
})
|
|
17058
|
-
}]
|
|
17059
|
-
});
|
|
17060
|
-
setSelected(draft.cells.length);
|
|
17061
|
-
},
|
|
17062
|
-
className: "flex items-center justify-center gap-1 self-end rounded border border-border px-2 py-1 uppercase",
|
|
17063
|
-
children: [/* @__PURE__ */ jsx(Plus, { className: "h-3 w-3" }), " Cell"]
|
|
17064
|
-
})
|
|
17065
|
-
]
|
|
17027
|
+
children: [/* @__PURE__ */ jsx(LabelledNumber, {
|
|
17028
|
+
label: "FPS",
|
|
17029
|
+
value: draft.fps,
|
|
17030
|
+
onChange: (fps) => {
|
|
17031
|
+
setDraft({
|
|
17032
|
+
...draft,
|
|
17033
|
+
fps
|
|
17034
|
+
});
|
|
17035
|
+
}
|
|
17036
|
+
}), /* @__PURE__ */ jsxs("button", {
|
|
17037
|
+
type: "button",
|
|
17038
|
+
disabled: draft.cells.length >= MAX_CELLS,
|
|
17039
|
+
onClick: () => {
|
|
17040
|
+
const first = cameras.find((camera) => camera.id !== deviceId);
|
|
17041
|
+
if (!first) return;
|
|
17042
|
+
setDraft({
|
|
17043
|
+
...draft,
|
|
17044
|
+
cells: [...draft.cells, {
|
|
17045
|
+
deviceId: first.id,
|
|
17046
|
+
source: FULL_FRAME,
|
|
17047
|
+
cell: clampNormalizedRect({
|
|
17048
|
+
x: .1,
|
|
17049
|
+
y: .1,
|
|
17050
|
+
width: .4,
|
|
17051
|
+
height: .4
|
|
17052
|
+
})
|
|
17053
|
+
}]
|
|
17054
|
+
});
|
|
17055
|
+
setSelected(draft.cells.length);
|
|
17056
|
+
},
|
|
17057
|
+
className: "flex items-center justify-center gap-1 self-end rounded border border-border px-2 py-1 uppercase",
|
|
17058
|
+
children: [/* @__PURE__ */ jsx(Plus, { className: "h-3 w-3" }), " Cell"]
|
|
17059
|
+
})]
|
|
17066
17060
|
}),
|
|
17067
17061
|
/* @__PURE__ */ jsx(GridProfileReport, {
|
|
17068
17062
|
offers: loaded.profiles,
|
|
@@ -17110,7 +17104,11 @@ function GridProfileReport({ offers, cameras }) {
|
|
|
17110
17104
|
children: offer.profile
|
|
17111
17105
|
}), offer.offered ? /* @__PURE__ */ jsxs("span", {
|
|
17112
17106
|
className: "text-foreground-subtle",
|
|
17113
|
-
children: [
|
|
17107
|
+
children: [
|
|
17108
|
+
offer.canvas,
|
|
17109
|
+
" — composed from every source’s ",
|
|
17110
|
+
offer.profile
|
|
17111
|
+
]
|
|
17114
17112
|
}) : /* @__PURE__ */ jsx("span", {
|
|
17115
17113
|
className: "text-danger",
|
|
17116
17114
|
children: offer.missingSources.length === 0 ? "not offered — this grid has no cells yet" : `not offered — no ${offer.profile} on ${offer.missingSources.map(nameOf).join(", ")}`
|