@activecollab/components 2.0.371 → 2.0.373
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.
- package/dist/cjs/components/Icons/collection/ConnectionIcon.js +9 -17
- package/dist/cjs/components/Icons/collection/ConnectionIcon.js.map +1 -1
- package/dist/cjs/components/Icons/collection/ShapesIcon.js +61 -0
- package/dist/cjs/components/Icons/collection/ShapesIcon.js.map +1 -0
- package/dist/cjs/components/Icons/collection/index.js +7 -0
- package/dist/cjs/components/Icons/collection/index.js.map +1 -1
- package/dist/cjs/components/StackedCard/StackedCard.js +103 -19
- package/dist/cjs/components/StackedCard/StackedCard.js.map +1 -1
- package/dist/cjs/components/StackedCard/Styles.js +23 -18
- package/dist/cjs/components/StackedCard/Styles.js.map +1 -1
- package/dist/cjs/components/StackedCard/index.js +22 -0
- package/dist/cjs/components/StackedCard/index.js.map +1 -1
- package/dist/cjs/components/StackedCard/resizePolicy.js +238 -0
- package/dist/cjs/components/StackedCard/resizePolicy.js.map +1 -0
- package/dist/cjs/components/StackedCard/resizePolicy.test.js +474 -0
- package/dist/cjs/components/StackedCard/resizePolicy.test.js.map +1 -0
- package/dist/cjs/components/StackedCard/useStackedCardResize.js +145 -0
- package/dist/cjs/components/StackedCard/useStackedCardResize.js.map +1 -0
- package/dist/cjs/presentation/stackedCard/content/LinkCard.js +35 -22
- package/dist/cjs/presentation/stackedCard/content/LinkCard.js.map +1 -1
- package/dist/esm/components/Icons/collection/ConnectionIcon.d.ts.map +1 -1
- package/dist/esm/components/Icons/collection/ConnectionIcon.js +9 -17
- package/dist/esm/components/Icons/collection/ConnectionIcon.js.map +1 -1
- package/dist/esm/components/Icons/collection/ShapesIcon.d.ts +32 -0
- package/dist/esm/components/Icons/collection/ShapesIcon.d.ts.map +1 -0
- package/dist/esm/components/Icons/collection/ShapesIcon.js +54 -0
- package/dist/esm/components/Icons/collection/ShapesIcon.js.map +1 -0
- package/dist/esm/components/Icons/collection/index.d.ts +1 -0
- package/dist/esm/components/Icons/collection/index.d.ts.map +1 -1
- package/dist/esm/components/Icons/collection/index.js +1 -0
- package/dist/esm/components/Icons/collection/index.js.map +1 -1
- package/dist/esm/components/StackedCard/StackedCard.d.ts +44 -3
- package/dist/esm/components/StackedCard/StackedCard.d.ts.map +1 -1
- package/dist/esm/components/StackedCard/StackedCard.js +102 -19
- package/dist/esm/components/StackedCard/StackedCard.js.map +1 -1
- package/dist/esm/components/StackedCard/Styles.d.ts +4 -1
- package/dist/esm/components/StackedCard/Styles.d.ts.map +1 -1
- package/dist/esm/components/StackedCard/Styles.js +23 -18
- package/dist/esm/components/StackedCard/Styles.js.map +1 -1
- package/dist/esm/components/StackedCard/index.d.ts +2 -0
- package/dist/esm/components/StackedCard/index.d.ts.map +1 -1
- package/dist/esm/components/StackedCard/index.js +2 -0
- package/dist/esm/components/StackedCard/index.js.map +1 -1
- package/dist/esm/components/StackedCard/resizePolicy.d.ts +111 -0
- package/dist/esm/components/StackedCard/resizePolicy.d.ts.map +1 -0
- package/dist/esm/{presentation/stackedCard → components/StackedCard}/resizePolicy.js +93 -48
- package/dist/esm/components/StackedCard/resizePolicy.js.map +1 -0
- package/dist/esm/components/StackedCard/resizePolicy.test.d.ts +2 -0
- package/dist/esm/components/StackedCard/resizePolicy.test.d.ts.map +1 -0
- package/dist/esm/components/StackedCard/resizePolicy.test.js +470 -0
- package/dist/esm/components/StackedCard/resizePolicy.test.js.map +1 -0
- package/dist/esm/components/StackedCard/useStackedCardResize.d.ts +62 -0
- package/dist/esm/components/StackedCard/useStackedCardResize.d.ts.map +1 -0
- package/dist/esm/components/StackedCard/useStackedCardResize.js +137 -0
- package/dist/esm/components/StackedCard/useStackedCardResize.js.map +1 -0
- package/dist/esm/presentation/stackedCard/content/LinkCard.d.ts.map +1 -1
- package/dist/esm/presentation/stackedCard/content/LinkCard.js +35 -20
- package/dist/esm/presentation/stackedCard/content/LinkCard.js.map +1 -1
- package/dist/index.js +989 -482
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +1 -1
- package/dist/cjs/presentation/stackedCard/resizePolicy.js +0 -183
- package/dist/cjs/presentation/stackedCard/resizePolicy.js.map +0 -1
- package/dist/esm/presentation/stackedCard/resizePolicy.d.ts +0 -97
- package/dist/esm/presentation/stackedCard/resizePolicy.d.ts.map +0 -1
- package/dist/esm/presentation/stackedCard/resizePolicy.js.map +0 -1
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { useCallback, useRef } from "react";
|
|
2
|
+
import { applyResize, isResizeKey, keyboardResize, makeStart, measurePercent } from "./resizePolicy";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The one place pointer and keyboard input meet the resize policy.
|
|
6
|
+
*
|
|
7
|
+
* `StackedCard`'s built-in grip reports raw deltas and knows no policy — enough
|
|
8
|
+
* for a host that just tracks a width. This hook is the full contract: it
|
|
9
|
+
* captures the gesture start, funnels both inputs through the pure policy in
|
|
10
|
+
* `resizePolicy.ts`, streams preview events and fires exactly ONE commit per
|
|
11
|
+
* gesture. It returns the props to spread on the grip, including the live
|
|
12
|
+
* separator ARIA.
|
|
13
|
+
*
|
|
14
|
+
* Preview versus commit (spec §7e): the continuous stream is live feedback
|
|
15
|
+
* only. A host creates an undo entry on the COMMIT, never on a preview — and a
|
|
16
|
+
* gesture that never changed the size commits nothing at all, so a bare click
|
|
17
|
+
* on the grip is not a change.
|
|
18
|
+
*
|
|
19
|
+
* The hook never touches the card's content: the intrinsic minimum is read
|
|
20
|
+
* through `contentMin`, which may be a getter so a card that measures its own
|
|
21
|
+
* footer can answer at the moment it is asked.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/** The props to spread on the grip — `StackedCard`'s `resizeHandleProps`. */
|
|
25
|
+
|
|
26
|
+
const sameSize = (a, b) => a.w === b.w && a.h === b.h;
|
|
27
|
+
export const useStackedCardResize = _ref => {
|
|
28
|
+
let size = _ref.size,
|
|
29
|
+
policy = _ref.policy,
|
|
30
|
+
cardId = _ref.cardId,
|
|
31
|
+
contentMin = _ref.contentMin,
|
|
32
|
+
_ref$axis = _ref.axis,
|
|
33
|
+
axis = _ref$axis === void 0 ? "both" : _ref$axis,
|
|
34
|
+
_ref$scale = _ref.scale,
|
|
35
|
+
scale = _ref$scale === void 0 ? 1 : _ref$scale,
|
|
36
|
+
_ref$label = _ref.label,
|
|
37
|
+
label = _ref$label === void 0 ? "Resize card" : _ref$label,
|
|
38
|
+
onResize = _ref.onResize,
|
|
39
|
+
onResizeCommit = _ref.onResizeCommit;
|
|
40
|
+
// The pointer gesture's anchor: the size + content-min captured on pointer
|
|
41
|
+
// down, plus the pointer origin the delta is measured from.
|
|
42
|
+
const pointerStart = useRef(null);
|
|
43
|
+
// Mirrors the latest emitted size so pointer-up / key-up can commit exactly
|
|
44
|
+
// what preview last showed, without a stale closure.
|
|
45
|
+
const latest = useRef(size);
|
|
46
|
+
latest.current = size;
|
|
47
|
+
// Whether this gesture actually moved the card. A bare click, or a Home on an
|
|
48
|
+
// axis with no floor, leaves it false and commits nothing.
|
|
49
|
+
const dirty = useRef(false);
|
|
50
|
+
|
|
51
|
+
// Read through refs so the handlers below can stay stable across renders
|
|
52
|
+
// while still seeing the current policy, axis and zoom.
|
|
53
|
+
const policyRef = useRef(policy);
|
|
54
|
+
policyRef.current = policy;
|
|
55
|
+
const axisRef = useRef(axis);
|
|
56
|
+
axisRef.current = axis;
|
|
57
|
+
const scaleRef = useRef(scale);
|
|
58
|
+
scaleRef.current = scale;
|
|
59
|
+
const contentMinRef = useRef(contentMin);
|
|
60
|
+
contentMinRef.current = contentMin;
|
|
61
|
+
const readContentMin = useCallback(() => {
|
|
62
|
+
const source = contentMinRef.current;
|
|
63
|
+
return typeof source === "function" ? source() : source;
|
|
64
|
+
}, []);
|
|
65
|
+
const emitPreview = useCallback((next, source) => {
|
|
66
|
+
// Nothing changed — not a preview, and not something to commit later.
|
|
67
|
+
if (sameSize(next, latest.current)) return;
|
|
68
|
+
latest.current = next;
|
|
69
|
+
dirty.current = true;
|
|
70
|
+
onResize(next, source);
|
|
71
|
+
}, [onResize]);
|
|
72
|
+
const handlePointerDown = useCallback(e => {
|
|
73
|
+
pointerStart.current = {
|
|
74
|
+
start: makeStart(latest.current, readContentMin()),
|
|
75
|
+
x: e.clientX,
|
|
76
|
+
y: e.clientY
|
|
77
|
+
};
|
|
78
|
+
dirty.current = false;
|
|
79
|
+
e.target.setPointerCapture == null || e.target.setPointerCapture(e.pointerId);
|
|
80
|
+
e.preventDefault();
|
|
81
|
+
}, [readContentMin]);
|
|
82
|
+
const handlePointerMove = useCallback(e => {
|
|
83
|
+
const ps = pointerStart.current;
|
|
84
|
+
if (!ps) return;
|
|
85
|
+
const z = scaleRef.current || 1;
|
|
86
|
+
const next = applyResize(ps.start, {
|
|
87
|
+
dx: (e.clientX - ps.x) / z,
|
|
88
|
+
dy: (e.clientY - ps.y) / z
|
|
89
|
+
}, policyRef.current,
|
|
90
|
+
// Shift held during a free-form drag = temporary proportional lock.
|
|
91
|
+
{
|
|
92
|
+
constrain: e.shiftKey,
|
|
93
|
+
axis: axisRef.current
|
|
94
|
+
});
|
|
95
|
+
emitPreview(next, "pointer");
|
|
96
|
+
}, [emitPreview]);
|
|
97
|
+
const endPointer = useCallback(() => {
|
|
98
|
+
if (!pointerStart.current) return;
|
|
99
|
+
pointerStart.current = null;
|
|
100
|
+
if (dirty.current) onResizeCommit(latest.current, "pointer");
|
|
101
|
+
dirty.current = false;
|
|
102
|
+
}, [onResizeCommit]);
|
|
103
|
+
const handleKeyDown = useCallback(e => {
|
|
104
|
+
const next = keyboardResize(e.key, latest.current, policyRef.current, readContentMin(), {
|
|
105
|
+
shiftKey: e.shiftKey,
|
|
106
|
+
axis: axisRef.current
|
|
107
|
+
});
|
|
108
|
+
if (!next) return;
|
|
109
|
+
// The key is ours even when it resolves to no movement (already pinned at
|
|
110
|
+
// a bound), so the browser must not also scroll the surface.
|
|
111
|
+
e.preventDefault();
|
|
112
|
+
emitPreview(next, "keyboard");
|
|
113
|
+
}, [emitPreview, readContentMin]);
|
|
114
|
+
const handleKeyUp = useCallback(e => {
|
|
115
|
+
if (!isResizeKey(e.key)) return;
|
|
116
|
+
// The gesture end for the keyboard is the key release: one commit per
|
|
117
|
+
// hold, mirroring pointer-up after a stream of moves.
|
|
118
|
+
if (dirty.current) onResizeCommit(latest.current, "keyboard");
|
|
119
|
+
dirty.current = false;
|
|
120
|
+
}, [onResizeCommit]);
|
|
121
|
+
return {
|
|
122
|
+
role: "separator",
|
|
123
|
+
tabIndex: 0,
|
|
124
|
+
"aria-label": label,
|
|
125
|
+
"aria-controls": cardId,
|
|
126
|
+
"aria-valuemin": 0,
|
|
127
|
+
"aria-valuemax": 100,
|
|
128
|
+
"aria-valuenow": measurePercent(size, policy, readContentMin()),
|
|
129
|
+
onPointerDown: handlePointerDown,
|
|
130
|
+
onPointerMove: handlePointerMove,
|
|
131
|
+
onPointerUp: endPointer,
|
|
132
|
+
onLostPointerCapture: endPointer,
|
|
133
|
+
onKeyDown: handleKeyDown,
|
|
134
|
+
onKeyUp: handleKeyUp
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
//# sourceMappingURL=useStackedCardResize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useStackedCardResize.js","names":["useCallback","useRef","applyResize","isResizeKey","keyboardResize","makeStart","measurePercent","sameSize","a","b","w","h","useStackedCardResize","_ref","size","policy","cardId","contentMin","_ref$axis","axis","_ref$scale","scale","_ref$label","label","onResize","onResizeCommit","pointerStart","latest","current","dirty","policyRef","axisRef","scaleRef","contentMinRef","readContentMin","source","emitPreview","next","handlePointerDown","e","start","x","clientX","y","clientY","target","setPointerCapture","pointerId","preventDefault","handlePointerMove","ps","z","dx","dy","constrain","shiftKey","endPointer","handleKeyDown","key","handleKeyUp","role","tabIndex","onPointerDown","onPointerMove","onPointerUp","onLostPointerCapture","onKeyDown","onKeyUp"],"sources":["../../../../src/components/StackedCard/useStackedCardResize.ts"],"sourcesContent":["import React, { useCallback, useRef } from \"react\";\n\nimport {\n StackedCardContentMin,\n StackedCardResizeAxis,\n StackedCardResizePolicy,\n StackedCardResizeSource,\n StackedCardResizeStart,\n StackedCardSize,\n applyResize,\n isResizeKey,\n keyboardResize,\n makeStart,\n measurePercent,\n} from \"./resizePolicy\";\n\n/**\n * The one place pointer and keyboard input meet the resize policy.\n *\n * `StackedCard`'s built-in grip reports raw deltas and knows no policy — enough\n * for a host that just tracks a width. This hook is the full contract: it\n * captures the gesture start, funnels both inputs through the pure policy in\n * `resizePolicy.ts`, streams preview events and fires exactly ONE commit per\n * gesture. It returns the props to spread on the grip, including the live\n * separator ARIA.\n *\n * Preview versus commit (spec §7e): the continuous stream is live feedback\n * only. A host creates an undo entry on the COMMIT, never on a preview — and a\n * gesture that never changed the size commits nothing at all, so a bare click\n * on the grip is not a change.\n *\n * The hook never touches the card's content: the intrinsic minimum is read\n * through `contentMin`, which may be a getter so a card that measures its own\n * footer can answer at the moment it is asked.\n */\n\nexport interface UseStackedCardResizeArgs {\n /** The card's current size, owned by the host. */\n size: StackedCardSize;\n policy: StackedCardResizePolicy;\n /** Id of the element the grip resizes — becomes `aria-controls`. */\n cardId: string;\n /** The card's intrinsic minimum; a getter is read at the moment it is needed. */\n contentMin: StackedCardContentMin | (() => StackedCardContentMin);\n /** `width` locks the vertical axis (auto-height cards). Defaults to `both`. */\n axis?: StackedCardResizeAxis;\n /**\n * Pointer deltas are divided by this before they reach the policy, so a grip\n * inside a zoomed canvas tracks the cursor exactly. Keyboard nudges are\n * already in the host's units and pass straight through. Defaults to 1.\n */\n scale?: number;\n /** Accessible name for the grip. Defaults to \"Resize card\". */\n label?: string;\n /** Live feedback during the gesture. Never an undoable change. */\n onResize: (next: StackedCardSize, source: StackedCardResizeSource) => void;\n /** Fires once per gesture, and only if the size actually changed. */\n onResizeCommit: (\n final: StackedCardSize,\n source: StackedCardResizeSource\n ) => void;\n}\n\n/** The props to spread on the grip — `StackedCard`'s `resizeHandleProps`. */\nexport interface StackedCardResizeHandleProps {\n role: \"separator\";\n tabIndex: 0;\n \"aria-label\": string;\n \"aria-controls\": string;\n \"aria-valuemin\": number;\n \"aria-valuemax\": number;\n \"aria-valuenow\": number;\n onPointerDown: (e: React.PointerEvent) => void;\n onPointerMove: (e: React.PointerEvent) => void;\n onPointerUp: (e: React.PointerEvent) => void;\n onLostPointerCapture: (e: React.PointerEvent) => void;\n onKeyDown: (e: React.KeyboardEvent) => void;\n onKeyUp: (e: React.KeyboardEvent) => void;\n}\n\nconst sameSize = (a: StackedCardSize, b: StackedCardSize): boolean =>\n a.w === b.w && a.h === b.h;\n\nexport const useStackedCardResize = ({\n size,\n policy,\n cardId,\n contentMin,\n axis = \"both\",\n scale = 1,\n label = \"Resize card\",\n onResize,\n onResizeCommit,\n}: UseStackedCardResizeArgs): StackedCardResizeHandleProps => {\n // The pointer gesture's anchor: the size + content-min captured on pointer\n // down, plus the pointer origin the delta is measured from.\n const pointerStart = useRef<{\n start: StackedCardResizeStart;\n x: number;\n y: number;\n } | null>(null);\n // Mirrors the latest emitted size so pointer-up / key-up can commit exactly\n // what preview last showed, without a stale closure.\n const latest = useRef<StackedCardSize>(size);\n latest.current = size;\n // Whether this gesture actually moved the card. A bare click, or a Home on an\n // axis with no floor, leaves it false and commits nothing.\n const dirty = useRef(false);\n\n // Read through refs so the handlers below can stay stable across renders\n // while still seeing the current policy, axis and zoom.\n const policyRef = useRef(policy);\n policyRef.current = policy;\n const axisRef = useRef(axis);\n axisRef.current = axis;\n const scaleRef = useRef(scale);\n scaleRef.current = scale;\n const contentMinRef = useRef(contentMin);\n contentMinRef.current = contentMin;\n\n const readContentMin = useCallback((): StackedCardContentMin => {\n const source = contentMinRef.current;\n return typeof source === \"function\" ? source() : source;\n }, []);\n\n const emitPreview = useCallback(\n (next: StackedCardSize, source: StackedCardResizeSource) => {\n // Nothing changed — not a preview, and not something to commit later.\n if (sameSize(next, latest.current)) return;\n latest.current = next;\n dirty.current = true;\n onResize(next, source);\n },\n [onResize]\n );\n\n const handlePointerDown = useCallback(\n (e: React.PointerEvent) => {\n pointerStart.current = {\n start: makeStart(latest.current, readContentMin()),\n x: e.clientX,\n y: e.clientY,\n };\n dirty.current = false;\n (e.target as HTMLElement).setPointerCapture?.(e.pointerId);\n e.preventDefault();\n },\n [readContentMin]\n );\n\n const handlePointerMove = useCallback(\n (e: React.PointerEvent) => {\n const ps = pointerStart.current;\n if (!ps) return;\n const z = scaleRef.current || 1;\n const next = applyResize(\n ps.start,\n { dx: (e.clientX - ps.x) / z, dy: (e.clientY - ps.y) / z },\n policyRef.current,\n // Shift held during a free-form drag = temporary proportional lock.\n { constrain: e.shiftKey, axis: axisRef.current }\n );\n emitPreview(next, \"pointer\");\n },\n [emitPreview]\n );\n\n const endPointer = useCallback(() => {\n if (!pointerStart.current) return;\n pointerStart.current = null;\n if (dirty.current) onResizeCommit(latest.current, \"pointer\");\n dirty.current = false;\n }, [onResizeCommit]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n const next = keyboardResize(\n e.key,\n latest.current,\n policyRef.current,\n readContentMin(),\n { shiftKey: e.shiftKey, axis: axisRef.current }\n );\n if (!next) return;\n // The key is ours even when it resolves to no movement (already pinned at\n // a bound), so the browser must not also scroll the surface.\n e.preventDefault();\n emitPreview(next, \"keyboard\");\n },\n [emitPreview, readContentMin]\n );\n\n const handleKeyUp = useCallback(\n (e: React.KeyboardEvent) => {\n if (!isResizeKey(e.key)) return;\n // The gesture end for the keyboard is the key release: one commit per\n // hold, mirroring pointer-up after a stream of moves.\n if (dirty.current) onResizeCommit(latest.current, \"keyboard\");\n dirty.current = false;\n },\n [onResizeCommit]\n );\n\n return {\n role: \"separator\",\n tabIndex: 0,\n \"aria-label\": label,\n \"aria-controls\": cardId,\n \"aria-valuemin\": 0,\n \"aria-valuemax\": 100,\n \"aria-valuenow\": measurePercent(size, policy, readContentMin()),\n onPointerDown: handlePointerDown,\n onPointerMove: handlePointerMove,\n onPointerUp: endPointer,\n onLostPointerCapture: endPointer,\n onKeyDown: handleKeyDown,\n onKeyUp: handleKeyUp,\n };\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LinkCard.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/stackedCard/content/LinkCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAc5C,OAAO,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"LinkCard.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/stackedCard/content/LinkCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAc5C,OAAO,EAAE,gBAAgB,EAA+B,MAAM,UAAU,CAAC;AAsBzE;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,UAAU,CAAC;AA6KjD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,gBAAgB,CAAC;IACzB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED,eAAO,MAAM,QAAQ,GAAI,uCAItB,aAAa,KAAG,YAsKlB,CAAC;AAyBF,eAAO,MAAM,YAAY,QAAO,YA0B/B,CAAC;AAIF,eAAO,MAAM,eAAe,GAC1B,OAAO,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,KACnD,YAEF,CAAC"}
|
|
@@ -9,6 +9,11 @@ import { STACKED_CARD_COVER_RATIO as COVER_RATIO, STACKED_CARD_CONTROL_CLASS, St
|
|
|
9
9
|
import { Body2, Caption1 } from "../../../components/Typography";
|
|
10
10
|
import { Typography } from "../../../components/Typography/Typography";
|
|
11
11
|
|
|
12
|
+
/* There is no global CSS reset in this Storybook, so a raw <button> falls back
|
|
13
|
+
to the UA font (Arial) instead of the DS stack. Every button below is text, so
|
|
14
|
+
they all need it. */
|
|
15
|
+
const CONTROL_FONT = "-apple-system, BlinkMacSystemFont, \"Roboto\",\n \"Helvetica Neue\", Arial, sans-serif";
|
|
16
|
+
|
|
12
17
|
/**
|
|
13
18
|
* LinkCard — a link preview as a LIFECYCLE, not two static layouts.
|
|
14
19
|
*
|
|
@@ -47,7 +52,7 @@ const StyledStaleStrip = styled.div.withConfig({
|
|
|
47
52
|
const StyledReunfurl = styled.button.withConfig({
|
|
48
53
|
displayName: "LinkCard__StyledReunfurl",
|
|
49
54
|
componentId: "sc-qyea73-3"
|
|
50
|
-
})(["display:inline-flex;align-items:center;gap:4px;flex:0 0 auto;padding:3px 8px;border:1px solid var(--border-primary);border-radius:6px;background:var(--page-paper-main);color:var(--color-theme-800);font-size:11px;cursor:pointer;svg{width:12px;height:12px;}&:hover{background:var(--color-theme-200);border-color:var(--sc-selection-ring);}"]);
|
|
55
|
+
})(["display:inline-flex;align-items:center;gap:4px;flex:0 0 auto;padding:3px 8px;border:1px solid var(--border-primary);border-radius:6px;background:var(--page-paper-main);color:var(--color-theme-800);font-family:", ";font-size:11px;cursor:pointer;svg{width:12px;height:12px;}&:hover{background:var(--color-theme-200);border-color:var(--sc-selection-ring);}"], CONTROL_FONT);
|
|
51
56
|
|
|
52
57
|
/* The error body — favicon + raw URL + retry, no media (per spec §5). It is a
|
|
53
58
|
column row like any other: the padding comes from the role, so the error
|
|
@@ -60,7 +65,21 @@ const StyledErrorRow = styled(StackRow).withConfig({
|
|
|
60
65
|
const StyledRetry = styled.button.withConfig({
|
|
61
66
|
displayName: "LinkCard__StyledRetry",
|
|
62
67
|
componentId: "sc-qyea73-5"
|
|
63
|
-
})(["align-self:flex-start;display:inline-flex;align-items:center;gap:6px;padding:5px 10px;border:1px solid var(--border-primary);border-radius:6px;background:var(--page-paper-main);color:var(--color-theme-800);cursor:pointer;svg{width:14px;height:14px;}&:hover{background:var(--color-theme-200);border-color:var(--sc-selection-ring);}"]);
|
|
68
|
+
})(["align-self:flex-start;display:inline-flex;align-items:center;gap:6px;padding:5px 10px;border:1px solid var(--border-primary);border-radius:6px;background:var(--page-paper-main);color:var(--color-theme-800);font-family:", ";cursor:pointer;svg{width:14px;height:14px;}&:hover{background:var(--color-theme-200);border-color:var(--sc-selection-ring);}"], CONTROL_FONT);
|
|
69
|
+
|
|
70
|
+
/* The resolved cover. A production unfurl stores the OpenGraph image, so when
|
|
71
|
+
the ladder returns one we render a real <img> (the Cover fill already gives
|
|
72
|
+
it `object-fit: cover`); the fill colour is the fallback for links that carry
|
|
73
|
+
no image at all. */
|
|
74
|
+
const resolvedCover = data => {
|
|
75
|
+
var _data$heroColor;
|
|
76
|
+
return data.heroSrc ? /*#__PURE__*/React.createElement("img", {
|
|
77
|
+
src: data.heroSrc,
|
|
78
|
+
alt: ""
|
|
79
|
+
}) : /*#__PURE__*/React.createElement(StyledColorCover, {
|
|
80
|
+
$color: (_data$heroColor = data.heroColor) != null ? _data$heroColor : "#1D9E75"
|
|
81
|
+
});
|
|
82
|
+
};
|
|
64
83
|
|
|
65
84
|
/* The expanded footer band — tinted, holds the title + domain under the hero. */
|
|
66
85
|
const StyledFooterTitle = styled(Body2).withConfig({
|
|
@@ -75,7 +94,7 @@ const StyledFooterTitle = styled(Body2).withConfig({
|
|
|
75
94
|
const StyledDisplayToggle = styled.button.withConfig({
|
|
76
95
|
displayName: "LinkCard__StyledDisplayToggle",
|
|
77
96
|
componentId: "sc-qyea73-7"
|
|
78
|
-
})(["display:inline-flex;align-items:center;padding:2px 8px;border:1px solid var(--border-primary);border-radius:10px;background:var(--color-theme-200);color:var(--color-theme-700);font-size:11px;cursor:pointer;white-space:nowrap;&:hover{background:var(--color-theme-300);}"]);
|
|
97
|
+
})(["display:inline-flex;align-items:center;padding:2px 8px;border:1px solid var(--border-primary);border-radius:10px;background:var(--color-theme-200);color:var(--color-theme-700);font-family:", ";font-size:11px;cursor:pointer;white-space:nowrap;&:hover{background:var(--color-theme-300);}"], CONTROL_FONT);
|
|
79
98
|
const DisplayToggle = _ref => {
|
|
80
99
|
let display = _ref.display,
|
|
81
100
|
onToggle = _ref.onToggle;
|
|
@@ -93,7 +112,7 @@ const DisplayToggle = _ref => {
|
|
|
93
112
|
/* ------------------------------------------------------------------ */
|
|
94
113
|
|
|
95
114
|
export const LinkCard = _ref2 => {
|
|
96
|
-
var _data$
|
|
115
|
+
var _data$faviconColor2;
|
|
97
116
|
let unfurl = _ref2.unfurl,
|
|
98
117
|
_ref2$display = _ref2.display,
|
|
99
118
|
display = _ref2$display === void 0 ? "compact" : _ref2$display,
|
|
@@ -132,18 +151,22 @@ export const LinkCard = _ref2 => {
|
|
|
132
151
|
}
|
|
133
152
|
const hasBasic = tier === "basic" || tier === "full";
|
|
134
153
|
const hasFull = tier === "full";
|
|
135
|
-
|
|
154
|
+
/* The display level belongs to the host, so the switch only appears when a
|
|
155
|
+
host actually owns one. A surface that fixes the card at one level (the
|
|
156
|
+
whiteboard pins it to expanded) gets no dead control. */
|
|
157
|
+
const toggle = onToggleDisplay ? /*#__PURE__*/React.createElement(DisplayToggle, {
|
|
158
|
+
display: display,
|
|
159
|
+
onToggle: onToggleDisplay
|
|
160
|
+
}) : null;
|
|
136
161
|
|
|
137
162
|
// ── Expanded: hero + tinted footer band (title + domain) ────────
|
|
138
163
|
if (display === "expanded") {
|
|
139
|
-
var _data$
|
|
164
|
+
var _data$faviconColor;
|
|
140
165
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Cover, {
|
|
141
166
|
aspectRatio: COVER_RATIO_HERO,
|
|
142
167
|
centerSlot: hasFull && data.playable ? playControl : undefined,
|
|
143
168
|
topRightSlot: coverManagement()
|
|
144
|
-
}, hasFull ? /*#__PURE__*/React.createElement(
|
|
145
|
-
$color: (_data$heroColor = data.heroColor) != null ? _data$heroColor : "#1D9E75"
|
|
146
|
-
}) : /*#__PURE__*/React.createElement(SkeletonLoader, {
|
|
169
|
+
}, hasFull ? resolvedCover(data) : /*#__PURE__*/React.createElement(SkeletonLoader, {
|
|
147
170
|
style: {
|
|
148
171
|
width: "100%",
|
|
149
172
|
height: "100%"
|
|
@@ -170,10 +193,7 @@ export const LinkCard = _ref2 => {
|
|
|
170
193
|
style: {
|
|
171
194
|
flex: "1 1 auto"
|
|
172
195
|
}
|
|
173
|
-
}), /*#__PURE__*/React.createElement(
|
|
174
|
-
display: display,
|
|
175
|
-
onToggle: toggle
|
|
176
|
-
})), hasBasic ? /*#__PURE__*/React.createElement(StyledFooterTitle, {
|
|
196
|
+
}), toggle), hasBasic ? /*#__PURE__*/React.createElement(StyledFooterTitle, {
|
|
177
197
|
weight: "bold"
|
|
178
198
|
}, data.title) : /*#__PURE__*/React.createElement(SkeletonLoader, {
|
|
179
199
|
style: {
|
|
@@ -199,9 +219,7 @@ export const LinkCard = _ref2 => {
|
|
|
199
219
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Cover, {
|
|
200
220
|
aspectRatio: COVER_RATIO,
|
|
201
221
|
centerSlot: hasFull && data.playable ? playControl : undefined
|
|
202
|
-
}, hasFull ? /*#__PURE__*/React.createElement(
|
|
203
|
-
$color: (_data$heroColor2 = data.heroColor) != null ? _data$heroColor2 : "#1D9E75"
|
|
204
|
-
}) : /*#__PURE__*/React.createElement(SkeletonLoader, {
|
|
222
|
+
}, hasFull ? resolvedCover(data) : /*#__PURE__*/React.createElement(SkeletonLoader, {
|
|
205
223
|
style: {
|
|
206
224
|
width: "100%",
|
|
207
225
|
height: "100%"
|
|
@@ -226,10 +244,7 @@ export const LinkCard = _ref2 => {
|
|
|
226
244
|
style: {
|
|
227
245
|
flex: "1 1 auto"
|
|
228
246
|
}
|
|
229
|
-
}), /*#__PURE__*/React.createElement(
|
|
230
|
-
display: display,
|
|
231
|
-
onToggle: toggle
|
|
232
|
-
}))), /*#__PURE__*/React.createElement(StackRow, {
|
|
247
|
+
}), toggle)), /*#__PURE__*/React.createElement(StackRow, {
|
|
233
248
|
role: "title"
|
|
234
249
|
}, hasBasic ? /*#__PURE__*/React.createElement(StyledClamp, null, data.title) : /*#__PURE__*/React.createElement("div", {
|
|
235
250
|
style: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LinkCard.js","names":["React","styled","COVER_RATIO_HERO","StyledChip","StyledClamp","StyledColorCover","StyledFavicon","coverManagement","playControl","Placeholder","formatFetchedAt","ArrowRefreshIcon","InsertLinkIcon","WarningTriangleIcon","SkeletonLoader","STACKED_CARD_COVER_RATIO","COVER_RATIO","STACKED_CARD_CONTROL_CLASS","StackedCardCover","Cover","StackedCardRow","StackRow","Body2","Caption1","Typography","StyledDomainRow","div","withConfig","displayName","componentId","StyledChips","StyledStaleStrip","StyledReunfurl","button","StyledErrorRow","StyledRetry","StyledFooterTitle","StyledDisplayToggle","DisplayToggle","_ref","display","onToggle","createElement","type","className","onClick","LinkCard","_ref2","_data$heroColor2","_data$faviconColor2","unfurl","_ref2$display","onToggleDisplay","status","tier","data","fetchedAt","retry","reunfurl","role","direction","weight","color","$bg","url","as","variant","hasBasic","hasFull","toggle","undefined","_data$heroColor","_data$faviconColor","Fragment","aspectRatio","centerSlot","playable","topRightSlot","$color","heroColor","style","width","height","background","faviconColor","borderRadius","domain","flex","title","description","StaleStrip","onReunfurl","marginTop","kind","duration","_ref3","LinkSkeleton","LinkPlaceholder","props","_extends","icon","label"],"sources":["../../../../../src/presentation/stackedCard/content/LinkCard.tsx"],"sourcesContent":["import React, { ReactElement } from \"react\";\n\nimport styled from \"styled-components\";\n\nimport {\n COVER_RATIO_HERO,\n StyledChip,\n StyledClamp,\n StyledColorCover,\n StyledFavicon,\n coverManagement,\n playControl,\n Placeholder,\n} from \"./shared\";\nimport { UnfurlController, formatFetchedAt } from \"./unfurl\";\nimport {\n ArrowRefreshIcon,\n InsertLinkIcon,\n WarningTriangleIcon,\n} from \"../../../components/Icons\";\nimport { SkeletonLoader } from \"../../../components/Loaders\";\nimport {\n STACKED_CARD_COVER_RATIO as COVER_RATIO,\n STACKED_CARD_CONTROL_CLASS,\n StackedCardCover as Cover,\n StackedCardRow as StackRow,\n} from \"../../../components/StackedCard\";\nimport { Body2, Caption1 } from \"../../../components/Typography\";\nimport { Typography } from \"../../../components/Typography/Typography\";\n\n/**\n * LinkCard — a link preview as a LIFECYCLE, not two static layouts.\n *\n * Data climbs a progressive ladder (url → basic → full); the anatomy is\n * CONSTANT at every tier, so each slot swaps a skeleton for real content in\n * place and the card never reflows on upgrade. Four statuses layer on top:\n * resolving — climbing the ladder, aspect + rows reserved by skeletons\n * resolved — the full card\n * stale — resolved, but past its cache window: shows `fetchedAt` and a\n * re-unfurl affordance\n * error — the unfurl failed: favicon + raw URL + retry, NO media\n *\n * Compact ↔ expanded is a user-switchable DISPLAY LEVEL on the same link\n * entity (the data lives in the controller, so switching never refetches or\n * loses it) — not two separate card types.\n */\n\nexport type LinkDisplay = \"compact\" | \"expanded\";\n\n/* ------------------------------------------------------------------ */\n/* Small building blocks */\n/* ------------------------------------------------------------------ */\n\nconst StyledDomainRow = styled.div`\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 16px;\n`;\n\nconst StyledChips = styled.div`\n display: flex;\n align-items: center;\n gap: 6px;\n min-height: 18px;\n`;\n\n/* The stale strip — a re-unfurl affordance with the fetch time. */\nconst StyledStaleStrip = styled.div`\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--color-theme-600);\n\n > span {\n flex: 1 1 auto;\n min-width: 0;\n }\n`;\n\nconst StyledReunfurl = styled.button`\n display: inline-flex;\n align-items: center;\n gap: 4px;\n flex: 0 0 auto;\n padding: 3px 8px;\n border: 1px solid var(--border-primary);\n border-radius: 6px;\n background: var(--page-paper-main);\n color: var(--color-theme-800);\n font-size: 11px;\n cursor: pointer;\n\n svg {\n width: 12px;\n height: 12px;\n }\n\n &:hover {\n background: var(--color-theme-200);\n border-color: var(--sc-selection-ring);\n }\n`;\n\n/* The error body — favicon + raw URL + retry, no media (per spec §5). It is a\n column row like any other: the padding comes from the role, so the error\n state lines up with the states it replaces instead of setting its own inset.\n Only the gap is widened — three stacked blocks, not four text lines. */\nconst StyledErrorRow = styled(StackRow)`\n gap: 10px;\n\n .err-head {\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--red-alert);\n }\n\n .err-head svg {\n width: 16px;\n height: 16px;\n flex: 0 0 auto;\n }\n\n .err-url {\n display: flex;\n align-items: center;\n gap: 8px;\n word-break: break-all;\n }\n`;\n\nconst StyledRetry = styled.button`\n align-self: flex-start;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 10px;\n border: 1px solid var(--border-primary);\n border-radius: 6px;\n background: var(--page-paper-main);\n color: var(--color-theme-800);\n cursor: pointer;\n\n svg {\n width: 14px;\n height: 14px;\n }\n\n &:hover {\n background: var(--color-theme-200);\n border-color: var(--sc-selection-ring);\n }\n`;\n\n/* The expanded footer band — tinted, holds the title + domain under the hero. */\nconst StyledFooterTitle = styled(Body2)`\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n`;\n\n/* ------------------------------------------------------------------ */\n/* The display-level switch — lives in the entity \"…\" slot */\n/* ------------------------------------------------------------------ */\n\nconst StyledDisplayToggle = styled.button`\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border: 1px solid var(--border-primary);\n border-radius: 10px;\n background: var(--color-theme-200);\n color: var(--color-theme-700);\n font-size: 11px;\n cursor: pointer;\n white-space: nowrap;\n\n &:hover {\n background: var(--color-theme-300);\n }\n`;\n\nconst DisplayToggle = ({\n display,\n onToggle,\n}: {\n display: LinkDisplay;\n onToggle: () => void;\n}): ReactElement => (\n <StyledDisplayToggle\n type=\"button\"\n data-fixed\n className={STACKED_CARD_CONTROL_CLASS}\n aria-label=\"Switch display level\"\n onClick={onToggle}\n >\n {display === \"compact\" ? \"Expand ▾\" : \"Compact ▴\"}\n </StyledDisplayToggle>\n);\n\n/* ------------------------------------------------------------------ */\n/* LinkCard */\n/* ------------------------------------------------------------------ */\n\nexport interface LinkCardProps {\n unfurl: UnfurlController;\n display?: LinkDisplay;\n onToggleDisplay?: () => void;\n}\n\nexport const LinkCard = ({\n unfurl,\n display = \"compact\",\n onToggleDisplay,\n}: LinkCardProps): ReactElement => {\n const { status, tier, data, fetchedAt, retry, reunfurl } = unfurl;\n\n // ── Error: favicon + raw URL + retry, no media ──────────────────\n if (status === \"error\") {\n return (\n <StyledErrorRow role=\"custom\" direction=\"column\">\n <div className=\"err-head\">\n <WarningTriangleIcon />\n <Caption1 weight=\"bold\" color=\"tertiary\">\n Couldn’t load a preview\n </Caption1>\n </div>\n <div className=\"err-url\">\n <StyledFavicon $bg=\"var(--color-theme-400)\" data-fixed />\n <Caption1 color=\"secondary\">{data.url}</Caption1>\n </div>\n <StyledRetry type=\"button\" onClick={retry}>\n <ArrowRefreshIcon />\n <Typography as=\"span\" variant=\"Caption 1\">\n Retry\n </Typography>\n </StyledRetry>\n </StyledErrorRow>\n );\n }\n\n const hasBasic = tier === \"basic\" || tier === \"full\";\n const hasFull = tier === \"full\";\n const toggle = onToggleDisplay ?? (() => undefined);\n\n // ── Expanded: hero + tinted footer band (title + domain) ────────\n if (display === \"expanded\") {\n return (\n <>\n <Cover\n aspectRatio={COVER_RATIO_HERO}\n centerSlot={hasFull && data.playable ? playControl : undefined}\n topRightSlot={coverManagement()}\n >\n {hasFull ? (\n <StyledColorCover $color={data.heroColor ?? \"#1D9E75\"} />\n ) : (\n <SkeletonLoader style={{ width: \"100%\", height: \"100%\" }} />\n )}\n </Cover>\n <StackRow\n role=\"footer\"\n direction=\"column\"\n background=\"var(--color-theme-200)\"\n >\n <StyledDomainRow>\n {hasBasic ? (\n <StyledFavicon $bg={data.faviconColor ?? \"#0F6E56\"} data-fixed />\n ) : (\n <SkeletonLoader\n data-fixed\n style={{ width: 16, height: 16, borderRadius: 4 }}\n />\n )}\n {hasBasic ? (\n <Caption1 color=\"tertiary\">{data.domain}</Caption1>\n ) : (\n <Caption1 color=\"tertiary\">{data.url}</Caption1>\n )}\n <span style={{ flex: \"1 1 auto\" }} />\n <DisplayToggle display={display} onToggle={toggle} />\n </StyledDomainRow>\n {hasBasic ? (\n <StyledFooterTitle weight=\"bold\">{data.title}</StyledFooterTitle>\n ) : (\n <SkeletonLoader style={{ height: 14, width: \"90%\" }} />\n )}\n {hasFull ? (\n <Caption1 color=\"tertiary\">{data.description}</Caption1>\n ) : (\n <SkeletonLoader style={{ height: 10, width: \"70%\" }} />\n )}\n </StackRow>\n {status === \"stale\" ? (\n <StackRow role=\"meta\">\n <StaleStrip fetchedAt={fetchedAt} onReunfurl={reunfurl} />\n </StackRow>\n ) : null}\n </>\n );\n }\n\n // ── Compact: cover + favicon/domain + title + chips ─────────────\n return (\n <>\n <Cover\n aspectRatio={COVER_RATIO}\n centerSlot={hasFull && data.playable ? playControl : undefined}\n >\n {hasFull ? (\n <StyledColorCover $color={data.heroColor ?? \"#1D9E75\"} />\n ) : (\n <SkeletonLoader style={{ width: \"100%\", height: \"100%\" }} />\n )}\n </Cover>\n\n <StackRow role=\"custom\">\n <StyledDomainRow>\n {hasBasic ? (\n <StyledFavicon $bg={data.faviconColor ?? \"#0F6E56\"} data-fixed />\n ) : (\n <SkeletonLoader\n data-fixed\n style={{ width: 16, height: 16, borderRadius: 4 }}\n />\n )}\n {hasBasic ? (\n <Caption1 color=\"tertiary\">{data.domain}</Caption1>\n ) : (\n <Caption1 color=\"tertiary\">{data.url}</Caption1>\n )}\n <span style={{ flex: \"1 1 auto\" }} />\n <DisplayToggle display={display} onToggle={toggle} />\n </StyledDomainRow>\n </StackRow>\n\n <StackRow role=\"title\">\n {hasBasic ? (\n <StyledClamp>{data.title}</StyledClamp>\n ) : (\n <div style={{ width: \"100%\" }}>\n <SkeletonLoader style={{ height: 14, width: \"92%\" }} />\n <SkeletonLoader\n style={{ height: 14, width: \"60%\", marginTop: 6 }}\n />\n </div>\n )}\n </StackRow>\n\n <StackRow role=\"custom\">\n <StyledChips>\n {hasFull ? (\n <>\n {data.kind ? (\n <StyledChip data-fixed>{data.kind}</StyledChip>\n ) : null}\n {data.duration ? (\n <StyledChip data-fixed>{data.duration}</StyledChip>\n ) : null}\n </>\n ) : (\n <SkeletonLoader\n style={{ height: 18, width: 96, borderRadius: 10 }}\n />\n )}\n </StyledChips>\n </StackRow>\n\n {status === \"stale\" ? (\n <StackRow role=\"meta\">\n <StaleStrip fetchedAt={fetchedAt} onReunfurl={reunfurl} />\n </StackRow>\n ) : null}\n </>\n );\n};\n\n/* The stale affordance — fetch time + a manual re-unfurl button. */\nconst StaleStrip = ({\n fetchedAt,\n onReunfurl,\n}: {\n fetchedAt: number | null;\n onReunfurl: () => void;\n}): ReactElement => (\n <StyledStaleStrip>\n <Typography as=\"span\" variant=\"Caption 1\" color=\"tertiary\">\n Preview may be out of date · fetched {formatFetchedAt(fetchedAt)}\n </Typography>\n <StyledReunfurl type=\"button\" onClick={onReunfurl}>\n <ArrowRefreshIcon />\n Re-unfurl\n </StyledReunfurl>\n </StyledStaleStrip>\n);\n\n/* ---- skeleton ---- */\n\n/* Mirrors the compact anatomy row for row (this is the `resolving` render at\n tier `url`), so a resolving link never reflows as it climbs the ladder. */\nexport const LinkSkeleton = (): ReactElement => (\n <>\n <Cover aspectRatio={COVER_RATIO}>\n <SkeletonLoader style={{ width: \"100%\", height: \"100%\" }} />\n </Cover>\n <StackRow role=\"custom\">\n <StyledDomainRow>\n <SkeletonLoader\n data-fixed\n style={{ width: 16, height: 16, borderRadius: 4 }}\n />\n <SkeletonLoader style={{ height: 10, width: \"40%\" }} />\n </StyledDomainRow>\n </StackRow>\n <StackRow role=\"title\">\n <div style={{ width: \"100%\" }}>\n <SkeletonLoader style={{ height: 14, width: \"92%\" }} />\n <SkeletonLoader style={{ height: 14, width: \"60%\", marginTop: 6 }} />\n </div>\n </StackRow>\n <StackRow role=\"custom\">\n <StyledChips>\n <SkeletonLoader style={{ height: 18, width: 96, borderRadius: 10 }} />\n </StyledChips>\n </StackRow>\n </>\n);\n\n/* ---- placeholder ---- */\n\nexport const LinkPlaceholder = (\n props: React.ButtonHTMLAttributes<HTMLButtonElement>\n): ReactElement => (\n <Placeholder icon={<InsertLinkIcon />} label=\"Add a link\" {...props} />\n);\n"],"mappings":";AAAA,OAAOA,KAAK,MAAwB,OAAO;AAE3C,OAAOC,MAAM,MAAM,mBAAmB;AAEtC,SACEC,gBAAgB,EAChBC,UAAU,EACVC,WAAW,EACXC,gBAAgB,EAChBC,aAAa,EACbC,eAAe,EACfC,WAAW,EACXC,WAAW,QACN,UAAU;AACjB,SAA2BC,eAAe,QAAQ,UAAU;AAC5D,SACEC,gBAAgB,EAChBC,cAAc,EACdC,mBAAmB,QACd,2BAA2B;AAClC,SAASC,cAAc,QAAQ,6BAA6B;AAC5D,SACEC,wBAAwB,IAAIC,WAAW,EACvCC,0BAA0B,EAC1BC,gBAAgB,IAAIC,KAAK,EACzBC,cAAc,IAAIC,QAAQ,QACrB,iCAAiC;AACxC,SAASC,KAAK,EAAEC,QAAQ,QAAQ,gCAAgC;AAChE,SAASC,UAAU,QAAQ,2CAA2C;;AAEtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAIA;AACA;AACA;;AAEA,MAAMC,eAAe,GAAGxB,MAAM,CAACyB,GAAG,CAAAC,UAAA;EAAAC,WAAA;EAAAC,WAAA;AAAA,gEAKjC;AAED,MAAMC,WAAW,GAAG7B,MAAM,CAACyB,GAAG,CAAAC,UAAA;EAAAC,WAAA;EAAAC,WAAA;AAAA,gEAK7B;;AAED;AACA,MAAME,gBAAgB,GAAG9B,MAAM,CAACyB,GAAG,CAAAC,UAAA;EAAAC,WAAA;EAAAC,WAAA;AAAA,+GAUlC;AAED,MAAMG,cAAc,GAAG/B,MAAM,CAACgC,MAAM,CAAAN,UAAA;EAAAC,WAAA;EAAAC,WAAA;AAAA,wVAsBnC;;AAED;AACA;AACA;AACA;AACA,MAAMK,cAAc,GAAGjC,MAAM,CAACoB,QAAQ,CAAC,CAAAM,UAAA;EAAAC,WAAA;EAAAC,WAAA;AAAA,sNAsBtC;AAED,MAAMM,WAAW,GAAGlC,MAAM,CAACgC,MAAM,CAAAN,UAAA;EAAAC,WAAA;EAAAC,WAAA;AAAA,kVAqBhC;;AAED;AACA,MAAMO,iBAAiB,GAAGnC,MAAM,CAACqB,KAAK,CAAC,CAAAK,UAAA;EAAAC,WAAA;EAAAC,WAAA;AAAA,6FAKtC;;AAED;AACA;AACA;;AAEA,MAAMQ,mBAAmB,GAAGpC,MAAM,CAACgC,MAAM,CAAAN,UAAA;EAAAC,WAAA;EAAAC,WAAA;AAAA,oRAexC;AAED,MAAMS,aAAa,GAAGC,IAAA;EAAA,IACpBC,OAAO,GAAAD,IAAA,CAAPC,OAAO;IACPC,QAAQ,GAAAF,IAAA,CAARE,QAAQ;EAAA,oBAKRzC,KAAA,CAAA0C,aAAA,CAACL,mBAAmB;IAClBM,IAAI,EAAC,QAAQ;IACb,kBAAU;IACVC,SAAS,EAAE3B,0BAA2B;IACtC,cAAW,sBAAsB;IACjC4B,OAAO,EAAEJ;EAAS,GAEjBD,OAAO,KAAK,SAAS,GAAG,UAAU,GAAG,WACnB,CAAC;AAAA,CACvB;;AAED;AACA;AACA;;AAQA,OAAO,MAAMM,QAAQ,GAAGC,KAAA,IAIW;EAAA,IAAAC,gBAAA,EAAAC,mBAAA;EAAA,IAHjCC,MAAM,GAAAH,KAAA,CAANG,MAAM;IAAAC,aAAA,GAAAJ,KAAA,CACNP,OAAO;IAAPA,OAAO,GAAAW,aAAA,cAAG,SAAS,GAAAA,aAAA;IACnBC,eAAe,GAAAL,KAAA,CAAfK,eAAe;EAEf,MAAQC,MAAM,GAA6CH,MAAM,CAAzDG,MAAM;IAAEC,IAAI,GAAuCJ,MAAM,CAAjDI,IAAI;IAAEC,IAAI,GAAiCL,MAAM,CAA3CK,IAAI;IAAEC,SAAS,GAAsBN,MAAM,CAArCM,SAAS;IAAEC,KAAK,GAAeP,MAAM,CAA1BO,KAAK;IAAEC,QAAQ,GAAKR,MAAM,CAAnBQ,QAAQ;;EAEtD;EACA,IAAIL,MAAM,KAAK,OAAO,EAAE;IACtB,oBACErD,KAAA,CAAA0C,aAAA,CAACR,cAAc;MAACyB,IAAI,EAAC,QAAQ;MAACC,SAAS,EAAC;IAAQ,gBAC9C5D,KAAA,CAAA0C,aAAA;MAAKE,SAAS,EAAC;IAAU,gBACvB5C,KAAA,CAAA0C,aAAA,CAAC7B,mBAAmB,MAAE,CAAC,eACvBb,KAAA,CAAA0C,aAAA,CAACnB,QAAQ;MAACsC,MAAM,EAAC,MAAM;MAACC,KAAK,EAAC;IAAU,GAAC,8BAE/B,CACP,CAAC,eACN9D,KAAA,CAAA0C,aAAA;MAAKE,SAAS,EAAC;IAAS,gBACtB5C,KAAA,CAAA0C,aAAA,CAACpC,aAAa;MAACyD,GAAG,EAAC,wBAAwB;MAAC;IAAU,CAAE,CAAC,eACzD/D,KAAA,CAAA0C,aAAA,CAACnB,QAAQ;MAACuC,KAAK,EAAC;IAAW,GAAEP,IAAI,CAACS,GAAc,CAC7C,CAAC,eACNhE,KAAA,CAAA0C,aAAA,CAACP,WAAW;MAACQ,IAAI,EAAC,QAAQ;MAACE,OAAO,EAAEY;IAAM,gBACxCzD,KAAA,CAAA0C,aAAA,CAAC/B,gBAAgB,MAAE,CAAC,eACpBX,KAAA,CAAA0C,aAAA,CAAClB,UAAU;MAACyC,EAAE,EAAC,MAAM;MAACC,OAAO,EAAC;IAAW,GAAC,OAE9B,CACD,CACC,CAAC;EAErB;EAEA,MAAMC,QAAQ,GAAGb,IAAI,KAAK,OAAO,IAAIA,IAAI,KAAK,MAAM;EACpD,MAAMc,OAAO,GAAGd,IAAI,KAAK,MAAM;EAC/B,MAAMe,MAAM,GAAGjB,eAAe,WAAfA,eAAe,GAAK,MAAMkB,SAAU;;EAEnD;EACA,IAAI9B,OAAO,KAAK,UAAU,EAAE;IAAA,IAAA+B,eAAA,EAAAC,kBAAA;IAC1B,oBACExE,KAAA,CAAA0C,aAAA,CAAA1C,KAAA,CAAAyE,QAAA,qBACEzE,KAAA,CAAA0C,aAAA,CAACvB,KAAK;MACJuD,WAAW,EAAExE,gBAAiB;MAC9ByE,UAAU,EAAEP,OAAO,IAAIb,IAAI,CAACqB,QAAQ,GAAGpE,WAAW,GAAG8D,SAAU;MAC/DO,YAAY,EAAEtE,eAAe,CAAC;IAAE,GAE/B6D,OAAO,gBACNpE,KAAA,CAAA0C,aAAA,CAACrC,gBAAgB;MAACyE,MAAM,GAAAP,eAAA,GAAEhB,IAAI,CAACwB,SAAS,YAAAR,eAAA,GAAI;IAAU,CAAE,CAAC,gBAEzDvE,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;MAACkE,KAAK,EAAE;QAAEC,KAAK,EAAE,MAAM;QAAEC,MAAM,EAAE;MAAO;IAAE,CAAE,CAExD,CAAC,eACRlF,KAAA,CAAA0C,aAAA,CAACrB,QAAQ;MACPsC,IAAI,EAAC,QAAQ;MACbC,SAAS,EAAC,QAAQ;MAClBuB,UAAU,EAAC;IAAwB,gBAEnCnF,KAAA,CAAA0C,aAAA,CAACjB,eAAe,QACb0C,QAAQ,gBACPnE,KAAA,CAAA0C,aAAA,CAACpC,aAAa;MAACyD,GAAG,GAAAS,kBAAA,GAAEjB,IAAI,CAAC6B,YAAY,YAAAZ,kBAAA,GAAI,SAAU;MAAC;IAAU,CAAE,CAAC,gBAEjExE,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;MACb,kBAAU;MACVkE,KAAK,EAAE;QAAEC,KAAK,EAAE,EAAE;QAAEC,MAAM,EAAE,EAAE;QAAEG,YAAY,EAAE;MAAE;IAAE,CACnD,CACF,EACAlB,QAAQ,gBACPnE,KAAA,CAAA0C,aAAA,CAACnB,QAAQ;MAACuC,KAAK,EAAC;IAAU,GAAEP,IAAI,CAAC+B,MAAiB,CAAC,gBAEnDtF,KAAA,CAAA0C,aAAA,CAACnB,QAAQ;MAACuC,KAAK,EAAC;IAAU,GAAEP,IAAI,CAACS,GAAc,CAChD,eACDhE,KAAA,CAAA0C,aAAA;MAAMsC,KAAK,EAAE;QAAEO,IAAI,EAAE;MAAW;IAAE,CAAE,CAAC,eACrCvF,KAAA,CAAA0C,aAAA,CAACJ,aAAa;MAACE,OAAO,EAAEA,OAAQ;MAACC,QAAQ,EAAE4B;IAAO,CAAE,CACrC,CAAC,EACjBF,QAAQ,gBACPnE,KAAA,CAAA0C,aAAA,CAACN,iBAAiB;MAACyB,MAAM,EAAC;IAAM,GAAEN,IAAI,CAACiC,KAAyB,CAAC,gBAEjExF,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;MAACkE,KAAK,EAAE;QAAEE,MAAM,EAAE,EAAE;QAAED,KAAK,EAAE;MAAM;IAAE,CAAE,CACvD,EACAb,OAAO,gBACNpE,KAAA,CAAA0C,aAAA,CAACnB,QAAQ;MAACuC,KAAK,EAAC;IAAU,GAAEP,IAAI,CAACkC,WAAsB,CAAC,gBAExDzF,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;MAACkE,KAAK,EAAE;QAAEE,MAAM,EAAE,EAAE;QAAED,KAAK,EAAE;MAAM;IAAE,CAAE,CAEhD,CAAC,EACV5B,MAAM,KAAK,OAAO,gBACjBrD,KAAA,CAAA0C,aAAA,CAACrB,QAAQ;MAACsC,IAAI,EAAC;IAAM,gBACnB3D,KAAA,CAAA0C,aAAA,CAACgD,UAAU;MAAClC,SAAS,EAAEA,SAAU;MAACmC,UAAU,EAAEjC;IAAS,CAAE,CACjD,CAAC,GACT,IACJ,CAAC;EAEP;;EAEA;EACA,oBACE1D,KAAA,CAAA0C,aAAA,CAAA1C,KAAA,CAAAyE,QAAA,qBACEzE,KAAA,CAAA0C,aAAA,CAACvB,KAAK;IACJuD,WAAW,EAAE1D,WAAY;IACzB2D,UAAU,EAAEP,OAAO,IAAIb,IAAI,CAACqB,QAAQ,GAAGpE,WAAW,GAAG8D;EAAU,GAE9DF,OAAO,gBACNpE,KAAA,CAAA0C,aAAA,CAACrC,gBAAgB;IAACyE,MAAM,GAAA9B,gBAAA,GAAEO,IAAI,CAACwB,SAAS,YAAA/B,gBAAA,GAAI;EAAU,CAAE,CAAC,gBAEzDhD,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;IAACkE,KAAK,EAAE;MAAEC,KAAK,EAAE,MAAM;MAAEC,MAAM,EAAE;IAAO;EAAE,CAAE,CAExD,CAAC,eAERlF,KAAA,CAAA0C,aAAA,CAACrB,QAAQ;IAACsC,IAAI,EAAC;EAAQ,gBACrB3D,KAAA,CAAA0C,aAAA,CAACjB,eAAe,QACb0C,QAAQ,gBACPnE,KAAA,CAAA0C,aAAA,CAACpC,aAAa;IAACyD,GAAG,GAAAd,mBAAA,GAAEM,IAAI,CAAC6B,YAAY,YAAAnC,mBAAA,GAAI,SAAU;IAAC;EAAU,CAAE,CAAC,gBAEjEjD,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;IACb,kBAAU;IACVkE,KAAK,EAAE;MAAEC,KAAK,EAAE,EAAE;MAAEC,MAAM,EAAE,EAAE;MAAEG,YAAY,EAAE;IAAE;EAAE,CACnD,CACF,EACAlB,QAAQ,gBACPnE,KAAA,CAAA0C,aAAA,CAACnB,QAAQ;IAACuC,KAAK,EAAC;EAAU,GAAEP,IAAI,CAAC+B,MAAiB,CAAC,gBAEnDtF,KAAA,CAAA0C,aAAA,CAACnB,QAAQ;IAACuC,KAAK,EAAC;EAAU,GAAEP,IAAI,CAACS,GAAc,CAChD,eACDhE,KAAA,CAAA0C,aAAA;IAAMsC,KAAK,EAAE;MAAEO,IAAI,EAAE;IAAW;EAAE,CAAE,CAAC,eACrCvF,KAAA,CAAA0C,aAAA,CAACJ,aAAa;IAACE,OAAO,EAAEA,OAAQ;IAACC,QAAQ,EAAE4B;EAAO,CAAE,CACrC,CACT,CAAC,eAEXrE,KAAA,CAAA0C,aAAA,CAACrB,QAAQ;IAACsC,IAAI,EAAC;EAAO,GACnBQ,QAAQ,gBACPnE,KAAA,CAAA0C,aAAA,CAACtC,WAAW,QAAEmD,IAAI,CAACiC,KAAmB,CAAC,gBAEvCxF,KAAA,CAAA0C,aAAA;IAAKsC,KAAK,EAAE;MAAEC,KAAK,EAAE;IAAO;EAAE,gBAC5BjF,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;IAACkE,KAAK,EAAE;MAAEE,MAAM,EAAE,EAAE;MAAED,KAAK,EAAE;IAAM;EAAE,CAAE,CAAC,eACvDjF,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;IACbkE,KAAK,EAAE;MAAEE,MAAM,EAAE,EAAE;MAAED,KAAK,EAAE,KAAK;MAAEW,SAAS,EAAE;IAAE;EAAE,CACnD,CACE,CAEC,CAAC,eAEX5F,KAAA,CAAA0C,aAAA,CAACrB,QAAQ;IAACsC,IAAI,EAAC;EAAQ,gBACrB3D,KAAA,CAAA0C,aAAA,CAACZ,WAAW,QACTsC,OAAO,gBACNpE,KAAA,CAAA0C,aAAA,CAAA1C,KAAA,CAAAyE,QAAA,QACGlB,IAAI,CAACsC,IAAI,gBACR7F,KAAA,CAAA0C,aAAA,CAACvC,UAAU;IAAC;EAAU,GAAEoD,IAAI,CAACsC,IAAiB,CAAC,GAC7C,IAAI,EACPtC,IAAI,CAACuC,QAAQ,gBACZ9F,KAAA,CAAA0C,aAAA,CAACvC,UAAU;IAAC;EAAU,GAAEoD,IAAI,CAACuC,QAAqB,CAAC,GACjD,IACJ,CAAC,gBAEH9F,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;IACbkE,KAAK,EAAE;MAAEE,MAAM,EAAE,EAAE;MAAED,KAAK,EAAE,EAAE;MAAEI,YAAY,EAAE;IAAG;EAAE,CACpD,CAEQ,CACL,CAAC,EAEVhC,MAAM,KAAK,OAAO,gBACjBrD,KAAA,CAAA0C,aAAA,CAACrB,QAAQ;IAACsC,IAAI,EAAC;EAAM,gBACnB3D,KAAA,CAAA0C,aAAA,CAACgD,UAAU;IAAClC,SAAS,EAAEA,SAAU;IAACmC,UAAU,EAAEjC;EAAS,CAAE,CACjD,CAAC,GACT,IACJ,CAAC;AAEP,CAAC;;AAED;AACA,MAAMgC,UAAU,GAAGK,KAAA;EAAA,IACjBvC,SAAS,GAAAuC,KAAA,CAATvC,SAAS;IACTmC,UAAU,GAAAI,KAAA,CAAVJ,UAAU;EAAA,oBAKV3F,KAAA,CAAA0C,aAAA,CAACX,gBAAgB,qBACf/B,KAAA,CAAA0C,aAAA,CAAClB,UAAU;IAACyC,EAAE,EAAC,MAAM;IAACC,OAAO,EAAC,WAAW;IAACJ,KAAK,EAAC;EAAU,GAAC,0CACpB,EAACpD,eAAe,CAAC8C,SAAS,CACrD,CAAC,eACbxD,KAAA,CAAA0C,aAAA,CAACV,cAAc;IAACW,IAAI,EAAC,QAAQ;IAACE,OAAO,EAAE8C;EAAW,gBAChD3F,KAAA,CAAA0C,aAAA,CAAC/B,gBAAgB,MAAE,CAAC,aAEN,CACA,CAAC;AAAA,CACpB;;AAED;;AAEA;AACA;AACA,OAAO,MAAMqF,YAAY,GAAGA,CAAA,kBAC1BhG,KAAA,CAAA0C,aAAA,CAAA1C,KAAA,CAAAyE,QAAA,qBACEzE,KAAA,CAAA0C,aAAA,CAACvB,KAAK;EAACuD,WAAW,EAAE1D;AAAY,gBAC9BhB,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;EAACkE,KAAK,EAAE;IAAEC,KAAK,EAAE,MAAM;IAAEC,MAAM,EAAE;EAAO;AAAE,CAAE,CACtD,CAAC,eACRlF,KAAA,CAAA0C,aAAA,CAACrB,QAAQ;EAACsC,IAAI,EAAC;AAAQ,gBACrB3D,KAAA,CAAA0C,aAAA,CAACjB,eAAe,qBACdzB,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;EACb,kBAAU;EACVkE,KAAK,EAAE;IAAEC,KAAK,EAAE,EAAE;IAAEC,MAAM,EAAE,EAAE;IAAEG,YAAY,EAAE;EAAE;AAAE,CACnD,CAAC,eACFrF,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;EAACkE,KAAK,EAAE;IAAEE,MAAM,EAAE,EAAE;IAAED,KAAK,EAAE;EAAM;AAAE,CAAE,CACvC,CACT,CAAC,eACXjF,KAAA,CAAA0C,aAAA,CAACrB,QAAQ;EAACsC,IAAI,EAAC;AAAO,gBACpB3D,KAAA,CAAA0C,aAAA;EAAKsC,KAAK,EAAE;IAAEC,KAAK,EAAE;EAAO;AAAE,gBAC5BjF,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;EAACkE,KAAK,EAAE;IAAEE,MAAM,EAAE,EAAE;IAAED,KAAK,EAAE;EAAM;AAAE,CAAE,CAAC,eACvDjF,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;EAACkE,KAAK,EAAE;IAAEE,MAAM,EAAE,EAAE;IAAED,KAAK,EAAE,KAAK;IAAEW,SAAS,EAAE;EAAE;AAAE,CAAE,CACjE,CACG,CAAC,eACX5F,KAAA,CAAA0C,aAAA,CAACrB,QAAQ;EAACsC,IAAI,EAAC;AAAQ,gBACrB3D,KAAA,CAAA0C,aAAA,CAACZ,WAAW,qBACV9B,KAAA,CAAA0C,aAAA,CAAC5B,cAAc;EAACkE,KAAK,EAAE;IAAEE,MAAM,EAAE,EAAE;IAAED,KAAK,EAAE,EAAE;IAAEI,YAAY,EAAE;EAAG;AAAE,CAAE,CAC1D,CACL,CACV,CACH;;AAED;;AAEA,OAAO,MAAMY,eAAe,GAC1BC,KAAoD,iBAEpDlG,KAAA,CAAA0C,aAAA,CAACjC,WAAW,EAAA0F,QAAA;EAACC,IAAI,eAAEpG,KAAA,CAAA0C,aAAA,CAAC9B,cAAc,MAAE,CAAE;EAACyF,KAAK,EAAC;AAAY,GAAKH,KAAK,CAAG,CACvE","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"LinkCard.js","names":["React","styled","COVER_RATIO_HERO","StyledChip","StyledClamp","StyledColorCover","StyledFavicon","coverManagement","playControl","Placeholder","formatFetchedAt","ArrowRefreshIcon","InsertLinkIcon","WarningTriangleIcon","SkeletonLoader","STACKED_CARD_COVER_RATIO","COVER_RATIO","STACKED_CARD_CONTROL_CLASS","StackedCardCover","Cover","StackedCardRow","StackRow","Body2","Caption1","Typography","CONTROL_FONT","StyledDomainRow","div","withConfig","displayName","componentId","StyledChips","StyledStaleStrip","StyledReunfurl","button","StyledErrorRow","StyledRetry","resolvedCover","data","_data$heroColor","heroSrc","createElement","src","alt","$color","heroColor","StyledFooterTitle","StyledDisplayToggle","DisplayToggle","_ref","display","onToggle","type","className","onClick","LinkCard","_ref2","_data$faviconColor2","unfurl","_ref2$display","onToggleDisplay","status","tier","fetchedAt","retry","reunfurl","role","direction","weight","color","$bg","url","as","variant","hasBasic","hasFull","toggle","_data$faviconColor","Fragment","aspectRatio","centerSlot","playable","undefined","topRightSlot","style","width","height","background","faviconColor","borderRadius","domain","flex","title","description","StaleStrip","onReunfurl","marginTop","kind","duration","_ref3","LinkSkeleton","LinkPlaceholder","props","_extends","icon","label"],"sources":["../../../../../src/presentation/stackedCard/content/LinkCard.tsx"],"sourcesContent":["import React, { ReactElement } from \"react\";\n\nimport styled from \"styled-components\";\n\nimport {\n COVER_RATIO_HERO,\n StyledChip,\n StyledClamp,\n StyledColorCover,\n StyledFavicon,\n coverManagement,\n playControl,\n Placeholder,\n} from \"./shared\";\nimport { UnfurlController, UnfurlData, formatFetchedAt } from \"./unfurl\";\nimport {\n ArrowRefreshIcon,\n InsertLinkIcon,\n WarningTriangleIcon,\n} from \"../../../components/Icons\";\nimport { SkeletonLoader } from \"../../../components/Loaders\";\nimport {\n STACKED_CARD_COVER_RATIO as COVER_RATIO,\n STACKED_CARD_CONTROL_CLASS,\n StackedCardCover as Cover,\n StackedCardRow as StackRow,\n} from \"../../../components/StackedCard\";\nimport { Body2, Caption1 } from \"../../../components/Typography\";\nimport { Typography } from \"../../../components/Typography/Typography\";\n\n/* There is no global CSS reset in this Storybook, so a raw <button> falls back\n to the UA font (Arial) instead of the DS stack. Every button below is text, so\n they all need it. */\nconst CONTROL_FONT = `-apple-system, BlinkMacSystemFont, \"Roboto\",\n \"Helvetica Neue\", Arial, sans-serif`;\n\n/**\n * LinkCard — a link preview as a LIFECYCLE, not two static layouts.\n *\n * Data climbs a progressive ladder (url → basic → full); the anatomy is\n * CONSTANT at every tier, so each slot swaps a skeleton for real content in\n * place and the card never reflows on upgrade. Four statuses layer on top:\n * resolving — climbing the ladder, aspect + rows reserved by skeletons\n * resolved — the full card\n * stale — resolved, but past its cache window: shows `fetchedAt` and a\n * re-unfurl affordance\n * error — the unfurl failed: favicon + raw URL + retry, NO media\n *\n * Compact ↔ expanded is a user-switchable DISPLAY LEVEL on the same link\n * entity (the data lives in the controller, so switching never refetches or\n * loses it) — not two separate card types.\n */\n\nexport type LinkDisplay = \"compact\" | \"expanded\";\n\n/* ------------------------------------------------------------------ */\n/* Small building blocks */\n/* ------------------------------------------------------------------ */\n\nconst StyledDomainRow = styled.div`\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 16px;\n`;\n\nconst StyledChips = styled.div`\n display: flex;\n align-items: center;\n gap: 6px;\n min-height: 18px;\n`;\n\n/* The stale strip — a re-unfurl affordance with the fetch time. */\nconst StyledStaleStrip = styled.div`\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--color-theme-600);\n\n > span {\n flex: 1 1 auto;\n min-width: 0;\n }\n`;\n\nconst StyledReunfurl = styled.button`\n display: inline-flex;\n align-items: center;\n gap: 4px;\n flex: 0 0 auto;\n padding: 3px 8px;\n border: 1px solid var(--border-primary);\n border-radius: 6px;\n background: var(--page-paper-main);\n color: var(--color-theme-800);\n font-family: ${CONTROL_FONT};\n font-size: 11px;\n cursor: pointer;\n\n svg {\n width: 12px;\n height: 12px;\n }\n\n &:hover {\n background: var(--color-theme-200);\n border-color: var(--sc-selection-ring);\n }\n`;\n\n/* The error body — favicon + raw URL + retry, no media (per spec §5). It is a\n column row like any other: the padding comes from the role, so the error\n state lines up with the states it replaces instead of setting its own inset.\n Only the gap is widened — three stacked blocks, not four text lines. */\nconst StyledErrorRow = styled(StackRow)`\n gap: 10px;\n\n .err-head {\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--red-alert);\n }\n\n .err-head svg {\n width: 16px;\n height: 16px;\n flex: 0 0 auto;\n }\n\n .err-url {\n display: flex;\n align-items: center;\n gap: 8px;\n word-break: break-all;\n }\n`;\n\nconst StyledRetry = styled.button`\n align-self: flex-start;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 10px;\n border: 1px solid var(--border-primary);\n border-radius: 6px;\n background: var(--page-paper-main);\n color: var(--color-theme-800);\n font-family: ${CONTROL_FONT};\n cursor: pointer;\n\n svg {\n width: 14px;\n height: 14px;\n }\n\n &:hover {\n background: var(--color-theme-200);\n border-color: var(--sc-selection-ring);\n }\n`;\n\n/* The resolved cover. A production unfurl stores the OpenGraph image, so when\n the ladder returns one we render a real <img> (the Cover fill already gives\n it `object-fit: cover`); the fill colour is the fallback for links that carry\n no image at all. */\nconst resolvedCover = (data: UnfurlData): ReactElement =>\n data.heroSrc ? (\n <img src={data.heroSrc} alt=\"\" />\n ) : (\n <StyledColorCover $color={data.heroColor ?? \"#1D9E75\"} />\n );\n\n/* The expanded footer band — tinted, holds the title + domain under the hero. */\nconst StyledFooterTitle = styled(Body2)`\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n`;\n\n/* ------------------------------------------------------------------ */\n/* The display-level switch — lives in the entity \"…\" slot */\n/* ------------------------------------------------------------------ */\n\nconst StyledDisplayToggle = styled.button`\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border: 1px solid var(--border-primary);\n border-radius: 10px;\n background: var(--color-theme-200);\n color: var(--color-theme-700);\n font-family: ${CONTROL_FONT};\n font-size: 11px;\n cursor: pointer;\n white-space: nowrap;\n\n &:hover {\n background: var(--color-theme-300);\n }\n`;\n\nconst DisplayToggle = ({\n display,\n onToggle,\n}: {\n display: LinkDisplay;\n onToggle: () => void;\n}): ReactElement => (\n <StyledDisplayToggle\n type=\"button\"\n data-fixed\n className={STACKED_CARD_CONTROL_CLASS}\n aria-label=\"Switch display level\"\n onClick={onToggle}\n >\n {display === \"compact\" ? \"Expand ▾\" : \"Compact ▴\"}\n </StyledDisplayToggle>\n);\n\n/* ------------------------------------------------------------------ */\n/* LinkCard */\n/* ------------------------------------------------------------------ */\n\nexport interface LinkCardProps {\n unfurl: UnfurlController;\n display?: LinkDisplay;\n onToggleDisplay?: () => void;\n}\n\nexport const LinkCard = ({\n unfurl,\n display = \"compact\",\n onToggleDisplay,\n}: LinkCardProps): ReactElement => {\n const { status, tier, data, fetchedAt, retry, reunfurl } = unfurl;\n\n // ── Error: favicon + raw URL + retry, no media ──────────────────\n if (status === \"error\") {\n return (\n <StyledErrorRow role=\"custom\" direction=\"column\">\n <div className=\"err-head\">\n <WarningTriangleIcon />\n <Caption1 weight=\"bold\" color=\"tertiary\">\n Couldn’t load a preview\n </Caption1>\n </div>\n <div className=\"err-url\">\n <StyledFavicon $bg=\"var(--color-theme-400)\" data-fixed />\n <Caption1 color=\"secondary\">{data.url}</Caption1>\n </div>\n <StyledRetry type=\"button\" onClick={retry}>\n <ArrowRefreshIcon />\n <Typography as=\"span\" variant=\"Caption 1\">\n Retry\n </Typography>\n </StyledRetry>\n </StyledErrorRow>\n );\n }\n\n const hasBasic = tier === \"basic\" || tier === \"full\";\n const hasFull = tier === \"full\";\n /* The display level belongs to the host, so the switch only appears when a\n host actually owns one. A surface that fixes the card at one level (the\n whiteboard pins it to expanded) gets no dead control. */\n const toggle = onToggleDisplay ? (\n <DisplayToggle display={display} onToggle={onToggleDisplay} />\n ) : null;\n\n // ── Expanded: hero + tinted footer band (title + domain) ────────\n if (display === \"expanded\") {\n return (\n <>\n <Cover\n aspectRatio={COVER_RATIO_HERO}\n centerSlot={hasFull && data.playable ? playControl : undefined}\n topRightSlot={coverManagement()}\n >\n {hasFull ? (\n resolvedCover(data)\n ) : (\n <SkeletonLoader style={{ width: \"100%\", height: \"100%\" }} />\n )}\n </Cover>\n <StackRow\n role=\"footer\"\n direction=\"column\"\n background=\"var(--color-theme-200)\"\n >\n <StyledDomainRow>\n {hasBasic ? (\n <StyledFavicon $bg={data.faviconColor ?? \"#0F6E56\"} data-fixed />\n ) : (\n <SkeletonLoader\n data-fixed\n style={{ width: 16, height: 16, borderRadius: 4 }}\n />\n )}\n {hasBasic ? (\n <Caption1 color=\"tertiary\">{data.domain}</Caption1>\n ) : (\n <Caption1 color=\"tertiary\">{data.url}</Caption1>\n )}\n <span style={{ flex: \"1 1 auto\" }} />\n {toggle}\n </StyledDomainRow>\n {hasBasic ? (\n <StyledFooterTitle weight=\"bold\">{data.title}</StyledFooterTitle>\n ) : (\n <SkeletonLoader style={{ height: 14, width: \"90%\" }} />\n )}\n {hasFull ? (\n <Caption1 color=\"tertiary\">{data.description}</Caption1>\n ) : (\n <SkeletonLoader style={{ height: 10, width: \"70%\" }} />\n )}\n </StackRow>\n {status === \"stale\" ? (\n <StackRow role=\"meta\">\n <StaleStrip fetchedAt={fetchedAt} onReunfurl={reunfurl} />\n </StackRow>\n ) : null}\n </>\n );\n }\n\n // ── Compact: cover + favicon/domain + title + chips ─────────────\n return (\n <>\n <Cover\n aspectRatio={COVER_RATIO}\n centerSlot={hasFull && data.playable ? playControl : undefined}\n >\n {hasFull ? (\n resolvedCover(data)\n ) : (\n <SkeletonLoader style={{ width: \"100%\", height: \"100%\" }} />\n )}\n </Cover>\n\n <StackRow role=\"custom\">\n <StyledDomainRow>\n {hasBasic ? (\n <StyledFavicon $bg={data.faviconColor ?? \"#0F6E56\"} data-fixed />\n ) : (\n <SkeletonLoader\n data-fixed\n style={{ width: 16, height: 16, borderRadius: 4 }}\n />\n )}\n {hasBasic ? (\n <Caption1 color=\"tertiary\">{data.domain}</Caption1>\n ) : (\n <Caption1 color=\"tertiary\">{data.url}</Caption1>\n )}\n <span style={{ flex: \"1 1 auto\" }} />\n {toggle}\n </StyledDomainRow>\n </StackRow>\n\n <StackRow role=\"title\">\n {hasBasic ? (\n <StyledClamp>{data.title}</StyledClamp>\n ) : (\n <div style={{ width: \"100%\" }}>\n <SkeletonLoader style={{ height: 14, width: \"92%\" }} />\n <SkeletonLoader\n style={{ height: 14, width: \"60%\", marginTop: 6 }}\n />\n </div>\n )}\n </StackRow>\n\n <StackRow role=\"custom\">\n <StyledChips>\n {hasFull ? (\n <>\n {data.kind ? (\n <StyledChip data-fixed>{data.kind}</StyledChip>\n ) : null}\n {data.duration ? (\n <StyledChip data-fixed>{data.duration}</StyledChip>\n ) : null}\n </>\n ) : (\n <SkeletonLoader\n style={{ height: 18, width: 96, borderRadius: 10 }}\n />\n )}\n </StyledChips>\n </StackRow>\n\n {status === \"stale\" ? (\n <StackRow role=\"meta\">\n <StaleStrip fetchedAt={fetchedAt} onReunfurl={reunfurl} />\n </StackRow>\n ) : null}\n </>\n );\n};\n\n/* The stale affordance — fetch time + a manual re-unfurl button. */\nconst StaleStrip = ({\n fetchedAt,\n onReunfurl,\n}: {\n fetchedAt: number | null;\n onReunfurl: () => void;\n}): ReactElement => (\n <StyledStaleStrip>\n <Typography as=\"span\" variant=\"Caption 1\" color=\"tertiary\">\n Preview may be out of date · fetched {formatFetchedAt(fetchedAt)}\n </Typography>\n <StyledReunfurl type=\"button\" onClick={onReunfurl}>\n <ArrowRefreshIcon />\n Re-unfurl\n </StyledReunfurl>\n </StyledStaleStrip>\n);\n\n/* ---- skeleton ---- */\n\n/* Mirrors the compact anatomy row for row (this is the `resolving` render at\n tier `url`), so a resolving link never reflows as it climbs the ladder. */\nexport const LinkSkeleton = (): ReactElement => (\n <>\n <Cover aspectRatio={COVER_RATIO}>\n <SkeletonLoader style={{ width: \"100%\", height: \"100%\" }} />\n </Cover>\n <StackRow role=\"custom\">\n <StyledDomainRow>\n <SkeletonLoader\n data-fixed\n style={{ width: 16, height: 16, borderRadius: 4 }}\n />\n <SkeletonLoader style={{ height: 10, width: \"40%\" }} />\n </StyledDomainRow>\n </StackRow>\n <StackRow role=\"title\">\n <div style={{ width: \"100%\" }}>\n <SkeletonLoader style={{ height: 14, width: \"92%\" }} />\n <SkeletonLoader style={{ height: 14, width: \"60%\", marginTop: 6 }} />\n </div>\n </StackRow>\n <StackRow role=\"custom\">\n <StyledChips>\n <SkeletonLoader style={{ height: 18, width: 96, borderRadius: 10 }} />\n </StyledChips>\n </StackRow>\n </>\n);\n\n/* ---- placeholder ---- */\n\nexport const LinkPlaceholder = (\n props: React.ButtonHTMLAttributes<HTMLButtonElement>\n): ReactElement => (\n <Placeholder icon={<InsertLinkIcon />} label=\"Add a link\" {...props} />\n);\n"],"mappings":"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","ignoreList":[]}
|