@dreamlake/dockit 0.2.20 → 0.2.22

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.
@@ -43,3 +43,29 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
43
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
44
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
45
45
  SOFTWARE.
46
+
47
+ ---
48
+
49
+ UIKit tab primitives: https://github.com/dreamlake-ai/uikit-workspace
50
+
51
+ MIT License
52
+
53
+ Copyright (c) 2026 DreamLake
54
+
55
+ Permission is hereby granted, free of charge, to any person obtaining a copy
56
+ of this software and associated documentation files (the "Software"), to deal
57
+ in the Software without restriction, including without limitation the rights
58
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
59
+ copies of the Software, and to permit persons to whom the Software is
60
+ furnished to do so, subject to the following conditions:
61
+
62
+ The above copyright notice and this permission notice shall be included in all
63
+ copies or substantial portions of the Software.
64
+
65
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
66
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
67
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
68
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
69
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
70
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
71
+ SOFTWARE.
@@ -1,5 +1,6 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
- import { useRef, useState } from "react";
2
+ import { useContext, useRef, useState } from "react";
3
+ import { CodeTabsContext } from "./code-tabs-context.js";
3
4
  import { useLineNumbers } from "../lib/use-line-numbers.js";
4
5
  const headerBtnStyle = (active) => ({
5
6
  display: "inline-flex",
@@ -19,6 +20,7 @@ const headerBtnStyle = (active) => ({
19
20
  transition: "color 0.12s ease, border-color 0.12s ease"
20
21
  });
21
22
  function CodeBlock({ children, filename, lang }) {
23
+ const embedded = useContext(CodeTabsContext);
22
24
  const wrapRef = useRef(null);
23
25
  const [copied, setCopied] = useState(false);
24
26
  const [showLines, setShowLines] = useLineNumbers();
@@ -39,11 +41,11 @@ function CodeBlock({ children, filename, lang }) {
39
41
  {
40
42
  ref: wrapRef,
41
43
  "data-line-numbers": showLines ? "on" : "off",
42
- className: "group relative border border-doc-template-faint bg-doc-template-code",
44
+ className: embedded ? void 0 : "group relative border border-doc-template-faint bg-doc-template-code",
43
45
  style: {
44
- margin: "18px 0 22px",
45
- borderRadius: "var(--radius-doc-template)",
46
- overflow: "hidden"
46
+ margin: embedded ? 0 : "18px 0 22px",
47
+ borderRadius: embedded ? 0 : "var(--radius-doc-template)",
48
+ overflow: embedded ? "visible" : "hidden"
47
49
  },
48
50
  children: [
49
51
  filename && /* @__PURE__ */ jsxs(
@@ -97,7 +99,7 @@ function CodeBlock({ children, filename, lang }) {
97
99
  "div",
98
100
  {
99
101
  className: "absolute top-0 right-0 z-10 flex items-center opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity duration-150",
100
- style: { gap: 6, padding: "8px 8px", isolation: "isolate" },
102
+ style: { gap: 6, padding: embedded ? "3px 8px" : "8px 8px", isolation: "isolate" },
101
103
  children: [
102
104
  /* @__PURE__ */ jsx(
103
105
  "span",
@@ -109,8 +111,8 @@ function CodeBlock({ children, filename, lang }) {
109
111
  zIndex: -1,
110
112
  pointerEvents: "none",
111
113
  borderRadius: 6,
112
- background: "color-mix(in srgb, var(--color-doc-template-code) 88%, transparent)",
113
- boxShadow: "0 0 10px 6px var(--color-doc-template-code)",
114
+ background: embedded ? "var(--color-doc-template-bg)" : "color-mix(in srgb, var(--color-doc-template-code) 88%, transparent)",
115
+ boxShadow: embedded ? void 0 : "0 0 10px 6px var(--color-doc-template-code)",
114
116
  backdropFilter: "blur(8px)",
115
117
  WebkitBackdropFilter: "blur(8px)"
116
118
  }
@@ -0,0 +1,13 @@
1
+ import { ReactNode } from 'react';
2
+ export interface CodeExampleProps {
3
+ label: string;
4
+ children: ReactNode;
5
+ }
6
+ /** Keep ordinary fenced MDX as children so generated Markdown retains each example. */
7
+ export declare function CodeExample({ children }: CodeExampleProps): import("react").JSX.Element;
8
+ export interface CodeTabsProps {
9
+ children: ReactNode;
10
+ 'aria-label'?: string;
11
+ }
12
+ /** Equivalent fenced examples in one frame; arrow keys activate and focus tabs. */
13
+ export declare function CodeTabs({ children, 'aria-label': label }: CodeTabsProps): import("react").JSX.Element | null;
@@ -0,0 +1,60 @@
1
+ import { jsx, Fragment, jsxs } from "react/jsx-runtime";
2
+ import { Children, isValidElement, useState, useId, useRef } from "react";
3
+ import { Tabs, TabsList, TabsTrigger } from "../vendor/@dreamlake/uikit/src/components/Tabs/Tabs.js";
4
+ import { CodeTabsContext } from "./code-tabs-context.js";
5
+ function CodeExample({ children }) {
6
+ return /* @__PURE__ */ jsx(Fragment, { children });
7
+ }
8
+ function CodeTabs({ children, "aria-label": label = "Code examples" }) {
9
+ const examples = Children.toArray(children).filter(isValidElement);
10
+ const [selected, setSelected] = useState(0);
11
+ const active = Math.min(selected, Math.max(0, examples.length - 1));
12
+ const id = useId();
13
+ const buttons = useRef([]);
14
+ if (!examples.length) return null;
15
+ return /* @__PURE__ */ jsx("div", { "data-code-tabs": true, className: "dockit-code-tabs group relative border border-doc-template-faint bg-doc-template-code", children: /* @__PURE__ */ jsxs(Tabs, { value: String(active), onValueChange: (value) => setSelected(Number(value)), children: [
16
+ /* @__PURE__ */ jsx("div", { className: "dockit-code-tabs-header", children: /* @__PURE__ */ jsx(TabsList, { "aria-label": label, className: "dockit-code-tabs-list border-0 font-doc-template-ui", children: examples.map((example, index) => /* @__PURE__ */ jsx(
17
+ TabsTrigger,
18
+ {
19
+ value: String(index),
20
+ className: "shrink-0 text-doc-template-muted hover:text-doc-template-ink data-[active]:text-doc-template-ink data-[active]:border-doc-template-ink text-[12px]",
21
+ ref: (element) => {
22
+ buttons.current[index] = element;
23
+ },
24
+ id: `${id}-tab-${index}`,
25
+ "aria-controls": `${id}-panel-${index}`,
26
+ "aria-selected": active === index,
27
+ tabIndex: active === index ? 0 : -1,
28
+ onKeyDown: (event) => {
29
+ let next;
30
+ if (event.key === "ArrowRight") next = (index + 1) % examples.length;
31
+ else if (event.key === "ArrowLeft") next = (index - 1 + examples.length) % examples.length;
32
+ else if (event.key === "Home") next = 0;
33
+ else if (event.key === "End") next = examples.length - 1;
34
+ else return;
35
+ event.preventDefault();
36
+ setSelected(next);
37
+ buttons.current[next]?.focus();
38
+ },
39
+ children: example.props.label
40
+ },
41
+ example.key ?? index
42
+ )) }) }),
43
+ /* @__PURE__ */ jsx(CodeTabsContext.Provider, { value: true, children: examples.map((example, index) => /* @__PURE__ */ jsx(
44
+ "div",
45
+ {
46
+ role: "tabpanel",
47
+ id: `${id}-panel-${index}`,
48
+ "aria-labelledby": `${id}-tab-${index}`,
49
+ hidden: active !== index,
50
+ tabIndex: 0,
51
+ children: example.props.children
52
+ },
53
+ example.key ?? index
54
+ )) })
55
+ ] }) });
56
+ }
57
+ export {
58
+ CodeExample,
59
+ CodeTabs
60
+ };
@@ -0,0 +1,2 @@
1
+ /** Internal: a fenced block shares the surrounding tabs' frame and toolbar. */
2
+ export declare const CodeTabsContext: import('react').Context<boolean>;
@@ -0,0 +1,5 @@
1
+ import { createContext } from "react";
2
+ const CodeTabsContext = createContext(false);
3
+ export {
4
+ CodeTabsContext
5
+ };
package/dist/index.d.ts CHANGED
@@ -30,6 +30,7 @@ export { Callout } from './components/Callout';
30
30
  export { Chip, type ChipProps, type ChipVariant } from './components/Chip';
31
31
  export { ClientOnly } from './components/ClientOnly';
32
32
  export { CodeBlock } from './components/CodeBlock';
33
+ export { CodeTabs, CodeExample, type CodeTabsProps, type CodeExampleProps } from './components/CodeTabs';
33
34
  export { DocFooter } from './components/DocFooter';
34
35
  export { mdxComponents } from './components/mdx-components';
35
36
  export { Preview, type PreviewProps } from './components/Preview';
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ import { Callout } from "./components/Callout.js";
15
15
  import { Chip } from "./components/Chip.js";
16
16
  import { ClientOnly } from "./components/ClientOnly.js";
17
17
  import { CodeBlock } from "./components/CodeBlock.js";
18
+ import { CodeExample, CodeTabs } from "./components/CodeTabs.js";
18
19
  import { DocFooter } from "./components/DocFooter.js";
19
20
  import { mdxComponents } from "./components/mdx-components.js";
20
21
  import { Preview } from "./components/Preview.js";
@@ -45,6 +46,8 @@ export {
45
46
  Chip,
46
47
  ClientOnly,
47
48
  CodeBlock,
49
+ CodeExample,
50
+ CodeTabs,
48
51
  DOC_PREFIX,
49
52
  DocFooter,
50
53
  Layout,
package/dist/styles.css CHANGED
@@ -378,3 +378,25 @@
378
378
  .doc-sidebar::-webkit-scrollbar-thumb { background: var(--color-doc-template-faint-strong); border-radius: 3px; }
379
379
  .doc-sidebar .sidebar-section > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
380
380
  .doc-sidebar .sidebar-section > span:last-child { flex-shrink: 0; white-space: nowrap; }
381
+
382
+ /* One frame and toolbar for ordinary MDX fenced examples. Inactive panels keep
383
+ their code/control state but are absent from keyboard and accessibility flow. */
384
+ .dockit-code-tabs {
385
+ margin: 18px 0 22px;
386
+ border-radius: var(--radius-doc-template);
387
+ overflow: hidden;
388
+ }
389
+ .dockit-code-tabs-header {
390
+ border-bottom: 1px solid var(--color-doc-template-faint);
391
+ background: var(--color-doc-template-bg);
392
+ min-height: 30px;
393
+ padding: 0 156px 0 12px;
394
+ }
395
+ .dockit-code-tabs-list { overflow-x: auto; min-height: 29px; }
396
+ .dockit-code-tabs-list [role='tab'] { background: transparent; }
397
+ .dockit-code-tabs-list [role='tab']:focus-visible,
398
+ .dockit-code-tabs [role='tabpanel']:focus-visible {
399
+ outline: 2px solid var(--color-doc-template-accent);
400
+ outline-offset: -3px;
401
+ }
402
+ .dockit-code-tabs [role='tabpanel'][hidden] { display: none; }
@@ -0,0 +1,334 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useState, useRef, useEffect, useContext, createContext } from "react";
3
+ import { cn } from "../../lib/utils.js";
4
+ const TabsContext = createContext(null);
5
+ function useTabsContext(name) {
6
+ const c = useContext(TabsContext);
7
+ if (!c) throw new Error(`<${name}> must be used inside <Tabs>`);
8
+ return c;
9
+ }
10
+ const underlineSizeMap = {
11
+ xs: "text-uikit-11 h-5 pt-px pb-[5px] mr-3",
12
+ sm: "text-uikit-12 h-[27px] pt-1 pb-2 mr-[18px]",
13
+ md: "text-[13.5px] h-[22px] pt-px pb-2 mr-[18px]",
14
+ lg: "text-[15px] h-[34px] pt-1 pb-3 mr-[22px]"
15
+ };
16
+ const segmentConfig = {
17
+ xs: {
18
+ inset: 1,
19
+ containerR: 3,
20
+ pillR: 3,
21
+ buttonR: 3,
22
+ padV: 1,
23
+ padH: 4,
24
+ iconSize: 9
25
+ },
26
+ sm: {
27
+ inset: 1,
28
+ containerR: 4,
29
+ pillR: 4,
30
+ buttonR: 4,
31
+ padV: 2,
32
+ padH: 5,
33
+ iconSize: 10
34
+ },
35
+ md: {
36
+ inset: 2,
37
+ containerR: 6,
38
+ pillR: 5,
39
+ buttonR: 5,
40
+ padV: 4,
41
+ padH: 6,
42
+ iconSize: 12
43
+ },
44
+ lg: {
45
+ inset: 3,
46
+ containerR: 8,
47
+ pillR: 6,
48
+ buttonR: 6,
49
+ padV: 5,
50
+ padH: 7,
51
+ iconSize: 14
52
+ }
53
+ };
54
+ function UnderlineTabItem({
55
+ tab,
56
+ active,
57
+ size,
58
+ innerRef,
59
+ onClick
60
+ }) {
61
+ const isSmall = size === "xs" || size === "sm";
62
+ return /* @__PURE__ */ jsxs(
63
+ "div",
64
+ {
65
+ ref: innerRef,
66
+ role: "tab",
67
+ "aria-selected": active,
68
+ "data-active": active || void 0,
69
+ "data-small": isSmall || void 0,
70
+ onClick,
71
+ className: cn(
72
+ "group/tab relative inline-flex items-center gap-1.5 cursor-pointer select-none whitespace-nowrap",
73
+ "font-uikit-ui tracking-uikit-snug",
74
+ "transition-[color,opacity] duration-[120ms]",
75
+ underlineSizeMap[size],
76
+ // Color: muted by default, ink when active.
77
+ "text-uikit-muted data-[active]:text-uikit-ink",
78
+ // Weight (only when !isSmall).
79
+ "[&:not([data-small])]:font-medium",
80
+ "[&:not([data-small])]:data-[active]:font-semibold",
81
+ // Opacity (large variants): rest 0.45, hover 0.7, active 1.
82
+ "[&:not([data-small])]:opacity-45",
83
+ "[&:not([data-small])]:hover:opacity-70",
84
+ "[&:not([data-small])]:data-[active]:opacity-100",
85
+ // Opacity (small variants): rest 0.75, hover/active 1.
86
+ "data-[small]:opacity-75",
87
+ "data-[small]:hover:opacity-100",
88
+ "data-[small]:data-[active]:opacity-100"
89
+ ),
90
+ children: [
91
+ /* @__PURE__ */ jsx("span", { children: tab.label }),
92
+ tab.count != null && /* @__PURE__ */ jsx(
93
+ "span",
94
+ {
95
+ className: cn(
96
+ "font-uikit-mono text-[9.5px] rounded-full px-1.5 py-px tracking-uikit-wide",
97
+ "transition-[background-color,opacity] duration-[120ms]",
98
+ // Weight + opacity track the parent's active/hover state.
99
+ "font-medium opacity-55 group-hover/tab:opacity-90 group-data-[active]/tab:opacity-100",
100
+ "group-data-[active]/tab:font-semibold",
101
+ // Background tracks parent state — uses currentColor for theme inheritance.
102
+ "bg-[color-mix(in_oklab,currentColor_5%,transparent)]",
103
+ "group-data-[active]/tab:bg-[color-mix(in_oklab,currentColor_12%,transparent)]"
104
+ ),
105
+ children: tab.count
106
+ }
107
+ )
108
+ ]
109
+ }
110
+ );
111
+ }
112
+ function Tabs(props) {
113
+ if (props.children !== void 0) {
114
+ return /* @__PURE__ */ jsx(
115
+ TabsRoot,
116
+ {
117
+ value: props.value,
118
+ defaultValue: props.defaultValue,
119
+ onValueChange: props.onValueChange ?? props.onChange,
120
+ className: props.className,
121
+ children: props.children
122
+ }
123
+ );
124
+ }
125
+ return /* @__PURE__ */ jsx(TabsData, { ...props });
126
+ }
127
+ function TabsData({
128
+ tabs,
129
+ defaultValue,
130
+ value,
131
+ onChange,
132
+ onValueChange,
133
+ variant = "underline",
134
+ size = "md",
135
+ indicatorHeight,
136
+ className
137
+ }) {
138
+ const [internalValue, setInternalValue] = useState(
139
+ defaultValue ?? tabs?.[0]?.value ?? ""
140
+ );
141
+ const [bar, setBar] = useState({
142
+ left: 0,
143
+ width: 0,
144
+ height: 0,
145
+ ready: false
146
+ });
147
+ const tabRefs = useRef({});
148
+ const activeValue = value !== void 0 ? value : internalValue;
149
+ const handleTabClick = (newValue) => {
150
+ if (value === void 0) setInternalValue(newValue);
151
+ (onValueChange ?? onChange)?.(newValue);
152
+ };
153
+ useEffect(() => {
154
+ if (value !== void 0) setInternalValue(value);
155
+ }, [value]);
156
+ useEffect(() => {
157
+ const el = tabRefs.current[activeValue];
158
+ if (!el) return;
159
+ setBar({
160
+ left: el.offsetLeft,
161
+ width: el.offsetWidth,
162
+ height: el.offsetHeight,
163
+ ready: true
164
+ });
165
+ }, [activeValue, tabs?.length]);
166
+ const segCfg = segmentConfig[size];
167
+ const tabList = tabs ?? [];
168
+ return /* @__PURE__ */ jsxs(
169
+ "div",
170
+ {
171
+ role: "tablist",
172
+ className: cn(
173
+ "relative font-uikit-ui",
174
+ variant === "underline" && "flex items-end",
175
+ variant === "segment" && "inline-flex bg-uikit-ink-5",
176
+ className
177
+ ),
178
+ style: variant === "segment" ? {
179
+ padding: segCfg.inset,
180
+ gap: 1,
181
+ borderRadius: segCfg.containerR
182
+ } : void 0,
183
+ children: [
184
+ variant === "underline" && /* @__PURE__ */ jsx(
185
+ "span",
186
+ {
187
+ className: "absolute pointer-events-none z-[2] bg-uikit-ink",
188
+ style: {
189
+ left: bar.left,
190
+ width: bar.width,
191
+ height: indicatorHeight ?? 4,
192
+ bottom: -1,
193
+ transition: bar.ready ? "left 280ms cubic-bezier(.4,0,.2,1), width 280ms cubic-bezier(.4,0,.2,1)" : "none"
194
+ }
195
+ }
196
+ ),
197
+ variant === "segment" && /* @__PURE__ */ jsx(
198
+ "div",
199
+ {
200
+ "aria-hidden": true,
201
+ className: "absolute pointer-events-none bg-uikit-bg shadow-[0_1px_2px_var(--shadow-tint-1)]",
202
+ style: {
203
+ top: segCfg.inset,
204
+ bottom: segCfg.inset,
205
+ left: 0,
206
+ width: bar.width,
207
+ transform: `translateX(${bar.left}px)`,
208
+ borderRadius: segCfg.pillR,
209
+ opacity: bar.ready ? 1 : 0,
210
+ // Position springs (--uikit-ease-thumb, the theme toggle's curve);
211
+ // width does NOT. An overshoot is a thumb arriving with weight when
212
+ // it only slides, but a width that overshoots is the pill's far
213
+ // edge lunging past the label it is meant to sit under — two
214
+ // segments of different widths made that obvious. So width rides
215
+ // the same duration on a curve that only decelerates, and the two
216
+ // land together.
217
+ transition: bar.ready ? "transform var(--uikit-dur-thumb, 420ms) var(--uikit-ease-thumb, cubic-bezier(.34,1.45,.55,1)), width var(--uikit-dur-thumb, 420ms) cubic-bezier(.32,.72,0,1)" : "none"
218
+ }
219
+ }
220
+ ),
221
+ tabList.map((tab) => {
222
+ const active = tab.value === activeValue;
223
+ if (variant === "underline") {
224
+ return /* @__PURE__ */ jsx(
225
+ UnderlineTabItem,
226
+ {
227
+ tab,
228
+ active,
229
+ size,
230
+ innerRef: (el) => {
231
+ tabRefs.current[tab.value] = el;
232
+ },
233
+ onClick: () => handleTabClick(tab.value)
234
+ },
235
+ tab.value
236
+ );
237
+ }
238
+ return /* @__PURE__ */ jsx(
239
+ "button",
240
+ {
241
+ ref: (el) => {
242
+ tabRefs.current[tab.value] = el;
243
+ },
244
+ type: "button",
245
+ title: tab.title,
246
+ "aria-pressed": active,
247
+ "data-active": active || void 0,
248
+ onClick: () => handleTabClick(tab.value),
249
+ className: cn(
250
+ "relative z-[1] inline-flex items-center justify-center cursor-pointer select-none",
251
+ "appearance-none border-0 bg-transparent outline-none",
252
+ "text-uikit-muted data-[active]:text-uikit-ink",
253
+ "transition-colors duration-[160ms]"
254
+ ),
255
+ style: {
256
+ padding: `${segCfg.padV}px ${segCfg.padH}px`,
257
+ borderRadius: segCfg.buttonR,
258
+ fontSize: segCfg.iconSize,
259
+ lineHeight: 1
260
+ },
261
+ children: tab.label
262
+ },
263
+ tab.value
264
+ );
265
+ })
266
+ ]
267
+ }
268
+ );
269
+ }
270
+ function TabsRoot({
271
+ value,
272
+ defaultValue,
273
+ onValueChange,
274
+ className,
275
+ children
276
+ }) {
277
+ const [internal, setInternal] = useState(defaultValue ?? "");
278
+ const isControlled = value !== void 0;
279
+ const current = isControlled ? value : internal;
280
+ const setValue = (v) => {
281
+ if (!isControlled) setInternal(v);
282
+ onValueChange?.(v);
283
+ };
284
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value: { value: current, setValue }, children: /* @__PURE__ */ jsx("div", { className: cn("flex flex-col", className), children }) });
285
+ }
286
+ function TabsList({ className, ...props }) {
287
+ return /* @__PURE__ */ jsx(
288
+ "div",
289
+ {
290
+ role: "tablist",
291
+ className: cn(
292
+ "flex items-end gap-3 border-b border-uikit-faint font-uikit-ui",
293
+ className
294
+ ),
295
+ ...props
296
+ }
297
+ );
298
+ }
299
+ function TabsTrigger({
300
+ value,
301
+ className,
302
+ children,
303
+ onClick,
304
+ ...props
305
+ }) {
306
+ const ctx = useTabsContext("TabsTrigger");
307
+ const active = ctx.value === value;
308
+ return /* @__PURE__ */ jsx(
309
+ "button",
310
+ {
311
+ type: "button",
312
+ role: "tab",
313
+ "aria-selected": active,
314
+ "data-active": active || void 0,
315
+ onClick: (e) => {
316
+ onClick?.(e);
317
+ ctx.setValue(value);
318
+ },
319
+ className: cn(
320
+ "relative -mb-px cursor-pointer select-none whitespace-nowrap border-b-2 border-transparent",
321
+ "pb-1.5 pt-1 text-uikit-12 text-uikit-muted transition-colors",
322
+ "hover:text-uikit-ink data-[active]:border-uikit-ink data-[active]:text-uikit-ink data-[active]:font-medium",
323
+ className
324
+ ),
325
+ ...props,
326
+ children
327
+ }
328
+ );
329
+ }
330
+ export {
331
+ Tabs,
332
+ TabsList,
333
+ TabsTrigger
334
+ };
@@ -0,0 +1,56 @@
1
+ import { clsx } from "clsx";
2
+ import { extendTailwindMerge } from "tailwind-merge";
3
+ const twMerge = extendTailwindMerge({
4
+ override: {
5
+ // Standard `font-size` group (covers stock `text-base`, `text-[Npx]`, etc.)
6
+ // no longer invalidates `leading-*`. Required so e.g. `text-[13.5px]`
7
+ // and `leading-[1.2]` can coexist on Tag.
8
+ conflictingClassGroups: {
9
+ "font-size": []
10
+ }
11
+ },
12
+ extend: {
13
+ classGroups: {
14
+ // Custom group for our font-size scale. Only conflicts with itself.
15
+ "uikit-font-size": [
16
+ "text-uikit-9",
17
+ "text-uikit-10",
18
+ "text-uikit-11",
19
+ "text-uikit-12",
20
+ "text-uikit-13",
21
+ "text-uikit-14",
22
+ "text-uikit-17",
23
+ "text-uikit-22"
24
+ ],
25
+ // Text color utilities — token aliases + alpha-mix presets.
26
+ "text-color": [
27
+ "text-uikit-ink",
28
+ "text-uikit-muted",
29
+ "text-uikit-bg",
30
+ "text-uikit-panel",
31
+ "text-uikit-rail",
32
+ "text-uikit-accent",
33
+ "text-uikit-accent-soft",
34
+ "text-uikit-faint",
35
+ "text-uikit-chip",
36
+ "text-uikit-search",
37
+ "text-uikit-selected",
38
+ "text-uikit-danger",
39
+ "text-uikit-ink-4",
40
+ "text-uikit-ink-5",
41
+ "text-uikit-ink-6",
42
+ "text-uikit-ink-8",
43
+ "text-uikit-ink-12",
44
+ "text-uikit-ink-50",
45
+ "text-uikit-accent-12",
46
+ "text-uikit-danger-8"
47
+ ]
48
+ }
49
+ }
50
+ });
51
+ function cn(...inputs) {
52
+ return twMerge(clsx(inputs));
53
+ }
54
+ export {
55
+ cn
56
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreamlake/dockit",
3
- "version": "0.2.20",
3
+ "version": "0.2.22",
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",
@@ -42,10 +42,10 @@
42
42
  "@mdx-js/react": ">=3.0.0",
43
43
  "react": ">=19.0.0",
44
44
  "react-dom": ">=19.0.0",
45
+ "tailwindcss": "^4.0.0",
45
46
  "vike": "^0.4.210",
46
47
  "vike-react": "^0.5.0",
47
- "vite": ">=6.0.0",
48
- "tailwindcss": "^4.0.0"
48
+ "vite": ">=6.0.0"
49
49
  },
50
50
  "peerDependenciesMeta": {
51
51
  "vite": {
@@ -57,11 +57,13 @@
57
57
  "@shikijs/rehype": "^1.24.0",
58
58
  "@tailwindcss/vite": "^4.0.0",
59
59
  "@vitejs/plugin-react": "^4.3.4",
60
+ "clsx": "^2.1.1",
60
61
  "rehype-slug": "^6.0.0",
61
62
  "remark-frontmatter": "^5.0.0",
62
63
  "remark-gfm": "^4.0.0",
63
64
  "remark-mdx-frontmatter": "^5.2.0",
64
65
  "shiki": "^1.24.0",
66
+ "tailwind-merge": "^3.7.0",
65
67
  "yaml": "^2.9.0"
66
68
  },
67
69
  "devDependencies": {
@@ -71,12 +73,13 @@
71
73
  "@types/react-dom": "latest",
72
74
  "react": "latest",
73
75
  "react-dom": "latest",
76
+ "tailwindcss": "^4.0.0",
74
77
  "typescript": "^5.7.0",
75
78
  "vike": "^0.4.210",
76
79
  "vike-react": "^0.5.0",
77
80
  "vite": "^7.0.0",
78
81
  "vite-plugin-dts": "^4.3.0",
79
- "tailwindcss": "^4.0.0"
82
+ "@dreamlake/uikit": "0.1.15"
80
83
  },
81
84
  "scripts": {
82
85
  "build": "vite build",