@simplysm/sd-claude 14.0.81 → 14.0.83

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 (87) hide show
  1. package/claude/references/sd-requirement-source-handling.md +20 -20
  2. package/claude/references/sd-simplysm14/README.md +13 -13
  3. package/claude/references/sd-simplysm14/manuals/client-component.md +92 -92
  4. package/claude/references/sd-simplysm14/manuals/client-crud.md +11 -11
  5. package/claude/references/sd-simplysm14/manuals/client-demo.md +28 -28
  6. package/claude/references/sd-simplysm14/manuals/client-rules.md +1 -1
  7. package/claude/references/sd-simplysm14/manuals/client-setup.md +21 -21
  8. package/claude/references/sd-simplysm14/manuals/client-tab.md +3 -3
  9. package/claude/references/sd-simplysm14/manuals/logging.md +15 -15
  10. package/claude/references/sd-simplysm14/manuals/orm-union.md +6 -6
  11. package/claude/references/sd-simplysm14/manuals/orm.md +19 -19
  12. package/claude/references/sd-simplysm14/manuals/test.md +33 -33
  13. package/claude/rules/sd-base-rules.md +44 -43
  14. package/claude/rules/sd-design-rules.md +18 -18
  15. package/claude/skills/sd-commit/SKILL.md +10 -10
  16. package/claude/skills/sd-config/SKILL.md +2 -2
  17. package/claude/skills/sd-demo/SKILL.md +45 -45
  18. package/claude/skills/sd-dev/SKILL.md +15 -15
  19. package/claude/skills/sd-docs/SKILL.md +7 -7
  20. package/claude/skills/sd-docs/references/subagent-prompt.md +33 -33
  21. package/claude/skills/sd-impl/SKILL.md +60 -60
  22. package/claude/skills/sd-review/SKILL.md +9 -9
  23. package/claude/skills/sd-skill/SKILL.md +74 -74
  24. package/claude/skills/sd-skill/evals/fixtures/existing-skill/.claude/skills/todo-format/SKILL.md +1 -1
  25. package/claude/skills/sd-spec/SKILL.md +355 -319
  26. package/claude/skills/sd-spec/references/example-spec.md +104 -104
  27. package/claude/skills/sd-unpack/SKILL.md +34 -34
  28. package/claude/skills/sd-use/SKILL.md +4 -4
  29. package/package.json +1 -1
  30. package/claude/references/sd-simplysm14/apis/angular/README.md +0 -37
  31. package/claude/references/sd-simplysm14/apis/angular/app-structure.md +0 -92
  32. package/claude/references/sd-simplysm14/apis/angular/buttons.md +0 -88
  33. package/claude/references/sd-simplysm14/apis/angular/crud.md +0 -100
  34. package/claude/references/sd-simplysm14/apis/angular/forms.md +0 -200
  35. package/claude/references/sd-simplysm14/apis/angular/infrastructure.md +0 -231
  36. package/claude/references/sd-simplysm14/apis/angular/kanban.md +0 -80
  37. package/claude/references/sd-simplysm14/apis/angular/layout.md +0 -92
  38. package/claude/references/sd-simplysm14/apis/angular/modal.md +0 -115
  39. package/claude/references/sd-simplysm14/apis/angular/routing.md +0 -107
  40. package/claude/references/sd-simplysm14/apis/angular/select-dropdown.md +0 -35
  41. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +0 -82
  42. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +0 -134
  43. package/claude/references/sd-simplysm14/apis/angular/sheet.md +0 -127
  44. package/claude/references/sd-simplysm14/apis/angular/toast.md +0 -97
  45. package/claude/references/sd-simplysm14/apis/angular/visual.md +0 -167
  46. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +0 -79
  47. package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +0 -83
  48. package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +0 -91
  49. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +0 -49
  50. package/claude/references/sd-simplysm14/apis/core-browser/README.md +0 -143
  51. package/claude/references/sd-simplysm14/apis/core-common/README.md +0 -58
  52. package/claude/references/sd-simplysm14/apis/core-common/extensions.md +0 -88
  53. package/claude/references/sd-simplysm14/apis/core-common/features.md +0 -51
  54. package/claude/references/sd-simplysm14/apis/core-common/types.md +0 -88
  55. package/claude/references/sd-simplysm14/apis/core-common/utils.md +0 -189
  56. package/claude/references/sd-simplysm14/apis/core-node/README.md +0 -12
  57. package/claude/references/sd-simplysm14/apis/core-node/consola.md +0 -59
  58. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +0 -44
  59. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +0 -42
  60. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +0 -53
  61. package/claude/references/sd-simplysm14/apis/core-node/pathx.md +0 -24
  62. package/claude/references/sd-simplysm14/apis/core-node/worker.md +0 -65
  63. package/claude/references/sd-simplysm14/apis/excel/README.md +0 -193
  64. package/claude/references/sd-simplysm14/apis/lint/README.md +0 -94
  65. package/claude/references/sd-simplysm14/apis/orm-common/README.md +0 -58
  66. package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +0 -77
  67. package/claude/references/sd-simplysm14/apis/orm-common/executable.md +0 -20
  68. package/claude/references/sd-simplysm14/apis/orm-common/expr.md +0 -92
  69. package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +0 -98
  70. package/claude/references/sd-simplysm14/apis/orm-common/schema-builders.md +0 -128
  71. package/claude/references/sd-simplysm14/apis/orm-node/README.md +0 -69
  72. package/claude/references/sd-simplysm14/apis/sd-claude/README.md +0 -32
  73. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +0 -80
  74. package/claude/references/sd-simplysm14/apis/sd-cli/sd-config.md +0 -155
  75. package/claude/references/sd-simplysm14/apis/service-client/README.md +0 -131
  76. package/claude/references/sd-simplysm14/apis/service-common/README.md +0 -29
  77. package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +0 -63
  78. package/claude/references/sd-simplysm14/apis/service-common/messages.md +0 -56
  79. package/claude/references/sd-simplysm14/apis/service-common/protocol.md +0 -64
  80. package/claude/references/sd-simplysm14/apis/service-common/service-types.md +0 -43
  81. package/claude/references/sd-simplysm14/apis/service-server/README.md +0 -13
  82. package/claude/references/sd-simplysm14/apis/service-server/auth.md +0 -39
  83. package/claude/references/sd-simplysm14/apis/service-server/builtin-services.md +0 -71
  84. package/claude/references/sd-simplysm14/apis/service-server/define-service.md +0 -55
  85. package/claude/references/sd-simplysm14/apis/service-server/internals.md +0 -82
  86. package/claude/references/sd-simplysm14/apis/service-server/server.md +0 -57
  87. package/claude/references/sd-simplysm14/apis/storage/README.md +0 -71
@@ -1,115 +0,0 @@
1
- # @simplysm/angular — modal
2
-
3
- `SdModalProvider.showAsync` 로 프로그래밍 호출, 또는 `<sd-modal>` 컴포넌트 직접 배치.
4
-
5
- ## SdModalProvider (root)
6
-
7
- ```ts
8
- modalCount: WritableSignal<number>;
9
- showAsync<T extends SdModalContentDef<any>>(modal: SdModalInfo<T>, options?: SdModalOptions): Promise<O|undefined>;
10
-
11
- interface SdModalContentDef<O> {
12
- initialized: Signal<boolean>;
13
- close: OutputEmitterRef<O|undefined>;
14
- actionTplRef?: TemplateRef<any>;
15
- readonly _optionalModalInputs?: string; // type-level marker, optional inputs 이름 union
16
- }
17
-
18
- interface SdModalInfo<T, X = ""> {
19
- title: string;
20
- type: Type<T>;
21
- inputs: ...; // T 의 InputSignal prop 들 (close/initialized 등 제외, _optionalModalInputs 마킹 prop 은 optional)
22
- }
23
-
24
- interface SdModalOptions {
25
- key?: string; hideHeader?: boolean; hideCloseButton?: boolean;
26
- headerStyle?: string;
27
- useCloseByBackdrop?: boolean; useCloseByEscapeKey?: boolean;
28
- float?: boolean; fill?: boolean;
29
- resizable?: boolean; movable?: boolean;
30
- position?: "bottom-right"|"top-right";
31
- minHeightPx?: number; minWidthPx?: number;
32
- heightPx?: number; widthPx?: number;
33
- noFirstControlFocusing?: boolean;
34
- }
35
- ```
36
-
37
- - `showAsync` — 컴포넌트 동적 생성·body 부착·열림 애니메이션·포커스 캡처. 컨텐츠 컴포넌트가 `close.emit(result)` 또는 배경/ESC/닫기버튼으로 `closeRequest` 발화하면 close 진행, Promise 가 result 로 resolve(취소는 undefined).
38
- - `modalCount` — 동시 열린 모달 수. 키보드 이벤트 핸들러 등에서 활용.
39
- - `SdModalContentDef.initialized` — 모달 컴포넌트가 자기 준비 끝났을 때 `true` 로 set. `SdPrintProvider` 등은 이걸 기다림(`SdModalProvider` 는 직접 사용 안 함).
40
- - `SdModalContentDef.actionTplRef` — 모달 헤더 우측 추가 액션 영역에 띄울 `TemplateRef`. set 하면 자동으로 `<sd-modal>` 의 `actionTplRef` 로 브릿지.
41
- - `_optionalModalInputs` — `SdModalInfo.inputs` 의 일부 prop 을 optional 로 만들 때 사용하는 type-level 마커(`= "fieldA" | "fieldB"`). 런타임 값 없음.
42
- - `SdModalOptions` 필드별:
43
- - `key` — 지정 시 `SdSystemConfigProvider` 키 `sd-modal.<key>` 로 width/height/left/top 자동 저장·복원.
44
- - `hideHeader`/`hideCloseButton` — 헤더 영역 전체/닫기 버튼만 숨김.
45
- - `headerStyle` — 헤더 인라인 style 문자열.
46
- - `useCloseByBackdrop`/`useCloseByEscapeKey` — 기본 true. false 면 배경 클릭/ESC 무시.
47
- - `float` — true 면 배경 어둡지 않고 그림자만(비차단 플로팅).
48
- - `fill` — true 면 전체 화면. 헤더 투명·테두리 없음.
49
- - `resizable` — true 면 8방향 리사이즈 핸들.
50
- - `movable` — true 면 헤더 드래그로 이동.
51
- - `position` — `bottom-right`/`top-right` 절대 배치. 미지정 = 상단 가운데.
52
- - `minWidthPx`/`minHeightPx`/`widthPx`/`heightPx` — 사이즈 제약·고정.
53
- - `noFirstControlFocusing` — true 면 첫 탭가능 요소가 아니라 dialog 박스 자체에 포커스.
54
-
55
- ```ts
56
- const result = await sdModal.showAsync({ title: "직원선택", type: EmpSelectModal, inputs: {} }, { resizable: true, key: "emp-select" });
57
- ```
58
-
59
- ## SdModal — `<sd-modal>`
60
-
61
- `SdModalProvider` 가 내부에서 사용. 직접 템플릿에 두려면:
62
-
63
- ```ts
64
- open = model(false); key = input<string|undefined>();
65
- title = input(""); hideHeader = input(false); hideCloseButton = input(false);
66
- headerStyle = input<string|undefined>();
67
- useCloseByBackdrop = input(true); useCloseByEscapeKey = input(true);
68
- float = input(false); fill = input(false);
69
- resizable = input(false); movable = input(false);
70
- position = input<"bottom-right"|"top-right"|undefined>();
71
- minHeightPx/minWidthPx/heightPx/widthPx = input<number|undefined>();
72
- actionTplRef = input<TemplateRef<any>|undefined>();
73
- closeRequest = output<void>();
74
- ```
75
-
76
- - 의미는 위 `SdModalOptions` 와 1:1. `closeRequest` 발화 시 부모가 `open.set(false)` 책임.
77
-
78
- ## SdActivatedModalProvider (inject inside modal content)
79
-
80
- ```ts
81
- modalComponent: WritableSignal<SdModal|undefined>;
82
- contentComponent: WritableSignal<T|undefined>;
83
- canDeactivateFn: () => boolean; // 닫기 차단 시 false 반환
84
- ```
85
-
86
- - 컨텐츠 컴포넌트 내부에서 `inject(SdActivatedModalProvider)` 로 자기 모달 참조 가져오기. `canDeactivateFn` 을 함수로 덮어쓰면 ESC/배경/닫기버튼이 false 시 닫힘 차단(저장 안된 변경 사항 보호 패턴).
87
- - `setupCanDeactivate(fn)` 헬퍼가 이걸 set 함 ([routing.md](./routing.md)).
88
-
89
- ## SdPromptModal / SdConfirmModal (사전 정의 컨텐츠)
90
-
91
- ```ts
92
- class SdPromptModal implements SdModalContentDef<string> { message = input.required<string>(); }
93
- class SdConfirmModal implements SdModalContentDef<boolean> { message = input.required<string>(); }
94
- ```
95
-
96
- - 확인 시 prompt 는 입력값, confirm 은 `true` emit. 취소는 둘 다 `undefined`.
97
-
98
- ```ts
99
- const input = await sdModal.showAsync({ title: "입력", type: SdPromptModal, inputs: { message: "이름?" } });
100
- const ok = await sdModal.showAsync({ title: "확인", type: SdConfirmModal, inputs: { message: "삭제할까요?" } });
101
- ```
102
-
103
- ## SelectModalOutputResult<TKey>
104
-
105
- ```ts
106
- interface SelectModalOutputResult<TKey = any> { selectedKeys: TKey[]; }
107
- ```
108
-
109
- - `SdModalSelectButton`/`SdSharedDataSelect*` 가 선택 모달을 호출할 때 모달이 emit 할 표준 출력 형태.
110
-
111
- ## 주의
112
-
113
- - 컨텐츠 컴포넌트가 `close.emit(value)` 를 호출해야 Promise 가 resolve. 닫기 버튼/ESC/배경 클릭은 `closeRequest` → `undefined` resolve.
114
- - 컨텐츠 안에 `<ng-template #actionTpl>...</ng-template>` 두고 컴포넌트 클래스에서 `actionTplRef = viewChild('actionTpl')` 한 뒤 set 하면 헤더 액션 영역 표시됨.
115
- - `resizable`/`movable`/`key` 조합 시 사용자 조정 사이즈·위치가 `sd-modal.<key>` 키로 `SdSystemConfigProvider` 에 저장됨.
@@ -1,107 +0,0 @@
1
- # @simplysm/angular — routing
2
-
3
- Angular Router 위에 페이지 코드(`a.b.c` 점 표기)·뷰 타입·새창 네비게이션 헬퍼.
4
-
5
- ## SdRouterLink — `[sdRouterLink]` (Directive)
6
-
7
- ```ts
8
- option = input<{
9
- link: string;
10
- params?: Record<string, string>;
11
- window?: { width?: number; height?: number }; // 새창 띄울 때 크기
12
- outletName?: string;
13
- queryParams?: Record<string, string>;
14
- } | undefined>(undefined, { alias: "sdRouterLink" });
15
- ```
16
-
17
- - click 처리. `Alt+click` 무시(브라우저 기본 다운로드 거동 보존). 새창 모드(`SdNavigateWindowProvider.isWindow=true` 또는 `Ctrl/Shift+click`)면 `window.open` 으로 새창 띄움. 일반 모드면 `Router.navigate`.
18
- - `link` — 라우터 경로. `window` 옵션 지정 시 width/height (기본 800x800) 으로 새창.
19
- - `outletName` — 보조 outlet 라우팅용. 미지정 시 primary.
20
- - `params`/`queryParams` — 라우터 매트릭스 파라미터/쿼리 파라미터.
21
-
22
- ```html
23
- <sd-anchor [sdRouterLink]="{ link: '/home/sales/invoice', params: { id: '1' } }">송장</sd-anchor>
24
- ```
25
-
26
- ## SdNavigateWindowProvider (root)
27
-
28
- ```ts
29
- get isWindow: boolean; // 현재 URL hash 의 ;window=true 여부
30
- open(navigate: string, params?: Record<string, string>, features?: string): void;
31
- ```
32
-
33
- - 현재 창이 simplysm 새창 모드인지 판단(`location.hash` 의 `;window=true`).
34
- - `open` — 새창이거나 `features` 가 주어지면 `window.open(... features)`. 일반 모드면 `_blank` 탭. 부모창 close 시 자식들도 일괄 종료.
35
-
36
- ## injectCurrentPageCodeSignal
37
-
38
- ```ts
39
- function injectCurrentPageCodeSignal(): Signal<string> | undefined
40
- ```
41
-
42
- - `ActivatedRoute.pathFromRoot.slice(2)` 의 url segments 를 `.` 으로 join. 라우터 컨텍스트 없으면 undefined.
43
- - 예: `/home/sales/invoice` → `"sales.invoice"`.
44
-
45
- ## injectFullPageCodeSignal
46
-
47
- ```ts
48
- function injectFullPageCodeSignal(): Signal<string>
49
- ```
50
-
51
- - `Router.events` 의 NavigationEnd → URL → segment 2개부터 `.` join. matrix/query 제거.
52
- - "전체 페이지 코드" 로 메뉴 선택 상태 판정에 사용.
53
-
54
- ## injectViewTitleSignal
55
-
56
- ```ts
57
- function injectViewTitleSignal(): Signal<string>
58
- ```
59
-
60
- - 모달 안이면 `SdActivatedModalProvider.modalComponent().title()`.
61
- - 그 외엔 `SdAppStructureProvider.getTitleByFullCode(currentPageCode ?? fullPageCode)`.
62
- - 페이지/모달 상단에 표시할 제목.
63
-
64
- ## injectViewTypeSignal
65
-
66
- ```ts
67
- function injectViewTypeSignal(): Signal<SdViewType>;
68
- type SdViewType = "page" | "modal" | "control";
69
- ```
70
-
71
- - `page`: 라우터 진입 페이지 컴포넌트, `modal`: 모달 컨텐츠, `control`: 그 외(다른 컴포넌트의 자식). 컴포넌트가 자기 컨텍스트별로 다르게 그릴 때.
72
-
73
- ## setupCanDeactivate
74
-
75
- ```ts
76
- function setupCanDeactivate(fn: () => boolean): void
77
- ```
78
-
79
- - 모달 안: `SdActivatedModalProvider.canDeactivateFn = fn` 으로 ESC/배경/닫기 차단.
80
- - 라우터 페이지: route config 에 `CanDeactivate` 가드 추가(컴포넌트 파괴 시 자동 제거).
81
- - 저장 안된 변경 사항 보호용.
82
-
83
- ```ts
84
- setupCanDeactivate(() => !isDirty() || confirm("변경 사항이 있습니다. 나가시겠습니까?"));
85
- ```
86
-
87
- ## getMenuRouterLinkOption
88
-
89
- ```ts
90
- function getMenuRouterLinkOption(menu: SdMenu): { link: string; queryParams: Record<string, string>|undefined } | undefined
91
- ```
92
-
93
- - leaf 메뉴(`children` 도 `url` 도 없음)만 결과 반환. 그룹/외부URL 메뉴는 undefined.
94
- - 반환 link 는 `/home/<codeChain join "/">`. 마지막 segment 에 `?key=val` 포함 시 분리해 queryParams 로.
95
-
96
- ## getIsMenuSelected
97
-
98
- ```ts
99
- function getIsMenuSelected(menu: SdMenu, fullPageCode: string|undefined, customFn?: (menu) => boolean): boolean
100
- ```
101
-
102
- - 커스텀 함수 있으면 그것 사용. 없으면 `fullPageCode === menu.codeChain.join(".")`.
103
-
104
- ## 주의
105
-
106
- - 페이지 코드는 `/home/` 다음의 segment 들 `.` join. 라우터를 이 컨벤션에 맞춰 설계해야 메뉴 선택 표시·뷰 타이틀 자동 동작.
107
- - `SdRouterLink` 의 `link` 는 라우터 절대경로 또는 상대경로. `link` 에 `?queryString` 직접 쓰지 말고 `queryParams` 객체로 분리.
@@ -1,35 +0,0 @@
1
- # @simplysm/angular — select-dropdown
2
-
3
- ## `<sd-dropdown>` / `<sd-dropdown-popup>`
4
-
5
- ```html
6
- <sd-dropdown [(open)]="open" [disabled]="false">
7
- trigger 컨텐츠
8
- <sd-dropdown-popup>팝업 컨텐츠</sd-dropdown-popup>
9
- </sd-dropdown>
10
- ```
11
-
12
- - `open` 시 popup을 body로 이동(트리거 위치 기준 배치). 모바일(`max-width:520px`)이면 backdrop+bottom sheet.
13
- - 트리거 클릭/Enter/ArrowDown 으로 open.
14
-
15
- ## `<sd-select<M extends "single"|"multi", T>>`
16
-
17
- ```html
18
- <sd-select [items]="items" [(value)]="value" [selectMode]="'single'" [trackByFn]="byId">
19
- <sd-select-item *ngFor="let it of items" [value]="it.id">{{ it.name }}</sd-select-item>
20
- </sd-select>
21
- ```
22
-
23
- `SelectModeValue<T> = { single: T; multi: T[] }`. value type = `SelectModeValue<T>[M]`.
24
-
25
- 주요 input: `selectMode`, `value` (model), `placeholder`, `disabled`, `inline`, `inset`, `size`, `required`, `hideSelectAll`, `multiSelectionDisplayDirection: "vertical"`, `items`, `trackByFn`, `getChildrenFn` (트리), `contentClass/Style`, `dropdownOpen` (model).
26
-
27
- `<ng-template #headerTpl>`, `<ng-template #beforeTpl>`, `<ng-template itemOf>` (`SdItemOfTemplate`) 으로 커스터마이즈.
28
-
29
- ## `<sd-select-item<T> [value]>`
30
-
31
- projected content 가 옵션 라벨.
32
-
33
- ## `<sd-select-button>`
34
-
35
- 검색 트리거 버튼만 노출하는 경량 select (내부 사용용).
@@ -1,82 +0,0 @@
1
- # @simplysm/angular — selection-managers
2
-
3
- 리스트 컴포넌트 내부에서 쓰는 선택·확장·정렬 로직 함수 훅. signal 바인딩.
4
-
5
- ## useSelectionManager
6
-
7
- ```ts
8
- function useSelectionManager<TItem, TKey>(options: {
9
- displayItems: Signal<TItem[]>;
10
- selectedKeys: WritableSignal<TKey[]>;
11
- selectMode: Signal<"single"|"multi"|undefined>;
12
- getItemSelectableFn: Signal<((item: TItem) => boolean|string)|undefined>;
13
- trackByFn: Signal<(item, index) => TKey>;
14
- }): {
15
- hasSelectable: Signal<boolean>;
16
- isAllSelected: Signal<boolean>;
17
- getSelectable(item): true|string|undefined;
18
- getCanChangeFn(item): () => boolean;
19
- select(item): void;
20
- deselect(item): void;
21
- toggle(item): void;
22
- toggleAll(): void;
23
- isSelected(item): boolean;
24
- };
25
- ```
26
-
27
- - `selectMode=single` 이면 `select` 가 기존 키 덮어씀, `multi` 면 추가.
28
- - `getItemSelectableFn` — true: 선택 가능, false: 불가, string: 불가 + 사유.
29
- - `getSelectable` 반환 → `true` (선택 가능), `string` (사유), `undefined` (해당 없음).
30
- - `isAllSelected` — selectable 항목 전체가 선택된 상태.
31
- - 키 비교는 `obj.equal` (deep equal).
32
-
33
- ## useExpandingManager
34
-
35
- ```ts
36
- function useExpandingManager<T>(binding: {
37
- items: Signal<T[]>;
38
- expandedItems: WritableSignal<T[]>;
39
- getChildrenFn: Signal<((item: T, index: number) => T[]|undefined)|undefined>;
40
- sort: (items: T[]) => T[];
41
- }): {
42
- displayItems: Signal<T[]>; // 트리 평탄화 + 정렬 적용
43
- hasExpandable: Signal<boolean>;
44
- isAllExpanded: Signal<boolean>;
45
- toggle(item): void;
46
- toggleAll(): void;
47
- isVisible(item): boolean; // 조상 모두 expanded 인지
48
- def(item): ExpandItemDef<T>;
49
- };
50
-
51
- interface ExpandItemDef<T> {
52
- item: T;
53
- parentDef: ExpandItemDef<T>|undefined;
54
- hasChildren: boolean;
55
- depth: number;
56
- }
57
- ```
58
-
59
- - `getChildrenFn` 으로 트리 워킹 → 깊이·부모 정보 포함한 def 배열 생성.
60
- - `sort` — 각 depth 별 자식들에 적용할 정렬 함수(보통 `useSortingManager.sort`).
61
- - `isVisible` — 항목이 화면에 보일 조건(모든 조상이 expanded).
62
-
63
- ## useSortingManager
64
-
65
- ```ts
66
- function useSortingManager(options: { sorts: WritableSignal<SortingDef[]> }): {
67
- defMap: Signal<Map<string, { indexText?: string; desc: boolean }>>;
68
- toggle(key: string, multiple: boolean): void;
69
- sort<T>(items: T[]): T[];
70
- };
71
-
72
- interface SortingDef { key: string; desc: boolean; }
73
- ```
74
-
75
- - 컬럼 클릭 시 `toggle(key, ctrlKey)`. 단일 정렬은 `asc → desc → 없음` 순환, 다중(`multiple=true`)은 같은 키 누적 + 마지막에 제거.
76
- - `defMap.indexText` — 다중 정렬일 때 컬럼 헤더에 표시할 순번 ("1", "2"…). 단일이면 undefined.
77
- - `sort` — `key` 별 prop 값 비교. string 은 localeCompare, number 는 산술, 그 외는 String 변환 localeCompare. null/undefined 는 최소값.
78
-
79
- ## 주의
80
-
81
- - 세 훅 모두 컴포넌트의 inject 컨텍스트 없이 호출 가능(순수 함수). 단 signal 바인딩이므로 reactive 컨텍스트에서 사용.
82
- - `<sd-sheet>` 가 내부적으로 셋 다 사용. 새 리스트 컴포넌트 만들 때 같은 동작 원하면 재사용.
@@ -1,134 +0,0 @@
1
- # @simplysm/angular — shared-data
2
-
3
- 서버 마스터데이터(부서·거래처·코드 등)를 키 기반으로 등록/구독. 서버 변경 이벤트로 자동 부분 갱신.
4
-
5
- ## SdSharedDataProvider<T> (abstract, 사용자가 상속해 `initialize()` 안에서 `register` 호출)
6
-
7
- ```ts
8
- abstract class SdSharedDataProvider<T extends Record<string, SharedDataBase<string|number>>> {
9
- loadingCount: WritableSignal<number>;
10
- abstract initialize(): void;
11
- register<K extends keyof T & string>(name: K, info: SharedDataInfo<T[K]>): void;
12
- getHandle<K extends keyof T & string>(name: K): SharedDataHandle<T[K]>;
13
- emitAsync<K extends keyof T & string>(name: K, changeKeys?: (string|number)[]): Promise<void>;
14
- wait(): Promise<void>; // loadingCount 가 0 될 때까지
15
- }
16
-
17
- interface SharedDataBase<TKey> {
18
- __valueKey: TKey;
19
- __searchText: string;
20
- __isHidden: boolean;
21
- __parentKey?: TKey;
22
- }
23
- interface SharedDataInfo<T> {
24
- serviceKey: string; // SdServiceClientFactoryProvider 의 client key
25
- getter: (changeKeys?: (string|number)[]) => Promise<T[]>;
26
- filter?: unknown;
27
- orderBy?: (item: T) => any;
28
- }
29
- interface SharedDataHandle<T> {
30
- items: Signal<T[]>;
31
- get(key: T["__valueKey"]|undefined): T|undefined;
32
- }
33
-
34
- const SdSharedDataChangeEvent = defineEvent<{ name: string; filter: unknown }, (string|number)[]|undefined>("SdSharedDataChange");
35
- ```
36
-
37
- - `register` — 데이터 소스 등록. `getHandle` 첫 호출 시 `getter()` lazy 로드 + 서버 이벤트 리스너 등록. 이후 `SdSharedDataChangeEvent` 수신 시 `changeKeys` 기준 부분 갱신(또는 undefined 면 전체 reload).
38
- - `getHandle.items` — readonly signal. orderBy 적용된 정렬 상태.
39
- - `getHandle.get(key)` — `__valueKey` 로 O(1) 조회.
40
- - `emitAsync` — 클라이언트에서 변경 발생 시 같은 `serviceKey` 의 다른 클라이언트에 변경 통지(filter 동일한 등록만 수신).
41
- - `wait` — 초기 로드/갱신이 완료될 때까지. CRUD 컨테이너의 ready 처리에 사용.
42
- - `SharedDataBase` 의 `__searchText` — `matchesSearchText` 가 사용할 검색 대상 문자열. `__isHidden` — 보이지 않을 항목 마킹. `__parentKey` — 트리형 데이터의 부모 키.
43
- - `filter` — 서버 측 필터 식별자. 다른 filter 로 등록된 같은 name 은 별개 인스턴스.
44
-
45
- ```ts
46
- @Injectable({ providedIn: "root" })
47
- class MySharedData extends SdSharedDataProvider<{ depts: Dept }> {
48
- initialize() {
49
- this.register("depts", {
50
- serviceKey: "main",
51
- getter: async (keys) => await api.depts.list(keys),
52
- orderBy: (d) => d.name,
53
- });
54
- }
55
- }
56
- const depts = mySharedData.getHandle("depts").items();
57
- ```
58
-
59
- ## SdSharedDataSelect — `<sd-shared-data-select>`
60
-
61
- ```ts
62
- class SdSharedDataSelect<TMode, TModal, TItem extends SharedDataBase<...>>
63
- value = model<SelectModeValue<TItem["__valueKey"]|undefined>[TMode]>();
64
- items = input.required<TItem[]>();
65
- disabled/required/useUndefined/inset/inline = input(false); size = input<"sm"|"lg">();
66
- selectMode = input("single" as TMode);
67
- filterFn = input<(item, index, ...params) => boolean>();
68
- filterFnParams = input<any[]>();
69
- modal = input<SdSelectModalInfo<TModal>>();
70
- editModal = input<SdModalInfo<SdModalContentDef<boolean>>>();
71
- selectClass = input<string>();
72
- multiSelectionDisplayDirection = input<"vertical">();
73
- getIsHiddenFn = input<(item, index) => boolean>(...); // 기본 (i)=>i.__isHidden
74
- getSearchTextFn = input<(item, index) => string>(...); // 기본 (i)=>i.__searchText
75
- displayOrderKeyProp = input<string>();
76
- ```
77
-
78
- - 공유데이터 전용 셀렉트. `items` 는 보통 `sharedData.getHandle("xx").items()`.
79
- - `useUndefined` — true 면 "선택 안 함" 옵션 노출. 단일 모드에서 null 가능.
80
- - `filterFn` + `filterFnParams` — 추가 필터(signal 변경 시 재계산).
81
- - `modal` — "더보기" 검색 모달. 미지정 시 모달 버튼 안 보임.
82
- - `editModal` — 항목 편집 모달(연필 아이콘). true emit 시 데이터 reload.
83
- - `getIsHiddenFn`/`getSearchTextFn` — 기본은 `SharedDataBase` 의 `__isHidden`/`__searchText` 사용. 커스텀 가능.
84
- - `displayOrderKeyProp` — 트리 표시 시 정렬에 쓸 prop 이름.
85
-
86
- ## SdSharedDataSelectButton — `<sd-shared-data-select-button>`
87
-
88
- ```ts
89
- value = model<SelectModeValue<string|number>[TMode]>();
90
- items = input<TItem[]>([]);
91
- modal = input.required<SdSelectModalInfo<TModal>>();
92
- selectMode = input<TMode>("single" as TMode);
93
- disabled/required/inset = input(false); size = input<"sm"|"lg">();
94
- ```
95
-
96
- - 셀렉트 드롭다운 대신 항상 모달로 검색. `<ng-content>` 가 선택값 표시 슬롯. `modal` 필수.
97
-
98
- ## SdSharedDataSelectList — `<sd-shared-data-select-list>`
99
-
100
- ```ts
101
- class SdSharedDataSelectList<TItem extends SharedDataBase<...>, TModal>
102
- selectedItem = model<TItem>();
103
- canChangeFn = input<(item: TItem|undefined) => boolean|Promise<boolean>>(...);
104
- items = input.required<TItem[]>();
105
- selectedIcon = input<string>();
106
- useUndefined = input(false);
107
- filterFn = input<(item, index) => boolean>();
108
- modal = input<SdSelectModalInfo<TModal>>();
109
- header = input<string>();
110
- pageItemCount = input<number>();
111
- ```
112
-
113
- - 사이드 패널형 리스트(단일 선택). 검색 박스 + 페이지네이션 자동.
114
- - `canChangeFn` — 변경 직전 비동기 확인.
115
- - `pageItemCount` — 페이지당 항목 수. 미지정 시 페이지 분할 없음.
116
-
117
- ## matchesSearchText
118
-
119
- ```ts
120
- function matchesSearchText(itemText: string, searchQuery: string|undefined): boolean
121
- ```
122
-
123
- - 공백 분리 AND 검색. 모든 단어가 `itemText` (대소문자 무시) 안에 포함되면 true. 빈 query 는 true.
124
- - 커스텀 선택 리스트에서 검색 필터 짤 때 사용.
125
-
126
- ```ts
127
- items.filter((it) => matchesSearchText(it.name + " " + it.code, q()))
128
- ```
129
-
130
- ## 주의
131
-
132
- - `SdSharedDataProvider` 상속 후 `initialize()` 안에서만 `register`. 부트스트랩 시 1회 호출.
133
- - 같은 name 으로 다시 `register` 호출 시 generation 증가 + listener 교체 → 이전 비동기 결과는 무시.
134
- - 변경 이벤트는 같은 `serviceKey` 의 같은 `name`·동일 `filter` 등록만 수신.
@@ -1,127 +0,0 @@
1
- # @simplysm/angular — sheet
2
-
3
- 데이터 그리드. 컬럼·셀 템플릿·정렬·페이징·선택·확장 트리·컬럼 설정 모달 내장.
4
-
5
- ## SdSheet — `<sd-sheet>`
6
-
7
- ```ts
8
- class SdSheet<TItem>
9
- key = input<string>();
10
- items = input<TItem[]>([]);
11
- trackByFn = input<(item: TItem, index: number) => unknown>((i) => i);
12
- selectMode = input<"single"|"multi">();
13
- autoSelect = input<"click"|"focus">();
14
- getItemSelectableFn = input<(item) => boolean|string>();
15
- getChildrenFn = input<(item, index) => TItem[]|undefined>();
16
- useAutoSort = input(false);
17
- visiblePageCount = input(10);
18
- totalPageCount = input(0);
19
- itemsPerPage = input(0);
20
- focusMode = input<"row"|"cell">("cell");
21
- inset = input(false);
22
- contentStyle = input<string>();
23
- getItemCellClassFn = input<(item, colKey: string) => string>();
24
- getItemCellStyleFn = input<(item, colKey: string) => string|undefined>();
25
- hideConfigBar = input(false);
26
-
27
- itemKeydown = output<SdSheetItemKeydownEventParam<TItem>>();
28
- cellKeydown = output<SdSheetCellKeydownEventParam<TItem>>();
29
-
30
- selectedKeys = model<unknown[]>([]);
31
- expandedItems = model<TItem[]>([]);
32
- sorts = model<SortingDef[]>([]);
33
- currentPage = model(0);
34
-
35
- columnControlsInput = input<readonly SdSheetColumn[]>([]); // 동적 컬럼 주입용
36
- ```
37
-
38
- - `key` — 지정 시 `SdSystemConfigProvider` 키 `sd-sheet.<key>` 로 컬럼 width/hidden/fixed/ordering 자동 저장·복원. 미지정이면 세션 한정.
39
- - `items` + `trackByFn` — 데이터와 키 추출. 트리는 `getChildrenFn` 으로 자식 반환(`expandedItems` 양방향 model 로 펼침 상태).
40
- - `selectMode` — `single`/`multi`. 미지정이면 선택 안 함. `selectedKeys` 는 `trackByFn` 반환값 배열.
41
- - `autoSelect` — `click`: 행 클릭 시 선택, `focus`: 포커스만 들어가도 선택. 미지정이면 명시적 체크박스만.
42
- - `getItemSelectableFn` — true 면 선택 가능, false/string 이면 불가(string 은 사유 툴팁).
43
- - `useAutoSort` — true 면 `sorts` 변경 시 클라이언트 자체 정렬. false 면 서버 사이드 페치 가정.
44
- - `totalPageCount`/`itemsPerPage`/`visiblePageCount`/`currentPage` — 페이지네이션. `totalPageCount=0` 이면 페이지바 숨김.
45
- - `focusMode` — `row` 면 행 단위 포커스, `cell` 면 셀 단위(엑셀형).
46
- - `inset` — 컨테이너 안에 박힌 룩(보더 제거).
47
- - `getItemCellClassFn`/`getItemCellStyleFn` — 셀별 동적 class/style.
48
- - `hideConfigBar` — 상단 컬럼 설정 바(컬럼 표시/순서 조작) 숨김.
49
- - `itemKeydown`/`cellKeydown` — 단축키 처리. focusMode 에 따라 둘 중 1개 활용.
50
- - 자식: `<sd-sheet-column>` 들을 content projection 으로 배치.
51
-
52
- ```html
53
- <sd-sheet [items]="rows()" [trackByFn]="trackById" [(selectedKeys)]="sel" selectMode="multi" key="invoice-list">
54
- <sd-sheet-column key="no" header="번호" width="80px" />
55
- <sd-sheet-column key="name" header="이름">
56
- <ng-template cell [cell]="rows()" let-item>{{ item.name }}</ng-template>
57
- </sd-sheet-column>
58
- </sd-sheet>
59
- ```
60
-
61
- ## SdSheetColumn — `<sd-sheet-column>` (Directive)
62
-
63
- ```ts
64
- class SdSheetColumn<T = unknown>
65
- key = input.required<string>();
66
- header = input<string|string[]>(""); // 배열이면 다단 헤더
67
- headerStyle = input<string>();
68
- tooltip = input<string>();
69
- width = input<string>(); // CSS 값 ("120px"·"1fr")
70
- fixed = input(false); // 좌측 고정 컬럼
71
- hidden = input(false);
72
- collapse = input(false); // 접힘(헤더만 좁게)
73
- disableSorting = input(false);
74
- disableResizing = input(false);
75
- ordering = input(0); // 표시 순서 weight
76
-
77
- interface SdSheetCellContext<T = unknown> { ... } // 셀 템플릿 컨텍스트
78
- ```
79
-
80
- - `key` — 정렬·설정 저장 식별자. 시트 내 unique.
81
- - `header` 배열 — `["상위", "하위"]` 형태로 2단·3단 헤더 그룹화. 인접 컬럼이 같은 상위 헤더면 머지.
82
- - `fixed` — 좌측 sticky.
83
- - `ordering` — 사용자가 드래그로 바꾼 순서가 우선. 같은 ordering 끼리는 선언 순서.
84
-
85
- ## SdSheetColumnCellTemplate — `<ng-template cell>` (Directive)
86
-
87
- ```ts
88
- class SdSheetColumnCellTemplate<T> { cell = input.required<T[]>(); }
89
- ```
90
-
91
- - `<sd-sheet-column>` 안의 셀 템플릿 마커. `[cell]` 에 items 배열 바인딩(type guard 용도). let-item, let-index, let-depth 사용 가능.
92
-
93
- ## SdSheetConfigModal — `<sd-sheet-config-modal>` (SdModalContentDef)
94
-
95
- ```ts
96
- sheetKey = input.required<string>();
97
- controls = input.required<readonly SdSheetColumn[]>();
98
- config = input.required<SdSheetConfig|undefined>();
99
- close = output<SdSheetConfig|undefined>();
100
- ```
101
-
102
- - 컬럼 표시/숨김/순서/너비 설정 모달. `SdSheet` 내부에서 호출. 직접 부를 일은 거의 없음.
103
-
104
- ## 타입
105
-
106
- ```ts
107
- interface SdSheetColumnDef {
108
- key, header, headerStyle, tooltip, width, fixed, hidden, collapse,
109
- disableSorting, disableResizing, ordering
110
- }
111
- interface SdSheetHeaderDef {
112
- text, colspan, rowspan, isLastRow, fixed, colDef, colIndex
113
- }
114
- interface SdSheetConfig {
115
- columnRecord: Record<string, { width?, hidden?, fixed?, ordering? }>;
116
- }
117
- interface SdSheetItemKeydownEventParam<T> { item: T; event: KeyboardEvent; }
118
- interface SdSheetCellKeydownEventParam<T> { item: T; key: string; event: KeyboardEvent; }
119
- ```
120
-
121
- - `SdSheetCellContext<T>` 는 셀 템플릿 안에서 노출되는 context 타입(item/index/depth/edit mode 등).
122
-
123
- ## 주의
124
-
125
- - `key` 지정 시 `SdSystemConfigProvider` 가 부착되어 있어야 영구 저장. 미부착이면 `SdLocalStorageProvider` 경유.
126
- - `selectMode=multi` 일 때 `selectedKeys` 는 `trackByFn` 반환 키. `items` 와 별개 배열.
127
- - 트리(`getChildrenFn`) + 정렬(`useAutoSort=true`) 동시 사용 시 정렬은 각 depth 안에서만 적용.