@toolpath/dfm 0.1.0 → 0.2.1
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 +1246 -250
- 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,
|
|
@@ -36,7 +37,7 @@ import {
|
|
|
36
37
|
} from "./chunk-5MPHT7BC.js";
|
|
37
38
|
|
|
38
39
|
// src/rule-list/rule-list.tsx
|
|
39
|
-
import { useMemo as useMemo2, useState as
|
|
40
|
+
import { useMemo as useMemo2, useState as useState8 } from "react";
|
|
40
41
|
import { ScrollArea } from "@toolpath/ui";
|
|
41
42
|
|
|
42
43
|
// src/rule-list/list-keys.ts
|
|
@@ -69,48 +70,31 @@ var currentIndex = (items, active) => {
|
|
|
69
70
|
var isField = (target) => target instanceof HTMLSelectElement || target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement && target.type !== "color" && target.type !== "button" || target instanceof HTMLElement && target.isContentEditable;
|
|
70
71
|
|
|
71
72
|
// src/rule-list/new-rule.tsx
|
|
72
|
-
import { useState } from "react";
|
|
73
|
-
import { cn as cn2 } from "@toolpath/ui";
|
|
73
|
+
import { useState as useState2 } from "react";
|
|
74
74
|
|
|
75
|
-
// src/rule-list/options.
|
|
76
|
-
|
|
77
|
-
var MORE = "__more";
|
|
78
|
-
var showMore = (select, setAll) => {
|
|
79
|
-
setAll(true);
|
|
80
|
-
requestAnimationFrame(() => {
|
|
81
|
-
try {
|
|
82
|
-
select.showPicker();
|
|
83
|
-
} catch {
|
|
84
|
-
select.focus();
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
};
|
|
88
|
-
var option = (value, label) => /* @__PURE__ */ jsx("option", { value, children: label }, value);
|
|
89
|
-
var SubjectOptions = ({
|
|
90
|
-
current,
|
|
91
|
-
all
|
|
92
|
-
}) => {
|
|
75
|
+
// src/rule-list/options.ts
|
|
76
|
+
var subjectChoices = (current, all) => {
|
|
93
77
|
const quick = [...QUICK_SUBJECTS, ...QUICK_SUBJECTS.includes(current) ? [] : [current]];
|
|
78
|
+
const first = { choices: quick.map((value) => ({ value, label: subjectLabel(value) })) };
|
|
79
|
+
if (!all) return { groups: [first], more: "More feature types\u2026" };
|
|
94
80
|
const rest = FEATURE_SUBJECTS.filter((each) => !quick.includes(each.value));
|
|
95
|
-
return
|
|
96
|
-
quick.map((value) => option(value, subjectLabel(value))),
|
|
97
|
-
all ? /* @__PURE__ */ jsx("optgroup", { label: "More feature types", children: rest.map((each) => option(each.value, each.label)) }) : option(MORE, "More feature types\u2026")
|
|
98
|
-
] });
|
|
81
|
+
return { groups: [first, { heading: "More feature types", choices: rest }] };
|
|
99
82
|
};
|
|
100
|
-
var
|
|
101
|
-
subject,
|
|
102
|
-
current,
|
|
103
|
-
all
|
|
104
|
-
}) => {
|
|
83
|
+
var metricChoices = (subject, current, all) => {
|
|
105
84
|
const offered = metricsForSubject(subject);
|
|
106
85
|
const quick = offered.filter((each) => QUICK_METRICS.includes(each.key) || each.key === current);
|
|
107
86
|
quick.sort((a, b) => rank(a.key) - rank(b.key));
|
|
108
87
|
const rest = offered.filter((each) => !quick.includes(each));
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
88
|
+
const first = { choices: quick.map(choice) };
|
|
89
|
+
if (!all) return { groups: [first], more: rest.length > 0 ? "More measures\u2026" : void 0 };
|
|
90
|
+
return {
|
|
91
|
+
groups: [
|
|
92
|
+
first,
|
|
93
|
+
...grouped(rest).map(([heading, metrics]) => ({ heading, choices: metrics.map(choice) }))
|
|
94
|
+
]
|
|
95
|
+
};
|
|
113
96
|
};
|
|
97
|
+
var choice = ({ key, label }) => ({ value: key, label });
|
|
114
98
|
var rank = (key) => {
|
|
115
99
|
const at = QUICK_METRICS.indexOf(key);
|
|
116
100
|
return at === -1 ? QUICK_METRICS.length : at;
|
|
@@ -121,6 +105,17 @@ var grouped = (items) => {
|
|
|
121
105
|
return [...groups];
|
|
122
106
|
};
|
|
123
107
|
|
|
108
|
+
// src/rule-list/picker.tsx
|
|
109
|
+
import {
|
|
110
|
+
Fragment,
|
|
111
|
+
useEffect,
|
|
112
|
+
useId,
|
|
113
|
+
useRef,
|
|
114
|
+
useState
|
|
115
|
+
} from "react";
|
|
116
|
+
import { CheckIcon } from "@phosphor-icons/react";
|
|
117
|
+
import { Menu, cn as cn2 } from "@toolpath/ui";
|
|
118
|
+
|
|
124
119
|
// src/rule-list/styles.ts
|
|
125
120
|
import { cn } from "@toolpath/ui";
|
|
126
121
|
var FOCUS_RING = "outline-none focus-visible:ring-2 focus-visible:ring-info/75";
|
|
@@ -131,10 +126,157 @@ var WORD = cn(
|
|
|
131
126
|
"outline-none focus-visible:bg-gray-100 focus-visible:ring-2 focus-visible:ring-info/75 dark:focus-visible:bg-zinc-700"
|
|
132
127
|
);
|
|
133
128
|
|
|
129
|
+
// src/rule-list/picker.tsx
|
|
130
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
131
|
+
var HEADING = "px-2 pt-1.5 pb-1 text-[10px] font-semibold tracking-wider text-gray-300 uppercase font-body dark:text-zinc-500";
|
|
132
|
+
var Picker = ({
|
|
133
|
+
label,
|
|
134
|
+
value,
|
|
135
|
+
choices,
|
|
136
|
+
onChange,
|
|
137
|
+
onMore,
|
|
138
|
+
placeholder,
|
|
139
|
+
title: title2,
|
|
140
|
+
className,
|
|
141
|
+
autoFocus
|
|
142
|
+
}) => {
|
|
143
|
+
const id = useId();
|
|
144
|
+
const held = useRef(null);
|
|
145
|
+
const [holding, setHolding] = useState(0);
|
|
146
|
+
const hold = (next) => {
|
|
147
|
+
held.current = next;
|
|
148
|
+
if (next) setHolding((count) => count + 1);
|
|
149
|
+
};
|
|
150
|
+
const flat = choices.groups.flatMap((group) => group.choices);
|
|
151
|
+
const at = flat.findIndex((choice2) => choice2.value === value);
|
|
152
|
+
const shown = flat[at]?.label ?? placeholder ?? value;
|
|
153
|
+
const starts = choices.groups.map(
|
|
154
|
+
(_, g) => choices.groups.slice(0, g).reduce((count, group) => count + group.choices.length, 0)
|
|
155
|
+
);
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
if (holding === 0) return;
|
|
158
|
+
const frame = requestAnimationFrame(() => focusHeld(id, held.current));
|
|
159
|
+
return () => cancelAnimationFrame(frame);
|
|
160
|
+
}, [holding, id]);
|
|
161
|
+
return (
|
|
162
|
+
// A click on the word, in its menu or on the menu's backdrop is the picker's: React would carry
|
|
163
|
+
// it up through the portal to the row, which opens on a click.
|
|
164
|
+
/* @__PURE__ */ jsx("span", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsxs(Menu, { onOpenChange: (open) => hold(open && at !== -1 ? { index: at, reveal: false } : null), children: [
|
|
165
|
+
/* @__PURE__ */ jsx(
|
|
166
|
+
Menu.Trigger,
|
|
167
|
+
{
|
|
168
|
+
nativeButton: true,
|
|
169
|
+
render: /* @__PURE__ */ jsx(
|
|
170
|
+
"button",
|
|
171
|
+
{
|
|
172
|
+
type: "button",
|
|
173
|
+
"aria-label": at === -1 ? label : `${label}: ${shown}`,
|
|
174
|
+
title: title2,
|
|
175
|
+
className: cn2(
|
|
176
|
+
WORD,
|
|
177
|
+
"data-[popup-open]:bg-gray-100 dark:data-[popup-open]:bg-zinc-700",
|
|
178
|
+
className
|
|
179
|
+
),
|
|
180
|
+
autoFocus
|
|
181
|
+
}
|
|
182
|
+
),
|
|
183
|
+
children: shown
|
|
184
|
+
}
|
|
185
|
+
),
|
|
186
|
+
/* @__PURE__ */ jsxs(
|
|
187
|
+
Menu.Popover,
|
|
188
|
+
{
|
|
189
|
+
align: "start",
|
|
190
|
+
sideOffset: 4,
|
|
191
|
+
collisionPadding: 8,
|
|
192
|
+
className: "max-h-[min(24rem,var(--available-height))] min-w-[var(--anchor-width)] overflow-y-auto py-1 shadow-lg",
|
|
193
|
+
onFocus: (event) => {
|
|
194
|
+
const item = held.current && document.getElementById(itemId(id, held.current.index));
|
|
195
|
+
if (item && event.target !== item) focusHeld(id, held.current);
|
|
196
|
+
},
|
|
197
|
+
onPointerMove: () => hold(null),
|
|
198
|
+
onKeyDownCapture: () => hold(null),
|
|
199
|
+
onKeyDown: keepKeys,
|
|
200
|
+
children: [
|
|
201
|
+
choices.groups.map((group, g) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
202
|
+
g > 0 ? /* @__PURE__ */ jsx(Menu.Divider, { className: "my-1" }) : null,
|
|
203
|
+
/* @__PURE__ */ jsxs(
|
|
204
|
+
"div",
|
|
205
|
+
{
|
|
206
|
+
role: "group",
|
|
207
|
+
"aria-labelledby": group.heading ? `${id}-group-${g}` : void 0,
|
|
208
|
+
className: "flex flex-col",
|
|
209
|
+
children: [
|
|
210
|
+
group.heading ? /* @__PURE__ */ jsx("div", { id: `${id}-group-${g}`, className: HEADING, children: group.heading }) : null,
|
|
211
|
+
group.choices.map((choice2, c) => {
|
|
212
|
+
const chosen = choice2.value === value;
|
|
213
|
+
return /* @__PURE__ */ jsxs(
|
|
214
|
+
Menu.Item,
|
|
215
|
+
{
|
|
216
|
+
id: itemId(id, (starts[g] ?? 0) + c),
|
|
217
|
+
label: choice2.label,
|
|
218
|
+
onClick: () => {
|
|
219
|
+
if (!chosen) onChange(choice2.value);
|
|
220
|
+
},
|
|
221
|
+
className: "gap-3",
|
|
222
|
+
children: [
|
|
223
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1", children: choice2.label }),
|
|
224
|
+
/* @__PURE__ */ jsx(
|
|
225
|
+
CheckIcon,
|
|
226
|
+
{
|
|
227
|
+
"aria-hidden": true,
|
|
228
|
+
weight: "bold",
|
|
229
|
+
className: cn2(
|
|
230
|
+
"size-3.5 text-gray-400 dark:text-zinc-300",
|
|
231
|
+
!chosen && "invisible"
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
)
|
|
235
|
+
]
|
|
236
|
+
},
|
|
237
|
+
choice2.value
|
|
238
|
+
);
|
|
239
|
+
})
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
] }, group.heading ?? g)),
|
|
244
|
+
choices.more && onMore ? /* @__PURE__ */ jsx(
|
|
245
|
+
Menu.Item,
|
|
246
|
+
{
|
|
247
|
+
closeOnClick: false,
|
|
248
|
+
onClick: () => {
|
|
249
|
+
hold({ index: flat.length, reveal: true });
|
|
250
|
+
onMore();
|
|
251
|
+
},
|
|
252
|
+
className: "text-gray-400 dark:text-zinc-400",
|
|
253
|
+
children: choices.more
|
|
254
|
+
}
|
|
255
|
+
) : null
|
|
256
|
+
]
|
|
257
|
+
}
|
|
258
|
+
)
|
|
259
|
+
] }) })
|
|
260
|
+
);
|
|
261
|
+
};
|
|
262
|
+
var focusHeld = (picker, held) => {
|
|
263
|
+
const item = held && document.getElementById(itemId(picker, held.index));
|
|
264
|
+
if (!item) return;
|
|
265
|
+
item.focus({ preventScroll: held.reveal });
|
|
266
|
+
const menu = item.closest('[role="menu"]');
|
|
267
|
+
const group = item.closest('[role="group"]');
|
|
268
|
+
if (held.reveal && menu && group)
|
|
269
|
+
menu.scrollTop += group.getBoundingClientRect().top - menu.getBoundingClientRect().top - 8;
|
|
270
|
+
};
|
|
271
|
+
var itemId = (picker, index) => `${picker}-${index}`;
|
|
272
|
+
var keepKeys = (event) => {
|
|
273
|
+
if (event.key !== "Tab") event.stopPropagation();
|
|
274
|
+
};
|
|
275
|
+
|
|
134
276
|
// src/rule-list/new-rule.tsx
|
|
135
277
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
136
278
|
var NewRule = ({ onAdd }) => {
|
|
137
|
-
const [all, setAll] =
|
|
279
|
+
const [all, setAll] = useState2(false);
|
|
138
280
|
return /* @__PURE__ */ jsxs2("li", { className: "flex items-start gap-1.5 py-1 pr-1.5", children: [
|
|
139
281
|
/* @__PURE__ */ jsx2("span", { "aria-hidden": true, className: "size-7 shrink-0" }),
|
|
140
282
|
/* @__PURE__ */ jsx2(
|
|
@@ -144,27 +286,23 @@ var NewRule = ({ onAdd }) => {
|
|
|
144
286
|
className: "mt-1.5 size-4 shrink-0 rounded-full border border-dashed border-gray-300 dark:border-zinc-600"
|
|
145
287
|
}
|
|
146
288
|
),
|
|
147
|
-
/* @__PURE__ */ jsx2("p", { className: "min-w-0 flex-1 text-sm leading-7", children: /* @__PURE__ */
|
|
148
|
-
|
|
289
|
+
/* @__PURE__ */ jsx2("p", { className: "min-w-0 flex-1 text-sm leading-7", children: /* @__PURE__ */ jsx2(
|
|
290
|
+
Picker,
|
|
149
291
|
{
|
|
150
|
-
|
|
151
|
-
|
|
292
|
+
label: "New rule",
|
|
293
|
+
placeholder: "+ New Rule",
|
|
152
294
|
value: "",
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
children: [
|
|
158
|
-
/* @__PURE__ */ jsx2("option", { value: "", disabled: true, children: "+ New Rule" }),
|
|
159
|
-
/* @__PURE__ */ jsx2(SubjectOptions, { current: "any", all })
|
|
160
|
-
]
|
|
295
|
+
choices: subjectChoices("any", all),
|
|
296
|
+
onChange: onAdd,
|
|
297
|
+
onMore: () => setAll(true),
|
|
298
|
+
className: "font-normal text-gray-400 dark:text-zinc-500"
|
|
161
299
|
}
|
|
162
300
|
) })
|
|
163
301
|
] });
|
|
164
302
|
};
|
|
165
303
|
|
|
166
304
|
// src/rule-list/rule-row.tsx
|
|
167
|
-
import { useRef as
|
|
305
|
+
import { useRef as useRef3, useState as useState6 } from "react";
|
|
168
306
|
import { CaretRightIcon as CaretRightIcon2, TrashIcon } from "@phosphor-icons/react";
|
|
169
307
|
import { IconButton, cn as cn7 } from "@toolpath/ui";
|
|
170
308
|
|
|
@@ -246,7 +384,7 @@ var FeatureButton = ({
|
|
|
246
384
|
};
|
|
247
385
|
|
|
248
386
|
// src/rule-list/hole-group-row.tsx
|
|
249
|
-
import { useRef, useState as
|
|
387
|
+
import { useRef as useRef2, useState as useState3 } from "react";
|
|
250
388
|
import { CaretRightIcon } from "@phosphor-icons/react";
|
|
251
389
|
import { cn as cn4 } from "@toolpath/ui";
|
|
252
390
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
@@ -255,8 +393,8 @@ var HoleGroupRow = ({
|
|
|
255
393
|
direction,
|
|
256
394
|
...context
|
|
257
395
|
}) => {
|
|
258
|
-
const [open, setOpen] =
|
|
259
|
-
const groupRef =
|
|
396
|
+
const [open, setOpen] = useState3(false);
|
|
397
|
+
const groupRef = useRef2(null);
|
|
260
398
|
const { rule, check, units, selectedGroup, featureOf, onInspect, onHover, onBack } = context;
|
|
261
399
|
const [first] = row.tags;
|
|
262
400
|
const chosen = selectedGroup?.[0] === first;
|
|
@@ -373,10 +511,9 @@ var FeatureRows = ({
|
|
|
373
511
|
var directionOf = (feature) => feature ? directionLabel(feature.machiningDirection) : "";
|
|
374
512
|
|
|
375
513
|
// src/rule-list/rule-sentence.tsx
|
|
376
|
-
import { useState as
|
|
514
|
+
import { useState as useState5 } from "react";
|
|
377
515
|
|
|
378
|
-
// src/rule-list/ops.
|
|
379
|
-
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
516
|
+
// src/rule-list/ops.ts
|
|
380
517
|
var OP_TITLES = {
|
|
381
518
|
gte: "at least",
|
|
382
519
|
gt: "more than",
|
|
@@ -388,44 +525,50 @@ var OP_TITLES = {
|
|
|
388
525
|
};
|
|
389
526
|
var LOW_SYMBOLS = { gte: "\u2264", gt: "<" };
|
|
390
527
|
var ONE_SIDED = "one:";
|
|
391
|
-
var
|
|
392
|
-
|
|
393
|
-
"
|
|
394
|
-
|
|
395
|
-
|
|
528
|
+
var ONE_SIDED_CHOICES = {
|
|
529
|
+
heading: "One-sided",
|
|
530
|
+
choices: OPS.filter((op) => op !== "between").map((op) => ({
|
|
531
|
+
value: `${ONE_SIDED}${op}`,
|
|
532
|
+
label: `${opSymbol(op)} ${OP_TITLES[op]}`
|
|
533
|
+
}))
|
|
534
|
+
};
|
|
396
535
|
var rangeEnd = (rule, chosen, hold) => chosen.startsWith(ONE_SIDED) ? withOp(rule, chosen.slice(ONE_SIDED.length)) : { ...rule, ...hold(chosen) };
|
|
397
536
|
|
|
398
537
|
// src/rule-list/comparison.tsx
|
|
399
|
-
import { jsx as
|
|
400
|
-
var
|
|
401
|
-
|
|
538
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
539
|
+
var COMPARISONS = {
|
|
540
|
+
groups: [{ choices: OPS.map((op) => ({ value: op, label: opSymbol(op) })) }]
|
|
541
|
+
};
|
|
542
|
+
var RANGE_HIGH = {
|
|
543
|
+
groups: [
|
|
544
|
+
{ heading: "Range", choices: RANGE_HIGHS.map((op) => ({ value: op, label: opSymbol(op) })) },
|
|
545
|
+
ONE_SIDED_CHOICES
|
|
546
|
+
]
|
|
547
|
+
};
|
|
548
|
+
var Comparison = ({ rule, ranged, onChange }) => ranged ? /* @__PURE__ */ jsx6(
|
|
549
|
+
Picker,
|
|
402
550
|
{
|
|
403
|
-
|
|
551
|
+
label: "High end",
|
|
404
552
|
title: OP_TITLES[highOf(rule)],
|
|
405
|
-
className: WORD,
|
|
406
553
|
value: highOf(rule),
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
/* @__PURE__ */ jsx7("optgroup", { label: "Range", children: RANGE_HIGHS.map((op) => /* @__PURE__ */ jsx7("option", { value: op, children: opSymbol(op) }, op)) }),
|
|
410
|
-
/* @__PURE__ */ jsx7(OneSidedOptions, {})
|
|
411
|
-
]
|
|
554
|
+
choices: RANGE_HIGH,
|
|
555
|
+
onChange: (value) => onChange(rangeEnd(rule, value, (op) => ({ highOp: op })))
|
|
412
556
|
}
|
|
413
|
-
) : /* @__PURE__ */
|
|
414
|
-
|
|
557
|
+
) : /* @__PURE__ */ jsx6(
|
|
558
|
+
Picker,
|
|
415
559
|
{
|
|
416
|
-
|
|
560
|
+
label: "Comparison",
|
|
417
561
|
title: OP_TITLES[rule.op],
|
|
418
|
-
className: WORD,
|
|
419
562
|
value: rule.op,
|
|
420
|
-
|
|
421
|
-
|
|
563
|
+
choices: COMPARISONS,
|
|
564
|
+
onChange: (value) => onChange(withOp(rule, value))
|
|
422
565
|
}
|
|
423
566
|
);
|
|
424
567
|
|
|
425
568
|
// src/rule-list/value-field.tsx
|
|
426
|
-
import { useEffect, useState as
|
|
569
|
+
import { useEffect as useEffect2, useState as useState4 } from "react";
|
|
427
570
|
import { cn as cn5 } from "@toolpath/ui";
|
|
428
|
-
import { jsx as
|
|
571
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
429
572
|
var ValueField = ({
|
|
430
573
|
label,
|
|
431
574
|
info,
|
|
@@ -434,13 +577,13 @@ var ValueField = ({
|
|
|
434
577
|
onChange
|
|
435
578
|
}) => {
|
|
436
579
|
const shown = toField(info.quantity, value, units);
|
|
437
|
-
const [text, setText] =
|
|
438
|
-
const [typing, setTyping] =
|
|
439
|
-
|
|
580
|
+
const [text, setText] = useState4(shown);
|
|
581
|
+
const [typing, setTyping] = useState4(false);
|
|
582
|
+
useEffect2(() => {
|
|
440
583
|
if (!typing) setText(shown);
|
|
441
584
|
}, [shown, typing]);
|
|
442
585
|
const invalid = fromField(info, text, units) === null;
|
|
443
|
-
return /* @__PURE__ */
|
|
586
|
+
return /* @__PURE__ */ jsx7(
|
|
444
587
|
"input",
|
|
445
588
|
{
|
|
446
589
|
"aria-label": label,
|
|
@@ -467,7 +610,13 @@ var ValueField = ({
|
|
|
467
610
|
};
|
|
468
611
|
|
|
469
612
|
// src/rule-list/rule-sentence.tsx
|
|
470
|
-
import { Fragment as Fragment3, jsx as
|
|
613
|
+
import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
614
|
+
var RANGE_LOW = {
|
|
615
|
+
groups: [
|
|
616
|
+
{ heading: "Range", choices: RANGE_LOWS.map((op) => ({ value: op, label: LOW_SYMBOLS[op] })) },
|
|
617
|
+
ONE_SIDED_CHOICES
|
|
618
|
+
]
|
|
619
|
+
};
|
|
471
620
|
var RuleSentence = ({
|
|
472
621
|
rule,
|
|
473
622
|
units,
|
|
@@ -479,28 +628,25 @@ var RuleSentence = ({
|
|
|
479
628
|
const presence = info?.quantity === "presence";
|
|
480
629
|
const ranged = info !== void 0 && !flag && rule.op === "between";
|
|
481
630
|
const unit = info ? quantityUnit(info.quantity, units) : "";
|
|
482
|
-
const [allSubjects, setAllSubjects] =
|
|
483
|
-
const [allMetrics, setAllMetrics] =
|
|
484
|
-
const unitSpan = unit ? /* @__PURE__ */
|
|
485
|
-
return /* @__PURE__ */
|
|
486
|
-
/* @__PURE__ */
|
|
487
|
-
|
|
631
|
+
const [allSubjects, setAllSubjects] = useState5(false);
|
|
632
|
+
const [allMetrics, setAllMetrics] = useState5(false);
|
|
633
|
+
const unitSpan = unit ? /* @__PURE__ */ jsx8("span", { className: unit === "\xB0" || unit === "%" ? "" : "pl-1", children: unit }) : null;
|
|
634
|
+
return /* @__PURE__ */ jsxs6("p", { className: "min-w-0 flex-1 text-sm leading-7 text-gray-500 dark:text-zinc-400", children: [
|
|
635
|
+
/* @__PURE__ */ jsx8(
|
|
636
|
+
Picker,
|
|
488
637
|
{
|
|
489
|
-
|
|
490
|
-
className: WORD,
|
|
638
|
+
label: "Features",
|
|
491
639
|
value: rule.subject,
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
},
|
|
496
|
-
children: /* @__PURE__ */ jsx9(SubjectOptions, { current: rule.subject, all: allSubjects })
|
|
640
|
+
choices: subjectChoices(rule.subject, allSubjects),
|
|
641
|
+
onChange: (value) => onChange(withSubject(rule, value, units)),
|
|
642
|
+
onMore: () => setAllSubjects(true)
|
|
497
643
|
}
|
|
498
644
|
),
|
|
499
645
|
presence ? ", " : " with ",
|
|
500
|
-
/* @__PURE__ */
|
|
501
|
-
ranged ? /* @__PURE__ */
|
|
502
|
-
/* @__PURE__ */
|
|
503
|
-
/* @__PURE__ */
|
|
646
|
+
/* @__PURE__ */ jsxs6("span", { className: ranged ? "whitespace-nowrap" : void 0, children: [
|
|
647
|
+
ranged ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
648
|
+
/* @__PURE__ */ jsxs6("span", { className: "whitespace-nowrap", children: [
|
|
649
|
+
/* @__PURE__ */ jsx8(
|
|
504
650
|
ValueField,
|
|
505
651
|
{
|
|
506
652
|
label: "From",
|
|
@@ -513,43 +659,36 @@ var RuleSentence = ({
|
|
|
513
659
|
unitSpan
|
|
514
660
|
] }),
|
|
515
661
|
" ",
|
|
516
|
-
/* @__PURE__ */
|
|
517
|
-
|
|
662
|
+
/* @__PURE__ */ jsx8(
|
|
663
|
+
Picker,
|
|
518
664
|
{
|
|
519
|
-
|
|
665
|
+
label: "Low end",
|
|
520
666
|
title: OP_TITLES[lowOf(rule)],
|
|
521
|
-
className: WORD,
|
|
522
667
|
value: lowOf(rule),
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
/* @__PURE__ */ jsx9("optgroup", { label: "Range", children: RANGE_LOWS.map((op) => /* @__PURE__ */ jsx9("option", { value: op, children: LOW_SYMBOLS[op] }, op)) }),
|
|
526
|
-
/* @__PURE__ */ jsx9(OneSidedOptions, {})
|
|
527
|
-
]
|
|
668
|
+
choices: RANGE_LOW,
|
|
669
|
+
onChange: (value) => onChange(rangeEnd(rule, value, (op) => ({ lowOp: op })))
|
|
528
670
|
}
|
|
529
671
|
),
|
|
530
672
|
" "
|
|
531
673
|
] }) : null,
|
|
532
|
-
/* @__PURE__ */
|
|
533
|
-
|
|
674
|
+
/* @__PURE__ */ jsx8(
|
|
675
|
+
Picker,
|
|
534
676
|
{
|
|
535
|
-
|
|
677
|
+
label: "Measure",
|
|
536
678
|
title: info?.hint,
|
|
537
|
-
className: WORD,
|
|
538
679
|
value: rule.metric,
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
autoFocus,
|
|
544
|
-
children: /* @__PURE__ */ jsx9(MetricOptions, { subject: rule.subject, current: rule.metric, all: allMetrics })
|
|
680
|
+
choices: metricChoices(rule.subject, rule.metric, allMetrics),
|
|
681
|
+
onChange: (value) => onChange(withMetric(rule, value, units)),
|
|
682
|
+
onMore: () => setAllMetrics(true),
|
|
683
|
+
autoFocus
|
|
545
684
|
}
|
|
546
685
|
),
|
|
547
|
-
info && !flag ? /* @__PURE__ */
|
|
686
|
+
info && !flag ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
548
687
|
" ",
|
|
549
|
-
/* @__PURE__ */
|
|
688
|
+
/* @__PURE__ */ jsx8(Comparison, { rule, ranged, onChange }),
|
|
550
689
|
" ",
|
|
551
|
-
/* @__PURE__ */
|
|
552
|
-
/* @__PURE__ */
|
|
690
|
+
/* @__PURE__ */ jsxs6("span", { className: "whitespace-nowrap", children: [
|
|
691
|
+
/* @__PURE__ */ jsx8(
|
|
553
692
|
ValueField,
|
|
554
693
|
{
|
|
555
694
|
label: ranged ? "Up to" : "Value",
|
|
@@ -568,7 +707,7 @@ var RuleSentence = ({
|
|
|
568
707
|
|
|
569
708
|
// src/rule-list/swatch.tsx
|
|
570
709
|
import { cn as cn6 } from "@toolpath/ui";
|
|
571
|
-
import { jsx as
|
|
710
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
572
711
|
var swatchKeys = listKeys("swatches", "horizontal");
|
|
573
712
|
var Swatch = ({
|
|
574
713
|
color,
|
|
@@ -580,7 +719,7 @@ var Swatch = ({
|
|
|
580
719
|
ref
|
|
581
720
|
}) => {
|
|
582
721
|
const dot = cn6("size-4 shrink-0 rounded-full ring-1 ring-black/10 dark:ring-white/15", className);
|
|
583
|
-
return onClick ? /* @__PURE__ */
|
|
722
|
+
return onClick ? /* @__PURE__ */ jsx9(
|
|
584
723
|
"button",
|
|
585
724
|
{
|
|
586
725
|
ref,
|
|
@@ -596,12 +735,12 @@ var Swatch = ({
|
|
|
596
735
|
),
|
|
597
736
|
style: { backgroundColor: color }
|
|
598
737
|
}
|
|
599
|
-
) : /* @__PURE__ */
|
|
738
|
+
) : /* @__PURE__ */ jsx9("span", { "aria-hidden": true, className: dot, style: { backgroundColor: color } });
|
|
600
739
|
};
|
|
601
740
|
var ColorPicker = ({
|
|
602
741
|
value,
|
|
603
742
|
onChange
|
|
604
|
-
}) => /* @__PURE__ */
|
|
743
|
+
}) => /* @__PURE__ */ jsx9("div", { className: "flex flex-wrap items-center gap-1.5 py-1", onKeyDown: swatchKeys, children: RULE_COLORS.map((each) => /* @__PURE__ */ jsx9(
|
|
605
744
|
"button",
|
|
606
745
|
{
|
|
607
746
|
type: "button",
|
|
@@ -621,7 +760,7 @@ var ColorPicker = ({
|
|
|
621
760
|
)) });
|
|
622
761
|
|
|
623
762
|
// src/rule-list/rule-row.tsx
|
|
624
|
-
import { jsx as
|
|
763
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
625
764
|
var isControl = (target) => target instanceof Element && target.closest("button, select, input, a") !== null;
|
|
626
765
|
var RuleRow = ({
|
|
627
766
|
rule,
|
|
@@ -638,8 +777,8 @@ var RuleRow = ({
|
|
|
638
777
|
units,
|
|
639
778
|
...list
|
|
640
779
|
}) => {
|
|
641
|
-
const [picking, setPicking] =
|
|
642
|
-
const swatchRef =
|
|
780
|
+
const [picking, setPicking] = useState6(false);
|
|
781
|
+
const swatchRef = useRef3(null);
|
|
643
782
|
const count = result?.tags.length ?? 0;
|
|
644
783
|
const others = result?.otherTags.length ?? 0;
|
|
645
784
|
const canOpen = count + others > 0;
|
|
@@ -654,7 +793,7 @@ var RuleRow = ({
|
|
|
654
793
|
onToggle();
|
|
655
794
|
}
|
|
656
795
|
};
|
|
657
|
-
return /* @__PURE__ */
|
|
796
|
+
return /* @__PURE__ */ jsxs7(
|
|
658
797
|
"li",
|
|
659
798
|
{
|
|
660
799
|
className: cn7(
|
|
@@ -663,7 +802,7 @@ var RuleRow = ({
|
|
|
663
802
|
!checking && count === 0 && "opacity-55 transition-opacity focus-within:opacity-100 hover:opacity-100"
|
|
664
803
|
),
|
|
665
804
|
children: [
|
|
666
|
-
/* @__PURE__ */
|
|
805
|
+
/* @__PURE__ */ jsxs7(
|
|
667
806
|
"div",
|
|
668
807
|
{
|
|
669
808
|
onClick: (event) => {
|
|
@@ -674,7 +813,7 @@ var RuleRow = ({
|
|
|
674
813
|
canOpen && "cursor-pointer"
|
|
675
814
|
),
|
|
676
815
|
children: [
|
|
677
|
-
/* @__PURE__ */
|
|
816
|
+
/* @__PURE__ */ jsx10(
|
|
678
817
|
"button",
|
|
679
818
|
{
|
|
680
819
|
type: "button",
|
|
@@ -686,7 +825,7 @@ var RuleRow = ({
|
|
|
686
825
|
"flex size-7 shrink-0 items-center justify-center rounded text-gray-400 dark:text-zinc-400",
|
|
687
826
|
canOpen ? "cursor-pointer hover:bg-gray-100 hover:text-gray-600 dark:hover:bg-zinc-700 dark:hover:text-zinc-100" : "invisible"
|
|
688
827
|
),
|
|
689
|
-
children: /* @__PURE__ */
|
|
828
|
+
children: /* @__PURE__ */ jsx10(
|
|
690
829
|
CaretRightIcon2,
|
|
691
830
|
{
|
|
692
831
|
weight: "bold",
|
|
@@ -695,7 +834,7 @@ var RuleRow = ({
|
|
|
695
834
|
)
|
|
696
835
|
}
|
|
697
836
|
),
|
|
698
|
-
/* @__PURE__ */
|
|
837
|
+
/* @__PURE__ */ jsx10(
|
|
699
838
|
Swatch,
|
|
700
839
|
{
|
|
701
840
|
ref: swatchRef,
|
|
@@ -707,9 +846,9 @@ var RuleRow = ({
|
|
|
707
846
|
className: "mt-1.5"
|
|
708
847
|
}
|
|
709
848
|
),
|
|
710
|
-
/* @__PURE__ */
|
|
711
|
-
/* @__PURE__ */
|
|
712
|
-
/* @__PURE__ */
|
|
849
|
+
/* @__PURE__ */ jsx10(RuleSentence, { rule, units, onChange, autoFocus: focusOnMount }),
|
|
850
|
+
/* @__PURE__ */ jsxs7("div", { className: "relative mt-1 shrink-0", children: [
|
|
851
|
+
/* @__PURE__ */ jsx10(
|
|
713
852
|
IconButton,
|
|
714
853
|
{
|
|
715
854
|
"aria-label": "Remove rule",
|
|
@@ -722,10 +861,10 @@ var RuleRow = ({
|
|
|
722
861
|
"group-focus-within/rule:pointer-events-auto group-focus-within/rule:opacity-100",
|
|
723
862
|
"group-hover/rule:pointer-events-auto group-hover/rule:opacity-100"
|
|
724
863
|
),
|
|
725
|
-
children: /* @__PURE__ */
|
|
864
|
+
children: /* @__PURE__ */ jsx10(TrashIcon, { weight: "bold" })
|
|
726
865
|
}
|
|
727
866
|
),
|
|
728
|
-
/* @__PURE__ */
|
|
867
|
+
/* @__PURE__ */ jsx10(
|
|
729
868
|
CountPill,
|
|
730
869
|
{
|
|
731
870
|
count,
|
|
@@ -740,7 +879,7 @@ var RuleRow = ({
|
|
|
740
879
|
]
|
|
741
880
|
}
|
|
742
881
|
),
|
|
743
|
-
picking ? /* @__PURE__ */
|
|
882
|
+
picking ? /* @__PURE__ */ jsx10("div", { className: "pb-1 pl-[34px]", children: /* @__PURE__ */ jsx10(
|
|
744
883
|
ColorPicker,
|
|
745
884
|
{
|
|
746
885
|
value: rule.color,
|
|
@@ -751,7 +890,7 @@ var RuleRow = ({
|
|
|
751
890
|
}
|
|
752
891
|
}
|
|
753
892
|
) }) : null,
|
|
754
|
-
open && result && check && features && sheets ? /* @__PURE__ */
|
|
893
|
+
open && result && check && features && sheets ? /* @__PURE__ */ jsx10(
|
|
755
894
|
FeatureRows,
|
|
756
895
|
{
|
|
757
896
|
rule,
|
|
@@ -776,7 +915,7 @@ var CountPill = ({
|
|
|
776
915
|
open,
|
|
777
916
|
canOpen,
|
|
778
917
|
onToggle
|
|
779
|
-
}) => /* @__PURE__ */
|
|
918
|
+
}) => /* @__PURE__ */ jsx10(
|
|
780
919
|
"button",
|
|
781
920
|
{
|
|
782
921
|
type: "button",
|
|
@@ -800,22 +939,32 @@ var countLabel = (count, others) => {
|
|
|
800
939
|
};
|
|
801
940
|
|
|
802
941
|
// src/rule-list/rule-set-actions.tsx
|
|
803
|
-
import {
|
|
804
|
-
|
|
805
|
-
useEffect as useEffect2,
|
|
806
|
-
useRef as useRef3,
|
|
807
|
-
useState as useState6
|
|
808
|
-
} from "react";
|
|
809
|
-
import { CheckIcon, CopyIcon, DownloadSimpleIcon, UploadSimpleIcon } from "@phosphor-icons/react";
|
|
942
|
+
import { useRef as useRef4 } from "react";
|
|
943
|
+
import { CheckIcon as CheckIcon2, CopyIcon, DownloadSimpleIcon, UploadSimpleIcon } from "@phosphor-icons/react";
|
|
810
944
|
import { Button, cn as cn8 } from "@toolpath/ui";
|
|
811
|
-
|
|
945
|
+
|
|
946
|
+
// src/rule-list/use-timed-value.ts
|
|
947
|
+
import { useCallback, useEffect as useEffect3, useState as useState7 } from "react";
|
|
948
|
+
var useTimedValue = (ms) => {
|
|
949
|
+
const [box, setBox] = useState7(null);
|
|
950
|
+
useEffect3(() => {
|
|
951
|
+
if (box === null) return;
|
|
952
|
+
const timer = setTimeout(() => setBox(null), ms);
|
|
953
|
+
return () => clearTimeout(timer);
|
|
954
|
+
}, [box, ms]);
|
|
955
|
+
const set = useCallback((value) => setBox({ value }), []);
|
|
956
|
+
return [box?.value ?? null, set];
|
|
957
|
+
};
|
|
958
|
+
|
|
959
|
+
// src/rule-list/rule-set-actions.tsx
|
|
960
|
+
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
812
961
|
var NOTE_MS = 4e3;
|
|
813
962
|
var COPIED_MS = 2e3;
|
|
814
963
|
var EXPORT_FILE_NAME = "dfm-rules.json";
|
|
815
964
|
var RuleSetActions = ({ rules }) => {
|
|
816
965
|
const [note, setNote] = useTimedValue(NOTE_MS);
|
|
817
966
|
const [copied, setCopied] = useTimedValue(COPIED_MS);
|
|
818
|
-
const fileInput =
|
|
967
|
+
const fileInput = useRef4(null);
|
|
819
968
|
const importRules = async (file) => {
|
|
820
969
|
if (!file) return;
|
|
821
970
|
let text;
|
|
@@ -843,23 +992,23 @@ var RuleSetActions = ({ rules }) => {
|
|
|
843
992
|
setCopied(true);
|
|
844
993
|
setNote("Paste the prompt into an LLM, then import the JSON it writes.");
|
|
845
994
|
};
|
|
846
|
-
return /* @__PURE__ */
|
|
847
|
-
/* @__PURE__ */
|
|
848
|
-
/* @__PURE__ */
|
|
849
|
-
/* @__PURE__ */
|
|
850
|
-
/* @__PURE__ */
|
|
995
|
+
return /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-2 px-4 pt-2 pb-3", children: [
|
|
996
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
997
|
+
/* @__PURE__ */ jsx11(Button, { variant: "secondary", onClick: () => fileInput.current?.click(), children: /* @__PURE__ */ jsx11(ActionLabel, { icon: /* @__PURE__ */ jsx11(UploadSimpleIcon, { weight: "bold" }), children: "Import\u2026" }) }),
|
|
998
|
+
/* @__PURE__ */ jsx11(Button, { variant: "secondary", onClick: () => downloadRuleSet(rules), children: /* @__PURE__ */ jsx11(ActionLabel, { icon: /* @__PURE__ */ jsx11(DownloadSimpleIcon, { weight: "bold" }), children: "Export" }) }),
|
|
999
|
+
/* @__PURE__ */ jsx11(
|
|
851
1000
|
Button,
|
|
852
1001
|
{
|
|
853
1002
|
variant: "secondary",
|
|
854
1003
|
title: "Copies a prompt that walks an LLM through writing a rule set for you",
|
|
855
1004
|
onClick: () => void copyPrompt(),
|
|
856
|
-
children: /* @__PURE__ */
|
|
857
|
-
/* @__PURE__ */
|
|
858
|
-
/* @__PURE__ */
|
|
1005
|
+
children: /* @__PURE__ */ jsxs8("span", { className: "grid justify-items-center *:col-start-1 *:row-start-1", children: [
|
|
1006
|
+
/* @__PURE__ */ jsx11(ActionLabel, { hidden: copied !== null, icon: /* @__PURE__ */ jsx11(CopyIcon, { weight: "bold" }), children: "Copy LLM prompt" }),
|
|
1007
|
+
/* @__PURE__ */ jsx11(ActionLabel, { hidden: copied === null, icon: /* @__PURE__ */ jsx11(CheckIcon2, { weight: "bold" }), children: "Copied" })
|
|
859
1008
|
] })
|
|
860
1009
|
}
|
|
861
1010
|
),
|
|
862
|
-
/* @__PURE__ */
|
|
1011
|
+
/* @__PURE__ */ jsx11(
|
|
863
1012
|
"input",
|
|
864
1013
|
{
|
|
865
1014
|
ref: fileInput,
|
|
@@ -874,10 +1023,10 @@ var RuleSetActions = ({ rules }) => {
|
|
|
874
1023
|
}
|
|
875
1024
|
)
|
|
876
1025
|
] }),
|
|
877
|
-
note ? /* @__PURE__ */
|
|
1026
|
+
note ? /* @__PURE__ */ jsx11("p", { className: "text-xs text-gray-500 dark:text-zinc-400", role: "status", children: note }) : null
|
|
878
1027
|
] });
|
|
879
1028
|
};
|
|
880
|
-
var ActionLabel = ({ icon, children, hidden = false }) => /* @__PURE__ */
|
|
1029
|
+
var ActionLabel = ({ icon, children, hidden = false }) => /* @__PURE__ */ jsxs8(
|
|
881
1030
|
"span",
|
|
882
1031
|
{
|
|
883
1032
|
"aria-hidden": hidden || void 0,
|
|
@@ -888,16 +1037,6 @@ var ActionLabel = ({ icon, children, hidden = false }) => /* @__PURE__ */ jsxs10
|
|
|
888
1037
|
]
|
|
889
1038
|
}
|
|
890
1039
|
);
|
|
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
1040
|
var downloadRuleSet = (rules) => {
|
|
902
1041
|
const url = URL.createObjectURL(
|
|
903
1042
|
new Blob([serializeRuleSet(rules.rules)], { type: "application/json" })
|
|
@@ -916,7 +1055,7 @@ var importedNote = (count, skipped, name) => {
|
|
|
916
1055
|
};
|
|
917
1056
|
|
|
918
1057
|
// src/rule-list/rule-list.tsx
|
|
919
|
-
import { jsx as
|
|
1058
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
920
1059
|
var ruleListKeys = listKeys("rules");
|
|
921
1060
|
var RuleList = ({
|
|
922
1061
|
rules,
|
|
@@ -926,8 +1065,8 @@ var RuleList = ({
|
|
|
926
1065
|
units,
|
|
927
1066
|
...list
|
|
928
1067
|
}) => {
|
|
929
|
-
const [openIds, setOpenIds] =
|
|
930
|
-
const [added, setAdded] =
|
|
1068
|
+
const [openIds, setOpenIds] = useState8(/* @__PURE__ */ new Set());
|
|
1069
|
+
const [added, setAdded] = useState8(null);
|
|
931
1070
|
const toggleOpen = (id) => setOpenIds((was) => {
|
|
932
1071
|
const next = new Set(was);
|
|
933
1072
|
if (!next.delete(id)) next.add(id);
|
|
@@ -943,7 +1082,7 @@ var RuleList = ({
|
|
|
943
1082
|
};
|
|
944
1083
|
const active = rules.rules.filter(found);
|
|
945
1084
|
const none = rules.rules.filter((rule) => !found(rule));
|
|
946
|
-
const row = (rule) => /* @__PURE__ */
|
|
1085
|
+
const row = (rule) => /* @__PURE__ */ jsx12(
|
|
947
1086
|
RuleRow,
|
|
948
1087
|
{
|
|
949
1088
|
rule,
|
|
@@ -964,11 +1103,11 @@ var RuleList = ({
|
|
|
964
1103
|
);
|
|
965
1104
|
return (
|
|
966
1105
|
// Grows with its rules, and scrolls once the panel can grow no more.
|
|
967
|
-
/* @__PURE__ */
|
|
968
|
-
/* @__PURE__ */
|
|
1106
|
+
/* @__PURE__ */ jsxs9(ScrollArea, { className: "min-h-0 flex-auto", children: [
|
|
1107
|
+
/* @__PURE__ */ jsxs9("ul", { className: "flex flex-col gap-0.5 pt-2 pr-4 pl-2", children: [
|
|
969
1108
|
active.map(row),
|
|
970
1109
|
none.map(row),
|
|
971
|
-
/* @__PURE__ */
|
|
1110
|
+
/* @__PURE__ */ jsx12(
|
|
972
1111
|
NewRule,
|
|
973
1112
|
{
|
|
974
1113
|
onAdd: (subject) => {
|
|
@@ -979,7 +1118,7 @@ var RuleList = ({
|
|
|
979
1118
|
}
|
|
980
1119
|
)
|
|
981
1120
|
] }),
|
|
982
|
-
/* @__PURE__ */
|
|
1121
|
+
/* @__PURE__ */ jsx12(RuleSetActions, { rules })
|
|
983
1122
|
] })
|
|
984
1123
|
);
|
|
985
1124
|
};
|
|
@@ -988,7 +1127,7 @@ var RuleList = ({
|
|
|
988
1127
|
import { useMemo as useMemo4 } from "react";
|
|
989
1128
|
|
|
990
1129
|
// src/reach/reach-section.tsx
|
|
991
|
-
import { useId, useMemo as useMemo3, useState as
|
|
1130
|
+
import { useId as useId2, useMemo as useMemo3, useState as useState9 } from "react";
|
|
992
1131
|
|
|
993
1132
|
// src/reach/reading.tsx
|
|
994
1133
|
import { heightAt } from "@toolpath/tool-support";
|
|
@@ -1063,7 +1202,7 @@ var READ = "stroke-sky-600 dark:stroke-sky-400";
|
|
|
1063
1202
|
var READ_DOT = "fill-sky-600 dark:fill-sky-400";
|
|
1064
1203
|
|
|
1065
1204
|
// src/reach/reading.tsx
|
|
1066
|
-
import { jsx as
|
|
1205
|
+
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1067
1206
|
var readingAt = ({ offsets, heights }, offset) => ({
|
|
1068
1207
|
offset,
|
|
1069
1208
|
height: heightAt({ horizontalOffset: offsets, verticalOffset: heights }, offset),
|
|
@@ -1086,8 +1225,8 @@ var ReadingMark = ({
|
|
|
1086
1225
|
const pointerX = x(reading.offset);
|
|
1087
1226
|
const onRight = pointerX + READ_INSET + textWidth <= width - READ_INSET;
|
|
1088
1227
|
const labelX = onRight ? pointerX + READ_INSET : Math.min(Math.max(pointerX - READ_INSET, READ_INSET + textWidth), width - READ_INSET);
|
|
1089
|
-
return /* @__PURE__ */
|
|
1090
|
-
/* @__PURE__ */
|
|
1228
|
+
return /* @__PURE__ */ jsxs10("g", { pointerEvents: "none", children: [
|
|
1229
|
+
/* @__PURE__ */ jsx13(
|
|
1091
1230
|
"line",
|
|
1092
1231
|
{
|
|
1093
1232
|
x1: pointerX,
|
|
@@ -1099,8 +1238,8 @@ var ReadingMark = ({
|
|
|
1099
1238
|
className: READ
|
|
1100
1239
|
}
|
|
1101
1240
|
),
|
|
1102
|
-
/* @__PURE__ */
|
|
1103
|
-
/* @__PURE__ */
|
|
1241
|
+
/* @__PURE__ */ jsx13("circle", { cx: pointerX, cy: y(reading.height), r: 4, className: READ_DOT }),
|
|
1242
|
+
/* @__PURE__ */ jsx13(
|
|
1104
1243
|
"text",
|
|
1105
1244
|
{
|
|
1106
1245
|
x: labelX,
|
|
@@ -1199,8 +1338,8 @@ var sectionGeometry = (whole, feature, width) => {
|
|
|
1199
1338
|
};
|
|
1200
1339
|
|
|
1201
1340
|
// src/reach/section-parts.tsx
|
|
1202
|
-
import { Fragment as Fragment4, jsx as
|
|
1203
|
-
var Arrows = ({ id }) => /* @__PURE__ */
|
|
1341
|
+
import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1342
|
+
var Arrows = ({ id }) => /* @__PURE__ */ jsx14("defs", { children: /* @__PURE__ */ jsx14(
|
|
1204
1343
|
"marker",
|
|
1205
1344
|
{
|
|
1206
1345
|
id,
|
|
@@ -1210,14 +1349,14 @@ var Arrows = ({ id }) => /* @__PURE__ */ jsx15("defs", { children: /* @__PURE__
|
|
|
1210
1349
|
markerWidth: "7",
|
|
1211
1350
|
markerHeight: "7",
|
|
1212
1351
|
orient: "auto-start-reverse",
|
|
1213
|
-
children: /* @__PURE__ */
|
|
1352
|
+
children: /* @__PURE__ */ jsx14("path", { d: "M 0 1.5 L 10 5 L 0 8.5 z", className: ARROW })
|
|
1214
1353
|
}
|
|
1215
1354
|
) });
|
|
1216
1355
|
var SectionShapes = ({ geometry }) => {
|
|
1217
1356
|
const { x, floorY, right, featureTopY, featureBottomY, wallTop, feature } = geometry;
|
|
1218
1357
|
const floorLeft = feature.through ? x(0) : SECTION_PAD.left;
|
|
1219
|
-
return /* @__PURE__ */
|
|
1220
|
-
/* @__PURE__ */
|
|
1358
|
+
return /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1359
|
+
/* @__PURE__ */ jsx14(
|
|
1221
1360
|
"rect",
|
|
1222
1361
|
{
|
|
1223
1362
|
x: SECTION_PAD.left,
|
|
@@ -1227,7 +1366,7 @@ var SectionShapes = ({ geometry }) => {
|
|
|
1227
1366
|
className: FEATURE_FILL
|
|
1228
1367
|
}
|
|
1229
1368
|
),
|
|
1230
|
-
/* @__PURE__ */
|
|
1369
|
+
/* @__PURE__ */ jsx14(
|
|
1231
1370
|
"rect",
|
|
1232
1371
|
{
|
|
1233
1372
|
x: floorLeft,
|
|
@@ -1237,9 +1376,9 @@ var SectionShapes = ({ geometry }) => {
|
|
|
1237
1376
|
className: FLOOR
|
|
1238
1377
|
}
|
|
1239
1378
|
),
|
|
1240
|
-
/* @__PURE__ */
|
|
1241
|
-
/* @__PURE__ */
|
|
1242
|
-
feature.through ? null : /* @__PURE__ */
|
|
1379
|
+
/* @__PURE__ */ jsx14("path", { d: geometry.materialPath, strokeWidth: 1, className: MATERIAL }),
|
|
1380
|
+
/* @__PURE__ */ jsx14("line", { x1: floorLeft, x2: right, y1: floorY, y2: floorY, strokeWidth: 1, className: LINE }),
|
|
1381
|
+
feature.through ? null : /* @__PURE__ */ jsx14(
|
|
1243
1382
|
"line",
|
|
1244
1383
|
{
|
|
1245
1384
|
x1: SECTION_PAD.left,
|
|
@@ -1250,7 +1389,7 @@ var SectionShapes = ({ geometry }) => {
|
|
|
1250
1389
|
className: FEATURE_LINE
|
|
1251
1390
|
}
|
|
1252
1391
|
),
|
|
1253
|
-
/* @__PURE__ */
|
|
1392
|
+
/* @__PURE__ */ jsx14(
|
|
1254
1393
|
"line",
|
|
1255
1394
|
{
|
|
1256
1395
|
x1: x(0),
|
|
@@ -1261,7 +1400,7 @@ var SectionShapes = ({ geometry }) => {
|
|
|
1261
1400
|
className: FEATURE_LINE
|
|
1262
1401
|
}
|
|
1263
1402
|
),
|
|
1264
|
-
/* @__PURE__ */
|
|
1403
|
+
/* @__PURE__ */ jsx14(
|
|
1265
1404
|
"line",
|
|
1266
1405
|
{
|
|
1267
1406
|
x1: x(0),
|
|
@@ -1277,8 +1416,8 @@ var SectionShapes = ({ geometry }) => {
|
|
|
1277
1416
|
};
|
|
1278
1417
|
var SectionHeadings = ({ geometry }) => {
|
|
1279
1418
|
const { right } = geometry;
|
|
1280
|
-
return /* @__PURE__ */
|
|
1281
|
-
/* @__PURE__ */
|
|
1419
|
+
return /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1420
|
+
/* @__PURE__ */ jsx14(
|
|
1282
1421
|
"text",
|
|
1283
1422
|
{
|
|
1284
1423
|
x: geometry.featureHeadingX,
|
|
@@ -1290,7 +1429,7 @@ var SectionHeadings = ({ geometry }) => {
|
|
|
1290
1429
|
children: geometry.featureHeading
|
|
1291
1430
|
}
|
|
1292
1431
|
),
|
|
1293
|
-
/* @__PURE__ */
|
|
1432
|
+
/* @__PURE__ */ jsx14(
|
|
1294
1433
|
"text",
|
|
1295
1434
|
{
|
|
1296
1435
|
x: right,
|
|
@@ -1304,7 +1443,7 @@ var SectionHeadings = ({ geometry }) => {
|
|
|
1304
1443
|
)
|
|
1305
1444
|
] });
|
|
1306
1445
|
};
|
|
1307
|
-
var FeatureBreak = ({ geometry }) => geometry.featureCut ? /* @__PURE__ */
|
|
1446
|
+
var FeatureBreak = ({ geometry }) => geometry.featureCut ? /* @__PURE__ */ jsx14(
|
|
1308
1447
|
"path",
|
|
1309
1448
|
{
|
|
1310
1449
|
d: featureBreak(SECTION_PAD.left, geometry.featureTopY, geometry.featureBottomY),
|
|
@@ -1317,9 +1456,9 @@ var FeatureDepth = ({ geometry, units }) => {
|
|
|
1317
1456
|
const { x, featureTopY, datumX } = geometry;
|
|
1318
1457
|
const { depth } = geometry.feature;
|
|
1319
1458
|
if (depth === null) return null;
|
|
1320
|
-
return /* @__PURE__ */
|
|
1321
|
-
/* @__PURE__ */
|
|
1322
|
-
/* @__PURE__ */
|
|
1459
|
+
return /* @__PURE__ */ jsxs11("g", { children: [
|
|
1460
|
+
/* @__PURE__ */ jsx14("title", { children: "Feature depth" }),
|
|
1461
|
+
/* @__PURE__ */ jsx14(
|
|
1323
1462
|
"line",
|
|
1324
1463
|
{
|
|
1325
1464
|
x1: SECTION_PAD.left,
|
|
@@ -1330,7 +1469,7 @@ var FeatureDepth = ({ geometry, units }) => {
|
|
|
1330
1469
|
className: FEATURE_LINE
|
|
1331
1470
|
}
|
|
1332
1471
|
),
|
|
1333
|
-
/* @__PURE__ */
|
|
1472
|
+
/* @__PURE__ */ jsx14(
|
|
1334
1473
|
"line",
|
|
1335
1474
|
{
|
|
1336
1475
|
x1: x(0),
|
|
@@ -1342,7 +1481,7 @@ var FeatureDepth = ({ geometry, units }) => {
|
|
|
1342
1481
|
className: FEATURE_LINE
|
|
1343
1482
|
}
|
|
1344
1483
|
),
|
|
1345
|
-
x(0) - SECTION_PAD.left >= DEPTH_WORD_PX ? /* @__PURE__ */
|
|
1484
|
+
x(0) - SECTION_PAD.left >= DEPTH_WORD_PX ? /* @__PURE__ */ jsx14(
|
|
1346
1485
|
"text",
|
|
1347
1486
|
{
|
|
1348
1487
|
x: SECTION_PAD.left + 4,
|
|
@@ -1353,7 +1492,7 @@ var FeatureDepth = ({ geometry, units }) => {
|
|
|
1353
1492
|
children: "depth"
|
|
1354
1493
|
}
|
|
1355
1494
|
) : null,
|
|
1356
|
-
/* @__PURE__ */
|
|
1495
|
+
/* @__PURE__ */ jsx14(
|
|
1357
1496
|
"text",
|
|
1358
1497
|
{
|
|
1359
1498
|
x: datumX + 4,
|
|
@@ -1369,8 +1508,8 @@ var FeatureDepth = ({ geometry, units }) => {
|
|
|
1369
1508
|
var ReadRun = ({ geometry, units, arrowId }) => {
|
|
1370
1509
|
const { x, last, cut, floorY, ordinateY } = geometry;
|
|
1371
1510
|
if (last <= 0 || cut) return null;
|
|
1372
|
-
return /* @__PURE__ */
|
|
1373
|
-
/* @__PURE__ */
|
|
1511
|
+
return /* @__PURE__ */ jsxs11("g", { children: [
|
|
1512
|
+
/* @__PURE__ */ jsx14(
|
|
1374
1513
|
"line",
|
|
1375
1514
|
{
|
|
1376
1515
|
x1: x(0),
|
|
@@ -1383,7 +1522,7 @@ var ReadRun = ({ geometry, units, arrowId }) => {
|
|
|
1383
1522
|
className: LINE
|
|
1384
1523
|
}
|
|
1385
1524
|
),
|
|
1386
|
-
/* @__PURE__ */
|
|
1525
|
+
/* @__PURE__ */ jsx14(
|
|
1387
1526
|
"line",
|
|
1388
1527
|
{
|
|
1389
1528
|
x1: x(last),
|
|
@@ -1394,7 +1533,7 @@ var ReadRun = ({ geometry, units, arrowId }) => {
|
|
|
1394
1533
|
className: LINE
|
|
1395
1534
|
}
|
|
1396
1535
|
),
|
|
1397
|
-
/* @__PURE__ */
|
|
1536
|
+
/* @__PURE__ */ jsxs11(
|
|
1398
1537
|
"text",
|
|
1399
1538
|
{
|
|
1400
1539
|
x: (x(0) + x(last)) / 2,
|
|
@@ -1413,8 +1552,8 @@ var ReadRun = ({ geometry, units, arrowId }) => {
|
|
|
1413
1552
|
var OffsetOrdinates = (props) => {
|
|
1414
1553
|
const { geometry, units } = props;
|
|
1415
1554
|
const { x, y, right, width, floorY, ordinateY } = geometry;
|
|
1416
|
-
return /* @__PURE__ */
|
|
1417
|
-
/* @__PURE__ */
|
|
1555
|
+
return /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1556
|
+
/* @__PURE__ */ jsx14(
|
|
1418
1557
|
"text",
|
|
1419
1558
|
{
|
|
1420
1559
|
x: Math.min(
|
|
@@ -1429,7 +1568,7 @@ var OffsetOrdinates = (props) => {
|
|
|
1429
1568
|
children: "XY PLANE DISTANCE FROM FEATURE"
|
|
1430
1569
|
}
|
|
1431
1570
|
),
|
|
1432
|
-
/* @__PURE__ */
|
|
1571
|
+
/* @__PURE__ */ jsx14(
|
|
1433
1572
|
"line",
|
|
1434
1573
|
{
|
|
1435
1574
|
x1: x(0),
|
|
@@ -1440,9 +1579,9 @@ var OffsetOrdinates = (props) => {
|
|
|
1440
1579
|
className: LINE
|
|
1441
1580
|
}
|
|
1442
1581
|
),
|
|
1443
|
-
/* @__PURE__ */
|
|
1444
|
-
geometry.across.map((riser) => /* @__PURE__ */
|
|
1445
|
-
/* @__PURE__ */
|
|
1582
|
+
/* @__PURE__ */ jsx14("text", { x: x(0), y: ordinateY + 15, textAnchor: "middle", fontSize: 10, className: TEXT, children: "0" }),
|
|
1583
|
+
geometry.across.map((riser) => /* @__PURE__ */ jsxs11("g", { children: [
|
|
1584
|
+
/* @__PURE__ */ jsx14(
|
|
1446
1585
|
"line",
|
|
1447
1586
|
{
|
|
1448
1587
|
x1: x(riser.at),
|
|
@@ -1454,7 +1593,7 @@ var OffsetOrdinates = (props) => {
|
|
|
1454
1593
|
className: LINE
|
|
1455
1594
|
}
|
|
1456
1595
|
),
|
|
1457
|
-
/* @__PURE__ */
|
|
1596
|
+
/* @__PURE__ */ jsx14(
|
|
1458
1597
|
"text",
|
|
1459
1598
|
{
|
|
1460
1599
|
x: x(riser.at),
|
|
@@ -1466,15 +1605,15 @@ var OffsetOrdinates = (props) => {
|
|
|
1466
1605
|
}
|
|
1467
1606
|
)
|
|
1468
1607
|
] }, `x:${riser.at}`)),
|
|
1469
|
-
/* @__PURE__ */
|
|
1608
|
+
/* @__PURE__ */ jsx14(ReadRun, { ...props })
|
|
1470
1609
|
] });
|
|
1471
1610
|
};
|
|
1472
1611
|
var HeightOrdinates = ({ geometry, units }) => {
|
|
1473
1612
|
const { y, right, floorY, datumX } = geometry;
|
|
1474
|
-
return /* @__PURE__ */
|
|
1475
|
-
/* @__PURE__ */
|
|
1476
|
-
geometry.up.map((h) => /* @__PURE__ */
|
|
1477
|
-
/* @__PURE__ */
|
|
1613
|
+
return /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1614
|
+
/* @__PURE__ */ jsx14("text", { x: datumX + 4, y: floorY + 3.5, fontSize: 10, className: TEXT, children: "0" }),
|
|
1615
|
+
geometry.up.map((h) => /* @__PURE__ */ jsxs11("g", { children: [
|
|
1616
|
+
/* @__PURE__ */ jsx14(
|
|
1478
1617
|
"line",
|
|
1479
1618
|
{
|
|
1480
1619
|
x1: right - 2,
|
|
@@ -1486,37 +1625,37 @@ var HeightOrdinates = ({ geometry, units }) => {
|
|
|
1486
1625
|
className: LINE
|
|
1487
1626
|
}
|
|
1488
1627
|
),
|
|
1489
|
-
/* @__PURE__ */
|
|
1628
|
+
/* @__PURE__ */ jsx14("text", { x: datumX + 4, y: y(h) + 3.5, fontSize: 10, className: TEXT, children: lengthValue(h, units) })
|
|
1490
1629
|
] }, `y:${h}`))
|
|
1491
1630
|
] });
|
|
1492
1631
|
};
|
|
1493
1632
|
|
|
1494
1633
|
// src/reach/reach-section.tsx
|
|
1495
|
-
import { Fragment as Fragment5, jsx as
|
|
1634
|
+
import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1496
1635
|
var ReachSection = ({
|
|
1497
1636
|
curve: whole,
|
|
1498
1637
|
units,
|
|
1499
1638
|
feature,
|
|
1500
1639
|
width
|
|
1501
1640
|
}) => {
|
|
1502
|
-
const [hover, setHover] =
|
|
1641
|
+
const [hover, setHover] = useState9(null);
|
|
1503
1642
|
const geometry = useMemo3(() => sectionGeometry(whole, feature, width), [whole, feature, width]);
|
|
1504
|
-
const reactId =
|
|
1643
|
+
const reactId = useId2();
|
|
1505
1644
|
const arrowId = `reach-dim-arrow-${reactId.replace(/[^\w-]/g, "")}`;
|
|
1506
1645
|
const reading = hover === null ? null : readingAt(whole, hover);
|
|
1507
1646
|
const drawing = useMemo3(
|
|
1508
|
-
() => /* @__PURE__ */
|
|
1509
|
-
/* @__PURE__ */
|
|
1510
|
-
/* @__PURE__ */
|
|
1511
|
-
/* @__PURE__ */
|
|
1512
|
-
/* @__PURE__ */
|
|
1513
|
-
/* @__PURE__ */
|
|
1514
|
-
/* @__PURE__ */
|
|
1515
|
-
/* @__PURE__ */
|
|
1647
|
+
() => /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
1648
|
+
/* @__PURE__ */ jsx15(Arrows, { id: arrowId }),
|
|
1649
|
+
/* @__PURE__ */ jsx15(SectionShapes, { geometry }),
|
|
1650
|
+
/* @__PURE__ */ jsx15(SectionHeadings, { geometry }),
|
|
1651
|
+
/* @__PURE__ */ jsx15(FeatureBreak, { geometry }),
|
|
1652
|
+
/* @__PURE__ */ jsx15(FeatureDepth, { geometry, units }),
|
|
1653
|
+
/* @__PURE__ */ jsx15(OffsetOrdinates, { geometry, units, arrowId }),
|
|
1654
|
+
/* @__PURE__ */ jsx15(HeightOrdinates, { geometry, units })
|
|
1516
1655
|
] }),
|
|
1517
1656
|
[arrowId, geometry, units]
|
|
1518
1657
|
);
|
|
1519
|
-
return /* @__PURE__ */
|
|
1658
|
+
return /* @__PURE__ */ jsxs12(
|
|
1520
1659
|
"svg",
|
|
1521
1660
|
{
|
|
1522
1661
|
viewBox: `0 0 ${width} ${geometry.height}`,
|
|
@@ -1529,17 +1668,17 @@ var ReachSection = ({
|
|
|
1529
1668
|
onPointerLeave: () => setHover(null),
|
|
1530
1669
|
children: [
|
|
1531
1670
|
drawing,
|
|
1532
|
-
reading ? /* @__PURE__ */
|
|
1671
|
+
reading ? /* @__PURE__ */ jsx15(ReadingMark, { geometry, reading, units }) : null
|
|
1533
1672
|
]
|
|
1534
1673
|
}
|
|
1535
1674
|
);
|
|
1536
1675
|
};
|
|
1537
1676
|
|
|
1538
1677
|
// src/reach/use-element-size.ts
|
|
1539
|
-
import { useLayoutEffect, useRef as
|
|
1678
|
+
import { useLayoutEffect, useRef as useRef5, useState as useState10 } from "react";
|
|
1540
1679
|
var useElementSize = () => {
|
|
1541
|
-
const ref =
|
|
1542
|
-
const [size, setSize] =
|
|
1680
|
+
const ref = useRef5(null);
|
|
1681
|
+
const [size, setSize] = useState10({ width: 0, height: 0 });
|
|
1543
1682
|
useLayoutEffect(() => {
|
|
1544
1683
|
const element = ref.current;
|
|
1545
1684
|
if (!element) return;
|
|
@@ -1557,12 +1696,12 @@ var useElementSize = () => {
|
|
|
1557
1696
|
};
|
|
1558
1697
|
|
|
1559
1698
|
// src/reach/reach-chart.tsx
|
|
1560
|
-
import { Fragment as Fragment6, jsx as
|
|
1699
|
+
import { Fragment as Fragment6, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1561
1700
|
var CHART_MIN_W = 200;
|
|
1562
1701
|
var DRAWING_MIN_W = 240;
|
|
1563
1702
|
var ReachChart = ({ curve, units, feature }) => {
|
|
1564
1703
|
const [ref, size] = useElementSize();
|
|
1565
|
-
return /* @__PURE__ */
|
|
1704
|
+
return /* @__PURE__ */ jsx16("div", { ref, className: "w-full", children: /* @__PURE__ */ jsx16(
|
|
1566
1705
|
ReachSection,
|
|
1567
1706
|
{
|
|
1568
1707
|
curve,
|
|
@@ -1580,7 +1719,7 @@ var CutNote = ({
|
|
|
1580
1719
|
if (!trimmed.cut) return null;
|
|
1581
1720
|
const drawnTo = trimmed.curve.offsets[trimmed.curve.offsets.length - 1] ?? 0;
|
|
1582
1721
|
const readTo = curve.offsets[curve.offsets.length - 1] ?? 0;
|
|
1583
|
-
return /* @__PURE__ */
|
|
1722
|
+
return /* @__PURE__ */ jsxs13(Fragment6, { children: [
|
|
1584
1723
|
" ",
|
|
1585
1724
|
"It is at full height from ",
|
|
1586
1725
|
lengthValue(drawnTo, units),
|
|
@@ -1595,13 +1734,13 @@ var CutNote = ({
|
|
|
1595
1734
|
};
|
|
1596
1735
|
var ReachDrawing = ({ curve, units, feature }) => {
|
|
1597
1736
|
const [ref, size] = useElementSize();
|
|
1598
|
-
return /* @__PURE__ */
|
|
1599
|
-
/* @__PURE__ */
|
|
1600
|
-
/* @__PURE__ */
|
|
1737
|
+
return /* @__PURE__ */ jsxs13("div", { ref, className: "flex flex-col gap-3 p-4", children: [
|
|
1738
|
+
/* @__PURE__ */ jsxs13("figure", { className: "flex flex-col gap-1", children: [
|
|
1739
|
+
/* @__PURE__ */ jsxs13("figcaption", { className: "text-2xs font-semibold text-gray-400 uppercase dark:text-zinc-500", children: [
|
|
1601
1740
|
"Section at the wall \xB7 to scale \xB7 ",
|
|
1602
1741
|
unitLabel(units)
|
|
1603
1742
|
] }),
|
|
1604
|
-
/* @__PURE__ */
|
|
1743
|
+
/* @__PURE__ */ jsx16(
|
|
1605
1744
|
ReachSection,
|
|
1606
1745
|
{
|
|
1607
1746
|
curve,
|
|
@@ -1611,18 +1750,875 @@ var ReachDrawing = ({ curve, units, feature }) => {
|
|
|
1611
1750
|
}
|
|
1612
1751
|
)
|
|
1613
1752
|
] }),
|
|
1614
|
-
/* @__PURE__ */
|
|
1753
|
+
/* @__PURE__ */ jsxs13("p", { className: "text-2xs text-gray-400 dark:text-zinc-500", children: [
|
|
1615
1754
|
"Point at the walls to read them: the distance from the feature, then the reach a tool needs there.",
|
|
1616
|
-
/* @__PURE__ */
|
|
1755
|
+
/* @__PURE__ */ jsx16(CutNote, { curve, units })
|
|
1617
1756
|
] })
|
|
1618
1757
|
] });
|
|
1619
1758
|
};
|
|
1759
|
+
|
|
1760
|
+
// src/feature-panel/fold-store.ts
|
|
1761
|
+
var storageFolds = (storage, prefix) => ({
|
|
1762
|
+
read: (id) => {
|
|
1763
|
+
try {
|
|
1764
|
+
const stored = storage?.getItem(`${prefix}${id}`);
|
|
1765
|
+
return stored === "open" ? true : stored === "shut" ? false : void 0;
|
|
1766
|
+
} catch {
|
|
1767
|
+
return void 0;
|
|
1768
|
+
}
|
|
1769
|
+
},
|
|
1770
|
+
write: (id, open) => {
|
|
1771
|
+
try {
|
|
1772
|
+
storage?.setItem(`${prefix}${id}`, open ? "open" : "shut");
|
|
1773
|
+
} catch {
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
});
|
|
1777
|
+
|
|
1778
|
+
// src/feature-panel/feature-details.tsx
|
|
1779
|
+
import { useCallback as useCallback2, useMemo as useMemo7, useState as useState13 } from "react";
|
|
1780
|
+
import { CrosshairIcon, InfoIcon } from "@phosphor-icons/react";
|
|
1781
|
+
import { Button as Button3, Tooltip, cn as cn12 } from "@toolpath/ui";
|
|
1782
|
+
|
|
1783
|
+
// src/feature-panel/feature-name.tsx
|
|
1784
|
+
import { cn as cn9 } from "@toolpath/ui";
|
|
1785
|
+
|
|
1786
|
+
// src/feature-panel/look.ts
|
|
1787
|
+
var resolveLook = (look) => ({
|
|
1788
|
+
rules: look?.rules ?? "sentence",
|
|
1789
|
+
selected: look?.selected ?? "grey",
|
|
1790
|
+
muted: look?.muted ?? "pale"
|
|
1791
|
+
});
|
|
1792
|
+
var secondaryText = (look) => look.muted === "strong" ? "text-gray dark:text-zinc-300" : "text-gray-400 dark:text-zinc-400";
|
|
1793
|
+
var faintText = (look) => look.muted === "strong" ? "text-gray dark:text-zinc-300" : "text-gray-300 dark:text-zinc-500";
|
|
1794
|
+
|
|
1795
|
+
// src/feature-panel/feature-name.tsx
|
|
1796
|
+
import { Fragment as Fragment7, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1797
|
+
var FeatureName = ({ feature, label, look }) => /* @__PURE__ */ jsxs14(Fragment7, { children: [
|
|
1798
|
+
label ?? featureTypeLabel(feature.featureType),
|
|
1799
|
+
" ",
|
|
1800
|
+
/* @__PURE__ */ jsxs14("span", { className: cn9("font-normal", faintText(look)), children: [
|
|
1801
|
+
"from ",
|
|
1802
|
+
directionLabel(feature.machiningDirection)
|
|
1803
|
+
] })
|
|
1804
|
+
] });
|
|
1805
|
+
var RequiredBadge = () => /* @__PURE__ */ jsx17("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" });
|
|
1806
|
+
|
|
1807
|
+
// src/feature-panel/fold-section.tsx
|
|
1808
|
+
import { useState as useState11 } from "react";
|
|
1809
|
+
import { CaretRightIcon as CaretRightIcon3 } from "@phosphor-icons/react";
|
|
1810
|
+
import { cn as cn10 } from "@toolpath/ui";
|
|
1811
|
+
import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1812
|
+
var FoldSection = ({
|
|
1813
|
+
id,
|
|
1814
|
+
title: title2,
|
|
1815
|
+
action,
|
|
1816
|
+
defaultOpen = true,
|
|
1817
|
+
folds,
|
|
1818
|
+
className,
|
|
1819
|
+
children
|
|
1820
|
+
}) => {
|
|
1821
|
+
const [open, setOpen] = useState11(() => folds?.read(id) ?? defaultOpen);
|
|
1822
|
+
return /* @__PURE__ */ jsxs15("section", { className: cn10("flex flex-col gap-1", className), children: [
|
|
1823
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1", children: [
|
|
1824
|
+
/* @__PURE__ */ jsxs15(
|
|
1825
|
+
"button",
|
|
1826
|
+
{
|
|
1827
|
+
type: "button",
|
|
1828
|
+
"aria-expanded": open,
|
|
1829
|
+
onClick: () => {
|
|
1830
|
+
setOpen(!open);
|
|
1831
|
+
folds?.write(id, !open);
|
|
1832
|
+
},
|
|
1833
|
+
className: cn10(
|
|
1834
|
+
"flex min-w-0 flex-1 cursor-pointer items-center gap-1 rounded text-left text-2xs font-semibold text-gray-400 uppercase",
|
|
1835
|
+
"hover:text-gray-600 dark:text-zinc-500 dark:hover:text-zinc-300",
|
|
1836
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-info/75"
|
|
1837
|
+
),
|
|
1838
|
+
children: [
|
|
1839
|
+
/* @__PURE__ */ jsx18(
|
|
1840
|
+
CaretRightIcon3,
|
|
1841
|
+
{
|
|
1842
|
+
weight: "bold",
|
|
1843
|
+
className: cn10("size-3 shrink-0 transition-transform duration-150", open && "rotate-90")
|
|
1844
|
+
}
|
|
1845
|
+
),
|
|
1846
|
+
/* @__PURE__ */ jsx18("span", { className: "truncate", children: title2 })
|
|
1847
|
+
]
|
|
1848
|
+
}
|
|
1849
|
+
),
|
|
1850
|
+
action
|
|
1851
|
+
] }),
|
|
1852
|
+
open ? children : null
|
|
1853
|
+
] });
|
|
1854
|
+
};
|
|
1855
|
+
|
|
1856
|
+
// src/feature-panel/read-state.tsx
|
|
1857
|
+
import { useEffect as useEffect4, useState as useState12 } from "react";
|
|
1858
|
+
import { Button as Button2 } from "@toolpath/ui";
|
|
1859
|
+
import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1860
|
+
var Reading = ({ children }) => /* @__PURE__ */ jsx19("p", { className: "text-sm text-gray-400 dark:text-zinc-400", role: "status", children });
|
|
1861
|
+
var ReadFailure = ({
|
|
1862
|
+
failure
|
|
1863
|
+
}) => {
|
|
1864
|
+
const waiting = useWaiting(failure.retryAt);
|
|
1865
|
+
return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-start gap-2 text-sm", children: [
|
|
1866
|
+
/* @__PURE__ */ jsx19("p", { className: "text-danger", role: "alert", children: failure.message }),
|
|
1867
|
+
failure.retry ? /* @__PURE__ */ jsx19(Button2, { variant: "secondary", size: "sm", disabled: waiting, onClick: failure.retry, children: "Retry" }) : null
|
|
1868
|
+
] });
|
|
1869
|
+
};
|
|
1870
|
+
var useWaiting = (until) => {
|
|
1871
|
+
const [passed, setPassed] = useState12(void 0);
|
|
1872
|
+
useEffect4(() => {
|
|
1873
|
+
if (until === void 0) return;
|
|
1874
|
+
const timer = setTimeout(() => setPassed(until), Math.max(until - Date.now(), 0));
|
|
1875
|
+
return () => clearTimeout(timer);
|
|
1876
|
+
}, [until]);
|
|
1877
|
+
return until !== void 0 && passed !== until;
|
|
1878
|
+
};
|
|
1879
|
+
|
|
1880
|
+
// src/feature-panel/pop-outs.tsx
|
|
1881
|
+
import { useMemo as useMemo6 } from "react";
|
|
1882
|
+
import {
|
|
1883
|
+
ArrowSquareOutIcon,
|
|
1884
|
+
BracketsCurlyIcon,
|
|
1885
|
+
ChartLineIcon,
|
|
1886
|
+
TableIcon
|
|
1887
|
+
} from "@phosphor-icons/react";
|
|
1888
|
+
import { IconButton as IconButton3 } from "@toolpath/ui";
|
|
1889
|
+
|
|
1890
|
+
// src/feature-panel/record-sections.tsx
|
|
1891
|
+
import { useMemo as useMemo5 } from "react";
|
|
1892
|
+
import { CheckIcon as CheckIcon3, CopyIcon as CopyIcon2 } from "@phosphor-icons/react";
|
|
1893
|
+
import { IconButton as IconButton2, cn as cn11 } from "@toolpath/ui";
|
|
1894
|
+
|
|
1895
|
+
// src/model/feature-record.ts
|
|
1896
|
+
var MAX_DATASHEET_FIELDS = 500;
|
|
1897
|
+
var formatLeaf = (value) => typeof value === "number" ? String(Number(value.toFixed(4))) : typeof value === "string" ? value : value === null ? "null" : String(value);
|
|
1898
|
+
var datasheetFields = (datasheet) => {
|
|
1899
|
+
const fields = [];
|
|
1900
|
+
let more = false;
|
|
1901
|
+
const walk = (value, path) => {
|
|
1902
|
+
if (fields.length >= MAX_DATASHEET_FIELDS) {
|
|
1903
|
+
more = true;
|
|
1904
|
+
return;
|
|
1905
|
+
}
|
|
1906
|
+
if (Array.isArray(value)) {
|
|
1907
|
+
if (value.every((each) => typeof each !== "object" || each === null)) {
|
|
1908
|
+
fields.push({ path, value: value.length === 0 ? "[]" : value.map(formatLeaf).join(", ") });
|
|
1909
|
+
} else {
|
|
1910
|
+
value.forEach((each, index) => walk(each, `${path}[${index}]`));
|
|
1911
|
+
}
|
|
1912
|
+
} else if (typeof value === "object" && value !== null) {
|
|
1913
|
+
const entries = Object.entries(value);
|
|
1914
|
+
if (entries.length === 0) fields.push({ path, value: "{}" });
|
|
1915
|
+
for (const [key, each] of entries) walk(each, path ? `${path}.${key}` : key);
|
|
1916
|
+
} else {
|
|
1917
|
+
fields.push({ path, value: formatLeaf(value) });
|
|
1918
|
+
}
|
|
1919
|
+
};
|
|
1920
|
+
if (datasheet !== null && datasheet !== void 0) walk(datasheet, "");
|
|
1921
|
+
return { fields, more };
|
|
1922
|
+
};
|
|
1923
|
+
|
|
1924
|
+
// src/feature-panel/record-sections.tsx
|
|
1925
|
+
import { Fragment as Fragment8, jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1926
|
+
var COPIED_MS2 = 1500;
|
|
1927
|
+
var RecordSections = ({
|
|
1928
|
+
record,
|
|
1929
|
+
look,
|
|
1930
|
+
folds,
|
|
1931
|
+
popOut
|
|
1932
|
+
}) => {
|
|
1933
|
+
const value = record.status === "ready" ? record.value : null;
|
|
1934
|
+
const { fields, more } = useMemo5(() => datasheetFields(value?.datasheet), [value]);
|
|
1935
|
+
const json = useMemo5(() => value ? JSON.stringify(value, null, 2) : "", [value]);
|
|
1936
|
+
if (record.status === "ready" && !value) return null;
|
|
1937
|
+
const waiting = record.status === "loading" ? /* @__PURE__ */ jsx20(Reading, { children: "Reading the feature\u2019s record\u2026" }) : record.status === "error" ? /* @__PURE__ */ jsx20(ReadFailure, { failure: record }) : null;
|
|
1938
|
+
const count = more ? `${MAX_DATASHEET_FIELDS}+` : String(fields.length);
|
|
1939
|
+
return /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1940
|
+
/* @__PURE__ */ jsx20(
|
|
1941
|
+
FoldSection,
|
|
1942
|
+
{
|
|
1943
|
+
id: "datasheet",
|
|
1944
|
+
defaultOpen: false,
|
|
1945
|
+
title: value ? `All datasheet fields (${count})` : "All datasheet fields",
|
|
1946
|
+
action: value ? popOut?.("datasheet") : null,
|
|
1947
|
+
folds,
|
|
1948
|
+
children: waiting ?? /* @__PURE__ */ jsx20(DatasheetFields, { record: value, look })
|
|
1949
|
+
}
|
|
1950
|
+
),
|
|
1951
|
+
/* @__PURE__ */ jsx20(
|
|
1952
|
+
FoldSection,
|
|
1953
|
+
{
|
|
1954
|
+
id: "raw",
|
|
1955
|
+
defaultOpen: false,
|
|
1956
|
+
title: "Raw API record",
|
|
1957
|
+
action: value ? /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
1958
|
+
/* @__PURE__ */ jsx20(CopyButton, { text: json }),
|
|
1959
|
+
popOut?.("raw")
|
|
1960
|
+
] }) : null,
|
|
1961
|
+
folds,
|
|
1962
|
+
children: waiting ?? /* @__PURE__ */ jsx20(RawRecord, { json })
|
|
1963
|
+
}
|
|
1964
|
+
)
|
|
1965
|
+
] });
|
|
1966
|
+
};
|
|
1967
|
+
var DatasheetFields = ({ record, look, wide = false }) => {
|
|
1968
|
+
const { fields } = useMemo5(() => datasheetFields(record?.datasheet), [record]);
|
|
1969
|
+
return record?.datasheet ? /* @__PURE__ */ jsx20(
|
|
1970
|
+
"dl",
|
|
1971
|
+
{
|
|
1972
|
+
className: cn11(
|
|
1973
|
+
"grid grid-cols-[minmax(0,1fr)_auto] gap-y-0.5 text-xs",
|
|
1974
|
+
wide ? "gap-x-4 p-4" : "gap-x-3"
|
|
1975
|
+
),
|
|
1976
|
+
children: fields.map((field) => /* @__PURE__ */ jsxs17("div", { className: "contents", children: [
|
|
1977
|
+
/* @__PURE__ */ jsx20("dt", { className: cn11("truncate font-mono", secondaryText(look)), title: field.path, children: field.path }),
|
|
1978
|
+
/* @__PURE__ */ jsx20(
|
|
1979
|
+
"dd",
|
|
1980
|
+
{
|
|
1981
|
+
className: cn11(
|
|
1982
|
+
"truncate text-right font-mono text-gray-600 tabular-nums select-text dark:text-zinc-100",
|
|
1983
|
+
wide ? "max-w-60" : "max-w-40"
|
|
1984
|
+
),
|
|
1985
|
+
title: field.value,
|
|
1986
|
+
children: field.value
|
|
1987
|
+
}
|
|
1988
|
+
)
|
|
1989
|
+
] }, field.path))
|
|
1990
|
+
}
|
|
1991
|
+
) : /* @__PURE__ */ jsx20("p", { className: cn11("text-sm", secondaryText(look), wide && "p-4"), children: "The API sent no datasheet for this feature." });
|
|
1992
|
+
};
|
|
1993
|
+
var RawRecord = ({
|
|
1994
|
+
json,
|
|
1995
|
+
wide = false
|
|
1996
|
+
}) => /* @__PURE__ */ jsx20(
|
|
1997
|
+
"pre",
|
|
1998
|
+
{
|
|
1999
|
+
className: cn11(
|
|
2000
|
+
"font-mono text-2xs leading-relaxed text-gray-600 select-text dark:text-zinc-200",
|
|
2001
|
+
wide ? "p-4" : "max-h-80 overflow-auto rounded bg-gray-50 p-2 dark:bg-zinc-800/60"
|
|
2002
|
+
),
|
|
2003
|
+
children: json
|
|
2004
|
+
}
|
|
2005
|
+
);
|
|
2006
|
+
var CopyButton = ({ text }) => {
|
|
2007
|
+
const [copied, setCopied] = useTimedValue(COPIED_MS2);
|
|
2008
|
+
return /* @__PURE__ */ jsx20(
|
|
2009
|
+
IconButton2,
|
|
2010
|
+
{
|
|
2011
|
+
"aria-label": copied ? "Copied" : "Copy raw record",
|
|
2012
|
+
title: "Copy",
|
|
2013
|
+
variant: "muted",
|
|
2014
|
+
size: "sm",
|
|
2015
|
+
onClick: () => {
|
|
2016
|
+
void navigator.clipboard?.writeText(text).then(() => setCopied(true)).catch(() => void 0);
|
|
2017
|
+
},
|
|
2018
|
+
children: copied ? /* @__PURE__ */ jsx20(CheckIcon3, { weight: "bold" }) : /* @__PURE__ */ jsx20(CopyIcon2, { weight: "bold" })
|
|
2019
|
+
}
|
|
2020
|
+
);
|
|
2021
|
+
};
|
|
2022
|
+
|
|
2023
|
+
// src/feature-panel/pop-outs.tsx
|
|
2024
|
+
import { Fragment as Fragment9, jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2025
|
+
var TITLES = {
|
|
2026
|
+
reach: "Reach",
|
|
2027
|
+
datasheet: "All datasheet fields",
|
|
2028
|
+
raw: "Raw API record"
|
|
2029
|
+
};
|
|
2030
|
+
var LABELS = {
|
|
2031
|
+
reach: "Pop out the reach drawing",
|
|
2032
|
+
datasheet: "Pop out the datasheet fields",
|
|
2033
|
+
raw: "Pop out the raw record"
|
|
2034
|
+
};
|
|
2035
|
+
var PopOutButton = ({
|
|
2036
|
+
id,
|
|
2037
|
+
onOpen
|
|
2038
|
+
}) => /* @__PURE__ */ jsx21(
|
|
2039
|
+
IconButton3,
|
|
2040
|
+
{
|
|
2041
|
+
"aria-label": LABELS[id],
|
|
2042
|
+
title: "Pop out, larger",
|
|
2043
|
+
variant: "muted",
|
|
2044
|
+
size: "sm",
|
|
2045
|
+
onClick: () => onOpen(id),
|
|
2046
|
+
children: /* @__PURE__ */ jsx21(ArrowSquareOutIcon, { weight: "bold" })
|
|
2047
|
+
}
|
|
2048
|
+
);
|
|
2049
|
+
var PopOuts = ({
|
|
2050
|
+
open,
|
|
2051
|
+
onClose,
|
|
2052
|
+
Window,
|
|
2053
|
+
subtitle,
|
|
2054
|
+
record,
|
|
2055
|
+
units,
|
|
2056
|
+
profile,
|
|
2057
|
+
look
|
|
2058
|
+
}) => {
|
|
2059
|
+
const curve = useMemo6(() => readReachCurve(record?.datasheet), [record]);
|
|
2060
|
+
const json = useMemo6(() => record ? JSON.stringify(record, null, 2) : "", [record]);
|
|
2061
|
+
if (!record) return null;
|
|
2062
|
+
return /* @__PURE__ */ jsxs18(Fragment9, { children: [
|
|
2063
|
+
open.has("reach") && curve ? /* @__PURE__ */ jsx21(
|
|
2064
|
+
Window,
|
|
2065
|
+
{
|
|
2066
|
+
id: "reach",
|
|
2067
|
+
title: TITLES.reach,
|
|
2068
|
+
subtitle,
|
|
2069
|
+
icon: /* @__PURE__ */ jsx21(ChartLineIcon, { weight: "bold" }),
|
|
2070
|
+
onClose: () => onClose("reach"),
|
|
2071
|
+
children: /* @__PURE__ */ jsx21(ReachDrawing, { curve, units, feature: profile })
|
|
2072
|
+
}
|
|
2073
|
+
) : null,
|
|
2074
|
+
open.has("datasheet") ? /* @__PURE__ */ jsx21(
|
|
2075
|
+
Window,
|
|
2076
|
+
{
|
|
2077
|
+
id: "datasheet",
|
|
2078
|
+
title: TITLES.datasheet,
|
|
2079
|
+
subtitle,
|
|
2080
|
+
icon: /* @__PURE__ */ jsx21(TableIcon, { weight: "bold" }),
|
|
2081
|
+
onClose: () => onClose("datasheet"),
|
|
2082
|
+
children: /* @__PURE__ */ jsx21(DatasheetFields, { record, look, wide: true })
|
|
2083
|
+
}
|
|
2084
|
+
) : null,
|
|
2085
|
+
open.has("raw") ? /* @__PURE__ */ jsx21(
|
|
2086
|
+
Window,
|
|
2087
|
+
{
|
|
2088
|
+
id: "raw",
|
|
2089
|
+
title: TITLES.raw,
|
|
2090
|
+
subtitle,
|
|
2091
|
+
icon: /* @__PURE__ */ jsx21(BracketsCurlyIcon, { weight: "bold" }),
|
|
2092
|
+
action: /* @__PURE__ */ jsx21(CopyButton, { text: json }),
|
|
2093
|
+
onClose: () => onClose("raw"),
|
|
2094
|
+
children: /* @__PURE__ */ jsx21(RawRecord, { json, wide: true })
|
|
2095
|
+
}
|
|
2096
|
+
) : null
|
|
2097
|
+
] });
|
|
2098
|
+
};
|
|
2099
|
+
|
|
2100
|
+
// src/feature-panel/feature-details.tsx
|
|
2101
|
+
import { Fragment as Fragment10, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2102
|
+
var FeatureDetails = ({
|
|
2103
|
+
feature,
|
|
2104
|
+
units,
|
|
2105
|
+
directionColor,
|
|
2106
|
+
profile,
|
|
2107
|
+
label,
|
|
2108
|
+
required,
|
|
2109
|
+
onFrame,
|
|
2110
|
+
actions,
|
|
2111
|
+
status,
|
|
2112
|
+
children,
|
|
2113
|
+
rules,
|
|
2114
|
+
measurements,
|
|
2115
|
+
record,
|
|
2116
|
+
PopOut,
|
|
2117
|
+
look: lookOption,
|
|
2118
|
+
folds
|
|
2119
|
+
}) => {
|
|
2120
|
+
const look = resolveLook(lookOption);
|
|
2121
|
+
const name = /* @__PURE__ */ jsx22(FeatureName, { feature, label, look });
|
|
2122
|
+
const [out, setOut] = useState13(/* @__PURE__ */ new Set());
|
|
2123
|
+
const openOut = useCallback2((id) => setOut((was) => new Set(was).add(id)), []);
|
|
2124
|
+
const closeOut = useCallback2(
|
|
2125
|
+
(id) => setOut((was) => {
|
|
2126
|
+
const next = new Set(was);
|
|
2127
|
+
next.delete(id);
|
|
2128
|
+
return next;
|
|
2129
|
+
}),
|
|
2130
|
+
[]
|
|
2131
|
+
);
|
|
2132
|
+
const popOut = PopOut ? (id) => /* @__PURE__ */ jsx22(PopOutButton, { id, onOpen: openOut }) : void 0;
|
|
2133
|
+
return /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-4 p-4", children: [
|
|
2134
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-2", children: [
|
|
2135
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex items-start gap-2", children: [
|
|
2136
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
|
|
2137
|
+
/* @__PURE__ */ jsx22("h3", { className: "truncate text-sm font-semibold text-gray-600 dark:text-zinc-100", children: name }),
|
|
2138
|
+
/* @__PURE__ */ jsxs19("p", { className: cn12("flex flex-wrap items-center gap-1.5 text-xs", secondaryText(look)), children: [
|
|
2139
|
+
/* @__PURE__ */ jsx22(Swatch, { color: directionColor, className: "size-2.5" }),
|
|
2140
|
+
"Machined from ",
|
|
2141
|
+
directionLabel(feature.machiningDirection),
|
|
2142
|
+
required ? /* @__PURE__ */ jsx22(RequiredBadge, {}) : null,
|
|
2143
|
+
status
|
|
2144
|
+
] })
|
|
2145
|
+
] }),
|
|
2146
|
+
actions,
|
|
2147
|
+
onFrame ? /* @__PURE__ */ jsx22(Button3, { variant: "secondary", size: "sm", onClick: onFrame, className: "shrink-0", children: /* @__PURE__ */ jsxs19("span", { className: "flex items-center gap-1 whitespace-nowrap", children: [
|
|
2148
|
+
/* @__PURE__ */ jsx22(CrosshairIcon, { weight: "bold", className: "size-3.5" }),
|
|
2149
|
+
"Show this feature"
|
|
2150
|
+
] }) }) : null
|
|
2151
|
+
] }),
|
|
2152
|
+
children
|
|
2153
|
+
] }),
|
|
2154
|
+
/* @__PURE__ */ jsx22(FoldSection, { id: "rules", title: "Rules broken", folds, children: /* @__PURE__ */ jsx22(BrokenRuleList, { rules, look }) }),
|
|
2155
|
+
/* @__PURE__ */ jsx22(MeasurementSections, { measurements, look, folds }),
|
|
2156
|
+
/* @__PURE__ */ jsx22(
|
|
2157
|
+
ReachSection2,
|
|
2158
|
+
{
|
|
2159
|
+
record,
|
|
2160
|
+
units,
|
|
2161
|
+
profile,
|
|
2162
|
+
folds,
|
|
2163
|
+
action: popOut?.("reach")
|
|
2164
|
+
}
|
|
2165
|
+
),
|
|
2166
|
+
/* @__PURE__ */ jsx22(RecordSections, { record, look, folds, popOut }),
|
|
2167
|
+
PopOut ? /* @__PURE__ */ jsx22(
|
|
2168
|
+
PopOuts,
|
|
2169
|
+
{
|
|
2170
|
+
open: out,
|
|
2171
|
+
onClose: closeOut,
|
|
2172
|
+
Window: PopOut,
|
|
2173
|
+
subtitle: name,
|
|
2174
|
+
record: record.status === "ready" ? record.value : null,
|
|
2175
|
+
units,
|
|
2176
|
+
profile,
|
|
2177
|
+
look
|
|
2178
|
+
}
|
|
2179
|
+
) : null
|
|
2180
|
+
] });
|
|
2181
|
+
};
|
|
2182
|
+
var BrokenRuleList = ({
|
|
2183
|
+
rules,
|
|
2184
|
+
look
|
|
2185
|
+
}) => rules.length > 0 ? /* @__PURE__ */ jsx22("ul", { className: "flex flex-col gap-1", children: rules.map((rule) => /* @__PURE__ */ jsxs19(
|
|
2186
|
+
"li",
|
|
2187
|
+
{
|
|
2188
|
+
className: "flex items-start gap-2 text-sm text-gray-600 dark:text-zinc-100",
|
|
2189
|
+
children: [
|
|
2190
|
+
/* @__PURE__ */ jsx22(Swatch, { color: rule.color, className: "mt-0.5" }),
|
|
2191
|
+
/* @__PURE__ */ jsx22(Explained, { note: rule.note, children: /* @__PURE__ */ jsx22("span", { className: "min-w-0 flex-1", children: rule.text }) }),
|
|
2192
|
+
rule.figure ? /* @__PURE__ */ jsxs19(
|
|
2193
|
+
"span",
|
|
2194
|
+
{
|
|
2195
|
+
className: cn12(
|
|
2196
|
+
"shrink-0 tabular-nums",
|
|
2197
|
+
look.rules === "result" ? "font-semibold" : secondaryText(look)
|
|
2198
|
+
),
|
|
2199
|
+
style: look.rules === "result" ? { color: rule.color } : void 0,
|
|
2200
|
+
children: [
|
|
2201
|
+
rule.figure,
|
|
2202
|
+
look.rules === "result" && rule.limit ? /* @__PURE__ */ jsx22("span", { className: "ml-1 font-normal opacity-60", children: rule.limit }) : null
|
|
2203
|
+
]
|
|
2204
|
+
}
|
|
2205
|
+
) : null
|
|
2206
|
+
]
|
|
2207
|
+
},
|
|
2208
|
+
rule.key
|
|
2209
|
+
)) }) : /* @__PURE__ */ jsx22(None, { look });
|
|
2210
|
+
var Explained = ({ note, children }) => note ? /* @__PURE__ */ jsx22(Tooltip, { tip: note, side: "left", children: /* @__PURE__ */ jsx22(
|
|
2211
|
+
"span",
|
|
2212
|
+
{
|
|
2213
|
+
tabIndex: 0,
|
|
2214
|
+
className: "min-w-0 flex-1 rounded outline-none focus-visible:ring-2 focus-visible:ring-info/75",
|
|
2215
|
+
children
|
|
2216
|
+
}
|
|
2217
|
+
) }) : children;
|
|
2218
|
+
var None = ({ look }) => /* @__PURE__ */ jsx22("p", { className: cn12("text-sm", secondaryText(look)), children: "None" });
|
|
2219
|
+
var MeasurementSections = ({ measurements, look, folds }) => {
|
|
2220
|
+
if (measurements.status !== "ready") {
|
|
2221
|
+
return /* @__PURE__ */ jsx22(Fragment10, { children: /* @__PURE__ */ jsx22(FoldSection, { id: "measurements", title: "Measurements", folds, children: measurements.status === "loading" ? /* @__PURE__ */ jsx22(Reading, { children: "Reading the feature\u2019s datasheet\u2026" }) : /* @__PURE__ */ jsx22(ReadFailure, { failure: measurements }) }) });
|
|
2222
|
+
}
|
|
2223
|
+
const measured = measurements.value.filter((row) => !row.milling);
|
|
2224
|
+
const milling = measurements.value.filter((row) => row.milling);
|
|
2225
|
+
return /* @__PURE__ */ jsxs19(Fragment10, { children: [
|
|
2226
|
+
/* @__PURE__ */ jsx22(FoldSection, { id: "measurements", title: "Measurements", folds, children: /* @__PURE__ */ jsx22(MeasurementList, { rows: measured, look }) }),
|
|
2227
|
+
milling.length > 0 ? /* @__PURE__ */ jsx22(FoldSection, { id: "milling", title: "Milling considerations", folds, children: /* @__PURE__ */ jsx22(MeasurementList, { rows: milling, look }) }) : null
|
|
2228
|
+
] });
|
|
2229
|
+
};
|
|
2230
|
+
var MeasurementList = ({ rows, look }) => rows.length > 0 ? /* @__PURE__ */ jsx22("dl", { className: "grid grid-cols-[1fr_auto] items-center gap-x-3 gap-y-1 text-sm", children: rows.map((row) => /* @__PURE__ */ jsxs19("div", { className: "contents", children: [
|
|
2231
|
+
/* @__PURE__ */ jsxs19("dt", { className: cn12("flex items-center gap-1", secondaryText(look)), children: [
|
|
2232
|
+
row.label,
|
|
2233
|
+
/* @__PURE__ */ jsx22(Derivation, { lines: row.derivation, look })
|
|
2234
|
+
] }),
|
|
2235
|
+
/* @__PURE__ */ jsx22("dd", { className: "text-right text-gray-600 tabular-nums dark:text-zinc-100", title: row.alt, children: row.value })
|
|
2236
|
+
] }, row.key)) }) : /* @__PURE__ */ jsx22(None, { look });
|
|
2237
|
+
var Derivation = ({
|
|
2238
|
+
lines,
|
|
2239
|
+
look
|
|
2240
|
+
}) => lines.length > 0 ? /* @__PURE__ */ jsx22(
|
|
2241
|
+
Tooltip,
|
|
2242
|
+
{
|
|
2243
|
+
side: "left",
|
|
2244
|
+
hoverable: true,
|
|
2245
|
+
tip: /* @__PURE__ */ jsx22("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__ */ jsx22("span", { children: line }, index)) }),
|
|
2246
|
+
children: /* @__PURE__ */ jsx22(
|
|
2247
|
+
"button",
|
|
2248
|
+
{
|
|
2249
|
+
type: "button",
|
|
2250
|
+
"aria-label": "How this was measured",
|
|
2251
|
+
className: cn12(
|
|
2252
|
+
"shrink-0 rounded outline-none hover:text-gray-500 focus-visible:ring-2 focus-visible:ring-info/75 dark:hover:text-zinc-300",
|
|
2253
|
+
faintText(look)
|
|
2254
|
+
),
|
|
2255
|
+
children: /* @__PURE__ */ jsx22(InfoIcon, { weight: "bold", className: "size-3" })
|
|
2256
|
+
}
|
|
2257
|
+
)
|
|
2258
|
+
}
|
|
2259
|
+
) : null;
|
|
2260
|
+
var ReachSection2 = ({ record, units, profile, folds, action }) => {
|
|
2261
|
+
const curve = useMemo7(
|
|
2262
|
+
() => record.status === "ready" ? readReachCurve(record.value?.datasheet) : null,
|
|
2263
|
+
[record]
|
|
2264
|
+
);
|
|
2265
|
+
if (record.status === "ready" && !curve) return null;
|
|
2266
|
+
return /* @__PURE__ */ jsx22(FoldSection, { id: "reach", title: "Reach", folds, action: curve ? action : null, children: record.status === "loading" ? /* @__PURE__ */ jsx22(Reading, { children: "Reading the reach curve\u2026" }) : record.status === "error" ? /* @__PURE__ */ jsx22(ReadFailure, { failure: record }) : curve ? /* @__PURE__ */ jsx22(ReachChart, { curve, units, feature: profile }) : null });
|
|
2267
|
+
};
|
|
2268
|
+
|
|
2269
|
+
// src/feature-panel/candidate-list.tsx
|
|
2270
|
+
import { XIcon } from "@phosphor-icons/react";
|
|
2271
|
+
import { IconButton as IconButton4, cn as cn13 } from "@toolpath/ui";
|
|
2272
|
+
import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2273
|
+
var candidateListKeys = listKeys("candidates");
|
|
2274
|
+
var faceLetter = (index) => String.fromCharCode(65 + index % 26);
|
|
2275
|
+
var FaceLetter = ({
|
|
2276
|
+
index,
|
|
2277
|
+
active
|
|
2278
|
+
}) => /* @__PURE__ */ jsx23(
|
|
2279
|
+
"span",
|
|
2280
|
+
{
|
|
2281
|
+
className: cn13(
|
|
2282
|
+
"inline-flex size-4 shrink-0 items-center justify-center rounded-sm text-2xs font-bold",
|
|
2283
|
+
active ? "bg-info text-white" : "bg-gray-100 text-gray-500 dark:bg-zinc-800 dark:text-zinc-300"
|
|
2284
|
+
),
|
|
2285
|
+
children: faceLetter(index)
|
|
2286
|
+
}
|
|
2287
|
+
);
|
|
2288
|
+
var CandidateList = ({
|
|
2289
|
+
rows,
|
|
2290
|
+
selected,
|
|
2291
|
+
onSelect,
|
|
2292
|
+
onHover,
|
|
2293
|
+
face,
|
|
2294
|
+
look: lookOption,
|
|
2295
|
+
folds
|
|
2296
|
+
}) => {
|
|
2297
|
+
const look = resolveLook(lookOption);
|
|
2298
|
+
const count = `Candidate features (${rows.length})`;
|
|
2299
|
+
return /* @__PURE__ */ jsx23("div", { className: "border-b border-gray-100 p-2 dark:border-zinc-800", children: /* @__PURE__ */ jsx23(
|
|
2300
|
+
FoldSection,
|
|
2301
|
+
{
|
|
2302
|
+
id: face ? `candidates-${faceLetter(face.index)}` : "candidates",
|
|
2303
|
+
title: face ? /* @__PURE__ */ jsxs20("span", { className: "flex items-center gap-1.5", children: [
|
|
2304
|
+
/* @__PURE__ */ jsx23(FaceLetter, { index: face.index, active: face.active }),
|
|
2305
|
+
count
|
|
2306
|
+
] }) : count,
|
|
2307
|
+
action: face?.onStop ? /* @__PURE__ */ jsx23(
|
|
2308
|
+
IconButton4,
|
|
2309
|
+
{
|
|
2310
|
+
"aria-label": `Stop comparing face ${faceLetter(face.index)}`,
|
|
2311
|
+
variant: "muted",
|
|
2312
|
+
size: "sm",
|
|
2313
|
+
onClick: face.onStop,
|
|
2314
|
+
children: /* @__PURE__ */ jsx23(XIcon, { weight: "bold" })
|
|
2315
|
+
}
|
|
2316
|
+
) : null,
|
|
2317
|
+
folds,
|
|
2318
|
+
className: "px-2",
|
|
2319
|
+
children: /* @__PURE__ */ jsx23("ul", { className: "-mx-2 flex flex-col gap-0.5", children: rows.map((row) => /* @__PURE__ */ jsx23(
|
|
2320
|
+
Row,
|
|
2321
|
+
{
|
|
2322
|
+
row,
|
|
2323
|
+
chosen: row.feature.tag === selected,
|
|
2324
|
+
onSelect,
|
|
2325
|
+
onHover,
|
|
2326
|
+
look
|
|
2327
|
+
},
|
|
2328
|
+
row.feature.tag
|
|
2329
|
+
)) })
|
|
2330
|
+
}
|
|
2331
|
+
) });
|
|
2332
|
+
};
|
|
2333
|
+
var Row = ({ row, chosen, onSelect, onHover, look }) => {
|
|
2334
|
+
const { feature } = row;
|
|
2335
|
+
const info = look.selected === "info";
|
|
2336
|
+
return /* @__PURE__ */ jsxs20(
|
|
2337
|
+
"li",
|
|
2338
|
+
{
|
|
2339
|
+
className: cn13(
|
|
2340
|
+
"flex items-center gap-1",
|
|
2341
|
+
info && "rounded border pr-1",
|
|
2342
|
+
info && (chosen ? "border-info/60 bg-info/15" : "border-transparent")
|
|
2343
|
+
),
|
|
2344
|
+
children: [
|
|
2345
|
+
/* @__PURE__ */ jsxs20(
|
|
2346
|
+
"button",
|
|
2347
|
+
{
|
|
2348
|
+
type: "button",
|
|
2349
|
+
"data-list-item": "candidates",
|
|
2350
|
+
"data-follow": true,
|
|
2351
|
+
"aria-pressed": chosen,
|
|
2352
|
+
onClick: () => onSelect(feature.tag),
|
|
2353
|
+
onPointerEnter: onHover ? () => onHover(feature.tag) : void 0,
|
|
2354
|
+
onPointerLeave: onHover ? () => onHover(null) : void 0,
|
|
2355
|
+
className: cn13(
|
|
2356
|
+
"flex min-w-0 flex-1 cursor-pointer flex-col rounded px-2 py-1.5 text-left text-sm",
|
|
2357
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-info/75",
|
|
2358
|
+
"text-gray-600 dark:text-zinc-200",
|
|
2359
|
+
info ? "hover:bg-gray-50 dark:hover:bg-zinc-800/60" : "hover:bg-gray-100 dark:hover:bg-zinc-800",
|
|
2360
|
+
chosen && (info ? "font-medium" : "bg-gray-100 font-semibold dark:bg-zinc-800")
|
|
2361
|
+
),
|
|
2362
|
+
children: [
|
|
2363
|
+
/* @__PURE__ */ jsxs20("span", { className: "flex w-full items-center gap-2", children: [
|
|
2364
|
+
row.color ? /* @__PURE__ */ jsx23(Swatch, { color: row.color }) : /* @__PURE__ */ jsx23("span", { "aria-hidden": true, className: "size-4 shrink-0" }),
|
|
2365
|
+
/* @__PURE__ */ jsx23("span", { className: "min-w-0 flex-1 truncate", children: /* @__PURE__ */ jsx23(FeatureName, { feature, label: row.label, look }) }),
|
|
2366
|
+
row.ruleCount ? /* @__PURE__ */ jsxs20("span", { className: cn13("text-2xs tabular-nums", secondaryText(look)), children: [
|
|
2367
|
+
row.ruleCount,
|
|
2368
|
+
" ",
|
|
2369
|
+
row.ruleCount === 1 ? "rule" : "rules"
|
|
2370
|
+
] }) : null,
|
|
2371
|
+
row.required ? /* @__PURE__ */ jsx23(RequiredBadge, {}) : null,
|
|
2372
|
+
row.detail ? /* @__PURE__ */ jsx23("span", { className: cn13("max-w-32 shrink-0 truncate text-xs", secondaryText(look)), children: row.detail }) : null
|
|
2373
|
+
] }),
|
|
2374
|
+
row.note ? /* @__PURE__ */ jsx23("span", { className: "pl-6 text-2xs text-warning-darken", children: row.note }) : null
|
|
2375
|
+
]
|
|
2376
|
+
}
|
|
2377
|
+
),
|
|
2378
|
+
row.action
|
|
2379
|
+
]
|
|
2380
|
+
}
|
|
2381
|
+
);
|
|
2382
|
+
};
|
|
2383
|
+
|
|
2384
|
+
// src/feature-panel/comparison-table.tsx
|
|
2385
|
+
import { useMemo as useMemo8 } from "react";
|
|
2386
|
+
import { cn as cn14 } from "@toolpath/ui";
|
|
2387
|
+
import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2388
|
+
var DASH = "\u2014";
|
|
2389
|
+
var ComparisonTable = ({
|
|
2390
|
+
faces,
|
|
2391
|
+
active,
|
|
2392
|
+
onSelect,
|
|
2393
|
+
onHover,
|
|
2394
|
+
look: lookOption,
|
|
2395
|
+
folds
|
|
2396
|
+
}) => {
|
|
2397
|
+
const look = resolveLook(lookOption);
|
|
2398
|
+
const rows = useMemo8(() => {
|
|
2399
|
+
const row = (key, label, read) => {
|
|
2400
|
+
const values = faces.map((face) => face.feature ? read(face, face.feature) : null);
|
|
2401
|
+
const texts = values.map((value) => value?.text ?? DASH);
|
|
2402
|
+
return {
|
|
2403
|
+
key,
|
|
2404
|
+
label,
|
|
2405
|
+
cells: values.map((value) => value?.node ?? value?.text ?? DASH),
|
|
2406
|
+
differs: new Set(texts).size > 1
|
|
2407
|
+
};
|
|
2408
|
+
};
|
|
2409
|
+
const fixed = [
|
|
2410
|
+
row("type", "Type", (_, feature) => ({ text: featureTypeLabel(feature.featureType) })),
|
|
2411
|
+
row("direction", "Machined from", (face, feature) => {
|
|
2412
|
+
const text = directionLabel(feature.machiningDirection);
|
|
2413
|
+
return {
|
|
2414
|
+
text,
|
|
2415
|
+
node: /* @__PURE__ */ jsxs21("span", { className: "inline-flex items-center gap-1", children: [
|
|
2416
|
+
/* @__PURE__ */ jsx24(Swatch, { color: face.directionColor, className: "size-2.5" }),
|
|
2417
|
+
text
|
|
2418
|
+
] })
|
|
2419
|
+
};
|
|
2420
|
+
}),
|
|
2421
|
+
...faces.some((face) => face.required !== void 0) ? [row("required", "Required", (face) => ({ text: face.required ? "Yes" : "No" }))] : [],
|
|
2422
|
+
row("rules", "Rules broken", (face) => ({
|
|
2423
|
+
text: face.rules.map((rule) => rule.key).join(",") || "None",
|
|
2424
|
+
node: face.rules.length > 0 ? /* @__PURE__ */ jsxs21(
|
|
2425
|
+
"span",
|
|
2426
|
+
{
|
|
2427
|
+
className: "inline-flex items-center gap-0.5",
|
|
2428
|
+
title: face.rules.map((rule) => rule.text).join("\n"),
|
|
2429
|
+
children: [
|
|
2430
|
+
face.rules.map((rule) => /* @__PURE__ */ jsx24(Swatch, { color: rule.color, className: "size-2.5" }, rule.key)),
|
|
2431
|
+
/* @__PURE__ */ jsx24("span", { className: "ml-0.5", children: face.rules.length })
|
|
2432
|
+
]
|
|
2433
|
+
}
|
|
2434
|
+
) : "None"
|
|
2435
|
+
}))
|
|
2436
|
+
];
|
|
2437
|
+
const labels = /* @__PURE__ */ new Map();
|
|
2438
|
+
for (const face of faces)
|
|
2439
|
+
for (const each of face.measurements) labels.set(each.key, labels.get(each.key) ?? each.label);
|
|
2440
|
+
const measured = [...labels].map(([key, label]) => {
|
|
2441
|
+
const values = faces.map((face) => face.measurements.find((each) => each.key === key));
|
|
2442
|
+
return {
|
|
2443
|
+
key,
|
|
2444
|
+
label,
|
|
2445
|
+
cells: values.map((value) => value ? /* @__PURE__ */ jsx24("span", { title: value.alt, children: value.value }) : DASH),
|
|
2446
|
+
differs: new Set(values.map((value) => value?.value ?? DASH)).size > 1
|
|
2447
|
+
};
|
|
2448
|
+
});
|
|
2449
|
+
return [...fixed, ...measured];
|
|
2450
|
+
}, [faces]);
|
|
2451
|
+
return /* @__PURE__ */ jsx24("div", { className: "border-b border-gray-100 p-4 dark:border-zinc-800", children: /* @__PURE__ */ jsx24(FoldSection, { id: "comparison", title: "Comparison", folds, children: /* @__PURE__ */ jsx24("div", { className: "-mx-1 overflow-x-auto", children: /* @__PURE__ */ jsxs21("table", { className: "w-full border-separate border-spacing-x-1 border-spacing-y-0.5 text-sm", children: [
|
|
2452
|
+
/* @__PURE__ */ jsx24("thead", { children: /* @__PURE__ */ jsxs21("tr", { children: [
|
|
2453
|
+
/* @__PURE__ */ jsx24("th", { className: "w-0" }),
|
|
2454
|
+
faces.map(({ feature }, index) => /* @__PURE__ */ jsx24("th", { className: "text-left align-bottom font-normal", children: /* @__PURE__ */ jsxs21(
|
|
2455
|
+
"button",
|
|
2456
|
+
{
|
|
2457
|
+
type: "button",
|
|
2458
|
+
disabled: !feature,
|
|
2459
|
+
onClick: () => feature && onSelect(feature.tag, index),
|
|
2460
|
+
onPointerEnter: onHover ? () => onHover(feature?.tag ?? null) : void 0,
|
|
2461
|
+
onPointerLeave: onHover ? () => onHover(null) : void 0,
|
|
2462
|
+
className: cn14(
|
|
2463
|
+
"flex w-full min-w-0 cursor-pointer items-center gap-1.5 rounded px-1 py-1 text-left text-xs",
|
|
2464
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-info/75",
|
|
2465
|
+
"text-gray-600 hover:bg-gray-100 dark:text-zinc-200 dark:hover:bg-zinc-800",
|
|
2466
|
+
index === active && "bg-gray-100 font-semibold dark:bg-zinc-800"
|
|
2467
|
+
),
|
|
2468
|
+
children: [
|
|
2469
|
+
/* @__PURE__ */ jsx24(FaceLetter, { index, active: index === active }),
|
|
2470
|
+
/* @__PURE__ */ jsx24("span", { className: "min-w-0 truncate", children: feature ? /* @__PURE__ */ jsx24(FeatureName, { feature, look }) : "No feature" })
|
|
2471
|
+
]
|
|
2472
|
+
}
|
|
2473
|
+
) }, index))
|
|
2474
|
+
] }) }),
|
|
2475
|
+
/* @__PURE__ */ jsx24("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs21("tr", { "data-differs": row.differs || void 0, children: [
|
|
2476
|
+
/* @__PURE__ */ jsx24(
|
|
2477
|
+
"th",
|
|
2478
|
+
{
|
|
2479
|
+
scope: "row",
|
|
2480
|
+
className: cn14(
|
|
2481
|
+
"pr-2 text-left align-top font-normal whitespace-nowrap",
|
|
2482
|
+
secondaryText(look)
|
|
2483
|
+
),
|
|
2484
|
+
children: row.label
|
|
2485
|
+
}
|
|
2486
|
+
),
|
|
2487
|
+
row.cells.map((cell, index) => /* @__PURE__ */ jsx24(
|
|
2488
|
+
"td",
|
|
2489
|
+
{
|
|
2490
|
+
className: cn14(
|
|
2491
|
+
"px-1 align-top tabular-nums whitespace-nowrap",
|
|
2492
|
+
row.differs ? "text-gray-600 dark:text-zinc-100" : "text-gray-400 dark:text-zinc-500"
|
|
2493
|
+
),
|
|
2494
|
+
children: cell
|
|
2495
|
+
},
|
|
2496
|
+
index
|
|
2497
|
+
))
|
|
2498
|
+
] }, row.key)) })
|
|
2499
|
+
] }) }) }) });
|
|
2500
|
+
};
|
|
2501
|
+
|
|
2502
|
+
// src/feature-panel/feature-panel.tsx
|
|
2503
|
+
import { CubeIcon, XIcon as XIcon2 } from "@phosphor-icons/react";
|
|
2504
|
+
import { IconButton as IconButton5, ScrollArea as ScrollArea2, cn as cn15 } from "@toolpath/ui";
|
|
2505
|
+
import { Fragment as Fragment11, jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2506
|
+
var title = (faces, active, group) => {
|
|
2507
|
+
if (faces.length > 1) return `Comparing ${faces.length} faces`;
|
|
2508
|
+
if (faces[active]?.region !== null && faces[active]?.region !== void 0)
|
|
2509
|
+
return "Features on this face";
|
|
2510
|
+
if (group !== void 0) return `${group} identical holes`;
|
|
2511
|
+
return "Feature";
|
|
2512
|
+
};
|
|
2513
|
+
var FeaturePanel = ({
|
|
2514
|
+
faces,
|
|
2515
|
+
active,
|
|
2516
|
+
group,
|
|
2517
|
+
comparison,
|
|
2518
|
+
onSelect,
|
|
2519
|
+
onDropFace,
|
|
2520
|
+
onHover,
|
|
2521
|
+
onClose,
|
|
2522
|
+
headerProps,
|
|
2523
|
+
className,
|
|
2524
|
+
look: lookOption,
|
|
2525
|
+
folds,
|
|
2526
|
+
children
|
|
2527
|
+
}) => {
|
|
2528
|
+
const look = resolveLook(lookOption);
|
|
2529
|
+
const comparing = faces.length > 1;
|
|
2530
|
+
const face = faces[active];
|
|
2531
|
+
const heading = title(faces, active, group);
|
|
2532
|
+
return /* @__PURE__ */ jsxs22(
|
|
2533
|
+
"section",
|
|
2534
|
+
{
|
|
2535
|
+
"aria-label": heading,
|
|
2536
|
+
"data-list-root": true,
|
|
2537
|
+
onKeyDown: (event) => {
|
|
2538
|
+
if (event.defaultPrevented || !event.currentTarget.contains(event.target)) return;
|
|
2539
|
+
if (event.key === "Escape") onClose();
|
|
2540
|
+
else candidateListKeys(event);
|
|
2541
|
+
},
|
|
2542
|
+
className: cn15(
|
|
2543
|
+
"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",
|
|
2544
|
+
"dark:bg-zinc-900/90 dark:ring-zinc-800",
|
|
2545
|
+
className
|
|
2546
|
+
),
|
|
2547
|
+
children: [
|
|
2548
|
+
/* @__PURE__ */ jsxs22(
|
|
2549
|
+
"header",
|
|
2550
|
+
{
|
|
2551
|
+
...headerProps,
|
|
2552
|
+
className: cn15(
|
|
2553
|
+
"flex items-center gap-2 border-b border-gray-100 py-2 pr-2 pl-4 select-none dark:border-zinc-800",
|
|
2554
|
+
headerProps?.className
|
|
2555
|
+
),
|
|
2556
|
+
children: [
|
|
2557
|
+
/* @__PURE__ */ jsx25(CubeIcon, { weight: "bold", className: cn15("size-5 shrink-0", secondaryText(look)) }),
|
|
2558
|
+
/* @__PURE__ */ jsx25("h2", { className: "flex-1 text-sm font-semibold text-gray-600 dark:text-zinc-100", children: heading }),
|
|
2559
|
+
/* @__PURE__ */ jsx25(IconButton5, { "aria-label": "Close", variant: "muted", onClick: onClose, children: /* @__PURE__ */ jsx25(XIcon2, { weight: "bold" }) })
|
|
2560
|
+
]
|
|
2561
|
+
}
|
|
2562
|
+
),
|
|
2563
|
+
/* @__PURE__ */ jsxs22(ScrollArea2, { className: "min-h-0 flex-1", children: [
|
|
2564
|
+
comparing ? /* @__PURE__ */ jsxs22(Fragment11, { children: [
|
|
2565
|
+
faces.map((each, index) => /* @__PURE__ */ jsx25(
|
|
2566
|
+
CandidateList,
|
|
2567
|
+
{
|
|
2568
|
+
rows: each.rows,
|
|
2569
|
+
selected: each.selected,
|
|
2570
|
+
onSelect: (tag) => onSelect(tag, index),
|
|
2571
|
+
onHover,
|
|
2572
|
+
face: {
|
|
2573
|
+
index,
|
|
2574
|
+
active: index === active,
|
|
2575
|
+
...onDropFace ? { onStop: () => onDropFace(index) } : {}
|
|
2576
|
+
},
|
|
2577
|
+
look: lookOption,
|
|
2578
|
+
folds
|
|
2579
|
+
},
|
|
2580
|
+
`${each.region ?? "list"}-${index}`
|
|
2581
|
+
)),
|
|
2582
|
+
comparison ? /* @__PURE__ */ jsx25(
|
|
2583
|
+
ComparisonTable,
|
|
2584
|
+
{
|
|
2585
|
+
faces: comparison,
|
|
2586
|
+
active,
|
|
2587
|
+
onSelect,
|
|
2588
|
+
onHover,
|
|
2589
|
+
look: lookOption,
|
|
2590
|
+
folds
|
|
2591
|
+
}
|
|
2592
|
+
) : null
|
|
2593
|
+
] }) : face && face.region !== null ? /* @__PURE__ */ jsx25(
|
|
2594
|
+
CandidateList,
|
|
2595
|
+
{
|
|
2596
|
+
rows: face.rows,
|
|
2597
|
+
selected: face.selected,
|
|
2598
|
+
onSelect: (tag) => onSelect(tag, active),
|
|
2599
|
+
onHover,
|
|
2600
|
+
look: lookOption,
|
|
2601
|
+
folds
|
|
2602
|
+
}
|
|
2603
|
+
) : null,
|
|
2604
|
+
face?.selected ? children : /* @__PURE__ */ jsx25("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." })
|
|
2605
|
+
] })
|
|
2606
|
+
]
|
|
2607
|
+
}
|
|
2608
|
+
);
|
|
2609
|
+
};
|
|
1620
2610
|
export {
|
|
2611
|
+
CandidateList,
|
|
2612
|
+
ComparisonTable,
|
|
2613
|
+
FeatureDetails,
|
|
2614
|
+
FeaturePanel,
|
|
1621
2615
|
ReachChart,
|
|
1622
2616
|
ReachDrawing,
|
|
1623
2617
|
RuleList,
|
|
1624
2618
|
Swatch,
|
|
2619
|
+
candidateListKeys,
|
|
1625
2620
|
isField,
|
|
1626
2621
|
listKeys,
|
|
1627
|
-
ruleListKeys
|
|
2622
|
+
ruleListKeys,
|
|
2623
|
+
storageFolds
|
|
1628
2624
|
};
|