@techsio/ui-kit 0.44.1 → 0.46.0

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.
Files changed (47) hide show
  1. package/dist/atoms/hotkeys.js +52 -0
  2. package/dist/hotkeys.js +108 -0
  3. package/dist/internal/molecules/command.context.js +14 -0
  4. package/dist/molecules/command.js +177 -0
  5. package/dist/molecules/tour.js +318 -0
  6. package/dist/src/atoms/hotkeys.d.ts +29 -0
  7. package/dist/src/atoms/hotkeys.d.ts.map +1 -0
  8. package/dist/src/hotkeys.d.ts +19 -0
  9. package/dist/src/hotkeys.d.ts.map +1 -0
  10. package/dist/src/internal/molecules/command.context.d.ts +6 -0
  11. package/dist/src/internal/molecules/command.context.d.ts.map +1 -0
  12. package/dist/src/molecules/command.d.ts +51 -0
  13. package/dist/src/molecules/command.d.ts.map +1 -0
  14. package/dist/src/molecules/toast.d.ts +9 -9
  15. package/dist/src/molecules/tour.d.ts +72 -0
  16. package/dist/src/molecules/tour.d.ts.map +1 -0
  17. package/dist/src/types/zag.d.ts +2 -0
  18. package/dist/src/types/zag.d.ts.map +1 -1
  19. package/dist/stories/atoms/hotkeys-hydration.fixture.d.ts +6 -0
  20. package/dist/stories/atoms/hotkeys-hydration.fixture.d.ts.map +1 -0
  21. package/dist/stories/atoms/hotkeys.stories.d.ts +336 -0
  22. package/dist/stories/atoms/hotkeys.stories.d.ts.map +1 -0
  23. package/dist/stories/changelog/changelog.stories.d.ts +1 -1
  24. package/dist/stories/changelog/changelog.stories.d.ts.map +1 -1
  25. package/dist/stories/molecules/command-hotkeys.stories.d.ts +38 -0
  26. package/dist/stories/molecules/command-hotkeys.stories.d.ts.map +1 -0
  27. package/dist/stories/molecules/command.stories.d.ts +74 -0
  28. package/dist/stories/molecules/command.stories.d.ts.map +1 -0
  29. package/dist/stories/molecules/tour.stories.d.ts +58 -0
  30. package/dist/stories/molecules/tour.stories.d.ts.map +1 -0
  31. package/dist/test/command-hotkeys.spec.d.ts +2 -0
  32. package/dist/test/command-hotkeys.spec.d.ts.map +1 -0
  33. package/dist/test/command.spec.d.ts +2 -0
  34. package/dist/test/command.spec.d.ts.map +1 -0
  35. package/dist/test/hotkeys.spec.d.ts +2 -0
  36. package/dist/test/hotkeys.spec.d.ts.map +1 -0
  37. package/dist/test/tour.playwright.config.d.ts +4 -0
  38. package/dist/test/tour.playwright.config.d.ts.map +1 -0
  39. package/dist/test/tour.spec.d.ts +2 -0
  40. package/dist/test/tour.spec.d.ts.map +1 -0
  41. package/dist/test/tour.typecheck.d.ts +11 -0
  42. package/dist/test/tour.typecheck.d.ts.map +1 -0
  43. package/package.json +7 -1
  44. package/src/tokens/components/atoms/_hotkeys.css +36 -0
  45. package/src/tokens/components/components.css +3 -0
  46. package/src/tokens/components/molecules/_command.css +43 -0
  47. package/src/tokens/components/molecules/_tour.css +121 -0
@@ -0,0 +1,52 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useFormatHotkey } from "../hotkeys.js";
3
+ import { tv } from "../utils.js";
4
+ const hotkeysStyles = tv({
5
+ slots: {
6
+ root: "inline-flex items-center gap-hotkeys whitespace-nowrap font-hotkeys text-hotkeys-sm",
7
+ key: "hotkeys-key-border-width inline-flex items-center justify-center rounded-hotkeys-key border-hotkeys-key-border bg-hotkeys-key-bg px-hotkeys-key-x py-hotkeys-key-y text-hotkeys-key-fg",
8
+ separator: "text-hotkeys-separator-fg"
9
+ }
10
+ });
11
+ function Hotkeys({ hotkey, formatOptions, children, className, ref, ...props }) {
12
+ const format = useFormatHotkey();
13
+ return /*#__PURE__*/ jsx("span", {
14
+ ...props,
15
+ className: hotkeysStyles().root({
16
+ className
17
+ }),
18
+ "data-part": "root",
19
+ "data-scope": "hotkeys",
20
+ ref: ref,
21
+ children: children ?? (void 0 !== hotkey ? /*#__PURE__*/ jsx(Hotkeys.Key, {
22
+ children: format(hotkey, formatOptions)
23
+ }) : null)
24
+ });
25
+ }
26
+ Hotkeys.Key = function({ className, ref, ...props }) {
27
+ return /*#__PURE__*/ jsx("kbd", {
28
+ ...props,
29
+ className: hotkeysStyles().key({
30
+ className
31
+ }),
32
+ "data-part": "key",
33
+ "data-scope": "hotkeys",
34
+ ref: ref
35
+ });
36
+ };
37
+ Hotkeys.Separator = function({ children = "+", className, ref, ...props }) {
38
+ return /*#__PURE__*/ jsx("span", {
39
+ ...props,
40
+ "aria-hidden": "true",
41
+ className: hotkeysStyles().separator({
42
+ className
43
+ }),
44
+ "data-part": "separator",
45
+ "data-scope": "hotkeys",
46
+ ref: ref,
47
+ children: children
48
+ });
49
+ };
50
+ Hotkeys.Root = Hotkeys;
51
+ Hotkeys.displayName = "Hotkeys";
52
+ export { Hotkeys };
@@ -0,0 +1,108 @@
1
+ import { createHotkeyStore, formatHotkey } from "@zag-js/hotkeys";
2
+ import { useEffect, useId, useLayoutEffect, useMemo, useRef, useSyncExternalStore } from "react";
3
+ function useHotkey({ store, id, ...command }) {
4
+ const generatedId = useId();
5
+ useHotkeys({
6
+ store,
7
+ commands: [
8
+ {
9
+ ...command,
10
+ id: id ?? generatedId
11
+ }
12
+ ]
13
+ });
14
+ }
15
+ function sameValues(left, right) {
16
+ if (Object.is(left, right)) return true;
17
+ return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index)=>Object.is(value, right[index]));
18
+ }
19
+ function sameOptions(left, right) {
20
+ return left?.capture === right?.capture && left?.eventType === right?.eventType && left?.preventDefault === right?.preventDefault && left?.stopPropagation === right?.stopPropagation && left?.requireReset === right?.requireReset && left?.enableOnContentEditable === right?.enableOnContentEditable && sameValues(left?.enableOnFormTags, right?.enableOnFormTags) && left?.target === right?.target;
21
+ }
22
+ function sameRegistration(left, right) {
23
+ return left.hotkey === right.hotkey && left.label === right.label && left.description === right.description && left.category === right.category && sameValues(left.scopes, right.scopes) && sameValues(left.keywords, right.keywords) && sameOptions(left.options, right.options);
24
+ }
25
+ function readEnabled(command) {
26
+ const value = command?.enabled;
27
+ return "function" == typeof value ? value() : value ?? false;
28
+ }
29
+ function syncCommand(store, command, previous, getCurrent) {
30
+ const enabled = "function" == typeof command.enabled ? ()=>readEnabled(getCurrent()) : command.enabled ?? true;
31
+ const enabledUnchanged = previous?.enabled === command.enabled || "function" == typeof previous?.enabled && "function" == typeof command.enabled;
32
+ if (previous && sameRegistration(previous, command)) {
33
+ if (!enabledUnchanged) store.setEnabled(command.id, enabled);
34
+ return;
35
+ }
36
+ if (previous) store.unregister(command.id);
37
+ store.register({
38
+ ...command,
39
+ action: (event)=>getCurrent()?.action(event),
40
+ enabled
41
+ });
42
+ }
43
+ function useHotkeys({ store, commands }) {
44
+ const current = useRef(commands);
45
+ const registered = useRef(new Map());
46
+ useLayoutEffect(()=>{
47
+ current.current = commands;
48
+ });
49
+ useEffect(()=>{
50
+ const owned = registered.current;
51
+ return ()=>{
52
+ for (const id of owned.keys())store.unregister(id);
53
+ owned.clear();
54
+ };
55
+ }, [
56
+ store
57
+ ]);
58
+ useEffect(()=>{
59
+ const owned = registered.current;
60
+ for (const id of owned.keys())if (!commands.some((command)=>command.id === id)) {
61
+ owned.delete(id);
62
+ store.unregister(id);
63
+ }
64
+ for (const command of commands){
65
+ const previous = owned.get(command.id);
66
+ owned.set(command.id, command);
67
+ syncCommand(store, command, previous, ()=>current.current.find((item)=>item.id === command.id));
68
+ }
69
+ });
70
+ }
71
+ const emptyRegistrations = [];
72
+ const getServerRegistrations = ()=>emptyRegistrations;
73
+ function useHotkeyRegistrations({ store }) {
74
+ const subscription = useMemo(()=>{
75
+ let snapshot = [];
76
+ const getSnapshot = ()=>{
77
+ const commands = [
78
+ ...store.getState().commands.values()
79
+ ];
80
+ if (commands.length !== snapshot.length || commands.some((command, index)=>{
81
+ const previous = snapshot[index];
82
+ return !previous || command._registrationOrder !== previous._registrationOrder || command.enabled !== previous.enabled || command.options !== previous.options || command._parsed !== previous._parsed;
83
+ })) snapshot = commands.map((command)=>({
84
+ ...command
85
+ }));
86
+ return snapshot;
87
+ };
88
+ return {
89
+ getSnapshot,
90
+ subscribe: (notify)=>store.subscribe(getSnapshot, notify)
91
+ };
92
+ }, [
93
+ store
94
+ ]);
95
+ return useSyncExternalStore(subscription.subscribe, subscription.getSnapshot, getServerRegistrations);
96
+ }
97
+ const subscribeToHydration = ()=>()=>{};
98
+ const getClientHydration = ()=>true;
99
+ const getServerHydration = ()=>false;
100
+ function useFormatHotkey() {
101
+ const hydrated = useSyncExternalStore(subscribeToHydration, getClientHydration, getServerHydration);
102
+ const defaultPlatform = hydrated ? "auto" : "windows";
103
+ return (hotkey, options)=>formatHotkey(hotkey, {
104
+ ...options,
105
+ platform: options?.platform && "auto" !== options.platform ? options.platform : defaultPlatform
106
+ });
107
+ }
108
+ export { createHotkeyStore, useFormatHotkey, useHotkey, useHotkeyRegistrations, useHotkeys };
@@ -0,0 +1,14 @@
1
+ import { createContext, useContext } from "react";
2
+ const CommandContext = createContext(null);
3
+ const CommandItemContext = createContext(null);
4
+ function useCommandContext() {
5
+ const api = useContext(CommandContext);
6
+ if (!api) throw new Error("Command components must be used within Command.Root");
7
+ return api;
8
+ }
9
+ function useCommandItemContext() {
10
+ const item = useContext(CommandItemContext);
11
+ if (!item) throw new Error("Command.ItemText must be used within Command.Item");
12
+ return item;
13
+ }
14
+ export { CommandContext, CommandItemContext, useCommandContext, useCommandItemContext };
@@ -0,0 +1,177 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { createFilter } from "@zag-js/i18n-utils";
3
+ import { mergeProps, normalizeProps, useMachine } from "@zag-js/react";
4
+ import { useEffect, useId, useMemo, useState } from "react";
5
+ import { Input } from "../atoms/input.js";
6
+ import { Label } from "../atoms/label.js";
7
+ import { CommandContext, CommandItemContext, useCommandContext, useCommandItemContext } from "../internal/molecules/command.context.js";
8
+ import { tv } from "../utils.js";
9
+ import * as __rspack_external__zag_js_combobox_6371d768 from "@zag-js/combobox";
10
+ const commandVariants = tv({
11
+ slots: {
12
+ root: "command-border-width flex w-full flex-col gap-command-gap rounded-command border-command-border bg-command-bg p-command text-command-fg text-command-md",
13
+ control: "relative flex items-center",
14
+ list: "max-h-command-list-max overflow-y-auto overscroll-contain p-command-list",
15
+ item: "flex w-full cursor-pointer select-none items-center gap-command-item-gap rounded-command-item px-command-item-x py-command-item-y data-disabled:cursor-not-allowed data-highlighted:bg-command-item-bg-highlighted data-disabled:text-command-item-fg-disabled",
16
+ itemText: "min-w-0 flex-1",
17
+ itemGroup: "",
18
+ itemGroupLabel: "px-command-item-x py-command-item-y font-command-group-label text-command-group-label-fg",
19
+ empty: "text-center text-command-empty-fg data-empty:p-command-empty"
20
+ }
21
+ });
22
+ function Command({ items, children, id, className, ref, disabled, loopFocus = true, onSelect, locale, inputValue, defaultInputValue = "", onInputValueChange, onEscape }) {
23
+ const generatedId = useId();
24
+ const [uncontrolledQuery, setUncontrolledQuery] = useState(defaultInputValue);
25
+ const query = inputValue ?? uncontrolledQuery;
26
+ const collection = useMemo(()=>{
27
+ const filter = createFilter({
28
+ sensitivity: "base",
29
+ locale
30
+ });
31
+ return __rspack_external__zag_js_combobox_6371d768.collection({
32
+ items: items.filter((item)=>filter.contains(item.label, query) || item.keywords?.some((keyword)=>filter.contains(keyword, query))),
33
+ itemToValue: (item)=>item.value,
34
+ itemToString: (item)=>item.label,
35
+ isItemDisabled: (item)=>!!item.disabled
36
+ });
37
+ }, [
38
+ items,
39
+ query,
40
+ locale
41
+ ]);
42
+ const service = useMachine(__rspack_external__zag_js_combobox_6371d768.machine, {
43
+ id: id ?? generatedId,
44
+ collection,
45
+ disabled,
46
+ loopFocus,
47
+ onSelect,
48
+ inputValue: query,
49
+ onInputValueChange (details) {
50
+ if (void 0 === inputValue) setUncontrolledQuery(details.inputValue);
51
+ onInputValueChange?.(details);
52
+ },
53
+ onOpenChange (details) {
54
+ if (!details.open && "escape-key" === details.reason) onEscape?.();
55
+ },
56
+ open: true,
57
+ disableLayer: true,
58
+ inputBehavior: "autohighlight",
59
+ selectionBehavior: "preserve",
60
+ closeOnSelect: false
61
+ });
62
+ const api = __rspack_external__zag_js_combobox_6371d768.connect(service, normalizeProps);
63
+ useEffect(()=>{
64
+ if (api.collection.find(api.highlightedValue)?.disabled) api.clearHighlightValue();
65
+ }, [
66
+ api
67
+ ]);
68
+ return /*#__PURE__*/ jsx(CommandContext.Provider, {
69
+ value: api,
70
+ children: /*#__PURE__*/ jsx("div", {
71
+ ...api.getRootProps(),
72
+ className: commandVariants().root({
73
+ className
74
+ }),
75
+ ref: ref,
76
+ children: children
77
+ })
78
+ });
79
+ }
80
+ Command.Root = Command;
81
+ Command.Label = function({ children, ...props }) {
82
+ const api = useCommandContext();
83
+ return /*#__PURE__*/ jsx(Label, {
84
+ ...mergeProps(props, api.getLabelProps()),
85
+ children: children
86
+ });
87
+ };
88
+ Command.Control = function({ className, ...props }) {
89
+ const api = useCommandContext();
90
+ return /*#__PURE__*/ jsx("div", {
91
+ ...mergeProps(props, api.getControlProps()),
92
+ className: commandVariants().control({
93
+ className
94
+ })
95
+ });
96
+ };
97
+ Command.Input = function({ size, ...props }) {
98
+ const api = useCommandContext();
99
+ return /*#__PURE__*/ jsx(Input, {
100
+ ...mergeProps(props, api.getInputProps()),
101
+ size: size
102
+ });
103
+ };
104
+ Command.List = function({ className, ...props }) {
105
+ const api = useCommandContext();
106
+ return /*#__PURE__*/ jsx("div", {
107
+ ...mergeProps(props, api.getContentProps()),
108
+ className: commandVariants().list({
109
+ className
110
+ })
111
+ });
112
+ };
113
+ Command.ItemGroup = function({ id, className, ...props }) {
114
+ const api = useCommandContext();
115
+ return /*#__PURE__*/ jsx("div", {
116
+ ...mergeProps(props, api.getItemGroupProps({
117
+ id
118
+ })),
119
+ className: commandVariants().itemGroup({
120
+ className
121
+ })
122
+ });
123
+ };
124
+ Command.ItemGroupLabel = function({ htmlFor, className, ...props }) {
125
+ const api = useCommandContext();
126
+ return /*#__PURE__*/ jsx("div", {
127
+ ...mergeProps(props, api.getItemGroupLabelProps({
128
+ htmlFor
129
+ })),
130
+ className: commandVariants().itemGroupLabel({
131
+ className
132
+ })
133
+ });
134
+ };
135
+ Command.Item = function({ item, className, ...props }) {
136
+ const api = useCommandContext();
137
+ return /*#__PURE__*/ jsx(CommandItemContext.Provider, {
138
+ value: item,
139
+ children: /*#__PURE__*/ jsx("div", {
140
+ ...mergeProps(props, api.getItemProps({
141
+ item
142
+ })),
143
+ className: commandVariants().item({
144
+ className
145
+ })
146
+ })
147
+ });
148
+ };
149
+ Command.ItemText = function({ className, children, ...props }) {
150
+ const api = useCommandContext();
151
+ const item = useCommandItemContext();
152
+ return /*#__PURE__*/ jsx("span", {
153
+ ...mergeProps(props, api.getItemTextProps({
154
+ item
155
+ })),
156
+ className: commandVariants().itemText({
157
+ className
158
+ }),
159
+ children: children ?? item.label
160
+ });
161
+ };
162
+ Command.Context = function({ children }) {
163
+ return children(useCommandContext());
164
+ };
165
+ Command.Empty = function({ children, className, ...props }) {
166
+ const api = useCommandContext();
167
+ const empty = 0 === api.collection.size;
168
+ return /*#__PURE__*/ jsx("output", {
169
+ ...props,
170
+ className: commandVariants().empty({
171
+ className
172
+ }),
173
+ "data-empty": empty || void 0,
174
+ children: empty ? children : null
175
+ });
176
+ };
177
+ export { Command };
@@ -0,0 +1,318 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Portal, mergeProps, normalizeProps, useMachine } from "@zag-js/react";
3
+ import { connect, machine } from "@zag-js/tour";
4
+ import { createContext, useContext, useEffect, useId, useLayoutEffect, useRef } from "react";
5
+ import { ActionIcon } from "../atoms/action-icon.js";
6
+ import { Button } from "../atoms/button.js";
7
+ import { tv } from "../utils.js";
8
+ const tourStyles = tv({
9
+ slots: {
10
+ backdrop: "tour-layer bg-tour-backdrop-bg",
11
+ spotlight: "tour-layer tour-spotlight-border",
12
+ positioner: "tour-layer tour-positioner",
13
+ content: "tour-layer tour-content tour-border relative flex flex-col gap-tour-content rounded-tour bg-tour-bg p-tour text-tour-fg shadow-tour outline-none",
14
+ arrow: "tour-arrow",
15
+ arrowTip: "bg-tour-arrow-bg",
16
+ title: "pe-tour-title font-tour-title text-tour-title-size",
17
+ description: "text-tour-body-size text-tour-description-fg",
18
+ progressText: "text-tour-progress-fg text-tour-progress-size",
19
+ actions: "flex flex-wrap items-center justify-end gap-tour-actions pt-tour-actions",
20
+ closeTrigger: "absolute end-tour-close top-tour-close"
21
+ }
22
+ });
23
+ const TourContext = /*#__PURE__*/ createContext(null);
24
+ const useIsomorphicLayoutEffect = "u" < typeof window ? useEffect : useLayoutEffect;
25
+ function useTourContext() {
26
+ const api = useContext(TourContext);
27
+ if (!api) throw new Error("Tour components must be used within Tour.Root");
28
+ return api;
29
+ }
30
+ function Tour({ children, getRootNode, id, onStatusChange, steps, ...props }) {
31
+ const generatedId = useId();
32
+ const previousFocus = useRef(null);
33
+ const effectCleanup = useRef(void 0);
34
+ const service = useMachine(machine, {
35
+ ...props,
36
+ preventInteraction: false,
37
+ getRootNode,
38
+ id: id ?? generatedId,
39
+ steps: steps.map(prepareStep),
40
+ onStatusChange (details) {
41
+ if ("not-found" === details.status) effectCleanup.current?.();
42
+ if ("started" === details.status) {
43
+ const rootNode = getRootNode?.() ?? document;
44
+ const activeElement = "activeElement" in rootNode ? rootNode.activeElement : rootNode.ownerDocument?.activeElement;
45
+ previousFocus.current = activeElement instanceof HTMLElement ? activeElement : null;
46
+ } else if ("idle" !== details.status) {
47
+ const target = previousFocus.current;
48
+ previousFocus.current = null;
49
+ requestAnimationFrame(()=>{
50
+ if (target?.isConnected) target.focus({
51
+ preventScroll: true
52
+ });
53
+ });
54
+ }
55
+ onStatusChange?.(details);
56
+ }
57
+ });
58
+ function prepareStep(step) {
59
+ return {
60
+ ...step,
61
+ effect: step.effect && prepareEffect(step.effect)
62
+ };
63
+ }
64
+ function prepareEffect(effect) {
65
+ return (args)=>{
66
+ const cleanup = effect(args);
67
+ let cleaned = false;
68
+ const cleanupOnce = ()=>{
69
+ if (cleaned) return;
70
+ cleaned = true;
71
+ if (effectCleanup.current === cleanupOnce) effectCleanup.current = void 0;
72
+ cleanup?.();
73
+ };
74
+ effectCleanup.current = cleanupOnce;
75
+ return cleanupOnce;
76
+ };
77
+ }
78
+ const zag = connect(service, normalizeProps);
79
+ const handleKeyDown = (event)=>{
80
+ if (event.defaultPrevented || false === props.keyboardNavigation) return;
81
+ if (event.target instanceof Element && event.target.closest("input, textarea, select, [contenteditable='true']")) return;
82
+ const [nextKey, prevKey] = "rtl" === props.dir ? [
83
+ "ArrowLeft",
84
+ "ArrowRight"
85
+ ] : [
86
+ "ArrowRight",
87
+ "ArrowLeft"
88
+ ];
89
+ if (event.key === nextKey && zag.hasNextStep) {
90
+ event.preventDefault();
91
+ zag.next();
92
+ return;
93
+ }
94
+ if (event.key === prevKey && zag.hasPrevStep) {
95
+ event.preventDefault();
96
+ zag.prev();
97
+ }
98
+ };
99
+ const api = {
100
+ ...zag,
101
+ addStep: (step)=>zag.addStep(prepareStep(step)),
102
+ updateStep: (stepId, step)=>zag.updateStep(stepId, "effect" in step ? {
103
+ ...step,
104
+ effect: step.effect && prepareEffect(step.effect)
105
+ } : step),
106
+ setSteps: (nextSteps)=>zag.setSteps(nextSteps.map(prepareStep)),
107
+ getContentProps () {
108
+ return {
109
+ ...zag.getContentProps(),
110
+ onKeyDown: handleKeyDown
111
+ };
112
+ }
113
+ };
114
+ const activeTarget = api.step?.target?.();
115
+ useIsomorphicLayoutEffect(()=>{
116
+ if (!(api.open && props.preventInteraction && activeTarget) || activeTarget.inert) return;
117
+ activeTarget.inert = true;
118
+ let changedExternally = false;
119
+ const observer = new MutationObserver(()=>{
120
+ changedExternally = true;
121
+ });
122
+ observer.observe(activeTarget, {
123
+ attributes: true,
124
+ attributeFilter: [
125
+ "inert"
126
+ ]
127
+ });
128
+ return ()=>{
129
+ const hasExternalWrite = changedExternally || observer.takeRecords().length > 0;
130
+ observer.disconnect();
131
+ if (!hasExternalWrite) activeTarget.inert = false;
132
+ };
133
+ }, [
134
+ api.open,
135
+ props.preventInteraction,
136
+ activeTarget
137
+ ]);
138
+ useEffect(()=>()=>{
139
+ const target = previousFocus.current;
140
+ previousFocus.current = null;
141
+ queueMicrotask(()=>{
142
+ if (target?.isConnected) target.focus({
143
+ preventScroll: true
144
+ });
145
+ });
146
+ }, []);
147
+ return /*#__PURE__*/ jsx(TourContext.Provider, {
148
+ value: {
149
+ ...api,
150
+ isRunning: !service.state.matches("tourInactive")
151
+ },
152
+ children: children
153
+ });
154
+ }
155
+ Tour.Context = function({ children }) {
156
+ return children(useTourContext());
157
+ };
158
+ Tour.Trigger = function({ disabled, onClick, stepId, type = "button", ...props }) {
159
+ const api = useTourContext();
160
+ return /*#__PURE__*/ jsx(Button, {
161
+ ...props,
162
+ disabled: disabled || api.isRunning || 0 === api.totalSteps,
163
+ onClick: (event)=>{
164
+ onClick?.(event);
165
+ if (!event.defaultPrevented) api.start(stepId);
166
+ },
167
+ type: type
168
+ });
169
+ };
170
+ Tour.Portal = Portal;
171
+ Tour.Backdrop = function({ className, ref, ...props }) {
172
+ const api = useTourContext();
173
+ if (!(api.open && api.step?.backdrop)) return null;
174
+ return /*#__PURE__*/ jsx("div", {
175
+ ...mergeProps(props, api.getBackdropProps()),
176
+ className: tourStyles().backdrop({
177
+ className
178
+ }),
179
+ ref: ref
180
+ });
181
+ };
182
+ Tour.Spotlight = function({ className, ref, ...props }) {
183
+ const api = useTourContext();
184
+ if (!api.open || api.step?.type !== "tooltip") return null;
185
+ return /*#__PURE__*/ jsx("div", {
186
+ ...mergeProps(props, api.getSpotlightProps()),
187
+ className: tourStyles().spotlight({
188
+ className
189
+ }),
190
+ ref: ref
191
+ });
192
+ };
193
+ Tour.Positioner = function({ className, ref, ...props }) {
194
+ const api = useTourContext();
195
+ if (!api.open) return null;
196
+ return /*#__PURE__*/ jsx("div", {
197
+ ...mergeProps(props, api.getPositionerProps()),
198
+ className: tourStyles().positioner({
199
+ className
200
+ }),
201
+ ref: ref
202
+ });
203
+ };
204
+ Tour.Content = function({ className, ref, ...props }) {
205
+ const api = useTourContext();
206
+ return /*#__PURE__*/ jsx("div", {
207
+ ...mergeProps(props, api.getContentProps()),
208
+ className: tourStyles().content({
209
+ className
210
+ }),
211
+ ref: ref
212
+ });
213
+ };
214
+ Tour.Arrow = function({ children, className, ref, ...props }) {
215
+ const api = useTourContext();
216
+ if (!api.step?.arrow || "tooltip" !== api.step.type) return null;
217
+ return /*#__PURE__*/ jsx("div", {
218
+ ...mergeProps(props, api.getArrowProps()),
219
+ className: tourStyles().arrow({
220
+ className
221
+ }),
222
+ ref: ref,
223
+ children: children ?? /*#__PURE__*/ jsx(Tour.ArrowTip, {})
224
+ });
225
+ };
226
+ Tour.ArrowTip = function({ className, ref, ...props }) {
227
+ const api = useTourContext();
228
+ return /*#__PURE__*/ jsx("div", {
229
+ ...mergeProps(props, api.getArrowTipProps()),
230
+ className: tourStyles().arrowTip({
231
+ className
232
+ }),
233
+ ref: ref
234
+ });
235
+ };
236
+ Tour.Title = function({ children, className, ref, ...props }) {
237
+ const api = useTourContext();
238
+ return /*#__PURE__*/ jsx("div", {
239
+ ...mergeProps(props, api.getTitleProps()),
240
+ className: tourStyles().title({
241
+ className
242
+ }),
243
+ ref: ref,
244
+ children: children ?? api.step?.title
245
+ });
246
+ };
247
+ Tour.Description = function({ children, className, ref, ...props }) {
248
+ const api = useTourContext();
249
+ return /*#__PURE__*/ jsx("div", {
250
+ ...mergeProps(props, api.getDescriptionProps()),
251
+ className: tourStyles().description({
252
+ className
253
+ }),
254
+ ref: ref,
255
+ children: children ?? api.step?.description
256
+ });
257
+ };
258
+ Tour.ProgressText = function({ children, className, ref, ...props }) {
259
+ const api = useTourContext();
260
+ return /*#__PURE__*/ jsx("span", {
261
+ ...mergeProps(props, api.getProgressTextProps()),
262
+ className: tourStyles().progressText({
263
+ className
264
+ }),
265
+ ref: ref,
266
+ children: children ?? api.getProgressText()
267
+ });
268
+ };
269
+ Tour.Actions = function({ className, ref, ...props }) {
270
+ useTourContext();
271
+ return /*#__PURE__*/ jsx("div", {
272
+ ...props,
273
+ className: tourStyles().actions({
274
+ className
275
+ }),
276
+ ref: ref
277
+ });
278
+ };
279
+ Tour.ActionTrigger = function({ action, children, disabled, onClick, type = "button", ...props }) {
280
+ const api = useTourContext();
281
+ const { onClick: onMachineClick, disabled: machineDisabled, "aria-label": machineLabel, ...machineProps } = api.getActionTriggerProps({
282
+ action: {
283
+ action,
284
+ label: ""
285
+ }
286
+ });
287
+ return /*#__PURE__*/ jsx(Button, {
288
+ ...mergeProps(props, machineProps),
289
+ "aria-label": props["aria-label"] ?? (null != children ? void 0 : machineLabel),
290
+ disabled: disabled || machineDisabled,
291
+ onClick: (event)=>{
292
+ onClick?.(event);
293
+ if (!event.defaultPrevented) onMachineClick?.(event);
294
+ },
295
+ type: type,
296
+ children: children
297
+ });
298
+ };
299
+ Tour.CloseTrigger = function({ className, icon = "token-icon-close", onClick, ref, ...props }) {
300
+ const api = useTourContext();
301
+ const { onClick: onMachineClick, "aria-label": machineLabel, ...machineProps } = api.getCloseTriggerProps();
302
+ return /*#__PURE__*/ jsx(ActionIcon, {
303
+ ...mergeProps(props, machineProps),
304
+ "aria-label": props["aria-label"] ?? machineLabel,
305
+ className: tourStyles().closeTrigger({
306
+ className
307
+ }),
308
+ icon: icon,
309
+ onClick: (event)=>{
310
+ onClick?.(event);
311
+ if (!event.defaultPrevented) onMachineClick?.(event);
312
+ },
313
+ ref: ref
314
+ });
315
+ };
316
+ Tour.Root = Tour;
317
+ Tour.displayName = "Tour";
318
+ export { Tour };