@xylabs/react-button 4.1.2 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"ButtonExBase.d.ts","sourceRoot":"","sources":["../../../src/components/ButtonExBase.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAqB,MAAM,OAAO,CAAA;AAEzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAExD,QAAA,MAAM,YAAY,yFAuBhB,CAAA;AAIF,OAAO,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"ButtonExBase.d.ts","sourceRoot":"","sources":["../../../src/components/ButtonExBase.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAqB,MAAM,OAAO,CAAA;AAEzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAExD,QAAA,MAAM,YAAY,yFAsDhB,CAAA;AAIF,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -2,6 +2,11 @@ import type { ButtonProps } from '@mui/material';
2
2
  import type { BoxlikeComponentProps, BusyProps } from '@xylabs/react-shared';
3
3
  import type { NavigateOptions, To } from 'react-router-dom';
4
4
  interface ButtonExProps extends Omit<ButtonProps, 'ref'>, BoxlikeComponentProps, BusyProps {
5
+ disableMixpanel?: boolean;
6
+ disableUserEvents?: boolean;
7
+ eventName?: string;
8
+ funnel?: string;
9
+ placement?: string;
5
10
  target?: string;
6
11
  to?: To;
7
12
  toOptions?: NavigateOptions;
@@ -1 +1 @@
1
- {"version":3,"file":"ButtonExProps.d.ts","sourceRoot":"","sources":["../../../src/components/ButtonExProps.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAA;AAE3D,UAAU,aAAc,SAAQ,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,qBAAqB,EAAE,SAAS;IACxF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,EAAE,CAAC,EAAE,EAAE,CAAA;IACP,SAAS,CAAC,EAAE,eAAe,CAAA;CAC5B;AAED,YAAY,EAAE,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"ButtonExProps.d.ts","sourceRoot":"","sources":["../../../src/components/ButtonExProps.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAA;AAE3D,UAAU,aAAc,SAAQ,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,qBAAqB,EAAE,SAAS;IACxF,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,EAAE,CAAC,EAAE,EAAE,CAAA;IACP,SAAS,CAAC,EAAE,eAAe,CAAA;CAC5B;AAED,YAAY,EAAE,aAAa,EAAE,CAAA"}
@@ -6,19 +6,54 @@ import React3, { forwardRef as forwardRef3 } from "react";
6
6
 
7
7
  // src/components/ButtonExBase.tsx
8
8
  import { Button, useTheme } from "@mui/material";
9
+ import { useMixpanel } from "@xylabs/react-mixpanel";
10
+ import { useUserEvents } from "@xylabs/react-pixel";
9
11
  import { BusyCircularProgress, BusyLinearProgress, mergeBoxlikeStyles } from "@xylabs/react-shared";
10
12
  import React, { forwardRef } from "react";
11
- var ButtonExBase = /* @__PURE__ */ forwardRef((props, ref) => {
13
+ var ButtonExBase = /* @__PURE__ */ forwardRef(({ eventName = "Button Click", funnel, target, placement, disableUserEvents, href, disableMixpanel, ...props }, ref) => {
12
14
  const theme = useTheme();
15
+ const userEvents = useUserEvents();
16
+ const mixpanel = useMixpanel(false);
13
17
  const { busy, busyVariant = "linear", busyOpacity, onClick, children, ...rootProps } = mergeBoxlikeStyles(theme, props);
14
18
  const localOnClick = /* @__PURE__ */ __name((event) => {
15
- if (!busy) {
16
- onClick?.(event);
19
+ if (busy) {
20
+ event.preventDefault();
21
+ } else {
22
+ if (!disableMixpanel && mixpanel) {
23
+ mixpanel.track(eventName, {
24
+ funnel,
25
+ placement: placement ?? rootProps["aria-label"] ?? event.currentTarget.textContent
26
+ });
27
+ }
28
+ if (!disableUserEvents && userEvents) {
29
+ const callOnClickAndFollowHref = /* @__PURE__ */ __name(() => {
30
+ onClick?.(event);
31
+ if (href) {
32
+ if (target) {
33
+ window.open(href, target);
34
+ } else {
35
+ window.location.href = href;
36
+ }
37
+ }
38
+ }, "callOnClickAndFollowHref");
39
+ event.preventDefault();
40
+ userEvents.userClick({
41
+ elementName: eventName,
42
+ elementType: placement
43
+ }).then(() => {
44
+ callOnClickAndFollowHref();
45
+ }).catch((ex) => {
46
+ console.error("User event failed", eventName, ex);
47
+ callOnClickAndFollowHref();
48
+ });
49
+ }
17
50
  }
18
51
  }, "localOnClick");
19
52
  return /* @__PURE__ */ React.createElement(Button, {
20
53
  ref,
54
+ href,
21
55
  onClick: localOnClick,
56
+ target,
22
57
  ...rootProps
23
58
  }, busy && busyVariant === "linear" ? /* @__PURE__ */ React.createElement(BusyLinearProgress, {
24
59
  rounded: true,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/ButtonEx.tsx","../../src/components/ButtonExBase.tsx","../../src/components/ButtonExTo.tsx"],"sourcesContent":["import React, { forwardRef } from 'react'\n\nimport { ButtonExBase } from './ButtonExBase.tsx'\nimport type { ButtonExProps } from './ButtonExProps.tsx'\nimport { ButtonToEx } from './ButtonExTo.tsx'\n\nconst ButtonEx = forwardRef<HTMLButtonElement, ButtonExProps>(({ to, ...props }, ref) => {\n return to ? <ButtonToEx to={to} ref={ref} {...props} /> : <ButtonExBase {...props} />\n})\n\nButtonEx.displayName = 'ButtonExXYLabs'\n\nexport { ButtonEx }\n","import { Button, useTheme } from '@mui/material'\nimport {\n BusyCircularProgress, BusyLinearProgress, mergeBoxlikeStyles,\n} from '@xylabs/react-shared'\nimport type { MouseEvent } from 'react'\nimport React, { forwardRef } from 'react'\n\nimport type { ButtonExProps } from './ButtonExProps.tsx'\n\nconst ButtonExBase = forwardRef<HTMLButtonElement, ButtonExProps>((props, ref) => {\n const theme = useTheme()\n const {\n busy, busyVariant = 'linear', busyOpacity, onClick, children, ...rootProps\n } = mergeBoxlikeStyles<ButtonExProps>(theme, props)\n\n const localOnClick = (event: MouseEvent<HTMLButtonElement>) => {\n if (!busy) {\n onClick?.(event)\n }\n }\n\n return (\n <Button ref={ref} onClick={localOnClick} {...rootProps}>\n {busy && busyVariant === 'linear'\n ? <BusyLinearProgress rounded opacity={busyOpacity ?? 0} />\n : null}\n {busy && busyVariant === 'circular'\n ? <BusyCircularProgress rounded size={24} opacity={busyOpacity ?? 0.5} />\n : null}\n {children}\n </Button>\n )\n})\n\nButtonExBase.displayName = 'ButtonExBaseXYLabs'\n\nexport { ButtonExBase }\n","import type { MouseEvent } from 'react'\nimport React, { forwardRef } from 'react'\nimport { useNavigate } from 'react-router-dom'\n\nimport { ButtonExBase } from './ButtonExBase.tsx'\nimport type { ButtonExProps } from './ButtonExProps.tsx'\n\nconst ButtonToEx = forwardRef<HTMLButtonElement, ButtonExProps>(({\n to, toOptions, onClick, ...props\n}, ref) => {\n const navigate = useNavigate()\n const localOnClick = (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event)\n if (to) {\n navigate(to, toOptions)\n }\n }\n\n return <ButtonExBase ref={ref} onClick={localOnClick} {...props} />\n})\n\nButtonToEx.displayName = 'ButtonToExXYLabs'\n\nexport { ButtonToEx }\n"],"mappings":";;;;AAAA,OAAOA,UAASC,cAAAA,mBAAkB;;;ACAlC,SAASC,QAAQC,gBAAgB;AACjC,SACEC,sBAAsBC,oBAAoBC,0BACrC;AAEP,OAAOC,SAASC,kBAAkB;AAIlC,IAAMC,eAAeC,2BAA6C,CAACC,OAAOC,QAAAA;AACxE,QAAMC,QAAQC,SAAAA;AACd,QAAM,EACJC,MAAMC,cAAc,UAAUC,aAAaC,SAASC,UAAU,GAAGC,UAAAA,IAC/DC,mBAAkCR,OAAOF,KAAAA;AAE7C,QAAMW,eAAe,wBAACC,UAAAA;AACpB,QAAI,CAACR,MAAM;AACTG,gBAAUK,KAAAA;IACZ;EACF,GAJqB;AAMrB,SACE,sBAAA,cAACC,QAAAA;IAAOZ;IAAUM,SAASI;IAAe,GAAGF;KAC1CL,QAAQC,gBAAgB,WACrB,sBAAA,cAACS,oBAAAA;IAAmBC,SAAAA;IAAQC,SAASV,eAAe;OACpD,MACHF,QAAQC,gBAAgB,aACrB,sBAAA,cAACY,sBAAAA;IAAqBF,SAAAA;IAAQG,MAAM;IAAIF,SAASV,eAAe;OAChE,MACHE,QAAAA;AAGP,CAAA;AAEAV,aAAaqB,cAAc;;;ACjC3B,OAAOC,UAASC,cAAAA,mBAAkB;AAClC,SAASC,mBAAmB;AAK5B,IAAMC,aAAaC,gBAAAA,YAA6C,CAAC,EAC/DC,IAAIC,WAAWC,SAAS,GAAGC,MAAAA,GAC1BC,QAAAA;AACD,QAAMC,WAAWC,YAAAA;AACjB,QAAMC,eAAe,wBAACC,UAAAA;AACpBN,cAAUM,KAAAA;AACV,QAAIR,IAAI;AACNK,eAASL,IAAIC,SAAAA;IACf;EACF,GALqB;AAOrB,SAAO,gBAAAQ,OAAA,cAACC,cAAAA;IAAaN;IAAUF,SAASK;IAAe,GAAGJ;;AAC5D,CAAA;AAEAL,WAAWa,cAAc;;;AFfzB,IAAMC,WAAWC,gBAAAA,YAA6C,CAAC,EAAEC,IAAI,GAAGC,MAAAA,GAASC,QAAAA;AAC/E,SAAOF,KAAK,gBAAAG,OAAA,cAACC,YAAAA;IAAWJ;IAAQE;IAAW,GAAGD;OAAY,gBAAAE,OAAA,cAACE,cAAiBJ,KAAAA;AAC9E,CAAA;AAEAH,SAASQ,cAAc;","names":["React","forwardRef","Button","useTheme","BusyCircularProgress","BusyLinearProgress","mergeBoxlikeStyles","React","forwardRef","ButtonExBase","forwardRef","props","ref","theme","useTheme","busy","busyVariant","busyOpacity","onClick","children","rootProps","mergeBoxlikeStyles","localOnClick","event","Button","BusyLinearProgress","rounded","opacity","BusyCircularProgress","size","displayName","React","forwardRef","useNavigate","ButtonToEx","forwardRef","to","toOptions","onClick","props","ref","navigate","useNavigate","localOnClick","event","React","ButtonExBase","displayName","ButtonEx","forwardRef","to","props","ref","React","ButtonToEx","ButtonExBase","displayName"]}
1
+ {"version":3,"sources":["../../src/components/ButtonEx.tsx","../../src/components/ButtonExBase.tsx","../../src/components/ButtonExTo.tsx"],"sourcesContent":["import React, { forwardRef } from 'react'\n\nimport { ButtonExBase } from './ButtonExBase.tsx'\nimport type { ButtonExProps } from './ButtonExProps.tsx'\nimport { ButtonToEx } from './ButtonExTo.tsx'\n\nconst ButtonEx = forwardRef<HTMLButtonElement, ButtonExProps>(({ to, ...props }, ref) => {\n return to ? <ButtonToEx to={to} ref={ref} {...props} /> : <ButtonExBase {...props} />\n})\n\nButtonEx.displayName = 'ButtonExXYLabs'\n\nexport { ButtonEx }\n","import { Button, useTheme } from '@mui/material'\nimport { useMixpanel } from '@xylabs/react-mixpanel'\nimport { useUserEvents } from '@xylabs/react-pixel'\nimport {\n BusyCircularProgress, BusyLinearProgress, mergeBoxlikeStyles,\n} from '@xylabs/react-shared'\nimport type { MouseEvent } from 'react'\nimport React, { forwardRef } from 'react'\n\nimport type { ButtonExProps } from './ButtonExProps.tsx'\n\nconst ButtonExBase = forwardRef<HTMLButtonElement, ButtonExProps>(({\n eventName = 'Button Click', funnel, target, placement, disableUserEvents, href, disableMixpanel, ...props\n}, ref) => {\n const theme = useTheme()\n const userEvents = useUserEvents()\n const mixpanel = useMixpanel(false)\n const {\n busy, busyVariant = 'linear', busyOpacity, onClick, children, ...rootProps\n } = mergeBoxlikeStyles<ButtonExProps>(theme, props)\n\n const localOnClick = (event: MouseEvent<HTMLButtonElement>) => {\n if (busy) {\n // If it is busy, do not allow href clicks\n event.preventDefault()\n } else {\n if (!disableMixpanel && mixpanel) {\n mixpanel.track(eventName, {\n funnel,\n placement: placement ?? rootProps['aria-label'] ?? event.currentTarget.textContent,\n })\n }\n if (!disableUserEvents && userEvents) {\n const callOnClickAndFollowHref = () => {\n onClick?.(event)\n if (href) {\n if (target) {\n window.open(href, target)\n } else {\n window.location.href = href\n }\n }\n }\n event.preventDefault()\n userEvents.userClick({ elementName: eventName, elementType: placement }).then(() => {\n callOnClickAndFollowHref()\n }).catch((ex) => {\n console.error('User event failed', eventName, ex)\n callOnClickAndFollowHref()\n })\n }\n }\n }\n\n return (\n <Button ref={ref} href={href} onClick={localOnClick} target={target} {...rootProps}>\n {busy && busyVariant === 'linear'\n ? <BusyLinearProgress rounded opacity={busyOpacity ?? 0} />\n : null}\n {busy && busyVariant === 'circular'\n ? <BusyCircularProgress rounded size={24} opacity={busyOpacity ?? 0.5} />\n : null}\n {children}\n </Button>\n )\n})\n\nButtonExBase.displayName = 'ButtonExBaseXYLabs'\n\nexport { ButtonExBase }\n","import type { MouseEvent } from 'react'\nimport React, { forwardRef } from 'react'\nimport { useNavigate } from 'react-router-dom'\n\nimport { ButtonExBase } from './ButtonExBase.tsx'\nimport type { ButtonExProps } from './ButtonExProps.tsx'\n\nconst ButtonToEx = forwardRef<HTMLButtonElement, ButtonExProps>(({\n to, toOptions, onClick, ...props\n}, ref) => {\n const navigate = useNavigate()\n const localOnClick = (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event)\n if (to) {\n navigate(to, toOptions)\n }\n }\n\n return <ButtonExBase ref={ref} onClick={localOnClick} {...props} />\n})\n\nButtonToEx.displayName = 'ButtonToExXYLabs'\n\nexport { ButtonToEx }\n"],"mappings":";;;;AAAA,OAAOA,UAASC,cAAAA,mBAAkB;;;ACAlC,SAASC,QAAQC,gBAAgB;AACjC,SAASC,mBAAmB;AAC5B,SAASC,qBAAqB;AAC9B,SACEC,sBAAsBC,oBAAoBC,0BACrC;AAEP,OAAOC,SAASC,kBAAkB;AAIlC,IAAMC,eAAeC,2BAA6C,CAAC,EACjEC,YAAY,gBAAgBC,QAAQC,QAAQC,WAAWC,mBAAmBC,MAAMC,iBAAiB,GAAGC,MAAAA,GACnGC,QAAAA;AACD,QAAMC,QAAQC,SAAAA;AACd,QAAMC,aAAaC,cAAAA;AACnB,QAAMC,WAAWC,YAAY,KAAA;AAC7B,QAAM,EACJC,MAAMC,cAAc,UAAUC,aAAaC,SAASC,UAAU,GAAGC,UAAAA,IAC/DC,mBAAkCZ,OAAOF,KAAAA;AAE7C,QAAMe,eAAe,wBAACC,UAAAA;AACpB,QAAIR,MAAM;AAERQ,YAAMC,eAAc;IACtB,OAAO;AACL,UAAI,CAAClB,mBAAmBO,UAAU;AAChCA,iBAASY,MAAMzB,WAAW;UACxBC;UACAE,WAAWA,aAAaiB,UAAU,YAAA,KAAiBG,MAAMG,cAAcC;QACzE,CAAA;MACF;AACA,UAAI,CAACvB,qBAAqBO,YAAY;AACpC,cAAMiB,2BAA2B,6BAAA;AAC/BV,oBAAUK,KAAAA;AACV,cAAIlB,MAAM;AACR,gBAAIH,QAAQ;AACV2B,qBAAOC,KAAKzB,MAAMH,MAAAA;YACpB,OAAO;AACL2B,qBAAOE,SAAS1B,OAAOA;YACzB;UACF;QACF,GATiC;AAUjCkB,cAAMC,eAAc;AACpBb,mBAAWqB,UAAU;UAAEC,aAAajC;UAAWkC,aAAa/B;QAAU,CAAA,EAAGgC,KAAK,MAAA;AAC5EP,mCAAAA;QACF,CAAA,EAAGQ,MAAM,CAACC,OAAAA;AACRC,kBAAQC,MAAM,qBAAqBvC,WAAWqC,EAAAA;AAC9CT,mCAAAA;QACF,CAAA;MACF;IACF;EACF,GA/BqB;AAiCrB,SACE,sBAAA,cAACY,QAAAA;IAAOhC;IAAUH;IAAYa,SAASI;IAAcpB;IAAiB,GAAGkB;KACtEL,QAAQC,gBAAgB,WACrB,sBAAA,cAACyB,oBAAAA;IAAmBC,SAAAA;IAAQC,SAAS1B,eAAe;OACpD,MACHF,QAAQC,gBAAgB,aACrB,sBAAA,cAAC4B,sBAAAA;IAAqBF,SAAAA;IAAQG,MAAM;IAAIF,SAAS1B,eAAe;OAChE,MACHE,QAAAA;AAGP,CAAA;AAEArB,aAAagD,cAAc;;;AClE3B,OAAOC,UAASC,cAAAA,mBAAkB;AAClC,SAASC,mBAAmB;AAK5B,IAAMC,aAAaC,gBAAAA,YAA6C,CAAC,EAC/DC,IAAIC,WAAWC,SAAS,GAAGC,MAAAA,GAC1BC,QAAAA;AACD,QAAMC,WAAWC,YAAAA;AACjB,QAAMC,eAAe,wBAACC,UAAAA;AACpBN,cAAUM,KAAAA;AACV,QAAIR,IAAI;AACNK,eAASL,IAAIC,SAAAA;IACf;EACF,GALqB;AAOrB,SAAO,gBAAAQ,OAAA,cAACC,cAAAA;IAAaN;IAAUF,SAASK;IAAe,GAAGJ;;AAC5D,CAAA;AAEAL,WAAWa,cAAc;;;AFfzB,IAAMC,WAAWC,gBAAAA,YAA6C,CAAC,EAAEC,IAAI,GAAGC,MAAAA,GAASC,QAAAA;AAC/E,SAAOF,KAAK,gBAAAG,OAAA,cAACC,YAAAA;IAAWJ;IAAQE;IAAW,GAAGD;OAAY,gBAAAE,OAAA,cAACE,cAAiBJ,KAAAA;AAC9E,CAAA;AAEAH,SAASQ,cAAc;","names":["React","forwardRef","Button","useTheme","useMixpanel","useUserEvents","BusyCircularProgress","BusyLinearProgress","mergeBoxlikeStyles","React","forwardRef","ButtonExBase","forwardRef","eventName","funnel","target","placement","disableUserEvents","href","disableMixpanel","props","ref","theme","useTheme","userEvents","useUserEvents","mixpanel","useMixpanel","busy","busyVariant","busyOpacity","onClick","children","rootProps","mergeBoxlikeStyles","localOnClick","event","preventDefault","track","currentTarget","textContent","callOnClickAndFollowHref","window","open","location","userClick","elementName","elementType","then","catch","ex","console","error","Button","BusyLinearProgress","rounded","opacity","BusyCircularProgress","size","displayName","React","forwardRef","useNavigate","ButtonToEx","forwardRef","to","toOptions","onClick","props","ref","navigate","useNavigate","localOnClick","event","React","ButtonExBase","displayName","ButtonEx","forwardRef","to","props","ref","React","ButtonToEx","ButtonExBase","displayName"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xylabs/react-button",
3
- "version": "4.1.2",
3
+ "version": "4.2.0",
4
4
  "description": "Common React library for all XY Labs projects that use React",
5
5
  "keywords": [
6
6
  "utility",
@@ -37,14 +37,16 @@
37
37
  "packages/*"
38
38
  ],
39
39
  "dependencies": {
40
- "@xylabs/react-shared": "^4.1.2",
40
+ "@xylabs/react-mixpanel": "^4.2.0",
41
+ "@xylabs/react-pixel": "^4.2.0",
42
+ "@xylabs/react-shared": "^4.2.0",
41
43
  "react-router-dom": "^6.26.1"
42
44
  },
43
45
  "devDependencies": {
44
- "@mui/material": "^6.0.1",
46
+ "@mui/material": "^6.0.2",
45
47
  "@storybook/react": "^8.2.9",
46
48
  "@types/react": "^18.3.5",
47
- "@xylabs/react-flexbox": "^4.1.2",
49
+ "@xylabs/react-flexbox": "^4.2.0",
48
50
  "@xylabs/ts-scripts-yarn3": "^4.0.7",
49
51
  "@xylabs/tsconfig-react": "^4.0.7",
50
52
  "react": "^18.3.1",
@@ -1,4 +1,6 @@
1
1
  import { Button, useTheme } from '@mui/material'
2
+ import { useMixpanel } from '@xylabs/react-mixpanel'
3
+ import { useUserEvents } from '@xylabs/react-pixel'
2
4
  import {
3
5
  BusyCircularProgress, BusyLinearProgress, mergeBoxlikeStyles,
4
6
  } from '@xylabs/react-shared'
@@ -7,20 +9,51 @@ import React, { forwardRef } from 'react'
7
9
 
8
10
  import type { ButtonExProps } from './ButtonExProps.tsx'
9
11
 
10
- const ButtonExBase = forwardRef<HTMLButtonElement, ButtonExProps>((props, ref) => {
12
+ const ButtonExBase = forwardRef<HTMLButtonElement, ButtonExProps>(({
13
+ eventName = 'Button Click', funnel, target, placement, disableUserEvents, href, disableMixpanel, ...props
14
+ }, ref) => {
11
15
  const theme = useTheme()
16
+ const userEvents = useUserEvents()
17
+ const mixpanel = useMixpanel(false)
12
18
  const {
13
19
  busy, busyVariant = 'linear', busyOpacity, onClick, children, ...rootProps
14
20
  } = mergeBoxlikeStyles<ButtonExProps>(theme, props)
15
21
 
16
22
  const localOnClick = (event: MouseEvent<HTMLButtonElement>) => {
17
- if (!busy) {
18
- onClick?.(event)
23
+ if (busy) {
24
+ // If it is busy, do not allow href clicks
25
+ event.preventDefault()
26
+ } else {
27
+ if (!disableMixpanel && mixpanel) {
28
+ mixpanel.track(eventName, {
29
+ funnel,
30
+ placement: placement ?? rootProps['aria-label'] ?? event.currentTarget.textContent,
31
+ })
32
+ }
33
+ if (!disableUserEvents && userEvents) {
34
+ const callOnClickAndFollowHref = () => {
35
+ onClick?.(event)
36
+ if (href) {
37
+ if (target) {
38
+ window.open(href, target)
39
+ } else {
40
+ window.location.href = href
41
+ }
42
+ }
43
+ }
44
+ event.preventDefault()
45
+ userEvents.userClick({ elementName: eventName, elementType: placement }).then(() => {
46
+ callOnClickAndFollowHref()
47
+ }).catch((ex) => {
48
+ console.error('User event failed', eventName, ex)
49
+ callOnClickAndFollowHref()
50
+ })
51
+ }
19
52
  }
20
53
  }
21
54
 
22
55
  return (
23
- <Button ref={ref} onClick={localOnClick} {...rootProps}>
56
+ <Button ref={ref} href={href} onClick={localOnClick} target={target} {...rootProps}>
24
57
  {busy && busyVariant === 'linear'
25
58
  ? <BusyLinearProgress rounded opacity={busyOpacity ?? 0} />
26
59
  : null}
@@ -3,6 +3,11 @@ import type { BoxlikeComponentProps, BusyProps } from '@xylabs/react-shared'
3
3
  import type { NavigateOptions, To } from 'react-router-dom'
4
4
 
5
5
  interface ButtonExProps extends Omit<ButtonProps, 'ref'>, BoxlikeComponentProps, BusyProps {
6
+ disableMixpanel?: boolean
7
+ disableUserEvents?: boolean
8
+ eventName?: string
9
+ funnel?: string
10
+ placement?: string
6
11
  target?: string
7
12
  to?: To
8
13
  toOptions?: NavigateOptions