@dreamlake/dockit 0.2.11 → 0.2.13

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.
@@ -5,6 +5,7 @@ import { tabForUrl, TABS, urlInTab } from "../lib/tabs.js";
5
5
  import { pages } from "../lib/navigation.js";
6
6
  import { useHiddenToggle } from "../lib/use-hidden-toggle.js";
7
7
  const SPRING = "cubic-bezier(0.4, 0.7, 0.3, 1)";
8
+ const SSR_BAR_BOTTOM = -13;
8
9
  function TabStrip() {
9
10
  const { urlPathname } = usePageContext();
10
11
  const activeTab = tabForUrl(urlPathname);
@@ -21,28 +22,31 @@ function TabStrip() {
21
22
  const [bar, setBar] = useState({
22
23
  left: 0,
23
24
  width: 0,
25
+ bottom: SSR_BAR_BOTTOM,
24
26
  ready: false
25
27
  });
26
28
  const targetTab = hovered ?? activeTab;
27
- useLayoutEffect(() => {
29
+ function measure() {
28
30
  const container = containerRef.current;
29
31
  const target = linkRefs.current[targetTab];
30
32
  if (!container || !target) return;
31
33
  const cR = container.getBoundingClientRect();
32
34
  const tR = target.getBoundingClientRect();
33
- setBar({ left: tR.left - cR.left, width: tR.width, ready: true });
34
- }, [targetTab, urlPathname]);
35
+ const hR = container.closest("header")?.getBoundingClientRect();
36
+ const next = {
37
+ left: tR.left - cR.left,
38
+ width: tR.width,
39
+ bottom: hR ? cR.bottom - hR.bottom : SSR_BAR_BOTTOM,
40
+ ready: true
41
+ };
42
+ setBar(
43
+ (prev) => prev.ready && prev.left === next.left && prev.width === next.width && prev.bottom === next.bottom ? prev : next
44
+ );
45
+ }
46
+ useLayoutEffect(measure);
35
47
  useLayoutEffect(() => {
36
- function onResize() {
37
- const container = containerRef.current;
38
- const target = linkRefs.current[targetTab];
39
- if (!container || !target) return;
40
- const cR = container.getBoundingClientRect();
41
- const tR = target.getBoundingClientRect();
42
- setBar((b) => ({ ...b, left: tR.left - cR.left, width: tR.width }));
43
- }
44
- window.addEventListener("resize", onResize);
45
- return () => window.removeEventListener("resize", onResize);
48
+ window.addEventListener("resize", measure);
49
+ return () => window.removeEventListener("resize", measure);
46
50
  }, [targetTab]);
47
51
  if (visibleTabs.length === 0) return null;
48
52
  return /* @__PURE__ */ jsxs(
@@ -58,8 +62,9 @@ function TabStrip() {
58
62
  // intrinsic width (`shrink-0` on the <li>) and the strip clips
59
63
  // whatever no longer fits rather than reflowing.
60
64
  //
61
- // `clip`, not `hidden`: the underbar below sits at bottom:-13px,
62
- // deliberately outside this box. Setting `overflow-x: hidden`
65
+ // `clip`, not `hidden`: the underbar below sits at a negative
66
+ // bottom offset, deliberately outside this box (whenever the strip
67
+ // is shorter than the topbar). Setting `overflow-x: hidden`
63
68
  // makes CSS compute the still-`visible` overflow-y to `auto`,
64
69
  // which would clip that bar away (and risk a stray scrollbar).
65
70
  // `clip` is the one overflow value that leaves the other axis
@@ -109,7 +114,7 @@ function TabStrip() {
109
114
  "aria-hidden": true,
110
115
  style: {
111
116
  position: "absolute",
112
- bottom: -13,
117
+ bottom: bar.bottom,
113
118
  left: 0,
114
119
  height: 3,
115
120
  background: "var(--color-doc-template-ink)",
@@ -160,7 +160,7 @@ function Topbar({ searchOpen, onOpenSearch, onCloseSearch, query, setQuery }) {
160
160
  const [tabsFit, setTabsFit] = useState(false);
161
161
  const [tabsW, setTabsW] = useState(0);
162
162
  const [pinLeft, setPinLeft] = useState(0);
163
- const [searchPinRight, setSearchPinRight] = useState(null);
163
+ const [searchPinLeft, setSearchPinLeft] = useState(null);
164
164
  useLayoutEffect(() => {
165
165
  const tabsEl = tabsRef.current;
166
166
  if (!tabsEl) return;
@@ -178,13 +178,13 @@ function Topbar({ searchOpen, onOpenSearch, onCloseSearch, query, setQuery }) {
178
178
  const brandClear = brandMaxRight.current + 16 <= pin;
179
179
  const actions = actionsRef.current?.getBoundingClientRect();
180
180
  const actionsLeft = actions ? actions.left : window.innerWidth;
181
- const pinnedSearchLeft = textRight - closedWidth;
181
+ const pinnedSearchLeft = textRight;
182
182
  const packedSearchLeft = actionsLeft - 8 - closedWidth;
183
183
  const fits = (searchLeft) => w > 0 && brandClear && pin + w + 16 <= searchLeft;
184
- const fullPin = textRight + 16 <= actionsLeft && fits(pinnedSearchLeft);
184
+ const fullPin = textRight + closedWidth + 16 <= actionsLeft && fits(pinnedSearchLeft);
185
185
  setTabsW(w);
186
186
  setPinLeft(pin);
187
- setSearchPinRight(fullPin ? window.innerWidth - textRight : null);
187
+ setSearchPinLeft(fullPin ? pinnedSearchLeft : null);
188
188
  setTabsFit(fullPin || fits(packedSearchLeft));
189
189
  };
190
190
  measure();
@@ -244,14 +244,17 @@ function Topbar({ searchOpen, onOpenSearch, onCloseSearch, query, setQuery }) {
244
244
  placeSelf: "stretch",
245
245
  boxShadow: "0 4px 14px rgb(0 0 0 / 0.06)",
246
246
  transition: `left ${EXPAND_MS}ms ${EXPAND_EASE}, right ${EXPAND_MS}ms ${EXPAND_EASE}, background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease`
247
- } : searchPinRight != null ? {
248
- // Closed, right-aligned to the content column's right
249
- // edge (mirrors the pinned tab strip on the left edge).
247
+ } : searchPinLeft != null ? {
248
+ // Closed, sitting just outside the content column with
249
+ // its left edge on the column's right border (mirrors
250
+ // the tab strip pinned to the left edge). Left-anchored,
251
+ // so breakpoint width changes grow it away from the
252
+ // column and the shared border never moves.
250
253
  // (gridArea/placeSelf: see the note above about
251
254
  // fixed-positioned grid items.)
252
255
  position: "fixed",
253
256
  top: 6,
254
- right: searchPinRight,
257
+ left: searchPinLeft,
255
258
  width: closedWidth,
256
259
  maxWidth: closedWidth,
257
260
  height: 28,
@@ -180,6 +180,7 @@ const H1 = ({ id, children, style, ...rest }) => /* @__PURE__ */ jsxs(
180
180
  fontWeight: 700,
181
181
  letterSpacing: "-0.025em",
182
182
  margin: "18px 0 10px",
183
+ paddingBottom: 24,
183
184
  lineHeight: 1.1,
184
185
  gap: 8,
185
186
  ...style
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreamlake/dockit",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "The DreamLake documentation shell — Vike + React + Tailwind v4 + MDX docs framework with sidebar, TOC, search, and theming",
5
5
  "license": "MIT",
6
6
  "type": "module",