From 31e6dd958dc30b9e32b1cca0b8e12e2d3cce6670 Mon Sep 17 00:00:00 2001 From: Tamas Kovacs Date: Tue, 27 Aug 2024 17:06:13 +0200 Subject: [PATCH] docs(ui-editable,ui-menu,ui-number-input): functional based examples are added to InplaceEdit, Menu and NumberInput Closes: INSTUI-4173 --- .../ui-editable/src/InPlaceEdit/README.md | 806 ++++++++++++------ packages/ui-menu/src/Menu/README.md | 191 +++-- .../ui-number-input/src/NumberInput/README.md | 324 +++++-- 3 files changed, 885 insertions(+), 436 deletions(-) diff --git a/packages/ui-editable/src/InPlaceEdit/README.md b/packages/ui-editable/src/InPlaceEdit/README.md index c5a12a8e7c..5def559222 100644 --- a/packages/ui-editable/src/InPlaceEdit/README.md +++ b/packages/ui-editable/src/InPlaceEdit/README.md @@ -31,352 +31,610 @@ the space it consumes in the app. Use `InPlaceEdit` to edit `Text` using `Text as="input"`. Also demonstrates how you might wish to handle the case when the text is empty. Use the checkbox to switch between inline and block layout. -```js ---- -type: example ---- -class Example extends React.Component { +- ```js + class Example extends React.Component { + constructor(props) { + super(props) + this.state = { + mode: props.mode || 'view', + value: 'This is some text', + inline: true + } + } - constructor (props) { - super(props) - this.state = { - mode: props.mode || 'view', - value: 'This is some text', - inline: true + // You must provide this to Editable to be + // notified of mode changes + handleChangeMode = (mode) => { + this.setState({ mode }) } - } - // You must provide this to Editable to be - // notified of mode changes - handleChangeMode = (mode) => { - this.setState({mode}) - } + // You attach an event handler to your edit component + // to be notified of value changes from user interactions + handleChange = (event) => { + this.setState({ value: event.target.value }) + } - // You attach an event handler to your edit component - // to be notified of value changes from user interactions - handleChange = (event) => { - this.setState({value: event.target.value}) - } + // Renders the view component + // Be sure to give it the current value + renderView = () => ( + + {this.state.value || 'Enter some text'} + + ) - // Renders the view component - // Be sure to give it the current value - renderView = () => ( - - {this.state.value || 'Enter some text'} - - ) - - // Renders the edit component. - // You have to forward the props on, which - // includes an onBlur property to help manage - // the mode changes. - // Be sure to give it the current value - renderEdit = ({onBlur, editorRef}) => ( - - ) - - // Renders the edit button. - // Leverage the default implementation provided by InPlaceEdit - renderEditButton = (props) => { - props.label = `Edit title "${this.state.value}"` - return InPlaceEdit.renderDefaultEditButton(props) - } + // Renders the edit component. + // You have to forward the props on, which + // includes an onBlur property to help manage + // the mode changes. + // Be sure to give it the current value + renderEdit = ({ onBlur, editorRef }) => ( + + ) + + // Renders the edit button. + // Leverage the default implementation provided by InPlaceEdit + renderEditButton = (props) => { + props.label = `Edit title "${this.state.value}"` + return InPlaceEdit.renderDefaultEditButton(props) + } + + onChangeLayout = (event) => { + this.setState({ inline: event.target.checked }) + } - onChangeLayout = (event) => { - this.setState({inline: event.target.checked}) + render() { + return ( + + + + + + + ) + } } + render() + ``` + +- ```js + const Example = (props) => { + const [mode, setMode] = useState(props.mode || 'view') + const [value, setValue] = useState('This is some text') + const [inline, setInline] = useState(true) + + // You must provide this to Editable to be + // notified of mode changes + const handleChangeMode = (mode) => { + setMode(mode) + } + + // You attach an event handler to your edit component + // to be notified of value changes from user interactions + const handleChange = (event) => { + setValue(event.target.value) + } + + // Renders the view component + // Be sure to give it the current value + const renderView = () => ( + + {value || 'Enter some text'} + + ) + + // Renders the edit component. + // You have to forward the props on, which + // includes an onBlur property to help manage + // the mode changes. + // Be sure to give it the current value + const renderEdit = ({ onBlur, editorRef }) => ( + + ) + + // Renders the edit button. + // Leverage the default implementation provided by InPlaceEdit + const renderEditButton = (props) => { + props.label = `Edit title "${value}"` + return InPlaceEdit.renderDefaultEditButton(props) + } + + const onChangeLayout = (event) => { + setInline(event.target.checked) + } - render () { return ( - + ) } -} -render() -``` + + render() + ``` A readOnly `InPlaceEdit` -```js ---- -type: example ---- -class Example extends React.Component { +- ```js + class Example extends React.Component { + constructor(props) { + super(props) + this.state = { + mode: props.mode || 'view', + value: 'This is some text' + } + } - constructor (props) { - super(props) - this.state = { - mode: props.mode || 'view', - value: 'This is some text', + // You must provide this to Editable to be + // notified of mode changes + handleChangeMode = (mode) => { + this.setState({ mode }) } - } - // You must provide this to Editable to be - // notified of mode changes - handleChangeMode = (mode) => { - this.setState({mode}) - } + // You attach an event handler to your edit component + // to be notified of value changes from user interactions + handleChange = (event) => { + this.setState({ value: event.target.value }) + } - // You attach an event handler to your edit component - // to be notified of value changes from user interactions - handleChange = (event) => { - this.setState({value: event.target.value}) - } + // Renders the view component + // Be sure to give it the current value + renderView = () => {this.state.value} + + // Renders the edit component. + // You have to forward the props on, which + // includes an onBlur property to help manage + // the mode changes. + // Be sure to give it the current value + renderEdit = ({ onBlur, editorRef }) => ( + + ) - // Renders the view component - // Be sure to give it the current value - renderView = () => ( - - {this.state.value} - - ) - - // Renders the edit component. - // You have to forward the props on, which - // includes an onBlur property to help manage - // the mode changes. - // Be sure to give it the current value - renderEdit = ({onBlur, editorRef}) => ( - - ) - - // Renders the edit button. - // Leverage the default implementation provided by InPlaceEdit - renderEditButton = (props) => { - props.label = `Edit title "${this.state.value}"` - return InPlaceEdit.renderDefaultEditButton(props) + // Renders the edit button. + // Leverage the default implementation provided by InPlaceEdit + renderEditButton = (props) => { + props.label = `Edit title "${this.state.value}"` + return InPlaceEdit.renderDefaultEditButton(props) + } + + render() { + return ( + + ) + } } + render() + ``` + +- ```js + const Example = (props) => { + const [mode, setMode] = useState(props.mode || 'view') + const [value, setValue] = useState('This is some text') + + // You must provide this to Editable to be + // notified of mode changes + const handleChangeMode = (mode) => { + setMode(mode) + } + + // You attach an event handler to your edit component + // to be notified of value changes from user interactions + const handleChange = (event) => { + setValue(event.target.value) + } + + // Renders the view component + // Be sure to give it the current value + const renderView = () => {value} + + // Renders the edit component. + // You have to forward the props on, which + // includes an onBlur property to help manage + // the mode changes. + // Be sure to give it the current value + const renderEdit = ({ onBlur, editorRef }) => ( + + ) + + // Renders the edit button. + // Leverage the default implementation provided by InPlaceEdit + const renderEditButton = (props) => { + props.label = `Edit title "${value}"` + return InPlaceEdit.renderDefaultEditButton(props) + } - render () { return ( ) } -} -render() -``` + + render() + ``` To edit end-justified text, wrap `` in a `` component, as follows: -```js ---- -type: example ---- -class Example extends React.Component { +- ```js + class Example extends React.Component { + constructor(props) { + super(props) + this.state = { + mode: props.mode || 'view', + value: 'This is some text' + } + } - constructor (props) { - super(props) - this.state = { - mode: props.mode || 'view', - value: 'This is some text', + // You must provide this to Editable to be + // notified of mode changes + handleChangeMode = (mode) => { + this.setState({ mode }) } - } - // You must provide this to Editable to be - // notified of mode changes - handleChangeMode = (mode) => { - this.setState({mode}) - } + // You attach an event handler to your edit component + // to be notified of value changes from user interactions + handleChange = (event) => { + this.setState({ value: event.target.value }) + } - // You attach an event handler to your edit component - // to be notified of value changes from user interactions - handleChange = (event) => { - this.setState({value: event.target.value}) - } + // Renders the view component + // Be sure to give it the current value + renderView = () => {this.state.value} + + // Renders the edit component. + // You have to forward the props on, which + // includes an onBlur property to help manage + // the mode changes. + // Be sure to give it the current value + renderEdit = ({ onBlur, editorRef }) => ( + + ) - // Renders the view component - // Be sure to give it the current value - renderView = () => ( - - {this.state.value} - - ) - - // Renders the edit component. - // You have to forward the props on, which - // includes an onBlur property to help manage - // the mode changes. - // Be sure to give it the current value - renderEdit = ({onBlur, editorRef}) => ( - - ) - - // Renders the edit button. - // Leverage the default implementation provided by InPlaceEdit - renderEditButton = (props) => { - props.label = `Edit title "${this.state.value}"` - return InPlaceEdit.renderDefaultEditButton(props) + // Renders the edit button. + // Leverage the default implementation provided by InPlaceEdit + renderEditButton = (props) => { + props.label = `Edit title "${this.state.value}"` + return InPlaceEdit.renderDefaultEditButton(props) + } + + render() { + return ( + + + + ) + } } + render() + ``` + +- ```js + const Example = (props) => { + const [mode, setMode] = useState(props.mode || 'view') + const [value, setValue] = useState('This is some text') + + // You must provide this to Editable to be + // notified of mode changes + const handleChangeMode = (mode) => { + setMode(mode) + } + + // You attach an event handler to your edit component + // to be notified of value changes from user interactions + const handleChange = (event) => { + setValue(event.target.value) + } + + // Renders the view component + // Be sure to give it the current value + const renderView = () => {value} + + // Renders the edit component. + // You have to forward the props on, which + // includes an onBlur property to help manage + // the mode changes. + // Be sure to give it the current value + const renderEdit = ({ onBlur, editorRef }) => ( + + ) + + // Renders the edit button. + // Leverage the default implementation provided by InPlaceEdit + const renderEditButton = (props) => { + props.label = `Edit title "${value}"` + return InPlaceEdit.renderDefaultEditButton(props) + } - render () { return ( ) } -} -render() -``` + + render() + ``` Same as the first example, but notifies `Editable`'s `onChange` when the user has finished editing and the value has changed. -```js ---- -type: example ---- -class Example extends React.Component { +- ```js + class Example extends React.Component { + constructor(props) { + super(props) + this.state = { + mode: props.mode || 'view', + value: 'Edit me', + onChangeValue: undefined + } + } - constructor (props) { - super(props) - this.state = { - mode: props.mode || 'view', - value: 'Edit me', - onChangeValue: undefined, + // typically provided by the application so it can + // be notified of value changes when the user is + // finished editing + onChange = (newValue) => { + this.setState({ onChangeValue: newValue }) } - } - // typically provided by the application so it can - // be notified of value changes when the user is - // finished editing - onChange = (newValue) => { - this.setState({onChangeValue: newValue}) - } + // You must provide this to Editable to be + // notified of mode changes + handleChangeMode = (mode) => { + this.setState({ mode }) + } + // You attach an event handler to your edit component + // to be notified of value changes from user interactions + handleChange = (event) => { + this.setState({ value: event.target.value }) + } - // You must provide this to Editable to be - // notified of mode changes - handleChangeMode = (mode) => { - this.setState({mode}) - } + // Renders the view component + // Be sure to give it the current value + renderView = () => {this.state.value} + + // Renders the edit component. + // You have to forward the props on, which + // includes an onBlur property to help manage + // the mode changes. + // Be sure to give it the current value + renderEdit = ({ onBlur, editorRef }) => ( + + ) - // You attach an event handler to your edit component - // to be notified of value changes from user interactions - handleChange = (event) => { - this.setState({value: event.target.value}) - } + // Renders the edit button. + // Leverage the default implementation provided by InPlaceEdit + renderEditButton = (props) => { + props.label = `Edit title "${this.state.value}"` + return InPlaceEdit.renderDefaultEditButton(props) + } - // Renders the view component - // Be sure to give it the current value - renderView = () => ( - - {this.state.value} - - ) - - // Renders the edit component. - // You have to forward the props on, which - // includes an onBlur property to help manage - // the mode changes. - // Be sure to give it the current value - renderEdit = ({onBlur, editorRef}) => ( - - ) - - // Renders the edit button. - // Leverage the default implementation provided by InPlaceEdit - renderEditButton = (props) => { - props.label = `Edit title "${this.state.value}"` - return InPlaceEdit.renderDefaultEditButton(props) + render() { + return ( + + +
+ + {this.state.onChangeValue !== undefined + ? `onChange said: ${this.state.onChangeValue}` + : `You haven't edited me yet!`} + +
+
+ ) + } } + render() + ``` + +- ```js + const Example = (props) => { + const [mode, setMode] = useState(props.mode || 'view') + const [value, setValue] = useState('Edit me') + const [onChangeValue, setOnChangeValue] = useState(undefined) + + // typically provided by the application so it can + // be notified of value changes when the user is + // finished editing + const onChange = (newValue) => { + setOnChangeValue(newValue) + } + + // You must provide this to Editable to be + // notified of mode changes + const handleChangeMode = (mode) => { + setMode(mode) + } + + // You attach an event handler to your edit component + // to be notified of value changes from user interactions + const handleChange = (event) => { + setValue(event.target.value) + } + + // Renders the view component + // Be sure to give it the current value + const renderView = () => {value} + + // Renders the edit component. + // You have to forward the props on, which + // includes an onBlur property to help manage + // the mode changes. + // Be sure to give it the current value + const renderEdit = ({ onBlur, editorRef }) => ( + + ) + + // Renders the edit button. + // Leverage the default implementation provided by InPlaceEdit + const renderEditButton = (props) => { + props.label = `Edit title "${value}"` + return InPlaceEdit.renderDefaultEditButton(props) + } - render () { return (
- {this.state.onChangeValue !== undefined - ? `onChange said: ${this.state.onChangeValue}` : `You haven't edited me yet!`} + {onChangeValue !== undefined + ? `onChange said: ${onChangeValue}` + : `You haven't edited me yet!`}
) } -} -render() -``` + + render() + ``` diff --git a/packages/ui-menu/src/Menu/README.md b/packages/ui-menu/src/Menu/README.md index bae004c42b..a12522b53b 100644 --- a/packages/ui-menu/src/Menu/README.md +++ b/packages/ui-menu/src/Menu/README.md @@ -16,89 +16,144 @@ the [Menu](#Menu) in a [Popover](#Popover). Note: `` cannot contain content that is not a `` (links or buttons). If you need to include more complex content, take a look at [Popover](#Popover). -```js ---- -type: example ---- -class Example extends React.Component { - constructor (props) { - super(props) +- ```js + class Example extends React.Component { + constructor(props) { + super(props) + + this.state = { + singleSelection: ['itemOne'], + multipleSelection: ['optionOne', 'optionThree'] + } + } + + handleSingleSelect = (e, newSelected) => { + this.setState({ + singleSelection: newSelected + }) + } - this.state = { - singleSelection: ['itemOne'], - multipleSelection: ['optionOne', 'optionThree'] + handleMultipleSelect = (e, newSelected) => { + this.setState({ + multipleSelection: newSelected + }) + } + + render() { + return ( + + Menu} + mountNode={() => document.getElementById('main')} + > + Learning Mastery + + Default (Grid view) + + Individual (List view) + + + Option 1 + Option 2 + Option 3 + + + Navigation + Set as default + + + + Item 1 + Item 2 + + + Open grading history... + + + ) } } - handleSingleSelect = (e, newSelected) => { - this.setState({ - singleSelection: newSelected - }) - }; + render() + ``` + +- ```js + const Example = () => { + const [singleSelection, setSingleSelection] = useState(['itemOne']) + const [multipleSelection, setMultipleSelection] = useState([ + 'optionOne', + 'optionThree' + ]) + + const handleSingleSelect = (e, newSelected) => { + setSingleSelection(newSelected) + } - handleMultipleSelect = (e, newSelected) => { - this.setState({ - multipleSelection: newSelected - }) - }; + const handleMultipleSelect = (e, newSelected) => { + setMultipleSelection(newSelected) + } - render () { return ( - - Menu - } - mountNode={() => document.getElementById('main')} - > - Learning Mastery - Default (Grid view) - Individual (List view) - + + Menu} + mountNode={() => document.getElementById('main')} + > + Learning Mastery + + Default (Grid view) + + Individual (List view) + + + Option 1 + Option 2 + Option 3 + + + Navigation + Set as default + + - - Option 1 - - - Option 2 - - - Option 3 - + Item 1 + Item 2 - Navigation - Set as default + Open grading history... - - - - Item 1 - - - Item 2 - - - - Open grading history... - - + ) } -} -render() -``` + render() + ``` ### Guidelines diff --git a/packages/ui-number-input/src/NumberInput/README.md b/packages/ui-number-input/src/NumberInput/README.md index 69b59b7283..28c4e382c8 100644 --- a/packages/ui-number-input/src/NumberInput/README.md +++ b/packages/ui-number-input/src/NumberInput/README.md @@ -10,137 +10,273 @@ This example handles arrow buttons, up/down arrow keys, and typing into the input. It also includes an `onBlur` handler that displays an error message if the input is invalid or missing. -```js ---- -type: example ---- -class Example extends React.Component { - MIN = 0 - MAX = 999 - - state = { - disabled: false, - inline: false, - messages: null, - number: null, - readOnly: false, - showArrows: true, - value: '' - } +- ```js + class Example extends React.Component { + MIN = 0 + MAX = 999 - handleChange = (event, value) => this.setState({ - messages: null, - number: value ? Number(value) : null, - value - }) - - handleDecrement = (event) => this.setState(({ number }) => { - if (isNaN(number)) return - if (number === null) return this.setNumber(this.MIN) - if (isInteger(number)) return this.setNumber(number - 1) - return this.setNumber(Math.floor(number)) - }) - - handleIncrement = (event) => this.setState(({ number }) => { - if (isNaN(number)) return - if (number === null) return this.setNumber(this.MIN + 1) - if (isInteger(number)) return this.setNumber(number + 1) - return this.setNumber(Math.ceil(number)) - }) - - handleBlur = (event) => this.setState(({ number, value }) => { - if (isNaN(number)) return this.invalidNumber(value) - if (number === null) return this.required() - return this.setNumber(Math.round(number)) - }) - - setNumber (n) { - const number = this.bound(n) - return { + state = { + disabled: false, + inline: false, messages: null, - number, - value: number + number: null, + readOnly: false, + showArrows: true, + value: '' } - } - bound (n) { - if (n < this.MIN) return this.MIN - if (n > this.MAX) return this.MAX - return n - } + handleChange = (event, value) => + this.setState({ + messages: null, + number: value ? Number(value) : null, + value + }) + + handleDecrement = (event) => + this.setState(({ number }) => { + if (isNaN(number)) return + if (number === null) return this.setNumber(this.MIN) + if (Number.isInteger(number)) return this.setNumber(number - 1) + return this.setNumber(Math.floor(number)) + }) + + handleIncrement = (event) => + this.setState(({ number }) => { + if (isNaN(number)) return + if (number === null) return this.setNumber(this.MIN + 1) + if (Number.isInteger(number)) return this.setNumber(number + 1) + return this.setNumber(Math.ceil(number)) + }) - invalidNumber (value) { - return { - messages: [{ text: `'${value}' is not a valid number.`, type: 'error' }] + handleBlur = (event) => + this.setState(({ number, value }) => { + if (isNaN(number)) return this.invalidNumber(value) + if (number === null) return this.required() + return this.setNumber(Math.round(number)) + }) + + setNumber(n) { + const number = this.bound(n) + return { + messages: null, + number, + value: number + } } - } - required () { - return { - messages: [{ text: 'This is required.', type: 'error' }] + bound(n) { + if (n < this.MIN) return this.MIN + if (n > this.MAX) return this.MAX + return n + } + + invalidNumber(value) { + return { + messages: [{ text: `'${value}' is not a valid number.`, type: 'error' }] + } + } + + required() { + return { + messages: [{ text: 'This is required.', type: 'error' }] + } + } + + toggleDisabled = (event) => + this.setState(({ disabled }) => ({ disabled: !disabled })) + + toggleInline = (event) => + this.setState(({ inline }) => ({ inline: !inline })) + + toggleReadOnly = (event) => + this.setState(({ readOnly }) => ({ readOnly: !readOnly })) + + toggleShowArrows = (event) => + this.setState(({ showArrows }) => ({ showArrows: !showArrows })) + + render() { + return ( + + + + + + + + ) } } - toggleDisabled = (event) => this.setState(({ disabled }) => ({ disabled: !disabled })) + render() + ``` + +- ```js + const Example = () => { + const MIN = 0 + const MAX = 999 + + const [disabled, setDisabled] = useState(false) + const [inline, setInline] = useState(false) + const [messages, setMessages] = useState(null) + const [number, setNumber] = useState(null) + const [readOnly, setReadOnly] = useState(false) + const [showArrows, setShowArrows] = useState(true) + const [value, setValue] = useState('') - toggleInline = (event) => this.setState(({ inline }) => ({ inline: !inline })) + const handleChange = (event, value) => { + setMessages(null) + setNumber(value ? Number(value) : null) + setValue(value) + } + + const handleDecrement = (event) => { + if (!isNaN(number)) { + const newNumber = + number === null + ? MIN + : Number.isInteger(number) + ? number - 1 + : Math.floor(number) + updateNumber(newNumber) + } + } + + const handleIncrement = (event) => { + if (!isNaN(number)) { + const newNumber = + number === null + ? MIN + 1 + : Number.isInteger(number) + ? number + 1 + : Math.ceil(number) + updateNumber(newNumber) + } + } + + const handleBlur = (event) => { + if (isNaN(number)) return invalidNumber(value) + if (number === null) return required() + return updateNumber(Math.round(number)) + } + + const updateNumber = (n) => { + const number = bound(n) + setMessages(null) + setNumber(number) + setValue(number) + } - toggleReadOnly = (event) => this.setState(({ readOnly }) => ({ readOnly: !readOnly })) + const bound = (n) => { + if (n < MIN) return MIN + if (n > MAX) return MAX + return n + } - toggleShowArrows = (event) => this.setState(({ showArrows }) => ({ showArrows: !showArrows })) + const invalidNumber = (value) => { + setMessages([ + { text: `'${value}' is not a valid number.`, type: 'error' } + ]) + } + + const required = () => { + setMessages([{ text: 'This is required.', type: 'error' }]) + } + + const toggleDisabled = (event) => { + setDisabled((prevDisabled) => !prevDisabled) + } + + const toggleInline = (event) => { + setInline((prevInline) => !prevInline) + } + + const toggleReadOnly = (event) => { + setReadOnly((prevReadOnly) => !prevReadOnly) + } + + const toggleShowArrows = (event) => { + setShowArrows((prevShowArrows) => !prevShowArrows) + } - render () { return ( ) } -} -// IE11 doesn't support Number.isInteger -function isInteger (number) { - return Math.floor(number) === number -} - -render() -``` + render() + ``` > Note: `NumberInput` accepts a string or number as its `value`. However, the value returned by the `onChange` callback is always a string and should be converted to a number before attempting to augment it.