diff --git a/docs/app/Examples/collections/Grid/ResponsiveVariations/GridExampleDeviceVisibility.js b/docs/app/Examples/collections/Grid/ResponsiveVariations/GridExampleOnly.js
similarity index 93%
rename from docs/app/Examples/collections/Grid/ResponsiveVariations/GridExampleDeviceVisibility.js
rename to docs/app/Examples/collections/Grid/ResponsiveVariations/GridExampleOnly.js
index 0ea0e8eef0..26ca88fa27 100644
--- a/docs/app/Examples/collections/Grid/ResponsiveVariations/GridExampleDeviceVisibility.js
+++ b/docs/app/Examples/collections/Grid/ResponsiveVariations/GridExampleOnly.js
@@ -1,7 +1,7 @@
import React from 'react'
import { Grid, Segment } from 'semantic-ui-react'
-const GridExampleDeviceVisibility = () => (
+const GridExampleOnly = () => (
@@ -55,7 +55,7 @@ const GridExampleDeviceVisibility = () => (
Computer
-
+
Tablet
@@ -69,4 +69,4 @@ const GridExampleDeviceVisibility = () => (
)
-export default GridExampleDeviceVisibility
+export default GridExampleOnly
diff --git a/docs/app/Examples/collections/Grid/ResponsiveVariations/GridExampleOnlyMultiple.js b/docs/app/Examples/collections/Grid/ResponsiveVariations/GridExampleOnlyMultiple.js
new file mode 100644
index 0000000000..5189b893fb
--- /dev/null
+++ b/docs/app/Examples/collections/Grid/ResponsiveVariations/GridExampleOnlyMultiple.js
@@ -0,0 +1,35 @@
+import React from 'react'
+import { Grid, Segment } from 'semantic-ui-react'
+
+const GridExampleOnlyMultiple = () => (
+
+
+
+ Mobile
+
+
+ Tablet
+
+
+
+
+
+ Tablet
+
+
+ Computer
+
+
+
+
+
+ Large Screen
+
+
+ Widescreen
+
+
+
+)
+
+export default GridExampleOnlyMultiple
diff --git a/docs/app/Examples/collections/Grid/ResponsiveVariations/index.js b/docs/app/Examples/collections/Grid/ResponsiveVariations/index.js
index d4fc3008d5..0bd44b5357 100644
--- a/docs/app/Examples/collections/Grid/ResponsiveVariations/index.js
+++ b/docs/app/Examples/collections/Grid/ResponsiveVariations/index.js
@@ -40,8 +40,9 @@ const GridResponsiveVariationsExamples = () => (
+
*
*/
-import { numberToWord } from './numberToWord'
/**
* Props where only the prop key is used in the className.
@@ -51,36 +52,25 @@ export const useKeyOrValueAndKey = (val, key) => val && (val === true ? key : `$
//
/**
- * Create "X", "X wide" and "equal width" classNames.
- * "X" is a numberToWord value and "wide" is configurable.
- * @param {*} val The prop value
- * @param {string} [widthClass=''] The class
- * @param {boolean} [canEqual=false] Flag that indicates possibility of "equal" value
+ * The "only" prop implements control of visibility classes for Grid subcomponents.
*
- * @example
- *
- *
- *
- *
- *
- *
- *
- *
+ * @param {*} val The value of the "only" prop
*
* @example
- *
- *
+ *
+ *
+ *
+ *
*/
-export const useWidthProp = (val, widthClass = '', canEqual = false) => {
- if (canEqual && val === 'equal') {
- return 'equal width'
- }
- const valType = typeof val
- if ((valType === 'string' || valType === 'number') && widthClass) {
- return `${numberToWord(val)} ${widthClass}`
- }
- return numberToWord(val)
+export const useOnlyProp = val => {
+ if (!val || val === true) return null
+
+ return val.replace('large screen', 'large-screen')
+ .split(' ')
+ .map(prop => `${prop.replace('-', ' ')} only`)
+ .join(' ')
}
+
/**
* The "textAlign" prop follows the useValueAndKey except when the value is "justified'.
* In this case, only the class "justified" is used, ignoring the "aligned" class.
@@ -106,3 +96,35 @@ export const useTextAlignProp = val => val === 'justified' ? 'justified' : useVa
*
*/
export const useVerticalAlignProp = val => useValueAndKey(val, 'aligned')
+
+/**
+ * Create "X", "X wide" and "equal width" classNames.
+ * "X" is a numberToWord value and "wide" is configurable.
+ * @param {*} val The prop value
+ * @param {string} [widthClass=''] The class
+ * @param {boolean} [canEqual=false] Flag that indicates possibility of "equal" value
+ *
+ * @example
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * @example
+ *
+ *
+ */
+export const useWidthProp = (val, widthClass = '', canEqual = false) => {
+ if (canEqual && val === 'equal') {
+ return 'equal width'
+ }
+ const valType = typeof val
+ if ((valType === 'string' || valType === 'number') && widthClass) {
+ return `${numberToWord(val)} ${widthClass}`
+ }
+ return numberToWord(val)
+}
diff --git a/src/lib/customPropTypes.js b/src/lib/customPropTypes.js
index 9645ef0e9b..ccff3a17a9 100644
--- a/src/lib/customPropTypes.js
+++ b/src/lib/customPropTypes.js
@@ -236,6 +236,37 @@ export const demand = (requiredProps) => {
}
}
+/**
+ * Ensure an only prop contains a string with only possible values.
+ * @param {string[]} possible An array of possible values to prop.
+ */
+export const onlyProp = possible => {
+ return (props, propName, componentName) => {
+ if (!Array.isArray(possible)) {
+ throw new Error([
+ 'Invalid argument supplied to some, expected an instance of array.',
+ `See \`${propName}\` prop in \`${componentName}\`.`,
+ ].join(' '))
+ }
+
+ const propValue = props[propName]
+
+ // skip if prop is undefined
+ if (_.isNil(propValue) || propValue === false) return
+
+ const values = propValue
+ .replace('large screen', 'large-screen')
+ .split(' ')
+ .map(val => _.trim(val).replace('-', ' '))
+ const invalid = _.difference(values, possible)
+
+ // fail only if there are invalid values
+ if (invalid.length > 0) {
+ return new Error(`\`${propName}\` prop in \`${componentName}\` has invalid values: \`${invalid.join('`, `')}\`.`)
+ }
+ }
+}
+
/**
* Ensure a component can render as a node passed as a prop value in place of children.
*/
diff --git a/src/lib/index.js b/src/lib/index.js
index a241be811d..810a913c06 100644
--- a/src/lib/index.js
+++ b/src/lib/index.js
@@ -3,11 +3,13 @@ export * as childrenUtils from './childrenUtils'
export {
useKeyOnly,
- useValueAndKey,
useKeyOrValueAndKey,
- useWidthProp,
+ useValueAndKey,
+
+ useOnlyProp,
useTextAlignProp,
useVerticalAlignProp,
+ useWidthProp,
} from './classNameBuilders'
export * as customPropTypes from './customPropTypes'
diff --git a/test/specs/collections/Grid/GridColumn-test.js b/test/specs/collections/Grid/GridColumn-test.js
index 6d2df8e6ca..942171be72 100644
--- a/test/specs/collections/Grid/GridColumn-test.js
+++ b/test/specs/collections/Grid/GridColumn-test.js
@@ -6,6 +6,7 @@ describe('GridColumn', () => {
common.isConformant(GridColumn)
common.rendersChildren(GridColumn)
+ common.implementsOnlyProp(GridColumn)
common.implementsTextAlignProp(GridColumn)
common.implementsVerticalAlignProp(GridColumn)
@@ -41,9 +42,6 @@ describe('GridColumn', () => {
})
common.propKeyAndValueToClassName(GridColumn, 'floated', SUI.FLOATS)
- common.propKeyAndValueToClassName(GridColumn, 'only', [
- 'computer', 'large screen', 'mobile', 'tablet mobile', 'tablet', 'widescreen',
- ])
common.propKeyOnlyToClassName(GridColumn, 'stretched')
diff --git a/test/specs/collections/Grid/GridRow-test.js b/test/specs/collections/Grid/GridRow-test.js
index c7bf77bf74..85d5d468de 100644
--- a/test/specs/collections/Grid/GridRow-test.js
+++ b/test/specs/collections/Grid/GridRow-test.js
@@ -6,6 +6,7 @@ describe('GridRow', () => {
common.isConformant(GridRow)
common.rendersChildren(GridRow)
+ common.implementsOnlyProp(GridRow)
common.implementsTextAlignProp(GridRow)
common.implementsVerticalAlignProp(GridRow)
common.implementsWidthProp(GridRow, SUI.WIDTHS, {
@@ -13,9 +14,6 @@ describe('GridRow', () => {
widthClass: 'column',
})
- common.propKeyAndValueToClassName(GridRow, 'only', [
- 'computer', 'large screen', 'mobile', 'tablet mobile', 'tablet', 'widescreen',
- ])
common.propKeyAndValueToClassName(GridRow, 'reversed', [
['computer', 'computer vertically', 'mobile', 'mobile vertically', 'tablet', 'tablet vertically'],
])
diff --git a/test/specs/commonTests.js b/test/specs/commonTests.js
index 41113e0571..ae583bd65d 100644
--- a/test/specs/commonTests.js
+++ b/test/specs/commonTests.js
@@ -856,6 +856,35 @@ export const implementsImageProp = (Component, options = {}) => {
})
}
+/**
+ * Assert that a Component correctly implements the "only" prop.
+ * @param {React.Component|Function} Component The component to test.
+ */
+export const implementsOnlyProp = Component => {
+ const { assertRequired } = commonTestHelpers('propKeyAndValueToClassName', Component)
+ const propValues = SUI.VISIBILITY
+
+ describe('only (common)', () => {
+ assertRequired(Component, 'a `Component`')
+
+ _noDefaultClassNameFromProp(Component, 'only', propValues)
+ _noClassNameFromBoolProps(Component, 'only', propValues)
+
+ propValues.forEach(propVal => {
+ it(`adds "${propVal} only" to className`, () => {
+ shallow(createElement(Component, { only: propVal })).should.have.className(`${propVal} only`)
+ })
+ })
+
+ it('adds all possible values to className', () => {
+ const className = propValues.map(prop => `${prop} only`).join(' ')
+ const propValue = propValues.join(' ')
+
+ shallow(createElement(Component, { only: propValue })).should.have.className(className)
+ })
+ })
+}
+
/**
* Assert that a Component correctly implements the "textAlign" prop.
* @param {React.Component|Function} Component The component to test.