@@ -26,47 +26,16 @@ export function isMotionDisabled(element: HTMLElement): boolean {
2626 ) ;
2727}
2828
29- // Note that this hook doesn't take into consideration @media print (unlike the dark mode CSS),
30- // due to challenges with cross-browser implementations of media/print state change listeners.
31- // This means that components using this hook will render in dark mode even when printing.
32- export function useCurrentMode ( elementRef : React . RefObject < HTMLElement > ) {
33- const [ value , setValue ] = useState < 'light' | 'dark' > ( 'light' ) ;
34- useMutationObserver ( elementRef , node => {
35- const darkModeParent = findUpUntil (
36- node ,
37- node => node . classList . contains ( 'awsui-polaris-dark-mode' ) || node . classList . contains ( 'awsui-dark-mode' )
38- ) ;
39- const newValue = darkModeParent ? 'dark' : 'light' ;
40-
41- // refer to the comment below in `useReducedMotion`
42- if ( newValue !== value ) {
43- setValue ( newValue ) ;
44- }
45- } ) ;
46- return value ;
47- }
48-
49- export function useDensityMode ( elementRef : React . RefObject < HTMLElement > ) {
50- const [ value , setValue ] = useState < 'comfortable' | 'compact' > ( 'comfortable' ) ;
51- useMutationObserver ( elementRef , node => {
52- const compactModeParent = findUpUntil (
53- node ,
54- node => node . classList . contains ( 'awsui-polaris-compact-mode' ) || node . classList . contains ( 'awsui-compact-mode' )
55- ) ;
56- const newValue = compactModeParent ? 'compact' : 'comfortable' ;
57-
58- // refer to the comment below in `useReducedMotion`
59- if ( newValue !== value ) {
60- setValue ( newValue ) ;
61- }
62- } ) ;
63- return value ;
64- }
65-
66- export function useReducedMotion ( elementRef : React . RefObject < HTMLElement > ) {
67- const [ value , setValue ] = useState ( false ) ;
29+ // Generic hook for detecting mode changes via DOM mutation observation.
30+ // Prevents unnecessary re-renders by only updating state when the value actually changes.
31+ function useModeDetector < T > (
32+ elementRef : React . RefObject < HTMLElement > ,
33+ detector : ( node : HTMLElement ) => T ,
34+ initialValue : T
35+ ) : T {
36+ const [ value , setValue ] = useState < T > ( initialValue ) ;
6837 useMutationObserver ( elementRef , node => {
69- const newValue = isMotionDisabled ( node ) ;
38+ const newValue = detector ( node ) ;
7039 /**
7140 * React has a behavior that triggers a re-render even if the same value is provided in the setState, while it does not
7241 * commit any changes to the DOM (commit phase) the function rerenders. This causes a false react act warnings in testing
@@ -82,6 +51,37 @@ export function useReducedMotion(elementRef: React.RefObject<HTMLElement>) {
8251 return value ;
8352}
8453
54+ function detectCurrentMode ( node : HTMLElement ) : 'light' | 'dark' {
55+ const darkModeParent = findUpUntil (
56+ node ,
57+ node => node . classList . contains ( 'awsui-polaris-dark-mode' ) || node . classList . contains ( 'awsui-dark-mode' )
58+ ) ;
59+ return darkModeParent ? 'dark' : 'light' ;
60+ }
61+
62+ function detectDensityMode ( node : HTMLElement ) : 'comfortable' | 'compact' {
63+ const compactModeParent = findUpUntil (
64+ node ,
65+ node => node . classList . contains ( 'awsui-polaris-compact-mode' ) || node . classList . contains ( 'awsui-compact-mode' )
66+ ) ;
67+ return compactModeParent ? 'compact' : 'comfortable' ;
68+ }
69+
70+ // Note that this hook doesn't take into consideration @media print (unlike the dark mode CSS),
71+ // due to challenges with cross-browser implementations of media/print state change listeners.
72+ // This means that components using this hook will render in dark mode even when printing.
73+ export function useCurrentMode ( elementRef : React . RefObject < HTMLElement > ) {
74+ return useModeDetector ( elementRef , detectCurrentMode , 'light' ) ;
75+ }
76+
77+ export function useDensityMode ( elementRef : React . RefObject < HTMLElement > ) {
78+ return useModeDetector ( elementRef , detectDensityMode , 'comfortable' ) ;
79+ }
80+
81+ export function useReducedMotion ( elementRef : React . RefObject < HTMLElement > ) {
82+ return useModeDetector ( elementRef , isMotionDisabled , false ) ;
83+ }
84+
8585const useMutationSingleton = createSingletonHandler < void > ( handler => {
8686 const observer = new MutationObserver ( ( ) => handler ( ) ) ;
8787 observer . observe ( document . body , { attributes : true , subtree : true } ) ;
0 commit comments