@bitrise/bitkit-v2 0.3.260 → 0.3.261

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.
@@ -1,11 +1,15 @@
1
1
  import IconCross from "../../icons/IconCross.js";
2
+ import IconPlus from "../../icons/IconPlus.js";
3
+ import BitkitControlButton from "../BitkitControlButton/BitkitControlButton.js";
2
4
  import { Box } from "@chakra-ui/react/box";
3
5
  import { chakra, useRecipe } from "@chakra-ui/react/styled-system";
4
6
  import { Text } from "@chakra-ui/react/text";
5
- import { forwardRef } from "react";
7
+ import { Children, Fragment, cloneElement, forwardRef, isValidElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
6
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
- import { createContext as createContext$1 } from "@chakra-ui/react";
8
- import { Tabs } from "@chakra-ui/react/tabs";
9
+ import { Portal } from "@chakra-ui/react/portal";
10
+ import { Menu } from "@chakra-ui/react/menu";
11
+ import { createContext as createContext$1, mergeRefs, useSafeLayoutEffect } from "@chakra-ui/react";
12
+ import { Tabs, useTabsContext, useTabsStyles } from "@chakra-ui/react/tabs";
9
13
  //#region lib/components/BitkitTabs/BitkitTabs.tsx
10
14
  var [RootPropsProvider, useRootPropsContext] = createContext$1({
11
15
  name: "RootPropsContext",
@@ -21,15 +25,23 @@ var Root = forwardRef((props, ref) => {
21
25
  })
22
26
  });
23
27
  });
28
+ var STATUS_COLOR_TOKEN = {
29
+ neutral: "color/neutral/muted",
30
+ purple: "interactive/bold",
31
+ red: "color/red/base",
32
+ yellow: "color/yellow/bold"
33
+ };
24
34
  Root.displayName = "BitkitTabs.Root";
25
35
  var Trigger = forwardRef((props, ref) => {
26
- const { badge, changed, children, className, icon: Icon, onClose, onKeyDown, secondaryText, ...rest } = props;
27
- const { variant } = useRootPropsContext();
36
+ const { badge, children, className, icon: Icon, onClose, onKeyDown, secondaryText, statusColor, ...rest } = props;
37
+ const { variant = "line" } = useRootPropsContext();
28
38
  const closeButtonRecipe = useRecipe({ key: "closeButton" });
29
- const closable = !!onClose && !rest.disabled;
30
- const showTrailing = (closable || changed) && !rest.disabled;
39
+ const isCanvas = variant === "canvas";
40
+ const closable = isCanvas && !!onClose && !rest.disabled;
41
+ const hasStatus = isCanvas && !!statusColor && !rest.disabled;
42
+ const showTrailing = closable || hasStatus;
31
43
  const mergedClassName = showTrailing ? className ? `group ${className}` : "group" : className;
32
- const revealCloseOnInteraction = closable && !!changed;
44
+ const revealCloseOnInteraction = closable && hasStatus;
33
45
  const revealOnInteraction = {
34
46
  opacity: 1,
35
47
  pointerEvents: "auto"
@@ -43,7 +55,7 @@ var Trigger = forwardRef((props, ref) => {
43
55
  if (closable && (event.key === "Delete" || event.key === "Backspace")) {
44
56
  event.preventDefault();
45
57
  const trigger = event.currentTarget;
46
- const triggers = [...trigger.closest("[role=\"tablist\"]")?.querySelectorAll("[role=\"tab\"]") ?? []];
58
+ const triggers = [...trigger.closest("[role=\"tablist\"]")?.querySelectorAll("[role=\"tab\"]:not([hidden])") ?? []];
47
59
  const index = triggers.indexOf(trigger);
48
60
  (triggers[index + 1] ?? triggers[index - 1])?.focus();
49
61
  onClose?.();
@@ -57,7 +69,7 @@ var Trigger = forwardRef((props, ref) => {
57
69
  justifyContent: "center",
58
70
  boxSize: "24",
59
71
  flexShrink: 0,
60
- children: [changed && /* @__PURE__ */ jsx(chakra.span, {
72
+ children: [hasStatus && statusColor && /* @__PURE__ */ jsx(chakra.span, {
61
73
  position: "absolute",
62
74
  inset: 0,
63
75
  display: "flex",
@@ -70,7 +82,7 @@ var Trigger = forwardRef((props, ref) => {
70
82
  children: /* @__PURE__ */ jsx(chakra.span, {
71
83
  boxSize: "8",
72
84
  borderRadius: "full",
73
- backgroundColor: "interactive/bold"
85
+ backgroundColor: STATUS_COLOR_TOKEN[statusColor]
74
86
  })
75
87
  }), closable && /* @__PURE__ */ jsx(chakra.span, {
76
88
  "aria-hidden": true,
@@ -92,10 +104,16 @@ var Trigger = forwardRef((props, ref) => {
92
104
  ref,
93
105
  ...rest,
94
106
  className: mergedClassName,
95
- gap: showTrailing ? "12" : void 0,
107
+ gap: isCanvas ? "4" : showTrailing ? "12" : void 0,
96
108
  onKeyDown: handleTriggerKeyDown,
97
- paddingInlineEnd: showTrailing ? "12" : void 0,
98
- children: variant === "line" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Box, {
109
+ paddingInlineEnd: isCanvas ? showTrailing ? "8" : void 0 : showTrailing ? "12" : void 0,
110
+ paddingInlineStart: isCanvas && Icon ? "8" : void 0,
111
+ children: isCanvas ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Box, {
112
+ display: "flex",
113
+ alignItems: "center",
114
+ gap: "8",
115
+ children: [Icon && /* @__PURE__ */ jsx(Icon, { size: "16" }), children]
116
+ }), trailing] }) : variant === "line" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Box, {
99
117
  display: "flex",
100
118
  alignItems: "center",
101
119
  gap: "8",
@@ -121,13 +139,177 @@ var Trigger = forwardRef((props, ref) => {
121
139
  });
122
140
  });
123
141
  Trigger.displayName = "BitkitTabs.Trigger";
142
+ var flattenChildren = (nodes) => Children.toArray(nodes).flatMap((child) => {
143
+ if (!isValidElement(child)) return [];
144
+ if (child.type === Fragment) return flattenChildren(child.props.children);
145
+ return [child];
146
+ });
147
+ var getVisibleIndices = (total, count, selectedIndex) => {
148
+ const visible = /* @__PURE__ */ new Set();
149
+ for (let i = 0; i < count; i += 1) visible.add(i);
150
+ if (selectedIndex >= 0 && selectedIndex < total && !visible.has(selectedIndex)) {
151
+ visible.delete(count - 1);
152
+ visible.add(selectedIndex);
153
+ }
154
+ return visible;
155
+ };
156
+ var AddButton = forwardRef((props, ref) => {
157
+ const { label = "Add tab", ...rest } = props;
158
+ return /* @__PURE__ */ jsx(BitkitControlButton, {
159
+ ref,
160
+ icon: IconPlus,
161
+ label,
162
+ size: "xxs",
163
+ ...rest
164
+ });
165
+ });
166
+ AddButton.displayName = "BitkitTabs.AddButton";
167
+ var List = forwardRef((props, ref) => {
168
+ const { children, id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...rest } = props;
169
+ const { variant = "line" } = useRootPropsContext();
170
+ const api = useTabsContext();
171
+ const styles = useTabsStyles();
172
+ const allChildren = flattenChildren(children);
173
+ const addButton = allChildren.find((child) => child.type === AddButton) ?? null;
174
+ const items = allChildren.filter((child) => child.type === Trigger);
175
+ const measureKey = variant + items.map((item) => {
176
+ const p = item.props;
177
+ return [
178
+ p.value,
179
+ String(p.children),
180
+ p.icon ? "i" : "",
181
+ p.badge ? String(p.badge) : "",
182
+ p.secondaryText ? String(p.secondaryText) : "",
183
+ p.statusColor ?? "",
184
+ p.onClose ? "c" : "",
185
+ p.disabled ? "d" : ""
186
+ ].join(":");
187
+ }).join("|");
188
+ const selectedIndex = items.findIndex((item) => item.props.value === api.value);
189
+ const moreReserve = variant === "canvas" ? 100 : 140;
190
+ const addReserve = addButton ? 48 : 0;
191
+ const listRef = useRef(null);
192
+ const widthsRef = useRef([]);
193
+ const paddingRef = useRef(0);
194
+ const [measuredKey, setMeasuredKey] = useState(null);
195
+ const [visibleCount, setVisibleCount] = useState(items.length);
196
+ const setListRef = useMemo(() => mergeRefs(listRef, ref), [ref]);
197
+ const recompute = useCallback(() => {
198
+ const el = listRef.current;
199
+ const widths = widthsRef.current;
200
+ if (!el || !widths.length) return;
201
+ const available = el.clientWidth - paddingRef.current - addReserve;
202
+ if (widths.reduce((sum, w) => sum + w, 0) <= available) {
203
+ setVisibleCount(widths.length);
204
+ return;
205
+ }
206
+ let used = moreReserve;
207
+ let count = 0;
208
+ for (let i = 0; i < widths.length; i += 1) {
209
+ if (used + widths[i] > available) break;
210
+ used += widths[i];
211
+ count += 1;
212
+ }
213
+ setVisibleCount(Math.max(count, 1));
214
+ }, [addReserve, moreReserve]);
215
+ const measuring = measuredKey !== measureKey;
216
+ useSafeLayoutEffect(() => {
217
+ const el = listRef.current;
218
+ if (!el) return;
219
+ if (measuredKey !== measureKey) {
220
+ const tabEls = el.querySelectorAll("[data-tab-trigger]");
221
+ widthsRef.current = Array.from(tabEls, (node) => node.offsetWidth);
222
+ const cs = getComputedStyle(el);
223
+ paddingRef.current = parseFloat(cs.paddingLeft) + parseFloat(cs.paddingRight);
224
+ setMeasuredKey(measureKey);
225
+ }
226
+ recompute();
227
+ }, [
228
+ measureKey,
229
+ measuredKey,
230
+ recompute
231
+ ]);
232
+ useEffect(() => {
233
+ const el = listRef.current;
234
+ if (!el || typeof ResizeObserver === "undefined") return;
235
+ let raf = 0;
236
+ const observer = new ResizeObserver(() => {
237
+ cancelAnimationFrame(raf);
238
+ raf = requestAnimationFrame(recompute);
239
+ });
240
+ observer.observe(el);
241
+ return () => {
242
+ cancelAnimationFrame(raf);
243
+ observer.disconnect();
244
+ };
245
+ }, [recompute]);
246
+ const visible = measuring || visibleCount >= items.length ? null : getVisibleIndices(items.length, visibleCount, selectedIndex);
247
+ const hiddenItems = visible ? items.filter((_, i) => !visible.has(i)) : [];
248
+ return /* @__PURE__ */ jsxs(Box, {
249
+ ref: setListRef,
250
+ css: styles.list,
251
+ ...rest,
252
+ children: [
253
+ /* @__PURE__ */ jsx(Tabs.List, {
254
+ display: "contents",
255
+ id,
256
+ "aria-label": ariaLabel,
257
+ "aria-labelledby": ariaLabelledby,
258
+ children: items.map((item, i) => cloneElement(item, {
259
+ key: item.props.value,
260
+ "data-tab-trigger": "",
261
+ hidden: visible ? !visible.has(i) : void 0
262
+ }))
263
+ }),
264
+ hiddenItems.length > 0 && /* @__PURE__ */ jsxs(Menu.Root, {
265
+ size: "md",
266
+ positioning: {
267
+ gutter: 0,
268
+ shift: -4
269
+ },
270
+ children: [/* @__PURE__ */ jsx(Menu.Trigger, {
271
+ asChild: true,
272
+ children: /* @__PURE__ */ jsxs(chakra.button, {
273
+ type: "button",
274
+ css: styles.moreTrigger,
275
+ children: [hiddenItems.length, " more…"]
276
+ })
277
+ }), /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, { children: /* @__PURE__ */ jsx(Menu.Content, { children: hiddenItems.map((item) => /* @__PURE__ */ jsxs(Menu.Item, {
278
+ value: item.props.value,
279
+ disabled: item.props.disabled,
280
+ onSelect: () => api.setValue(item.props.value),
281
+ alignItems: "center",
282
+ children: [/* @__PURE__ */ jsx(Text, {
283
+ flex: "1",
284
+ color: item.props.disabled ? "text/on-disabled" : "inherit",
285
+ children: item.props.children
286
+ }), variant === "canvas" && item.props.statusColor && /* @__PURE__ */ jsx(chakra.span, {
287
+ boxSize: "8",
288
+ borderRadius: "full",
289
+ flexShrink: 0,
290
+ backgroundColor: STATUS_COLOR_TOKEN[item.props.statusColor]
291
+ })]
292
+ }, item.props.value)) }) }) })]
293
+ }),
294
+ addButton && /* @__PURE__ */ jsx(Box, {
295
+ display: "flex",
296
+ alignItems: "center",
297
+ flexShrink: 0,
298
+ paddingInline: "8",
299
+ children: addButton
300
+ })
301
+ ]
302
+ });
303
+ });
304
+ List.displayName = "BitkitTabs.List";
124
305
  var BitkitTabs = {
125
306
  ...Tabs,
307
+ AddButton,
308
+ List,
126
309
  Root,
127
310
  Trigger
128
311
  };
129
312
  BitkitTabs.Content.displayName = "BitkitTabs.Content";
130
- BitkitTabs.List.displayName = "BitkitTabs.List";
131
313
  BitkitTabs.ContentGroup.displayName = "BitkitTabs.ContentGroup";
132
314
  BitkitTabs.Root.displayName = "BitkitTabs.Root";
133
315
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"BitkitTabs.js","names":[],"sources":["../../../lib/components/BitkitTabs/BitkitTabs.tsx"],"sourcesContent":["// eslint-disable-next-line no-restricted-imports\nimport { createContext } from '@chakra-ui/react';\nimport { Box } from '@chakra-ui/react/box';\nimport { chakra, useRecipe } from '@chakra-ui/react/styled-system';\nimport { Tabs } from '@chakra-ui/react/tabs';\nimport { Text } from '@chakra-ui/react/text';\nimport { forwardRef, type KeyboardEvent, type MouseEvent, type ReactNode } from 'react';\n\nimport { type BitkitIconComponent, IconCross } from '../../icons';\n\nexport const [RootPropsProvider, useRootPropsContext] = createContext<Tabs.RootProps>({\n name: 'RootPropsContext',\n hookName: 'useRootPropsContext',\n providerName: '<RootProps />',\n});\n\nconst Root = forwardRef<HTMLDivElement, Tabs.RootProps>((props, ref) => {\n return (\n <RootPropsProvider value={props}>\n <Tabs.Root ref={ref} {...props} />\n </RootPropsProvider>\n );\n});\n\ntype TriggerProps = Tabs.TriggerProps & {\n badge?: ReactNode;\n /** Shows a \"changed\" indicator dot. When hovered (and `onClose` is set), the close button replaces it. */\n changed?: boolean;\n children?: string;\n icon?: BitkitIconComponent;\n /** When provided, a close button reveals on hover and calls this handler when clicked. */\n onClose?: () => void;\n secondaryText?: ReactNode;\n};\n\nRoot.displayName = 'BitkitTabs.Root';\n\nconst Trigger = forwardRef<HTMLButtonElement, TriggerProps>((props, ref) => {\n const { badge, changed, children, className, icon: Icon, onClose, onKeyDown, secondaryText, ...rest } = props;\n const { variant } = useRootPropsContext();\n const closeButtonRecipe = useRecipe({ key: 'closeButton' });\n\n const closable = !!onClose && !rest.disabled;\n const showTrailing = (closable || changed) && !rest.disabled;\n const mergedClassName = showTrailing ? (className ? `group ${className}` : 'group') : className;\n // The close button is always visible when there is no \"changed\" dot; when the dot is shown it is\n // revealed on hover/focus instead (replacing the dot).\n const revealCloseOnInteraction = closable && !!changed;\n const revealOnInteraction = { opacity: 1, pointerEvents: 'auto' } as const;\n\n const handleCloseClick = (event: MouseEvent<HTMLSpanElement>) => {\n event.stopPropagation();\n event.preventDefault();\n onClose?.();\n };\n\n // The close control is not in the tab order; keyboard users close the focused tab with Delete/Backspace.\n const handleTriggerKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (closable && (event.key === 'Delete' || event.key === 'Backspace')) {\n event.preventDefault();\n // Move focus to a sibling tab before removal so keyboard navigation can continue.\n const trigger = event.currentTarget;\n const triggers = [...(trigger.closest('[role=\"tablist\"]')?.querySelectorAll<HTMLElement>('[role=\"tab\"]') ?? [])];\n const index = triggers.indexOf(trigger);\n (triggers[index + 1] ?? triggers[index - 1])?.focus();\n onClose?.();\n }\n onKeyDown?.(event);\n };\n\n const trailing = showTrailing ? (\n <chakra.span\n position=\"relative\"\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"center\"\n boxSize=\"24\"\n flexShrink={0}\n >\n {changed && (\n <chakra.span\n position=\"absolute\"\n inset={0}\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"center\"\n pointerEvents=\"none\"\n transition=\"opacity 0.1s\"\n _groupHover={closable ? { opacity: 0 } : undefined}\n _groupFocusWithin={closable ? { opacity: 0 } : undefined}\n >\n <chakra.span boxSize=\"8\" borderRadius=\"full\" backgroundColor=\"interactive/bold\" />\n </chakra.span>\n )}\n {closable && (\n <chakra.span\n aria-hidden\n tabIndex={-1}\n onClick={handleCloseClick}\n css={closeButtonRecipe({ size: 'xs' })}\n position=\"absolute\"\n inset={0}\n color=\"icon/primary\"\n opacity={revealCloseOnInteraction ? 0 : 1}\n pointerEvents={revealCloseOnInteraction ? 'none' : 'auto'}\n transition=\"opacity 0.1s\"\n _groupHover={revealCloseOnInteraction ? revealOnInteraction : undefined}\n _groupFocusWithin={revealCloseOnInteraction ? revealOnInteraction : undefined}\n >\n <IconCross size=\"16\" />\n </chakra.span>\n )}\n </chakra.span>\n ) : null;\n\n return (\n <Tabs.Trigger\n ref={ref}\n {...rest}\n className={mergedClassName}\n gap={showTrailing ? '12' : undefined}\n onKeyDown={handleTriggerKeyDown}\n paddingInlineEnd={showTrailing ? '12' : undefined}\n >\n {variant === 'line' ? (\n <>\n <Box display=\"flex\" alignItems=\"center\" gap=\"8\">\n {Icon && <Icon size=\"24\" />}\n {children}\n {badge}\n </Box>\n {trailing}\n </>\n ) : (\n <>\n <Box display=\"flex\" gap=\"16\">\n {children}\n {Icon && <Icon size=\"24\" />}\n </Box>\n {!!secondaryText && (\n <Text as=\"span\" textStyle=\"body/md/regular\" color={rest.disabled ? 'text/on-disabled' : 'text/secondary'}>\n {secondaryText}\n </Text>\n )}\n {trailing}\n </>\n )}\n </Tabs.Trigger>\n );\n});\n\nTrigger.displayName = 'BitkitTabs.Trigger';\n\nconst BitkitTabs: Omit<typeof Tabs, 'Root' | 'Trigger'> & { Root: typeof Root; Trigger: typeof Trigger } = {\n ...Tabs,\n Root,\n Trigger,\n};\n\nBitkitTabs.Content.displayName = 'BitkitTabs.Content';\nBitkitTabs.List.displayName = 'BitkitTabs.List';\nBitkitTabs.ContentGroup.displayName = 'BitkitTabs.ContentGroup';\nBitkitTabs.Root.displayName = 'BitkitTabs.Root';\n\nexport default BitkitTabs;\n"],"mappings":"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"}
1
+ {"version":3,"file":"BitkitTabs.js","names":[],"sources":["../../../lib/components/BitkitTabs/BitkitTabs.tsx"],"sourcesContent":["// eslint-disable-next-line no-restricted-imports\nimport { createContext, mergeRefs, useSafeLayoutEffect } from '@chakra-ui/react';\nimport { Box } from '@chakra-ui/react/box';\nimport { Menu } from '@chakra-ui/react/menu';\nimport { Portal } from '@chakra-ui/react/portal';\nimport { chakra, useRecipe } from '@chakra-ui/react/styled-system';\nimport { Tabs, useTabsContext, useTabsStyles } from '@chakra-ui/react/tabs';\nimport { Text } from '@chakra-ui/react/text';\nimport {\n Children,\n cloneElement,\n forwardRef,\n Fragment,\n isValidElement,\n type KeyboardEvent,\n type MouseEvent,\n type ReactElement,\n type ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { type BitkitIconComponent, IconCross, IconPlus } from '../../icons';\nimport BitkitControlButton, { type BitkitControlButtonProps } from '../BitkitControlButton/BitkitControlButton';\n\nexport const [RootPropsProvider, useRootPropsContext] = createContext<Tabs.RootProps>({\n name: 'RootPropsContext',\n hookName: 'useRootPropsContext',\n providerName: '<RootProps />',\n});\n\nconst Root = forwardRef<HTMLDivElement, Tabs.RootProps>((props, ref) => {\n return (\n <RootPropsProvider value={props}>\n <Tabs.Root ref={ref} {...props} />\n </RootPropsProvider>\n );\n});\n\n/** Status-dot colors for the `canvas` variant. */\nexport type BitkitTabsStatusColor = 'neutral' | 'purple' | 'red' | 'yellow';\n\nconst STATUS_COLOR_TOKEN: Record<BitkitTabsStatusColor, string> = {\n neutral: 'color/neutral/muted',\n purple: 'interactive/bold',\n red: 'color/red/base',\n yellow: 'color/yellow/bold',\n};\n\ntype TriggerProps = Tabs.TriggerProps & {\n badge?: ReactNode;\n children?: string;\n icon?: BitkitIconComponent;\n /** `canvas` variant only — when provided, a close button reveals on hover and calls this handler when clicked. */\n onClose?: () => void;\n secondaryText?: ReactNode;\n /** `canvas` variant only — shows a status indicator dot. When hovered (and `onClose` is set), the close button replaces it. */\n statusColor?: BitkitTabsStatusColor;\n};\n\nRoot.displayName = 'BitkitTabs.Root';\n\nconst Trigger = forwardRef<HTMLButtonElement, TriggerProps>((props, ref) => {\n const { badge, children, className, icon: Icon, onClose, onKeyDown, secondaryText, statusColor, ...rest } = props;\n // Mirror the recipe's defaultVariant so an unset `variant` renders the line layout (not the\n // contained one) — otherwise an undefined variant would fall through to the contained branch.\n const { variant = 'line' } = useRootPropsContext();\n const closeButtonRecipe = useRecipe({ key: 'closeButton' });\n\n // Close button and status dot are exclusive to the canvas variant.\n const isCanvas = variant === 'canvas';\n const closable = isCanvas && !!onClose && !rest.disabled;\n const hasStatus = isCanvas && !!statusColor && !rest.disabled;\n const showTrailing = closable || hasStatus;\n const mergedClassName = showTrailing ? (className ? `group ${className}` : 'group') : className;\n // The close button is always visible when there is no status dot; when the dot is shown it is\n // revealed on hover/focus instead (replacing the dot).\n const revealCloseOnInteraction = closable && hasStatus;\n const revealOnInteraction = { opacity: 1, pointerEvents: 'auto' } as const;\n\n const handleCloseClick = (event: MouseEvent<HTMLSpanElement>) => {\n event.stopPropagation();\n event.preventDefault();\n onClose?.();\n };\n\n // The close control is not in the tab order; keyboard users close the focused tab with Delete/Backspace.\n const handleTriggerKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (closable && (event.key === 'Delete' || event.key === 'Backspace')) {\n event.preventDefault();\n // Move focus to a sibling tab before removal so keyboard navigation can continue.\n const trigger = event.currentTarget;\n // Skip overflowed (`hidden`) tabs — they aren't focusable.\n const triggers = [\n ...(trigger.closest('[role=\"tablist\"]')?.querySelectorAll<HTMLElement>('[role=\"tab\"]:not([hidden])') ?? []),\n ];\n const index = triggers.indexOf(trigger);\n (triggers[index + 1] ?? triggers[index - 1])?.focus();\n onClose?.();\n }\n onKeyDown?.(event);\n };\n\n const trailing = showTrailing ? (\n <chakra.span\n position=\"relative\"\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"center\"\n boxSize=\"24\"\n flexShrink={0}\n >\n {hasStatus && statusColor && (\n <chakra.span\n position=\"absolute\"\n inset={0}\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"center\"\n pointerEvents=\"none\"\n transition=\"opacity 0.1s\"\n _groupHover={closable ? { opacity: 0 } : undefined}\n _groupFocusWithin={closable ? { opacity: 0 } : undefined}\n >\n <chakra.span boxSize=\"8\" borderRadius=\"full\" backgroundColor={STATUS_COLOR_TOKEN[statusColor]} />\n </chakra.span>\n )}\n {closable && (\n <chakra.span\n aria-hidden\n tabIndex={-1}\n onClick={handleCloseClick}\n css={closeButtonRecipe({ size: 'xs' })}\n position=\"absolute\"\n inset={0}\n color=\"icon/primary\"\n opacity={revealCloseOnInteraction ? 0 : 1}\n pointerEvents={revealCloseOnInteraction ? 'none' : 'auto'}\n transition=\"opacity 0.1s\"\n _groupHover={revealCloseOnInteraction ? revealOnInteraction : undefined}\n _groupFocusWithin={revealCloseOnInteraction ? revealOnInteraction : undefined}\n >\n <IconCross size=\"16\" />\n </chakra.span>\n )}\n </chakra.span>\n ) : null;\n\n return (\n <Tabs.Trigger\n ref={ref}\n {...rest}\n className={mergedClassName}\n gap={isCanvas ? '4' : showTrailing ? '12' : undefined}\n onKeyDown={handleTriggerKeyDown}\n paddingInlineEnd={isCanvas ? (showTrailing ? '8' : undefined) : showTrailing ? '12' : undefined}\n paddingInlineStart={isCanvas && Icon ? '8' : undefined}\n >\n {isCanvas ? (\n <>\n <Box display=\"flex\" alignItems=\"center\" gap=\"8\">\n {Icon && <Icon size=\"16\" />}\n {children}\n </Box>\n {trailing}\n </>\n ) : variant === 'line' ? (\n <>\n <Box display=\"flex\" alignItems=\"center\" gap=\"8\">\n {Icon && <Icon size=\"24\" />}\n {children}\n {badge}\n </Box>\n {trailing}\n </>\n ) : (\n <>\n <Box display=\"flex\" gap=\"16\">\n {children}\n {Icon && <Icon size=\"24\" />}\n </Box>\n {!!secondaryText && (\n <Text as=\"span\" textStyle=\"body/md/regular\" color={rest.disabled ? 'text/on-disabled' : 'text/secondary'}>\n {secondaryText}\n </Text>\n )}\n {trailing}\n </>\n )}\n </Tabs.Trigger>\n );\n});\n\nTrigger.displayName = 'BitkitTabs.Trigger';\n\ntype TabItem = ReactElement<TriggerProps>;\n\n// Flattens children to a list of elements, unwrapping fragments so a Trigger grouped inside a\n// fragment (e.g. conditional rendering) isn't silently dropped.\nconst flattenChildren = (nodes: ReactNode): ReactElement[] =>\n Children.toArray(nodes).flatMap((child) => {\n if (!isValidElement(child)) return [];\n if (child.type === Fragment) return flattenChildren((child.props as { children?: ReactNode }).children);\n return [child];\n });\n\n// Returns the set of visible tab indices for the overflow, always keeping the selected tab\n// visible: if it would overflow, it takes the last visible slot.\nconst getVisibleIndices = (total: number, count: number, selectedIndex: number) => {\n const visible = new Set<number>();\n for (let i = 0; i < count; i += 1) visible.add(i);\n if (selectedIndex >= 0 && selectedIndex < total && !visible.has(selectedIndex)) {\n visible.delete(count - 1);\n visible.add(selectedIndex);\n }\n return visible;\n};\n\nexport type BitkitTabsAddButtonProps = Omit<\n Extract<BitkitControlButtonProps, { href?: undefined }>,\n 'icon' | 'label' | 'size'\n> & {\n /** Accessible label / tooltip for the add button. */\n label?: string;\n};\n\n// \"+\" button to add a tab. Place it as a child of `List`; it always renders at the end of the row\n// (after the overflow menu). A compact `xxs` control button (16px icon, 4px padding) per the design.\nconst AddButton = forwardRef<HTMLButtonElement, BitkitTabsAddButtonProps>((props, ref) => {\n const { label = 'Add tab', ...rest } = props;\n return <BitkitControlButton ref={ref} icon={IconPlus} label={label} size=\"xxs\" {...rest} />;\n});\n\nAddButton.displayName = 'BitkitTabs.AddButton';\n\n// Overflow-aware List (all variants): measures the tabs and collapses the overflowing ones into a\n// \"N more…\" menu. The more-button look comes from the variant's `moreTrigger` recipe slot.\nconst List = forwardRef<HTMLDivElement, Tabs.ListProps>((props, ref) => {\n // Semantic/labelling attributes belong on the actual tablist, not the visual wrapper.\n const { children, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, ...rest } = props;\n const { variant = 'line' } = useRootPropsContext();\n const api = useTabsContext();\n const styles = useTabsStyles();\n\n // Split children: tab triggers participate in overflow; the optional add button always renders last.\n const allChildren = flattenChildren(children);\n const addButton = allChildren.find((child) => child.type === AddButton) ?? null;\n // Only Trigger elements are measured/overflowed; anything else (fragments, stray nodes) is ignored.\n const items = allChildren.filter((child) => child.type === Trigger) as TabItem[];\n // Re-measure whenever the tab set OR any width-affecting input changes — the variant, each tab's\n // value/label, icon/status/close/disabled state, and badge/secondaryText content (best-effort\n // string form, so width-changing text like \"3 errors\" → \"12 errors\" invalidates the cache).\n const measureKey =\n variant +\n items\n .map((item) => {\n const p = item.props;\n return [\n p.value,\n String(p.children),\n p.icon ? 'i' : '',\n p.badge ? String(p.badge) : '',\n p.secondaryText ? String(p.secondaryText) : '',\n p.statusColor ?? '',\n p.onClose ? 'c' : '',\n p.disabled ? 'd' : '',\n ].join(':');\n })\n .join('|');\n const selectedIndex = items.findIndex((item) => item.props.value === api.value);\n // Conservative width reservations: the more button (wider for the lg/semibold variants) and the\n // always-visible add button.\n const moreReserve = variant === 'canvas' ? 100 : 140;\n const addReserve = addButton ? 48 : 0;\n\n const listRef = useRef<HTMLDivElement | null>(null);\n const widthsRef = useRef<number[]>([]);\n // Horizontal padding of the list, cached during the measure pass so the resize hot path doesn't\n // call getComputedStyle on every tick.\n const paddingRef = useRef(0);\n // `measuredKey` is state (not a ref) so finishing the measure pass always re-renders and flips\n // `measuring` off — even when recompute keeps the same visibleCount (which would skip a re-render).\n const [measuredKey, setMeasuredKey] = useState<string | null>(null);\n const [visibleCount, setVisibleCount] = useState(items.length);\n\n const setListRef = useMemo(() => mergeRefs(listRef, ref), [ref]);\n\n const recompute = useCallback(() => {\n const el = listRef.current;\n const widths = widthsRef.current;\n if (!el || !widths.length) return;\n const available = el.clientWidth - paddingRef.current - addReserve;\n const totalWidth = widths.reduce((sum, w) => sum + w, 0);\n if (totalWidth <= available) {\n setVisibleCount(widths.length);\n return;\n }\n let used = moreReserve;\n let count = 0;\n for (let i = 0; i < widths.length; i += 1) {\n if (used + widths[i] > available) break;\n used += widths[i];\n count += 1;\n }\n setVisibleCount(Math.max(count, 1));\n }, [addReserve, moreReserve]);\n\n // Measure once per width-affecting change (all tabs are rendered visible during this pass).\n // Isomorphic layout effect: avoids the SSR \"useLayoutEffect does nothing on the server\" warning.\n const measuring = measuredKey !== measureKey;\n useSafeLayoutEffect(() => {\n const el = listRef.current;\n if (!el) return;\n if (measuredKey !== measureKey) {\n const tabEls = el.querySelectorAll<HTMLElement>('[data-tab-trigger]');\n widthsRef.current = Array.from(tabEls, (node) => node.offsetWidth);\n const cs = getComputedStyle(el);\n paddingRef.current = parseFloat(cs.paddingLeft) + parseFloat(cs.paddingRight);\n setMeasuredKey(measureKey);\n }\n recompute();\n }, [measureKey, measuredKey, recompute]);\n\n useEffect(() => {\n const el = listRef.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n // Coalesce resize bursts into one recompute per frame to avoid a read/write layout storm.\n let raf = 0;\n const observer = new ResizeObserver(() => {\n cancelAnimationFrame(raf);\n raf = requestAnimationFrame(recompute);\n });\n observer.observe(el);\n return () => {\n cancelAnimationFrame(raf);\n observer.disconnect();\n };\n }, [recompute]);\n\n const showAll = measuring || visibleCount >= items.length;\n const visible = showAll ? null : getVisibleIndices(items.length, visibleCount, selectedIndex);\n const hiddenItems = visible ? items.filter((_, i) => !visible.has(i)) : [];\n\n return (\n // The visual row carries the list styling (background, baseline border, leading padding) and is\n // measured for overflow. The tablist itself only wraps the tabs (`display: contents` keeps the\n // flex layout intact), so the more/add controls stay outside `role=\"tablist\"` per the ARIA spec.\n <Box ref={setListRef} css={styles.list} {...rest}>\n <Tabs.List display=\"contents\" id={id} aria-label={ariaLabel} aria-labelledby={ariaLabelledby}>\n {items.map((item, i) =>\n cloneElement(item, {\n key: item.props.value,\n 'data-tab-trigger': '',\n hidden: visible ? !visible.has(i) : undefined,\n } as Partial<TriggerProps>),\n )}\n </Tabs.List>\n {hiddenItems.length > 0 && (\n <Menu.Root size=\"md\" positioning={{ gutter: 0, shift: -4 }}>\n <Menu.Trigger asChild>\n <chakra.button type=\"button\" css={styles.moreTrigger}>\n {hiddenItems.length} more…\n </chakra.button>\n </Menu.Trigger>\n <Portal>\n <Menu.Positioner>\n <Menu.Content>\n {hiddenItems.map((item) => (\n <Menu.Item\n key={item.props.value}\n value={item.props.value}\n disabled={item.props.disabled}\n onSelect={() => api.setValue(item.props.value)}\n alignItems=\"center\"\n >\n <Text flex=\"1\" color={item.props.disabled ? 'text/on-disabled' : 'inherit'}>\n {item.props.children}\n </Text>\n {variant === 'canvas' && item.props.statusColor && (\n <chakra.span\n boxSize=\"8\"\n borderRadius=\"full\"\n flexShrink={0}\n backgroundColor={STATUS_COLOR_TOKEN[item.props.statusColor]}\n />\n )}\n </Menu.Item>\n ))}\n </Menu.Content>\n </Menu.Positioner>\n </Portal>\n </Menu.Root>\n )}\n {addButton && (\n <Box display=\"flex\" alignItems=\"center\" flexShrink={0} paddingInline=\"8\">\n {addButton}\n </Box>\n )}\n </Box>\n );\n});\n\nList.displayName = 'BitkitTabs.List';\n\nconst BitkitTabs: Omit<typeof Tabs, 'Root' | 'Trigger' | 'List'> & {\n AddButton: typeof AddButton;\n List: typeof List;\n Root: typeof Root;\n Trigger: typeof Trigger;\n} = {\n ...Tabs,\n AddButton,\n List,\n Root,\n Trigger,\n};\n\nBitkitTabs.Content.displayName = 'BitkitTabs.Content';\nBitkitTabs.ContentGroup.displayName = 'BitkitTabs.ContentGroup';\nBitkitTabs.Root.displayName = 'BitkitTabs.Root';\n\nexport default BitkitTabs;\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- declare const tabsSlotRecipe: import('@chakra-ui/react').SlotRecipeDefinition<"content" | "list" | "root" | "trigger" | "indicator" | "contentGroup", {
1
+ declare const tabsSlotRecipe: import('@chakra-ui/react').SlotRecipeDefinition<"content" | "list" | "root" | "trigger" | "indicator" | "contentGroup" | "moreTrigger", {
2
2
  variant: {
3
3
  line: {
4
4
  list: {
@@ -10,7 +10,6 @@ declare const tabsSlotRecipe: import('@chakra-ui/react').SlotRecipeDefinition<"c
10
10
  display: "flex";
11
11
  alignItems: "center";
12
12
  gap: "8";
13
- color: "text/secondary";
14
13
  paddingBlockStart: "12";
15
14
  paddingBlockEnd: string;
16
15
  borderBlockEnd: "2px solid transparent";
@@ -25,13 +24,28 @@ declare const tabsSlotRecipe: import('@chakra-ui/react').SlotRecipeDefinition<"c
25
24
  color: "text/disabled";
26
25
  };
27
26
  };
27
+ moreTrigger: {
28
+ bottom: "-1px";
29
+ textStyle: "body/lg/semibold";
30
+ paddingInline: "16";
31
+ paddingBlockStart: "12";
32
+ paddingBlockEnd: string;
33
+ borderBlockEnd: "2px solid transparent";
34
+ _hover: {
35
+ backgroundColor: "background/hover";
36
+ color: "text/primary";
37
+ };
38
+ _open: {
39
+ backgroundColor: "background/active";
40
+ color: "text/primary";
41
+ };
42
+ };
28
43
  };
29
44
  contained: {
30
45
  trigger: {
31
46
  paddingBlockStart: string;
32
47
  paddingBlockEnd: "12";
33
48
  backgroundColor: "background/tertiary";
34
- color: "text/secondary";
35
49
  borderBlockStart: "2px solid transparent";
36
50
  _hover: {
37
51
  backgroundColor: "background/active";
@@ -48,6 +62,96 @@ declare const tabsSlotRecipe: import('@chakra-ui/react').SlotRecipeDefinition<"c
48
62
  };
49
63
  };
50
64
  };
65
+ moreTrigger: {
66
+ textStyle: "body/lg/semibold";
67
+ paddingInline: "16";
68
+ paddingBlockStart: string;
69
+ paddingBlockEnd: "12";
70
+ backgroundColor: "background/tertiary";
71
+ borderBlockStart: "2px solid transparent";
72
+ _hover: {
73
+ backgroundColor: "background/active";
74
+ color: "text/primary";
75
+ };
76
+ _open: {
77
+ backgroundColor: "background/active";
78
+ color: "text/primary";
79
+ };
80
+ };
81
+ };
82
+ canvas: {
83
+ list: {
84
+ paddingInlineStart: "12";
85
+ borderBlockEnd: "1px solid";
86
+ borderColor: "border/regular";
87
+ };
88
+ trigger: {
89
+ height: "40";
90
+ display: "flex";
91
+ alignItems: "center";
92
+ gap: "8";
93
+ textStyle: "body/md/regular";
94
+ backgroundColor: "background/secondary";
95
+ paddingInline: "12";
96
+ paddingBlock: "8";
97
+ borderBlockEnd: "1px solid";
98
+ bottom: "-1px";
99
+ borderInlineEnd: "1px solid";
100
+ borderColor: "border/regular";
101
+ _hover: {
102
+ backgroundColor: "background/primary";
103
+ color: "text/primary";
104
+ };
105
+ _selected: {
106
+ zIndex: number;
107
+ backgroundColor: "background/primary";
108
+ color: "text/primary";
109
+ borderColor: "border/regular";
110
+ borderBlockEndColor: "border/minimal";
111
+ _after: {
112
+ content: "\"\"";
113
+ position: "absolute";
114
+ insetBlockStart: number;
115
+ insetInline: number;
116
+ height: "2";
117
+ backgroundColor: "border/selected";
118
+ };
119
+ _hover: {
120
+ backgroundColor: "background/primary";
121
+ borderColor: "border/regular";
122
+ borderBlockEndColor: "border/minimal";
123
+ };
124
+ };
125
+ _disabled: {
126
+ backgroundColor: "color/neutral/moderate";
127
+ color: "text/on-disabled";
128
+ _hover: {
129
+ backgroundColor: "color/neutral/moderate";
130
+ color: "text/on-disabled";
131
+ };
132
+ };
133
+ };
134
+ moreTrigger: {
135
+ height: "40";
136
+ textStyle: "body/md/regular";
137
+ paddingInline: "12";
138
+ bottom: "-1px";
139
+ borderBlockEnd: "1px solid";
140
+ borderInlineEnd: "1px solid";
141
+ borderColor: "border/regular";
142
+ _hover: {
143
+ backgroundColor: "background/primary";
144
+ color: "text/primary";
145
+ };
146
+ _open: {
147
+ backgroundColor: "background/active";
148
+ color: "text/primary";
149
+ };
150
+ _focusVisible: {
151
+ outline: "none";
152
+ boxShadow: "inset 0 0 0 var(--focus-ring-width) var(--focus-ring-color)";
153
+ };
154
+ };
51
155
  };
52
156
  };
53
157
  }>;
@@ -3,17 +3,19 @@ import { defineSlotRecipe } from "@chakra-ui/react/styled-system";
3
3
  import { tabsAnatomy } from "@chakra-ui/react/anatomy";
4
4
  //#region lib/theme/slot-recipes/Tabs.recipe.ts
5
5
  var tabsSlotRecipe = defineSlotRecipe({
6
- slots: tabsAnatomy.keys(),
6
+ slots: [...tabsAnatomy.keys(), "moreTrigger"],
7
7
  className: "chakra-tabs",
8
8
  base: {
9
9
  list: { display: "flex" },
10
10
  trigger: {
11
11
  "--focus-ring-width": rem(2),
12
+ color: "text/secondary",
12
13
  cursor: "pointer",
13
14
  textStyle: "body/lg/semibold",
14
15
  paddingInline: "16",
15
16
  position: "relative",
16
17
  textAlign: "left",
18
+ whiteSpace: "nowrap",
17
19
  zIndex: 0,
18
20
  _disabled: { cursor: "not-allowed" },
19
21
  _selected: {
@@ -24,7 +26,17 @@ var tabsSlotRecipe = defineSlotRecipe({
24
26
  }
25
27
  },
26
28
  content: { outline: "none" },
27
- contentGroup: { backgroundColor: "background/primary" }
29
+ contentGroup: { backgroundColor: "background/primary" },
30
+ moreTrigger: {
31
+ "--focus-ring-width": rem(2),
32
+ position: "relative",
33
+ display: "flex",
34
+ alignItems: "center",
35
+ flexShrink: 0,
36
+ whiteSpace: "nowrap",
37
+ cursor: "pointer",
38
+ color: "text/secondary"
39
+ }
28
40
  },
29
41
  variants: { variant: {
30
42
  line: {
@@ -37,7 +49,6 @@ var tabsSlotRecipe = defineSlotRecipe({
37
49
  display: "flex",
38
50
  alignItems: "center",
39
51
  gap: "8",
40
- color: "text/secondary",
41
52
  paddingBlockStart: "12",
42
53
  paddingBlockEnd: rem(9),
43
54
  borderBlockEnd: "2px solid transparent",
@@ -47,25 +58,132 @@ var tabsSlotRecipe = defineSlotRecipe({
47
58
  color: "text/primary"
48
59
  },
49
60
  _disabled: { color: "text/disabled" }
61
+ },
62
+ moreTrigger: {
63
+ bottom: "-1px",
64
+ textStyle: "body/lg/semibold",
65
+ paddingInline: "16",
66
+ paddingBlockStart: "12",
67
+ paddingBlockEnd: rem(9),
68
+ borderBlockEnd: "2px solid transparent",
69
+ _hover: {
70
+ backgroundColor: "background/hover",
71
+ color: "text/primary"
72
+ },
73
+ _open: {
74
+ backgroundColor: "background/active",
75
+ color: "text/primary"
76
+ }
50
77
  }
51
78
  },
52
- contained: { trigger: {
53
- paddingBlockStart: rem(10),
54
- paddingBlockEnd: "12",
55
- backgroundColor: "background/tertiary",
56
- color: "text/secondary",
57
- borderBlockStart: "2px solid transparent",
58
- _hover: { backgroundColor: "background/active" },
59
- _disabled: {
60
- backgroundColor: "color/neutral/moderate",
61
- color: "text/on-disabled"
79
+ contained: {
80
+ trigger: {
81
+ paddingBlockStart: rem(10),
82
+ paddingBlockEnd: "12",
83
+ backgroundColor: "background/tertiary",
84
+ borderBlockStart: "2px solid transparent",
85
+ _hover: { backgroundColor: "background/active" },
86
+ _disabled: {
87
+ backgroundColor: "color/neutral/moderate",
88
+ color: "text/on-disabled"
89
+ },
90
+ _selected: {
91
+ backgroundColor: "background/primary",
92
+ color: "text/selected",
93
+ _hover: { backgroundColor: "background/primary" }
94
+ }
62
95
  },
63
- _selected: {
64
- backgroundColor: "background/primary",
65
- color: "text/selected",
66
- _hover: { backgroundColor: "background/primary" }
96
+ moreTrigger: {
97
+ textStyle: "body/lg/semibold",
98
+ paddingInline: "16",
99
+ paddingBlockStart: rem(10),
100
+ paddingBlockEnd: "12",
101
+ backgroundColor: "background/tertiary",
102
+ borderBlockStart: "2px solid transparent",
103
+ _hover: {
104
+ backgroundColor: "background/active",
105
+ color: "text/primary"
106
+ },
107
+ _open: {
108
+ backgroundColor: "background/active",
109
+ color: "text/primary"
110
+ }
111
+ }
112
+ },
113
+ canvas: {
114
+ list: {
115
+ paddingInlineStart: "12",
116
+ borderBlockEnd: "1px solid",
117
+ borderColor: "border/regular"
118
+ },
119
+ trigger: {
120
+ height: "40",
121
+ display: "flex",
122
+ alignItems: "center",
123
+ gap: "8",
124
+ textStyle: "body/md/regular",
125
+ backgroundColor: "background/secondary",
126
+ paddingInline: "12",
127
+ paddingBlock: "8",
128
+ borderBlockEnd: "1px solid",
129
+ bottom: "-1px",
130
+ borderInlineEnd: "1px solid",
131
+ borderColor: "border/regular",
132
+ _hover: {
133
+ backgroundColor: "background/primary",
134
+ color: "text/primary"
135
+ },
136
+ _selected: {
137
+ zIndex: 1,
138
+ backgroundColor: "background/primary",
139
+ color: "text/primary",
140
+ borderColor: "border/regular",
141
+ borderBlockEndColor: "border/minimal",
142
+ _after: {
143
+ content: "\"\"",
144
+ position: "absolute",
145
+ insetBlockStart: 0,
146
+ insetInline: 0,
147
+ height: "2",
148
+ backgroundColor: "border/selected"
149
+ },
150
+ _hover: {
151
+ backgroundColor: "background/primary",
152
+ borderColor: "border/regular",
153
+ borderBlockEndColor: "border/minimal"
154
+ }
155
+ },
156
+ _disabled: {
157
+ backgroundColor: "color/neutral/moderate",
158
+ color: "text/on-disabled",
159
+ _hover: {
160
+ backgroundColor: "color/neutral/moderate",
161
+ color: "text/on-disabled"
162
+ }
163
+ }
164
+ },
165
+ moreTrigger: {
166
+ height: "40",
167
+ textStyle: "body/md/regular",
168
+ paddingInline: "12",
169
+ bottom: "-1px",
170
+ borderBlockEnd: "1px solid",
171
+ borderInlineEnd: "1px solid",
172
+ borderColor: "border/regular",
173
+ _hover: {
174
+ backgroundColor: "background/primary",
175
+ color: "text/primary"
176
+ },
177
+ _open: {
178
+ backgroundColor: "background/active",
179
+ color: "text/primary"
180
+ },
181
+ _focusVisible: {
182
+ outline: "none",
183
+ boxShadow: "inset 0 0 0 var(--focus-ring-width) var(--focus-ring-color)"
184
+ }
67
185
  }
68
- } }
186
+ }
69
187
  } },
70
188
  defaultVariants: { variant: "line" }
71
189
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/Tabs.recipe.ts"],"sourcesContent":["import { tabsAnatomy } from '@chakra-ui/react/anatomy';\nimport { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { rem } from '../themeUtils';\n\nconst tabsSlotRecipe = defineSlotRecipe({\n slots: tabsAnatomy.keys(),\n className: 'chakra-tabs',\n base: {\n list: {\n display: 'flex',\n },\n trigger: {\n '--focus-ring-width': rem(2),\n cursor: 'pointer',\n textStyle: 'body/lg/semibold',\n paddingInline: '16',\n position: 'relative',\n textAlign: 'left',\n zIndex: 0,\n _disabled: {\n cursor: 'not-allowed',\n },\n _selected: {\n zIndex: 1,\n borderColor: 'border/selected',\n _hover: {\n borderColor: 'border/selected',\n },\n '& > svg': {\n color: 'icon/interactive',\n },\n },\n },\n content: {\n outline: 'none',\n },\n contentGroup: {\n backgroundColor: 'background/primary',\n },\n },\n\n variants: {\n variant: {\n line: {\n list: {\n borderBlockEnd: '1px solid',\n borderColor: 'border/regular',\n },\n trigger: {\n bottom: '-1px',\n display: 'flex',\n alignItems: 'center',\n gap: '8',\n color: 'text/secondary',\n paddingBlockStart: '12',\n paddingBlockEnd: rem(9),\n borderBlockEnd: '2px solid transparent',\n _selected: {\n color: 'text/primary',\n },\n _hover: {\n borderColor: 'border/hover',\n color: 'text/primary',\n },\n _disabled: {\n color: 'text/disabled',\n },\n },\n },\n contained: {\n trigger: {\n paddingBlockStart: rem(10),\n paddingBlockEnd: '12',\n backgroundColor: 'background/tertiary',\n color: 'text/secondary',\n borderBlockStart: '2px solid transparent',\n _hover: {\n backgroundColor: 'background/active',\n },\n _disabled: {\n backgroundColor: 'color/neutral/moderate',\n color: 'text/on-disabled',\n },\n _selected: {\n backgroundColor: 'background/primary',\n color: 'text/selected',\n _hover: {\n backgroundColor: 'background/primary',\n },\n },\n },\n },\n },\n },\n\n defaultVariants: {\n variant: 'line',\n },\n});\n\nexport default tabsSlotRecipe;\n"],"mappings":";;;;AAKA,IAAM,iBAAiB,iBAAiB;CACtC,OAAO,YAAY,KAAK;CACxB,WAAW;CACX,MAAM;EACJ,MAAM,EACJ,SAAS,OACX;EACA,SAAS;GACP,sBAAsB,IAAI,CAAC;GAC3B,QAAQ;GACR,WAAW;GACX,eAAe;GACf,UAAU;GACV,WAAW;GACX,QAAQ;GACR,WAAW,EACT,QAAQ,cACV;GACA,WAAW;IACT,QAAQ;IACR,aAAa;IACb,QAAQ,EACN,aAAa,kBACf;IACA,WAAW,EACT,OAAO,mBACT;GACF;EACF;EACA,SAAS,EACP,SAAS,OACX;EACA,cAAc,EACZ,iBAAiB,qBACnB;CACF;CAEA,UAAU,EACR,SAAS;EACP,MAAM;GACJ,MAAM;IACJ,gBAAgB;IAChB,aAAa;GACf;GACA,SAAS;IACP,QAAQ;IACR,SAAS;IACT,YAAY;IACZ,KAAK;IACL,OAAO;IACP,mBAAmB;IACnB,iBAAiB,IAAI,CAAC;IACtB,gBAAgB;IAChB,WAAW,EACT,OAAO,eACT;IACA,QAAQ;KACN,aAAa;KACb,OAAO;IACT;IACA,WAAW,EACT,OAAO,gBACT;GACF;EACF;EACA,WAAW,EACT,SAAS;GACP,mBAAmB,IAAI,EAAE;GACzB,iBAAiB;GACjB,iBAAiB;GACjB,OAAO;GACP,kBAAkB;GAClB,QAAQ,EACN,iBAAiB,oBACnB;GACA,WAAW;IACT,iBAAiB;IACjB,OAAO;GACT;GACA,WAAW;IACT,iBAAiB;IACjB,OAAO;IACP,QAAQ,EACN,iBAAiB,qBACnB;GACF;EACF,EACF;CACF,EACF;CAEA,iBAAiB,EACf,SAAS,OACX;AACF,CAAC"}
1
+ {"version":3,"file":"Tabs.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/Tabs.recipe.ts"],"sourcesContent":["import { tabsAnatomy } from '@chakra-ui/react/anatomy';\nimport { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { rem } from '../themeUtils';\n\nconst tabsSlotRecipe = defineSlotRecipe({\n // `moreTrigger` is a custom slot (not in the Chakra anatomy) for the overflow \"N more…\" button.\n slots: [...tabsAnatomy.keys(), 'moreTrigger'],\n className: 'chakra-tabs',\n base: {\n list: {\n display: 'flex',\n },\n trigger: {\n '--focus-ring-width': rem(2),\n color: 'text/secondary',\n cursor: 'pointer',\n textStyle: 'body/lg/semibold',\n paddingInline: '16',\n position: 'relative',\n textAlign: 'left',\n whiteSpace: 'nowrap',\n zIndex: 0,\n _disabled: {\n cursor: 'not-allowed',\n },\n _selected: {\n zIndex: 1,\n borderColor: 'border/selected',\n _hover: {\n borderColor: 'border/selected',\n },\n '& > svg': {\n color: 'icon/interactive',\n },\n },\n },\n content: {\n outline: 'none',\n },\n contentGroup: {\n backgroundColor: 'background/primary',\n },\n // Overflow \"N more…\" button — variant-specific look is layered on per variant below.\n moreTrigger: {\n '--focus-ring-width': rem(2),\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n flexShrink: 0,\n whiteSpace: 'nowrap',\n cursor: 'pointer',\n color: 'text/secondary',\n },\n },\n\n variants: {\n variant: {\n line: {\n list: {\n borderBlockEnd: '1px solid',\n borderColor: 'border/regular',\n },\n trigger: {\n bottom: '-1px',\n display: 'flex',\n alignItems: 'center',\n gap: '8',\n paddingBlockStart: '12',\n paddingBlockEnd: rem(9),\n borderBlockEnd: '2px solid transparent',\n _selected: {\n color: 'text/primary',\n },\n _hover: {\n borderColor: 'border/hover',\n color: 'text/primary',\n },\n _disabled: {\n color: 'text/disabled',\n },\n },\n moreTrigger: {\n bottom: '-1px',\n textStyle: 'body/lg/semibold',\n paddingInline: '16',\n paddingBlockStart: '12',\n paddingBlockEnd: rem(9),\n borderBlockEnd: '2px solid transparent',\n _hover: { backgroundColor: 'background/hover', color: 'text/primary' },\n _open: { backgroundColor: 'background/active', color: 'text/primary' },\n },\n },\n contained: {\n trigger: {\n paddingBlockStart: rem(10),\n paddingBlockEnd: '12',\n backgroundColor: 'background/tertiary',\n borderBlockStart: '2px solid transparent',\n _hover: {\n backgroundColor: 'background/active',\n },\n _disabled: {\n backgroundColor: 'color/neutral/moderate',\n color: 'text/on-disabled',\n },\n _selected: {\n backgroundColor: 'background/primary',\n color: 'text/selected',\n _hover: {\n backgroundColor: 'background/primary',\n },\n },\n },\n moreTrigger: {\n textStyle: 'body/lg/semibold',\n paddingInline: '16',\n paddingBlockStart: rem(10),\n paddingBlockEnd: '12',\n backgroundColor: 'background/tertiary',\n borderBlockStart: '2px solid transparent',\n _hover: { backgroundColor: 'background/active', color: 'text/primary' },\n _open: { backgroundColor: 'background/active', color: 'text/primary' },\n },\n },\n // IDE-style canvas tabs: fixed-height, edge-to-edge segments separated by vertical\n // dividers, with the selection marker on top. Closable + status-dot live only here.\n canvas: {\n list: {\n // Small leading gap before the first tab.\n paddingInlineStart: '12',\n borderBlockEnd: '1px solid',\n borderColor: 'border/regular',\n },\n trigger: {\n height: '40',\n display: 'flex',\n alignItems: 'center',\n gap: '8',\n textStyle: 'body/md/regular',\n backgroundColor: 'background/secondary',\n paddingInline: '12',\n paddingBlock: '8',\n // Bottom divider; shifted down 1px so it sits exactly on the list's bottom border (no\n // double line). The selected tab paints this white to merge with the content panel below.\n borderBlockEnd: '1px solid',\n bottom: '-1px',\n // Vertical divider between segments.\n borderInlineEnd: '1px solid',\n borderColor: 'border/regular',\n // The leading icon inherits the trigger's text color (secondary → primary by state); no\n // explicit svg rule, so the close-button icon keeps its own color.\n _hover: {\n backgroundColor: 'background/primary',\n color: 'text/primary',\n },\n _selected: {\n zIndex: 1,\n backgroundColor: 'background/primary',\n color: 'text/primary',\n // Keep neutral side dividers; the selected tab keeps a subtle bottom border because the\n // panel below it is secondary grey (not white), so it shouldn't fully merge.\n borderColor: 'border/regular',\n borderBlockEndColor: 'border/minimal',\n // Selection marker: an overlay bar on top of the selected tab only — non-selected\n // tabs have no top border, and it adds no layout height so nothing shifts.\n _after: {\n content: '\"\"',\n position: 'absolute',\n insetBlockStart: 0,\n insetInline: 0,\n height: '2',\n backgroundColor: 'border/selected',\n },\n _hover: {\n backgroundColor: 'background/primary',\n borderColor: 'border/regular',\n borderBlockEndColor: 'border/minimal',\n },\n },\n _disabled: {\n backgroundColor: 'color/neutral/moderate',\n color: 'text/on-disabled',\n _hover: {\n backgroundColor: 'color/neutral/moderate',\n color: 'text/on-disabled',\n },\n },\n },\n moreTrigger: {\n height: '40',\n textStyle: 'body/md/regular',\n paddingInline: '12',\n bottom: '-1px',\n borderBlockEnd: '1px solid',\n borderInlineEnd: '1px solid',\n borderColor: 'border/regular',\n _hover: { backgroundColor: 'background/primary', color: 'text/primary' },\n _open: { backgroundColor: 'background/active', color: 'text/primary' },\n _focusVisible: { outline: 'none', boxShadow: 'inset 0 0 0 var(--focus-ring-width) var(--focus-ring-color)' },\n },\n },\n },\n },\n\n defaultVariants: {\n variant: 'line',\n },\n});\n\nexport default tabsSlotRecipe;\n"],"mappings":"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"}
@@ -2090,7 +2090,7 @@ declare const slotRecipes: {
2090
2090
  };
2091
2091
  };
2092
2092
  }>;
2093
- tabs: import('@chakra-ui/react').SlotRecipeDefinition<"content" | "list" | "root" | "trigger" | "indicator" | "contentGroup", {
2093
+ tabs: import('@chakra-ui/react').SlotRecipeDefinition<"content" | "list" | "root" | "trigger" | "indicator" | "contentGroup" | "moreTrigger", {
2094
2094
  variant: {
2095
2095
  line: {
2096
2096
  list: {
@@ -2102,7 +2102,6 @@ declare const slotRecipes: {
2102
2102
  display: "flex";
2103
2103
  alignItems: "center";
2104
2104
  gap: "8";
2105
- color: "text/secondary";
2106
2105
  paddingBlockStart: "12";
2107
2106
  paddingBlockEnd: string;
2108
2107
  borderBlockEnd: "2px solid transparent";
@@ -2117,13 +2116,28 @@ declare const slotRecipes: {
2117
2116
  color: "text/disabled";
2118
2117
  };
2119
2118
  };
2119
+ moreTrigger: {
2120
+ bottom: "-1px";
2121
+ textStyle: "body/lg/semibold";
2122
+ paddingInline: "16";
2123
+ paddingBlockStart: "12";
2124
+ paddingBlockEnd: string;
2125
+ borderBlockEnd: "2px solid transparent";
2126
+ _hover: {
2127
+ backgroundColor: "background/hover";
2128
+ color: "text/primary";
2129
+ };
2130
+ _open: {
2131
+ backgroundColor: "background/active";
2132
+ color: "text/primary";
2133
+ };
2134
+ };
2120
2135
  };
2121
2136
  contained: {
2122
2137
  trigger: {
2123
2138
  paddingBlockStart: string;
2124
2139
  paddingBlockEnd: "12";
2125
2140
  backgroundColor: "background/tertiary";
2126
- color: "text/secondary";
2127
2141
  borderBlockStart: "2px solid transparent";
2128
2142
  _hover: {
2129
2143
  backgroundColor: "background/active";
@@ -2140,6 +2154,96 @@ declare const slotRecipes: {
2140
2154
  };
2141
2155
  };
2142
2156
  };
2157
+ moreTrigger: {
2158
+ textStyle: "body/lg/semibold";
2159
+ paddingInline: "16";
2160
+ paddingBlockStart: string;
2161
+ paddingBlockEnd: "12";
2162
+ backgroundColor: "background/tertiary";
2163
+ borderBlockStart: "2px solid transparent";
2164
+ _hover: {
2165
+ backgroundColor: "background/active";
2166
+ color: "text/primary";
2167
+ };
2168
+ _open: {
2169
+ backgroundColor: "background/active";
2170
+ color: "text/primary";
2171
+ };
2172
+ };
2173
+ };
2174
+ canvas: {
2175
+ list: {
2176
+ paddingInlineStart: "12";
2177
+ borderBlockEnd: "1px solid";
2178
+ borderColor: "border/regular";
2179
+ };
2180
+ trigger: {
2181
+ height: "40";
2182
+ display: "flex";
2183
+ alignItems: "center";
2184
+ gap: "8";
2185
+ textStyle: "body/md/regular";
2186
+ backgroundColor: "background/secondary";
2187
+ paddingInline: "12";
2188
+ paddingBlock: "8";
2189
+ borderBlockEnd: "1px solid";
2190
+ bottom: "-1px";
2191
+ borderInlineEnd: "1px solid";
2192
+ borderColor: "border/regular";
2193
+ _hover: {
2194
+ backgroundColor: "background/primary";
2195
+ color: "text/primary";
2196
+ };
2197
+ _selected: {
2198
+ zIndex: number;
2199
+ backgroundColor: "background/primary";
2200
+ color: "text/primary";
2201
+ borderColor: "border/regular";
2202
+ borderBlockEndColor: "border/minimal";
2203
+ _after: {
2204
+ content: "\"\"";
2205
+ position: "absolute";
2206
+ insetBlockStart: number;
2207
+ insetInline: number;
2208
+ height: "2";
2209
+ backgroundColor: "border/selected";
2210
+ };
2211
+ _hover: {
2212
+ backgroundColor: "background/primary";
2213
+ borderColor: "border/regular";
2214
+ borderBlockEndColor: "border/minimal";
2215
+ };
2216
+ };
2217
+ _disabled: {
2218
+ backgroundColor: "color/neutral/moderate";
2219
+ color: "text/on-disabled";
2220
+ _hover: {
2221
+ backgroundColor: "color/neutral/moderate";
2222
+ color: "text/on-disabled";
2223
+ };
2224
+ };
2225
+ };
2226
+ moreTrigger: {
2227
+ height: "40";
2228
+ textStyle: "body/md/regular";
2229
+ paddingInline: "12";
2230
+ bottom: "-1px";
2231
+ borderBlockEnd: "1px solid";
2232
+ borderInlineEnd: "1px solid";
2233
+ borderColor: "border/regular";
2234
+ _hover: {
2235
+ backgroundColor: "background/primary";
2236
+ color: "text/primary";
2237
+ };
2238
+ _open: {
2239
+ backgroundColor: "background/active";
2240
+ color: "text/primary";
2241
+ };
2242
+ _focusVisible: {
2243
+ outline: "none";
2244
+ boxShadow: "inset 0 0 0 var(--focus-ring-width) var(--focus-ring-color)";
2245
+ };
2246
+ };
2143
2247
  };
2144
2248
  };
2145
2249
  }>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bitrise/bitkit-v2",
3
3
  "private": false,
4
- "version": "0.3.260",
4
+ "version": "0.3.261",
5
5
  "description": "Bitrise Design System Components built with Chakra UI V3",
6
6
  "keywords": [
7
7
  "react",
@@ -1,20 +0,0 @@
1
- import { Tabs } from '@chakra-ui/react/tabs';
2
- import { ReactNode } from 'react';
3
- import { BitkitIconComponent } from '../../icons';
4
- export declare const RootPropsProvider: import('react').Provider<Tabs.RootProps>, useRootPropsContext: () => Tabs.RootProps;
5
- declare const Root: import('react').ForwardRefExoticComponent<Tabs.RootProps & import('react').RefAttributes<HTMLDivElement>>;
6
- declare const Trigger: import('react').ForwardRefExoticComponent<Tabs.TriggerProps & {
7
- badge?: ReactNode;
8
- /** Shows a "changed" indicator dot. When hovered (and `onClose` is set), the close button replaces it. */
9
- changed?: boolean;
10
- children?: string;
11
- icon?: BitkitIconComponent;
12
- /** When provided, a close button reveals on hover and calls this handler when clicked. */
13
- onClose?: () => void;
14
- secondaryText?: ReactNode;
15
- } & import('react').RefAttributes<HTMLButtonElement>>;
16
- declare const BitkitTabs: Omit<typeof Tabs, 'Root' | 'Trigger'> & {
17
- Root: typeof Root;
18
- Trigger: typeof Trigger;
19
- };
20
- export default BitkitTabs;