@aws-amplify/ui-react-core 3.0.17 → 3.0.19

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.
package/README.md CHANGED
@@ -1,3 +1,3 @@
1
1
  # Amplify UI React Core
2
2
 
3
- `@aws-amplify/ui-react-core` is a React platform agnostic utility library for Amplify UI internal usage in the `@aws-amplify/ui-react` and `@aws-amplify/ui-react-native` packages.
3
+ `@aws-amplify/ui-react-core` is a React platform agnostic utility library for Amplify UI internal usage in `@aws-amplify/ui-react*` and `@aws-amplify/ui-react-native*` namespaced packages.
@@ -0,0 +1,135 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var React = require('react');
6
+
7
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
+
9
+ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
10
+
11
+ const ElementsContext = React__default["default"].createContext(undefined);
12
+ /**
13
+ * @internal @unstable
14
+ *
15
+ * `ElementsProvider` provides the values contained in `ElementsContext`
16
+ * to its `children`. `ElementsContext` lookup is handled directly
17
+ * by `BaseElement`components returned by `defineBaseElement`.
18
+ *
19
+ * @example
20
+ *
21
+ * Add `ElementsContext` aware `BaseElement` components to a Connected
22
+ * Component
23
+ *
24
+ * ```tsx
25
+ * // `BaseElement`, renders custom or default element defintion
26
+ * const ViewElement = defineBaseElement({
27
+ * displayName: "View",
28
+ * type: "div",
29
+ * });
30
+ *
31
+ * // `BaseElement` components to be provided through `ElementsContext`
32
+ * interface ConnectedComponentElements {
33
+ * View: typeof ViewElement;
34
+ * }
35
+ *
36
+ * function createConnectedComponent<T extends ConnectedComponentElements>(
37
+ * elements?: T
38
+ * ) {
39
+ * const Provider = ({ children }: { children?: React.ReactNode }) => (
40
+ * <ElementsProvider elements={elements}>
41
+ * <Children />
42
+ * </ElementsProvider>
43
+ * );
44
+ *
45
+ * function ConnectedComponent() {
46
+ * return (
47
+ * <Provider>
48
+ * <ConnectedComponentContent />
49
+ * </Provider>
50
+ * );
51
+ * }
52
+ *
53
+ * ConnectedComponent.Provider = Provider;
54
+ *
55
+ * return ConnectedComponent;
56
+ * }
57
+ * ```
58
+ */
59
+ function ElementsProvider({ elements, ...props }) {
60
+ return React__default["default"].createElement(ElementsContext.Provider, { ...props, value: elements });
61
+ }
62
+
63
+ /**
64
+ * @internal @unstable
65
+ *
66
+ * Defines a `ElementsContext` aware `BaseElement` UI component of the
67
+ * provided `type` with an assigned `displayName`.
68
+ *
69
+ * If `BaseElement` is used as a child of an `ElementsProvider`, returns the
70
+ * `BaseElement` value of the provided `displayName` of `ElementsContext`.
71
+ *
72
+ * When used outside of a parent `ElementsProvider` or no `BaseElement`
73
+ * of `displayName` is found in the `ElementsContext`, returns a stateless,
74
+ * unstyled HTML element of the provided `type`.
75
+ *
76
+ * @param {DefineBaseElementInput} input `BaseElement` parameters
77
+ * @returns {BaseElement} `ElementsContext` aware UI component
78
+ */
79
+ function defineBaseElement(input) {
80
+ const { displayName, type } = input;
81
+ const Element = React__default["default"].forwardRef(({ variant, ...props }, ref) => {
82
+ const Element = React__default["default"].useContext(ElementsContext)?.[displayName];
83
+ if (Element) {
84
+ // only pass `variant` to provided `Element` values
85
+ return React__default["default"].createElement(Element, { ...props, ref, variant });
86
+ }
87
+ return React__default["default"].createElement(type, { ...props, ref });
88
+ });
89
+ Element.displayName = displayName;
90
+ return Element;
91
+ }
92
+
93
+ /**
94
+ * @internal @unstable
95
+ *
96
+ * Extend target `BaseElement` with `defaultProps`. `defaultProps`
97
+ * are overidden by `props` provided to returned `BaseElement`.
98
+ *
99
+ * @example
100
+ *
101
+ * Extend `InputElement` with default `className` and `type`
102
+ * ```tsx
103
+ *
104
+ * // define extended `props` on `BaseElement` interface
105
+ * type InputElementPropKey = 'onChange' | 'type';
106
+ *
107
+ * // create `InputElement` base with `type` generic and extended `props` key
108
+ * export const InputElement = defineBaseElement<"input", InputElementPropKey>({
109
+ * type: "input",
110
+ * displayName: "Input",
111
+ * });
112
+ *
113
+ * // extend base `InputElement` with default input `type` of `checkbox`
114
+ * const CheckboxElement = withBaseElementProps(Input, {
115
+ * className: 'submit-toggle__checkbox',
116
+ * type: 'checkbox',
117
+ * });
118
+ * ```
119
+ *
120
+ * @param Target `BaseElement` to extend
121
+ * @param defaultProps `defaultProps` to apply to `Target`, accepts object or callback
122
+ * @returns extended `BaseElement` with `defaultProps`
123
+ */
124
+ function withBaseElementProps(Target, defaultProps) {
125
+ const Component = React__default["default"].forwardRef((props, ref) => (React__default["default"].createElement(Target, { ...(typeof defaultProps === 'function'
126
+ ? defaultProps(props)
127
+ : defaultProps),
128
+ ...props, ref: ref })));
129
+ Component.displayName = Target.displayName;
130
+ return Component;
131
+ }
132
+
133
+ exports.ElementsProvider = ElementsProvider;
134
+ exports.defineBaseElement = defineBaseElement;
135
+ exports.withBaseElementProps = withBaseElementProps;
@@ -0,0 +1,55 @@
1
+ import React__default from 'react';
2
+
3
+ const ElementsContext = React__default.createContext(undefined);
4
+ /**
5
+ * @internal @unstable
6
+ *
7
+ * `ElementsProvider` provides the values contained in `ElementsContext`
8
+ * to its `children`. `ElementsContext` lookup is handled directly
9
+ * by `BaseElement`components returned by `defineBaseElement`.
10
+ *
11
+ * @example
12
+ *
13
+ * Add `ElementsContext` aware `BaseElement` components to a Connected
14
+ * Component
15
+ *
16
+ * ```tsx
17
+ * // `BaseElement`, renders custom or default element defintion
18
+ * const ViewElement = defineBaseElement({
19
+ * displayName: "View",
20
+ * type: "div",
21
+ * });
22
+ *
23
+ * // `BaseElement` components to be provided through `ElementsContext`
24
+ * interface ConnectedComponentElements {
25
+ * View: typeof ViewElement;
26
+ * }
27
+ *
28
+ * function createConnectedComponent<T extends ConnectedComponentElements>(
29
+ * elements?: T
30
+ * ) {
31
+ * const Provider = ({ children }: { children?: React.ReactNode }) => (
32
+ * <ElementsProvider elements={elements}>
33
+ * <Children />
34
+ * </ElementsProvider>
35
+ * );
36
+ *
37
+ * function ConnectedComponent() {
38
+ * return (
39
+ * <Provider>
40
+ * <ConnectedComponentContent />
41
+ * </Provider>
42
+ * );
43
+ * }
44
+ *
45
+ * ConnectedComponent.Provider = Provider;
46
+ *
47
+ * return ConnectedComponent;
48
+ * }
49
+ * ```
50
+ */
51
+ function ElementsProvider({ elements, ...props }) {
52
+ return React__default.createElement(ElementsContext.Provider, { ...props, value: elements });
53
+ }
54
+
55
+ export { ElementsContext, ElementsProvider };
@@ -0,0 +1,34 @@
1
+ import React__default from 'react';
2
+ import { ElementsContext } from './ElementsContext.mjs';
3
+
4
+ /**
5
+ * @internal @unstable
6
+ *
7
+ * Defines a `ElementsContext` aware `BaseElement` UI component of the
8
+ * provided `type` with an assigned `displayName`.
9
+ *
10
+ * If `BaseElement` is used as a child of an `ElementsProvider`, returns the
11
+ * `BaseElement` value of the provided `displayName` of `ElementsContext`.
12
+ *
13
+ * When used outside of a parent `ElementsProvider` or no `BaseElement`
14
+ * of `displayName` is found in the `ElementsContext`, returns a stateless,
15
+ * unstyled HTML element of the provided `type`.
16
+ *
17
+ * @param {DefineBaseElementInput} input `BaseElement` parameters
18
+ * @returns {BaseElement} `ElementsContext` aware UI component
19
+ */
20
+ function defineBaseElement(input) {
21
+ const { displayName, type } = input;
22
+ const Element = React__default.forwardRef(({ variant, ...props }, ref) => {
23
+ const Element = React__default.useContext(ElementsContext)?.[displayName];
24
+ if (Element) {
25
+ // only pass `variant` to provided `Element` values
26
+ return React__default.createElement(Element, { ...props, ref, variant });
27
+ }
28
+ return React__default.createElement(type, { ...props, ref });
29
+ });
30
+ Element.displayName = displayName;
31
+ return Element;
32
+ }
33
+
34
+ export { defineBaseElement as default };
@@ -0,0 +1,3 @@
1
+ export { default as defineBaseElement } from './defineBaseElement.mjs';
2
+ export { default as withBaseElementProps } from './withBaseElementProps.mjs';
3
+ export { ElementsProvider } from './ElementsContext.mjs';
@@ -0,0 +1,43 @@
1
+ import React__default from 'react';
2
+
3
+ /**
4
+ * @internal @unstable
5
+ *
6
+ * Extend target `BaseElement` with `defaultProps`. `defaultProps`
7
+ * are overidden by `props` provided to returned `BaseElement`.
8
+ *
9
+ * @example
10
+ *
11
+ * Extend `InputElement` with default `className` and `type`
12
+ * ```tsx
13
+ *
14
+ * // define extended `props` on `BaseElement` interface
15
+ * type InputElementPropKey = 'onChange' | 'type';
16
+ *
17
+ * // create `InputElement` base with `type` generic and extended `props` key
18
+ * export const InputElement = defineBaseElement<"input", InputElementPropKey>({
19
+ * type: "input",
20
+ * displayName: "Input",
21
+ * });
22
+ *
23
+ * // extend base `InputElement` with default input `type` of `checkbox`
24
+ * const CheckboxElement = withBaseElementProps(Input, {
25
+ * className: 'submit-toggle__checkbox',
26
+ * type: 'checkbox',
27
+ * });
28
+ * ```
29
+ *
30
+ * @param Target `BaseElement` to extend
31
+ * @param defaultProps `defaultProps` to apply to `Target`, accepts object or callback
32
+ * @returns extended `BaseElement` with `defaultProps`
33
+ */
34
+ function withBaseElementProps(Target, defaultProps) {
35
+ const Component = React__default.forwardRef((props, ref) => (React__default.createElement(Target, { ...(typeof defaultProps === 'function'
36
+ ? defaultProps(props)
37
+ : defaultProps),
38
+ ...props, ref: ref })));
39
+ Component.displayName = Target.displayName;
40
+ return Component;
41
+ }
42
+
43
+ export { withBaseElementProps as default };
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+ import { ElementDisplayName } from './types';
3
+ /**
4
+ * @internal @unstable
5
+ */
6
+ export interface Elements extends Partial<Record<ElementDisplayName, React.ComponentType>> {
7
+ }
8
+ export declare const ElementsContext: React.Context<Elements | undefined>;
9
+ /**
10
+ * @internal @unstable
11
+ *
12
+ * `ElementsProvider` provides the values contained in `ElementsContext`
13
+ * to its `children`. `ElementsContext` lookup is handled directly
14
+ * by `BaseElement`components returned by `defineBaseElement`.
15
+ *
16
+ * @example
17
+ *
18
+ * Add `ElementsContext` aware `BaseElement` components to a Connected
19
+ * Component
20
+ *
21
+ * ```tsx
22
+ * // `BaseElement`, renders custom or default element defintion
23
+ * const ViewElement = defineBaseElement({
24
+ * displayName: "View",
25
+ * type: "div",
26
+ * });
27
+ *
28
+ * // `BaseElement` components to be provided through `ElementsContext`
29
+ * interface ConnectedComponentElements {
30
+ * View: typeof ViewElement;
31
+ * }
32
+ *
33
+ * function createConnectedComponent<T extends ConnectedComponentElements>(
34
+ * elements?: T
35
+ * ) {
36
+ * const Provider = ({ children }: { children?: React.ReactNode }) => (
37
+ * <ElementsProvider elements={elements}>
38
+ * <Children />
39
+ * </ElementsProvider>
40
+ * );
41
+ *
42
+ * function ConnectedComponent() {
43
+ * return (
44
+ * <Provider>
45
+ * <ConnectedComponentContent />
46
+ * </Provider>
47
+ * );
48
+ * }
49
+ *
50
+ * ConnectedComponent.Provider = Provider;
51
+ *
52
+ * return ConnectedComponent;
53
+ * }
54
+ * ```
55
+ */
56
+ export declare function ElementsProvider<T extends Elements>({ elements, ...props }: {
57
+ children?: React.ReactNode;
58
+ elements?: T;
59
+ }): React.JSX.Element;
@@ -0,0 +1,31 @@
1
+ import { BaseElement, BaseElementProps, ElementDisplayName, ElementRefType, ReactElementProps, ReactElementType } from './types';
2
+ /**
3
+ * @internal @unstable
4
+ */
5
+ export interface DefineBaseElementInput<T> {
6
+ /**
7
+ * `BaseElement` display name in React dev tools and stack traces
8
+ */
9
+ displayName: ElementDisplayName;
10
+ /**
11
+ * base HTML `element` type
12
+ */
13
+ type: T;
14
+ }
15
+ /**
16
+ * @internal @unstable
17
+ *
18
+ * Defines a `ElementsContext` aware `BaseElement` UI component of the
19
+ * provided `type` with an assigned `displayName`.
20
+ *
21
+ * If `BaseElement` is used as a child of an `ElementsProvider`, returns the
22
+ * `BaseElement` value of the provided `displayName` of `ElementsContext`.
23
+ *
24
+ * When used outside of a parent `ElementsProvider` or no `BaseElement`
25
+ * of `displayName` is found in the `ElementsContext`, returns a stateless,
26
+ * unstyled HTML element of the provided `type`.
27
+ *
28
+ * @param {DefineBaseElementInput} input `BaseElement` parameters
29
+ * @returns {BaseElement} `ElementsContext` aware UI component
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>>;
@@ -0,0 +1,3 @@
1
+ export { default as defineBaseElement } from './defineBaseElement';
2
+ export { default as withBaseElementProps } from './withBaseElementProps';
3
+ export { ElementsProvider } from './ElementsContext';
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ /**
3
+ * @internal @unstable
4
+ *
5
+ * Base type definition of `BaseElement` components available through
6
+ * `ElementsContext`. The definitions define a contract between a
7
+ * Connected Component and the `elements` that can be provided as
8
+ * overrides.
9
+ *
10
+ * `BaseElement` interfaces surface a minimal set of HTML semantic `props`
11
+ * required to achieve the base functionality of consumers. `props`
12
+ * are always optional at the interface level, allowing for additional `props`
13
+ * to be added to existing `BaseElement` interfaces as needed.
14
+ */
15
+ export type BaseElement<T = {}, K = {}> = React.ForwardRefExoticComponent<React.PropsWithoutRef<T> & React.RefAttributes<K>>;
16
+ type ListElementSubType = 'Ordered' | 'Unordered';
17
+ type ListElementDisplayName = 'List' | `${ListElementSubType}List`;
18
+ type TableElementSubType = 'Body' | 'Data' | 'Row' | 'Head' | 'Header';
19
+ type TableElementDisplayName = 'Table' | `Table${TableElementSubType}`;
20
+ /**
21
+ * @internal @unstable
22
+ *
23
+ * allowed values of `displayName` of `BaseElement` and `ElemebtsContext` keys
24
+ */
25
+ export type ElementDisplayName = 'Button' | 'Divider' | 'Heading' | 'Icon' | 'Input' | 'Label' | 'ListItem' | 'Nav' | 'ProgressBar' | 'Span' | 'Text' | 'Title' | 'View' | ListElementDisplayName | TableElementDisplayName;
26
+ /**
27
+ * @internal @unstable
28
+ */
29
+ export type ElementRefType<T> = T extends {
30
+ ref?: React.LegacyRef<infer K> | React.Ref<infer K> | React.ForwardedRef<infer K>;
31
+ } ? K : never;
32
+ /**
33
+ * @internal @unstable
34
+ */
35
+ export type ReactElementType = keyof React.JSX.IntrinsicElements;
36
+ /**
37
+ * @internal @unstable
38
+ */
39
+ export type ReactElementProps<T extends ReactElementType> = React.JSX.IntrinsicElements[T];
40
+ /**
41
+ * @internal @unstable
42
+ *
43
+ * key of `props` always available on `BaseElement` definitions
44
+ */
45
+ type ElementPropKey<T> = T | 'children' | 'className' | 'style';
46
+ /**
47
+ * @internal @unstable
48
+ */
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>> & {
50
+ testId?: string;
51
+ variant?: V;
52
+ };
53
+ export {};
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import { BaseElement, ElementRefType } from './types';
3
+ /**
4
+ * @internal @unstable
5
+ *
6
+ * Extend target `BaseElement` with `defaultProps`. `defaultProps`
7
+ * are overidden by `props` provided to returned `BaseElement`.
8
+ *
9
+ * @example
10
+ *
11
+ * Extend `InputElement` with default `className` and `type`
12
+ * ```tsx
13
+ *
14
+ * // define extended `props` on `BaseElement` interface
15
+ * type InputElementPropKey = 'onChange' | 'type';
16
+ *
17
+ * // create `InputElement` base with `type` generic and extended `props` key
18
+ * export const InputElement = defineBaseElement<"input", InputElementPropKey>({
19
+ * type: "input",
20
+ * displayName: "Input",
21
+ * });
22
+ *
23
+ * // extend base `InputElement` with default input `type` of `checkbox`
24
+ * const CheckboxElement = withBaseElementProps(Input, {
25
+ * className: 'submit-toggle__checkbox',
26
+ * type: 'checkbox',
27
+ * });
28
+ * ```
29
+ *
30
+ * @param Target `BaseElement` to extend
31
+ * @param defaultProps `defaultProps` to apply to `Target`, accepts object or callback
32
+ * @returns extended `BaseElement` with `defaultProps`
33
+ */
34
+ export default function withBaseElementProps<T, K extends T | ((input: T) => T)>(Target: React.ForwardRefExoticComponent<T>, defaultProps: K): BaseElement<T, ElementRefType<T>>;
@@ -1,4 +1,4 @@
1
- export { default as useDataState } from './useDataState';
1
+ export { default as useDataState, 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';
@@ -1,7 +1,7 @@
1
- interface ActionState<T> {
1
+ export interface DataState<T> {
2
2
  data: T;
3
+ hasError: boolean;
3
4
  isLoading: boolean;
4
5
  message: string | undefined;
5
6
  }
6
- export default function useDataState<T, K>(action: (prevData: Awaited<T>, ...input: K[]) => T | Promise<T>, initialData: Awaited<T>): [state: ActionState<Awaited<T>>, handleAction: (...input: K[]) => void];
7
- export {};
7
+ export default function useDataState<T, K>(action: (prevData: T, ...input: K[]) => T | Promise<T>, initialData: T): [state: DataState<T>, handleAction: (...input: K[]) => void];
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "@aws-amplify/ui-react-core/elements",
3
+ "main": "../dist/elements.js",
4
+ "module": "../dist/esm/elements/elements.mjs",
5
+ "types": "../dist/types/elements/index.d.ts"
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws-amplify/ui-react-core",
3
- "version": "3.0.17",
3
+ "version": "3.0.19",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/esm/index.mjs",
6
6
  "react-native": "src/index.ts",
@@ -10,12 +10,19 @@
10
10
  "require": "./dist/index.js",
11
11
  "types": "./dist/types/index.d.ts"
12
12
  },
13
+ "./elements": {
14
+ "import": "./dist/esm/elements/elements.mjs",
15
+ "require": "./dist/elements.js",
16
+ "react-native": "./src/elements/index.ts",
17
+ "types": "./dist/types/elements/index.d.ts"
18
+ },
13
19
  "./package.json": "./package.json"
14
20
  },
15
21
  "types": "dist/types/index.d.ts",
16
22
  "license": "Apache-2.0",
17
23
  "files": [
18
24
  "dist",
25
+ "elements",
19
26
  "LICENSE",
20
27
  "src",
21
28
  "!**/__mocks__",
@@ -33,7 +40,7 @@
33
40
  "typecheck": "tsc --noEmit"
34
41
  },
35
42
  "dependencies": {
36
- "@aws-amplify/ui": "6.0.17",
43
+ "@aws-amplify/ui": "6.2.0",
37
44
  "@xstate/react": "^3.2.2",
38
45
  "lodash": "4.17.21",
39
46
  "react-hook-form": "^7.43.5",
@@ -0,0 +1,69 @@
1
+ import React from 'react';
2
+ import { ElementDisplayName } from './types';
3
+
4
+ /**
5
+ * @internal @unstable
6
+ */
7
+ export interface Elements
8
+ extends Partial<Record<ElementDisplayName, React.ComponentType>> {}
9
+
10
+ export const ElementsContext = React.createContext<Elements | undefined>(
11
+ undefined
12
+ );
13
+
14
+ /**
15
+ * @internal @unstable
16
+ *
17
+ * `ElementsProvider` provides the values contained in `ElementsContext`
18
+ * to its `children`. `ElementsContext` lookup is handled directly
19
+ * by `BaseElement`components returned by `defineBaseElement`.
20
+ *
21
+ * @example
22
+ *
23
+ * Add `ElementsContext` aware `BaseElement` components to a Connected
24
+ * Component
25
+ *
26
+ * ```tsx
27
+ * // `BaseElement`, renders custom or default element defintion
28
+ * const ViewElement = defineBaseElement({
29
+ * displayName: "View",
30
+ * type: "div",
31
+ * });
32
+ *
33
+ * // `BaseElement` components to be provided through `ElementsContext`
34
+ * interface ConnectedComponentElements {
35
+ * View: typeof ViewElement;
36
+ * }
37
+ *
38
+ * function createConnectedComponent<T extends ConnectedComponentElements>(
39
+ * elements?: T
40
+ * ) {
41
+ * const Provider = ({ children }: { children?: React.ReactNode }) => (
42
+ * <ElementsProvider elements={elements}>
43
+ * <Children />
44
+ * </ElementsProvider>
45
+ * );
46
+ *
47
+ * function ConnectedComponent() {
48
+ * return (
49
+ * <Provider>
50
+ * <ConnectedComponentContent />
51
+ * </Provider>
52
+ * );
53
+ * }
54
+ *
55
+ * ConnectedComponent.Provider = Provider;
56
+ *
57
+ * return ConnectedComponent;
58
+ * }
59
+ * ```
60
+ */
61
+ export function ElementsProvider<T extends Elements>({
62
+ elements,
63
+ ...props
64
+ }: {
65
+ children?: React.ReactNode;
66
+ elements?: T;
67
+ }): React.JSX.Element {
68
+ return <ElementsContext.Provider {...props} value={elements} />;
69
+ }
@@ -0,0 +1,73 @@
1
+ import React from 'react';
2
+ import { ElementsContext } from './ElementsContext';
3
+ import {
4
+ BaseElement,
5
+ BaseElementProps,
6
+ ElementDisplayName,
7
+ ElementRefType,
8
+ ReactElementProps,
9
+ ReactElementType,
10
+ } from './types';
11
+
12
+ /**
13
+ * @internal @unstable
14
+ */
15
+ export interface DefineBaseElementInput<T> {
16
+ /**
17
+ * `BaseElement` display name in React dev tools and stack traces
18
+ */
19
+ displayName: ElementDisplayName;
20
+
21
+ /**
22
+ * base HTML `element` type
23
+ */
24
+ type: T;
25
+ }
26
+
27
+ /**
28
+ * @internal @unstable
29
+ *
30
+ * Defines a `ElementsContext` aware `BaseElement` UI component of the
31
+ * provided `type` with an assigned `displayName`.
32
+ *
33
+ * If `BaseElement` is used as a child of an `ElementsProvider`, returns the
34
+ * `BaseElement` value of the provided `displayName` of `ElementsContext`.
35
+ *
36
+ * When used outside of a parent `ElementsProvider` or no `BaseElement`
37
+ * of `displayName` is found in the `ElementsContext`, returns a stateless,
38
+ * unstyled HTML element of the provided `type`.
39
+ *
40
+ * @param {DefineBaseElementInput} input `BaseElement` parameters
41
+ * @returns {BaseElement} `ElementsContext` aware UI component
42
+ */
43
+ export default function defineBaseElement<
44
+ // element type
45
+ T extends ReactElementType,
46
+ // string union of base element props to include
47
+ K extends keyof U = never,
48
+ // variant string union
49
+ V = string,
50
+ // available props of base element type
51
+ U extends ReactElementProps<T> = ReactElementProps<T>,
52
+ // control element props
53
+ P extends BaseElementProps<K, V, U> = BaseElementProps<K, V, U>,
54
+ >(input: DefineBaseElementInput<T>): BaseElement<P, ElementRefType<P>> {
55
+ const { displayName, type } = input;
56
+
57
+ const Element = React.forwardRef<ElementRefType<P>, P>(
58
+ ({ variant, ...props }, ref) => {
59
+ const Element = React.useContext(ElementsContext)?.[displayName];
60
+
61
+ if (Element) {
62
+ // only pass `variant` to provided `Element` values
63
+ return <Element {...{ ...props, ref, variant }} />;
64
+ }
65
+
66
+ return React.createElement(type, { ...props, ref });
67
+ }
68
+ );
69
+
70
+ Element.displayName = displayName;
71
+
72
+ return Element;
73
+ }
@@ -0,0 +1,3 @@
1
+ export { default as defineBaseElement } from './defineBaseElement';
2
+ export { default as withBaseElementProps } from './withBaseElementProps';
3
+ export { ElementsProvider } from './ElementsContext';
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+
3
+ /**
4
+ * @internal @unstable
5
+ *
6
+ * Base type definition of `BaseElement` components available through
7
+ * `ElementsContext`. The definitions define a contract between a
8
+ * Connected Component and the `elements` that can be provided as
9
+ * overrides.
10
+ *
11
+ * `BaseElement` interfaces surface a minimal set of HTML semantic `props`
12
+ * required to achieve the base functionality of consumers. `props`
13
+ * are always optional at the interface level, allowing for additional `props`
14
+ * to be added to existing `BaseElement` interfaces as needed.
15
+ */
16
+ export type BaseElement<T = {}, K = {}> = React.ForwardRefExoticComponent<
17
+ React.PropsWithoutRef<T> & React.RefAttributes<K>
18
+ >;
19
+
20
+ type ListElementSubType = 'Ordered' | 'Unordered';
21
+ type ListElementDisplayName = 'List' | `${ListElementSubType}List`;
22
+
23
+ type TableElementSubType = 'Body' | 'Data' | 'Row' | 'Head' | 'Header';
24
+ type TableElementDisplayName = 'Table' | `Table${TableElementSubType}`;
25
+
26
+ /**
27
+ * @internal @unstable
28
+ *
29
+ * allowed values of `displayName` of `BaseElement` and `ElemebtsContext` keys
30
+ */
31
+ export type ElementDisplayName =
32
+ | 'Button'
33
+ | 'Divider'
34
+ | 'Heading' // h1, h2, etc
35
+ | 'Icon'
36
+ | 'Input'
37
+ | 'Label'
38
+ | 'ListItem'
39
+ | 'Nav'
40
+ | 'ProgressBar'
41
+ | 'Span'
42
+ | 'Text'
43
+ | 'Title'
44
+ | 'View'
45
+ | ListElementDisplayName
46
+ | TableElementDisplayName;
47
+
48
+ /**
49
+ * @internal @unstable
50
+ */
51
+ export type ElementRefType<T> = T extends {
52
+ ref?:
53
+ | React.LegacyRef<infer K>
54
+ | React.Ref<infer K>
55
+ | React.ForwardedRef<infer K>;
56
+ }
57
+ ? K
58
+ : never;
59
+
60
+ /**
61
+ * @internal @unstable
62
+ */
63
+ export type ReactElementType = keyof React.JSX.IntrinsicElements;
64
+
65
+ /**
66
+ * @internal @unstable
67
+ */
68
+ export type ReactElementProps<T extends ReactElementType> =
69
+ React.JSX.IntrinsicElements[T];
70
+
71
+ /**
72
+ * @internal @unstable
73
+ *
74
+ * key of `props` always available on `BaseElement` definitions
75
+ */
76
+ type ElementPropKey<T> = T | 'children' | 'className' | 'style';
77
+
78
+ /**
79
+ * @internal @unstable
80
+ */
81
+ export type BaseElementProps<
82
+ T extends keyof K,
83
+ V = string,
84
+ K extends Record<ElementPropKey<keyof K>, any> = Record<string, any>,
85
+ > = React.AriaAttributes &
86
+ React.RefAttributes<ElementRefType<K>> &
87
+ Pick<K, ElementPropKey<T>> & { testId?: string; variant?: V };
@@ -0,0 +1,55 @@
1
+ import React from 'react';
2
+ import { BaseElement, ElementRefType } from './types';
3
+
4
+ /**
5
+ * @internal @unstable
6
+ *
7
+ * Extend target `BaseElement` with `defaultProps`. `defaultProps`
8
+ * are overidden by `props` provided to returned `BaseElement`.
9
+ *
10
+ * @example
11
+ *
12
+ * Extend `InputElement` with default `className` and `type`
13
+ * ```tsx
14
+ *
15
+ * // define extended `props` on `BaseElement` interface
16
+ * type InputElementPropKey = 'onChange' | 'type';
17
+ *
18
+ * // create `InputElement` base with `type` generic and extended `props` key
19
+ * export const InputElement = defineBaseElement<"input", InputElementPropKey>({
20
+ * type: "input",
21
+ * displayName: "Input",
22
+ * });
23
+ *
24
+ * // extend base `InputElement` with default input `type` of `checkbox`
25
+ * const CheckboxElement = withBaseElementProps(Input, {
26
+ * className: 'submit-toggle__checkbox',
27
+ * type: 'checkbox',
28
+ * });
29
+ * ```
30
+ *
31
+ * @param Target `BaseElement` to extend
32
+ * @param defaultProps `defaultProps` to apply to `Target`, accepts object or callback
33
+ * @returns extended `BaseElement` with `defaultProps`
34
+ */
35
+ export default function withBaseElementProps<
36
+ T,
37
+ K extends T | ((input: T) => T),
38
+ >(
39
+ Target: React.ForwardRefExoticComponent<T>,
40
+ defaultProps: K
41
+ ): BaseElement<T, ElementRefType<T>> {
42
+ const Component = React.forwardRef<ElementRefType<T>, T>((props, ref) => (
43
+ <Target
44
+ {...{
45
+ ...(typeof defaultProps === 'function'
46
+ ? defaultProps(props)
47
+ : defaultProps),
48
+ ...props,
49
+ }}
50
+ ref={ref}
51
+ />
52
+ ));
53
+ Component.displayName = Target.displayName;
54
+ return Component;
55
+ }
@@ -1,4 +1,5 @@
1
- export { default as useDataState } from './useDataState';
1
+ export { default as useDataState, DataState } from './useDataState';
2
+
2
3
  export {
3
4
  default as useDeprecationWarning,
4
5
  UseDeprecationWarning,
@@ -1,42 +1,50 @@
1
1
  import React from 'react';
2
2
 
3
- interface ActionState<T> {
3
+ export interface DataState<T> {
4
4
  data: T;
5
+ hasError: boolean;
5
6
  isLoading: boolean;
6
7
  message: string | undefined;
7
8
  }
8
9
 
9
- const getActionState = <T>(data: T): ActionState<T> => ({
10
- data,
11
- isLoading: false,
12
- message: undefined,
13
- });
10
+ // default state
11
+ const INITIAL_STATE = { hasError: false, isLoading: false, message: undefined };
12
+ const LOADING_STATE = { hasError: false, isLoading: true, message: undefined };
13
+ const ERROR_STATE = { hasError: true, isLoading: false };
14
+
15
+ const resolveMaybeAsync = async <T>(
16
+ value: T | Promise<T>
17
+ ): Promise<Awaited<T>> => {
18
+ const awaited = await value;
19
+ return awaited;
20
+ };
14
21
 
15
22
  export default function useDataState<T, K>(
16
- action: (prevData: Awaited<T>, ...input: K[]) => T | Promise<T>,
17
- initialData: Awaited<T>
18
- ): [state: ActionState<Awaited<T>>, handleAction: (...input: K[]) => void] {
19
- const [actionState, setActionState] = React.useState<ActionState<Awaited<T>>>(
20
- () => getActionState(initialData)
21
- );
23
+ action: (prevData: T, ...input: K[]) => T | Promise<T>,
24
+ initialData: T
25
+ ): [state: DataState<T>, handleAction: (...input: K[]) => void] {
26
+ const [dataState, setDataState] = React.useState<DataState<T>>(() => ({
27
+ ...INITIAL_STATE,
28
+ data: initialData,
29
+ }));
22
30
 
23
31
  const prevData = React.useRef(initialData);
24
32
 
25
33
  const handleAction: (...input: K[]) => void = React.useCallback(
26
34
  (...input) => {
27
- setActionState((prev) => ({ ...prev, isLoading: true }));
35
+ setDataState(({ data }) => ({ ...LOADING_STATE, data }));
28
36
 
29
- Promise.resolve(action(prevData.current, ...input))
30
- .then((data) => {
37
+ resolveMaybeAsync(action(prevData.current, ...input))
38
+ .then((data: T) => {
31
39
  prevData.current = data;
32
- setActionState(getActionState(data));
40
+ setDataState({ ...INITIAL_STATE, data });
33
41
  })
34
42
  .catch(({ message }: Error) => {
35
- setActionState((prev) => ({ ...prev, isLoading: false, message }));
43
+ setDataState(({ data }) => ({ ...ERROR_STATE, data, message }));
36
44
  });
37
45
  },
38
46
  [action]
39
47
  );
40
48
 
41
- return [actionState, handleAction];
49
+ return [dataState, handleAction];
42
50
  }