@doccov/ui 0.2.1 → 0.2.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/dist/{components/api → api}/index.js +9 -4
- package/dist/badge/index.d.ts +14 -0
- package/dist/badge/index.js +86 -0
- package/dist/breadcrumb/index.d.ts +24 -0
- package/dist/breadcrumb/index.js +77 -0
- package/dist/button/index.d.ts +18 -0
- package/dist/button/index.js +109 -0
- package/dist/coverage-trends/index.d.ts +46 -0
- package/dist/coverage-trends/index.js +182 -0
- package/dist/{components/docskit → docskit}/index.js +24 -5
- package/dist/file-change-row/index.d.ts +34 -0
- package/dist/file-change-row/index.js +4415 -0
- package/dist/file-chip/index.d.ts +7 -0
- package/dist/file-chip/index.js +30 -0
- package/dist/input/index.d.ts +23 -0
- package/dist/input/index.js +242 -0
- package/dist/lib/utils.js +0 -20
- package/dist/tabs/index.d.ts +56 -0
- package/dist/tabs/index.js +224 -0
- package/package.json +37 -5
- /package/dist/{components/api → api}/index.d.ts +0 -0
- /package/dist/{components/docskit → docskit}/index.d.ts +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// src/components/file-chip/file-chip.tsx
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
|
|
4
|
+
// src/lib/utils.ts
|
|
5
|
+
import { clsx } from "clsx";
|
|
6
|
+
import { twMerge } from "tailwind-merge";
|
|
7
|
+
function cn(...inputs) {
|
|
8
|
+
return twMerge(clsx(inputs));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// src/components/file-chip/file-chip.tsx
|
|
12
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
var FileChip = React.forwardRef(({ filename, clickable = true, className, ...props }, ref) => {
|
|
14
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
15
|
+
ref,
|
|
16
|
+
className: cn("inline-flex items-center gap-1 px-1.5 py-0.5 rounded font-mono text-sm", "bg-secondary text-secondary-foreground", clickable && "cursor-pointer hover:bg-accent transition-colors", className),
|
|
17
|
+
...props,
|
|
18
|
+
children: [
|
|
19
|
+
/* @__PURE__ */ jsx("span", {
|
|
20
|
+
className: "text-muted-foreground",
|
|
21
|
+
children: "@"
|
|
22
|
+
}),
|
|
23
|
+
filename
|
|
24
|
+
]
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
FileChip.displayName = "FileChip";
|
|
28
|
+
export {
|
|
29
|
+
FileChip
|
|
30
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { VariantProps } from "class-variance-authority";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
declare const inputVariants: unknown;
|
|
4
|
+
interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size">, VariantProps<typeof inputVariants> {
|
|
5
|
+
label?: string;
|
|
6
|
+
helperText?: string;
|
|
7
|
+
error?: string;
|
|
8
|
+
leftIcon?: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
declare const Input: unknown;
|
|
11
|
+
interface InputWithButtonProps extends Omit<InputProps, "rightIcon" | "onSubmit"> {
|
|
12
|
+
buttonText?: string;
|
|
13
|
+
buttonLoading?: boolean;
|
|
14
|
+
onButtonClick?: () => void;
|
|
15
|
+
onSubmit?: (value: string) => void;
|
|
16
|
+
}
|
|
17
|
+
declare const InputWithButton: unknown;
|
|
18
|
+
interface SearchInputProps extends Omit<InputProps, "leftIcon"> {
|
|
19
|
+
onClear?: () => void;
|
|
20
|
+
showClear?: boolean;
|
|
21
|
+
}
|
|
22
|
+
declare const SearchInput: unknown;
|
|
23
|
+
export { inputVariants, SearchInputProps, SearchInput, InputWithButtonProps, InputWithButton, InputProps, Input };
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/components/input/input.tsx
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
|
|
6
|
+
// src/lib/utils.ts
|
|
7
|
+
import { clsx } from "clsx";
|
|
8
|
+
import { twMerge } from "tailwind-merge";
|
|
9
|
+
function cn(...inputs) {
|
|
10
|
+
return twMerge(clsx(inputs));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// src/components/input/input.tsx
|
|
14
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
|
|
16
|
+
var inputVariants = cva([
|
|
17
|
+
"w-full font-mono text-[var(--input-text)]",
|
|
18
|
+
"placeholder:text-[var(--input-placeholder)]",
|
|
19
|
+
"border border-[var(--input-border)]",
|
|
20
|
+
"bg-[var(--input-bg)]",
|
|
21
|
+
"rounded-md outline-none transition-all duration-150",
|
|
22
|
+
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
23
|
+
], {
|
|
24
|
+
variants: {
|
|
25
|
+
inputSize: {
|
|
26
|
+
sm: "h-10 px-3 text-sm",
|
|
27
|
+
md: "h-12 px-4 text-base",
|
|
28
|
+
lg: "h-[66px] px-5 text-base"
|
|
29
|
+
},
|
|
30
|
+
variant: {
|
|
31
|
+
default: [
|
|
32
|
+
"hover:border-[var(--input-border-hover)]",
|
|
33
|
+
"focus:border-[var(--input-border-focus)]",
|
|
34
|
+
"focus:bg-[var(--input-bg-focus)]",
|
|
35
|
+
"focus:shadow-[var(--input-focus-shadow)]"
|
|
36
|
+
],
|
|
37
|
+
error: [
|
|
38
|
+
"border-destructive/60",
|
|
39
|
+
"focus:border-destructive",
|
|
40
|
+
"focus:shadow-[0_0_0_3px_rgb(254,202,202)]"
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
defaultVariants: {
|
|
45
|
+
inputSize: "lg",
|
|
46
|
+
variant: "default"
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
var Input = React.forwardRef(({ className, inputSize, variant, label, helperText, error, leftIcon, id, ...props }, ref) => {
|
|
50
|
+
const generatedId = React.useId();
|
|
51
|
+
const inputId = id || `input-${generatedId}`;
|
|
52
|
+
const hasError = !!error;
|
|
53
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
54
|
+
className: "w-full space-y-2",
|
|
55
|
+
children: [
|
|
56
|
+
label && /* @__PURE__ */ jsx("label", {
|
|
57
|
+
htmlFor: inputId,
|
|
58
|
+
className: "text-sm font-medium text-[var(--input-text)]",
|
|
59
|
+
children: label
|
|
60
|
+
}),
|
|
61
|
+
/* @__PURE__ */ jsxs("div", {
|
|
62
|
+
className: "relative",
|
|
63
|
+
children: [
|
|
64
|
+
leftIcon && /* @__PURE__ */ jsx("div", {
|
|
65
|
+
className: "absolute left-4 top-1/2 -translate-y-1/2 text-[var(--input-placeholder)] [&_svg]:size-5",
|
|
66
|
+
children: leftIcon
|
|
67
|
+
}),
|
|
68
|
+
/* @__PURE__ */ jsx("input", {
|
|
69
|
+
id: inputId,
|
|
70
|
+
ref,
|
|
71
|
+
className: cn(inputVariants({ inputSize, variant: hasError ? "error" : variant }), leftIcon && "pl-12", className),
|
|
72
|
+
...props
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
}),
|
|
76
|
+
(helperText || error) && /* @__PURE__ */ jsx("p", {
|
|
77
|
+
className: cn("text-sm font-mono", hasError ? "text-destructive" : "text-[var(--input-placeholder)]"),
|
|
78
|
+
children: error || helperText
|
|
79
|
+
})
|
|
80
|
+
]
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
Input.displayName = "Input";
|
|
84
|
+
var InputWithButton = React.forwardRef(({
|
|
85
|
+
className,
|
|
86
|
+
inputSize = "lg",
|
|
87
|
+
buttonText = "Subscribe",
|
|
88
|
+
buttonLoading,
|
|
89
|
+
onButtonClick,
|
|
90
|
+
onSubmit,
|
|
91
|
+
...props
|
|
92
|
+
}, ref) => {
|
|
93
|
+
const generatedId = React.useId();
|
|
94
|
+
const inputId = props.id || `input-${generatedId}`;
|
|
95
|
+
const inputRef = React.useRef(null);
|
|
96
|
+
const handleClick = () => {
|
|
97
|
+
if (onSubmit && inputRef.current) {
|
|
98
|
+
onSubmit(inputRef.current.value);
|
|
99
|
+
}
|
|
100
|
+
onButtonClick?.();
|
|
101
|
+
};
|
|
102
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
103
|
+
className: "w-full space-y-2",
|
|
104
|
+
children: [
|
|
105
|
+
props.label && /* @__PURE__ */ jsx("label", {
|
|
106
|
+
htmlFor: inputId,
|
|
107
|
+
className: "text-sm font-medium text-[var(--input-text)]",
|
|
108
|
+
children: props.label
|
|
109
|
+
}),
|
|
110
|
+
/* @__PURE__ */ jsxs("div", {
|
|
111
|
+
className: "relative",
|
|
112
|
+
children: [
|
|
113
|
+
props.leftIcon && /* @__PURE__ */ jsx("div", {
|
|
114
|
+
className: "absolute left-4 top-1/2 -translate-y-1/2 text-[var(--input-placeholder)] [&_svg]:size-5",
|
|
115
|
+
children: props.leftIcon
|
|
116
|
+
}),
|
|
117
|
+
/* @__PURE__ */ jsx("input", {
|
|
118
|
+
id: inputId,
|
|
119
|
+
ref: (node) => {
|
|
120
|
+
inputRef.current = node;
|
|
121
|
+
if (typeof ref === "function") {
|
|
122
|
+
ref(node);
|
|
123
|
+
} else if (ref) {
|
|
124
|
+
ref.current = node;
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
className: cn(inputVariants({ inputSize, variant: props.error ? "error" : "default" }), props.leftIcon && "pl-12", "pr-36", className),
|
|
128
|
+
...props
|
|
129
|
+
}),
|
|
130
|
+
/* @__PURE__ */ jsx("button", {
|
|
131
|
+
type: "button",
|
|
132
|
+
onClick: handleClick,
|
|
133
|
+
disabled: props.disabled || buttonLoading,
|
|
134
|
+
className: cn("absolute top-1/2 right-3 -translate-y-1/2", "h-10 px-5 rounded", "bg-[var(--btn-primary-bg)] text-[var(--btn-primary-text)]", "font-mono text-base font-medium", "hover:opacity-90", "transition-colors duration-150", "disabled:opacity-50 disabled:cursor-not-allowed"),
|
|
135
|
+
children: buttonLoading ? /* @__PURE__ */ jsxs("span", {
|
|
136
|
+
className: "inline-flex items-center gap-2",
|
|
137
|
+
children: [
|
|
138
|
+
/* @__PURE__ */ jsxs("svg", {
|
|
139
|
+
className: "animate-spin size-4",
|
|
140
|
+
viewBox: "0 0 24 24",
|
|
141
|
+
fill: "none",
|
|
142
|
+
"aria-hidden": "true",
|
|
143
|
+
children: [
|
|
144
|
+
/* @__PURE__ */ jsx("circle", {
|
|
145
|
+
cx: "12",
|
|
146
|
+
cy: "12",
|
|
147
|
+
r: "10",
|
|
148
|
+
stroke: "currentColor",
|
|
149
|
+
strokeWidth: "3",
|
|
150
|
+
className: "opacity-25"
|
|
151
|
+
}),
|
|
152
|
+
/* @__PURE__ */ jsx("path", {
|
|
153
|
+
fill: "currentColor",
|
|
154
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z",
|
|
155
|
+
className: "opacity-75"
|
|
156
|
+
})
|
|
157
|
+
]
|
|
158
|
+
}),
|
|
159
|
+
"..."
|
|
160
|
+
]
|
|
161
|
+
}) : buttonText
|
|
162
|
+
})
|
|
163
|
+
]
|
|
164
|
+
}),
|
|
165
|
+
(props.helperText || props.error) && /* @__PURE__ */ jsx("p", {
|
|
166
|
+
className: cn("text-sm font-mono", props.error ? "text-destructive" : "text-[var(--input-placeholder)]"),
|
|
167
|
+
children: props.error || props.helperText
|
|
168
|
+
})
|
|
169
|
+
]
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
InputWithButton.displayName = "InputWithButton";
|
|
173
|
+
var SearchInput = React.forwardRef(({ className, inputSize = "md", showClear, onClear, ...props }, ref) => {
|
|
174
|
+
const inputId = React.useId();
|
|
175
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
176
|
+
className: "w-full space-y-2",
|
|
177
|
+
children: [
|
|
178
|
+
props.label && /* @__PURE__ */ jsx("label", {
|
|
179
|
+
htmlFor: inputId,
|
|
180
|
+
className: "text-sm font-medium text-[var(--input-text)]",
|
|
181
|
+
children: props.label
|
|
182
|
+
}),
|
|
183
|
+
/* @__PURE__ */ jsxs("div", {
|
|
184
|
+
className: "relative",
|
|
185
|
+
children: [
|
|
186
|
+
/* @__PURE__ */ jsx("div", {
|
|
187
|
+
className: "absolute left-4 top-1/2 -translate-y-1/2 text-[var(--input-placeholder)]",
|
|
188
|
+
children: /* @__PURE__ */ jsx("svg", {
|
|
189
|
+
className: "size-5",
|
|
190
|
+
fill: "none",
|
|
191
|
+
stroke: "currentColor",
|
|
192
|
+
viewBox: "0 0 24 24",
|
|
193
|
+
"aria-hidden": "true",
|
|
194
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
195
|
+
strokeLinecap: "round",
|
|
196
|
+
strokeLinejoin: "round",
|
|
197
|
+
strokeWidth: 2,
|
|
198
|
+
d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
|
199
|
+
})
|
|
200
|
+
})
|
|
201
|
+
}),
|
|
202
|
+
/* @__PURE__ */ jsx("input", {
|
|
203
|
+
id: inputId,
|
|
204
|
+
ref,
|
|
205
|
+
className: cn(inputVariants({ inputSize, variant: props.error ? "error" : "default" }), "pl-12", showClear && "pr-10", className),
|
|
206
|
+
...props
|
|
207
|
+
}),
|
|
208
|
+
showClear && /* @__PURE__ */ jsx("button", {
|
|
209
|
+
type: "button",
|
|
210
|
+
onClick: onClear,
|
|
211
|
+
"aria-label": "Clear search",
|
|
212
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-[var(--input-placeholder)] hover:text-[var(--input-text)] transition-colors",
|
|
213
|
+
children: /* @__PURE__ */ jsx("svg", {
|
|
214
|
+
className: "size-5",
|
|
215
|
+
fill: "none",
|
|
216
|
+
stroke: "currentColor",
|
|
217
|
+
viewBox: "0 0 24 24",
|
|
218
|
+
"aria-hidden": "true",
|
|
219
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
220
|
+
strokeLinecap: "round",
|
|
221
|
+
strokeLinejoin: "round",
|
|
222
|
+
strokeWidth: 2,
|
|
223
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
224
|
+
})
|
|
225
|
+
})
|
|
226
|
+
})
|
|
227
|
+
]
|
|
228
|
+
}),
|
|
229
|
+
(props.helperText || props.error) && /* @__PURE__ */ jsx("p", {
|
|
230
|
+
className: cn("text-sm font-mono", props.error ? "text-destructive" : "text-[var(--input-placeholder)]"),
|
|
231
|
+
children: props.error || props.helperText
|
|
232
|
+
})
|
|
233
|
+
]
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
SearchInput.displayName = "SearchInput";
|
|
237
|
+
export {
|
|
238
|
+
inputVariants,
|
|
239
|
+
SearchInput,
|
|
240
|
+
InputWithButton,
|
|
241
|
+
Input
|
|
242
|
+
};
|
package/dist/lib/utils.js
CHANGED
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
7
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
8
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
9
|
-
for (let key of __getOwnPropNames(mod))
|
|
10
|
-
if (!__hasOwnProp.call(to, key))
|
|
11
|
-
__defProp(to, key, {
|
|
12
|
-
get: () => mod[key],
|
|
13
|
-
enumerable: true
|
|
14
|
-
});
|
|
15
|
-
return to;
|
|
16
|
-
};
|
|
17
|
-
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
18
|
-
|
|
19
1
|
// src/lib/utils.ts
|
|
20
2
|
import { clsx } from "clsx";
|
|
21
3
|
import { twMerge } from "tailwind-merge";
|
|
@@ -25,5 +7,3 @@ function cn(...inputs) {
|
|
|
25
7
|
export {
|
|
26
8
|
cn
|
|
27
9
|
};
|
|
28
|
-
|
|
29
|
-
export { __toESM, __commonJS, cn };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
interface TabCellBase {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
isActive?: boolean;
|
|
6
|
+
}
|
|
7
|
+
interface TextTab extends TabCellBase {
|
|
8
|
+
type: "text";
|
|
9
|
+
}
|
|
10
|
+
interface CountTab extends TabCellBase {
|
|
11
|
+
type: "count";
|
|
12
|
+
count: number;
|
|
13
|
+
}
|
|
14
|
+
interface FileTab extends TabCellBase {
|
|
15
|
+
type: "file";
|
|
16
|
+
fileType?: "ts" | "tsx" | "js" | "jsx" | "html" | "css" | "json" | "md";
|
|
17
|
+
closeable?: boolean;
|
|
18
|
+
}
|
|
19
|
+
interface ProgressTab extends TabCellBase {
|
|
20
|
+
type: "progress";
|
|
21
|
+
percent: number;
|
|
22
|
+
}
|
|
23
|
+
interface ActionTab {
|
|
24
|
+
id: string;
|
|
25
|
+
type: "action";
|
|
26
|
+
icon: React.ReactNode;
|
|
27
|
+
label?: string;
|
|
28
|
+
}
|
|
29
|
+
type TabCell = TextTab | CountTab | FileTab | ProgressTab | ActionTab;
|
|
30
|
+
interface SegmentedTabsProps {
|
|
31
|
+
tabs: TabCell[];
|
|
32
|
+
activeTab?: string;
|
|
33
|
+
onTabChange?: (id: string) => void;
|
|
34
|
+
onTabClose?: (id: string) => void;
|
|
35
|
+
onAction?: (id: string) => void;
|
|
36
|
+
className?: string;
|
|
37
|
+
}
|
|
38
|
+
declare const SegmentedTabs: unknown;
|
|
39
|
+
interface TabItem {
|
|
40
|
+
id: string;
|
|
41
|
+
label: string;
|
|
42
|
+
icon?: React.ReactNode;
|
|
43
|
+
count?: number;
|
|
44
|
+
closeable?: boolean;
|
|
45
|
+
}
|
|
46
|
+
interface TabsProps {
|
|
47
|
+
tabs: TabItem[];
|
|
48
|
+
activeTab: string;
|
|
49
|
+
onTabChange: (id: string) => void;
|
|
50
|
+
onTabClose?: (id: string) => void;
|
|
51
|
+
onAddTab?: () => void;
|
|
52
|
+
className?: string;
|
|
53
|
+
size?: "default" | "lg";
|
|
54
|
+
}
|
|
55
|
+
declare const Tabs: unknown;
|
|
56
|
+
export { TabsProps, Tabs, TabItem, TabCell, SegmentedTabsProps, SegmentedTabs };
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// src/components/tabs/tabs.tsx
|
|
3
|
+
import { Plus, X } from "lucide-react";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
|
|
6
|
+
// src/lib/utils.ts
|
|
7
|
+
import { clsx } from "clsx";
|
|
8
|
+
import { twMerge } from "tailwind-merge";
|
|
9
|
+
function cn(...inputs) {
|
|
10
|
+
return twMerge(clsx(inputs));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// src/components/tabs/tabs.tsx
|
|
14
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
15
|
+
|
|
16
|
+
var fileTypeColors = {
|
|
17
|
+
ts: "bg-blue-500",
|
|
18
|
+
tsx: "bg-blue-500",
|
|
19
|
+
js: "bg-yellow-500",
|
|
20
|
+
jsx: "bg-yellow-500",
|
|
21
|
+
html: "bg-orange-500",
|
|
22
|
+
css: "bg-purple-500",
|
|
23
|
+
json: "bg-green-600",
|
|
24
|
+
md: "bg-stone-500"
|
|
25
|
+
};
|
|
26
|
+
var fileTypeLabels = {
|
|
27
|
+
ts: "TS",
|
|
28
|
+
tsx: "TS",
|
|
29
|
+
js: "JS",
|
|
30
|
+
jsx: "JS",
|
|
31
|
+
html: "HTML",
|
|
32
|
+
css: "CSS",
|
|
33
|
+
json: "JSON",
|
|
34
|
+
md: "MD"
|
|
35
|
+
};
|
|
36
|
+
function MiniProgress({ percent, className }) {
|
|
37
|
+
const radius = 5;
|
|
38
|
+
const circumference = 2 * Math.PI * radius;
|
|
39
|
+
const strokeDashoffset = circumference - percent / 100 * circumference;
|
|
40
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
41
|
+
className: cn("size-4", className),
|
|
42
|
+
viewBox: "0 0 14 14",
|
|
43
|
+
"aria-hidden": "true",
|
|
44
|
+
children: [
|
|
45
|
+
/* @__PURE__ */ jsx("circle", {
|
|
46
|
+
cx: "7",
|
|
47
|
+
cy: "7",
|
|
48
|
+
r: radius,
|
|
49
|
+
fill: "none",
|
|
50
|
+
stroke: "currentColor",
|
|
51
|
+
strokeWidth: "1.5",
|
|
52
|
+
className: "opacity-20"
|
|
53
|
+
}),
|
|
54
|
+
/* @__PURE__ */ jsx("circle", {
|
|
55
|
+
cx: "7",
|
|
56
|
+
cy: "7",
|
|
57
|
+
r: radius,
|
|
58
|
+
fill: "none",
|
|
59
|
+
stroke: "currentColor",
|
|
60
|
+
strokeWidth: "1.5",
|
|
61
|
+
strokeDasharray: circumference,
|
|
62
|
+
strokeDashoffset,
|
|
63
|
+
strokeLinecap: "round",
|
|
64
|
+
transform: "rotate(-90 7 7)"
|
|
65
|
+
})
|
|
66
|
+
]
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
var SegmentedTabs = React.forwardRef(({ tabs, activeTab, onTabChange, onTabClose, onAction, className }, ref) => {
|
|
70
|
+
return /* @__PURE__ */ jsx("div", {
|
|
71
|
+
ref,
|
|
72
|
+
className: cn("inline-flex items-stretch", "border border-border rounded-md", "bg-background shadow-sm", className),
|
|
73
|
+
children: tabs.map((tab, index) => {
|
|
74
|
+
const isLast = index === tabs.length - 1;
|
|
75
|
+
const isActive = "isActive" in tab ? tab.isActive : tab.id === activeTab;
|
|
76
|
+
const isAction = tab.type === "action";
|
|
77
|
+
const isFileWithClose = tab.type === "file" && tab.closeable && onTabClose;
|
|
78
|
+
if (isFileWithClose && tab.type === "file") {
|
|
79
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
80
|
+
className: cn("relative flex items-center", !isLast && "border-r border-border"),
|
|
81
|
+
children: [
|
|
82
|
+
/* @__PURE__ */ jsxs("button", {
|
|
83
|
+
type: "button",
|
|
84
|
+
onClick: () => onTabChange?.(tab.id),
|
|
85
|
+
className: cn("flex items-center gap-1.5 pl-3 pr-1 py-2 text-[13px] transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset", isActive ? "bg-accent text-foreground font-medium" : "text-muted-foreground hover:bg-accent/50 hover:text-foreground"),
|
|
86
|
+
children: [
|
|
87
|
+
/* @__PURE__ */ jsx("span", {
|
|
88
|
+
className: cn("flex items-center justify-center size-4 rounded-[3px] text-[8px] font-bold text-white", fileTypeColors[tab.fileType || "ts"] || "bg-stone-500"),
|
|
89
|
+
children: fileTypeLabels[tab.fileType || "ts"]
|
|
90
|
+
}),
|
|
91
|
+
/* @__PURE__ */ jsx("span", {
|
|
92
|
+
className: "font-mono text-[13px]",
|
|
93
|
+
children: tab.label
|
|
94
|
+
})
|
|
95
|
+
]
|
|
96
|
+
}),
|
|
97
|
+
/* @__PURE__ */ jsx("button", {
|
|
98
|
+
type: "button",
|
|
99
|
+
onClick: () => onTabClose(tab.id),
|
|
100
|
+
className: cn("p-0.5 mr-2 rounded-sm transition-colors", "text-muted-foreground/50 hover:text-foreground hover:bg-accent", isActive ? "bg-accent" : ""),
|
|
101
|
+
"aria-label": `Close ${tab.label}`,
|
|
102
|
+
children: /* @__PURE__ */ jsx(X, {
|
|
103
|
+
className: "size-3"
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
]
|
|
107
|
+
}, tab.id);
|
|
108
|
+
}
|
|
109
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
110
|
+
type: "button",
|
|
111
|
+
onClick: () => {
|
|
112
|
+
if (isAction) {
|
|
113
|
+
onAction?.(tab.id);
|
|
114
|
+
} else {
|
|
115
|
+
onTabChange?.(tab.id);
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
className: cn("relative flex items-center gap-1.5 px-3 py-2 text-[13px] transition-colors", "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset", !isLast && "border-r border-border", isActive ? "bg-accent text-foreground font-medium" : "text-muted-foreground hover:bg-accent/50 hover:text-foreground", isAction && "px-2.5"),
|
|
119
|
+
children: [
|
|
120
|
+
tab.type === "text" && /* @__PURE__ */ jsx("span", {
|
|
121
|
+
children: tab.label
|
|
122
|
+
}),
|
|
123
|
+
tab.type === "count" && /* @__PURE__ */ jsxs(Fragment, {
|
|
124
|
+
children: [
|
|
125
|
+
/* @__PURE__ */ jsx("span", {
|
|
126
|
+
children: tab.label
|
|
127
|
+
}),
|
|
128
|
+
/* @__PURE__ */ jsxs("span", {
|
|
129
|
+
className: "text-xs text-muted-foreground tabular-nums",
|
|
130
|
+
children: [
|
|
131
|
+
"(",
|
|
132
|
+
tab.count,
|
|
133
|
+
")"
|
|
134
|
+
]
|
|
135
|
+
})
|
|
136
|
+
]
|
|
137
|
+
}),
|
|
138
|
+
tab.type === "file" && /* @__PURE__ */ jsxs(Fragment, {
|
|
139
|
+
children: [
|
|
140
|
+
/* @__PURE__ */ jsx("span", {
|
|
141
|
+
className: cn("flex items-center justify-center size-4 rounded-[3px] text-[8px] font-bold text-white", fileTypeColors[tab.fileType || "ts"] || "bg-stone-500"),
|
|
142
|
+
children: fileTypeLabels[tab.fileType || "ts"]
|
|
143
|
+
}),
|
|
144
|
+
/* @__PURE__ */ jsx("span", {
|
|
145
|
+
className: "font-mono text-[13px]",
|
|
146
|
+
children: tab.label
|
|
147
|
+
})
|
|
148
|
+
]
|
|
149
|
+
}),
|
|
150
|
+
tab.type === "progress" && /* @__PURE__ */ jsxs(Fragment, {
|
|
151
|
+
children: [
|
|
152
|
+
/* @__PURE__ */ jsx(MiniProgress, {
|
|
153
|
+
percent: tab.percent
|
|
154
|
+
}),
|
|
155
|
+
/* @__PURE__ */ jsxs("span", {
|
|
156
|
+
className: "tabular-nums",
|
|
157
|
+
children: [
|
|
158
|
+
tab.percent,
|
|
159
|
+
"%"
|
|
160
|
+
]
|
|
161
|
+
})
|
|
162
|
+
]
|
|
163
|
+
}),
|
|
164
|
+
tab.type === "action" && /* @__PURE__ */ jsx(Fragment, {
|
|
165
|
+
children: tab.icon
|
|
166
|
+
})
|
|
167
|
+
]
|
|
168
|
+
}, tab.id);
|
|
169
|
+
})
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
SegmentedTabs.displayName = "SegmentedTabs";
|
|
173
|
+
var Tabs = React.forwardRef(({ tabs, activeTab, onTabChange, onTabClose, onAddTab, className, size = "default" }, ref) => {
|
|
174
|
+
const convertedTabs = tabs.map((tab) => {
|
|
175
|
+
if (tab.count !== undefined) {
|
|
176
|
+
return {
|
|
177
|
+
id: tab.id,
|
|
178
|
+
type: "count",
|
|
179
|
+
label: tab.label,
|
|
180
|
+
count: tab.count
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
if (tab.closeable) {
|
|
184
|
+
return {
|
|
185
|
+
id: tab.id,
|
|
186
|
+
type: "file",
|
|
187
|
+
label: tab.label,
|
|
188
|
+
closeable: true
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
id: tab.id,
|
|
193
|
+
type: "text",
|
|
194
|
+
label: tab.label
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
if (onAddTab) {
|
|
198
|
+
convertedTabs.push({
|
|
199
|
+
id: "__add__",
|
|
200
|
+
type: "action",
|
|
201
|
+
icon: /* @__PURE__ */ jsx(Plus, {
|
|
202
|
+
className: "size-4"
|
|
203
|
+
})
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return /* @__PURE__ */ jsx(SegmentedTabs, {
|
|
207
|
+
ref,
|
|
208
|
+
tabs: convertedTabs,
|
|
209
|
+
activeTab,
|
|
210
|
+
onTabChange,
|
|
211
|
+
onTabClose,
|
|
212
|
+
onAction: (id) => {
|
|
213
|
+
if (id === "__add__" && onAddTab) {
|
|
214
|
+
onAddTab();
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
className: cn(size === "lg" && "[&_button]:px-4 [&_button]:py-3", className)
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
Tabs.displayName = "Tabs";
|
|
221
|
+
export {
|
|
222
|
+
Tabs,
|
|
223
|
+
SegmentedTabs
|
|
224
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doccov/ui",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"files": [
|
|
@@ -8,16 +8,48 @@
|
|
|
8
8
|
],
|
|
9
9
|
"exports": {
|
|
10
10
|
"./api": {
|
|
11
|
-
"types": "./dist/
|
|
12
|
-
"import": "./dist/
|
|
11
|
+
"types": "./dist/api/index.d.ts",
|
|
12
|
+
"import": "./dist/api/index.js"
|
|
13
13
|
},
|
|
14
14
|
"./docskit": {
|
|
15
|
-
"types": "./dist/
|
|
16
|
-
"import": "./dist/
|
|
15
|
+
"types": "./dist/docskit/index.d.ts",
|
|
16
|
+
"import": "./dist/docskit/index.js"
|
|
17
17
|
},
|
|
18
18
|
"./lib/utils": {
|
|
19
19
|
"types": "./dist/lib/utils.d.ts",
|
|
20
20
|
"import": "./dist/lib/utils.js"
|
|
21
|
+
},
|
|
22
|
+
"./button": {
|
|
23
|
+
"types": "./dist/button/index.d.ts",
|
|
24
|
+
"import": "./dist/button/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./badge": {
|
|
27
|
+
"types": "./dist/badge/index.d.ts",
|
|
28
|
+
"import": "./dist/badge/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./breadcrumb": {
|
|
31
|
+
"types": "./dist/breadcrumb/index.d.ts",
|
|
32
|
+
"import": "./dist/breadcrumb/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./input": {
|
|
35
|
+
"types": "./dist/input/index.d.ts",
|
|
36
|
+
"import": "./dist/input/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./tabs": {
|
|
39
|
+
"types": "./dist/tabs/index.d.ts",
|
|
40
|
+
"import": "./dist/tabs/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./file-chip": {
|
|
43
|
+
"types": "./dist/file-chip/index.d.ts",
|
|
44
|
+
"import": "./dist/file-chip/index.js"
|
|
45
|
+
},
|
|
46
|
+
"./file-change-row": {
|
|
47
|
+
"types": "./dist/file-change-row/index.d.ts",
|
|
48
|
+
"import": "./dist/file-change-row/index.js"
|
|
49
|
+
},
|
|
50
|
+
"./coverage-trends": {
|
|
51
|
+
"types": "./dist/coverage-trends/index.d.ts",
|
|
52
|
+
"import": "./dist/coverage-trends/index.js"
|
|
21
53
|
}
|
|
22
54
|
},
|
|
23
55
|
"scripts": {
|
|
File without changes
|
|
File without changes
|