@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.
- package/THIRD_PARTY_NOTICES +26 -0
- package/dist/components/CodeBlock.js +10 -8
- package/dist/components/CodeTabs.d.ts +13 -0
- package/dist/components/CodeTabs.js +60 -0
- package/dist/components/code-tabs-context.d.ts +2 -0
- package/dist/components/code-tabs-context.js +5 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/styles.css +22 -0
- package/dist/vendor/@dreamlake/uikit/src/components/Tabs/Tabs.js +334 -0
- package/dist/vendor/@dreamlake/uikit/src/lib/utils.js +56 -0
- package/package.json +7 -4
package/THIRD_PARTY_NOTICES
CHANGED
|
@@ -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
|
+
};
|
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.
|
|
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
|
-
"
|
|
82
|
+
"@dreamlake/uikit": "0.1.15"
|
|
80
83
|
},
|
|
81
84
|
"scripts": {
|
|
82
85
|
"build": "vite build",
|