tp-react-elements 3.0.9 → 3.0.11
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/_virtual/index.esm11.js +2 -2
- package/dist/_virtual/index.esm12.js +2 -2
- package/dist/_virtual/index.esm13.js +2 -2
- package/dist/auth/authContext.d.ts +8 -0
- package/dist/auth/authContext.esm.js +13 -2
- package/dist/components/Form/FormActiveSwitch.d.ts +9 -0
- package/dist/components/Form/FormActiveSwitch.esm.js +64 -1
- package/dist/components/FormComponents/FormRadioGroup/FormRadioGroup.esm.js +16 -11
- package/dist/components/FormComponents/FormTextField/FormTextField.esm.js +2 -1
- package/dist/components/FormComponents/Select/MultiSelectv1.esm.js +43 -7
- package/dist/components/FormComponents/Select/SingleSelect.esm.js +1 -1
- package/dist/components/PaginatedGrid/GenericPaginatedGrid.d.ts +17 -1
- package/dist/components/PaginatedGrid/GenericPaginatedGrid.esm.js +7 -3
- package/dist/node_modules/react-date-range/dist/components/DateInput/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DayCell/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/InputRangeField/index.esm.js +1 -1
- package/dist/utils/Constants/FormConstants.d.ts +2 -0
- package/dist/utils/Constants/FormConstants.esm.js +4 -2
- package/dist/utils/Interface/FormInterface.d.ts +10 -0
- package/dist/utils/Interface/MainInterface.d.ts +31 -0
- package/dist/utils/index.esm.js +1 -1
- package/package.json +1 -1
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var InputRangeField = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { InputRangeField as __exports };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var DayCell = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { DayCell as __exports };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var DateInput = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { DateInput as __exports };
|
|
@@ -16,4 +16,12 @@ interface AuthProviderProps {
|
|
|
16
16
|
}
|
|
17
17
|
export declare const TPElementsProvider: React.FC<AuthProviderProps>;
|
|
18
18
|
export declare const useAuth: () => AuthContextType;
|
|
19
|
+
/**
|
|
20
|
+
* Same `projectTheme` as `useAuth()`, but never throws when the tree isn't wrapped in
|
|
21
|
+
* `<TPElementsProvider>` — just returns `undefined`. Components rendered deep inside generic
|
|
22
|
+
* form/grid utilities (toggle switches, radio groups, etc.) use this instead of `useAuth()` so
|
|
23
|
+
* that consumers who never opted into `TPElementsProvider` keep working exactly as before,
|
|
24
|
+
* rather than crashing the moment a themeable field type is used.
|
|
25
|
+
*/
|
|
26
|
+
export declare const useOptionalProjectTheme: () => ProjectThemePropsTp | undefined;
|
|
19
27
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { createContext,
|
|
2
|
+
import { createContext, useContext, useState } from 'react';
|
|
3
3
|
|
|
4
4
|
const AuthContext = createContext(undefined);
|
|
5
5
|
const TPElementsProvider = ({ children, projectTheme }) => {
|
|
@@ -22,5 +22,16 @@ const useAuth = () => {
|
|
|
22
22
|
}
|
|
23
23
|
return context;
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Same `projectTheme` as `useAuth()`, but never throws when the tree isn't wrapped in
|
|
27
|
+
* `<TPElementsProvider>` — just returns `undefined`. Components rendered deep inside generic
|
|
28
|
+
* form/grid utilities (toggle switches, radio groups, etc.) use this instead of `useAuth()` so
|
|
29
|
+
* that consumers who never opted into `TPElementsProvider` keep working exactly as before,
|
|
30
|
+
* rather than crashing the moment a themeable field type is used.
|
|
31
|
+
*/
|
|
32
|
+
const useOptionalProjectTheme = () => {
|
|
33
|
+
const context = useContext(AuthContext);
|
|
34
|
+
return context?.projectTheme;
|
|
35
|
+
};
|
|
25
36
|
|
|
26
|
-
export { TPElementsProvider, useAuth };
|
|
37
|
+
export { TPElementsProvider, useAuth, useOptionalProjectTheme };
|
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
import '../Form/FormsStyles.scss';
|
|
2
|
+
/**
|
|
3
|
+
* `toggleSwitch` field renderer.
|
|
4
|
+
*
|
|
5
|
+
* By default (no `TPToggleSwitch` entry in the consuming app's `projectTheme`) this renders the
|
|
6
|
+
* original wide pill switch unchanged — every existing consumer of this package sees no visual
|
|
7
|
+
* difference. Passing `projectTheme.Styles.Component.TPToggleSwitch` to `<TPElementsProvider>`
|
|
8
|
+
* opts an app into a compact iOS-style switch with a title/description card instead, using
|
|
9
|
+
* `item.label` as the title and `item.helperText` as the description.
|
|
10
|
+
*/
|
|
2
11
|
declare const FormActiveSwitch: ({ props }: any) => import("react/jsx-runtime").JSX.Element;
|
|
3
12
|
export default FormActiveSwitch;
|
|
@@ -1,15 +1,78 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { Controller } from 'react-hook-form';
|
|
3
|
+
import { useOptionalProjectTheme } from '../../auth/authContext.esm.js';
|
|
3
4
|
|
|
4
5
|
// Static — hoisted so they aren't rebuilt on every render.
|
|
5
6
|
const FIELDSET_STYLE = { border: 'none', padding: 0, margin: 0 };
|
|
6
7
|
const LEGEND_STYLE = { fontSize: '12px', paddingRight: 10 };
|
|
7
8
|
const LABEL_STYLE = { textTransform: 'none' };
|
|
9
|
+
const CARD_STYLE = {
|
|
10
|
+
display: 'flex',
|
|
11
|
+
alignItems: 'flex-start',
|
|
12
|
+
gap: 12,
|
|
13
|
+
background: '#FAFBFD',
|
|
14
|
+
border: '1px solid #E5EAF0',
|
|
15
|
+
borderRadius: 9,
|
|
16
|
+
padding: '13px 14px',
|
|
17
|
+
width: '100%',
|
|
18
|
+
boxSizing: 'border-box',
|
|
19
|
+
};
|
|
20
|
+
const TRACK_BASE = {
|
|
21
|
+
width: 34,
|
|
22
|
+
height: 19,
|
|
23
|
+
borderRadius: 10,
|
|
24
|
+
flex: 'none',
|
|
25
|
+
position: 'relative',
|
|
26
|
+
cursor: 'pointer',
|
|
27
|
+
marginTop: 2,
|
|
28
|
+
border: 'none',
|
|
29
|
+
padding: 0,
|
|
30
|
+
};
|
|
31
|
+
const KNOB_BASE = {
|
|
32
|
+
position: 'absolute',
|
|
33
|
+
top: 2,
|
|
34
|
+
width: 15,
|
|
35
|
+
height: 15,
|
|
36
|
+
borderRadius: '50%',
|
|
37
|
+
background: '#fff',
|
|
38
|
+
transition: 'left .18s ease',
|
|
39
|
+
};
|
|
40
|
+
const BADGE_BASE = {
|
|
41
|
+
display: 'inline-flex',
|
|
42
|
+
padding: '2px 8px',
|
|
43
|
+
borderRadius: 5,
|
|
44
|
+
fontSize: 9.5,
|
|
45
|
+
fontWeight: 700,
|
|
46
|
+
letterSpacing: '0.06em',
|
|
47
|
+
whiteSpace: 'nowrap',
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* `toggleSwitch` field renderer.
|
|
51
|
+
*
|
|
52
|
+
* By default (no `TPToggleSwitch` entry in the consuming app's `projectTheme`) this renders the
|
|
53
|
+
* original wide pill switch unchanged — every existing consumer of this package sees no visual
|
|
54
|
+
* difference. Passing `projectTheme.Styles.Component.TPToggleSwitch` to `<TPElementsProvider>`
|
|
55
|
+
* opts an app into a compact iOS-style switch with a title/description card instead, using
|
|
56
|
+
* `item.label` as the title and `item.helperText` as the description.
|
|
57
|
+
*/
|
|
8
58
|
const FormActiveSwitch = ({ props }) => {
|
|
9
59
|
const { control, item } = props;
|
|
10
60
|
const valueActive = item.value1 ?? 'A';
|
|
11
61
|
const valueInactive = item.value2 ?? 'I';
|
|
12
|
-
|
|
62
|
+
const toggleConfig = useOptionalProjectTheme()?.Styles?.Component?.TPToggleSwitch;
|
|
63
|
+
if (!toggleConfig) {
|
|
64
|
+
return (jsxs("fieldset", { className: "m-form__input", style: FIELDSET_STYLE, children: [item.label && (jsx("legend", { id: `${item.name}-label`, style: LEGEND_STYLE, children: item.label })), jsx(Controller, { name: item.name, control: control, render: ({ field }) => (jsxs("span", { className: "switch prestashop-switch fixed-width-lg", role: "radiogroup", "aria-labelledby": `${item.name}-label`, children: [jsx("input", { id: `${item.name}_on`, name: item.name, type: "radio", value: valueActive, checked: field.value === valueActive, onChange: () => field.onChange(valueActive), "aria-checked": field.value === valueActive }), jsx("label", { htmlFor: `${item.name}_on`, style: LABEL_STYLE, children: item.label1 ?? 'Active' }), jsx("input", { id: `${item.name}_off`, name: item.name, type: "radio", value: valueInactive, checked: field.value === valueInactive, onChange: () => field.onChange(valueInactive), "aria-checked": field.value === valueInactive }), jsx("label", { htmlFor: `${item.name}_off`, style: LABEL_STYLE, children: item.label2 ?? 'In Active' }), jsx("span", { className: "slide-button btn", "aria-hidden": "true" })] })) })] }));
|
|
65
|
+
}
|
|
66
|
+
const onColor = toggleConfig.onColor ?? '#00A86B';
|
|
67
|
+
const offColor = toggleConfig.offColor ?? '#D5DCE6';
|
|
68
|
+
return (jsx(Controller, { name: item.name, control: control, render: ({ field }) => {
|
|
69
|
+
const on = field.value === valueActive;
|
|
70
|
+
return (jsxs("div", { style: CARD_STYLE, children: [jsx("button", { type: "button", role: "switch", "aria-checked": on, "aria-labelledby": `${item.name}-label`, onClick: () => field.onChange(on ? valueInactive : valueActive), style: { ...TRACK_BASE, background: on ? onColor : offColor }, children: jsx("span", { style: { ...KNOB_BASE, left: on ? 17 : 2 } }) }), jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }, children: [jsx("span", { id: `${item.name}-label`, style: { fontSize: 12.5, fontWeight: 700, whiteSpace: 'nowrap' }, children: item.label }), jsx("span", { style: {
|
|
71
|
+
...BADGE_BASE,
|
|
72
|
+
background: on ? '#EEF7F2' : '#F2F5F9',
|
|
73
|
+
color: on ? '#00764A' : '#8A97A8',
|
|
74
|
+
}, children: on ? 'ON' : 'OFF' })] }), item.helperText && (jsx("div", { style: { fontSize: 11.5, color: '#6C757D', marginTop: 3, whiteSpace: 'normal', lineHeight: 1.5 }, children: item.helperText }))] })] }));
|
|
75
|
+
} }));
|
|
13
76
|
};
|
|
14
77
|
|
|
15
78
|
export { FormActiveSwitch as default };
|
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useMemo } from 'react';
|
|
2
3
|
import { FormControl, RadioGroup, FormControlLabel, Typography, Radio } from '@mui/material';
|
|
3
4
|
import { Controller } from 'react-hook-form';
|
|
4
5
|
import FormBottomField from '../FormBottomField/FormBottomField.esm.js';
|
|
5
6
|
import 'dayjs';
|
|
6
7
|
import { renderLabel } from '../../../utils/Constants/FormConstants.esm.js';
|
|
8
|
+
import { useOptionalProjectTheme } from '../../../auth/authContext.esm.js';
|
|
7
9
|
|
|
8
10
|
// Static — same for the group and for every radio option — hoisted so they
|
|
9
11
|
// aren't rebuilt on every render/option.
|
|
10
12
|
const RADIO_GROUP_SX = { gap: '8px' };
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
color: 'black',
|
|
14
|
-
'&.Mui-checked': {
|
|
15
|
-
color: '#1976d2', // blue when selected
|
|
16
|
-
},
|
|
17
|
-
'& .MuiSvgIcon-root': {
|
|
18
|
-
fontSize: 16, // controls the radio icon size
|
|
19
|
-
},
|
|
20
|
-
};
|
|
13
|
+
/** Stock MUI blue — unchanged default for every consumer that doesn't set `TPRadioGroup.checkedColor`. */
|
|
14
|
+
const DEFAULT_CHECKED_COLOR = '#1976d2';
|
|
21
15
|
/**
|
|
22
16
|
* FormRadioGroup Component
|
|
23
17
|
*
|
|
@@ -34,13 +28,24 @@ const RADIO_SX = {
|
|
|
34
28
|
* <FormRadioGroup props={formRenderProps} variant="outlined" />
|
|
35
29
|
*/
|
|
36
30
|
const FormRadioGroup = ({ props, variant }) => {
|
|
31
|
+
const checkedColor = useOptionalProjectTheme()?.Styles?.Component?.TPRadioGroup?.checkedColor ?? DEFAULT_CHECKED_COLOR;
|
|
32
|
+
const radioSx = useMemo(() => ({
|
|
33
|
+
padding: '6px 2px 6px 8px',
|
|
34
|
+
color: 'black',
|
|
35
|
+
'&.Mui-checked': {
|
|
36
|
+
color: checkedColor,
|
|
37
|
+
},
|
|
38
|
+
'& .MuiSvgIcon-root': {
|
|
39
|
+
fontSize: 16, // controls the radio icon size
|
|
40
|
+
},
|
|
41
|
+
}), [checkedColor]);
|
|
37
42
|
/**
|
|
38
43
|
* Renders a group of radio buttons with labels and validation support
|
|
39
44
|
*/
|
|
40
45
|
return (jsxs(Fragment, { children: [renderLabel(variant, props), jsx(FormControl, { component: "fieldset", children: jsx(Controller, { name: props.item.name, control: props.control, render: ({ field }) => (jsx(RadioGroup, { value: field.value || '', onChange: (e) => {
|
|
41
46
|
field.onChange(e.target.value); // update form state
|
|
42
47
|
props.item.onChangeFn && props.item.onChangeFn(e.target.value); // optional handler
|
|
43
|
-
}, row: true, sx: RADIO_GROUP_SX, children: props.item?.settings?.map((option, i) => (jsx(FormControlLabel, { value: option.name, control: jsx(Radio, { sx:
|
|
48
|
+
}, row: true, sx: RADIO_GROUP_SX, children: props.item?.settings?.map((option, i) => (jsx(FormControlLabel, { value: option.name, control: jsx(Radio, { sx: radioSx }), label: jsx(Typography, { fontSize: '11px', fontWeight: 'normal !important', children: option.label }) }, i))) })) }) }), jsx(FormBottomField, { ...props })] }));
|
|
44
49
|
};
|
|
45
50
|
|
|
46
51
|
export { FormRadioGroup as default };
|
|
@@ -47,7 +47,8 @@ const FormTextField = ({ props, variant }) => {
|
|
|
47
47
|
* Generates the field label based on variant type
|
|
48
48
|
* For non-standard variants, appends an asterisk if the field is required
|
|
49
49
|
*/
|
|
50
|
-
const
|
|
50
|
+
const isStaticLabel = props.item.labelVariant === 'static';
|
|
51
|
+
const label = variant !== 'standard' && !isStaticLabel ? `${props.item.label}${props.item.required ? ' *' : ''}` : '';
|
|
51
52
|
/**
|
|
52
53
|
* Handles input events with various text restrictions
|
|
53
54
|
*
|
|
@@ -11,9 +11,30 @@ import { useWatch } from 'react-hook-form';
|
|
|
11
11
|
import FormBottomField from '../FormBottomField/FormBottomField.esm.js';
|
|
12
12
|
import 'dayjs';
|
|
13
13
|
import { renderLabel } from '../../../utils/Constants/FormConstants.esm.js';
|
|
14
|
+
import { useOptionalProjectTheme } from '../../../auth/authContext.esm.js';
|
|
14
15
|
|
|
15
16
|
const ITEM_HEIGHT = 36;
|
|
16
17
|
const ITEM_PADDING_TOP = 2;
|
|
18
|
+
/**
|
|
19
|
+
* Base shape shared by both states of the themed option glyph — only the border/background
|
|
20
|
+
* (checked vs unchecked) differ, passed in by the caller via `Checkbox`'s own `icon` and
|
|
21
|
+
* `checkedIcon` props. Kept as plain style objects (not a component) so the existing
|
|
22
|
+
* `<Checkbox>` stays the single source of truth for check state/interaction; this only
|
|
23
|
+
* reskins what it renders.
|
|
24
|
+
*/
|
|
25
|
+
const themedGlyphSx = {
|
|
26
|
+
width: 15,
|
|
27
|
+
height: 15,
|
|
28
|
+
borderRadius: '4px',
|
|
29
|
+
display: 'flex',
|
|
30
|
+
alignItems: 'center',
|
|
31
|
+
justifyContent: 'center',
|
|
32
|
+
fontSize: 10,
|
|
33
|
+
fontWeight: 800,
|
|
34
|
+
color: '#fff',
|
|
35
|
+
border: '1.5px solid',
|
|
36
|
+
lineHeight: 1,
|
|
37
|
+
};
|
|
17
38
|
const extractValuesToArray = (inputString) => {
|
|
18
39
|
if (!inputString)
|
|
19
40
|
return [];
|
|
@@ -23,6 +44,7 @@ function MultiSelectV1({ props, variant, }) {
|
|
|
23
44
|
const [searchText, setSearchText] = useState('');
|
|
24
45
|
const options = props.item?.options || [];
|
|
25
46
|
const textfieldRef = useRef(null);
|
|
47
|
+
const multiSelectTheme = useOptionalProjectTheme()?.Styles?.Component?.TPMultiSelect;
|
|
26
48
|
// Ref to capture the width of the Select container
|
|
27
49
|
const containerRef = useRef(null);
|
|
28
50
|
const fieldValue = useWatch({ control: props.control, name: props.item.name });
|
|
@@ -56,7 +78,7 @@ function MultiSelectV1({ props, variant, }) {
|
|
|
56
78
|
const selectedOptions = useMemo(() => options.filter((item) => fieldValue?.split(',').some((value) => value === item.value)), [options, fieldValue]);
|
|
57
79
|
const selectedValuesString = selectedOptions.map((item) => item.label).join(' , ');
|
|
58
80
|
const isShowBorderError = !!props.errors?.[props.item.name];
|
|
59
|
-
return (jsx(Box, { children: jsxs(FormControl, { fullWidth: true, ref: containerRef, sx: { '& .MuiFormLabel-root': { top: -10 }, '& .MuiInputLabel-shrink': { top: 0 } }, children: [renderLabel(variant, props), variant !== 'standard' && (jsxs(InputLabel, { error: isShowBorderError, id: `${props.item.name}-ms-labelId`, children: [props.item.label, props.item.required ? ' *' : ''] })), jsxs(Select, { labelId: `${props.item.name}-ms-labelId`, id: `${props.item.name}-ms-select`, multiple: true, displayEmpty: true, error: isShowBorderError, disabled: props.item.disable, value: fieldValue ? extractValuesToArray(fieldValue) : [], onChange: handleChange, onOpen: () => {
|
|
81
|
+
return (jsx(Box, { children: jsxs(FormControl, { fullWidth: true, ref: containerRef, sx: { '& .MuiFormLabel-root': { top: -10 }, '& .MuiInputLabel-shrink': { top: 0 } }, children: [renderLabel(variant, props), variant !== 'standard' && props.item.labelVariant !== 'static' && (jsxs(InputLabel, { error: isShowBorderError, id: `${props.item.name}-ms-labelId`, children: [props.item.label, props.item.required ? ' *' : ''] })), jsxs(Select, { labelId: `${props.item.name}-ms-labelId`, id: `${props.item.name}-ms-select`, multiple: true, displayEmpty: true, error: isShowBorderError, disabled: props.item.disable, value: fieldValue ? extractValuesToArray(fieldValue) : [], onChange: handleChange, onOpen: () => {
|
|
60
82
|
if (!props.item.doNotEnableMultiselectOrder) {
|
|
61
83
|
setSavedSortValue(fieldValue);
|
|
62
84
|
}
|
|
@@ -67,7 +89,7 @@ function MultiSelectV1({ props, variant, }) {
|
|
|
67
89
|
setSavedSortValue(fieldValue);
|
|
68
90
|
}
|
|
69
91
|
props?.item?.onCloseMenu && props?.item?.onCloseMenu();
|
|
70
|
-
}, input: jsx(OutlinedInput, { label: variant !== 'standard' ? props.item.label : '' }), renderValue: () => (jsx(Tooltip, { title: selectedValuesString, children: jsx("span", { style: { display: 'block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: props.item.placeholder && selectedOptions.length === 0 ? (jsx("span", { style: { color: '#0009' }, children: props.item.placeholder })) : (selectedOptions.length > (props.item.multiSelectLabelLength || 3)
|
|
92
|
+
}, input: jsx(OutlinedInput, { label: variant !== 'standard' && props.item.labelVariant !== 'static' ? props.item.label : '' }), renderValue: () => (jsx(Tooltip, { title: selectedValuesString, children: jsx("span", { style: { display: 'block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: props.item.placeholder && selectedOptions.length === 0 ? (jsx("span", { style: { color: '#0009' }, children: props.item.placeholder })) : (selectedOptions.length > (props.item.multiSelectLabelLength || 3)
|
|
71
93
|
? `${selectedOptions.length} Selected`
|
|
72
94
|
: selectedValuesString) }) })), MenuProps: {
|
|
73
95
|
PaperProps: {
|
|
@@ -111,15 +133,29 @@ function MultiSelectV1({ props, variant, }) {
|
|
|
111
133
|
whiteSpace: 'normal',
|
|
112
134
|
wordBreak: 'break-all',
|
|
113
135
|
alignItems: 'center',
|
|
114
|
-
py: 0.5,
|
|
115
|
-
px: 2,
|
|
136
|
+
py: multiSelectTheme ? 1 : 0.5,
|
|
137
|
+
px: multiSelectTheme ? 1.25 : 2,
|
|
116
138
|
minHeight: ITEM_HEIGHT,
|
|
117
|
-
|
|
118
|
-
|
|
139
|
+
...(multiSelectTheme && {
|
|
140
|
+
mx: 0.5,
|
|
141
|
+
borderRadius: '6px',
|
|
142
|
+
'&.Mui-selected, &.Mui-selected:hover': {
|
|
143
|
+
backgroundColor: multiSelectTheme.selectedRowBg ?? '#F4F8FC',
|
|
144
|
+
},
|
|
145
|
+
}),
|
|
146
|
+
}, children: [jsx(Checkbox, { checked: isChecked, size: "small", sx: multiSelectTheme ? { p: 0, mr: 1.25, pointerEvents: 'none' } : { p: 1, mr: 1, pointerEvents: 'none' }, ...(multiSelectTheme && {
|
|
147
|
+
icon: (jsx(Box, { component: "span", sx: { ...themedGlyphSx, borderColor: multiSelectTheme.uncheckedBorderColor ?? '#C9D3E0', background: '#fff' } })),
|
|
148
|
+
checkedIcon: (jsx(Box, { component: "span", sx: { ...themedGlyphSx, borderColor: multiSelectTheme.checkedColor ?? '#073B6D', background: multiSelectTheme.checkedColor ?? '#073B6D' }, children: "\u2713" })),
|
|
149
|
+
}) }), jsx(ListItemText, { className: 'Mui-multi-select-option', primary: option.label, primaryTypographyProps: {
|
|
150
|
+
fontSize: multiSelectTheme ? 12.5 : (props.item?.optionFontSize || '13px'),
|
|
119
151
|
sx: {
|
|
120
152
|
whiteSpace: 'normal',
|
|
121
153
|
wordBreak: 'break-all',
|
|
122
|
-
lineHeight: '1.2'
|
|
154
|
+
lineHeight: multiSelectTheme ? 1.35 : '1.2',
|
|
155
|
+
...(multiSelectTheme && {
|
|
156
|
+
fontWeight: 600,
|
|
157
|
+
color: isChecked ? (multiSelectTheme.checkedColor ?? '#073B6D') : '#42536B',
|
|
158
|
+
}),
|
|
123
159
|
}
|
|
124
160
|
} })] }, option.value));
|
|
125
161
|
})) : (jsx(MenuItem, { disabled: true, children: "No data Found" }))] }), jsx(FormBottomField, { ...props })] }) }, props.item.name));
|
|
@@ -56,7 +56,7 @@ const SingleSelect = ({ props, variant }) => {
|
|
|
56
56
|
opacity: option.disable ? 0.5 : 1,
|
|
57
57
|
pointerEvents: option.disable ? 'none' : 'auto',
|
|
58
58
|
}, key: option.value }, option.label));
|
|
59
|
-
}, renderInput: (params) => (jsx(TextField, { ...params, placeholder: props.item.placeholder, error: isShowBorderError, label: variant !== 'standard'
|
|
59
|
+
}, renderInput: (params) => (jsx(TextField, { ...params, placeholder: props.item.placeholder, error: isShowBorderError, label: variant !== 'standard' && props.item.labelVariant !== 'static'
|
|
60
60
|
? `${props.item.label}${props.item.required ? ' *' : ''}`
|
|
61
61
|
: '', inputProps: {
|
|
62
62
|
...params.inputProps,
|
|
@@ -119,6 +119,22 @@ export interface GenericPaginatedGridProps<TData extends object> {
|
|
|
119
119
|
disableResponsive?: boolean;
|
|
120
120
|
/** Choices shown in the "Rows per page" footer dropdown. Default: [1 000, 5 000, 10 000]. */
|
|
121
121
|
pageSizeOptions?: number[];
|
|
122
|
+
/**
|
|
123
|
+
* Initial "Rows per page" value, shown in the footer before the user touches the dropdown.
|
|
124
|
+
*
|
|
125
|
+
* The grid never slices rows client-side (`manualPagination: true`, no row model) — whatever
|
|
126
|
+
* `fetchPage` resolves with for a page **is** that page, shown in full. `pageSize` only feeds
|
|
127
|
+
* the footer's count text and the Next-page button's math, so it must match how many rows
|
|
128
|
+
* `fetchPage` actually returns per call, same as `batchSize` always had to. The two exist
|
|
129
|
+
* separately only because `batchSize` doubles as "rows per fetch" documentation elsewhere;
|
|
130
|
+
* use `pageSize` when you want the initial dropdown value to be authoritative without
|
|
131
|
+
* reinterpreting `batchSize`'s meaning at every call site.
|
|
132
|
+
*
|
|
133
|
+
* Default: `batchSize` (unchanged behaviour — identical to how the initial page size worked
|
|
134
|
+
* before this prop existed). If this value isn't already in `pageSizeOptions`, it's folded in
|
|
135
|
+
* automatically so the dropdown always has a matching selected entry.
|
|
136
|
+
*/
|
|
137
|
+
pageSize?: number;
|
|
122
138
|
/**
|
|
123
139
|
* Show the Global Search input expanded by default (instead of requiring a
|
|
124
140
|
* click on the search icon to reveal it). The icon remains in the top-right
|
|
@@ -306,5 +322,5 @@ export interface GenericPaginatedGridProps<TData extends object> {
|
|
|
306
322
|
*/
|
|
307
323
|
enableExpanding?: boolean;
|
|
308
324
|
}
|
|
309
|
-
declare function GenericPaginatedGrid<TData extends object>({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize, exportFilename, gridId, tableHeight, tableMinHeight, tableMaxHeight, autoFillViewport, layoutMode, uiDensity, uiDensityOptions, responsiveBreakpoints, disableResponsive, pageSizeOptions, showGlobalSearchByDefault, showDensityToggle, headerBgColor, exportHeaderBgColor, exportHeaderTextColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, getRowSx, getHeaderSx, renderDetailPanel, enableExpanding, }: GenericPaginatedGridProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
325
|
+
declare function GenericPaginatedGrid<TData extends object>({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize, exportFilename, gridId, tableHeight, tableMinHeight, tableMaxHeight, autoFillViewport, layoutMode, uiDensity, uiDensityOptions, responsiveBreakpoints, disableResponsive, pageSizeOptions, pageSize, showGlobalSearchByDefault, showDensityToggle, headerBgColor, exportHeaderBgColor, exportHeaderTextColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, getRowSx, getHeaderSx, renderDetailPanel, enableExpanding, }: GenericPaginatedGridProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
310
326
|
export default GenericPaginatedGrid;
|
|
@@ -304,7 +304,7 @@ const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoa
|
|
|
304
304
|
}, children: pageIndex + 1 }), jsx(Tooltip, { title: "Next page", children: jsx("span", { children: jsx(IconButton, { id: `${gridId}_next_page_icon`, size: "small", onClick: onNext, disabled: !canNext, sx: { p: 0.5 }, children: jsx(ChevronRightIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Tooltip, { title: "Last page", children: jsx("span", { children: jsx(IconButton, { id: `${gridId}_last_page_icon`, size: "small", onClick: onLast, disabled: !canNext, sx: { p: 0.5 }, children: jsx(LastPageIcon, { sx: { fontSize: density.footerIconSize } }) }) }) })] })] }));
|
|
305
305
|
};
|
|
306
306
|
// ─── GenericPaginatedGrid ─────────────────────────────────────────────────────
|
|
307
|
-
function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize = 10000, exportFilename = 'export', gridId, tableHeight, tableMinHeight = '300px', tableMaxHeight, autoFillViewport = true, layoutMode = 'grid', uiDensity, uiDensityOptions, responsiveBreakpoints, disableResponsive = false, pageSizeOptions = [1000, 5000, 10000], showGlobalSearchByDefault = false, showDensityToggle = false, headerBgColor, exportHeaderBgColor, exportHeaderTextColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters = 4, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, getRowSx, getHeaderSx, renderDetailPanel, enableExpanding = !!renderDetailPanel, }) {
|
|
307
|
+
function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize = 10000, exportFilename = 'export', gridId, tableHeight, tableMinHeight = '300px', tableMaxHeight, autoFillViewport = true, layoutMode = 'grid', uiDensity, uiDensityOptions, responsiveBreakpoints, disableResponsive = false, pageSizeOptions = [1000, 5000, 10000], pageSize, showGlobalSearchByDefault = false, showDensityToggle = false, headerBgColor, exportHeaderBgColor, exportHeaderTextColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters = 4, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, getRowSx, getHeaderSx, renderDetailPanel, enableExpanding = !!renderDetailPanel, }) {
|
|
308
308
|
// ── Responsive tier detection ────────────────────────────────────────────────
|
|
309
309
|
// Three tiers (desktop / tablet / mobile) drive auto density, a progressively
|
|
310
310
|
// lower filter-chip cap, toolbar wrapping, and a stacked pagination footer —
|
|
@@ -392,9 +392,13 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
392
392
|
// ── State ──────────────────────────────────────────────────────────────────
|
|
393
393
|
const [filterValues, setFilterValues] = useState(defaultFilters);
|
|
394
394
|
const [visibleFilterIds, setVisibleFilterIds] = useState(defaultVisible);
|
|
395
|
+
const initialPageSize = pageSize ?? batchSize;
|
|
396
|
+
// The footer's "Rows per page" <Select> only highlights a value that's actually one of its
|
|
397
|
+
// <MenuItem>s — fold the initial page size in (deduped, ascending) so it's never orphaned.
|
|
398
|
+
const resolvedPageSizeOptions = useMemo(() => Array.from(new Set([...pageSizeOptions, initialPageSize])).sort((a, b) => a - b), [pageSizeOptions, initialPageSize]);
|
|
395
399
|
const [pagination, setPagination] = useState({
|
|
396
400
|
pageIndex: 0,
|
|
397
|
-
pageSize:
|
|
401
|
+
pageSize: initialPageSize,
|
|
398
402
|
});
|
|
399
403
|
const [sorting, setSorting] = useState([]);
|
|
400
404
|
const [columnFilters, setColumnFilters] = useState([]);
|
|
@@ -766,7 +770,7 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
766
770
|
availableColumns, effectiveMaxVisibleFilters, densityTokens, handleToggleFilter,
|
|
767
771
|
]);
|
|
768
772
|
const renderToolbarInternalActions = useCallback(({ table: t }) => (jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.5 }, children: [jsx(MRT_ToggleGlobalFilterButton, { table: t, id: `${resolvedGridId}_global_search_icon` }), jsx(MRT_ShowHideColumnsButton, { table: t, id: `${resolvedGridId}_columns_icon` }), showDensityToggle && (jsx(MRT_ToggleDensePaddingButton, { table: t, id: `${resolvedGridId}_density_icon` })), jsx(MRT_ToggleFullScreenButton, { table: t, id: `${resolvedGridId}_fullscreen_icon` })] })), [resolvedGridId, showDensityToggle]);
|
|
769
|
-
const renderBottomToolbar = useCallback(({ table: t }) => (jsx(PaginationFooter, { pageIndex: t.getState().pagination.pageIndex, pageSize: t.getState().pagination.pageSize, totalRecords: totalRecords, isFetching: isFetching, isLoading: isLoading, canPrev: t.getCanPreviousPage() && !isFetching, canNext: t.getCanNextPage() && !isFetching, onFirst: () => t.firstPage(), onPrev: () => t.previousPage(), onNext: () => t.nextPage(), onLast: () => t.lastPage(), onPageSizeChange: (s) => t.setPageSize(s), pageSizeOptions:
|
|
773
|
+
const renderBottomToolbar = useCallback(({ table: t }) => (jsx(PaginationFooter, { pageIndex: t.getState().pagination.pageIndex, pageSize: t.getState().pagination.pageSize, totalRecords: totalRecords, isFetching: isFetching, isLoading: isLoading, canPrev: t.getCanPreviousPage() && !isFetching, canNext: t.getCanNextPage() && !isFetching, onFirst: () => t.firstPage(), onPrev: () => t.previousPage(), onNext: () => t.nextPage(), onLast: () => t.lastPage(), onPageSizeChange: (s) => t.setPageSize(s), pageSizeOptions: resolvedPageSizeOptions, density: densityTokens, gridId: resolvedGridId, isStacked: isMobileTier, isClientFiltered: isFiltered, filteredRowCount: t.getFilteredRowModel().rows.length, pageRowCount: rows.length })), [totalRecords, isFetching, isLoading, resolvedPageSizeOptions, densityTokens, resolvedGridId, isMobileTier, isFiltered, rows]);
|
|
770
774
|
// ── Table instance ─────────────────────────────────────────────────────────
|
|
771
775
|
const table = useMaterialReactTable({
|
|
772
776
|
columns: processedColumns,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as DateInput } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as DateInput } from '../../../../../_virtual/index.esm13.js';
|
|
2
2
|
import require$$0__default from 'react';
|
|
3
3
|
import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
|
|
4
4
|
import { __require as requireClassnames } from '../../../../classnames/index.esm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as DayCell } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as DayCell } from '../../../../../_virtual/index.esm12.js';
|
|
2
2
|
import require$$0__default from 'react';
|
|
3
3
|
import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
|
|
4
4
|
import { __require as requireClassnames } from '../../../../classnames/index.esm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as InputRangeField } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as InputRangeField } from '../../../../../_virtual/index.esm11.js';
|
|
2
2
|
import require$$0__default from 'react';
|
|
3
3
|
import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
|
|
4
4
|
|
|
@@ -9,6 +9,8 @@ import { VariantProps, FormRenderProps } from '../Interface/FormInterface';
|
|
|
9
9
|
* @returns {JSX.Element | false} The rendered label element or false if not shown.
|
|
10
10
|
*/
|
|
11
11
|
export declare const renderLabel: (variant: VariantProps, props: FormRenderProps, showLabel?: boolean) => false | import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
/** True when this field should render its label outside/above the input instead of MUI's floating inline label — either because the caller forced it, or the field opted into `labelVariant: 'static'`. */
|
|
13
|
+
export declare const usesStaticLabel: (props: FormRenderProps) => boolean;
|
|
12
14
|
/**
|
|
13
15
|
* Formats a date string in "M/YYYY" or "MM/YYYY" format to "MM/01/YYYY".
|
|
14
16
|
*
|
|
@@ -9,7 +9,9 @@ import dayjs from 'dayjs';
|
|
|
9
9
|
* @param {boolean} [showLabel=false] - Whether to always show the label.
|
|
10
10
|
* @returns {JSX.Element | false} The rendered label element or false if not shown.
|
|
11
11
|
*/
|
|
12
|
-
const renderLabel = (variant, props, showLabel = false) => (variant === 'standard' || showLabel) && (jsxs("span", { id: `${props.item.name}-label`, className: "formInputlabel", style: { fontSize: '12px' }, children: [props.item.label, ' ', props.item.required && (jsx("span", { "aria-hidden": "true", style: { color: 'var(--mui-palette-error-main, #B3261E)' }, children: "*" }))] }));
|
|
12
|
+
const renderLabel = (variant, props, showLabel = false) => (variant === 'standard' || showLabel || props.item.labelVariant === 'static') && (jsxs("span", { id: `${props.item.name}-label`, className: "formInputlabel", style: { fontSize: '12px', ...(props.item.labelVariant === 'static' ? props.item.labelSx : {}) }, children: [props.item.label, ' ', props.item.required && (jsx("span", { "aria-hidden": "true", style: { color: 'var(--mui-palette-error-main, #B3261E)' }, children: "*" }))] }));
|
|
13
|
+
/** True when this field should render its label outside/above the input instead of MUI's floating inline label — either because the caller forced it, or the field opted into `labelVariant: 'static'`. */
|
|
14
|
+
const usesStaticLabel = (props) => props.item.labelVariant === 'static';
|
|
13
15
|
/**
|
|
14
16
|
* Formats a date string in "M/YYYY" or "MM/YYYY" format to "MM/01/YYYY".
|
|
15
17
|
*
|
|
@@ -75,4 +77,4 @@ const extractDate = (inputDateString) => {
|
|
|
75
77
|
return formattedDate;
|
|
76
78
|
};
|
|
77
79
|
|
|
78
|
-
export { extractDate, formatDateMonthAndYear, formatDayjsToCustomTime, parseCustomTime, renderLabel };
|
|
80
|
+
export { extractDate, formatDateMonthAndYear, formatDayjsToCustomTime, parseCustomTime, renderLabel, usesStaticLabel };
|
|
@@ -87,6 +87,16 @@ export interface FormSectionPropsItem {
|
|
|
87
87
|
id?: string;
|
|
88
88
|
className?: string;
|
|
89
89
|
dataAttr?: any;
|
|
90
|
+
/**
|
|
91
|
+
* Overrides how this field's label is positioned, regardless of the form-level `variant`.
|
|
92
|
+
* `'floating'` (default when omitted) keeps every existing consumer's current look —
|
|
93
|
+
* the label sits inside the input border and floats up on focus/fill. `'static'` renders
|
|
94
|
+
* the label as a fixed caption above the input instead (no floating, no MUI notch).
|
|
95
|
+
* Opt-in per field; omitting it changes nothing for existing usage.
|
|
96
|
+
*/
|
|
97
|
+
labelVariant?: 'floating' | 'static';
|
|
98
|
+
/** Style overrides for the label span when `labelVariant: 'static'` is used. */
|
|
99
|
+
labelSx?: SxProps<Theme>;
|
|
90
100
|
}
|
|
91
101
|
export type VariantProps = 'standard' | 'outlined' | '';
|
|
92
102
|
export interface FormRenderProps {
|
|
@@ -5,9 +5,40 @@ export interface ProjectComponentTPButton {
|
|
|
5
5
|
isEnableConfirmDialog: boolean;
|
|
6
6
|
sx?: SxProps<Theme>;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Optional brand colors for the `toggleSwitch` field. When omitted entirely (the default for
|
|
10
|
+
* every existing consumer), `FormActiveSwitch` renders its original pill-switch look unchanged.
|
|
11
|
+
* Providing this object opts an app into the compact iOS-style switch + title/description card.
|
|
12
|
+
*/
|
|
13
|
+
export interface ProjectComponentTPToggleSwitch {
|
|
14
|
+
onColor?: string;
|
|
15
|
+
offColor?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Optional checked-state color for `radio-group` fields. Omitted = the existing stock MUI blue
|
|
19
|
+
* (`#1976d2`) is unchanged for every current consumer.
|
|
20
|
+
*/
|
|
21
|
+
export interface ProjectComponentTPRadioGroup {
|
|
22
|
+
checkedColor?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Optional row/checkbox styling for `multiselect` (`MultiSelectV1`)'s dropdown options. Omitted
|
|
26
|
+
* entirely = the existing stock MUI `Checkbox` + default `MenuItem` selected-row tint are
|
|
27
|
+
* unchanged for every current consumer. Providing this swaps the checkbox for a compact
|
|
28
|
+
* rounded-square box and restyles the option row (padding/radius/selected background/text
|
|
29
|
+
* weight) to match a flatter, more custom design language.
|
|
30
|
+
*/
|
|
31
|
+
export interface ProjectComponentTPMultiSelect {
|
|
32
|
+
checkedColor?: string;
|
|
33
|
+
uncheckedBorderColor?: string;
|
|
34
|
+
selectedRowBg?: string;
|
|
35
|
+
}
|
|
8
36
|
export interface ProjectComponentStyles {
|
|
9
37
|
TPButton: ProjectComponentTPButton[];
|
|
10
38
|
TPButtonCommonSx: SxProps<Theme>;
|
|
39
|
+
TPToggleSwitch?: ProjectComponentTPToggleSwitch;
|
|
40
|
+
TPRadioGroup?: ProjectComponentTPRadioGroup;
|
|
41
|
+
TPMultiSelect?: ProjectComponentTPMultiSelect;
|
|
11
42
|
}
|
|
12
43
|
export interface ProjectThemeStyles {
|
|
13
44
|
Component: ProjectComponentStyles;
|
package/dist/utils/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { calculateTotalArrayValueTotal, checkIsDateIsBefore, findMenuHierarchy, getDesiredDate, getFormattedDate, getInitials, getUsernameFromEmail, handleDownloadReactTableDataExcel, lightenColor } from './Constants/FunctionConstants.esm.js';
|
|
2
|
-
export { extractDate, formatDateMonthAndYear, formatDayjsToCustomTime, parseCustomTime, renderLabel } from './Constants/FormConstants.esm.js';
|
|
2
|
+
export { extractDate, formatDateMonthAndYear, formatDayjsToCustomTime, parseCustomTime, renderLabel, usesStaticLabel } from './Constants/FormConstants.esm.js';
|
|
3
3
|
|
|
4
4
|
// Utility Functions - Helper functions for form operations and data manipulation
|