pixelize-design-library 2.3.12 → 2.3.14
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/.cursor/modules/data-display/MODULE.md +2 -0
- package/dist/Components/Timeline/Timeline.d.ts +1 -1
- package/dist/Components/Timeline/Timeline.d.ts.map +1 -1
- package/dist/Components/Timeline/Timeline.js +54 -4
- package/dist/Components/Timeline/TimelineProps.d.ts +23 -0
- package/dist/Components/Timeline/TimelineProps.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -12,6 +12,8 @@ Tag, Timeline, Reorder, Divider, Trail.
|
|
|
12
12
|
|
|
13
13
|
## Key rules
|
|
14
14
|
|
|
15
|
+
- Timeline: each event card renders its manual notes from `event.notes` (`TimelineNote[]` — `log_note_id`, `title`, `note`, `attachments[]`, `created_by`, `created_at`). Adding a note is event-scoped via the per-card "Add note" button → `onAddNote(note, title, files, event, index)`; the consumer persists it against `event.logs_id` and re-supplies it back in `event.notes`. Attachments show as links opening `attachment.url`.
|
|
16
|
+
- Timeline notes support edit + delete: hovering a note shows edit/delete icons → `onEditNote(logNoteId, note, title, files, event, index)` (inline `NoteTextArea`) and `onDeleteNote(logNoteId, event, index)` (consumer owns any confirm dialog). Loading props: `addNoteLoading`/`editNoteLoading` keep the editor open with a Save spinner until the request resolves (then auto-close); `deletingNoteId` shows a spinner on the note being deleted. With no loading props wired, the add editor closes immediately on submit (back-compat).
|
|
15
17
|
- Trail includes editable cell demos
|
|
16
18
|
- Tag styling lives in `Tag.styles.tsx` (Chakra component theme), not hardcoded in `Tag.tsx`
|
|
17
19
|
- Tag sizes: `xs | sm | md | lg`; variants: `solid | outline | subtle`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { TimelineProps } from "./TimelineProps";
|
|
2
|
-
declare const Timeline: ({ timelineEvents, onEventClick, onAddNote, showAddNote }: TimelineProps) => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
declare const Timeline: ({ timelineEvents, onEventClick, onAddNote, onEditNote, onDeleteNote, showAddNote, addNoteLoading, editNoteLoading, deletingNoteId, }: TimelineProps) => import("react/jsx-runtime").JSX.Element;
|
|
3
3
|
export default Timeline;
|
|
4
4
|
//# sourceMappingURL=Timeline.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Timeline.d.ts","sourceRoot":"","sources":["../../../src/Components/Timeline/Timeline.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Timeline.d.ts","sourceRoot":"","sources":["../../../src/Components/Timeline/Timeline.tsx"],"names":[],"mappings":"AAqBA,OAAO,EAAgC,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAM9E,QAAA,MAAM,QAAQ,GAAI,sIAUf,aAAa,4CA0wBf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -10,12 +10,29 @@ const useCustomTheme_1 = require("../../Theme/useCustomTheme");
|
|
|
10
10
|
const functions_1 = require("../../Utils/functions");
|
|
11
11
|
const NoteTextArea_1 = __importDefault(require("../NoteTextArea/NoteTextArea"));
|
|
12
12
|
const react_2 = require("react");
|
|
13
|
-
const Timeline = ({ timelineEvents, onEventClick, onAddNote, showAddNote = false }) => {
|
|
13
|
+
const Timeline = ({ timelineEvents, onEventClick, onAddNote, onEditNote, onDeleteNote, showAddNote = false, addNoteLoading, editNoteLoading, deletingNoteId, }) => {
|
|
14
14
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
15
15
|
const theme = (0, useCustomTheme_1.useCustomTheme)();
|
|
16
16
|
const colors = (_a = theme.colors) !== null && _a !== void 0 ? _a : {};
|
|
17
17
|
const isMobile = (0, react_1.useBreakpointValue)({ base: true, md: false });
|
|
18
18
|
const [activeNoteEventIndex, setActiveNoteEventIndex] = (0, react_2.useState)(null);
|
|
19
|
+
const [activeEditNoteId, setActiveEditNoteId] = (0, react_2.useState)(null);
|
|
20
|
+
// Auto-close the add editor once the create request finishes (true -> false).
|
|
21
|
+
const prevAddLoading = (0, react_2.useRef)(addNoteLoading);
|
|
22
|
+
(0, react_2.useEffect)(() => {
|
|
23
|
+
if (prevAddLoading.current && !addNoteLoading) {
|
|
24
|
+
setActiveNoteEventIndex(null);
|
|
25
|
+
}
|
|
26
|
+
prevAddLoading.current = addNoteLoading;
|
|
27
|
+
}, [addNoteLoading]);
|
|
28
|
+
// Auto-close the edit editor once the update request finishes.
|
|
29
|
+
const prevEditLoading = (0, react_2.useRef)(editNoteLoading);
|
|
30
|
+
(0, react_2.useEffect)(() => {
|
|
31
|
+
if (prevEditLoading.current && !editNoteLoading) {
|
|
32
|
+
setActiveEditNoteId(null);
|
|
33
|
+
}
|
|
34
|
+
prevEditLoading.current = editNoteLoading;
|
|
35
|
+
}, [editNoteLoading]);
|
|
19
36
|
const formatTimestamp = (timestamp, type) => {
|
|
20
37
|
if (typeof timestamp === "string" && !timestamp.match(/^\d+$/)) {
|
|
21
38
|
const date = new Date(timestamp);
|
|
@@ -142,10 +159,37 @@ const Timeline = ({ timelineEvents, onEventClick, onAddNote, showAddNote = false
|
|
|
142
159
|
if (!timelineEvents || timelineEvents.length === 0) {
|
|
143
160
|
return ((0, jsx_runtime_1.jsxs)(react_1.Flex, { direction: "column", align: "center", justify: "center", py: 12, gap: 2, color: (_b = colors.gray) === null || _b === void 0 ? void 0 : _b[500], children: [(0, jsx_runtime_1.jsx)(react_1.Box, { boxSize: "2.75rem", borderRadius: "full", bg: (_c = colors.gray) === null || _c === void 0 ? void 0 : _c[100], display: "flex", alignItems: "center", justifyContent: "center", color: (_d = colors.gray) === null || _d === void 0 ? void 0 : _d[400], children: (0, jsx_runtime_1.jsx)(lucide_react_1.Volleyball, { size: 20 }) }), (0, jsx_runtime_1.jsx)(react_1.Text, { fontSize: "0.875rem", fontWeight: 500, children: "No timeline events to display" })] }));
|
|
144
161
|
}
|
|
162
|
+
// A single manual note attached to a log — read view + hover edit/delete,
|
|
163
|
+
// swapping to an inline NoteTextArea while editing.
|
|
164
|
+
const NoteItem = ({ note, event, index, }) => {
|
|
165
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
|
|
166
|
+
const [hovered, setHovered] = (0, react_2.useState)(false);
|
|
167
|
+
const isEditing = activeEditNoteId === note.log_note_id;
|
|
168
|
+
const isDeleting = deletingNoteId != null && deletingNoteId === note.log_note_id;
|
|
169
|
+
if (isEditing) {
|
|
170
|
+
return ((0, jsx_runtime_1.jsx)(react_1.Box, { children: (0, jsx_runtime_1.jsx)(NoteTextArea_1.default, { isEditable: true, value: (_a = note.note) !== null && _a !== void 0 ? _a : "", title: (_b = note.title) !== null && _b !== void 0 ? _b : "", saveButtonLoading: editNoteLoading, handleSubmit: (n, t, f) => onEditNote === null || onEditNote === void 0 ? void 0 : onEditNote(note.log_note_id, n, t, f, event, index), handleCancel: () => setActiveEditNoteId(null) }) }));
|
|
171
|
+
}
|
|
172
|
+
return ((0, jsx_runtime_1.jsxs)(react_1.Box, { onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), position: "relative", bg: (_c = colors.gray) === null || _c === void 0 ? void 0 : _c[50], border: `0.063rem solid ${(_e = (_d = colors.boxborder) === null || _d === void 0 ? void 0 : _d[200]) !== null && _e !== void 0 ? _e : (_f = colors.gray) === null || _f === void 0 ? void 0 : _f[200]}`, borderRadius: "0.5rem", px: 2.5, py: 2, opacity: isDeleting ? 0.6 : 1, children: [(0, jsx_runtime_1.jsxs)(react_1.Flex, { align: "center", gap: 1.5, mb: note.note ? 1 : 0, children: [(0, jsx_runtime_1.jsx)(react_1.Box, { as: "span", color: (_g = colors.primary) === null || _g === void 0 ? void 0 : _g[500], display: "inline-flex", children: (0, jsx_runtime_1.jsx)(lucide_react_1.StickyNote, { size: 12 }) }), note.title && ((0, jsx_runtime_1.jsx)(react_1.Text, { fontSize: "0.6875rem", fontWeight: 700, color: (_j = (_h = colors.text) === null || _h === void 0 ? void 0 : _h[800]) !== null && _j !== void 0 ? _j : (_k = colors.gray) === null || _k === void 0 ? void 0 : _k[800], noOfLines: 1, children: note.title })), (onEditNote || onDeleteNote) && (hovered || isDeleting) && ((0, jsx_runtime_1.jsx)(react_1.Flex, { align: "center", gap: 0.5, ml: "auto", flexShrink: 0, children: isDeleting ? ((0, jsx_runtime_1.jsx)(react_1.Spinner, { size: "xs", color: (_l = colors.gray) === null || _l === void 0 ? void 0 : _l[500] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [onEditNote && ((0, jsx_runtime_1.jsx)(react_1.Tooltip, { label: "Edit", placement: "top", hasArrow: true, children: (0, jsx_runtime_1.jsx)(react_1.Box, { as: "button", type: "button", display: "inline-flex", alignItems: "center", justifyContent: "center", p: 1, borderRadius: "0.375rem", color: (_m = colors.gray) === null || _m === void 0 ? void 0 : _m[500], bg: "transparent", cursor: "pointer", _hover: {
|
|
173
|
+
bg: (_o = colors.primary) === null || _o === void 0 ? void 0 : _o[50],
|
|
174
|
+
color: (_p = colors.primary) === null || _p === void 0 ? void 0 : _p[600],
|
|
175
|
+
}, onClick: (e) => {
|
|
176
|
+
e.stopPropagation();
|
|
177
|
+
setActiveEditNoteId(note.log_note_id);
|
|
178
|
+
}, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { size: 12 }) }) })), onDeleteNote && ((0, jsx_runtime_1.jsx)(react_1.Tooltip, { label: "Delete", placement: "top", hasArrow: true, children: (0, jsx_runtime_1.jsx)(react_1.Box, { as: "button", type: "button", display: "inline-flex", alignItems: "center", justifyContent: "center", p: 1, borderRadius: "0.375rem", color: (_q = colors.gray) === null || _q === void 0 ? void 0 : _q[500], bg: "transparent", cursor: "pointer", _hover: {
|
|
179
|
+
bg: (_t = (_s = (_r = colors.semantic) === null || _r === void 0 ? void 0 : _r.error) === null || _s === void 0 ? void 0 : _s[50]) !== null && _t !== void 0 ? _t : (_u = colors.red) === null || _u === void 0 ? void 0 : _u[50],
|
|
180
|
+
color: (_x = (_w = (_v = colors.semantic) === null || _v === void 0 ? void 0 : _v.error) === null || _w === void 0 ? void 0 : _w[600]) !== null && _x !== void 0 ? _x : (_y = colors.red) === null || _y === void 0 ? void 0 : _y[600],
|
|
181
|
+
}, onClick: (e) => {
|
|
182
|
+
e.stopPropagation();
|
|
183
|
+
onDeleteNote === null || onDeleteNote === void 0 ? void 0 : onDeleteNote(note.log_note_id, event, index);
|
|
184
|
+
}, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 12 }) }) }))] })) }))] }), note.note && ((0, jsx_runtime_1.jsx)(react_1.Text, { fontSize: "0.6875rem", color: (_0 = (_z = colors.text) === null || _z === void 0 ? void 0 : _z[700]) !== null && _0 !== void 0 ? _0 : (_1 = colors.gray) === null || _1 === void 0 ? void 0 : _1[700], whiteSpace: "pre-wrap", children: note.note })), note.attachments && note.attachments.length > 0 && ((0, jsx_runtime_1.jsx)(react_1.Flex, { wrap: "wrap", gap: 1.5, mt: 1.5, children: note.attachments.map((att, attIndex) => {
|
|
185
|
+
var _a, _b, _c;
|
|
186
|
+
return ((0, jsx_runtime_1.jsxs)(react_1.Flex, { as: "a", href: att.url, target: "_blank", rel: "noopener noreferrer", onClick: (e) => e.stopPropagation(), align: "center", gap: 1, px: 1.5, py: 0.5, borderRadius: "full", bg: (_a = colors.primary) === null || _a === void 0 ? void 0 : _a[50], color: (_b = colors.primary) === null || _b === void 0 ? void 0 : _b[700], fontSize: "0.625rem", maxW: "100%", _hover: { bg: (_c = colors.primary) === null || _c === void 0 ? void 0 : _c[100] }, children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Paperclip, { size: 10 }), (0, jsx_runtime_1.jsx)(react_1.Box, { as: "span", noOfLines: 1, maxW: "9rem", children: att.name || "attachment" })] }, attIndex));
|
|
187
|
+
}) })), (note.created_by || note.created_at) && ((0, jsx_runtime_1.jsxs)(react_1.Text, { fontSize: "0.625rem", color: (_2 = colors.gray) === null || _2 === void 0 ? void 0 : _2[500], mt: 1, children: [note.created_by ? (0, functions_1.toWords)(note.created_by) : "", note.created_by && note.created_at ? " · " : "", note.created_at ? formatTimestamp(note.created_at, "time") : ""] }))] }));
|
|
188
|
+
};
|
|
145
189
|
// The colored event card (shared by both the desktop "tree" and mobile rail).
|
|
146
190
|
// `accent` decides which edge carries the colored bar (pointing toward the spine).
|
|
147
191
|
const EventCard = ({ event, index, accent, }) => {
|
|
148
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
|
|
192
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3;
|
|
149
193
|
const scale = getEventScale(event.title);
|
|
150
194
|
const changes = parseChanges(event.changes);
|
|
151
195
|
const clickable = typeof onEventClick === "function";
|
|
@@ -163,9 +207,15 @@ const Timeline = ({ timelineEvents, onEventClick, onAddNote, showAddNote = false
|
|
|
163
207
|
setActiveNoteEventIndex(isActiveNote ? null : index);
|
|
164
208
|
}, px: 2, py: 1, borderRadius: "0.375rem", fontSize: "0.75rem", fontWeight: 600, color: (_z = colors.primary) === null || _z === void 0 ? void 0 : _z[700], bg: "transparent", cursor: "pointer", _hover: {
|
|
165
209
|
bg: (_0 = colors.primary) === null || _0 === void 0 ? void 0 : _0[50],
|
|
166
|
-
}, children: isActiveNote ? "Hide note" : "Add note" }))] })
|
|
210
|
+
}, children: isActiveNote ? "Hide note" : "Add note" }))] }), event.notes && event.notes.length > 0 && ((0, jsx_runtime_1.jsx)(react_1.Flex, { direction: "column", gap: 2, mt: 2, pt: 2, borderTop: `0.063rem solid ${(_2 = (_1 = colors.gray) === null || _1 === void 0 ? void 0 : _1[100]) !== null && _2 !== void 0 ? _2 : (_3 = colors.boxborder) === null || _3 === void 0 ? void 0 : _3[200]}`, children: event.notes.map((note, noteIndex) => {
|
|
211
|
+
var _a;
|
|
212
|
+
return ((0, jsx_runtime_1.jsx)(NoteItem, { note: note, event: event, index: index }, (_a = note.log_note_id) !== null && _a !== void 0 ? _a : noteIndex));
|
|
213
|
+
}) }))] }), isActiveNote && ((0, jsx_runtime_1.jsx)(react_1.Box, { mt: 2, children: (0, jsx_runtime_1.jsx)(NoteTextArea_1.default, { saveButtonLoading: addNoteLoading, handleSubmit: (note, title, files) => {
|
|
167
214
|
onAddNote === null || onAddNote === void 0 ? void 0 : onAddNote(note, title, files, event, index);
|
|
168
|
-
|
|
215
|
+
// When the consumer wires addNoteLoading, the effect closes the
|
|
216
|
+
// editor on completion; otherwise close immediately.
|
|
217
|
+
if (addNoteLoading === undefined)
|
|
218
|
+
setActiveNoteEventIndex(null);
|
|
169
219
|
}, handleCancel: () => setActiveNoteEventIndex(null) }) }))] }));
|
|
170
220
|
};
|
|
171
221
|
const NODE = "1.875rem"; // 30px node, centered on the spine
|
|
@@ -3,13 +3,35 @@ export interface TimelineProps {
|
|
|
3
3
|
timelineEvents: TimelineEvents[];
|
|
4
4
|
onEventClick?: (event: TimelineEvents, index: number) => void;
|
|
5
5
|
onAddNote?: (note: string, title: string, files: File[], event: TimelineEvents, index: number) => void;
|
|
6
|
+
onEditNote?: (logNoteId: number, note: string, title: string, files: File[], event: TimelineEvents, index: number) => void;
|
|
7
|
+
onDeleteNote?: (logNoteId: number, event: TimelineEvents, index: number) => void;
|
|
6
8
|
showAddNote?: boolean;
|
|
9
|
+
/** Spinner on the "Add note" editor while the create request is in flight. */
|
|
10
|
+
addNoteLoading?: boolean;
|
|
11
|
+
/** Spinner on the open note editor while the update request is in flight. */
|
|
12
|
+
editNoteLoading?: boolean;
|
|
13
|
+
/** log_note_id currently being deleted — shows a spinner on that note. */
|
|
14
|
+
deletingNoteId?: number | string | null;
|
|
7
15
|
}
|
|
8
16
|
export interface TimelineEvent {
|
|
9
17
|
title: string;
|
|
10
18
|
description: string;
|
|
11
19
|
time: string;
|
|
12
20
|
}
|
|
21
|
+
export interface TimelineNoteAttachment {
|
|
22
|
+
url: string;
|
|
23
|
+
name?: string;
|
|
24
|
+
size?: number | null;
|
|
25
|
+
}
|
|
26
|
+
export interface TimelineNote {
|
|
27
|
+
log_note_id: number;
|
|
28
|
+
logs_id?: number;
|
|
29
|
+
title?: string | null;
|
|
30
|
+
note?: string | null;
|
|
31
|
+
attachments?: TimelineNoteAttachment[] | null;
|
|
32
|
+
created_at?: number | string | null;
|
|
33
|
+
created_by?: string | null;
|
|
34
|
+
}
|
|
13
35
|
export interface TimelineEvents {
|
|
14
36
|
logs_id: number;
|
|
15
37
|
title: string;
|
|
@@ -19,5 +41,6 @@ export interface TimelineEvents {
|
|
|
19
41
|
action_by: string;
|
|
20
42
|
created_at: number;
|
|
21
43
|
changes: unknown;
|
|
44
|
+
notes?: TimelineNote[] | null;
|
|
22
45
|
}
|
|
23
46
|
//# sourceMappingURL=TimelineProps.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimelineProps.d.ts","sourceRoot":"","sources":["../../../src/Components/Timeline/TimelineProps.tsx"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,cAAc,EAAE,cAAc,EAAE,CAAC;IACjC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9D,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvG,WAAW,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"TimelineProps.d.ts","sourceRoot":"","sources":["../../../src/Components/Timeline/TimelineProps.tsx"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,cAAc,EAAE,cAAc,EAAE,CAAC;IACjC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9D,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvG,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3H,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,sBAAsB,EAAE,GAAG,IAAI,CAAC;IAC9C,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;CAC/B"}
|