@cimpress-ui/react 1.33.1 → 1.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/components/button/button.d.ts +12 -1
- package/dist/commonjs/components/button/button.d.ts.map +1 -1
- package/dist/commonjs/components/button/button.js +6 -2
- package/dist/commonjs/components/button/button.js.map +1 -1
- package/dist/commonjs/components/button/disabled-with-reason.d.ts +2 -0
- package/dist/commonjs/components/button/disabled-with-reason.d.ts.map +1 -0
- package/dist/commonjs/components/button/disabled-with-reason.js +43 -0
- package/dist/commonjs/components/button/disabled-with-reason.js.map +1 -0
- package/dist/commonjs/components/button/icon-button.d.ts +12 -1
- package/dist/commonjs/components/button/icon-button.d.ts.map +1 -1
- package/dist/commonjs/components/button/icon-button.js +6 -2
- package/dist/commonjs/components/button/icon-button.js.map +1 -1
- package/dist/commonjs/components/button/icon-link-button.d.ts +12 -1
- package/dist/commonjs/components/button/icon-link-button.d.ts.map +1 -1
- package/dist/commonjs/components/button/icon-link-button.js +8 -1
- package/dist/commonjs/components/button/icon-link-button.js.map +1 -1
- package/dist/commonjs/components/button/link-button.d.ts +12 -1
- package/dist/commonjs/components/button/link-button.d.ts.map +1 -1
- package/dist/commonjs/components/button/link-button.js +8 -1
- package/dist/commonjs/components/button/link-button.js.map +1 -1
- package/dist/esm/components/button/button.d.ts +12 -1
- package/dist/esm/components/button/button.d.ts.map +1 -1
- package/dist/esm/components/button/button.js +6 -2
- package/dist/esm/components/button/button.js.map +1 -1
- package/dist/esm/components/button/disabled-with-reason.d.ts +2 -0
- package/dist/esm/components/button/disabled-with-reason.d.ts.map +1 -0
- package/dist/esm/components/button/disabled-with-reason.js +39 -0
- package/dist/esm/components/button/disabled-with-reason.js.map +1 -0
- package/dist/esm/components/button/icon-button.d.ts +12 -1
- package/dist/esm/components/button/icon-button.d.ts.map +1 -1
- package/dist/esm/components/button/icon-button.js +6 -2
- package/dist/esm/components/button/icon-button.js.map +1 -1
- package/dist/esm/components/button/icon-link-button.d.ts +12 -1
- package/dist/esm/components/button/icon-link-button.d.ts.map +1 -1
- package/dist/esm/components/button/icon-link-button.js +8 -1
- package/dist/esm/components/button/icon-link-button.js.map +1 -1
- package/dist/esm/components/button/link-button.d.ts +12 -1
- package/dist/esm/components/button/link-button.d.ts.map +1 -1
- package/dist/esm/components/button/link-button.js +8 -1
- 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,5 +1,16 @@
|
|
|
1
1
|
import type { ActionButtonProps, BaseButtonProps, TextButtonProps } from './types.js';
|
|
2
|
-
export interface ButtonProps extends BaseButtonProps, TextButtonProps, ActionButtonProps {
|
|
2
|
+
export interface ButtonProps extends BaseButtonProps, TextButtonProps, Omit<ActionButtonProps, 'isDisabled'> {
|
|
3
|
+
/**
|
|
4
|
+
* Whether the button is disabled.
|
|
5
|
+
*
|
|
6
|
+
* Optionally, you can provide an object with the `reason` property explaining why the button is disabled.
|
|
7
|
+
* This information will be shown to end-users as a tooltip or a popover.
|
|
8
|
+
*
|
|
9
|
+
* @default false
|
|
10
|
+
*/
|
|
11
|
+
isDisabled?: boolean | {
|
|
12
|
+
reason: string;
|
|
13
|
+
};
|
|
3
14
|
}
|
|
4
15
|
/**
|
|
5
16
|
* Displays a labelled button that allows users to perform an action.
|
|
@@ -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":"AAWA,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;AAyDD;;;;GAIG;AACH,QAAA,MAAM,OAAO,gKAA+C,CAAC;AAE7D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,CAAC"}
|
|
@@ -13,13 +13,17 @@ const use_production_warning_js_1 = require("../../utils/use-production-warning.
|
|
|
13
13
|
const with_style_props_js_1 = require("../../with-style-props.js");
|
|
14
14
|
const spinner_js_1 = require("../internal/spinner/spinner.js");
|
|
15
15
|
const constants_js_1 = require("./constants.js");
|
|
16
|
-
|
|
16
|
+
const disabled_with_reason_js_1 = require("./disabled-with-reason.js");
|
|
17
|
+
function Button({ children, variant = 'secondary', tone = 'base', size = 'medium', iconStart, iconEnd, isLoading, loadingLabel, isDisabled, fullWidth, UNSAFE_className, UNSAFE_style, slot, ...props }, ref) {
|
|
17
18
|
(0, use_production_warning_js_1.useProductionWarning)(() => {
|
|
18
19
|
if (isLoading && !loadingLabel) {
|
|
19
20
|
console.warn('Button requires loadingLabel when isLoading is true for accessibility');
|
|
20
21
|
}
|
|
21
22
|
}, [isLoading, loadingLabel]);
|
|
22
|
-
|
|
23
|
+
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
24
|
+
props = (0, disabled_with_reason_js_1.useDisableInteractions)(props, isDisabled ?? false);
|
|
25
|
+
const button = ((0, jsx_runtime_1.jsx)(react_aria_components_1.Button, { ...props, ref: ref, 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, 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
|
+
return hasDisabledReason ? (0, jsx_runtime_1.jsx)(disabled_with_reason_js_1.DisabledWithReason, { reason: isDisabled.reason, children: button }) : button;
|
|
23
27
|
}
|
|
24
28
|
/**
|
|
25
29
|
* Displays a labelled button that allows users to perform an action.
|
|
@@ -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;
|
|
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,uEAAuF;AAevF,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,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;IAE3D,MAAM,MAAM,GAAG,CACb,uBAAC,8BAAS,OACJ,KAAK,EACT,GAAG,EAAE,GAAG,EACR,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,YAEnB,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 { 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 } 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 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\n const button = (\n <RACButton\n {...props}\n ref={ref}\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 >\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"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disabled-with-reason.d.ts","sourceRoot":"","sources":["../../../../src/components/button/disabled-with-reason.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DisabledWithReason = DisabledWithReason;
|
|
4
|
+
exports.useDisableInteractions = useDisableInteractions;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const use_media_query_js_1 = require("../../utils/use-media-query.js");
|
|
7
|
+
const popover_js_1 = require("../popover/popover.js");
|
|
8
|
+
const tooltip_js_1 = require("../tooltip/tooltip.js");
|
|
9
|
+
/** @internal */
|
|
10
|
+
function DisabledWithReason({ children, reason }) {
|
|
11
|
+
const hasHover = (0, use_media_query_js_1.useMediaQuery)('(hover: hover)', { defaultValue: true, initializeWithValue: true });
|
|
12
|
+
if (hasHover) {
|
|
13
|
+
return (0, jsx_runtime_1.jsx)(tooltip_js_1.Tooltip, { label: reason, children: children });
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
return ((0, jsx_runtime_1.jsxs)(popover_js_1.PopoverRoot, { children: [children, (0, jsx_runtime_1.jsx)(popover_js_1.Popover, { children: reason })] }));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
// Events to preserve when `isDisabled` is true (for tooltips and other overlays)
|
|
20
|
+
const PRESERVED_EVENT_PATTERN = /Focus|Blur|Hover|Pointer(Enter|Leave|Over|Out)|Mouse(Enter|Leave|Over|Out)/;
|
|
21
|
+
/** @internal */
|
|
22
|
+
// eslint-disable-next-line react-refresh/only-export-components
|
|
23
|
+
function useDisableInteractions(props, isDisabled) {
|
|
24
|
+
if (isDisabled !== false) {
|
|
25
|
+
for (const key in props) {
|
|
26
|
+
if (key.startsWith('on') && !PRESERVED_EVENT_PATTERN.test(key)) {
|
|
27
|
+
delete props[key];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (typeof isDisabled === 'object' && isDisabled.reason) {
|
|
32
|
+
// Use `aria-disabled` instead of `disabled`
|
|
33
|
+
props['aria-disabled'] = true;
|
|
34
|
+
// Prevent form submission
|
|
35
|
+
props.type = props.type === 'submit' ? 'button' : props.type;
|
|
36
|
+
}
|
|
37
|
+
else if (isDisabled !== false) {
|
|
38
|
+
// Make the button actually disabled
|
|
39
|
+
props.isDisabled = true;
|
|
40
|
+
}
|
|
41
|
+
return props;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=disabled-with-reason.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disabled-with-reason.js","sourceRoot":"","sources":["../../../../src/components/button/disabled-with-reason.tsx"],"names":[],"mappings":";;AAOA,gDAcC;AAOD,wDAuBC;;AAjDD,uEAA+D;AAC/D,sDAA6D;AAC7D,sDAAgD;AAEhD,gBAAgB;AAChB,SAAgB,kBAAkB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAA2C;IAC9F,MAAM,QAAQ,GAAG,IAAA,kCAAa,EAAC,gBAAgB,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC,CAAC;IAEpG,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,uBAAC,oBAAO,IAAC,KAAK,EAAE,MAAM,YAAG,QAAQ,GAAW,CAAC;IACtD,CAAC;SAAM,CAAC;QACN,OAAO,CACL,wBAAC,wBAAW,eACT,QAAQ,EAET,uBAAC,oBAAO,cAAE,MAAM,GAAW,IACf,CACf,CAAC;IACJ,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,MAAM,uBAAuB,GAAG,4EAA4E,CAAC;AAE7G,gBAAgB;AAChB,gEAAgE;AAChE,SAAgB,sBAAsB,CACpC,KAAQ,EACR,UAAwC;IAExC,IAAI,UAAU,KAAK,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;YACxB,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/D,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACxD,4CAA4C;QAC5C,KAAK,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC;QAC9B,0BAA0B;QAC1B,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IAC/D,CAAC;SAAM,IAAI,UAAU,KAAK,KAAK,EAAE,CAAC;QAChC,oCAAoC;QACpC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import type { HTMLAttributes, 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';\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"]}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { ActionButtonProps, BaseButtonProps, SingleIconButtonProps } from './types.js';
|
|
2
|
-
export interface IconButtonProps extends BaseButtonProps, SingleIconButtonProps, ActionButtonProps {
|
|
2
|
+
export interface IconButtonProps extends BaseButtonProps, SingleIconButtonProps, Omit<ActionButtonProps, 'isDisabled'> {
|
|
3
|
+
/**
|
|
4
|
+
* Whether the button is disabled.
|
|
5
|
+
*
|
|
6
|
+
* Optionally, you can provide an object with the `reason` property explaining why the button is disabled.
|
|
7
|
+
* This information will be shown to the end-users as a tooltip or a popover.
|
|
8
|
+
*
|
|
9
|
+
* @default false
|
|
10
|
+
*/
|
|
11
|
+
isDisabled?: boolean | {
|
|
12
|
+
reason: string;
|
|
13
|
+
};
|
|
3
14
|
}
|
|
4
15
|
/**
|
|
5
16
|
* Displays an icon-only button that allows users to perform an action.
|
|
@@ -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":"AAWA,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;AAqDD;;;;GAIG;AACH,QAAA,MAAM,WAAW,oKAAuD,CAAC;AAEzE,OAAO,EAAE,WAAW,IAAI,UAAU,EAAE,CAAC"}
|
|
@@ -13,13 +13,17 @@ const use_production_warning_js_1 = require("../../utils/use-production-warning.
|
|
|
13
13
|
const with_style_props_js_1 = require("../../with-style-props.js");
|
|
14
14
|
const spinner_js_1 = require("../internal/spinner/spinner.js");
|
|
15
15
|
const constants_js_1 = require("./constants.js");
|
|
16
|
-
|
|
16
|
+
const disabled_with_reason_js_1 = require("./disabled-with-reason.js");
|
|
17
|
+
function IconButton({ icon, variant = 'secondary', tone = 'base', size = 'medium', isLoading, loadingLabel, isDisabled, fullWidth, UNSAFE_className, UNSAFE_style, slot, ...props }, ref) {
|
|
17
18
|
(0, use_production_warning_js_1.useProductionWarning)(() => {
|
|
18
19
|
if (isLoading && !loadingLabel) {
|
|
19
20
|
console.warn('IconButton requires loadingLabel when isLoading is true for accessibility');
|
|
20
21
|
}
|
|
21
22
|
}, [isLoading, loadingLabel]);
|
|
22
|
-
|
|
23
|
+
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
24
|
+
props = (0, disabled_with_reason_js_1.useDisableInteractions)(props, isDisabled ?? false);
|
|
25
|
+
const button = ((0, jsx_runtime_1.jsx)(react_aria_components_1.Button, { ...props, ref: ref, 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, 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
|
+
return hasDisabledReason ? (0, jsx_runtime_1.jsx)(disabled_with_reason_js_1.DisabledWithReason, { reason: isDisabled.reason, children: button }) : button;
|
|
23
27
|
}
|
|
24
28
|
/**
|
|
25
29
|
* Displays an icon-only button that allows users to perform an action.
|
|
@@ -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;
|
|
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,uEAAuF;AAevF,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,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;IAE3D,MAAM,MAAM,GAAG,CACb,uBAAC,8BAAS,OACJ,KAAK,EACT,GAAG,EAAE,GAAG,EACR,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,YAEnB,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 { 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 } 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 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\n const button = (\n <RACButton\n {...props}\n ref={ref}\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 >\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,7 +1,18 @@
|
|
|
1
1
|
import { type LinkProps as RACLinkProps } from 'react-aria-components';
|
|
2
2
|
import type { NavigationProps, WithRequired } from '../types.js';
|
|
3
3
|
import type { BaseButtonProps, SingleIconButtonProps } from './types.js';
|
|
4
|
-
export interface IconLinkButtonProps extends Omit<BaseButtonProps, 'id'>, SingleIconButtonProps, WithRequired<NavigationProps, 'href'>, Pick<RACLinkProps, '
|
|
4
|
+
export interface IconLinkButtonProps extends Omit<BaseButtonProps, 'id'>, SingleIconButtonProps, WithRequired<NavigationProps, 'href'>, Pick<RACLinkProps, 'onHoverStart' | 'onHoverEnd'> {
|
|
5
|
+
/**
|
|
6
|
+
* Whether the button is disabled.
|
|
7
|
+
*
|
|
8
|
+
* Optionally, you can provide an object with the `reason` property explaining why the button is disabled.
|
|
9
|
+
* This information will be shown to the end-users as a tooltip or a popover.
|
|
10
|
+
*
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
isDisabled?: boolean | {
|
|
14
|
+
reason: string;
|
|
15
|
+
};
|
|
5
16
|
}
|
|
6
17
|
/**
|
|
7
18
|
* Displays an icon-only button that allows users to navigate to another page or resource.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/icon-link-button.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,SAAS,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGxF,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"icon-link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/icon-link-button.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,SAAS,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGxF,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEjE,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;AAsDD;;;;GAIG;AACH,QAAA,MAAM,eAAe,wKAA+D,CAAC;AAErF,OAAO,EAAE,eAAe,IAAI,cAAc,EAAE,CAAC"}
|
|
@@ -10,8 +10,15 @@ const clsx_1 = __importDefault(require("clsx"));
|
|
|
10
10
|
const react_aria_components_1 = require("react-aria-components");
|
|
11
11
|
const forward_ref_js_1 = require("../../forward-ref.js");
|
|
12
12
|
const with_style_props_js_1 = require("../../with-style-props.js");
|
|
13
|
+
const icon_button_js_1 = require("./icon-button.js");
|
|
13
14
|
function IconLinkButton({ icon, variant = 'secondary', tone = 'base', size = 'medium', isDisabled = false, fullWidth = false, UNSAFE_className, UNSAFE_style, ...props }, ref) {
|
|
14
|
-
|
|
15
|
+
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
16
|
+
if (hasDisabledReason) {
|
|
17
|
+
// `RACLink` doesn't support aria-disabled while keeping interactivity, so we render an `IconButton` instead
|
|
18
|
+
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 }));
|
|
20
|
+
}
|
|
21
|
+
return ((0, jsx_runtime_1.jsx)(react_aria_components_1.Link, { ...props, ref: ref, 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, children: icon }));
|
|
15
22
|
}
|
|
16
23
|
/**
|
|
17
24
|
* 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;AAExB,iEAAwF;AACxF,yDAAkD;AAClD,mEAA2D;
|
|
1
|
+
{"version":3,"file":"icon-link-button.js","sourceRoot":"","sources":["../../../../src/components/button/icon-link-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;AAEb,gDAAwB;AAExB,iEAAwF;AACxF,yDAAkD;AAClD,mEAA2D;AAE3D,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,iBAAiB,GAAG,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,KAAK,EAAE,CAAC;IAErF,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,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,GAC1B,CACH,CAAC;IACJ,CAAC;IAED,OAAO,CACL,uBAAC,4BAAO,OACF,KAAK,EACT,GAAG,EAAE,GAAG,EACR,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,YAEvB,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 type { ForwardedRef } from 'react';\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 { 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 hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';\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 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 />\n );\n }\n\n return (\n <RACLink\n {...props}\n ref={ref}\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 >\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,7 +1,18 @@
|
|
|
1
1
|
import { type LinkProps as RACLinkProps } from 'react-aria-components';
|
|
2
2
|
import type { NavigationProps, WithRequired } from '../types.js';
|
|
3
3
|
import type { BaseButtonProps, TextButtonProps } from './types.js';
|
|
4
|
-
export interface LinkButtonProps extends Omit<BaseButtonProps, 'id'>, TextButtonProps, WithRequired<NavigationProps, 'href'>, Pick<RACLinkProps, '
|
|
4
|
+
export interface LinkButtonProps extends Omit<BaseButtonProps, 'id'>, TextButtonProps, WithRequired<NavigationProps, 'href'>, Pick<RACLinkProps, 'onHoverStart' | 'onHoverEnd'> {
|
|
5
|
+
/**
|
|
6
|
+
* Whether the button is disabled.
|
|
7
|
+
*
|
|
8
|
+
* Optionally, you can provide an object with the `reason` property explaining why the button is disabled.
|
|
9
|
+
* This information will be shown to the end-users as a tooltip or a popover.
|
|
10
|
+
*
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
isDisabled?: boolean | {
|
|
14
|
+
reason: string;
|
|
15
|
+
};
|
|
5
16
|
}
|
|
6
17
|
/**
|
|
7
18
|
* Displays a labelled button that allows users to navigate to another page or resource.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/link-button.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,SAAS,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGxF,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/link-button.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,SAAS,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGxF,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEjE,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;AA6DD;;;;GAIG;AACH,QAAA,MAAM,WAAW,oKAAuD,CAAC;AAEzE,OAAO,EAAE,WAAW,IAAI,UAAU,EAAE,CAAC"}
|
|
@@ -10,8 +10,15 @@ const clsx_1 = __importDefault(require("clsx"));
|
|
|
10
10
|
const react_aria_components_1 = require("react-aria-components");
|
|
11
11
|
const forward_ref_js_1 = require("../../forward-ref.js");
|
|
12
12
|
const with_style_props_js_1 = require("../../with-style-props.js");
|
|
13
|
+
const button_js_1 = require("./button.js");
|
|
13
14
|
function LinkButton({ children, variant = 'secondary', tone = 'base', size = 'medium', iconStart, iconEnd, isDisabled = false, fullWidth = false, UNSAFE_className, UNSAFE_style, ...props }, ref) {
|
|
14
|
-
|
|
15
|
+
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
16
|
+
if (hasDisabledReason) {
|
|
17
|
+
// `RACLink` doesn't support aria-disabled while keeping interactivity, so we render a `Button` instead
|
|
18
|
+
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, children: children }));
|
|
20
|
+
}
|
|
21
|
+
return ((0, jsx_runtime_1.jsxs)(react_aria_components_1.Link, { ...props, ref: ref, 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, children: [iconStart, (0, jsx_runtime_1.jsx)("span", { className: "cim-button-text", children: children }), iconEnd] }));
|
|
15
22
|
}
|
|
16
23
|
/**
|
|
17
24
|
* 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;AAExB,iEAAwF;AACxF,yDAAkD;AAClD,mEAA2D;
|
|
1
|
+
{"version":3,"file":"link-button.js","sourceRoot":"","sources":["../../../../src/components/button/link-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;;;;AAEb,gDAAwB;AAExB,iEAAwF;AACxF,yDAAkD;AAClD,mEAA2D;AAE3D,2CAAqC;AAoBrC,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,iBAAiB,GAAG,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,KAAK,EAAE,CAAC;IAErF,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,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,YAEzB,QAAQ,GACF,CACV,CAAC;IACJ,CAAC;IAED,OAAO,CACL,wBAAC,4BAAO,OACF,KAAK,EACT,GAAG,EAAE,GAAG,EACR,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,aAEvB,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 type { ForwardedRef } from 'react';\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 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 hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';\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 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 >\n {children}\n </Button>\n );\n }\n\n return (\n <RACLink\n {...props}\n ref={ref}\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 >\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,5 +1,16 @@
|
|
|
1
1
|
import type { ActionButtonProps, BaseButtonProps, TextButtonProps } from './types.js';
|
|
2
|
-
export interface ButtonProps extends BaseButtonProps, TextButtonProps, ActionButtonProps {
|
|
2
|
+
export interface ButtonProps extends BaseButtonProps, TextButtonProps, Omit<ActionButtonProps, 'isDisabled'> {
|
|
3
|
+
/**
|
|
4
|
+
* Whether the button is disabled.
|
|
5
|
+
*
|
|
6
|
+
* Optionally, you can provide an object with the `reason` property explaining why the button is disabled.
|
|
7
|
+
* This information will be shown to end-users as a tooltip or a popover.
|
|
8
|
+
*
|
|
9
|
+
* @default false
|
|
10
|
+
*/
|
|
11
|
+
isDisabled?: boolean | {
|
|
12
|
+
reason: string;
|
|
13
|
+
};
|
|
3
14
|
}
|
|
4
15
|
/**
|
|
5
16
|
* Displays a labelled button that allows users to perform an action.
|
|
@@ -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":"AAWA,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;AAyDD;;;;GAIG;AACH,QAAA,MAAM,OAAO,gKAA+C,CAAC;AAE7D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,CAAC"}
|
|
@@ -7,13 +7,17 @@ import { useProductionWarning } from '../../utils/use-production-warning.js';
|
|
|
7
7
|
import { withStyleProps } from '../../with-style-props.js';
|
|
8
8
|
import { InternalSpinner } from '../internal/spinner/spinner.js';
|
|
9
9
|
import { SPINNER_SIZES } from './constants.js';
|
|
10
|
-
|
|
10
|
+
import { DisabledWithReason, useDisableInteractions } from './disabled-with-reason.js';
|
|
11
|
+
function Button({ children, variant = 'secondary', tone = 'base', size = 'medium', iconStart, iconEnd, isLoading, loadingLabel, isDisabled, fullWidth, UNSAFE_className, UNSAFE_style, slot, ...props }, ref) {
|
|
11
12
|
useProductionWarning(() => {
|
|
12
13
|
if (isLoading && !loadingLabel) {
|
|
13
14
|
console.warn('Button requires loadingLabel when isLoading is true for accessibility');
|
|
14
15
|
}
|
|
15
16
|
}, [isLoading, loadingLabel]);
|
|
16
|
-
|
|
17
|
+
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
18
|
+
props = useDisableInteractions(props, isDisabled ?? false);
|
|
19
|
+
const button = (_jsx(RACButton, { ...props, ref: ref, 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, 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
|
+
return hasDisabledReason ? _jsx(DisabledWithReason, { reason: isDisabled.reason, children: button }) : button;
|
|
17
21
|
}
|
|
18
22
|
/**
|
|
19
23
|
* Displays a labelled button that allows users to perform an action.
|
|
@@ -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;
|
|
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;AAevF,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,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;IAE3D,MAAM,MAAM,GAAG,CACb,KAAC,SAAS,OACJ,KAAK,EACT,GAAG,EAAE,GAAG,EACR,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,YAEnB,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 { 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 } 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 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\n const button = (\n <RACButton\n {...props}\n ref={ref}\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 >\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"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disabled-with-reason.d.ts","sourceRoot":"","sources":["../../../../src/components/button/disabled-with-reason.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMediaQuery } from '../../utils/use-media-query.js';
|
|
3
|
+
import { Popover, PopoverRoot } from '../popover/popover.js';
|
|
4
|
+
import { Tooltip } from '../tooltip/tooltip.js';
|
|
5
|
+
/** @internal */
|
|
6
|
+
export function DisabledWithReason({ children, reason }) {
|
|
7
|
+
const hasHover = useMediaQuery('(hover: hover)', { defaultValue: true, initializeWithValue: true });
|
|
8
|
+
if (hasHover) {
|
|
9
|
+
return _jsx(Tooltip, { label: reason, children: children });
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
return (_jsxs(PopoverRoot, { children: [children, _jsx(Popover, { children: reason })] }));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
// Events to preserve when `isDisabled` is true (for tooltips and other overlays)
|
|
16
|
+
const PRESERVED_EVENT_PATTERN = /Focus|Blur|Hover|Pointer(Enter|Leave|Over|Out)|Mouse(Enter|Leave|Over|Out)/;
|
|
17
|
+
/** @internal */
|
|
18
|
+
// eslint-disable-next-line react-refresh/only-export-components
|
|
19
|
+
export function useDisableInteractions(props, isDisabled) {
|
|
20
|
+
if (isDisabled !== false) {
|
|
21
|
+
for (const key in props) {
|
|
22
|
+
if (key.startsWith('on') && !PRESERVED_EVENT_PATTERN.test(key)) {
|
|
23
|
+
delete props[key];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (typeof isDisabled === 'object' && isDisabled.reason) {
|
|
28
|
+
// Use `aria-disabled` instead of `disabled`
|
|
29
|
+
props['aria-disabled'] = true;
|
|
30
|
+
// Prevent form submission
|
|
31
|
+
props.type = props.type === 'submit' ? 'button' : props.type;
|
|
32
|
+
}
|
|
33
|
+
else if (isDisabled !== false) {
|
|
34
|
+
// Make the button actually disabled
|
|
35
|
+
props.isDisabled = true;
|
|
36
|
+
}
|
|
37
|
+
return props;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=disabled-with-reason.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disabled-with-reason.js","sourceRoot":"","sources":["../../../../src/components/button/disabled-with-reason.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD,gBAAgB;AAChB,MAAM,UAAU,kBAAkB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAA2C;IAC9F,MAAM,QAAQ,GAAG,aAAa,CAAC,gBAAgB,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC,CAAC;IAEpG,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,KAAC,OAAO,IAAC,KAAK,EAAE,MAAM,YAAG,QAAQ,GAAW,CAAC;IACtD,CAAC;SAAM,CAAC;QACN,OAAO,CACL,MAAC,WAAW,eACT,QAAQ,EAET,KAAC,OAAO,cAAE,MAAM,GAAW,IACf,CACf,CAAC;IACJ,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,MAAM,uBAAuB,GAAG,4EAA4E,CAAC;AAE7G,gBAAgB;AAChB,gEAAgE;AAChE,MAAM,UAAU,sBAAsB,CACpC,KAAQ,EACR,UAAwC;IAExC,IAAI,UAAU,KAAK,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;YACxB,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/D,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACxD,4CAA4C;QAC5C,KAAK,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC;QAC9B,0BAA0B;QAC1B,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IAC/D,CAAC;SAAM,IAAI,UAAU,KAAK,KAAK,EAAE,CAAC;QAChC,oCAAoC;QACpC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import type { HTMLAttributes, 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';\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"]}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { ActionButtonProps, BaseButtonProps, SingleIconButtonProps } from './types.js';
|
|
2
|
-
export interface IconButtonProps extends BaseButtonProps, SingleIconButtonProps, ActionButtonProps {
|
|
2
|
+
export interface IconButtonProps extends BaseButtonProps, SingleIconButtonProps, Omit<ActionButtonProps, 'isDisabled'> {
|
|
3
|
+
/**
|
|
4
|
+
* Whether the button is disabled.
|
|
5
|
+
*
|
|
6
|
+
* Optionally, you can provide an object with the `reason` property explaining why the button is disabled.
|
|
7
|
+
* This information will be shown to the end-users as a tooltip or a popover.
|
|
8
|
+
*
|
|
9
|
+
* @default false
|
|
10
|
+
*/
|
|
11
|
+
isDisabled?: boolean | {
|
|
12
|
+
reason: string;
|
|
13
|
+
};
|
|
3
14
|
}
|
|
4
15
|
/**
|
|
5
16
|
* Displays an icon-only button that allows users to perform an action.
|
|
@@ -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":"AAWA,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;AAqDD;;;;GAIG;AACH,QAAA,MAAM,WAAW,oKAAuD,CAAC;AAEzE,OAAO,EAAE,WAAW,IAAI,UAAU,EAAE,CAAC"}
|
|
@@ -7,13 +7,17 @@ import { useProductionWarning } from '../../utils/use-production-warning.js';
|
|
|
7
7
|
import { withStyleProps } from '../../with-style-props.js';
|
|
8
8
|
import { InternalSpinner } from '../internal/spinner/spinner.js';
|
|
9
9
|
import { SPINNER_SIZES } from './constants.js';
|
|
10
|
-
|
|
10
|
+
import { DisabledWithReason, useDisableInteractions } from './disabled-with-reason.js';
|
|
11
|
+
function IconButton({ icon, variant = 'secondary', tone = 'base', size = 'medium', isLoading, loadingLabel, isDisabled, fullWidth, UNSAFE_className, UNSAFE_style, slot, ...props }, ref) {
|
|
11
12
|
useProductionWarning(() => {
|
|
12
13
|
if (isLoading && !loadingLabel) {
|
|
13
14
|
console.warn('IconButton requires loadingLabel when isLoading is true for accessibility');
|
|
14
15
|
}
|
|
15
16
|
}, [isLoading, loadingLabel]);
|
|
16
|
-
|
|
17
|
+
const hasDisabledReason = typeof isDisabled === 'object' && isDisabled.reason !== '';
|
|
18
|
+
props = useDisableInteractions(props, isDisabled ?? false);
|
|
19
|
+
const button = (_jsx(RACButton, { ...props, ref: ref, 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, children: ({ isPending }) => (_jsxs(_Fragment, { children: [icon, isPending && _jsx(InternalSpinner, { size: SPINNER_SIZES[size], "aria-label": loadingLabel })] })) }));
|
|
20
|
+
return hasDisabledReason ? _jsx(DisabledWithReason, { reason: isDisabled.reason, children: button }) : button;
|
|
17
21
|
}
|
|
18
22
|
/**
|
|
19
23
|
* Displays an icon-only button that allows users to perform an action.
|
|
@@ -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;
|
|
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;AAevF,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,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;IAE3D,MAAM,MAAM,GAAG,CACb,KAAC,SAAS,OACJ,KAAK,EACT,GAAG,EAAE,GAAG,EACR,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,YAEnB,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 { 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 } 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 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\n const button = (\n <RACButton\n {...props}\n ref={ref}\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 >\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,7 +1,18 @@
|
|
|
1
1
|
import { type LinkProps as RACLinkProps } from 'react-aria-components';
|
|
2
2
|
import type { NavigationProps, WithRequired } from '../types.js';
|
|
3
3
|
import type { BaseButtonProps, SingleIconButtonProps } from './types.js';
|
|
4
|
-
export interface IconLinkButtonProps extends Omit<BaseButtonProps, 'id'>, SingleIconButtonProps, WithRequired<NavigationProps, 'href'>, Pick<RACLinkProps, '
|
|
4
|
+
export interface IconLinkButtonProps extends Omit<BaseButtonProps, 'id'>, SingleIconButtonProps, WithRequired<NavigationProps, 'href'>, Pick<RACLinkProps, 'onHoverStart' | 'onHoverEnd'> {
|
|
5
|
+
/**
|
|
6
|
+
* Whether the button is disabled.
|
|
7
|
+
*
|
|
8
|
+
* Optionally, you can provide an object with the `reason` property explaining why the button is disabled.
|
|
9
|
+
* This information will be shown to the end-users as a tooltip or a popover.
|
|
10
|
+
*
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
isDisabled?: boolean | {
|
|
14
|
+
reason: string;
|
|
15
|
+
};
|
|
5
16
|
}
|
|
6
17
|
/**
|
|
7
18
|
* Displays an icon-only button that allows users to navigate to another page or resource.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/icon-link-button.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,SAAS,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGxF,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"icon-link-button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/icon-link-button.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,SAAS,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGxF,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEjE,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;AAsDD;;;;GAIG;AACH,QAAA,MAAM,eAAe,wKAA+D,CAAC;AAErF,OAAO,EAAE,eAAe,IAAI,cAAc,EAAE,CAAC"}
|