@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.
- package/lib/Hooks/useAsync.d.ts +21 -0
- package/lib/Hooks/useAsync.js +53 -0
- package/lib/Hooks/useChildResources.d.ts +3 -7
- package/lib/Hooks/useChildResources.js +5 -29
- package/lib/Hooks/useResource.d.ts +15 -0
- package/lib/Hooks/useResource.js +12 -0
- package/lib/Hooks/useResourcePath.d.ts +1 -1
- package/lib/Icons/Generics/Back.d.ts +4 -0
- package/lib/Icons/Generics/Back.js +12 -0
- package/lib/Icons/Generics/Empty.d.ts +4 -0
- package/lib/Icons/Generics/Empty.js +12 -0
- package/lib/Icons/Generics/GenericIconMap.d.ts +3 -1
- package/lib/Icons/Generics/GenericIconMap.js +2 -0
- package/lib/Icons/Generics/index.d.ts +2 -0
- package/lib/Icons/Generics/index.js +5 -1
- package/lib/Icons/Icon.d.ts +2 -0
- package/lib/PreviewPanel/details/MatrixResource.js +2 -1
- package/lib/ResourceBrowserContext/ResourceBrowserContext.d.ts +8 -0
- package/lib/ResourceBrowserContext/ResourceBrowserContext.js +18 -0
- package/lib/ResourceItem/ResourceItem.d.ts +2 -2
- package/lib/ResourceItem/ResourceItem.js +6 -5
- package/lib/ResourceList/ResourceList.d.ts +3 -2
- package/lib/ResourceList/ResourceList.js +4 -3
- package/lib/ResourcePicker/ResetButton.d.ts +5 -0
- package/lib/ResourcePicker/ResetButton.js +11 -0
- package/lib/ResourcePicker/ResourcePicker.d.ts +14 -0
- package/lib/ResourcePicker/ResourcePicker.js +26 -0
- package/lib/ResourcePicker/States/Error.d.ts +6 -0
- package/lib/ResourcePicker/States/Error.js +14 -0
- package/lib/ResourcePicker/States/Loading.d.ts +1 -0
- package/lib/ResourcePicker/States/Loading.js +11 -0
- package/lib/ResourcePicker/States/Selected.d.ts +7 -0
- package/lib/ResourcePicker/States/Selected.js +43 -0
- package/lib/ResourcePickerContainer/ResourcePickerContainer.js +5 -5
- package/lib/ResourceState/ResourceState.d.ts +7 -0
- package/lib/{ResourceError/ResourceError.js → ResourceState/ResourceState.js} +7 -7
- package/lib/Skeleton/ListItem/SkeletonListItem.js +1 -1
- package/lib/SourceDropdown/SourceDropdown.js +3 -3
- package/lib/SourceList/SourceList.d.ts +1 -3
- package/lib/SourceList/SourceList.js +4 -4
- package/lib/StatusIndicator/StatusIndicator.d.ts +2 -1
- package/lib/StatusIndicator/StatusIndicator.js +3 -2
- package/lib/index.css +9 -3
- package/lib/index.d.ts +8 -7
- package/lib/index.js +35 -13
- package/lib/types.d.ts +67 -0
- package/lib/types.js +2 -0
- package/package.json +3 -3
- package/src/Hooks/useAsync.spec.ts +106 -0
- package/src/Hooks/useAsync.ts +62 -0
- package/src/Hooks/useChildResources.spec.ts +2 -23
- package/src/Hooks/useChildResources.ts +9 -34
- package/src/Hooks/useResource.spec.ts +32 -0
- package/src/Hooks/useResource.ts +19 -0
- package/src/Hooks/useSources.spec.ts +2 -14
- package/src/Hooks/useSources.ts +3 -26
- package/src/Icons/Generics/Back.tsx +13 -0
- package/src/Icons/Generics/Empty.tsx +13 -0
- package/src/Icons/Generics/GenericIconMap.ts +3 -1
- package/src/Icons/Generics/index.tsx +2 -0
- package/src/PreviewPanel/details/MatrixResource.tsx +1 -2
- package/src/ResourceBrowserContext/ResourceBrowserContext.spec.tsx +32 -0
- package/src/ResourceBrowserContext/ResourceBrowserContext.ts +20 -0
- package/src/ResourceItem/ResourceItem.tsx +7 -5
- package/src/ResourceList/ResourceList.spec.tsx +6 -0
- package/src/ResourceList/ResourceList.tsx +12 -4
- package/src/ResourcePicker/ResetButton.tsx +7 -1
- package/src/ResourcePicker/ResourcePicker.spec.tsx +8 -4
- package/src/ResourcePicker/ResourcePicker.stories.tsx +2 -2
- package/src/ResourcePicker/ResourcePicker.tsx +21 -12
- package/src/ResourcePicker/States/Error.tsx +9 -3
- package/src/ResourcePicker/States/Selected.tsx +9 -4
- package/src/ResourcePickerContainer/ResourcePickerContainer.spec.tsx +1 -1
- package/src/ResourcePickerContainer/ResourcePickerContainer.tsx +6 -7
- package/src/{ResourceError/ResourceError.spec.tsx → ResourceState/ResourceState.spec.tsx} +6 -5
- package/src/ResourceState/ResourceState.stories.tsx +24 -0
- package/src/ResourceState/ResourceState.tsx +31 -0
- package/src/Skeleton/ListItem/SkeletonListItem.tsx +1 -1
- package/src/SourceDropdown/SourceDropdown.tsx +3 -3
- package/src/SourceList/SourceList.spec.tsx +1 -40
- package/src/SourceList/SourceList.tsx +2 -9
- package/src/StatusIndicator/StatusIndicator.tsx +5 -2
- package/src/__mocks__/StorybookHelpers.ts +18 -13
- package/src/index.spec.tsx +4 -4
- package/src/index.stories.tsx +15 -15
- package/src/index.tsx +39 -54
- package/src/{types.d.ts → types.ts} +1 -1
- package/tailwind.config.cjs +5 -0
- package/lib/Hooks/useSources.d.ts +0 -16
- package/lib/Hooks/useSources.js +0 -31
- package/lib/ResourceError/ResourceError.d.ts +0 -6
- package/src/ResourceError/ResourceError.tsx +0 -27
@@ -1,7 +1,7 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
|
3
3
|
export const SkeletonListItem = () => (
|
4
|
-
<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">
|
4
|
+
<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">
|
5
5
|
<div className="animate-skeleton-pulse grid grid-cols-[24px_1fr_45px] w-full flex items-center p-4 rounded">
|
6
6
|
<span className="w-6 h-6 bg-gray-200 rounded-full" />
|
7
7
|
<div className="w-full d-flex flex-col mx-4">
|
@@ -56,7 +56,7 @@ export default function SourceDropdown({
|
|
56
56
|
};
|
57
57
|
|
58
58
|
return (
|
59
|
-
<div {...focusWithinProps} {...keyboardProps} className="relative w-72 border
|
59
|
+
<div {...focusWithinProps} {...keyboardProps} className="relative w-72 border-2 rounded border-gray-300">
|
60
60
|
<button
|
61
61
|
ref={buttonRef}
|
62
62
|
type="button"
|
@@ -92,13 +92,13 @@ export default function SourceDropdown({
|
|
92
92
|
<ul
|
93
93
|
id={`${uniqueId}-button-menu`}
|
94
94
|
aria-hidden={!isOpen}
|
95
|
-
className={`absolute z-50 top-[calc(100%+5px)] -left-0.5 w-[calc(100%+4px)] bg-gray-100 border
|
95
|
+
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 ${
|
96
96
|
!isOpen ? 'hidden' : ''
|
97
97
|
}`}
|
98
98
|
>
|
99
99
|
<li
|
100
100
|
key="return-root"
|
101
|
-
className="flex items-center text-sm font-semibold mb-2 bg-white border rounded border-grey-200"
|
101
|
+
className="flex items-center text-sm font-semibold mb-2 bg-white border-1 rounded border-grey-200"
|
102
102
|
>
|
103
103
|
<button
|
104
104
|
type="button"
|
@@ -80,7 +80,6 @@ describe('SourceList', () => {
|
|
80
80
|
previewModalState={previewModalState}
|
81
81
|
isLoading={true}
|
82
82
|
onSourceSelect={() => {}}
|
83
|
-
onSourceDrillDown={() => {}}
|
84
83
|
error={null}
|
85
84
|
handleReload={reload}
|
86
85
|
/>
|
@@ -106,7 +105,6 @@ describe('SourceList', () => {
|
|
106
105
|
previewModalState={previewModalState}
|
107
106
|
isLoading={false}
|
108
107
|
onSourceSelect={() => {}}
|
109
|
-
onSourceDrillDown={() => {}}
|
110
108
|
error={null}
|
111
109
|
handleReload={reload}
|
112
110
|
/>
|
@@ -133,7 +131,6 @@ describe('SourceList', () => {
|
|
133
131
|
previewModalState={previewModalState}
|
134
132
|
isLoading={false}
|
135
133
|
onSourceSelect={() => {}}
|
136
|
-
onSourceDrillDown={() => {}}
|
137
134
|
error={null}
|
138
135
|
handleReload={reload}
|
139
136
|
/>
|
@@ -159,7 +156,6 @@ describe('SourceList', () => {
|
|
159
156
|
previewModalState={previewModalState}
|
160
157
|
isLoading={false}
|
161
158
|
onSourceSelect={() => {}}
|
162
|
-
onSourceDrillDown={() => {}}
|
163
159
|
error={null}
|
164
160
|
handleReload={reload}
|
165
161
|
/>
|
@@ -192,7 +188,6 @@ describe('SourceList', () => {
|
|
192
188
|
previewModalState={previewModalState}
|
193
189
|
isLoading={false}
|
194
190
|
onSourceSelect={onSourceSelect}
|
195
|
-
onSourceDrillDown={() => {}}
|
196
191
|
error={null}
|
197
192
|
handleReload={reload}
|
198
193
|
/>
|
@@ -202,7 +197,7 @@ describe('SourceList', () => {
|
|
202
197
|
);
|
203
198
|
|
204
199
|
const user = userEvent.setup();
|
205
|
-
const itemButton = screen.getByRole('button', { name: '
|
200
|
+
const itemButton = screen.getByRole('button', { name: 'Drill down to Node 1 children' });
|
206
201
|
user.click(itemButton);
|
207
202
|
|
208
203
|
await waitFor(() => {
|
@@ -217,39 +212,6 @@ describe('SourceList', () => {
|
|
217
212
|
});
|
218
213
|
});
|
219
214
|
|
220
|
-
it('Clicking node child count triggers correct onSourceDrillDown', async () => {
|
221
|
-
const onSourceDrillDown = jest.fn();
|
222
|
-
const reload = jest.fn();
|
223
|
-
|
224
|
-
render(
|
225
|
-
<SourceListTestWrapper
|
226
|
-
constructFunction={(previewModalState) => {
|
227
|
-
return (
|
228
|
-
<SourceList
|
229
|
-
sources={sources}
|
230
|
-
previewModalState={previewModalState}
|
231
|
-
isLoading={false}
|
232
|
-
onSourceSelect={() => {}}
|
233
|
-
onSourceDrillDown={onSourceDrillDown}
|
234
|
-
error={null}
|
235
|
-
handleReload={reload}
|
236
|
-
/>
|
237
|
-
);
|
238
|
-
}}
|
239
|
-
/>,
|
240
|
-
);
|
241
|
-
|
242
|
-
const user = userEvent.setup();
|
243
|
-
user.click(screen.getByRole('button', { name: 'Drill down to Node 1 children' }));
|
244
|
-
|
245
|
-
await waitFor(() => {
|
246
|
-
expect(onSourceDrillDown).toHaveBeenCalledWith({
|
247
|
-
source: sources[0],
|
248
|
-
resource: sources[0].nodes[0],
|
249
|
-
});
|
250
|
-
});
|
251
|
-
});
|
252
|
-
|
253
215
|
it('Renders error state when an error occurs loading source list', async () => {
|
254
216
|
const reload = jest.fn();
|
255
217
|
|
@@ -262,7 +224,6 @@ describe('SourceList', () => {
|
|
262
224
|
previewModalState={previewModalState}
|
263
225
|
isLoading={false}
|
264
226
|
onSourceSelect={() => {}}
|
265
|
-
onSourceDrillDown={() => {}}
|
266
227
|
error={new Error('Source list error!')}
|
267
228
|
handleReload={reload}
|
268
229
|
/>
|
@@ -7,15 +7,13 @@ import { Source, ScopedSource } from '../types';
|
|
7
7
|
import { SkeletonList } from '../Skeleton/List/SkeletonList';
|
8
8
|
import clsx from 'clsx';
|
9
9
|
import { useCategorisedSources } from '../Hooks/useCategorisedSources';
|
10
|
-
import
|
10
|
+
import ResourceState from '../ResourceState/ResourceState';
|
11
11
|
|
12
12
|
export interface SourceListProps {
|
13
13
|
sources: Source[];
|
14
14
|
previewModalState: OverlayTriggerState;
|
15
15
|
isLoading: boolean;
|
16
16
|
onSourceSelect: (node: ScopedSource, overlayProps: DOMAttributes<FocusableElement>) => void;
|
17
|
-
onSourceDrillDown: (node: ScopedSource) => void;
|
18
|
-
allowedTypes?: string[] | undefined;
|
19
17
|
handleReload: () => void;
|
20
18
|
error: Error | null;
|
21
19
|
}
|
@@ -25,8 +23,6 @@ const SourceList = function ({
|
|
25
23
|
previewModalState,
|
26
24
|
isLoading,
|
27
25
|
onSourceSelect,
|
28
|
-
onSourceDrillDown,
|
29
|
-
allowedTypes,
|
30
26
|
handleReload,
|
31
27
|
error,
|
32
28
|
}: SourceListProps) {
|
@@ -59,7 +55,7 @@ const SourceList = function ({
|
|
59
55
|
</>
|
60
56
|
)}
|
61
57
|
|
62
|
-
{!isLoading && error && <
|
58
|
+
{!isLoading && error && <ResourceState state="error" message={error.message} handleReload={handleReload} />}
|
63
59
|
|
64
60
|
{!isLoading &&
|
65
61
|
!error &&
|
@@ -78,12 +74,9 @@ const SourceList = function ({
|
|
78
74
|
item={{ source, resource }}
|
79
75
|
label={resource?.name || source.name}
|
80
76
|
type={resource?.type.code || 'folder'}
|
81
|
-
childCount={resource?.childCount || 0}
|
82
77
|
previewModalState={previewModalState}
|
83
78
|
onSelect={onSourceSelect}
|
84
|
-
onDrillDown={onSourceDrillDown}
|
85
79
|
className="mt-3 rounded-lg"
|
86
|
-
allowedTypes={allowedTypes}
|
87
80
|
/>
|
88
81
|
);
|
89
82
|
})}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import React from 'react';
|
2
|
+
import clsx from 'clsx';
|
2
3
|
import { Status } from '../types';
|
3
4
|
|
4
5
|
const statusColour = {
|
@@ -18,16 +19,18 @@ const statusColour = {
|
|
18
19
|
};
|
19
20
|
|
20
21
|
export type StatusIndicatorProps = {
|
22
|
+
className?: string;
|
21
23
|
status: Status;
|
22
24
|
};
|
23
25
|
|
24
|
-
const StatusIndicator = ({ status }: StatusIndicatorProps) => {
|
26
|
+
const StatusIndicator = ({ className, status }: StatusIndicatorProps) => {
|
25
27
|
const color = statusColour[status.code as keyof typeof statusColour] || statusColour.unknown;
|
26
28
|
|
27
29
|
return (
|
28
30
|
<span
|
29
31
|
style={{ backgroundColor: color }}
|
30
|
-
className=
|
32
|
+
className={clsx('block rounded-full w-3 h-3 border-1 border-solid border-black border-opacity-20', className)}
|
33
|
+
title={status.name}
|
31
34
|
></span>
|
32
35
|
);
|
33
36
|
};
|
@@ -18,15 +18,15 @@ export const createResourceBrowserCallbacks = ({
|
|
18
18
|
return {
|
19
19
|
onRequestSources: () => {
|
20
20
|
return new Promise((resolve, reject) => {
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
if (!sourceIsLoading) {
|
22
|
+
setTimeout(() => {
|
23
|
+
if (error && Math.random() > 0.5) {
|
24
|
+
reject(new Error(error));
|
25
|
+
} else {
|
26
26
|
resolve(sampleSources);
|
27
27
|
}
|
28
|
-
}
|
29
|
-
}
|
28
|
+
}, delay);
|
29
|
+
}
|
30
30
|
});
|
31
31
|
},
|
32
32
|
onRequestChildren: (source: Source, resource: Resource | null) => {
|
@@ -36,8 +36,7 @@ export const createResourceBrowserCallbacks = ({
|
|
36
36
|
if (error && Math.random() > 0.5) {
|
37
37
|
reject(new Error(error));
|
38
38
|
} else {
|
39
|
-
|
40
|
-
resolve(children);
|
39
|
+
resolve(((resource as any)?._children || sampleResources) as Resource[] | undefined);
|
41
40
|
}
|
42
41
|
}, delay);
|
43
42
|
}
|
@@ -56,10 +55,16 @@ export const createResourceBrowserCallbacks = ({
|
|
56
55
|
}
|
57
56
|
});
|
58
57
|
},
|
59
|
-
onChange: (
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
onChange: (reference: HydratedResourceReference | null) => {
|
59
|
+
if (reference) {
|
60
|
+
const { resource, source } = reference;
|
61
|
+
|
62
|
+
alert(
|
63
|
+
`Resource Browser has selected resource #${resource.id} (${resource.name}) from source #${source.id} (${source.name}).`,
|
64
|
+
);
|
65
|
+
} else {
|
66
|
+
alert(`Resource Browser has cleared selected resource.`);
|
67
|
+
}
|
63
68
|
},
|
64
69
|
};
|
65
70
|
};
|
package/src/index.spec.tsx
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { render, screen } from '@testing-library/react';
|
3
|
-
import
|
3
|
+
import { ResourceBrowserInput } from './index';
|
4
4
|
|
5
5
|
const mockRequestSources = jest.fn();
|
6
6
|
const mockRequestChildren = jest.fn();
|
@@ -18,14 +18,14 @@ const defaultProps: any = {
|
|
18
18
|
|
19
19
|
describe('Related Asset Picker', () => {
|
20
20
|
it('should render the related asset picker with the default label', () => {
|
21
|
-
render(<
|
21
|
+
render(<ResourceBrowserInput {...defaultProps} />);
|
22
22
|
const pickerLabel = screen.getByText('Choose asset');
|
23
23
|
|
24
24
|
expect(pickerLabel).toBeInTheDocument();
|
25
25
|
});
|
26
26
|
|
27
27
|
it('should display the generic asset picking icon', () => {
|
28
|
-
render(<
|
28
|
+
render(<ResourceBrowserInput {...defaultProps} />);
|
29
29
|
const pickerLabel = screen.getByText('Choose asset');
|
30
30
|
const pickerIcon = screen.getByTestId('AdsClickRoundedIcon');
|
31
31
|
|
@@ -34,7 +34,7 @@ describe('Related Asset Picker', () => {
|
|
34
34
|
});
|
35
35
|
|
36
36
|
it('should display the image icon when only images are allowed', () => {
|
37
|
-
render(<
|
37
|
+
render(<ResourceBrowserInput {...defaultProps} allowedTypes={['image']} />);
|
38
38
|
const pickerLabel = screen.getByText('Choose image');
|
39
39
|
const pickerIcon = screen.getByTestId('PhotoLibraryRoundedIcon');
|
40
40
|
|
package/src/index.stories.tsx
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
import { StoryFn, Meta } from '@storybook/react';
|
2
|
-
import
|
2
|
+
import { ResourceBrowserInput, ResourceBrowserContext } from './index';
|
3
3
|
import { createResourceBrowserCallbacks } from './__mocks__/StorybookHelpers';
|
4
4
|
|
5
5
|
export default {
|
6
|
-
title: '
|
7
|
-
component:
|
8
|
-
} as Meta<typeof
|
6
|
+
title: 'Resource browser input',
|
7
|
+
component: ResourceBrowserInput,
|
8
|
+
} as Meta<typeof ResourceBrowserInput>;
|
9
9
|
|
10
|
-
const Template: StoryFn<typeof
|
11
|
-
const { sourceIsLoading, resourceIsLoading, error } = props;
|
10
|
+
const Template: StoryFn<typeof ResourceBrowserInput> = (props) => {
|
11
|
+
const { sourceIsLoading, resourceIsLoading, error, ...other } = props;
|
12
12
|
const { onRequestSources, onRequestChildren, onRequestResource, onChange } = createResourceBrowserCallbacks({
|
13
13
|
sourceIsLoading: !!sourceIsLoading,
|
14
14
|
resourceIsLoading: !!resourceIsLoading,
|
@@ -17,13 +17,9 @@ const Template: StoryFn<typeof RelatedAssetPicker> = (props) => {
|
|
17
17
|
|
18
18
|
return (
|
19
19
|
<div className="w-[400px] m-3">
|
20
|
-
<
|
21
|
-
{...
|
22
|
-
|
23
|
-
onRequestChildren={onRequestChildren}
|
24
|
-
onRequestResource={onRequestResource}
|
25
|
-
onChange={onChange}
|
26
|
-
/>
|
20
|
+
<ResourceBrowserContext.Provider value={{ onRequestSources, onRequestChildren, onRequestResource }}>
|
21
|
+
<ResourceBrowserInput {...other} onChange={onChange} />
|
22
|
+
</ResourceBrowserContext.Provider>
|
27
23
|
</div>
|
28
24
|
);
|
29
25
|
};
|
@@ -31,11 +27,15 @@ const Template: StoryFn<typeof RelatedAssetPicker> = (props) => {
|
|
31
27
|
export const Primary = Template.bind({});
|
32
28
|
|
33
29
|
Primary.args = {
|
34
|
-
modalTitle: '
|
30
|
+
modalTitle: 'Choose asset',
|
35
31
|
sourceIsLoading: false,
|
36
32
|
resourceIsLoading: false,
|
37
33
|
error: '',
|
38
|
-
|
34
|
+
};
|
35
|
+
|
36
|
+
export const Selected = Template.bind({});
|
37
|
+
Selected.args = {
|
38
|
+
value: { resource: '1', source: '2' },
|
39
39
|
};
|
40
40
|
|
41
41
|
export const ImagesOnly = Template.bind({});
|
package/src/index.tsx
CHANGED
@@ -1,68 +1,53 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import ModalTrigger from './Modal/ModalTrigger';
|
1
|
+
import React, { useContext } from 'react';
|
3
2
|
import ResourcePickerContainer from './ResourcePickerContainer/ResourcePickerContainer';
|
4
3
|
import { HydratedResourceReference, Resource, ResourceReference, Source } from './types';
|
5
|
-
import
|
6
|
-
import
|
7
|
-
import
|
8
|
-
import clsx from 'clsx';
|
9
|
-
// import { LoadingState, ErrorState, SelectedState } from './ResourcePicker/ResourcePicker';
|
4
|
+
import { ResourceBrowserContext } from './ResourceBrowserContext/ResourceBrowserContext';
|
5
|
+
import ResourcePicker from './ResourcePicker/ResourcePicker';
|
6
|
+
import { useResource } from './Hooks/useResource';
|
10
7
|
|
11
8
|
export type { HydratedResourceReference, Resource, ResourceReference, Source };
|
9
|
+
export { ResourceBrowserContext };
|
12
10
|
|
13
|
-
|
11
|
+
type ResourceBrowserInputProps = {
|
12
|
+
modalTitle: string;
|
13
|
+
allowedTypes?: string[];
|
14
|
+
isDisabled?: boolean;
|
15
|
+
value: ResourceReference | null;
|
16
|
+
onChange(resource: HydratedResourceReference | null): void;
|
17
|
+
};
|
18
|
+
|
19
|
+
export const ResourceBrowserInput = ({
|
14
20
|
modalTitle,
|
15
21
|
allowedTypes,
|
16
|
-
onRequestSources,
|
17
|
-
onRequestChildren,
|
18
22
|
onChange,
|
23
|
+
value,
|
19
24
|
isDisabled,
|
20
|
-
}: {
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
onRequestChildren(source: Source, resource: Resource | null): Promise<Resource[]>;
|
25
|
-
onRequestResource(reference: ResourceReference): Promise<Resource | null>;
|
26
|
-
onChange(resource: HydratedResourceReference | null): void;
|
27
|
-
isDisabled?: boolean;
|
28
|
-
}) {
|
29
|
-
const isImagePicker = allowedTypes && allowedTypes.length === 1 && allowedTypes.includes('image');
|
25
|
+
}: ResourceBrowserInputProps) => {
|
26
|
+
const { onRequestSources, onRequestChildren, onRequestResource } = useContext(ResourceBrowserContext);
|
27
|
+
const { data: resource, error, isLoading } = useResource({ onRequestResource, reference: value });
|
28
|
+
|
30
29
|
return (
|
31
30
|
<div className="squiz-rb-scope">
|
32
|
-
<
|
33
|
-
{
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
<ResourcePicker
|
32
|
+
resource={resource}
|
33
|
+
allowedTypes={allowedTypes}
|
34
|
+
error={error}
|
35
|
+
isLoading={isLoading}
|
36
|
+
isDisabled={isDisabled}
|
37
|
+
onClear={() => onChange(null)}
|
38
|
+
>
|
39
|
+
{(onClose, titleProps) => (
|
40
|
+
<ResourcePickerContainer
|
41
|
+
title={modalTitle}
|
42
|
+
titleAriaProps={titleProps}
|
43
|
+
allowedTypes={allowedTypes}
|
44
|
+
onClose={onClose}
|
45
|
+
onRequestSources={onRequestSources}
|
46
|
+
onRequestChildren={onRequestChildren}
|
47
|
+
onChange={onChange}
|
48
|
+
/>
|
37
49
|
)}
|
38
|
-
|
39
|
-
<ModalTrigger
|
40
|
-
showLabel={true}
|
41
|
-
label={isImagePicker ? `Choose image` : `Choose asset`}
|
42
|
-
icon={<AddCircleOutlineRoundedIcon aria-hidden className="!w-4 !h-4" />}
|
43
|
-
isDisabled={isDisabled}
|
44
|
-
>
|
45
|
-
{(onClose, titleProps) => (
|
46
|
-
<ResourcePickerContainer
|
47
|
-
title={modalTitle}
|
48
|
-
titleAriaProps={titleProps}
|
49
|
-
allowedTypes={allowedTypes}
|
50
|
-
onClose={onClose}
|
51
|
-
onRequestSources={onRequestSources}
|
52
|
-
onRequestChildren={onRequestChildren}
|
53
|
-
onChange={onChange}
|
54
|
-
/>
|
55
|
-
)}
|
56
|
-
</ModalTrigger>
|
57
|
-
{/* TODO: Add all these states in - examples of them can be found in the Resource Picker story and corresponding file /ResourcePicker/ResourcePicker.tsx */}
|
58
|
-
{/* <div className="resource-picker-info">
|
59
|
-
<div className="resource-picker-info__layout">
|
60
|
-
{isLoading && <LoadingState />}
|
61
|
-
{isError && <ErrorState />}
|
62
|
-
{resource !== null && <SelectedState resource={resource} />}
|
63
|
-
</div>
|
64
|
-
</div> */}
|
65
|
-
</div>
|
50
|
+
</ResourcePicker>
|
66
51
|
</div>
|
67
52
|
);
|
68
|
-
}
|
53
|
+
};
|
@@ -63,7 +63,7 @@ export type Hierarchy<T> = Array<{
|
|
63
63
|
/**
|
64
64
|
* Augments a type so that all properties are optional.
|
65
65
|
*/
|
66
|
-
type DeepPartial<T> = {
|
66
|
+
export type DeepPartial<T> = {
|
67
67
|
[P in keyof T]?: T[P] extends Array<infer U>
|
68
68
|
? Array<DeepPartial<U>>
|
69
69
|
: T[P] extends ReadonlyArray<infer U>
|
package/tailwind.config.cjs
CHANGED
@@ -3,6 +3,11 @@ module.exports = {
|
|
3
3
|
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}', './node_modules/flowbite/**/*.js'],
|
4
4
|
theme: {
|
5
5
|
extend: {
|
6
|
+
borderWidth: {
|
7
|
+
// We shouldn't use ".border" class and instead use ".border-1".
|
8
|
+
// ".border" has !important styling defined in Matrix so overrides anything various border styling if used.
|
9
|
+
1: '1px',
|
10
|
+
},
|
6
11
|
borderRadius: {
|
7
12
|
DEFAULT: '4px',
|
8
13
|
md: '6px',
|
@@ -1,16 +0,0 @@
|
|
1
|
-
import { Source } from '../types';
|
2
|
-
type UseSourcesProps = {
|
3
|
-
onRequestSources: () => Promise<Source[]>;
|
4
|
-
};
|
5
|
-
/**
|
6
|
-
* Loads and caches the source list when a component using the hook is mounted.
|
7
|
-
*
|
8
|
-
* @param {Function} onRequestSources
|
9
|
-
*/
|
10
|
-
export declare const useSources: ({ onRequestSources }: UseSourcesProps) => {
|
11
|
-
isLoading: boolean;
|
12
|
-
sources: Source[];
|
13
|
-
reload: () => void;
|
14
|
-
error: Error | null;
|
15
|
-
};
|
16
|
-
export {};
|
package/lib/Hooks/useSources.js
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.useSources = void 0;
|
4
|
-
const react_1 = require("react");
|
5
|
-
/**
|
6
|
-
* Loads and caches the source list when a component using the hook is mounted.
|
7
|
-
*
|
8
|
-
* @param {Function} onRequestSources
|
9
|
-
*/
|
10
|
-
const useSources = ({ onRequestSources }) => {
|
11
|
-
const [error, setError] = (0, react_1.useState)(null);
|
12
|
-
const [isLoading, setIsLoading] = (0, react_1.useState)(true);
|
13
|
-
const [sources, setSources] = (0, react_1.useState)([]);
|
14
|
-
const loadSources = (0, react_1.useCallback)(() => {
|
15
|
-
setIsLoading(true);
|
16
|
-
onRequestSources()
|
17
|
-
.then((sources) => {
|
18
|
-
setIsLoading(false);
|
19
|
-
setSources(sources);
|
20
|
-
setError(null);
|
21
|
-
})
|
22
|
-
.catch((error) => {
|
23
|
-
setIsLoading(false);
|
24
|
-
setError(error);
|
25
|
-
});
|
26
|
-
}, []);
|
27
|
-
// trigger a load of the sources when the component using the hook is initially rendered.
|
28
|
-
(0, react_1.useEffect)(loadSources, []);
|
29
|
-
return { isLoading, sources, reload: loadSources, error };
|
30
|
-
};
|
31
|
-
exports.useSources = useSources;
|
@@ -1,27 +0,0 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import Icon, { IconOptions } from '../Icons/Icon';
|
3
|
-
|
4
|
-
interface ResourceError {
|
5
|
-
errorMessage: string;
|
6
|
-
handleReload: () => void;
|
7
|
-
}
|
8
|
-
|
9
|
-
const ResourceError = function ({ errorMessage, handleReload }: ResourceError) {
|
10
|
-
return (
|
11
|
-
<div className="flex flex-col items-center rounded-lg py-8 bg-white h-204 gap-3">
|
12
|
-
<Icon icon={'error' as IconOptions} aria-hidden />
|
13
|
-
{/* Error message */}
|
14
|
-
<span className="text-md text-gray-800 font-semibold leading-5">{errorMessage}</span>
|
15
|
-
{/* Retry button */}
|
16
|
-
<button
|
17
|
-
type="button"
|
18
|
-
onClick={handleReload}
|
19
|
-
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"
|
20
|
-
>
|
21
|
-
<Icon icon={'retry' as IconOptions} aria-hidden /> Try again
|
22
|
-
</button>
|
23
|
-
</div>
|
24
|
-
);
|
25
|
-
};
|
26
|
-
|
27
|
-
export default ResourceError;
|