@activecollab/components 2.0.363 → 2.0.364

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 (79) hide show
  1. package/dist/cjs/presentation/stackedCard/content/ImageCard.js +60 -0
  2. package/dist/cjs/presentation/stackedCard/content/ImageCard.js.map +1 -0
  3. package/dist/cjs/presentation/stackedCard/content/LinkCard.js +348 -0
  4. package/dist/cjs/presentation/stackedCard/content/LinkCard.js.map +1 -0
  5. package/dist/cjs/presentation/stackedCard/content/NoteCard.js +92 -0
  6. package/dist/cjs/presentation/stackedCard/content/NoteCard.js.map +1 -0
  7. package/dist/cjs/presentation/stackedCard/content/SwatchCard.js +74 -0
  8. package/dist/cjs/presentation/stackedCard/content/SwatchCard.js.map +1 -0
  9. package/dist/cjs/presentation/stackedCard/content/TaskCard.js +231 -0
  10. package/dist/cjs/presentation/stackedCard/content/TaskCard.js.map +1 -0
  11. package/dist/cjs/presentation/stackedCard/content/index.js +83 -0
  12. package/dist/cjs/presentation/stackedCard/content/index.js.map +1 -0
  13. package/dist/cjs/presentation/stackedCard/content/shared.js +144 -0
  14. package/dist/cjs/presentation/stackedCard/content/shared.js.map +1 -0
  15. package/dist/cjs/presentation/stackedCard/content/unfurl.js +172 -0
  16. package/dist/cjs/presentation/stackedCard/content/unfurl.js.map +1 -0
  17. package/dist/cjs/presentation/stackedCard/primitives.js +254 -0
  18. package/dist/cjs/presentation/stackedCard/primitives.js.map +1 -0
  19. package/dist/cjs/presentation/stackedCard/resizePolicy.js +183 -0
  20. package/dist/cjs/presentation/stackedCard/resizePolicy.js.map +1 -0
  21. package/dist/cjs/presentation/stackedCard/shell.js +165 -0
  22. package/dist/cjs/presentation/stackedCard/shell.js.map +1 -0
  23. package/dist/cjs/presentation/stackedCard/storyScaffold.js +72 -0
  24. package/dist/cjs/presentation/stackedCard/storyScaffold.js.map +1 -0
  25. package/dist/cjs/presentation/stackedCard/useInlineEdit.js +208 -0
  26. package/dist/cjs/presentation/stackedCard/useInlineEdit.js.map +1 -0
  27. package/dist/esm/presentation/stackedCard/content/ImageCard.d.ts +15 -0
  28. package/dist/esm/presentation/stackedCard/content/ImageCard.d.ts.map +1 -0
  29. package/dist/esm/presentation/stackedCard/content/ImageCard.js +50 -0
  30. package/dist/esm/presentation/stackedCard/content/ImageCard.js.map +1 -0
  31. package/dist/esm/presentation/stackedCard/content/LinkCard.d.ts +28 -0
  32. package/dist/esm/presentation/stackedCard/content/LinkCard.d.ts.map +1 -0
  33. package/dist/esm/presentation/stackedCard/content/LinkCard.js +336 -0
  34. package/dist/esm/presentation/stackedCard/content/LinkCard.js.map +1 -0
  35. package/dist/esm/presentation/stackedCard/content/NoteCard.d.ts +10 -0
  36. package/dist/esm/presentation/stackedCard/content/NoteCard.d.ts.map +1 -0
  37. package/dist/esm/presentation/stackedCard/content/NoteCard.js +82 -0
  38. package/dist/esm/presentation/stackedCard/content/NoteCard.js.map +1 -0
  39. package/dist/esm/presentation/stackedCard/content/SwatchCard.d.ts +14 -0
  40. package/dist/esm/presentation/stackedCard/content/SwatchCard.d.ts.map +1 -0
  41. package/dist/esm/presentation/stackedCard/content/SwatchCard.js +64 -0
  42. package/dist/esm/presentation/stackedCard/content/SwatchCard.js.map +1 -0
  43. package/dist/esm/presentation/stackedCard/content/TaskCard.d.ts +29 -0
  44. package/dist/esm/presentation/stackedCard/content/TaskCard.d.ts.map +1 -0
  45. package/dist/esm/presentation/stackedCard/content/TaskCard.js +218 -0
  46. package/dist/esm/presentation/stackedCard/content/TaskCard.js.map +1 -0
  47. package/dist/esm/presentation/stackedCard/content/index.d.ts +8 -0
  48. package/dist/esm/presentation/stackedCard/content/index.d.ts.map +1 -0
  49. package/dist/esm/presentation/stackedCard/content/index.js +8 -0
  50. package/dist/esm/presentation/stackedCard/content/index.js.map +1 -0
  51. package/dist/esm/presentation/stackedCard/content/shared.d.ts +46 -0
  52. package/dist/esm/presentation/stackedCard/content/shared.d.ts.map +1 -0
  53. package/dist/esm/presentation/stackedCard/content/shared.js +134 -0
  54. package/dist/esm/presentation/stackedCard/content/shared.js.map +1 -0
  55. package/dist/esm/presentation/stackedCard/content/unfurl.d.ts +89 -0
  56. package/dist/esm/presentation/stackedCard/content/unfurl.d.ts.map +1 -0
  57. package/dist/esm/presentation/stackedCard/content/unfurl.js +147 -0
  58. package/dist/esm/presentation/stackedCard/content/unfurl.js.map +1 -0
  59. package/dist/esm/presentation/stackedCard/primitives.d.ts +84 -0
  60. package/dist/esm/presentation/stackedCard/primitives.d.ts.map +1 -0
  61. package/dist/esm/presentation/stackedCard/primitives.js +241 -0
  62. package/dist/esm/presentation/stackedCard/primitives.js.map +1 -0
  63. package/dist/esm/presentation/stackedCard/resizePolicy.d.ts +97 -0
  64. package/dist/esm/presentation/stackedCard/resizePolicy.d.ts.map +1 -0
  65. package/dist/esm/presentation/stackedCard/resizePolicy.js +173 -0
  66. package/dist/esm/presentation/stackedCard/resizePolicy.js.map +1 -0
  67. package/dist/esm/presentation/stackedCard/shell.d.ts +46 -0
  68. package/dist/esm/presentation/stackedCard/shell.d.ts.map +1 -0
  69. package/dist/esm/presentation/stackedCard/shell.js +156 -0
  70. package/dist/esm/presentation/stackedCard/shell.js.map +1 -0
  71. package/dist/esm/presentation/stackedCard/storyScaffold.d.ts +28 -0
  72. package/dist/esm/presentation/stackedCard/storyScaffold.d.ts.map +1 -0
  73. package/dist/esm/presentation/stackedCard/storyScaffold.js +66 -0
  74. package/dist/esm/presentation/stackedCard/storyScaffold.js.map +1 -0
  75. package/dist/esm/presentation/stackedCard/useInlineEdit.d.ts +68 -0
  76. package/dist/esm/presentation/stackedCard/useInlineEdit.d.ts.map +1 -0
  77. package/dist/esm/presentation/stackedCard/useInlineEdit.js +192 -0
  78. package/dist/esm/presentation/stackedCard/useInlineEdit.js.map +1 -0
  79. package/package.json +1 -1
@@ -0,0 +1,218 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
2
+ import React from "react";
3
+ import styled, { css } from "styled-components";
4
+ import { EntityDots, StyledClamp, coverManagement, playControl, Placeholder } from "./shared";
5
+ import { ChecklistSmallIcon, EyeOffIcon, InsertLinkIcon, MessageSmallIcon, PersonPlusIcon } from "../../../components/Icons";
6
+ import { SkeletonLoader } from "../../../components/Loaders";
7
+ import { Caption1 } from "../../../components/Typography";
8
+ import { Typography } from "../../../components/Typography/Typography";
9
+ import { RoundAvatar, AVATAR_COLORS } from "../../shared";
10
+ import { Cover, StackRow } from "../primitives";
11
+ import { COVER_RATIO } from "../shell";
12
+
13
+ /**
14
+ * TaskCard — the baseline-preservation card.
15
+ *
16
+ * This is the replacement for today's column card, so it must reproduce every
17
+ * behavior that card has (note 52104 §B2) — none of them are optional, each is
18
+ * a silent-regression risk. Every one is a prop here so the story can toggle it:
19
+ *
20
+ * - task-number prefix in the title (config-gated, mirrors `show_task_id`)
21
+ * - overdue date colouring (red ONLY when overdue AND not completed)
22
+ * - dependency counter (behind a feature-flag prop)
23
+ * - hidden-from-clients signifier (shown only when it DIFFERS from the
24
+ * project default)
25
+ * - inline assignee affordance (avatar, or an add-assignee placeholder)
26
+ * - completed (teal tint, no "…" menu, no overdue colour)
27
+ *
28
+ * The pending/optimistic and priority states are SHELL states (dimmed +
29
+ * pointer-events off; red left bar), so the card is wrapped in a `<StackedCard
30
+ * pending>` / `<StackedCard priorityColor>` by the host — they are not the
31
+ * card's own concern and live on the shell, not here.
32
+ */
33
+
34
+ const LABEL_DOTS = ["#378ADD", "#D85A30", "#639922", "#EF9F27", "#7F77DD"];
35
+
36
+ /* The completed tint fills the card body; the shell keeps the priority bar and
37
+ selection ring on top of it. */
38
+ const StyledBody = styled.div.withConfig({
39
+ displayName: "TaskCard__StyledBody",
40
+ componentId: "sc-5iuhg8-0"
41
+ })(["display:flex;flex-direction:column;", ""], _ref => {
42
+ let $completed = _ref.$completed;
43
+ return $completed && css(["background:var(--sc-completed-tint,rgba(72,201,176,0.16));"]);
44
+ });
45
+ const StyledMetaCluster = styled.div.withConfig({
46
+ displayName: "TaskCard__StyledMetaCluster",
47
+ componentId: "sc-5iuhg8-1"
48
+ })(["display:flex;align-items:center;gap:6px;color:var(--color-theme-600);.sc-dots{display:flex;gap:4px;}.sc-sep{opacity:0.6;}.sc-count{display:inline-flex;align-items:center;gap:3px;}svg{width:14px;height:14px;}"]);
49
+ const StyledDot = styled.span.withConfig({
50
+ displayName: "TaskCard__StyledDot",
51
+ componentId: "sc-5iuhg8-2"
52
+ })(["width:11px;height:11px;border-radius:50%;background:", ";"], _ref2 => {
53
+ let $color = _ref2.$color;
54
+ return $color;
55
+ });
56
+
57
+ /* Hidden-from-clients signifier — an eye-off badge, shown only when the task's
58
+ visibility differs from the project default. */
59
+ const StyledHiddenBadge = styled.span.withConfig({
60
+ displayName: "TaskCard__StyledHiddenBadge",
61
+ componentId: "sc-5iuhg8-3"
62
+ })(["display:inline-flex;align-items:center;gap:3px;color:var(--color-theme-600);svg{width:14px;height:14px;}"]);
63
+
64
+ /* Date — bold; turns red only when overdue AND the task is not completed. */
65
+ const StyledDate = styled.span.withConfig({
66
+ displayName: "TaskCard__StyledDate",
67
+ componentId: "sc-5iuhg8-4"
68
+ })(["font-weight:bold;color:", ";"], _ref3 => {
69
+ let $overdue = _ref3.$overdue;
70
+ return $overdue ? "var(--red-alert)" : "var(--color-theme-900)";
71
+ });
72
+
73
+ /* Inline assignee affordance placeholder — a dashed add-assignee target that
74
+ stands in until the real picker is wired at integration. */
75
+ const StyledAddAssignee = styled.button.withConfig({
76
+ displayName: "TaskCard__StyledAddAssignee",
77
+ componentId: "sc-5iuhg8-5"
78
+ })(["display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:1.5px dashed var(--color-theme-400);border-radius:50%;background:transparent;color:var(--color-theme-600);cursor:pointer;svg{width:14px;height:14px;display:block;}&:hover{border-color:var(--sc-selection-ring);color:var(--color-theme-800);}"]);
79
+ export const TaskCard = _ref4 => {
80
+ let _ref4$title = _ref4.title,
81
+ title = _ref4$title === void 0 ? "Implement the design from the reference on this page" : _ref4$title,
82
+ _ref4$cover = _ref4.cover,
83
+ cover = _ref4$cover === void 0 ? false : _ref4$cover,
84
+ _ref4$playable = _ref4.playable,
85
+ playable = _ref4$playable === void 0 ? false : _ref4$playable,
86
+ _ref4$coverControls = _ref4.coverControls,
87
+ coverControls = _ref4$coverControls === void 0 ? false : _ref4$coverControls,
88
+ _ref4$showTaskId = _ref4.showTaskId,
89
+ showTaskId = _ref4$showTaskId === void 0 ? false : _ref4$showTaskId,
90
+ _ref4$taskId = _ref4.taskId,
91
+ taskId = _ref4$taskId === void 0 ? 4521 : _ref4$taskId,
92
+ _ref4$dateLabel = _ref4.dateLabel,
93
+ dateLabel = _ref4$dateLabel === void 0 ? "May 8 – Sep 10" : _ref4$dateLabel,
94
+ _ref4$overdue = _ref4.overdue,
95
+ overdue = _ref4$overdue === void 0 ? false : _ref4$overdue,
96
+ _ref4$showDependencie = _ref4.showDependencies,
97
+ showDependencies = _ref4$showDependencie === void 0 ? false : _ref4$showDependencie,
98
+ _ref4$dependencyCount = _ref4.dependencyCount,
99
+ dependencyCount = _ref4$dependencyCount === void 0 ? 2 : _ref4$dependencyCount,
100
+ _ref4$hiddenFromClien = _ref4.hiddenFromClients,
101
+ hiddenFromClients = _ref4$hiddenFromClien === void 0 ? false : _ref4$hiddenFromClien,
102
+ _ref4$projectDefaultH = _ref4.projectDefaultHidden,
103
+ projectDefaultHidden = _ref4$projectDefaultH === void 0 ? false : _ref4$projectDefaultH,
104
+ _ref4$assigned = _ref4.assigned,
105
+ assigned = _ref4$assigned === void 0 ? true : _ref4$assigned,
106
+ _ref4$completed = _ref4.completed,
107
+ completed = _ref4$completed === void 0 ? false : _ref4$completed;
108
+ // Signifier appears only when the task's visibility differs from the default.
109
+ const showHiddenSignifier = hiddenFromClients !== projectDefaultHidden;
110
+ // Overdue colour is suppressed on completed tasks.
111
+ const dateIsOverdue = overdue && !completed;
112
+ return /*#__PURE__*/React.createElement(StyledBody, {
113
+ $completed: completed
114
+ }, cover ? /*#__PURE__*/React.createElement(Cover, {
115
+ aspectRatio: COVER_RATIO,
116
+ centerSlot: playable ? playControl : undefined,
117
+ topRightSlot: coverControls ? coverManagement() : undefined
118
+ }, /*#__PURE__*/React.createElement("div", {
119
+ style: {
120
+ width: "100%",
121
+ height: "100%",
122
+ background: "var(--color-theme-300)"
123
+ }
124
+ })) : null, /*#__PURE__*/React.createElement(StackRow, {
125
+ role: "title"
126
+ }, /*#__PURE__*/React.createElement(StyledClamp, null, showTaskId ? /*#__PURE__*/React.createElement(Typography, {
127
+ as: "span",
128
+ variant: "Caption 1",
129
+ color: "tertiary"
130
+ }, "#" + taskId + " ") : null, title), completed ? null : /*#__PURE__*/React.createElement(EntityDots, {
131
+ "aria-label": "Task options"
132
+ })), /*#__PURE__*/React.createElement(StackRow, {
133
+ role: "meta"
134
+ }, /*#__PURE__*/React.createElement(StyledMetaCluster, null, /*#__PURE__*/React.createElement("span", {
135
+ className: "sc-dots"
136
+ }, LABEL_DOTS.map(color => /*#__PURE__*/React.createElement(StyledDot, {
137
+ key: color,
138
+ $color: color
139
+ }))), /*#__PURE__*/React.createElement(Caption1, {
140
+ color: "tertiary"
141
+ }, "+3"), /*#__PURE__*/React.createElement("span", {
142
+ className: "sc-sep"
143
+ }, "\xB7"), /*#__PURE__*/React.createElement("span", {
144
+ className: "sc-count"
145
+ }, /*#__PURE__*/React.createElement(MessageSmallIcon, null), /*#__PURE__*/React.createElement(Caption1, {
146
+ color: "tertiary"
147
+ }, "7")), /*#__PURE__*/React.createElement("span", {
148
+ className: "sc-sep"
149
+ }, "\xB7"), /*#__PURE__*/React.createElement("span", {
150
+ className: "sc-count"
151
+ }, /*#__PURE__*/React.createElement(ChecklistSmallIcon, null), /*#__PURE__*/React.createElement(Caption1, {
152
+ color: "tertiary"
153
+ }, "2")), showDependencies ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
154
+ className: "sc-sep"
155
+ }, "\xB7"), /*#__PURE__*/React.createElement("span", {
156
+ className: "sc-count",
157
+ title: "Dependencies"
158
+ }, /*#__PURE__*/React.createElement(InsertLinkIcon, null), /*#__PURE__*/React.createElement(Caption1, {
159
+ color: "tertiary"
160
+ }, dependencyCount))) : null, showHiddenSignifier ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
161
+ className: "sc-sep"
162
+ }, "\xB7"), /*#__PURE__*/React.createElement(StyledHiddenBadge, {
163
+ title: "Hidden from clients"
164
+ }, /*#__PURE__*/React.createElement(EyeOffIcon, null))) : null)), /*#__PURE__*/React.createElement(StackRow, {
165
+ role: "footer"
166
+ }, /*#__PURE__*/React.createElement(StyledDate, {
167
+ $overdue: dateIsOverdue
168
+ }, dateLabel), /*#__PURE__*/React.createElement("span", null), assigned ? /*#__PURE__*/React.createElement(RoundAvatar, {
169
+ $bg: AVATAR_COLORS.teal,
170
+ $size: 24,
171
+ $bordered: false,
172
+ "data-fixed": true
173
+ }, "MS") : /*#__PURE__*/React.createElement(StyledAddAssignee, {
174
+ type: "button",
175
+ "aria-label": "Assign task",
176
+ "data-fixed": true
177
+ }, /*#__PURE__*/React.createElement(PersonPlusIcon, null))));
178
+ };
179
+
180
+ /* ---- placeholder + skeleton ---- */
181
+
182
+ export const TaskPlaceholder = props => /*#__PURE__*/React.createElement(Placeholder, _extends({
183
+ icon: /*#__PURE__*/React.createElement(ChecklistSmallIcon, null),
184
+ label: "Name this task"
185
+ }, props));
186
+
187
+ /* Skeleton mirrors the task anatomy row for row: title, meta, footer. */
188
+ export const TaskSkeleton = () => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(StackRow, {
189
+ role: "title"
190
+ }, /*#__PURE__*/React.createElement(SkeletonLoader, {
191
+ style: {
192
+ height: 14,
193
+ width: "90%"
194
+ }
195
+ })), /*#__PURE__*/React.createElement(StackRow, {
196
+ role: "meta"
197
+ }, /*#__PURE__*/React.createElement(SkeletonLoader, {
198
+ style: {
199
+ height: 10,
200
+ width: "55%"
201
+ }
202
+ })), /*#__PURE__*/React.createElement(StackRow, {
203
+ role: "footer"
204
+ }, /*#__PURE__*/React.createElement(SkeletonLoader, {
205
+ style: {
206
+ height: 12,
207
+ width: 64
208
+ },
209
+ "data-fixed": true
210
+ }), /*#__PURE__*/React.createElement("span", null), /*#__PURE__*/React.createElement(SkeletonLoader, {
211
+ "data-fixed": true,
212
+ style: {
213
+ width: 24,
214
+ height: 24,
215
+ borderRadius: "50%"
216
+ }
217
+ })));
218
+ //# sourceMappingURL=TaskCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskCard.js","names":["React","styled","css","EntityDots","StyledClamp","coverManagement","playControl","Placeholder","ChecklistSmallIcon","EyeOffIcon","InsertLinkIcon","MessageSmallIcon","PersonPlusIcon","SkeletonLoader","Caption1","Typography","RoundAvatar","AVATAR_COLORS","Cover","StackRow","COVER_RATIO","LABEL_DOTS","StyledBody","div","withConfig","displayName","componentId","_ref","$completed","StyledMetaCluster","StyledDot","span","_ref2","$color","StyledHiddenBadge","StyledDate","_ref3","$overdue","StyledAddAssignee","button","TaskCard","_ref4","_ref4$title","title","_ref4$cover","cover","_ref4$playable","playable","_ref4$coverControls","coverControls","_ref4$showTaskId","showTaskId","_ref4$taskId","taskId","_ref4$dateLabel","dateLabel","_ref4$overdue","overdue","_ref4$showDependencie","showDependencies","_ref4$dependencyCount","dependencyCount","_ref4$hiddenFromClien","hiddenFromClients","_ref4$projectDefaultH","projectDefaultHidden","_ref4$assigned","assigned","_ref4$completed","completed","showHiddenSignifier","dateIsOverdue","createElement","aspectRatio","centerSlot","undefined","topRightSlot","style","width","height","background","role","as","variant","color","className","map","key","Fragment","$bg","teal","$size","$bordered","type","TaskPlaceholder","props","_extends","icon","label","TaskSkeleton","borderRadius"],"sources":["../../../../../src/presentation/stackedCard/content/TaskCard.tsx"],"sourcesContent":["import React, { ReactElement } from \"react\";\n\nimport styled, { css } from \"styled-components\";\n\nimport {\n EntityDots,\n StyledClamp,\n coverManagement,\n playControl,\n Placeholder,\n} from \"./shared\";\nimport {\n ChecklistSmallIcon,\n EyeOffIcon,\n InsertLinkIcon,\n MessageSmallIcon,\n PersonPlusIcon,\n} from \"../../../components/Icons\";\nimport { SkeletonLoader } from \"../../../components/Loaders\";\nimport { Caption1 } from \"../../../components/Typography\";\nimport { Typography } from \"../../../components/Typography/Typography\";\nimport { RoundAvatar, AVATAR_COLORS } from \"../../shared\";\nimport { Cover, StackRow } from \"../primitives\";\nimport { COVER_RATIO } from \"../shell\";\n\n/**\n * TaskCard — the baseline-preservation card.\n *\n * This is the replacement for today's column card, so it must reproduce every\n * behavior that card has (note 52104 §B2) — none of them are optional, each is\n * a silent-regression risk. Every one is a prop here so the story can toggle it:\n *\n * - task-number prefix in the title (config-gated, mirrors `show_task_id`)\n * - overdue date colouring (red ONLY when overdue AND not completed)\n * - dependency counter (behind a feature-flag prop)\n * - hidden-from-clients signifier (shown only when it DIFFERS from the\n * project default)\n * - inline assignee affordance (avatar, or an add-assignee placeholder)\n * - completed (teal tint, no \"…\" menu, no overdue colour)\n *\n * The pending/optimistic and priority states are SHELL states (dimmed +\n * pointer-events off; red left bar), so the card is wrapped in a `<StackedCard\n * pending>` / `<StackedCard priorityColor>` by the host — they are not the\n * card's own concern and live on the shell, not here.\n */\n\nconst LABEL_DOTS = [\"#378ADD\", \"#D85A30\", \"#639922\", \"#EF9F27\", \"#7F77DD\"];\n\n/* The completed tint fills the card body; the shell keeps the priority bar and\n selection ring on top of it. */\nconst StyledBody = styled.div<{ $completed?: boolean }>`\n display: flex;\n flex-direction: column;\n\n ${({ $completed }) =>\n $completed &&\n css`\n background: var(--sc-completed-tint, rgba(72, 201, 176, 0.16));\n `}\n`;\n\nconst StyledMetaCluster = styled.div`\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--color-theme-600);\n\n .sc-dots {\n display: flex;\n gap: 4px;\n }\n\n .sc-sep {\n opacity: 0.6;\n }\n\n .sc-count {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n }\n\n svg {\n width: 14px;\n height: 14px;\n }\n`;\n\nconst StyledDot = styled.span<{ $color: string }>`\n width: 11px;\n height: 11px;\n border-radius: 50%;\n background: ${({ $color }) => $color};\n`;\n\n/* Hidden-from-clients signifier — an eye-off badge, shown only when the task's\n visibility differs from the project default. */\nconst StyledHiddenBadge = styled.span`\n display: inline-flex;\n align-items: center;\n gap: 3px;\n color: var(--color-theme-600);\n\n svg {\n width: 14px;\n height: 14px;\n }\n`;\n\n/* Date — bold; turns red only when overdue AND the task is not completed. */\nconst StyledDate = styled.span<{ $overdue?: boolean }>`\n font-weight: bold;\n color: ${({ $overdue }) =>\n $overdue ? \"var(--red-alert)\" : \"var(--color-theme-900)\"};\n`;\n\n/* Inline assignee affordance placeholder — a dashed add-assignee target that\n stands in until the real picker is wired at integration. */\nconst StyledAddAssignee = styled.button`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n border: 1.5px dashed var(--color-theme-400);\n border-radius: 50%;\n background: transparent;\n color: var(--color-theme-600);\n cursor: pointer;\n\n svg {\n width: 14px;\n height: 14px;\n display: block;\n }\n\n &:hover {\n border-color: var(--sc-selection-ring);\n color: var(--color-theme-800);\n }\n`;\n\nexport interface TaskCardProps {\n title?: string;\n /** Optional cover — task cards in a column usually have none. */\n cover?: boolean;\n playable?: boolean;\n coverControls?: boolean;\n /** Config-gated task-number prefix (mirrors `show_task_id`). */\n showTaskId?: boolean;\n taskId?: number;\n dateLabel?: string;\n /** Overdue date — colours the date red, but only when NOT completed. */\n overdue?: boolean;\n /** Dependency counter, gated behind a feature flag. */\n showDependencies?: boolean;\n dependencyCount?: number;\n /** The task's hidden-from-clients flag. */\n hiddenFromClients?: boolean;\n /** The project default for client visibility; the signifier shows on a diff. */\n projectDefaultHidden?: boolean;\n /** Whether the task has an assignee (avatar) or shows the add affordance. */\n assigned?: boolean;\n /** Completed — teal tint, no \"…\" menu, no overdue colour. */\n completed?: boolean;\n}\n\nexport const TaskCard = ({\n title = \"Implement the design from the reference on this page\",\n cover = false,\n playable = false,\n coverControls = false,\n showTaskId = false,\n taskId = 4521,\n dateLabel = \"May 8 – Sep 10\",\n overdue = false,\n showDependencies = false,\n dependencyCount = 2,\n hiddenFromClients = false,\n projectDefaultHidden = false,\n assigned = true,\n completed = false,\n}: TaskCardProps): ReactElement => {\n // Signifier appears only when the task's visibility differs from the default.\n const showHiddenSignifier = hiddenFromClients !== projectDefaultHidden;\n // Overdue colour is suppressed on completed tasks.\n const dateIsOverdue = overdue && !completed;\n\n return (\n <StyledBody $completed={completed}>\n {cover ? (\n <Cover\n aspectRatio={COVER_RATIO}\n centerSlot={playable ? playControl : undefined}\n topRightSlot={coverControls ? coverManagement() : undefined}\n >\n <div\n style={{\n width: \"100%\",\n height: \"100%\",\n background: \"var(--color-theme-300)\",\n }}\n />\n </Cover>\n ) : null}\n\n <StackRow role=\"title\">\n <StyledClamp>\n {showTaskId ? (\n <Typography as=\"span\" variant=\"Caption 1\" color=\"tertiary\">\n {`#${taskId} `}\n </Typography>\n ) : null}\n {title}\n </StyledClamp>\n {/* Completed tasks drop the \"…\" menu. */}\n {completed ? null : <EntityDots aria-label=\"Task options\" />}\n </StackRow>\n\n <StackRow role=\"meta\">\n <StyledMetaCluster>\n <span className=\"sc-dots\">\n {LABEL_DOTS.map((color) => (\n <StyledDot key={color} $color={color} />\n ))}\n </span>\n <Caption1 color=\"tertiary\">+3</Caption1>\n <span className=\"sc-sep\">·</span>\n <span className=\"sc-count\">\n <MessageSmallIcon />\n <Caption1 color=\"tertiary\">7</Caption1>\n </span>\n <span className=\"sc-sep\">·</span>\n <span className=\"sc-count\">\n <ChecklistSmallIcon />\n <Caption1 color=\"tertiary\">2</Caption1>\n </span>\n {showDependencies ? (\n <>\n <span className=\"sc-sep\">·</span>\n <span className=\"sc-count\" title=\"Dependencies\">\n <InsertLinkIcon />\n <Caption1 color=\"tertiary\">{dependencyCount}</Caption1>\n </span>\n </>\n ) : null}\n {showHiddenSignifier ? (\n <>\n <span className=\"sc-sep\">·</span>\n <StyledHiddenBadge title=\"Hidden from clients\">\n <EyeOffIcon />\n </StyledHiddenBadge>\n </>\n ) : null}\n </StyledMetaCluster>\n </StackRow>\n\n <StackRow role=\"footer\">\n <StyledDate $overdue={dateIsOverdue}>{dateLabel}</StyledDate>\n <span />\n {assigned ? (\n <RoundAvatar\n $bg={AVATAR_COLORS.teal}\n $size={24}\n $bordered={false}\n data-fixed\n >\n MS\n </RoundAvatar>\n ) : (\n <StyledAddAssignee type=\"button\" aria-label=\"Assign task\" data-fixed>\n <PersonPlusIcon />\n </StyledAddAssignee>\n )}\n </StackRow>\n </StyledBody>\n );\n};\n\n/* ---- placeholder + skeleton ---- */\n\nexport const TaskPlaceholder = (\n props: React.ButtonHTMLAttributes<HTMLButtonElement>\n): ReactElement => (\n <Placeholder\n icon={<ChecklistSmallIcon />}\n label=\"Name this task\"\n {...props}\n />\n);\n\n/* Skeleton mirrors the task anatomy row for row: title, meta, footer. */\nexport const TaskSkeleton = (): ReactElement => (\n <>\n <StackRow role=\"title\">\n <SkeletonLoader style={{ height: 14, width: \"90%\" }} />\n </StackRow>\n <StackRow role=\"meta\">\n <SkeletonLoader style={{ height: 10, width: \"55%\" }} />\n </StackRow>\n <StackRow role=\"footer\">\n <SkeletonLoader style={{ height: 12, width: 64 }} data-fixed />\n <span />\n <SkeletonLoader\n data-fixed\n style={{ width: 24, height: 24, borderRadius: \"50%\" }}\n />\n </StackRow>\n </>\n);\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,8 @@
1
+ export * from "./shared";
2
+ export * from "./unfurl";
3
+ export * from "./TaskCard";
4
+ export * from "./LinkCard";
5
+ export * from "./ImageCard";
6
+ export * from "./SwatchCard";
7
+ export * from "./NoteCard";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/stackedCard/content/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,8 @@
1
+ export * from "./shared";
2
+ export * from "./unfurl";
3
+ export * from "./TaskCard";
4
+ export * from "./LinkCard";
5
+ export * from "./ImageCard";
6
+ export * from "./SwatchCard";
7
+ export * from "./NoteCard";
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../../src/presentation/stackedCard/content/index.ts"],"sourcesContent":["export * from \"./shared\";\nexport * from \"./unfurl\";\nexport * from \"./TaskCard\";\nexport * from \"./LinkCard\";\nexport * from \"./ImageCard\";\nexport * from \"./SwatchCard\";\nexport * from \"./NoteCard\";\n"],"mappings":"AAAA,cAAc,UAAU;AACxB,cAAc,UAAU;AACxB,cAAc,YAAY;AAC1B,cAAc,YAAY;AAC1B,cAAc,aAAa;AAC3B,cAAc,cAAc;AAC5B,cAAc,YAAY","ignoreList":[]}
@@ -0,0 +1,46 @@
1
+ import React, { ReactElement, ReactNode } from "react";
2
+ /**
3
+ * Content-level chrome shared by the typed StackedCard components.
4
+ *
5
+ * These live OUTSIDE the shell on purpose. The shell is hollow; the "…" entity
6
+ * menu, the cover-management controls, the clamp, the favicon, the chips and
7
+ * the placeholder frame are content concerns, so they belong here where the
8
+ * typed cards (TaskCard, LinkCard, …) compose them.
9
+ */
10
+ /** Centered media control (play), for a cover that wraps audio/video. */
11
+ export declare const playControl: React.JSX.Element;
12
+ /**
13
+ * Top-right cover management. Acts on the COVER (collapse it, remove it) — not
14
+ * on the entity. Callers wire the click handlers; the default is inert chrome
15
+ * for the static demos.
16
+ */
17
+ export declare const coverManagement: ({ removeLabel, onCollapse, onRemove, }?: {
18
+ removeLabel?: string;
19
+ onCollapse?: () => void;
20
+ onRemove?: () => void;
21
+ }) => ReactElement;
22
+ export declare const EntityDots: (props: React.ButtonHTMLAttributes<HTMLButtonElement>) => ReactElement;
23
+ /** Two-line title clamp — the card's name row content. */
24
+ export declare const StyledClamp: import("styled-components").StyledComponent<React.ForwardRefExoticComponent<import("../../..").IBodyProps & Omit<import("../../../components/Typography/Typography").ITypographyProps, "variant" | "weight"> & React.RefAttributes<HTMLDivElement>>, any, {}, never>;
25
+ /** A favicon square — a solid data colour stands in for the real favicon. */
26
+ export declare const StyledFavicon: import("styled-components").StyledComponent<"span", any, {
27
+ $bg: string;
28
+ }, never>;
29
+ /** A small pill for link metadata (media kind, duration, …). */
30
+ export declare const StyledChip: import("styled-components").StyledComponent<"span", any, {}, never>;
31
+ /** A solid-colour cover fill (swatch value, generic link cover, image stand-in). */
32
+ export declare const StyledColorCover: import("styled-components").StyledComponent<"div", any, {
33
+ $color: string;
34
+ }, never>;
35
+ /**
36
+ * The shared placeholder frame. Each type supplies its own icon and verb-first,
37
+ * sentence-case invitation (ActiveCollab voice). Interactive by design — the
38
+ * whole frame is a button — and distinct from the loading skeleton.
39
+ */
40
+ export declare const Placeholder: ({ icon, label, height, dashed, ...rest }: {
41
+ icon: ReactNode;
42
+ label: ReactNode;
43
+ height?: number;
44
+ dashed?: boolean;
45
+ } & React.ButtonHTMLAttributes<HTMLButtonElement>) => ReactElement;
46
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/stackedCard/content/shared.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAcvD;;;;;;;GAOG;AAMH,yEAAyE;AACzE,eAAO,MAAM,WAAW,mBAIvB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,yCAI7B;IACD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB,KAAG,YASR,CAAC;AA8BF,eAAO,MAAM,UAAU,GACrB,OAAO,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,KACnD,YAUF,CAAC;AAMF,0DAA0D;AAC1D,eAAO,MAAM,WAAW,sQAKvB,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,aAAa;SAAsB,MAAM;SAOrD,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,UAAU,qEAStB,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,gBAAgB;YAAwB,MAAM;SAI1D,CAAC;AA6CF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,0CAMzB;IACD,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,KAAG,YAOnD,CAAC"}
@@ -0,0 +1,134 @@
1
+ import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
2
+ import _extends from "@babel/runtime/helpers/esm/extends";
3
+ const _excluded = ["icon", "label", "height", "dashed"];
4
+ import React from "react";
5
+ import styled, { css } from "styled-components";
6
+ import { PlayIcon, TreeDotsIcon } from "../../../components/Icons";
7
+ import { Body2 } from "../../../components/Typography";
8
+ import { Typography } from "../../../components/Typography/Typography";
9
+ import { CollapseGlyph, CoverButton, PlayBadge, RemoveCoverGlyph } from "../primitives";
10
+
11
+ /**
12
+ * Content-level chrome shared by the typed StackedCard components.
13
+ *
14
+ * These live OUTSIDE the shell on purpose. The shell is hollow; the "…" entity
15
+ * menu, the cover-management controls, the clamp, the favicon, the chips and
16
+ * the placeholder frame are content concerns, so they belong here where the
17
+ * typed cards (TaskCard, LinkCard, …) compose them.
18
+ */
19
+
20
+ /* ------------------------------------------------------------------ */
21
+ /* Cover chrome — media control + cover management */
22
+ /* ------------------------------------------------------------------ */
23
+
24
+ /** Centered media control (play), for a cover that wraps audio/video. */
25
+ export const playControl = /*#__PURE__*/React.createElement(PlayBadge, null, /*#__PURE__*/React.createElement(PlayIcon, null));
26
+
27
+ /**
28
+ * Top-right cover management. Acts on the COVER (collapse it, remove it) — not
29
+ * on the entity. Callers wire the click handlers; the default is inert chrome
30
+ * for the static demos.
31
+ */
32
+ export const coverManagement = function (_temp) {
33
+ let _ref = _temp === void 0 ? {} : _temp,
34
+ _ref$removeLabel = _ref.removeLabel,
35
+ removeLabel = _ref$removeLabel === void 0 ? "Remove cover" : _ref$removeLabel,
36
+ onCollapse = _ref.onCollapse,
37
+ onRemove = _ref.onRemove;
38
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(CoverButton, {
39
+ type: "button",
40
+ "aria-label": "Collapse cover",
41
+ onClick: onCollapse
42
+ }, /*#__PURE__*/React.createElement(CollapseGlyph, null)), /*#__PURE__*/React.createElement(CoverButton, {
43
+ type: "button",
44
+ "aria-label": removeLabel,
45
+ onClick: onRemove
46
+ }, /*#__PURE__*/React.createElement(RemoveCoverGlyph, null)));
47
+ };
48
+
49
+ /* ------------------------------------------------------------------ */
50
+ /* Entity "…" menu — acts on the ENTITY, lives in a content row */
51
+ /* ------------------------------------------------------------------ */
52
+
53
+ const StyledEntityDots = styled.button.withConfig({
54
+ displayName: "shared__StyledEntityDots",
55
+ componentId: "sc-1x5md9a-0"
56
+ })(["display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;padding:0;border:0;border-radius:6px;cursor:pointer;color:var(--color-theme-700);background:var(--color-theme-200);svg{width:16px;height:16px;display:block;}&:hover{background:var(--color-theme-300);}"]);
57
+ export const EntityDots = props => /*#__PURE__*/React.createElement(StyledEntityDots, _extends({
58
+ type: "button",
59
+ "aria-label": "Options",
60
+ "data-fixed": true,
61
+ className: "sc-control"
62
+ }, props), /*#__PURE__*/React.createElement(TreeDotsIcon, null));
63
+
64
+ /* ------------------------------------------------------------------ */
65
+ /* Text + inline bits */
66
+ /* ------------------------------------------------------------------ */
67
+
68
+ /** Two-line title clamp — the card's name row content. */
69
+ export const StyledClamp = styled(Body2).withConfig({
70
+ displayName: "shared__StyledClamp",
71
+ componentId: "sc-1x5md9a-1"
72
+ })(["display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;"]);
73
+
74
+ /** A favicon square — a solid data colour stands in for the real favicon. */
75
+ export const StyledFavicon = styled.span.withConfig({
76
+ displayName: "shared__StyledFavicon",
77
+ componentId: "sc-1x5md9a-2"
78
+ })(["display:inline-flex;width:16px;height:16px;border-radius:4px;background:", ";flex-shrink:0;"], _ref2 => {
79
+ let $bg = _ref2.$bg;
80
+ return $bg;
81
+ });
82
+
83
+ /** A small pill for link metadata (media kind, duration, …). */
84
+ export const StyledChip = styled.span.withConfig({
85
+ displayName: "shared__StyledChip",
86
+ componentId: "sc-1x5md9a-3"
87
+ })(["display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;background:var(--color-theme-300);color:var(--color-theme-800);font-size:11px;white-space:nowrap;"]);
88
+
89
+ /** A solid-colour cover fill (swatch value, generic link cover, image stand-in). */
90
+ export const StyledColorCover = styled.div.withConfig({
91
+ displayName: "shared__StyledColorCover",
92
+ componentId: "sc-1x5md9a-4"
93
+ })(["width:100%;height:100%;background:", ";"], _ref3 => {
94
+ let $color = _ref3.$color;
95
+ return $color;
96
+ });
97
+
98
+ /* ------------------------------------------------------------------ */
99
+ /* Placeholder frame — the interactive empty state, per type */
100
+ /* ------------------------------------------------------------------ */
101
+
102
+ const StyledPlaceholder = styled.button.withConfig({
103
+ displayName: "shared__StyledPlaceholder",
104
+ componentId: "sc-1x5md9a-5"
105
+ })(["display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;width:100%;height:", "px;padding:0;border:0;background:transparent;color:var(--color-theme-600);text-align:center;cursor:pointer;", " > svg{width:40px;height:40px;color:var(--color-theme-500);}"], _ref4 => {
106
+ let $height = _ref4.$height;
107
+ return $height != null ? $height : 150;
108
+ }, _ref5 => {
109
+ let $dashed = _ref5.$dashed;
110
+ return $dashed && css(["margin:8px;width:calc(100% - 16px);border:1.5px dashed var(--color-theme-400);border-radius:6px;&:hover{border-color:var(--sc-selection-ring);color:var(--color-theme-700);}"]);
111
+ });
112
+
113
+ /**
114
+ * The shared placeholder frame. Each type supplies its own icon and verb-first,
115
+ * sentence-case invitation (ActiveCollab voice). Interactive by design — the
116
+ * whole frame is a button — and distinct from the loading skeleton.
117
+ */
118
+ export const Placeholder = _ref6 => {
119
+ let icon = _ref6.icon,
120
+ label = _ref6.label,
121
+ height = _ref6.height,
122
+ dashed = _ref6.dashed,
123
+ rest = _objectWithoutPropertiesLoose(_ref6, _excluded);
124
+ return /*#__PURE__*/React.createElement(StyledPlaceholder, _extends({
125
+ type: "button",
126
+ $height: height,
127
+ $dashed: dashed
128
+ }, rest), icon, /*#__PURE__*/React.createElement(Typography, {
129
+ as: "span",
130
+ variant: "Body 2",
131
+ color: "secondary"
132
+ }, label));
133
+ };
134
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","names":["React","styled","css","PlayIcon","TreeDotsIcon","Body2","Typography","CollapseGlyph","CoverButton","PlayBadge","RemoveCoverGlyph","playControl","createElement","coverManagement","_temp","_ref","_ref$removeLabel","removeLabel","onCollapse","onRemove","Fragment","type","onClick","StyledEntityDots","button","withConfig","displayName","componentId","EntityDots","props","_extends","className","StyledClamp","StyledFavicon","span","_ref2","$bg","StyledChip","StyledColorCover","div","_ref3","$color","StyledPlaceholder","_ref4","$height","_ref5","$dashed","Placeholder","_ref6","icon","label","height","dashed","rest","_objectWithoutPropertiesLoose","_excluded","as","variant","color"],"sources":["../../../../../src/presentation/stackedCard/content/shared.tsx"],"sourcesContent":["import React, { ReactElement, ReactNode } from \"react\";\n\nimport styled, { css } from \"styled-components\";\n\nimport { PlayIcon, TreeDotsIcon } from \"../../../components/Icons\";\nimport { Body2 } from \"../../../components/Typography\";\nimport { Typography } from \"../../../components/Typography/Typography\";\nimport {\n CollapseGlyph,\n CoverButton,\n PlayBadge,\n RemoveCoverGlyph,\n} from \"../primitives\";\n\n/**\n * Content-level chrome shared by the typed StackedCard components.\n *\n * These live OUTSIDE the shell on purpose. The shell is hollow; the \"…\" entity\n * menu, the cover-management controls, the clamp, the favicon, the chips and\n * the placeholder frame are content concerns, so they belong here where the\n * typed cards (TaskCard, LinkCard, …) compose them.\n */\n\n/* ------------------------------------------------------------------ */\n/* Cover chrome — media control + cover management */\n/* ------------------------------------------------------------------ */\n\n/** Centered media control (play), for a cover that wraps audio/video. */\nexport const playControl = (\n <PlayBadge>\n <PlayIcon />\n </PlayBadge>\n);\n\n/**\n * Top-right cover management. Acts on the COVER (collapse it, remove it) — not\n * on the entity. Callers wire the click handlers; the default is inert chrome\n * for the static demos.\n */\nexport const coverManagement = ({\n removeLabel = \"Remove cover\",\n onCollapse,\n onRemove,\n}: {\n removeLabel?: string;\n onCollapse?: () => void;\n onRemove?: () => void;\n} = {}): ReactElement => (\n <>\n <CoverButton type=\"button\" aria-label=\"Collapse cover\" onClick={onCollapse}>\n <CollapseGlyph />\n </CoverButton>\n <CoverButton type=\"button\" aria-label={removeLabel} onClick={onRemove}>\n <RemoveCoverGlyph />\n </CoverButton>\n </>\n);\n\n/* ------------------------------------------------------------------ */\n/* Entity \"…\" menu — acts on the ENTITY, lives in a content row */\n/* ------------------------------------------------------------------ */\n\nconst StyledEntityDots = styled.button`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: 0;\n border-radius: 6px;\n cursor: pointer;\n color: var(--color-theme-700);\n background: var(--color-theme-200);\n\n svg {\n width: 16px;\n height: 16px;\n display: block;\n }\n\n &:hover {\n background: var(--color-theme-300);\n }\n`;\n\nexport const EntityDots = (\n props: React.ButtonHTMLAttributes<HTMLButtonElement>\n): ReactElement => (\n <StyledEntityDots\n type=\"button\"\n aria-label=\"Options\"\n data-fixed\n className=\"sc-control\"\n {...props}\n >\n <TreeDotsIcon />\n </StyledEntityDots>\n);\n\n/* ------------------------------------------------------------------ */\n/* Text + inline bits */\n/* ------------------------------------------------------------------ */\n\n/** Two-line title clamp — the card's name row content. */\nexport const StyledClamp = styled(Body2)`\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n`;\n\n/** A favicon square — a solid data colour stands in for the real favicon. */\nexport const StyledFavicon = styled.span<{ $bg: string }>`\n display: inline-flex;\n width: 16px;\n height: 16px;\n border-radius: 4px;\n background: ${({ $bg }) => $bg};\n flex-shrink: 0;\n`;\n\n/** A small pill for link metadata (media kind, duration, …). */\nexport const StyledChip = styled.span`\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border-radius: 10px;\n background: var(--color-theme-300);\n color: var(--color-theme-800);\n font-size: 11px;\n white-space: nowrap;\n`;\n\n/** A solid-colour cover fill (swatch value, generic link cover, image stand-in). */\nexport const StyledColorCover = styled.div<{ $color: string }>`\n width: 100%;\n height: 100%;\n background: ${({ $color }) => $color};\n`;\n\n/* ------------------------------------------------------------------ */\n/* Placeholder frame — the interactive empty state, per type */\n/* ------------------------------------------------------------------ */\n\nconst StyledPlaceholder = styled.button<{\n $height?: number;\n $dashed?: boolean;\n}>`\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 10px;\n width: 100%;\n height: ${({ $height }) => $height ?? 150}px;\n padding: 0;\n border: 0;\n background: transparent;\n color: var(--color-theme-600);\n text-align: center;\n cursor: pointer;\n\n ${({ $dashed }) =>\n $dashed &&\n css`\n margin: 8px;\n width: calc(100% - 16px);\n border: 1.5px dashed var(--color-theme-400);\n border-radius: 6px;\n\n &:hover {\n border-color: var(--sc-selection-ring);\n color: var(--color-theme-700);\n }\n `}\n\n > svg {\n width: 40px;\n height: 40px;\n color: var(--color-theme-500);\n }\n`;\n\n/**\n * The shared placeholder frame. Each type supplies its own icon and verb-first,\n * sentence-case invitation (ActiveCollab voice). Interactive by design — the\n * whole frame is a button — and distinct from the loading skeleton.\n */\nexport const Placeholder = ({\n icon,\n label,\n height,\n dashed,\n ...rest\n}: {\n icon: ReactNode;\n label: ReactNode;\n height?: number;\n dashed?: boolean;\n} & React.ButtonHTMLAttributes<HTMLButtonElement>): ReactElement => (\n <StyledPlaceholder type=\"button\" $height={height} $dashed={dashed} {...rest}>\n {icon}\n <Typography as=\"span\" variant=\"Body 2\" color=\"secondary\">\n {label}\n </Typography>\n </StyledPlaceholder>\n);\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Mock unfurl service for the LinkCard concept.
3
+ *
4
+ * A link preview is a LIFECYCLE, not two static layouts. The real service is
5
+ * server-side (SSRF-guarded, oEmbed → OpenGraph → Twitter Cards → <title>,
6
+ * cached ~24h with a stored `fetchedAt` and a manual re-unfurl affordance — see
7
+ * note 52104 §B3). This is a promise-based fake with a configurable delay and a
8
+ * failure toggle so the story can drive the whole lifecycle without a network.
9
+ *
10
+ * The data arrives on a PROGRESSIVE LADDER of three tiers, each carrying more
11
+ * than the last:
12
+ * url → just the raw URL (nothing fetched yet)
13
+ * basic → favicon + title + domain
14
+ * full → + description, hero image, media kind / duration
15
+ * The card reserves the next tier's space at every tier, so climbing the ladder
16
+ * never reflows the card.
17
+ */
18
+ export type UnfurlTier = "url" | "basic" | "full";
19
+ export type UnfurlStatus = "resolving" | "resolved" | "stale" | "error";
20
+ /** The cumulative data shape. Fields fill in as the ladder climbs. */
21
+ export interface UnfurlData {
22
+ /** Always present — the raw pasted URL. */
23
+ url: string;
24
+ /** Tier `basic` and up: a stand-in favicon colour. */
25
+ faviconColor?: string;
26
+ /** Tier `basic` and up: page title. */
27
+ title?: string;
28
+ /** Tier `basic` and up: the display domain. */
29
+ domain?: string;
30
+ /** Tier `full`: short description / summary. */
31
+ description?: string;
32
+ /** Tier `full`: hero image src (a real <img> in production). */
33
+ heroSrc?: string;
34
+ /** Tier `full`: hero fill colour, used when there is no hero image. */
35
+ heroColor?: string;
36
+ /** Tier `full`: media kind chip (Video, Article, …). */
37
+ kind?: string;
38
+ /** Tier `full`: duration chip for playable media. */
39
+ duration?: string;
40
+ /** Tier `full`: whether the media is playable (shows the cover play badge). */
41
+ playable?: boolean;
42
+ }
43
+ /** A seed link — what the fake "server" would resolve the URL to at tier full. */
44
+ export interface MockLink {
45
+ url: string;
46
+ faviconColor: string;
47
+ title: string;
48
+ domain: string;
49
+ description: string;
50
+ heroColor: string;
51
+ heroSrc?: string;
52
+ kind: string;
53
+ duration?: string;
54
+ playable?: boolean;
55
+ }
56
+ export declare const MOCK_LINKS: Record<string, MockLink>;
57
+ export interface UnfurlConfig {
58
+ /** Which seed link to resolve. */
59
+ link: MockLink;
60
+ /** Per-tier delay in ms (url→basic and basic→full each wait this long). */
61
+ delayMs?: number;
62
+ /** When true, the unfurl fails partway and lands in the error state. */
63
+ shouldFail?: boolean;
64
+ }
65
+ export interface UnfurlController {
66
+ status: UnfurlStatus;
67
+ tier: UnfurlTier;
68
+ data: UnfurlData;
69
+ /** Epoch ms of the last successful resolve (drives the stale affordance). */
70
+ fetchedAt: number | null;
71
+ /** Start (or restart) the unfurl ladder from scratch. */
72
+ start: () => void;
73
+ /** Retry after an error — re-runs the simulation. */
74
+ retry: () => void;
75
+ /** Re-unfurl a resolved/stale card — re-runs the simulation. */
76
+ reunfurl: () => void;
77
+ /** Force the resolved card into the stale state (demo affordance). */
78
+ markStale: () => void;
79
+ }
80
+ /**
81
+ * Drives one link through the unfurl lifecycle. Climbs url → basic → full on a
82
+ * timer, or lands in `error` if `shouldFail`. `retry` / `reunfurl` re-run it;
83
+ * `markStale` moves a resolved card to the stale state so the re-unfurl
84
+ * affordance can be shown.
85
+ */
86
+ export declare const useUnfurl: ({ link, delayMs, shouldFail, }: UnfurlConfig) => UnfurlController;
87
+ /** Human-readable "fetched N ago" for the stale affordance. */
88
+ export declare const formatFetchedAt: (fetchedAt: number | null) => string;
89
+ //# sourceMappingURL=unfurl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unfurl.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/stackedCard/content/unfurl.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,CAAC;AAExE,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,kFAAkF;AAClF,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAyB/C,CAAC;AAgBF,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,IAAI,EAAE,QAAQ,CAAC;IACf,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,6EAA6E;IAC7E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,yDAAyD;IACzD,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,qDAAqD;IACrD,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,sEAAsE;IACtE,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,GAAI,gCAIvB,YAAY,KAAG,gBA6DjB,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,eAAe,GAAI,WAAW,MAAM,GAAG,IAAI,KAAG,MAS1D,CAAC"}