@squiz/resource-browser 1.69.1 → 2.1.8-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/CHANGELOG.md +88 -35
  2. package/LICENSE.md +15 -0
  3. package/README.md +9 -0
  4. package/jest.config.ts +22 -21
  5. package/lib/Hooks/useSelectedState.d.ts +15 -0
  6. package/lib/Hooks/useSelectedState.js +16 -0
  7. package/lib/Hooks/useSources.d.ts +5 -4
  8. package/lib/Hooks/useSources.js +25 -1
  9. package/lib/MainContainer/MainContainer.d.ts +17 -0
  10. package/lib/MainContainer/MainContainer.js +61 -0
  11. package/lib/Plugin/Plugin.d.ts +13 -0
  12. package/lib/Plugin/Plugin.js +17 -0
  13. package/lib/ResourceBrowserContext/ResourceBrowserContext.d.ts +2 -3
  14. package/lib/ResourceBrowserContext/ResourceBrowserContext.js +4 -17
  15. package/lib/ResourceBrowserInput/ResourceBrowserInput.d.ts +24 -0
  16. package/lib/ResourceBrowserInput/ResourceBrowserInput.js +16 -0
  17. package/lib/ResourcePicker/ResourcePicker.d.ts +6 -4
  18. package/lib/ResourcePicker/ResourcePicker.js +14 -8
  19. package/lib/ResourcePicker/States/Selected.d.ts +10 -4
  20. package/lib/ResourcePicker/States/Selected.js +11 -32
  21. package/lib/SourceDropdown/SourceDropdown.d.ts +5 -11
  22. package/lib/SourceDropdown/SourceDropdown.js +20 -99
  23. package/lib/SourceList/SourceList.d.ts +5 -16
  24. package/lib/SourceList/SourceList.js +14 -75
  25. package/lib/index.css +42 -202
  26. package/lib/index.d.ts +7 -7
  27. package/lib/index.js +69 -13
  28. package/lib/types.d.ts +41 -59
  29. package/package.json +82 -80
  30. package/src/Hooks/useSelectedState.spec.ts +46 -0
  31. package/src/Hooks/useSelectedState.ts +22 -0
  32. package/src/Hooks/useSources.spec.ts +30 -12
  33. package/src/Hooks/useSources.ts +33 -4
  34. package/src/Icons/CircledLoopIcon.tsx +8 -8
  35. package/src/MainContainer/MainContainer.spec.tsx +203 -0
  36. package/src/MainContainer/MainContainer.stories.tsx +62 -0
  37. package/src/MainContainer/MainContainer.tsx +101 -0
  38. package/src/Plugin/Plugin.spec.tsx +46 -0
  39. package/src/Plugin/Plugin.tsx +20 -0
  40. package/src/ResourceBrowserContext/ResourceBrowserContext.spec.tsx +65 -106
  41. package/src/ResourceBrowserContext/ResourceBrowserContext.tsx +24 -39
  42. package/src/ResourceBrowserInput/ResourceBrowserInput.spec.tsx +192 -0
  43. package/src/ResourceBrowserInput/ResourceBrowserInput.tsx +81 -0
  44. package/src/ResourcePicker/ResourcePicker.spec.tsx +159 -116
  45. package/src/ResourcePicker/ResourcePicker.stories.tsx +28 -24
  46. package/src/ResourcePicker/ResourcePicker.tsx +79 -59
  47. package/src/ResourcePicker/States/Error.tsx +8 -8
  48. package/src/ResourcePicker/States/Loading.tsx +3 -3
  49. package/src/ResourcePicker/States/Selected.tsx +66 -73
  50. package/src/ResourcePicker/mock-image-resource.json +25 -47
  51. package/src/ResourcePicker/mock-resource.json +11 -13
  52. package/src/ResourcePicker/resource-picker.scss +13 -13
  53. package/src/SourceDropdown/SourceDropdown.spec.tsx +65 -391
  54. package/src/SourceDropdown/SourceDropdown.stories.tsx +21 -24
  55. package/src/SourceDropdown/SourceDropdown.tsx +80 -258
  56. package/src/SourceList/SourceList.spec.tsx +37 -430
  57. package/src/SourceList/SourceList.stories.tsx +17 -37
  58. package/src/SourceList/SourceList.tsx +28 -155
  59. package/src/__mocks__/MockModels.ts +56 -25
  60. package/src/__mocks__/PluginExample.tsx +98 -0
  61. package/src/__mocks__/StorybookHelpers.tsx +141 -0
  62. package/src/__mocks__/renderWithContext.tsx +14 -18
  63. package/src/__mocks__/sample-sources.json +32 -0
  64. package/src/index.scss +18 -8
  65. package/src/index.spec.tsx +277 -99
  66. package/src/index.stories.tsx +65 -39
  67. package/src/index.tsx +119 -57
  68. package/src/types.ts +54 -63
  69. package/tailwind.config.cjs +92 -92
  70. package/vite.config.js +12 -12
  71. package/lib/Hooks/useCategorisedSources.d.ts +0 -14
  72. package/lib/Hooks/useCategorisedSources.js +0 -38
  73. package/lib/Hooks/useChildResources.d.ts +0 -16
  74. package/lib/Hooks/useChildResources.js +0 -13
  75. package/lib/Hooks/usePreselectedResourcePath.d.ts +0 -20
  76. package/lib/Hooks/usePreselectedResourcePath.js +0 -31
  77. package/lib/Hooks/useRecentLocations.d.ts +0 -5
  78. package/lib/Hooks/useRecentLocations.js +0 -38
  79. package/lib/Hooks/useRecentResourcesPaths.d.ts +0 -20
  80. package/lib/Hooks/useRecentResourcesPaths.js +0 -30
  81. package/lib/Hooks/useResource.d.ts +0 -28
  82. package/lib/Hooks/useResource.js +0 -23
  83. package/lib/Hooks/useResourcePath.d.ts +0 -16
  84. package/lib/Hooks/useResourcePath.js +0 -64
  85. package/lib/Icons/HistoryIcon.d.ts +0 -4
  86. package/lib/Icons/HistoryIcon.js +0 -13
  87. package/lib/PreviewPanel/PreviewPanel.d.ts +0 -5
  88. package/lib/PreviewPanel/PreviewPanel.js +0 -8
  89. package/lib/PreviewPanel/details/MatrixResource.d.ts +0 -7
  90. package/lib/PreviewPanel/details/MatrixResource.js +0 -35
  91. package/lib/ResourceBreadcrumb/ResourceBreadcrumb.d.ts +0 -9
  92. package/lib/ResourceBreadcrumb/ResourceBreadcrumb.js +0 -54
  93. package/lib/ResourceList/ResourceList.d.ts +0 -18
  94. package/lib/ResourceList/ResourceList.js +0 -49
  95. package/lib/ResourcePickerContainer/ResourcePickerContainer.d.ts +0 -17
  96. package/lib/ResourcePickerContainer/ResourcePickerContainer.js +0 -166
  97. package/lib/StatusIndicator/StatusIndicator.d.ts +0 -8
  98. package/lib/StatusIndicator/StatusIndicator.js +0 -27
  99. package/lib/utils/findBestMatchLineage.d.ts +0 -2
  100. package/lib/utils/findBestMatchLineage.js +0 -28
  101. package/lib/utils/uuid.d.ts +0 -1
  102. package/lib/utils/uuid.js +0 -6
  103. package/src/Hooks/useCategorisedSources.spec.ts +0 -39
  104. package/src/Hooks/useCategorisedSources.ts +0 -46
  105. package/src/Hooks/useChildResources.spec.ts +0 -29
  106. package/src/Hooks/useChildResources.ts +0 -21
  107. package/src/Hooks/usePreselectedResourcePath.ts +0 -54
  108. package/src/Hooks/useRecentLocations.spec.ts +0 -81
  109. package/src/Hooks/useRecentLocations.ts +0 -44
  110. package/src/Hooks/useRecentResourcesPaths.ts +0 -54
  111. package/src/Hooks/useResource.spec.ts +0 -61
  112. package/src/Hooks/useResource.ts +0 -38
  113. package/src/Hooks/useResourcePath.spec.ts +0 -120
  114. package/src/Hooks/useResourcePath.ts +0 -76
  115. package/src/Icons/HistoryIcon.tsx +0 -17
  116. package/src/PreviewPanel/PreviewPanel.spec.tsx +0 -198
  117. package/src/PreviewPanel/PreviewPanel.stories.tsx +0 -76
  118. package/src/PreviewPanel/PreviewPanel.tsx +0 -6
  119. package/src/PreviewPanel/details/MatrixResource.tsx +0 -54
  120. package/src/PreviewPanel/details/matrix-resource.scss +0 -16
  121. package/src/ResourceBreadcrumb/ResourceBreadcrumb.spec.tsx +0 -133
  122. package/src/ResourceBreadcrumb/ResourceBreadcrumb.stories.tsx +0 -24
  123. package/src/ResourceBreadcrumb/ResourceBreadcrumb.tsx +0 -79
  124. package/src/ResourceBreadcrumb/resource-breadcrumb.scss +0 -28
  125. package/src/ResourceBreadcrumb/sample-hierarchy.json +0 -27
  126. package/src/ResourceList/ResourceList.spec.tsx +0 -202
  127. package/src/ResourceList/ResourceList.stories.tsx +0 -40
  128. package/src/ResourceList/ResourceList.tsx +0 -83
  129. package/src/ResourceList/sample-resources.json +0 -851
  130. package/src/ResourcePickerContainer/ResourcePickerContainer.spec.tsx +0 -780
  131. package/src/ResourcePickerContainer/ResourcePickerContainer.stories.tsx +0 -45
  132. package/src/ResourcePickerContainer/ResourcePickerContainer.tsx +0 -290
  133. package/src/SourceList/sample-sources.json +0 -251
  134. package/src/StatusIndicator/StatusIndicator.stories.tsx +0 -83
  135. package/src/StatusIndicator/StatusIndicator.tsx +0 -38
  136. package/src/__mocks__/JestHelpers.ts +0 -65
  137. package/src/__mocks__/StorybookHelpers.ts +0 -128
  138. package/src/__mocks__/jestHelpers.spec.ts +0 -38
  139. package/src/utils/findBestMatchLineage.spec.ts +0 -81
  140. package/src/utils/findBestMatchLineage.ts +0 -30
  141. package/src/utils/uuid.ts +0 -5
@@ -1,9 +1,15 @@
1
- import React from 'react';
2
- import { Resource } from '../../types';
1
+ import React, { ReactElement } from 'react';
2
+ import { ResourceBrowserResource } from '../../types';
3
3
  export type SelectedStateProps = {
4
- resource: Resource;
4
+ resource: ResourceBrowserResource;
5
+ showThumbnail: boolean;
6
+ icon: ReactElement | undefined;
7
+ label: string;
8
+ description: Array<ReactElement>;
5
9
  isDisabled?: boolean;
6
10
  onClear: () => void;
7
11
  resourcePickerContainer: any;
12
+ isModalOpen?: boolean;
13
+ onModalStateChange?(isOpen: boolean): void;
8
14
  };
9
- export declare const SelectedState: ({ resource: { id, type, name, status, squizImage, url }, isDisabled, onClear, resourcePickerContainer, }: SelectedStateProps) => React.JSX.Element;
15
+ export declare const SelectedState: ({ resource, showThumbnail, icon, label, description, isDisabled, onClear, resourcePickerContainer, isModalOpen, onModalStateChange, }: SelectedStateProps) => React.JSX.Element;
@@ -5,42 +5,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.SelectedState = void 0;
7
7
  const react_1 = __importDefault(require("react"));
8
- const pretty_bytes_1 = __importDefault(require("pretty-bytes"));
9
8
  const generic_browser_lib_1 = require("@squiz/generic-browser-lib");
10
- const StatusIndicator_1 = __importDefault(require("../../StatusIndicator/StatusIndicator"));
9
+ const resource_browser_ui_lib_1 = require("@squiz/resource-browser-ui-lib");
11
10
  const CircledLoopIcon_1 = require("../../Icons/CircledLoopIcon");
12
- const SelectedState = ({ resource: { id, type, name, status, squizImage, url }, isDisabled, onClear, resourcePickerContainer, }) => {
13
- const fileSize = squizImage?.imageVariations?.original?.byteSize;
14
- const fileWidth = squizImage?.imageVariations?.original?.width;
15
- const fileHeight = squizImage?.imageVariations?.original?.height;
16
- const replaceAsset = (react_1.default.createElement(generic_browser_lib_1.ModalTrigger, { showLabel: false, label: "Replace selection", containerClasses: "text-gray-500 hover:text-gray-800 focus:text-gray-800 disabled:text-gray-500 disabled:cursor-not-allowed", icon: react_1.default.createElement(CircledLoopIcon_1.CircledLoopIcon, { "aria-hidden": true, className: "m-1" }), isDisabled: isDisabled, scope: "squiz-rb-scope" }, resourcePickerContainer));
11
+ const SelectedState = ({ resource, showThumbnail, icon, label, description, isDisabled, onClear, resourcePickerContainer, isModalOpen, onModalStateChange, }) => {
12
+ const modalController = {
13
+ isOpen: isModalOpen,
14
+ onOpenChange: onModalStateChange,
15
+ };
16
+ const replaceAsset = (react_1.default.createElement(resource_browser_ui_lib_1.ModalTrigger, { overlayTriggerState: isModalOpen && onModalStateChange ? modalController : undefined, showLabel: false, label: "Replace selection", containerClasses: "text-gray-500 hover:text-gray-800 focus:text-gray-800 disabled:text-gray-500 disabled:cursor-not-allowed", icon: react_1.default.createElement(CircledLoopIcon_1.CircledLoopIcon, { "aria-hidden": true, className: "m-1" }), isDisabled: isDisabled, scope: "squiz-rb-scope" }, resourcePickerContainer));
17
17
  return (react_1.default.createElement(react_1.default.Fragment, null,
18
- type.code === 'image' && url ? (react_1.default.createElement("div", { className: "checkered-bg w-[56px] h-[56px] overflow-hidden flex justify-center items-center rounded" },
19
- react_1.default.createElement("img", { src: url, className: "w-full h-full object-cover object-center", alt: name }))) : (react_1.default.createElement(generic_browser_lib_1.Icon, { icon: type.code, resourceSource: "matrix", className: "w-4 h-4 mt-1 flex self-start" })),
18
+ showThumbnail && resource.squizImage ? (react_1.default.createElement("div", { className: "checkered-bg w-[56px] h-[56px] overflow-hidden flex justify-center items-center rounded" },
19
+ react_1.default.createElement("img", { src: resource.squizImage.imageVariations.original.url || resource.url, className: "w-full h-full object-cover object-center", alt: resource.squizImage.name || resource.name }))) : (react_1.default.createElement("div", { className: "w-4 h-4 mt-1 flex self-start overflow-hidden" }, icon)),
20
20
  react_1.default.createElement("div", { className: "justify-self-start self-center w-full overflow-hidden break-words" },
21
- react_1.default.createElement("span", null, name),
22
- react_1.default.createElement("dl", { className: "col-start-2 col-end-2 flex flex-row gap-1 justify-self-start items-center font-normal text-sm" },
23
- react_1.default.createElement("div", null,
24
- react_1.default.createElement("dt", { className: "hidden" },
25
- "Status: ",
26
- status.name),
27
- react_1.default.createElement("dd", { className: "flex items-center" },
28
- react_1.default.createElement(StatusIndicator_1.default, { status: status }))),
29
- react_1.default.createElement("div", null,
30
- react_1.default.createElement("dt", { className: "hidden" }, "Asset ID"),
31
- react_1.default.createElement("dd", { className: "text-gray-700" },
32
- "#",
33
- id))),
34
- fileSize && (react_1.default.createElement("dl", { className: "col-start-2 col-end-2 flex flex-row gap-1 justify-self-start items-center font-normal text-sm" },
35
- react_1.default.createElement("div", null,
36
- react_1.default.createElement("dt", { className: "hidden" }, "Asset size"),
37
- react_1.default.createElement("dd", { className: "text-gray-600" },
38
- (0, pretty_bytes_1.default)(fileSize),
39
- ", ",
40
- fileWidth,
41
- " x ",
42
- fileHeight,
43
- "px"))))),
21
+ label,
22
+ description),
44
23
  react_1.default.createElement("div", { className: "flex" },
45
24
  replaceAsset,
46
25
  react_1.default.createElement(generic_browser_lib_1.ResetButton, { isDisabled: isDisabled, onClick: onClear }))));
@@ -1,13 +1,7 @@
1
1
  import React from 'react';
2
- import type { Source, ScopedSource, Resource } from '../types';
3
- import { RecentResourcesPaths } from '../Hooks/useRecentResourcesPaths';
4
- export default function SourceDropdown({ sources, selectedSource, isLoading, onRootSelect, onSourceSelect, setSource, currentResource, recentSources, }: {
5
- sources: Source[];
6
- selectedSource: ScopedSource | null;
7
- isLoading: boolean;
8
- onRootSelect: () => void;
9
- onSourceSelect: (source: ScopedSource) => void;
10
- setSource: (source: ScopedSource | null, path?: Resource[]) => void;
11
- currentResource: Resource | null;
12
- recentSources: RecentResourcesPaths[];
2
+ import { ResourceBrowserSource } from '../types';
3
+ export default function SourceDropdown({ sources, selectedSource, onSourceSelect, }: {
4
+ sources: ResourceBrowserSource[];
5
+ selectedSource: ResourceBrowserSource;
6
+ onSourceSelect(source: ResourceBrowserSource): void;
13
7
  }): React.JSX.Element;
@@ -22,31 +22,22 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
25
  Object.defineProperty(exports, "__esModule", { value: true });
29
26
  const react_1 = __importStar(require("react"));
30
- const interactions_1 = require("@react-aria/interactions");
31
27
  const generic_browser_lib_1 = require("@squiz/generic-browser-lib");
32
- const uuid_1 = __importDefault(require("../utils/uuid"));
33
- const useCategorisedSources_1 = require("../Hooks/useCategorisedSources");
34
- const HistoryIcon_1 = require("../Icons/HistoryIcon");
35
- function SourceDropdown({ sources, selectedSource, isLoading, onRootSelect, onSourceSelect, setSource, currentResource, recentSources, }) {
36
- const categorisedSources = (0, useCategorisedSources_1.useCategorisedSources)(sources);
37
- const filteredRecentSources = recentSources.filter((item) => item.path?.length);
38
- const [recentLocationSelection, setRecentLocationSelection] = (0, react_1.useState)();
39
- const [uniqueId] = (0, react_1.useState)((0, uuid_1.default)());
28
+ const react_aria_1 = require("react-aria");
29
+ function SourceDropdown({ sources, selectedSource, onSourceSelect, }) {
30
+ const [uniqueId] = (0, react_1.useState)((0, generic_browser_lib_1.uuid)());
40
31
  const buttonRef = (0, react_1.useRef)(null);
41
32
  const [isOpen, setIsOpen] = (0, react_1.useState)(false);
42
33
  // Watch the focus and blur on the menu and close if focus leaves the control
43
- const { focusWithinProps } = (0, interactions_1.useFocusWithin)({
34
+ const { focusWithinProps } = (0, react_aria_1.useFocusWithin)({
44
35
  onBlurWithin: () => {
45
36
  setIsOpen(false);
46
37
  },
47
38
  });
48
39
  // Listen for Esc key within this element
49
- const { keyboardProps } = (0, interactions_1.useKeyboard)({
40
+ const { keyboardProps } = (0, react_aria_1.useKeyboard)({
50
41
  onKeyDown: (e) => {
51
42
  if (isOpen && e.key === 'Escape') {
52
43
  setIsOpen(false);
@@ -56,96 +47,26 @@ function SourceDropdown({ sources, selectedSource, isLoading, onRootSelect, onSo
56
47
  });
57
48
  const handleSourceClick = (source) => {
58
49
  setIsOpen(false);
59
- setRecentLocationSelection(null);
60
50
  buttonRef.current?.focus();
61
51
  onSourceSelect(source);
62
52
  };
63
- const handleRootSelect = () => {
64
- setIsOpen(false);
65
- setRecentLocationSelection(null);
66
- buttonRef.current?.focus();
67
- onRootSelect();
68
- };
69
- const handleRecentLocationClick = (location) => {
70
- setIsOpen(false);
71
- setRecentLocationSelection(location);
72
- buttonRef.current?.focus();
73
- if (location.path) {
74
- const [rootNode, ...path] = location.path;
75
- setSource({
76
- source: location.source,
77
- resource: rootNode,
78
- }, path);
79
- }
80
- };
81
- (0, react_1.useEffect)(() => {
82
- if (recentLocationSelection?.path) {
83
- const lastResource = recentLocationSelection.path[recentLocationSelection.path.length - 1];
84
- // If the current resource selected in the resource browser is no longer the item selected in the
85
- // recent locations section dropdown then we set the selection to null to prevent active statuses.
86
- if (currentResource && currentResource.id !== lastResource?.id) {
87
- setRecentLocationSelection(null);
88
- }
89
- }
90
- }, [recentLocationSelection, currentResource]);
53
+ if (!sources.length) {
54
+ return react_1.default.createElement(react_1.default.Fragment, null);
55
+ }
91
56
  return (react_1.default.createElement("div", { ...focusWithinProps, ...keyboardProps, className: "relative w-72 border-2 rounded border-gray-300" },
92
57
  react_1.default.createElement("button", { ref: buttonRef, type: "button", "aria-label": "Source quick select", "aria-expanded": isOpen, "aria-controls": `${uniqueId}-button-menu`, onClick: () => setIsOpen(!isOpen), className: "relative flex items-center text-sm font-semibold p-1.5 w-full" },
93
- selectedSource && (react_1.default.createElement(react_1.default.Fragment, null,
94
- react_1.default.createElement("span", { className: "sr-only" }, "current source "),
95
- react_1.default.createElement(generic_browser_lib_1.Icon, { icon:
96
- // Ignoring this specific line in test coverage because its a super niche issue that I could only replicate in Matrix
97
- /* istanbul ignore next */
98
- recentLocationSelection
99
- ? currentResource?.type.code || selectedSource.resource?.type.code
100
- : selectedSource.resource?.type.code, resourceSource: "matrix", "aria-hidden": true, className: "mr-2.5 h-[20px] w-[20px]" }),
101
- react_1.default.createElement("div", { className: "truncate max-w-[200px]" },
102
- // Ignoring this specific line in test coverage because its a super niche issue that I could only replicate in Matrix
103
- /* istanbul ignore next */
104
- recentLocationSelection
105
- ? currentResource?.name || selectedSource.resource?.name || selectedSource.source.name
106
- : selectedSource.resource?.name || selectedSource.source.name))),
107
- !selectedSource && (react_1.default.createElement(react_1.default.Fragment, null,
108
- react_1.default.createElement("span", { className: "sr-only" }, "view "),
109
- react_1.default.createElement(generic_browser_lib_1.Icon, { icon: 'root', "aria-hidden": true, className: "mr-2.5 h-[20px] w-[20px]" }),
110
- "All available sources")),
58
+ react_1.default.createElement("span", { className: "sr-only" }, "current source "),
59
+ react_1.default.createElement(generic_browser_lib_1.Icon, { icon: selectedSource.type, "aria-hidden": true, className: "mr-2.5 h-[20px] w-[20px]" }),
60
+ react_1.default.createElement("div", { className: "truncate max-w-[200px]" }, selectedSource.name),
111
61
  react_1.default.createElement(generic_browser_lib_1.Icon, { icon: 'arrow-down', "aria-hidden": true, className: "absolute right-3" })),
112
- react_1.default.createElement("ul", { id: `${uniqueId}-button-menu`, "aria-hidden": !isOpen, className: `absolute z-50 top-[calc(100%+5px)] -left-0.5 w-[calc(100%+4px)] bg-gray-100 border-2 rounded border-gray-300 p-2 overflow-y-scroll max-h-80 ${!isOpen ? 'hidden' : ''}` },
113
- react_1.default.createElement("li", { key: "return-root", className: "flex items-center text-sm font-semibold mb-2 bg-white border-1 rounded border-grey-200" },
114
- react_1.default.createElement("button", { type: "button", onClick: handleRootSelect, className: `relative grow flex items-center p-2.5 hover:bg-gray-100 focus:bg-gray-100` },
115
- react_1.default.createElement(generic_browser_lib_1.Icon, { icon: 'root', "aria-hidden": true, className: "mr-2.5" }),
116
- "All available sources")),
117
- isLoading && (react_1.default.createElement("li", { className: "mt-2" },
118
- react_1.default.createElement(generic_browser_lib_1.Spinner, { size: "sm", label: "Loading sources", className: "m-3" }))),
119
- !isLoading && filteredRecentSources.length > 0 && (react_1.default.createElement("li", { className: `flex flex-col text-sm font-semibold text-grey-800` },
120
- react_1.default.createElement("div", { className: "relative flex justify-center before:w-full before:h-px before:bg-gray-300 before:absolute before:top-2/4 before:z-0" },
121
- react_1.default.createElement("span", { className: "z-10 bg-gray-100 px-2.5 flex gap-1 items-center" },
122
- react_1.default.createElement(HistoryIcon_1.HistoryIcon, null),
123
- "Recent locations")),
124
- react_1.default.createElement("ul", { "aria-label": "recent location nodes", className: "flex flex-col mt-2" }, filteredRecentSources.map((item, index) => {
125
- const lastResource = item.path && item.path[item.path.length - 1];
126
- const isSelectedSource = item.source?.id === selectedSource?.source.id &&
127
- lastResource?.id === recentLocationSelection?.path?.[recentLocationSelection.path?.length - 1]?.id;
128
- return (react_1.default.createElement("li", { key: `${index}-${item.source?.id}-${lastResource?.id}`, className: "flex items-center bg-white border border-b-0 last:border-b border-grey-200 first:rounded-t last:rounded-b" },
129
- react_1.default.createElement("button", { type: "button", onClick: () => handleRecentLocationClick(item), className: `relative grow flex items-center p-2.5 hover:bg-gray-100 focus:bg-gray-100` },
130
- react_1.default.createElement(generic_browser_lib_1.Icon, { icon: (lastResource?.type.code || 'folder'), resourceSource: "matrix", "aria-label": lastResource?.name || item.source?.name, className: "shrink-0 mr-2.5" }),
131
- react_1.default.createElement("span", { className: "text-left mr-7" }, lastResource?.name || item.source?.name),
132
- isSelectedSource && (react_1.default.createElement(generic_browser_lib_1.Icon, { icon: 'selected', "aria-label": "selected", className: "absolute right-4" })))));
133
- })))),
134
- !isLoading &&
135
- categorisedSources.map(({ key, label, sources }, index) => {
136
- return (react_1.default.createElement("li", { key: key, className: `flex flex-col text-sm font-semibold text-grey-800 ${index > 0 || filteredRecentSources.length > 0 ? 'mt-3' : ''}` },
137
- react_1.default.createElement("div", { className: "relative flex justify-center before:w-full before:h-px before:bg-gray-300 before:absolute before:top-2/4 before:z-0" },
138
- react_1.default.createElement("span", { className: "z-10 bg-gray-100 px-2.5" }, label)),
139
- sources?.length > 0 && (react_1.default.createElement("ul", { "aria-label": `${label} nodes`, className: "flex flex-col mt-2" }, sources.map(({ source, resource }) => {
140
- const isSelectedSource = source.id === selectedSource?.source.id &&
141
- resource?.id === selectedSource?.resource?.id &&
142
- !recentLocationSelection;
143
- return (react_1.default.createElement("li", { key: `${source.id}-${resource?.id}`, className: "flex items-center bg-white border border-b-0 last:border-b border-grey-200 first:rounded-t last:rounded-b" },
144
- react_1.default.createElement("button", { type: "button", onClick: () => handleSourceClick({ source, resource }), className: `relative grow flex items-center p-2.5 hover:bg-gray-100 focus:bg-gray-100` },
145
- react_1.default.createElement(generic_browser_lib_1.Icon, { icon: resource?.type.code, resourceSource: "matrix", "aria-label": resource?.type.name, className: "shrink-0 mr-2.5" }),
146
- react_1.default.createElement("span", { className: "text-left mr-7" }, resource?.name || source.name),
147
- isSelectedSource && (react_1.default.createElement(generic_browser_lib_1.Icon, { icon: 'selected', "aria-label": "selected", className: "absolute right-4" })))));
148
- })))));
149
- }))));
62
+ react_1.default.createElement("ul", { id: `${uniqueId}-button-menu`, "aria-hidden": !isOpen, className: `absolute z-50 top-[calc(100%+5px)] -left-0.5 w-[calc(100%+4px)] bg-gray-100 border-1 shadow-md rounded border-gray-300 p-2 pb-0 overflow-y-scroll max-h-80 ${!isOpen ? 'hidden' : ''}` }, sources.map((source) => {
63
+ const { id, name, type } = source;
64
+ const isSelectedSource = id === selectedSource.id;
65
+ return (react_1.default.createElement("li", { key: id, className: "flex items-center text-sm font-semibold mb-2 bg-white rounded" },
66
+ react_1.default.createElement("button", { type: "button", onClick: () => handleSourceClick(source), className: `relative grow flex items-center p-2 border-1 border-white rounded hover:bg-gray-50 hover:border-gray-300 focus:bg-gray-100` },
67
+ react_1.default.createElement(generic_browser_lib_1.Icon, { icon: type, "aria-label": type, className: "shrink-0 mr-2.5" }),
68
+ react_1.default.createElement("span", { className: "text-left mr-7" }, name),
69
+ isSelectedSource && (react_1.default.createElement(generic_browser_lib_1.Icon, { icon: 'selected', "aria-label": "selected", className: "absolute right-4" })))));
70
+ }))));
150
71
  }
151
72
  exports.default = SourceDropdown;
@@ -1,19 +1,8 @@
1
1
  import React from 'react';
2
- import { OverlayTriggerState } from 'react-stately';
3
- import { DOMAttributes, FocusableElement } from '@react-types/shared';
4
- import { Source, ScopedSource, Resource } from '../types';
5
- import { RecentResourcesPaths } from '../Hooks/useRecentResourcesPaths';
6
- export interface SourceListProps {
7
- sources: Source[];
8
- selectedResource?: Resource | null;
9
- previewModalState: OverlayTriggerState;
10
- isLoading: boolean;
11
- onSourceSelect: (node: ScopedSource, overlayProps: DOMAttributes<FocusableElement>) => void;
12
- onSourceDrilldown: (source: ScopedSource) => void;
13
- handleReload: () => void;
14
- setSource: (source: ScopedSource | null, path?: Resource[]) => void;
15
- recentSources: RecentResourcesPaths[];
16
- error: Error | null;
2
+ import { ResourceBrowserSource } from '../types';
3
+ interface SourceListProps {
4
+ sources: ResourceBrowserSource[];
5
+ onSourceSelect(source: ResourceBrowserSource): void;
17
6
  }
18
- declare const SourceList: ({ sources, selectedResource, previewModalState, isLoading, onSourceSelect, onSourceDrilldown, handleReload, setSource, recentSources, error, }: SourceListProps) => React.JSX.Element;
7
+ declare function SourceList({ sources, onSourceSelect }: SourceListProps): React.JSX.Element;
19
8
  export default SourceList;
@@ -1,82 +1,21 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
4
  };
28
5
  Object.defineProperty(exports, "__esModule", { value: true });
29
- const react_1 = __importStar(require("react"));
6
+ const react_1 = __importDefault(require("react"));
30
7
  const generic_browser_lib_1 = require("@squiz/generic-browser-lib");
31
- const clsx_1 = __importDefault(require("clsx"));
32
- const useCategorisedSources_1 = require("../Hooks/useCategorisedSources");
33
- const HistoryIcon_1 = require("../Icons/HistoryIcon");
34
- const SourceList = function ({ sources, selectedResource, previewModalState, isLoading, onSourceSelect, onSourceDrilldown, handleReload, setSource, recentSources, error, }) {
35
- const categorisedSources = (0, useCategorisedSources_1.useCategorisedSources)(sources);
36
- const listRef = (0, react_1.useRef)(null);
37
- const filteredRecentSources = recentSources.filter((item) => item.path?.length);
38
- (0, react_1.useEffect)(() => {
39
- if (listRef.current) {
40
- listRef.current?.focus({
41
- preventScroll: true,
42
- });
43
- }
44
- }, []);
45
- if (isLoading) {
46
- return (react_1.default.createElement("div", { className: "flex flex-col bg-gray-100 min-h-full", "aria-label": "loading Source list" },
47
- react_1.default.createElement(generic_browser_lib_1.SkeletonList, { itemCount: 3 }),
48
- react_1.default.createElement(generic_browser_lib_1.SkeletonList, { itemCount: 3 })));
49
- }
50
- return (react_1.default.createElement("ul", { ref: listRef, tabIndex: -1, "aria-label": `Source list`, className: (0, clsx_1.default)('flex flex-col bg-gray-100 min-h-full focus-visible:outline-0 px-7 py-4') },
51
- error && react_1.default.createElement(generic_browser_lib_1.ResourceState, { state: "error", message: error.message, handleReload: handleReload }),
52
- !error && filteredRecentSources.length > 0 && (react_1.default.createElement("li", { className: `flex flex-col text-sm font-semibold text-grey-800` },
53
- react_1.default.createElement("div", { className: "relative flex justify-center before:w-full before:h-px before:bg-gray-300 before:absolute before:top-2/4 before:z-0" },
54
- react_1.default.createElement("span", { className: "z-10 bg-gray-100 px-2.5 flex gap-1 items-center" },
55
- react_1.default.createElement(HistoryIcon_1.HistoryIcon, null),
56
- "Recent locations")),
57
- react_1.default.createElement("ul", { "aria-label": `recent location nodes`, className: "flex flex-col" }, filteredRecentSources.map((item, index) => {
58
- if (item.path) {
59
- const lastResource = item.path[item.path.length - 1];
60
- const [rootNode, ...path] = item.path;
61
- return (react_1.default.createElement(generic_browser_lib_1.ResourceItem, { key: `${index}-${item.source?.id}-${lastResource?.id}`, item: { source: item.source, resource: lastResource }, label: lastResource?.name || item.source?.name || '', type: lastResource?.type?.code || 'folder', previewModalState: previewModalState, onSelect: () => {
62
- setSource({
63
- source: item.source,
64
- resource: rootNode,
65
- }, path);
66
- }, className: (0, clsx_1.default)(index === 0 && 'rounded-t-lg mt-3', index === filteredRecentSources.length - 1 && 'rounded-b-lg'), showChevron: true }));
67
- }
68
- })))),
69
- !error &&
70
- categorisedSources.map(({ key, label, sources }, index) => {
71
- return (react_1.default.createElement("li", { key: key, className: `flex flex-col text-sm font-semibold text-grey-800 ${index > 0 || filteredRecentSources.length > 0 ? 'mt-3' : ''}` },
72
- react_1.default.createElement("div", { className: "relative flex justify-center before:w-full before:h-px before:bg-gray-300 before:absolute before:top-2/4 before:z-0" },
73
- react_1.default.createElement("span", { className: "z-10 bg-gray-100 px-2.5" }, label)),
74
- sources.length > 0 && (react_1.default.createElement("ul", { "aria-label": `${label} nodes`, className: "flex flex-col" }, sources.map(({ source, resource }) => {
75
- if (!resource || resource.childCount === 0) {
76
- return (react_1.default.createElement(generic_browser_lib_1.ResourceItem, { key: `${source.id}-${resource?.id}`, item: { source, resource }, label: resource?.name || source.name, type: resource?.type.code || 'folder', previewModalState: previewModalState, onSelect: onSourceDrilldown, className: "mt-3 rounded-lg", showChevron: true }));
77
- }
78
- return (react_1.default.createElement(generic_browser_lib_1.ResourceItem, { key: `${source.id}-${resource?.id}`, item: { source, resource }, selected: resource?.id == selectedResource?.id && resource != null, label: resource?.name || source.name, type: resource?.type.code || 'folder', childCount: resource?.childCount || undefined, previewModalState: previewModalState, onSelect: onSourceSelect, onDrillDown: onSourceDrilldown, className: "mt-3 rounded-lg", showChevron: true }));
79
- })))));
80
- })));
81
- };
8
+ function SourceList({ sources, onSourceSelect }) {
9
+ return (react_1.default.createElement("div", { className: "overflow-y-scroll w-screen max-w-[400px] flex-1 grow-[3] border-r border-gray-300 bg-gray-100 pl-4.5 pr-4.5 pb-4.5 pt-3" },
10
+ react_1.default.createElement("div", { className: "text-md font-semibold" }, "Select an environment to use"),
11
+ react_1.default.createElement("ul", { tabIndex: -1, "aria-label": `environment list`, className: "flex flex-col bg-gray-100 min-h-full focus-visible:outline-0" }, sources.map((source, index) => {
12
+ return (react_1.default.createElement("li", { key: index, className: "flex items-stretch relative" },
13
+ react_1.default.createElement("button", { onClick: () => {
14
+ onSourceSelect(source);
15
+ }, className: "w-full p-1 mt-3 bg-white border-1 border-grey-200 min-h-[64px] rounded-lg flex items-center text-md font-semibold" },
16
+ react_1.default.createElement(generic_browser_lib_1.Icon, { icon: source.type, className: "ml-4" }),
17
+ react_1.default.createElement("span", { className: "line-clamp-2 text-left break-word ml-4" }, source.name || source.id),
18
+ react_1.default.createElement(generic_browser_lib_1.Icon, { icon: 'arrow-right', className: "absolute ml-1 right-4" }))));
19
+ }))));
20
+ }
82
21
  exports.default = SourceList;