@aws-amplify/ui-react-core 3.0.29 → 3.1.0

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 (38) 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/hooks/useDropZone.mjs +13 -4
  10. package/dist/esm/utils/createContextUtilities.mjs +6 -3
  11. package/dist/esm/utils/processDroppedItems.mjs +66 -0
  12. package/dist/index.js +92 -11
  13. package/dist/types/elements/ControlsContext.d.ts +63 -0
  14. package/dist/types/elements/ElementsContext.d.ts +3 -2
  15. package/dist/types/elements/defineBaseElement.d.ts +19 -2
  16. package/dist/types/elements/index.d.ts +4 -1
  17. package/dist/types/elements/types.d.ts +88 -6
  18. package/dist/types/elements/utils.d.ts +3 -0
  19. package/dist/types/elements/withBaseElementProps.d.ts +3 -3
  20. package/dist/types/hooks/index.d.ts +1 -1
  21. package/dist/types/hooks/useDataState.d.ts +6 -1
  22. package/dist/types/index.d.ts +1 -1
  23. package/dist/types/utils/createContextUtilities.d.ts +1 -1
  24. package/dist/types/utils/processDroppedItems.d.ts +1 -0
  25. package/package.json +3 -3
  26. package/src/elements/ControlsContext.tsx +89 -0
  27. package/src/elements/ElementsContext.tsx +3 -2
  28. package/src/elements/defineBaseElement.tsx +50 -2
  29. package/src/elements/index.ts +7 -1
  30. package/src/elements/types.ts +114 -6
  31. package/src/elements/utils.ts +20 -0
  32. package/src/elements/withBaseElementProps.tsx +3 -3
  33. package/src/hooks/index.ts +6 -1
  34. package/src/hooks/useDataState.ts +25 -7
  35. package/src/hooks/useDropZone.ts +18 -7
  36. package/src/index.ts +2 -0
  37. package/src/utils/createContextUtilities.tsx +9 -6
  38. package/src/utils/processDroppedItems.ts +79 -0
@@ -0,0 +1,63 @@
1
+ import React from 'react';
2
+ /**
3
+ * @internal @unstable
4
+ */
5
+ export interface Controls extends Partial<Record<string, React.ComponentType>> {
6
+ }
7
+ /**
8
+ * @internal @unstable
9
+ */
10
+ export declare const ControlsContext: React.Context<Controls | undefined>;
11
+ /**
12
+ * @internal @unstable
13
+ *
14
+ * `ControlsProvider` provides the values contained in `ControlsContext`
15
+ * to consumers. `ControlsContext` lookup is handled directly
16
+ * by `Control` components returned by `withControls`.
17
+ *
18
+ * @example
19
+ *
20
+ * Add `ControlsContext` aware `Controls` components to a Connected
21
+ * Component:
22
+ *
23
+ * ```tsx
24
+ * const DataList = withControls(function DataList<T>(data: T[]) {
25
+ * return <ScrollView>data.map(ListItem)</ScrollView>;
26
+ * }, 'DataList');
27
+ *
28
+ * const DataListControl = () => {
29
+ * const data = useData();
30
+ * return <DataList data={data} />;
31
+ * }
32
+ *
33
+ * interface ComponentControls {
34
+ * DataList: typeof DataListControl;
35
+ * }
36
+ *
37
+ * function Component<T extends ComponentControls>(
38
+ * controls?: T
39
+ * ) {
40
+ * function ConnectedComponent({
41
+ * children,
42
+ * }: { children?: React.ReactNode }) {
43
+ * return (
44
+ * <ControlsProvider controls={controls}>
45
+ * {children}
46
+ * </ControlsProvider>
47
+ * );
48
+ * }
49
+ *
50
+ * return ConnectedComponent;
51
+ * }
52
+ * ```
53
+ */
54
+ export declare function ControlsProvider<T extends Controls>({ controls, ...props }: {
55
+ children?: React.ReactNode;
56
+ controls?: T;
57
+ }): React.JSX.Element;
58
+ /**
59
+ * @internal @unstable
60
+ *
61
+ * @note reference `ControlsProvider` for example usage
62
+ */
63
+ export declare function withControls<T extends React.ComponentType<any>, K extends keyof Controls>(Default: T, name: K): (props: React.ComponentProps<T>) => React.JSX.Element;
@@ -11,7 +11,8 @@ export declare const ElementsContext: React.Context<Elements | undefined>;
11
11
  *
12
12
  * `ElementsProvider` provides the values contained in `ElementsContext`
13
13
  * to its `children`. `ElementsContext` lookup is handled directly
14
- * by `BaseElement`components returned by `defineBaseElement`.
14
+ * by `BaseElement`components returned by `defineBaseElement` and
15
+ * `defineBaseElementWithRef`.
15
16
  *
16
17
  * @example
17
18
  *
@@ -20,7 +21,7 @@ export declare const ElementsContext: React.Context<Elements | undefined>;
20
21
  *
21
22
  * ```tsx
22
23
  * // `BaseElement`, renders custom or default element defintion
23
- * const ViewElement = defineBaseElement({
24
+ * const ViewElement = defineBaseElementWithRef({
24
25
  * displayName: "View",
25
26
  * type: "div",
26
27
  * });
@@ -1,4 +1,4 @@
1
- import { BaseElement, BaseElementProps, ElementDisplayName, ElementRefType, ReactElementProps, ReactElementType } from './types';
1
+ import { BaseElement, BaseElementProps, BaseElementWithRef, BaseElementWithRefProps, ElementDisplayName, ElementRefType, ReactElementProps, ReactElementType } from './types';
2
2
  /**
3
3
  * @internal @unstable
4
4
  */
@@ -28,4 +28,21 @@ export interface DefineBaseElementInput<T> {
28
28
  * @param {DefineBaseElementInput} input `BaseElement` parameters
29
29
  * @returns {BaseElement} `ElementsContext` aware UI component
30
30
  */
31
- export default function defineBaseElement<T extends ReactElementType, K extends keyof U = never, V = string, U extends ReactElementProps<T> = ReactElementProps<T>, P extends BaseElementProps<K, V, U> = BaseElementProps<K, V, U>>(input: DefineBaseElementInput<T>): BaseElement<P, ElementRefType<P>>;
31
+ export declare function defineBaseElement<T extends ReactElementType, K extends keyof U = never, V = string, U extends ReactElementProps<T> = ReactElementProps<T>, P extends BaseElementProps<K, V, U> = BaseElementProps<K, V, U>>(input: DefineBaseElementInput<T>): BaseElement<P>;
32
+ /**
33
+ * @internal @unstable
34
+ *
35
+ * Defines a `ElementsContext` aware `BaseElement` UI component of the
36
+ * provided `type` with an assigned `displayName` and element `ref`.
37
+ *
38
+ * If `BaseElement` is used as a child of an `ElementsProvider`, returns the
39
+ * `BaseElement` value of the provided `displayName` of `ElementsContext`.
40
+ *
41
+ * When used outside of a parent `ElementsProvider` or no `BaseElement`
42
+ * of `displayName` is found in the `ElementsContext`, returns a stateless,
43
+ * unstyled HTML element of the provided `type`.
44
+ *
45
+ * @param {DefineBaseElementInput} input `BaseElement` parameters
46
+ * @returns {BaseElementWithRefProps} `ElementsContext` aware UI component
47
+ */
48
+ export declare function defineBaseElementWithRef<T extends ReactElementType, K extends keyof U = never, V = string, U extends ReactElementProps<T> = ReactElementProps<T>, P extends BaseElementWithRefProps<K, V, U> = BaseElementWithRefProps<K, V, U>>(input: DefineBaseElementInput<T>): BaseElementWithRef<P, ElementRefType<P>>;
@@ -1,3 +1,6 @@
1
- export { default as defineBaseElement } from './defineBaseElement';
1
+ export * from './ControlsContext';
2
+ export { defineBaseElement, defineBaseElementWithRef, } from './defineBaseElement';
2
3
  export { default as withBaseElementProps } from './withBaseElementProps';
3
4
  export { ElementsProvider } from './ElementsContext';
5
+ export { isComponent, isForwardRefExoticComponent } from './utils';
6
+ export * from './types';
@@ -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:
@@ -0,0 +1 @@
1
+ export declare function processDroppedItems(dataTransferItems: DataTransferItem[]): Promise<File[]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws-amplify/ui-react-core",
3
- "version": "3.0.29",
3
+ "version": "3.1.0",
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.5",
43
+ "@aws-amplify/ui": "6.7.0",
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';