@postenbring/hedwig-react 1.5.0 → 2.0.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.
Files changed (71) hide show
  1. package/dist/button/button.d.ts +13 -7
  2. package/dist/button/button.d.ts.map +1 -1
  3. package/dist/button/button.js +5 -3
  4. package/dist/button/button.js.map +1 -1
  5. package/dist/button/button.mjs +1 -1
  6. package/dist/button/index.js +5 -3
  7. package/dist/button/index.js.map +1 -1
  8. package/dist/button/index.mjs +1 -1
  9. package/dist/card/card.d.ts +10 -0
  10. package/dist/card/card.d.ts.map +1 -1
  11. package/dist/card/card.js +6 -2
  12. package/dist/card/card.js.map +1 -1
  13. package/dist/card/card.mjs +1 -1
  14. package/dist/card/index.js +6 -2
  15. package/dist/card/index.js.map +1 -1
  16. package/dist/card/index.mjs +1 -1
  17. package/dist/{chunk-6DWIJEHQ.mjs → chunk-444SCBJD.mjs} +3 -3
  18. package/dist/chunk-444SCBJD.mjs.map +1 -0
  19. package/dist/{chunk-BQR4ZRFT.mjs → chunk-7WHIRDTL.mjs} +2 -2
  20. package/dist/{chunk-6VKQ6IRG.mjs → chunk-GXIKHXWC.mjs} +1 -1
  21. package/dist/chunk-GXIKHXWC.mjs.map +1 -0
  22. package/dist/{chunk-NE6PE5W7.mjs → chunk-LDZIJR2D.mjs} +7 -3
  23. package/dist/chunk-LDZIJR2D.mjs.map +1 -0
  24. package/dist/{chunk-V5X3ZS23.mjs → chunk-OHDHIRAW.mjs} +5 -3
  25. package/dist/chunk-OHDHIRAW.mjs.map +1 -0
  26. package/dist/{chunk-AYCHNAU7.mjs → chunk-TYCGAA35.mjs} +6 -4
  27. package/dist/chunk-TYCGAA35.mjs.map +1 -0
  28. package/dist/footer/footer.js +6 -4
  29. package/dist/footer/footer.js.map +1 -1
  30. package/dist/footer/footer.mjs +2 -2
  31. package/dist/footer/index.js +6 -4
  32. package/dist/footer/index.js.map +1 -1
  33. package/dist/footer/index.mjs +2 -2
  34. package/dist/form/error-summary/error-summary.js +4 -2
  35. package/dist/form/error-summary/error-summary.js.map +1 -1
  36. package/dist/form/error-summary/error-summary.mjs +2 -2
  37. package/dist/form/error-summary/index.js +4 -2
  38. package/dist/form/error-summary/index.js.map +1 -1
  39. package/dist/form/error-summary/index.mjs +2 -2
  40. package/dist/form/index.js +4 -2
  41. package/dist/form/index.js.map +1 -1
  42. package/dist/form/index.mjs +2 -2
  43. package/dist/index.js +19 -11
  44. package/dist/index.js.map +1 -1
  45. package/dist/index.mjs +6 -6
  46. package/dist/link/index.js +4 -2
  47. package/dist/link/index.js.map +1 -1
  48. package/dist/link/index.mjs +1 -1
  49. package/dist/link/link.d.ts +9 -3
  50. package/dist/link/link.d.ts.map +1 -1
  51. package/dist/link/link.js +4 -2
  52. package/dist/link/link.js.map +1 -1
  53. package/dist/link/link.mjs +1 -1
  54. package/dist/modal/index.js.map +1 -1
  55. package/dist/modal/index.mjs +1 -1
  56. package/dist/modal/modal.d.ts +1 -1
  57. package/dist/modal/modal.js.map +1 -1
  58. package/dist/modal/modal.mjs +1 -1
  59. package/package.json +6 -6
  60. package/src/button/button.tsx +19 -10
  61. package/src/card/card.tsx +16 -2
  62. package/src/footer/footer.tsx +1 -1
  63. package/src/link/link.tsx +18 -5
  64. package/src/modal/modal.stories.tsx +1 -1
  65. package/src/modal/modal.tsx +1 -1
  66. package/dist/chunk-6DWIJEHQ.mjs.map +0 -1
  67. package/dist/chunk-6VKQ6IRG.mjs.map +0 -1
  68. package/dist/chunk-AYCHNAU7.mjs.map +0 -1
  69. package/dist/chunk-NE6PE5W7.mjs.map +0 -1
  70. package/dist/chunk-V5X3ZS23.mjs.map +0 -1
  71. /package/dist/{chunk-BQR4ZRFT.mjs.map → chunk-7WHIRDTL.mjs.map} +0 -0
package/dist/index.mjs CHANGED
@@ -67,7 +67,7 @@ import {
67
67
  ModalContent,
68
68
  ModalFooter,
69
69
  ModalHeader
70
- } from "./chunk-6VKQ6IRG.mjs";
70
+ } from "./chunk-GXIKHXWC.mjs";
71
71
  import "./chunk-HQVL3ZJ2.mjs";
72
72
  import "./chunk-IJSEJZ3W.mjs";
73
73
  import "./chunk-AGZHQDCQ.mjs";
@@ -89,7 +89,7 @@ import {
89
89
  import "./chunk-KPPLVGZ3.mjs";
90
90
  import {
91
91
  ErrorSummary
92
- } from "./chunk-BQR4ZRFT.mjs";
92
+ } from "./chunk-7WHIRDTL.mjs";
93
93
  import "./chunk-CKAL5ZJZ.mjs";
94
94
  import "./chunk-7LPYJC6S.mjs";
95
95
  import {
@@ -155,7 +155,7 @@ import "./chunk-NE6W2PCD.mjs";
155
155
  import "./chunk-XLLYMQLW.mjs";
156
156
  import {
157
157
  Link
158
- } from "./chunk-V5X3ZS23.mjs";
158
+ } from "./chunk-OHDHIRAW.mjs";
159
159
  import "./chunk-ARHJZUZG.mjs";
160
160
  import {
161
161
  Card,
@@ -168,7 +168,7 @@ import {
168
168
  CardBodyHeaderTitle,
169
169
  CardMedia,
170
170
  CardMediaImg
171
- } from "./chunk-NE6PE5W7.mjs";
171
+ } from "./chunk-LDZIJR2D.mjs";
172
172
  import "./chunk-2YL2MVWN.mjs";
173
173
  import {
174
174
  DescriptionList
@@ -183,7 +183,7 @@ import {
183
183
  FooterLinkSection,
184
184
  FooterLinkSections,
185
185
  FooterLogo
186
- } from "./chunk-6DWIJEHQ.mjs";
186
+ } from "./chunk-444SCBJD.mjs";
187
187
  import {
188
188
  LinkList
189
189
  } from "./chunk-Z2ZCM4BE.mjs";
@@ -208,7 +208,7 @@ import {
208
208
  } from "./chunk-A42PXOVR.mjs";
209
209
  import {
210
210
  Button
211
- } from "./chunk-AYCHNAU7.mjs";
211
+ } from "./chunk-TYCGAA35.mjs";
212
212
  import "./chunk-ZKMFJZSH.mjs";
213
213
  import {
214
214
  Accordion
@@ -61,7 +61,7 @@ var import_react_slot = require("@radix-ui/react-slot");
61
61
  var import_jsx_runtime = require("react/jsx-runtime");
62
62
  var Link = (0, import_react.forwardRef)(
63
63
  (_a, ref) => {
64
- var _b = _a, { asChild, children, variant = "underline", size = "default", className } = _b, rest = __objRest(_b, ["asChild", "children", "variant", "size", "className"]);
64
+ var _b = _a, { asChild, children, variant = "underline", size = "default", icon, className } = _b, rest = __objRest(_b, ["asChild", "children", "variant", "size", "icon", "className"]);
65
65
  const Component = asChild ? import_react_slot.Slot : "a";
66
66
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
67
67
  Component,
@@ -69,7 +69,9 @@ var Link = (0, import_react.forwardRef)(
69
69
  className: (0, import_typed_classname.clsx)(
70
70
  "hds-link",
71
71
  variant !== "underline" && `hds-link--${variant}`,
72
- size !== "default" && size !== "medium" && `hds-link--${size}`,
72
+ size !== "default" && `hds-link--${size}`,
73
+ { "hds-link--trailing-icon": icon === "trailing" },
74
+ { "hds-link--leading-icon": icon === "leading" },
73
75
  className
74
76
  ),
75
77
  ref
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/link/index.tsx","../../src/link/link.tsx"],"sourcesContent":["export { Link } from \"./link\";\n\nexport type * from \"./link\";\n","import * as React from \"react\";\nimport { clsx } from \"@postenbring/hedwig-css/typed-classname\";\nimport { forwardRef } from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\n\nexport interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n /**\n * The visual style of the link\n */\n variant?: \"underline\" | \"solid\" | \"inverted\" | \"no-underline\";\n\n /**\n * Font size of the link\n *\n * Note: `medium` is deprecated, use `default` instead of `medium`\n */\n size?: \"default\" | \"small\" | \"large\" | \"technical\" | \"medium\";\n\n children: React.ReactNode;\n\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\n\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n ({ asChild, children, variant = \"underline\", size = \"default\", className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"a\";\n return (\n <Component\n className={clsx(\n \"hds-link\",\n variant !== \"underline\" && `hds-link--${variant}`,\n size !== \"default\" && size !== \"medium\" && `hds-link--${size}`,\n className as undefined,\n )}\n ref={ref}\n {...rest}\n >\n {children}\n </Component>\n );\n },\n);\nLink.displayName = \"Link\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,YAAuB;AACvB,6BAAqB;AACrB,mBAA2B;AAC3B,wBAAqB;AA6Bf;AAJC,IAAM,WAAO;AAAA,EAClB,CAAC,IAAoF,QAAQ;AAA5F,iBAAE,WAAS,UAAU,UAAU,aAAa,OAAO,WAAW,UA7BjE,IA6BG,IAA4E,iBAA5E,IAA4E,CAA1E,WAAS,YAAU,WAAuB,QAAkB;AAC7D,UAAM,YAAY,UAAU,yBAAO;AACnC,WACE;AAAA,MAAC;AAAA;AAAA,QACC,eAAW;AAAA,UACT;AAAA,UACA,YAAY,eAAe,aAAa,OAAO;AAAA,UAC/C,SAAS,aAAa,SAAS,YAAY,aAAa,IAAI;AAAA,UAC5D;AAAA,QACF;AAAA,QACA;AAAA,SACI,OARL;AAAA,QAUE;AAAA;AAAA,IACH;AAAA,EAEJ;AACF;AACA,KAAK,cAAc;","names":[]}
1
+ {"version":3,"sources":["../../src/link/index.tsx","../../src/link/link.tsx"],"sourcesContent":["export { Link } from \"./link\";\n\nexport type * from \"./link\";\n","import * as React from \"react\";\nimport { clsx } from \"@postenbring/hedwig-css/typed-classname\";\nimport { forwardRef } from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\n\nexport interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n /**\n * The visual style of the link\n */\n variant?: \"underline\" | \"solid\" | \"inverted\" | \"no-underline\" | \"inverted-no-underline\";\n\n /**\n * Font size of the link\n * @default \"default\"\n */\n size?: \"default\" | \"small\" | \"large\" | \"technical\";\n\n /**\n * Specify that there is an icon in the link.\n * `icon=\"leading\"`: There is an icon before the text.\n * `icon=\"trailing\"`: There is an icon after the text.\n *\n */\n icon?: \"leading\" | \"trailing\";\n\n children: React.ReactNode;\n\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\n\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n (\n { asChild, children, variant = \"underline\", size = \"default\", icon, className, ...rest },\n ref,\n ) => {\n const Component = asChild ? Slot : \"a\";\n\n return (\n <Component\n className={clsx(\n \"hds-link\",\n variant !== \"underline\" && `hds-link--${variant}`,\n size !== \"default\" && `hds-link--${size}`,\n { \"hds-link--trailing-icon\": icon === \"trailing\" },\n { \"hds-link--leading-icon\": icon === \"leading\" },\n className as undefined,\n )}\n ref={ref}\n {...rest}\n >\n {children}\n </Component>\n );\n },\n);\nLink.displayName = \"Link\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,YAAuB;AACvB,6BAAqB;AACrB,mBAA2B;AAC3B,wBAAqB;AAwCf;AARC,IAAM,WAAO;AAAA,EAClB,CACE,IACA,QACG;AAFH,iBAAE,WAAS,UAAU,UAAU,aAAa,OAAO,WAAW,MAAM,UArCxE,IAqCI,IAAkF,iBAAlF,IAAkF,CAAhF,WAAS,YAAU,WAAuB,QAAkB,QAAM;AAGpE,UAAM,YAAY,UAAU,yBAAO;AAEnC,WACE;AAAA,MAAC;AAAA;AAAA,QACC,eAAW;AAAA,UACT;AAAA,UACA,YAAY,eAAe,aAAa,OAAO;AAAA,UAC/C,SAAS,aAAa,aAAa,IAAI;AAAA,UACvC,EAAE,2BAA2B,SAAS,WAAW;AAAA,UACjD,EAAE,0BAA0B,SAAS,UAAU;AAAA,UAC/C;AAAA,QACF;AAAA,QACA;AAAA,SACI,OAVL;AAAA,QAYE;AAAA;AAAA,IACH;AAAA,EAEJ;AACF;AACA,KAAK,cAAc;","names":[]}
@@ -1,7 +1,7 @@
1
1
  import "../chunk-XLLYMQLW.mjs";
2
2
  import {
3
3
  Link
4
- } from "../chunk-V5X3ZS23.mjs";
4
+ } from "../chunk-OHDHIRAW.mjs";
5
5
  import "../chunk-YOSPWY5K.mjs";
6
6
  export {
7
7
  Link
@@ -3,13 +3,19 @@ export interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement>
3
3
  /**
4
4
  * The visual style of the link
5
5
  */
6
- variant?: "underline" | "solid" | "inverted" | "no-underline";
6
+ variant?: "underline" | "solid" | "inverted" | "no-underline" | "inverted-no-underline";
7
7
  /**
8
8
  * Font size of the link
9
+ * @default "default"
10
+ */
11
+ size?: "default" | "small" | "large" | "technical";
12
+ /**
13
+ * Specify that there is an icon in the link.
14
+ * `icon="leading"`: There is an icon before the text.
15
+ * `icon="trailing"`: There is an icon after the text.
9
16
  *
10
- * Note: `medium` is deprecated, use `default` instead of `medium`
11
17
  */
12
- size?: "default" | "small" | "large" | "technical" | "medium";
18
+ icon?: "leading" | "trailing";
13
19
  children: React.ReactNode;
14
20
  /**
15
21
  * Change the default rendered element for the one passed as a child, merging their props and behavior.
@@ -1 +1 @@
1
- {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/link/link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,WAAW,SAAU,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IAC9E;;OAEG;IACH,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,cAAc,CAAC;IAE9D;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,WAAW,GAAG,QAAQ,CAAC;IAE9D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAE1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,IAAI,qFAkBhB,CAAC"}
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/link/link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,WAAW,SAAU,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IAC9E;;OAEG;IACH,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,cAAc,GAAG,uBAAuB,CAAC;IAExF;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,WAAW,CAAC;IAEnD;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IAE9B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAE1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,IAAI,qFAwBhB,CAAC"}
package/dist/link/link.js CHANGED
@@ -59,7 +59,7 @@ var import_react_slot = require("@radix-ui/react-slot");
59
59
  var import_jsx_runtime = require("react/jsx-runtime");
60
60
  var Link = (0, import_react.forwardRef)(
61
61
  (_a, ref) => {
62
- var _b = _a, { asChild, children, variant = "underline", size = "default", className } = _b, rest = __objRest(_b, ["asChild", "children", "variant", "size", "className"]);
62
+ var _b = _a, { asChild, children, variant = "underline", size = "default", icon, className } = _b, rest = __objRest(_b, ["asChild", "children", "variant", "size", "icon", "className"]);
63
63
  const Component = asChild ? import_react_slot.Slot : "a";
64
64
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
65
65
  Component,
@@ -67,7 +67,9 @@ var Link = (0, import_react.forwardRef)(
67
67
  className: (0, import_typed_classname.clsx)(
68
68
  "hds-link",
69
69
  variant !== "underline" && `hds-link--${variant}`,
70
- size !== "default" && size !== "medium" && `hds-link--${size}`,
70
+ size !== "default" && `hds-link--${size}`,
71
+ { "hds-link--trailing-icon": icon === "trailing" },
72
+ { "hds-link--leading-icon": icon === "leading" },
71
73
  className
72
74
  ),
73
75
  ref
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/link/link.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { clsx } from \"@postenbring/hedwig-css/typed-classname\";\nimport { forwardRef } from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\n\nexport interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n /**\n * The visual style of the link\n */\n variant?: \"underline\" | \"solid\" | \"inverted\" | \"no-underline\";\n\n /**\n * Font size of the link\n *\n * Note: `medium` is deprecated, use `default` instead of `medium`\n */\n size?: \"default\" | \"small\" | \"large\" | \"technical\" | \"medium\";\n\n children: React.ReactNode;\n\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\n\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n ({ asChild, children, variant = \"underline\", size = \"default\", className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"a\";\n return (\n <Component\n className={clsx(\n \"hds-link\",\n variant !== \"underline\" && `hds-link--${variant}`,\n size !== \"default\" && size !== \"medium\" && `hds-link--${size}`,\n className as undefined,\n )}\n ref={ref}\n {...rest}\n >\n {children}\n </Component>\n );\n },\n);\nLink.displayName = \"Link\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAAuB;AACvB,6BAAqB;AACrB,mBAA2B;AAC3B,wBAAqB;AA6Bf;AAJC,IAAM,WAAO;AAAA,EAClB,CAAC,IAAoF,QAAQ;AAA5F,iBAAE,WAAS,UAAU,UAAU,aAAa,OAAO,WAAW,UA7BjE,IA6BG,IAA4E,iBAA5E,IAA4E,CAA1E,WAAS,YAAU,WAAuB,QAAkB;AAC7D,UAAM,YAAY,UAAU,yBAAO;AACnC,WACE;AAAA,MAAC;AAAA;AAAA,QACC,eAAW;AAAA,UACT;AAAA,UACA,YAAY,eAAe,aAAa,OAAO;AAAA,UAC/C,SAAS,aAAa,SAAS,YAAY,aAAa,IAAI;AAAA,UAC5D;AAAA,QACF;AAAA,QACA;AAAA,SACI,OARL;AAAA,QAUE;AAAA;AAAA,IACH;AAAA,EAEJ;AACF;AACA,KAAK,cAAc;","names":[]}
1
+ {"version":3,"sources":["../../src/link/link.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { clsx } from \"@postenbring/hedwig-css/typed-classname\";\nimport { forwardRef } from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\n\nexport interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n /**\n * The visual style of the link\n */\n variant?: \"underline\" | \"solid\" | \"inverted\" | \"no-underline\" | \"inverted-no-underline\";\n\n /**\n * Font size of the link\n * @default \"default\"\n */\n size?: \"default\" | \"small\" | \"large\" | \"technical\";\n\n /**\n * Specify that there is an icon in the link.\n * `icon=\"leading\"`: There is an icon before the text.\n * `icon=\"trailing\"`: There is an icon after the text.\n *\n */\n icon?: \"leading\" | \"trailing\";\n\n children: React.ReactNode;\n\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\n\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n (\n { asChild, children, variant = \"underline\", size = \"default\", icon, className, ...rest },\n ref,\n ) => {\n const Component = asChild ? Slot : \"a\";\n\n return (\n <Component\n className={clsx(\n \"hds-link\",\n variant !== \"underline\" && `hds-link--${variant}`,\n size !== \"default\" && `hds-link--${size}`,\n { \"hds-link--trailing-icon\": icon === \"trailing\" },\n { \"hds-link--leading-icon\": icon === \"leading\" },\n className as undefined,\n )}\n ref={ref}\n {...rest}\n >\n {children}\n </Component>\n );\n },\n);\nLink.displayName = \"Link\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAAuB;AACvB,6BAAqB;AACrB,mBAA2B;AAC3B,wBAAqB;AAwCf;AARC,IAAM,WAAO;AAAA,EAClB,CACE,IACA,QACG;AAFH,iBAAE,WAAS,UAAU,UAAU,aAAa,OAAO,WAAW,MAAM,UArCxE,IAqCI,IAAkF,iBAAlF,IAAkF,CAAhF,WAAS,YAAU,WAAuB,QAAkB,QAAM;AAGpE,UAAM,YAAY,UAAU,yBAAO;AAEnC,WACE;AAAA,MAAC;AAAA;AAAA,QACC,eAAW;AAAA,UACT;AAAA,UACA,YAAY,eAAe,aAAa,OAAO;AAAA,UAC/C,SAAS,aAAa,aAAa,IAAI;AAAA,UACvC,EAAE,2BAA2B,SAAS,WAAW;AAAA,UACjD,EAAE,0BAA0B,SAAS,UAAU;AAAA,UAC/C;AAAA,QACF;AAAA,QACA;AAAA,SACI,OAVL;AAAA,QAYE;AAAA;AAAA,IACH;AAAA,EAEJ;AACF;AACA,KAAK,cAAc;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Link
3
- } from "../chunk-V5X3ZS23.mjs";
3
+ } from "../chunk-OHDHIRAW.mjs";
4
4
  import "../chunk-YOSPWY5K.mjs";
5
5
  export {
6
6
  Link
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modal/index.tsx","../../src/modal/modal.tsx","../../src/box/box.tsx","../../src/utils/utils.ts"],"sourcesContent":["export { Modal, ModalHeader, ModalContent, ModalFooter } from \"./modal\";\n\nexport type * from \"./modal\";\n","import { forwardRef, useEffect, useRef } from \"react\";\nimport { clsx } from \"@postenbring/hedwig-css/typed-classname\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { Box } from \"../box/box\";\nimport { useMergeRefs } from \"../utils/utils\";\n\ninterface ModalHeaderProps extends React.HTMLAttributes<HTMLHeadingElement> {\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\nexport const ModalHeader = forwardRef<HTMLHeadingElement, ModalHeaderProps>(\n ({ asChild, className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"h1\";\n return (\n <Component\n className={clsx(\"hds-modal__header\", className as undefined)}\n ref={ref}\n {...rest}\n />\n );\n },\n);\nModalHeader.displayName = \"Modal.Header\";\n\ninterface ModalContentProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\nexport const ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(\n ({ asChild, className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"div\";\n return (\n <Component\n className={clsx(\"hds-modal__content\", className as undefined)}\n ref={ref}\n {...rest}\n />\n );\n },\n);\nModalContent.displayName = \"Modal.Content\";\n\ninterface ModalFooterProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\nexport const ModalFooter = forwardRef<HTMLDivElement, ModalFooterProps>(\n ({ asChild, className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"footer\";\n return (\n <Component\n className={clsx(\"hds-modal__footer\", className as undefined)}\n ref={ref}\n {...rest}\n />\n );\n },\n);\nModalFooter.displayName = \"Modal.Footer\";\n\nexport interface ModalProps extends React.HTMLAttributes<HTMLDialogElement> {\n children: React.ReactNode;\n\n /**\n * Controls the open state of the modal\n */\n open?: boolean;\n\n /**\n * Whether to close when clicking on the backdrop.\n */\n closeOnBackdropClick?: boolean;\n}\n\n/**\n * A modal dialog is a window that forces the user to interact with it before they can return to other parts of the application.\n *\n * Uses the native [`dialog`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog) element.\n *\n * @example\n * ```tsx\n * const modalRef = useRef<HTMLDialogElement>(null);\n * const onClose = () => modalRef.current?.close();\n *\n * return (\n * <>\n * <Button onClick={() => modalRef.current?.showModal()}>Open Modal</Button>\n * <Modal ref={modalRef}>\n * <Modal.Header>Dialog header</Modal.Header>\n * <Modal.Content>\n * <p>\n * Dialog header Dialog description - a description of what is about to happen and maybe\n * something about the consequences.\n * </p>\n * </Modal.Content>\n * <Modal.Footer>\n * <HStack gap=\"16\" wrap>\n * <Button onClick={onMainAction}>Main action</Button>\n * <Button variant=\"primary-outline\" onClick={onClose}>\n * Cancel\n * </Button>\n * </HStack>\n * </Modal.Footer>\n * </Modal>\n * </>\n * );\n * ```\n */\nexport const Modal = forwardRef<HTMLDialogElement, ModalProps>(\n ({ children, className, open, closeOnBackdropClick, onClick, ...rest }, ref) => {\n const modalRef = useRef<HTMLDialogElement>(null);\n const mergedRef = useMergeRefs([modalRef, ref]);\n\n // The X close button that comes from the `Box` component\n function onCloseButtonClick() {\n modalRef.current?.close();\n return false;\n }\n\n // No scroll when modal is open\n useScrollLock(modalRef, \"hds-modal-scroll-lock\");\n\n // `open` prop\n useEffect(() => {\n if (modalRef.current && open !== undefined) {\n if (open && !modalRef.current.open) {\n modalRef.current.showModal();\n } else if (!open && modalRef.current.open) {\n modalRef.current.close();\n }\n }\n }, [modalRef, open]);\n\n function onDialogClick(e: React.MouseEvent<HTMLElement>) {\n if (closeOnBackdropClick && e.target === modalRef.current) {\n modalRef.current.close();\n }\n onClick?.(e as React.MouseEvent<HTMLDialogElement>);\n }\n\n return (\n <Box\n asChild\n className={clsx(\"hds-modal\", className as undefined)}\n closeable\n onClick={onDialogClick}\n onClose={onCloseButtonClick}\n variant=\"white\"\n >\n <dialog ref={mergedRef} {...rest}>\n {children}\n </dialog>\n </Box>\n );\n },\n) as ModalType;\nModal.displayName = \"Modal\";\n\ntype ModalType = ReturnType<typeof forwardRef<HTMLDialogElement, ModalProps>> & {\n Header: typeof ModalHeader;\n Content: typeof ModalContent;\n Footer: typeof ModalFooter;\n};\n\nModal.Header = ModalHeader;\nModal.Content = ModalContent;\nModal.Footer = ModalFooter;\n\nfunction useScrollLock(modalRef: React.RefObject<HTMLDialogElement>, bodyClass: string) {\n useEffect(() => {\n if (!modalRef.current) return;\n if (modalRef.current.open) document.body.classList.add(bodyClass);\n\n const observer = new MutationObserver(() => {\n if (modalRef.current?.open) document.body.classList.add(bodyClass);\n else document.body.classList.remove(bodyClass);\n });\n observer.observe(modalRef.current, {\n attributes: true,\n attributeFilter: [\"open\"],\n });\n return () => {\n observer.disconnect();\n document.body.classList.remove(bodyClass);\n };\n }, [bodyClass, modalRef]);\n}\n","import { forwardRef, useCallback, useState } from \"react\";\nimport { clsx } from \"@postenbring/hedwig-css/typed-classname\";\nimport { Slot, Slottable } from \"@radix-ui/react-slot\";\n\nexport type BoxCloseButtonProps = Omit<React.HTMLAttributes<HTMLButtonElement>, \"children\">;\nexport const BoxCloseButton = forwardRef<HTMLButtonElement, BoxCloseButtonProps>(\n ({ className, ...rest }, ref) => {\n return (\n <button\n className={clsx(\"hds-box__close-button\", className as undefined)}\n ref={ref}\n type=\"button\"\n {...rest}\n />\n );\n },\n);\nBoxCloseButton.displayName = \"Box.CloseButton\";\n\nexport interface BoxProps extends React.HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode;\n\n /**\n * Color variant of the box\n *\n * @default \"light-grey\"\n */\n variant?: \"light-grey\" | \"lighter\" | \"white\" | \"warning\";\n\n /**\n * If `true`, a close button will be shown.\n * Use when you want to control the close button using the BoxCloseButton component.\n *\n * @default false\n */\n closeable?: boolean;\n\n /**\n * Callback fired when the component requests to be closed.\n * If not set, the component will be closed without any user interaction.\n *\n * If set, and the handler returns non-true value, the component will not be closed.\n * Use this if you want to control the closing of the component, using the `closed` prop\n *\n * If set, and the handler returns the true, the component will be closed.\n * Use this with `window.confirm()` to ask the user to confirm closing the component.\n */\n // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents -- It's fine, I want to have the boolean in the type\n onClose?: () => boolean | unknown;\n\n /**\n * If `true`, the box will be closed and hidden from view\n */\n closed?: boolean;\n\n /**\n * Props applied to the close button element.\n */\n closeButtonProps?: BoxCloseButtonProps;\n\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\n\nexport const Box = forwardRef<HTMLDivElement, BoxProps>(\n (\n {\n asChild,\n variant,\n closeable = false,\n onClose: onCloseProp,\n closed: closedProp,\n closeButtonProps,\n children,\n className,\n ...rest\n },\n ref,\n ) => {\n const [closedState, setClosedState] = useState(false);\n const onClose = useCallback(() => {\n if (onCloseProp) {\n const result = onCloseProp();\n if (result === true) {\n setClosedState(true);\n }\n } else {\n setClosedState(true);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- I know better\n }, []);\n const closed = closedProp ?? closedState;\n const Component = asChild ? Slot : \"div\";\n\n return (\n <Component\n className={clsx(\n \"hds-box\",\n variant && `hds-box--${variant}`,\n { \"hds-box--closed\": closed },\n className as undefined,\n )}\n ref={ref}\n {...rest}\n >\n {closeable ? <BoxCloseButton onClick={onClose} {...closeButtonProps} /> : null}\n <Slottable>{children}</Slottable>\n </Component>\n );\n },\n) as BoxType;\nBox.displayName = \"Box\";\n\nBox.CloseButton = BoxCloseButton;\n\ntype BoxType = ReturnType<typeof forwardRef<HTMLDivElement, BoxProps>> & {\n CloseButton: typeof BoxCloseButton;\n};\n","import * as React from \"react\";\nimport { useCallback, useEffect, useState } from \"react\";\n\n/**\n * Merges an array of refs into a single memoized callback ref or `null`.\n * @see https://floating-ui.com/docs/useMergeRefs\n */\nexport function useMergeRefs<Instance>(\n refs: (React.Ref<Instance> | undefined)[],\n): React.RefCallback<Instance> | null {\n return React.useMemo(() => {\n if (refs.every((ref) => ref === null)) {\n return null;\n }\n\n return (value) => {\n refs.forEach((ref) => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref !== null) {\n (ref as React.MutableRefObject<Instance | null>).current = value;\n }\n });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- It's ok\n }, refs);\n}\n\nexport function useResize<Instance extends HTMLElement>(\n ref: React.RefObject<Instance> | undefined | null,\n): { width: number; height: number } {\n const [width, setWidth] = useState<number>(0);\n const [height, setHeight] = useState<number>(0);\n const handleResize = useCallback(() => {\n if (ref?.current !== null) {\n setWidth(ref?.current?.offsetWidth ?? 0);\n setHeight(ref?.current?.offsetHeight ?? 0);\n }\n }, [ref]);\n useEffect(() => {\n window.addEventListener(\"load\", handleResize);\n window.addEventListener(\"resize\", handleResize);\n return () => {\n window.removeEventListener(\"load\", handleResize);\n window.removeEventListener(\"resize\", handleResize);\n };\n }, [ref, handleResize]);\n useEffect(() => {\n handleResize();\n // eslint-disable-next-line react-hooks/exhaustive-deps -- It's ok\n }, []);\n return { width, height };\n}\n\nfunction subscribe() {\n // eslint-disable-next-line @typescript-eslint/no-empty-function -- It's ok\n return () => {};\n}\n\nexport function useHydrated() {\n return React.useSyncExternalStore(\n subscribe,\n () => true,\n () => false,\n );\n}\n\n/**\n * Trap focus inside an element using the `inert` attribute.\n *\n * Adds `inert` to all siblings of the given element, and all their ancestors up to the body.\n * Returns a cleanup function which removes the `inert` property from the elements, effectively giving focus back to rest of the document.\n *\n * NOTE: Does not support portals, i.e. elements outside the DOM hierarchy of the given element.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/inert\n * @see https://web.dev/articles/inert\n */\nexport function focusTrap(element: HTMLElement) {\n // eslint-disable-next-line @typescript-eslint/no-empty-function -- NOP on focus trapping the body element\n if (element === document.body) return () => {};\n\n let inertElements: HTMLElement[] = [];\n for (let el: HTMLElement | null = element; el; el = el.parentElement) {\n if (el === document.body) break;\n\n for (const sibling of el.parentElement?.children ?? []) {\n if (sibling === el) continue;\n if (!(sibling instanceof HTMLElement)) continue;\n if (sibling.hasAttribute(\"inert\")) continue;\n\n sibling.setAttribute(\"inert\", \"true\");\n inertElements.push(sibling);\n }\n }\n\n return () => {\n releaseFocusTrap(inertElements);\n inertElements = [];\n };\n}\n\n/**\n * Unset the `inert` attribute on all elements given\n */\nfunction releaseFocusTrap(inertElements: Iterable<HTMLElement>) {\n for (const el of inertElements) {\n el.removeAttribute(\"inert\");\n }\n}\n"],"mappings":"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","names":["import_react","import_typed_classname","import_react_slot","import_react","import_jsx_runtime","_a"]}
1
+ {"version":3,"sources":["../../src/modal/index.tsx","../../src/modal/modal.tsx","../../src/box/box.tsx","../../src/utils/utils.ts"],"sourcesContent":["export { Modal, ModalHeader, ModalContent, ModalFooter } from \"./modal\";\n\nexport type * from \"./modal\";\n","import { forwardRef, useEffect, useRef } from \"react\";\nimport { clsx } from \"@postenbring/hedwig-css/typed-classname\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { Box } from \"../box/box\";\nimport { useMergeRefs } from \"../utils/utils\";\n\ninterface ModalHeaderProps extends React.HTMLAttributes<HTMLHeadingElement> {\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\nexport const ModalHeader = forwardRef<HTMLHeadingElement, ModalHeaderProps>(\n ({ asChild, className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"h1\";\n return (\n <Component\n className={clsx(\"hds-modal__header\", className as undefined)}\n ref={ref}\n {...rest}\n />\n );\n },\n);\nModalHeader.displayName = \"Modal.Header\";\n\ninterface ModalContentProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\nexport const ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(\n ({ asChild, className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"div\";\n return (\n <Component\n className={clsx(\"hds-modal__content\", className as undefined)}\n ref={ref}\n {...rest}\n />\n );\n },\n);\nModalContent.displayName = \"Modal.Content\";\n\ninterface ModalFooterProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\nexport const ModalFooter = forwardRef<HTMLDivElement, ModalFooterProps>(\n ({ asChild, className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"footer\";\n return (\n <Component\n className={clsx(\"hds-modal__footer\", className as undefined)}\n ref={ref}\n {...rest}\n />\n );\n },\n);\nModalFooter.displayName = \"Modal.Footer\";\n\nexport interface ModalProps extends React.HTMLAttributes<HTMLDialogElement> {\n children: React.ReactNode;\n\n /**\n * Controls the open state of the modal\n */\n open?: boolean;\n\n /**\n * Whether to close when clicking on the backdrop.\n */\n closeOnBackdropClick?: boolean;\n}\n\n/**\n * A modal dialog is a window that forces the user to interact with it before they can return to other parts of the application.\n *\n * Uses the native [`dialog`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog) element.\n *\n * @example\n * ```tsx\n * const modalRef = useRef<HTMLDialogElement>(null);\n * const onClose = () => modalRef.current?.close();\n *\n * return (\n * <>\n * <Button onClick={() => modalRef.current?.showModal()}>Open Modal</Button>\n * <Modal ref={modalRef}>\n * <Modal.Header>Dialog header</Modal.Header>\n * <Modal.Content>\n * <p>\n * Dialog header Dialog description - a description of what is about to happen and maybe\n * something about the consequences.\n * </p>\n * </Modal.Content>\n * <Modal.Footer>\n * <HStack gap=\"16\" wrap>\n * <Button onClick={onMainAction}>Main action</Button>\n * <Button variant=\"secondary\" onClick={onClose}>\n * Cancel\n * </Button>\n * </HStack>\n * </Modal.Footer>\n * </Modal>\n * </>\n * );\n * ```\n */\nexport const Modal = forwardRef<HTMLDialogElement, ModalProps>(\n ({ children, className, open, closeOnBackdropClick, onClick, ...rest }, ref) => {\n const modalRef = useRef<HTMLDialogElement>(null);\n const mergedRef = useMergeRefs([modalRef, ref]);\n\n // The X close button that comes from the `Box` component\n function onCloseButtonClick() {\n modalRef.current?.close();\n return false;\n }\n\n // No scroll when modal is open\n useScrollLock(modalRef, \"hds-modal-scroll-lock\");\n\n // `open` prop\n useEffect(() => {\n if (modalRef.current && open !== undefined) {\n if (open && !modalRef.current.open) {\n modalRef.current.showModal();\n } else if (!open && modalRef.current.open) {\n modalRef.current.close();\n }\n }\n }, [modalRef, open]);\n\n function onDialogClick(e: React.MouseEvent<HTMLElement>) {\n if (closeOnBackdropClick && e.target === modalRef.current) {\n modalRef.current.close();\n }\n onClick?.(e as React.MouseEvent<HTMLDialogElement>);\n }\n\n return (\n <Box\n asChild\n className={clsx(\"hds-modal\", className as undefined)}\n closeable\n onClick={onDialogClick}\n onClose={onCloseButtonClick}\n variant=\"white\"\n >\n <dialog ref={mergedRef} {...rest}>\n {children}\n </dialog>\n </Box>\n );\n },\n) as ModalType;\nModal.displayName = \"Modal\";\n\ntype ModalType = ReturnType<typeof forwardRef<HTMLDialogElement, ModalProps>> & {\n Header: typeof ModalHeader;\n Content: typeof ModalContent;\n Footer: typeof ModalFooter;\n};\n\nModal.Header = ModalHeader;\nModal.Content = ModalContent;\nModal.Footer = ModalFooter;\n\nfunction useScrollLock(modalRef: React.RefObject<HTMLDialogElement>, bodyClass: string) {\n useEffect(() => {\n if (!modalRef.current) return;\n if (modalRef.current.open) document.body.classList.add(bodyClass);\n\n const observer = new MutationObserver(() => {\n if (modalRef.current?.open) document.body.classList.add(bodyClass);\n else document.body.classList.remove(bodyClass);\n });\n observer.observe(modalRef.current, {\n attributes: true,\n attributeFilter: [\"open\"],\n });\n return () => {\n observer.disconnect();\n document.body.classList.remove(bodyClass);\n };\n }, [bodyClass, modalRef]);\n}\n","import { forwardRef, useCallback, useState } from \"react\";\nimport { clsx } from \"@postenbring/hedwig-css/typed-classname\";\nimport { Slot, Slottable } from \"@radix-ui/react-slot\";\n\nexport type BoxCloseButtonProps = Omit<React.HTMLAttributes<HTMLButtonElement>, \"children\">;\nexport const BoxCloseButton = forwardRef<HTMLButtonElement, BoxCloseButtonProps>(\n ({ className, ...rest }, ref) => {\n return (\n <button\n className={clsx(\"hds-box__close-button\", className as undefined)}\n ref={ref}\n type=\"button\"\n {...rest}\n />\n );\n },\n);\nBoxCloseButton.displayName = \"Box.CloseButton\";\n\nexport interface BoxProps extends React.HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode;\n\n /**\n * Color variant of the box\n *\n * @default \"light-grey\"\n */\n variant?: \"light-grey\" | \"lighter\" | \"white\" | \"warning\";\n\n /**\n * If `true`, a close button will be shown.\n * Use when you want to control the close button using the BoxCloseButton component.\n *\n * @default false\n */\n closeable?: boolean;\n\n /**\n * Callback fired when the component requests to be closed.\n * If not set, the component will be closed without any user interaction.\n *\n * If set, and the handler returns non-true value, the component will not be closed.\n * Use this if you want to control the closing of the component, using the `closed` prop\n *\n * If set, and the handler returns the true, the component will be closed.\n * Use this with `window.confirm()` to ask the user to confirm closing the component.\n */\n // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents -- It's fine, I want to have the boolean in the type\n onClose?: () => boolean | unknown;\n\n /**\n * If `true`, the box will be closed and hidden from view\n */\n closed?: boolean;\n\n /**\n * Props applied to the close button element.\n */\n closeButtonProps?: BoxCloseButtonProps;\n\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\n\nexport const Box = forwardRef<HTMLDivElement, BoxProps>(\n (\n {\n asChild,\n variant,\n closeable = false,\n onClose: onCloseProp,\n closed: closedProp,\n closeButtonProps,\n children,\n className,\n ...rest\n },\n ref,\n ) => {\n const [closedState, setClosedState] = useState(false);\n const onClose = useCallback(() => {\n if (onCloseProp) {\n const result = onCloseProp();\n if (result === true) {\n setClosedState(true);\n }\n } else {\n setClosedState(true);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- I know better\n }, []);\n const closed = closedProp ?? closedState;\n const Component = asChild ? Slot : \"div\";\n\n return (\n <Component\n className={clsx(\n \"hds-box\",\n variant && `hds-box--${variant}`,\n { \"hds-box--closed\": closed },\n className as undefined,\n )}\n ref={ref}\n {...rest}\n >\n {closeable ? <BoxCloseButton onClick={onClose} {...closeButtonProps} /> : null}\n <Slottable>{children}</Slottable>\n </Component>\n );\n },\n) as BoxType;\nBox.displayName = \"Box\";\n\nBox.CloseButton = BoxCloseButton;\n\ntype BoxType = ReturnType<typeof forwardRef<HTMLDivElement, BoxProps>> & {\n CloseButton: typeof BoxCloseButton;\n};\n","import * as React from \"react\";\nimport { useCallback, useEffect, useState } from \"react\";\n\n/**\n * Merges an array of refs into a single memoized callback ref or `null`.\n * @see https://floating-ui.com/docs/useMergeRefs\n */\nexport function useMergeRefs<Instance>(\n refs: (React.Ref<Instance> | undefined)[],\n): React.RefCallback<Instance> | null {\n return React.useMemo(() => {\n if (refs.every((ref) => ref === null)) {\n return null;\n }\n\n return (value) => {\n refs.forEach((ref) => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref !== null) {\n (ref as React.MutableRefObject<Instance | null>).current = value;\n }\n });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- It's ok\n }, refs);\n}\n\nexport function useResize<Instance extends HTMLElement>(\n ref: React.RefObject<Instance> | undefined | null,\n): { width: number; height: number } {\n const [width, setWidth] = useState<number>(0);\n const [height, setHeight] = useState<number>(0);\n const handleResize = useCallback(() => {\n if (ref?.current !== null) {\n setWidth(ref?.current?.offsetWidth ?? 0);\n setHeight(ref?.current?.offsetHeight ?? 0);\n }\n }, [ref]);\n useEffect(() => {\n window.addEventListener(\"load\", handleResize);\n window.addEventListener(\"resize\", handleResize);\n return () => {\n window.removeEventListener(\"load\", handleResize);\n window.removeEventListener(\"resize\", handleResize);\n };\n }, [ref, handleResize]);\n useEffect(() => {\n handleResize();\n // eslint-disable-next-line react-hooks/exhaustive-deps -- It's ok\n }, []);\n return { width, height };\n}\n\nfunction subscribe() {\n // eslint-disable-next-line @typescript-eslint/no-empty-function -- It's ok\n return () => {};\n}\n\nexport function useHydrated() {\n return React.useSyncExternalStore(\n subscribe,\n () => true,\n () => false,\n );\n}\n\n/**\n * Trap focus inside an element using the `inert` attribute.\n *\n * Adds `inert` to all siblings of the given element, and all their ancestors up to the body.\n * Returns a cleanup function which removes the `inert` property from the elements, effectively giving focus back to rest of the document.\n *\n * NOTE: Does not support portals, i.e. elements outside the DOM hierarchy of the given element.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/inert\n * @see https://web.dev/articles/inert\n */\nexport function focusTrap(element: HTMLElement) {\n // eslint-disable-next-line @typescript-eslint/no-empty-function -- NOP on focus trapping the body element\n if (element === document.body) return () => {};\n\n let inertElements: HTMLElement[] = [];\n for (let el: HTMLElement | null = element; el; el = el.parentElement) {\n if (el === document.body) break;\n\n for (const sibling of el.parentElement?.children ?? []) {\n if (sibling === el) continue;\n if (!(sibling instanceof HTMLElement)) continue;\n if (sibling.hasAttribute(\"inert\")) continue;\n\n sibling.setAttribute(\"inert\", \"true\");\n inertElements.push(sibling);\n }\n }\n\n return () => {\n releaseFocusTrap(inertElements);\n inertElements = [];\n };\n}\n\n/**\n * Unset the `inert` attribute on all elements given\n */\nfunction releaseFocusTrap(inertElements: Iterable<HTMLElement>) {\n for (const el of inertElements) {\n el.removeAttribute(\"inert\");\n }\n}\n"],"mappings":"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","names":["import_react","import_typed_classname","import_react_slot","import_react","import_jsx_runtime","_a"]}
@@ -4,7 +4,7 @@ import {
4
4
  ModalContent,
5
5
  ModalFooter,
6
6
  ModalHeader
7
- } from "../chunk-6VKQ6IRG.mjs";
7
+ } from "../chunk-GXIKHXWC.mjs";
8
8
  import "../chunk-ILFK3VKS.mjs";
9
9
  import "../chunk-3OGHJOJF.mjs";
10
10
  import "../chunk-YOSPWY5K.mjs";
@@ -61,7 +61,7 @@ export interface ModalProps extends React.HTMLAttributes<HTMLDialogElement> {
61
61
  * <Modal.Footer>
62
62
  * <HStack gap="16" wrap>
63
63
  * <Button onClick={onMainAction}>Main action</Button>
64
- * <Button variant="primary-outline" onClick={onClose}>
64
+ * <Button variant="secondary" onClick={onClose}>
65
65
  * Cancel
66
66
  * </Button>
67
67
  * </HStack>
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modal/modal.tsx","../../src/box/box.tsx","../../src/utils/utils.ts"],"sourcesContent":["import { forwardRef, useEffect, useRef } from \"react\";\nimport { clsx } from \"@postenbring/hedwig-css/typed-classname\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { Box } from \"../box/box\";\nimport { useMergeRefs } from \"../utils/utils\";\n\ninterface ModalHeaderProps extends React.HTMLAttributes<HTMLHeadingElement> {\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\nexport const ModalHeader = forwardRef<HTMLHeadingElement, ModalHeaderProps>(\n ({ asChild, className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"h1\";\n return (\n <Component\n className={clsx(\"hds-modal__header\", className as undefined)}\n ref={ref}\n {...rest}\n />\n );\n },\n);\nModalHeader.displayName = \"Modal.Header\";\n\ninterface ModalContentProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\nexport const ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(\n ({ asChild, className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"div\";\n return (\n <Component\n className={clsx(\"hds-modal__content\", className as undefined)}\n ref={ref}\n {...rest}\n />\n );\n },\n);\nModalContent.displayName = \"Modal.Content\";\n\ninterface ModalFooterProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\nexport const ModalFooter = forwardRef<HTMLDivElement, ModalFooterProps>(\n ({ asChild, className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"footer\";\n return (\n <Component\n className={clsx(\"hds-modal__footer\", className as undefined)}\n ref={ref}\n {...rest}\n />\n );\n },\n);\nModalFooter.displayName = \"Modal.Footer\";\n\nexport interface ModalProps extends React.HTMLAttributes<HTMLDialogElement> {\n children: React.ReactNode;\n\n /**\n * Controls the open state of the modal\n */\n open?: boolean;\n\n /**\n * Whether to close when clicking on the backdrop.\n */\n closeOnBackdropClick?: boolean;\n}\n\n/**\n * A modal dialog is a window that forces the user to interact with it before they can return to other parts of the application.\n *\n * Uses the native [`dialog`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog) element.\n *\n * @example\n * ```tsx\n * const modalRef = useRef<HTMLDialogElement>(null);\n * const onClose = () => modalRef.current?.close();\n *\n * return (\n * <>\n * <Button onClick={() => modalRef.current?.showModal()}>Open Modal</Button>\n * <Modal ref={modalRef}>\n * <Modal.Header>Dialog header</Modal.Header>\n * <Modal.Content>\n * <p>\n * Dialog header Dialog description - a description of what is about to happen and maybe\n * something about the consequences.\n * </p>\n * </Modal.Content>\n * <Modal.Footer>\n * <HStack gap=\"16\" wrap>\n * <Button onClick={onMainAction}>Main action</Button>\n * <Button variant=\"primary-outline\" onClick={onClose}>\n * Cancel\n * </Button>\n * </HStack>\n * </Modal.Footer>\n * </Modal>\n * </>\n * );\n * ```\n */\nexport const Modal = forwardRef<HTMLDialogElement, ModalProps>(\n ({ children, className, open, closeOnBackdropClick, onClick, ...rest }, ref) => {\n const modalRef = useRef<HTMLDialogElement>(null);\n const mergedRef = useMergeRefs([modalRef, ref]);\n\n // The X close button that comes from the `Box` component\n function onCloseButtonClick() {\n modalRef.current?.close();\n return false;\n }\n\n // No scroll when modal is open\n useScrollLock(modalRef, \"hds-modal-scroll-lock\");\n\n // `open` prop\n useEffect(() => {\n if (modalRef.current && open !== undefined) {\n if (open && !modalRef.current.open) {\n modalRef.current.showModal();\n } else if (!open && modalRef.current.open) {\n modalRef.current.close();\n }\n }\n }, [modalRef, open]);\n\n function onDialogClick(e: React.MouseEvent<HTMLElement>) {\n if (closeOnBackdropClick && e.target === modalRef.current) {\n modalRef.current.close();\n }\n onClick?.(e as React.MouseEvent<HTMLDialogElement>);\n }\n\n return (\n <Box\n asChild\n className={clsx(\"hds-modal\", className as undefined)}\n closeable\n onClick={onDialogClick}\n onClose={onCloseButtonClick}\n variant=\"white\"\n >\n <dialog ref={mergedRef} {...rest}>\n {children}\n </dialog>\n </Box>\n );\n },\n) as ModalType;\nModal.displayName = \"Modal\";\n\ntype ModalType = ReturnType<typeof forwardRef<HTMLDialogElement, ModalProps>> & {\n Header: typeof ModalHeader;\n Content: typeof ModalContent;\n Footer: typeof ModalFooter;\n};\n\nModal.Header = ModalHeader;\nModal.Content = ModalContent;\nModal.Footer = ModalFooter;\n\nfunction useScrollLock(modalRef: React.RefObject<HTMLDialogElement>, bodyClass: string) {\n useEffect(() => {\n if (!modalRef.current) return;\n if (modalRef.current.open) document.body.classList.add(bodyClass);\n\n const observer = new MutationObserver(() => {\n if (modalRef.current?.open) document.body.classList.add(bodyClass);\n else document.body.classList.remove(bodyClass);\n });\n observer.observe(modalRef.current, {\n attributes: true,\n attributeFilter: [\"open\"],\n });\n return () => {\n observer.disconnect();\n document.body.classList.remove(bodyClass);\n };\n }, [bodyClass, modalRef]);\n}\n","import { forwardRef, useCallback, useState } from \"react\";\nimport { clsx } from \"@postenbring/hedwig-css/typed-classname\";\nimport { Slot, Slottable } from \"@radix-ui/react-slot\";\n\nexport type BoxCloseButtonProps = Omit<React.HTMLAttributes<HTMLButtonElement>, \"children\">;\nexport const BoxCloseButton = forwardRef<HTMLButtonElement, BoxCloseButtonProps>(\n ({ className, ...rest }, ref) => {\n return (\n <button\n className={clsx(\"hds-box__close-button\", className as undefined)}\n ref={ref}\n type=\"button\"\n {...rest}\n />\n );\n },\n);\nBoxCloseButton.displayName = \"Box.CloseButton\";\n\nexport interface BoxProps extends React.HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode;\n\n /**\n * Color variant of the box\n *\n * @default \"light-grey\"\n */\n variant?: \"light-grey\" | \"lighter\" | \"white\" | \"warning\";\n\n /**\n * If `true`, a close button will be shown.\n * Use when you want to control the close button using the BoxCloseButton component.\n *\n * @default false\n */\n closeable?: boolean;\n\n /**\n * Callback fired when the component requests to be closed.\n * If not set, the component will be closed without any user interaction.\n *\n * If set, and the handler returns non-true value, the component will not be closed.\n * Use this if you want to control the closing of the component, using the `closed` prop\n *\n * If set, and the handler returns the true, the component will be closed.\n * Use this with `window.confirm()` to ask the user to confirm closing the component.\n */\n // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents -- It's fine, I want to have the boolean in the type\n onClose?: () => boolean | unknown;\n\n /**\n * If `true`, the box will be closed and hidden from view\n */\n closed?: boolean;\n\n /**\n * Props applied to the close button element.\n */\n closeButtonProps?: BoxCloseButtonProps;\n\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\n\nexport const Box = forwardRef<HTMLDivElement, BoxProps>(\n (\n {\n asChild,\n variant,\n closeable = false,\n onClose: onCloseProp,\n closed: closedProp,\n closeButtonProps,\n children,\n className,\n ...rest\n },\n ref,\n ) => {\n const [closedState, setClosedState] = useState(false);\n const onClose = useCallback(() => {\n if (onCloseProp) {\n const result = onCloseProp();\n if (result === true) {\n setClosedState(true);\n }\n } else {\n setClosedState(true);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- I know better\n }, []);\n const closed = closedProp ?? closedState;\n const Component = asChild ? Slot : \"div\";\n\n return (\n <Component\n className={clsx(\n \"hds-box\",\n variant && `hds-box--${variant}`,\n { \"hds-box--closed\": closed },\n className as undefined,\n )}\n ref={ref}\n {...rest}\n >\n {closeable ? <BoxCloseButton onClick={onClose} {...closeButtonProps} /> : null}\n <Slottable>{children}</Slottable>\n </Component>\n );\n },\n) as BoxType;\nBox.displayName = \"Box\";\n\nBox.CloseButton = BoxCloseButton;\n\ntype BoxType = ReturnType<typeof forwardRef<HTMLDivElement, BoxProps>> & {\n CloseButton: typeof BoxCloseButton;\n};\n","import * as React from \"react\";\nimport { useCallback, useEffect, useState } from \"react\";\n\n/**\n * Merges an array of refs into a single memoized callback ref or `null`.\n * @see https://floating-ui.com/docs/useMergeRefs\n */\nexport function useMergeRefs<Instance>(\n refs: (React.Ref<Instance> | undefined)[],\n): React.RefCallback<Instance> | null {\n return React.useMemo(() => {\n if (refs.every((ref) => ref === null)) {\n return null;\n }\n\n return (value) => {\n refs.forEach((ref) => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref !== null) {\n (ref as React.MutableRefObject<Instance | null>).current = value;\n }\n });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- It's ok\n }, refs);\n}\n\nexport function useResize<Instance extends HTMLElement>(\n ref: React.RefObject<Instance> | undefined | null,\n): { width: number; height: number } {\n const [width, setWidth] = useState<number>(0);\n const [height, setHeight] = useState<number>(0);\n const handleResize = useCallback(() => {\n if (ref?.current !== null) {\n setWidth(ref?.current?.offsetWidth ?? 0);\n setHeight(ref?.current?.offsetHeight ?? 0);\n }\n }, [ref]);\n useEffect(() => {\n window.addEventListener(\"load\", handleResize);\n window.addEventListener(\"resize\", handleResize);\n return () => {\n window.removeEventListener(\"load\", handleResize);\n window.removeEventListener(\"resize\", handleResize);\n };\n }, [ref, handleResize]);\n useEffect(() => {\n handleResize();\n // eslint-disable-next-line react-hooks/exhaustive-deps -- It's ok\n }, []);\n return { width, height };\n}\n\nfunction subscribe() {\n // eslint-disable-next-line @typescript-eslint/no-empty-function -- It's ok\n return () => {};\n}\n\nexport function useHydrated() {\n return React.useSyncExternalStore(\n subscribe,\n () => true,\n () => false,\n );\n}\n\n/**\n * Trap focus inside an element using the `inert` attribute.\n *\n * Adds `inert` to all siblings of the given element, and all their ancestors up to the body.\n * Returns a cleanup function which removes the `inert` property from the elements, effectively giving focus back to rest of the document.\n *\n * NOTE: Does not support portals, i.e. elements outside the DOM hierarchy of the given element.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/inert\n * @see https://web.dev/articles/inert\n */\nexport function focusTrap(element: HTMLElement) {\n // eslint-disable-next-line @typescript-eslint/no-empty-function -- NOP on focus trapping the body element\n if (element === document.body) return () => {};\n\n let inertElements: HTMLElement[] = [];\n for (let el: HTMLElement | null = element; el; el = el.parentElement) {\n if (el === document.body) break;\n\n for (const sibling of el.parentElement?.children ?? []) {\n if (sibling === el) continue;\n if (!(sibling instanceof HTMLElement)) continue;\n if (sibling.hasAttribute(\"inert\")) continue;\n\n sibling.setAttribute(\"inert\", \"true\");\n inertElements.push(sibling);\n }\n }\n\n return () => {\n releaseFocusTrap(inertElements);\n inertElements = [];\n };\n}\n\n/**\n * Unset the `inert` attribute on all elements given\n */\nfunction releaseFocusTrap(inertElements: Iterable<HTMLElement>) {\n for (const el of inertElements) {\n el.removeAttribute(\"inert\");\n }\n}\n"],"mappings":"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","names":["import_react","import_typed_classname","import_react_slot","import_react","import_jsx_runtime","_a"]}
1
+ {"version":3,"sources":["../../src/modal/modal.tsx","../../src/box/box.tsx","../../src/utils/utils.ts"],"sourcesContent":["import { forwardRef, useEffect, useRef } from \"react\";\nimport { clsx } from \"@postenbring/hedwig-css/typed-classname\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { Box } from \"../box/box\";\nimport { useMergeRefs } from \"../utils/utils\";\n\ninterface ModalHeaderProps extends React.HTMLAttributes<HTMLHeadingElement> {\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\nexport const ModalHeader = forwardRef<HTMLHeadingElement, ModalHeaderProps>(\n ({ asChild, className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"h1\";\n return (\n <Component\n className={clsx(\"hds-modal__header\", className as undefined)}\n ref={ref}\n {...rest}\n />\n );\n },\n);\nModalHeader.displayName = \"Modal.Header\";\n\ninterface ModalContentProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\nexport const ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(\n ({ asChild, className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"div\";\n return (\n <Component\n className={clsx(\"hds-modal__content\", className as undefined)}\n ref={ref}\n {...rest}\n />\n );\n },\n);\nModalContent.displayName = \"Modal.Content\";\n\ninterface ModalFooterProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\nexport const ModalFooter = forwardRef<HTMLDivElement, ModalFooterProps>(\n ({ asChild, className, ...rest }, ref) => {\n const Component = asChild ? Slot : \"footer\";\n return (\n <Component\n className={clsx(\"hds-modal__footer\", className as undefined)}\n ref={ref}\n {...rest}\n />\n );\n },\n);\nModalFooter.displayName = \"Modal.Footer\";\n\nexport interface ModalProps extends React.HTMLAttributes<HTMLDialogElement> {\n children: React.ReactNode;\n\n /**\n * Controls the open state of the modal\n */\n open?: boolean;\n\n /**\n * Whether to close when clicking on the backdrop.\n */\n closeOnBackdropClick?: boolean;\n}\n\n/**\n * A modal dialog is a window that forces the user to interact with it before they can return to other parts of the application.\n *\n * Uses the native [`dialog`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog) element.\n *\n * @example\n * ```tsx\n * const modalRef = useRef<HTMLDialogElement>(null);\n * const onClose = () => modalRef.current?.close();\n *\n * return (\n * <>\n * <Button onClick={() => modalRef.current?.showModal()}>Open Modal</Button>\n * <Modal ref={modalRef}>\n * <Modal.Header>Dialog header</Modal.Header>\n * <Modal.Content>\n * <p>\n * Dialog header Dialog description - a description of what is about to happen and maybe\n * something about the consequences.\n * </p>\n * </Modal.Content>\n * <Modal.Footer>\n * <HStack gap=\"16\" wrap>\n * <Button onClick={onMainAction}>Main action</Button>\n * <Button variant=\"secondary\" onClick={onClose}>\n * Cancel\n * </Button>\n * </HStack>\n * </Modal.Footer>\n * </Modal>\n * </>\n * );\n * ```\n */\nexport const Modal = forwardRef<HTMLDialogElement, ModalProps>(\n ({ children, className, open, closeOnBackdropClick, onClick, ...rest }, ref) => {\n const modalRef = useRef<HTMLDialogElement>(null);\n const mergedRef = useMergeRefs([modalRef, ref]);\n\n // The X close button that comes from the `Box` component\n function onCloseButtonClick() {\n modalRef.current?.close();\n return false;\n }\n\n // No scroll when modal is open\n useScrollLock(modalRef, \"hds-modal-scroll-lock\");\n\n // `open` prop\n useEffect(() => {\n if (modalRef.current && open !== undefined) {\n if (open && !modalRef.current.open) {\n modalRef.current.showModal();\n } else if (!open && modalRef.current.open) {\n modalRef.current.close();\n }\n }\n }, [modalRef, open]);\n\n function onDialogClick(e: React.MouseEvent<HTMLElement>) {\n if (closeOnBackdropClick && e.target === modalRef.current) {\n modalRef.current.close();\n }\n onClick?.(e as React.MouseEvent<HTMLDialogElement>);\n }\n\n return (\n <Box\n asChild\n className={clsx(\"hds-modal\", className as undefined)}\n closeable\n onClick={onDialogClick}\n onClose={onCloseButtonClick}\n variant=\"white\"\n >\n <dialog ref={mergedRef} {...rest}>\n {children}\n </dialog>\n </Box>\n );\n },\n) as ModalType;\nModal.displayName = \"Modal\";\n\ntype ModalType = ReturnType<typeof forwardRef<HTMLDialogElement, ModalProps>> & {\n Header: typeof ModalHeader;\n Content: typeof ModalContent;\n Footer: typeof ModalFooter;\n};\n\nModal.Header = ModalHeader;\nModal.Content = ModalContent;\nModal.Footer = ModalFooter;\n\nfunction useScrollLock(modalRef: React.RefObject<HTMLDialogElement>, bodyClass: string) {\n useEffect(() => {\n if (!modalRef.current) return;\n if (modalRef.current.open) document.body.classList.add(bodyClass);\n\n const observer = new MutationObserver(() => {\n if (modalRef.current?.open) document.body.classList.add(bodyClass);\n else document.body.classList.remove(bodyClass);\n });\n observer.observe(modalRef.current, {\n attributes: true,\n attributeFilter: [\"open\"],\n });\n return () => {\n observer.disconnect();\n document.body.classList.remove(bodyClass);\n };\n }, [bodyClass, modalRef]);\n}\n","import { forwardRef, useCallback, useState } from \"react\";\nimport { clsx } from \"@postenbring/hedwig-css/typed-classname\";\nimport { Slot, Slottable } from \"@radix-ui/react-slot\";\n\nexport type BoxCloseButtonProps = Omit<React.HTMLAttributes<HTMLButtonElement>, \"children\">;\nexport const BoxCloseButton = forwardRef<HTMLButtonElement, BoxCloseButtonProps>(\n ({ className, ...rest }, ref) => {\n return (\n <button\n className={clsx(\"hds-box__close-button\", className as undefined)}\n ref={ref}\n type=\"button\"\n {...rest}\n />\n );\n },\n);\nBoxCloseButton.displayName = \"Box.CloseButton\";\n\nexport interface BoxProps extends React.HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode;\n\n /**\n * Color variant of the box\n *\n * @default \"light-grey\"\n */\n variant?: \"light-grey\" | \"lighter\" | \"white\" | \"warning\";\n\n /**\n * If `true`, a close button will be shown.\n * Use when you want to control the close button using the BoxCloseButton component.\n *\n * @default false\n */\n closeable?: boolean;\n\n /**\n * Callback fired when the component requests to be closed.\n * If not set, the component will be closed without any user interaction.\n *\n * If set, and the handler returns non-true value, the component will not be closed.\n * Use this if you want to control the closing of the component, using the `closed` prop\n *\n * If set, and the handler returns the true, the component will be closed.\n * Use this with `window.confirm()` to ask the user to confirm closing the component.\n */\n // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents -- It's fine, I want to have the boolean in the type\n onClose?: () => boolean | unknown;\n\n /**\n * If `true`, the box will be closed and hidden from view\n */\n closed?: boolean;\n\n /**\n * Props applied to the close button element.\n */\n closeButtonProps?: BoxCloseButtonProps;\n\n /**\n * Change the default rendered element for the one passed as a child, merging their props and behavior.\n *\n * @default false\n */\n asChild?: boolean;\n}\n\nexport const Box = forwardRef<HTMLDivElement, BoxProps>(\n (\n {\n asChild,\n variant,\n closeable = false,\n onClose: onCloseProp,\n closed: closedProp,\n closeButtonProps,\n children,\n className,\n ...rest\n },\n ref,\n ) => {\n const [closedState, setClosedState] = useState(false);\n const onClose = useCallback(() => {\n if (onCloseProp) {\n const result = onCloseProp();\n if (result === true) {\n setClosedState(true);\n }\n } else {\n setClosedState(true);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- I know better\n }, []);\n const closed = closedProp ?? closedState;\n const Component = asChild ? Slot : \"div\";\n\n return (\n <Component\n className={clsx(\n \"hds-box\",\n variant && `hds-box--${variant}`,\n { \"hds-box--closed\": closed },\n className as undefined,\n )}\n ref={ref}\n {...rest}\n >\n {closeable ? <BoxCloseButton onClick={onClose} {...closeButtonProps} /> : null}\n <Slottable>{children}</Slottable>\n </Component>\n );\n },\n) as BoxType;\nBox.displayName = \"Box\";\n\nBox.CloseButton = BoxCloseButton;\n\ntype BoxType = ReturnType<typeof forwardRef<HTMLDivElement, BoxProps>> & {\n CloseButton: typeof BoxCloseButton;\n};\n","import * as React from \"react\";\nimport { useCallback, useEffect, useState } from \"react\";\n\n/**\n * Merges an array of refs into a single memoized callback ref or `null`.\n * @see https://floating-ui.com/docs/useMergeRefs\n */\nexport function useMergeRefs<Instance>(\n refs: (React.Ref<Instance> | undefined)[],\n): React.RefCallback<Instance> | null {\n return React.useMemo(() => {\n if (refs.every((ref) => ref === null)) {\n return null;\n }\n\n return (value) => {\n refs.forEach((ref) => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref !== null) {\n (ref as React.MutableRefObject<Instance | null>).current = value;\n }\n });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- It's ok\n }, refs);\n}\n\nexport function useResize<Instance extends HTMLElement>(\n ref: React.RefObject<Instance> | undefined | null,\n): { width: number; height: number } {\n const [width, setWidth] = useState<number>(0);\n const [height, setHeight] = useState<number>(0);\n const handleResize = useCallback(() => {\n if (ref?.current !== null) {\n setWidth(ref?.current?.offsetWidth ?? 0);\n setHeight(ref?.current?.offsetHeight ?? 0);\n }\n }, [ref]);\n useEffect(() => {\n window.addEventListener(\"load\", handleResize);\n window.addEventListener(\"resize\", handleResize);\n return () => {\n window.removeEventListener(\"load\", handleResize);\n window.removeEventListener(\"resize\", handleResize);\n };\n }, [ref, handleResize]);\n useEffect(() => {\n handleResize();\n // eslint-disable-next-line react-hooks/exhaustive-deps -- It's ok\n }, []);\n return { width, height };\n}\n\nfunction subscribe() {\n // eslint-disable-next-line @typescript-eslint/no-empty-function -- It's ok\n return () => {};\n}\n\nexport function useHydrated() {\n return React.useSyncExternalStore(\n subscribe,\n () => true,\n () => false,\n );\n}\n\n/**\n * Trap focus inside an element using the `inert` attribute.\n *\n * Adds `inert` to all siblings of the given element, and all their ancestors up to the body.\n * Returns a cleanup function which removes the `inert` property from the elements, effectively giving focus back to rest of the document.\n *\n * NOTE: Does not support portals, i.e. elements outside the DOM hierarchy of the given element.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/inert\n * @see https://web.dev/articles/inert\n */\nexport function focusTrap(element: HTMLElement) {\n // eslint-disable-next-line @typescript-eslint/no-empty-function -- NOP on focus trapping the body element\n if (element === document.body) return () => {};\n\n let inertElements: HTMLElement[] = [];\n for (let el: HTMLElement | null = element; el; el = el.parentElement) {\n if (el === document.body) break;\n\n for (const sibling of el.parentElement?.children ?? []) {\n if (sibling === el) continue;\n if (!(sibling instanceof HTMLElement)) continue;\n if (sibling.hasAttribute(\"inert\")) continue;\n\n sibling.setAttribute(\"inert\", \"true\");\n inertElements.push(sibling);\n }\n }\n\n return () => {\n releaseFocusTrap(inertElements);\n inertElements = [];\n };\n}\n\n/**\n * Unset the `inert` attribute on all elements given\n */\nfunction releaseFocusTrap(inertElements: Iterable<HTMLElement>) {\n for (const el of inertElements) {\n el.removeAttribute(\"inert\");\n }\n}\n"],"mappings":"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","names":["import_react","import_typed_classname","import_react_slot","import_react","import_jsx_runtime","_a"]}
@@ -3,7 +3,7 @@ import {
3
3
  ModalContent,
4
4
  ModalFooter,
5
5
  ModalHeader
6
- } from "../chunk-6VKQ6IRG.mjs";
6
+ } from "../chunk-GXIKHXWC.mjs";
7
7
  import "../chunk-ILFK3VKS.mjs";
8
8
  import "../chunk-3OGHJOJF.mjs";
9
9
  import "../chunk-YOSPWY5K.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postenbring/hedwig-react",
3
- "version": "1.5.0",
3
+ "version": "2.0.0",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -17,8 +17,8 @@
17
17
  "@types/react-dom": "^18.3.1",
18
18
  "react": "^18.3.1",
19
19
  "react-dom": "18.3.1",
20
- "tsup": "^8.3.5",
21
- "typescript": "^5.6.3",
20
+ "tsup": "^8.4.0",
21
+ "typescript": "^5.8.3",
22
22
  "eslint-config-custom": "0.0.1",
23
23
  "hedwig-tsconfig": "0.0.0"
24
24
  },
@@ -29,9 +29,9 @@
29
29
  "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
30
30
  },
31
31
  "dependencies": {
32
- "@radix-ui/react-popover": "1.1.2",
33
- "@radix-ui/react-slot": "1.1.0",
34
- "@postenbring/hedwig-css": "1.6.0"
32
+ "@radix-ui/react-popover": "1.1.6",
33
+ "@radix-ui/react-slot": "1.1.2",
34
+ "@postenbring/hedwig-css": "2.0.0"
35
35
  },
36
36
  "publishConfig": {
37
37
  "access": "public"
@@ -5,15 +5,17 @@ import { Slot } from "@radix-ui/react-slot";
5
5
  export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
6
6
  /**
7
7
  * The height, font size and padding of the button
8
+ *
9
+ * @default "large"
8
10
  */
9
- size?: "small" | "medium" | "large";
11
+ size?: "small" | "large";
10
12
 
11
13
  /**
12
14
  * The background and fill of the button
13
15
  *
14
16
  * @default "primary"
15
17
  */
16
- variant?: "primary" | "secondary" | "primary-outline" | "secondary-outline";
18
+ variant?: "primary" | "secondary" | "tertiary" | "inverted";
17
19
 
18
20
  /**
19
21
  * Make the button use 100% width available.
@@ -22,11 +24,14 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
22
24
  fullWidth?: boolean | "mobile";
23
25
 
24
26
  /**
25
- * Use the button as an icon button
27
+ * Specify that there is an icon in the button.
28
+ * `icon`: There is only an icon in the button.
29
+ * `icon="leading"`: There is an icon before the text.
30
+ * `icon="trailing"`: There is an icon after the text.
26
31
  *
27
- * Render the icon in `children`
32
+ * @default false
28
33
  */
29
- icon?: boolean;
34
+ icon?: boolean | "leading" | "trailing";
30
35
 
31
36
  /**
32
37
  * Change the default rendered element for the one passed as a child, merging their props and behavior.
@@ -42,8 +47,9 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
42
47
  * @example
43
48
  * <Button variant="primary">Primary</Button>
44
49
  * <Button variant="secondary" size="large">Secondary</Button>
45
- * <Button variant="primary-outline">Primary Outline</Button>
46
- * <Button variant="secondary-outline" fullWidth="mobile">Secondary Outline</Button>
50
+ * <Button variant="inverted">Inverted</Button>
51
+ * <Button variant="tertiary" fullWidth="mobile">Tertiary</Button>
52
+ * <Button icon="leading"><LeadingIcon />Leading icon</Button>
47
53
  *
48
54
  * @example
49
55
  * // If used for navigation use the `asChild` prop with a anchor element as a child.
@@ -55,15 +61,16 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
55
61
  asChild,
56
62
  children,
57
63
  variant = "primary",
58
- size = "medium",
64
+ size = "large",
59
65
  fullWidth = false,
60
- icon,
66
+ icon = false,
61
67
  className,
62
68
  ...rest
63
69
  },
64
70
  ref,
65
71
  ) => {
66
72
  const Component = asChild ? Slot : "button";
73
+
67
74
  return (
68
75
  <Component
69
76
  className={clsx(
@@ -73,7 +80,9 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
73
80
  {
74
81
  "hds-button--full": fullWidth === true,
75
82
  "hds-button--mobile-full": fullWidth === "mobile",
76
- "hds-button--icon-only": icon,
83
+ "hds-button--only-icon": icon === true,
84
+ "hds-button--leading-icon": icon === "leading",
85
+ "hds-button--trailing-icon": icon === "trailing",
77
86
  },
78
87
  className as undefined,
79
88
  )}
package/src/card/card.tsx CHANGED
@@ -22,14 +22,28 @@ export interface CardImageMediaProps extends React.ImgHTMLAttributes<HTMLImageEl
22
22
  * @default false
23
23
  */
24
24
  asChild?: boolean;
25
+ /**
26
+ * Define image scaling behavior when the image are varies in both width and height across different page breaks and sizes of the card.
27
+ * "crop": Image always fills the available space.
28
+ * If the aspect ratio doesn't match, then the top/bottom or left/right edges are cropped away.
29
+ * "scale": No cropping, image scales to the maximum size available and centers.
30
+ * If the aspect ratio doesn't match, then the background will show on the top/bottom or left/right sides of the image.
31
+ *
32
+ * @default "crop"
33
+ */
34
+ variant?: "crop" | "scale";
25
35
  }
26
36
  export const CardMediaImg = forwardRef<HTMLImageElement, CardImageMediaProps>(
27
- ({ asChild, className, ...rest }, ref) => {
37
+ ({ asChild, variant, className, ...rest }, ref) => {
28
38
  const Component = asChild ? Slot : "img";
29
39
  return (
30
40
  <Component
31
41
  {...rest}
32
- className={clsx("hds-card__media__img", className as undefined)}
42
+ className={clsx(
43
+ "hds-card__media__img",
44
+ { "hds-card__img__scale": variant === "scale" },
45
+ className as undefined,
46
+ )}
33
47
  ref={ref}
34
48
  />
35
49
  );
@@ -47,7 +47,7 @@ export const FooterButtonLink = forwardRef<HTMLAnchorElement, FooterButtonLinkPr
47
47
  ({ children, className, asChild, ...rest }, ref) => {
48
48
  const Component = asChild ? Slot : "a";
49
49
  return (
50
- <Button asChild variant="primary-outline" className={clsx(className as undefined)}>
50
+ <Button asChild variant="inverted" className={clsx(className as undefined)}>
51
51
  <Component ref={ref} {...rest}>
52
52
  {children}
53
53
  </Component>
package/src/link/link.tsx CHANGED
@@ -7,14 +7,21 @@ export interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement>
7
7
  /**
8
8
  * The visual style of the link
9
9
  */
10
- variant?: "underline" | "solid" | "inverted" | "no-underline";
10
+ variant?: "underline" | "solid" | "inverted" | "no-underline" | "inverted-no-underline";
11
11
 
12
12
  /**
13
13
  * Font size of the link
14
+ * @default "default"
15
+ */
16
+ size?: "default" | "small" | "large" | "technical";
17
+
18
+ /**
19
+ * Specify that there is an icon in the link.
20
+ * `icon="leading"`: There is an icon before the text.
21
+ * `icon="trailing"`: There is an icon after the text.
14
22
  *
15
- * Note: `medium` is deprecated, use `default` instead of `medium`
16
23
  */
17
- size?: "default" | "small" | "large" | "technical" | "medium";
24
+ icon?: "leading" | "trailing";
18
25
 
19
26
  children: React.ReactNode;
20
27
 
@@ -27,14 +34,20 @@ export interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement>
27
34
  }
28
35
 
29
36
  export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
30
- ({ asChild, children, variant = "underline", size = "default", className, ...rest }, ref) => {
37
+ (
38
+ { asChild, children, variant = "underline", size = "default", icon, className, ...rest },
39
+ ref,
40
+ ) => {
31
41
  const Component = asChild ? Slot : "a";
42
+
32
43
  return (
33
44
  <Component
34
45
  className={clsx(
35
46
  "hds-link",
36
47
  variant !== "underline" && `hds-link--${variant}`,
37
- size !== "default" && size !== "medium" && `hds-link--${size}`,
48
+ size !== "default" && `hds-link--${size}`,
49
+ { "hds-link--trailing-icon": icon === "trailing" },
50
+ { "hds-link--leading-icon": icon === "leading" },
38
51
  className as undefined,
39
52
  )}
40
53
  ref={ref}
@@ -34,7 +34,7 @@ export const Preview: Story = {
34
34
  <Modal.Footer>
35
35
  <HStack gap="16" wrap>
36
36
  <Button onClick={onMainAction}>Main action</Button>
37
- <Button variant="primary-outline" onClick={onClose}>
37
+ <Button variant="secondary" onClick={onClose}>
38
38
  Cancel
39
39
  </Button>
40
40
  </HStack>
@@ -108,7 +108,7 @@ export interface ModalProps extends React.HTMLAttributes<HTMLDialogElement> {
108
108
  * <Modal.Footer>
109
109
  * <HStack gap="16" wrap>
110
110
  * <Button onClick={onMainAction}>Main action</Button>
111
- * <Button variant="primary-outline" onClick={onClose}>
111
+ * <Button variant="secondary" onClick={onClose}>
112
112
  * Cancel
113
113
  * </Button>
114
114
  * </HStack>