Skip to content

Commit

Permalink
feat(label): add a label package
Browse files Browse the repository at this point in the history
  • Loading branch information
SiTaggart committed Oct 7, 2020
1 parent 2aea8f2 commit e20faad
Show file tree
Hide file tree
Showing 9 changed files with 317 additions and 0 deletions.
Empty file.
56 changes: 56 additions & 0 deletions packages/paste-core/components/label/__tests__/formlabel.test.tsx
@@ -0,0 +1,56 @@
import * as React from 'react';
import * as renderer from 'react-test-renderer';
import {shallow} from 'enzyme';
import {Theme} from '@twilio-paste/theme';
import {Label} from '../src';

describe('Label render', () => {
it('it should render', (): void => {
const tree = renderer
.create(
<Theme.Provider theme="console">
<Label htmlFor="input">child</Label>
</Theme.Provider>
)
.toJSON();
expect(tree).toMatchSnapshot();
});

it('it should render with required', (): void => {
const tree = renderer
.create(
<Theme.Provider theme="console">
<Label htmlFor="input" required>
child
</Label>
</Theme.Provider>
)
.toJSON();
expect(tree).toMatchSnapshot();
});
});

describe('Label for prop', () => {
const initialProps = {
htmlFor: 'input',
};

const container = shallow(<Label {...initialProps}>Label</Label>);

it('should have a for prop on label', () => {
expect(container.find('Box').prop('htmlFor')).toEqual('input');
});
});

describe('Label required prop', () => {
const initialProps = {
htmlFor: 'input',
required: true,
};

const container = shallow(<Label {...initialProps}>label</Label>);

it('should have a required indicator', () => {
expect(container.find('Styled(span)').length).toEqual(1);
});
});
56 changes: 56 additions & 0 deletions packages/paste-core/components/label/package.json
@@ -0,0 +1,56 @@
{
"name": "@twilio-paste/label",
"version": "1.0.0",
"category": "user input",
"status": "beta",
"description": "Label used to name Paste form fields",
"author": "Twilio Inc.",
"license": "MIT",
"main:dev": "src/index.tsx",
"main": "dist/index.js",
"module": "dist/index.es.js",
"types": "dist/index.d.ts",
"sideEffects": false,
"publishConfig": {
"access": "public"
},
"files": [
"dist"
],
"scripts": {
"build": "yarn clean && yarn compile",
"build:dev": "yarn clean && yarn compile:dev",
"build:props": "typedoc --tsconfig ./tsconfig.json --json ./dist/prop-types.json",
"clean": "rm -rf ./dist && rm -rf tsconfig.build.tsbuildinfo && rm -rf .rpt2_cache",
"compile": "rollup -c --environment NODE_ENV:production",
"compile:dev": "rollup -c --environment NODE_ENV:development",
"prepublishOnly": "yarn build",
"type-check": "tsc --noEmit"
},
"peerDependencies": {
"@twilio-paste/box": "^2.10.4",
"@twilio-paste/design-tokens": "^6.3.2",
"@twilio-paste/flex": "^0.3.57",
"@twilio-paste/screen-reader-only": "^1.1.12",
"@twilio-paste/style-props": "^1.6.4",
"@twilio-paste/styling-library": "^0.1.2",
"@twilio-paste/text": "^2.3.4",
"@twilio-paste/theme": "^3.2.21",
"@twilio-paste/types": "^3.0.24",
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-uid": "^2.2.0"
},
"devDependencies": {
"@twilio-paste/box": "^2.10.4",
"@twilio-paste/design-tokens": "^6.3.2",
"@twilio-paste/flex": "^0.3.57",
"@twilio-paste/screen-reader-only": "^1.1.12",
"@twilio-paste/style-props": "^1.6.4",
"@twilio-paste/styling-library": "^0.1.2",
"@twilio-paste/text": "^2.3.4",
"@twilio-paste/theme": "^3.2.21",
"@twilio-paste/types": "^3.0.24"
}
}
34 changes: 34 additions & 0 deletions packages/paste-core/components/label/rollup.config.js
@@ -0,0 +1,34 @@
import typescript from 'rollup-plugin-typescript2';
import babel from 'rollup-plugin-babel';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import {terser} from 'rollup-plugin-terser';
import pkg from './package.json';

export default {
input: pkg['main:dev'],
output: [
{
file: pkg.main,
format: 'cjs',
},
{
file: pkg.module,
format: 'esm',
},
],
external: [...Object.keys(pkg.peerDependencies || {})],
plugins: [
resolve(),
commonjs(),
typescript({
clean: true,
typescript: require('typescript'),
tsconfig: './tsconfig.build.json',
}),
babel({
exclude: 'node_modules/**',
}),
process.env.NODE_ENV === 'production' ? terser() : null,
],
};
94 changes: 94 additions & 0 deletions packages/paste-core/components/label/src/Label.tsx
@@ -0,0 +1,94 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import {styled, css} from '@twilio-paste/styling-library';
import {Box, safelySpreadBoxProps} from '@twilio-paste/box';
import {Flex} from '@twilio-paste/flex';
import {Text} from '@twilio-paste/text';
import {ScreenReaderOnly} from '@twilio-paste/screen-reader-only';
import {TextColor} from '@twilio-paste/style-props';

export interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {
as?: 'label' | 'legend';
children: NonNullable<React.ReactNode>;
disabled?: boolean;
htmlFor: string | undefined;
marginBottom?: 'space0';
required?: boolean;
variant?: 'default' | 'inverse';
}

// eslint-disable-next-line emotion/syntax-preference
const StyledRequiredDot = styled(Text)(
css({
backgroundColor: 'colorBackgroundRequired',
borderRadius: '50%',
cursor: 'pointer',
display: 'block',
height: '4px',
marginRight: 'space20',
width: '4px',
})
);

const Label: React.FC<LabelProps> = ({as, marginBottom, required, disabled, children, variant, ...props}) => {
let textColor = 'colorText' as TextColor;
if (disabled && variant === 'inverse') {
textColor = 'colorTextInverseWeak';
} else if (disabled) {
textColor = 'colorTextWeak';
} else if (variant === 'inverse') {
textColor = 'colorTextInverse';
}
return (
<Box
{...safelySpreadBoxProps(props)}
as={as}
// Setting a bottom border here to prevent Bootstrap's bottom border
// on legend in Console.
borderBottomWidth="borderWidth0"
display="block"
marginBottom={marginBottom || 'space20'}
paddingLeft="space0"
paddingRight="space0"
textTransform="none"
>
<Flex as="span" vAlignContent="center">
{required ? (
<StyledRequiredDot as="span" lineHeight="lineHeight30">
<ScreenReaderOnly>Required: </ScreenReaderOnly>
</StyledRequiredDot>
) : null}
<Text
as="span"
fontSize="fontSize30"
fontWeight="fontWeightSemibold"
lineHeight="lineHeight30"
color={textColor}
cursor={disabled ? 'not-allowed' : 'pointer'}
>
{children}
</Text>
</Flex>
</Box>
);
};

Label.displayName = 'Label';

Label.defaultProps = {
as: 'label',
};

if (process.env.NODE_ENV === 'development') {
Label.propTypes = {
as: PropTypes.oneOf(['label', 'legend']),
disabled: PropTypes.bool,
htmlFor: PropTypes.string,
marginBottom: PropTypes.oneOf(['space0']),
required: PropTypes.bool,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
variant: PropTypes.oneOf(['default', 'inverse']) as any,
};
}

export {Label};
1 change: 1 addition & 0 deletions packages/paste-core/components/label/src/index.tsx
@@ -0,0 +1 @@
export * from './Label';
30 changes: 30 additions & 0 deletions packages/paste-core/components/label/stories/label.stories.tsx
@@ -0,0 +1,30 @@
import * as React from 'react';
import {storiesOf} from '@storybook/react';
import {withKnobs} from '@storybook/addon-knobs';
import {Box} from '@twilio-paste/box';
import {Label} from '../src';

storiesOf('Components|Label', module)
.addDecorator(withKnobs)
.add('Default', () => {
return (
<>
<Label htmlFor="label">Label</Label>
<Label htmlFor="label" required>
Required Label
</Label>
</>
);
})
.add('Inverse', () => {
return (
<Box backgroundColor="colorBackgroundBodyInverse" padding="space60">
<Label htmlFor="label" variant="inverse">
Label
</Label>
<Label htmlFor="label" required variant="inverse">
Required Label
</Label>
</Box>
);
});
42 changes: 42 additions & 0 deletions packages/paste-core/components/label/tsconfig.build.json
@@ -0,0 +1,42 @@
{
"extends": "../../../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": [
"src/**/*"
],
"references": [
{
"path": "../../primitives/box"
},
{
"path": "../../../paste-design-tokens"
},
{
"path": "../../layout/flex"
},
{
"path": "../../../paste-icons"
},
{
"path": "../screen-reader-only"
},
{
"path": "../../../paste-style-props"
},
{
"path": "../../../paste-libraries/styling"
},
{
"path": "../../primitives/text"
},
{
"path": "../../../paste-theme"
},
{
"path": "../../../paste-types"
}
]
}
4 changes: 4 additions & 0 deletions packages/paste-core/components/label/tsconfig.json
@@ -0,0 +1,4 @@
{
"extends": "../../../../tsconfig.json",
"include": ["src/**/*"]
}

0 comments on commit e20faad

Please sign in to comment.