@ai-matrx/associations 0.7.2 → 0.7.4

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.
@@ -1415,8 +1415,11 @@ async function loadRecents(store, tokens) {
1415
1415
  if (!res.ok) return [];
1416
1416
  const tokenSet = new Set(tokens);
1417
1417
  const rows = res.data.items.filter(
1418
- (i) => tokenSet.has(i.entityType) && isEntityTypeToken(i.entityType) && i.lastViewedAt
1419
- ).sort((a, b) => (b.lastViewedAt ?? "").localeCompare(a.lastViewedAt ?? "")).slice(0, RECENTS_LIMIT);
1418
+ (i) => tokenSet.has(i.entityType) && isEntityTypeToken(i.entityType) && (i.isFavorite || i.lastViewedAt)
1419
+ ).sort((a, b) => {
1420
+ if (a.isFavorite !== b.isFavorite) return a.isFavorite ? -1 : 1;
1421
+ return (b.lastViewedAt ?? "").localeCompare(a.lastViewedAt ?? "");
1422
+ }).slice(0, RECENTS_LIMIT);
1420
1423
  if (rows.length === 0) return [];
1421
1424
  const byToken = /* @__PURE__ */ new Map();
1422
1425
  for (const r of rows) {
@@ -2484,27 +2487,35 @@ function UniversalAssociationPicker(props) {
2484
2487
  ),
2485
2488
  loading && browseToken === null && /* @__PURE__ */ jsx8(SpinnerIcon, { className: "absolute right-2.5 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-muted-foreground" })
2486
2489
  ] }),
2487
- /* @__PURE__ */ jsx8("div", { className: "flex flex-wrap gap-1", children: tokens.map((t) => {
2488
- const info = store.registry.getEntityInfo(t);
2489
- const ChipIcon = info.Icon ?? DefaultEntityIcon;
2490
- const active = browseToken === t;
2491
- return /* @__PURE__ */ jsxs6(
2492
- "button",
2493
- {
2494
- type: "button",
2495
- onClick: () => setBrowseToken(active ? null : t),
2496
- className: cn4(
2497
- "inline-flex items-center gap-1 rounded-md border px-1.5 py-0.5 text-[11px] transition-colors",
2498
- active ? "border-primary/50 bg-primary/10 text-foreground" : "border-border text-muted-foreground hover:text-foreground hover:bg-accent"
2499
- ),
2500
- children: [
2501
- /* @__PURE__ */ jsx8(ChipIcon, { className: "h-3 w-3" }),
2502
- info.labelPlural
2503
- ]
2504
- },
2505
- t
2506
- );
2507
- }) }),
2490
+ /* @__PURE__ */ jsx8(
2491
+ "div",
2492
+ {
2493
+ role: "group",
2494
+ "aria-label": "Entity type filters",
2495
+ className: "flex shrink-0 flex-nowrap gap-1 overflow-x-auto pb-1",
2496
+ children: tokens.map((t) => {
2497
+ const info = store.registry.getEntityInfo(t);
2498
+ const ChipIcon = info.Icon ?? DefaultEntityIcon;
2499
+ const active = browseToken === t;
2500
+ return /* @__PURE__ */ jsxs6(
2501
+ "button",
2502
+ {
2503
+ type: "button",
2504
+ onClick: () => setBrowseToken(active ? null : t),
2505
+ className: cn4(
2506
+ "inline-flex shrink-0 items-center gap-1 rounded-md border px-1.5 py-0.5 text-[11px] transition-colors",
2507
+ active ? "border-primary/50 bg-primary/10 text-foreground" : "border-border text-muted-foreground hover:text-foreground hover:bg-accent"
2508
+ ),
2509
+ children: [
2510
+ /* @__PURE__ */ jsx8(ChipIcon, { className: "h-3 w-3" }),
2511
+ info.labelPlural
2512
+ ]
2513
+ },
2514
+ t
2515
+ );
2516
+ })
2517
+ }
2518
+ ),
2508
2519
  browseToken && BrowseOverride ? (
2509
2520
  // The token's canonical host picker (e.g. the stored-files browser)
2510
2521
  // owns per-token browsing when registered — never a plain list twin.
@@ -2537,71 +2548,79 @@ function UniversalAssociationPicker(props) {
2537
2548
  onAttach: (id, title) => onAttach(browseToken, id, title),
2538
2549
  onDetach: (id) => onDetach(browseToken, id)
2539
2550
  }
2540
- ) }) : /* @__PURE__ */ jsx8("div", { className: "-mx-1 min-h-0 flex-1 overflow-y-auto px-1", children: results.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "py-6 text-center text-[12px] text-muted-foreground", children: loading ? "Searching\u2026" : query.trim() ? "No matches \u2014 narrow with a type chip to browse." : "No recent items. Type to search, or pick a type to browse." }) : /* @__PURE__ */ jsxs6("div", { className: "space-y-2", children: [
2541
- isRecents && /* @__PURE__ */ jsx8("p", { className: "px-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/60", children: "Recent" }),
2542
- [...groups.entries()].map(([token, items]) => {
2543
- const info = store.registry.getEntityInfo(token);
2544
- const GroupIcon = info.Icon ?? DefaultEntityIcon;
2545
- return /* @__PURE__ */ jsxs6("div", { className: "space-y-0.5", children: [
2546
- /* @__PURE__ */ jsxs6("p", { className: "flex items-center gap-1 px-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/70", children: [
2547
- /* @__PURE__ */ jsx8(GroupIcon, { className: "h-3 w-3" }),
2548
- info.labelPlural
2549
- ] }),
2550
- /* @__PURE__ */ jsx8("ul", { className: "space-y-0.5", children: items.map((c) => {
2551
- const key = attachedKey(c.token, c.id);
2552
- const attached = attachedKeys.has(key);
2553
- const busy = busyKey === key;
2554
- return /* @__PURE__ */ jsxs6(
2555
- "li",
2556
- {
2557
- className: cn4(
2558
- "group/entity-ref group flex items-center gap-1 rounded-md pr-1.5 transition-colors",
2559
- "hover:bg-accent",
2560
- attached && "bg-accent/40"
2561
- ),
2562
- children: [
2563
- /* @__PURE__ */ jsxs6(
2564
- "button",
2565
- {
2566
- type: "button",
2567
- disabled: busy,
2568
- onClick: () => toggle(c),
2569
- title: attached ? `Detach "${c.title}"` : `Attach "${c.title}"`,
2570
- className: cn4(
2571
- "flex min-w-0 flex-1 items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-sm",
2572
- "disabled:opacity-50"
2551
+ ) }) : /* @__PURE__ */ jsx8(
2552
+ "div",
2553
+ {
2554
+ role: "region",
2555
+ "aria-label": "Association search results",
2556
+ className: "-mx-1 min-h-24 flex-1 overflow-y-auto overscroll-contain px-1",
2557
+ children: results.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "py-6 text-center text-[12px] text-muted-foreground", children: loading ? "Searching\u2026" : query.trim() ? "No matches \u2014 narrow with a type chip to browse." : "No recent items. Type to search, or pick a type to browse." }) : /* @__PURE__ */ jsxs6("div", { className: "space-y-2", children: [
2558
+ isRecents && /* @__PURE__ */ jsx8("p", { className: "px-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/60", children: "Recent" }),
2559
+ [...groups.entries()].map(([token, items]) => {
2560
+ const info = store.registry.getEntityInfo(token);
2561
+ const GroupIcon = info.Icon ?? DefaultEntityIcon;
2562
+ return /* @__PURE__ */ jsxs6("div", { className: "space-y-0.5", children: [
2563
+ /* @__PURE__ */ jsxs6("p", { className: "flex items-center gap-1 px-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/70", children: [
2564
+ /* @__PURE__ */ jsx8(GroupIcon, { className: "h-3 w-3" }),
2565
+ info.labelPlural
2566
+ ] }),
2567
+ /* @__PURE__ */ jsx8("ul", { className: "space-y-0.5", children: items.map((c) => {
2568
+ const key = attachedKey(c.token, c.id);
2569
+ const attached = attachedKeys.has(key);
2570
+ const busy = busyKey === key;
2571
+ return /* @__PURE__ */ jsxs6(
2572
+ "li",
2573
+ {
2574
+ className: cn4(
2575
+ "group/entity-ref group flex items-center gap-1 rounded-md pr-1.5 transition-colors",
2576
+ "hover:bg-accent",
2577
+ attached && "bg-accent/40"
2578
+ ),
2579
+ children: [
2580
+ /* @__PURE__ */ jsxs6(
2581
+ "button",
2582
+ {
2583
+ type: "button",
2584
+ disabled: busy,
2585
+ onClick: () => toggle(c),
2586
+ title: attached ? `Detach "${c.title}"` : `Attach "${c.title}"`,
2587
+ className: cn4(
2588
+ "flex min-w-0 flex-1 items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-sm",
2589
+ "disabled:opacity-50"
2590
+ ),
2591
+ children: [
2592
+ /* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-1 truncate text-foreground", children: c.title }),
2593
+ /* @__PURE__ */ jsx8(
2594
+ "span",
2595
+ {
2596
+ className: cn4(
2597
+ "flex h-5 w-5 shrink-0 items-center justify-center rounded-full",
2598
+ attached ? "bg-primary text-primary-foreground" : "border border-border text-muted-foreground group-hover:border-primary/60"
2599
+ ),
2600
+ children: busy ? /* @__PURE__ */ jsx8(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : attached ? /* @__PURE__ */ jsx8(CheckIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx8(PlusIcon, { className: "h-3 w-3" })
2601
+ }
2602
+ )
2603
+ ]
2604
+ }
2573
2605
  ),
2574
- children: [
2575
- /* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-1 truncate text-foreground", children: c.title }),
2576
- /* @__PURE__ */ jsx8(
2577
- "span",
2578
- {
2579
- className: cn4(
2580
- "flex h-5 w-5 shrink-0 items-center justify-center rounded-full",
2581
- attached ? "bg-primary text-primary-foreground" : "border border-border text-muted-foreground group-hover:border-primary/60"
2582
- ),
2583
- children: busy ? /* @__PURE__ */ jsx8(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : attached ? /* @__PURE__ */ jsx8(CheckIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx8(PlusIcon, { className: "h-3 w-3" })
2584
- }
2585
- )
2586
- ]
2587
- }
2588
- ),
2589
- /* @__PURE__ */ jsx8(
2590
- DoorControlsSlot,
2591
- {
2592
- token: c.token,
2593
- id: c.id,
2594
- name: c.title
2595
- }
2596
- )
2597
- ]
2598
- },
2599
- key
2600
- );
2601
- }) })
2602
- ] }, token);
2603
- })
2604
- ] }) })
2606
+ /* @__PURE__ */ jsx8(
2607
+ DoorControlsSlot,
2608
+ {
2609
+ token: c.token,
2610
+ id: c.id,
2611
+ name: c.title
2612
+ }
2613
+ )
2614
+ ]
2615
+ },
2616
+ key
2617
+ );
2618
+ }) })
2619
+ ] }, token);
2620
+ })
2621
+ ] })
2622
+ }
2623
+ )
2605
2624
  ] });
2606
2625
  }
2607
2626