@cairntale/chimeling-react 1.0.0-alpha.5 → 1.0.0-alpha.6

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.
Files changed (35) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/components/index.d.ts +2 -2
  3. package/dist/components/playground/panel.js +142 -10
  4. package/dist/components/playground/panel.js.map +1 -1
  5. package/dist/components/playground/playground.d.ts +3 -1
  6. package/dist/components/playground/playground.js +42 -18
  7. package/dist/components/playground/playground.js.map +1 -1
  8. package/dist/components/playground/store.js +49 -8
  9. package/dist/components/playground/store.js.map +1 -1
  10. package/dist/components/popover.d.ts +9 -2
  11. package/dist/components/popover.js +117 -15
  12. package/dist/components/popover.js.map +1 -1
  13. package/dist/components/provider.d.ts +8 -1
  14. package/dist/components/provider.js +38 -8
  15. package/dist/components/provider.js.map +1 -1
  16. package/dist/components/root.js +8 -4
  17. package/dist/components/root.js.map +1 -1
  18. package/dist/components/trigger.d.ts +7 -2
  19. package/dist/components/trigger.js +67 -5
  20. package/dist/components/trigger.js.map +1 -1
  21. package/dist/index.d.ts +2 -2
  22. package/dist/lib/widget-context.d.ts +3 -1
  23. package/dist/lib/widget-context.js.map +1 -1
  24. package/dist/theme/color-system.d.ts +1 -0
  25. package/dist/theme/color-system.js +96 -0
  26. package/dist/theme/color-system.js.map +1 -0
  27. package/dist/theme/context.d.ts +2 -0
  28. package/dist/theme/context.js +15 -0
  29. package/dist/theme/context.js.map +1 -0
  30. package/dist/theme/index.d.ts +4 -0
  31. package/dist/theme/index.js +4 -0
  32. package/dist/theme/tokens.d.ts +6 -0
  33. package/dist/theme/tokens.js +69 -0
  34. package/dist/theme/tokens.js.map +1 -0
  35. package/package.json +2 -1
@@ -3,34 +3,136 @@ import { useWidgetContext } from "../lib/widget-context.js";
3
3
  import { formatActivityDuration } from "../lib/format-activity-duration.js";
4
4
  import { iconImageUrl } from "../lib/icon-url.js";
5
5
  import Logo from "./logo.js";
6
+ import { ClassNames } from "@emotion/react";
6
7
  import { jsx, jsxs } from "react/jsx-runtime";
7
8
  import { Popover } from "@base-ui/react/popover";
8
9
  //#region src/components/popover.tsx
9
- function ChimelingPopover({ className, style }) {
10
+ const DEFAULT_POPOVER = {
11
+ ring: true,
12
+ shadow: "elevated",
13
+ minWidth: 320,
14
+ gerundCapitalize: true,
15
+ gerundEllipsis: true
16
+ };
17
+ const iconSize = "calc(22px * var(--chl-font-size-scaling, 1))";
18
+ function ChimelingPopover({ className, style, ring = DEFAULT_POPOVER.ring, shadow = DEFAULT_POPOVER.shadow, minWidth = DEFAULT_POPOVER.minWidth, gerundCapitalize = DEFAULT_POPOVER.gerundCapitalize, gerundEllipsis = DEFAULT_POPOVER.gerundEllipsis }) {
10
19
  const { showable, now, poweredBy, placement, baseUrl } = useWidgetContext();
11
20
  if (!showable) return null;
12
21
  const { gerund, appName, iconHash, startedAt } = showable.activity;
13
- return /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, {
22
+ return /* @__PURE__ */ jsx(ClassNames, { children: ({ css, cx }) => /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, {
14
23
  side: placement.side,
15
24
  align: placement.align,
16
25
  sideOffset: placement.sideOffset,
17
26
  children: /* @__PURE__ */ jsxs(Popover.Popup, {
18
- className,
27
+ className: cx("chl-popover", css({
28
+ boxSizing: "border-box",
29
+ display: "flex",
30
+ flexDirection: "column",
31
+ minWidth,
32
+ overflow: "clip",
33
+ padding: 0,
34
+ margin: 0,
35
+ outline: "none",
36
+ color: "var(--chl-color-text-primary)",
37
+ backgroundColor: "var(--chl-color-background-primary)",
38
+ borderRadius: "var(--chl-border-radius-lg)",
39
+ border: "none",
40
+ boxShadow: [
41
+ ...shadow === "subtle" ? ["var(--chl-shadow-subtle)"] : [],
42
+ ...shadow === "elevated" ? ["var(--chl-shadow-elevated)"] : [],
43
+ ...ring ? ["var(--chl-ring)"] : []
44
+ ].join(", ") || "none"
45
+ }), className),
19
46
  style,
20
- children: [
21
- /* @__PURE__ */ jsx(Popover.Description, { children: gerund }),
22
- /* @__PURE__ */ jsx(Popover.Title, { children: appName }),
23
- /* @__PURE__ */ jsx("span", { children: formatActivityDuration(startedAt, now) }),
24
- iconHash ? /* @__PURE__ */ jsx("img", {
25
- src: iconImageUrl(baseUrl, iconHash),
26
- alt: ""
27
- }) : null,
28
- poweredBy ? /* @__PURE__ */ jsxs("div", { children: ["Powered by ", /* @__PURE__ */ jsx(Logo, {})] }) : null
29
- ]
47
+ "data-ring": ring ? "true" : "false",
48
+ "data-shadow": shadow,
49
+ "data-gerund-capitalize": gerundCapitalize ? "true" : "false",
50
+ "data-gerund-ellipsis": gerundEllipsis ? "true" : "false",
51
+ children: [/* @__PURE__ */ jsxs("div", {
52
+ className: css({
53
+ display: "flex",
54
+ flexDirection: "column",
55
+ gap: "var(--chl-spacing-2xs)",
56
+ padding: "var(--chl-spacing-sm)"
57
+ }),
58
+ children: [
59
+ /* @__PURE__ */ jsx(Popover.Description, {
60
+ className: css({
61
+ margin: 0,
62
+ fontSize: "var(--chl-font-size-sm)",
63
+ fontWeight: 400,
64
+ color: "var(--chl-color-text-tertiary)",
65
+ "[data-gerund-capitalize=\"true\"] &::first-letter": { textTransform: "uppercase" },
66
+ "[data-gerund-ellipsis=\"true\"] &::after": { content: "\"...\"" }
67
+ }),
68
+ children: gerund
69
+ }),
70
+ /* @__PURE__ */ jsxs("div", {
71
+ className: css({
72
+ display: "flex",
73
+ alignItems: "center",
74
+ gap: "var(--chl-spacing-2xs)",
75
+ minWidth: 0
76
+ }),
77
+ children: [iconHash ? /* @__PURE__ */ jsx("img", {
78
+ src: iconImageUrl(baseUrl, iconHash),
79
+ alt: "",
80
+ width: 24,
81
+ height: 24,
82
+ className: css({
83
+ display: "block",
84
+ flex: "0 0 auto",
85
+ inlineSize: iconSize,
86
+ blockSize: iconSize,
87
+ aspectRatio: "1",
88
+ objectFit: "contain",
89
+ margin: `calc(${iconSize} * -0.1)`
90
+ })
91
+ }) : null, /* @__PURE__ */ jsx(Popover.Title, {
92
+ className: css({
93
+ margin: 0,
94
+ minWidth: 0,
95
+ fontSize: "var(--chl-font-size-md)",
96
+ fontWeight: 450,
97
+ color: "var(--chl-color-text-primary)",
98
+ textBox: "trim-both cap alphabetic"
99
+ }),
100
+ children: appName
101
+ })]
102
+ }),
103
+ /* @__PURE__ */ jsx("span", {
104
+ className: css({
105
+ fontSize: "var(--chl-font-size-xs)",
106
+ color: "var(--chl-color-text-tertiary)"
107
+ }),
108
+ children: formatActivityDuration(startedAt, now)
109
+ })
110
+ ]
111
+ }), poweredBy ? /* @__PURE__ */ jsxs("a", {
112
+ href: "https://chimeling.app",
113
+ target: "_blank",
114
+ rel: "noopener noreferrer",
115
+ "aria-label": "Powered by Chimeling",
116
+ className: css({
117
+ display: "flex",
118
+ alignItems: "center",
119
+ gap: "var(--chl-spacing-2xs)",
120
+ paddingBlock: "var(--chl-spacing-xs)",
121
+ paddingInline: "var(--chl-spacing-sm)",
122
+ fontSize: "var(--chl-font-size-xs)",
123
+ color: "var(--chl-color-text-tertiary)",
124
+ backgroundColor: "var(--chl-color-background-secondary)",
125
+ textDecoration: "none",
126
+ outline: "none",
127
+ "&:hover, &:focus-visible": { backgroundColor: "var(--chl-color-background-secondary-focus)" },
128
+ "&:active": { backgroundColor: "var(--chl-color-background-secondary-active)" }
129
+ }),
130
+ children: ["Powered by ", /* @__PURE__ */ jsx(Logo, {})]
131
+ }) : null]
30
132
  })
31
- }) });
133
+ }) }) });
32
134
  }
33
135
  //#endregion
34
- export { ChimelingPopover };
136
+ export { ChimelingPopover, DEFAULT_POPOVER };
35
137
 
36
138
  //# sourceMappingURL=popover.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"popover.js","names":[],"sources":["../../src/components/popover.tsx"],"sourcesContent":["'use client'\n\nimport { Popover } from '@base-ui/react/popover'\nimport type { PopoverPopupProps } from '@base-ui/react/popover'\nimport { formatActivityDuration } from '../lib/format-activity-duration'\nimport { iconImageUrl } from '../lib/icon-url'\nimport { useWidgetContext } from '../lib/widget-context'\nimport Logo from './logo'\n\n// TODO: decide whether to expose the rest of Base UI Popup props.\nexport type ChimelingPopoverProps = Pick<PopoverPopupProps, 'className' | 'style'>\n\nexport function ChimelingPopover({ className, style }: ChimelingPopoverProps) {\n const { showable, now, poweredBy, placement, baseUrl } = useWidgetContext()\n\n if (!showable) {\n return null\n }\n\n const { gerund, appName, iconHash, startedAt } = showable.activity\n\n return (\n <Popover.Portal>\n {/* TODO: decide whether to expose the rest of Base UI Positioner props. */}\n <Popover.Positioner\n side={placement.side}\n align={placement.align}\n sideOffset={placement.sideOffset}\n >\n <Popover.Popup className={className} style={style}>\n <Popover.Description>{gerund}</Popover.Description>\n <Popover.Title>{appName}</Popover.Title>\n <span>{formatActivityDuration(startedAt, now)}</span>\n {iconHash ? <img src={iconImageUrl(baseUrl, iconHash)} alt=\"\" /> : null}\n {poweredBy ? (\n <div>\n Powered by <Logo />\n </div>\n ) : null}\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n )\n}\n"],"mappings":";;;;;;;;AAYA,SAAgB,iBAAiB,EAAE,WAAW,SAAgC;CAC5E,MAAM,EAAE,UAAU,KAAK,WAAW,WAAW,YAAY,iBAAiB;CAE1E,IAAI,CAAC,UACH,OAAO;CAGT,MAAM,EAAE,QAAQ,SAAS,UAAU,cAAc,SAAS;CAE1D,OACE,oBAAC,QAAQ,QAAT,EAAA,UAEE,oBAAC,QAAQ,YAAT;EACE,MAAM,UAAU;EAChB,OAAO,UAAU;EACjB,YAAY,UAAU;EAEtB,UAAA,qBAAC,QAAQ,OAAT;GAA0B;GAAkB;GAA5C,UAAA;IACE,oBAAC,QAAQ,aAAT,EAAA,UAAsB,OAA4B,CAAA;IAClD,oBAAC,QAAQ,OAAT,EAAA,UAAgB,QAAuB,CAAA;IACvC,oBAAC,QAAD,EAAA,UAAO,uBAAuB,WAAW,GAAG,EAAQ,CAAA;IACnD,WAAW,oBAAC,OAAD;KAAK,KAAK,aAAa,SAAS,QAAQ;KAAG,KAAI;IAAI,CAAA,IAAI;IAClE,YACC,qBAAC,OAAD,EAAA,UAAA,CAAK,eACQ,oBAAC,MAAD,CAAO,CAAA,CACf,EAAA,CAAA,IACH;GACS;;CACG,CAAA,EACN,CAAA;AAEpB"}
1
+ {"version":3,"file":"popover.js","names":[],"sources":["../../src/components/popover.tsx"],"sourcesContent":["'use client'\n\nimport { ClassNames } from '@emotion/react'\nimport { Popover } from '@base-ui/react/popover'\nimport type { PopoverPopupProps } from '@base-ui/react/popover'\nimport { formatActivityDuration } from '../lib/format-activity-duration'\nimport { iconImageUrl } from '../lib/icon-url'\nimport { useWidgetContext } from '../lib/widget-context'\nimport Logo from './logo'\n\n// TODO: decide whether to expose the rest of Base UI Popup props.\nexport type ChimelingPopoverProps = Pick<PopoverPopupProps, 'style'> & {\n className?: string\n ring?: boolean\n shadow?: 'none' | 'subtle' | 'elevated'\n minWidth?: number\n gerundCapitalize?: boolean\n gerundEllipsis?: boolean\n}\n\nexport const DEFAULT_POPOVER = {\n ring: true,\n shadow: 'elevated',\n minWidth: 320,\n gerundCapitalize: true,\n gerundEllipsis: true,\n} as const\n\nconst iconSize = 'calc(22px * var(--chl-font-size-scaling, 1))'\n\nexport function ChimelingPopover({\n className,\n style,\n ring = DEFAULT_POPOVER.ring,\n shadow = DEFAULT_POPOVER.shadow,\n minWidth = DEFAULT_POPOVER.minWidth,\n gerundCapitalize = DEFAULT_POPOVER.gerundCapitalize,\n gerundEllipsis = DEFAULT_POPOVER.gerundEllipsis,\n}: ChimelingPopoverProps) {\n const { showable, now, poweredBy, placement, baseUrl } = useWidgetContext()\n\n if (!showable) {\n return null\n }\n\n const { gerund, appName, iconHash, startedAt } = showable.activity\n\n return (\n <ClassNames>\n {({ css, cx }) => (\n <Popover.Portal>\n {/* TODO: decide whether to expose the rest of Base UI Positioner props. */}\n <Popover.Positioner\n side={placement.side}\n align={placement.align}\n sideOffset={placement.sideOffset}\n >\n <Popover.Popup\n className={cx(\n 'chl-popover',\n css({\n boxSizing: 'border-box',\n display: 'flex',\n flexDirection: 'column',\n minWidth,\n overflow: 'clip',\n padding: 0,\n margin: 0,\n outline: 'none',\n color: 'var(--chl-color-text-primary)',\n backgroundColor: 'var(--chl-color-background-primary)',\n borderRadius: 'var(--chl-border-radius-lg)',\n border: 'none',\n boxShadow:\n [\n ...(shadow === 'subtle' ? ['var(--chl-shadow-subtle)'] : []),\n ...(shadow === 'elevated' ? ['var(--chl-shadow-elevated)'] : []),\n ...(ring ? ['var(--chl-ring)'] : []),\n ].join(', ') || 'none',\n }),\n className,\n )}\n style={style}\n data-ring={ring ? 'true' : 'false'}\n data-shadow={shadow}\n data-gerund-capitalize={gerundCapitalize ? 'true' : 'false'}\n data-gerund-ellipsis={gerundEllipsis ? 'true' : 'false'}\n >\n <div\n className={css({\n display: 'flex',\n flexDirection: 'column',\n gap: 'var(--chl-spacing-2xs)',\n padding: 'var(--chl-spacing-sm)',\n })}\n >\n <Popover.Description\n className={css({\n margin: 0,\n fontSize: 'var(--chl-font-size-sm)',\n fontWeight: 400,\n color: 'var(--chl-color-text-tertiary)',\n '[data-gerund-capitalize=\"true\"] &::first-letter': {\n textTransform: 'uppercase',\n },\n '[data-gerund-ellipsis=\"true\"] &::after': {\n content: '\"...\"',\n },\n })}\n >\n {gerund}\n </Popover.Description>\n <div\n className={css({\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--chl-spacing-2xs)',\n minWidth: 0,\n })}\n >\n {iconHash ? (\n <img\n src={iconImageUrl(baseUrl, iconHash)}\n alt=\"\"\n width={24}\n height={24}\n className={css({\n display: 'block',\n flex: '0 0 auto',\n inlineSize: iconSize,\n blockSize: iconSize,\n aspectRatio: '1',\n objectFit: 'contain',\n margin: `calc(${iconSize} * -0.1)`,\n })}\n />\n ) : null}\n <Popover.Title\n className={css({\n margin: 0,\n minWidth: 0,\n fontSize: 'var(--chl-font-size-md)',\n fontWeight: 450,\n color: 'var(--chl-color-text-primary)',\n textBox: 'trim-both cap alphabetic',\n })}\n >\n {appName}\n </Popover.Title>\n </div>\n <span\n className={css({\n fontSize: 'var(--chl-font-size-xs)',\n color: 'var(--chl-color-text-tertiary)',\n })}\n >\n {formatActivityDuration(startedAt, now)}\n </span>\n </div>\n {poweredBy ? (\n <a\n href=\"https://chimeling.app\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label=\"Powered by Chimeling\"\n className={css({\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--chl-spacing-2xs)',\n paddingBlock: 'var(--chl-spacing-xs)',\n paddingInline: 'var(--chl-spacing-sm)',\n fontSize: 'var(--chl-font-size-xs)',\n color: 'var(--chl-color-text-tertiary)',\n backgroundColor: 'var(--chl-color-background-secondary)',\n textDecoration: 'none',\n outline: 'none',\n '&:hover, &:focus-visible': {\n backgroundColor: 'var(--chl-color-background-secondary-focus)',\n },\n '&:active': {\n backgroundColor: 'var(--chl-color-background-secondary-active)',\n },\n })}\n >\n Powered by <Logo />\n </a>\n ) : null}\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n )}\n </ClassNames>\n )\n}\n"],"mappings":";;;;;;;;;AAoBA,MAAa,kBAAkB;CAC7B,MAAM;CACN,QAAQ;CACR,UAAU;CACV,kBAAkB;CAClB,gBAAgB;AAClB;AAEA,MAAM,WAAW;AAEjB,SAAgB,iBAAiB,EAC/B,WACA,OACA,OAAO,gBAAgB,MACvB,SAAS,gBAAgB,QACzB,WAAW,gBAAgB,UAC3B,mBAAmB,gBAAgB,kBACnC,iBAAiB,gBAAgB,kBACT;CACxB,MAAM,EAAE,UAAU,KAAK,WAAW,WAAW,YAAY,iBAAiB;CAE1E,IAAI,CAAC,UACH,OAAO;CAGT,MAAM,EAAE,QAAQ,SAAS,UAAU,cAAc,SAAS;CAE1D,OACE,oBAAC,YAAD,EAAA,WACI,EAAE,KAAK,SACP,oBAAC,QAAQ,QAAT,EAAA,UAEE,oBAAC,QAAQ,YAAT;EACE,MAAM,UAAU;EAChB,OAAO,UAAU;EACjB,YAAY,UAAU;EAEtB,UAAA,qBAAC,QAAQ,OAAT;GACE,WAAW,GACT,eACA,IAAI;IACF,WAAW;IACX,SAAS;IACT,eAAe;IACf;IACA,UAAU;IACV,SAAS;IACT,QAAQ;IACR,SAAS;IACT,OAAO;IACP,iBAAiB;IACjB,cAAc;IACd,QAAQ;IACR,WACE;KACE,GAAI,WAAW,WAAW,CAAC,0BAA0B,IAAI,CAAC;KAC1D,GAAI,WAAW,aAAa,CAAC,4BAA4B,IAAI,CAAC;KAC9D,GAAI,OAAO,CAAC,iBAAiB,IAAI,CAAC;IACpC,CAAC,CAAC,KAAK,IAAI,KAAK;GACpB,CAAC,GACD,SACF;GACO;GACP,aAAW,OAAO,SAAS;GAC3B,eAAa;GACb,0BAAwB,mBAAmB,SAAS;GACpD,wBAAsB,iBAAiB,SAAS;GA7BlD,UAAA,CA+BE,qBAAC,OAAD;IACE,WAAW,IAAI;KACb,SAAS;KACT,eAAe;KACf,KAAK;KACL,SAAS;IACX,CAAC;IANH,UAAA;KAQE,oBAAC,QAAQ,aAAT;MACE,WAAW,IAAI;OACb,QAAQ;OACR,UAAU;OACV,YAAY;OACZ,OAAO;OACP,qDAAmD,EACjD,eAAe,YACjB;OACA,4CAA0C,EACxC,SAAS,UACX;MACF,CAAC;MAEA,UAAA;KACkB,CAAA;KACrB,qBAAC,OAAD;MACE,WAAW,IAAI;OACb,SAAS;OACT,YAAY;OACZ,KAAK;OACL,UAAU;MACZ,CAAC;MANH,UAAA,CAQG,WACC,oBAAC,OAAD;OACE,KAAK,aAAa,SAAS,QAAQ;OACnC,KAAI;OACJ,OAAO;OACP,QAAQ;OACR,WAAW,IAAI;QACb,SAAS;QACT,MAAM;QACN,YAAY;QACZ,WAAW;QACX,aAAa;QACb,WAAW;QACX,QAAQ,QAAQ,SAAS;OAC3B,CAAC;MACF,CAAA,IACC,MACJ,oBAAC,QAAQ,OAAT;OACE,WAAW,IAAI;QACb,QAAQ;QACR,UAAU;QACV,UAAU;QACV,YAAY;QACZ,OAAO;QACP,SAAS;OACX,CAAC;OAEA,UAAA;MACY,CAAA,CACZ;;KACL,oBAAC,QAAD;MACE,WAAW,IAAI;OACb,UAAU;OACV,OAAO;MACT,CAAC;MAEA,UAAA,uBAAuB,WAAW,GAAG;KAClC,CAAA;IACH;GACJ,CAAA,GAAA,YACC,qBAAC,KAAD;IACE,MAAK;IACL,QAAO;IACP,KAAI;IACJ,cAAW;IACX,WAAW,IAAI;KACb,SAAS;KACT,YAAY;KACZ,KAAK;KACL,cAAc;KACd,eAAe;KACf,UAAU;KACV,OAAO;KACP,iBAAiB;KACjB,gBAAgB;KAChB,SAAS;KACT,4BAA4B,EAC1B,iBAAiB,8CACnB;KACA,YAAY,EACV,iBAAiB,+CACnB;IACF,CAAC;IAtBH,UAAA,CAuBC,eACY,oBAAC,MAAD,CAAO,CAAA,CACjB;GACD,CAAA,IAAA,IACS;;CACG,CAAA,EACN,CAAA,EAER,CAAA;AAEhB"}
@@ -1,3 +1,5 @@
1
+ import { ChimelingColorScheme } from "../theme/tokens.js";
2
+ import "../theme/index.js";
1
3
  import { ReactNode } from "react";
2
4
  //#region src/components/provider.d.ts
3
5
  type ChimelingProviderProps = {
@@ -5,8 +7,13 @@ type ChimelingProviderProps = {
5
7
  refreshInterval?: number;
6
8
  children?: ReactNode;
7
9
  nonce?: string;
10
+ accentColor?: string;
11
+ colorScheme?: ChimelingColorScheme;
12
+ spacingScaling?: number;
13
+ fontSizeScaling?: number;
14
+ borderRadiusScaling?: number;
8
15
  };
9
- declare function ChimelingProvider({ baseUrl, refreshInterval, children, nonce }: ChimelingProviderProps): import("react").JSX.Element;
16
+ declare function ChimelingProvider({ baseUrl, refreshInterval, children, nonce, accentColor, colorScheme, spacingScaling, fontSizeScaling, borderRadiusScaling }: ChimelingProviderProps): import("react").JSX.Element;
10
17
  //#endregion
11
18
  export { ChimelingProvider, ChimelingProviderProps };
12
19
  //# sourceMappingURL=provider.d.ts.map
@@ -1,18 +1,39 @@
1
1
  "use client";
2
2
  import { DEFAULT_PRESENCE_REFRESH_INTERVAL } from "../lib/config.js";
3
3
  import { ChimelingContext } from "../lib/context.js";
4
+ import { generateContrastColor } from "../theme/color-system.js";
5
+ import { rootStyle } from "../theme/tokens.js";
6
+ import { ThemeProvider } from "../theme/context.js";
7
+ import "../theme/index.js";
4
8
  import { useMemo } from "react";
5
9
  import { createClient, createConfig } from "@cairntale/chimeling-js/client";
6
10
  import createCache from "@emotion/cache";
7
- import { CacheProvider } from "@emotion/react";
8
- import { jsx } from "react/jsx-runtime";
11
+ import { CacheProvider, Global } from "@emotion/react";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
9
13
  //#region src/components/provider.tsx
10
- function ChimelingProvider({ baseUrl, refreshInterval = DEFAULT_PRESENCE_REFRESH_INTERVAL, children, nonce }) {
14
+ const DEFAULT_BASE_URL = "https://chimeling.app";
15
+ function ChimelingProvider({ baseUrl, refreshInterval = DEFAULT_PRESENCE_REFRESH_INTERVAL, children, nonce, accentColor, colorScheme, spacingScaling, fontSizeScaling, borderRadiusScaling }) {
11
16
  const client = useMemo(() => createClient(createConfig({ baseUrl: baseUrl ?? "https://chimeling.app" })), [baseUrl]);
12
17
  const value = useMemo(() => ({
13
18
  client,
14
19
  refreshInterval
15
20
  }), [client, refreshInterval]);
21
+ const theme = useMemo(() => {
22
+ if (accentColor !== void 0) generateContrastColor(accentColor);
23
+ return {
24
+ accentColor,
25
+ colorScheme,
26
+ spacingScaling,
27
+ fontSizeScaling,
28
+ borderRadiusScaling
29
+ };
30
+ }, [
31
+ accentColor,
32
+ colorScheme,
33
+ spacingScaling,
34
+ fontSizeScaling,
35
+ borderRadiusScaling
36
+ ]);
16
37
  const emotionCache = useMemo(() => {
17
38
  const insertionPoint = typeof document !== "undefined" ? document.querySelector(`style#chl-style-insertion-point`) ?? void 0 : void 0;
18
39
  return createCache({
@@ -22,15 +43,24 @@ function ChimelingProvider({ baseUrl, refreshInterval = DEFAULT_PRESENCE_REFRESH
22
43
  nonce
23
44
  });
24
45
  }, [nonce]);
25
- return /* @__PURE__ */ jsx(CacheProvider, {
46
+ return /* @__PURE__ */ jsxs(CacheProvider, {
26
47
  value: emotionCache,
27
- children: /* @__PURE__ */ jsx(ChimelingContext.Provider, {
48
+ children: [/* @__PURE__ */ jsx(Global, { styles: {
49
+ ":root": rootStyle(theme),
50
+ ".chl-trigger, .chl-popover": {
51
+ fontFamily: "var(--chl-font-family)",
52
+ ...theme.colorScheme === "light" || theme.colorScheme === "dark" ? { colorScheme: theme.colorScheme } : {}
53
+ }
54
+ } }), /* @__PURE__ */ jsx(ChimelingContext.Provider, {
28
55
  value,
29
- children
30
- })
56
+ children: /* @__PURE__ */ jsx(ThemeProvider, {
57
+ value: theme,
58
+ children
59
+ })
60
+ })]
31
61
  });
32
62
  }
33
63
  //#endregion
34
- export { ChimelingProvider };
64
+ export { ChimelingProvider, DEFAULT_BASE_URL };
35
65
 
36
66
  //# sourceMappingURL=provider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","names":[],"sources":["../../src/components/provider.tsx"],"sourcesContent":["'use client'\n\nimport { useMemo, type ReactNode } from 'react'\nimport { createClient, createConfig } from '@cairntale/chimeling-js/client'\nimport { DEFAULT_PRESENCE_REFRESH_INTERVAL } from '../lib/config'\nimport { ChimelingContext } from '../lib/context'\nimport createCache from '@emotion/cache'\nimport { CacheProvider } from '@emotion/react'\n\nexport type ChimelingProviderProps = {\n baseUrl?: string\n refreshInterval?: number\n children?: ReactNode\n nonce?: string\n}\n\nexport function ChimelingProvider({\n baseUrl,\n refreshInterval = DEFAULT_PRESENCE_REFRESH_INTERVAL,\n children,\n nonce,\n}: ChimelingProviderProps) {\n const client = useMemo(\n () => createClient(createConfig({ baseUrl: baseUrl ?? 'https://chimeling.app' })),\n [baseUrl],\n )\n const value = useMemo(() => ({ client, refreshInterval }), [client, refreshInterval])\n\n const emotionCache = useMemo(() => {\n const insertionPoint =\n typeof document !== 'undefined'\n ? (document.querySelector<HTMLElement>(`style#chl-style-insertion-point`) ?? undefined)\n : undefined\n\n return createCache({\n key: 'chl-internal',\n prepend: !insertionPoint,\n insertionPoint,\n nonce,\n })\n }, [nonce])\n\n return (\n <CacheProvider value={emotionCache}>\n <ChimelingContext.Provider value={value}>{children}</ChimelingContext.Provider>\n </CacheProvider>\n )\n}\n"],"mappings":";;;;;;;;;AAgBA,SAAgB,kBAAkB,EAChC,SACA,kBAAkB,mCAClB,UACA,SACyB;CACzB,MAAM,SAAS,cACP,aAAa,aAAa,EAAE,SAAS,WAAW,wBAAwB,CAAC,CAAC,GAChF,CAAC,OAAO,CACV;CACA,MAAM,QAAQ,eAAe;EAAE;EAAQ;CAAgB,IAAI,CAAC,QAAQ,eAAe,CAAC;CAEpF,MAAM,eAAe,cAAc;EACjC,MAAM,iBACJ,OAAO,aAAa,cACf,SAAS,cAA2B,iCAAiC,KAAK,KAAA,IAC3E,KAAA;EAEN,OAAO,YAAY;GACjB,KAAK;GACL,SAAS,CAAC;GACV;GACA;EACF,CAAC;CACH,GAAG,CAAC,KAAK,CAAC;CAEV,OACE,oBAAC,eAAD;EAAe,OAAO;EACpB,UAAA,oBAAC,iBAAiB,UAAlB;GAAkC;GAAQ;EAAoC,CAAA;CACjE,CAAA;AAEnB"}
1
+ {"version":3,"file":"provider.js","names":[],"sources":["../../src/components/provider.tsx"],"sourcesContent":["'use client'\n\nimport { useMemo, type ReactNode } from 'react'\nimport { createClient, createConfig } from '@cairntale/chimeling-js/client'\nimport { DEFAULT_PRESENCE_REFRESH_INTERVAL } from '../lib/config'\nimport { ChimelingContext } from '../lib/context'\nimport createCache from '@emotion/cache'\nimport { CacheProvider, Global } from '@emotion/react'\nimport {\n ThemeProvider,\n generateContrastColor,\n rootStyle,\n type ChimelingColorScheme,\n} from '../theme'\n\nexport type ChimelingProviderProps = {\n baseUrl?: string\n refreshInterval?: number\n children?: ReactNode\n nonce?: string\n accentColor?: string\n colorScheme?: ChimelingColorScheme\n spacingScaling?: number\n fontSizeScaling?: number\n borderRadiusScaling?: number\n}\n\nexport const DEFAULT_BASE_URL = 'https://chimeling.app'\n\nexport function ChimelingProvider({\n baseUrl,\n refreshInterval = DEFAULT_PRESENCE_REFRESH_INTERVAL,\n children,\n nonce,\n accentColor,\n colorScheme,\n spacingScaling,\n fontSizeScaling,\n borderRadiusScaling,\n}: ChimelingProviderProps) {\n const client = useMemo(\n () => createClient(createConfig({ baseUrl: baseUrl ?? DEFAULT_BASE_URL })),\n [baseUrl],\n )\n const value = useMemo(() => ({ client, refreshInterval }), [client, refreshInterval])\n const theme = useMemo(() => {\n if (accentColor !== undefined) {\n generateContrastColor(accentColor)\n }\n return { accentColor, colorScheme, spacingScaling, fontSizeScaling, borderRadiusScaling }\n }, [accentColor, colorScheme, spacingScaling, fontSizeScaling, borderRadiusScaling])\n\n const emotionCache = useMemo(() => {\n const insertionPoint =\n typeof document !== 'undefined'\n ? (document.querySelector<HTMLElement>(`style#chl-style-insertion-point`) ?? undefined)\n : undefined\n\n return createCache({\n key: 'chl-internal',\n prepend: !insertionPoint,\n insertionPoint,\n nonce,\n })\n }, [nonce])\n\n return (\n <CacheProvider value={emotionCache}>\n <Global\n styles={{\n ':root': rootStyle(theme),\n '.chl-trigger, .chl-popover': {\n fontFamily: 'var(--chl-font-family)',\n ...(theme.colorScheme === 'light' || theme.colorScheme === 'dark'\n ? { colorScheme: theme.colorScheme }\n : {}),\n },\n }}\n />\n <ChimelingContext.Provider value={value}>\n <ThemeProvider value={theme}>{children}</ThemeProvider>\n </ChimelingContext.Provider>\n </CacheProvider>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AA2BA,MAAa,mBAAmB;AAEhC,SAAgB,kBAAkB,EAChC,SACA,kBAAkB,mCAClB,UACA,OACA,aACA,aACA,gBACA,iBACA,uBACyB;CACzB,MAAM,SAAS,cACP,aAAa,aAAa,EAAE,SAAS,WAAA,wBAA4B,CAAC,CAAC,GACzE,CAAC,OAAO,CACV;CACA,MAAM,QAAQ,eAAe;EAAE;EAAQ;CAAgB,IAAI,CAAC,QAAQ,eAAe,CAAC;CACpF,MAAM,QAAQ,cAAc;EAC1B,IAAI,gBAAgB,KAAA,GAClB,sBAAsB,WAAW;EAEnC,OAAO;GAAE;GAAa;GAAa;GAAgB;GAAiB;EAAoB;CAC1F,GAAG;EAAC;EAAa;EAAa;EAAgB;EAAiB;CAAmB,CAAC;CAEnF,MAAM,eAAe,cAAc;EACjC,MAAM,iBACJ,OAAO,aAAa,cACf,SAAS,cAA2B,iCAAiC,KAAK,KAAA,IAC3E,KAAA;EAEN,OAAO,YAAY;GACjB,KAAK;GACL,SAAS,CAAC;GACV;GACA;EACF,CAAC;CACH,GAAG,CAAC,KAAK,CAAC;CAEV,OACE,qBAAC,eAAD;EAAe,OAAO;EAAtB,UAAA,CACE,oBAAC,QAAD,EACE,QAAQ;GACN,SAAS,UAAU,KAAK;GACxB,8BAA8B;IAC5B,YAAY;IACZ,GAAI,MAAM,gBAAgB,WAAW,MAAM,gBAAgB,SACvD,EAAE,aAAa,MAAM,YAAY,IACjC,CAAC;GACP;EACF,EACD,CAAA,GACD,oBAAC,iBAAiB,UAAlB;GAAkC;GAChC,UAAA,oBAAC,eAAD;IAAe,OAAO;IAAQ;GAAwB,CAAA;EAC7B,CAAA,CACd;;AAEnB"}
@@ -7,9 +7,13 @@ import { useEffect, useMemo, useRef, useState } from "react";
7
7
  import { jsx } from "react/jsx-runtime";
8
8
  import { Popover } from "@base-ui/react/popover";
9
9
  //#region src/components/root.tsx
10
- const DEFAULT_HOVER_OPEN_DELAY = 300;
11
- const DEFAULT_HOVER_CLOSE_DELAY = 0;
12
- function ChimelingRoot({ userId, children, poweredBy = true, openOnHover = false, hoverOpenDelay = DEFAULT_HOVER_OPEN_DELAY, hoverCloseDelay = DEFAULT_HOVER_CLOSE_DELAY, onReady, presence: presenceOverride, refreshInterval, side, align, sideOffset }) {
10
+ const DEFAULT_ROOT = {
11
+ openOnHover: false,
12
+ hoverOpenDelay: 300,
13
+ hoverCloseDelay: 0,
14
+ sideOffset: 6
15
+ };
16
+ function ChimelingRoot({ userId, children, poweredBy = true, openOnHover = DEFAULT_ROOT.openOnHover, hoverOpenDelay = DEFAULT_ROOT.hoverOpenDelay, hoverCloseDelay = DEFAULT_ROOT.hoverCloseDelay, onReady, presence: presenceOverride, refreshInterval, side, align, sideOffset = DEFAULT_ROOT.sideOffset }) {
13
17
  const { client } = useChimelingContext();
14
18
  const fetched = useResolvedUserPresence(presenceOverride === void 0 ? userId : "", { refreshInterval });
15
19
  const presence = presenceOverride ?? fetched.data;
@@ -61,6 +65,6 @@ function ChimelingRoot({ userId, children, poweredBy = true, openOnHover = false
61
65
  });
62
66
  }
63
67
  //#endregion
64
- export { ChimelingRoot };
68
+ export { ChimelingRoot, DEFAULT_ROOT };
65
69
 
66
70
  //# sourceMappingURL=root.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"root.js","names":[],"sources":["../../src/components/root.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useMemo, useRef, useState, type ReactNode } from 'react'\nimport { Popover } from '@base-ui/react/popover'\nimport type { GetResolvedUserPresenceResponse } from '@cairntale/chimeling-js'\nimport { useResolvedUserPresence } from '../hooks/use-resolved-user-presence'\nimport { useChimelingContext } from '../lib/context'\nimport { getShowablePresence, type ShowablePresence } from '../lib/showable-presence'\nimport { WidgetContext, type WidgetPlacement } from '../lib/widget-context'\n\nconst DEFAULT_HOVER_OPEN_DELAY = 300\nconst DEFAULT_HOVER_CLOSE_DELAY = 0\n\nexport type ChimelingRootProps = WidgetPlacement & {\n userId: string\n children: ReactNode\n poweredBy?: boolean\n openOnHover?: boolean\n hoverOpenDelay?: number\n hoverCloseDelay?: number\n onReady?: (presence: ShowablePresence) => void\n presence?: GetResolvedUserPresenceResponse\n refreshInterval?: number\n}\n\nexport function ChimelingRoot({\n userId,\n children,\n poweredBy = true,\n openOnHover = false,\n hoverOpenDelay = DEFAULT_HOVER_OPEN_DELAY,\n hoverCloseDelay = DEFAULT_HOVER_CLOSE_DELAY,\n onReady,\n presence: presenceOverride,\n refreshInterval,\n side,\n align,\n sideOffset,\n}: ChimelingRootProps) {\n const { client } = useChimelingContext()\n const fetched = useResolvedUserPresence(presenceOverride === undefined ? userId : '', {\n refreshInterval,\n })\n const presence = presenceOverride ?? fetched.data\n const showable = useMemo(() => getShowablePresence(presence), [presence])\n\n const [now, setNow] = useState(() => new Date())\n const readyRef = useRef(false)\n\n useEffect(() => {\n if (!showable) {\n return\n }\n\n const id = setInterval(() => setNow(new Date()), 1000)\n return () => clearInterval(id)\n }, [showable])\n\n useEffect(() => {\n if (readyRef.current || !showable) {\n return\n }\n\n readyRef.current = true\n onReady?.(showable)\n }, [showable, onReady])\n\n const baseUrl = client.getConfig().baseUrl ?? ''\n const placement = useMemo(() => ({ side, align, sideOffset }), [side, align, sideOffset])\n\n const value = useMemo(\n () => ({\n showable,\n now,\n poweredBy,\n openOnHover,\n hoverOpenDelay,\n hoverCloseDelay,\n placement,\n baseUrl,\n }),\n [showable, now, poweredBy, openOnHover, hoverOpenDelay, hoverCloseDelay, placement, baseUrl],\n )\n\n return (\n <WidgetContext.Provider value={value}>\n {/* TODO: decide whether to expose Base UI Root props (open, onOpenChange, …). */}\n {showable ? <Popover.Root>{children}</Popover.Root> : children}\n </WidgetContext.Provider>\n )\n}\n"],"mappings":";;;;;;;;;AAUA,MAAM,2BAA2B;AACjC,MAAM,4BAA4B;AAclC,SAAgB,cAAc,EAC5B,QACA,UACA,YAAY,MACZ,cAAc,OACd,iBAAiB,0BACjB,kBAAkB,2BAClB,SACA,UAAU,kBACV,iBACA,MACA,OACA,cACqB;CACrB,MAAM,EAAE,WAAW,oBAAoB;CACvC,MAAM,UAAU,wBAAwB,qBAAqB,KAAA,IAAY,SAAS,IAAI,EACpF,gBACF,CAAC;CACD,MAAM,WAAW,oBAAoB,QAAQ;CAC7C,MAAM,WAAW,cAAc,oBAAoB,QAAQ,GAAG,CAAC,QAAQ,CAAC;CAExE,MAAM,CAAC,KAAK,UAAU,+BAAe,IAAI,KAAK,CAAC;CAC/C,MAAM,WAAW,OAAO,KAAK;CAE7B,gBAAgB;EACd,IAAI,CAAC,UACH;EAGF,MAAM,KAAK,kBAAkB,uBAAO,IAAI,KAAK,CAAC,GAAG,GAAI;EACrD,aAAa,cAAc,EAAE;CAC/B,GAAG,CAAC,QAAQ,CAAC;CAEb,gBAAgB;EACd,IAAI,SAAS,WAAW,CAAC,UACvB;EAGF,SAAS,UAAU;EACnB,UAAU,QAAQ;CACpB,GAAG,CAAC,UAAU,OAAO,CAAC;CAEtB,MAAM,UAAU,OAAO,UAAU,CAAC,CAAC,WAAW;CAC9C,MAAM,YAAY,eAAe;EAAE;EAAM;EAAO;CAAW,IAAI;EAAC;EAAM;EAAO;CAAU,CAAC;CAExF,MAAM,QAAQ,eACL;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,IACA;EAAC;EAAU;EAAK;EAAW;EAAa;EAAgB;EAAiB;EAAW;CAAO,CAC7F;CAEA,OACE,oBAAC,cAAc,UAAf;EAA+B;EAE5B,UAAA,WAAW,oBAAC,QAAQ,MAAT,EAAe,SAAuB,CAAA,IAAI;CAChC,CAAA;AAE5B"}
1
+ {"version":3,"file":"root.js","names":[],"sources":["../../src/components/root.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useMemo, useRef, useState, type ReactNode } from 'react'\nimport { Popover } from '@base-ui/react/popover'\nimport type { GetResolvedUserPresenceResponse } from '@cairntale/chimeling-js'\nimport { useResolvedUserPresence } from '../hooks/use-resolved-user-presence'\nimport { useChimelingContext } from '../lib/context'\nimport { getShowablePresence, type ShowablePresence } from '../lib/showable-presence'\nimport { WidgetContext, type WidgetPlacement } from '../lib/widget-context'\n\nexport const DEFAULT_ROOT = {\n openOnHover: false,\n hoverOpenDelay: 300,\n hoverCloseDelay: 0,\n sideOffset: 6,\n} as const\n\nexport type ChimelingRootProps = WidgetPlacement & {\n userId: string\n children: ReactNode\n poweredBy?: boolean\n openOnHover?: boolean\n hoverOpenDelay?: number\n hoverCloseDelay?: number\n onReady?: (presence: ShowablePresence) => void\n presence?: GetResolvedUserPresenceResponse\n refreshInterval?: number\n}\n\nexport function ChimelingRoot({\n userId,\n children,\n poweredBy = true,\n openOnHover = DEFAULT_ROOT.openOnHover,\n hoverOpenDelay = DEFAULT_ROOT.hoverOpenDelay,\n hoverCloseDelay = DEFAULT_ROOT.hoverCloseDelay,\n onReady,\n presence: presenceOverride,\n refreshInterval,\n side,\n align,\n sideOffset = DEFAULT_ROOT.sideOffset,\n}: ChimelingRootProps) {\n const { client } = useChimelingContext()\n const fetched = useResolvedUserPresence(presenceOverride === undefined ? userId : '', {\n refreshInterval,\n })\n const presence = presenceOverride ?? fetched.data\n const showable = useMemo(() => getShowablePresence(presence), [presence])\n\n const [now, setNow] = useState(() => new Date())\n const readyRef = useRef(false)\n\n useEffect(() => {\n if (!showable) {\n return\n }\n\n const id = setInterval(() => setNow(new Date()), 1000)\n return () => clearInterval(id)\n }, [showable])\n\n useEffect(() => {\n if (readyRef.current || !showable) {\n return\n }\n\n readyRef.current = true\n onReady?.(showable)\n }, [showable, onReady])\n\n const baseUrl = client.getConfig().baseUrl ?? ''\n const placement = useMemo(() => ({ side, align, sideOffset }), [side, align, sideOffset])\n\n const value = useMemo(\n () => ({\n showable,\n now,\n poweredBy,\n openOnHover,\n hoverOpenDelay,\n hoverCloseDelay,\n placement,\n baseUrl,\n }),\n [showable, now, poweredBy, openOnHover, hoverOpenDelay, hoverCloseDelay, placement, baseUrl],\n )\n\n return (\n <WidgetContext.Provider value={value}>\n {showable ? <Popover.Root>{children}</Popover.Root> : children}\n </WidgetContext.Provider>\n )\n}\n"],"mappings":";;;;;;;;;AAUA,MAAa,eAAe;CAC1B,aAAa;CACb,gBAAgB;CAChB,iBAAiB;CACjB,YAAY;AACd;AAcA,SAAgB,cAAc,EAC5B,QACA,UACA,YAAY,MACZ,cAAc,aAAa,aAC3B,iBAAiB,aAAa,gBAC9B,kBAAkB,aAAa,iBAC/B,SACA,UAAU,kBACV,iBACA,MACA,OACA,aAAa,aAAa,cACL;CACrB,MAAM,EAAE,WAAW,oBAAoB;CACvC,MAAM,UAAU,wBAAwB,qBAAqB,KAAA,IAAY,SAAS,IAAI,EACpF,gBACF,CAAC;CACD,MAAM,WAAW,oBAAoB,QAAQ;CAC7C,MAAM,WAAW,cAAc,oBAAoB,QAAQ,GAAG,CAAC,QAAQ,CAAC;CAExE,MAAM,CAAC,KAAK,UAAU,+BAAe,IAAI,KAAK,CAAC;CAC/C,MAAM,WAAW,OAAO,KAAK;CAE7B,gBAAgB;EACd,IAAI,CAAC,UACH;EAGF,MAAM,KAAK,kBAAkB,uBAAO,IAAI,KAAK,CAAC,GAAG,GAAI;EACrD,aAAa,cAAc,EAAE;CAC/B,GAAG,CAAC,QAAQ,CAAC;CAEb,gBAAgB;EACd,IAAI,SAAS,WAAW,CAAC,UACvB;EAGF,SAAS,UAAU;EACnB,UAAU,QAAQ;CACpB,GAAG,CAAC,UAAU,OAAO,CAAC;CAEtB,MAAM,UAAU,OAAO,UAAU,CAAC,CAAC,WAAW;CAC9C,MAAM,YAAY,eAAe;EAAE;EAAM;EAAO;CAAW,IAAI;EAAC;EAAM;EAAO;CAAU,CAAC;CAExF,MAAM,QAAQ,eACL;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,IACA;EAAC;EAAU;EAAK;EAAW;EAAa;EAAgB;EAAiB;EAAW;CAAO,CAC7F;CAEA,OACE,oBAAC,cAAc,UAAf;EAA+B;EAC5B,UAAA,WAAW,oBAAC,QAAQ,MAAT,EAAe,SAAuB,CAAA,IAAI;CAChC,CAAA;AAE5B"}
@@ -1,7 +1,12 @@
1
1
  import { PopoverTriggerProps } from "@base-ui/react/popover";
2
2
  //#region src/components/trigger.d.ts
3
- type ChimelingTriggerProps = Pick<PopoverTriggerProps, 'className' | 'style' | 'nativeButton' | 'id'>;
4
- declare function ChimelingTrigger({ className, style, nativeButton, id }: ChimelingTriggerProps): import("react").JSX.Element | null;
3
+ type ChimelingTriggerProps = Pick<PopoverTriggerProps, 'style' | 'nativeButton' | 'id'> & {
4
+ className?: string;
5
+ variant?: 'inline' | 'pill';
6
+ shimmer?: boolean;
7
+ gradient?: boolean;
8
+ };
9
+ declare function ChimelingTrigger({ className, style, nativeButton, id, variant, shimmer, gradient }: ChimelingTriggerProps): import("react").JSX.Element | null;
5
10
  //#endregion
6
11
  export { ChimelingTrigger, ChimelingTriggerProps };
7
12
  //# sourceMappingURL=trigger.d.ts.map
@@ -1,23 +1,85 @@
1
1
  "use client";
2
2
  import { useWidgetContext } from "../lib/widget-context.js";
3
+ import { ClassNames, keyframes } from "@emotion/react";
3
4
  import { jsx } from "react/jsx-runtime";
4
5
  import { Popover } from "@base-ui/react/popover";
5
6
  //#region src/components/trigger.tsx
6
- function ChimelingTrigger({ className, style, nativeButton, id }) {
7
+ const shimmerAnimation = keyframes({
8
+ from: { backgroundPosition: "200% 0" },
9
+ to: { backgroundPosition: "-200% 0" }
10
+ });
11
+ const triggerReset = {
12
+ border: "none",
13
+ outline: "none",
14
+ margin: 0,
15
+ padding: 0,
16
+ backgroundColor: "unset",
17
+ fontWeight: 450
18
+ };
19
+ const DEFAULT_TRIGGER = {
20
+ variant: "inline",
21
+ shimmer: true,
22
+ gradient: true
23
+ };
24
+ function ChimelingTrigger({ className, style, nativeButton, id, variant = DEFAULT_TRIGGER.variant, shimmer = DEFAULT_TRIGGER.shimmer, gradient = DEFAULT_TRIGGER.gradient }) {
7
25
  const { showable, openOnHover, hoverOpenDelay, hoverCloseDelay } = useWidgetContext();
8
26
  if (!showable) return null;
9
- return /* @__PURE__ */ jsx(Popover.Trigger, {
10
- className,
27
+ return /* @__PURE__ */ jsx(ClassNames, { children: ({ css, cx }) => /* @__PURE__ */ jsx(Popover.Trigger, {
28
+ className: cx("chl-trigger", css({
29
+ ...triggerReset,
30
+ "&[data-variant=\"inline\"]": {
31
+ display: "inline",
32
+ fontSize: "inherit",
33
+ ...shimmer ? {
34
+ backgroundImage: `linear-gradient(to right, var(--chl-color-background-accent) 0%, color-mix(in oklch, var(--chl-color-background-accent) 60%, #fff) 50%, var(--chl-color-background-accent) 100%)`,
35
+ backgroundSize: "200% 100%",
36
+ backgroundClip: "text",
37
+ WebkitBackgroundClip: "text",
38
+ color: "transparent",
39
+ animation: `${shimmerAnimation} 4s linear infinite`,
40
+ "@media (prefers-reduced-motion: reduce)": { animation: "none" },
41
+ "&:hover, &:focus-visible": { backgroundImage: `linear-gradient(to right, var(--chl-color-background-accent-focus) 0%, color-mix(in oklch, var(--chl-color-background-accent-focus) 60%, #fff) 50%, var(--chl-color-background-accent-focus) 100%)` },
42
+ "&:active": { backgroundImage: `linear-gradient(to right, var(--chl-color-background-accent-active) 0%, color-mix(in oklch, var(--chl-color-background-accent-active) 60%, #fff) 50%, var(--chl-color-background-accent-active) 100%)` }
43
+ } : {
44
+ color: "var(--chl-color-background-accent)",
45
+ "&:hover, &:focus-visible": { color: "var(--chl-color-background-accent-focus)" },
46
+ "&:active": { color: "var(--chl-color-background-accent-active)" }
47
+ }
48
+ },
49
+ "&[data-variant=\"pill\"]": {
50
+ display: "block",
51
+ padding: "var(--chl-spacing-2xs) var(--chl-spacing-xs)",
52
+ borderRadius: "var(--chl-border-radius-full)",
53
+ fontSize: "var(--chl-font-size-sm)",
54
+ color: "var(--chl-color-background-accent-contrast)",
55
+ backgroundImage: gradient ? `linear-gradient(to bottom, color-mix(in oklch, var(--chl-color-background-accent) 80%, #fff), var(--chl-color-background-accent))` : void 0,
56
+ backgroundColor: gradient ? void 0 : "var(--chl-color-background-accent)",
57
+ "&::first-letter": { textTransform: "uppercase" },
58
+ "&:hover, &:focus-visible": {
59
+ color: "var(--chl-color-background-accent-contrast-focus)",
60
+ backgroundImage: gradient ? `linear-gradient(to bottom, color-mix(in oklch, var(--chl-color-background-accent-focus) 80%, #fff), var(--chl-color-background-accent-focus))` : void 0,
61
+ backgroundColor: gradient ? void 0 : "var(--chl-color-background-accent-focus)"
62
+ },
63
+ "&:active": {
64
+ color: "var(--chl-color-background-accent-contrast-active)",
65
+ backgroundImage: gradient ? `linear-gradient(to bottom, color-mix(in oklch, var(--chl-color-background-accent-active) 80%, #fff), var(--chl-color-background-accent-active))` : void 0,
66
+ backgroundColor: gradient ? void 0 : "var(--chl-color-background-accent-active)"
67
+ }
68
+ }
69
+ }), className),
11
70
  style,
12
71
  nativeButton,
13
72
  id,
73
+ "data-variant": variant,
74
+ "data-shimmer": shimmer ? "true" : "false",
75
+ "data-gradient": gradient ? "true" : "false",
14
76
  openOnHover,
15
77
  delay: hoverOpenDelay,
16
78
  closeDelay: hoverCloseDelay,
17
79
  children: showable.activity.gerund
18
- });
80
+ }) });
19
81
  }
20
82
  //#endregion
21
- export { ChimelingTrigger };
83
+ export { ChimelingTrigger, DEFAULT_TRIGGER };
22
84
 
23
85
  //# sourceMappingURL=trigger.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"trigger.js","names":[],"sources":["../../src/components/trigger.tsx"],"sourcesContent":["'use client'\n\nimport { Popover } from '@base-ui/react/popover'\nimport type { PopoverTriggerProps } from '@base-ui/react/popover'\nimport { useWidgetContext } from '../lib/widget-context'\n\n// TODO: decide whether to expose the rest of Base UI Trigger props.\nexport type ChimelingTriggerProps = Pick<\n PopoverTriggerProps,\n 'className' | 'style' | 'nativeButton' | 'id'\n>\n\nexport function ChimelingTrigger({ className, style, nativeButton, id }: ChimelingTriggerProps) {\n const { showable, openOnHover, hoverOpenDelay, hoverCloseDelay } = useWidgetContext()\n\n if (!showable) {\n return null\n }\n\n return (\n <Popover.Trigger\n className={className}\n style={style}\n nativeButton={nativeButton}\n id={id}\n openOnHover={openOnHover}\n delay={hoverOpenDelay}\n closeDelay={hoverCloseDelay}\n >\n {showable.activity.gerund}\n </Popover.Trigger>\n )\n}\n"],"mappings":";;;;;AAYA,SAAgB,iBAAiB,EAAE,WAAW,OAAO,cAAc,MAA6B;CAC9F,MAAM,EAAE,UAAU,aAAa,gBAAgB,oBAAoB,iBAAiB;CAEpF,IAAI,CAAC,UACH,OAAO;CAGT,OACE,oBAAC,QAAQ,SAAT;EACa;EACJ;EACO;EACV;EACS;EACb,OAAO;EACP,YAAY;EAEX,UAAA,SAAS,SAAS;CACJ,CAAA;AAErB"}
1
+ {"version":3,"file":"trigger.js","names":[],"sources":["../../src/components/trigger.tsx"],"sourcesContent":["'use client'\n\nimport { ClassNames, keyframes } from '@emotion/react'\nimport { Popover } from '@base-ui/react/popover'\nimport type { PopoverTriggerProps } from '@base-ui/react/popover'\nimport { useWidgetContext } from '../lib/widget-context'\n\nconst shimmerAnimation = keyframes({\n from: { backgroundPosition: '200% 0' },\n to: { backgroundPosition: '-200% 0' },\n})\n\nconst triggerReset = {\n border: 'none',\n outline: 'none',\n margin: 0,\n padding: 0,\n backgroundColor: 'unset',\n fontWeight: 450,\n} as const\n\nexport type ChimelingTriggerProps = Pick<PopoverTriggerProps, 'style' | 'nativeButton' | 'id'> & {\n className?: string\n variant?: 'inline' | 'pill'\n shimmer?: boolean\n gradient?: boolean\n}\n\nexport const DEFAULT_TRIGGER = {\n variant: 'inline',\n shimmer: true,\n gradient: true,\n} as const\n\nexport function ChimelingTrigger({\n className,\n style,\n nativeButton,\n id,\n variant = DEFAULT_TRIGGER.variant,\n shimmer = DEFAULT_TRIGGER.shimmer,\n gradient = DEFAULT_TRIGGER.gradient,\n}: ChimelingTriggerProps) {\n const { showable, openOnHover, hoverOpenDelay, hoverCloseDelay } = useWidgetContext()\n\n if (!showable) {\n return null\n }\n\n return (\n <ClassNames>\n {({ css, cx }) => (\n <Popover.Trigger\n className={cx(\n 'chl-trigger',\n css({\n ...triggerReset,\n '&[data-variant=\"inline\"]': {\n display: 'inline',\n fontSize: 'inherit',\n ...(shimmer\n ? {\n backgroundImage: `linear-gradient(to right, var(--chl-color-background-accent) 0%, color-mix(in oklch, var(--chl-color-background-accent) 60%, #fff) 50%, var(--chl-color-background-accent) 100%)`,\n backgroundSize: '200% 100%',\n backgroundClip: 'text',\n WebkitBackgroundClip: 'text',\n color: 'transparent',\n animation: `${shimmerAnimation} 4s linear infinite`,\n '@media (prefers-reduced-motion: reduce)': {\n animation: 'none',\n },\n '&:hover, &:focus-visible': {\n backgroundImage: `linear-gradient(to right, var(--chl-color-background-accent-focus) 0%, color-mix(in oklch, var(--chl-color-background-accent-focus) 60%, #fff) 50%, var(--chl-color-background-accent-focus) 100%)`,\n },\n '&:active': {\n backgroundImage: `linear-gradient(to right, var(--chl-color-background-accent-active) 0%, color-mix(in oklch, var(--chl-color-background-accent-active) 60%, #fff) 50%, var(--chl-color-background-accent-active) 100%)`,\n },\n }\n : {\n color: 'var(--chl-color-background-accent)',\n '&:hover, &:focus-visible': {\n color: 'var(--chl-color-background-accent-focus)',\n },\n '&:active': {\n color: 'var(--chl-color-background-accent-active)',\n },\n }),\n },\n '&[data-variant=\"pill\"]': {\n display: 'block',\n padding: 'var(--chl-spacing-2xs) var(--chl-spacing-xs)',\n borderRadius: 'var(--chl-border-radius-full)',\n fontSize: 'var(--chl-font-size-sm)',\n color: 'var(--chl-color-background-accent-contrast)',\n backgroundImage: gradient\n ? `linear-gradient(to bottom, color-mix(in oklch, var(--chl-color-background-accent) 80%, #fff), var(--chl-color-background-accent))`\n : undefined,\n backgroundColor: gradient ? undefined : 'var(--chl-color-background-accent)',\n '&::first-letter': {\n textTransform: 'uppercase',\n },\n '&:hover, &:focus-visible': {\n color: 'var(--chl-color-background-accent-contrast-focus)',\n backgroundImage: gradient\n ? `linear-gradient(to bottom, color-mix(in oklch, var(--chl-color-background-accent-focus) 80%, #fff), var(--chl-color-background-accent-focus))`\n : undefined,\n backgroundColor: gradient\n ? undefined\n : 'var(--chl-color-background-accent-focus)',\n },\n '&:active': {\n color: 'var(--chl-color-background-accent-contrast-active)',\n backgroundImage: gradient\n ? `linear-gradient(to bottom, color-mix(in oklch, var(--chl-color-background-accent-active) 80%, #fff), var(--chl-color-background-accent-active))`\n : undefined,\n backgroundColor: gradient\n ? undefined\n : 'var(--chl-color-background-accent-active)',\n },\n },\n }),\n className,\n )}\n style={style}\n nativeButton={nativeButton}\n id={id}\n data-variant={variant}\n data-shimmer={shimmer ? 'true' : 'false'}\n data-gradient={gradient ? 'true' : 'false'}\n openOnHover={openOnHover}\n delay={hoverOpenDelay}\n closeDelay={hoverCloseDelay}\n >\n {showable.activity.gerund}\n </Popover.Trigger>\n )}\n </ClassNames>\n )\n}\n"],"mappings":";;;;;;AAOA,MAAM,mBAAmB,UAAU;CACjC,MAAM,EAAE,oBAAoB,SAAS;CACrC,IAAI,EAAE,oBAAoB,UAAU;AACtC,CAAC;AAED,MAAM,eAAe;CACnB,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,SAAS;CACT,iBAAiB;CACjB,YAAY;AACd;AASA,MAAa,kBAAkB;CAC7B,SAAS;CACT,SAAS;CACT,UAAU;AACZ;AAEA,SAAgB,iBAAiB,EAC/B,WACA,OACA,cACA,IACA,UAAU,gBAAgB,SAC1B,UAAU,gBAAgB,SAC1B,WAAW,gBAAgB,YACH;CACxB,MAAM,EAAE,UAAU,aAAa,gBAAgB,oBAAoB,iBAAiB;CAEpF,IAAI,CAAC,UACH,OAAO;CAGT,OACE,oBAAC,YAAD,EAAA,WACI,EAAE,KAAK,SACP,oBAAC,QAAQ,SAAT;EACE,WAAW,GACT,eACA,IAAI;GACF,GAAG;GACH,8BAA4B;IAC1B,SAAS;IACT,UAAU;IACV,GAAI,UACA;KACE,iBAAiB;KACjB,gBAAgB;KAChB,gBAAgB;KAChB,sBAAsB;KACtB,OAAO;KACP,WAAW,GAAG,iBAAiB;KAC/B,2CAA2C,EACzC,WAAW,OACb;KACA,4BAA4B,EAC1B,iBAAiB,qMACnB;KACA,YAAY,EACV,iBAAiB,wMACnB;IACF,IACA;KACE,OAAO;KACP,4BAA4B,EAC1B,OAAO,2CACT;KACA,YAAY,EACV,OAAO,4CACT;IACF;GACN;GACA,4BAA0B;IACxB,SAAS;IACT,SAAS;IACT,cAAc;IACd,UAAU;IACV,OAAO;IACP,iBAAiB,WACb,sIACA,KAAA;IACJ,iBAAiB,WAAW,KAAA,IAAY;IACxC,mBAAmB,EACjB,eAAe,YACjB;IACA,4BAA4B;KAC1B,OAAO;KACP,iBAAiB,WACb,kJACA,KAAA;KACJ,iBAAiB,WACb,KAAA,IACA;IACN;IACA,YAAY;KACV,OAAO;KACP,iBAAiB,WACb,oJACA,KAAA;KACJ,iBAAiB,WACb,KAAA,IACA;IACN;GACF;EACF,CAAC,GACD,SACF;EACO;EACO;EACV;EACJ,gBAAc;EACd,gBAAc,UAAU,SAAS;EACjC,iBAAe,WAAW,SAAS;EACtB;EACb,OAAO;EACP,YAAY;EAEX,UAAA,SAAS,SAAS;CACJ,CAAA,EAET,CAAA;AAEhB"}
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import { ChimelingRoot, ChimelingRootProps } from "./components/root.js";
4
4
  import { ChimelingTrigger, ChimelingTriggerProps } from "./components/trigger.js";
5
5
  import { ChimelingPopover, ChimelingPopoverProps } from "./components/popover.js";
6
6
  import { Chimeling } from "./components/chimeling.js";
7
- import { ChimelingPlayground } from "./components/playground/playground.js";
7
+ import { ChimelingPlayground, ChimelingPlaygroundProps } from "./components/playground/playground.js";
8
8
  import "./components/index.js";
9
9
  import { useChimelingClient } from "./hooks/use-client.js";
10
10
  import { useResolvedUserPresence } from "./hooks/use-resolved-user-presence.js";
@@ -12,4 +12,4 @@ import "./hooks/index.js";
12
12
  import { formatActivityDuration } from "./lib/format-activity-duration.js";
13
13
  import { iconImageUrl } from "./lib/icon-url.js";
14
14
  import "./lib/index.js";
15
- export { Chimeling, ChimelingPlayground, ChimelingPopover, type ChimelingPopoverProps, ChimelingProvider, type ChimelingProviderProps, ChimelingRoot, type ChimelingRootProps, ChimelingTrigger, type ChimelingTriggerProps, type PresenceActivity, type ShowablePresence, formatActivityDuration, getShowablePresence, iconImageUrl, useChimelingClient, useResolvedUserPresence };
15
+ export { Chimeling, ChimelingPlayground, type ChimelingPlaygroundProps, ChimelingPopover, type ChimelingPopoverProps, ChimelingProvider, type ChimelingProviderProps, ChimelingRoot, type ChimelingRootProps, ChimelingTrigger, type ChimelingTriggerProps, type PresenceActivity, type ShowablePresence, formatActivityDuration, getShowablePresence, iconImageUrl, useChimelingClient, useResolvedUserPresence };
@@ -1,7 +1,9 @@
1
1
  import "./showable-presence.js";
2
2
  import { PopoverPositionerProps } from "@base-ui/react/popover";
3
3
  //#region src/lib/widget-context.d.ts
4
- type WidgetPlacement = Pick<PopoverPositionerProps, 'side' | 'align' | 'sideOffset'>;
4
+ type WidgetPlacement = Pick<PopoverPositionerProps, 'side' | 'align'> & {
5
+ sideOffset?: number;
6
+ };
5
7
  //#endregion
6
8
  export { WidgetPlacement };
7
9
  //# sourceMappingURL=widget-context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"widget-context.js","names":[],"sources":["../../src/lib/widget-context.ts"],"sourcesContent":["'use client'\n\nimport { createContext, useContext } from 'react'\nimport type { PopoverPositionerProps } from '@base-ui/react/popover'\nimport { packageErrorMessage } from './config'\nimport type { ShowablePresence } from './showable-presence'\n\nexport type WidgetPlacement = Pick<PopoverPositionerProps, 'side' | 'align' | 'sideOffset'>\n\nexport type WidgetContextValue = {\n showable: ShowablePresence | null\n now: Date\n poweredBy: boolean\n openOnHover: boolean\n hoverOpenDelay: number\n hoverCloseDelay: number\n placement: WidgetPlacement\n baseUrl: string\n}\n\nexport const WidgetContext = createContext<WidgetContextValue | null>(null)\n\nexport function useWidgetContext(): WidgetContextValue {\n const context = useContext(WidgetContext)\n if (!context) {\n throw new Error(\n packageErrorMessage(\n 'This component can only be used within the <Chimeling.Root /> component.',\n ),\n )\n }\n return context\n}\n"],"mappings":";;;;AAoBA,MAAa,gBAAgB,cAAyC,IAAI;AAE1E,SAAgB,mBAAuC;CACrD,MAAM,UAAU,WAAW,aAAa;CACxC,IAAI,CAAC,SACH,MAAM,IAAI,MACR,oBACE,0EACF,CACF;CAEF,OAAO;AACT"}
1
+ {"version":3,"file":"widget-context.js","names":[],"sources":["../../src/lib/widget-context.ts"],"sourcesContent":["'use client'\n\nimport { createContext, useContext } from 'react'\nimport type { PopoverPositionerProps } from '@base-ui/react/popover'\nimport { packageErrorMessage } from './config'\nimport type { ShowablePresence } from './showable-presence'\n\nexport type WidgetPlacement = Pick<PopoverPositionerProps, 'side' | 'align'> & {\n sideOffset?: number\n}\n\nexport type WidgetContextValue = {\n showable: ShowablePresence | null\n now: Date\n poweredBy: boolean\n openOnHover: boolean\n hoverOpenDelay: number\n hoverCloseDelay: number\n placement: WidgetPlacement\n baseUrl: string\n}\n\nexport const WidgetContext = createContext<WidgetContextValue | null>(null)\n\nexport function useWidgetContext(): WidgetContextValue {\n const context = useContext(WidgetContext)\n if (!context) {\n throw new Error(\n packageErrorMessage(\n 'This component can only be used within the <Chimeling.Root /> component.',\n ),\n )\n }\n return context\n}\n"],"mappings":";;;;AAsBA,MAAa,gBAAgB,cAAyC,IAAI;AAE1E,SAAgB,mBAAuC;CACrD,MAAM,UAAU,WAAW,aAAa;CACxC,IAAI,CAAC,SACH,MAAM,IAAI,MACR,oBACE,0EACF,CACF;CAEF,OAAO;AACT"}
@@ -0,0 +1 @@
1
+ import "@emotion/react";
@@ -0,0 +1,96 @@
1
+ import { packageErrorMessage } from "../lib/config.js";
2
+ import Color from "colorjs.io";
3
+ //#region src/theme/color-system.ts
4
+ function generateContrastColor(source) {
5
+ let color;
6
+ try {
7
+ color = new Color(source);
8
+ } catch (cause) {
9
+ throw new Error(packageErrorMessage(`Invalid accent color: ${JSON.stringify(source)}`), { cause });
10
+ }
11
+ const light = color.mix("oklch(1 0 0)", .95, { space: "oklch" });
12
+ const dark = color.mix("oklch(0 0 0)", .95, { space: "oklch" });
13
+ const lightContrast = color.contrastWCAG21(light);
14
+ const darkContrast = color.contrastWCAG21(dark);
15
+ if (lightContrast >= 4.2) return light.to("oklch").toString();
16
+ if (lightContrast > darkContrast) return light.to("oklch").toString();
17
+ return dark.to("oklch").toString();
18
+ }
19
+ const STATE_LIGHTNESS_DELTAS = {
20
+ background: {
21
+ light: {
22
+ focus: -.02,
23
+ active: -.04,
24
+ selected: -.03
25
+ },
26
+ dark: {
27
+ focus: .05,
28
+ active: .03,
29
+ selected: .04
30
+ }
31
+ },
32
+ text: {
33
+ light: {
34
+ focus: -.25,
35
+ active: .05,
36
+ selected: -.15
37
+ },
38
+ dark: {
39
+ focus: .25,
40
+ active: -.05,
41
+ selected: .15
42
+ }
43
+ }
44
+ };
45
+ function parseColor(value) {
46
+ try {
47
+ return new Color(value);
48
+ } catch {
49
+ const fallback = value.match(/^var\([^,]+,\s*(.+)\)$/)?.[1]?.trim();
50
+ if (!fallback) return;
51
+ try {
52
+ return new Color(fallback);
53
+ } catch {
54
+ return;
55
+ }
56
+ }
57
+ }
58
+ function backgroundScheme(value, scheme) {
59
+ const color = parseColor(value);
60
+ if (!color) return scheme;
61
+ return (color.oklch.l ?? 0) >= .75 ? "light" : "dark";
62
+ }
63
+ function generateStateVariants(name, base, type, variant) {
64
+ const deltas = STATE_LIGHTNESS_DELTAS[type][variant];
65
+ const vars = {};
66
+ for (const [state, delta] of Object.entries(deltas)) vars[`${name}-${state}`] = `oklch(from ${base} calc(l + ${delta}) c h)`;
67
+ return vars;
68
+ }
69
+ function generateColorFamily(type, level, value, contrast = false, scheme = "light") {
70
+ const name = `--chl-color-${type}-${level}`;
71
+ const bgVariant = type === "background" ? backgroundScheme(value, scheme) : scheme;
72
+ const vars = {
73
+ [name]: value,
74
+ ...generateStateVariants(name, `var(${name})`, type, bgVariant)
75
+ };
76
+ if (!contrast) return vars;
77
+ const parsed = parseColor(value);
78
+ const contrastValue = contrast === "auto" ? generateContrastColor(parsed ? parsed.to("oklch").toString() : value) : contrast;
79
+ const contrastName = `${name}-contrast`;
80
+ vars[contrastName] = contrastValue;
81
+ Object.assign(vars, generateStateVariants(contrastName, `var(${contrastName})`, "text", bgVariant));
82
+ return vars;
83
+ }
84
+ function lightDarkFamilies(light, dark) {
85
+ const vars = {};
86
+ for (const key of Object.keys(light)) {
87
+ const lightValue = light[key];
88
+ const darkValue = dark[key];
89
+ vars[key] = lightValue === darkValue ? lightValue : `light-dark(${lightValue}, ${darkValue})`;
90
+ }
91
+ return vars;
92
+ }
93
+ //#endregion
94
+ export { generateColorFamily, generateContrastColor, lightDarkFamilies };
95
+
96
+ //# sourceMappingURL=color-system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-system.js","names":[],"sources":["../../src/theme/color-system.ts"],"sourcesContent":["import type { CSSObject } from '@emotion/react'\nimport Color from 'colorjs.io'\nimport { packageErrorMessage } from '../lib/config'\n\nexport function generateContrastColor(source: string): string {\n let color: Color\n try {\n color = new Color(source)\n } catch (cause) {\n throw new Error(packageErrorMessage(`Invalid accent color: ${JSON.stringify(source)}`), {\n cause,\n })\n }\n\n const light = color.mix('oklch(1 0 0)', 0.95, { space: 'oklch' })\n const dark = color.mix('oklch(0 0 0)', 0.95, { space: 'oklch' })\n const lightContrast = color.contrastWCAG21(light)\n const darkContrast = color.contrastWCAG21(dark)\n\n if (lightContrast >= 4.2) {\n return light.to('oklch').toString()\n }\n if (lightContrast > darkContrast) {\n return light.to('oklch').toString()\n }\n return dark.to('oklch').toString()\n}\n\nconst STATE_LIGHTNESS_DELTAS = {\n background: {\n light: { focus: -0.02, active: -0.04, selected: -0.03 },\n dark: { focus: 0.05, active: 0.03, selected: 0.04 },\n },\n text: {\n light: { focus: -0.25, active: 0.05, selected: -0.15 },\n dark: { focus: 0.25, active: -0.05, selected: 0.15 },\n },\n} as const\n\ntype ColorType = keyof typeof STATE_LIGHTNESS_DELTAS\ntype Scheme = 'light' | 'dark'\n\nfunction parseColor(value: string): Color | undefined {\n try {\n return new Color(value)\n } catch {\n const fallback = value.match(/^var\\([^,]+,\\s*(.+)\\)$/)?.[1]?.trim()\n if (!fallback) {\n return undefined\n }\n try {\n return new Color(fallback)\n } catch {\n return undefined\n }\n }\n}\n\nfunction backgroundScheme(value: string, scheme: Scheme): Scheme {\n const color = parseColor(value)\n if (!color) {\n return scheme\n }\n return (color.oklch.l ?? 0) >= 0.75 ? 'light' : 'dark'\n}\n\nfunction generateStateVariants(\n name: string,\n base: string,\n type: ColorType,\n variant: Scheme,\n): CSSObject {\n const deltas = STATE_LIGHTNESS_DELTAS[type][variant]\n const vars: CSSObject = {}\n for (const [state, delta] of Object.entries(deltas)) {\n vars[`${name}-${state}`] = `oklch(from ${base} calc(l + ${delta}) c h)`\n }\n return vars\n}\n\nexport function generateColorFamily(\n type: ColorType,\n level: string,\n value: string,\n contrast: false | 'auto' | string = false,\n scheme: Scheme = 'light',\n): CSSObject {\n const name = `--chl-color-${type}-${level}`\n const bgVariant = type === 'background' ? backgroundScheme(value, scheme) : scheme\n const vars: CSSObject = {\n [name]: value,\n ...generateStateVariants(name, `var(${name})`, type, bgVariant),\n }\n\n if (!contrast) {\n return vars\n }\n\n const parsed = parseColor(value)\n const contrastValue =\n contrast === 'auto'\n ? generateContrastColor(parsed ? parsed.to('oklch').toString() : value)\n : contrast\n const contrastName = `${name}-contrast`\n vars[contrastName] = contrastValue\n Object.assign(\n vars,\n generateStateVariants(contrastName, `var(${contrastName})`, 'text', bgVariant),\n )\n\n return vars\n}\n\nexport function lightDarkFamilies(light: CSSObject, dark: CSSObject): CSSObject {\n const vars: CSSObject = {}\n for (const key of Object.keys(light)) {\n const lightValue = light[key]\n const darkValue = dark[key]\n vars[key] = lightValue === darkValue ? lightValue : `light-dark(${lightValue}, ${darkValue})`\n }\n return vars\n}\n"],"mappings":";;;AAIA,SAAgB,sBAAsB,QAAwB;CAC5D,IAAI;CACJ,IAAI;EACF,QAAQ,IAAI,MAAM,MAAM;CAC1B,SAAS,OAAO;EACd,MAAM,IAAI,MAAM,oBAAoB,yBAAyB,KAAK,UAAU,MAAM,GAAG,GAAG,EACtF,MACF,CAAC;CACH;CAEA,MAAM,QAAQ,MAAM,IAAI,gBAAgB,KAAM,EAAE,OAAO,QAAQ,CAAC;CAChE,MAAM,OAAO,MAAM,IAAI,gBAAgB,KAAM,EAAE,OAAO,QAAQ,CAAC;CAC/D,MAAM,gBAAgB,MAAM,eAAe,KAAK;CAChD,MAAM,eAAe,MAAM,eAAe,IAAI;CAE9C,IAAI,iBAAiB,KACnB,OAAO,MAAM,GAAG,OAAO,CAAC,CAAC,SAAS;CAEpC,IAAI,gBAAgB,cAClB,OAAO,MAAM,GAAG,OAAO,CAAC,CAAC,SAAS;CAEpC,OAAO,KAAK,GAAG,OAAO,CAAC,CAAC,SAAS;AACnC;AAEA,MAAM,yBAAyB;CAC7B,YAAY;EACV,OAAO;GAAE,OAAO;GAAO,QAAQ;GAAO,UAAU;EAAM;EACtD,MAAM;GAAE,OAAO;GAAM,QAAQ;GAAM,UAAU;EAAK;CACpD;CACA,MAAM;EACJ,OAAO;GAAE,OAAO;GAAO,QAAQ;GAAM,UAAU;EAAM;EACrD,MAAM;GAAE,OAAO;GAAM,QAAQ;GAAO,UAAU;EAAK;CACrD;AACF;AAKA,SAAS,WAAW,OAAkC;CACpD,IAAI;EACF,OAAO,IAAI,MAAM,KAAK;CACxB,QAAQ;EACN,MAAM,WAAW,MAAM,MAAM,wBAAwB,CAAC,GAAG,EAAE,EAAE,KAAK;EAClE,IAAI,CAAC,UACH;EAEF,IAAI;GACF,OAAO,IAAI,MAAM,QAAQ;EAC3B,QAAQ;GACN;EACF;CACF;AACF;AAEA,SAAS,iBAAiB,OAAe,QAAwB;CAC/D,MAAM,QAAQ,WAAW,KAAK;CAC9B,IAAI,CAAC,OACH,OAAO;CAET,QAAQ,MAAM,MAAM,KAAK,MAAM,MAAO,UAAU;AAClD;AAEA,SAAS,sBACP,MACA,MACA,MACA,SACW;CACX,MAAM,SAAS,uBAAuB,KAAK,CAAC;CAC5C,MAAM,OAAkB,CAAC;CACzB,KAAK,MAAM,CAAC,OAAO,UAAU,OAAO,QAAQ,MAAM,GAChD,KAAK,GAAG,KAAK,GAAG,WAAW,cAAc,KAAK,YAAY,MAAM;CAElE,OAAO;AACT;AAEA,SAAgB,oBACd,MACA,OACA,OACA,WAAoC,OACpC,SAAiB,SACN;CACX,MAAM,OAAO,eAAe,KAAK,GAAG;CACpC,MAAM,YAAY,SAAS,eAAe,iBAAiB,OAAO,MAAM,IAAI;CAC5E,MAAM,OAAkB;GACrB,OAAO;EACR,GAAG,sBAAsB,MAAM,OAAO,KAAK,IAAI,MAAM,SAAS;CAChE;CAEA,IAAI,CAAC,UACH,OAAO;CAGT,MAAM,SAAS,WAAW,KAAK;CAC/B,MAAM,gBACJ,aAAa,SACT,sBAAsB,SAAS,OAAO,GAAG,OAAO,CAAC,CAAC,SAAS,IAAI,KAAK,IACpE;CACN,MAAM,eAAe,GAAG,KAAK;CAC7B,KAAK,gBAAgB;CACrB,OAAO,OACL,MACA,sBAAsB,cAAc,OAAO,aAAa,IAAI,QAAQ,SAAS,CAC/E;CAEA,OAAO;AACT;AAEA,SAAgB,kBAAkB,OAAkB,MAA4B;CAC9E,MAAM,OAAkB,CAAC;CACzB,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,GAAG;EACpC,MAAM,aAAa,MAAM;EACzB,MAAM,YAAY,KAAK;EACvB,KAAK,OAAO,eAAe,YAAY,aAAa,cAAc,WAAW,IAAI,UAAU;CAC7F;CACA,OAAO;AACT"}