Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "feat: add swatch picker components",
"packageName": "@fluentui/react-headless-components-preview",
"email": "dmytrokirpa@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import * as Skeleton from '@fluentui/react-headless-components-preview/skeleton'
import * as Slider from '@fluentui/react-headless-components-preview/slider';
import * as SpinButton from '@fluentui/react-headless-components-preview/spin-button';
import * as Spinner from '@fluentui/react-headless-components-preview/spinner';
import * as SwatchPicker from '@fluentui/react-headless-components-preview/swatch-picker';
import * as Switch from '@fluentui/react-headless-components-preview/switch';
import * as TabList from '@fluentui/react-headless-components-preview/tab-list';
import * as Tag from '@fluentui/react-headless-components-preview/tag';
Expand Down Expand Up @@ -85,6 +86,7 @@ console.log({
Slider,
SpinButton,
Spinner,
SwatchPicker,
Switch,
TabList,
Tag,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
## API Report File for "@fluentui/react-headless-components-preview"

> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).

```ts

import { ColorSwatchBaseProps as ColorSwatchProps } from '@fluentui/react-swatch-picker';
import { ColorSwatchSlots } from '@fluentui/react-swatch-picker';
import { ColorSwatchBaseState as ColorSwatchState } from '@fluentui/react-swatch-picker';
import { EmptySwatchBaseProps as EmptySwatchProps } from '@fluentui/react-swatch-picker';
import { EmptySwatchSlots } from '@fluentui/react-swatch-picker';
import { EmptySwatchBaseState as EmptySwatchState } from '@fluentui/react-swatch-picker';
import type { ForwardRefComponent } from '@fluentui/react-utilities';
import type { ImageSwatchBaseProps } from '@fluentui/react-swatch-picker';
import type { ImageSwatchBaseState } from '@fluentui/react-swatch-picker';
import type { ImageSwatchSlots as ImageSwatchSlots_2 } from '@fluentui/react-swatch-picker';
import type * as React_2 from 'react';
import { renderColorSwatch_unstable as renderColorSwatch } from '@fluentui/react-swatch-picker';
import { renderEmptySwatch_unstable as renderEmptySwatch } from '@fluentui/react-swatch-picker';
import { renderImageSwatch_unstable as renderImageSwatch } from '@fluentui/react-swatch-picker';
import { renderSwatchPicker_unstable as renderSwatchPicker } from '@fluentui/react-swatch-picker';
import { renderSwatchPickerRow_unstable as renderSwatchPickerRow } from '@fluentui/react-swatch-picker';
import type { SwatchPickerBaseState } from '@fluentui/react-swatch-picker';
import { SwatchPickerBaseProps as SwatchPickerProps } from '@fluentui/react-swatch-picker';
import { SwatchPickerRowBaseProps as SwatchPickerRowProps } from '@fluentui/react-swatch-picker';
import { SwatchPickerRowSlots } from '@fluentui/react-swatch-picker';
import { SwatchPickerRowBaseState as SwatchPickerRowState } from '@fluentui/react-swatch-picker';
import { SwatchPickerSlots } from '@fluentui/react-swatch-picker';
import { useColorSwatchBase_unstable as useColorSwatch } from '@fluentui/react-swatch-picker';
import { useEmptySwatchBase_unstable as useEmptySwatch } from '@fluentui/react-swatch-picker';
import { useSwatchPickerContextValue_unstable as useSwatchPickerContextValue } from '@fluentui/react-swatch-picker';
import { useSwatchPickerContextValues } from '@fluentui/react-swatch-picker';
import { useSwatchPickerRowBase_unstable as useSwatchPickerRow } from '@fluentui/react-swatch-picker';

// @public (undocumented)
export const ColorSwatch: ForwardRefComponent<ColorSwatchProps>;

export { ColorSwatchProps }

export { ColorSwatchSlots }

export { ColorSwatchState }

// @public (undocumented)
export const EmptySwatch: ForwardRefComponent<EmptySwatchProps>;

export { EmptySwatchProps }

export { EmptySwatchSlots }

export { EmptySwatchState }

// @public (undocumented)
export const ImageSwatch: ForwardRefComponent<ImageSwatchProps>;

// @public (undocumented)
export type ImageSwatchProps = ImageSwatchBaseProps;

// @public (undocumented)
export type ImageSwatchSlots = ImageSwatchSlots_2;

// @public (undocumented)
export type ImageSwatchState = ImageSwatchBaseState & {
root: {
'data-selected'?: string;
};
};

export { renderColorSwatch }

export { renderEmptySwatch }

export { renderImageSwatch }

export { renderSwatchPicker }

export { renderSwatchPickerRow }

// @public
export const SwatchPicker: ForwardRefComponent<SwatchPickerProps>;

export { SwatchPickerProps }

// @public (undocumented)
export const SwatchPickerRow: ForwardRefComponent<SwatchPickerRowProps>;

export { SwatchPickerRowProps }

export { SwatchPickerRowSlots }

export { SwatchPickerRowState }

export { SwatchPickerSlots }

// @public (undocumented)
export type SwatchPickerState = SwatchPickerBaseState & {
root: {
focusgroup?: string;
};
};

export { useColorSwatch }

export { useEmptySwatch }

// @public (undocumented)
export const useImageSwatch: (props: ImageSwatchProps, ref: React_2.Ref<HTMLButtonElement>) => ImageSwatchState;

// @public (undocumented)
export const useSwatchPicker: (props: SwatchPickerProps, ref: React_2.Ref<HTMLDivElement>) => SwatchPickerState;

export { useSwatchPickerContextValue }

export { useSwatchPickerContextValues }

export { useSwatchPickerRow }

// (No @packageDocumentation comment for this package)

```
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"@fluentui/react-slider": "^9.6.4",
"@fluentui/react-spinbutton": "^9.6.4",
"@fluentui/react-spinner": "^9.8.4",
"@fluentui/react-swatch-picker": "^9.5.4",
"@fluentui/react-switch": "^9.7.4",
"@fluentui/react-tabs": "^9.12.3",
"@fluentui/react-tabster": "^9.26.16",
Expand Down Expand Up @@ -310,6 +311,12 @@
"import": "./lib/spinner.js",
"require": "./lib-commonjs/spinner.js"
},
"./swatch-picker": {
"types": "./dist/swatch-picker.d.ts",
"node": "./lib-commonjs/swatch-picker.js",
"import": "./lib/swatch-picker.js",
"require": "./lib-commonjs/swatch-picker.js"
},
"./switch": {
"types": "./dist/switch.d.ts",
"node": "./lib-commonjs/switch.js",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as React from 'react';
import { render } from '@testing-library/react';
import { isConformant } from '../../../testing/isConformant';
import { ColorSwatch } from './ColorSwatch';
import { SwatchPicker } from '../SwatchPicker';

describe('ColorSwatch', () => {
isConformant({
Component: ColorSwatch,
displayName: 'ColorSwatch',
disabledTests: ['has-top-level-file-extra'],
});

it('emits selected and disabled state attributes', () => {
const { getByRole } = render(<ColorSwatch color="#f09" value="pink" aria-label="Pink" />, {
wrapper: ({ children }) => (
<SwatchPicker aria-label="Colors" selectedValue="pink">
{children}
</SwatchPicker>
),
});
const swatch = getByRole('radio');
expect(swatch).toHaveAttribute('aria-label', 'Pink');
expect(swatch).toHaveAttribute('aria-checked', 'true');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use client';

import * as React from 'react';
import type { ForwardRefComponent } from '@fluentui/react-utilities';
import type { ColorSwatchProps } from './ColorSwatch.types';
import { useColorSwatch } from './useColorSwatch';
import { renderColorSwatch } from './renderColorSwatch';

export const ColorSwatch: ForwardRefComponent<ColorSwatchProps> = React.forwardRef((props, ref) => {
const state = useColorSwatch(props, ref);
return renderColorSwatch(state);
});

ColorSwatch.displayName = 'ColorSwatch';
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type {
ColorSwatchBaseProps as ColorSwatchProps,
ColorSwatchSlots,
ColorSwatchBaseState as ColorSwatchState,
} from '@fluentui/react-swatch-picker';
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { ColorSwatch } from './ColorSwatch';
export { renderColorSwatch } from './renderColorSwatch';
export { useColorSwatch } from './useColorSwatch';
export type { ColorSwatchSlots, ColorSwatchProps, ColorSwatchState } from './ColorSwatch.types';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { renderColorSwatch_unstable as renderColorSwatch } from '@fluentui/react-swatch-picker';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { useColorSwatchBase_unstable as useColorSwatch } from '@fluentui/react-swatch-picker';
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react';
import { render } from '@testing-library/react';
import { isConformant } from '../../../testing/isConformant';
import { EmptySwatch } from './EmptySwatch';

describe('EmptySwatch', () => {
isConformant({ Component: EmptySwatch, displayName: 'EmptySwatch', disabledTests: ['has-top-level-file-extra'] });

it('renders a native radio swatch', () => {
expect(render(<EmptySwatch aria-label="Empty" />).getByRole('radio')).toHaveAttribute('aria-checked', 'false');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use client';

import * as React from 'react';
import type { ForwardRefComponent } from '@fluentui/react-utilities';
import type { EmptySwatchProps } from './EmptySwatch.types';
import { useEmptySwatch } from './useEmptySwatch';
import { renderEmptySwatch } from './renderEmptySwatch';

export const EmptySwatch: ForwardRefComponent<EmptySwatchProps> = React.forwardRef((props, ref) => {
const state = useEmptySwatch(props, ref);
return renderEmptySwatch(state);
});

EmptySwatch.displayName = 'EmptySwatch';
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type {
EmptySwatchBaseProps as EmptySwatchProps,
EmptySwatchSlots,
EmptySwatchBaseState as EmptySwatchState,
} from '@fluentui/react-swatch-picker';
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { EmptySwatch } from './EmptySwatch';
export { renderEmptySwatch } from './renderEmptySwatch';
export { useEmptySwatch } from './useEmptySwatch';
export type { EmptySwatchSlots, EmptySwatchProps, EmptySwatchState } from './EmptySwatch.types';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { renderEmptySwatch_unstable as renderEmptySwatch } from '@fluentui/react-swatch-picker';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { useEmptySwatchBase_unstable as useEmptySwatch } from '@fluentui/react-swatch-picker';
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as React from 'react';
import { render } from '@testing-library/react';
import { isConformant } from '../../../testing/isConformant';
import { ImageSwatch } from './ImageSwatch';
import { SwatchPicker } from '../SwatchPicker';

describe('ImageSwatch', () => {
isConformant({ Component: ImageSwatch, displayName: 'ImageSwatch', disabledTests: ['has-top-level-file-extra'] });

it('renders an image swatch with its selection state', () => {
const { getByRole } = render(<ImageSwatch src="image.png" value="image" aria-label="Image" />, {
wrapper: ({ children }) => <SwatchPicker selectedValue="image">{children}</SwatchPicker>,
});

expect(getByRole('radio')).toHaveAttribute('data-selected', '');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use client';

import * as React from 'react';
import type { ForwardRefComponent } from '@fluentui/react-utilities';
import type { ImageSwatchProps } from './ImageSwatch.types';
import { useImageSwatch } from './useImageSwatch';
import { renderImageSwatch } from './renderImageSwatch';

export const ImageSwatch: ForwardRefComponent<ImageSwatchProps> = React.forwardRef((props, ref) => {
const state = useImageSwatch(props, ref);
return renderImageSwatch(state);
});

ImageSwatch.displayName = 'ImageSwatch';
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type {
ImageSwatchBaseProps,
ImageSwatchBaseState,
ImageSwatchSlots as ImageSwatchBaseSlots,
} from '@fluentui/react-swatch-picker';

export type ImageSwatchProps = ImageSwatchBaseProps;

export type ImageSwatchSlots = ImageSwatchBaseSlots;

export type ImageSwatchState = ImageSwatchBaseState & {
root: {
'data-selected'?: string;
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { ImageSwatch } from './ImageSwatch';
export { renderImageSwatch } from './renderImageSwatch';
export { useImageSwatch } from './useImageSwatch';
export type { ImageSwatchSlots, ImageSwatchProps, ImageSwatchState } from './ImageSwatch.types';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { renderImageSwatch_unstable as renderImageSwatch } from '@fluentui/react-swatch-picker';
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use client';

import type * as React from 'react';
import { useImageSwatchBase_unstable } from '@fluentui/react-swatch-picker';
import { stringifyDataAttribute } from '../../../utils/stringifyDataAttribute';
import type { ImageSwatchProps, ImageSwatchState } from './ImageSwatch.types';

export const useImageSwatch = (props: ImageSwatchProps, ref: React.Ref<HTMLButtonElement>): ImageSwatchState => {
const state: ImageSwatchState = useImageSwatchBase_unstable(props, ref);

// eslint-disable-next-line react-hooks/immutability
state.root['data-selected'] = stringifyDataAttribute(state.selected);

return state;
};
Loading