Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature(FDS-342): Add input image field #261

Merged
merged 29 commits into from
Sep 20, 2021
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
136e889
Add input file module
rociobaena Sep 15, 2021
d3013a8
Add input image module
rociobaena Sep 15, 2021
c95c30f
Add input image module
rociobaena Sep 15, 2021
6670b99
update branch
rociobaena Sep 16, 2021
aa6e408
update branch
rociobaena Sep 16, 2021
7893d29
Add input month
rociobaena Sep 16, 2021
e4f5549
Merge branch 'develop' into chore/FDS-342-month
github-actions[bot] Sep 16, 2021
757eb4e
Merge branch 'develop' into chore/FDS-342-image
github-actions[bot] Sep 16, 2021
0faa902
Merge branch 'develop' into chore/FDS-342-month
github-actions[bot] Sep 16, 2021
258fbd3
Merge branch 'develop' into chore/FDS-342-image
github-actions[bot] Sep 16, 2021
187cdb3
Merge branch 'develop' into chore/FDS-342-month
github-actions[bot] Sep 16, 2021
b2e8aba
Merge branch 'develop' into chore/FDS-342-image
github-actions[bot] Sep 16, 2021
68b327c
Merge branch 'develop' into chore/FDS-342-month
github-actions[bot] Sep 16, 2021
c5cfd55
Merge branch 'develop' into chore/FDS-342-image
github-actions[bot] Sep 16, 2021
0437e0e
Merge branch 'develop' into chore/FDS-342-month
github-actions[bot] Sep 17, 2021
9b28d45
Merge branch 'develop' into chore/FDS-342-image
github-actions[bot] Sep 17, 2021
645352d
Improve fixture
rociobaena Sep 17, 2021
7e1c60c
Recover settings from develop
rociobaena Sep 17, 2021
86ad8d3
update from latest
rociobaena Sep 17, 2021
5ba34dd
improve tests
rociobaena Sep 17, 2021
6ae1d9d
Merge branch 'develop' into chore/FDS-342-image
github-actions[bot] Sep 18, 2021
c22738c
Merge branch 'develop' into chore/FDS-342-image
github-actions[bot] Sep 18, 2021
67b28a6
update snapshots
rociobaena Sep 18, 2021
ae2519d
add helper function
rociobaena Sep 18, 2021
ca365ff
update from latest
rociobaena Sep 18, 2021
4895d95
Merge branch 'develop' into chore/FDS-342-image
github-actions[bot] Sep 20, 2021
6254ce1
Merge branch 'develop' into chore/FDS-342-image
github-actions[bot] Sep 20, 2021
1c0e204
resolve conflicts
rociobaena Sep 20, 2021
56dd214
Merge branch 'develop' into chore/FDS-342-image
github-actions[bot] Sep 20, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions packages/cascara/src/modules/DataDateTime/DataDateTime.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ModuleContext } from '../context';
import styles from '../DataModule.module.scss';

import ModuleErrorBoundary from '../ModuleErrorBoundary';
import getAccessibleLabelSetters from '../helpers';

const propTypes = {
/** A module can have an Attribute, which will be used as form field name */
Expand All @@ -28,14 +29,10 @@ const DataDateTime = ({
...rest
}) => {
const { isEditing, formMethods } = useContext(ModuleContext);

// NOTE: THESE TWO SET DEFINITIONS COULD PROBABLY BECOME A HELPER FUNCTION FOR USE IN ALL MODULES
// We do not want to add a redundant aria-label property if there
// is an html label present with a linking `for` attribute.
const setAriaLabel = isLabeled ? undefined : label;
// We do not want to set a for attribute if there is no label content
// because we are defining aria label instead
const setHtmlFor = isLabeled ? label : undefined;
const { setAriaLabel, setHtmlFor } = getAccessibleLabelSetters(
isLabeled,
label
);

const renderEditing = (
<label htmlFor={setHtmlFor}>
Expand Down
29 changes: 29 additions & 0 deletions packages/cascara/src/modules/DataImage/DataImage.doc.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
title: DataImage
propTable: ./DataImage.js
type: 'module'
public: false
---

A data module to display an input **image** field

### Sandbox

Feel free to play around with the following code:

```jsx
<ModuleSandbox
isEditing={true}
record={{
id: 1,
firstName: 'John',
lastName: 'Doe',
}}
>
<DataImage
attribute='firstName'
alt='My Text'
src='/media/examples/login-button.png'
/>
</ModuleSandbox>
```
34 changes: 34 additions & 0 deletions packages/cascara/src/modules/DataImage/DataImage.fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import DataImage from './DataImage';
import ModuleSandbox from '../ModuleSandbox';

const DataImageSandbox = ({ isEditing, ...rest }) => (
<ModuleSandbox isEditing={isEditing}>
<DataImage {...rest} />
</ModuleSandbox>
);

const srcPath = '/media/examples/my-button.png';

const displayProps = {
label: 'Display',
src: srcPath,
};

const editingProps = {
isEditing: true,
label: 'Editing',
src: srcPath,
alt: 'Start',
};

// These can be used in tests
export { displayProps, editingProps };

// These are our fixtures
export default {
display: <DataImageSandbox {...displayProps} />,
displayNoLabel: <DataImageSandbox {...displayProps} isLabeled={false} />,
editing: <DataImageSandbox {...editingProps} />,
editingNoLabel: <DataImageSandbox {...editingProps} isLabeled={false} />,
};
79 changes: 79 additions & 0 deletions packages/cascara/src/modules/DataImage/DataImage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { useContext } from 'react';
import { Input } from 'reakit/Input';
import pt from 'prop-types';
import { ModuleContext } from '../context';
import styles from '../DataModule.module.scss';

import ModuleErrorBoundary from '../ModuleErrorBoundary';
import getAccessibleLabelSetters from '../helpers';

const propTypes = {
/** A module can have an Attribute, which will be used as form field name */
attribute: pt.string,
/** A Module can be defined to not present an editing state */
isEditable: pt.bool,
/** Presents the input without a label. NOT USER CONFIGURABLE */
isLabeled: pt.bool,
/** A Module needs to have a unique label relative to its context */
label: pt.string,
/** Image path */
src: pt.string,
/** A Module can have a value */
value: pt.string,
};

const DataImage = ({
attribute,
isEditable = true,
isLabeled = true,
label,
value,
src,
...rest
}) => {
const { isEditing, formMethods } = useContext(ModuleContext);
const { setAriaLabel, setHtmlFor } = getAccessibleLabelSetters(
isLabeled,
label
);

const renderEditing = (
<label htmlFor={setHtmlFor}>
{label && isLabeled && <span className={styles.LabelText}>{label}</span>}
<Input
{...rest}
aria-label={setAriaLabel}
className={styles.Input}
defaultValue={value}
id={label}
name={attribute || label}
ref={formMethods?.register}
src={src}
type={'image'}
/>
</label>
);

const renderDisplay = (
<span>
{label && isLabeled && <span className={styles.LabelText}>{label}</span>}
<span aria-label={label} className={styles.Image} {...rest}>
{src}
</span>
</span>
);

// Do not render an editable input if the module is not editable
return (
<ModuleErrorBoundary>
<div className={styles.Image}>
{isEditing && isEditable ? renderEditing : renderDisplay}
</div>
</ModuleErrorBoundary>
);
};

DataImage.propTypes = propTypes;

export { propTypes };
export default DataImage;
102 changes: 102 additions & 0 deletions packages/cascara/src/modules/DataImage/DataImage.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { render, screen } from '@testing-library/react';

import cosmosFixtures, {
displayProps,
editingProps,
} from './DataImage.fixture';

// We cannot destructure during import because the default export in Cosmos
// multi-fixture files is an object so we need to import the fixtures first,
// then destructure them separately.
const { display, editing, displayNoLabel, editingNoLabel } = cosmosFixtures;

describe('DataDateTime', () => {
// without ModuleSandbox will render the property information into a span
describe('display', () => {
// We need a place to store the view for snapshot testing. This is not required when we are using `screen` directly from RTL.
let view;

beforeEach(() => {
// Set the render container to our `view` so it is in scope for the snapshot test
view = render(display).container;
});

test('snapshot', () => {
expect(view).toMatchSnapshot();
});

test('renders a <span> by default', () => {
const input = screen.getByLabelText(displayProps.label);
// Make sure the actual DOM element is not render an input
expect(input.tagName).toMatch('SPAN');
// Make sure the dom element that has not our aria-label is the not an input
expect(input.classList.contains('Input')).toBe(false);
});
});

describe('editing', () => {
// We need a place to store the view for snapshot testing. This is not required when we are using `screen` directly from RTL.
let view;

beforeEach(() => {
// Set the render container to our `view` so it is in scope for the snapshot test
view = render(editing).container;
});

test('snapshot', () => {
expect(view).toMatchSnapshot();
});

test('renders a <input date> by default', () => {
const input = screen.getByLabelText(editingProps.label);
// Check that we also use the correct type
expect(input).toHaveAttribute('type', 'image');
});

test('renders the src', () => {
const input = screen.getByLabelText(editingProps.label);
expect(input).toHaveAttribute('alt', 'Start');
expect(input).toHaveAttribute('src', '/media/examples/my-button.png');
});
});

describe('accessibility', () => {
test('editing', () => {
render(editing);

const input = screen.getByLabelText(editingProps.label);
// The label tag is the parent wrapper
const label = input.closest('label');

// Test is written this way to make sure we know that both values need to be the same.
const linkedLabelValue = editingProps.label;

// Verify label for attribute has linked value
expect(label).toHaveAttribute(
'for',
expect.stringContaining(linkedLabelValue)
);
// Verify input id attribute has linked value
expect(input).toHaveAttribute(
'id',
expect.stringContaining(linkedLabelValue)
);
// Check that the input does NOT have an aria-label defined because there is a label tag
expect(input).not.toHaveAttribute('aria-label');
});

test('display no label', () => {
// Make sure that the input is still accessible with label text even when we are not showing a label tag in tables
render(displayNoLabel);
const input = screen.getByLabelText(displayProps.label);
expect(input).toBeDefined();
});

test('editing no label', () => {
// Make sure that the input is still accessible with label text even when we are not showing a label tag in tables
render(editingNoLabel);
const input = screen.getByLabelText(editingProps.label);
expect(input).toBeDefined();
});
});
});
49 changes: 49 additions & 0 deletions packages/cascara/src/modules/DataImage/DataImage.test.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`DataDateTime display snapshot 1`] = `
<div>
<div
class="Image"
>
<span>
<span
class="LabelText"
>
Display
</span>
<span
aria-label="Display"
class="Image"
>
/media/examples/my-button.png
</span>
</span>
</div>
</div>
`;

exports[`DataDateTime editing snapshot 1`] = `
<div>
<div
class="Image"
>
<label
for="Editing"
>
<span
class="LabelText"
>
Editing
</span>
<input
alt="Start"
class="Input"
id="Editing"
name="Editing"
src="/media/examples/my-button.png"
type="image"
/>
</label>
</div>
</div>
`;
1 change: 1 addition & 0 deletions packages/cascara/src/modules/DataImage/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './DataImage';
2 changes: 2 additions & 0 deletions packages/cascara/src/modules/DataModule.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ $module-background: #f0f0f0;

.Email,
.File,
.Image,
.Month,
.Number,
.Text,
.TextArea,
Expand Down
26 changes: 26 additions & 0 deletions packages/cascara/src/modules/DataMonth/DataMonth.doc.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: DataMonth
propTable: ./DataMonth.js
type: 'module'
public: false
---

A data module to display **string** values, it renders a input of type **month**.

### Sandbox

Feel free to play around with the following code:

```jsx
<ModuleSandbox
isEditing={true}
record={{
id: 1,
firstName: 'John',
lastName: 'Doe',
month: '2018-05',
}}
>
<DataText attribute='month' isEditable label='Month' value='2018-05' />
</ModuleSandbox>
```
35 changes: 35 additions & 0 deletions packages/cascara/src/modules/DataMonth/DataMonth.fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import DataMonth from './DataMonth';
import ModuleSandbox from '../ModuleSandbox';

const DataMonthSandbox = ({ isEditing, ...rest }) => (
<ModuleSandbox isEditing={isEditing}>
<DataMonth {...rest} />
</ModuleSandbox>
);

const monthValue = '2018-06';

const displayProps = {
label: 'Display',
value: monthValue,
};

const editingProps = {
isEditing: true,
label: 'Editing',
max: '2018-08',
min: '2018-06',
value: monthValue,
};

// These can be used in tests
export { displayProps, editingProps };

// These are our fixtures
export default {
display: <DataMonthSandbox {...displayProps} />,
displayNoLabel: <DataMonthSandbox {...displayProps} isLabeled={false} />,
editing: <DataMonthSandbox {...editingProps} />,
editingNoLabel: <DataMonthSandbox {...editingProps} isLabeled={false} />,
};
Loading