diff --git a/packages/vanilla/src/controls/OneOfRadioGroupControl.tsx b/packages/vanilla/src/controls/OneOfRadioGroupControl.tsx new file mode 100644 index 000000000..7ccaeb20d --- /dev/null +++ b/packages/vanilla/src/controls/OneOfRadioGroupControl.tsx @@ -0,0 +1,48 @@ +/* + The MIT License + + Copyright (c) 2018-2021 EclipseSource Munich + https://github.com/eclipsesource/jsonforms + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ +import React from 'react'; +import { + and, + ControlProps, + isOneOfEnumControl, + optionIs, + RankedTester, + rankWith, +} from '@jsonforms/core'; +import { withVanillaControlProps } from '../util'; +import { VanillaRendererProps } from '../index'; +import { withJsonFormsOneOfEnumProps } from '@jsonforms/react'; +import { RadioGroup } from './RadioGroup'; + +export const OneOfRadioGroupControl = (props: ControlProps & VanillaRendererProps) => { + return ; +}; + +export const oneOfRadioGroupControlTester: RankedTester = rankWith( + 3, + and(isOneOfEnumControl, optionIs('format', 'radio')) +); + +export default withVanillaControlProps(withJsonFormsOneOfEnumProps(OneOfRadioGroupControl)); diff --git a/packages/vanilla/src/controls/RadioGroup.tsx b/packages/vanilla/src/controls/RadioGroup.tsx new file mode 100644 index 000000000..db893b6bd --- /dev/null +++ b/packages/vanilla/src/controls/RadioGroup.tsx @@ -0,0 +1,107 @@ +/* + The MIT License + + Copyright (c) 2017-2021 EclipseSource Munich + https://github.com/eclipsesource/jsonforms + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ +import React from 'react'; +import { + computeLabel, + ControlProps, + ControlState, + isDescriptionHidden, + OwnPropsOfEnum +} from '@jsonforms/core'; +import { Control } from '@jsonforms/react'; +import { VanillaRendererProps } from '../index'; +import merge from 'lodash/merge'; + +export class RadioGroup extends Control< + ControlProps & VanillaRendererProps & OwnPropsOfEnum, + ControlState +> { + render() { + const { + classNames, + id, + label, + options, + required, + description, + errors, + data, + uischema, + visible, + config + } = this.props; + const isValid = errors.length === 0; + const divClassNames = `validation ${isValid ? classNames.description : 'validation_error' + }`; + const groupStyle: { [x: string]: any } = { + display: 'flex', + flexDirection: 'row' + }; + + const appliedUiSchemaOptions = merge({}, config, uischema.options); + const showDescription = !isDescriptionHidden( + visible, + description, + this.state.isFocused, + appliedUiSchemaOptions.showUnfocusedDescription + ); + + return ( + + ); + } +} \ No newline at end of file diff --git a/packages/vanilla/src/controls/RadioGroupControl.tsx b/packages/vanilla/src/controls/RadioGroupControl.tsx index 1bded620c..7ddf91cc6 100644 --- a/packages/vanilla/src/controls/RadioGroupControl.tsx +++ b/packages/vanilla/src/controls/RadioGroupControl.tsx @@ -1,7 +1,7 @@ /* The MIT License - Copyright (c) 2017-2019 EclipseSource Munich + Copyright (c) 2017-2021 EclipseSource Munich https://github.com/eclipsesource/jsonforms Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24,91 +24,21 @@ */ import React from 'react'; import { - computeLabel, + and, ControlProps, - ControlState, - isDescriptionHidden, + isEnumControl, + optionIs, RankedTester, rankWith } from '@jsonforms/core'; -import { Control, withJsonFormsControlProps } from '@jsonforms/react'; +import { withJsonFormsEnumProps } from '@jsonforms/react'; +import { RadioGroup } from './RadioGroup'; import { withVanillaControlProps } from '../util'; import { VanillaRendererProps } from '../index'; -import merge from 'lodash/merge'; +export const RadioGroupControl = (props: ControlProps & VanillaRendererProps) => { + return ; +}; -export class RadioGroupControl extends Control< - ControlProps & VanillaRendererProps, - ControlState -> { - render() { - const { - classNames, - id, - label, - required, - description, - errors, - data, - schema, - uischema, - visible, - config - } = this.props; - const isValid = errors.length === 0; - const divClassNames = `validation ${ - isValid ? classNames.description : 'validation_error' - }`; - const groupStyle: { [x: string]: any } = { - display: 'flex', - flexDirection: 'row' - }; - - const appliedUiSchemaOptions = merge({}, config, uischema.options); - const showDescription = !isDescriptionHidden( - visible, - description, - this.state.isFocused, - appliedUiSchemaOptions.showUnfocusedDescription - ); - - const options = schema.enum; - - return ( - - ); - } -} - -export default withVanillaControlProps( - withJsonFormsControlProps(RadioGroupControl) +export const radioGroupControlTester: RankedTester = rankWith( + 3, + and(isEnumControl, optionIs('format', 'radio')) ); +export default withVanillaControlProps(withJsonFormsEnumProps(RadioGroupControl)); diff --git a/packages/vanilla/src/controls/index.ts b/packages/vanilla/src/controls/index.ts index a308f54b4..fa601cad6 100644 --- a/packages/vanilla/src/controls/index.ts +++ b/packages/vanilla/src/controls/index.ts @@ -23,4 +23,13 @@ THE SOFTWARE. */ import InputControl, { inputControlTester } from './InputControl'; -export { InputControl, inputControlTester }; +import RadioGroupControl, { radioGroupControlTester } from './RadioGroupControl'; +import OneOfRadioGroupControl, { oneOfRadioGroupControlTester } from './OneOfRadioGroupControl'; +export { + InputControl, + inputControlTester, + RadioGroupControl, + radioGroupControlTester, + OneOfRadioGroupControl, + oneOfRadioGroupControlTester +}; diff --git a/packages/vanilla/src/index.ts b/packages/vanilla/src/index.ts index fd6746f7a..b6ccc7caa 100644 --- a/packages/vanilla/src/index.ts +++ b/packages/vanilla/src/index.ts @@ -46,7 +46,7 @@ import { timeCellTester } from './cells'; -import { InputControl, inputControlTester } from './controls'; +import { InputControl, inputControlTester, RadioGroupControl, radioGroupControlTester, OneOfRadioGroupControl, oneOfRadioGroupControlTester, } from './controls'; import { ArrayControl, @@ -110,6 +110,8 @@ export * from './styles'; export const vanillaRenderers: { tester: RankedTester; renderer: any }[] = [ { tester: inputControlTester, renderer: InputControl }, + { tester: radioGroupControlTester, renderer: RadioGroupControl }, + { tester: oneOfRadioGroupControlTester, renderer: OneOfRadioGroupControl }, { tester: arrayControlTester, renderer: ArrayControl }, { tester: labelRendererTester, renderer: LabelRenderer }, { tester: categorizationTester, renderer: Categorization }, diff --git a/packages/vanilla/test/renderers/RadioGroupControl.test.tsx b/packages/vanilla/test/renderers/RadioGroupControl.test.tsx index 264520a68..c423b559e 100644 --- a/packages/vanilla/test/renderers/RadioGroupControl.test.tsx +++ b/packages/vanilla/test/renderers/RadioGroupControl.test.tsx @@ -24,6 +24,7 @@ */ import { isEnumControl, + isOneOfEnumControl, rankWith, } from '@jsonforms/core'; import { JsonFormsStateProvider } from '@jsonforms/react'; @@ -32,7 +33,7 @@ import * as _ from 'lodash'; import Adapter from 'enzyme-adapter-react-16'; import Enzyme, { mount, ReactWrapper } from 'enzyme'; import '../../src'; -import RadioGroupControl from '../../src/controls/RadioGroupControl'; +import { RadioGroupControl, OneOfRadioGroupControl } from '../../src'; import { initCore } from '../util'; Enzyme.configure({ adapter: new Adapter() }); @@ -54,45 +55,82 @@ const fixture = { } }; +const oneOfFixture = { + data: { foo: 'b' }, + schema: { + type: 'object', + properties: { + foo: { + oneOf: [ + { const: 'a', title: 'A' }, + { const: 'b', title: 'B' }, + { const: 'c', title: 'C' } + ] + } + } + }, + uischema: { + type: 'Control', + scope: '#/properties/foo' + } +}; + describe('Radio group control', () => { - let wrapper: ReactWrapper; - - afterEach(() => wrapper.unmount()); - - test('render', () => { - const renderers = [{ tester: rankWith(10, isEnumControl), renderer: RadioGroupControl }]; - const core = initCore(fixture.schema, fixture.uischema, fixture.data); - wrapper = mount( - - - - ); - - const radioButtons = wrapper.find('input[type="radio"]'); - expect(radioButtons).toHaveLength(4); - // make sure one option is selected and iexpect "D" - const currentlyChecked = radioButtons.filter('input[checked=true]'); - expect(currentlyChecked).toHaveLength(1); - expect((currentlyChecked.getDOMNode() as HTMLInputElement).value).toBe('D'); - }); - - test('Radio group should have only one selected option', () => { - const renderers = [{ tester: rankWith(10, isEnumControl), renderer: RadioGroupControl }]; - const core = initCore(fixture.schema, fixture.uischema, fixture.data); - wrapper = mount( - - - - ); - - // change and verify selection - core.data = { ...core.data, foo: 'A' }; - core.data = { ...core.data, foo: 'B' }; - wrapper.setProps({ initState: { core }} ); - wrapper.update(); - const currentlyChecked = wrapper.find('input[checked=true]'); - expect(currentlyChecked).toHaveLength(1); - expect((currentlyChecked.getDOMNode() as HTMLInputElement).value).toBe('B'); - }); + let wrapper: ReactWrapper; + + afterEach(() => wrapper.unmount()); + + test('render enum', () => { + const renderers = [{ tester: rankWith(10, isEnumControl), renderer: RadioGroupControl }]; + const core = initCore(fixture.schema, fixture.uischema, fixture.data); + wrapper = mount( + + + + ); + + const radioButtons = wrapper.find('input[type="radio"]'); + expect(radioButtons).toHaveLength(4); + + // make sure one option is selected and expect "D" + const currentlyChecked = radioButtons.filter('input[checked=true]'); + expect(currentlyChecked).toHaveLength(1); + expect((currentlyChecked.getDOMNode() as HTMLInputElement).value).toBe('D'); + }); + + test('render oneOf', () => { + const renderers = [{ tester: rankWith(10, isOneOfEnumControl), renderer: OneOfRadioGroupControl }]; + const core = initCore(oneOfFixture.schema, oneOfFixture.uischema, oneOfFixture.data); + wrapper = mount( + + + + ); + + const radioButtons = wrapper.find('input[type="radio"]'); + expect(radioButtons).toHaveLength(3); + const currentlyChecked = radioButtons.filter('input[checked=true]'); + expect(currentlyChecked).toHaveLength(1); + expect((currentlyChecked.getDOMNode() as HTMLInputElement).value).toBe('b'); + }); + + test('Radio group should have only one selected option', () => { + const renderers = [{ tester: rankWith(10, isEnumControl), renderer: RadioGroupControl }]; + const core = initCore(fixture.schema, fixture.uischema, fixture.data); + wrapper = mount( + + + + ); + + // change and verify selection + core.data = { ...core.data, foo: 'A' }; + core.data = { ...core.data, foo: 'B' }; + wrapper.setProps({ initState: { core } }); + wrapper.update(); + const currentlyChecked = wrapper.find('input[checked=true]'); + expect(currentlyChecked).toHaveLength(1); + expect((currentlyChecked.getDOMNode() as HTMLInputElement).value).toBe('B'); + }); });