@bitrise/bitkit-v2 0.3.507 → 0.3.509
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/AGENTS.md +2 -2
- package/dist/components/BitkitContentWrapper/BitkitContentWrapper.d.ts +4 -3
- package/dist/components/BitkitContentWrapper/BitkitContentWrapper.js +4 -1
- package/dist/components/BitkitContentWrapper/BitkitContentWrapper.js.map +1 -1
- package/dist/components/BitkitContentWrapper/BitkitContentWrapperStickyBar.d.ts +12 -0
- package/dist/components/BitkitContentWrapper/BitkitContentWrapperStickyBar.js +23 -0
- package/dist/components/BitkitContentWrapper/BitkitContentWrapperStickyBar.js.map +1 -0
- package/dist/components/BitkitOverflowTooltip/BitkitOverflowTooltip.d.ts +4 -4
- package/dist/components/BitkitOverflowTooltip/BitkitOverflowTooltip.js +11 -4
- package/dist/components/BitkitOverflowTooltip/BitkitOverflowTooltip.js.map +1 -1
- package/dist/components/BitkitPageSidebar/BitkitPageSidebar.d.ts +7 -0
- package/dist/components/BitkitPageSidebar/BitkitPageSidebar.js +19 -6
- package/dist/components/BitkitPageSidebar/BitkitPageSidebar.js.map +1 -1
- package/dist/components/BitkitTooltip/BitkitTooltip.d.ts +3 -3
- package/dist/components/BitkitTooltip/BitkitTooltip.js.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/main.js +2 -2
- package/dist/theme/common/ContentWidth.common.d.ts +1 -1
- package/dist/theme/recipes/ContentWrapperStickyBar.recipe.d.ts +19 -0
- package/dist/theme/recipes/ContentWrapperStickyBar.recipe.js +32 -0
- package/dist/theme/recipes/ContentWrapperStickyBar.recipe.js.map +1 -0
- package/dist/theme/recipes/index.js +2 -0
- package/dist/theme/recipes/index.js.map +1 -1
- package/dist/theme/slot-recipes/PageHeader.recipe.js +1 -0
- package/dist/theme/slot-recipes/PageHeader.recipe.js.map +1 -1
- package/dist/theme/slot-recipes/PageSubheader.recipe.js +1 -0
- package/dist/theme/slot-recipes/PageSubheader.recipe.js.map +1 -1
- package/dist/theme/tokens/index.d.ts +3 -0
- package/dist/theme/tokens/sizes.d.ts +3 -0
- package/dist/theme/tokens/sizes.js +1 -0
- package/dist/theme/tokens/sizes.js.map +1 -1
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -111,7 +111,7 @@ Bitkit components use consistent prop names across the library:
|
|
|
111
111
|
- **A component that branches on `size` must resolve the default itself** — the recipe's `defaultVariants` applies in CSS, so an omitted `size` still reaches the component as `undefined`. Any JS that derives an icon or addon size from it then takes the wrong branch, and the element renders at one size with its icons at another. Give the prop a default where it is destructured (`size = 'lg'`), or resolve it at the point of use (`(props.size ?? 'lg') === 'lg' ? … : …`) when the component destructures in several places. Never rely on phrasing the condition so `undefined` happens to fall through — that is how `BitkitNumberInput`, `BitkitSelect`, `BitkitIconButton` and `BitkitCloseButton` each ended up mismatched.
|
|
112
112
|
The fallback must equal the recipe's `defaultVariants.size`; both are needed, since the recipe's is what raw Chakra and slot consumers get. And when a component calls its own recipe, pass the variant (`recipe({ size })`, never `recipe()`).
|
|
113
113
|
- **`state` prop replaces `disabled`/`loading`** — use `<BitkitButton state="disabled">`, not `<BitkitButton disabled>`. Values: `'disabled' | 'loading' | 'skeleton'`.
|
|
114
|
-
- **Say why a button is disabled with `disabledReason`** — on `BitkitButton` and `
|
|
114
|
+
- **Say why a button is disabled with `disabledReason`** — on `BitkitButton`, `BitkitIconButton` and `BitkitPageSidebar.Item`, next to `state="disabled"`. The component shows it in a tooltip, stays focusable and is announced as disabled. Don't wrap a disabled button or sidebar item in `BitkitTooltip wrapTrigger` (or a focusable `Box`), and don't turn the icon button's label tooltip off for it:
|
|
115
115
|
```tsx
|
|
116
116
|
<BitkitIconButton disabledReason="Only owners can delete" icon={IconTrash} label="Delete" state="disabled" />
|
|
117
117
|
```
|
|
@@ -239,7 +239,7 @@ Bitkit components use consistent prop names across the library:
|
|
|
239
239
|
- **Always use `textStyle`** — never set `fontFamily` or `fontSize` on `<Text>`. Use `textStyle="body/md/regular"`, `textStyle="code/md"`, etc.
|
|
240
240
|
- **Sizes as strings** — `width="32"`, not `width={32}`. Tokens are strings.
|
|
241
241
|
- **Responsive values as objects** — `padding={{ base: '16', tablet: '32' }}`, never the array form `padding={['16', '32']}`, which hides which breakpoint each value belongs to. The same goes for `columnTemplate` on `BitkitContentWrapper` (`{ tablet: '1fr 25rem' }`; its string form is deprecated).
|
|
242
|
-
- **Use existing size tokens** — closest existing token (1, 2, 4, 6, 8, 12, 16, 20, 24, 32, 40, 48, 64, 96, 128) representing pixel values (1=1px, 32=32px). Avoid arbitrary px (`width="100px"`). Above 128: a page's content width is `contentWidth` (`layout/maxWidth/640`, `…/960`, `…/1280`, `…/1616`, `…/full`) on `BitkitContentWrapper` and on the page header, subheader and filter bar above it — see `Docs/Page Layout`; for anything else use Bitkit's `rem()` helper (`import { rem } from '@bitrise/bitkit-v2'`, `maxWidth={rem(800)}`), never a bare-number string — `maxWidth="800"` is not a token, reaches the CSS without a unit, and the browser silently drops it.
|
|
242
|
+
- **Use existing size tokens** — closest existing token (1, 2, 4, 6, 8, 12, 16, 20, 24, 32, 40, 48, 64, 96, 128) representing pixel values (1=1px, 32=32px). Avoid arbitrary px (`width="100px"`). Above 128: a page's content width is `contentWidth` (`layout/maxWidth/480`, `…/640`, `…/960`, `…/1280`, `…/1616`, `…/full`) on `BitkitContentWrapper` and on the page header, subheader and filter bar above it — see `Docs/Page Layout`; for anything else use Bitkit's `rem()` helper (`import { rem } from '@bitrise/bitkit-v2'`, `maxWidth={rem(800)}`), never a bare-number string — `maxWidth="800"` is not a token, reaches the CSS without a unit, and the browser silently drops it.
|
|
243
243
|
- **Omit default prop values** — `<IconCross />`, not `<IconCross size="24" />` when 24 is the default.
|
|
244
244
|
- **Never pass `color` to a colored icon** — multi/fixed-color icons (`Icon*Color`, `IconWarningYellow`, `Icon*White`, etc.) have their colors baked in. They omit `color` from their props, so passing it is a type error. Only monochrome icons follow `color` (via `currentColor`).
|
|
245
245
|
- **No shorthand props** — use full names: `marginInline`, `paddingBlockEnd`, `width`, `background`, `padding`. Never `mx`, `pb`, `w`, `bg`, `p`, `mt`.
|
|
@@ -16,6 +16,7 @@ export interface BitkitContentWrapperProps extends BoxProps {
|
|
|
16
16
|
/** The cap on the page's content column, padding included. Pick the same value for the page header above it. */
|
|
17
17
|
contentWidth: BitkitContentWidth;
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
declare const _default: import('react').ForwardRefExoticComponent<BitkitContentWrapperProps & import('react').RefAttributes<HTMLDivElement>> & {
|
|
20
|
+
StickyBar: import('react').ForwardRefExoticComponent<import('./BitkitContentWrapperStickyBar').BitkitContentWrapperStickyBarProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
21
|
+
};
|
|
22
|
+
export default _default;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { withSubComponents } from "../../utilities/withSubComponents.js";
|
|
2
|
+
import BitkitContentWrapperStickyBar from "./BitkitContentWrapperStickyBar.js";
|
|
1
3
|
import { useRecipe } from "@chakra-ui/react/styled-system";
|
|
2
4
|
import { forwardRef } from "react";
|
|
3
5
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -16,7 +18,8 @@ var BitkitContentWrapper = forwardRef((props, ref) => {
|
|
|
16
18
|
});
|
|
17
19
|
});
|
|
18
20
|
BitkitContentWrapper.displayName = "BitkitContentWrapper";
|
|
21
|
+
var BitkitContentWrapper_default = withSubComponents(BitkitContentWrapper, { StickyBar: BitkitContentWrapperStickyBar });
|
|
19
22
|
//#endregion
|
|
20
|
-
export {
|
|
23
|
+
export { BitkitContentWrapper_default as default };
|
|
21
24
|
|
|
22
25
|
//# sourceMappingURL=BitkitContentWrapper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BitkitContentWrapper.js","names":[],"sources":["../../../lib/components/BitkitContentWrapper/BitkitContentWrapper.tsx"],"sourcesContent":["import { Box, type BoxProps } from '@chakra-ui/react/box';\nimport { useRecipe } from '@chakra-ui/react/styled-system';\nimport { forwardRef } from 'react';\n\nimport type breakpoints from '../../theme/breakpoints';\nimport { type ContentWidth } from '../../theme/common/ContentWidth.common';\n\n/** A page content width: one of the `layout/maxWidth` tokens, `layout/maxWidth/full` for no cap. */\nexport type BitkitContentWidth = ContentWidth;\n\nexport interface BitkitContentWrapperProps extends BoxProps {\n /**\n * Side-by-side columns: a CSS grid template per breakpoint, so where they split is visible at the call site —\n * `{ tablet: '1fr 25rem' }` for one column that fills next to a fixed one from `tablet` up. Below the first\n * breakpoint given, the columns stack.\n *\n * The string form (`'1fr 25rem'`, applied from `tablet`) is deprecated and goes away with the move to responsive\n * conditions; use the object form in new code.\n */\n columnTemplate?: string | Partial<Record<keyof typeof breakpoints, string>>;\n /** The cap on the page's content column, padding included. Pick the same value for the page header above it. */\n contentWidth: BitkitContentWidth;\n}\n\n/** The page's content grid: capped at a `layout/maxWidth` token, centred, one column of sections 32 apart unless `columnTemplate` says otherwise. */\nconst BitkitContentWrapper = forwardRef<HTMLDivElement, BitkitContentWrapperProps>((props, ref) => {\n const { columnTemplate, contentWidth, css, ...rest } = props;\n\n const recipe = useRecipe({ key: 'contentWrapper' });\n\n return (\n <Box\n css={[recipe(), css]}\n gridTemplateColumns={typeof columnTemplate === 'string' ? { tablet: columnTemplate } : columnTemplate}\n maxWidth={contentWidth}\n ref={ref}\n {...rest}\n />\n );\n});\n\nBitkitContentWrapper.displayName = 'BitkitContentWrapper';\n\nexport default BitkitContentWrapper;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"BitkitContentWrapper.js","names":[],"sources":["../../../lib/components/BitkitContentWrapper/BitkitContentWrapper.tsx"],"sourcesContent":["import { Box, type BoxProps } from '@chakra-ui/react/box';\nimport { useRecipe } from '@chakra-ui/react/styled-system';\nimport { forwardRef } from 'react';\n\nimport type breakpoints from '../../theme/breakpoints';\nimport { type ContentWidth } from '../../theme/common/ContentWidth.common';\nimport { withSubComponents } from '../../utilities/withSubComponents';\nimport BitkitContentWrapperStickyBar from './BitkitContentWrapperStickyBar';\n\n/** A page content width: one of the `layout/maxWidth` tokens, `layout/maxWidth/full` for no cap. */\nexport type BitkitContentWidth = ContentWidth;\n\nexport interface BitkitContentWrapperProps extends BoxProps {\n /**\n * Side-by-side columns: a CSS grid template per breakpoint, so where they split is visible at the call site —\n * `{ tablet: '1fr 25rem' }` for one column that fills next to a fixed one from `tablet` up. Below the first\n * breakpoint given, the columns stack.\n *\n * The string form (`'1fr 25rem'`, applied from `tablet`) is deprecated and goes away with the move to responsive\n * conditions; use the object form in new code.\n */\n columnTemplate?: string | Partial<Record<keyof typeof breakpoints, string>>;\n /** The cap on the page's content column, padding included. Pick the same value for the page header above it. */\n contentWidth: BitkitContentWidth;\n}\n\n/** The page's content grid: capped at a `layout/maxWidth` token, centred, one column of sections 32 apart unless `columnTemplate` says otherwise. */\nconst BitkitContentWrapper = forwardRef<HTMLDivElement, BitkitContentWrapperProps>((props, ref) => {\n const { columnTemplate, contentWidth, css, ...rest } = props;\n\n const recipe = useRecipe({ key: 'contentWrapper' });\n\n return (\n <Box\n css={[recipe(), css]}\n gridTemplateColumns={typeof columnTemplate === 'string' ? { tablet: columnTemplate } : columnTemplate}\n maxWidth={contentWidth}\n ref={ref}\n {...rest}\n />\n );\n});\n\nBitkitContentWrapper.displayName = 'BitkitContentWrapper';\n\nexport default withSubComponents(BitkitContentWrapper, { StickyBar: BitkitContentWrapperStickyBar });\n"],"mappings":";;;;;;;;AA2BA,IAAM,uBAAuB,YAAuD,OAAO,QAAQ;CACjG,MAAM,EAAE,gBAAgB,cAAc,KAAK,GAAG,SAAS;CAEvD,MAAM,SAAS,UAAU,EAAE,KAAK,iBAAiB,CAAC;CAElD,OACE,oBAAC,KAAD;EACE,KAAK,CAAC,OAAO,GAAG,GAAG;EACnB,qBAAqB,OAAO,mBAAmB,WAAW,EAAE,QAAQ,eAAe,IAAI;EACvF,UAAU;EACL;EACL,GAAI;CACL,CAAA;AAEL,CAAC;AAED,qBAAqB,cAAc;AAEnC,IAAA,+BAAe,kBAAkB,sBAAsB,EAAE,WAAW,8BAA8B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BoxProps } from '@chakra-ui/react/box';
|
|
2
|
+
export interface BitkitContentWrapperStickyBarProps extends Omit<BoxProps, 'colorVariant'> {
|
|
3
|
+
/** The page background behind the bar, so content scrolling under it stays hidden. Defaults to `gray`. */
|
|
4
|
+
colorVariant?: 'gray' | 'white';
|
|
5
|
+
/** Whether the bar is stuck; adds the shadow. The consumer owns the scroll detection, as with `BitkitPageHeader`. */
|
|
6
|
+
isSticky?: boolean;
|
|
7
|
+
/** Where the bar sticks: the bottom of whatever is stuck above it, such as the page header. */
|
|
8
|
+
insetBlockStart: BoxProps['insetBlockStart'];
|
|
9
|
+
}
|
|
10
|
+
/** A bar that sticks under the page header once scrolled to, as the first child of `BitkitContentWrapper`. Sticky from `tablet` up. */
|
|
11
|
+
declare const BitkitContentWrapperStickyBar: import('react').ForwardRefExoticComponent<BitkitContentWrapperStickyBarProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
12
|
+
export default BitkitContentWrapperStickyBar;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useRecipe } from "@chakra-ui/react/styled-system";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { Box } from "@chakra-ui/react/box";
|
|
5
|
+
//#region lib/components/BitkitContentWrapper/BitkitContentWrapperStickyBar.tsx
|
|
6
|
+
/** A bar that sticks under the page header once scrolled to, as the first child of `BitkitContentWrapper`. Sticky from `tablet` up. */
|
|
7
|
+
var BitkitContentWrapperStickyBar = forwardRef((props, ref) => {
|
|
8
|
+
const { colorVariant, css, isSticky, ...rest } = props;
|
|
9
|
+
const recipe = useRecipe({ key: "contentWrapperStickyBar" });
|
|
10
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
11
|
+
css: [recipe({
|
|
12
|
+
colorVariant,
|
|
13
|
+
isSticky
|
|
14
|
+
}), css],
|
|
15
|
+
ref,
|
|
16
|
+
...rest
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
BitkitContentWrapperStickyBar.displayName = "BitkitContentWrapperStickyBar";
|
|
20
|
+
//#endregion
|
|
21
|
+
export { BitkitContentWrapperStickyBar as default };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=BitkitContentWrapperStickyBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BitkitContentWrapperStickyBar.js","names":[],"sources":["../../../lib/components/BitkitContentWrapper/BitkitContentWrapperStickyBar.tsx"],"sourcesContent":["import { Box, type BoxProps } from '@chakra-ui/react/box';\nimport { useRecipe } from '@chakra-ui/react/styled-system';\nimport { forwardRef } from 'react';\n\nexport interface BitkitContentWrapperStickyBarProps extends Omit<BoxProps, 'colorVariant'> {\n /** The page background behind the bar, so content scrolling under it stays hidden. Defaults to `gray`. */\n colorVariant?: 'gray' | 'white';\n /** Whether the bar is stuck; adds the shadow. The consumer owns the scroll detection, as with `BitkitPageHeader`. */\n isSticky?: boolean;\n /** Where the bar sticks: the bottom of whatever is stuck above it, such as the page header. */\n insetBlockStart: BoxProps['insetBlockStart'];\n}\n\n/** A bar that sticks under the page header once scrolled to, as the first child of `BitkitContentWrapper`. Sticky from `tablet` up. */\nconst BitkitContentWrapperStickyBar = forwardRef<HTMLDivElement, BitkitContentWrapperStickyBarProps>((props, ref) => {\n const { colorVariant, css, isSticky, ...rest } = props;\n\n const recipe = useRecipe({ key: 'contentWrapperStickyBar' });\n\n return <Box css={[recipe({ colorVariant, isSticky }), css]} ref={ref} {...rest} />;\n});\n\nBitkitContentWrapperStickyBar.displayName = 'BitkitContentWrapperStickyBar';\n\nexport default BitkitContentWrapperStickyBar;\n"],"mappings":";;;;;;AAcA,IAAM,gCAAgC,YAAgE,OAAO,QAAQ;CACnH,MAAM,EAAE,cAAc,KAAK,UAAU,GAAG,SAAS;CAEjD,MAAM,SAAS,UAAU,EAAE,KAAK,0BAA0B,CAAC;CAE3D,OAAO,oBAAC,KAAD;EAAK,KAAK,CAAC,OAAO;GAAE;GAAc;EAAS,CAAC,GAAG,GAAG;EAAQ;EAAK,GAAI;CAAO,CAAA;AACnF,CAAC;AAED,8BAA8B,cAAc"}
|
|
@@ -23,9 +23,9 @@ export type BitkitOverflowTooltipProps = {
|
|
|
23
23
|
* clipping container by definition, and an inline tooltip would be cut off by the very `overflow`
|
|
24
24
|
* that truncated the text. Dialogs turn the portal off through `BitkitPortalContext`;
|
|
25
25
|
* `disablePortal` is the manual override.
|
|
26
|
+
*
|
|
27
|
+
* It forwards its ref, and any props an outer `asChild` trigger hands it, to the element it wraps,
|
|
28
|
+
* so it can itself sit inside a `BitkitTooltip` with both opening on the same element.
|
|
26
29
|
*/
|
|
27
|
-
declare const BitkitOverflowTooltip:
|
|
28
|
-
({ children, disablePortal, disabled, placement, text, }: BitkitOverflowTooltipProps): import('react').JSX.Element;
|
|
29
|
-
displayName: string;
|
|
30
|
-
};
|
|
30
|
+
declare const BitkitOverflowTooltip: import('react').ForwardRefExoticComponent<BitkitOverflowTooltipProps & import('react').RefAttributes<HTMLElement>>;
|
|
31
31
|
export default BitkitOverflowTooltip;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import BitkitPortalContext from "../../utilities/BitkitPortalContext.js";
|
|
2
2
|
import { rem } from "../../theme/themeUtils.js";
|
|
3
|
-
import { useContext, useRef } from "react";
|
|
3
|
+
import { forwardRef, useContext, useMemo, useRef } from "react";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { Portal } from "@chakra-ui/react/portal";
|
|
6
6
|
import { Tooltip } from "@chakra-ui/react/tooltip";
|
|
7
|
+
import { mergeRefs } from "@chakra-ui/react";
|
|
7
8
|
//#region lib/components/BitkitOverflowTooltip/BitkitOverflowTooltip.tsx
|
|
8
9
|
/**
|
|
9
10
|
* Reveals text that its container had to truncate. Light, roomy (up to 800px) and plain — it repeats
|
|
@@ -13,10 +14,15 @@ import { Tooltip } from "@chakra-ui/react/tooltip";
|
|
|
13
14
|
* clipping container by definition, and an inline tooltip would be cut off by the very `overflow`
|
|
14
15
|
* that truncated the text. Dialogs turn the portal off through `BitkitPortalContext`;
|
|
15
16
|
* `disablePortal` is the manual override.
|
|
17
|
+
*
|
|
18
|
+
* It forwards its ref, and any props an outer `asChild` trigger hands it, to the element it wraps,
|
|
19
|
+
* so it can itself sit inside a `BitkitTooltip` with both opening on the same element.
|
|
16
20
|
*/
|
|
17
|
-
var BitkitOverflowTooltip = (
|
|
21
|
+
var BitkitOverflowTooltip = forwardRef((props, ref) => {
|
|
22
|
+
const { children, disablePortal, disabled, placement = "right", text, ...outerTriggerProps } = props;
|
|
18
23
|
const { disablePortal: disablePortalFromContext } = useContext(BitkitPortalContext);
|
|
19
24
|
const triggerRef = useRef(null);
|
|
25
|
+
const setTriggerRef = useMemo(() => mergeRefs(triggerRef, ref), [ref]);
|
|
20
26
|
return /* @__PURE__ */ jsxs(Tooltip.Root, {
|
|
21
27
|
disabled,
|
|
22
28
|
paddingSize: "sm",
|
|
@@ -31,8 +37,9 @@ var BitkitOverflowTooltip = ({ children, disablePortal, disabled, placement = "r
|
|
|
31
37
|
textStyle: "sm/regular",
|
|
32
38
|
variant: "light",
|
|
33
39
|
children: [/* @__PURE__ */ jsx(Tooltip.Trigger, {
|
|
34
|
-
ref:
|
|
40
|
+
ref: setTriggerRef,
|
|
35
41
|
asChild: true,
|
|
42
|
+
...outerTriggerProps,
|
|
36
43
|
children
|
|
37
44
|
}), /* @__PURE__ */ jsx(Portal, {
|
|
38
45
|
disabled: disablePortal || disablePortalFromContext,
|
|
@@ -42,7 +49,7 @@ var BitkitOverflowTooltip = ({ children, disablePortal, disabled, placement = "r
|
|
|
42
49
|
}) })
|
|
43
50
|
})]
|
|
44
51
|
});
|
|
45
|
-
};
|
|
52
|
+
});
|
|
46
53
|
BitkitOverflowTooltip.displayName = "BitkitOverflowTooltip";
|
|
47
54
|
//#endregion
|
|
48
55
|
export { BitkitOverflowTooltip as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BitkitOverflowTooltip.js","names":[],"sources":["../../../lib/components/BitkitOverflowTooltip/BitkitOverflowTooltip.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"BitkitOverflowTooltip.js","names":[],"sources":["../../../lib/components/BitkitOverflowTooltip/BitkitOverflowTooltip.tsx"],"sourcesContent":["// eslint-disable-next-line no-restricted-imports\nimport { mergeRefs } from '@chakra-ui/react';\nimport { Portal } from '@chakra-ui/react/portal';\nimport { Tooltip, type TooltipRootProps } from '@chakra-ui/react/tooltip';\nimport { forwardRef, type ReactNode, type Ref, useContext, useMemo, useRef } from 'react';\n\nimport { rem } from '../../theme/themeUtils';\nimport BitkitPortalContext from '../../utilities/BitkitPortalContext';\n\nexport type BitkitOverflowTooltipProps = {\n /** The truncated element the tooltip is anchored to. Rendered via `asChild`, so it must accept a ref. */\n children: ReactNode;\n /** Render the trigger without a tooltip — pass `true` when the text isn't actually truncated. */\n disabled?: TooltipRootProps['disabled'];\n /**\n * Render the tooltip inline instead of in a portal. Only needed when it must stay inside its\n * parent's DOM subtree — a dialog already sets this for you.\n */\n disablePortal?: boolean;\n /** Where the tooltip sits relative to the trigger (default `right`). It flips if space is short. */\n placement?: NonNullable<TooltipRootProps['positioning']>['placement'];\n /** The full, untruncated text. */\n text: string;\n};\n\n/**\n * Reveals text that its container had to truncate. Light, roomy (up to 800px) and plain — it repeats\n * content the user can already partly see, so it carries no icon, link or action.\n *\n * The content renders in a portal, which matters more here than elsewhere: the trigger lives in a\n * clipping container by definition, and an inline tooltip would be cut off by the very `overflow`\n * that truncated the text. Dialogs turn the portal off through `BitkitPortalContext`;\n * `disablePortal` is the manual override.\n *\n * It forwards its ref, and any props an outer `asChild` trigger hands it, to the element it wraps,\n * so it can itself sit inside a `BitkitTooltip` with both opening on the same element.\n */\nconst BitkitOverflowTooltip = forwardRef<HTMLElement, BitkitOverflowTooltipProps>((props, ref) => {\n const { children, disablePortal, disabled, placement = 'right', text, ...outerTriggerProps } = props;\n const { disablePortal: disablePortalFromContext } = useContext(BitkitPortalContext);\n\n // Anchor positioning to the trigger node by ref rather than relying on Zag's\n // id/data-scope lookup. When the trigger is also wrapped by another `asChild`\n // trigger (e.g. Menu.Trigger), the outer trigger's id and data-scope/data-part\n // overwrite ours on the shared node, so `getTriggerEl()` can't find it and the\n // tooltip loses its anchor. `getAnchorElement` takes precedence over the id\n // lookup, so this is safe in the standalone case too.\n const triggerRef = useRef<HTMLElement>(null);\n const setTriggerRef = useMemo(() => mergeRefs<HTMLElement>(triggerRef, ref), [ref]);\n\n return (\n <Tooltip.Root\n disabled={disabled}\n paddingSize=\"sm\"\n positioning={{ getAnchorElement: () => triggerRef.current, placement, offset: { mainAxis: 4, crossAxis: 0 } }}\n textStyle=\"sm/regular\"\n variant=\"light\"\n >\n <Tooltip.Trigger ref={setTriggerRef as Ref<HTMLButtonElement>} asChild {...outerTriggerProps}>\n {children}\n </Tooltip.Trigger>\n <Portal disabled={disablePortal || disablePortalFromContext}>\n <Tooltip.Positioner>\n <Tooltip.Content css={{ maxWidth: rem(800) }}>{text}</Tooltip.Content>\n </Tooltip.Positioner>\n </Portal>\n </Tooltip.Root>\n );\n});\n\nBitkitOverflowTooltip.displayName = 'BitkitOverflowTooltip';\n\nexport default BitkitOverflowTooltip;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAqCA,IAAM,wBAAwB,YAAqD,OAAO,QAAQ;CAChG,MAAM,EAAE,UAAU,eAAe,UAAU,YAAY,SAAS,MAAM,GAAG,sBAAsB;CAC/F,MAAM,EAAE,eAAe,6BAA6B,WAAW,mBAAmB;CAQlF,MAAM,aAAa,OAAoB,IAAI;CAC3C,MAAM,gBAAgB,cAAc,UAAuB,YAAY,GAAG,GAAG,CAAC,GAAG,CAAC;CAElF,OACE,qBAAC,QAAQ,MAAT;EACY;EACV,aAAY;EACZ,aAAa;GAAE,wBAAwB,WAAW;GAAS;GAAW,QAAQ;IAAE,UAAU;IAAG,WAAW;GAAE;EAAE;EAC5G,WAAU;EACV,SAAQ;EALV,UAAA,CAOE,oBAAC,QAAQ,SAAT;GAAiB,KAAK;GAAyC,SAAA;GAAQ,GAAI;GACxE;EACc,CAAA,GACjB,oBAAC,QAAD;GAAQ,UAAU,iBAAiB;GACjC,UAAA,oBAAC,QAAQ,YAAT,EAAA,UACE,oBAAC,QAAQ,SAAT;IAAiB,KAAK,EAAE,UAAU,IAAI,GAAG,EAAE;IAAI,UAAA;GAAsB,CAAA,EACnD,CAAA;EACd,CAAA,CACI;;AAElB,CAAC;AAED,sBAAsB,cAAc"}
|
|
@@ -30,6 +30,13 @@ interface BitkitPageSidebarItemCommonProps {
|
|
|
30
30
|
* an ellipsis, and the overflow tooltip needs the full text to reveal.
|
|
31
31
|
*/
|
|
32
32
|
children: string;
|
|
33
|
+
/**
|
|
34
|
+
* Why the item is unavailable, shown in a tooltip on it while `state` is `"disabled"`. The item
|
|
35
|
+
* then stays focusable and is announced as disabled (`aria-disabled`), so the tooltip opens on
|
|
36
|
+
* hover and focus. It still neither navigates nor activates. Use it instead of wrapping a disabled
|
|
37
|
+
* item in `BitkitTooltip`.
|
|
38
|
+
*/
|
|
39
|
+
disabledReason?: string;
|
|
33
40
|
icon?: BitkitIconComponent;
|
|
34
41
|
/**
|
|
35
42
|
* Marks the item as the current page. Mutually exclusive with `state="disabled"` — you cannot be
|
|
@@ -2,6 +2,8 @@ import { withSubComponents } from "../../utilities/withSubComponents.js";
|
|
|
2
2
|
import IconChevronLeft from "../../icons/IconChevronLeft.js";
|
|
3
3
|
import BitkitCloseButton from "../BitkitCloseButton/BitkitCloseButton.js";
|
|
4
4
|
import BitkitControlButton from "../BitkitControlButton/BitkitControlButton.js";
|
|
5
|
+
import focusableDisabledProps from "../../utilities/focusableDisabledProps.js";
|
|
6
|
+
import BitkitTooltip from "../BitkitTooltip/BitkitTooltip.js";
|
|
5
7
|
import BitkitGroupHeading from "../BitkitGroupHeading/BitkitGroupHeading.js";
|
|
6
8
|
import useResponsive from "../../hooks/useResponsive.js";
|
|
7
9
|
import BitkitOverflowTooltip from "../BitkitOverflowTooltip/BitkitOverflowTooltip.js";
|
|
@@ -101,8 +103,9 @@ var BitkitPageSidebar = forwardRef((props, ref) => {
|
|
|
101
103
|
});
|
|
102
104
|
BitkitPageSidebar.displayName = "BitkitPageSidebar";
|
|
103
105
|
var BitkitPageSidebarItem = forwardRef((props, ref) => {
|
|
104
|
-
const { badge, children, icon: Icon, selected, state, suffixIcon: SuffixIcon, ...rest } = props;
|
|
106
|
+
const { badge, children, disabledReason, icon: Icon, selected, state, suffixIcon: SuffixIcon, ...rest } = props;
|
|
105
107
|
const isDisabled = state === "disabled";
|
|
108
|
+
const hasReason = isDisabled && !!disabledReason;
|
|
106
109
|
const isSelected = selected === true && !isDisabled;
|
|
107
110
|
const styles = useSlotRecipe({ key: "pageSidebar" })({
|
|
108
111
|
isDisabled,
|
|
@@ -140,10 +143,15 @@ var BitkitPageSidebarItem = forwardRef((props, ref) => {
|
|
|
140
143
|
css: styles.selectionMarker
|
|
141
144
|
})
|
|
142
145
|
] });
|
|
143
|
-
const withTooltip = (row) => /* @__PURE__ */ jsx(
|
|
144
|
-
disabled: !
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
const withTooltip = (row) => /* @__PURE__ */ jsx(BitkitTooltip, {
|
|
147
|
+
disabled: !hasReason,
|
|
148
|
+
placement: "right",
|
|
149
|
+
text: disabledReason ?? "",
|
|
150
|
+
children: /* @__PURE__ */ jsx(BitkitOverflowTooltip, {
|
|
151
|
+
disabled: !isTruncated || hasReason,
|
|
152
|
+
text: children,
|
|
153
|
+
children: row
|
|
154
|
+
})
|
|
147
155
|
});
|
|
148
156
|
if (rest.href !== void 0) {
|
|
149
157
|
const { className, href, onClick, onKeyDown, ...linkRest } = rest;
|
|
@@ -167,6 +175,10 @@ var BitkitPageSidebarItem = forwardRef((props, ref) => {
|
|
|
167
175
|
href: isDisabled ? void 0 : href,
|
|
168
176
|
onClick: handleClick,
|
|
169
177
|
onKeyDown: handleKeyDown,
|
|
178
|
+
...hasReason && {
|
|
179
|
+
role: "link",
|
|
180
|
+
tabIndex: 0
|
|
181
|
+
},
|
|
170
182
|
children: itemContent
|
|
171
183
|
}));
|
|
172
184
|
}
|
|
@@ -177,8 +189,9 @@ var BitkitPageSidebarItem = forwardRef((props, ref) => {
|
|
|
177
189
|
"aria-current": isSelected ? "page" : void 0,
|
|
178
190
|
className: className ? `group ${className}` : "group",
|
|
179
191
|
css: styles.item,
|
|
180
|
-
disabled: isDisabled,
|
|
192
|
+
disabled: isDisabled && !hasReason,
|
|
181
193
|
type: "button",
|
|
194
|
+
...hasReason && focusableDisabledProps,
|
|
182
195
|
children: itemContent
|
|
183
196
|
}));
|
|
184
197
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BitkitPageSidebar.js","names":["_Fragment"],"sources":["../../../lib/components/BitkitPageSidebar/BitkitPageSidebar.tsx"],"sourcesContent":["import { Box, type BoxProps } from '@chakra-ui/react/box';\nimport { Drawer } from '@chakra-ui/react/drawer';\nimport { Portal } from '@chakra-ui/react/portal';\nimport { Separator, type SeparatorProps } from '@chakra-ui/react/separator';\nimport { chakra, type HTMLChakraProps, useChakraContext, useSlotRecipe } from '@chakra-ui/react/styled-system';\nimport { Text } from '@chakra-ui/react/text';\nimport { forwardRef, type KeyboardEvent, type MouseEvent, type ReactNode, type Ref } from 'react';\n\nimport useResponsive from '../../hooks/useResponsive';\nimport { type BitkitIconComponent } from '../../icons';\nimport IconChevronLeft from '../../icons/IconChevronLeft';\nimport { type BitkitColorToken } from '../../theme/themeUtils';\nimport useIsTruncated from '../../utilities/useIsTruncated';\nimport { withSubComponents } from '../../utilities/withSubComponents';\nimport BitkitCloseButton from '../BitkitCloseButton/BitkitCloseButton';\nimport BitkitControlButton from '../BitkitControlButton/BitkitControlButton';\nimport BitkitGroupHeading, { type BitkitGroupHeadingProps } from '../BitkitGroupHeading/BitkitGroupHeading';\nimport BitkitOverflowTooltip from '../BitkitOverflowTooltip/BitkitOverflowTooltip';\n\n// The 16 and 24 icons are separate drawings, not one scaled to two sizes, so the breakpoint swap\n// cannot live in the recipe — both are rendered and one is hidden. A `useBreakpointValue` would\n// render a single icon, but it only re-reads on mount: resize a live page across `tablet` and the\n// row resizes underneath an icon that keeps its old size.\nconst showAtDesktop = { display: { base: 'none', tablet: 'block' } };\nconst showAtMobile = { display: { base: 'block', tablet: 'none' } };\n\n// ----- BitkitPageSidebar (Root) -----\n\nexport interface BitkitPageSidebarProps extends BoxProps {\n children: ReactNode;\n /**\n * Header of the mobile drawer panel, naming what the navigation belongs to — pass a\n * `BitkitPageSidebar.DrawerHeader`. Only rendered in drawer mode.\n */\n drawerHeader?: ReactNode;\n /**\n * Mobile drawer visibility. Controlled, because the page header's menu button is what opens it.\n * Passing `onOpenChange` is what opts the sidebar into the drawer below `tablet`; without it the\n * sidebar stays in the flow at full width there. Both are ignored from `tablet` up.\n *\n * Style props and `css` apply to the sidebar beside the page only — the drawer panel sizes\n * itself, so a desktop `width` or padding never reaches the navigation inside it.\n */\n onOpenChange?: (open: boolean) => void;\n open?: boolean;\n}\n\n/**\n * Page-level navigation sidebar. It expects three children, in this order:\n *\n * ```tsx\n * <BitkitPageSidebar>\n * <BitkitPageSidebar.Title>Title</BitkitPageSidebar.Title>\n * <BitkitPageSidebar.Body>\n * <BitkitPageSidebar.Item icon={IconWorkflow}>Workflows</BitkitPageSidebar.Item>\n * </BitkitPageSidebar.Body>\n * <BitkitPageSidebar.Footer>…</BitkitPageSidebar.Footer>\n * </BitkitPageSidebar>\n * ```\n *\n * `Title` and `Footer` are optional. The sidebar scrolls as a single block: when the navigation is\n * taller than the viewport the whole thing — footer included — grows and scrolls with the page,\n * which is why `Body` keeps a minimum gap above the footer so the two blocks never touch.\n *\n * The `<nav>` carries a default `aria-label` so it is not announced as an unnamed landmark. A page\n * with more than one sidebar should name each one — pass your own `aria-label` (or\n * `aria-labelledby`), which overrides the default.\n *\n * It stands at least viewport-tall by default. An embedded panel that should size to its content\n * opts out with `minHeight=\"auto\"`.\n *\n * Below the `tablet` breakpoint it switches to the mobile design on its own — full width, 48px\n * rows, larger icons and labels, a squared-off selection edge. A sidebar that sits beside page\n * content has nowhere to go at that width, so it can become a drawer instead: pass `open` and\n * `onOpenChange` (opened by `BitkitPageHeader`'s menu button) and below `tablet` it slides in\n * from the trailing edge over a backdrop, with its close button on the backdrop beside the panel\n * and a `drawerHeader` naming the page. Both props are ignored from `tablet` up.\n */\nconst BitkitPageSidebar = forwardRef<HTMLElement, BitkitPageSidebarProps>((props, ref) => {\n const { children, css, drawerHeader, onOpenChange, open = false, ...rest } = props;\n\n const { isMobile } = useResponsive();\n const { splitCssProps } = useChakraContext();\n const hasDrawer = onOpenChange !== undefined;\n const isDrawer = isMobile && hasDrawer;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe({ layout: isDrawer ? 'drawer' : hasDrawer ? 'hidden' : 'static' });\n\n if (!isDrawer) {\n return (\n <Box ref={ref} aria-label=\"Page navigation\" asChild css={[styles.root, css]} {...rest}>\n <nav>{children}</nav>\n </Box>\n );\n }\n\n // The consumer's sizing is for the sidebar beside the page; inside the panel only the recipe\n // lays the navigation out.\n const [, navProps] = splitCssProps(rest);\n\n return (\n <Drawer.Root onOpenChange={(details) => onOpenChange(details.open)} open={open}>\n <Portal>\n <Drawer.Backdrop css={styles.drawerBackdrop} />\n <Drawer.Positioner>\n <Drawer.Content aria-label=\"Navigation\" css={styles.drawerContent}>\n {drawerHeader}\n <Box ref={ref} aria-label=\"Page navigation\" asChild css={styles.root} {...navProps}>\n <nav>{children}</nav>\n </Box>\n <Box css={styles.drawerCloseButton}>\n <BitkitCloseButton\n aria-label=\"Close navigation\"\n colorVariant=\"white\"\n onClick={() => onOpenChange(false)}\n size=\"md\"\n />\n </Box>\n </Drawer.Content>\n </Drawer.Positioner>\n </Portal>\n </Drawer.Root>\n );\n});\n\nBitkitPageSidebar.displayName = 'BitkitPageSidebar';\n\n// ----- BitkitPageSidebar.Item -----\n\ninterface BitkitPageSidebarItemCommonProps {\n badge?: ReactNode;\n /**\n * The item's label. Typed as a string rather than `ReactNode` because the row truncates it with\n * an ellipsis, and the overflow tooltip needs the full text to reveal.\n */\n children: string;\n icon?: BitkitIconComponent;\n /**\n * Marks the item as the current page. Mutually exclusive with `state=\"disabled\"` — you cannot be\n * on a page whose nav item is unavailable — but the two are not type-checked against each other:\n * the combination only ever arrives from a computed `selected`, which no union can catch, and\n * checking it would break the ordinary `selected={item.id === currentId}` mapping. If both do\n * turn up, disabled wins, since that is the one of the two the design actually defines.\n */\n selected?: boolean;\n state?: 'disabled';\n suffixIcon?: BitkitIconComponent;\n}\n\ninterface BitkitPageSidebarItemLinkProps\n extends Omit<HTMLChakraProps<'a'>, 'children'>, BitkitPageSidebarItemCommonProps {\n href: string;\n}\n\ninterface BitkitPageSidebarItemButtonProps\n extends Omit<HTMLChakraProps<'button'>, 'children' | 'disabled'>, BitkitPageSidebarItemCommonProps {\n href?: never;\n}\n\nexport type BitkitPageSidebarItemProps = BitkitPageSidebarItemButtonProps | BitkitPageSidebarItemLinkProps;\n\nconst BitkitPageSidebarItem = forwardRef<HTMLButtonElement | HTMLAnchorElement, BitkitPageSidebarItemProps>(\n (props, ref) => {\n const { badge, children, icon: Icon, selected, state, suffixIcon: SuffixIcon, ...rest } = props;\n\n const isDisabled = state === 'disabled';\n // `selected` and `state=\"disabled\"` are not checked against each other in the types, so this is\n // the single place the overlap is resolved: disabled wins, and the two recipe variants can never\n // both claim the same slot.\n const isSelected = selected === true && !isDisabled;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe({ isDisabled, selected: isSelected });\n\n // The design gives neither a selected row nor a disabled one a trailing icon — the desktop\n // (`20014:6498`, `20014:6494`) and mobile (`9221:4417`) items drop it in those states.\n const VisibleSuffixIcon = isSelected || isDisabled ? undefined : SuffixIcon;\n\n const { isTruncated, ref: labelRef } = useIsTruncated<HTMLSpanElement>(children);\n\n const itemContent = (\n <>\n {/* `span`, not the default `div`: in button mode these sit inside a `<button>`, whose\n content model allows phrasing content only. */}\n <Box as=\"span\" css={styles.contentBlock}>\n {Icon && (\n <>\n <Icon css={[styles.itemIcon, showAtDesktop]} size=\"16\" />\n <Icon css={[styles.itemIcon, showAtMobile]} size=\"24\" />\n </>\n )}\n <Text as=\"span\" css={styles.itemLabel} ref={labelRef}>\n {children}\n </Text>\n </Box>\n {badge}\n {VisibleSuffixIcon && (\n <>\n <VisibleSuffixIcon css={[styles.suffixIcon, showAtDesktop]} size=\"16\" />\n <VisibleSuffixIcon css={[styles.suffixIcon, showAtMobile]} size=\"24\" />\n </>\n )}\n {isSelected && <Box as=\"span\" css={styles.selectionMarker} />}\n </>\n );\n\n // The overflow tooltip anchors to the row itself, which is the focusable element: anchored to an\n // inner node it would only ever open on hover, leaving keyboard users unable to read a truncated\n // label. `Tooltip.Trigger` renders `asChild` and composes refs, so the consumer's forwarded ref\n // survives, and the ref measuring the truncation sits on the label further in.\n const withTooltip = (row: ReactNode) => (\n <BitkitOverflowTooltip disabled={!isTruncated} text={children}>\n {row}\n </BitkitOverflowTooltip>\n );\n\n // `chakra.a` / `chakra.button` rather than a named primitive: the item carries its own slot recipe,\n // and Chakra's `Button`/`Link` would layer their own recipe styles on top of it.\n if (rest.href !== undefined) {\n const { className, href, onClick, onKeyDown, ...linkRest } = rest;\n const handleClick = isDisabled\n ? (event: MouseEvent<HTMLAnchorElement>) => {\n event.preventDefault();\n event.stopPropagation();\n }\n : onClick;\n const handleKeyDown = isDisabled\n ? (event: KeyboardEvent<HTMLAnchorElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n event.stopPropagation();\n }\n }\n : onKeyDown;\n\n return withTooltip(\n <chakra.a\n ref={ref as Ref<HTMLAnchorElement>}\n {...linkRest}\n aria-current={isSelected ? 'page' : undefined}\n aria-disabled={isDisabled || undefined}\n className={className ? `group ${className}` : 'group'}\n css={styles.item}\n // Dropping the attribute is what actually disables the link, the way `BitkitLink` and\n // `BitkitControlButton` do it. The handlers below only block `click` and `Enter`/`Space`;\n // a middle click fires `auxclick`, and \"Open link in new tab\" never reaches the page at\n // all, so both would still navigate while an `href` is there to follow.\n href={isDisabled ? undefined : href}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n >\n {itemContent}\n </chakra.a>,\n );\n }\n\n const { className, href: _href, ...buttonRest } = rest;\n\n return withTooltip(\n <chakra.button\n ref={ref as Ref<HTMLButtonElement>}\n {...buttonRest}\n aria-current={isSelected ? 'page' : undefined}\n className={className ? `group ${className}` : 'group'}\n css={styles.item}\n disabled={isDisabled}\n type=\"button\"\n >\n {itemContent}\n </chakra.button>,\n );\n },\n);\n\nBitkitPageSidebarItem.displayName = 'BitkitPageSidebarItem';\n\n// ----- BitkitPageSidebar.ProgressItem -----\n\nexport interface BitkitPageSidebarProgressItemProps extends Omit<HTMLChakraProps<'button'>, 'children' | 'disabled'> {\n /**\n * Trailing content between the label and the connector — a `BitkitBadge` counting what the stage\n * is waiting on. Sized to itself; the connector takes the rest.\n *\n * The design draws it 20px tall, which is `size=\"xs\"`. The badge arrives as a node, so the\n * component cannot set that for you — a taller one grows the row past its 40px.\n */\n badge?: ReactNode;\n /** The row's label. */\n children: ReactNode;\n /**\n * The status icon. Unlike `Item`, whose icon colour the sidebar owns, this one carries the\n * stage's status, so `iconColor` is the consumer's to set — `selected`, `notRequired` and\n * `state=\"disabled\"` still win over it, since those describe the row rather than the status.\n */\n icon: BitkitIconComponent;\n /**\n * A semantic token for the status the icon is showing. Left out, the icon takes the sidebar's own\n * `icon/secondary` — which is what the design gives a stage whose icon carries no status, such as\n * an approvals step.\n *\n * Narrowed to the `icon/*` and `color/*` tokens, so a name that does not exist is a compile error\n * rather than a colour that silently does not apply. Both families are here because the statuses\n * need both: the design takes success and failure from `icon/*` but in-progress from\n * `color/orange/bold`, which the `icon/*` set has no equivalent of.\n */\n iconColor?: BitkitColorToken<'color' | 'icon'>;\n /**\n * A stage the release does not have to clear. Steps the icon and the label down one level, so the\n * row reads as present but not awaited.\n */\n notRequired?: boolean;\n /** Follows the label after a middle dot — `auto-upload`, `not required`. */\n secondaryText?: string;\n selected?: boolean;\n state?: 'disabled';\n /**\n * Draws the dashed rule that runs from the badge to the trailing edge, tying one stage to the\n * next. The last stage in a list has nothing to tie to, so it goes without.\n */\n withConnector?: boolean;\n}\n\n/**\n * A stage of something that progresses, as a row of the page sidebar — a release running through\n * its steps, and whatever comes to look like it.\n *\n * It is a sibling of `Item` rather than a variant of it: the row reports where a stage stands\n * rather than navigating, so its icon is status-coloured, its label does not grow, and a dashed\n * connector runs to the trailing edge between the stages.\n *\n * Always a `<button>`, and always interactive — it carries the shared row's pointer cursor and\n * hover background, so a row without an `onClick` looks actionable and is not. `Item`'s\n * button-or-anchor union is deliberately not here: a stage is selected within the page it is\n * already on rather than navigated to.\n */\nconst BitkitPageSidebarProgressItem = forwardRef<HTMLButtonElement, BitkitPageSidebarProgressItemProps>(\n (props, ref) => {\n const {\n badge,\n children,\n className,\n css,\n icon: Icon,\n iconColor,\n notRequired,\n secondaryText,\n selected,\n state,\n withConnector,\n ...rest\n } = props;\n\n const isDisabled = state === 'disabled';\n // Disabled is the whole state of the row, so the other two are dropped rather than merged: the\n // recipe resolves a combination in its own order, and a disabled row came out of it carrying\n // the selected icon colour. Nothing about a disabled stage is selected or not-required.\n const isSelected = selected && !isDisabled;\n // And `selected` wins over `notRequired`, which the design decides rather than declaration\n // order: its `selected=yes, notRequired=true` variant draws the selected row's icon and label\n // and keeps `not required` in the secondary text -- which is what dropping this produces.\n const isNotRequired = notRequired && !isDisabled && !isSelected;\n\n const statusColor = isDisabled || isNotRequired || isSelected ? undefined : iconColor;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe({ isDisabled, notRequired: isNotRequired, selected: isSelected });\n\n return (\n <chakra.button\n ref={ref}\n {...rest}\n // `step` rather than the `page` an `Item` carries: these are stages of one thing, not\n // separate pages.\n aria-current={isSelected ? 'step' : undefined}\n className={className ? `group ${className}` : 'group'}\n css={[styles.item, styles.progressRow, css]}\n disabled={isDisabled}\n type=\"button\"\n >\n <Box as=\"span\" css={[styles.contentBlock, styles.progressContentBlock]}>\n {/* Two icons, one per size, for the reason `Item` has two -- see `showAtDesktop`.\n The status colour applies while the row is ordinary: `selected`, `notRequired` and\n disabled are states of the row rather than of the status, and the design recolours the\n icon in all three, so the recipe takes it back there. */}\n <Icon color={statusColor} css={[styles.progressIcon, showAtDesktop]} size=\"16\" />\n <Icon color={statusColor} css={[styles.progressIcon, showAtMobile]} size=\"24\" />\n <Box as=\"span\" css={styles.progressTextBlock}>\n <Text as=\"span\" css={styles.progressLabel}>\n {children}\n </Text>\n {secondaryText && (\n <Text as=\"span\" css={styles.progressSecondaryText}>\n {`\\u00b7 ${secondaryText}`}\n </Text>\n )}\n </Box>\n {(badge || withConnector) && (\n <Box as=\"span\" css={styles.progressBlocker}>\n {badge}\n {/* Decorative: it ties the stages together visually and has nothing to separate in\n the button's accessibility tree. */}\n {withConnector && <Separator aria-hidden css={styles.progressConnector} />}\n </Box>\n )}\n </Box>\n {isSelected && <Box as=\"span\" css={styles.selectionMarker} />}\n </chakra.button>\n );\n },\n);\n\nBitkitPageSidebarProgressItem.displayName = 'BitkitPageSidebarProgressItem';\n\n// ----- BitkitPageSidebar.Title -----\n\ninterface BitkitPageSidebarTitleCommonProps extends BoxProps {\n backLabel?: string;\n children: ReactNode;\n}\n\ninterface BitkitPageSidebarTitleLinkProps extends BitkitPageSidebarTitleCommonProps {\n backHref: string;\n onBackClick?: never;\n}\n\ninterface BitkitPageSidebarTitleButtonProps extends BitkitPageSidebarTitleCommonProps {\n backHref?: never;\n onBackClick: () => void;\n}\n\ninterface BitkitPageSidebarTitlePlainProps extends BitkitPageSidebarTitleCommonProps {\n backHref?: never;\n onBackClick?: never;\n}\n\nexport type BitkitPageSidebarTitleProps =\n BitkitPageSidebarTitleButtonProps | BitkitPageSidebarTitleLinkProps | BitkitPageSidebarTitlePlainProps;\n\nconst BitkitPageSidebarTitle = forwardRef<HTMLDivElement, BitkitPageSidebarTitleProps>((props, ref) => {\n const { backHref, backLabel = 'Back', children, css, onBackClick, ...rest } = props;\n\n const hasBack = backHref !== undefined || onBackClick !== undefined;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe({ hasBack });\n\n return (\n <Box ref={ref} css={[styles.title, css]} {...rest}>\n <Box css={styles.titleBlock}>\n {/* The label tooltip opens to the right. Its default `top` has nowhere to go here — the\n button sits at the very top of the sidebar, so the tooltip jams against the viewport\n edge and covers the header instead of flipping. */}\n {hasBack &&\n (backHref !== undefined ? (\n <BitkitControlButton\n href={backHref}\n icon={IconChevronLeft}\n label={backLabel}\n size=\"xs\"\n tooltipProps={{ placement: 'right' }}\n />\n ) : (\n <BitkitControlButton\n icon={IconChevronLeft}\n label={backLabel}\n onClick={onBackClick}\n size=\"xs\"\n tooltipProps={{ placement: 'right' }}\n />\n ))}\n <Text as=\"span\" css={styles.titleText}>\n {children}\n </Text>\n </Box>\n </Box>\n );\n});\n\nBitkitPageSidebarTitle.displayName = 'BitkitPageSidebarTitle';\n\n// ----- BitkitPageSidebar.Body -----\n\nexport interface BitkitPageSidebarBodyProps extends BoxProps {\n children: ReactNode;\n}\n\n/**\n * Holds the navigation items. It absorbs the space left between `Title` and `Footer`, so the footer\n * sits at the bottom of the viewport on a short navigation, and keeps a minimum gap above the\n * footer so the two blocks stay visually separate however long the list gets.\n */\nconst BitkitPageSidebarBody = forwardRef<HTMLDivElement, BitkitPageSidebarBodyProps>((props, ref) => {\n const { children, css, ...rest } = props;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe();\n\n return (\n <Box ref={ref} css={[styles.body, css]} {...rest}>\n {children}\n </Box>\n );\n});\n\nBitkitPageSidebarBody.displayName = 'BitkitPageSidebarBody';\n\n// ----- BitkitPageSidebar.Footer -----\n\nexport interface BitkitPageSidebarFooterProps extends BoxProps {\n children: ReactNode;\n}\n\nconst BitkitPageSidebarFooter = forwardRef<HTMLDivElement, BitkitPageSidebarFooterProps>((props, ref) => {\n const { children, css, ...rest } = props;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe();\n\n return (\n <Box ref={ref} css={[styles.footer, css]} {...rest}>\n {children}\n </Box>\n );\n});\n\nBitkitPageSidebarFooter.displayName = 'BitkitPageSidebarFooter';\n\n// ----- BitkitPageSidebar.Project -----\n\nexport interface BitkitPageSidebarProjectProps extends BoxProps {\n label: string;\n value: string;\n}\n\nconst BitkitPageSidebarProject = forwardRef<HTMLDivElement, BitkitPageSidebarProjectProps>((props, ref) => {\n const { css, label, value, ...rest } = props;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe();\n\n const { isTruncated, ref: valueRef } = useIsTruncated<HTMLSpanElement>(value);\n\n return (\n <Box ref={ref} css={[styles.project, css]} {...rest}>\n <Text as=\"span\" css={styles.projectLabel}>\n {label}\n </Text>\n {/* Wrapper for the same reason as in Item: the trigger cannot be the element being measured. */}\n <BitkitOverflowTooltip disabled={!isTruncated} text={value}>\n <Box css={styles.projectValueWrapper}>\n <Text as=\"span\" css={styles.projectValue} ref={valueRef}>\n {value}\n </Text>\n </Box>\n </BitkitOverflowTooltip>\n </Box>\n );\n});\n\nBitkitPageSidebarProject.displayName = 'BitkitPageSidebarProject';\n\n// ----- BitkitPageSidebar.GroupHeading -----\n\nexport type BitkitPageSidebarGroupHeadingProps = BitkitGroupHeadingProps;\n\nconst BitkitPageSidebarGroupHeading = forwardRef<HTMLDivElement, BitkitPageSidebarGroupHeadingProps>((props, ref) => {\n return <BitkitGroupHeading ref={ref} paddingBlockEnd=\"8\" paddingBlockStart=\"16\" paddingInline=\"24\" {...props} />;\n});\n\nBitkitPageSidebarGroupHeading.displayName = 'BitkitPageSidebarGroupHeading';\n\n// ----- BitkitPageSidebar.DrawerHeader -----\n\nexport interface BitkitPageSidebarDrawerHeaderProps extends Omit<BoxProps, 'title'> {\n /** App icon or user avatar before the title — a 32px `BitkitAvatar`. */\n avatar?: ReactNode;\n /** The entity's secondary line, an app's bundle id or a user's email. Its presence selects the entity layout. */\n secondaryText?: string;\n /** What the navigation belongs to: the page, app or user. */\n title: string;\n}\n\n/**\n * Header of the sidebar's mobile drawer (Figma `mobilePageSidebarHeader`). Pass it as the\n * sidebar's `drawerHeader`; it is what the panel opens with, above the navigation.\n */\nconst BitkitPageSidebarDrawerHeader = forwardRef<HTMLDivElement, BitkitPageSidebarDrawerHeaderProps>((props, ref) => {\n const { avatar, css, secondaryText, title, ...rest } = props;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe({ hasSecondaryText: secondaryText !== undefined });\n\n return (\n <Box ref={ref} css={[styles.drawerHeader, css]} {...rest}>\n {avatar !== undefined && <Box css={styles.drawerHeaderAvatar}>{avatar}</Box>}\n <Box css={styles.drawerHeaderTextBlock}>\n <Text css={styles.drawerHeaderTitle}>{title}</Text>\n {secondaryText !== undefined && <Text css={styles.drawerHeaderSecondaryText}>{secondaryText}</Text>}\n </Box>\n </Box>\n );\n});\n\nBitkitPageSidebarDrawerHeader.displayName = 'BitkitPageSidebarDrawerHeader';\n\n// ----- BitkitPageSidebar.Divider -----\n\nexport type BitkitPageSidebarDividerProps = SeparatorProps;\n\nconst BitkitPageSidebarDivider = forwardRef<HTMLDivElement, BitkitPageSidebarDividerProps>((props, ref) => {\n const { css, ...rest } = props;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe();\n\n return <Separator ref={ref} css={[styles.divider, css]} {...rest} />;\n});\n\nBitkitPageSidebarDivider.displayName = 'BitkitPageSidebarDivider';\n\nexport default withSubComponents(BitkitPageSidebar, {\n Body: BitkitPageSidebarBody,\n Divider: BitkitPageSidebarDivider,\n DrawerHeader: BitkitPageSidebarDrawerHeader,\n Footer: BitkitPageSidebarFooter,\n GroupHeading: BitkitPageSidebarGroupHeading,\n Item: BitkitPageSidebarItem,\n ProgressItem: BitkitPageSidebarProgressItem,\n Project: BitkitPageSidebarProject,\n Title: BitkitPageSidebarTitle,\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BitkitPageSidebar.js","names":["_Fragment"],"sources":["../../../lib/components/BitkitPageSidebar/BitkitPageSidebar.tsx"],"sourcesContent":["import { Box, type BoxProps } from '@chakra-ui/react/box';\nimport { Drawer } from '@chakra-ui/react/drawer';\nimport { Portal } from '@chakra-ui/react/portal';\nimport { Separator, type SeparatorProps } from '@chakra-ui/react/separator';\nimport { chakra, type HTMLChakraProps, useChakraContext, useSlotRecipe } from '@chakra-ui/react/styled-system';\nimport { Text } from '@chakra-ui/react/text';\nimport { forwardRef, type KeyboardEvent, type MouseEvent, type ReactNode, type Ref } from 'react';\n\nimport useResponsive from '../../hooks/useResponsive';\nimport { type BitkitIconComponent } from '../../icons';\nimport IconChevronLeft from '../../icons/IconChevronLeft';\nimport { type BitkitColorToken } from '../../theme/themeUtils';\nimport focusableDisabledProps from '../../utilities/focusableDisabledProps';\nimport useIsTruncated from '../../utilities/useIsTruncated';\nimport { withSubComponents } from '../../utilities/withSubComponents';\nimport BitkitCloseButton from '../BitkitCloseButton/BitkitCloseButton';\nimport BitkitControlButton from '../BitkitControlButton/BitkitControlButton';\nimport BitkitGroupHeading, { type BitkitGroupHeadingProps } from '../BitkitGroupHeading/BitkitGroupHeading';\nimport BitkitOverflowTooltip from '../BitkitOverflowTooltip/BitkitOverflowTooltip';\nimport BitkitTooltip from '../BitkitTooltip/BitkitTooltip';\n\n// The 16 and 24 icons are separate drawings, not one scaled to two sizes, so the breakpoint swap\n// cannot live in the recipe — both are rendered and one is hidden. A `useBreakpointValue` would\n// render a single icon, but it only re-reads on mount: resize a live page across `tablet` and the\n// row resizes underneath an icon that keeps its old size.\nconst showAtDesktop = { display: { base: 'none', tablet: 'block' } };\nconst showAtMobile = { display: { base: 'block', tablet: 'none' } };\n\n// ----- BitkitPageSidebar (Root) -----\n\nexport interface BitkitPageSidebarProps extends BoxProps {\n children: ReactNode;\n /**\n * Header of the mobile drawer panel, naming what the navigation belongs to — pass a\n * `BitkitPageSidebar.DrawerHeader`. Only rendered in drawer mode.\n */\n drawerHeader?: ReactNode;\n /**\n * Mobile drawer visibility. Controlled, because the page header's menu button is what opens it.\n * Passing `onOpenChange` is what opts the sidebar into the drawer below `tablet`; without it the\n * sidebar stays in the flow at full width there. Both are ignored from `tablet` up.\n *\n * Style props and `css` apply to the sidebar beside the page only — the drawer panel sizes\n * itself, so a desktop `width` or padding never reaches the navigation inside it.\n */\n onOpenChange?: (open: boolean) => void;\n open?: boolean;\n}\n\n/**\n * Page-level navigation sidebar. It expects three children, in this order:\n *\n * ```tsx\n * <BitkitPageSidebar>\n * <BitkitPageSidebar.Title>Title</BitkitPageSidebar.Title>\n * <BitkitPageSidebar.Body>\n * <BitkitPageSidebar.Item icon={IconWorkflow}>Workflows</BitkitPageSidebar.Item>\n * </BitkitPageSidebar.Body>\n * <BitkitPageSidebar.Footer>…</BitkitPageSidebar.Footer>\n * </BitkitPageSidebar>\n * ```\n *\n * `Title` and `Footer` are optional. The sidebar scrolls as a single block: when the navigation is\n * taller than the viewport the whole thing — footer included — grows and scrolls with the page,\n * which is why `Body` keeps a minimum gap above the footer so the two blocks never touch.\n *\n * The `<nav>` carries a default `aria-label` so it is not announced as an unnamed landmark. A page\n * with more than one sidebar should name each one — pass your own `aria-label` (or\n * `aria-labelledby`), which overrides the default.\n *\n * It stands at least viewport-tall by default. An embedded panel that should size to its content\n * opts out with `minHeight=\"auto\"`.\n *\n * Below the `tablet` breakpoint it switches to the mobile design on its own — full width, 48px\n * rows, larger icons and labels, a squared-off selection edge. A sidebar that sits beside page\n * content has nowhere to go at that width, so it can become a drawer instead: pass `open` and\n * `onOpenChange` (opened by `BitkitPageHeader`'s menu button) and below `tablet` it slides in\n * from the trailing edge over a backdrop, with its close button on the backdrop beside the panel\n * and a `drawerHeader` naming the page. Both props are ignored from `tablet` up.\n */\nconst BitkitPageSidebar = forwardRef<HTMLElement, BitkitPageSidebarProps>((props, ref) => {\n const { children, css, drawerHeader, onOpenChange, open = false, ...rest } = props;\n\n const { isMobile } = useResponsive();\n const { splitCssProps } = useChakraContext();\n const hasDrawer = onOpenChange !== undefined;\n const isDrawer = isMobile && hasDrawer;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe({ layout: isDrawer ? 'drawer' : hasDrawer ? 'hidden' : 'static' });\n\n if (!isDrawer) {\n return (\n <Box ref={ref} aria-label=\"Page navigation\" asChild css={[styles.root, css]} {...rest}>\n <nav>{children}</nav>\n </Box>\n );\n }\n\n // The consumer's sizing is for the sidebar beside the page; inside the panel only the recipe\n // lays the navigation out.\n const [, navProps] = splitCssProps(rest);\n\n return (\n <Drawer.Root onOpenChange={(details) => onOpenChange(details.open)} open={open}>\n <Portal>\n <Drawer.Backdrop css={styles.drawerBackdrop} />\n <Drawer.Positioner>\n <Drawer.Content aria-label=\"Navigation\" css={styles.drawerContent}>\n {drawerHeader}\n <Box ref={ref} aria-label=\"Page navigation\" asChild css={styles.root} {...navProps}>\n <nav>{children}</nav>\n </Box>\n <Box css={styles.drawerCloseButton}>\n <BitkitCloseButton\n aria-label=\"Close navigation\"\n colorVariant=\"white\"\n onClick={() => onOpenChange(false)}\n size=\"md\"\n />\n </Box>\n </Drawer.Content>\n </Drawer.Positioner>\n </Portal>\n </Drawer.Root>\n );\n});\n\nBitkitPageSidebar.displayName = 'BitkitPageSidebar';\n\n// ----- BitkitPageSidebar.Item -----\n\ninterface BitkitPageSidebarItemCommonProps {\n badge?: ReactNode;\n /**\n * The item's label. Typed as a string rather than `ReactNode` because the row truncates it with\n * an ellipsis, and the overflow tooltip needs the full text to reveal.\n */\n children: string;\n /**\n * Why the item is unavailable, shown in a tooltip on it while `state` is `\"disabled\"`. The item\n * then stays focusable and is announced as disabled (`aria-disabled`), so the tooltip opens on\n * hover and focus. It still neither navigates nor activates. Use it instead of wrapping a disabled\n * item in `BitkitTooltip`.\n */\n disabledReason?: string;\n icon?: BitkitIconComponent;\n /**\n * Marks the item as the current page. Mutually exclusive with `state=\"disabled\"` — you cannot be\n * on a page whose nav item is unavailable — but the two are not type-checked against each other:\n * the combination only ever arrives from a computed `selected`, which no union can catch, and\n * checking it would break the ordinary `selected={item.id === currentId}` mapping. If both do\n * turn up, disabled wins, since that is the one of the two the design actually defines.\n */\n selected?: boolean;\n state?: 'disabled';\n suffixIcon?: BitkitIconComponent;\n}\n\ninterface BitkitPageSidebarItemLinkProps\n extends Omit<HTMLChakraProps<'a'>, 'children'>, BitkitPageSidebarItemCommonProps {\n href: string;\n}\n\ninterface BitkitPageSidebarItemButtonProps\n extends Omit<HTMLChakraProps<'button'>, 'children' | 'disabled'>, BitkitPageSidebarItemCommonProps {\n href?: never;\n}\n\nexport type BitkitPageSidebarItemProps = BitkitPageSidebarItemButtonProps | BitkitPageSidebarItemLinkProps;\n\nconst BitkitPageSidebarItem = forwardRef<HTMLButtonElement | HTMLAnchorElement, BitkitPageSidebarItemProps>(\n (props, ref) => {\n const { badge, children, disabledReason, icon: Icon, selected, state, suffixIcon: SuffixIcon, ...rest } = props;\n\n const isDisabled = state === 'disabled';\n const hasReason = isDisabled && !!disabledReason;\n // `selected` and `state=\"disabled\"` are not checked against each other in the types, so this is\n // the single place the overlap is resolved: disabled wins, and the two recipe variants can never\n // both claim the same slot.\n const isSelected = selected === true && !isDisabled;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe({ isDisabled, selected: isSelected });\n\n // The design gives neither a selected row nor a disabled one a trailing icon — the desktop\n // (`20014:6498`, `20014:6494`) and mobile (`9221:4417`) items drop it in those states.\n const VisibleSuffixIcon = isSelected || isDisabled ? undefined : SuffixIcon;\n\n const { isTruncated, ref: labelRef } = useIsTruncated<HTMLSpanElement>(children);\n\n const itemContent = (\n <>\n {/* `span`, not the default `div`: in button mode these sit inside a `<button>`, whose\n content model allows phrasing content only. */}\n <Box as=\"span\" css={styles.contentBlock}>\n {Icon && (\n <>\n <Icon css={[styles.itemIcon, showAtDesktop]} size=\"16\" />\n <Icon css={[styles.itemIcon, showAtMobile]} size=\"24\" />\n </>\n )}\n <Text as=\"span\" css={styles.itemLabel} ref={labelRef}>\n {children}\n </Text>\n </Box>\n {badge}\n {VisibleSuffixIcon && (\n <>\n <VisibleSuffixIcon css={[styles.suffixIcon, showAtDesktop]} size=\"16\" />\n <VisibleSuffixIcon css={[styles.suffixIcon, showAtMobile]} size=\"24\" />\n </>\n )}\n {isSelected && <Box as=\"span\" css={styles.selectionMarker} />}\n </>\n );\n\n // The overflow tooltip anchors to the row itself, which is the focusable element: anchored to an\n // inner node it would only ever open on hover, leaving keyboard users unable to read a truncated\n // label. `Tooltip.Trigger` renders `asChild` and composes refs, so the consumer's forwarded ref\n // survives, and the ref measuring the truncation sits on the label further in.\n // The reason tooltip is always rendered so a state change can't remount the row and drop its focus.\n const withTooltip = (row: ReactNode) => (\n <BitkitTooltip disabled={!hasReason} placement=\"right\" text={disabledReason ?? ''}>\n <BitkitOverflowTooltip disabled={!isTruncated || hasReason} text={children}>\n {row}\n </BitkitOverflowTooltip>\n </BitkitTooltip>\n );\n\n // `chakra.a` / `chakra.button` rather than a named primitive: the item carries its own slot recipe,\n // and Chakra's `Button`/`Link` would layer their own recipe styles on top of it.\n if (rest.href !== undefined) {\n const { className, href, onClick, onKeyDown, ...linkRest } = rest;\n const handleClick = isDisabled\n ? (event: MouseEvent<HTMLAnchorElement>) => {\n event.preventDefault();\n event.stopPropagation();\n }\n : onClick;\n const handleKeyDown = isDisabled\n ? (event: KeyboardEvent<HTMLAnchorElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n event.stopPropagation();\n }\n }\n : onKeyDown;\n\n return withTooltip(\n <chakra.a\n ref={ref as Ref<HTMLAnchorElement>}\n {...linkRest}\n aria-current={isSelected ? 'page' : undefined}\n aria-disabled={isDisabled || undefined}\n className={className ? `group ${className}` : 'group'}\n css={styles.item}\n // Dropping the attribute is what actually disables the link, the way `BitkitLink` and\n // `BitkitControlButton` do it. The handlers below only block `click` and `Enter`/`Space`;\n // a middle click fires `auxclick`, and \"Open link in new tab\" never reaches the page at\n // all, so both would still navigate while an `href` is there to follow.\n href={isDisabled ? undefined : href}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n // Without `href` the anchor is neither a link nor focusable, and the reason tooltip needs both.\n {...(hasReason && { role: 'link', tabIndex: 0 })}\n >\n {itemContent}\n </chakra.a>,\n );\n }\n\n const { className, href: _href, ...buttonRest } = rest;\n\n return withTooltip(\n <chakra.button\n ref={ref as Ref<HTMLButtonElement>}\n {...buttonRest}\n aria-current={isSelected ? 'page' : undefined}\n className={className ? `group ${className}` : 'group'}\n css={styles.item}\n disabled={isDisabled && !hasReason}\n type=\"button\"\n {...(hasReason && focusableDisabledProps)}\n >\n {itemContent}\n </chakra.button>,\n );\n },\n);\n\nBitkitPageSidebarItem.displayName = 'BitkitPageSidebarItem';\n\n// ----- BitkitPageSidebar.ProgressItem -----\n\nexport interface BitkitPageSidebarProgressItemProps extends Omit<HTMLChakraProps<'button'>, 'children' | 'disabled'> {\n /**\n * Trailing content between the label and the connector — a `BitkitBadge` counting what the stage\n * is waiting on. Sized to itself; the connector takes the rest.\n *\n * The design draws it 20px tall, which is `size=\"xs\"`. The badge arrives as a node, so the\n * component cannot set that for you — a taller one grows the row past its 40px.\n */\n badge?: ReactNode;\n /** The row's label. */\n children: ReactNode;\n /**\n * The status icon. Unlike `Item`, whose icon colour the sidebar owns, this one carries the\n * stage's status, so `iconColor` is the consumer's to set — `selected`, `notRequired` and\n * `state=\"disabled\"` still win over it, since those describe the row rather than the status.\n */\n icon: BitkitIconComponent;\n /**\n * A semantic token for the status the icon is showing. Left out, the icon takes the sidebar's own\n * `icon/secondary` — which is what the design gives a stage whose icon carries no status, such as\n * an approvals step.\n *\n * Narrowed to the `icon/*` and `color/*` tokens, so a name that does not exist is a compile error\n * rather than a colour that silently does not apply. Both families are here because the statuses\n * need both: the design takes success and failure from `icon/*` but in-progress from\n * `color/orange/bold`, which the `icon/*` set has no equivalent of.\n */\n iconColor?: BitkitColorToken<'color' | 'icon'>;\n /**\n * A stage the release does not have to clear. Steps the icon and the label down one level, so the\n * row reads as present but not awaited.\n */\n notRequired?: boolean;\n /** Follows the label after a middle dot — `auto-upload`, `not required`. */\n secondaryText?: string;\n selected?: boolean;\n state?: 'disabled';\n /**\n * Draws the dashed rule that runs from the badge to the trailing edge, tying one stage to the\n * next. The last stage in a list has nothing to tie to, so it goes without.\n */\n withConnector?: boolean;\n}\n\n/**\n * A stage of something that progresses, as a row of the page sidebar — a release running through\n * its steps, and whatever comes to look like it.\n *\n * It is a sibling of `Item` rather than a variant of it: the row reports where a stage stands\n * rather than navigating, so its icon is status-coloured, its label does not grow, and a dashed\n * connector runs to the trailing edge between the stages.\n *\n * Always a `<button>`, and always interactive — it carries the shared row's pointer cursor and\n * hover background, so a row without an `onClick` looks actionable and is not. `Item`'s\n * button-or-anchor union is deliberately not here: a stage is selected within the page it is\n * already on rather than navigated to.\n */\nconst BitkitPageSidebarProgressItem = forwardRef<HTMLButtonElement, BitkitPageSidebarProgressItemProps>(\n (props, ref) => {\n const {\n badge,\n children,\n className,\n css,\n icon: Icon,\n iconColor,\n notRequired,\n secondaryText,\n selected,\n state,\n withConnector,\n ...rest\n } = props;\n\n const isDisabled = state === 'disabled';\n // Disabled is the whole state of the row, so the other two are dropped rather than merged: the\n // recipe resolves a combination in its own order, and a disabled row came out of it carrying\n // the selected icon colour. Nothing about a disabled stage is selected or not-required.\n const isSelected = selected && !isDisabled;\n // And `selected` wins over `notRequired`, which the design decides rather than declaration\n // order: its `selected=yes, notRequired=true` variant draws the selected row's icon and label\n // and keeps `not required` in the secondary text -- which is what dropping this produces.\n const isNotRequired = notRequired && !isDisabled && !isSelected;\n\n const statusColor = isDisabled || isNotRequired || isSelected ? undefined : iconColor;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe({ isDisabled, notRequired: isNotRequired, selected: isSelected });\n\n return (\n <chakra.button\n ref={ref}\n {...rest}\n // `step` rather than the `page` an `Item` carries: these are stages of one thing, not\n // separate pages.\n aria-current={isSelected ? 'step' : undefined}\n className={className ? `group ${className}` : 'group'}\n css={[styles.item, styles.progressRow, css]}\n disabled={isDisabled}\n type=\"button\"\n >\n <Box as=\"span\" css={[styles.contentBlock, styles.progressContentBlock]}>\n {/* Two icons, one per size, for the reason `Item` has two -- see `showAtDesktop`.\n The status colour applies while the row is ordinary: `selected`, `notRequired` and\n disabled are states of the row rather than of the status, and the design recolours the\n icon in all three, so the recipe takes it back there. */}\n <Icon color={statusColor} css={[styles.progressIcon, showAtDesktop]} size=\"16\" />\n <Icon color={statusColor} css={[styles.progressIcon, showAtMobile]} size=\"24\" />\n <Box as=\"span\" css={styles.progressTextBlock}>\n <Text as=\"span\" css={styles.progressLabel}>\n {children}\n </Text>\n {secondaryText && (\n <Text as=\"span\" css={styles.progressSecondaryText}>\n {`\\u00b7 ${secondaryText}`}\n </Text>\n )}\n </Box>\n {(badge || withConnector) && (\n <Box as=\"span\" css={styles.progressBlocker}>\n {badge}\n {/* Decorative: it ties the stages together visually and has nothing to separate in\n the button's accessibility tree. */}\n {withConnector && <Separator aria-hidden css={styles.progressConnector} />}\n </Box>\n )}\n </Box>\n {isSelected && <Box as=\"span\" css={styles.selectionMarker} />}\n </chakra.button>\n );\n },\n);\n\nBitkitPageSidebarProgressItem.displayName = 'BitkitPageSidebarProgressItem';\n\n// ----- BitkitPageSidebar.Title -----\n\ninterface BitkitPageSidebarTitleCommonProps extends BoxProps {\n backLabel?: string;\n children: ReactNode;\n}\n\ninterface BitkitPageSidebarTitleLinkProps extends BitkitPageSidebarTitleCommonProps {\n backHref: string;\n onBackClick?: never;\n}\n\ninterface BitkitPageSidebarTitleButtonProps extends BitkitPageSidebarTitleCommonProps {\n backHref?: never;\n onBackClick: () => void;\n}\n\ninterface BitkitPageSidebarTitlePlainProps extends BitkitPageSidebarTitleCommonProps {\n backHref?: never;\n onBackClick?: never;\n}\n\nexport type BitkitPageSidebarTitleProps =\n BitkitPageSidebarTitleButtonProps | BitkitPageSidebarTitleLinkProps | BitkitPageSidebarTitlePlainProps;\n\nconst BitkitPageSidebarTitle = forwardRef<HTMLDivElement, BitkitPageSidebarTitleProps>((props, ref) => {\n const { backHref, backLabel = 'Back', children, css, onBackClick, ...rest } = props;\n\n const hasBack = backHref !== undefined || onBackClick !== undefined;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe({ hasBack });\n\n return (\n <Box ref={ref} css={[styles.title, css]} {...rest}>\n <Box css={styles.titleBlock}>\n {/* The label tooltip opens to the right. Its default `top` has nowhere to go here — the\n button sits at the very top of the sidebar, so the tooltip jams against the viewport\n edge and covers the header instead of flipping. */}\n {hasBack &&\n (backHref !== undefined ? (\n <BitkitControlButton\n href={backHref}\n icon={IconChevronLeft}\n label={backLabel}\n size=\"xs\"\n tooltipProps={{ placement: 'right' }}\n />\n ) : (\n <BitkitControlButton\n icon={IconChevronLeft}\n label={backLabel}\n onClick={onBackClick}\n size=\"xs\"\n tooltipProps={{ placement: 'right' }}\n />\n ))}\n <Text as=\"span\" css={styles.titleText}>\n {children}\n </Text>\n </Box>\n </Box>\n );\n});\n\nBitkitPageSidebarTitle.displayName = 'BitkitPageSidebarTitle';\n\n// ----- BitkitPageSidebar.Body -----\n\nexport interface BitkitPageSidebarBodyProps extends BoxProps {\n children: ReactNode;\n}\n\n/**\n * Holds the navigation items. It absorbs the space left between `Title` and `Footer`, so the footer\n * sits at the bottom of the viewport on a short navigation, and keeps a minimum gap above the\n * footer so the two blocks stay visually separate however long the list gets.\n */\nconst BitkitPageSidebarBody = forwardRef<HTMLDivElement, BitkitPageSidebarBodyProps>((props, ref) => {\n const { children, css, ...rest } = props;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe();\n\n return (\n <Box ref={ref} css={[styles.body, css]} {...rest}>\n {children}\n </Box>\n );\n});\n\nBitkitPageSidebarBody.displayName = 'BitkitPageSidebarBody';\n\n// ----- BitkitPageSidebar.Footer -----\n\nexport interface BitkitPageSidebarFooterProps extends BoxProps {\n children: ReactNode;\n}\n\nconst BitkitPageSidebarFooter = forwardRef<HTMLDivElement, BitkitPageSidebarFooterProps>((props, ref) => {\n const { children, css, ...rest } = props;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe();\n\n return (\n <Box ref={ref} css={[styles.footer, css]} {...rest}>\n {children}\n </Box>\n );\n});\n\nBitkitPageSidebarFooter.displayName = 'BitkitPageSidebarFooter';\n\n// ----- BitkitPageSidebar.Project -----\n\nexport interface BitkitPageSidebarProjectProps extends BoxProps {\n label: string;\n value: string;\n}\n\nconst BitkitPageSidebarProject = forwardRef<HTMLDivElement, BitkitPageSidebarProjectProps>((props, ref) => {\n const { css, label, value, ...rest } = props;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe();\n\n const { isTruncated, ref: valueRef } = useIsTruncated<HTMLSpanElement>(value);\n\n return (\n <Box ref={ref} css={[styles.project, css]} {...rest}>\n <Text as=\"span\" css={styles.projectLabel}>\n {label}\n </Text>\n {/* Wrapper for the same reason as in Item: the trigger cannot be the element being measured. */}\n <BitkitOverflowTooltip disabled={!isTruncated} text={value}>\n <Box css={styles.projectValueWrapper}>\n <Text as=\"span\" css={styles.projectValue} ref={valueRef}>\n {value}\n </Text>\n </Box>\n </BitkitOverflowTooltip>\n </Box>\n );\n});\n\nBitkitPageSidebarProject.displayName = 'BitkitPageSidebarProject';\n\n// ----- BitkitPageSidebar.GroupHeading -----\n\nexport type BitkitPageSidebarGroupHeadingProps = BitkitGroupHeadingProps;\n\nconst BitkitPageSidebarGroupHeading = forwardRef<HTMLDivElement, BitkitPageSidebarGroupHeadingProps>((props, ref) => {\n return <BitkitGroupHeading ref={ref} paddingBlockEnd=\"8\" paddingBlockStart=\"16\" paddingInline=\"24\" {...props} />;\n});\n\nBitkitPageSidebarGroupHeading.displayName = 'BitkitPageSidebarGroupHeading';\n\n// ----- BitkitPageSidebar.DrawerHeader -----\n\nexport interface BitkitPageSidebarDrawerHeaderProps extends Omit<BoxProps, 'title'> {\n /** App icon or user avatar before the title — a 32px `BitkitAvatar`. */\n avatar?: ReactNode;\n /** The entity's secondary line, an app's bundle id or a user's email. Its presence selects the entity layout. */\n secondaryText?: string;\n /** What the navigation belongs to: the page, app or user. */\n title: string;\n}\n\n/**\n * Header of the sidebar's mobile drawer (Figma `mobilePageSidebarHeader`). Pass it as the\n * sidebar's `drawerHeader`; it is what the panel opens with, above the navigation.\n */\nconst BitkitPageSidebarDrawerHeader = forwardRef<HTMLDivElement, BitkitPageSidebarDrawerHeaderProps>((props, ref) => {\n const { avatar, css, secondaryText, title, ...rest } = props;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe({ hasSecondaryText: secondaryText !== undefined });\n\n return (\n <Box ref={ref} css={[styles.drawerHeader, css]} {...rest}>\n {avatar !== undefined && <Box css={styles.drawerHeaderAvatar}>{avatar}</Box>}\n <Box css={styles.drawerHeaderTextBlock}>\n <Text css={styles.drawerHeaderTitle}>{title}</Text>\n {secondaryText !== undefined && <Text css={styles.drawerHeaderSecondaryText}>{secondaryText}</Text>}\n </Box>\n </Box>\n );\n});\n\nBitkitPageSidebarDrawerHeader.displayName = 'BitkitPageSidebarDrawerHeader';\n\n// ----- BitkitPageSidebar.Divider -----\n\nexport type BitkitPageSidebarDividerProps = SeparatorProps;\n\nconst BitkitPageSidebarDivider = forwardRef<HTMLDivElement, BitkitPageSidebarDividerProps>((props, ref) => {\n const { css, ...rest } = props;\n\n const recipe = useSlotRecipe({ key: 'pageSidebar' });\n const styles = recipe();\n\n return <Separator ref={ref} css={[styles.divider, css]} {...rest} />;\n});\n\nBitkitPageSidebarDivider.displayName = 'BitkitPageSidebarDivider';\n\nexport default withSubComponents(BitkitPageSidebar, {\n Body: BitkitPageSidebarBody,\n Divider: BitkitPageSidebarDivider,\n DrawerHeader: BitkitPageSidebarDrawerHeader,\n Footer: BitkitPageSidebarFooter,\n GroupHeading: BitkitPageSidebarGroupHeading,\n Item: BitkitPageSidebarItem,\n ProgressItem: BitkitPageSidebarProgressItem,\n Project: BitkitPageSidebarProject,\n Title: BitkitPageSidebarTitle,\n});\n"],"mappings":"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"}
|
|
@@ -36,8 +36,8 @@ export type BitkitTooltipProps = {
|
|
|
36
36
|
* that cannot take focus — on a focusable one this adds a second, redundant tab stop for the same
|
|
37
37
|
* control. A disabled `<button>` dispatches no pointer events and is out of the tab order, so
|
|
38
38
|
* without a wrapper the tooltip never opens — in the one state whose explanation the user actually
|
|
39
|
-
* needs. For a disabled `BitkitButton` or `
|
|
40
|
-
*
|
|
39
|
+
* needs. For a disabled `BitkitButton`, `BitkitIconButton` or `BitkitPageSidebar.Item`, pass its
|
|
40
|
+
* `disabledReason` instead: it stays focusable and announced as disabled, with no wrapper.
|
|
41
41
|
*
|
|
42
42
|
* Chakra v2's `Tooltip` had this built in as `shouldWrapChildren`, rendering a
|
|
43
43
|
* `<span display="inline-block" tabIndex={0}>` that carried the trigger props. Ark's tooltip has no
|
|
@@ -47,7 +47,7 @@ export type BitkitTooltipProps = {
|
|
|
47
47
|
*
|
|
48
48
|
* The wrapper is a plain focusable span, so focusing it announces the trigger's label and the
|
|
49
49
|
* tooltip text, not the trigger's own state — a disabled button inside is not re-announced as
|
|
50
|
-
* disabled; that is what `disabledReason`
|
|
50
|
+
* disabled; that is what `disabledReason` fixes.
|
|
51
51
|
*/
|
|
52
52
|
wrapTrigger?: boolean;
|
|
53
53
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BitkitTooltip.js","names":[],"sources":["../../../lib/components/BitkitTooltip/BitkitTooltip.tsx"],"sourcesContent":["import { Box } from '@chakra-ui/react/box';\nimport { Portal } from '@chakra-ui/react/portal';\nimport { Tooltip, type TooltipRootProps } from '@chakra-ui/react/tooltip';\nimport { isValidElement, type ReactNode, type Ref, useContext, useRef } from 'react';\n\nimport { type BitkitIconComponent } from '../../icons';\nimport BitkitPortalContext from '../../utilities/BitkitPortalContext';\n\nexport type BitkitTooltipProps = {\n /**\n * The trigger the tooltip is anchored to. Rendered via `asChild`, so it must accept a ref —\n * unless `wrapTrigger` puts a wrapper in between.\n */\n children: ReactNode;\n /** Dismiss the tooltip when the trigger is clicked. */\n closeOnClick?: TooltipRootProps['closeOnClick'];\n /**\n * Render the tooltip inline instead of in a portal. Only needed when it must stay inside its\n * parent's DOM subtree — a dialog already sets this for you.\n */\n disablePortal?: boolean;\n /** Render the trigger without a tooltip — for hints that only apply in some states. */\n disabled?: TooltipRootProps['disabled'];\n /**\n * Icon rendered after `text`, at size 16. Use it for the affordance the tooltip describes — an\n * `IconArrowNortheast` when the trigger opens something in a new tab, for instance.\n */\n icon?: BitkitIconComponent;\n /** Called when the tooltip opens or closes, including from hover and focus. */\n onOpenChange?: TooltipRootProps['onOpenChange'];\n /** Controlled open state. Leave unset to let hover and focus drive it. */\n open?: TooltipRootProps['open'];\n /** Delay in ms before an uncontrolled tooltip opens on hover. */\n openDelay?: TooltipRootProps['openDelay'];\n /** Where the tooltip sits relative to the trigger (default `top`). It flips if space is short. */\n placement?: NonNullable<TooltipRootProps['positioning']>['placement'];\n /** The tooltip's text. Plain string only — use `icon` for a glyph after it. */\n text: string;\n /**\n * Render the trigger inside a focusable wrapper instead of on the trigger itself. Only for triggers\n * that cannot take focus — on a focusable one this adds a second, redundant tab stop for the same\n * control. A disabled `<button>` dispatches no pointer events and is out of the tab order, so\n * without a wrapper the tooltip never opens — in the one state whose explanation the user actually\n * needs. For a disabled `BitkitButton` or `
|
|
1
|
+
{"version":3,"file":"BitkitTooltip.js","names":[],"sources":["../../../lib/components/BitkitTooltip/BitkitTooltip.tsx"],"sourcesContent":["import { Box } from '@chakra-ui/react/box';\nimport { Portal } from '@chakra-ui/react/portal';\nimport { Tooltip, type TooltipRootProps } from '@chakra-ui/react/tooltip';\nimport { isValidElement, type ReactNode, type Ref, useContext, useRef } from 'react';\n\nimport { type BitkitIconComponent } from '../../icons';\nimport BitkitPortalContext from '../../utilities/BitkitPortalContext';\n\nexport type BitkitTooltipProps = {\n /**\n * The trigger the tooltip is anchored to. Rendered via `asChild`, so it must accept a ref —\n * unless `wrapTrigger` puts a wrapper in between.\n */\n children: ReactNode;\n /** Dismiss the tooltip when the trigger is clicked. */\n closeOnClick?: TooltipRootProps['closeOnClick'];\n /**\n * Render the tooltip inline instead of in a portal. Only needed when it must stay inside its\n * parent's DOM subtree — a dialog already sets this for you.\n */\n disablePortal?: boolean;\n /** Render the trigger without a tooltip — for hints that only apply in some states. */\n disabled?: TooltipRootProps['disabled'];\n /**\n * Icon rendered after `text`, at size 16. Use it for the affordance the tooltip describes — an\n * `IconArrowNortheast` when the trigger opens something in a new tab, for instance.\n */\n icon?: BitkitIconComponent;\n /** Called when the tooltip opens or closes, including from hover and focus. */\n onOpenChange?: TooltipRootProps['onOpenChange'];\n /** Controlled open state. Leave unset to let hover and focus drive it. */\n open?: TooltipRootProps['open'];\n /** Delay in ms before an uncontrolled tooltip opens on hover. */\n openDelay?: TooltipRootProps['openDelay'];\n /** Where the tooltip sits relative to the trigger (default `top`). It flips if space is short. */\n placement?: NonNullable<TooltipRootProps['positioning']>['placement'];\n /** The tooltip's text. Plain string only — use `icon` for a glyph after it. */\n text: string;\n /**\n * Render the trigger inside a focusable wrapper instead of on the trigger itself. Only for triggers\n * that cannot take focus — on a focusable one this adds a second, redundant tab stop for the same\n * control. A disabled `<button>` dispatches no pointer events and is out of the tab order, so\n * without a wrapper the tooltip never opens — in the one state whose explanation the user actually\n * needs. For a disabled `BitkitButton`, `BitkitIconButton` or `BitkitPageSidebar.Item`, pass its\n * `disabledReason` instead: it stays focusable and announced as disabled, with no wrapper.\n *\n * Chakra v2's `Tooltip` had this built in as `shouldWrapChildren`, rendering a\n * `<span display=\"inline-block\" tabIndex={0}>` that carried the trigger props. Ark's tooltip has no\n * equivalent, and Chakra's own v2->v3 codemod replaces it with a bare `<span>` — which restores\n * hover but silently drops the tab stop, so the tooltip stays unreachable by keyboard. This prop is\n * that escape hatch, `tabIndex` included.\n *\n * The wrapper is a plain focusable span, so focusing it announces the trigger's label and the\n * tooltip text, not the trigger's own state — a disabled button inside is not re-announced as\n * disabled; that is what `disabledReason` fixes.\n */\n wrapTrigger?: boolean;\n};\n\n/**\n * A hover/focus tooltip anchored to its child: `text` carries the message and `icon` appends a\n * glyph after it. Text only — a tooltip closes when focus leaves its trigger and ignores touch, so a\n * link or a button inside one couldn't be reached. For those use `BitkitToggletip`, which looks the\n * same and opens on click.\n *\n * The content renders in a portal, so it escapes any ancestor that traps stacking (`isolation`,\n * `transform`, a `z-index`ed positioned box) or clips overflow. Dialogs turn that off through\n * `BitkitPortalContext`; `disablePortal` is the manual override.\n */\nconst BitkitTooltip = ({\n children,\n closeOnClick,\n disablePortal,\n disabled,\n icon: Icon,\n onOpenChange,\n open,\n openDelay,\n placement = 'top',\n text,\n wrapTrigger,\n}: BitkitTooltipProps) => {\n const { disablePortal: disablePortalFromContext } = useContext(BitkitPortalContext);\n\n // Anchor positioning to the trigger node by ref rather than relying on Zag's\n // id/data-scope lookup. When the trigger is also wrapped by another `asChild`\n // trigger (e.g. Menu.Trigger), the outer trigger's id and data-scope/data-part\n // overwrite ours on the shared node, so `getTriggerEl()` can't find it and the\n // tooltip loses its anchor. `getAnchorElement` takes precedence over the id\n // lookup, so this is safe in the standalone case too.\n const triggerRef = useRef<HTMLElement>(null);\n\n return (\n <Tooltip.Root\n closeOnClick={closeOnClick}\n disabled={disabled}\n onOpenChange={onOpenChange}\n open={open}\n openDelay={openDelay}\n positioning={{ getAnchorElement: () => triggerRef.current, placement, offset: { mainAxis: 4, crossAxis: 0 } }}\n >\n <Tooltip.Trigger ref={triggerRef as Ref<HTMLButtonElement>} asChild>\n {wrapTrigger || !isValidElement(children) ? (\n // inline-flex so the wrapper shrink-wraps the trigger: a plain inline span adds descender\n // space below it and shifts the alignment of whatever sits next to it.\n <Box\n as=\"span\"\n display=\"inline-flex\"\n tabIndex={0}\n css={{\n // The wrapper owns the tab stop, but the focus ring belongs on the trigger: an outline\n // follows the border-radius of the element it is drawn on, and the wrapper has none —\n // so leaving it here squares off a pill or a round trigger.\n _focusVisible: {\n outline: 'none',\n '& > *': {\n outlineColor: 'var(--focus-ring-color)',\n outlineOffset: 'var(--focus-ring-offset, 2px)',\n outlineStyle: 'var(--focus-ring-style, solid)',\n outlineWidth: 'var(--focus-ring-width, 2px)',\n },\n },\n }}\n >\n {children}\n </Box>\n ) : (\n children\n )}\n </Tooltip.Trigger>\n <Portal disabled={disablePortal || disablePortalFromContext}>\n <Tooltip.Positioner>\n <Tooltip.Content>\n <Tooltip.Arrow>\n <Tooltip.ArrowTip />\n </Tooltip.Arrow>\n <Box display=\"flex\" gap=\"8\">\n {text}\n {Icon && <Icon flexShrink=\"0\" size=\"16\" />}\n </Box>\n </Tooltip.Content>\n </Tooltip.Positioner>\n </Portal>\n </Tooltip.Root>\n );\n};\n\nBitkitTooltip.displayName = 'BitkitTooltip';\n\nexport default BitkitTooltip;\n"],"mappings":";;;;;;;;;;;;;;;;;AAqEA,IAAM,iBAAiB,EACrB,UACA,cACA,eACA,UACA,MAAM,MACN,cACA,MACA,WACA,YAAY,OACZ,MACA,kBACwB;CACxB,MAAM,EAAE,eAAe,6BAA6B,WAAW,mBAAmB;CAQlF,MAAM,aAAa,OAAoB,IAAI;CAE3C,OACE,qBAAC,QAAQ,MAAT;EACgB;EACJ;EACI;EACR;EACK;EACX,aAAa;GAAE,wBAAwB,WAAW;GAAS;GAAW,QAAQ;IAAE,UAAU;IAAG,WAAW;GAAE;EAAE;EAN9G,UAAA,CAQE,oBAAC,QAAQ,SAAT;GAAiB,KAAK;GAAsC,SAAA;GACzD,UAAA,eAAe,CAAC,eAAe,QAAQ,IAGtC,oBAAC,KAAD;IACE,IAAG;IACH,SAAQ;IACR,UAAU;IACV,KAAK,EAIH,eAAe;KACb,SAAS;KACT,SAAS;MACP,cAAc;MACd,eAAe;MACf,cAAc;MACd,cAAc;KAChB;IACF,EACF;IAEC;GACE,CAAA,IAEL;EAEa,CAAA,GACjB,oBAAC,QAAD;GAAQ,UAAU,iBAAiB;GACjC,UAAA,oBAAC,QAAQ,YAAT,EAAA,UACE,qBAAC,QAAQ,SAAT,EAAA,UAAA,CACE,oBAAC,QAAQ,OAAT,EAAA,UACE,oBAAC,QAAQ,UAAT,CAAmB,CAAA,EACN,CAAA,GACf,qBAAC,KAAD;IAAK,SAAQ;IAAO,KAAI;IAAxB,UAAA,CACG,MACA,QAAQ,oBAAC,MAAD;KAAM,YAAW;KAAI,MAAK;IAAM,CAAA,CACtC;GACU,CAAA,CAAA,EAAA,CAAA,EACC,CAAA;EACd,CAAA,CACI;;AAElB;AAEA,cAAc,cAAc"}
|
|
@@ -16,6 +16,7 @@ export { default as BitkitCollapsible, type BitkitCollapsibleProps } from './Bit
|
|
|
16
16
|
export { default as BitkitColorButton, type BitkitColorButtonProps } from './BitkitColorButton/BitkitColorButton';
|
|
17
17
|
export { default as BitkitCombobox, type BitkitComboboxProps } from './BitkitCombobox/BitkitCombobox';
|
|
18
18
|
export { type BitkitContentWidth, default as BitkitContentWrapper, type BitkitContentWrapperProps, } from './BitkitContentWrapper/BitkitContentWrapper';
|
|
19
|
+
export { type BitkitContentWrapperStickyBarProps } from './BitkitContentWrapper/BitkitContentWrapperStickyBar';
|
|
19
20
|
export { default as BitkitControlButton, type BitkitControlButtonProps, } from './BitkitControlButton/BitkitControlButton';
|
|
20
21
|
export { default as BitkitDataWidget, type BitkitDataWidgetProps } from './BitkitDataWidget/BitkitDataWidget';
|
|
21
22
|
export { default as BitkitDatePicker, type BitkitDatePickerProps } from './BitkitDatePicker/BitkitDatePicker';
|
package/dist/main.js
CHANGED
|
@@ -323,7 +323,7 @@ import BitkitLabel from "./components/BitkitLabel/BitkitLabel.js";
|
|
|
323
323
|
import BitkitCollapsible from "./components/BitkitCollapsible/BitkitCollapsible.js";
|
|
324
324
|
import BitkitField from "./components/BitkitField/BitkitField.js";
|
|
325
325
|
import BitkitCombobox_default from "./components/BitkitCombobox/BitkitCombobox.js";
|
|
326
|
-
import
|
|
326
|
+
import BitkitContentWrapper_default from "./components/BitkitContentWrapper/BitkitContentWrapper.js";
|
|
327
327
|
import BitkitDataWidget from "./components/BitkitDataWidget/BitkitDataWidget.js";
|
|
328
328
|
import BitkitDatePicker from "./components/BitkitDatePicker/BitkitDatePicker.js";
|
|
329
329
|
import BitkitToggletip from "./components/BitkitToggletip/BitkitToggletip.js";
|
|
@@ -399,4 +399,4 @@ import { uiSideNavRailWidth } from "./theme/slot-recipes/UISideNav.recipe.js";
|
|
|
399
399
|
import BitkitUISideNav_default from "./components/BitkitUISideNav/BitkitUISideNav.js";
|
|
400
400
|
import bitkitTheme from "./theme/index.js";
|
|
401
401
|
import Provider from "./providers/BitkitProvider.js";
|
|
402
|
-
export { BitbotLogoWithText, BitkitAccordion_default as BitkitAccordion, BitkitActionBar, BitkitActionMenu_default as BitkitActionMenu, BitkitAlert, BitkitAvatar, BitkitBadge, BitkitBreadcrumb, BitkitButton, BitkitCalendar, BitkitCheckbox, BitkitCheckboxGroup, BitkitCloseButton, BitkitCodeSnippet, BitkitCollapsible, BitkitColorButton, BitkitCombobox_default as BitkitCombobox, BitkitContentWrapper, BitkitControlButton, BitkitDataWidget, BitkitDatePicker, BitkitDefinitionTooltip, BitkitDialog_default as BitkitDialog, BitkitDraggableCard, BitkitDrawer, BitkitEmptyState, BitkitExpandableCard, BitkitField, BitkitFileInput, BitkitFilter_default as BitkitFilter, BitkitFormDialog_default as BitkitFormDialog, BitkitGroupHeading, BitkitHeading, BitkitIconButton, BitkitInlineLoading, BitkitLabel, BitkitLabelTooltip, BitkitLabeledData, BitkitLightbox, BitkitLink, BitkitLinkButton, BitkitList_default as BitkitList, BitkitMarkdown, BitkitMarkdownCard, BitkitMultiselect_default as BitkitMultiselect, BitkitMultiselectMenu, BitkitNativeSelect, BitkitNoteCard, BitkitNumberInput, BitkitOverflowContent, BitkitOverflowTooltip, BitkitPageFooter_default as BitkitPageFooter, BitkitPageHeader, BitkitPageSidebar_default as BitkitPageSidebar, BitkitPageSubheader, BitkitPagination, BitkitPaginationLoadMore, BitkitPopover, BitkitProgressBar, BitkitPromoBanner, Provider as BitkitProvider, BitkitRadio, BitkitRadioGroup, BitkitRibbon, BitkitSearchInput, BitkitSectionHeading, BitkitSegmentedControl_default as BitkitSegmentedControl, BitkitSelect_default as BitkitSelect, BitkitSelectMenu, BitkitSelectMenuAction, BitkitSelectableTag_default as BitkitSelectableTag, BitkitSettingsCard_default as BitkitSettingsCard, BitkitSkeletonGroup, BitkitSpinner, BitkitSplitButton_default as BitkitSplitButton, BitkitStat, BitkitSteps_default as BitkitSteps, BitkitStepsCard_default as BitkitStepsCard, BitkitStepsDialog_default as BitkitStepsDialog, BitkitSwitch, BitkitTable, BitkitTableCard, BitkitTabs, BitkitTag, BitkitTagsInput, BitkitTextArea, BitkitTextInput, BitkitToggleButton, BitkitToggletip, BitkitTooltip, BitkitTour, BitkitTreeView, BitkitUIHeader_default as BitkitUIHeader, BitkitUISideNav_default as BitkitUISideNav, IconAbortCircle, IconAbortCircleFilled, IconAddons, IconAgent, IconAnchor, IconAndroid, IconApp, IconAppSettings, IconAppStore, IconAppStoreColor, IconApple, IconArchive, IconArchiveDelete, IconArchiveRestore, IconArrowBackAndDown, IconArrowBackAndUp, IconArrowDown, IconArrowForwardAndDown, IconArrowForwardAndUp, IconArrowLeft, IconArrowNortheast, IconArrowNorthwest, IconArrowRight, IconArrowUp, IconArrowsHorizontal, IconArrowsVertical, IconAutomation, IconAws, IconAwsColor, IconBadge3RdParty, IconBadgeBitrise, IconBadgeUpgrade, IconBadgeVersionOk, IconBazel, IconBell, IconBitbot, IconBitbotError, IconBitbotIntercomWhite, IconBitbucket, IconBitbucketColor, IconBitbucketNeutral, IconBitbucketWhite, IconBlockCircle, IconBook, IconBoxArrowDown, IconBoxDot, IconBoxLinesOverflow, IconBoxLinesWrap, IconBranch, IconBrowserstackColor, IconBug, IconBuild, IconBuildCache, IconBuildCacheFilled, IconBuildEnvSetup, IconBuildHub, IconBuildHubFilled, IconCalendar, IconChangePlan, IconChat, IconCheck, IconCheckCircle, IconCheckCircleFilled, IconChevronDown, IconChevronLeft, IconChevronRight, IconChevronUp, IconCi, IconCiFilled, IconCircle, IconCircleDashed, IconCircleHalfFilled, IconClaude, IconClaudeColor, IconClock, IconCode, IconCodePush, IconCodeSigning, IconCoffee, IconCommit, IconConfigure, IconConnectedAccounts, IconContainer, IconCopilot, IconCopy, IconCordova, IconCpu, IconCreditcard, IconCredits, IconCross, IconCrossCircle, IconCrossCircleFilled, IconCrown, IconCursor, IconCycle, IconDashboard, IconDashboardFilled, IconDeployment, IconDetails, IconDoc, IconDollar, IconDot, IconDotnet, IconDotnetColor, IconDotnetText, IconDotnetTextColor, IconDoubleCircle, IconDownload, IconDragHandle, IconEc2Ami, IconEnterprise, IconErrorCircle, IconErrorCircleFilled, IconExpand, IconExtraBuildCapacity, IconEye, IconEyeSlash, IconFastlane, IconFile, IconFileDoc, IconFilePdf, IconFilePlist, IconFileYml, IconFileZip, IconFilter, IconFlag, IconFlutter, IconFolder, IconFullscreen, IconFullscreenExit, IconGauge, IconGit, IconGithub, IconGitlab, IconGitlabColor, IconGitlabWhite, IconGlobe, IconGo, IconGoogleColor, IconGooglePlay, IconGooglePlayColor, IconGradle, IconGroup, IconHashtag, IconHeadset, IconHeart, IconHistory, IconHourglass, IconImage, IconInfoCircle, IconInfoCircleFilled, IconInsights, IconInsightsFilled, IconInstall, IconInteraction, IconInvoice, IconIonic, IconJapanese, IconJava, IconJavaColor, IconJavaDuke, IconJavaDukeColor, IconKey, IconKiroColor, IconKotlin, IconKotlinColor, IconKotlinWhite, IconLaptop, IconLaunchdarkly, IconLegacyApp, IconLightbulb, IconLink, IconLinux, IconLock, IconLockOpen, IconLogin, IconLogout, IconMacos, IconMagicWand, IconMagnifier, IconMail, IconMcp, IconMedal, IconMemory, IconMenuGrid, IconMenuHamburger, IconMessage, IconMessageAlert, IconMessageQuestion, IconMicrophone, IconMinus, IconMinusCircle, IconMinusCircleFilled, IconMobile, IconMobileLandscape, IconModeDark, IconModeLight, IconModeSystem, IconMonitorChart, IconMoreHorizontal, IconMoreVertical, IconNews, IconNextjs, IconNodejs, IconOpenInNew, IconOther, IconOutsideContributor, IconOverview, IconPause, IconPencil, IconPeople, IconPercent, IconPerson, IconPersonWithDesk, IconPin, IconPlay, IconPlus, IconPlusCircle, IconPlusCircleFilled, IconPower, IconProject, IconProjectSettings, IconPull, IconPush, IconPuzzle, IconPython, IconPythonColor, IconQuestionCircle, IconQuestionCircleFilled, IconReact, IconRefresh, IconRegex, IconRelease, IconReleaseFilled, IconRemoteAccess, IconReplace, IconResponsiveness, IconReviewerApproved, IconReviewerAssigned, IconReviewerRejected, IconRuby, IconRubyColor, IconSave, IconSecurityShield, IconSettings, IconSettingsFilled, IconShuffle, IconSiren, IconSkip, IconSkipCircle, IconSkipCircleFilled, IconSlack, IconSlackColor, IconSparkle, IconSparkleFilled, IconSpinnerOnDisabled, IconSpinnerPurple, IconSpinnerPurpleDouble, IconSpinnerWhite, IconStability, IconStack, IconStar, IconStep, IconStop, IconStopwatch, IconTabPlus, IconTag, IconTasks, IconTeams, IconTeamsColor, IconTemplateCode, IconTerminal, IconTerminalFilled, IconTestQuarantine, IconThemeDarkToggle, IconThumbDown, IconThumbUp, IconTools, IconTrash, IconTrigger, IconUbuntu, IconUbuntuColor, IconUnity3D, IconUnpin, IconUpload, IconValidateShield, IconVideo, IconVsCode, IconWarning, IconWarningYellow, IconWebUi, IconWebhooks, IconWindsurf, IconWorkflow, IconWorkflowFlow, IconXTwitter, IconXamarin, IconXcode, ResponsiveProvider, bitkitIcon, bitkitTheme as bitriseTheme, createBitkitToast, createTreeCollection, dismissBitkitToast, rem, uiHeaderHeight, uiHeaderHeightPx, uiSideNavRailWidth, useBitkitTour, useResponsive, useStepsDialog, useUISideNav };
|
|
402
|
+
export { BitbotLogoWithText, BitkitAccordion_default as BitkitAccordion, BitkitActionBar, BitkitActionMenu_default as BitkitActionMenu, BitkitAlert, BitkitAvatar, BitkitBadge, BitkitBreadcrumb, BitkitButton, BitkitCalendar, BitkitCheckbox, BitkitCheckboxGroup, BitkitCloseButton, BitkitCodeSnippet, BitkitCollapsible, BitkitColorButton, BitkitCombobox_default as BitkitCombobox, BitkitContentWrapper_default as BitkitContentWrapper, BitkitControlButton, BitkitDataWidget, BitkitDatePicker, BitkitDefinitionTooltip, BitkitDialog_default as BitkitDialog, BitkitDraggableCard, BitkitDrawer, BitkitEmptyState, BitkitExpandableCard, BitkitField, BitkitFileInput, BitkitFilter_default as BitkitFilter, BitkitFormDialog_default as BitkitFormDialog, BitkitGroupHeading, BitkitHeading, BitkitIconButton, BitkitInlineLoading, BitkitLabel, BitkitLabelTooltip, BitkitLabeledData, BitkitLightbox, BitkitLink, BitkitLinkButton, BitkitList_default as BitkitList, BitkitMarkdown, BitkitMarkdownCard, BitkitMultiselect_default as BitkitMultiselect, BitkitMultiselectMenu, BitkitNativeSelect, BitkitNoteCard, BitkitNumberInput, BitkitOverflowContent, BitkitOverflowTooltip, BitkitPageFooter_default as BitkitPageFooter, BitkitPageHeader, BitkitPageSidebar_default as BitkitPageSidebar, BitkitPageSubheader, BitkitPagination, BitkitPaginationLoadMore, BitkitPopover, BitkitProgressBar, BitkitPromoBanner, Provider as BitkitProvider, BitkitRadio, BitkitRadioGroup, BitkitRibbon, BitkitSearchInput, BitkitSectionHeading, BitkitSegmentedControl_default as BitkitSegmentedControl, BitkitSelect_default as BitkitSelect, BitkitSelectMenu, BitkitSelectMenuAction, BitkitSelectableTag_default as BitkitSelectableTag, BitkitSettingsCard_default as BitkitSettingsCard, BitkitSkeletonGroup, BitkitSpinner, BitkitSplitButton_default as BitkitSplitButton, BitkitStat, BitkitSteps_default as BitkitSteps, BitkitStepsCard_default as BitkitStepsCard, BitkitStepsDialog_default as BitkitStepsDialog, BitkitSwitch, BitkitTable, BitkitTableCard, BitkitTabs, BitkitTag, BitkitTagsInput, BitkitTextArea, BitkitTextInput, BitkitToggleButton, BitkitToggletip, BitkitTooltip, BitkitTour, BitkitTreeView, BitkitUIHeader_default as BitkitUIHeader, BitkitUISideNav_default as BitkitUISideNav, IconAbortCircle, IconAbortCircleFilled, IconAddons, IconAgent, IconAnchor, IconAndroid, IconApp, IconAppSettings, IconAppStore, IconAppStoreColor, IconApple, IconArchive, IconArchiveDelete, IconArchiveRestore, IconArrowBackAndDown, IconArrowBackAndUp, IconArrowDown, IconArrowForwardAndDown, IconArrowForwardAndUp, IconArrowLeft, IconArrowNortheast, IconArrowNorthwest, IconArrowRight, IconArrowUp, IconArrowsHorizontal, IconArrowsVertical, IconAutomation, IconAws, IconAwsColor, IconBadge3RdParty, IconBadgeBitrise, IconBadgeUpgrade, IconBadgeVersionOk, IconBazel, IconBell, IconBitbot, IconBitbotError, IconBitbotIntercomWhite, IconBitbucket, IconBitbucketColor, IconBitbucketNeutral, IconBitbucketWhite, IconBlockCircle, IconBook, IconBoxArrowDown, IconBoxDot, IconBoxLinesOverflow, IconBoxLinesWrap, IconBranch, IconBrowserstackColor, IconBug, IconBuild, IconBuildCache, IconBuildCacheFilled, IconBuildEnvSetup, IconBuildHub, IconBuildHubFilled, IconCalendar, IconChangePlan, IconChat, IconCheck, IconCheckCircle, IconCheckCircleFilled, IconChevronDown, IconChevronLeft, IconChevronRight, IconChevronUp, IconCi, IconCiFilled, IconCircle, IconCircleDashed, IconCircleHalfFilled, IconClaude, IconClaudeColor, IconClock, IconCode, IconCodePush, IconCodeSigning, IconCoffee, IconCommit, IconConfigure, IconConnectedAccounts, IconContainer, IconCopilot, IconCopy, IconCordova, IconCpu, IconCreditcard, IconCredits, IconCross, IconCrossCircle, IconCrossCircleFilled, IconCrown, IconCursor, IconCycle, IconDashboard, IconDashboardFilled, IconDeployment, IconDetails, IconDoc, IconDollar, IconDot, IconDotnet, IconDotnetColor, IconDotnetText, IconDotnetTextColor, IconDoubleCircle, IconDownload, IconDragHandle, IconEc2Ami, IconEnterprise, IconErrorCircle, IconErrorCircleFilled, IconExpand, IconExtraBuildCapacity, IconEye, IconEyeSlash, IconFastlane, IconFile, IconFileDoc, IconFilePdf, IconFilePlist, IconFileYml, IconFileZip, IconFilter, IconFlag, IconFlutter, IconFolder, IconFullscreen, IconFullscreenExit, IconGauge, IconGit, IconGithub, IconGitlab, IconGitlabColor, IconGitlabWhite, IconGlobe, IconGo, IconGoogleColor, IconGooglePlay, IconGooglePlayColor, IconGradle, IconGroup, IconHashtag, IconHeadset, IconHeart, IconHistory, IconHourglass, IconImage, IconInfoCircle, IconInfoCircleFilled, IconInsights, IconInsightsFilled, IconInstall, IconInteraction, IconInvoice, IconIonic, IconJapanese, IconJava, IconJavaColor, IconJavaDuke, IconJavaDukeColor, IconKey, IconKiroColor, IconKotlin, IconKotlinColor, IconKotlinWhite, IconLaptop, IconLaunchdarkly, IconLegacyApp, IconLightbulb, IconLink, IconLinux, IconLock, IconLockOpen, IconLogin, IconLogout, IconMacos, IconMagicWand, IconMagnifier, IconMail, IconMcp, IconMedal, IconMemory, IconMenuGrid, IconMenuHamburger, IconMessage, IconMessageAlert, IconMessageQuestion, IconMicrophone, IconMinus, IconMinusCircle, IconMinusCircleFilled, IconMobile, IconMobileLandscape, IconModeDark, IconModeLight, IconModeSystem, IconMonitorChart, IconMoreHorizontal, IconMoreVertical, IconNews, IconNextjs, IconNodejs, IconOpenInNew, IconOther, IconOutsideContributor, IconOverview, IconPause, IconPencil, IconPeople, IconPercent, IconPerson, IconPersonWithDesk, IconPin, IconPlay, IconPlus, IconPlusCircle, IconPlusCircleFilled, IconPower, IconProject, IconProjectSettings, IconPull, IconPush, IconPuzzle, IconPython, IconPythonColor, IconQuestionCircle, IconQuestionCircleFilled, IconReact, IconRefresh, IconRegex, IconRelease, IconReleaseFilled, IconRemoteAccess, IconReplace, IconResponsiveness, IconReviewerApproved, IconReviewerAssigned, IconReviewerRejected, IconRuby, IconRubyColor, IconSave, IconSecurityShield, IconSettings, IconSettingsFilled, IconShuffle, IconSiren, IconSkip, IconSkipCircle, IconSkipCircleFilled, IconSlack, IconSlackColor, IconSparkle, IconSparkleFilled, IconSpinnerOnDisabled, IconSpinnerPurple, IconSpinnerPurpleDouble, IconSpinnerWhite, IconStability, IconStack, IconStar, IconStep, IconStop, IconStopwatch, IconTabPlus, IconTag, IconTasks, IconTeams, IconTeamsColor, IconTemplateCode, IconTerminal, IconTerminalFilled, IconTestQuarantine, IconThemeDarkToggle, IconThumbDown, IconThumbUp, IconTools, IconTrash, IconTrigger, IconUbuntu, IconUbuntuColor, IconUnity3D, IconUnpin, IconUpload, IconValidateShield, IconVideo, IconVsCode, IconWarning, IconWarningYellow, IconWebUi, IconWebhooks, IconWindsurf, IconWorkflow, IconWorkflowFlow, IconXTwitter, IconXamarin, IconXcode, ResponsiveProvider, bitkitIcon, bitkitTheme as bitriseTheme, createBitkitToast, createTreeCollection, dismissBitkitToast, rem, uiHeaderHeight, uiHeaderHeightPx, uiSideNavRailWidth, useBitkitTour, useResponsive, useStepsDialog, useUISideNav };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** The page content widths, padding included: a `layout/maxWidth` token, `full` for no cap. */
|
|
2
|
-
export declare const contentWidths: readonly ["layout/maxWidth/640", "layout/maxWidth/960", "layout/maxWidth/1280", "layout/maxWidth/1616", "layout/maxWidth/full"];
|
|
2
|
+
export declare const contentWidths: readonly ["layout/maxWidth/480", "layout/maxWidth/640", "layout/maxWidth/960", "layout/maxWidth/1280", "layout/maxWidth/1616", "layout/maxWidth/full"];
|
|
3
3
|
export type ContentWidth = (typeof contentWidths)[number];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
declare const contentWrapperStickyBarRecipe: import('@chakra-ui/react').RecipeDefinition<{
|
|
2
|
+
colorVariant: {
|
|
3
|
+
gray: {
|
|
4
|
+
background: "background/secondary";
|
|
5
|
+
};
|
|
6
|
+
white: {
|
|
7
|
+
background: "background/primary";
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
isSticky: {
|
|
11
|
+
false: {};
|
|
12
|
+
true: {
|
|
13
|
+
boxShadow: {
|
|
14
|
+
tablet: "elevation/sm";
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
}>;
|
|
19
|
+
export default contentWrapperStickyBarRecipe;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { defineRecipe } from "@chakra-ui/react/styled-system";
|
|
2
|
+
//#region lib/theme/recipes/ContentWrapperStickyBar.recipe.ts
|
|
3
|
+
var contentWrapperStickyBarRecipe = defineRecipe({
|
|
4
|
+
className: "content-wrapper-sticky-bar",
|
|
5
|
+
base: {
|
|
6
|
+
marginBlock: "-16",
|
|
7
|
+
paddingBlock: "16",
|
|
8
|
+
position: {
|
|
9
|
+
base: "static",
|
|
10
|
+
tablet: "sticky"
|
|
11
|
+
},
|
|
12
|
+
zIndex: 1
|
|
13
|
+
},
|
|
14
|
+
variants: {
|
|
15
|
+
colorVariant: {
|
|
16
|
+
gray: { background: "background/secondary" },
|
|
17
|
+
white: { background: "background/primary" }
|
|
18
|
+
},
|
|
19
|
+
isSticky: {
|
|
20
|
+
false: {},
|
|
21
|
+
true: { boxShadow: { tablet: "elevation/sm" } }
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
defaultVariants: {
|
|
25
|
+
colorVariant: "gray",
|
|
26
|
+
isSticky: false
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
//#endregion
|
|
30
|
+
export { contentWrapperStickyBarRecipe as default };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=ContentWrapperStickyBar.recipe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContentWrapperStickyBar.recipe.js","names":[],"sources":["../../../lib/theme/recipes/ContentWrapperStickyBar.recipe.ts"],"sourcesContent":["import { defineRecipe } from '@chakra-ui/react/styled-system';\n\nconst contentWrapperStickyBarRecipe = defineRecipe({\n className: 'content-wrapper-sticky-bar',\n base: {\n // The padding keeps room around the content once the bar sticks; the negative margins take it back,\n // so in place the bar sits on the wrapper's own padding and row gap, nothing added.\n marginBlock: '-16',\n paddingBlock: '16',\n position: { base: 'static', tablet: 'sticky' },\n zIndex: 1,\n },\n variants: {\n colorVariant: {\n gray: { background: 'background/secondary' },\n white: { background: 'background/primary' },\n },\n isSticky: {\n false: {},\n true: { boxShadow: { tablet: 'elevation/sm' } },\n },\n },\n defaultVariants: {\n colorVariant: 'gray',\n isSticky: false,\n },\n});\n\nexport default contentWrapperStickyBarRecipe;\n"],"mappings":";;AAEA,IAAM,gCAAgC,aAAa;CACjD,WAAW;CACX,MAAM;EAGJ,aAAa;EACb,cAAc;EACd,UAAU;GAAE,MAAM;GAAU,QAAQ;EAAS;EAC7C,QAAQ;CACV;CACA,UAAU;EACR,cAAc;GACZ,MAAM,EAAE,YAAY,uBAAuB;GAC3C,OAAO,EAAE,YAAY,qBAAqB;EAC5C;EACA,UAAU;GACR,OAAO,CAAC;GACR,MAAM,EAAE,WAAW,EAAE,QAAQ,eAAe,EAAE;EAChD;CACF;CACA,iBAAiB;EACf,cAAc;EACd,UAAU;CACZ;AACF,CAAC"}
|
|
@@ -5,6 +5,7 @@ import badgeRecipe from "./Badge.recipe.js";
|
|
|
5
5
|
import buttonRecipe from "./Button.recipe.js";
|
|
6
6
|
import closeButtonRecipe from "./CloseButton.recipe.js";
|
|
7
7
|
import contentWrapperRecipe from "./ContentWrapper.recipe.js";
|
|
8
|
+
import contentWrapperStickyBarRecipe from "./ContentWrapperStickyBar.recipe.js";
|
|
8
9
|
import controlButtonRecipe from "./ControlButton.recipe.js";
|
|
9
10
|
import definitionTooltipRecipe from "./DefinitionTooltip.recipe.js";
|
|
10
11
|
import iconRecipe from "./Icon.recipe.js";
|
|
@@ -25,6 +26,7 @@ var recipes = {
|
|
|
25
26
|
controlButton: controlButtonRecipe,
|
|
26
27
|
colorButton: colorButtonRecipe,
|
|
27
28
|
contentWrapper: contentWrapperRecipe,
|
|
29
|
+
contentWrapperStickyBar: contentWrapperStickyBarRecipe,
|
|
28
30
|
definitionTooltip: definitionTooltipRecipe,
|
|
29
31
|
icon: iconRecipe,
|
|
30
32
|
input: inputRecipe,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../lib/theme/recipes/index.ts"],"sourcesContent":["import badgeRecipe from './Badge.recipe';\nimport buttonRecipe from './Button.recipe';\nimport closeButtonRecipe from './CloseButton.recipe';\nimport colorButtonRecipe from './ColorButton.recipe';\nimport contentWrapperRecipe from './ContentWrapper.recipe';\nimport controlButtonRecipe from './ControlButton.recipe';\nimport definitionTooltipRecipe from './DefinitionTooltip.recipe';\nimport iconRecipe from './Icon.recipe';\nimport inputRecipe from './Input.recipe';\nimport inputAddonRecipe from './InputAddon.recipe';\nimport linkRecipe from './Link.recipe';\nimport linkButtonRecipe from './LinkButton.recipe';\nimport selectableTagRecipe from './SelectableTag.recipe';\nimport separatorRecipe from './Separator.recipe';\nimport skeletonRecipe from './Skeleton.recipe';\nimport spinnerRecipe from './Spinner.recipe';\nimport textareaRecipe from './Textarea.recipe';\nimport toggleButtonRecipe from './ToggleButton.recipe';\nimport uiHeaderButtonRecipe from './UIHeaderButton.recipe';\n\nconst recipes = {\n badge: badgeRecipe,\n button: buttonRecipe,\n closeButton: closeButtonRecipe,\n controlButton: controlButtonRecipe,\n colorButton: colorButtonRecipe,\n contentWrapper: contentWrapperRecipe,\n definitionTooltip: definitionTooltipRecipe,\n icon: iconRecipe,\n input: inputRecipe,\n inputAddon: inputAddonRecipe,\n link: linkRecipe,\n linkButton: linkButtonRecipe,\n selectableTag: selectableTagRecipe,\n separator: separatorRecipe,\n skeleton: skeletonRecipe,\n spinner: spinnerRecipe,\n textarea: textareaRecipe,\n toggleButton: toggleButtonRecipe,\n uiHeaderButton: uiHeaderButtonRecipe,\n};\n\nexport default recipes;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../lib/theme/recipes/index.ts"],"sourcesContent":["import badgeRecipe from './Badge.recipe';\nimport buttonRecipe from './Button.recipe';\nimport closeButtonRecipe from './CloseButton.recipe';\nimport colorButtonRecipe from './ColorButton.recipe';\nimport contentWrapperRecipe from './ContentWrapper.recipe';\nimport contentWrapperStickyBarRecipe from './ContentWrapperStickyBar.recipe';\nimport controlButtonRecipe from './ControlButton.recipe';\nimport definitionTooltipRecipe from './DefinitionTooltip.recipe';\nimport iconRecipe from './Icon.recipe';\nimport inputRecipe from './Input.recipe';\nimport inputAddonRecipe from './InputAddon.recipe';\nimport linkRecipe from './Link.recipe';\nimport linkButtonRecipe from './LinkButton.recipe';\nimport selectableTagRecipe from './SelectableTag.recipe';\nimport separatorRecipe from './Separator.recipe';\nimport skeletonRecipe from './Skeleton.recipe';\nimport spinnerRecipe from './Spinner.recipe';\nimport textareaRecipe from './Textarea.recipe';\nimport toggleButtonRecipe from './ToggleButton.recipe';\nimport uiHeaderButtonRecipe from './UIHeaderButton.recipe';\n\nconst recipes = {\n badge: badgeRecipe,\n button: buttonRecipe,\n closeButton: closeButtonRecipe,\n controlButton: controlButtonRecipe,\n colorButton: colorButtonRecipe,\n contentWrapper: contentWrapperRecipe,\n contentWrapperStickyBar: contentWrapperStickyBarRecipe,\n definitionTooltip: definitionTooltipRecipe,\n icon: iconRecipe,\n input: inputRecipe,\n inputAddon: inputAddonRecipe,\n link: linkRecipe,\n linkButton: linkButtonRecipe,\n selectableTag: selectableTagRecipe,\n separator: separatorRecipe,\n skeleton: skeletonRecipe,\n spinner: spinnerRecipe,\n textarea: textareaRecipe,\n toggleButton: toggleButtonRecipe,\n uiHeaderButton: uiHeaderButtonRecipe,\n};\n\nexport default recipes;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,IAAM,UAAU;CACd,OAAO;CACP,QAAQ;CACR,aAAa;CACb,eAAe;CACf,aAAa;CACb,gBAAgB;CAChB,yBAAyB;CACzB,mBAAmB;CACnB,MAAM;CACN,OAAO;CACP,YAAY;CACZ,MAAM;CACN,YAAY;CACZ,eAAe;CACf,WAAW;CACX,UAAU;CACV,SAAS;CACT,UAAU;CACV,cAAc;CACd,gBAAgB;AAClB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageHeader.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/PageHeader.recipe.ts"],"sourcesContent":["import { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { rem } from '../themeUtils';\n\n/**\n * The collapsed single-row layout, shared by `variant=\"minimal\"` and `isSticky`. Both apply the\n * exact same overrides, so the two variants are idempotent when combined. The expanded layout\n * lives in `base` — `variant=\"default\"` and `isSticky: false` deliberately define nothing, so\n * neither can undo the other's collapse.\n *\n * Every override is scoped to `tablet` and up, with no `base` key: below the breakpoint the `base`\n * styles win and the header stays expanded. The mobile Figma frame has no sticky or minimal\n * variant — it always shows the title as a heading — and a single 72px row cannot hold a\n * breadcrumb plus full-width actions at 375px.\n *\n * The slots the collapsed row drops are hidden here rather than omitted from the DOM, so the\n * component never has to know the viewport: no breakpoint hook, and no wrong-layout first paint.\n */\nconst collapsedSlots = {\n headerBlock: {\n tablet: {\n alignItems: 'center',\n flexDirection: 'row',\n gap: '24',\n // No 72 in the size scale — the design fixes the collapsed row height.\n minHeight: rem(72),\n paddingBlockEnd: '12',\n paddingBlockStart: '12',\n paddingInlineEnd: '32',\n paddingInlineStart: '24',\n },\n },\n breadcrumb: {\n tablet: {\n flex: '0 1 auto',\n minWidth: 0,\n },\n },\n contentBlock: {\n tablet: {\n alignItems: 'center',\n flex: '1 0 0',\n // 24 between the title and the actions, per `pageType=main, isSticky=true`. The 8 belongs to\n // `actionBlock`, between the buttons.\n gap: '24',\n justifyContent: 'flex-end',\n minWidth: 0,\n },\n },\n titleBlock: {\n tablet: {\n alignItems: 'center',\n },\n },\n title: {\n tablet: {\n textStyle: 'heading/h3',\n },\n },\n actionBlock: {\n tablet: {\n alignItems: 'center',\n flexDirection: 'row',\n gap: '8',\n width: 'auto',\n },\n },\n avatar: {\n tablet: { display: 'none' },\n },\n badge: {\n tablet: { display: 'none' },\n },\n secondaryText: {\n tablet: { display: 'none' },\n },\n tabs: {\n tablet: { display: 'none' },\n },\n} as const;\n\n/**\n * Collapsed *and* carrying a breadcrumb: the trail shows the title as its current item, so the\n * heading would duplicate it. `Breadcrumb.CurrentLink` is a link and not a heading, so the block is\n * made screen-reader-only instead of hidden — that keeps exactly one `h1` on the page at every\n * width without a second, conditionally rendered heading node.\n */\nconst titleInBreadcrumb = {\n titleBlock: { tablet: { srOnly: true } },\n // The row is trail + actions. The actions cannot shrink, so leaving `contentBlock` on a zero\n // basis let a long trail take the whole row and collapse it to width 0 — the buttons then\n // overflowed their own box and painted on top of the trail. Sizing the actions to their content\n // and letting the trail take what is left makes the trail yield, and its last crumb ellipsise.\n breadcrumb: { tablet: { flex: '1 1 auto' } },\n // `width: auto` matters as much as the flex here, for the same reason it does in `controlsRow`:\n // the base width is `100%`, which flex-basis `auto` resolves to, so without it this block claims\n // the whole row and squeezes the trail to nothing.\n contentBlock: { tablet: { flex: '0 0 auto', width: 'auto' } },\n} as const;\n\n/**\n * `minimal` *with* inline controls: the row carries three groups — trail, controls, actions — spread\n * apart rather than the usual trail-left/actions-right pair. `contentBlock` gives up its `flex: 1`\n * so `space-between` has room to distribute; without that it would absorb the free space and pin\n * the controls against the actions.\n *\n * Paired with both collapse modes, since `minimal` and `isSticky` produce the same row through\n * `collapsedSlots` — pairing it with `minimal` alone left the sticky row dropping the middle group.\n * This is the row the design file calls `PageHeader-WFE`.\n */\nconst controlsRow = {\n headerBlock: { tablet: { justifyContent: 'space-between' } },\n // Undoes the `flex: 1 1 auto` that `titleInBreadcrumb` gives the trail. That growth is right for\n // the two-group row (trail + actions), but here a third group sits between them: a growing trail\n // swallows all the free space on its side and shoves the controls island against the actions.\n // Shrink-only keeps the trail ellipsising when the row is tight, while `space-between` gets free\n // space to distribute.\n breadcrumb: { tablet: { flex: '0 1 auto' } },\n // `width: auto` matters as much as the flex: the base width is `100%`, which flex-basis `auto`\n // resolves to, so the block would otherwise claim the whole row and shrink the trail until its\n // metadata truncated away. Sized to its actions instead, leaving the free space to distribute.\n contentBlock: { tablet: { flex: '0 0 auto', width: 'auto' } },\n} as const;\n\n/**\n * Collapsed with inline controls but no trail: the title takes the left slot, so the three groups\n * are the title, the controls and the actions — all inside `contentBlock`, which already spans the\n * row. The title block gives up its `flex: 1` so `space-between` has free space to distribute; left\n * growing, it would absorb the row and shove the controls against the actions.\n */\nconst controlsWithoutTrail = {\n contentBlock: { tablet: { justifyContent: 'space-between' } },\n titleBlock: { tablet: { flex: '0 1 auto' } },\n} as const;\n\n/**\n * `alignsToContent`'s 32, restated for the collapsed row. The collapsed slots set the header block's\n * start padding under the same `tablet` key, and the variant applied later wins the merge -- which\n * is the collapsed one, since `isSticky` and `variant` come after `alignsToContent`. A compound\n * variant is applied after every plain one, so this holds whatever order the props arrive in.\n */\nconst contentAlignedCollapsed = {\n headerBlock: { tablet: { paddingInlineStart: '32' } },\n} as const;\n\n/**\n * Shared by the `app` and `user` content shapes — a larger avatar centred against a smaller title\n * and 14px secondary text. The two differ only in the avatar-to-text gap.\n */\nconst entityContent = {\n titleBlock: {\n alignItems: 'center',\n },\n title: {\n textStyle: { base: 'heading/mobile/h2', tablet: 'heading/h2' },\n },\n secondaryText: {\n textStyle: 'body/md/regular',\n },\n} as const;\n\nconst pageHeaderSlotRecipe = defineSlotRecipe({\n className: 'page-header',\n slots: [\n 'root',\n 'headerBlock',\n 'breadcrumb',\n 'controls',\n 'contentBlock',\n 'titleBar',\n 'titleBlock',\n 'avatar',\n 'textBlock',\n 'titleRow',\n 'title',\n 'badge',\n 'secondaryText',\n 'actionBlock',\n 'menuButton',\n 'sectionBlock',\n 'sectionTitle',\n 'tabs',\n ] as const,\n base: {\n root: {\n background: 'background/primary',\n borderBlockEnd: '1px solid',\n borderColor: 'border/regular',\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n },\n headerBlock: {\n alignItems: 'flex-start',\n display: 'flex',\n flexDirection: 'column',\n gap: { base: '16', tablet: '24' },\n paddingBlockEnd: { base: '16', tablet: '24' },\n paddingBlockStart: { base: '16', tablet: '24' },\n paddingInlineEnd: { base: '16', tablet: '32' },\n paddingInlineStart: { base: '16', tablet: '24' },\n width: '100%',\n },\n breadcrumb: {\n display: 'flex',\n maxWidth: '100%',\n minWidth: 0,\n // The trail's list is `white-space: nowrap`, so without this a long one escapes the header's\n // right edge instead of being clipped by it. `BitkitBreadcrumb` ellipsises its last crumb on\n // its own, but only once it is allowed to shrink — see the `breadcrumb` prop docs.\n overflow: 'hidden',\n },\n controls: {\n alignItems: 'center',\n display: 'flex',\n flexShrink: 0,\n },\n contentBlock: {\n alignItems: { base: 'flex-start', tablet: 'flex-end' },\n display: 'flex',\n flexDirection: { base: 'column', tablet: 'row' },\n gap: { base: '16', tablet: '32' },\n width: '100%',\n },\n // The title block and the menu button, which `hasSidebar` wraps them in. It stands in for the\n // title block in the content row from `tablet`, where the button is gone.\n // `contents` from `tablet`: the wrapper drops out of the layout there, so the title block is a\n // direct child of the content row again and every desktop rule — collapsed, controls, trail —\n // keeps targeting it as before.\n titleBar: {\n alignItems: 'center',\n display: { base: 'flex', tablet: 'contents' },\n gap: '12',\n minWidth: 0,\n width: '100%',\n },\n titleBlock: {\n // Full row width below `tablet`, where the content block is a column aligned to the start; sized to\n // its content, a long title or subtitle pushed the header past the page edge.\n alignSelf: { base: 'stretch', tablet: 'auto' },\n display: 'flex',\n flex: '1 0 0',\n minWidth: 0,\n },\n avatar: {\n display: 'flex',\n flexShrink: 0,\n },\n textBlock: {\n display: 'flex',\n flexDirection: 'column',\n minWidth: 0,\n },\n titleRow: {\n alignItems: 'center',\n display: 'flex',\n gap: '12',\n minWidth: 0,\n paddingInlineEnd: { base: '0', tablet: '24' },\n },\n title: {\n color: 'text/primary',\n minWidth: 0,\n textStyle: { base: 'heading/mobile/h1', tablet: 'heading/h1' },\n // One line with an ellipsis rather than wrapping. A wrapped title grew the header without\n // limit, and the collapsed row is a fixed 72px that a second line would break. The component\n // pairs this with `BitkitOverflowTooltip` so the full string stays readable.\n truncate: true,\n },\n badge: {\n display: 'flex',\n flexShrink: 0,\n // The design nudges the badge below the optical centre of the title line, wrapping it in\n // `flex-col h-full justify-center pt-8`. Reproduced with the same mechanism rather than a\n // fixed offset: the row centres the margin box, so this lands the badge `8 / 2` lower —\n // 12px down a 40px desktop line and 10px down a 36px mobile one, matching both frames.\n marginBlockStart: '8',\n },\n secondaryText: {\n color: 'text/secondary',\n textStyle: 'body/lg/regular',\n truncate: true,\n },\n actionBlock: {\n // The design puts the primary action on top once the actions stack, so `base` reverses them\n // visually while the DOM keeps its secondary-then-primary order for the row layout.\n //\n // That mismatch is deliberate and settled — please don't \"fix\" it. Actions arrive as an opaque\n // `children` list, so with one DOM order and two visual orders, no arrangement satisfies both\n // breakpoints; flipping the DOM only moves the mismatch to the row. The alternatives are a\n // design change or a structured actions API, and neither earns its cost: the surviving case is\n // a zoomed desktop window rendering `base`, where focus steps up rather than down between two\n // adjacent buttons and nothing becomes unreachable. Chasing visual order through the DOM is\n // also a pattern the design system avoids. v1 ships the same behaviour in `SubHeader.tsx:96`.\n alignItems: { base: 'stretch', tablet: 'flex-end' },\n display: 'flex',\n flexDirection: { base: 'column-reverse', tablet: 'row' },\n flexShrink: 0,\n gap: '12',\n justifyContent: 'flex-end',\n width: { base: '100%', tablet: 'auto' },\n },\n // `hasSidebar` only, and mobile only: the button that opens the sidebar's drawer, and the\n // active section's name under a rule. From `tablet` the sidebar is beside the page and names\n // the section itself, so both go.\n menuButton: {\n display: { base: 'flex', tablet: 'none' },\n flexShrink: 0,\n },\n sectionBlock: {\n // The content block aligns its children to the start, so the rule has to ask for the width.\n alignSelf: 'stretch',\n borderBlockStartColor: 'border/minimal',\n borderBlockStartStyle: 'solid',\n borderBlockStartWidth: '1',\n display: { base: 'flex', tablet: 'none' },\n flexDirection: 'column',\n // The rule runs edge to edge through the header block's inline padding.\n marginInline: '-16',\n paddingBlockStart: '16',\n paddingInline: '16',\n },\n sectionTitle: {\n color: 'text/primary',\n textStyle: 'heading/mobile/h1',\n truncate: true,\n },\n tabs: {\n // The tab list draws its own bottom border, inset by this padding. Pulling the row up by 1px\n // lands it exactly on the root's border instead of stacking a second line above it, so the\n // header keeps one full-width bottom edge as designed.\n marginBlockEnd: rem(-1),\n paddingInlineEnd: { base: '0', tablet: '32' },\n paddingInlineStart: { base: '0', tablet: '16' },\n width: '100%',\n },\n },\n compoundVariants: [\n // The with-sidebar header shows the page title small beside the menu button, and the section\n // below it large: `heading/mobile/h2` after a trail (`mobilePageHeader_content_withSidebar`),\n // `heading/mobile/h3` without one, where the row is the design's `sidebar-block`.\n {\n contentVariant: 'title',\n hasBreadcrumb: true,\n hasSidebar: true,\n css: { title: { base: { textStyle: 'heading/mobile/h2' } } },\n },\n { hasBreadcrumb: true, variant: 'minimal', css: titleInBreadcrumb },\n { hasBreadcrumb: true, isSticky: true, css: titleInBreadcrumb },\n { hasBreadcrumb: true, hasControls: true, variant: 'minimal', css: controlsRow },\n { hasBreadcrumb: true, hasControls: true, isSticky: true, css: controlsRow },\n { hasBreadcrumb: false, hasControls: true, variant: 'minimal', css: controlsWithoutTrail },\n { hasBreadcrumb: false, hasControls: true, isSticky: true, css: controlsWithoutTrail },\n { alignsToContent: true, variant: 'minimal', css: contentAlignedCollapsed },\n { alignsToContent: true, isSticky: true, css: contentAlignedCollapsed },\n ],\n variants: {\n contentVariant: {\n title: {\n titleBlock: {\n // `center` rather than the design's `flex-end`. With no secondary text the two are\n // identical — a 40px avatar against a 40px title line — so the bare sub-page card is\n // unaffected. With secondary text present, `flex-end` dropped the avatar down beside it;\n // centring matches how the app card sits its avatar against a two-line block.\n alignItems: 'center',\n gap: '12',\n },\n textBlock: {\n gap: '4',\n },\n },\n // `app` and `user` differ only in the gap between the avatar and the text — 16 and 12\n // respectively — so they share everything else via `entityContent`.\n app: {\n ...entityContent,\n titleBlock: {\n ...entityContent.titleBlock,\n gap: '16',\n },\n },\n user: {\n ...entityContent,\n titleBlock: {\n ...entityContent.titleBlock,\n gap: '12',\n },\n },\n },\n // Mobile splits the trail into its own `breadcrumb-margin` block (`pt-24 px-16`) above a\n // `p-16` header block, so the breadcrumb sits 24 from the top rather than 16. Desktop is 24\n // either way, hence the flat value.\n hasBreadcrumb: {\n true: {\n headerBlock: {\n paddingBlockStart: '24',\n },\n },\n false: {},\n },\n hasControls: {\n true: {},\n false: {},\n },\n /**\n * From the component's `onMenuClick`: the mobile layout for a page with a sidebar\n * (`PageHeader - mobile`, `hasSidebar=true`). The title row tightens up — 12 above, 8 to the\n * trail — and the title steps down to leave the section name as the page's large heading. All\n * `base`: from `tablet` the header is the ordinary one.\n */\n hasSidebar: {\n true: {\n headerBlock: {\n base: {\n gap: '8',\n paddingBlockStart: '12',\n },\n },\n title: {\n base: { textStyle: 'heading/mobile/h3' },\n },\n },\n false: {},\n },\n /**\n * From the component's `showDivider`. The header's background is the page's, so without the line\n * the bottom padding reads as nothing but a margin -- one the page cannot shrink -- and it goes\n * with the line. Flat values, so the collapsed row's `tablet` padding still centres it, and\n * `isSticky` restores the line from `tablet`.\n */\n hasDivider: {\n true: {},\n false: {\n root: { borderBlockEndWidth: 0 },\n headerBlock: { paddingBlockEnd: 0 },\n },\n },\n isSticky: {\n true: {\n root: {\n // Scoped to `tablet` like the layout overrides: below the breakpoint `isSticky` is\n // ignored entirely, so the expanded header must not pick up the stuck chrome either.\n tablet: {\n // Content scrolls under a stuck header, so it keeps its line with `hasDivider: false`\n // too. Width only: the `borderBlockEnd` shorthand would also reset the colour.\n borderBlockEndWidth: '1',\n borderColor: 'border/minimal',\n boxShadow: 'elevation/sm',\n },\n },\n ...collapsedSlots,\n },\n false: {},\n },\n variant: {\n default: {},\n minimal: collapsedSlots,\n },\n /**\n * Lines the content up with the page content below, leaving the root full-width — so the header's background and\n * bottom border run edge to edge while the title and the tabs sit where the content does. The cap is a `maxWidth`\n * the component sets from `contentWidth`; the auto margins centre it, and resolve to nothing when there is no cap.\n *\n * The design's centred frame pads both sides with 32, where the default header starts at 24. Only from `tablet`:\n * below it the base 16 stands, matching what a content column pads with there.\n *\n * The collapsed row (`isSticky`, `minimal`) resets the start padding to 24 under the same `tablet` key and wins\n * that merge, so the 32 is restated there by a compound variant — see `contentAlignedCollapsed`.\n */\n alignsToContent: {\n true: {\n headerBlock: {\n marginInline: 'auto',\n tablet: {\n paddingInlineStart: '32',\n },\n },\n tabs: {\n marginInline: 'auto',\n },\n },\n false: {},\n },\n },\n defaultVariants: {\n alignsToContent: false,\n contentVariant: 'title',\n hasBreadcrumb: false,\n hasControls: false,\n hasDivider: true,\n hasSidebar: false,\n isSticky: false,\n variant: 'default',\n },\n});\n\nexport default pageHeaderSlotRecipe;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PageHeader.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/PageHeader.recipe.ts"],"sourcesContent":["import { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { rem } from '../themeUtils';\n\n/**\n * The collapsed single-row layout, shared by `variant=\"minimal\"` and `isSticky`. Both apply the\n * exact same overrides, so the two variants are idempotent when combined. The expanded layout\n * lives in `base` — `variant=\"default\"` and `isSticky: false` deliberately define nothing, so\n * neither can undo the other's collapse.\n *\n * Every override is scoped to `tablet` and up, with no `base` key: below the breakpoint the `base`\n * styles win and the header stays expanded. The mobile Figma frame has no sticky or minimal\n * variant — it always shows the title as a heading — and a single 72px row cannot hold a\n * breadcrumb plus full-width actions at 375px.\n *\n * The slots the collapsed row drops are hidden here rather than omitted from the DOM, so the\n * component never has to know the viewport: no breakpoint hook, and no wrong-layout first paint.\n */\nconst collapsedSlots = {\n headerBlock: {\n tablet: {\n alignItems: 'center',\n flexDirection: 'row',\n gap: '24',\n // No 72 in the size scale — the design fixes the collapsed row height.\n minHeight: rem(72),\n paddingBlockEnd: '12',\n paddingBlockStart: '12',\n paddingInlineEnd: '32',\n paddingInlineStart: '24',\n },\n },\n breadcrumb: {\n tablet: {\n flex: '0 1 auto',\n minWidth: 0,\n },\n },\n contentBlock: {\n tablet: {\n alignItems: 'center',\n flex: '1 0 0',\n // 24 between the title and the actions, per `pageType=main, isSticky=true`. The 8 belongs to\n // `actionBlock`, between the buttons.\n gap: '24',\n justifyContent: 'flex-end',\n minWidth: 0,\n },\n },\n titleBlock: {\n tablet: {\n alignItems: 'center',\n },\n },\n title: {\n tablet: {\n textStyle: 'heading/h3',\n },\n },\n actionBlock: {\n tablet: {\n alignItems: 'center',\n flexDirection: 'row',\n gap: '8',\n width: 'auto',\n },\n },\n avatar: {\n tablet: { display: 'none' },\n },\n badge: {\n tablet: { display: 'none' },\n },\n secondaryText: {\n tablet: { display: 'none' },\n },\n tabs: {\n tablet: { display: 'none' },\n },\n} as const;\n\n/**\n * Collapsed *and* carrying a breadcrumb: the trail shows the title as its current item, so the\n * heading would duplicate it. `Breadcrumb.CurrentLink` is a link and not a heading, so the block is\n * made screen-reader-only instead of hidden — that keeps exactly one `h1` on the page at every\n * width without a second, conditionally rendered heading node.\n */\nconst titleInBreadcrumb = {\n titleBlock: { tablet: { srOnly: true } },\n // The row is trail + actions. The actions cannot shrink, so leaving `contentBlock` on a zero\n // basis let a long trail take the whole row and collapse it to width 0 — the buttons then\n // overflowed their own box and painted on top of the trail. Sizing the actions to their content\n // and letting the trail take what is left makes the trail yield, and its last crumb ellipsise.\n breadcrumb: { tablet: { flex: '1 1 auto' } },\n // `width: auto` matters as much as the flex here, for the same reason it does in `controlsRow`:\n // the base width is `100%`, which flex-basis `auto` resolves to, so without it this block claims\n // the whole row and squeezes the trail to nothing.\n contentBlock: { tablet: { flex: '0 0 auto', width: 'auto' } },\n} as const;\n\n/**\n * `minimal` *with* inline controls: the row carries three groups — trail, controls, actions — spread\n * apart rather than the usual trail-left/actions-right pair. `contentBlock` gives up its `flex: 1`\n * so `space-between` has room to distribute; without that it would absorb the free space and pin\n * the controls against the actions.\n *\n * Paired with both collapse modes, since `minimal` and `isSticky` produce the same row through\n * `collapsedSlots` — pairing it with `minimal` alone left the sticky row dropping the middle group.\n * This is the row the design file calls `PageHeader-WFE`.\n */\nconst controlsRow = {\n headerBlock: { tablet: { justifyContent: 'space-between' } },\n // Undoes the `flex: 1 1 auto` that `titleInBreadcrumb` gives the trail. That growth is right for\n // the two-group row (trail + actions), but here a third group sits between them: a growing trail\n // swallows all the free space on its side and shoves the controls island against the actions.\n // Shrink-only keeps the trail ellipsising when the row is tight, while `space-between` gets free\n // space to distribute.\n breadcrumb: { tablet: { flex: '0 1 auto' } },\n // `width: auto` matters as much as the flex: the base width is `100%`, which flex-basis `auto`\n // resolves to, so the block would otherwise claim the whole row and shrink the trail until its\n // metadata truncated away. Sized to its actions instead, leaving the free space to distribute.\n contentBlock: { tablet: { flex: '0 0 auto', width: 'auto' } },\n} as const;\n\n/**\n * Collapsed with inline controls but no trail: the title takes the left slot, so the three groups\n * are the title, the controls and the actions — all inside `contentBlock`, which already spans the\n * row. The title block gives up its `flex: 1` so `space-between` has free space to distribute; left\n * growing, it would absorb the row and shove the controls against the actions.\n */\nconst controlsWithoutTrail = {\n contentBlock: { tablet: { justifyContent: 'space-between' } },\n titleBlock: { tablet: { flex: '0 1 auto' } },\n} as const;\n\n/**\n * `alignsToContent`'s 32, restated for the collapsed row. The collapsed slots set the header block's\n * start padding under the same `tablet` key, and the variant applied later wins the merge -- which\n * is the collapsed one, since `isSticky` and `variant` come after `alignsToContent`. A compound\n * variant is applied after every plain one, so this holds whatever order the props arrive in.\n */\nconst contentAlignedCollapsed = {\n headerBlock: { tablet: { paddingInlineStart: '32' } },\n} as const;\n\n/**\n * Shared by the `app` and `user` content shapes — a larger avatar centred against a smaller title\n * and 14px secondary text. The two differ only in the avatar-to-text gap.\n */\nconst entityContent = {\n titleBlock: {\n alignItems: 'center',\n },\n title: {\n textStyle: { base: 'heading/mobile/h2', tablet: 'heading/h2' },\n },\n secondaryText: {\n textStyle: 'body/md/regular',\n },\n} as const;\n\nconst pageHeaderSlotRecipe = defineSlotRecipe({\n className: 'page-header',\n slots: [\n 'root',\n 'headerBlock',\n 'breadcrumb',\n 'controls',\n 'contentBlock',\n 'titleBar',\n 'titleBlock',\n 'avatar',\n 'textBlock',\n 'titleRow',\n 'title',\n 'badge',\n 'secondaryText',\n 'actionBlock',\n 'menuButton',\n 'sectionBlock',\n 'sectionTitle',\n 'tabs',\n ] as const,\n base: {\n root: {\n background: 'background/primary',\n borderBlockEnd: '1px solid',\n borderColor: 'border/regular',\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n },\n headerBlock: {\n alignItems: 'flex-start',\n display: 'flex',\n flexDirection: 'column',\n gap: { base: '16', tablet: '24' },\n paddingBlockEnd: { base: '16', tablet: '24' },\n paddingBlockStart: { base: '16', tablet: '24' },\n paddingInlineEnd: { base: '16', tablet: '32' },\n paddingInlineStart: { base: '16', tablet: '24' },\n width: '100%',\n },\n breadcrumb: {\n display: 'flex',\n maxWidth: '100%',\n minWidth: 0,\n // The trail's list is `white-space: nowrap`, so without this a long one escapes the header's\n // right edge instead of being clipped by it. `BitkitBreadcrumb` ellipsises its last crumb on\n // its own, but only once it is allowed to shrink — see the `breadcrumb` prop docs.\n overflow: 'hidden',\n },\n controls: {\n alignItems: 'center',\n display: 'flex',\n flexShrink: 0,\n },\n contentBlock: {\n alignItems: { base: 'flex-start', tablet: 'flex-end' },\n display: 'flex',\n flexDirection: { base: 'column', tablet: 'row' },\n gap: { base: '16', tablet: '32' },\n width: '100%',\n },\n // The title block and the menu button, which `hasSidebar` wraps them in. It stands in for the\n // title block in the content row from `tablet`, where the button is gone.\n // `contents` from `tablet`: the wrapper drops out of the layout there, so the title block is a\n // direct child of the content row again and every desktop rule — collapsed, controls, trail —\n // keeps targeting it as before.\n titleBar: {\n alignItems: 'center',\n display: { base: 'flex', tablet: 'contents' },\n gap: '12',\n minWidth: 0,\n width: '100%',\n },\n titleBlock: {\n // Full row width below `tablet`, where the content block is a column aligned to the start; sized to\n // its content, a long title or subtitle pushed the header past the page edge.\n alignSelf: { base: 'stretch', tablet: 'auto' },\n display: 'flex',\n flex: '1 0 0',\n minWidth: 0,\n },\n avatar: {\n display: 'flex',\n flexShrink: 0,\n },\n textBlock: {\n display: 'flex',\n flexDirection: 'column',\n minWidth: 0,\n },\n titleRow: {\n alignItems: 'center',\n display: 'flex',\n gap: '12',\n minWidth: 0,\n paddingInlineEnd: { base: '0', tablet: '24' },\n },\n title: {\n color: 'text/primary',\n minWidth: 0,\n textStyle: { base: 'heading/mobile/h1', tablet: 'heading/h1' },\n // One line with an ellipsis rather than wrapping. A wrapped title grew the header without\n // limit, and the collapsed row is a fixed 72px that a second line would break. The component\n // pairs this with `BitkitOverflowTooltip` so the full string stays readable.\n truncate: true,\n },\n badge: {\n display: 'flex',\n flexShrink: 0,\n // The design nudges the badge below the optical centre of the title line, wrapping it in\n // `flex-col h-full justify-center pt-8`. Reproduced with the same mechanism rather than a\n // fixed offset: the row centres the margin box, so this lands the badge `8 / 2` lower —\n // 12px down a 40px desktop line and 10px down a 36px mobile one, matching both frames.\n marginBlockStart: '8',\n },\n secondaryText: {\n color: 'text/secondary',\n textStyle: 'body/lg/regular',\n truncate: true,\n },\n actionBlock: {\n // The design puts the primary action on top once the actions stack, so `base` reverses them\n // visually while the DOM keeps its secondary-then-primary order for the row layout.\n //\n // That mismatch is deliberate and settled — please don't \"fix\" it. Actions arrive as an opaque\n // `children` list, so with one DOM order and two visual orders, no arrangement satisfies both\n // breakpoints; flipping the DOM only moves the mismatch to the row. The alternatives are a\n // design change or a structured actions API, and neither earns its cost: the surviving case is\n // a zoomed desktop window rendering `base`, where focus steps up rather than down between two\n // adjacent buttons and nothing becomes unreachable. Chasing visual order through the DOM is\n // also a pattern the design system avoids. v1 ships the same behaviour in `SubHeader.tsx:96`.\n alignItems: { base: 'stretch', tablet: 'flex-end' },\n display: 'flex',\n flexDirection: { base: 'column-reverse', tablet: 'row' },\n flexShrink: 0,\n gap: '12',\n justifyContent: 'flex-end',\n width: { base: '100%', tablet: 'auto' },\n },\n // `hasSidebar` only, and mobile only: the button that opens the sidebar's drawer, and the\n // active section's name under a rule. From `tablet` the sidebar is beside the page and names\n // the section itself, so both go.\n menuButton: {\n display: { base: 'flex', tablet: 'none' },\n flexShrink: 0,\n },\n sectionBlock: {\n // The content block aligns its children to the start, so the rule has to ask for the width.\n alignSelf: 'stretch',\n borderBlockStartColor: 'border/minimal',\n borderBlockStartStyle: 'solid',\n borderBlockStartWidth: '1',\n display: { base: 'flex', tablet: 'none' },\n flexDirection: 'column',\n // The rule runs edge to edge through the header block's inline padding.\n marginInline: '-16',\n paddingBlockStart: '16',\n paddingInline: '16',\n },\n sectionTitle: {\n color: 'text/primary',\n textStyle: 'heading/mobile/h1',\n truncate: true,\n },\n tabs: {\n // The tab list draws its own bottom border, inset by this padding. Pulling the row up by 1px\n // lands it on the root's border, so the selected tab's underline sits on the header's edge.\n // The list's line is made transparent: at a non-100% browser zoom the two 1px lines round to\n // different pixels, and the inset one showed as a second line ending at the content's edge.\n '& > div': { borderBlockEndColor: 'transparent' },\n marginBlockEnd: rem(-1),\n paddingInlineEnd: { base: '0', tablet: '32' },\n paddingInlineStart: { base: '0', tablet: '16' },\n width: '100%',\n },\n },\n compoundVariants: [\n // The with-sidebar header shows the page title small beside the menu button, and the section\n // below it large: `heading/mobile/h2` after a trail (`mobilePageHeader_content_withSidebar`),\n // `heading/mobile/h3` without one, where the row is the design's `sidebar-block`.\n {\n contentVariant: 'title',\n hasBreadcrumb: true,\n hasSidebar: true,\n css: { title: { base: { textStyle: 'heading/mobile/h2' } } },\n },\n { hasBreadcrumb: true, variant: 'minimal', css: titleInBreadcrumb },\n { hasBreadcrumb: true, isSticky: true, css: titleInBreadcrumb },\n { hasBreadcrumb: true, hasControls: true, variant: 'minimal', css: controlsRow },\n { hasBreadcrumb: true, hasControls: true, isSticky: true, css: controlsRow },\n { hasBreadcrumb: false, hasControls: true, variant: 'minimal', css: controlsWithoutTrail },\n { hasBreadcrumb: false, hasControls: true, isSticky: true, css: controlsWithoutTrail },\n { alignsToContent: true, variant: 'minimal', css: contentAlignedCollapsed },\n { alignsToContent: true, isSticky: true, css: contentAlignedCollapsed },\n ],\n variants: {\n contentVariant: {\n title: {\n titleBlock: {\n // `center` rather than the design's `flex-end`. With no secondary text the two are\n // identical — a 40px avatar against a 40px title line — so the bare sub-page card is\n // unaffected. With secondary text present, `flex-end` dropped the avatar down beside it;\n // centring matches how the app card sits its avatar against a two-line block.\n alignItems: 'center',\n gap: '12',\n },\n textBlock: {\n gap: '4',\n },\n },\n // `app` and `user` differ only in the gap between the avatar and the text — 16 and 12\n // respectively — so they share everything else via `entityContent`.\n app: {\n ...entityContent,\n titleBlock: {\n ...entityContent.titleBlock,\n gap: '16',\n },\n },\n user: {\n ...entityContent,\n titleBlock: {\n ...entityContent.titleBlock,\n gap: '12',\n },\n },\n },\n // Mobile splits the trail into its own `breadcrumb-margin` block (`pt-24 px-16`) above a\n // `p-16` header block, so the breadcrumb sits 24 from the top rather than 16. Desktop is 24\n // either way, hence the flat value.\n hasBreadcrumb: {\n true: {\n headerBlock: {\n paddingBlockStart: '24',\n },\n },\n false: {},\n },\n hasControls: {\n true: {},\n false: {},\n },\n /**\n * From the component's `onMenuClick`: the mobile layout for a page with a sidebar\n * (`PageHeader - mobile`, `hasSidebar=true`). The title row tightens up — 12 above, 8 to the\n * trail — and the title steps down to leave the section name as the page's large heading. All\n * `base`: from `tablet` the header is the ordinary one.\n */\n hasSidebar: {\n true: {\n headerBlock: {\n base: {\n gap: '8',\n paddingBlockStart: '12',\n },\n },\n title: {\n base: { textStyle: 'heading/mobile/h3' },\n },\n },\n false: {},\n },\n /**\n * From the component's `showDivider`. The header's background is the page's, so without the line\n * the bottom padding reads as nothing but a margin -- one the page cannot shrink -- and it goes\n * with the line. Flat values, so the collapsed row's `tablet` padding still centres it, and\n * `isSticky` restores the line from `tablet`.\n */\n hasDivider: {\n true: {},\n false: {\n root: { borderBlockEndWidth: 0 },\n headerBlock: { paddingBlockEnd: 0 },\n },\n },\n isSticky: {\n true: {\n root: {\n // Scoped to `tablet` like the layout overrides: below the breakpoint `isSticky` is\n // ignored entirely, so the expanded header must not pick up the stuck chrome either.\n tablet: {\n // Content scrolls under a stuck header, so it keeps its line with `hasDivider: false`\n // too. Width only: the `borderBlockEnd` shorthand would also reset the colour.\n borderBlockEndWidth: '1',\n borderColor: 'border/minimal',\n boxShadow: 'elevation/sm',\n },\n },\n ...collapsedSlots,\n },\n false: {},\n },\n variant: {\n default: {},\n minimal: collapsedSlots,\n },\n /**\n * Lines the content up with the page content below, leaving the root full-width — so the header's background and\n * bottom border run edge to edge while the title and the tabs sit where the content does. The cap is a `maxWidth`\n * the component sets from `contentWidth`; the auto margins centre it, and resolve to nothing when there is no cap.\n *\n * The design's centred frame pads both sides with 32, where the default header starts at 24. Only from `tablet`:\n * below it the base 16 stands, matching what a content column pads with there.\n *\n * The collapsed row (`isSticky`, `minimal`) resets the start padding to 24 under the same `tablet` key and wins\n * that merge, so the 32 is restated there by a compound variant — see `contentAlignedCollapsed`.\n */\n alignsToContent: {\n true: {\n headerBlock: {\n marginInline: 'auto',\n tablet: {\n paddingInlineStart: '32',\n },\n },\n tabs: {\n marginInline: 'auto',\n },\n },\n false: {},\n },\n },\n defaultVariants: {\n alignsToContent: false,\n contentVariant: 'title',\n hasBreadcrumb: false,\n hasControls: false,\n hasDivider: true,\n hasSidebar: false,\n isSticky: false,\n variant: 'default',\n },\n});\n\nexport default pageHeaderSlotRecipe;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageSubheader.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/PageSubheader.recipe.ts"],"sourcesContent":["import { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { rem } from '../themeUtils';\n\nconst pageSubheaderSlotRecipe = defineSlotRecipe({\n className: 'page-subheader',\n slots: ['root', 'contentBlock', 'headerBlock', 'textBlock', 'title', 'secondaryText', 'actionBlock', 'tabs'] as const,\n base: {\n root: {\n background: 'background/primary',\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n },\n contentBlock: {\n display: 'flex',\n flexDirection: 'column',\n marginInline: 'auto',\n width: '100%',\n },\n headerBlock: {\n alignItems: { base: 'stretch', tablet: 'flex-end' },\n display: 'flex',\n flexDirection: { base: 'column', tablet: 'row' },\n gap: { base: '16', tablet: '32' },\n paddingBlockEnd: { base: '16', tablet: '0' },\n paddingBlockStart: { base: '16', tablet: '32' },\n paddingInline: { base: '16', tablet: '32' },\n },\n textBlock: {\n display: 'flex',\n flex: { base: 'none', tablet: '1 0 0' },\n flexDirection: 'column',\n gap: { base: '4', tablet: '0' },\n minWidth: 0,\n },\n title: {\n color: 'text/primary',\n // Desktop keeps the design's 4px under the title with or without the secondary text; mobile has a gap instead.\n paddingBlockEnd: { base: '0', tablet: '4' },\n textStyle: { base: 'heading/mobile/h1', tablet: 'heading/h2' },\n truncate: true,\n },\n secondaryText: {\n color: 'text/secondary',\n textStyle: 'body/md/regular',\n },\n actionBlock: {\n display: 'flex',\n flexShrink: 0,\n // Mobile puts the primary action first, so the row (and its lines, once they wrap) reverses the DOM order.\n flexDirection: { base: 'row-reverse', tablet: 'row' },\n flexWrap: { base: 'wrap-reverse', tablet: 'wrap' },\n gap: '12',\n '& > *': { flex: { base: '1 1 auto', tablet: 'none' } },\n },\n tabs: {\n // Lands the tab list's own
|
|
1
|
+
{"version":3,"file":"PageSubheader.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/PageSubheader.recipe.ts"],"sourcesContent":["import { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { rem } from '../themeUtils';\n\nconst pageSubheaderSlotRecipe = defineSlotRecipe({\n className: 'page-subheader',\n slots: ['root', 'contentBlock', 'headerBlock', 'textBlock', 'title', 'secondaryText', 'actionBlock', 'tabs'] as const,\n base: {\n root: {\n background: 'background/primary',\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n },\n contentBlock: {\n display: 'flex',\n flexDirection: 'column',\n marginInline: 'auto',\n width: '100%',\n },\n headerBlock: {\n alignItems: { base: 'stretch', tablet: 'flex-end' },\n display: 'flex',\n flexDirection: { base: 'column', tablet: 'row' },\n gap: { base: '16', tablet: '32' },\n paddingBlockEnd: { base: '16', tablet: '0' },\n paddingBlockStart: { base: '16', tablet: '32' },\n paddingInline: { base: '16', tablet: '32' },\n },\n textBlock: {\n display: 'flex',\n flex: { base: 'none', tablet: '1 0 0' },\n flexDirection: 'column',\n gap: { base: '4', tablet: '0' },\n minWidth: 0,\n },\n title: {\n color: 'text/primary',\n // Desktop keeps the design's 4px under the title with or without the secondary text; mobile has a gap instead.\n paddingBlockEnd: { base: '0', tablet: '4' },\n textStyle: { base: 'heading/mobile/h1', tablet: 'heading/h2' },\n truncate: true,\n },\n secondaryText: {\n color: 'text/secondary',\n textStyle: 'body/md/regular',\n },\n actionBlock: {\n display: 'flex',\n flexShrink: 0,\n // Mobile puts the primary action first, so the row (and its lines, once they wrap) reverses the DOM order.\n flexDirection: { base: 'row-reverse', tablet: 'row' },\n flexWrap: { base: 'wrap-reverse', tablet: 'wrap' },\n gap: '12',\n '& > *': { flex: { base: '1 1 auto', tablet: 'none' } },\n },\n tabs: {\n // Lands the tab list on the root's border, and hides its own line, which at a non-100% browser zoom rounded\n // to a different pixel than the root's and showed as a second line.\n '& > div': { borderBlockEndColor: 'transparent' },\n marginBlockEnd: rem(-1),\n paddingInlineEnd: '32',\n paddingInlineStart: '16',\n },\n },\n variants: {\n // The capped design insets the tabs by 32, the full-width one by 16 (pending a design answer on which is right).\n isCapped: {\n true: { tabs: { paddingInlineStart: { base: '16', tablet: '32' } } },\n false: {},\n },\n hasTabs: {\n true: {\n root: {\n borderBlockEnd: '1px solid',\n borderColor: 'border/regular',\n },\n headerBlock: {\n paddingBlockEnd: { base: '16', tablet: '24' },\n },\n },\n false: {},\n },\n },\n defaultVariants: {\n hasTabs: false,\n isCapped: false,\n },\n});\n\nexport default pageSubheaderSlotRecipe;\n"],"mappings":";;;AAIA,IAAM,0BAA0B,iBAAiB;CAC/C,WAAW;CACX,OAAO;EAAC;EAAQ;EAAgB;EAAe;EAAa;EAAS;EAAiB;EAAe;CAAM;CAC3G,MAAM;EACJ,MAAM;GACJ,YAAY;GACZ,SAAS;GACT,eAAe;GACf,OAAO;EACT;EACA,cAAc;GACZ,SAAS;GACT,eAAe;GACf,cAAc;GACd,OAAO;EACT;EACA,aAAa;GACX,YAAY;IAAE,MAAM;IAAW,QAAQ;GAAW;GAClD,SAAS;GACT,eAAe;IAAE,MAAM;IAAU,QAAQ;GAAM;GAC/C,KAAK;IAAE,MAAM;IAAM,QAAQ;GAAK;GAChC,iBAAiB;IAAE,MAAM;IAAM,QAAQ;GAAI;GAC3C,mBAAmB;IAAE,MAAM;IAAM,QAAQ;GAAK;GAC9C,eAAe;IAAE,MAAM;IAAM,QAAQ;GAAK;EAC5C;EACA,WAAW;GACT,SAAS;GACT,MAAM;IAAE,MAAM;IAAQ,QAAQ;GAAQ;GACtC,eAAe;GACf,KAAK;IAAE,MAAM;IAAK,QAAQ;GAAI;GAC9B,UAAU;EACZ;EACA,OAAO;GACL,OAAO;GAEP,iBAAiB;IAAE,MAAM;IAAK,QAAQ;GAAI;GAC1C,WAAW;IAAE,MAAM;IAAqB,QAAQ;GAAa;GAC7D,UAAU;EACZ;EACA,eAAe;GACb,OAAO;GACP,WAAW;EACb;EACA,aAAa;GACX,SAAS;GACT,YAAY;GAEZ,eAAe;IAAE,MAAM;IAAe,QAAQ;GAAM;GACpD,UAAU;IAAE,MAAM;IAAgB,QAAQ;GAAO;GACjD,KAAK;GACL,SAAS,EAAE,MAAM;IAAE,MAAM;IAAY,QAAQ;GAAO,EAAE;EACxD;EACA,MAAM;GAGJ,WAAW,EAAE,qBAAqB,cAAc;GAChD,gBAAgB,IAAI,EAAE;GACtB,kBAAkB;GAClB,oBAAoB;EACtB;CACF;CACA,UAAU;EAER,UAAU;GACR,MAAM,EAAE,MAAM,EAAE,oBAAoB;IAAE,MAAM;IAAM,QAAQ;GAAK,EAAE,EAAE;GACnE,OAAO,CAAC;EACV;EACA,SAAS;GACP,MAAM;IACJ,MAAM;KACJ,gBAAgB;KAChB,aAAa;IACf;IACA,aAAa,EACX,iBAAiB;KAAE,MAAM;KAAM,QAAQ;IAAK,EAC9C;GACF;GACA,OAAO,CAAC;EACV;CACF;CACA,iBAAiB;EACf,SAAS;EACT,UAAU;CACZ;AACF,CAAC"}
|
|
@@ -3,6 +3,7 @@ import { defineTokens } from "@chakra-ui/react/styled-system";
|
|
|
3
3
|
//#region lib/theme/tokens/sizes.ts
|
|
4
4
|
var sizes = defineTokens.sizes({
|
|
5
5
|
...sizesAndSpacing_default,
|
|
6
|
+
"layout/maxWidth/480": { value: "30rem" },
|
|
6
7
|
"layout/maxWidth/640": { value: "40rem" },
|
|
7
8
|
"layout/maxWidth/960": { value: "60rem" },
|
|
8
9
|
"layout/maxWidth/1280": { value: "80rem" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sizes.js","names":["object"],"sources":["../../../lib/theme/tokens/sizes.ts"],"sourcesContent":["import { defineTokens } from '@chakra-ui/react/styled-system';\n\nimport object from './sizesAndSpacing.json';\n\nconst sizes = defineTokens.sizes({\n ...object,\n 'layout/maxWidth/640': { value: '40rem' },\n 'layout/maxWidth/960': { value: '60rem' },\n 'layout/maxWidth/1280': { value: '80rem' },\n 'layout/maxWidth/1616': { value: '101rem' },\n 'layout/maxWidth/full': { value: '100%' },\n});\n\nexport default sizes;\n"],"mappings":";;;AAIA,IAAM,QAAQ,aAAa,MAAM;CAC/B,GAAGA;CACH,uBAAuB,EAAE,OAAO,QAAQ;CACxC,uBAAuB,EAAE,OAAO,QAAQ;CACxC,wBAAwB,EAAE,OAAO,QAAQ;CACzC,wBAAwB,EAAE,OAAO,SAAS;CAC1C,wBAAwB,EAAE,OAAO,OAAO;AAC1C,CAAC"}
|
|
1
|
+
{"version":3,"file":"sizes.js","names":["object"],"sources":["../../../lib/theme/tokens/sizes.ts"],"sourcesContent":["import { defineTokens } from '@chakra-ui/react/styled-system';\n\nimport object from './sizesAndSpacing.json';\n\nconst sizes = defineTokens.sizes({\n ...object,\n 'layout/maxWidth/480': { value: '30rem' },\n 'layout/maxWidth/640': { value: '40rem' },\n 'layout/maxWidth/960': { value: '60rem' },\n 'layout/maxWidth/1280': { value: '80rem' },\n 'layout/maxWidth/1616': { value: '101rem' },\n 'layout/maxWidth/full': { value: '100%' },\n});\n\nexport default sizes;\n"],"mappings":";;;AAIA,IAAM,QAAQ,aAAa,MAAM;CAC/B,GAAGA;CACH,uBAAuB,EAAE,OAAO,QAAQ;CACxC,uBAAuB,EAAE,OAAO,QAAQ;CACxC,uBAAuB,EAAE,OAAO,QAAQ;CACxC,wBAAwB,EAAE,OAAO,QAAQ;CACzC,wBAAwB,EAAE,OAAO,SAAS;CAC1C,wBAAwB,EAAE,OAAO,OAAO;AAC1C,CAAC"}
|