diff --git a/package.json b/package.json index 717102e2..65ff8e73 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@dnd-kit/modifiers": "^7.0.0", "@dnd-kit/utilities": "^3.2.2", "@fluentui/react": "^8.120.2", - "@fluentui/react-components": "^9.54.13", + "@fluentui/react-components": "^9.59.0", "@fluentui/react-icons": "^2.0.249", "@fluentui/react-migration-v8-v9": "^9.6.23", "@fluentui/react-shared-contexts": "^9.7.2", diff --git a/packages/teams-components/src/components/Toolbar/Toolbar.styles.ts b/packages/teams-components/src/components/Toolbar/Toolbar.styles.ts new file mode 100644 index 00000000..a4442eb6 --- /dev/null +++ b/packages/teams-components/src/components/Toolbar/Toolbar.styles.ts @@ -0,0 +1,7 @@ +import { makeStyles } from '@fluentui/react-components'; + +export const useStyles = makeStyles({ + root: { + display: 'flex', + }, +}); diff --git a/packages/teams-components/src/components/Toolbar/Toolbar.test.tsx b/packages/teams-components/src/components/Toolbar/Toolbar.test.tsx new file mode 100644 index 00000000..eadacbda --- /dev/null +++ b/packages/teams-components/src/components/Toolbar/Toolbar.test.tsx @@ -0,0 +1,9 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; +import { Toolbar } from './Toolbar'; + +describe('Toolbar', () => { + it('should render', () => { + render(); + }); +}); diff --git a/packages/teams-components/src/components/Toolbar/Toolbar.tsx b/packages/teams-components/src/components/Toolbar/Toolbar.tsx new file mode 100644 index 00000000..2a42e6e1 --- /dev/null +++ b/packages/teams-components/src/components/Toolbar/Toolbar.tsx @@ -0,0 +1,87 @@ +import { + mergeClasses, + useArrowNavigationGroup, +} from '@fluentui/react-components'; +import * as React from 'react'; +import { useStyles } from './Toolbar.styles'; +import { StrictCssClass } from '../../strictStyles'; +import { + ToolbarItemRegistrationProvider, + useInitItemRegistration, +} from './itemRegistration'; + +export interface ToolbarProps { + children: React.ReactNode; + className?: StrictCssClass; +} + +export const toolbarClassNames = { + root: 'tco-Toolbar', +}; + +export const Toolbar = React.forwardRef( + (props, ref) => { + const { children, className } = props; + const styles = useStyles(); + const registerItem = useInitItemRegistration(); + const contextValue = React.useMemo( + () => ({ registerItem }), + [registerItem] + ); + + return ( + +
+ {children} +
+
+ ); + } +); + +// TODO implement DOM validation API +// const isAllowedToolbarItem = (el: HTMLElement) => { +// return ( +// el.classList.contains(toolbarButtonClassNames.root) || +// el.classList.contains(toolbarDividerClassNames.root) || +// el.classList.contains(toolbarMenuButtonClassNames.root) || +// el.classList.contains(toolbarToggleButtonClassNames.root) +// ); +// }; +// +// const isPortalSpan = (el: HTMLElement) => { +// return el.tagName === 'SPAN' && el.hasAttribute('hidden'); +// }; +// +// const isTabsterDummy = (el: HTMLElement) => { +// return el.hasAttribute('data-tabster-dummy'); +// }; +// +// const validateToolbarItems = (root: HTMLElement) => { +// const children = root.children; +// for (const child of children) { +// // TODO is this even possible? +// if (!isHTMLElement(child)) { +// continue; +// } +// +// if ( +// !isAllowedToolbarItem(child) && +// !isPortalSpan(child) && +// !isTabsterDummy(child) +// ) { +// throw new Error( +// '@fluentui-contrib/teams-components::Toolbar::Use Toolbar components from @fluentui-contrib/teams-components package only' +// ); +// } +// } +// }; diff --git a/packages/teams-components/src/components/Toolbar/ToolbarButton.tsx b/packages/teams-components/src/components/Toolbar/ToolbarButton.tsx new file mode 100644 index 00000000..44b1fcfd --- /dev/null +++ b/packages/teams-components/src/components/Toolbar/ToolbarButton.tsx @@ -0,0 +1,33 @@ +import * as React from 'react'; +import { Button, type ButtonProps } from '../Button'; +import { createStrictClass } from '../../strictStyles/createStrictClass'; +import { useItemRegistration } from './itemRegistration'; +import { useMergedRefs } from '@fluentui/react-components'; +import { mergeStrictClasses } from '../../strictStyles/mergeStrictClasses'; + +export const toolbarButtonClassNames = { + root: 'tco-ToolbarButton', +}; + +export type ToolbarButtonProps = Omit; + +const rootStrictClassName = createStrictClass(toolbarButtonClassNames.root); + +// TODO teams-components should reuse composition patterns +export const ToolbarButton = React.forwardRef( + (props, ref) => { + const { ref: registerRef, styles } = useItemRegistration({ + appearance: props.appearance, + type: 'button', + }); + + return ( +