Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { BatchSizeRow, type BatchGeometry } from './geometry/BatchGeometryRows';
import EditSessionBoundary from '../selection/EditSessionBoundary';
import BatchPanelHeader from './BatchPanelHeader';
import type { MixedValueResult } from './batchPanelShared';
import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar';

interface BatchPluginOnlyPanelProps {
setPanelElement: (el: HTMLDivElement | null) => void;
Expand Down Expand Up @@ -119,6 +120,7 @@ const BatchPluginOnlyPanel: React.FC<BatchPluginOnlyPanelProps> = ({
{pluginSettings}
</EditSessionBoundary>
</div>
<OverlayScrollbar />
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
LegacyKeyLikeBatchBody,
type LegacyKeyLikeHost,
} from './legacyKeyLikeBatch';
import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar';

// 옛 종류 선택의 일괄 기하 - 속성 패널이 옛 선택 모양(플러그인 요소 포함)에서 만든다
export type LegacyBatchGeometry = BatchGeometry;
Expand Down Expand Up @@ -367,6 +368,7 @@ const DocumentBatchPanel = ({
{legacyHost?.pluginSettings}
</EditSessionBoundary>
</div>
<OverlayScrollbar />
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { singlePanelWriterFor } from './documentPanelWriter';
import { LegacyCustomCssSection, LegacySingleStyle } from './legacyBundleRows';
import { KeyStatGeometry } from './legacyKeyStatSections';
import type { PanelTab } from '@src/renderer/elementKinds/defineElementKind';
import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar';

interface DocumentElementPanelProps {
sceneId: string;
Expand Down Expand Up @@ -380,6 +381,7 @@ const ElementPanelBody = ({
{tabBody('style')}
</div>
)}
<OverlayScrollbar />
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import {
} from './documentPanelModel';
import { PanelSections, type PanelSectionRenderers } from './documentPanelRows';
import { canEditBundleField, type UnionSection } from './documentPanelUnion';
import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar';

// 속성 패널이 갖는 일괄 피커 상태 - 선택이 바뀌면 속성 패널이 닫는다
export interface LegacyKeyLikeHost {
Expand Down Expand Up @@ -635,6 +636,7 @@ export const LegacyKeyLikeBatchBody = ({
{tabBody('style')}
</div>
)}
<OverlayScrollbar />
</div>

<BatchColorPickerPopup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,14 @@ interface LayerRowHandlers {
onContextMenu: (event: React.MouseEvent) => void;
}

// 오른쪽 12px는 스크롤 막대 자리 - 숨김 토글 버튼이 그 띠에 걸리지 않게 비워 둔다
const rowClass = (
selected: boolean,
hidden: boolean,
dragging: boolean,
dimmed = false,
) => `
group relative flex items-center gap-[8px] pr-[4px] h-[34px] select-none dmn-row-grabbable
group relative flex items-center gap-[8px] pr-[12px] h-[34px] select-none dmn-row-grabbable
${dimmed ? 'opacity-30' : hidden ? 'opacity-60' : ''}
${
selected
Expand Down Expand Up @@ -200,7 +201,7 @@ export const LayerGroupRow = ({
style={{ paddingLeft: layerRowIndent(depth) }}
className={
dropInto
? 'group relative flex items-center gap-[8px] pr-[4px] h-[34px] select-none bg-fill-hover text-fg-muted'
? 'group relative flex items-center gap-[8px] pr-[12px] h-[34px] select-none bg-fill-hover text-fg-muted'
: rowClass(selected, hidden, dragging, dimmed)
}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import {
type LayerRowRename,
} from './LayerRows';
import { useLayerCollapseStore } from '@stores/grid/useLayerCollapseStore';
import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar';

// 끌기로 보지 않는 움직임 (화면 px)
// 예전 레이어 끌기와 같은 시작 거리 (가로·세로 어느 쪽이든)
Expand Down Expand Up @@ -771,6 +772,7 @@ const LayerTabContent = ({
</div>
)}
</div>
<OverlayScrollbar inert={dragging} />

{contextMenuPresence.mounted &&
createPortal(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
hasRenderableSettings,
type SettingsNormalizationErrorKind,
} from '@plugins/runtime/settingsSections';
import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar';

interface PluginSettingsPanelViewProps {
setPanelElement: (el: HTMLDivElement | null) => void;
Expand Down Expand Up @@ -100,6 +101,7 @@ const PluginSettingsPanelView: React.FC<PluginSettingsPanelViewProps> = ({
)}
</div>
</div>
<OverlayScrollbar />
</div>
) : (
<div className="flex-1 flex items-center justify-center px-[24px]">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from '../controls/PropertyInputs';
import { AXIS_FIELD_WIDTH } from '@utils/cardRecipes';
import EditSessionBoundary from '../selection/EditSessionBoundary';
import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar';

// ============================================================================
// Plugin Selection Panel
Expand Down Expand Up @@ -256,6 +257,7 @@ export const PluginSelectionPanel: React.FC<PluginSelectionPanelProps> = ({
)}
</EditSessionBoundary>
</div>
<OverlayScrollbar />
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useLenis } from '@hooks/useLenis';
import Dropdown from '@components/main/common/dropdown/Dropdown';
import SearchField from '@components/main/common/SearchField';
import ListAddRow from '@components/main/common/ListAddRow';
import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar';

type FilterOption = {
value: string;
Expand Down Expand Up @@ -167,7 +168,7 @@ export default function CommonListPickerPage<T>({
/>
</div>
{/* 리스트 컨테이너 — 배경보다 한 단계 밝은 필 테이블. 빈 공간도 테이블의 빈 영역으로 읽힘 */}
<div className="mx-[12px] bg-inset rounded-surface p-[4px] flex-1 min-h-0 flex flex-col">
<div className="relative mx-[12px] bg-inset rounded-surface p-[4px] flex-1 min-h-0 flex flex-col">
<div
ref={setViewportEl}
className="flex-1 min-h-0 flex flex-col overflow-y-auto modal-content-scroll dmn-scroll-fade dmn-scroll-fade-shallow"
Expand Down Expand Up @@ -212,6 +213,11 @@ export default function CommonListPickerPage<T>({
)}
</div>
</div>
{/* 행과 ⋮ 버튼이 상자 끝까지 차 있어 막대는 상자 바깥 12px 여백에 둔다 */}
<OverlayScrollbar
placement="outside"
className="[--ui-scrollbar-band:12px]"
/>
</div>
{/* 하단 필터 바 */}
<div className="p-[12px] shrink-0">
Expand Down
9 changes: 9 additions & 0 deletions src/renderer/components/main/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { cssApi } from '@api/modules/resources/cssApi';
import { jsApi } from '@api/modules/plugin/jsApi';
import { keysApi } from '@api/modules/editor/keysApi';
import { appApi, windowApi } from '@api/modules/app/appApi';
import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar';

interface SettingsProps {
showAlert: (msg: string, confirmText?: string) => void;
Expand All @@ -64,6 +65,10 @@ interface SettingsProps {
) => void;
}

// 스크롤 컨테이너가 창 전체 폭이라 막대를 오른쪽 끝에 두면 프리뷰 옆에 붙는다.
// 카드 열(패딩 12 + 폭 348)과 프리뷰 페인(left 372) 사이 12px 골에 둔다
const SETTINGS_RAIL_LEFT = 360;

const Settings = ({
showAlert,
showConfirm,
Expand Down Expand Up @@ -739,6 +744,10 @@ const Settings = ({
</div>
</div>
</div>
<OverlayScrollbar
railLeft={SETTINGS_RAIL_LEFT}
className="[--ui-scrollbar-band:12px] [--ui-scrollbar-pad:12px]"
/>
{/* 우측 고정 콘텐츠 페인 - 기본은 튜토리얼 프리뷰, 선택 시 설정 상세가 같은 표면을 채움 */}
<div
className={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import type {
} from '@src/types/plugin/api';
import { cssApi } from '@api/modules/resources/cssApi';
import { useSingleFlightAction } from '@hooks/useSingleFlightAction';
import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar';

const CSS_HISTORY_ERROR_CODES: ReadonlySet<string> = new Set([
'PATH_NOT_AUTHORIZED',
Expand Down Expand Up @@ -334,6 +335,7 @@ const CssPanelContent = ({
</div>
)}
</div>
<OverlayScrollbar />
</div>

{/* 하단 바 - 불러오기(주 액션, 크게) + 닫기 */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { usePickerItemMenu } from '@hooks/usePickerItemMenu';
import { usePluginHealthStore } from '@stores/plugin/usePluginHealthStore';
import { getPluginDisplayName } from '@utils/plugin/components/pluginUtils';
import type { JsPlugin } from '@src/types/plugin/js';
import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar';

interface PluginsPanelContentProps {
plugins: JsPlugin[];
Expand Down Expand Up @@ -146,6 +147,7 @@ const PluginsPanelContent = ({
</div>
)}
</div>
<OverlayScrollbar />
</div>

{/* 하단 바 - 추가(주 액션, 크게) + 닫기 */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
} from '@src/types/settings/shortcuts';
import { getDefaultShortcuts } from '@src/renderer/defaults';
import { isHistoryEditorFlushLocked } from '@src/renderer/editor/runtime/lifecycle/historyEditorFlushLock';
import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar';

type ShortcutKey = keyof ShortcutsState;

Expand Down Expand Up @@ -321,7 +322,7 @@ const ShortcutsPanelContent = ({

return (
<div
className="flex flex-col h-full"
className="relative flex flex-col h-full"
onPointerDownCapture={(event) => {
if (!isListening) return;
const target = event.target as HTMLElement | null;
Expand Down Expand Up @@ -353,6 +354,7 @@ const ShortcutsPanelContent = ({
) : null}
</div>
</div>
<OverlayScrollbar />

{/* 하단 바 - 닫기 */}
<div className="px-[12px] pb-[12px] shrink-0">
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/components/main/SettingsPanel/panelChrome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const PANEL_PILL_CLASS =

// 인셋 리스트 웰 + 내부 스크롤 + 빈 상태 + 행 이름
export const PANEL_LIST_WELL_CLASS =
'mx-[12px] mb-[12px] bg-inset rounded-surface flex-1 min-h-0 flex flex-col';
'relative mx-[12px] mb-[12px] bg-inset rounded-surface flex-1 min-h-0 flex flex-col';
// 마스터 스위치가 꺼져도 목록은 가라앉히지 않는다. 그룹 opacity는 켜짐 알약의
// 면과 항목 이름까지 같이 깎아, 정작 읽어야 할 '무엇이 켜져 있나'를 지운다.
// 마스터 상태는 바로 위 토글이 이미 말하고 있다
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { useEffect, useRef } from 'react';

import { usePanelHost } from '@contexts/PanelHostContext';

import {
createOverlayScrollbarController,
type OverlayScrollbarController,
type OverlayScrollbarPlacement,
} from './overlayScrollbarController';

interface OverlayScrollbarProps {
/** 끌어 정렬처럼 뷰포트 위 히트 판정이 필요한 동안 막대 입력을 끈다 */
inert?: boolean;
/** 레일 왼쪽 위치(뷰포트 기준 px). edge 배치에서만 쓴다 */
railLeft?: number;
/** edge는 뷰포트 오른쪽 끝 안쪽, outside는 부모 상자 바깥 오른쪽 여백 */
placement?: OverlayScrollbarPlacement;
className?: string;
}

/**
* 오버레이 스크롤 막대. 스크롤 뷰포트와 같은 부모(위치 지정 요소) 안 마지막 자식으로 둔다.
* 네이티브 막대는 전역에서 숨긴 채, 스크롤할 때와 가장자리에 포인터가 닿을 때만 드러난다.
* 레일 자리(오른쪽 띠)에는 버튼이 없어야 한다 - 쓰는 쪽 레이아웃이 그 띠를 비워 둔다
*/
const OverlayScrollbar = ({
inert = false,
railLeft,
placement = 'edge',
className,
}: OverlayScrollbarProps) => {
// 분리 패널로 옮겨지면 그 창 기준으로 관찰자를 다시 만든다
const { window: ownerWindow } = usePanelHost();
const railRef = useRef<HTMLDivElement>(null);
const thumbRef = useRef<HTMLDivElement>(null);
const controllerRef = useRef<OverlayScrollbarController | null>(null);

useEffect(() => {
const rail = railRef.current;
const thumb = thumbRef.current;
if (!rail || !thumb) return undefined;
const view = (rail.ownerDocument.defaultView ?? ownerWindow) as Window &
typeof globalThis;
const controller = createOverlayScrollbarController(rail, thumb, view);
controllerRef.current = controller;
return () => {
controller.destroy();
controllerRef.current = null;
};
}, [ownerWindow]);

useEffect(() => {
controllerRef.current?.setOptions({ inert, railLeft, placement });
}, [inert, railLeft, placement, ownerWindow]);

return (
<div
ref={railRef}
aria-hidden="true"
className={className ? `dmn-scrollbar ${className}` : 'dmn-scrollbar'}
>
<div ref={thumbRef} className="dmn-scrollbar-thumb" />
</div>
);
};

export default OverlayScrollbar;
Loading
Loading