@hubspot/ui-extensions 0.9.2 → 0.9.4

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.
@@ -4,29 +4,35 @@ function isCrmPropertiesResponse(data) {
4
4
  // Confirm the data is a defined object
5
5
  data === null ||
6
6
  typeof data !== 'object' ||
7
- // Confirm all keys and values are strings
8
- !Object.keys(data).every((key) => typeof key === 'string' && typeof data[key] === 'string')) {
7
+ // Confirm all keys and values are strings, or null
8
+ !Object.keys(data).every((key) => typeof key === 'string' &&
9
+ (typeof data[key] === 'string' || data[key] === null))) {
9
10
  return false;
10
11
  }
11
12
  return true;
12
13
  }
13
- export const fetchCrmProperties = async (propertyNames, propertiesUpdatedCallback) => {
14
+ export const fetchCrmProperties = async (propertyNames, propertiesUpdatedCallback, options) => {
15
+ let response;
16
+ let result;
14
17
  try {
15
18
  // eslint-disable-next-line hubspot-dev/no-confusing-browser-globals
16
- const response = await self.fetchCrmProperties(propertyNames, propertiesUpdatedCallback);
17
- if (!response.ok) {
18
- throw new Error(`Failed to fetch CRM properties: ${response.statusText}`);
19
- }
20
- const data = await response.json();
21
- if (!isCrmPropertiesResponse(data)) {
22
- throw new Error('Invalid response format');
23
- }
24
- return data;
19
+ response = await self.fetchCrmProperties(propertyNames, propertiesUpdatedCallback, options);
20
+ result = await response.json();
25
21
  }
26
22
  catch (error) {
27
- if (error instanceof Error) {
28
- throw error;
29
- }
30
- throw new Error('Failed to fetch CRM properties: Unknown error');
23
+ // Only handle network/parsing errors, not our validation errors
24
+ throw error instanceof Error
25
+ ? error
26
+ : new Error('Failed to fetch CRM properties: Unknown error');
31
27
  }
28
+ if (result.error) {
29
+ throw new Error(result.error);
30
+ }
31
+ if (!response.ok) {
32
+ throw new Error(`Failed to fetch CRM properties: ${response.statusText}`);
33
+ }
34
+ if (!isCrmPropertiesResponse(result.data)) {
35
+ throw new Error('Invalid response format');
36
+ }
37
+ return result;
32
38
  };
@@ -0,0 +1,10 @@
1
+ import { type FetchAssociationsRequest, type AssociationsResponse } from '../crm/fetchAssociations';
2
+ import { type FetchCrmPropertiesOptions } from '../crm/fetchCrmProperties';
3
+ export interface AssociationsState {
4
+ results: AssociationsResponse['results'];
5
+ error: Error | null;
6
+ isLoading: boolean;
7
+ hasMore: boolean;
8
+ nextOffset: number;
9
+ }
10
+ export declare function useAssociations(request: FetchAssociationsRequest, options?: FetchCrmPropertiesOptions): AssociationsState;
@@ -0,0 +1,116 @@
1
+ import { useEffect, useReducer, useMemo, useRef } from 'react';
2
+ import { logger } from '../../logger';
3
+ import { fetchAssociations, } from '../crm/fetchAssociations';
4
+ const initialState = {
5
+ results: [],
6
+ error: null,
7
+ isLoading: true,
8
+ hasMore: false,
9
+ nextOffset: 0,
10
+ };
11
+ function associationsReducer(state, action) {
12
+ switch (action.type) {
13
+ case 'FETCH_START':
14
+ return {
15
+ ...state,
16
+ isLoading: true,
17
+ error: null,
18
+ };
19
+ case 'FETCH_SUCCESS':
20
+ return {
21
+ ...state,
22
+ isLoading: false,
23
+ results: action.payload.results,
24
+ hasMore: action.payload.hasMore,
25
+ nextOffset: action.payload.nextOffset,
26
+ error: null,
27
+ };
28
+ case 'FETCH_ERROR':
29
+ return {
30
+ ...state,
31
+ isLoading: false,
32
+ error: action.payload,
33
+ results: [],
34
+ hasMore: false,
35
+ nextOffset: 0,
36
+ };
37
+ default:
38
+ return state;
39
+ }
40
+ }
41
+ const DEFAULT_OPTIONS = {};
42
+ export function useAssociations(request, options = DEFAULT_OPTIONS) {
43
+ const [state, dispatch] = useReducer(associationsReducer, initialState);
44
+ // Log experimental warning once on mount
45
+ useEffect(() => {
46
+ logger.warn('useAssociations is an experimental hook and might change or be removed in the future.');
47
+ }, []);
48
+ /**
49
+ * HOOK OPTIMIZATION:
50
+ *
51
+ * Create stable references for request and options to prevent unnecessary re-renders and API calls.
52
+ * Then, external developers can pass inline objects without worrying about memoization
53
+ * We handle the deep equality comparison ourselves, and return the same object reference when content is equivalent.
54
+ */
55
+ const lastRequestRef = useRef();
56
+ const lastRequestKeyRef = useRef();
57
+ const lastOptionsRef = useRef();
58
+ const lastOptionsKeyRef = useRef();
59
+ const stableRequest = useMemo(() => {
60
+ const requestKey = JSON.stringify(request);
61
+ if (requestKey === lastRequestKeyRef.current) {
62
+ return lastRequestRef.current;
63
+ }
64
+ lastRequestKeyRef.current = requestKey;
65
+ lastRequestRef.current = request;
66
+ return request;
67
+ }, [request]);
68
+ const stableOptions = useMemo(() => {
69
+ const optionsKey = JSON.stringify(options);
70
+ if (optionsKey === lastOptionsKeyRef.current) {
71
+ return lastOptionsRef.current;
72
+ }
73
+ lastOptionsKeyRef.current = optionsKey;
74
+ lastOptionsRef.current = options;
75
+ return options;
76
+ }, [options]);
77
+ // Fetch the associations
78
+ useEffect(() => {
79
+ let cancelled = false;
80
+ let cleanup = null;
81
+ const fetchData = async () => {
82
+ try {
83
+ dispatch({ type: 'FETCH_START' });
84
+ const result = await fetchAssociations(stableRequest, stableOptions);
85
+ if (!cancelled) {
86
+ dispatch({
87
+ type: 'FETCH_SUCCESS',
88
+ payload: {
89
+ results: result.data.results,
90
+ hasMore: result.data.hasMore,
91
+ nextOffset: result.data.nextOffset,
92
+ },
93
+ });
94
+ cleanup = result.cleanup;
95
+ }
96
+ }
97
+ catch (err) {
98
+ if (!cancelled) {
99
+ const errorData = err instanceof Error
100
+ ? err
101
+ : new Error('Failed to fetch associations');
102
+ dispatch({ type: 'FETCH_ERROR', payload: errorData });
103
+ }
104
+ }
105
+ };
106
+ fetchData();
107
+ return () => {
108
+ cancelled = true;
109
+ // Call cleanup function to release resources
110
+ if (cleanup) {
111
+ cleanup();
112
+ }
113
+ };
114
+ }, [stableRequest, stableOptions]);
115
+ return state;
116
+ }
@@ -1,5 +1,6 @@
1
+ import { type FetchCrmPropertiesOptions } from '../crm/fetchCrmProperties';
1
2
  export interface CrmPropertiesState {
2
- properties: Record<string, string>;
3
+ properties: Record<string, string | null>;
3
4
  error: Error | null;
4
5
  isLoading: boolean;
5
6
  }
@@ -8,4 +9,4 @@ export interface CrmPropertiesState {
8
9
  *
9
10
  * @experimental This hook is experimental and might change or be removed in future versions.
10
11
  */
11
- export declare function useCrmProperties(propertyNames: string[]): CrmPropertiesState;
12
+ export declare function useCrmProperties(propertyNames: string[], options?: FetchCrmPropertiesOptions): CrmPropertiesState;
@@ -1,49 +1,113 @@
1
- import { useEffect, useState } from 'react';
1
+ import { useEffect, useReducer, useMemo, useRef } from 'react';
2
2
  import { logger } from '../../logger';
3
- import { fetchCrmProperties } from '../crm/fetchCrmProperties';
3
+ import { fetchCrmProperties, } from '../crm/fetchCrmProperties';
4
+ const initialState = {
5
+ properties: {},
6
+ error: null,
7
+ isLoading: true,
8
+ };
9
+ function crmPropertiesReducer(state, action) {
10
+ switch (action.type) {
11
+ case 'FETCH_START':
12
+ return {
13
+ ...state,
14
+ isLoading: true,
15
+ error: null,
16
+ };
17
+ case 'FETCH_SUCCESS':
18
+ return {
19
+ ...state,
20
+ isLoading: false,
21
+ properties: action.payload,
22
+ error: null,
23
+ };
24
+ case 'FETCH_ERROR':
25
+ return {
26
+ ...state,
27
+ isLoading: false,
28
+ error: action.payload,
29
+ properties: {},
30
+ };
31
+ default:
32
+ return state;
33
+ }
34
+ }
35
+ const DEFAULT_OPTIONS = {};
4
36
  /**
5
37
  * A hook for using and managing CRM properties.
6
38
  *
7
39
  * @experimental This hook is experimental and might change or be removed in future versions.
8
40
  */
9
- export function useCrmProperties(propertyNames) {
10
- const [properties, setProperties] = useState({});
11
- const [isLoading, setIsLoading] = useState(true);
12
- const [error, setError] = useState(null);
41
+ export function useCrmProperties(propertyNames, options = DEFAULT_OPTIONS) {
42
+ const [state, dispatch] = useReducer(crmPropertiesReducer, initialState);
13
43
  // Log experimental warning once on mount
14
44
  useEffect(() => {
15
45
  logger.warn('useCrmProperties is an experimental hook and might change or be removed in the future.');
16
46
  }, []);
17
- const propertiesUpdatedCallback = (newProperties) => {
18
- setProperties(newProperties);
19
- };
47
+ /**
48
+ * HOOK OPTIMIZATION:
49
+ *
50
+ * Create stable references for propertyNames and options to prevent unnecessary re-renders and API calls.
51
+ * Then, external developers can pass inline arrays/objects without worrying about memoization
52
+ * We handle the deep equality comparison ourselves, and return the same object reference when content is equivalent.
53
+ */
54
+ const lastPropertyNamesRef = useRef();
55
+ const lastPropertyNamesKeyRef = useRef();
56
+ const lastOptionsRef = useRef();
57
+ const lastOptionsKeyRef = useRef();
58
+ const stablePropertyNames = useMemo(() => {
59
+ const sortedNames = [...propertyNames].sort();
60
+ const propertyNamesKey = JSON.stringify(sortedNames);
61
+ if (propertyNamesKey === lastPropertyNamesKeyRef.current) {
62
+ return lastPropertyNamesRef.current;
63
+ }
64
+ lastPropertyNamesKeyRef.current = propertyNamesKey;
65
+ lastPropertyNamesRef.current = sortedNames;
66
+ return sortedNames;
67
+ }, [propertyNames]);
68
+ const stableOptions = useMemo(() => {
69
+ const optionsKey = JSON.stringify(options);
70
+ if (optionsKey === lastOptionsKeyRef.current) {
71
+ return lastOptionsRef.current;
72
+ }
73
+ lastOptionsKeyRef.current = optionsKey;
74
+ lastOptionsRef.current = options;
75
+ return options;
76
+ }, [options]);
20
77
  // Fetch the properties
21
78
  useEffect(() => {
22
- (async () => {
79
+ let cancelled = false;
80
+ let cleanup = null;
81
+ const fetchData = async () => {
23
82
  try {
24
- const propertyData = await fetchCrmProperties(propertyNames, propertiesUpdatedCallback);
25
- setProperties(propertyData);
26
- setError(null);
83
+ dispatch({ type: 'FETCH_START' });
84
+ const result = await fetchCrmProperties(stablePropertyNames, (data) => {
85
+ if (!cancelled) {
86
+ dispatch({ type: 'FETCH_SUCCESS', payload: data });
87
+ }
88
+ }, stableOptions);
89
+ if (!cancelled) {
90
+ dispatch({ type: 'FETCH_SUCCESS', payload: result.data });
91
+ cleanup = result.cleanup;
92
+ }
27
93
  }
28
94
  catch (err) {
29
- const errorData = err instanceof Error
30
- ? err
31
- : new Error('Failed to fetch CRM properties');
32
- setError(errorData);
33
- setProperties({});
95
+ if (!cancelled) {
96
+ const errorData = err instanceof Error
97
+ ? err
98
+ : new Error('Failed to fetch CRM properties');
99
+ dispatch({ type: 'FETCH_ERROR', payload: errorData });
100
+ }
34
101
  }
35
- finally {
36
- setIsLoading(false);
102
+ };
103
+ fetchData();
104
+ return () => {
105
+ cancelled = true;
106
+ // Call cleanup function to release RPC resources
107
+ if (cleanup) {
108
+ cleanup();
37
109
  }
38
- })().catch((err) => {
39
- setError(err);
40
- setProperties({});
41
- setIsLoading(false);
42
- });
43
- }, [propertyNames]);
44
- return {
45
- properties,
46
- error,
47
- isLoading,
48
- };
110
+ };
111
+ }, [stablePropertyNames, stableOptions]);
112
+ return state;
49
113
  }
@@ -1,6 +1,7 @@
1
1
  import type * as types from '../types';
2
2
  import type * as experimentalTypes from './types';
3
3
  export { useCrmProperties } from './hooks/useCrmProperties';
4
+ export { useAssociations } from './hooks/useAssociations';
4
5
  /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
5
6
  declare const Iframe: "Iframe" & {
6
7
  readonly type?: "Iframe" | undefined;
@@ -83,4 +84,36 @@ declare const FileInput: "FileInput" & {
83
84
  readonly props?: experimentalTypes.FileInputProps | undefined;
84
85
  readonly children?: true | undefined;
85
86
  } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"FileInput", experimentalTypes.FileInputProps, true>>;
86
- export { Iframe, MediaObject, Inline, Stack2, Center, SimpleGrid, GridItem, Grid, SettingsView, ExpandableText, Popover, FileInput, };
87
+ /**
88
+ * The TimeInput component renders an input field where a user can select a time.
89
+ */
90
+ declare const TimeInput: "TimeInput" & {
91
+ readonly type?: "TimeInput" | undefined;
92
+ readonly props?: experimentalTypes.TimeInputProps | undefined;
93
+ readonly children?: true | undefined;
94
+ } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"TimeInput", experimentalTypes.TimeInputProps, true>>;
95
+ /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
96
+ declare const CurrencyInput: "CurrencyInput" & {
97
+ readonly type?: "CurrencyInput" | undefined;
98
+ readonly props?: experimentalTypes.CurrencyInputProps | undefined;
99
+ readonly children?: true | undefined;
100
+ } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"CurrencyInput", experimentalTypes.CurrencyInputProps, true>>;
101
+ /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
102
+ declare const HeaderActions: "HeaderActions" & {
103
+ readonly type?: "HeaderActions" | undefined;
104
+ readonly props?: experimentalTypes.HeaderActionsProps | undefined;
105
+ readonly children?: true | undefined;
106
+ } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"HeaderActions", experimentalTypes.HeaderActionsProps, true>>;
107
+ /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
108
+ declare const PrimaryHeaderActionButton: "PrimaryHeaderActionButton" & {
109
+ readonly type?: "PrimaryHeaderActionButton" | undefined;
110
+ readonly props?: experimentalTypes.HeaderActionButtonProps | undefined;
111
+ readonly children?: true | undefined;
112
+ } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"PrimaryHeaderActionButton", experimentalTypes.HeaderActionButtonProps, true>>;
113
+ /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
114
+ declare const SecondaryHeaderActionButton: "SecondaryHeaderActionButton" & {
115
+ readonly type?: "SecondaryHeaderActionButton" | undefined;
116
+ readonly props?: experimentalTypes.HeaderActionButtonProps | undefined;
117
+ readonly children?: true | undefined;
118
+ } & import("@remote-ui/react").ReactComponentTypeFromRemoteComponentType<import("@remote-ui/types").RemoteComponentType<"SecondaryHeaderActionButton", experimentalTypes.HeaderActionButtonProps, true>>;
119
+ export { Iframe, MediaObject, Inline, Stack2, Center, SimpleGrid, GridItem, Grid, SettingsView, ExpandableText, Popover, FileInput, TimeInput, CurrencyInput, HeaderActions, PrimaryHeaderActionButton, SecondaryHeaderActionButton, };
@@ -1,5 +1,6 @@
1
1
  import { createRemoteReactComponent } from '@remote-ui/react';
2
2
  export { useCrmProperties } from './hooks/useCrmProperties';
3
+ export { useAssociations } from './hooks/useAssociations';
3
4
  /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
4
5
  const Iframe = createRemoteReactComponent('Iframe');
5
6
  /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
@@ -34,8 +35,22 @@ const ExpandableText = createRemoteReactComponent('ExpandableText');
34
35
  *
35
36
  * - {@link https://developers.hubspot.com/docs/reference/ui-components/standard-components/popover Popover Docs}
36
37
  */
37
- const Popover = createRemoteReactComponent('Popover', {
38
- fragmentProps: ['header', 'body', 'footer'],
39
- });
38
+ const Popover = createRemoteReactComponent('Popover');
40
39
  const FileInput = createRemoteReactComponent('FileInput');
41
- export { Iframe, MediaObject, Inline, Stack2, Center, SimpleGrid, GridItem, Grid, SettingsView, ExpandableText, Popover, FileInput, };
40
+ /**
41
+ * The TimeInput component renders an input field where a user can select a time.
42
+ */
43
+ const TimeInput = createRemoteReactComponent('TimeInput');
44
+ /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
45
+ const CurrencyInput = createRemoteReactComponent('CurrencyInput');
46
+ /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
47
+ const HeaderActions = createRemoteReactComponent('HeaderActions');
48
+ /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
49
+ const PrimaryHeaderActionButton = createRemoteReactComponent('PrimaryHeaderActionButton', {
50
+ fragmentProps: ['overlay'],
51
+ });
52
+ /** @experimental This component is experimental. Avoid using it in production due to potential breaking changes. Your feedback is valuable for improvements. Stay tuned for updates. */
53
+ const SecondaryHeaderActionButton = createRemoteReactComponent('SecondaryHeaderActionButton', {
54
+ fragmentProps: ['overlay'],
55
+ });
56
+ export { Iframe, MediaObject, Inline, Stack2, Center, SimpleGrid, GridItem, Grid, SettingsView, ExpandableText, Popover, FileInput, TimeInput, CurrencyInput, HeaderActions, PrimaryHeaderActionButton, SecondaryHeaderActionButton, };
@@ -127,17 +127,39 @@ export interface ExpandableTextProps {
127
127
  * @experimental do not use in production
128
128
  */
129
129
  export interface PopoverProps {
130
+ /**
131
+ * A unique ID for the popover. Used to identify the popover in the overlay system.
132
+ *
133
+ */
134
+ id: string;
135
+ /**
136
+ * The content to render inside the popover.
137
+ */
130
138
  children: ReactNode;
131
- open?: boolean;
132
- onOpenChange?: () => void;
139
+ /**
140
+ * The placement of the popover.
141
+ *
142
+ * @defaultValue `top`
143
+ */
133
144
  placement?: 'left' | 'right' | 'top' | 'bottom';
134
- header?: ReactNode;
135
- body?: ReactNode;
136
- footer?: ReactNode;
145
+ /**
146
+ * The variant of the popover.
147
+ *
148
+ * @defaultValue `default`
149
+ */
137
150
  variant?: 'default' | 'shepherd' | 'longform';
151
+ /**
152
+ * If set to `true`, will show the close button in the popover. PopoverHeader required to display close button.
153
+ *
154
+ * @defaultValue `false`
155
+ */
138
156
  showCloseButton?: boolean;
157
+ /**
158
+ * The size of the arrow in the popover. If set to `none`, the arrow will not be displayed.
159
+ *
160
+ * @defaultValue `small`
161
+ */
139
162
  arrowSize?: 'none' | 'small' | 'medium';
140
- onClick?: ReactionsHandler<ExtensionEvent>;
141
163
  }
142
164
  export interface FileInputProps {
143
165
  value?: File | {
@@ -146,4 +168,188 @@ export interface FileInputProps {
146
168
  name: string;
147
169
  onChange: (event: any) => void;
148
170
  }
171
+ /**
172
+ * @ignore
173
+ * @experimental do not use in production
174
+ */
175
+ export interface BaseTime {
176
+ /** The hour for the time (0 to 23) in 24-hour format (e.g. 0 = 12:00 AM, 9 = 9:00 AM, 15 = 3:00 PM). */
177
+ hours: number;
178
+ /** The minutes for the time (0 to 59). */
179
+ minutes: number;
180
+ }
181
+ /**
182
+ * Generic collection of props for all inputs (experimental version)
183
+ * @internal
184
+ * */
185
+ export interface BaseInputProps<T = string, V = string> {
186
+ /**
187
+ * The label text to display for the form input element.
188
+ */
189
+ label: string;
190
+ /**
191
+ * The unique identifier for the input element, this could be thought of as the HTML5 [Input element's name attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#name).
192
+ */
193
+ name: string;
194
+ /**
195
+ * The value of the input.
196
+ */
197
+ value?: T;
198
+ /**
199
+ * Determines if the required indicator should be displayed.
200
+ *
201
+ * @defaultValue `false`
202
+ */
203
+ required?: boolean;
204
+ /**
205
+ * Determines if the field is editable or not.
206
+ *
207
+ * @defaultValue `false`
208
+ */
209
+ readOnly?: boolean;
210
+ /**
211
+ * Instructional message to display to the user to help understand the purpose of the input.
212
+ */
213
+ description?: string;
214
+ /**
215
+ * Text that will appear in a tooltip next to the input label.
216
+ */
217
+ tooltip?: string;
218
+ /**
219
+ * Text that appears in the input when it has no value set.
220
+ */
221
+ placeholder?: string;
222
+ /**
223
+ * If set to `true`, `validationMessage` is displayed as an error message, if it was provided. The input will also render its error state to let the user know there is an error. If set to `false`, `validationMessage` is displayed as a success message.
224
+ *
225
+ * @defaultValue `false`
226
+ */
227
+ error?: boolean;
228
+ /**
229
+ * The value of the input on the first render.
230
+ */
231
+ defaultValue?: T;
232
+ /**
233
+ * The text to show under the input for error or success validations.
234
+ */
235
+ validationMessage?: string;
236
+ /**
237
+ * A callback function that is invoked when the value is committed. Currently these times are `onBlur` of the input and when the user submits the form.
238
+ *
239
+ * @event
240
+ */
241
+ onChange?: (value: V) => void;
242
+ /**
243
+ * A function that is called and passed the value every time the field is edited by the user. It is recommended that you do not use this value to update state, that is what `onChange` should be used for. Instead this should be used for validation.
244
+ *
245
+ * @event
246
+ */
247
+ onInput?: (value: V) => void;
248
+ /**
249
+ * A function that is called and passed the value every time the field loses focus.
250
+ *
251
+ * @event
252
+ */
253
+ onBlur?: (value: V) => void;
254
+ /**
255
+ * A function that is called and passed the value every time the field gets focused.
256
+ *
257
+ * @event
258
+ */
259
+ onFocus?: (value: V) => void;
260
+ }
261
+ /**
262
+ * @ignore
263
+ * @experimental do not use in production
264
+ *
265
+ * The values used to invoke events on the TimeInput component
266
+ */
267
+ export interface TimeInputEventsPayload extends BaseTime {
268
+ }
269
+ /**
270
+ * @internal
271
+ * @ignore
272
+ * */
273
+ type BaseTimeInputForTime = Omit<BaseInputProps<BaseTime | null, TimeInputEventsPayload>, 'onInput' | 'placeholder' | 'onChange'>;
274
+ /**
275
+ * @ignore
276
+ * @experimental do not use in production
277
+ */
278
+ export interface TimeInputProps extends BaseTimeInputForTime {
279
+ /**
280
+ * A callback function that is invoked when the value is changed.
281
+ *
282
+ * @event
283
+ */
284
+ onChange?: (value: TimeInputEventsPayload) => void;
285
+ /**
286
+ * Sets the earliest time that will be valid.
287
+ */
288
+ min?: BaseTime;
289
+ /**
290
+ * Sets the latest time that will be valid.
291
+ */
292
+ max?: BaseTime;
293
+ /**
294
+ * Sets the interval (in minutes) between the dropdown options.
295
+ *
296
+ * @defaultValue `30`
297
+ */
298
+ interval?: number;
299
+ /**
300
+ * Sets the timezone that the component will display alongside times in the TimePicker. This will not adjust the available valid inputs.
301
+ *
302
+ */
303
+ timezone?: 'userTz' | 'portalTz';
304
+ }
305
+ /**
306
+ * @ignore
307
+ * @experimental do not use in production
308
+ */
309
+ type BaseInputForNumber = Omit<BaseInputProps<number, number>, 'onInput'>;
310
+ /**
311
+ * @ignore
312
+ * @experimental do not use in production
313
+ */
314
+ export interface CurrencyInputProps extends BaseInputForNumber {
315
+ /**
316
+ * ISO 4217 currency code (e.g., "USD", "EUR", "JPY")
317
+ * @defaultValue "USD"
318
+ */
319
+ currency?: string;
320
+ /**
321
+ * Sets the number of decimal places for the currency
322
+ * If not provided, defaults to currency-specific precision
323
+ */
324
+ precision?: number;
325
+ /**
326
+ * Sets the lower bound of the input
327
+ */
328
+ min?: number;
329
+ /**
330
+ * Sets the upper bound of the input
331
+ */
332
+ max?: number;
333
+ }
334
+ /**
335
+ * @ignore
336
+ * @experimental do not use in production
337
+ */
338
+ export interface HeaderActionsProps {
339
+ children: ReactNode;
340
+ }
341
+ /**
342
+ * @ignore
343
+ * @experimental do not use in production
344
+ */
345
+ export interface HeaderActionButtonProps {
346
+ onClick?: ReactionsHandler<ExtensionEvent>;
347
+ href?: string | {
348
+ url: string;
349
+ external?: boolean;
350
+ };
351
+ disabled?: boolean;
352
+ children: ReactNode;
353
+ overlay?: RemoteFragment;
354
+ }
149
355
  export {};