[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CBEP2JCE97MMN48YZ6M5AN":3,"skill-same:01M6CBEP2JCE97MMN48YZ6M5AN":44},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":21,"frontMatter":22,"refName":23,"commitSha":24,"skillDirectory":25,"forksCount":13,"repositoryHtmlUrl":26,"repositoryHomepageUrl":6,"ownerHtmlUrl":27,"ownerBlogUrl":6,"ownerDescription":28,"updatedAt":29,"install":30,"resources":43},"01M6CBEP2JCE97MMN48YZ6M5AN","12-group",null,"devwinsoft\u002Fdevian","devwinsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F22570160?v=4","01M6C6RR8W05NH8NPKQNCE3Q72","maoshy","01M6C6RRDJ5TJJCZXRTY801YDH",0,"MIT","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian-unity\u002F23-ui-package\u002F13-ui-toast-system\u002F12-group\u002FSKILL.md",[],[18],"12 group","2026-11-10 10:12:30",false,"# 12-group — UIToastGroup\n\nStatus: ACTIVE\nAppliesTo: v11\n\n---\n\n## 목적\n\ngroup 단위 queue, duplicate 처리, max-visible 제한, layout을 담당하는 **non-MonoBehaviour** 런타임 객체.\n`UIToastPanel`이 group당 1개 인스턴스를 소유한다.\n\n---\n\n## SSOT\n\n### Code Path\n\n```\nframework-cs\u002Fupm\u002Fcom.devian.foundation\u002FSamples~\u002FUIPackage\u002FRuntime\u002FToast\u002FUIToastGroup.cs\n```\n\n### Class Signature\n\n```csharp\nnamespace Devian\n{\n    public sealed class UIToastGroup\n    {\n        public UIToastGroup(\n            UIToastCanvas canvas,\n            RectTransform root,\n            UI_TOAST_FRAME_ID toastFrameId,\n            ToastGroupConfig config);\n\n        public void Enqueue(string message, ToastType toastType);\n        public void Clear();\n    }\n}\n```\n\n---\n\n## Enqueue 흐름\n\n```\n1. TryHandleDuplicate(request)\n   → DuplicatePolicy에 따라 처리 (아래 표 참조)\n   → true 반환 시 → 여기서 종료 (request 소비됨)\n\n2. _active.Count \u003C ResolveMaxVisibleCount()\n   → true  → ShowImmediate(request)\n   → false → _pending.Enqueue(request)\n```\n\n### DuplicatePolicy 처리 표\n\n| Policy | 동작 |\n|--------|------|\n| `Allow` | 항상 false 반환 (중복 무시 없음) |\n| `IgnoreIfVisible` | 동일 message가 active에 있으면 true 반환 (skip) |\n| `RefreshDurationIfVisible` | 동일 message가 active에 있으면 duration 갱신 후 true 반환 |\n\n\"동일 message\" 기준: `StringComparison.Ordinal` (HasMessage 위임).\n\n---\n\n## ShowImmediate 흐름\n\n```\n1. `toastFrameId` invalid면 error log 후 종료\n2. BundlePool.Spawn\u003CUIToastFrame>(toastFrameId, parent: _root)\n3. frame.isFrameInitialized 미완료 시: frame._Init + _InitComplete 직접 호출\n4. frame.Bind(request)\n5. frame.transform.SetAsLastSibling()\n6. 현재 active frame들의 실제 높이를 누적해서 next local offset 계산\n7. frame.ApplyGroupOffset(config.AnchoredOffset + nextOffset)\n8. _active.Add(frame)\n9. frame.Show(duration, OnFrameHidden)\n```\n\n---\n\n## OnFrameHidden 흐름\n\n```\n1. _active.Remove(frame)\n2. BundlePool.Despawn(frame)\n3. Relayout()\n4. FlushQueue()\n```\n\nFlushQueue: `_active.Count \u003C MaxVisible && _pending.Count > 0`인 동안 dequeue → duplicate 재검사 → ShowImmediate.\n\n---\n\n## Layout 규약\n\n- `_root`는 anchorMin `(0,0)` \u002F anchorMax `(1,1)` \u002F sizeDelta `0`의 full-stretch rect다.\n- `_root`는 frame size를 결정하지 않는다.\n- 각 frame은 prefab의 원본 `RectTransform` 값을 유지한다.\n- `config.AnchorPreset`은 `_root.rect.size - frameSize`를 기준으로 계산한 anchor offset으로 반영한다.\n- active frame은 생성 순서대로 `LayoutDirection.Down`이면 y 음수 방향, `LayoutDirection.Up`이면 y 양수 방향으로 적층한다.\n- 각 frame은 원본 `anchoredPosition`을 복원한 뒤 `anchorOffset + config.AnchoredOffset + localOffset`을 더한다.\n- frame size는 `LayoutUtility.GetPreferredWidth\u002FHeight`를 우선 사용하고, 값이 `0 이하`면 `rect.width\u002Fheight`로 fallback.\n- 새 frame의 local offset은 `active.Count * 고정값`이 아니라, 현재 visible frame들의 실제 높이와 spacing 누적값으로 계산한다.\n- `DuplicatePolicy = Allow`일 때 새 frame은 base slot을 재사용하지 않고 stack의 끝 슬롯에 append된다.\n- spacing: `UIToastDefaults.DefaultSpacing`.\n\n---\n\n## MaxVisibleCount\n\n- `Mathf.Max(1, config.MaxVisibleCount)` — 최소 1 보장.\n\n## Duration\n\n- `request.DurationOverride`가 있으면 override 우선.\n- 없으면 `config.DefaultDuration` 사용.\n- `config.DefaultDuration \u003C= 0`이면 `UIToastDefaults.DefaultDuration`으로 fallback.\n\n---\n\n## Reference\n\n- Overview: `..\u002F00-overview\u002FSKILL.md`\n- Canvas\u002FPanel: `..\u002F11-canvas-panel\u002FSKILL.md`\n- Frame: `..\u002F13-frame\u002FSKILL.md`\n- Data Model: `..\u002F14-data-model\u002FSKILL.md`\n",{},"main","8cb5bd877a3a7004867d2f55697cb9e4ff2f1734","skills\u002Fdevian-unity\u002F23-ui-package\u002F13-ui-toast-system\u002F12-group","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian","https:\u002F\u002Fgithub.com\u002Fdevwinsoft","Kim Hyong Joon","2026-04-12 18:44:10",{"source":7,"skillName":5,"commands":31,"prompt":41,"zipAvailable":42},[32,35,38],{"tool":33,"command":34},"npx","npx skills add devwinsoft\u002Fdevian --skill 12-group",{"tool":36,"command":37},"bunx","bunx skills add devwinsoft\u002Fdevian --skill 12-group",{"tool":39,"command":40},"pnpm","pnpm dlx skills add devwinsoft\u002Fdevian --skill 12-group","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian-unity\u002F23-ui-package\u002F13-ui-toast-system\u002F12-group\u002FSKILL.md",true,[],[45,51,59,67,76,83],{"skillNo":46,"name":47,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":48,"categories":49,"keywords":50,"publishedAt":19},"01M6CBX3K2JJV38ANHVGCAT8A0","devian","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002FSKILL.md",[],[47],{"skillNo":52,"name":53,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":54,"categories":55,"keywords":56,"publishedAt":19},"01M6CBX210BFMM8AMN770J9WY8","90-project-archive","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F90-project-archive\u002FSKILL.md",[],[57,58],"archive","90 project archive",{"skillNo":60,"name":61,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":62,"categories":63,"keywords":64,"publishedAt":19},"01M6CBWZSGRR9R3YJZB3177667","30-env-management","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F30-env-management\u002FSKILL.md",[],[65,66],"management","30 env management",{"skillNo":68,"name":69,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":70,"categories":71,"keywords":72,"publishedAt":19},"01M6CBWYD3TGWBQV7V35551THF","19-page-push-send","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F19-page-push-send\u002FSKILL.md",[],[73,74,75],"push","page","19 page push send",{"skillNo":77,"name":78,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":79,"categories":80,"keywords":81,"publishedAt":19},"01M6CBWWRQ05A7604GHJKTPJTF","18-page-savedata","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F18-page-savedata\u002FSKILL.md",[],[74,82],"18 page savedata",{"skillNo":84,"name":85,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":88,"publishedAt":19},"01M6CBWVH4S2VF1V7B2GBTESCT","17-page-deobfuscate","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F17-page-deobfuscate\u002FSKILL.md",[],[74,89],"17 page deobfuscate"]