@applica-software-guru/react-admin 1.3.149 → 1.3.151
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/dist/components/ra-fields/LocalizedTextField.d.ts +5 -0
- package/dist/components/ra-fields/LocalizedTextField.d.ts.map +1 -0
- package/dist/components/ra-fields/index.d.ts +2 -1
- package/dist/components/ra-fields/index.d.ts.map +1 -1
- package/dist/components/ra-inputs/LocalizedTextInput.d.ts +6 -0
- package/dist/components/ra-inputs/LocalizedTextInput.d.ts.map +1 -0
- package/dist/components/ra-inputs/index.d.ts +2 -1
- package/dist/components/ra-inputs/index.d.ts.map +1 -1
- package/dist/react-admin.cjs.js +57 -57
- package/dist/react-admin.cjs.js.map +1 -1
- package/dist/react-admin.es.js +6744 -6693
- package/dist/react-admin.es.js.map +1 -1
- package/dist/react-admin.umd.js +58 -58
- package/dist/react-admin.umd.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/localizedValue.d.ts +11 -0
- package/dist/utils/localizedValue.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/components/ra-fields/LocalizedTextField.tsx +46 -0
- package/src/components/ra-fields/index.jsx +2 -0
- package/src/components/ra-inputs/LocalizedTextInput.tsx +77 -0
- package/src/components/ra-inputs/index.jsx +2 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/localizedValue.ts +14 -0
package/dist/utils/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type ILocalizedValue<T> = {
|
|
2
|
+
[key: string]: T;
|
|
3
|
+
};
|
|
4
|
+
declare function localizedValueHasAllLocales<T>(value?: ILocalizedValue<T>, locales?: Array<{
|
|
5
|
+
name: string;
|
|
6
|
+
locale: string;
|
|
7
|
+
}>, options?: {
|
|
8
|
+
isEmpty?: (v: T) => boolean;
|
|
9
|
+
}): boolean;
|
|
10
|
+
export { localizedValueHasAllLocales };
|
|
11
|
+
//# sourceMappingURL=localizedValue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localizedValue.d.ts","sourceRoot":"","sources":["../../../src/utils/localizedValue.ts"],"names":[],"mappings":"AACA,KAAK,eAAe,CAAC,CAAC,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAA;CAAE,CAAC;AAE/C,iBAAS,2BAA2B,CAAC,CAAC,EACpC,KAAK,GAAE,eAAe,CAAC,CAAC,CAAM,EAC9B,OAAO,GAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAM,EACrD,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAA;CAAO,GAC5C,OAAO,CAIT;AAED,OAAO,EAAE,2BAA2B,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import { TextFieldProps } from 'ra-ui-materialui';
|
|
3
|
+
import { Stack, Typography, useTheme } from '@mui/material';
|
|
4
|
+
import { useLocaleState, useLocales, useRecordContext } from 'ra-core';
|
|
5
|
+
import TextField from './TextField';
|
|
6
|
+
import { FlagOutlined, FlagFilled } from '@ant-design/icons';
|
|
7
|
+
import { useSx } from '../../hooks';
|
|
8
|
+
import { localizedValueHasAllLocales } from '../../utils';
|
|
9
|
+
import { ReactElement, useMemo } from 'react';
|
|
10
|
+
import { Tooltip } from '../@extended';
|
|
11
|
+
|
|
12
|
+
type ILocalizedTextFieldProps = TextFieldProps;
|
|
13
|
+
|
|
14
|
+
function LocalizedTextField(props: ILocalizedTextFieldProps) {
|
|
15
|
+
const theme = useTheme(),
|
|
16
|
+
locales = useLocales(),
|
|
17
|
+
{ source = '' } = props,
|
|
18
|
+
record = useRecordContext(props),
|
|
19
|
+
value = record[source],
|
|
20
|
+
isMissingLocalizations = !localizedValueHasAllLocales(value, locales),
|
|
21
|
+
sx = useSx(props, { flex: 1 }),
|
|
22
|
+
[currentLocale] = useLocaleState(),
|
|
23
|
+
IconElement: ReactElement = useMemo(() => {
|
|
24
|
+
return isMissingLocalizations ? <FlagFilled style={{ color: theme.palette.warning.main }} /> : <FlagOutlined />;
|
|
25
|
+
}, [isMissingLocalizations]),
|
|
26
|
+
tooltipTitle = useMemo(() => {
|
|
27
|
+
return (
|
|
28
|
+
<Stack>
|
|
29
|
+
{_.map(locales, (l, index) => {
|
|
30
|
+
return <Typography key={index}>{`${l.locale.toUpperCase()}: ${(value ?? {})[l.locale] ?? ''}`}</Typography>;
|
|
31
|
+
})}
|
|
32
|
+
</Stack>
|
|
33
|
+
);
|
|
34
|
+
}, [value, locales]);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Tooltip title={tooltipTitle} arrow={false}>
|
|
38
|
+
<Stack alignItems="center" direction="row" gap={1}>
|
|
39
|
+
{IconElement}
|
|
40
|
+
<TextField {...props} source={`${source}.${currentLocale}`} sx={sx} />
|
|
41
|
+
</Stack>
|
|
42
|
+
</Tooltip>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default LocalizedTextField;
|
|
@@ -7,6 +7,7 @@ import EmailField from './EmailField';
|
|
|
7
7
|
import FileField from './FileField';
|
|
8
8
|
import FunctionField from './FunctionField';
|
|
9
9
|
import ImageField from './ImageField';
|
|
10
|
+
import LocalizedTextField from './LocalizedTextField';
|
|
10
11
|
import ReadonlyField from './ReadonlyField';
|
|
11
12
|
import ReferenceManyField from './ReferenceManyField';
|
|
12
13
|
import SizeField from './SizeField';
|
|
@@ -21,6 +22,7 @@ export {
|
|
|
21
22
|
FileField,
|
|
22
23
|
FunctionField,
|
|
23
24
|
ImageField,
|
|
25
|
+
LocalizedTextField,
|
|
24
26
|
ReadonlyField,
|
|
25
27
|
ReferenceManyField,
|
|
26
28
|
SizeField,
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import { ReactElement, useCallback, useMemo, useState } from 'react';
|
|
3
|
+
import { Box, Chip, ListItemText, Menu, MenuItem, PopoverOrigin, Typography } from '@mui/material';
|
|
4
|
+
import { useInput, useLocaleState, useLocales } from 'ra-core';
|
|
5
|
+
import { TextInputProps } from 'ra-ui-materialui';
|
|
6
|
+
import TextInput from './TextInput';
|
|
7
|
+
import { localizedValueHasAllLocales } from '../../utils';
|
|
8
|
+
import { useWatch } from 'react-hook-form';
|
|
9
|
+
import LabeledInput, { LabeledInputProps } from './LabeledInput';
|
|
10
|
+
|
|
11
|
+
type ILocalizedTextInputProps = TextInputProps & LabeledInputProps;
|
|
12
|
+
|
|
13
|
+
const ANCHOR_ORIGIN: PopoverOrigin = { vertical: 'bottom', horizontal: 'right' },
|
|
14
|
+
TRANSFORM_ORIGIN: PopoverOrigin = { vertical: 'top', horizontal: 'right' };
|
|
15
|
+
|
|
16
|
+
function LocalizedTextInput(props: ILocalizedTextInputProps) {
|
|
17
|
+
const { source } = props,
|
|
18
|
+
{ fieldState } = useInput(props),
|
|
19
|
+
value = useWatch({ name: source }),
|
|
20
|
+
{ error } = fieldState,
|
|
21
|
+
locales = useLocales(),
|
|
22
|
+
isMissingLocalizations = !localizedValueHasAllLocales(value, locales),
|
|
23
|
+
[currentLocale] = useLocaleState(),
|
|
24
|
+
[locale, setLocale] = useState(currentLocale),
|
|
25
|
+
[anchorEl, setAnchorEl] = useState<null | HTMLDivElement>(null),
|
|
26
|
+
open = Boolean(anchorEl),
|
|
27
|
+
toggle = useCallback((e: React.MouseEvent<HTMLDivElement>) => setAnchorEl(open ? null : e.currentTarget), [open, setAnchorEl]),
|
|
28
|
+
handleClose = useCallback(() => setAnchorEl(null), [setAnchorEl]),
|
|
29
|
+
MenuItems: Array<ReactElement> = useMemo(() => {
|
|
30
|
+
return _.map(locales, (l, index) => {
|
|
31
|
+
return (
|
|
32
|
+
<MenuItem
|
|
33
|
+
key={index}
|
|
34
|
+
onClick={() => {
|
|
35
|
+
setLocale(l.locale);
|
|
36
|
+
handleClose();
|
|
37
|
+
}}
|
|
38
|
+
>
|
|
39
|
+
<ListItemText primary={`${l.locale.toUpperCase()}: ${(value ?? {})[l.locale] ?? ''}`} />
|
|
40
|
+
</MenuItem>
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
}, [locales, setLocale, handleClose, value]);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<LabeledInput {...props} helperText={error?.message}>
|
|
47
|
+
<Box flex={1}>
|
|
48
|
+
{_.map(locales, (l, index) => {
|
|
49
|
+
return (
|
|
50
|
+
<TextInput
|
|
51
|
+
key={index}
|
|
52
|
+
{...props}
|
|
53
|
+
source={`${source}.${l.locale}`}
|
|
54
|
+
sx={{ width: '100%', display: l.locale === locale ? 'inline-flex' : 'none' }}
|
|
55
|
+
label={false}
|
|
56
|
+
InputProps={{
|
|
57
|
+
endAdornment: (
|
|
58
|
+
<Chip
|
|
59
|
+
label={<Typography variant="button">{locale}</Typography>}
|
|
60
|
+
size="small"
|
|
61
|
+
onClick={toggle}
|
|
62
|
+
color={isMissingLocalizations ? 'warning' : undefined}
|
|
63
|
+
/>
|
|
64
|
+
)
|
|
65
|
+
}}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
})}
|
|
69
|
+
<Menu anchorEl={anchorEl} open={open} anchorOrigin={ANCHOR_ORIGIN} transformOrigin={TRANSFORM_ORIGIN} onClose={handleClose}>
|
|
70
|
+
{MenuItems}
|
|
71
|
+
</Menu>
|
|
72
|
+
</Box>
|
|
73
|
+
</LabeledInput>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export default LocalizedTextInput;
|
|
@@ -9,6 +9,7 @@ import FileInput from './FileInput';
|
|
|
9
9
|
import ImageInput from './ImageInput';
|
|
10
10
|
import LabeledArrayInput from './LabeledArrayInput';
|
|
11
11
|
import LabeledInput from './LabeledInput';
|
|
12
|
+
import LocalizedTextInput from './LocalizedTextInput';
|
|
12
13
|
import NumberInput from './NumberInput';
|
|
13
14
|
import RecordInput from './RecordInput';
|
|
14
15
|
import ReferenceArrayInput from './ReferenceArrayInput';
|
|
@@ -32,6 +33,7 @@ export {
|
|
|
32
33
|
ImageInput,
|
|
33
34
|
LabeledArrayInput,
|
|
34
35
|
LabeledInput,
|
|
36
|
+
LocalizedTextInput,
|
|
35
37
|
NumberInput,
|
|
36
38
|
RecordInput,
|
|
37
39
|
ReferenceArrayInput,
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
type ILocalizedValue<T> = { [key: string]: T };
|
|
3
|
+
|
|
4
|
+
function localizedValueHasAllLocales<T>(
|
|
5
|
+
value: ILocalizedValue<T> = {},
|
|
6
|
+
locales: Array<{ name: string; locale: string }> = [],
|
|
7
|
+
options: { isEmpty?: (v: T) => boolean } = {}
|
|
8
|
+
): boolean {
|
|
9
|
+
const { isEmpty = _.isEmpty } = options;
|
|
10
|
+
|
|
11
|
+
return !_.some(locales, (l) => isEmpty((value ?? {})[l.locale]));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { localizedValueHasAllLocales };
|