@ai-matrx/associations 0.13.21 → 0.13.23

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.
@@ -3868,10 +3868,60 @@ function AttachedItemsBody({
3868
3868
  var import_react16 = require("react");
3869
3869
  var import_design_system7 = require("@ai-matrx/design-system");
3870
3870
  var import_tap_target = require("@ai-matrx/design-system/tap-target");
3871
+
3872
+ // src/react/contentRoles.ts
3873
+ var CONTENT_ROLES = [
3874
+ {
3875
+ id: "utility",
3876
+ title: "Utilities",
3877
+ tagline: "The agents and tools that act on your knowledge.",
3878
+ accentText: "text-violet-600 dark:text-violet-400",
3879
+ accentBg: "bg-violet-500/10",
3880
+ accentBar: "bg-violet-500"
3881
+ },
3882
+ {
3883
+ id: "source",
3884
+ title: "Sources",
3885
+ tagline: "Incoming sources of truth (Knowledge In).",
3886
+ accentText: "text-sky-600 dark:text-sky-400",
3887
+ accentBg: "bg-sky-500/10",
3888
+ accentBar: "bg-sky-500"
3889
+ },
3890
+ {
3891
+ id: "destination",
3892
+ title: "Outputs",
3893
+ tagline: "Knowledge your team produces.",
3894
+ accentText: "text-emerald-600 dark:text-emerald-400",
3895
+ accentBg: "bg-emerald-500/10",
3896
+ accentBar: "bg-emerald-500"
3897
+ },
3898
+ {
3899
+ id: "hybrid",
3900
+ title: "Sources & Outputs",
3901
+ tagline: "Read from and written to.",
3902
+ accentText: "text-teal-600 dark:text-teal-400",
3903
+ accentBg: "bg-teal-500/10",
3904
+ accentBar: "bg-gradient-to-r from-sky-500 to-emerald-500"
3905
+ },
3906
+ {
3907
+ id: "container",
3908
+ title: "Workspaces",
3909
+ tagline: "How work is organized.",
3910
+ accentText: "text-amber-600 dark:text-amber-400",
3911
+ accentBg: "bg-amber-500/10",
3912
+ accentBar: "bg-amber-500"
3913
+ }
3914
+ ];
3915
+ function getContentRoleMeta(role) {
3916
+ return CONTENT_ROLES.find((r) => r.id === role) ?? CONTENT_ROLES[2];
3917
+ }
3918
+
3919
+ // src/react/components/AssociationCard.tsx
3871
3920
  var import_jsx_runtime11 = require("react/jsx-runtime");
3872
3921
  function AssociationCard({
3873
3922
  token,
3874
3923
  container: containerProp,
3924
+ look = "tiles",
3875
3925
  className
3876
3926
  }) {
3877
3927
  const store = useAssociationsStore();
@@ -3879,6 +3929,7 @@ function AssociationCard({
3879
3929
  const container = containerProp ?? fromCtx;
3880
3930
  const [open, setOpen] = (0, import_react16.useState)(false);
3881
3931
  const info = store.registry.getEntityInfo(token);
3932
+ const role = getContentRoleMeta(info.contentRole);
3882
3933
  const Icon = info.Icon ?? DefaultEntityIcon;
3883
3934
  const [listOpen, setListOpen] = (0, import_react16.useState)(false);
3884
3935
  const {
@@ -3904,43 +3955,118 @@ function AssociationCard({
3904
3955
  const canAttach = info.canListCandidates && (!filing || isAssociationTargetType(token));
3905
3956
  const canDrillIn = count > 0;
3906
3957
  const countWord = filing ? "filed under" : "attached";
3958
+ const drillTitle = canDrillIn ? `View the ${info.labelPlural.toLowerCase()} attached to ${container.label ?? "this"}` : void 0;
3907
3959
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
3908
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3960
+ look === "simplified" ? (
3961
+ // SIMPLIFIED (opt-in, off by default): one header line — small icon,
3962
+ // UPPERCASE name, count, round ghost "+" — the same geometry as the
3963
+ // CRM record's SectionCard header, so the two sit flush together.
3964
+ // TapTargetButton puts `className` on its ICON, not the button: never
3965
+ // pass layout classes there (an `ml-auto` pushed the "+" glyph off
3966
+ // center inside its circle). The flex-1 drill button already puts the
3967
+ // "+" at the end of the row.
3968
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3969
+ "div",
3970
+ {
3971
+ "data-association-card": token,
3972
+ "data-association-card-look": "simplified",
3973
+ className: (0, import_design_system7.cn)(
3974
+ "flex min-h-8 items-center gap-x-1.5 rounded-md border border-border bg-card px-2.5 py-1 sm:py-0 lg:pointer-fine:[--matrx-tap-target-size:1.75rem]",
3975
+ className
3976
+ ),
3977
+ children: [
3978
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3979
+ "button",
3980
+ {
3981
+ type: "button",
3982
+ disabled: !canDrillIn,
3983
+ onClick: () => setListOpen(true),
3984
+ title: drillTitle,
3985
+ "aria-label": loading ? info.labelPlural : `${info.labelPlural}: ${count} ${countWord}`,
3986
+ className: (0, import_design_system7.cn)(
3987
+ "flex min-h-8 min-w-0 flex-1 items-center gap-x-1.5 text-left",
3988
+ canDrillIn ? "cursor-pointer hover:text-foreground" : "cursor-default"
3989
+ ),
3990
+ children: [
3991
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
3992
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "min-w-0 truncate text-xs font-semibold uppercase tracking-wider text-foreground", children: info.labelPlural }),
3993
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SpinnerIcon, { className: "h-3 w-3 animate-spin text-muted-foreground" }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xs tabular-nums text-muted-foreground", children: count })
3994
+ ]
3995
+ }
3996
+ ),
3997
+ canAttach && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3998
+ import_tap_target.TapTargetButton,
3999
+ {
4000
+ ariaLabel: `Attach ${info.labelPlural.toLowerCase()}`,
4001
+ tooltip: false,
4002
+ onClick: () => setOpen(true),
4003
+ icon: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PlusIcon, { className: "h-4 w-4" })
4004
+ }
4005
+ )
4006
+ ]
4007
+ }
4008
+ )
4009
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3909
4010
  "div",
3910
4011
  {
3911
4012
  "data-association-card": token,
4013
+ "data-association-card-look": "tiles",
3912
4014
  className: (0, import_design_system7.cn)(
3913
- "flex min-h-8 items-center gap-x-1.5 rounded-md border border-border bg-card px-2.5 py-1 sm:py-0 lg:pointer-fine:[--matrx-tap-target-size:1.75rem]",
4015
+ "group relative flex items-center gap-3 overflow-hidden rounded-xl border border-border bg-card transition-all hover:border-primary/30 hover:bg-accent/40",
3914
4016
  className
3915
4017
  ),
3916
4018
  children: [
4019
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4020
+ "span",
4021
+ {
4022
+ className: (0, import_design_system7.cn)(
4023
+ "absolute inset-x-0 top-0 h-0.5 opacity-60",
4024
+ role.accentBar
4025
+ )
4026
+ }
4027
+ ),
3917
4028
  /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3918
4029
  "button",
3919
4030
  {
3920
4031
  type: "button",
3921
4032
  disabled: !canDrillIn,
3922
4033
  onClick: () => setListOpen(true),
3923
- title: canDrillIn ? `View the ${info.labelPlural.toLowerCase()} attached to ${container.label ?? "this"}` : void 0,
3924
- "aria-label": loading ? info.labelPlural : `${info.labelPlural}: ${count} ${countWord}`,
4034
+ title: drillTitle,
3925
4035
  className: (0, import_design_system7.cn)(
3926
- "flex min-h-8 min-w-0 flex-1 items-center gap-x-1.5 text-left",
3927
- canDrillIn ? "cursor-pointer hover:text-foreground" : "cursor-default"
4036
+ "flex min-w-0 flex-1 items-center gap-3 px-3 py-2.5 text-left",
4037
+ canDrillIn ? "cursor-pointer" : "cursor-default"
3928
4038
  ),
3929
4039
  children: [
3930
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
3931
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "min-w-0 truncate text-xs font-semibold uppercase tracking-wider text-foreground", children: info.labelPlural }),
3932
- loading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SpinnerIcon, { className: "h-3 w-3 animate-spin text-muted-foreground" }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xs tabular-nums text-muted-foreground", children: count })
4040
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4041
+ "span",
4042
+ {
4043
+ className: (0, import_design_system7.cn)(
4044
+ "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg",
4045
+ role.accentBg,
4046
+ role.accentText
4047
+ ),
4048
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { className: "h-4 w-4" })
4049
+ }
4050
+ ),
4051
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "min-w-0 flex-1", children: [
4052
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "block truncate text-sm font-medium text-foreground", children: info.labelPlural }),
4053
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "block text-xs text-muted-foreground tabular-nums", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
4054
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SpinnerIcon, { className: "h-3 w-3 animate-spin" }),
4055
+ "Loading\u2026"
4056
+ ] }) : `${count} ${countWord}` })
4057
+ ] })
3933
4058
  ]
3934
4059
  }
3935
4060
  ),
3936
4061
  canAttach && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3937
- import_tap_target.TapTargetButton,
4062
+ "button",
3938
4063
  {
3939
- ariaLabel: `Attach ${info.labelPlural.toLowerCase()}`,
3940
- tooltip: false,
4064
+ type: "button",
3941
4065
  onClick: () => setOpen(true),
3942
- className: "ml-auto shrink-0",
3943
- icon: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PlusIcon, { className: "h-4 w-4" })
4066
+ "aria-label": `Attach ${info.labelPlural.toLowerCase()}`,
4067
+ title: `Attach ${info.labelPlural.toLowerCase()}`,
4068
+ className: "mr-2 flex h-11 w-11 shrink-0 items-center justify-center rounded-md border border-border text-muted-foreground transition-colors hover:border-primary/60 hover:text-foreground lg:mr-3 lg:h-7 lg:w-7",
4069
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PlusIcon, { className: "h-4 w-4" })
3944
4070
  }
3945
4071
  )
3946
4072
  ]
@@ -3961,8 +4087,8 @@ function AssociationCard({
3961
4087
  setOpen(true);
3962
4088
  }
3963
4089
  } : {},
3964
- onDetach: (resourceId, role) => detach(token, resourceId, role ?? void 0),
3965
- onSetPinned: (resourceId, pinned, role) => setPinned(token, resourceId, pinned, role ?? void 0)
4090
+ onDetach: (resourceId, role2) => detach(token, resourceId, role2 ?? void 0),
4091
+ onSetPinned: (resourceId, pinned, role2) => setPinned(token, resourceId, pinned, role2 ?? void 0)
3966
4092
  }
3967
4093
  ),
3968
4094
  canAttach && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
@@ -3984,61 +4110,29 @@ function AssociationCard({
3984
4110
 
3985
4111
  // src/react/components/AssociationCardGrid.tsx
3986
4112
  var import_design_system8 = require("@ai-matrx/design-system");
3987
-
3988
- // src/react/contentRoles.ts
3989
- var CONTENT_ROLES = [
3990
- {
3991
- id: "utility",
3992
- title: "Utilities",
3993
- tagline: "The agents and tools that act on your knowledge.",
3994
- accentText: "text-violet-600 dark:text-violet-400",
3995
- accentBg: "bg-violet-500/10",
3996
- accentBar: "bg-violet-500"
3997
- },
3998
- {
3999
- id: "source",
4000
- title: "Sources",
4001
- tagline: "Incoming sources of truth (Knowledge In).",
4002
- accentText: "text-sky-600 dark:text-sky-400",
4003
- accentBg: "bg-sky-500/10",
4004
- accentBar: "bg-sky-500"
4005
- },
4006
- {
4007
- id: "destination",
4008
- title: "Outputs",
4009
- tagline: "Knowledge your team produces.",
4010
- accentText: "text-emerald-600 dark:text-emerald-400",
4011
- accentBg: "bg-emerald-500/10",
4012
- accentBar: "bg-emerald-500"
4013
- },
4014
- {
4015
- id: "hybrid",
4016
- title: "Sources & Outputs",
4017
- tagline: "Read from and written to.",
4018
- accentText: "text-teal-600 dark:text-teal-400",
4019
- accentBg: "bg-teal-500/10",
4020
- accentBar: "bg-gradient-to-r from-sky-500 to-emerald-500"
4021
- },
4022
- {
4023
- id: "container",
4024
- title: "Workspaces",
4025
- tagline: "How work is organized.",
4026
- accentText: "text-amber-600 dark:text-amber-400",
4027
- accentBg: "bg-amber-500/10",
4028
- accentBar: "bg-amber-500"
4029
- }
4030
- ];
4031
- function getContentRoleMeta(role) {
4032
- return CONTENT_ROLES.find((r) => r.id === role) ?? CONTENT_ROLES[2];
4033
- }
4034
-
4035
- // src/react/components/AssociationCardGrid.tsx
4036
4113
  var import_jsx_runtime12 = require("react/jsx-runtime");
4037
- var GROUP_LABEL = "mb-1 text-xs font-medium uppercase tracking-wider text-muted-foreground";
4038
- var TILE_ROW = "flex flex-wrap gap-2 [&>*]:min-w-[16rem] [&>*]:flex-1";
4114
+ var SIMPLE_GROUP_LABEL = "mb-1 text-xs font-medium uppercase tracking-wider text-muted-foreground";
4115
+ var SIMPLE_TILE_ROW = "flex flex-wrap gap-2 [&>*]:min-w-[16rem] [&>*]:flex-1";
4116
+ var TILE_GRID = "grid grid-cols-1 gap-2 @md:grid-cols-2 @3xl:grid-cols-3";
4117
+ function GroupHeader({
4118
+ look,
4119
+ title,
4120
+ tagline,
4121
+ dotClassName
4122
+ }) {
4123
+ if (look === "simplified") return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { className: SIMPLE_GROUP_LABEL, children: title });
4124
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "mb-2.5 flex items-baseline gap-3 pl-1.5", children: [
4125
+ dotClassName ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-2", children: [
4126
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: (0, import_design_system8.cn)("h-2.5 w-2.5 rounded-full", dotClassName) }),
4127
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { className: "text-sm font-semibold text-foreground", children: title })
4128
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { className: "text-sm font-semibold text-foreground", children: title }),
4129
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "hidden text-xs text-muted-foreground sm:block", children: tagline })
4130
+ ] });
4131
+ }
4039
4132
  function AssociationCardGrid({
4040
4133
  tokens,
4041
4134
  excludeTokens,
4135
+ look = "tiles",
4042
4136
  className
4043
4137
  }) {
4044
4138
  const store = useAssociationsStore();
@@ -4061,22 +4155,45 @@ function AssociationCardGrid({
4061
4155
  const role = store.registry.getEntityInfo(token).contentRole;
4062
4156
  return !role || !roleIds.has(role);
4063
4157
  }) : [];
4064
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: (0, import_design_system8.cn)("@container space-y-3", className), children: [
4065
- CONTENT_ROLES.map((role) => {
4066
- const inRole = list.filter(
4067
- (token) => store.registry.getEntityInfo(token).contentRole === role.id
4068
- );
4069
- if (inRole.length === 0) return null;
4070
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { children: [
4071
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { className: GROUP_LABEL, children: role.title }),
4072
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: TILE_ROW, children: inRole.map((token) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AssociationCard, { token }, token)) })
4073
- ] }, role.id);
4074
- }),
4075
- roleless.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { children: [
4076
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { className: GROUP_LABEL, children: "Filed under" }),
4077
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: TILE_ROW, children: roleless.map((token) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AssociationCard, { token }, token)) })
4078
- ] })
4079
- ] });
4158
+ const rowClass = look === "simplified" ? SIMPLE_TILE_ROW : TILE_GRID;
4159
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4160
+ "div",
4161
+ {
4162
+ "data-association-grid-look": look,
4163
+ className: (0, import_design_system8.cn)("@container", look === "simplified" ? "space-y-3" : "space-y-5", className),
4164
+ children: [
4165
+ CONTENT_ROLES.map((role) => {
4166
+ const inRole = list.filter(
4167
+ (token) => store.registry.getEntityInfo(token).contentRole === role.id
4168
+ );
4169
+ if (inRole.length === 0) return null;
4170
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { children: [
4171
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4172
+ GroupHeader,
4173
+ {
4174
+ look,
4175
+ title: role.title,
4176
+ tagline: role.tagline,
4177
+ dotClassName: role.accentBar
4178
+ }
4179
+ ),
4180
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: rowClass, children: inRole.map((token) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AssociationCard, { token, look }, token)) })
4181
+ ] }, role.id);
4182
+ }),
4183
+ roleless.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { children: [
4184
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4185
+ GroupHeader,
4186
+ {
4187
+ look,
4188
+ title: "Filed under",
4189
+ tagline: "Libraries, topics and other places this is kept."
4190
+ }
4191
+ ),
4192
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: rowClass, children: roleless.map((token) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AssociationCard, { token, look }, token)) })
4193
+ ] })
4194
+ ]
4195
+ }
4196
+ );
4080
4197
  }
4081
4198
 
4082
4199
  // src/react/components/AssociationList.tsx