@camstack/ui-library 1.2.331 → 1.2.332

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.
@@ -1,20 +1,17 @@
1
- /**
2
- * `GroupedTilePicker` — choose ONE "type of thing" from tiles grouped by who
3
- * provides it (an AI profile kind, a notification-target kind…): an uppercase
4
- * group label, then a grid of icon + label tiles. The pre-modal of a
5
- * create-flow whose form depends on the choice.
6
- *
7
- * The tile is deliberately not a `Button`: a vertical icon-over-label card in
8
- * a grid, which toolbar-button chrome fights. One place owns that look so the
9
- * pickers stay identical.
10
- */
11
- import type { JSX, ReactNode } from "react";
1
+ import { type JSX, type ReactNode } from "react";
12
2
  export interface TilePickerTile {
13
3
  /** Unique within the picker; handed back to `onPick`. */
14
4
  readonly key: string;
15
5
  readonly label: string;
16
6
  readonly icon: ReactNode;
17
7
  readonly testId?: string;
8
+ /**
9
+ * Extra facts for the tile (supported operations, a shared-capability list).
10
+ * A tap target beside the name — it does not choose the tile.
11
+ */
12
+ readonly detail?: ReactNode;
13
+ /** Accessible name of the detail control. Required when `detail` is set. */
14
+ readonly detailLabel?: string;
18
15
  }
19
16
  export interface TilePickerGroup {
20
17
  readonly id: string;
package/dist/index.cjs CHANGED
@@ -14504,6 +14504,9 @@ function AccountSignInField({ field, values, disabled, onAction, onChangeMany })
14504
14504
  if (Object.keys(patch).length > 0) onChangeMany?.(patch);
14505
14505
  const nextChoices = choicesOf(result["choices"]);
14506
14506
  setChoices(nextChoices.length > 1 ? nextChoices : []);
14507
+ const picked = typeof result["gatewayId"] === "string" && result["gatewayId"].length > 0;
14508
+ const summary = typeof result["summary"] === "string" ? result["summary"] : null;
14509
+ if (summary !== null && !picked && nextChoices.length < 2) setError(summary);
14507
14510
  setPhase("idle");
14508
14511
  setPaste("");
14509
14512
  setAttemptId(null);
@@ -31013,13 +31016,13 @@ function InfoBox({ field }) {
31013
31016
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
31014
31017
  className: `rounded-md border-l-4 px-3 py-2.5 ${styles.border} ${styles.bg}`,
31015
31018
  children: [field.label && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
31016
- className: `text-xs font-semibold mb-0.5 ${styles.text}`,
31019
+ className: field.content.length > 0 ? `text-xs font-semibold mb-0.5 ${styles.text}` : "text-xs text-foreground-subtle leading-relaxed whitespace-pre-line break-words",
31017
31020
  children: field.label
31018
31021
  }), isHtml ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
31019
31022
  className: "text-xs text-foreground-subtle leading-relaxed info-html-content",
31020
31023
  dangerouslySetInnerHTML: { __html: sanitizeInfoHtml(field.content) }
31021
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
31022
- className: "text-xs text-foreground-subtle leading-relaxed whitespace-pre-line",
31024
+ }) : field.content.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
31025
+ className: "text-xs text-foreground-subtle leading-relaxed whitespace-pre-line break-words",
31023
31026
  children: field.content
31024
31027
  })]
31025
31028
  })
@@ -61148,28 +61151,61 @@ function FormField$1({ label, description, error, required, children, orientatio
61148
61151
  }
61149
61152
  //#endregion
61150
61153
  //#region src/composites/grouped-tile-picker.tsx
61154
+ /**
61155
+ * `GroupedTilePicker` — choose ONE "type of thing" from tiles grouped by who
61156
+ * provides it (an AI profile kind, a notification-target kind…): an uppercase
61157
+ * group label, then a grid of icon + label tiles. The pre-modal of a
61158
+ * create-flow whose form depends on the choice.
61159
+ *
61160
+ * The tile is deliberately not a `Button`: a vertical icon-over-label card in
61161
+ * a grid, which toolbar-button chrome fights. One place owns that look so the
61162
+ * pickers stay identical.
61163
+ */
61151
61164
  function GroupedTilePicker({ groups, onPick, emptyMessage }) {
61165
+ const [openKey, setOpenKey] = (0, react$1.useState)(null);
61166
+ const openTile = openKey === null ? null : groups.flatMap((group) => group.tiles).find((tile) => tile.key === openKey) ?? null;
61152
61167
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
61153
61168
  className: "space-y-4",
61154
- children: [groups.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
61155
- className: "text-xs text-foreground-subtle",
61156
- children: emptyMessage
61157
- }), groups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
61158
- className: "mb-1.5 text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle",
61159
- children: group.label
61160
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
61161
- className: "grid grid-cols-2 gap-2 sm:grid-cols-3",
61162
- children: group.tiles.map((tile) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
61163
- type: "button",
61164
- "data-testid": tile.testId,
61165
- onClick: () => onPick(tile.key),
61166
- className: "flex flex-col items-center gap-1.5 rounded-lg border border-border bg-surface px-3 py-3 text-xs transition-colors hover:border-primary/50 hover:bg-surface-hover",
61167
- children: [tile.icon, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
61168
- className: "text-center font-medium text-foreground",
61169
- children: tile.label
61170
- })]
61171
- }, tile.key))
61172
- })] }, group.id))]
61169
+ children: [
61170
+ groups.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
61171
+ className: "text-xs text-foreground-subtle",
61172
+ children: emptyMessage
61173
+ }),
61174
+ groups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
61175
+ className: "mb-1.5 text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle",
61176
+ children: group.label
61177
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
61178
+ className: "grid grid-cols-2 gap-2 sm:grid-cols-3",
61179
+ children: group.tiles.map((tile) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
61180
+ className: "relative",
61181
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
61182
+ type: "button",
61183
+ "data-testid": tile.testId,
61184
+ onClick: () => onPick(tile.key),
61185
+ className: "flex h-full w-full flex-col items-center gap-1.5 rounded-lg border border-border bg-surface px-3 py-3 text-xs transition-colors hover:border-primary/50 hover:bg-surface-hover",
61186
+ children: [tile.icon, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
61187
+ className: "text-center font-medium text-foreground",
61188
+ children: tile.label
61189
+ })]
61190
+ }), tile.detail !== void 0 && tile.detailLabel !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
61191
+ className: "absolute top-1 right-1",
61192
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconButton, {
61193
+ type: "button",
61194
+ variant: "ghost",
61195
+ size: "sm",
61196
+ icon: Info,
61197
+ "aria-label": tile.detailLabel,
61198
+ onClick: () => setOpenKey((current) => current === tile.key ? null : tile.key)
61199
+ })
61200
+ })]
61201
+ }, tile.key))
61202
+ })] }, group.id)),
61203
+ openTile?.detail !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BottomSheet, {
61204
+ open: true,
61205
+ onClose: () => setOpenKey(null),
61206
+ children: openTile.detail
61207
+ })
61208
+ ]
61173
61209
  });
61174
61210
  }
61175
61211
  //#endregion
package/dist/index.js CHANGED
@@ -14480,6 +14480,9 @@ function AccountSignInField({ field, values, disabled, onAction, onChangeMany })
14480
14480
  if (Object.keys(patch).length > 0) onChangeMany?.(patch);
14481
14481
  const nextChoices = choicesOf(result["choices"]);
14482
14482
  setChoices(nextChoices.length > 1 ? nextChoices : []);
14483
+ const picked = typeof result["gatewayId"] === "string" && result["gatewayId"].length > 0;
14484
+ const summary = typeof result["summary"] === "string" ? result["summary"] : null;
14485
+ if (summary !== null && !picked && nextChoices.length < 2) setError(summary);
14483
14486
  setPhase("idle");
14484
14487
  setPaste("");
14485
14488
  setAttemptId(null);
@@ -30989,13 +30992,13 @@ function InfoBox({ field }) {
30989
30992
  children: /* @__PURE__ */ jsxs("div", {
30990
30993
  className: `rounded-md border-l-4 px-3 py-2.5 ${styles.border} ${styles.bg}`,
30991
30994
  children: [field.label && /* @__PURE__ */ jsx("p", {
30992
- className: `text-xs font-semibold mb-0.5 ${styles.text}`,
30995
+ className: field.content.length > 0 ? `text-xs font-semibold mb-0.5 ${styles.text}` : "text-xs text-foreground-subtle leading-relaxed whitespace-pre-line break-words",
30993
30996
  children: field.label
30994
30997
  }), isHtml ? /* @__PURE__ */ jsx("div", {
30995
30998
  className: "text-xs text-foreground-subtle leading-relaxed info-html-content",
30996
30999
  dangerouslySetInnerHTML: { __html: sanitizeInfoHtml(field.content) }
30997
- }) : /* @__PURE__ */ jsx("p", {
30998
- className: "text-xs text-foreground-subtle leading-relaxed whitespace-pre-line",
31000
+ }) : field.content.length > 0 && /* @__PURE__ */ jsx("p", {
31001
+ className: "text-xs text-foreground-subtle leading-relaxed whitespace-pre-line break-words",
30999
31002
  children: field.content
31000
31003
  })]
31001
31004
  })
@@ -61124,28 +61127,61 @@ function FormField$1({ label, description, error, required, children, orientatio
61124
61127
  }
61125
61128
  //#endregion
61126
61129
  //#region src/composites/grouped-tile-picker.tsx
61130
+ /**
61131
+ * `GroupedTilePicker` — choose ONE "type of thing" from tiles grouped by who
61132
+ * provides it (an AI profile kind, a notification-target kind…): an uppercase
61133
+ * group label, then a grid of icon + label tiles. The pre-modal of a
61134
+ * create-flow whose form depends on the choice.
61135
+ *
61136
+ * The tile is deliberately not a `Button`: a vertical icon-over-label card in
61137
+ * a grid, which toolbar-button chrome fights. One place owns that look so the
61138
+ * pickers stay identical.
61139
+ */
61127
61140
  function GroupedTilePicker({ groups, onPick, emptyMessage }) {
61141
+ const [openKey, setOpenKey] = useState(null);
61142
+ const openTile = openKey === null ? null : groups.flatMap((group) => group.tiles).find((tile) => tile.key === openKey) ?? null;
61128
61143
  return /* @__PURE__ */ jsxs("div", {
61129
61144
  className: "space-y-4",
61130
- children: [groups.length === 0 && /* @__PURE__ */ jsx("p", {
61131
- className: "text-xs text-foreground-subtle",
61132
- children: emptyMessage
61133
- }), groups.map((group) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
61134
- className: "mb-1.5 text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle",
61135
- children: group.label
61136
- }), /* @__PURE__ */ jsx("div", {
61137
- className: "grid grid-cols-2 gap-2 sm:grid-cols-3",
61138
- children: group.tiles.map((tile) => /* @__PURE__ */ jsxs("button", {
61139
- type: "button",
61140
- "data-testid": tile.testId,
61141
- onClick: () => onPick(tile.key),
61142
- className: "flex flex-col items-center gap-1.5 rounded-lg border border-border bg-surface px-3 py-3 text-xs transition-colors hover:border-primary/50 hover:bg-surface-hover",
61143
- children: [tile.icon, /* @__PURE__ */ jsx("span", {
61144
- className: "text-center font-medium text-foreground",
61145
- children: tile.label
61146
- })]
61147
- }, tile.key))
61148
- })] }, group.id))]
61145
+ children: [
61146
+ groups.length === 0 && /* @__PURE__ */ jsx("p", {
61147
+ className: "text-xs text-foreground-subtle",
61148
+ children: emptyMessage
61149
+ }),
61150
+ groups.map((group) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
61151
+ className: "mb-1.5 text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle",
61152
+ children: group.label
61153
+ }), /* @__PURE__ */ jsx("div", {
61154
+ className: "grid grid-cols-2 gap-2 sm:grid-cols-3",
61155
+ children: group.tiles.map((tile) => /* @__PURE__ */ jsxs("div", {
61156
+ className: "relative",
61157
+ children: [/* @__PURE__ */ jsxs("button", {
61158
+ type: "button",
61159
+ "data-testid": tile.testId,
61160
+ onClick: () => onPick(tile.key),
61161
+ className: "flex h-full w-full flex-col items-center gap-1.5 rounded-lg border border-border bg-surface px-3 py-3 text-xs transition-colors hover:border-primary/50 hover:bg-surface-hover",
61162
+ children: [tile.icon, /* @__PURE__ */ jsx("span", {
61163
+ className: "text-center font-medium text-foreground",
61164
+ children: tile.label
61165
+ })]
61166
+ }), tile.detail !== void 0 && tile.detailLabel !== void 0 && /* @__PURE__ */ jsx("div", {
61167
+ className: "absolute top-1 right-1",
61168
+ children: /* @__PURE__ */ jsx(IconButton, {
61169
+ type: "button",
61170
+ variant: "ghost",
61171
+ size: "sm",
61172
+ icon: Info,
61173
+ "aria-label": tile.detailLabel,
61174
+ onClick: () => setOpenKey((current) => current === tile.key ? null : tile.key)
61175
+ })
61176
+ })]
61177
+ }, tile.key))
61178
+ })] }, group.id)),
61179
+ openTile?.detail !== void 0 && /* @__PURE__ */ jsx(BottomSheet, {
61180
+ open: true,
61181
+ onClose: () => setOpenKey(null),
61182
+ children: openTile.detail
61183
+ })
61184
+ ]
61149
61185
  });
61150
61186
  }
61151
61187
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/ui-library",
3
- "version": "1.2.331",
3
+ "version": "1.2.332",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/camstack/server.git",