@elliemae/ds-chip 3.70.0-next.71 → 3.70.0-next.72
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/cjs/DSChip.js +7 -13
- package/dist/cjs/DSChip.js.map +2 -2
- package/dist/cjs/config/useLabelExpansion.js +21 -38
- package/dist/cjs/config/useLabelExpansion.js.map +2 -2
- package/dist/esm/DSChip.js +7 -13
- package/dist/esm/DSChip.js.map +2 -2
- package/dist/esm/config/useLabelExpansion.js +21 -38
- package/dist/esm/config/useLabelExpansion.js.map +2 -2
- package/dist/types/config/useLabelExpansion.d.ts +6 -14
- package/package.json +7 -7
package/dist/cjs/DSChip.js
CHANGED
|
@@ -61,20 +61,14 @@ const DSChip = (props) => {
|
|
|
61
61
|
disabled,
|
|
62
62
|
className,
|
|
63
63
|
onClick,
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
onBlur: consumerBlur,
|
|
64
|
+
// Consumer-supplied pointer/focus handlers stay in `restGlobals` so they remain on the button:
|
|
65
|
+
// their target contract is preserved (e.g. onBlur must bubble from the control for tooltips), and
|
|
66
|
+
// React's suppression of events on a natively disabled button applies to them, as before. Internal
|
|
67
|
+
// label expansion is driven separately from the non-disabled wrapper (see useLabelExpansion).
|
|
68
|
+
// `onKeyDown` is not intercepted — Escape is handled at the document level, so it passes untouched.
|
|
70
69
|
...restGlobals
|
|
71
70
|
} = globalAttrs;
|
|
72
|
-
const { expanded, labelRef, expansionHandlers } = (0, import_useLabelExpansion.useLabelExpansion)(wrapText
|
|
73
|
-
onMouseEnter: consumerMouseEnter,
|
|
74
|
-
onMouseLeave: consumerMouseLeave,
|
|
75
|
-
onFocus: consumerFocus,
|
|
76
|
-
onBlur: consumerBlur
|
|
77
|
-
});
|
|
71
|
+
const { expanded, labelRef, expansionHandlers } = (0, import_useLabelExpansion.useLabelExpansion)(wrapText);
|
|
78
72
|
const handleOnClick = (0, import_react.useCallback)(
|
|
79
73
|
(e) => {
|
|
80
74
|
if (applyAriaDisabled) return;
|
|
@@ -93,6 +87,7 @@ const DSChip = (props) => {
|
|
|
93
87
|
className,
|
|
94
88
|
...xStyledAttrs,
|
|
95
89
|
...ownerPropsConfig,
|
|
90
|
+
...expansionHandlers,
|
|
96
91
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
97
92
|
import_styles.StyledChip,
|
|
98
93
|
{
|
|
@@ -106,7 +101,6 @@ const DSChip = (props) => {
|
|
|
106
101
|
buttonSize: size,
|
|
107
102
|
expanded,
|
|
108
103
|
"data-expanded": expanded || void 0,
|
|
109
|
-
...expansionHandlers,
|
|
110
104
|
...restGlobals,
|
|
111
105
|
...ownerPropsConfig,
|
|
112
106
|
children: [
|
package/dist/cjs/DSChip.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/DSChip.tsx", "../../../../../scripts/build/transpile/react-shim.js"],
|
|
4
|
-
"sourcesContent": ["import React, { useCallback } from 'react';\nimport { describe } from '@elliemae/ds-props-helpers';\nimport { TYPOGRAPHY_VARIANTS } from '@elliemae/ds-typography';\nimport { DSIconSizes } from '@elliemae/ds-icon';\nimport { useConfig } from './config/useConfig.js';\nimport { useLabelExpansion } from './config/useLabelExpansion.js';\nimport { StyledChip, StyledChipLabel, StyledWrapper, StyledRoundShape, StyledSpanWithEllipsis } from './styles.js';\nimport { CHIP_SHAPES } from './constants/index.js';\nimport type { DSChipT } from './react-desc-prop-types.js';\nimport { DSChipPropTypesSchema } from './react-desc-prop-types.js';\n\nconst DSChip: React.ComponentType<DSChipT.Props> = (props) => {\n const {\n size,\n shape,\n selected,\n applyAriaDisabled,\n innerRef,\n icon: Icon,\n label,\n globalAttrs,\n xStyledAttrs,\n ownerPropsConfig,\n wrapText,\n } = useConfig(props);\n\n const {\n disabled,\n className,\n onClick,\n //
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;
|
|
4
|
+
"sourcesContent": ["import React, { useCallback } from 'react';\nimport { describe } from '@elliemae/ds-props-helpers';\nimport { TYPOGRAPHY_VARIANTS } from '@elliemae/ds-typography';\nimport { DSIconSizes } from '@elliemae/ds-icon';\nimport { useConfig } from './config/useConfig.js';\nimport { useLabelExpansion } from './config/useLabelExpansion.js';\nimport { StyledChip, StyledChipLabel, StyledWrapper, StyledRoundShape, StyledSpanWithEllipsis } from './styles.js';\nimport { CHIP_SHAPES } from './constants/index.js';\nimport type { DSChipT } from './react-desc-prop-types.js';\nimport { DSChipPropTypesSchema } from './react-desc-prop-types.js';\n\nconst DSChip: React.ComponentType<DSChipT.Props> = (props) => {\n const {\n size,\n shape,\n selected,\n applyAriaDisabled,\n innerRef,\n icon: Icon,\n label,\n globalAttrs,\n xStyledAttrs,\n ownerPropsConfig,\n wrapText,\n } = useConfig(props);\n\n const {\n disabled,\n className,\n onClick,\n // Consumer-supplied pointer/focus handlers stay in `restGlobals` so they remain on the button:\n // their target contract is preserved (e.g. onBlur must bubble from the control for tooltips), and\n // React's suppression of events on a natively disabled button applies to them, as before. Internal\n // label expansion is driven separately from the non-disabled wrapper (see useLabelExpansion).\n // `onKeyDown` is not intercepted \u2014 Escape is handled at the document level, so it passes untouched.\n ...restGlobals\n } = globalAttrs;\n\n const { expanded, labelRef, expansionHandlers } = useLabelExpansion(wrapText);\n\n const handleOnClick = useCallback(\n (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {\n if (applyAriaDisabled) return;\n if (onClick) {\n onClick(e);\n }\n },\n [applyAriaDisabled, onClick],\n );\n\n return (\n <StyledWrapper\n wrapText={wrapText}\n buttonShape={shape}\n buttonSize={size}\n className={className}\n {...xStyledAttrs}\n {...ownerPropsConfig}\n {...expansionHandlers}\n >\n <StyledChip\n buttonShape={shape}\n aria-disabled={disabled || applyAriaDisabled}\n disabled={disabled}\n innerRef={innerRef}\n selected={selected}\n role=\"button\"\n onClick={handleOnClick}\n buttonSize={size}\n expanded={expanded}\n data-expanded={expanded || undefined}\n {...restGlobals}\n {...ownerPropsConfig}\n >\n {shape === CHIP_SHAPES.ROUND ? (\n <StyledRoundShape disabled={disabled} size={size} {...ownerPropsConfig}>\n <Icon size={DSIconSizes.M} />\n </StyledRoundShape>\n ) : (\n <Icon size={DSIconSizes.M} />\n )}\n <StyledChipLabel size={size} {...ownerPropsConfig}>\n <StyledSpanWithEllipsis\n component=\"span\"\n variant={TYPOGRAPHY_VARIANTS.B4}\n wrapText={wrapText}\n innerRef={labelRef}\n {...ownerPropsConfig}\n >\n {label}\n </StyledSpanWithEllipsis>\n </StyledChipLabel>\n </StyledChip>\n </StyledWrapper>\n );\n};\n\nDSChip.displayName = 'DSChip';\nconst DSChipWithSchema = describe(DSChip);\nDSChipWithSchema.propTypes = DSChipPropTypesSchema;\n\nexport { DSChip, DSChipWithSchema };\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;AD4DjB;AA5DN,mBAAmC;AACnC,8BAAyB;AACzB,2BAAoC;AACpC,qBAA4B;AAC5B,uBAA0B;AAC1B,+BAAkC;AAClC,oBAAqG;AACrG,uBAA4B;AAE5B,mCAAsC;AAEtC,MAAM,SAA6C,CAAC,UAAU;AAC5D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,QAAI,4BAAU,KAAK;AAEnB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,EAAE,UAAU,UAAU,kBAAkB,QAAI,4CAAkB,QAAQ;AAE5E,QAAM,oBAAgB;AAAA,IACpB,CAAC,MAAuD;AACtD,UAAI,kBAAmB;AACvB,UAAI,SAAS;AACX,gBAAQ,CAAC;AAAA,MACX;AAAA,IACF;AAAA,IACA,CAAC,mBAAmB,OAAO;AAAA,EAC7B;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,aAAa;AAAA,MACb,YAAY;AAAA,MACZ;AAAA,MACC,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MAEJ;AAAA,QAAC;AAAA;AAAA,UACC,aAAa;AAAA,UACb,iBAAe,YAAY;AAAA,UAC3B;AAAA,UACA;AAAA,UACA;AAAA,UACA,MAAK;AAAA,UACL,SAAS;AAAA,UACT,YAAY;AAAA,UACZ;AAAA,UACA,iBAAe,YAAY;AAAA,UAC1B,GAAG;AAAA,UACH,GAAG;AAAA,UAEH;AAAA,sBAAU,6BAAY,QACrB,4CAAC,kCAAiB,UAAoB,MAAa,GAAG,kBACpD,sDAAC,QAAK,MAAM,2BAAY,GAAG,GAC7B,IAEA,4CAAC,QAAK,MAAM,2BAAY,GAAG;AAAA,YAE7B,4CAAC,iCAAgB,MAAa,GAAG,kBAC/B;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,SAAS,yCAAoB;AAAA,gBAC7B;AAAA,gBACA,UAAU;AAAA,gBACT,GAAG;AAAA,gBAEH;AAAA;AAAA,YACH,GACF;AAAA;AAAA;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;AAEA,OAAO,cAAc;AACrB,MAAM,uBAAmB,kCAAS,MAAM;AACxC,iBAAiB,YAAY;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -34,7 +34,7 @@ module.exports = __toCommonJS(useLabelExpansion_exports);
|
|
|
34
34
|
var React = __toESM(require("react"));
|
|
35
35
|
var import_react = require("react");
|
|
36
36
|
var import_useEscapeDismiss = require("./useEscapeDismiss.js");
|
|
37
|
-
const useLabelExpansion = (wrapText
|
|
37
|
+
const useLabelExpansion = (wrapText) => {
|
|
38
38
|
const [isHovered, setIsHovered] = (0, import_react.useState)(false);
|
|
39
39
|
const [isFocused, setIsFocused] = (0, import_react.useState)(false);
|
|
40
40
|
const [isDismissed, setIsDismissed] = (0, import_react.useState)(false);
|
|
@@ -55,43 +55,26 @@ const useLabelExpansion = (wrapText, consumer) => {
|
|
|
55
55
|
setIsDismissed(false);
|
|
56
56
|
}
|
|
57
57
|
}, []);
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
);
|
|
68
|
-
const
|
|
69
|
-
(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
(e) => {
|
|
79
|
-
measureOverflowOnEntry();
|
|
80
|
-
focusedRef.current = true;
|
|
81
|
-
setIsFocused(true);
|
|
82
|
-
onFocus?.(e);
|
|
83
|
-
},
|
|
84
|
-
[onFocus, measureOverflowOnEntry]
|
|
85
|
-
);
|
|
86
|
-
const handleBlur = (0, import_react.useCallback)(
|
|
87
|
-
(e) => {
|
|
88
|
-
focusedRef.current = false;
|
|
89
|
-
setIsFocused(false);
|
|
90
|
-
rearmIfLeft();
|
|
91
|
-
onBlur?.(e);
|
|
92
|
-
},
|
|
93
|
-
[onBlur, rearmIfLeft]
|
|
94
|
-
);
|
|
58
|
+
const handleMouseEnter = (0, import_react.useCallback)(() => {
|
|
59
|
+
measureOverflowOnEntry();
|
|
60
|
+
hoveredRef.current = true;
|
|
61
|
+
setIsHovered(true);
|
|
62
|
+
}, [measureOverflowOnEntry]);
|
|
63
|
+
const handleMouseLeave = (0, import_react.useCallback)(() => {
|
|
64
|
+
hoveredRef.current = false;
|
|
65
|
+
setIsHovered(false);
|
|
66
|
+
rearmIfLeft();
|
|
67
|
+
}, [rearmIfLeft]);
|
|
68
|
+
const handleFocus = (0, import_react.useCallback)(() => {
|
|
69
|
+
measureOverflowOnEntry();
|
|
70
|
+
focusedRef.current = true;
|
|
71
|
+
setIsFocused(true);
|
|
72
|
+
}, [measureOverflowOnEntry]);
|
|
73
|
+
const handleBlur = (0, import_react.useCallback)(() => {
|
|
74
|
+
focusedRef.current = false;
|
|
75
|
+
setIsFocused(false);
|
|
76
|
+
rearmIfLeft();
|
|
77
|
+
}, [rearmIfLeft]);
|
|
95
78
|
const handleEscapeDismiss = (0, import_react.useCallback)(() => {
|
|
96
79
|
dismissedRef.current = true;
|
|
97
80
|
setIsDismissed(true);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/config/useLabelExpansion.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
|
|
4
|
-
"sourcesContent": ["import
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;
|
|
4
|
+
"sourcesContent": ["import { useCallback, useRef, useState } from 'react';\nimport { useEscapeDismiss } from './useEscapeDismiss.js';\n\n// PUI-17950 \u2014 the expanded label overlays adjacent content, so WCAG 1.4.13 requires it be dismissible\n// without moving pointer or focus. That rules out CSS :hover/:focus, which a keypress cannot switch off.\n// `isOverflowing` matters beyond the visuals: without it a label that already fits would still claim an\n// expansion and swallow an Escape meant for an ancestor.\n//\n// PUI-18894 \u2014 these handlers drive expansion internally and are attached to the chip's root wrapper (a\n// `<div>`), not the button. React does not dispatch synthetic mouse/focus events to a natively disabled\n// form control, so a disabled chip would never expand if they lived on the button; the non-disabled\n// wrapper still receives the (bubbling) native events. Consumer-supplied handlers are intentionally NOT\n// composed here \u2014 they stay on the button so their target contract (e.g. onBlur bubbling for tooltips)\n// is preserved.\nexport const useLabelExpansion = (wrapText: boolean) => {\n const [isHovered, setIsHovered] = useState(false);\n const [isFocused, setIsFocused] = useState(false);\n const [isDismissed, setIsDismissed] = useState(false);\n const [isOverflowing, setIsOverflowing] = useState(false);\n\n // Mirrored so the leave handlers read both signals in the same tick, without a useEffect.\n const hoveredRef = useRef(false);\n const focusedRef = useRef(false);\n const dismissedRef = useRef(false);\n const labelRef = useRef<HTMLDivElement | null>(null);\n\n const expanded = !wrapText && isOverflowing && (isHovered || isFocused) && !isDismissed;\n\n // Only on a fresh entry: an already-expanded label is no longer clipped and would measure as fitting.\n const measureOverflowOnEntry = useCallback(() => {\n if (wrapText || hoveredRef.current || focusedRef.current) return;\n const node = labelRef.current;\n setIsOverflowing(!!node && node.scrollWidth > node.clientWidth);\n }, [wrapText]);\n\n const rearmIfLeft = useCallback(() => {\n if (!hoveredRef.current && !focusedRef.current && dismissedRef.current) {\n dismissedRef.current = false;\n setIsDismissed(false);\n }\n }, []);\n\n const handleMouseEnter = useCallback(() => {\n measureOverflowOnEntry();\n hoveredRef.current = true;\n setIsHovered(true);\n }, [measureOverflowOnEntry]);\n\n const handleMouseLeave = useCallback(() => {\n hoveredRef.current = false;\n setIsHovered(false);\n rearmIfLeft();\n }, [rearmIfLeft]);\n\n // Focus/blur bubble from the button up to the wrapper (focusin/focusout), so keyboard-focus\n // expansion keeps working even though the handlers no longer sit on the control itself.\n const handleFocus = useCallback(() => {\n measureOverflowOnEntry();\n focusedRef.current = true;\n setIsFocused(true);\n }, [measureOverflowOnEntry]);\n\n const handleBlur = useCallback(() => {\n focusedRef.current = false;\n setIsFocused(false);\n rearmIfLeft();\n }, [rearmIfLeft]);\n\n // Stable, or useEscapeDismiss resubscribes every render.\n const handleEscapeDismiss = useCallback(() => {\n dismissedRef.current = true;\n setIsDismissed(true);\n }, []);\n\n useEscapeDismiss(expanded, handleEscapeDismiss);\n\n return {\n expanded,\n labelRef,\n expansionHandlers: {\n onMouseEnter: handleMouseEnter,\n onMouseLeave: handleMouseLeave,\n onFocus: handleFocus,\n onBlur: handleBlur,\n },\n };\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,mBAA8C;AAC9C,8BAAiC;AAa1B,MAAM,oBAAoB,CAAC,aAAsB;AACtD,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,KAAK;AAChD,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,KAAK;AAChD,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,KAAK;AACpD,QAAM,CAAC,eAAe,gBAAgB,QAAI,uBAAS,KAAK;AAGxD,QAAM,iBAAa,qBAAO,KAAK;AAC/B,QAAM,iBAAa,qBAAO,KAAK;AAC/B,QAAM,mBAAe,qBAAO,KAAK;AACjC,QAAM,eAAW,qBAA8B,IAAI;AAEnD,QAAM,WAAW,CAAC,YAAY,kBAAkB,aAAa,cAAc,CAAC;AAG5E,QAAM,6BAAyB,0BAAY,MAAM;AAC/C,QAAI,YAAY,WAAW,WAAW,WAAW,QAAS;AAC1D,UAAM,OAAO,SAAS;AACtB,qBAAiB,CAAC,CAAC,QAAQ,KAAK,cAAc,KAAK,WAAW;AAAA,EAChE,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,kBAAc,0BAAY,MAAM;AACpC,QAAI,CAAC,WAAW,WAAW,CAAC,WAAW,WAAW,aAAa,SAAS;AACtE,mBAAa,UAAU;AACvB,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,uBAAmB,0BAAY,MAAM;AACzC,2BAAuB;AACvB,eAAW,UAAU;AACrB,iBAAa,IAAI;AAAA,EACnB,GAAG,CAAC,sBAAsB,CAAC;AAE3B,QAAM,uBAAmB,0BAAY,MAAM;AACzC,eAAW,UAAU;AACrB,iBAAa,KAAK;AAClB,gBAAY;AAAA,EACd,GAAG,CAAC,WAAW,CAAC;AAIhB,QAAM,kBAAc,0BAAY,MAAM;AACpC,2BAAuB;AACvB,eAAW,UAAU;AACrB,iBAAa,IAAI;AAAA,EACnB,GAAG,CAAC,sBAAsB,CAAC;AAE3B,QAAM,iBAAa,0BAAY,MAAM;AACnC,eAAW,UAAU;AACrB,iBAAa,KAAK;AAClB,gBAAY;AAAA,EACd,GAAG,CAAC,WAAW,CAAC;AAGhB,QAAM,0BAAsB,0BAAY,MAAM;AAC5C,iBAAa,UAAU;AACvB,mBAAe,IAAI;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,gDAAiB,UAAU,mBAAmB;AAE9C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,mBAAmB;AAAA,MACjB,cAAc;AAAA,MACd,cAAc;AAAA,MACd,SAAS;AAAA,MACT,QAAQ;AAAA,IACV;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/esm/DSChip.js
CHANGED
|
@@ -27,20 +27,14 @@ const DSChip = (props) => {
|
|
|
27
27
|
disabled,
|
|
28
28
|
className,
|
|
29
29
|
onClick,
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
onBlur: consumerBlur,
|
|
30
|
+
// Consumer-supplied pointer/focus handlers stay in `restGlobals` so they remain on the button:
|
|
31
|
+
// their target contract is preserved (e.g. onBlur must bubble from the control for tooltips), and
|
|
32
|
+
// React's suppression of events on a natively disabled button applies to them, as before. Internal
|
|
33
|
+
// label expansion is driven separately from the non-disabled wrapper (see useLabelExpansion).
|
|
34
|
+
// `onKeyDown` is not intercepted — Escape is handled at the document level, so it passes untouched.
|
|
36
35
|
...restGlobals
|
|
37
36
|
} = globalAttrs;
|
|
38
|
-
const { expanded, labelRef, expansionHandlers } = useLabelExpansion(wrapText
|
|
39
|
-
onMouseEnter: consumerMouseEnter,
|
|
40
|
-
onMouseLeave: consumerMouseLeave,
|
|
41
|
-
onFocus: consumerFocus,
|
|
42
|
-
onBlur: consumerBlur
|
|
43
|
-
});
|
|
37
|
+
const { expanded, labelRef, expansionHandlers } = useLabelExpansion(wrapText);
|
|
44
38
|
const handleOnClick = useCallback(
|
|
45
39
|
(e) => {
|
|
46
40
|
if (applyAriaDisabled) return;
|
|
@@ -59,6 +53,7 @@ const DSChip = (props) => {
|
|
|
59
53
|
className,
|
|
60
54
|
...xStyledAttrs,
|
|
61
55
|
...ownerPropsConfig,
|
|
56
|
+
...expansionHandlers,
|
|
62
57
|
children: /* @__PURE__ */ jsxs(
|
|
63
58
|
StyledChip,
|
|
64
59
|
{
|
|
@@ -72,7 +67,6 @@ const DSChip = (props) => {
|
|
|
72
67
|
buttonSize: size,
|
|
73
68
|
expanded,
|
|
74
69
|
"data-expanded": expanded || void 0,
|
|
75
|
-
...expansionHandlers,
|
|
76
70
|
...restGlobals,
|
|
77
71
|
...ownerPropsConfig,
|
|
78
72
|
children: [
|
package/dist/esm/DSChip.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/DSChip.tsx"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import React, { useCallback } from 'react';\nimport { describe } from '@elliemae/ds-props-helpers';\nimport { TYPOGRAPHY_VARIANTS } from '@elliemae/ds-typography';\nimport { DSIconSizes } from '@elliemae/ds-icon';\nimport { useConfig } from './config/useConfig.js';\nimport { useLabelExpansion } from './config/useLabelExpansion.js';\nimport { StyledChip, StyledChipLabel, StyledWrapper, StyledRoundShape, StyledSpanWithEllipsis } from './styles.js';\nimport { CHIP_SHAPES } from './constants/index.js';\nimport type { DSChipT } from './react-desc-prop-types.js';\nimport { DSChipPropTypesSchema } from './react-desc-prop-types.js';\n\nconst DSChip: React.ComponentType<DSChipT.Props> = (props) => {\n const {\n size,\n shape,\n selected,\n applyAriaDisabled,\n innerRef,\n icon: Icon,\n label,\n globalAttrs,\n xStyledAttrs,\n ownerPropsConfig,\n wrapText,\n } = useConfig(props);\n\n const {\n disabled,\n className,\n onClick,\n //
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import React, { useCallback } from 'react';\nimport { describe } from '@elliemae/ds-props-helpers';\nimport { TYPOGRAPHY_VARIANTS } from '@elliemae/ds-typography';\nimport { DSIconSizes } from '@elliemae/ds-icon';\nimport { useConfig } from './config/useConfig.js';\nimport { useLabelExpansion } from './config/useLabelExpansion.js';\nimport { StyledChip, StyledChipLabel, StyledWrapper, StyledRoundShape, StyledSpanWithEllipsis } from './styles.js';\nimport { CHIP_SHAPES } from './constants/index.js';\nimport type { DSChipT } from './react-desc-prop-types.js';\nimport { DSChipPropTypesSchema } from './react-desc-prop-types.js';\n\nconst DSChip: React.ComponentType<DSChipT.Props> = (props) => {\n const {\n size,\n shape,\n selected,\n applyAriaDisabled,\n innerRef,\n icon: Icon,\n label,\n globalAttrs,\n xStyledAttrs,\n ownerPropsConfig,\n wrapText,\n } = useConfig(props);\n\n const {\n disabled,\n className,\n onClick,\n // Consumer-supplied pointer/focus handlers stay in `restGlobals` so they remain on the button:\n // their target contract is preserved (e.g. onBlur must bubble from the control for tooltips), and\n // React's suppression of events on a natively disabled button applies to them, as before. Internal\n // label expansion is driven separately from the non-disabled wrapper (see useLabelExpansion).\n // `onKeyDown` is not intercepted \u2014 Escape is handled at the document level, so it passes untouched.\n ...restGlobals\n } = globalAttrs;\n\n const { expanded, labelRef, expansionHandlers } = useLabelExpansion(wrapText);\n\n const handleOnClick = useCallback(\n (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {\n if (applyAriaDisabled) return;\n if (onClick) {\n onClick(e);\n }\n },\n [applyAriaDisabled, onClick],\n );\n\n return (\n <StyledWrapper\n wrapText={wrapText}\n buttonShape={shape}\n buttonSize={size}\n className={className}\n {...xStyledAttrs}\n {...ownerPropsConfig}\n {...expansionHandlers}\n >\n <StyledChip\n buttonShape={shape}\n aria-disabled={disabled || applyAriaDisabled}\n disabled={disabled}\n innerRef={innerRef}\n selected={selected}\n role=\"button\"\n onClick={handleOnClick}\n buttonSize={size}\n expanded={expanded}\n data-expanded={expanded || undefined}\n {...restGlobals}\n {...ownerPropsConfig}\n >\n {shape === CHIP_SHAPES.ROUND ? (\n <StyledRoundShape disabled={disabled} size={size} {...ownerPropsConfig}>\n <Icon size={DSIconSizes.M} />\n </StyledRoundShape>\n ) : (\n <Icon size={DSIconSizes.M} />\n )}\n <StyledChipLabel size={size} {...ownerPropsConfig}>\n <StyledSpanWithEllipsis\n component=\"span\"\n variant={TYPOGRAPHY_VARIANTS.B4}\n wrapText={wrapText}\n innerRef={labelRef}\n {...ownerPropsConfig}\n >\n {label}\n </StyledSpanWithEllipsis>\n </StyledChipLabel>\n </StyledChip>\n </StyledWrapper>\n );\n};\n\nDSChip.displayName = 'DSChip';\nconst DSChipWithSchema = describe(DSChip);\nDSChipWithSchema.propTypes = DSChipPropTypesSchema;\n\nexport { DSChip, DSChipWithSchema };\n"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;AC4DjB,SAgBM,KAhBN;AA5DN,SAAgB,mBAAmB;AACnC,SAAS,gBAAgB;AACzB,SAAS,2BAA2B;AACpC,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAC1B,SAAS,yBAAyB;AAClC,SAAS,YAAY,iBAAiB,eAAe,kBAAkB,8BAA8B;AACrG,SAAS,mBAAmB;AAE5B,SAAS,6BAA6B;AAEtC,MAAM,SAA6C,CAAC,UAAU;AAC5D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,UAAU,KAAK;AAEnB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,EAAE,UAAU,UAAU,kBAAkB,IAAI,kBAAkB,QAAQ;AAE5E,QAAM,gBAAgB;AAAA,IACpB,CAAC,MAAuD;AACtD,UAAI,kBAAmB;AACvB,UAAI,SAAS;AACX,gBAAQ,CAAC;AAAA,MACX;AAAA,IACF;AAAA,IACA,CAAC,mBAAmB,OAAO;AAAA,EAC7B;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,aAAa;AAAA,MACb,YAAY;AAAA,MACZ;AAAA,MACC,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MAEJ;AAAA,QAAC;AAAA;AAAA,UACC,aAAa;AAAA,UACb,iBAAe,YAAY;AAAA,UAC3B;AAAA,UACA;AAAA,UACA;AAAA,UACA,MAAK;AAAA,UACL,SAAS;AAAA,UACT,YAAY;AAAA,UACZ;AAAA,UACA,iBAAe,YAAY;AAAA,UAC1B,GAAG;AAAA,UACH,GAAG;AAAA,UAEH;AAAA,sBAAU,YAAY,QACrB,oBAAC,oBAAiB,UAAoB,MAAa,GAAG,kBACpD,8BAAC,QAAK,MAAM,YAAY,GAAG,GAC7B,IAEA,oBAAC,QAAK,MAAM,YAAY,GAAG;AAAA,YAE7B,oBAAC,mBAAgB,MAAa,GAAG,kBAC/B;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,SAAS,oBAAoB;AAAA,gBAC7B;AAAA,gBACA,UAAU;AAAA,gBACT,GAAG;AAAA,gBAEH;AAAA;AAAA,YACH,GACF;AAAA;AAAA;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;AAEA,OAAO,cAAc;AACrB,MAAM,mBAAmB,SAAS,MAAM;AACxC,iBAAiB,YAAY;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { useCallback, useRef, useState } from "react";
|
|
3
3
|
import { useEscapeDismiss } from "./useEscapeDismiss.js";
|
|
4
|
-
const useLabelExpansion = (wrapText
|
|
4
|
+
const useLabelExpansion = (wrapText) => {
|
|
5
5
|
const [isHovered, setIsHovered] = useState(false);
|
|
6
6
|
const [isFocused, setIsFocused] = useState(false);
|
|
7
7
|
const [isDismissed, setIsDismissed] = useState(false);
|
|
@@ -22,43 +22,26 @@ const useLabelExpansion = (wrapText, consumer) => {
|
|
|
22
22
|
setIsDismissed(false);
|
|
23
23
|
}
|
|
24
24
|
}, []);
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
);
|
|
35
|
-
const
|
|
36
|
-
(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
(e) => {
|
|
46
|
-
measureOverflowOnEntry();
|
|
47
|
-
focusedRef.current = true;
|
|
48
|
-
setIsFocused(true);
|
|
49
|
-
onFocus?.(e);
|
|
50
|
-
},
|
|
51
|
-
[onFocus, measureOverflowOnEntry]
|
|
52
|
-
);
|
|
53
|
-
const handleBlur = useCallback(
|
|
54
|
-
(e) => {
|
|
55
|
-
focusedRef.current = false;
|
|
56
|
-
setIsFocused(false);
|
|
57
|
-
rearmIfLeft();
|
|
58
|
-
onBlur?.(e);
|
|
59
|
-
},
|
|
60
|
-
[onBlur, rearmIfLeft]
|
|
61
|
-
);
|
|
25
|
+
const handleMouseEnter = useCallback(() => {
|
|
26
|
+
measureOverflowOnEntry();
|
|
27
|
+
hoveredRef.current = true;
|
|
28
|
+
setIsHovered(true);
|
|
29
|
+
}, [measureOverflowOnEntry]);
|
|
30
|
+
const handleMouseLeave = useCallback(() => {
|
|
31
|
+
hoveredRef.current = false;
|
|
32
|
+
setIsHovered(false);
|
|
33
|
+
rearmIfLeft();
|
|
34
|
+
}, [rearmIfLeft]);
|
|
35
|
+
const handleFocus = useCallback(() => {
|
|
36
|
+
measureOverflowOnEntry();
|
|
37
|
+
focusedRef.current = true;
|
|
38
|
+
setIsFocused(true);
|
|
39
|
+
}, [measureOverflowOnEntry]);
|
|
40
|
+
const handleBlur = useCallback(() => {
|
|
41
|
+
focusedRef.current = false;
|
|
42
|
+
setIsFocused(false);
|
|
43
|
+
rearmIfLeft();
|
|
44
|
+
}, [rearmIfLeft]);
|
|
62
45
|
const handleEscapeDismiss = useCallback(() => {
|
|
63
46
|
dismissedRef.current = true;
|
|
64
47
|
setIsDismissed(true);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/config/useLabelExpansion.ts"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { useCallback, useRef, useState } from 'react';\nimport { useEscapeDismiss } from './useEscapeDismiss.js';\n\n// PUI-17950 \u2014 the expanded label overlays adjacent content, so WCAG 1.4.13 requires it be dismissible\n// without moving pointer or focus. That rules out CSS :hover/:focus, which a keypress cannot switch off.\n// `isOverflowing` matters beyond the visuals: without it a label that already fits would still claim an\n// expansion and swallow an Escape meant for an ancestor.\n//\n// PUI-18894 \u2014 these handlers drive expansion internally and are attached to the chip's root wrapper (a\n// `<div>`), not the button. React does not dispatch synthetic mouse/focus events to a natively disabled\n// form control, so a disabled chip would never expand if they lived on the button; the non-disabled\n// wrapper still receives the (bubbling) native events. Consumer-supplied handlers are intentionally NOT\n// composed here \u2014 they stay on the button so their target contract (e.g. onBlur bubbling for tooltips)\n// is preserved.\nexport const useLabelExpansion = (wrapText: boolean) => {\n const [isHovered, setIsHovered] = useState(false);\n const [isFocused, setIsFocused] = useState(false);\n const [isDismissed, setIsDismissed] = useState(false);\n const [isOverflowing, setIsOverflowing] = useState(false);\n\n // Mirrored so the leave handlers read both signals in the same tick, without a useEffect.\n const hoveredRef = useRef(false);\n const focusedRef = useRef(false);\n const dismissedRef = useRef(false);\n const labelRef = useRef<HTMLDivElement | null>(null);\n\n const expanded = !wrapText && isOverflowing && (isHovered || isFocused) && !isDismissed;\n\n // Only on a fresh entry: an already-expanded label is no longer clipped and would measure as fitting.\n const measureOverflowOnEntry = useCallback(() => {\n if (wrapText || hoveredRef.current || focusedRef.current) return;\n const node = labelRef.current;\n setIsOverflowing(!!node && node.scrollWidth > node.clientWidth);\n }, [wrapText]);\n\n const rearmIfLeft = useCallback(() => {\n if (!hoveredRef.current && !focusedRef.current && dismissedRef.current) {\n dismissedRef.current = false;\n setIsDismissed(false);\n }\n }, []);\n\n const handleMouseEnter = useCallback(() => {\n measureOverflowOnEntry();\n hoveredRef.current = true;\n setIsHovered(true);\n }, [measureOverflowOnEntry]);\n\n const handleMouseLeave = useCallback(() => {\n hoveredRef.current = false;\n setIsHovered(false);\n rearmIfLeft();\n }, [rearmIfLeft]);\n\n // Focus/blur bubble from the button up to the wrapper (focusin/focusout), so keyboard-focus\n // expansion keeps working even though the handlers no longer sit on the control itself.\n const handleFocus = useCallback(() => {\n measureOverflowOnEntry();\n focusedRef.current = true;\n setIsFocused(true);\n }, [measureOverflowOnEntry]);\n\n const handleBlur = useCallback(() => {\n focusedRef.current = false;\n setIsFocused(false);\n rearmIfLeft();\n }, [rearmIfLeft]);\n\n // Stable, or useEscapeDismiss resubscribes every render.\n const handleEscapeDismiss = useCallback(() => {\n dismissedRef.current = true;\n setIsDismissed(true);\n }, []);\n\n useEscapeDismiss(expanded, handleEscapeDismiss);\n\n return {\n expanded,\n labelRef,\n expansionHandlers: {\n onMouseEnter: handleMouseEnter,\n onMouseLeave: handleMouseLeave,\n onFocus: handleFocus,\n onBlur: handleBlur,\n },\n };\n};\n"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,aAAa,QAAQ,gBAAgB;AAC9C,SAAS,wBAAwB;AAa1B,MAAM,oBAAoB,CAAC,aAAsB;AACtD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AACpD,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,KAAK;AAGxD,QAAM,aAAa,OAAO,KAAK;AAC/B,QAAM,aAAa,OAAO,KAAK;AAC/B,QAAM,eAAe,OAAO,KAAK;AACjC,QAAM,WAAW,OAA8B,IAAI;AAEnD,QAAM,WAAW,CAAC,YAAY,kBAAkB,aAAa,cAAc,CAAC;AAG5E,QAAM,yBAAyB,YAAY,MAAM;AAC/C,QAAI,YAAY,WAAW,WAAW,WAAW,QAAS;AAC1D,UAAM,OAAO,SAAS;AACtB,qBAAiB,CAAC,CAAC,QAAQ,KAAK,cAAc,KAAK,WAAW;AAAA,EAChE,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,cAAc,YAAY,MAAM;AACpC,QAAI,CAAC,WAAW,WAAW,CAAC,WAAW,WAAW,aAAa,SAAS;AACtE,mBAAa,UAAU;AACvB,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAmB,YAAY,MAAM;AACzC,2BAAuB;AACvB,eAAW,UAAU;AACrB,iBAAa,IAAI;AAAA,EACnB,GAAG,CAAC,sBAAsB,CAAC;AAE3B,QAAM,mBAAmB,YAAY,MAAM;AACzC,eAAW,UAAU;AACrB,iBAAa,KAAK;AAClB,gBAAY;AAAA,EACd,GAAG,CAAC,WAAW,CAAC;AAIhB,QAAM,cAAc,YAAY,MAAM;AACpC,2BAAuB;AACvB,eAAW,UAAU;AACrB,iBAAa,IAAI;AAAA,EACnB,GAAG,CAAC,sBAAsB,CAAC;AAE3B,QAAM,aAAa,YAAY,MAAM;AACnC,eAAW,UAAU;AACrB,iBAAa,KAAK;AAClB,gBAAY;AAAA,EACd,GAAG,CAAC,WAAW,CAAC;AAGhB,QAAM,sBAAsB,YAAY,MAAM;AAC5C,iBAAa,UAAU;AACvB,mBAAe,IAAI;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,mBAAiB,UAAU,mBAAmB;AAE9C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,mBAAmB;AAAA,MACjB,cAAc;AAAA,MACd,cAAc;AAAA,MACd,SAAS;AAAA,MACT,QAAQ;AAAA,IACV;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,18 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
interface ConsumerHandlersT {
|
|
3
|
-
onMouseEnter?: React.MouseEventHandler<HTMLButtonElement>;
|
|
4
|
-
onMouseLeave?: React.MouseEventHandler<HTMLButtonElement>;
|
|
5
|
-
onFocus?: React.FocusEventHandler<HTMLButtonElement>;
|
|
6
|
-
onBlur?: React.FocusEventHandler<HTMLButtonElement>;
|
|
7
|
-
}
|
|
8
|
-
export declare const useLabelExpansion: (wrapText: boolean, consumer: ConsumerHandlersT) => {
|
|
1
|
+
export declare const useLabelExpansion: (wrapText: boolean) => {
|
|
9
2
|
expanded: boolean;
|
|
10
|
-
labelRef:
|
|
3
|
+
labelRef: import("react").MutableRefObject<HTMLDivElement | null>;
|
|
11
4
|
expansionHandlers: {
|
|
12
|
-
onMouseEnter: (
|
|
13
|
-
onMouseLeave: (
|
|
14
|
-
onFocus: (
|
|
15
|
-
onBlur: (
|
|
5
|
+
onMouseEnter: () => void;
|
|
6
|
+
onMouseLeave: () => void;
|
|
7
|
+
onFocus: () => void;
|
|
8
|
+
onBlur: () => void;
|
|
16
9
|
};
|
|
17
10
|
};
|
|
18
|
-
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elliemae/ds-chip",
|
|
3
|
-
"version": "3.70.0-next.
|
|
3
|
+
"version": "3.70.0-next.72",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "ICE MT - Dimsum - Chip",
|
|
6
6
|
"files": [
|
|
@@ -36,16 +36,16 @@
|
|
|
36
36
|
"indent": 4
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@elliemae/ds-props-helpers": "3.70.0-next.
|
|
40
|
-
"@elliemae/ds-
|
|
41
|
-
"@elliemae/ds-
|
|
39
|
+
"@elliemae/ds-props-helpers": "3.70.0-next.72",
|
|
40
|
+
"@elliemae/ds-system": "3.70.0-next.72",
|
|
41
|
+
"@elliemae/ds-typescript-helpers": "3.70.0-next.72"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"jest": "^30.0.0",
|
|
45
45
|
"styled-components": "~5.3.11",
|
|
46
|
-
"@elliemae/ds-
|
|
47
|
-
"@elliemae/ds-test-utils": "3.70.0-next.
|
|
48
|
-
"@elliemae/ds-
|
|
46
|
+
"@elliemae/ds-icons": "3.70.0-next.72",
|
|
47
|
+
"@elliemae/ds-test-utils": "3.70.0-next.72",
|
|
48
|
+
"@elliemae/ds-monorepo-devops": "3.70.0-next.72"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"lodash-es": "^4.18.1",
|