@estiva-app/ui 0.71.0 → 0.72.0-widgets2.0
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/ReferenceMenu.d.ts.map +1 -1
- package/dist/editor.js.map +2 -2
- package/dist/widgets-2/fixtures.d.ts +100 -0
- package/dist/widgets-2/fixtures.d.ts.map +1 -0
- package/dist/widgets-2/proposed.d.ts +130 -0
- package/dist/widgets-2/proposed.d.ts.map +1 -0
- package/dist/widgets-2.d.ts +11 -0
- package/dist/widgets-2.d.ts.map +1 -0
- package/dist/widgets-2.js +418 -0
- package/dist/widgets-2.js.map +7 -0
- package/package.json +5 -1
- package/registry.json +1 -1
- package/src/ReferenceMenu.tsx +2 -0
- package/src/gates/gates.test.ts +2 -1
- package/src/widgets-2/fixtures.ts +159 -0
- package/src/widgets-2/proposed.tsx +596 -0
- package/src/widgets-2.ts +10 -0
- package/stories/widgets-2/ReadMe.mdx +60 -0
- package/stories/widgets-2/Widgets.stories.tsx +504 -0
- package/stories/widgets-2/today.tsx +352 -0
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
// src/widgets-2/proposed.tsx
|
|
2
|
+
import { IconCircleCheck, IconCircleDashed, IconCircleHalf2, IconCircleX, IconFileText, IconMessage2, IconPaperclip } from "@tabler/icons-react";
|
|
3
|
+
import { Avatar } from "@estiva-app/ui";
|
|
4
|
+
import { AvatarGroup } from "@estiva-app/ui";
|
|
5
|
+
import { Card } from "@estiva-app/ui";
|
|
6
|
+
import { cn } from "@estiva-app/ui";
|
|
7
|
+
import { InlineChip } from "@estiva-app/ui";
|
|
8
|
+
import { KindIcon } from "@estiva-app/ui";
|
|
9
|
+
import { Link } from "@estiva-app/ui";
|
|
10
|
+
import { MenuPanel } from "@estiva-app/ui";
|
|
11
|
+
import { PreviewCard } from "@estiva-app/ui";
|
|
12
|
+
import { Select } from "@estiva-app/ui";
|
|
13
|
+
import { SkeletonBar } from "@estiva-app/ui";
|
|
14
|
+
import { UnreadDot } from "@estiva-app/ui";
|
|
15
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
var HREF = "#";
|
|
17
|
+
var noop = () => {
|
|
18
|
+
};
|
|
19
|
+
var STATUS_ICON = {
|
|
20
|
+
neutral: { Icon: IconCircleDashed, tone: "text-text-secondary" },
|
|
21
|
+
blue: { Icon: IconCircleHalf2, tone: "text-info-default" },
|
|
22
|
+
green: { Icon: IconCircleCheck, tone: "text-success-default" },
|
|
23
|
+
muted: { Icon: IconCircleX, tone: "text-text-muted" }
|
|
24
|
+
};
|
|
25
|
+
function StatusMark({ status }) {
|
|
26
|
+
return /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center", title: status.label, children: [
|
|
27
|
+
/* @__PURE__ */ jsx(StatusIcon, { status }),
|
|
28
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: status.label })
|
|
29
|
+
] });
|
|
30
|
+
}
|
|
31
|
+
function StatusIcon({ status }) {
|
|
32
|
+
const { Icon, tone } = STATUS_ICON[status.colour];
|
|
33
|
+
return /* @__PURE__ */ jsx(Icon, { size: 14, stroke: 1.5, className: cn("shrink-0", tone), "aria-hidden": true });
|
|
34
|
+
}
|
|
35
|
+
function ThingIcon({ kind, size = 16, tone = "secondary" }) {
|
|
36
|
+
if (kind === "page") return /* @__PURE__ */ jsx(IconFileText, { size, stroke: 1.5, className: cn("shrink-0", tone === "secondary" && "text-text-secondary"), "aria-hidden": true });
|
|
37
|
+
return /* @__PURE__ */ jsx(KindIcon, { kind, size, tone });
|
|
38
|
+
}
|
|
39
|
+
function Key({ children }) {
|
|
40
|
+
return /* @__PURE__ */ jsx("span", { className: "shrink-0 text-caption tabular-nums text-text-muted", children });
|
|
41
|
+
}
|
|
42
|
+
function ProgressRing({ done, total }) {
|
|
43
|
+
const size = 16;
|
|
44
|
+
const stroke = 2;
|
|
45
|
+
const r = (size - stroke) / 2;
|
|
46
|
+
const c = 2 * Math.PI * r;
|
|
47
|
+
return /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-1 text-caption tabular-nums text-text-secondary", title: `${done} of ${total} done`, children: [
|
|
48
|
+
/* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, className: "shrink-0 -rotate-90", "aria-hidden": true, children: [
|
|
49
|
+
/* @__PURE__ */ jsx("circle", { cx: size / 2, cy: size / 2, r, fill: "none", strokeWidth: stroke, className: "stroke-border-default" }),
|
|
50
|
+
/* @__PURE__ */ jsx("circle", { cx: size / 2, cy: size / 2, r, fill: "none", strokeWidth: stroke, strokeLinecap: "round", strokeDasharray: `${c * done / total} ${c}`, className: "stroke-success-default" })
|
|
51
|
+
] }),
|
|
52
|
+
done,
|
|
53
|
+
"/",
|
|
54
|
+
total
|
|
55
|
+
] });
|
|
56
|
+
}
|
|
57
|
+
var CONVERSATION_HREF = "#conversation";
|
|
58
|
+
function Comments({ count, unread = false, noun = "comments" }) {
|
|
59
|
+
return /* @__PURE__ */ jsxs(
|
|
60
|
+
Link,
|
|
61
|
+
{
|
|
62
|
+
href: CONVERSATION_HREF,
|
|
63
|
+
variant: "plain",
|
|
64
|
+
className: cn(
|
|
65
|
+
"relative z-10 -mx-1 inline-flex shrink-0 items-center gap-1 rounded-sm px-1 text-caption tabular-nums hover:bg-bg-active",
|
|
66
|
+
unread ? "font-medium text-text-primary" : "text-text-secondary"
|
|
67
|
+
),
|
|
68
|
+
children: [
|
|
69
|
+
/* @__PURE__ */ jsx(IconMessage2, { size: 14, stroke: 1.5, "aria-hidden": true }),
|
|
70
|
+
count,
|
|
71
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: unread ? `${noun}, unread \u2014 open the conversation` : `${noun} \u2014 open the conversation` }),
|
|
72
|
+
unread && /* @__PURE__ */ jsx(UnreadDot, { className: "h-auto w-auto" })
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
function Conversations({ thing }) {
|
|
78
|
+
return /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-2", children: [
|
|
79
|
+
/* @__PURE__ */ jsx("span", { className: "text-caption text-text-secondary", children: thing.updated }),
|
|
80
|
+
/* @__PURE__ */ jsx(Comments, { count: thing.conversations ?? 0, unread: thing.unread, noun: "conversations" })
|
|
81
|
+
] });
|
|
82
|
+
}
|
|
83
|
+
var people = (names = []) => names.map((name) => ({ name }));
|
|
84
|
+
function Pickers({ thing, readOnly = false }) {
|
|
85
|
+
if (!thing.status) return null;
|
|
86
|
+
if (readOnly) {
|
|
87
|
+
return /* @__PURE__ */ jsxs("span", { className: "flex h-6 min-w-0 items-center gap-3 text-caption text-text-secondary", children: [
|
|
88
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-1", children: [
|
|
89
|
+
/* @__PURE__ */ jsx(StatusIcon, { status: thing.status }),
|
|
90
|
+
thing.status.label
|
|
91
|
+
] }),
|
|
92
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex min-w-0 items-center gap-1", children: [
|
|
93
|
+
/* @__PURE__ */ jsx(Avatar, { name: thing.assignee, size: 16 }),
|
|
94
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: thing.assignee ?? "Unassigned" })
|
|
95
|
+
] })
|
|
96
|
+
] });
|
|
97
|
+
}
|
|
98
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
99
|
+
/* @__PURE__ */ jsx(Select, { size: "small", className: "w-auto", value: "s", onChange: noop, ariaLabel: "Status", options: [{ value: "s", label: thing.status.label, leading: /* @__PURE__ */ jsx(StatusIcon, { status: thing.status }) }] }),
|
|
100
|
+
/* @__PURE__ */ jsx(
|
|
101
|
+
Select,
|
|
102
|
+
{
|
|
103
|
+
size: "small",
|
|
104
|
+
className: "w-auto",
|
|
105
|
+
value: "a",
|
|
106
|
+
onChange: noop,
|
|
107
|
+
ariaLabel: thing.kind === "project" ? "Lead" : "Assignee",
|
|
108
|
+
options: [{ value: "a", label: thing.assignee ?? "Unassigned", leading: /* @__PURE__ */ jsx(Avatar, { name: thing.assignee, size: 16 }) }]
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
] });
|
|
112
|
+
}
|
|
113
|
+
function Lead({ thing, chip = false }) {
|
|
114
|
+
if (thing.kind === "message") return /* @__PURE__ */ jsx(Avatar, { name: thing.author, size: 16 });
|
|
115
|
+
return /* @__PURE__ */ jsx(ThingIcon, { kind: thing.kind, size: chip ? 14 : 16, tone: chip ? "inherit" : "secondary" });
|
|
116
|
+
}
|
|
117
|
+
function ReferenceChip({ thing, state = "ready", preview = false }) {
|
|
118
|
+
if (state === "loading") {
|
|
119
|
+
return /* @__PURE__ */ jsx(InlineChip, { icon: /* @__PURE__ */ jsx(ThingIcon, { kind: thing.kind, size: 14, tone: "inherit" }), children: /* @__PURE__ */ jsx(SkeletonBar, { className: "h-2.5 w-16" }) });
|
|
120
|
+
}
|
|
121
|
+
if (state === "unavailable") {
|
|
122
|
+
return /* @__PURE__ */ jsxs(InlineChip, { icon: /* @__PURE__ */ jsx(ThingIcon, { kind: thing.kind, size: 14, tone: "inherit" }), className: "text-text-muted", children: [
|
|
123
|
+
thing.noun,
|
|
124
|
+
", not available"
|
|
125
|
+
] });
|
|
126
|
+
}
|
|
127
|
+
const chip = /* @__PURE__ */ jsxs(InlineChip, { icon: /* @__PURE__ */ jsx(Lead, { thing, chip: true }), href: HREF, className: "max-w-[28ch]", children: [
|
|
128
|
+
thing.key && /* @__PURE__ */ jsx(Key, { children: thing.key }),
|
|
129
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: thing.kind === "message" ? `${thing.author}: ${thing.body}` : thing.title }),
|
|
130
|
+
thing.status && /* @__PURE__ */ jsx(StatusMark, { status: thing.status })
|
|
131
|
+
] });
|
|
132
|
+
return preview ? /* @__PURE__ */ jsx(HoverPreview, { thing, children: chip }) : chip;
|
|
133
|
+
}
|
|
134
|
+
function CompactCard({ thing, preview = false }) {
|
|
135
|
+
const card = /* @__PURE__ */ jsxs(Card, { fill: "inset", hover: "hairline", className: "relative flex h-9 items-center gap-2 px-3", children: [
|
|
136
|
+
/* @__PURE__ */ jsx(Lead, { thing }),
|
|
137
|
+
thing.kind === "message" ? /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 items-baseline gap-2 text-body-2", children: [
|
|
138
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-body-2-strong text-text-primary", children: thing.author }),
|
|
139
|
+
/* @__PURE__ */ jsx(Link, { href: HREF, variant: "quiet", cover: true, truncate: true, className: "text-text-secondary", children: thing.body })
|
|
140
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
141
|
+
thing.key && /* @__PURE__ */ jsx(Key, { children: thing.key }),
|
|
142
|
+
/* @__PURE__ */ jsx("span", { className: "contents text-body-2-strong text-text-primary", children: /* @__PURE__ */ jsx(Link, { href: HREF, variant: "quiet", cover: true, truncate: true, className: "min-w-0 flex-1", children: thing.title }) })
|
|
143
|
+
] }),
|
|
144
|
+
thing.kind === "topic" && /* @__PURE__ */ jsx(Conversations, { thing }),
|
|
145
|
+
thing.kind === "page" && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-caption text-text-secondary", children: thing.updated }),
|
|
146
|
+
thing.kind === "message" && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-caption text-text-muted", children: thing.updated }),
|
|
147
|
+
thing.unread && thing.comments !== void 0 && /* @__PURE__ */ jsx(Comments, { count: thing.comments, unread: true }),
|
|
148
|
+
thing.status && thing.kind === "issue" && /* @__PURE__ */ jsx(StatusMark, { status: thing.status }),
|
|
149
|
+
thing.done && /* @__PURE__ */ jsx(ProgressRing, { done: thing.done.done, total: thing.done.total }),
|
|
150
|
+
thing.assignee && /* @__PURE__ */ jsx(Avatar, { name: thing.assignee, size: 16 }),
|
|
151
|
+
thing.members && /* @__PURE__ */ jsx(AvatarGroup, { members: people(thing.members), size: 16 }),
|
|
152
|
+
thing.authors && /* @__PURE__ */ jsx(AvatarGroup, { members: people(thing.authors), size: 16 })
|
|
153
|
+
] });
|
|
154
|
+
return preview ? /* @__PURE__ */ jsx(HoverPreview, { thing, block: true, children: card }) : card;
|
|
155
|
+
}
|
|
156
|
+
function DetailedCard({ thing, bare = false, readOnly = bare }) {
|
|
157
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
158
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-h-[19.6px] items-center gap-2", children: [
|
|
159
|
+
/* @__PURE__ */ jsxs(Link, { href: HREF, variant: "quiet", className: "flex min-w-0 flex-1 items-center gap-2 text-body-2-strong text-text-primary", children: [
|
|
160
|
+
/* @__PURE__ */ jsx(ThingIcon, { kind: thing.kind }),
|
|
161
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: thing.title })
|
|
162
|
+
] }),
|
|
163
|
+
thing.done && /* @__PURE__ */ jsx(ProgressRing, { done: thing.done.done, total: thing.done.total }),
|
|
164
|
+
thing.members && /* @__PURE__ */ jsx(AvatarGroup, { members: people(thing.members), size: 16 })
|
|
165
|
+
] }),
|
|
166
|
+
(thing.key || thing.subtitle) && /* @__PURE__ */ jsx("p", { className: "-mt-1 pl-6 text-caption text-text-secondary", children: [thing.key, thing.subtitle].filter(Boolean).join(" \xB7 ") }),
|
|
167
|
+
thing.summary && /* @__PURE__ */ jsx("p", { className: "line-clamp-2 text-body-2 text-text-secondary", children: thing.summary }),
|
|
168
|
+
thing.children && /* @__PURE__ */ jsx("div", { className: "flex flex-col divide-y divide-border-subtle rounded-md border border-border-subtle", children: thing.children.map((child) => /* @__PURE__ */ jsxs("div", { className: "relative flex h-8 items-center gap-2 px-2 hover:bg-bg-active", children: [
|
|
169
|
+
/* @__PURE__ */ jsx(StatusMark, { status: child.status }),
|
|
170
|
+
/* @__PURE__ */ jsx(Key, { children: child.key }),
|
|
171
|
+
/* @__PURE__ */ jsx("span", { className: "contents text-body-2 text-text-primary", children: /* @__PURE__ */ jsx(Link, { href: HREF, variant: "quiet", cover: true, truncate: true, className: "min-w-0 flex-1", children: child.title }) }),
|
|
172
|
+
child.assignee ? /* @__PURE__ */ jsx(Avatar, { name: child.assignee, size: 16 }) : /* @__PURE__ */ jsx("span", { className: "size-4 shrink-0", "aria-hidden": true })
|
|
173
|
+
] }, child.key)) }),
|
|
174
|
+
thing.latest && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
175
|
+
/* @__PURE__ */ jsx("span", { className: "text-caption text-text-muted", children: "Latest conversation" }),
|
|
176
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2 rounded-md border border-border-subtle p-2", children: [
|
|
177
|
+
/* @__PURE__ */ jsx(Avatar, { name: thing.latest.author, size: 16 }),
|
|
178
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
179
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2 text-caption", children: [
|
|
180
|
+
/* @__PURE__ */ jsx("span", { className: "text-text-primary", children: thing.latest.author }),
|
|
181
|
+
/* @__PURE__ */ jsx("span", { className: "text-text-muted", children: thing.latest.at })
|
|
182
|
+
] }),
|
|
183
|
+
/* @__PURE__ */ jsx("p", { className: "line-clamp-2 text-body-2 text-text-secondary", children: thing.latest.body })
|
|
184
|
+
] })
|
|
185
|
+
] })
|
|
186
|
+
] }),
|
|
187
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-h-6 items-center gap-2 border-t border-border-subtle pt-2", children: [
|
|
188
|
+
(thing.kind === "issue" || thing.kind === "project") && /* @__PURE__ */ jsx(Pickers, { thing, readOnly }),
|
|
189
|
+
thing.kind === "topic" && /* @__PURE__ */ jsx("span", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs("span", { className: "text-caption text-text-secondary", children: [
|
|
190
|
+
"Updated ",
|
|
191
|
+
thing.updated
|
|
192
|
+
] }) }),
|
|
193
|
+
thing.authors && /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-2 text-caption text-text-secondary", children: [
|
|
194
|
+
/* @__PURE__ */ jsx(AvatarGroup, { members: people(thing.authors), size: 16 }),
|
|
195
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0", children: thing.updated })
|
|
196
|
+
] }),
|
|
197
|
+
thing.kind === "topic" && /* @__PURE__ */ jsx("span", { className: "ml-auto flex", children: /* @__PURE__ */ jsx(Comments, { count: thing.conversations ?? 0, unread: thing.unread, noun: "conversations" }) }),
|
|
198
|
+
thing.comments !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-auto flex", children: /* @__PURE__ */ jsx(Comments, { count: thing.comments, unread: thing.unread }) })
|
|
199
|
+
] })
|
|
200
|
+
] });
|
|
201
|
+
if (bare) return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2 p-3", children: body });
|
|
202
|
+
return /* @__PURE__ */ jsx(Card, { fill: "inset", "data-card": "detailed", className: "flex flex-col gap-2 p-3", children: body });
|
|
203
|
+
}
|
|
204
|
+
function HoverPreview({ thing, block = false, children }) {
|
|
205
|
+
return /* @__PURE__ */ jsx(PreviewCard, { side: "bottom", content: /* @__PURE__ */ jsx(DetailedCard, { thing, bare: true }), wrapperClassName: block ? "grid w-full min-w-0 grid-cols-[minmax(0,1fr)]" : "max-w-full", children });
|
|
206
|
+
}
|
|
207
|
+
function HoverPreviewOpen({ thing }) {
|
|
208
|
+
return /* @__PURE__ */ jsx(MenuPanel, { className: "w-[360px] p-0", children: /* @__PURE__ */ jsx(DetailedCard, { thing, bare: true }) });
|
|
209
|
+
}
|
|
210
|
+
function MessageCard({ thing }) {
|
|
211
|
+
return /* @__PURE__ */ jsxs(Card, { fill: "inset", className: "flex flex-col gap-2 p-3", children: [
|
|
212
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
213
|
+
/* @__PURE__ */ jsx(Avatar, { name: thing.author, size: 24 }),
|
|
214
|
+
/* @__PURE__ */ jsx("span", { className: "text-body-2-strong text-text-primary", children: thing.author }),
|
|
215
|
+
/* @__PURE__ */ jsx(Link, { href: HREF, variant: "quiet", className: "text-caption text-text-muted", children: thing.updated })
|
|
216
|
+
] }),
|
|
217
|
+
/* @__PURE__ */ jsx("p", { className: "line-clamp-4 text-body-2 text-text-primary", children: thing.body })
|
|
218
|
+
] });
|
|
219
|
+
}
|
|
220
|
+
function loadingShapeOf(thing) {
|
|
221
|
+
return {
|
|
222
|
+
subtitle: !!(thing.subtitle || thing.key),
|
|
223
|
+
summary: !!thing.summary,
|
|
224
|
+
rows: thing.children?.length ?? 0,
|
|
225
|
+
preview: !!thing.latest,
|
|
226
|
+
ring: !!thing.done,
|
|
227
|
+
footer: thing.kind === "issue" || thing.kind === "project" ? "pickers" : thing.authors ? "people" : "line"
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function Bar({ className }) {
|
|
231
|
+
return /* @__PURE__ */ jsx(SkeletonBar, { className: cn("bg-bg-active", className) });
|
|
232
|
+
}
|
|
233
|
+
function CardLoading({ kind, layout, shape = {} }) {
|
|
234
|
+
if (layout === "compact") {
|
|
235
|
+
return /* @__PURE__ */ jsxs(Card, { fill: "inset", "aria-hidden": true, "data-card": "loading", className: "flex h-9 items-center gap-2 px-3 animate-skeleton-in", children: [
|
|
236
|
+
/* @__PURE__ */ jsx(ThingIcon, { kind }),
|
|
237
|
+
/* @__PURE__ */ jsx(Bar, { className: "h-3 w-2/5" }),
|
|
238
|
+
/* @__PURE__ */ jsx(Bar, { className: "ml-auto size-4 rounded-full" })
|
|
239
|
+
] });
|
|
240
|
+
}
|
|
241
|
+
const { subtitle = false, summary = true, rows = 0, preview = false, ring = false, footer = "line" } = shape;
|
|
242
|
+
return /* @__PURE__ */ jsxs(Card, { fill: "inset", "aria-hidden": true, "data-card": "loading", className: "flex flex-col gap-2 p-3 animate-skeleton-in", children: [
|
|
243
|
+
/* @__PURE__ */ jsxs("div", { className: "flex h-[19.6px] items-center gap-2", children: [
|
|
244
|
+
/* @__PURE__ */ jsx(ThingIcon, { kind }),
|
|
245
|
+
/* @__PURE__ */ jsx(Bar, { className: "h-3.5 w-1/2" }),
|
|
246
|
+
ring && /* @__PURE__ */ jsx(Bar, { className: "ml-auto size-4 rounded-full" })
|
|
247
|
+
] }),
|
|
248
|
+
subtitle && /* @__PURE__ */ jsx("div", { className: "-mt-1 flex h-[14.4px] items-center pl-6", children: /* @__PURE__ */ jsx(Bar, { className: "h-2.5 w-20" }) }),
|
|
249
|
+
summary && /* @__PURE__ */ jsx("div", { className: "flex h-[19.6px] items-center", children: /* @__PURE__ */ jsx(Bar, { className: "h-3 w-4/5" }) }),
|
|
250
|
+
rows > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col divide-y divide-border-subtle rounded-md border border-border-subtle", children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx("div", { className: "flex h-8 items-center px-2", children: /* @__PURE__ */ jsx(Bar, { className: "h-3 w-1/3" }) }, i)) }),
|
|
251
|
+
preview && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
252
|
+
/* @__PURE__ */ jsx("div", { className: "flex h-[14.4px] items-center", children: /* @__PURE__ */ jsx(Bar, { className: "h-2.5 w-28" }) }),
|
|
253
|
+
/* @__PURE__ */ jsxs("div", { className: "flex h-[71.6px] flex-col justify-center gap-2 rounded-md border border-border-subtle p-2", children: [
|
|
254
|
+
/* @__PURE__ */ jsx(Bar, { className: "h-2.5 w-24" }),
|
|
255
|
+
/* @__PURE__ */ jsx(Bar, { className: "h-3 w-full" }),
|
|
256
|
+
/* @__PURE__ */ jsx(Bar, { className: "h-3 w-3/5" })
|
|
257
|
+
] })
|
|
258
|
+
] }),
|
|
259
|
+
footer !== "none" && /* @__PURE__ */ jsx("div", { className: "flex min-h-6 items-center gap-2 border-t border-border-subtle pt-2", children: footer === "pickers" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
260
|
+
/* @__PURE__ */ jsx(Bar, { className: "h-6 w-24 rounded-md" }),
|
|
261
|
+
/* @__PURE__ */ jsx(Bar, { className: "h-6 w-28 rounded-md" })
|
|
262
|
+
] }) : footer === "people" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
263
|
+
/* @__PURE__ */ jsx(Bar, { className: "size-4 rounded-full" }),
|
|
264
|
+
/* @__PURE__ */ jsx(Bar, { className: "h-3 w-40" })
|
|
265
|
+
] }) : /* @__PURE__ */ jsx(Bar, { className: "h-3 w-40" }) })
|
|
266
|
+
] });
|
|
267
|
+
}
|
|
268
|
+
function CardUnavailable({ kind, noun, app }) {
|
|
269
|
+
return /* @__PURE__ */ jsxs(Card, { fill: "none", unreadable: true, className: "flex h-9 items-center gap-2 px-3", children: [
|
|
270
|
+
/* @__PURE__ */ jsx(ThingIcon, { kind }),
|
|
271
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1 truncate text-body-2 text-text-muted", children: [
|
|
272
|
+
noun,
|
|
273
|
+
" \u2014 not available."
|
|
274
|
+
] }),
|
|
275
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-caption", children: /* @__PURE__ */ jsxs(Link, { href: HREF, variant: "quiet", external: true, className: "text-text-secondary", children: [
|
|
276
|
+
"Open in ",
|
|
277
|
+
app,
|
|
278
|
+
" \u2197"
|
|
279
|
+
] }) })
|
|
280
|
+
] });
|
|
281
|
+
}
|
|
282
|
+
function PartCard({ kind, heading, partKey, children, state = "ready", noun, app }) {
|
|
283
|
+
if (state === "loading") return /* @__PURE__ */ jsx(CardLoading, { kind, layout: "detailed", shape: { summary: true, rows: 0, footer: "none" } });
|
|
284
|
+
if (state === "unavailable") return /* @__PURE__ */ jsx(CardUnavailable, { kind, noun: `A part of this ${noun.toLowerCase()}`, app });
|
|
285
|
+
return /* @__PURE__ */ jsxs(Card, { fill: "inset", className: "flex flex-col gap-2 p-3", children: [
|
|
286
|
+
/* @__PURE__ */ jsxs(Link, { href: HREF, variant: "quiet", className: "flex min-w-0 items-center gap-2 text-body-2-strong text-text-primary", children: [
|
|
287
|
+
/* @__PURE__ */ jsx(ThingIcon, { kind }),
|
|
288
|
+
partKey && /* @__PURE__ */ jsx(Key, { children: partKey }),
|
|
289
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: heading })
|
|
290
|
+
] }),
|
|
291
|
+
/* @__PURE__ */ jsx("div", { className: "border-l-2 border-border-default pl-3", children })
|
|
292
|
+
] });
|
|
293
|
+
}
|
|
294
|
+
function CommentAnchor({ text }) {
|
|
295
|
+
if (text === void 0) return /* @__PURE__ */ jsx("div", { className: "border-l-2 border-border-default pl-2 text-caption text-text-muted", children: "The part this is about was deleted." });
|
|
296
|
+
return /* @__PURE__ */ jsx("div", { className: "border-l-2 border-border-strong pl-2 text-caption text-text-muted", children: /* @__PURE__ */ jsx("span", { className: "line-clamp-2 italic", children: text }) });
|
|
297
|
+
}
|
|
298
|
+
function AttachmentChip({ name, state = "ready" }) {
|
|
299
|
+
if (state === "loading") {
|
|
300
|
+
return /* @__PURE__ */ jsx(InlineChip, { icon: /* @__PURE__ */ jsx(IconPaperclip, { size: 14, stroke: 1.5, "aria-hidden": true }), children: /* @__PURE__ */ jsx(SkeletonBar, { className: "h-2.5 w-16" }) });
|
|
301
|
+
}
|
|
302
|
+
if (state === "unavailable") {
|
|
303
|
+
return /* @__PURE__ */ jsx(InlineChip, { icon: /* @__PURE__ */ jsx(IconPaperclip, { size: 14, stroke: 1.5, "aria-hidden": true }), className: "text-text-muted", children: "File, not available" });
|
|
304
|
+
}
|
|
305
|
+
return /* @__PURE__ */ jsx(InlineChip, { icon: /* @__PURE__ */ jsx(IconPaperclip, { size: 14, stroke: 1.5, "aria-hidden": true }), href: HREF, className: "max-w-[24ch]", children: /* @__PURE__ */ jsx("span", { className: "truncate", children: name }) });
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// src/widgets-2/fixtures.ts
|
|
309
|
+
var TODO = { label: "Todo", colour: "neutral" };
|
|
310
|
+
var DOING = { label: "In progress", colour: "blue" };
|
|
311
|
+
var DONE = { label: "Done", colour: "green" };
|
|
312
|
+
var PARAGRAPH = "A description long enough to need more than one line, so the card has to choose how much of it to show and where to cut it short. The rest is there when you open it.";
|
|
313
|
+
var SUMMARY = "A one-sentence summary of what this is for.";
|
|
314
|
+
var ISSUE = {
|
|
315
|
+
kind: "issue",
|
|
316
|
+
noun: "Issue",
|
|
317
|
+
app: "Ship",
|
|
318
|
+
title: "Item one, with a title long enough to be cut short",
|
|
319
|
+
key: "ABC-2",
|
|
320
|
+
subtitle: "Group one",
|
|
321
|
+
body: PARAGRAPH,
|
|
322
|
+
summary: SUMMARY,
|
|
323
|
+
status: DOING,
|
|
324
|
+
assignee: "Person One",
|
|
325
|
+
comments: 4,
|
|
326
|
+
unread: true
|
|
327
|
+
};
|
|
328
|
+
var PROJECT = {
|
|
329
|
+
kind: "project",
|
|
330
|
+
noun: "Project",
|
|
331
|
+
app: "Ship",
|
|
332
|
+
title: "Group one",
|
|
333
|
+
body: PARAGRAPH,
|
|
334
|
+
summary: SUMMARY,
|
|
335
|
+
status: DOING,
|
|
336
|
+
assignee: "Person Two",
|
|
337
|
+
progress: "3 of 8 done",
|
|
338
|
+
done: { done: 3, total: 8 },
|
|
339
|
+
comments: 6,
|
|
340
|
+
children: [
|
|
341
|
+
{ title: "Item one", key: "ABC-1", status: DONE, assignee: "Person One" },
|
|
342
|
+
{ title: "Item two", key: "ABC-2", status: DOING, assignee: "Person Two" },
|
|
343
|
+
{ title: "Item three", key: "ABC-3", status: TODO }
|
|
344
|
+
]
|
|
345
|
+
};
|
|
346
|
+
var TOPIC = {
|
|
347
|
+
kind: "topic",
|
|
348
|
+
noun: "Topic",
|
|
349
|
+
app: "Peek",
|
|
350
|
+
title: "Place one",
|
|
351
|
+
conversations: 12,
|
|
352
|
+
unread: true,
|
|
353
|
+
members: ["Person One", "Person Two", "Person Three"],
|
|
354
|
+
updated: "2h ago",
|
|
355
|
+
latest: { author: "Person Three", body: "The latest conversation in the topic, as its first message reads. It may run to a second line before it is cut short.", at: "2h ago" }
|
|
356
|
+
};
|
|
357
|
+
var MESSAGE = {
|
|
358
|
+
kind: "message",
|
|
359
|
+
noun: "Message",
|
|
360
|
+
app: "Peek",
|
|
361
|
+
title: "Person Two",
|
|
362
|
+
author: "Person Two",
|
|
363
|
+
body: "A message of two sentences, written by someone in a conversation. It is the words the link points to.",
|
|
364
|
+
updated: "10:42"
|
|
365
|
+
};
|
|
366
|
+
var PAGE = {
|
|
367
|
+
kind: "page",
|
|
368
|
+
noun: "Page",
|
|
369
|
+
app: "Leaf",
|
|
370
|
+
title: "Page one",
|
|
371
|
+
subtitle: "Folder one",
|
|
372
|
+
body: PARAGRAPH,
|
|
373
|
+
summary: SUMMARY,
|
|
374
|
+
author: "Person One",
|
|
375
|
+
authors: ["Person One", "Person Two"],
|
|
376
|
+
comments: 2,
|
|
377
|
+
updated: "Edited yesterday"
|
|
378
|
+
};
|
|
379
|
+
var PART = {
|
|
380
|
+
heading: "Item one",
|
|
381
|
+
noun: "Issue",
|
|
382
|
+
app: "Ship",
|
|
383
|
+
blocks: ["Heading of the part", "A paragraph of the part, as it reads in the description right now.", "A point in a list", "Another point"]
|
|
384
|
+
};
|
|
385
|
+
var ATTACHMENT = { name: "picture-one.png", size: 182400, contentType: "image/png" };
|
|
386
|
+
var ATTACHMENT_FILE = { name: "document-one.pdf", size: 124e4, contentType: "application/pdf" };
|
|
387
|
+
var UNREADABLE = { kind: "issue", noun: "Issue", app: "Ship", address: "naddr1qqjxgdmzxy6r2vfs95cryvmp956x2etp94sns" };
|
|
388
|
+
var PICTURE = "data:image/svg+xml;utf8," + encodeURIComponent(
|
|
389
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="480" height="300"><rect width="480" height="300" fill="#8a94a6"/><circle cx="360" cy="90" r="40" fill="#d8dde6"/><path d="M0 300 L170 120 L300 260 L380 190 L480 300 Z" fill="#5d6778"/></svg>'
|
|
390
|
+
);
|
|
391
|
+
export {
|
|
392
|
+
ATTACHMENT,
|
|
393
|
+
ATTACHMENT_FILE,
|
|
394
|
+
AttachmentChip,
|
|
395
|
+
CardLoading,
|
|
396
|
+
CardUnavailable,
|
|
397
|
+
CommentAnchor,
|
|
398
|
+
CompactCard,
|
|
399
|
+
DetailedCard,
|
|
400
|
+
HoverPreview,
|
|
401
|
+
HoverPreviewOpen,
|
|
402
|
+
ISSUE,
|
|
403
|
+
MESSAGE,
|
|
404
|
+
MessageCard,
|
|
405
|
+
PAGE,
|
|
406
|
+
PART,
|
|
407
|
+
PICTURE,
|
|
408
|
+
PROJECT,
|
|
409
|
+
PartCard,
|
|
410
|
+
ProgressRing,
|
|
411
|
+
ReferenceChip,
|
|
412
|
+
StatusMark,
|
|
413
|
+
TOPIC,
|
|
414
|
+
ThingIcon,
|
|
415
|
+
UNREADABLE,
|
|
416
|
+
loadingShapeOf
|
|
417
|
+
};
|
|
418
|
+
//# sourceMappingURL=widgets-2.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/widgets-2/proposed.tsx", "../src/widgets-2/fixtures.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Widgets 2 prototype: the proposed shared kit, one drawing of each widget for\n * Peek, Ship and Leaf alike. Written as the package would export it: no app\n * name and no product noun in a name or a prop. The kind's icon, the key and\n * every field arrive as data from the app's manifest.\n *\n * In `src/` on `concept/widgets-2` only, so the apps' own Storybooks can place\n * it (WID-3): `@estiva-app/ui/widgets-2`, an unlisted entry published only as a\n * `concept` prerelease. The build project shapes the real exports from it once\n * Miky and Katerina approve it.\n *\n * Second iteration, from Miky's notes on WID-2 (15 Oct):\n * - no noun in a card's corner and no \"Open in \u2026\": the icon says what it is,\n * and the title is the link;\n * - an issue shows its key; the only status and assignee are the actionable ones;\n * - detailed shows the file's short summary, not the opening of its description;\n * - hovering a chip or a compact card shows the detailed card;\n * - a project shows its progress as a ring, its status and lead as actions,\n * its comments, and each issue's assignee;\n * - a topic shows its conversations, its last update and its members, and\n * detailed adds the latest conversation;\n * - a message is drawn with its author's face; a page with its authors and\n * its last edit.\n */\nimport { IconCircle, IconCircleCheck, IconCircleDashed, IconCircleHalf2, IconCircleX, IconFileText, IconMessage2, IconPaperclip } from '@tabler/icons-react'\nimport type { ReactNode } from 'react'\nimport { Avatar } from '../Avatar'\nimport { AvatarGroup } from '../AvatarGroup'\nimport { Card } from '../Card'\nimport { cn } from '../cn'\nimport { InlineChip } from '../InlineChip'\nimport { KindIcon } from '../KindIcon'\nimport { Link } from '../Link'\nimport { MenuPanel } from '../Menu'\nimport { PreviewCard } from '../PreviewCard'\nimport { Select } from '../Select'\nimport { SkeletonBar } from '../Skeleton'\nimport { UnreadDot } from '../UnreadDot'\nimport type { Status, StatusColour, Thing } from './fixtures'\n\nconst HREF = '#'\nconst noop = () => {}\n\n/* ------------------------------------------------------------ the parts */\n\nconst STATUS_ICON: Record<StatusColour, { Icon: typeof IconCircle; tone: string }> = {\n neutral: { Icon: IconCircleDashed, tone: 'text-text-secondary' },\n blue: { Icon: IconCircleHalf2, tone: 'text-info-default' },\n green: { Icon: IconCircleCheck, tone: 'text-success-default' },\n muted: { Icon: IconCircleX, tone: 'text-text-muted' },\n}\n\n/** A status as its shape: Ship's icons, which read without colour. */\nexport function StatusMark({ status }: { status: Status }) {\n return (\n <span className=\"inline-flex shrink-0 items-center\" title={status.label}>\n <StatusIcon status={status} />\n <span className=\"sr-only\">{status.label}</span>\n </span>\n )\n}\n\n/** The status's shape alone, beside words that already name it. */\nfunction StatusIcon({ status }: { status: Status }) {\n const { Icon, tone } = STATUS_ICON[status.colour]\n return <Icon size={14} stroke={1.5} className={cn('shrink-0', tone)} aria-hidden />\n}\n\n/** The icon for a kind. A page gets its own (proposed): today every app draws it as \"another app's file\". */\nexport function ThingIcon({ kind, size = 16, tone = 'secondary' }: { kind: Thing['kind']; size?: 14 | 16; tone?: 'secondary' | 'inherit' }) {\n if (kind === 'page') return <IconFileText size={size} stroke={1.5} className={cn('shrink-0', tone === 'secondary' && 'text-text-secondary')} aria-hidden />\n return <KindIcon kind={kind} size={size} tone={tone} />\n}\n\n/** A key, the way people say it (\"ABC-2\"): before the title, quieter than it. */\nfunction Key({ children }: { children: ReactNode }) {\n return <span className=\"shrink-0 text-caption tabular-nums text-text-muted\">{children}</span>\n}\n\n/**\n * Progress as a small ring with the count beside it as a label (Miky, 15 Oct,\n * second round: the ring with the count inside was too big).\n */\nexport function ProgressRing({ done, total }: { done: number; total: number }) {\n const size = 16\n const stroke = 2\n const r = (size - stroke) / 2\n const c = 2 * Math.PI * r\n return (\n <span className=\"inline-flex shrink-0 items-center gap-1 text-caption tabular-nums text-text-secondary\" title={`${done} of ${total} done`}>\n <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} className=\"shrink-0 -rotate-90\" aria-hidden>\n <circle cx={size / 2} cy={size / 2} r={r} fill=\"none\" strokeWidth={stroke} className=\"stroke-border-default\" />\n <circle cx={size / 2} cy={size / 2} r={r} fill=\"none\" strokeWidth={stroke} strokeLinecap=\"round\" strokeDasharray={`${(c * done) / total} ${c}`} className=\"stroke-success-default\" />\n </svg>\n {done}/{total}\n </span>\n )\n}\n\n/*\n The unread dot after a count is the package's UnreadDot: the reader has\n something unread in this conversation. Only a member has unread (SPEC \u00A711.8),\n so a reader who is not one sees the count alone.\n*/\n\n/** Where the count leads: the file's conversation, at the first unread when there is one. */\nconst CONVERSATION_HREF = '#conversation'\n\n/**\n * The comment count, the words brighter and a dot after it when the reader\n * has unread there. It is a link to the conversation (Miky, fourth round:\n * \"especially needed when you have unread messages\"), and it sits above a\n * compact card's covering link, so the card opens the file and the count\n * opens its conversation.\n */\nfunction Comments({ count, unread = false, noun = 'comments' }: { count: number; unread?: boolean; noun?: string }) {\n return (\n <Link\n href={CONVERSATION_HREF}\n variant=\"plain\"\n className={cn(\n 'relative z-10 -mx-1 inline-flex shrink-0 items-center gap-1 rounded-sm px-1 text-caption tabular-nums hover:bg-bg-active',\n unread ? 'font-medium text-text-primary' : 'text-text-secondary',\n )}\n >\n <IconMessage2 size={14} stroke={1.5} aria-hidden />\n {count}\n <span className=\"sr-only\">{unread ? `${noun}, unread \u2014 open the conversation` : `${noun} \u2014 open the conversation`}</span>\n {unread && <UnreadDot className=\"h-auto w-auto\" />}\n </Link>\n )\n}\n\n/**\n * A topic's conversations: the same icon and count as every other file's\n * comments (Miky, third round), after when the last one moved.\n */\nfunction Conversations({ thing }: { thing: Thing }) {\n return (\n <span className=\"inline-flex shrink-0 items-center gap-2\">\n <span className=\"text-caption text-text-secondary\">{thing.updated}</span>\n <Comments count={thing.conversations ?? 0} unread={thing.unread} noun=\"conversations\" />\n </span>\n )\n}\n\nconst people = (names: string[] = []) => names.map((name) => ({ name }))\n\n/**\n * The kind's own pickers, the only place its status and owner show in detailed.\n * Read only, for a reader who may not change the file and in the hover preview\n * (Miky, 15 Oct: no actions on hover), they are the same two values as words,\n * in the same place.\n */\nfunction Pickers({ thing, readOnly = false }: { thing: Thing; readOnly?: boolean }) {\n if (!thing.status) return null\n if (readOnly) {\n return (\n <span className=\"flex h-6 min-w-0 items-center gap-3 text-caption text-text-secondary\">\n <span className=\"inline-flex shrink-0 items-center gap-1\">\n <StatusIcon status={thing.status} />\n {thing.status.label}\n </span>\n <span className=\"inline-flex min-w-0 items-center gap-1\">\n <Avatar name={thing.assignee} size={16} />\n <span className=\"truncate\">{thing.assignee ?? 'Unassigned'}</span>\n </span>\n </span>\n )\n }\n return (\n <>\n <Select size=\"small\" className=\"w-auto\" value=\"s\" onChange={noop} ariaLabel=\"Status\" options={[{ value: 's', label: thing.status.label, leading: <StatusIcon status={thing.status} /> }]} />\n <Select\n size=\"small\"\n className=\"w-auto\"\n value=\"a\"\n onChange={noop}\n ariaLabel={thing.kind === 'project' ? 'Lead' : 'Assignee'}\n options={[{ value: 'a', label: thing.assignee ?? 'Unassigned', leading: <Avatar name={thing.assignee} size={16} /> }]}\n />\n </>\n )\n}\n\n/* ----------------------------------------------------------------- chip */\n\nexport interface ReferenceChipProps {\n thing: Thing\n state?: 'ready' | 'loading' | 'unavailable'\n /** Hovering the chip shows the detailed card. */\n preview?: boolean\n}\n\n/** What leads a chip and a compact card: the author's face for a message, the kind's icon otherwise. */\nfunction Lead({ thing, chip = false }: { thing: Thing; chip?: boolean }) {\n if (thing.kind === 'message') return <Avatar name={thing.author} size={16} />\n return <ThingIcon kind={thing.kind} size={chip ? 14 : 16} tone={chip ? 'inherit' : 'secondary'} />\n}\n\n/**\n * A link in running text: the icon (or the author's face), the key, the\n * title cut at 24ch, the status as its shape. Loading keeps the icon (the\n * kind is known from the address); not available says so in words.\n */\nexport function ReferenceChip({ thing, state = 'ready', preview = false }: ReferenceChipProps) {\n if (state === 'loading') {\n return (\n <InlineChip icon={<ThingIcon kind={thing.kind} size={14} tone=\"inherit\" />}>\n <SkeletonBar className=\"h-2.5 w-16\" />\n </InlineChip>\n )\n }\n if (state === 'unavailable') {\n return (\n <InlineChip icon={<ThingIcon kind={thing.kind} size={14} tone=\"inherit\" />} className=\"text-text-muted\">\n {thing.noun}, not available\n </InlineChip>\n )\n }\n const chip = (\n <InlineChip icon={<Lead thing={thing} chip />} href={HREF} className=\"max-w-[28ch]\">\n {thing.key && <Key>{thing.key}</Key>}\n <span className=\"truncate\">{thing.kind === 'message' ? `${thing.author}: ${thing.body}` : thing.title}</span>\n {thing.status && <StatusMark status={thing.status} />}\n </InlineChip>\n )\n return preview ? <HoverPreview thing={thing}>{chip}</HoverPreview> : chip\n}\n\n/* ---------------------------------------------------------------- cards */\n\nexport type CardLayout = 'compact' | 'detailed'\n\n/** Compact: one 36px line. Every kind, every app. Hovering it shows the detailed card. */\nexport function CompactCard({ thing, preview = false }: { thing: Thing; preview?: boolean }) {\n const card = (\n <Card fill=\"inset\" hover=\"hairline\" className=\"relative flex h-9 items-center gap-2 px-3\">\n <Lead thing={thing} />\n {thing.kind === 'message' ? (\n <span className=\"flex min-w-0 flex-1 items-baseline gap-2 text-body-2\">\n <span className=\"shrink-0 text-body-2-strong text-text-primary\">{thing.author}</span>\n <Link href={HREF} variant=\"quiet\" cover truncate className=\"text-text-secondary\">\n {thing.body}\n </Link>\n </span>\n ) : (\n <>\n {thing.key && <Key>{thing.key}</Key>}\n <span className=\"contents text-body-2-strong text-text-primary\">\n <Link href={HREF} variant=\"quiet\" cover truncate className=\"min-w-0 flex-1\">\n {thing.title}\n </Link>\n </span>\n </>\n )}\n {thing.kind === 'topic' && <Conversations thing={thing} />}\n {thing.kind === 'page' && <span className=\"shrink-0 text-caption text-text-secondary\">{thing.updated}</span>}\n {thing.kind === 'message' && <span className=\"shrink-0 text-caption text-text-muted\">{thing.updated}</span>}\n {/* Compact keeps to one line: the comment count shows only when there is something unread in it. */}\n {thing.unread && thing.comments !== undefined && <Comments count={thing.comments} unread />}\n {thing.status && thing.kind === 'issue' && <StatusMark status={thing.status} />}\n {thing.done && <ProgressRing done={thing.done.done} total={thing.done.total} />}\n {thing.assignee && <Avatar name={thing.assignee} size={16} />}\n {thing.members && <AvatarGroup members={people(thing.members)} size={16} />}\n {thing.authors && <AvatarGroup members={people(thing.authors)} size={16} />}\n </Card>\n )\n return preview ? (\n <HoverPreview thing={thing} block>\n {card}\n </HoverPreview>\n ) : (\n card\n )\n}\n\n/**\n * Detailed: what compact cannot hold. The header is compact's line (icon, key,\n * title as the link; a project's ring or a topic's members in the corner),\n * then the summary, the kind's own extras (a project's issues, a topic's\n * latest conversation), and a footer: the pickers and the comments for an\n * issue or a project, who and when for a page and a topic.\n *\n * `bare` drops the card's frame, for the hover preview, which draws the\n * package's one elevated box around it.\n */\nexport function DetailedCard({ thing, bare = false, readOnly = bare }: { thing: Thing; bare?: boolean; readOnly?: boolean }) {\n const body = (\n <>\n <div className=\"flex min-h-[19.6px] items-center gap-2\">\n {/* The icon opens the file too, so the target is larger than the words (Miky, third round). */}\n <Link href={HREF} variant=\"quiet\" className=\"flex min-w-0 flex-1 items-center gap-2 text-body-2-strong text-text-primary\">\n <ThingIcon kind={thing.kind} />\n <span className=\"truncate\">{thing.title}</span>\n </Link>\n {thing.done && <ProgressRing done={thing.done.done} total={thing.done.total} />}\n {thing.members && <AvatarGroup members={people(thing.members)} size={16} />}\n </div>\n {/* The key sits with the project under the title: \"ABC-2 \u00B7 Group one\" (Miky, second round). */}\n {(thing.key || thing.subtitle) && <p className=\"-mt-1 pl-6 text-caption text-text-secondary\">{[thing.key, thing.subtitle].filter(Boolean).join(' \u00B7 ')}</p>}\n {thing.summary && <p className=\"line-clamp-2 text-body-2 text-text-secondary\">{thing.summary}</p>}\n {thing.children && (\n <div className=\"flex flex-col divide-y divide-border-subtle rounded-md border border-border-subtle\">\n {thing.children.map((child) => (\n <div key={child.key} className=\"relative flex h-8 items-center gap-2 px-2 hover:bg-bg-active\">\n {/* The status is the row's icon: a list of issues needs no issue icon on every row (Miky, second round). */}\n <StatusMark status={child.status} />\n <Key>{child.key}</Key>\n {/* Each issue opens on its own; the link covers its row (Miky, third round). */}\n <span className=\"contents text-body-2 text-text-primary\">\n <Link href={HREF} variant=\"quiet\" cover truncate className=\"min-w-0 flex-1\">\n {child.title}\n </Link>\n </span>\n {child.assignee ? <Avatar name={child.assignee} size={16} /> : <span className=\"size-4 shrink-0\" aria-hidden />}\n </div>\n ))}\n </div>\n )}\n {thing.latest && (\n <div className=\"flex flex-col gap-1\">\n {/*\n \"Latest\" in words: the card follows the topic, so it is not the conversation the link was sent about.\n The label names the whole box, so it sits above it, not inside (Miky, fourth round).\n */}\n <span className=\"text-caption text-text-muted\">Latest conversation</span>\n <div className=\"flex gap-2 rounded-md border border-border-subtle p-2\">\n <Avatar name={thing.latest.author} size={16} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-baseline gap-2 text-caption\">\n <span className=\"text-text-primary\">{thing.latest.author}</span>\n <span className=\"text-text-muted\">{thing.latest.at}</span>\n </div>\n <p className=\"line-clamp-2 text-body-2 text-text-secondary\">{thing.latest.body}</p>\n </div>\n </div>\n </div>\n )}\n <div className=\"flex min-h-6 items-center gap-2 border-t border-border-subtle pt-2\">\n {(thing.kind === 'issue' || thing.kind === 'project') && <Pickers thing={thing} readOnly={readOnly} />}\n {thing.kind === 'topic' && (\n <span className=\"flex items-center gap-2\">\n <span className=\"text-caption text-text-secondary\">Updated {thing.updated}</span>\n </span>\n )}\n {/* Faces only, as every other widget: names would not fit once several people wrote it (Miky, third round). */}\n {thing.authors && (\n <span className=\"flex min-w-0 items-center gap-2 text-caption text-text-secondary\">\n <AvatarGroup members={people(thing.authors)} size={16} />\n <span className=\"shrink-0\">{thing.updated}</span>\n </span>\n )}\n {thing.kind === 'topic' && (\n <span className=\"ml-auto flex\">\n <Comments count={thing.conversations ?? 0} unread={thing.unread} noun=\"conversations\" />\n </span>\n )}\n {thing.comments !== undefined && (\n <span className=\"ml-auto flex\">\n <Comments count={thing.comments} unread={thing.unread} />\n </span>\n )}\n </div>\n </>\n )\n if (bare) return <div className=\"flex flex-col gap-2 p-3\">{body}</div>\n return (\n <Card fill=\"inset\" data-card=\"detailed\" className=\"flex flex-col gap-2 p-3\">\n {body}\n </Card>\n )\n}\n\n/** The detailed card, on hover over a chip or a compact card: the package's preview card. */\nexport function HoverPreview({ thing, block = false, children }: { thing: Thing; block?: boolean; children: ReactNode }) {\n // A compact card fills its column; PreviewCard's own trigger is inline and would shrink it to its words.\n return (\n <PreviewCard side=\"bottom\" content={<DetailedCard thing={thing} bare />} wrapperClassName={block ? 'grid w-full min-w-0 grid-cols-[minmax(0,1fr)]' : 'max-w-full'}>\n {children}\n </PreviewCard>\n )\n}\n\n/** The hover preview drawn open, for a still picture of it: the same box PreviewCard draws. */\nexport function HoverPreviewOpen({ thing }: { thing: Thing }) {\n return (\n <MenuPanel className=\"w-[360px] p-0\">\n <DetailedCard thing={thing} bare />\n </MenuPanel>\n )\n}\n\n/**\n * A linked message, detailed: a card, the frame every other detailed card has\n * (Miky, 15 Oct: \"card it is\", over a quote). The time is the link.\n */\nexport function MessageCard({ thing }: { thing: Thing }) {\n return (\n <Card fill=\"inset\" className=\"flex flex-col gap-2 p-3\">\n <div className=\"flex items-center gap-2\">\n <Avatar name={thing.author} size={24} />\n <span className=\"text-body-2-strong text-text-primary\">{thing.author}</span>\n <Link href={HREF} variant=\"quiet\" className=\"text-caption text-text-muted\">\n {thing.updated}\n </Link>\n </div>\n <p className=\"line-clamp-4 text-body-2 text-text-primary\">{thing.body}</p>\n </Card>\n )\n}\n\n/* ------------------------------------------------- loading, not available */\n\n/** What a kind's detailed card will hold, known before it loads (the kind is in the address). */\nexport interface LoadingShape {\n subtitle?: boolean\n summary?: boolean\n rows?: number\n preview?: boolean\n ring?: boolean\n footer?: 'pickers' | 'people' | 'line' | 'none'\n}\n\n/** The shape a thing's detailed card takes, for its placeholder. */\nexport function loadingShapeOf(thing: Thing): LoadingShape {\n return {\n subtitle: !!(thing.subtitle || thing.key),\n summary: !!thing.summary,\n rows: thing.children?.length ?? 0,\n preview: !!thing.latest,\n ring: !!thing.done,\n footer: thing.kind === 'issue' || thing.kind === 'project' ? 'pickers' : thing.authors ? 'people' : 'line',\n }\n}\n\n/** A bar that shows on an inset card: the package's bar is the inset colour, and vanishes on one. */\nfunction Bar({ className }: { className?: string }) {\n return <SkeletonBar className={cn('bg-bg-active', className)} />\n}\n\n/**\n * Loading: the card it will become, drawn in bars, at the card's own height,\n * so the conversation does not jump when it arrives.\n */\nexport function CardLoading({ kind, layout, shape = {} }: { kind: Thing['kind']; layout: CardLayout; shape?: LoadingShape }) {\n if (layout === 'compact') {\n return (\n <Card fill=\"inset\" aria-hidden data-card=\"loading\" className=\"flex h-9 items-center gap-2 px-3 animate-skeleton-in\">\n <ThingIcon kind={kind} />\n <Bar className=\"h-3 w-2/5\" />\n <Bar className=\"ml-auto size-4 rounded-full\" />\n </Card>\n )\n }\n const { subtitle = false, summary = true, rows = 0, preview = false, ring = false, footer = 'line' } = shape\n return (\n <Card fill=\"inset\" aria-hidden data-card=\"loading\" className=\"flex flex-col gap-2 p-3 animate-skeleton-in\">\n <div className=\"flex h-[19.6px] items-center gap-2\">\n <ThingIcon kind={kind} />\n <Bar className=\"h-3.5 w-1/2\" />\n {ring && <Bar className=\"ml-auto size-4 rounded-full\" />}\n </div>\n {subtitle && (\n <div className=\"-mt-1 flex h-[14.4px] items-center pl-6\">\n <Bar className=\"h-2.5 w-20\" />\n </div>\n )}\n {summary && (\n <div className=\"flex h-[19.6px] items-center\">\n <Bar className=\"h-3 w-4/5\" />\n </div>\n )}\n {rows > 0 && (\n <div className=\"flex flex-col divide-y divide-border-subtle rounded-md border border-border-subtle\">\n {Array.from({ length: rows }, (_, i) => (\n <div key={i} className=\"flex h-8 items-center px-2\">\n <Bar className=\"h-3 w-1/3\" />\n </div>\n ))}\n </div>\n )}\n {preview && (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex h-[14.4px] items-center\">\n <Bar className=\"h-2.5 w-28\" />\n </div>\n <div className=\"flex h-[71.6px] flex-col justify-center gap-2 rounded-md border border-border-subtle p-2\">\n <Bar className=\"h-2.5 w-24\" />\n <Bar className=\"h-3 w-full\" />\n <Bar className=\"h-3 w-3/5\" />\n </div>\n </div>\n )}\n {footer !== 'none' && (\n <div className=\"flex min-h-6 items-center gap-2 border-t border-border-subtle pt-2\">\n {footer === 'pickers' ? (\n <>\n <Bar className=\"h-6 w-24 rounded-md\" />\n <Bar className=\"h-6 w-28 rounded-md\" />\n </>\n ) : footer === 'people' ? (\n <>\n <Bar className=\"size-4 rounded-full\" />\n <Bar className=\"h-3 w-40\" />\n </>\n ) : (\n <Bar className=\"h-3 w-40\" />\n )}\n </div>\n )}\n </Card>\n )\n}\n\n/**\n * Not available: one line, at compact's height, whichever layout was chosen.\n * Deleted and unreadable read the same (Widgets 2, Not in scope). Here the\n * way out stays: there is no title to click, and the app it lives in may\n * still open it for you.\n */\nexport function CardUnavailable({ kind, noun, app }: { kind: Thing['kind']; noun: string; app: string }) {\n return (\n <Card fill=\"none\" unreadable className=\"flex h-9 items-center gap-2 px-3\">\n <ThingIcon kind={kind} />\n <span className=\"min-w-0 flex-1 truncate text-body-2 text-text-muted\">{noun} \u2014 not available.</span>\n <span className=\"shrink-0 text-caption\">\n <Link href={HREF} variant=\"quiet\" external className=\"text-text-secondary\">\n Open in {app} \u2197\n </Link>\n </span>\n </Card>\n )\n}\n\n/* ------------------------------------------------------------ the part */\n\n/**\n * A block of a description, shared live (a part). No compact or detailed:\n * a pasted block link inserts the part itself (the-author-chooses-a-links-card,\n * Accepted). The same header as a detailed card: the key and the title of\n * the file it is part of, as the link.\n */\nexport function PartCard({ kind, heading, partKey, children, state = 'ready', noun, app }: { kind: Thing['kind']; heading: string; partKey?: string; children?: ReactNode; state?: 'ready' | 'loading' | 'unavailable'; noun: string; app: string }) {\n if (state === 'loading') return <CardLoading kind={kind} layout=\"detailed\" shape={{ summary: true, rows: 0, footer: 'none' }} />\n if (state === 'unavailable') return <CardUnavailable kind={kind} noun={`A part of this ${noun.toLowerCase()}`} app={app} />\n return (\n <Card fill=\"inset\" className=\"flex flex-col gap-2 p-3\">\n <Link href={HREF} variant=\"quiet\" className=\"flex min-w-0 items-center gap-2 text-body-2-strong text-text-primary\">\n <ThingIcon kind={kind} />\n {partKey && <Key>{partKey}</Key>}\n <span className=\"truncate\">{heading}</span>\n </Link>\n <div className=\"border-l-2 border-border-default pl-3\">{children}</div>\n </Card>\n )\n}\n\n/**\n * A comment's anchor: the part it is about, quoted above the comment.\n * Unchanged from today (the two apps already agree), with the deleted line in\n * the same muted voice as \"not available.\".\n */\nexport function CommentAnchor({ text }: { text?: string }) {\n if (text === undefined) return <div className=\"border-l-2 border-border-default pl-2 text-caption text-text-muted\">The part this is about was deleted.</div>\n return (\n <div className=\"border-l-2 border-border-strong pl-2 text-caption text-text-muted\">\n <span className=\"line-clamp-2 italic\">{text}</span>\n </div>\n )\n}\n\n/* ----------------------------------------------------------- attachment */\n\n/** An attachment's chip: a paperclip and the file's name. */\nexport function AttachmentChip({ name, state = 'ready' }: { name: string; state?: 'ready' | 'loading' | 'unavailable' }) {\n if (state === 'loading') {\n return (\n <InlineChip icon={<IconPaperclip size={14} stroke={1.5} aria-hidden />}>\n <SkeletonBar className=\"h-2.5 w-16\" />\n </InlineChip>\n )\n }\n if (state === 'unavailable') {\n return (\n <InlineChip icon={<IconPaperclip size={14} stroke={1.5} aria-hidden />} className=\"text-text-muted\">\n File, not available\n </InlineChip>\n )\n }\n return (\n <InlineChip icon={<IconPaperclip size={14} stroke={1.5} aria-hidden />} href={HREF} className=\"max-w-[24ch]\">\n <span className=\"truncate\">{name}</span>\n </InlineChip>\n )\n}\n", "/**\n * Widgets 2 prototype: the placeholder things every widget on these pages\n * draws. Words are placeholders (stories-and-pages.md); the kinds are named,\n * because telling them apart is what the prototype is for.\n */\nimport type { ThingKind } from '../KindIcon'\n\n/** The colours a status draws in, as the apps' manifests name them. */\nexport type StatusColour = 'neutral' | 'blue' | 'green' | 'muted'\n\nexport interface Status {\n label: string\n colour: StatusColour\n}\n\n/** One thing a link can stand for, with every field any app draws today. */\nexport interface Thing {\n /** The kinds the prototype covers, one more than KindIcon has: a page. */\n kind: ThingKind | 'page'\n /** The noun a card's corner says. */\n noun: string\n /** The app it opens in. */\n app: string\n title: string\n /** Its key, the way people say it: an issue's \"WID-2\". */\n key?: string\n /** The line under the title: the project an issue is in, a page's Folder. */\n subtitle?: string\n /** The opening of its description, a page's text, a message's words: what the apps draw today. */\n body?: string\n /**\n * A short summary of the file, one or two sentences (Miky, 15 Oct: detailed\n * shows the summary, not the opening of the long description). No file\n * carries one yet; it is its own project.\n */\n summary?: string\n status?: Status\n assignee?: string\n author?: string\n /** Everyone who wrote a page. */\n authors?: string[]\n comments?: number\n /**\n * The reader has something unread in its conversation: they are a member\n * and it moved since they last read it (SPEC \u00A711.8, membership-replaces-following).\n */\n unread?: boolean\n /** A project's issues, drawn as rows inside its detailed card. */\n children?: { title: string; key: string; status: Status; assignee?: string }[]\n /** A project's progress line. */\n progress?: string\n /** A project's progress as numbers, for the ring. */\n done?: { done: number; total: number }\n /** A topic: how many conversations, who is in it, and its latest one. */\n conversations?: number\n members?: string[]\n latest?: { author: string; body: string; at: string }\n updated?: string\n}\n\nconst TODO: Status = { label: 'Todo', colour: 'neutral' }\nconst DOING: Status = { label: 'In progress', colour: 'blue' }\nconst DONE: Status = { label: 'Done', colour: 'green' }\n\nconst PARAGRAPH =\n 'A description long enough to need more than one line, so the card has to choose how much of it to show and where to cut it short. The rest is there when you open it.'\n\nconst SUMMARY = 'A one-sentence summary of what this is for.'\n\nexport const ISSUE: Thing = {\n kind: 'issue',\n noun: 'Issue',\n app: 'Ship',\n title: 'Item one, with a title long enough to be cut short',\n key: 'ABC-2',\n subtitle: 'Group one',\n body: PARAGRAPH,\n summary: SUMMARY,\n status: DOING,\n assignee: 'Person One',\n comments: 4,\n unread: true,\n}\n\nexport const PROJECT: Thing = {\n kind: 'project',\n noun: 'Project',\n app: 'Ship',\n title: 'Group one',\n body: PARAGRAPH,\n summary: SUMMARY,\n status: DOING,\n assignee: 'Person Two',\n progress: '3 of 8 done',\n done: { done: 3, total: 8 },\n comments: 6,\n children: [\n { title: 'Item one', key: 'ABC-1', status: DONE, assignee: 'Person One' },\n { title: 'Item two', key: 'ABC-2', status: DOING, assignee: 'Person Two' },\n { title: 'Item three', key: 'ABC-3', status: TODO },\n ],\n}\n\nexport const TOPIC: Thing = {\n kind: 'topic',\n noun: 'Topic',\n app: 'Peek',\n title: 'Place one',\n conversations: 12,\n unread: true,\n members: ['Person One', 'Person Two', 'Person Three'],\n updated: '2h ago',\n latest: { author: 'Person Three', body: 'The latest conversation in the topic, as its first message reads. It may run to a second line before it is cut short.', at: '2h ago' },\n}\n\nexport const MESSAGE: Thing = {\n kind: 'message',\n noun: 'Message',\n app: 'Peek',\n title: 'Person Two',\n author: 'Person Two',\n body: 'A message of two sentences, written by someone in a conversation. It is the words the link points to.',\n updated: '10:42',\n}\n\nexport const PAGE: Thing = {\n kind: 'page',\n noun: 'Page',\n app: 'Leaf',\n title: 'Page one',\n subtitle: 'Folder one',\n body: PARAGRAPH,\n summary: SUMMARY,\n author: 'Person One',\n authors: ['Person One', 'Person Two'],\n comments: 2,\n updated: 'Edited yesterday',\n}\n\n/** A block of a description: drawn live, as the part it is. */\nexport const PART = {\n heading: 'Item one',\n noun: 'Issue',\n app: 'Ship',\n blocks: ['Heading of the part', 'A paragraph of the part, as it reads in the description right now.', 'A point in a list', 'Another point'],\n}\n\nexport const ATTACHMENT = { name: 'picture-one.png', size: 182_400, contentType: 'image/png' }\nexport const ATTACHMENT_FILE = { name: 'document-one.pdf', size: 1_240_000, contentType: 'application/pdf' }\n\n/** A file the reader cannot read: only its kind and app are known, from its address. */\nexport const UNREADABLE = { kind: 'issue' as const, noun: 'Issue', app: 'Ship', address: 'naddr1qqjxgdmzxy6r2vfs95cryvmp956x2etp94sns' }\n\n/** A small picture for the attachment, drawn rather than fetched. */\nexport const PICTURE =\n 'data:image/svg+xml;utf8,' +\n encodeURIComponent(\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"480\" height=\"300\"><rect width=\"480\" height=\"300\" fill=\"#8a94a6\"/><circle cx=\"360\" cy=\"90\" r=\"40\" fill=\"#d8dde6\"/><path d=\"M0 300 L170 120 L300 260 L380 190 L480 300 Z\" fill=\"#5d6778\"/></svg>',\n )\n"],
|
|
5
|
+
"mappings": ";AAwBA,SAAqB,iBAAiB,kBAAkB,iBAAiB,aAAa,cAAc,cAAc,qBAAqB;AAEvI,SAAS,cAAc;AACvB,SAAS,mBAAmB;AAC5B,SAAS,YAAY;AACrB,SAAS,UAAU;AACnB,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAC5B,SAAS,cAAc;AACvB,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAkBtB,SAoHA,UAnHE,KADF;AAfJ,IAAM,OAAO;AACb,IAAM,OAAO,MAAM;AAAC;AAIpB,IAAM,cAA+E;AAAA,EACnF,SAAS,EAAE,MAAM,kBAAkB,MAAM,sBAAsB;AAAA,EAC/D,MAAM,EAAE,MAAM,iBAAiB,MAAM,oBAAoB;AAAA,EACzD,OAAO,EAAE,MAAM,iBAAiB,MAAM,uBAAuB;AAAA,EAC7D,OAAO,EAAE,MAAM,aAAa,MAAM,kBAAkB;AACtD;AAGO,SAAS,WAAW,EAAE,OAAO,GAAuB;AACzD,SACE,qBAAC,UAAK,WAAU,qCAAoC,OAAO,OAAO,OAChE;AAAA,wBAAC,cAAW,QAAgB;AAAA,IAC5B,oBAAC,UAAK,WAAU,WAAW,iBAAO,OAAM;AAAA,KAC1C;AAEJ;AAGA,SAAS,WAAW,EAAE,OAAO,GAAuB;AAClD,QAAM,EAAE,MAAM,KAAK,IAAI,YAAY,OAAO,MAAM;AAChD,SAAO,oBAAC,QAAK,MAAM,IAAI,QAAQ,KAAK,WAAW,GAAG,YAAY,IAAI,GAAG,eAAW,MAAC;AACnF;AAGO,SAAS,UAAU,EAAE,MAAM,OAAO,IAAI,OAAO,YAAY,GAA4E;AAC1I,MAAI,SAAS,OAAQ,QAAO,oBAAC,gBAAa,MAAY,QAAQ,KAAK,WAAW,GAAG,YAAY,SAAS,eAAe,qBAAqB,GAAG,eAAW,MAAC;AACzJ,SAAO,oBAAC,YAAS,MAAY,MAAY,MAAY;AACvD;AAGA,SAAS,IAAI,EAAE,SAAS,GAA4B;AAClD,SAAO,oBAAC,UAAK,WAAU,sDAAsD,UAAS;AACxF;AAMO,SAAS,aAAa,EAAE,MAAM,MAAM,GAAoC;AAC7E,QAAM,OAAO;AACb,QAAM,SAAS;AACf,QAAM,KAAK,OAAO,UAAU;AAC5B,QAAM,IAAI,IAAI,KAAK,KAAK;AACxB,SACE,qBAAC,UAAK,WAAU,yFAAwF,OAAO,GAAG,IAAI,OAAO,KAAK,SAChI;AAAA,yBAAC,SAAI,OAAO,MAAM,QAAQ,MAAM,SAAS,OAAO,IAAI,IAAI,IAAI,IAAI,WAAU,uBAAsB,eAAW,MACzG;AAAA,0BAAC,YAAO,IAAI,OAAO,GAAG,IAAI,OAAO,GAAG,GAAM,MAAK,QAAO,aAAa,QAAQ,WAAU,yBAAwB;AAAA,MAC7G,oBAAC,YAAO,IAAI,OAAO,GAAG,IAAI,OAAO,GAAG,GAAM,MAAK,QAAO,aAAa,QAAQ,eAAc,SAAQ,iBAAiB,GAAI,IAAI,OAAQ,KAAK,IAAI,CAAC,IAAI,WAAU,0BAAyB;AAAA,OACrL;AAAA,IACC;AAAA,IAAK;AAAA,IAAE;AAAA,KACV;AAEJ;AASA,IAAM,oBAAoB;AAS1B,SAAS,SAAS,EAAE,OAAO,SAAS,OAAO,OAAO,WAAW,GAAuD;AAClH,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM;AAAA,MACN,SAAQ;AAAA,MACR,WAAW;AAAA,QACT;AAAA,QACA,SAAS,kCAAkC;AAAA,MAC7C;AAAA,MAEA;AAAA,4BAAC,gBAAa,MAAM,IAAI,QAAQ,KAAK,eAAW,MAAC;AAAA,QAChD;AAAA,QACD,oBAAC,UAAK,WAAU,WAAW,mBAAS,GAAG,IAAI,0CAAqC,GAAG,IAAI,iCAA2B;AAAA,QACjH,UAAU,oBAAC,aAAU,WAAU,iBAAgB;AAAA;AAAA;AAAA,EAClD;AAEJ;AAMA,SAAS,cAAc,EAAE,MAAM,GAAqB;AAClD,SACE,qBAAC,UAAK,WAAU,2CACd;AAAA,wBAAC,UAAK,WAAU,oCAAoC,gBAAM,SAAQ;AAAA,IAClE,oBAAC,YAAS,OAAO,MAAM,iBAAiB,GAAG,QAAQ,MAAM,QAAQ,MAAK,iBAAgB;AAAA,KACxF;AAEJ;AAEA,IAAM,SAAS,CAAC,QAAkB,CAAC,MAAM,MAAM,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE;AAQvE,SAAS,QAAQ,EAAE,OAAO,WAAW,MAAM,GAAyC;AAClF,MAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,MAAI,UAAU;AACZ,WACE,qBAAC,UAAK,WAAU,wEACd;AAAA,2BAAC,UAAK,WAAU,2CACd;AAAA,4BAAC,cAAW,QAAQ,MAAM,QAAQ;AAAA,QACjC,MAAM,OAAO;AAAA,SAChB;AAAA,MACA,qBAAC,UAAK,WAAU,0CACd;AAAA,4BAAC,UAAO,MAAM,MAAM,UAAU,MAAM,IAAI;AAAA,QACxC,oBAAC,UAAK,WAAU,YAAY,gBAAM,YAAY,cAAa;AAAA,SAC7D;AAAA,OACF;AAAA,EAEJ;AACA,SACE,iCACE;AAAA,wBAAC,UAAO,MAAK,SAAQ,WAAU,UAAS,OAAM,KAAI,UAAU,MAAM,WAAU,UAAS,SAAS,CAAC,EAAE,OAAO,KAAK,OAAO,MAAM,OAAO,OAAO,SAAS,oBAAC,cAAW,QAAQ,MAAM,QAAQ,EAAG,CAAC,GAAG;AAAA,IAC1L;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,OAAM;AAAA,QACN,UAAU;AAAA,QACV,WAAW,MAAM,SAAS,YAAY,SAAS;AAAA,QAC/C,SAAS,CAAC,EAAE,OAAO,KAAK,OAAO,MAAM,YAAY,cAAc,SAAS,oBAAC,UAAO,MAAM,MAAM,UAAU,MAAM,IAAI,EAAG,CAAC;AAAA;AAAA,IACtH;AAAA,KACF;AAEJ;AAYA,SAAS,KAAK,EAAE,OAAO,OAAO,MAAM,GAAqC;AACvE,MAAI,MAAM,SAAS,UAAW,QAAO,oBAAC,UAAO,MAAM,MAAM,QAAQ,MAAM,IAAI;AAC3E,SAAO,oBAAC,aAAU,MAAM,MAAM,MAAM,MAAM,OAAO,KAAK,IAAI,MAAM,OAAO,YAAY,aAAa;AAClG;AAOO,SAAS,cAAc,EAAE,OAAO,QAAQ,SAAS,UAAU,MAAM,GAAuB;AAC7F,MAAI,UAAU,WAAW;AACvB,WACE,oBAAC,cAAW,MAAM,oBAAC,aAAU,MAAM,MAAM,MAAM,MAAM,IAAI,MAAK,WAAU,GACtE,8BAAC,eAAY,WAAU,cAAa,GACtC;AAAA,EAEJ;AACA,MAAI,UAAU,eAAe;AAC3B,WACE,qBAAC,cAAW,MAAM,oBAAC,aAAU,MAAM,MAAM,MAAM,MAAM,IAAI,MAAK,WAAU,GAAI,WAAU,mBACnF;AAAA,YAAM;AAAA,MAAK;AAAA,OACd;AAAA,EAEJ;AACA,QAAM,OACJ,qBAAC,cAAW,MAAM,oBAAC,QAAK,OAAc,MAAI,MAAC,GAAI,MAAM,MAAM,WAAU,gBAClE;AAAA,UAAM,OAAO,oBAAC,OAAK,gBAAM,KAAI;AAAA,IAC9B,oBAAC,UAAK,WAAU,YAAY,gBAAM,SAAS,YAAY,GAAG,MAAM,MAAM,KAAK,MAAM,IAAI,KAAK,MAAM,OAAM;AAAA,IACrG,MAAM,UAAU,oBAAC,cAAW,QAAQ,MAAM,QAAQ;AAAA,KACrD;AAEF,SAAO,UAAU,oBAAC,gBAAa,OAAe,gBAAK,IAAkB;AACvE;AAOO,SAAS,YAAY,EAAE,OAAO,UAAU,MAAM,GAAwC;AAC3F,QAAM,OACJ,qBAAC,QAAK,MAAK,SAAQ,OAAM,YAAW,WAAU,6CAC5C;AAAA,wBAAC,QAAK,OAAc;AAAA,IACnB,MAAM,SAAS,YACd,qBAAC,UAAK,WAAU,wDACd;AAAA,0BAAC,UAAK,WAAU,iDAAiD,gBAAM,QAAO;AAAA,MAC9E,oBAAC,QAAK,MAAM,MAAM,SAAQ,SAAQ,OAAK,MAAC,UAAQ,MAAC,WAAU,uBACxD,gBAAM,MACT;AAAA,OACF,IAEA,iCACG;AAAA,YAAM,OAAO,oBAAC,OAAK,gBAAM,KAAI;AAAA,MAC9B,oBAAC,UAAK,WAAU,iDACd,8BAAC,QAAK,MAAM,MAAM,SAAQ,SAAQ,OAAK,MAAC,UAAQ,MAAC,WAAU,kBACxD,gBAAM,OACT,GACF;AAAA,OACF;AAAA,IAED,MAAM,SAAS,WAAW,oBAAC,iBAAc,OAAc;AAAA,IACvD,MAAM,SAAS,UAAU,oBAAC,UAAK,WAAU,6CAA6C,gBAAM,SAAQ;AAAA,IACpG,MAAM,SAAS,aAAa,oBAAC,UAAK,WAAU,yCAAyC,gBAAM,SAAQ;AAAA,IAEnG,MAAM,UAAU,MAAM,aAAa,UAAa,oBAAC,YAAS,OAAO,MAAM,UAAU,QAAM,MAAC;AAAA,IACxF,MAAM,UAAU,MAAM,SAAS,WAAW,oBAAC,cAAW,QAAQ,MAAM,QAAQ;AAAA,IAC5E,MAAM,QAAQ,oBAAC,gBAAa,MAAM,MAAM,KAAK,MAAM,OAAO,MAAM,KAAK,OAAO;AAAA,IAC5E,MAAM,YAAY,oBAAC,UAAO,MAAM,MAAM,UAAU,MAAM,IAAI;AAAA,IAC1D,MAAM,WAAW,oBAAC,eAAY,SAAS,OAAO,MAAM,OAAO,GAAG,MAAM,IAAI;AAAA,IACxE,MAAM,WAAW,oBAAC,eAAY,SAAS,OAAO,MAAM,OAAO,GAAG,MAAM,IAAI;AAAA,KAC3E;AAEF,SAAO,UACL,oBAAC,gBAAa,OAAc,OAAK,MAC9B,gBACH,IAEA;AAEJ;AAYO,SAAS,aAAa,EAAE,OAAO,OAAO,OAAO,WAAW,KAAK,GAAyD;AAC3H,QAAM,OACJ,iCACE;AAAA,yBAAC,SAAI,WAAU,0CAEb;AAAA,2BAAC,QAAK,MAAM,MAAM,SAAQ,SAAQ,WAAU,+EAC1C;AAAA,4BAAC,aAAU,MAAM,MAAM,MAAM;AAAA,QAC7B,oBAAC,UAAK,WAAU,YAAY,gBAAM,OAAM;AAAA,SAC1C;AAAA,MACC,MAAM,QAAQ,oBAAC,gBAAa,MAAM,MAAM,KAAK,MAAM,OAAO,MAAM,KAAK,OAAO;AAAA,MAC5E,MAAM,WAAW,oBAAC,eAAY,SAAS,OAAO,MAAM,OAAO,GAAG,MAAM,IAAI;AAAA,OAC3E;AAAA,KAEE,MAAM,OAAO,MAAM,aAAa,oBAAC,OAAE,WAAU,+CAA+C,WAAC,MAAM,KAAK,MAAM,QAAQ,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK,GAAE;AAAA,IACrJ,MAAM,WAAW,oBAAC,OAAE,WAAU,gDAAgD,gBAAM,SAAQ;AAAA,IAC5F,MAAM,YACL,oBAAC,SAAI,WAAU,sFACZ,gBAAM,SAAS,IAAI,CAAC,UACnB,qBAAC,SAAoB,WAAU,gEAE7B;AAAA,0BAAC,cAAW,QAAQ,MAAM,QAAQ;AAAA,MAClC,oBAAC,OAAK,gBAAM,KAAI;AAAA,MAEhB,oBAAC,UAAK,WAAU,0CACd,8BAAC,QAAK,MAAM,MAAM,SAAQ,SAAQ,OAAK,MAAC,UAAQ,MAAC,WAAU,kBACxD,gBAAM,OACT,GACF;AAAA,MACC,MAAM,WAAW,oBAAC,UAAO,MAAM,MAAM,UAAU,MAAM,IAAI,IAAK,oBAAC,UAAK,WAAU,mBAAkB,eAAW,MAAC;AAAA,SAVrG,MAAM,GAWhB,CACD,GACH;AAAA,IAED,MAAM,UACL,qBAAC,SAAI,WAAU,uBAKb;AAAA,0BAAC,UAAK,WAAU,gCAA+B,iCAAmB;AAAA,MAClE,qBAAC,SAAI,WAAU,yDACb;AAAA,4BAAC,UAAO,MAAM,MAAM,OAAO,QAAQ,MAAM,IAAI;AAAA,QAC7C,qBAAC,SAAI,WAAU,kBACb;AAAA,+BAAC,SAAI,WAAU,0CACb;AAAA,gCAAC,UAAK,WAAU,qBAAqB,gBAAM,OAAO,QAAO;AAAA,YACzD,oBAAC,UAAK,WAAU,mBAAmB,gBAAM,OAAO,IAAG;AAAA,aACrD;AAAA,UACA,oBAAC,OAAE,WAAU,gDAAgD,gBAAM,OAAO,MAAK;AAAA,WACjF;AAAA,SACF;AAAA,OACF;AAAA,IAEF,qBAAC,SAAI,WAAU,sEACX;AAAA,aAAM,SAAS,WAAW,MAAM,SAAS,cAAc,oBAAC,WAAQ,OAAc,UAAoB;AAAA,MACnG,MAAM,SAAS,WACd,oBAAC,UAAK,WAAU,2BACd,+BAAC,UAAK,WAAU,oCAAmC;AAAA;AAAA,QAAS,MAAM;AAAA,SAAQ,GAC5E;AAAA,MAGD,MAAM,WACL,qBAAC,UAAK,WAAU,oEACd;AAAA,4BAAC,eAAY,SAAS,OAAO,MAAM,OAAO,GAAG,MAAM,IAAI;AAAA,QACvD,oBAAC,UAAK,WAAU,YAAY,gBAAM,SAAQ;AAAA,SAC5C;AAAA,MAED,MAAM,SAAS,WACd,oBAAC,UAAK,WAAU,gBACd,8BAAC,YAAS,OAAO,MAAM,iBAAiB,GAAG,QAAQ,MAAM,QAAQ,MAAK,iBAAgB,GACxF;AAAA,MAED,MAAM,aAAa,UAClB,oBAAC,UAAK,WAAU,gBACd,8BAAC,YAAS,OAAO,MAAM,UAAU,QAAQ,MAAM,QAAQ,GACzD;AAAA,OAEJ;AAAA,KACF;AAEF,MAAI,KAAM,QAAO,oBAAC,SAAI,WAAU,2BAA2B,gBAAK;AAChE,SACE,oBAAC,QAAK,MAAK,SAAQ,aAAU,YAAW,WAAU,2BAC/C,gBACH;AAEJ;AAGO,SAAS,aAAa,EAAE,OAAO,QAAQ,OAAO,SAAS,GAA2D;AAEvH,SACE,oBAAC,eAAY,MAAK,UAAS,SAAS,oBAAC,gBAAa,OAAc,MAAI,MAAC,GAAI,kBAAkB,QAAQ,kDAAkD,cAClJ,UACH;AAEJ;AAGO,SAAS,iBAAiB,EAAE,MAAM,GAAqB;AAC5D,SACE,oBAAC,aAAU,WAAU,iBACnB,8BAAC,gBAAa,OAAc,MAAI,MAAC,GACnC;AAEJ;AAMO,SAAS,YAAY,EAAE,MAAM,GAAqB;AACvD,SACE,qBAAC,QAAK,MAAK,SAAQ,WAAU,2BAC3B;AAAA,yBAAC,SAAI,WAAU,2BACb;AAAA,0BAAC,UAAO,MAAM,MAAM,QAAQ,MAAM,IAAI;AAAA,MACtC,oBAAC,UAAK,WAAU,wCAAwC,gBAAM,QAAO;AAAA,MACrE,oBAAC,QAAK,MAAM,MAAM,SAAQ,SAAQ,WAAU,gCACzC,gBAAM,SACT;AAAA,OACF;AAAA,IACA,oBAAC,OAAE,WAAU,8CAA8C,gBAAM,MAAK;AAAA,KACxE;AAEJ;AAeO,SAAS,eAAe,OAA4B;AACzD,SAAO;AAAA,IACL,UAAU,CAAC,EAAE,MAAM,YAAY,MAAM;AAAA,IACrC,SAAS,CAAC,CAAC,MAAM;AAAA,IACjB,MAAM,MAAM,UAAU,UAAU;AAAA,IAChC,SAAS,CAAC,CAAC,MAAM;AAAA,IACjB,MAAM,CAAC,CAAC,MAAM;AAAA,IACd,QAAQ,MAAM,SAAS,WAAW,MAAM,SAAS,YAAY,YAAY,MAAM,UAAU,WAAW;AAAA,EACtG;AACF;AAGA,SAAS,IAAI,EAAE,UAAU,GAA2B;AAClD,SAAO,oBAAC,eAAY,WAAW,GAAG,gBAAgB,SAAS,GAAG;AAChE;AAMO,SAAS,YAAY,EAAE,MAAM,QAAQ,QAAQ,CAAC,EAAE,GAAsE;AAC3H,MAAI,WAAW,WAAW;AACxB,WACE,qBAAC,QAAK,MAAK,SAAQ,eAAW,MAAC,aAAU,WAAU,WAAU,wDAC3D;AAAA,0BAAC,aAAU,MAAY;AAAA,MACvB,oBAAC,OAAI,WAAU,aAAY;AAAA,MAC3B,oBAAC,OAAI,WAAU,+BAA8B;AAAA,OAC/C;AAAA,EAEJ;AACA,QAAM,EAAE,WAAW,OAAO,UAAU,MAAM,OAAO,GAAG,UAAU,OAAO,OAAO,OAAO,SAAS,OAAO,IAAI;AACvG,SACE,qBAAC,QAAK,MAAK,SAAQ,eAAW,MAAC,aAAU,WAAU,WAAU,+CAC3D;AAAA,yBAAC,SAAI,WAAU,sCACb;AAAA,0BAAC,aAAU,MAAY;AAAA,MACvB,oBAAC,OAAI,WAAU,eAAc;AAAA,MAC5B,QAAQ,oBAAC,OAAI,WAAU,+BAA8B;AAAA,OACxD;AAAA,IACC,YACC,oBAAC,SAAI,WAAU,2CACb,8BAAC,OAAI,WAAU,cAAa,GAC9B;AAAA,IAED,WACC,oBAAC,SAAI,WAAU,gCACb,8BAAC,OAAI,WAAU,aAAY,GAC7B;AAAA,IAED,OAAO,KACN,oBAAC,SAAI,WAAU,sFACZ,gBAAM,KAAK,EAAE,QAAQ,KAAK,GAAG,CAAC,GAAG,MAChC,oBAAC,SAAY,WAAU,8BACrB,8BAAC,OAAI,WAAU,aAAY,KADnB,CAEV,CACD,GACH;AAAA,IAED,WACC,qBAAC,SAAI,WAAU,uBACb;AAAA,0BAAC,SAAI,WAAU,gCACb,8BAAC,OAAI,WAAU,cAAa,GAC9B;AAAA,MACA,qBAAC,SAAI,WAAU,4FACb;AAAA,4BAAC,OAAI,WAAU,cAAa;AAAA,QAC5B,oBAAC,OAAI,WAAU,cAAa;AAAA,QAC5B,oBAAC,OAAI,WAAU,aAAY;AAAA,SAC7B;AAAA,OACF;AAAA,IAED,WAAW,UACV,oBAAC,SAAI,WAAU,sEACZ,qBAAW,YACV,iCACE;AAAA,0BAAC,OAAI,WAAU,uBAAsB;AAAA,MACrC,oBAAC,OAAI,WAAU,uBAAsB;AAAA,OACvC,IACE,WAAW,WACb,iCACE;AAAA,0BAAC,OAAI,WAAU,uBAAsB;AAAA,MACrC,oBAAC,OAAI,WAAU,YAAW;AAAA,OAC5B,IAEA,oBAAC,OAAI,WAAU,YAAW,GAE9B;AAAA,KAEJ;AAEJ;AAQO,SAAS,gBAAgB,EAAE,MAAM,MAAM,IAAI,GAAuD;AACvG,SACE,qBAAC,QAAK,MAAK,QAAO,YAAU,MAAC,WAAU,oCACrC;AAAA,wBAAC,aAAU,MAAY;AAAA,IACvB,qBAAC,UAAK,WAAU,uDAAuD;AAAA;AAAA,MAAK;AAAA,OAAiB;AAAA,IAC7F,oBAAC,UAAK,WAAU,yBACd,+BAAC,QAAK,MAAM,MAAM,SAAQ,SAAQ,UAAQ,MAAC,WAAU,uBAAsB;AAAA;AAAA,MAChE;AAAA,MAAI;AAAA,OACf,GACF;AAAA,KACF;AAEJ;AAUO,SAAS,SAAS,EAAE,MAAM,SAAS,SAAS,UAAU,QAAQ,SAAS,MAAM,IAAI,GAA6J;AACnP,MAAI,UAAU,UAAW,QAAO,oBAAC,eAAY,MAAY,QAAO,YAAW,OAAO,EAAE,SAAS,MAAM,MAAM,GAAG,QAAQ,OAAO,GAAG;AAC9H,MAAI,UAAU,cAAe,QAAO,oBAAC,mBAAgB,MAAY,MAAM,kBAAkB,KAAK,YAAY,CAAC,IAAI,KAAU;AACzH,SACE,qBAAC,QAAK,MAAK,SAAQ,WAAU,2BAC3B;AAAA,yBAAC,QAAK,MAAM,MAAM,SAAQ,SAAQ,WAAU,wEAC1C;AAAA,0BAAC,aAAU,MAAY;AAAA,MACtB,WAAW,oBAAC,OAAK,mBAAQ;AAAA,MAC1B,oBAAC,UAAK,WAAU,YAAY,mBAAQ;AAAA,OACtC;AAAA,IACA,oBAAC,SAAI,WAAU,yCAAyC,UAAS;AAAA,KACnE;AAEJ;AAOO,SAAS,cAAc,EAAE,KAAK,GAAsB;AACzD,MAAI,SAAS,OAAW,QAAO,oBAAC,SAAI,WAAU,sEAAqE,iDAAmC;AACtJ,SACE,oBAAC,SAAI,WAAU,qEACb,8BAAC,UAAK,WAAU,uBAAuB,gBAAK,GAC9C;AAEJ;AAKO,SAAS,eAAe,EAAE,MAAM,QAAQ,QAAQ,GAAkE;AACvH,MAAI,UAAU,WAAW;AACvB,WACE,oBAAC,cAAW,MAAM,oBAAC,iBAAc,MAAM,IAAI,QAAQ,KAAK,eAAW,MAAC,GAClE,8BAAC,eAAY,WAAU,cAAa,GACtC;AAAA,EAEJ;AACA,MAAI,UAAU,eAAe;AAC3B,WACE,oBAAC,cAAW,MAAM,oBAAC,iBAAc,MAAM,IAAI,QAAQ,KAAK,eAAW,MAAC,GAAI,WAAU,mBAAkB,iCAEpG;AAAA,EAEJ;AACA,SACE,oBAAC,cAAW,MAAM,oBAAC,iBAAc,MAAM,IAAI,QAAQ,KAAK,eAAW,MAAC,GAAI,MAAM,MAAM,WAAU,gBAC5F,8BAAC,UAAK,WAAU,YAAY,gBAAK,GACnC;AAEJ;;;ACvhBA,IAAM,OAAe,EAAE,OAAO,QAAQ,QAAQ,UAAU;AACxD,IAAM,QAAgB,EAAE,OAAO,eAAe,QAAQ,OAAO;AAC7D,IAAM,OAAe,EAAE,OAAO,QAAQ,QAAQ,QAAQ;AAEtD,IAAM,YACJ;AAEF,IAAM,UAAU;AAET,IAAM,QAAe;AAAA,EAC1B,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AAAA,EACP,KAAK;AAAA,EACL,UAAU;AAAA,EACV,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,UAAU;AAAA,EACV,QAAQ;AACV;AAEO,IAAM,UAAiB;AAAA,EAC5B,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,UAAU;AAAA,EACV,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE;AAAA,EAC1B,UAAU;AAAA,EACV,UAAU;AAAA,IACR,EAAE,OAAO,YAAY,KAAK,SAAS,QAAQ,MAAM,UAAU,aAAa;AAAA,IACxE,EAAE,OAAO,YAAY,KAAK,SAAS,QAAQ,OAAO,UAAU,aAAa;AAAA,IACzE,EAAE,OAAO,cAAc,KAAK,SAAS,QAAQ,KAAK;AAAA,EACpD;AACF;AAEO,IAAM,QAAe;AAAA,EAC1B,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AAAA,EACP,eAAe;AAAA,EACf,QAAQ;AAAA,EACR,SAAS,CAAC,cAAc,cAAc,cAAc;AAAA,EACpD,SAAS;AAAA,EACT,QAAQ,EAAE,QAAQ,gBAAgB,MAAM,yHAAyH,IAAI,SAAS;AAChL;AAEO,IAAM,UAAiB;AAAA,EAC5B,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,SAAS;AACX;AAEO,IAAM,OAAc;AAAA,EACzB,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AAAA,EACP,UAAU;AAAA,EACV,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS,CAAC,cAAc,YAAY;AAAA,EACpC,UAAU;AAAA,EACV,SAAS;AACX;AAGO,IAAM,OAAO;AAAA,EAClB,SAAS;AAAA,EACT,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ,CAAC,uBAAuB,sEAAsE,qBAAqB,eAAe;AAC5I;AAEO,IAAM,aAAa,EAAE,MAAM,mBAAmB,MAAM,QAAS,aAAa,YAAY;AACtF,IAAM,kBAAkB,EAAE,MAAM,oBAAoB,MAAM,OAAW,aAAa,kBAAkB;AAGpG,IAAM,aAAa,EAAE,MAAM,SAAkB,MAAM,SAAS,KAAK,QAAQ,SAAS,8CAA8C;AAGhI,IAAM,UACX,6BACA;AAAA,EACE;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@estiva-app/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.72.0-widgets2.0",
|
|
4
4
|
"description": "Estiva's design tokens (the contract) and a small set of primitives (a convenience) for every Estiva app.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
"types": "./dist/editor.d.ts",
|
|
30
30
|
"default": "./dist/editor.js"
|
|
31
31
|
},
|
|
32
|
+
"./widgets-2": {
|
|
33
|
+
"types": "./dist/widgets-2.d.ts",
|
|
34
|
+
"default": "./dist/widgets-2.js"
|
|
35
|
+
},
|
|
32
36
|
"./gates": {
|
|
33
37
|
"types": "./dist/gates/index.d.ts",
|
|
34
38
|
"default": "./dist/gates/index.js"
|
package/registry.json
CHANGED
package/src/ReferenceMenu.tsx
CHANGED
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
* Two parts: the extension `ReferenceMenu` holds which chip the menu is open
|
|
22
22
|
* on, and `ReferenceMenuView` draws it beside `EditorContent`. Pair them with
|
|
23
23
|
* `ReferenceNode` and `ReferenceCards`.
|
|
24
|
+
*
|
|
25
|
+
* why: https://github.com/estiva-app/estiva-docs/blob/main/decisions/clicking-a-chip-while-editing-opens-a-menu.md
|
|
24
26
|
*/
|
|
25
27
|
import { useCallback } from 'react'
|
|
26
28
|
import { Extension, type Editor } from '@tiptap/core'
|
package/src/gates/gates.test.ts
CHANGED
|
@@ -413,7 +413,8 @@ describe('gates:status', () => {
|
|
|
413
413
|
expect(out).toContain('✅ UIG-2')
|
|
414
414
|
expect(out).toContain('⬜ UIG-9')
|
|
415
415
|
const json = JSON.parse(await runStatus({ root: dir, json: true }))
|
|
416
|
-
|
|
416
|
+
// A prerelease (`1.2.0-name.0`, published on the `concept` dist-tag) is a version too.
|
|
417
|
+
expect(json.engine).toMatch(/^@estiva-app\/ui@\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/)
|
|
417
418
|
})
|
|
418
419
|
|
|
419
420
|
it('finds the checks file beside the app, and still reads the repo from its top (Ship, UIG-32)', async () => {
|