@wipco/sdui 0.50.1 → 1.0.0

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 (111) hide show
  1. package/dist/{DatePicker-BK_jsV7i.d.ts → DatePicker-C_TT_SOw.d.ts} +25 -0
  2. package/dist/{chunk-OEWTVLPZ.js → chunk-2HLXCKK7.js} +2 -2
  3. package/dist/{chunk-PWVHAUJC.js → chunk-2YP5N4VV.js} +6 -4
  4. package/dist/{chunk-QTHYLNJW.js → chunk-37SFFW37.js} +2 -13
  5. package/dist/{chunk-YQOMSWW5.js → chunk-5WW4MBRO.js} +1 -1
  6. package/dist/{chunk-LIOS3PF2.js → chunk-5XPZ3RSA.js} +3 -4
  7. package/dist/{chunk-ZD3VNVRF.js → chunk-7BGDSSAN.js} +5 -13
  8. package/dist/{chunk-Y2LIEWQX.js → chunk-7FZTUI6U.js} +6 -5
  9. package/dist/{chunk-HJ5VSXR4.js → chunk-7P7N43JV.js} +2 -2
  10. package/dist/{chunk-55VB6SDU.js → chunk-A5XQOEVH.js} +23 -20
  11. package/dist/{chunk-77LKJCMM.js → chunk-A6LAIGUS.js} +20 -108
  12. package/dist/{chunk-YXS5FXVS.js → chunk-AC5TI3BE.js} +7 -16
  13. package/dist/{chunk-AIOJYVJ2.js → chunk-AXGF4M57.js} +1 -1
  14. package/dist/{chunk-5MPK3NZK.js → chunk-B6WMC2AN.js} +3 -3
  15. package/dist/{chunk-C6ZV4VBN.js → chunk-C37U3GCC.js} +4 -4
  16. package/dist/{chunk-265YPW4W.js → chunk-DMLDKW7K.js} +1 -1
  17. package/dist/{chunk-FZ72IDVF.js → chunk-E6ISNQK3.js} +2 -2
  18. package/dist/{chunk-STX2AX6Y.js → chunk-FLAN7CV3.js} +7 -39
  19. package/dist/{chunk-IV5YTVHR.js → chunk-GE6BYNQJ.js} +18 -33
  20. package/dist/{chunk-ZX36LKJ7.js → chunk-GTGS2QRL.js} +7 -6
  21. package/dist/{chunk-NL3I6F2I.js → chunk-HBBTENSV.js} +3 -3
  22. package/dist/{chunk-RUU7WBGR.js → chunk-I45EUZC6.js} +19 -9
  23. package/dist/{chunk-JBKNIALK.js → chunk-I5SD7XRA.js} +9 -6
  24. package/dist/{chunk-X7GHY2RI.js → chunk-IFKYGJXP.js} +14 -42
  25. package/dist/{chunk-J3YMUR6R.js → chunk-IZ3JA2BR.js} +3 -3
  26. package/dist/{chunk-AUW5RP24.js → chunk-JIV4YHCZ.js} +7 -6
  27. package/dist/{chunk-M6KM3FJS.js → chunk-JYAR7D5U.js} +2 -2
  28. package/dist/{chunk-DKPNFEVU.js → chunk-KO6OEY3G.js} +19 -6
  29. package/dist/{chunk-JHHMFL5D.js → chunk-LFEJLOFN.js} +28 -16
  30. package/dist/chunk-MMIGOPO5.js +111 -0
  31. package/dist/{chunk-YSSNP6JM.js → chunk-N25YP7ID.js} +6 -21
  32. package/dist/{chunk-F2W2FWOT.js → chunk-N5RKM6IC.js} +7 -7
  33. package/dist/{chunk-C4HYWZML.js → chunk-O4IISNE7.js} +1 -1
  34. package/dist/chunk-Q4SWUINA.js +51 -0
  35. package/dist/{chunk-TUOG7EEI.js → chunk-RNOUXUBO.js} +418 -22
  36. package/dist/{chunk-4VZI3PLI.js → chunk-RYHEV5E3.js} +15 -39
  37. package/dist/{chunk-AVRNQOB5.js → chunk-SAPBDJJQ.js} +14 -13
  38. package/dist/{chunk-OPJ4DYNI.js → chunk-SJ3737RA.js} +156 -158
  39. package/dist/{chunk-UMANGYRD.js → chunk-TFGNKFL2.js} +1 -1
  40. package/dist/{chunk-KYGSMUUU.js → chunk-VY7MVBSE.js} +2 -2
  41. package/dist/{chunk-VDBUXYEB.js → chunk-WOYMEEPH.js} +8 -8
  42. package/dist/{chunk-I5Z2RVDF.js → chunk-WSLT32Q4.js} +278 -30
  43. package/dist/{chunk-NYUHSMUU.js → chunk-XGFDY43I.js} +2 -2
  44. package/dist/{chunk-ODKZF4IT.js → chunk-YOZN35HD.js} +17 -9
  45. package/dist/{chunk-EKP6Z3G6.js → chunk-YVTV4ZV6.js} +1 -1
  46. package/dist/{chunk-6BCWFPNJ.js → chunk-YWUDBLO6.js} +2 -2
  47. package/dist/chunk-Z4PYMTTS.js +41 -0
  48. package/dist/{chunk-WXIQLWIX.js → chunk-ZFNFPXPR.js} +2 -2
  49. package/dist/{chunk-7GOWOSX6.js → chunk-ZORQPB6B.js} +11 -5
  50. package/dist/index.d.ts +1096 -941
  51. package/dist/index.js +369 -610
  52. package/dist/meta.d.ts +13 -12
  53. package/dist/meta.js +84 -16
  54. package/dist/rich/ExcelUploadCard.d.ts +7 -0
  55. package/dist/rich/ExcelUploadCard.js +17 -13
  56. package/dist/rich.d.ts +1 -1
  57. package/dist/rich.js +25 -12
  58. package/dist/styles.css +10 -2
  59. package/dist/{types-D14eqLpf.d.ts → types-C7y9CpgF.d.ts} +7 -5
  60. package/dist/widgets/ApprovalLineEditor.js +7 -6
  61. package/dist/widgets/ApprovalOverridesEditor.d.ts +11 -1
  62. package/dist/widgets/ApprovalOverridesEditor.js +9 -8
  63. package/dist/widgets/ApprovalStepper.js +3 -3
  64. package/dist/widgets/AutocompleteField.d.ts +1 -0
  65. package/dist/widgets/AutocompleteField.js +7 -6
  66. package/dist/widgets/ColumnBoard.js +3 -3
  67. package/dist/widgets/DiffView.js +3 -3
  68. package/dist/widgets/Disclosure.js +3 -3
  69. package/dist/widgets/EventCalendar.d.ts +16 -1
  70. package/dist/widgets/EventCalendar.js +3 -3
  71. package/dist/widgets/FileDropzone.js +7 -6
  72. package/dist/widgets/ImageLightbox.js +5 -4
  73. package/dist/widgets/InlineEdit.js +3 -3
  74. package/dist/widgets/JsonField.js +3 -3
  75. package/dist/widgets/LiveClock.js +2 -2
  76. package/dist/widgets/OptionSchemaEditor.js +4 -4
  77. package/dist/widgets/OptionValueFields.d.ts +5 -0
  78. package/dist/widgets/OptionValueFields.js +4 -4
  79. package/dist/widgets/OrgChart.js +4 -3
  80. package/dist/widgets/OrgChartBoard.d.ts +93 -4
  81. package/dist/widgets/OrgChartBoard.js +9 -6
  82. package/dist/widgets/PeriodFilter.js +4 -4
  83. package/dist/widgets/PermissionMatrixEditor.d.ts +16 -0
  84. package/dist/widgets/PermissionMatrixEditor.js +4 -4
  85. package/dist/widgets/PositionSelect.d.ts +6 -1
  86. package/dist/widgets/PositionSelect.js +5 -4
  87. package/dist/widgets/PrintSheet.js +3 -3
  88. package/dist/widgets/ProfileEditDiffCard.d.ts +6 -0
  89. package/dist/widgets/ProfileEditDiffCard.js +4 -4
  90. package/dist/widgets/QRDisplay.js +4 -4
  91. package/dist/widgets/RankBoard.d.ts +6 -0
  92. package/dist/widgets/RankBoard.js +6 -5
  93. package/dist/widgets/RecordSheet.js +2 -2
  94. package/dist/widgets/RoleMemberPicker.d.ts +11 -5
  95. package/dist/widgets/RoleMemberPicker.js +5 -4
  96. package/dist/widgets/SearchableMultiPicker.js +5 -5
  97. package/dist/widgets/SecureScreen.d.ts +12 -0
  98. package/dist/widgets/SecureScreen.js +3 -3
  99. package/dist/widgets/StackedMeter.js +2 -2
  100. package/dist/widgets/StagePeriodEditor.js +4 -5
  101. package/dist/widgets/Strip.js +2 -2
  102. package/dist/widgets/SummaryTable.js +2 -2
  103. package/dist/widgets/TagMultiSelect.d.ts +0 -1
  104. package/dist/widgets/TagMultiSelect.js +4 -4
  105. package/dist/widgets/Timeline.js +4 -4
  106. package/dist/widgets/TreePicker.js +6 -6
  107. package/dist/widgets/TreeView.js +5 -5
  108. package/dist/widgets/index.d.ts +3 -3
  109. package/dist/widgets/index.js +81 -79
  110. package/package.json +1 -1
  111. package/dist/chunk-EKVA7T7P.js +0 -198
package/dist/meta.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { b as SduiPropValue, i as SduiNode } from './types-D14eqLpf.js';
1
+ import { b as SduiPropValue, i as SduiNode } from './types-C7y9CpgF.js';
2
2
 
3
3
  /**
4
4
  * 시각 빌더용 컴포넌트 메타데이터 스키마.
@@ -256,7 +256,7 @@ declare function withSelfAxis(meta: SduiComponentMeta): SduiComponentMeta;
256
256
  declare function withSelfAxisAll(catalog: Record<string, SduiComponentMeta>): Record<string, SduiComponentMeta>;
257
257
 
258
258
  /**
259
- * 기본 어휘(`defaultRegistry`) 41종의 빌더 메타데이터.
259
+ * 기본 어휘(`defaultRegistry`) 42종의 빌더 메타데이터.
260
260
  *
261
261
  * 프롭 목록은 `components.tsx`·`primitives.tsx`·`SduiForm.tsx`·`Can.tsx`·
262
262
  * `DatePicker.tsx`·`search/SduiSearchResults.tsx`의 **실제 프롭 인터페이스**와,
@@ -332,7 +332,7 @@ declare const ShowMeta: SduiComponentMeta;
332
332
  * 컴파일 시점에 난다 — 둘이 어긋난 채로는 빌드가 통과하지 않는다.
333
333
  *
334
334
  * 팔레트처럼 전체가 필요한 곳이 아니면 개별 export(`ButtonMeta` 등)를 쓰는 편이
335
- * 번들에 유리하다 — 이 객체를 참조하는 순간 41종이 전부 따라온다.
335
+ * 번들에 유리하다 — 이 객체를 참조하는 순간 42종이 전부 따라온다.
336
336
  */
337
337
  declare const coreComponentMeta: {
338
338
  Actions: SduiComponentMeta;
@@ -399,7 +399,7 @@ declare const richComponentMeta: {
399
399
  };
400
400
 
401
401
  /**
402
- * `@wipco/sdui/widgets` 어휘 21종의 빌더 메타데이터.
402
+ * `@wipco/sdui/widgets` 어휘 37종의 빌더 메타데이터.
403
403
  *
404
404
  * core와 파일을 나눈 이유는 `rich.ts`와 같다 — 위젯을 얹지 않은 소비자가 이 데이터를
405
405
  * 받지 않게 하려는 것이다. 여기도 값 import는 없다(`import type`만).
@@ -464,11 +464,12 @@ declare const StripMeta: SduiComponentMeta;
464
464
  * 위젯 어휘의 메타데이터.
465
465
  *
466
466
  * 키 타입이 `SduiWidgetComponentName | 'AutocompleteField' | 'FileDropzone' | 'ExcelUploadCard'`인 이유:
467
- * 앞의 20종은 `widgetComponents`와 키가 어긋나면 컴파일 에러가 나야 하고(core·rich와 같다),
468
- * `AutocompleteField`는 그 묶음에 **일부러 빠져 있는** 이름이라 union에 직접 적어야 한다.
469
- * 표시 계층만 라이브러리에 있고 조회는 앱 어댑터가 얹는 구조인데(widgets/index.ts 참고),
470
- * 스펙과 빌더 입장에서는 엄연히 쓰는 어휘라 메타데이터까지 빼면 속성 패널이 6곳의
471
- * 프롭을 못 그린다.
467
+ * 앞의 34종은 `widgetComponents`와 키가 어긋나면 컴파일 에러가 나야 하고(core·rich와 같다),
468
+ * `AutocompleteField`·`FileDropzone`·`ExcelUploadCard`는 그 묶음에 **일부러 빠져 있는**
469
+ * 이름들이라 union에 직접 적어야 한다(빠진 사정은 widgets/index.ts 주석 참고 —
470
+ * AutocompleteField는 조회를 앱 어댑터가 얹고, FileDropzone은 rawFetch 없이는 업로드가
471
+ * 안 되며, ExcelUploadCard는 rich 진입점이다). 스펙과 빌더 입장에서는 셋 다 엄연히
472
+ * 쓰는 어휘라 메타데이터까지 빼면 속성 패널이 그 노드들의 프롭을 못 그린다.
472
473
  */
473
474
  declare const widgetComponentMeta: {
474
475
  ApprovalLineEditor: SduiComponentMeta;
@@ -560,7 +561,7 @@ declare const dsComponentMeta: {
560
561
  * ForEach는 레지스트리에 없다 — `SduiRenderer`가 노드를 보고 직접 반복 스코프를
561
562
  * 만든다. 그래서 core/rich처럼 레지스트리 키와 타입으로 대조할 대상이 없고,
562
563
  * 대신 여기 한 곳에 모아 둔다. 렌더러에 내장 어휘가 늘면 여기도 늘려야 한다
563
- * (`scripts/check-meta.mts`가 `SduiRenderer.tsx`를 훑어 누락을 잡는다).
564
+ * (`scripts/check-meta.mjs`가 `SduiRenderer.tsx`를 훑어 누락을 잡는다).
564
565
  */
565
566
 
566
567
  declare const ForEachMeta: SduiComponentMeta;
@@ -589,11 +590,11 @@ declare const SDUI_CATEGORIES: ReadonlyArray<{
589
590
  label: string;
590
591
  }>;
591
592
  /**
592
- * 라이브러리가 아는 어휘 전체 — 기본 42 + rich 2 + 위젯 22 + DS 6 + 렌더러 내장 2 = 74종.
593
+ * 라이브러리가 아는 어휘 전체 — 기본 42 + rich 2 + 위젯 37 + DS 6 + 렌더러 내장 2 = 89종.
593
594
  * 편집기처럼 어휘 전부를 다뤄야 하는 쪽에서 쓴다.
594
595
  *
595
596
  * **레지스트리와 일대일이 아니다.** `defaultRegistry`에 없는 것도 들어 있다 —
596
- * rich 2종, 위젯 22종, DS 6종은 소비자가 `createRegistry`로 직접 얹는 어휘라서
597
+ * rich 2종, 위젯 37종, DS 6종은 소비자가 `createRegistry`로 직접 얹는 어휘라서
597
598
  * 여기 있다고 곧바로 렌더되지는 않는다. 이 목록은 "빌더가 프롭을 그릴 줄 아는 이름"이지
598
599
  * "지금 렌더할 수 있는 이름"이 아니다.
599
600
  *
package/dist/meta.js CHANGED
@@ -91,6 +91,7 @@ var SIZE_OPTIONS = [
91
91
  { value: "full", label: "\uBD80\uBAA8 \uD3ED \uAC00\uB4DD" }
92
92
  ];
93
93
  var SPACE_OPTIONS = [
94
+ { value: "0", label: "0px (\uC5EC\uBC31 \uC5C6\uC74C)" },
94
95
  { value: "2", label: "2px" },
95
96
  { value: "4", label: "4px" },
96
97
  { value: "8", label: "8px" },
@@ -457,6 +458,15 @@ var CardMeta = {
457
458
  props: [
458
459
  { name: "title", kind: "node", label: "\uC81C\uBAA9", slot: true, group: "content" },
459
460
  { name: "subtitle", kind: "node", label: "\uBD80\uC81C", slot: true, group: "content" },
461
+ {
462
+ name: "cover",
463
+ kind: "node",
464
+ label: "\uD45C\uC9C0",
465
+ slot: true,
466
+ description: "\uBA38\uB9AC \uC704\uC5D0 \uAF49 \uCC28\uAC8C \uAE54\uB9AC\uB294 \uD45C\uC9C0 \u2014 \uBAA9\uB85D \uCE74\uB4DC\uC758 \uB300\uD45C \uC0AC\uC9C4 \uC790\uB9AC\uB2E4. \uC548\uCABD \uC5EC\uBC31\uC744 \uBB34\uC2DC\uD558\uACE0 \uC704 \uB450 \uBAA8\uC11C\uB9AC\uB9CC \uCE74\uB4DC \uACE1\uB960\uC744 \uB530\uB978\uB2E4.",
467
+ group: "content"
468
+ },
469
+ // 검색 gridCard 의 imageKey 가 실제로 쓴다(cell-image 테스트가 wp-card__cover 를 확인한다)
460
470
  {
461
471
  name: "variant",
462
472
  kind: "enum",
@@ -636,7 +646,9 @@ var PageHeadMeta = {
636
646
  description: "\uD398\uC774\uC9C0 \uC0C1\uB2E8\uC758 \uC81C\uBAA9\xB7\uBD80\uC81C\xB7\uC561\uC158 \uC601\uC5ED.",
637
647
  props: [
638
648
  { name: "title", kind: "node", label: "\uC81C\uBAA9", slot: true, group: "content" },
639
- { name: "subtitle", kind: "node", label: "\uBD80\uC81C", slot: true, group: "content" }
649
+ { name: "subtitle", kind: "node", label: "\uBD80\uC81C", slot: true, group: "content" },
650
+ styleProp,
651
+ classNameProp
640
652
  ],
641
653
  slots: [
642
654
  { name: "actions", label: "\uC6B0\uCE21 \uC561\uC158", allow: ["Actions", "Button", "IconButton", "Row", "Show", "Can"] }
@@ -2859,7 +2871,10 @@ var RadioMeta = {
2859
2871
  },
2860
2872
  { name: "value", kind: "string", label: "\uAC12", description: "\uC774 \uD56D\uBAA9\uC744 \uACE8\uB790\uC744 \uB54C\uC758 \uAC12.", group: "data" },
2861
2873
  { name: "checked", kind: "boolean", label: "\uC120\uD0DD\uB428", bindable: true, group: "data" },
2862
- { name: "onChange", kind: "action", label: "\uBCC0\uACBD", eventArg: "\uC120\uD0DD \uC5EC\uBD80(boolean)", group: "behavior" },
2874
+ // radio 는 checkbox 와 달리 checked(boolean)가 아니라 input 의 value 문자열이 이벤트 값이다
2875
+ // (렌더러의 eventValue 가 checkbox 만 checked 로 꺼낸다). fromEvent 보다는 프리셋처럼
2876
+ // value 리터럴 setState 를 거는 편이 안전하다.
2877
+ { name: "onChange", kind: "action", label: "\uBCC0\uACBD", eventArg: "\uC774 \uB77C\uB514\uC624\uC758 value \uBB38\uC790\uC5F4(fromEvent \uC0AC\uC6A9 \uC2DC \u2014 value \uBBF8\uC9C0\uC815\uC774\uBA74 'on')", group: "behavior" },
2863
2878
  { name: "disabled", kind: "boolean", label: "\uBE44\uD65C\uC131", default: false, bindable: true, group: "behavior" },
2864
2879
  styleProp2,
2865
2880
  classNameProp2
@@ -3762,7 +3777,7 @@ var OrgChartBoardMeta = {
3762
3777
  kind: "action",
3763
3778
  label: "\uC0AC\uC6D0 \uCE74\uB4DC \uD074\uB9AD",
3764
3779
  eventArg: "\uC0AC\uC6D0 \uD589(snake_case \uC6D0\uBB38 \u2014 id\xB7name\xB7grade\xB7job_title\xB7department_id \u2026)",
3765
- description: "\uBE44\uC6B0\uBA74 \uC704\uC82F\uC774 /hr/personal-card/{id}\uB85C \uC9C1\uC811 \uC774\uB3D9\uD55C\uB2E4.",
3780
+ description: '\uBE44\uC6B0\uBA74 \uD074\uB9AD\uD574\uB3C4 \uC544\uBB34 \uC77C\uB3C4 \uD558\uC9C0 \uC54A\uB294\uB2E4 \u2014 \uC0C1\uC138 \uD654\uBA74 \uACBD\uB85C\uB294 \uC18C\uBE44 \uC571\uC758 \uAC83\uC774\uB77C \uC704\uC82F\uC774 \uBAA8\uB978\uB2E4. \uC0C1\uC138\uB85C \uBCF4\uB0B4\uB824\uBA74 setState(fromEvent)\uB85C \uD589\uC744 \uBC1B\uC544 \uB450\uACE0 navigate \uC758 to \uB97C { "$calc": { "op": "concat", "args": ["/\uC571\uC758/\uC0C1\uC138/\uACBD\uB85C/", { "$state": "orgMember.id" }] } } \uCC98\uB7FC \uC787\uB294\uB2E4.',
3766
3781
  group: "behavior"
3767
3782
  },
3768
3783
  {
@@ -3797,25 +3812,69 @@ var OrgChartBoardMeta = {
3797
3812
  description: "\uC11C\uC5F4 \uC815\uB82C\uC5D0 \uC4F4\uB2E4. \uC2E4\uD328\uD574\uB3C4 \uC774\uB984\uC21C\uC73C\uB85C \uB5A8\uC5B4\uC9C4\uB2E4. \uAE30\uBCF8 '/job-positions'.",
3798
3813
  group: "data",
3799
3814
  advanced: true
3815
+ },
3816
+ // 아래 직제 어휘 5종은 전부 "주면 기본값을 통째로 대체"다 — 기본과 주입을 섞으면
3817
+ // 어느 회사의 직제도 아니게 된다(구현의 orgVocabOf 참조).
3818
+ {
3819
+ name: "dutyOrder",
3820
+ kind: "array",
3821
+ label: "\uC9C1\uCC45 \uC11C\uC5F4",
3822
+ description: "\uB192\uC740 \uC21C \uBB38\uC790\uC5F4 \uBAA9\uB85D. \uC8FC\uBA74 \uAE30\uBCF8 \uC11C\uC5F4(\uD68C\uC7A5\u2026\uD30C\uD2B8\uC7A5, v2 \uD558\uB4DC\uCF54\uB529)\uC744 \uD1B5\uC9F8\uB85C \uB300\uCCB4\uD55C\uB2E4. \uBCF5\uD569 \uBA85\uCE6D\uC740 \uAC00\uC7A5 \uAE34 \uD3EC\uD568 \uD56D\uBAA9\uC73C\uB85C \uB9E4\uCE6D\uD55C\uB2E4.",
3823
+ group: "data",
3824
+ advanced: true,
3825
+ item: [],
3826
+ itemKind: "string"
3827
+ },
3828
+ {
3829
+ name: "gradeOrder",
3830
+ kind: "array",
3831
+ label: "\uC9C1\uC704 \uC11C\uC5F4 \uD3F4\uBC31",
3832
+ description: "\uC9C1\uC704 \uB9C8\uC2A4\uD130\uB97C \uBABB \uC77D\uC5C8\uC744 \uB54C\uB9CC \uC4F0\uB294 \uB192\uC740 \uC21C \uBAA9\uB85D. \uC8FC\uBA74 \uAE30\uBCF8\uAC12(\uD68C\uC7A5\u2026\uC778\uD134)\uC744 \uD1B5\uC9F8\uB85C \uB300\uCCB4\uD55C\uB2E4.",
3833
+ group: "data",
3834
+ advanced: true,
3835
+ item: [],
3836
+ itemKind: "string"
3837
+ },
3838
+ {
3839
+ name: "leadershipMatch",
3840
+ kind: "array",
3841
+ label: "\uB9AC\uB354\uC2ED \uD310\uBCC4 \uD3EC\uD568\uC5B4",
3842
+ description: '\uB9AC\uB354\uC2ED \uC2A4\uD0DD(\uC0C1\uB2E8 \uC778\uBB3C \uCE74\uB4DC)\uC73C\uB85C \uBF51\uC744 \uC9C1\uD568 \uD3EC\uD568\uC5B4 \u2014 \uC55E\uC5D0 \uC62C\uC218\uB85D \uC704(\uCD5C\uB300 3\uBA85). \uD56D\uBAA9\uC740 \uBB38\uC790\uC5F4 \uD558\uB098 \uB610\uB294 \uB3D9\uC21C\uC704 \uBB36\uC74C \uBC30\uC5F4(["\uC0AC\uC7A5","CEO"])\uC774\uACE0, \uC8FC\uBA74 \uAE30\uBCF8 \uBAA9\uB85D(\uD68C\uC7A5\xB7\uB300\uD45C\uC774\uC0AC\xB7\uB300\uD45C\xB7\uC0AC\uC7A5=CEO)\uC744 \uD1B5\uC9F8\uB85C \uB300\uCCB4\uD55C\uB2E4.',
3843
+ group: "data",
3844
+ advanced: true,
3845
+ item: [],
3846
+ itemKind: "string"
3847
+ },
3848
+ {
3849
+ name: "unassignedGroupIds",
3850
+ kind: "array",
3851
+ label: "\uBBF8\uC9C0\uC815 \uADF8\uB8F9 id",
3852
+ description: "\uC870\uC9C1\uB3C4\uC5D0\uC11C \uC228\uAE38 \uADF8\uB8F9 id \uBAA9\uB85D. \uC8FC\uBA74 \uAE30\uBCF8 \uC13C\uD2F0\uB110(kc_unassigned_department)\uC744 \uD1B5\uC9F8\uB85C \uB300\uCCB4\uD55C\uB2E4.",
3853
+ group: "data",
3854
+ advanced: true,
3855
+ item: [],
3856
+ itemKind: "string"
3857
+ },
3858
+ {
3859
+ name: "unassignedNames",
3860
+ kind: "array",
3861
+ label: "\uBBF8\uC9C0\uC815 \uADF8\uB8F9 \uC774\uB984",
3862
+ description: "id\uC640 \uBB34\uAD00\uD558\uAC8C \uC228\uAE38 \uADF8\uB8F9 \uC774\uB984 \uBAA9\uB85D. \uC8FC\uBA74 \uAE30\uBCF8\uAC12(['\uBBF8\uC9C0\uC815'])\uC744 \uD1B5\uC9F8\uB85C \uB300\uCCB4\uD55C\uB2E4 \u2014 \uB2E4\uB978 \uC5B8\uC5B4\xB7\uBA85\uCE6D\uC758 \uBC31\uC5D4\uB4DC\uC6A9.",
3863
+ group: "data",
3864
+ advanced: true,
3865
+ item: [],
3866
+ itemKind: "string"
3800
3867
  }
3801
3868
  ],
3802
3869
  children: { accepts: false },
3803
3870
  dom: { element: "div" },
3804
3871
  preset: {
3805
3872
  component: "OrgChartBoard",
3873
+ // navigate 예시는 넣지 않는다 — 상세 화면 경로는 소비 앱의 라우트라서, 어떤 경로를
3874
+ // 박아 둬도 다른 앱에서는 존재하지 않는 곳으로 이동하는 조각이 된다(구현이 같은
3875
+ // 이유로 location.assign 폴백을 버렸다). 잇는 방법은 onMemberClick 설명에 있다.
3806
3876
  props: {
3807
- onMemberClick: [
3808
- { action: "setState", key: "orgMember", fromEvent: true },
3809
- {
3810
- action: "navigate",
3811
- to: {
3812
- $calc: {
3813
- op: "concat",
3814
- args: ["/hr/personal-card/", { $state: "orgMember.id", default: "" }]
3815
- }
3816
- }
3817
- }
3818
- ]
3877
+ onMemberClick: [{ action: "setState", key: "orgMember", fromEvent: true }]
3819
3878
  }
3820
3879
  },
3821
3880
  resize: { kind: "none" }
@@ -4296,8 +4355,17 @@ var QRDisplayMeta = {
4296
4355
  group: "appearance"
4297
4356
  },
4298
4357
  // 실측 2/2 (148, 112)
4299
- { name: "caption", kind: "string", label: "\uCEA1\uC158", group: "content" }
4358
+ { name: "caption", kind: "string", label: "\uCEA1\uC158", group: "content" },
4300
4359
  // 실측 2/2
4360
+ {
4361
+ name: "endpoint",
4362
+ kind: "string",
4363
+ label: "QR \uB80C\uB354\uB7EC \uACBD\uB85C",
4364
+ description: "QR \uC774\uBBF8\uC9C0\uB97C \uB0B4\uC8FC\uB294 \uC11C\uBC84 \uACBD\uB85C \u2014 ?data=<\uC778\uCF54\uB529\uB41C URL>&size=<px> \uAC00 \uBD99\uB294\uB2E4. \uAE30\uBCF8 '/qr'. API \uAC00 \uB2E4\uB978 \uC624\uB9AC\uC9C4\uC774\uBA74 \uADF8 \uC808\uB300 \uC8FC\uC18C\uB97C \uB118\uAE34\uB2E4.",
4365
+ group: "data",
4366
+ advanced: true
4367
+ }
4368
+ // 스펙 실측 0 — ERP는 레지스트리 래퍼가 넘기지만(registry.tsx의 ErpQRDisplay), 스펙이 덮어쓸 수 있어야 한다
4301
4369
  ],
4302
4370
  children: { accepts: false },
4303
4371
  dom: { element: "figure" },
@@ -30,6 +30,13 @@ interface ExcelUploadCardProps {
30
30
  summaryLabels?: Record<string, string>;
31
31
  /** server: 응답 JSON / preview: 서버 응답(없으면 유효 행 배열) */
32
32
  onComplete?: (result: unknown) => void;
33
+ /**
34
+ * 503 응답을 "백엔드 미연동(데모 모드)"으로 해석한다 — 미연동 상태를 503으로 알리는
35
+ * 개발 프록시 호스트 전용 opt-in. 503은 표준 Service Unavailable(재배포·과부하)이기도
36
+ * 해서, 기본(꺼짐)에서는 일반 오류로 알리고 재시도에 맡긴다 — 일시적 503 한 번에
37
+ * 업로드 버튼이 잠기면 안 된다.
38
+ */
39
+ demoModeOn503?: boolean;
33
40
  }
34
41
  /** 바깥에서 온 `style`·`className`을 뿌리에 얹어 내보낸다 — 자기 축(폭·여백)이 닿게 하는 통로. */
35
42
  declare const ExcelUploadCard: React__default.FC<ExcelUploadCardProps & SduiBoxProps>;
@@ -1,11 +1,12 @@
1
- import { loadOptionalModule } from '../chunk-EKP6Z3G6.js';
2
- import { useSduiAdapter, useSduiSandbox, hostFetchOf, defaultAdapter, hostRawFetchOf } from '../chunk-DKPNFEVU.js';
3
- import { Select, Input, Card, Button, Spinner, Icon, Alert, StatCard, Badge, Table, EmptyState } from '../chunk-TUOG7EEI.js';
4
- import { boxed } from '../chunk-YQOMSWW5.js';
1
+ import { loadOptionalModule } from '../chunk-YVTV4ZV6.js';
2
+ import { useSduiAdapter, useSduiSandbox, hostFetchOf, defaultAdapter, hostRawFetchOf } from '../chunk-KO6OEY3G.js';
3
+ import { Select, Input, Card, Button, Spinner, Icon, Alert, StatCard, Badge, Table, EmptyState } from '../chunk-RNOUXUBO.js';
4
+ import { boxed } from '../chunk-5WW4MBRO.js';
5
5
  import { useRef, useState, useMemo, useCallback } from 'react';
6
6
  import { jsx, jsxs } from 'react/jsx-runtime';
7
7
 
8
8
  var ACCEPT = ".xlsx,.xls";
9
+ var loadXlsx = () => import('xlsx');
9
10
  function pickCell(raw, column) {
10
11
  const keys = Object.keys(raw);
11
12
  const match = keys.find((key) => key.trim() === column.header) ?? keys.find((key) => key.trim() === column.key);
@@ -48,7 +49,8 @@ function ExcelUploadCardImpl({
48
49
  templateColumns,
49
50
  columns,
50
51
  summaryLabels,
51
- onComplete
52
+ onComplete,
53
+ demoModeOn503 = false
52
54
  }) {
53
55
  const adapter = useSduiAdapter();
54
56
  const sandbox = useSduiSandbox();
@@ -74,6 +76,7 @@ function ExcelUploadCardImpl({
74
76
  setResult(null);
75
77
  setRows(null);
76
78
  setNotice(null);
79
+ setDemoMode(false);
77
80
  setInputKey((key) => key + 1);
78
81
  }, []);
79
82
  const hasTemplate = (templateColumns?.length ?? 0) > 0 || Boolean(templateEndpoint);
@@ -81,7 +84,7 @@ function ExcelUploadCardImpl({
81
84
  setDownloading(true);
82
85
  try {
83
86
  if (templateColumns && templateColumns.length > 0) {
84
- const XLSX = await loadOptionalModule(() => import('xlsx'), "xlsx");
87
+ const XLSX = await loadOptionalModule(loadXlsx, "xlsx");
85
88
  const headers = templateColumns.map((column) => column.header);
86
89
  const examples = templateColumns.map((column) => column.example ?? "");
87
90
  const sheet = XLSX.utils.aoa_to_sheet([headers, examples]);
@@ -93,7 +96,7 @@ function ExcelUploadCardImpl({
93
96
  XLSX.writeFile(workbook, "\uC5D1\uC140_\uC5C5\uB85C\uB4DC_\uD15C\uD50C\uB9BF.xlsx");
94
97
  } else if (templateEndpoint) {
95
98
  const res = await rawFetch(templateEndpoint, { method: "GET" });
96
- if (res.status === 503) {
99
+ if (res.status === 503 && demoModeOn503) {
97
100
  setDemoMode(true);
98
101
  setNotice({
99
102
  tone: "warning",
@@ -117,7 +120,7 @@ function ExcelUploadCardImpl({
117
120
  } finally {
118
121
  setDownloading(false);
119
122
  }
120
- }, [templateColumns, templateEndpoint]);
123
+ }, [demoModeOn503, rawFetch, templateColumns, templateEndpoint]);
121
124
  const handleServerUpload = useCallback(async () => {
122
125
  if (!file || !endpoint) return;
123
126
  setUploading(true);
@@ -131,7 +134,7 @@ function ExcelUploadCardImpl({
131
134
  return;
132
135
  }
133
136
  const res = await rawFetch(endpoint, { method: "POST", body: formData });
134
- if (res.status === 503) {
137
+ if (res.status === 503 && demoModeOn503) {
135
138
  setDemoMode(true);
136
139
  return;
137
140
  }
@@ -155,7 +158,7 @@ function ExcelUploadCardImpl({
155
158
  } finally {
156
159
  setUploading(false);
157
160
  }
158
- }, [endpoint, file, onComplete]);
161
+ }, [demoModeOn503, endpoint, file, onComplete, rawFetch, sandbox]);
159
162
  const validateRow = useCallback(
160
163
  (row) => {
161
164
  const errors = {};
@@ -174,7 +177,7 @@ function ExcelUploadCardImpl({
174
177
  setRows(null);
175
178
  try {
176
179
  const buffer = await selected.arrayBuffer();
177
- const XLSX = await loadOptionalModule(() => import('xlsx'), "xlsx");
180
+ const XLSX = await loadOptionalModule(loadXlsx, "xlsx");
178
181
  const workbook = XLSX.read(buffer, { type: "array" });
179
182
  const sheet = workbook.Sheets[workbook.SheetNames[0]];
180
183
  if (!sheet) throw new Error("\uC5D1\uC140 \uD30C\uC77C\uC5D0\uC11C \uC2DC\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
@@ -243,7 +246,7 @@ function ExcelUploadCardImpl({
243
246
  setFileName(null);
244
247
  setInputKey((key) => key + 1);
245
248
  } catch (error) {
246
- if (error?.status === 503) {
249
+ if (demoModeOn503 && error?.status === 503) {
247
250
  setDemoMode(true);
248
251
  setNotice({
249
252
  tone: "warning",
@@ -259,7 +262,7 @@ function ExcelUploadCardImpl({
259
262
  } finally {
260
263
  setImporting(false);
261
264
  }
262
- }, [endpoint, onComplete, validRows]);
265
+ }, [api, demoModeOn503, endpoint, onComplete, sandbox, validRows]);
263
266
  const previewTableColumns = useMemo(() => {
264
267
  const base = [
265
268
  {
@@ -339,6 +342,7 @@ function ExcelUploadCardImpl({
339
342
  const handleFileChange = (event) => {
340
343
  const selected = event.target.files?.[0];
341
344
  if (!selected) return;
345
+ setDemoMode(false);
342
346
  if (mode === "preview") {
343
347
  void parsePreviewFile(selected);
344
348
  } else {
package/dist/rich.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import React__default from 'react';
2
- export { b as DatePicker, D as DatePickerProps, c as DateRangePicker, a as DateRangePickerProps, d as DateRangeValue, e as TimePicker, T as TimePickerProps } from './DatePicker-BK_jsV7i.js';
2
+ export { b as DatePicker, D as DatePickerProps, c as DateRangePicker, a as DateRangePickerProps, d as DateRangeValue, e as TimePicker, T as TimePickerProps } from './DatePicker-C_TT_SOw.js';
3
3
  import './layout-C3nRXMwb.js';
4
4
 
5
5
  /**
package/dist/rich.js CHANGED
@@ -1,11 +1,10 @@
1
- import { useOptionalModule, DependencyPlaceholder } from './chunk-EKP6Z3G6.js';
2
- export { TimePicker } from './chunk-EKVA7T7P.js';
3
- import { HoistedStyle } from './chunk-I5Z2RVDF.js';
4
- export { DatePicker, DateRangePicker } from './chunk-I5Z2RVDF.js';
1
+ import { useOptionalModule, DependencyPlaceholder } from './chunk-YVTV4ZV6.js';
2
+ import { HoistedStyle } from './chunk-WSLT32Q4.js';
3
+ export { DatePicker, DateRangePicker, TimePicker } from './chunk-WSLT32Q4.js';
5
4
  import './chunk-XQPTSEJC.js';
6
- import { useSduiAssetResolver } from './chunk-DKPNFEVU.js';
7
- import { Spinner, EmptyState } from './chunk-TUOG7EEI.js';
8
- import './chunk-YQOMSWW5.js';
5
+ import { useSduiAssetResolver } from './chunk-KO6OEY3G.js';
6
+ import { Spinner, EmptyState } from './chunk-RNOUXUBO.js';
7
+ import './chunk-5WW4MBRO.js';
9
8
  import { useRef, useCallback, useMemo, useState, useEffect, useLayoutEffect } from 'react';
10
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
10
 
@@ -25,11 +24,25 @@ function useSeriesPalette(ref) {
25
24
  useLayoutEffect(() => {
26
25
  const el = ref.current;
27
26
  if (el === null) return;
28
- const computed = getComputedStyle(el);
29
- const next = SERIES_FALLBACK.map(
30
- (fallback, i) => computed.getPropertyValue(`--wp-series-${i + 1}`).trim() || fallback
31
- );
32
- setPalette((prev) => prev.every((color, i) => color === next[i]) ? prev : next);
27
+ const resolve = () => {
28
+ const computed = getComputedStyle(el);
29
+ const next = SERIES_FALLBACK.map(
30
+ (fallback, i) => computed.getPropertyValue(`--wp-series-${i + 1}`).trim() || fallback
31
+ );
32
+ setPalette((prev) => prev.every((color, i) => color === next[i]) ? prev : next);
33
+ };
34
+ resolve();
35
+ const observer = new MutationObserver(resolve);
36
+ observer.observe(document.documentElement, {
37
+ attributes: true,
38
+ attributeFilter: ["class", "data-theme"]
39
+ });
40
+ const media = typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)") : null;
41
+ media?.addEventListener("change", resolve);
42
+ return () => {
43
+ observer.disconnect();
44
+ media?.removeEventListener("change", resolve);
45
+ };
33
46
  }, [ref]);
34
47
  return palette;
35
48
  }
package/dist/styles.css CHANGED
@@ -969,10 +969,15 @@
969
969
  * ERP는 이 모양을 앱 셸 CSS(src/globals.css의 .erp-popover)로 냈고, 라이브러리에는
970
970
  * 클래스가 없어 search/popover.tsx가 같은 값을 인라인 style로 조립하고 있었다.
971
971
  * 클래스를 여기로 들여와 AutocompleteField 같은 이관 위젯이 그대로 동작하게 한다.
972
- * (이름을 erp-*로 둔 이유는 widgets/index.ts 주석과 같다 — 이관 중 두 사본이 겹쳐도
973
- * 규칙이 한 벌만 남아야 한다.)
972
+ *
973
+ * 정본 이름은 wp-popover*다(1.0) — npm 소비자가 겨눌 이름을 erp-*로 얼리면 나중의
974
+ * 개명이 그들의 CSS·e2e 선택자를 깨는 파괴적 변경이 된다. erp-*는 이관기 하위호환
975
+ * **별칭**으로 남는다: ERP 앱 셸 CSS와 이관 위젯(AutocompleteField 등)이 아직 이
976
+ * 이름을 겨누고 있어서다. 별칭 제거는 ERP 쪽 선택자 이관이 끝난 뒤에만 한다.
974
977
  */
978
+ .wp-popover-host,
975
979
  .erp-popover-host { position: relative; }
980
+ .wp-popover,
976
981
  .erp-popover {
977
982
  position: absolute; top: calc(100% + var(--wp-space-2)); right: 0; min-width: 100%;
978
983
  background: var(--wp-surface-card);
@@ -980,12 +985,15 @@
980
985
  border-radius: var(--wp-radius-lg); box-shadow: var(--wp-shadow-lg);
981
986
  z-index: var(--wp-z-dropdown);
982
987
  }
988
+ .wp-popover--left,
983
989
  .erp-popover--left { right: auto; left: 0; }
984
990
  /* 내부 스크롤을 두지 않는다 — 낮은 창에서 60vh 캡이 필드 두 줄짜리 패널마저 잘라
985
991
  컨트롤이 반쯤 걸친 채 스크롤됐다(실사용 지적, 법인차 관리). 패널은 내용만큼 크고,
986
992
  화면보다 길면 페이지가 스크롤된다. 정말 긴 목록(분류 175종)은 목록 자신이
987
993
  스크롤한다(SearchToolbar 의 옵션 목록 max-height). */
994
+ .wp-popover__body,
988
995
  .erp-popover__body { padding: var(--wp-space-4); }
996
+ .wp-popover__foot,
989
997
  .erp-popover__foot {
990
998
  display: flex; align-items: center; justify-content: space-between; gap: var(--wp-space-2);
991
999
  padding: var(--wp-space-3); border-top: var(--wp-border-w) solid var(--wp-divider);
@@ -237,27 +237,29 @@ type SduiAction = {
237
237
  onError?: SduiAction[];
238
238
  /**
239
239
  * 실패 상세를 담을 상태 키. 주면 `onError` 체인이 돌기 **직전에**
240
- * `{ status, message, body }` 를 여기 심는다.
240
+ * `{ status, message, body }` 를 여기 심는다. `request` 액션과 같은 계약이다.
241
241
  *
242
242
  * `onError` 의 이벤트 값은 예전 그대로 **문자열 메시지**다(기존 스펙 불변).
243
243
  * 상태 코드나 응답 본문으로 갈라 써야 할 때만 이 키를 준다 — 예컨대 서버가
244
244
  * 409 로 거절하며 위반 목록을 실어 보내면, 그것을 화면에 그리는 길이 여기다:
245
245
  *
246
- * { "action": "request", "endpoint": "…", "errorKey": "saveError",
246
+ * { "action": "submitForm", "form": "f", "endpoint": "…", "errorKey": "saveError",
247
247
  * "onError": [{ "action": "toast", "tone": "danger",
248
248
  * "message": { "$state": "saveError.message" } }] }
249
249
  * → ForEach source: { "$state": "saveError.body.violations" }
250
250
  *
251
251
  * `status`·`body` 는 호스트 어댑터가 오류에 얹어 줬을 때만 채워진다
252
252
  * (계약은 {@link SduiAdapter.fetch} 참고). 안 얹으면 message 만 남는다.
253
+ * 검증 실패(규칙 위반·규칙 자체의 오류)에는 심지 않는다 — 그쪽은
254
+ * `{form}.$errors`와 검증 규칙 오류 토스트의 몫이다.
253
255
  */
254
256
  errorKey?: string;
255
257
  /**
256
258
  * 진행 상태를 담을 상태 키. 요청 직전에 `true`, 끝나면(성공·실패 모두) `false`.
257
259
  *
258
- * `submitForm`이 `{form}.$submitting`을 관리하는 것과 같은 자리다 — 그쪽은 폼이
259
- * 있어 이름이 파생되지만 `request`는 폼이 없으므로 키를 받는다. 버튼의
260
- * `loading`·`disabled`를 여기 물리면 이중 제출과 무반응이 함께 사라진다.
260
+ * `{form}.$submitting` 이 이미 있는데 따로 받는 이유: 그쪽은 이름이 폼에서
261
+ * 파생되는 고정 키라, 폼 밖 버튼·여러 폼을 묶은 화면 조각이 물릴 이름을 스펙이
262
+ * 정할 수 없다. 검증에 걸려 요청이 안 나가면 켜지 않는다(`$submitting`과 다른 점).
261
263
  */
262
264
  pendingKey?: string;
263
265
  }
@@ -1,7 +1,8 @@
1
- export { ApprovalLineEditor, stepLabel, stepTypeIcon } from '../chunk-STX2AX6Y.js';
2
- import '../chunk-VDBUXYEB.js';
3
- import '../chunk-I5Z2RVDF.js';
1
+ export { ApprovalLineEditor, stepLabel, stepTypeIcon } from '../chunk-FLAN7CV3.js';
2
+ import '../chunk-Q4SWUINA.js';
3
+ import '../chunk-WOYMEEPH.js';
4
+ import '../chunk-WSLT32Q4.js';
4
5
  import '../chunk-XQPTSEJC.js';
5
- import '../chunk-DKPNFEVU.js';
6
- import '../chunk-TUOG7EEI.js';
7
- import '../chunk-YQOMSWW5.js';
6
+ import '../chunk-KO6OEY3G.js';
7
+ import '../chunk-RNOUXUBO.js';
8
+ import '../chunk-5WW4MBRO.js';
@@ -36,7 +36,17 @@ interface ApprovalOverridesEditorProps {
36
36
  searchOptions?: CustomApprover[];
37
37
  disabled?: boolean;
38
38
  }
39
+ /**
40
+ * `/employees` 응답에서 직책·직급 distinct 추출. 봉투는 공용 규칙(items/data/
41
+ * results/rows, shared.unwrapRows)으로 풀고, 키는 스네이크(실측 job_title·grade)에
42
+ * 카멜(jobTitle) 폴백을 더한다 — 응답 모양이 다른 백엔드에서 조용한 무동작이 되지
43
+ * 않게 하기 위해서다. export 는 DOM 없이 그대로 재기 위한 것.
44
+ */
45
+ declare function facetsFrom(payload: unknown): {
46
+ titles: string[];
47
+ grades: string[];
48
+ };
39
49
  /** 바깥에서 온 `style`·`className`을 뿌리에 얹어 내보낸다 — 자기 축(폭·여백)이 닿게 하는 통로. */
40
50
  declare const ApprovalOverridesEditor: React__default.FC<ApprovalOverridesEditorProps & SduiBoxProps>;
41
51
 
42
- export { type ApprovalLineOverride, ApprovalOverridesEditor, type ApprovalOverridesEditorProps };
52
+ export { type ApprovalLineOverride, ApprovalOverridesEditor, type ApprovalOverridesEditorProps, facetsFrom };
@@ -1,9 +1,10 @@
1
- export { ApprovalOverridesEditor } from '../chunk-IV5YTVHR.js';
2
- import '../chunk-JBKNIALK.js';
3
- import '../chunk-STX2AX6Y.js';
4
- import '../chunk-VDBUXYEB.js';
5
- import '../chunk-I5Z2RVDF.js';
1
+ export { ApprovalOverridesEditor, facetsFrom } from '../chunk-GE6BYNQJ.js';
2
+ import '../chunk-I5SD7XRA.js';
3
+ import '../chunk-FLAN7CV3.js';
4
+ import '../chunk-Q4SWUINA.js';
5
+ import '../chunk-WOYMEEPH.js';
6
+ import '../chunk-WSLT32Q4.js';
6
7
  import '../chunk-XQPTSEJC.js';
7
- import '../chunk-DKPNFEVU.js';
8
- import '../chunk-TUOG7EEI.js';
9
- import '../chunk-YQOMSWW5.js';
8
+ import '../chunk-KO6OEY3G.js';
9
+ import '../chunk-RNOUXUBO.js';
10
+ import '../chunk-5WW4MBRO.js';
@@ -1,3 +1,3 @@
1
- export { ApprovalStepper } from '../chunk-NYUHSMUU.js';
2
- import '../chunk-TUOG7EEI.js';
3
- import '../chunk-YQOMSWW5.js';
1
+ export { ApprovalStepper } from '../chunk-XGFDY43I.js';
2
+ import '../chunk-RNOUXUBO.js';
3
+ import '../chunk-5WW4MBRO.js';
@@ -78,6 +78,7 @@ declare function endpointSearchFn(endpoint: string, searchParam: string, hostFet
78
78
  /**
79
79
  * 응답이 배열이 아니면 items/data/results/rows 래핑까지 풀어 준다.
80
80
  * 조회를 앱이 맡게 됐으므로 이 정규화도 함께 내보낸다 — 앱마다 다시 짤 규칙이 아니다.
81
+ * 구현은 형제 위젯들과 공유한다(shared.unwrapRows) — 봉투 규칙은 한 곳에만 산다.
81
82
  */
82
83
  declare function toAutocompleteOptions(payload: unknown): AutocompleteOption[];
83
84
  /**
@@ -1,7 +1,8 @@
1
- export { AutocompleteField, endpointSearchFn, toAutocompleteOptions } from '../chunk-YSSNP6JM.js';
2
- import '../chunk-VDBUXYEB.js';
3
- import '../chunk-I5Z2RVDF.js';
1
+ export { AutocompleteField, endpointSearchFn, toAutocompleteOptions } from '../chunk-N25YP7ID.js';
2
+ import '../chunk-Q4SWUINA.js';
3
+ import '../chunk-WOYMEEPH.js';
4
+ import '../chunk-WSLT32Q4.js';
4
5
  import '../chunk-XQPTSEJC.js';
5
- import '../chunk-DKPNFEVU.js';
6
- import '../chunk-TUOG7EEI.js';
7
- import '../chunk-YQOMSWW5.js';
6
+ import '../chunk-KO6OEY3G.js';
7
+ import '../chunk-RNOUXUBO.js';
8
+ import '../chunk-5WW4MBRO.js';
@@ -1,3 +1,3 @@
1
- export { ColumnBoard } from '../chunk-6BCWFPNJ.js';
2
- import '../chunk-TUOG7EEI.js';
3
- import '../chunk-YQOMSWW5.js';
1
+ export { ColumnBoard } from '../chunk-YWUDBLO6.js';
2
+ import '../chunk-RNOUXUBO.js';
3
+ import '../chunk-5WW4MBRO.js';
@@ -1,3 +1,3 @@
1
- export { DiffView } from '../chunk-M6KM3FJS.js';
2
- import '../chunk-TUOG7EEI.js';
3
- import '../chunk-YQOMSWW5.js';
1
+ export { DiffView } from '../chunk-JYAR7D5U.js';
2
+ import '../chunk-RNOUXUBO.js';
3
+ import '../chunk-5WW4MBRO.js';
@@ -1,3 +1,3 @@
1
- export { Disclosure } from '../chunk-OEWTVLPZ.js';
2
- import '../chunk-TUOG7EEI.js';
3
- import '../chunk-YQOMSWW5.js';
1
+ export { Disclosure } from '../chunk-2HLXCKK7.js';
2
+ import '../chunk-RNOUXUBO.js';
3
+ import '../chunk-5WW4MBRO.js';
@@ -52,13 +52,28 @@ interface EventCalendarProps {
52
52
  onDateChange?: (date: string) => void;
53
53
  /** 유형 필터 칩. 주어지면 칩 토글로 해당 type 일정을 숨기거나 보인다. */
54
54
  types?: EventCalendarTypeOption[];
55
+ /**
56
+ * 상태 문자열 → 배지 톤(정확 일치). 기본 판정은 자산 대여 ERP의 상태 어휘
57
+ * (반납·대여중·수리중·분실 …)를 아는 정규식 폴백이라, 다른 도메인의 상태
58
+ * ('confirmed'·'휴가' 등)는 여기로 톤을 지정한다. 맵에 없거나 톤 값이 잘못된
59
+ * 상태는 기본 판정으로 떨어진다 — 프롭 없는 기존 스펙은 이전과 똑같이 렌더된다.
60
+ */
61
+ statusTones?: Record<string, EventCalendarStatusTone>;
55
62
  onEventClick?: (event: EventCalendarEvent) => void;
56
63
  selectedId?: string;
57
64
  }
65
+ declare const STATUS_TONES: readonly ["neutral", "info", "success", "warning", "danger"];
66
+ type EventCalendarStatusTone = (typeof STATUS_TONES)[number];
67
+ /**
68
+ * 상태 → 톤. 주입 맵(`statusTones`, 정확 일치)이 우선이고, 없으면 자산 대여 ERP
69
+ * 시절의 정규식 판정으로 떨어진다. 스펙은 신뢰할 수 없는 JSON이라 맵의 톤 값이
70
+ * 다섯 가지 밖이면 버린다 — Badge에 모르는 tone을 흘리지 않는다.
71
+ */
72
+ declare const statusToneOf: (status: string, overrides?: Record<string, EventCalendarStatusTone>) => EventCalendarStatusTone;
58
73
  /**
59
74
  * 바깥에서 온 `style`·`className`을 뿌리에 얹어 내보낸다 — 자식 축(`grow`·`width` …)이
60
75
  * 이 컴포넌트에서도 동작하게 하는 유일한 통로다. 까닭은 {@link ../boxed.tsx}에 있다.
61
76
  */
62
77
  declare const EventCalendar: React.FC<EventCalendarProps & SduiBoxProps>;
63
78
 
64
- export { EventCalendar, type EventCalendarEvent, type EventCalendarProps, type EventCalendarTypeOption, type EventCalendarView, type EventCalendarViewItem };
79
+ export { EventCalendar, type EventCalendarEvent, type EventCalendarProps, type EventCalendarStatusTone, type EventCalendarTypeOption, type EventCalendarView, type EventCalendarViewItem, statusToneOf };