@activecollab/components 2.0.397 → 2.0.399

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/cjs/presentation/whiteboard/bottomDock.js +194 -0
  2. package/dist/cjs/presentation/whiteboard/bottomDock.js.map +1 -0
  3. package/dist/cjs/presentation/whiteboard/canvasElements.js +877 -0
  4. package/dist/cjs/presentation/whiteboard/canvasElements.js.map +1 -0
  5. package/dist/cjs/presentation/whiteboard/elements.js +816 -0
  6. package/dist/cjs/presentation/whiteboard/elements.js.map +1 -0
  7. package/dist/cjs/presentation/whiteboard/fileElement.js +457 -0
  8. package/dist/cjs/presentation/whiteboard/fileElement.js.map +1 -0
  9. package/dist/cjs/presentation/whiteboard/glyphs.js +67 -0
  10. package/dist/cjs/presentation/whiteboard/glyphs.js.map +1 -0
  11. package/dist/cjs/presentation/whiteboard/inspector.js +884 -0
  12. package/dist/cjs/presentation/whiteboard/inspector.js.map +1 -0
  13. package/dist/cjs/presentation/whiteboard/linkElement.js +357 -0
  14. package/dist/cjs/presentation/whiteboard/linkElement.js.map +1 -0
  15. package/dist/cjs/presentation/whiteboard/outline.js +966 -0
  16. package/dist/cjs/presentation/whiteboard/outline.js.map +1 -0
  17. package/dist/cjs/presentation/whiteboard/peopleMenu.js +516 -0
  18. package/dist/cjs/presentation/whiteboard/peopleMenu.js.map +1 -0
  19. package/dist/cjs/presentation/whiteboard/settingsMenu.js +177 -0
  20. package/dist/cjs/presentation/whiteboard/settingsMenu.js.map +1 -0
  21. package/dist/esm/presentation/whiteboard/bottomDock.d.ts +51 -0
  22. package/dist/esm/presentation/whiteboard/bottomDock.d.ts.map +1 -0
  23. package/dist/esm/presentation/whiteboard/bottomDock.js +162 -0
  24. package/dist/esm/presentation/whiteboard/bottomDock.js.map +1 -0
  25. package/dist/esm/presentation/whiteboard/canvasElements.d.ts +61 -0
  26. package/dist/esm/presentation/whiteboard/canvasElements.d.ts.map +1 -0
  27. package/dist/esm/presentation/whiteboard/canvasElements.js +746 -0
  28. package/dist/esm/presentation/whiteboard/canvasElements.js.map +1 -0
  29. package/dist/esm/presentation/whiteboard/elements.d.ts +180 -0
  30. package/dist/esm/presentation/whiteboard/elements.d.ts.map +1 -0
  31. package/dist/esm/presentation/whiteboard/elements.js +736 -0
  32. package/dist/esm/presentation/whiteboard/elements.js.map +1 -0
  33. package/dist/esm/presentation/whiteboard/fileElement.d.ts +113 -0
  34. package/dist/esm/presentation/whiteboard/fileElement.d.ts.map +1 -0
  35. package/dist/esm/presentation/whiteboard/fileElement.js +430 -0
  36. package/dist/esm/presentation/whiteboard/fileElement.js.map +1 -0
  37. package/dist/esm/presentation/whiteboard/glyphs.d.ts +32 -0
  38. package/dist/esm/presentation/whiteboard/glyphs.d.ts.map +1 -0
  39. package/dist/esm/presentation/whiteboard/glyphs.js +50 -0
  40. package/dist/esm/presentation/whiteboard/glyphs.js.map +1 -0
  41. package/dist/esm/presentation/whiteboard/inspector.d.ts +100 -0
  42. package/dist/esm/presentation/whiteboard/inspector.d.ts.map +1 -0
  43. package/dist/esm/presentation/whiteboard/inspector.js +753 -0
  44. package/dist/esm/presentation/whiteboard/inspector.js.map +1 -0
  45. package/dist/esm/presentation/whiteboard/linkElement.d.ts +97 -0
  46. package/dist/esm/presentation/whiteboard/linkElement.d.ts.map +1 -0
  47. package/dist/esm/presentation/whiteboard/linkElement.js +327 -0
  48. package/dist/esm/presentation/whiteboard/linkElement.js.map +1 -0
  49. package/dist/esm/presentation/whiteboard/outline.d.ts +89 -0
  50. package/dist/esm/presentation/whiteboard/outline.d.ts.map +1 -0
  51. package/dist/esm/presentation/whiteboard/outline.js +870 -0
  52. package/dist/esm/presentation/whiteboard/outline.js.map +1 -0
  53. package/dist/esm/presentation/whiteboard/peopleMenu.d.ts +44 -0
  54. package/dist/esm/presentation/whiteboard/peopleMenu.d.ts.map +1 -0
  55. package/dist/esm/presentation/whiteboard/peopleMenu.js +440 -0
  56. package/dist/esm/presentation/whiteboard/peopleMenu.js.map +1 -0
  57. package/dist/esm/presentation/whiteboard/settingsMenu.d.ts +13 -0
  58. package/dist/esm/presentation/whiteboard/settingsMenu.d.ts.map +1 -0
  59. package/dist/esm/presentation/whiteboard/settingsMenu.js +155 -0
  60. package/dist/esm/presentation/whiteboard/settingsMenu.js.map +1 -0
  61. package/package.json +1 -1
@@ -0,0 +1,870 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
2
+ import React, { useCallback, useState } from "react";
3
+ import styled, { createGlobalStyle } from "styled-components";
4
+ import { SELECTION_BLUE } from "./elements";
5
+ import { WhiteboardPeopleMenu } from "./peopleMenu";
6
+ import { Button } from "../../components/Button";
7
+ import { Chip } from "../../components/Chip";
8
+ import { ChooseV2 } from "../../components/ChooseV2";
9
+ import { EditableText } from "../../components/EditableText";
10
+ import { IconButton } from "../../components/IconButton";
11
+ import { ArrowLeftIcon, AttachmentIcon, CaretRightIcon, CircleIcon, CollapseExpandSingleIcon, DependencySmallIcon, DrawIcon, DuplicateIcon, EditIcon, FolderMoveIcon, FolderPlusIcon, InsertLinkIcon, LayerBackIcon, LayerBackwardIcon, LayerForwardIcon, LayerFrontIcon, LayersIcon, LockIcon, LockSmallIcon, RoundedRectangleIcon, SidebarLeftIcon, NoteIcon, TextIcon, TrashIcon, TreeDotsIcon, TriangleIcon } from "../../components/Icons";
12
+ import { List, ListItem, ListSeparator } from "../../components/List";
13
+ import { Menu, MenuHeader } from "../../components/Menu";
14
+ import { Signifier } from "../../components/Signifier";
15
+ import { Tooltip } from "../../components/Tooltip";
16
+ import { ResizeTransition, SlideLeftRightTransition } from "../../components/Transitions";
17
+ import { Body2, Caption1, Header3 } from "../../components/Typography";
18
+
19
+ /* ------------------------------------------------------------------ */
20
+ /* Outline sidebar */
21
+ /* ------------------------------------------------------------------ */
22
+
23
+ /* An OUTLINE, not a layers panel. Whiteboard elements are a flat list today
24
+ with no nesting and no names, so the hierarchy here is AUTHORED rather than
25
+ derived from z-order or spatial containment: the user creates groups, names
26
+ things, and drags to order them, and all of that is persisted.
27
+ Deliberately excluded: stacking order. z-order stays on the element context
28
+ menu (send to front / back / forward / backward) and the sidebar never shows
29
+ or edits it — the outline order and the paint order are different questions,
30
+ and conflating them is what makes layers panels confusing on boards that are
31
+ really structured documents.
32
+
33
+ The model this prototype stands in for:
34
+ GroupElement a new element type on the single-table-inheritance
35
+ `whiteboard_elements` table — no migration needed, and it
36
+ inherits ops, realtime, undo/redo and trash for free.
37
+ Element.jsx's render switch already returns null by
38
+ default, so a group draws nothing on the canvas. It must be
39
+ filtered out of the spatial index, marquee select and the
40
+ z-order sort.
41
+ name a real authored field, separate from `content` (the text
42
+ painted on the canvas). Needed because the eventual goal is
43
+ exporting the outline as a document, and `content` is empty
44
+ on every freshly drawn shape and absent on freehand.
45
+ outlinePosition
46
+ integer ordering SCOPED PER CONTAINER — groups ordered
47
+ among themselves, elements ordered within their group.
48
+ Named to avoid colliding with `element.position`, which is
49
+ already the {x, y} canvas coordinate. Reordering follows
50
+ the house TaskReorderer contract: the client sends the full
51
+ ordered id list, the server renumbers 1..N in one
52
+ transaction. Here that is a new `reorder` op on the
53
+ existing ops pipeline, so it inherits undo/redo, the id_map
54
+ reconcile and the realtime merge.
55
+
56
+ ONE level of nesting only. Groups cannot contain groups — an exported
57
+ document does not want arbitrarily deep headings, and multi-level grouping
58
+ is a later, separate model. */
59
+
60
+ /* The local `Glyph` type is for this story's hand-drawn SVGs; the DS icons are
61
+ forwardRef components, so the map needs the wider component type. */
62
+
63
+ export const OUTLINE_TYPE_ICONS = {
64
+ circle: CircleIcon,
65
+ roundedRectangle: RoundedRectangleIcon,
66
+ triangle: TriangleIcon,
67
+ postit: NoteIcon,
68
+ text: TextIcon,
69
+ freehand: DrawIcon,
70
+ link: InsertLinkIcon,
71
+ file: AttachmentIcon
72
+ };
73
+
74
+ /* Fallback label when an element has no name. Deliberately reads as a
75
+ PLACEHOLDER (muted + italic) rather than as a name, because an unnamed
76
+ element exports as nothing — the styling is the warning. */
77
+ export const OUTLINE_TYPE_LABELS = {
78
+ circle: "Circle",
79
+ roundedRectangle: "Rounded Rectangle",
80
+ triangle: "Triangle",
81
+ postit: "Sticky Note",
82
+ text: "Text",
83
+ freehand: "Freehand",
84
+ link: "Link",
85
+ file: "File"
86
+ };
87
+ /* Ids prefixed `shape-` / `sticky` are the elements really on the canvas, so
88
+ selection syncs both ways for them. The rest stand in for the parts of a
89
+ bigger board scrolled out of view — a four-element outline would not show
90
+ whether the grouping reads well. */
91
+ export const OUTLINE_GROUPS = [{
92
+ id: "group-discovery",
93
+ name: "Discovery phase"
94
+ }, {
95
+ id: "group-sketches",
96
+ name: "Solution sketches"
97
+ }, {
98
+ id: "group-questions",
99
+ name: "Open questions"
100
+ }];
101
+ export const OUTLINE_ELEMENTS = [{
102
+ id: "sticky",
103
+ name: "Interview five customers",
104
+ type: "postit",
105
+ connections: 2,
106
+ groupId: "group-discovery"
107
+ }, {
108
+ id: "shape-rounded",
109
+ name: "Problem statement",
110
+ type: "roundedRectangle",
111
+ connections: 3,
112
+ groupId: "group-discovery"
113
+ }, {
114
+ id: "outline-freehand",
115
+ name: null,
116
+ type: "freehand",
117
+ groupId: "group-discovery"
118
+ }, {
119
+ id: "shape-circle",
120
+ name: "Success metric",
121
+ type: "circle",
122
+ locked: true,
123
+ connections: 1,
124
+ groupId: "group-discovery"
125
+ }, {
126
+ id: "outline-sketch-link",
127
+ name: "Competitor teardown",
128
+ type: "link",
129
+ groupId: "group-sketches"
130
+ }, {
131
+ id: "outline-sketch-file",
132
+ name: "Wireframes v3.pdf",
133
+ type: "file",
134
+ connections: 1,
135
+ groupId: "group-sketches"
136
+ }, {
137
+ id: "outline-sketch-text",
138
+ name: null,
139
+ type: "text",
140
+ groupId: "group-sketches"
141
+ },
142
+ /* A deliberately long name, so the truncation and the right-edge behaviour of
143
+ the signifiers and the counter are visible in the story. */
144
+ {
145
+ id: "outline-parking",
146
+ name: "Parking lot for everything we could not agree on today",
147
+ type: "postit",
148
+ connections: 4,
149
+ locked: true,
150
+ groupId: null
151
+ }, {
152
+ id: "shape-triangle",
153
+ name: null,
154
+ type: "triangle",
155
+ groupId: null
156
+ }, {
157
+ id: "outline-q3",
158
+ name: "Revisit in Q3",
159
+ type: "text",
160
+ connections: 12,
161
+ groupId: null
162
+ }];
163
+
164
+ /* Min is the point below which a group name plus its counter stops being
165
+ readable; max follows the common side-panel rule of thumb of 3x the min, past
166
+ which the panel competes with the canvas for the screen rather than annotating
167
+ it. The default sits just above the min — panels of this sort open narrow and
168
+ are widened on demand, not the other way round. */
169
+ export const OUTLINE_MIN_WIDTH = 260;
170
+ export const OUTLINE_MAX_WIDTH = OUTLINE_MIN_WIDTH * 3;
171
+ export const OUTLINE_WIDTH = 320;
172
+ export const UNGROUPED = "__ungrouped__";
173
+ export const StyledOutlineSidebar = styled.aside.withConfig({
174
+ displayName: "outline__StyledOutlineSidebar",
175
+ componentId: "sc-173k9fg-0"
176
+ })(["flex-shrink:0;position:relative;box-sizing:border-box;display:flex;flex-direction:column;border-right:1px solid var(--selectable);background-color:var(--page-paper-main);font-family:-apple-system,BlinkMacSystemFont,\"Roboto\",\"Helvetica Neue\",Arial,sans-serif;"]);
177
+
178
+ /* Grab strip on the RIGHT edge, because the panel is docked left — dragging it
179
+ right widens. It sits outside the row list and uses mouse events rather than
180
+ HTML5 drag, so it can never be mistaken for a row reorder. 3px wide with a
181
+ larger invisible hit area is the usual compromise: easy to grab. The border
182
+ line itself stays the selectable grey until hover paints the active token
183
+ over it. */
184
+ export const StyledOutlineResizer = styled.div.withConfig({
185
+ displayName: "outline__StyledOutlineResizer",
186
+ componentId: "sc-173k9fg-1"
187
+ })(["position:absolute;top:0;bottom:0;right:-4px;width:8px;cursor:col-resize;z-index:2;&::after{content:\"\";position:absolute;top:0;bottom:0;left:50%;margin-left:-0.5px;width:1px;background-color:var(--selectable-active);opacity:0;transition:opacity 150ms ease;}&:hover::after,&.resizing::after{opacity:1;}"]);
188
+ export const StyledOutlineBody = styled.div.withConfig({
189
+ displayName: "outline__StyledOutlineBody",
190
+ componentId: "sc-173k9fg-2"
191
+ })(["flex:1;overflow-y:auto;padding:6px 0 24px;"]);
192
+
193
+ /* Rows are bordered, not carded — the outline is a dense list and rounded
194
+ tiles at this density read as clutter. */
195
+ /* Row geometry is My Work's, not something invented for this sidebar: the app's
196
+ `ListItem` is `tw-w-full tw-flex tw-items-center tw-h-10` — a fixed 40px row —
197
+ with `border-bottom: 1px solid var(--color-theme-300)` from `.list-item-wrapper`
198
+ and `background-color: var(--color-theme-200)` on `.task-list-item:hover`.
199
+ Reusing those exact values is what makes the outline read as an ActiveCollab
200
+ list rather than as a bespoke panel. */
201
+ export const StyledOutlineRow = styled.div.withConfig({
202
+ displayName: "outline__StyledOutlineRow",
203
+ componentId: "sc-173k9fg-3"
204
+ })(["display:flex;align-items:center;height:40px;box-sizing:border-box;padding-right:8px;cursor:pointer;position:relative;border-bottom:1px solid var(--color-theme-300);&:hover{background-color:var(--color-theme-200);}&.selected{background-color:var(--color-theme-200);box-shadow:inset 2px 0 0 0 ", ";}&.drop-before::after,&.drop-after::after{content:\"\";position:absolute;left:0;right:0;height:2px;background-color:", ";z-index:1;}&.drop-before::after{top:-1px;}&.drop-after::after{bottom:-1px;}&.drop-into{background-color:var(--color-theme-200);box-shadow:inset 0 0 0 1px ", ";}&.dragging{opacity:0.4;}.outline-trailing{flex-shrink:0;display:flex;align-items:center;}.outline-options{margin-left:auto;flex-shrink:0;display:flex;align-items:center;padding-left:4px;}.outline-hover{opacity:0;transition:opacity 200ms ease;}&:hover .outline-hover,.outline-hover.open,.outline-hover:focus-within{opacity:1;}"], SELECTION_BLUE, SELECTION_BLUE, SELECTION_BLUE);
205
+
206
+ /* 8px so the 24px toggle sits in the same left rail as the app's ExpandToggle,
207
+ scaled down from My Work's 24px page margin for a 300px panel. */
208
+ export const StyledOutlineGroupRow = styled(StyledOutlineRow).withConfig({
209
+ displayName: "outline__StyledOutlineGroupRow",
210
+ componentId: "sc-173k9fg-4"
211
+ })(["padding-left:8px;"]);
212
+
213
+ /* 32px = where the group's 24px toggle ends. The child's type icon starts
214
+ exactly there, putting the child NAME one 16px step right of the group name —
215
+ enough to read as nested without a staircase, which is all one level of
216
+ nesting ever needs. */
217
+ export const StyledOutlineChildRow = styled(StyledOutlineRow).withConfig({
218
+ displayName: "outline__StyledOutlineChildRow",
219
+ componentId: "sc-173k9fg-5"
220
+ })(["padding-left:32px;"]);
221
+
222
+ /* Matches the app's ExpandToggle exactly: CollapseExpandSingleIcon at its
223
+ intrinsic 24px, rotate(0) expanded and rotate(180deg) collapsed, over
224
+ `transition-transform` 200ms. */
225
+ export const StyledOutlineToggle = styled.button.withConfig({
226
+ displayName: "outline__StyledOutlineToggle",
227
+ componentId: "sc-173k9fg-6"
228
+ })(["border:0;padding:0;margin:0 8px 0 0;background:none;cursor:pointer;display:flex;align-items:center;flex-shrink:0;transition:transform 200ms ease;&.collapsed{transform:rotate(180deg);}"]);
229
+
230
+ /* Same treatment as the count badges on the System Settings pages — a Chip on
231
+ var(--color-theme-300) with var(--color-theme-900) text — at the 18px small
232
+ size, which sits inside a 40px row without crowding it. Wrapped so the 8px
233
+ left margin is one decision rather than repeated at each call site: it is what
234
+ keeps the chip a fixed distance from the name whether the name is an
235
+ EditableText (whose input carries its own 4px padding) or plain Typography. */
236
+ export const StyledOutlineCounter = styled.span.withConfig({
237
+ displayName: "outline__StyledOutlineCounter",
238
+ componentId: "sc-173k9fg-7"
239
+ })(["display:flex;align-items:center;flex-shrink:0;margin-left:8px;"]);
240
+ export const OutlineCounter = _ref => {
241
+ let count = _ref.count;
242
+ return /*#__PURE__*/React.createElement(StyledOutlineCounter, {
243
+ className: "outline-trailing"
244
+ }, /*#__PURE__*/React.createElement(Chip, {
245
+ label: String(count),
246
+ backgroundColor: "var(--color-theme-300)",
247
+ color: "var(--color-theme-900)",
248
+ size: "small"
249
+ }));
250
+ };
251
+
252
+ /* The 2px separator dot is a house convention rather than part of the DS
253
+ Signifier: `_components.task-signifiers.less` puts it on `.c-signifier:before`
254
+ at 2px square, `var(--color-theme-600)`, `margin: 0 6px`, with no
255
+ `:not(:first-child)` guard — so the first signifier gets a leading dot too,
256
+ which is exactly what separates it from the name. */
257
+ export const StyledOutlineSignifiers = styled.span.withConfig({
258
+ displayName: "outline__StyledOutlineSignifiers",
259
+ componentId: "sc-173k9fg-8"
260
+ })(["display:inline-flex;align-items:center;flex-shrink:0;.c-signifier::before{content:\"\";flex-shrink:0;width:2px;height:2px;margin:0 6px;border-radius:100%;background-color:var(--color-theme-600);}"]);
261
+
262
+ /* The DS EditableText is an always-live input styled as text — it reveals its
263
+ border on hover and focus rather than swapping into an edit mode. That makes
264
+ it a click-to-edit target, which competes with the row's own click. Element
265
+ rows therefore keep it `disabled` until the row is SELECTED: the first click
266
+ selects, and only then does the name accept a caret. Group rows have no
267
+ selected state, so their name is always live (matching the task-list header
268
+ in ListView) and the toggle, count and row padding carry the collapse. */
269
+ /* 24px reserved so the icon column is stable whether or not a type icon is a
270
+ perfect 16px square, and so it lines up with the group toggle above it. */
271
+ export const StyledOutlineTypeIcon = styled.span.withConfig({
272
+ displayName: "outline__StyledOutlineTypeIcon",
273
+ componentId: "sc-173k9fg-9"
274
+ })(["display:flex;align-items:center;justify-content:flex-start;width:24px;flex-shrink:0;"]);
275
+ export const StyledOutlineName = styled.div.withConfig({
276
+ displayName: "outline__StyledOutlineName",
277
+ componentId: "sc-173k9fg-10"
278
+ })(["display:flex;align-items:center;flex:0 1 auto;min-width:0;> div{max-width:100%;}> .typography{display:block;padding-left:4px;padding-right:4px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}&.unnamed .presentation,&.unnamed input{font-style:italic;color:var(--color-theme-500);}"]);
279
+ export const outlineLabel = element => {
280
+ var _element$name;
281
+ return (_element$name = element.name) != null ? _element$name : OUTLINE_TYPE_LABELS[element.type];
282
+ };
283
+
284
+ /* Both menus follow the shared TaskListOptionsMenu shape: Menu in normal mode
285
+ (260px bubble), an IconButton + TreeDots trigger whose `.open` class keeps it
286
+ visible while the menu is up, and a flat List of leading-icon ListItems
287
+ grouped by ListSeparator. Every row is an icon plus a caption — no submenu
288
+ rows and no icon-only action strip, so there is exactly one way to read the
289
+ menu.
290
+
291
+ Note where STACKING lives: bring to front / send to back are here, not in the
292
+ outline. The outline orders the document; the menu orders the pixels. Keeping
293
+ them apart is the whole reason the sidebar can be an outline rather than a
294
+ layers panel. */
295
+ export const OUTLINE_MENU_LIST_STYLE = {
296
+ padding: "8px 0"
297
+ };
298
+ export const OUTLINE_MENU_WIDTH = 264;
299
+
300
+ /* Same drill-in mechanics as the board Settings menu: the paper clips the two
301
+ sliding panels and gives them a positioning context. */
302
+ export const OutlineMenuSliderStyle = createGlobalStyle([".c-simple-menu__paper.outline-element-menu{overflow:hidden;position:relative;}"]);
303
+ export const StyledOutlineElementMenu = styled.div.withConfig({
304
+ displayName: "outline__StyledOutlineElementMenu",
305
+ componentId: "sc-173k9fg-11"
306
+ })([".drill-item{justify-content:space-between;}.drill-item .opt-left{display:flex;align-items:center;min-width:0;}.drill-item .opt-left > svg:first-child{margin-right:8px;}.drill-item .drill-caret{flex-shrink:0;fill:var(--color-theme-600);}"]);
307
+ export const ARRANGE_ITEMS = [{
308
+ label: "Bring to Front",
309
+ Icon: LayerFrontIcon
310
+ }, {
311
+ label: "Send Forward",
312
+ Icon: LayerForwardIcon
313
+ }, {
314
+ label: "Send Backward",
315
+ Icon: LayerBackwardIcon
316
+ }, {
317
+ label: "Send to Back",
318
+ Icon: LayerBackIcon
319
+ }];
320
+ export const OutlineElementOptionsMenu = _ref2 => {
321
+ let locked = _ref2.locked,
322
+ onToggleLock = _ref2.onToggleLock;
323
+ const _useState = useState(false),
324
+ open = _useState[0],
325
+ setOpen = _useState[1];
326
+ const _useState2 = useState("index"),
327
+ view = _useState2[0],
328
+ setView = _useState2[1];
329
+ const _useState3 = useState(true),
330
+ isLeft = _useState3[0],
331
+ setIsLeft = _useState3[1];
332
+ const _useState4 = useState(0),
333
+ height = _useState4[0],
334
+ setHeight = _useState4[1];
335
+ const measure = useCallback(node => {
336
+ if (node) {
337
+ setHeight(node.offsetHeight);
338
+ }
339
+ }, []);
340
+ const goToArrange = () => {
341
+ setView("arrange");
342
+ setIsLeft(true);
343
+ };
344
+ const backToIndex = () => {
345
+ setView("index");
346
+ setIsLeft(false);
347
+ };
348
+ const handleClose = () => {
349
+ setOpen(false);
350
+ setView("index");
351
+ setIsLeft(true);
352
+ };
353
+ const indexView = /*#__PURE__*/React.createElement(StyledOutlineElementMenu, null, /*#__PURE__*/React.createElement(List, {
354
+ style: OUTLINE_MENU_LIST_STYLE,
355
+ tabIndex: -1
356
+ }, /*#__PURE__*/React.createElement(ListItem, null, /*#__PURE__*/React.createElement(EditIcon, null), "Rename"), /*#__PURE__*/React.createElement(ListItem, null, /*#__PURE__*/React.createElement(DuplicateIcon, null), "Duplicate"), /*#__PURE__*/React.createElement(ListSeparator, null), /*#__PURE__*/React.createElement(ListItem, null, /*#__PURE__*/React.createElement(FolderMoveIcon, null), "Move to Group"), /*#__PURE__*/React.createElement(ListItem, {
357
+ className: "drill-item",
358
+ onClick: goToArrange
359
+ }, /*#__PURE__*/React.createElement("span", {
360
+ className: "opt-left"
361
+ }, /*#__PURE__*/React.createElement(LayersIcon, null), "Arrange"), /*#__PURE__*/React.createElement(CaretRightIcon, {
362
+ className: "drill-caret",
363
+ width: 16,
364
+ height: 16
365
+ })), /*#__PURE__*/React.createElement(ListSeparator, null), /*#__PURE__*/React.createElement(ListItem, {
366
+ onClick: () => {
367
+ onToggleLock();
368
+ handleClose();
369
+ }
370
+ }, /*#__PURE__*/React.createElement(LockIcon, null), locked ? "Unlock" : "Lock"), /*#__PURE__*/React.createElement(ListSeparator, null), /*#__PURE__*/React.createElement(ListItem, null, /*#__PURE__*/React.createElement(TrashIcon, null), "Move to Trash")));
371
+ const arrangeView = /*#__PURE__*/React.createElement(StyledOutlineElementMenu, null, /*#__PURE__*/React.createElement(MenuHeader, {
372
+ title: "Arrange",
373
+ leftElement: /*#__PURE__*/React.createElement(IconButton, {
374
+ type: "button",
375
+ variant: "text gray",
376
+ size: "small",
377
+ onClick: backToIndex,
378
+ "aria-label": "Back"
379
+ }, /*#__PURE__*/React.createElement(ArrowLeftIcon, null))
380
+ }), /*#__PURE__*/React.createElement(List, {
381
+ style: OUTLINE_MENU_LIST_STYLE,
382
+ tabIndex: -1
383
+ }, ARRANGE_ITEMS.map(_ref3 => {
384
+ let label = _ref3.label,
385
+ Icon = _ref3.Icon;
386
+ return /*#__PURE__*/React.createElement(ListItem, {
387
+ key: label,
388
+ onClick: backToIndex
389
+ }, /*#__PURE__*/React.createElement(Icon, null), label);
390
+ })));
391
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(OutlineMenuSliderStyle, null), /*#__PURE__*/React.createElement(Menu, {
392
+ open: open,
393
+ onOpen: () => setOpen(true),
394
+ onClose: handleClose,
395
+ position: "bottom-end",
396
+ menuClassName: "outline-element-menu",
397
+ target: /*#__PURE__*/React.createElement(IconButton, {
398
+ type: "button",
399
+ variant: "text gray",
400
+ className: open ? "open" : undefined,
401
+ active: open
402
+ }, /*#__PURE__*/React.createElement(TreeDotsIcon, null))
403
+ }, /*#__PURE__*/React.createElement(ResizeTransition, {
404
+ in: true,
405
+ style: {
406
+ height,
407
+ width: OUTLINE_MENU_WIDTH
408
+ }
409
+ }, /*#__PURE__*/React.createElement("div", {
410
+ style: {
411
+ position: "relative",
412
+ overflow: "hidden"
413
+ }
414
+ }, /*#__PURE__*/React.createElement(SlideLeftRightTransition, {
415
+ in: view === "index",
416
+ direction: isLeft ? "left" : "right"
417
+ }, /*#__PURE__*/React.createElement("div", {
418
+ ref: measure,
419
+ style: {
420
+ width: OUTLINE_MENU_WIDTH
421
+ }
422
+ }, indexView)), /*#__PURE__*/React.createElement(SlideLeftRightTransition, {
423
+ in: view === "arrange",
424
+ direction: isLeft ? "left" : "right"
425
+ }, /*#__PURE__*/React.createElement("div", {
426
+ ref: measure,
427
+ style: {
428
+ width: OUTLINE_MENU_WIDTH
429
+ }
430
+ }, arrangeView))))));
431
+ };
432
+ export const OutlineGroupOptionsMenu = () => {
433
+ const _useState5 = useState(false),
434
+ open = _useState5[0],
435
+ setOpen = _useState5[1];
436
+ return /*#__PURE__*/React.createElement(Menu, {
437
+ open: open,
438
+ onOpen: () => setOpen(true),
439
+ onClose: () => setOpen(false),
440
+ position: "bottom-end",
441
+ target: /*#__PURE__*/React.createElement(IconButton, {
442
+ type: "button",
443
+ variant: "text gray",
444
+ className: open ? "open" : undefined,
445
+ active: open
446
+ }, /*#__PURE__*/React.createElement(TreeDotsIcon, null))
447
+ }, /*#__PURE__*/React.createElement(List, {
448
+ style: OUTLINE_MENU_LIST_STYLE,
449
+ tabIndex: -1
450
+ }, /*#__PURE__*/React.createElement(ListItem, null, /*#__PURE__*/React.createElement(EditIcon, null), "Rename"), /*#__PURE__*/React.createElement(ListItem, null, /*#__PURE__*/React.createElement(DuplicateIcon, null), "Duplicate"), /*#__PURE__*/React.createElement(ListSeparator, null), /*#__PURE__*/React.createElement(ListItem, null, /*#__PURE__*/React.createElement(FolderMoveIcon, null), "Ungroup"), /*#__PURE__*/React.createElement(ListSeparator, null), /*#__PURE__*/React.createElement(ListItem, null, /*#__PURE__*/React.createElement(TrashIcon, null), "Move to Trash")));
451
+ };
452
+ export const INFO_ROWS = [["Owner", "Ilija Studen"], ["Created", "Jul 30, 2026"], ["Members", "12"], ["Elements", "48"], ["Last edited", "2 hours ago"]];
453
+
454
+ /* The upper-left menu — exit fullscreen, board name, the Show / Hide Sidebar
455
+ toggle and the people menu. It renders in one of two places: floating over the
456
+ board while the sidebar is closed, and inside the sidebar's header once it
457
+ opens, so the controls follow the panel rather than being shoved aside by it. */
458
+ export const LeftMenuContents = _ref4 => {
459
+ let sidebarOpen = _ref4.sidebarOpen,
460
+ onToggleSidebar = _ref4.onToggleSidebar,
461
+ boardName = _ref4.boardName,
462
+ onRenameBoard = _ref4.onRenameBoard;
463
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Tooltip, {
464
+ title: "Back to Whiteboards"
465
+ }, /*#__PURE__*/React.createElement(IconButton, {
466
+ variant: "text gray"
467
+ }, /*#__PURE__*/React.createElement(ArrowLeftIcon, null))), /*#__PURE__*/React.createElement("span", {
468
+ className: "wb-title"
469
+ }, /*#__PURE__*/React.createElement(EditableText, {
470
+ value: boardName,
471
+ variant: "Title 2",
472
+ weight: "bold",
473
+ onSave: event => onRenameBoard(event.target.value),
474
+ inputProps: {
475
+ maxLength: 150
476
+ }
477
+ })), /*#__PURE__*/React.createElement(Tooltip, {
478
+ title: sidebarOpen ? "Hide Sidebar" : "Show Sidebar"
479
+ }, /*#__PURE__*/React.createElement(IconButton, {
480
+ variant: "text gray",
481
+ onClick: onToggleSidebar
482
+ }, /*#__PURE__*/React.createElement(SidebarLeftIcon, null))), /*#__PURE__*/React.createElement(WhiteboardPeopleMenu, null));
483
+ };
484
+
485
+ /* When the sidebar is open the left menu becomes its header: same controls, but
486
+ laid out as a flat 60px bar with the board name flexing to fill the middle. */
487
+ export const StyledSidebarHeader = styled.div.withConfig({
488
+ displayName: "outline__StyledSidebarHeader",
489
+ componentId: "sc-173k9fg-12"
490
+ })(["display:flex;align-items:center;gap:2px;height:60px;padding:0 12px;box-sizing:border-box;flex-shrink:0;.wb-title{flex:1;min-width:0;margin:0 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}"]);
491
+
492
+ /* Centered segmented switch between the dock's two panels; the active one is
493
+ highlighted. This row replaces the old per-panel header. */
494
+ export const StyledChooseRow = styled.div.withConfig({
495
+ displayName: "outline__StyledChooseRow",
496
+ componentId: "sc-173k9fg-13"
497
+ })(["display:flex;justify-content:center;padding:12px 16px;flex-shrink:0;"]);
498
+
499
+ /* The app renders the switch through ChooseV2 in a fixed 224px slot with the
500
+ button group centered inside it (the group alone is narrower than the slot,
501
+ and ChooseV2's own flex container leaves it at the left edge). */
502
+ export const StyledPanelChooseSlot = styled.div.withConfig({
503
+ displayName: "outline__StyledPanelChooseSlot",
504
+ componentId: "sc-173k9fg-14"
505
+ })(["width:224px;.c-btn-group{margin:0 auto;}"]);
506
+ export const StyledInfoPanel = styled.div.withConfig({
507
+ displayName: "outline__StyledInfoPanel",
508
+ componentId: "sc-173k9fg-15"
509
+ })(["flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:16px;.info-meta{display:flex;flex-direction:column;gap:10px;}.info-row{display:flex;align-items:baseline;justify-content:space-between;gap:12px;}"]);
510
+
511
+ /* Mock only — the Info panel's content is a placeholder while the two-panel dock
512
+ is explored; the fields here are not the point. */
513
+ export const InfoPanelContent = _ref5 => {
514
+ let boardName = _ref5.boardName;
515
+ return /*#__PURE__*/React.createElement(StyledInfoPanel, null, /*#__PURE__*/React.createElement(Header3, {
516
+ color: "primary"
517
+ }, boardName), /*#__PURE__*/React.createElement("div", {
518
+ className: "info-meta"
519
+ }, INFO_ROWS.map(_ref6 => {
520
+ let label = _ref6[0],
521
+ value = _ref6[1];
522
+ return /*#__PURE__*/React.createElement("div", {
523
+ className: "info-row",
524
+ key: label
525
+ }, /*#__PURE__*/React.createElement(Caption1, {
526
+ color: "secondary"
527
+ }, label), /*#__PURE__*/React.createElement(Body2, {
528
+ weight: "medium"
529
+ }, value));
530
+ })));
531
+ };
532
+
533
+ /* Centered text button below the group list — same text-gray treatment as the
534
+ old header icon (no outline, gray fill on hover), now with a label since it is
535
+ no longer squeezed into a header. */
536
+ export const StyledNewGroupRow = styled.div.withConfig({
537
+ displayName: "outline__StyledNewGroupRow",
538
+ componentId: "sc-173k9fg-16"
539
+ })(["display:flex;justify-content:center;padding:12px 0 4px;svg{width:16px;height:16px;margin-right:6px;}"]);
540
+ export const LeftSidebar = _ref7 => {
541
+ let selectedId = _ref7.selectedId,
542
+ onSelect = _ref7.onSelect,
543
+ activePanel = _ref7.activePanel,
544
+ onPanelChange = _ref7.onPanelChange,
545
+ sidebarOpen = _ref7.sidebarOpen,
546
+ onToggleSidebar = _ref7.onToggleSidebar,
547
+ boardName = _ref7.boardName,
548
+ onRenameBoard = _ref7.onRenameBoard;
549
+ const _useState6 = useState(OUTLINE_WIDTH),
550
+ width = _useState6[0],
551
+ setWidth = _useState6[1];
552
+ const _useState7 = useState(false),
553
+ resizing = _useState7[0],
554
+ setResizing = _useState7[1];
555
+ const _useState8 = useState(OUTLINE_GROUPS),
556
+ groups = _useState8[0],
557
+ setGroups = _useState8[1];
558
+ const _useState9 = useState(OUTLINE_ELEMENTS),
559
+ elements = _useState9[0],
560
+ setElements = _useState9[1];
561
+ const _useState0 = useState(["group-sketches"]),
562
+ collapsed = _useState0[0],
563
+ setCollapsed = _useState0[1];
564
+ const _useState1 = useState(null),
565
+ dragId = _useState1[0],
566
+ setDragId = _useState1[1];
567
+ const _useState10 = useState(null),
568
+ dropSpot = _useState10[0],
569
+ setDropSpot = _useState10[1];
570
+ const isGroup = useCallback(id => groups.some(group => group.id === id), [groups]);
571
+ const membersOf = useCallback(groupId => elements.filter(element => element.groupId === groupId), [elements]);
572
+ const toggleCollapsed = useCallback(id => {
573
+ setCollapsed(current => current.includes(id) ? current.filter(entry => entry !== id) : [...current, id]);
574
+ }, []);
575
+ const renameGroup = useCallback((id, name) => {
576
+ setGroups(current => current.map(group => group.id === id ? _extends({}, group, {
577
+ name
578
+ }) : group));
579
+ }, []);
580
+ const renameElement = useCallback((id, name) => {
581
+ setElements(current => current.map(element => element.id === id ? _extends({}, element, {
582
+ name
583
+ }) : element));
584
+ }, []);
585
+ const toggleLock = useCallback(id => {
586
+ setElements(current => current.map(element => element.id === id ? _extends({}, element, {
587
+ locked: !element.locked
588
+ }) : element));
589
+ }, []);
590
+
591
+ /* The gesture is tracked from its ORIGIN (pointer x + width at mousedown)
592
+ rather than from the pointer's absolute position, so the panel edge stays
593
+ locked to the cursor even once the width clamps at a bound — otherwise the
594
+ pointer drifts away from the edge and the panel jumps when it comes back.
595
+ Listeners go on window so the drag survives the pointer leaving the strip,
596
+ and body user-select is suspended so dragging does not select the rows. */
597
+ const startResize = useCallback(event => {
598
+ var _event$currentTarget$, _event$currentTarget$2;
599
+ event.preventDefault();
600
+ const startX = event.clientX;
601
+ const startWidth = (_event$currentTarget$ = (_event$currentTarget$2 = event.currentTarget.parentElement) == null ? void 0 : _event$currentTarget$2.offsetWidth) != null ? _event$currentTarget$ : 0;
602
+ const previousUserSelect = document.body.style.userSelect;
603
+ setResizing(true);
604
+ document.body.style.userSelect = "none";
605
+ document.body.style.cursor = "col-resize";
606
+ const handleMove = moveEvent => {
607
+ const next = startWidth + (moveEvent.clientX - startX);
608
+ setWidth(Math.min(OUTLINE_MAX_WIDTH, Math.max(OUTLINE_MIN_WIDTH, next)));
609
+ };
610
+ const handleUp = () => {
611
+ setResizing(false);
612
+ document.body.style.userSelect = previousUserSelect;
613
+ document.body.style.cursor = "";
614
+ window.removeEventListener("mousemove", handleMove);
615
+ window.removeEventListener("mouseup", handleUp);
616
+ };
617
+ window.addEventListener("mousemove", handleMove);
618
+ window.addEventListener("mouseup", handleUp);
619
+ }, []);
620
+ const addGroup = useCallback(() => {
621
+ setGroups(current => [...current, {
622
+ id: "group-" + Date.now(),
623
+ name: "New group"
624
+ }]);
625
+ }, []);
626
+
627
+ /* Reorder mirrors the server contract: splice the moved entry into its new
628
+ slot, then treat the resulting array order AS the 1..N renumbering the
629
+ server would write back. Groups reorder among groups; an element moves
630
+ within or between containers, and its groupId follows the drop target —
631
+ which is the whole of "one level of nesting" as an invariant, since a
632
+ group is never a valid child. */
633
+ const handleDrop = useCallback(() => {
634
+ const draggedId = dragId;
635
+ const spot = dropSpot;
636
+ setDragId(null);
637
+ setDropSpot(null);
638
+ if (!draggedId || !spot || draggedId === spot.id) {
639
+ return;
640
+ }
641
+ if (isGroup(draggedId)) {
642
+ /* a group can only land among groups, never inside one */
643
+ if (spot.kind === "into" || !isGroup(spot.id)) {
644
+ return;
645
+ }
646
+ setGroups(current => {
647
+ const from = current.findIndex(group => group.id === draggedId);
648
+ const next = [...current];
649
+ const _next$splice = next.splice(from, 1),
650
+ moved = _next$splice[0];
651
+ const to = next.findIndex(group => group.id === spot.id);
652
+ next.splice(spot.kind === "before" ? to : to + 1, 0, moved);
653
+ return next;
654
+ });
655
+ return;
656
+ }
657
+ setElements(current => {
658
+ const from = current.findIndex(element => element.id === draggedId);
659
+ const next = [...current];
660
+ const _next$splice2 = next.splice(from, 1),
661
+ moved = _next$splice2[0];
662
+ if (spot.kind === "into") {
663
+ const groupId = spot.id === UNGROUPED ? null : spot.id;
664
+ const last = next.reduce((acc, element, index) => element.groupId === groupId ? index : acc, -1);
665
+ next.splice(last + 1, 0, _extends({}, moved, {
666
+ groupId
667
+ }));
668
+ return next;
669
+ }
670
+ const target = next.find(element => element.id === spot.id);
671
+ if (!target) {
672
+ return current;
673
+ }
674
+ const to = next.findIndex(element => element.id === spot.id);
675
+ next.splice(spot.kind === "before" ? to : to + 1, 0, _extends({}, moved, {
676
+ groupId: target.groupId
677
+ }));
678
+ return next;
679
+ });
680
+ }, [dragId, dropSpot, isGroup]);
681
+ const rowDragProps = useCallback(id => ({
682
+ draggable: true,
683
+ onDragStart: event => {
684
+ /* A live EditableText input sits inside the row, and dragging a text
685
+ selection inside it must not turn into a row reorder. */
686
+ if (event.target.closest("input")) {
687
+ event.preventDefault();
688
+ return;
689
+ }
690
+ event.stopPropagation();
691
+ setDragId(id);
692
+ },
693
+ onDragEnd: () => {
694
+ setDragId(null);
695
+ setDropSpot(null);
696
+ },
697
+ onDragOver: event => {
698
+ if (!dragId || dragId === id) {
699
+ return;
700
+ }
701
+ event.preventDefault();
702
+ event.stopPropagation();
703
+ const box = event.currentTarget.getBoundingClientRect();
704
+ const isTopHalf = event.clientY - box.top < box.height / 2;
705
+
706
+ /* an element dragged onto a GROUP header joins that group; the
707
+ insertion halves are reserved for reordering groups themselves */
708
+ if (isGroup(id) && !isGroup(dragId)) {
709
+ setDropSpot({
710
+ kind: "into",
711
+ id
712
+ });
713
+ return;
714
+ }
715
+ setDropSpot({
716
+ kind: isTopHalf ? "before" : "after",
717
+ id
718
+ });
719
+ },
720
+ onDrop: event => {
721
+ event.preventDefault();
722
+ event.stopPropagation();
723
+ handleDrop();
724
+ }
725
+ }), [dragId, handleDrop, isGroup]);
726
+ const dropClass = useCallback(id => {
727
+ if (dragId === id) {
728
+ return "dragging";
729
+ }
730
+ if (!dropSpot || dropSpot.id !== id) {
731
+ return "";
732
+ }
733
+ return "drop-" + dropSpot.kind;
734
+ }, [dragId, dropSpot]);
735
+ const renderElementRow = element => {
736
+ const TypeIcon = OUTLINE_TYPE_ICONS[element.type];
737
+ const selected = element.id === selectedId;
738
+ return /*#__PURE__*/React.createElement(StyledOutlineChildRow, _extends({
739
+ key: element.id,
740
+ className: (selected ? "selected" : "") + " " + dropClass(element.id),
741
+ onClick: () => onSelect(element.id)
742
+ }, rowDragProps(element.id)), /*#__PURE__*/React.createElement(StyledOutlineTypeIcon, null, /*#__PURE__*/React.createElement(TypeIcon, {
743
+ width: 16,
744
+ height: 16,
745
+ fill: element.name ? "var(--color-theme-700)" : "var(--color-theme-500)"
746
+ })), /*#__PURE__*/React.createElement(StyledOutlineName, {
747
+ className: element.name ? "" : "unnamed"
748
+ }, /*#__PURE__*/React.createElement(EditableText, {
749
+ value: outlineLabel(element),
750
+ variant: "Body 2",
751
+ weight: "medium",
752
+ disabled: !selected,
753
+ onSave: event => renameElement(element.id, event.target.value),
754
+ inputProps: {
755
+ maxLength: 150
756
+ }
757
+ })), element.locked || element.connections ? /*#__PURE__*/React.createElement(StyledOutlineSignifiers, {
758
+ className: "outline-trailing"
759
+ }, element.connections ? /*#__PURE__*/React.createElement(Signifier, {
760
+ type: DependencySmallIcon,
761
+ value: element.connections,
762
+ tooltipText: element.connections + " " + (element.connections === 1 ? "connection" : "connections")
763
+ }) : null, element.locked ? /*#__PURE__*/React.createElement(Signifier, {
764
+ type: LockSmallIcon,
765
+ tooltipText: "Locked"
766
+ }) : null) : null, /*#__PURE__*/React.createElement("span", {
767
+ className: "outline-options outline-hover"
768
+ }, /*#__PURE__*/React.createElement(OutlineElementOptionsMenu, {
769
+ locked: Boolean(element.locked),
770
+ onToggleLock: () => toggleLock(element.id)
771
+ })));
772
+ };
773
+ return /*#__PURE__*/React.createElement(StyledOutlineSidebar, {
774
+ style: {
775
+ width
776
+ }
777
+ }, /*#__PURE__*/React.createElement(StyledOutlineResizer, {
778
+ className: resizing ? "resizing" : "",
779
+ onMouseDown: startResize,
780
+ role: "separator",
781
+ "aria-orientation": "vertical",
782
+ "aria-label": "Resize outline"
783
+ }), /*#__PURE__*/React.createElement(StyledSidebarHeader, null, /*#__PURE__*/React.createElement(LeftMenuContents, {
784
+ sidebarOpen: sidebarOpen,
785
+ onToggleSidebar: onToggleSidebar,
786
+ boardName: boardName,
787
+ onRenameBoard: onRenameBoard
788
+ })), /*#__PURE__*/React.createElement(StyledChooseRow, null, /*#__PURE__*/React.createElement(StyledPanelChooseSlot, null, /*#__PURE__*/React.createElement(ChooseV2, {
789
+ required: true,
790
+ options: [{
791
+ id: "info",
792
+ name: "Info"
793
+ }, {
794
+ id: "outline",
795
+ name: "Outline"
796
+ }],
797
+ selected: [activePanel],
798
+ onChange: selected => onPanelChange(selected[0])
799
+ }))), activePanel === "info" ? /*#__PURE__*/React.createElement(InfoPanelContent, {
800
+ boardName: boardName
801
+ }) : null, activePanel === "outline" ? /*#__PURE__*/React.createElement(StyledOutlineBody, null, /*#__PURE__*/React.createElement(StyledOutlineGroupRow, {
802
+ className: (dropSpot == null ? void 0 : dropSpot.kind) === "into" && dropSpot.id === UNGROUPED ? "drop-into" : "",
803
+ onClick: () => toggleCollapsed(UNGROUPED),
804
+ onDragOver: event => {
805
+ if (!dragId || isGroup(dragId)) {
806
+ return;
807
+ }
808
+ event.preventDefault();
809
+ setDropSpot({
810
+ kind: "into",
811
+ id: UNGROUPED
812
+ });
813
+ },
814
+ onDrop: event => {
815
+ event.preventDefault();
816
+ handleDrop();
817
+ }
818
+ }, /*#__PURE__*/React.createElement(StyledOutlineToggle, {
819
+ type: "button",
820
+ className: collapsed.includes(UNGROUPED) ? "collapsed" : "",
821
+ "aria-label": "Toggle ungrouped",
822
+ onClick: event => {
823
+ event.stopPropagation();
824
+ toggleCollapsed(UNGROUPED);
825
+ }
826
+ }, /*#__PURE__*/React.createElement(CollapseExpandSingleIcon, {
827
+ fill: "var(--color-theme-700)"
828
+ })), /*#__PURE__*/React.createElement(StyledOutlineName, null, /*#__PURE__*/React.createElement(Header3, {
829
+ color: "primary"
830
+ }, "Ungrouped")), /*#__PURE__*/React.createElement(OutlineCounter, {
831
+ count: membersOf(null).length
832
+ })), collapsed.includes(UNGROUPED) ? null : membersOf(null).map(renderElementRow), groups.map(group => {
833
+ const members = membersOf(group.id);
834
+ const isOpen = !collapsed.includes(group.id);
835
+ return /*#__PURE__*/React.createElement(React.Fragment, {
836
+ key: group.id
837
+ }, /*#__PURE__*/React.createElement(StyledOutlineGroupRow, _extends({
838
+ className: dropClass(group.id),
839
+ onClick: () => toggleCollapsed(group.id)
840
+ }, rowDragProps(group.id)), /*#__PURE__*/React.createElement(StyledOutlineToggle, {
841
+ type: "button",
842
+ className: isOpen ? "" : "collapsed",
843
+ "aria-label": isOpen ? "Collapse group" : "Expand group",
844
+ onClick: event => {
845
+ event.stopPropagation();
846
+ toggleCollapsed(group.id);
847
+ }
848
+ }, /*#__PURE__*/React.createElement(CollapseExpandSingleIcon, {
849
+ fill: "var(--color-theme-700)"
850
+ })), /*#__PURE__*/React.createElement(StyledOutlineName, {
851
+ onClick: event => event.stopPropagation()
852
+ }, /*#__PURE__*/React.createElement(EditableText, {
853
+ value: group.name,
854
+ variant: "Header 3",
855
+ weight: "bold",
856
+ onSave: event => renameGroup(group.id, event.target.value),
857
+ inputProps: {
858
+ maxLength: 150
859
+ }
860
+ })), /*#__PURE__*/React.createElement(OutlineCounter, {
861
+ count: members.length
862
+ }), /*#__PURE__*/React.createElement("span", {
863
+ className: "outline-options outline-hover"
864
+ }, /*#__PURE__*/React.createElement(OutlineGroupOptionsMenu, null))), isOpen ? members.map(renderElementRow) : null);
865
+ }), /*#__PURE__*/React.createElement(StyledNewGroupRow, null, /*#__PURE__*/React.createElement(Button, {
866
+ variant: "text gray",
867
+ onClick: addGroup
868
+ }, /*#__PURE__*/React.createElement(FolderPlusIcon, null), "New Group"))) : null);
869
+ };
870
+ //# sourceMappingURL=outline.js.map