Skip to content

Commit dfec9cc

Browse files
committed
add FocusChin to the guide toolbar v2 with dedicated controls
1 parent 1f8dc0a commit dfec9cc

File tree

4 files changed

+214
-39
lines changed

4 files changed

+214
-39
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import { useGuideContext, useStore } from "@knocklabs/react-core";
2+
import { Button } from "@telegraph/button";
3+
import { Box, Stack } from "@telegraph/layout";
4+
import { Tooltip } from "@telegraph/tooltip";
5+
import { Text } from "@telegraph/typography";
6+
import { ChevronLeft, ChevronRight, X } from "lucide-react";
7+
8+
import { DisplayOption } from "./helpers";
9+
// import React from "react";
10+
11+
import { InspectionResultOk } from "./useInspectGuideClientStore";
12+
13+
// const findNextPrevKey = (
14+
// currKey: string,
15+
// guides: InspectionResultOk["guides"]
16+
// ) => {
17+
// const selectableGuides = guides.filter(g => !!g.annotation.selectable);
18+
// const currIndex = selectableGuides.findIndex(g => g.key === currKey);
19+
//
20+
// const prevGuide = currIndex === 0
21+
// ? undefined
22+
// : selectableGuides[currIndex - 1];
23+
//
24+
// const nextGuide = currIndex + 1 > selectableGuides.length - 1
25+
// ? undefined
26+
// : selectableGuides[currIndex + 1];
27+
//
28+
// return { prev: prevGuide, next: nextGuide };
29+
// }
30+
// const findNextGuideKey = (
31+
// currKey: string,
32+
// guides: InspectionResultOk["guides"]
33+
// ) => {
34+
// const selectableGuides = guides.filter(g => !!g.annotation.selectable);
35+
// const currIndex = selectableGuides.findIndex(g => g.key === currKey);
36+
//
37+
// const prevGuide = currIndex === 0
38+
// ? undefined
39+
// : selectableGuides[currIndex - 1];
40+
//
41+
// const nextGuide = currIndex + 1 > selectableGuides.length - 1
42+
// ? undefined
43+
// : selectableGuides[currIndex + 1];
44+
//
45+
// return { prev: prevGuide, next: nextGuide };
46+
// }
47+
48+
type Props = {
49+
guides: InspectionResultOk["guides"];
50+
displayOption: DisplayOption;
51+
};
52+
53+
export const FocusChin = ({ guides, displayOption }: Props) => {
54+
const { client } = useGuideContext();
55+
const { debugSettings } = useStore(client.store, (state) => ({
56+
debugSettings: state.debug || {},
57+
}));
58+
59+
const focusedKeys = Object.keys(debugSettings.focusedGuideKeys || {});
60+
61+
// const { prev, next } = React.useMemo(() => {
62+
// if (focusedKeys.length === 0) {
63+
// return {}
64+
// }
65+
// const currentKey = focusedKeys[0];
66+
//
67+
// return findNextAndPrevGuideKey(currentKey, guides)
68+
// }, [displayOption, focusedKeys.length]);
69+
70+
const isFocused = focusedKeys.length > 0;
71+
if (!isFocused) {
72+
return null;
73+
}
74+
75+
const currentKey = focusedKeys[0];
76+
77+
// const currentIndex = currentKey ? guideKeys.indexOf(currentKey) : -1;
78+
79+
// const setFocus = (key: string) => {
80+
// client.setDebug({
81+
// ...debugSettings,
82+
// focusedGuideKeys: { [key]: true },
83+
// });
84+
// };
85+
//
86+
// const hasPrev = currentIndex > 0;
87+
// const hasNext = currentIndex >= 0 && currentIndex < guideKeys.length - 1;
88+
89+
return (
90+
<Box
91+
borderTop="px"
92+
px="3"
93+
py="1"
94+
overflow="hidden"
95+
backgroundColor="blue-2"
96+
>
97+
<Stack align="center" justify="space-between">
98+
<Text as="span" size="1" weight="medium" color="blue">
99+
Focus lock: {currentKey}
100+
</Text>
101+
<Stack align="center" gap="1">
102+
<Tooltip label="Focus previous guide">
103+
<Button
104+
size="0"
105+
variant="ghost"
106+
color="blue"
107+
leadingIcon={{ icon: ChevronLeft, alt: "Previous guide" }}
108+
// disabled={!hasPrev}
109+
onClick={() => {
110+
const selectableGuides = guides.filter(
111+
(g) => !!g.annotation.selectable.status,
112+
);
113+
const currIndex = selectableGuides.findIndex(
114+
(g) => g.key === currentKey,
115+
);
116+
117+
const prevGuide =
118+
currIndex === 0 ? undefined : selectableGuides[currIndex - 1];
119+
120+
if (!prevGuide) return;
121+
122+
client.setDebug({
123+
...debugSettings,
124+
focusedGuideKeys: { [prevGuide.key]: true },
125+
});
126+
}}
127+
/>
128+
</Tooltip>
129+
<Tooltip label="Focus next guide">
130+
<Button
131+
size="0"
132+
variant="ghost"
133+
color="blue"
134+
leadingIcon={{ icon: ChevronRight, alt: "Next guide" }}
135+
// disabled={!hasNext}
136+
onClick={() => {
137+
const selectableGuides = guides.filter(
138+
(g) => !!g.annotation.selectable.status,
139+
);
140+
console.log(1, selectableGuides);
141+
const currIndex = selectableGuides.findIndex(
142+
(g) => g.key === currentKey,
143+
);
144+
145+
const nextGuide =
146+
currIndex + 1 > selectableGuides.length - 1
147+
? undefined
148+
: selectableGuides[currIndex + 1];
149+
150+
if (!nextGuide) return;
151+
152+
client.setDebug({
153+
...debugSettings,
154+
focusedGuideKeys: { [nextGuide.key]: true },
155+
});
156+
}}
157+
/>
158+
</Tooltip>
159+
<Tooltip label="Exit focus lock">
160+
<Button
161+
size="0"
162+
variant="ghost"
163+
color="blue"
164+
leadingIcon={{ icon: X, alt: "Clear focus" }}
165+
onClick={() => {
166+
client.setDebug({ ...debugSettings, focusedGuideKeys: {} });
167+
}}
168+
/>
169+
</Tooltip>
170+
</Stack>
171+
</Stack>
172+
</Box>
173+
);
174+
};

packages/react/src/modules/guide/components/Toolbar/V2/V2.tsx

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ import { KnockButton } from "../KnockButton";
1919
import { TOOLBAR_Z_INDEX } from "../shared";
2020
import "../styles.css";
2121

22+
import { FocusChin } from "./FocusChin";
2223
import { GuideContextDetails } from "./GuideContextDetails";
2324
import { GuideRow } from "./GuideRow";
24-
import { clearRunConfigLS, getRunConfig } from "./helpers";
25+
import { DisplayOption, clearRunConfigLS, getRunConfig } from "./helpers";
2526
import { useDraggable } from "./useDraggable";
2627
import {
2728
InspectionResultOk,
@@ -46,46 +47,21 @@ const Kbd = ({ children }: { children: React.ReactNode }) => {
4647
);
4748
};
4849

49-
type DisplayOption = "all-guides" | "only-eligible" | "only-displayable";
50-
51-
const GuidesList = ({
52-
guides,
53-
displayOption,
54-
}: {
55-
guides: InspectionResultOk["guides"];
56-
displayOption: DisplayOption;
57-
}) => {
58-
const [expandedGuideRowKey, setExpandedGuideRowKey] = React.useState<
59-
string | undefined
60-
>();
61-
62-
React.useEffect(() => {
63-
setExpandedGuideRowKey(undefined);
64-
}, [displayOption]);
65-
66-
return guides.map((guide, idx) => {
50+
const filterGuides = (
51+
guides: InspectionResultOk["guides"],
52+
displayOption: DisplayOption,
53+
) => {
54+
return guides.filter((guide) => {
6755
const { isEligible, isQualified } = guide.annotation;
6856
const isDisplayable = isEligible && isQualified;
6957

7058
if (displayOption === "only-displayable" && !isDisplayable) {
71-
return null;
59+
return false;
7260
}
7361
if (displayOption === "only-eligible" && !isEligible) {
74-
return null;
62+
return false;
7563
}
76-
return (
77-
<GuideRow
78-
key={guide.key}
79-
guide={guide}
80-
orderIndex={idx}
81-
isExpanded={guide.key === expandedGuideRowKey}
82-
onClick={() => {
83-
setExpandedGuideRowKey((k) =>
84-
k && k === guide.key ? undefined : guide.key,
85-
);
86-
}}
87-
/>
88-
);
64+
return true;
8965
});
9066
};
9167

@@ -98,6 +74,14 @@ export const V2 = () => {
9874
const [isCollapsed, setIsCollapsed] = React.useState(false);
9975
const [isContextPanelOpen, setIsContextPanelOpen] = React.useState(false);
10076

77+
const [expandedGuideRowKey, setExpandedGuideRowKey] = React.useState<
78+
string | undefined
79+
>();
80+
81+
React.useEffect(() => {
82+
setExpandedGuideRowKey(undefined);
83+
}, [displayOption]);
84+
10185
React.useEffect(() => {
10286
const { isVisible = false, focusedGuideKeys = {} } = runConfig || {};
10387
const isDebugging = client.store.state.debug?.debugging;
@@ -155,6 +139,9 @@ export const V2 = () => {
155139
return null;
156140
}
157141

142+
const guides =
143+
result.status === "ok" ? filterGuides(result.guides, displayOption) : [];
144+
158145
return (
159146
<Box
160147
tgphRef={containerRef}
@@ -356,12 +343,24 @@ export const V2 = () => {
356343
</Text>
357344
</Box>
358345
) : (
359-
<GuidesList
360-
guides={result.guides}
361-
displayOption={displayOption}
362-
/>
346+
guides.map((guide, idx) => (
347+
<GuideRow
348+
key={guide.key}
349+
guide={guide}
350+
orderIndex={idx}
351+
isExpanded={guide.key === expandedGuideRowKey}
352+
onClick={() => {
353+
setExpandedGuideRowKey((k) =>
354+
k && k === guide.key ? undefined : guide.key,
355+
);
356+
}}
357+
/>
358+
))
363359
)}
364360
</Box>
361+
362+
{/* Focus chin with dedicated controls */}
363+
<FocusChin guides={guides} displayOption={displayOption} />
365364
</Stack>
366365
)}
367366
</Box>

packages/react/src/modules/guide/components/Toolbar/V2/helpers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { KnockGuide } from "@knocklabs/client";
22

33
import { checkForWindow } from "../../../../../modules/core";
44

5+
export type DisplayOption = "all-guides" | "only-eligible" | "only-displayable";
6+
57
// Use this param to start Toolbar and enter into a debugging session when
68
// it is present and set to true.
79
const TOOLBAR_QUERY_PARAM = "knock_guide_toolbar";

packages/react/src/modules/guide/components/Toolbar/styles.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@
2222
opacity: 1;
2323
transform: scale(1);
2424
}
25-
}
25+
}

0 commit comments

Comments
 (0)