piral-modals 1.0.0-pre.2296 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +8 -2
- package/esm/Modals.js +18 -18
- package/esm/Modals.js.map +1 -1
- package/esm/actions.js +5 -6
- package/esm/actions.js.map +1 -1
- package/esm/components.d.ts +3 -4
- package/esm/components.js +2 -2
- package/esm/components.js.map +1 -1
- package/esm/create.d.ts +13 -2
- package/esm/create.js +36 -31
- package/esm/create.js.map +1 -1
- package/esm/default.js +2 -2
- package/esm/default.js.map +1 -1
- package/esm/types.d.ts +36 -5
- package/lib/Modals.js +22 -21
- package/lib/Modals.js.map +1 -1
- package/lib/actions.js +5 -6
- package/lib/actions.js.map +1 -1
- package/lib/components.d.ts +3 -4
- package/lib/components.js +3 -3
- package/lib/components.js.map +1 -1
- package/lib/create.d.ts +13 -2
- package/lib/create.js +39 -34
- package/lib/create.js.map +1 -1
- package/lib/default.js +6 -4
- package/lib/default.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/types.d.ts +36 -5
- package/package.json +29 -6
- package/piral-modals.min.js +1 -0
- package/src/Modals.test.tsx +151 -85
- package/src/Modals.tsx +7 -9
- package/src/actions.test.ts +19 -18
- package/src/actions.ts +2 -2
- package/src/components.tsx +2 -4
- package/src/create.test.ts +7 -3
- package/src/create.ts +43 -23
- package/src/default.tsx +1 -1
- package/src/types.ts +36 -3
package/src/actions.test.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import
|
|
1
|
+
import create from 'zustand';
|
|
2
|
+
import { createListener } from 'piral-base';
|
|
3
|
+
import { createActions } from 'piral-core';
|
|
2
4
|
import { registerModal, unregisterModal, openModal, closeModal } from './actions';
|
|
3
|
-
import { createActions, createListener } from 'piral-core';
|
|
4
5
|
|
|
5
6
|
describe('Modals Actions Module', () => {
|
|
6
7
|
it('registerModal and unregisterModal', () => {
|
|
7
|
-
const state =
|
|
8
|
+
const state: any = create(() => ({
|
|
8
9
|
foo: 5,
|
|
9
10
|
registry: {
|
|
10
11
|
foo: 5,
|
|
11
12
|
modals: {},
|
|
12
13
|
},
|
|
13
|
-
});
|
|
14
|
+
}));
|
|
14
15
|
const ctx = createActions(state, createListener({}));
|
|
15
16
|
registerModal(ctx, 'foo', 10);
|
|
16
|
-
expect(
|
|
17
|
+
expect(state.getState()).toEqual({
|
|
17
18
|
foo: 5,
|
|
18
19
|
registry: {
|
|
19
20
|
foo: 5,
|
|
@@ -23,7 +24,7 @@ describe('Modals Actions Module', () => {
|
|
|
23
24
|
},
|
|
24
25
|
});
|
|
25
26
|
unregisterModal(ctx, 'foo');
|
|
26
|
-
expect(
|
|
27
|
+
expect(state.getState()).toEqual({
|
|
27
28
|
foo: 5,
|
|
28
29
|
registry: {
|
|
29
30
|
foo: 5,
|
|
@@ -33,28 +34,28 @@ describe('Modals Actions Module', () => {
|
|
|
33
34
|
});
|
|
34
35
|
|
|
35
36
|
it('openModal adds a new modal', () => {
|
|
36
|
-
const state =
|
|
37
|
+
const state: any = create(() => ({
|
|
37
38
|
foo: 5,
|
|
38
|
-
modals: ['b'],
|
|
39
|
-
});
|
|
39
|
+
modals: [{ id: 'b' }],
|
|
40
|
+
}));
|
|
40
41
|
const ctx = createActions(state, createListener({}));
|
|
41
|
-
openModal(ctx, 'a');
|
|
42
|
-
expect(
|
|
42
|
+
openModal(ctx, { id: 'a' });
|
|
43
|
+
expect(state.getState()).toEqual({
|
|
43
44
|
foo: 5,
|
|
44
|
-
modals: ['a', 'b'],
|
|
45
|
+
modals: [{ id: 'a' }, { id: 'b' }],
|
|
45
46
|
});
|
|
46
47
|
});
|
|
47
48
|
|
|
48
49
|
it('closeModal removes an existing modal', () => {
|
|
49
|
-
const state =
|
|
50
|
+
const state: any = create(() => ({
|
|
50
51
|
foo: 5,
|
|
51
|
-
modals: ['a', 'b', 'c'],
|
|
52
|
-
});
|
|
52
|
+
modals: [{ id: 'a' }, { id: 'b' }, { id: 'c' }],
|
|
53
|
+
}));
|
|
53
54
|
const ctx = createActions(state, createListener({}));
|
|
54
|
-
closeModal(ctx, 'b');
|
|
55
|
-
expect(
|
|
55
|
+
closeModal(ctx, { id: 'b' });
|
|
56
|
+
expect(state.getState()).toEqual({
|
|
56
57
|
foo: 5,
|
|
57
|
-
modals: ['a', 'c'],
|
|
58
|
+
modals: [{ id: 'a' }, { id: 'c' }],
|
|
58
59
|
});
|
|
59
60
|
});
|
|
60
61
|
});
|
package/src/actions.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { withKey, withoutKey, prependItem,
|
|
1
|
+
import { withKey, withoutKey, prependItem, excludeOn, GlobalStateContext } from 'piral-core';
|
|
2
2
|
import { ModalRegistration, OpenModalDialog } from './types';
|
|
3
3
|
|
|
4
4
|
export function openModal(ctx: GlobalStateContext, dialog: OpenModalDialog) {
|
|
@@ -11,7 +11,7 @@ export function openModal(ctx: GlobalStateContext, dialog: OpenModalDialog) {
|
|
|
11
11
|
export function closeModal(ctx: GlobalStateContext, dialog: OpenModalDialog) {
|
|
12
12
|
ctx.dispatch((state) => ({
|
|
13
13
|
...state,
|
|
14
|
-
modals:
|
|
14
|
+
modals: excludeOn(state.modals, (modal) => modal.id === dialog.id),
|
|
15
15
|
}));
|
|
16
16
|
}
|
|
17
17
|
|
package/src/components.tsx
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
1
|
import { getPiralComponent } from 'piral-core';
|
|
3
|
-
import { ModalsHostProps, ModalsDialogProps } from './types';
|
|
4
2
|
|
|
5
|
-
export const PiralModalsHost
|
|
6
|
-
export const PiralModalsDialog
|
|
3
|
+
export const PiralModalsHost = getPiralComponent('ModalsHost');
|
|
4
|
+
export const PiralModalsDialog = getPiralComponent('ModalsDialog');
|
package/src/create.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import create from 'zustand';
|
|
2
2
|
import { createElement, FC } from 'react';
|
|
3
3
|
import { createModalsApi } from './create';
|
|
4
4
|
|
|
@@ -6,7 +6,11 @@ const StubComponent: FC = (props) => createElement('div', props);
|
|
|
6
6
|
StubComponent.displayName = 'StubComponent';
|
|
7
7
|
|
|
8
8
|
function createMockContainer() {
|
|
9
|
-
const state =
|
|
9
|
+
const state = create(() => ({
|
|
10
|
+
registry: {
|
|
11
|
+
extensions: {},
|
|
12
|
+
},
|
|
13
|
+
}));
|
|
10
14
|
return {
|
|
11
15
|
context: {
|
|
12
16
|
on: jest.fn(),
|
|
@@ -19,7 +23,7 @@ function createMockContainer() {
|
|
|
19
23
|
},
|
|
20
24
|
state,
|
|
21
25
|
dispatch(update) {
|
|
22
|
-
|
|
26
|
+
state.setState(update(state.getState()));
|
|
23
27
|
},
|
|
24
28
|
} as any,
|
|
25
29
|
api: {} as any,
|
package/src/create.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as actions from './actions';
|
|
2
2
|
import { ComponentType } from 'react';
|
|
3
|
-
import { withApi, buildName, PiralPlugin, Dict } from 'piral-core';
|
|
3
|
+
import { withApi, buildName, PiralPlugin, Dict, withRootExtension, withAll, GlobalState } from 'piral-core';
|
|
4
4
|
import { DefaultHost, DefaultDialog } from './default';
|
|
5
|
-
import {
|
|
5
|
+
import { Modals } from './Modals';
|
|
6
|
+
import { PiletModalsApi, ModalRegistration, BareModalComponentProps, ModalLayoutOptions } from './types';
|
|
6
7
|
|
|
7
8
|
export interface InitialModalDialog {
|
|
8
9
|
/**
|
|
@@ -16,7 +17,11 @@ export interface InitialModalDialog {
|
|
|
16
17
|
/**
|
|
17
18
|
* The default options for the modal dialog.
|
|
18
19
|
*/
|
|
19
|
-
defaults
|
|
20
|
+
defaults?: any;
|
|
21
|
+
/**
|
|
22
|
+
* The layout options for the modal dialog.
|
|
23
|
+
*/
|
|
24
|
+
layout?: ModalLayoutOptions;
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
/**
|
|
@@ -27,69 +32,84 @@ export interface ModalsConfig {
|
|
|
27
32
|
* The initial modal dialogs.
|
|
28
33
|
*/
|
|
29
34
|
dialogs?: Array<InitialModalDialog>;
|
|
35
|
+
/**
|
|
36
|
+
* Defines how the next ID for the key is selected.
|
|
37
|
+
* By default a random number is used.
|
|
38
|
+
*
|
|
39
|
+
* @param name The name of the modal dialog.
|
|
40
|
+
*/
|
|
41
|
+
selectId?(name: string): string;
|
|
30
42
|
}
|
|
31
43
|
|
|
32
44
|
function getModalDialogs(dialogs: Array<InitialModalDialog>) {
|
|
33
45
|
const modals: Dict<ModalRegistration> = {};
|
|
34
46
|
|
|
35
|
-
for (const { name, component, defaults } of dialogs) {
|
|
47
|
+
for (const { name, component, defaults, layout = {} } of dialogs) {
|
|
36
48
|
modals[`global-${name}`] = {
|
|
37
49
|
pilet: undefined,
|
|
38
50
|
name,
|
|
39
51
|
component,
|
|
40
52
|
defaults,
|
|
53
|
+
layout,
|
|
41
54
|
};
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
return modals;
|
|
45
58
|
}
|
|
46
59
|
|
|
60
|
+
function withModals(modals: Dict<ModalRegistration>) {
|
|
61
|
+
return (state: GlobalState): GlobalState => ({
|
|
62
|
+
...state,
|
|
63
|
+
components: {
|
|
64
|
+
ModalsHost: DefaultHost,
|
|
65
|
+
ModalsDialog: DefaultDialog,
|
|
66
|
+
...state.components,
|
|
67
|
+
},
|
|
68
|
+
registry: {
|
|
69
|
+
...state.registry,
|
|
70
|
+
modals,
|
|
71
|
+
},
|
|
72
|
+
modals: [],
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
47
76
|
/**
|
|
48
77
|
* Creates new Pilet API extensions for support modal dialogs.
|
|
49
78
|
*/
|
|
50
79
|
export function createModalsApi(config: ModalsConfig = {}): PiralPlugin<PiletModalsApi> {
|
|
51
|
-
const { dialogs = [] } = config;
|
|
80
|
+
const { dialogs = [], selectId = (name) => `${name}-${~~(Math.random() * 10000)}` } = config;
|
|
52
81
|
|
|
53
82
|
return (context) => {
|
|
54
83
|
context.defineActions(actions);
|
|
55
84
|
|
|
56
|
-
context.dispatch((
|
|
57
|
-
...state,
|
|
58
|
-
components: {
|
|
59
|
-
ModalsHost: DefaultHost,
|
|
60
|
-
ModalsDialog: DefaultDialog,
|
|
61
|
-
...state.components,
|
|
62
|
-
},
|
|
63
|
-
registry: {
|
|
64
|
-
...state.registry,
|
|
65
|
-
modals: getModalDialogs(dialogs),
|
|
66
|
-
},
|
|
67
|
-
modals: [],
|
|
68
|
-
}));
|
|
85
|
+
context.dispatch(withAll(withModals(getModalDialogs(dialogs)), withRootExtension('piral-modals', Modals)));
|
|
69
86
|
|
|
70
87
|
return (api, target) => {
|
|
71
88
|
const pilet = target.name;
|
|
72
89
|
|
|
73
90
|
return {
|
|
74
|
-
showModal(
|
|
91
|
+
showModal(simpleName, options) {
|
|
92
|
+
const name = buildName(pilet, simpleName);
|
|
75
93
|
const dialog = {
|
|
76
|
-
|
|
77
|
-
|
|
94
|
+
id: selectId(name),
|
|
95
|
+
name,
|
|
96
|
+
alternative: simpleName,
|
|
78
97
|
options,
|
|
79
98
|
close() {
|
|
80
|
-
|
|
99
|
+
context.closeModal(dialog);
|
|
81
100
|
},
|
|
82
101
|
};
|
|
83
102
|
context.openModal(dialog);
|
|
84
103
|
return dialog.close;
|
|
85
104
|
},
|
|
86
|
-
registerModal(name, arg, defaults) {
|
|
105
|
+
registerModal(name, arg, defaults, layout = {}) {
|
|
87
106
|
const id = buildName(pilet, name);
|
|
88
107
|
context.registerModal(id, {
|
|
89
108
|
pilet,
|
|
90
109
|
name,
|
|
91
110
|
component: withApi(context, arg, api, 'modal'),
|
|
92
111
|
defaults,
|
|
112
|
+
layout,
|
|
93
113
|
});
|
|
94
114
|
return () => api.unregisterModal(name);
|
|
95
115
|
},
|
package/src/default.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import { defaultRender } from 'piral-core';
|
|
|
3
3
|
import { ModalsHostProps, ModalsDialogProps } from './types';
|
|
4
4
|
|
|
5
5
|
export const DefaultHost: React.FC<ModalsHostProps> = (props) => (
|
|
6
|
-
<div className="piral-modals-host"
|
|
6
|
+
<div className="piral-modals-host">
|
|
7
7
|
{props.open && <div className="piral-modals-overlay">{props.children}</div>}
|
|
8
8
|
</div>
|
|
9
9
|
);
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ComponentType } from 'react';
|
|
2
|
-
import {
|
|
1
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
2
|
+
import type {
|
|
3
3
|
Dict,
|
|
4
4
|
WrappedComponent,
|
|
5
5
|
BaseComponentProps,
|
|
@@ -75,9 +75,31 @@ export interface ModalsHostProps {
|
|
|
75
75
|
* Callback to invoke closing the modal dialog.
|
|
76
76
|
*/
|
|
77
77
|
close(): void;
|
|
78
|
+
/**
|
|
79
|
+
* The dialogs to display.
|
|
80
|
+
*/
|
|
81
|
+
children?: ReactNode;
|
|
78
82
|
}
|
|
79
83
|
|
|
80
|
-
export interface ModalsDialogProps extends OpenModalDialog {
|
|
84
|
+
export interface ModalsDialogProps extends OpenModalDialog {
|
|
85
|
+
/**
|
|
86
|
+
* The layout options given for the current dialog.
|
|
87
|
+
*/
|
|
88
|
+
layout: ModalLayoutOptions;
|
|
89
|
+
/**
|
|
90
|
+
* The provided default options.
|
|
91
|
+
*/
|
|
92
|
+
defaults: any;
|
|
93
|
+
/**
|
|
94
|
+
* The content of the dialog to display.
|
|
95
|
+
*/
|
|
96
|
+
children?: ReactNode;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The options provided for the dialog layout.
|
|
101
|
+
*/
|
|
102
|
+
export interface ModalLayoutOptions {}
|
|
81
103
|
|
|
82
104
|
/**
|
|
83
105
|
* The error used when a registered modal dialog crashed.
|
|
@@ -95,9 +117,17 @@ export interface ModalErrorInfoProps {
|
|
|
95
117
|
* Callback for closing the modal programmatically.
|
|
96
118
|
*/
|
|
97
119
|
onClose(): void;
|
|
120
|
+
/**
|
|
121
|
+
* The name of the pilet emitting the error.
|
|
122
|
+
*/
|
|
123
|
+
pilet?: string;
|
|
98
124
|
}
|
|
99
125
|
|
|
100
126
|
export interface OpenModalDialog {
|
|
127
|
+
/**
|
|
128
|
+
* Gets the ID of the modal to open. For tracking its state.
|
|
129
|
+
*/
|
|
130
|
+
id: string;
|
|
101
131
|
/**
|
|
102
132
|
* Specifies the fully qualified name of the dialog to show.
|
|
103
133
|
*/
|
|
@@ -131,6 +161,7 @@ export interface ModalRegistration extends BaseRegistration {
|
|
|
131
161
|
name: string;
|
|
132
162
|
component: WrappedComponent<ModalComponentProps<any>>;
|
|
133
163
|
defaults: any;
|
|
164
|
+
layout: ModalLayoutOptions;
|
|
134
165
|
}
|
|
135
166
|
|
|
136
167
|
export interface BaseModalOptions {}
|
|
@@ -162,11 +193,13 @@ export interface PiletModalsApi {
|
|
|
162
193
|
* @param name The name of the modal to register.
|
|
163
194
|
* @param Component The component to render the page.
|
|
164
195
|
* @param defaults Optionally, sets the default values for the inserted options.
|
|
196
|
+
* @param layout Optionally, sets the layout options for the dialog wrapper.
|
|
165
197
|
*/
|
|
166
198
|
registerModal<T>(
|
|
167
199
|
name: T extends string ? T : string,
|
|
168
200
|
Component: AnyComponent<ModalComponentProps<T>>,
|
|
169
201
|
defaults?: ModalOptions<T>,
|
|
202
|
+
layout?: ModalLayoutOptions,
|
|
170
203
|
): RegistrationDisposer;
|
|
171
204
|
/**
|
|
172
205
|
* Unregisters a modal by its name.
|