From 40b630899118efcaa4b875a2b3c70f1abfb84e8f Mon Sep 17 00:00:00 2001 From: "rocio.baena" Date: Sun, 19 Sep 2021 22:27:42 -0500 Subject: [PATCH 1/2] Input range --- .../src/modules/DataModule.module.scss | 1 + .../src/modules/DataRange/DataRange.doc.mdx | 24 +++++ .../modules/DataRange/DataRange.fixture.js | 35 ++++++ .../src/modules/DataRange/DataRange.js | 75 +++++++++++++ .../src/modules/DataRange/DataRange.test.js | 101 ++++++++++++++++++ .../src/modules/DataRange/DataRange.test.snap | 51 +++++++++ .../cascara/src/modules/DataRange/index.js | 1 + packages/cascara/src/modules/ModuleKeys.js | 2 + packages/cascara/src/modules/index.js | 1 + .../ui/Table/tests/TableSnapshot.test.snap | 2 +- 10 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 packages/cascara/src/modules/DataRange/DataRange.doc.mdx create mode 100644 packages/cascara/src/modules/DataRange/DataRange.fixture.js create mode 100644 packages/cascara/src/modules/DataRange/DataRange.js create mode 100644 packages/cascara/src/modules/DataRange/DataRange.test.js create mode 100644 packages/cascara/src/modules/DataRange/DataRange.test.snap create mode 100644 packages/cascara/src/modules/DataRange/index.js diff --git a/packages/cascara/src/modules/DataModule.module.scss b/packages/cascara/src/modules/DataModule.module.scss index 3eb8a12ce..0e223dd5a 100644 --- a/packages/cascara/src/modules/DataModule.module.scss +++ b/packages/cascara/src/modules/DataModule.module.scss @@ -54,6 +54,7 @@ $module-background: #f0f0f0; .Email, .File, .Number, +.Range, .Text, .TextArea, .Select { diff --git a/packages/cascara/src/modules/DataRange/DataRange.doc.mdx b/packages/cascara/src/modules/DataRange/DataRange.doc.mdx new file mode 100644 index 000000000..201aaecd0 --- /dev/null +++ b/packages/cascara/src/modules/DataRange/DataRange.doc.mdx @@ -0,0 +1,24 @@ +--- +title: DataRange +propTable: DataRange.js +type: 'module' +public: false +--- + +A data module to display **string** values, it renders a input of type **range**. + +### Sandbox + +Feel free to play around with the following code: + +```jsx + + + +``` diff --git a/packages/cascara/src/modules/DataRange/DataRange.fixture.js b/packages/cascara/src/modules/DataRange/DataRange.fixture.js new file mode 100644 index 000000000..bd8e7c3a0 --- /dev/null +++ b/packages/cascara/src/modules/DataRange/DataRange.fixture.js @@ -0,0 +1,35 @@ +import React from 'react'; +import DataRange from './DataRange'; +import ModuleSandbox from '../ModuleSandbox'; + +const DataRangeSandbox = ({ isEditing, ...rest }) => ( + + + +); + +const rangeValue = '7'; + +const displayProps = { + label: 'Display', + value: rangeValue, +}; + +const editingProps = { + isEditing: true, + label: 'Editing', + min: '0', + max: '11', + value: rangeValue, + step: '1', +}; + +// These can be used in tests +export { displayProps, editingProps }; + +export default { + display: , + displayNoLabel: , + editing: , + editingNoLabel: , +}; diff --git a/packages/cascara/src/modules/DataRange/DataRange.js b/packages/cascara/src/modules/DataRange/DataRange.js new file mode 100644 index 000000000..9dff767a8 --- /dev/null +++ b/packages/cascara/src/modules/DataRange/DataRange.js @@ -0,0 +1,75 @@ +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, + /** A Module can have a value */ + value: pt.string, +}; + +const DataRange = ({ + attribute, + isEditable = true, + isLabeled = true, + label, + value, + ...rest +}) => { + const { isEditing, formMethods } = useContext(ModuleContext); + const { setAriaLabel, setHtmlFor } = getAccessibleLabelSetters( + isLabeled, + label + ); + + const renderEditing = ( + + ); + + const renderDisplay = ( + + {label && isLabeled && {label}} + + {value} + + + ); + + // Do not render an editable input if the module is not editable + return ( + +
+ {isEditing && isEditable ? renderEditing : renderDisplay} +
+
+ ); +}; + +DataRange.propTypes = propTypes; + +export { propTypes }; +export default DataRange; diff --git a/packages/cascara/src/modules/DataRange/DataRange.test.js b/packages/cascara/src/modules/DataRange/DataRange.test.js new file mode 100644 index 000000000..b0cec7842 --- /dev/null +++ b/packages/cascara/src/modules/DataRange/DataRange.test.js @@ -0,0 +1,101 @@ +import { fireEvent, render, screen } from '@testing-library/react'; + +import cosmosFixtures, { + displayProps, + editingProps, +} from './DataRange.fixture'; + +const { display, editing, displayNoLabel, editingNoLabel } = cosmosFixtures; + +describe('DataRange', () => { + // 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 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 our aria-label is the input + expect(input.classList.contains('Range')).toBe(true); + }); + }); + + 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 by default', () => { + const input = screen.getByLabelText(editingProps.label); + // Check that we also use the correct type + expect(input).toHaveAttribute('type', 'range'); + }); + + test('change value', () => { + const newRange = '5'; + const input = screen.getByLabelText(editingProps.label); + fireEvent.change(input, { target: { value: newRange } }); + expect(input).toHaveValue(newRange); + }); + }); + + 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(); + }); + }); +}); diff --git a/packages/cascara/src/modules/DataRange/DataRange.test.snap b/packages/cascara/src/modules/DataRange/DataRange.test.snap new file mode 100644 index 000000000..870daaaf2 --- /dev/null +++ b/packages/cascara/src/modules/DataRange/DataRange.test.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DataRange display snapshot 1`] = ` +
+
+ + + Display + + + 7 + + +
+
+`; + +exports[`DataRange editing snapshot 1`] = ` +
+
+ +
+
+`; diff --git a/packages/cascara/src/modules/DataRange/index.js b/packages/cascara/src/modules/DataRange/index.js new file mode 100644 index 000000000..637682c9e --- /dev/null +++ b/packages/cascara/src/modules/DataRange/index.js @@ -0,0 +1 @@ +export { default } from './DataRange'; diff --git a/packages/cascara/src/modules/ModuleKeys.js b/packages/cascara/src/modules/ModuleKeys.js index 040179745..f588afb24 100644 --- a/packages/cascara/src/modules/ModuleKeys.js +++ b/packages/cascara/src/modules/ModuleKeys.js @@ -14,6 +14,7 @@ import DataTextArea from './DataTextArea'; import DataFile from './DataFile'; import DataDate from './DataDate'; import DataDateTime from './DataDateTime'; +import DataRange from './DataRange'; const actionModules = { button: ActionButton, @@ -30,6 +31,7 @@ const dataModules = { json: DataJson, number: DataNumber, radio: DataRadio, + range: DataRange, select: DataSelect, text: DataText, textarea: DataTextArea, diff --git a/packages/cascara/src/modules/index.js b/packages/cascara/src/modules/index.js index d3cf12585..e9e1850d9 100644 --- a/packages/cascara/src/modules/index.js +++ b/packages/cascara/src/modules/index.js @@ -15,3 +15,4 @@ export { default as ModuleSandbox } from './ModuleSandbox'; export { default as DataFile } from './DataFile'; export { default as DataDate } from './DataDate'; export { default as DataDateTime } from './DataDateTime'; +export { default as DataRange } from './DataRange'; diff --git a/packages/cascara/src/ui/Table/tests/TableSnapshot.test.snap b/packages/cascara/src/ui/Table/tests/TableSnapshot.test.snap index 3b6a30790..c12dc07f1 100644 --- a/packages/cascara/src/ui/Table/tests/TableSnapshot.test.snap +++ b/packages/cascara/src/ui/Table/tests/TableSnapshot.test.snap @@ -344,7 +344,7 @@ exports[`Table snapshot tests dataDisplay with non-existent module 1`] = ` class="Error" data-testid="module-error" > - unknownModule is not a valid value for module. Try using one of [checkbox, date, datetime, email, file, json, number, radio, select, text, textarea] + unknownModule is not a valid value for module. Try using one of [checkbox, date, datetime, email, file, json, number, radio, range, select, text, textarea] Date: Mon, 20 Sep 2021 17:15:28 -0700 Subject: [PATCH 2/2] fix time --- packages/cascara/src/modules/DataModule.module.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cascara/src/modules/DataModule.module.scss b/packages/cascara/src/modules/DataModule.module.scss index 3a3ce4699..695aed7de 100644 --- a/packages/cascara/src/modules/DataModule.module.scss +++ b/packages/cascara/src/modules/DataModule.module.scss @@ -63,7 +63,7 @@ $module-background: #f0f0f0; .Tel, .Text, .TextArea, -.Time { +.Time, .Url { @extend %ModuleContainer; }