Skip to content

Commit 8f19f82

Browse files
authored
feat: hand tool locks embeds (#62)
* feat: embeds stay locked while using Hand tool - Updated LockIndicator to accept appState as a prop, allowing it to respond to hand tool activation. - Improved visibility logic for the lock icon based on scrolling and hand tool state. - Added new styles for lock icon text in CustomEmbeddableRenderer.scss to enhance user feedback during interactions. * fix: improve visibility logic for Hand tool in LockIndicator - Updated LockIndicator component to conditionally render the Hand tool text based on the isHandToolActive state, enhancing user feedback during interactions.
1 parent 9c9cadf commit 8f19f82

File tree

2 files changed

+66
-15
lines changed

2 files changed

+66
-15
lines changed

src/frontend/src/CustomEmbeddableRenderer.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@
3535
&.visible {
3636
opacity: 1;
3737
}
38+
39+
&__text {
40+
margin-left: 4px;
41+
font-size: 12px;
42+
font-weight: 600;
43+
font-family: 'Roboto', sans-serif;
44+
color: #afafaf;
45+
opacity: 0.7;
46+
}
3847
}
3948

4049
&__content {

src/frontend/src/CustomEmbeddableRenderer.tsx

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export const renderCustomEmbeddable = (
7373
<div className="custom-embed">
7474
<div className="custom-embed__title-bar">
7575
<div className="custom-embed__title-bar__text">{title}</div>
76-
<LockIndicator />
76+
<LockIndicator appState={appState} />
7777
</div>
7878
<div className="custom-embed__content">
7979
{content}
@@ -87,7 +87,7 @@ export const renderCustomEmbeddable = (
8787
<div className="custom-embed">
8888
<div className="custom-embed__title-bar">
8989
<div className="custom-embed__title-bar__text">{title}</div>
90-
<LockIndicator />
90+
<LockIndicator appState={appState} />
9191
</div>
9292
<div className="custom-embed__content">
9393
<iframe className="custom-embed__content--iframe" src={element.link} />
@@ -97,13 +97,15 @@ export const renderCustomEmbeddable = (
9797
}
9898
};
9999

100-
// Lock icon component that shows when scrolling
101-
const LockIndicator = () => {
102-
const [visible, setVisible] = useState(false);
100+
// Lock icon component that shows when scrolling or when hand tool is active
101+
const LockIndicator = ({ appState }: { appState?: AppState }) => {
102+
const [isScrolling, setIsScrolling] = useState(false);
103+
const [isHandToolActive, setIsHandToolActive] = useState(false);
103104

105+
// Effect to handle scroll state changes
104106
useEffect(() => {
105107
const handleScrollStateChange = (event: CustomEvent<{ isScrolling: boolean }>) => {
106-
setVisible(event.detail.isScrolling);
108+
setIsScrolling(event.detail.isScrolling);
107109
};
108110

109111
// Add event listener for scroll state changes
@@ -115,15 +117,48 @@ const LockIndicator = () => {
115117
};
116118
}, []);
117119

120+
// Separate effect to handle hand tool state changes
121+
useEffect(() => {
122+
// Check hand tool state
123+
const handToolActive = appState?.activeTool?.type === "hand";
124+
const wasHandToolActive = isHandToolActive;
125+
setIsHandToolActive(handToolActive);
126+
127+
// If hand tool was active but is now deactivated
128+
if (wasHandToolActive && !handToolActive) {
129+
// Force reset of global scrolling state
130+
globalIsScrolling = false;
131+
document.documentElement.style.setProperty('--embeddable-pointer-events', 'all');
132+
133+
// Dispatch event to update all components
134+
scrollStateChangeEvent.detail.isScrolling = false;
135+
document.dispatchEvent(scrollStateChangeEvent);
136+
137+
// Update component state
138+
setIsScrolling(false);
139+
} else if (handToolActive) {
140+
// Set pointer-events to none when hand tool is active
141+
document.documentElement.style.setProperty('--embeddable-pointer-events', 'none');
142+
}
143+
}, [appState]);
144+
145+
// Determine if the lock should be visible
146+
const visible = isScrolling || isHandToolActive;
147+
118148
return (
119149
<div className={`custom-embed__lock-icon ${visible ? 'visible' : ''}`}>
120150
<Lock size={16} />
151+
{isHandToolActive && (
152+
<span className="custom-embed__lock-icon__text visible">
153+
(Hand tool)
154+
</span>
155+
)}
121156
</div>
122157
);
123158
};
124159

125-
// Track scrolling state
126-
let isScrolling = false;
160+
// Track scrolling state globally
161+
let globalIsScrolling = false;
127162
// Create a custom event for scrolling state changes
128163
const scrollStateChangeEvent = new CustomEvent('scrollStateChange', { detail: { isScrolling: false } });
129164

@@ -137,7 +172,7 @@ const getDebouncedScrollEnd = (() => {
137172
if (currentDebounceTime !== lastDebounceTime || !debouncedFn) {
138173
lastDebounceTime = currentDebounceTime;
139174
debouncedFn = debounce(() => {
140-
isScrolling = false;
175+
globalIsScrolling = false;
141176
// Set pointer-events back to all when not scrolling
142177
document.documentElement.style.setProperty('--embeddable-pointer-events', 'all');
143178
// Dispatch event with updated scrolling state
@@ -153,16 +188,23 @@ export const lockEmbeddables = (appState?: AppState) => {
153188
// Get the debounce time from settings, with fallback to default
154189
const debounceTime = appState?.pad?.userSettings?.embedLockDebounceTime || 350;
155190

156-
if (!isScrolling) {
157-
isScrolling = true;
158-
// Set pointer-events to none during scrolling
191+
// Check if hand tool is active
192+
const handToolActive = appState?.activeTool?.type === "hand";
193+
194+
if (!globalIsScrolling) {
195+
globalIsScrolling = true;
196+
// Set pointer-events to none during scrolling or when hand tool is active
159197
document.documentElement.style.setProperty('--embeddable-pointer-events', 'none');
160198
// Dispatch event with updated scrolling state
161199
scrollStateChangeEvent.detail.isScrolling = true;
162200
document.dispatchEvent(scrollStateChangeEvent);
163201
}
164202

165-
// Get the current debounced function and call it
166-
const debouncedScrollEnd = getDebouncedScrollEnd(debounceTime);
167-
debouncedScrollEnd();
203+
// If hand tool is not active, use debounce to unlock after scrolling stops
204+
// If hand tool is active, we don't want to unlock
205+
if (!handToolActive) {
206+
// Get the current debounced function and call it
207+
const debouncedScrollEnd = getDebouncedScrollEnd(debounceTime);
208+
debouncedScrollEnd();
209+
}
168210
};

0 commit comments

Comments
 (0)