126 lines
8.3 KiB
YAML
126 lines
8.3 KiB
YAML
feature: 레이아웃 편집기 배열 빌트인 — array 노드 에디터(ARRAY-PROP 속성 패널)
|
|
|
|
description: |
|
|
컴포넌트의 정적 배열 prop(node.props[arrayProp] — 예 TabNavigation tabs, Breadcrumb items,
|
|
Dropdown/ActionMenu items, DataGrid columns, PageHeader actions)을 속성 모달 본체에서 항목
|
|
단위로 구조 편집한다. capability 의 일반 슬롯 `nodeEditor:{kind:"array",params:{arrayProp,
|
|
itemLabel,fields,newItem}}`(부록4-ter)로 선언하고, 코어 빌트인 ArrayItemsEditor 를
|
|
registerCoreEditors 가 registerNodeEditor('array', ...) 로 일반 레지스트리에 등록한다(특권
|
|
분기 0 — 코어는 kind 만 알고 컴포넌트명/배열 prop 이름을 가정하지 않음. arrayProp/항목 필드
|
|
스키마는 params 가 공급 → 임의 배열 prop 컴포넌트에 동일 에디터 재사용).
|
|
|
|
children 노드 에디터(ChildrenListControl)가 실제 자식 노드 트리를 다루는 것과 달리, array
|
|
에디터는 props 안의 정적 데이터 배열(객체/원시 항목)을 추가/삭제/정렬/필드편집한다.
|
|
|
|
필드 위젯: text(평문 즉시 반영) / i18n-text(평문 blur → createCustomKey → $t:custom.* 기록,
|
|
기존 키 → updateCustomKeyValue 현재 로케일만) / select(options) / boolean / icon(아이콘명 문자열).
|
|
primary 필드(미지정 시 첫 필드)는 행 주 입력. 원시 string[] 항목은 primary 필드로 값 자체 편집.
|
|
|
|
정적-바인딩 가드: props[arrayProp] 가 `{{...}}` 데이터바인딩이거나 비-배열이면 편집
|
|
비대상 → "바인딩됨(코드 편집)" 디그레이드(덮어쓰기 위험 차단). 항목 텍스트 다국어는
|
|
children/table 항목과 공용 모델(createCustomKey) SSoT.
|
|
|
|
axes:
|
|
operation: [add, remove, move, edit_text_field, edit_i18n_field, edit_select, edit_boolean, edit_icon]
|
|
array_value: [static_array, binding_expression, non_array, empty]
|
|
field_widget: [text, i18n_text, select, boolean, icon]
|
|
template: [sirsoft-basic, sirsoft-admin_basic]
|
|
|
|
exclusions:
|
|
- { operation: add, array_value: binding_expression, reason: "바인딩식 배열 prop 은 편집 비대상(디그레이드) — CRUD 불가" }
|
|
- { operation: remove, array_value: binding_expression, reason: "동일" }
|
|
- { operation: move, array_value: binding_expression, reason: "동일" }
|
|
- { operation: edit_text_field, array_value: binding_expression, reason: "동일" }
|
|
- { operation: edit_i18n_field, array_value: binding_expression, reason: "동일" }
|
|
- { operation: edit_select, array_value: binding_expression, reason: "동일" }
|
|
- { operation: edit_boolean, array_value: binding_expression, reason: "동일" }
|
|
- { operation: edit_icon, array_value: binding_expression, reason: "동일" }
|
|
- { operation: add, array_value: non_array, reason: "비-배열 prop 은 디그레이드 — CRUD 불가" }
|
|
- { operation: remove, array_value: non_array, reason: "동일" }
|
|
- { operation: move, array_value: non_array, reason: "동일" }
|
|
- { operation: edit_text_field, array_value: non_array, reason: "동일" }
|
|
- { operation: edit_i18n_field, array_value: non_array, reason: "동일" }
|
|
- { operation: edit_select, array_value: non_array, reason: "동일" }
|
|
- { operation: edit_boolean, array_value: non_array, reason: "동일" }
|
|
- { operation: edit_icon, array_value: non_array, reason: "동일" }
|
|
- { operation: remove, array_value: empty, reason: "빈 배열은 제거 대상 없음" }
|
|
- { operation: move, array_value: empty, reason: "빈 배열은 이동 대상 없음" }
|
|
- { operation: edit_text_field, array_value: empty, reason: "빈 배열은 편집 대상 없음(추가만 가능)" }
|
|
- { operation: edit_i18n_field, array_value: empty, reason: "동일" }
|
|
- { operation: edit_select, array_value: empty, reason: "동일" }
|
|
- { operation: edit_boolean, array_value: empty, reason: "동일" }
|
|
- { operation: edit_icon, array_value: empty, reason: "동일" }
|
|
- { operation: edit_text_field, field_widget: i18n_text, reason: "필드 위젯 축은 edit 종류로 이미 분기 — 교차 중복" }
|
|
- { operation: edit_text_field, field_widget: select, reason: "동일" }
|
|
- { operation: edit_text_field, field_widget: boolean, reason: "동일" }
|
|
- { operation: edit_text_field, field_widget: icon, reason: "동일" }
|
|
- { operation: edit_i18n_field, field_widget: text, reason: "동일" }
|
|
- { operation: edit_i18n_field, field_widget: select, reason: "동일" }
|
|
- { operation: edit_i18n_field, field_widget: boolean, reason: "동일" }
|
|
- { operation: edit_i18n_field, field_widget: icon, reason: "동일" }
|
|
- { operation: edit_select, field_widget: text, reason: "동일" }
|
|
- { operation: edit_select, field_widget: i18n_text, reason: "동일" }
|
|
- { operation: edit_select, field_widget: boolean, reason: "동일" }
|
|
- { operation: edit_select, field_widget: icon, reason: "동일" }
|
|
- { operation: edit_boolean, field_widget: text, reason: "동일" }
|
|
- { operation: edit_boolean, field_widget: i18n_text, reason: "동일" }
|
|
- { operation: edit_boolean, field_widget: select, reason: "동일" }
|
|
- { operation: edit_boolean, field_widget: icon, reason: "동일" }
|
|
- { operation: edit_icon, field_widget: text, reason: "동일" }
|
|
- { operation: edit_icon, field_widget: i18n_text, reason: "동일" }
|
|
- { operation: edit_icon, field_widget: select, reason: "동일" }
|
|
- { operation: edit_icon, field_widget: boolean, reason: "동일" }
|
|
- { operation: add, field_widget: i18n_text, reason: "구조 연산(add/remove/move)은 필드 위젯 종류 무관" }
|
|
- { operation: add, field_widget: select, reason: "동일" }
|
|
- { operation: add, field_widget: boolean, reason: "동일" }
|
|
- { operation: add, field_widget: icon, reason: "동일" }
|
|
- { operation: remove, field_widget: i18n_text, reason: "동일" }
|
|
- { operation: remove, field_widget: select, reason: "동일" }
|
|
- { operation: remove, field_widget: boolean, reason: "동일" }
|
|
- { operation: remove, field_widget: icon, reason: "동일" }
|
|
- { operation: move, field_widget: i18n_text, reason: "동일" }
|
|
- { operation: move, field_widget: select, reason: "동일" }
|
|
- { operation: move, field_widget: boolean, reason: "동일" }
|
|
- { operation: move, field_widget: icon, reason: "동일" }
|
|
|
|
effects:
|
|
# capability/등록
|
|
- array_capability_declared_on_p1_components_both_templates
|
|
- array_editor_registered_via_registercoreeditors_kind_agnostic
|
|
- property_modal_dispatches_array_node_editor_in_props_tab_by_kind
|
|
# 가드
|
|
- binding_expression_array_prop_degrades_to_bound_notice
|
|
- non_array_prop_value_degrades_to_bound_notice
|
|
- missing_array_prop_capability_shows_misconfigured_notice
|
|
# 구조 연산
|
|
- add_item_appends_newitem_skeleton_patches_whole_node
|
|
- add_item_synthesizes_empty_item_from_fields_when_no_newitem
|
|
- remove_item_drops_only_that_index
|
|
- move_up_down_swaps_adjacent_with_boundary_guard
|
|
# 필드 편집
|
|
- text_field_updates_item_immediately
|
|
- icon_field_updates_item_with_icon_name_string
|
|
- select_field_updates_item_with_chosen_value
|
|
- boolean_field_toggles_item_flag
|
|
- i18n_text_plain_blur_creates_custom_key_and_writes_dollar_t_custom
|
|
- existing_custom_key_blur_updates_current_locale_value_keeps_key
|
|
- primitive_string_item_edits_value_via_primary_field
|
|
- node_prop_change_clears_draft_buffer_no_stale
|
|
# 라이브(E2E)
|
|
- live_add_tab_edit_label_reorder_save_persists_to_user_page
|
|
|
|
test_files:
|
|
- resources/js/core/template-engine/layout-editor/__tests__/components/ArrayItemsEditor.test.tsx
|
|
- resources/js/core/template-engine/layout-editor/__tests__/spec/editorRegistries.test.ts
|
|
- tests/Playwright/specs/layout-editor/array-editor.spec.ts
|
|
|
|
validation:
|
|
note: |
|
|
Vitest 단위가 axes cross product 회귀(추가/삭제/정렬, text/select/boolean/icon/i18n-text 필드
|
|
편집, 바인딩/비-배열/미선언 디그레이드, 원시 string[] 항목, 노드 파생 무상태)와 capability
|
|
부착·등록(kind-agnostic)을 잠근다. Playwright E2E 가 라이브 편집기에서 TabNavigation 선택 →
|
|
array 에디터 마운트 → 탭 추가 → 라벨 편집 → 정렬 → 저장(PUT 200) → 실사용자화면 반영을
|
|
브라우저로 검증한다. 캔버스 인플레이스 레퍼런스(TabNavigation registerCanvasOverlay)는 단계
|
|
4-b 산출물 — 본 단계는 속성 패널 경로.
|
|
e2e_spec: tests/Playwright/specs/layout-editor/array-editor.spec.ts
|