@aws-amplify/ui-react-core 3.0.30 → 3.1.1

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 (33) hide show
  1. package/dist/elements.js +116 -3
  2. package/dist/esm/elements/ControlsContext.mjs +71 -0
  3. package/dist/esm/elements/ElementsContext.mjs +3 -2
  4. package/dist/esm/elements/defineBaseElement.mjs +30 -1
  5. package/dist/esm/elements/utils.mjs +11 -0
  6. package/dist/esm/elements/withBaseElementProps.mjs +1 -1
  7. package/dist/esm/elements.mjs +3 -1
  8. package/dist/esm/hooks/useDataState.mjs +10 -4
  9. package/dist/esm/utils/createContextUtilities.mjs +6 -3
  10. package/dist/index.js +15 -7
  11. package/dist/types/elements/ControlsContext.d.ts +63 -0
  12. package/dist/types/elements/ElementsContext.d.ts +3 -2
  13. package/dist/types/elements/defineBaseElement.d.ts +19 -2
  14. package/dist/types/elements/index.d.ts +4 -1
  15. package/dist/types/elements/types.d.ts +88 -6
  16. package/dist/types/elements/utils.d.ts +3 -0
  17. package/dist/types/elements/withBaseElementProps.d.ts +3 -3
  18. package/dist/types/hooks/index.d.ts +1 -1
  19. package/dist/types/hooks/useDataState.d.ts +6 -1
  20. package/dist/types/index.d.ts +1 -1
  21. package/dist/types/utils/createContextUtilities.d.ts +1 -1
  22. package/package.json +3 -3
  23. package/src/elements/ControlsContext.tsx +89 -0
  24. package/src/elements/ElementsContext.tsx +3 -2
  25. package/src/elements/defineBaseElement.tsx +50 -2
  26. package/src/elements/index.ts +7 -1
  27. package/src/elements/types.ts +114 -6
  28. package/src/elements/utils.ts +20 -0
  29. package/src/elements/withBaseElementProps.tsx +3 -3
  30. package/src/hooks/index.ts +6 -1
  31. package/src/hooks/useDataState.ts +25 -7
  32. package/src/index.ts +2 -0
  33. package/src/utils/createContextUtilities.tsx +9 -6
@@ -12,17 +12,27 @@ import React from 'react';
12
12
  * are always optional at the interface level, allowing for additional `props`
13
13
  * to be added to existing `BaseElement` interfaces as needed.
14
14
  */
15
- export type BaseElement<T = {}, K = {}> = React.ForwardRefExoticComponent<React.PropsWithoutRef<T> & React.RefAttributes<K>>;
15
+ export type BaseElement<T = {}> = (props: T) => React.JSX.Element;
16
+ /**
17
+ * @internal @unstable
18
+ *
19
+ * see @type {BaseElement}
20
+ *
21
+ * `BaseElement` with a `ref` corresponding to the `element` type
22
+ */
23
+ export type BaseElementWithRef<T = {}, K = {}> = React.ForwardRefExoticComponent<React.PropsWithoutRef<T> & React.RefAttributes<K>>;
16
24
  type ListElementSubType = 'Ordered' | 'Unordered';
17
- type ListElementDisplayName = 'List' | `${ListElementSubType}List`;
18
- type TableElementSubType = 'Body' | 'Data' | 'Row' | 'Head' | 'Header';
25
+ type ListElementDisplayName = `${ListElementSubType}List`;
26
+ type TableElementSubType = 'Body' | 'DataCell' | 'Row' | 'Head' | 'Header';
19
27
  type TableElementDisplayName = 'Table' | `Table${TableElementSubType}`;
28
+ type DescriptionElementSubType = 'Details' | 'List' | 'Term';
29
+ type DescriptionElementDisplayName = `Description${DescriptionElementSubType}`;
20
30
  /**
21
31
  * @internal @unstable
22
32
  *
23
33
  * allowed values of `displayName` of `BaseElement` and `ElemebtsContext` keys
24
34
  */
25
- export type ElementDisplayName = 'Button' | 'Divider' | 'Heading' | 'Icon' | 'Image' | 'Input' | 'Label' | 'ListItem' | 'Nav' | 'ProgressBar' | 'Span' | 'Text' | 'TextArea' | 'Title' | 'View' | ListElementDisplayName | TableElementDisplayName;
35
+ export type ElementDisplayName = 'Button' | 'Heading' | 'Icon' | 'Image' | 'Input' | 'Label' | 'ListItem' | 'Nav' | 'ProgressBar' | 'Span' | 'Text' | 'TextArea' | 'Title' | 'View' | DescriptionElementDisplayName | ListElementDisplayName | TableElementDisplayName;
26
36
  /**
27
37
  * @internal @unstable
28
38
  */
@@ -36,7 +46,7 @@ export type ReactElementType = keyof React.JSX.IntrinsicElements;
36
46
  /**
37
47
  * @internal @unstable
38
48
  */
39
- export type ReactElementProps<T extends ReactElementType> = React.JSX.IntrinsicElements[T];
49
+ export type ReactElementProps<T extends ReactElementType> = React.ComponentProps<T>;
40
50
  /**
41
51
  * @internal @unstable
42
52
  *
@@ -46,8 +56,80 @@ type ElementPropKey<T> = T | 'children' | 'className' | 'style';
46
56
  /**
47
57
  * @internal @unstable
48
58
  */
49
- export type BaseElementProps<T extends keyof K, V = string, K extends Record<ElementPropKey<keyof K>, any> = Record<string, any>> = React.AriaAttributes & React.RefAttributes<ElementRefType<K>> & Pick<K, ElementPropKey<T>> & {
59
+ export type BaseElementProps<T extends keyof K, V = string, K extends Record<ElementPropKey<keyof K>, any> = Record<string, any>> = React.AriaAttributes & React.Attributes & Pick<K, ElementPropKey<T>> & {
50
60
  testId?: string;
51
61
  variant?: V;
52
62
  };
63
+ /**
64
+ * @internal @unstable
65
+ */
66
+ export type BaseElementWithRefProps<T extends keyof K, V = string, K extends Record<ElementPropKey<keyof K>, any> = Record<string, any>> = BaseElementProps<T, V, K> & React.RefAttributes<ElementRefType<K>>;
67
+ /**
68
+ * @internal @unstable
69
+ */
70
+ export type ElementWithAndWithoutRef<T extends ReactElementType, K extends React.ComponentType<React.ComponentProps<T>> = React.ComponentType<React.ComponentProps<T>>> = K extends React.ComponentType<infer U> ? React.ForwardRefExoticComponent<U> : never;
71
+ /**
72
+ * @internal @unstable
73
+ *
74
+ * Merge `BaseElement` defintions with `elements` types provided by
75
+ * consumers, for use with top level connected component function
76
+ * signatures.
77
+ *
78
+ * Example:
79
+ *
80
+ * ```tsx
81
+ * export function createStorageBrowser<
82
+ * T extends Partial<StorageBrowserElements>,
83
+ * >({ elements }: CreateStorageBrowserInput<T> = {}): {
84
+ * StorageBrowser: StorageBrowser<MergeElements<StorageBrowserElements, T>>
85
+ * } {
86
+ * // ...do create stuff
87
+ * };
88
+ * ```
89
+ */
90
+ export type MergeBaseElements<T, K extends Partial<T>> = {
91
+ [U in keyof T]: K[U] extends T[U] ? K[U] : T[U];
92
+ };
93
+ /**
94
+ * @internal @unstable
95
+ *
96
+ * Extend the defintion of a `BaseElement` with additional `props`.
97
+ *
98
+ * Use cases are restricted to scenarios where additional `props`
99
+ * are required for a `ControlElement` interface, for example:
100
+ *
101
+ * @example
102
+ * ```tsx
103
+ * const FieldInput = defineBaseElementWithRef({
104
+ * type: 'input',
105
+ * displayName: 'Input'
106
+ * });
107
+ *
108
+ * type InputWithSearchCallback =
109
+ * ExtendBaseElement<
110
+ * typeof FieldInput,
111
+ * { onSearch?: (event: { value: string }) => void }
112
+ * >
113
+ *
114
+ * const SearchInput = React.forwardRef((
115
+ * { onSearch, ...props }
116
+ * ref
117
+ * ) => {
118
+ * // ...do something with onSearch
119
+ *
120
+ * return <FieldInput {...props} ref={ref} />;
121
+ * });
122
+ * ```
123
+ *
124
+ * Caveats:
125
+ * - additional `props` should not be passed directly to
126
+ * `BaseElement` components, the outputted interface should be
127
+ * applied to a wrapping element that handles the additional `props`
128
+ *
129
+ * - additional `props` that share a key with existing `props`
130
+ * are omitted from the outputted interface to adhere to `BaseElement`
131
+ * type contracts
132
+ *
133
+ */
134
+ export type ExtendBaseElement<T extends React.ComponentType, K = {}, U extends React.ComponentPropsWithRef<T> = React.ComponentPropsWithRef<T>> = BaseElementWithRef<U & Omit<K, keyof U>, U>;
53
135
  export {};
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ export declare function isComponent<T>(component?: React.ComponentType<T> | React.ForwardRefExoticComponent<T>): component is React.ComponentType<T>;
3
+ export declare function isForwardRefExoticComponent<T>(component: React.ComponentType<T> | React.ForwardRefExoticComponent<T>): component is React.ForwardRefExoticComponent<T>;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { BaseElement, ElementRefType } from './types';
2
+ import { BaseElementWithRef, ElementRefType } from './types';
3
3
  /**
4
4
  * @internal @unstable
5
5
  *
@@ -15,7 +15,7 @@ import { BaseElement, ElementRefType } from './types';
15
15
  * type InputElementPropKey = 'onChange' | 'type';
16
16
  *
17
17
  * // create `InputElement` base with `type` generic and extended `props` key
18
- * export const InputElement = defineBaseElement<"input", InputElementPropKey>({
18
+ * export const InputElement = defineBaseElementWithRef<"input", InputElementPropKey>({
19
19
  * type: "input",
20
20
  * displayName: "Input",
21
21
  * });
@@ -31,4 +31,4 @@ import { BaseElement, ElementRefType } from './types';
31
31
  * @param defaultProps `defaultProps` to apply to `Target`, accepts object or callback
32
32
  * @returns extended `BaseElement` with `defaultProps`
33
33
  */
34
- export default function withBaseElementProps<T, K extends T | ((input: T) => T)>(Target: React.ForwardRefExoticComponent<T>, defaultProps: K): BaseElement<T, ElementRefType<T>>;
34
+ export default function withBaseElementProps<T, K extends T | ((input: T) => T)>(Target: React.ForwardRefExoticComponent<T>, defaultProps: K): BaseElementWithRef<T, ElementRefType<T>>;
@@ -1,4 +1,4 @@
1
- export { default as useDataState, DataState } from './useDataState';
1
+ export { default as useDataState, AsyncDataAction, DataAction, DataState, } from './useDataState';
2
2
  export { default as useDeprecationWarning, UseDeprecationWarning, } from './useDeprecationWarning';
3
3
  export { default as useGetUrl } from './useGetUrl';
4
4
  export { default as useHasValueUpdated } from './useHasValueUpdated';
@@ -4,4 +4,9 @@ export interface DataState<T> {
4
4
  isLoading: boolean;
5
5
  message: string | undefined;
6
6
  }
7
- export default function useDataState<T, K>(action: (prevData: T, ...input: K[]) => T | Promise<T>, initialData: T): [state: DataState<T>, handleAction: (...input: K[]) => void];
7
+ export type DataAction<T = any, K = any> = (prevData: T, input: K) => T;
8
+ export type AsyncDataAction<T = any, K = any> = (prevData: T, input: K) => Promise<T>;
9
+ export default function useDataState<T, K>(action: DataAction<T, K> | AsyncDataAction<T, K>, initialData: T, options?: {
10
+ onSuccess?: (data: T) => void;
11
+ onError?: (message: string) => void;
12
+ }): [state: DataState<T>, handleAction: (input: K) => void];
@@ -1,5 +1,5 @@
1
1
  export { AuthenticatorComponentDefaults, AuthenticatorComponentDefaultProps, AuthenticatorComponentOverrides, AuthenticatorFooterComponent, AuthenticatorFormFieldsComponent, AuthenticatorHeaderComponent, AuthenticatorLegacyField, AuthenticatorMachineContext, AuthenticatorProvider, AuthenticatorRouteComponentKey, AuthenticatorRouteComponentName, isAuthenticatorComponentRouteKey, resolveAuthenticatorComponents, useAuthenticator, useAuthenticatorRoute, UseAuthenticator, useAuthenticatorInitMachine, UseAuthenticatorRoute, } from './Authenticator';
2
2
  export { FormProvider, FormProviderProps, RenderNothing, FormValues, FormHandle, useField, useForm, UseForm, Validate, Validator, withFormProvider, } from './components';
3
- export { useDeprecationWarning, UseDeprecationWarning, useGetUrl, useHasValueUpdated, usePreviousValue, useSetUserAgent, useTimeout, useDataState, DataState, useDropZone, UseDropZoneParams, } from './hooks';
3
+ export { AsyncDataAction, DataAction, useDeprecationWarning, UseDeprecationWarning, useGetUrl, useHasValueUpdated, usePreviousValue, useSetUserAgent, useTimeout, useDataState, DataState, useDropZone, UseDropZoneParams, } from './hooks';
4
4
  export { MergeProps } from './types';
5
5
  export { createContextUtilities } from './utils';
@@ -16,7 +16,7 @@ type HookParams = {
16
16
  };
17
17
  type UtilityKey<ContextName extends string> = `${ContextName}Provider` | `use${ContextName}` | `${ContextName}Context`;
18
18
  type CreateContextUtilitiesReturn<ContextType, ContextName extends string> = {
19
- [Key in UtilityKey<ContextName>]: Key extends `${string}Provider` ? React.ComponentType<React.PropsWithChildren<ContextType>> : Key extends `use${string}` ? (params?: HookParams) => ContextType : Key extends `${string}Context` ? React.Context<ContextType | undefined> : never;
19
+ [Key in UtilityKey<ContextName>]: Key extends `${string}Provider` ? React.ComponentType<React.PropsWithChildren<ContextType>> : Key extends `use${string}` ? (params?: HookParams) => ContextType : Key extends `${string}Context` ? React.Context<ContextType> : never;
20
20
  };
21
21
  /**
22
22
  * Uses `ContextType`/`Name` generics and `options` to create:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws-amplify/ui-react-core",
3
- "version": "3.0.30",
3
+ "version": "3.1.1",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/esm/index.mjs",
6
6
  "react-native": "src/index.ts",
@@ -40,14 +40,14 @@
40
40
  "typecheck": "tsc --noEmit"
41
41
  },
42
42
  "dependencies": {
43
- "@aws-amplify/ui": "6.6.6",
43
+ "@aws-amplify/ui": "6.7.1",
44
44
  "@xstate/react": "^3.2.2",
45
45
  "lodash": "4.17.21",
46
46
  "react-hook-form": "^7.43.5",
47
47
  "xstate": "^4.33.6"
48
48
  },
49
49
  "peerDependencies": {
50
- "aws-amplify": "^6.6.5",
50
+ "aws-amplify": "^6.9.0",
51
51
  "react": "^16.14.0 || ^17.0 || ^18.0"
52
52
  },
53
53
  "sideEffects": false
@@ -0,0 +1,89 @@
1
+ import React from 'react';
2
+ import { isComponent } from './utils';
3
+
4
+ /**
5
+ * @internal @unstable
6
+ */
7
+ export interface Controls
8
+ extends Partial<Record<string, React.ComponentType>> {}
9
+
10
+ /**
11
+ * @internal @unstable
12
+ */
13
+ export const ControlsContext = React.createContext<Controls | undefined>(
14
+ undefined
15
+ );
16
+
17
+ /**
18
+ * @internal @unstable
19
+ *
20
+ * `ControlsProvider` provides the values contained in `ControlsContext`
21
+ * to consumers. `ControlsContext` lookup is handled directly
22
+ * by `Control` components returned by `withControls`.
23
+ *
24
+ * @example
25
+ *
26
+ * Add `ControlsContext` aware `Controls` components to a Connected
27
+ * Component:
28
+ *
29
+ * ```tsx
30
+ * const DataList = withControls(function DataList<T>(data: T[]) {
31
+ * return <ScrollView>data.map(ListItem)</ScrollView>;
32
+ * }, 'DataList');
33
+ *
34
+ * const DataListControl = () => {
35
+ * const data = useData();
36
+ * return <DataList data={data} />;
37
+ * }
38
+ *
39
+ * interface ComponentControls {
40
+ * DataList: typeof DataListControl;
41
+ * }
42
+ *
43
+ * function Component<T extends ComponentControls>(
44
+ * controls?: T
45
+ * ) {
46
+ * function ConnectedComponent({
47
+ * children,
48
+ * }: { children?: React.ReactNode }) {
49
+ * return (
50
+ * <ControlsProvider controls={controls}>
51
+ * {children}
52
+ * </ControlsProvider>
53
+ * );
54
+ * }
55
+ *
56
+ * return ConnectedComponent;
57
+ * }
58
+ * ```
59
+ */
60
+ export function ControlsProvider<T extends Controls>({
61
+ controls,
62
+ ...props
63
+ }: {
64
+ children?: React.ReactNode;
65
+ controls?: T;
66
+ }): React.JSX.Element {
67
+ return <ControlsContext.Provider {...props} value={controls} />;
68
+ }
69
+
70
+ /**
71
+ * @internal @unstable
72
+ *
73
+ * @note reference `ControlsProvider` for example usage
74
+ */
75
+ export function withControls<
76
+ T extends React.ComponentType<any>,
77
+ K extends keyof Controls,
78
+ >(Default: T, name: K): (props: React.ComponentProps<T>) => React.JSX.Element {
79
+ const Component = (props: React.ComponentProps<T>) => {
80
+ const Override = React.useContext(ControlsContext)?.[name];
81
+ if (isComponent(Override)) {
82
+ return <Override {...props} />;
83
+ }
84
+ return <Default {...props} />;
85
+ };
86
+
87
+ Component.displayName = name;
88
+ return Component;
89
+ }
@@ -16,7 +16,8 @@ export const ElementsContext = React.createContext<Elements | undefined>(
16
16
  *
17
17
  * `ElementsProvider` provides the values contained in `ElementsContext`
18
18
  * to its `children`. `ElementsContext` lookup is handled directly
19
- * by `BaseElement`components returned by `defineBaseElement`.
19
+ * by `BaseElement`components returned by `defineBaseElement` and
20
+ * `defineBaseElementWithRef`.
20
21
  *
21
22
  * @example
22
23
  *
@@ -25,7 +26,7 @@ export const ElementsContext = React.createContext<Elements | undefined>(
25
26
  *
26
27
  * ```tsx
27
28
  * // `BaseElement`, renders custom or default element defintion
28
- * const ViewElement = defineBaseElement({
29
+ * const ViewElement = defineBaseElementWithRef({
29
30
  * displayName: "View",
30
31
  * type: "div",
31
32
  * });
@@ -3,6 +3,8 @@ import { ElementsContext } from './ElementsContext';
3
3
  import {
4
4
  BaseElement,
5
5
  BaseElementProps,
6
+ BaseElementWithRef,
7
+ BaseElementWithRefProps,
6
8
  ElementDisplayName,
7
9
  ElementRefType,
8
10
  ReactElementProps,
@@ -40,7 +42,7 @@ export interface DefineBaseElementInput<T> {
40
42
  * @param {DefineBaseElementInput} input `BaseElement` parameters
41
43
  * @returns {BaseElement} `ElementsContext` aware UI component
42
44
  */
43
- export default function defineBaseElement<
45
+ export function defineBaseElement<
44
46
  // element type
45
47
  T extends ReactElementType,
46
48
  // string union of base element props to include
@@ -51,7 +53,53 @@ export default function defineBaseElement<
51
53
  U extends ReactElementProps<T> = ReactElementProps<T>,
52
54
  // control element props
53
55
  P extends BaseElementProps<K, V, U> = BaseElementProps<K, V, U>,
54
- >(input: DefineBaseElementInput<T>): BaseElement<P, ElementRefType<P>> {
56
+ >(input: DefineBaseElementInput<T>): BaseElement<P> {
57
+ const { displayName, type } = input;
58
+
59
+ const Element = ({ variant, ...props }: Omit<P, 'ref'>) => {
60
+ const Element = React.useContext(ElementsContext)?.[displayName];
61
+
62
+ if (Element) {
63
+ // only pass `variant` to provided `Element` values
64
+ return <Element {...{ ...props, variant }} />;
65
+ }
66
+
67
+ return React.createElement(type, props);
68
+ };
69
+
70
+ Element.displayName = displayName;
71
+
72
+ return Element;
73
+ }
74
+
75
+ /**
76
+ * @internal @unstable
77
+ *
78
+ * Defines a `ElementsContext` aware `BaseElement` UI component of the
79
+ * provided `type` with an assigned `displayName` and element `ref`.
80
+ *
81
+ * If `BaseElement` is used as a child of an `ElementsProvider`, returns the
82
+ * `BaseElement` value of the provided `displayName` of `ElementsContext`.
83
+ *
84
+ * When used outside of a parent `ElementsProvider` or no `BaseElement`
85
+ * of `displayName` is found in the `ElementsContext`, returns a stateless,
86
+ * unstyled HTML element of the provided `type`.
87
+ *
88
+ * @param {DefineBaseElementInput} input `BaseElement` parameters
89
+ * @returns {BaseElementWithRefProps} `ElementsContext` aware UI component
90
+ */
91
+ export function defineBaseElementWithRef<
92
+ // element type
93
+ T extends ReactElementType,
94
+ // string union of base element props to include
95
+ K extends keyof U = never,
96
+ // variant string union
97
+ V = string,
98
+ // available props of base element type
99
+ U extends ReactElementProps<T> = ReactElementProps<T>,
100
+ // control element props
101
+ P extends BaseElementWithRefProps<K, V, U> = BaseElementWithRefProps<K, V, U>,
102
+ >(input: DefineBaseElementInput<T>): BaseElementWithRef<P, ElementRefType<P>> {
55
103
  const { displayName, type } = input;
56
104
 
57
105
  const Element = React.forwardRef<ElementRefType<P>, P>(
@@ -1,3 +1,9 @@
1
- export { default as defineBaseElement } from './defineBaseElement';
1
+ export * from './ControlsContext';
2
+ export {
3
+ defineBaseElement,
4
+ defineBaseElementWithRef,
5
+ } from './defineBaseElement';
2
6
  export { default as withBaseElementProps } from './withBaseElementProps';
3
7
  export { ElementsProvider } from './ElementsContext';
8
+ export { isComponent, isForwardRefExoticComponent } from './utils';
9
+ export * from './types';
@@ -13,16 +13,31 @@ import React from 'react';
13
13
  * are always optional at the interface level, allowing for additional `props`
14
14
  * to be added to existing `BaseElement` interfaces as needed.
15
15
  */
16
- export type BaseElement<T = {}, K = {}> = React.ForwardRefExoticComponent<
16
+ export type BaseElement<T = {}> = (props: T) => React.JSX.Element;
17
+
18
+ /**
19
+ * @internal @unstable
20
+ *
21
+ * see @type {BaseElement}
22
+ *
23
+ * `BaseElement` with a `ref` corresponding to the `element` type
24
+ */
25
+ export type BaseElementWithRef<
26
+ T = {},
27
+ K = {},
28
+ > = React.ForwardRefExoticComponent<
17
29
  React.PropsWithoutRef<T> & React.RefAttributes<K>
18
30
  >;
19
31
 
20
32
  type ListElementSubType = 'Ordered' | 'Unordered';
21
- type ListElementDisplayName = 'List' | `${ListElementSubType}List`;
33
+ type ListElementDisplayName = `${ListElementSubType}List`;
22
34
 
23
- type TableElementSubType = 'Body' | 'Data' | 'Row' | 'Head' | 'Header';
35
+ type TableElementSubType = 'Body' | 'DataCell' | 'Row' | 'Head' | 'Header';
24
36
  type TableElementDisplayName = 'Table' | `Table${TableElementSubType}`;
25
37
 
38
+ type DescriptionElementSubType = 'Details' | 'List' | 'Term';
39
+ type DescriptionElementDisplayName = `Description${DescriptionElementSubType}`;
40
+
26
41
  /**
27
42
  * @internal @unstable
28
43
  *
@@ -30,7 +45,6 @@ type TableElementDisplayName = 'Table' | `Table${TableElementSubType}`;
30
45
  */
31
46
  export type ElementDisplayName =
32
47
  | 'Button'
33
- | 'Divider'
34
48
  | 'Heading' // h1, h2, etc
35
49
  | 'Icon'
36
50
  | 'Image'
@@ -44,6 +58,7 @@ export type ElementDisplayName =
44
58
  | 'TextArea'
45
59
  | 'Title'
46
60
  | 'View'
61
+ | DescriptionElementDisplayName
47
62
  | ListElementDisplayName
48
63
  | TableElementDisplayName;
49
64
 
@@ -68,7 +83,7 @@ export type ReactElementType = keyof React.JSX.IntrinsicElements;
68
83
  * @internal @unstable
69
84
  */
70
85
  export type ReactElementProps<T extends ReactElementType> =
71
- React.JSX.IntrinsicElements[T];
86
+ React.ComponentProps<T>;
72
87
 
73
88
  /**
74
89
  * @internal @unstable
@@ -85,5 +100,98 @@ export type BaseElementProps<
85
100
  V = string,
86
101
  K extends Record<ElementPropKey<keyof K>, any> = Record<string, any>,
87
102
  > = React.AriaAttributes &
88
- React.RefAttributes<ElementRefType<K>> &
103
+ React.Attributes &
89
104
  Pick<K, ElementPropKey<T>> & { testId?: string; variant?: V };
105
+
106
+ /**
107
+ * @internal @unstable
108
+ */
109
+ export type BaseElementWithRefProps<
110
+ T extends keyof K,
111
+ V = string,
112
+ K extends Record<ElementPropKey<keyof K>, any> = Record<string, any>,
113
+ > = BaseElementProps<T, V, K> & React.RefAttributes<ElementRefType<K>>;
114
+
115
+ /**
116
+ * @internal @unstable
117
+ */
118
+ export type ElementWithAndWithoutRef<
119
+ T extends ReactElementType,
120
+ K extends React.ComponentType<React.ComponentProps<T>> = React.ComponentType<
121
+ React.ComponentProps<T>
122
+ >,
123
+ > = K extends React.ComponentType<infer U>
124
+ ? React.ForwardRefExoticComponent<U>
125
+ : never;
126
+
127
+ /**
128
+ * @internal @unstable
129
+ *
130
+ * Merge `BaseElement` defintions with `elements` types provided by
131
+ * consumers, for use with top level connected component function
132
+ * signatures.
133
+ *
134
+ * Example:
135
+ *
136
+ * ```tsx
137
+ * export function createStorageBrowser<
138
+ * T extends Partial<StorageBrowserElements>,
139
+ * >({ elements }: CreateStorageBrowserInput<T> = {}): {
140
+ * StorageBrowser: StorageBrowser<MergeElements<StorageBrowserElements, T>>
141
+ * } {
142
+ * // ...do create stuff
143
+ * };
144
+ * ```
145
+ */
146
+ export type MergeBaseElements<T, K extends Partial<T>> = {
147
+ [U in keyof T]: K[U] extends T[U] ? K[U] : T[U];
148
+ };
149
+
150
+ /**
151
+ * @internal @unstable
152
+ *
153
+ * Extend the defintion of a `BaseElement` with additional `props`.
154
+ *
155
+ * Use cases are restricted to scenarios where additional `props`
156
+ * are required for a `ControlElement` interface, for example:
157
+ *
158
+ * @example
159
+ * ```tsx
160
+ * const FieldInput = defineBaseElementWithRef({
161
+ * type: 'input',
162
+ * displayName: 'Input'
163
+ * });
164
+ *
165
+ * type InputWithSearchCallback =
166
+ * ExtendBaseElement<
167
+ * typeof FieldInput,
168
+ * { onSearch?: (event: { value: string }) => void }
169
+ * >
170
+ *
171
+ * const SearchInput = React.forwardRef((
172
+ * { onSearch, ...props }
173
+ * ref
174
+ * ) => {
175
+ * // ...do something with onSearch
176
+ *
177
+ * return <FieldInput {...props} ref={ref} />;
178
+ * });
179
+ * ```
180
+ *
181
+ * Caveats:
182
+ * - additional `props` should not be passed directly to
183
+ * `BaseElement` components, the outputted interface should be
184
+ * applied to a wrapping element that handles the additional `props`
185
+ *
186
+ * - additional `props` that share a key with existing `props`
187
+ * are omitted from the outputted interface to adhere to `BaseElement`
188
+ * type contracts
189
+ *
190
+ */
191
+ export type ExtendBaseElement<
192
+ // `BaseElement` to extend
193
+ T extends React.ComponentType,
194
+ // additional `props`
195
+ K = {},
196
+ U extends React.ComponentPropsWithRef<T> = React.ComponentPropsWithRef<T>,
197
+ > = BaseElementWithRef<U & Omit<K, keyof U>, U>;
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+
3
+ export function isComponent<T>(
4
+ component?: React.ComponentType<T> | React.ForwardRefExoticComponent<T>
5
+ ): component is React.ComponentType<T> {
6
+ return typeof component === 'function';
7
+ }
8
+
9
+ export function isForwardRefExoticComponent<T>(
10
+ component: React.ComponentType<T> | React.ForwardRefExoticComponent<T>
11
+ ): component is React.ForwardRefExoticComponent<T> {
12
+ return (
13
+ typeof component === 'object' &&
14
+ typeof (component as React.ForwardRefExoticComponent<T>).$$typeof ===
15
+ 'symbol' &&
16
+ ['react.memo', 'react.forward_ref'].includes(
17
+ (component as React.ForwardRefExoticComponent<T>).$$typeof.description!
18
+ )
19
+ );
20
+ }
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { BaseElement, ElementRefType } from './types';
2
+ import { BaseElementWithRef, ElementRefType } from './types';
3
3
 
4
4
  /**
5
5
  * @internal @unstable
@@ -16,7 +16,7 @@ import { BaseElement, ElementRefType } from './types';
16
16
  * type InputElementPropKey = 'onChange' | 'type';
17
17
  *
18
18
  * // create `InputElement` base with `type` generic and extended `props` key
19
- * export const InputElement = defineBaseElement<"input", InputElementPropKey>({
19
+ * export const InputElement = defineBaseElementWithRef<"input", InputElementPropKey>({
20
20
  * type: "input",
21
21
  * displayName: "Input",
22
22
  * });
@@ -38,7 +38,7 @@ export default function withBaseElementProps<
38
38
  >(
39
39
  Target: React.ForwardRefExoticComponent<T>,
40
40
  defaultProps: K
41
- ): BaseElement<T, ElementRefType<T>> {
41
+ ): BaseElementWithRef<T, ElementRefType<T>> {
42
42
  const Component = React.forwardRef<ElementRefType<T>, T>((props, ref) => (
43
43
  <Target
44
44
  {...{
@@ -1,4 +1,9 @@
1
- export { default as useDataState, DataState } from './useDataState';
1
+ export {
2
+ default as useDataState,
3
+ AsyncDataAction,
4
+ DataAction,
5
+ DataState,
6
+ } from './useDataState';
2
7
 
3
8
  export {
4
9
  default as useDeprecationWarning,