@squiz/resource-browser 1.32.1-alpha.32 → 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 (92) 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/Icons/Generics/Back.d.ts +4 -0
  9. package/lib/Icons/Generics/Back.js +12 -0
  10. package/lib/Icons/Generics/Empty.d.ts +4 -0
  11. package/lib/Icons/Generics/Empty.js +12 -0
  12. package/lib/Icons/Generics/GenericIconMap.d.ts +3 -1
  13. package/lib/Icons/Generics/GenericIconMap.js +2 -0
  14. package/lib/Icons/Generics/index.d.ts +2 -0
  15. package/lib/Icons/Generics/index.js +5 -1
  16. package/lib/Icons/Icon.d.ts +2 -0
  17. package/lib/PreviewPanel/details/MatrixResource.js +2 -1
  18. package/lib/ResourceBrowserContext/ResourceBrowserContext.d.ts +8 -0
  19. package/lib/ResourceBrowserContext/ResourceBrowserContext.js +18 -0
  20. package/lib/ResourceItem/ResourceItem.d.ts +2 -2
  21. package/lib/ResourceItem/ResourceItem.js +6 -5
  22. package/lib/ResourceList/ResourceList.d.ts +3 -2
  23. package/lib/ResourceList/ResourceList.js +4 -3
  24. package/lib/ResourcePicker/ResetButton.d.ts +5 -0
  25. package/lib/ResourcePicker/ResetButton.js +11 -0
  26. package/lib/ResourcePicker/ResourcePicker.d.ts +14 -0
  27. package/lib/ResourcePicker/ResourcePicker.js +26 -0
  28. package/lib/ResourcePicker/States/Error.d.ts +6 -0
  29. package/lib/ResourcePicker/States/Error.js +14 -0
  30. package/lib/ResourcePicker/States/Loading.d.ts +1 -0
  31. package/lib/ResourcePicker/States/Loading.js +11 -0
  32. package/lib/ResourcePicker/States/Selected.d.ts +7 -0
  33. package/lib/ResourcePicker/States/Selected.js +43 -0
  34. package/lib/ResourcePickerContainer/ResourcePickerContainer.js +5 -5
  35. package/lib/ResourceState/ResourceState.d.ts +7 -0
  36. package/lib/{ResourceError/ResourceError.js → ResourceState/ResourceState.js} +7 -7
  37. package/lib/Skeleton/ListItem/SkeletonListItem.js +1 -1
  38. package/lib/SourceDropdown/SourceDropdown.js +3 -3
  39. package/lib/SourceList/SourceList.d.ts +1 -3
  40. package/lib/SourceList/SourceList.js +4 -4
  41. package/lib/StatusIndicator/StatusIndicator.d.ts +2 -1
  42. package/lib/StatusIndicator/StatusIndicator.js +3 -2
  43. package/lib/index.css +9 -3
  44. package/lib/index.d.ts +8 -7
  45. package/lib/index.js +35 -13
  46. package/lib/types.d.ts +67 -0
  47. package/lib/types.js +2 -0
  48. package/package.json +3 -3
  49. package/src/Hooks/useAsync.spec.ts +106 -0
  50. package/src/Hooks/useAsync.ts +62 -0
  51. package/src/Hooks/useChildResources.spec.ts +2 -23
  52. package/src/Hooks/useChildResources.ts +9 -34
  53. package/src/Hooks/useResource.spec.ts +32 -0
  54. package/src/Hooks/useResource.ts +19 -0
  55. package/src/Hooks/useSources.spec.ts +2 -14
  56. package/src/Hooks/useSources.ts +3 -26
  57. package/src/Icons/Generics/Back.tsx +13 -0
  58. package/src/Icons/Generics/Empty.tsx +13 -0
  59. package/src/Icons/Generics/GenericIconMap.ts +3 -1
  60. package/src/Icons/Generics/index.tsx +2 -0
  61. package/src/PreviewPanel/details/MatrixResource.tsx +1 -2
  62. package/src/ResourceBrowserContext/ResourceBrowserContext.spec.tsx +32 -0
  63. package/src/ResourceBrowserContext/ResourceBrowserContext.ts +20 -0
  64. package/src/ResourceItem/ResourceItem.tsx +7 -5
  65. package/src/ResourceList/ResourceList.spec.tsx +6 -0
  66. package/src/ResourceList/ResourceList.tsx +12 -4
  67. package/src/ResourcePicker/ResetButton.tsx +7 -1
  68. package/src/ResourcePicker/ResourcePicker.spec.tsx +8 -4
  69. package/src/ResourcePicker/ResourcePicker.stories.tsx +2 -2
  70. package/src/ResourcePicker/ResourcePicker.tsx +21 -12
  71. package/src/ResourcePicker/States/Error.tsx +9 -3
  72. package/src/ResourcePicker/States/Selected.tsx +9 -4
  73. package/src/ResourcePickerContainer/ResourcePickerContainer.spec.tsx +1 -1
  74. package/src/ResourcePickerContainer/ResourcePickerContainer.tsx +6 -7
  75. package/src/{ResourceError/ResourceError.spec.tsx → ResourceState/ResourceState.spec.tsx} +6 -5
  76. package/src/ResourceState/ResourceState.stories.tsx +24 -0
  77. package/src/ResourceState/ResourceState.tsx +31 -0
  78. package/src/Skeleton/ListItem/SkeletonListItem.tsx +1 -1
  79. package/src/SourceDropdown/SourceDropdown.tsx +3 -3
  80. package/src/SourceList/SourceList.spec.tsx +1 -40
  81. package/src/SourceList/SourceList.tsx +2 -9
  82. package/src/StatusIndicator/StatusIndicator.tsx +5 -2
  83. package/src/__mocks__/StorybookHelpers.ts +18 -13
  84. package/src/index.spec.tsx +4 -4
  85. package/src/index.stories.tsx +15 -15
  86. package/src/index.tsx +39 -54
  87. package/src/{types.d.ts → types.ts} +1 -1
  88. package/tailwind.config.cjs +5 -0
  89. package/lib/Hooks/useSources.d.ts +0 -16
  90. package/lib/Hooks/useSources.js +0 -31
  91. package/lib/ResourceError/ResourceError.d.ts +0 -6
  92. package/src/ResourceError/ResourceError.tsx +0 -27
@@ -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;
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export default function Back({ isDecorative, ...props }: {
3
+ isDecorative: boolean;
4
+ } & React.SVGProps<SVGSVGElement>): JSX.Element;
@@ -0,0 +1,12 @@
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
+ function Back({ isDecorative, ...props }) {
8
+ return (react_1.default.createElement("svg", { width: "17", height: "16", viewBox: "0 0 17 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props },
9
+ react_1.default.createElement("path", { d: "M15.2912 7.00501H4.12124L9.00124 2.12501C9.39124 1.73501 9.39124 1.09501 9.00124 0.705006C8.61124 0.315006 7.98124 0.315006 7.59124 0.705006L1.00124 7.29501C0.61124 7.68501 0.61124 8.31501 1.00124 8.70501L7.59124 15.295C7.98124 15.685 8.61124 15.685 9.00124 15.295C9.39124 14.905 9.39124 14.275 9.00124 13.885L4.12124 9.00501H15.2912C15.8412 9.00501 16.2912 8.55501 16.2912 8.00501C16.2912 7.45501 15.8412 7.00501 15.2912 7.00501Z", fill: "#3D3D3D" }),
10
+ !isDecorative && react_1.default.createElement("title", null, "back icon")));
11
+ }
12
+ exports.default = Back;
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export default function Empty({ isDecorative, ...props }: {
3
+ isDecorative: boolean;
4
+ } & React.SVGProps<SVGSVGElement>): JSX.Element;
@@ -0,0 +1,12 @@
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
+ function Empty({ isDecorative, ...props }) {
8
+ return (react_1.default.createElement("svg", { width: "42", height: "42", viewBox: "0 0 42 42", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props },
9
+ react_1.default.createElement("path", { d: "M1.3925 3.82749C0.612495 4.60749 0.612495 5.88749 1.3925 6.66749L4.5125 9.78749C2.0125 13.5475 0.752495 18.1875 1.3325 23.1675C2.37249 32.2475 9.75249 39.6275 18.8325 40.6675C23.8125 41.2475 28.4525 39.9875 32.2125 37.4875L35.3325 40.6075C36.1125 41.3875 37.3725 41.3875 38.1525 40.6075C38.9325 39.8275 38.9325 38.5675 38.1525 37.7875L4.21249 3.82749C3.4325 3.04749 2.17249 3.04749 1.3925 3.82749ZM21.1925 36.8075C12.3725 36.8075 5.19249 29.6275 5.19249 20.8075C5.19249 17.8475 6.01249 15.0875 7.43249 12.6875L29.3125 34.5675C26.9125 35.9875 24.1525 36.8075 21.1925 36.8075ZM13.0725 7.04749L10.1725 4.12749C13.3325 2.0275 17.1125 0.807495 21.1925 0.807495C32.2325 0.807495 41.1925 9.76749 41.1925 20.8075C41.1925 24.8875 39.9725 28.6675 37.8725 31.8275L34.9525 28.9075C36.3725 26.5275 37.1925 23.7675 37.1925 20.8075C37.1925 11.9875 30.0125 4.80749 21.1925 4.80749C18.2325 4.80749 15.4725 5.62749 13.0725 7.04749Z", fill: "#949494" }),
10
+ !isDecorative && react_1.default.createElement("title", null, "empty icon")));
11
+ }
12
+ exports.default = Empty;
@@ -1,4 +1,4 @@
1
- import { ArrowRight, ArrowDown, Selected, Root, ResourceSelect, Close, Error, Retry } from '.';
1
+ import { ArrowRight, ArrowDown, Selected, Root, ResourceSelect, Close, Error, Retry, Empty, Back } from '.';
2
2
  declare const GenericIconMap: {
3
3
  'arrow-right': typeof ArrowRight;
4
4
  'arrow-down': typeof ArrowDown;
@@ -8,5 +8,7 @@ declare const GenericIconMap: {
8
8
  close: typeof Close;
9
9
  error: typeof Error;
10
10
  retry: typeof Retry;
11
+ empty: typeof Empty;
12
+ back: typeof Back;
11
13
  };
12
14
  export default GenericIconMap;
@@ -11,6 +11,8 @@ const GenericIconMap = {
11
11
  close: _1.Close,
12
12
  error: _1.Error,
13
13
  retry: _1.Retry,
14
+ empty: _1.Empty,
15
+ back: _1.Back,
14
16
  };
15
17
  // Export our map
16
18
  exports.default = GenericIconMap;
@@ -6,3 +6,5 @@ export { default as ResourceSelect } from './ResourceSelect';
6
6
  export { default as Close } from './Close';
7
7
  export { default as Error } from './Error';
8
8
  export { default as Retry } from './Retry';
9
+ export { default as Empty } from './Empty';
10
+ export { default as Back } from './Back';
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Retry = exports.Error = exports.Close = exports.ResourceSelect = exports.Root = exports.Selected = exports.ArrowDown = exports.ArrowRight = void 0;
6
+ exports.Back = exports.Empty = exports.Retry = exports.Error = exports.Close = exports.ResourceSelect = exports.Root = exports.Selected = exports.ArrowDown = exports.ArrowRight = void 0;
7
7
  // Exports all icons from the Generics folder
8
8
  var ArrowRight_1 = require("./ArrowRight");
9
9
  Object.defineProperty(exports, "ArrowRight", { enumerable: true, get: function () { return __importDefault(ArrowRight_1).default; } });
@@ -21,3 +21,7 @@ var Error_1 = require("./Error");
21
21
  Object.defineProperty(exports, "Error", { enumerable: true, get: function () { return __importDefault(Error_1).default; } });
22
22
  var Retry_1 = require("./Retry");
23
23
  Object.defineProperty(exports, "Retry", { enumerable: true, get: function () { return __importDefault(Retry_1).default; } });
24
+ var Empty_1 = require("./Empty");
25
+ Object.defineProperty(exports, "Empty", { enumerable: true, get: function () { return __importDefault(Empty_1).default; } });
26
+ var Back_1 = require("./Back");
27
+ Object.defineProperty(exports, "Back", { enumerable: true, get: function () { return __importDefault(Back_1).default; } });
@@ -9,6 +9,8 @@ export declare const iconSources: {
9
9
  close: typeof import("./Generics").Close;
10
10
  error: typeof import("./Generics").Error;
11
11
  retry: typeof import("./Generics").Retry;
12
+ empty: typeof import("./Generics").Empty;
13
+ back: typeof import("./Generics").Back;
12
14
  };
13
15
  matrix: {
14
16
  audio_file: typeof import("./MatrixResources").Audio;
@@ -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
+ });
@@ -5,10 +5,10 @@ interface ResourceItem<T> {
5
5
  selected?: boolean;
6
6
  label: string;
7
7
  type: string;
8
- childCount: number;
8
+ childCount?: number;
9
9
  previewModalState: OverlayTriggerState;
10
10
  onSelect: (node: T, overlayProps: DOMAttributes<FocusableElement>) => void;
11
- onDrillDown: (node: T) => void;
11
+ onDrillDown?: (node: T) => void;
12
12
  className: string;
13
13
  allowedTypes?: string[] | undefined;
14
14
  }
@@ -11,15 +11,16 @@ 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}` },
15
- react_1.default.createElement(ModalOpeningButton_1.default, { type: "button", ...triggerProps, isDisabled: isDisabled, onPress: () => onSelect(item, overlayProps), className: `
16
- relative grow flex items-center px-4 py-2 rounded outline-0 ${selected ? 'bg-blue-100 text-blue-400' : ''} ${childCount > 0 ? 'mr-2' : ''} ${isDisabled ? 'font-normal text-gray-600 cursor-not-allowed' : 'hover:bg-gray-50 focus:bg-gray-50'}
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
+ 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
+ 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 },
18
18
  react_1.default.createElement(Icon_1.default, { icon: type, resourceSource: "matrix", "aria-label": type, className: `mr-4 shrink-0 ${isDisabled && 'opacity-40'}` }),
19
19
  react_1.default.createElement("span", { className: `relative flex items-center ${selected ? 'mr-8' : ''}` },
20
20
  react_1.default.createElement("span", { className: "line-clamp-2 text-left break-word" }, label),
21
- selected && react_1.default.createElement(Icon_1.default, { icon: 'selected', "aria-label": "selected", className: "absolute -right-8" }))),
22
- childCount > 0 && (react_1.default.createElement("button", { type: "button", "aria-label": `Drill down to ${label} children`, onClick: () => onDrillDown(item), className: `relative shrink-0 flex items-center p-4 rounded outline-0 before:w-px before:h-[calc(100%-0.75rem)] before:bg-gray-200 before:absolute before:top-1.5 before:-left-1 hover:bg-gray-50 focus:bg-gray-50` },
21
+ selected && react_1.default.createElement(Icon_1.default, { icon: 'selected', "aria-label": "selected", className: "absolute -right-8" })),
22
+ childCount === undefined && react_1.default.createElement(Icon_1.default, { icon: 'arrow-right', className: "absolute right-5" })),
23
+ childCount !== undefined && childCount > 0 && onDrillDown && (react_1.default.createElement("button", { type: "button", "aria-label": `Drill down to ${label} children`, onClick: () => onDrillDown(item), className: `relative shrink-0 flex items-center p-4 rounded outline-0 before:w-px before:h-[calc(100%-0.75rem)] before:bg-gray-200 before:absolute before:top-1.5 before:-left-1 hover:bg-gray-50 focus:bg-gray-50` },
23
24
  react_1.default.createElement("span", { className: "ml-auto flex items-center" },
24
25
  react_1.default.createElement("span", { className: "truncate w-14 text-right", title: String(childCount) }, childCount),
25
26
  react_1.default.createElement(Icon_1.default, { icon: 'arrow-right', className: "ml-1" }))))));
@@ -9,8 +9,9 @@ export interface ResourceListProps {
9
9
  onResourceSelect: (resource: Resource, overlayProps: DOMAttributes<FocusableElement>) => void;
10
10
  onResourceDrillDown: (resource: Resource) => void;
11
11
  allowedTypes?: string[] | undefined;
12
- error: Error | null;
12
+ handleReturnToRoot: () => void;
13
13
  handleReload: () => void;
14
+ error: Error | null;
14
15
  }
15
- declare const ResourceList: ({ resources, selectedResource, previewModalState, isLoading, onResourceSelect, onResourceDrillDown, allowedTypes, error, handleReload, }: ResourceListProps) => JSX.Element;
16
+ declare const ResourceList: ({ resources, selectedResource, previewModalState, isLoading, onResourceSelect, onResourceDrillDown, allowedTypes, handleReturnToRoot, handleReload, error, }: ResourceListProps) => JSX.Element;
16
17
  export default ResourceList;
@@ -29,8 +29,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  const react_1 = __importStar(require("react"));
30
30
  const ResourceItem_1 = __importDefault(require("../ResourceItem/ResourceItem"));
31
31
  const SkeletonListItem_1 = require("../Skeleton/ListItem/SkeletonListItem");
32
- const ResourceError_1 = __importDefault(require("../ResourceError/ResourceError"));
33
- const ResourceList = function ({ resources, selectedResource, previewModalState, isLoading, onResourceSelect, onResourceDrillDown, allowedTypes, error, handleReload, }) {
32
+ const ResourceState_1 = __importDefault(require("../ResourceState/ResourceState"));
33
+ const ResourceList = function ({ resources, selectedResource, previewModalState, isLoading, onResourceSelect, onResourceDrillDown, allowedTypes, handleReturnToRoot, handleReload, error, }) {
34
34
  const listRef = (0, react_1.useRef)(null);
35
35
  // When resources change, because we are on a new page, reset focus to the list
36
36
  (0, react_1.useEffect)(() => {
@@ -44,7 +44,8 @@ const ResourceList = function ({ resources, selectedResource, previewModalState,
44
44
  isLoading && (react_1.default.createElement(react_1.default.Fragment, null, [...Array(8)].map((_item, index) => {
45
45
  return react_1.default.createElement(SkeletonListItem_1.SkeletonListItem, { key: index });
46
46
  }))),
47
- !isLoading && error && react_1.default.createElement(ResourceError_1.default, { errorMessage: error.message, handleReload: handleReload }),
47
+ !isLoading && error && react_1.default.createElement(ResourceState_1.default, { state: "error", message: error.message, handleReload: handleReload }),
48
+ !isLoading && !error && resources.length === 0 && (react_1.default.createElement(ResourceState_1.default, { state: "empty", handleReload: handleReturnToRoot })),
48
49
  !isLoading &&
49
50
  !error &&
50
51
  resources.map((resource) => {
@@ -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]);
@@ -79,8 +79,8 @@ function ResourcePickerContainer({ title, titleAriaProps, allowedTypes, onReques
79
79
  react_1.default.createElement("div", { className: "overflow-y-scroll flex-1 grow-[3] border-r border-gray-300" },
80
80
  react_1.default.createElement("h3", { className: "sr-only" }, "Resource List"),
81
81
  hierarchy.length > 0 && (react_1.default.createElement(ResourceBreadcrumb_1.default, { hierarchy: hierarchy, onBreadcrumbSelect: popUntil, onReturnToRoot: handleReturnToRoot })),
82
- !source && (react_1.default.createElement(SourceList_1.default, { sources: sources, previewModalState: previewModalState, isLoading: isSourceLoading, onSourceSelect: handleSourceDrilldown, onSourceDrillDown: handleSourceDrilldown, allowedTypes: allowedTypes, handleReload: handleSourceReload, error: sourceError })),
83
- source && (react_1.default.createElement(ResourceList_1.default, { previewModalState: previewModalState, resources: resources, selectedResource: selectedResource, isLoading: isResourcesLoading, onResourceSelect: handleResourceSelected, onResourceDrillDown: handleResourceDrillDown, allowedTypes: allowedTypes, handleReload: handleResourceReload, error: resourceError }))),
82
+ !source && (react_1.default.createElement(SourceList_1.default, { sources: sources, previewModalState: previewModalState, isLoading: isSourceLoading, onSourceSelect: handleSourceDrilldown, handleReload: handleSourceReload, error: sourceError })),
83
+ source && (react_1.default.createElement(ResourceList_1.default, { previewModalState: previewModalState, resources: resources, selectedResource: selectedResource, isLoading: isResourcesLoading, onResourceSelect: handleResourceSelected, onResourceDrillDown: handleResourceDrillDown, allowedTypes: allowedTypes, handleReturnToRoot: handleReturnToRoot, handleReload: handleResourceReload, error: resourceError }))),
84
84
  react_1.default.createElement(PreviewPanel_1.default, { resource: selectedResource, modalState: previewModalState, previewModalOverlayProps: previewModalOverlayProps, allowedTypes: allowedTypes, onSelect: handleDetailSelect, onClose: handleDetailClose }))));
85
85
  }
86
86
  exports.default = ResourcePickerContainer;
@@ -0,0 +1,7 @@
1
+ interface ResourceState {
2
+ state: 'error' | 'empty';
3
+ message?: string;
4
+ handleReload: () => void;
5
+ }
6
+ declare const ResourceState: ({ state, message, handleReload }: ResourceState) => JSX.Element;
7
+ export default ResourceState;
@@ -5,12 +5,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const react_1 = __importDefault(require("react"));
7
7
  const Icon_1 = __importDefault(require("../Icons/Icon"));
8
- const ResourceError = function ({ errorMessage, handleReload }) {
8
+ const ResourceState = function ({ state, message, handleReload }) {
9
9
  return (react_1.default.createElement("div", { className: "flex flex-col items-center rounded-lg py-8 bg-white h-204 gap-3" },
10
- react_1.default.createElement(Icon_1.default, { icon: 'error', "aria-hidden": true }),
11
- react_1.default.createElement("span", { className: "text-md text-gray-800 font-semibold leading-5" }, errorMessage),
12
- react_1.default.createElement("button", { type: "button", onClick: handleReload, className: "flex flex-row items-center justify-center gap-3 bg-black bg-opacity-10 w-[119px] h-9 mt-3 rounded text-md font-bold text-gray-700" },
13
- react_1.default.createElement(Icon_1.default, { icon: 'retry', "aria-hidden": true }),
14
- " Try again")));
10
+ react_1.default.createElement(Icon_1.default, { icon: state, "aria-hidden": true }),
11
+ react_1.default.createElement("span", { className: "text-md text-gray-800 font-semibold leading-5" }, state === 'empty' ? 'There are no items to display' : message),
12
+ react_1.default.createElement("button", { type: "button", onClick: handleReload, className: "flex flex-row items-center justify-center gap-3 bg-black bg-opacity-10 h-9 mt-3 rounded text-md font-bold text-gray-700 py-2 px-3" },
13
+ react_1.default.createElement(Icon_1.default, { icon: state === 'empty' ? 'back' : 'retry', "aria-hidden": true }),
14
+ state === 'empty' ? 'Back to source list' : 'Try again')));
15
15
  };
16
- exports.default = ResourceError;
16
+ exports.default = ResourceState;