Skip to content

Commit

Permalink
Support adding label as Reactnode
Browse files Browse the repository at this point in the history
  • Loading branch information
badiuoanaalexandra committed Apr 8, 2024
1 parent 3f0f65d commit a90c837
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,32 @@ exports[`ControlLabel basic with optional renders 1`] = `
</div>
</body>
`;

exports[`ControlLabel with ReactNode text renders 1`] = `
<body>
<div>
<div>
<label
class="inline-block color-red"
for="label-id"
>
<div>
Something
</div>
Some text
<span
class="txt-normal"
>
(optional)
</span>
</label>
<span
class="inline-block ml12"
>
This is an aside
</span>
</div>
</div>
</body>
`;
27 changes: 23 additions & 4 deletions src/components/control-label/control-label.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ import { render } from '@testing-library/react';
import ControlLabel from './control-label';

describe('ControlLabel', () => {

describe('basic', () => {
const props = {
text: 'basic label',
id: 'label-id'
};

test('renders', () => {
const { baseElement } = render(<ControlLabel {...props} />)
const { baseElement } = render(<ControlLabel {...props} />);
expect(baseElement).toMatchSnapshot();
});
});
Expand All @@ -24,7 +23,7 @@ describe('ControlLabel', () => {
};

test('renders', () => {
const { baseElement } = render(<ControlLabel {...props} />)
const { baseElement } = render(<ControlLabel {...props} />);
expect(baseElement).toMatchSnapshot();
});
});
Expand All @@ -39,7 +38,27 @@ describe('ControlLabel', () => {
};

test('renders', () => {
const { baseElement } = render(<ControlLabel {...props} />)
const { baseElement } = render(<ControlLabel {...props} />);
expect(baseElement).toMatchSnapshot();
});
});

describe('with ReactNode text', () => {
const props = {
text: (
<>
<div>Something</div>
Some text
</>
),
id: 'label-id',
aside: 'This is an aside',
optional: true,
themeLabel: 'color-red'
};

test('renders', () => {
const { baseElement } = render(<ControlLabel {...props} />);
expect(baseElement).toMatchSnapshot();
});
});
Expand Down
4 changes: 2 additions & 2 deletions src/components/control-label/control-label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PropTypes from 'prop-types';

interface Props {
id: string;
text: string;
text: string | ReactNode;
aside?: ReactNode;
optional?: boolean;
themeLabel?: string;
Expand Down Expand Up @@ -33,7 +33,7 @@ ControlLabel.propTypes = {
/** Value should match the identifying id of the input element. */
id: PropTypes.string.isRequired,
/** Label text */
text: PropTypes.string.isRequired,
text: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
/** Additional content to provide aligned to the right of the label. */
aside: PropTypes.node,
/** If true, label text adds (optional) alongside it. */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
With icon.
*/
import React from 'react';
import ControlLabel from '../control-label';
import Icon from '../../icon/icon';

export default function Example() {
const getLabelWithIcon = (
<>
<Icon name="marker" inline={true} />
Your story
</>
);
return (
<>
<ControlLabel id="name" text={getLabelWithIcon} />
<input id="name" type="text" placeholder="Enter name" />
</>
);
}
17 changes: 10 additions & 7 deletions src/components/control-range/control-range.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {ReactElement, ReactNode} from 'react';
import React, { ReactElement, ReactNode } from 'react';
import * as SliderPrimitive from '@radix-ui/react-slider';
import PropTypes from 'prop-types';
import omit from '../utils/omit';
Expand All @@ -24,11 +24,11 @@ const propNames = [
'validator'
];

interface Props extends Omit<InputProps, 'value' | 'onChange'>{
interface Props extends Omit<InputProps, 'value' | 'onChange'> {
id: string;
onChange: (value: Array<number>, id: string) => void;
value?: Array<number>;
label?: string;
label?: string | ReactNode;
optional?: boolean;
aside?: ReactNode;
tooltip?: boolean;
Expand Down Expand Up @@ -58,7 +58,6 @@ export default function ControlRange({
themeLabel,
...props
}: Props): ReactElement {

const extraProps = omit(props, propNames);

const rootProps = {
Expand All @@ -76,7 +75,9 @@ export default function ControlRange({
}

const renderThumb = (value: number, index: number) => {
return <SliderPrimitive.Thumb key={index} className={`${themeControlThumb}`} />
return (
<SliderPrimitive.Thumb key={index} className={`${themeControlThumb}`} />
);
};

return (
Expand All @@ -97,7 +98,9 @@ export default function ControlRange({
<div className={`range ${themeControlRange}`}>
<SliderPrimitive.Root {...rootProps}>
<SliderPrimitive.Track className={`${themeControlTrack}`}>
<SliderPrimitive.Range className={`absolute h-full ${themeControlRangeActive}`}/>
<SliderPrimitive.Range
className={`absolute h-full ${themeControlRangeActive}`}
/>
</SliderPrimitive.Track>
{value.map(renderThumb)}
</SliderPrimitive.Root>
Expand All @@ -114,7 +117,7 @@ ControlRange.propTypes = {
/** Accepts an array of numbers, where each number matches a draggable thumb. */
value: PropTypes.array,
/** Value passed to the label element. */
label: PropTypes.string,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
/** If provided the text, "(optional)" is appended to the value of the label element. */
optional: PropTypes.bool,
/** Additional content inserted alongside the label element. */
Expand Down
57 changes: 36 additions & 21 deletions src/components/control-text/control-text.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
import React, { ReactElement, ReactNode, useState, useRef, ChangeEvent, HTMLInputTypeAttribute, CSSProperties } from 'react';
import React, {
ReactElement,
ReactNode,
useState,
useRef,
ChangeEvent,
HTMLInputTypeAttribute,
CSSProperties
} from 'react';
import PropTypes from 'prop-types';
import omit from '../utils/omit';
import ControlLabel from '../control-label';
import ControlWrapper from '../control-wrapper';
import Popover from '../popover';
import Icon from '../icon';
import {InputProps, PopoverProps} from '../typings';
import { InputProps, PopoverProps } from '../typings';

interface Props extends Omit<InputProps, 'onChange'> {
id: string;
onChange: (value: string, id: string) => void;
value?: string | number;
type?: HTMLInputTypeAttribute;
label?: string;
label?: string | ReactNode;
noAuto?: boolean;
optional?: boolean;
aside?: ReactNode;
validationError?: ReactNode;
errorStyle?: 'default' | 'inline';
popoverProps?: PopoverProps;
popoverProps?: PopoverProps;
themeControlInput?: string;
themeControlWrapper?: string;
themeLabel?: string;
Expand Down Expand Up @@ -70,7 +78,7 @@ export default function ControlText({
};

const isActive = () => {
if (typeof window === 'undefined') return false
if (typeof window === 'undefined') return false;

return (
window.document.activeElement === inputElement.current ||
Expand Down Expand Up @@ -101,22 +109,23 @@ export default function ControlText({
};

const inputProps: {
id: string,
name: string,
onChange: (e: ChangeEvent<HTMLInputElement>) => void,
value: string | number,
type: HTMLInputTypeAttribute,
className: string,
'aria-required': boolean,
'data-testid': string,
autoCapitalize?: string,
autoCorrect?: string,
spellCheck?: boolean,
style?: CSSProperties
id: string;
name: string;
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
value: string | number;
type: HTMLInputTypeAttribute;
className: string;
'aria-required': boolean;
'data-testid': string;
autoCapitalize?: string;
autoCorrect?: string;
spellCheck?: boolean;
style?: CSSProperties;
} = {
id,
name: id,
onChange: (e: ChangeEvent<HTMLInputElement>) => onChange(e.target.value, id),
onChange: (e: ChangeEvent<HTMLInputElement>) =>
onChange(e.target.value, id),
value,
type,
className: themeControlInput,
Expand Down Expand Up @@ -166,7 +175,7 @@ export default function ControlText({
content={validationError}
placement="top"
aria-label="Validation error"
{ ...props.popoverProps }
{...props.popoverProps}
>
<button
type="button"
Expand All @@ -179,7 +188,13 @@ export default function ControlText({
className="h-full bg-red color-white round-r px6"
>
<span className="flex flex--center-cross flex--center-main">
<Icon name="alert" passthroughProps={{ fill: 'white', className: "cursor-pointer" }} />
<Icon
name="alert"
passthroughProps={{
fill: 'white',
className: 'cursor-pointer'
}}
/>
</span>
</button>
</Popover>
Expand Down Expand Up @@ -223,7 +238,7 @@ ControlText.propTypes = {
/** Type attribute to override the existing default of 'text' */
type: PropTypes.string,
/** Label for the control. */
label: PropTypes.string,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
/** Enable/Disable browser enabled autocorrect or spelling suggestions from the element. */
noAuto: PropTypes.bool,
/** If provided, "(optional)" is appended to the value of the legend element. */
Expand Down
30 changes: 15 additions & 15 deletions src/components/control-textarea/control-textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface Props extends Omit<InputProps, 'onChange'> {
onChange: (value: string, id: string) => void;
id?: string;
value?: string;
label?: string;
label?: string | ReactNode;
noAuto?: boolean;
optional?: boolean;
aside?: ReactNode;
Expand Down Expand Up @@ -52,21 +52,22 @@ export default function ControlTextarea({
}: Props): ReactElement {
const extraProps = omit(props, propNames);
const textareaProps: {
id: string,
name: string,
onChange: (e: ChangeEvent<HTMLTextAreaElement>) => void,
value: string,
className: string,
'aria-required': boolean,
'data-testid': string,
autoCapitalize?: string,
autoCorrect?: string,
spellCheck?: boolean,
'aria-invalid'?: boolean
id: string;
name: string;
onChange: (e: ChangeEvent<HTMLTextAreaElement>) => void;
value: string;
className: string;
'aria-required': boolean;
'data-testid': string;
autoCapitalize?: string;
autoCorrect?: string;
spellCheck?: boolean;
'aria-invalid'?: boolean;
} = {
id,
name: id,
onChange: (e: ChangeEvent<HTMLTextAreaElement>) => onChange(e.target.value, id),
onChange: (e: ChangeEvent<HTMLTextAreaElement>) =>
onChange(e.target.value, id),
value,
className: themeControlTextarea,
'aria-required': optional ? false : true,
Expand Down Expand Up @@ -114,7 +115,7 @@ ControlTextarea.propTypes = {
*/
onChange: PropTypes.func.isRequired,
/** Label for the control. */
label: PropTypes.string,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
/** If `true`, autocorrect and spelling suggestions will be disabled. */
noAuto: PropTypes.bool,
/** If `true`, the text `(optional)` is appended to the label element. */
Expand All @@ -130,4 +131,3 @@ ControlTextarea.propTypes = {
/** Classes to apply to the label element. */
themeLabel: PropTypes.string
};

0 comments on commit a90c837

Please sign in to comment.