@dsn-starter-kit/components-react 3.4.0 → 4.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.
- package/dist/Card/Card.d.mts +86 -21
- package/dist/Card/Card.d.mts.map +1 -1
- package/dist/Card/Card2.mjs +100 -17
- package/dist/Card/Card2.mjs.map +1 -1
- package/dist/Card/index.d.mts +2 -2
- package/dist/DateInput/DateInput.d.mts +1 -1
- package/dist/DateInput/DateInput.d.mts.map +1 -1
- package/dist/DateInput/DateInput2.mjs +1 -2
- package/dist/DateInput/DateInput2.mjs.map +1 -1
- package/dist/DateInputGroup/DateInputGroup2.mjs +3 -3
- package/dist/DateInputGroup/DateInputGroup2.mjs.map +1 -1
- package/dist/Drawer/Drawer.d.mts +11 -3
- package/dist/Drawer/Drawer.d.mts.map +1 -1
- package/dist/Drawer/Drawer2.mjs +28 -4
- package/dist/Drawer/Drawer2.mjs.map +1 -1
- package/dist/EmailInput/EmailInput.d.mts +10 -5
- package/dist/EmailInput/EmailInput.d.mts.map +1 -1
- package/dist/EmailInput/EmailInput2.mjs +2 -2
- package/dist/EmailInput/EmailInput2.mjs.map +1 -1
- package/dist/ModalDialog/ModalDialog.d.mts +12 -2
- package/dist/ModalDialog/ModalDialog.d.mts.map +1 -1
- package/dist/ModalDialog/ModalDialog2.mjs +35 -8
- package/dist/ModalDialog/ModalDialog2.mjs.map +1 -1
- package/dist/NumberInput/NumberInput.d.mts +4 -4
- package/dist/NumberInput/NumberInput.d.mts.map +1 -1
- package/dist/NumberInput/NumberInput2.mjs +2 -2
- package/dist/NumberInput/NumberInput2.mjs.map +1 -1
- package/dist/PageHeader/PageHeader.d.mts.map +1 -1
- package/dist/PageHeader/PageHeader2.mjs +20 -2
- package/dist/PageHeader/PageHeader2.mjs.map +1 -1
- package/dist/PasswordInput/PasswordInput.d.mts +10 -5
- package/dist/PasswordInput/PasswordInput.d.mts.map +1 -1
- package/dist/PasswordInput/PasswordInput2.mjs +2 -2
- package/dist/PasswordInput/PasswordInput2.mjs.map +1 -1
- package/dist/SearchInput/SearchInput.d.mts +10 -5
- package/dist/SearchInput/SearchInput.d.mts.map +1 -1
- package/dist/SearchInput/SearchInput2.mjs +2 -3
- package/dist/SearchInput/SearchInput2.mjs.map +1 -1
- package/dist/Select/Select.d.mts +6 -6
- package/dist/Select/Select.d.mts.map +1 -1
- package/dist/Select/Select2.mjs +4 -5
- package/dist/Select/Select2.mjs.map +1 -1
- package/dist/TelephoneInput/TelephoneInput.d.mts +10 -5
- package/dist/TelephoneInput/TelephoneInput.d.mts.map +1 -1
- package/dist/TelephoneInput/TelephoneInput2.mjs +2 -2
- package/dist/TelephoneInput/TelephoneInput2.mjs.map +1 -1
- package/dist/TextArea/TextArea.d.mts +10 -5
- package/dist/TextArea/TextArea.d.mts.map +1 -1
- package/dist/TextArea/TextArea2.mjs +2 -2
- package/dist/TextArea/TextArea2.mjs.map +1 -1
- package/dist/TextInput/TextInput.d.mts +4 -4
- package/dist/TextInput/TextInput.d.mts.map +1 -1
- package/dist/TextInput/TextInput2.mjs +2 -2
- package/dist/TextInput/TextInput2.mjs.map +1 -1
- package/dist/TimeInput/TimeInput.d.mts +1 -1
- package/dist/TimeInput/TimeInput.d.mts.map +1 -1
- package/dist/TimeInput/TimeInput2.mjs +1 -2
- package/dist/TimeInput/TimeInput2.mjs.map +1 -1
- package/dist/index.cjs +303 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +5439 -3838
- package/dist/index.d.cts +163 -55
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/utils/focusTrap.mjs +99 -0
- package/dist/utils/focusTrap.mjs.map +1 -0
- 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,
|
|
1634
|
-
const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input",
|
|
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,
|
|
1698
|
-
const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input",
|
|
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,
|
|
1735
|
-
const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input",
|
|
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,
|
|
1766
|
-
const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input",
|
|
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,
|
|
1799
|
-
const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-input",
|
|
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,
|
|
1832
|
-
const wrapperClasses = (0, _dsn_starter_kit_core.classNames)("dsn-search-input-wrapper",
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
* //
|
|
2106
|
-
* <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,
|
|
2113
|
-
const wrapperClasses = (0, _dsn_starter_kit_core.classNames)("dsn-select-wrapper",
|
|
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,
|
|
2158
|
-
const classes = (0, _dsn_starter_kit_core.classNames)("dsn-text-area",
|
|
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,
|
|
@@ -3431,8 +3431,106 @@ const PageFooter = react.default.forwardRef(({ className, slot1, slot2, slot3, s
|
|
|
3431
3431
|
});
|
|
3432
3432
|
PageFooter.displayName = "PageFooter";
|
|
3433
3433
|
//#endregion
|
|
3434
|
+
//#region src/utils/focusTrap.ts
|
|
3435
|
+
/**
|
|
3436
|
+
* Focus-trap hulpfuncties voor dialoogachtige componenten.
|
|
3437
|
+
*
|
|
3438
|
+
* Gebaseerd op de techniek van Hidde de Vries:
|
|
3439
|
+
* https://hidde.blog/using-javascript-to-trap-focus-in-an-element/
|
|
3440
|
+
*
|
|
3441
|
+
* Het native `<dialog>` element trapt de focus zelf zodra het via `.showModal()`
|
|
3442
|
+
* geopend wordt. Die native trap is echter niet overal betrouwbaar: zodra het
|
|
3443
|
+
* dialoogvenster in een `<iframe>` staat (Storybook, embeds, previews) laat
|
|
3444
|
+
* Safari de focus alsnog over de iframe-grens ontsnappen naar de pagina
|
|
3445
|
+
* eromheen. Deze expliciete trap staat daarbovenop en maakt het gedrag
|
|
3446
|
+
* browseronafhankelijk.
|
|
3447
|
+
*/
|
|
3448
|
+
/**
|
|
3449
|
+
* Selector voor elementen die standaard in de tabvolgorde staan.
|
|
3450
|
+
* Uitgeschakelde controls en `tabindex="-1"` vallen er bewust buiten.
|
|
3451
|
+
*/
|
|
3452
|
+
const FOCUSABLE_SELECTOR = [
|
|
3453
|
+
"a[href]",
|
|
3454
|
+
"area[href]",
|
|
3455
|
+
"button:not(:disabled)",
|
|
3456
|
+
"input:not(:disabled):not([type=\"hidden\"])",
|
|
3457
|
+
"select:not(:disabled)",
|
|
3458
|
+
"textarea:not(:disabled)",
|
|
3459
|
+
"details > summary:first-of-type",
|
|
3460
|
+
"iframe",
|
|
3461
|
+
"audio[controls]",
|
|
3462
|
+
"video[controls]",
|
|
3463
|
+
"[contenteditable]:not([contenteditable=\"false\"])",
|
|
3464
|
+
"[tabindex]:not([tabindex^=\"-\"])"
|
|
3465
|
+
].join(", ");
|
|
3466
|
+
/**
|
|
3467
|
+
* Elementen die de focus niet kunnen krijgen omdat ze (of een voorouder)
|
|
3468
|
+
* verborgen of inert zijn. `[hidden]` en `[inert]` halen een element uit de
|
|
3469
|
+
* tabvolgorde, `[aria-hidden="true"]` hoort geen focusbare inhoud te bevatten.
|
|
3470
|
+
*/
|
|
3471
|
+
function isReachable(element) {
|
|
3472
|
+
return !element.closest("[hidden], [inert], [aria-hidden=\"true\"]");
|
|
3473
|
+
}
|
|
3474
|
+
/**
|
|
3475
|
+
* Alle bereikbare focusbare elementen binnen een container, in DOM-volgorde.
|
|
3476
|
+
*
|
|
3477
|
+
* De trap staat of valt met die volgorde: het eerste en het laatste element
|
|
3478
|
+
* bepalen waar Tab en Shift+Tab omslaan. Daarom lopen we alle elementen langs
|
|
3479
|
+
* en toetsen we ze met `matches`, in plaats van `querySelectorAll` met de hele
|
|
3480
|
+
* selectorlijst. Browsers geven daar documentvolgorde bij terug, maar jsdom
|
|
3481
|
+
* groepeert het resultaat per losse selector, en dan zou de trap in tests
|
|
3482
|
+
* ander gedrag vertonen dan in het echt.
|
|
3483
|
+
*/
|
|
3484
|
+
function getFocusableElements(container) {
|
|
3485
|
+
return Array.from(container.querySelectorAll("*")).filter((element) => element.matches(FOCUSABLE_SELECTOR) && isReachable(element));
|
|
3486
|
+
}
|
|
3487
|
+
/**
|
|
3488
|
+
* Houdt de toetsenbordfocus binnen `containerRef` zolang `active` waar is.
|
|
3489
|
+
*
|
|
3490
|
+
* De listener hangt aan de container zelf, niet aan het document: hij grijpt
|
|
3491
|
+
* alleen in wanneer de focus al binnen de container zit, en laat de rest van de
|
|
3492
|
+
* pagina met rust.
|
|
3493
|
+
*
|
|
3494
|
+
* Elementen met `tabindex="-1"` (zoals de heading die bij openen focus krijgt)
|
|
3495
|
+
* staan niet in de tabvolgorde. Vanaf zo'n element wrapt Shift+Tab naar het
|
|
3496
|
+
* laatste focusbare element, zodat de focus ook daar niet naar buiten valt.
|
|
3497
|
+
*/
|
|
3498
|
+
function useFocusTrap(containerRef, active) {
|
|
3499
|
+
react.default.useEffect(() => {
|
|
3500
|
+
if (!active) return;
|
|
3501
|
+
const container = containerRef.current;
|
|
3502
|
+
if (!container) return;
|
|
3503
|
+
const handleKeyDown = (event) => {
|
|
3504
|
+
if (event.key !== "Tab") return;
|
|
3505
|
+
const focusable = getFocusableElements(container);
|
|
3506
|
+
if (focusable.length === 0) {
|
|
3507
|
+
event.preventDefault();
|
|
3508
|
+
return;
|
|
3509
|
+
}
|
|
3510
|
+
const first = focusable[0];
|
|
3511
|
+
const last = focusable[focusable.length - 1];
|
|
3512
|
+
const current = document.activeElement;
|
|
3513
|
+
const isInTabOrder = current ? focusable.includes(current) : false;
|
|
3514
|
+
if (event.shiftKey) {
|
|
3515
|
+
if (current === first || !isInTabOrder) {
|
|
3516
|
+
event.preventDefault();
|
|
3517
|
+
last.focus();
|
|
3518
|
+
}
|
|
3519
|
+
} else if (current === last) {
|
|
3520
|
+
event.preventDefault();
|
|
3521
|
+
first.focus();
|
|
3522
|
+
}
|
|
3523
|
+
};
|
|
3524
|
+
container.addEventListener("keydown", handleKeyDown);
|
|
3525
|
+
return () => container.removeEventListener("keydown", handleKeyDown);
|
|
3526
|
+
}, [active, containerRef]);
|
|
3527
|
+
}
|
|
3528
|
+
//#endregion
|
|
3434
3529
|
//#region src/Drawer/Drawer.tsx
|
|
3435
|
-
const DrawerContext = react.default.createContext({
|
|
3530
|
+
const DrawerContext = react.default.createContext({
|
|
3531
|
+
headingId: "",
|
|
3532
|
+
headingRef: { current: null }
|
|
3533
|
+
});
|
|
3436
3534
|
/**
|
|
3437
3535
|
* Drawer component
|
|
3438
3536
|
* Zijpaneel dat vanuit links of rechts de viewport inschuift.
|
|
@@ -3459,22 +3557,33 @@ const DrawerContext = react.default.createContext({ headingId: "" });
|
|
|
3459
3557
|
* </Drawer>
|
|
3460
3558
|
* ```
|
|
3461
3559
|
*/
|
|
3462
|
-
const Drawer = react.default.forwardRef(({ className, isOpen, onClose, modal = true, side = "right", children, ...props }, ref) => {
|
|
3560
|
+
const Drawer = react.default.forwardRef(({ className, isOpen, onClose, modal = true, triggerRef, side = "right", children, ...props }, ref) => {
|
|
3463
3561
|
const internalRef = react.default.useRef(null);
|
|
3464
3562
|
const dialogRef = ref ?? internalRef;
|
|
3465
3563
|
const headingId = react.default.useId();
|
|
3564
|
+
const headingRef = react.default.useRef(null);
|
|
3466
3565
|
react.default.useEffect(() => {
|
|
3467
3566
|
const dialog = dialogRef.current;
|
|
3468
3567
|
if (!dialog) return;
|
|
3469
3568
|
if (isOpen && !dialog.open) {
|
|
3470
3569
|
if (modal) dialog.showModal();
|
|
3471
3570
|
else dialog.show();
|
|
3571
|
+
(headingRef.current ?? dialog).focus();
|
|
3472
3572
|
} else if (!isOpen && dialog.open) dialog.close();
|
|
3473
3573
|
}, [
|
|
3474
3574
|
isOpen,
|
|
3475
3575
|
modal,
|
|
3476
3576
|
dialogRef
|
|
3477
3577
|
]);
|
|
3578
|
+
useFocusTrap(dialogRef, isOpen && modal);
|
|
3579
|
+
react.default.useEffect(() => {
|
|
3580
|
+
const trigger = triggerRef?.current;
|
|
3581
|
+
if (!trigger) return;
|
|
3582
|
+
trigger.setAttribute("aria-expanded", isOpen ? "true" : "false");
|
|
3583
|
+
return () => {
|
|
3584
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
3585
|
+
};
|
|
3586
|
+
}, [isOpen, triggerRef]);
|
|
3478
3587
|
react.default.useEffect(() => {
|
|
3479
3588
|
if (modal) return;
|
|
3480
3589
|
const dialog = dialogRef.current;
|
|
@@ -3498,6 +3607,7 @@ const Drawer = react.default.forwardRef(({ className, isOpen, onClose, modal = t
|
|
|
3498
3607
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DrawerContext.Provider, {
|
|
3499
3608
|
value: {
|
|
3500
3609
|
headingId,
|
|
3610
|
+
headingRef,
|
|
3501
3611
|
onClose
|
|
3502
3612
|
},
|
|
3503
3613
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dialog", {
|
|
@@ -3505,6 +3615,7 @@ const Drawer = react.default.forwardRef(({ className, isOpen, onClose, modal = t
|
|
|
3505
3615
|
className: classes,
|
|
3506
3616
|
"aria-labelledby": headingId,
|
|
3507
3617
|
onCancel: handleCancel,
|
|
3618
|
+
tabIndex: -1,
|
|
3508
3619
|
...props,
|
|
3509
3620
|
children
|
|
3510
3621
|
})
|
|
@@ -3538,14 +3649,21 @@ DrawerHeader.displayName = "DrawerHeader";
|
|
|
3538
3649
|
/**
|
|
3539
3650
|
* DrawerHeading
|
|
3540
3651
|
* De heading van het zijpaneel. ID wordt automatisch gegenereerd voor aria-labelledby.
|
|
3652
|
+
* Krijgt `tabindex="-1"` zodat de Drawer er bij openen de focus op kan zetten.
|
|
3541
3653
|
*/
|
|
3542
3654
|
const DrawerHeading = react.default.forwardRef(({ className, level = 2, children, ...props }, ref) => {
|
|
3543
|
-
const { headingId } = react.default.useContext(DrawerContext);
|
|
3655
|
+
const { headingId, headingRef } = react.default.useContext(DrawerContext);
|
|
3544
3656
|
const Tag = `h${level}`;
|
|
3657
|
+
const setRef = react.default.useCallback((node) => {
|
|
3658
|
+
headingRef.current = node;
|
|
3659
|
+
if (typeof ref === "function") ref(node);
|
|
3660
|
+
else if (ref) ref.current = node;
|
|
3661
|
+
}, [headingRef, ref]);
|
|
3545
3662
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tag, {
|
|
3546
|
-
ref,
|
|
3663
|
+
ref: setRef,
|
|
3547
3664
|
id: headingId,
|
|
3548
3665
|
className: (0, _dsn_starter_kit_core.classNames)("dsn-drawer-heading", className),
|
|
3666
|
+
tabIndex: -1,
|
|
3549
3667
|
...props,
|
|
3550
3668
|
children
|
|
3551
3669
|
});
|
|
@@ -3579,6 +3697,10 @@ const DrawerFooter = react.default.forwardRef(({ className, children, ...props }
|
|
|
3579
3697
|
DrawerFooter.displayName = "DrawerFooter";
|
|
3580
3698
|
//#endregion
|
|
3581
3699
|
//#region src/PageHeader/PageHeader.tsx
|
|
3700
|
+
/** Auto-hide: boven deze scrollpositie (px) blijft de header altijd zichtbaar */
|
|
3701
|
+
const AUTO_HIDE_OFFSET = 100;
|
|
3702
|
+
/** Auto-hide: zoveel px omhoog scrollen voordat de header terugkomt */
|
|
3703
|
+
const AUTO_HIDE_REVEAL_DISTANCE = 64;
|
|
3582
3704
|
/**
|
|
3583
3705
|
* PageHeader component
|
|
3584
3706
|
* Primaire navigatieheader voor een pagina. Mobile-first implementatie.
|
|
@@ -3626,11 +3748,24 @@ const PageHeader = react.default.forwardRef(({ className, logoSlot, sticky = "no
|
|
|
3626
3748
|
react.default.useEffect(() => {
|
|
3627
3749
|
if (sticky !== "auto-hide") return;
|
|
3628
3750
|
let lastScrollY = window.scrollY;
|
|
3751
|
+
let scrolledUp = 0;
|
|
3629
3752
|
const handleScroll = () => {
|
|
3630
3753
|
const currentScrollY = window.scrollY;
|
|
3631
|
-
const
|
|
3632
|
-
combinedRef.current?.setAttribute("data-hidden", String(isScrollingDown));
|
|
3754
|
+
const delta = currentScrollY - lastScrollY;
|
|
3633
3755
|
lastScrollY = currentScrollY;
|
|
3756
|
+
let hidden;
|
|
3757
|
+
if (currentScrollY <= AUTO_HIDE_OFFSET) {
|
|
3758
|
+
hidden = false;
|
|
3759
|
+
scrolledUp = 0;
|
|
3760
|
+
} else if (delta > 0) {
|
|
3761
|
+
hidden = true;
|
|
3762
|
+
scrolledUp = 0;
|
|
3763
|
+
} else if (delta < 0) {
|
|
3764
|
+
scrolledUp -= delta;
|
|
3765
|
+
if (scrolledUp < AUTO_HIDE_REVEAL_DISTANCE) return;
|
|
3766
|
+
hidden = false;
|
|
3767
|
+
} else return;
|
|
3768
|
+
combinedRef.current?.setAttribute("data-hidden", String(hidden));
|
|
3634
3769
|
};
|
|
3635
3770
|
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
3636
3771
|
return () => window.removeEventListener("scroll", handleScroll);
|
|
@@ -3827,6 +3962,7 @@ const PageHeader = react.default.forwardRef(({ className, logoSlot, sticky = "no
|
|
|
3827
3962
|
isOpen: isMenuOpen,
|
|
3828
3963
|
onClose: handleMenuClose,
|
|
3829
3964
|
side: "left",
|
|
3965
|
+
triggerRef: menuButtonRef,
|
|
3830
3966
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DrawerHeader, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DrawerHeading, { children: menuButtonLabel }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DrawerBody, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Stack, {
|
|
3831
3967
|
space: "5xl",
|
|
3832
3968
|
children: [primaryNavigation && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
|
|
@@ -4375,22 +4511,29 @@ Image.displayName = "Image";
|
|
|
4375
4511
|
const CardContext = react.default.createContext({});
|
|
4376
4512
|
/**
|
|
4377
4513
|
* Card component
|
|
4378
|
-
* Configureerbare container
|
|
4379
|
-
*
|
|
4380
|
-
*
|
|
4514
|
+
* Configureerbare container met vier optionele secties: `CardPreHeader`,
|
|
4515
|
+
* `CardHeader`, `CardBody` en `CardFooter` (zie DR-2026-11).
|
|
4516
|
+
*
|
|
4517
|
+
* Zet `CardHeader` in de JSX altijd vóór `CardPreHeader`: zo kondigt een
|
|
4518
|
+
* screenreader de heading eerst aan. De CSS zet de pre-header visueel bovenaan.
|
|
4519
|
+
*
|
|
4520
|
+
* Met `href` wordt de heading een stretched link: de link dekt de volledige
|
|
4521
|
+
* card, en screenreaders lezen alleen de heading-tekst als linknaam.
|
|
4381
4522
|
*
|
|
4382
4523
|
* @example
|
|
4383
4524
|
* ```tsx
|
|
4384
4525
|
* <Card href="/artikel/slug">
|
|
4385
4526
|
* <CardHeader>
|
|
4386
|
-
* <
|
|
4527
|
+
* <CardHeading level={2}>Artikeltitel</CardHeading>
|
|
4387
4528
|
* </CardHeader>
|
|
4529
|
+
* <CardPreHeader>
|
|
4530
|
+
* <Image src="/foto.jpg" alt="" width={800} height={450} ratio="16:9" />
|
|
4531
|
+
* </CardPreHeader>
|
|
4388
4532
|
* <CardBody>
|
|
4389
|
-
* <CardHeading level={2}>Artikeltitel</CardHeading>
|
|
4390
4533
|
* <Paragraph>Korte beschrijving.</Paragraph>
|
|
4391
4534
|
* </CardBody>
|
|
4392
4535
|
* <CardFooter>
|
|
4393
|
-
* <
|
|
4536
|
+
* <CardAffordance>Lees meer</CardAffordance>
|
|
4394
4537
|
* </CardFooter>
|
|
4395
4538
|
* </Card>
|
|
4396
4539
|
* ```
|
|
@@ -4408,13 +4551,14 @@ const Card = react.default.forwardRef(({ className, href, children, ...props },
|
|
|
4408
4551
|
});
|
|
4409
4552
|
Card.displayName = "Card";
|
|
4410
4553
|
/**
|
|
4411
|
-
*
|
|
4554
|
+
* CardPreHeader sub-component
|
|
4555
|
+
* Staat in de DOM ná `CardHeader` en komt visueel bovenaan via `order: -1`.
|
|
4412
4556
|
* Zonder children → toont automatisch een afbeeldingsplaceholder.
|
|
4413
4557
|
*/
|
|
4414
|
-
const
|
|
4558
|
+
const CardPreHeader = react.default.forwardRef(({ className, children, ...props }, ref) => {
|
|
4415
4559
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4416
4560
|
ref,
|
|
4417
|
-
className: (0, _dsn_starter_kit_core.classNames)("dsn-
|
|
4561
|
+
className: (0, _dsn_starter_kit_core.classNames)("dsn-card__pre-header", className),
|
|
4418
4562
|
...props,
|
|
4419
4563
|
children: children ? children : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4420
4564
|
className: "dsn-card__image-placeholder",
|
|
@@ -4422,10 +4566,24 @@ const CardHeader = react.default.forwardRef(({ className, children, ...props },
|
|
|
4422
4566
|
})
|
|
4423
4567
|
});
|
|
4424
4568
|
});
|
|
4569
|
+
CardPreHeader.displayName = "CardPreHeader";
|
|
4570
|
+
/**
|
|
4571
|
+
* CardHeader sub-component
|
|
4572
|
+
* Bevat de heading of het label van de card. Zet hem in de JSX vóór
|
|
4573
|
+
* `CardPreHeader`.
|
|
4574
|
+
*/
|
|
4575
|
+
const CardHeader = react.default.forwardRef(({ className, children, ...props }, ref) => {
|
|
4576
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4577
|
+
ref,
|
|
4578
|
+
className: (0, _dsn_starter_kit_core.classNames)("dsn-card__header", className),
|
|
4579
|
+
...props,
|
|
4580
|
+
children
|
|
4581
|
+
});
|
|
4582
|
+
});
|
|
4425
4583
|
CardHeader.displayName = "CardHeader";
|
|
4426
4584
|
/**
|
|
4427
4585
|
* CardBody sub-component
|
|
4428
|
-
*
|
|
4586
|
+
* Inhoudssectie onder de header.
|
|
4429
4587
|
*/
|
|
4430
4588
|
const CardBody = react.default.forwardRef(({ className, children, ...props }, ref) => {
|
|
4431
4589
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -4439,7 +4597,7 @@ CardBody.displayName = "CardBody";
|
|
|
4439
4597
|
/**
|
|
4440
4598
|
* CardHeading sub-component
|
|
4441
4599
|
* Ontvangt `href` automatisch via React context van de parent `Card`.
|
|
4442
|
-
* Wanneer `href` beschikbaar is,
|
|
4600
|
+
* Wanneer `href` beschikbaar is, staat de heading-tekst in een `<a class="dsn-card__link">`.
|
|
4443
4601
|
* Het `::before` pseudo-element dekt de volledige card (stretched link).
|
|
4444
4602
|
*/
|
|
4445
4603
|
const CardHeading = react.default.forwardRef(({ className, level = 2, children, ...props }, ref) => {
|
|
@@ -4447,21 +4605,67 @@ const CardHeading = react.default.forwardRef(({ className, level = 2, children,
|
|
|
4447
4605
|
const Tag = `h${level}`;
|
|
4448
4606
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tag, {
|
|
4449
4607
|
ref,
|
|
4450
|
-
className: (0, _dsn_starter_kit_core.classNames)("dsn-
|
|
4608
|
+
className: (0, _dsn_starter_kit_core.classNames)("dsn-card__heading", className),
|
|
4451
4609
|
...props,
|
|
4452
4610
|
children: href ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
4453
4611
|
href,
|
|
4454
|
-
className: "dsn-
|
|
4612
|
+
className: "dsn-card__link",
|
|
4455
4613
|
children
|
|
4456
4614
|
}) : children
|
|
4457
4615
|
});
|
|
4458
4616
|
});
|
|
4459
4617
|
CardHeading.displayName = "CardHeading";
|
|
4460
4618
|
/**
|
|
4619
|
+
* CardLabel sub-component
|
|
4620
|
+
* Gebruik in plaats van `CardHeading` wanneer de card geen nieuw onderwerp
|
|
4621
|
+
* introduceert, zoals bij login-opties of instellingen. Ontvangt `href` via
|
|
4622
|
+
* context, net als `CardHeading`.
|
|
4623
|
+
*/
|
|
4624
|
+
const CardLabel = react.default.forwardRef(({ className, children, ...props }, ref) => {
|
|
4625
|
+
const { href } = react.default.useContext(CardContext);
|
|
4626
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4627
|
+
ref,
|
|
4628
|
+
className: (0, _dsn_starter_kit_core.classNames)("dsn-card__label", className),
|
|
4629
|
+
...props,
|
|
4630
|
+
children: href ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
4631
|
+
href,
|
|
4632
|
+
className: "dsn-card__link",
|
|
4633
|
+
children
|
|
4634
|
+
}) : children
|
|
4635
|
+
});
|
|
4636
|
+
});
|
|
4637
|
+
CardLabel.displayName = "CardLabel";
|
|
4638
|
+
/**
|
|
4639
|
+
* CardDescription sub-component
|
|
4640
|
+
* Korte omschrijving met eigen typografie-tokens.
|
|
4641
|
+
*/
|
|
4642
|
+
const CardDescription = react.default.forwardRef(({ className, children, ...props }, ref) => {
|
|
4643
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4644
|
+
ref,
|
|
4645
|
+
className: (0, _dsn_starter_kit_core.classNames)("dsn-card__description", className),
|
|
4646
|
+
...props,
|
|
4647
|
+
children
|
|
4648
|
+
});
|
|
4649
|
+
});
|
|
4650
|
+
CardDescription.displayName = "CardDescription";
|
|
4651
|
+
/**
|
|
4652
|
+
* CardMeta sub-component
|
|
4653
|
+
* Aanvullende gegevens bij de card, zoals een datum.
|
|
4654
|
+
*/
|
|
4655
|
+
const CardMeta = react.default.forwardRef(({ className, children, ...props }, ref) => {
|
|
4656
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4657
|
+
ref,
|
|
4658
|
+
className: (0, _dsn_starter_kit_core.classNames)("dsn-card__meta", className),
|
|
4659
|
+
...props,
|
|
4660
|
+
children
|
|
4661
|
+
});
|
|
4662
|
+
});
|
|
4663
|
+
CardMeta.displayName = "CardMeta";
|
|
4664
|
+
/**
|
|
4461
4665
|
* CardFooter sub-component
|
|
4462
|
-
*
|
|
4463
|
-
*
|
|
4464
|
-
* bestemming
|
|
4666
|
+
* Staat altijd onderaan de card. Links en buttons staan boven de stretched
|
|
4667
|
+
* link en blijven zelfstandig klikbaar. Voor een visuele "Lees meer" naar
|
|
4668
|
+
* dezelfde bestemming als de card: gebruik `CardAffordance`.
|
|
4465
4669
|
*/
|
|
4466
4670
|
const CardFooter = react.default.forwardRef(({ className, children, ...props }, ref) => {
|
|
4467
4671
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -4473,6 +4677,21 @@ const CardFooter = react.default.forwardRef(({ className, children, ...props },
|
|
|
4473
4677
|
});
|
|
4474
4678
|
CardFooter.displayName = "CardFooter";
|
|
4475
4679
|
/**
|
|
4680
|
+
* CardAffordance sub-component
|
|
4681
|
+
* Een `<span aria-hidden="true">` die eruitziet als een link. De stretched
|
|
4682
|
+
* link vangt de klik al af, dus er is geen tweede tabstop nodig.
|
|
4683
|
+
*/
|
|
4684
|
+
const CardAffordance = react.default.forwardRef(({ className, children, ...props }, ref) => {
|
|
4685
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4686
|
+
ref,
|
|
4687
|
+
className: (0, _dsn_starter_kit_core.classNames)("dsn-card__affordance", className),
|
|
4688
|
+
"aria-hidden": "true",
|
|
4689
|
+
...props,
|
|
4690
|
+
children
|
|
4691
|
+
});
|
|
4692
|
+
});
|
|
4693
|
+
CardAffordance.displayName = "CardAffordance";
|
|
4694
|
+
/**
|
|
4476
4695
|
* CardGroup sub-component
|
|
4477
4696
|
* Flexbox wrapper die gelijke hoogte garandeert en de footer in elke card onderaan uitlijnt.
|
|
4478
4697
|
* Rendert `role="list"` wanneer `as="ul"` — nodig omdat CSS-resets de lijstsemantiek verwijderen.
|
|
@@ -4490,13 +4709,18 @@ const CardGroup = react.default.forwardRef(({ className, as: Tag = "ul", childre
|
|
|
4490
4709
|
CardGroup.displayName = "CardGroup";
|
|
4491
4710
|
//#endregion
|
|
4492
4711
|
//#region src/ModalDialog/ModalDialog.tsx
|
|
4493
|
-
const ModalDialogContext = react.default.createContext({
|
|
4712
|
+
const ModalDialogContext = react.default.createContext({
|
|
4713
|
+
headingId: "",
|
|
4714
|
+
headingRef: { current: null }
|
|
4715
|
+
});
|
|
4494
4716
|
/**
|
|
4495
4717
|
* ModalDialog component
|
|
4496
4718
|
* Modaal dialoogvenster gebaseerd op het native `<dialog>` element.
|
|
4497
4719
|
*
|
|
4498
|
-
* Gebruik altijd `.showModal()` (intern afgehandeld via `isOpen` prop)
|
|
4499
|
-
* Dit garandeert
|
|
4720
|
+
* Gebruik altijd `.showModal()` (intern afgehandeld via `isOpen` prop), nooit `.show()`.
|
|
4721
|
+
* Dit garandeert aria-modal semantiek en het inert-attribuut op de achtergrond.
|
|
4722
|
+
* De focus blijft binnen het venster via de native focus-trap plus een
|
|
4723
|
+
* expliciete trap, en komt bij openen op de heading te staan.
|
|
4500
4724
|
*
|
|
4501
4725
|
* @example
|
|
4502
4726
|
* ```tsx
|
|
@@ -4516,16 +4740,28 @@ const ModalDialogContext = react.default.createContext({ headingId: "" });
|
|
|
4516
4740
|
* </ModalDialog>
|
|
4517
4741
|
* ```
|
|
4518
4742
|
*/
|
|
4519
|
-
const ModalDialog = react.default.forwardRef(({ className, isOpen, onClose, children, ...props }, ref) => {
|
|
4743
|
+
const ModalDialog = react.default.forwardRef(({ className, isOpen, onClose, triggerRef, children, ...props }, ref) => {
|
|
4520
4744
|
const internalRef = react.default.useRef(null);
|
|
4521
4745
|
const dialogRef = ref ?? internalRef;
|
|
4522
4746
|
const headingId = react.default.useId();
|
|
4747
|
+
const headingRef = react.default.useRef(null);
|
|
4523
4748
|
react.default.useEffect(() => {
|
|
4524
4749
|
const dialog = dialogRef.current;
|
|
4525
4750
|
if (!dialog) return;
|
|
4526
|
-
if (isOpen && !dialog.open)
|
|
4527
|
-
|
|
4751
|
+
if (isOpen && !dialog.open) {
|
|
4752
|
+
dialog.showModal();
|
|
4753
|
+
(headingRef.current ?? dialog).focus();
|
|
4754
|
+
} else if (!isOpen && dialog.open) dialog.close();
|
|
4528
4755
|
}, [isOpen, dialogRef]);
|
|
4756
|
+
useFocusTrap(dialogRef, isOpen);
|
|
4757
|
+
react.default.useEffect(() => {
|
|
4758
|
+
const trigger = triggerRef?.current;
|
|
4759
|
+
if (!trigger) return;
|
|
4760
|
+
trigger.setAttribute("aria-expanded", isOpen ? "true" : "false");
|
|
4761
|
+
return () => {
|
|
4762
|
+
trigger.setAttribute("aria-expanded", "false");
|
|
4763
|
+
};
|
|
4764
|
+
}, [isOpen, triggerRef]);
|
|
4529
4765
|
const handleCancel = (event) => {
|
|
4530
4766
|
event.preventDefault();
|
|
4531
4767
|
onClose?.();
|
|
@@ -4534,6 +4770,7 @@ const ModalDialog = react.default.forwardRef(({ className, isOpen, onClose, chil
|
|
|
4534
4770
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModalDialogContext.Provider, {
|
|
4535
4771
|
value: {
|
|
4536
4772
|
headingId,
|
|
4773
|
+
headingRef,
|
|
4537
4774
|
onClose
|
|
4538
4775
|
},
|
|
4539
4776
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dialog", {
|
|
@@ -4541,6 +4778,7 @@ const ModalDialog = react.default.forwardRef(({ className, isOpen, onClose, chil
|
|
|
4541
4778
|
className: classes,
|
|
4542
4779
|
"aria-labelledby": headingId,
|
|
4543
4780
|
onCancel: handleCancel,
|
|
4781
|
+
tabIndex: -1,
|
|
4544
4782
|
...props,
|
|
4545
4783
|
children
|
|
4546
4784
|
})
|
|
@@ -4574,14 +4812,21 @@ ModalDialogHeader.displayName = "ModalDialogHeader";
|
|
|
4574
4812
|
/**
|
|
4575
4813
|
* ModalDialogHeading
|
|
4576
4814
|
* De heading van het dialoogvenster. ID wordt automatisch gegenereerd voor aria-labelledby.
|
|
4815
|
+
* Krijgt `tabindex="-1"` zodat het ModalDialog er bij openen de focus op kan zetten.
|
|
4577
4816
|
*/
|
|
4578
4817
|
const ModalDialogHeading = react.default.forwardRef(({ className, level = 2, children, ...props }, ref) => {
|
|
4579
|
-
const { headingId } = react.default.useContext(ModalDialogContext);
|
|
4818
|
+
const { headingId, headingRef } = react.default.useContext(ModalDialogContext);
|
|
4580
4819
|
const Tag = `h${level}`;
|
|
4820
|
+
const setRef = react.default.useCallback((node) => {
|
|
4821
|
+
headingRef.current = node;
|
|
4822
|
+
if (typeof ref === "function") ref(node);
|
|
4823
|
+
else if (ref) ref.current = node;
|
|
4824
|
+
}, [headingRef, ref]);
|
|
4581
4825
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tag, {
|
|
4582
|
-
ref,
|
|
4826
|
+
ref: setRef,
|
|
4583
4827
|
id: headingId,
|
|
4584
4828
|
className: (0, _dsn_starter_kit_core.classNames)("dsn-modal-dialog-heading", className),
|
|
4829
|
+
tabIndex: -1,
|
|
4585
4830
|
...props,
|
|
4586
4831
|
children
|
|
4587
4832
|
});
|
|
@@ -5036,11 +5281,16 @@ exports.BreakoutSection = BreakoutSection;
|
|
|
5036
5281
|
exports.Button = Button;
|
|
5037
5282
|
exports.ButtonLink = ButtonLink;
|
|
5038
5283
|
exports.Card = Card;
|
|
5284
|
+
exports.CardAffordance = CardAffordance;
|
|
5039
5285
|
exports.CardBody = CardBody;
|
|
5286
|
+
exports.CardDescription = CardDescription;
|
|
5040
5287
|
exports.CardFooter = CardFooter;
|
|
5041
5288
|
exports.CardGroup = CardGroup;
|
|
5042
5289
|
exports.CardHeader = CardHeader;
|
|
5043
5290
|
exports.CardHeading = CardHeading;
|
|
5291
|
+
exports.CardLabel = CardLabel;
|
|
5292
|
+
exports.CardMeta = CardMeta;
|
|
5293
|
+
exports.CardPreHeader = CardPreHeader;
|
|
5044
5294
|
exports.Checkbox = Checkbox;
|
|
5045
5295
|
exports.CheckboxGroup = CheckboxGroup;
|
|
5046
5296
|
exports.CheckboxOption = CheckboxOption;
|