@things-factory/board-ai 10.0.0-beta.79 → 10.0.0-beta.81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -110,5 +110,20 @@ export const DEFAULT_SLASH_TEMPLATES: SlashTemplate[] = [
110
110
  name: 'group',
111
111
  description: '선택 컴포넌트 그룹화',
112
112
  template: '선택한 컴포넌트들을 하나의 그룹으로 묶어줘'
113
+ },
114
+ {
115
+ name: 'rename-sequential',
116
+ description: '선택 컴포넌트들에 순번 라벨',
117
+ template: '선택한 컴포넌트들에 1, 2, 3 순번 라벨을 붙여줘'
118
+ },
119
+ {
120
+ name: 'bulk-set',
121
+ description: '선택 컴포넌트 속성 일괄 변경',
122
+ template: '선택한 컴포넌트들의 [속성]을 [값]으로 일괄 설정해줘'
123
+ },
124
+ {
125
+ name: 'cleanup',
126
+ description: '겹침/어색한 위치 자동 정리',
127
+ template: '겹쳐있거나 어색한 위치의 컴포넌트들을 자연스럽게 정리해줘'
113
128
  }
114
129
  ]
@@ -93,6 +93,21 @@ export const DEFAULT_SLASH_TEMPLATES = [
93
93
  name: 'group',
94
94
  description: '선택 컴포넌트 그룹화',
95
95
  template: '선택한 컴포넌트들을 하나의 그룹으로 묶어줘'
96
+ },
97
+ {
98
+ name: 'rename-sequential',
99
+ description: '선택 컴포넌트들에 순번 라벨',
100
+ template: '선택한 컴포넌트들에 1, 2, 3 순번 라벨을 붙여줘'
101
+ },
102
+ {
103
+ name: 'bulk-set',
104
+ description: '선택 컴포넌트 속성 일괄 변경',
105
+ template: '선택한 컴포넌트들의 [속성]을 [값]으로 일괄 설정해줘'
106
+ },
107
+ {
108
+ name: 'cleanup',
109
+ description: '겹침/어색한 위치 자동 정리',
110
+ template: '겹쳐있거나 어색한 위치의 컴포넌트들을 자연스럽게 정리해줘'
96
111
  }
97
112
  ];
98
113
  //# sourceMappingURL=default-slash-templates.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"default-slash-templates.js","sourceRoot":"","sources":["../../../client/components/default-slash-templates.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,uBAAuB,GAAoB;IACtD;QACE,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,oBAAoB;QACjC,QAAQ,EAAE,0BAA0B;KACrC;IACD;QACE,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,iBAAiB;QAC9B,QAAQ,EAAE,sBAAsB;KACjC;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,mBAAmB;QAChC,QAAQ,EAAE,wBAAwB;KACnC;IACD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,eAAe;QAC5B,QAAQ,EAAE,mCAAmC;KAC9C;IACD;QACE,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,uBAAuB;QACpC,QAAQ,EAAE,6CAA6C;KACxD;IACD;QACE,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,gBAAgB;QAC7B,QAAQ,EAAE,oDAAoD;KAC/D;IACD;QACE,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,YAAY;QACzB,QAAQ,EAAE,+BAA+B;KAC1C;IACD;QACE,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,WAAW;QACxB,QAAQ,EAAE,mBAAmB;KAC9B;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,iBAAiB;QAC9B,QAAQ,EAAE,wBAAwB;KACnC;IACD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,eAAe;QAC5B,QAAQ,EAAE,yBAAyB;KACpC;IACD;QACE,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,2BAA2B;QACxC,QAAQ,EAAE,yBAAyB;KACpC;IACD;QACE,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,kBAAkB;QAC/B,QAAQ,EAAE,6BAA6B;KACxC;IACD;QACE,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,YAAY;QACzB,QAAQ,EAAE,iCAAiC;KAC5C;IACD;QACE,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,eAAe;QAC5B,QAAQ,EAAE,6BAA6B;KACxC;IACD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,eAAe;QAC5B,QAAQ,EAAE,8BAA8B;KACzC;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,YAAY;QACzB,QAAQ,EAAE,2BAA2B;KACtC;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,cAAc;QAC3B,QAAQ,EAAE,4BAA4B;KACvC;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,eAAe;QAC5B,QAAQ,EAAE,wBAAwB;KACnC;IACD;QACE,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,aAAa;QAC1B,QAAQ,EAAE,yBAAyB;KACpC;CACF,CAAA","sourcesContent":["/**\n * Default slash templates — 사용자에게 빠르게 작성된 자연어 prompt 를 끼워주는 단축키.\n *\n * `/grid` → \"선택한 컴포넌트들을 3x2 그리드로 정렬해줘\" 같이 텍스트가 textarea 에\n * 삽입됨. 사용자는 그대로 보내거나 숫자/카탈로그 이름을 수정해 보낼 수 있다.\n *\n * Slash 는 LLM 우회 명령이 아니다 — AI 가 받는 입력은 일반 자연어 prompt 와 동일.\n * 단지 \"이런 명령이 가능하구나\" 의 discoverability 를 popup 으로 보여주는 역할.\n *\n * 수정 / 추가 정책:\n * - 한국어 우선 (자연어가 한국어라야 한국 사용자에게 즉시 작동)\n * - 카탈로그 이름 (@monitor-card 등) 가 들어간 템플릿은 server-side resolver 와\n * 자동 호환 — drift 검증은 default-catalog-entries.test.ts 가 잡음\n * - 너무 많이 만들지 말 것 (popup 이 과해짐). 가장 흔한 의도만.\n */\nimport type { SlashTemplate } from './mention-popup-helpers.js'\n\nexport const DEFAULT_SLASH_TEMPLATES: SlashTemplate[] = [\n {\n name: 'grid',\n description: '선택한 컴포넌트들을 그리드로 정렬',\n template: '선택한 컴포넌트들을 3x2 그리드로 정렬해줘'\n },\n {\n name: 'row',\n description: '선택한 컴포넌트들을 한 줄로',\n template: '선택한 컴포넌트들을 한 줄로 배치해줘'\n },\n {\n name: 'column',\n description: '선택한 컴포넌트들을 세로로 일렬',\n template: '선택한 컴포넌트들을 세로로 일렬 배치해줘'\n },\n {\n name: 'palette',\n description: '검증된 색 팔레트로 통일',\n template: '@industrial-steel 팔레트로 보드 전체 통일해줘'\n },\n {\n name: 'atmosphere',\n description: '보드 분위기 변경 (자연어 자유 작성)',\n template: '보드 분위기를 어둡고 차분하게 바꿔줘 (atmosphere primer 활용)'\n },\n {\n name: 'dashboard',\n description: 'KPI 대시보드 기본 구성',\n template: '@kpi-row 레이아웃으로 @stat-tile 4개를 상단에 + 아래 메인 영역 구성해줘'\n },\n {\n name: 'add-monitor',\n description: '모니터링 카드 추가',\n template: '@monitor-card 추가 (제목과 값은 적절히)'\n },\n {\n name: 'fit',\n description: '보드 전체 보이게',\n template: '보드 전체가 보이게 화면 맞춰줘'\n },\n {\n name: 'center',\n description: '선택 컴포넌트 화면 가운데로',\n template: '선택한 컴포넌트를 화면 가운데로 이동해줘'\n },\n {\n name: 'inspect',\n description: '선택 컴포넌트 정보 보기',\n template: '현재 선택된 컴포넌트의 모든 속성을 보여줘'\n },\n {\n name: 'align',\n description: '선택 컴포넌트 정렬 (좌/우/위/아래/가운데)',\n template: '선택한 컴포넌트들을 왼쪽 기준으로 정렬해줘'\n },\n {\n name: 'distribute',\n description: '선택 컴포넌트 간격 균등 분배',\n template: '선택한 컴포넌트들을 가로로 간격 균등하게 분배해줘'\n },\n {\n name: 'duplicate',\n description: '선택 컴포넌트 복제',\n template: '선택한 컴포넌트를 오른쪽에 같은 크기로 하나 더 복제해줘'\n },\n {\n name: 'match-size',\n description: '선택 컴포넌트 크기 통일',\n template: '선택한 컴포넌트들을 첫 번째와 같은 크기로 맞춰줘'\n },\n {\n name: 'z-front',\n description: '선택 컴포넌트 맨 앞으로',\n template: '선택한 컴포넌트를 z-order 맨 앞으로 가져와줘'\n },\n {\n name: 'rotate',\n description: '선택 컴포넌트 회전',\n template: '선택한 컴포넌트를 시계방향으로 90도 회전해줘'\n },\n {\n name: 'z-back',\n description: '선택 컴포넌트 맨 뒤로',\n template: '선택한 컴포넌트를 z-order 맨 뒤로 보내줘'\n },\n {\n name: 'mirror',\n description: '선택 컴포넌트 좌우 반전',\n template: '선택한 컴포넌트를 좌우 대칭으로 반전해줘'\n },\n {\n name: 'group',\n description: '선택 컴포넌트 그룹화',\n template: '선택한 컴포넌트들을 하나의 그룹으로 묶어줘'\n }\n]\n"]}
1
+ {"version":3,"file":"default-slash-templates.js","sourceRoot":"","sources":["../../../client/components/default-slash-templates.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,uBAAuB,GAAoB;IACtD;QACE,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,oBAAoB;QACjC,QAAQ,EAAE,0BAA0B;KACrC;IACD;QACE,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,iBAAiB;QAC9B,QAAQ,EAAE,sBAAsB;KACjC;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,mBAAmB;QAChC,QAAQ,EAAE,wBAAwB;KACnC;IACD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,eAAe;QAC5B,QAAQ,EAAE,mCAAmC;KAC9C;IACD;QACE,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,uBAAuB;QACpC,QAAQ,EAAE,6CAA6C;KACxD;IACD;QACE,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,gBAAgB;QAC7B,QAAQ,EAAE,oDAAoD;KAC/D;IACD;QACE,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,YAAY;QACzB,QAAQ,EAAE,+BAA+B;KAC1C;IACD;QACE,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,WAAW;QACxB,QAAQ,EAAE,mBAAmB;KAC9B;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,iBAAiB;QAC9B,QAAQ,EAAE,wBAAwB;KACnC;IACD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,eAAe;QAC5B,QAAQ,EAAE,yBAAyB;KACpC;IACD;QACE,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,2BAA2B;QACxC,QAAQ,EAAE,yBAAyB;KACpC;IACD;QACE,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,kBAAkB;QAC/B,QAAQ,EAAE,6BAA6B;KACxC;IACD;QACE,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,YAAY;QACzB,QAAQ,EAAE,iCAAiC;KAC5C;IACD;QACE,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,eAAe;QAC5B,QAAQ,EAAE,6BAA6B;KACxC;IACD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,eAAe;QAC5B,QAAQ,EAAE,8BAA8B;KACzC;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,YAAY;QACzB,QAAQ,EAAE,2BAA2B;KACtC;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,cAAc;QAC3B,QAAQ,EAAE,4BAA4B;KACvC;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,eAAe;QAC5B,QAAQ,EAAE,wBAAwB;KACnC;IACD;QACE,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,aAAa;QAC1B,QAAQ,EAAE,yBAAyB;KACpC;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,WAAW,EAAE,iBAAiB;QAC9B,QAAQ,EAAE,+BAA+B;KAC1C;IACD;QACE,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,kBAAkB;QAC/B,QAAQ,EAAE,gCAAgC;KAC3C;IACD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,iBAAiB;QAC9B,QAAQ,EAAE,iCAAiC;KAC5C;CACF,CAAA","sourcesContent":["/**\n * Default slash templates — 사용자에게 빠르게 작성된 자연어 prompt 를 끼워주는 단축키.\n *\n * `/grid` → \"선택한 컴포넌트들을 3x2 그리드로 정렬해줘\" 같이 텍스트가 textarea 에\n * 삽입됨. 사용자는 그대로 보내거나 숫자/카탈로그 이름을 수정해 보낼 수 있다.\n *\n * Slash 는 LLM 우회 명령이 아니다 — AI 가 받는 입력은 일반 자연어 prompt 와 동일.\n * 단지 \"이런 명령이 가능하구나\" 의 discoverability 를 popup 으로 보여주는 역할.\n *\n * 수정 / 추가 정책:\n * - 한국어 우선 (자연어가 한국어라야 한국 사용자에게 즉시 작동)\n * - 카탈로그 이름 (@monitor-card 등) 가 들어간 템플릿은 server-side resolver 와\n * 자동 호환 — drift 검증은 default-catalog-entries.test.ts 가 잡음\n * - 너무 많이 만들지 말 것 (popup 이 과해짐). 가장 흔한 의도만.\n */\nimport type { SlashTemplate } from './mention-popup-helpers.js'\n\nexport const DEFAULT_SLASH_TEMPLATES: SlashTemplate[] = [\n {\n name: 'grid',\n description: '선택한 컴포넌트들을 그리드로 정렬',\n template: '선택한 컴포넌트들을 3x2 그리드로 정렬해줘'\n },\n {\n name: 'row',\n description: '선택한 컴포넌트들을 한 줄로',\n template: '선택한 컴포넌트들을 한 줄로 배치해줘'\n },\n {\n name: 'column',\n description: '선택한 컴포넌트들을 세로로 일렬',\n template: '선택한 컴포넌트들을 세로로 일렬 배치해줘'\n },\n {\n name: 'palette',\n description: '검증된 색 팔레트로 통일',\n template: '@industrial-steel 팔레트로 보드 전체 통일해줘'\n },\n {\n name: 'atmosphere',\n description: '보드 분위기 변경 (자연어 자유 작성)',\n template: '보드 분위기를 어둡고 차분하게 바꿔줘 (atmosphere primer 활용)'\n },\n {\n name: 'dashboard',\n description: 'KPI 대시보드 기본 구성',\n template: '@kpi-row 레이아웃으로 @stat-tile 4개를 상단에 + 아래 메인 영역 구성해줘'\n },\n {\n name: 'add-monitor',\n description: '모니터링 카드 추가',\n template: '@monitor-card 추가 (제목과 값은 적절히)'\n },\n {\n name: 'fit',\n description: '보드 전체 보이게',\n template: '보드 전체가 보이게 화면 맞춰줘'\n },\n {\n name: 'center',\n description: '선택 컴포넌트 화면 가운데로',\n template: '선택한 컴포넌트를 화면 가운데로 이동해줘'\n },\n {\n name: 'inspect',\n description: '선택 컴포넌트 정보 보기',\n template: '현재 선택된 컴포넌트의 모든 속성을 보여줘'\n },\n {\n name: 'align',\n description: '선택 컴포넌트 정렬 (좌/우/위/아래/가운데)',\n template: '선택한 컴포넌트들을 왼쪽 기준으로 정렬해줘'\n },\n {\n name: 'distribute',\n description: '선택 컴포넌트 간격 균등 분배',\n template: '선택한 컴포넌트들을 가로로 간격 균등하게 분배해줘'\n },\n {\n name: 'duplicate',\n description: '선택 컴포넌트 복제',\n template: '선택한 컴포넌트를 오른쪽에 같은 크기로 하나 더 복제해줘'\n },\n {\n name: 'match-size',\n description: '선택 컴포넌트 크기 통일',\n template: '선택한 컴포넌트들을 첫 번째와 같은 크기로 맞춰줘'\n },\n {\n name: 'z-front',\n description: '선택 컴포넌트 맨 앞으로',\n template: '선택한 컴포넌트를 z-order 맨 앞으로 가져와줘'\n },\n {\n name: 'rotate',\n description: '선택 컴포넌트 회전',\n template: '선택한 컴포넌트를 시계방향으로 90도 회전해줘'\n },\n {\n name: 'z-back',\n description: '선택 컴포넌트 맨 뒤로',\n template: '선택한 컴포넌트를 z-order 맨 뒤로 보내줘'\n },\n {\n name: 'mirror',\n description: '선택 컴포넌트 좌우 반전',\n template: '선택한 컴포넌트를 좌우 대칭으로 반전해줘'\n },\n {\n name: 'group',\n description: '선택 컴포넌트 그룹화',\n template: '선택한 컴포넌트들을 하나의 그룹으로 묶어줘'\n },\n {\n name: 'rename-sequential',\n description: '선택 컴포넌트들에 순번 라벨',\n template: '선택한 컴포넌트들에 1, 2, 3 순번 라벨을 붙여줘'\n },\n {\n name: 'bulk-set',\n description: '선택 컴포넌트 속성 일괄 변경',\n template: '선택한 컴포넌트들의 [속성]을 [값]으로 일괄 설정해줘'\n },\n {\n name: 'cleanup',\n description: '겹침/어색한 위치 자동 정리',\n template: '겹쳐있거나 어색한 위치의 컴포넌트들을 자연스럽게 정리해줘'\n }\n]\n"]}
@@ -1,12 +1,19 @@
1
1
  const ASPECT_TO_PATCH = {
2
2
  fill: { fillStyle: { type: 'none' } },
3
- stroke: { strokeStyle: { width: 0 } },
3
+ // stroke: strokeStyle 색상 문자열 (top-level), 굵기는 lineWidth (top-level).
4
+ // 굵기 0 으로 윤곽선 시각 제거 (색은 유지). 완전 제거는 strokeStyle: null 동시 set.
5
+ stroke: { lineWidth: 0 },
4
6
  shadow: { shadow: { blur: 0, color: 'transparent' } },
5
7
  material: { material3d: { preset: 'default' } },
6
- // font: 폰트는 reset 의도가 모호 — fontSize 같은 핵심 키만 unset 하고 나머지
7
- // 실제 reset deleteKey 필요한데 patch 시스템이 그걸 어떻게 표현할지 별도 결정.
8
- // 일단 placeholder 로 빈 객체 (의미 없음 — 향후 dispatch 에서 deleteKey 추가)
9
- font: {},
8
+ // font: null = delete 시맨틱 (apply-patch.ts:233-243). 핵심 폰트 모두 제거
9
+ // component 기본 폰트 동작으로 복귀. 보존이 의도라면 font aspect 미선택.
10
+ font: {
11
+ fontSize: null,
12
+ fontFamily: null,
13
+ fontColor: null,
14
+ fontWeight: null,
15
+ fontStyle: null
16
+ },
10
17
  opacity: { alpha: 1 }
11
18
  };
12
19
  export function buildClearStyleOps(input) {
@@ -1 +1 @@
1
- {"version":3,"file":"clear-tools.js","sourceRoot":"","sources":["../../../../server/service/styling/clear-tools.ts"],"names":[],"mappings":"AAiBA,MAAM,eAAe,GAAwB;IAC3C,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;IACrC,MAAM,EAAE,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IACrC,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE;IACrD,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE;IAC/C,8DAA8D;IAC9D,4DAA4D;IAC5D,8DAA8D;IAC9D,IAAI,EAAE,EAAE;IACR,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE;CACtB,CAAA;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAsB;IACvD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9D,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,kCAAkC,CAAC,EAAE,CAAA;IAClE,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;IACpF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,yBAAyB,CAAC,EAAE,CAAA;IAEhF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,mCAAmC,CAAC,EAAE,CAAA;IACnE,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,CAAA;IACzE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,GAAG,EAAE,EAAE;YACP,MAAM,EAAE,CAAC,sBAAsB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;SAChF,CAAA;IACH,CAAC;IAED,uDAAuD;IACvD,MAAM,MAAM,GAAQ,EAAE,CAAA;IACtB,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,CAAA;IAC3C,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,wCAAwC,CAAC,EAAE,CAAA;IACxE,CAAC;IAED,OAAO;QACL,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAClE,MAAM,EAAE,EAAE;KACX,CAAA;AACH,CAAC","sourcesContent":["/**\n * clearStyle — 특정 styling aspect 들을 초기화 (제거).\n *\n * preset 적용 전 / 데이터 바인딩 적용 전 깨끗한 상태로 돌리기 위한 helper.\n */\nimport type { BoardEditOp } from '../types'\n\nexport interface ClearStyleInput {\n refids: number[]\n aspects: Array<'fill' | 'stroke' | 'shadow' | 'material' | 'font' | 'opacity'>\n}\n\nexport interface OpsResult {\n ops: BoardEditOp[]\n errors: string[]\n}\n\nconst ASPECT_TO_PATCH: Record<string, any> = {\n fill: { fillStyle: { type: 'none' } },\n stroke: { strokeStyle: { width: 0 } },\n shadow: { shadow: { blur: 0, color: 'transparent' } },\n material: { material3d: { preset: 'default' } },\n // font: 폰트는 reset 의도가 모호 — fontSize 같은 핵심 키만 unset 하고 나머지 둠\n // 실제 reset deleteKey 필요한데 patch 시스템이 그걸 어떻게 표현할지 별도 결정.\n // 일단 placeholder 객체 (의미 없음 — 향후 dispatch 에서 deleteKey 추가)\n font: {},\n opacity: { alpha: 1 }\n}\n\nexport function buildClearStyleOps(input: ClearStyleInput): OpsResult {\n if (!Array.isArray(input.refids) || input.refids.length === 0) {\n return { ops: [], errors: ['refids must be a non-empty array'] }\n }\n const refids = input.refids.filter(n => typeof n === 'number' && Number.isFinite(n))\n if (refids.length === 0) return { ops: [], errors: ['No valid numeric refids'] }\n\n if (!Array.isArray(input.aspects) || input.aspects.length === 0) {\n return { ops: [], errors: ['aspects must be a non-empty array'] }\n }\n const valid = ['fill', 'stroke', 'shadow', 'material', 'font', 'opacity']\n const unknown = input.aspects.filter(a => !valid.includes(a))\n if (unknown.length > 0) {\n return {\n ops: [],\n errors: [`Unknown aspect(s): ${unknown.join(', ')}. Valid: ${valid.join('/')}`]\n }\n }\n\n // 모든 aspect 의 patch 를 하나로 병합 (한 refid 당 하나의 modify op)\n const merged: any = {}\n for (const a of input.aspects) {\n Object.assign(merged, ASPECT_TO_PATCH[a])\n }\n if (Object.keys(merged).length === 0) {\n return { ops: [], errors: ['No effective patch — try other aspects'] }\n }\n\n return {\n ops: refids.map(refid => ({ op: 'modify', refid, patch: merged })),\n errors: []\n }\n}\n"]}
1
+ {"version":3,"file":"clear-tools.js","sourceRoot":"","sources":["../../../../server/service/styling/clear-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * clearStyle — 특정 styling aspect 들을 초기화 (제거).\n *\n * preset 적용 전 / 데이터 바인딩 적용 전 깨끗한 상태로 돌리기 위한 helper.\n */\nimport type { BoardEditOp } from '../types'\n\nexport interface ClearStyleInput {\n refids: number[]\n aspects: Array<'fill' | 'stroke' | 'shadow' | 'material' | 'font' | 'opacity'>\n}\n\nexport interface OpsResult {\n ops: BoardEditOp[]\n errors: string[]\n}\n\nconst ASPECT_TO_PATCH: Record<string, any> = {\n fill: { fillStyle: { type: 'none' } },\n // stroke: strokeStyle 는 색상 문자열 (top-level), 굵기는 lineWidth (top-level).\n // 굵기 0 으로 윤곽선 시각 제거 (색은 유지). 완전 제거는 strokeStyle: null 동시 set.\n stroke: { lineWidth: 0 },\n shadow: { shadow: { blur: 0, color: 'transparent' } },\n material: { material3d: { preset: 'default' } },\n // font: null = delete 시맨틱 (apply-patch.ts:233-243). 핵심 폰트 모두 제거 →\n // component 기본 폰트 동작으로 복귀. 보존이 의도라면 font aspect 미선택.\n font: {\n fontSize: null,\n fontFamily: null,\n fontColor: null,\n fontWeight: null,\n fontStyle: null\n },\n opacity: { alpha: 1 }\n}\n\nexport function buildClearStyleOps(input: ClearStyleInput): OpsResult {\n if (!Array.isArray(input.refids) || input.refids.length === 0) {\n return { ops: [], errors: ['refids must be a non-empty array'] }\n }\n const refids = input.refids.filter(n => typeof n === 'number' && Number.isFinite(n))\n if (refids.length === 0) return { ops: [], errors: ['No valid numeric refids'] }\n\n if (!Array.isArray(input.aspects) || input.aspects.length === 0) {\n return { ops: [], errors: ['aspects must be a non-empty array'] }\n }\n const valid = ['fill', 'stroke', 'shadow', 'material', 'font', 'opacity']\n const unknown = input.aspects.filter(a => !valid.includes(a))\n if (unknown.length > 0) {\n return {\n ops: [],\n errors: [`Unknown aspect(s): ${unknown.join(', ')}. Valid: ${valid.join('/')}`]\n }\n }\n\n // 모든 aspect 의 patch 를 하나로 병합 (한 refid 당 하나의 modify op)\n const merged: any = {}\n for (const a of input.aspects) {\n Object.assign(merged, ASPECT_TO_PATCH[a])\n }\n if (Object.keys(merged).length === 0) {\n return { ops: [], errors: ['No effective patch — try other aspects'] }\n }\n\n return {\n ops: refids.map(refid => ({ op: 'modify', refid, patch: merged })),\n errors: []\n }\n}\n"]}