Skip to content

Commit 9da9e15

Browse files
committed
add FocusChin to the guide toolbar v2 with dedicated controls
1 parent a8f7cae commit 9da9e15

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,
@@ -48,46 +49,21 @@ const Kbd = ({ children }: { children: React.ReactNode }) => {
4849
);
4950
};
5051

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

7260
if (displayOption === "only-displayable" && !isDisplayable) {
73-
return null;
61+
return false;
7462
}
7563
if (displayOption === "only-eligible" && !isEligible) {
76-
return null;
64+
return false;
7765
}
78-
return (
79-
<GuideRow
80-
key={guide.key}
81-
guide={guide}
82-
orderIndex={idx}
83-
isExpanded={guide.key === expandedGuideRowKey}
84-
onClick={() => {
85-
setExpandedGuideRowKey((k) =>
86-
k && k === guide.key ? undefined : guide.key,
87-
);
88-
}}
89-
/>
90-
);
66+
return true;
9167
});
9268
};
9369

@@ -100,6 +76,14 @@ export const V2 = () => {
10076
const [isCollapsed, setIsCollapsed] = React.useState(false);
10177
const [isContextPanelOpen, setIsContextPanelOpen] = React.useState(false);
10278

79+
const [expandedGuideRowKey, setExpandedGuideRowKey] = React.useState<
80+
string | undefined
81+
>();
82+
83+
React.useEffect(() => {
84+
setExpandedGuideRowKey(undefined);
85+
}, [displayOption]);
86+
10387
React.useEffect(() => {
10488
const { isVisible = false, focusedGuideKeys = {} } = runConfig || {};
10589
const isDebugging = client.store.state.debug?.debugging;
@@ -157,6 +141,9 @@ export const V2 = () => {
157141
return null;
158142
}
159143

144+
const guides =
145+
result.status === "ok" ? filterGuides(result.guides, displayOption) : [];
146+
160147
return (
161148
<Box
162149
tgphRef={containerRef}
@@ -358,12 +345,24 @@ export const V2 = () => {
358345
</Text>
359346
</Box>
360347
) : (
361-
<GuidesList
362-
guides={result.guides}
363-
displayOption={displayOption}
364-
/>
348+
guides.map((guide, idx) => (
349+
<GuideRow
350+
key={guide.key}
351+
guide={guide}
352+
orderIndex={idx}
353+
isExpanded={guide.key === expandedGuideRowKey}
354+
onClick={() => {
355+
setExpandedGuideRowKey((k) =>
356+
k && k === guide.key ? undefined : guide.key,
357+
);
358+
}}
359+
/>
360+
))
365361
)}
366362
</Box>
363+
364+
{/* Focus chin with dedicated controls */}
365+
<FocusChin guides={guides} displayOption={displayOption} />
367366
</Stack>
368367
)}
369368
</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)