Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keyboard support for palette entries #833

Merged
merged 3 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions e2e/visual/no-theme.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,8 @@ test('no-theme - editor', async ({ page, makeAxeBuilder }) => {
await expect(page).toHaveScreenshot();

// and then
// @Note(pinussilvestrus): the palette entries are currently
// not keyboard accessible, as we need to invest in an overall
// editor keyboard experience
// cf. https://github.com/bpmn-io/form-js/issues/536
const results = await makeAxeBuilder({
disableRules: [
'scrollable-region-focusable',
'page-has-heading-one'
]
}).analyze();
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 0 additions & 5 deletions e2e/visual/theming.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,8 @@ test('theming - editor', async ({ page, makeAxeBuilder }) => {
await expect(page).toHaveScreenshot();

// and then
// @Note(pinussilvestrus): the palette entries are currently
// not keyboard accessible, as we need to invest in an overall
// editor keyboard experience
// cf. https://github.com/bpmn-io/form-js/issues/536
const results = await makeAxeBuilder({
disableRules: [
'scrollable-region-focusable',
'page-has-heading-one'
]
}).analyze();
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions packages/form-js-editor/assets/form-js-editor-base.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
--cds-border-strong,
var(--cds-border-strong-01, var(--color-grey-225-10-80))
);
--color-palette-field-focus: var(--cds-border-interactive, var(--color-blue-205-100-45));
--color-palette-field-hover-background: var(--cds-background-hover, var(--color-grey-225-10-90));
--cursor-palette-field: grab;
--palette-width: 250px;
Expand Down Expand Up @@ -625,6 +626,9 @@
flex-direction: column;
justify-content: center;
font-size: 11px;
align-items: center;
border: none;
font-family: inherit;
user-select: none;
color: var( --color-palette-field);
background: var(--color-palette-field-background);
Expand All @@ -634,12 +638,18 @@
width: 68px;
}

.fjs-palette-container .fjs-palette-field:focus {
outline: none;
border: solid 1px var(--color-palette-field-focus);
}

.fjs-palette-field .fjs-palette-field-icon {
margin: 0 auto;
}

.fjs-palette-field .fjs-palette-field-text {
text-align: center;
width: inherit;
}

.fjs-palette-container .fjs-palette-field:hover {
Expand Down
30 changes: 6 additions & 24 deletions packages/form-js-editor/src/features/palette/components/Palette.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import {

import {
CloseIcon,
iconsByType,
SearchIcon
} from '../../../render/components/icons';

import PaletteEntry from './PaletteEntry';

import { formFields } from '@bpmn-io/form-js-viewer';

export const PALETTE_ENTRIES = formFields.filter(({ config: fieldConfig }) => fieldConfig.type !== 'default').map(({ config: fieldConfig }) => {
Expand Down Expand Up @@ -120,20 +121,11 @@ export default function Palette(props) {
<span class="fjs-palette-group-title">{ label }</span>
<div class="fjs-palette-fields fjs-drag-container fjs-no-drop">
{
entries.map(({ label, type }) => {
const Icon = iconsByType(type);

entries.map(entry => {
return (
<div
class="fjs-palette-field fjs-drag-copy fjs-no-drop"
data-field-type={ type }
title={ `Create ${getIndefiniteArticle(type)} ${label} element` }
>
{
Icon ? <Icon class="fjs-palette-field-icon" width="36" height="36" viewBox="0 0 54 54" /> : null
}
<span class="fjs-palette-field-text">{ label }</span>
</div>
<PaletteEntry
{ ...entry }
/>
);
})
}
Expand Down Expand Up @@ -174,14 +166,4 @@ function groupEntries(entries) {
});

return groups.filter(g => g.entries.length);
}

function getIndefiniteArticle(type) {
if ([
'image'
].includes(type)) {
return 'an';
}

return 'a';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
iconsByType
} from '../../../render/components/icons';

import { useService } from '../../../render/hooks';

export default function PaletteEntry(props) {
const {
type,
label
} = props;

const modeling = useService('modeling');
const formEditor = useService('formEditor');

const Icon = iconsByType(type);

const onKeyDown = (event) => {
if (event.code === 'Enter') {

const { fieldType: type } = event.target.dataset;

const { schema } = formEditor._getState();

// add new form field to last position
modeling.addFormField({ type }, schema, schema.components.length);
}
};

return (
<button
class="fjs-palette-field fjs-drag-copy fjs-no-drop"
data-field-type={ type }
title={ `Create ${getIndefiniteArticle(type)} ${label} element` }
onKeyDown={ onKeyDown }
>
{
Icon ? <Icon class="fjs-palette-field-icon" width="36" height="36" viewBox="0 0 54 54" /> : null
}
<span class="fjs-palette-field-text">{ label }</span>
</button>
);
}


// helpers ///////////

function getIndefiniteArticle(type) {
vsgoulart marked this conversation as resolved.
Show resolved Hide resolved
if ([
'image'
].includes(type)) {
return 'an';
}

return 'a';
}
12 changes: 1 addition & 11 deletions packages/form-js-editor/test/spec/FormEditor.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1501,17 +1501,7 @@ describe('FormEditor', function() {
});

// then
// @Note(pinussilvestrus): the palette entries are currently
// not keyboard accessible, as we need to invest in an overall
// editor keyboard experience
// cf. https://github.com/bpmn-io/form-js/issues/536
await expectNoViolations(container, {
rules: {
'scrollable-region-focusable': {
enabled: false
}
}
});
await expectNoViolations(container);
});

});
Expand Down
82 changes: 62 additions & 20 deletions packages/form-js-editor/test/spec/features/palette/Palette.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,65 @@ describe('palette', function() {
});


describe('keyboard support', function() {


it('should add entry on ENTER', async function() {

// given
const spy = sinon.spy();

const schema = {
components: []
};

const result = createPalette({
container,
modeling: { addFormField: spy },
formEditor: { _getState: () => ({ schema }) }
});

const entry = result.container.querySelector('[data-field-type="textfield"]');

// when
fireEvent.focus(entry);
fireEvent.keyDown(entry, { key: 'Enter', code: 'Enter' });

// then
expect(spy).to.have.been.calledOnceWith({ type: 'textfield' }, schema, 0);
});


it('should add entry to last position', async function() {

// given
const spy = sinon.spy();

const schema = {
components: [ {
type: 'textfield',
id: 'foo'
} ]
};

const result = createPalette({
container,
modeling: { addFormField: spy },
formEditor: { _getState: () => ({ schema }) }
});

const entry = result.container.querySelector('[data-field-type="textfield"]');

// when
fireEvent.focus(entry);
fireEvent.keyDown(entry, { key: 'Enter', code: 'Enter' });

// then
expect(spy).to.have.been.calledOnceWith({ type: 'textfield' }, schema, 1);
});
});


describe('a11y', function() {

it('should have no violations', async function() {
Expand All @@ -183,17 +242,7 @@ describe('palette', function() {
const result = createPalette({ container });

// then
// @Note(pinussilvestrus): the palette entries are currently
// not keyboard accessible, as we need to invest in an overall
// editor keyboard experience
// cf. https://github.com/bpmn-io/form-js/issues/536
await expectNoViolations(result.container, {
rules: {
'scrollable-region-focusable': {
enabled: false
}
}
});
await expectNoViolations(result.container);
});


Expand All @@ -210,15 +259,8 @@ describe('palette', function() {
fireEvent.input(search, { target: { value: 'text' } });

// then
await expectNoViolations(result.container, {
rules: {
'scrollable-region-focusable': {
enabled: false
}
}
});
await expectNoViolations(result.container);
});

});

});
Expand All @@ -230,7 +272,7 @@ function createPalette(options = {}) {
const { container } = options;

return render(
WithFormEditorContext(<Palette />),
WithFormEditorContext(<Palette />, options),
{
container
}
Expand Down
Loading