@fmsim/board 2.0.2 → 3.0.0-beta.1

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.
Files changed (35) hide show
  1. package/custom-elements.json +161 -53
  2. package/dist/src/board-thumbnail.d.ts +6 -0
  3. package/dist/src/board-thumbnail.js +21 -0
  4. package/dist/src/board-thumbnail.js.map +1 -0
  5. package/dist/src/index.d.ts +2 -0
  6. package/dist/src/index.js +7 -0
  7. package/dist/src/index.js.map +1 -1
  8. package/dist/src/layers/movement-layer.js +21 -7
  9. package/dist/src/layers/movement-layer.js.map +1 -1
  10. package/dist/src/modeller/bulk-create-dialog.js +4 -4
  11. package/dist/src/modeller/bulk-create-dialog.js.map +1 -1
  12. package/dist/src/modeller/component-toolbar/component-menu.js +62 -6
  13. package/dist/src/modeller/component-toolbar/component-menu.js.map +1 -1
  14. package/dist/src/modeller/component-toolbar/component-toolbar.d.ts +1 -0
  15. package/dist/src/modeller/component-toolbar/component-toolbar.js +28 -7
  16. package/dist/src/modeller/component-toolbar/component-toolbar.js.map +1 -1
  17. package/dist/src/modeller/property-sidebar/specifics/specifics.d.ts +2 -0
  18. package/dist/src/modeller/property-sidebar/specifics/specifics.js +18 -0
  19. package/dist/src/modeller/property-sidebar/specifics/specifics.js.map +1 -1
  20. package/dist/src/modeller/scene-viewer/ox-scene-viewer.d.ts +2 -0
  21. package/dist/src/modeller/scene-viewer/ox-scene-viewer.js +4 -0
  22. package/dist/src/modeller/scene-viewer/ox-scene-viewer.js.map +1 -1
  23. package/dist/src/ox-board-list.js +2 -4
  24. package/dist/src/ox-board-list.js.map +1 -1
  25. package/dist/src/ox-board-modeller.d.ts +2 -0
  26. package/dist/src/ox-board-modeller.js +4 -0
  27. package/dist/src/ox-board-modeller.js.map +1 -1
  28. package/dist/src/ox-board-viewer.js +11 -11
  29. package/dist/src/ox-board-viewer.js.map +1 -1
  30. package/dist/src/selector/ox-board-selector.js +2 -5
  31. package/dist/src/selector/ox-board-selector.js.map +1 -1
  32. package/dist/src/types.d.ts +10 -0
  33. package/dist/src/types.js.map +1 -1
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/package.json +7 -6
@@ -1 +1 @@
1
- {"version":3,"file":"bulk-create-dialog.js","sourceRoot":"","sources":["../../../src/modeller/bulk-create-dialog.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * 멀티 컴포넌트 생성 dialog — 템플릿 + 영역 + 옵션 입력 → OK 시 콜백 호출.\n */\n\nimport { LitElement, css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\n\nimport { OxInputEntityId } from './property-sidebar/shapes/ox-input-entity-id'\n\nimport {\n generateBulkComponents,\n findIdConflicts,\n inferIdPattern,\n nextAvailableStart,\n deriveGridShape,\n type BulkCreateOptions,\n type Pattern,\n type Area\n} from './bulk-create.js'\n\nexport type ConflictPolicy = 'skip' | 'duplicate'\n\nexport interface BulkCreateDialogProps {\n /** 템플릿 컴포넌트 state (read-only 표시용). */\n template: Record<string, any>\n /** 초기 영역 (보드 좌표). 사용자가 dialog 내에서 조정 가능. */\n initialArea: Area\n /** 기존 scene 의 모든 ID — 충돌 검사. */\n existingIds?: Set<string>\n /** OK 클릭 시 콜백 — 생성할 model 배열 전달. */\n onConfirm: (models: ReturnType<typeof generateBulkComponents>) => void\n /** 취소 / 닫기 콜백. */\n onCancel?: () => void\n}\n\n@customElement('bulk-create-dialog')\nexport class BulkCreateDialog extends ScopedElementsMixin(LitElement) {\n static get scopedElements() {\n return {\n 'ox-input-entity-id': OxInputEntityId\n }\n }\n\n static styles = css`\n :host {\n display: block;\n padding: 16px 20px;\n min-width: 340px;\n max-width: 480px;\n background: rgba(30, 30, 30, 0.94);\n border: 1px solid rgba(255, 255, 255, 0.08);\n border-radius: 10px;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);\n color: rgba(255, 255, 255, 0.85);\n font: 12px/1.6 -apple-system, BlinkMacSystemFont, sans-serif;\n }\n h3 {\n margin: 0 0 12px;\n font-size: 13px;\n font-weight: 600;\n color: #4a9eff;\n }\n .row {\n display: grid;\n grid-template-columns: 100px 1fr;\n align-items: center;\n gap: 8px;\n margin: 6px 0;\n }\n label {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.55);\n }\n input,\n select {\n padding: 4px 6px;\n font: inherit;\n font-size: 12px;\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 3px;\n width: 100%;\n box-sizing: border-box;\n color: rgba(255, 255, 255, 0.9);\n outline: none;\n }\n input:focus,\n select:focus {\n border-color: #4a9eff;\n background: rgba(74, 158, 255, 0.08);\n }\n /* parentObject 입력(ox-input-entity-id)의 내부 input 을 dialog 의 다른 input 과 통일. */\n ox-input-entity-id::part(input) {\n padding: 4px 6px;\n font: inherit;\n font-size: 12px;\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 3px;\n color: rgba(255, 255, 255, 0.9);\n outline: none;\n }\n ox-input-entity-id::part(input):focus {\n border-color: #4a9eff;\n background: rgba(74, 158, 255, 0.08);\n }\n /* 검색 드롭다운(shadow 내부)은 md-sys-color 변수 + 상속 color 로 다크 테마 통일.\n (변수는 shadow 경계를 관통하고, .item 은 color 를 host 로부터 상속받는다.) */\n ox-input-entity-id {\n color: rgba(255, 255, 255, 0.9);\n --md-sys-color-surface: rgb(30, 30, 30);\n --md-sys-color-surface-variant: rgb(45, 45, 45);\n --md-sys-color-outline-variant: rgba(255, 255, 255, 0.15);\n --md-sys-color-secondary-container: rgba(74, 158, 255, 0.25);\n --md-sys-color-on-surface-variant: rgba(255, 255, 255, 0.55);\n }\n select option {\n background: rgb(30, 30, 30);\n color: rgba(255, 255, 255, 0.9);\n }\n .grid-shape {\n display: grid;\n grid-template-columns: 1fr 20px 1fr;\n gap: 4px;\n align-items: center;\n }\n .grid-shape > span {\n text-align: center;\n color: rgba(255, 255, 255, 0.35);\n }\n .pattern-picker {\n display: flex;\n gap: 6px;\n }\n .pattern-btn {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n padding: 6px 4px;\n background: rgba(255, 255, 255, 0.04);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 4px;\n cursor: pointer;\n color: rgba(255, 255, 255, 0.6);\n transition: background 0.1s, border-color 0.1s;\n }\n .pattern-btn:hover {\n background: rgba(255, 255, 255, 0.08);\n }\n .pattern-btn.active {\n border-color: #4a9eff;\n background: rgba(74, 158, 255, 0.15);\n color: rgba(255, 255, 255, 0.95);\n }\n .pattern-btn svg {\n width: 28px;\n height: 28px;\n }\n .pattern-btn svg circle {\n fill: currentColor;\n }\n .pattern-btn span {\n font-size: 10.5px;\n }\n .policy-radios {\n display: flex;\n gap: 12px;\n align-items: center;\n }\n .policy-radios label {\n display: flex;\n align-items: center;\n gap: 4px;\n cursor: pointer;\n color: rgba(255, 255, 255, 0.75);\n }\n .policy-radios input[type='radio'] {\n width: auto;\n accent-color: #4a9eff;\n margin: 0;\n }\n code {\n font-family: ui-monospace, SFMono-Regular, monospace;\n background: rgba(255, 255, 255, 0.08);\n padding: 1px 4px;\n border-radius: 3px;\n color: #b6d4fe;\n font-size: 11px;\n }\n .hint {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n margin-top: 2px;\n grid-column: 2;\n }\n .preview {\n font-size: 11.5px;\n color: rgba(255, 255, 255, 0.65);\n margin-top: 10px;\n padding: 6px 8px;\n background: rgba(255, 255, 255, 0.04);\n border-radius: 4px;\n }\n .conflict {\n margin-top: 8px;\n padding: 8px 10px;\n background: rgba(255, 100, 100, 0.12);\n border: 1px solid rgba(255, 100, 100, 0.3);\n border-radius: 4px;\n color: #ffb3b3;\n font-size: 11.5px;\n }\n .conflict strong {\n color: #ff8080;\n }\n .conflict-hint {\n margin-top: 4px;\n color: rgba(255, 255, 255, 0.45);\n font-size: 11px;\n }\n .actions {\n margin-top: 16px;\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n }\n button {\n padding: 5px 14px;\n font: inherit;\n font-size: 12px;\n border: 1px solid rgba(255, 255, 255, 0.15);\n background: rgba(255, 255, 255, 0.06);\n color: rgba(255, 255, 255, 0.85);\n cursor: pointer;\n border-radius: 4px;\n }\n button:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.1);\n }\n button:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n button.primary {\n background: #4a9eff;\n color: white;\n border-color: #4a9eff;\n }\n button.primary:hover:not(:disabled) {\n background: #6db1ff;\n }\n `\n\n @property({ type: Object }) template!: Record<string, any>\n @property({ type: Object }) initialArea!: Area\n @property({ attribute: false }) existingIds: Set<string> = new Set()\n @property({ attribute: false }) onConfirm!: BulkCreateDialogProps['onConfirm']\n @property({ attribute: false }) onCancel?: BulkCreateDialogProps['onCancel']\n /** parentObject 필드 노출 여부 (template 이 ParentObjectMixin 컴포넌트일 때). */\n @property({ attribute: false }) hasParentObject = false\n /** parentObject 후보 id 리스트 (template 타입 기준, toolbar 에서 계산해 주입). */\n @property({ attribute: false }) parentObjectItems: string[] = []\n\n @state() private pattern: Pattern = 'grid'\n @state() private parentObjectId = ''\n @state() private count = 12\n @state() private rows: number | undefined = undefined\n @state() private cols: number | undefined = undefined\n @state() private idPattern = '{i}'\n @state() private idStart = 1\n @state() private idPadding = 0\n @state() private area!: Area\n @state() private conflictPolicy: ConflictPolicy = 'skip'\n\n @query('#count-input') countInput!: HTMLInputElement\n\n connectedCallback() {\n super.connectedCallback()\n // OxPopup wrapper (ox-popup) 의 흰색 배경 + box-shadow 가 dialog 라운드 코너\n // 밖으로 비쳐서 4 꼭지점에 흰색 사각형이 보임. 부모를 투명/그림자 없이 만들어\n // dialog 자체의 라운드 + 그림자만 보이게.\n const parent = this.parentElement as HTMLElement | null\n if (parent) {\n parent.style.background = 'transparent'\n parent.style.boxShadow = 'none'\n parent.style.border = 'none'\n }\n this.area = { ...this.initialArea }\n\n // 1) 영역 종횡비로 레이아웃 기본 선택:\n // 너비 ≫ 높이 → line-h (가로), 높이 ≫ 너비 → line-v (세로), 비슷하면 grid.\n const w = Math.max(this.area.width, 1)\n const h = Math.max(this.area.height, 1)\n const aspect = w / h\n if (aspect >= 2.5) this.pattern = 'line-h'\n else if (aspect <= 0.4) this.pattern = 'line-v'\n else this.pattern = 'grid'\n\n // 2) 템플릿 id 로부터 ID 패턴 / padding 자동 추론.\n const inferred = inferIdPattern(this.template?.id)\n this.idPattern = inferred.pattern\n this.idPadding = inferred.padding\n\n // 3) 시작 번호 = existingIds 에 패턴 매칭되는 *최대 번호 + 1*.\n // 반복 bulk-paste 시 이전 batch 의 끝 다음으로 자동 advance.\n // 매칭 ID 가 없으면 inferIdPattern 의 fallback (= template num+1) 사용.\n this.idStart = nextAvailableStart(inferred.pattern, this.existingIds, inferred.start)\n\n // 4) 복사 대상(template)이 이미 parentObjectId 를 가지면 그것을 초기값으로.\n this.parentObjectId = String(this.template?.parentObjectId ?? '')\n }\n\n /** rows/cols 가 미입력 (undefined) 이면 영역 종횡비 + count 로 자동 계산해 표시. */\n private get displayRows(): number {\n if (this.rows != null) return this.rows\n return deriveGridShape(this.count, this.area, undefined, this.cols).rows\n }\n\n private get displayCols(): number {\n if (this.cols != null) return this.cols\n return deriveGridShape(this.count, this.area, this.rows, undefined).cols\n }\n\n firstUpdated() {\n this.countInput?.focus()\n this.countInput?.select()\n }\n\n private updateArea(field: keyof Area, value: number) {\n this.area = { ...this.area, [field]: value }\n }\n\n private get previewModels() {\n if (!this.template) return []\n return generateBulkComponents({\n template: this.template,\n area: this.area,\n pattern: this.pattern,\n count: this.count,\n rows: this.rows,\n cols: this.cols,\n idPattern: this.idPattern.replace(/\\{type\\}/g, String(this.template?.type ?? 'C')),\n idStart: this.idStart,\n idPadding: this.idPadding,\n // 선택 시 각 생성 컴포넌트에 parentObjectId 를 병합 (도메인 특수값은 여기서만).\n extraState: this.parentObjectId ? { parentObjectId: this.parentObjectId } : undefined\n })\n }\n\n private get conflicts(): string[] {\n return findIdConflicts(this.previewModels, this.existingIds)\n }\n\n /** 충돌 정책 적용 후 실제 생성될 model 배열. */\n private get effectiveModels() {\n const all = this.previewModels\n if (this.conflictPolicy === 'skip' && this.existingIds.size > 0) {\n return all.filter(m => !this.existingIds.has(m.id))\n }\n return all\n }\n\n private onOk = () => {\n const models = this.effectiveModels\n if (models.length === 0) return\n this.onConfirm(models)\n }\n\n private onCancelClick = () => {\n this.onCancel?.()\n }\n\n render() {\n const tplType = this.template?.type ?? '?'\n const tplId = this.template?.id ?? '?'\n const models = this.previewModels\n\n return html`\n <h3>Bulk Paste — ${tplType}</h3>\n\n <div class=\"row\">\n <label>템플릿</label>\n <span style=\"color:#b6d4fe;\">${tplId} <span style=\"color:rgba(255,255,255,0.4);\">(${tplType})</span></span>\n </div>\n\n <div class=\"row\">\n <label>레이아웃</label>\n <div class=\"pattern-picker\">\n <button\n type=\"button\"\n class=\"pattern-btn ${this.pattern === 'grid' ? 'active' : ''}\"\n @click=${() => (this.pattern = 'grid')}\n title=\"격자\"\n >\n <svg viewBox=\"0 0 24 24\">\n <circle cx=\"6\" cy=\"6\" r=\"1.6\" /><circle cx=\"12\" cy=\"6\" r=\"1.6\" /><circle cx=\"18\" cy=\"6\" r=\"1.6\" />\n <circle cx=\"6\" cy=\"12\" r=\"1.6\" /><circle cx=\"12\" cy=\"12\" r=\"1.6\" /><circle cx=\"18\" cy=\"12\" r=\"1.6\" />\n <circle cx=\"6\" cy=\"18\" r=\"1.6\" /><circle cx=\"12\" cy=\"18\" r=\"1.6\" /><circle cx=\"18\" cy=\"18\" r=\"1.6\" />\n </svg>\n <span>격자</span>\n </button>\n <button\n type=\"button\"\n class=\"pattern-btn ${this.pattern === 'line-h' ? 'active' : ''}\"\n @click=${() => (this.pattern = 'line-h')}\n title=\"가로 1줄\"\n >\n <svg viewBox=\"0 0 24 24\">\n <circle cx=\"3\" cy=\"12\" r=\"1.6\" /><circle cx=\"8\" cy=\"12\" r=\"1.6\" /><circle cx=\"13\" cy=\"12\" r=\"1.6\" />\n <circle cx=\"18\" cy=\"12\" r=\"1.6\" /><circle cx=\"22\" cy=\"12\" r=\"1.4\" />\n </svg>\n <span>가로</span>\n </button>\n <button\n type=\"button\"\n class=\"pattern-btn ${this.pattern === 'line-v' ? 'active' : ''}\"\n @click=${() => (this.pattern = 'line-v')}\n title=\"세로 1줄\"\n >\n <svg viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"3\" r=\"1.6\" /><circle cx=\"12\" cy=\"8\" r=\"1.6\" /><circle cx=\"12\" cy=\"13\" r=\"1.6\" />\n <circle cx=\"12\" cy=\"18\" r=\"1.6\" /><circle cx=\"12\" cy=\"22\" r=\"1.4\" />\n </svg>\n <span>세로</span>\n </button>\n </div>\n </div>\n\n <div class=\"row\">\n <label>개수</label>\n <input\n id=\"count-input\"\n type=\"number\"\n min=\"1\"\n .value=${String(this.count)}\n @input=${(e: Event) => (this.count = Math.max(1, +(e.target as HTMLInputElement).value))}\n />\n </div>\n\n ${this.pattern === 'grid'\n ? html`\n <div class=\"row\">\n <label>행 × 열</label>\n <div class=\"grid-shape\">\n <input\n type=\"number\"\n min=\"1\"\n .value=${String(this.displayRows)}\n @input=${(e: Event) => {\n const v = (e.target as HTMLInputElement).value\n this.rows = v ? Math.max(1, +v) : undefined\n }}\n />\n <span>×</span>\n <input\n type=\"number\"\n min=\"1\"\n .value=${String(this.displayCols)}\n @input=${(e: Event) => {\n const v = (e.target as HTMLInputElement).value\n this.cols = v ? Math.max(1, +v) : undefined\n }}\n />\n </div>\n </div>\n `\n : ''}\n\n <div class=\"row\">\n <label>ID 패턴</label>\n <input\n type=\"text\"\n .value=${this.idPattern}\n @input=${(e: Event) => (this.idPattern = (e.target as HTMLInputElement).value)}\n />\n </div>\n <div class=\"row\">\n <span></span>\n <div class=\"hint\">placeholder: <code>{i}</code> 일련번호, <code>{r}</code> 행, <code>{c}</code> 열 (grid)</div>\n </div>\n\n <div class=\"row\">\n <label>시작 번호</label>\n <input\n type=\"number\"\n .value=${String(this.idStart)}\n @input=${(e: Event) => (this.idStart = +(e.target as HTMLInputElement).value)}\n />\n </div>\n\n <div class=\"row\">\n <label>Zero-pad 자릿수</label>\n <input\n type=\"number\"\n min=\"0\"\n .value=${String(this.idPadding)}\n @input=${(e: Event) => (this.idPadding = Math.max(0, +(e.target as HTMLInputElement).value))}\n />\n </div>\n\n ${this.hasParentObject\n ? html`\n <div class=\"row\">\n <label>상위 객체</label>\n <ox-input-entity-id\n .localItems=${this.parentObjectItems}\n .value=${this.parentObjectId}\n placeholder=\"상위 객체 id (검색)\"\n @change=${(e: Event) => (this.parentObjectId = (e.target as OxInputEntityId).value)}\n ></ox-input-entity-id>\n </div>\n `\n : ''}\n\n <div class=\"preview\">\n ${models.length > 0\n ? html`총 ${models.length}개 — 예: <code>${models[0].id}</code> ... <code>${models[models.length - 1].id}</code>`\n : html`<span style=\"color:#ff8080;\">생성될 컴포넌트 없음</span>`}\n </div>\n\n ${this.conflicts.length > 0\n ? html`\n <div class=\"conflict\">\n <strong>ID 충돌 ${this.conflicts.length}개</strong>\n <code>${this.conflicts.slice(0, 5).join(', ')}${this.conflicts.length > 5 ? ', ...' : ''}</code>\n <div class=\"conflict-hint\" style=\"margin-top:6px;\">\n <div class=\"policy-radios\">\n <label>\n <input\n type=\"radio\"\n name=\"conflict-policy\"\n value=\"skip\"\n .checked=${this.conflictPolicy === 'skip'}\n @change=${() => (this.conflictPolicy = 'skip')}\n />\n 충돌 ID 스킵 (기본)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"conflict-policy\"\n value=\"duplicate\"\n .checked=${this.conflictPolicy === 'duplicate'}\n @change=${() => (this.conflictPolicy = 'duplicate')}\n />\n 중복 그대로 생성\n </label>\n </div>\n </div>\n </div>\n `\n : ''}\n\n <div class=\"actions\">\n <button @click=${this.onCancelClick}>취소</button>\n <button\n class=\"primary\"\n @click=${this.onOk}\n ?disabled=${this.effectiveModels.length === 0}\n >\n 생성 (${this.effectiveModels.length}${\n this.conflicts.length > 0 && this.conflictPolicy === 'skip'\n ? html`<span style=\"opacity:0.6;\"> / ${models.length}</span>`\n : ''\n })\n </button>\n </div>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'bulk-create-dialog': BulkCreateDialog\n }\n}\n"]}
1
+ {"version":3,"file":"bulk-create-dialog.js","sourceRoot":"","sources":["../../../src/modeller/bulk-create-dialog.ts"],"names":[],"mappings":"AAAA;;;;GAIG;;AAEH,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAE9D,OAAO,EAAE,eAAe,EAAE,MAAM,8CAA8C,CAAA;AAE9E,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,eAAe,EAIhB,MAAM,kBAAkB,CAAA;AAkBlB,IAAM,gBAAgB,GAAtB,MAAM,gBAAiB,SAAQ,mBAAmB,CAAC,UAAU,CAAC;IAA9D;;QA+N2B,gBAAW,GAAgB,IAAI,GAAG,EAAE,CAAA;QAGpE,oEAAoE;QACpC,oBAAe,GAAG,KAAK,CAAA;QACvD,kEAAkE;QAClC,sBAAiB,GAAa,EAAE,CAAA;QAE/C,YAAO,GAAY,MAAM,CAAA;QACzB,mBAAc,GAAG,EAAE,CAAA;QACnB,UAAK,GAAG,EAAE,CAAA;QACV,SAAI,GAAuB,SAAS,CAAA;QACpC,SAAI,GAAuB,SAAS,CAAA;QACpC,cAAS,GAAG,KAAK,CAAA;QACjB,YAAO,GAAG,CAAC,CAAA;QACX,cAAS,GAAG,CAAC,CAAA;QAEb,mBAAc,GAAmB,MAAM,CAAA;QA0FhD,SAAI,GAAG,GAAG,EAAE;YAClB,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAA;YACnC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAM;YAC/B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QACxB,CAAC,CAAA;QAEO,kBAAa,GAAG,GAAG,EAAE;;YAC3B,MAAA,IAAI,CAAC,QAAQ,oDAAI,CAAA;QACnB,CAAC,CAAA;IAuMH,CAAC;IAxhBC,MAAM,KAAK,cAAc;QACvB,OAAO;YACL,oBAAoB,EAAE,eAAe;SACtC,CAAA;IACH,CAAC;IA+OD,iBAAiB;;QACf,KAAK,CAAC,iBAAiB,EAAE,CAAA;QACzB,kEAAkE;QAClE,+CAA+C;QAC/C,6BAA6B;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,aAAmC,CAAA;QACvD,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,aAAa,CAAA;YACvC,MAAM,CAAC,KAAK,CAAC,SAAS,GAAG,MAAM,CAAA;YAC/B,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAA;QAC9B,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,CAAA;QAEnC,yBAAyB;QACzB,8DAA8D;QAC9D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QACtC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QACvC,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,CAAA;QACpB,IAAI,MAAM,IAAI,GAAG;YAAE,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAA;aACrC,IAAI,MAAM,IAAI,GAAG;YAAE,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAA;;YAC1C,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QAE1B,uCAAuC;QACvC,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAA,IAAI,CAAC,QAAQ,0CAAE,EAAE,CAAC,CAAA;QAClD,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAA;QACjC,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAA;QAEjC,gDAAgD;QAChD,mDAAmD;QACnD,kEAAkE;QAClE,IAAI,CAAC,OAAO,GAAG,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;QAErF,yDAAyD;QACzD,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,MAAA,MAAA,IAAI,CAAC,QAAQ,0CAAE,cAAc,mCAAI,EAAE,CAAC,CAAA;IACnE,CAAC;IAED,iEAAiE;IACjE,IAAY,WAAW;QACrB,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC,IAAI,CAAA;QACvC,OAAO,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAA;IAC1E,CAAC;IAED,IAAY,WAAW;QACrB,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC,IAAI,CAAA;QACvC,OAAO,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,IAAI,CAAA;IAC1E,CAAC;IAED,YAAY;;QACV,MAAA,IAAI,CAAC,UAAU,0CAAE,KAAK,EAAE,CAAA;QACxB,MAAA,IAAI,CAAC,UAAU,0CAAE,MAAM,EAAE,CAAA;IAC3B,CAAC;IAEO,UAAU,CAAC,KAAiB,EAAE,KAAa;QACjD,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAA;IAC9C,CAAC;IAED,IAAY,aAAa;;QACvB,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO,EAAE,CAAA;QAC7B,OAAO,sBAAsB,CAAC;YAC5B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,MAAA,MAAA,IAAI,CAAC,QAAQ,0CAAE,IAAI,mCAAI,GAAG,CAAC,CAAC;YAClF,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,uDAAuD;YACvD,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,SAAS;SACtF,CAAC,CAAA;IACJ,CAAC;IAED,IAAY,SAAS;QACnB,OAAO,eAAe,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;IAC9D,CAAC;IAED,kCAAkC;IAClC,IAAY,eAAe;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAA;QAC9B,IAAI,IAAI,CAAC,cAAc,KAAK,MAAM,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAChE,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACrD,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;IAYD,MAAM;;QACJ,MAAM,OAAO,GAAG,MAAA,MAAA,IAAI,CAAC,QAAQ,0CAAE,IAAI,mCAAI,GAAG,CAAA;QAC1C,MAAM,KAAK,GAAG,MAAA,MAAA,IAAI,CAAC,QAAQ,0CAAE,EAAE,mCAAI,GAAG,CAAA;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAA;QAEjC,OAAO,IAAI,CAAA;yBACU,OAAO;;;;uCAIO,KAAK,gDAAgD,OAAO;;;;;;;;iCAQlE,IAAI,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;qBACnD,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;;;;;;;;;;;;iCAYjB,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;qBACrD,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC;;;;;;;;;;;iCAWnB,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;qBACrD,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC;;;;;;;;;;;;;;;;;;mBAkBjC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;mBAClB,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAE,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC,CAAC;;;;QAI1F,IAAI,CAAC,OAAO,KAAK,MAAM;YACvB,CAAC,CAAC,IAAI,CAAA;;;;;;;2BAOa,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;2BACxB,CAAC,CAAQ,EAAE,EAAE;gBACpB,MAAM,CAAC,GAAI,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAA;gBAC9C,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAC7C,CAAC;;;;;;2BAMQ,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;2BACxB,CAAC,CAAQ,EAAE,EAAE;gBACpB,MAAM,CAAC,GAAI,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAA;gBAC9C,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAC7C,CAAC;;;;WAIR;YACH,CAAC,CAAC,EAAE;;;;;;mBAMO,IAAI,CAAC,SAAS;mBACd,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,GAAI,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC;;;;;;;;;;;;mBAYrE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;mBACpB,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,CAAE,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC;;;;;;;;;mBASpE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;mBACtB,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAE,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC,CAAC;;;;QAI9F,IAAI,CAAC,eAAe;YACpB,CAAC,CAAC,IAAI,CAAA;;;;8BAIgB,IAAI,CAAC,iBAAiB;yBAC3B,IAAI,CAAC,cAAc;;0BAElB,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,GAAI,CAAC,CAAC,MAA0B,CAAC,KAAK,CAAC;;;WAGxF;YACH,CAAC,CAAC,EAAE;;;UAGF,MAAM,CAAC,MAAM,GAAG,CAAC;YACjB,CAAC,CAAC,IAAI,CAAA,KAAK,MAAM,CAAC,MAAM,gBAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,qBAAqB,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,SAAS;YAC9G,CAAC,CAAC,IAAI,CAAA,qDAAqD;;;QAG7D,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;YACzB,CAAC,CAAC,IAAI,CAAA;;8BAEgB,IAAI,CAAC,SAAS,CAAC,MAAM;sBAC7B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;;;;;;;;iCAQrE,IAAI,CAAC,cAAc,KAAK,MAAM;gCAC/B,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC;;;;;;;;;iCASnC,IAAI,CAAC,cAAc,KAAK,WAAW;gCACpC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,GAAG,WAAW,CAAC;;;;;;;WAO9D;YACH,CAAC,CAAC,EAAE;;;yBAGa,IAAI,CAAC,aAAa;;;mBAGxB,IAAI,CAAC,IAAI;sBACN,IAAI,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC;;gBAEvC,IAAI,CAAC,eAAe,CAAC,MAAM,GAC/B,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,cAAc,KAAK,MAAM;YACzD,CAAC,CAAC,IAAI,CAAA,iCAAiC,MAAM,CAAC,MAAM,SAAS;YAC7D,CAAC,CAAC,EACN;;;KAGL,CAAA;IACH,CAAC;;AAjhBM,uBAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoNlB,AApNY,CAoNZ;AAE2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;kDAA+B;AAC9B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;qDAAmB;AACd;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;qDAAqC;AACpC;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;mDAA+C;AAC9C;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;kDAA6C;AAE5C;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;yDAAwB;AAEvB;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;2DAAiC;AAE/C;IAAhB,KAAK,EAAE;iDAAkC;AACzB;IAAhB,KAAK,EAAE;wDAA4B;AACnB;IAAhB,KAAK,EAAE;+CAAmB;AACV;IAAhB,KAAK,EAAE;8CAA6C;AACpC;IAAhB,KAAK,EAAE;8CAA6C;AACpC;IAAhB,KAAK,EAAE;mDAA0B;AACjB;IAAhB,KAAK,EAAE;iDAAoB;AACX;IAAhB,KAAK,EAAE;mDAAsB;AACb;IAAhB,KAAK,EAAE;8CAAoB;AACX;IAAhB,KAAK,EAAE;wDAAgD;AAEjC;IAAtB,KAAK,CAAC,cAAc,CAAC;oDAA8B;AAlPzC,gBAAgB;IAD5B,aAAa,CAAC,oBAAoB,CAAC;GACvB,gBAAgB,CAyhB5B","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * 멀티 컴포넌트 생성 dialog — 템플릿 + 영역 + 옵션 입력 → OK 시 콜백 호출.\n */\n\nimport { LitElement, css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\n\nimport { OxInputEntityId } from './property-sidebar/shapes/ox-input-entity-id'\n\nimport {\n generateBulkComponents,\n findIdConflicts,\n inferIdPattern,\n nextAvailableStart,\n deriveGridShape,\n type BulkCreateOptions,\n type Pattern,\n type Area\n} from './bulk-create.js'\n\nexport type ConflictPolicy = 'skip' | 'duplicate'\n\nexport interface BulkCreateDialogProps {\n /** 템플릿 컴포넌트 state (read-only 표시용). */\n template: Record<string, any>\n /** 초기 영역 (보드 좌표). 사용자가 dialog 내에서 조정 가능. */\n initialArea: Area\n /** 기존 scene 의 모든 ID — 충돌 검사. */\n existingIds?: Set<string>\n /** OK 클릭 시 콜백 — 생성할 model 배열 전달. */\n onConfirm: (models: ReturnType<typeof generateBulkComponents>) => void\n /** 취소 / 닫기 콜백. */\n onCancel?: () => void\n}\n\n@customElement('bulk-create-dialog')\nexport class BulkCreateDialog extends ScopedElementsMixin(LitElement) {\n static get scopedElements() {\n return {\n 'ox-input-entity-id': OxInputEntityId\n }\n }\n\n static styles = css`\n :host {\n display: block;\n padding: 16px 20px;\n min-width: 340px;\n max-width: 480px;\n background: rgba(30, 30, 30, 0.94);\n border: 1px solid rgba(255, 255, 255, 0.08);\n border-radius: 10px;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);\n color: rgba(255, 255, 255, 0.85);\n font: 12px/1.6 -apple-system, BlinkMacSystemFont, sans-serif;\n }\n h3 {\n margin: 0 0 12px;\n font-size: 13px;\n font-weight: 600;\n color: #4a9eff;\n }\n .row {\n display: grid;\n grid-template-columns: 100px 1fr;\n align-items: center;\n gap: 8px;\n margin: 6px 0;\n }\n label {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.55);\n }\n input,\n select {\n padding: 4px 6px;\n font: inherit;\n font-size: 12px;\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 3px;\n width: 100%;\n box-sizing: border-box;\n color: rgba(255, 255, 255, 0.9);\n outline: none;\n }\n input:focus,\n select:focus {\n border-color: #4a9eff;\n background: rgba(74, 158, 255, 0.08);\n }\n /* parentObject 입력(ox-input-entity-id)의 내부 input 을 dialog 의 다른 input 과 통일. */\n ox-input-entity-id::part(input) {\n padding: 4px 6px;\n font: inherit;\n font-size: 12px;\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 3px;\n color: rgba(255, 255, 255, 0.9);\n outline: none;\n }\n ox-input-entity-id::part(input):focus {\n border-color: #4a9eff;\n background: rgba(74, 158, 255, 0.08);\n }\n /* 검색 드롭다운(shadow 내부)은 md-sys-color 변수 + 상속 color 로 다크 테마 통일.\n (변수는 shadow 경계를 관통하고, .item 은 color 를 host 로부터 상속받는다.) */\n ox-input-entity-id {\n color: rgba(255, 255, 255, 0.9);\n --md-sys-color-surface: rgb(30, 30, 30);\n --md-sys-color-surface-variant: rgb(45, 45, 45);\n --md-sys-color-outline-variant: rgba(255, 255, 255, 0.15);\n --md-sys-color-secondary-container: rgba(74, 158, 255, 0.25);\n --md-sys-color-on-surface-variant: rgba(255, 255, 255, 0.55);\n }\n select option {\n background: rgb(30, 30, 30);\n color: rgba(255, 255, 255, 0.9);\n }\n .grid-shape {\n display: grid;\n grid-template-columns: 1fr 20px 1fr;\n gap: 4px;\n align-items: center;\n }\n .grid-shape > span {\n text-align: center;\n color: rgba(255, 255, 255, 0.35);\n }\n .pattern-picker {\n display: flex;\n gap: 6px;\n }\n .pattern-btn {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n padding: 6px 4px;\n background: rgba(255, 255, 255, 0.04);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 4px;\n cursor: pointer;\n color: rgba(255, 255, 255, 0.6);\n transition: background 0.1s, border-color 0.1s;\n }\n .pattern-btn:hover {\n background: rgba(255, 255, 255, 0.08);\n }\n .pattern-btn.active {\n border-color: #4a9eff;\n background: rgba(74, 158, 255, 0.15);\n color: rgba(255, 255, 255, 0.95);\n }\n .pattern-btn svg {\n width: 28px;\n height: 28px;\n }\n .pattern-btn svg circle {\n fill: currentColor;\n }\n .pattern-btn span {\n font-size: 10.5px;\n }\n .policy-radios {\n display: flex;\n gap: 12px;\n align-items: center;\n }\n .policy-radios label {\n display: flex;\n align-items: center;\n gap: 4px;\n cursor: pointer;\n color: rgba(255, 255, 255, 0.75);\n }\n .policy-radios input[type='radio'] {\n width: auto;\n accent-color: #4a9eff;\n margin: 0;\n }\n code {\n font-family: ui-monospace, SFMono-Regular, monospace;\n background: rgba(255, 255, 255, 0.08);\n padding: 1px 4px;\n border-radius: 3px;\n color: #b6d4fe;\n font-size: 11px;\n }\n .hint {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n margin-top: 2px;\n grid-column: 2;\n }\n .preview {\n font-size: 11.5px;\n color: rgba(255, 255, 255, 0.65);\n margin-top: 10px;\n padding: 6px 8px;\n background: rgba(255, 255, 255, 0.04);\n border-radius: 4px;\n }\n .conflict {\n margin-top: 8px;\n padding: 8px 10px;\n background: rgba(255, 100, 100, 0.12);\n border: 1px solid rgba(255, 100, 100, 0.3);\n border-radius: 4px;\n color: #ffb3b3;\n font-size: 11.5px;\n }\n .conflict strong {\n color: #ff8080;\n }\n .conflict-hint {\n margin-top: 4px;\n color: rgba(255, 255, 255, 0.45);\n font-size: 11px;\n }\n .actions {\n margin-top: 16px;\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n }\n button {\n padding: 5px 14px;\n font: inherit;\n font-size: 12px;\n border: 1px solid rgba(255, 255, 255, 0.15);\n background: rgba(255, 255, 255, 0.06);\n color: rgba(255, 255, 255, 0.85);\n cursor: pointer;\n border-radius: 4px;\n }\n button:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.1);\n }\n button:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n button.primary {\n background: #4a9eff;\n color: white;\n border-color: #4a9eff;\n }\n button.primary:hover:not(:disabled) {\n background: #6db1ff;\n }\n `\n\n @property({ type: Object }) template!: Record<string, any>\n @property({ type: Object }) initialArea!: Area\n @property({ attribute: false }) existingIds: Set<string> = new Set()\n @property({ attribute: false }) onConfirm!: BulkCreateDialogProps['onConfirm']\n @property({ attribute: false }) onCancel?: BulkCreateDialogProps['onCancel']\n /** parentObject 필드 노출 여부 (template 이 ParentObjectMixin 컴포넌트일 때). */\n @property({ attribute: false }) hasParentObject = false\n /** parentObject 후보 id 리스트 (template 타입 기준, toolbar 에서 계산해 주입). */\n @property({ attribute: false }) parentObjectItems: string[] = []\n\n @state() private pattern: Pattern = 'grid'\n @state() private parentObjectId = ''\n @state() private count = 12\n @state() private rows: number | undefined = undefined\n @state() private cols: number | undefined = undefined\n @state() private idPattern = '{i}'\n @state() private idStart = 1\n @state() private idPadding = 0\n @state() private area!: Area\n @state() private conflictPolicy: ConflictPolicy = 'skip'\n\n @query('#count-input') countInput!: HTMLInputElement\n\n connectedCallback() {\n super.connectedCallback()\n // OxPopup wrapper (ox-popup) 의 흰색 배경 + box-shadow 가 dialog 라운드 코너\n // 밖으로 비쳐서 4 꼭지점에 흰색 사각형이 보임. 부모를 투명/그림자 없이 만들어\n // dialog 자체의 라운드 + 그림자만 보이게.\n const parent = this.parentElement as HTMLElement | null\n if (parent) {\n parent.style.background = 'transparent'\n parent.style.boxShadow = 'none'\n parent.style.border = 'none'\n }\n this.area = { ...this.initialArea }\n\n // 1) 영역 종횡비로 레이아웃 기본 선택:\n // 너비 ≫ 높이 → line-h (가로), 높이 ≫ 너비 → line-v (세로), 비슷하면 grid.\n const w = Math.max(this.area.width, 1)\n const h = Math.max(this.area.height, 1)\n const aspect = w / h\n if (aspect >= 2.5) this.pattern = 'line-h'\n else if (aspect <= 0.4) this.pattern = 'line-v'\n else this.pattern = 'grid'\n\n // 2) 템플릿 id 로부터 ID 패턴 / padding 자동 추론.\n const inferred = inferIdPattern(this.template?.id)\n this.idPattern = inferred.pattern\n this.idPadding = inferred.padding\n\n // 3) 시작 번호 = existingIds 에 패턴 매칭되는 *최대 번호 + 1*.\n // 반복 bulk-paste 시 이전 batch 의 끝 다음으로 자동 advance.\n // 매칭 ID 가 없으면 inferIdPattern 의 fallback (= template num+1) 사용.\n this.idStart = nextAvailableStart(inferred.pattern, this.existingIds, inferred.start)\n\n // 4) 복사 대상(template)이 이미 parentObjectId 를 가지면 그것을 초기값으로.\n this.parentObjectId = String(this.template?.parentObjectId ?? '')\n }\n\n /** rows/cols 가 미입력 (undefined) 이면 영역 종횡비 + count 로 자동 계산해 표시. */\n private get displayRows(): number {\n if (this.rows != null) return this.rows\n return deriveGridShape(this.count, this.area, undefined, this.cols).rows\n }\n\n private get displayCols(): number {\n if (this.cols != null) return this.cols\n return deriveGridShape(this.count, this.area, this.rows, undefined).cols\n }\n\n firstUpdated() {\n this.countInput?.focus()\n this.countInput?.select()\n }\n\n private updateArea(field: keyof Area, value: number) {\n this.area = { ...this.area, [field]: value }\n }\n\n private get previewModels() {\n if (!this.template) return []\n return generateBulkComponents({\n template: this.template,\n area: this.area,\n pattern: this.pattern,\n count: this.count,\n rows: this.rows,\n cols: this.cols,\n idPattern: this.idPattern.replace(/\\{type\\}/g, String(this.template?.type ?? 'C')),\n idStart: this.idStart,\n idPadding: this.idPadding,\n // 선택 시 각 생성 컴포넌트에 parentObjectId 를 병합 (도메인 특수값은 여기서만).\n extraState: this.parentObjectId ? { parentObjectId: this.parentObjectId } : undefined\n })\n }\n\n private get conflicts(): string[] {\n return findIdConflicts(this.previewModels, this.existingIds)\n }\n\n /** 충돌 정책 적용 후 실제 생성될 model 배열. */\n private get effectiveModels() {\n const all = this.previewModels\n if (this.conflictPolicy === 'skip' && this.existingIds.size > 0) {\n return all.filter(m => !this.existingIds.has(m.id))\n }\n return all\n }\n\n private onOk = () => {\n const models = this.effectiveModels\n if (models.length === 0) return\n this.onConfirm(models)\n }\n\n private onCancelClick = () => {\n this.onCancel?.()\n }\n\n render() {\n const tplType = this.template?.type ?? '?'\n const tplId = this.template?.id ?? '?'\n const models = this.previewModels\n\n return html`\n <h3>Bulk Paste — ${tplType}</h3>\n\n <div class=\"row\">\n <label>템플릿</label>\n <span style=\"color:#b6d4fe;\">${tplId} <span style=\"color:rgba(255,255,255,0.4);\">(${tplType})</span></span>\n </div>\n\n <div class=\"row\">\n <label>레이아웃</label>\n <div class=\"pattern-picker\">\n <button\n type=\"button\"\n class=\"pattern-btn ${this.pattern === 'grid' ? 'active' : ''}\"\n @click=${() => (this.pattern = 'grid')}\n title=\"격자\"\n >\n <svg viewBox=\"0 0 24 24\">\n <circle cx=\"6\" cy=\"6\" r=\"1.6\" /><circle cx=\"12\" cy=\"6\" r=\"1.6\" /><circle cx=\"18\" cy=\"6\" r=\"1.6\" />\n <circle cx=\"6\" cy=\"12\" r=\"1.6\" /><circle cx=\"12\" cy=\"12\" r=\"1.6\" /><circle cx=\"18\" cy=\"12\" r=\"1.6\" />\n <circle cx=\"6\" cy=\"18\" r=\"1.6\" /><circle cx=\"12\" cy=\"18\" r=\"1.6\" /><circle cx=\"18\" cy=\"18\" r=\"1.6\" />\n </svg>\n <span>격자</span>\n </button>\n <button\n type=\"button\"\n class=\"pattern-btn ${this.pattern === 'line-h' ? 'active' : ''}\"\n @click=${() => (this.pattern = 'line-h')}\n title=\"가로 1줄\"\n >\n <svg viewBox=\"0 0 24 24\">\n <circle cx=\"3\" cy=\"12\" r=\"1.6\" /><circle cx=\"8\" cy=\"12\" r=\"1.6\" /><circle cx=\"13\" cy=\"12\" r=\"1.6\" />\n <circle cx=\"18\" cy=\"12\" r=\"1.6\" /><circle cx=\"22\" cy=\"12\" r=\"1.4\" />\n </svg>\n <span>가로</span>\n </button>\n <button\n type=\"button\"\n class=\"pattern-btn ${this.pattern === 'line-v' ? 'active' : ''}\"\n @click=${() => (this.pattern = 'line-v')}\n title=\"세로 1줄\"\n >\n <svg viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"3\" r=\"1.6\" /><circle cx=\"12\" cy=\"8\" r=\"1.6\" /><circle cx=\"12\" cy=\"13\" r=\"1.6\" />\n <circle cx=\"12\" cy=\"18\" r=\"1.6\" /><circle cx=\"12\" cy=\"22\" r=\"1.4\" />\n </svg>\n <span>세로</span>\n </button>\n </div>\n </div>\n\n <div class=\"row\">\n <label>개수</label>\n <input\n id=\"count-input\"\n type=\"number\"\n min=\"1\"\n .value=${String(this.count)}\n @input=${(e: Event) => (this.count = Math.max(1, +(e.target as HTMLInputElement).value))}\n />\n </div>\n\n ${this.pattern === 'grid'\n ? html`\n <div class=\"row\">\n <label>행 × 열</label>\n <div class=\"grid-shape\">\n <input\n type=\"number\"\n min=\"1\"\n .value=${String(this.displayRows)}\n @input=${(e: Event) => {\n const v = (e.target as HTMLInputElement).value\n this.rows = v ? Math.max(1, +v) : undefined\n }}\n />\n <span>×</span>\n <input\n type=\"number\"\n min=\"1\"\n .value=${String(this.displayCols)}\n @input=${(e: Event) => {\n const v = (e.target as HTMLInputElement).value\n this.cols = v ? Math.max(1, +v) : undefined\n }}\n />\n </div>\n </div>\n `\n : ''}\n\n <div class=\"row\">\n <label>ID 패턴</label>\n <input\n type=\"text\"\n .value=${this.idPattern}\n @input=${(e: Event) => (this.idPattern = (e.target as HTMLInputElement).value)}\n />\n </div>\n <div class=\"row\">\n <span></span>\n <div class=\"hint\">치환 변수: <code>{i}</code> 일련번호, <code>{r}</code> 행, <code>{c}</code> 열 (격자)</div>\n </div>\n\n <div class=\"row\">\n <label>시작 번호</label>\n <input\n type=\"number\"\n .value=${String(this.idStart)}\n @input=${(e: Event) => (this.idStart = +(e.target as HTMLInputElement).value)}\n />\n </div>\n\n <div class=\"row\">\n <label>번호 자릿수 (앞자리 0 채움)</label>\n <input\n type=\"number\"\n min=\"0\"\n .value=${String(this.idPadding)}\n @input=${(e: Event) => (this.idPadding = Math.max(0, +(e.target as HTMLInputElement).value))}\n />\n </div>\n\n ${this.hasParentObject\n ? html`\n <div class=\"row\">\n <label>상위 객체</label>\n <ox-input-entity-id\n .localItems=${this.parentObjectItems}\n .value=${this.parentObjectId}\n placeholder=\"상위 객체 id (검색)\"\n @change=${(e: Event) => (this.parentObjectId = (e.target as OxInputEntityId).value)}\n ></ox-input-entity-id>\n </div>\n `\n : ''}\n\n <div class=\"preview\">\n ${models.length > 0\n ? html`총 ${models.length}개 — 예: <code>${models[0].id}</code> ... <code>${models[models.length - 1].id}</code>`\n : html`<span style=\"color:#ff8080;\">생성할 컴포넌트가 없습니다.</span>`}\n </div>\n\n ${this.conflicts.length > 0\n ? html`\n <div class=\"conflict\">\n <strong>ID 충돌 ${this.conflicts.length}개</strong>\n <code>${this.conflicts.slice(0, 5).join(', ')}${this.conflicts.length > 5 ? ', ...' : ''}</code>\n <div class=\"conflict-hint\" style=\"margin-top:6px;\">\n <div class=\"policy-radios\">\n <label>\n <input\n type=\"radio\"\n name=\"conflict-policy\"\n value=\"skip\"\n .checked=${this.conflictPolicy === 'skip'}\n @change=${() => (this.conflictPolicy = 'skip')}\n />\n 중복 ID 건너뛰기 (기본)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"conflict-policy\"\n value=\"duplicate\"\n .checked=${this.conflictPolicy === 'duplicate'}\n @change=${() => (this.conflictPolicy = 'duplicate')}\n />\n 중복 그대로 생성\n </label>\n </div>\n </div>\n </div>\n `\n : ''}\n\n <div class=\"actions\">\n <button @click=${this.onCancelClick}>취소</button>\n <button\n class=\"primary\"\n @click=${this.onOk}\n ?disabled=${this.effectiveModels.length === 0}\n >\n 생성 (${this.effectiveModels.length}${\n this.conflicts.length > 0 && this.conflictPolicy === 'skip'\n ? html`<span style=\"opacity:0.6;\"> / ${models.length}</span>`\n : ''\n })\n </button>\n </div>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'bulk-create-dialog': BulkCreateDialog\n }\n}\n"]}
@@ -2,10 +2,11 @@
2
2
  * @license Copyright © HatioLab Inc. All rights reserved.
3
3
  */
4
4
  import { __decorate } from "tslib";
5
- import { css, html, LitElement } from 'lit';
5
+ import { css, html, LitElement, nothing } from 'lit';
6
6
  import { property, query, state } from 'lit/decorators.js';
7
7
  import { ScopedElementsMixin } from '@open-wc/scoped-elements';
8
8
  import { ScrollbarStyles } from '@operato/styles';
9
+ import { i18next } from '@operato/i18n';
9
10
  import { ComponentDetail } from './component-detail';
10
11
  const noImage = new URL('../../../../icons/components/no-image.png', import.meta.url).href;
11
12
  export class ComponentMenu extends ScopedElementsMixin(LitElement) {
@@ -27,11 +28,27 @@ export class ComponentMenu extends ScopedElementsMixin(LitElement) {
27
28
  <h2 onclick=${(e) => e.stopPropagation()}>${this.group} list</h2>
28
29
 
29
30
  <div templates @mouseover=${(e) => this.onHoverComponent(e)}>
30
- ${(this.templates || []).map(template => html `
31
- <div @click=${this.onClickTemplate} data-type=${template.type} template>
32
- <img src=${this.templateIcon(template)} />${template.type}
31
+ ${(this.templates || []).map(template => {
32
+ const { type } = template;
33
+ const reason = template.unavailableReason;
34
+ const label = i18next.exists(`component.${type}`) ? i18next.t(`component.${type}`) : template.description || type;
35
+ return html `
36
+ <div
37
+ @click=${this.onClickTemplate}
38
+ data-type=${type}
39
+ template
40
+ ?unavailable=${!!reason}
41
+ aria-disabled=${reason ? 'true' : 'false'}
42
+ title=${reason || ''}
43
+ >
44
+ <img src=${String(this.templateIcon(template))} draggable="false" />
45
+ <span name>${label}${reason ? html `<span reason>${reason}</span>` : nothing}</span>
46
+ ${reason
47
+ ? html `<span mark>${template.unavailableLabel || i18next.t('text.unavailable', { defaultValue: 'unavailable' })}</span>`
48
+ : nothing}
33
49
  </div>
34
- `)}
50
+ `;
51
+ })}
35
52
  </div>
36
53
 
37
54
  <component-detail
@@ -73,12 +90,16 @@ export class ComponentMenu extends ScopedElementsMixin(LitElement) {
73
90
  this.findTemplate((_a = button.closest('[data-type]')) === null || _a === void 0 ? void 0 : _a.getAttribute('data-type'));
74
91
  }
75
92
  onClickTemplate(e) {
76
- var _a;
93
+ var _a, _b;
77
94
  var item = e.target;
78
95
  var type = (_a = item.closest('[data-type]')) === null || _a === void 0 ? void 0 : _a.getAttribute('data-type');
79
96
  if (!type) {
80
97
  return;
81
98
  }
99
+ /* A template that cannot be placed here does nothing when picked; its reason is on the item. */
100
+ if ((_b = this.templates.find(template => template.type == type)) === null || _b === void 0 ? void 0 : _b.unavailableReason) {
101
+ return;
102
+ }
82
103
  if (this.scene) {
83
104
  this.template = this.templates.find(template => template.type == type);
84
105
  this.template && this.scene.startAddMode(JSON.parse(JSON.stringify(this.template.model)));
@@ -158,6 +179,41 @@ ComponentMenu.styles = [
158
179
  height: var(--component-menu-item-icon-size);
159
180
  }
160
181
 
182
+ /* Shown but not placeable: dimmed, marked, and the reason under the name on hover (ADR-0114 P7). */
183
+ [template][unavailable] {
184
+ opacity: 0.5;
185
+ cursor: not-allowed;
186
+ }
187
+
188
+ [template][unavailable]:hover,
189
+ [template][unavailable]:focus {
190
+ font-weight: normal;
191
+ cursor: not-allowed;
192
+ }
193
+
194
+ [template] [name] {
195
+ display: flex;
196
+ flex-direction: column;
197
+ min-width: 0;
198
+ }
199
+
200
+ [template] [mark] {
201
+ margin-left: auto;
202
+ padding: 0 4px;
203
+ border-radius: 4px;
204
+ background: var(--md-sys-color-surface-container-high);
205
+ color: var(--md-sys-color-on-surface-variant);
206
+ white-space: nowrap;
207
+ }
208
+
209
+ [template] [reason] {
210
+ display: none;
211
+ }
212
+
213
+ [template][unavailable]:hover [reason] {
214
+ display: block;
215
+ }
216
+
161
217
  component-detail {
162
218
  position: absolute;
163
219
  top: 0;
@@ -1 +1 @@
1
- {"version":3,"file":"component-menu.js","sourceRoot":"","sources":["../../../../src/modeller/component-toolbar/component-menu.ts"],"names":[],"mappings":"AAAA;;GAEG;;AAEH,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAkB,MAAM,KAAK,CAAA;AAC3D,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAG1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGjD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEpD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,2CAA2C,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA;AAE1F,MAAM,OAAO,aAAc,SAAQ,mBAAmB,CAAC,UAAU,CAAC;IAAlE;;QAoF8B,WAAM,GAAa,EAAE,CAAA;QACrB,UAAK,GAAiB,IAAI,CAAA;QAC1B,UAAK,GAAkB,EAAE,CAAA;QAE5C,cAAS,GAAiB,EAAE,CAAA;IAqFvC,CAAC;IAhFC,MAAM,KAAK,cAAc;QACvB,OAAO;YACL,kBAAkB,EAAE,eAAe;SACpC,CAAA;IACH,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,KAAK;YACf,CAAC,CAAC,IAAI,CAAA;wBACY,CAAC,CAAa,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,IAAI,IAAI,CAAC,KAAK;;sCAEtC,CAAC,CAAa,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;cACnE,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAC1B,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAA;8BACA,IAAI,CAAC,eAAe,cAAc,QAAQ,CAAC,IAAI;6BAChD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,QAAQ,CAAC,IAAI;;eAE5D,CACF;;;;;wBAKW,GAAG,EAAE;gBACf,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;YACtB,CAAC;wBACW,IAAI,CAAC,QAAQ;;;;SAI5B;YACH,CAAC,CAAC,IAAI,CAAA,EAAE,CAAA;IACZ,CAAC;IAED,OAAO,CAAC,OAA6B;;QACnC,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAChB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;gBACnB,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;YACjC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,SAAS,GAAG,CAAA,MAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,0CAAE,SAAS,KAAI,EAAE,CAAA;gBACxF,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAA;YAChC,CAAC;QACH,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK;gBAClC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC;gBACvC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;QAC5C,CAAC;IACH,CAAC;IAED,YAAY,CAAC,IAA+B;QAC1C,IAAI,CAAC,QAAQ,GAAG,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,CAAA;IAChF,CAAC;IAED,gBAAgB,CAAC,CAAa;;QAC5B,MAAM,MAAM,GAAG,CAAC,CAAC,MAAqB,CAAA;QACtC,IAAI,CAAC,YAAY,CAAC,MAAA,MAAO,CAAC,OAAO,CAAC,aAAa,CAAC,0CAAE,YAAY,CAAC,WAAW,CAAC,CAAC,CAAA;IAC9E,CAAC;IAED,eAAe,CAAC,CAAa;;QAC3B,IAAI,IAAI,GAAG,CAAC,CAAC,MAAqB,CAAA;QAClC,IAAI,IAAI,GAAG,MAAA,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,0CAAE,YAAY,CAAC,WAAW,CAAC,CAAA;QAEjE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAM;QACR,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,CAAA;YACtE,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAC3F,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;IACnB,CAAC;IAED,YAAY,CAAC,QAAoB;QAC/B,OAAO,QAAQ,CAAC,IAAI,IAAI,OAAO,CAAA;IACjC,CAAC;;AA3KM,oBAAM,GAAG;IACd,eAAe;IACf,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8EF;CACF,AAjFY,CAiFZ;AAE2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;6CAAsB;AACrB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4CAA2B;AAC1B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4CAA0B;AAE5C;IAAR,KAAK,EAAE;gDAA6B;AAC5B;IAAR,KAAK,EAAE;+CAA2B;AAER;IAA1B,KAAK,CAAC,kBAAkB,CAAC;6CAAqB","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { property, query, state } from 'lit/decorators.js'\n\nimport { Scene } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { Pallet, PalletItem } from '../../types'\nimport { ComponentDetail } from './component-detail'\n\nconst noImage = new URL('../../../../icons/components/no-image.png', import.meta.url).href\n\nexport class ComponentMenu extends ScopedElementsMixin(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n align-content: stretch;\n\n background-color: var(--component-menu-background-color);\n margin: 0px;\n padding: 0px;\n\n width: 180px;\n height: 100%;\n\n overflow: visible;\n\n border: 2px solid var(--component-menu-border-color);\n box-sizing: border-box;\n\n position: absolute;\n top: 0px;\n\n z-index: 1;\n }\n\n h2 {\n background-color: var(--component-menu-border-color);\n padding: 1px 5px;\n margin: 0;\n font: var(--component-menu-title);\n color: #fff;\n text-transform: capitalize;\n }\n\n [templates] {\n flex: 1;\n\n display: block;\n margin: 0;\n padding: 0;\n overflow-y: auto;\n\n background-color: var(--component-menu-background-color);\n }\n\n [template] {\n display: flex;\n align-items: center;\n min-height: var(--component-menu-item-icon-size);\n padding: 0 5px 0 0;\n border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n font-size: 11px;\n color: var(--component-menu-item-color);\n }\n\n [template]:hover,\n [template]:focus {\n color: var(--component-menu-item-hover-color);\n font-weight: bold;\n cursor: pointer;\n }\n\n [template] img {\n margin: 5px;\n width: var(--component-menu-item-icon-size);\n height: var(--component-menu-item-icon-size);\n }\n\n component-detail {\n position: absolute;\n top: 0;\n left: 180px;\n height: 100%;\n outline: none;\n }\n\n component-detail[hidden] {\n display: none;\n }\n `\n ]\n\n @property({ type: Object }) groups: Pallet[] = []\n @property({ type: Object }) scene: Scene | null = null\n @property({ type: String }) group: string | null = ''\n\n @state() templates: PalletItem[] = []\n @state() template: PalletItem | any\n\n @query('component-detail') detail!: HTMLElement\n\n static get scopedElements() {\n return {\n 'component-detail': ComponentDetail\n }\n }\n\n render() {\n return this.group\n ? html`\n <h2 onclick=${(e: MouseEvent) => e.stopPropagation()}>${this.group} list</h2>\n\n <div templates @mouseover=${(e: MouseEvent) => this.onHoverComponent(e)}>\n ${(this.templates || []).map(\n template => html`\n <div @click=${this.onClickTemplate} data-type=${template.type} template>\n <img src=${this.templateIcon(template)} />${template.type}\n </div>\n `\n )}\n </div>\n\n <component-detail\n tabindex=\"-1\"\n @focusout=${() => {\n this.template = null\n }}\n .template=${this.template}\n hidden\n >\n </component-detail>\n `\n : html``\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('group')) {\n if (!this.group) {\n this.templates = []\n this.setAttribute('hidden', '')\n } else {\n this.templates = this.groups.find((g: Pallet) => g.name === this.group)?.templates || []\n this.removeAttribute('active')\n }\n }\n\n if (changes.has('template')) {\n this.template && this.template.about\n ? this.detail.removeAttribute('hidden')\n : this.detail.setAttribute('hidden', '')\n }\n }\n\n findTemplate(type: string | null | undefined) {\n this.template = type && this.templates.find(template => template.type == type)\n }\n\n onHoverComponent(e: MouseEvent) {\n const button = e.target as HTMLElement\n this.findTemplate(button!.closest('[data-type]')?.getAttribute('data-type'))\n }\n\n onClickTemplate(e: MouseEvent) {\n var item = e.target as HTMLElement\n var type = item.closest('[data-type]')?.getAttribute('data-type')\n\n if (!type) {\n return\n }\n\n if (this.scene) {\n this.template = this.templates.find(template => template.type == type)\n this.template && this.scene.startAddMode(JSON.parse(JSON.stringify(this.template.model)))\n }\n\n this.group = null\n }\n\n templateIcon(template: PalletItem) {\n return template.icon || noImage\n }\n}\n"]}
1
+ {"version":3,"file":"component-menu.js","sourceRoot":"","sources":["../../../../src/modeller/component-toolbar/component-menu.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { css, html, LitElement, nothing, PropertyValues } from 'lit'\nimport { property, query, state } from 'lit/decorators.js'\n\nimport { Scene } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { i18next } from '@operato/i18n'\nimport { Pallet, PalletItem } from '../../types'\nimport { ComponentDetail } from './component-detail'\n\nconst noImage = new URL('../../../../icons/components/no-image.png', import.meta.url).href\n\nexport class ComponentMenu extends ScopedElementsMixin(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n align-content: stretch;\n\n background-color: var(--component-menu-background-color);\n margin: 0px;\n padding: 0px;\n\n width: 180px;\n height: 100%;\n\n overflow: visible;\n\n border: 2px solid var(--component-menu-border-color);\n box-sizing: border-box;\n\n position: absolute;\n top: 0px;\n\n z-index: 1;\n }\n\n h2 {\n background-color: var(--component-menu-border-color);\n padding: 1px 5px;\n margin: 0;\n font: var(--component-menu-title);\n color: #fff;\n text-transform: capitalize;\n }\n\n [templates] {\n flex: 1;\n\n display: block;\n margin: 0;\n padding: 0;\n overflow-y: auto;\n\n background-color: var(--component-menu-background-color);\n }\n\n [template] {\n display: flex;\n align-items: center;\n min-height: var(--component-menu-item-icon-size);\n padding: 0 5px 0 0;\n border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n font-size: 11px;\n color: var(--component-menu-item-color);\n }\n\n [template]:hover,\n [template]:focus {\n color: var(--component-menu-item-hover-color);\n font-weight: bold;\n cursor: pointer;\n }\n\n [template] img {\n margin: 5px;\n width: var(--component-menu-item-icon-size);\n height: var(--component-menu-item-icon-size);\n }\n\n /* Shown but not placeable: dimmed, marked, and the reason under the name on hover (ADR-0114 P7). */\n [template][unavailable] {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n [template][unavailable]:hover,\n [template][unavailable]:focus {\n font-weight: normal;\n cursor: not-allowed;\n }\n\n [template] [name] {\n display: flex;\n flex-direction: column;\n min-width: 0;\n }\n\n [template] [mark] {\n margin-left: auto;\n padding: 0 4px;\n border-radius: 4px;\n background: var(--md-sys-color-surface-container-high);\n color: var(--md-sys-color-on-surface-variant);\n white-space: nowrap;\n }\n\n [template] [reason] {\n display: none;\n }\n\n [template][unavailable]:hover [reason] {\n display: block;\n }\n\n component-detail {\n position: absolute;\n top: 0;\n left: 180px;\n height: 100%;\n outline: none;\n }\n\n component-detail[hidden] {\n display: none;\n }\n `\n ]\n\n @property({ type: Object }) groups: Pallet[] = []\n @property({ type: Object }) scene: Scene | null = null\n @property({ type: String }) group: string | null = ''\n\n @state() templates: PalletItem[] = []\n @state() template: PalletItem | any\n\n @query('component-detail') detail!: HTMLElement\n\n static get scopedElements() {\n return {\n 'component-detail': ComponentDetail\n }\n }\n\n render() {\n return this.group\n ? html`\n <h2 onclick=${(e: MouseEvent) => e.stopPropagation()}>${this.group} list</h2>\n\n <div templates @mouseover=${(e: MouseEvent) => this.onHoverComponent(e)}>\n ${(this.templates || []).map(template => {\n const { type } = template\n\n const reason = template.unavailableReason\n const label = i18next.exists(`component.${type}`) ? i18next.t(`component.${type}`) : template.description || type\n\n return html`\n <div\n @click=${this.onClickTemplate}\n data-type=${type}\n template\n ?unavailable=${!!reason}\n aria-disabled=${reason ? 'true' : 'false'}\n title=${reason || ''}\n >\n <img src=${String(this.templateIcon(template))} draggable=\"false\" />\n <span name>${label}${reason ? html`<span reason>${reason}</span>` : nothing}</span>\n ${reason\n ? html`<span mark>${template.unavailableLabel || i18next.t('text.unavailable', { defaultValue: 'unavailable' })}</span>`\n : nothing}\n </div>\n `\n })}\n </div>\n\n <component-detail\n tabindex=\"-1\"\n @focusout=${() => {\n this.template = null\n }}\n .template=${this.template}\n hidden\n >\n </component-detail>\n `\n : html``\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('group')) {\n if (!this.group) {\n this.templates = []\n this.setAttribute('hidden', '')\n } else {\n this.templates = this.groups.find((g: Pallet) => g.name === this.group)?.templates || []\n this.removeAttribute('active')\n }\n }\n\n if (changes.has('template')) {\n this.template && this.template.about\n ? this.detail.removeAttribute('hidden')\n : this.detail.setAttribute('hidden', '')\n }\n }\n\n findTemplate(type: string | null | undefined) {\n this.template = type && this.templates.find(template => template.type == type)\n }\n\n onHoverComponent(e: MouseEvent) {\n const button = e.target as HTMLElement\n this.findTemplate(button!.closest('[data-type]')?.getAttribute('data-type'))\n }\n\n onClickTemplate(e: MouseEvent) {\n var item = e.target as HTMLElement\n var type = item.closest('[data-type]')?.getAttribute('data-type')\n\n if (!type) {\n return\n }\n\n /* A template that cannot be placed here does nothing when picked; its reason is on the item. */\n if (this.templates.find(template => template.type == type)?.unavailableReason) {\n return\n }\n\n if (this.scene) {\n this.template = this.templates.find(template => template.type == type)\n this.template && this.scene.startAddMode(JSON.parse(JSON.stringify(this.template.model)))\n }\n\n this.group = null\n }\n\n templateIcon(template: PalletItem) {\n return template.icon || noImage\n }\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @license Copyright © HatioLab Inc. All rights reserved.
3
3
  */
4
+ import '@material/web/icon/icon.js';
4
5
  import { LitElement, PropertyValues } from 'lit';
5
6
  import { Scene, SceneMode } from '@hatiolab/things-scene';
6
7
  import { ComponentGroup } from '../../types';
@@ -2,6 +2,7 @@
2
2
  * @license Copyright © HatioLab Inc. All rights reserved.
3
3
  */
4
4
  import { __decorate } from "tslib";
5
+ import '@material/web/icon/icon.js';
5
6
  import { css, html, LitElement } from 'lit';
6
7
  import { property, query, queryAll } from 'lit/decorators.js';
7
8
  import { Component, SCENE_MODE, isThreedEnabled } from '@hatiolab/things-scene';
@@ -69,13 +70,17 @@ export class ComponentToolbar extends ScopedElementsMixin(LitElement) {
69
70
 
70
71
  ${componentList
71
72
  .filter(group => { var _a; return ((_a = group.templates) === null || _a === void 0 ? void 0 : _a.length) > 0; })
72
- .map(group => html `
73
- <img
74
- data-group=${group.name}
75
- @click=${(e) => this._onClickGroup(e)}
76
- .src=${this.icons[group.name]}
77
- />
78
- `)}
73
+ .map(group => !group.icon && group.symbol
74
+ ? html `<md-icon data-group=${group.name} title=${group.description || group.name} @click=${(e) => this._onClickGroup(e)}
75
+ >${group.symbol}</md-icon
76
+ >`
77
+ : html `
78
+ <img
79
+ data-group=${group.name}
80
+ @click=${(e) => this._onClickGroup(e)}
81
+ .src=${this.icons[group.name]}
82
+ />
83
+ `)}
79
84
  </div>
80
85
 
81
86
  <component-menu
@@ -160,6 +165,22 @@ ComponentToolbar.styles = [
160
165
  box-sizing: border-box;
161
166
  }
162
167
 
168
+ /* A group that brings a Material Symbols glyph instead of a picture of its own (the Figure group). */
169
+ [components] > md-icon[data-group] {
170
+ display: flex;
171
+ align-items: center;
172
+ justify-content: center;
173
+
174
+ width: var(--component-toolbar-icon-size);
175
+ height: var(--component-toolbar-icon-size);
176
+ --md-icon-size: 22px;
177
+ color: var(--primary-color);
178
+
179
+ border-bottom: var(--component-toolbar-border);
180
+ box-sizing: border-box;
181
+ cursor: pointer;
182
+ }
183
+
163
184
  #shift[active] {
164
185
  background-color: #beb9b3;
165
186
  }
@@ -1 +1 @@
1
- {"version":3,"file":"component-toolbar.js","sourceRoot":"","sources":["../../../../src/modeller/component-toolbar/component-toolbar.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { property, query, queryAll } from 'lit/decorators.js'\n\nimport { Component, Scene, SCENE_MODE, SceneMode, isThreedEnabled } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\n\nimport { ComponentGroup } from '../../types'\nimport { ComponentMenu } from './component-menu.js'\nimport { ICON_EDIT_MODE, ICON_SHIFT_MODE } from './mode-icons'\n\nexport class ComponentToolbar extends ScopedElementsMixin(LitElement) {\n static styles = [\n css`\n :host {\n left: 0;\n display: block;\n position: relative;\n\n width: var(--component-toolbar-icon-size);\n background-color: var(--component-toolbar-background-color);\n }\n\n [components] {\n display: block;\n padding: 0;\n margin: 0;\n\n width: 100%;\n height: 100%;\n overflow: hidden;\n }\n\n [components] > img {\n display: flex;\n flex-direction: row;\n\n width: var(--component-toolbar-icon-size);\n height: var(--component-toolbar-icon-size);\n min-width: 50%;\n\n border-bottom: var(--component-toolbar-border);\n margin: 0;\n padding: 6px;\n box-sizing: border-box;\n }\n\n #shift[active] {\n background-color: #beb9b3;\n }\n\n component-menu {\n position: absolute;\n top: 0;\n left: var(--component-toolbar-icon-size);\n height: 100%;\n outline: none;\n }\n\n component-menu[hidden] {\n display: none;\n }\n `\n ]\n\n @property({ type: Array }) componentGroupList: ComponentGroup[] = []\n @property({ type: String }) group?: string | null\n @property({ type: Object }) scene!: Scene\n @property({ type: Number }) mode: SceneMode = SCENE_MODE.EDIT\n\n @query('#shift') shift!: HTMLImageElement\n @query('component-menu') private menu!: HTMLElement\n @query('div[components]') private componentsContainer!: HTMLElement\n @queryAll('[data-group]') private groups!: NodeListOf<HTMLElement>\n\n private icons: { [name: string]: string } = {}\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('componentGroupList')) {\n const color = getComputedStyle(this, null).getPropertyValue('--primary-color')\n\n this.icons = (this.componentGroupList || [])\n .filter(group => group.templates?.length > 0)\n .reduce((sum, group: ComponentGroup) => {\n sum[group.name] =\n 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(group.icon.replace(/{{strokeColor}}/g, color))\n return sum\n }, {} as { [name: string]: string })\n\n this.icons['mode-edit'] =\n 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(ICON_EDIT_MODE.replace(/{{strokeColor}}/g, color))\n this.icons['mode-shift'] =\n 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(ICON_SHIFT_MODE.replace(/{{strokeColor}}/g, color))\n }\n\n if (changes.has('group')) {\n this.groups.forEach(group => {\n group.getAttribute('data-group') === this.group\n ? group.setAttribute('active', '')\n : group.removeAttribute('active')\n })\n\n this.group ? this.menu.removeAttribute('hidden') : this.menu.setAttribute('hidden', '')\n }\n }\n\n static get scopedElements() {\n return {\n 'component-menu': ComponentMenu\n }\n }\n\n /**\n * 3D 비활성(전역 isThreedEnabled()=false)에서는 3D 전용 컴포넌트 타입\n * (requires3d — decal/backdrop/floor-plate 등)을 팔레트에서 제외하고, 비게 된 그룹도 숨긴다.\n * 3D 활성(기본)이면 원본 목록 그대로.\n */\n private get _visibleGroupList(): ComponentGroup[] {\n const list = this.componentGroupList || []\n if (isThreedEnabled()) return list\n\n return list\n .map(group => ({\n ...group,\n templates: (group.templates || []).filter(t => !Component.register(t.type)?.requires3d)\n }))\n .filter(group => group.templates.length > 0)\n }\n\n render() {\n const componentList = this._visibleGroupList\n const modeIcon = this.icons[this.mode === SCENE_MODE.SHIFT ? 'mode-shift' : 'mode-edit']\n\n return html`\n <div components @mousewheel=${(e: MouseEvent) => this.onWheelEvent(e)}>\n <img id=\"shift\" .src=${modeIcon} @click=${(e: MouseEvent) => this._onClickShift(e)} />\n\n ${componentList\n .filter(group => group.templates?.length > 0)\n .map(\n group => html`\n <img\n data-group=${group.name}\n @click=${(e: MouseEvent) => this._onClickGroup(e)}\n .src=${this.icons[group.name]}\n />\n `\n )}\n </div>\n\n <component-menu\n tabindex=\"-1\"\n @focusout=${() => {\n this.group = null\n }}\n .scene=${this.scene}\n .group=${this.group}\n .groups=${componentList}\n hidden\n >\n </component-menu>\n `\n }\n\n onWheelEvent(e: Event) {\n var delta = Math.max(-1, Math.min(1, (e as WheelEvent).deltaY || -(e as WheelEvent).detail))\n this.componentsContainer.scrollTop += delta * 10\n\n e.preventDefault()\n }\n\n _setMode(mode: SceneMode) {\n this.mode = mode\n\n this.dispatchEvent(\n new CustomEvent('mode-changed', {\n bubbles: true,\n composed: true,\n detail: { value: mode }\n })\n )\n }\n\n _onClickShift(e: MouseEvent) {\n const shift = this.shift\n\n if (shift.hasAttribute('active')) {\n shift.removeAttribute('active')\n this._setMode(SCENE_MODE.EDIT)\n } else {\n shift.setAttribute('active', '')\n this._setMode(SCENE_MODE.SHIFT)\n }\n }\n\n async _onClickGroup(e: MouseEvent) {\n var button = e.target as HTMLElement\n\n this.group = button!.closest('[data-group]')?.getAttribute('data-group')\n\n if (!this.group) return\n\n await this.updateComplete\n\n this.menu?.focus()\n }\n}\n"]}
1
+ {"version":3,"file":"component-toolbar.js","sourceRoot":"","sources":["../../../../src/modeller/component-toolbar/component-toolbar.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { property, query, queryAll } from 'lit/decorators.js'\n\nimport { Component, Scene, SCENE_MODE, SceneMode, isThreedEnabled } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\n\nimport { ComponentGroup } from '../../types'\nimport { ComponentMenu } from './component-menu.js'\nimport { ICON_EDIT_MODE, ICON_SHIFT_MODE } from './mode-icons'\n\nexport class ComponentToolbar extends ScopedElementsMixin(LitElement) {\n static styles = [\n css`\n :host {\n left: 0;\n display: block;\n position: relative;\n\n width: var(--component-toolbar-icon-size);\n background-color: var(--component-toolbar-background-color);\n }\n\n [components] {\n display: block;\n padding: 0;\n margin: 0;\n\n width: 100%;\n height: 100%;\n overflow: hidden;\n }\n\n [components] > img {\n display: flex;\n flex-direction: row;\n\n width: var(--component-toolbar-icon-size);\n height: var(--component-toolbar-icon-size);\n min-width: 50%;\n\n border-bottom: var(--component-toolbar-border);\n margin: 0;\n padding: 6px;\n box-sizing: border-box;\n }\n\n /* A group that brings a Material Symbols glyph instead of a picture of its own (the Figure group). */\n [components] > md-icon[data-group] {\n display: flex;\n align-items: center;\n justify-content: center;\n\n width: var(--component-toolbar-icon-size);\n height: var(--component-toolbar-icon-size);\n --md-icon-size: 22px;\n color: var(--primary-color);\n\n border-bottom: var(--component-toolbar-border);\n box-sizing: border-box;\n cursor: pointer;\n }\n\n #shift[active] {\n background-color: #beb9b3;\n }\n\n component-menu {\n position: absolute;\n top: 0;\n left: var(--component-toolbar-icon-size);\n height: 100%;\n outline: none;\n }\n\n component-menu[hidden] {\n display: none;\n }\n `\n ]\n\n @property({ type: Array }) componentGroupList: ComponentGroup[] = []\n @property({ type: String }) group?: string | null\n @property({ type: Object }) scene!: Scene\n @property({ type: Number }) mode: SceneMode = SCENE_MODE.EDIT\n\n @query('#shift') shift!: HTMLImageElement\n @query('component-menu') private menu!: HTMLElement\n @query('div[components]') private componentsContainer!: HTMLElement\n @queryAll('[data-group]') private groups!: NodeListOf<HTMLElement>\n\n private icons: { [name: string]: string } = {}\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('componentGroupList')) {\n const color = getComputedStyle(this, null).getPropertyValue('--primary-color')\n\n this.icons = (this.componentGroupList || [])\n .filter(group => group.templates?.length > 0)\n .reduce((sum, group: ComponentGroup) => {\n sum[group.name] =\n 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(group.icon.replace(/{{strokeColor}}/g, color))\n return sum\n }, {} as { [name: string]: string })\n\n this.icons['mode-edit'] =\n 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(ICON_EDIT_MODE.replace(/{{strokeColor}}/g, color))\n this.icons['mode-shift'] =\n 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(ICON_SHIFT_MODE.replace(/{{strokeColor}}/g, color))\n }\n\n if (changes.has('group')) {\n this.groups.forEach(group => {\n group.getAttribute('data-group') === this.group\n ? group.setAttribute('active', '')\n : group.removeAttribute('active')\n })\n\n this.group ? this.menu.removeAttribute('hidden') : this.menu.setAttribute('hidden', '')\n }\n }\n\n static get scopedElements() {\n return {\n 'component-menu': ComponentMenu\n }\n }\n\n /**\n * 3D 비활성(전역 isThreedEnabled()=false)에서는 3D 전용 컴포넌트 타입\n * (requires3d — decal/backdrop/floor-plate 등)을 팔레트에서 제외하고, 비게 된 그룹도 숨긴다.\n * 3D 활성(기본)이면 원본 목록 그대로.\n */\n private get _visibleGroupList(): ComponentGroup[] {\n const list = this.componentGroupList || []\n if (isThreedEnabled()) return list\n\n return list\n .map(group => ({\n ...group,\n templates: (group.templates || []).filter(t => !Component.register(t.type)?.requires3d)\n }))\n .filter(group => group.templates.length > 0)\n }\n\n render() {\n const componentList = this._visibleGroupList\n const modeIcon = this.icons[this.mode === SCENE_MODE.SHIFT ? 'mode-shift' : 'mode-edit']\n\n return html`\n <div components @mousewheel=${(e: MouseEvent) => this.onWheelEvent(e)}>\n <img id=\"shift\" .src=${modeIcon} @click=${(e: MouseEvent) => this._onClickShift(e)} />\n\n ${componentList\n .filter(group => group.templates?.length > 0)\n .map(\n group =>\n !group.icon && group.symbol\n ? html`<md-icon data-group=${group.name} title=${group.description || group.name} @click=${(e: MouseEvent) => this._onClickGroup(e)}\n >${group.symbol}</md-icon\n >`\n : html`\n <img\n data-group=${group.name}\n @click=${(e: MouseEvent) => this._onClickGroup(e)}\n .src=${this.icons[group.name]}\n />\n `\n )}\n </div>\n\n <component-menu\n tabindex=\"-1\"\n @focusout=${() => {\n this.group = null\n }}\n .scene=${this.scene}\n .group=${this.group}\n .groups=${componentList}\n hidden\n >\n </component-menu>\n `\n }\n\n onWheelEvent(e: Event) {\n var delta = Math.max(-1, Math.min(1, (e as WheelEvent).deltaY || -(e as WheelEvent).detail))\n this.componentsContainer.scrollTop += delta * 10\n\n e.preventDefault()\n }\n\n _setMode(mode: SceneMode) {\n this.mode = mode\n\n this.dispatchEvent(\n new CustomEvent('mode-changed', {\n bubbles: true,\n composed: true,\n detail: { value: mode }\n })\n )\n }\n\n _onClickShift(e: MouseEvent) {\n const shift = this.shift\n\n if (shift.hasAttribute('active')) {\n shift.removeAttribute('active')\n this._setMode(SCENE_MODE.EDIT)\n } else {\n shift.setAttribute('active', '')\n this._setMode(SCENE_MODE.SHIFT)\n }\n }\n\n async _onClickGroup(e: MouseEvent) {\n var button = e.target as HTMLElement\n\n this.group = button!.closest('[data-group]')?.getAttribute('data-group')\n\n if (!this.group) return\n\n await this.updateComplete\n\n this.menu?.focus()\n }\n}\n"]}
@@ -24,6 +24,8 @@ export declare class PropertySpecific extends PropertySpecific_base {
24
24
  };
25
25
  private _isGroupSelected;
26
26
  render(): import("lit-html").TemplateResult<1>;
27
+ /** 단일 선택이 적재 레이아웃 홀더(@fmsim/machine LoadLayoutHolder)인지. 구역 요소는 machine editors 가 등록한다 */
28
+ _hasLoadLayout(selected: Component[]): boolean;
27
29
  _onValueChange(e: Event): void;
28
30
  _isIdentifiable(selected: Component[]): boolean;
29
31
  /**
@@ -101,8 +101,26 @@ export class PropertySpecific extends ScopedElementsMixin(AbstractProperty) {
101
101
 
102
102
  <specific-properties-builder .value=${value} .props=${this._visibleProps} .propertyEditor=${this.propertyEditor}>
103
103
  </specific-properties-builder>
104
+
105
+ ${this._hasLoadLayout(this.selected)
106
+ ? html `
107
+ <fieldset>
108
+ <legend><ox-i18n msgid="label.load-layout.title">Carrier load slots</ox-i18n></legend>
109
+ <ox-load-layout-panel
110
+ custom-editor
111
+ value-key="slotLayout"
112
+ .holder=${selected}
113
+ .value=${value.slotLayout}
114
+ ></ox-load-layout-panel>
115
+ </fieldset>
116
+ `
117
+ : html ``}
104
118
  `;
105
119
  }
120
+ /** 단일 선택이 적재 레이아웃 홀더(@fmsim/machine LoadLayoutHolder)인지. 구역 요소는 machine editors 가 등록한다 */
121
+ _hasLoadLayout(selected) {
122
+ return ((selected === null || selected === void 0 ? void 0 : selected.length) === 1 && 'loadMount' in selected[0] && !!customElements.get('ox-load-layout-panel'));
123
+ }
106
124
  _onValueChange(e) {
107
125
  var element = e.target;
108
126
  var key = element.getAttribute('value-key');
@@ -1 +1 @@
1
- {"version":3,"file":"specifics.js","sourceRoot":"","sources":["../../../../../src/modeller/property-sidebar/specifics/specifics.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { css, html, LitElement } from 'lit'\nimport { property } from 'lit/decorators.js'\n\nimport { Component, Scene, isThreedEnabled } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\n\nimport { PropertySharedStyle } from '../property-shared-style'\nimport { SpecificPropertiesBuilder } from './specific-properties-builder.js'\nimport { AbstractProperty } from '../abstract-property'\nimport { OxInputEntityId } from '../shapes/ox-input-entity-id'\nimport { hasParentObject, collectParentObjectItems } from './parent-object.js'\n\nexport class PropertySpecific extends ScopedElementsMixin(AbstractProperty) {\n static styles = [\n PropertySharedStyle,\n css`\n label[component-type] {\n display: block;\n margin: 10px;\n\n text-align: right;\n font: bold 14px var(--theme-font);\n color: var(--primary-color);\n text-transform: capitalize;\n }\n `\n ]\n\n @property({ type: Object }) value: any\n @property({ type: Object }) scene: Scene | null = null\n @property({ type: Array }) selected: Component[] = []\n @property({ type: Array }) props: any[] = []\n @property({ type: Array }) propertyEditor: any[] = []\n /** 3D 비활성 시 requires3d 태그 속성(조명 프리셋 등)을 뺀 목록. */\n private get _visibleProps(): any[] {\n return isThreedEnabled() ? this.props : (this.props || []).filter(p => !p.requires3d)\n }\n\n private boundINeedSelected: any = this._onINeedSelected.bind(this)\n\n connectedCallback() {\n super.connectedCallback()\n\n this.addEventListener('i-need-selected', this.boundINeedSelected)\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n\n this.removeEventListener('i-need-selected', this.boundINeedSelected)\n }\n\n static get scopedElements() {\n return {\n 'specific-properties-builder': SpecificPropertiesBuilder,\n 'ox-input-entity-id': OxInputEntityId\n }\n }\n\n private _isGroupSelected(): boolean {\n return this.selected?.length > 0 && (this.selected[0] as any).isGroup?.()\n }\n\n render() {\n const selected = this.selected && this.selected[0]\n const value = this.value || {}\n\n if (this._isGroupSelected()) {\n return html`<label component-type>${value.type}</label>`\n }\n\n return html`\n <label component-type>${value.type}</label>\n <fieldset>\n <div class=\"property-grid\">\n ${this._isIdentifiable(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.id\">ID</ox-i18n> </label>\n ${this._idLookupType(this.selected)\n ? html`\n <ox-input-entity-id\n custom-editor\n value-key=\"id\"\n .value=${value.id || ''}\n .entityType=${this._idLookupType(this.selected)}\n .machine=${this._parentMachineId(this.selected)}\n .requireMachine=${!!(this.selected[0] as any).idLookupRequiresMachine}\n ></ox-input-entity-id>\n `\n : html`<input value-key=\"id\" .value=${value.id || ''} />`}\n `\n : html``}\n ${this._hasParentObject(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.parent-object-id\">parent object</ox-i18n> </label>\n <ox-input-entity-id\n custom-editor\n value-key=\"parentObjectId\"\n .value=${value.parentObjectId || ''}\n .localItems=${this._parentObjectItems(this.selected)}\n ></ox-input-entity-id>\n `\n : html``}\n ${this._hasTextProperty(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.text\">Text</ox-i18n> </label>\n <input value-key=\"text\" .value=${value.text || ''} />\n <label> <ox-i18n msgid=\"label.text-format\">Text Format</ox-i18n> </label>\n <input value-key=\"textFormat\" .value=${value.textFormat || ''} list=\"format-list\" />\n <datalist id=\"format-list\">\n <option value=\"#,###.\"></option>\n <option value=\"#,###.#\"></option>\n <option value=\"#,###.0\"></option>\n <option value=\"#,##0.#\"></option>\n <option value=\"#,##0.0\"></option>\n <option value=\"#,##0.0%\"></option>\n </datalist>\n `\n : html``}\n </div>\n </fieldset>\n\n <specific-properties-builder .value=${value} .props=${this._visibleProps} .propertyEditor=${this.propertyEditor}>\n </specific-properties-builder>\n `\n }\n\n _onValueChange(e: Event) {\n var element = e.target as HTMLElement\n var key = element.getAttribute('value-key')\n\n if (!key) {\n return\n }\n\n var value = this._getValueFromEventTarget(element)\n\n this._onAfterValueChange(key, value)\n }\n\n _isIdentifiable(selected: Component[]) {\n if (!selected || selected.length == 0 || selected.length > 1 || (selected[0].isLayer && selected[0].isLayer()))\n return false\n if ((selected[0] as any).isGroup?.())\n return false\n\n return true\n }\n\n /**\n * 단일 선택 컴포넌트의 부모 machine id (unit 의 ID 검색 시 조회조건으로 전달).\n * 부모가 루트 모델/레이어가 아니고 id 를 가지면 그 id 를 반환. 그 외엔 빈 문자열.\n * (shape 탭 PropertyShapes 와 동일한 규칙.)\n */\n _parentMachineId(selected: Component[]): string {\n const target = selected?.length === 1 ? (selected[0] as any) : null\n if (!target) return ''\n // 명시적 parentObjectId(= 부모 머신 id) 우선 — 모델러에 실제 없는 id 라도 그대로 조회조건으로 사용.\n const pid = target.state?.parentObjectId\n if (pid) return String(pid)\n const parent = target.parent\n if (!parent || parent.isRootModel?.() || (parent.isLayer && parent.isLayer())) return ''\n return parent.state?.id || ''\n }\n\n /**\n * 선택 컴포넌트의 id 조회용 타입명 (capability `idLookupType`). 값이 있으면 그 타입으로\n * 검색 에디터, 없으면 plain input — 불필요한 id 리스트 요청을 막는다. 기본은 자기 타입,\n * 특수 케이스는 override. (shape 탭 PropertyShapes 와 동일 규칙.)\n */\n _idLookupType(selected: Component[]): string | undefined {\n if (selected?.length !== 1) return undefined\n if (!this._idLookupEnabled(selected)) return undefined\n return (selected[0] as any).idLookupType\n }\n\n /** Board 루트 속성 state.idLookup 으로 id 룩업 전체 ON/OFF (기본 ON). */\n _idLookupEnabled(selected: Component[]): boolean {\n const root = (selected?.[0] as any)?.root\n return root?.state?.idLookup !== false\n }\n\n _hasTextProperty(selected: Component[]) {\n for (let i = 0; i < selected.length; i++) {\n if (!selected[i].hasTextProperty) return false\n }\n\n return true\n }\n\n /** 선택 컴포넌트가 ParentObjectMixin(= parentObject/parentObjectTypes capability) 인지. */\n _hasParentObject(selected: Component[]): boolean {\n return selected?.length === 1 && hasParentObject(selected[0])\n }\n\n /**\n * parentObject 후보 — 씬에서 컴포넌트 타입 기준 수집 (공유 헬퍼 재사용).\n * 실제 부모 컨테이너가 id 를 가지면 그 부모를 후보 맨 위로.\n */\n _parentObjectItems(selected: Component[]): string[] {\n const target = selected?.[0] as any\n const parent = target?.parent\n const knownParentId =\n parent && !parent.isRootModel?.() && !(parent.isLayer && parent.isLayer()) ? String(parent.state?.id || '') : ''\n return collectParentObjectItems(target?.parentObjectTypes, target?.root, { exclude: target, knownParentId })\n }\n\n _onINeedSelected(e: CustomEvent) {\n e.stopPropagation()\n\n var { callback } = e.detail\n\n this.scene!.undoableChange(() => {\n callback.call(null, this.selected)\n })\n }\n}\n"]}
1
+ {"version":3,"file":"specifics.js","sourceRoot":"","sources":["../../../../../src/modeller/property-sidebar/specifics/specifics.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { css, html, LitElement } from 'lit'\nimport { property } from 'lit/decorators.js'\n\nimport { Component, Scene, isThreedEnabled } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\n\nimport { PropertySharedStyle } from '../property-shared-style'\nimport { SpecificPropertiesBuilder } from './specific-properties-builder.js'\nimport { AbstractProperty } from '../abstract-property'\nimport { OxInputEntityId } from '../shapes/ox-input-entity-id'\nimport { hasParentObject, collectParentObjectItems } from './parent-object.js'\n\nexport class PropertySpecific extends ScopedElementsMixin(AbstractProperty) {\n static styles = [\n PropertySharedStyle,\n css`\n label[component-type] {\n display: block;\n margin: 10px;\n\n text-align: right;\n font: bold 14px var(--theme-font);\n color: var(--primary-color);\n text-transform: capitalize;\n }\n `\n ]\n\n @property({ type: Object }) value: any\n @property({ type: Object }) scene: Scene | null = null\n @property({ type: Array }) selected: Component[] = []\n @property({ type: Array }) props: any[] = []\n @property({ type: Array }) propertyEditor: any[] = []\n /** 3D 비활성 시 requires3d 태그 속성(조명 프리셋 등)을 뺀 목록. */\n private get _visibleProps(): any[] {\n return isThreedEnabled() ? this.props : (this.props || []).filter(p => !p.requires3d)\n }\n\n private boundINeedSelected: any = this._onINeedSelected.bind(this)\n\n connectedCallback() {\n super.connectedCallback()\n\n this.addEventListener('i-need-selected', this.boundINeedSelected)\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n\n this.removeEventListener('i-need-selected', this.boundINeedSelected)\n }\n\n static get scopedElements() {\n return {\n 'specific-properties-builder': SpecificPropertiesBuilder,\n 'ox-input-entity-id': OxInputEntityId\n }\n }\n\n private _isGroupSelected(): boolean {\n return this.selected?.length > 0 && (this.selected[0] as any).isGroup?.()\n }\n\n render() {\n const selected = this.selected && this.selected[0]\n const value = this.value || {}\n\n if (this._isGroupSelected()) {\n return html`<label component-type>${value.type}</label>`\n }\n\n return html`\n <label component-type>${value.type}</label>\n <fieldset>\n <div class=\"property-grid\">\n ${this._isIdentifiable(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.id\">ID</ox-i18n> </label>\n ${this._idLookupType(this.selected)\n ? html`\n <ox-input-entity-id\n custom-editor\n value-key=\"id\"\n .value=${value.id || ''}\n .entityType=${this._idLookupType(this.selected)}\n .machine=${this._parentMachineId(this.selected)}\n .requireMachine=${!!(this.selected[0] as any).idLookupRequiresMachine}\n ></ox-input-entity-id>\n `\n : html`<input value-key=\"id\" .value=${value.id || ''} />`}\n `\n : html``}\n ${this._hasParentObject(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.parent-object-id\">parent object</ox-i18n> </label>\n <ox-input-entity-id\n custom-editor\n value-key=\"parentObjectId\"\n .value=${value.parentObjectId || ''}\n .localItems=${this._parentObjectItems(this.selected)}\n ></ox-input-entity-id>\n `\n : html``}\n ${this._hasTextProperty(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.text\">Text</ox-i18n> </label>\n <input value-key=\"text\" .value=${value.text || ''} />\n <label> <ox-i18n msgid=\"label.text-format\">Text Format</ox-i18n> </label>\n <input value-key=\"textFormat\" .value=${value.textFormat || ''} list=\"format-list\" />\n <datalist id=\"format-list\">\n <option value=\"#,###.\"></option>\n <option value=\"#,###.#\"></option>\n <option value=\"#,###.0\"></option>\n <option value=\"#,##0.#\"></option>\n <option value=\"#,##0.0\"></option>\n <option value=\"#,##0.0%\"></option>\n </datalist>\n `\n : html``}\n </div>\n </fieldset>\n\n <specific-properties-builder .value=${value} .props=${this._visibleProps} .propertyEditor=${this.propertyEditor}>\n </specific-properties-builder>\n\n ${this._hasLoadLayout(this.selected)\n ? html`\n <fieldset>\n <legend><ox-i18n msgid=\"label.load-layout.title\">Carrier load slots</ox-i18n></legend>\n <ox-load-layout-panel\n custom-editor\n value-key=\"slotLayout\"\n .holder=${selected}\n .value=${value.slotLayout}\n ></ox-load-layout-panel>\n </fieldset>\n `\n : html``}\n `\n }\n\n /** 단일 선택이 적재 레이아웃 홀더(@fmsim/machine LoadLayoutHolder)인지. 구역 요소는 machine editors 가 등록한다 */\n _hasLoadLayout(selected: Component[]): boolean {\n return (\n selected?.length === 1 && 'loadMount' in (selected[0] as any) && !!customElements.get('ox-load-layout-panel')\n )\n }\n\n _onValueChange(e: Event) {\n var element = e.target as HTMLElement\n var key = element.getAttribute('value-key')\n\n if (!key) {\n return\n }\n\n var value = this._getValueFromEventTarget(element)\n\n this._onAfterValueChange(key, value)\n }\n\n _isIdentifiable(selected: Component[]) {\n if (!selected || selected.length == 0 || selected.length > 1 || (selected[0].isLayer && selected[0].isLayer()))\n return false\n if ((selected[0] as any).isGroup?.()) return false\n\n return true\n }\n\n /**\n * 단일 선택 컴포넌트의 부모 machine id (unit 의 ID 검색 시 조회조건으로 전달).\n * 부모가 루트 모델/레이어가 아니고 id 를 가지면 그 id 를 반환. 그 외엔 빈 문자열.\n * (shape 탭 PropertyShapes 와 동일한 규칙.)\n */\n _parentMachineId(selected: Component[]): string {\n const target = selected?.length === 1 ? (selected[0] as any) : null\n if (!target) return ''\n // 명시적 parentObjectId(= 부모 머신 id) 우선 — 모델러에 실제 없는 id 라도 그대로 조회조건으로 사용.\n const pid = target.state?.parentObjectId\n if (pid) return String(pid)\n const parent = target.parent\n if (!parent || parent.isRootModel?.() || (parent.isLayer && parent.isLayer())) return ''\n return parent.state?.id || ''\n }\n\n /**\n * 선택 컴포넌트의 id 조회용 타입명 (capability `idLookupType`). 값이 있으면 그 타입으로\n * 검색 에디터, 없으면 plain input — 불필요한 id 리스트 요청을 막는다. 기본은 자기 타입,\n * 특수 케이스는 override. (shape 탭 PropertyShapes 와 동일 규칙.)\n */\n _idLookupType(selected: Component[]): string | undefined {\n if (selected?.length !== 1) return undefined\n if (!this._idLookupEnabled(selected)) return undefined\n return (selected[0] as any).idLookupType\n }\n\n /** Board 루트 속성 state.idLookup 으로 id 룩업 전체 ON/OFF (기본 ON). */\n _idLookupEnabled(selected: Component[]): boolean {\n const root = (selected?.[0] as any)?.root\n return root?.state?.idLookup !== false\n }\n\n _hasTextProperty(selected: Component[]) {\n for (let i = 0; i < selected.length; i++) {\n if (!selected[i].hasTextProperty) return false\n }\n\n return true\n }\n\n /** 선택 컴포넌트가 ParentObjectMixin(= parentObject/parentObjectTypes capability) 인지. */\n _hasParentObject(selected: Component[]): boolean {\n return selected?.length === 1 && hasParentObject(selected[0])\n }\n\n /**\n * parentObject 후보 — 씬에서 컴포넌트 타입 기준 수집 (공유 헬퍼 재사용).\n * 실제 부모 컨테이너가 id 를 가지면 그 부모를 후보 맨 위로.\n */\n _parentObjectItems(selected: Component[]): string[] {\n const target = selected?.[0] as any\n const parent = target?.parent\n const knownParentId =\n parent && !parent.isRootModel?.() && !(parent.isLayer && parent.isLayer()) ? String(parent.state?.id || '') : ''\n return collectParentObjectItems(target?.parentObjectTypes, target?.root, { exclude: target, knownParentId })\n }\n\n _onINeedSelected(e: CustomEvent) {\n e.stopPropagation()\n\n var { callback } = e.detail\n\n this.scene!.undoableChange(() => {\n callback.call(null, this.selected)\n })\n }\n}\n"]}
@@ -12,6 +12,8 @@ export default class OxSceneViewer extends LitElement {
12
12
  variables: Properties;
13
13
  data: any;
14
14
  themes?: any;
15
+ /** The domain's item type table (ADR-0155), given to the scene as it is made */
16
+ itemTypes?: unknown;
15
17
  fit: FITMODE;
16
18
  selected: Component[];
17
19
  disposeWhenDetached: boolean;
@@ -117,6 +117,7 @@ let OxSceneViewer = class OxSceneViewer extends LitElement {
117
117
  target: this,
118
118
  model: JSON.parse(JSON.stringify(model)),
119
119
  style: this.themes,
120
+ itemTypes: this.itemTypes,
120
121
  layers,
121
122
  handlers,
122
123
  mode: this.mode,
@@ -223,6 +224,9 @@ __decorate([
223
224
  __decorate([
224
225
  property({ type: Object })
225
226
  ], OxSceneViewer.prototype, "themes", void 0);
227
+ __decorate([
228
+ property({ type: Object })
229
+ ], OxSceneViewer.prototype, "itemTypes", void 0);
226
230
  __decorate([
227
231
  property({ type: String })
228
232
  ], OxSceneViewer.prototype, "fit", void 0);