@codecademy/gamut 67.6.3 → 67.6.4-alpha.09d6ed.0
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/dist/ConnectedForm/ConnectedFormGroup.d.ts +5 -0
- package/dist/ConnectedForm/ConnectedFormGroup.js +1 -1
- package/dist/Form/elements/FormGroupLabel.js +8 -2
- package/dist/GridForm/GridFormInputGroup/__fixtures__/renderers.d.ts +4 -0
- package/dist/GridForm/types.d.ts +5 -0
- package/dist/Tip/InfoTip/InfoTipButton.js +5 -2
- package/dist/Tip/InfoTip/index.d.ts +18 -0
- package/dist/Tip/InfoTip/index.js +46 -68
- package/dist/Tip/__tests__/helpers.d.ts +5 -26
- package/dist/Tip/shared/FloatingTip.js +3 -3
- package/dist/Tip/shared/InlineTip.js +4 -1
- package/dist/Tip/shared/types.d.ts +1 -1
- package/dist/Tip/shared/utils.d.ts +19 -0
- package/dist/Tip/shared/utils.js +104 -0
- package/package.json +2 -2
- package/dist/Tip/InfoTip/elements.d.ts +0 -12
- package/dist/Tip/InfoTip/elements.js +0 -9
|
@@ -8,6 +8,11 @@ export interface ConnectedFormGroupBaseProps extends Omit<FormGroupProps, 'label
|
|
|
8
8
|
name: string;
|
|
9
9
|
label: React.ReactNode;
|
|
10
10
|
required?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* InfoTip to display next to the field label. String labels automatically
|
|
13
|
+
* label the InfoTip button. For ReactNode labels, provide `ariaLabel` or
|
|
14
|
+
* set `labelledByFieldLabel: true` to ensure the InfoTip is accessible.
|
|
15
|
+
*/
|
|
11
16
|
infotip?: InfoTipProps;
|
|
12
17
|
}
|
|
13
18
|
export interface ConnectedFormGroupProps<T extends ConnectedField> extends SubmitContextProps, ConnectedFormGroupBaseProps {
|
|
@@ -13,7 +13,7 @@ const ErrorAnchor = /*#__PURE__*/_styled(Anchor, {
|
|
|
13
13
|
label: "ErrorAnchor"
|
|
14
14
|
})(css({
|
|
15
15
|
color: 'feedback-error'
|
|
16
|
-
}), process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
16
|
+
}), process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9Db25uZWN0ZWRGb3JtL0Nvbm5lY3RlZEZvcm1Hcm91cC50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBa0JvQiIsImZpbGUiOiIuLi8uLi9zcmMvQ29ubmVjdGVkRm9ybS9Db25uZWN0ZWRGb3JtR3JvdXAudHN4Iiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY3NzIH0gZnJvbSAnQGNvZGVjYWRlbXkvZ2FtdXQtc3R5bGVzJztcbmltcG9ydCBzdHlsZWQgZnJvbSAnQGVtb3Rpb24vc3R5bGVkJztcbmltcG9ydCB7IHVzZUVmZmVjdCB9IGZyb20gJ3JlYWN0JztcbmltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0JztcblxuaW1wb3J0IHtcbiAgRm9ybUVycm9yLFxuICBGb3JtR3JvdXAsXG4gIEZvcm1Hcm91cExhYmVsLFxuICBGb3JtR3JvdXBQcm9wcyxcbiAgSW5mb1RpcFByb3BzLFxufSBmcm9tICcuLic7XG5pbXBvcnQgeyBBbmNob3IgfSBmcm9tICcuLi9BbmNob3InO1xuaW1wb3J0IHsgSGlkZGVuVGV4dCB9IGZyb20gJy4uL0hpZGRlblRleHQnO1xuaW1wb3J0IHsgTWFya2Rvd24gfSBmcm9tICcuLi9NYXJrZG93bic7XG5pbXBvcnQgeyBDb25uZWN0ZWRGaWVsZCwgRmllbGRQcm9wcywgU3VibWl0Q29udGV4dFByb3BzIH0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBnZXRFcnJvck1lc3NhZ2UsIHVzZUZpZWxkIH0gZnJvbSAnLi91dGlscyc7XG5cbmNvbnN0IEVycm9yQW5jaG9yID0gc3R5bGVkKEFuY2hvcikoXG4gIGNzcyh7XG4gICAgY29sb3I6ICdmZWVkYmFjay1lcnJvcicsXG4gIH0pXG4pO1xuXG5leHBvcnQgaW50ZXJmYWNlIENvbm5lY3RlZEZvcm1Hcm91cEJhc2VQcm9wc1xuICBleHRlbmRzIE9taXQ8XG4gICAgRm9ybUdyb3VwUHJvcHMsXG4gICAgJ2xhYmVsJyB8ICdkaXNhYmxlZCcgfCAnZGVzY3JpcHRpb24nIHwgJ2h0bWxGb3InXG4gID4ge1xuICBjdXN0b21FcnJvcj86IHN0cmluZztcbiAgZXJyb3JUeXBlPzogJ2luaXRpYWwnIHwgJ2Fic29sdXRlJztcbiAgaGlkZUxhYmVsPzogYm9vbGVhbjtcbiAgbmFtZTogc3RyaW5nO1xuICBsYWJlbDogUmVhY3QuUmVhY3ROb2RlO1xuICByZXF1aXJlZD86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBJbmZvVGlwIHRvIGRpc3BsYXkgbmV4dCB0byB0aGUgZmllbGQgbGFiZWwuIFN0cmluZyBsYWJlbHMgYXV0b21hdGljYWxseVxuICAgKiBsYWJlbCB0aGUgSW5mb1RpcCBidXR0b24uIEZvciBSZWFjdE5vZGUgbGFiZWxzLCBwcm92aWRlIGBhcmlhTGFiZWxgIG9yXG4gICAqIHNldCBgbGFiZWxsZWRCeUZpZWxkTGFiZWw6IHRydWVgIHRvIGVuc3VyZSB0aGUgSW5mb1RpcCBpcyBhY2Nlc3NpYmxlLlxuICAgKi9cbiAgaW5mb3RpcD86IEluZm9UaXBQcm9wcztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb25uZWN0ZWRGb3JtR3JvdXBQcm9wczxUIGV4dGVuZHMgQ29ubmVjdGVkRmllbGQ+XG4gIGV4dGVuZHMgU3VibWl0Q29udGV4dFByb3BzLFxuICAgIENvbm5lY3RlZEZvcm1Hcm91cEJhc2VQcm9wcyB7XG4gIC8qKlxuICAgKiBBbiBvYmplY3QgY29uc2lzdGluZyBvZiBhIGBjb21wb25lbnRgIGtleSB0byBzcGVjaWZ5IHdoYXQgQ29ubmVjdGVkRm9ybUlucHV0IHRvIHJlbmRlciAtIHRoZSByZW1haW5pbmcga2V5L3ZhbHVlIHBhaXJzIGFyZSB0aGF0IGNvbXBvbmVudHMgZGVzaXJlZCBwcm9wcy5cbiAgICovXG4gIGZpZWxkOiBPbWl0PFJlYWN0LkNvbXBvbmVudFByb3BzPFQ+LCAnbmFtZScgfCAnZGlzYWJsZWQnPiAmIEZpZWxkUHJvcHM8VD47XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBDb25uZWN0ZWRGb3JtR3JvdXA8VCBleHRlbmRzIENvbm5lY3RlZEZpZWxkPih7XG4gIGN1c3RvbUVycm9yLFxuICBjaGlsZHJlbixcbiAgZGlzYWJsZWQgPSBmYWxzZSxcbiAgZXJyb3JUeXBlID0gJ2Fic29sdXRlJyxcbiAgZmllbGQsXG4gIGhpZGVMYWJlbCxcbiAgaWQsXG4gIGxhYmVsLFxuICBuYW1lLFxuICBsYWJlbFNpemUsXG4gIHNwYWNpbmcgPSAnZml0JyxcbiAgaXNTb2xvRmllbGQsXG4gIGluZm90aXAsXG59OiBDb25uZWN0ZWRGb3JtR3JvdXBQcm9wczxUPikge1xuICBjb25zdCB7IGVycm9yLCBpc0ZpcnN0RXJyb3IsIGlzRGlzYWJsZWQsIHNldEVycm9yLCB2YWxpZGF0aW9uIH0gPSB1c2VGaWVsZCh7XG4gICAgbmFtZSxcbiAgICBkaXNhYmxlZCxcbiAgfSk7XG4gIGNvbnN0IHsgY29tcG9uZW50OiBDb21wb25lbnQsIC4uLnJlc3QgfSA9IGZpZWxkO1xuXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgaWYgKGN1c3RvbUVycm9yKSB7XG4gICAgICBzZXRFcnJvcihuYW1lLCB7XG4gICAgICAgIHR5cGU6ICdtYW51YWwnLFxuICAgICAgICBtZXNzYWdlOiBjdXN0b21FcnJvcixcbiAgICAgIH0pO1xuICAgIH1cbiAgfSwgW2N1c3RvbUVycm9yLCBuYW1lLCBzZXRFcnJvcl0pO1xuXG4gIGNvbnN0IHJlbmRlcmVkTGFiZWwgPSAoXG4gICAgPEZvcm1Hcm91cExhYmVsXG4gICAgICBkaXNhYmxlZD17aXNEaXNhYmxlZH1cbiAgICAgIGh0bWxGb3I9e2lkIHx8IG5hbWV9XG4gICAgICBpbmZvdGlwPXtpbmZvdGlwfVxuICAgICAgaXNTb2xvRmllbGQ9e2lzU29sb0ZpZWxkfVxuICAgICAgcmVxdWlyZWQ9eyEhdmFsaWRhdGlvbj8ucmVxdWlyZWR9XG4gICAgICBzaXplPXtsYWJlbFNpemV9XG4gICAgPlxuICAgICAge2xhYmVsfVxuICAgIDwvRm9ybUdyb3VwTGFiZWw+XG4gICk7XG5cbiAgY29uc3QgdGV4dEVycm9yID0gY3VzdG9tRXJyb3IgfHwgZ2V0RXJyb3JNZXNzYWdlKGVycm9yKTtcbiAgY29uc3Qgc2hvd0Vycm9yID0gISEodGV4dEVycm9yICYmICFoaWRlTGFiZWwpO1xuICBjb25zdCBlcnJvcklkID0gc2hvd0Vycm9yID8gYCR7aWQgfHwgbmFtZX1fZXJyb3JgIDogdW5kZWZpbmVkO1xuXG4gIHJldHVybiAoXG4gICAgPEZvcm1Hcm91cCBzcGFjaW5nPXtoaWRlTGFiZWwgPyAndGlnaHQnIDogc3BhY2luZ30+XG4gICAgICB7aGlkZUxhYmVsID8gPEhpZGRlblRleHQ+e3JlbmRlcmVkTGFiZWx9PC9IaWRkZW5UZXh0PiA6IHJlbmRlcmVkTGFiZWx9XG4gICAgICA8Q29tcG9uZW50XG4gICAgICAgIHsuLi4ocmVzdCBhcyBhbnkpfVxuICAgICAgICBhcmlhLWRlc2NyaWJlZGJ5PXtlcnJvcklkfVxuICAgICAgICBhcmlhLWludmFsaWQ9e3Nob3dFcnJvcn1cbiAgICAgICAgZGlzYWJsZWQ9e2Rpc2FibGVkfVxuICAgICAgICBuYW1lPXtuYW1lfVxuICAgICAgLz5cbiAgICAgIHtjaGlsZHJlbn1cbiAgICAgIHtzaG93RXJyb3IgJiYgKFxuICAgICAgICA8Rm9ybUVycm9yXG4gICAgICAgICAgYXJpYS1saXZlPXtpc0ZpcnN0RXJyb3IgPyAnYXNzZXJ0aXZlJyA6ICdvZmYnfVxuICAgICAgICAgIGlkPXtlcnJvcklkfVxuICAgICAgICAgIHJvbGU9e2lzRmlyc3RFcnJvciA/ICdhbGVydCcgOiAnc3RhdHVzJ31cbiAgICAgICAgICB2YXJpYW50PXtlcnJvclR5cGV9XG4gICAgICAgID5cbiAgICAgICAgICA8TWFya2Rvd25cbiAgICAgICAgICAgIGlubGluZVxuICAgICAgICAgICAgb3ZlcnJpZGVzPXt7XG4gICAgICAgICAgICAgIGE6IHtcbiAgICAgICAgICAgICAgICBhbGxvd2VkQXR0cmlidXRlczogWydocmVmJywgJ3RhcmdldCddLFxuICAgICAgICAgICAgICAgIGNvbXBvbmVudDogRXJyb3JBbmNob3IsXG4gICAgICAgICAgICAgICAgcHJvY2Vzc05vZGU6IChcbiAgICAgICAgICAgICAgICAgIG5vZGU6IHVua25vd24sXG4gICAgICAgICAgICAgICAgICBwcm9wczogeyBvbkNsaWNrPzogKCkgPT4gdm9pZCB9XG4gICAgICAgICAgICAgICAgKSA9PiA8RXJyb3JBbmNob3Igey4uLnByb3BzfSAvPixcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH19XG4gICAgICAgICAgICBza2lwRGVmYXVsdE92ZXJyaWRlcz17eyBhOiB0cnVlIH19XG4gICAgICAgICAgICBzcGFjaW5nPVwibm9uZVwiXG4gICAgICAgICAgICB0ZXh0PXt0ZXh0RXJyb3J9XG4gICAgICAgICAgLz5cbiAgICAgICAgPC9Gb3JtRXJyb3I+XG4gICAgICApfVxuICAgIDwvRm9ybUdyb3VwPlxuICApO1xufVxuIl19 */");
|
|
17
17
|
export function ConnectedFormGroup({
|
|
18
18
|
customError,
|
|
19
19
|
children,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import _styled from "@emotion/styled/base";
|
|
2
2
|
import { states, variant } from '@codecademy/gamut-styles';
|
|
3
|
+
import { useId } from 'react';
|
|
3
4
|
import * as React from 'react';
|
|
4
5
|
import { FlexBox } from '../..';
|
|
5
6
|
import { InfoTip } from '../../Tip/InfoTip';
|
|
@@ -30,7 +31,7 @@ const labelStates = states({
|
|
|
30
31
|
const Label = /*#__PURE__*/_styled("label", {
|
|
31
32
|
target: "e1t0n89n0",
|
|
32
33
|
label: "Label"
|
|
33
|
-
})(labelSizeVariants, labelStates, process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
34
|
+
})(labelSizeVariants, labelStates, process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9Gb3JtL2VsZW1lbnRzL0Zvcm1Hcm91cExhYmVsLnRzeCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFtRGMiLCJmaWxlIjoiLi4vLi4vLi4vc3JjL0Zvcm0vZWxlbWVudHMvRm9ybUdyb3VwTGFiZWwudHN4Iiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgc3RhdGVzLCB2YXJpYW50IH0gZnJvbSAnQGNvZGVjYWRlbXkvZ2FtdXQtc3R5bGVzJztcbmltcG9ydCB7IFN0eWxlUHJvcHMgfSBmcm9tICdAY29kZWNhZGVteS92YXJpYW5jZSc7XG5pbXBvcnQgc3R5bGVkIGZyb20gJ0BlbW90aW9uL3N0eWxlZCc7XG5pbXBvcnQgeyBIVE1MQXR0cmlidXRlcywgdXNlSWQgfSBmcm9tICdyZWFjdCc7XG5pbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCc7XG5cbmltcG9ydCB7IEZsZXhCb3ggfSBmcm9tICcuLi8uLic7XG5pbXBvcnQgeyBJbmZvVGlwLCBJbmZvVGlwUHJvcHMgfSBmcm9tICcuLi8uLi9UaXAvSW5mb1RpcCc7XG5pbXBvcnQgeyBUZXh0IH0gZnJvbSAnLi4vLi4vVHlwb2dyYXBoeS9UZXh0JztcbmltcG9ydCB7IGZvcm1CYXNlU3R5bGVzLCBmb3JtRmllbGRUZXh0RGlzYWJsZWRTdHlsZXMgfSBmcm9tICcuLi9zdHlsZXMnO1xuaW1wb3J0IHsgQmFzZUlucHV0UHJvcHMgfSBmcm9tICcuLi90eXBlcyc7XG5cbmNvbnN0IGxhYmVsU2l6ZVZhcmlhbnRzID0gdmFyaWFudCh7XG4gIGRlZmF1bHRWYXJpYW50OiAnc21hbGwnLFxuICBwcm9wOiAnc2l6ZScsXG4gIGJhc2U6IHsgZGlzcGxheTogJ2Jsb2NrJywgLi4uZm9ybUJhc2VTdHlsZXMgfSxcbiAgdmFyaWFudHM6IHtcbiAgICBzbWFsbDoge1xuICAgICAgbGluZUhlaWdodDogJ2Jhc2UnLFxuICAgIH0sXG4gICAgbGFyZ2U6IHtcbiAgICAgIGZvbnRTaXplOiAyMixcbiAgICAgIGxpbmVIZWlnaHQ6ICdiYXNlJyxcbiAgICAgIGZvbnRXZWlnaHQ6ICd0aXRsZScsXG4gICAgfSxcbiAgfSxcbn0pO1xuXG5jb25zdCBsYWJlbFN0YXRlcyA9IHN0YXRlcyh7XG4gIGRpc2FibGVkOiBmb3JtRmllbGRUZXh0RGlzYWJsZWRTdHlsZXMsXG59KTtcblxuZXhwb3J0IGludGVyZmFjZSBMYWJlbFZhcmlhbnRzXG4gIGV4dGVuZHMgU3R5bGVQcm9wczx0eXBlb2YgbGFiZWxTaXplVmFyaWFudHM+LFxuICAgIFN0eWxlUHJvcHM8dHlwZW9mIGxhYmVsU3RhdGVzPiB7fVxuXG5leHBvcnQgdHlwZSBGb3JtR3JvdXBMYWJlbFByb3BzID0gSFRNTEF0dHJpYnV0ZXM8SFRNTERpdkVsZW1lbnQ+ICZcbiAgSFRNTEF0dHJpYnV0ZXM8SFRNTExhYmVsRWxlbWVudD4gJlxuICBMYWJlbFZhcmlhbnRzICZcbiAgUGljazxCYXNlSW5wdXRQcm9wcywgJ2h0bWxGb3InIHwgJ3JlcXVpcmVkJz4gJiB7XG4gICAgLyoqXG4gICAgICogW1RoZSBmb3IvaWQgc3RyaW5nIG9mIGEgbGFiZWwgb3IgbGFiZWxhYmxlIGZvcm0tcmVsYXRlZCBlbGVtZW50XShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvSFRNTExhYmVsRWxlbWVudC9odG1sRm9yKS4gVGhlIG91dGVyIEZvcm1Hcm91cCBvciBGb3JtTGFiZWwgc2hvdWxkIGhhdmUgYW4gaWRlbnRpY2FsIHN0cmluZyBhcyB0aGUgaW5uZXIgRm9ybUVsZW1lbnQgZm9yIGFjY2Vzc2liaWxpdHkgcHVycG9zZXMuXG4gICAgICovXG4gICAgaW5mb3RpcD86IEluZm9UaXBQcm9wcztcbiAgICBzaXplPzogJ3NtYWxsJyB8ICdsYXJnZSc7XG4gICAgLyoqXG4gICAgICogU29sbyBmaWVsZHMgc2hvdWxkIGFsd2F5cyBiZSByZXF1aXJlZCBhbmQgaGF2ZSBubyBvcHRpb25hbC9yZXF1aXJlZCB0ZXh0XG4gICAgICovXG4gICAgaXNTb2xvRmllbGQ/OiBib29sZWFuO1xuICB9O1xuXG5jb25zdCBMYWJlbCA9IHN0eWxlZC5sYWJlbDxGb3JtR3JvdXBMYWJlbFByb3BzPihsYWJlbFNpemVWYXJpYW50cywgbGFiZWxTdGF0ZXMpO1xuXG5leHBvcnQgY29uc3QgRm9ybUdyb3VwTGFiZWw6IFJlYWN0LkZDPEZvcm1Hcm91cExhYmVsUHJvcHM+ID0gKHtcbiAgY2hpbGRyZW4sXG4gIGNsYXNzTmFtZSxcbiAgZGlzYWJsZWQsXG4gIGh0bWxGb3IsXG4gIGluZm90aXAsXG4gIGlzU29sb0ZpZWxkLFxuICByZXF1aXJlZCxcbiAgc2l6ZSxcbiAgLi4ucmVzdFxufSkgPT4ge1xuICBjb25zdCBsYWJlbElkID0gdXNlSWQoKTtcbiAgY29uc3QgaXNTdHJpbmdMYWJlbCA9IHR5cGVvZiBjaGlsZHJlbiA9PT0gJ3N0cmluZyc7XG4gIGNvbnN0IHNob3VsZExhYmVsSW5mb1RpcCA9XG4gICAgKGlzU3RyaW5nTGFiZWwgfHwgaW5mb3RpcD8ubGFiZWxsZWRCeUZpZWxkTGFiZWwpICYmXG4gICAgIWluZm90aXA/LmFyaWFMYWJlbCAmJlxuICAgICFpbmZvdGlwPy5hcmlhTGFiZWxsZWRieTtcblxuICByZXR1cm4gKFxuICAgIDxGbGV4Qm94IGp1c3RpZnlDb250ZW50PVwic3BhY2UtYmV0d2VlblwiIG1iPXs0fT5cbiAgICAgIDxMYWJlbFxuICAgICAgICB7Li4ucmVzdH1cbiAgICAgICAgYXM9e2h0bWxGb3IgPyAnbGFiZWwnIDogJ2Rpdid9XG4gICAgICAgIGNsYXNzTmFtZT17Y2xhc3NOYW1lfVxuICAgICAgICBkaXNhYmxlZD17ZGlzYWJsZWR9XG4gICAgICAgIGh0bWxGb3I9e2h0bWxGb3J9XG4gICAgICAgIGlkPXtpbmZvdGlwICYmIHNob3VsZExhYmVsSW5mb1RpcCA/IGxhYmVsSWQgOiB1bmRlZmluZWR9XG4gICAgICAgIHNpemU9e3NpemV9XG4gICAgICA+XG4gICAgICAgIHtjaGlsZHJlbn1cbiAgICAgICAgeyFpc1NvbG9GaWVsZCAmJlxuICAgICAgICAgIChyZXF1aXJlZCA/IChcbiAgICAgICAgICAgIDxUZXh0IGFyaWEtaGlkZGVuIGFzPVwic3BhblwiPlxuICAgICAgICAgICAgICAqXG4gICAgICAgICAgICA8L1RleHQ+XG4gICAgICAgICAgKSA6IChcbiAgICAgICAgICAgICdcXHUwMEEwKG9wdGlvbmFsKSdcbiAgICAgICAgICApKX1cbiAgICAgIDwvTGFiZWw+XG4gICAgICB7aW5mb3RpcCAmJiAoXG4gICAgICAgIDxJbmZvVGlwXG4gICAgICAgICAgey4uLmluZm90aXB9XG4gICAgICAgICAgYXJpYUxhYmVsbGVkYnk9e3Nob3VsZExhYmVsSW5mb1RpcCA/IGxhYmVsSWQgOiBpbmZvdGlwLmFyaWFMYWJlbGxlZGJ5fVxuICAgICAgICAvPlxuICAgICAgKX1cbiAgICA8L0ZsZXhCb3g+XG4gICk7XG59O1xuIl19 */");
|
|
34
35
|
export const FormGroupLabel = ({
|
|
35
36
|
children,
|
|
36
37
|
className,
|
|
@@ -42,6 +43,9 @@ export const FormGroupLabel = ({
|
|
|
42
43
|
size,
|
|
43
44
|
...rest
|
|
44
45
|
}) => {
|
|
46
|
+
const labelId = useId();
|
|
47
|
+
const isStringLabel = typeof children === 'string';
|
|
48
|
+
const shouldLabelInfoTip = (isStringLabel || infotip?.labelledByFieldLabel) && !infotip?.ariaLabel && !infotip?.ariaLabelledby;
|
|
45
49
|
return /*#__PURE__*/_jsxs(FlexBox, {
|
|
46
50
|
justifyContent: "space-between",
|
|
47
51
|
mb: 4,
|
|
@@ -51,6 +55,7 @@ export const FormGroupLabel = ({
|
|
|
51
55
|
className: className,
|
|
52
56
|
disabled: disabled,
|
|
53
57
|
htmlFor: htmlFor,
|
|
58
|
+
id: infotip && shouldLabelInfoTip ? labelId : undefined,
|
|
54
59
|
size: size,
|
|
55
60
|
children: [children, !isSoloField && (required ? /*#__PURE__*/_jsx(Text, {
|
|
56
61
|
"aria-hidden": true,
|
|
@@ -58,7 +63,8 @@ export const FormGroupLabel = ({
|
|
|
58
63
|
children: "*"
|
|
59
64
|
}) : '\u00A0(optional)')]
|
|
60
65
|
}), infotip && /*#__PURE__*/_jsx(InfoTip, {
|
|
61
|
-
...infotip
|
|
66
|
+
...infotip,
|
|
67
|
+
ariaLabelledby: shouldLabelInfoTip ? labelId : infotip.ariaLabelledby
|
|
62
68
|
})]
|
|
63
69
|
});
|
|
64
70
|
};
|
|
@@ -21,6 +21,10 @@ export declare const getComponent: (componentName: string) => {
|
|
|
21
21
|
};
|
|
22
22
|
type GridFormInputGroupTestComponentProps = GridFormInputGroupProps & {
|
|
23
23
|
mode?: 'onSubmit' | 'onChange';
|
|
24
|
+
externalLabel?: {
|
|
25
|
+
id: string;
|
|
26
|
+
text: string;
|
|
27
|
+
};
|
|
24
28
|
};
|
|
25
29
|
export declare const GridFormInputGroupTestComponent: React.FC<GridFormInputGroupTestComponentProps>;
|
|
26
30
|
export {};
|
package/dist/GridForm/types.d.ts
CHANGED
|
@@ -25,6 +25,11 @@ export type BaseFormField<Value> = {
|
|
|
25
25
|
* HTML id to use instead of the name.
|
|
26
26
|
*/
|
|
27
27
|
id?: string;
|
|
28
|
+
/**
|
|
29
|
+
* InfoTip to display next to the field label. String labels automatically
|
|
30
|
+
* label the InfoTip button. For ReactNode labels, provide `ariaLabel` or
|
|
31
|
+
* set `labelledByFieldLabel: true` to ensure the InfoTip is accessible.
|
|
32
|
+
*/
|
|
28
33
|
infotip?: InfoTipProps;
|
|
29
34
|
isSoloField?: boolean;
|
|
30
35
|
name: string;
|
|
@@ -8,14 +8,17 @@ export const InfoTipButton = /*#__PURE__*/forwardRef(({
|
|
|
8
8
|
active,
|
|
9
9
|
children,
|
|
10
10
|
emphasis,
|
|
11
|
+
'aria-label': ariaLabel,
|
|
12
|
+
'aria-labelledby': ariaLabelledby,
|
|
11
13
|
...props
|
|
12
14
|
}, ref) => {
|
|
13
15
|
const Icon = emphasis === 'high' ? MiniInfoCircleIcon : MiniInfoOutlineIcon;
|
|
14
16
|
return /*#__PURE__*/_jsxs(InfoTipButtonBase, {
|
|
17
|
+
...props,
|
|
15
18
|
active: active,
|
|
16
19
|
"aria-expanded": active,
|
|
17
|
-
"aria-label":
|
|
18
|
-
|
|
20
|
+
"aria-label": ariaLabel,
|
|
21
|
+
"aria-labelledby": ariaLabelledby,
|
|
19
22
|
ref: ref,
|
|
20
23
|
children: [Icon && /*#__PURE__*/_jsx(Icon, {
|
|
21
24
|
"aria-hidden": true,
|
|
@@ -2,7 +2,25 @@
|
|
|
2
2
|
import { TipBaseAlignment, TipBaseProps } from '../shared/types';
|
|
3
3
|
export type InfoTipProps = TipBaseProps & {
|
|
4
4
|
alignment?: TipBaseAlignment;
|
|
5
|
+
/**
|
|
6
|
+
* Accessible label for the InfoTip button. Its recommended to provide either `ariaLabel` or `ariaLabelledby`.
|
|
7
|
+
*/
|
|
8
|
+
ariaLabel?: string;
|
|
9
|
+
/**
|
|
10
|
+
* ID of an element that labels the InfoTip button. Its recommended to provide either `ariaLabel` or `ariaLabelledby`.
|
|
11
|
+
*/
|
|
12
|
+
ariaLabelledby?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Accessible role description for the InfoTip button. Useful for translation.
|
|
15
|
+
* @default "More information button"
|
|
16
|
+
*/
|
|
17
|
+
ariaRoleDescription?: string;
|
|
5
18
|
emphasis?: 'low' | 'high';
|
|
19
|
+
/**
|
|
20
|
+
* When true, the InfoTip button will be labelled by the form field's label element.
|
|
21
|
+
* This is automatic for string labels, but can be opted into for ReactNode labels.
|
|
22
|
+
*/
|
|
23
|
+
labelledByFieldLabel?: boolean;
|
|
6
24
|
/**
|
|
7
25
|
* Called when the info tip is clicked - the onClick function is called after the DOM updates and the tip is mounted.
|
|
8
26
|
*/
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { getFocusableElements as getFocusableElementsUtil } from '../../utils/focus';
|
|
3
|
-
import { extractTextContent } from '../../utils/react';
|
|
4
3
|
import { FloatingTip } from '../shared/FloatingTip';
|
|
5
4
|
import { InlineTip } from '../shared/InlineTip';
|
|
6
5
|
import { tipDefaultProps } from '../shared/types';
|
|
7
|
-
import {
|
|
8
|
-
import { ScreenreaderNavigableText } from './elements';
|
|
6
|
+
import { isFloatingElementOpen } from '../shared/utils';
|
|
9
7
|
import { InfoTipButton } from './InfoTipButton';
|
|
10
|
-
import { jsx as _jsx
|
|
11
|
-
const ARIA_HIDDEN_DELAY_MS = 1000;
|
|
12
|
-
|
|
13
|
-
// Match native dialogs with open attribute, and role-based dialogs that aren't aria-hidden
|
|
8
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
9
|
const MODAL_SELECTOR = 'dialog[open],[role="dialog"]:not([aria-hidden="true"]),[role="alertdialog"]:not([aria-hidden="true"])';
|
|
15
10
|
export const InfoTip = ({
|
|
16
11
|
alignment = 'top-right',
|
|
12
|
+
ariaLabel,
|
|
13
|
+
ariaLabelledby,
|
|
14
|
+
ariaRoleDescription = 'More information button',
|
|
17
15
|
emphasis = 'low',
|
|
18
16
|
info,
|
|
19
17
|
onClick,
|
|
@@ -22,25 +20,14 @@ export const InfoTip = ({
|
|
|
22
20
|
}) => {
|
|
23
21
|
const isFloating = placement === 'floating';
|
|
24
22
|
const [isTipHidden, setHideTip] = useState(true);
|
|
25
|
-
const [isAriaHidden, setIsAriaHidden] = useState(false);
|
|
26
|
-
const [shouldAnnounce, setShouldAnnounce] = useState(false);
|
|
27
23
|
const [loaded, setLoaded] = useState(false);
|
|
28
24
|
const wrapperRef = useRef(null);
|
|
29
25
|
const buttonRef = useRef(null);
|
|
30
26
|
const popoverContentNodeRef = useRef(null);
|
|
31
27
|
const isInitialMount = useRef(true);
|
|
32
|
-
const ariaHiddenTimeoutRef = useRef(null);
|
|
33
|
-
const announceTimeoutRef = useRef(null);
|
|
34
28
|
const getFocusableElements = useCallback(() => {
|
|
35
29
|
return getFocusableElementsUtil(popoverContentNodeRef.current);
|
|
36
30
|
}, []);
|
|
37
|
-
const clearAndSetTimeout = useCallback((timeoutRef, callback, delay) => {
|
|
38
|
-
clearTimeout(timeoutRef.current ?? undefined);
|
|
39
|
-
timeoutRef.current = setTimeout(() => {
|
|
40
|
-
callback();
|
|
41
|
-
timeoutRef.current = null;
|
|
42
|
-
}, delay);
|
|
43
|
-
}, []);
|
|
44
31
|
const popoverContentRef = useCallback(node => {
|
|
45
32
|
popoverContentNodeRef.current = node;
|
|
46
33
|
if (node && !isTipHidden && isFloating) {
|
|
@@ -51,24 +38,10 @@ export const InfoTip = ({
|
|
|
51
38
|
}, [onClick, isTipHidden, isFloating]);
|
|
52
39
|
useEffect(() => {
|
|
53
40
|
setLoaded(true);
|
|
54
|
-
const ariaHiddenTimeout = ariaHiddenTimeoutRef.current;
|
|
55
|
-
const announceTimeout = announceTimeoutRef.current;
|
|
56
|
-
return () => {
|
|
57
|
-
clearTimeout(ariaHiddenTimeout ?? undefined);
|
|
58
|
-
clearTimeout(announceTimeout ?? undefined);
|
|
59
|
-
};
|
|
60
41
|
}, []);
|
|
61
42
|
const setTipIsHidden = useCallback(nextTipState => {
|
|
62
43
|
setHideTip(nextTipState);
|
|
63
|
-
|
|
64
|
-
clearAndSetTimeout(ariaHiddenTimeoutRef, () => setIsAriaHidden(true), ARIA_HIDDEN_DELAY_MS);
|
|
65
|
-
} else if (nextTipState) {
|
|
66
|
-
if (isAriaHidden) setIsAriaHidden(false);
|
|
67
|
-
setShouldAnnounce(false);
|
|
68
|
-
clearTimeout(ariaHiddenTimeoutRef.current ?? undefined);
|
|
69
|
-
ariaHiddenTimeoutRef.current = null;
|
|
70
|
-
}
|
|
71
|
-
}, [isAriaHidden, isFloating, clearAndSetTimeout]);
|
|
44
|
+
}, []);
|
|
72
45
|
const handleOutsideClick = useCallback(e => {
|
|
73
46
|
const wrapper = wrapperRef.current;
|
|
74
47
|
const isOutside = wrapper && (!(e.target instanceof HTMLElement) || !wrapper.contains(e.target));
|
|
@@ -79,10 +52,7 @@ export const InfoTip = ({
|
|
|
79
52
|
const clickHandler = useCallback(() => {
|
|
80
53
|
const currentTipState = !isTipHidden;
|
|
81
54
|
setTipIsHidden(currentTipState);
|
|
82
|
-
|
|
83
|
-
clearAndSetTimeout(announceTimeoutRef, () => setShouldAnnounce(true), 0);
|
|
84
|
-
}
|
|
85
|
-
}, [isTipHidden, setTipIsHidden, clearAndSetTimeout]);
|
|
55
|
+
}, [isTipHidden, setTipIsHidden]);
|
|
86
56
|
useLayoutEffect(() => {
|
|
87
57
|
if (isInitialMount.current) {
|
|
88
58
|
isInitialMount.current = false;
|
|
@@ -108,7 +78,14 @@ export const InfoTip = ({
|
|
|
108
78
|
const handleGlobalEscapeKey = e => {
|
|
109
79
|
if (e.key !== 'Escape') return;
|
|
110
80
|
const openModals = document.querySelectorAll(MODAL_SELECTOR);
|
|
111
|
-
const hasUnrelatedModal = Array.from(openModals).some(modal =>
|
|
81
|
+
const hasUnrelatedModal = Array.from(openModals).some(modal => {
|
|
82
|
+
// Only consider floating elements that are actually open
|
|
83
|
+
if (!isFloatingElementOpen(modal)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
// Check if it's unrelated to this InfoTip
|
|
87
|
+
return wrapperRef.current && !modal.contains(wrapperRef.current);
|
|
88
|
+
});
|
|
112
89
|
if (hasUnrelatedModal) return;
|
|
113
90
|
e.preventDefault();
|
|
114
91
|
e.stopPropagation();
|
|
@@ -120,7 +97,18 @@ export const InfoTip = ({
|
|
|
120
97
|
const handleTabKeyInPopover = event => {
|
|
121
98
|
if (event.key !== 'Tab' || event.shiftKey) return;
|
|
122
99
|
const focusableElements = getFocusableElements();
|
|
123
|
-
|
|
100
|
+
const {
|
|
101
|
+
activeElement
|
|
102
|
+
} = document;
|
|
103
|
+
|
|
104
|
+
// If no focusable elements and popover itself has focus, wrap to button
|
|
105
|
+
if (focusableElements.length === 0) {
|
|
106
|
+
if (activeElement === popoverContentNodeRef.current) {
|
|
107
|
+
event.preventDefault();
|
|
108
|
+
buttonRef.current?.focus();
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
124
112
|
const lastElement = focusableElements[focusableElements.length - 1];
|
|
125
113
|
|
|
126
114
|
// Only wrap forward: if on last element, wrap to button
|
|
@@ -141,45 +129,35 @@ export const InfoTip = ({
|
|
|
141
129
|
};
|
|
142
130
|
}
|
|
143
131
|
return () => document.removeEventListener('keydown', handleGlobalEscapeKey, true);
|
|
144
|
-
}, [isTipHidden, isFloating,
|
|
132
|
+
}, [isTipHidden, isFloating, getFocusableElements, setTipIsHidden]);
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
if (isTipHidden) return;
|
|
135
|
+
const timeoutId = setTimeout(() => {
|
|
136
|
+
popoverContentNodeRef.current?.focus();
|
|
137
|
+
}, 0);
|
|
138
|
+
return () => clearTimeout(timeoutId);
|
|
139
|
+
}, [isTipHidden]);
|
|
145
140
|
const Tip = loaded && isFloating ? FloatingTip : InlineTip;
|
|
146
141
|
const tipProps = useMemo(() => ({
|
|
147
142
|
alignment,
|
|
148
143
|
info,
|
|
149
144
|
isTipHidden,
|
|
145
|
+
contentRef: popoverContentRef,
|
|
150
146
|
wrapperRef,
|
|
151
|
-
...(isFloating && {
|
|
152
|
-
popoverContentRef
|
|
153
|
-
}),
|
|
154
147
|
...rest
|
|
155
|
-
}), [alignment, info, isTipHidden,
|
|
156
|
-
const extractedTextContent = useMemo(() => extractTextContent(info), [info]);
|
|
157
|
-
const screenreaderInfo = shouldAnnounce && !isTipHidden ? extractedTextContent : '\xa0';
|
|
158
|
-
const screenreaderText = useMemo(() => /*#__PURE__*/_jsx(ScreenreaderNavigableText, {
|
|
159
|
-
"aria-hidden": isAriaHidden,
|
|
160
|
-
"aria-live": "assertive",
|
|
161
|
-
screenreader: true,
|
|
162
|
-
children: screenreaderInfo
|
|
163
|
-
}), [isAriaHidden, screenreaderInfo]);
|
|
164
|
-
const button = useMemo(() => /*#__PURE__*/_jsx(InfoTipButton, {
|
|
165
|
-
active: !isTipHidden,
|
|
166
|
-
"aria-expanded": !isTipHidden,
|
|
167
|
-
emphasis: emphasis,
|
|
168
|
-
ref: buttonRef,
|
|
169
|
-
onClick: clickHandler
|
|
170
|
-
}), [isTipHidden, emphasis, clickHandler]);
|
|
171
|
-
|
|
172
|
-
/*
|
|
173
|
-
* For floating placement, screenreader text comes before button to maintain
|
|
174
|
-
* correct DOM order despite Portal rendering. See GMT-64 for planned fix.
|
|
175
|
-
*/
|
|
148
|
+
}), [alignment, info, isTipHidden, popoverContentRef, wrapperRef, rest]);
|
|
176
149
|
return /*#__PURE__*/_jsx(Tip, {
|
|
177
150
|
...tipProps,
|
|
178
151
|
type: "info",
|
|
179
|
-
children:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
152
|
+
children: /*#__PURE__*/_jsx(InfoTipButton, {
|
|
153
|
+
active: !isTipHidden,
|
|
154
|
+
"aria-expanded": !isTipHidden,
|
|
155
|
+
"aria-label": ariaLabel,
|
|
156
|
+
"aria-labelledby": ariaLabelledby,
|
|
157
|
+
"aria-roledescription": ariaRoleDescription,
|
|
158
|
+
emphasis: emphasis,
|
|
159
|
+
ref: buttonRef,
|
|
160
|
+
onClick: clickHandler
|
|
183
161
|
})
|
|
184
162
|
});
|
|
185
163
|
};
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
/// <reference types="testing-library__jest-dom" />
|
|
3
3
|
import { setupRtl } from '@codecademy/gamut-tests';
|
|
4
4
|
import { RefObject } from 'react';
|
|
5
|
-
import { InfoTip
|
|
5
|
+
import { InfoTip } from '../InfoTip';
|
|
6
6
|
import { TipPlacements } from '../shared/types';
|
|
7
7
|
type InfoTipView = ReturnType<ReturnType<typeof setupRtl<typeof InfoTip>>>['view'];
|
|
8
|
-
type Placement = NonNullable<InfoTipProps['placement']>;
|
|
9
8
|
type ViewParam = {
|
|
10
9
|
view: InfoTipView;
|
|
11
10
|
};
|
|
@@ -16,7 +15,7 @@ type InfoParam = {
|
|
|
16
15
|
info: string;
|
|
17
16
|
};
|
|
18
17
|
type PlacementParam = {
|
|
19
|
-
placement:
|
|
18
|
+
placement: TipPlacements;
|
|
20
19
|
};
|
|
21
20
|
export declare const createFocusOnClick: (ref: RefObject<HTMLDivElement>) => ({ isTipHidden }: {
|
|
22
21
|
isTipHidden: boolean;
|
|
@@ -48,13 +47,10 @@ export declare const pressKey: (key: string) => Promise<void>;
|
|
|
48
47
|
export declare const waitForLinkToHaveFocus: ({ view, linkText, }: ViewParam & LinkTextParam) => Promise<HTMLElement>;
|
|
49
48
|
export declare const openTipAndWaitForLink: ({ view, linkText, }: ViewParam & LinkTextParam) => Promise<HTMLElement>;
|
|
50
49
|
export declare const openTipTabToLinkAndWaitForFocus: (view: InfoTipView, linkText: string) => Promise<HTMLElement>;
|
|
51
|
-
export declare const
|
|
52
|
-
export declare const testEscapeKeyReturnsFocus: ({ view, info, placement, }: ViewParam & InfoParam & PlacementParam) => Promise<void>;
|
|
53
|
-
export declare const testFocusWrap: ({ view, containerRef, direction, }: ViewParam & {
|
|
54
|
-
containerRef: RefObject<HTMLDivElement>;
|
|
50
|
+
export declare const testFocusWrap: ({ view, direction, }: ViewParam & {
|
|
55
51
|
direction: 'forward' | 'backward';
|
|
56
52
|
}) => Promise<void>;
|
|
57
|
-
export declare const
|
|
53
|
+
export declare const testTabFromPopoverWithNoInteractiveElements: (view: InfoTipView) => Promise<void>;
|
|
58
54
|
export declare const testTabbingBetweenLinks: ({ view, firstLinkText, secondLinkText, placement, }: ViewParam & {
|
|
59
55
|
firstLinkText: string;
|
|
60
56
|
secondLinkText: string;
|
|
@@ -62,7 +58,6 @@ export declare const testTabbingBetweenLinks: ({ view, firstLinkText, secondLink
|
|
|
62
58
|
}) => Promise<void>;
|
|
63
59
|
export declare const setupLinkTestWithPlacement: (linkText: string, placement: TipPlacements, renderView: ReturnType<typeof setupRtl<typeof InfoTip>>) => {
|
|
64
60
|
view: import("@testing-library/react").RenderResult;
|
|
65
|
-
containerRef: RefObject<HTMLDivElement>;
|
|
66
61
|
info: import("react/jsx-runtime").JSX.Element;
|
|
67
62
|
onClick: ({ isTipHidden }: {
|
|
68
63
|
isTipHidden: boolean;
|
|
@@ -86,28 +81,12 @@ type ViewWithQueries = {
|
|
|
86
81
|
getAllByText: (text: string) => HTMLElement[];
|
|
87
82
|
getAllByLabelText: (text: string) => HTMLElement[];
|
|
88
83
|
};
|
|
89
|
-
export declare const getVisibleTip: ({ text, placement, }: {
|
|
90
|
-
text: string;
|
|
91
|
-
placement?: "inline" | "floating" | undefined;
|
|
92
|
-
}) => HTMLElement | undefined;
|
|
93
|
-
export declare const expectTipToBeVisible: ({ text, placement, }: {
|
|
94
|
-
text: string;
|
|
95
|
-
placement?: "inline" | "floating" | undefined;
|
|
96
|
-
}) => void;
|
|
97
|
-
export declare const expectTipToBeClosed: ({ text, placement, }: {
|
|
98
|
-
text: string;
|
|
99
|
-
placement?: "inline" | "floating" | undefined;
|
|
100
|
-
}) => void;
|
|
101
84
|
export declare const openInfoTipsWithKeyboard: ({ view, count, }: {
|
|
102
85
|
view: ViewWithQueries;
|
|
103
86
|
count: number;
|
|
104
87
|
}) => Promise<void>;
|
|
105
88
|
export declare const expectTipsVisible: (tips: {
|
|
106
89
|
text: string;
|
|
107
|
-
placement?: 'inline' | 'floating';
|
|
108
|
-
}[]) => void;
|
|
109
|
-
export declare const expectTipsClosed: (tips: {
|
|
110
|
-
text: string;
|
|
111
|
-
placement?: 'inline' | 'floating';
|
|
112
90
|
}[]) => void;
|
|
91
|
+
export declare const expectTipsClosed: () => void;
|
|
113
92
|
export {};
|
|
@@ -18,7 +18,7 @@ export const FloatingTip = ({
|
|
|
18
18
|
loading,
|
|
19
19
|
narrow,
|
|
20
20
|
overline,
|
|
21
|
-
|
|
21
|
+
contentRef,
|
|
22
22
|
truncateLines,
|
|
23
23
|
type,
|
|
24
24
|
username,
|
|
@@ -123,7 +123,7 @@ export const FloatingTip = ({
|
|
|
123
123
|
width: inheritDims ? 'inherit' : undefined,
|
|
124
124
|
onBlur: toolOnlyEventFunc,
|
|
125
125
|
onFocus: toolOnlyEventFunc,
|
|
126
|
-
onKeyDown: escapeKeyPressHandler
|
|
126
|
+
onKeyDown: escapeKeyPressHandler,
|
|
127
127
|
onMouseDown: e => e.preventDefault(),
|
|
128
128
|
onMouseEnter: toolOnlyEventFunc,
|
|
129
129
|
children: children
|
|
@@ -134,7 +134,7 @@ export const FloatingTip = ({
|
|
|
134
134
|
horizontalOffset: offset,
|
|
135
135
|
isOpen: isPopoverOpen,
|
|
136
136
|
outline: true,
|
|
137
|
-
popoverContainerRef:
|
|
137
|
+
popoverContainerRef: contentRef,
|
|
138
138
|
skipFocusTrap: true,
|
|
139
139
|
targetRef: ref,
|
|
140
140
|
variant: "secondary",
|
|
@@ -17,6 +17,7 @@ export const InlineTip = ({
|
|
|
17
17
|
loading,
|
|
18
18
|
narrow,
|
|
19
19
|
overline,
|
|
20
|
+
contentRef,
|
|
20
21
|
truncateLines,
|
|
21
22
|
type,
|
|
22
23
|
username,
|
|
@@ -42,7 +43,7 @@ export const InlineTip = ({
|
|
|
42
43
|
height: inheritDims ? 'inherit' : undefined,
|
|
43
44
|
ref: wrapperRef,
|
|
44
45
|
width: inheritDims ? 'inherit' : undefined,
|
|
45
|
-
onKeyDown: escapeKeyPressHandler
|
|
46
|
+
onKeyDown: escapeKeyPressHandler,
|
|
46
47
|
children: children
|
|
47
48
|
});
|
|
48
49
|
const tipBody = /*#__PURE__*/_jsx(InlineTipBodyWrapper, {
|
|
@@ -55,7 +56,9 @@ export const InlineTip = ({
|
|
|
55
56
|
color: "currentColor",
|
|
56
57
|
horizNarrow: narrow && isHorizontalCenter,
|
|
57
58
|
id: id,
|
|
59
|
+
ref: contentRef,
|
|
58
60
|
role: type === 'tool' ? 'tooltip' : undefined,
|
|
61
|
+
tabIndex: type === 'info' ? -1 : undefined,
|
|
59
62
|
width: narrow && !isHorizontalCenter ? narrowWidth : 'max-content',
|
|
60
63
|
zIndex: "auto",
|
|
61
64
|
children: type === 'preview' ? /*#__PURE__*/_jsxs(_Fragment, {
|
|
@@ -46,7 +46,7 @@ export type TipPlacementComponentProps = Omit<TipNewBaseProps, 'placement' | 'em
|
|
|
46
46
|
escapeKeyPressHandler?: (event: React.KeyboardEvent<HTMLDivElement>) => void;
|
|
47
47
|
id?: string;
|
|
48
48
|
isTipHidden?: boolean;
|
|
49
|
-
|
|
49
|
+
contentRef?: React.RefObject<HTMLDivElement> | ((node: HTMLDivElement | null) => void);
|
|
50
50
|
type: 'info' | 'tool' | 'preview';
|
|
51
51
|
wrapperRef?: React.RefObject<HTMLDivElement>;
|
|
52
52
|
zIndex?: number;
|
|
@@ -6,3 +6,22 @@ export declare const escapeKeyPressHandler: (event: React.KeyboardEvent<HTMLDivE
|
|
|
6
6
|
* Uses the modern checkVisibility API with a fallback for older browsers.
|
|
7
7
|
*/
|
|
8
8
|
export declare const isElementVisible: (element: Element) => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Check if a floating element (modal, dialog, popover, overlay, etc.) is actually open and blocking.
|
|
11
|
+
*
|
|
12
|
+
* A floating element is considered "open" and blocking if:
|
|
13
|
+
* 1. It's a <dialog> element with the open attribute (always blocking per HTML spec), OR
|
|
14
|
+
* 2. It has role="alertdialog" (always blocking per ARIA spec), OR
|
|
15
|
+
* 3. It has role="dialog" AND:
|
|
16
|
+
* - It's not aria-hidden="true", AND
|
|
17
|
+
* - It doesn't have aria-expanded="false" (for collapsible dialogs), AND
|
|
18
|
+
* - It's actually visible (not just in DOM), AND
|
|
19
|
+
* - It has aria-modal="true" (indicates blocking modal per ARIA spec)
|
|
20
|
+
*
|
|
21
|
+
* Non-blocking popovers and collapsible dialogs without aria-modal="true" are not considered
|
|
22
|
+
* blocking and should not prevent InfoTip from closing.
|
|
23
|
+
*
|
|
24
|
+
* @param element - The DOM element to check
|
|
25
|
+
* @returns `true` if the floating element is actually open and blocking, `false` otherwise
|
|
26
|
+
*/
|
|
27
|
+
export declare const isFloatingElementOpen: (element: Element) => boolean;
|
package/dist/Tip/shared/utils.js
CHANGED
|
@@ -15,4 +15,108 @@ export const escapeKeyPressHandler = event => {
|
|
|
15
15
|
export const isElementVisible = element => {
|
|
16
16
|
if (!(element instanceof HTMLElement)) return false;
|
|
17
17
|
return element.checkVisibility?.() ?? true;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check if a floating element (modal, dialog, popover, overlay, etc.) is actually open and blocking.
|
|
22
|
+
*
|
|
23
|
+
* A floating element is considered "open" and blocking if:
|
|
24
|
+
* 1. It's a <dialog> element with the open attribute (always blocking per HTML spec), OR
|
|
25
|
+
* 2. It has role="alertdialog" (always blocking per ARIA spec), OR
|
|
26
|
+
* 3. It has role="dialog" AND:
|
|
27
|
+
* - It's not aria-hidden="true", AND
|
|
28
|
+
* - It doesn't have aria-expanded="false" (for collapsible dialogs), AND
|
|
29
|
+
* - It's actually visible (not just in DOM), AND
|
|
30
|
+
* - It has aria-modal="true" (indicates blocking modal per ARIA spec)
|
|
31
|
+
*
|
|
32
|
+
* Non-blocking popovers and collapsible dialogs without aria-modal="true" are not considered
|
|
33
|
+
* blocking and should not prevent InfoTip from closing.
|
|
34
|
+
*
|
|
35
|
+
* @param element - The DOM element to check
|
|
36
|
+
* @returns `true` if the floating element is actually open and blocking, `false` otherwise
|
|
37
|
+
*/
|
|
38
|
+
export const isFloatingElementOpen = element => {
|
|
39
|
+
if (!isElementVisible(element)) return false;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Native <dialog> elements are always blocking when open.
|
|
43
|
+
* Per HTML spec, dialog elements with the open attribute are modal.
|
|
44
|
+
*/
|
|
45
|
+
if (element instanceof HTMLDialogElement) {
|
|
46
|
+
return element.open === true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Elements with role="dialog" or role="alertdialog".
|
|
51
|
+
* Per ARIA spec, role="alertdialog" is always modal (blocking).
|
|
52
|
+
* role="dialog" requires aria-modal="true" to be blocking.
|
|
53
|
+
*/
|
|
54
|
+
const role = element.getAttribute('role');
|
|
55
|
+
if (role !== 'dialog' && role !== 'alertdialog') {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Cache attribute values to avoid multiple DOM reads.
|
|
61
|
+
* Check aria-hidden first as it's a common exclusion case.
|
|
62
|
+
*/
|
|
63
|
+
const ariaHidden = element.getAttribute('aria-hidden');
|
|
64
|
+
if (ariaHidden === 'true') {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check for collapsible dialogs (like help menus).
|
|
70
|
+
* If aria-expanded exists and is false, the dialog is closed.
|
|
71
|
+
* These dialogs stay in DOM but are collapsed when closed.
|
|
72
|
+
*/
|
|
73
|
+
const ariaExpanded = element.getAttribute('aria-expanded');
|
|
74
|
+
if (ariaExpanded === 'false') {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Per ARIA spec, role="alertdialog" is always modal (blocking).
|
|
80
|
+
* At this point, we've already verified:
|
|
81
|
+
* - The element is visible (not hidden via CSS)
|
|
82
|
+
* - It's not aria-hidden="true"
|
|
83
|
+
* - It's not aria-expanded="false"
|
|
84
|
+
* So if it's an alertdialog, it's open and blocking.
|
|
85
|
+
* Handle alertdialog here to avoid expensive DOM queries for dialog elements.
|
|
86
|
+
*/
|
|
87
|
+
if (role === 'alertdialog') {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* For role="dialog", check if any child button with aria-expanded indicates the dialog is closed.
|
|
93
|
+
* Some dialogs use a toggle button pattern where the button's aria-expanded
|
|
94
|
+
* reflects the dialog's state.
|
|
95
|
+
* Only perform this expensive querySelector operation after all other checks pass.
|
|
96
|
+
*/
|
|
97
|
+
const toggleButton = element.querySelector('button[aria-expanded], [role="button"][aria-expanded]');
|
|
98
|
+
if (toggleButton && toggleButton.getAttribute('aria-expanded') === 'false') {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* For role="dialog", check aria-modal attribute.
|
|
104
|
+
* aria-modal="true" indicates a blocking modal (Modal, Dialog).
|
|
105
|
+
* aria-modal="false" or absence indicates non-blocking.
|
|
106
|
+
*/
|
|
107
|
+
const ariaModal = element.getAttribute('aria-modal');
|
|
108
|
+
if (ariaModal === 'true') {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
if (ariaModal === 'false') {
|
|
112
|
+
// Explicitly non-modal, should not block
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Elements with role="dialog" but without aria-modal="true" are non-blocking.
|
|
118
|
+
* These include collapsible dialogs (help menus) and popovers (Popover, InfoTip, Tooltip)
|
|
119
|
+
* that use role="dialog". They should not prevent InfoTip from closing.
|
|
120
|
+
*/
|
|
121
|
+
return false;
|
|
18
122
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codecademy/gamut",
|
|
3
3
|
"description": "Styleguide & Component library for Codecademy",
|
|
4
|
-
"version": "67.6.
|
|
4
|
+
"version": "67.6.4-alpha.09d6ed.0",
|
|
5
5
|
"author": "Codecademy Engineering <dev@codecademy.com>",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@codecademy/gamut-icons": "9.54.0",
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"dist/**/[A-Z]**/[A-Z]*.js",
|
|
57
57
|
"dist/**/[A-Z]**/index.js"
|
|
58
58
|
],
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "a40bc2aa38a29be9b4b3190898613eb70f7df8d8"
|
|
60
60
|
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
export declare const ScreenreaderNavigableText: import("@emotion/styled").StyledComponent<(((Omit<{
|
|
3
|
-
theme?: import("@emotion/react").Theme | undefined;
|
|
4
|
-
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
5
|
-
} & import("../..").TextTruncateProps & Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "slot" | "style" | "title" | "dir" | "children" | "className" | "aria-hidden" | "onAnimationStart" | "onDragStart" | "onDragEnd" | "onDrag" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "autoFocus" | "contentEditable" | "contextMenu" | "draggable" | "hidden" | "id" | "lang" | "nonce" | "spellCheck" | "tabIndex" | "translate" | "radioGroup" | "role" | "about" | "content" | "datatype" | "inlist" | "prefix" | "property" | "rel" | "resource" | "rev" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-braillelabel" | "aria-brailleroledescription" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colindextext" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-description" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowindextext" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onResize" | "onResizeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDragCapture" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerLeave" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | keyof import("react").ClassAttributes<HTMLSpanElement>>, "ref"> | Omit<{
|
|
6
|
-
theme?: import("@emotion/react").Theme | undefined;
|
|
7
|
-
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
8
|
-
} & import("../..").TextNoTruncateProps & Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "slot" | "style" | "title" | "dir" | "children" | "className" | "aria-hidden" | "onAnimationStart" | "onDragStart" | "onDragEnd" | "onDrag" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "autoFocus" | "contentEditable" | "contextMenu" | "draggable" | "hidden" | "id" | "lang" | "nonce" | "spellCheck" | "tabIndex" | "translate" | "radioGroup" | "role" | "about" | "content" | "datatype" | "inlist" | "prefix" | "property" | "rel" | "resource" | "rev" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-braillelabel" | "aria-brailleroledescription" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colindextext" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-description" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowindextext" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onResize" | "onResizeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDragCapture" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerLeave" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | keyof import("react").ClassAttributes<HTMLSpanElement>>, "ref">) & import("react").RefAttributes<HTMLSpanElement>) & {
|
|
9
|
-
theme?: import("@emotion/react").Theme | undefined;
|
|
10
|
-
}) & {
|
|
11
|
-
theme?: import("@emotion/react").Theme | undefined;
|
|
12
|
-
}, {}, {}>;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import _styled from "@emotion/styled/base";
|
|
2
|
-
import { css } from '@codecademy/gamut-styles';
|
|
3
|
-
import { Text } from '../../Typography';
|
|
4
|
-
export const ScreenreaderNavigableText = /*#__PURE__*/_styled(Text, {
|
|
5
|
-
target: "e1rvjfdo0",
|
|
6
|
-
label: "ScreenreaderNavigableText"
|
|
7
|
-
})(css({
|
|
8
|
-
position: 'absolute'
|
|
9
|
-
}), process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9UaXAvSW5mb1RpcC9lbGVtZW50cy50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBS3lDIiwiZmlsZSI6Ii4uLy4uLy4uL3NyYy9UaXAvSW5mb1RpcC9lbGVtZW50cy50c3giLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjc3MgfSBmcm9tICdAY29kZWNhZGVteS9nYW11dC1zdHlsZXMnO1xuaW1wb3J0IHN0eWxlZCBmcm9tICdAZW1vdGlvbi9zdHlsZWQnO1xuXG5pbXBvcnQgeyBUZXh0IH0gZnJvbSAnLi4vLi4vVHlwb2dyYXBoeSc7XG5cbmV4cG9ydCBjb25zdCBTY3JlZW5yZWFkZXJOYXZpZ2FibGVUZXh0ID0gc3R5bGVkKFRleHQpKFxuICBjc3MoeyBwb3NpdGlvbjogJ2Fic29sdXRlJyB9KVxuKTtcbiJdfQ== */");
|