@bitrise/bitkit-v2 0.3.386 → 0.3.387

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"BitkitTour.js","names":[],"sources":["../../../lib/components/BitkitTour/BitkitTour.tsx"],"sourcesContent":["import {\n Tour as ArkTour,\n type TourStepDetails,\n useTour,\n type UseTourProps,\n type UseTourReturn,\n} from '@ark-ui/react/tour';\nimport { Box } from '@chakra-ui/react/box';\nimport { useEnvironmentContext } from '@chakra-ui/react/environment';\nimport { Portal } from '@chakra-ui/react/portal';\nimport { chakra, useSlotRecipe } from '@chakra-ui/react/styled-system';\nimport { isIos } from '@zag-js/dom-query';\nimport { preventBodyScroll } from '@zag-js/remove-scroll';\nimport { type ReactNode, useCallback, useEffect, useRef } from 'react';\n\nimport BitkitButton from '../BitkitButton/BitkitButton';\nimport BitkitCloseButton from '../BitkitCloseButton/BitkitCloseButton';\n\ntype BitkitTourStepAction = NonNullable<TourStepDetails['actions']>[number];\n\n/**\n * The link-style action in the footer, e.g. `Skip tour` or `Learn more`. It either drives the tour\n * (`action`) or leaves the page (`href`) — the union makes passing both, or neither, a type error.\n */\nexport type BitkitTourSecondaryAction =\n | {\n /**\n * A tour action — `'skip'`, `'dismiss'`, `'next'`, `'prev'`, or a function that receives the\n * action map (`{ next, prev, dismiss, skip, goto }`) to do something else first.\n */\n action: NonNullable<BitkitTourStepAction['action']>;\n href?: never;\n label: string;\n }\n | {\n action?: never;\n /** Renders the action as a link out. */\n href: string;\n /** Opens the link in a new tab, with the matching `rel`. */\n isExternal?: boolean;\n label: string;\n };\n\n/**\n * A single step of the tour. On top of Ark's step details it carries the three Bitkit slots —\n * `badge`, `content` and `secondaryAction`. Zag spreads the whole step object when it normalises\n * it, so these reach `tour.step` untouched. (Zag also offers a `meta` bag for this; flat fields\n * read better at the call site, at the cost of a name clash if Zag ever adds one of these.)\n *\n * Ark's step `type` is not part of this: every step is a card anchored to an element, so the hook\n * sets it. `target` is required for the same reason — Zag turns a step without one into a centred\n * dialog, which is a presentation this component doesn't have.\n */\nexport type BitkitTourStep = Omit<TourStepDetails, 'type'> & {\n /**\n * Rendered next to the title — a `BitkitBadge` in practice, e.g. `BETA` or `NEW`. Nothing about\n * the badge is fixed here beyond its placement: the element itself comes from the caller.\n */\n badge?: ReactNode;\n /** Rendered between the description and the footer — an image, a video, a table, anything. */\n content?: ReactNode;\n secondaryAction?: BitkitTourSecondaryAction;\n /** The element the step points at. */\n target: NonNullable<TourStepDetails['target']>;\n};\n\nexport interface BitkitTourOptions extends Omit<UseTourProps, 'closeOnInteractOutside' | 'onStepsChange' | 'steps'> {\n /**\n * Called whenever the tour ends, whichever way it ended — the close button, `Skip tour`, the last\n * step's action, or a target that never appeared. It is the counterpart to `open`: turn your own\n * value false here and the tour can be opened again, without having to know which of Zag's five\n * statuses mean \"over\". `onStatusChange` still reports which one it was, for deciding whether to\n * record the tour as seen.\n */\n onClose?: () => void;\n /** Refined so the callback reports the Bitkit slots too, like the rest of the api does. */\n onStepsChange?: (details: { steps: BitkitTourStep[] }) => void;\n /**\n * Drives the tour from a value the caller already has — it starts when this turns true and closes\n * when it turns false. This is how a tour is opened: it announces something, so it appears once\n * the user is eligible for it, never in answer to the interaction it would interrupt.\n *\n * Only the transitions count: a tour that ends on its own — `Skip tour`, a lost target, the last\n * step — stays closed while this is still true, and starts again on the next `false → true`.\n */\n open?: boolean;\n steps: BitkitTourStep[];\n}\n/** The tour api returned by `useBitkitTour` — pass it around to control the tour from anywhere. */\nexport type BitkitTourInstance = Omit<UseTourReturn, 'addStep' | 'setSteps' | 'step' | 'updateStep'> & {\n addStep: (step: BitkitTourStep) => void;\n setSteps: (steps: BitkitTourStep[]) => void;\n /** The current step, with the Bitkit slots (`badge`, `content`, `secondaryAction`) still typed on it. */\n step: BitkitTourStep | null;\n /** Closes the tour, the same way its close button does. */\n dismiss: () => void;\n updateStep: (id: string, stepOverrides: Partial<BitkitTourStep>) => void;\n};\nexport type BitkitTourProps = {\n /** The tour instance returned by `useBitkitTour`. */\n tour: BitkitTourInstance;\n};\n\n/**\n * Creates the tour instance that drives `BitkitTour`. Takes the steps plus the tour-level options\n * (`onStepChange`, `onStatusChange`, `closeOnEscape`, `preventInteraction`, `translations`, …) and\n * returns the api that reports and navigates it: `step`, `stepIndex`, `totalSteps`, `next()`,\n * `prev()`, `setStep()`. Closing on a click outside isn't among them — see below.\n *\n * A one-step tour announces a feature, and behaves the same wherever it's used:\n *\n * - it appears on its own — `open` turns true once the user is eligible, and nothing has to be\n * clicked to bring it up;\n * - dismissing it closes it, and it doesn't come back;\n * - acting on the control it points at closes it too, reported as a dismissal like any other, so\n * the target keeps doing whatever it did before;\n * - until one of those two happens, a reload or a new session brings it back — which means the\n * dismissal is recorded for the user in `onStatusChange`, not kept in page state.\n */\nexport const useBitkitTour = (options: BitkitTourOptions): BitkitTourInstance => {\n // The document the tour lives in — the global one unless a consumer renders under an\n // `EnvironmentProvider`, e.g. into an iframe. Same route Zag's own machines take.\n const { getDocument } = useEnvironmentContext();\n\n // `onClose` is ours, not Zag's, so it is kept out of what reaches the machine. The ref keeps an\n // inline callback from giving the machine a new `onStatusChange` on every render.\n const { onClose, ...tourOptions } = options;\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n // Zag reports the end of a tour more than once — a dismissal on the last step emits `dismissed`\n // and then `completed` — so the run, not the status, is what `onClose` is tied to. Guarding on the\n // status names instead would encode which pairs the machine currently emits together.\n const hasClosedRef = useRef(false);\n\n const tour = useTour({\n // The highlight sits 8 around the target, and the card 12 from the highlight — the 8 the arrow\n // takes plus the 4 gap the design asks for. Both are measured from the highlight, since Zag\n // grows the anchor rect by `spotlightOffset` before positioning. `offset.mainAxis` replaces\n // Zag's own gutter, and Popper adds half the arrow's box on top of it: 6 + 5.65 ≈ the 12.\n spotlightOffset: { x: 8, y: 8 },\n // 4 is also Zag's current default, but the design asks for it and a third-party default is not\n // ours to rely on — the z-index contract already moved under us once between two minors.\n spotlightRadius: 4,\n ...tourOptions,\n // Not part of the options, and set after the spread so it can't be turned back on: a tour is a\n // guided flow with its own ways out — the close button, `Skip tour`, `Done` — and Zag would\n // otherwise end it on any click outside the card, losing the whole thing to a stray click on\n // the dimmed page. Escape is a deliberate keystroke rather than a stray click, so it keeps\n // closing the tour by default — and unlike this one, `closeOnEscape` stays in the options for\n // callers who want it off.\n closeOnInteractOutside: false,\n // Every status other than `started` is the tour ending, and `onClose` is what saves callers from\n // knowing that. The caller's own `onStatusChange` runs first and unchanged — it reports every\n // status, including the ones `onClose` collapses.\n onStatusChange: (details) => {\n tourOptions.onStatusChange?.(details);\n\n if (details.status === 'started') {\n hasClosedRef.current = false;\n\n return;\n }\n\n if (hasClosedRef.current) {\n return;\n }\n\n hasClosedRef.current = true;\n onCloseRef.current?.();\n },\n // Same reason as the cast on `Tour.Root` below: our step type isn't a supertype of Ark's, so a\n // callback taking ours doesn't match the signature Ark declares. The payload is Ark's.\n onStepsChange: tourOptions.onStepsChange as UseTourProps['onStepsChange'],\n // Zag's default is `close tour`, and this one is visible rather than screen-reader only: the\n // close button shows its own aria-label in a tooltip. The rest of Zag's translations\n // (`nextStep`, `prevStep`, `skip`) stay as they are — those only ever reach assistive tech.\n translations: { close: 'Close tour', ...tourOptions.translations },\n // `type` last: there is one presentation, so it isn't the caller's to pick.\n steps: tourOptions.steps.map((step) => ({ offset: { mainAxis: 6 }, ...step, type: 'tooltip' as const })),\n });\n\n // Zag's api can start a tour but not stop one. Its close trigger's click handler *is* the\n // machine's dismiss, so this borrows that instead of reaching into the machine. The cast says\n // what the handler is rather than manufacturing an event for it: `actionMap.dismiss` takes none.\n const dismiss = useCallback(() => {\n const closeTriggerClick = tour.getCloseTriggerProps().onClick as (() => void) | undefined;\n\n closeTriggerClick?.();\n }, [tour]);\n\n // A single-step tour points at one control, and operating that control is the same\n // acknowledgement its close button is — there is no next step to go to, so the tour is done. Zag\n // leaves the target clickable on purpose (it excludes it from interact-outside), so without this\n // every caller has to wire the dismissal into the target's own handler, and the ones that forget\n // show the tour again on the user's next visit. Multi-step tours are left alone: there, clicking\n // the highlighted control could as easily mean \"go on\" as \"I'm done\", which isn't ours to guess.\n //\n // The listener is on the document rather than the target, resolving the target when the click\n // happens: the target can re-render while the tour is open, and capture runs even when the\n // caller's own handler stops propagation. `click` rather than `pointerdown` — a right-click or an\n // abandoned drag isn't acting on it — and it still runs before a link's navigation, so a caller\n // that records the dismissal gets its request away.\n // `dismiss` closes over `tour`, which is a new object on every render, so listing it would put the\n // effects below on every render as well — attaching and detaching the listener for nothing.\n const dismissRef = useRef(dismiss);\n dismissRef.current = dismiss;\n\n const isSingleStep = options.steps.length === 1;\n useEffect(() => {\n if (!tour.open || !isSingleStep) {\n return undefined;\n }\n\n const onDocumentClick = (event: MouseEvent) => {\n const target = tour.step?.target?.();\n\n // The event path rather than `target.contains(event.target)`: under an `EnvironmentProvider`\n // the click comes from another realm, where a node is not an instance of this one's `Node`, so\n // narrowing it that way is always false — and the path crosses shadow boundaries as well.\n if (target && event.composedPath().includes(target)) {\n dismissRef.current();\n }\n };\n\n const doc = getDocument();\n\n doc.addEventListener('click', onDocumentClick, true);\n\n return () => doc.removeEventListener('click', onDocumentClick, true);\n // `tour` is a new object on every render; the machine's own state is what matters here.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [getDocument, isSingleStep, tour.open, tour.step?.id]);\n\n // Edge-triggered, on the prop's own `false → true`: comparing it against `tour.open` instead made\n // every close the machine performs for its own reasons look like a caller who wants the tour open,\n // and started it again. Zag reports five statuses and callers reasonably handle `dismissed` only,\n // so `Skip tour` (`skipped`) and a target that goes missing (`not-found`) both closed the tour and\n // had it come straight back at step one. `undefined` as the initial value so an `open` that is\n // already true on mount still starts the tour.\n const { open } = tourOptions;\n const previousOpen = useRef<boolean | undefined>(undefined);\n useEffect(() => {\n if (open === undefined || open === previousOpen.current) {\n return;\n }\n\n previousOpen.current = open;\n\n if (open) {\n tour.start();\n } else {\n dismissRef.current();\n }\n // `tour` is a new object on every render, and reacting to the machine's own `open` is exactly\n // what this effect must not do.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n\n return { ...tour, dismiss, step: tour.step as BitkitTourStep | null };\n};\n\n// The Ark parts aren't Chakra components, so they're wrapped with the `chakra()` factory to accept\n// `css`. They're deliberately NOT wrapped with `asChild`: each Ark part falls back to the current\n// step's content (title, description, progress text, action label) only when it renders its own\n// children, and `asChild` would replace those children with the wrapper element.\nconst TourBackdrop = chakra(ArkTour.Backdrop);\nconst TourSpotlight = chakra(ArkTour.Spotlight);\nconst TourPositioner = chakra(ArkTour.Positioner);\nconst TourContent = chakra(ArkTour.Content);\nconst TourArrow = chakra(ArkTour.Arrow);\nconst TourArrowTip = chakra(ArkTour.ArrowTip);\nconst TourTitle = chakra(ArkTour.Title);\nconst TourDescription = chakra(ArkTour.Description);\nconst TourControl = chakra(ArkTour.Control);\nconst TourProgressText = chakra(ArkTour.ProgressText);\n\nconst SecondaryAction = ({ secondaryAction }: { secondaryAction: BitkitTourSecondaryAction }) => {\n const { action, href, label } = secondaryAction;\n\n if (href !== undefined) {\n return (\n <BitkitButton href={href} isExternal={secondaryAction.isExternal} size=\"sm\" variant=\"tertiary\">\n {label}\n </BitkitButton>\n );\n }\n\n if (!action) return null;\n\n return (\n <ArkTour.ActionTrigger asChild action={{ action, label }} aria-label={label}>\n <BitkitButton size=\"sm\" variant=\"tertiary\">\n {label}\n </BitkitButton>\n </ArkTour.ActionTrigger>\n );\n};\n\n/**\n * A guided product tour: a step card anchored to an element on the page, with a spotlight cut out\n * of the dimmed backdrop around that element.\n *\n * The steps and the tour behaviour live on the instance — create it with `useBitkitTour` and render\n * `BitkitTour` once, anywhere in the tree. Each step declares its own action buttons; the last one\n * is rendered as the primary button. A single-step tour drops the `1 of n` label, which is what\n * turns the card into the single-feature presentation.\n */\nconst BitkitTour = ({ tour }: BitkitTourProps) => {\n const recipe = useSlotRecipe({ key: 'tour' });\n const styles = recipe();\n const step = tour.step;\n const actions = step?.actions ?? [];\n\n // Zag traps focus with fixed options, so it lands on the card's first tabbable — the close button,\n // which means a screen reader opens the tour on `Close tour` instead of on what the step says. The\n // card is what should take it: Zag gives the content `role=\"alertdialog\"`, `tabIndex: -1` and the\n // `aria-labelledby`/`aria-describedby` pair exactly so it can be focused and read out. Measured\n // alternatives that don't work: making the card tabbable (the trap picks a descendant either way)\n // and a ref (it doesn't survive the `chakra()`-wrapped Ark part). This corrects the trap's choice\n // instead of trying to beat it — the trap activates asynchronously too, and racing it with a frame\n // loses whenever the first paint is slow. The listener takes the first focus that lands anywhere\n // in the card, moves it to the card itself and then steps out of the way, so everything after it\n // (Tab, the buttons, a click) behaves normally. It arms on open and not per step, so stepping on\n // keeps the focus on the button that did it, rather than pulling the next keystroke back to the\n // card. The lookup goes through the machine's own content id, so two mounted tours can't reach\n // each other's card.\n //\n // The tour machine is the one Zag component that can't be told where to put focus: `dialog` takes\n // an `initialFocusEl` and hands it to the same trap, and even defaults an `alertdialog` to its\n // close trigger deliberately. Once the tour has that prop too, this effect goes away.\n const { open } = tour;\n // Everything below reaches for the document through the environment rather than the global one:\n // under an `EnvironmentProvider` — a consumer rendering into an iframe — that is the document the\n // portal, and so the tour, actually lives in. Zag's own machines take the same route.\n const { getDocument } = useEnvironmentContext();\n\n // The tour machine has no scroll handling of its own — no `preventScroll` prop, no listener —\n // while Zag's dialog machine locks the body through this same helper. The tour needs it just as\n // much: everything it paints is positioned in document coordinates from a target it resolves once,\n // when the step opens, and never looks up again. Let the page scroll and any layout that swaps its\n // elements around — a sticky header that moves its buttons into a portal is the common one —\n // leaves the machine anchored to a node that is no longer in the document. A detached node\n // measures zero, so the card, the spotlight and the backdrop's cut-out all collapse into the\n // top-left corner of the page. Locking is the honest reading of the presentation anyway: the tour\n // dims the page and takes focus, exactly like a modal dialog.\n // Not on iOS, where the helper pins `<body>` with `position: fixed` instead of hiding the\n // overflow: from there the machine's `scrollIntoView` on step entry can't move the viewport, so a\n // target below the fold is unreachable and the tour locks the user onto a step they can't see —\n // worse than the misalignment the lock is here to prevent. (`overflow: hidden` leaves programmatic\n // scrolling alone, which is what makes the lock safe everywhere else.)\n useEffect(() => (open && !isIos() ? preventBodyScroll(getDocument()) : undefined), [getDocument, open]);\n\n const contentId = tour.getContentProps().id;\n useEffect(() => {\n if (!open || contentId === undefined) {\n return undefined;\n }\n\n const contentEl = getDocument().getElementById(contentId);\n if (!contentEl) {\n return undefined;\n }\n\n const takeFocus = () => {\n contentEl.removeEventListener('focusin', takeFocus);\n // `preventScroll`, because this runs before Popper has placed the card, and until then the\n // card is parked off-screen at `-100vh` — a plain `focus()` scrolls the page up to it and\n // leaves the user looking at the top of the page with a tour they can't see. Zag passes the\n // same option everywhere it moves focus itself.\n contentEl.focus({ preventScroll: true });\n };\n\n contentEl.addEventListener('focusin', takeFocus);\n\n return () => contentEl.removeEventListener('focusin', takeFocus);\n }, [contentId, getDocument, open]);\n\n return (\n // `unmountOnExit` isn't only tidiness: Ark's backdrop applies `hidden: !tour.step?.backdrop`\n // after merging the presence props, which overrides the presence's own `hidden` — and since the\n // step is kept after the tour closes, the dimming would stay on screen for good. Unmounting on\n // exit takes the node out before that can happen.\n // The cast is the price of refining `step` and the step-mutating methods on the instance: our\n // step type isn't a supertype of Ark's, so the methods no longer match its api signature. The\n // object is Ark's api — only the types are ours.\n <ArkTour.Root unmountOnExit tour={tour as UseTourReturn}>\n <Portal>\n <TourBackdrop css={styles.backdrop} />\n <TourSpotlight css={styles.spotlight} />\n <TourPositioner css={styles.positioner}>\n <TourContent css={styles.content}>\n {/* `hidden={false}` overrides Zag, which hides the arrow until the card has been\n positioned — while Popper computes that position from the arrow's `clientHeight`, so\n a hidden arrow measures 0 and the card lands 6 short of the design's 12, then drops\n by that 6 as soon as anything recomputes. Nothing shows in the meantime: until it is\n positioned the card itself sits off-screen at `-100vh`. */}\n <TourArrow css={styles.arrow} hidden={false}>\n <TourArrowTip css={styles.arrowTip} />\n </TourArrow>\n <Box css={styles.header}>\n <Box css={styles.titleGroup}>\n {tour.totalSteps > 1 ? <TourProgressText css={styles.progressText} /> : null}\n <Box css={styles.titleRow}>\n <TourTitle css={styles.title} />\n {step?.badge ? <Box css={styles.badge}>{step.badge}</Box> : null}\n </Box>\n </Box>\n <ArkTour.CloseTrigger asChild>\n <BitkitCloseButton css={styles.closeTrigger} size=\"xs\" />\n </ArkTour.CloseTrigger>\n </Box>\n <TourDescription css={styles.description} />\n {step?.content ? <Box css={styles.media}>{step.content}</Box> : null}\n <TourControl css={styles.control}>\n {step?.secondaryAction ? <SecondaryAction secondaryAction={step.secondaryAction} /> : null}\n <Box css={styles.actions}>\n {actions.map((action, index) => (\n // Zag labels the trigger from its own translations (`close tour`, `next step`),\n // which would override the visible text as the accessible name — and put two\n // `Close tour` buttons on a card whose dismiss action reads `Got it`.\n <ArkTour.ActionTrigger key={action.label} asChild action={action} aria-label={action.label}>\n <BitkitButton size=\"sm\" variant={index === actions.length - 1 ? 'primary' : 'secondary'}>\n {action.label}\n </BitkitButton>\n </ArkTour.ActionTrigger>\n ))}\n </Box>\n </TourControl>\n </TourContent>\n </TourPositioner>\n </Portal>\n </ArkTour.Root>\n );\n};\n\nBitkitTour.displayName = 'BitkitTour';\n\nexport default BitkitTour;\n"],"mappings":"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"}
1
+ {"version":3,"file":"BitkitTour.js","names":[],"sources":["../../../lib/components/BitkitTour/BitkitTour.tsx"],"sourcesContent":["import {\n Tour as ArkTour,\n type TourStepDetails,\n useTour,\n type UseTourProps,\n type UseTourReturn,\n} from '@ark-ui/react/tour';\nimport { Box } from '@chakra-ui/react/box';\nimport { useEnvironmentContext } from '@chakra-ui/react/environment';\nimport { Portal } from '@chakra-ui/react/portal';\nimport { chakra, useSlotRecipe } from '@chakra-ui/react/styled-system';\nimport { isIos } from '@zag-js/dom-query';\nimport { preventBodyScroll } from '@zag-js/remove-scroll';\nimport { type ReactNode, useCallback, useEffect, useRef } from 'react';\n\nimport BitkitButton from '../BitkitButton/BitkitButton';\nimport BitkitCloseButton from '../BitkitCloseButton/BitkitCloseButton';\n\ntype BitkitTourStepAction = NonNullable<TourStepDetails['actions']>[number];\n\n/**\n * The link-style action in the footer, e.g. `Skip tour` or `Learn more`. It either drives the tour\n * (`action`) or leaves the page (`href`) — the union makes passing both, or neither, a type error.\n */\nexport type BitkitTourSecondaryAction =\n | {\n /**\n * A tour action — `'skip'`, `'dismiss'`, `'next'`, `'prev'`, or a function that receives the\n * action map (`{ next, prev, dismiss, skip, goto }`) to do something else first.\n */\n action: NonNullable<BitkitTourStepAction['action']>;\n href?: never;\n label: string;\n }\n | {\n action?: never;\n /** Renders the action as a link out. */\n href: string;\n /** Opens the link in a new tab, with the matching `rel`. */\n isExternal?: boolean;\n label: string;\n };\n\n/**\n * A single step of the tour. On top of Ark's step details it carries the three Bitkit slots —\n * `badge`, `content` and `secondaryAction`. Zag spreads the whole step object when it normalises\n * it, so these reach `tour.step` untouched. (Zag also offers a `meta` bag for this; flat fields\n * read better at the call site, at the cost of a name clash if Zag ever adds one of these.)\n *\n * Ark's step `type` is not part of this: every step is a card anchored to an element, so the hook\n * sets it. `target` is required for the same reason — Zag turns a step without one into a centred\n * dialog, which is a presentation this component doesn't have.\n */\nexport type BitkitTourStep = Omit<TourStepDetails, 'type'> & {\n /**\n * Rendered next to the title — a `BitkitBadge` in practice, e.g. `BETA` or `NEW`. Nothing about\n * the badge is fixed here beyond its placement: the element itself comes from the caller.\n */\n badge?: ReactNode;\n /** Rendered between the description and the footer — an image, a video, a table, anything. */\n content?: ReactNode;\n secondaryAction?: BitkitTourSecondaryAction;\n /** The element the step points at. */\n target: NonNullable<TourStepDetails['target']>;\n};\n\nexport interface BitkitTourOptions extends Omit<UseTourProps, 'closeOnInteractOutside' | 'onStepsChange' | 'steps'> {\n /**\n * Called whenever the tour ends, whichever way it ended — the close button, `Skip tour`, the last\n * step's action, or a target that never appeared. It is the counterpart to `open`: turn your own\n * value false here and the tour can be opened again, without having to know which of Zag's five\n * statuses mean \"over\". `onStatusChange` still reports which one it was, for deciding whether to\n * record the tour as seen.\n */\n onClose?: () => void;\n /** Refined so the callback reports the Bitkit slots too, like the rest of the api does. */\n onStepsChange?: (details: { steps: BitkitTourStep[] }) => void;\n /**\n * Drives the tour from a value the caller already has — it starts when this turns true and closes\n * when it turns false. This is how a tour is opened: it announces something, so it appears once\n * the user is eligible for it, never in answer to the interaction it would interrupt.\n *\n * Only the transitions count: a tour that ends on its own — `Skip tour`, a lost target, the last\n * step — stays closed while this is still true, and starts again on the next `false → true`.\n */\n open?: boolean;\n steps: BitkitTourStep[];\n}\n/** The tour api returned by `useBitkitTour` — pass it around to control the tour from anywhere. */\nexport type BitkitTourInstance = Omit<UseTourReturn, 'addStep' | 'setSteps' | 'step' | 'updateStep'> & {\n addStep: (step: BitkitTourStep) => void;\n setSteps: (steps: BitkitTourStep[]) => void;\n /** The current step, with the Bitkit slots (`badge`, `content`, `secondaryAction`) still typed on it. */\n step: BitkitTourStep | null;\n /** Closes the tour, the same way its close button does. */\n dismiss: () => void;\n updateStep: (id: string, stepOverrides: Partial<BitkitTourStep>) => void;\n};\nexport type BitkitTourProps = {\n /** The tour instance returned by `useBitkitTour`. */\n tour: BitkitTourInstance;\n};\n\n/**\n * Creates the tour instance that drives `BitkitTour`. Takes the steps plus the tour-level options\n * (`onStepChange`, `onStatusChange`, `closeOnEscape`, `preventInteraction`, `translations`, …) and\n * returns the api that reports and navigates it: `step`, `stepIndex`, `totalSteps`, `next()`,\n * `prev()`, `setStep()`. Closing on a click outside isn't among them — see below.\n *\n * A one-step tour announces a feature, and behaves the same wherever it's used:\n *\n * - it appears on its own — `open` turns true once the user is eligible, and nothing has to be\n * clicked to bring it up;\n * - dismissing it closes it, and it doesn't come back;\n * - acting on the control it points at closes it too, reported as a dismissal like any other, so\n * the target keeps doing whatever it did before;\n * - until one of those two happens, a reload or a new session brings it back — which means the\n * dismissal is recorded for the user in `onStatusChange`, not kept in page state.\n */\nexport const useBitkitTour = (options: BitkitTourOptions): BitkitTourInstance => {\n // The document the tour lives in — the global one unless a consumer renders under an\n // `EnvironmentProvider`, e.g. into an iframe. Same route Zag's own machines take.\n const { getDocument } = useEnvironmentContext();\n\n // `onClose` is ours, not Zag's, so it is kept out of what reaches the machine. The ref keeps an\n // inline callback from giving the machine a new `onStatusChange` on every render.\n const { onClose, ...tourOptions } = options;\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n // Zag reports the end of a tour more than once — a dismissal on the last step emits `dismissed`\n // and then `completed` — so the run, not the status, is what `onClose` is tied to. Guarding on the\n // status names instead would encode which pairs the machine currently emits together.\n const hasClosedRef = useRef(false);\n\n const tour = useTour({\n // The highlight sits 8 around the target, and the card 12 from the highlight — the 8 the arrow\n // takes plus the 4 gap the design asks for. Both are measured from the highlight, since Zag\n // grows the anchor rect by `spotlightOffset` before positioning. `offset.mainAxis` replaces\n // Zag's own gutter, and Popper adds half the arrow's box on top of it: 6 + 5.65 ≈ the 12.\n spotlightOffset: { x: 8, y: 8 },\n // 4 is also Zag's current default, but the design asks for it and a third-party default is not\n // ours to rely on — the z-index contract already moved under us once between two minors.\n spotlightRadius: 4,\n ...tourOptions,\n // Not part of the options, and set after the spread so it can't be turned back on: a tour is a\n // guided flow with its own ways out — the close button, `Skip tour`, `Done` — and Zag would\n // otherwise end it on any click outside the card, losing the whole thing to a stray click on\n // the dimmed page. Escape is a deliberate keystroke rather than a stray click, so it keeps\n // closing the tour by default — and unlike this one, `closeOnEscape` stays in the options for\n // callers who want it off.\n closeOnInteractOutside: false,\n // Every status other than `started` is the tour ending, and `onClose` is what saves callers from\n // knowing that. The caller's own `onStatusChange` runs first and unchanged — it reports every\n // status, including the ones `onClose` collapses.\n onStatusChange: (details) => {\n tourOptions.onStatusChange?.(details);\n\n if (details.status === 'started') {\n hasClosedRef.current = false;\n\n return;\n }\n\n if (hasClosedRef.current) {\n return;\n }\n\n hasClosedRef.current = true;\n onCloseRef.current?.();\n },\n // Same reason as the cast on `Tour.Root` below: our step type isn't a supertype of Ark's, so a\n // callback taking ours doesn't match the signature Ark declares. The payload is Ark's.\n onStepsChange: tourOptions.onStepsChange as UseTourProps['onStepsChange'],\n // Zag's default is `close tour`, and this one is visible rather than screen-reader only: the\n // close button shows its own aria-label in a tooltip. The rest of Zag's translations\n // (`nextStep`, `prevStep`, `skip`) stay as they are — those only ever reach assistive tech.\n translations: { close: 'Close tour', ...tourOptions.translations },\n // `type` last: there is one presentation, so it isn't the caller's to pick.\n steps: tourOptions.steps.map((step) => ({ offset: { mainAxis: 6 }, ...step, type: 'tooltip' as const })),\n });\n\n // Zag's api can start a tour but not stop one. Its close trigger's click handler *is* the\n // machine's dismiss, so this borrows that instead of reaching into the machine. The cast says\n // what the handler is rather than manufacturing an event for it: `actionMap.dismiss` takes none.\n const dismiss = useCallback(() => {\n const closeTriggerClick = tour.getCloseTriggerProps().onClick as (() => void) | undefined;\n\n closeTriggerClick?.();\n }, [tour]);\n\n // A single-step tour points at one control, and operating that control is the same\n // acknowledgement its close button is — there is no next step to go to, so the tour is done. Zag\n // leaves the target clickable on purpose (it excludes it from interact-outside), so without this\n // every caller has to wire the dismissal into the target's own handler, and the ones that forget\n // show the tour again on the user's next visit. Multi-step tours are left alone: there, clicking\n // the highlighted control could as easily mean \"go on\" as \"I'm done\", which isn't ours to guess.\n //\n // The listener is on the document rather than the target, resolving the target when the click\n // happens: the target can re-render while the tour is open, and capture runs even when the\n // caller's own handler stops propagation. `click` rather than `pointerdown` — a right-click or an\n // abandoned drag isn't acting on it — and it still runs before a link's navigation, so a caller\n // that records the dismissal gets its request away.\n // `dismiss` closes over `tour`, which is a new object on every render, so listing it would put the\n // effects below on every render as well — attaching and detaching the listener for nothing.\n const dismissRef = useRef(dismiss);\n dismissRef.current = dismiss;\n\n const isSingleStep = options.steps.length === 1;\n useEffect(() => {\n if (!tour.open || !isSingleStep) {\n return undefined;\n }\n\n const onDocumentClick = (event: MouseEvent) => {\n const target = tour.step?.target?.();\n\n // The event path rather than `target.contains(event.target)`: under an `EnvironmentProvider`\n // the click comes from another realm, where a node is not an instance of this one's `Node`, so\n // narrowing it that way is always false — and the path crosses shadow boundaries as well.\n if (target && event.composedPath().includes(target)) {\n dismissRef.current();\n }\n };\n\n const doc = getDocument();\n\n doc.addEventListener('click', onDocumentClick, true);\n\n return () => doc.removeEventListener('click', onDocumentClick, true);\n // `tour` is a new object on every render; the machine's own state is what matters here.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [getDocument, isSingleStep, tour.open, tour.step?.id]);\n\n // Edge-triggered, on the prop's own `false → true`: comparing it against `tour.open` instead made\n // every close the machine performs for its own reasons look like a caller who wants the tour open,\n // and started it again. Zag reports five statuses and callers reasonably handle `dismissed` only,\n // so `Skip tour` (`skipped`) and a target that goes missing (`not-found`) both closed the tour and\n // had it come straight back at step one. `undefined` as the initial value so an `open` that is\n // already true on mount still starts the tour.\n const { open } = tourOptions;\n const previousOpen = useRef<boolean | undefined>(undefined);\n useEffect(() => {\n if (open === undefined || open === previousOpen.current) {\n return;\n }\n\n previousOpen.current = open;\n\n if (open) {\n tour.start();\n } else {\n dismissRef.current();\n }\n // `tour` is a new object on every render, and reacting to the machine's own `open` is exactly\n // what this effect must not do.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n\n return { ...tour, dismiss, step: tour.step as BitkitTourStep | null };\n};\n\n// The Ark parts aren't Chakra components, so they're wrapped with the `chakra()` factory to accept\n// `css`. They're deliberately NOT wrapped with `asChild`: each Ark part falls back to the current\n// step's content (title, description, progress text, action label) only when it renders its own\n// children, and `asChild` would replace those children with the wrapper element.\nconst TourBackdrop = chakra(ArkTour.Backdrop);\nconst TourSpotlight = chakra(ArkTour.Spotlight);\nconst TourPositioner = chakra(ArkTour.Positioner);\nconst TourContent = chakra(ArkTour.Content);\nconst TourArrow = chakra(ArkTour.Arrow);\nconst TourArrowTip = chakra(ArkTour.ArrowTip);\nconst TourTitle = chakra(ArkTour.Title);\nconst TourDescription = chakra(ArkTour.Description);\nconst TourControl = chakra(ArkTour.Control);\nconst TourProgressText = chakra(ArkTour.ProgressText);\n\nconst SecondaryAction = ({ secondaryAction }: { secondaryAction: BitkitTourSecondaryAction }) => {\n const { action, href, label } = secondaryAction;\n\n if (href !== undefined) {\n return (\n <BitkitButton href={href} isExternal={secondaryAction.isExternal} size=\"sm\" variant=\"tertiary\">\n {label}\n </BitkitButton>\n );\n }\n\n if (!action) return null;\n\n return (\n <ArkTour.ActionTrigger asChild action={{ action, label }} aria-label={label}>\n <BitkitButton size=\"sm\" variant=\"tertiary\">\n {label}\n </BitkitButton>\n </ArkTour.ActionTrigger>\n );\n};\n\n/**\n * A guided product tour: a step card anchored to an element on the page, with a spotlight cut out\n * of the dimmed backdrop around that element.\n *\n * The steps and the tour behaviour live on the instance — create it with `useBitkitTour` and render\n * `BitkitTour` once, anywhere in the tree. Each step declares its own action buttons; the last one\n * is rendered as the primary button. A single-step tour drops the `1 of n` label, which is what\n * turns the card into the single-feature presentation.\n */\nconst BitkitTour = ({ tour }: BitkitTourProps) => {\n const recipe = useSlotRecipe({ key: 'tour' });\n const styles = recipe();\n const step = tour.step;\n const actions = step?.actions ?? [];\n\n // Zag traps focus with fixed options, so it lands on the card's first tabbable — the close button,\n // which means a screen reader opens the tour on `Close tour` instead of on what the step says. The\n // card is what should take it: Zag gives the content `role=\"alertdialog\"`, `tabIndex: -1` and the\n // `aria-labelledby`/`aria-describedby` pair exactly so it can be focused and read out. Measured\n // alternatives that don't work: making the card tabbable (the trap picks a descendant either way)\n // and a ref (it doesn't survive the `chakra()`-wrapped Ark part). This corrects the trap's choice\n // instead of trying to beat it — the trap activates asynchronously too, and racing it with a frame\n // loses whenever the first paint is slow. The listener takes the first focus that lands anywhere\n // in the card, moves it to the card itself and then steps out of the way, so everything after it\n // (Tab, the buttons, a click) behaves normally. It arms on open and not per step, so stepping on\n // keeps the focus on the button that did it, rather than pulling the next keystroke back to the\n // card. The lookup goes through the machine's own content id, so two mounted tours can't reach\n // each other's card.\n //\n // The tour machine is the one Zag component that can't be told where to put focus: `dialog` takes\n // an `initialFocusEl` and hands it to the same trap, and even defaults an `alertdialog` to its\n // close trigger deliberately. Once the tour has that prop too, this effect goes away.\n const { open } = tour;\n // Everything below reaches for the document through the environment rather than the global one:\n // under an `EnvironmentProvider` — a consumer rendering into an iframe — that is the document the\n // portal, and so the tour, actually lives in. Zag's own machines take the same route.\n const { getDocument } = useEnvironmentContext();\n\n // The tour machine has no scroll handling of its own — no `preventScroll` prop, no listener —\n // while Zag's dialog machine locks the body through this same helper. The tour needs it just as\n // much: everything it paints is positioned in document coordinates from a target it resolves once,\n // when the step opens, and never looks up again. Let the page scroll and any layout that swaps its\n // elements around — a sticky header that moves its buttons into a portal is the common one —\n // leaves the machine anchored to a node that is no longer in the document. A detached node\n // measures zero, so the card, the spotlight and the backdrop's cut-out all collapse into the\n // top-left corner of the page. Locking is the honest reading of the presentation anyway: the tour\n // dims the page and takes focus, exactly like a modal dialog.\n // Not on iOS, where the helper pins `<body>` with `position: fixed` instead of hiding the\n // overflow: from there the machine's `scrollIntoView` on step entry can't move the viewport, so a\n // target below the fold is unreachable and the tour locks the user onto a step they can't see —\n // worse than the misalignment the lock is here to prevent. (`overflow: hidden` leaves programmatic\n // scrolling alone, which is what makes the lock safe everywhere else.)\n useEffect(() => (open && !isIos() ? preventBodyScroll(getDocument()) : undefined), [getDocument, open]);\n\n const contentId = tour.getContentProps().id;\n useEffect(() => {\n if (!open || contentId === undefined) {\n return undefined;\n }\n\n const contentEl = getDocument().getElementById(contentId);\n if (!contentEl) {\n return undefined;\n }\n\n const takeFocus = () => {\n contentEl.removeEventListener('focusin', takeFocus);\n // `preventScroll`, because this runs before Popper has placed the card, and until then the\n // card is parked off-screen at `-100vh` — a plain `focus()` scrolls the page up to it and\n // leaves the user looking at the top of the page with a tour they can't see. Zag passes the\n // same option everywhere it moves focus itself.\n contentEl.focus({ preventScroll: true });\n };\n\n contentEl.addEventListener('focusin', takeFocus);\n\n return () => contentEl.removeEventListener('focusin', takeFocus);\n }, [contentId, getDocument, open]);\n\n return (\n // `unmountOnExit` so a closed tour leaves nothing behind: the card, the backdrop and the\n // spotlight are all page-level overlays, and there is no state to keep alive between two runs.\n // The cast is the price of refining `step` and the step-mutating methods on the instance: our\n // step type isn't a supertype of Ark's, so the methods no longer match its api signature. The\n // object is Ark's api — only the types are ours.\n <ArkTour.Root unmountOnExit tour={tour as UseTourReturn}>\n <Portal>\n <TourBackdrop css={styles.backdrop} />\n <TourSpotlight css={styles.spotlight} />\n <TourPositioner css={styles.positioner}>\n <TourContent css={styles.content}>\n {/* `hidden={false}` overrides Zag, which hides the arrow until the card has been\n positioned — while Popper computes that position from the arrow's `clientHeight`, so\n a hidden arrow measures 0 and the card lands 6 short of the design's 12, then drops\n by that 6 as soon as anything recomputes. Nothing shows in the meantime: until it is\n positioned the card itself sits off-screen at `-100vh`. */}\n <TourArrow css={styles.arrow} hidden={false}>\n <TourArrowTip css={styles.arrowTip} />\n </TourArrow>\n <Box css={styles.header}>\n <Box css={styles.titleGroup}>\n {tour.totalSteps > 1 ? <TourProgressText css={styles.progressText} /> : null}\n <Box css={styles.titleRow}>\n <TourTitle css={styles.title} />\n {step?.badge ? <Box css={styles.badge}>{step.badge}</Box> : null}\n </Box>\n </Box>\n <ArkTour.CloseTrigger asChild>\n <BitkitCloseButton css={styles.closeTrigger} size=\"xs\" />\n </ArkTour.CloseTrigger>\n </Box>\n <TourDescription css={styles.description} />\n {step?.content ? <Box css={styles.media}>{step.content}</Box> : null}\n <TourControl css={styles.control}>\n {step?.secondaryAction ? <SecondaryAction secondaryAction={step.secondaryAction} /> : null}\n <Box css={styles.actions}>\n {actions.map((action, index) => (\n // Zag labels the trigger from its own translations (`close tour`, `next step`),\n // which would override the visible text as the accessible name — and put two\n // `Close tour` buttons on a card whose dismiss action reads `Got it`.\n <ArkTour.ActionTrigger key={action.label} asChild action={action} aria-label={action.label}>\n <BitkitButton size=\"sm\" variant={index === actions.length - 1 ? 'primary' : 'secondary'}>\n {action.label}\n </BitkitButton>\n </ArkTour.ActionTrigger>\n ))}\n </Box>\n </TourControl>\n </TourContent>\n </TourPositioner>\n </Portal>\n </ArkTour.Root>\n );\n};\n\nBitkitTour.displayName = 'BitkitTour';\n\nexport default BitkitTour;\n"],"mappings":"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"}
@@ -20,8 +20,7 @@ var tourSlotRecipe = defineSlotRecipe({
20
20
  _open: {
21
21
  animationStyle: "fade-in",
22
22
  animationDuration: "moderate"
23
- },
24
- _closed: { display: "none" }
23
+ }
25
24
  },
26
25
  spotlight: {
27
26
  borderRadius: "4",
@@ -1 +1 @@
1
- {"version":3,"file":"Tour.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/Tour.recipe.ts"],"sourcesContent":["// The Tour parts come from Ark UI, so the anatomy comes from there too — Chakra has no `tour`\n// counterpart yet (chakra-ui/chakra-ui#10410 is still open).\nimport { tourAnatomy } from '@ark-ui/react/anatomy';\nimport { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { rem } from '../themeUtils';\n\nconst tourSlotRecipe = defineSlotRecipe({\n className: 'tour',\n slots: [...tourAnatomy.keys(), 'actions', 'badge', 'header', 'media', 'titleGroup', 'titleRow'] as const,\n base: {\n backdrop: {\n background: 'utilities/overlay',\n zIndex: 'dialogOverlay',\n _open: {\n animationStyle: 'fade-in',\n animationDuration: 'moderate',\n },\n // No exit animation: Ark sets `hidden` on the backdrop and the content the moment the tour\n // closes, so the node is `display: none` in the same frame and an exit animation can never\n // paint — it only leaves the animation assigned, which flashes the card back in for a frame\n // on the next render. Most visible on steps without a backdrop, where nothing masks it.\n //\n // And this is what keeps the dimming off the page once the tour is over. Ark's `Tour.Backdrop`\n // writes `hidden={!tour.step?.backdrop}` *after* every other prop, Zag defaults `backdrop` to\n // true on a tooltip step, and the step outlives the tour — so a backdrop still in the DOM when\n // the tour closes is visible, whatever its `data-state` says. `unmountOnExit` is meant to take\n // it out first, but that goes through the presence machine, which reads the computed\n // `animation-name` in a `raf` and, on anything other than `none`, waits for an `animationend`\n // that never arrives — leaving the page dimmed for good. Seen in production, on a page that\n // re-renders while the tour closes. `display: none` needs nothing to happen at the right time.\n _closed: {\n display: 'none',\n },\n },\n // Sits on the same layer as the backdrop and after it in DOM order, so the ring around the\n // highlighted element paints over the dimmed page.\n spotlight: {\n borderRadius: '4',\n outline: '2px solid',\n outlineColor: 'interactive/highlight',\n zIndex: 'dialogOverlay',\n },\n // Zag positions and layers this one inline, writing\n // `z-index: calc(var(--tour-layer) + var(--tour-z-index))` and expecting us to supply the base.\n // Without it the calc is invalid, the positioner falls back to `auto` — and since it opens its\n // own stacking context (`isolation: isolate`), the card's own z-index can't reach past it, so\n // the whole card ends up under the backdrop and swallows every click. The plain `zIndex` is the\n // fallback for the day Zag stops writing that inline.\n positioner: {\n '--tour-z-index': 'zIndex.dialog',\n zIndex: 'dialog',\n },\n content: {\n background: 'background/primary',\n borderRadius: '8',\n boxShadow: 'elevation/lg',\n display: 'flex',\n flexDirection: 'column',\n gap: '8',\n maxHeight: 'var(--available-height, 100dvh)',\n maxWidth: '100%',\n outline: 'none',\n padding: '16',\n position: 'relative',\n width: rem(360),\n zIndex: 'dialog',\n // Fade only, no scale: Zag puts `--transform-origin` at the arrow tip, so a `scale-in` grows\n // the card away from the highlight — a 360x300 card gains ~15 of height on the way in, which\n // reads as the card repositioning itself rather than appearing.\n _open: {\n animationStyle: 'fade-in',\n animationDuration: 'moderate',\n },\n },\n header: {\n alignItems: 'flex-start',\n display: 'flex',\n gap: '16',\n justifyContent: 'space-between',\n },\n titleGroup: {\n display: 'flex',\n flexDirection: 'column',\n gap: '8',\n },\n // flex-start, not center: the badge is as tall as one line of the title, so it lines up with\n // the first line instead of floating beside the middle of a title that wrapped.\n titleRow: {\n alignItems: 'flex-start',\n display: 'flex',\n gap: '8',\n },\n badge: {\n flexShrink: 0,\n },\n title: {\n color: 'text/primary',\n textStyle: 'heading/h4',\n },\n progressText: {\n color: 'text/secondary',\n textStyle: 'body/sm/regular',\n },\n description: {\n color: 'text/body',\n minHeight: 0,\n overflowY: 'auto',\n textStyle: 'body/md/regular',\n },\n // These two margins stack on the content's own 8 gap, which is how the layout spec builds the\n // spacing: 16 between the description and the visual, and 24 above the footer. The footer gets\n // nothing below it, so the card's own 16 padding is the whole gap under the buttons.\n media: {\n marginBlockStart: '8',\n },\n control: {\n alignItems: 'center',\n display: 'flex',\n gap: '16',\n justifyContent: 'space-between',\n marginBlockStart: '16',\n },\n actions: {\n display: 'flex',\n gap: '8',\n marginInlineStart: 'auto',\n },\n closeTrigger: {\n flexShrink: 0,\n },\n arrow: {\n // Popper draws the arrow as a square rotated 45°, so the visible triangle is `size * √2`\n // wide and `size / √2` tall — 11.3 gives the design's 16×8.\n '--arrow-size': rem(11.3),\n '--arrow-background': 'colors.background/primary',\n // Size and out-of-flow positioning are set here, not only by Popper's inline styles, because\n // the component keeps this element out of Zag's `hidden` (see BitkitTour): Popper derives the\n // card's distance from the anchor as `offset.mainAxis + arrowEl.clientHeight / 2`, read off\n // the DOM. A `display: none` arrow measures 0, which puts the card 6 short of the design's 12\n // on the first pass. `absolute` keeps it from adding its height to the card while it waits\n // for Popper's own inline placement.\n height: 'var(--arrow-size)',\n position: 'absolute',\n width: 'var(--arrow-size)',\n },\n arrowTip: {\n borderColor: 'border/minimal',\n borderInlineStartWidth: '1',\n borderTopWidth: '1',\n },\n },\n});\n\nexport default tourSlotRecipe;\n"],"mappings":";;;;AAOA,IAAM,iBAAiB,iBAAiB;CACtC,WAAW;CACX,OAAO;EAAC,GAAG,YAAY,KAAK;EAAG;EAAW;EAAS;EAAU;EAAS;EAAc;CAAU;CAC9F,MAAM;EACJ,UAAU;GACR,YAAY;GACZ,QAAQ;GACR,OAAO;IACL,gBAAgB;IAChB,mBAAmB;GACrB;GAcA,SAAS,EACP,SAAS,OACX;EACF;EAGA,WAAW;GACT,cAAc;GACd,SAAS;GACT,cAAc;GACd,QAAQ;EACV;EAOA,YAAY;GACV,kBAAkB;GAClB,QAAQ;EACV;EACA,SAAS;GACP,YAAY;GACZ,cAAc;GACd,WAAW;GACX,SAAS;GACT,eAAe;GACf,KAAK;GACL,WAAW;GACX,UAAU;GACV,SAAS;GACT,SAAS;GACT,UAAU;GACV,OAAO,IAAI,GAAG;GACd,QAAQ;GAIR,OAAO;IACL,gBAAgB;IAChB,mBAAmB;GACrB;EACF;EACA,QAAQ;GACN,YAAY;GACZ,SAAS;GACT,KAAK;GACL,gBAAgB;EAClB;EACA,YAAY;GACV,SAAS;GACT,eAAe;GACf,KAAK;EACP;EAGA,UAAU;GACR,YAAY;GACZ,SAAS;GACT,KAAK;EACP;EACA,OAAO,EACL,YAAY,EACd;EACA,OAAO;GACL,OAAO;GACP,WAAW;EACb;EACA,cAAc;GACZ,OAAO;GACP,WAAW;EACb;EACA,aAAa;GACX,OAAO;GACP,WAAW;GACX,WAAW;GACX,WAAW;EACb;EAIA,OAAO,EACL,kBAAkB,IACpB;EACA,SAAS;GACP,YAAY;GACZ,SAAS;GACT,KAAK;GACL,gBAAgB;GAChB,kBAAkB;EACpB;EACA,SAAS;GACP,SAAS;GACT,KAAK;GACL,mBAAmB;EACrB;EACA,cAAc,EACZ,YAAY,EACd;EACA,OAAO;GAGL,gBAAgB,IAAI,IAAI;GACxB,sBAAsB;GAOtB,QAAQ;GACR,UAAU;GACV,OAAO;EACT;EACA,UAAU;GACR,aAAa;GACb,wBAAwB;GACxB,gBAAgB;EAClB;CACF;AACF,CAAC"}
1
+ {"version":3,"file":"Tour.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/Tour.recipe.ts"],"sourcesContent":["// The Tour parts come from Ark UI, so the anatomy comes from there too — Chakra has no `tour`\n// counterpart yet (chakra-ui/chakra-ui#10410 is still open).\nimport { tourAnatomy } from '@ark-ui/react/anatomy';\nimport { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { rem } from '../themeUtils';\n\nconst tourSlotRecipe = defineSlotRecipe({\n className: 'tour',\n slots: [...tourAnatomy.keys(), 'actions', 'badge', 'header', 'media', 'titleGroup', 'titleRow'] as const,\n base: {\n backdrop: {\n background: 'utilities/overlay',\n zIndex: 'dialogOverlay',\n _open: {\n animationStyle: 'fade-in',\n animationDuration: 'moderate',\n },\n // No exit animation: Ark sets `hidden` on the backdrop and the content the moment the tour\n // closes, so the node is `display: none` in the same frame and an exit animation can never\n // paint — it only leaves the animation assigned, which flashes the card back in for a frame\n // on the next render. Most visible on steps without a backdrop, where nothing masks it.\n },\n // Sits on the same layer as the backdrop and after it in DOM order, so the ring around the\n // highlighted element paints over the dimmed page.\n spotlight: {\n borderRadius: '4',\n outline: '2px solid',\n outlineColor: 'interactive/highlight',\n zIndex: 'dialogOverlay',\n },\n // Zag positions and layers this one inline, writing\n // `z-index: calc(var(--tour-layer) + var(--tour-z-index))` and expecting us to supply the base.\n // Without it the calc is invalid, the positioner falls back to `auto` — and since it opens its\n // own stacking context (`isolation: isolate`), the card's own z-index can't reach past it, so\n // the whole card ends up under the backdrop and swallows every click. The plain `zIndex` is the\n // fallback for the day Zag stops writing that inline.\n positioner: {\n '--tour-z-index': 'zIndex.dialog',\n zIndex: 'dialog',\n },\n content: {\n background: 'background/primary',\n borderRadius: '8',\n boxShadow: 'elevation/lg',\n display: 'flex',\n flexDirection: 'column',\n gap: '8',\n maxHeight: 'var(--available-height, 100dvh)',\n maxWidth: '100%',\n outline: 'none',\n padding: '16',\n position: 'relative',\n width: rem(360),\n zIndex: 'dialog',\n // Fade only, no scale: Zag puts `--transform-origin` at the arrow tip, so a `scale-in` grows\n // the card away from the highlight — a 360x300 card gains ~15 of height on the way in, which\n // reads as the card repositioning itself rather than appearing.\n _open: {\n animationStyle: 'fade-in',\n animationDuration: 'moderate',\n },\n },\n header: {\n alignItems: 'flex-start',\n display: 'flex',\n gap: '16',\n justifyContent: 'space-between',\n },\n titleGroup: {\n display: 'flex',\n flexDirection: 'column',\n gap: '8',\n },\n // flex-start, not center: the badge is as tall as one line of the title, so it lines up with\n // the first line instead of floating beside the middle of a title that wrapped.\n titleRow: {\n alignItems: 'flex-start',\n display: 'flex',\n gap: '8',\n },\n badge: {\n flexShrink: 0,\n },\n title: {\n color: 'text/primary',\n textStyle: 'heading/h4',\n },\n progressText: {\n color: 'text/secondary',\n textStyle: 'body/sm/regular',\n },\n description: {\n color: 'text/body',\n minHeight: 0,\n overflowY: 'auto',\n textStyle: 'body/md/regular',\n },\n // These two margins stack on the content's own 8 gap, which is how the layout spec builds the\n // spacing: 16 between the description and the visual, and 24 above the footer. The footer gets\n // nothing below it, so the card's own 16 padding is the whole gap under the buttons.\n media: {\n marginBlockStart: '8',\n },\n control: {\n alignItems: 'center',\n display: 'flex',\n gap: '16',\n justifyContent: 'space-between',\n marginBlockStart: '16',\n },\n actions: {\n display: 'flex',\n gap: '8',\n marginInlineStart: 'auto',\n },\n closeTrigger: {\n flexShrink: 0,\n },\n arrow: {\n // Popper draws the arrow as a square rotated 45°, so the visible triangle is `size * √2`\n // wide and `size / √2` tall — 11.3 gives the design's 16×8.\n '--arrow-size': rem(11.3),\n '--arrow-background': 'colors.background/primary',\n // Size and out-of-flow positioning are set here, not only by Popper's inline styles, because\n // the component keeps this element out of Zag's `hidden` (see BitkitTour): Popper derives the\n // card's distance from the anchor as `offset.mainAxis + arrowEl.clientHeight / 2`, read off\n // the DOM. A `display: none` arrow measures 0, which puts the card 6 short of the design's 12\n // on the first pass. `absolute` keeps it from adding its height to the card while it waits\n // for Popper's own inline placement.\n height: 'var(--arrow-size)',\n position: 'absolute',\n width: 'var(--arrow-size)',\n },\n arrowTip: {\n borderColor: 'border/minimal',\n borderInlineStartWidth: '1',\n borderTopWidth: '1',\n },\n },\n});\n\nexport default tourSlotRecipe;\n"],"mappings":";;;;AAOA,IAAM,iBAAiB,iBAAiB;CACtC,WAAW;CACX,OAAO;EAAC,GAAG,YAAY,KAAK;EAAG;EAAW;EAAS;EAAU;EAAS;EAAc;CAAU;CAC9F,MAAM;EACJ,UAAU;GACR,YAAY;GACZ,QAAQ;GACR,OAAO;IACL,gBAAgB;IAChB,mBAAmB;GACrB;EAKF;EAGA,WAAW;GACT,cAAc;GACd,SAAS;GACT,cAAc;GACd,QAAQ;EACV;EAOA,YAAY;GACV,kBAAkB;GAClB,QAAQ;EACV;EACA,SAAS;GACP,YAAY;GACZ,cAAc;GACd,WAAW;GACX,SAAS;GACT,eAAe;GACf,KAAK;GACL,WAAW;GACX,UAAU;GACV,SAAS;GACT,SAAS;GACT,UAAU;GACV,OAAO,IAAI,GAAG;GACd,QAAQ;GAIR,OAAO;IACL,gBAAgB;IAChB,mBAAmB;GACrB;EACF;EACA,QAAQ;GACN,YAAY;GACZ,SAAS;GACT,KAAK;GACL,gBAAgB;EAClB;EACA,YAAY;GACV,SAAS;GACT,eAAe;GACf,KAAK;EACP;EAGA,UAAU;GACR,YAAY;GACZ,SAAS;GACT,KAAK;EACP;EACA,OAAO,EACL,YAAY,EACd;EACA,OAAO;GACL,OAAO;GACP,WAAW;EACb;EACA,cAAc;GACZ,OAAO;GACP,WAAW;EACb;EACA,aAAa;GACX,OAAO;GACP,WAAW;GACX,WAAW;GACX,WAAW;EACb;EAIA,OAAO,EACL,kBAAkB,IACpB;EACA,SAAS;GACP,YAAY;GACZ,SAAS;GACT,KAAK;GACL,gBAAgB;GAChB,kBAAkB;EACpB;EACA,SAAS;GACP,SAAS;GACT,KAAK;GACL,mBAAmB;EACrB;EACA,cAAc,EACZ,YAAY,EACd;EACA,OAAO;GAGL,gBAAgB,IAAI,IAAI;GACxB,sBAAsB;GAOtB,QAAQ;GACR,UAAU;GACV,OAAO;EACT;EACA,UAAU;GACR,aAAa;GACb,wBAAwB;GACxB,gBAAgB;EAClB;CACF;AACF,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bitrise/bitkit-v2",
3
3
  "private": false,
4
- "version": "0.3.386",
4
+ "version": "0.3.387",
5
5
  "description": "Bitrise Design System Components built with Chakra UI V3",
6
6
  "keywords": [
7
7
  "react",
@@ -95,7 +95,7 @@
95
95
  "vite-plugin-svgr": "^5.2.0"
96
96
  },
97
97
  "dependencies": {
98
- "@ark-ui/react": "5.39.1",
98
+ "@ark-ui/react": "5.39.2",
99
99
  "@fontsource-variable/figtree": "^5.3.0",
100
100
  "@fontsource-variable/source-code-pro": "^5.3.0",
101
101
  "@zag-js/dom-query": "1.43.3",