Skip to content

Commit eb2f46e

Browse files
authored
feat(react-headless-components-preview): expose ToastTitle intent sta… (#36640)
1 parent 25b0646 commit eb2f46e

5 files changed

Lines changed: 43 additions & 21 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "patch",
3+
"comment": "feat: expose ToastTitle intent state via data attribute",
4+
"packageName": "@fluentui/react-headless-components-preview",
5+
"email": "dmytrokirpa@microsoft.com"
6+
}

packages/react-components/react-headless-components-preview/library/etc/toast.api.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ import { ToastPosition } from '@fluentui/react-toast';
3434
import { ToastBaseProps as ToastProps } from '@fluentui/react-toast';
3535
import { ToastSlots } from '@fluentui/react-toast';
3636
import { ToastStatus } from '@fluentui/react-toast';
37+
import type { ToastTitleBaseState } from '@fluentui/react-toast';
3738
import { ToastTitleBaseProps as ToastTitleProps } from '@fluentui/react-toast';
3839
import { ToastTitleSlots } from '@fluentui/react-toast';
39-
import { ToastTitleBaseState as ToastTitleState } from '@fluentui/react-toast';
4040
import { useToastBodyBase_unstable as useToastBody } from '@fluentui/react-toast';
4141
import { useToastContainerContext } from '@fluentui/react-toast';
4242
import { useToastController } from '@fluentui/react-toast';
@@ -152,7 +152,12 @@ export { ToastTitleProps }
152152

153153
export { ToastTitleSlots }
154154

155-
export { ToastTitleState }
155+
// @public (undocumented)
156+
export type ToastTitleState = ToastTitleBaseState & {
157+
media?: ToastTitleBaseState['media'] & {
158+
'data-intent'?: ToastTitleBaseState['intent'];
159+
};
160+
};
156161

157162
// @public
158163
export const useToast: (props: ToastProps, ref: React_2.Ref<HTMLElement>) => ToastState;

packages/react-components/react-headless-components-preview/library/src/components/Toast/Toast.cy.tsx

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@ import { Provider } from '../Provider';
88
/**
99
* Selectors used by the headless tests. Unlike the styled v9 layer, the headless
1010
* Toast does not emit Griffel class names — we target structural roles and the
11-
* `data-intent` attribute the headless `Toast` adds to its root.
11+
* structural roles on the headless `ToastContainer` root.
1212
*/
1313
const TOAST_CONTAINER = '[role="listitem"]';
14-
const TOAST = '[data-intent]';
1514

1615
const mount = (element: JSXElement) =>
1716
mountBase(
@@ -43,7 +42,7 @@ describe('Toast (headless)', () => {
4342
};
4443

4544
mount(<Example />);
46-
cy.get('button').click().get(TOAST).should('exist');
45+
cy.get('button').click().get(TOAST_CONTAINER).should('exist');
4746
});
4847

4948
it('should dismiss toast', () => {
@@ -73,8 +72,8 @@ describe('Toast (headless)', () => {
7372
};
7473

7574
mount(<Example />);
76-
cy.get('#make').click().get(TOAST).should('exist');
77-
cy.get('#dismiss').click().get(TOAST).should('not.exist');
75+
cy.get('#make').click().get(TOAST_CONTAINER).should('exist');
76+
cy.get('#dismiss').click().get(TOAST_CONTAINER).should('not.exist');
7877
});
7978

8079
it('should dismiss all toasts', () => {
@@ -105,8 +104,8 @@ describe('Toast (headless)', () => {
105104
};
106105

107106
mount(<Example />);
108-
cy.get('#make').click().get(TOAST).should('have.length', 5);
109-
cy.get('#dismiss').click().get(TOAST).should('not.exist');
107+
cy.get('#make').click().get(TOAST_CONTAINER).should('have.length', 5);
108+
cy.get('#dismiss').click().get(TOAST_CONTAINER).should('not.exist');
110109
});
111110

112111
it('should play and pause toast', () => {
@@ -138,9 +137,9 @@ describe('Toast (headless)', () => {
138137
};
139138

140139
mount(<Example />);
141-
cy.get('#make').click().get(TOAST).should('exist');
142-
cy.get('#pause').click().wait(1000).get(TOAST).should('exist');
143-
cy.get('#play').click().get(TOAST).should('not.exist');
140+
cy.get('#make').click().get(TOAST_CONTAINER).should('exist');
141+
cy.get('#pause').click().wait(1000).get(TOAST_CONTAINER).should('exist');
142+
cy.get('#play').click().get(TOAST_CONTAINER).should('not.exist');
144143
});
145144

146145
it('should update toast content', () => {
@@ -178,7 +177,7 @@ describe('Toast (headless)', () => {
178177
};
179178

180179
mount(<Example />);
181-
cy.get('#make').click().get(TOAST).should('exist');
180+
cy.get('#make').click().get(TOAST_CONTAINER).should('exist');
182181
cy.get('#update').click().get('body').contains('Foo');
183182
});
184183

@@ -204,7 +203,7 @@ describe('Toast (headless)', () => {
204203
};
205204

206205
mount(<Example />);
207-
cy.get('#make').click().get(TOAST).trigger('mouseenter').wait(700).get(TOAST).should('exist');
206+
cy.get('#make').click().get(TOAST_CONTAINER).trigger('mouseenter').wait(700).get(TOAST_CONTAINER).should('exist');
208207
});
209208

210209
it('should follow lifecycle', () => {

packages/react-components/react-headless-components-preview/library/src/components/Toast/ToastTitle/ToastTitle.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,21 @@
22

33
import * as React from 'react';
44
import type { ForwardRefComponent } from '@fluentui/react-utilities';
5-
import type { ToastTitleProps } from './ToastTitle.types';
5+
import type { ToastTitleProps, ToastTitleState } from './ToastTitle.types';
66
import { useToastTitle } from './useToastTitle';
77
import { renderToastTitle } from './renderToastTitle';
88

99
/**
1010
* Represents the title of a toast, which is a brief summary or headline for the toast message.
1111
*/
1212
export const ToastTitle: ForwardRefComponent<ToastTitleProps> = React.forwardRef((props, ref) => {
13-
const state = useToastTitle(props, ref);
13+
const state: ToastTitleState = useToastTitle(props, ref);
14+
15+
if (state.media) {
16+
// eslint-disable-next-line react-hooks/immutability
17+
state.media['data-intent'] = state.intent;
18+
}
19+
1420
return renderToastTitle(state);
1521
});
1622

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
export type {
2-
ToastTitleBaseProps as ToastTitleProps,
3-
ToastTitleBaseState as ToastTitleState,
4-
ToastTitleSlots,
5-
} from '@fluentui/react-toast';
1+
import type { ToastTitleBaseState } from '@fluentui/react-toast';
2+
export type { ToastTitleBaseProps as ToastTitleProps, ToastTitleSlots } from '@fluentui/react-toast';
3+
4+
export type ToastTitleState = ToastTitleBaseState & {
5+
media?: ToastTitleBaseState['media'] & {
6+
/**
7+
* The intent of the toast, used for styling purposes.
8+
*/
9+
'data-intent'?: ToastTitleBaseState['intent'];
10+
};
11+
};

0 commit comments

Comments
 (0)