@simplysm/sd-claude 14.0.87 โ†’ 14.0.89

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 (127) hide show
  1. package/claude/references/sd-simplysm14/README.md +17 -18
  2. package/claude/references/sd-simplysm14/apis/angular/README.md +35 -0
  3. package/claude/references/sd-simplysm14/apis/angular/controls.md +51 -0
  4. package/claude/references/sd-simplysm14/apis/angular/crud.md +53 -0
  5. package/claude/references/sd-simplysm14/apis/angular/directives.md +34 -0
  6. package/claude/references/sd-simplysm14/apis/angular/features.md +40 -0
  7. package/claude/references/sd-simplysm14/apis/angular/infra.md +74 -0
  8. package/claude/references/sd-simplysm14/apis/angular/layout.md +27 -0
  9. package/claude/references/sd-simplysm14/apis/angular/overlay.md +103 -0
  10. package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +69 -0
  11. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +28 -0
  12. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +57 -0
  13. package/claude/references/sd-simplysm14/apis/angular/sheet.md +73 -0
  14. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +78 -0
  15. package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +66 -0
  16. package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +71 -0
  17. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +62 -0
  18. package/claude/references/sd-simplysm14/apis/core-browser/README.md +70 -0
  19. package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +62 -0
  20. package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +80 -0
  21. package/claude/references/sd-simplysm14/apis/core-common/README.md +262 -0
  22. package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +121 -0
  23. package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +128 -0
  24. package/claude/references/sd-simplysm14/apis/core-common/datetime.md +129 -0
  25. package/claude/references/sd-simplysm14/apis/core-common/errors.md +91 -0
  26. package/claude/references/sd-simplysm14/apis/core-common/json-transfer.md +53 -0
  27. package/claude/references/sd-simplysm14/apis/core-common/obj.md +117 -0
  28. package/claude/references/sd-simplysm14/apis/core-node/README.md +17 -0
  29. package/claude/references/sd-simplysm14/apis/core-node/consola.md +43 -0
  30. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +50 -0
  31. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +41 -0
  32. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +72 -0
  33. package/claude/references/sd-simplysm14/apis/core-node/pathx.md +39 -0
  34. package/claude/references/sd-simplysm14/apis/core-node/worker.md +52 -0
  35. package/claude/references/sd-simplysm14/apis/excel/README.md +43 -0
  36. package/claude/references/sd-simplysm14/apis/excel/cell.md +54 -0
  37. package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +51 -0
  38. package/claude/references/sd-simplysm14/apis/excel/style.md +67 -0
  39. package/claude/references/sd-simplysm14/apis/excel/utils.md +35 -0
  40. package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +97 -0
  41. package/claude/references/sd-simplysm14/apis/excel/wrapper.md +83 -0
  42. package/claude/references/sd-simplysm14/apis/lint/README.md +49 -0
  43. package/claude/references/sd-simplysm14/apis/lint/rules.md +130 -0
  44. package/claude/references/sd-simplysm14/apis/orm-common/README.md +13 -0
  45. package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +111 -0
  46. package/claude/references/sd-simplysm14/apis/orm-common/expr.md +128 -0
  47. package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +145 -0
  48. package/claude/references/sd-simplysm14/apis/orm-common/schema.md +147 -0
  49. package/claude/references/sd-simplysm14/apis/orm-common/types.md +62 -0
  50. package/claude/references/sd-simplysm14/apis/orm-node/README.md +90 -0
  51. package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +94 -0
  52. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +26 -0
  53. package/claude/references/sd-simplysm14/apis/sd-cli/SdTsCompiler.md +117 -0
  54. package/claude/references/sd-simplysm14/apis/sd-cli/sd-config-types.md +291 -0
  55. package/claude/references/sd-simplysm14/apis/service-client/README.md +150 -0
  56. package/claude/references/sd-simplysm14/apis/service-client/orm.md +48 -0
  57. package/claude/references/sd-simplysm14/apis/service-client/transport.md +59 -0
  58. package/claude/references/sd-simplysm14/apis/service-common/README.md +84 -0
  59. package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +48 -0
  60. package/claude/references/sd-simplysm14/apis/service-common/protocol.md +72 -0
  61. package/claude/references/sd-simplysm14/apis/service-server/README.md +118 -0
  62. package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +71 -0
  63. package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +62 -0
  64. package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +39 -0
  65. package/claude/references/sd-simplysm14/apis/storage/README.md +120 -0
  66. package/claude/skills/sd-demo/SKILL.md +6 -0
  67. package/claude/skills/sd-impl/SKILL.md +4 -7
  68. package/claude/skills/sd-spec/SKILL.md +31 -858
  69. package/claude/skills/sd-spec/references/spec-authoring.md +519 -0
  70. package/claude/workflows/sd-docs.js +84 -0
  71. package/claude/{skills/sd-docs/references/subagent-prompt.md โ†’ workflows/sd-docs.rules.md} +25 -40
  72. package/package.json +1 -1
  73. package/claude/skills/sd-demo/evals/fixtures/inventory-list/.specs/inventory/spec.md +0 -99
  74. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/package.json +0 -12
  75. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/index.ts +0 -3
  76. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/inbound/inbound.list.ts +0 -150
  77. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/inventory/inventory-master.list.ts +0 -143
  78. package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/outbound/outbound.list.ts +0 -150
  79. package/claude/skills/sd-demo/evals/fixtures/inventory-list/pnpm-workspace.yaml +0 -2
  80. package/claude/skills/sd-demo/evals/fixtures/inventory-list/sd.config.ts +0 -12
  81. package/claude/skills/sd-demo/evals/golden.jsonl +0 -1
  82. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/package.json +0 -8
  83. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/src/.gitkeep +0 -0
  84. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/tests/.gitkeep +0 -0
  85. package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/tsconfig.json +0 -10
  86. package/claude/skills/sd-dev/evals/golden.jsonl +0 -1
  87. package/claude/skills/sd-docs/SKILL.md +0 -58
  88. package/claude/skills/sd-docs/evals/fixtures/new-write/.claude/references/sd-simplysm14/README.md +0 -7
  89. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/package.json +0 -5
  90. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/src/index.ts +0 -3
  91. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/package.json +0 -6
  92. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/src/index.ts +0 -1
  93. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/package.json +0 -5
  94. package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/src/index.ts +0 -8
  95. package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/README.md +0 -7
  96. package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/apis/foo/README.md +0 -3
  97. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/package.json +0 -5
  98. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/src/index.ts +0 -3
  99. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/package.json +0 -6
  100. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/src/index.ts +0 -1
  101. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/package.json +0 -5
  102. package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/src/index.ts +0 -8
  103. package/claude/skills/sd-docs/evals/golden.jsonl +0 -2
  104. package/claude/skills/sd-impl/evals/fixtures/case-a-new-screen/.specs/260513120000_warehouse/spec.md +0 -101
  105. package/claude/skills/sd-impl/evals/fixtures/case-b-update-with-demo/.specs/260513120000_warehouse/spec.md +0 -101
  106. package/claude/skills/sd-impl/evals/fixtures/case-b-update-with-demo/packages/app/src/screens/box-register/box-register.view.ts +0 -46
  107. package/claude/skills/sd-impl/evals/fixtures/case-c-new-cross/.specs/260513120000_warehouse/spec.md +0 -89
  108. package/claude/skills/sd-impl/evals/fixtures/case-d-spec-modify/.specs/260513120000_warehouse/spec.md +0 -101
  109. package/claude/skills/sd-impl/evals/golden.jsonl +0 -4
  110. package/claude/skills/sd-manual/evals/fixtures/new-manual/src/notification.ts +0 -25
  111. package/claude/skills/sd-manual/evals/fixtures/update-manual/.claude/references/sd-simplysm14/manuals/notification.md +0 -14
  112. package/claude/skills/sd-manual/evals/fixtures/update-manual/src/notification.ts +0 -37
  113. package/claude/skills/sd-manual/evals/golden.jsonl +0 -2
  114. package/claude/skills/sd-review/evals/fixtures/code-review/src/foo.ts +0 -7
  115. package/claude/skills/sd-review/evals/fixtures/doc-review/docs/foo.md +0 -4
  116. package/claude/skills/sd-review/evals/golden.jsonl +0 -2
  117. package/claude/skills/sd-skill/evals/fixtures/existing-skill/.claude/skills/todo-format/SKILL.md +0 -14
  118. package/claude/skills/sd-skill/evals/fixtures/new-skill/.gitkeep +0 -0
  119. package/claude/skills/sd-skill/evals/golden.jsonl +0 -2
  120. package/claude/skills/sd-spec/evals/fixtures/case-a-split//355/232/214/354/235/230/353/241/235.md +0 -20
  121. package/claude/skills/sd-spec/evals/fixtures/case-b-detail/.specs/260513120000_warehouse/spec.md +0 -95
  122. package/claude/skills/sd-spec/evals/golden.jsonl +0 -2
  123. package/claude/skills/sd-unpack/evals/fixtures/eml-with-text-attachment/meeting.eml +0 -21
  124. package/claude/skills/sd-unpack/evals/fixtures/simple-eml/meeting.eml +0 -10
  125. package/claude/skills/sd-unpack/evals/golden.jsonl +0 -2
  126. package/claude/skills/sd-use/evals/fixtures/empty/.gitkeep +0 -0
  127. package/claude/skills/sd-use/evals/golden.jsonl +0 -6
@@ -44,21 +44,20 @@ ORM ํ˜ธ์ถœ, ํŒŒ์ผ ๋ณ€ํ™˜, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋“ฑ์€ ์œ„ ๋‘ ๊ฒฝ์šฐ์— ํ•ด๋‹น
44
44
 
45
45
  ## ํŒจํ‚ค์ง€ ์ธ๋ฑ์Šค
46
46
 
47
- - **angular** โ€” Angular 21 standalone/signal/zoneless ๊ธฐ๋ฐ˜ ์—…๋ฌด ํด๋ผ์ด์–ธํŠธ UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ. `provideSdAngular` ๋ถ€ํŠธ์ŠคํŠธ๋žฉ, ํผ/์‹œํŠธ/CRUD/๋ชจ๋‹ฌ/ํ† ์ŠคํŠธ/์‚ฌ์ด๋“œ๋ฐ”ยทํƒ‘๋ฐ”ยท๋“œ๋กญ๋‹ค์šด/๊ณต์œ ๋ฐ์ดํ„ฐยท์นธ๋ฐ˜ ๋“ฑ ํ™”๋ฉด ์ปดํฌ๋„ŒํŠธ์™€ ์ธํ”„๋ผ ํ”„๋กœ๋ฐ”์ด๋” ์ œ๊ณต. ์ž์„ธํžˆ: [apis/angular/README.md](./apis/angular/README.md)
48
- - **capacitor-plugin-auto-update** โ€” Android Capacitor ์•ฑ์—์„œ APK ์ž๋™ ์—…๋ฐ์ดํŠธ์™€ APK ์„ค์น˜ ๊ถŒํ•œยท๋ฒ„์ „ ์กฐํšŒ. ์ž์„ธํžˆ: [apis/capacitor-plugin-auto-update/README.md](./apis/capacitor-plugin-auto-update/README.md)
49
- - **capacitor-plugin-file-system** โ€” Capacitor ๋ชจ๋ฐ”์ผ/์›น ํŒŒ์ผ ์‹œ์Šคํ…œ ์ ‘๊ทผ(๊ถŒํ•œยท๊ฒฝ๋กœยท๋””๋ ‰ํ† ๋ฆฌยทํŒŒ์ผ IO). ์ž์„ธํžˆ: [apis/capacitor-plugin-file-system/README.md](./apis/capacitor-plugin-file-system/README.md)
50
- - **capacitor-plugin-intent** โ€” Android ์ธํ…ํŠธ ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ ์†ก์ˆ˜์‹  ๋ฐ `startActivityForResult` ์—ฐ๋™(์‚ฐ์—…์šฉ ์Šค์บ๋„ˆยทPDAยท์™ธ๋ถ€ ๊ฒฐ์ œ ๋“ฑ). ์ž์„ธํžˆ: [apis/capacitor-plugin-intent/README.md](./apis/capacitor-plugin-intent/README.md)
51
- - **capacitor-plugin-usb-storage** โ€” Android/Browser ์—์„œ USB Mass Storage ์žฅ์น˜ ๋ชฉ๋กยท๊ถŒํ•œยท๋””๋ ‰ํ† ๋ฆฌ/ํŒŒ์ผ ์ฝ๊ธฐ. ์ž์„ธํžˆ: [apis/capacitor-plugin-usb-storage/README.md](./apis/capacitor-plugin-usb-storage/README.md)
52
- - **core-browser** โ€” ๋ธŒ๋ผ์šฐ์ € ์ „์šฉ. `Element`/`HTMLElement` ํ”„๋กœํ† ํƒ€์ž… ํ™•์žฅ, DOM ํƒ์ƒ‰ยทํฌ์ปค์Šคยท๋ ˆ์ด์•„์›ƒ ๋ณด์ •, ํด๋ฆฝ๋ณด๋“œ/์ธก์ •, ํŒŒ์ผ ๋‹ค์ด์–ผ๋กœ๊ทธยท๋‹ค์šด๋กœ๋“œ, ์ง„ํ–‰๋ฅ  fetch, IndexedDB ํ‚ค/๊ฐ’ ์ €์žฅ์†Œ์™€ ๊ฐ€์ƒ ํŒŒ์ผ์‹œ์Šคํ…œ. ์ž์„ธํžˆ: [apis/core-browser/README.md](./apis/core-browser/README.md)
53
- - **core-common** โ€” ๊ณตํ†ต ์œ ํ‹ธ๋ฆฌํ‹ฐ(ํƒ€์ž…ยท์—๋Ÿฌยทํยท์ด๋ฒคํŠธยท๋ณ€ํ™˜ยทํ™•์žฅ ๋ฉ”์„œ๋“œยทํ™˜๊ฒฝ๋ณ€์ˆ˜). simplysm ๋ชจ๋“  ํŒจํ‚ค์ง€์˜ ๊ณต์šฉ ๊ธฐ๋ฐ˜. ์ž์„ธํžˆ: [apis/core-common/README.md](./apis/core-common/README.md)
54
- - **core-node** โ€” Node ์ „์šฉ IO/๊ฒฝ๋กœ/ํ”„๋กœ์„ธ์Šค/๊ฐ์‹œ/consola/worker_threads ๋ž˜ํผ(`fsx`, `pathx`, `cpx`, `FsWatcher`, `setupConsola`, `Worker`/`createWorker`). ์ž์„ธํžˆ: [apis/core-node/README.md](./apis/core-node/README.md)
55
- - **excel** โ€” xlsx ์›Œํฌ๋ถ์„ ์—ด์–ด ์…€ยท์‹œํŠธยท์Šคํƒ€์ผยท์กฐ๊ฑด๋ถ€์„œ์‹ยท์ด๋ฏธ์ง€๋ฅผ ์ฝ๊ณ  ์“ฐ๊ฑฐ๋‚˜, Zod ์Šคํ‚ค๋งˆ ๊ธฐ๋ฐ˜ ๋ ˆ์ฝ”๋“œ ์ž…์ถœ๋ ฅ. ์ž์„ธํžˆ: [apis/excel/README.md](./apis/excel/README.md)
56
- - **lint** โ€” ESLint flat config ์ž‘์„ฑ ์‹œ `@simplysm/lint/eslint-recommended` ํ”„๋ฆฌ์…‹ ๋˜๋Š” `@simplysm/lint/eslint-plugin` ๊ฐœ๋ณ„ ๊ทœ์น™ import. ์ž์„ธํžˆ: [apis/lint/README.md](./apis/lint/README.md)
57
- - **orm-common** โ€” Dialect ๋…๋ฆฝ ORM ์ฝ”์–ด. `DbContext` ์„œ๋ธŒํด๋ž˜์‹ฑ + Table/View/Procedure ๋นŒ๋” + `expr` AST + `Queryable` ์ฒด์ด๋‹์œผ๋กœ SQL ์„ ๋งŒ๋“ค๊ณ  dialect QueryBuilder ๋กœ ๋ Œ๋”. ์ž์„ธํžˆ: [apis/orm-common/README.md](./apis/orm-common/README.md)
58
- - **orm-node** โ€” Node ํ™˜๊ฒฝ์—์„œ `DbContext` ๋ฅผ MSSQL/MySQL/PostgreSQL ์‹ค ์—ฐ๊ฒฐ์— ๋ถ™์ด๋Š” ์–ด๋Œ‘ํ„ฐ(`createOrm`), raw SQL/bulk insert (`createDbConn`). ์ž์„ธํžˆ: [apis/orm-node/README.md](./apis/orm-node/README.md)
59
- - **sd-claude** โ€” simplysm ํ‘œ์ค€ Claude ์ž์‚ฐ(์Šคํ‚ฌยท๋ฃฐยทํ›…) ๋™๊ธฐํ™” ๋ฐ Claude ๊ณ„์ • ์ €์žฅ/์ „ํ™˜ CLI(`sd-claude auth save`/`switch`). ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ฝ”๋“œ API ์—†์Œ. ์ž์„ธํžˆ: [apis/sd-claude/README.md](./apis/sd-claude/README.md)
60
- - **sd-cli** โ€” simplysm ๋นŒ๋“œ/๋ฐฐํฌ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ CLI. ์„œ๋ธŒ์ปค๋งจ๋“œ(`check`/`watch`/`dev`/`device`/`build`/`publish`/`replace-deps`/`init`), `sd.config.ts` ์ž‘์„ฑ ํƒ€์ž…, Vitest ์˜ Angular AOT plugin(`sdAngularPlugin`), TS ํŒจํ‚ค์ง€ ์ฆ๋ถ„ ์ปดํŒŒ์ผ ์—”์ง„(`SdTsCompiler`). ์ž์„ธํžˆ: [apis/sd-cli/README.md](./apis/sd-cli/README.md)
61
- - **service-client** โ€” `@simplysm/service-server` ์™€ WebSocket ์œผ๋กœ ํ†ต์‹ ํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ. RPCยท์ด๋ฒคํŠธ ๊ตฌ๋…ยทํŒŒ์ผ ์—…/๋‹ค์šด๋กœ๋“œยท์›๊ฒฉ ORM ์‹คํ–‰์„ ๋‹จ์ผ `ServiceClient` ์—์„œ ์ œ๊ณต(Node/๋ธŒ๋ผ์šฐ์ € ๊ณต์šฉ). ์ž์„ธํžˆ: [apis/service-client/README.md](./apis/service-client/README.md)
62
- - **service-common** โ€” ์„œ๋ฒ„/ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ณต์œ ํ•˜๋Š” ์„œ๋น„์Šค ํ”„๋กœํ† ์ฝœยท๋ฉ”์‹œ์ง€ยท์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šคยท์•ฑ ๊ตฌ์กฐยท์ด๋ฒคํŠธ ์ •์˜. ์ž์„ธํžˆ: [apis/service-common/README.md](./apis/service-common/README.md)
63
- - **service-server** โ€” Fastify + WebSocket ์œ„์— ์„œ๋น„์Šค(`defineService`)ยทJWT ์ธ์ฆ(`auth`)ยท๋นŒํŠธ์ธ ORM/AutoUpdate/AppStructureยทV1 ๋ ˆ๊ฑฐ์‹œ ํ˜ธํ™˜์„ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ(`createServiceServer().listen()`). ์ž์„ธํžˆ: [apis/service-server/README.md](./apis/service-server/README.md)
64
- - **storage** โ€” FTP/FTPS/SFTP ์›๊ฒฉ ์Šคํ† ๋ฆฌ์ง€์— ๋™์ผ ์ธํ„ฐํŽ˜์ด์Šค(`StorageClient`)๋กœ ํŒŒ์ผ ์ฝ๊ธฐ/์“ฐ๊ธฐ/๊ด€๋ฆฌ. ์ž์„ธํžˆ: [apis/storage/README.md](./apis/storage/README.md)
47
+ - **angular** โ€” Angular(zonelessยทsignal) ์—…๋ฌด ํ”„๋ก ํŠธ์—”๋“œ ์ปดํฌ๋„ŒํŠธยท๋””๋ ‰ํ‹ฐ๋ธŒยทํ”„๋กœ๋ฐ”์ด๋” โ€” ์•ฑ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ(provideSdAngular)ยท๋ชจ๋‹ฌ/ํ† ์ŠคํŠธ/busy/์ธ์‡„ยท๋ผ์šฐํŒ…/๋ฉ”๋‰ด/๊ถŒํ•œยทํผ ์ปจํŠธ๋กคยท๋ ˆ์ด์•„์›ƒยทsd-sheetยท๊ณต์œ ๋ฐ์ดํ„ฐยทCRUD ํ™”๋ฉด ๊ณจ๊ฒฉยท์ฃผ์†Œ๊ฒ€์ƒ‰/์—๋””ํ„ฐ/์ฐจํŠธ/์นธ๋ฐ˜์„ ๋‹ค๋ฃฐ ๋•Œ. ์ž์„ธํžˆ: [apis/angular/README.md](./apis/angular/README.md)
48
+ - **capacitor-plugin-auto-update** โ€” Capacitor(Android) ์•ฑ์—์„œ APK ์„ค์น˜ ์ธํ…ํŠธ ์‹คํ–‰ยท์„ค์น˜ ๊ถŒํ•œ ๊ด€๋ฆฌ, ์„œ๋ฒ„/์™ธ๋ถ€ ์ €์žฅ์†Œ ๊ธฐ๋ฐ˜ ์ตœ์‹  APK ์ž๋™ ๊ฐ์ง€ยท๋‹ค์šด๋กœ๋“œยท์„ค์น˜ ํ๋ฆ„์„ ๋Œ๋ฆด ๋•Œ. ์ž์„ธํžˆ: [apis/capacitor-plugin-auto-update/README.md](./apis/capacitor-plugin-auto-update/README.md)
49
+ - **capacitor-plugin-file-system** โ€” Capacitor ํŒŒ์ผ ์‹œ์Šคํ…œ ํ”Œ๋Ÿฌ๊ทธ์ธ. ๋„ค์ดํ‹ฐ๋ธŒ(Android ์™ธ๋ถ€/์•ฑ ์ €์žฅ์†Œ)ยท๋ธŒ๋ผ์šฐ์ €(IndexedDB ์—๋ฎฌ๋ ˆ์ด์…˜)์—์„œ ํŒŒ์ผ ์ฝ๊ธฐ/์“ฐ๊ธฐ, ๋””๋ ‰ํ† ๋ฆฌ ์กฐํšŒ/์ƒ์„ฑ/์‚ญ์ œ, ์กด์žฌ ํ™•์ธ, ๊ถŒํ•œ ํ™•์ธ/์š”์ฒญ, ์ €์žฅ์†Œ ๊ฒฝ๋กœยทURI ์กฐํšŒ๋ฅผ static FileSystem ํด๋ž˜์Šค๋กœ ์ œ๊ณต. ์ž์„ธํžˆ: [apis/capacitor-plugin-file-system/README.md](./apis/capacitor-plugin-file-system/README.md)
50
+ - **capacitor-plugin-intent** โ€” Android ์ธํ…ํŠธ ์†ก์ˆ˜์‹  Capacitor ํ”Œ๋Ÿฌ๊ทธ์ธ โ€” ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ ๊ตฌ๋…/์ „์†กยท์‹คํ–‰ ์ธํ…ํŠธ ์กฐํšŒยทnewIntent ๋ฆฌ์Šค๋„ˆยทstartActivityForResult ์™ธ๋ถ€ Activity ์‹คํ–‰์„ ์ •์  ํด๋ž˜์Šค Intent ๋กœ ์ˆ˜ํ–‰(๋ฐ”์ฝ”๋“œ ์Šค์บ๋„ˆยทPDA ์—ฐ๋™, ์›น์€ ๋ฏธ์ง€์› ์Šคํ…). ์ž์„ธํžˆ: [apis/capacitor-plugin-intent/README.md](./apis/capacitor-plugin-intent/README.md)
51
+ - **capacitor-plugin-usb-storage** โ€” USB Mass Storage ์žฅ์น˜(Android=libaums ์‹ค๋ฌผ, web=IndexedDB ๊ฐ€์ƒ)์˜ ์žฅ์น˜ ๋ชฉ๋ก ์กฐํšŒยท๊ถŒํ•œ ์š”์ฒญ/ํ™•์ธยท๋””๋ ‰ํ† ๋ฆฌ/ํŒŒ์ผ ์ฝ๊ธฐ๊ฐ€ ํ•„์š”ํ•  ๋•Œ โ€” ์ •์  ํด๋ž˜์Šค UsbStorage. ์ž์„ธํžˆ: [apis/capacitor-plugin-usb-storage/README.md](./apis/capacitor-plugin-usb-storage/README.md)
52
+ - **core-browser** โ€” ๋ธŒ๋ผ์šฐ์ € ์ „์šฉ ์œ ํ‹ธ โ€” DOM ์š”์†Œ ํ™•์žฅ ๋ฉ”์„œ๋“œ(์กฐํšŒยทํƒญ์ด๋™ยท๊ฐ€์‹œ์„ฑยท์ƒ๋Œ€์ขŒํ‘œยท์Šคํฌ๋กคยทํด๋ฆฝ๋ณด๋“œยท๊ฒฝ๊ณ„์ธก์ •), Blob ๋‹ค์šด๋กœ๋“œ/ํŒŒ์ผ์„ ํƒ/์ง„ํ–‰๋ฅ  fetch, IndexedDB KV ์ €์žฅ์†Œ ๋ฐ ๊ฐ€์ƒ ํŒŒ์ผ์‹œ์Šคํ…œ. ์ž์„ธํžˆ: [apis/core-browser/README.md](./apis/core-browser/README.md)
53
+ - **core-common** โ€” ๋Ÿฐํƒ€์ž„ ๋ฌด๊ด€ ๊ณตํ†ต ์œ ํ‹ธ โ€” ๋‚ ์งœ/์‹œ๊ฐ„ ๊ฐ’ ํƒ€์ž…(DateTime/DateOnly/Time), ์—๋Ÿฌ ํŠธ๋ฆฌ(SdError ๋“ฑ), ๋น„๋™๊ธฐ ํ/์ด๋ฒคํŠธ/์บ์‹œ, Array/Set/Map ํ”„๋กœํ† ํƒ€์ž… ํ™•์žฅ, obj/json/transfer/str/num/bytes/path/xml ์œ ํ‹ธ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๊ฐ€ ํ•„์š”ํ•  ๋•Œ. ์ž์„ธํžˆ: [apis/core-common/README.md](./apis/core-common/README.md)
54
+ - **core-node** โ€” Node ๋Ÿฐํƒ€์ž„ ์ „์šฉ ์œ ํ‹ธ โ€” ํŒŒ์ผ์‹œ์Šคํ…œ IO(fsx), ์ž์‹ ํ”„๋กœ์„ธ์Šค ์‹คํ–‰ยท์ธ์ฝ”๋”ฉ(cpx), POSIX ๊ฒฝ๋กœ ๊ฐ€๊ณต(pathx), ํŒŒ์ผ ๋ณ€๊ฒฝ ๊ฐ์‹œ(FsWatcher), consola ๋กœ๊น… ์…‹์—…, worker_threads ํƒ€์ž… ์•ˆ์ „ ๋ž˜ํผ(worker). ์ž์„ธํžˆ: [apis/core-node/README.md](./apis/core-node/README.md)
55
+ - **excel** โ€” OOXML(.xlsx) ์›Œํฌ๋ถ์„ ZIP lazy-load ๋กœ ์ฝ๊ณ  ์“ฐ๊ธฐ โ€” ExcelWorkbook/Worksheet ์ง„์ž…, ์…€ ๊ฐ’ยท์ˆ˜์‹ยท์Šคํƒ€์ผยท๋ณ‘ํ•ฉ, ์กฐ๊ฑด๋ถ€ ์„œ์‹, ์ด๋ฏธ์ง€, Zod ๊ธฐ๋ฐ˜ ExcelWrapper, ์ฃผ์†Œยท๋‚ ์งœยท์ˆซ์žํ˜•์‹ ๋ณ€ํ™˜ ์œ ํ‹ธ์ด ํ•„์š”ํ•  ๋•Œ. ์ž์„ธํžˆ: [apis/excel/README.md](./apis/excel/README.md)
56
+ - **lint** โ€” ESLint 9 flat-config ํ”„๋ฆฌ์…‹(eslint-recommended)๊ณผ simplysm ์ปค์Šคํ…€ ๊ทœ์น™ 9์ข…(eslint-plugin)์„ subpath export ๋กœ ์ œ๊ณต โ€” ํ”„๋กœ์ ํŠธ lint ์„ค์ •์„ ์žก๊ฑฐ๋‚˜ ์ปค์Šคํ…€ ๊ทœ์น™ ๋™์ž‘์„ ๊ฒ€ํ† ํ•  ๋•Œ. ์ž์„ธํžˆ: [apis/lint/README.md](./apis/lint/README.md)
57
+ - **orm-common** โ€” Dialect ๋…๋ฆฝ ORM ์ฝ”์–ด โ€” Table/View/Procedure fluent ๋นŒ๋”๋กœ ์Šคํ‚ค๋งˆ๋ฅผ ์ •์˜ํ•˜๊ณ  DbContext ์— ๋“ฑ๋กํ•ด connect/transaction/DDL ์„ ๋Œ๋ฆฌ๋ฉฐ, Queryable ์ฒด์ด๋‹๊ณผ expr ํ‘œํ˜„์‹์œผ๋กœ SELECT/CUD/ํ”„๋กœ์‹œ์ € ์ฟผ๋ฆฌ๋ฅผ JSON AST(QueryDef/Expr)๋กœ ์กฐ๋ฆฝํ•  ๋•Œ(์‹ค์ œ SQL ๋ Œ๋”๋งยท๊ฒฐ๊ณผ ํŒŒ์‹ฑ์€ mysql/mssql/postgresql ๋นŒ๋”ยทexecutor ๊ฐ€ ๋‹ด๋‹น). ์ž์„ธํžˆ: [apis/orm-common/README.md](./apis/orm-common/README.md)
58
+ - **orm-node** โ€” Node.js ํ™˜๊ฒฝ์—์„œ @simplysm/orm-common ์˜ DbContext ๋ฅผ MSSQL/MySQL/PostgreSQL ์‹ค DB ์— ์—ฐ๊ฒฐํ•ด ์‹คํ–‰ โ€” createOrm ์œผ๋กœ ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„ ORM ์‹คํ–‰์„ ํ•˜๊ฑฐ๋‚˜, ์ €์ˆ˜์ค€ DbConn ์œผ๋กœ raw SQLยทํŒŒ๋ผ๋ฏธํ„ฐ ์ฟผ๋ฆฌยทbulk insertยท์ˆ˜๋™ ํŠธ๋žœ์žญ์…˜์„ ์ง์ ‘ ๋‹ค๋ฃฐ ๋•Œ. ์ž์„ธํžˆ: [apis/orm-node/README.md](./apis/orm-node/README.md)
59
+ - **sd-cli** โ€” sd.config.ts ์„ค์ • ํƒ€์ž…(๋นŒ๋“œ ํƒ€๊ฒŸยท๋ฐฐํฌยทCapacitor/Electron/PWA), ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹ TS/Angular AOT ์ฆ๋ถ„ ์ปดํŒŒ์ผ๋Ÿฌ(SdTsCompiler), Vitest์šฉ Angular AOT Vite ํ”Œ๋Ÿฌ๊ทธ์ธ(sdAngularPlugin)์„ ๋‹ค๋ฃฐ ๋•Œ. ์ž์„ธํžˆ: [apis/sd-cli/README.md](./apis/sd-cli/README.md)
60
+ - **service-client** โ€” WebSocket ์„œ๋น„์Šค ์„œ๋ฒ„์— ์ ‘์†ํ•ด ์„œ๋น„์Šค ๋ฉ”์„œ๋“œ RPC ํ˜ธ์ถœยท์ธ์ฆยท์„œ๋ฒ„ ์ด๋ฒคํŠธ ๊ตฌ๋…ยทํŒŒ์ผ ์—…๋‹ค์šด๋กœ๋“œยทORM ์›๊ฒฉ ํŠธ๋žœ์žญ์…˜ ์‹คํ–‰์ด ํ•„์š”ํ•  ๋•Œ (๋ธŒ๋ผ์šฐ์ €/Node ๊ณต์šฉ ํด๋ผ์ด์–ธํŠธ). ์ž์„ธํžˆ: [apis/service-client/README.md](./apis/service-client/README.md)
61
+ - **service-common** โ€” ์„œ๋ฒ„ยทํด๋ผ์ด์–ธํŠธ ๊ณต์œ  ํ†ต์‹  ๊ณ„์•ฝ โ€” ๋ฐ”์ด๋„ˆ๋ฆฌ ํ”„๋กœํ† ์ฝœ(์ธ์ฝ”๋”ฉ/์ฒญํ‚น/์žฌ์กฐ๋ฆฝ)ยท๋ฉ”์‹œ์ง€ ํƒ€์ž…, ORM/์ž๋™์—…๋ฐ์ดํŠธ/์—…๋กœ๋“œ ์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šค, ํƒ€์ž… ์•ˆ์ „ ์ด๋ฒคํŠธ ์ •์˜(defineEvent), ์•ฑ ๋ฉ”๋‰ดยท๊ถŒํ•œ ํŠธ๋ฆฌ ๋ชจ๋ธ์„ ๋‹ค๋ฃฐ ๋•Œ. ์ž์„ธํžˆ: [apis/service-common/README.md](./apis/service-common/README.md)
62
+ - **service-server** โ€” Fastify ๊ธฐ๋ฐ˜ WebSocket/HTTP RPC ์„œ๋น„์Šค ์„œ๋ฒ„ โ€” defineService/auth ๋กœ ์„œ๋น„์Šค ์ •์˜, JWT ์ธ์ฆ, ์ •์  ํŒŒ์ผยท์—…๋กœ๋“œ, ์„œ๋ฒ„โ†’ํด๋ผ์ด์–ธํŠธ ์ด๋ฒคํŠธ ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ, ORM/์ž๋™์—…๋ฐ์ดํŠธ ๋‚ด์žฅ ์„œ๋น„์Šค, V1 ๋ ˆ๊ฑฐ์‹œ ํ˜ธํ™˜์„ ๋‹ค๋ฃฐ ๋•Œ. ์ž์„ธํžˆ: [apis/service-server/README.md](./apis/service-server/README.md)
63
+ - **storage** โ€” FTP/FTPS/SFTP ์›๊ฒฉ ์Šคํ† ๋ฆฌ์ง€์— ์—ฐ๊ฒฐํ•ด ํŒŒ์ผยท๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์—…๋กœ๋“œยท๋‹ค์šด๋กœ๋“œยท์กฐํšŒยท์‚ญ์ œํ•  ๋•Œ. ์ง„์ž…์ ์€ StorageFactory.connect(ํ”„๋กœํ† ์ฝœ, ์ ‘์†์ •๋ณด, ์ฝœ๋ฐฑ)๋กœ ์—ฐ๊ฒฐยท์ข…๋ฃŒ ์ž๋™ ๊ด€๋ฆฌ. ์ž์„ธํžˆ: [apis/storage/README.md](./apis/storage/README.md)
@@ -0,0 +1,35 @@
1
+ # @simplysm/angular
2
+
3
+ Angular 19+ (zoneless, signal ๊ธฐ๋ฐ˜) ์—…๋ฌด ํ”„๋ก ํŠธ์—”๋“œ์šฉ ์ปดํฌ๋„ŒํŠธยท๋””๋ ‰ํ‹ฐ๋ธŒยทํ”„๋กœ๋ฐ”์ด๋” ๋ชจ์Œ. ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋Š” standalone, `OnPush`, signal input/model/output ์‚ฌ์šฉ. ๋ถ€ํŠธ์ŠคํŠธ๋žฉ์€ `provideSdAngular` 1๊ฐœ๋กœ ์‹œ์ž‘.
4
+
5
+ ## ์‚ฌ์šฉ ํŠธ๋ฆฌ๊ฑฐ ์ธ๋ฑ์Šค
6
+
7
+ - **์•ฑ ๋ถ€ํŠธ์ŠคํŠธ๋žฉยท์ „์—ญ ์„ค์ •** โ€” ์•ฑ ์‹œ์ž‘ ์‹œ `provideSdAngular` ํ˜ธ์ถœ, ์ „์—ญ ์—๋Ÿฌ ์ฒ˜๋ฆฌยทํ…Œ๋งˆยท๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€ยท์„œ๋ฒ„์—ฐ๊ฒฐยท์‹œ์Šคํ…œ์„ค์ • ํ”„๋กœ๋ฐ”์ด๋” ์ฃผ์ž…. ์ž์„ธํžˆ: [infra.md](./infra.md)
8
+ - **๋ชจ๋‹ฌยทํ† ์ŠคํŠธยท๋ฐ”์จยท์ธ์‡„(์˜ค๋ฒ„๋ ˆ์ด)** โ€” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ๋ชจ๋‹ฌ/ํ† ์ŠคํŠธ ๋„์šฐ๊ธฐ, busy ํ‘œ์‹œ, ํ™”๋ฉด ์ธ์‡„/PDF. ์ž์„ธํžˆ: [overlay.md](./overlay.md)
9
+ - **๋ผ์šฐํŒ…ยท์•ฑ ๊ตฌ์กฐยท๋ฉ”๋‰ดยท๊ถŒํ•œ** โ€” ํŽ˜์ด์ง€ ์ฝ”๋“œยท๋ทฐ ํƒ€์ž…ยท๋ทฐ ์ œ๋ชฉ signal, ๋ผ์šฐํ„ฐ ๋งํฌ, ์‚ฌ์ด๋“œ๋ฐ”/ํƒ‘๋ฐ” ๋ฉ”๋‰ด ํŠธ๋ฆฌ, ๊ถŒํ•œ ํŒ์ •. ์ž์„ธํžˆ: [routing-appstructure.md](./routing-appstructure.md)
10
+ - **ํ˜ธ์ŠคํŠธ ๋””๋ ‰ํ‹ฐ๋ธŒยทsetup ํ›…** โ€” ์—˜๋ฆฌ๋จผํŠธ์— ripple/show-effect/invalid ํ‘œ์‹œ ๋ถ€์ฐฉ, ๋ฆฌ์‚ฌ์ด์ฆˆ/๊ต์ฐจ/๋ช…๋ น(ctrl+s ๋“ฑ) ์ด๋ฒคํŠธ, ์˜ต์…˜ ์ด๋ฒคํŠธ(`.capture`/`.passive`), ํƒ€์ž…๋“œ ํ…œํ”Œ๋ฆฟ. ์ž์„ธํžˆ: [directives.md](./directives.md)
11
+ - **์ž…๋ ฅยท๋ฒ„ํŠผ ์ปจํŠธ๋กค** โ€” textfield/textarea/numpad/range/checkbox/switch/select/dropdown/form/button ๋“ฑ ํผ ์ปจํŠธ๋กค. ์ž์„ธํžˆ: [controls.md](./controls.md)
12
+ - **๋ ˆ์ด์•„์›ƒ(์‚ฌ์ด๋“œ๋ฐ”ยทํƒ‘๋ฐ”)** โ€” ํ™”๋ฉด ๊ณจ๊ฒฉ(์‚ฌ์ด๋“œ๋ฐ” ์ปจํ…Œ์ด๋„ˆ/๋ฉ”๋‰ด/์œ ์ €, ํƒ‘๋ฐ” ์ปจํ…Œ์ด๋„ˆ/๋ฉ”๋‰ด/์œ ์ €). ์ž์„ธํžˆ: [layout.md](./layout.md)
13
+ - **์‹œํŠธ(๋ฐ์ดํ„ฐ ๊ทธ๋ฆฌ๋“œ)** โ€” `sd-sheet` ์™€ ์ปฌ๋Ÿผ ์ •์˜, ์ •๋ ฌ/์„ ํƒ/ํŽ˜์ด์ง•/๊ณ ์ •/์…€ํŽธ์ง‘. ์ž์„ธํžˆ: [sheet.md](./sheet.md)
14
+ - **๊ณต์œ  ๋ฐ์ดํ„ฐ(shared-data)** โ€” ์„œ๋ฒ„ ๋งˆ์Šคํ„ฐ ๋ฐ์ดํ„ฐ ์บ์‹œ ํ”„๋กœ๋ฐ”์ด๋”์™€ ๊ทธ select/list/button UI. ์ž์„ธํžˆ: [shared-data.md](./shared-data.md)
15
+ - **์„ ํƒยท์ •๋ ฌยทํ™•์žฅ ๋งค๋‹ˆ์ €(use* ์ปดํฌ์ €๋ธ”)** โ€” ์ปค์Šคํ…€ ๋ฆฌ์ŠคํŠธ์— ์„ ํƒ/์ •๋ ฌ/ํŠธ๋ฆฌํ™•์žฅ ๋กœ์ง ๋ถ€์ฐฉ. ์ž์„ธํžˆ: [selection-managers.md](./selection-managers.md)
16
+ - **CRUD ํ™”๋ฉด ๊ณจ๊ฒฉยท์ƒํƒœํ”„๋ฆฌ์…‹ยท๊ถŒํ•œํ‘œ** โ€” ๋ชฉ๋ก/์ƒ์„ธ ํ™”๋ฉด ์ปจํ…Œ์ด๋„ˆ, ์ƒํƒœ ํ”„๋ฆฌ์…‹ ์ €์žฅ, ๊ถŒํ•œ ํŽธ์ง‘ ํ…Œ์ด๋ธ”. ์ž์„ธํžˆ: [crud.md](./crud.md)
17
+ - **๊ธฐ๋Šฅ ์ปดํฌ๋„ŒํŠธ(์ฃผ์†Œ๊ฒ€์ƒ‰ยท์—๋””ํ„ฐยท์‹œ๊ฐํ™”ยท์นธ๋ฐ˜)** โ€” ๋‹ค์Œ ์ฃผ์†Œ๊ฒ€์ƒ‰ ๋ชจ๋‹ฌ, tiptap ์—๋””ํ„ฐ, ๋ฐ”์ฝ”๋“œ/๋‹ฌ๋ ฅ/์ฐจํŠธ/๋ผ๋ฒจ/๋…ธํŠธ/์ง„ํ–‰๋ฅ , ์นธ๋ฐ˜ ๋ณด๋“œ. ์ž์„ธํžˆ: [features.md](./features.md)
18
+ - **FormatPipe** โ€” ํ…œํ”Œ๋ฆฟ์—์„œ ๋ฌธ์ž์—ด/๋‚ ์งœ ํฌ๋งท ํ‘œ์‹œ. ์•„๋ž˜ ์ธ๋ผ์ธ ์ฐธ์กฐ.
19
+ - **SelectModalOutputResult / DirectiveInputSignals / UndefToOptional / WithOptional** โ€” ๋ชจ๋‹ฌ ์„ ํƒ ๊ฒฐ๊ณผยทinput signal ํƒ€์ž… ์œ ํ‹ธ. ์•„๋ž˜ ์ธ๋ผ์ธ ์ฐธ์กฐ.
20
+
21
+ ## FormatPipe
22
+
23
+ `{{ value | format: formatStr }}` โ€” ํŒŒ์ดํ”„. value ๊ฐ€ `DateTime`/`DateOnly` ๋ฉด `toFormatString(formatStr)`, `string` ์ด๋ฉด `X` ๋งˆ์Šคํฌ ํฌ๋งท ์ ์šฉ(์˜ˆ: `format: 'XXX-XXXX'`, `|` ๋กœ ๊ธธ์ด๋ณ„ ๋‹ค์ค‘ ํŒจํ„ด ๋ถ„๊ธฐ โ€” `X` ๊ฐœ์ˆ˜๊ฐ€ value.length ์™€ ์ผ์น˜ํ•˜๋Š” ํŒจํ„ด ์„ ํƒ). value ๊ฐ€ null/undefined ๋ฉด `""` ๋ฐ˜ํ™˜(๊ฒฐ์ธก์€ ๋นˆ ๋ฌธ์ž์—ด๋กœ ํ‘œ์‹œ). standalone import ํ›„ ์‚ฌ์šฉ.
24
+
25
+ ```html
26
+ <span>{{ phone | format: 'XXX-XXXX-XXXX|XXX-XXX-XXXX' }}</span>
27
+ <span>{{ dateOnly | format: 'yyyy-MM-dd' }}</span>
28
+ ```
29
+
30
+ ## ํƒ€์ž… ์œ ํ‹ธ
31
+
32
+ - **SelectModalOutputResult<TKey>** โ€” `{ selectedKeys: TKey[] }`. ์„ ํƒ ๋ชจ๋‹ฌ์ด `close.emit` ์œผ๋กœ ๋Œ๋ ค์ฃผ๋Š” ๊ฒฐ๊ณผ ํ˜•ํƒœ. ์„ ํƒ ๋ชจ๋‹ฌ ์ปดํฌ๋„ŒํŠธ ์ž‘์„ฑ ์‹œ close output ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉ.
33
+ - **DirectiveInputSignals<T>** โ€” ์ปดํฌ๋„ŒํŠธ/๋””๋ ‰ํ‹ฐ๋ธŒ ํด๋ž˜์Šค T ์˜ `InputSignal` prop ๋“ค๋งŒ ๊ณจ๋ผ `{ prop: ๊ฐ’ํƒ€์ž… }` ๊ฐ์ฒด ํƒ€์ž…์œผ๋กœ ์ถ”์ถœ. `undefined` ํฌํ•จ ํ•„๋“œ๋Š” optional ๋กœ ๋ณ€ํ™˜. ๋ชจ๋‹ฌ/ํ† ์ŠคํŠธ/์ธ์‡„์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋„˜๊ธธ ๋•Œ inputs ํƒ€์ž… ์‚ฐ์ถœ์— ๋‚ด๋ถ€์ ์œผ๋กœ ์“ฐ์ž„.
34
+ - **UndefToOptional<T>** โ€” `value: T | undefined` ํ•„๋“œ๋ฅผ `value?: T` ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋งคํ•‘ ํƒ€์ž…. `DirectiveInputSignals` ๊ฐ€ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉ.
35
+ - **WithOptional<T, K>** โ€” T ์—์„œ ํ‚ค K ๋“ค๋งŒ optional ๋กœ ๋งŒ๋“œ๋Š” ํƒ€์ž…. ๋ชจ๋‹ฌ/์ธ์‡„ inputs ์—์„œ ์ผ๋ถ€ input ์„ ์„ ํƒ ํ•ญ๋ชฉ์œผ๋กœ ํ‘œ์‹œํ•  ๋•Œ ์‚ฌ์šฉ.
@@ -0,0 +1,51 @@
1
+ # @simplysm/angular โ€” ํผ ์ปจํŠธ๋กคยท๋ฒ„ํŠผยท์„ ํƒ ์ปจํŠธ๋กค
2
+
3
+ ํผ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๋Š” ์ž…๋ ฅ/๋ฒ„ํŠผ/์„ ํƒ ์ปดํฌ๋„ŒํŠธ ๋ฌถ์Œ. ๋Œ€๋ถ€๋ถ„ `value = model()` ์–‘๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ๊ณผ `theme`/`size`/`inline`/`inset`/`disabled` ๊ณตํ†ต input ์„ ๊ฐ€์ง. ๊ณตํ†ต enum:
4
+ - theme(๊ธฐ๋ณธ 8์ƒ‰): `"primary"|"secondary"|"info"|"success"|"warning"|"danger"|"gray"|"blue-gray"` โ€” ์ƒ‰์ƒ ํ…Œ๋งˆ.
5
+ - size: `"sm"|"lg"` โ€” ์ž‘๊ฒŒ/ํฌ๊ฒŒ(๋ฏธ์ง€์ •=๊ธฐ๋ณธ).
6
+ - inline: boolean โ€” inline-block ์œผ๋กœ ๋ฐฐ์น˜(ํญ ์ž๋™).
7
+ - inset: boolean โ€” ํ…Œ๋‘๋ฆฌยท๋ผ์šด๋“œ ์ œ๊ฑฐ(์…€/๊ทธ๋ฃน ๋‚ด๋ถ€ ์‚ฝ์ž…์šฉ).
8
+ - disabled: boolean โ€” ๋น„ํ™œ์„ฑ.
9
+
10
+ ## ๋ฒ„ํŠผ๋ฅ˜
11
+
12
+ - **SdButton** `<sd-button>` โ€” ๋ฒ„ํŠผ. `type`("button"|"submit", ๊ธฐ๋ณธ button), `theme`(8์ƒ‰ + `"link"`/`"link-<์ƒ‰>"`/`"link-rev"` ํ…์ŠคํŠธํ˜•), `inline`/`inset`/`size`/`disabled`, `buttonStyle`/`buttonClass`(๋‚ด๋ถ€ button ์—˜๋ฆฌ๋จผํŠธ ์Šคํƒ€์ผ/ํด๋ž˜์Šค). ํผ ์ œ์ถœ ๋ฒ„ํŠผ์ด๋ฉด `type="submit"`.
13
+ - **SdAnchor** `<sd-anchor>` โ€” ํ…์ŠคํŠธ ๋งํฌ. `theme`(8์ƒ‰, ๊ธฐ๋ณธ primary), `disabled`. ์ธ๋ผ์ธ ํด๋ฆญ ์š”์†Œ(์•„์ด์ฝ˜ ๋ฒ„ํŠผ ๋“ฑ)์—.
14
+ - **SdAdditionalButton** `<sd-additional-button>` โ€” ๋‚ด์šฉ + ์šฐ์ธก ๋ถ€์† ๋ฒ„ํŠผ(`sd-anchor`/`sd-button` ํˆฌ์˜) ์ปจํ…Œ์ด๋„ˆ. `size`/`inset`.
15
+ - **SdModalSelectButton** `<sd-modal-select-button>` โ€” ํด๋ฆญ ์‹œ ์„ ํƒ ๋ชจ๋‹ฌ์„ ๋„์›Œ ๊ฐ’ ์„ ํƒ. `modal = input.required<SdSelectModalInfo<...>>()`, `value = model()`, `selectMode`("single"|"multi", ๊ธฐ๋ณธ single โ€” single ์ด๋ฉด ๋‹จ์ผ ํ‚ค, multi ๋ฉด ํ‚ค ๋ฐฐ์—ด), `required`(๋ฏธ์„ ํƒ ์‹œ ๊ฒ€์ฆ ์˜ค๋ฅ˜ + ์ง€์šฐ๊ฐœ ์ˆจ๊น€), `disabled`/`inset`/`size`, `modalOptions`, `searchIcon`. required ์•„๋‹ˆ๊ณ  ๊ฐ’ ์žˆ์œผ๋ฉด ์ง€์šฐ๊ฐœ ํ‘œ์‹œ. ํƒ€์ž…: `SdSelectModal<TKey>`(์„ ํƒ๋ชจ๋‹ฌ์ด ๊ตฌํ˜„, `SdModalContentDef<SelectModalOutputResult<TKey>>` + `selectMode`/`selectedKeys` input), `SdSelectModalInfo<T>`(selectMode/selectedKeys ์ œ์™ธํ•œ ๋ชจ๋‹ฌ ์ •๋ณด).
16
+
17
+ ## ํ…์ŠคํŠธยท์ˆซ์ž ์ž…๋ ฅ
18
+
19
+ - **SdTextfield<K>** `<sd-textfield [type]="...">` โ€” ํƒ€์ž…๋ณ„ ๋‹จ์ผ ์ž…๋ ฅ. `type = input.required<K>()`(K = `SdTextfieldTypes` ํ‚ค), `value = model<SdTextfieldTypes[K]>()`. ์ถ”๊ฐ€ input: `placeholder`/`title`, `min`/`max`(ํƒ€์ž…์— ๋งž๋Š” ๊ฐ’), `minlength`/`maxlength`/`pattern`(๋ฌธ์žํ˜• ๊ฒ€์ฆ), `validatorFn`(์ปค์Šคํ…€ ๊ฒ€์ฆ, ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜), `format`(format ํƒ€์ž…์˜ X ๋งˆ์Šคํฌ), `step`, `autocomplete`, `useNumberComma`(์ˆซ์ž ์ฒœ๋‹จ์œ„ ์ฝค๋งˆ, ๊ธฐ๋ณธ true), `minDigits`(์ˆซ์ž ์†Œ์ˆ˜ ์ตœ์†Œ ์ž๋ฆฟ์ˆ˜), `required`, `readonly`, `inline`/`inset`/`size`/`theme`. ๊ฒ€์ฆ ์‹คํŒจ ์‹œ `setupInvalid` ๋กœ ํผ ์—ฐ๋™.
20
+ - **SdTextfieldTypes / sdTextfieldTypes** โ€” ํƒ€์ž…โ†’๊ฐ’ ๋งคํ•‘: `number`:number, `text`/`password`/`color`/`email`/`format`:string, `date`/`month`/`year`:DateOnly, `datetime`/`datetime-sec`:DateTime, `time`/`time-sec`:Time. `sdTextfieldTypes` ๋Š” ํ‚ค ๋ฐฐ์—ด(์˜ˆ: select ์˜ต์…˜ ์ƒ์„ฑ).
21
+ - **SdTextarea** `<sd-textarea>` โ€” ์—ฌ๋Ÿฌ ์ค„ ํ…์ŠคํŠธ. `value = model<string>()`, `minRows`(๊ธฐ๋ณธ 1, ๋‚ด์šฉ ์ค„ ์ˆ˜๋งŒํผ ์ž๋™ ํ™•์žฅ), `placeholder`/`title`/`required`/`readonly`/`validatorFn`/`inline`/`inset`/`size`/`theme`/`inputStyle`/`inputClass`.
22
+ - **SdNumpad** `<sd-numpad>` โ€” ํ™”๋ฉด ์ˆซ์ž ํ‚คํŒจ๋“œ. `value = model<number>()`, `placeholder`, `required`, `inputDisabled`(์ƒ๋‹จ ์ž…๋ ฅ์นธ ์ง์ ‘์ž…๋ ฅ ๋ง‰๊ธฐ), `useEnterButton`/`useMinusButton`(ENT/โˆ’ ๋ฒ„ํŠผ ํ‘œ์‹œ), `enterButtonClick = output()`.
23
+ - **SdRange<K>** `<sd-range [type]="...">` โ€” ๋™์ผ ํƒ€์ž… ๋‘ ๊ฐ’์˜ ๋ฒ”์œ„(`from ~ to`). `type = input.required<K>()`, `from`/`to` = model<SdTextfieldTypes[K]>(), `required`/`disabled`/`inputStyle`. to ์˜ min ์€ from ์œผ๋กœ ์ž๋™ ์ œํ•œ.
24
+ - **SdDateRangePicker** `<sd-date-range-picker>` โ€” ์ผ/์›”/๋ฒ”์œ„ ์„ ํƒ. `periodType = model<"์ผ"|"์›”"|"๋ฒ”์œ„">("๋ฒ”์œ„")`(์ผ=from=to ๋™๊ธฐํ™”, ์›”=ํ•ด๋‹น ์›” 1์ผ~๋ง์ผ ์ž๋™, ๋ฒ”์œ„=from~to ์ž์œ ), `from`/`to` = model<DateOnly>(), `required`.
25
+
26
+ ## ์ฒดํฌยท์Šค์œ„์น˜
27
+
28
+ - **SdCheckbox** `<sd-checkbox>` โ€” ์ฒดํฌ๋ฐ•์Šค/๋ผ๋””์˜ค. `value = model(false)`, `canChangeFn`(๋ณ€๊ฒฝ ๊ฐ€๋“œ, boolean|Promise), `icon`(์ฒดํฌ ์•„์ด์ฝ˜), `radio`(๋ผ๋””์˜ค ๋ชจ์–‘ยทํ•ด์ œ ๋ถˆ๊ฐ€), `disabled`/`size`/`inline`/`inset`, `theme`(8์ƒ‰ + `"white"`), `contentStyle`.
29
+ - **SdSwitch** `<sd-switch>` โ€” ํ† ๊ธ€ ์Šค์œ„์น˜. `value = model(false)`, `canChangeFn`, `disabled`/`inline`/`inset`/`size`/`theme`(8์ƒ‰).
30
+ - **SdCheckboxGroup<T>** / **SdCheckboxGroupItem<T>** โ€” ๊ทธ๋ฃน ๋‹ค์ค‘์„ ํƒ. group: `value = model<T[]>([])`, `disabled`. item: `value = input.required<T>()`, `inline`. ํ•ญ๋ชฉ ํด๋ฆญ ์‹œ ๊ทธ๋ฃน value ๋ฐฐ์—ด์— ์ถ”๊ฐ€/์ œ๊ฑฐ.
31
+
32
+ ## ์„ ํƒ(๋“œ๋กญ๋‹ค์šด)
33
+
34
+ - **SdSelect<M, T>** `<sd-select>` โ€” ๋“œ๋กญ๋‹ค์šด ์„ ํƒ. `selectMode = input("single" as M)`("single"|"multi" โ€” multi ๋ฉด value ๊ฐ€ ๋ฐฐ์—ดยท์ „์ฒด์„ ํƒ ๋ฐ” ํ‘œ์‹œ), `value = model<...>()`, `placeholder`, `required`(๋ฏธ์„ ํƒ ์‹œ ๊ฒ€์ฆ์˜ค๋ฅ˜), `disabled`/`inline`/`inset`/`size`, `hideSelectAll`(multi ์ „์ฒด์„ ํƒ ๋ฐ” ์ˆจ๊น€), `multiSelectionDisplayDirection`("vertical" ์ด๋ฉด ์„ ํƒ ํ•ญ๋ชฉ ์„ธ๋กœ ํ‘œ์‹œ), `items`/`trackByFn`/`getChildrenFn`(items ์ง€์ • ์‹œ `itemOf` ํ…œํ”Œ๋ฆฟ์œผ๋กœ ๋ Œ๋”ยทํŠธ๋ฆฌ ์ง€์›), `contentClass`/`contentStyle`, `dropdownOpen = model(false)`. ๋ฉ”์„œ๋“œ: selectItem/toggleItem/openDropdown/closeDropdown/onSelectAll/onDeselectAll. ํ‚ค๋ณด๋“œ โ†‘โ†“ ๋กœ ํ•ญ๋ชฉ ์ด๋™. ํƒ€์ž… `SelectModeValue<T> = { multi: T[]; single: T }`.
35
+ - **SdSelectItem<T>** `<sd-select-item [value]="...">` โ€” ์„ ํƒ ํ•ญ๋ชฉ. `value`, `disabled`, `hidden`(๊ฒ€์ƒ‰ ํ•„ํ„ฐ ๋“ฑ์œผ๋กœ ์ˆจ๊น€). multi ๋ชจ๋“œ๋ฉด ์ขŒ์ธก ์ฒดํฌ๋ฐ•์Šค ํ‘œ์‹œ. Enter/Space ๋กœ ์„ ํƒยทํ† ๊ธ€.
36
+ - **SdSelectButton** `<sd-select-button>` โ€” sd-select ์šฐ์ธก์— ๋ถ™๋Š” ๋ถ€์† ๋ฒ„ํŠผ(๊ฒ€์ƒ‰/ํŽธ์ง‘ ๋“ฑ ํŠธ๋ฆฌ๊ฑฐ). input ์—†์Œ, ํด๋ฆญ ์ด๋ฒคํŠธ๋Š” ํˆฌ์˜๋œ ๋‚ด์šฉ์—์„œ ์ฒ˜๋ฆฌ.
37
+
38
+ ## ๋“œ๋กญ๋‹ค์šด(์ €์ˆ˜์ค€)
39
+
40
+ - **SdDropdown** `<sd-dropdown>` โ€” ํŠธ๋ฆฌ๊ฑฐ + `sd-dropdown-popup` ํŒ์—…. `open = model(false)`, `disabled`. ํ™”๋ฉด ์œ„์น˜ ์ž๋™ ๋ฐฐ์น˜, ๋ชจ๋ฐ”์ผ(โ‰ค520px)์—์„  ํ•˜๋‹จ ์‹œํŠธ + backdrop. ํ‚ค๋ณด๋“œ โ†“ ๋กœ ์—ด๊ณ  โ†‘/ESC ๋กœ ๋‹ซ์Œ. `popupElRef`(contentChild)๋กœ ํŒ์—… ์—˜๋ฆฌ๋จผํŠธ ์ ‘๊ทผ.
41
+ - **SdDropdownPopup** `<sd-dropdown-popup>` โ€” ๋“œ๋กญ๋‹ค์šด ๋‚ด์šฉ. input ์—†์Œ. ๋‚ด์šฉ ๋†’์ด 300px ์ดˆ๊ณผ ์‹œ ์ž๋™ ์Šคํฌ๋กค ์บก.
42
+
43
+ ## ํผยท์ ‘๊ธฐยทํƒญยท๋ฆฌ์ŠคํŠธยท์—ฌ๋ฐฑยทํŽ˜์ด์ง€
44
+
45
+ - **SdForm** `<sd-form>` โ€” `(formSubmit)`(๊ฒ€์ฆ ํ†ต๊ณผ ์‹œ SubmitEvent), `(formInvalid)`(๊ฒ€์ฆ ์‹คํŒจ ์‹œ, ๋„ค์ดํ‹ฐ๋ธŒ ๋ฉ”์‹œ์ง€ยทํฌ์ปค์Šค ์ž๋™). `requestSubmit()` ๋ฉ”์„œ๋“œ, `formElRef`/`formEl`(ํผ ์—˜๋ฆฌ๋จผํŠธ ์ ‘๊ทผ). ๋‚ด๋ถ€ ์ปจํŠธ๋กค๋“ค์˜ `setupInvalid` ๊ฒ€์ฆ์„ ๋ชจ์•„ ์ œ์ถœ ์ œ์–ด.
46
+ - **SdCollapse** `<sd-collapse [open]="...">` โ€” ๋†’์ด ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ‘๊ธฐ. `open`(boolean). ๋‚ด์šฉ ๋†’์ด ์ž๋™ ์ธก์ •.
47
+ - **SdCollapseIcon** `<sd-collapse-icon [open]="...">` โ€” ํŽผ์นจ ์ƒํƒœ ํšŒ์ „ ์•„์ด์ฝ˜. `icon`(๊ธฐ๋ณธ chevronDown), `open`, `openRotate`(ํŽผ์น  ๋•Œ ํšŒ์ „๊ฐ๋„, ๊ธฐ๋ณธ 90).
48
+ - **SdTab<any>** / **SdTabItem** โ€” ํƒญ. tab: `value = model<any>()`. item: `value = input<any>()`(ํด๋ฆญ ์‹œ ๋ถ€๋ชจ value ์„ค์ •, ์ผ์น˜ํ•˜๋ฉด ์„ ํƒ ํ‘œ์‹œ).
49
+ - **SdList** / **SdListItem** โ€” ๋ฆฌ์ŠคํŠธ(ํŠธ๋ฆฌ). list: `inset`. item: `layout`("accordion"|"flat", ๊ธฐ๋ณธ accordion โ€” accordion ์€ ํด๋ฆญ ์‹œ ์ž์‹ ์ ‘๊ธฐ/ํŽผ์น˜๊ธฐ, flat ์€ ํ•ญ์ƒ ํŽผ์นจยทํ—ค๋” ๋น„ํด๋ฆญ), `open = model(false)`, `selected`(์„ ํƒ ๊ฐ•์กฐ), `selectedIcon`(์„ ํƒ ์•„์ด์ฝ˜ ํ‘œ์‹œ), `readonly`(ํด๋ฆญ ๋น„ํ™œ์„ฑ), `contentStyle`/`contentClass`, `toolTpl`(์šฐ์ธก ๋„๊ตฌ ํ…œํ”Œ๋ฆฟ). ์ž์‹ `sd-list` ํˆฌ์˜ ์‹œ ํ•˜์œ„ ํŠธ๋ฆฌ.
50
+ - **SdGap** `<sd-gap>` โ€” ์—ฌ๋ฐฑ ์ŠคํŽ˜์ด์„œ. `height`/`width`("xxs"|"xs"|"sm"|"default"|"lg"|"xl"|"xxl" CSS ๋ณ€์ˆ˜ ๋‹จ์œ„), `heightPx`/`widthPx`/`widthEm`(์ˆซ์ž, 0 ์ด๋ฉด display:none). width ๊ณ„์—ด ์ง€์ • ์‹œ inline-block, height ๊ณ„์—ด์ด๋ฉด block.
51
+ - **SdPagination** `<sd-pagination>` โ€” ํŽ˜์ด์ง€ ๋„ค๋น„๊ฒŒ์ด์…˜. `currentPage = model(0)`(0 ๊ธฐ๋ฐ˜), `totalPageCount`(์ „์ฒด ํŽ˜์ด์ง€ ์ˆ˜), `visiblePageCount`(ํ•œ ๊ทธ๋ฃน ํ‘œ์‹œ ์ˆ˜, ๊ธฐ๋ณธ 10). ์ฒ˜์Œ/์ด์ „๊ทธ๋ฃน/ํŽ˜์ด์ง€๋ฒˆํ˜ธ/๋‹ค์Œ๊ทธ๋ฃน/๋ ๋ฒ„ํŠผ.
@@ -0,0 +1,53 @@
1
+ # @simplysm/angular โ€” CRUD ํ™”๋ฉด ๊ณจ๊ฒฉยท์ƒํƒœํ”„๋ฆฌ์…‹ยท๊ถŒํ•œํ‘œ
2
+
3
+ ์—…๋ฌด ๋ชฉ๋ก/์ƒ์„ธ ํ™”๋ฉด์˜ ๊ณตํ†ต ๊ณจ๊ฒฉ(ํƒ‘๋ฐ”ยทbusyยท๊ถŒํ•œ ์ œํ•œยท๋„๊ตฌ๋ฐ”)๊ณผ ๋ณด์กฐ ์ปดํฌ๋„ŒํŠธ. ๋ชจ๋‘ `viewType = input.required<SdViewType>()` ๋กœ page/modal/control ๋งฅ๋ฝ์„ ๋ฐ›์Œ(`injectViewTypeSignal()` ๊ฒฐ๊ณผ ์ „๋‹ฌ). ํ™”๋ฉด ์ง„์ž… ์‹œ ๊ณต์œ  ๋ฐ์ดํ„ฐ ์ค€๋น„๋ฅผ ๋Œ€๊ธฐํ•˜๊ณ  `ready` ๋กœ ์•Œ๋ฆผ.
4
+
5
+ ## SdBaseContainer
6
+
7
+ `<sd-base-container [viewType]="...">` โ€” ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ํ™”๋ฉด ์ปจํ…Œ์ด๋„ˆ(ํƒ‘๋ฐ” + busy + ๊ถŒํ•œ์ œํ•œ + ๋„๊ตฌ๋ฐ”).
8
+ - ready = model(false) โ€” ๊ณต์œ  ๋ฐ์ดํ„ฐ ๋Œ€๊ธฐ ์™„๋ฃŒ ์‹œ true. ํ™”๋ฉด ๋ณธ๋ฌธ ํ‘œ์‹œ ์กฐ๊ฑด์—.
9
+ - initialized: boolean โ€” ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์™„๋ฃŒ ์—ฌ๋ถ€(false ๋ฉด busy).
10
+ - busyCount = model(0) โ€” busy ์นด์šดํŠธ(>0 ๋ฉด ์˜ค๋ฒ„๋ ˆ์ด).
11
+ - restricted: boolean โ€” true ๋ฉด "์‚ฌ์šฉ๊ถŒํ•œ ์—†์Œ" ์•ˆ๋‚ด๋งŒ ํ‘œ์‹œ.
12
+ - viewType: input.required<SdViewType> โ€” page ๋ฉด ํƒ‘๋ฐ”(์ œ๋ชฉ+topbarTpl) ๊ฐ์‹ธ๊ณ , ์•„๋‹ˆ๋ฉด ๋ณธ๋ฌธ๋งŒ.
13
+ - (contentChild) topbarTpl/commandTpl/contentTpl/bottomCommandTpl โ€” ํƒ‘๋ฐ” ์šฐ์ธก/์ƒ๋‹จ ๋ช…๋ น/๋ณธ๋ฌธ/ํ•˜๋‹จ ๋ช…๋ น ์˜์—ญ.
14
+
15
+ ## SdCrudDetail
16
+
17
+ `<sd-crud-detail [viewType]="...">` โ€” ๋‹จ๊ฑด ์ƒ์„ธ/ํŽธ์ง‘ ํ™”๋ฉด(ํผ ํฌํ•จ).
18
+ - ready/initialized/busyCount/restricted/viewType โ€” ์œ„์™€ ๋™์ผ.
19
+ - readonly: boolean โ€” ์ฝ๊ธฐ ์ „์šฉ.
20
+ - (viewChild) formCtrl: SdForm โ€” ๋‚ด๋ถ€ ํผ.
21
+ - (output) submit โ€” ํผ ์ œ์ถœ(๊ฒ€์ฆ ํ†ต๊ณผ).
22
+ - (contentChild) commandTpl/contentTpl/bottomCommandTpl.
23
+
24
+ ## SdCrudList<TItem, TKey>
25
+
26
+ `<sd-crud-list [viewType]="...">` โ€” ๋ชฉ๋ก ํ™”๋ฉด(ํ•„ํ„ฐ ํผ + ์‹œํŠธ + ํŽ˜์ด์ง• + ์„ ํƒ/์‚ญ์ œ/๋ณต์›).
27
+ - ready/initialized/busyCount/restricted/viewType/readonly โ€” ์œ„์™€ ๋™์ผ.
28
+ - selectMode?: "single"|"multi" โ€” ํ–‰ ์„ ํƒ ๋ชจ๋“œ.
29
+ - key: input.required<string> โ€” ์‹œํŠธ ์„ค์ • ์˜์† ํ‚ค.
30
+ - (viewChild) formCtrl: SdForm.
31
+ - (output) filterSubmit โ€” ํ•„ํ„ฐ ํผ ์ œ์ถœ. submit โ€” ์ผ๋ฐ˜ ์ œ์ถœ. create โ€” ์ถ”๊ฐ€ ๋ฒ„ํŠผ. delete: TItem[] โ€” ์‚ญ์ œ ๋Œ€์ƒ. restore: TItem[] โ€” ๋ณต์› ๋Œ€์ƒ.
32
+ - items: TItem[] โ€” ๋ชฉ๋ก ๋ฐ์ดํ„ฐ.
33
+ - selectedKeys = model<NonNullable<TKey>[]>([]) โ€” ์„ ํƒ ํ‚ค.
34
+ - currDeletedItems: TItem[] โ€” ํ˜„์žฌ ์‚ญ์ œํ‘œ์‹œ๋œ ํ•ญ๋ชฉ(๋ณต์› ๋Œ€์ƒ ํ‘œ์‹œ).
35
+ - currentPage = model(0) / totalPageCount / itemsPerPage / visiblePageCount(๊ธฐ๋ณธ 10) โ€” ํŽ˜์ด์ง•(์‹œํŠธ๋กœ ์œ„์ž„).
36
+ - sorts = model<SortingDef[]>([]) โ€” ์ •๋ ฌ ์ƒํƒœ.
37
+ - trackByFn: input.required<(item) => TKey> โ€” ํ–‰ ํ‚ค.
38
+ - (contentChild) commandTpl/filterTpl/toolTpl/bottomCommandTpl, `sd-sheet-column` ๋“ค โ€” ๋ช…๋ น/ํ•„ํ„ฐ/๋„๊ตฌ/ํ•˜๋‹จ ๋ช…๋ น ์˜์—ญ๊ณผ ์‹œํŠธ ์ปฌ๋Ÿผ.
39
+
40
+ ## SdStatePreset<TState>
41
+
42
+ `<sd-state-preset [key]="..." [(state)]="...">` โ€” ํ™”๋ฉด ์ƒํƒœ(ํ•„ํ„ฐ ๋“ฑ) ํ”„๋ฆฌ์…‹ ์ €์žฅ/์ ์šฉ ๋ฐ”.
43
+ - key: input.required<string> โ€” ํ”„๋ฆฌ์…‹ ์˜์† ํ‚ค(`SdSystemConfigProvider`).
44
+ - state = model.required<TState> โ€” ํ˜„์žฌ ์ƒํƒœ(์ €์žฅยท์ ์šฉ ๋Œ€์ƒ).
45
+ - size?: "sm"|"lg".
46
+ - โ˜… ๋ฒ„ํŠผ์œผ๋กœ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ์ด๋ฆ„ ๋ถ™์—ฌ ์ €์žฅ, ํ”„๋ฆฌ์…‹ ํด๋ฆญ ์‹œ ์ƒํƒœ ์ ์šฉ, ๊ฐ ํ”„๋ฆฌ์…‹ ์ €์žฅ(๋ฎ์–ด์“ฐ๊ธฐ)ยท์‚ญ์ œ. ํƒ€์ž… `SdStatePresetDef<TState> = { name: string; state: TState }`.
47
+
48
+ ## SdPermissionTable<TModule>
49
+
50
+ `<sd-permission-table [items]="...">` โ€” ๊ถŒํ•œ(use/edit) ํŽธ์ง‘ ํ…Œ์ด๋ธ”.
51
+ - value = model<Record<string, boolean>>({}) โ€” `<์ฝ”๋“œ>.<use|edit>` โ†’ ํ—ˆ์šฉ ๋งต.
52
+ - items: SdPermission<TModule>[] โ€” ๊ถŒํ•œ ํŠธ๋ฆฌ(`SdAppStructureProvider.getPermissionsByStructure` ๊ฒฐ๊ณผ).
53
+ - disabled: boolean โ€” ํŽธ์ง‘ ๋น„ํ™œ์„ฑ.
@@ -0,0 +1,34 @@
1
+ # @simplysm/angular โ€” ํ˜ธ์ŠคํŠธ ๋””๋ ‰ํ‹ฐ๋ธŒยท๋™์ž‘ ์…‹์—…ยทํ…œํ”Œ๋ฆฟ
2
+
3
+ ์—˜๋ฆฌ๋จผํŠธ/์ปดํฌ๋„ŒํŠธ์— ๋™์ž‘์„ ๋ถ€์ฐฉํ•˜๋Š” ๋””๋ ‰ํ‹ฐ๋ธŒ์™€, ์ปดํฌ๋„ŒํŠธ constructor ์—์„œ ํ˜ธ์ถœํ•˜๋Š” `setup*` ํ›…, ํƒ€์ž…๋“œ ng-template ๋ฌถ์Œ. ์ปดํฌ๋„ŒํŠธ ๋™์ž‘์„ ์ง์ ‘ ์กฐ๋ฆฝํ•  ๋•Œ ํ•จ๊ป˜ ์ฝํž˜.
4
+
5
+ ## ์ด๋ฒคํŠธ ๋””๋ ‰ํ‹ฐ๋ธŒ
6
+
7
+ ์˜ต์…˜ ์ด๋ฒคํŠธ(`.capture`/`.passive`/`.once`)๋Š” `provideSdAngular` ๊ฐ€ ๋“ฑ๋กํ•œ `SdOptionEventPlugin` ์œผ๋กœ ๋™์ž‘. ์ง์ ‘ inject ์•ˆ ํ•จ.
8
+
9
+ - **SdEvents** โ€” ํ‘œ์ค€ ์ด๋ฒคํŠธ์˜ ์˜ต์…˜ ๋ณ€ํ˜•์„ output ์œผ๋กœ ๋…ธ์ถœํ•˜๋Š” ๋””๋ ‰ํ‹ฐ๋ธŒ. `(click.capture)`, `(scroll.passive)`, `(touchstart.passive)`, `(wheel.capture.passive)`, `(transitionend.once)` ๋“ฑ(์…€๋ ‰ํ„ฐ์— ์—ด๊ฑฐ๋œ ์กฐํ•ฉ๋งŒ). ๋ฒ„๋ธ”๋ง ์•ˆ ๋˜๋Š” focus/blur ๋ฅผ capture ๋กœ ๋ฐ›๊ฑฐ๋‚˜ ์„ฑ๋Šฅ์ƒ passive ์Šคํฌ๋กค์ด ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ.
10
+ - **SdResizeDirective** โ€” `(sdResize)` ์ถœ๋ ฅ. ResizeObserver ๊ธฐ๋ฐ˜, requestAnimationFrame ๋””๋ฐ”์šด์Šค. ์ด๋ฒคํŠธ `SdResizeEvent = { heightChanged; widthChanged; target: HTMLElement; contentRect: DOMRectReadOnly }`. ํฌ๊ธฐ ๋ณ€ํ™”์— ๋ฐ˜์‘ํ•  ๋•Œ.
11
+ - **SdIntersectionDirective** โ€” `(sdIntersection)` ์ถœ๋ ฅ. IntersectionObserver ๊ธฐ๋ฐ˜. ์ด๋ฒคํŠธ `SdIntersectionEvent = { entry: IntersectionObserverEntry }`. ํ™”๋ฉด ์ง„์ž… ๊ฐ์ง€(์ง€์—ฐ ๋กœ๋“œ ๋“ฑ)์—.
12
+ - **SdCommandDirective** โ€” `(sdRefreshCommand)`(Ctrl+Alt+L), `(sdSaveCommand)`(Ctrl+S), `(sdInsertCommand)`(Insert) ์ถœ๋ ฅ(`KeyboardEvent`). ์ตœ์ƒ์œ„๋กœ ์—ด๋ฆฐ ๋ชจ๋‹ฌ ์•ˆ์—์„œ๋งŒ ๋™์ž‘(๊ฐ€๋ ค์ง„ ํ™”๋ฉด ๋‹จ์ถ•ํ‚ค ์ฐจ๋‹จ). ์ƒˆ๋กœ๊ณ ์นจ/์ €์žฅ/์ถ”๊ฐ€ ๋‹จ์ถ•ํ‚ค ๋ฐ”์ธ๋”ฉ์—.
13
+
14
+ ## ํ‘œ์‹œ ํšจ๊ณผ ๋””๋ ‰ํ‹ฐ๋ธŒ + ์…‹์—… ํ›…
15
+
16
+ - **SdRipple** / **setupRipple** โ€” `[sdRipple]="enabled"` ๋””๋ ‰ํ‹ฐ๋ธŒ ๋˜๋Š” `setupRipple(enableFn?: () => boolean)` ํ›…. ํฌ์ธํ„ฐ ๋‹ค์šด ์œ„์น˜์—์„œ ํผ์ง€๋Š” ๋ฌผ๊ฒฐ ํšจ๊ณผ. enabled/enableFn false ๋ฉด ๋น„ํ™œ์„ฑ. ๋ฒ„ํŠผ๋ฅ˜์— ๋ถ€์ฐฉ.
17
+ - **SdShowEffect** / **setupRevealOnShow** โ€” `[sdShowEffect]="enabled"` + `sdShowEffectType`("l2r"|"t2b", ๊ธฐ๋ณธ t2b) ๋””๋ ‰ํ‹ฐ๋ธŒ, ๋˜๋Š” `setupRevealOnShow(optFn?: () => { type?; enabled? })` ํ›…. ํ™”๋ฉด ์ง„์ž… ์‹œ ํŽ˜์ด๋“œ+์Šฌ๋ผ์ด๋“œ๋กœ ๋‚˜ํƒ€๋‚จ. type ์€ ์Šฌ๋ผ์ด๋“œ ๋ฐฉํ–ฅ(t2b=์œ„โ†’์•„๋ž˜, l2r=์™ผโ†’์˜ค). ์ง„์ž… ์• ๋‹ˆ๋ฉ”์ด์…˜์—.
18
+ - **SdInvalid** / **setupInvalid** โ€” `[sdInvalid]="message"` ๋””๋ ‰ํ‹ฐ๋ธŒ, ๋˜๋Š” `setupInvalid(getInvalidMessage: () => string)` ํ›…. ๋ฉ”์‹œ์ง€๊ฐ€ ๋นˆ ๋ฌธ์ž์—ด์ด ์•„๋‹ˆ๋ฉด ํ˜ธ์ŠคํŠธ ์ขŒ์ƒ๋‹จ์— ๋นจ๊ฐ„ ์  ํ‘œ์‹œ + ์ˆจ๊น€ input ์˜ `setCustomValidity` ๋กœ ํผ ๊ฒ€์ฆ ์—ฐ๋™(ํผ submit ์‹œ ๋ฉ”์‹œ์ง€ ๋…ธ์ถœ). ์ปค์Šคํ…€ ์ปจํŠธ๋กค์˜ ์œ ํšจ์„ฑ ํ‘œ์‹œ์—. (sd-textfield ๋“ฑ ๋‚ด์žฅ ์ปจํŠธ๋กค์ด ์ด๋ฏธ ์‚ฌ์šฉ)
19
+
20
+ ## ๊ธฐํƒ€ ์…‹์—… ํ›…ยท์œ ํ‹ธ
21
+
22
+ - **setupModelHook<T>(model, canFn: Signal<(item) => boolean | Promise<boolean>>)** โ€” model ์˜ set/update ๋ฅผ ๊ฐ€๋กœ์ฑ„ canFn ๊ฒฐ๊ณผ๊ฐ€ false ๋ฉด ๋ณ€๊ฒฝ ์ฐจ๋‹จ(Promise ๋ฉด ๋น„๋™๊ธฐ ํ—ˆ์šฉ). ์ฒดํฌ๋ฐ•์Šค/์Šค์œ„์น˜/๋ฆฌ์ŠคํŠธ ์„ ํƒ์˜ ๋ณ€๊ฒฝ ๊ฐ€๋“œ(`canChangeFn`)์— ์‚ฌ์šฉ.
23
+ - **setupBgTheme(options?: { theme?; lightness? })** โ€” body ๋ฐฐ๊ฒฝ์ƒ‰ CSS ๋ณ€์ˆ˜๋ฅผ ํ…Œ๋งˆ์ƒ‰์œผ๋กœ ์„ค์ •(์ปดํฌ๋„ŒํŠธ ํŒŒ๊ดด ์‹œ ๋ณต์›). theme = `"primary"|...|"gray"|"blue-gray"`, lightness = `"lightest"|"lighter"`(๊ธฐ๋ณธ lightest). ํ™”๋ฉด ๋ฐฐ๊ฒฝ ํ†ค ์ง€์ •์—.
24
+ - **setSafeStyle(renderer: Renderer2, el, style: Partial<CSSStyleDeclaration>)** โ€” Renderer2 ๋กœ ์—ฌ๋Ÿฌ ์Šคํƒ€์ผ ์ผ๊ด„ ์ ์šฉ. ๋””๋ ‰ํ‹ฐ๋ธŒ์—์„œ DOM ์Šคํƒ€์ผ ์ง์ ‘ ์กฐ์ž‘ ์‹œ.
25
+ - **mark(sig: WritableSignal<any>)** โ€” in-place ๋ณ€๊ฒฝ(๋ฐฐ์—ด push ๋“ฑ) ํ›„ shallow copy ์ƒˆ ์ฐธ์กฐ๋กœ set ํ•˜์—ฌ signal ์†Œ๋น„์ž์—๊ฒŒ ๋ณ€๊ฒฝ ํ†ต์ง€. ๋ฐฐ์—ด/๊ฐ์ฒด๋ฅผ ์ง์ ‘ ๋ณ€ํ˜•ํ–ˆ์„ ๋•Œ.
26
+
27
+ ## ํƒ€์ž…๋“œ ํ…œํ”Œ๋ฆฟ ๋””๋ ‰ํ‹ฐ๋ธŒ
28
+
29
+ - **SdTypedTemplate<T>** โ€” `<ng-template [typed]="typeToken" let-x="...">`. ng-template ์ปจํ…์ŠคํŠธ์— ํƒ€์ž…์„ ๋ถ€์—ฌ(ํƒ€์ž… ๊ฐ€๋“œ). ์žฌ๊ท€ ๋ฉ”๋‰ด ํ…œํ”Œ๋ฆฟ ๋“ฑ์—์„œ ์ปจํ…์ŠคํŠธ ํƒ€์ž… ๋ณด์žฅ์— ์‚ฌ์šฉ.
30
+ - **SdItemOfTemplate<TItem>** / **SdItemOfTemplateContext<TItem>** โ€” `<ng-template [itemOf]="items" let-item="item" let-index="index" let-depth="depth">`. ์ปจํ…์ŠคํŠธ `{ $implicit; item; index; depth }`. select/shared-data/calendar ๋“ฑ์ด ํ•ญ๋ชฉ ๋ Œ๋” ํ…œํ”Œ๋ฆฟ ๊ทœ์•ฝ์œผ๋กœ ์‚ฌ์šฉ.
31
+
32
+ ## SdOptionEventPlugin
33
+
34
+ `provideSdAngular` ๊ฐ€ ๋“ฑ๋กํ•˜๋Š” `EventManagerPlugin`. `.capture`/`.passive`/`.once` ์ ‘๋ฏธ ์ด๋ฒคํŠธ๋ฅผ ํ•ด์„. ์ง์ ‘ ์‚ฌ์šฉ ์•ˆ ํ•จ.
@@ -0,0 +1,40 @@
1
+ # @simplysm/angular โ€” ๊ธฐ๋Šฅ ์ปดํฌ๋„ŒํŠธ(์ฃผ์†Œ๊ฒ€์ƒ‰ยท์—๋””ํ„ฐยท์‹œ๊ฐํ™”ยท์นธ๋ฐ˜)
2
+
3
+ ํŠน์ • ๋„๋ฉ”์ธ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ๋…๋ฆฝ ์ปดํฌ๋„ŒํŠธ ๋ฌถ์Œ. ํ•„์š”ํ•œ ํ™”๋ฉด์—์„œ ๊ฐœ๋ณ„์ ์œผ๋กœ ๊ฐ€์ ธ๋‹ค ์”€.
4
+
5
+ ## ์ฃผ์†Œ ๊ฒ€์ƒ‰
6
+
7
+ - **SdAddressSearchModal** โ€” ๋‹ค์Œ(์นด์นด์˜ค) ์šฐํŽธ๋ฒˆํ˜ธ ๊ฒ€์ƒ‰ ๋ชจ๋‹ฌ ์ปดํฌ๋„ŒํŠธ. `SdModalContentDef<Address>` ๊ตฌํ˜„์ด๋ผ `SdModalProvider.showAsync({ type: SdAddressSearchModal, ... })` ๋กœ ๋„์›€. ์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ(daum postcode) ๋ฅผ ๋™์  ๋กœ๋“œ. `close = output<Address>()`.
8
+ - **Address** โ€” `{ postNumber: string | undefined; address: string | undefined; buildingName: string | undefined }`. ๊ฒฐ์ธก์€ undefined ๋ณด์กด.
9
+
10
+ ## ์—๋””ํ„ฐ
11
+
12
+ - **SdTiptapEditor** `<sd-tiptap-editor [(value)]="...">` โ€” tiptap ๊ธฐ๋ฐ˜ ๋ฆฌ์น˜ํ…์ŠคํŠธ ์—๋””ํ„ฐ(HTML ๋ฌธ์ž์—ด).
13
+ - value = model<string>() โ€” HTML ๋ณธ๋ฌธ.
14
+ - disabled/readonly/required: boolean โ€” ๋น„ํ™œ์„ฑ/์ฝ๊ธฐ์ „์šฉ/ํ•„์ˆ˜(๋นˆ ๊ฐ’ ๊ฒ€์ฆ).
15
+ - placeholder?: string.
16
+ - validatorFn?: (value) => string | undefined โ€” ์ปค์Šคํ…€ ๊ฒ€์ฆ ๋ฉ”์‹œ์ง€.
17
+ - extensions?: AnyExtension[] โ€” ์ถ”๊ฐ€ tiptap ํ™•์žฅ.
18
+
19
+ ## ์‹œ๊ฐํ™”
20
+
21
+ - **SdLabel** `<sd-label>` โ€” ์ž‘์€ ๋ฐฐ์ง€/ํƒœ๊ทธ. `theme`(8์ƒ‰), `color?: string`(์ž„์˜ ๋ฐฐ๊ฒฝ์ƒ‰), `clickable: boolean`(ํ˜ธ๋ฒ„ ๊ฐ•์กฐ + ์ปค์„œ).
22
+ - **SdNote** `<sd-note>` โ€” ์•ˆ๋‚ด ๋ฐ•์Šค. `theme`(8์ƒ‰), `size`("sm"|"lg"), `inset: boolean`.
23
+ - **SdProgress** `<sd-progress [theme]="..." [value]="...">` โ€” ์ง„ํ–‰๋ฅ  ๋ง‰๋Œ€. `theme: input.required`(8์ƒ‰), `value: input.required<number>`(0~1, ๋ฐฑ๋ถ„์œจ ํ‘œ์‹œยท๋ง‰๋Œ€ ํญ์€ 0~100% clamp), `size`("sm"|"lg"), `inset: boolean`.
24
+ - **SdCalendar<T>** `<sd-calendar [items]="..." [getItemDateFn]="...">` โ€” ์›”๊ฐ„ ๋‹ฌ๋ ฅ์— ํ•ญ๋ชฉ ๋ฐฐ์น˜.
25
+ - items: input.required<T[]>.
26
+ - getItemDateFn: input.required<(item, index) => DateOnly> โ€” ํ•ญ๋ชฉ์˜ ๋‚ ์งœ.
27
+ - yearMonth: input(๊ธฐ๋ณธ ์ด๋ฒˆ ๋‹ฌ 1์ผ) โ€” ํ‘œ์‹œ ์›”.
28
+ - weekStartDay: number(๊ธฐ๋ณธ 0=์ผ์š”์ผ) / minDaysInFirstWeek: number(๊ธฐ๋ณธ 1) โ€” ์ฃผ ์‹œ์ž‘ยท์ฒซ ์ฃผ ๊ธฐ์ค€.
29
+ - (contentChild) `itemOf` ํ…œํ”Œ๋ฆฟ ํ•„์ˆ˜ โ€” ๋‚ ์งœ ์นธ ํ•ญ๋ชฉ ๋ Œ๋”.
30
+ - **SdBarcode** `<sd-barcode [type]="..." [value]="...">` โ€” bwip-js ๋กœ ๋ฐ”์ฝ”๋“œ SVG ๋ Œ๋”. `type: input.required<BarcodeType>`(qrcode/code128/ean13 ๋“ฑ ๋‹ค์ˆ˜ โ€” `BarcodeType` ์œ ๋‹ˆ์˜จ ์ฐธ์กฐ), `value?: string`(๋นˆ ๊ฐ’์ด๋ฉด ๋ฏธํ‘œ์‹œ).
31
+ - **SdEcharts** `<sd-echarts [option]="...">` โ€” ECharts ์ฐจํŠธ. `option: input.required<echarts.EChartsOption>`, `notMerge: boolean`(๊ธฐ๋ณธ false, true ๋ฉด ์˜ต์…˜ ๋ณ‘ํ•ฉ ๋Œ€์‹  ๊ต์ฒด), `loading: boolean`(๋กœ๋”ฉ ์˜ค๋ฒ„๋ ˆ์ด).
32
+
33
+ ## ์นธ๋ฐ˜
34
+
35
+ - **SdKanbanBoard<L, T>** `<sd-kanban-board>` โ€” ์นธ๋ฐ˜ ๋ณด๋“œ ์ปจํ…Œ์ด๋„ˆ(๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ ์กฐ์œจ).
36
+ - selectedValues = model<T[]>([]) โ€” ์„ ํƒ๋œ ์นด๋“œ ๊ฐ’(Shift+ํด๋ฆญ ๋‹ค์ค‘ ์„ ํƒ).
37
+ - (output) drop: `SdKanbanBoardDropInfo<L,T>` = `{ sourceKanbanValue?; targetLaneValue?; targetKanbanValue? }` โ€” ๋“œ๋กญ ์‹œ ๋ฐœ์ƒ(์†Œ์Šค ์นด๋“œโ†’๋Œ€์ƒ ๋ ˆ์ธ/์นด๋“œ).
38
+ - **SdKanbanLane<L, T>** `<sd-kanban-lane [value]="...">` โ€” ๋ ˆ์ธ(์—ด). `value?: L`(๋ ˆ์ธ ์‹๋ณ„), `busy: boolean`, `useCollapse: boolean`(์ ‘๊ธฐ ๋ฒ„ํŠผ) + `collapse = model(false)`, `toolTpl`/`titleTpl`(๋„๊ตฌยท์ œ๋ชฉ ํ…œํ”Œ๋ฆฟ). ์ „์ฒด์„ ํƒ ์ฒดํฌ๋ฐ•์Šค(์„ ํƒ๊ฐ€๋Šฅ ์นด๋“œ ์žˆ์„ ๋•Œ).
39
+ - **SdKanban<L, T>** `<sd-kanban [value]="...">` โ€” ์นด๋“œ. `value?: T`, `selectable: boolean`(Shift+ํด๋ฆญ ์„ ํƒ ํ—ˆ์šฉ), `draggable: boolean`(๋“œ๋ž˜๊ทธ ํ—ˆ์šฉ), `contentClass?: string`. ๋“œ๋ž˜๊ทธ ์‹œ ๋‹ค๋ฅธ ์นด๋“œ/๋ ˆ์ธ ์œ„์— ๋“œ๋กญ ์œ„์น˜ ํ‘œ์‹œ.
40
+ - ํƒ€์ž…: **SdKanbanBoardDropInfo<L,T>**(์œ„), **SdKanbanDragRef<L,T>**(`{ value(); heightOnDrag() }`), **SdKanbanDropTarget<L,T>**(`{ targetLaneValue(); targetKanbanValue?() }`) โ€” ๋ณด๋“œ ๋‚ด๋ถ€ ๋“œ๋ž˜๊ทธ/๋“œ๋กญ ๋Œ€์ƒ ๊ทœ์•ฝ.
@@ -0,0 +1,74 @@
1
+ # @simplysm/angular โ€” ๋ถ€ํŠธ์ŠคํŠธ๋žฉยท์„ค์ •ยท๋กœ๊น…ยท์„œ๋น„์Šค ์ธํ”„๋ผ
2
+
3
+ ์•ฑ ์‹œ์ž‘ ์‹œ 1ํšŒ ์„ค์ •ํ•˜๋Š” ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ํ•จ์ˆ˜์™€ ์ „์—ญ ํ”„๋กœ๋ฐ”์ด๋” ๋ฌถ์Œ. ์•ฑ ๋ถ€ํŒ… ์ฝ”๋“œ(`appConfig`/`main.ts`)ยท์ „์—ญ ์—๋Ÿฌยท์„œ๋ฒ„ ์—ฐ๊ฒฐยท์‹œ์Šคํ…œ ์„ค์ • ์ €์žฅ์„ ๋‹ค๋ฃฐ ๋•Œ ํ•จ๊ป˜ ์ฝํž˜.
4
+
5
+ ## provideSdAngular
6
+
7
+ `provideSdAngular(opt: { clientName: string }): EnvironmentProviders` โ€” ์•ฑ `providers` ์— 1๊ฐœ ์ถ”๊ฐ€ํ•˜๋ฉด ๋‹ค์Œ์„ ์ผ๊ด„ ์„ค์ •. zoneless ๋ณ€๊ฒฝ๊ฐ์ง€ ํ™œ์„ฑ, ์ „์—ญ ์—๋Ÿฌ ํ•ธ๋“ค๋Ÿฌ(`SdGlobalErrorHandlerPlugin`) ๋“ฑ๋ก, ์˜ต์…˜ ์ด๋ฒคํŠธ ํ”Œ๋Ÿฌ๊ทธ์ธ(`SdOptionEventPlugin`) ๋“ฑ๋ก, ng-icons ๊ธฐ๋ณธ์„ค์ •(strokeWidth 1.5, size 1.33em), `IMAGE_CONFIG` ๊ฒฝ๊ณ  ๋น„ํ™œ์„ฑ, ํ…Œ๋งˆ dark/fontSize ๋ฅผ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€(`sd-theme-dark`/`sd-theme-font-size`)์— ์ž๋™ ์˜์†, service worker ์—…๋ฐ์ดํŠธ ํด๋ง(5๋ถ„~์ตœ๋Œ€1์‹œ๊ฐ„ ์ง€์ˆ˜ ๋ฐฑ์˜คํ”„, ๊ฐฑ์‹  ๊ฐ์ง€ ์‹œ ์ƒˆ๋กœ๊ณ ์นจ ํ™•์ธ), ๋ผ์šฐํ„ฐ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋™์•ˆ ๊ธ€๋กœ๋ฒŒ busy ์นด์šดํŠธ ์ฆ๊ฐ.
8
+
9
+ - opt.clientName: string โ€” ์ด ํด๋ผ์ด์–ธํŠธ ์‹๋ณ„์ž. ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€ ํ‚ค prefixยทservice-client ์—ฐ๊ฒฐ ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉ. ์•ฑ๋งˆ๋‹ค ๊ณ ์œ  ๋ฌธ์ž์—ด.
10
+
11
+ ```ts
12
+ bootstrapApplication(AppComponent, {
13
+ providers: [provideRouter(routes), provideSdAngular({ clientName: "my-app" })],
14
+ });
15
+ ```
16
+
17
+ ## SdAngularConfigProvider
18
+
19
+ `@Injectable({providedIn:"root"})`. `clientName: string` ํ•„๋“œ 1๊ฐœ. `provideSdAngular` ๊ฐ€ ์ฑ„์›Œ์คŒ. ๋‹ค๋ฅธ ํ”„๋กœ๋ฐ”์ด๋”๊ฐ€ clientName ์„ ์ฐธ์กฐํ•  ๋•Œ inject.
20
+
21
+ ## SdSystemLogProvider
22
+
23
+ ์ „์—ญ ๋กœ๊ทธ ๊ธฐ๋ก ํ”„๋กœ๋ฐ”์ด๋”. ์ฝ˜์†” ๋กœ๊ทธ + ์„ ํƒ์  ์„œ๋ฒ„ ์ „์†ก.
24
+
25
+ - writeFn?: (severity, ...data) => Promise<void> | void โ€” ์™ธ๋ถ€(์„œ๋ฒ„) ์ „์†ก ํ›…. ์ง€์ •ํ•˜๋ฉด ๋งค ๋กœ๊ทธ๋งˆ๋‹ค ํ˜ธ์ถœ. ์„œ๋ฒ„ ๋กœ๊ทธ ์ ์žฌ๊ฐ€ ํ•„์š”ํ•˜๋ฉด ์•ฑ ์ดˆ๊ธฐํ™” ๋•Œ ํ• ๋‹น.
26
+ - writeAsync(severity: "error"|"warn"|"log", ...data): Promise<void> โ€” ๋กœ๊ทธ ๊ธฐ๋ก. ์ฝ˜์†”์— ๋จผ์ € ์ถœ๋ ฅ ํ›„ writeFn ํ˜ธ์ถœ. writeFn ์ด throw ํ•ด๋„ ๋กœ๊น… ์ž์ฒด๋Š” ์‹คํŒจํ•˜์ง€ ์•Š์Œ(๋‚ด๋ถ€ logger.error ๋กœ ๊ธฐ๋ก).
27
+
28
+ ## SdLocalStorageProvider<T>
29
+
30
+ `clientName.<key>` ํ˜•ํƒœ๋กœ localStorage ์— JSON ์ €์žฅ/์กฐํšŒ. T ๋Š” `{ key: ๊ฐ’ํƒ€์ž… }` ๋งต.
31
+
32
+ - set<K>(key, value) โ€” JSON.stringify ํ›„ ์ €์žฅ.
33
+ - get<K>(key): T[K] | undefined โ€” ์—†๊ฑฐ๋‚˜ ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ undefined(๊ฒฐ์ธก ๋ณด์กด).
34
+ - remove(key) โ€” ์‚ญ์ œ.
35
+
36
+ ## SdSystemConfigProvider<T>
37
+
38
+ ํ™”๋ฉด๋ณ„ ์„ค์ •(์‹œํŠธ ์ปฌ๋Ÿผ ์ƒํƒœ, ๋ชจ๋‹ฌ ์œ„์น˜, ์ƒํƒœ ํ”„๋ฆฌ์…‹ ๋“ฑ) ์˜์† ํ”„๋กœ๋ฐ”์ด๋”. `fn` ๋ฏธ์ง€์ • ์‹œ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€๋กœ ํด๋ฐฑ.
39
+
40
+ - fn?: { set(key, data): Promise|void; get(key): PromiseLike<unknown> } โ€” ์„œ๋ฒ„ ์˜์† ํ›…. ์ง€์ •ํ•˜๋ฉด ์„œ๋ฒ„์— ์ €์žฅ/์กฐํšŒ, ๋ฏธ์ง€์ •์ด๋ฉด `SdLocalStorageProvider` ๋กœ ํด๋ฐฑ. ์„œ๋ฒ„ ๋™๊ธฐํ™”๊ฐ€ ํ•„์š”ํ•˜๋ฉด ์•ฑ ์ดˆ๊ธฐํ™” ๋•Œ ํ• ๋‹น.
41
+ - setAsync<K>(key, data) โ€” data ๊ฐ€ null ์ด๋ฉด ์ œ๊ฑฐ(ํด๋ฐฑ ์‹œ), ์•„๋‹ˆ๋ฉด ์ €์žฅ.
42
+ - getAsync(key) โ€” ์ €์žฅ๋œ ๊ฐ’ ์กฐํšŒ.
43
+
44
+ ## injectSdSystemConfigResource<T>
45
+
46
+ `injectSdSystemConfigResource<T>({ key: Signal<string|undefined> })` โ€” ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ํ˜ธ์ถœ. ํ˜ธ์ŠคํŠธ ์—˜๋ฆฌ๋จผํŠธ ํƒœ๊ทธ๋ช… + key ๋ฅผ ํ•ฉ์นœ ํ‚ค๋กœ `SdSystemConfigProvider` ์— ์—ฐ๋™๋˜๋Š” resource ํ•ธ๋“ค ๋ฐ˜ํ™˜. key ๊ฐ€ undefined ๋ฉด ๋กœ๋“œ/์ €์žฅ ์•ˆ ํ•จ.
47
+
48
+ - key: Signal<string|undefined> โ€” ์„ค์ • ํ‚ค signal. ๋นˆ ๊ฐ’์ด๋ฉด ๋น„ํ™œ์„ฑ.
49
+ - ๋ฐ˜ํ™˜: `{ value, isLoading, status, hasValue(), reload(), set(v), update(fn) }`. set/update ๋Š” ์ฆ‰์‹œ ๋กœ์ปฌ ๋ฐ˜์˜ ํ›„ microtask ๋กœ ๋น„๋™๊ธฐ ์˜์†(์‹คํŒจ ์‹œ errorHandler ๋กœ ์ „๋‹ฌ). ์‹œํŠธ/์ƒํƒœํ”„๋ฆฌ์…‹์ด ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉ.
50
+
51
+ ## SdServiceClientFactoryProvider
52
+
53
+ `@simplysm/service-client` ์—ฐ๊ฒฐ์„ key ๋‹จ์œ„๋กœ ๊ด€๋ฆฌํ•˜๋Š” ํŒฉํ† ๋ฆฌ. ์š”์ฒญ/์‘๋‹ต ์ง„ํ–‰๋ฅ ์„ ํ† ์ŠคํŠธ๋กœ ํ‘œ์‹œ.
54
+
55
+ - connectAsync(key: string, options?: Partial<ServiceConnectionOptions>): Promise<void> โ€” ์—ฐ๊ฒฐ ์ƒ์„ฑ. host/port/ssl ๋ฏธ์ง€์ • ์‹œ ํ˜„์žฌ location ๊ธฐ์ค€ ๊ธฐ๋ณธ๊ฐ’. ๊ฐ™์€ key ์žฌ์—ฐ๊ฒฐยท๋Š๊ธด key ์žฌ์‚ฌ์šฉ ์‹œ throw.
56
+ - closeAsync(key): Promise<void> โ€” ์—ฐ๊ฒฐ ์ข…๋ฃŒ. ๋ฏธ์—ฐ๊ฒฐ key ๋ฉด throw.
57
+ - get(key): ServiceClient โ€” ์—ฐ๊ฒฐ๋œ ํด๋ผ์ด์–ธํŠธ ๋ฐ˜ํ™˜. ๋ฏธ์—ฐ๊ฒฐ/๋Š๊น€์ด๋ฉด throw. ์„œ๋น„์Šค ํ˜ธ์ถœ ์‹œ ์ด๊ฑธ๋กœ ServiceClient ํš๋“.
58
+
59
+ ## SdGlobalErrorHandlerPlugin
60
+
61
+ `ErrorHandler` ๊ตฌํ˜„. `provideSdAngular` ๊ฐ€ ๋“ฑ๋กํ•˜๋ฏ€๋กœ ์ง์ ‘ ์“ธ ์ผ์€ ๋“œ๋ฌพ. ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ์—๋Ÿฌ/Promise ๊ฑฐ๋ถ€๋ฅผ ์‹œ์Šคํ…œ ๋กœ๊ทธ์— ๊ธฐ๋กํ•˜๊ณ  ์ „์ฒดํ™”๋ฉด ์˜ค๋ฅ˜ ์˜ค๋ฒ„๋ ˆ์ด๋ฅผ 1ํšŒ ํ‘œ์‹œ ํ›„ ์•ฑ์„ destroy(ํด๋ฆญ ์‹œ ์ƒˆ๋กœ๊ณ ์นจ). ์ง์ ‘ inject ํ•˜์ง€ ๋ง๊ณ  `throw` ๋กœ ์œ„์ž„.
62
+
63
+ ## SdThemeProvider
64
+
65
+ `@Injectable({providedIn:"root"})`. ๋‹คํฌ๋ชจ๋“œยทํฐํŠธํฌ๊ธฐ ์ „์—ญ ์ƒํƒœ.
66
+
67
+ - dark: WritableSignal<boolean> โ€” ๋‹คํฌ๋ชจ๋“œ. true ๋ฉด body ์— `sd-theme-dark` ํด๋ž˜์Šค ํ† ๊ธ€.
68
+ - fontSize: WritableSignal<number> โ€” ๋ฃจํŠธ ํฐํŠธ ํฌ๊ธฐ(px). ๋ณ€๊ฒฝ ์‹œ `documentElement.style.fontSize` ๋ฐ˜์˜.
69
+ - fontSizePresets: readonly number[] โ€” `[12,14,16,20,24,28]`. ์ฆ๊ฐ ๋‹จ๊ณ„.
70
+ - increaseFontSize() / decreaseFontSize() โ€” ํ”„๋ฆฌ์…‹ ๋‚ด ๋‹ค์Œ/์ด์ „ ๋‹จ๊ณ„๋กœ ์ด๋™.
71
+
72
+ ## SdThemeSelector
73
+
74
+ `<sd-theme-selector />` โ€” ํฐํŠธํฌ๊ธฐ ์ฆ๊ฐยท๋‹คํฌ๋ชจ๋“œ ์Šค์œ„์น˜๋ฅผ ๋“œ๋กญ๋‹ค์šด์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ. input ์—†์Œ. `SdThemeProvider` ๋ฅผ ์ง์ ‘ ์กฐ์ž‘. ํƒ‘๋ฐ” ๋“ฑ์— ๋ฐฐ์น˜.
@@ -0,0 +1,27 @@
1
+ # @simplysm/angular โ€” ๋ ˆ์ด์•„์›ƒ(์‚ฌ์ด๋“œ๋ฐ”ยทํƒ‘๋ฐ”)
2
+
3
+ ํ™”๋ฉด ๊ณจ๊ฒฉ์„ ๋งŒ๋“œ๋Š” ์‚ฌ์ด๋“œ๋ฐ”ยทํƒ‘๋ฐ” ์ปดํฌ๋„ŒํŠธ ๋ฌถ์Œ. ๋ฉ”๋‰ด ๋ฐ์ดํ„ฐ๋Š” `SdMenu`(routing-appstructure.md ์ฐธ์กฐ) ๋˜๋Š” ์ž์ฒด ๋ฉ”๋‰ด ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉ.
4
+
5
+ ## ์‚ฌ์ด๋“œ๋ฐ”
6
+
7
+ - **SdSidebarContainer** `<sd-sidebar-container>` โ€” ์‚ฌ์ด๋“œ๋ฐ” + ๋ณธ๋ฌธ ๋ ˆ์ด์•„์›ƒ ์ปจํ…Œ์ด๋„ˆ. input ์—†์Œ. `toggle: WritableSignal<boolean>`(์ ‘ํž˜ ์ƒํƒœ, ๋ชจ๋ฐ”์ผ์€ backdrop ํ‘œ์‹œ). ๋ผ์šฐํ„ฐ ๋„ค๋น„๊ฒŒ์ด์…˜ ์‹œ์ž‘ ์‹œ ์ž๋™ ์ ‘ํž˜. ์ž์‹์œผ๋กœ `sd-sidebar` ์™€ ๋ณธ๋ฌธ์„ ๋‘ .
8
+ - **SdSidebar** `<sd-sidebar>` โ€” ์‚ฌ์ด๋“œ๋ฐ” ํŒจ๋„. input ์—†์Œ(์ปจํ…Œ์ด๋„ˆ์˜ toggle ์„ ๋”ฐ๋ฆ„). ์ขŒ์ธก ๊ณ ์ •, ๋ชจ๋ฐ”์ผ์—์„œ ์˜ค๋ฒ„๋ ˆ์ด.
9
+ - **SdSidebarMenu** `<sd-sidebar-menu>` โ€” ๋ฉ”๋‰ด ํŠธ๋ฆฌ ๋ Œ๋”. `menus = input<SdMenu[]>([])`, `layout`("accordion"|"flat" โ€” ๋ฏธ์ง€์ • ์‹œ ์ตœ์ƒ์œ„ 3๊ฐœ ์ดํ•˜๋ฉด flat, ์•„๋‹ˆ๋ฉด accordion), `getMenuIsSelectedFn`(์„ ํƒ ํŒ์ • ์ปค์Šคํ…€). leaf ๋Š” `sdRouterLink` ๋กœ ์ด๋™, `menu.url` ์žˆ์œผ๋ฉด ์ƒˆ ์ฐฝ.
10
+ - **SdSidebarUser** `<sd-sidebar-user>` โ€” ์‚ฌ์šฉ์ž ์˜์—ญ + ์ ‘์ด์‹ ๋ฉ”๋‰ด. `userMenu = input<SdSidebarUserMenu>()`. ํˆฌ์˜ ๋‚ด์šฉ(ํ”„๋กœํ•„) + ํด๋ฆญ ์‹œ ํŽผ์ณ์ง€๋Š” ๋ฉ”๋‰ด ๋ชฉ๋ก. ํƒ€์ž… `SdSidebarUserMenu = { title: string; menus: { title; onClick }[] }`.
11
+
12
+ ```html
13
+ <sd-sidebar-container>
14
+ <sd-sidebar>
15
+ <sd-sidebar-user [userMenu]="userMenu">{{ userName }}</sd-sidebar-user>
16
+ <sd-sidebar-menu [menus]="appStructure.usableMenus()" />
17
+ </sd-sidebar>
18
+ <router-outlet />
19
+ </sd-sidebar-container>
20
+ ```
21
+
22
+ ## ํƒ‘๋ฐ”
23
+
24
+ - **SdTopbarContainer** `<sd-topbar-container>` โ€” ํƒ‘๋ฐ” + ๋ณธ๋ฌธ ์„ธ๋กœ ๋ ˆ์ด์•„์›ƒ. input ์—†์Œ.
25
+ - **SdTopbar** `<sd-topbar>` โ€” ์ƒ๋‹จ ๋ฐ”. `sidebarContainer = input<SdSidebarContainer>()`(๋ฏธ์ง€์ • ์‹œ ์ฃผ์ž…๋œ ์ปจํ…Œ์ด๋„ˆ ์ž๋™ ์‚ฌ์šฉ). ์‚ฌ์ด๋“œ๋ฐ”๊ฐ€ ์žˆ์œผ๋ฉด ์ขŒ์ธก ํ† ๊ธ€(ํ–„๋ฒ„๊ฑฐ) ๋ฒ„ํŠผ ํ‘œ์‹œ. ์ œ๋ชฉยท๋„๊ตฌ๋Š” ํˆฌ์˜.
26
+ - **SdTopbarMenu** `<sd-topbar-menu>` โ€” ๋“œ๋กญ๋‹ค์šดํ˜• ์ƒ๋‹จ ๋ฉ”๋‰ด ํŠธ๋ฆฌ. `menus = input<SdMenu[]>([])`, `getMenuIsSelectedFn`. ์ตœ์ƒ์œ„ ๋ฉ”๋‰ด๋ณ„ ๋“œ๋กญ๋‹ค์šด, leaf ํด๋ฆญ ์‹œ ์ด๋™ยท๋“œ๋กญ๋‹ค์šด ๋‹ซํž˜.
27
+ - **SdTopbarUser** `<sd-topbar-user>` โ€” ์‚ฌ์šฉ์ž ๋“œ๋กญ๋‹ค์šด ๋ฉ”๋‰ด. `menus = input.required<SdTopbarUserMenu[]>()`. ํˆฌ์˜ ๋‚ด์šฉ(์ด๋ฆ„) ํด๋ฆญ ์‹œ ๋ฉ”๋‰ด ๋ชฉ๋ก. ํƒ€์ž… `SdTopbarUserMenu = { title: string; onClick: () => void }`.
@@ -0,0 +1,103 @@
1
+ # @simplysm/angular โ€” ๋ชจ๋‹ฌยทํ† ์ŠคํŠธยทBusyยท์ธ์‡„ (์˜ค๋ฒ„๋ ˆ์ด)
2
+
3
+ ํ™”๋ฉด ์œ„์— ๋„์šฐ๋Š” ํ”ผ๋“œ๋ฐฑยท์˜ค๋ฒ„๋ ˆ์ด ๋ฌถ์Œ. ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ๋ชจ๋‹ฌ/ํ† ์ŠคํŠธ๋ฅผ ๋„์šฐ๊ฑฐ๋‚˜ ์ž‘์—… ์ง„ํ–‰ ํ‘œ์‹œ, ํ™”๋ฉด ์ธ์‡„/PDF ๊ฐ€ ํ•„์š”ํ•  ๋•Œ ํ•จ๊ป˜ ์ฝํž˜.
4
+
5
+ ## SdModalProvider
6
+
7
+ `@Injectable({providedIn:"root"})`. ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ชจ๋‹ฌ๋กœ ๋™์  ์ƒ์„ฑ.
8
+
9
+ - showAsync<T>(modal: SdModalInfo<T>, options?: SdModalOptions): Promise<close๊ฒฐ๊ณผ | undefined> โ€” ๋ชจ๋‹ฌ ํ‘œ์‹œ. ์ปจํ…์ธ  ์ปดํฌ๋„ŒํŠธ์˜ `close.emit(result)` ์‹œ result ๋กœ resolve, ๋ฐฐ๊ฒฝํด๋ฆญ/ESC/๋‹ซ๊ธฐ๋ฒ„ํŠผ ์‹œ undefined ๋กœ resolve. ์ฒซ ํƒญ ๊ฐ€๋Šฅ ์ปจํŠธ๋กค์— ์ž๋™ ํฌ์ปค์Šค.
10
+ - modalCount: Signal<number> โ€” ํ˜„์žฌ ์—ด๋ฆฐ ๋ชจ๋‹ฌ ์ˆ˜.
11
+
12
+ `SdModalInfo<T, X>` = `{ title: string; type: Type<T>; inputs: ... }`. inputs ๋Š” ์ปจํ…์ธ  ์ปดํฌ๋„ŒํŠธ์˜ input ์ค‘ `initialized`/`close`/`actionTplRef`/`_optionalModalInputs` ์™€ X ๋กœ ์ง€์ •ํ•œ ํ‚ค๋ฅผ ์ œ์™ธํ•œ ๊ฒƒ. `_optionalModalInputs` ๋กœ ์„ ์–ธํ•œ ํ‚ค๋Š” optional.
13
+
14
+ `SdModalContentDef<O>` โ€” ๋ชจ๋‹ฌ ์ปจํ…์ธ  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ตฌํ˜„ํ•  ์ธํ„ฐํŽ˜์ด์Šค:
15
+ - initialized: Signal<boolean> โ€” ์ดˆ๊ธฐํ™” ์™„๋ฃŒ ์‹ ํ˜ธ(์ธ์‡„/๋Œ€๊ธฐ ๋™๊ธฐํ™”์— ์‚ฌ์šฉ).
16
+ - close: OutputEmitterRef<O | undefined> โ€” ๊ฒฐ๊ณผ emit. O ๊ฐ€ ๋ชจ๋‹ฌ ๋ฐ˜ํ™˜ ํƒ€์ž….
17
+ - actionTplRef?: TemplateRef โ€” ํ—ค๋” ์šฐ์ธก ์•ก์…˜ ์˜์—ญ์— ํˆฌ์˜ํ•  ํ…œํ”Œ๋ฆฟ(์žˆ์œผ๋ฉด ๋ชจ๋‹ฌ ํ—ค๋”๋กœ ๋ธŒ๋ฆฟ์ง€๋จ).
18
+ - _optionalModalInputs?: string โ€” optional ๋กœ ๋‘˜ input ํ‚ค๋“ค์˜ ์œ ๋‹ˆ์˜จ ํƒ€์ž… ํ‘œ์‹(๋Ÿฐํƒ€์ž„ ๊ฐ’ ์•„๋‹˜).
19
+
20
+ `SdModalOptions`:
21
+ - key?: string โ€” ์ง€์ • ์‹œ ํฌ๊ธฐยท์œ„์น˜๋ฅผ `SdSystemConfigProvider` ์— ์˜์†(`sd-modal.<key>`).
22
+ - hideHeader?: boolean โ€” ํ—ค๋”(์ œ๋ชฉยท๋‹ซ๊ธฐ๋ฒ„ํŠผ) ์ˆจ๊น€.
23
+ - hideCloseButton?: boolean โ€” ์šฐ์ƒ๋‹จ ๋‹ซ๊ธฐ ๋ฒ„ํŠผ๋งŒ ์ˆจ๊น€.
24
+ - headerStyle?: string โ€” ํ—ค๋” ์ธ๋ผ์ธ ์Šคํƒ€์ผ.
25
+ - useCloseByBackdrop?: boolean โ€” ๋ฐฐ๊ฒฝ ํด๋ฆญ์œผ๋กœ ๋‹ซ๊ธฐ ํ—ˆ์šฉ(๊ธฐ๋ณธ true). ์ž…๋ ฅ ํ™•์ธ ๋ชจ๋‹ฌ์ด๋ฉด false.
26
+ - useCloseByEscapeKey?: boolean โ€” ESC ๋กœ ๋‹ซ๊ธฐ ํ—ˆ์šฉ(๊ธฐ๋ณธ true).
27
+ - float?: boolean โ€” ๋ฐฐ๊ฒฝ(backdrop) ์—†์ด ๋–  ์žˆ๋Š” ๋ชจ๋‹ฌ. ๋น„์ฐจ๋‹จ ํŒจ๋„์ด๋ฉด true.
28
+ - fill?: boolean โ€” ํ™”๋ฉด ๊ฐ€๋“ ์ฑ„์›€(์ „์ฒดํ™”๋ฉด ๋ชจ๋‹ฌ).
29
+ - resizable?: boolean โ€” 8๋ฐฉํ–ฅ ๋ฆฌ์‚ฌ์ด์ฆˆ ํ•ธ๋“ค ํ‘œ์‹œ.
30
+ - movable?: boolean โ€” ํ—ค๋” ๋“œ๋ž˜๊ทธ๋กœ ์ด๋™.
31
+ - position?: "bottom-right" | "top-right" โ€” ๊ณ ์ • ์œ„์น˜(์•Œ๋ฆผํ˜• ๋ชจ๋‹ฌ).
32
+ - minHeightPx/minWidthPx/heightPx/widthPx?: number โ€” ์ตœ์†Œยท์ดˆ๊ธฐ ํฌ๊ธฐ(px).
33
+ - noFirstControlFocusing?: boolean โ€” ์ฒซ ์ปจํŠธ๋กค ์ž๋™ ํฌ์ปค์Šค ๋น„ํ™œ์„ฑ(๋‹ค์ด์–ผ๋กœ๊ทธ ์ž์ฒด์— ํฌ์ปค์Šค).
34
+
35
+ ```ts
36
+ const result = await sdModal.showAsync(
37
+ { title: "์‚ฌ์šฉ์ž ์„ ํƒ", type: UserSelectModal, inputs: { teamId } },
38
+ { resizable: true, key: "user-select" },
39
+ );
40
+ ```
41
+
42
+ ## SdModal
43
+
44
+ `<sd-modal>` โ€” `SdModalProvider` ๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ์…ธ ์ปดํฌ๋„ŒํŠธ. ์ง์ ‘ ํ…œํ”Œ๋ฆฟ์— ์“ฐ๊ธฐ๋ณด๋‹ค provider ๊ฒฝ์œ  ๊ถŒ์žฅ. ์œ„ `SdModalOptions` ์™€ ๋™์ผํ•œ input ๋“ค + `open = model(false)`, `closeRequest = output<void>()`, `title`/`actionTplRef` input ๋ณด์œ .
45
+
46
+ ## SdActivatedModalProvider
47
+
48
+ ๋ชจ๋‹ฌ ์ปจํ…์ธ  ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ inject. ํ˜„์žฌ ๋ชจ๋‹ฌ ์ œ์–ด.
49
+ - modalComponent: Signal<SdModal | undefined> / contentComponent: Signal<T | undefined>.
50
+ - canDeactivateFn: () => boolean โ€” ๋‹ซ๊ธฐ ์ฐจ๋‹จ ํŒ์ •. `setupCanDeactivate` ๊ฐ€ ์„ค์ •. true ๊ฐ€ ์•„๋‹ˆ๋ฉด ๋ฐฐ๊ฒฝ/ESC/๋ฒ„ํŠผ ๋‹ซ๊ธฐ ๋ฌด์‹œ.
51
+
52
+ ## SdPromptModal / SdConfirmModal
53
+
54
+ provider ์— ๋ฐ”๋กœ ๋„˜๊ธธ ์ˆ˜ ์žˆ๋Š” ๋ฒ”์šฉ ๋ชจ๋‹ฌ ์ปดํฌ๋„ŒํŠธ.
55
+ - SdPromptModal: `SdModalContentDef<string>`. `message = input.required<string>()`. ํ…์ŠคํŠธ ์ž…๋ ฅ(ํ•„์ˆ˜) ํ›„ ํ™•์ธ ์‹œ ์ž…๋ ฅ๊ฐ’, ์ทจ์†Œ ์‹œ undefined emit.
56
+ - SdConfirmModal: `SdModalContentDef<boolean>`. `message = input.required<string>()`. ํ™•์ธ ์‹œ `true`, ์ทจ์†Œ ์‹œ undefined emit.
57
+
58
+ ```ts
59
+ const name = await sdModal.showAsync({ title: "์ด๋ฆ„", type: SdPromptModal, inputs: { message: "์ด๋ฆ„?" } });
60
+ ```
61
+
62
+ ## SdToastProvider
63
+
64
+ `@Injectable({providedIn:"root"})`. ํ† ์ŠคํŠธ ์•Œ๋ฆผ.
65
+
66
+ - info/success/warning/danger(message: string, useProgress?: boolean) โ€” ์‹ฌ๊ฐ๋„๋ณ„ ํ† ์ŠคํŠธ. useProgress=true ๋ฉด ์ง„ํ–‰๋ฅ  ํ† ์ŠคํŠธ๊ฐ€ ๋˜์–ด `WritableSignal<number>`(0~100) ๋ฐ˜ํ™˜, 100 ๋„๋‹ฌ 1์ดˆ ๋’ค ์ž๋™ ํ•ด์ œ. useProgress ์—†๊ฑฐ๋‚˜ false ๋ฉด 3์ดˆ ํ›„ ์ž๋™ ํ•ด์ œ(ํ˜ธ๋ฒ„ ์ค‘ ์ง€์—ฐ), ๋ฐ˜ํ™˜ void.
67
+ - notify<T>(input: SdToastInput<T>): Promise<close๊ฒฐ๊ณผ | undefined> โ€” ์ปค์Šคํ…€ ์ปดํฌ๋„ŒํŠธ ํ† ์ŠคํŠธ. `SdToastInput<T>` = `{ type: Type<T>; inputs }`(์ปจํ…์ธ ๋Š” `SdToastContentDef<O>` = `{ close: OutputEmitterRef<O|undefined> }` ๊ตฌํ˜„). 5์ดˆ ํ›„ ์ž๋™ ํ•ด์ œ.
68
+ - try<R>(fn, messageFn?): Promise<R | undefined> โ€” fn ์‹คํ–‰ ์ค‘ Error ๋ฐœ์ƒ ์‹œ danger ํ† ์ŠคํŠธ + ์‹œ์Šคํ…œ๋กœ๊ทธ ๊ธฐ๋ก ํ›„ undefined ๋ฐ˜ํ™˜(Error ์•„๋‹Œ throw ๋Š” ์žฌthrow). ํ™”๋ฉด ์•ก์…˜ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๊ฐ์‹ธ๋Š” ํ‘œ์ค€ ํŒจํ„ด.
69
+ - alertThemes: WritableSignal<SdToastSeverity[]> โ€” ์ด ์‹ฌ๊ฐ๋„๋“ค์€ ํ† ์ŠคํŠธ ๋Œ€์‹  `window.alert`.
70
+ - overlap: WritableSignal<boolean> โ€” true ๋ฉด ์ƒˆ ํ† ์ŠคํŠธ๊ฐ€ ๊ธฐ์กด ํ† ์ŠคํŠธ ๋ชจ๋‘ ์ œ๊ฑฐ ํ›„ ํ‘œ์‹œ(๊ฒน์นจ ๋ฐฉ์ง€).
71
+ - beforeShowFn?: (theme) => void โ€” ํ† ์ŠคํŠธ ํ‘œ์‹œ ์ง์ „ ์ฝœ๋ฐฑ(์˜ˆ: ์‚ฌ์šด๋“œ).
72
+
73
+ ํƒ€์ž…: `SdToastSeverity = "info"|"success"|"warning"|"danger"`, `SdToastTheme = "primary"|"secondary"|SdToastSeverity|"gray"|"blue-gray"`.
74
+
75
+ ```ts
76
+ await sdToast.try(async () => { await save(); sdToast.success("์ €์žฅ๋จ"); });
77
+ ```
78
+
79
+ ## SdToast / SdToastContainer
80
+
81
+ `SdToastProvider` ๊ฐ€ ๋‚ด๋ถ€ ์ƒ์„ฑ. ์ง์ ‘ ์“ธ ์ผ ๋“œ๋ฌพ. SdToast: `open`/`progress`/`message` model, `useProgress`/`theme` input, severity ์— ๋”ฐ๋ผ `role`/`aria-live` ์ž๋™(infoยทsuccess=status/polite, warningยทdanger=alert/assertive). SdToastContainer: `overlap` input.
82
+
83
+ ## SdBusyProvider
84
+
85
+ `@Injectable({providedIn:"root"})`. ์ „์—ญ ๋กœ๋”ฉ ํ‘œ์‹œ.
86
+ - globalBusyCount: WritableSignal<number> โ€” >0 ์ด๋ฉด ์ „์—ญ busy ์˜ค๋ฒ„๋ ˆ์ด ํ‘œ์‹œ(๋ผ์šฐํŒ…ยท์ธ์‡„๊ฐ€ ์ž๋™ ์ฆ๊ฐ). ์ง์ ‘ ์ž‘์—… ๊ฐ์Œ€ ๋•Œ update ๋กœ ์ฆ๊ฐ.
87
+ - type: WritableSignal<SdBusyType> โ€” ๊ธฐ๋ณธ ํ‘œ์‹œ ์œ ํ˜•. `SdBusyType = "spinner"|"bar"|"cube"`.
88
+
89
+ ## SdBusyContainer
90
+
91
+ `<sd-busy-container [busy]="..." />` โ€” ์˜์—ญ ๋‹จ์œ„ busy ์˜ค๋ฒ„๋ ˆ์ด. ๋‚ด๋ถ€ ์ปจํ…์ธ  ์œ„์— ํ‘œ์‹œ.
92
+ - busy: boolean โ€” true ๋ฉด ์˜ค๋ฒ„๋ ˆ์ด ํ‘œ์‹œ + ์˜์—ญ ๋‚ด ํ‚ค์ž…๋ ฅ ์ฐจ๋‹จ.
93
+ - message?: string โ€” ํ‘œ์‹œ ๋ฉ”์‹œ์ง€.
94
+ - type?: "spinner"|"bar"|"cube" โ€” ๋ฏธ์ง€์ • ์‹œ `SdBusyProvider.type` ์‚ฌ์šฉ.
95
+ - progressPercent?: number โ€” ์ง€์ • ์‹œ ์ƒ๋‹จ ์ง„ํ–‰ ๋ฐ” ํ‘œ์‹œ(0~100).
96
+
97
+ ## SdPrintProvider
98
+
99
+ `@Injectable({providedIn:"root"})`. ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ธ์‡„/PDF ๋กœ ๋ Œ๋”.
100
+ - printAsync<T>(template: SdPrintInput<T>, options?: { size?: string; margin?: string }): Promise<void> โ€” ์ปดํฌ๋„ŒํŠธ๋ฅผ body ์— ์ž„์‹œ ๋ Œ๋” ํ›„ `window.print()`. size ๊ธฐ๋ณธ `"A4 auto"`, margin ๊ธฐ๋ณธ `"0"`. ์ธ์‡„ ๋™์•ˆ ๊ธ€๋กœ๋ฒŒ busy.
101
+ - getPdfBufferAsync<T>(template, options?: { orientation?: "portrait"|"landscape"; pageSize?: string }): Promise<Uint8Array> โ€” `.page` ์—˜๋ฆฌ๋จผํŠธ๋ณ„๋กœ ์บ”๋ฒ„์Šค ๋ณ€ํ™˜(jsPDF) ํ›„ PDF ๋ฒ„ํผ ๋ฐ˜ํ™˜. pageSize ๊ธฐ๋ณธ `"a4"`, orientation ๊ธฐ๋ณธ portrait.
102
+
103
+ `SdPrintInput<T, X>` = `{ type: Type<T>; inputs }`. ์ปจํ…์ธ ๋Š” `SdPrint`(= `{ initialized: Signal<boolean>; _optionalPrintInputs?: string }`) ๊ตฌํ˜„. `initialized()` ๊ฐ€ true ๊ฐ€ ๋˜๊ณ  ์ด๋ฏธ์ง€ ๋กœ๋“œ ์™„๋ฃŒ๊นŒ์ง€ ๋Œ€๊ธฐ ํ›„ ์ธ์‡„.
@@ -0,0 +1,69 @@
1
+ # @simplysm/angular โ€” ๋ผ์šฐํŒ… / ์•ฑ ๊ตฌ์กฐ(๋ฉ”๋‰ดยท๊ถŒํ•œ)
2
+
3
+ ํ˜„์žฌ ํŽ˜์ด์ง€ ์‹๋ณ„ยท๋ทฐ ์ œ๋ชฉ/ํƒ€์ž… ํŒ์ •, ๋ผ์šฐํ„ฐ ๋งํฌ, ์•ฑ ๋ฉ”๋‰ด/๊ถŒํ•œ ํŠธ๋ฆฌ ๊ตฌ์„ฑ์„ ๋‹ค๋ฃฐ ๋•Œ ํ•จ๊ป˜ ์ฝํž˜. ์•ฑ ๊ตฌ์กฐ ๋ฐ์ดํ„ฐ ์›๋ณธ์€ `@simplysm/service-common` ์˜ `AppStructureItem`.
4
+
5
+ ## injectFullPageCodeSignal
6
+
7
+ `injectFullPageCodeSignal(): Signal<string>` โ€” ํ˜„์žฌ ๋ผ์šฐํ„ฐ URL ์—์„œ ์•ž 2 ์„ธ๊ทธ๋จผํŠธ(`/home` ๋“ฑ)๋ฅผ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€๋ฅผ `.` ์œผ๋กœ ์ด์€ ํŽ˜์ด์ง€ ์ฝ”๋“œ. ๋„ค๋น„๊ฒŒ์ด์…˜ ์ข…๋ฃŒ๋งˆ๋‹ค ๊ฐฑ์‹ . ๋ฉ”๋‰ด ์„ ํƒ ํ‘œ์‹œยท๋ทฐ ์ œ๋ชฉ ์กฐํšŒ์— ์‚ฌ์šฉ.
8
+
9
+ ## injectCurrentPageCodeSignal
10
+
11
+ `injectCurrentPageCodeSignal(): Signal<string> | undefined` โ€” ํ˜„์žฌ `ActivatedRoute` ์˜ pathFromRoot ๊ธฐ์ค€ ์ฝ”๋“œ(์ค‘์ฒฉ outlet/๋ชจ๋‹ฌ ์•ˆ์—์„œ ์ž๊ธฐ ์ž์‹  ๊ฒฝ๋กœ). ActivatedRoute ์—†์œผ๋ฉด undefined. fullPageCode ์™€ ๋น„๊ตํ•ด page/control ํŒ์ •์— ์‚ฌ์šฉ.
12
+
13
+ ## injectViewTitleSignal
14
+
15
+ `injectViewTitleSignal(): Signal<string>` โ€” ๋ชจ๋‹ฌ ์•ˆ์ด๋ฉด ๋ชจ๋‹ฌ ์ œ๋ชฉ, ์•„๋‹ˆ๋ฉด ์•ฑ ๊ตฌ์กฐ์—์„œ ํ˜„์žฌ ํŽ˜์ด์ง€ ์ฝ”๋“œ๋กœ ์ฐพ์€ ์ œ๋ชฉ(`[์ƒ์œ„ > ์ƒ์œ„] ํ˜„์žฌ`). ๋ชป ์ฐพ์œผ๋ฉด `""`. ํ™”๋ฉด ์ปจํ…Œ์ด๋„ˆ ์ œ๋ชฉ ํ‘œ์‹œ์— ์‚ฌ์šฉ.
16
+
17
+ ## injectViewTypeSignal
18
+
19
+ `injectViewTypeSignal(): Signal<SdViewType>` โ€” ํ˜„์žฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ด๋–ค ๋งฅ๋ฝ์œผ๋กœ ๋–  ์žˆ๋Š”์ง€ ํŒ์ •. `SdViewType = "page"|"modal"|"control"`. ๋ชจ๋‹ฌ ์•ˆ์ด๋ฉด "page"๊ฐ€ ์•„๋‹Œ "modal", ๋ผ์šฐํŠธ์˜ ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ๋กœ ์ง์ ‘ ๋–  ์žˆ๊ณ  fullPageCode===currPageCode ๋ฉด "page", ๊ทธ ์™ธ "control"(๋‹ค๋ฅธ ํ™”๋ฉด์— ๋ฐ•ํžŒ ์žฌ์‚ฌ์šฉ ์ปดํฌ๋„ŒํŠธ). CRUD ์ปจํ…Œ์ด๋„ˆ์˜ `viewType` input ์— ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ.
20
+
21
+ ## setupCanDeactivate
22
+
23
+ `setupCanDeactivate(fn: () => boolean): void` โ€” ์ปดํฌ๋„ŒํŠธ ๋‚ด ํ˜ธ์ถœ. ๋ชจ๋‹ฌ ์•ˆ์ด๋ฉด `SdActivatedModalProvider.canDeactivateFn` ์—, ๋ผ์šฐํŠธ๋ฉด ํ•ด๋‹น route ์˜ `canDeactivate` ๊ฐ€๋“œ์— fn ์„ ๋“ฑ๋ก(์ปดํฌ๋„ŒํŠธ ํŒŒ๊ดด ์‹œ ํ•ด์ œ). fn ์ด false ๋ฉด ์ดํƒˆ/๋‹ซ๊ธฐ ์ฐจ๋‹จ. ๋ฏธ์ €์žฅ ๋ณ€๊ฒฝ ๋ณดํ˜ธ์— ์‚ฌ์šฉ.
24
+
25
+ ```ts
26
+ setupCanDeactivate(() => !this.dirty() || confirm("์ €์žฅํ•˜์ง€ ์•Š๊ณ  ๋‚˜๊ฐˆ๊นŒ์š”?"));
27
+ ```
28
+
29
+ ## SdRouterLink
30
+
31
+ `[sdRouterLink]="option"` ๋””๋ ‰ํ‹ฐ๋ธŒ. ํด๋ฆญ ์‹œ option ์œผ๋กœ ๋ผ์šฐํ„ฐ ์ด๋™(๋˜๋Š” ์ƒˆ ์ฐฝ).
32
+ - option: `{ link: string; params?; window?: {width?;height?}; outletName?: string; queryParams? } | undefined` โ€” undefined ๋ฉด ๋™์ž‘ ์—†์Œ(์ปค์„œ๋„ ๊ธฐ๋ณธ). ํ˜„์žฌ๊ฐ€ window ๋ชจ๋“œ๊ฑฐ๋‚˜ Ctrl/Shift+ํด๋ฆญ์ด๋ฉด ์ƒˆ ์ฐฝ์œผ๋กœ, outletName ์žˆ์œผ๋ฉด named outlet ์œผ๋กœ ์ด๋™. Alt+ํด๋ฆญ์€ ๋ฌด์‹œ.
33
+
34
+ ## SdNavigateWindowProvider
35
+
36
+ `@Injectable({providedIn:"root"})`. ์ƒˆ ์ฐฝ/ํŒ์—… ๋„ค๋น„๊ฒŒ์ด์…˜.
37
+ - isWindow: boolean โ€” ํ˜„์žฌ URL ํ•ด์‹œ์— `window=true` ๊ฐ€ ์žˆ๋Š”์ง€(ํŒ์—…์œผ๋กœ ์—ด๋ฆฐ ์ฐฝ์ธ์ง€).
38
+ - open(navigate: string, params?, features?): void โ€” window ๋ชจ๋“œ๊ฑฐ๋‚˜ features ์ง€์ • ์‹œ `window.open` ํŒ์—…(๋‹ซํž ๋•Œ ๋ถ€๋ชจ์™€ ํ•จ๊ป˜ ์ •๋ฆฌ), ์•„๋‹ˆ๋ฉด `_blank` ํƒญ.
39
+
40
+ ## getMenuRouterLinkOption / getIsMenuSelected
41
+
42
+ - `getMenuRouterLinkOption(menu: SdMenu): { link; queryParams } | undefined` โ€” leaf ๋ฉ”๋‰ด(children/url ์—†์Œ)๋ฉด `/home/<์ฝ”๋“œ์ฒด์ธ>` ๋งํฌ + ์ฟผ๋ฆฌํŒŒ๋ผ๋ฏธํ„ฐ ์˜ต์…˜, ๊ทธ ์™ธ undefined. `SdRouterLink` ์— ๋ฐ”๋กœ ์ „๋‹ฌ.
43
+ - `getIsMenuSelected(menu, fullPageCode, customFn?): boolean` โ€” customFn ์žˆ์œผ๋ฉด ๊ทธ ๊ฒฐ๊ณผ, ์—†์œผ๋ฉด `fullPageCode === menu.codeChain.join(".")`. ๋ฉ”๋‰ด ์„ ํƒ ๊ฐ•์กฐ์— ์‚ฌ์šฉ.
44
+
45
+ ## SdAppStructureProvider<TModule>
46
+
47
+ `@Injectable({providedIn:"root"})`. ์•ฑ ๋ฉ”๋‰ดยท๊ถŒํ•œ ํŠธ๋ฆฌ์˜ ๋‹จ์ผ ์†Œ์Šค.
48
+ - usableModules: Signal<TModule[]|undefined> โ€” ํ™œ์„ฑ ๋ชจ๋“ˆ ๋ชฉ๋ก. ๋ฉ”๋‰ด/๊ถŒํ•œ ํ•„ํ„ฐ์— ์‚ฌ์šฉ(๋ฏธ์„ค์ • ์‹œ ์ „์ฒด ํ—ˆ์šฉ ์ทจ๊ธ‰).
49
+ - permRecord: Signal<Record<string,boolean>|undefined> โ€” `<์ฝ”๋“œ>.<๊ถŒํ•œํ‚ค>` โ†’ ํ—ˆ์šฉ ์—ฌ๋ถ€ ๋งต.
50
+ - items: Signal<AppStructureItem<TModule>[]> โ€” ๊ตฌ์กฐ ์›๋ณธ.
51
+ - initialize(items) โ€” ๊ตฌ์กฐ ์ฃผ์ž….
52
+ - usableMenus: Signal<SdMenu[]> โ€” ๋ชจ๋“ˆยท๊ถŒํ•œ ํ†ต๊ณผํ•œ ๋ฉ”๋‰ด ํŠธ๋ฆฌ(์‚ฌ์ด๋“œ๋ฐ”/ํƒ‘๋ฐ”์šฉ).
53
+ - usableFlatMenus: Signal<SdFlatMenu<TModule>[]> โ€” ํ‰ํƒ„ํ™”๋œ ๋ฉ”๋‰ด ๋ชฉ๋ก.
54
+ - getPermissionsByStructure(items, codeChain?) โ€” ๊ถŒํ•œ ํŽธ์ง‘ํ‘œ์šฉ `SdPermission` ํŠธ๋ฆฌ ์ƒ์„ฑ.
55
+ - getTitleByFullCode(fullCode) / findTitleByFullCode(fullCode) โ€” ์ „์ž๋Š” ๋ชป ์ฐพ์œผ๋ฉด throw, ํ›„์ž๋Š” undefined(๊ฒฐ์ธก ๋ณด์กด).
56
+ - getItemChainByFullCode(fullCode) โ€” ์ฝ”๋“œ ์ฒด์ธ์— ํ•ด๋‹นํ•˜๋Š” ํ•ญ๋ชฉ ๋ฐฐ์—ด(์—†์œผ๋ฉด ๋นˆ ๋ฐฐ์—ด).
57
+ - getPermsByFullCode(fullCodes, permKeys) โ€” ํ•ด๋‹น ์ฝ”๋“œ๋“ค์—์„œ ๋ณด์œ ํ•œ ๊ถŒํ•œ ํ‚ค ๋ชฉ๋ก.
58
+
59
+ `injectPermsSignal<K>(viewCodes: string[], keys: K[]): Signal<K[]>` โ€” ํ˜„์žฌ ๋ณด์œ  ๊ถŒํ•œ ํ‚ค๋ฅผ computed signal ๋กœ. ํ™”๋ฉด์—์„œ ํŽธ์ง‘/์‚ฌ์šฉ ๊ถŒํ•œ ๋ถ„๊ธฐ์— ์‚ฌ์šฉ.
60
+
61
+ ## SdAppStructureUtils
62
+
63
+ `abstract class`. `SdAppStructureProvider` ๊ฐ€ ๋‚ด๋ถ€ ์‚ฌ์šฉํ•˜๋Š” ์ •์  ์œ ํ‹ธ ๋ชจ์Œ(์ง์ ‘ ํ˜ธ์ถœ ๊ฐ€๋Šฅ): `getMenus`/`getFlatMenus`/`getPermissions`/`getFlatPermissions`/`getTitleByFullCode`/`findTitleByFullCode`/`getItemChainByFullCode`/`getPermsByFullCode`. ์‹œ๊ทธ๋‹ˆ์ฒ˜๋Š” provider ๋ฉ”์„œ๋“œ์™€ ๋Œ€์‘(์ถ”๊ฐ€๋กœ items/usableModules/permRecord ๋ฅผ ์ธ์ž๋กœ ๋ฐ›์Œ).
64
+
65
+ ## ํƒ€์ž…
66
+
67
+ - **SdMenu** โ€” `{ title; codeChain: string[]; url?; icon?; children?: SdMenu[] }`. ๋ฉ”๋‰ด ํŠธ๋ฆฌ ๋…ธ๋“œ.
68
+ - **SdFlatMenu<TModule>** โ€” `{ titleChain: string[]; codeChain: string[]; modulesChain: TModule[][] }`. ํ‰ํƒ„ ๋ฉ”๋‰ด.
69
+ - **SdPermission<TModule>** โ€” `{ title; codeChain; modules; perms: ("use"|"edit")[]|undefined; children }`. ๊ถŒํ•œ ํŠธ๋ฆฌ ๋…ธ๋“œ(๊ถŒํ•œํ‘œ ์ž…๋ ฅ).
@@ -0,0 +1,28 @@
1
+ # @simplysm/angular โ€” ์„ ํƒยท์ •๋ ฌยทํ™•์žฅ ๋งค๋‹ˆ์ €(use* ์ปดํฌ์ €๋ธ”)
2
+
3
+ ์ปค์Šคํ…€ ๋ฆฌ์ŠคํŠธ/๊ทธ๋ฆฌ๋“œ ์ปดํฌ๋„ŒํŠธ์— ์„ ํƒยท์ •๋ ฌยทํŠธ๋ฆฌ ํ™•์žฅ ๋กœ์ง์„ ๋ถ™์ด๋Š” ํ•จ์ˆ˜ํ˜• ์ปดํฌ์ €๋ธ”. signal ๋ฐ”์ธ๋”ฉ์„ ๋„˜๊ธฐ๋ฉด ํŒŒ์ƒ signal ๊ณผ ์กฐ์ž‘ ๋ฉ”์„œ๋“œ๋ฅผ ๋Œ๋ ค์คŒ. `sd-sheet` ๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ ์ด๋“ค์„ ์กฐํ•ฉํ•จ.
4
+
5
+ ## useSelectionManager<TItem, TKey>
6
+
7
+ ๋‹ค์ค‘/๋‹จ์ผ ์„ ํƒ ์ƒํƒœ ๊ด€๋ฆฌ.
8
+ - options: `{ displayItems: Signal<TItem[]>; selectedKeys: WritableSignal<TKey[]>; selectMode: Signal<"single"|"multi"|undefined>; getItemSelectableFn: Signal<((item) => boolean|string)|undefined>; trackByFn: Signal<(item,index) => TKey> }` โ€” selectMode ๋ฏธ์ง€์ •์ด๋ฉด ์„ ํƒ ๋น„ํ™œ์„ฑ, getItemSelectableFn ์ด string ๋ฐ˜ํ™˜ ์‹œ ๊ทธ ์‚ฌ์œ ๋กœ ๋ถˆ๊ฐ€, trackByFn ์œผ๋กœ ํ‚ค ๋น„๊ต(`obj.equal` ๊นŠ์€ ๋น„๊ต).
9
+ - ๋ฐ˜ํ™˜: `hasSelectable`/`isAllSelected`(Signal), `getSelectable(item): true|string|undefined`, `getCanChangeFn(item)`, `select`/`deselect`/`toggle`/`toggleAll`/`isSelected`. single ์€ 1๊ฐœ๋กœ ๊ต์ฒด, multi ๋Š” ๋ˆ„์ .
10
+
11
+ ## useSortingManager
12
+
13
+ ํ—ค๋” ํด๋ฆญ ์ •๋ ฌ ์ƒํƒœ + ์ •๋ ฌ ์‹คํ–‰.
14
+ - options: `{ sorts: WritableSignal<SortingDef[]> }`.
15
+ - ๋ฐ˜ํ™˜: `defMap: Signal<Map<key, { indexText?; desc }>>`(๋‹ค์ค‘ ์ •๋ ฌ ์‹œ ์ˆœ๋ฒˆ ํ‘œ์‹œ), `toggle(key, multiple)`(๋‹จ์ผ/๋‹ค์ค‘ ํ† ๊ธ€: ์—†์Œโ†’์˜ค๋ฆ„์ฐจ์ˆœโ†’๋‚ด๋ฆผ์ฐจ์ˆœโ†’ํ•ด์ œ ์ˆœํ™˜), `sort<T>(items): T[]`(null ์€ ์•ž, ๋ฌธ์ž์—ด localeCompare, ์ˆซ์ž ์ฐจ์ด ๊ธฐ์ค€).
16
+ - **SortingDef** โ€” `{ key: string; desc: boolean }`. ์ •๋ ฌ 1๊ฑด.
17
+
18
+ ## useExpandingManager<T>
19
+
20
+ ํŠธ๋ฆฌ ํŽผ์นจ ์ƒํƒœ + ๊ฐ€์‹œ ํ•ญ๋ชฉ ํ‰ํƒ„ํ™”.
21
+ - binding: `{ items: Signal<T[]>; expandedItems: WritableSignal<T[]>; getChildrenFn: Signal<((item,index) => T[]|undefined)|undefined>; sort: (items) => T[] }` โ€” getChildrenFn ์œผ๋กœ ์ž์‹ ์กฐํšŒ, sort ๋กœ ๊ฐ ๋ ˆ๋ฒจ ์ •๋ ฌ.
22
+ - ๋ฐ˜ํ™˜: `displayItems`/`hasExpandable`/`isAllExpanded`(Signal), `toggle(item)`/`toggleAll()`, `isVisible(item)`(์กฐ์ƒ์ด ๋ชจ๋‘ ํŽผ์ณ์กŒ๋Š”์ง€), `def(item): ExpandItemDef<T>`(๋ชป ์ฐพ์œผ๋ฉด throw).
23
+ - **ExpandItemDef<T>** โ€” `{ item; parentDef: ExpandItemDef<T>|undefined; hasChildren; depth }`. ํ•ญ๋ชฉ์˜ ํŠธ๋ฆฌ ์œ„์น˜ ์ •์˜.
24
+
25
+ ```ts
26
+ const sorting = useSortingManager({ sorts });
27
+ const selection = useSelectionManager({ displayItems, selectedKeys, selectMode, getItemSelectableFn, trackByFn });
28
+ ```