@dsn-starter-kit/components-react 3.5.0 → 4.1.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 (77) hide show
  1. package/dist/Card/Card.d.mts +86 -21
  2. package/dist/Card/Card.d.mts.map +1 -1
  3. package/dist/Card/Card2.mjs +100 -17
  4. package/dist/Card/Card2.mjs.map +1 -1
  5. package/dist/Card/index.d.mts +2 -2
  6. package/dist/DateInput/DateInput.d.mts +1 -1
  7. package/dist/DateInput/DateInput2.mjs +1 -1
  8. package/dist/DateInput/DateInput2.mjs.map +1 -1
  9. package/dist/DateInputGroup/DateInputGroup2.mjs +3 -3
  10. package/dist/DateInputGroup/DateInputGroup2.mjs.map +1 -1
  11. package/dist/Drawer/Drawer.d.mts +5 -2
  12. package/dist/Drawer/Drawer.d.mts.map +1 -1
  13. package/dist/Drawer/Drawer2.mjs +18 -3
  14. package/dist/Drawer/Drawer2.mjs.map +1 -1
  15. package/dist/EmailInput/EmailInput.d.mts +10 -5
  16. package/dist/EmailInput/EmailInput.d.mts.map +1 -1
  17. package/dist/EmailInput/EmailInput2.mjs +2 -2
  18. package/dist/EmailInput/EmailInput2.mjs.map +1 -1
  19. package/dist/ModalDialog/ModalDialog.d.mts +13 -3
  20. package/dist/ModalDialog/ModalDialog.d.mts.map +1 -1
  21. package/dist/ModalDialog/ModalDialog2.mjs +10 -3
  22. package/dist/ModalDialog/ModalDialog2.mjs.map +1 -1
  23. package/dist/NumberInput/NumberInput.d.mts +4 -4
  24. package/dist/NumberInput/NumberInput.d.mts.map +1 -1
  25. package/dist/NumberInput/NumberInput2.mjs +2 -2
  26. package/dist/NumberInput/NumberInput2.mjs.map +1 -1
  27. package/dist/PageHeader/PageHeader.d.mts.map +1 -1
  28. package/dist/PageHeader/PageHeader2.mjs +19 -2
  29. package/dist/PageHeader/PageHeader2.mjs.map +1 -1
  30. package/dist/PasswordInput/PasswordInput.d.mts +10 -5
  31. package/dist/PasswordInput/PasswordInput.d.mts.map +1 -1
  32. package/dist/PasswordInput/PasswordInput2.mjs +2 -2
  33. package/dist/PasswordInput/PasswordInput2.mjs.map +1 -1
  34. package/dist/Popover/Popover.d.mts +16 -23
  35. package/dist/Popover/Popover.d.mts.map +1 -1
  36. package/dist/Popover/Popover2.mjs +33 -119
  37. package/dist/Popover/Popover2.mjs.map +1 -1
  38. package/dist/PopoverMenu/PopoverMenu.d.mts +62 -0
  39. package/dist/PopoverMenu/PopoverMenu.d.mts.map +1 -0
  40. package/dist/PopoverMenu/PopoverMenu2.mjs +66 -0
  41. package/dist/PopoverMenu/PopoverMenu2.mjs.map +1 -0
  42. package/dist/PopoverMenu/index.d.mts +2 -0
  43. package/dist/SearchInput/SearchInput.d.mts +10 -5
  44. package/dist/SearchInput/SearchInput.d.mts.map +1 -1
  45. package/dist/SearchInput/SearchInput2.mjs +2 -2
  46. package/dist/SearchInput/SearchInput2.mjs.map +1 -1
  47. package/dist/Select/Select.d.mts +6 -6
  48. package/dist/Select/Select.d.mts.map +1 -1
  49. package/dist/Select/Select2.mjs +4 -4
  50. package/dist/Select/Select2.mjs.map +1 -1
  51. package/dist/TelephoneInput/TelephoneInput.d.mts +10 -5
  52. package/dist/TelephoneInput/TelephoneInput.d.mts.map +1 -1
  53. package/dist/TelephoneInput/TelephoneInput2.mjs +2 -2
  54. package/dist/TelephoneInput/TelephoneInput2.mjs.map +1 -1
  55. package/dist/TextArea/TextArea.d.mts +10 -5
  56. package/dist/TextArea/TextArea.d.mts.map +1 -1
  57. package/dist/TextArea/TextArea2.mjs +2 -2
  58. package/dist/TextArea/TextArea2.mjs.map +1 -1
  59. package/dist/TextInput/TextInput.d.mts +4 -4
  60. package/dist/TextInput/TextInput.d.mts.map +1 -1
  61. package/dist/TextInput/TextInput2.mjs +2 -2
  62. package/dist/TextInput/TextInput2.mjs.map +1 -1
  63. package/dist/TimeInput/TimeInput.d.mts +1 -1
  64. package/dist/TimeInput/TimeInput2.mjs +1 -1
  65. package/dist/TimeInput/TimeInput2.mjs.map +1 -1
  66. package/dist/index.cjs +315 -79
  67. package/dist/index.cjs.map +1 -1
  68. package/dist/index.css +5950 -5217
  69. package/dist/index.d.cts +243 -66
  70. package/dist/index.d.cts.map +1 -1
  71. package/dist/index.d.mts +4 -2
  72. package/dist/index.mjs +3 -2
  73. package/dist/utils/popover.d.mts +27 -0
  74. package/dist/utils/popover.d.mts.map +1 -0
  75. package/dist/utils/popover.mjs +142 -0
  76. package/dist/utils/popover.mjs.map +1 -0
  77. package/package.json +3 -3
package/dist/index.cjs CHANGED
@@ -1630,8 +1630,8 @@ LinkButton.displayName = "LinkButton";
1630
1630
  * <TextInput readOnly value="Cannot edit this" />
1631
1631
  * ```
1632
1632
  */
1633
- const TextInput = react.default.forwardRef(({ className, invalid, width, type = "text", ...props }, ref) => {
1634
- const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input", width && `dsn-text-input--width-${width}`, className);
1633
+ const TextInput = react.default.forwardRef(({ className, invalid, inlineSize, type = "text", ...props }, ref) => {
1634
+ const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input", inlineSize && `dsn-text-input--inline-size-${inlineSize}`, className);
1635
1635
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1636
1636
  ref,
1637
1637
  type,
@@ -1694,8 +1694,8 @@ FileInput.displayName = "FileInput";
1694
1694
  * <EmailInput invalid aria-invalid="true" aria-describedby="error" />
1695
1695
  * ```
1696
1696
  */
1697
- const EmailInput = react.default.forwardRef(({ className, invalid, width, autoComplete, ...props }, ref) => {
1698
- const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input", width && `dsn-text-input--width-${width}`, className);
1697
+ const EmailInput = react.default.forwardRef(({ className, invalid, inlineSize, autoComplete, ...props }, ref) => {
1698
+ const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input", inlineSize && `dsn-text-input--inline-size-${inlineSize}`, className);
1699
1699
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1700
1700
  ref,
1701
1701
  type: "email",
@@ -1731,8 +1731,8 @@ EmailInput.displayName = "EmailInput";
1731
1731
  * <PasswordInput invalid aria-invalid="true" aria-describedby="error" />
1732
1732
  * ```
1733
1733
  */
1734
- const PasswordInput = react.default.forwardRef(({ passwordAutocomplete = "current-password", className, invalid, width, autoComplete, ...props }, ref) => {
1735
- const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input", width && `dsn-text-input--width-${width}`, className);
1734
+ const PasswordInput = react.default.forwardRef(({ passwordAutocomplete = "current-password", className, invalid, inlineSize, autoComplete, ...props }, ref) => {
1735
+ const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input", inlineSize && `dsn-text-input--inline-size-${inlineSize}`, className);
1736
1736
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1737
1737
  ref,
1738
1738
  type: "password",
@@ -1762,8 +1762,8 @@ PasswordInput.displayName = "PasswordInput";
1762
1762
  * <NumberInput invalid aria-invalid="true" aria-describedby="error" />
1763
1763
  * ```
1764
1764
  */
1765
- const NumberInput = react.default.forwardRef(({ className, invalid, width, allowDecimals = false, ...props }, ref) => {
1766
- const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input", width && `dsn-text-input--width-${width}`, className);
1765
+ const NumberInput = react.default.forwardRef(({ className, invalid, inlineSize, allowDecimals = false, ...props }, ref) => {
1766
+ const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input", inlineSize && `dsn-text-input--inline-size-${inlineSize}`, className);
1767
1767
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1768
1768
  ref,
1769
1769
  type: "text",
@@ -1795,8 +1795,8 @@ NumberInput.displayName = "NumberInput";
1795
1795
  * <TelephoneInput invalid aria-invalid="true" aria-describedby="error" />
1796
1796
  * ```
1797
1797
  */
1798
- const TelephoneInput = react.default.forwardRef(({ className, invalid, width, autoComplete, ...props }, ref) => {
1799
- const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input", width && `dsn-text-input--width-${width}`, className);
1798
+ const TelephoneInput = react.default.forwardRef(({ className, invalid, inlineSize = "md", autoComplete, ...props }, ref) => {
1799
+ const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input", inlineSize && `dsn-text-input--inline-size-${inlineSize}`, className);
1800
1800
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1801
1801
  ref,
1802
1802
  type: "tel",
@@ -1828,8 +1828,8 @@ TelephoneInput.displayName = "TelephoneInput";
1828
1828
  * <SearchInput invalid aria-invalid="true" aria-describedby="error" />
1829
1829
  * ```
1830
1830
  */
1831
- const SearchInput = react.default.forwardRef(({ className, invalid, width, ...props }, ref) => {
1832
- const wrapperClasses = (0, _dsn_starter_kit_core.classNames)("dsn-search-input-wrapper", width && `dsn-search-input-wrapper--width-${width}`);
1831
+ const SearchInput = react.default.forwardRef(({ className, invalid, inlineSize, ...props }, ref) => {
1832
+ const wrapperClasses = (0, _dsn_starter_kit_core.classNames)("dsn-search-input-wrapper", inlineSize && `dsn-search-input-wrapper--inline-size-${inlineSize}`);
1833
1833
  const inputClasses = (0, _dsn_starter_kit_core.classNames)("dsn-text-input", "dsn-search-input", className);
1834
1834
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1835
1835
  className: wrapperClasses,
@@ -1852,7 +1852,7 @@ SearchInput.displayName = "SearchInput";
1852
1852
  /**
1853
1853
  * Time Input component
1854
1854
  * Time input with an interactive clock button at inline-end that opens the native time picker.
1855
- * Fixed width (sm) — not configurable, as time inputs have a predictable content width.
1855
+ * Fixed inline-size (sm): not configurable, as time inputs have a predictable content length.
1856
1856
  *
1857
1857
  * @example
1858
1858
  * ```tsx
@@ -1911,7 +1911,7 @@ TimeInput.displayName = "TimeInput";
1911
1911
  /**
1912
1912
  * Date Input component
1913
1913
  * Date input with an interactive calendar button at inline-end that opens the native date picker.
1914
- * Fixed width (sm) — not configurable, as date inputs have a predictable content width.
1914
+ * Fixed inline-size (md): not configurable, as date inputs have a predictable content length.
1915
1915
  *
1916
1916
  * @example
1917
1917
  * ```tsx
@@ -2024,7 +2024,7 @@ const DateInputGroup = react.default.forwardRef(({ className, value, onChange, i
2024
2024
  children: "Dag"
2025
2025
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NumberInput, {
2026
2026
  id: dayId,
2027
- width: "xs",
2027
+ inlineSize: "xs",
2028
2028
  value: value?.day ?? "",
2029
2029
  onChange: handleChange("day"),
2030
2030
  invalid,
@@ -2043,7 +2043,7 @@ const DateInputGroup = react.default.forwardRef(({ className, value, onChange, i
2043
2043
  children: "Maand"
2044
2044
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NumberInput, {
2045
2045
  id: monthId,
2046
- width: "xs",
2046
+ inlineSize: "xs",
2047
2047
  value: value?.month ?? "",
2048
2048
  onChange: handleChange("month"),
2049
2049
  invalid,
@@ -2062,7 +2062,7 @@ const DateInputGroup = react.default.forwardRef(({ className, value, onChange, i
2062
2062
  children: "Jaar"
2063
2063
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NumberInput, {
2064
2064
  id: yearId,
2065
- width: "sm",
2065
+ inlineSize: "sm",
2066
2066
  value: value?.year ?? "",
2067
2067
  onChange: handleChange("year"),
2068
2068
  invalid,
@@ -2102,15 +2102,15 @@ DateInputGroup.displayName = "DateInputGroup";
2102
2102
  * </Select>
2103
2103
  * </FormField>
2104
2104
  *
2105
- * // Width variant
2106
- * <Select width="lg">...</Select>
2105
+ * // Inline-size variant
2106
+ * <Select inlineSize="lg">...</Select>
2107
2107
  *
2108
2108
  * // Invalid state
2109
2109
  * <Select invalid aria-invalid="true" aria-describedby="error">...</Select>
2110
2110
  * ```
2111
2111
  */
2112
- const Select = react.default.forwardRef(({ className, invalid, width, disabled, children, ...props }, ref) => {
2113
- const wrapperClasses = (0, _dsn_starter_kit_core.classNames)("dsn-select-wrapper", width && `dsn-select-wrapper--width-${width}`);
2112
+ const Select = react.default.forwardRef(({ className, invalid, inlineSize, disabled, children, ...props }, ref) => {
2113
+ const wrapperClasses = (0, _dsn_starter_kit_core.classNames)("dsn-select-wrapper", inlineSize && `dsn-select-wrapper--inline-size-${inlineSize}`);
2114
2114
  const selectClasses = (0, _dsn_starter_kit_core.classNames)("dsn-text-input", "dsn-select", className);
2115
2115
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2116
2116
  className: wrapperClasses,
@@ -2154,8 +2154,8 @@ Select.displayName = "Select";
2154
2154
  * <TextArea readOnly value="View only" rows={3} />
2155
2155
  * ```
2156
2156
  */
2157
- const TextArea = react.default.forwardRef(({ className, invalid, width, rows = 4, ...props }, ref) => {
2158
- const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-area", width && `dsn-text-area--width-${width}`, className);
2157
+ const TextArea = react.default.forwardRef(({ className, invalid, inlineSize, rows = 4, ...props }, ref) => {
2158
+ const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-area", inlineSize && `dsn-text-area--inline-size-${inlineSize}`, className);
2159
2159
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
2160
2160
  ref,
2161
2161
  className: classes,
@@ -3562,14 +3562,28 @@ const Drawer = react.default.forwardRef(({ className, isOpen, onClose, modal = t
3562
3562
  const dialogRef = ref ?? internalRef;
3563
3563
  const headingId = react.default.useId();
3564
3564
  const headingRef = react.default.useRef(null);
3565
+ const popoverShownRef = react.default.useRef(false);
3566
+ const previousFocusRef = react.default.useRef(null);
3565
3567
  react.default.useEffect(() => {
3566
3568
  const dialog = dialogRef.current;
3567
3569
  if (!dialog) return;
3568
- if (isOpen && !dialog.open) {
3570
+ const isShown = dialog.open || popoverShownRef.current;
3571
+ if (isOpen && !isShown) {
3569
3572
  if (modal) dialog.showModal();
3570
- else dialog.show();
3573
+ else {
3574
+ previousFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
3575
+ dialog.showPopover();
3576
+ popoverShownRef.current = true;
3577
+ }
3571
3578
  (headingRef.current ?? dialog).focus();
3572
- } else if (!isOpen && dialog.open) dialog.close();
3579
+ } else if (!isOpen && isShown) {
3580
+ if (popoverShownRef.current) {
3581
+ const focusWasInside = dialog.contains(document.activeElement);
3582
+ dialog.hidePopover();
3583
+ popoverShownRef.current = false;
3584
+ if (focusWasInside) previousFocusRef.current?.focus();
3585
+ } else dialog.close();
3586
+ }
3573
3587
  }, [
3574
3588
  isOpen,
3575
3589
  modal,
@@ -3616,6 +3630,7 @@ const Drawer = react.default.forwardRef(({ className, isOpen, onClose, modal = t
3616
3630
  "aria-labelledby": headingId,
3617
3631
  onCancel: handleCancel,
3618
3632
  tabIndex: -1,
3633
+ popover: modal ? void 0 : "manual",
3619
3634
  ...props,
3620
3635
  children
3621
3636
  })
@@ -3697,6 +3712,10 @@ const DrawerFooter = react.default.forwardRef(({ className, children, ...props }
3697
3712
  DrawerFooter.displayName = "DrawerFooter";
3698
3713
  //#endregion
3699
3714
  //#region src/PageHeader/PageHeader.tsx
3715
+ /** Auto-hide: boven deze scrollpositie (px) blijft de header altijd zichtbaar */
3716
+ const AUTO_HIDE_OFFSET = 100;
3717
+ /** Auto-hide: zoveel px omhoog scrollen voordat de header terugkomt */
3718
+ const AUTO_HIDE_REVEAL_DISTANCE = 64;
3700
3719
  /**
3701
3720
  * PageHeader component
3702
3721
  * Primaire navigatieheader voor een pagina. Mobile-first implementatie.
@@ -3744,11 +3763,24 @@ const PageHeader = react.default.forwardRef(({ className, logoSlot, sticky = "no
3744
3763
  react.default.useEffect(() => {
3745
3764
  if (sticky !== "auto-hide") return;
3746
3765
  let lastScrollY = window.scrollY;
3766
+ let scrolledUp = 0;
3747
3767
  const handleScroll = () => {
3748
3768
  const currentScrollY = window.scrollY;
3749
- const isScrollingDown = currentScrollY > lastScrollY && currentScrollY > 100;
3750
- combinedRef.current?.setAttribute("data-hidden", String(isScrollingDown));
3769
+ const delta = currentScrollY - lastScrollY;
3751
3770
  lastScrollY = currentScrollY;
3771
+ let hidden;
3772
+ if (currentScrollY <= AUTO_HIDE_OFFSET) {
3773
+ hidden = false;
3774
+ scrolledUp = 0;
3775
+ } else if (delta > 0) {
3776
+ hidden = true;
3777
+ scrolledUp = 0;
3778
+ } else if (delta < 0) {
3779
+ scrolledUp -= delta;
3780
+ if (scrolledUp < AUTO_HIDE_REVEAL_DISTANCE) return;
3781
+ hidden = false;
3782
+ } else return;
3783
+ combinedRef.current?.setAttribute("data-hidden", String(hidden));
3752
3784
  };
3753
3785
  window.addEventListener("scroll", handleScroll, { passive: true });
3754
3786
  return () => window.removeEventListener("scroll", handleScroll);
@@ -4494,22 +4526,29 @@ Image.displayName = "Image";
4494
4526
  const CardContext = react.default.createContext({});
4495
4527
  /**
4496
4528
  * Card component
4497
- * Configureerbare container voor gestructureerde content met header, body en footer.
4498
- * Gebruikt een stretched-link techniek: de link in `CardHeading` dekt de volledige card.
4499
- * Screenreaders lezen alleen de heading-tekst als linknaam.
4529
+ * Configureerbare container met vier optionele secties: `CardPreHeader`,
4530
+ * `CardHeader`, `CardBody` en `CardFooter` (zie DR-2026-11).
4531
+ *
4532
+ * Zet `CardHeader` in de JSX altijd vóór `CardPreHeader`: zo kondigt een
4533
+ * screenreader de heading eerst aan. De CSS zet de pre-header visueel bovenaan.
4534
+ *
4535
+ * Met `href` wordt de heading een stretched link: de link dekt de volledige
4536
+ * card, en screenreaders lezen alleen de heading-tekst als linknaam.
4500
4537
  *
4501
4538
  * @example
4502
4539
  * ```tsx
4503
4540
  * <Card href="/artikel/slug">
4504
4541
  * <CardHeader>
4505
- * <Image src="/foto.jpg" alt="" width={800} height={450} ratio="16:9" />
4542
+ * <CardHeading level={2}>Artikeltitel</CardHeading>
4506
4543
  * </CardHeader>
4544
+ * <CardPreHeader>
4545
+ * <Image src="/foto.jpg" alt="" width={800} height={450} ratio="16:9" />
4546
+ * </CardPreHeader>
4507
4547
  * <CardBody>
4508
- * <CardHeading level={2}>Artikeltitel</CardHeading>
4509
4548
  * <Paragraph>Korte beschrijving.</Paragraph>
4510
4549
  * </CardBody>
4511
4550
  * <CardFooter>
4512
- * <Link href="/artikel/slug" aria-hidden tabIndex={-1}>Lees meer</Link>
4551
+ * <CardAffordance>Lees meer</CardAffordance>
4513
4552
  * </CardFooter>
4514
4553
  * </Card>
4515
4554
  * ```
@@ -4527,13 +4566,14 @@ const Card = react.default.forwardRef(({ className, href, children, ...props },
4527
4566
  });
4528
4567
  Card.displayName = "Card";
4529
4568
  /**
4530
- * CardHeader sub-component
4569
+ * CardPreHeader sub-component
4570
+ * Staat in de DOM ná `CardHeader` en komt visueel bovenaan via `order: -1`.
4531
4571
  * Zonder children → toont automatisch een afbeeldingsplaceholder.
4532
4572
  */
4533
- const CardHeader = react.default.forwardRef(({ className, children, ...props }, ref) => {
4573
+ const CardPreHeader = react.default.forwardRef(({ className, children, ...props }, ref) => {
4534
4574
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4535
4575
  ref,
4536
- className: (0, _dsn_starter_kit_core.classNames)("dsn-card__header", className),
4576
+ className: (0, _dsn_starter_kit_core.classNames)("dsn-card__pre-header", className),
4537
4577
  ...props,
4538
4578
  children: children ? children : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4539
4579
  className: "dsn-card__image-placeholder",
@@ -4541,10 +4581,24 @@ const CardHeader = react.default.forwardRef(({ className, children, ...props },
4541
4581
  })
4542
4582
  });
4543
4583
  });
4584
+ CardPreHeader.displayName = "CardPreHeader";
4585
+ /**
4586
+ * CardHeader sub-component
4587
+ * Bevat de heading of het label van de card. Zet hem in de JSX vóór
4588
+ * `CardPreHeader`.
4589
+ */
4590
+ const CardHeader = react.default.forwardRef(({ className, children, ...props }, ref) => {
4591
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4592
+ ref,
4593
+ className: (0, _dsn_starter_kit_core.classNames)("dsn-card__header", className),
4594
+ ...props,
4595
+ children
4596
+ });
4597
+ });
4544
4598
  CardHeader.displayName = "CardHeader";
4545
4599
  /**
4546
4600
  * CardBody sub-component
4547
- * Groeit via `flex: 1` zodat de footer altijd onderaan uitlijnt.
4601
+ * Inhoudssectie onder de header.
4548
4602
  */
4549
4603
  const CardBody = react.default.forwardRef(({ className, children, ...props }, ref) => {
4550
4604
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -4558,7 +4612,7 @@ CardBody.displayName = "CardBody";
4558
4612
  /**
4559
4613
  * CardHeading sub-component
4560
4614
  * Ontvangt `href` automatisch via React context van de parent `Card`.
4561
- * Wanneer `href` beschikbaar is, wraps de heading-tekst in een `<a class="dsn-card-heading__link">`.
4615
+ * Wanneer `href` beschikbaar is, staat de heading-tekst in een `<a class="dsn-card__link">`.
4562
4616
  * Het `::before` pseudo-element dekt de volledige card (stretched link).
4563
4617
  */
4564
4618
  const CardHeading = react.default.forwardRef(({ className, level = 2, children, ...props }, ref) => {
@@ -4566,21 +4620,67 @@ const CardHeading = react.default.forwardRef(({ className, level = 2, children,
4566
4620
  const Tag = `h${level}`;
4567
4621
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tag, {
4568
4622
  ref,
4569
- className: (0, _dsn_starter_kit_core.classNames)("dsn-card-heading", className),
4623
+ className: (0, _dsn_starter_kit_core.classNames)("dsn-card__heading", className),
4570
4624
  ...props,
4571
4625
  children: href ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
4572
4626
  href,
4573
- className: "dsn-card-heading__link",
4627
+ className: "dsn-card__link",
4574
4628
  children
4575
4629
  }) : children
4576
4630
  });
4577
4631
  });
4578
4632
  CardHeading.displayName = "CardHeading";
4579
4633
  /**
4634
+ * CardLabel sub-component
4635
+ * Gebruik in plaats van `CardHeading` wanneer de card geen nieuw onderwerp
4636
+ * introduceert, zoals bij login-opties of instellingen. Ontvangt `href` via
4637
+ * context, net als `CardHeading`.
4638
+ */
4639
+ const CardLabel = react.default.forwardRef(({ className, children, ...props }, ref) => {
4640
+ const { href } = react.default.useContext(CardContext);
4641
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4642
+ ref,
4643
+ className: (0, _dsn_starter_kit_core.classNames)("dsn-card__label", className),
4644
+ ...props,
4645
+ children: href ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
4646
+ href,
4647
+ className: "dsn-card__link",
4648
+ children
4649
+ }) : children
4650
+ });
4651
+ });
4652
+ CardLabel.displayName = "CardLabel";
4653
+ /**
4654
+ * CardDescription sub-component
4655
+ * Korte omschrijving met eigen typografie-tokens.
4656
+ */
4657
+ const CardDescription = react.default.forwardRef(({ className, children, ...props }, ref) => {
4658
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4659
+ ref,
4660
+ className: (0, _dsn_starter_kit_core.classNames)("dsn-card__description", className),
4661
+ ...props,
4662
+ children
4663
+ });
4664
+ });
4665
+ CardDescription.displayName = "CardDescription";
4666
+ /**
4667
+ * CardMeta sub-component
4668
+ * Aanvullende gegevens bij de card, zoals een datum.
4669
+ */
4670
+ const CardMeta = react.default.forwardRef(({ className, children, ...props }, ref) => {
4671
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4672
+ ref,
4673
+ className: (0, _dsn_starter_kit_core.classNames)("dsn-card__meta", className),
4674
+ ...props,
4675
+ children
4676
+ });
4677
+ });
4678
+ CardMeta.displayName = "CardMeta";
4679
+ /**
4580
4680
  * CardFooter sub-component
4581
- * Directe kinderen staan boven de stretched link via `z-index: 2` in CSS.
4582
- * Gebruik `aria-hidden` + `tabIndex={-1}` op de link wanneer deze dezelfde
4583
- * bestemming heeft als de card — vermijdt een dubbele tabstop.
4681
+ * Staat altijd onderaan de card. Links en buttons staan boven de stretched
4682
+ * link en blijven zelfstandig klikbaar. Voor een visuele "Lees meer" naar
4683
+ * dezelfde bestemming als de card: gebruik `CardAffordance`.
4584
4684
  */
4585
4685
  const CardFooter = react.default.forwardRef(({ className, children, ...props }, ref) => {
4586
4686
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -4592,6 +4692,21 @@ const CardFooter = react.default.forwardRef(({ className, children, ...props },
4592
4692
  });
4593
4693
  CardFooter.displayName = "CardFooter";
4594
4694
  /**
4695
+ * CardAffordance sub-component
4696
+ * Een `<span aria-hidden="true">` die eruitziet als een link. De stretched
4697
+ * link vangt de klik al af, dus er is geen tweede tabstop nodig.
4698
+ */
4699
+ const CardAffordance = react.default.forwardRef(({ className, children, ...props }, ref) => {
4700
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4701
+ ref,
4702
+ className: (0, _dsn_starter_kit_core.classNames)("dsn-card__affordance", className),
4703
+ "aria-hidden": "true",
4704
+ ...props,
4705
+ children
4706
+ });
4707
+ });
4708
+ CardAffordance.displayName = "CardAffordance";
4709
+ /**
4595
4710
  * CardGroup sub-component
4596
4711
  * Flexbox wrapper die gelijke hoogte garandeert en de footer in elke card onderaan uitlijnt.
4597
4712
  * Rendert `role="list"` wanneer `as="ul"` — nodig omdat CSS-resets de lijstsemantiek verwijderen.
@@ -4611,6 +4726,7 @@ CardGroup.displayName = "CardGroup";
4611
4726
  //#region src/ModalDialog/ModalDialog.tsx
4612
4727
  const ModalDialogContext = react.default.createContext({
4613
4728
  headingId: "",
4729
+ bodyId: "",
4614
4730
  headingRef: { current: null }
4615
4731
  });
4616
4732
  /**
@@ -4624,7 +4740,7 @@ const ModalDialogContext = react.default.createContext({
4624
4740
  *
4625
4741
  * @example
4626
4742
  * ```tsx
4627
- * <ModalDialog isOpen={isOpen} onClose={() => setIsOpen(false)}>
4743
+ * <ModalDialog alert isOpen={isOpen} onClose={() => setIsOpen(false)}>
4628
4744
  * <ModalDialogHeader>
4629
4745
  * <ModalDialogHeading>Bevestig verwijderen</ModalDialogHeading>
4630
4746
  * </ModalDialogHeader>
@@ -4633,17 +4749,18 @@ const ModalDialogContext = react.default.createContext({
4633
4749
  * </ModalDialogBody>
4634
4750
  * <ModalDialogFooter>
4635
4751
  * <ActionGroup>
4636
- * <Button variant="negative" onClick={() => setIsOpen(false)}>Verwijderen</Button>
4752
+ * <Button variant="strong-negative" onClick={() => setIsOpen(false)}>Verwijderen</Button>
4637
4753
  * <Button variant="default" onClick={() => setIsOpen(false)}>Annuleren</Button>
4638
4754
  * </ActionGroup>
4639
4755
  * </ModalDialogFooter>
4640
4756
  * </ModalDialog>
4641
4757
  * ```
4642
4758
  */
4643
- const ModalDialog = react.default.forwardRef(({ className, isOpen, onClose, triggerRef, children, ...props }, ref) => {
4759
+ const ModalDialog = react.default.forwardRef(({ className, isOpen, onClose, triggerRef, alert = false, children, ...props }, ref) => {
4644
4760
  const internalRef = react.default.useRef(null);
4645
4761
  const dialogRef = ref ?? internalRef;
4646
4762
  const headingId = react.default.useId();
4763
+ const bodyId = react.default.useId();
4647
4764
  const headingRef = react.default.useRef(null);
4648
4765
  react.default.useEffect(() => {
4649
4766
  const dialog = dialogRef.current;
@@ -4670,13 +4787,16 @@ const ModalDialog = react.default.forwardRef(({ className, isOpen, onClose, trig
4670
4787
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModalDialogContext.Provider, {
4671
4788
  value: {
4672
4789
  headingId,
4790
+ bodyId,
4673
4791
  headingRef,
4674
4792
  onClose
4675
4793
  },
4676
4794
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dialog", {
4677
4795
  ref: dialogRef,
4678
4796
  className: classes,
4797
+ role: alert ? "alertdialog" : void 0,
4679
4798
  "aria-labelledby": headingId,
4799
+ "aria-describedby": alert ? bodyId : void 0,
4680
4800
  onCancel: handleCancel,
4681
4801
  tabIndex: -1,
4682
4802
  ...props,
@@ -4737,8 +4857,10 @@ ModalDialogHeading.displayName = "ModalDialogHeading";
4737
4857
  * De scrollbare inhoudssectie van het dialoogvenster met scroll-affordance schaduw.
4738
4858
  */
4739
4859
  const ModalDialogBody = react.default.forwardRef(({ className, children, ...props }, ref) => {
4860
+ const { bodyId } = react.default.useContext(ModalDialogContext);
4740
4861
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4741
4862
  ref,
4863
+ id: bodyId,
4742
4864
  className: (0, _dsn_starter_kit_core.classNames)("dsn-modal-dialog__body", className),
4743
4865
  ...props,
4744
4866
  children
@@ -4759,7 +4881,7 @@ const ModalDialogFooter = react.default.forwardRef(({ className, children, ...pr
4759
4881
  });
4760
4882
  ModalDialogFooter.displayName = "ModalDialogFooter";
4761
4883
  //#endregion
4762
- //#region src/Popover/Popover.tsx
4884
+ //#region src/utils/popover.ts
4763
4885
  const GAP = 4;
4764
4886
  function positionPopover(popover, trigger, placement) {
4765
4887
  const triggerRect = trigger.getBoundingClientRect();
@@ -4812,39 +4934,32 @@ function focusFirstInteractive(container) {
4812
4934
  if (first) first.focus();
4813
4935
  else container.focus();
4814
4936
  }
4815
- const PopoverContext = react.default.createContext({ headingId: "" });
4816
4937
  /**
4817
- * Popover component
4818
- * Lichtgewicht, contextgebonden overlay verankerd aan een triggerelement.
4819
- *
4820
- * Gebaseerd op de HTML Popover API (`popover="auto"`) voor ingebakken
4821
- * light-dismiss en top-layer gedrag. Positionering via JavaScript.
4822
- *
4823
- * @example
4824
- * ```tsx
4825
- * const triggerRef = useRef<HTMLButtonElement>(null);
4826
- * const [isOpen, setIsOpen] = useState(false);
4827
- *
4828
- * <Button ref={triggerRef} onClick={() => setIsOpen(true)}>Opties</Button>
4829
- * <Popover isOpen={isOpen} onClose={() => setIsOpen(false)} triggerRef={triggerRef} label="Opties">
4830
- * <PopoverBody>
4831
- * <Menu>...</Menu>
4832
- * </PopoverBody>
4833
- * </Popover>
4834
- * ```
4938
+ * Opent en sluit een element met `popover="auto"` synchroon met `isOpen`,
4939
+ * positioneert het bij de trigger en houdt `aria-expanded` op de trigger bij.
4940
+ *
4941
+ * Bij openen gaat de focus naar `initialFocusRef` (of de popover zelf als die
4942
+ * ref leeg is), en anders naar het eerste interactieve element. Bij sluiten
4943
+ * gaat de focus alleen terug naar de trigger wanneer dat zinvol is: als de
4944
+ * focus op dat moment nog in de popover stond (Escape, een sluitknop, een
4945
+ * actie in de popover). Klikt de gebruiker ergens anders, dan blijft de focus
4946
+ * daar; terugspringen naar de trigger zou die klik tenietdoen.
4835
4947
  */
4836
- const Popover = react.default.forwardRef(({ className, isOpen, onClose, triggerRef, placement = "bottom", label, children, ...props }, ref) => {
4837
- const internalRef = react.default.useRef(null);
4838
- const popoverRef = ref ?? internalRef;
4839
- const headingId = react.default.useId();
4948
+ function usePopover({ popoverRef, triggerRef, isOpen, onClose, placement, initialFocusRef }) {
4949
+ const restoreFocusRef = react.default.useRef(false);
4950
+ const dismissedByPointerRef = react.default.useRef(false);
4951
+ const onCloseRef = react.default.useRef(onClose);
4952
+ onCloseRef.current = onClose;
4840
4953
  react.default.useEffect(() => {
4841
4954
  const el = popoverRef.current;
4842
4955
  if (!el) return;
4843
4956
  if (isOpen) {
4957
+ dismissedByPointerRef.current = false;
4844
4958
  el.showPopover();
4845
4959
  const trigger = triggerRef.current;
4846
4960
  if (trigger) positionPopover(el, trigger, placement);
4847
- focusFirstInteractive(el);
4961
+ if (initialFocusRef) (initialFocusRef.current ?? el).focus();
4962
+ else focusFirstInteractive(el);
4848
4963
  } else try {
4849
4964
  el.hidePopover();
4850
4965
  } catch {}
@@ -4852,7 +4967,8 @@ const Popover = react.default.forwardRef(({ className, isOpen, onClose, triggerR
4852
4967
  isOpen,
4853
4968
  placement,
4854
4969
  triggerRef,
4855
- popoverRef
4970
+ popoverRef,
4971
+ initialFocusRef
4856
4972
  ]);
4857
4973
  react.default.useEffect(() => {
4858
4974
  const trigger = triggerRef.current;
@@ -4862,19 +4978,23 @@ const Popover = react.default.forwardRef(({ className, isOpen, onClose, triggerR
4862
4978
  trigger.setAttribute("aria-expanded", "false");
4863
4979
  };
4864
4980
  }, [isOpen, triggerRef]);
4865
- const onCloseRef = react.default.useRef(onClose);
4866
- onCloseRef.current = onClose;
4867
4981
  react.default.useEffect(() => {
4868
4982
  const el = popoverRef.current;
4869
4983
  if (!el) return;
4984
+ const handleBeforeToggle = (event) => {
4985
+ if (event.newState === "closed") restoreFocusRef.current = !dismissedByPointerRef.current && el.contains(document.activeElement);
4986
+ };
4870
4987
  const handleToggle = (event) => {
4871
4988
  if (event.newState === "closed") {
4872
4989
  onCloseRef.current?.();
4873
- triggerRef.current?.focus();
4990
+ if (restoreFocusRef.current) triggerRef.current?.focus();
4991
+ restoreFocusRef.current = false;
4874
4992
  }
4875
4993
  };
4994
+ el.addEventListener("beforetoggle", handleBeforeToggle);
4876
4995
  el.addEventListener("toggle", handleToggle);
4877
4996
  return () => {
4997
+ el.removeEventListener("beforetoggle", handleBeforeToggle);
4878
4998
  el.removeEventListener("toggle", handleToggle);
4879
4999
  };
4880
5000
  }, [triggerRef, popoverRef]);
@@ -4885,8 +5005,8 @@ const Popover = react.default.forwardRef(({ className, isOpen, onClose, triggerR
4885
5005
  const handlePointerDown = (event) => {
4886
5006
  const target = event.target;
4887
5007
  if (el.contains(target) || triggerRef.current?.contains(target)) return;
5008
+ dismissedByPointerRef.current = true;
4888
5009
  onCloseRef.current?.();
4889
- triggerRef.current?.focus();
4890
5010
  };
4891
5011
  document.addEventListener("pointerdown", handlePointerDown);
4892
5012
  return () => {
@@ -4897,11 +5017,57 @@ const Popover = react.default.forwardRef(({ className, isOpen, onClose, triggerR
4897
5017
  triggerRef,
4898
5018
  popoverRef
4899
5019
  ]);
5020
+ }
5021
+ //#endregion
5022
+ //#region src/Popover/Popover.tsx
5023
+ const PopoverContext = react.default.createContext({
5024
+ headingId: "",
5025
+ headingRef: { current: null }
5026
+ });
5027
+ /**
5028
+ * Popover component
5029
+ * Niet-modaal dialoogvenster verankerd aan een triggerelement
5030
+ * (`role="dialog"`, `aria-modal="false"`).
5031
+ *
5032
+ * Gebaseerd op de HTML Popover API (`popover="auto"`) voor ingebakken
5033
+ * light-dismiss en top-layer gedrag. Positionering via JavaScript.
5034
+ *
5035
+ * Voor een lijst met acties of links: gebruik `PopoverMenu`. Een lijst is
5036
+ * geen dialoogvenster.
5037
+ *
5038
+ * @example
5039
+ * ```tsx
5040
+ * const triggerRef = useRef<HTMLButtonElement>(null);
5041
+ * const [isOpen, setIsOpen] = useState(false);
5042
+ *
5043
+ * <Button ref={triggerRef} onClick={() => setIsOpen((v) => !v)}>Filters</Button>
5044
+ * <Popover isOpen={isOpen} onClose={() => setIsOpen(false)} triggerRef={triggerRef}>
5045
+ * <PopoverHeader>
5046
+ * <PopoverHeading>Filters</PopoverHeading>
5047
+ * </PopoverHeader>
5048
+ * <PopoverBody>...</PopoverBody>
5049
+ * </Popover>
5050
+ * ```
5051
+ */
5052
+ const Popover = react.default.forwardRef(({ className, isOpen, onClose, triggerRef, placement = "bottom", label, children, ...props }, ref) => {
5053
+ const internalRef = react.default.useRef(null);
5054
+ const popoverRef = ref ?? internalRef;
5055
+ const headingId = react.default.useId();
5056
+ const headingRef = react.default.useRef(null);
5057
+ usePopover({
5058
+ popoverRef,
5059
+ triggerRef,
5060
+ isOpen,
5061
+ onClose,
5062
+ placement,
5063
+ initialFocusRef: headingRef
5064
+ });
4900
5065
  const classes = (0, _dsn_starter_kit_core.classNames)("dsn-popover", `dsn-popover--placement-${placement}`, className);
4901
5066
  const ariaProps = label ? { "aria-label": label } : { "aria-labelledby": headingId };
4902
5067
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PopoverContext.Provider, {
4903
5068
  value: {
4904
5069
  headingId,
5070
+ headingRef,
4905
5071
  onClose
4906
5072
  },
4907
5073
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -4945,14 +5111,21 @@ PopoverHeader.displayName = "PopoverHeader";
4945
5111
  /**
4946
5112
  * PopoverHeading
4947
5113
  * De heading van de popover. ID wordt automatisch gegenereerd voor aria-labelledby.
5114
+ * Krijgt `tabindex="-1"` zodat de Popover er bij openen de focus op kan zetten.
4948
5115
  */
4949
5116
  const PopoverHeading = react.default.forwardRef(({ className, level = 2, children, ...props }, ref) => {
4950
- const { headingId } = react.default.useContext(PopoverContext);
5117
+ const { headingId, headingRef } = react.default.useContext(PopoverContext);
4951
5118
  const Tag = `h${level}`;
5119
+ const setRef = react.default.useCallback((node) => {
5120
+ headingRef.current = node;
5121
+ if (typeof ref === "function") ref(node);
5122
+ else if (ref) ref.current = node;
5123
+ }, [headingRef, ref]);
4952
5124
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tag, {
4953
- ref,
5125
+ ref: setRef,
4954
5126
  id: headingId,
4955
5127
  className: (0, _dsn_starter_kit_core.classNames)("dsn-popover-heading", className),
5128
+ tabIndex: -1,
4956
5129
  ...props,
4957
5130
  children
4958
5131
  });
@@ -4985,6 +5158,63 @@ const PopoverFooter = react.default.forwardRef(({ className, children, ...props
4985
5158
  });
4986
5159
  PopoverFooter.displayName = "PopoverFooter";
4987
5160
  //#endregion
5161
+ //#region src/PopoverMenu/PopoverMenu.tsx
5162
+ const ITEM_SELECTOR = ".dsn-menu-button__button, .dsn-menu-link__link";
5163
+ /**
5164
+ * PopoverMenu component
5165
+ * Lijst met acties of links in een zwevend paneel, geopend vanuit een
5166
+ * triggerknop.
5167
+ *
5168
+ * Anders dan `Popover` is dit géén dialoogvenster: het paneel heeft geen rol,
5169
+ * de inhoud is een gewone lijst (`<ul role="list">`). Ook bewust geen
5170
+ * `role="menu"`: die rol belooft pijltjesnavigatie en zet screenreaders in
5171
+ * een applicatiemodus. De context komt uit het label van de trigger.
5172
+ *
5173
+ * Het menu sluit zichzelf zodra een item wordt geactiveerd, en zet de focus
5174
+ * dan terug op de trigger.
5175
+ *
5176
+ * @example
5177
+ * ```tsx
5178
+ * const triggerRef = useRef<HTMLButtonElement>(null);
5179
+ * const [isOpen, setIsOpen] = useState(false);
5180
+ *
5181
+ * <Button ref={triggerRef} onClick={() => setIsOpen((v) => !v)}>Acties</Button>
5182
+ * <PopoverMenu isOpen={isOpen} onClose={() => setIsOpen(false)} triggerRef={triggerRef}>
5183
+ * <MenuButton onClick={edit}>Bewerken</MenuButton>
5184
+ * <MenuButton onClick={duplicate}>Dupliceren</MenuButton>
5185
+ * </PopoverMenu>
5186
+ * ```
5187
+ */
5188
+ const PopoverMenu = react.default.forwardRef(({ className, isOpen, onClose, triggerRef, placement = "bottom", iconStart = false, onClick, children, ...props }, ref) => {
5189
+ const internalRef = react.default.useRef(null);
5190
+ const popoverRef = ref ?? internalRef;
5191
+ usePopover({
5192
+ popoverRef,
5193
+ triggerRef,
5194
+ isOpen,
5195
+ onClose,
5196
+ placement
5197
+ });
5198
+ const handleClick = (event) => {
5199
+ onClick?.(event);
5200
+ if (event.target.closest(ITEM_SELECTOR)) onClose?.();
5201
+ };
5202
+ const classes = (0, _dsn_starter_kit_core.classNames)("dsn-popover-menu", `dsn-popover-menu--placement-${placement}`, className);
5203
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5204
+ ref: popoverRef,
5205
+ popover: "auto",
5206
+ className: classes,
5207
+ onClick: handleClick,
5208
+ ...props,
5209
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Menu, {
5210
+ role: "list",
5211
+ iconStart,
5212
+ children
5213
+ })
5214
+ });
5215
+ });
5216
+ PopoverMenu.displayName = "PopoverMenu";
5217
+ //#endregion
4988
5218
  //#region src/File/File.tsx
4989
5219
  /**
4990
5220
  * File component
@@ -5181,11 +5411,16 @@ exports.BreakoutSection = BreakoutSection;
5181
5411
  exports.Button = Button;
5182
5412
  exports.ButtonLink = ButtonLink;
5183
5413
  exports.Card = Card;
5414
+ exports.CardAffordance = CardAffordance;
5184
5415
  exports.CardBody = CardBody;
5416
+ exports.CardDescription = CardDescription;
5185
5417
  exports.CardFooter = CardFooter;
5186
5418
  exports.CardGroup = CardGroup;
5187
5419
  exports.CardHeader = CardHeader;
5188
5420
  exports.CardHeading = CardHeading;
5421
+ exports.CardLabel = CardLabel;
5422
+ exports.CardMeta = CardMeta;
5423
+ exports.CardPreHeader = CardPreHeader;
5189
5424
  exports.Checkbox = Checkbox;
5190
5425
  exports.CheckboxGroup = CheckboxGroup;
5191
5426
  exports.CheckboxOption = CheckboxOption;
@@ -5246,6 +5481,7 @@ exports.PopoverBody = PopoverBody;
5246
5481
  exports.PopoverFooter = PopoverFooter;
5247
5482
  exports.PopoverHeader = PopoverHeader;
5248
5483
  exports.PopoverHeading = PopoverHeading;
5484
+ exports.PopoverMenu = PopoverMenu;
5249
5485
  exports.PreHeading = PreHeading;
5250
5486
  exports.ProgressBar = ProgressBar;
5251
5487
  exports.Radio = Radio;