Skip to content

Commit 52b843a

Browse files
react-vanilla: Disable array buttons when readonly (#2303)
* Add toggling readonly state to the example app * Disable array control and array table control buttons when the controls are disabled. This is the case when controls are readonly * Add unit tests for the controls' button enablement Co-authored-by: Lucas Koehler <lkoehler@eclipsesource.com>
1 parent 429f11a commit 52b843a

File tree

7 files changed

+118
-0
lines changed

7 files changed

+118
-0
lines changed

packages/examples/src/example.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export interface ExampleDescription {
4141
config?: any;
4242
actions?: { label: string; apply: (props: StateProps) => any }[];
4343
i18n?: JsonFormsI18nState;
44+
readonly?: boolean;
4445
}
4546

4647
export interface StateProps {
@@ -51,4 +52,5 @@ export interface StateProps {
5152
cells?: JsonFormsCellRendererRegistryEntry[];
5253
config?: any;
5354
uischemas?: JsonFormsUISchemaRegistryEntry[];
55+
readonly?: boolean;
5456
}

packages/examples/src/examples/arrays-with-detail.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
import { registerExamples } from '../register';
2626
import { personCoreSchema } from './person';
27+
import { StateProps } from '../example';
2728

2829
export const schema = {
2930
type: 'object',
@@ -93,12 +94,22 @@ export const data = {
9394
],
9495
};
9596

97+
const actions = [
98+
{
99+
label: 'Toggle readonly',
100+
apply: (props: StateProps) => {
101+
return { ...props, readonly: !props.readonly };
102+
},
103+
},
104+
];
105+
96106
registerExamples([
97107
{
98108
name: 'array-with-detail',
99109
label: 'Array with detail',
100110
data,
101111
schema,
102112
uischema,
113+
actions,
103114
},
104115
]);

packages/examples/src/examples/arrays.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ const actions = [
123123
};
124124
},
125125
},
126+
{
127+
label: 'Toggle readonly',
128+
apply: (props: StateProps) => {
129+
return { ...props, readonly: !props.readonly };
130+
},
131+
},
126132
];
127133

128134
registerExamples([

packages/vanilla-renderers/src/complex/TableArrayControl.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class TableArrayControl extends React.Component<
8383
getStyleAsClassName,
8484
childErrors,
8585
translations,
86+
enabled,
8687
} = this.props;
8788

8889
const controlElement = uischema as ControlElement;
@@ -112,6 +113,7 @@ class TableArrayControl extends React.Component<
112113
<label className={labelClass}>{label}</label>
113114
<button
114115
type='button'
116+
disabled={!enabled}
115117
className={buttonClass}
116118
onClick={addItem(path, createDefaultValue(schema, rootSchema))}
117119
>
@@ -216,6 +218,7 @@ class TableArrayControl extends React.Component<
216218
<td>
217219
<button
218220
type='button'
221+
disabled={!enabled}
219222
aria-label={translations.removeAriaLabel}
220223
onClick={() => {
221224
if (

packages/vanilla-renderers/src/complex/array/ArrayControlRenderer.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export const ArrayControl = ({
5858
renderers,
5959
rootSchema,
6060
translations,
61+
enabled,
6162
}: ArrayControlProps & VanillaRendererProps) => {
6263
const controlElement = uischema as ControlElement;
6364
const childUiSchema = useMemo(
@@ -98,6 +99,7 @@ export const ArrayControl = ({
9899
<button
99100
type='button'
100101
className={buttonClassAdd}
102+
disabled={!enabled}
101103
onClick={addItem(path, createDefaultValue(schema, rootSchema))}
102104
>
103105
Add to {label}
@@ -121,6 +123,7 @@ export const ArrayControl = ({
121123
<button
122124
type='button'
123125
className={buttonClassUp}
126+
disabled={!enabled}
124127
aria-label={translations.upAriaLabel}
125128
onClick={() => {
126129
moveUp(path, index)();
@@ -131,6 +134,7 @@ export const ArrayControl = ({
131134
<button
132135
type='button'
133136
className={buttonClassDown}
137+
disabled={!enabled}
134138
aria-label={translations.downAriaLabel}
135139
onClick={() => {
136140
moveDown(path, index)();
@@ -141,6 +145,7 @@ export const ArrayControl = ({
141145
<button
142146
type='button'
143147
className={buttonClassDelete}
148+
disabled={!enabled}
144149
aria-label={translations.removeAriaLabel}
145150
onClick={() => {
146151
if (

packages/vanilla-renderers/test/renderers/ArrayControl.test.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,54 @@ describe('Array control renderer', () => {
7575

7676
expect(controls).toHaveLength(3);
7777
});
78+
79+
test('renders buttons', () => {
80+
const core = initCore(fixture.schema, fixture.uischema, fixture.data);
81+
const cells = [{ tester: integerCellTester, cell: IntegerCell }];
82+
const wrapper = mount(
83+
<JsonFormsStateProvider
84+
initState={{
85+
renderers: vanillaRenderers,
86+
cells,
87+
core,
88+
uischemas: [{ tester: () => 1, uischema: { type: 'Control' } }],
89+
}}
90+
>
91+
<ArrayControl schema={fixture.schema} uischema={fixture.uischema} />
92+
</JsonFormsStateProvider>
93+
);
94+
95+
const buttons = wrapper.find('button');
96+
expect(buttons).toHaveLength(4);
97+
buttons.forEach((button) => {
98+
expect(button.prop('disabled')).toBe(false);
99+
});
100+
});
101+
102+
test('disabled control renders disabled buttons', () => {
103+
const core = initCore(fixture.schema, fixture.uischema, fixture.data);
104+
const cells = [{ tester: integerCellTester, cell: IntegerCell }];
105+
const wrapper = mount(
106+
<JsonFormsStateProvider
107+
initState={{
108+
renderers: vanillaRenderers,
109+
cells,
110+
core,
111+
uischemas: [{ tester: () => 1, uischema: { type: 'Control' } }],
112+
}}
113+
>
114+
<ArrayControl
115+
schema={fixture.schema}
116+
uischema={fixture.uischema}
117+
enabled={false}
118+
/>
119+
</JsonFormsStateProvider>
120+
);
121+
122+
const buttons = wrapper.find('button');
123+
expect(buttons).toHaveLength(4);
124+
buttons.forEach((button) => {
125+
expect(button.prop('disabled')).toBe(true);
126+
});
127+
});
78128
});

packages/vanilla-renderers/test/renderers/TableArrayControl.test.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,47 @@ const fixture2 = {
9191
},
9292
};
9393

94+
describe('Table array control', () => {
95+
test('renders buttons', () => {
96+
const core = initCore(fixture.schema, fixture.uischema, fixture.data);
97+
const cells = [{ tester: integerCellTester, cell: IntegerCell }];
98+
const wrapper = mount(
99+
<JsonFormsStateProvider initState={{ core, cells }}>
100+
<TableArrayControl
101+
schema={fixture.schema}
102+
uischema={fixture.uischema}
103+
/>
104+
</JsonFormsStateProvider>
105+
);
106+
107+
const buttons = wrapper.find('button');
108+
expect(buttons).toHaveLength(2);
109+
buttons.forEach((button) => {
110+
expect(button.prop('disabled')).toBe(false);
111+
});
112+
});
113+
114+
test('disabled control renders disabled buttons', () => {
115+
const core = initCore(fixture.schema, fixture.uischema, fixture.data);
116+
const cells = [{ tester: integerCellTester, cell: IntegerCell }];
117+
const wrapper = mount(
118+
<JsonFormsStateProvider initState={{ core, cells }}>
119+
<TableArrayControl
120+
schema={fixture.schema}
121+
uischema={fixture.uischema}
122+
enabled={false}
123+
/>
124+
</JsonFormsStateProvider>
125+
);
126+
127+
const buttons = wrapper.find('button');
128+
expect(buttons).toHaveLength(2);
129+
buttons.forEach((button) => {
130+
expect(button.prop('disabled')).toBe(true);
131+
});
132+
});
133+
});
134+
94135
describe('Table array tester', () => {
95136
test('tester with recursive document ref only', () => {
96137
const control: ControlElement = {

0 commit comments

Comments
 (0)