@iyulab/enterprise 0.7.0 → 0.8.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.
@@ -2,6 +2,7 @@
2
2
  * @iyulab/enterprise Helpers
3
3
  * Reusable utility classes for enterprise applications
4
4
  */
5
+ export * from './messages';
5
6
  export * from './CurrencyHelper';
6
7
  export * from './DateHelper';
7
8
  export * from './ProgressHelper';
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `@iyulab/enterprise` 의 화면 문자열 — **영어 기본 + 로케일 레지스트리**.
3
+ *
4
+ * ## 왜 이 파일이 생겼나
5
+ *
6
+ * 헬퍼들이 라벨을 **한국어 리터럴로** 들고 있었다(실측 14건). 이 리포는 이미 로케일 표준을
7
+ * 채택했지만(영어 기본 + 레지스트리) **강제하는 장치가 없어서** 채택 이후에 들어온 코드가
8
+ * 한국어 기본값을 갖고 있었다.
9
+ *
10
+ * ⚠**「의견 있음」이 정당화하는 것은 스타일 값의 의견이지 언어가 아니다**(2026-08-04 결정).
11
+ *
12
+ * ## 왜 자체 레지스트리를 만들지 않았나
13
+ *
14
+ * `@iyulab/components` 의 `Locale.namespace()`(1.23.0~)를 쓴다. 자체 구현은 이 조직의
15
+ * **네 번째 레지스트리**가 됐을 것이고, 그러면 소비자가 앱 하나에서 로케일을 **두 번**
16
+ * 전환해야 한다. `Locale.set()` 한 번으로 검증 메시지·이 라벨이 함께 따라온다.
17
+ *
18
+ * ## 동작 변화
19
+ *
20
+ * ⚠기본 로케일은 브라우저 언어에서 감지된다 — **한국어 브라우저는 종전과 같은 문구**를 본다
21
+ * (`ko-KR` → `ko`). 그 밖의 환경은 한국어 대신 **영어**를 본다. 그것이 이 이주의 목적이다.
22
+ */
23
+ export type EnterpriseMessageKey = 'progressNotStarted' | 'progressEarly' | 'progressInProgress' | 'progressPastMid' | 'progressAlmost' | 'progressDone' | 'urgencyOverdue' | 'urgencyCritical' | 'urgencyUrgent' | 'urgencySoon' | 'urgencyNormal' | 'daysOverdue' | 'daysToday' | 'daysRemaining';
24
+ /** 이 패키지의 문자열 묶음. 소비자는 `messages.register(locale, table)` 로 덮거나 언어를 더한다. */
25
+ export declare const messages: any;
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Locale } from "@iyulab/components";
2
3
  import { HttpClient } from "@iyulab/http-client";
3
4
  import buildQuery from "odata-query";
4
5
  //#region src/FormSection.tsx
@@ -79,6 +80,42 @@ function FormRow({ children, full, columns = 2, className, style }) {
79
80
  });
80
81
  }
81
82
  //#endregion
83
+ //#region src/helpers/messages.ts
84
+ /** 이 패키지의 문자열 묶음. 소비자는 `messages.register(locale, table)` 로 덮거나 언어를 더한다. */
85
+ var messages = Locale.namespace("@iyulab/enterprise");
86
+ messages.register("en", {
87
+ progressNotStarted: "Not started",
88
+ progressEarly: "Early stage",
89
+ progressInProgress: "In progress",
90
+ progressPastMid: "Past halfway",
91
+ progressAlmost: "Almost done",
92
+ progressDone: "Done",
93
+ urgencyOverdue: "Overdue",
94
+ urgencyCritical: "Critical",
95
+ urgencyUrgent: "Urgent",
96
+ urgencySoon: "Due soon",
97
+ urgencyNormal: "On track",
98
+ daysOverdue: "{days} days overdue",
99
+ daysToday: "Today",
100
+ daysRemaining: "{days} days left"
101
+ });
102
+ messages.register("ko", {
103
+ progressNotStarted: "시작 전",
104
+ progressEarly: "초기 단계",
105
+ progressInProgress: "진행 중",
106
+ progressPastMid: "중반 이상",
107
+ progressAlmost: "거의 완료",
108
+ progressDone: "완료",
109
+ urgencyOverdue: "지연",
110
+ urgencyCritical: "매우 급함",
111
+ urgencyUrgent: "급함",
112
+ urgencySoon: "곧 도래",
113
+ urgencyNormal: "여유",
114
+ daysOverdue: "{days}일 지연",
115
+ daysToday: "오늘",
116
+ daysRemaining: "{days}일"
117
+ });
118
+ //#endregion
82
119
  //#region src/helpers/CurrencyHelper.ts
83
120
  /**
84
121
  * Currency formatting utility class
@@ -295,12 +332,12 @@ var ProgressHelper = class {
295
332
  */
296
333
  static getProgressLabel(progress) {
297
334
  const validated = this.validateProgress(progress);
298
- if (validated === 0) return "시작 전";
299
- if (validated < 25) return "초기 단계";
300
- if (validated < 50) return "진행 중";
301
- if (validated < 75) return "중반 이상";
302
- if (validated < 100) return "거의 완료";
303
- return "완료";
335
+ if (validated === 0) return messages.text("progressNotStarted");
336
+ if (validated < 25) return messages.text("progressEarly");
337
+ if (validated < 50) return messages.text("progressInProgress");
338
+ if (validated < 75) return messages.text("progressPastMid");
339
+ if (validated < 100) return messages.text("progressAlmost");
340
+ return messages.text("progressDone");
304
341
  }
305
342
  /**
306
343
  * Calculate progress from current and total values
@@ -373,11 +410,11 @@ var UrgencyHelper = class {
373
410
  */
374
411
  static getUrgencyText(daysRemaining, config, labels) {
375
412
  const defaultLabels = {
376
- overdue: "지연",
377
- critical: "매우 급함",
378
- urgent: "급함",
379
- soon: "곧 도래",
380
- normal: "여유"
413
+ overdue: messages.text("urgencyOverdue"),
414
+ critical: messages.text("urgencyCritical"),
415
+ urgent: messages.text("urgencyUrgent"),
416
+ soon: messages.text("urgencySoon"),
417
+ normal: messages.text("urgencyNormal")
381
418
  };
382
419
  const level = this.getUrgencyLevel(daysRemaining, config);
383
420
  return labels?.[level] || defaultLabels[level];
@@ -421,9 +458,9 @@ var UrgencyHelper = class {
421
458
  */
422
459
  static formatDaysRemaining(daysRemaining) {
423
460
  if (daysRemaining === null || daysRemaining === void 0) return "-";
424
- if (daysRemaining < 0) return `${Math.abs(daysRemaining)}일 지연`;
425
- if (daysRemaining === 0) return "오늘";
426
- return `${daysRemaining}일`;
461
+ if (daysRemaining < 0) return messages.text("daysOverdue", { days: Math.abs(daysRemaining) });
462
+ if (daysRemaining === 0) return messages.text("daysToday");
463
+ return messages.text("daysRemaining", { days: daysRemaining });
427
464
  }
428
465
  /**
429
466
  * Check if deadline is overdue
@@ -945,4 +982,4 @@ function createAuthClient(config) {
945
982
  };
946
983
  }
947
984
  //#endregion
948
- export { ApiConfig, ApiError, CurrencyHelper, DateHelper, FormRow, FormSection, ProgressHelper, UrgencyHelper, clearPermissions, createAuthClient, createODataService, createPermissionStore, defaultPermissionStore, getPermissions, hasAllPermissions, hasAnyPermission, hasPermission, setPermissions };
985
+ export { ApiConfig, ApiError, CurrencyHelper, DateHelper, FormRow, FormSection, ProgressHelper, UrgencyHelper, clearPermissions, createAuthClient, createODataService, createPermissionStore, defaultPermissionStore, getPermissions, hasAllPermissions, hasAnyPermission, hasPermission, messages, setPermissions };
@@ -23,11 +23,19 @@
23
23
  * ⑵ **`--u-*` 값만 덮는다.** 새 클래스·새 선택자를 만들지 않는다. 만들기 시작하면
24
24
  * 소비자가 그 선택자와 특이도 싸움을 하게 되고, 그때부터 이 파일은 프리셋이 아니라
25
25
  * 또 하나의 프레임워크가 된다. (`tests/preset-contract.test.ts` 가 지킨다.)
26
- * ⑶ 🔴**소비자가 항상 이긴다.** 아래 선택자는 `:where()` 감싸 **특이도 0** 이다 —
27
- * 소비앱의 평범한 `:root { }` 한 줄이 **로드 순서와 무관하게** 이 값을 덮는다.
28
- * ★종전에 소비앱들이 `:root:not([theme="dark"])` 같은 **특이도 방어**를 쓰고 있었는데,
29
- * 그것은 업스트림이 `:root` 로 선언해 "뒤에 온 쪽이 이기는" 상황을 만들었기 때문이다.
30
- * 특이도 0 으로 선언하면 그 방어가 통째로 필요 없어진다.
26
+ * ⑶ 🔴**층은 «로드 순서»로 선다.** 층이 전부 `:root`(0,1,0)이므로 나중에 로드된
27
+ * 것이 이긴다 소비자가 이미 통제하는 축이다.
28
+ *
29
+ * 기본값(components/styles/light.css) → 하우스(이 파일) → 소비자 브랜드
30
+ *
31
+ * ⚠**종전 판(0.7.0)은 이 자리를 `:where()` 로 감싸 특이도 0 으로 만들었고,
32
+ * 그래서 «한 줄도 적용되지 않았다».** 의도는 옳았다 — *"프리셋이 소비자 브랜드를
33
+ * 덮으면 안 된다"*. 그러나 특이도 0 은 **이겨야 할 상대(기본값)와 지지 말아야 할
34
+ * 상대(브랜드)를 구분하지 못한다.** 기본 시트가 같은 토큰을 `:root` 로 선언하므로
35
+ * 구조적으로 졌다. 실측: 이 파일의 40선언 중 **기본 시트에 없는 것이 0개** —
36
+ * `:where()` 가 이길 수 있는 자리가 하나도 없었다.
37
+ * ★그리고 **그 실패는 조용했다.** 오류도 경고도 없고, 소비자에게는
38
+ * *"프리셋 값이 우리 값과 우연히 같았나 보다"* 로 보인다.
31
39
  *
32
40
  * ──────────────────────────────────────────────────────────────────────────
33
41
  * 이 프리셋이 정하는 것 / 정하지 않는 것
@@ -39,7 +47,7 @@
39
47
  * 안 정한다 **브랜드 색** — 그것은 소비앱의 몫이다. 프리셋은 브랜드를 갖지 않는다.
40
48
  * ========================================================================== */
41
49
 
42
- :where(:root) {
50
+ :root {
43
51
  /* ==========================================================================
44
52
  타이포 — LOB 밀도
45
53
  ★업무 화면은 한 화면에 담기는 정보량이 곧 생산성이다. 중립 기본값보다 한 단씩
@@ -120,7 +128,7 @@
120
128
  * ★어두운 배경 위의 검은 그림자는 보이지 않는다. 알파를 라이트보다 크게 잡되,
121
129
  * 깊이의 대부분은 표면 밝기 차(`--u-bg-color-raised` 등, `components` 소유)가 낸다.
122
130
  */
123
- :where(:root[theme='dark']) {
131
+ :root[theme='dark'] {
124
132
  --u-shadow-color-weaker: rgba(0, 0, 0, 0.20);
125
133
  --u-shadow-color-weak: rgba(0, 0, 0, 0.28);
126
134
  --u-shadow-color-normal: rgba(0, 0, 0, 0.36);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iyulab/enterprise",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Enterprise utilities and components for iyulab framework",
5
5
  "keywords": [
6
6
  "enterprise",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "peerDependencies": {
47
47
  "react": ">=18",
48
- "@iyulab/components": ">=1.21.0"
48
+ "@iyulab/components": ">=1.23.0"
49
49
  },
50
50
  "peerDependenciesMeta": {
51
51
  "@iyulab/components": {