@cimpress-ui/react 1.34.0 → 1.34.2
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/commonjs/components/button/button.d.ts.map +1 -1
- package/dist/commonjs/components/button/button.js +4 -1
- package/dist/commonjs/components/button/button.js.map +1 -1
- package/dist/commonjs/components/button/disabled-with-reason.js +26 -0
- package/dist/commonjs/components/button/disabled-with-reason.js.map +1 -1
- package/dist/commonjs/components/button/icon-button.d.ts.map +1 -1
- package/dist/commonjs/components/button/icon-button.js +4 -1
- package/dist/commonjs/components/button/icon-button.js.map +1 -1
- package/dist/commonjs/components/button/icon-link-button.d.ts.map +1 -1
- package/dist/commonjs/components/button/icon-link-button.js +10 -2
- package/dist/commonjs/components/button/icon-link-button.js.map +1 -1
- package/dist/commonjs/components/button/link-button.d.ts.map +1 -1
- package/dist/commonjs/components/button/link-button.js +10 -2
- package/dist/commonjs/components/button/link-button.js.map +1 -1
- package/dist/esm/components/button/button.d.ts.map +1 -1
- package/dist/esm/components/button/button.js +5 -2
- package/dist/esm/components/button/button.js.map +1 -1
- package/dist/esm/components/button/disabled-with-reason.js +25 -0
- package/dist/esm/components/button/disabled-with-reason.js.map +1 -1
- package/dist/esm/components/button/icon-button.d.ts.map +1 -1
- package/dist/esm/components/button/icon-button.js +5 -2
- package/dist/esm/components/button/icon-button.js.map +1 -1
- package/dist/esm/components/button/icon-link-button.d.ts.map +1 -1
- package/dist/esm/components/button/icon-link-button.js +10 -2
- package/dist/esm/components/button/icon-link-button.js.map +1 -1
- package/dist/esm/components/button/link-button.d.ts.map +1 -1
- package/dist/esm/components/button/link-button.js +10 -2
- package/dist/esm/components/button/link-button.js.map +1 -1
- package/dist-styles/core.css +1 -1
- package/dist-styles/styles.css +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/button.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/button.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEtF,MAAM,WAAW,WAAY,SAAQ,eAAe,EAAE,eAAe,EAAE,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAC;IAC1G;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AA6DD;;;;GAIG;AACH,QAAA,MAAM,OAAO,gKAA+C,CAAC;AAE7D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,CAAC"}
|
|
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.Button = void 0;
|
|
8
8
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
9
|
const clsx_1 = __importDefault(require("clsx"));
|
|
10
|
+
const react_aria_1 = require("react-aria");
|
|
10
11
|
const react_aria_components_1 = require("react-aria-components");
|
|
11
12
|
const forward_ref_js_1 = require("../../forward-ref.js");
|
|
12
13
|
const use_production_warning_js_1 = require("../../utils/use-production-warning.js");
|
|
@@ -15,6 +16,7 @@ const spinner_js_1 = require("../internal/spinner/spinner.js");
|
|
|
15
16
|
const constants_js_1 = require("./constants.js");
|
|
16
17
|
const disabled_with_reason_js_1 = require("./disabled-with-reason.js");
|
|
17
18
|
function Button({ children, variant = 'secondary', tone = 'base', size = 'medium', iconStart, iconEnd, isLoading, loadingLabel, isDisabled, fullWidth, UNSAFE_className, UNSAFE_style, slot, ...props }, ref) {
|
|
19
|
+
const buttonRef = (0, react_aria_1.useObjectRef)(ref);
|
|
18
20
|
(0, use_production_warning_js_1.useProductionWarning)(() => {
|
|
19
21
|
if (isLoading && !loadingLabel) {
|
|
20
22
|
console.warn('Button requires loadingLabel when isLoading is true for accessibility');
|
|
@@ -22,7 +24,8 @@ function Button({ children, variant = 'secondary', tone = 'base', size = 'medium
|
|
|
22
24
|
}, [isLoading, loadingLabel]);
|
|
23
25
|
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
24
26
|
props = (0, disabled_with_reason_js_1.useDisableInteractions)(props, isDisabled ?? false);
|
|
25
|
-
const
|
|
27
|
+
const onFocusChange = (0, disabled_with_reason_js_1.usePreserveFocus)(buttonRef, buttonRef, isDisabled ?? false);
|
|
28
|
+
const button = ((0, jsx_runtime_1.jsx)(react_aria_components_1.Button, { ...props, ref: buttonRef, slot: slot, className: (0, clsx_1.default)('cim-button', UNSAFE_className), style: UNSAFE_style, "data-variant": variant, "data-tone": tone, "data-size": size, "data-full-width": fullWidth || undefined, isPending: isLoading, onFocusChange: onFocusChange, children: ({ isPending }) => ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [iconStart, (0, jsx_runtime_1.jsx)("span", { className: "cim-button-text", children: children }), iconEnd, isPending && (0, jsx_runtime_1.jsx)(spinner_js_1.InternalSpinner, { size: constants_js_1.SPINNER_SIZES[size], "aria-label": loadingLabel })] })) }));
|
|
26
29
|
return hasDisabledReason ? (0, jsx_runtime_1.jsx)(disabled_with_reason_js_1.DisabledWithReason, { reason: isDisabled.reason, children: button }) : button;
|
|
27
30
|
}
|
|
28
31
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.js","sourceRoot":"","sources":["../../../../src/components/button/button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;AAEb,gDAAwB;AAExB,iEAA4D;AAC5D,yDAAkD;AAClD,qFAA6E;AAC7E,mEAA2D;AAC3D,+DAAiE;AACjE,iDAA+C;AAC/C,
|
|
1
|
+
{"version":3,"file":"button.js","sourceRoot":"","sources":["../../../../src/components/button/button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;AAEb,gDAAwB;AAExB,2CAA0C;AAC1C,iEAA4D;AAC5D,yDAAkD;AAClD,qFAA6E;AAC7E,mEAA2D;AAC3D,+DAAiE;AACjE,iDAA+C;AAC/C,uEAAyG;AAezG,SAAS,MAAM,CACb,EACE,QAAQ,EACR,OAAO,GAAG,WAAW,EACrB,IAAI,GAAG,MAAM,EACb,IAAI,GAAG,QAAQ,EACf,SAAS,EACT,OAAO,EACP,SAAS,EACT,YAAY,EACZ,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,IAAI,EACJ,GAAG,KAAK,EACI,EACd,GAAoC;IAEpC,MAAM,SAAS,GAAG,IAAA,yBAAY,EAAC,GAAG,CAAC,CAAC;IAEpC,IAAA,gDAAoB,EAAC,GAAG,EAAE;QACxB,IAAI,SAAS,IAAI,CAAC,YAAY,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,uEAAuE,CAAC,CAAC;QACxF,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;IAE9B,MAAM,iBAAiB,GAAG,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,KAAK,EAAE,CAAC;IACrF,KAAK,GAAG,IAAA,gDAAsB,EAAC,KAAK,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC;IAC3D,MAAM,aAAa,GAAG,IAAA,0CAAgB,EAAC,SAAS,EAAE,SAAS,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC;IAElF,MAAM,MAAM,GAAG,CACb,uBAAC,8BAAS,OACJ,KAAK,EACT,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,IAAA,cAAI,EAAC,YAAY,EAAE,gBAAgB,CAAC,EAC/C,KAAK,EAAE,YAAY,kBACL,OAAO,eACV,IAAI,eACJ,IAAI,qBACE,SAAS,IAAI,SAAS,EACvC,SAAS,EAAE,SAAS,EACpB,aAAa,EAAE,aAAa,YAE3B,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAClB,6DACG,SAAS,EACV,iCAAM,SAAS,EAAC,iBAAiB,YAAE,QAAQ,GAAQ,EAClD,OAAO,EACP,SAAS,IAAI,uBAAC,4BAAe,IAAC,IAAI,EAAE,4BAAa,CAAC,IAAI,CAAC,gBAAc,YAAY,GAAI,IACrF,CACJ,GACS,CACb,CAAC;IAEF,OAAO,iBAAiB,CAAC,CAAC,CAAC,uBAAC,4CAAkB,IAAC,MAAM,EAAE,UAAU,CAAC,MAAM,YAAG,MAAM,GAAsB,CAAC,CAAC,CAAC,MAAM,CAAC;AACnH,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,GAAG,IAAA,oCAAc,EAAC,IAAA,2BAAU,EAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;AAEzC,yBAAM","sourcesContent":["'use client';\n\nimport clsx from 'clsx';\nimport type { ForwardedRef } from 'react';\nimport { useObjectRef } from 'react-aria';\nimport { Button as RACButton } from 'react-aria-components';\nimport { forwardRef } from '../../forward-ref.js';\nimport { useProductionWarning } from '../../utils/use-production-warning.js';\nimport { withStyleProps } from '../../with-style-props.js';\nimport { InternalSpinner } from '../internal/spinner/spinner.js';\nimport { SPINNER_SIZES } from './constants.js';\nimport { DisabledWithReason, useDisableInteractions, usePreserveFocus } from './disabled-with-reason.js';\nimport type { ActionButtonProps, BaseButtonProps, TextButtonProps } from './types.js';\n\nexport interface ButtonProps extends BaseButtonProps, TextButtonProps, Omit<ActionButtonProps, 'isDisabled'> {\n /**\n * Whether the button is disabled.\n *\n * Optionally, you can provide an object with the `reason` property explaining why the button is disabled.\n * This information will be shown to end-users as a tooltip or a popover.\n *\n * @default false\n */\n isDisabled?: boolean | { reason: string };\n}\n\nfunction Button(\n {\n children,\n variant = 'secondary',\n tone = 'base',\n size = 'medium',\n iconStart,\n iconEnd,\n isLoading,\n loadingLabel,\n isDisabled,\n fullWidth,\n UNSAFE_className,\n UNSAFE_style,\n slot,\n ...props\n }: ButtonProps,\n ref: ForwardedRef<HTMLButtonElement>,\n) {\n const buttonRef = useObjectRef(ref);\n\n useProductionWarning(() => {\n if (isLoading && !loadingLabel) {\n console.warn('Button requires loadingLabel when isLoading is true for accessibility');\n }\n }, [isLoading, loadingLabel]);\n\n const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';\n props = useDisableInteractions(props, isDisabled ?? false);\n const onFocusChange = usePreserveFocus(buttonRef, buttonRef, isDisabled ?? false);\n\n const button = (\n <RACButton\n {...props}\n ref={buttonRef}\n slot={slot}\n className={clsx('cim-button', UNSAFE_className)}\n style={UNSAFE_style}\n data-variant={variant}\n data-tone={tone}\n data-size={size}\n data-full-width={fullWidth || undefined}\n isPending={isLoading}\n onFocusChange={onFocusChange}\n >\n {({ isPending }) => (\n <>\n {iconStart}\n <span className=\"cim-button-text\">{children}</span>\n {iconEnd}\n {isPending && <InternalSpinner size={SPINNER_SIZES[size]} aria-label={loadingLabel} />}\n </>\n )}\n </RACButton>\n );\n\n return hasDisabledReason ? <DisabledWithReason reason={isDisabled.reason}>{button}</DisabledWithReason> : button;\n}\n\n/**\n * Displays a labelled button that allows users to perform an action.\n *\n * See [button usage guidelines](https://ui.cimpress.io/components/button/).\n */\nconst _Button = withStyleProps(forwardRef(Button), 'Button');\n\nexport { _Button as Button };\n"]}
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DisabledWithReason = DisabledWithReason;
|
|
4
4
|
exports.useDisableInteractions = useDisableInteractions;
|
|
5
|
+
exports.usePreserveFocus = usePreserveFocus;
|
|
5
6
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
7
|
+
const utils_1 = require("@react-aria/utils");
|
|
8
|
+
const react_1 = require("react");
|
|
6
9
|
const use_media_query_js_1 = require("../../utils/use-media-query.js");
|
|
7
10
|
const popover_js_1 = require("../popover/popover.js");
|
|
8
11
|
const tooltip_js_1 = require("../tooltip/tooltip.js");
|
|
@@ -40,4 +43,27 @@ function useDisableInteractions(props, isDisabled) {
|
|
|
40
43
|
}
|
|
41
44
|
return props;
|
|
42
45
|
}
|
|
46
|
+
/** @internal */
|
|
47
|
+
// eslint-disable-next-line react-refresh/only-export-components
|
|
48
|
+
function usePreserveFocus(enabledRef, disabledRef, isDisabled) {
|
|
49
|
+
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
50
|
+
const isFocusable = !isDisabled || hasDisabledReason;
|
|
51
|
+
const isFocusedRef = (0, react_1.useRef)(false);
|
|
52
|
+
const wasFocusableRef = (0, react_1.useRef)(isFocusable);
|
|
53
|
+
(0, utils_1.useLayoutEffect)(() => {
|
|
54
|
+
// Refocus button if focus was lost when changing between "enabled" and "disabled with a reason"
|
|
55
|
+
if (isFocusedRef.current && wasFocusableRef.current && isFocusable && document.activeElement === document.body) {
|
|
56
|
+
if (hasDisabledReason) {
|
|
57
|
+
disabledRef.current?.focus();
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
enabledRef.current?.focus();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}, [hasDisabledReason, isFocusable, enabledRef, disabledRef]);
|
|
64
|
+
(0, react_1.useEffect)(() => {
|
|
65
|
+
wasFocusableRef.current = isFocusable;
|
|
66
|
+
}, [isFocusable]);
|
|
67
|
+
return (isFocused) => (isFocusedRef.current = isFocused);
|
|
68
|
+
}
|
|
43
69
|
//# sourceMappingURL=disabled-with-reason.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"disabled-with-reason.js","sourceRoot":"","sources":["../../../../src/components/button/disabled-with-reason.tsx"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"disabled-with-reason.js","sourceRoot":"","sources":["../../../../src/components/button/disabled-with-reason.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect } from '@react-aria/utils';\nimport { useEffect, useRef, type HTMLAttributes, type MutableRefObject, type ReactNode } from 'react';\nimport type { ButtonProps as RACButtonProps } from 'react-aria-components';\nimport { useMediaQuery } from '../../utils/use-media-query.js';\nimport { Popover, PopoverRoot } from '../popover/popover.js';\nimport { Tooltip } from '../tooltip/tooltip.js';\nimport type { FocusableElement } from '../types.js';\n\n/** @internal */\nexport function DisabledWithReason({ children, reason }: { children: ReactNode; reason: string }) {\n const hasHover = useMediaQuery('(hover: hover)', { defaultValue: true, initializeWithValue: true });\n\n if (hasHover) {\n return <Tooltip label={reason}>{children}</Tooltip>;\n } else {\n return (\n <PopoverRoot>\n {children}\n {/* TODO: add aria-label */}\n <Popover>{reason}</Popover>\n </PopoverRoot>\n );\n }\n}\n\n// Events to preserve when `isDisabled` is true (for tooltips and other overlays)\nconst PRESERVED_EVENT_PATTERN = /Focus|Blur|Hover|Pointer(Enter|Leave|Over|Out)|Mouse(Enter|Leave|Over|Out)/;\n\n/** @internal */\n// eslint-disable-next-line react-refresh/only-export-components\nexport function useDisableInteractions<T extends Partial<RACButtonProps & HTMLAttributes<HTMLButtonElement>>>(\n props: T,\n isDisabled: boolean | { reason: string },\n): T {\n if (isDisabled !== false) {\n for (const key in props) {\n if (key.startsWith('on') && !PRESERVED_EVENT_PATTERN.test(key)) {\n delete props[key];\n }\n }\n }\n\n if (typeof isDisabled === 'object' && isDisabled.reason) {\n // Use `aria-disabled` instead of `disabled`\n props['aria-disabled'] = true;\n // Prevent form submission\n props.type = props.type === 'submit' ? 'button' : props.type;\n } else if (isDisabled !== false) {\n // Make the button actually disabled\n props.isDisabled = true;\n }\n\n return props;\n}\n\n/** @internal */\n// eslint-disable-next-line react-refresh/only-export-components\nexport function usePreserveFocus(\n enabledRef: MutableRefObject<FocusableElement | null>,\n disabledRef: MutableRefObject<FocusableElement | null>,\n isDisabled: boolean | { reason: string },\n): (isFocused: boolean) => void {\n const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';\n const isFocusable = !isDisabled || hasDisabledReason;\n\n const isFocusedRef = useRef<boolean>(false);\n const wasFocusableRef = useRef<boolean>(isFocusable);\n\n useLayoutEffect(() => {\n // Refocus button if focus was lost when changing between \"enabled\" and \"disabled with a reason\"\n if (isFocusedRef.current && wasFocusableRef.current && isFocusable && document.activeElement === document.body) {\n if (hasDisabledReason) {\n disabledRef.current?.focus();\n } else {\n enabledRef.current?.focus();\n }\n }\n }, [hasDisabledReason, isFocusable, enabledRef, disabledRef]);\n\n useEffect(() => {\n wasFocusableRef.current = isFocusable;\n }, [isFocusable]);\n\n return (isFocused) => (isFocusedRef.current = isFocused);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/icon-button.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"icon-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/icon-button.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE5F,MAAM,WAAW,eAAgB,SAAQ,eAAe,EAAE,qBAAqB,EAAE,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAC;IACpH;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAyDD;;;;GAIG;AACH,QAAA,MAAM,WAAW,oKAAuD,CAAC;AAEzE,OAAO,EAAE,WAAW,IAAI,UAAU,EAAE,CAAC"}
|
|
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.IconButton = void 0;
|
|
8
8
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
9
|
const clsx_1 = __importDefault(require("clsx"));
|
|
10
|
+
const react_aria_1 = require("react-aria");
|
|
10
11
|
const react_aria_components_1 = require("react-aria-components");
|
|
11
12
|
const forward_ref_js_1 = require("../../forward-ref.js");
|
|
12
13
|
const use_production_warning_js_1 = require("../../utils/use-production-warning.js");
|
|
@@ -15,6 +16,7 @@ const spinner_js_1 = require("../internal/spinner/spinner.js");
|
|
|
15
16
|
const constants_js_1 = require("./constants.js");
|
|
16
17
|
const disabled_with_reason_js_1 = require("./disabled-with-reason.js");
|
|
17
18
|
function IconButton({ icon, variant = 'secondary', tone = 'base', size = 'medium', isLoading, loadingLabel, isDisabled, fullWidth, UNSAFE_className, UNSAFE_style, slot, ...props }, ref) {
|
|
19
|
+
const buttonRef = (0, react_aria_1.useObjectRef)(ref);
|
|
18
20
|
(0, use_production_warning_js_1.useProductionWarning)(() => {
|
|
19
21
|
if (isLoading && !loadingLabel) {
|
|
20
22
|
console.warn('IconButton requires loadingLabel when isLoading is true for accessibility');
|
|
@@ -22,7 +24,8 @@ function IconButton({ icon, variant = 'secondary', tone = 'base', size = 'medium
|
|
|
22
24
|
}, [isLoading, loadingLabel]);
|
|
23
25
|
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
24
26
|
props = (0, disabled_with_reason_js_1.useDisableInteractions)(props, isDisabled ?? false);
|
|
25
|
-
const
|
|
27
|
+
const onFocusChange = (0, disabled_with_reason_js_1.usePreserveFocus)(buttonRef, buttonRef, isDisabled ?? false);
|
|
28
|
+
const button = ((0, jsx_runtime_1.jsx)(react_aria_components_1.Button, { ...props, ref: buttonRef, slot: slot, className: (0, clsx_1.default)('cim-icon-button', UNSAFE_className), style: UNSAFE_style, "data-variant": variant, "data-tone": tone, "data-size": size, "data-full-width": fullWidth || undefined, isPending: isLoading, onFocusChange: onFocusChange, children: ({ isPending }) => ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [icon, isPending && (0, jsx_runtime_1.jsx)(spinner_js_1.InternalSpinner, { size: constants_js_1.SPINNER_SIZES[size], "aria-label": loadingLabel })] })) }));
|
|
26
29
|
return hasDisabledReason ? (0, jsx_runtime_1.jsx)(disabled_with_reason_js_1.DisabledWithReason, { reason: isDisabled.reason, children: button }) : button;
|
|
27
30
|
}
|
|
28
31
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-button.js","sourceRoot":"","sources":["../../../../src/components/button/icon-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;AAEb,gDAAwB;AAExB,iEAA4D;AAC5D,yDAAkD;AAClD,qFAA6E;AAC7E,mEAA2D;AAC3D,+DAAiE;AACjE,iDAA+C;AAC/C,
|
|
1
|
+
{"version":3,"file":"icon-button.js","sourceRoot":"","sources":["../../../../src/components/button/icon-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;AAEb,gDAAwB;AAExB,2CAA0C;AAC1C,iEAA4D;AAC5D,yDAAkD;AAClD,qFAA6E;AAC7E,mEAA2D;AAC3D,+DAAiE;AACjE,iDAA+C;AAC/C,uEAAyG;AAezG,SAAS,UAAU,CACjB,EACE,IAAI,EACJ,OAAO,GAAG,WAAW,EACrB,IAAI,GAAG,MAAM,EACb,IAAI,GAAG,QAAQ,EACf,SAAS,EACT,YAAY,EACZ,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,IAAI,EACJ,GAAG,KAAK,EACQ,EAClB,GAAoC;IAEpC,MAAM,SAAS,GAAG,IAAA,yBAAY,EAAC,GAAG,CAAC,CAAC;IAEpC,IAAA,gDAAoB,EAAC,GAAG,EAAE;QACxB,IAAI,SAAS,IAAI,CAAC,YAAY,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,2EAA2E,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;IAE9B,MAAM,iBAAiB,GAAG,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,KAAK,EAAE,CAAC;IACrF,KAAK,GAAG,IAAA,gDAAsB,EAAC,KAAK,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC;IAC3D,MAAM,aAAa,GAAG,IAAA,0CAAgB,EAAC,SAAS,EAAE,SAAS,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC;IAElF,MAAM,MAAM,GAAG,CACb,uBAAC,8BAAS,OACJ,KAAK,EACT,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,IAAA,cAAI,EAAC,iBAAiB,EAAE,gBAAgB,CAAC,EACpD,KAAK,EAAE,YAAY,kBACL,OAAO,eACV,IAAI,eACJ,IAAI,qBACE,SAAS,IAAI,SAAS,EACvC,SAAS,EAAE,SAAS,EACpB,aAAa,EAAE,aAAa,YAE3B,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAClB,6DACG,IAAI,EACJ,SAAS,IAAI,uBAAC,4BAAe,IAAC,IAAI,EAAE,4BAAa,CAAC,IAAI,CAAC,gBAAc,YAAY,GAAI,IACrF,CACJ,GACS,CACb,CAAC;IAEF,OAAO,iBAAiB,CAAC,CAAC,CAAC,uBAAC,4CAAkB,IAAC,MAAM,EAAE,UAAU,CAAC,MAAM,YAAG,MAAM,GAAsB,CAAC,CAAC,CAAC,MAAM,CAAC;AACnH,CAAC;AAED;;;;GAIG;AACH,MAAM,WAAW,GAAG,IAAA,oCAAc,EAAC,IAAA,2BAAU,EAAC,UAAU,CAAC,EAAE,YAAY,CAAC,CAAC;AAEjD,iCAAU","sourcesContent":["'use client';\n\nimport clsx from 'clsx';\nimport type { ForwardedRef } from 'react';\nimport { useObjectRef } from 'react-aria';\nimport { Button as RACButton } from 'react-aria-components';\nimport { forwardRef } from '../../forward-ref.js';\nimport { useProductionWarning } from '../../utils/use-production-warning.js';\nimport { withStyleProps } from '../../with-style-props.js';\nimport { InternalSpinner } from '../internal/spinner/spinner.js';\nimport { SPINNER_SIZES } from './constants.js';\nimport { DisabledWithReason, useDisableInteractions, usePreserveFocus } from './disabled-with-reason.js';\nimport type { ActionButtonProps, BaseButtonProps, SingleIconButtonProps } from './types.js';\n\nexport interface IconButtonProps extends BaseButtonProps, SingleIconButtonProps, Omit<ActionButtonProps, 'isDisabled'> {\n /**\n * Whether the button is disabled.\n *\n * Optionally, you can provide an object with the `reason` property explaining why the button is disabled.\n * This information will be shown to the end-users as a tooltip or a popover.\n *\n * @default false\n */\n isDisabled?: boolean | { reason: string };\n}\n\nfunction IconButton(\n {\n icon,\n variant = 'secondary',\n tone = 'base',\n size = 'medium',\n isLoading,\n loadingLabel,\n isDisabled,\n fullWidth,\n UNSAFE_className,\n UNSAFE_style,\n slot,\n ...props\n }: IconButtonProps,\n ref: ForwardedRef<HTMLButtonElement>,\n) {\n const buttonRef = useObjectRef(ref);\n\n useProductionWarning(() => {\n if (isLoading && !loadingLabel) {\n console.warn('IconButton requires loadingLabel when isLoading is true for accessibility');\n }\n }, [isLoading, loadingLabel]);\n\n const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';\n props = useDisableInteractions(props, isDisabled ?? false);\n const onFocusChange = usePreserveFocus(buttonRef, buttonRef, isDisabled ?? false);\n\n const button = (\n <RACButton\n {...props}\n ref={buttonRef}\n slot={slot}\n className={clsx('cim-icon-button', UNSAFE_className)}\n style={UNSAFE_style}\n data-variant={variant}\n data-tone={tone}\n data-size={size}\n data-full-width={fullWidth || undefined}\n isPending={isLoading}\n onFocusChange={onFocusChange}\n >\n {({ isPending }) => (\n <>\n {icon}\n {isPending && <InternalSpinner size={SPINNER_SIZES[size]} aria-label={loadingLabel} />}\n </>\n )}\n </RACButton>\n );\n\n return hasDisabledReason ? <DisabledWithReason reason={isDisabled.reason}>{button}</DisabledWithReason> : button;\n}\n\n/**\n * Displays an icon-only button that allows users to perform an action.\n *\n * See [button usage guidelines](https://ui.cimpress.io/components/button/).\n */\nconst _IconButton = withStyleProps(forwardRef(IconButton), 'IconButton');\n\nexport { _IconButton as IconButton };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/icon-link-button.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"icon-link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/icon-link-button.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAmB,KAAK,SAAS,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGxF,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGjE,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,WAAW,mBACf,SACE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,EAC3B,qBAAqB,EACrB,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,EACrC,IAAI,CAAC,YAAY,EAAE,cAAc,GAAG,YAAY,CAAC;IACnD;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AA8DD;;;;GAIG;AACH,QAAA,MAAM,eAAe,wKAA+D,CAAC;AAErF,OAAO,EAAE,eAAe,IAAI,cAAc,EAAE,CAAC"}
|
|
@@ -7,18 +7,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.IconLinkButton = void 0;
|
|
8
8
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
9
|
const clsx_1 = __importDefault(require("clsx"));
|
|
10
|
+
const react_1 = require("react");
|
|
11
|
+
const react_aria_1 = require("react-aria");
|
|
10
12
|
const react_aria_components_1 = require("react-aria-components");
|
|
11
13
|
const forward_ref_js_1 = require("../../forward-ref.js");
|
|
12
14
|
const with_style_props_js_1 = require("../../with-style-props.js");
|
|
15
|
+
const disabled_with_reason_js_1 = require("./disabled-with-reason.js");
|
|
13
16
|
const icon_button_js_1 = require("./icon-button.js");
|
|
14
17
|
function IconLinkButton({ icon, variant = 'secondary', tone = 'base', size = 'medium', isDisabled = false, fullWidth = false, UNSAFE_className, UNSAFE_style, ...props }, ref) {
|
|
18
|
+
const linkRef = (0, react_aria_1.useObjectRef)(ref);
|
|
19
|
+
const buttonRef = (0, react_1.useRef)(null);
|
|
15
20
|
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
21
|
+
const onFocusChange = (0, disabled_with_reason_js_1.usePreserveFocus)(linkRef, buttonRef, isDisabled ?? false);
|
|
16
22
|
if (hasDisabledReason) {
|
|
17
23
|
// `RACLink` doesn't support aria-disabled while keeping interactivity, so we render an `IconButton` instead
|
|
18
24
|
const { href, target, hrefLang, download, ping, referrerPolicy, rel, routerOptions, ...buttonProps } = props;
|
|
19
|
-
return ((0, jsx_runtime_1.jsx)(icon_button_js_1.IconButton, { ...buttonProps, icon: icon, variant: variant, tone: tone, size: size, isDisabled: isDisabled, fullWidth: fullWidth, UNSAFE_className: UNSAFE_className, UNSAFE_style: UNSAFE_style
|
|
25
|
+
return ((0, jsx_runtime_1.jsx)(icon_button_js_1.IconButton, { ...buttonProps, ref: buttonRef, icon: icon, variant: variant, tone: tone, size: size, isDisabled: isDisabled, fullWidth: fullWidth, UNSAFE_className: UNSAFE_className, UNSAFE_style: UNSAFE_style,
|
|
26
|
+
// @ts-expect-error our buttons don't expose `onFocusChange`, but it gets passed to React Aria anyway
|
|
27
|
+
onFocusChange: onFocusChange }));
|
|
20
28
|
}
|
|
21
|
-
return ((0, jsx_runtime_1.jsx)(react_aria_components_1.Link, { ...props, ref:
|
|
29
|
+
return ((0, jsx_runtime_1.jsx)(react_aria_components_1.Link, { ...props, ref: linkRef, className: (0, clsx_1.default)('cim-icon-button', UNSAFE_className), style: UNSAFE_style, "data-variant": variant, "data-tone": tone, "data-size": size, "data-full-width": fullWidth || undefined, isDisabled: !!isDisabled, onFocusChange: onFocusChange, children: icon }));
|
|
22
30
|
}
|
|
23
31
|
/**
|
|
24
32
|
* Displays an icon-only button that allows users to navigate to another page or resource.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-link-button.js","sourceRoot":"","sources":["../../../../src/components/button/icon-link-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;AAEb,gDAAwB;
|
|
1
|
+
{"version":3,"file":"icon-link-button.js","sourceRoot":"","sources":["../../../../src/components/button/icon-link-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;AAEb,gDAAwB;AACxB,iCAAkD;AAClD,2CAA0C;AAC1C,iEAAwF;AACxF,yDAAkD;AAClD,mEAA2D;AAE3D,uEAA6D;AAC7D,qDAA8C;AAoB9C,SAAS,cAAc,CACrB,EACE,IAAI,EACJ,OAAO,GAAG,WAAW,EACrB,IAAI,GAAG,MAAM,EACb,IAAI,GAAG,QAAQ,EACf,UAAU,GAAG,KAAK,EAClB,SAAS,GAAG,KAAK,EACjB,gBAAgB,EAChB,YAAY,EACZ,GAAG,KAAK,EACY,EACtB,GAAoC;IAEpC,MAAM,OAAO,GAAG,IAAA,yBAAY,EAAC,GAAG,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,IAAA,cAAM,EAA2B,IAAI,CAAC,CAAC;IAEzD,MAAM,iBAAiB,GAAG,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,KAAK,EAAE,CAAC;IACrF,MAAM,aAAa,GAAG,IAAA,0CAAgB,EAAC,OAAO,EAAE,SAAS,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC;IAEhF,IAAI,iBAAiB,EAAE,CAAC;QACtB,4GAA4G;QAC5G,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,WAAW,EAAE,GAAG,KAAK,CAAC;QAE7G,OAAO,CACL,uBAAC,2BAAU,OACL,WAAW,EACf,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,gBAAgB,EAAE,gBAAgB,EAClC,YAAY,EAAE,YAAY;YAC1B,qGAAqG;YACrG,aAAa,EAAE,aAAa,GAC5B,CACH,CAAC;IACJ,CAAC;IAED,OAAO,CACL,uBAAC,4BAAO,OACF,KAAK,EACT,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,IAAA,cAAI,EAAC,iBAAiB,EAAE,gBAAgB,CAAC,EACpD,KAAK,EAAE,YAAY,kBACL,OAAO,eACV,IAAI,eACJ,IAAI,qBACE,SAAS,IAAI,SAAS,EACvC,UAAU,EAAE,CAAC,CAAC,UAAU,EACxB,aAAa,EAAE,aAAa,YAE3B,IAAI,GACG,CACX,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,eAAe,GAAG,IAAA,oCAAc,EAAC,IAAA,2BAAU,EAAC,cAAc,CAAC,EAAE,gBAAgB,CAAC,CAAC;AAEzD,yCAAc","sourcesContent":["'use client';\n\nimport clsx from 'clsx';\nimport { useRef, type ForwardedRef } from 'react';\nimport { useObjectRef } from 'react-aria';\nimport { Link as RACLink, type LinkProps as RACLinkProps } from 'react-aria-components';\nimport { forwardRef } from '../../forward-ref.js';\nimport { withStyleProps } from '../../with-style-props.js';\nimport type { NavigationProps, WithRequired } from '../types.js';\nimport { usePreserveFocus } from './disabled-with-reason.js';\nimport { IconButton } from './icon-button.js';\nimport type { BaseButtonProps, SingleIconButtonProps } from './types.js';\n\nexport interface IconLinkButtonProps\n extends\n Omit<BaseButtonProps, 'id'>,\n SingleIconButtonProps,\n WithRequired<NavigationProps, 'href'>,\n Pick<RACLinkProps, 'onHoverStart' | 'onHoverEnd'> {\n /**\n * Whether the button is disabled.\n *\n * Optionally, you can provide an object with the `reason` property explaining why the button is disabled.\n * This information will be shown to the end-users as a tooltip or a popover.\n *\n * @default false\n */\n isDisabled?: boolean | { reason: string };\n}\n\nfunction IconLinkButton(\n {\n icon,\n variant = 'secondary',\n tone = 'base',\n size = 'medium',\n isDisabled = false,\n fullWidth = false,\n UNSAFE_className,\n UNSAFE_style,\n ...props\n }: IconLinkButtonProps,\n ref: ForwardedRef<HTMLAnchorElement>,\n) {\n const linkRef = useObjectRef(ref);\n const buttonRef = useRef<HTMLButtonElement | null>(null);\n\n const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';\n const onFocusChange = usePreserveFocus(linkRef, buttonRef, isDisabled ?? false);\n\n if (hasDisabledReason) {\n // `RACLink` doesn't support aria-disabled while keeping interactivity, so we render an `IconButton` instead\n const { href, target, hrefLang, download, ping, referrerPolicy, rel, routerOptions, ...buttonProps } = props;\n\n return (\n <IconButton\n {...buttonProps}\n ref={buttonRef}\n icon={icon}\n variant={variant}\n tone={tone}\n size={size}\n isDisabled={isDisabled}\n fullWidth={fullWidth}\n UNSAFE_className={UNSAFE_className}\n UNSAFE_style={UNSAFE_style}\n // @ts-expect-error our buttons don't expose `onFocusChange`, but it gets passed to React Aria anyway\n onFocusChange={onFocusChange}\n />\n );\n }\n\n return (\n <RACLink\n {...props}\n ref={linkRef}\n className={clsx('cim-icon-button', UNSAFE_className)}\n style={UNSAFE_style}\n data-variant={variant}\n data-tone={tone}\n data-size={size}\n data-full-width={fullWidth || undefined}\n isDisabled={!!isDisabled}\n onFocusChange={onFocusChange}\n >\n {icon}\n </RACLink>\n );\n}\n\n/**\n * Displays an icon-only button that allows users to navigate to another page or resource.\n *\n * See [button usage guidelines](https://ui.cimpress.io/components/button/).\n */\nconst _IconLinkButton = withStyleProps(forwardRef(IconLinkButton), 'IconLinkButton');\n\nexport { _IconLinkButton as IconLinkButton };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/link-button.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/link-button.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAmB,KAAK,SAAS,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGxF,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGjE,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,WAAW,eACf,SACE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,EAC3B,eAAe,EACf,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,EACrC,IAAI,CAAC,YAAY,EAAE,cAAc,GAAG,YAAY,CAAC;IACnD;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAqED;;;;GAIG;AACH,QAAA,MAAM,WAAW,oKAAuD,CAAC;AAEzE,OAAO,EAAE,WAAW,IAAI,UAAU,EAAE,CAAC"}
|
|
@@ -7,18 +7,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.LinkButton = void 0;
|
|
8
8
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
9
|
const clsx_1 = __importDefault(require("clsx"));
|
|
10
|
+
const react_1 = require("react");
|
|
11
|
+
const react_aria_1 = require("react-aria");
|
|
10
12
|
const react_aria_components_1 = require("react-aria-components");
|
|
11
13
|
const forward_ref_js_1 = require("../../forward-ref.js");
|
|
12
14
|
const with_style_props_js_1 = require("../../with-style-props.js");
|
|
13
15
|
const button_js_1 = require("./button.js");
|
|
16
|
+
const disabled_with_reason_js_1 = require("./disabled-with-reason.js");
|
|
14
17
|
function LinkButton({ children, variant = 'secondary', tone = 'base', size = 'medium', iconStart, iconEnd, isDisabled = false, fullWidth = false, UNSAFE_className, UNSAFE_style, ...props }, ref) {
|
|
18
|
+
const linkRef = (0, react_aria_1.useObjectRef)(ref);
|
|
19
|
+
const buttonRef = (0, react_1.useRef)(null);
|
|
15
20
|
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
21
|
+
const onFocusChange = (0, disabled_with_reason_js_1.usePreserveFocus)(linkRef, buttonRef, isDisabled ?? false);
|
|
16
22
|
if (hasDisabledReason) {
|
|
17
23
|
// `RACLink` doesn't support aria-disabled while keeping interactivity, so we render a `Button` instead
|
|
18
24
|
const { href, target, hrefLang, download, ping, referrerPolicy, rel, routerOptions, ...buttonProps } = props;
|
|
19
|
-
return ((0, jsx_runtime_1.jsx)(button_js_1.Button, { ...buttonProps, variant: variant, tone: tone, size: size, iconStart: iconStart, iconEnd: iconEnd, isDisabled: isDisabled, fullWidth: fullWidth, UNSAFE_className: UNSAFE_className, UNSAFE_style: UNSAFE_style,
|
|
25
|
+
return ((0, jsx_runtime_1.jsx)(button_js_1.Button, { ...buttonProps, ref: buttonRef, variant: variant, tone: tone, size: size, iconStart: iconStart, iconEnd: iconEnd, isDisabled: isDisabled, fullWidth: fullWidth, UNSAFE_className: UNSAFE_className, UNSAFE_style: UNSAFE_style,
|
|
26
|
+
// @ts-expect-error our buttons don't expose `onFocusChange`, but it gets passed to React Aria anyway
|
|
27
|
+
onFocusChange: onFocusChange, children: children }));
|
|
20
28
|
}
|
|
21
|
-
return ((0, jsx_runtime_1.jsxs)(react_aria_components_1.Link, { ...props, ref:
|
|
29
|
+
return ((0, jsx_runtime_1.jsxs)(react_aria_components_1.Link, { ...props, ref: linkRef, className: (0, clsx_1.default)('cim-button', UNSAFE_className), style: UNSAFE_style, "data-variant": variant, "data-tone": tone, "data-size": size, "data-full-width": fullWidth || undefined, isDisabled: !!isDisabled, onFocusChange: onFocusChange, children: [iconStart, (0, jsx_runtime_1.jsx)("span", { className: "cim-button-text", children: children }), iconEnd] }));
|
|
22
30
|
}
|
|
23
31
|
/**
|
|
24
32
|
* Displays a labelled button that allows users to navigate to another page or resource.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-button.js","sourceRoot":"","sources":["../../../../src/components/button/link-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;AAEb,gDAAwB;
|
|
1
|
+
{"version":3,"file":"link-button.js","sourceRoot":"","sources":["../../../../src/components/button/link-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;AAEb,gDAAwB;AACxB,iCAAkD;AAClD,2CAA0C;AAC1C,iEAAwF;AACxF,yDAAkD;AAClD,mEAA2D;AAE3D,2CAAqC;AACrC,uEAA6D;AAoB7D,SAAS,UAAU,CACjB,EACE,QAAQ,EACR,OAAO,GAAG,WAAW,EACrB,IAAI,GAAG,MAAM,EACb,IAAI,GAAG,QAAQ,EACf,SAAS,EACT,OAAO,EACP,UAAU,GAAG,KAAK,EAClB,SAAS,GAAG,KAAK,EACjB,gBAAgB,EAChB,YAAY,EACZ,GAAG,KAAK,EACQ,EAClB,GAAoC;IAEpC,MAAM,OAAO,GAAG,IAAA,yBAAY,EAAC,GAAG,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,IAAA,cAAM,EAA2B,IAAI,CAAC,CAAC;IAEzD,MAAM,iBAAiB,GAAG,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,KAAK,EAAE,CAAC;IACrF,MAAM,aAAa,GAAG,IAAA,0CAAgB,EAAC,OAAO,EAAE,SAAS,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC;IAEhF,IAAI,iBAAiB,EAAE,CAAC;QACtB,uGAAuG;QACvG,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,WAAW,EAAE,GAAG,KAAK,CAAC;QAE7G,OAAO,CACL,uBAAC,kBAAM,OACD,WAAW,EACf,GAAG,EAAE,SAAS,EACd,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,gBAAgB,EAAE,gBAAgB,EAClC,YAAY,EAAE,YAAY;YAC1B,qGAAqG;YACrG,aAAa,EAAE,aAAa,YAE3B,QAAQ,GACF,CACV,CAAC;IACJ,CAAC;IAED,OAAO,CACL,wBAAC,4BAAO,OACF,KAAK,EACT,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,IAAA,cAAI,EAAC,YAAY,EAAE,gBAAgB,CAAC,EAC/C,KAAK,EAAE,YAAY,kBACL,OAAO,eACV,IAAI,eACJ,IAAI,qBACE,SAAS,IAAI,SAAS,EACvC,UAAU,EAAE,CAAC,CAAC,UAAU,EACxB,aAAa,EAAE,aAAa,aAE3B,SAAS,EACV,iCAAM,SAAS,EAAC,iBAAiB,YAAE,QAAQ,GAAQ,EAClD,OAAO,IACA,CACX,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,WAAW,GAAG,IAAA,oCAAc,EAAC,IAAA,2BAAU,EAAC,UAAU,CAAC,EAAE,YAAY,CAAC,CAAC;AAEjD,iCAAU","sourcesContent":["'use client';\n\nimport clsx from 'clsx';\nimport { useRef, type ForwardedRef } from 'react';\nimport { useObjectRef } from 'react-aria';\nimport { Link as RACLink, type LinkProps as RACLinkProps } from 'react-aria-components';\nimport { forwardRef } from '../../forward-ref.js';\nimport { withStyleProps } from '../../with-style-props.js';\nimport type { NavigationProps, WithRequired } from '../types.js';\nimport { Button } from './button.js';\nimport { usePreserveFocus } from './disabled-with-reason.js';\nimport type { BaseButtonProps, TextButtonProps } from './types.js';\n\nexport interface LinkButtonProps\n extends\n Omit<BaseButtonProps, 'id'>,\n TextButtonProps,\n WithRequired<NavigationProps, 'href'>,\n Pick<RACLinkProps, 'onHoverStart' | 'onHoverEnd'> {\n /**\n * Whether the button is disabled.\n *\n * Optionally, you can provide an object with the `reason` property explaining why the button is disabled.\n * This information will be shown to the end-users as a tooltip or a popover.\n *\n * @default false\n */\n isDisabled?: boolean | { reason: string };\n}\n\nfunction LinkButton(\n {\n children,\n variant = 'secondary',\n tone = 'base',\n size = 'medium',\n iconStart,\n iconEnd,\n isDisabled = false,\n fullWidth = false,\n UNSAFE_className,\n UNSAFE_style,\n ...props\n }: LinkButtonProps,\n ref: ForwardedRef<HTMLAnchorElement>,\n) {\n const linkRef = useObjectRef(ref);\n const buttonRef = useRef<HTMLButtonElement | null>(null);\n\n const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';\n const onFocusChange = usePreserveFocus(linkRef, buttonRef, isDisabled ?? false);\n\n if (hasDisabledReason) {\n // `RACLink` doesn't support aria-disabled while keeping interactivity, so we render a `Button` instead\n const { href, target, hrefLang, download, ping, referrerPolicy, rel, routerOptions, ...buttonProps } = props;\n\n return (\n <Button\n {...buttonProps}\n ref={buttonRef}\n variant={variant}\n tone={tone}\n size={size}\n iconStart={iconStart}\n iconEnd={iconEnd}\n isDisabled={isDisabled}\n fullWidth={fullWidth}\n UNSAFE_className={UNSAFE_className}\n UNSAFE_style={UNSAFE_style}\n // @ts-expect-error our buttons don't expose `onFocusChange`, but it gets passed to React Aria anyway\n onFocusChange={onFocusChange}\n >\n {children}\n </Button>\n );\n }\n\n return (\n <RACLink\n {...props}\n ref={linkRef}\n className={clsx('cim-button', UNSAFE_className)}\n style={UNSAFE_style}\n data-variant={variant}\n data-tone={tone}\n data-size={size}\n data-full-width={fullWidth || undefined}\n isDisabled={!!isDisabled}\n onFocusChange={onFocusChange}\n >\n {iconStart}\n <span className=\"cim-button-text\">{children}</span>\n {iconEnd}\n </RACLink>\n );\n}\n\n/**\n * Displays a labelled button that allows users to navigate to another page or resource.\n *\n * See [button usage guidelines](https://ui.cimpress.io/components/button/).\n */\nconst _LinkButton = withStyleProps(forwardRef(LinkButton), 'LinkButton');\n\nexport { _LinkButton as LinkButton };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/button.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/button.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEtF,MAAM,WAAW,WAAY,SAAQ,eAAe,EAAE,eAAe,EAAE,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAC;IAC1G;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AA6DD;;;;GAIG;AACH,QAAA,MAAM,OAAO,gKAA+C,CAAC;AAE7D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,CAAC"}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import clsx from 'clsx';
|
|
4
|
+
import { useObjectRef } from 'react-aria';
|
|
4
5
|
import { Button as RACButton } from 'react-aria-components';
|
|
5
6
|
import { forwardRef } from '../../forward-ref.js';
|
|
6
7
|
import { useProductionWarning } from '../../utils/use-production-warning.js';
|
|
7
8
|
import { withStyleProps } from '../../with-style-props.js';
|
|
8
9
|
import { InternalSpinner } from '../internal/spinner/spinner.js';
|
|
9
10
|
import { SPINNER_SIZES } from './constants.js';
|
|
10
|
-
import { DisabledWithReason, useDisableInteractions } from './disabled-with-reason.js';
|
|
11
|
+
import { DisabledWithReason, useDisableInteractions, usePreserveFocus } from './disabled-with-reason.js';
|
|
11
12
|
function Button({ children, variant = 'secondary', tone = 'base', size = 'medium', iconStart, iconEnd, isLoading, loadingLabel, isDisabled, fullWidth, UNSAFE_className, UNSAFE_style, slot, ...props }, ref) {
|
|
13
|
+
const buttonRef = useObjectRef(ref);
|
|
12
14
|
useProductionWarning(() => {
|
|
13
15
|
if (isLoading && !loadingLabel) {
|
|
14
16
|
console.warn('Button requires loadingLabel when isLoading is true for accessibility');
|
|
@@ -16,7 +18,8 @@ function Button({ children, variant = 'secondary', tone = 'base', size = 'medium
|
|
|
16
18
|
}, [isLoading, loadingLabel]);
|
|
17
19
|
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
18
20
|
props = useDisableInteractions(props, isDisabled ?? false);
|
|
19
|
-
const
|
|
21
|
+
const onFocusChange = usePreserveFocus(buttonRef, buttonRef, isDisabled ?? false);
|
|
22
|
+
const button = (_jsx(RACButton, { ...props, ref: buttonRef, slot: slot, className: clsx('cim-button', UNSAFE_className), style: UNSAFE_style, "data-variant": variant, "data-tone": tone, "data-size": size, "data-full-width": fullWidth || undefined, isPending: isLoading, onFocusChange: onFocusChange, children: ({ isPending }) => (_jsxs(_Fragment, { children: [iconStart, _jsx("span", { className: "cim-button-text", children: children }), iconEnd, isPending && _jsx(InternalSpinner, { size: SPINNER_SIZES[size], "aria-label": loadingLabel })] })) }));
|
|
20
23
|
return hasDisabledReason ? _jsx(DisabledWithReason, { reason: isDisabled.reason, children: button }) : button;
|
|
21
24
|
}
|
|
22
25
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.js","sourceRoot":"","sources":["../../../../src/components/button/button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"button.js","sourceRoot":"","sources":["../../../../src/components/button/button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAezG,SAAS,MAAM,CACb,EACE,QAAQ,EACR,OAAO,GAAG,WAAW,EACrB,IAAI,GAAG,MAAM,EACb,IAAI,GAAG,QAAQ,EACf,SAAS,EACT,OAAO,EACP,SAAS,EACT,YAAY,EACZ,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,IAAI,EACJ,GAAG,KAAK,EACI,EACd,GAAoC;IAEpC,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAEpC,oBAAoB,CAAC,GAAG,EAAE;QACxB,IAAI,SAAS,IAAI,CAAC,YAAY,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,uEAAuE,CAAC,CAAC;QACxF,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;IAE9B,MAAM,iBAAiB,GAAG,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,KAAK,EAAE,CAAC;IACrF,KAAK,GAAG,sBAAsB,CAAC,KAAK,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC;IAC3D,MAAM,aAAa,GAAG,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC;IAElF,MAAM,MAAM,GAAG,CACb,KAAC,SAAS,OACJ,KAAK,EACT,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,IAAI,CAAC,YAAY,EAAE,gBAAgB,CAAC,EAC/C,KAAK,EAAE,YAAY,kBACL,OAAO,eACV,IAAI,eACJ,IAAI,qBACE,SAAS,IAAI,SAAS,EACvC,SAAS,EAAE,SAAS,EACpB,aAAa,EAAE,aAAa,YAE3B,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAClB,8BACG,SAAS,EACV,eAAM,SAAS,EAAC,iBAAiB,YAAE,QAAQ,GAAQ,EAClD,OAAO,EACP,SAAS,IAAI,KAAC,eAAe,IAAC,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC,gBAAc,YAAY,GAAI,IACrF,CACJ,GACS,CACb,CAAC;IAEF,OAAO,iBAAiB,CAAC,CAAC,CAAC,KAAC,kBAAkB,IAAC,MAAM,EAAE,UAAU,CAAC,MAAM,YAAG,MAAM,GAAsB,CAAC,CAAC,CAAC,MAAM,CAAC;AACnH,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,GAAG,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;AAE7D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,CAAC","sourcesContent":["'use client';\n\nimport clsx from 'clsx';\nimport type { ForwardedRef } from 'react';\nimport { useObjectRef } from 'react-aria';\nimport { Button as RACButton } from 'react-aria-components';\nimport { forwardRef } from '../../forward-ref.js';\nimport { useProductionWarning } from '../../utils/use-production-warning.js';\nimport { withStyleProps } from '../../with-style-props.js';\nimport { InternalSpinner } from '../internal/spinner/spinner.js';\nimport { SPINNER_SIZES } from './constants.js';\nimport { DisabledWithReason, useDisableInteractions, usePreserveFocus } from './disabled-with-reason.js';\nimport type { ActionButtonProps, BaseButtonProps, TextButtonProps } from './types.js';\n\nexport interface ButtonProps extends BaseButtonProps, TextButtonProps, Omit<ActionButtonProps, 'isDisabled'> {\n /**\n * Whether the button is disabled.\n *\n * Optionally, you can provide an object with the `reason` property explaining why the button is disabled.\n * This information will be shown to end-users as a tooltip or a popover.\n *\n * @default false\n */\n isDisabled?: boolean | { reason: string };\n}\n\nfunction Button(\n {\n children,\n variant = 'secondary',\n tone = 'base',\n size = 'medium',\n iconStart,\n iconEnd,\n isLoading,\n loadingLabel,\n isDisabled,\n fullWidth,\n UNSAFE_className,\n UNSAFE_style,\n slot,\n ...props\n }: ButtonProps,\n ref: ForwardedRef<HTMLButtonElement>,\n) {\n const buttonRef = useObjectRef(ref);\n\n useProductionWarning(() => {\n if (isLoading && !loadingLabel) {\n console.warn('Button requires loadingLabel when isLoading is true for accessibility');\n }\n }, [isLoading, loadingLabel]);\n\n const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';\n props = useDisableInteractions(props, isDisabled ?? false);\n const onFocusChange = usePreserveFocus(buttonRef, buttonRef, isDisabled ?? false);\n\n const button = (\n <RACButton\n {...props}\n ref={buttonRef}\n slot={slot}\n className={clsx('cim-button', UNSAFE_className)}\n style={UNSAFE_style}\n data-variant={variant}\n data-tone={tone}\n data-size={size}\n data-full-width={fullWidth || undefined}\n isPending={isLoading}\n onFocusChange={onFocusChange}\n >\n {({ isPending }) => (\n <>\n {iconStart}\n <span className=\"cim-button-text\">{children}</span>\n {iconEnd}\n {isPending && <InternalSpinner size={SPINNER_SIZES[size]} aria-label={loadingLabel} />}\n </>\n )}\n </RACButton>\n );\n\n return hasDisabledReason ? <DisabledWithReason reason={isDisabled.reason}>{button}</DisabledWithReason> : button;\n}\n\n/**\n * Displays a labelled button that allows users to perform an action.\n *\n * See [button usage guidelines](https://ui.cimpress.io/components/button/).\n */\nconst _Button = withStyleProps(forwardRef(Button), 'Button');\n\nexport { _Button as Button };\n"]}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useLayoutEffect } from '@react-aria/utils';
|
|
3
|
+
import { useEffect, useRef } from 'react';
|
|
2
4
|
import { useMediaQuery } from '../../utils/use-media-query.js';
|
|
3
5
|
import { Popover, PopoverRoot } from '../popover/popover.js';
|
|
4
6
|
import { Tooltip } from '../tooltip/tooltip.js';
|
|
@@ -36,4 +38,27 @@ export function useDisableInteractions(props, isDisabled) {
|
|
|
36
38
|
}
|
|
37
39
|
return props;
|
|
38
40
|
}
|
|
41
|
+
/** @internal */
|
|
42
|
+
// eslint-disable-next-line react-refresh/only-export-components
|
|
43
|
+
export function usePreserveFocus(enabledRef, disabledRef, isDisabled) {
|
|
44
|
+
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
45
|
+
const isFocusable = !isDisabled || hasDisabledReason;
|
|
46
|
+
const isFocusedRef = useRef(false);
|
|
47
|
+
const wasFocusableRef = useRef(isFocusable);
|
|
48
|
+
useLayoutEffect(() => {
|
|
49
|
+
// Refocus button if focus was lost when changing between "enabled" and "disabled with a reason"
|
|
50
|
+
if (isFocusedRef.current && wasFocusableRef.current && isFocusable && document.activeElement === document.body) {
|
|
51
|
+
if (hasDisabledReason) {
|
|
52
|
+
disabledRef.current?.focus();
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
enabledRef.current?.focus();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}, [hasDisabledReason, isFocusable, enabledRef, disabledRef]);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
wasFocusableRef.current = isFocusable;
|
|
61
|
+
}, [isFocusable]);
|
|
62
|
+
return (isFocused) => (isFocusedRef.current = isFocused);
|
|
63
|
+
}
|
|
39
64
|
//# sourceMappingURL=disabled-with-reason.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"disabled-with-reason.js","sourceRoot":"","sources":["../../../../src/components/button/disabled-with-reason.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"disabled-with-reason.js","sourceRoot":"","sources":["../../../../src/components/button/disabled-with-reason.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect } from '@react-aria/utils';\nimport { useEffect, useRef, type HTMLAttributes, type MutableRefObject, type ReactNode } from 'react';\nimport type { ButtonProps as RACButtonProps } from 'react-aria-components';\nimport { useMediaQuery } from '../../utils/use-media-query.js';\nimport { Popover, PopoverRoot } from '../popover/popover.js';\nimport { Tooltip } from '../tooltip/tooltip.js';\nimport type { FocusableElement } from '../types.js';\n\n/** @internal */\nexport function DisabledWithReason({ children, reason }: { children: ReactNode; reason: string }) {\n const hasHover = useMediaQuery('(hover: hover)', { defaultValue: true, initializeWithValue: true });\n\n if (hasHover) {\n return <Tooltip label={reason}>{children}</Tooltip>;\n } else {\n return (\n <PopoverRoot>\n {children}\n {/* TODO: add aria-label */}\n <Popover>{reason}</Popover>\n </PopoverRoot>\n );\n }\n}\n\n// Events to preserve when `isDisabled` is true (for tooltips and other overlays)\nconst PRESERVED_EVENT_PATTERN = /Focus|Blur|Hover|Pointer(Enter|Leave|Over|Out)|Mouse(Enter|Leave|Over|Out)/;\n\n/** @internal */\n// eslint-disable-next-line react-refresh/only-export-components\nexport function useDisableInteractions<T extends Partial<RACButtonProps & HTMLAttributes<HTMLButtonElement>>>(\n props: T,\n isDisabled: boolean | { reason: string },\n): T {\n if (isDisabled !== false) {\n for (const key in props) {\n if (key.startsWith('on') && !PRESERVED_EVENT_PATTERN.test(key)) {\n delete props[key];\n }\n }\n }\n\n if (typeof isDisabled === 'object' && isDisabled.reason) {\n // Use `aria-disabled` instead of `disabled`\n props['aria-disabled'] = true;\n // Prevent form submission\n props.type = props.type === 'submit' ? 'button' : props.type;\n } else if (isDisabled !== false) {\n // Make the button actually disabled\n props.isDisabled = true;\n }\n\n return props;\n}\n\n/** @internal */\n// eslint-disable-next-line react-refresh/only-export-components\nexport function usePreserveFocus(\n enabledRef: MutableRefObject<FocusableElement | null>,\n disabledRef: MutableRefObject<FocusableElement | null>,\n isDisabled: boolean | { reason: string },\n): (isFocused: boolean) => void {\n const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';\n const isFocusable = !isDisabled || hasDisabledReason;\n\n const isFocusedRef = useRef<boolean>(false);\n const wasFocusableRef = useRef<boolean>(isFocusable);\n\n useLayoutEffect(() => {\n // Refocus button if focus was lost when changing between \"enabled\" and \"disabled with a reason\"\n if (isFocusedRef.current && wasFocusableRef.current && isFocusable && document.activeElement === document.body) {\n if (hasDisabledReason) {\n disabledRef.current?.focus();\n } else {\n enabledRef.current?.focus();\n }\n }\n }, [hasDisabledReason, isFocusable, enabledRef, disabledRef]);\n\n useEffect(() => {\n wasFocusableRef.current = isFocusable;\n }, [isFocusable]);\n\n return (isFocused) => (isFocusedRef.current = isFocused);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/icon-button.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"icon-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/icon-button.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE5F,MAAM,WAAW,eAAgB,SAAQ,eAAe,EAAE,qBAAqB,EAAE,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAC;IACpH;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAyDD;;;;GAIG;AACH,QAAA,MAAM,WAAW,oKAAuD,CAAC;AAEzE,OAAO,EAAE,WAAW,IAAI,UAAU,EAAE,CAAC"}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import clsx from 'clsx';
|
|
4
|
+
import { useObjectRef } from 'react-aria';
|
|
4
5
|
import { Button as RACButton } from 'react-aria-components';
|
|
5
6
|
import { forwardRef } from '../../forward-ref.js';
|
|
6
7
|
import { useProductionWarning } from '../../utils/use-production-warning.js';
|
|
7
8
|
import { withStyleProps } from '../../with-style-props.js';
|
|
8
9
|
import { InternalSpinner } from '../internal/spinner/spinner.js';
|
|
9
10
|
import { SPINNER_SIZES } from './constants.js';
|
|
10
|
-
import { DisabledWithReason, useDisableInteractions } from './disabled-with-reason.js';
|
|
11
|
+
import { DisabledWithReason, useDisableInteractions, usePreserveFocus } from './disabled-with-reason.js';
|
|
11
12
|
function IconButton({ icon, variant = 'secondary', tone = 'base', size = 'medium', isLoading, loadingLabel, isDisabled, fullWidth, UNSAFE_className, UNSAFE_style, slot, ...props }, ref) {
|
|
13
|
+
const buttonRef = useObjectRef(ref);
|
|
12
14
|
useProductionWarning(() => {
|
|
13
15
|
if (isLoading && !loadingLabel) {
|
|
14
16
|
console.warn('IconButton requires loadingLabel when isLoading is true for accessibility');
|
|
@@ -16,7 +18,8 @@ function IconButton({ icon, variant = 'secondary', tone = 'base', size = 'medium
|
|
|
16
18
|
}, [isLoading, loadingLabel]);
|
|
17
19
|
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
18
20
|
props = useDisableInteractions(props, isDisabled ?? false);
|
|
19
|
-
const
|
|
21
|
+
const onFocusChange = usePreserveFocus(buttonRef, buttonRef, isDisabled ?? false);
|
|
22
|
+
const button = (_jsx(RACButton, { ...props, ref: buttonRef, slot: slot, className: clsx('cim-icon-button', UNSAFE_className), style: UNSAFE_style, "data-variant": variant, "data-tone": tone, "data-size": size, "data-full-width": fullWidth || undefined, isPending: isLoading, onFocusChange: onFocusChange, children: ({ isPending }) => (_jsxs(_Fragment, { children: [icon, isPending && _jsx(InternalSpinner, { size: SPINNER_SIZES[size], "aria-label": loadingLabel })] })) }));
|
|
20
23
|
return hasDisabledReason ? _jsx(DisabledWithReason, { reason: isDisabled.reason, children: button }) : button;
|
|
21
24
|
}
|
|
22
25
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-button.js","sourceRoot":"","sources":["../../../../src/components/button/icon-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"icon-button.js","sourceRoot":"","sources":["../../../../src/components/button/icon-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAezG,SAAS,UAAU,CACjB,EACE,IAAI,EACJ,OAAO,GAAG,WAAW,EACrB,IAAI,GAAG,MAAM,EACb,IAAI,GAAG,QAAQ,EACf,SAAS,EACT,YAAY,EACZ,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,IAAI,EACJ,GAAG,KAAK,EACQ,EAClB,GAAoC;IAEpC,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAEpC,oBAAoB,CAAC,GAAG,EAAE;QACxB,IAAI,SAAS,IAAI,CAAC,YAAY,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,2EAA2E,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;IAE9B,MAAM,iBAAiB,GAAG,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,KAAK,EAAE,CAAC;IACrF,KAAK,GAAG,sBAAsB,CAAC,KAAK,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC;IAC3D,MAAM,aAAa,GAAG,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC;IAElF,MAAM,MAAM,GAAG,CACb,KAAC,SAAS,OACJ,KAAK,EACT,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,EACpD,KAAK,EAAE,YAAY,kBACL,OAAO,eACV,IAAI,eACJ,IAAI,qBACE,SAAS,IAAI,SAAS,EACvC,SAAS,EAAE,SAAS,EACpB,aAAa,EAAE,aAAa,YAE3B,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAClB,8BACG,IAAI,EACJ,SAAS,IAAI,KAAC,eAAe,IAAC,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC,gBAAc,YAAY,GAAI,IACrF,CACJ,GACS,CACb,CAAC;IAEF,OAAO,iBAAiB,CAAC,CAAC,CAAC,KAAC,kBAAkB,IAAC,MAAM,EAAE,UAAU,CAAC,MAAM,YAAG,MAAM,GAAsB,CAAC,CAAC,CAAC,MAAM,CAAC;AACnH,CAAC;AAED;;;;GAIG;AACH,MAAM,WAAW,GAAG,cAAc,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,YAAY,CAAC,CAAC;AAEzE,OAAO,EAAE,WAAW,IAAI,UAAU,EAAE,CAAC","sourcesContent":["'use client';\n\nimport clsx from 'clsx';\nimport type { ForwardedRef } from 'react';\nimport { useObjectRef } from 'react-aria';\nimport { Button as RACButton } from 'react-aria-components';\nimport { forwardRef } from '../../forward-ref.js';\nimport { useProductionWarning } from '../../utils/use-production-warning.js';\nimport { withStyleProps } from '../../with-style-props.js';\nimport { InternalSpinner } from '../internal/spinner/spinner.js';\nimport { SPINNER_SIZES } from './constants.js';\nimport { DisabledWithReason, useDisableInteractions, usePreserveFocus } from './disabled-with-reason.js';\nimport type { ActionButtonProps, BaseButtonProps, SingleIconButtonProps } from './types.js';\n\nexport interface IconButtonProps extends BaseButtonProps, SingleIconButtonProps, Omit<ActionButtonProps, 'isDisabled'> {\n /**\n * Whether the button is disabled.\n *\n * Optionally, you can provide an object with the `reason` property explaining why the button is disabled.\n * This information will be shown to the end-users as a tooltip or a popover.\n *\n * @default false\n */\n isDisabled?: boolean | { reason: string };\n}\n\nfunction IconButton(\n {\n icon,\n variant = 'secondary',\n tone = 'base',\n size = 'medium',\n isLoading,\n loadingLabel,\n isDisabled,\n fullWidth,\n UNSAFE_className,\n UNSAFE_style,\n slot,\n ...props\n }: IconButtonProps,\n ref: ForwardedRef<HTMLButtonElement>,\n) {\n const buttonRef = useObjectRef(ref);\n\n useProductionWarning(() => {\n if (isLoading && !loadingLabel) {\n console.warn('IconButton requires loadingLabel when isLoading is true for accessibility');\n }\n }, [isLoading, loadingLabel]);\n\n const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';\n props = useDisableInteractions(props, isDisabled ?? false);\n const onFocusChange = usePreserveFocus(buttonRef, buttonRef, isDisabled ?? false);\n\n const button = (\n <RACButton\n {...props}\n ref={buttonRef}\n slot={slot}\n className={clsx('cim-icon-button', UNSAFE_className)}\n style={UNSAFE_style}\n data-variant={variant}\n data-tone={tone}\n data-size={size}\n data-full-width={fullWidth || undefined}\n isPending={isLoading}\n onFocusChange={onFocusChange}\n >\n {({ isPending }) => (\n <>\n {icon}\n {isPending && <InternalSpinner size={SPINNER_SIZES[size]} aria-label={loadingLabel} />}\n </>\n )}\n </RACButton>\n );\n\n return hasDisabledReason ? <DisabledWithReason reason={isDisabled.reason}>{button}</DisabledWithReason> : button;\n}\n\n/**\n * Displays an icon-only button that allows users to perform an action.\n *\n * See [button usage guidelines](https://ui.cimpress.io/components/button/).\n */\nconst _IconButton = withStyleProps(forwardRef(IconButton), 'IconButton');\n\nexport { _IconButton as IconButton };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/icon-link-button.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"icon-link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/icon-link-button.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAmB,KAAK,SAAS,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGxF,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGjE,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,WAAW,mBACf,SACE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,EAC3B,qBAAqB,EACrB,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,EACrC,IAAI,CAAC,YAAY,EAAE,cAAc,GAAG,YAAY,CAAC;IACnD;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AA8DD;;;;GAIG;AACH,QAAA,MAAM,eAAe,wKAA+D,CAAC;AAErF,OAAO,EAAE,eAAe,IAAI,cAAc,EAAE,CAAC"}
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import clsx from 'clsx';
|
|
4
|
+
import { useRef } from 'react';
|
|
5
|
+
import { useObjectRef } from 'react-aria';
|
|
4
6
|
import { Link as RACLink } from 'react-aria-components';
|
|
5
7
|
import { forwardRef } from '../../forward-ref.js';
|
|
6
8
|
import { withStyleProps } from '../../with-style-props.js';
|
|
9
|
+
import { usePreserveFocus } from './disabled-with-reason.js';
|
|
7
10
|
import { IconButton } from './icon-button.js';
|
|
8
11
|
function IconLinkButton({ icon, variant = 'secondary', tone = 'base', size = 'medium', isDisabled = false, fullWidth = false, UNSAFE_className, UNSAFE_style, ...props }, ref) {
|
|
12
|
+
const linkRef = useObjectRef(ref);
|
|
13
|
+
const buttonRef = useRef(null);
|
|
9
14
|
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
15
|
+
const onFocusChange = usePreserveFocus(linkRef, buttonRef, isDisabled ?? false);
|
|
10
16
|
if (hasDisabledReason) {
|
|
11
17
|
// `RACLink` doesn't support aria-disabled while keeping interactivity, so we render an `IconButton` instead
|
|
12
18
|
const { href, target, hrefLang, download, ping, referrerPolicy, rel, routerOptions, ...buttonProps } = props;
|
|
13
|
-
return (_jsx(IconButton, { ...buttonProps, icon: icon, variant: variant, tone: tone, size: size, isDisabled: isDisabled, fullWidth: fullWidth, UNSAFE_className: UNSAFE_className, UNSAFE_style: UNSAFE_style
|
|
19
|
+
return (_jsx(IconButton, { ...buttonProps, ref: buttonRef, icon: icon, variant: variant, tone: tone, size: size, isDisabled: isDisabled, fullWidth: fullWidth, UNSAFE_className: UNSAFE_className, UNSAFE_style: UNSAFE_style,
|
|
20
|
+
// @ts-expect-error our buttons don't expose `onFocusChange`, but it gets passed to React Aria anyway
|
|
21
|
+
onFocusChange: onFocusChange }));
|
|
14
22
|
}
|
|
15
|
-
return (_jsx(RACLink, { ...props, ref:
|
|
23
|
+
return (_jsx(RACLink, { ...props, ref: linkRef, className: clsx('cim-icon-button', UNSAFE_className), style: UNSAFE_style, "data-variant": variant, "data-tone": tone, "data-size": size, "data-full-width": fullWidth || undefined, isDisabled: !!isDisabled, onFocusChange: onFocusChange, children: icon }));
|
|
16
24
|
}
|
|
17
25
|
/**
|
|
18
26
|
* Displays an icon-only button that allows users to navigate to another page or resource.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-link-button.js","sourceRoot":"","sources":["../../../../src/components/button/icon-link-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,IAAI,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"icon-link-button.js","sourceRoot":"","sources":["../../../../src/components/button/icon-link-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,EAAqB,MAAM,OAAO,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,IAAI,IAAI,OAAO,EAAkC,MAAM,uBAAuB,CAAC;AACxF,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAoB9C,SAAS,cAAc,CACrB,EACE,IAAI,EACJ,OAAO,GAAG,WAAW,EACrB,IAAI,GAAG,MAAM,EACb,IAAI,GAAG,QAAQ,EACf,UAAU,GAAG,KAAK,EAClB,SAAS,GAAG,KAAK,EACjB,gBAAgB,EAChB,YAAY,EACZ,GAAG,KAAK,EACY,EACtB,GAAoC;IAEpC,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,MAAM,CAA2B,IAAI,CAAC,CAAC;IAEzD,MAAM,iBAAiB,GAAG,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,KAAK,EAAE,CAAC;IACrF,MAAM,aAAa,GAAG,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC;IAEhF,IAAI,iBAAiB,EAAE,CAAC;QACtB,4GAA4G;QAC5G,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,WAAW,EAAE,GAAG,KAAK,CAAC;QAE7G,OAAO,CACL,KAAC,UAAU,OACL,WAAW,EACf,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,gBAAgB,EAAE,gBAAgB,EAClC,YAAY,EAAE,YAAY;YAC1B,qGAAqG;YACrG,aAAa,EAAE,aAAa,GAC5B,CACH,CAAC;IACJ,CAAC;IAED,OAAO,CACL,KAAC,OAAO,OACF,KAAK,EACT,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,EACpD,KAAK,EAAE,YAAY,kBACL,OAAO,eACV,IAAI,eACJ,IAAI,qBACE,SAAS,IAAI,SAAS,EACvC,UAAU,EAAE,CAAC,CAAC,UAAU,EACxB,aAAa,EAAE,aAAa,YAE3B,IAAI,GACG,CACX,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,eAAe,GAAG,cAAc,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,gBAAgB,CAAC,CAAC;AAErF,OAAO,EAAE,eAAe,IAAI,cAAc,EAAE,CAAC","sourcesContent":["'use client';\n\nimport clsx from 'clsx';\nimport { useRef, type ForwardedRef } from 'react';\nimport { useObjectRef } from 'react-aria';\nimport { Link as RACLink, type LinkProps as RACLinkProps } from 'react-aria-components';\nimport { forwardRef } from '../../forward-ref.js';\nimport { withStyleProps } from '../../with-style-props.js';\nimport type { NavigationProps, WithRequired } from '../types.js';\nimport { usePreserveFocus } from './disabled-with-reason.js';\nimport { IconButton } from './icon-button.js';\nimport type { BaseButtonProps, SingleIconButtonProps } from './types.js';\n\nexport interface IconLinkButtonProps\n extends\n Omit<BaseButtonProps, 'id'>,\n SingleIconButtonProps,\n WithRequired<NavigationProps, 'href'>,\n Pick<RACLinkProps, 'onHoverStart' | 'onHoverEnd'> {\n /**\n * Whether the button is disabled.\n *\n * Optionally, you can provide an object with the `reason` property explaining why the button is disabled.\n * This information will be shown to the end-users as a tooltip or a popover.\n *\n * @default false\n */\n isDisabled?: boolean | { reason: string };\n}\n\nfunction IconLinkButton(\n {\n icon,\n variant = 'secondary',\n tone = 'base',\n size = 'medium',\n isDisabled = false,\n fullWidth = false,\n UNSAFE_className,\n UNSAFE_style,\n ...props\n }: IconLinkButtonProps,\n ref: ForwardedRef<HTMLAnchorElement>,\n) {\n const linkRef = useObjectRef(ref);\n const buttonRef = useRef<HTMLButtonElement | null>(null);\n\n const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';\n const onFocusChange = usePreserveFocus(linkRef, buttonRef, isDisabled ?? false);\n\n if (hasDisabledReason) {\n // `RACLink` doesn't support aria-disabled while keeping interactivity, so we render an `IconButton` instead\n const { href, target, hrefLang, download, ping, referrerPolicy, rel, routerOptions, ...buttonProps } = props;\n\n return (\n <IconButton\n {...buttonProps}\n ref={buttonRef}\n icon={icon}\n variant={variant}\n tone={tone}\n size={size}\n isDisabled={isDisabled}\n fullWidth={fullWidth}\n UNSAFE_className={UNSAFE_className}\n UNSAFE_style={UNSAFE_style}\n // @ts-expect-error our buttons don't expose `onFocusChange`, but it gets passed to React Aria anyway\n onFocusChange={onFocusChange}\n />\n );\n }\n\n return (\n <RACLink\n {...props}\n ref={linkRef}\n className={clsx('cim-icon-button', UNSAFE_className)}\n style={UNSAFE_style}\n data-variant={variant}\n data-tone={tone}\n data-size={size}\n data-full-width={fullWidth || undefined}\n isDisabled={!!isDisabled}\n onFocusChange={onFocusChange}\n >\n {icon}\n </RACLink>\n );\n}\n\n/**\n * Displays an icon-only button that allows users to navigate to another page or resource.\n *\n * See [button usage guidelines](https://ui.cimpress.io/components/button/).\n */\nconst _IconLinkButton = withStyleProps(forwardRef(IconLinkButton), 'IconLinkButton');\n\nexport { _IconLinkButton as IconLinkButton };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/link-button.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/link-button.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAmB,KAAK,SAAS,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGxF,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGjE,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,WAAW,eACf,SACE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,EAC3B,eAAe,EACf,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,EACrC,IAAI,CAAC,YAAY,EAAE,cAAc,GAAG,YAAY,CAAC;IACnD;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAqED;;;;GAIG;AACH,QAAA,MAAM,WAAW,oKAAuD,CAAC;AAEzE,OAAO,EAAE,WAAW,IAAI,UAAU,EAAE,CAAC"}
|