Add value, defaultValue, and checked props to appropriate elements. Add link to Feather Icons for the Icon component. The styling of TextInput docs has been fixed.tags/0.3.0
@@ -1 +0,0 @@ | |||
packages/react-common-docs/src/pages/index.md |
@@ -0,0 +1,94 @@ | |||
# Tesseract Design - React Common | |||
Common front-end components for Web using the [Tesseract design system](https://make.modal.sh/tesseract/design), written for [React](https://reactjs.org). | |||
Package: | |||
[![@tesseract-design/react-common](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=package&color=C78AB3&kind=name)](https://js.pack.modal.sh/-/web/detail/@tesseract-design/react-common) | |||
[![Version List](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=package&color=C78AB3&kind=version)](https://js.pack.modal.sh/-/web/detail/@tesseract-design/react-common#versions) | |||
Dependencies: | |||
[![React](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=react&kind=peerDependencies)](https://github.com/facebook/react) | |||
[![Styled Components](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=styled-components&kind=peerDependencies)](https://github.com/styled-components/styled-components) | |||
[![TypeScript](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=typescript&kind=devDependencies)](https://github.com/microsoft/typescript) | |||
[![Jest](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=jest&kind=devDependencies)](https://github.com/facebook/jest) | |||
[![Rollup](https://code.modal.sh/badge?repo=tesseract-design/react-common&type=dependency&dependency=rollup&kind=devDependencies)](https://github.com/rollup/rollup) | |||
Check the [documentation](https://make.modal.sh/tesseract/web/react/common) for more details. | |||
## Installation | |||
This package resides primarily in the [Modal.sh JavaScript Package Registry](https://js.pack.modal.sh/). You will need to | |||
adjust configuration in your chosen package manager. | |||
With [Yarn v.1.x](https://classic.arnpkg.com), add this to your `.yarnrc` file: | |||
```yarnrc | |||
"@tesseract-design:registry" "https://js.pack.modal.sh/" | |||
``` | |||
Then, install the package by running the following command: | |||
```shell script | |||
yarn add @tesseract-design/react-common | |||
``` | |||
## Usage | |||
The package includes components as named exports. Simply import the components you need individually or use a namespace | |||
import, like so: | |||
```jsx harmony | |||
import * as React from 'react' | |||
import ReactDOM from 'react-dom' | |||
import * as T from '@tesseract-design/react-common' | |||
const LoginForm = etcProps => ( | |||
<form | |||
{...etcProps} | |||
> | |||
<fieldset> | |||
<legend> | |||
Log In | |||
</legend> | |||
<div> | |||
<T.TextInput | |||
label="Username" | |||
/> | |||
</div> | |||
<div> | |||
<T.TextInput | |||
type="password" | |||
label="Password" | |||
/> | |||
</div> | |||
<div> | |||
<T.Button> | |||
Log In | |||
</T.Button> | |||
</div> | |||
</fieldset> | |||
</form> | |||
) | |||
const mountNode = window.document.createElement('div') | |||
ReactDOM.render( | |||
<LoginForm />, | |||
mountNode, | |||
) | |||
window.document.body.appendChild(mountNode) | |||
``` | |||
Detailed usage guides can be found in the documentation linked above. | |||
## TypeScript | |||
The package is written and tested using TypeScript. Thus, typings for consumption in TypeScript are bundled with the | |||
compiled source. | |||
## License | |||
MIT. See the LICENSE file on the package repository for the full text. |
@@ -2,7 +2,7 @@ | |||
"name": "@tesseract-design/react-common", | |||
"title": "React Common", | |||
"org": "Tesseract Design", | |||
"version": "0.2.4", | |||
"version": "0.2.5", | |||
"description": "Common front-end components for Web using the Tesseract design system, written in React.", | |||
"directories": { | |||
"lib": "dist" | |||
@@ -52,8 +52,7 @@ | |||
"prepublishOnly": "NODE_ENV=production rm -rf dist/ && rollup -c", | |||
"test": "jest", | |||
"build": "rm -rf dist/ && rollup -c", | |||
"generate": "plop", | |||
"docs": "docz" | |||
"generate": "plop" | |||
}, | |||
"peerDependencies": { | |||
"@reach/slider": "^0.10.5", | |||
@@ -19,7 +19,7 @@ const Title = styled('strong')({ | |||
const Org = styled('small')({ | |||
position: 'absolute', | |||
top: '-0.25em', | |||
top: '-0.375em', | |||
right: 0, | |||
fontWeight: 600, | |||
textTransform: 'lowercase', | |||
@@ -46,7 +46,7 @@ | |||
--font-family-base: 'Encode Sans', system-ui; | |||
--font-stretch-base: semi-expanded; | |||
--font-weight-base: 400; | |||
--line-height-base: 2; | |||
--line-height-base: 2em; | |||
--font-family-headings: 'Encode Sans', system-ui; | |||
--font-stretch-headings: condensed; | |||
--font-weight-headings: 100; | |||
@@ -228,6 +228,24 @@ | |||
"type": { | |||
"name": "(...args: any[]) => any" | |||
} | |||
}, | |||
"value": { | |||
"defaultValue": null, | |||
"description": "Value of the component.", | |||
"name": "value", | |||
"required": false, | |||
"type": { | |||
"name": "any" | |||
} | |||
}, | |||
"checked": { | |||
"defaultValue": null, | |||
"description": "Checked state of the component.", | |||
"name": "checked", | |||
"required": false, | |||
"type": { | |||
"name": "boolean" | |||
} | |||
} | |||
} | |||
}, | |||
@@ -331,6 +349,24 @@ | |||
"type": { | |||
"name": "(...args: any[]) => any" | |||
} | |||
}, | |||
"value": { | |||
"defaultValue": null, | |||
"description": "Value of the component.", | |||
"name": "value", | |||
"required": false, | |||
"type": { | |||
"name": "any" | |||
} | |||
}, | |||
"checked": { | |||
"defaultValue": null, | |||
"description": "Checked state of the component.", | |||
"name": "checked", | |||
"required": false, | |||
"type": { | |||
"name": "boolean" | |||
} | |||
} | |||
} | |||
}, | |||
@@ -431,6 +467,15 @@ | |||
"name": "(...args: any[]) => any" | |||
} | |||
}, | |||
"value": { | |||
"defaultValue": null, | |||
"description": "Value of the component.", | |||
"name": "value", | |||
"required": false, | |||
"type": { | |||
"name": "any" | |||
} | |||
}, | |||
"hint": { | |||
"defaultValue": { | |||
"value": "" | |||
@@ -452,6 +497,15 @@ | |||
"type": { | |||
"name": "boolean" | |||
} | |||
}, | |||
"defaultValue": { | |||
"defaultValue": null, | |||
"description": "Default value of the component.", | |||
"name": "defaultValue", | |||
"required": false, | |||
"type": { | |||
"name": "any" | |||
} | |||
} | |||
} | |||
}, | |||
@@ -491,6 +545,24 @@ | |||
"name": "(...args: any[]) => any" | |||
} | |||
}, | |||
"value": { | |||
"defaultValue": null, | |||
"description": "Value of the component.", | |||
"name": "value", | |||
"required": false, | |||
"type": { | |||
"name": "any" | |||
} | |||
}, | |||
"defaultValue": { | |||
"defaultValue": null, | |||
"description": "Default value of the component.", | |||
"name": "defaultValue", | |||
"required": false, | |||
"type": { | |||
"name": "any" | |||
} | |||
}, | |||
"orientation": { | |||
"defaultValue": { | |||
"value": "horizontal" | |||
@@ -521,6 +593,17 @@ | |||
"type": { | |||
"name": "ReactText" | |||
} | |||
}, | |||
"fallback": { | |||
"defaultValue": { | |||
"value": false | |||
}, | |||
"description": "Use the sSR-friendly rendering of the component.", | |||
"name": "fallback", | |||
"required": false, | |||
"type": { | |||
"name": "boolean" | |||
} | |||
} | |||
} | |||
}, | |||
@@ -612,6 +695,15 @@ | |||
"name": "(...args: any[]) => any" | |||
} | |||
}, | |||
"value": { | |||
"defaultValue": null, | |||
"description": "Value of the component.", | |||
"name": "value", | |||
"required": false, | |||
"type": { | |||
"name": "any" | |||
} | |||
}, | |||
"hint": { | |||
"defaultValue": { | |||
"value": "" | |||
@@ -623,6 +715,15 @@ | |||
"name": "any" | |||
} | |||
}, | |||
"defaultValue": { | |||
"defaultValue": null, | |||
"description": "Default value of the component.", | |||
"name": "defaultValue", | |||
"required": false, | |||
"type": { | |||
"name": "any" | |||
} | |||
}, | |||
"indicator": { | |||
"defaultValue": { | |||
"value": null | |||
@@ -19,3 +19,7 @@ import Header from '../../components/Header/Header' | |||
## Props | |||
<Props of="Icon" /> | |||
## See Also | |||
- [Feather Icons](https://feathericons.com) for a list of icon names. |
@@ -70,7 +70,13 @@ some content that is best displayed outside the component instead of putting in | |||
</div> | |||
<div> | |||
<TextInput alternate border size="large" label="Country" hint="abbreviations are accepted" /> | |||
<small> | |||
<small | |||
style={{ | |||
display: 'block', | |||
marginTop: '0.5em', | |||
lineHeight: '1.5em', | |||
}} | |||
> | |||
Consult the <a href="#">fees table</a> for shipping fee details. | |||
</small> | |||
</div> | |||
@@ -6,7 +6,7 @@ import * as Enzyme from 'enzyme' | |||
import * as Axe from 'jest-axe' | |||
import * as React from 'react' | |||
import Button, { Variant, ButtonElement } from './Button' | |||
import stringify from '../../services/stringify' | |||
import stringify from '../../utilities/stringify' | |||
const CUSTOM_VARIANTS: string[] = ['primary'] | |||
@@ -1,8 +1,8 @@ | |||
import * as React from 'react' | |||
import * as PropTypes from 'prop-types' | |||
import styled, { CSSObject } from 'styled-components' | |||
import { Size, SizeMap } from '../../services/utilities' | |||
import stringify from '../../services/stringify' | |||
import { Size, SizeMap } from '../../utilities/utilities' | |||
import stringify from '../../utilities/stringify' | |||
export type Variant = 'outline' | 'primary' | |||
@@ -6,7 +6,7 @@ import * as Enzyme from 'enzyme' | |||
import * as Axe from 'jest-axe' | |||
import * as React from 'react' | |||
import Checkbox from './Checkbox' | |||
import stringify from '../../services/stringify' | |||
import stringify from '../../utilities/stringify' | |||
it('should exist', () => { | |||
expect(Checkbox).toBeDefined() | |||
@@ -1,7 +1,7 @@ | |||
import * as React from 'react' | |||
import * as PropTypes from 'prop-types' | |||
import styled from 'styled-components' | |||
import stringify from '../../services/stringify' | |||
import stringify from '../../utilities/stringify' | |||
import Icon from '../Icon/Icon' | |||
const Base = styled('div')({ | |||
@@ -107,6 +107,7 @@ const Label = styled('span')({ | |||
width: 'calc(100% - 2.5rem)', | |||
fontFamily: 'var(--font-family-base, sans-serif)', | |||
pointerEvents: 'none', | |||
marginTop: '-0.25em', | |||
}) | |||
const LabelContent = styled('span')({ | |||
@@ -135,6 +136,14 @@ const propTypes = { | |||
* Event handler triggered when the component loses focus. | |||
*/ | |||
onBlur: PropTypes.func, | |||
/** | |||
* Value of the component. | |||
*/ | |||
value: PropTypes.any, | |||
/** | |||
* Checked state of the component. | |||
*/ | |||
checked: PropTypes.bool, | |||
} | |||
type Props = PropTypes.InferProps<typeof propTypes> | |||
@@ -143,9 +152,8 @@ type Props = PropTypes.InferProps<typeof propTypes> | |||
* Component for values that have an on/off state. | |||
* @see {@link Select} for a similar component suitable for selecting more values. | |||
* @see {@link RadioButton} for a similar component on selecting a single value among very few choices. | |||
* @type {React.ComponentType<{readonly label?: string} & React.ClassAttributes<unknown>>} | |||
*/ | |||
const Checkbox = React.forwardRef<HTMLInputElement, Props>(({ label = '', name, onChange, onFocus, onBlur }, ref) => ( | |||
const Checkbox = React.forwardRef<HTMLInputElement, Props>(({ label = '', name, onChange, onFocus, onBlur, value, checked, }, ref) => ( | |||
<Base> | |||
<CaptureArea> | |||
<Input | |||
@@ -155,6 +163,8 @@ const Checkbox = React.forwardRef<HTMLInputElement, Props>(({ label = '', name, | |||
onChange={onChange as React.ChangeEventHandler} | |||
onFocus={onFocus as React.FocusEventHandler} | |||
onBlur={onBlur as React.FocusEventHandler} | |||
value={value} | |||
checked={checked} | |||
/> | |||
<IndicatorWrapper> | |||
<Border /> | |||
@@ -3,7 +3,7 @@ import * as PropTypes from 'prop-types' | |||
import * as FeatherIcon from 'react-feather' | |||
import styled from 'styled-components' | |||
import { pascalCase, pascalCaseTransformMerge } from 'pascal-case' | |||
import splitValueAndUnit from '../../services/splitValueAndUnit' | |||
import splitValueAndUnit from '../../utilities/splitValueAndUnit' | |||
const Label = styled('span')({ | |||
position: 'absolute', | |||
@@ -45,11 +45,11 @@ type Props = PropTypes.InferProps<typeof propTypes> | |||
/** | |||
* Component for displaying graphics. | |||
* @param name | |||
* @param weight | |||
* @param size | |||
* @param label | |||
* @constructor | |||
* @param name - Name of the icon to display. | |||
* @param weight - Width of the icon's strokes. | |||
* @param size - Size of the icon. This controls both the width and the height. | |||
* @param label - Description of what the component represents. | |||
* @see {@link https://feathericons.com|Feather Icons} for a list of icon names. | |||
*/ | |||
const Icon: React.FC<Props> = ({ name, weight = '0.125rem', size = '1.5rem', label = name }) => { | |||
const iconName = pascalCase(name, { transform: pascalCaseTransformMerge }) | |||
@@ -6,7 +6,7 @@ import * as Enzyme from 'enzyme' | |||
import * as Axe from 'jest-axe' | |||
import * as React from 'react' | |||
import RadioButton from './RadioButton' | |||
import stringify from '../../services/stringify' | |||
import stringify from '../../utilities/stringify' | |||
it('should exist', () => { | |||
expect(RadioButton).toBeDefined() | |||
@@ -1,7 +1,7 @@ | |||
import * as React from 'react' | |||
import * as PropTypes from 'prop-types' | |||
import styled from 'styled-components' | |||
import stringify from '../../services/stringify' | |||
import stringify from '../../utilities/stringify' | |||
const Base = styled('div')({ | |||
display: 'block', | |||
@@ -105,6 +105,7 @@ const Label = styled('span')({ | |||
width: 'calc(100% - 2.5rem)', | |||
fontFamily: 'var(--font-family-base, sans-serif)', | |||
pointerEvents: 'none', | |||
marginTop: '-0.25em', | |||
}) | |||
const LabelContent = styled('span')({ | |||
@@ -133,6 +134,14 @@ const propTypes = { | |||
* Event handler triggered when the component loses focus. | |||
*/ | |||
onBlur: PropTypes.func, | |||
/** | |||
* Value of the component. | |||
*/ | |||
value: PropTypes.any, | |||
/** | |||
* Checked state of the component. | |||
*/ | |||
checked: PropTypes.bool, | |||
} | |||
type Props = PropTypes.InferProps<typeof propTypes> | |||
@@ -144,7 +153,7 @@ type Props = PropTypes.InferProps<typeof propTypes> | |||
* @type {React.ComponentType<{readonly label?: string, readonly name?: string} & React.ClassAttributes<unknown>>} | |||
*/ | |||
const RadioButton = React.forwardRef<HTMLInputElement, Props>( | |||
({ label = '', name, onChange, onFocus, onBlur }, ref) => ( | |||
({ label = '', name, onChange, onFocus, onBlur, value, checked, }, ref) => ( | |||
<Base> | |||
<CaptureArea> | |||
<Input | |||
@@ -154,6 +163,8 @@ const RadioButton = React.forwardRef<HTMLInputElement, Props>( | |||
onChange={onChange as React.ChangeEventHandler} | |||
onFocus={onFocus as React.FocusEventHandler} | |||
onBlur={onBlur as React.FocusEventHandler} | |||
value={value} | |||
checked={checked} | |||
/> | |||
<IndicatorWrapper> | |||
<Border /> | |||
@@ -6,7 +6,7 @@ import * as Enzyme from 'enzyme' | |||
import * as Axe from 'jest-axe' | |||
import * as React from 'react' | |||
import Select from './Select' | |||
import stringify from '../../services/stringify' | |||
import stringify from '../../utilities/stringify' | |||
it('should exist', () => { | |||
expect(Select).toBeDefined() | |||
@@ -1,8 +1,8 @@ | |||
import * as React from 'react' | |||
import * as PropTypes from 'prop-types' | |||
import styled from 'styled-components' | |||
import stringify from '../../services/stringify' | |||
import { Size, SizeMap } from '../../services/utilities' | |||
import stringify from '../../utilities/stringify' | |||
import { Size, SizeMap } from '../../utilities/utilities' | |||
import Icon from '../Icon/Icon' | |||
const MIN_HEIGHTS: SizeMap<string | number> = { | |||
@@ -216,6 +216,14 @@ const propTypes = { | |||
* Event handler triggered when the component loses focus. | |||
*/ | |||
onBlur: PropTypes.func, | |||
/** | |||
* Default value of the component. | |||
*/ | |||
defaultValue: PropTypes.any, | |||
/** | |||
* Value of the component. | |||
*/ | |||
value: PropTypes.any, | |||
} | |||
type Props = PropTypes.InferProps<typeof propTypes> | |||
@@ -237,7 +245,8 @@ const Select = React.forwardRef<HTMLSelectElement, Props>( | |||
onChange, | |||
onFocus, | |||
onBlur, | |||
...etcProps | |||
defaultValue, | |||
value, | |||
}, | |||
ref, | |||
) => { | |||
@@ -261,7 +270,8 @@ const Select = React.forwardRef<HTMLSelectElement, Props>( | |||
</LabelWrapper> | |||
{stringify(label).length > 0 && ' '} | |||
<Input | |||
{...etcProps} | |||
defaultValue={defaultValue} | |||
value={value} | |||
onChange={onChange as React.ChangeEventHandler} | |||
onFocus={onFocus as React.FocusEventHandler} | |||
onBlur={onBlur as React.FocusEventHandler} | |||
@@ -2,7 +2,8 @@ import * as React from 'react' | |||
import * as PropTypes from 'prop-types' | |||
import * as ReachSlider from '@reach/slider' | |||
import styled from 'styled-components' | |||
import stringify from '../../services/stringify' | |||
import stringify from '../../utilities/stringify' | |||
import useHydration from '../../utilities/hooks/useHydration' | |||
const Wrapper = styled('div')({ | |||
position: 'relative', | |||
@@ -208,6 +209,18 @@ const propTypes = { | |||
* Event handler triggered when the component changes value. | |||
*/ | |||
onChange: PropTypes.func, | |||
/** | |||
* Use the sSR-friendly rendering of the component. | |||
*/ | |||
fallback: PropTypes.bool, | |||
/** | |||
* Default value of the component. | |||
*/ | |||
defaultValue: PropTypes.any, | |||
/** | |||
* Value of the component. | |||
*/ | |||
value: PropTypes.any, | |||
} | |||
type Props = PropTypes.InferProps<typeof propTypes> | |||
@@ -223,20 +236,20 @@ type Props = PropTypes.InferProps<typeof propTypes> | |||
* @param {*} [label] - Short textual description indicating the nature of the component's value. | |||
* @param {string | number} [length] - CSS size for the component length. | |||
* @param {boolean} [disabled] - Is the component active? | |||
* @returns {React.ReactElement} The component elements. | |||
* @param [onChange] - Event handler triggered when the component changes value. | |||
*/ | |||
const Slider: React.FC<Props> = ({ | |||
const Slider = React.forwardRef<unknown, Props>(({ | |||
orientation = 'horizontal', | |||
label = '', | |||
length = '16rem', | |||
disabled = false, | |||
onChange, | |||
}) => { | |||
const [isClient, setIsClient] = React.useState(false) | |||
fallback = false, | |||
}, ref) => { | |||
const isClient = useHydration() | |||
React.useEffect(() => { | |||
window.document.body.style.setProperty('--reach-slider', '1') | |||
setIsClient(true) | |||
}, []) | |||
const parallelDimension: Dimension = orientation === 'horizontal' ? 'width' : 'height' | |||
@@ -255,7 +268,7 @@ const Slider: React.FC<Props> = ({ | |||
orient: orientation, | |||
} | |||
if (isClient) { | |||
if (!fallback && isClient) { | |||
return ( | |||
<Wrapper | |||
style={{ | |||
@@ -301,6 +314,7 @@ const Slider: React.FC<Props> = ({ | |||
cursor: disabled ? 'not-allowed' : undefined, | |||
}} | |||
onChange={onChange!} | |||
ref={ref} | |||
> | |||
<Track> | |||
<Highlight | |||
@@ -369,13 +383,14 @@ const Slider: React.FC<Props> = ({ | |||
disabled={disabled!} | |||
onChange={onChange!} | |||
type="range" | |||
ref={ref} | |||
/> | |||
</ClickArea> | |||
</TransformWrapper> | |||
</SizingWrapper> | |||
</Wrapper> | |||
) | |||
} | |||
}) | |||
Slider.propTypes = propTypes | |||
@@ -6,7 +6,7 @@ import * as Enzyme from 'enzyme' | |||
import * as Axe from 'jest-axe' | |||
import * as React from 'react' | |||
import TextInput from './TextInput' | |||
import stringify from '../../services/stringify' | |||
import stringify from '../../utilities/stringify' | |||
it('should exist', () => { | |||
expect(TextInput).toBeDefined() | |||
@@ -1,8 +1,8 @@ | |||
import * as React from 'react' | |||
import * as PropTypes from 'prop-types' | |||
import styled from 'styled-components' | |||
import stringify from '../../services/stringify' | |||
import { Size, SizeMap } from '../../services/utilities' | |||
import stringify from '../../utilities/stringify' | |||
import { Size, SizeMap } from '../../utilities/utilities' | |||
// TODO implement web-client text inputs! | |||
@@ -255,6 +255,14 @@ const propTypes = { | |||
* Should the component be displayed with an alternate appearance? | |||
*/ | |||
alternate: PropTypes.bool, | |||
/** | |||
* Default value of the component. | |||
*/ | |||
defaultValue: PropTypes.any, | |||
/** | |||
* Value of the component. | |||
*/ | |||
value: PropTypes.any, | |||
} | |||
type Props = PropTypes.InferProps<typeof propTypes> | |||
@@ -281,7 +289,8 @@ const TextInput = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, Props | |||
onFocus, | |||
onBlur, | |||
alternate = false, | |||
...etcProps | |||
defaultValue, | |||
value, | |||
}, | |||
ref, | |||
) => ( | |||
@@ -306,7 +315,6 @@ const TextInput = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, Props | |||
{stringify(label).length > 0 && ' '} | |||
{multiline && ( | |||
<TextArea | |||
{...etcProps} | |||
onChange={onChange as React.ChangeEventHandler} | |||
onFocus={onFocus as React.FocusEventHandler} | |||
onBlur={onBlur as React.FocusEventHandler} | |||
@@ -323,11 +331,12 @@ const TextInput = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, Props | |||
paddingRight: indicator ? MIN_HEIGHTS[size!] : (alternate ? '1rem' : undefined), | |||
paddingLeft: alternate ? '1rem' : undefined, | |||
}} | |||
defaultValue={defaultValue} | |||
value={value} | |||
/> | |||
)} | |||
{!multiline && ( | |||
<Input | |||
{...etcProps} | |||
onChange={onChange as React.ChangeEventHandler} | |||
onFocus={onFocus as React.FocusEventHandler} | |||
onBlur={onBlur as React.FocusEventHandler} | |||
@@ -341,6 +350,8 @@ const TextInput = React.forwardRef<HTMLInputElement | HTMLTextAreaElement, Props | |||
paddingTop: alternate ? undefined : `calc(${SECONDARY_TEXT_SIZES[size!]} * 2)`, | |||
paddingRight: indicator ? MIN_HEIGHTS[size!] : (alternate ? '1rem' : undefined), | |||
}} | |||
defaultValue={defaultValue} | |||
value={value} | |||
/> | |||
)} | |||
</CaptureArea> | |||
@@ -0,0 +1,13 @@ | |||
import { useEffect, useState } from 'react' | |||
const useHydration = () => { | |||
const [hydrated, setHydrated] = useState(false) | |||
useEffect(() => { | |||
setHydrated(true) | |||
}, []) | |||
return hydrated | |||
} | |||
export default useHydration |