diff --git a/src/renderer/__tests__/panel/__snapshots__/panelDomContract.test.tsx.snap b/src/renderer/__tests__/panel/__snapshots__/panelDomContract.test.tsx.snap index 328fe8d10..69c81aad0 100644 --- a/src/renderer/__tests__/panel/__snapshots__/panelDomContract.test.tsx.snap +++ b/src/renderer/__tests__/panel/__snapshots__/panelDomContract.test.tsx.snap @@ -2041,6 +2041,24 @@ exports[`속성 패널 DOM 약속 > 그래프 여럿 - 그룹 하나 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -4378,6 +4396,24 @@ exports[`속성 패널 DOM 약속 > 그래프 여럿 - 섞인 값 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -6008,6 +6044,24 @@ exports[`속성 패널 DOM 약속 > 그래프 하나 - 기본값 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -7698,6 +7752,24 @@ exports[`속성 패널 DOM 약속 > 그래프 하나 - 이름·고른 값·사 ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -10779,6 +10851,24 @@ exports[`속성 패널 DOM 약속 > 그래프와 커서 트래커 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -13064,6 +13154,24 @@ exports[`속성 패널 DOM 약속 > 노브 여럿 - 섞인 값 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -14647,6 +14755,24 @@ exports[`속성 패널 DOM 약속 > 노브 하나 - 기본값 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -16334,6 +16460,24 @@ exports[`속성 패널 DOM 약속 > 노브 하나 - 축·고른 값·사용자 C ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -18851,6 +18995,24 @@ exports[`속성 패널 DOM 약속 > 노브와 그래프 - 카운터 탭 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -21368,6 +21530,24 @@ exports[`속성 패널 DOM 약속 > 노브와 그래프 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -25464,6 +25644,24 @@ exports[`속성 패널 DOM 약속 > 스탯 여럿 - 카운터 탭 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -29560,6 +29758,24 @@ exports[`속성 패널 DOM 약속 > 스탯 여럿 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -33148,6 +33364,24 @@ exports[`속성 패널 DOM 약속 > 스탯 하나 - 기본값 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -36636,6 +36870,24 @@ exports[`속성 패널 DOM 약속 > 스탯 하나 - 이름·누적·카운터 ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -38585,6 +38837,24 @@ exports[`속성 패널 DOM 약속 > 스프라이트 여럿 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -39945,6 +40215,24 @@ exports[`속성 패널 DOM 약속 > 스프라이트 하나 - 기본값 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -41479,6 +41767,24 @@ exports[`속성 패널 DOM 약속 > 스프라이트 하나 - 이미지·자세· ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -44130,6 +44436,24 @@ exports[`속성 패널 DOM 약속 > 스프라이트와 그래프 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -47184,6 +47508,24 @@ exports[`속성 패널 DOM 약속 > 스프라이트와 커서 트래커 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -49806,6 +50148,24 @@ exports[`속성 패널 DOM 약속 > 커서 트래커 여럿 - 섞인 모드 1`] ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -51719,6 +52079,24 @@ exports[`속성 패널 DOM 약속 > 커서 트래커 하나 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -57355,6 +57733,24 @@ exports[`속성 패널 DOM 약속 > 키 여럿 - 그룹 하나 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -62931,6 +63327,24 @@ exports[`속성 패널 DOM 약속 > 키 여럿 - 노트 탭 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -68631,6 +69045,24 @@ exports[`속성 패널 DOM 약속 > 키 여럿 - 섞인 값 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -74207,6 +74639,24 @@ exports[`속성 패널 DOM 약속 > 키 여럿 - 카운터 탭 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -79191,6 +79641,24 @@ exports[`속성 패널 DOM 약속 > 키 하나 - 기본값 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -84175,6 +84643,24 @@ exports[`속성 패널 DOM 약속 > 키 하나 - 노트 탭 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -89171,6 +89657,24 @@ exports[`속성 패널 DOM 약속 > 키 하나 - 이름·고른 값·사용자 C ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -94155,6 +94659,24 @@ exports[`속성 패널 DOM 약속 > 키 하나 - 카운터 탭 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -100297,6 +100819,24 @@ exports[`속성 패널 DOM 약속 > 키·그래프·노브 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -106705,6 +107245,24 @@ exports[`속성 패널 DOM 약속 > 키·스프라이트·그래프 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -112607,6 +113165,24 @@ exports[`속성 패널 DOM 약속 > 키와 그래프 - 카운터 탭 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -118509,6 +119085,24 @@ exports[`속성 패널 DOM 약속 > 키와 그래프 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -124220,6 +124814,24 @@ exports[`속성 패널 DOM 약속 > 키와 노브 - 노트 탭 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -129931,6 +130543,24 @@ exports[`속성 패널 DOM 약속 > 키와 노브 - 카운터 탭 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -135642,6 +136272,24 @@ exports[`속성 패널 DOM 약속 > 키와 노브 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -141331,6 +141979,24 @@ exports[`속성 패널 DOM 약속 > 키와 스탯 - 노트 탭 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -147020,6 +147686,24 @@ exports[`속성 패널 DOM 약속 > 키와 스탯 - 카운터 탭 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -152709,6 +153393,24 @@ exports[`속성 패널 DOM 약속 > 키와 스탯 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -158694,6 +159396,24 @@ exports[`속성 패널 DOM 약속 > 키와 스프라이트 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", @@ -164919,6 +165639,24 @@ exports[`속성 패널 DOM 약속 > 키와 커서 트래커 1`] = ` ], "tag": "div", }, + { + "attrs": { + "aria-hidden": "true", + "data-state": "none", + }, + "children": [ + { + "class": [ + "dmn-scrollbar-thumb", + ], + "tag": "div", + }, + ], + "class": [ + "dmn-scrollbar", + ], + "tag": "div", + }, ], "class": [ "flex-1", diff --git a/src/renderer/components/main/Grid/PropertiesPanel/batch/BatchPluginOnlyPanel.tsx b/src/renderer/components/main/Grid/PropertiesPanel/batch/BatchPluginOnlyPanel.tsx index 8eb609f27..b6ea4d188 100644 --- a/src/renderer/components/main/Grid/PropertiesPanel/batch/BatchPluginOnlyPanel.tsx +++ b/src/renderer/components/main/Grid/PropertiesPanel/batch/BatchPluginOnlyPanel.tsx @@ -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; @@ -119,6 +120,7 @@ const BatchPluginOnlyPanel: React.FC = ({ {pluginSettings} + ); diff --git a/src/renderer/components/main/Grid/PropertiesPanel/document/DocumentBatchPanel.tsx b/src/renderer/components/main/Grid/PropertiesPanel/document/DocumentBatchPanel.tsx index ecbab23f7..dceda7a3d 100644 --- a/src/renderer/components/main/Grid/PropertiesPanel/document/DocumentBatchPanel.tsx +++ b/src/renderer/components/main/Grid/PropertiesPanel/document/DocumentBatchPanel.tsx @@ -52,6 +52,7 @@ import { LegacyKeyLikeBatchBody, type LegacyKeyLikeHost, } from './legacyKeyLikeBatch'; +import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar'; // 옛 종류 선택의 일괄 기하 - 속성 패널이 옛 선택 모양(플러그인 요소 포함)에서 만든다 export type LegacyBatchGeometry = BatchGeometry; @@ -367,6 +368,7 @@ const DocumentBatchPanel = ({ {legacyHost?.pluginSettings} + ); diff --git a/src/renderer/components/main/Grid/PropertiesPanel/document/DocumentElementPanel.tsx b/src/renderer/components/main/Grid/PropertiesPanel/document/DocumentElementPanel.tsx index 157993709..542d1605c 100644 --- a/src/renderer/components/main/Grid/PropertiesPanel/document/DocumentElementPanel.tsx +++ b/src/renderer/components/main/Grid/PropertiesPanel/document/DocumentElementPanel.tsx @@ -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; @@ -380,6 +381,7 @@ const ElementPanelBody = ({ {tabBody('style')} )} + ); diff --git a/src/renderer/components/main/Grid/PropertiesPanel/document/legacyKeyLikeBatch.tsx b/src/renderer/components/main/Grid/PropertiesPanel/document/legacyKeyLikeBatch.tsx index 2c1a7c9e4..8c0743944 100644 --- a/src/renderer/components/main/Grid/PropertiesPanel/document/legacyKeyLikeBatch.tsx +++ b/src/renderer/components/main/Grid/PropertiesPanel/document/legacyKeyLikeBatch.tsx @@ -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 { @@ -635,6 +636,7 @@ export const LegacyKeyLikeBatchBody = ({ {tabBody('style')} )} + 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 @@ -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) } > diff --git a/src/renderer/components/main/Grid/PropertiesPanel/layer/LayerTabContent.tsx b/src/renderer/components/main/Grid/PropertiesPanel/layer/LayerTabContent.tsx index d159771b7..543d68bdb 100644 --- a/src/renderer/components/main/Grid/PropertiesPanel/layer/LayerTabContent.tsx +++ b/src/renderer/components/main/Grid/PropertiesPanel/layer/LayerTabContent.tsx @@ -54,6 +54,7 @@ import { type LayerRowRename, } from './LayerRows'; import { useLayerCollapseStore } from '@stores/grid/useLayerCollapseStore'; +import OverlayScrollbar from '@components/main/common/overlayScrollbar/OverlayScrollbar'; // 끌기로 보지 않는 움직임 (화면 px) // 예전 레이어 끌기와 같은 시작 거리 (가로·세로 어느 쪽이든) @@ -771,6 +772,7 @@ const LayerTabContent = ({ )} + {contextMenuPresence.mounted && createPortal( diff --git a/src/renderer/components/main/Grid/PropertiesPanel/plugin/PluginSettingsPanelView.tsx b/src/renderer/components/main/Grid/PropertiesPanel/plugin/PluginSettingsPanelView.tsx index 359c00772..ba0945dd8 100644 --- a/src/renderer/components/main/Grid/PropertiesPanel/plugin/PluginSettingsPanelView.tsx +++ b/src/renderer/components/main/Grid/PropertiesPanel/plugin/PluginSettingsPanelView.tsx @@ -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; @@ -100,6 +101,7 @@ const PluginSettingsPanelView: React.FC = ({ )} + ) : (
diff --git a/src/renderer/components/main/Grid/PropertiesPanel/single/SingleSelectionPanel.tsx b/src/renderer/components/main/Grid/PropertiesPanel/single/SingleSelectionPanel.tsx index 3b89e507e..8b68ddf2d 100644 --- a/src/renderer/components/main/Grid/PropertiesPanel/single/SingleSelectionPanel.tsx +++ b/src/renderer/components/main/Grid/PropertiesPanel/single/SingleSelectionPanel.tsx @@ -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 @@ -256,6 +257,7 @@ export const PluginSelectionPanel: React.FC = ({ )}
+ ); diff --git a/src/renderer/components/main/Modal/content/pickers/CommonListPickerPage.tsx b/src/renderer/components/main/Modal/content/pickers/CommonListPickerPage.tsx index 28372a763..58c1fc8f5 100644 --- a/src/renderer/components/main/Modal/content/pickers/CommonListPickerPage.tsx +++ b/src/renderer/components/main/Modal/content/pickers/CommonListPickerPage.tsx @@ -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; @@ -167,7 +168,7 @@ export default function CommonListPickerPage({ /> {/* 리스트 컨테이너 — 배경보다 한 단계 밝은 필 테이블. 빈 공간도 테이블의 빈 영역으로 읽힘 */} -
+
({ )}
+ {/* 행과 ⋮ 버튼이 상자 끝까지 차 있어 막대는 상자 바깥 12px 여백에 둔다 */} +
{/* 하단 필터 바 */}
diff --git a/src/renderer/components/main/Settings.tsx b/src/renderer/components/main/Settings.tsx index 28260b639..e55adc31b 100644 --- a/src/renderer/components/main/Settings.tsx +++ b/src/renderer/components/main/Settings.tsx @@ -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; @@ -64,6 +65,10 @@ interface SettingsProps { ) => void; } +// 스크롤 컨테이너가 창 전체 폭이라 막대를 오른쪽 끝에 두면 프리뷰 옆에 붙는다. +// 카드 열(패딩 12 + 폭 348)과 프리뷰 페인(left 372) 사이 12px 골에 둔다 +const SETTINGS_RAIL_LEFT = 360; + const Settings = ({ showAlert, showConfirm, @@ -739,6 +744,10 @@ const Settings = ({
+ {/* 우측 고정 콘텐츠 페인 - 기본은 튜토리얼 프리뷰, 선택 시 설정 상세가 같은 표면을 채움 */}
= new Set([ 'PATH_NOT_AUTHORIZED', @@ -334,6 +335,7 @@ const CssPanelContent = ({
)} + {/* 하단 바 - 불러오기(주 액션, 크게) + 닫기 */} diff --git a/src/renderer/components/main/SettingsPanel/PluginsPanelContent.tsx b/src/renderer/components/main/SettingsPanel/PluginsPanelContent.tsx index 56769f665..45634c08e 100644 --- a/src/renderer/components/main/SettingsPanel/PluginsPanelContent.tsx +++ b/src/renderer/components/main/SettingsPanel/PluginsPanelContent.tsx @@ -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[]; @@ -146,6 +147,7 @@ const PluginsPanelContent = ({ )} + {/* 하단 바 - 추가(주 액션, 크게) + 닫기 */} diff --git a/src/renderer/components/main/SettingsPanel/ShortcutsPanelContent.tsx b/src/renderer/components/main/SettingsPanel/ShortcutsPanelContent.tsx index 20fccf42e..65ab1688a 100644 --- a/src/renderer/components/main/SettingsPanel/ShortcutsPanelContent.tsx +++ b/src/renderer/components/main/SettingsPanel/ShortcutsPanelContent.tsx @@ -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; @@ -321,7 +322,7 @@ const ShortcutsPanelContent = ({ return (
{ if (!isListening) return; const target = event.target as HTMLElement | null; @@ -353,6 +354,7 @@ const ShortcutsPanelContent = ({ ) : null}
+ {/* 하단 바 - 닫기 */}
diff --git a/src/renderer/components/main/SettingsPanel/panelChrome.ts b/src/renderer/components/main/SettingsPanel/panelChrome.ts index 10cfa0a01..950f06317 100644 --- a/src/renderer/components/main/SettingsPanel/panelChrome.ts +++ b/src/renderer/components/main/SettingsPanel/panelChrome.ts @@ -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는 켜짐 알약의 // 면과 항목 이름까지 같이 깎아, 정작 읽어야 할 '무엇이 켜져 있나'를 지운다. // 마스터 상태는 바로 위 토글이 이미 말하고 있다 diff --git a/src/renderer/components/main/common/overlayScrollbar/OverlayScrollbar.tsx b/src/renderer/components/main/common/overlayScrollbar/OverlayScrollbar.tsx new file mode 100644 index 000000000..7356fd733 --- /dev/null +++ b/src/renderer/components/main/common/overlayScrollbar/OverlayScrollbar.tsx @@ -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(null); + const thumbRef = useRef(null); + const controllerRef = useRef(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 ( +