@squiz/resource-browser 1.32.1-alpha.33 → 1.32.1-alpha.34

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 (62) hide show
  1. package/lib/Hooks/useAsync.d.ts +21 -0
  2. package/lib/Hooks/useAsync.js +53 -0
  3. package/lib/Hooks/useChildResources.d.ts +3 -7
  4. package/lib/Hooks/useChildResources.js +5 -29
  5. package/lib/Hooks/useResource.d.ts +15 -0
  6. package/lib/Hooks/useResource.js +12 -0
  7. package/lib/Hooks/useResourcePath.d.ts +1 -1
  8. package/lib/PreviewPanel/details/MatrixResource.js +2 -1
  9. package/lib/ResourceBrowserContext/ResourceBrowserContext.d.ts +8 -0
  10. package/lib/ResourceBrowserContext/ResourceBrowserContext.js +18 -0
  11. package/lib/ResourceItem/ResourceItem.js +1 -1
  12. package/lib/ResourcePicker/ResetButton.d.ts +5 -0
  13. package/lib/ResourcePicker/ResetButton.js +11 -0
  14. package/lib/ResourcePicker/ResourcePicker.d.ts +14 -0
  15. package/lib/ResourcePicker/ResourcePicker.js +26 -0
  16. package/lib/ResourcePicker/States/Error.d.ts +6 -0
  17. package/lib/ResourcePicker/States/Error.js +14 -0
  18. package/lib/ResourcePicker/States/Loading.d.ts +1 -0
  19. package/lib/ResourcePicker/States/Loading.js +11 -0
  20. package/lib/ResourcePicker/States/Selected.d.ts +7 -0
  21. package/lib/ResourcePicker/States/Selected.js +43 -0
  22. package/lib/ResourcePickerContainer/ResourcePickerContainer.js +3 -3
  23. package/lib/Skeleton/ListItem/SkeletonListItem.js +1 -1
  24. package/lib/SourceDropdown/SourceDropdown.js +3 -3
  25. package/lib/StatusIndicator/StatusIndicator.d.ts +2 -1
  26. package/lib/StatusIndicator/StatusIndicator.js +3 -2
  27. package/lib/index.css +6 -0
  28. package/lib/index.d.ts +8 -7
  29. package/lib/index.js +35 -13
  30. package/lib/types.d.ts +67 -0
  31. package/lib/types.js +2 -0
  32. package/package.json +3 -3
  33. package/src/Hooks/useAsync.spec.ts +106 -0
  34. package/src/Hooks/useAsync.ts +62 -0
  35. package/src/Hooks/useChildResources.spec.ts +2 -23
  36. package/src/Hooks/useChildResources.ts +9 -34
  37. package/src/Hooks/useResource.spec.ts +32 -0
  38. package/src/Hooks/useResource.ts +19 -0
  39. package/src/Hooks/useSources.spec.ts +2 -14
  40. package/src/Hooks/useSources.ts +3 -26
  41. package/src/PreviewPanel/details/MatrixResource.tsx +1 -2
  42. package/src/ResourceBrowserContext/ResourceBrowserContext.spec.tsx +32 -0
  43. package/src/ResourceBrowserContext/ResourceBrowserContext.ts +20 -0
  44. package/src/ResourceItem/ResourceItem.tsx +1 -1
  45. package/src/ResourcePicker/ResetButton.tsx +7 -1
  46. package/src/ResourcePicker/ResourcePicker.spec.tsx +8 -4
  47. package/src/ResourcePicker/ResourcePicker.stories.tsx +2 -2
  48. package/src/ResourcePicker/ResourcePicker.tsx +21 -12
  49. package/src/ResourcePicker/States/Error.tsx +9 -3
  50. package/src/ResourcePicker/States/Selected.tsx +9 -4
  51. package/src/ResourcePickerContainer/ResourcePickerContainer.tsx +5 -5
  52. package/src/Skeleton/ListItem/SkeletonListItem.tsx +1 -1
  53. package/src/SourceDropdown/SourceDropdown.tsx +3 -3
  54. package/src/StatusIndicator/StatusIndicator.tsx +5 -2
  55. package/src/__mocks__/StorybookHelpers.ts +18 -13
  56. package/src/index.spec.tsx +4 -4
  57. package/src/index.stories.tsx +15 -15
  58. package/src/index.tsx +39 -54
  59. package/src/{types.d.ts → types.ts} +1 -1
  60. package/tailwind.config.cjs +5 -0
  61. package/lib/Hooks/useSources.d.ts +0 -16
  62. package/lib/Hooks/useSources.js +0 -31
@@ -0,0 +1,21 @@
1
+ import { DependencyList } from 'react';
2
+ export type UseAsyncProps<TReturnType, TDefaultValueType> = {
3
+ /** The async callback to call for fetching data. */
4
+ callback: () => TReturnType | Promise<TReturnType>;
5
+ /** The default value to populate the data as when initially mounted or reloading data. */
6
+ defaultValue: TReturnType | TDefaultValueType;
7
+ };
8
+ /**
9
+ * Hook for invoking a piece of async code and keeping track of its state.
10
+ *
11
+ * Data is loaded in 3 different ways:
12
+ * 1. On initial mount.
13
+ * 2. When any of the `deps` change.
14
+ * 3. When the `relaod` function is called.
15
+ */
16
+ export declare const useAsync: <TReturnType, TDefaultValueType>({ callback, defaultValue }: UseAsyncProps<TReturnType, TDefaultValueType>, deps: DependencyList) => {
17
+ data: TReturnType | TDefaultValueType;
18
+ error: Error | null;
19
+ isLoading: boolean;
20
+ reload: () => void;
21
+ };
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useAsync = void 0;
4
+ const react_1 = require("react");
5
+ /**
6
+ * Hook for invoking a piece of async code and keeping track of its state.
7
+ *
8
+ * Data is loaded in 3 different ways:
9
+ * 1. On initial mount.
10
+ * 2. When any of the `deps` change.
11
+ * 3. When the `relaod` function is called.
12
+ */
13
+ const useAsync = ({ callback, defaultValue }, deps) => {
14
+ const [data, setData] = (0, react_1.useState)(defaultValue);
15
+ const [isLoading, setIsLoading] = (0, react_1.useState)(false);
16
+ const [error, setError] = (0, react_1.useState)(null);
17
+ const reload = (0, react_1.useCallback)(() => {
18
+ setIsLoading(true);
19
+ setError(null);
20
+ setData(defaultValue);
21
+ try {
22
+ const result = callback();
23
+ if (result instanceof Promise) {
24
+ // if the callback returned a promise wait for it to either resolve or reject.
25
+ result
26
+ .then((resolved) => {
27
+ setData(resolved);
28
+ setIsLoading(false);
29
+ })
30
+ .catch((e) => {
31
+ setError(e instanceof Error ? e : new Error(String(e)));
32
+ setIsLoading(false);
33
+ });
34
+ }
35
+ else {
36
+ // if the callback returned something other than a promise assume it is the data we want.
37
+ setData(result);
38
+ setIsLoading(false);
39
+ }
40
+ }
41
+ catch (e) {
42
+ // callback threw outside of the scope of the promise.
43
+ setError(e instanceof Error ? e : new Error(String(e)));
44
+ setIsLoading(false);
45
+ }
46
+ }, deps);
47
+ // reload data on dependency change (and initial mount)
48
+ (0, react_1.useEffect)(() => {
49
+ reload();
50
+ }, deps);
51
+ return { data, error, isLoading, reload };
52
+ };
53
+ exports.useAsync = useAsync;
@@ -6,15 +6,11 @@ type UseChildResourcesProps = {
6
6
  };
7
7
  /**
8
8
  * Triggers a reload of the child resources when the source or current resource change.
9
- *
10
- * @param {ScopedSource|null} source
11
- * @param {Resource|null} currentResource
12
- * @param {Function} onRequestChildren
13
9
  */
14
10
  export declare const useChildResources: ({ source, currentResource, onRequestChildren }: UseChildResourcesProps) => {
15
- isLoading: boolean;
16
- resources: Resource[];
17
- reloadResources: () => void;
11
+ data: never[] | Resource[];
18
12
  error: Error | null;
13
+ isLoading: boolean;
14
+ reload: () => void;
19
15
  };
20
16
  export {};
@@ -1,36 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useChildResources = void 0;
4
- const react_1 = require("react");
4
+ const useAsync_1 = require("./useAsync");
5
5
  /**
6
6
  * Triggers a reload of the child resources when the source or current resource change.
7
- *
8
- * @param {ScopedSource|null} source
9
- * @param {Resource|null} currentResource
10
- * @param {Function} onRequestChildren
11
7
  */
12
- const useChildResources = ({ source, currentResource, onRequestChildren }) => {
13
- const [error, setError] = (0, react_1.useState)(null);
14
- const [isLoading, setIsLoading] = (0, react_1.useState)(false);
15
- const [resources, setResources] = (0, react_1.useState)([]);
16
- const loadResource = (0, react_1.useCallback)(() => {
17
- setError(null);
18
- setResources([]);
19
- if (source) {
20
- setIsLoading(true);
21
- onRequestChildren(source.source, currentResource)
22
- .then((resources) => {
23
- setResources(resources);
24
- setIsLoading(false);
25
- })
26
- .catch((e) => {
27
- setError(e);
28
- setIsLoading(false);
29
- });
30
- }
31
- }, [source, currentResource]);
32
- // trigger a reload of the resources when the source or the current resource changes.
33
- (0, react_1.useEffect)(loadResource, [source, currentResource]);
34
- return { isLoading, resources, reloadResources: loadResource, error };
35
- };
8
+ const useChildResources = ({ source, currentResource, onRequestChildren }) => (0, useAsync_1.useAsync)({
9
+ callback: () => (source ? onRequestChildren(source.source, currentResource || source.resource) : []),
10
+ defaultValue: [],
11
+ }, [source, currentResource]);
36
12
  exports.useChildResources = useChildResources;
@@ -0,0 +1,15 @@
1
+ import { Resource, ResourceReference } from '../types';
2
+ type UseResourceProps = {
3
+ onRequestResource: (reference: ResourceReference) => Promise<Resource | null>;
4
+ reference?: ResourceReference | null;
5
+ };
6
+ /**
7
+ * Loads the resource indicated by the provided reference.
8
+ */
9
+ export declare const useResource: ({ onRequestResource, reference }: UseResourceProps) => {
10
+ data: Resource | null;
11
+ error: Error | null;
12
+ isLoading: boolean;
13
+ reload: () => void;
14
+ };
15
+ export {};
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useResource = void 0;
4
+ const useAsync_1 = require("./useAsync");
5
+ /**
6
+ * Loads the resource indicated by the provided reference.
7
+ */
8
+ const useResource = ({ onRequestResource, reference }) => (0, useAsync_1.useAsync)({
9
+ callback: () => (reference ? onRequestResource(reference) : null),
10
+ defaultValue: null,
11
+ }, [reference?.source, reference?.resource]);
12
+ exports.useResource = useResource;
@@ -9,7 +9,7 @@ import { Hierarchy, ScopedSource, Resource } from '../types';
9
9
  export declare const useResourcePath: () => {
10
10
  source: ScopedSource | null;
11
11
  currentResource: Resource | null;
12
- hierarchy: Hierarchy<ScopedSource | Resource>;
12
+ hierarchy: Hierarchy<Resource | ScopedSource>;
13
13
  setSource: (source: ScopedSource | null) => void;
14
14
  push: (resource: Resource) => void;
15
15
  popUntil: (node: ScopedSource | Resource) => void;
@@ -24,7 +24,8 @@ const MatrixResource = ({ resource: { id, type, name, status } }) => {
24
24
  react_1.default.createElement("div", { className: "flex mb-2" },
25
25
  react_1.default.createElement("dt", { className: "w-[60px] mr-4 text-gray-600" }, "Status"),
26
26
  react_1.default.createElement("dd", { className: "flex items-center font-semibold" },
27
- react_1.default.createElement(StatusIndicator_1.default, { status: status }),
27
+ react_1.default.createElement(StatusIndicator_1.default, { className: "mr-1", status: status }),
28
+ " ",
28
29
  status.name))))));
29
30
  };
30
31
  exports.default = MatrixResource;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { Resource, ResourceReference, Source } from '../types';
3
+ export type ResourceBrowserContextProps = {
4
+ onRequestSources: () => Promise<Source[]>;
5
+ onRequestChildren(source: Source, resource: Resource | null): Promise<Resource[]>;
6
+ onRequestResource(reference: ResourceReference): Promise<Resource | null>;
7
+ };
8
+ export declare const ResourceBrowserContext: React.Context<ResourceBrowserContextProps>;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ResourceBrowserContext = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ exports.ResourceBrowserContext = react_1.default.createContext({
9
+ onRequestSources: () => {
10
+ throw new Error('onRequestSources has not been configured.');
11
+ },
12
+ onRequestChildren: () => {
13
+ throw new Error('onRequestChildren has not been configured.');
14
+ },
15
+ onRequestResource: () => {
16
+ throw new Error('onRequestResource has not been configured.');
17
+ },
18
+ });
@@ -11,7 +11,7 @@ const ResourceItem = ({ item, selected, label, type, childCount, previewModalSta
11
11
  const { triggerProps, overlayProps } = (0, react_aria_1.useOverlayTrigger)({ type: 'dialog' }, previewModalState);
12
12
  const isDisabled = allowedTypes !== undefined && !allowedTypes.includes(type);
13
13
  const title = isDisabled ? "You can't select this item" : label;
14
- return (react_1.default.createElement("li", { className: `flex items-stretch p-1 bg-white border border-grey-200 min-h-[64px] ${className}` },
14
+ return (react_1.default.createElement("li", { className: `flex items-stretch p-1 bg-white border-1 border-grey-200 min-h-[64px] ${className}` },
15
15
  react_1.default.createElement(ModalOpeningButton_1.default, { type: "button", ...triggerProps, isDisabled: isDisabled, onPress: () => onSelect(item, overlayProps), "aria-label": childCount === undefined ? `Drill down to ${label} children` : '', className: `
16
16
  relative grow flex items-center px-4 py-2 rounded outline-0 ${selected ? 'bg-blue-100 text-blue-400' : ''} ${childCount !== undefined && childCount > 0 ? 'mr-2' : ''} ${isDisabled ? 'font-normal text-gray-600 cursor-not-allowed' : 'hover:bg-gray-50 focus:bg-gray-50'}
17
17
  `, title: title },
@@ -0,0 +1,5 @@
1
+ export type ResetButtonProps = {
2
+ onClick: () => void;
3
+ isDisabled?: boolean;
4
+ };
5
+ export declare const ResetButton: ({ onClick, isDisabled }: ResetButtonProps) => JSX.Element;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ResetButton = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const CloseRounded_1 = __importDefault(require("@mui/icons-material/CloseRounded"));
9
+ const ResetButton = ({ onClick, isDisabled }) => (react_1.default.createElement("button", { type: "button", "aria-label": `Remove selection`, title: `Remove selection`, className: "text-gray-500 hover:text-gray-800 focus:text-gray-800 w-6 h-6 disabled:text-gray-500 disabled:cursor-not-allowed", disabled: isDisabled, onClick: onClick },
10
+ react_1.default.createElement(CloseRounded_1.default, null)));
11
+ exports.ResetButton = ResetButton;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { DOMAttributes } from '@react-types/shared';
3
+ import { Resource } from '../types';
4
+ export type ResourcePickerProps = {
5
+ resource: Resource | null;
6
+ allowedTypes: string[] | undefined;
7
+ error: Error | null;
8
+ isLoading: boolean;
9
+ isDisabled?: boolean;
10
+ children: (onClose: () => void, titleProps: DOMAttributes) => React.ReactElement;
11
+ onClear: () => void;
12
+ };
13
+ declare const ResourcePicker: ({ resource, allowedTypes, error, isLoading, isDisabled, children, onClear, }: ResourcePickerProps) => JSX.Element;
14
+ export default ResourcePicker;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const react_1 = __importDefault(require("react"));
7
+ const AdsClickRounded_1 = __importDefault(require("@mui/icons-material/AdsClickRounded"));
8
+ const AddCircleOutlineRounded_1 = __importDefault(require("@mui/icons-material/AddCircleOutlineRounded"));
9
+ const PhotoLibraryRounded_1 = __importDefault(require("@mui/icons-material/PhotoLibraryRounded"));
10
+ const ModalTrigger_1 = __importDefault(require("../Modal/ModalTrigger"));
11
+ const Error_1 = require("./States/Error");
12
+ const Loading_1 = require("./States/Loading");
13
+ const Selected_1 = require("./States/Selected");
14
+ const clsx_1 = __importDefault(require("clsx"));
15
+ const ResourcePicker = ({ resource, allowedTypes, error, isLoading, isDisabled, children, onClear, }) => {
16
+ const isImagePicker = allowedTypes && allowedTypes.length === 1 && allowedTypes.includes('image');
17
+ const isEmpty = resource === null && !isLoading && !error;
18
+ return (react_1.default.createElement("div", { className: (0, clsx_1.default)('resource-picker', isDisabled && 'bg-gray-300') },
19
+ isImagePicker ? (react_1.default.createElement(PhotoLibraryRounded_1.default, { "aria-hidden": true, className: "w-6 h-6" })) : (react_1.default.createElement(AdsClickRounded_1.default, { "aria-hidden": true, className: "w-6 h-6" })),
20
+ isEmpty ? (react_1.default.createElement(ModalTrigger_1.default, { showLabel: true, label: isImagePicker ? `Choose image` : `Choose asset`, icon: react_1.default.createElement(AddCircleOutlineRounded_1.default, { "aria-hidden": true, className: "!w-4 !h-4" }), isDisabled: isDisabled }, children)) : (react_1.default.createElement("div", { className: "resource-picker-info" },
21
+ react_1.default.createElement("div", { className: "resource-picker-info__layout" },
22
+ isLoading && react_1.default.createElement(Loading_1.LoadingState, null),
23
+ error && react_1.default.createElement(Error_1.ErrorState, { error: error, onClear: onClear }),
24
+ resource && react_1.default.createElement(Selected_1.SelectedState, { resource: resource, isDisabled: isDisabled, onClear: onClear }))))));
25
+ };
26
+ exports.default = ResourcePicker;
@@ -0,0 +1,6 @@
1
+ export type ErrorStateProps = {
2
+ error: Error;
3
+ isDisabled?: boolean;
4
+ onClear: () => void;
5
+ };
6
+ export declare const ErrorState: ({ error, isDisabled, onClear }: ErrorStateProps) => JSX.Element;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ErrorState = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const Icon_1 = __importDefault(require("../../Icons/Icon"));
9
+ const ResetButton_1 = require("../ResetButton");
10
+ const ErrorState = ({ error, isDisabled, onClear }) => (react_1.default.createElement(react_1.default.Fragment, null,
11
+ react_1.default.createElement(Icon_1.default, { icon: 'error', "aria-hidden": true, className: "w-6 h-6 text-red-300" }),
12
+ react_1.default.createElement("div", { className: "text-red-300" }, error.message),
13
+ react_1.default.createElement(ResetButton_1.ResetButton, { isDisabled: isDisabled, onClick: onClear })));
14
+ exports.ErrorState = ErrorState;
@@ -0,0 +1 @@
1
+ export declare const LoadingState: () => JSX.Element;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.LoadingState = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const Spinner_1 = __importDefault(require("../../Spinner/Spinner"));
9
+ const LoadingState = () => (react_1.default.createElement("div", { className: "col-start-2 col-end-2" },
10
+ react_1.default.createElement(Spinner_1.default, { label: "Loading selection", className: "text-gray-600 m-2" })));
11
+ exports.LoadingState = LoadingState;
@@ -0,0 +1,7 @@
1
+ import { Resource } from '../../types';
2
+ export type SelectedStateProps = {
3
+ resource: Resource;
4
+ isDisabled?: boolean;
5
+ onClear: () => void;
6
+ };
7
+ export declare const SelectedState: ({ resource: { id, type, name, status, squizImage }, isDisabled, onClear, }: SelectedStateProps) => JSX.Element;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SelectedState = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const pretty_bytes_1 = __importDefault(require("pretty-bytes"));
9
+ const Icon_1 = __importDefault(require("../../Icons/Icon"));
10
+ const StatusIndicator_1 = __importDefault(require("../../StatusIndicator/StatusIndicator"));
11
+ const ResetButton_1 = require("../ResetButton");
12
+ const SelectedState = ({ resource: { id, type, name, status, squizImage }, isDisabled, onClear, }) => {
13
+ const fileSize = squizImage?.imageVariations?.original?.byteSize;
14
+ const fileWidth = squizImage?.imageVariations?.original?.width;
15
+ const fileHeight = squizImage?.imageVariations?.original?.height;
16
+ return (react_1.default.createElement(react_1.default.Fragment, null,
17
+ react_1.default.createElement(react_1.default.Fragment, null,
18
+ react_1.default.createElement(Icon_1.default, { icon: type.code, resourceSource: "matrix", className: "w-4 h-4 flex self-center" }),
19
+ react_1.default.createElement("div", { className: "justify-self-start self-center" }, name),
20
+ react_1.default.createElement(ResetButton_1.ResetButton, { isDisabled: isDisabled, onClick: onClear })),
21
+ 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" },
22
+ react_1.default.createElement("div", null,
23
+ react_1.default.createElement("dt", { className: "hidden" },
24
+ "Status: ",
25
+ status.name),
26
+ react_1.default.createElement("dd", { className: "flex items-center" },
27
+ react_1.default.createElement(StatusIndicator_1.default, { status: status }))),
28
+ react_1.default.createElement("div", null,
29
+ react_1.default.createElement("dt", { className: "hidden" }, "Asset ID"),
30
+ react_1.default.createElement("dd", { className: "text-gray-700" },
31
+ "#",
32
+ id)),
33
+ fileSize && (react_1.default.createElement("div", null,
34
+ react_1.default.createElement("dt", { className: "hidden" }, "Asset size"),
35
+ react_1.default.createElement("dd", { className: "ml-4 text-gray-600" },
36
+ (0, pretty_bytes_1.default)(fileSize),
37
+ ", ",
38
+ fileWidth,
39
+ " x ",
40
+ fileHeight,
41
+ "px"))))));
42
+ };
43
+ exports.SelectedState = SelectedState;
@@ -34,15 +34,15 @@ const ResourceBreadcrumb_1 = __importDefault(require("../ResourceBreadcrumb/Reso
34
34
  const PreviewPanel_1 = __importDefault(require("../PreviewPanel/PreviewPanel"));
35
35
  const SourceDropdown_1 = __importDefault(require("../SourceDropdown/SourceDropdown"));
36
36
  const useResourcePath_1 = require("../Hooks/useResourcePath");
37
+ const useAsync_1 = require("../Hooks/useAsync");
37
38
  const useChildResources_1 = require("../Hooks/useChildResources");
38
- const useSources_1 = require("../Hooks/useSources");
39
39
  function ResourcePickerContainer({ title, titleAriaProps, allowedTypes, onRequestSources, onRequestChildren, onChange, onClose, }) {
40
40
  const previewModalState = (0, react_stately_1.useOverlayTriggerState)({});
41
41
  const [selectedResource, setSelectedResource] = (0, react_1.useState)(null);
42
42
  const [previewModalOverlayProps, setPreviewModalOverlayProps] = (0, react_1.useState)({});
43
43
  const { source, currentResource, hierarchy, setSource, push, popUntil } = (0, useResourcePath_1.useResourcePath)();
44
- const { sources, isLoading: isSourceLoading, reload: handleSourceReload, error: sourceError, } = (0, useSources_1.useSources)({ onRequestSources });
45
- const { resources, isLoading: isResourcesLoading, reloadResources: handleResourceReload, error: resourceError, } = (0, useChildResources_1.useChildResources)({ source, currentResource, onRequestChildren });
44
+ const { data: sources, isLoading: isSourceLoading, reload: handleSourceReload, error: sourceError, } = (0, useAsync_1.useAsync)({ callback: onRequestSources, defaultValue: [] }, []);
45
+ const { data: resources, isLoading: isResourcesLoading, reload: handleResourceReload, error: resourceError, } = (0, useChildResources_1.useChildResources)({ source, currentResource, onRequestChildren });
46
46
  const handleResourceDrillDown = (0, react_1.useCallback)((resource) => {
47
47
  push(resource);
48
48
  }, [push]);
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.SkeletonListItem = void 0;
7
7
  const react_1 = __importDefault(require("react"));
8
- const SkeletonListItem = () => (react_1.default.createElement("li", { className: "flex items-center p-1 first:mt-0 bg-white border border-b-0 border-grey-200 first:rounded-t-lg last:rounded-b-lg last:border-b" },
8
+ const SkeletonListItem = () => (react_1.default.createElement("li", { className: "flex items-center p-1 first:mt-0 bg-white border-1 border-b-0 border-grey-200 first:rounded-t-lg last:rounded-b-lg last:border-b" },
9
9
  react_1.default.createElement("div", { className: "animate-skeleton-pulse grid grid-cols-[24px_1fr_45px] w-full flex items-center p-4 rounded" },
10
10
  react_1.default.createElement("span", { className: "w-6 h-6 bg-gray-200 rounded-full" }),
11
11
  react_1.default.createElement("div", { className: "w-full d-flex flex-col mx-4" },
@@ -62,7 +62,7 @@ function SourceDropdown({ sources, selectedSource, isLoading, onRootSelect, onSo
62
62
  buttonRef.current?.focus();
63
63
  onRootSelect();
64
64
  };
65
- return (react_1.default.createElement("div", { ...focusWithinProps, ...keyboardProps, className: "relative w-72 border border-2 rounded border-gray-300" },
65
+ return (react_1.default.createElement("div", { ...focusWithinProps, ...keyboardProps, className: "relative w-72 border-2 rounded border-gray-300" },
66
66
  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" },
67
67
  selectedSource && (react_1.default.createElement(react_1.default.Fragment, null,
68
68
  react_1.default.createElement("span", { className: "sr-only" }, "current source "),
@@ -73,8 +73,8 @@ function SourceDropdown({ sources, selectedSource, isLoading, onRootSelect, onSo
73
73
  react_1.default.createElement(Icon_1.default, { icon: 'root', "aria-hidden": true, className: "mr-2.5 h-[20px] w-[20px]" }),
74
74
  "All available sources")),
75
75
  react_1.default.createElement(Icon_1.default, { icon: 'arrow-down', "aria-hidden": true, className: "absolute right-3" })),
76
- 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 border-2 rounded border-gray-300 p-2 ${!isOpen ? 'hidden' : ''}` },
77
- react_1.default.createElement("li", { key: "return-root", className: "flex items-center text-sm font-semibold mb-2 bg-white border rounded border-grey-200" },
76
+ 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 ${!isOpen ? 'hidden' : ''}` },
77
+ 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" },
78
78
  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` },
79
79
  react_1.default.createElement(Icon_1.default, { icon: 'root', "aria-hidden": true, className: "mr-2.5" }),
80
80
  "All available sources")),
@@ -1,6 +1,7 @@
1
1
  import { Status } from '../types';
2
2
  export type StatusIndicatorProps = {
3
+ className?: string;
3
4
  status: Status;
4
5
  };
5
- declare const StatusIndicator: ({ status }: StatusIndicatorProps) => JSX.Element;
6
+ declare const StatusIndicator: ({ className, status }: StatusIndicatorProps) => JSX.Element;
6
7
  export default StatusIndicator;
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const react_1 = __importDefault(require("react"));
7
+ const clsx_1 = __importDefault(require("clsx"));
7
8
  const statusColour = {
8
9
  // Duplicated from the Matrix repository.
9
10
  // src/Api/AssetManagementApi/Constants/AssetStatuses.php - contains a list of possible statuses.
@@ -19,8 +20,8 @@ const statusColour = {
19
20
  safe_editing_pending_approval: '#d688db',
20
21
  safe_edit_approved_to_go_live: '#ffb34a',
21
22
  };
22
- const StatusIndicator = ({ status }) => {
23
+ const StatusIndicator = ({ className, status }) => {
23
24
  const color = statusColour[status.code] || statusColour.unknown;
24
- return (react_1.default.createElement("span", { style: { backgroundColor: color }, className: "block rounded-full w-3 h-3 border border-solid border-black border-opacity-20" }));
25
+ return (react_1.default.createElement("span", { style: { backgroundColor: color }, className: (0, clsx_1.default)('block rounded-full w-3 h-3 border-1 border-solid border-black border-opacity-20', className), title: status.name }));
25
26
  };
26
27
  exports.default = StatusIndicator;
package/lib/index.css CHANGED
@@ -475,6 +475,9 @@
475
475
  .squiz-rb-scope .ml-auto {
476
476
  margin-left: auto;
477
477
  }
478
+ .squiz-rb-scope .mr-1 {
479
+ margin-right: 0.25rem;
480
+ }
478
481
  .squiz-rb-scope .mr-2 {
479
482
  margin-right: 0.5rem;
480
483
  }
@@ -711,6 +714,9 @@
711
714
  .squiz-rb-scope .border {
712
715
  border-width: 1px;
713
716
  }
717
+ .squiz-rb-scope .border-1 {
718
+ border-width: 1px;
719
+ }
714
720
  .squiz-rb-scope .border-2 {
715
721
  border-width: 2px;
716
722
  }
package/lib/index.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { HydratedResourceReference, Resource, ResourceReference, Source } from './types';
2
+ import { ResourceBrowserContext } from './ResourceBrowserContext/ResourceBrowserContext';
2
3
  export type { HydratedResourceReference, Resource, ResourceReference, Source };
3
- export default function ComponentEditorContentBrowser({ modalTitle, allowedTypes, onRequestSources, onRequestChildren, onChange, isDisabled, }: {
4
+ export { ResourceBrowserContext };
5
+ type ResourceBrowserInputProps = {
4
6
  modalTitle: string;
5
- allowedTypes: string[] | undefined;
6
- onRequestSources: () => Promise<Source[]>;
7
- onRequestChildren(source: Source, resource: Resource | null): Promise<Resource[]>;
8
- onRequestResource(reference: ResourceReference): Promise<Resource | null>;
9
- onChange(resource: HydratedResourceReference | null): void;
7
+ allowedTypes?: string[];
10
8
  isDisabled?: boolean;
11
- }): JSX.Element;
9
+ value: ResourceReference | null;
10
+ onChange(resource: HydratedResourceReference | null): void;
11
+ };
12
+ export declare const ResourceBrowserInput: ({ modalTitle, allowedTypes, onChange, value, isDisabled, }: ResourceBrowserInputProps) => JSX.Element;
package/lib/index.js CHANGED
@@ -1,20 +1,42 @@
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
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const react_1 = __importDefault(require("react"));
7
- const ModalTrigger_1 = __importDefault(require("./Modal/ModalTrigger"));
29
+ exports.ResourceBrowserInput = exports.ResourceBrowserContext = void 0;
30
+ const react_1 = __importStar(require("react"));
8
31
  const ResourcePickerContainer_1 = __importDefault(require("./ResourcePickerContainer/ResourcePickerContainer"));
9
- const AdsClickRounded_1 = __importDefault(require("@mui/icons-material/AdsClickRounded"));
10
- const AddCircleOutlineRounded_1 = __importDefault(require("@mui/icons-material/AddCircleOutlineRounded"));
11
- const PhotoLibraryRounded_1 = __importDefault(require("@mui/icons-material/PhotoLibraryRounded"));
12
- const clsx_1 = __importDefault(require("clsx"));
13
- function ComponentEditorContentBrowser({ modalTitle, allowedTypes, onRequestSources, onRequestChildren, onChange, isDisabled, }) {
14
- const isImagePicker = allowedTypes && allowedTypes.length === 1 && allowedTypes.includes('image');
32
+ const ResourceBrowserContext_1 = require("./ResourceBrowserContext/ResourceBrowserContext");
33
+ Object.defineProperty(exports, "ResourceBrowserContext", { enumerable: true, get: function () { return ResourceBrowserContext_1.ResourceBrowserContext; } });
34
+ const ResourcePicker_1 = __importDefault(require("./ResourcePicker/ResourcePicker"));
35
+ const useResource_1 = require("./Hooks/useResource");
36
+ const ResourceBrowserInput = ({ modalTitle, allowedTypes, onChange, value, isDisabled, }) => {
37
+ const { onRequestSources, onRequestChildren, onRequestResource } = (0, react_1.useContext)(ResourceBrowserContext_1.ResourceBrowserContext);
38
+ const { data: resource, error, isLoading } = (0, useResource_1.useResource)({ onRequestResource, reference: value });
15
39
  return (react_1.default.createElement("div", { className: "squiz-rb-scope" },
16
- react_1.default.createElement("div", { className: (0, clsx_1.default)('resource-picker', isDisabled && 'bg-gray-300') },
17
- isImagePicker ? (react_1.default.createElement(PhotoLibraryRounded_1.default, { "aria-hidden": true, className: "w-6 h-6" })) : (react_1.default.createElement(AdsClickRounded_1.default, { "aria-hidden": true, className: "w-6 h-6" })),
18
- react_1.default.createElement(ModalTrigger_1.default, { showLabel: true, label: isImagePicker ? `Choose image` : `Choose asset`, icon: react_1.default.createElement(AddCircleOutlineRounded_1.default, { "aria-hidden": true, className: "!w-4 !h-4" }), isDisabled: isDisabled }, (onClose, titleProps) => (react_1.default.createElement(ResourcePickerContainer_1.default, { title: modalTitle, titleAriaProps: titleProps, allowedTypes: allowedTypes, onClose: onClose, onRequestSources: onRequestSources, onRequestChildren: onRequestChildren, onChange: onChange }))))));
19
- }
20
- exports.default = ComponentEditorContentBrowser;
40
+ react_1.default.createElement(ResourcePicker_1.default, { resource: resource, allowedTypes: allowedTypes, error: error, isLoading: isLoading, isDisabled: isDisabled, onClear: () => onChange(null) }, (onClose, titleProps) => (react_1.default.createElement(ResourcePickerContainer_1.default, { title: modalTitle, titleAriaProps: titleProps, allowedTypes: allowedTypes, onClose: onClose, onRequestSources: onRequestSources, onRequestChildren: onRequestChildren, onChange: onChange })))));
41
+ };
42
+ exports.ResourceBrowserInput = ResourceBrowserInput;