tp-react-elements 3.0.9 → 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.
Files changed (26) hide show
  1. package/dist/_virtual/index.esm12.js +2 -2
  2. package/dist/_virtual/index.esm13.js +2 -2
  3. package/dist/_virtual/index.esm6.js +2 -2
  4. package/dist/_virtual/index.esm7.js +2 -2
  5. package/dist/auth/authContext.d.ts +8 -0
  6. package/dist/auth/authContext.esm.js +13 -2
  7. package/dist/components/Form/FormActiveSwitch.d.ts +9 -0
  8. package/dist/components/Form/FormActiveSwitch.esm.js +64 -1
  9. package/dist/components/Form/FormRender.esm.js +6 -6
  10. package/dist/components/FormComponents/FormRadioGroup/FormRadioGroup.esm.js +16 -11
  11. package/dist/components/FormComponents/FormTextField/FormTextField.esm.js +2 -1
  12. package/dist/components/FormComponents/Select/MultiSelectv1.esm.js +2 -2
  13. package/dist/components/FormComponents/Select/SingleSelect.esm.js +1 -1
  14. package/dist/components/FormComponents/index.esm.js +10 -27
  15. package/dist/components/PaginatedGrid/GenericPaginatedGrid.d.ts +17 -1
  16. package/dist/components/PaginatedGrid/GenericPaginatedGrid.esm.js +7 -3
  17. package/dist/node_modules/react-date-range/dist/components/Calendar/index.esm.js +1 -1
  18. package/dist/node_modules/react-date-range/dist/components/DateInput/index.esm.js +1 -1
  19. package/dist/node_modules/react-date-range/dist/components/DefinedRange/index.esm.js +1 -1
  20. package/dist/node_modules/react-date-range/dist/components/InputRangeField/index.esm.js +1 -1
  21. package/dist/utils/Constants/FormConstants.d.ts +2 -0
  22. package/dist/utils/Constants/FormConstants.esm.js +4 -2
  23. package/dist/utils/Interface/FormInterface.d.ts +10 -0
  24. package/dist/utils/Interface/MainInterface.d.ts +18 -0
  25. package/dist/utils/index.esm.js +1 -1
  26. package/package.json +1 -1
@@ -1,3 +1,3 @@
1
- var DateInput = {};
1
+ var InputRangeField = {};
2
2
 
3
- export { DateInput as __exports };
3
+ export { InputRangeField as __exports };
@@ -1,3 +1,3 @@
1
- var InputRangeField = {};
1
+ var DateInput = {};
2
2
 
3
- export { InputRangeField as __exports };
3
+ export { DateInput as __exports };
@@ -1,3 +1,3 @@
1
- var DefinedRange = {};
1
+ var Calendar = {};
2
2
 
3
- export { DefinedRange as __exports };
3
+ export { Calendar as __exports };
@@ -1,3 +1,3 @@
1
- var Calendar = {};
1
+ var DefinedRange = {};
2
2
 
3
- export { Calendar as __exports };
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, useState, useContext } from 'react';
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
- 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" })] })) })] }));
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 };
@@ -2,12 +2,6 @@ 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
4
  import FormCheckBoxGroup from '../FormComponents/FormCheckBoxGroup/FormCheckBoxGroup.esm.js';
5
- import FormNumberField from '../FormComponents/FormNumberField/FormNumberField.esm.js';
6
- import FormNumberFieldDecimal from '../FormComponents/FormNumberField/FormNumberFieldDecimal.esm.js';
7
- import FormRadioGroup from '../FormComponents/FormRadioGroup/FormRadioGroup.esm.js';
8
- import FormTextAreaField from '../FormComponents/FormTextAreaField/FormTextAreaField.esm.js';
9
- import FormTextField from '../FormComponents/FormTextField/FormTextField.esm.js';
10
- import PasswordField from '../FormComponents/PasswordField/PasswordField.esm.js';
11
5
  import SingleSelect from '../FormComponents/Select/SingleSelect.esm.js';
12
6
  import MultiSelectAutocomplete from '../FormComponents/Select/MultiSelectAutocomplete.esm.js';
13
7
  import SingleSelectNonAutoComplete from '../FormComponents/Select/SingleSelectNonAutoComplete.esm.js';
@@ -18,6 +12,12 @@ import DateRangePickerComponent from '../DateRangePicker/DateRangePicker.esm.js'
18
12
  import RichTextEditorWrapper from '../FormComponents/RichTextEditor/RichTextEditorWrapper.esm.js';
19
13
  import SingleSelectSearchApi from '../FormComponents/Select/SingleSelectSearchApi.esm.js';
20
14
  import DatetimepickerWrapper from '../FormComponents/DatePicker/DatetimepickerWrapper.esm.js';
15
+ import FormTextAreaField from '../FormComponents/FormTextAreaField/FormTextAreaField.esm.js';
16
+ import FormRadioGroup from '../FormComponents/FormRadioGroup/FormRadioGroup.esm.js';
17
+ import FormNumberFieldDecimal from '../FormComponents/FormNumberField/FormNumberFieldDecimal.esm.js';
18
+ import FormNumberField from '../FormComponents/FormNumberField/FormNumberField.esm.js';
19
+ import PasswordField from '../FormComponents/PasswordField/PasswordField.esm.js';
20
+ import FormTextField from '../FormComponents/FormTextField/FormTextField.esm.js';
21
21
 
22
22
  // Lazy-loaded heavy components
23
23
  // const RichTextEditorWrapper = lazy(() =>
@@ -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
- const RADIO_SX = {
12
- padding: '6px 2px 6px 8px',
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: RADIO_SX }), label: jsx(Typography, { fontSize: '11px', fontWeight: 'normal !important', children: option.label }) }, i))) })) }) }), jsx(FormBottomField, { ...props })] }));
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 label = variant !== 'standard' ? `${props.item.label}${props.item.required ? ' *' : ''}` : '';
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
  *
@@ -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: {
@@ -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,
@@ -1,8 +1,3 @@
1
- export { default as FormNumberField } from './FormNumberField/FormNumberField.esm.js';
2
- export { default as FormNumberFieldDecimal } from './FormNumberField/FormNumberFieldDecimal.esm.js';
3
- export { default as FormTextAreaField } from './FormTextAreaField/FormTextAreaField.esm.js';
4
- export { default as FormTextField } from './FormTextField/FormTextField.esm.js';
5
- export { default as PasswordField } from './PasswordField/PasswordField.esm.js';
6
1
  export { default as FormCheckBox } from './FormCheckBox/FormCheckBox.esm.js';
7
2
  export { default as SingleSelect } from './Select/SingleSelect.esm.js';
8
3
  export { default as SingleSelectNonAutoComplete } from './Select/SingleSelectNonAutoComplete.esm.js';
@@ -11,32 +6,20 @@ export { default as MultiSelectV1 } from './Select/MultiSelectv1.esm.js';
11
6
  export { default as MultiSelectTable } from './Select/MultiSelectTable.esm.js';
12
7
  export { default as SearchableSelect } from './Select/SearchableSelect.esm.js';
13
8
  export { default as FormCheckBoxGroup } from './FormCheckBoxGroup/FormCheckBoxGroup.esm.js';
14
- export { default as FormRadioGroup } from './FormRadioGroup/FormRadioGroup.esm.js';
15
9
  export { default as DatepickerWrapperV2 } from './DatePicker/DatepickerWrapperV2.esm.js';
16
- export { default as Monthpickerrender } from './DatePicker/Monthpickerrender.esm.js';
17
- import 'react/jsx-runtime';
18
- import 'react';
19
- import '@mui/material';
20
- import '@mui/icons-material/CalendarToday';
21
- import '@mui/icons-material/ChevronLeft';
22
- import '@mui/icons-material/ChevronRight';
23
- import 'react-hook-form';
24
10
  export { default as FormBottomField } from './FormBottomField/FormBottomField.esm.js';
25
- import 'dayjs';
26
- export { default as YearPickerField } from './YearPickerField/YearPickerField.esm.js';
27
- export { default as TimePicker } from './TimePicker/TimePicker.esm.js';
11
+ export { default as FormErrorField } from './FormErrorField/FormErrorField.esm.js';
12
+ export { default as FormNumberField } from './FormNumberField/FormNumberField.esm.js';
13
+ export { default as FormNumberFieldDecimal } from './FormNumberField/FormNumberFieldDecimal.esm.js';
14
+ export { default as FormRadioGroup } from './FormRadioGroup/FormRadioGroup.esm.js';
28
15
  export { default as FormRenderFileUpload } from './FileUpload/FormRenderFileUpload.esm.js';
29
16
  export { default as FormRenderMultiFileUpload } from './FileUpload/FormRenderMultiFileUpload.esm.js';
30
- import '@mui/icons-material/Visibility';
31
- import '@mui/icons-material/Close';
32
- import '@mui/icons-material/NavigateBefore';
33
- import '@mui/icons-material/NavigateNext';
34
- import '@mui/icons-material/Delete';
35
- import '@mui/icons-material/UploadFile';
36
- import '@mui/icons-material/PictureAsPdf';
37
- import '@mui/icons-material/TableChart';
38
- import '@mui/icons-material/Description';
39
- export { default as FormErrorField } from './FormErrorField/FormErrorField.esm.js';
17
+ export { default as FormTextAreaField } from './FormTextAreaField/FormTextAreaField.esm.js';
18
+ export { default as FormTextField } from './FormTextField/FormTextField.esm.js';
40
19
  export { default as HelperText } from './HelperText/HelperText.esm.js';
20
+ export { default as Monthpickerrender } from './DatePicker/Monthpickerrender.esm.js';
21
+ export { default as PasswordField } from './PasswordField/PasswordField.esm.js';
41
22
  export { default as RichTextEditor } from './RichTextEditor/RichTextEditor.esm.js';
42
23
  export { default as RichTextEditorWrapper } from './RichTextEditor/RichTextEditorWrapper.esm.js';
24
+ export { default as TimePicker } from './TimePicker/TimePicker.esm.js';
25
+ export { default as YearPickerField } from './YearPickerField/YearPickerField.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: batchSize,
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: pageSizeOptions, density: densityTokens, gridId: resolvedGridId, isStacked: isMobileTier, isClientFiltered: isFiltered, filteredRowCount: t.getFilteredRowModel().rows.length, pageRowCount: rows.length })), [totalRecords, isFetching, isLoading, pageSizeOptions, densityTokens, resolvedGridId, isMobileTier, isFiltered, rows]);
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 Calendar } from '../../../../../_virtual/index.esm7.js';
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 DateInput } from '../../../../../_virtual/index.esm12.js';
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 DefinedRange } from '../../../../../_virtual/index.esm6.js';
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.esm13.js';
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
 
@@ -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;
@@ -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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tp-react-elements",
3
- "version": "3.0.9",
3
+ "version": "3.0.10",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "React form components library built with React Hook Form and Yup",