@toolpath/dfm 0.1.0 → 0.2.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.
- package/README.md +122 -6
- package/dfm.css +3 -2
- package/dist/{reach-CfmYU_yQ.d.ts → feature-record-BUoFFjN6.d.ts} +89 -1
- package/dist/index.d.ts +254 -3
- package/dist/index.js +875 -17
- package/dist/model/index.d.ts +62 -43
- package/dist/model/index.js +276 -4
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
parseRuleSetFile,
|
|
24
24
|
peakHeight,
|
|
25
25
|
quantityUnit,
|
|
26
|
+
readReachCurve,
|
|
26
27
|
runStart,
|
|
27
28
|
serializeRuleSet,
|
|
28
29
|
subjectLabel,
|
|
@@ -800,14 +801,24 @@ var countLabel = (count, others) => {
|
|
|
800
801
|
};
|
|
801
802
|
|
|
802
803
|
// src/rule-list/rule-set-actions.tsx
|
|
803
|
-
import {
|
|
804
|
-
useCallback,
|
|
805
|
-
useEffect as useEffect2,
|
|
806
|
-
useRef as useRef3,
|
|
807
|
-
useState as useState6
|
|
808
|
-
} from "react";
|
|
804
|
+
import { useRef as useRef3 } from "react";
|
|
809
805
|
import { CheckIcon, CopyIcon, DownloadSimpleIcon, UploadSimpleIcon } from "@phosphor-icons/react";
|
|
810
806
|
import { Button, cn as cn8 } from "@toolpath/ui";
|
|
807
|
+
|
|
808
|
+
// src/rule-list/use-timed-value.ts
|
|
809
|
+
import { useCallback, useEffect as useEffect2, useState as useState6 } from "react";
|
|
810
|
+
var useTimedValue = (ms) => {
|
|
811
|
+
const [box, setBox] = useState6(null);
|
|
812
|
+
useEffect2(() => {
|
|
813
|
+
if (box === null) return;
|
|
814
|
+
const timer = setTimeout(() => setBox(null), ms);
|
|
815
|
+
return () => clearTimeout(timer);
|
|
816
|
+
}, [box, ms]);
|
|
817
|
+
const set = useCallback((value) => setBox({ value }), []);
|
|
818
|
+
return [box?.value ?? null, set];
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
// src/rule-list/rule-set-actions.tsx
|
|
811
822
|
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
812
823
|
var NOTE_MS = 4e3;
|
|
813
824
|
var COPIED_MS = 2e3;
|
|
@@ -888,16 +899,6 @@ var ActionLabel = ({ icon, children, hidden = false }) => /* @__PURE__ */ jsxs10
|
|
|
888
899
|
]
|
|
889
900
|
}
|
|
890
901
|
);
|
|
891
|
-
var useTimedValue = (ms) => {
|
|
892
|
-
const [box, setBox] = useState6(null);
|
|
893
|
-
useEffect2(() => {
|
|
894
|
-
if (box === null) return;
|
|
895
|
-
const timer = setTimeout(() => setBox(null), ms);
|
|
896
|
-
return () => clearTimeout(timer);
|
|
897
|
-
}, [box, ms]);
|
|
898
|
-
const set = useCallback((value) => setBox({ value }), []);
|
|
899
|
-
return [box?.value ?? null, set];
|
|
900
|
-
};
|
|
901
902
|
var downloadRuleSet = (rules) => {
|
|
902
903
|
const url = URL.createObjectURL(
|
|
903
904
|
new Blob([serializeRuleSet(rules.rules)], { type: "application/json" })
|
|
@@ -1617,12 +1618,869 @@ var ReachDrawing = ({ curve, units, feature }) => {
|
|
|
1617
1618
|
] })
|
|
1618
1619
|
] });
|
|
1619
1620
|
};
|
|
1621
|
+
|
|
1622
|
+
// src/feature-panel/fold-store.ts
|
|
1623
|
+
var storageFolds = (storage, prefix) => ({
|
|
1624
|
+
read: (id) => {
|
|
1625
|
+
try {
|
|
1626
|
+
const stored = storage?.getItem(`${prefix}${id}`);
|
|
1627
|
+
return stored === "open" ? true : stored === "shut" ? false : void 0;
|
|
1628
|
+
} catch {
|
|
1629
|
+
return void 0;
|
|
1630
|
+
}
|
|
1631
|
+
},
|
|
1632
|
+
write: (id, open) => {
|
|
1633
|
+
try {
|
|
1634
|
+
storage?.setItem(`${prefix}${id}`, open ? "open" : "shut");
|
|
1635
|
+
} catch {
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
});
|
|
1639
|
+
|
|
1640
|
+
// src/feature-panel/feature-details.tsx
|
|
1641
|
+
import { useCallback as useCallback2, useMemo as useMemo7, useState as useState12 } from "react";
|
|
1642
|
+
import { CrosshairIcon, InfoIcon } from "@phosphor-icons/react";
|
|
1643
|
+
import { Button as Button3, Tooltip, cn as cn12 } from "@toolpath/ui";
|
|
1644
|
+
|
|
1645
|
+
// src/feature-panel/feature-name.tsx
|
|
1646
|
+
import { cn as cn9 } from "@toolpath/ui";
|
|
1647
|
+
|
|
1648
|
+
// src/feature-panel/look.ts
|
|
1649
|
+
var resolveLook = (look) => ({
|
|
1650
|
+
rules: look?.rules ?? "sentence",
|
|
1651
|
+
selected: look?.selected ?? "grey",
|
|
1652
|
+
muted: look?.muted ?? "pale"
|
|
1653
|
+
});
|
|
1654
|
+
var secondaryText = (look) => look.muted === "strong" ? "text-gray dark:text-zinc-300" : "text-gray-400 dark:text-zinc-400";
|
|
1655
|
+
var faintText = (look) => look.muted === "strong" ? "text-gray dark:text-zinc-300" : "text-gray-300 dark:text-zinc-500";
|
|
1656
|
+
|
|
1657
|
+
// src/feature-panel/feature-name.tsx
|
|
1658
|
+
import { Fragment as Fragment7, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1659
|
+
var FeatureName = ({ feature, label, look }) => /* @__PURE__ */ jsxs16(Fragment7, { children: [
|
|
1660
|
+
label ?? featureTypeLabel(feature.featureType),
|
|
1661
|
+
" ",
|
|
1662
|
+
/* @__PURE__ */ jsxs16("span", { className: cn9("font-normal", faintText(look)), children: [
|
|
1663
|
+
"from ",
|
|
1664
|
+
directionLabel(feature.machiningDirection)
|
|
1665
|
+
] })
|
|
1666
|
+
] });
|
|
1667
|
+
var RequiredBadge = () => /* @__PURE__ */ jsx18("span", { className: "rounded-full bg-gray-100 px-1.5 text-2xs font-semibold text-gray-500 uppercase dark:bg-zinc-800 dark:text-zinc-300", children: "Required" });
|
|
1668
|
+
|
|
1669
|
+
// src/feature-panel/fold-section.tsx
|
|
1670
|
+
import { useState as useState10 } from "react";
|
|
1671
|
+
import { CaretRightIcon as CaretRightIcon3 } from "@phosphor-icons/react";
|
|
1672
|
+
import { cn as cn10 } from "@toolpath/ui";
|
|
1673
|
+
import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1674
|
+
var FoldSection = ({
|
|
1675
|
+
id,
|
|
1676
|
+
title: title2,
|
|
1677
|
+
action,
|
|
1678
|
+
defaultOpen = true,
|
|
1679
|
+
folds,
|
|
1680
|
+
className,
|
|
1681
|
+
children
|
|
1682
|
+
}) => {
|
|
1683
|
+
const [open, setOpen] = useState10(() => folds?.read(id) ?? defaultOpen);
|
|
1684
|
+
return /* @__PURE__ */ jsxs17("section", { className: cn10("flex flex-col gap-1", className), children: [
|
|
1685
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-1", children: [
|
|
1686
|
+
/* @__PURE__ */ jsxs17(
|
|
1687
|
+
"button",
|
|
1688
|
+
{
|
|
1689
|
+
type: "button",
|
|
1690
|
+
"aria-expanded": open,
|
|
1691
|
+
onClick: () => {
|
|
1692
|
+
setOpen(!open);
|
|
1693
|
+
folds?.write(id, !open);
|
|
1694
|
+
},
|
|
1695
|
+
className: cn10(
|
|
1696
|
+
"flex min-w-0 flex-1 cursor-pointer items-center gap-1 rounded text-left text-2xs font-semibold text-gray-400 uppercase",
|
|
1697
|
+
"hover:text-gray-600 dark:text-zinc-500 dark:hover:text-zinc-300",
|
|
1698
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-info/75"
|
|
1699
|
+
),
|
|
1700
|
+
children: [
|
|
1701
|
+
/* @__PURE__ */ jsx19(
|
|
1702
|
+
CaretRightIcon3,
|
|
1703
|
+
{
|
|
1704
|
+
weight: "bold",
|
|
1705
|
+
className: cn10("size-3 shrink-0 transition-transform duration-150", open && "rotate-90")
|
|
1706
|
+
}
|
|
1707
|
+
),
|
|
1708
|
+
/* @__PURE__ */ jsx19("span", { className: "truncate", children: title2 })
|
|
1709
|
+
]
|
|
1710
|
+
}
|
|
1711
|
+
),
|
|
1712
|
+
action
|
|
1713
|
+
] }),
|
|
1714
|
+
open ? children : null
|
|
1715
|
+
] });
|
|
1716
|
+
};
|
|
1717
|
+
|
|
1718
|
+
// src/feature-panel/read-state.tsx
|
|
1719
|
+
import { useEffect as useEffect3, useState as useState11 } from "react";
|
|
1720
|
+
import { Button as Button2 } from "@toolpath/ui";
|
|
1721
|
+
import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1722
|
+
var Reading = ({ children }) => /* @__PURE__ */ jsx20("p", { className: "text-sm text-gray-400 dark:text-zinc-400", role: "status", children });
|
|
1723
|
+
var ReadFailure = ({
|
|
1724
|
+
failure
|
|
1725
|
+
}) => {
|
|
1726
|
+
const waiting = useWaiting(failure.retryAt);
|
|
1727
|
+
return /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-start gap-2 text-sm", children: [
|
|
1728
|
+
/* @__PURE__ */ jsx20("p", { className: "text-danger", role: "alert", children: failure.message }),
|
|
1729
|
+
failure.retry ? /* @__PURE__ */ jsx20(Button2, { variant: "secondary", size: "sm", disabled: waiting, onClick: failure.retry, children: "Retry" }) : null
|
|
1730
|
+
] });
|
|
1731
|
+
};
|
|
1732
|
+
var useWaiting = (until) => {
|
|
1733
|
+
const [passed, setPassed] = useState11(void 0);
|
|
1734
|
+
useEffect3(() => {
|
|
1735
|
+
if (until === void 0) return;
|
|
1736
|
+
const timer = setTimeout(() => setPassed(until), Math.max(until - Date.now(), 0));
|
|
1737
|
+
return () => clearTimeout(timer);
|
|
1738
|
+
}, [until]);
|
|
1739
|
+
return until !== void 0 && passed !== until;
|
|
1740
|
+
};
|
|
1741
|
+
|
|
1742
|
+
// src/feature-panel/pop-outs.tsx
|
|
1743
|
+
import { useMemo as useMemo6 } from "react";
|
|
1744
|
+
import {
|
|
1745
|
+
ArrowSquareOutIcon,
|
|
1746
|
+
BracketsCurlyIcon,
|
|
1747
|
+
ChartLineIcon,
|
|
1748
|
+
TableIcon
|
|
1749
|
+
} from "@phosphor-icons/react";
|
|
1750
|
+
import { IconButton as IconButton3 } from "@toolpath/ui";
|
|
1751
|
+
|
|
1752
|
+
// src/feature-panel/record-sections.tsx
|
|
1753
|
+
import { useMemo as useMemo5 } from "react";
|
|
1754
|
+
import { CheckIcon as CheckIcon2, CopyIcon as CopyIcon2 } from "@phosphor-icons/react";
|
|
1755
|
+
import { IconButton as IconButton2, cn as cn11 } from "@toolpath/ui";
|
|
1756
|
+
|
|
1757
|
+
// src/model/feature-record.ts
|
|
1758
|
+
var MAX_DATASHEET_FIELDS = 500;
|
|
1759
|
+
var formatLeaf = (value) => typeof value === "number" ? String(Number(value.toFixed(4))) : typeof value === "string" ? value : value === null ? "null" : String(value);
|
|
1760
|
+
var datasheetFields = (datasheet) => {
|
|
1761
|
+
const fields = [];
|
|
1762
|
+
let more = false;
|
|
1763
|
+
const walk = (value, path) => {
|
|
1764
|
+
if (fields.length >= MAX_DATASHEET_FIELDS) {
|
|
1765
|
+
more = true;
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
if (Array.isArray(value)) {
|
|
1769
|
+
if (value.every((each) => typeof each !== "object" || each === null)) {
|
|
1770
|
+
fields.push({ path, value: value.length === 0 ? "[]" : value.map(formatLeaf).join(", ") });
|
|
1771
|
+
} else {
|
|
1772
|
+
value.forEach((each, index) => walk(each, `${path}[${index}]`));
|
|
1773
|
+
}
|
|
1774
|
+
} else if (typeof value === "object" && value !== null) {
|
|
1775
|
+
const entries = Object.entries(value);
|
|
1776
|
+
if (entries.length === 0) fields.push({ path, value: "{}" });
|
|
1777
|
+
for (const [key, each] of entries) walk(each, path ? `${path}.${key}` : key);
|
|
1778
|
+
} else {
|
|
1779
|
+
fields.push({ path, value: formatLeaf(value) });
|
|
1780
|
+
}
|
|
1781
|
+
};
|
|
1782
|
+
if (datasheet !== null && datasheet !== void 0) walk(datasheet, "");
|
|
1783
|
+
return { fields, more };
|
|
1784
|
+
};
|
|
1785
|
+
|
|
1786
|
+
// src/feature-panel/record-sections.tsx
|
|
1787
|
+
import { Fragment as Fragment8, jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1788
|
+
var COPIED_MS2 = 1500;
|
|
1789
|
+
var RecordSections = ({
|
|
1790
|
+
record,
|
|
1791
|
+
look,
|
|
1792
|
+
folds,
|
|
1793
|
+
popOut
|
|
1794
|
+
}) => {
|
|
1795
|
+
const value = record.status === "ready" ? record.value : null;
|
|
1796
|
+
const { fields, more } = useMemo5(() => datasheetFields(value?.datasheet), [value]);
|
|
1797
|
+
const json = useMemo5(() => value ? JSON.stringify(value, null, 2) : "", [value]);
|
|
1798
|
+
if (record.status === "ready" && !value) return null;
|
|
1799
|
+
const waiting = record.status === "loading" ? /* @__PURE__ */ jsx21(Reading, { children: "Reading the feature\u2019s record\u2026" }) : record.status === "error" ? /* @__PURE__ */ jsx21(ReadFailure, { failure: record }) : null;
|
|
1800
|
+
const count = more ? `${MAX_DATASHEET_FIELDS}+` : String(fields.length);
|
|
1801
|
+
return /* @__PURE__ */ jsxs19(Fragment8, { children: [
|
|
1802
|
+
/* @__PURE__ */ jsx21(
|
|
1803
|
+
FoldSection,
|
|
1804
|
+
{
|
|
1805
|
+
id: "datasheet",
|
|
1806
|
+
defaultOpen: false,
|
|
1807
|
+
title: value ? `All datasheet fields (${count})` : "All datasheet fields",
|
|
1808
|
+
action: value ? popOut?.("datasheet") : null,
|
|
1809
|
+
folds,
|
|
1810
|
+
children: waiting ?? /* @__PURE__ */ jsx21(DatasheetFields, { record: value, look })
|
|
1811
|
+
}
|
|
1812
|
+
),
|
|
1813
|
+
/* @__PURE__ */ jsx21(
|
|
1814
|
+
FoldSection,
|
|
1815
|
+
{
|
|
1816
|
+
id: "raw",
|
|
1817
|
+
defaultOpen: false,
|
|
1818
|
+
title: "Raw API record",
|
|
1819
|
+
action: value ? /* @__PURE__ */ jsxs19(Fragment8, { children: [
|
|
1820
|
+
/* @__PURE__ */ jsx21(CopyButton, { text: json }),
|
|
1821
|
+
popOut?.("raw")
|
|
1822
|
+
] }) : null,
|
|
1823
|
+
folds,
|
|
1824
|
+
children: waiting ?? /* @__PURE__ */ jsx21(RawRecord, { json })
|
|
1825
|
+
}
|
|
1826
|
+
)
|
|
1827
|
+
] });
|
|
1828
|
+
};
|
|
1829
|
+
var DatasheetFields = ({ record, look, wide = false }) => {
|
|
1830
|
+
const { fields } = useMemo5(() => datasheetFields(record?.datasheet), [record]);
|
|
1831
|
+
return record?.datasheet ? /* @__PURE__ */ jsx21(
|
|
1832
|
+
"dl",
|
|
1833
|
+
{
|
|
1834
|
+
className: cn11(
|
|
1835
|
+
"grid grid-cols-[minmax(0,1fr)_auto] gap-y-0.5 text-xs",
|
|
1836
|
+
wide ? "gap-x-4 p-4" : "gap-x-3"
|
|
1837
|
+
),
|
|
1838
|
+
children: fields.map((field) => /* @__PURE__ */ jsxs19("div", { className: "contents", children: [
|
|
1839
|
+
/* @__PURE__ */ jsx21("dt", { className: cn11("truncate font-mono", secondaryText(look)), title: field.path, children: field.path }),
|
|
1840
|
+
/* @__PURE__ */ jsx21(
|
|
1841
|
+
"dd",
|
|
1842
|
+
{
|
|
1843
|
+
className: cn11(
|
|
1844
|
+
"truncate text-right font-mono text-gray-600 tabular-nums select-text dark:text-zinc-100",
|
|
1845
|
+
wide ? "max-w-60" : "max-w-40"
|
|
1846
|
+
),
|
|
1847
|
+
title: field.value,
|
|
1848
|
+
children: field.value
|
|
1849
|
+
}
|
|
1850
|
+
)
|
|
1851
|
+
] }, field.path))
|
|
1852
|
+
}
|
|
1853
|
+
) : /* @__PURE__ */ jsx21("p", { className: cn11("text-sm", secondaryText(look), wide && "p-4"), children: "The API sent no datasheet for this feature." });
|
|
1854
|
+
};
|
|
1855
|
+
var RawRecord = ({
|
|
1856
|
+
json,
|
|
1857
|
+
wide = false
|
|
1858
|
+
}) => /* @__PURE__ */ jsx21(
|
|
1859
|
+
"pre",
|
|
1860
|
+
{
|
|
1861
|
+
className: cn11(
|
|
1862
|
+
"font-mono text-2xs leading-relaxed text-gray-600 select-text dark:text-zinc-200",
|
|
1863
|
+
wide ? "p-4" : "max-h-80 overflow-auto rounded bg-gray-50 p-2 dark:bg-zinc-800/60"
|
|
1864
|
+
),
|
|
1865
|
+
children: json
|
|
1866
|
+
}
|
|
1867
|
+
);
|
|
1868
|
+
var CopyButton = ({ text }) => {
|
|
1869
|
+
const [copied, setCopied] = useTimedValue(COPIED_MS2);
|
|
1870
|
+
return /* @__PURE__ */ jsx21(
|
|
1871
|
+
IconButton2,
|
|
1872
|
+
{
|
|
1873
|
+
"aria-label": copied ? "Copied" : "Copy raw record",
|
|
1874
|
+
title: "Copy",
|
|
1875
|
+
variant: "muted",
|
|
1876
|
+
size: "sm",
|
|
1877
|
+
onClick: () => {
|
|
1878
|
+
void navigator.clipboard?.writeText(text).then(() => setCopied(true)).catch(() => void 0);
|
|
1879
|
+
},
|
|
1880
|
+
children: copied ? /* @__PURE__ */ jsx21(CheckIcon2, { weight: "bold" }) : /* @__PURE__ */ jsx21(CopyIcon2, { weight: "bold" })
|
|
1881
|
+
}
|
|
1882
|
+
);
|
|
1883
|
+
};
|
|
1884
|
+
|
|
1885
|
+
// src/feature-panel/pop-outs.tsx
|
|
1886
|
+
import { Fragment as Fragment9, jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1887
|
+
var TITLES = {
|
|
1888
|
+
reach: "Reach",
|
|
1889
|
+
datasheet: "All datasheet fields",
|
|
1890
|
+
raw: "Raw API record"
|
|
1891
|
+
};
|
|
1892
|
+
var LABELS = {
|
|
1893
|
+
reach: "Pop out the reach drawing",
|
|
1894
|
+
datasheet: "Pop out the datasheet fields",
|
|
1895
|
+
raw: "Pop out the raw record"
|
|
1896
|
+
};
|
|
1897
|
+
var PopOutButton = ({
|
|
1898
|
+
id,
|
|
1899
|
+
onOpen
|
|
1900
|
+
}) => /* @__PURE__ */ jsx22(
|
|
1901
|
+
IconButton3,
|
|
1902
|
+
{
|
|
1903
|
+
"aria-label": LABELS[id],
|
|
1904
|
+
title: "Pop out, larger",
|
|
1905
|
+
variant: "muted",
|
|
1906
|
+
size: "sm",
|
|
1907
|
+
onClick: () => onOpen(id),
|
|
1908
|
+
children: /* @__PURE__ */ jsx22(ArrowSquareOutIcon, { weight: "bold" })
|
|
1909
|
+
}
|
|
1910
|
+
);
|
|
1911
|
+
var PopOuts = ({
|
|
1912
|
+
open,
|
|
1913
|
+
onClose,
|
|
1914
|
+
Window,
|
|
1915
|
+
subtitle,
|
|
1916
|
+
record,
|
|
1917
|
+
units,
|
|
1918
|
+
profile,
|
|
1919
|
+
look
|
|
1920
|
+
}) => {
|
|
1921
|
+
const curve = useMemo6(() => readReachCurve(record?.datasheet), [record]);
|
|
1922
|
+
const json = useMemo6(() => record ? JSON.stringify(record, null, 2) : "", [record]);
|
|
1923
|
+
if (!record) return null;
|
|
1924
|
+
return /* @__PURE__ */ jsxs20(Fragment9, { children: [
|
|
1925
|
+
open.has("reach") && curve ? /* @__PURE__ */ jsx22(
|
|
1926
|
+
Window,
|
|
1927
|
+
{
|
|
1928
|
+
id: "reach",
|
|
1929
|
+
title: TITLES.reach,
|
|
1930
|
+
subtitle,
|
|
1931
|
+
icon: /* @__PURE__ */ jsx22(ChartLineIcon, { weight: "bold" }),
|
|
1932
|
+
onClose: () => onClose("reach"),
|
|
1933
|
+
children: /* @__PURE__ */ jsx22(ReachDrawing, { curve, units, feature: profile })
|
|
1934
|
+
}
|
|
1935
|
+
) : null,
|
|
1936
|
+
open.has("datasheet") ? /* @__PURE__ */ jsx22(
|
|
1937
|
+
Window,
|
|
1938
|
+
{
|
|
1939
|
+
id: "datasheet",
|
|
1940
|
+
title: TITLES.datasheet,
|
|
1941
|
+
subtitle,
|
|
1942
|
+
icon: /* @__PURE__ */ jsx22(TableIcon, { weight: "bold" }),
|
|
1943
|
+
onClose: () => onClose("datasheet"),
|
|
1944
|
+
children: /* @__PURE__ */ jsx22(DatasheetFields, { record, look, wide: true })
|
|
1945
|
+
}
|
|
1946
|
+
) : null,
|
|
1947
|
+
open.has("raw") ? /* @__PURE__ */ jsx22(
|
|
1948
|
+
Window,
|
|
1949
|
+
{
|
|
1950
|
+
id: "raw",
|
|
1951
|
+
title: TITLES.raw,
|
|
1952
|
+
subtitle,
|
|
1953
|
+
icon: /* @__PURE__ */ jsx22(BracketsCurlyIcon, { weight: "bold" }),
|
|
1954
|
+
action: /* @__PURE__ */ jsx22(CopyButton, { text: json }),
|
|
1955
|
+
onClose: () => onClose("raw"),
|
|
1956
|
+
children: /* @__PURE__ */ jsx22(RawRecord, { json, wide: true })
|
|
1957
|
+
}
|
|
1958
|
+
) : null
|
|
1959
|
+
] });
|
|
1960
|
+
};
|
|
1961
|
+
|
|
1962
|
+
// src/feature-panel/feature-details.tsx
|
|
1963
|
+
import { Fragment as Fragment10, jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1964
|
+
var FeatureDetails = ({
|
|
1965
|
+
feature,
|
|
1966
|
+
units,
|
|
1967
|
+
directionColor,
|
|
1968
|
+
profile,
|
|
1969
|
+
label,
|
|
1970
|
+
required,
|
|
1971
|
+
onFrame,
|
|
1972
|
+
actions,
|
|
1973
|
+
status,
|
|
1974
|
+
children,
|
|
1975
|
+
rules,
|
|
1976
|
+
measurements,
|
|
1977
|
+
record,
|
|
1978
|
+
PopOut,
|
|
1979
|
+
look: lookOption,
|
|
1980
|
+
folds
|
|
1981
|
+
}) => {
|
|
1982
|
+
const look = resolveLook(lookOption);
|
|
1983
|
+
const name = /* @__PURE__ */ jsx23(FeatureName, { feature, label, look });
|
|
1984
|
+
const [out, setOut] = useState12(/* @__PURE__ */ new Set());
|
|
1985
|
+
const openOut = useCallback2((id) => setOut((was) => new Set(was).add(id)), []);
|
|
1986
|
+
const closeOut = useCallback2(
|
|
1987
|
+
(id) => setOut((was) => {
|
|
1988
|
+
const next = new Set(was);
|
|
1989
|
+
next.delete(id);
|
|
1990
|
+
return next;
|
|
1991
|
+
}),
|
|
1992
|
+
[]
|
|
1993
|
+
);
|
|
1994
|
+
const popOut = PopOut ? (id) => /* @__PURE__ */ jsx23(PopOutButton, { id, onOpen: openOut }) : void 0;
|
|
1995
|
+
return /* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-4 p-4", children: [
|
|
1996
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-2", children: [
|
|
1997
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex items-start gap-2", children: [
|
|
1998
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
|
|
1999
|
+
/* @__PURE__ */ jsx23("h3", { className: "truncate text-sm font-semibold text-gray-600 dark:text-zinc-100", children: name }),
|
|
2000
|
+
/* @__PURE__ */ jsxs21("p", { className: cn12("flex flex-wrap items-center gap-1.5 text-xs", secondaryText(look)), children: [
|
|
2001
|
+
/* @__PURE__ */ jsx23(Swatch, { color: directionColor, className: "size-2.5" }),
|
|
2002
|
+
"Machined from ",
|
|
2003
|
+
directionLabel(feature.machiningDirection),
|
|
2004
|
+
required ? /* @__PURE__ */ jsx23(RequiredBadge, {}) : null,
|
|
2005
|
+
status
|
|
2006
|
+
] })
|
|
2007
|
+
] }),
|
|
2008
|
+
actions,
|
|
2009
|
+
onFrame ? /* @__PURE__ */ jsx23(Button3, { variant: "secondary", size: "sm", onClick: onFrame, className: "shrink-0", children: /* @__PURE__ */ jsxs21("span", { className: "flex items-center gap-1 whitespace-nowrap", children: [
|
|
2010
|
+
/* @__PURE__ */ jsx23(CrosshairIcon, { weight: "bold", className: "size-3.5" }),
|
|
2011
|
+
"Show this feature"
|
|
2012
|
+
] }) }) : null
|
|
2013
|
+
] }),
|
|
2014
|
+
children
|
|
2015
|
+
] }),
|
|
2016
|
+
/* @__PURE__ */ jsx23(FoldSection, { id: "rules", title: "Rules broken", folds, children: /* @__PURE__ */ jsx23(BrokenRuleList, { rules, look }) }),
|
|
2017
|
+
/* @__PURE__ */ jsx23(MeasurementSections, { measurements, look, folds }),
|
|
2018
|
+
/* @__PURE__ */ jsx23(
|
|
2019
|
+
ReachSection2,
|
|
2020
|
+
{
|
|
2021
|
+
record,
|
|
2022
|
+
units,
|
|
2023
|
+
profile,
|
|
2024
|
+
folds,
|
|
2025
|
+
action: popOut?.("reach")
|
|
2026
|
+
}
|
|
2027
|
+
),
|
|
2028
|
+
/* @__PURE__ */ jsx23(RecordSections, { record, look, folds, popOut }),
|
|
2029
|
+
PopOut ? /* @__PURE__ */ jsx23(
|
|
2030
|
+
PopOuts,
|
|
2031
|
+
{
|
|
2032
|
+
open: out,
|
|
2033
|
+
onClose: closeOut,
|
|
2034
|
+
Window: PopOut,
|
|
2035
|
+
subtitle: name,
|
|
2036
|
+
record: record.status === "ready" ? record.value : null,
|
|
2037
|
+
units,
|
|
2038
|
+
profile,
|
|
2039
|
+
look
|
|
2040
|
+
}
|
|
2041
|
+
) : null
|
|
2042
|
+
] });
|
|
2043
|
+
};
|
|
2044
|
+
var BrokenRuleList = ({
|
|
2045
|
+
rules,
|
|
2046
|
+
look
|
|
2047
|
+
}) => rules.length > 0 ? /* @__PURE__ */ jsx23("ul", { className: "flex flex-col gap-1", children: rules.map((rule) => /* @__PURE__ */ jsxs21(
|
|
2048
|
+
"li",
|
|
2049
|
+
{
|
|
2050
|
+
className: "flex items-start gap-2 text-sm text-gray-600 dark:text-zinc-100",
|
|
2051
|
+
children: [
|
|
2052
|
+
/* @__PURE__ */ jsx23(Swatch, { color: rule.color, className: "mt-0.5" }),
|
|
2053
|
+
/* @__PURE__ */ jsx23(Explained, { note: rule.note, children: /* @__PURE__ */ jsx23("span", { className: "min-w-0 flex-1", children: rule.text }) }),
|
|
2054
|
+
rule.figure ? /* @__PURE__ */ jsxs21(
|
|
2055
|
+
"span",
|
|
2056
|
+
{
|
|
2057
|
+
className: cn12(
|
|
2058
|
+
"shrink-0 tabular-nums",
|
|
2059
|
+
look.rules === "result" ? "font-semibold" : secondaryText(look)
|
|
2060
|
+
),
|
|
2061
|
+
style: look.rules === "result" ? { color: rule.color } : void 0,
|
|
2062
|
+
children: [
|
|
2063
|
+
rule.figure,
|
|
2064
|
+
look.rules === "result" && rule.limit ? /* @__PURE__ */ jsx23("span", { className: "ml-1 font-normal opacity-60", children: rule.limit }) : null
|
|
2065
|
+
]
|
|
2066
|
+
}
|
|
2067
|
+
) : null
|
|
2068
|
+
]
|
|
2069
|
+
},
|
|
2070
|
+
rule.key
|
|
2071
|
+
)) }) : /* @__PURE__ */ jsx23(None, { look });
|
|
2072
|
+
var Explained = ({ note, children }) => note ? /* @__PURE__ */ jsx23(Tooltip, { tip: note, side: "left", children: /* @__PURE__ */ jsx23(
|
|
2073
|
+
"span",
|
|
2074
|
+
{
|
|
2075
|
+
tabIndex: 0,
|
|
2076
|
+
className: "min-w-0 flex-1 rounded outline-none focus-visible:ring-2 focus-visible:ring-info/75",
|
|
2077
|
+
children
|
|
2078
|
+
}
|
|
2079
|
+
) }) : children;
|
|
2080
|
+
var None = ({ look }) => /* @__PURE__ */ jsx23("p", { className: cn12("text-sm", secondaryText(look)), children: "None" });
|
|
2081
|
+
var MeasurementSections = ({ measurements, look, folds }) => {
|
|
2082
|
+
if (measurements.status !== "ready") {
|
|
2083
|
+
return /* @__PURE__ */ jsx23(Fragment10, { children: /* @__PURE__ */ jsx23(FoldSection, { id: "measurements", title: "Measurements", folds, children: measurements.status === "loading" ? /* @__PURE__ */ jsx23(Reading, { children: "Reading the feature\u2019s datasheet\u2026" }) : /* @__PURE__ */ jsx23(ReadFailure, { failure: measurements }) }) });
|
|
2084
|
+
}
|
|
2085
|
+
const measured = measurements.value.filter((row) => !row.milling);
|
|
2086
|
+
const milling = measurements.value.filter((row) => row.milling);
|
|
2087
|
+
return /* @__PURE__ */ jsxs21(Fragment10, { children: [
|
|
2088
|
+
/* @__PURE__ */ jsx23(FoldSection, { id: "measurements", title: "Measurements", folds, children: /* @__PURE__ */ jsx23(MeasurementList, { rows: measured, look }) }),
|
|
2089
|
+
milling.length > 0 ? /* @__PURE__ */ jsx23(FoldSection, { id: "milling", title: "Milling considerations", folds, children: /* @__PURE__ */ jsx23(MeasurementList, { rows: milling, look }) }) : null
|
|
2090
|
+
] });
|
|
2091
|
+
};
|
|
2092
|
+
var MeasurementList = ({ rows, look }) => rows.length > 0 ? /* @__PURE__ */ jsx23("dl", { className: "grid grid-cols-[1fr_auto] items-center gap-x-3 gap-y-1 text-sm", children: rows.map((row) => /* @__PURE__ */ jsxs21("div", { className: "contents", children: [
|
|
2093
|
+
/* @__PURE__ */ jsxs21("dt", { className: cn12("flex items-center gap-1", secondaryText(look)), children: [
|
|
2094
|
+
row.label,
|
|
2095
|
+
/* @__PURE__ */ jsx23(Derivation, { lines: row.derivation, look })
|
|
2096
|
+
] }),
|
|
2097
|
+
/* @__PURE__ */ jsx23("dd", { className: "text-right text-gray-600 tabular-nums dark:text-zinc-100", title: row.alt, children: row.value })
|
|
2098
|
+
] }, row.key)) }) : /* @__PURE__ */ jsx23(None, { look });
|
|
2099
|
+
var Derivation = ({
|
|
2100
|
+
lines,
|
|
2101
|
+
look
|
|
2102
|
+
}) => lines.length > 0 ? /* @__PURE__ */ jsx23(
|
|
2103
|
+
Tooltip,
|
|
2104
|
+
{
|
|
2105
|
+
side: "left",
|
|
2106
|
+
hoverable: true,
|
|
2107
|
+
tip: /* @__PURE__ */ jsx23("div", { className: "flex max-w-sm flex-col gap-0.5 font-mono text-2xs leading-snug whitespace-pre-wrap", children: lines.map((line, index) => /* @__PURE__ */ jsx23("span", { children: line }, index)) }),
|
|
2108
|
+
children: /* @__PURE__ */ jsx23(
|
|
2109
|
+
"button",
|
|
2110
|
+
{
|
|
2111
|
+
type: "button",
|
|
2112
|
+
"aria-label": "How this was measured",
|
|
2113
|
+
className: cn12(
|
|
2114
|
+
"shrink-0 rounded outline-none hover:text-gray-500 focus-visible:ring-2 focus-visible:ring-info/75 dark:hover:text-zinc-300",
|
|
2115
|
+
faintText(look)
|
|
2116
|
+
),
|
|
2117
|
+
children: /* @__PURE__ */ jsx23(InfoIcon, { weight: "bold", className: "size-3" })
|
|
2118
|
+
}
|
|
2119
|
+
)
|
|
2120
|
+
}
|
|
2121
|
+
) : null;
|
|
2122
|
+
var ReachSection2 = ({ record, units, profile, folds, action }) => {
|
|
2123
|
+
const curve = useMemo7(
|
|
2124
|
+
() => record.status === "ready" ? readReachCurve(record.value?.datasheet) : null,
|
|
2125
|
+
[record]
|
|
2126
|
+
);
|
|
2127
|
+
if (record.status === "ready" && !curve) return null;
|
|
2128
|
+
return /* @__PURE__ */ jsx23(FoldSection, { id: "reach", title: "Reach", folds, action: curve ? action : null, children: record.status === "loading" ? /* @__PURE__ */ jsx23(Reading, { children: "Reading the reach curve\u2026" }) : record.status === "error" ? /* @__PURE__ */ jsx23(ReadFailure, { failure: record }) : curve ? /* @__PURE__ */ jsx23(ReachChart, { curve, units, feature: profile }) : null });
|
|
2129
|
+
};
|
|
2130
|
+
|
|
2131
|
+
// src/feature-panel/candidate-list.tsx
|
|
2132
|
+
import { XIcon } from "@phosphor-icons/react";
|
|
2133
|
+
import { IconButton as IconButton4, cn as cn13 } from "@toolpath/ui";
|
|
2134
|
+
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2135
|
+
var candidateListKeys = listKeys("candidates");
|
|
2136
|
+
var faceLetter = (index) => String.fromCharCode(65 + index % 26);
|
|
2137
|
+
var FaceLetter = ({
|
|
2138
|
+
index,
|
|
2139
|
+
active
|
|
2140
|
+
}) => /* @__PURE__ */ jsx24(
|
|
2141
|
+
"span",
|
|
2142
|
+
{
|
|
2143
|
+
className: cn13(
|
|
2144
|
+
"inline-flex size-4 shrink-0 items-center justify-center rounded-sm text-2xs font-bold",
|
|
2145
|
+
active ? "bg-info text-white" : "bg-gray-100 text-gray-500 dark:bg-zinc-800 dark:text-zinc-300"
|
|
2146
|
+
),
|
|
2147
|
+
children: faceLetter(index)
|
|
2148
|
+
}
|
|
2149
|
+
);
|
|
2150
|
+
var CandidateList = ({
|
|
2151
|
+
rows,
|
|
2152
|
+
selected,
|
|
2153
|
+
onSelect,
|
|
2154
|
+
onHover,
|
|
2155
|
+
face,
|
|
2156
|
+
look: lookOption,
|
|
2157
|
+
folds
|
|
2158
|
+
}) => {
|
|
2159
|
+
const look = resolveLook(lookOption);
|
|
2160
|
+
const count = `Candidate features (${rows.length})`;
|
|
2161
|
+
return /* @__PURE__ */ jsx24("div", { className: "border-b border-gray-100 p-2 dark:border-zinc-800", children: /* @__PURE__ */ jsx24(
|
|
2162
|
+
FoldSection,
|
|
2163
|
+
{
|
|
2164
|
+
id: face ? `candidates-${faceLetter(face.index)}` : "candidates",
|
|
2165
|
+
title: face ? /* @__PURE__ */ jsxs22("span", { className: "flex items-center gap-1.5", children: [
|
|
2166
|
+
/* @__PURE__ */ jsx24(FaceLetter, { index: face.index, active: face.active }),
|
|
2167
|
+
count
|
|
2168
|
+
] }) : count,
|
|
2169
|
+
action: face?.onStop ? /* @__PURE__ */ jsx24(
|
|
2170
|
+
IconButton4,
|
|
2171
|
+
{
|
|
2172
|
+
"aria-label": `Stop comparing face ${faceLetter(face.index)}`,
|
|
2173
|
+
variant: "muted",
|
|
2174
|
+
size: "sm",
|
|
2175
|
+
onClick: face.onStop,
|
|
2176
|
+
children: /* @__PURE__ */ jsx24(XIcon, { weight: "bold" })
|
|
2177
|
+
}
|
|
2178
|
+
) : null,
|
|
2179
|
+
folds,
|
|
2180
|
+
className: "px-2",
|
|
2181
|
+
children: /* @__PURE__ */ jsx24("ul", { className: "-mx-2 flex flex-col gap-0.5", children: rows.map((row) => /* @__PURE__ */ jsx24(
|
|
2182
|
+
Row,
|
|
2183
|
+
{
|
|
2184
|
+
row,
|
|
2185
|
+
chosen: row.feature.tag === selected,
|
|
2186
|
+
onSelect,
|
|
2187
|
+
onHover,
|
|
2188
|
+
look
|
|
2189
|
+
},
|
|
2190
|
+
row.feature.tag
|
|
2191
|
+
)) })
|
|
2192
|
+
}
|
|
2193
|
+
) });
|
|
2194
|
+
};
|
|
2195
|
+
var Row = ({ row, chosen, onSelect, onHover, look }) => {
|
|
2196
|
+
const { feature } = row;
|
|
2197
|
+
const info = look.selected === "info";
|
|
2198
|
+
return /* @__PURE__ */ jsxs22(
|
|
2199
|
+
"li",
|
|
2200
|
+
{
|
|
2201
|
+
className: cn13(
|
|
2202
|
+
"flex items-center gap-1",
|
|
2203
|
+
info && "rounded border pr-1",
|
|
2204
|
+
info && (chosen ? "border-info/60 bg-info/15" : "border-transparent")
|
|
2205
|
+
),
|
|
2206
|
+
children: [
|
|
2207
|
+
/* @__PURE__ */ jsxs22(
|
|
2208
|
+
"button",
|
|
2209
|
+
{
|
|
2210
|
+
type: "button",
|
|
2211
|
+
"data-list-item": "candidates",
|
|
2212
|
+
"data-follow": true,
|
|
2213
|
+
"aria-pressed": chosen,
|
|
2214
|
+
onClick: () => onSelect(feature.tag),
|
|
2215
|
+
onPointerEnter: onHover ? () => onHover(feature.tag) : void 0,
|
|
2216
|
+
onPointerLeave: onHover ? () => onHover(null) : void 0,
|
|
2217
|
+
className: cn13(
|
|
2218
|
+
"flex min-w-0 flex-1 cursor-pointer flex-col rounded px-2 py-1.5 text-left text-sm",
|
|
2219
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-info/75",
|
|
2220
|
+
"text-gray-600 dark:text-zinc-200",
|
|
2221
|
+
info ? "hover:bg-gray-50 dark:hover:bg-zinc-800/60" : "hover:bg-gray-100 dark:hover:bg-zinc-800",
|
|
2222
|
+
chosen && (info ? "font-medium" : "bg-gray-100 font-semibold dark:bg-zinc-800")
|
|
2223
|
+
),
|
|
2224
|
+
children: [
|
|
2225
|
+
/* @__PURE__ */ jsxs22("span", { className: "flex w-full items-center gap-2", children: [
|
|
2226
|
+
row.color ? /* @__PURE__ */ jsx24(Swatch, { color: row.color }) : /* @__PURE__ */ jsx24("span", { "aria-hidden": true, className: "size-4 shrink-0" }),
|
|
2227
|
+
/* @__PURE__ */ jsx24("span", { className: "min-w-0 flex-1 truncate", children: /* @__PURE__ */ jsx24(FeatureName, { feature, label: row.label, look }) }),
|
|
2228
|
+
row.ruleCount ? /* @__PURE__ */ jsxs22("span", { className: cn13("text-2xs tabular-nums", secondaryText(look)), children: [
|
|
2229
|
+
row.ruleCount,
|
|
2230
|
+
" ",
|
|
2231
|
+
row.ruleCount === 1 ? "rule" : "rules"
|
|
2232
|
+
] }) : null,
|
|
2233
|
+
row.required ? /* @__PURE__ */ jsx24(RequiredBadge, {}) : null,
|
|
2234
|
+
row.detail ? /* @__PURE__ */ jsx24("span", { className: cn13("max-w-32 shrink-0 truncate text-xs", secondaryText(look)), children: row.detail }) : null
|
|
2235
|
+
] }),
|
|
2236
|
+
row.note ? /* @__PURE__ */ jsx24("span", { className: "pl-6 text-2xs text-warning-darken", children: row.note }) : null
|
|
2237
|
+
]
|
|
2238
|
+
}
|
|
2239
|
+
),
|
|
2240
|
+
row.action
|
|
2241
|
+
]
|
|
2242
|
+
}
|
|
2243
|
+
);
|
|
2244
|
+
};
|
|
2245
|
+
|
|
2246
|
+
// src/feature-panel/comparison-table.tsx
|
|
2247
|
+
import { useMemo as useMemo8 } from "react";
|
|
2248
|
+
import { cn as cn14 } from "@toolpath/ui";
|
|
2249
|
+
import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2250
|
+
var DASH = "\u2014";
|
|
2251
|
+
var ComparisonTable = ({
|
|
2252
|
+
faces,
|
|
2253
|
+
active,
|
|
2254
|
+
onSelect,
|
|
2255
|
+
onHover,
|
|
2256
|
+
look: lookOption,
|
|
2257
|
+
folds
|
|
2258
|
+
}) => {
|
|
2259
|
+
const look = resolveLook(lookOption);
|
|
2260
|
+
const rows = useMemo8(() => {
|
|
2261
|
+
const row = (key, label, read) => {
|
|
2262
|
+
const values = faces.map((face) => face.feature ? read(face, face.feature) : null);
|
|
2263
|
+
const texts = values.map((value) => value?.text ?? DASH);
|
|
2264
|
+
return {
|
|
2265
|
+
key,
|
|
2266
|
+
label,
|
|
2267
|
+
cells: values.map((value) => value?.node ?? value?.text ?? DASH),
|
|
2268
|
+
differs: new Set(texts).size > 1
|
|
2269
|
+
};
|
|
2270
|
+
};
|
|
2271
|
+
const fixed = [
|
|
2272
|
+
row("type", "Type", (_, feature) => ({ text: featureTypeLabel(feature.featureType) })),
|
|
2273
|
+
row("direction", "Machined from", (face, feature) => {
|
|
2274
|
+
const text = directionLabel(feature.machiningDirection);
|
|
2275
|
+
return {
|
|
2276
|
+
text,
|
|
2277
|
+
node: /* @__PURE__ */ jsxs23("span", { className: "inline-flex items-center gap-1", children: [
|
|
2278
|
+
/* @__PURE__ */ jsx25(Swatch, { color: face.directionColor, className: "size-2.5" }),
|
|
2279
|
+
text
|
|
2280
|
+
] })
|
|
2281
|
+
};
|
|
2282
|
+
}),
|
|
2283
|
+
...faces.some((face) => face.required !== void 0) ? [row("required", "Required", (face) => ({ text: face.required ? "Yes" : "No" }))] : [],
|
|
2284
|
+
row("rules", "Rules broken", (face) => ({
|
|
2285
|
+
text: face.rules.map((rule) => rule.key).join(",") || "None",
|
|
2286
|
+
node: face.rules.length > 0 ? /* @__PURE__ */ jsxs23(
|
|
2287
|
+
"span",
|
|
2288
|
+
{
|
|
2289
|
+
className: "inline-flex items-center gap-0.5",
|
|
2290
|
+
title: face.rules.map((rule) => rule.text).join("\n"),
|
|
2291
|
+
children: [
|
|
2292
|
+
face.rules.map((rule) => /* @__PURE__ */ jsx25(Swatch, { color: rule.color, className: "size-2.5" }, rule.key)),
|
|
2293
|
+
/* @__PURE__ */ jsx25("span", { className: "ml-0.5", children: face.rules.length })
|
|
2294
|
+
]
|
|
2295
|
+
}
|
|
2296
|
+
) : "None"
|
|
2297
|
+
}))
|
|
2298
|
+
];
|
|
2299
|
+
const labels = /* @__PURE__ */ new Map();
|
|
2300
|
+
for (const face of faces)
|
|
2301
|
+
for (const each of face.measurements) labels.set(each.key, labels.get(each.key) ?? each.label);
|
|
2302
|
+
const measured = [...labels].map(([key, label]) => {
|
|
2303
|
+
const values = faces.map((face) => face.measurements.find((each) => each.key === key));
|
|
2304
|
+
return {
|
|
2305
|
+
key,
|
|
2306
|
+
label,
|
|
2307
|
+
cells: values.map((value) => value ? /* @__PURE__ */ jsx25("span", { title: value.alt, children: value.value }) : DASH),
|
|
2308
|
+
differs: new Set(values.map((value) => value?.value ?? DASH)).size > 1
|
|
2309
|
+
};
|
|
2310
|
+
});
|
|
2311
|
+
return [...fixed, ...measured];
|
|
2312
|
+
}, [faces]);
|
|
2313
|
+
return /* @__PURE__ */ jsx25("div", { className: "border-b border-gray-100 p-4 dark:border-zinc-800", children: /* @__PURE__ */ jsx25(FoldSection, { id: "comparison", title: "Comparison", folds, children: /* @__PURE__ */ jsx25("div", { className: "-mx-1 overflow-x-auto", children: /* @__PURE__ */ jsxs23("table", { className: "w-full border-separate border-spacing-x-1 border-spacing-y-0.5 text-sm", children: [
|
|
2314
|
+
/* @__PURE__ */ jsx25("thead", { children: /* @__PURE__ */ jsxs23("tr", { children: [
|
|
2315
|
+
/* @__PURE__ */ jsx25("th", { className: "w-0" }),
|
|
2316
|
+
faces.map(({ feature }, index) => /* @__PURE__ */ jsx25("th", { className: "text-left align-bottom font-normal", children: /* @__PURE__ */ jsxs23(
|
|
2317
|
+
"button",
|
|
2318
|
+
{
|
|
2319
|
+
type: "button",
|
|
2320
|
+
disabled: !feature,
|
|
2321
|
+
onClick: () => feature && onSelect(feature.tag, index),
|
|
2322
|
+
onPointerEnter: onHover ? () => onHover(feature?.tag ?? null) : void 0,
|
|
2323
|
+
onPointerLeave: onHover ? () => onHover(null) : void 0,
|
|
2324
|
+
className: cn14(
|
|
2325
|
+
"flex w-full min-w-0 cursor-pointer items-center gap-1.5 rounded px-1 py-1 text-left text-xs",
|
|
2326
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-info/75",
|
|
2327
|
+
"text-gray-600 hover:bg-gray-100 dark:text-zinc-200 dark:hover:bg-zinc-800",
|
|
2328
|
+
index === active && "bg-gray-100 font-semibold dark:bg-zinc-800"
|
|
2329
|
+
),
|
|
2330
|
+
children: [
|
|
2331
|
+
/* @__PURE__ */ jsx25(FaceLetter, { index, active: index === active }),
|
|
2332
|
+
/* @__PURE__ */ jsx25("span", { className: "min-w-0 truncate", children: feature ? /* @__PURE__ */ jsx25(FeatureName, { feature, look }) : "No feature" })
|
|
2333
|
+
]
|
|
2334
|
+
}
|
|
2335
|
+
) }, index))
|
|
2336
|
+
] }) }),
|
|
2337
|
+
/* @__PURE__ */ jsx25("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs23("tr", { "data-differs": row.differs || void 0, children: [
|
|
2338
|
+
/* @__PURE__ */ jsx25(
|
|
2339
|
+
"th",
|
|
2340
|
+
{
|
|
2341
|
+
scope: "row",
|
|
2342
|
+
className: cn14(
|
|
2343
|
+
"pr-2 text-left align-top font-normal whitespace-nowrap",
|
|
2344
|
+
secondaryText(look)
|
|
2345
|
+
),
|
|
2346
|
+
children: row.label
|
|
2347
|
+
}
|
|
2348
|
+
),
|
|
2349
|
+
row.cells.map((cell, index) => /* @__PURE__ */ jsx25(
|
|
2350
|
+
"td",
|
|
2351
|
+
{
|
|
2352
|
+
className: cn14(
|
|
2353
|
+
"px-1 align-top tabular-nums whitespace-nowrap",
|
|
2354
|
+
row.differs ? "text-gray-600 dark:text-zinc-100" : "text-gray-400 dark:text-zinc-500"
|
|
2355
|
+
),
|
|
2356
|
+
children: cell
|
|
2357
|
+
},
|
|
2358
|
+
index
|
|
2359
|
+
))
|
|
2360
|
+
] }, row.key)) })
|
|
2361
|
+
] }) }) }) });
|
|
2362
|
+
};
|
|
2363
|
+
|
|
2364
|
+
// src/feature-panel/feature-panel.tsx
|
|
2365
|
+
import { CubeIcon, XIcon as XIcon2 } from "@phosphor-icons/react";
|
|
2366
|
+
import { IconButton as IconButton5, ScrollArea as ScrollArea2, cn as cn15 } from "@toolpath/ui";
|
|
2367
|
+
import { Fragment as Fragment11, jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2368
|
+
var title = (faces, active, group) => {
|
|
2369
|
+
if (faces.length > 1) return `Comparing ${faces.length} faces`;
|
|
2370
|
+
if (faces[active]?.region !== null && faces[active]?.region !== void 0)
|
|
2371
|
+
return "Features on this face";
|
|
2372
|
+
if (group !== void 0) return `${group} identical holes`;
|
|
2373
|
+
return "Feature";
|
|
2374
|
+
};
|
|
2375
|
+
var FeaturePanel = ({
|
|
2376
|
+
faces,
|
|
2377
|
+
active,
|
|
2378
|
+
group,
|
|
2379
|
+
comparison,
|
|
2380
|
+
onSelect,
|
|
2381
|
+
onDropFace,
|
|
2382
|
+
onHover,
|
|
2383
|
+
onClose,
|
|
2384
|
+
headerProps,
|
|
2385
|
+
className,
|
|
2386
|
+
look: lookOption,
|
|
2387
|
+
folds,
|
|
2388
|
+
children
|
|
2389
|
+
}) => {
|
|
2390
|
+
const look = resolveLook(lookOption);
|
|
2391
|
+
const comparing = faces.length > 1;
|
|
2392
|
+
const face = faces[active];
|
|
2393
|
+
const heading = title(faces, active, group);
|
|
2394
|
+
return /* @__PURE__ */ jsxs24(
|
|
2395
|
+
"section",
|
|
2396
|
+
{
|
|
2397
|
+
"aria-label": heading,
|
|
2398
|
+
"data-list-root": true,
|
|
2399
|
+
onKeyDown: (event) => {
|
|
2400
|
+
if (event.defaultPrevented || !event.currentTarget.contains(event.target)) return;
|
|
2401
|
+
if (event.key === "Escape") onClose();
|
|
2402
|
+
else candidateListKeys(event);
|
|
2403
|
+
},
|
|
2404
|
+
className: cn15(
|
|
2405
|
+
"flex h-full min-h-0 flex-col overflow-hidden rounded bg-white/90 shadow-lg ring-1 ring-gray-200/70 backdrop-blur-md",
|
|
2406
|
+
"dark:bg-zinc-900/90 dark:ring-zinc-800",
|
|
2407
|
+
className
|
|
2408
|
+
),
|
|
2409
|
+
children: [
|
|
2410
|
+
/* @__PURE__ */ jsxs24(
|
|
2411
|
+
"header",
|
|
2412
|
+
{
|
|
2413
|
+
...headerProps,
|
|
2414
|
+
className: cn15(
|
|
2415
|
+
"flex items-center gap-2 border-b border-gray-100 py-2 pr-2 pl-4 select-none dark:border-zinc-800",
|
|
2416
|
+
headerProps?.className
|
|
2417
|
+
),
|
|
2418
|
+
children: [
|
|
2419
|
+
/* @__PURE__ */ jsx26(CubeIcon, { weight: "bold", className: cn15("size-5 shrink-0", secondaryText(look)) }),
|
|
2420
|
+
/* @__PURE__ */ jsx26("h2", { className: "flex-1 text-sm font-semibold text-gray-600 dark:text-zinc-100", children: heading }),
|
|
2421
|
+
/* @__PURE__ */ jsx26(IconButton5, { "aria-label": "Close", variant: "muted", onClick: onClose, children: /* @__PURE__ */ jsx26(XIcon2, { weight: "bold" }) })
|
|
2422
|
+
]
|
|
2423
|
+
}
|
|
2424
|
+
),
|
|
2425
|
+
/* @__PURE__ */ jsxs24(ScrollArea2, { className: "min-h-0 flex-1", children: [
|
|
2426
|
+
comparing ? /* @__PURE__ */ jsxs24(Fragment11, { children: [
|
|
2427
|
+
faces.map((each, index) => /* @__PURE__ */ jsx26(
|
|
2428
|
+
CandidateList,
|
|
2429
|
+
{
|
|
2430
|
+
rows: each.rows,
|
|
2431
|
+
selected: each.selected,
|
|
2432
|
+
onSelect: (tag) => onSelect(tag, index),
|
|
2433
|
+
onHover,
|
|
2434
|
+
face: {
|
|
2435
|
+
index,
|
|
2436
|
+
active: index === active,
|
|
2437
|
+
...onDropFace ? { onStop: () => onDropFace(index) } : {}
|
|
2438
|
+
},
|
|
2439
|
+
look: lookOption,
|
|
2440
|
+
folds
|
|
2441
|
+
},
|
|
2442
|
+
`${each.region ?? "list"}-${index}`
|
|
2443
|
+
)),
|
|
2444
|
+
comparison ? /* @__PURE__ */ jsx26(
|
|
2445
|
+
ComparisonTable,
|
|
2446
|
+
{
|
|
2447
|
+
faces: comparison,
|
|
2448
|
+
active,
|
|
2449
|
+
onSelect,
|
|
2450
|
+
onHover,
|
|
2451
|
+
look: lookOption,
|
|
2452
|
+
folds
|
|
2453
|
+
}
|
|
2454
|
+
) : null
|
|
2455
|
+
] }) : face && face.region !== null ? /* @__PURE__ */ jsx26(
|
|
2456
|
+
CandidateList,
|
|
2457
|
+
{
|
|
2458
|
+
rows: face.rows,
|
|
2459
|
+
selected: face.selected,
|
|
2460
|
+
onSelect: (tag) => onSelect(tag, active),
|
|
2461
|
+
onHover,
|
|
2462
|
+
look: lookOption,
|
|
2463
|
+
folds
|
|
2464
|
+
}
|
|
2465
|
+
) : null,
|
|
2466
|
+
face?.selected ? children : /* @__PURE__ */ jsx26("p", { className: cn15("px-4 py-3 text-sm", secondaryText(look)), children: face && face.rows.length > 0 ? "Choose a feature to read its details." : "No feature owns this face." })
|
|
2467
|
+
] })
|
|
2468
|
+
]
|
|
2469
|
+
}
|
|
2470
|
+
);
|
|
2471
|
+
};
|
|
1620
2472
|
export {
|
|
2473
|
+
CandidateList,
|
|
2474
|
+
ComparisonTable,
|
|
2475
|
+
FeatureDetails,
|
|
2476
|
+
FeaturePanel,
|
|
1621
2477
|
ReachChart,
|
|
1622
2478
|
ReachDrawing,
|
|
1623
2479
|
RuleList,
|
|
1624
2480
|
Swatch,
|
|
2481
|
+
candidateListKeys,
|
|
1625
2482
|
isField,
|
|
1626
2483
|
listKeys,
|
|
1627
|
-
ruleListKeys
|
|
2484
|
+
ruleListKeys,
|
|
2485
|
+
storageFolds
|
|
1628
2486
|
};
|