dishui 0.0.91 → 0.0.101

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.
Files changed (156) hide show
  1. package/dist/.release-verified.json +6 -0
  2. package/dist/ai.js +24 -0
  3. package/dist/components/Card/Metric2.js +11 -11
  4. package/dist/components/Card/Metric2.js.map +1 -1
  5. package/dist/components/Card/Ticket.d.ts +52 -0
  6. package/dist/components/Card/Ticket2.js +218 -0
  7. package/dist/components/Card/Ticket2.js.map +1 -0
  8. package/dist/components/Card/index.d.ts +32 -0
  9. package/dist/components/Card/index.js +211 -203
  10. package/dist/components/Card/index.js.map +1 -1
  11. package/dist/components/GroupButton/index.js +4 -4
  12. package/dist/components/GroupButton/index.js.map +1 -1
  13. package/dist/components/GroupedTable/index.js +10 -10
  14. package/dist/components/GroupedTable/index.js.map +1 -1
  15. package/dist/components/NavigationList/index.js +9 -9
  16. package/dist/components/NavigationList/index.js.map +1 -1
  17. package/dist/components/Section/index.js +11 -11
  18. package/dist/components/Section/index.js.map +1 -1
  19. package/dist/components/Skeleton/index.js +1 -1
  20. package/dist/components/Skeleton/index.js.map +1 -1
  21. package/dist/components/Table/index.js +6 -6
  22. package/dist/components/Table/index.js.map +1 -1
  23. package/dist/components/ai/AgentChat/index.d.ts +54 -0
  24. package/dist/components/ai/AgentChat/index.js +176 -0
  25. package/dist/components/ai/AgentChat/index.js.map +1 -0
  26. package/dist/components/ai/AgentRunCard/index.d.ts +38 -0
  27. package/dist/components/ai/AgentRunCard/index.js +100 -0
  28. package/dist/components/ai/AgentRunCard/index.js.map +1 -0
  29. package/dist/components/ai/AgentScreen/index.d.ts +50 -0
  30. package/dist/components/ai/AgentScreen/index.js +233 -0
  31. package/dist/components/ai/AgentScreen/index.js.map +1 -0
  32. package/dist/components/ai/ApprovalCard/index.d.ts +26 -0
  33. package/dist/components/ai/ApprovalCard/index.js +89 -0
  34. package/dist/components/ai/ApprovalCard/index.js.map +1 -0
  35. package/dist/components/ai/CodeView/index.d.ts +30 -0
  36. package/dist/components/ai/CodeView/index.js +149 -0
  37. package/dist/components/ai/CodeView/index.js.map +1 -0
  38. package/dist/components/ai/CommandSearch/index.d.ts +39 -0
  39. package/dist/components/ai/CommandSearch/index.js +217 -0
  40. package/dist/components/ai/CommandSearch/index.js.map +1 -0
  41. package/dist/components/ai/ContextCards/index.d.ts +42 -0
  42. package/dist/components/ai/ContextCards/index.js +106 -0
  43. package/dist/components/ai/ContextCards/index.js.map +1 -0
  44. package/dist/components/ai/DiffTable/index.d.ts +70 -0
  45. package/dist/components/ai/DiffTable/index.js +235 -0
  46. package/dist/components/ai/DiffTable/index.js.map +1 -0
  47. package/dist/components/ai/FilterTable/index.d.ts +35 -0
  48. package/dist/components/ai/FilterTable/index.js +86 -0
  49. package/dist/components/ai/FilterTable/index.js.map +1 -0
  50. package/dist/components/ai/FineTuneCard/index.d.ts +24 -0
  51. package/dist/components/ai/FineTuneCard/index.js +75 -0
  52. package/dist/components/ai/FineTuneCard/index.js.map +1 -0
  53. package/dist/components/ai/InsightCards/index.d.ts +23 -0
  54. package/dist/components/ai/InsightCards/index.js +64 -0
  55. package/dist/components/ai/InsightCards/index.js.map +1 -0
  56. package/dist/components/ai/IssueCard/index.d.ts +39 -0
  57. package/dist/components/ai/IssueCard/index.js +78 -0
  58. package/dist/components/ai/IssueCard/index.js.map +1 -0
  59. package/dist/components/ai/LoadingState/index.d.ts +22 -0
  60. package/dist/components/ai/LoadingState/index.js +80 -0
  61. package/dist/components/ai/LoadingState/index.js.map +1 -0
  62. package/dist/components/ai/PromptBar/index.d.ts +26 -0
  63. package/dist/components/ai/PromptBar/index.js +117 -0
  64. package/dist/components/ai/PromptBar/index.js.map +1 -0
  65. package/dist/components/ai/RecommendationCard/index.d.ts +44 -0
  66. package/dist/components/ai/RecommendationCard/index.js +142 -0
  67. package/dist/components/ai/RecommendationCard/index.js.map +1 -0
  68. package/dist/components/ai/RecordsTable/index.d.ts +65 -0
  69. package/dist/components/ai/RecordsTable/index.js +334 -0
  70. package/dist/components/ai/RecordsTable/index.js.map +1 -0
  71. package/dist/components/ai/SelectionActions/index.d.ts +19 -0
  72. package/dist/components/ai/SelectionActions/index.js +40 -0
  73. package/dist/components/ai/SelectionActions/index.js.map +1 -0
  74. package/dist/components/ai/StateFlow/index.d.ts +24 -0
  75. package/dist/components/ai/StateFlow/index.js +50 -0
  76. package/dist/components/ai/StateFlow/index.js.map +1 -0
  77. package/dist/components/ai/StreamingText/index.d.ts +44 -0
  78. package/dist/components/ai/StreamingText/index.js +211 -0
  79. package/dist/components/ai/StreamingText/index.js.map +1 -0
  80. package/dist/components/ai/TaskRows/index.d.ts +53 -0
  81. package/dist/components/ai/TaskRows/index.js +186 -0
  82. package/dist/components/ai/TaskRows/index.js.map +1 -0
  83. package/dist/components/ai/Thinking/index.d.ts +47 -0
  84. package/dist/components/ai/Thinking/index.js +197 -0
  85. package/dist/components/ai/Thinking/index.js.map +1 -0
  86. package/dist/components/ai/ToolChips/index.d.ts +21 -0
  87. package/dist/components/ai/ToolChips/index.js +63 -0
  88. package/dist/components/ai/ToolChips/index.js.map +1 -0
  89. package/dist/components/ai/index.d.ts +54 -0
  90. package/dist/components/ai/shared.d.ts +13 -0
  91. package/dist/components/ai/shared.js +25 -0
  92. package/dist/components/ai/shared.js.map +1 -0
  93. package/dist/components/pro/DataTable/rowDetailExtension.js +1 -1
  94. package/dist/components/pro/DataTable/rowDetailExtension.js.map +1 -1
  95. package/dist/components/pro/Flow/constants.js +3 -3
  96. package/dist/components/pro/Flow/constants.js.map +1 -1
  97. package/dist/components/pro/Flow/nodes/shapes.js +3 -3
  98. package/dist/components/pro/Flow/nodes/shapes.js.map +1 -1
  99. package/dist/components/pro/Flow/utils/themeColor.d.ts +2 -2
  100. package/dist/components/pro/Flow/utils/themeColor.js +2 -2
  101. package/dist/components/pro/Flow/utils/themeColor.js.map +1 -1
  102. package/dist/components/pro/Kanban/Kanban.d.ts +3 -0
  103. package/dist/components/pro/Kanban/Kanban.js +339 -0
  104. package/dist/components/pro/Kanban/Kanban.js.map +1 -0
  105. package/dist/components/pro/Kanban/Swimlanes.d.ts +3 -0
  106. package/dist/components/pro/Kanban/Swimlanes.js +60 -0
  107. package/dist/components/pro/Kanban/Swimlanes.js.map +1 -0
  108. package/dist/components/pro/Kanban/index.d.ts +5 -0
  109. package/dist/components/pro/Kanban/types.d.ts +103 -0
  110. package/dist/components/pro/Kanban/useKanbanDrag.d.ts +17 -0
  111. package/dist/components/pro/Kanban/useKanbanDrag.js +69 -0
  112. package/dist/components/pro/Kanban/useKanbanDrag.js.map +1 -0
  113. package/dist/components/pro/Kanban/utils.d.ts +13 -0
  114. package/dist/components/pro/Kanban/utils.js +48 -0
  115. package/dist/components/pro/Kanban/utils.js.map +1 -0
  116. package/dist/components/pro/RichTextEditor/AIRewrite.js +158 -127
  117. package/dist/components/pro/RichTextEditor/AIRewrite.js.map +1 -1
  118. package/dist/components/pro/RichTextEditor/BlockHandle.d.ts +2 -0
  119. package/dist/components/pro/RichTextEditor/BlockHandle.js +156 -115
  120. package/dist/components/pro/RichTextEditor/BlockHandle.js.map +1 -1
  121. package/dist/components/pro/RichTextEditor/RichTextEditor.js +136 -159
  122. package/dist/components/pro/RichTextEditor/RichTextEditor.js.map +1 -1
  123. package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js +44 -41
  124. package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js.map +1 -1
  125. package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js +59 -53
  126. package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js.map +1 -1
  127. package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js +48 -44
  128. package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js.map +1 -1
  129. package/dist/components/pro/RichTextEditor/Toolbar/TableOpsMenu.js +67 -63
  130. package/dist/components/pro/RichTextEditor/Toolbar/TableOpsMenu.js.map +1 -1
  131. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.d.ts +1 -0
  132. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js +182 -129
  133. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js.map +1 -1
  134. package/dist/components/pro/RichTextEditor/Toolbar/ToolbarButton.d.ts +1 -0
  135. package/dist/components/pro/RichTextEditor/Toolbar/ToolbarButton.js +3 -3
  136. package/dist/components/pro/RichTextEditor/Toolbar/ToolbarButton.js.map +1 -1
  137. package/dist/components/pro/RichTextEditor/Toolbar/useAnchoredDropdown.d.ts +3 -0
  138. package/dist/components/pro/RichTextEditor/Toolbar/useAnchoredDropdown.js +31 -0
  139. package/dist/components/pro/RichTextEditor/Toolbar/useAnchoredDropdown.js.map +1 -0
  140. package/dist/components/pro/RichTextEditor/index.d.ts +1 -1
  141. package/dist/components/pro/RichTextEditor/types.d.ts +78 -11
  142. package/dist/components/pro/RichTextEditor/types.js +11 -0
  143. package/dist/components/pro/RichTextEditor/types.js.map +1 -1
  144. package/dist/dishui.css +1 -1
  145. package/dist/index-nostyled.d.ts +1 -1
  146. package/dist/index.d.ts +6 -3
  147. package/dist/index.js +134 -107
  148. package/dist/kanban.js +5 -0
  149. package/dist/layouts/Sidebar.d.ts +16 -0
  150. package/dist/layouts/Sidebar.js +85 -52
  151. package/dist/layouts/Sidebar.js.map +1 -1
  152. package/dist/utils/i18n.js +20 -0
  153. package/dist/utils/i18n.js.map +1 -1
  154. package/dist/utils/menu.js +1 -1
  155. package/dist/utils/menu.js.map +1 -1
  156. package/package.json +14 -3
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ /** Priority tone drives the small trailing dot beside the identifier. */
3
+ export type IssuePriority = 'none' | 'low' | 'medium' | 'high' | 'urgent';
4
+ /** Accent stripe on the leading edge of the card. */
5
+ export type IssueAccent = 'none' | 'neutral' | 'info' | 'success' | 'warning' | 'danger';
6
+ export type IssueLabel = {
7
+ id?: string;
8
+ text: React.ReactNode;
9
+ };
10
+ export type IssueCardProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'title' | 'onSelect'> & {
11
+ /** Primary issue title. */
12
+ title: React.ReactNode;
13
+ /** Short labels/tags shown below the title (e.g. `ui`, `infra`). */
14
+ labels?: Array<IssueLabel | string>;
15
+ /** Leading icon slot (e.g. issue type glyph). Style the box via `iconTone`. */
16
+ icon?: React.ReactNode;
17
+ /** Colour of the leading icon box. */
18
+ iconTone?: 'neutral' | 'info' | 'success' | 'warning' | 'danger';
19
+ /** Human-facing identifier, rendered in a monospace, tabular style (e.g. `FCE-38`). */
20
+ identifier?: React.ReactNode;
21
+ /** Priority drives the coloured dot next to the identifier. */
22
+ priority?: IssuePriority;
23
+ /** Numeric badge on the trailing edge (e.g. estimate/points). */
24
+ count?: React.ReactNode;
25
+ /** Assignee slot, typically an `Avatar`. */
26
+ assignee?: React.ReactNode;
27
+ /** Coloured stripe on the leading edge. Defaults to `none`. */
28
+ accent?: IssueAccent;
29
+ /** Selected state (raises border + subtle surface shift). */
30
+ selected?: boolean;
31
+ /** Click handler turns the card into a button for keyboard users. */
32
+ onSelect?: () => void;
33
+ };
34
+ /**
35
+ * Linear-style issue card: an optional accent stripe, a title, small labels,
36
+ * and a footer that pairs a type icon, identifier, a priority dot, an estimate
37
+ * and an assignee. Status is always carried by text/icon, never colour alone.
38
+ */
39
+ export default function IssueCard({ title, labels, icon, iconTone, identifier, priority, count, assignee, accent, selected, onSelect, className, ...rest }: IssueCardProps): React.JSX.Element;
@@ -0,0 +1,78 @@
1
+ import { cn as e } from "../../../utils/cn.js";
2
+ /* empty css */
3
+ import "react";
4
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
5
+ //#region src/components/ai/IssueCard/index.tsx
6
+ var r = {
7
+ none: "No priority",
8
+ low: "Low priority",
9
+ medium: "Medium priority",
10
+ high: "High priority",
11
+ urgent: "Urgent priority"
12
+ }, i = [], a = (e, t) => typeof e == "string" ? {
13
+ text: e,
14
+ key: `${e}-${t}`
15
+ } : {
16
+ ...e,
17
+ key: e.id ?? `${String(e.text)}-${t}`
18
+ };
19
+ function o({ title: o, labels: s = i, icon: c, iconTone: l = "neutral", identifier: u, priority: d = "none", count: f, assignee: p, accent: m = "none", selected: h = !1, onSelect: g, className: _, ...v }) {
20
+ let y = !!g, b = s.map(a);
21
+ return /* @__PURE__ */ n("div", {
22
+ ...v,
23
+ className: e("dishui-ai-issue-card", m !== "none" && `dishui-ai-issue-card--accent-${m}`, h && "dishui-ai-issue-card--selected", y && "dishui-ai-issue-card--interactive", _),
24
+ role: y ? "button" : void 0,
25
+ tabIndex: y ? 0 : void 0,
26
+ "aria-pressed": y ? h : void 0,
27
+ onClick: y ? g : v.onClick,
28
+ onKeyDown: y ? (e) => {
29
+ e.target === e.currentTarget && (e.key === "Enter" || e.key === " ") && (e.preventDefault(), e.repeat || g?.());
30
+ } : void 0,
31
+ children: [
32
+ /* @__PURE__ */ t("h3", {
33
+ className: "dishui-ai-issue-card__title",
34
+ children: o
35
+ }),
36
+ b.length > 0 && /* @__PURE__ */ t("div", {
37
+ className: "dishui-ai-issue-card__labels",
38
+ children: b.map((e) => /* @__PURE__ */ t("span", {
39
+ className: "dishui-ai-issue-card__label",
40
+ children: e.text
41
+ }, e.key))
42
+ }),
43
+ /* @__PURE__ */ n("div", {
44
+ className: "dishui-ai-issue-card__footer",
45
+ children: [
46
+ c != null && /* @__PURE__ */ t("span", {
47
+ className: e("dishui-ai-issue-card__icon", `dishui-ai-issue-card__icon--${l}`),
48
+ "aria-hidden": "true",
49
+ children: c
50
+ }),
51
+ u != null && /* @__PURE__ */ t("span", {
52
+ className: "dishui-ai-issue-card__id",
53
+ children: u
54
+ }),
55
+ d !== "none" && /* @__PURE__ */ t("span", {
56
+ className: e("dishui-ai-issue-card__priority", `dishui-ai-issue-card__priority--${d}`),
57
+ role: "img",
58
+ "aria-label": r[d],
59
+ title: r[d]
60
+ }),
61
+ /* @__PURE__ */ t("span", { className: "dishui-ai-issue-card__spacer" }),
62
+ f != null && /* @__PURE__ */ t("span", {
63
+ className: "dishui-ai-issue-card__count",
64
+ children: f
65
+ }),
66
+ p != null && /* @__PURE__ */ t("span", {
67
+ className: "dishui-ai-issue-card__assignee",
68
+ children: p
69
+ })
70
+ ]
71
+ })
72
+ ]
73
+ });
74
+ }
75
+ //#endregion
76
+ export { o as default };
77
+
78
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/IssueCard/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../../utils/cn';\nimport './IssueCard.css';\n\n/** Priority tone drives the small trailing dot beside the identifier. */\nexport type IssuePriority = 'none' | 'low' | 'medium' | 'high' | 'urgent';\n\n/** Accent stripe on the leading edge of the card. */\nexport type IssueAccent = 'none' | 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n\nexport type IssueLabel = {\n id?: string;\n text: React.ReactNode;\n};\n\nexport type IssueCardProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'title' | 'onSelect'> & {\n /** Primary issue title. */\n title: React.ReactNode;\n /** Short labels/tags shown below the title (e.g. `ui`, `infra`). */\n labels?: Array<IssueLabel | string>;\n /** Leading icon slot (e.g. issue type glyph). Style the box via `iconTone`. */\n icon?: React.ReactNode;\n /** Colour of the leading icon box. */\n iconTone?: 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n /** Human-facing identifier, rendered in a monospace, tabular style (e.g. `FCE-38`). */\n identifier?: React.ReactNode;\n /** Priority drives the coloured dot next to the identifier. */\n priority?: IssuePriority;\n /** Numeric badge on the trailing edge (e.g. estimate/points). */\n count?: React.ReactNode;\n /** Assignee slot, typically an `Avatar`. */\n assignee?: React.ReactNode;\n /** Coloured stripe on the leading edge. Defaults to `none`. */\n accent?: IssueAccent;\n /** Selected state (raises border + subtle surface shift). */\n selected?: boolean;\n /** Click handler turns the card into a button for keyboard users. */\n onSelect?: () => void;\n};\n\nconst PRIORITY_LABEL: Record<IssuePriority, string> = {\n none: 'No priority',\n low: 'Low priority',\n medium: 'Medium priority',\n high: 'High priority',\n urgent: 'Urgent priority',\n};\n\nconst EMPTY_LABELS: Array<IssueLabel | string> = [];\n\nconst toLabel = (label: IssueLabel | string, index: number): IssueLabel & { key: string } => {\n if (typeof label === 'string') return { text: label, key: `${label}-${index}` };\n return { ...label, key: label.id ?? `${String(label.text)}-${index}` };\n};\n\n/**\n * Linear-style issue card: an optional accent stripe, a title, small labels,\n * and a footer that pairs a type icon, identifier, a priority dot, an estimate\n * and an assignee. Status is always carried by text/icon, never colour alone.\n */\nexport default function IssueCard({\n title,\n labels = EMPTY_LABELS,\n icon,\n iconTone = 'neutral',\n identifier,\n priority = 'none',\n count,\n assignee,\n accent = 'none',\n selected = false,\n onSelect,\n className,\n ...rest\n}: IssueCardProps) {\n const interactive = !!onSelect;\n const items = labels.map(toLabel);\n\n return (\n <div\n {...rest}\n className={cn(\n 'dishui-ai-issue-card',\n accent !== 'none' && `dishui-ai-issue-card--accent-${accent}`,\n selected && 'dishui-ai-issue-card--selected',\n interactive && 'dishui-ai-issue-card--interactive',\n className,\n )}\n role={interactive ? 'button' : undefined}\n tabIndex={interactive ? 0 : undefined}\n aria-pressed={interactive ? selected : undefined}\n onClick={interactive ? onSelect : rest.onClick}\n onKeyDown={interactive ? (event) => {\n if (event.target !== event.currentTarget) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n if (!event.repeat) onSelect?.();\n }\n } : undefined}\n >\n <h3 className=\"dishui-ai-issue-card__title\">{title}</h3>\n\n {items.length > 0 && (\n <div className=\"dishui-ai-issue-card__labels\">\n {items.map(label => (\n <span key={label.key} className=\"dishui-ai-issue-card__label\">{label.text}</span>\n ))}\n </div>\n )}\n\n <div className=\"dishui-ai-issue-card__footer\">\n {icon !== null && icon !== undefined && (\n <span className={cn('dishui-ai-issue-card__icon', `dishui-ai-issue-card__icon--${iconTone}`)} aria-hidden=\"true\">\n {icon}\n </span>\n )}\n {identifier !== null && identifier !== undefined && (\n <span className=\"dishui-ai-issue-card__id\">{identifier}</span>\n )}\n {priority !== 'none' && (\n <span\n className={cn('dishui-ai-issue-card__priority', `dishui-ai-issue-card__priority--${priority}`)}\n role=\"img\"\n aria-label={PRIORITY_LABEL[priority]}\n title={PRIORITY_LABEL[priority]}\n />\n )}\n <span className=\"dishui-ai-issue-card__spacer\" />\n {count !== null && count !== undefined && (\n <span className=\"dishui-ai-issue-card__count\">{count}</span>\n )}\n {assignee !== null && assignee !== undefined && (\n <span className=\"dishui-ai-issue-card__assignee\">{assignee}</span>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAwCA,IAAM,IAAgD;CACpD,MAAM;CACN,KAAK;CACL,QAAQ;CACR,MAAM;CACN,QAAQ;AACV,GAEM,IAA2C,CAAC,GAE5C,KAAW,GAA4B,MACvC,OAAO,KAAU,WAAiB;CAAE,MAAM;CAAO,KAAK,GAAG,EAAM,GAAG;AAAQ,IACvE;CAAE,GAAG;CAAO,KAAK,EAAM,MAAM,GAAG,OAAO,EAAM,IAAI,EAAE,GAAG;AAAQ;AAQvE,SAAwB,EAAU,EAChC,UACA,YAAS,GACT,SACA,cAAW,WACX,eACA,cAAW,QACX,UACA,aACA,YAAS,QACT,cAAW,IACX,aACA,cACA,GAAG,KACc;CACjB,IAAM,IAAc,CAAC,CAAC,GAChB,IAAQ,EAAO,IAAI,CAAO;CAEhC,OACE,kBAAC,OAAD;EACE,GAAI;EACJ,WAAW,EACT,wBACA,MAAW,UAAU,gCAAgC,KACrD,KAAY,kCACZ,KAAe,qCACf,CACF;EACA,MAAM,IAAc,WAAW,KAAA;EAC/B,UAAU,IAAc,IAAI,KAAA;EAC5B,gBAAc,IAAc,IAAW,KAAA;EACvC,SAAS,IAAc,IAAW,EAAK;EACvC,WAAW,KAAe,MAAU;GAC9B,EAAM,WAAW,EAAM,kBACvB,EAAM,QAAQ,WAAW,EAAM,QAAQ,SACzC,EAAM,eAAe,GAChB,EAAM,UAAQ,IAAW;EAElC,IAAI,KAAA;EAnBN,UAAA;GAqBE,kBAAC,MAAD;IAAI,WAAU;IAA+B,UAAA;GAAU,CAAA;GAEtD,EAAM,SAAS,KACd,kBAAC,OAAD;IAAK,WAAU;IACZ,UAAA,EAAM,KAAI,MACT,kBAAC,QAAD;KAAsB,WAAU;KAA+B,UAAA,EAAM;IAAW,GAArE,EAAM,GAA+D,CACjF;GACE,CAAA;GAGP,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACG,KAAS,QACR,kBAAC,QAAD;MAAM,WAAW,EAAG,8BAA8B,+BAA+B,GAAU;MAAG,eAAY;MACvG,UAAA;KACG,CAAA;KAEP,KAAe,QACd,kBAAC,QAAD;MAAM,WAAU;MAA4B,UAAA;KAAiB,CAAA;KAE9D,MAAa,UACZ,kBAAC,QAAD;MACE,WAAW,EAAG,kCAAkC,mCAAmC,GAAU;MAC7F,MAAK;MACL,cAAY,EAAe;MAC3B,OAAO,EAAe;KACvB,CAAA;KAEH,kBAAC,QAAD,EAAM,WAAU,+BAAgC,CAAA;KAC/C,KAAU,QACT,kBAAC,QAAD;MAAM,WAAU;MAA+B,UAAA;KAAY,CAAA;KAE5D,KAAa,QACZ,kBAAC,QAAD;MAAM,WAAU;MAAkC,UAAA;KAAe,CAAA;IAEhE;;EACF;;AAET"}
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ export type LoadingStateVariant = 'grid' | 'drive' | 'dots' | 'orbit' | 'surfer';
3
+ export type LoadingStateProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {
4
+ /** Short present-tense verb shown next to the glyph, e.g. `Churning`, `Searching`. */
5
+ label?: React.ReactNode;
6
+ /** Glyph animation. All variants are indeterminate and respect reduced motion. */
7
+ variant?: LoadingStateVariant;
8
+ /** Show the elapsed time next to the label. */
9
+ showElapsed?: boolean;
10
+ /** Epoch milliseconds the work started; defaults to mount time. */
11
+ startedAt?: number;
12
+ /** Controlled elapsed time in milliseconds. When set, the internal timer is disabled. */
13
+ elapsedMs?: number;
14
+ /** `inline` sits in a sentence; `block` renders a bordered row. */
15
+ layout?: 'inline' | 'block';
16
+ size?: 'sm' | 'md';
17
+ };
18
+ /**
19
+ * Indeterminate agent progress: pixel-grid (or sibling) glyph, a short label
20
+ * and the elapsed time. Announces as a polite status region.
21
+ */
22
+ export default function LoadingState({ label, variant, showElapsed, startedAt, elapsedMs, layout, size, className, ...rest }: LoadingStateProps): React.JSX.Element;
@@ -0,0 +1,80 @@
1
+ import { cn as e } from "../../../utils/cn.js";
2
+ import { formatElapsed as t } from "../shared.js";
3
+ /* empty css */
4
+ import { useEffect as n, useState as r } from "react";
5
+ import { Fragment as i, jsx as a, jsxs as o } from "react/jsx-runtime";
6
+ //#region src/components/ai/LoadingState/index.tsx
7
+ var s = (e) => ({ "--i": e }), c = ({ variant: e }) => {
8
+ switch (e) {
9
+ case "drive": return /* @__PURE__ */ a("span", {
10
+ className: "dishui-ai-loading__drive",
11
+ children: Array.from({ length: 4 }, (e, t) => /* @__PURE__ */ a("span", {
12
+ className: "dishui-ai-loading__cell",
13
+ style: s(t)
14
+ }, t))
15
+ });
16
+ case "dots": return /* @__PURE__ */ a("span", {
17
+ className: "dishui-ai-loading__dots",
18
+ children: Array.from({ length: 3 }, (e, t) => /* @__PURE__ */ a("span", {
19
+ className: "dishui-ai-loading__dot",
20
+ style: s(t)
21
+ }, t))
22
+ });
23
+ case "orbit": return /* @__PURE__ */ o(i, { children: [/* @__PURE__ */ a("span", { className: "dishui-ai-loading__orbit" }), /* @__PURE__ */ a("span", { className: "dishui-ai-loading__satellite" })] });
24
+ case "surfer": return /* @__PURE__ */ a("span", {
25
+ className: "dishui-ai-loading__surfer",
26
+ children: Array.from({ length: 5 }, (e, t) => /* @__PURE__ */ a("span", {
27
+ className: "dishui-ai-loading__bar",
28
+ style: s(t)
29
+ }, t))
30
+ });
31
+ default: return /* @__PURE__ */ a("span", {
32
+ className: "dishui-ai-loading__grid",
33
+ children: Array.from({ length: 16 }, (e, t) => {
34
+ let n = Math.floor(t / 4) + t % 4;
35
+ return /* @__PURE__ */ a("span", {
36
+ className: "dishui-ai-loading__cell",
37
+ style: s(n)
38
+ }, t);
39
+ })
40
+ });
41
+ }
42
+ };
43
+ function l({ label: i = "Thinking", variant: s = "grid", showElapsed: l = !0, startedAt: u, elapsedMs: d, layout: f = "inline", size: p = "md", className: m, ...h }) {
44
+ let [g, _] = r(0), v = d !== void 0;
45
+ n(() => {
46
+ if (v || !l) return;
47
+ let e = u ?? Date.now(), t = window.setInterval(() => _(Date.now() - e), 100);
48
+ return () => window.clearInterval(t);
49
+ }, [
50
+ v,
51
+ l,
52
+ u
53
+ ]);
54
+ let y = v ? d : g;
55
+ return /* @__PURE__ */ o("div", {
56
+ role: "status",
57
+ "aria-live": "polite",
58
+ ...h,
59
+ className: e("dishui-ai-loading", `dishui-ai-loading--${s}`, p === "sm" && "dishui-ai-loading--sm", f === "block" && "dishui-ai-loading--block", m),
60
+ children: [
61
+ /* @__PURE__ */ a("span", {
62
+ className: "dishui-ai-loading__glyph",
63
+ "aria-hidden": "true",
64
+ children: /* @__PURE__ */ a(c, { variant: s })
65
+ }),
66
+ /* @__PURE__ */ a("span", {
67
+ className: "dishui-ai-loading__label",
68
+ children: i
69
+ }),
70
+ l && /* @__PURE__ */ a("span", {
71
+ className: "dishui-ai-loading__elapsed",
72
+ children: t(y)
73
+ })
74
+ ]
75
+ });
76
+ }
77
+ //#endregion
78
+ export { l as default };
79
+
80
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/LoadingState/index.tsx"],"sourcesContent":["import React, { useEffect, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport { formatElapsed } from '../shared';\nimport './LoadingState.css';\n\nexport type LoadingStateVariant = 'grid' | 'drive' | 'dots' | 'orbit' | 'surfer';\n\nexport type LoadingStateProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {\n /** Short present-tense verb shown next to the glyph, e.g. `Churning`, `Searching`. */\n label?: React.ReactNode;\n /** Glyph animation. All variants are indeterminate and respect reduced motion. */\n variant?: LoadingStateVariant;\n /** Show the elapsed time next to the label. */\n showElapsed?: boolean;\n /** Epoch milliseconds the work started; defaults to mount time. */\n startedAt?: number;\n /** Controlled elapsed time in milliseconds. When set, the internal timer is disabled. */\n elapsedMs?: number;\n /** `inline` sits in a sentence; `block` renders a bordered row. */\n layout?: 'inline' | 'block';\n size?: 'sm' | 'md';\n};\n\nconst index = (i: number) => ({ '--i': i } as React.CSSProperties);\n\nconst Glyph: React.FC<{ variant: LoadingStateVariant }> = ({ variant }) => {\n switch (variant) {\n case 'drive':\n return (\n <span className=\"dishui-ai-loading__drive\">\n {Array.from({ length: 4 }, (_, i) => <span key={i} className=\"dishui-ai-loading__cell\" style={index(i)} />)}\n </span>\n );\n case 'dots':\n return (\n <span className=\"dishui-ai-loading__dots\">\n {Array.from({ length: 3 }, (_, i) => <span key={i} className=\"dishui-ai-loading__dot\" style={index(i)} />)}\n </span>\n );\n case 'orbit':\n return (\n <>\n <span className=\"dishui-ai-loading__orbit\" />\n <span className=\"dishui-ai-loading__satellite\" />\n </>\n );\n case 'surfer':\n return (\n <span className=\"dishui-ai-loading__surfer\">\n {Array.from({ length: 5 }, (_, i) => <span key={i} className=\"dishui-ai-loading__bar\" style={index(i)} />)}\n </span>\n );\n default:\n return (\n <span className=\"dishui-ai-loading__grid\">\n {Array.from({ length: 16 }, (_, i) => {\n // Diagonal sweep: delay grows with row + column.\n const delay = Math.floor(i / 4) + (i % 4);\n return <span key={i} className=\"dishui-ai-loading__cell\" style={index(delay)} />;\n })}\n </span>\n );\n }\n};\n\n/**\n * Indeterminate agent progress: pixel-grid (or sibling) glyph, a short label\n * and the elapsed time. Announces as a polite status region.\n */\nexport default function LoadingState({\n label = 'Thinking',\n variant = 'grid',\n showElapsed = true,\n startedAt,\n elapsedMs,\n layout = 'inline',\n size = 'md',\n className,\n ...rest\n}: LoadingStateProps) {\n const [internalElapsed, setInternalElapsed] = useState(0);\n const controlled = elapsedMs !== undefined;\n\n useEffect(() => {\n if (controlled || !showElapsed) return;\n const start = startedAt ?? Date.now();\n const id = window.setInterval(() => setInternalElapsed(Date.now() - start), 100);\n return () => window.clearInterval(id);\n }, [controlled, showElapsed, startedAt]);\n\n const elapsed = controlled ? elapsedMs : internalElapsed;\n\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n {...rest}\n className={cn(\n 'dishui-ai-loading',\n `dishui-ai-loading--${variant}`,\n size === 'sm' && 'dishui-ai-loading--sm',\n layout === 'block' && 'dishui-ai-loading--block',\n className,\n )}\n >\n <span className=\"dishui-ai-loading__glyph\" aria-hidden=\"true\">\n <Glyph variant={variant} />\n </span>\n <span className=\"dishui-ai-loading__label\">{label}</span>\n {showElapsed && <span className=\"dishui-ai-loading__elapsed\">{formatElapsed(elapsed)}</span>}\n </div>\n );\n}\n"],"mappings":";;;;;;AAuBA,IAAM,KAAS,OAAe,EAAE,OAAO,EAAE,IAEnC,KAAqD,EAAE,iBAAc;CACzE,QAAQ,GAAR;EACE,KAAK,SACH,OACE,kBAAC,QAAD;GAAM,WAAU;GACb,UAAA,MAAM,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,MAAM,kBAAC,QAAD;IAAc,WAAU;IAA0B,OAAO,EAAM,CAAC;GAAI,GAAzD,CAAyD,CAAC;EACtG,CAAA;EAEV,KAAK,QACH,OACE,kBAAC,QAAD;GAAM,WAAU;GACb,UAAA,MAAM,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,MAAM,kBAAC,QAAD;IAAc,WAAU;IAAyB,OAAO,EAAM,CAAC;GAAI,GAAxD,CAAwD,CAAC;EACrG,CAAA;EAEV,KAAK,SACH,OACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,QAAD,EAAM,WAAU,2BAA4B,CAAA,GAC5C,kBAAC,QAAD,EAAM,WAAU,+BAAgC,CAAA,CAChD,EAAA,CAAA;EAEN,KAAK,UACH,OACE,kBAAC,QAAD;GAAM,WAAU;GACb,UAAA,MAAM,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,MAAM,kBAAC,QAAD;IAAc,WAAU;IAAyB,OAAO,EAAM,CAAC;GAAI,GAAxD,CAAwD,CAAC;EACrG,CAAA;EAEV,SACE,OACE,kBAAC,QAAD;GAAM,WAAU;GACb,UAAA,MAAM,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,MAAM;IAEpC,IAAM,IAAQ,KAAK,MAAM,IAAI,CAAC,IAAK,IAAI;IACvC,OAAO,kBAAC,QAAD;KAAc,WAAU;KAA0B,OAAO,EAAM,CAAK;IAAI,GAA7D,CAA6D;GACjF,CAAC;EACG,CAAA;CAEZ;AACF;AAMA,SAAwB,EAAa,EACnC,WAAQ,YACR,aAAU,QACV,iBAAc,IACd,cACA,cACA,YAAS,UACT,UAAO,MACP,cACA,GAAG,KACiB;CACpB,IAAM,CAAC,GAAiB,KAAsB,EAAS,CAAC,GAClD,IAAa,MAAc,KAAA;CAEjC,QAAgB;EACd,IAAI,KAAc,CAAC,GAAa;EAChC,IAAM,IAAQ,KAAa,KAAK,IAAI,GAC9B,IAAK,OAAO,kBAAkB,EAAmB,KAAK,IAAI,IAAI,CAAK,GAAG,GAAG;EAC/E,aAAa,OAAO,cAAc,CAAE;CACtC,GAAG;EAAC;EAAY;EAAa;CAAS,CAAC;CAEvC,IAAM,IAAU,IAAa,IAAY;CAEzC,OACE,kBAAC,OAAD;EACE,MAAK;EACL,aAAU;EACV,GAAI;EACJ,WAAW,EACT,qBACA,sBAAsB,KACtB,MAAS,QAAQ,yBACjB,MAAW,WAAW,4BACtB,CACF;EAVF,UAAA;GAYE,kBAAC,QAAD;IAAM,WAAU;IAA2B,eAAY;IACrD,UAAA,kBAAC,GAAD,EAAgB,WAAU,CAAA;GACtB,CAAA;GACN,kBAAC,QAAD;IAAM,WAAU;IAA4B,UAAA;GAAY,CAAA;GACvD,KAAe,kBAAC,QAAD;IAAM,WAAU;IAA8B,UAAA,EAAc,CAAO;GAAQ,CAAA;EACxF;;AAET"}
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ export type PromptAttachment = {
3
+ id: string;
4
+ name: string;
5
+ meta?: string;
6
+ };
7
+ export type PromptBarProps = Omit<React.FormHTMLAttributes<HTMLFormElement>, 'onSubmit' | 'onChange'> & {
8
+ value?: string;
9
+ defaultValue?: string;
10
+ onChange?: (value: string) => void;
11
+ onSubmit?: (value: string) => void;
12
+ placeholder?: string;
13
+ label?: string;
14
+ busy?: boolean;
15
+ disabled?: boolean;
16
+ maxLength?: number;
17
+ attachments?: PromptAttachment[];
18
+ onRemoveAttachment?: (attachment: PromptAttachment) => void;
19
+ /** Controls rendered at the left side of the bottom toolbar. */
20
+ leading?: React.ReactNode;
21
+ /** Controls rendered before the character count and send button. */
22
+ actions?: React.ReactNode;
23
+ submitLabel?: string;
24
+ };
25
+ /** Composer assembled from DishUI Textarea and Button primitives. */
26
+ export default function PromptBar({ value, defaultValue, onChange, onSubmit, placeholder, label, busy, disabled, maxLength, attachments, onRemoveAttachment, leading, actions, submitLabel, className, ...rest }: PromptBarProps): React.JSX.Element;
@@ -0,0 +1,117 @@
1
+ import { cn as e } from "../../../utils/cn.js";
2
+ import t from "../../Button/index.js";
3
+ import n from "../../Textarea/index.js";
4
+ /* empty css */
5
+ import { useId as r, useRef as i, useState as a } from "react";
6
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
7
+ //#region src/components/ai/PromptBar/index.tsx
8
+ var c = [], l = ({ busy: e }) => e ? /* @__PURE__ */ o("span", {
9
+ className: "dishui-ai-prompt-bar__busy",
10
+ "aria-hidden": "true",
11
+ children: "•••"
12
+ }) : /* @__PURE__ */ s("svg", {
13
+ "aria-hidden": "true",
14
+ width: "16",
15
+ height: "16",
16
+ viewBox: "0 0 24 24",
17
+ fill: "none",
18
+ stroke: "currentColor",
19
+ strokeWidth: "2",
20
+ strokeLinecap: "round",
21
+ strokeLinejoin: "round",
22
+ children: [/* @__PURE__ */ o("path", { d: "m5 12 7-7 7 7" }), /* @__PURE__ */ o("path", { d: "M12 19V5" })]
23
+ });
24
+ function u({ value: u, defaultValue: d = "", onChange: f, onSubmit: p, placeholder: m = "Ask the agent…", label: h = "Prompt", busy: g = !1, disabled: _ = !1, maxLength: v, attachments: y = c, onRemoveAttachment: b, leading: x, actions: S, submitLabel: C = "Send", className: w, ...T }) {
25
+ let E = r(), D = i(null), [O, k] = a(d), A = u ?? O, j = (e) => {
26
+ u === void 0 && k(e), f?.(e);
27
+ let t = D.current;
28
+ t && (t.style.height = "auto", t.style.height = `${Math.min(t.scrollHeight, 160)}px`);
29
+ }, M = () => {
30
+ let e = A.trim();
31
+ e && !g && !_ && p?.(e);
32
+ };
33
+ return /* @__PURE__ */ s("form", {
34
+ ...T,
35
+ className: e("dishui-ai-prompt-bar", w),
36
+ onSubmit: (e) => {
37
+ e.preventDefault(), M();
38
+ },
39
+ "aria-busy": g || void 0,
40
+ children: [y.length > 0 && /* @__PURE__ */ o("ul", {
41
+ className: "dishui-ai-prompt-bar__attachments",
42
+ "aria-label": "Attachments",
43
+ children: y.map((e) => /* @__PURE__ */ s("li", { children: [
44
+ /* @__PURE__ */ o("span", {
45
+ title: e.name,
46
+ children: e.name
47
+ }),
48
+ e.meta && /* @__PURE__ */ o("small", { children: e.meta }),
49
+ b && /* @__PURE__ */ o(t, {
50
+ type: "button",
51
+ variant: "ghost",
52
+ size: "xs",
53
+ square: !0,
54
+ "aria-label": `Remove ${e.name}`,
55
+ disabled: _ || g,
56
+ onClick: () => b(e),
57
+ children: "×"
58
+ })
59
+ ] }, e.id))
60
+ }), /* @__PURE__ */ s("div", {
61
+ className: "dishui-ai-prompt-bar__main",
62
+ children: [
63
+ x && /* @__PURE__ */ o("div", {
64
+ className: "dishui-ai-prompt-bar__leading",
65
+ children: x
66
+ }),
67
+ /* @__PURE__ */ o("div", {
68
+ className: "dishui-ai-prompt-bar__editor",
69
+ children: /* @__PURE__ */ o(n, {
70
+ ref: D,
71
+ id: E,
72
+ "aria-label": h,
73
+ rows: 1,
74
+ value: A,
75
+ maxLength: v,
76
+ disabled: _,
77
+ placeholder: m,
78
+ wrapperClassName: "dishui-ai-prompt-bar__textarea-wrap",
79
+ className: "dishui-ai-prompt-bar__textarea",
80
+ onChange: (e) => j(e.target.value),
81
+ onKeyDown: (e) => {
82
+ e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing && (e.preventDefault(), M());
83
+ }
84
+ })
85
+ }),
86
+ /* @__PURE__ */ s("div", {
87
+ className: "dishui-ai-prompt-bar__actions",
88
+ children: [
89
+ S,
90
+ v !== void 0 && /* @__PURE__ */ s("span", {
91
+ className: "dishui-ai-prompt-bar__count",
92
+ children: [
93
+ A.length,
94
+ "/",
95
+ v
96
+ ]
97
+ }),
98
+ /* @__PURE__ */ o(t, {
99
+ type: "submit",
100
+ variant: "primary",
101
+ size: "sm",
102
+ square: !0,
103
+ className: "dishui-ai-prompt-bar__submit",
104
+ disabled: _ || g || !A.trim(),
105
+ "aria-label": C,
106
+ children: /* @__PURE__ */ o(l, { busy: g })
107
+ })
108
+ ]
109
+ })
110
+ ]
111
+ })]
112
+ });
113
+ }
114
+ //#endregion
115
+ export { u as default };
116
+
117
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/PromptBar/index.tsx"],"sourcesContent":["import React, { useId, useRef, useState } from 'react';\nimport Button from '../../Button';\nimport Textarea from '../../Textarea';\nimport { cn } from '../../../utils/cn';\nimport './PromptBar.css';\n\nconst EMPTY_ATTACHMENTS: PromptAttachment[] = [];\n\nexport type PromptAttachment = { id: string; name: string; meta?: string };\nexport type PromptBarProps = Omit<React.FormHTMLAttributes<HTMLFormElement>, 'onSubmit' | 'onChange'> & {\n value?: string;\n defaultValue?: string;\n onChange?: (value: string) => void;\n onSubmit?: (value: string) => void;\n placeholder?: string;\n label?: string;\n busy?: boolean;\n disabled?: boolean;\n maxLength?: number;\n attachments?: PromptAttachment[];\n onRemoveAttachment?: (attachment: PromptAttachment) => void;\n /** Controls rendered at the left side of the bottom toolbar. */\n leading?: React.ReactNode;\n /** Controls rendered before the character count and send button. */\n actions?: React.ReactNode;\n submitLabel?: string;\n};\n\nconst SendIcon = ({ busy }: { busy: boolean }) => busy ? (\n <span className=\"dishui-ai-prompt-bar__busy\" aria-hidden=\"true\">•••</span>\n) : (\n <svg aria-hidden=\"true\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m5 12 7-7 7 7\" /><path d=\"M12 19V5\" />\n </svg>\n);\n\n/** Composer assembled from DishUI Textarea and Button primitives. */\nexport default function PromptBar({\n value,\n defaultValue = '',\n onChange,\n onSubmit,\n placeholder = 'Ask the agent…',\n label = 'Prompt',\n busy = false,\n disabled = false,\n maxLength,\n attachments = EMPTY_ATTACHMENTS,\n onRemoveAttachment,\n leading,\n actions,\n submitLabel = 'Send',\n className,\n ...rest\n}: PromptBarProps) {\n const id = useId();\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const [internal, setInternal] = useState(defaultValue);\n const text = value ?? internal;\n\n const update = (next: string) => {\n if (value === undefined) setInternal(next);\n onChange?.(next);\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.style.height = 'auto';\n textarea.style.height = `${Math.min(textarea.scrollHeight, 160)}px`;\n }\n };\n const submit = () => {\n const next = text.trim();\n if (next && !busy && !disabled) onSubmit?.(next);\n };\n\n return (\n <form {...rest} className={cn('dishui-ai-prompt-bar', className)} onSubmit={event => { event.preventDefault(); submit(); }} aria-busy={busy || undefined}>\n {attachments.length > 0 && (\n <ul className=\"dishui-ai-prompt-bar__attachments\" aria-label=\"Attachments\">\n {attachments.map(file => (\n <li key={file.id}>\n <span title={file.name}>{file.name}</span>\n {file.meta && <small>{file.meta}</small>}\n {onRemoveAttachment && (\n <Button type=\"button\" variant=\"ghost\" size=\"xs\" square aria-label={`Remove ${file.name}`} disabled={disabled || busy} onClick={() => onRemoveAttachment(file)}>×</Button>\n )}\n </li>\n ))}\n </ul>\n )}\n <div className=\"dishui-ai-prompt-bar__main\">\n {leading && <div className=\"dishui-ai-prompt-bar__leading\">{leading}</div>}\n <div className=\"dishui-ai-prompt-bar__editor\">\n <Textarea\n ref={textareaRef}\n id={id}\n aria-label={label}\n rows={1}\n value={text}\n maxLength={maxLength}\n disabled={disabled}\n placeholder={placeholder}\n wrapperClassName=\"dishui-ai-prompt-bar__textarea-wrap\"\n className=\"dishui-ai-prompt-bar__textarea\"\n onChange={event => update(event.target.value)}\n onKeyDown={event => {\n if (event.key === 'Enter' && !event.shiftKey && !event.nativeEvent.isComposing) {\n event.preventDefault();\n submit();\n }\n }}\n />\n </div>\n <div className=\"dishui-ai-prompt-bar__actions\">\n {actions}\n {maxLength !== undefined && <span className=\"dishui-ai-prompt-bar__count\">{text.length}/{maxLength}</span>}\n <Button\n type=\"submit\"\n variant=\"primary\"\n size=\"sm\"\n square\n className=\"dishui-ai-prompt-bar__submit\"\n disabled={disabled || busy || !text.trim()}\n aria-label={submitLabel}\n >\n <SendIcon busy={busy} />\n </Button>\n </div>\n </div>\n </form>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import React from 'react';
2
+ export type ConfidenceLevel = 'high' | 'medium' | 'low';
3
+ export type Recommendation = {
4
+ title: React.ReactNode;
5
+ detail?: React.ReactNode;
6
+ /** 0–1. */
7
+ confidence: number;
8
+ };
9
+ export type RecommendationAlternative = {
10
+ id: string;
11
+ title: React.ReactNode;
12
+ /** Short judgement shown on the right, e.g. `Needs review`, `No signal`. */
13
+ verdict?: React.ReactNode;
14
+ /** 0–1; when present a small meter is shown next to the verdict. */
15
+ confidence?: number;
16
+ };
17
+ export type RecommendationCardLabels = {
18
+ accept?: string;
19
+ alternatives?: string;
20
+ otherOptions?: string;
21
+ };
22
+ export type RecommendationCardProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {
23
+ /** The agent's question, e.g. `Want me to place this restock order?` */
24
+ question: React.ReactNode;
25
+ recommendation: Recommendation;
26
+ alternatives?: RecommendationAlternative[];
27
+ /** Map a 0–1 confidence to its label. */
28
+ confidenceLabel?: (value: number) => string;
29
+ onAccept?: () => void;
30
+ /** When omitted, the button toggles the built-in alternatives list. */
31
+ onAlternatives?: () => void;
32
+ onSelectAlternative?: (alternative: RecommendationAlternative) => void;
33
+ labels?: RecommendationCardLabels;
34
+ /** Accept is in flight: both buttons disabled, Accept marked `aria-busy`. */
35
+ busy?: boolean;
36
+ disabled?: boolean;
37
+ };
38
+ export declare function confidenceLevel(value: number): ConfidenceLevel;
39
+ /**
40
+ * An agent suggestion: the question it is answering, the recommended
41
+ * action with a segmented confidence meter, optional alternatives and a
42
+ * secondary/primary action pair.
43
+ */
44
+ export default function RecommendationCard({ question, recommendation, alternatives, confidenceLabel, onAccept, onAlternatives, onSelectAlternative, labels, busy, disabled, className, ...rest }: RecommendationCardProps): React.JSX.Element;
@@ -0,0 +1,142 @@
1
+ import { cn as e } from "../../../utils/cn.js";
2
+ import t from "../../Button/index.js";
3
+ import { clamp as n } from "../shared.js";
4
+ /* empty css */
5
+ import { useId as r, useState as i } from "react";
6
+ import { Fragment as a, jsx as o, jsxs as s } from "react/jsx-runtime";
7
+ //#region src/components/ai/RecommendationCard/index.tsx
8
+ var c = {
9
+ accept: "Accept",
10
+ alternatives: "Alternatives",
11
+ otherOptions: "Other options"
12
+ }, l = 5;
13
+ function u(e) {
14
+ return e >= .75 ? "high" : e >= .45 ? "medium" : "low";
15
+ }
16
+ var d = (e) => {
17
+ switch (u(e)) {
18
+ case "high": return "High confidence";
19
+ case "medium": return "Medium confidence";
20
+ default: return "Low confidence";
21
+ }
22
+ }, f = ({ value: t, label: r, compact: i }) => {
23
+ let a = n(Number.isFinite(t) ? t : 0, 0, 1), c = a === 0 ? 0 : Math.max(1, Math.round(a * l)), d = u(a);
24
+ return /* @__PURE__ */ s("div", {
25
+ className: e("dishui-ai-recommendation-card__meter", `dishui-ai-recommendation-card__meter--${d}`, i && "dishui-ai-recommendation-card__meter--compact"),
26
+ role: "meter",
27
+ "aria-valuemin": 0,
28
+ "aria-valuemax": 1,
29
+ "aria-valuenow": a,
30
+ "aria-valuetext": r,
31
+ "aria-label": "Confidence",
32
+ children: [/* @__PURE__ */ o("span", {
33
+ className: "dishui-ai-recommendation-card__segments",
34
+ "aria-hidden": "true",
35
+ children: Array.from({ length: l }, (t, n) => /* @__PURE__ */ o("span", { className: e("dishui-ai-recommendation-card__segment", n < c && "dishui-ai-recommendation-card__segment--on") }, n))
36
+ }), !i && /* @__PURE__ */ o("span", {
37
+ className: "dishui-ai-recommendation-card__meter-label",
38
+ children: r
39
+ })]
40
+ });
41
+ };
42
+ function p({ question: n, recommendation: l, alternatives: u, confidenceLabel: p = d, onAccept: m, onAlternatives: h, onSelectAlternative: g, labels: _, busy: v = !1, disabled: y = !1, className: b, ...x }) {
43
+ let S = r(), C = {
44
+ ...c,
45
+ ..._
46
+ }, [w, T] = i(!1), E = !!u?.length, D = `${S}-alternatives`, O = v || y, k = () => {
47
+ h ? h() : T((e) => !e);
48
+ };
49
+ return /* @__PURE__ */ s("div", {
50
+ ...x,
51
+ className: e("dishui-ai-recommendation-card", b),
52
+ children: [
53
+ /* @__PURE__ */ o("div", {
54
+ className: "dishui-ai-recommendation-card__question",
55
+ children: n
56
+ }),
57
+ /* @__PURE__ */ s("div", {
58
+ className: "dishui-ai-recommendation-card__body",
59
+ children: [
60
+ /* @__PURE__ */ o("div", {
61
+ className: "dishui-ai-recommendation-card__title",
62
+ children: l.title
63
+ }),
64
+ l.detail !== void 0 && /* @__PURE__ */ o("div", {
65
+ className: "dishui-ai-recommendation-card__detail",
66
+ children: l.detail
67
+ }),
68
+ /* @__PURE__ */ o(f, {
69
+ value: l.confidence,
70
+ label: p(l.confidence)
71
+ })
72
+ ]
73
+ }),
74
+ E && /* @__PURE__ */ s("div", {
75
+ id: D,
76
+ className: "dishui-ai-recommendation-card__alternatives",
77
+ hidden: !w,
78
+ children: [/* @__PURE__ */ o("div", {
79
+ className: "dishui-ai-recommendation-card__alternatives-title",
80
+ children: C.otherOptions
81
+ }), /* @__PURE__ */ o("ul", {
82
+ className: "dishui-ai-recommendation-card__list",
83
+ children: u.map((e) => {
84
+ let t = /* @__PURE__ */ s(a, { children: [
85
+ /* @__PURE__ */ o("span", {
86
+ className: "dishui-ai-recommendation-card__alt-title",
87
+ children: e.title
88
+ }),
89
+ e.confidence !== void 0 && /* @__PURE__ */ o(f, {
90
+ value: e.confidence,
91
+ label: p(e.confidence),
92
+ compact: !0
93
+ }),
94
+ e.verdict !== void 0 && /* @__PURE__ */ o("span", {
95
+ className: "dishui-ai-recommendation-card__verdict",
96
+ children: e.verdict
97
+ })
98
+ ] });
99
+ return /* @__PURE__ */ o("li", {
100
+ className: "dishui-ai-recommendation-card__alt",
101
+ children: g ? /* @__PURE__ */ o("button", {
102
+ type: "button",
103
+ className: "dishui-ai-recommendation-card__alt-button",
104
+ disabled: O,
105
+ onClick: () => g(e),
106
+ children: t
107
+ }) : /* @__PURE__ */ o("div", {
108
+ className: "dishui-ai-recommendation-card__alt-button dishui-ai-recommendation-card__alt-button--static",
109
+ children: t
110
+ })
111
+ }, e.id);
112
+ })
113
+ })]
114
+ }),
115
+ (m || h || E) && /* @__PURE__ */ s("div", {
116
+ className: "dishui-ai-recommendation-card__actions",
117
+ children: [(h || E) && /* @__PURE__ */ o(t, {
118
+ type: "button",
119
+ variant: "secondary",
120
+ size: "sm",
121
+ disabled: O,
122
+ "aria-expanded": h ? void 0 : w,
123
+ "aria-controls": h || !E ? void 0 : D,
124
+ onClick: k,
125
+ children: C.alternatives
126
+ }), m && /* @__PURE__ */ o(t, {
127
+ type: "button",
128
+ variant: "primary",
129
+ size: "sm",
130
+ disabled: O,
131
+ "aria-busy": v || void 0,
132
+ onClick: m,
133
+ children: C.accept
134
+ })]
135
+ })
136
+ ]
137
+ });
138
+ }
139
+ //#endregion
140
+ export { u as confidenceLevel, p as default };
141
+
142
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/RecommendationCard/index.tsx"],"sourcesContent":["import React, { useId, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport Button from '../../Button';\nimport { clamp } from '../shared';\nimport './RecommendationCard.css';\n\nexport type ConfidenceLevel = 'high' | 'medium' | 'low';\n\nexport type Recommendation = {\n title: React.ReactNode;\n detail?: React.ReactNode;\n /** 0–1. */\n confidence: number;\n};\n\nexport type RecommendationAlternative = {\n id: string;\n title: React.ReactNode;\n /** Short judgement shown on the right, e.g. `Needs review`, `No signal`. */\n verdict?: React.ReactNode;\n /** 0–1; when present a small meter is shown next to the verdict. */\n confidence?: number;\n};\n\nexport type RecommendationCardLabels = {\n accept?: string;\n alternatives?: string;\n otherOptions?: string;\n};\n\nexport type RecommendationCardProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {\n /** The agent's question, e.g. `Want me to place this restock order?` */\n question: React.ReactNode;\n recommendation: Recommendation;\n alternatives?: RecommendationAlternative[];\n /** Map a 0–1 confidence to its label. */\n confidenceLabel?: (value: number) => string;\n onAccept?: () => void;\n /** When omitted, the button toggles the built-in alternatives list. */\n onAlternatives?: () => void;\n onSelectAlternative?: (alternative: RecommendationAlternative) => void;\n labels?: RecommendationCardLabels;\n /** Accept is in flight: both buttons disabled, Accept marked `aria-busy`. */\n busy?: boolean;\n disabled?: boolean;\n};\n\nconst DEFAULT_LABELS: Required<RecommendationCardLabels> = {\n accept: 'Accept',\n alternatives: 'Alternatives',\n otherOptions: 'Other options',\n};\n\nconst SEGMENTS = 5;\n\nexport function confidenceLevel(value: number): ConfidenceLevel {\n if (value >= 0.75) return 'high';\n if (value >= 0.45) return 'medium';\n return 'low';\n}\n\nconst defaultConfidenceLabel = (value: number) => {\n switch (confidenceLevel(value)) {\n case 'high': return 'High confidence';\n case 'medium': return 'Medium confidence';\n default: return 'Low confidence';\n }\n};\n\nconst ConfidenceMeter: React.FC<{ value: number; label: string; compact?: boolean }> = ({ value, label, compact }) => {\n const v = clamp(Number.isFinite(value) ? value : 0, 0, 1);\n const filled = v === 0 ? 0 : Math.max(1, Math.round(v * SEGMENTS));\n const level = confidenceLevel(v);\n return (\n <div\n className={cn('dishui-ai-recommendation-card__meter', `dishui-ai-recommendation-card__meter--${level}`, compact && 'dishui-ai-recommendation-card__meter--compact')}\n role=\"meter\"\n aria-valuemin={0}\n aria-valuemax={1}\n aria-valuenow={v}\n aria-valuetext={label}\n aria-label=\"Confidence\"\n >\n <span className=\"dishui-ai-recommendation-card__segments\" aria-hidden=\"true\">\n {Array.from({ length: SEGMENTS }, (_, i) => (\n <span key={i} className={cn('dishui-ai-recommendation-card__segment', i < filled && 'dishui-ai-recommendation-card__segment--on')} />\n ))}\n </span>\n {!compact && <span className=\"dishui-ai-recommendation-card__meter-label\">{label}</span>}\n </div>\n );\n};\n\n/**\n * An agent suggestion: the question it is answering, the recommended\n * action with a segmented confidence meter, optional alternatives and a\n * secondary/primary action pair.\n */\nexport default function RecommendationCard({\n question,\n recommendation,\n alternatives,\n confidenceLabel = defaultConfidenceLabel,\n onAccept,\n onAlternatives,\n onSelectAlternative,\n labels,\n busy = false,\n disabled = false,\n className,\n ...rest\n}: RecommendationCardProps) {\n const baseId = useId();\n const text = { ...DEFAULT_LABELS, ...labels };\n const [showAlternatives, setShowAlternatives] = useState(false);\n const hasAlternatives = !!alternatives?.length;\n const listId = `${baseId}-alternatives`;\n const inert = busy || disabled;\n\n const handleAlternatives = () => {\n if (onAlternatives) onAlternatives();\n else setShowAlternatives(v => !v);\n };\n\n return (\n <div {...rest} className={cn('dishui-ai-recommendation-card', className)}>\n <div className=\"dishui-ai-recommendation-card__question\">{question}</div>\n\n <div className=\"dishui-ai-recommendation-card__body\">\n <div className=\"dishui-ai-recommendation-card__title\">{recommendation.title}</div>\n {recommendation.detail !== undefined && (\n <div className=\"dishui-ai-recommendation-card__detail\">{recommendation.detail}</div>\n )}\n <ConfidenceMeter value={recommendation.confidence} label={confidenceLabel(recommendation.confidence)} />\n </div>\n\n {hasAlternatives && (\n <div\n id={listId}\n className=\"dishui-ai-recommendation-card__alternatives\"\n hidden={!showAlternatives}\n >\n <div className=\"dishui-ai-recommendation-card__alternatives-title\">{text.otherOptions}</div>\n <ul className=\"dishui-ai-recommendation-card__list\">\n {alternatives!.map(alt => {\n const inner = (\n <>\n <span className=\"dishui-ai-recommendation-card__alt-title\">{alt.title}</span>\n {alt.confidence !== undefined && (\n <ConfidenceMeter value={alt.confidence} label={confidenceLabel(alt.confidence)} compact />\n )}\n {alt.verdict !== undefined && <span className=\"dishui-ai-recommendation-card__verdict\">{alt.verdict}</span>}\n </>\n );\n return (\n <li key={alt.id} className=\"dishui-ai-recommendation-card__alt\">\n {onSelectAlternative ? (\n <button\n type=\"button\"\n className=\"dishui-ai-recommendation-card__alt-button\"\n disabled={inert}\n onClick={() => onSelectAlternative(alt)}\n >\n {inner}\n </button>\n ) : (\n <div className=\"dishui-ai-recommendation-card__alt-button dishui-ai-recommendation-card__alt-button--static\">{inner}</div>\n )}\n </li>\n );\n })}\n </ul>\n </div>\n )}\n\n {(onAccept || onAlternatives || hasAlternatives) && (\n <div className=\"dishui-ai-recommendation-card__actions\">\n {(onAlternatives || hasAlternatives) && (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n disabled={inert}\n aria-expanded={onAlternatives ? undefined : showAlternatives}\n aria-controls={onAlternatives || !hasAlternatives ? undefined : listId}\n onClick={handleAlternatives}\n >\n {text.alternatives}\n </Button>\n )}\n {onAccept && (\n <Button type=\"button\" variant=\"primary\" size=\"sm\" disabled={inert} aria-busy={busy || undefined} onClick={onAccept}>\n {text.accept}\n </Button>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;AA+CA,IAAM,IAAqD;CACzD,QAAQ;CACR,cAAc;CACd,cAAc;AAChB,GAEM,IAAW;AAEjB,SAAgB,EAAgB,GAAgC;CAG9D,OAFI,KAAS,MAAa,SACtB,KAAS,MAAa,WACnB;AACT;AAEA,IAAM,KAA0B,MAAkB;CAChD,QAAQ,EAAgB,CAAK,GAA7B;EACE,KAAK,QAAQ,OAAO;EACpB,KAAK,UAAU,OAAO;EACtB,SAAS,OAAO;CAClB;AACF,GAEM,KAAkF,EAAE,UAAO,UAAO,iBAAc;CACpH,IAAM,IAAI,EAAM,OAAO,SAAS,CAAK,IAAI,IAAQ,GAAG,GAAG,CAAC,GAClD,IAAS,MAAM,IAAI,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,CAAQ,CAAC,GAC3D,IAAQ,EAAgB,CAAC;CAC/B,OACE,kBAAC,OAAD;EACE,WAAW,EAAG,wCAAwC,yCAAyC,KAAS,KAAW,+CAA+C;EAClK,MAAK;EACL,iBAAe;EACf,iBAAe;EACf,iBAAe;EACf,kBAAgB;EAChB,cAAW;EAPb,UAAA,CASE,kBAAC,QAAD;GAAM,WAAU;GAA0C,eAAY;GACnE,UAAA,MAAM,KAAK,EAAE,QAAQ,EAAS,IAAI,GAAG,MACpC,kBAAC,QAAD,EAAc,WAAW,EAAG,0CAA0C,IAAI,KAAU,4CAA4C,EAAI,GAAzH,CAAyH,CACrI;EACG,CAAA,GACL,CAAC,KAAW,kBAAC,QAAD;GAAM,WAAU;GAA8C,UAAA;EAAY,CAAA,CACpF;;AAET;AAOA,SAAwB,EAAmB,EACzC,aACA,mBACA,iBACA,qBAAkB,GAClB,aACA,mBACA,wBACA,WACA,UAAO,IACP,cAAW,IACX,cACA,GAAG,KACuB;CAC1B,IAAM,IAAS,EAAM,GACf,IAAO;EAAE,GAAG;EAAgB,GAAG;CAAO,GACtC,CAAC,GAAkB,KAAuB,EAAS,EAAK,GACxD,IAAkB,CAAC,CAAC,GAAc,QAClC,IAAS,GAAG,EAAO,gBACnB,IAAQ,KAAQ,GAEhB,UAA2B;EAC/B,AAAI,IAAgB,EAAe,IAC9B,GAAoB,MAAK,CAAC,CAAC;CAClC;CAEA,OACE,kBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,EAAG,iCAAiC,CAAS;EAAvE,UAAA;GACE,kBAAC,OAAD;IAAK,WAAU;IAA2C,UAAA;GAAc,CAAA;GAExE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,OAAD;MAAK,WAAU;MAAwC,UAAA,EAAe;KAAW,CAAA;KAChF,EAAe,WAAW,KAAA,KACzB,kBAAC,OAAD;MAAK,WAAU;MAAyC,UAAA,EAAe;KAAY,CAAA;KAErF,kBAAC,GAAD;MAAiB,OAAO,EAAe;MAAY,OAAO,EAAgB,EAAe,UAAU;KAAI,CAAA;IACpG;;GAEJ,KACC,kBAAC,OAAD;IACE,IAAI;IACJ,WAAU;IACV,QAAQ,CAAC;IAHX,UAAA,CAKE,kBAAC,OAAD;KAAK,WAAU;KAAqD,UAAA,EAAK;IAAkB,CAAA,GAC3F,kBAAC,MAAD;KAAI,WAAU;KACX,UAAA,EAAc,KAAI,MAAO;MACxB,IAAM,IACJ,kBAAA,GAAA,EAAA,UAAA;OACE,kBAAC,QAAD;QAAM,WAAU;QAA4C,UAAA,EAAI;OAAY,CAAA;OAC3E,EAAI,eAAe,KAAA,KAClB,kBAAC,GAAD;QAAiB,OAAO,EAAI;QAAY,OAAO,EAAgB,EAAI,UAAU;QAAG,SAAA;OAAS,CAAA;OAE1F,EAAI,YAAY,KAAA,KAAa,kBAAC,QAAD;QAAM,WAAU;QAA0C,UAAA,EAAI;OAAc,CAAA;MAC1G,EAAA,CAAA;MAEJ,OACE,kBAAC,MAAD;OAAiB,WAAU;OACxB,UAAA,IACC,kBAAC,UAAD;QACE,MAAK;QACL,WAAU;QACV,UAAU;QACV,eAAe,EAAoB,CAAG;QAErC,UAAA;OACK,CAAA,IAER,kBAAC,OAAD;QAAK,WAAU;QAA+F,UAAA;OAAW,CAAA;MAEzH,GAbK,EAAI,EAaT;KAER,CAAC;IACC,CAAA,CACD;;IAGL,KAAY,KAAkB,MAC9B,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,EACI,KAAkB,MAClB,kBAAC,GAAD;KACE,MAAK;KACL,SAAQ;KACR,MAAK;KACL,UAAU;KACV,iBAAe,IAAiB,KAAA,IAAY;KAC5C,iBAAe,KAAkB,CAAC,IAAkB,KAAA,IAAY;KAChE,SAAS;KAER,UAAA,EAAK;IACA,CAAA,GAET,KACC,kBAAC,GAAD;KAAQ,MAAK;KAAS,SAAQ;KAAU,MAAK;KAAK,UAAU;KAAO,aAAW,KAAQ,KAAA;KAAW,SAAS;KACvG,UAAA,EAAK;IACA,CAAA,CAEP;;EAEJ;;AAET"}