Skip to content

feat: 플러그인 설정 스키마에 조건부 표시(visible) 지원#52

Merged
lee-sihun merged 4 commits intoDmNote-App:masterfrom
dotoritos-kim:feat/plugin-settings-conditional-visibility
Mar 1, 2026
Merged

feat: 플러그인 설정 스키마에 조건부 표시(visible) 지원#52
lee-sihun merged 4 commits intoDmNote-App:masterfrom
dotoritos-kim:feat/plugin-settings-conditional-visibility

Conversation

@dotoritos-kim
Copy link

동기

현재 플러그인 설정 스키마(defineSettings, defineElement)에서 정의한 항목은
모두 무조건 표시됩니다. 특정 설정값에 따라 관련 없는 항목을 숨기는 것이 불가능합니다.

현재 상태

  • 설정 행에 식별자(id, data-*)가 없어 플러그인이 CSS/DOM으로 개별 행을 선택할 수 없음
  • 컨텍스트 메뉴에는 이미 visible/disabled 속성이 존재하지만, 설정 스키마에는 동등한 기능이 없음
    // 컨텍스트 메뉴 — 이미 지원됨 (api.ts:275-282)
    export type PluginMenuItem = {
      label: string;
      visible?: boolean | ((context: TContext) => boolean);
      disabled?: boolean | ((context: TContext) => boolean);
      onClick: ...;
    };

내장 플러그인의 실제 사례

kps.js에서 showGraph: false일 때 그래프 관련 설정 4개(graphType, graphSpeed,
graphColor, graphDivider)가 무의미하게 노출됨:

// kps.js — 현재 상태
showGraph: { type: "boolean", default: true, label: "settings.showGraph" },
graphDivider: { type: "divider" },                          // ← showGraph=false여도 보임
graphType:    { type: "select",  default: "line", ... },    // ← 동일
graphSpeed:   { type: "number",  default: 1000, ... },      // ← 동일
graphColor:   { type: "color",   default: "#86EFAC", ... }, // ← 동일

변경 내용

PluginSettingSchema에 optional visible 속성을 추가합니다.
기존 PluginMenuItemvisible 패턴과 동일한 시그니처를 사용합니다.

// 정적 boolean — 항상 숨김
hiddenOption: {
  type: "number",
  default: 5,
  label: "...",
  visible: false,
}

// 함수 — 다른 설정값에 따라 동적으로 표시/숨김
advancedOption: {
  type: "number",
  default: 5,
  label: "...",
  visible: (settings) => settings.mode === "advanced",
}

// divider에도 적용 가능
_separator: {
  type: "divider",
  visible: (settings) => settings.mode === "advanced",
}

kps.js에 적용하면

showGraph:    { type: "boolean", default: true, label: "settings.showGraph" },
graphDivider: { type: "divider", visible: (s) => s.showGraph },
graphType:    { type: "select",  default: "line", ..., visible: (s) => s.showGraph },
graphSpeed:   { type: "number",  default: 1000, ...,   visible: (s) => s.showGraph },
graphColor:   { type: "color",   default: "#86EFAC",   visible: (s) => s.showGraph },

적용 범위

설정이 렌더링되는 4개 경로 모두에 적용했습니다:

경로 파일
글로벌 설정 — 패널 PropertiesPanel.tsx
글로벌 설정 — 모달 defineSettings.ts
엘리먼트 설정 — 패널 PropertiesPanel.tsx (동일 함수)
엘리먼트 설정 — 모달 defineElement.ts

하위 호환성

  • visible은 optional 속성이므로, 기존 플러그인은 코드 변경 없이 동일하게 동작합니다
  • visible이 없는 설정은 모든 경로에서 무조건 표시됩니다 (기존 동작)
  • 숨겨진 설정의 저장값은 유지됩니다 — 표시만 제어하며 데이터 손실 없음

API 일관성

컨텍스트 메뉴의 PluginMenuItem에 이미 존재하는 visible 패턴과 동일한 시그니처를 사용합니다:

// PluginMenuItem (기존)
visible?: boolean | ((context: TContext) => boolean);

// PluginSettingSchema (이번 PR)
visible?: boolean | ((settings: Record<string, any>) => boolean);
  • 플러그인 개발자가 이미 익숙한 패턴을 재사용
  • 정적 boolean과 동적 함수 모두 지원
  • 임의 조건 표현이 가능하여 확장성 확보

타입 정의

export type PluginSettingSchema =
  | {
      type: "divider";
      label?: string;
      visible?: boolean | ((settings: Record<string, any>) => boolean);
    }
  | {
      type: Exclude<PluginSettingType, "divider">;
      default: any;
      label: string;
      min?: number;
      max?: number;
      step?: number;
      options?: { label: string; value: any }[];
      placeholder?: string;
      visible?: boolean | ((settings: Record<string, any>) => boolean);
    };

이 작업으로 할 수 있는 것들 예측

키 입력 통계

  • 그래프 표시를 끄면 ->그래프 종류, 색상, 속도 설정이 사라짐
  • 이미 코드에 존재하지만 visible 없이는 항상 모든 항목이 노출됨

날씨 위젯

  • 표시 형식을 "간단/상세"로 선택
  • "상세"일 때만 습도, 풍속, 체감온도 관련 설정이 나타남

포모도로 타이머

  • 휴식 알림 토글을 켜면 -> 휴식 시간, 알림음 설정 표시
  • 끄면 -> 해당 설정 숨김

음악 플레이어 연동

채팅 오버레이

공통점

"A를 고르면 B가 필요하고, C를 고르면 B가 불필요"

visible 없이는 모든 설정이 항상 보여서 사용자가 혼란스럽거나,
플러그인 개발자가 별도 모달을 직접 구현해야 함

kimkanghyun added 4 commits March 1, 2026 19:13
플러그인 설정 항목이 다른 설정값에 따라 동적으로 표시/숨김 가능하도록
PluginSettingSchema에 `when` 속성을 추가한다.

## 해결하는 문제

플러그인이 여러 모드를 지원할 때(예: 게임 구동기 선택) 특정 모드에서만
유효한 설정이 항상 노출되어 사용자에게 혼란을 줌.
기존 API에는 설정의 조건부 표시/숨기기 기능이 없었음.

## 변경 내용

- `PluginSettingSchema` 타입에 `when?: { key, value?, not? }` 속성 추가
  - `when: { key: "mode", value: "A" }` -> mode가 A일 때만 표시
  - `when: { key: "mode", not: "B" }` -> mode가 B가 아닐 때 표시
  - value/not에 배열을 넣으면 OR 매칭 지원
  - divider 타입에도 적용 가능
- 패널 모드(PropertiesPanel.tsx): 렌더 시 when 조건 평가, 미충족 시
  해당 항목을 렌더링하지 않음. React 리렌더 사이클에 의해 자동 반영.
- 모달 모드(defineSettings.ts): 초기 빌드 시 display:none 적용,
  설정 변경마다 _updateVisibility()로 DOM visibility 동기화.
- 숨겨진 설정의 저장값은 유지됨 (표시만 제어, 데이터 손실 없음)
PluginSettingWhenCondition 타입을 별도 정의하여 value/not 필드를
string | number | boolean 유니온으로 제한. 잘못된 타입의 조건값이
컴파일 타임에 검출되도록 한다.
defineElement.ts의 openInstanceSettings() 모달 렌더링 경로에
when 조건 체크가 누락되어 있었음. 이로 인해 엘리먼트 설정을
모달로 열 때는 조건부 visibility가 동작하지 않았음.
PluginMenuItem의 기존 visible?: boolean | ((ctx) => boolean) 패턴과
일관성을 맞추기 위해 설정 스키마의 when 객체를 visible로 변경.
PluginSettingWhenCondition 타입 제거, 4개 렌더링 경로 모두 반영.
@lee-sihun lee-sihun merged commit f82d56c into DmNote-App:master Mar 1, 2026
1 check failed
@dotoritos-kim
Copy link
Author

뭐 뭣 이렇게 빨리 머지 시켜주신다고요?

@lee-sihun
Copy link
Member

lee-sihun commented Mar 1, 2026

@all-contributors add @dotoritos-kim for code

기여 감사합니다! 하위 호환성이랑 API 일관성까지 신경 써 주셔서 바로 병합 했습니다.
앞으로도 다른 아이디어나 기여는 언제든 환영합니다. 😆😆

@lee-sihun
Copy link
Member

@all-contributors add @dotoritos-kim for code

@allcontributors
Copy link
Contributor

@lee-sihun

I've put up a pull request to add @dotoritos-kim! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants