Skip to content

Commit

Permalink
feat(InputField)!: introduce 2.0 component
Browse files Browse the repository at this point in the history
- this updates the separate sub-components as well as ancillary
  components (FieldNote, Input)
- updates to variant types and mixins
- export updates and added stories
  • Loading branch information
booc0mtaco committed Mar 20, 2024
1 parent f3fc767 commit f223eb2
Show file tree
Hide file tree
Showing 16 changed files with 1,033 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/components/Button/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { Button as default } from './Button';
export type { ButtonProps } from './Button';
export { Button as ButtonV2 } from './Button-v2';
52 changes: 52 additions & 0 deletions src/components/FieldNote/FieldNote-v2.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
@import '../../design-tokens/mixins.css';

/*------------------------------------*\
# FIELD NOTE
\*------------------------------------*/

/**
* Fieldnote
*/
.field-note {
font: var(--eds-theme-typography-body-sm);

color: var(--eds-theme-color-text-utility-default-secondary);
}

/**
* Fieldnote icon
*/
.field-note__icon {
position: relative;
margin-right: 0.25rem;
}

/**
* Disabled variant
*/
.field-note--disabled {
/* TODO-AH: figure out field note treatment and tokens */
color: var(--eds-theme-color-text-utility-disabled-primary);
}

/**
* Error variant
*/
.field-note--error {
color: var(--eds-theme-color-text-utility-critical);

& > .field-note__icon {
/* TODO-AH: using the text token for this icon since they match and no icon tokens existed in the sheet */
color: var(--eds-theme-color-text-utility-critical);
}
}


.field-note--warning {
color: var(--eds-theme-color-text-utility-warning);

& > .field-note__icon {
/* TODO-AH: using the text token for this icon since they match and no icon tokens existed in the sheet */
color: var(--eds-theme-color-text-utility-warning);
}
}
58 changes: 58 additions & 0 deletions src/components/FieldNote/FieldNote-v2.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { StoryObj, Meta } from '@storybook/react';
import React from 'react';

import { FieldNote } from './FieldNote-v2';
import { LinkV2 as Link } from '../Link';
import Text from '../Text';

export default {
title: 'Components/V2/FieldNote',
component: FieldNote,
parameters: {
badges: ['intro-1.0', 'current-2.0'],
},
} as Meta<Args>;

type Args = React.ComponentProps<typeof FieldNote>;

export const Default: StoryObj<Args> = {
args: {
children: 'This is a fieldnote.',
id: 'field-1',
},
};

export const WithErrorIcon: StoryObj<Args> = {
args: {
children: 'This is a fieldnote.',
id: 'field-1',
icon: 'person-add',
isError: true,
},
};

export const WithIcon: StoryObj<Args> = {
args: {
children: 'This is a fieldnote.',
id: 'field-1',
icon: 'person-add',
},
};

export const WithText: StoryObj<Args> = {
args: {
children: (
<div className="max-w-xl">
<Text className="mb-6">Here is a field note that involves:</Text>
<ul className="ml-4 list-disc">
<li>Multiple lines</li>
<li>Arbitrary HTML text</li>
<li>
Even <Link href="#">text links</Link>
</li>
</ul>
</div>
),
id: 'field-1',
},
};
88 changes: 88 additions & 0 deletions src/components/FieldNote/FieldNote-v2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import clsx from 'clsx';
import type { ReactNode } from 'react';
import React from 'react';
import Icon, { type IconName } from '../Icon';
import styles from './FieldNote-v2.module.css';

export interface Props {
// Component API
/**
* Child node(s) that can be nested inside component
*/
children?: ReactNode;
/**
* CSS class names that can be appended to the component.
*/
className?: string;
/**
* HTML id for the component
*/
id?: string;
// Design API
/**
* Toggles disabled styling of the field note.
*/
disabled?: boolean;
/**
* Icon to use when an "icon" variant of the avatar. Default is "dangerous"
*/
icon?: IconName;
/**
* Whether there is an error state for the field note text (and icon)
*/
isError?: boolean;
/**
* Whether there is a warning state for the field note text (and icon)
*/
isWarning?: boolean;
}

/**
* `import {FieldNote} from "@chanzuckerberg/eds";`
*
* Fieldnote component wraps text to describe other components.
*/
export const FieldNote = ({
children,
className,
id,
disabled,
icon,
isError,
isWarning,
...other
}: Props) => {
const componentClassName = clsx(
styles['field-note'],
disabled && styles['field-note--disabled'],
isError && styles['field-note--error'],
isWarning && styles['field-note--warning'],
className,
);

let iconToUse = icon;
if (isError) {
iconToUse = 'dangerous';
} else if (isWarning) {
iconToUse = 'warning';
} else if (icon) {
iconToUse = icon;
}

return (
<div className={componentClassName} id={id} {...other}>
{(isError || isWarning || iconToUse) && (
<Icon
className={styles['field-note__icon']}
name={iconToUse}
purpose="informative"
size="1rem"
title={isError ? 'error' : 'warning'}
/>
)}
{children}
</div>
);
};

FieldNote.displayName = 'FieldNote';
1 change: 1 addition & 0 deletions src/components/FieldNote/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { FieldNote as default } from './FieldNote';
export { FieldNote as FieldNoteV2 } from './FieldNote-v2';
12 changes: 12 additions & 0 deletions src/components/Input/Input-v2.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@import '../../design-tokens/mixins.css';

/*------------------------------------*\
    # INPUT
\*------------------------------------*/

/**
* Default input styles
*/
.input {
@mixin inputStylesV2;
}
113 changes: 113 additions & 0 deletions src/components/Input/Input-v2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import clsx from 'clsx';
import type { ChangeEventHandler } from 'react';
import React, { forwardRef } from 'react';
import styles from './Input-v2.module.css';

export type InputProps = React.InputHTMLAttributes<HTMLInputElement> & {
/**
* Aria-label to provide an accesible name for the text input if no visible label is provided.
*/
'aria-label'?: string;
/**
* CSS class names that can be appended to the component.
*/
className?: string;
/**
* Disables the input and prevents editing the contents
*/
disabled?: boolean;
/**
* HTML id for the component
*/
id?: string;
/**
* Gives a hint as to the type of data needed for text input
*/
inputMode?:
| 'text'
| 'email'
| 'url'
| 'search'
| 'tel'
| 'none'
| 'numeric'
| 'decimal';
/**
* Error state of the form field
*/
isError?: boolean;
/**
* Whether there is a warning state for the field note text (and icon)
*/
isWarning?: boolean;
/**
* Maximum number the input can take.
*/
max?: number | string;
/**
* Minimum number the input can take.
*/
min?: number | string;
/**
* HTML name attribute for the input
*/
name?: string;
/**
* Function that fires when field value has changed
*/
onChange?: ChangeEventHandler<HTMLInputElement>;
/**
* Placeholder attribute for input. Note: placeholder should be used sparingly
*/
placeholder?: string;
/**
* Toggles the form control's interactivity. When `readOnly` is set to `true`, the form control is not interactive
*/
readOnly?: boolean;
/**
* Indicates that field is required for form to be successfully submitted
*/
required?: boolean;
/**
* Title attribute on input
*/
title?: string;
/**
* HTML type attribute, allowing switching between text, password, and other HTML5 input field types
*/
type?: React.HTMLInputTypeAttribute;
/**
* The value of the input
*/
value?: string | number;
/**
* The default value of the input
*/
defaultValue?: string | number;
};

/**
* Input component for one line of text.
*/
export const Input = forwardRef<HTMLInputElement, InputProps>(
({ className, disabled, id, isError, isWarning, ...other }, ref) => {
const componentClassName = clsx(
styles['input'],
isError && styles['error'],
isWarning && styles['warning'],
className,
);

return (
<input
className={componentClassName}
disabled={disabled}
id={id}
ref={ref}
{...other}
/>
);
},
);

Input.displayName = 'Input';
1 change: 1 addition & 0 deletions src/components/Input/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { Input as default } from './Input';
export type { InputProps } from './Input';
export { Input as InputV2 } from './Input-v2';
Loading

0 comments on commit f223eb2

Please sign in to comment.