@evoke-platform/ui-components 1.1.0-testing.11 → 1.1.0-testing.13

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.
@@ -3,6 +3,7 @@ import { ClearRounded } from '@mui/icons-material';
3
3
  import { Box, darken, lighten, styled } from '@mui/material';
4
4
  import { TimePicker } from '@mui/x-date-pickers';
5
5
  import React, { useEffect, useRef, useState } from 'react';
6
+ import { InvalidDate } from '../../../util';
6
7
  import { Autocomplete, Chip, DatePicker, DateTimePicker, LocalizationProvider, Menu, MenuItem, TextField, Typography, } from '../../core';
7
8
  import { NumericFormat } from '../FormField/InputFieldComponent';
8
9
  const GroupHeader = styled('div')(({ theme }) => ({
@@ -32,6 +33,7 @@ const ValueEditor = (props) => {
32
33
  }));
33
34
  }
34
35
  }
36
+ const [invalidDateTime, setInvalidDateTime] = useState(false);
35
37
  const [anchorEl, setAnchorEl] = useState(null);
36
38
  const inputRef = useRef(null);
37
39
  const [openPresetValues, setOpenPresetValues] = useState(false);
@@ -82,12 +84,47 @@ const ValueEditor = (props) => {
82
84
  const groupRenderGroup = (params) => (React.createElement("li", { key: params.key },
83
85
  React.createElement(GroupHeader, null, params.group),
84
86
  React.createElement(GroupItems, null, params.children)));
85
- function parseISOStringToLocalDateTime(value) {
87
+ function validateDateTime(value) {
86
88
  if (!value) {
87
89
  return null;
88
90
  }
89
- const d = new Date(value);
90
- return LocalDateTime.ofInstant(Instant.ofEpochMilli(d.getTime()), ZoneId.systemDefault());
91
+ // check if it's an ISO string
92
+ const isoRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/;
93
+ if (isoRegex.test(value)) {
94
+ try {
95
+ const instant = Instant.parse(value);
96
+ return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
97
+ }
98
+ catch (error) {
99
+ console.error('Error parsing ISO string:', error);
100
+ }
101
+ }
102
+ return new InvalidDate(value);
103
+ }
104
+ // Prevents the RangeError issue on keyboard input by returning an empty string for invalid dates
105
+ // lets users type partial dates without crashing the component during the input process.
106
+ function convertToISOString(date) {
107
+ if (!date) {
108
+ return '';
109
+ }
110
+ try {
111
+ if (date instanceof InvalidDate) {
112
+ return '';
113
+ }
114
+ if (date instanceof LocalDateTime) {
115
+ return new Date(date.toString()).toISOString();
116
+ }
117
+ if (date instanceof LocalDate) {
118
+ // Convert LocalDate to LocalDateTime to avoid HourOfDay error
119
+ const dateTime = LocalDateTime.of(date, LocalTime.of(0));
120
+ return new Date(dateTime.toString()).toISOString();
121
+ }
122
+ return '';
123
+ }
124
+ catch (error) {
125
+ console.error('Error converting date to ISO string:', error);
126
+ return '';
127
+ }
91
128
  }
92
129
  const getEditor = () => {
93
130
  if (isPresetValueSelected) {
@@ -106,26 +143,44 @@ const ValueEditor = (props) => {
106
143
  React.createElement(TimePicker, { inputRef: inputRef, disabled: disabled, value: disabled || !value ? null : value, onChange: handleOnChange, renderInput: (params) => (React.createElement(TextField, { ...params, onClick: onClick, placeholder: "Value", size: "small", sx: styles.input })), readOnly: readOnly })));
107
144
  }
108
145
  else if (inputType === 'date-time') {
109
- const dateTimeValue = parseISOStringToLocalDateTime(value);
146
+ const dateTimeValue = validateDateTime(value);
110
147
  return (React.createElement(LocalizationProvider, null,
111
148
  React.createElement(DateTimePicker, { inputRef: inputRef, value: dateTimeValue, onChange: (date) => {
112
149
  if (!date) {
113
150
  handleOnChange('');
151
+ setInvalidDateTime(false);
114
152
  return;
115
153
  }
116
- let localDateTime;
117
- if (date instanceof LocalDate && !(date instanceof LocalDateTime)) {
118
- // onChange initially returns a LocalDate after date is selected
119
- localDateTime = LocalDateTime.of(date, LocalTime.of(0));
154
+ if (date instanceof InvalidDate) {
155
+ setInvalidDateTime(true);
156
+ return;
120
157
  }
121
- else {
122
- localDateTime = date;
158
+ try {
159
+ let localDateTime;
160
+ if (date instanceof LocalDate && !(date instanceof LocalDateTime)) {
161
+ // onChange initially returns a LocalDate after date is selected
162
+ localDateTime = LocalDateTime.of(date, LocalTime.of(0));
163
+ }
164
+ else {
165
+ localDateTime = date;
166
+ }
167
+ const isoString = convertToISOString(localDateTime);
168
+ if (isoString) {
169
+ setInvalidDateTime(false);
170
+ handleOnChange(isoString);
171
+ }
172
+ else {
173
+ setInvalidDateTime(true);
174
+ }
175
+ }
176
+ catch (error) {
177
+ console.error('Error processing date value:', error);
178
+ setInvalidDateTime(true);
123
179
  }
124
- handleOnChange(new Date(localDateTime.toString()).toISOString());
125
180
  }, onClose: onClose, PopperProps: {
126
181
  anchorEl,
127
182
  }, renderInput: (params) => (React.createElement(Box, { sx: styles.input, ref: setAnchorEl },
128
- React.createElement(TextField, { ...params, disabled: disabled, onClick: onClick, placeholder: "Value", size: "small", inputRef: inputRef }))), readOnly: readOnly })));
183
+ React.createElement(TextField, { ...params, disabled: disabled, onClick: onClick, placeholder: "Value", size: "small", inputRef: inputRef, error: invalidDateTime }))), readOnly: readOnly })));
129
184
  }
130
185
  else if (inputType === 'number' || inputType === 'integer') {
131
186
  const isMultiple = ['in', 'notIn'].includes(operator);
@@ -2,40 +2,77 @@ import { ApiServices, Obj, ObjectInstance, UserAccount } from '@evoke-platform/c
2
2
  import { ReactComponent } from '@formio/react';
3
3
  import React from 'react';
4
4
  import '../../../../styles/form-component.css';
5
- import { Document, ObjectPropertyInputProps } from '../types';
5
+ import { Address, Document, ObjectPropertyInputProps } from '../types';
6
6
  type OnSaveResponse = {
7
7
  isSuccessful: boolean;
8
8
  error?: Record<string, unknown>;
9
9
  };
10
10
  export type FormProps = {
11
- formKey?: number;
12
- object?: Obj;
13
- instance?: ObjectInstance;
14
- document?: Document;
15
- user?: UserAccount;
16
- onSave?: (data: Record<string, unknown>, setSubmitting?: (value: boolean) => void) => Promise<OnSaveResponse>;
17
- submitButtonLabel?: string;
18
- isReadOnly?: boolean;
19
- apiServices?: ApiServices | undefined;
20
- navigateTo?: (path: string) => void;
21
- closeModal?: () => void;
22
- clearable?: boolean;
23
- objectInputCommonProps?: ObjectPropertyInputProps;
11
+ /** An optional identifier for the action associated with the form. */
24
12
  actionId?: string;
25
- onAutoSave?: (data: Record<string, unknown>) => Promise<{
26
- isSuccessful: boolean;
27
- error?: Record<string, unknown>;
28
- }>;
13
+ /** The type of action associated with the form. */
29
14
  actionType?: string;
15
+ /** Optional API services for the form. */
16
+ apiServices?: ApiServices | undefined;
17
+ /** An object representing an associated object with optional `instanceId` and `propertyId` properties. */
30
18
  associatedObject?: {
31
19
  instanceId?: string;
32
20
  propertyId?: string;
33
21
  };
34
- queryAddresses?: unknown;
22
+ /**
23
+ * Whether the form can be cleared.
24
+ * @default false
25
+ * */
26
+ clearable?: boolean;
27
+ /** An optional document related to the form. */
28
+ document?: Document;
29
+ /** Defines the height of the fields in the form. */
35
30
  fieldHeight?: 'small' | 'medium';
31
+ /** An optional unique identifier for the form instance. */
32
+ formKey?: number;
33
+ /**
34
+ * A reference to the form for direct manipulation.
35
+ * i.e: formRef.current.submit({data: formRef.current.data}, 'submit', (error?: Record<string, unknown>) => {...}, (value: boolean) => {...})
36
+ * */
37
+ formRef?: React.MutableRefObject<FormRef | undefined>;
38
+ /** A React component used as a rich text editor. */
36
39
  richTextEditor?: typeof ReactComponent;
40
+ /**
41
+ * Whether to hide the buttons in the form.
42
+ * @default false
43
+ * */
37
44
  hideButtons?: boolean;
38
- formRef?: React.MutableRefObject<FormRef | undefined>;
45
+ /** An optional instance of an object associated with the form. */
46
+ instance?: ObjectInstance;
47
+ /**
48
+ * Whether the form is in read-only mode.
49
+ * @default false
50
+ * */
51
+ isReadOnly?: boolean;
52
+ /** An optional object associated with the form. */
53
+ object?: Obj;
54
+ /** Common properties for object input fields. */
55
+ objectInputCommonProps?: ObjectPropertyInputProps;
56
+ /** An optional user account associated with the form. */
57
+ user?: UserAccount;
58
+ /**
59
+ * The label for the submit button.
60
+ * @default Submit
61
+ * */
62
+ submitButtonLabel?: string;
63
+ /** A function to close a modal if the form is in one. */
64
+ closeModal?: () => void;
65
+ /** A function to navigate to a different path. */
66
+ navigateTo?: (path: string) => void;
67
+ /** A callback function to save draft the form data. */
68
+ onAutoSave?: (data: Record<string, unknown>) => Promise<{
69
+ isSuccessful: boolean;
70
+ error?: Record<string, unknown>;
71
+ }>;
72
+ /** A callback function to save the form data. It returns a promise with a response. */
73
+ onSave?: (data: Record<string, unknown>, setSubmitting?: (value: boolean) => void) => Promise<OnSaveResponse>;
74
+ /** A function to query addresses related to the form. */
75
+ queryAddresses?: (query: string) => Promise<Address[]>;
39
76
  };
40
77
  export type FormRef = {
41
78
  submit: (submission: Record<string, unknown>, type: 'submit' | 'draft', setError: (error?: Record<string, unknown>) => void, setSubmitting?: (value: boolean) => void) => void;
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  import { Action, ApiServices, Obj, Property, UserAccount } from '@evoke-platform/context';
3
- import { ObjectPropertyInputProps } from '../../types';
3
+ import { Address, ObjectPropertyInputProps } from '../../types';
4
4
  export type ActionDialogProps = {
5
5
  open: boolean;
6
6
  onClose: () => void;
@@ -15,7 +15,7 @@ export type ActionDialogProps = {
15
15
  instanceId?: string;
16
16
  relatedProperty?: Property;
17
17
  apiServices: ApiServices;
18
- queryAddresses?: unknown;
18
+ queryAddresses?: (query: string) => Promise<Address[]>;
19
19
  user?: UserAccount;
20
20
  };
21
21
  export declare const ActionDialog: (props: ActionDialogProps) => JSX.Element;
@@ -1,11 +1,12 @@
1
1
  /// <reference types="react" />
2
2
  import { ApiServices, ObjectInstance, Property, UserAccount, ViewLayoutEntityReference } from '@evoke-platform/context';
3
+ import { Address } from '../../types';
3
4
  export type ObjectPropertyInputProps = {
4
5
  property: Property;
5
6
  instance: ObjectInstance;
6
7
  canUpdateProperty: boolean;
7
8
  apiServices: ApiServices;
8
- queryAddresses?: unknown;
9
+ queryAddresses?: (query: string) => Promise<Address[]>;
9
10
  user?: UserAccount;
10
11
  viewLayout?: ViewLayoutEntityReference;
11
12
  };
@@ -2,7 +2,7 @@ import { ActionInput, ActionInputType, ApiServices, FormEntry, InputParameter, I
2
2
  import { ReactComponent } from '@formio/react';
3
3
  import { LocalDateTime } from '@js-joda/core';
4
4
  import { AutocompleteOption } from '../../core';
5
- import { ObjectPropertyInputProps } from './types';
5
+ import { Address, ObjectPropertyInputProps } from './types';
6
6
  export declare function determineComponentType(properties: Property[], parameter?: InputParameter): ActionInputType | undefined;
7
7
  export declare function determineParameterType(componentType: string): PropertyType;
8
8
  export declare function getFlattenEntries(entries: FormEntry[]): InputParameterReference[];
@@ -21,9 +21,9 @@ export declare function getMiddleObject(instance: ObjectInstance, property: Prop
21
21
  } | undefined;
22
22
  export declare function getMiddleInstance(instanceId: string, property: Property, middleObjectInstances: ObjectInstance[]): ObjectInstance | undefined;
23
23
  export declare function getPrefixedUrl(url: string): string;
24
- export declare function addObjectPropertiesToComponentProps(properties: Property[], formComponents: any[], instance?: ObjectInstance, objectPropertyInputProps?: ObjectPropertyInputProps, autoSave?: (data: Record<string, unknown>) => void, readOnly?: boolean, defaultPages?: Record<string, string>, navigateTo?: (path: string) => void, queryAddresses?: unknown, apiServices?: ApiServices, isModal?: boolean, fieldHeight?: 'small' | 'medium', richTextEditor?: typeof ReactComponent): Promise<ActionInput[]>;
24
+ export declare function addObjectPropertiesToComponentProps(properties: Property[], formComponents: any[], instance?: ObjectInstance, objectPropertyInputProps?: ObjectPropertyInputProps, autoSave?: (data: Record<string, unknown>) => void, readOnly?: boolean, defaultPages?: Record<string, string>, navigateTo?: (path: string) => void, queryAddresses?: (query: string) => Promise<Address[]>, apiServices?: ApiServices, isModal?: boolean, fieldHeight?: 'small' | 'medium', richTextEditor?: typeof ReactComponent): Promise<ActionInput[]>;
25
25
  export declare function getDefaultValue(initialValue: unknown, selectOptions?: AutocompleteOption[]): unknown;
26
- export declare const buildComponentPropsFromObjectProperties: (properties: Property[], objectId: string, instance?: ObjectInstance, objectPropertyInputProps?: ObjectPropertyInputProps, hasActionPermissions?: boolean, autoSave?: ((data: Record<string, unknown>) => void) | undefined, readOnly?: boolean, queryAddresses?: unknown, isModal?: boolean, fieldHeight?: 'small' | 'medium', richTextEditor?: typeof ReactComponent) => unknown[];
26
+ export declare const buildComponentPropsFromObjectProperties: (properties: Property[], objectId: string, instance?: ObjectInstance, objectPropertyInputProps?: ObjectPropertyInputProps, hasActionPermissions?: boolean, autoSave?: ((data: Record<string, unknown>) => void) | undefined, readOnly?: boolean, queryAddresses?: ((query: string) => Promise<Address[]>) | undefined, isModal?: boolean, fieldHeight?: 'small' | 'medium', richTextEditor?: typeof ReactComponent) => unknown[];
27
27
  export declare const buildComponentPropsFromDocumentProperties: (documentProperties: [string, unknown][], readOnly?: boolean, autoSave?: ((data: Record<string, unknown>) => void) | undefined, fieldHeight?: 'small' | 'medium') => {
28
28
  type: string;
29
29
  key: string;
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { CriteriaBuilder as BuildCriteria } from '../index';
3
3
  export default {
4
- title: 'Input/CriteriaBuilder',
4
+ title: 'Custom/CriteriaBuilder',
5
5
  component: BuildCriteria,
6
6
  };
7
7
  const defaultProperties = [
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { Button, Form } from '../index';
3
3
  export default {
4
- title: 'Input/Form',
4
+ title: 'Custom/Form',
5
5
  component: Form,
6
6
  };
7
7
  const object = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evoke-platform/ui-components",
3
- "version": "1.1.0-testing.11",
3
+ "version": "1.1.0-testing.13",
4
4
  "description": "",
5
5
  "main": "dist/published/index.js",
6
6
  "module": "dist/published/index.js",