@webiny/app-admin-ui 0.0.0-unstable.a4f3e4ea8b → 0.0.0-unstable.a85ef555b2

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 (171) hide show
  1. package/Breadcrumbs/Breadcrumbs.d.ts +14 -0
  2. package/Breadcrumbs/Breadcrumbs.js +74 -0
  3. package/Breadcrumbs/Breadcrumbs.js.map +1 -0
  4. package/CommandPalette/CommandPalette.d.ts +2 -2
  5. package/CommandPalette/CommandPalette.js +106 -75
  6. package/CommandPalette/CommandPalette.js.map +1 -1
  7. package/CommandPalette/components/AiModeBadge.d.ts +3 -0
  8. package/CommandPalette/components/AiModeBadge.js +11 -0
  9. package/CommandPalette/components/AiModeBadge.js.map +1 -0
  10. package/CommandPalette/components/AiSuggestions.d.ts +9 -0
  11. package/CommandPalette/components/AiSuggestions.js +32 -0
  12. package/CommandPalette/components/AiSuggestions.js.map +1 -0
  13. package/CommandPalette/components/AiTurn.d.ts +11 -0
  14. package/CommandPalette/components/AiTurn.js +61 -0
  15. package/CommandPalette/components/AiTurn.js.map +1 -0
  16. package/CommandPalette/components/AnswerSkeleton.d.ts +6 -0
  17. package/CommandPalette/components/AnswerSkeleton.js +20 -0
  18. package/CommandPalette/components/AnswerSkeleton.js.map +1 -0
  19. package/CommandPalette/components/ApprovalPlan.d.ts +16 -0
  20. package/CommandPalette/components/ApprovalPlan.js +56 -0
  21. package/CommandPalette/components/ApprovalPlan.js.map +1 -0
  22. package/CommandPalette/components/CommandItemRow.js +4 -2
  23. package/CommandPalette/components/CommandItemRow.js.map +1 -1
  24. package/CommandPalette/components/NoResults.d.ts +13 -0
  25. package/CommandPalette/components/NoResults.js +33 -0
  26. package/CommandPalette/components/NoResults.js.map +1 -0
  27. package/CommandPalette/components/PaletteFooter.d.ts +13 -0
  28. package/CommandPalette/components/PaletteFooter.js +18 -0
  29. package/CommandPalette/components/PaletteFooter.js.map +1 -0
  30. package/CommandPalette/components/ToolChip.d.ts +7 -0
  31. package/CommandPalette/components/ToolChip.js +32 -0
  32. package/CommandPalette/components/ToolChip.js.map +1 -0
  33. package/CommandPalette/components/index.d.ts +13 -5
  34. package/CommandPalette/components/index.js +13 -5
  35. package/CommandPalette/modes/PaletteMode.d.ts +73 -0
  36. package/CommandPalette/modes/PaletteMode.js +0 -0
  37. package/CommandPalette/modes/createAiMode.d.ts +13 -0
  38. package/CommandPalette/modes/createAiMode.js +80 -0
  39. package/CommandPalette/modes/createAiMode.js.map +1 -0
  40. package/CommandPalette/modes/index.d.ts +2 -0
  41. package/CommandPalette/modes/index.js +1 -0
  42. package/CommandPalette/usePaletteHotkeys.d.ts +16 -0
  43. package/CommandPalette/usePaletteHotkeys.js +38 -0
  44. package/CommandPalette/usePaletteHotkeys.js.map +1 -0
  45. package/Dashboard/Welcome.d.ts +4 -1
  46. package/Dashboard/Welcome.js +111 -24
  47. package/Dashboard/Welcome.js.map +1 -1
  48. package/Dashboard/components/DashboardToolbar.d.ts +11 -0
  49. package/Dashboard/components/DashboardToolbar.js +48 -0
  50. package/Dashboard/components/DashboardToolbar.js.map +1 -0
  51. package/Dashboard/components/addWidgetDrawer/AddToColumnMenu.d.ts +10 -0
  52. package/Dashboard/components/addWidgetDrawer/AddToColumnMenu.js +30 -0
  53. package/Dashboard/components/addWidgetDrawer/AddToColumnMenu.js.map +1 -0
  54. package/Dashboard/components/addWidgetDrawer/AddWidgetDrawer.d.ts +12 -0
  55. package/Dashboard/components/addWidgetDrawer/AddWidgetDrawer.js +61 -0
  56. package/Dashboard/components/addWidgetDrawer/AddWidgetDrawer.js.map +1 -0
  57. package/Dashboard/components/addWidgetDrawer/DrawerWidgetRow.d.ts +10 -0
  58. package/Dashboard/components/addWidgetDrawer/DrawerWidgetRow.js +38 -0
  59. package/Dashboard/components/addWidgetDrawer/DrawerWidgetRow.js.map +1 -0
  60. package/Dashboard/components/addWidgetDrawer/WidgetPreviewFrame.d.ts +7 -0
  61. package/Dashboard/components/addWidgetDrawer/WidgetPreviewFrame.js +44 -0
  62. package/Dashboard/components/addWidgetDrawer/WidgetPreviewFrame.js.map +1 -0
  63. package/Dashboard/components/addWidgetDrawer/WidgetSketch.d.ts +4 -0
  64. package/Dashboard/components/addWidgetDrawer/WidgetSketch.js +20 -0
  65. package/Dashboard/components/addWidgetDrawer/WidgetSketch.js.map +1 -0
  66. package/Dashboard/components/addWidgetDrawer/WidgetTabContent.d.ts +14 -0
  67. package/Dashboard/components/addWidgetDrawer/WidgetTabContent.js +76 -0
  68. package/Dashboard/components/addWidgetDrawer/WidgetTabContent.js.map +1 -0
  69. package/Dashboard/components/addWidgetDrawer/types.d.ts +10 -0
  70. package/Dashboard/components/addWidgetDrawer/types.js +0 -0
  71. package/Dashboard/components/dnd/ColumnCountControl.d.ts +9 -0
  72. package/Dashboard/components/dnd/ColumnCountControl.js +52 -0
  73. package/Dashboard/components/dnd/ColumnCountControl.js.map +1 -0
  74. package/Dashboard/components/dnd/ColumnEmptyState.d.ts +10 -0
  75. package/Dashboard/components/dnd/ColumnEmptyState.js +52 -0
  76. package/Dashboard/components/dnd/ColumnEmptyState.js.map +1 -0
  77. package/Dashboard/components/dnd/DashboardDragLayer.d.ts +6 -0
  78. package/Dashboard/components/dnd/DashboardDragLayer.js +28 -0
  79. package/Dashboard/components/dnd/DashboardDragLayer.js.map +1 -0
  80. package/Dashboard/components/dnd/DashboardWidgetCard.d.ts +13 -0
  81. package/Dashboard/components/dnd/DashboardWidgetCard.js +59 -0
  82. package/Dashboard/components/dnd/DashboardWidgetCard.js.map +1 -0
  83. package/Dashboard/components/dnd/DashboardWidgetColumn.d.ts +19 -0
  84. package/Dashboard/components/dnd/DashboardWidgetColumn.js +72 -0
  85. package/Dashboard/components/dnd/DashboardWidgetColumn.js.map +1 -0
  86. package/Dashboard/components/dnd/WidgetDropIndicator.d.ts +11 -0
  87. package/Dashboard/components/dnd/WidgetDropIndicator.js +29 -0
  88. package/Dashboard/components/dnd/WidgetDropIndicator.js.map +1 -0
  89. package/Dashboard/components/dnd/WidgetSlot.d.ts +6 -0
  90. package/Dashboard/components/dnd/WidgetSlot.js +9 -0
  91. package/Dashboard/components/dnd/WidgetSlot.js.map +1 -0
  92. package/Dashboard/components/dnd/dragItem.d.ts +6 -0
  93. package/Dashboard/components/dnd/dragItem.js +4 -0
  94. package/Dashboard/components/dnd/dragItem.js.map +1 -0
  95. package/Dashboard/components/dnd/useWidgetHosts.d.ts +1 -0
  96. package/Dashboard/components/dnd/useWidgetHosts.js +16 -0
  97. package/Dashboard/components/dnd/useWidgetHosts.js.map +1 -0
  98. package/Dashboard/components/layout/EditableColumns.d.ts +13 -0
  99. package/Dashboard/components/layout/EditableColumns.js +25 -0
  100. package/Dashboard/components/layout/EditableColumns.js.map +1 -0
  101. package/Dashboard/components/layout/StaticColumns.d.ts +8 -0
  102. package/Dashboard/components/layout/StaticColumns.js +20 -0
  103. package/Dashboard/components/layout/StaticColumns.js.map +1 -0
  104. package/Dashboard/components/layout/collapseColumns.d.ts +1 -0
  105. package/Dashboard/components/layout/collapseColumns.js +16 -0
  106. package/Dashboard/components/layout/collapseColumns.js.map +1 -0
  107. package/Dashboard/components/layout/layoutConstants.d.ts +2 -0
  108. package/Dashboard/components/layout/layoutConstants.js +5 -0
  109. package/Dashboard/components/layout/layoutConstants.js.map +1 -0
  110. package/Dashboard/components/layout/useColumnsThatFit.d.ts +6 -0
  111. package/Dashboard/components/layout/useColumnsThatFit.js +30 -0
  112. package/Dashboard/components/layout/useColumnsThatFit.js.map +1 -0
  113. package/Dashboard/components/layout/useWidgetPortals.d.ts +5 -0
  114. package/Dashboard/components/layout/useWidgetPortals.js +26 -0
  115. package/Dashboard/components/layout/useWidgetPortals.js.map +1 -0
  116. package/Dashboard/dashboardLayout/loadLayout/FetchDashboardLayoutUseCase.d.ts +12 -0
  117. package/Dashboard/dashboardLayout/loadLayout/FetchDashboardLayoutUseCase.js +19 -0
  118. package/Dashboard/dashboardLayout/loadLayout/FetchDashboardLayoutUseCase.js.map +1 -0
  119. package/Dashboard/dashboardLayout/loadLayout/GetCachedDashboardLayoutUseCase.d.ts +12 -0
  120. package/Dashboard/dashboardLayout/loadLayout/GetCachedDashboardLayoutUseCase.js +19 -0
  121. package/Dashboard/dashboardLayout/loadLayout/GetCachedDashboardLayoutUseCase.js.map +1 -0
  122. package/Dashboard/dashboardLayout/loadLayout/abstractions.d.ts +15 -0
  123. package/Dashboard/dashboardLayout/loadLayout/abstractions.js +6 -0
  124. package/Dashboard/dashboardLayout/loadLayout/abstractions.js.map +1 -0
  125. package/Dashboard/dashboardLayout/loadLayout/feature.d.ts +1 -0
  126. package/Dashboard/dashboardLayout/loadLayout/feature.js +13 -0
  127. package/Dashboard/dashboardLayout/loadLayout/feature.js.map +1 -0
  128. package/Dashboard/dashboardLayout/presenter/DashboardLayoutPresenter.d.ts +56 -0
  129. package/Dashboard/dashboardLayout/presenter/DashboardLayoutPresenter.js +308 -0
  130. package/Dashboard/dashboardLayout/presenter/DashboardLayoutPresenter.js.map +1 -0
  131. package/Dashboard/dashboardLayout/presenter/abstractions.d.ts +46 -0
  132. package/Dashboard/dashboardLayout/presenter/abstractions.js +5 -0
  133. package/Dashboard/dashboardLayout/presenter/abstractions.js.map +1 -0
  134. package/Dashboard/dashboardLayout/presenter/feature.d.ts +3 -0
  135. package/Dashboard/dashboardLayout/presenter/feature.js +23 -0
  136. package/Dashboard/dashboardLayout/presenter/feature.js.map +1 -0
  137. package/Dashboard/dashboardLayout/presenter/useDashboardLayoutPresenter.d.ts +1 -0
  138. package/Dashboard/dashboardLayout/presenter/useDashboardLayoutPresenter.js +6 -0
  139. package/Dashboard/dashboardLayout/presenter/useDashboardLayoutPresenter.js.map +1 -0
  140. package/Dashboard/dashboardLayout/repository/DashboardLayoutGateway.d.ts +13 -0
  141. package/Dashboard/dashboardLayout/repository/DashboardLayoutGateway.js +67 -0
  142. package/Dashboard/dashboardLayout/repository/DashboardLayoutGateway.js.map +1 -0
  143. package/Dashboard/dashboardLayout/repository/DashboardLayoutRepository.d.ts +20 -0
  144. package/Dashboard/dashboardLayout/repository/DashboardLayoutRepository.js +49 -0
  145. package/Dashboard/dashboardLayout/repository/DashboardLayoutRepository.js.map +1 -0
  146. package/Dashboard/dashboardLayout/repository/abstractions.d.ts +25 -0
  147. package/Dashboard/dashboardLayout/repository/abstractions.js +6 -0
  148. package/Dashboard/dashboardLayout/repository/abstractions.js.map +1 -0
  149. package/Dashboard/dashboardLayout/repository/feature.d.ts +1 -0
  150. package/Dashboard/dashboardLayout/repository/feature.js +13 -0
  151. package/Dashboard/dashboardLayout/repository/feature.js.map +1 -0
  152. package/Dashboard/dashboardLayout/saveLayout/SaveDashboardLayoutUseCase.d.ts +12 -0
  153. package/Dashboard/dashboardLayout/saveLayout/SaveDashboardLayoutUseCase.js +19 -0
  154. package/Dashboard/dashboardLayout/saveLayout/SaveDashboardLayoutUseCase.js.map +1 -0
  155. package/Dashboard/dashboardLayout/saveLayout/abstractions.d.ts +8 -0
  156. package/Dashboard/dashboardLayout/saveLayout/abstractions.js +5 -0
  157. package/Dashboard/dashboardLayout/saveLayout/abstractions.js.map +1 -0
  158. package/Dashboard/dashboardLayout/saveLayout/feature.d.ts +1 -0
  159. package/Dashboard/dashboardLayout/saveLayout/feature.js +11 -0
  160. package/Dashboard/dashboardLayout/saveLayout/feature.js.map +1 -0
  161. package/Dashboard/dashboardLayout/toColumnIndex.d.ts +1 -0
  162. package/Dashboard/dashboardLayout/toColumnIndex.js +7 -0
  163. package/Dashboard/dashboardLayout/toColumnIndex.js.map +1 -0
  164. package/Dashboard/dashboardLayout/types.d.ts +15 -0
  165. package/Dashboard/dashboardLayout/types.js +6 -0
  166. package/Dashboard/dashboardLayout/types.js.map +1 -0
  167. package/Layout.js +7 -5
  168. package/Layout.js.map +1 -1
  169. package/index.js +15 -4
  170. package/index.js.map +1 -1
  171. package/package.json +13 -7
@@ -0,0 +1,76 @@
1
+ import react from "react";
2
+ import { EmptyState, Icon, Input, Text } from "@webiny/admin-ui";
3
+ import { ReactComponent } from "@webiny/icons/search.svg";
4
+ import { DrawerWidgetRow } from "./DrawerWidgetRow.js";
5
+ const DEFAULT_GROUP = "Other";
6
+ const matchesSearch = (widget, query)=>{
7
+ if (!query) return true;
8
+ const fields = [
9
+ widget.title,
10
+ widget.description,
11
+ widget.group
12
+ ];
13
+ return fields.some((value)=>value?.toLowerCase().includes(query));
14
+ };
15
+ const groupWidgets = (widgets)=>{
16
+ const byGroup = new Map();
17
+ for (const widget of widgets){
18
+ const group = widget.group ?? DEFAULT_GROUP;
19
+ const items = byGroup.get(group) ?? [];
20
+ byGroup.set(group, [
21
+ ...items,
22
+ widget
23
+ ]);
24
+ }
25
+ return [
26
+ ...byGroup.entries()
27
+ ];
28
+ };
29
+ const WidgetTabContent = ({ items, search, onSearch, emptyTitle, emptyDescription, columnCount, presenter })=>{
30
+ const query = search.trim().toLowerCase();
31
+ const matches = items.filter((widget)=>matchesSearch(widget, query));
32
+ const groups = groupWidgets(matches);
33
+ let emptyState = null;
34
+ if (0 === items.length) emptyState = /*#__PURE__*/ react.createElement(EmptyState, {
35
+ size: "sm",
36
+ type: "layout",
37
+ title: emptyTitle,
38
+ description: emptyDescription
39
+ });
40
+ else if (0 === matches.length) emptyState = /*#__PURE__*/ react.createElement(EmptyState, {
41
+ size: "sm",
42
+ type: "select",
43
+ title: `No widgets match "${search}"`,
44
+ description: "Try a different search."
45
+ });
46
+ return /*#__PURE__*/ react.createElement("div", {
47
+ className: "pb-lg"
48
+ }, items.length > 0 && /*#__PURE__*/ react.createElement(Input, {
49
+ placeholder: "Search widgets",
50
+ value: search,
51
+ onChange: onSearch,
52
+ startIcon: /*#__PURE__*/ react.createElement(Icon, {
53
+ label: "Search",
54
+ icon: /*#__PURE__*/ react.createElement(ReactComponent, null)
55
+ })
56
+ }), emptyState && /*#__PURE__*/ react.createElement("div", {
57
+ className: "mt-lg"
58
+ }, emptyState), groups.map(([group, groupItems])=>/*#__PURE__*/ react.createElement("div", {
59
+ key: group,
60
+ className: "mt-lg"
61
+ }, /*#__PURE__*/ react.createElement(Text, {
62
+ as: "div",
63
+ size: "sm",
64
+ className: "mb-sm font-semibold uppercase tracking-wide text-neutral-strong"
65
+ }, group), /*#__PURE__*/ react.createElement("div", {
66
+ className: "flex flex-col gap-sm"
67
+ }, groupItems.map((widget)=>/*#__PURE__*/ react.createElement(DrawerWidgetRow, {
68
+ key: widget.name,
69
+ widget: widget,
70
+ columnCount: columnCount,
71
+ presenter: presenter
72
+ }))))));
73
+ };
74
+ export { WidgetTabContent };
75
+
76
+ //# sourceMappingURL=WidgetTabContent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dashboard/components/addWidgetDrawer/WidgetTabContent.js","sources":["../../../../src/Dashboard/components/addWidgetDrawer/WidgetTabContent.tsx"],"sourcesContent":["import React from \"react\";\nimport { EmptyState } from \"@webiny/admin-ui\";\nimport { Icon } from \"@webiny/admin-ui\";\nimport { Input } from \"@webiny/admin-ui\";\nimport { Text } from \"@webiny/admin-ui\";\nimport { ReactComponent as SearchIcon } from \"@webiny/icons/search.svg\";\nimport type { DashboardLayoutPresenter } from \"../../dashboardLayout/presenter/abstractions.js\";\nimport type { DrawerWidget } from \"./types.js\";\nimport { DrawerWidgetRow } from \"./DrawerWidgetRow.js\";\n\nconst DEFAULT_GROUP = \"Other\";\n\nconst matchesSearch = (widget: DrawerWidget, query: string): boolean => {\n if (!query) {\n return true;\n }\n const fields = [widget.title, widget.description, widget.group];\n return fields.some(value => value?.toLowerCase().includes(query));\n};\n\nconst groupWidgets = (widgets: DrawerWidget[]): [string, DrawerWidget[]][] => {\n const byGroup = new Map<string, DrawerWidget[]>();\n for (const widget of widgets) {\n const group = widget.group ?? DEFAULT_GROUP;\n const items = byGroup.get(group) ?? [];\n byGroup.set(group, [...items, widget]);\n }\n return [...byGroup.entries()];\n};\n\ninterface WidgetTabContentProps {\n items: DrawerWidget[];\n search: string;\n onSearch: (value: string) => void;\n emptyTitle: string;\n emptyDescription: string;\n columnCount: number;\n presenter: DashboardLayoutPresenter.Interface;\n}\n\nexport const WidgetTabContent = ({\n items,\n search,\n onSearch,\n emptyTitle,\n emptyDescription,\n columnCount,\n presenter\n}: WidgetTabContentProps) => {\n const query = search.trim().toLowerCase();\n const matches = items.filter(widget => matchesSearch(widget, query));\n const groups = groupWidgets(matches);\n\n let emptyState: React.ReactNode = null;\n if (items.length === 0) {\n emptyState = (\n <EmptyState\n size={\"sm\"}\n type={\"layout\"}\n title={emptyTitle}\n description={emptyDescription}\n />\n );\n } else if (matches.length === 0) {\n emptyState = (\n <EmptyState\n size={\"sm\"}\n type={\"select\"}\n title={`No widgets match \"${search}\"`}\n description={\"Try a different search.\"}\n />\n );\n }\n\n return (\n <div className={\"pb-lg\"}>\n {items.length > 0 && (\n <Input\n placeholder={\"Search widgets\"}\n value={search}\n onChange={onSearch}\n startIcon={<Icon label={\"Search\"} icon={<SearchIcon />} />}\n />\n )}\n {emptyState && <div className={\"mt-lg\"}>{emptyState}</div>}\n {groups.map(([group, groupItems]) => (\n <div key={group} className={\"mt-lg\"}>\n <Text\n as={\"div\"}\n size={\"sm\"}\n className={\n \"mb-sm font-semibold uppercase tracking-wide text-neutral-strong\"\n }\n >\n {group}\n </Text>\n <div className={\"flex flex-col gap-sm\"}>\n {groupItems.map(widget => (\n <DrawerWidgetRow\n key={widget.name}\n widget={widget}\n columnCount={columnCount}\n presenter={presenter}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n );\n};\n"],"names":["DEFAULT_GROUP","matchesSearch","widget","query","fields","value","groupWidgets","widgets","byGroup","Map","group","items","WidgetTabContent","search","onSearch","emptyTitle","emptyDescription","columnCount","presenter","matches","groups","emptyState","EmptyState","Input","Icon","SearchIcon","groupItems","Text","DrawerWidgetRow"],"mappings":";;;;AAUA,MAAMA,gBAAgB;AAEtB,MAAMC,gBAAgB,CAACC,QAAsBC;IACzC,IAAI,CAACA,OACD,OAAO;IAEX,MAAMC,SAAS;QAACF,OAAO,KAAK;QAAEA,OAAO,WAAW;QAAEA,OAAO,KAAK;KAAC;IAC/D,OAAOE,OAAO,IAAI,CAACC,CAAAA,QAASA,OAAO,cAAc,SAASF;AAC9D;AAEA,MAAMG,eAAe,CAACC;IAClB,MAAMC,UAAU,IAAIC;IACpB,KAAK,MAAMP,UAAUK,QAAS;QAC1B,MAAMG,QAAQR,OAAO,KAAK,IAAIF;QAC9B,MAAMW,QAAQH,QAAQ,GAAG,CAACE,UAAU,EAAE;QACtCF,QAAQ,GAAG,CAACE,OAAO;eAAIC;YAAOT;SAAO;IACzC;IACA,OAAO;WAAIM,QAAQ,OAAO;KAAG;AACjC;AAYO,MAAMI,mBAAmB,CAAC,EAC7BD,KAAK,EACLE,MAAM,EACNC,QAAQ,EACRC,UAAU,EACVC,gBAAgB,EAChBC,WAAW,EACXC,SAAS,EACW;IACpB,MAAMf,QAAQU,OAAO,IAAI,GAAG,WAAW;IACvC,MAAMM,UAAUR,MAAM,MAAM,CAACT,CAAAA,SAAUD,cAAcC,QAAQC;IAC7D,MAAMiB,SAASd,aAAaa;IAE5B,IAAIE,aAA8B;IAClC,IAAIV,AAAiB,MAAjBA,MAAM,MAAM,EACZU,aAAa,WAAbA,GACI,oBAACC,YAAUA;QACP,MAAM;QACN,MAAM;QACN,OAAOP;QACP,aAAaC;;SAGlB,IAAIG,AAAmB,MAAnBA,QAAQ,MAAM,EACrBE,aAAa,WAAbA,GACI,oBAACC,YAAUA;QACP,MAAM;QACN,MAAM;QACN,OAAO,CAAC,kBAAkB,EAAET,OAAO,CAAC,CAAC;QACrC,aAAa;;IAKzB,OAAO,WAAP,GACI,oBAAC;QAAI,WAAW;OACXF,MAAM,MAAM,GAAG,KAAK,WAAL,GACZ,oBAACY,OAAKA;QACF,aAAa;QACb,OAAOV;QACP,UAAUC;QACV,yBAAW,oBAACU,MAAIA;YAAC,OAAO;YAAU,oBAAM,oBAACC,gBAAUA;;QAG1DJ,cAAc,WAAdA,GAAc,oBAAC;QAAI,WAAW;OAAUA,aACxCD,OAAO,GAAG,CAAC,CAAC,CAACV,OAAOgB,WAAW,iBAC5B,oBAAC;YAAI,KAAKhB;YAAO,WAAW;yBACxB,oBAACiB,MAAIA;YACD,IAAI;YACJ,MAAM;YACN,WACI;WAGHjB,QAAAA,WAAAA,GAEL,oBAAC;YAAI,WAAW;WACXgB,WAAW,GAAG,CAACxB,CAAAA,SAAAA,WAAAA,GACZ,oBAAC0B,iBAAeA;gBACZ,KAAK1B,OAAO,IAAI;gBAChB,QAAQA;gBACR,aAAae;gBACb,WAAWC;;AAQ3C"}
@@ -0,0 +1,10 @@
1
+ import type React from "react";
2
+ export interface DrawerWidget {
3
+ name: string;
4
+ title: string;
5
+ description?: string;
6
+ group?: string;
7
+ preview?: React.ReactElement;
8
+ added: boolean;
9
+ defaultColumn: number;
10
+ }
File without changes
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ import type { DashboardLayoutPresenter } from "../../dashboardLayout/presenter/abstractions.js";
3
+ interface ColumnCountControlProps {
4
+ columnCount: number;
5
+ disabled?: boolean;
6
+ presenter: DashboardLayoutPresenter.Interface;
7
+ }
8
+ export declare const ColumnCountControl: ({ columnCount, disabled, presenter }: ColumnCountControlProps) => React.JSX.Element;
9
+ export {};
@@ -0,0 +1,52 @@
1
+ import react from "react";
2
+ import { Icon, ToggleGroup } from "@webiny/admin-ui";
3
+ import { ReactComponent } from "@webiny/icons/view_column_2.svg";
4
+ import { ReactComponent as view_column_svg_ReactComponent } from "@webiny/icons/view_column.svg";
5
+ import { ReactComponent as view_column_4_svg_ReactComponent } from "@webiny/icons/view_column_4.svg";
6
+ const ITEMS = [
7
+ {
8
+ value: "2",
9
+ icon: /*#__PURE__*/ react.createElement(Icon, {
10
+ icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
11
+ label: "2 columns",
12
+ size: "sm"
13
+ }),
14
+ tooltip: "2 columns"
15
+ },
16
+ {
17
+ value: "3",
18
+ icon: /*#__PURE__*/ react.createElement(Icon, {
19
+ icon: /*#__PURE__*/ react.createElement(view_column_svg_ReactComponent, null),
20
+ label: "3 columns",
21
+ size: "sm"
22
+ }),
23
+ tooltip: "3 columns"
24
+ },
25
+ {
26
+ value: "4",
27
+ icon: /*#__PURE__*/ react.createElement(Icon, {
28
+ icon: /*#__PURE__*/ react.createElement(view_column_4_svg_ReactComponent, null),
29
+ label: "4 columns",
30
+ size: "sm"
31
+ }),
32
+ tooltip: "4 columns"
33
+ }
34
+ ];
35
+ const ColumnCountControl = ({ columnCount, disabled, presenter })=>/*#__PURE__*/ react.createElement(ToggleGroup, {
36
+ type: "single",
37
+ variant: "ghost",
38
+ size: "sm",
39
+ bordered: true,
40
+ items: ITEMS,
41
+ value: String(columnCount),
42
+ disabled: disabled,
43
+ onChange: (value)=>{
44
+ if (value) {
45
+ const count = Number(value);
46
+ presenter.setColumnCount(count);
47
+ }
48
+ }
49
+ });
50
+ export { ColumnCountControl };
51
+
52
+ //# sourceMappingURL=ColumnCountControl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dashboard/components/dnd/ColumnCountControl.js","sources":["../../../../src/Dashboard/components/dnd/ColumnCountControl.tsx"],"sourcesContent":["import React from \"react\";\nimport { Icon } from \"@webiny/admin-ui\";\nimport { ToggleGroup } from \"@webiny/admin-ui\";\nimport { ReactComponent as TwoColumnsIcon } from \"@webiny/icons/view_column_2.svg\";\nimport { ReactComponent as ThreeColumnsIcon } from \"@webiny/icons/view_column.svg\";\nimport { ReactComponent as FourColumnsIcon } from \"@webiny/icons/view_column_4.svg\";\nimport type { DashboardLayoutPresenter } from \"../../dashboardLayout/presenter/abstractions.js\";\n\ninterface ColumnCountControlProps {\n columnCount: number;\n disabled?: boolean;\n presenter: DashboardLayoutPresenter.Interface;\n}\n\n// Covers MIN_COLUMN_COUNT..MAX_COLUMN_COUNT; add an icon here if that range grows.\n// `Icon`'s label is what gives each icon-only toggle an accessible name.\nconst ITEMS = [\n {\n value: \"2\",\n icon: <Icon icon={<TwoColumnsIcon />} label={\"2 columns\"} size={\"sm\"} />,\n tooltip: \"2 columns\"\n },\n {\n value: \"3\",\n icon: <Icon icon={<ThreeColumnsIcon />} label={\"3 columns\"} size={\"sm\"} />,\n tooltip: \"3 columns\"\n },\n {\n value: \"4\",\n icon: <Icon icon={<FourColumnsIcon />} label={\"4 columns\"} size={\"sm\"} />,\n tooltip: \"4 columns\"\n }\n];\n\nexport const ColumnCountControl = ({\n columnCount,\n disabled,\n presenter\n}: ColumnCountControlProps) => {\n return (\n <ToggleGroup\n type={\"single\"}\n variant={\"ghost\"}\n size={\"sm\"}\n bordered={true}\n items={ITEMS}\n value={String(columnCount)}\n disabled={disabled}\n onChange={value => {\n // Clicking the active option would clear it; a count is always required.\n if (value) {\n const count = Number(value);\n presenter.setColumnCount(count);\n }\n }}\n />\n );\n};\n"],"names":["ITEMS","Icon","TwoColumnsIcon","ThreeColumnsIcon","FourColumnsIcon","ColumnCountControl","columnCount","disabled","presenter","ToggleGroup","String","value","count","Number"],"mappings":";;;;;AAgBA,MAAMA,QAAQ;IACV;QACI,OAAO;QACP,MAAM,WAAN,GAAM,oBAACC,MAAIA;YAAC,oBAAM,oBAACC,gBAAcA;YAAK,OAAO;YAAa,MAAM;;QAChE,SAAS;IACb;IACA;QACI,OAAO;QACP,MAAM,WAAN,GAAM,oBAACD,MAAIA;YAAC,oBAAM,oBAACE,gCAAgBA;YAAK,OAAO;YAAa,MAAM;;QAClE,SAAS;IACb;IACA;QACI,OAAO;QACP,MAAM,WAAN,GAAM,oBAACF,MAAIA;YAAC,oBAAM,oBAACG,kCAAeA;YAAK,OAAO;YAAa,MAAM;;QACjE,SAAS;IACb;CACH;AAEM,MAAMC,qBAAqB,CAAC,EAC/BC,WAAW,EACXC,QAAQ,EACRC,SAAS,EACa,GACf,WAAP,GACI,oBAACC,aAAWA;QACR,MAAM;QACN,SAAS;QACT,MAAM;QACN,UAAU;QACV,OAAOT;QACP,OAAOU,OAAOJ;QACd,UAAUC;QACV,UAAUI,CAAAA;YAEN,IAAIA,OAAO;gBACP,MAAMC,QAAQC,OAAOF;gBACrBH,UAAU,cAAc,CAACI;YAC7B;QACJ"}
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ interface ColumnEmptyStateProps {
3
+ canRemove: boolean;
4
+ onRemove: () => void;
5
+ onBrowse: () => void;
6
+ dragging: boolean;
7
+ active: boolean;
8
+ }
9
+ export declare const ColumnEmptyState: ({ canRemove, onRemove, onBrowse, dragging, active }: ColumnEmptyStateProps) => React.JSX.Element;
10
+ export {};
@@ -0,0 +1,52 @@
1
+ import react from "react";
2
+ import { Button, Icon, Text, cn } from "@webiny/admin-ui";
3
+ import { ReactComponent } from "@webiny/icons/dashboard_customize.svg";
4
+ import { ReactComponent as add_circle_svg_ReactComponent } from "@webiny/icons/add_circle.svg";
5
+ const IDLE_CLASSES = "border-neutral-strong/40 bg-neutral-base/50 hover:border-neutral-strong/60";
6
+ const CAN_DROP_CLASSES = "border-primary/50 bg-primary/5";
7
+ const ACTIVE_CLASSES = "border-primary bg-primary/10";
8
+ const ColumnEmptyState = ({ canRemove, onRemove, onBrowse, dragging, active })=>{
9
+ let stateClasses = IDLE_CLASSES;
10
+ if (active) stateClasses = ACTIVE_CLASSES;
11
+ else if (dragging) stateClasses = CAN_DROP_CLASSES;
12
+ let icon = /*#__PURE__*/ react.createElement(Icon, {
13
+ icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
14
+ label: "Empty column",
15
+ size: "sm",
16
+ color: "neutral-strong"
17
+ });
18
+ if (dragging) icon = /*#__PURE__*/ react.createElement(Icon, {
19
+ icon: /*#__PURE__*/ react.createElement(add_circle_svg_ReactComponent, null),
20
+ label: "Drop here",
21
+ size: "sm",
22
+ color: "accent"
23
+ });
24
+ let body = /*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement(Text, {
25
+ as: "div",
26
+ size: "sm",
27
+ className: "text-center text-neutral-strong"
28
+ }, "Drop a widget here", /*#__PURE__*/ react.createElement("br", null), "or ", /*#__PURE__*/ react.createElement("button", {
29
+ type: "button",
30
+ onClick: onBrowse,
31
+ className: "cursor-pointer text-primary hover:underline"
32
+ }, "browse widgets")), canRemove && /*#__PURE__*/ react.createElement(Button, {
33
+ size: "sm",
34
+ variant: "ghost",
35
+ text: "Remove column",
36
+ onClick: onRemove
37
+ }));
38
+ if (dragging) body = /*#__PURE__*/ react.createElement(Text, {
39
+ as: "div",
40
+ size: "sm",
41
+ className: "text-center text-primary"
42
+ }, "Drop it here");
43
+ return /*#__PURE__*/ react.createElement("div", {
44
+ "data-testid": "dashboard-empty-column",
45
+ className: cn("flex min-h-[220px] flex-col items-center justify-center gap-sm rounded-xl", "border-2 border-dashed p-lg transition-colors", stateClasses)
46
+ }, /*#__PURE__*/ react.createElement("span", {
47
+ className: cn("flex size-xl items-center justify-center rounded-md", dragging ? "bg-primary/10" : "bg-neutral-dimmed")
48
+ }, icon), body);
49
+ };
50
+ export { ColumnEmptyState };
51
+
52
+ //# sourceMappingURL=ColumnEmptyState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dashboard/components/dnd/ColumnEmptyState.js","sources":["../../../../src/Dashboard/components/dnd/ColumnEmptyState.tsx"],"sourcesContent":["import React from \"react\";\nimport { Button } from \"@webiny/admin-ui\";\nimport { Icon } from \"@webiny/admin-ui\";\nimport { Text } from \"@webiny/admin-ui\";\nimport { cn } from \"@webiny/admin-ui\";\nimport { ReactComponent as DashboardCustomizeIcon } from \"@webiny/icons/dashboard_customize.svg\";\nimport { ReactComponent as AddCircleIcon } from \"@webiny/icons/add_circle.svg\";\n\ninterface ColumnEmptyStateProps {\n canRemove: boolean;\n onRemove: () => void;\n onBrowse: () => void;\n // A widget is being dragged somewhere on the dashboard.\n dragging: boolean;\n // ...and it's over this column.\n active: boolean;\n}\n\nconst IDLE_CLASSES = \"border-neutral-strong/40 bg-neutral-base/50 hover:border-neutral-strong/60\";\nconst CAN_DROP_CLASSES = \"border-primary/50 bg-primary/5\";\nconst ACTIVE_CLASSES = \"border-primary bg-primary/10\";\n\nexport const ColumnEmptyState = ({\n canRemove,\n onRemove,\n onBrowse,\n dragging,\n active\n}: ColumnEmptyStateProps) => {\n let stateClasses = IDLE_CLASSES;\n if (active) {\n stateClasses = ACTIVE_CLASSES;\n } else if (dragging) {\n stateClasses = CAN_DROP_CLASSES;\n }\n\n let icon = (\n <Icon\n icon={<DashboardCustomizeIcon />}\n label={\"Empty column\"}\n size={\"sm\"}\n color={\"neutral-strong\"}\n />\n );\n if (dragging) {\n icon = <Icon icon={<AddCircleIcon />} label={\"Drop here\"} size={\"sm\"} color={\"accent\"} />;\n }\n\n let body = (\n <>\n <Text as={\"div\"} size={\"sm\"} className={\"text-center text-neutral-strong\"}>\n {\"Drop a widget here\"}\n <br />\n {\"or \"}\n <button\n type={\"button\"}\n onClick={onBrowse}\n className={\"cursor-pointer text-primary hover:underline\"}\n >\n {\"browse widgets\"}\n </button>\n </Text>\n {canRemove && (\n <Button size={\"sm\"} variant={\"ghost\"} text={\"Remove column\"} onClick={onRemove} />\n )}\n </>\n );\n if (dragging) {\n body = (\n <Text as={\"div\"} size={\"sm\"} className={\"text-center text-primary\"}>\n {\"Drop it here\"}\n </Text>\n );\n }\n\n return (\n <div\n data-testid={\"dashboard-empty-column\"}\n className={cn(\n // `rounded-xl` and the 2px border match the cards' outline and the drop slot.\n \"flex min-h-[220px] flex-col items-center justify-center gap-sm rounded-xl\",\n \"border-2 border-dashed p-lg transition-colors\",\n stateClasses\n )}\n >\n <span\n className={cn(\n \"flex size-xl items-center justify-center rounded-md\",\n dragging ? \"bg-primary/10\" : \"bg-neutral-dimmed\"\n )}\n >\n {icon}\n </span>\n {body}\n </div>\n );\n};\n"],"names":["IDLE_CLASSES","CAN_DROP_CLASSES","ACTIVE_CLASSES","ColumnEmptyState","canRemove","onRemove","onBrowse","dragging","active","stateClasses","icon","Icon","DashboardCustomizeIcon","AddCircleIcon","body","Text","Button","cn"],"mappings":";;;;AAkBA,MAAMA,eAAe;AACrB,MAAMC,mBAAmB;AACzB,MAAMC,iBAAiB;AAEhB,MAAMC,mBAAmB,CAAC,EAC7BC,SAAS,EACTC,QAAQ,EACRC,QAAQ,EACRC,QAAQ,EACRC,MAAM,EACc;IACpB,IAAIC,eAAeT;IACnB,IAAIQ,QACAC,eAAeP;SACZ,IAAIK,UACPE,eAAeR;IAGnB,IAAIS,OAAO,WAAPA,GACA,oBAACC,MAAIA;QACD,oBAAM,oBAACC,gBAAsBA;QAC7B,OAAO;QACP,MAAM;QACN,OAAO;;IAGf,IAAIL,UACAG,OAAO,WAAPA,GAAO,oBAACC,MAAIA;QAAC,oBAAM,oBAACE,+BAAaA;QAAK,OAAO;QAAa,MAAM;QAAM,OAAO;;IAGjF,IAAIC,OAAO,WAAPA,GACA,wDACI,oBAACC,MAAIA;QAAC,IAAI;QAAO,MAAM;QAAM,WAAW;OACnC,oCACD,oBAAC,aACA,qBACD,oBAAC;QACG,MAAM;QACN,SAAST;QACT,WAAW;OAEV,oBAGRF,aAAa,WAAbA,GACG,oBAACY,QAAMA;QAAC,MAAM;QAAM,SAAS;QAAS,MAAM;QAAiB,SAASX;;IAIlF,IAAIE,UACAO,OAAO,WAAPA,GACI,oBAACC,MAAIA;QAAC,IAAI;QAAO,MAAM;QAAM,WAAW;OACnC;IAKb,OAAO,WAAP,GACI,oBAAC;QACG,eAAa;QACb,WAAWE,GAEP,6EACA,iDACAR;qBAGJ,oBAAC;QACG,WAAWQ,GACP,uDACAV,WAAW,kBAAkB;OAGhCG,OAEJI;AAGb"}
@@ -0,0 +1,6 @@
1
+ import React from "react";
2
+ /**
3
+ * A custom drag preview that follows the cursor. The native HTML5 preview is suppressed
4
+ * (see DashboardWidgetCard), so this chip is the only thing the user sees moving.
5
+ */
6
+ export declare const DashboardDragLayer: () => React.JSX.Element | null;
@@ -0,0 +1,28 @@
1
+ import react from "react";
2
+ import { useDragLayer } from "react-dnd";
3
+ import { Icon, cn } from "@webiny/admin-ui";
4
+ import { ReactComponent } from "@webiny/icons/drag_indicator.svg";
5
+ const DashboardDragLayer = ()=>{
6
+ const { isDragging, item, offset } = useDragLayer((monitor)=>({
7
+ isDragging: monitor.isDragging(),
8
+ item: monitor.getItem(),
9
+ offset: monitor.getClientOffset()
10
+ }));
11
+ if (!isDragging || !item || !offset) return null;
12
+ return /*#__PURE__*/ react.createElement("div", {
13
+ className: "pointer-events-none fixed left-0 top-0 z-[9999]"
14
+ }, /*#__PURE__*/ react.createElement("div", {
15
+ style: {
16
+ transform: `translate(${offset.x + 12}px, ${offset.y + 12}px)`
17
+ },
18
+ className: cn("flex items-center gap-sm whitespace-nowrap rounded-lg border-sm", "border-neutral-dimmed bg-neutral-base px-sm-extra py-sm-plus text-md", "font-semibold text-neutral-primary shadow-lg")
19
+ }, /*#__PURE__*/ react.createElement(Icon, {
20
+ icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
21
+ label: "Dragging",
22
+ size: "sm",
23
+ color: "neutral-light"
24
+ }), item.title));
25
+ };
26
+ export { DashboardDragLayer };
27
+
28
+ //# sourceMappingURL=DashboardDragLayer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dashboard/components/dnd/DashboardDragLayer.js","sources":["../../../../src/Dashboard/components/dnd/DashboardDragLayer.tsx"],"sourcesContent":["import React from \"react\";\nimport { useDragLayer } from \"react-dnd\";\nimport type { XYCoord } from \"react-dnd\";\nimport { Icon } from \"@webiny/admin-ui\";\nimport { cn } from \"@webiny/admin-ui\";\nimport { ReactComponent as DragIndicatorIcon } from \"@webiny/icons/drag_indicator.svg\";\n\nimport type { DashboardWidgetDragItem } from \"./dragItem.js\";\n\ninterface DragLayerState {\n isDragging: boolean;\n item: DashboardWidgetDragItem | null;\n offset: XYCoord | null;\n}\n\n/**\n * A custom drag preview that follows the cursor. The native HTML5 preview is suppressed\n * (see DashboardWidgetCard), so this chip is the only thing the user sees moving.\n */\nexport const DashboardDragLayer = () => {\n const { isDragging, item, offset } = useDragLayer<\n DragLayerState,\n DashboardWidgetDragItem | null\n >(monitor => ({\n isDragging: monitor.isDragging(),\n item: monitor.getItem(),\n offset: monitor.getClientOffset()\n }));\n\n if (!isDragging || !item || !offset) {\n return null;\n }\n\n return (\n <div className={\"pointer-events-none fixed left-0 top-0 z-[9999]\"}>\n <div\n style={{\n transform: `translate(${offset.x + 12}px, ${offset.y + 12}px)`\n }}\n className={cn(\n \"flex items-center gap-sm whitespace-nowrap rounded-lg border-sm\",\n \"border-neutral-dimmed bg-neutral-base px-sm-extra py-sm-plus text-md\",\n \"font-semibold text-neutral-primary shadow-lg\"\n )}\n >\n <Icon\n icon={<DragIndicatorIcon />}\n label={\"Dragging\"}\n size={\"sm\"}\n color={\"neutral-light\"}\n />\n {item.title}\n </div>\n </div>\n );\n};\n"],"names":["DashboardDragLayer","isDragging","item","offset","useDragLayer","monitor","cn","Icon","DragIndicatorIcon"],"mappings":";;;;AAmBO,MAAMA,qBAAqB;IAC9B,MAAM,EAAEC,UAAU,EAAEC,IAAI,EAAEC,MAAM,EAAE,GAAGC,aAGnCC,CAAAA,UAAY;YACV,YAAYA,QAAQ,UAAU;YAC9B,MAAMA,QAAQ,OAAO;YACrB,QAAQA,QAAQ,eAAe;QACnC;IAEA,IAAI,CAACJ,cAAc,CAACC,QAAQ,CAACC,QACzB,OAAO;IAGX,OAAO,WAAP,GACI,oBAAC;QAAI,WAAW;qBACZ,oBAAC;QACG,OAAO;YACH,WAAW,CAAC,UAAU,EAAEA,OAAO,CAAC,GAAG,GAAG,IAAI,EAAEA,OAAO,CAAC,GAAG,GAAG,GAAG,CAAC;QAClE;QACA,WAAWG,GACP,mEACA,wEACA;qBAGJ,oBAACC,MAAIA;QACD,oBAAM,oBAACC,gBAAiBA;QACxB,OAAO;QACP,MAAM;QACN,OAAO;QAEVN,KAAK,KAAK;AAI3B"}
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import type { DashboardLayoutPresenter } from "../../dashboardLayout/presenter/abstractions.js";
3
+ interface DashboardWidgetCardProps {
4
+ name: string;
5
+ title: string;
6
+ isDragging: boolean;
7
+ presenter: DashboardLayoutPresenter.Interface;
8
+ /** Reports the card's DOM node to the column so it can measure drop slots. */
9
+ registerRef: (name: string, node: HTMLElement | null) => void;
10
+ children: React.ReactNode;
11
+ }
12
+ export declare const DashboardWidgetCard: ({ name, title, isDragging, presenter, registerRef, children }: DashboardWidgetCardProps) => React.JSX.Element;
13
+ export {};
@@ -0,0 +1,59 @@
1
+ import react, { useRef } from "react";
2
+ import { DragPreviewImage, useDrag } from "react-dnd";
3
+ import { IconButton, Tooltip, cn } from "@webiny/admin-ui";
4
+ import { ReactComponent } from "@webiny/icons/delete.svg";
5
+ import { DASHBOARD_WIDGET_DND_TYPE } from "./dragItem.js";
6
+ const EMPTY_DRAG_IMAGE = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
7
+ const DashboardWidgetCard = ({ name, title, isDragging, presenter, registerRef, children })=>{
8
+ const cardRef = useRef(null);
9
+ const [, drag, preview] = useDrag({
10
+ type: DASHBOARD_WIDGET_DND_TYPE,
11
+ item: ()=>{
12
+ presenter.beginDrag(name);
13
+ const height = cardRef.current?.getBoundingClientRect().height ?? 0;
14
+ return {
15
+ name,
16
+ title,
17
+ height
18
+ };
19
+ },
20
+ end: ()=>{
21
+ presenter.endDrag();
22
+ }
23
+ });
24
+ return /*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement(DragPreviewImage, {
25
+ connect: preview,
26
+ src: EMPTY_DRAG_IMAGE
27
+ }), /*#__PURE__*/ react.createElement("div", {
28
+ ref: (node)=>{
29
+ cardRef.current = node;
30
+ registerRef(name, node);
31
+ },
32
+ className: cn("group/card relative rounded-xl transition-opacity", isDragging && "opacity-50")
33
+ }, /*#__PURE__*/ react.createElement("div", {
34
+ ref: (node)=>node?.setAttribute("inert", ""),
35
+ className: "select-none"
36
+ }, children), /*#__PURE__*/ react.createElement("div", {
37
+ ref: (node)=>{
38
+ drag(node);
39
+ },
40
+ role: "button",
41
+ "aria-label": `Drag ${title} to move it`,
42
+ "data-testid": `dashboard-card-${name}`,
43
+ className: cn("absolute inset-0 z-10 cursor-grab rounded-xl active:cursor-grabbing", "ring-2 ring-inset ring-primary/30 transition-colors", "hover:bg-primary/5 hover:ring-primary/60")
44
+ }), /*#__PURE__*/ react.createElement("div", {
45
+ className: cn("absolute -right-sm -top-sm z-20 opacity-0 transition-opacity", "group-hover/card:opacity-100 focus-within:opacity-100")
46
+ }, /*#__PURE__*/ react.createElement(Tooltip, {
47
+ content: "Remove from dashboard",
48
+ trigger: /*#__PURE__*/ react.createElement(IconButton, {
49
+ variant: "tertiary",
50
+ size: "sm",
51
+ icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
52
+ "aria-label": `Remove ${title} from the dashboard`,
53
+ onClick: ()=>presenter.removeWidget(name)
54
+ })
55
+ }))));
56
+ };
57
+ export { DashboardWidgetCard };
58
+
59
+ //# sourceMappingURL=DashboardWidgetCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dashboard/components/dnd/DashboardWidgetCard.js","sources":["../../../../src/Dashboard/components/dnd/DashboardWidgetCard.tsx"],"sourcesContent":["import React from \"react\";\nimport { useRef } from \"react\";\nimport { useDrag } from \"react-dnd\";\nimport { DragPreviewImage } from \"react-dnd\";\nimport { IconButton } from \"@webiny/admin-ui\";\nimport { Tooltip } from \"@webiny/admin-ui\";\nimport { cn } from \"@webiny/admin-ui\";\nimport { ReactComponent as RemoveIcon } from \"@webiny/icons/delete.svg\";\nimport type { DashboardLayoutPresenter } from \"../../dashboardLayout/presenter/abstractions.js\";\nimport { DASHBOARD_WIDGET_DND_TYPE } from \"./dragItem.js\";\nimport type { DashboardWidgetDragItem } from \"./dragItem.js\";\n\n// Transparent 1px gif. Hides the browser's drag preview so DashboardDragLayer's card is the only one.\nconst EMPTY_DRAG_IMAGE =\n \"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\";\n\ninterface DashboardWidgetCardProps {\n name: string;\n title: string;\n isDragging: boolean;\n presenter: DashboardLayoutPresenter.Interface;\n /** Reports the card's DOM node to the column so it can measure drop slots. */\n registerRef: (name: string, node: HTMLElement | null) => void;\n children: React.ReactNode;\n}\n\n/*\n * A widget in Customize mode. The whole card is the drag target: an overlay covers the widget, so\n * its own links and buttons can't catch the pointer, and a remove button sits in the corner.\n */\nexport const DashboardWidgetCard = ({\n name,\n title,\n isDragging,\n presenter,\n registerRef,\n children\n}: DashboardWidgetCardProps) => {\n const cardRef = useRef<HTMLElement | null>(null);\n\n const [, drag, preview] = useDrag({\n type: DASHBOARD_WIDGET_DND_TYPE,\n item: () => {\n presenter.beginDrag(name);\n const height = cardRef.current?.getBoundingClientRect().height ?? 0;\n return { name, title, height } satisfies DashboardWidgetDragItem;\n },\n end: () => {\n presenter.endDrag();\n }\n });\n\n return (\n <>\n <DragPreviewImage connect={preview} src={EMPTY_DRAG_IMAGE} />\n <div\n ref={node => {\n cardRef.current = node;\n registerRef(name, node);\n }}\n className={cn(\n // A named group: a plain `group` here would also trigger `group-hover:` styles inside the\n // widget (e.g. every Tabs trigger at once), since those match any `.group` ancestor.\n \"group/card relative rounded-xl transition-opacity\",\n isDragging && \"opacity-50\"\n )}\n >\n {/*\n `inert` keeps the widget out of the tab order and away from clicks. It's set\n through a ref because React 18's types don't know the attribute yet.\n */}\n <div ref={node => node?.setAttribute(\"inert\", \"\")} className={\"select-none\"}>\n {children}\n </div>\n <div\n ref={node => {\n drag(node);\n }}\n role={\"button\"}\n aria-label={`Drag ${title} to move it`}\n data-testid={`dashboard-card-${name}`}\n className={cn(\n // `rounded-xl` matches the DS Widget, so the outline follows its corners.\n \"absolute inset-0 z-10 cursor-grab rounded-xl active:cursor-grabbing\",\n \"ring-2 ring-inset ring-primary/30 transition-colors\",\n \"hover:bg-primary/5 hover:ring-primary/60\"\n )}\n />\n {/*\n On the corner, half outside the card, so it never covers the widget's own\n actions. Only the card under the pointer (or with focus) shows it, so six cards\n don't mean six buttons.\n */}\n <div\n className={cn(\n \"absolute -right-sm -top-sm z-20 opacity-0 transition-opacity\",\n \"group-hover/card:opacity-100 focus-within:opacity-100\"\n )}\n >\n <Tooltip\n content={\"Remove from dashboard\"}\n trigger={\n <IconButton\n variant={\"tertiary\"}\n size={\"sm\"}\n icon={<RemoveIcon />}\n aria-label={`Remove ${title} from the dashboard`}\n onClick={() => presenter.removeWidget(name)}\n />\n }\n />\n </div>\n </div>\n </>\n );\n};\n"],"names":["EMPTY_DRAG_IMAGE","DashboardWidgetCard","name","title","isDragging","presenter","registerRef","children","cardRef","useRef","drag","preview","useDrag","DASHBOARD_WIDGET_DND_TYPE","height","DragPreviewImage","node","cn","Tooltip","IconButton","RemoveIcon"],"mappings":";;;;;AAaA,MAAMA,mBACF;AAgBG,MAAMC,sBAAsB,CAAC,EAChCC,IAAI,EACJC,KAAK,EACLC,UAAU,EACVC,SAAS,EACTC,WAAW,EACXC,QAAQ,EACe;IACvB,MAAMC,UAAUC,OAA2B;IAE3C,MAAM,GAAGC,MAAMC,QAAQ,GAAGC,QAAQ;QAC9B,MAAMC;QACN,MAAM;YACFR,UAAU,SAAS,CAACH;YACpB,MAAMY,SAASN,QAAQ,OAAO,EAAE,wBAAwB,UAAU;YAClE,OAAO;gBAAEN;gBAAMC;gBAAOW;YAAO;QACjC;QACA,KAAK;YACDT,UAAU,OAAO;QACrB;IACJ;IAEA,OAAO,WAAP,GACI,wDACI,oBAACU,kBAAgBA;QAAC,SAASJ;QAAS,KAAKX;sBACzC,oBAAC;QACG,KAAKgB,CAAAA;YACDR,QAAQ,OAAO,GAAGQ;YAClBV,YAAYJ,MAAMc;QACtB;QACA,WAAWC,GAGP,qDACAb,cAAc;qBAOlB,oBAAC;QAAI,KAAKY,CAAAA,OAAQA,MAAM,aAAa,SAAS;QAAK,WAAW;OACzDT,WAAAA,WAAAA,GAEL,oBAAC;QACG,KAAKS,CAAAA;YACDN,KAAKM;QACT;QACA,MAAM;QACN,cAAY,CAAC,KAAK,EAAEb,MAAM,WAAW,CAAC;QACtC,eAAa,CAAC,eAAe,EAAED,MAAM;QACrC,WAAWe,GAEP,uEACA,uDACA;sBAQR,oBAAC;QACG,WAAWA,GACP,gEACA;qBAGJ,oBAACC,SAAOA;QACJ,SAAS;QACT,uBACI,oBAACC,YAAUA;YACP,SAAS;YACT,MAAM;YACN,oBAAM,oBAACC,gBAAUA;YACjB,cAAY,CAAC,OAAO,EAAEjB,MAAM,mBAAmB,CAAC;YAChD,SAAS,IAAME,UAAU,YAAY,CAACH;;;AAQtE"}
@@ -0,0 +1,19 @@
1
+ import React from "react";
2
+ import type { DashboardDropTarget } from "../../dashboardLayout/presenter/abstractions.js";
3
+ import type { DashboardLayoutPresenter } from "../../dashboardLayout/presenter/abstractions.js";
4
+ interface DashboardWidgetColumnProps {
5
+ columnIndex: number;
6
+ /** Ordered widget names for this column (from the presenter's view model). */
7
+ names: string[];
8
+ draggingName: string | null;
9
+ dropTarget: DashboardDropTarget | null;
10
+ canRemoveColumn: boolean;
11
+ elements: Map<string, React.ReactElement>;
12
+ titles: Map<string, {
13
+ title: string;
14
+ }>;
15
+ presenter: DashboardLayoutPresenter.Interface;
16
+ onBrowseWidgets: () => void;
17
+ }
18
+ export declare const DashboardWidgetColumn: ({ columnIndex, names, draggingName, dropTarget, canRemoveColumn, elements, titles, presenter, onBrowseWidgets }: DashboardWidgetColumnProps) => React.JSX.Element;
19
+ export {};
@@ -0,0 +1,72 @@
1
+ import react, { useRef } from "react";
2
+ import { useDrop } from "react-dnd";
3
+ import { DASHBOARD_WIDGET_DND_TYPE } from "./dragItem.js";
4
+ import { DashboardWidgetCard } from "./DashboardWidgetCard.js";
5
+ import { WidgetDropIndicator } from "./WidgetDropIndicator.js";
6
+ import { ColumnEmptyState } from "./ColumnEmptyState.js";
7
+ const DashboardWidgetColumn = ({ columnIndex, names, draggingName, dropTarget, canRemoveColumn, elements, titles, presenter, onBrowseWidgets })=>{
8
+ const cardRefs = useRef(new Map());
9
+ const registerRef = (name, node)=>{
10
+ if (node) cardRefs.current.set(name, node);
11
+ else cardRefs.current.delete(name);
12
+ };
13
+ const [{ item }, drop] = useDrop({
14
+ accept: DASHBOARD_WIDGET_DND_TYPE,
15
+ collect: (monitor)=>({
16
+ item: monitor.getItem()
17
+ }),
18
+ hover: (_item, monitor)=>{
19
+ const pointer = monitor.getClientOffset();
20
+ if (!pointer) return;
21
+ let beforeName = null;
22
+ for (const name of names){
23
+ const node = cardRefs.current.get(name);
24
+ if (!node) continue;
25
+ const rect = node.getBoundingClientRect();
26
+ if (pointer.y < rect.top + rect.height / 2) {
27
+ beforeName = name;
28
+ break;
29
+ }
30
+ }
31
+ presenter.hoverSlot(columnIndex, beforeName);
32
+ },
33
+ drop: ()=>{
34
+ presenter.drop();
35
+ }
36
+ });
37
+ const isDragging = null !== draggingName;
38
+ const showIndicatorBefore = (name)=>isDragging && null !== dropTarget && dropTarget.column === columnIndex && dropTarget.beforeName === name;
39
+ let indicator = null;
40
+ if (item) indicator = /*#__PURE__*/ react.createElement(WidgetDropIndicator, {
41
+ title: item.title,
42
+ height: item.height
43
+ });
44
+ return /*#__PURE__*/ react.createElement("div", {
45
+ ref: (node)=>{
46
+ drop(node);
47
+ },
48
+ className: "relative flex min-h-[120px] flex-1 flex-col gap-lg",
49
+ "data-testid": `dashboard-column-${columnIndex}`
50
+ }, names.map((name)=>{
51
+ const element = elements.get(name);
52
+ if (!element) return null;
53
+ return /*#__PURE__*/ react.createElement(react.Fragment, {
54
+ key: name
55
+ }, showIndicatorBefore(name) ? indicator : null, /*#__PURE__*/ react.createElement(DashboardWidgetCard, {
56
+ name: name,
57
+ title: titles.get(name)?.title ?? name,
58
+ isDragging: name === draggingName,
59
+ presenter: presenter,
60
+ registerRef: registerRef
61
+ }, element));
62
+ }), names.length > 0 && showIndicatorBefore(null) && indicator, 0 === names.length && /*#__PURE__*/ react.createElement(ColumnEmptyState, {
63
+ canRemove: canRemoveColumn,
64
+ onRemove: ()=>presenter.removeColumn(columnIndex),
65
+ onBrowse: onBrowseWidgets,
66
+ dragging: isDragging,
67
+ active: showIndicatorBefore(null)
68
+ }));
69
+ };
70
+ export { DashboardWidgetColumn };
71
+
72
+ //# sourceMappingURL=DashboardWidgetColumn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dashboard/components/dnd/DashboardWidgetColumn.js","sources":["../../../../src/Dashboard/components/dnd/DashboardWidgetColumn.tsx"],"sourcesContent":["import React from \"react\";\nimport { useRef } from \"react\";\nimport { useDrop } from \"react-dnd\";\nimport { DASHBOARD_WIDGET_DND_TYPE } from \"./dragItem.js\";\nimport type { DashboardWidgetDragItem } from \"./dragItem.js\";\nimport { DashboardWidgetCard } from \"./DashboardWidgetCard.js\";\nimport { WidgetDropIndicator } from \"./WidgetDropIndicator.js\";\nimport { ColumnEmptyState } from \"./ColumnEmptyState.js\";\nimport type { DashboardDropTarget } from \"../../dashboardLayout/presenter/abstractions.js\";\nimport type { DashboardLayoutPresenter } from \"../../dashboardLayout/presenter/abstractions.js\";\n\ninterface DashboardWidgetColumnProps {\n columnIndex: number;\n /** Ordered widget names for this column (from the presenter's view model). */\n names: string[];\n draggingName: string | null;\n dropTarget: DashboardDropTarget | null;\n canRemoveColumn: boolean;\n elements: Map<string, React.ReactElement>;\n titles: Map<string, { title: string }>;\n presenter: DashboardLayoutPresenter.Interface;\n onBrowseWidgets: () => void;\n}\n\nexport const DashboardWidgetColumn = ({\n columnIndex,\n names,\n draggingName,\n dropTarget,\n canRemoveColumn,\n elements,\n titles,\n presenter,\n onBrowseWidgets\n}: DashboardWidgetColumnProps) => {\n // The whole column is one drop target. On hover we measure each card's midpoint to decide\n // which slot the pointer is nearest, so gaps (and the indicator itself) never miss a drop.\n const cardRefs = useRef(new Map<string, HTMLElement>());\n\n const registerRef = (name: string, node: HTMLElement | null) => {\n if (node) {\n cardRefs.current.set(name, node);\n } else {\n cardRefs.current.delete(name);\n }\n };\n\n const [{ item }, drop] = useDrop({\n accept: DASHBOARD_WIDGET_DND_TYPE,\n collect: monitor => ({ item: monitor.getItem<DashboardWidgetDragItem | null>() }),\n hover: (_item, monitor) => {\n const pointer = monitor.getClientOffset();\n if (!pointer) {\n return;\n }\n let beforeName: string | null = null;\n for (const name of names) {\n const node = cardRefs.current.get(name);\n if (!node) {\n continue;\n }\n const rect = node.getBoundingClientRect();\n if (pointer.y < rect.top + rect.height / 2) {\n beforeName = name;\n break;\n }\n }\n presenter.hoverSlot(columnIndex, beforeName);\n },\n drop: () => {\n presenter.drop();\n }\n });\n\n const isDragging = draggingName !== null;\n const showIndicatorBefore = (name: string | null) =>\n isDragging &&\n dropTarget !== null &&\n dropTarget.column === columnIndex &&\n dropTarget.beforeName === name;\n\n // The slot takes the dragged card's size and names it, so it shows exactly what lands there.\n let indicator = null;\n if (item) {\n indicator = <WidgetDropIndicator title={item.title} height={item.height} />;\n }\n\n return (\n <div\n ref={node => {\n drop(node);\n }}\n className={\"relative flex min-h-[120px] flex-1 flex-col gap-lg\"}\n data-testid={`dashboard-column-${columnIndex}`}\n >\n {names.map(name => {\n const element = elements.get(name);\n if (!element) {\n return null;\n }\n return (\n <React.Fragment key={name}>\n {showIndicatorBefore(name) ? indicator : null}\n <DashboardWidgetCard\n name={name}\n title={titles.get(name)?.title ?? name}\n isDragging={name === draggingName}\n presenter={presenter}\n registerRef={registerRef}\n >\n {element}\n </DashboardWidgetCard>\n </React.Fragment>\n );\n })}\n {names.length > 0 && showIndicatorBefore(null) && indicator}\n {/* An empty column stays put and becomes the target itself, like the editor's empty slots. */}\n {names.length === 0 && (\n <ColumnEmptyState\n canRemove={canRemoveColumn}\n onRemove={() => presenter.removeColumn(columnIndex)}\n onBrowse={onBrowseWidgets}\n dragging={isDragging}\n active={showIndicatorBefore(null)}\n />\n )}\n </div>\n );\n};\n"],"names":["DashboardWidgetColumn","columnIndex","names","draggingName","dropTarget","canRemoveColumn","elements","titles","presenter","onBrowseWidgets","cardRefs","useRef","Map","registerRef","name","node","item","drop","useDrop","DASHBOARD_WIDGET_DND_TYPE","monitor","_item","pointer","beforeName","rect","isDragging","showIndicatorBefore","indicator","WidgetDropIndicator","element","React","DashboardWidgetCard","ColumnEmptyState"],"mappings":";;;;;;AAwBO,MAAMA,wBAAwB,CAAC,EAClCC,WAAW,EACXC,KAAK,EACLC,YAAY,EACZC,UAAU,EACVC,eAAe,EACfC,QAAQ,EACRC,MAAM,EACNC,SAAS,EACTC,eAAe,EACU;IAGzB,MAAMC,WAAWC,OAAO,IAAIC;IAE5B,MAAMC,cAAc,CAACC,MAAcC;QAC/B,IAAIA,MACAL,SAAS,OAAO,CAAC,GAAG,CAACI,MAAMC;aAE3BL,SAAS,OAAO,CAAC,MAAM,CAACI;IAEhC;IAEA,MAAM,CAAC,EAAEE,IAAI,EAAE,EAAEC,KAAK,GAAGC,QAAQ;QAC7B,QAAQC;QACR,SAASC,CAAAA,UAAY;gBAAE,MAAMA,QAAQ,OAAO;YAAmC;QAC/E,OAAO,CAACC,OAAOD;YACX,MAAME,UAAUF,QAAQ,eAAe;YACvC,IAAI,CAACE,SACD;YAEJ,IAAIC,aAA4B;YAChC,KAAK,MAAMT,QAAQZ,MAAO;gBACtB,MAAMa,OAAOL,SAAS,OAAO,CAAC,GAAG,CAACI;gBAClC,IAAI,CAACC,MACD;gBAEJ,MAAMS,OAAOT,KAAK,qBAAqB;gBACvC,IAAIO,QAAQ,CAAC,GAAGE,KAAK,GAAG,GAAGA,KAAK,MAAM,GAAG,GAAG;oBACxCD,aAAaT;oBACb;gBACJ;YACJ;YACAN,UAAU,SAAS,CAACP,aAAasB;QACrC;QACA,MAAM;YACFf,UAAU,IAAI;QAClB;IACJ;IAEA,MAAMiB,aAAatB,AAAiB,SAAjBA;IACnB,MAAMuB,sBAAsB,CAACZ,OACzBW,cACArB,AAAe,SAAfA,cACAA,WAAW,MAAM,KAAKH,eACtBG,WAAW,UAAU,KAAKU;IAG9B,IAAIa,YAAY;IAChB,IAAIX,MACAW,YAAY,WAAZA,GAAY,oBAACC,qBAAmBA;QAAC,OAAOZ,KAAK,KAAK;QAAE,QAAQA,KAAK,MAAM;;IAG3E,OAAO,WAAP,GACI,oBAAC;QACG,KAAKD,CAAAA;YACDE,KAAKF;QACT;QACA,WAAW;QACX,eAAa,CAAC,iBAAiB,EAAEd,aAAa;OAE7CC,MAAM,GAAG,CAACY,CAAAA;QACP,MAAMe,UAAUvB,SAAS,GAAG,CAACQ;QAC7B,IAAI,CAACe,SACD,OAAO;QAEX,OAAO,WAAP,GACI,oBAACC,MAAAA,QAAc;YAAC,KAAKhB;WAChBY,oBAAoBZ,QAAQa,YAAY,oBACzC,oBAACI,qBAAmBA;YAChB,MAAMjB;YACN,OAAOP,OAAO,GAAG,CAACO,OAAO,SAASA;YAClC,YAAYA,SAASX;YACrB,WAAWK;YACX,aAAaK;WAEZgB;IAIjB,IACC3B,MAAM,MAAM,GAAG,KAAKwB,oBAAoB,SAASC,WAEjDzB,AAAiB,MAAjBA,MAAM,MAAM,IAAU,WAAL,GACd,oBAAC8B,kBAAgBA;QACb,WAAW3B;QACX,UAAU,IAAMG,UAAU,YAAY,CAACP;QACvC,UAAUQ;QACV,UAAUgB;QACV,QAAQC,oBAAoB;;AAKhD"}
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ interface WidgetDropIndicatorProps {
3
+ title: string;
4
+ height: number;
5
+ }
6
+ /**
7
+ * The slot a dragged widget would drop into: an empty card the size of the dragged one, titled
8
+ * like it. It grows from nothing when it appears, so the cards below slide instead of jump.
9
+ */
10
+ export declare const WidgetDropIndicator: ({ title, height }: WidgetDropIndicatorProps) => React.JSX.Element;
11
+ export {};
@@ -0,0 +1,29 @@
1
+ import react, { useEffect, useState } from "react";
2
+ import { Text, cn } from "@webiny/admin-ui";
3
+ const FALLBACK_HEIGHT = 80;
4
+ const WidgetDropIndicator = ({ title, height })=>{
5
+ const [grown, setGrown] = useState(false);
6
+ useEffect(()=>{
7
+ const frame = requestAnimationFrame(()=>setGrown(true));
8
+ return ()=>cancelAnimationFrame(frame);
9
+ }, []);
10
+ let targetHeight = FALLBACK_HEIGHT;
11
+ if (height > 0) targetHeight = height;
12
+ return /*#__PURE__*/ react.createElement("div", {
13
+ "aria-hidden": true,
14
+ "data-testid": "dashboard-widget-drop-indicator",
15
+ className: cn("pointer-events-none w-full flex-none overflow-hidden", "rounded-xl border-2 border-dashed", "motion-safe:transition-[height] motion-safe:duration-200 motion-safe:ease-out"),
16
+ style: {
17
+ height: grown ? targetHeight : 0,
18
+ borderColor: "var(--color-primary-400)",
19
+ backgroundColor: "color-mix(in srgb, var(--color-primary-500) 6%, transparent)"
20
+ }
21
+ }, /*#__PURE__*/ react.createElement(Text, {
22
+ as: "div",
23
+ size: "md",
24
+ className: "px-lg pt-md-plus font-semibold text-accent-primary"
25
+ }, title));
26
+ };
27
+ export { WidgetDropIndicator };
28
+
29
+ //# sourceMappingURL=WidgetDropIndicator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dashboard/components/dnd/WidgetDropIndicator.js","sources":["../../../../src/Dashboard/components/dnd/WidgetDropIndicator.tsx"],"sourcesContent":["import React from \"react\";\nimport { useEffect } from \"react\";\nimport { useState } from \"react\";\nimport { Text } from \"@webiny/admin-ui\";\nimport { cn } from \"@webiny/admin-ui\";\n\n// Used when the dragged card couldn't be measured.\nconst FALLBACK_HEIGHT = 80;\n\ninterface WidgetDropIndicatorProps {\n // The dragged widget's title, shown in the slot.\n title: string;\n // The dragged card's height, so the slot reserves exactly the space the widget will take.\n height: number;\n}\n\n/**\n * The slot a dragged widget would drop into: an empty card the size of the dragged one, titled\n * like it. It grows from nothing when it appears, so the cards below slide instead of jump.\n */\nexport const WidgetDropIndicator = ({ title, height }: WidgetDropIndicatorProps) => {\n const [grown, setGrown] = useState(false);\n\n useEffect(() => {\n // One frame at zero height first, so the browser has something to transition from.\n const frame = requestAnimationFrame(() => setGrown(true));\n return () => cancelAnimationFrame(frame);\n }, []);\n\n let targetHeight = FALLBACK_HEIGHT;\n if (height > 0) {\n targetHeight = height;\n }\n\n return (\n <div\n aria-hidden\n data-testid={\"dashboard-widget-drop-indicator\"}\n className={cn(\n \"pointer-events-none w-full flex-none overflow-hidden\",\n // `rounded-xl` and the 2px border match the cards' outline in Customize mode.\n \"rounded-xl border-2 border-dashed\",\n \"motion-safe:transition-[height] motion-safe:duration-200 motion-safe:ease-out\"\n )}\n style={{\n height: grown ? targetHeight : 0,\n borderColor: \"var(--color-primary-400)\",\n backgroundColor: \"color-mix(in srgb, var(--color-primary-500) 6%, transparent)\"\n }}\n >\n {/* Where the card's own title sits, and out of the way of the drag chip under the pointer. */}\n <Text\n as={\"div\"}\n size={\"md\"}\n className={\"px-lg pt-md-plus font-semibold text-accent-primary\"}\n >\n {title}\n </Text>\n </div>\n );\n};\n"],"names":["FALLBACK_HEIGHT","WidgetDropIndicator","title","height","grown","setGrown","useState","useEffect","frame","requestAnimationFrame","cancelAnimationFrame","targetHeight","cn","Text"],"mappings":";;AAOA,MAAMA,kBAAkB;AAajB,MAAMC,sBAAsB,CAAC,EAAEC,KAAK,EAAEC,MAAM,EAA4B;IAC3E,MAAM,CAACC,OAAOC,SAAS,GAAGC,SAAS;IAEnCC,UAAU;QAEN,MAAMC,QAAQC,sBAAsB,IAAMJ,SAAS;QACnD,OAAO,IAAMK,qBAAqBF;IACtC,GAAG,EAAE;IAEL,IAAIG,eAAeX;IACnB,IAAIG,SAAS,GACTQ,eAAeR;IAGnB,OAAO,WAAP,GACI,oBAAC;QACG;QACA,eAAa;QACb,WAAWS,GACP,wDAEA,qCACA;QAEJ,OAAO;YACH,QAAQR,QAAQO,eAAe;YAC/B,aAAa;YACb,iBAAiB;QACrB;qBAGA,oBAACE,MAAIA;QACD,IAAI;QACJ,MAAM;QACN,WAAW;OAEVX;AAIjB"}
@@ -0,0 +1,6 @@
1
+ import React from "react";
2
+ interface WidgetSlotProps {
3
+ host: HTMLDivElement;
4
+ }
5
+ export declare const WidgetSlot: ({ host }: WidgetSlotProps) => React.JSX.Element;
6
+ export {};
@@ -0,0 +1,9 @@
1
+ import react from "react";
2
+ const WidgetSlot = ({ host })=>/*#__PURE__*/ react.createElement("div", {
3
+ ref: (node)=>{
4
+ if (node && host.parentNode !== node) node.appendChild(host);
5
+ }
6
+ });
7
+ export { WidgetSlot };
8
+
9
+ //# sourceMappingURL=WidgetSlot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dashboard/components/dnd/WidgetSlot.js","sources":["../../../../src/Dashboard/components/dnd/WidgetSlot.tsx"],"sourcesContent":["import React from \"react\";\n\ninterface WidgetSlotProps {\n // The widget's container from `useWidgetHosts`.\n host: HTMLDivElement;\n}\n\n// Marks where a widget sits and moves the widget's container here. See `useWidgetHosts`.\nexport const WidgetSlot = ({ host }: WidgetSlotProps) => {\n return (\n <div\n ref={node => {\n if (node && host.parentNode !== node) {\n node.appendChild(host);\n }\n }}\n />\n );\n};\n"],"names":["WidgetSlot","host","node"],"mappings":";AAQO,MAAMA,aAAa,CAAC,EAAEC,IAAI,EAAmB,GACzC,WAAP,GACI,oBAAC;QACG,KAAKC,CAAAA;YACD,IAAIA,QAAQD,KAAK,UAAU,KAAKC,MAC5BA,KAAK,WAAW,CAACD;QAEzB"}
@@ -0,0 +1,6 @@
1
+ export declare const DASHBOARD_WIDGET_DND_TYPE = "dashboard-widget";
2
+ export interface DashboardWidgetDragItem {
3
+ name: string;
4
+ title: string;
5
+ height: number;
6
+ }
@@ -0,0 +1,4 @@
1
+ const DASHBOARD_WIDGET_DND_TYPE = "dashboard-widget";
2
+ export { DASHBOARD_WIDGET_DND_TYPE };
3
+
4
+ //# sourceMappingURL=dragItem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dashboard/components/dnd/dragItem.js","sources":["../../../../src/Dashboard/components/dnd/dragItem.ts"],"sourcesContent":["export const DASHBOARD_WIDGET_DND_TYPE = \"dashboard-widget\";\n\n// What a dragged widget carries, so any column can size and label the slot it would drop into.\nexport interface DashboardWidgetDragItem {\n name: string;\n title: string;\n // The card's height when the drag started, in pixels.\n height: number;\n}\n"],"names":["DASHBOARD_WIDGET_DND_TYPE"],"mappings":"AAAO,MAAMA,4BAA4B"}
@@ -0,0 +1 @@
1
+ export declare const useWidgetHosts: () => (name: string) => HTMLDivElement;
@@ -0,0 +1,16 @@
1
+ import { useCallback, useRef } from "react";
2
+ const useWidgetHosts = ()=>{
3
+ const hosts = useRef(new Map());
4
+ return useCallback((name)=>{
5
+ let host = hosts.current.get(name);
6
+ if (!host) {
7
+ host = document.createElement("div");
8
+ host.dataset.widgetHost = name;
9
+ hosts.current.set(name, host);
10
+ }
11
+ return host;
12
+ }, []);
13
+ };
14
+ export { useWidgetHosts };
15
+
16
+ //# sourceMappingURL=useWidgetHosts.js.map