react-admin-base-bootstrap 0.5.1 → 0.5.4
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/assets/main.css +34 -0
- package/build.js +24 -0
- package/lib/esm/Components/ApiSelect.js +1 -1
- package/lib/esm/Components/BootstrapDataTable.js +2 -2
- package/lib/esm/Components/CRUD.js +12 -9
- package/lib/esm/Components/EntityEditor.js +1 -1
- package/lib/esm/Components/ThemeProvider.d.ts +8 -0
- package/lib/esm/Components/ThemeProvider.js +37 -0
- package/lib/esm/index.d.ts +2 -1
- package/lib/esm/index.js +2 -1
- package/package.json +6 -5
- package/src/Components/ApiSelect.tsx +2 -0
- package/src/Components/BootstrapDataTable.tsx +1 -1
- package/src/Components/CRUD.tsx +14 -8
- package/src/Components/EntityEditor.tsx +1 -1
- package/src/Components/MenuState.tsx +1 -0
- package/src/Components/ThemeProvider.tsx +53 -0
- package/src/index.ts +2 -0
- package/watch.js +58 -0
package/assets/main.css
CHANGED
|
@@ -61,3 +61,37 @@
|
|
|
61
61
|
.tingle-modal-box__footer {
|
|
62
62
|
text-align: center;
|
|
63
63
|
}
|
|
64
|
+
|
|
65
|
+
.back-btn-shown {
|
|
66
|
+
position: fixed;
|
|
67
|
+
bottom: 10px;
|
|
68
|
+
right: 10px;
|
|
69
|
+
width: 30px;
|
|
70
|
+
height: 30px;
|
|
71
|
+
background-color: black;
|
|
72
|
+
border: 1px solid white;
|
|
73
|
+
box-shadow: 0 10px 30px rgba(82, 85, 90, 0.2);
|
|
74
|
+
color: white;
|
|
75
|
+
text-align: center;
|
|
76
|
+
cursor: pointer;
|
|
77
|
+
line-height: 25px;
|
|
78
|
+
font-size: 20px;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.back-btn-shown span {
|
|
82
|
+
display: none;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.back-btn-shown:hover span {
|
|
86
|
+
position: absolute;
|
|
87
|
+
top: 0;
|
|
88
|
+
right: 35px;
|
|
89
|
+
width: 74px;
|
|
90
|
+
margin-left: -37px;
|
|
91
|
+
display: block;
|
|
92
|
+
background-color: black;
|
|
93
|
+
color: white;
|
|
94
|
+
font-size: 12px;
|
|
95
|
+
border: 1px solid black;
|
|
96
|
+
box-shadow: 0 10px 40px rgba(82, 85, 90, 0.2);
|
|
97
|
+
}
|
package/build.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
const rewire = require('rewire');
|
|
3
|
+
const webpackConfig = rewire('react-scripts/scripts/build');
|
|
4
|
+
const config = webpackConfig.__get__('config');
|
|
5
|
+
|
|
6
|
+
addLazyLoadingStyleLoader(config.module);
|
|
7
|
+
|
|
8
|
+
function addLazyLoadingStyleLoader(config) {
|
|
9
|
+
const cssLoader = config.rules[1].oneOf[5];
|
|
10
|
+
|
|
11
|
+
config.rules[1].oneOf.splice(5, 2, {
|
|
12
|
+
...cssLoader,
|
|
13
|
+
use: [
|
|
14
|
+
{
|
|
15
|
+
loader: require.resolve('style-loader'),
|
|
16
|
+
options: {
|
|
17
|
+
injectType: 'lazyStyleTag'
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
cssLoader.use[1],
|
|
21
|
+
cssLoader.use[2]
|
|
22
|
+
]
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -78,5 +78,5 @@ export default function ApiSelect(props) {
|
|
|
78
78
|
setIsMenuOpen(false);
|
|
79
79
|
}, [setIsMenuOpen]);
|
|
80
80
|
const Component = onCreateOption ? CreatableSelect : Select;
|
|
81
|
-
return jsx(Component, Object.assign({}, props, { onCreateOption: (onCreateOption && handleCreateOption) || null, getNewOptionData: onCreateOption ? getNewOptionData ? getNewOptionData : (inputValue) => ({ [nameKey || 'name']: inputValue, __isNew__: true }) : null, inputValue: search, onInputChange: a => setSearch(a), components: Components, isLoading: !!loading || creating, getOptionLabel: getOptionLabel || ((row) => row[nameKey || 'name']), getOptionValue: getOptionValue || ((row) => row[idKey || 'id']), isDisabled: !!disabled || creating, isClearable: true, isSearchable: true, placeholder: placeholder || intl.formatMessage({ id: 'SELECT' }), options: !options ? [] : ((filter && options.filter(filter)) || options), isMenuOpen: isMenuOpen, onMenuOpen: onMenuOpen, onMenuClose: onMenuClose }));
|
|
81
|
+
return jsx(Component, Object.assign({}, props, { className: 'react-select-container', classNamePrefix: "react-select", onCreateOption: (onCreateOption && handleCreateOption) || null, getNewOptionData: onCreateOption ? getNewOptionData ? getNewOptionData : (inputValue) => ({ [nameKey || 'name']: inputValue, __isNew__: true }) : null, inputValue: search, onInputChange: a => setSearch(a), components: Components, isLoading: !!loading || creating, getOptionLabel: getOptionLabel || ((row) => row[nameKey || 'name']), getOptionValue: getOptionValue || ((row) => row[idKey || 'id']), isDisabled: !!disabled || creating, isClearable: true, isSearchable: true, placeholder: placeholder || intl.formatMessage({ id: 'SELECT' }), options: !options ? [] : ((filter && options.filter(filter)) || options), isMenuOpen: isMenuOpen, onMenuOpen: onMenuOpen, onMenuClose: onMenuClose }));
|
|
82
82
|
}
|
|
@@ -128,8 +128,8 @@ export default function BootstrapTable({ url, bordered, noStrip, defaultParams,
|
|
|
128
128
|
children[2],
|
|
129
129
|
React.createElement(Col, { md: "3", className: "ms-auto" },
|
|
130
130
|
React.createElement(Input, { placeholder: intl.formatMessage({ id: "SEARCH" }), type: "text", value: params.query || '', bsSize: "lg", onChange: e => setParams(Object.assign(Object.assign({}, params), { query: e.currentTarget.value })) })))),
|
|
131
|
-
data === null ? React.createElement(Alert, { className: "text-center mb-0 ", color: "warning" },
|
|
132
|
-
React.createElement("i", { className: "fas fa-spinner fa-lg fa-spin" })) : !data.length ? React.createElement(Alert, { className: "text-center", color: "danger" },
|
|
131
|
+
data === null ? React.createElement(Alert, { className: "text-center mb-0 mx-3 ", color: "warning" },
|
|
132
|
+
React.createElement("i", { className: "fas fa-spinner fa-lg fa-spin" })) : !data.length ? React.createElement(Alert, { className: "text-center mx-3", color: "danger" },
|
|
133
133
|
React.createElement("i", { className: "far fa-times-circle fa-lg" }),
|
|
134
134
|
" ",
|
|
135
135
|
React.createElement(FormattedMessage, { id: "NO_DATA_IS_AVAILABLE" })) : React.createElement(Table, { hover: true, bordered: bordered, striped: !noStrip, responsive: true, size: "md", className: "mb-0 dataTable" },
|
|
@@ -11,7 +11,7 @@ import React, { useCallback, useContext, useRef, useState } from 'react';
|
|
|
11
11
|
import { ValidatorProvider } from "react-admin-base";
|
|
12
12
|
import { FormattedMessage } from 'react-intl';
|
|
13
13
|
import { Redirect, Route } from 'react-router-dom';
|
|
14
|
-
import { Alert, Button, Form, Modal, ModalFooter, ModalHeader } from "reactstrap";
|
|
14
|
+
import { Alert, Button, Col, Form, Modal, ModalFooter, ModalHeader, Row } from "reactstrap";
|
|
15
15
|
import LoadingButton from '../Components/LoadingButton';
|
|
16
16
|
import BootstrapDataTable, { Actions } from './BootstrapDataTable';
|
|
17
17
|
export function ModalEntityEditor({ entity, title, size, url, onReload, disabled, children }) {
|
|
@@ -56,14 +56,17 @@ export function ModalEntityEditor({ entity, title, size, url, onReload, disabled
|
|
|
56
56
|
React.createElement("fieldset", { disabled: !!loading || !!disabled }, children),
|
|
57
57
|
React.createElement(ModalFooter, null,
|
|
58
58
|
error && React.createElement(Alert, { color: "danger", toggle: () => setError(null), style: { display: 'block', width: '100%' } }, error),
|
|
59
|
-
React.createElement(
|
|
60
|
-
React.createElement(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
React.createElement(Row, { className: "w-100" },
|
|
60
|
+
React.createElement(Col, null,
|
|
61
|
+
React.createElement(LoadingButton, { block: true, loading: loading, type: "submit", color: "primary" },
|
|
62
|
+
React.createElement("i", { className: "fas fa-save" }),
|
|
63
|
+
' ',
|
|
64
|
+
React.createElement(FormattedMessage, { id: "ENTITY.SAVE" }))),
|
|
65
|
+
React.createElement(Col, null,
|
|
66
|
+
React.createElement(Button, { block: true, outline: true, color: "danger", onClick: (e) => { e.preventDefault(); (url ? setOpen(false) : onReload(null)); } },
|
|
67
|
+
React.createElement("i", { className: "fas fa-times-circle" }),
|
|
68
|
+
' ',
|
|
69
|
+
React.createElement(FormattedMessage, { id: "ENTITY.CANCEL" })))))))));
|
|
67
70
|
}
|
|
68
71
|
const UrlContext = React.createContext(null);
|
|
69
72
|
export function CRUDActions({ id, edit, del, children }) {
|
|
@@ -54,7 +54,7 @@ export default function EntityEditor({ entity, disabled, children, onSave, saveB
|
|
|
54
54
|
React.createElement("fieldset", { disabled: !!loading || !!disabled }, children),
|
|
55
55
|
React.createElement(ValidationErrors, null),
|
|
56
56
|
savedAlert,
|
|
57
|
-
React.createElement(LoadingButton, { className: saveButtonClassName || "col-md-12", loading: loading, type: "submit", color: "primary" },
|
|
57
|
+
React.createElement(LoadingButton, { className: saveButtonClassName || "col-md-12 mt-3", loading: loading, type: "submit", color: "primary" },
|
|
58
58
|
saveButtonText || React.createElement(FormattedMessage, { id: "ENTITY.SAVE" }),
|
|
59
59
|
" ",
|
|
60
60
|
React.createElement("i", { className: "fas fa-save fa-lg" }))));
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export declare function useTheme(): any;
|
|
3
|
+
export declare function useAllThemes(): any;
|
|
4
|
+
export default function ThemeProvider({ themes, defaultTheme, children }: {
|
|
5
|
+
themes: any;
|
|
6
|
+
defaultTheme: any;
|
|
7
|
+
children: any;
|
|
8
|
+
}): JSX.Element;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React, { createContext, useContext, useEffect, useMemo, useReducer } from "react";
|
|
2
|
+
import { useApp } from "react-admin-base";
|
|
3
|
+
const ThemeContext = createContext(null);
|
|
4
|
+
const AllThemesContext = createContext(null);
|
|
5
|
+
export function useTheme() {
|
|
6
|
+
return useContext(ThemeContext);
|
|
7
|
+
}
|
|
8
|
+
export function useAllThemes() {
|
|
9
|
+
return useContext(AllThemesContext);
|
|
10
|
+
}
|
|
11
|
+
function useLocalStorage(key) {
|
|
12
|
+
const app = useApp();
|
|
13
|
+
const _key = app.id + '_' + key;
|
|
14
|
+
const previousValue = useMemo(() => localStorage.getItem(_key), [_key]);
|
|
15
|
+
return useReducer((_, newValue) => {
|
|
16
|
+
localStorage.setItem(_key, newValue);
|
|
17
|
+
return newValue;
|
|
18
|
+
}, previousValue);
|
|
19
|
+
}
|
|
20
|
+
export default function ThemeProvider({ themes, defaultTheme, children }) {
|
|
21
|
+
const state = useLocalStorage('theme');
|
|
22
|
+
const [theme, setTheme] = state;
|
|
23
|
+
const rTheme = theme || defaultTheme || 'light';
|
|
24
|
+
useEffect(function () {
|
|
25
|
+
const promise = (themes[rTheme] || themes[defaultTheme]).css()
|
|
26
|
+
.then(css => {
|
|
27
|
+
css.default.use();
|
|
28
|
+
return css;
|
|
29
|
+
});
|
|
30
|
+
return function () {
|
|
31
|
+
promise.then(css => css.default.unuse());
|
|
32
|
+
};
|
|
33
|
+
}, [theme]);
|
|
34
|
+
const val = useMemo(() => [rTheme, setTheme], [rTheme, setTheme]);
|
|
35
|
+
return React.createElement(AllThemesContext.Provider, { value: themes },
|
|
36
|
+
React.createElement(ThemeContext.Provider, { value: val }, children));
|
|
37
|
+
}
|
package/lib/esm/index.d.ts
CHANGED
|
@@ -16,4 +16,5 @@ import CheckBox from './Components/CheckBox';
|
|
|
16
16
|
import ErrorBoundary from './Components/ErrorBoundary';
|
|
17
17
|
import { useMenuState, useIsMobile } from './Components/MenuState';
|
|
18
18
|
import TopProgressBar from './Components/TopProgressBar';
|
|
19
|
-
|
|
19
|
+
import ThemeProvider, { useTheme, useAllThemes } from './Components/ThemeProvider';
|
|
20
|
+
export { ThemeProvider, useTheme, useAllThemes, useIsMobile, useMenuState, TopProgressBar, CRUD, ModalEntityEditor, CRUDActions, Relative, ApiSelect, Preview, ExcelExportButton, ExternalLoginButton, SingleFilePicker, MultiFilePicker, ImagePicker, BootstrapTable, EntityEditor, GoToTop, Validator, ValueValidator, ValidationErrors, LoadingButton, BootstrapDataTable, IdColumn, Column, ActionsColumn, Actions, useDataTableContext, LanguageProvider, useLanguage, LanguageSwitcher, ErrorBoundary, CheckBox };
|
package/lib/esm/index.js
CHANGED
|
@@ -16,4 +16,5 @@ import CheckBox from './Components/CheckBox';
|
|
|
16
16
|
import ErrorBoundary from './Components/ErrorBoundary';
|
|
17
17
|
import { useMenuState, useIsMobile } from './Components/MenuState';
|
|
18
18
|
import TopProgressBar from './Components/TopProgressBar';
|
|
19
|
-
|
|
19
|
+
import ThemeProvider, { useTheme, useAllThemes } from './Components/ThemeProvider';
|
|
20
|
+
export { ThemeProvider, useTheme, useAllThemes, useIsMobile, useMenuState, TopProgressBar, CRUD, ModalEntityEditor, CRUDActions, Relative, ApiSelect, Preview, ExcelExportButton, ExternalLoginButton, SingleFilePicker, MultiFilePicker, ImagePicker, BootstrapTable, EntityEditor, GoToTop, Validator, ValueValidator, ValidationErrors, LoadingButton, BootstrapDataTable, IdColumn, Column, ActionsColumn, Actions, useDataTableContext, LanguageProvider, useLanguage, LanguageSwitcher, ErrorBoundary, CheckBox };
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-admin-base-bootstrap",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
7
7
|
"build": "tsc",
|
|
8
|
-
"watch": "nodemon --exec npm run build"
|
|
8
|
+
"watch": "nodemon -e js,jsx,ts,tsx --exec npm run build"
|
|
9
9
|
},
|
|
10
10
|
"main": "lib/esm/index.js",
|
|
11
11
|
"jsnext:main": "lib/esm/index.js",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": "^17.0.2",
|
|
29
29
|
"react-dom": "^17.0.2",
|
|
30
|
-
"react-
|
|
31
|
-
"react-
|
|
30
|
+
"react-intl": "^5.21.0",
|
|
31
|
+
"react-router-dom": "^5.3.0"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@emotion/react": "^11.5.0",
|
|
@@ -42,14 +42,15 @@
|
|
|
42
42
|
"react-responsive": "^8.2.0",
|
|
43
43
|
"react-select": "^5.2.1",
|
|
44
44
|
"reactstrap": "^9.0.0",
|
|
45
|
+
"rewire": "^6.0.0",
|
|
45
46
|
"sweetalert2": "^11.1.9"
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
|
48
49
|
"@types/react": "^17.0.34",
|
|
49
50
|
"@types/react-router-dom": "^5.3.2",
|
|
50
|
-
"react-intl": "^5.21.0",
|
|
51
51
|
"cross-env": "^7.0.3",
|
|
52
52
|
"nodemon": "^2.0.14",
|
|
53
|
+
"react-intl": "^5.21.0",
|
|
53
54
|
"typescript": "^4.4.4"
|
|
54
55
|
}
|
|
55
56
|
}
|
|
@@ -102,6 +102,8 @@ export default function ApiSelect(props) {
|
|
|
102
102
|
|
|
103
103
|
return <Component
|
|
104
104
|
{...props}
|
|
105
|
+
className='react-select-container'
|
|
106
|
+
classNamePrefix="react-select"
|
|
105
107
|
onCreateOption={(onCreateOption && handleCreateOption) || null}
|
|
106
108
|
getNewOptionData={onCreateOption ? getNewOptionData ? getNewOptionData : (inputValue) =>( { [nameKey || 'name']: inputValue, __isNew__: true }) : null}
|
|
107
109
|
inputValue={search}
|
|
@@ -137,7 +137,7 @@ export default function BootstrapTable({url, bordered, noStrip, defaultParams, a
|
|
|
137
137
|
</Col>
|
|
138
138
|
</Row>
|
|
139
139
|
</CardHeader>
|
|
140
|
-
{data === null ? <Alert className="text-center mb-0 " color="warning"><i className="fas fa-spinner fa-lg fa-spin"></i></Alert> : !data.length ? <Alert className="text-center" color="danger">
|
|
140
|
+
{data === null ? <Alert className="text-center mb-0 mx-3 " color="warning"><i className="fas fa-spinner fa-lg fa-spin"></i></Alert> : !data.length ? <Alert className="text-center mx-3" color="danger">
|
|
141
141
|
<i className="far fa-times-circle fa-lg"></i> <FormattedMessage id="NO_DATA_IS_AVAILABLE"/>
|
|
142
142
|
</Alert> : <Table hover bordered={bordered} striped={!noStrip} responsive size="md" className="mb-0 dataTable">
|
|
143
143
|
{children[0]}
|
package/src/Components/CRUD.tsx
CHANGED
|
@@ -2,7 +2,7 @@ import React, { useCallback, useContext, useRef, useState } from 'react';
|
|
|
2
2
|
import { ValidatorProvider } from "react-admin-base";
|
|
3
3
|
import { FormattedMessage } from 'react-intl';
|
|
4
4
|
import { Redirect, Route } from 'react-router-dom';
|
|
5
|
-
import { Alert, Button, Form, Modal, ModalFooter, ModalHeader } from "reactstrap";
|
|
5
|
+
import { Alert, Button, Col, Form, Modal, ModalFooter, ModalHeader, Row } from "reactstrap";
|
|
6
6
|
import LoadingButton from '../Components/LoadingButton';
|
|
7
7
|
import BootstrapDataTable, { Actions } from './BootstrapDataTable';
|
|
8
8
|
|
|
@@ -67,13 +67,19 @@ export function ModalEntityEditor({ entity, title, size, url, onReload, disabled
|
|
|
67
67
|
{ children }
|
|
68
68
|
</fieldset>
|
|
69
69
|
<ModalFooter>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
</
|
|
70
|
+
{ error && <Alert color="danger" toggle={() => setError(null)} style={{ display: 'block', width: '100%' }}>{ error }</Alert>}
|
|
71
|
+
<Row className="w-100">
|
|
72
|
+
<Col>
|
|
73
|
+
<LoadingButton block loading={loading} type="submit" color="primary">
|
|
74
|
+
<i className="fas fa-save" />{' '}<FormattedMessage id="ENTITY.SAVE" />
|
|
75
|
+
</LoadingButton>
|
|
76
|
+
</Col>
|
|
77
|
+
<Col>
|
|
78
|
+
<Button block outline color="danger" onClick={(e) => { e.preventDefault(); (url ? setOpen(false) : onReload(null)); }}>
|
|
79
|
+
<i className="fas fa-times-circle" />{' '}<FormattedMessage id="ENTITY.CANCEL" />
|
|
80
|
+
</Button>
|
|
81
|
+
</Col>
|
|
82
|
+
</Row>
|
|
77
83
|
</ModalFooter>
|
|
78
84
|
</Form>
|
|
79
85
|
</ValidatorProvider>
|
|
@@ -61,7 +61,7 @@ export default function EntityEditor({ entity, disabled, children, onSave, saveB
|
|
|
61
61
|
</fieldset>
|
|
62
62
|
<ValidationErrors />
|
|
63
63
|
{ savedAlert }
|
|
64
|
-
<LoadingButton className={saveButtonClassName || "col-md-12"} loading={loading} type="submit" color="primary">{ saveButtonText || <FormattedMessage id="ENTITY.SAVE" /> } <i className="fas fa-save fa-lg"></i></LoadingButton>
|
|
64
|
+
<LoadingButton className={saveButtonClassName || "col-md-12 mt-3"} loading={loading} type="submit" color="primary">{ saveButtonText || <FormattedMessage id="ENTITY.SAVE" /> } <i className="fas fa-save fa-lg"></i></LoadingButton>
|
|
65
65
|
</Form>
|
|
66
66
|
</ValidatorProvider>;
|
|
67
67
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React, { createContext, Dispatch, useContext, useEffect, useMemo, useReducer, useRef } from "react";
|
|
2
|
+
import { useApp } from "react-admin-base";
|
|
3
|
+
|
|
4
|
+
const ThemeContext = createContext(null as any);
|
|
5
|
+
const AllThemesContext = createContext(null as any);
|
|
6
|
+
|
|
7
|
+
export function useTheme() {
|
|
8
|
+
return useContext(ThemeContext);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function useAllThemes() {
|
|
12
|
+
return useContext(AllThemesContext);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function useLocalStorage(key: string) : [string, Dispatch<string>] {
|
|
16
|
+
const app = useApp();
|
|
17
|
+
|
|
18
|
+
const _key = app.id + '_' + key;
|
|
19
|
+
|
|
20
|
+
const previousValue = useMemo(() => localStorage.getItem(_key), [_key]);
|
|
21
|
+
|
|
22
|
+
return useReducer((_: string, newValue) => {
|
|
23
|
+
localStorage.setItem(_key, newValue);
|
|
24
|
+
return newValue;
|
|
25
|
+
}, previousValue);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default function ThemeProvider({ themes, defaultTheme, children }) {
|
|
29
|
+
const state = useLocalStorage('theme');
|
|
30
|
+
const [ theme, setTheme ] = state;
|
|
31
|
+
|
|
32
|
+
const rTheme = theme || defaultTheme || 'light';
|
|
33
|
+
|
|
34
|
+
useEffect(function() {
|
|
35
|
+
const promise = (themes[rTheme] || themes[defaultTheme]).css()
|
|
36
|
+
.then(css => {
|
|
37
|
+
css.default.use();
|
|
38
|
+
return css;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return function() {
|
|
42
|
+
promise.then(css => css.default.unuse());
|
|
43
|
+
};
|
|
44
|
+
}, [ theme ]);
|
|
45
|
+
|
|
46
|
+
const val = useMemo(() => [rTheme, setTheme], [rTheme, setTheme]);
|
|
47
|
+
|
|
48
|
+
return <AllThemesContext.Provider value={themes}>
|
|
49
|
+
<ThemeContext.Provider value={val}>
|
|
50
|
+
{ children }
|
|
51
|
+
</ThemeContext.Provider>
|
|
52
|
+
</AllThemesContext.Provider>;
|
|
53
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -17,8 +17,10 @@ import CheckBox from './Components/CheckBox';
|
|
|
17
17
|
import ErrorBoundary from './Components/ErrorBoundary';
|
|
18
18
|
import { useMenuState, useIsMobile } from './Components/MenuState';
|
|
19
19
|
import TopProgressBar from './Components/TopProgressBar';
|
|
20
|
+
import ThemeProvider, { useTheme, useAllThemes } from './Components/ThemeProvider';
|
|
20
21
|
|
|
21
22
|
export {
|
|
23
|
+
ThemeProvider, useTheme, useAllThemes,
|
|
22
24
|
useIsMobile, useMenuState,
|
|
23
25
|
TopProgressBar,
|
|
24
26
|
CRUD, ModalEntityEditor, CRUDActions,
|
package/watch.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
|
|
2
|
+
const rewire = require('rewire');
|
|
3
|
+
const webpackConfig = rewire('react-scripts/scripts/start');
|
|
4
|
+
const oldConfigFactory = webpackConfig.__get__('configFactory');
|
|
5
|
+
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
webpackConfig.__set__('configFactory', function(env) {
|
|
10
|
+
const config = oldConfigFactory(env);
|
|
11
|
+
|
|
12
|
+
// disable use modules outside of src
|
|
13
|
+
config.resolve.plugins = config.resolve.plugins.filter(plugin => !(plugin instanceof ModuleScopePlugin));
|
|
14
|
+
|
|
15
|
+
// disable local node_modules/ path
|
|
16
|
+
config.resolve.modules.shift();
|
|
17
|
+
|
|
18
|
+
// add aliased packages from /opt/packages
|
|
19
|
+
for (const alias of find_custom_packages('/opt/packages')){
|
|
20
|
+
config.resolve.alias[alias.name] = alias.path;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
addLazyLoadingStyleLoader(config.module);
|
|
24
|
+
|
|
25
|
+
console.log(config);
|
|
26
|
+
//process.exit(0);
|
|
27
|
+
|
|
28
|
+
return config;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
function* find_custom_packages(location) {
|
|
32
|
+
const dir = fs.opendirSync(location, { withFileTypes: true });
|
|
33
|
+
let dirent;
|
|
34
|
+
while ((dirent = dir.readSync()) !== null) {
|
|
35
|
+
if (dirent.isSymbolicLink()) {
|
|
36
|
+
yield {name: dirent.name, path: fs.realpathSync(path.join(location, dirent.name))};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
dir.closeSync();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function addLazyLoadingStyleLoader(config) {
|
|
43
|
+
const cssLoader = config.rules[1].oneOf[5];
|
|
44
|
+
|
|
45
|
+
config.rules[1].oneOf.splice(5, 2, {
|
|
46
|
+
...cssLoader,
|
|
47
|
+
use: [
|
|
48
|
+
{
|
|
49
|
+
loader: cssLoader.use[0],
|
|
50
|
+
options: {
|
|
51
|
+
injectType: 'lazyStyleTag'
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
cssLoader.use[1],
|
|
55
|
+
cssLoader.use[2]
|
|
56
|
+
]
|
|
57
|
+
});
|
|
58
|
+
}
|