88 lines
5.3 KiB
YAML
88 lines
5.3 KiB
YAML
# audit:allow test-scenario-coverage reason: axes cross product 의 핵심 회귀 가드는 test_files 의 단위(recipeEngine.scope/styleScope/flexModel/StyleScopeTabs/property-controls/s7-property-controls)·렌더(DynamicRenderer.responsive)·Feature(LayoutControllerEditorSaveTest) 가 cover. E2E axis 는 property-editor-scope.spec.ts 의 // @scenario/@effects docblock 으로 매핑.
|
||
|
||
feature: 레이아웃 편집기 스타일 탭 — 색 모드(라이트/다크) × 디바이스별 스타일 편집
|
||
|
||
description: |
|
||
속성 편집 모달 [스타일]/[표시조건] 탭에 색 모드 × 디바이스 세부탭을 두어, 선택 scope 가
|
||
가리키는 위치(base props 또는 responsive.{preset|커스텀범위}.props, 다크는 dark: classToken)에
|
||
스타일/flex/표시조건을 무손실로 기록·역해석한다.
|
||
|
||
핵심 동작:
|
||
- StyleScope = 색 모드(base|dark) × breakpoint(base|preset|커스텀범위) 직교 2축
|
||
- recipeEngine.applyRecipe/reverseResolve 가 scope 인자로 컨테이너 리다이렉트(기본 BASE_SCOPE = 회귀 0)
|
||
- 다크는 classToken 만 편집(dark: prefix 공존), 인라인은 읽기전용(darkReadonly)
|
||
- scope≠base 오버라이드 없으면 base 상속값을 placeholder 로(baseFallback)
|
||
- flexEnable on/off 2상태(off=명시 해제 토큰)로 디바이스별 flex 해제
|
||
- 모달 scope = 열리는 순간 툴바 스냅샷(독립, 패치 재마운트 불변)
|
||
- node-level responsive/if 저장·재로드 보존(백엔드 코드 변경 없음)
|
||
|
||
axes:
|
||
color_scheme: [light, dark]
|
||
device: [base, desktop, tablet, mobile, custom_range]
|
||
apply_type: [classToken, styleProp, cssVar, propValue, flex]
|
||
edit_target: [style, flex_enable, visibility_if]
|
||
scope_override_state: [no_override_inherits_base, has_scope_override]
|
||
|
||
exclusions:
|
||
- { color_scheme: dark, apply_type: styleProp, edit_target: style, reason: "다크 인라인은 읽기전용 — 편집 axis 아님(읽기전용 검증은 별도)" }
|
||
- { color_scheme: dark, apply_type: cssVar, reason: "다크 인라인 불가" }
|
||
- { color_scheme: dark, apply_type: propValue, reason: "다크 인라인 불가" }
|
||
- { color_scheme: dark, edit_target: visibility_if, reason: "표시조건은 다크 무관(D9) — 색 모드 줄 숨김" }
|
||
- { edit_target: flex_enable, apply_type: styleProp, reason: "flex enable 은 classToken 레시피" }
|
||
- { edit_target: flex_enable, apply_type: cssVar, reason: "동일" }
|
||
- { edit_target: flex_enable, apply_type: propValue, reason: "동일" }
|
||
|
||
effects:
|
||
# 위치 결정 + 무손실
|
||
- base_scope_writes_node_props_byte_identical_to_pre_scope
|
||
- device_scope_writes_responsive_breakpoint_props_base_unchanged
|
||
- custom_range_scope_writes_responsive_range_key
|
||
- empty_override_prunes_responsive_branch_keeping_code_authored_keys
|
||
# B안 시드 + 초기화 + 표시점
|
||
- device_scope_seeds_base_className_so_base_tokens_survive_shallow_merge
|
||
- seeded_base_tokens_render_as_placeholder_only_user_changes_are_solid
|
||
- device_override_is_copy_independent_of_later_base_changes
|
||
- reset_to_base_clears_device_override_restoring_inheritance
|
||
- reset_dark_clears_only_dark_tokens_keeping_light
|
||
- override_dot_shown_only_when_scope_differs_from_base_not_for_seed_only
|
||
# 다크
|
||
- dark_classToken_coexists_with_light_token_in_one_className
|
||
- dark_edit_preserves_light_token_and_vice_versa
|
||
- dark_inline_control_readonly_value_never_overwritten
|
||
- dark_and_device_compose_dark_prefix_in_responsive_props
|
||
# placeholder
|
||
- scope_without_override_shows_base_inherited_value_as_placeholder
|
||
- editing_placeholder_creates_scoped_override_only
|
||
# flex
|
||
- device_flex_disable_writes_explicit_off_token_breaking_base_inheritance
|
||
- scope_flex_judgment_uses_node_derivation_not_computed_style
|
||
- no_enable_control_hides_flex_toggle_in_non_base_scope
|
||
# 표시조건
|
||
- device_visibility_if_writes_responsive_breakpoint_if
|
||
- base_if_unchanged_when_device_if_edited
|
||
# 스냅샷 독립
|
||
- modal_scope_snapshots_toolbar_on_open
|
||
- modal_scope_independent_after_toolbar_change
|
||
- modal_scope_survives_patch_remount
|
||
# 저장/영속/실페이지
|
||
- save_persists_responsive_and_if_on_reload
|
||
- real_user_page_honors_responsive_override_at_matching_width
|
||
- real_user_page_honors_dark_token_under_dark_ancestor
|
||
# 프리뷰 토글
|
||
- preview_color_scheme_toggle_applies_dark_wrapper_to_preview_frame_only
|
||
|
||
test_files:
|
||
- resources/js/core/template-engine/layout-editor/__tests__/spec/styleScope.test.ts
|
||
- resources/js/core/template-engine/layout-editor/__tests__/spec/recipeEngine.scope.test.ts
|
||
- resources/js/core/template-engine/layout-editor/__tests__/spec/flexModel.test.ts
|
||
- resources/js/core/template-engine/layout-editor/__tests__/components/StyleScopeTabs.test.tsx
|
||
- resources/js/core/template-engine/layout-editor/__tests__/components/property-controls.test.tsx
|
||
- resources/js/core/template-engine/layout-editor/__tests__/components/s7-property-controls.test.tsx
|
||
- resources/js/core/template-engine/layout-editor/__tests__/components/PropertyEditorModal.test.tsx
|
||
- resources/js/core/template-engine/__tests__/DynamicRenderer.responsive.test.tsx
|
||
- tests/Feature/Api/Admin/LayoutControllerEditorSaveTest.php
|
||
- tests/Playwright/specs/layout-editor/property-editor-scope.spec.ts
|
||
|
||
validation:
|
||
e2e_spec: tests/Playwright/specs/layout-editor/property-editor-scope.spec.ts
|