@ai-matrx/associations 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -0
- package/dist/core/index.cjs +71 -0
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +19 -1
- package/dist/core/index.d.ts +19 -1
- package/dist/core/index.js +71 -0
- package/dist/core/index.js.map +1 -1
- package/dist/index.cjs +6 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -2
- package/dist/index.d.ts +50 -2
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +747 -0
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +85 -2
- package/dist/react/index.d.ts +85 -2
- package/dist/react/index.js +784 -0
- package/dist/react/index.js.map +1 -1
- package/package.json +4 -4
package/dist/react/index.cjs
CHANGED
|
@@ -25,6 +25,7 @@ __export(react_exports, {
|
|
|
25
25
|
AssociationCaptureToolbar: () => AssociationCaptureToolbar,
|
|
26
26
|
AssociationCard: () => AssociationCard,
|
|
27
27
|
AssociationCardGrid: () => AssociationCardGrid,
|
|
28
|
+
AssociationEntitySelect: () => AssociationEntitySelect,
|
|
28
29
|
AssociationList: () => AssociationList,
|
|
29
30
|
AssociationPicker: () => AssociationPicker,
|
|
30
31
|
AssociationWindow: () => AssociationWindow,
|
|
@@ -32,6 +33,8 @@ __export(react_exports, {
|
|
|
32
33
|
AttachedItemsSheet: () => AttachedItemsSheet,
|
|
33
34
|
CONTENT_ROLES: () => CONTENT_ROLES,
|
|
34
35
|
CaptureToolbarAction: () => CaptureToolbarAction,
|
|
36
|
+
CategorySelect: () => CategorySelect,
|
|
37
|
+
CategoryTagPicker: () => CategoryTagPicker,
|
|
35
38
|
DefaultEntityIcon: () => DefaultEntityIcon,
|
|
36
39
|
DoorRef: () => DoorRef,
|
|
37
40
|
PrimaryEntityProvider: () => PrimaryEntityProvider,
|
|
@@ -558,6 +561,7 @@ var ENTITY_TYPE_TOKENS = [
|
|
|
558
561
|
"platform_actor_session",
|
|
559
562
|
"platform_actor_token",
|
|
560
563
|
"platform_actor_token_event",
|
|
564
|
+
"platform_continued_access",
|
|
561
565
|
"platform_outcome_event",
|
|
562
566
|
"platform_outsider_consumer",
|
|
563
567
|
"platform_saved_view",
|
|
@@ -586,6 +590,7 @@ var ENTITY_TYPE_TOKENS = [
|
|
|
586
590
|
"research_tag",
|
|
587
591
|
"research_template",
|
|
588
592
|
"research_topic",
|
|
593
|
+
"route_manifest_entry",
|
|
589
594
|
"rulebook",
|
|
590
595
|
"sandbox_instance",
|
|
591
596
|
"sch_agent_task",
|
|
@@ -664,6 +669,7 @@ var ENTITY_TYPE_TOKENS = [
|
|
|
664
669
|
"seo_topic",
|
|
665
670
|
"seo_web_analytics_daily",
|
|
666
671
|
"shared_canvas_item",
|
|
672
|
+
"short_link",
|
|
667
673
|
"skill",
|
|
668
674
|
"skill_render_definition",
|
|
669
675
|
"sms_consent",
|
|
@@ -1467,6 +1473,27 @@ function ExternalLinkIcon(props) {
|
|
|
1467
1473
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" })
|
|
1468
1474
|
] });
|
|
1469
1475
|
}
|
|
1476
|
+
function ChevronDownIcon(props) {
|
|
1477
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { ...base(props), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m6 9 6 6 6-6" }) });
|
|
1478
|
+
}
|
|
1479
|
+
function ChevronsUpDownIcon(props) {
|
|
1480
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { ...base(props), children: [
|
|
1481
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m7 15 5 5 5-5" }),
|
|
1482
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m7 9 5-5 5 5" })
|
|
1483
|
+
] });
|
|
1484
|
+
}
|
|
1485
|
+
function CornerDownRightIcon(props) {
|
|
1486
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { ...base(props), children: [
|
|
1487
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "15 10 20 15 15 20" }),
|
|
1488
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M4 4v7a4 4 0 0 0 4 4h12" })
|
|
1489
|
+
] });
|
|
1490
|
+
}
|
|
1491
|
+
function TagIcon(props) {
|
|
1492
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { ...base(props), children: [
|
|
1493
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z" }),
|
|
1494
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "7.5", cy: "7.5", r: ".5", fill: "currentColor" })
|
|
1495
|
+
] });
|
|
1496
|
+
}
|
|
1470
1497
|
function DefaultEntityIcon(props) {
|
|
1471
1498
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { ...base(props), children: [
|
|
1472
1499
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z" }),
|
|
@@ -3155,4 +3182,724 @@ function CaptureToolbarAction({
|
|
|
3155
3182
|
}
|
|
3156
3183
|
);
|
|
3157
3184
|
}
|
|
3185
|
+
|
|
3186
|
+
// src/react/components/AssociationEntitySelect.tsx
|
|
3187
|
+
var import_react17 = require("react");
|
|
3188
|
+
var import_design_system10 = require("@ai-matrx/design-system");
|
|
3189
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
3190
|
+
function AssociationEntitySelect({
|
|
3191
|
+
token,
|
|
3192
|
+
adapter,
|
|
3193
|
+
className,
|
|
3194
|
+
labelClassName,
|
|
3195
|
+
align = "end",
|
|
3196
|
+
showIcon = true,
|
|
3197
|
+
renameActivation = "click",
|
|
3198
|
+
emptyLabel,
|
|
3199
|
+
iconClassName,
|
|
3200
|
+
createSlot
|
|
3201
|
+
}) {
|
|
3202
|
+
const store = useAssociationsStore();
|
|
3203
|
+
const { entityDoors } = useAssociationsUiPorts();
|
|
3204
|
+
const notifier = useNotifier();
|
|
3205
|
+
const info = store.registry.getEntityInfo(token);
|
|
3206
|
+
const InfoIcon = info.Icon ?? DefaultEntityIcon;
|
|
3207
|
+
const DoorControls = entityDoors?.DoorControls;
|
|
3208
|
+
const { items, activeId } = adapter;
|
|
3209
|
+
const active = items.find((i) => i.id === activeId) ?? null;
|
|
3210
|
+
const activeIndex = active ? items.indexOf(active) : -1;
|
|
3211
|
+
const [open, setOpen] = (0, import_react17.useState)(false);
|
|
3212
|
+
const [query, setQuery] = (0, import_react17.useState)("");
|
|
3213
|
+
const [creating, setCreating] = (0, import_react17.useState)(false);
|
|
3214
|
+
const [draftName, setDraftName] = (0, import_react17.useState)("");
|
|
3215
|
+
const [busy, setBusy] = (0, import_react17.useState)(false);
|
|
3216
|
+
const entityLabel = info.label.toLowerCase();
|
|
3217
|
+
const close = () => {
|
|
3218
|
+
setOpen(false);
|
|
3219
|
+
setQuery("");
|
|
3220
|
+
setCreating(false);
|
|
3221
|
+
setDraftName("");
|
|
3222
|
+
};
|
|
3223
|
+
const create = async (title) => {
|
|
3224
|
+
const name = title.trim();
|
|
3225
|
+
if (!name || busy || !adapter.createAndAttach) return;
|
|
3226
|
+
setBusy(true);
|
|
3227
|
+
const id = await adapter.createAndAttach(name);
|
|
3228
|
+
setBusy(false);
|
|
3229
|
+
if (id) close();
|
|
3230
|
+
else notifier.error(`Couldn't create the ${entityLabel}`);
|
|
3231
|
+
};
|
|
3232
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3233
|
+
"div",
|
|
3234
|
+
{
|
|
3235
|
+
className: (0, import_design_system10.cn)(
|
|
3236
|
+
"group/entity-ref flex min-w-0 items-center gap-0.5",
|
|
3237
|
+
className
|
|
3238
|
+
),
|
|
3239
|
+
children: [
|
|
3240
|
+
showIcon ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3241
|
+
InfoIcon,
|
|
3242
|
+
{
|
|
3243
|
+
className: (0, import_design_system10.cn)(
|
|
3244
|
+
"size-3.5 shrink-0",
|
|
3245
|
+
iconClassName ?? "text-muted-foreground"
|
|
3246
|
+
),
|
|
3247
|
+
"aria-hidden": true
|
|
3248
|
+
}
|
|
3249
|
+
) : null,
|
|
3250
|
+
active ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3251
|
+
import_design_system10.EditableLabel,
|
|
3252
|
+
{
|
|
3253
|
+
value: active.title,
|
|
3254
|
+
onCommit: async (next) => {
|
|
3255
|
+
const ok = await adapter.rename(active.id, next);
|
|
3256
|
+
if (!ok) {
|
|
3257
|
+
notifier.error(`Couldn't rename the ${entityLabel}`);
|
|
3258
|
+
throw new Error("rename failed");
|
|
3259
|
+
}
|
|
3260
|
+
},
|
|
3261
|
+
commitMode: "await",
|
|
3262
|
+
activation: renameActivation,
|
|
3263
|
+
ariaLabel: info.label,
|
|
3264
|
+
className: (0, import_design_system10.cn)("max-w-[14rem]", labelClassName),
|
|
3265
|
+
displayClassName: "text-xs font-medium text-foreground",
|
|
3266
|
+
inputClassName: "text-xs font-medium"
|
|
3267
|
+
}
|
|
3268
|
+
) : null,
|
|
3269
|
+
active && DoorControls ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DoorControls, { token, id: active.id, name: active.title }) : null,
|
|
3270
|
+
!active ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3271
|
+
"span",
|
|
3272
|
+
{
|
|
3273
|
+
className: (0, import_design_system10.cn)(
|
|
3274
|
+
"truncate px-1 text-xs font-medium text-muted-foreground",
|
|
3275
|
+
labelClassName
|
|
3276
|
+
),
|
|
3277
|
+
children: adapter.loading ? "\u2026" : emptyLabel ?? info.labelPlural
|
|
3278
|
+
}
|
|
3279
|
+
) : null,
|
|
3280
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3281
|
+
import_design_system10.Popover,
|
|
3282
|
+
{
|
|
3283
|
+
open,
|
|
3284
|
+
onOpenChange: (next) => next ? setOpen(true) : close(),
|
|
3285
|
+
children: [
|
|
3286
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_design_system10.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3287
|
+
"button",
|
|
3288
|
+
{
|
|
3289
|
+
type: "button",
|
|
3290
|
+
className: "inline-flex h-6 shrink-0 items-center gap-0.5 rounded-md px-1 text-[10px] font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
3291
|
+
title: `Switch or add ${info.labelPlural.toLowerCase()}`,
|
|
3292
|
+
"aria-label": `Switch or add ${info.labelPlural.toLowerCase()}`,
|
|
3293
|
+
children: [
|
|
3294
|
+
items.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "tabular-nums", children: [
|
|
3295
|
+
activeIndex >= 0 ? activeIndex + 1 : "\u2014",
|
|
3296
|
+
"/",
|
|
3297
|
+
items.length
|
|
3298
|
+
] }) : null,
|
|
3299
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChevronDownIcon, { className: "size-3 opacity-60" })
|
|
3300
|
+
]
|
|
3301
|
+
}
|
|
3302
|
+
) }),
|
|
3303
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_design_system10.PopoverContent, { className: "w-60 p-0", align, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_design_system10.Command, { children: [
|
|
3304
|
+
items.length > 5 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3305
|
+
import_design_system10.CommandInput,
|
|
3306
|
+
{
|
|
3307
|
+
value: query,
|
|
3308
|
+
onValueChange: setQuery,
|
|
3309
|
+
placeholder: `Search ${info.labelPlural.toLowerCase()}\u2026`
|
|
3310
|
+
}
|
|
3311
|
+
) : null,
|
|
3312
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_design_system10.CommandList, { children: [
|
|
3313
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_design_system10.CommandEmpty, { children: "No match." }),
|
|
3314
|
+
items.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_design_system10.CommandGroup, { children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3315
|
+
import_design_system10.CommandItem,
|
|
3316
|
+
{
|
|
3317
|
+
value: `${item.title} ${item.id}`,
|
|
3318
|
+
onSelect: () => {
|
|
3319
|
+
if (item.id !== activeId)
|
|
3320
|
+
void adapter.setActive(item.id);
|
|
3321
|
+
close();
|
|
3322
|
+
},
|
|
3323
|
+
className: "group/entity-ref group gap-2",
|
|
3324
|
+
children: [
|
|
3325
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3326
|
+
CheckIcon,
|
|
3327
|
+
{
|
|
3328
|
+
className: (0, import_design_system10.cn)(
|
|
3329
|
+
"size-3.5 shrink-0",
|
|
3330
|
+
item.id === activeId ? "opacity-100" : "opacity-0"
|
|
3331
|
+
)
|
|
3332
|
+
}
|
|
3333
|
+
),
|
|
3334
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "min-w-0 flex-1 truncate", children: item.title }),
|
|
3335
|
+
DoorControls ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3336
|
+
"span",
|
|
3337
|
+
{
|
|
3338
|
+
className: "inline-flex shrink-0 items-center",
|
|
3339
|
+
onPointerDown: (e) => {
|
|
3340
|
+
e.preventDefault();
|
|
3341
|
+
e.stopPropagation();
|
|
3342
|
+
},
|
|
3343
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3344
|
+
DoorControls,
|
|
3345
|
+
{
|
|
3346
|
+
token,
|
|
3347
|
+
id: item.id,
|
|
3348
|
+
name: item.title
|
|
3349
|
+
}
|
|
3350
|
+
)
|
|
3351
|
+
}
|
|
3352
|
+
) : null,
|
|
3353
|
+
adapter.detach && item.id !== activeId ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3354
|
+
"button",
|
|
3355
|
+
{
|
|
3356
|
+
type: "button",
|
|
3357
|
+
onPointerDown: (e) => {
|
|
3358
|
+
e.preventDefault();
|
|
3359
|
+
e.stopPropagation();
|
|
3360
|
+
},
|
|
3361
|
+
onClick: (e) => {
|
|
3362
|
+
e.stopPropagation();
|
|
3363
|
+
void adapter.detach?.(item.id);
|
|
3364
|
+
},
|
|
3365
|
+
className: "grid size-5 shrink-0 place-items-center rounded text-muted-foreground opacity-0 transition-opacity hover:bg-accent hover:text-destructive group-hover:opacity-100",
|
|
3366
|
+
title: `Remove this ${entityLabel} from here (does not delete it)`,
|
|
3367
|
+
"aria-label": `Remove ${item.title}`,
|
|
3368
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(XIcon, { className: "size-3" })
|
|
3369
|
+
}
|
|
3370
|
+
) : null
|
|
3371
|
+
]
|
|
3372
|
+
},
|
|
3373
|
+
item.id
|
|
3374
|
+
)) }) : null
|
|
3375
|
+
] }),
|
|
3376
|
+
createSlot !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "border-t border-border p-1", children: typeof createSlot === "function" ? createSlot(close) : createSlot }) : null,
|
|
3377
|
+
createSlot === void 0 && adapter.createAndAttach ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "border-t border-border p-1", children: creating ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-1 px-1 py-0.5", children: [
|
|
3378
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3379
|
+
"input",
|
|
3380
|
+
{
|
|
3381
|
+
autoFocus: true,
|
|
3382
|
+
type: "text",
|
|
3383
|
+
value: draftName,
|
|
3384
|
+
disabled: busy,
|
|
3385
|
+
placeholder: `New ${entityLabel} name\u2026`,
|
|
3386
|
+
onChange: (e) => setDraftName(e.target.value),
|
|
3387
|
+
onKeyDown: (e) => {
|
|
3388
|
+
if (e.key === "Enter") {
|
|
3389
|
+
e.preventDefault();
|
|
3390
|
+
void create(draftName);
|
|
3391
|
+
} else if (e.key === "Escape") {
|
|
3392
|
+
e.preventDefault();
|
|
3393
|
+
e.stopPropagation();
|
|
3394
|
+
setCreating(false);
|
|
3395
|
+
setDraftName("");
|
|
3396
|
+
}
|
|
3397
|
+
},
|
|
3398
|
+
className: "h-6 w-full min-w-0 rounded-sm bg-transparent px-1 text-base outline-none focus:bg-background focus:ring-1 focus:ring-ring md:text-xs",
|
|
3399
|
+
"aria-label": `New ${entityLabel} name`
|
|
3400
|
+
}
|
|
3401
|
+
),
|
|
3402
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3403
|
+
"button",
|
|
3404
|
+
{
|
|
3405
|
+
type: "button",
|
|
3406
|
+
disabled: busy || !draftName.trim(),
|
|
3407
|
+
onClick: () => void create(draftName),
|
|
3408
|
+
className: "inline-flex h-6 shrink-0 items-center rounded-md px-1.5 text-[10px] font-medium text-primary transition-colors hover:bg-accent disabled:opacity-50",
|
|
3409
|
+
children: busy ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SpinnerIcon, { className: "size-3 animate-spin" }) : "Create"
|
|
3410
|
+
}
|
|
3411
|
+
)
|
|
3412
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
3413
|
+
"button",
|
|
3414
|
+
{
|
|
3415
|
+
type: "button",
|
|
3416
|
+
disabled: busy,
|
|
3417
|
+
onClick: () => {
|
|
3418
|
+
if (query.trim()) void create(query);
|
|
3419
|
+
else setCreating(true);
|
|
3420
|
+
},
|
|
3421
|
+
className: "flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
3422
|
+
children: [
|
|
3423
|
+
busy ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SpinnerIcon, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PlusIcon, { className: "size-3.5" }),
|
|
3424
|
+
query.trim() ? `Create "${query.trim()}"` : `New ${info.label}`
|
|
3425
|
+
]
|
|
3426
|
+
}
|
|
3427
|
+
) }) : null
|
|
3428
|
+
] }) })
|
|
3429
|
+
]
|
|
3430
|
+
}
|
|
3431
|
+
)
|
|
3432
|
+
]
|
|
3433
|
+
}
|
|
3434
|
+
);
|
|
3435
|
+
}
|
|
3436
|
+
|
|
3437
|
+
// src/react/components/CategorySelect.tsx
|
|
3438
|
+
var import_react18 = require("react");
|
|
3439
|
+
var import_design_system11 = require("@ai-matrx/design-system");
|
|
3440
|
+
|
|
3441
|
+
// src/core/categoryHierarchy.ts
|
|
3442
|
+
function buildCategoryHierarchy(categories) {
|
|
3443
|
+
const byId = new Map(categories.map((category) => [category.id, category]));
|
|
3444
|
+
const hasHierarchy = categories.some(
|
|
3445
|
+
(category) => category.parentId !== null && byId.has(category.parentId)
|
|
3446
|
+
);
|
|
3447
|
+
if (!hasHierarchy) {
|
|
3448
|
+
return {
|
|
3449
|
+
items: categories.map((category) => ({
|
|
3450
|
+
category,
|
|
3451
|
+
depth: 0,
|
|
3452
|
+
parent: null,
|
|
3453
|
+
displayName: category.name
|
|
3454
|
+
})),
|
|
3455
|
+
roots: categories.filter((category) => category.parentId === null),
|
|
3456
|
+
hasHierarchy: false
|
|
3457
|
+
};
|
|
3458
|
+
}
|
|
3459
|
+
const roots = categories.filter(
|
|
3460
|
+
(category) => category.parentId === null || !byId.has(category.parentId)
|
|
3461
|
+
);
|
|
3462
|
+
const childrenByParent = /* @__PURE__ */ new Map();
|
|
3463
|
+
for (const category of categories) {
|
|
3464
|
+
if (!category.parentId || !byId.has(category.parentId)) continue;
|
|
3465
|
+
const children = childrenByParent.get(category.parentId) ?? [];
|
|
3466
|
+
children.push(category);
|
|
3467
|
+
childrenByParent.set(category.parentId, children);
|
|
3468
|
+
}
|
|
3469
|
+
const items = [];
|
|
3470
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3471
|
+
for (const root of roots) {
|
|
3472
|
+
items.push({
|
|
3473
|
+
category: root,
|
|
3474
|
+
depth: 0,
|
|
3475
|
+
parent: null,
|
|
3476
|
+
displayName: root.name
|
|
3477
|
+
});
|
|
3478
|
+
seen.add(root.id);
|
|
3479
|
+
for (const child of childrenByParent.get(root.id) ?? []) {
|
|
3480
|
+
items.push({
|
|
3481
|
+
category: child,
|
|
3482
|
+
depth: 1,
|
|
3483
|
+
parent: root,
|
|
3484
|
+
displayName: `${root.name} / ${child.name}`
|
|
3485
|
+
});
|
|
3486
|
+
seen.add(child.id);
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
3489
|
+
for (const category of categories) {
|
|
3490
|
+
if (seen.has(category.id)) continue;
|
|
3491
|
+
items.push({
|
|
3492
|
+
category,
|
|
3493
|
+
depth: 0,
|
|
3494
|
+
parent: null,
|
|
3495
|
+
displayName: category.name
|
|
3496
|
+
});
|
|
3497
|
+
}
|
|
3498
|
+
return {
|
|
3499
|
+
items,
|
|
3500
|
+
roots: categories.filter((category) => category.parentId === null),
|
|
3501
|
+
hasHierarchy: true
|
|
3502
|
+
};
|
|
3503
|
+
}
|
|
3504
|
+
|
|
3505
|
+
// src/react/components/CategorySelect.tsx
|
|
3506
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
3507
|
+
var NONE = "__none__";
|
|
3508
|
+
var ROOT_PARENT = "__root__";
|
|
3509
|
+
function plural(noun) {
|
|
3510
|
+
return /[^aeiou]y$/i.test(noun) ? `${noun.slice(0, -1)}ies` : `${noun}s`;
|
|
3511
|
+
}
|
|
3512
|
+
function CategorySelect({
|
|
3513
|
+
dimension,
|
|
3514
|
+
value,
|
|
3515
|
+
onChange,
|
|
3516
|
+
placeholder,
|
|
3517
|
+
allowNone = true,
|
|
3518
|
+
disabled,
|
|
3519
|
+
allowCreate = true,
|
|
3520
|
+
orgId,
|
|
3521
|
+
noun = "category"
|
|
3522
|
+
}) {
|
|
3523
|
+
const store = useAssociationsStore();
|
|
3524
|
+
const notifier = useNotifier();
|
|
3525
|
+
const {
|
|
3526
|
+
categories,
|
|
3527
|
+
status,
|
|
3528
|
+
error,
|
|
3529
|
+
create: createCategory,
|
|
3530
|
+
reload
|
|
3531
|
+
} = useCategories({ dimension });
|
|
3532
|
+
const hierarchy = buildCategoryHierarchy(categories);
|
|
3533
|
+
const [createParentId, setCreateParentId] = (0, import_react18.useState)(ROOT_PARENT);
|
|
3534
|
+
const options = [
|
|
3535
|
+
...allowNone ? [{ value: NONE, label: "None", keywords: "none clear empty" }] : [],
|
|
3536
|
+
...hierarchy.hasHierarchy ? hierarchy.items.map(({ category, depth, parent }) => ({
|
|
3537
|
+
value: category.id,
|
|
3538
|
+
label: category.name,
|
|
3539
|
+
// The type-ahead matches the parent's name too, so someone who knows
|
|
3540
|
+
// the branch but not the leaf still finds it.
|
|
3541
|
+
keywords: parent ? parent.name : "",
|
|
3542
|
+
render: depth === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-medium", children: category.name }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "flex items-center gap-1.5 pl-3 text-muted-foreground", children: [
|
|
3543
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CornerDownRightIcon, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
3544
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-foreground", children: category.name })
|
|
3545
|
+
] })
|
|
3546
|
+
})) : categories.map((category) => ({
|
|
3547
|
+
value: category.id,
|
|
3548
|
+
label: category.name
|
|
3549
|
+
}))
|
|
3550
|
+
];
|
|
3551
|
+
const selected = value ? hierarchy.items.find((item) => item.category.id === value)?.displayName ?? categories.find((category) => category.id === value)?.name ?? null : null;
|
|
3552
|
+
const create = async (typed) => {
|
|
3553
|
+
const name = typed.trim();
|
|
3554
|
+
if (!name) return null;
|
|
3555
|
+
const existing = categories.find(
|
|
3556
|
+
(category) => category.name.toLowerCase() === name.toLowerCase()
|
|
3557
|
+
);
|
|
3558
|
+
if (existing) return existing.id;
|
|
3559
|
+
let resolvedOrgId = orgId ?? null;
|
|
3560
|
+
if (!resolvedOrgId && store.identity.ensureOrgId) {
|
|
3561
|
+
try {
|
|
3562
|
+
resolvedOrgId = await store.identity.ensureOrgId();
|
|
3563
|
+
} catch (e) {
|
|
3564
|
+
store.errorSink({
|
|
3565
|
+
code: "ensure_org_failed",
|
|
3566
|
+
message: "[CategorySelect] identity.ensureOrgId threw",
|
|
3567
|
+
context: { error: e instanceof Error ? e.message : String(e) }
|
|
3568
|
+
});
|
|
3569
|
+
}
|
|
3570
|
+
}
|
|
3571
|
+
if (!resolvedOrgId) {
|
|
3572
|
+
notifier.error(`Select an organization before creating a ${noun}.`);
|
|
3573
|
+
return null;
|
|
3574
|
+
}
|
|
3575
|
+
const parentId = hierarchy.hasHierarchy && createParentId !== ROOT_PARENT ? createParentId : null;
|
|
3576
|
+
const result = await createCategory({ name, orgId: resolvedOrgId, parentId });
|
|
3577
|
+
if (!result.ok || !result.id) {
|
|
3578
|
+
notifier.error(`Couldn't create that ${noun}`, {
|
|
3579
|
+
...result.error != null ? { description: result.error } : {}
|
|
3580
|
+
});
|
|
3581
|
+
return null;
|
|
3582
|
+
}
|
|
3583
|
+
await reload();
|
|
3584
|
+
setCreateParentId(ROOT_PARENT);
|
|
3585
|
+
const under = parentId ? categories.find((category) => category.id === parentId)?.name : null;
|
|
3586
|
+
notifier.success(
|
|
3587
|
+
`\u201C${name}\u201D is now one of your ${plural(noun)}${under ? ` \u2014 it sits under ${under}, and every screen that offers ${plural(noun)} offers it.` : ` \u2014 every screen that offers ${plural(noun)} offers it from now on.`}`
|
|
3588
|
+
);
|
|
3589
|
+
return result.id;
|
|
3590
|
+
};
|
|
3591
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
|
|
3592
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3593
|
+
import_design_system11.CreatablePicker,
|
|
3594
|
+
{
|
|
3595
|
+
value: value ?? (allowNone ? NONE : null),
|
|
3596
|
+
onSelect: (next) => onChange(next === NONE ? null : next),
|
|
3597
|
+
options,
|
|
3598
|
+
placeholder,
|
|
3599
|
+
searchPlaceholder: allowCreate ? `Search or add a ${noun}\u2026` : `Search ${plural(noun)}\u2026`,
|
|
3600
|
+
noun,
|
|
3601
|
+
ariaLabel: placeholder,
|
|
3602
|
+
className: "text-sm",
|
|
3603
|
+
...disabled !== void 0 ? { disabled } : {},
|
|
3604
|
+
loading: status === "loading",
|
|
3605
|
+
emptyLabel: `No ${noun} matches that.`,
|
|
3606
|
+
...allowCreate ? { onCreate: create } : {},
|
|
3607
|
+
...allowCreate && hierarchy.hasHierarchy ? {
|
|
3608
|
+
createExtra: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_design_system11.Select, { value: createParentId, onValueChange: setCreateParentId, children: [
|
|
3609
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3610
|
+
import_design_system11.SelectTrigger,
|
|
3611
|
+
{
|
|
3612
|
+
className: "h-7 text-xs",
|
|
3613
|
+
"aria-label": `Put the new ${noun} under`,
|
|
3614
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_design_system11.SelectValue, {})
|
|
3615
|
+
}
|
|
3616
|
+
),
|
|
3617
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_design_system11.SelectContent, { children: [
|
|
3618
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_design_system11.SelectItem, { value: ROOT_PARENT, className: "text-xs", children: "Top level" }),
|
|
3619
|
+
hierarchy.items.filter((item) => item.depth === 0).map((item) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
3620
|
+
import_design_system11.SelectItem,
|
|
3621
|
+
{
|
|
3622
|
+
value: item.category.id,
|
|
3623
|
+
className: "text-xs",
|
|
3624
|
+
children: [
|
|
3625
|
+
"Under ",
|
|
3626
|
+
item.category.name
|
|
3627
|
+
]
|
|
3628
|
+
},
|
|
3629
|
+
item.category.id
|
|
3630
|
+
))
|
|
3631
|
+
] })
|
|
3632
|
+
] })
|
|
3633
|
+
} : {}
|
|
3634
|
+
}
|
|
3635
|
+
),
|
|
3636
|
+
selected === null && value !== null ? (
|
|
3637
|
+
// A stored id whose row this reader cannot see is not "nothing chosen":
|
|
3638
|
+
// saying so beats a blank box that looks like an unsaved field.
|
|
3639
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("p", { className: "mt-1 text-xs text-muted-foreground", children: [
|
|
3640
|
+
"This ",
|
|
3641
|
+
noun,
|
|
3642
|
+
" is no longer available to you."
|
|
3643
|
+
] })
|
|
3644
|
+
) : null,
|
|
3645
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "mt-1 text-xs text-destructive", children: error }) : null
|
|
3646
|
+
] });
|
|
3647
|
+
}
|
|
3648
|
+
|
|
3649
|
+
// src/react/components/CategoryTagPicker.tsx
|
|
3650
|
+
var import_react19 = require("react");
|
|
3651
|
+
var import_design_system12 = require("@ai-matrx/design-system");
|
|
3652
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
3653
|
+
var ROOT_PARENT2 = "__root__";
|
|
3654
|
+
function CategoryTagPicker({
|
|
3655
|
+
entityType,
|
|
3656
|
+
entityId,
|
|
3657
|
+
dimension,
|
|
3658
|
+
edgeRole,
|
|
3659
|
+
orgId,
|
|
3660
|
+
addLabel = "Add tag",
|
|
3661
|
+
icon: Icon = TagIcon,
|
|
3662
|
+
allowCreate = true,
|
|
3663
|
+
hierarchical,
|
|
3664
|
+
emptyText = "No categories yet."
|
|
3665
|
+
}) {
|
|
3666
|
+
const store = useAssociationsStore();
|
|
3667
|
+
const notifier = useNotifier();
|
|
3668
|
+
const [open, setOpen] = (0, import_react19.useState)(false);
|
|
3669
|
+
const [creating, setCreating] = (0, import_react19.useState)(false);
|
|
3670
|
+
const [writing, setWriting] = (0, import_react19.useState)(false);
|
|
3671
|
+
const [search, setSearch] = (0, import_react19.useState)("");
|
|
3672
|
+
const [createParentId, setCreateParentId] = (0, import_react19.useState)(ROOT_PARENT2);
|
|
3673
|
+
const {
|
|
3674
|
+
categories,
|
|
3675
|
+
create: createCategory,
|
|
3676
|
+
reload: reloadCategories
|
|
3677
|
+
} = useCategories({ dimension });
|
|
3678
|
+
const { edges, setTargets } = useAssociations({
|
|
3679
|
+
type: entityType,
|
|
3680
|
+
id: entityId
|
|
3681
|
+
});
|
|
3682
|
+
const hierarchy = buildCategoryHierarchy(categories);
|
|
3683
|
+
const showHierarchy = hierarchical ?? hierarchy.hasHierarchy;
|
|
3684
|
+
const hierarchyById = new Map(
|
|
3685
|
+
hierarchy.items.map((item) => [item.category.id, item])
|
|
3686
|
+
);
|
|
3687
|
+
const selectedIds = new Set(
|
|
3688
|
+
edges.filter(
|
|
3689
|
+
(e) => e.direction === "outgoing" && e.otherType === "category" && e.role === edgeRole
|
|
3690
|
+
).map((e) => e.otherId)
|
|
3691
|
+
);
|
|
3692
|
+
const selected = categories.filter((c) => selectedIds.has(c.id));
|
|
3693
|
+
const toggle = async (categoryId) => {
|
|
3694
|
+
if (writing) return;
|
|
3695
|
+
setWriting(true);
|
|
3696
|
+
try {
|
|
3697
|
+
const next = selectedIds.has(categoryId) ? [...selectedIds].filter((id) => id !== categoryId) : [...selectedIds, categoryId];
|
|
3698
|
+
const res = await setTargets({
|
|
3699
|
+
targetType: "category",
|
|
3700
|
+
targetIds: next,
|
|
3701
|
+
...orgId != null ? { orgId } : {},
|
|
3702
|
+
role: edgeRole
|
|
3703
|
+
});
|
|
3704
|
+
if (!res.ok) {
|
|
3705
|
+
store.errorSink({
|
|
3706
|
+
code: "category_tag_set_targets_failed",
|
|
3707
|
+
message: "[CategoryTagPicker] setTargets failed",
|
|
3708
|
+
context: { entityType, entityId, edgeRole, error: res.error }
|
|
3709
|
+
});
|
|
3710
|
+
notifier.error(res.error ?? "Could not update categories");
|
|
3711
|
+
}
|
|
3712
|
+
} finally {
|
|
3713
|
+
setWriting(false);
|
|
3714
|
+
}
|
|
3715
|
+
};
|
|
3716
|
+
const createAndAttach = async () => {
|
|
3717
|
+
const name = search.trim();
|
|
3718
|
+
if (!name) return;
|
|
3719
|
+
setCreating(true);
|
|
3720
|
+
try {
|
|
3721
|
+
let resolvedOrgId = orgId ?? null;
|
|
3722
|
+
if (!resolvedOrgId && store.identity.ensureOrgId) {
|
|
3723
|
+
try {
|
|
3724
|
+
resolvedOrgId = await store.identity.ensureOrgId();
|
|
3725
|
+
} catch (e) {
|
|
3726
|
+
store.errorSink({
|
|
3727
|
+
code: "ensure_org_failed",
|
|
3728
|
+
message: "[CategoryTagPicker] identity.ensureOrgId threw",
|
|
3729
|
+
context: { error: e instanceof Error ? e.message : String(e) }
|
|
3730
|
+
});
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
if (!resolvedOrgId) {
|
|
3734
|
+
store.errorSink({
|
|
3735
|
+
code: "ensure_org_missing",
|
|
3736
|
+
message: "[CategoryTagPicker] no org for the created category \u2014 pass `orgId` or bind `identity.ensureOrgId` on the store config",
|
|
3737
|
+
context: { entityType, entityId, dimension }
|
|
3738
|
+
});
|
|
3739
|
+
notifier.error(
|
|
3740
|
+
"Could not create the category \u2014 no organization is selected"
|
|
3741
|
+
);
|
|
3742
|
+
return;
|
|
3743
|
+
}
|
|
3744
|
+
const parentId = showHierarchy && createParentId !== ROOT_PARENT2 ? createParentId : null;
|
|
3745
|
+
const createRes = await createCategory({
|
|
3746
|
+
name,
|
|
3747
|
+
orgId: resolvedOrgId,
|
|
3748
|
+
parentId
|
|
3749
|
+
});
|
|
3750
|
+
if (!createRes.ok || !createRes.id) {
|
|
3751
|
+
store.errorSink({
|
|
3752
|
+
code: "category_tag_create_failed",
|
|
3753
|
+
message: "[CategoryTagPicker] create failed",
|
|
3754
|
+
context: { dimension, error: createRes.error }
|
|
3755
|
+
});
|
|
3756
|
+
notifier.error(createRes.error ?? "Could not create the category");
|
|
3757
|
+
return;
|
|
3758
|
+
}
|
|
3759
|
+
await reloadCategories();
|
|
3760
|
+
await toggle(createRes.id);
|
|
3761
|
+
setSearch("");
|
|
3762
|
+
setCreateParentId(ROOT_PARENT2);
|
|
3763
|
+
} finally {
|
|
3764
|
+
setCreating(false);
|
|
3765
|
+
}
|
|
3766
|
+
};
|
|
3767
|
+
const filtered = categories.filter(
|
|
3768
|
+
(c) => c.name.toLowerCase().includes(search.trim().toLowerCase())
|
|
3769
|
+
);
|
|
3770
|
+
const filteredHierarchy = hierarchy.items.filter(
|
|
3771
|
+
(item) => item.displayName.toLowerCase().includes(search.trim().toLowerCase())
|
|
3772
|
+
);
|
|
3773
|
+
const exactMatch = categories.some(
|
|
3774
|
+
(c) => c.name.toLowerCase() === search.trim().toLowerCase()
|
|
3775
|
+
);
|
|
3776
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", children: [
|
|
3777
|
+
selected.map((c) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3778
|
+
import_design_system12.Badge,
|
|
3779
|
+
{
|
|
3780
|
+
variant: "secondary",
|
|
3781
|
+
className: "gap-1 pr-1 text-xs font-medium",
|
|
3782
|
+
children: [
|
|
3783
|
+
showHierarchy ? hierarchyById.get(c.id)?.displayName ?? c.name : c.name,
|
|
3784
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3785
|
+
"button",
|
|
3786
|
+
{
|
|
3787
|
+
type: "button",
|
|
3788
|
+
onClick: () => void toggle(c.id),
|
|
3789
|
+
className: "ml-0.5 rounded-full p-0.5 hover:bg-muted-foreground/20",
|
|
3790
|
+
"aria-label": `Remove ${c.name}`,
|
|
3791
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(XIcon, { className: "h-2.5 w-2.5" })
|
|
3792
|
+
}
|
|
3793
|
+
)
|
|
3794
|
+
]
|
|
3795
|
+
},
|
|
3796
|
+
c.id
|
|
3797
|
+
)),
|
|
3798
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_design_system12.Popover, { open, onOpenChange: setOpen, children: [
|
|
3799
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system12.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3800
|
+
import_design_system12.Button,
|
|
3801
|
+
{
|
|
3802
|
+
variant: "outline",
|
|
3803
|
+
size: "sm",
|
|
3804
|
+
className: "h-7 gap-1 px-2 text-xs",
|
|
3805
|
+
children: [
|
|
3806
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Icon, { className: "h-3.5 w-3.5" }),
|
|
3807
|
+
selected.length === 0 ? addLabel : "Edit",
|
|
3808
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ChevronsUpDownIcon, { className: "h-3 w-3 opacity-50" })
|
|
3809
|
+
]
|
|
3810
|
+
}
|
|
3811
|
+
) }),
|
|
3812
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system12.PopoverContent, { className: "w-56 p-0", align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_design_system12.Command, { shouldFilter: false, children: [
|
|
3813
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3814
|
+
import_design_system12.CommandInput,
|
|
3815
|
+
{
|
|
3816
|
+
placeholder: allowCreate ? "Search or create..." : "Search...",
|
|
3817
|
+
value: search,
|
|
3818
|
+
onValueChange: setSearch
|
|
3819
|
+
}
|
|
3820
|
+
),
|
|
3821
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_design_system12.CommandList, { children: [
|
|
3822
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system12.CommandEmpty, { className: "px-2 py-3 text-xs text-muted-foreground", children: search.trim() ? "No match." : emptyText }),
|
|
3823
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system12.CommandGroup, { children: showHierarchy ? filteredHierarchy.map(({ category, depth, parent }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3824
|
+
import_design_system12.CommandItem,
|
|
3825
|
+
{
|
|
3826
|
+
value: category.id,
|
|
3827
|
+
keywords: parent ? [parent.name, category.name] : [],
|
|
3828
|
+
onSelect: () => void toggle(category.id),
|
|
3829
|
+
className: (0, import_design_system12.cn)("text-xs", depth === 1 && "pl-6"),
|
|
3830
|
+
children: [
|
|
3831
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3832
|
+
CheckIcon,
|
|
3833
|
+
{
|
|
3834
|
+
className: (0, import_design_system12.cn)(
|
|
3835
|
+
"mr-2 h-3.5 w-3.5",
|
|
3836
|
+
selectedIds.has(category.id) ? "opacity-100" : "opacity-0"
|
|
3837
|
+
)
|
|
3838
|
+
}
|
|
3839
|
+
),
|
|
3840
|
+
depth === 1 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(CornerDownRightIcon, { className: "mr-1.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }) : null,
|
|
3841
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: (0, import_design_system12.cn)(depth === 0 && "font-medium"), children: category.name })
|
|
3842
|
+
]
|
|
3843
|
+
},
|
|
3844
|
+
category.id
|
|
3845
|
+
)) : filtered.map((c) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3846
|
+
import_design_system12.CommandItem,
|
|
3847
|
+
{
|
|
3848
|
+
value: c.id,
|
|
3849
|
+
onSelect: () => void toggle(c.id),
|
|
3850
|
+
className: "text-xs",
|
|
3851
|
+
children: [
|
|
3852
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3853
|
+
CheckIcon,
|
|
3854
|
+
{
|
|
3855
|
+
className: (0, import_design_system12.cn)(
|
|
3856
|
+
"mr-2 h-3.5 w-3.5",
|
|
3857
|
+
selectedIds.has(c.id) ? "opacity-100" : "opacity-0"
|
|
3858
|
+
)
|
|
3859
|
+
}
|
|
3860
|
+
),
|
|
3861
|
+
c.name
|
|
3862
|
+
]
|
|
3863
|
+
},
|
|
3864
|
+
c.id
|
|
3865
|
+
)) }),
|
|
3866
|
+
allowCreate && search.trim() && !exactMatch ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_design_system12.CommandGroup, { children: [
|
|
3867
|
+
showHierarchy ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "space-y-1.5 px-2 pb-2", children: [
|
|
3868
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-[11px] font-medium text-muted-foreground", children: "Place in" }),
|
|
3869
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3870
|
+
import_design_system12.Select,
|
|
3871
|
+
{
|
|
3872
|
+
value: createParentId,
|
|
3873
|
+
onValueChange: setCreateParentId,
|
|
3874
|
+
children: [
|
|
3875
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system12.SelectTrigger, { size: "sm", className: "bg-background", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system12.SelectValue, {}) }),
|
|
3876
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_design_system12.SelectContent, { children: [
|
|
3877
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system12.SelectItem, { value: ROOT_PARENT2, children: "Top level" }),
|
|
3878
|
+
hierarchy.roots.map((root) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_design_system12.SelectItem, { value: root.id, children: root.name }, root.id))
|
|
3879
|
+
] })
|
|
3880
|
+
]
|
|
3881
|
+
}
|
|
3882
|
+
)
|
|
3883
|
+
] }) : null,
|
|
3884
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3885
|
+
import_design_system12.CommandItem,
|
|
3886
|
+
{
|
|
3887
|
+
value: `__create__${search}`,
|
|
3888
|
+
onSelect: () => void createAndAttach(),
|
|
3889
|
+
disabled: creating,
|
|
3890
|
+
className: "text-xs text-primary",
|
|
3891
|
+
children: [
|
|
3892
|
+
creating ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SpinnerIcon, { className: "mr-2 h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Icon, { className: "mr-2 h-3.5 w-3.5" }),
|
|
3893
|
+
"Create \u201C",
|
|
3894
|
+
search.trim(),
|
|
3895
|
+
"\u201D"
|
|
3896
|
+
]
|
|
3897
|
+
}
|
|
3898
|
+
)
|
|
3899
|
+
] }) : null
|
|
3900
|
+
] })
|
|
3901
|
+
] }) })
|
|
3902
|
+
] })
|
|
3903
|
+
] });
|
|
3904
|
+
}
|
|
3158
3905
|
//# sourceMappingURL=index.cjs.map
|