diff --git a/change/@fluentui-react-nav-preview-8415b62b-8398-424c-9b31-d1ee026e9b99.json b/change/@fluentui-react-nav-preview-8415b62b-8398-424c-9b31-d1ee026e9b99.json new file mode 100644 index 0000000000000..605d4f75d05ed --- /dev/null +++ b/change/@fluentui-react-nav-preview-8415b62b-8398-424c-9b31-d1ee026e9b99.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Scaffolds SplitNavItem", + "packageName": "@fluentui/react-nav-preview", + "email": "matejera@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-nav-preview/library/etc/react-nav-preview.api.md b/packages/react-components/react-nav-preview/library/etc/react-nav-preview.api.md index 88aea57efec56..18e875c7569cb 100644 --- a/packages/react-components/react-nav-preview/library/etc/react-nav-preview.api.md +++ b/packages/react-components/react-nav-preview/library/etc/react-nav-preview.api.md @@ -381,6 +381,26 @@ export const renderNavSubItem_unstable: (state: NavSubItemState) => JSX.Element; // @public export const renderNavSubItemGroup_unstable: (state: NavSubItemGroupState) => JSX.Element | null; +// @public +export const renderSplitNavItem_unstable: (state: SplitNavItemState) => JSX.Element; + +// @public +export const SplitNavItem: ForwardRefComponent; + +// @public (undocumented) +export const splitNavItemClassNames: SlotClassNames; + +// @public +export type SplitNavItemProps = ComponentProps & {}; + +// @public (undocumented) +export type SplitNavItemSlots = { + root: Slot<'div'>; +}; + +// @public +export type SplitNavItemState = ComponentState; + // @public export const useAppItem_unstable: (props: AppItemProps, ref: React_2.Ref) => AppItemState; @@ -471,6 +491,12 @@ export const useNavSubItemGroupStyles_unstable: (state: NavSubItemGroupState) => // @public export const useNavSubItemStyles_unstable: (state: NavSubItemState) => NavSubItemState; +// @public +export const useSplitNavItem_unstable: (props: SplitNavItemProps, ref: React_2.Ref) => SplitNavItemState; + +// @public +export const useSplitNavItemStyles_unstable: (state: SplitNavItemState) => SplitNavItemState; + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/react-components/react-nav-preview/library/src/SplitNavItem.ts b/packages/react-components/react-nav-preview/library/src/SplitNavItem.ts new file mode 100644 index 0000000000000..bbfa6494448f5 --- /dev/null +++ b/packages/react-components/react-nav-preview/library/src/SplitNavItem.ts @@ -0,0 +1 @@ +export * from './components/SplitNavItem/index'; diff --git a/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/SplitNavItem.test.tsx b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/SplitNavItem.test.tsx new file mode 100644 index 0000000000000..99e7e7ea47dba --- /dev/null +++ b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/SplitNavItem.test.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; +import { isConformant } from '../../testing/isConformant'; +import { SplitNavItem } from './SplitNavItem'; + +describe('SplitNavItem', () => { + isConformant({ + Component: SplitNavItem, + displayName: 'SplitNavItem', + }); + + // TODO add more tests here, and create visual regression tests in /apps/vr-tests + + it('renders a default state', () => { + const result = render(Default SplitNavItem); + expect(result.container).toMatchSnapshot(); + }); +}); diff --git a/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/SplitNavItem.tsx b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/SplitNavItem.tsx new file mode 100644 index 0000000000000..fc7fcb5f7640c --- /dev/null +++ b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/SplitNavItem.tsx @@ -0,0 +1,29 @@ +import * as React from 'react'; +import type { ForwardRefComponent } from '@fluentui/react-utilities'; +import { useSplitNavItem_unstable } from './useSplitNavItem'; +import { renderSplitNavItem_unstable } from './renderSplitNavItem'; +import { useSplitNavItemStyles_unstable } from './useSplitNavItemStyles.styles'; +import type { SplitNavItemProps } from './SplitNavItem.types'; + +/** + * SplitNavItem component - TODO: add more docs + */ +export const SplitNavItem: ForwardRefComponent = React.forwardRef((props, ref) => { + const state = useSplitNavItem_unstable(props, ref); + + useSplitNavItemStyles_unstable(state); + + /** + * @see https://github.com/microsoft/fluentui/blob/master/docs/react-v9/contributing/rfcs/react-components/convergence/custom-styling.md + * + * TODO: 💡 once package will become stable (PR which will be part of promoting PREVIEW package to STABLE), + * - uncomment this line + * - update types {@link file://./../../../../../../../packages/react-components/react-shared-contexts/library/src/CustomStyleHooksContext/CustomStyleHooksContext.ts#CustomStyleHooksContextValue} + * - verify that custom global style override works for your component + */ + // useCustomStyleHook_unstable('useSplitNavItemStyles_unstable')(state); + + return renderSplitNavItem_unstable(state); +}); + +SplitNavItem.displayName = 'SplitNavItem'; diff --git a/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/SplitNavItem.types.ts b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/SplitNavItem.types.ts new file mode 100644 index 0000000000000..8251c28d98ec0 --- /dev/null +++ b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/SplitNavItem.types.ts @@ -0,0 +1,17 @@ +import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities'; + +export type SplitNavItemSlots = { + root: Slot<'div'>; +}; + +/** + * SplitNavItem Props + */ +export type SplitNavItemProps = ComponentProps & {}; + +/** + * State used in rendering SplitNavItem + */ +export type SplitNavItemState = ComponentState; +// TODO: Remove semicolon from previous line, uncomment next line, and provide union of props to pick from SplitNavItemProps. +// & Required> diff --git a/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/__snapshots__/SplitNavItem.test.tsx.snap b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/__snapshots__/SplitNavItem.test.tsx.snap new file mode 100644 index 0000000000000..7c8a75e7d8391 --- /dev/null +++ b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/__snapshots__/SplitNavItem.test.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SplitNavItem renders a default state 1`] = ` +
+
+ Default SplitNavItem +
+
+`; diff --git a/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/index.ts b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/index.ts new file mode 100644 index 0000000000000..24c36db83805e --- /dev/null +++ b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/index.ts @@ -0,0 +1,5 @@ +export * from './SplitNavItem'; +export * from './SplitNavItem.types'; +export * from './renderSplitNavItem'; +export * from './useSplitNavItem'; +export * from './useSplitNavItemStyles.styles'; diff --git a/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/renderSplitNavItem.tsx b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/renderSplitNavItem.tsx new file mode 100644 index 0000000000000..01ea2b7b9e956 --- /dev/null +++ b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/renderSplitNavItem.tsx @@ -0,0 +1,15 @@ +/** @jsxRuntime automatic */ +/** @jsxImportSource @fluentui/react-jsx-runtime */ + +import { assertSlots } from '@fluentui/react-utilities'; +import type { SplitNavItemState, SplitNavItemSlots } from './SplitNavItem.types'; + +/** + * Render the final JSX of SplitNavItem + */ +export const renderSplitNavItem_unstable = (state: SplitNavItemState) => { + assertSlots(state); + + // TODO Add additional slots in the appropriate place + return ; +}; diff --git a/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/useSplitNavItem.ts b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/useSplitNavItem.ts new file mode 100644 index 0000000000000..66d80112a6f7e --- /dev/null +++ b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/useSplitNavItem.ts @@ -0,0 +1,34 @@ +import * as React from 'react'; +import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities'; +import type { SplitNavItemProps, SplitNavItemState } from './SplitNavItem.types'; + +/** + * Create the state required to render SplitNavItem. + * + * The returned state can be modified with hooks such as useSplitNavItemStyles_unstable, + * before being passed to renderSplitNavItem_unstable. + * + * @param props - props from this instance of SplitNavItem + * @param ref - reference to root HTMLDivElement of SplitNavItem + */ +export const useSplitNavItem_unstable = ( + props: SplitNavItemProps, + ref: React.Ref, +): SplitNavItemState => { + return { + // TODO add appropriate props/defaults + components: { + // TODO add each slot's element type or component + root: 'div', + }, + // TODO add appropriate slots, for example: + // mySlot: resolveShorthand(props.mySlot), + root: slot.always( + getIntrinsicElementProps('div', { + ref, + ...props, + }), + { elementType: 'div' }, + ), + }; +}; diff --git a/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/useSplitNavItemStyles.styles.ts b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/useSplitNavItemStyles.styles.ts new file mode 100644 index 0000000000000..651ee88bda8cb --- /dev/null +++ b/packages/react-components/react-nav-preview/library/src/components/SplitNavItem/useSplitNavItemStyles.styles.ts @@ -0,0 +1,35 @@ +import { makeStyles, mergeClasses } from '@griffel/react'; +import type { SlotClassNames } from '@fluentui/react-utilities'; +import type { SplitNavItemSlots, SplitNavItemState } from './SplitNavItem.types'; + +export const splitNavItemClassNames: SlotClassNames = { + root: 'fui-SplitNavItem', + // TODO: add class names for all slots on SplitNavItemSlots. + // Should be of the form `: 'fui-SplitNavItem__` +}; + +/** + * Styles for the root slot + */ +const useStyles = makeStyles({ + root: { + // TODO Add default styles for the root element + }, + + // TODO add additional classes for different states and/or slots +}); + +/** + * Apply styling to the SplitNavItem slots based on the state + */ +export const useSplitNavItemStyles_unstable = (state: SplitNavItemState): SplitNavItemState => { + 'use no memo'; + + const styles = useStyles(); + state.root.className = mergeClasses(splitNavItemClassNames.root, styles.root, state.root.className); + + // TODO Add class names to slots, for example: + // state.mySlot.className = mergeClasses(styles.mySlot, state.mySlot.className); + + return state; +}; diff --git a/packages/react-components/react-nav-preview/library/src/index.ts b/packages/react-components/react-nav-preview/library/src/index.ts index 9553e114fb735..843555cbcbd1b 100644 --- a/packages/react-components/react-nav-preview/library/src/index.ts +++ b/packages/react-components/react-nav-preview/library/src/index.ts @@ -113,3 +113,11 @@ export { useAppItemStaticStyles_unstable, useAppItemStatic_unstable, } from './AppItemStatic'; +export type { SplitNavItemProps, SplitNavItemSlots, SplitNavItemState } from './SplitNavItem'; +export { + SplitNavItem, + renderSplitNavItem_unstable, + splitNavItemClassNames, + useSplitNavItemStyles_unstable, + useSplitNavItem_unstable, +} from './SplitNavItem';