diff --git a/packages/fluentui/CHANGELOG.md b/packages/fluentui/CHANGELOG.md index dd25d7a7cc57ef..0e114a9211f28c 100644 --- a/packages/fluentui/CHANGELOG.md +++ b/packages/fluentui/CHANGELOG.md @@ -77,6 +77,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Added new `borderActive` color design token to `categoryColorScheme` @ling1726 ([#15717](https://github.com/microsoft/fluentui/pull/15717)) ### Documentation +- UIBuilder: Add accessibility props panel @jurokapsiar ([#15820](https://github.com/microsoft/fluentui/pull/15820)) - Add VoiceOver issue in known `accessibilityIssues` for `Toolbar` on `menuitemradio` @yuanboxue-amber ([#15203](https://github.com/microsoft/fluentui/pull/15203)) - Fixed icon margins after code change in UI builder @vyhnalekl ([#14859](https://github.com/microsoft/fluentui/pull/14859)) - Fixed image with no height in build mode - UI builder @vyhnalekl ([#14893](https://github.com/microsoft/fluentui/pull/14893)) diff --git a/packages/fluentui/react-builder/src/components/Knobs.tsx b/packages/fluentui/react-builder/src/components/Knobs.tsx index cc4838b91a39d0..08298d0e8c6403 100644 --- a/packages/fluentui/react-builder/src/components/Knobs.tsx +++ b/packages/fluentui/react-builder/src/components/Knobs.tsx @@ -1,7 +1,7 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { Header /* Slider */ } from '@fluentui/react-northstar'; -import { ComponentInfo } from '../componentInfo/types'; +import { Menu, tabListBehavior } from '@fluentui/react-northstar'; +import { ComponentInfo, ComponentProp } from '../componentInfo/types'; import { JSONTreeElement } from './types'; import { MultiTypeKnob } from '../config'; @@ -52,6 +52,82 @@ import { MultiTypeKnob } from '../config'; // // const rowStyle = { padding: '0.1rem 0.25rem' }; +const A11YPROPS: ComponentProp[] = [ + { + name: 'id', + required: false, + defaultValue: '', + tags: [], + description: 'ID of an element', + types: [{ name: 'string' }], + }, + { + name: 'role', + required: false, + defaultValue: '', + tags: [], + description: 'accessiblerole of an element', + types: [{ name: 'string' }], + }, + { + name: 'aria-label', + required: false, + defaultValue: '', + tags: [], + description: 'define a string that labels the current element', + types: [{ name: 'string' }], + }, + { + name: 'aria-labelledby', + required: false, + defaultValue: '', + tags: [], + description: 'establishes relationships between objects and their label(s)', + types: [{ name: 'string' }], + }, + { + name: 'aria-describedby', + required: false, + defaultValue: '', + tags: [], + description: 'indicates the IDs of the elements that describe the object', + types: [{ name: 'string' }], + }, + { + name: 'title', + required: false, + defaultValue: '', + tags: [], + description: 'specifies extra information about an element', + types: [{ name: 'string' }], + }, + { + name: 'aria-hidden', + required: false, + defaultValue: false, + tags: [], + description: 'removes the element and all of its children from the accessibility tree', + types: [{ name: 'boolean' }], + }, + { + name: 'tabIndex', + required: false, + defaultValue: 0, + tags: [], + description: + 'indicates that its element can be focused, and where it participates in sequential keyboard navigation', + types: [{ name: 'number' }], + }, + { + name: 'data-is-focusable', + required: false, + defaultValue: false, + tags: [], + description: 'define if data is focusable', + types: [{ name: 'boolean' }], + }, +]; + type DesignKnobProps = { onPropChange: ({ jsonTreeElement, @@ -67,26 +143,72 @@ type DesignKnobProps = { }; export const Knobs: React.FunctionComponent = ({ onPropChange, info, jsonTreeElement }) => { + const [menuActivePane, setMenuActivePane] = React.useState<'props' | 'accessibility'>('props'); return (
-
Props
- {info.props - // only allow knobs for regular props, not default props - .filter(prop => !/default[A-Z]/.test(prop.name)) - .map(prop => { + setMenuActivePane('props'), + }, + { + key: 'accessibility', + content: 'Accessibility', + onClick: () => setMenuActivePane('accessibility'), + }, + ]} + underlined + primary + styles={{ marginBottom: '1rem', marginTop: '1.5rem' }} + /> + {menuActivePane === 'props' && + info.props + // only allow knobs for regular props, not default props + .filter(prop => !/default[A-Z]/.test(prop.name)) + .map(prop => { + const propValue = jsonTreeElement.props?.[prop.name]; + const types = _.uniq(_.map(prop.types, 'name')); + const isLiteral = _.every(types, name => name === 'literal'); + const options = isLiteral ? _.map(prop.types, 'value') : null; + + const defaultValues = { + boolean: false, + number: 0, + string: '', + }; + + const value = typeof propValue !== 'undefined' ? propValue : defaultValues[types[0]]; + + return ( + { + onPropChange({ jsonTreeElement, name: prop.name, value }); + }} + /> + ); + })} + + {menuActivePane === 'accessibility' && + A11YPROPS.filter(prop => !/default[A-Z]/.test(prop.name)).map(prop => { const propValue = jsonTreeElement.props?.[prop.name]; const types = _.uniq(_.map(prop.types, 'name')); const isLiteral = _.every(types, name => name === 'literal'); const options = isLiteral ? _.map(prop.types, 'value') : null; - const defaultValues = { boolean: false, number: 0, string: '', }; - const value = typeof propValue !== 'undefined' ? propValue : defaultValues[types[0]]; - return ( = ({ onPropChange, /> ); })} - {/* -
Design
- {_.map(knobs, knob => { - const value = jsonTreeElement.props && jsonTreeElement.props.design && jsonTreeElement.props.design[knob.label]; - - return ( -
- {knob.kind === 'slider' ? ( - <> - {JSON.stringify(value, null, 2)} -
{knob.label}
- { - onPropChange({ jsonTreeElement, name: knob.label, value: knob.ramp[+data.value] }); - }} - /> - - ) : knob.kind === 'divider' ? ( - - ) : ( -
UNKNOWN
- )} -
- ); - })} - */}
); };