@roadlittledawn/docs-design-system-react 0.12.1 → 0.12.3
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/USAGE.md +23 -5
- package/dist/components/List.d.ts +1 -1
- package/dist/components/List.js +7 -3
- package/dist/components/Popover.js +32 -1
- package/dist/components/Popover.stories.js +1 -1
- package/dist/styles.css +67 -16
- package/package.json +1 -1
package/USAGE.md
CHANGED
|
@@ -529,10 +529,20 @@ import { List } from "@roadlittledawn/docs-design-system-react";
|
|
|
529
529
|
|
|
530
530
|
### List.Item Props
|
|
531
531
|
|
|
532
|
-
| Prop
|
|
533
|
-
|
|
|
534
|
-
| `children`
|
|
535
|
-
| `className`
|
|
532
|
+
| Prop | Type | Default | Description |
|
|
533
|
+
| ------------ | ----------- | ------- | --------------------------------------------------------------------------- |
|
|
534
|
+
| `children` | `ReactNode` | — | List item content |
|
|
535
|
+
| `className` | `string` | `""` | Additional CSS classes |
|
|
536
|
+
| `bulletIcon` | `ReactNode` | — | Custom bullet icon for this item. Overrides the parent `List`'s `bulletIcon` |
|
|
537
|
+
|
|
538
|
+
### CSS classes
|
|
539
|
+
|
|
540
|
+
| Class | Element | Notes |
|
|
541
|
+
| ----- | ------- | ----- |
|
|
542
|
+
| `dds-list` | `<ol>` / `<ul>` | Root list element |
|
|
543
|
+
| `dds-list-item` | `<li>` | Each list item |
|
|
544
|
+
| `dds-list-item-content` | `<div>` | Wraps item children; target for content-level overrides |
|
|
545
|
+
| `dds-list-item-icon` | `<span>` | Wrapper for custom `bulletIcon` SVG/node |
|
|
536
546
|
|
|
537
547
|
### Examples
|
|
538
548
|
|
|
@@ -1025,7 +1035,15 @@ A hover/tap-activated floating panel for enriching inline documentation content.
|
|
|
1025
1035
|
|
|
1026
1036
|
### Mobile behavior
|
|
1027
1037
|
|
|
1028
|
-
On screens ≤ 640px, the popover renders as a **bottom sheet** instead of a floating panel. Hover doesn't apply on touch devices; the popover
|
|
1038
|
+
On screens ≤ 640px, the popover renders as a **bottom sheet** instead of a floating panel. Hover doesn't apply on touch devices; the popover opens on tap.
|
|
1039
|
+
|
|
1040
|
+
### Closing the popover
|
|
1041
|
+
|
|
1042
|
+
The popover can be closed in three ways:
|
|
1043
|
+
|
|
1044
|
+
- **Close button** — the × button in the upper-right corner of the panel
|
|
1045
|
+
- **Click / tap outside** — native light-dismiss provided by `popover="auto"`
|
|
1046
|
+
- **Escape key** — handled automatically by the Popover API
|
|
1029
1047
|
|
|
1030
1048
|
### Content modes (choose one)
|
|
1031
1049
|
|
|
@@ -16,7 +16,7 @@ export interface ListItemProps {
|
|
|
16
16
|
children: ReactNode;
|
|
17
17
|
/** Additional CSS classes */
|
|
18
18
|
className?: string;
|
|
19
|
-
/**
|
|
19
|
+
/** Custom bullet icon (React node, e.g., SVG) for this item. Overrides the parent List's bulletIcon */
|
|
20
20
|
bulletIcon?: ReactNode;
|
|
21
21
|
}
|
|
22
22
|
export declare function ListItem({ children, className, bulletIcon }: ListItemProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/components/List.js
CHANGED
|
@@ -15,12 +15,16 @@ function ListImpl(_a) {
|
|
|
15
15
|
var children = _a.children, _b = _a.className, className = _b === void 0 ? "" : _b, _c = _a.ordered, ordered = _c === void 0 ? true : _c, bullet = _a.bullet, bulletIcon = _a.bulletIcon;
|
|
16
16
|
var listClasses = ["dds-list", className].filter(Boolean).join(" ");
|
|
17
17
|
var Element = ordered ? "ol" : "ul";
|
|
18
|
-
return (_jsx(Element, { className: listClasses, "data-ordered": ordered,
|
|
18
|
+
return (_jsx(Element, { className: listClasses, "data-ordered": ordered, style: bullet && !bulletIcon
|
|
19
19
|
? { "--dds-list-bullet": JSON.stringify(bullet) }
|
|
20
20
|
: undefined, children: bulletIcon && !ordered
|
|
21
21
|
? React.Children.map(children, function (child) {
|
|
22
|
+
var _a;
|
|
22
23
|
if (React.isValidElement(child) && child.type === ListItem) {
|
|
23
|
-
|
|
24
|
+
var childProps = child.props;
|
|
25
|
+
return React.cloneElement(child, __assign(__assign({}, childProps), {
|
|
26
|
+
// Child's own bulletIcon takes precedence over the parent's
|
|
27
|
+
bulletIcon: (_a = childProps.bulletIcon) !== null && _a !== void 0 ? _a : bulletIcon }));
|
|
24
28
|
}
|
|
25
29
|
return child;
|
|
26
30
|
})
|
|
@@ -29,7 +33,7 @@ function ListImpl(_a) {
|
|
|
29
33
|
export function ListItem(_a) {
|
|
30
34
|
var children = _a.children, _b = _a.className, className = _b === void 0 ? "" : _b, bulletIcon = _a.bulletIcon;
|
|
31
35
|
var itemClasses = ["dds-list-item", className].filter(Boolean).join(" ");
|
|
32
|
-
return (_jsxs("li", { className: itemClasses, children: [bulletIcon && (_jsx("span", { className: "dds-list-item-icon", "aria-hidden": "true", children: bulletIcon })), children] }));
|
|
36
|
+
return (_jsxs("li", { className: itemClasses, "data-has-icon": bulletIcon ? "true" : undefined, children: [bulletIcon && (_jsx("span", { className: "dds-list-item-icon", "aria-hidden": "true", children: bulletIcon })), _jsx("div", { className: "dds-list-item-content", children: children })] }));
|
|
33
37
|
}
|
|
34
38
|
export var List = Object.assign(ListImpl, {
|
|
35
39
|
Item: ListItem,
|
|
@@ -80,6 +80,14 @@ export function Popover(_a) {
|
|
|
80
80
|
var popoverRef = useRef(null);
|
|
81
81
|
var showTimerRef = useRef(null);
|
|
82
82
|
var hideTimerRef = useRef(null);
|
|
83
|
+
// Tracks when the popover was last shown automatically (hover/focus).
|
|
84
|
+
// Used to prevent the click handler from immediately closing a popover that
|
|
85
|
+
// was just opened by the hover timer (fixes the first-tap flicker on touch).
|
|
86
|
+
// On touch devices the synthetic `click` arrives ~300 ms after touch-start;
|
|
87
|
+
// the guard window must exceed showDelay (200 ms default) + that browser
|
|
88
|
+
// delay, so 400 ms is a safe minimum.
|
|
89
|
+
var FLICKER_GUARD_MS = 400;
|
|
90
|
+
var lastAutoShowTimeRef = useRef(0);
|
|
83
91
|
var clearTimers = useCallback(function () {
|
|
84
92
|
if (showTimerRef.current)
|
|
85
93
|
clearTimeout(showTimerRef.current);
|
|
@@ -131,6 +139,8 @@ export function Popover(_a) {
|
|
|
131
139
|
}
|
|
132
140
|
positionPopover();
|
|
133
141
|
popover.style.visibility = "";
|
|
142
|
+
// Record the time so the click handler knows the popover was auto-shown
|
|
143
|
+
lastAutoShowTimeRef.current = Date.now();
|
|
134
144
|
}, showDelay);
|
|
135
145
|
}, [clearTimers, showDelay, positionPopover]);
|
|
136
146
|
var hidePopover = useCallback(function () {
|
|
@@ -188,6 +198,15 @@ export function Popover(_a) {
|
|
|
188
198
|
var popover = popoverRef.current;
|
|
189
199
|
if (!popover)
|
|
190
200
|
return;
|
|
201
|
+
var isOpen = popover.matches(":popover-open") ||
|
|
202
|
+
popover.style.display === "block";
|
|
203
|
+
// Flicker guard: if the popover was just shown automatically by the
|
|
204
|
+
// hover/focus timer within the last 400 ms, a tap's synthetic click
|
|
205
|
+
// would arrive and toggle it closed. Instead, keep it open so the
|
|
206
|
+
// first tap reliably shows the popover.
|
|
207
|
+
if (isOpen && Date.now() - lastAutoShowTimeRef.current < FLICKER_GUARD_MS) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
191
210
|
try {
|
|
192
211
|
popover.togglePopover();
|
|
193
212
|
if (popover.matches(":popover-open"))
|
|
@@ -199,5 +218,17 @@ export function Popover(_a) {
|
|
|
199
218
|
if (!isVisible)
|
|
200
219
|
positionPopover();
|
|
201
220
|
}
|
|
202
|
-
}, "aria-describedby": popoverId, tabIndex: 0, children: children }),
|
|
221
|
+
}, "aria-describedby": popoverId, tabIndex: 0, children: children }), _jsxs("div", __assign({ ref: popoverRef, id: popoverId }, { popover: "auto" }, { className: popoverClasses, onMouseEnter: clearTimers, onMouseLeave: hidePopover, children: [_jsx("button", { className: "dds-popover-close", "aria-label": "Close", onClick: function (e) {
|
|
222
|
+
e.stopPropagation();
|
|
223
|
+
clearTimers();
|
|
224
|
+
var popover = popoverRef.current;
|
|
225
|
+
if (!popover)
|
|
226
|
+
return;
|
|
227
|
+
try {
|
|
228
|
+
popover.hidePopover();
|
|
229
|
+
}
|
|
230
|
+
catch (_a) {
|
|
231
|
+
popover.style.display = "none";
|
|
232
|
+
}
|
|
233
|
+
}, children: "\u00D7" }), popoverContent] }))] }));
|
|
203
234
|
}
|
|
@@ -64,7 +64,7 @@ var meta = {
|
|
|
64
64
|
layout: "centered",
|
|
65
65
|
docs: {
|
|
66
66
|
description: {
|
|
67
|
-
component: "\nA hover/tap-activated popover for enriching inline content in documentation.\nBuilt on the native [Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) for reliable top-layer rendering \u2014 no z-index wars, no overflow clipping.\n\nCommon use cases include glossary term definitions and Wikipedia-style content previews.\n\n## Content modes\n\nThe `Popover` supports three mutually exclusive content modes, checked in this order:\n\n1. **`content`** \u2014 arbitrary `ReactNode`; you control everything\n2. **`glossary`** \u2014 structured `{ term, title, definition }` template\n3. **`preview`** \u2014 structured `{ title, excerpt, imageUrl, href }` template\n\n## When to Use\n\n- Inline term definitions that would interrupt reading flow if expanded in-place\n- Link previews that let users get context without navigating away\n- Any contextual content that benefits from being on-demand rather than always visible\n\n## When Not to Use\n\n- For critical information users must read \u2014 use a `Callout` instead\n- As a primary navigation mechanism\n- For content that needs persistent visibility\n\n## Mobile behavior\n\nOn screens \u2264 640 px the popover renders as a bottom sheet instead of a floating panel.\nHover events don't apply; the popover
|
|
67
|
+
component: "\nA hover/tap-activated popover for enriching inline content in documentation.\nBuilt on the native [Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) for reliable top-layer rendering \u2014 no z-index wars, no overflow clipping.\n\nCommon use cases include glossary term definitions and Wikipedia-style content previews.\n\n## Content modes\n\nThe `Popover` supports three mutually exclusive content modes, checked in this order:\n\n1. **`content`** \u2014 arbitrary `ReactNode`; you control everything\n2. **`glossary`** \u2014 structured `{ term, title, definition }` template\n3. **`preview`** \u2014 structured `{ title, excerpt, imageUrl, href }` template\n\n## When to Use\n\n- Inline term definitions that would interrupt reading flow if expanded in-place\n- Link previews that let users get context without navigating away\n- Any contextual content that benefits from being on-demand rather than always visible\n\n## When Not to Use\n\n- For critical information users must read \u2014 use a `Callout` instead\n- As a primary navigation mechanism\n- For content that needs persistent visibility\n\n## Mobile behavior\n\nOn screens \u2264 640 px the popover renders as a bottom sheet instead of a floating panel.\nHover events don't apply; the popover opens on tap.\n\n## Closing the popover\n\nThe popover can be closed in three ways:\n- **Close button** \u2014 the \u00D7 button in the upper-right corner of the panel\n- **Click / tap outside** \u2014 native light-dismiss provided by `popover=\"auto\"`\n- **Escape key** \u2014 handled automatically by the Popover API\n\n## Accessibility\n\n- Trigger has `tabIndex={0}` and shows the popover on focus (keyboard accessible)\n- Popover panel has `role=\"tooltip\"` and is linked via `aria-describedby`\n- The native Popover API handles Escape-key dismissal automatically\n- Light-dismiss (click outside) is provided by `popover=\"auto\"`\n ",
|
|
68
68
|
},
|
|
69
69
|
},
|
|
70
70
|
},
|
package/dist/styles.css
CHANGED
|
@@ -1745,7 +1745,9 @@ a.no-text-decoration {
|
|
|
1745
1745
|
.dds-list-item {
|
|
1746
1746
|
counter-increment: list-counter;
|
|
1747
1747
|
position: relative;
|
|
1748
|
-
|
|
1748
|
+
display: flex;
|
|
1749
|
+
align-items: flex-start;
|
|
1750
|
+
gap: 1rem;
|
|
1749
1751
|
margin-bottom: var(--dds-list-item-margin-bottom, 1.5rem);
|
|
1750
1752
|
min-height: var(--dds-list-badge-size);
|
|
1751
1753
|
}
|
|
@@ -1767,13 +1769,10 @@ a.no-text-decoration {
|
|
|
1767
1769
|
/* Ordered list badges */
|
|
1768
1770
|
.dds-list[data-ordered="true"] .dds-list-item::before {
|
|
1769
1771
|
content: counter(list-counter);
|
|
1770
|
-
|
|
1771
|
-
left: 0;
|
|
1772
|
-
top: 0;
|
|
1772
|
+
flex-shrink: 0;
|
|
1773
1773
|
width: var(--dds-list-badge-size, 2.5rem);
|
|
1774
1774
|
height: var(--dds-list-badge-size, 2.5rem);
|
|
1775
1775
|
line-height: var(--dds-line-height-relaxed);
|
|
1776
|
-
inset-inline-start: 0;
|
|
1777
1776
|
display: flex;
|
|
1778
1777
|
align-items: center;
|
|
1779
1778
|
justify-content: center;
|
|
@@ -1787,27 +1786,24 @@ a.no-text-decoration {
|
|
|
1787
1786
|
/* Unordered list bullets */
|
|
1788
1787
|
.dds-list[data-ordered="false"] .dds-list-item::before {
|
|
1789
1788
|
content: var(--dds-list-bullet, "•");
|
|
1790
|
-
|
|
1791
|
-
left: 0;
|
|
1792
|
-
top: 0;
|
|
1789
|
+
flex-shrink: 0;
|
|
1793
1790
|
width: var(--dds-list-badge-size, 2.5rem);
|
|
1794
1791
|
height: var(--dds-list-badge-size, 2.5rem);
|
|
1795
|
-
inset-inline-start: 0;
|
|
1796
1792
|
display: flex;
|
|
1793
|
+
transform: translateY(var(--dds-list-bullet-offset, -0.1em));
|
|
1797
1794
|
align-items: center;
|
|
1798
1795
|
justify-content: center;
|
|
1799
|
-
font-size: var(--dds-list-bullet-size, 1.
|
|
1796
|
+
font-size: var(--dds-list-bullet-size, 1.25rem);
|
|
1800
1797
|
color: var(--dds-list-badge-text);
|
|
1801
1798
|
}
|
|
1802
|
-
/* Hide ::before when
|
|
1803
|
-
|
|
1799
|
+
/* Hide ::before when item has a custom icon.
|
|
1800
|
+
Specificity matches the show rules above (0-3-1) and comes after, so it wins. */
|
|
1801
|
+
.dds-list .dds-list-item[data-has-icon="true"]::before {
|
|
1804
1802
|
display: none;
|
|
1805
1803
|
}
|
|
1806
1804
|
/* Custom icon bullet */
|
|
1807
1805
|
.dds-list-item-icon {
|
|
1808
|
-
|
|
1809
|
-
left: 0;
|
|
1810
|
-
top: 0;
|
|
1806
|
+
flex-shrink: 0;
|
|
1811
1807
|
width: var(--dds-list-badge-size, 2.5rem);
|
|
1812
1808
|
height: var(--dds-list-badge-size, 2.5rem);
|
|
1813
1809
|
display: flex;
|
|
@@ -1819,6 +1815,27 @@ a.no-text-decoration {
|
|
|
1819
1815
|
width: 1.25rem;
|
|
1820
1816
|
height: 1.25rem;
|
|
1821
1817
|
}
|
|
1818
|
+
/* Content wrapper — flex child that fills remaining space */
|
|
1819
|
+
.dds-list-item-content {
|
|
1820
|
+
flex: 1;
|
|
1821
|
+
min-width: 0;
|
|
1822
|
+
}
|
|
1823
|
+
/* Neutralize consuming-site typography margins that would misalign the badge.
|
|
1824
|
+
The list item's own margin/padding controls spacing — not the children's. */
|
|
1825
|
+
.dds-list-item-content > :first-child {
|
|
1826
|
+
margin-top: 0;
|
|
1827
|
+
}
|
|
1828
|
+
.dds-list-item-content > :last-child {
|
|
1829
|
+
margin-bottom: 0;
|
|
1830
|
+
}
|
|
1831
|
+
/* For unordered lists, vertically center the content within the li so the first
|
|
1832
|
+
text line's center aligns with the bullet/icon center.
|
|
1833
|
+
margin-block: auto distributes remaining space evenly above and below the
|
|
1834
|
+
content span, so its midpoint always lands at badge-size/2 — the same as the
|
|
1835
|
+
bullet center — regardless of font-size or line-height. */
|
|
1836
|
+
.dds-list[data-ordered="false"] .dds-list-item-content {
|
|
1837
|
+
margin-block: auto;
|
|
1838
|
+
}
|
|
1822
1839
|
/* ==========================================================================
|
|
1823
1840
|
Popover Component
|
|
1824
1841
|
Uses the native Popover API for top-layer rendering.
|
|
@@ -1827,7 +1844,7 @@ a.no-text-decoration {
|
|
|
1827
1844
|
/* Trigger */
|
|
1828
1845
|
.dds-popover-trigger {
|
|
1829
1846
|
display: inline;
|
|
1830
|
-
cursor:
|
|
1847
|
+
cursor: help;
|
|
1831
1848
|
text-decoration-line: underline;
|
|
1832
1849
|
text-decoration-style: dotted;
|
|
1833
1850
|
text-decoration-color: currentColor;
|
|
@@ -1923,6 +1940,38 @@ a.no-text-decoration {
|
|
|
1923
1940
|
.dds-popover-lg {
|
|
1924
1941
|
width: var(--dds-popover-width-lg);
|
|
1925
1942
|
}
|
|
1943
|
+
/* ==========================================================================
|
|
1944
|
+
Close button — sits in the upper-right corner of the popover panel
|
|
1945
|
+
========================================================================== */
|
|
1946
|
+
.dds-popover-close {
|
|
1947
|
+
position: absolute;
|
|
1948
|
+
top: 0.5rem;
|
|
1949
|
+
right: 0.5rem;
|
|
1950
|
+
display: flex;
|
|
1951
|
+
align-items: center;
|
|
1952
|
+
justify-content: center;
|
|
1953
|
+
width: 1.5rem;
|
|
1954
|
+
height: 1.5rem;
|
|
1955
|
+
padding: 0;
|
|
1956
|
+
background: transparent;
|
|
1957
|
+
border: none;
|
|
1958
|
+
border-radius: 0.25rem;
|
|
1959
|
+
cursor: pointer;
|
|
1960
|
+
color: var(--dds-popover-eyebrow-color);
|
|
1961
|
+
font-size: 1.125rem;
|
|
1962
|
+
line-height: 1;
|
|
1963
|
+
transition:
|
|
1964
|
+
background 120ms,
|
|
1965
|
+
color 120ms;
|
|
1966
|
+
}
|
|
1967
|
+
.dds-popover-close:hover {
|
|
1968
|
+
background: var(--dds-popover-border);
|
|
1969
|
+
color: var(--dds-popover-text);
|
|
1970
|
+
}
|
|
1971
|
+
.dds-popover-close:focus-visible {
|
|
1972
|
+
outline: 2px solid var(--dds-link-color);
|
|
1973
|
+
outline-offset: 2px;
|
|
1974
|
+
}
|
|
1926
1975
|
/* ==========================================================================
|
|
1927
1976
|
Shared inner elements
|
|
1928
1977
|
========================================================================== */
|
|
@@ -1934,6 +1983,7 @@ a.no-text-decoration {
|
|
|
1934
1983
|
text-transform: uppercase;
|
|
1935
1984
|
color: var(--dds-popover-eyebrow-color);
|
|
1936
1985
|
margin-bottom: 0.25rem;
|
|
1986
|
+
padding-right: 1.75rem; /* leave room for the close button */
|
|
1937
1987
|
}
|
|
1938
1988
|
.dds-popover-title {
|
|
1939
1989
|
margin: 0 0 0.5rem;
|
|
@@ -1941,6 +1991,7 @@ a.no-text-decoration {
|
|
|
1941
1991
|
font-weight: var(--dds-font-semibold);
|
|
1942
1992
|
color: var(--dds-popover-title-color);
|
|
1943
1993
|
line-height: var(--dds-line-height-tight);
|
|
1994
|
+
padding-right: 1.75rem; /* leave room for the close button */
|
|
1944
1995
|
}
|
|
1945
1996
|
.dds-popover-title dfn {
|
|
1946
1997
|
font-style: normal;
|