@fluentui/react-aria 0.0.0-nightly-20241023-0407.1 → 0.0.0-nightly-20241028-0410.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,23 +1,23 @@
1
1
  # Change Log - @fluentui/react-aria
2
2
 
3
- This log was last generated on Wed, 23 Oct 2024 04:11:49 GMT and should not be manually modified.
3
+ This log was last generated on Mon, 28 Oct 2024 04:15:16 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
- ## [0.0.0-nightly-20241023-0407.1](https://github.com/microsoft/fluentui/tree/@fluentui/react-aria_v0.0.0-nightly-20241023-0407.1)
7
+ ## [0.0.0-nightly-20241028-0410.1](https://github.com/microsoft/fluentui/tree/@fluentui/react-aria_v0.0.0-nightly-20241028-0410.1)
8
8
 
9
- Wed, 23 Oct 2024 04:11:49 GMT
10
- [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-aria_v9.13.8..@fluentui/react-aria_v0.0.0-nightly-20241023-0407.1)
9
+ Mon, 28 Oct 2024 04:15:16 GMT
10
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-aria_v9.13.8..@fluentui/react-aria_v0.0.0-nightly-20241028-0410.1)
11
11
 
12
12
  ### Changes
13
13
 
14
14
  - Release nightly v9 ([commit](https://github.com/microsoft/fluentui/commit/not available) by fluentui-internal@service.microsoft.com)
15
- - Bump @fluentui/keyboard-keys to v0.0.0-nightly-20241023-0407.1 ([commit](https://github.com/microsoft/fluentui/commit/2d148a24ef86132106a54676eb87418afe7b84b2) by beachball)
16
- - Bump @fluentui/react-shared-contexts to v0.0.0-nightly-20241023-0407.1 ([commit](https://github.com/microsoft/fluentui/commit/2d148a24ef86132106a54676eb87418afe7b84b2) by beachball)
17
- - Bump @fluentui/react-jsx-runtime to v0.0.0-nightly-20241023-0407.1 ([commit](https://github.com/microsoft/fluentui/commit/2d148a24ef86132106a54676eb87418afe7b84b2) by beachball)
18
- - Bump @fluentui/react-tabster to v0.0.0-nightly-20241023-0407.1 ([commit](https://github.com/microsoft/fluentui/commit/2d148a24ef86132106a54676eb87418afe7b84b2) by beachball)
19
- - Bump @fluentui/react-utilities to v0.0.0-nightly-20241023-0407.1 ([commit](https://github.com/microsoft/fluentui/commit/2d148a24ef86132106a54676eb87418afe7b84b2) by beachball)
20
- - Bump @fluentui/react-conformance to v0.0.0-nightly-20241023-0407.1 ([commit](https://github.com/microsoft/fluentui/commit/2d148a24ef86132106a54676eb87418afe7b84b2) by beachball)
15
+ - Bump @fluentui/keyboard-keys to v0.0.0-nightly-20241028-0410.1 ([commit](https://github.com/microsoft/fluentui/commit/4e26fc20abf5c2554aa571266c0689dcd4aa585b) by beachball)
16
+ - Bump @fluentui/react-shared-contexts to v0.0.0-nightly-20241028-0410.1 ([commit](https://github.com/microsoft/fluentui/commit/4e26fc20abf5c2554aa571266c0689dcd4aa585b) by beachball)
17
+ - Bump @fluentui/react-jsx-runtime to v0.0.0-nightly-20241028-0410.1 ([commit](https://github.com/microsoft/fluentui/commit/4e26fc20abf5c2554aa571266c0689dcd4aa585b) by beachball)
18
+ - Bump @fluentui/react-tabster to v0.0.0-nightly-20241028-0410.1 ([commit](https://github.com/microsoft/fluentui/commit/4e26fc20abf5c2554aa571266c0689dcd4aa585b) by beachball)
19
+ - Bump @fluentui/react-utilities to v0.0.0-nightly-20241028-0410.1 ([commit](https://github.com/microsoft/fluentui/commit/4e26fc20abf5c2554aa571266c0689dcd4aa585b) by beachball)
20
+ - Bump @fluentui/react-conformance to v0.0.0-nightly-20241028-0410.1 ([commit](https://github.com/microsoft/fluentui/commit/4e26fc20abf5c2554aa571266c0689dcd4aa585b) by beachball)
21
21
 
22
22
  ## [9.13.8](https://github.com/microsoft/fluentui/tree/@fluentui/react-aria_v9.13.8)
23
23
 
@@ -87,9 +87,16 @@ import * as React from 'react';
87
87
  onKeyDown: disabledFocusable ? undefined : onKeyDown
88
88
  };
89
89
  } else {
90
+ // the role needs to be explicitly set if the href is undefined
91
+ const isLink = !!rest.href;
92
+ let roleOverride = isLink ? undefined : 'button';
93
+ if (!roleOverride && isDisabled) {
94
+ // need to set role=link explicitly for disabled links
95
+ roleOverride = 'link';
96
+ }
90
97
  const resultProps = {
91
- role: 'button',
92
- tabIndex: disabled && !disabledFocusable ? undefined : 0,
98
+ role: roleOverride,
99
+ tabIndex: disabledFocusable || !isLink && !disabled ? 0 : undefined,
93
100
  ...rest,
94
101
  // If it's not a <button> than listeners are required even with disabledFocusable
95
102
  // Since you cannot assure the default behavior of the element
@@ -97,7 +104,7 @@ import * as React from 'react';
97
104
  onClick: handleClick,
98
105
  onKeyUp: handleKeyUp,
99
106
  onKeyDown: handleKeyDown,
100
- 'aria-disabled': disabled || disabledFocusable || normalizedARIADisabled
107
+ 'aria-disabled': isDisabled
101
108
  };
102
109
  if (type === 'a' && isDisabled) {
103
110
  resultProps.href = undefined;
@@ -1 +1 @@
1
- {"version":3,"sources":["useARIAButtonProps.ts"],"sourcesContent":["import { Enter, Space } from '@fluentui/keyboard-keys';\nimport { useEventCallback } from '@fluentui/react-utilities';\nimport * as React from 'react';\nimport type { ARIAButtonElementIntersection, ARIAButtonProps, ARIAButtonResultProps, ARIAButtonType } from './types';\n\n/**\n * @internal\n *\n * Button keyboard handling, role, disabled and tabIndex implementation that ensures ARIA spec\n * for multiple scenarios of non native button elements. Ensuring 1st rule of ARIA for cases\n * where no attribute addition is required.\n *\n * @param type - the proper scenario to be interpreted by the hook.\n * 1. `button` - Minimal interference from the hook, as semantic button already supports most of the states\n * 2. `a` or `div` - Proper keyboard/mouse handling plus other support to ensure ARIA behavior\n * @param props - the props to be passed down the line to the desired element.\n * This hook will encapsulate proper properties, such as `onClick`, `onKeyDown`, `onKeyUp`, etc,.\n *\n * @example\n * ```tsx\n * const buttonProps = useARIAButtonProps('a', {\n * href: './some-route'\n * onClick: () => console.log('this should run both on click and Space and Enter')\n * })\n *\n * // ...\n *\n * return (\n * <a {...buttonProps}>This anchor will behave as a proper button</a>\n * )\n * ```\n */\nexport function useARIAButtonProps<Type extends ARIAButtonType, Props extends ARIAButtonProps<Type>>(\n type?: Type,\n props?: Props,\n): ARIAButtonResultProps<Type, Props> {\n const {\n disabled,\n disabledFocusable = false,\n ['aria-disabled']: ariaDisabled,\n onClick,\n onKeyDown,\n onKeyUp,\n ...rest\n } = props ?? {};\n\n const normalizedARIADisabled = typeof ariaDisabled === 'string' ? ariaDisabled === 'true' : ariaDisabled;\n\n const isDisabled = disabled || disabledFocusable || normalizedARIADisabled;\n\n const handleClick = useEventCallback((ev: React.MouseEvent<ARIAButtonElementIntersection>) => {\n if (isDisabled) {\n ev.preventDefault();\n ev.stopPropagation();\n } else {\n onClick?.(ev);\n }\n });\n\n const handleKeyDown = useEventCallback((ev: React.KeyboardEvent<ARIAButtonElementIntersection>) => {\n onKeyDown?.(ev);\n\n if (ev.isDefaultPrevented()) {\n return;\n }\n\n const key = ev.key;\n\n if (isDisabled && (key === Enter || key === Space)) {\n ev.preventDefault();\n ev.stopPropagation();\n return;\n }\n\n if (key === Space) {\n ev.preventDefault();\n return;\n }\n\n // If enter is pressed, activate the button\n else if (key === Enter) {\n ev.preventDefault();\n ev.currentTarget.click();\n }\n });\n\n const handleKeyUp = useEventCallback((ev: React.KeyboardEvent<ARIAButtonElementIntersection>) => {\n onKeyUp?.(ev);\n\n if (ev.isDefaultPrevented()) {\n return;\n }\n\n const key = ev.key;\n\n if (isDisabled && (key === Enter || key === Space)) {\n ev.preventDefault();\n ev.stopPropagation();\n return;\n }\n\n if (key === Space) {\n ev.preventDefault();\n ev.currentTarget.click();\n }\n });\n\n // If a <button> tag is to be rendered we just need to set disabled and aria-disabled correctly\n if (type === 'button' || type === undefined) {\n return {\n ...rest,\n disabled: disabled && !disabledFocusable,\n 'aria-disabled': disabledFocusable ? true : normalizedARIADisabled,\n // onclick should still use internal handler to ensure prevention if disabled\n // if disabledFocusable then there's no requirement for handlers as those events should not be propagated\n onClick: disabledFocusable ? undefined : handleClick,\n onKeyUp: disabledFocusable ? undefined : onKeyUp,\n onKeyDown: disabledFocusable ? undefined : onKeyDown,\n } as ARIAButtonResultProps<Type, Props>;\n }\n\n // If an <a> or <div> tag is to be rendered we have to remove disabled and type,\n // and set aria-disabled, role and tabIndex.\n else {\n const resultProps = {\n role: 'button',\n tabIndex: disabled && !disabledFocusable ? undefined : 0,\n ...rest,\n // If it's not a <button> than listeners are required even with disabledFocusable\n // Since you cannot assure the default behavior of the element\n // E.g: <a> will redirect on click\n onClick: handleClick,\n onKeyUp: handleKeyUp,\n onKeyDown: handleKeyDown,\n 'aria-disabled': disabled || disabledFocusable || normalizedARIADisabled,\n } as ARIAButtonResultProps<Type, Props>;\n\n if (type === 'a' && isDisabled) {\n (resultProps as ARIAButtonResultProps<'a', Props>).href = undefined;\n }\n\n return resultProps;\n }\n}\n"],"names":["Enter","Space","useEventCallback","React","useARIAButtonProps","type","props","disabled","disabledFocusable","ariaDisabled","onClick","onKeyDown","onKeyUp","rest","normalizedARIADisabled","isDisabled","handleClick","ev","preventDefault","stopPropagation","handleKeyDown","isDefaultPrevented","key","currentTarget","click","handleKeyUp","undefined","resultProps","role","tabIndex","href"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,KAAK,EAAEC,KAAK,QAAQ,0BAA0B;AACvD,SAASC,gBAAgB,QAAQ,4BAA4B;AAC7D,YAAYC,WAAW,QAAQ;AAG/B;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BC,GACD,OAAO,SAASC,mBACdC,IAAW,EACXC,KAAa;IAEb,MAAM,EACJC,QAAQ,EACRC,oBAAoB,KAAK,EACzB,CAAC,gBAAgB,EAAEC,YAAY,EAC/BC,OAAO,EACPC,SAAS,EACTC,OAAO,EACP,GAAGC,MACJ,GAAGP,kBAAAA,mBAAAA,QAAS,CAAC;IAEd,MAAMQ,yBAAyB,OAAOL,iBAAiB,WAAWA,iBAAiB,SAASA;IAE5F,MAAMM,aAAaR,YAAYC,qBAAqBM;IAEpD,MAAME,cAAcd,iBAAiB,CAACe;QACpC,IAAIF,YAAY;YACdE,GAAGC,cAAc;YACjBD,GAAGE,eAAe;QACpB,OAAO;YACLT,oBAAAA,8BAAAA,QAAUO;QACZ;IACF;IAEA,MAAMG,gBAAgBlB,iBAAiB,CAACe;QACtCN,sBAAAA,gCAAAA,UAAYM;QAEZ,IAAIA,GAAGI,kBAAkB,IAAI;YAC3B;QACF;QAEA,MAAMC,MAAML,GAAGK,GAAG;QAElB,IAAIP,cAAeO,CAAAA,QAAQtB,SAASsB,QAAQrB,KAAI,GAAI;YAClDgB,GAAGC,cAAc;YACjBD,GAAGE,eAAe;YAClB;QACF;QAEA,IAAIG,QAAQrB,OAAO;YACjBgB,GAAGC,cAAc;YACjB;QACF,OAGK,IAAII,QAAQtB,OAAO;YACtBiB,GAAGC,cAAc;YACjBD,GAAGM,aAAa,CAACC,KAAK;QACxB;IACF;IAEA,MAAMC,cAAcvB,iBAAiB,CAACe;QACpCL,oBAAAA,8BAAAA,QAAUK;QAEV,IAAIA,GAAGI,kBAAkB,IAAI;YAC3B;QACF;QAEA,MAAMC,MAAML,GAAGK,GAAG;QAElB,IAAIP,cAAeO,CAAAA,QAAQtB,SAASsB,QAAQrB,KAAI,GAAI;YAClDgB,GAAGC,cAAc;YACjBD,GAAGE,eAAe;YAClB;QACF;QAEA,IAAIG,QAAQrB,OAAO;YACjBgB,GAAGC,cAAc;YACjBD,GAAGM,aAAa,CAACC,KAAK;QACxB;IACF;IAEA,+FAA+F;IAC/F,IAAInB,SAAS,YAAYA,SAASqB,WAAW;QAC3C,OAAO;YACL,GAAGb,IAAI;YACPN,UAAUA,YAAY,CAACC;YACvB,iBAAiBA,oBAAoB,OAAOM;YAC5C,6EAA6E;YAC7E,yGAAyG;YACzGJ,SAASF,oBAAoBkB,YAAYV;YACzCJ,SAASJ,oBAAoBkB,YAAYd;YACzCD,WAAWH,oBAAoBkB,YAAYf;QAC7C;IACF,OAIK;QACH,MAAMgB,cAAc;YAClBC,MAAM;YACNC,UAAUtB,YAAY,CAACC,oBAAoBkB,YAAY;YACvD,GAAGb,IAAI;YACP,iFAAiF;YACjF,8DAA8D;YAC9D,kCAAkC;YAClCH,SAASM;YACTJ,SAASa;YACTd,WAAWS;YACX,iBAAiBb,YAAYC,qBAAqBM;QACpD;QAEA,IAAIT,SAAS,OAAOU,YAAY;YAC7BY,YAAkDG,IAAI,GAAGJ;QAC5D;QAEA,OAAOC;IACT;AACF"}
1
+ {"version":3,"sources":["useARIAButtonProps.ts"],"sourcesContent":["import { Enter, Space } from '@fluentui/keyboard-keys';\nimport { useEventCallback } from '@fluentui/react-utilities';\nimport * as React from 'react';\nimport type { ARIAButtonElementIntersection, ARIAButtonProps, ARIAButtonResultProps, ARIAButtonType } from './types';\n\n/**\n * @internal\n *\n * Button keyboard handling, role, disabled and tabIndex implementation that ensures ARIA spec\n * for multiple scenarios of non native button elements. Ensuring 1st rule of ARIA for cases\n * where no attribute addition is required.\n *\n * @param type - the proper scenario to be interpreted by the hook.\n * 1. `button` - Minimal interference from the hook, as semantic button already supports most of the states\n * 2. `a` or `div` - Proper keyboard/mouse handling plus other support to ensure ARIA behavior\n * @param props - the props to be passed down the line to the desired element.\n * This hook will encapsulate proper properties, such as `onClick`, `onKeyDown`, `onKeyUp`, etc,.\n *\n * @example\n * ```tsx\n * const buttonProps = useARIAButtonProps('a', {\n * href: './some-route'\n * onClick: () => console.log('this should run both on click and Space and Enter')\n * })\n *\n * // ...\n *\n * return (\n * <a {...buttonProps}>This anchor will behave as a proper button</a>\n * )\n * ```\n */\nexport function useARIAButtonProps<Type extends ARIAButtonType, Props extends ARIAButtonProps<Type>>(\n type?: Type,\n props?: Props,\n): ARIAButtonResultProps<Type, Props> {\n const {\n disabled,\n disabledFocusable = false,\n ['aria-disabled']: ariaDisabled,\n onClick,\n onKeyDown,\n onKeyUp,\n ...rest\n } = props ?? {};\n\n const normalizedARIADisabled = typeof ariaDisabled === 'string' ? ariaDisabled === 'true' : ariaDisabled;\n\n const isDisabled = disabled || disabledFocusable || normalizedARIADisabled;\n\n const handleClick = useEventCallback((ev: React.MouseEvent<ARIAButtonElementIntersection>) => {\n if (isDisabled) {\n ev.preventDefault();\n ev.stopPropagation();\n } else {\n onClick?.(ev);\n }\n });\n\n const handleKeyDown = useEventCallback((ev: React.KeyboardEvent<ARIAButtonElementIntersection>) => {\n onKeyDown?.(ev);\n\n if (ev.isDefaultPrevented()) {\n return;\n }\n\n const key = ev.key;\n\n if (isDisabled && (key === Enter || key === Space)) {\n ev.preventDefault();\n ev.stopPropagation();\n return;\n }\n\n if (key === Space) {\n ev.preventDefault();\n return;\n }\n\n // If enter is pressed, activate the button\n else if (key === Enter) {\n ev.preventDefault();\n ev.currentTarget.click();\n }\n });\n\n const handleKeyUp = useEventCallback((ev: React.KeyboardEvent<ARIAButtonElementIntersection>) => {\n onKeyUp?.(ev);\n\n if (ev.isDefaultPrevented()) {\n return;\n }\n\n const key = ev.key;\n\n if (isDisabled && (key === Enter || key === Space)) {\n ev.preventDefault();\n ev.stopPropagation();\n return;\n }\n\n if (key === Space) {\n ev.preventDefault();\n ev.currentTarget.click();\n }\n });\n\n // If a <button> tag is to be rendered we just need to set disabled and aria-disabled correctly\n if (type === 'button' || type === undefined) {\n return {\n ...rest,\n disabled: disabled && !disabledFocusable,\n 'aria-disabled': disabledFocusable ? true : normalizedARIADisabled,\n // onclick should still use internal handler to ensure prevention if disabled\n // if disabledFocusable then there's no requirement for handlers as those events should not be propagated\n onClick: disabledFocusable ? undefined : handleClick,\n onKeyUp: disabledFocusable ? undefined : onKeyUp,\n onKeyDown: disabledFocusable ? undefined : onKeyDown,\n } as ARIAButtonResultProps<Type, Props>;\n }\n\n // If an <a> or <div> tag is to be rendered we have to remove disabled and type,\n // and set aria-disabled, role and tabIndex.\n else {\n // the role needs to be explicitly set if the href is undefined\n const isLink = !!(rest as ARIAButtonResultProps<'a', Props>).href;\n let roleOverride = isLink ? undefined : 'button';\n if (!roleOverride && isDisabled) {\n // need to set role=link explicitly for disabled links\n roleOverride = 'link';\n }\n\n const resultProps = {\n role: roleOverride,\n tabIndex: disabledFocusable || (!isLink && !disabled) ? 0 : undefined,\n ...rest,\n // If it's not a <button> than listeners are required even with disabledFocusable\n // Since you cannot assure the default behavior of the element\n // E.g: <a> will redirect on click\n onClick: handleClick,\n onKeyUp: handleKeyUp,\n onKeyDown: handleKeyDown,\n 'aria-disabled': isDisabled,\n } as ARIAButtonResultProps<Type, Props>;\n\n if (type === 'a' && isDisabled) {\n (resultProps as ARIAButtonResultProps<'a', Props>).href = undefined;\n }\n\n return resultProps;\n }\n}\n"],"names":["Enter","Space","useEventCallback","React","useARIAButtonProps","type","props","disabled","disabledFocusable","ariaDisabled","onClick","onKeyDown","onKeyUp","rest","normalizedARIADisabled","isDisabled","handleClick","ev","preventDefault","stopPropagation","handleKeyDown","isDefaultPrevented","key","currentTarget","click","handleKeyUp","undefined","isLink","href","roleOverride","resultProps","role","tabIndex"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,KAAK,EAAEC,KAAK,QAAQ,0BAA0B;AACvD,SAASC,gBAAgB,QAAQ,4BAA4B;AAC7D,YAAYC,WAAW,QAAQ;AAG/B;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BC,GACD,OAAO,SAASC,mBACdC,IAAW,EACXC,KAAa;IAEb,MAAM,EACJC,QAAQ,EACRC,oBAAoB,KAAK,EACzB,CAAC,gBAAgB,EAAEC,YAAY,EAC/BC,OAAO,EACPC,SAAS,EACTC,OAAO,EACP,GAAGC,MACJ,GAAGP,kBAAAA,mBAAAA,QAAS,CAAC;IAEd,MAAMQ,yBAAyB,OAAOL,iBAAiB,WAAWA,iBAAiB,SAASA;IAE5F,MAAMM,aAAaR,YAAYC,qBAAqBM;IAEpD,MAAME,cAAcd,iBAAiB,CAACe;QACpC,IAAIF,YAAY;YACdE,GAAGC,cAAc;YACjBD,GAAGE,eAAe;QACpB,OAAO;YACLT,oBAAAA,8BAAAA,QAAUO;QACZ;IACF;IAEA,MAAMG,gBAAgBlB,iBAAiB,CAACe;QACtCN,sBAAAA,gCAAAA,UAAYM;QAEZ,IAAIA,GAAGI,kBAAkB,IAAI;YAC3B;QACF;QAEA,MAAMC,MAAML,GAAGK,GAAG;QAElB,IAAIP,cAAeO,CAAAA,QAAQtB,SAASsB,QAAQrB,KAAI,GAAI;YAClDgB,GAAGC,cAAc;YACjBD,GAAGE,eAAe;YAClB;QACF;QAEA,IAAIG,QAAQrB,OAAO;YACjBgB,GAAGC,cAAc;YACjB;QACF,OAGK,IAAII,QAAQtB,OAAO;YACtBiB,GAAGC,cAAc;YACjBD,GAAGM,aAAa,CAACC,KAAK;QACxB;IACF;IAEA,MAAMC,cAAcvB,iBAAiB,CAACe;QACpCL,oBAAAA,8BAAAA,QAAUK;QAEV,IAAIA,GAAGI,kBAAkB,IAAI;YAC3B;QACF;QAEA,MAAMC,MAAML,GAAGK,GAAG;QAElB,IAAIP,cAAeO,CAAAA,QAAQtB,SAASsB,QAAQrB,KAAI,GAAI;YAClDgB,GAAGC,cAAc;YACjBD,GAAGE,eAAe;YAClB;QACF;QAEA,IAAIG,QAAQrB,OAAO;YACjBgB,GAAGC,cAAc;YACjBD,GAAGM,aAAa,CAACC,KAAK;QACxB;IACF;IAEA,+FAA+F;IAC/F,IAAInB,SAAS,YAAYA,SAASqB,WAAW;QAC3C,OAAO;YACL,GAAGb,IAAI;YACPN,UAAUA,YAAY,CAACC;YACvB,iBAAiBA,oBAAoB,OAAOM;YAC5C,6EAA6E;YAC7E,yGAAyG;YACzGJ,SAASF,oBAAoBkB,YAAYV;YACzCJ,SAASJ,oBAAoBkB,YAAYd;YACzCD,WAAWH,oBAAoBkB,YAAYf;QAC7C;IACF,OAIK;QACH,+DAA+D;QAC/D,MAAMgB,SAAS,CAAC,CAAC,AAACd,KAA2Ce,IAAI;QACjE,IAAIC,eAAeF,SAASD,YAAY;QACxC,IAAI,CAACG,gBAAgBd,YAAY;YAC/B,sDAAsD;YACtDc,eAAe;QACjB;QAEA,MAAMC,cAAc;YAClBC,MAAMF;YACNG,UAAUxB,qBAAsB,CAACmB,UAAU,CAACpB,WAAY,IAAImB;YAC5D,GAAGb,IAAI;YACP,iFAAiF;YACjF,8DAA8D;YAC9D,kCAAkC;YAClCH,SAASM;YACTJ,SAASa;YACTd,WAAWS;YACX,iBAAiBL;QACnB;QAEA,IAAIV,SAAS,OAAOU,YAAY;YAC7Be,YAAkDF,IAAI,GAAGF;QAC5D;QAEA,OAAOI;IACT;AACF"}
@@ -72,9 +72,16 @@ function useARIAButtonProps(type, props) {
72
72
  onKeyDown: disabledFocusable ? undefined : onKeyDown
73
73
  };
74
74
  } else {
75
+ // the role needs to be explicitly set if the href is undefined
76
+ const isLink = !!rest.href;
77
+ let roleOverride = isLink ? undefined : 'button';
78
+ if (!roleOverride && isDisabled) {
79
+ // need to set role=link explicitly for disabled links
80
+ roleOverride = 'link';
81
+ }
75
82
  const resultProps = {
76
- role: 'button',
77
- tabIndex: disabled && !disabledFocusable ? undefined : 0,
83
+ role: roleOverride,
84
+ tabIndex: disabledFocusable || !isLink && !disabled ? 0 : undefined,
78
85
  ...rest,
79
86
  // If it's not a <button> than listeners are required even with disabledFocusable
80
87
  // Since you cannot assure the default behavior of the element
@@ -82,7 +89,7 @@ function useARIAButtonProps(type, props) {
82
89
  onClick: handleClick,
83
90
  onKeyUp: handleKeyUp,
84
91
  onKeyDown: handleKeyDown,
85
- 'aria-disabled': disabled || disabledFocusable || normalizedARIADisabled
92
+ 'aria-disabled': isDisabled
86
93
  };
87
94
  if (type === 'a' && isDisabled) {
88
95
  resultProps.href = undefined;
@@ -1 +1 @@
1
- {"version":3,"sources":["useARIAButtonProps.ts"],"sourcesContent":["import { Enter, Space } from '@fluentui/keyboard-keys';\nimport { useEventCallback } from '@fluentui/react-utilities';\nimport * as React from 'react';\nimport type { ARIAButtonElementIntersection, ARIAButtonProps, ARIAButtonResultProps, ARIAButtonType } from './types';\n\n/**\n * @internal\n *\n * Button keyboard handling, role, disabled and tabIndex implementation that ensures ARIA spec\n * for multiple scenarios of non native button elements. Ensuring 1st rule of ARIA for cases\n * where no attribute addition is required.\n *\n * @param type - the proper scenario to be interpreted by the hook.\n * 1. `button` - Minimal interference from the hook, as semantic button already supports most of the states\n * 2. `a` or `div` - Proper keyboard/mouse handling plus other support to ensure ARIA behavior\n * @param props - the props to be passed down the line to the desired element.\n * This hook will encapsulate proper properties, such as `onClick`, `onKeyDown`, `onKeyUp`, etc,.\n *\n * @example\n * ```tsx\n * const buttonProps = useARIAButtonProps('a', {\n * href: './some-route'\n * onClick: () => console.log('this should run both on click and Space and Enter')\n * })\n *\n * // ...\n *\n * return (\n * <a {...buttonProps}>This anchor will behave as a proper button</a>\n * )\n * ```\n */\nexport function useARIAButtonProps<Type extends ARIAButtonType, Props extends ARIAButtonProps<Type>>(\n type?: Type,\n props?: Props,\n): ARIAButtonResultProps<Type, Props> {\n const {\n disabled,\n disabledFocusable = false,\n ['aria-disabled']: ariaDisabled,\n onClick,\n onKeyDown,\n onKeyUp,\n ...rest\n } = props ?? {};\n\n const normalizedARIADisabled = typeof ariaDisabled === 'string' ? ariaDisabled === 'true' : ariaDisabled;\n\n const isDisabled = disabled || disabledFocusable || normalizedARIADisabled;\n\n const handleClick = useEventCallback((ev: React.MouseEvent<ARIAButtonElementIntersection>) => {\n if (isDisabled) {\n ev.preventDefault();\n ev.stopPropagation();\n } else {\n onClick?.(ev);\n }\n });\n\n const handleKeyDown = useEventCallback((ev: React.KeyboardEvent<ARIAButtonElementIntersection>) => {\n onKeyDown?.(ev);\n\n if (ev.isDefaultPrevented()) {\n return;\n }\n\n const key = ev.key;\n\n if (isDisabled && (key === Enter || key === Space)) {\n ev.preventDefault();\n ev.stopPropagation();\n return;\n }\n\n if (key === Space) {\n ev.preventDefault();\n return;\n }\n\n // If enter is pressed, activate the button\n else if (key === Enter) {\n ev.preventDefault();\n ev.currentTarget.click();\n }\n });\n\n const handleKeyUp = useEventCallback((ev: React.KeyboardEvent<ARIAButtonElementIntersection>) => {\n onKeyUp?.(ev);\n\n if (ev.isDefaultPrevented()) {\n return;\n }\n\n const key = ev.key;\n\n if (isDisabled && (key === Enter || key === Space)) {\n ev.preventDefault();\n ev.stopPropagation();\n return;\n }\n\n if (key === Space) {\n ev.preventDefault();\n ev.currentTarget.click();\n }\n });\n\n // If a <button> tag is to be rendered we just need to set disabled and aria-disabled correctly\n if (type === 'button' || type === undefined) {\n return {\n ...rest,\n disabled: disabled && !disabledFocusable,\n 'aria-disabled': disabledFocusable ? true : normalizedARIADisabled,\n // onclick should still use internal handler to ensure prevention if disabled\n // if disabledFocusable then there's no requirement for handlers as those events should not be propagated\n onClick: disabledFocusable ? undefined : handleClick,\n onKeyUp: disabledFocusable ? undefined : onKeyUp,\n onKeyDown: disabledFocusable ? undefined : onKeyDown,\n } as ARIAButtonResultProps<Type, Props>;\n }\n\n // If an <a> or <div> tag is to be rendered we have to remove disabled and type,\n // and set aria-disabled, role and tabIndex.\n else {\n const resultProps = {\n role: 'button',\n tabIndex: disabled && !disabledFocusable ? undefined : 0,\n ...rest,\n // If it's not a <button> than listeners are required even with disabledFocusable\n // Since you cannot assure the default behavior of the element\n // E.g: <a> will redirect on click\n onClick: handleClick,\n onKeyUp: handleKeyUp,\n onKeyDown: handleKeyDown,\n 'aria-disabled': disabled || disabledFocusable || normalizedARIADisabled,\n } as ARIAButtonResultProps<Type, Props>;\n\n if (type === 'a' && isDisabled) {\n (resultProps as ARIAButtonResultProps<'a', Props>).href = undefined;\n }\n\n return resultProps;\n }\n}\n"],"names":["useARIAButtonProps","type","props","disabled","disabledFocusable","ariaDisabled","onClick","onKeyDown","onKeyUp","rest","normalizedARIADisabled","isDisabled","handleClick","useEventCallback","ev","preventDefault","stopPropagation","handleKeyDown","isDefaultPrevented","key","Enter","Space","currentTarget","click","handleKeyUp","undefined","resultProps","role","tabIndex","href"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAgCgBA;;;eAAAA;;;;8BAhCa;gCACI;iEACV;AA8BhB,SAASA,mBACdC,IAAW,EACXC,KAAa;IAEb,MAAM,EACJC,QAAQ,EACRC,oBAAoB,KAAK,EACzB,CAAC,gBAAgB,EAAEC,YAAY,EAC/BC,OAAO,EACPC,SAAS,EACTC,OAAO,EACP,GAAGC,MACJ,GAAGP,UAAAA,QAAAA,UAAAA,KAAAA,IAAAA,QAAS,CAAC;IAEd,MAAMQ,yBAAyB,OAAOL,iBAAiB,WAAWA,iBAAiB,SAASA;IAE5F,MAAMM,aAAaR,YAAYC,qBAAqBM;IAEpD,MAAME,cAAcC,IAAAA,gCAAAA,EAAiB,CAACC;QACpC,IAAIH,YAAY;YACdG,GAAGC,cAAc;YACjBD,GAAGE,eAAe;QACpB,OAAO;YACLV,YAAAA,QAAAA,YAAAA,KAAAA,IAAAA,KAAAA,IAAAA,QAAUQ;QACZ;IACF;IAEA,MAAMG,gBAAgBJ,IAAAA,gCAAAA,EAAiB,CAACC;QACtCP,cAAAA,QAAAA,cAAAA,KAAAA,IAAAA,KAAAA,IAAAA,UAAYO;QAEZ,IAAIA,GAAGI,kBAAkB,IAAI;YAC3B;QACF;QAEA,MAAMC,MAAML,GAAGK,GAAG;QAElB,IAAIR,cAAeQ,CAAAA,QAAQC,mBAAAA,IAASD,QAAQE,mBAAI,AAAJA,GAAQ;YAClDP,GAAGC,cAAc;YACjBD,GAAGE,eAAe;YAClB;QACF;QAEA,IAAIG,QAAQE,mBAAAA,EAAO;YACjBP,GAAGC,cAAc;YACjB;QACF,OAGK,IAAII,QAAQC,mBAAAA,EAAO;YACtBN,GAAGC,cAAc;YACjBD,GAAGQ,aAAa,CAACC,KAAK;QACxB;IACF;IAEA,MAAMC,cAAcX,IAAAA,gCAAAA,EAAiB,CAACC;QACpCN,YAAAA,QAAAA,YAAAA,KAAAA,IAAAA,KAAAA,IAAAA,QAAUM;QAEV,IAAIA,GAAGI,kBAAkB,IAAI;YAC3B;QACF;QAEA,MAAMC,MAAML,GAAGK,GAAG;QAElB,IAAIR,cAAeQ,CAAAA,QAAQC,mBAAAA,IAASD,QAAQE,mBAAI,AAAJA,GAAQ;YAClDP,GAAGC,cAAc;YACjBD,GAAGE,eAAe;YAClB;QACF;QAEA,IAAIG,QAAQE,mBAAAA,EAAO;YACjBP,GAAGC,cAAc;YACjBD,GAAGQ,aAAa,CAACC,KAAK;QACxB;IACF;IAEA,+FAA+F;IAC/F,IAAItB,SAAS,YAAYA,SAASwB,WAAW;QAC3C,OAAO;YACL,GAAGhB,IAAI;YACPN,UAAUA,YAAY,CAACC;YACvB,iBAAiBA,oBAAoB,OAAOM;YAC5C,6EAA6E;YAC7E,yGAAyG;YACzGJ,SAASF,oBAAoBqB,YAAYb;YACzCJ,SAASJ,oBAAoBqB,YAAYjB;YACzCD,WAAWH,oBAAoBqB,YAAYlB;QAC7C;IACF,OAIK;QACH,MAAMmB,cAAc;YAClBC,MAAM;YACNC,UAAUzB,YAAY,CAACC,oBAAoBqB,YAAY;YACvD,GAAGhB,IAAI;YACP,iFAAiF;YACjF,8DAA8D;YAC9D,kCAAkC;YAClCH,SAASM;YACTJ,SAASgB;YACTjB,WAAWU;YACX,iBAAiBd,YAAYC,qBAAqBM;QACpD;QAEA,IAAIT,SAAS,OAAOU,YAAY;YAC7Be,YAAkDG,IAAI,GAAGJ;QAC5D;QAEA,OAAOC;IACT;AACF"}
1
+ {"version":3,"sources":["useARIAButtonProps.ts"],"sourcesContent":["import { Enter, Space } from '@fluentui/keyboard-keys';\nimport { useEventCallback } from '@fluentui/react-utilities';\nimport * as React from 'react';\nimport type { ARIAButtonElementIntersection, ARIAButtonProps, ARIAButtonResultProps, ARIAButtonType } from './types';\n\n/**\n * @internal\n *\n * Button keyboard handling, role, disabled and tabIndex implementation that ensures ARIA spec\n * for multiple scenarios of non native button elements. Ensuring 1st rule of ARIA for cases\n * where no attribute addition is required.\n *\n * @param type - the proper scenario to be interpreted by the hook.\n * 1. `button` - Minimal interference from the hook, as semantic button already supports most of the states\n * 2. `a` or `div` - Proper keyboard/mouse handling plus other support to ensure ARIA behavior\n * @param props - the props to be passed down the line to the desired element.\n * This hook will encapsulate proper properties, such as `onClick`, `onKeyDown`, `onKeyUp`, etc,.\n *\n * @example\n * ```tsx\n * const buttonProps = useARIAButtonProps('a', {\n * href: './some-route'\n * onClick: () => console.log('this should run both on click and Space and Enter')\n * })\n *\n * // ...\n *\n * return (\n * <a {...buttonProps}>This anchor will behave as a proper button</a>\n * )\n * ```\n */\nexport function useARIAButtonProps<Type extends ARIAButtonType, Props extends ARIAButtonProps<Type>>(\n type?: Type,\n props?: Props,\n): ARIAButtonResultProps<Type, Props> {\n const {\n disabled,\n disabledFocusable = false,\n ['aria-disabled']: ariaDisabled,\n onClick,\n onKeyDown,\n onKeyUp,\n ...rest\n } = props ?? {};\n\n const normalizedARIADisabled = typeof ariaDisabled === 'string' ? ariaDisabled === 'true' : ariaDisabled;\n\n const isDisabled = disabled || disabledFocusable || normalizedARIADisabled;\n\n const handleClick = useEventCallback((ev: React.MouseEvent<ARIAButtonElementIntersection>) => {\n if (isDisabled) {\n ev.preventDefault();\n ev.stopPropagation();\n } else {\n onClick?.(ev);\n }\n });\n\n const handleKeyDown = useEventCallback((ev: React.KeyboardEvent<ARIAButtonElementIntersection>) => {\n onKeyDown?.(ev);\n\n if (ev.isDefaultPrevented()) {\n return;\n }\n\n const key = ev.key;\n\n if (isDisabled && (key === Enter || key === Space)) {\n ev.preventDefault();\n ev.stopPropagation();\n return;\n }\n\n if (key === Space) {\n ev.preventDefault();\n return;\n }\n\n // If enter is pressed, activate the button\n else if (key === Enter) {\n ev.preventDefault();\n ev.currentTarget.click();\n }\n });\n\n const handleKeyUp = useEventCallback((ev: React.KeyboardEvent<ARIAButtonElementIntersection>) => {\n onKeyUp?.(ev);\n\n if (ev.isDefaultPrevented()) {\n return;\n }\n\n const key = ev.key;\n\n if (isDisabled && (key === Enter || key === Space)) {\n ev.preventDefault();\n ev.stopPropagation();\n return;\n }\n\n if (key === Space) {\n ev.preventDefault();\n ev.currentTarget.click();\n }\n });\n\n // If a <button> tag is to be rendered we just need to set disabled and aria-disabled correctly\n if (type === 'button' || type === undefined) {\n return {\n ...rest,\n disabled: disabled && !disabledFocusable,\n 'aria-disabled': disabledFocusable ? true : normalizedARIADisabled,\n // onclick should still use internal handler to ensure prevention if disabled\n // if disabledFocusable then there's no requirement for handlers as those events should not be propagated\n onClick: disabledFocusable ? undefined : handleClick,\n onKeyUp: disabledFocusable ? undefined : onKeyUp,\n onKeyDown: disabledFocusable ? undefined : onKeyDown,\n } as ARIAButtonResultProps<Type, Props>;\n }\n\n // If an <a> or <div> tag is to be rendered we have to remove disabled and type,\n // and set aria-disabled, role and tabIndex.\n else {\n // the role needs to be explicitly set if the href is undefined\n const isLink = !!(rest as ARIAButtonResultProps<'a', Props>).href;\n let roleOverride = isLink ? undefined : 'button';\n if (!roleOverride && isDisabled) {\n // need to set role=link explicitly for disabled links\n roleOverride = 'link';\n }\n\n const resultProps = {\n role: roleOverride,\n tabIndex: disabledFocusable || (!isLink && !disabled) ? 0 : undefined,\n ...rest,\n // If it's not a <button> than listeners are required even with disabledFocusable\n // Since you cannot assure the default behavior of the element\n // E.g: <a> will redirect on click\n onClick: handleClick,\n onKeyUp: handleKeyUp,\n onKeyDown: handleKeyDown,\n 'aria-disabled': isDisabled,\n } as ARIAButtonResultProps<Type, Props>;\n\n if (type === 'a' && isDisabled) {\n (resultProps as ARIAButtonResultProps<'a', Props>).href = undefined;\n }\n\n return resultProps;\n }\n}\n"],"names":["useARIAButtonProps","type","props","disabled","disabledFocusable","ariaDisabled","onClick","onKeyDown","onKeyUp","rest","normalizedARIADisabled","isDisabled","handleClick","useEventCallback","ev","preventDefault","stopPropagation","handleKeyDown","isDefaultPrevented","key","Enter","Space","currentTarget","click","handleKeyUp","undefined","isLink","href","roleOverride","resultProps","role","tabIndex"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAgCgBA;;;eAAAA;;;;8BAhCa;gCACI;iEACV;AA8BhB,SAASA,mBACdC,IAAW,EACXC,KAAa;IAEb,MAAM,EACJC,QAAQ,EACRC,oBAAoB,KAAK,EACzB,CAAC,gBAAgB,EAAEC,YAAY,EAC/BC,OAAO,EACPC,SAAS,EACTC,OAAO,EACP,GAAGC,MACJ,GAAGP,UAAAA,QAAAA,UAAAA,KAAAA,IAAAA,QAAS,CAAC;IAEd,MAAMQ,yBAAyB,OAAOL,iBAAiB,WAAWA,iBAAiB,SAASA;IAE5F,MAAMM,aAAaR,YAAYC,qBAAqBM;IAEpD,MAAME,cAAcC,IAAAA,gCAAAA,EAAiB,CAACC;QACpC,IAAIH,YAAY;YACdG,GAAGC,cAAc;YACjBD,GAAGE,eAAe;QACpB,OAAO;YACLV,YAAAA,QAAAA,YAAAA,KAAAA,IAAAA,KAAAA,IAAAA,QAAUQ;QACZ;IACF;IAEA,MAAMG,gBAAgBJ,IAAAA,gCAAAA,EAAiB,CAACC;QACtCP,cAAAA,QAAAA,cAAAA,KAAAA,IAAAA,KAAAA,IAAAA,UAAYO;QAEZ,IAAIA,GAAGI,kBAAkB,IAAI;YAC3B;QACF;QAEA,MAAMC,MAAML,GAAGK,GAAG;QAElB,IAAIR,cAAeQ,CAAAA,QAAQC,mBAAAA,IAASD,QAAQE,mBAAI,AAAJA,GAAQ;YAClDP,GAAGC,cAAc;YACjBD,GAAGE,eAAe;YAClB;QACF;QAEA,IAAIG,QAAQE,mBAAAA,EAAO;YACjBP,GAAGC,cAAc;YACjB;QACF,OAGK,IAAII,QAAQC,mBAAAA,EAAO;YACtBN,GAAGC,cAAc;YACjBD,GAAGQ,aAAa,CAACC,KAAK;QACxB;IACF;IAEA,MAAMC,cAAcX,IAAAA,gCAAAA,EAAiB,CAACC;QACpCN,YAAAA,QAAAA,YAAAA,KAAAA,IAAAA,KAAAA,IAAAA,QAAUM;QAEV,IAAIA,GAAGI,kBAAkB,IAAI;YAC3B;QACF;QAEA,MAAMC,MAAML,GAAGK,GAAG;QAElB,IAAIR,cAAeQ,CAAAA,QAAQC,mBAAAA,IAASD,QAAQE,mBAAI,AAAJA,GAAQ;YAClDP,GAAGC,cAAc;YACjBD,GAAGE,eAAe;YAClB;QACF;QAEA,IAAIG,QAAQE,mBAAAA,EAAO;YACjBP,GAAGC,cAAc;YACjBD,GAAGQ,aAAa,CAACC,KAAK;QACxB;IACF;IAEA,+FAA+F;IAC/F,IAAItB,SAAS,YAAYA,SAASwB,WAAW;QAC3C,OAAO;YACL,GAAGhB,IAAI;YACPN,UAAUA,YAAY,CAACC;YACvB,iBAAiBA,oBAAoB,OAAOM;YAC5C,6EAA6E;YAC7E,yGAAyG;YACzGJ,SAASF,oBAAoBqB,YAAYb;YACzCJ,SAASJ,oBAAoBqB,YAAYjB;YACzCD,WAAWH,oBAAoBqB,YAAYlB;QAC7C;IACF,OAIK;QACH,+DAA+D;QAC/D,MAAMmB,SAAS,CAAC,CAACjB,KAA4CkB,IAAI;QACjE,IAAIC,eAAeF,SAASD,YAAY;QACxC,IAAI,CAACG,gBAAgBjB,YAAY;YAC/B,sDAAsD;YACtDiB,eAAe;QACjB;QAEA,MAAMC,cAAc;YAClBC,MAAMF;YACNG,UAAU3B,qBAAsB,CAACsB,UAAU,CAACvB,WAAY,IAAIsB;YAC5D,GAAGhB,IAAI;YACP,iFAAiF;YACjF,8DAA8D;YAC9D,kCAAkC;YAClCH,SAASM;YACTJ,SAASgB;YACTjB,WAAWU;YACX,iBAAiBN;QACnB;QAEA,IAAIV,SAAS,OAAOU,YAAY;YAC7BkB,YAAkDF,IAAI,GAAGF;QAC5D;QAEA,OAAOI;IACT;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluentui/react-aria",
3
- "version": "0.0.0-nightly-20241023-0407.1",
3
+ "version": "0.0.0-nightly-20241028-0410.1",
4
4
  "description": "React helper to ensure ARIA",
5
5
  "main": "lib-commonjs/index.js",
6
6
  "module": "lib/index.js",
@@ -27,17 +27,17 @@
27
27
  },
28
28
  "devDependencies": {
29
29
  "@fluentui/eslint-plugin": "*",
30
- "@fluentui/react-conformance": "0.0.0-nightly-20241023-0407.1",
30
+ "@fluentui/react-conformance": "0.0.0-nightly-20241028-0410.1",
31
31
  "@fluentui/scripts-api-extractor": "*",
32
32
  "@fluentui/scripts-tasks": "*",
33
33
  "@fluentui/scripts-cypress": "*"
34
34
  },
35
35
  "dependencies": {
36
- "@fluentui/keyboard-keys": "0.0.0-nightly-20241023-0407.1",
37
- "@fluentui/react-shared-contexts": "0.0.0-nightly-20241023-0407.1",
38
- "@fluentui/react-jsx-runtime": "0.0.0-nightly-20241023-0407.1",
39
- "@fluentui/react-tabster": "0.0.0-nightly-20241023-0407.1",
40
- "@fluentui/react-utilities": "0.0.0-nightly-20241023-0407.1",
36
+ "@fluentui/keyboard-keys": "0.0.0-nightly-20241028-0410.1",
37
+ "@fluentui/react-shared-contexts": "0.0.0-nightly-20241028-0410.1",
38
+ "@fluentui/react-jsx-runtime": "0.0.0-nightly-20241028-0410.1",
39
+ "@fluentui/react-tabster": "0.0.0-nightly-20241028-0410.1",
40
+ "@fluentui/react-utilities": "0.0.0-nightly-20241028-0410.1",
41
41
  "@swc/helpers": "^0.5.1"
42
42
  },
43
43
  "peerDependencies": {