From 0c18eb18a4ea2f9fe2ca31a66d24abf367561902 Mon Sep 17 00:00:00 2001 From: Gustavo Fonseca Date: Thu, 19 Oct 2023 18:20:27 -0300 Subject: [PATCH 1/8] chore: object control - make the add and remove buttons accessible --- .../docs/src/blocks/controls/Object.tsx | 82 ++++++++++--------- .../react-editable-json-tree/JsonNodes.tsx | 45 ++++++---- 2 files changed, 72 insertions(+), 55 deletions(-) diff --git a/code/addons/docs/src/blocks/controls/Object.tsx b/code/addons/docs/src/blocks/controls/Object.tsx index 26194fa048d7..fa6d509ab79b 100644 --- a/code/addons/docs/src/blocks/controls/Object.tsx +++ b/code/addons/docs/src/blocks/controls/Object.tsx @@ -28,16 +28,9 @@ const Wrapper = styled.div(({ theme }) => ({ marginLeft: '1rem', fontSize: '13px', }, - '.rejt-value-node, .rejt-object-node > .rejt-collapsed, .rejt-array-node > .rejt-collapsed, .rejt-object-node > .rejt-not-collapsed, .rejt-array-node > .rejt-not-collapsed': - { - '& > svg': { - opacity: 0, - transition: 'opacity 0.2s', - }, - }, '.rejt-value-node:hover, .rejt-object-node:hover > .rejt-collapsed, .rejt-array-node:hover > .rejt-collapsed, .rejt-object-node:hover > .rejt-not-collapsed, .rejt-array-node:hover > .rejt-not-collapsed': { - '& > svg': { + '.rejt-plus-menu, .rejt-minus-menu': { opacity: 1, }, }, @@ -57,13 +50,6 @@ const Wrapper = styled.div(({ theme }) => ({ '.rejt-not-collapsed-delimiter': { lineHeight: '22px', }, - '.rejt-plus-menu': { - marginLeft: 5, - }, - '.rejt-object-node > span > *, .rejt-array-node > span > *': { - position: 'relative', - zIndex: 2, - }, '.rejt-object-node, .rejt-array-node': { position: 'relative', }, @@ -140,33 +126,35 @@ const ButtonInline = styled.button<{ primary?: boolean }>(({ theme, primary }) = order: primary ? 'initial' : 9, })); -const ActionAddIcon = styled(AddIcon)<{ disabled?: boolean }>(({ theme, disabled }) => ({ - display: 'inline-block', +const ActionButton = styled.button(({ theme }) => ({ + background: 'none', + border: 0, + display: 'inline-flex', verticalAlign: 'middle', - width: 15, - height: 15, padding: 3, marginLeft: 5, - cursor: disabled ? 'not-allowed' : 'pointer', color: theme.textMutedColor, - '&:hover': disabled ? {} : { color: theme.color.ancillary }, - 'svg + &': { - marginLeft: 0, + opacity: 0, + transition: 'opacity 0.2s', + cursor: 'pointer', + position: 'relative', + svg: { + width: 9, + height: 9, }, -})); - -const ActionSubstractIcon = styled(SubtractIcon)<{ disabled?: boolean }>(({ theme, disabled }) => ({ - display: 'inline-block', - verticalAlign: 'middle', - width: 15, - height: 15, - padding: 3, - marginLeft: 5, - cursor: disabled ? 'not-allowed' : 'pointer', - color: theme.textMutedColor, - '&:hover': disabled ? {} : { color: theme.color.negative }, - 'svg + &': { - marginLeft: 0, + ':disabled': { + cursor: 'not-allowed', + }, + ':focus-visible': { + opacity: 1, + }, + '&:hover:not(:disabled), &:focus-visible:not(:disabled)': { + '&.rejt-plus-menu': { + color: theme.color.ancillary, + }, + '&.rejt-minus-menu': { + color: theme.color.negative, + }, }, })); @@ -220,7 +208,13 @@ const RawInput = styled(Form.Textarea)(({ theme }) => ({ }, })); -const ENTER_EVENT = { bubbles: true, cancelable: true, key: 'Enter', code: 'Enter', keyCode: 13 }; +const ENTER_EVENT = { + bubbles: true, + cancelable: true, + key: 'Enter', + code: 'Enter', + keyCode: 13, +}; const dispatchEnterKey = (event: SyntheticEvent) => { event.currentTarget.dispatchEvent(new globalWindow.KeyboardEvent('keydown', ENTER_EVENT)); }; @@ -335,8 +329,16 @@ export const ObjectControl: FC = ({ name, value, onChange, argType Save } - plusMenuElement={} - minusMenuElement={} + plusMenuElement={ + + + + } + minusMenuElement={ + + + + } inputElement={(_: any, __: any, ___: any, key: string) => key ? : } diff --git a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx index 58efa33928d5..44cb05fa3f0a 100644 --- a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx +++ b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx @@ -324,13 +324,12 @@ export class JsonArray extends Component { const isReadOnly = readOnly(name, data, keyPath, deep, dataType); - const removeItemButton = - minusMenuElement && - cloneElement(minusMenuElement, { - onClick: handleRemove, - className: 'rejt-minus-menu', - style: minus, - }); + const removeItemButton = minusMenuElement && cloneElement(minusMenuElement, { + onClick: handleRemove, + className: 'rejt-minus-menu', + style: minus, + 'aria-label': `remove the array '${name}'`, + }); return ( @@ -368,19 +367,21 @@ export class JsonArray extends Component { const isReadOnly = readOnly(name, data, keyPath, deep, dataType); - const addItemButton = + const addItemButton = plusMenuElement && cloneElement(plusMenuElement, { onClick: this.handleAddMode, className: 'rejt-plus-menu', style: plus, + 'aria-label': `add a new item to the '${name}' array`, }); - const removeItemButton = + const removeItemButton = minusMenuElement && cloneElement(minusMenuElement, { onClick: handleRemove, className: 'rejt-minus-menu', style: minus, + 'aria-label': `remove the array '${name}'`, }); const onlyValue = true; @@ -669,12 +670,18 @@ export class JsonFunctionValue extends Component ); - const minusMenuLayout = + + const parentPropertyName = comeFromKeyPath.at(-1); + + const minusMenuLayout = minusMenuElement && cloneElement(minusMenuElement, { onClick: handleRemove, className: 'rejt-minus-menu', style: style.minus, + 'aria-label': `remove the function '${name}'${ + parentPropertyName ? ` from '${parentPropertyName}'` : '' + }`, }); minusElement = resultOnlyResult ? null : minusMenuLayout; } @@ -1233,12 +1240,13 @@ export class JsonObject extends Component { const isReadOnly = readOnly(name, data, keyPath, deep, dataType); - const removeItemButton = + const removeItemButton = minusMenuElement && cloneElement(minusMenuElement, { onClick: handleRemove, className: 'rejt-minus-menu', style: minus, + 'aria-label': `remove the object '${name}'`, }); return ( @@ -1279,12 +1287,13 @@ export class JsonObject extends Component { const isReadOnly = readOnly(name, data, keyPath, deep, dataType); - const addItemButton = + const addItemButton = plusMenuElement && cloneElement(plusMenuElement, { onClick: this.handleAddMode, className: 'rejt-plus-menu', style: plus, + 'aria-label': `add a new property to the object '${name}'`, }); const removeItemButton = minusMenuElement && @@ -1292,6 +1301,7 @@ export class JsonObject extends Component { onClick: handleRemove, className: 'rejt-minus-menu', style: minus, + 'aria-label': `remove the object '${name}'`, }); const list = keyList.map((key) => ( @@ -1560,12 +1570,17 @@ export class JsonValue extends Component { ref: this.refInput, defaultValue: JSON.stringify(originalValue), }); - const minusMenuLayout = - minusMenuElement && - cloneElement(minusMenuElement, { + + const parentPropertyName = keyPath.at(-2); + + const minusMenuLayout = + minusMenuElement && cloneElement(minusMenuElement, { onClick: handleRemove, className: 'rejt-minus-menu', style: style.minus, + 'aria-label': `remove the property '${name}' with value '${originalValue}'${ + parentPropertyName ? ` from '${parentPropertyName}'` : '' + }`, }); return ( From 07189a06e7b1d17d817d007f0252ecb8890f4a52 Mon Sep 17 00:00:00 2001 From: Gustavo Fonseca Date: Thu, 19 Oct 2023 18:23:44 -0300 Subject: [PATCH 2/8] chore: object control - remove the onkeydown event listener from the entire document and pass it to the fields --- .../react-editable-json-tree/JsonNodes.tsx | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx index 44cb05fa3f0a..76186aa34d14 100644 --- a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx +++ b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx @@ -37,12 +37,6 @@ export class JsonAddValue extends Component { } } - componentDidMount() { - document.addEventListener('keydown', this.onKeydown); - } - - componentWillUnmount() { - document.removeEventListener('keydown', this.onKeydown); - } - onKeydown(event: KeyboardEvent) { if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || event.repeat) { return; } if (event.code === 'Enter' || event.key === 'Enter') { event.preventDefault(); + this.handleEdit(); } + if (event.code === 'Escape' || event.key === 'Escape') { event.preventDefault(); + this.handleCancelEdit(); } } @@ -1569,6 +1563,7 @@ export class JsonValue extends Component { const inputElementLayout = cloneElement(inputElement, { ref: this.refInput, defaultValue: JSON.stringify(originalValue), + onKeyDown: this.onKeydown, }); const parentPropertyName = keyPath.at(-2); From 9979ac1e577bd1030bfa4245c034daa4f6240f58 Mon Sep 17 00:00:00 2001 From: Gustavo Fonseca Date: Mon, 23 Oct 2023 18:35:51 -0300 Subject: [PATCH 3/8] chore: object control - make the accordion accessible --- .../docs/src/blocks/controls/Object.tsx | 61 +--------- .../JsonNodeAccordion.tsx | 110 ++++++++++++++++++ .../react-editable-json-tree/JsonNodes.tsx | 61 +++++----- 3 files changed, 146 insertions(+), 86 deletions(-) create mode 100644 code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodeAccordion.tsx diff --git a/code/addons/docs/src/blocks/controls/Object.tsx b/code/addons/docs/src/blocks/controls/Object.tsx index fa6d509ab79b..de65f7bccadc 100644 --- a/code/addons/docs/src/blocks/controls/Object.tsx +++ b/code/addons/docs/src/blocks/controls/Object.tsx @@ -27,13 +27,13 @@ const Wrapper = styled.div(({ theme }) => ({ '.rejt-tree': { marginLeft: '1rem', fontSize: '13px', + listStyleType: 'none', }, - '.rejt-value-node:hover, .rejt-object-node:hover > .rejt-collapsed, .rejt-array-node:hover > .rejt-collapsed, .rejt-object-node:hover > .rejt-not-collapsed, .rejt-array-node:hover > .rejt-not-collapsed': - { - '.rejt-plus-menu, .rejt-minus-menu': { - opacity: 1, - }, + '.rejt-value-node:hover': { + '& > button': { + opacity: 1, }, + }, '.rejt-edit-form button': { display: 'none', }, @@ -50,55 +50,6 @@ const Wrapper = styled.div(({ theme }) => ({ '.rejt-not-collapsed-delimiter': { lineHeight: '22px', }, - '.rejt-object-node, .rejt-array-node': { - position: 'relative', - }, - '.rejt-object-node > span:first-of-type::after, .rejt-array-node > span:first-of-type::after, .rejt-collapsed::before, .rejt-not-collapsed::before': - { - content: '""', - position: 'absolute', - top: 0, - display: 'block', - width: '100%', - marginLeft: '-1rem', - padding: '0 4px 0 1rem', - height: 22, - }, - '.rejt-collapsed::before, .rejt-not-collapsed::before': { - zIndex: 1, - background: 'transparent', - borderRadius: 4, - transition: 'background 0.2s', - pointerEvents: 'none', - opacity: 0.1, - }, - '.rejt-object-node:hover, .rejt-array-node:hover': { - '& > .rejt-collapsed::before, & > .rejt-not-collapsed::before': { - background: theme.color.secondary, - }, - }, - '.rejt-collapsed::after, .rejt-not-collapsed::after': { - content: '""', - position: 'absolute', - display: 'inline-block', - pointerEvents: 'none', - width: 0, - height: 0, - }, - '.rejt-collapsed::after': { - left: -8, - top: 8, - borderTop: '3px solid transparent', - borderBottom: '3px solid transparent', - borderLeft: '3px solid rgba(153,153,153,0.6)', - }, - '.rejt-not-collapsed::after': { - left: -10, - top: 10, - borderTop: '3px solid rgba(153,153,153,0.6)', - borderLeft: '3px solid transparent', - borderRight: '3px solid transparent', - }, '.rejt-value': { display: 'inline-block', border: '1px solid transparent', @@ -145,7 +96,7 @@ const ActionButton = styled.button(({ theme }) => ({ ':disabled': { cursor: 'not-allowed', }, - ':focus-visible': { + ':hover, :focus-visible': { opacity: 1, }, '&:hover:not(:disabled), &:focus-visible:not(:disabled)': { diff --git a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodeAccordion.tsx b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodeAccordion.tsx new file mode 100644 index 000000000000..a0fb8e6b107c --- /dev/null +++ b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodeAccordion.tsx @@ -0,0 +1,110 @@ +import { styled } from '@storybook/theming'; +import type { ComponentPropsWithoutRef } from 'react'; +import React from 'react'; + +const Container = styled.div(({ theme }) => ({ + position: 'relative', + ':hover': { + '& > .rejt-accordion-button::after': { + background: theme.color.secondary, + }, + '& > .rejt-accordion-region > :is(.rejt-plus-menu, .rejt-minus-menu)': { + opacity: 1, + }, + }, +})); + +const Trigger = styled.button(({ theme }) => ({ + padding: 0, + background: 'transparent', + border: 'none', + marginRight: '3px', + lineHeight: '22px', + color: theme.color.secondary, + '::after': { + content: '""', + position: 'absolute', + top: 0, + display: 'block', + width: '100%', + marginLeft: '-1rem', + height: '22px', + background: 'transparent', + borderRadius: 4, + transition: 'background 0.2s', + opacity: 0.1, + paddingRight: '20px', + }, + '::before': { + content: '""', + position: 'absolute', + }, + '&[aria-expanded="true"]::before': { + left: -10, + top: 10, + borderTop: '3px solid rgba(153,153,153,0.6)', + borderLeft: '3px solid transparent', + borderRight: '3px solid transparent', + }, + '&[aria-expanded="false"]::before': { + left: -8, + top: 8, + borderTop: '3px solid transparent', + borderBottom: '3px solid transparent', + borderLeft: '3px solid rgba(153,153,153,0.6)', + }, +})); + +const Region = styled.div({ + display: 'inline', +}); + +type AccordionProps = { + name: string; + keyPath: string[]; + collapsed: boolean; + deep: number; +} & ComponentPropsWithoutRef<'button'>; + +export function JsonNodeAccordion({ + children, + name, + collapsed, + keyPath, + deep, + ...props +}: AccordionProps) { + const parentPropertyName = keyPath.at(-1) ?? 'root'; + + const accordionKey = `${parentPropertyName}-${name}-${deep}`; + + const ids = { + trigger: `${accordionKey}-trigger`, + region: `${accordionKey}-region`, + }; + + const containerTag = keyPath.length > 0 ? 'li' : 'div'; + + return ( + + + {name} : + + + {children} + + + ); +} diff --git a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx index 76186aa34d14..8005847c73ba 100644 --- a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx +++ b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx @@ -6,6 +6,7 @@ import * as dataTypes from './types/dataTypes'; import * as deltaTypes from './types/deltaTypes'; import * as inputUsageTypes from './types/inputUsageTypes'; import { getObjectType, isComponentWillChange } from './utils/objectTypes'; +import { JsonNodeAccordion } from './JsonNodeAccordion'; interface JsonAddValueState { inputRefKey: any; @@ -333,12 +334,12 @@ export class JsonArray extends Component { }); return ( - - + <> + [...] {data.length} {data.length === 1 ? 'item' : 'items'} {!isReadOnly && removeItemButton} - + ); } @@ -389,7 +390,7 @@ export class JsonArray extends Component { const startObject = '['; const endObject = ']'; return ( - + <> {startObject} @@ -443,25 +444,24 @@ export class JsonArray extends Component { {endObject} {!isReadOnly && removeItemButton} - + ); } render() { - const { name, collapsed, data, keyPath, deep } = this.state; - const { dataType, getStyle } = this.props; + const { name, collapsed, keyPath, deep } = this.state; const value = collapsed ? this.renderCollapsed() : this.renderNotCollapsed(); - const style = getStyle(name, data, keyPath, deep, dataType); return ( -
- - - {name} :{' '} - - + {value} -
+ ); } } @@ -686,7 +686,7 @@ export class JsonFunctionValue extends Component +
  • {name} :{' '} @@ -1249,12 +1249,12 @@ export class JsonObject extends Component { }); return ( - - + <> + {'{...}'} {keyList.length} {keyList.length === 1 ? 'key' : 'keys'} {!isReadOnly && removeItemButton} - + ); } @@ -1336,7 +1336,7 @@ export class JsonObject extends Component { const endObject = '}'; return ( - + <> {startObject} @@ -1362,25 +1362,24 @@ export class JsonObject extends Component { {endObject} {!isReadOnly && removeItemButton} - + ); } render() { - const { name, collapsed, data, keyPath, deep } = this.state; - const { getStyle, dataType } = this.props; + const { name, collapsed, keyPath, deep } = this.state; const value = collapsed ? this.renderCollapsed() : this.renderNotCollapsed(); - const style = getStyle(name, data, keyPath, deep, dataType); return ( -
    - - - {name} :{' '} - - + {value} -
    + ); } } From 9a625f8ec532a6bf12bb5a195be3764e952f7d1d Mon Sep 17 00:00:00 2001 From: Gustavo Fonseca Date: Tue, 24 Oct 2023 18:59:28 -0300 Subject: [PATCH 4/8] chore: object control - improve the accessibility of the raw button --- code/addons/docs/src/blocks/controls/Object.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/addons/docs/src/blocks/controls/Object.tsx b/code/addons/docs/src/blocks/controls/Object.tsx index de65f7bccadc..0e7957c5ec45 100644 --- a/code/addons/docs/src/blocks/controls/Object.tsx +++ b/code/addons/docs/src/blocks/controls/Object.tsx @@ -256,9 +256,12 @@ export const ObjectControl: FC = ({ name, value, onChange, argType {isObjectOrArray && ( { e.preventDefault(); - setShowRaw((v) => !v); + setShowRaw((isRaw) => !isRaw); }} > {showRaw ? : } From e3df6c8179c74be6249caa800742984701f67591 Mon Sep 17 00:00:00 2001 From: Gustavo Fonseca Date: Thu, 26 Oct 2023 19:08:19 -0300 Subject: [PATCH 5/8] chore: object control - adjust the tab order of the form buttons --- code/addons/docs/src/blocks/controls/Object.tsx | 1 - .../blocks/controls/react-editable-json-tree/JsonNodes.tsx | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/code/addons/docs/src/blocks/controls/Object.tsx b/code/addons/docs/src/blocks/controls/Object.tsx index 0e7957c5ec45..c9163ff3c2d1 100644 --- a/code/addons/docs/src/blocks/controls/Object.tsx +++ b/code/addons/docs/src/blocks/controls/Object.tsx @@ -74,7 +74,6 @@ const ButtonInline = styled.button<{ primary?: boolean }>(({ theme, primary }) = color: primary ? theme.color.lightest : theme.color.dark, fontWeight: primary ? 'bold' : 'normal', cursor: 'pointer', - order: primary ? 'initial' : 9, })); const ActionButton = styled.button(({ theme }) => ({ diff --git a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx index 8005847c73ba..5d804a6fb612 100644 --- a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx +++ b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx @@ -128,8 +128,8 @@ export class JsonAddValue extends Component {inputElementKeyLayout} {inputElementValueLayout} - {cancelButtonElementLayout} {addButtonElementLayout} + {cancelButtonElementLayout} ); } @@ -1585,8 +1585,8 @@ export class JsonValue extends Component { {isEditing ? ( - {inputElementLayout} {cancelButtonElementLayout} - {editButtonElementLayout} + {inputElementLayout} {editButtonElementLayout} + {cancelButtonElementLayout} ) : ( Date: Wed, 15 May 2024 15:58:08 -0300 Subject: [PATCH 6/8] chore: object control - remove the edit button that was already hidden with css --- .../docs/src/blocks/controls/Object.tsx | 4 -- .../react-editable-json-tree/JsonNodes.tsx | 53 +------------------ .../react-editable-json-tree/index.tsx | 3 -- 3 files changed, 2 insertions(+), 58 deletions(-) diff --git a/code/addons/docs/src/blocks/controls/Object.tsx b/code/addons/docs/src/blocks/controls/Object.tsx index c9163ff3c2d1..27f82b34815c 100644 --- a/code/addons/docs/src/blocks/controls/Object.tsx +++ b/code/addons/docs/src/blocks/controls/Object.tsx @@ -34,9 +34,6 @@ const Wrapper = styled.div(({ theme }) => ({ opacity: 1, }, }, - '.rejt-edit-form button': { - display: 'none', - }, '.rejt-add-form': { marginLeft: 10, }, @@ -276,7 +273,6 @@ export const ObjectControl: FC = ({ name, value, onChange, argType onFullyUpdate={onChange} getStyle={getCustomStyleFunction(theme)} cancelButtonElement={Cancel} - editButtonElement={Save} addButtonElement={ Save diff --git a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx index 5d804a6fb612..cd4f9f2aaf7b 100644 --- a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx +++ b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx @@ -354,7 +354,6 @@ export class JsonArray extends Component { dataType, addButtonElement, cancelButtonElement, - editButtonElement, inputElementGenerator, textareaElementGenerator, minusMenuElement, @@ -412,7 +411,6 @@ export class JsonArray extends Component { getStyle={getStyle} addButtonElement={addButtonElement} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} inputElementGenerator={inputElementGenerator} textareaElementGenerator={textareaElementGenerator} minusMenuElement={minusMenuElement} @@ -480,7 +478,6 @@ interface JsonArrayProps { getStyle: (...args: any) => any; addButtonElement?: ReactElement; cancelButtonElement?: ReactElement; - editButtonElement?: ReactElement; inputElementGenerator: (...args: any) => any; textareaElementGenerator: (...args: any) => any; minusMenuElement?: ReactElement; @@ -614,8 +611,6 @@ export class JsonFunctionValue extends Component - {textareaElementLayout} {cancelButtonElementLayout} - {editButtonElementLayout} + {textareaElementLayout} ); minusElement = null; @@ -708,7 +692,6 @@ interface JsonFunctionValueProps { readOnly: (...args: any) => any; dataType?: string; getStyle: (...args: any) => any; - editButtonElement?: ReactElement; cancelButtonElement?: ReactElement; textareaElementGenerator: (...args: any) => any; minusMenuElement?: ReactElement; @@ -721,7 +704,6 @@ JsonFunctionValue.defaultProps = { keyPath: [], deep: 0, handleUpdateValue: () => {}, - editButtonElement: , cancelButtonElement: , minusMenuElement: - , }; @@ -760,7 +742,6 @@ export class JsonNode extends Component { getStyle, addButtonElement, cancelButtonElement, - editButtonElement, inputElementGenerator, textareaElementGenerator, minusMenuElement, @@ -791,7 +772,6 @@ export class JsonNode extends Component { getStyle={getStyle} addButtonElement={addButtonElement} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} inputElementGenerator={inputElementGenerator} textareaElementGenerator={textareaElementGenerator} minusMenuElement={minusMenuElement} @@ -819,7 +799,6 @@ export class JsonNode extends Component { getStyle={getStyle} addButtonElement={addButtonElement} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} inputElementGenerator={inputElementGenerator} textareaElementGenerator={textareaElementGenerator} minusMenuElement={minusMenuElement} @@ -847,7 +826,6 @@ export class JsonNode extends Component { getStyle={getStyle} addButtonElement={addButtonElement} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} inputElementGenerator={inputElementGenerator} textareaElementGenerator={textareaElementGenerator} minusMenuElement={minusMenuElement} @@ -873,7 +851,6 @@ export class JsonNode extends Component { dataType={dataType} getStyle={getStyle} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} inputElementGenerator={inputElementGenerator} minusMenuElement={minusMenuElement} logger={logger} @@ -894,7 +871,6 @@ export class JsonNode extends Component { dataType={dataType} getStyle={getStyle} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} inputElementGenerator={inputElementGenerator} minusMenuElement={minusMenuElement} logger={logger} @@ -915,7 +891,6 @@ export class JsonNode extends Component { dataType={dataType} getStyle={getStyle} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} inputElementGenerator={inputElementGenerator} minusMenuElement={minusMenuElement} logger={logger} @@ -936,7 +911,6 @@ export class JsonNode extends Component { dataType={dataType} getStyle={getStyle} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} inputElementGenerator={inputElementGenerator} minusMenuElement={minusMenuElement} logger={logger} @@ -957,7 +931,6 @@ export class JsonNode extends Component { dataType={dataType} getStyle={getStyle} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} inputElementGenerator={inputElementGenerator} minusMenuElement={minusMenuElement} logger={logger} @@ -978,7 +951,6 @@ export class JsonNode extends Component { dataType={dataType} getStyle={getStyle} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} inputElementGenerator={inputElementGenerator} minusMenuElement={minusMenuElement} logger={logger} @@ -999,7 +971,6 @@ export class JsonNode extends Component { dataType={dataType} getStyle={getStyle} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} textareaElementGenerator={textareaElementGenerator} minusMenuElement={minusMenuElement} logger={logger} @@ -1020,7 +991,6 @@ export class JsonNode extends Component { dataType={dataType} getStyle={getStyle} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} inputElementGenerator={inputElementGenerator} minusMenuElement={minusMenuElement} logger={logger} @@ -1047,7 +1017,6 @@ interface JsonNodeProps { getStyle: (...args: any) => any; addButtonElement?: ReactElement; cancelButtonElement?: ReactElement; - editButtonElement?: ReactElement; inputElementGenerator: (...args: any) => any; textareaElementGenerator: (...args: any) => any; minusMenuElement?: ReactElement; @@ -1269,7 +1238,6 @@ export class JsonObject extends Component { dataType, addButtonElement, cancelButtonElement, - editButtonElement, inputElementGenerator, textareaElementGenerator, minusMenuElement, @@ -1319,7 +1287,6 @@ export class JsonObject extends Component { getStyle={getStyle} addButtonElement={addButtonElement} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} inputElementGenerator={inputElementGenerator} textareaElementGenerator={textareaElementGenerator} minusMenuElement={minusMenuElement} @@ -1398,7 +1365,6 @@ interface JsonObjectProps { getStyle: (...args: any) => any; addButtonElement?: ReactElement; cancelButtonElement?: ReactElement; - editButtonElement?: ReactElement; inputElementGenerator: (...args: any) => any; textareaElementGenerator: (...args: any) => any; minusMenuElement?: ReactElement; @@ -1530,8 +1496,6 @@ export class JsonValue extends Component { readOnly, dataType, getStyle, - editButtonElement, - cancelButtonElement, inputElementGenerator, minusMenuElement, keyPath: comeFromKeyPath, @@ -1549,16 +1513,6 @@ export class JsonValue extends Component { dataType ); - const editButtonElementLayout = - editButtonElement && - cloneElement(editButtonElement, { - onClick: this.handleEdit, - }); - const cancelButtonElementLayout = - cancelButtonElement && - cloneElement(cancelButtonElement, { - onClick: this.handleCancelEdit, - }); const inputElementLayout = cloneElement(inputElement, { ref: this.refInput, defaultValue: JSON.stringify(originalValue), @@ -1585,8 +1539,7 @@ export class JsonValue extends Component { {isEditing ? ( - {inputElementLayout} {editButtonElementLayout} - {cancelButtonElementLayout} + {inputElementLayout} ) : ( any; dataType?: string; getStyle: (...args: any) => any; - editButtonElement?: ReactElement; cancelButtonElement?: ReactElement; inputElementGenerator: (...args: any) => any; minusMenuElement?: ReactElement; @@ -1627,7 +1579,6 @@ JsonValue.defaultProps = { keyPath: [], deep: 0, handleUpdateValue: () => Promise.resolve(), - editButtonElement: , cancelButtonElement: , minusMenuElement: - , }; diff --git a/code/addons/docs/src/blocks/controls/react-editable-json-tree/index.tsx b/code/addons/docs/src/blocks/controls/react-editable-json-tree/index.tsx index b5c840b0639a..465d8da87c8e 100644 --- a/code/addons/docs/src/blocks/controls/react-editable-json-tree/index.tsx +++ b/code/addons/docs/src/blocks/controls/react-editable-json-tree/index.tsx @@ -53,7 +53,6 @@ export class JsonTree extends Component { getStyle, addButtonElement, cancelButtonElement, - editButtonElement, inputElement, textareaElement, minusMenuElement, @@ -98,7 +97,6 @@ export class JsonTree extends Component { getStyle={getStyle ?? (() => ({}))} addButtonElement={addButtonElement} cancelButtonElement={cancelButtonElement} - editButtonElement={editButtonElement} inputElementGenerator={inputElementFunction as (...args: any) => any} textareaElementGenerator={textareaElementFunction as (...args: any) => any} minusMenuElement={minusMenuElement} @@ -128,7 +126,6 @@ interface JsonTreeProps { getStyle?: (...args: any) => any; addButtonElement?: ReactElement; cancelButtonElement?: ReactElement; - editButtonElement?: ReactElement; inputElement?: ReactElement | ((...args: any) => ReactElement); textareaElement?: ReactElement | ((...args: any) => ReactElement); minusMenuElement?: ReactElement; From 5eac3052448dc98b11a358df755388270eaae653 Mon Sep 17 00:00:00 2001 From: Steve Dodier-Lazaro Date: Wed, 28 May 2025 09:11:01 +0200 Subject: [PATCH 7/8] Docs: Port JsonNodeAccordion changes to Storybook 9 imports --- .../controls/react-editable-json-tree/JsonNodeAccordion.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodeAccordion.tsx b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodeAccordion.tsx index a0fb8e6b107c..75da2a484b41 100644 --- a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodeAccordion.tsx +++ b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodeAccordion.tsx @@ -1,7 +1,8 @@ -import { styled } from '@storybook/theming'; import type { ComponentPropsWithoutRef } from 'react'; import React from 'react'; +import { styled } from 'storybook/theming'; + const Container = styled.div(({ theme }) => ({ position: 'relative', ':hover': { From b82f413e50b3770e3dbb12f517b72b5e309549e5 Mon Sep 17 00:00:00 2001 From: Steve Dodier-Lazaro Date: Mon, 23 Jun 2025 11:22:45 +0200 Subject: [PATCH 8/8] Lint files and fix type inconsistencies --- .../react-editable-json-tree/JsonNodes.tsx | 71 ++++++++++--------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx index cd4f9f2aaf7b..9933b5c3edb3 100644 --- a/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx +++ b/code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx @@ -2,11 +2,11 @@ import type { ReactElement } from 'react'; import React, { Component, cloneElement } from 'react'; +import { JsonNodeAccordion } from './JsonNodeAccordion'; import * as dataTypes from './types/dataTypes'; import * as deltaTypes from './types/deltaTypes'; import * as inputUsageTypes from './types/inputUsageTypes'; import { getObjectType, isComponentWillChange } from './utils/objectTypes'; -import { JsonNodeAccordion } from './JsonNodeAccordion'; interface JsonAddValueState { inputRefKey: any; @@ -157,8 +157,8 @@ JsonAddValue.defaultProps = { interface JsonArrayState { data: JsonArrayProps['data']; name: JsonArrayProps['name']; - keyPath: string[]; - deep: JsonArrayProps['deep']; + keyPath: Exclude; + deep: Exclude; nextDeep: JsonArrayProps['deep']; collapsed: any; addFormVisible: boolean; @@ -170,7 +170,7 @@ export class JsonArray extends Component { this.state = { data: props.data, name: props.name, - keyPath, + keyPath: keyPath ?? [], deep: props.deep ?? 0, nextDeep: (props.deep ?? 0) + 1, collapsed: props.isCollapsed(keyPath, props.deep ?? 0, props.data), @@ -326,12 +326,14 @@ export class JsonArray extends Component { const isReadOnly = readOnly(name, data, keyPath, deep, dataType); - const removeItemButton = minusMenuElement && cloneElement(minusMenuElement, { - onClick: handleRemove, - className: 'rejt-minus-menu', - style: minus, - 'aria-label': `remove the array '${name}'`, - }); + const removeItemButton = + minusMenuElement && + cloneElement(minusMenuElement, { + onClick: handleRemove, + className: 'rejt-minus-menu', + style: minus, + 'aria-label': `remove the array '${name}'`, + }); return ( <> @@ -368,7 +370,7 @@ export class JsonArray extends Component { const isReadOnly = readOnly(name, data, keyPath, deep, dataType); - const addItemButton = + const addItemButton = plusMenuElement && cloneElement(plusMenuElement, { onClick: this.handleAddMode, @@ -376,7 +378,7 @@ export class JsonArray extends Component { style: plus, 'aria-label': `add a new item to the '${name}' array`, }); - const removeItemButton = + const removeItemButton = minusMenuElement && cloneElement(minusMenuElement, { onClick: handleRemove, @@ -500,8 +502,8 @@ JsonArray.defaultProps = { interface JsonFunctionValueState { value: JsonFunctionValueProps['value']; name: JsonFunctionValueProps['name']; - keyPath: string[]; - deep: JsonFunctionValueProps['deep']; + keyPath: Exclude; + deep: Exclude; editEnabled: boolean; inputRef: any; } @@ -513,8 +515,8 @@ export class JsonFunctionValue extends Component; + deep: Exclude; } export class JsonNode extends Component { @@ -721,8 +723,8 @@ export class JsonNode extends Component { this.state = { data: props.data, name: props.name, - keyPath: props.keyPath, - deep: props.deep, + keyPath: props.keyPath ?? [], + deep: props.deep ?? 0, }; } @@ -1038,8 +1040,8 @@ interface JsonObjectState { name: string; collapsed: ReturnType; data: JsonObjectProps['data']; - keyPath: JsonObjectProps['keyPath']; - deep: JsonObjectProps['deep']; + keyPath: Exclude; + deep: Exclude; nextDeep: number; addFormVisible: boolean; } @@ -1051,7 +1053,7 @@ export class JsonObject extends Component { this.state = { name: props.name, data: props.data, - keyPath, + keyPath: keyPath ?? [], deep: props.deep ?? 0, nextDeep: (props.deep ?? 0) + 1, collapsed: props.isCollapsed(keyPath, props.deep ?? 0, props.data), @@ -1208,7 +1210,7 @@ export class JsonObject extends Component { const isReadOnly = readOnly(name, data, keyPath, deep, dataType); - const removeItemButton = + const removeItemButton = minusMenuElement && cloneElement(minusMenuElement, { onClick: handleRemove, @@ -1254,7 +1256,7 @@ export class JsonObject extends Component { const isReadOnly = readOnly(name, data, keyPath, deep, dataType); - const addItemButton = + const addItemButton = plusMenuElement && cloneElement(plusMenuElement, { onClick: this.handleAddMode, @@ -1334,7 +1336,7 @@ export class JsonObject extends Component { } render() { - const { name, collapsed, keyPath, deep } = this.state; + const { name, collapsed, keyPath, deep = 0 } = this.state; const value = collapsed ? this.renderCollapsed() : this.renderNotCollapsed(); return ( @@ -1387,8 +1389,8 @@ JsonObject.defaultProps = { interface JsonValueState { value: JsonValueProps['value']; name: JsonValueProps['name']; - keyPath: string[]; - deep: JsonValueProps['deep']; + keyPath: Exclude; + deep: Exclude; editEnabled: boolean; inputRef: any; } @@ -1400,8 +1402,8 @@ export class JsonValue extends Component { this.state = { value: props.value, name: props.name, - keyPath, - deep: props.deep, + keyPath: keyPath ?? [], + deep: props.deep ?? 0, editEnabled: false, inputRef: null, }; @@ -1521,8 +1523,9 @@ export class JsonValue extends Component { const parentPropertyName = keyPath.at(-2); - const minusMenuLayout = - minusMenuElement && cloneElement(minusMenuElement, { + const minusMenuLayout = + minusMenuElement && + cloneElement(minusMenuElement, { onClick: handleRemove, className: 'rejt-minus-menu', style: style.minus,