tp-react-elements 3.0.7 → 3.0.10
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.esm12.js +2 -2
- package/dist/_virtual/index.esm14.js +2 -2
- package/dist/_virtual/index.esm4.js +2 -2
- package/dist/_virtual/index.esm5.js +2 -2
- package/dist/_virtual/index.esm6.js +2 -2
- package/dist/_virtual/index.esm7.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/Form/FormRender.esm.js +1 -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/MultiSelectAutocomplete.esm.js +5 -2
- package/dist/components/FormComponents/Select/MultiSelectv1.esm.js +2 -2
- package/dist/components/FormComponents/Select/SingleSelect.esm.js +9 -5
- package/dist/components/FormComponents/Select/SingleSelectSearchApi.esm.js +1 -1
- package/dist/components/FormComponents/index.esm.js +1 -1
- package/dist/components/PaginatedGrid/GenericPaginatedGrid.d.ts +17 -1
- package/dist/components/PaginatedGrid/GenericPaginatedGrid.esm.js +26 -9
- package/dist/components/PaginatedGrid/types.d.ts +19 -0
- package/dist/node_modules/react-date-range/dist/components/Calendar/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DateRange/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DateRangePicker/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DefinedRange/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/InputRangeField/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/Month/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 +18 -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 Month = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { Month as __exports };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var DateRange = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { DateRange as __exports };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var DateRangePicker = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { DateRangePicker as __exports };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var Calendar = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { Calendar as __exports };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var DefinedRange = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { DefinedRange 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,6 +1,7 @@
|
|
|
1
1
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import require$$0__default, { lazy, Suspense } from 'react';
|
|
3
3
|
import FormCheckBox from '../FormComponents/FormCheckBox/FormCheckBox.esm.js';
|
|
4
|
+
import FormCheckBoxGroup from '../FormComponents/FormCheckBoxGroup/FormCheckBoxGroup.esm.js';
|
|
4
5
|
import SingleSelect from '../FormComponents/Select/SingleSelect.esm.js';
|
|
5
6
|
import MultiSelectAutocomplete from '../FormComponents/Select/MultiSelectAutocomplete.esm.js';
|
|
6
7
|
import SingleSelectNonAutoComplete from '../FormComponents/Select/SingleSelectNonAutoComplete.esm.js';
|
|
@@ -13,7 +14,6 @@ import SingleSelectSearchApi from '../FormComponents/Select/SingleSelectSearchAp
|
|
|
13
14
|
import DatetimepickerWrapper from '../FormComponents/DatePicker/DatetimepickerWrapper.esm.js';
|
|
14
15
|
import FormTextAreaField from '../FormComponents/FormTextAreaField/FormTextAreaField.esm.js';
|
|
15
16
|
import FormRadioGroup from '../FormComponents/FormRadioGroup/FormRadioGroup.esm.js';
|
|
16
|
-
import FormCheckBoxGroup from '../FormComponents/FormCheckBoxGroup/FormCheckBoxGroup.esm.js';
|
|
17
17
|
import FormNumberFieldDecimal from '../FormComponents/FormNumberField/FormNumberFieldDecimal.esm.js';
|
|
18
18
|
import FormNumberField from '../FormComponents/FormNumberField/FormNumberField.esm.js';
|
|
19
19
|
import PasswordField from '../FormComponents/PasswordField/PasswordField.esm.js';
|
|
@@ -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
|
*
|
|
@@ -72,7 +72,10 @@ const MultiSelectAutocomplete = ({ props, variant, maxChips = 2, }) => {
|
|
|
72
72
|
// ── Stable callbacks ───────────────────────────────────────────────────────
|
|
73
73
|
const getOptionLabelCb = useCallback((option) => String(option.label), []);
|
|
74
74
|
const isOptionEqualCb = useCallback((option, value) => String(option.value) === String(value.value), []);
|
|
75
|
-
const renderOptionCb = useCallback((renderProps, option, state) =>
|
|
75
|
+
const renderOptionCb = useCallback((renderProps, option, state) => {
|
|
76
|
+
const { key, ...otherProps } = renderProps;
|
|
77
|
+
return (jsxs("li", { ...otherProps, style: { fontSize: '11px' }, children: [jsx(Checkbox, { checked: state.selected, size: "small", sx: { mr: 1, p: '2px' } }), option.label] }, key));
|
|
78
|
+
}, []);
|
|
76
79
|
const chipSx = useMemo(() => ({
|
|
77
80
|
mr: 0.5,
|
|
78
81
|
height: 20,
|
|
@@ -109,7 +112,7 @@ const MultiSelectAutocomplete = ({ props, variant, maxChips = 2, }) => {
|
|
|
109
112
|
clearErrors?.(name);
|
|
110
113
|
}, [setValue, clearErrors, name, onChangeFn]);
|
|
111
114
|
// ── Render ─────────────────────────────────────────────────────────────────
|
|
112
|
-
return (jsx(Controller, { control: control, name: name, render: ({ field: { ref, onBlur: fieldOnBlur } }) => (jsxs(Fragment, { children: [renderLabel(variant, props), jsx(Autocomplete, { ref: ref, open: open, onOpen: () => setOpen(true), onClose: () => setOpen(false), multiple: true, disableCloseOnSelect: true, id: `${name}-autocomplete-multi`, options: options, value: selectedOptions, getOptionLabel: getOptionLabelCb, isOptionEqualToValue: isOptionEqualCb, getOptionDisabled: (option) => option.disable, onChange: handleChange, onBlur: (e) => {
|
|
115
|
+
return (jsx(Controller, { control: control, name: name, render: ({ field: { ref, onBlur: fieldOnBlur } }) => (jsxs(Fragment, { children: [renderLabel(variant, props), jsx(Autocomplete, { ref: ref, fullWidth: true, open: open, onOpen: () => setOpen(true), onClose: () => setOpen(false), multiple: true, disableCloseOnSelect: true, id: `${name}-autocomplete-multi`, options: options, value: selectedOptions, getOptionLabel: getOptionLabelCb, isOptionEqualToValue: isOptionEqualCb, getOptionDisabled: (option) => option.disable, onChange: handleChange, onBlur: (e) => {
|
|
113
116
|
fieldOnBlur();
|
|
114
117
|
handleBlur(e);
|
|
115
118
|
}, size: "small", disablePortal: false, autoHighlight: true, selectOnFocus: true, clearOnBlur: false, renderTags: (tagValue, getTagProps) => (jsx(Box, { ref: tagsContainerRef, sx: {
|
|
@@ -56,7 +56,7 @@ function MultiSelectV1({ props, variant, }) {
|
|
|
56
56
|
const selectedOptions = useMemo(() => options.filter((item) => fieldValue?.split(',').some((value) => value === item.value)), [options, fieldValue]);
|
|
57
57
|
const selectedValuesString = selectedOptions.map((item) => item.label).join(' , ');
|
|
58
58
|
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: () => {
|
|
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' && 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
60
|
if (!props.item.doNotEnableMultiselectOrder) {
|
|
61
61
|
setSavedSortValue(fieldValue);
|
|
62
62
|
}
|
|
@@ -67,7 +67,7 @@ function MultiSelectV1({ props, variant, }) {
|
|
|
67
67
|
setSavedSortValue(fieldValue);
|
|
68
68
|
}
|
|
69
69
|
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)
|
|
70
|
+
}, 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
71
|
? `${selectedOptions.length} Selected`
|
|
72
72
|
: selectedValuesString) }) })), MenuProps: {
|
|
73
73
|
PaperProps: {
|
|
@@ -14,7 +14,7 @@ const SingleSelect = ({ props, variant }) => {
|
|
|
14
14
|
const value = currentValue
|
|
15
15
|
? props.item.options?.find((item) => item.value === currentValue)
|
|
16
16
|
: null;
|
|
17
|
-
return (jsx(Controller, { control: props.control, name: props.item.name, render: ({ field }) => (jsxs(Fragment, { children: [renderLabel(variant, props), jsx(Tooltip, { title: props.item.isTooltipEnable ? (value?.label || '') : '', placement: "bottom-start", children: jsxs(Box, { sx: { width: '100%', position: 'relative' }, children: [jsx(Autocomplete, { ...field, id: `${props.item.name}-autocomplete`, value: value, onChange: (_, newValue) => {
|
|
17
|
+
return (jsx(Controller, { control: props.control, name: props.item.name, render: ({ field }) => (jsxs(Fragment, { children: [renderLabel(variant, props), jsx(Tooltip, { title: props.item.isTooltipEnable ? (value?.label || '') : '', placement: "bottom-start", children: jsxs(Box, { sx: { width: '100%', position: 'relative' }, children: [jsx(Autocomplete, { ...field, fullWidth: true, id: `${props.item.name}-autocomplete`, value: value, onChange: (_, newValue) => {
|
|
18
18
|
props.setValue(props?.item?.name, newValue?.value);
|
|
19
19
|
props?.item?.onChangeFn && props?.item?.onChangeFn(newValue?.value, newValue);
|
|
20
20
|
props?.clearErrors && props?.clearErrors(props?.item?.name);
|
|
@@ -49,10 +49,14 @@ const SingleSelect = ({ props, variant }) => {
|
|
|
49
49
|
fontSize: '11px',
|
|
50
50
|
},
|
|
51
51
|
},
|
|
52
|
-
}, renderOption: (props, option) =>
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
}, renderOption: (props, option) => {
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
54
|
+
const { key, ...optionProps } = props;
|
|
55
|
+
return (createElement("li", { ...optionProps, value: option.value, style: {
|
|
56
|
+
opacity: option.disable ? 0.5 : 1,
|
|
57
|
+
pointerEvents: option.disable ? 'none' : 'auto',
|
|
58
|
+
}, key: option.value }, option.label));
|
|
59
|
+
}, renderInput: (params) => (jsx(TextField, { ...params, placeholder: props.item.placeholder, error: isShowBorderError, label: variant !== 'standard' && props.item.labelVariant !== 'static'
|
|
56
60
|
? `${props.item.label}${props.item.required ? ' *' : ''}`
|
|
57
61
|
: '', inputProps: {
|
|
58
62
|
...params.inputProps,
|
|
@@ -197,7 +197,7 @@ const SingleSelectSearchApi = ({ props, variant, minSearchLength = 3, debounceMs
|
|
|
197
197
|
return fetchError ?? 'No results found';
|
|
198
198
|
}, [searchQuery, minSearchLength, fetchError]);
|
|
199
199
|
// ── Render ────────────────────────────────────────────────────────────────
|
|
200
|
-
return (jsx(Controller, { control: control, name: name, render: ({ field: { ref, onBlur } }) => (jsxs(Fragment, { children: [renderLabel(variant, props), jsx(Autocomplete, { ref: ref, value: resolvedValue, inputValue: displayText, onInputChange: handleInputChange, onChange: handleChange, onBlur: onBlur, options: options, getOptionLabel: getOptionLabel, isOptionEqualToValue: isOptionEqualToValue,
|
|
200
|
+
return (jsx(Controller, { control: control, name: name, render: ({ field: { ref, onBlur } }) => (jsxs(Fragment, { children: [renderLabel(variant, props), jsx(Autocomplete, { ref: ref, fullWidth: true, value: resolvedValue, inputValue: displayText, onInputChange: handleInputChange, onChange: handleChange, onBlur: onBlur, options: options, getOptionLabel: getOptionLabel, isOptionEqualToValue: isOptionEqualToValue,
|
|
201
201
|
// Options come pre-filtered from the server — disable client-side filtering
|
|
202
202
|
filterOptions: (x) => x, loading: isLoading, disabled: disable, size: "small", noOptionsText: noOptionsText, sx: {
|
|
203
203
|
'& .MuiAutocomplete-input': {
|
|
@@ -5,9 +5,9 @@ export { default as SingleSelectSearchApi } from './Select/SingleSelectSearchApi
|
|
|
5
5
|
export { default as MultiSelectV1 } from './Select/MultiSelectv1.esm.js';
|
|
6
6
|
export { default as MultiSelectTable } from './Select/MultiSelectTable.esm.js';
|
|
7
7
|
export { default as SearchableSelect } from './Select/SearchableSelect.esm.js';
|
|
8
|
+
export { default as FormCheckBoxGroup } from './FormCheckBoxGroup/FormCheckBoxGroup.esm.js';
|
|
8
9
|
export { default as DatepickerWrapperV2 } from './DatePicker/DatepickerWrapperV2.esm.js';
|
|
9
10
|
export { default as FormBottomField } from './FormBottomField/FormBottomField.esm.js';
|
|
10
|
-
export { default as FormCheckBoxGroup } from './FormCheckBoxGroup/FormCheckBoxGroup.esm.js';
|
|
11
11
|
export { default as FormErrorField } from './FormErrorField/FormErrorField.esm.js';
|
|
12
12
|
export { default as FormNumberField } from './FormNumberField/FormNumberField.esm.js';
|
|
13
13
|
export { default as FormNumberFieldDecimal } from './FormNumberField/FormNumberFieldDecimal.esm.js';
|
|
@@ -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([]);
|
|
@@ -460,12 +464,17 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
460
464
|
const allowGrow = layoutMode === 'grid' || layoutMode === 'semantic';
|
|
461
465
|
return columns.map((col) => {
|
|
462
466
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
463
|
-
const { filterType, options, getSearchText, ...mrtCol } = col;
|
|
467
|
+
const { filterType, options, getSearchText, exportExcel, ...mrtCol } = col;
|
|
464
468
|
if (allowGrow && mrtCol.grow === undefined) {
|
|
465
469
|
mrtCol.grow = true;
|
|
466
470
|
}
|
|
467
471
|
// Auto-inject filterFn only when the user hasn't already supplied one.
|
|
468
|
-
|
|
472
|
+
// Note: `filterType` omitted defaults to the same plain text-input chip
|
|
473
|
+
// as `filterType: 'text'` (see `ColumnFilterType` doc comment), so the
|
|
474
|
+
// text-matching branch below must handle both, not just the explicit
|
|
475
|
+
// `'text'` value — only `enableColumnFilter: false` / `'number'` should
|
|
476
|
+
// fall through without an injected filterFn.
|
|
477
|
+
if (!mrtCol.filterFn) {
|
|
469
478
|
if (filterType === 'date') {
|
|
470
479
|
// ISO date strings: "2026-05-05T00:00:00" → startsWith "2026-05-05"
|
|
471
480
|
mrtCol.filterFn = (row, columnId, filterValue) => filterValue
|
|
@@ -485,7 +494,16 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
485
494
|
? true
|
|
486
495
|
: filterValue.includes(row.getValue(columnId) ?? '');
|
|
487
496
|
}
|
|
488
|
-
|
|
497
|
+
else if (!filterType || filterType === 'text') {
|
|
498
|
+
// MRT's own default filterFn ('fuzzy', via match-sorter) is a
|
|
499
|
+
// non-contiguous subsequence match — e.g. "PH-1" would match like
|
|
500
|
+
// "%P%H%-%1%" instead of a plain substring. Use MRT's built-in
|
|
501
|
+
// 'contains' filterFn instead, matching Global Search's substring
|
|
502
|
+
// behavior (case-insensitive `.includes()`). Applies whether
|
|
503
|
+
// `filterType` is explicitly `'text'` or simply omitted.
|
|
504
|
+
mrtCol.filterFn = 'contains';
|
|
505
|
+
}
|
|
506
|
+
// 'number' uses MRT's built-in client-side filtering
|
|
489
507
|
}
|
|
490
508
|
return mrtCol;
|
|
491
509
|
});
|
|
@@ -521,8 +539,7 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
521
539
|
}, [searchTextGetters]);
|
|
522
540
|
// Stable references for the two table options below — recreating either
|
|
523
541
|
// per render would defeat the memoization on every other MRT callback
|
|
524
|
-
// (
|
|
525
|
-
// useMaterialReactTable must be memoized).
|
|
542
|
+
// (all function/object props passed into useMaterialReactTable must be memoized).
|
|
526
543
|
const tpFilterFns = useMemo(() => ({ tpGlobalSearch: tpGlobalSearchFn }), [tpGlobalSearchFn]);
|
|
527
544
|
const getColumnCanGlobalFilter = useCallback(() => true, []);
|
|
528
545
|
// ── Derive column list for filter chip picker ──────────────────────────────
|
|
@@ -589,7 +606,7 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
589
606
|
const exportRows = scope === 'filtered' && tableRef.current
|
|
590
607
|
? tableRef.current.getFilteredRowModel().rows.map((r) => r.original)
|
|
591
608
|
: rows;
|
|
592
|
-
const dataCols = columns.filter((c) => 'accessorKey' in c && c.accessorKey);
|
|
609
|
+
const dataCols = columns.filter((c) => 'accessorKey' in c && c.accessorKey && c.exportExcel !== false);
|
|
593
610
|
const headerArgb = hexToArgb(exportHeaderBgColor ?? headerBgColor) ?? 'FF1565C0';
|
|
594
611
|
const textArgb = hexToArgb(exportHeaderTextColor) ?? 'FFFFFFFF';
|
|
595
612
|
const headerRow = dataCols.map((c) => c.header ?? '');
|
|
@@ -753,7 +770,7 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
753
770
|
availableColumns, effectiveMaxVisibleFilters, densityTokens, handleToggleFilter,
|
|
754
771
|
]);
|
|
755
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]);
|
|
756
|
-
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]);
|
|
757
774
|
// ── Table instance ─────────────────────────────────────────────────────────
|
|
758
775
|
const table = useMaterialReactTable({
|
|
759
776
|
columns: processedColumns,
|
|
@@ -100,6 +100,25 @@ export type TPColumnDef<TData extends object = object, TValue = any> = MRT_Colum
|
|
|
100
100
|
* the raw accessor value is matched by default in that case.
|
|
101
101
|
*/
|
|
102
102
|
getSearchText?: (row: TData) => string | number | null | undefined;
|
|
103
|
+
/**
|
|
104
|
+
* Whether this column is included in the Excel (`.xlsx`) export.
|
|
105
|
+
*
|
|
106
|
+
* Set to `false` on columns that only render UI (e.g. edit/delete action
|
|
107
|
+
* icons) and have no meaningful exported value:
|
|
108
|
+
*
|
|
109
|
+
* ```ts
|
|
110
|
+
* {
|
|
111
|
+
* id: 'actions',
|
|
112
|
+
* header: 'Actions',
|
|
113
|
+
* Cell: ({ row }) => <IconButton onClick={() => onEdit(row.original)}><EditIcon /></IconButton>,
|
|
114
|
+
* exportExcel: false,
|
|
115
|
+
* }
|
|
116
|
+
* ```
|
|
117
|
+
*
|
|
118
|
+
* Default: `true` — every column with an `accessorKey` is exported unless
|
|
119
|
+
* explicitly opted out.
|
|
120
|
+
*/
|
|
121
|
+
exportExcel?: boolean;
|
|
103
122
|
};
|
|
104
123
|
export interface InvoiceDetail {
|
|
105
124
|
Data_from: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as Calendar } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as Calendar } from '../../../../../_virtual/index.esm6.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 requireDayCell } from '../DayCell/index.esm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as DateRange } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as DateRange } from '../../../../../_virtual/index.esm4.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 requireCalendar } from '../Calendar/index.esm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as DateRangePicker } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as DateRangePicker } from '../../../../../_virtual/index.esm5.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 requireDateRange } from '../DateRange/index.esm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as DefinedRange } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as DefinedRange } from '../../../../../_virtual/index.esm7.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 requireStyles } from '../../styles.esm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as InputRangeField } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as InputRangeField } 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
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as Month } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as Month } from '../../../../../_virtual/index.esm14.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 requireDayCell } from '../DayCell/index.esm.js';
|
|
@@ -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,27 @@ 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
|
+
}
|
|
8
24
|
export interface ProjectComponentStyles {
|
|
9
25
|
TPButton: ProjectComponentTPButton[];
|
|
10
26
|
TPButtonCommonSx: SxProps<Theme>;
|
|
27
|
+
TPToggleSwitch?: ProjectComponentTPToggleSwitch;
|
|
28
|
+
TPRadioGroup?: ProjectComponentTPRadioGroup;
|
|
11
29
|
}
|
|
12
30
|
export interface ProjectThemeStyles {
|
|
13
31
|
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
|