@kengcom202/kcore-ui 0.6.0 → 0.7.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.
package/README.md CHANGED
@@ -8,7 +8,7 @@ Angular 22 UI กลาง — ไม่พึ่งไลบรารีภา
8
8
  - `<app-search-select>` — dropdown พิมพ์ค้นหาได้ ค่าเป็น `value` ของ `SearchOption` (`''` = ไม่ระบุ) ปรับสีด้วย `--kc-ss-*`
9
9
  - `provideThaiPasteFix()` — ใส่ใน `app.config.ts` ครั้งเดียว แก้ข้อความไทยที่คัดลอกจาก PDF (□ แทนวรรณยุกต์, ช่องว่างหน้าวรรณยุกต์, "ํา") ตอนวางลงทุกช่อง
10
10
  - หน้าบัญชีผู้ใช้กลาง — `provideKcAuth({...})` + `kcAuthInterceptor` + `kcAuthRoutes()` (`/login`, `/register`, `/sso-callback`, `/thaid-callback`) — ปุ่ม SSO (`sso`) และ ThaiD (`thaid` เข้าสู่ระบบอย่างเดียว)
11
- และ `<kc-profile>`, `<kc-config-users>`, `<kc-config-kcllu>` คู่กับ `kcAuthGuard` / `kcAdminGuard`, `KcAuthService` — API ต้องทำ endpoint ตามสัญญาใน README ของรีโป kcore
11
+ และ `<kc-profile>`, `<kc-config-users>`, `<kc-config-kcllu>` คู่กับ `kcAuthGuard` / `kcAdminGuard`, `KcAuthService` — API ต้องทำ endpoint ตามสัญญาใน `README_NPM.md` ของรีโป kcore
12
12
  - utils: `toBuddhistText`, `toChristianText`, `parseDate`, `formatDate`, `fixThaiText`
13
13
 
14
14
  ```ts
@@ -1,5 +1,5 @@
1
1
  import * as i0 from "@angular/core";
2
- import { ApplicationRef, CSP_NONCE, Component, DOCUMENT, DestroyRef, Directive, ElementRef, EnvironmentInjector, Injectable, InjectionToken, NgZone, ViewChild, ViewEncapsulation, computed, createComponent, forwardRef, inject, input, makeEnvironmentProviders, provideEnvironmentInitializer, signal } from "@angular/core";
2
+ import { ApplicationRef, CSP_NONCE, Component, DOCUMENT, DestroyRef, Directive, ElementRef, EnvironmentInjector, Injectable, InjectionToken, NgZone, ViewChild, ViewEncapsulation, computed, createComponent, effect, forwardRef, inject, input, makeEnvironmentProviders, provideEnvironmentInitializer, signal, untracked } from "@angular/core";
3
3
  import * as i1 from "@angular/forms";
4
4
  import { FormBuilder, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule, Validators } from "@angular/forms";
5
5
  import { HttpClient, HttpErrorResponse } from "@angular/common/http";
@@ -1610,6 +1610,8 @@ const kcAuthInterceptor = (req, next) => {
1610
1610
  const STYLE_ID = "kcore-auth-styles";
1611
1611
  const AUTH_CSS = `
1612
1612
  .kc-auth-screen, .kc-auth-page, .kc-auth-modal-bg {
1613
+ /* ค่าเริ่มต้นใช้ฟอนต์ของเว็บ — เว็บที่ body ใช้ฟอนต์เฉพาะทาง (เช่น TH Sarabun ของหน้าพิมพ์) ตั้งฟอนต์ของหน้าชุดนี้แยกได้ */
1614
+ font-family: var(--kc-auth-font-family, inherit);
1613
1615
  font-size: var(--kc-auth-font-size, 14px);
1614
1616
  color: var(--kc-auth-text, #3a2a3a);
1615
1617
  line-height: 1.5;
@@ -1618,6 +1620,8 @@ const AUTH_CSS = `
1618
1620
 
1619
1621
  /* ---- หน้าเต็มจอ (login / register / sso-callback) ---- */
1620
1622
  .kc-auth-screen {
1623
+ /* border-box: padding อยู่ใน 100vh — ไม่งั้นสูงเกินจอ 48px และมี scrollbar ทั้งที่เนื้อหาน้อย */
1624
+ box-sizing: border-box;
1621
1625
  min-height: 100vh;
1622
1626
  display: flex;
1623
1627
  align-items: center;
@@ -1627,16 +1631,23 @@ const AUTH_CSS = `
1627
1631
  }
1628
1632
  .kc-auth-card {
1629
1633
  width: 100%;
1630
- max-width: 380px;
1631
- padding: 28px 28px 24px;
1634
+ max-width: var(--kc-auth-card-width, 380px);
1635
+ /* ขนาดกรอบของหน้าเต็มจอปรับได้ เช่น สูง 80vh แล้วขยายตัวอักษร/ช่องกรอก/โลโก้ตามความสูงจอ — ค่าเริ่มต้น = ขนาดเดิม */
1636
+ min-height: var(--kc-auth-card-height, auto);
1637
+ display: flex;
1638
+ flex-direction: column;
1639
+ justify-content: center;
1640
+ padding: var(--kc-auth-card-padding, 28px 28px 24px);
1641
+ font-size: var(--kc-auth-card-font-size, inherit);
1632
1642
  background: var(--kc-auth-bg, #fff);
1633
1643
  border: 1px solid var(--kc-auth-border, #f3e1f3);
1634
1644
  border-radius: var(--kc-auth-radius, 14px);
1635
1645
  box-shadow: 0 12px 36px rgba(204, 102, 204, 0.12);
1636
1646
  }
1637
- .kc-auth-card.wide { max-width: 560px; }
1647
+ .kc-auth-card.wide { max-width: var(--kc-auth-card-wide-width, 560px); }
1638
1648
  .kc-auth-card.center { text-align: center; }
1639
- .kc-auth-logo { display: block; max-height: 72px; max-width: 100%; margin: 0 auto 12px; }
1649
+ .kc-auth-card .kc-auth-input, .kc-auth-card .kc-auth-btn { height: var(--kc-auth-card-input-height, var(--kc-auth-input-height, 40px)); }
1650
+ .kc-auth-logo { display: block; max-height: var(--kc-auth-logo-height, 72px); max-width: 100%; margin: 0 auto 12px; }
1640
1651
  .kc-auth-title { margin: 0; font-size: 1.35em; font-weight: 600; text-align: center; }
1641
1652
  .kc-auth-subtitle { margin: 4px 0 20px; color: var(--kc-auth-muted, #806f80); text-align: center; }
1642
1653
  .kc-auth-footer { margin: 18px 0 0; text-align: center; color: var(--kc-auth-muted, #806f80); font-size: 0.93em; }
@@ -1699,6 +1710,8 @@ const AUTH_CSS = `
1699
1710
  .kc-auth-pw > .kc-auth-input { padding-right: 42px; }
1700
1711
  .kc-auth-pw > input::-ms-reveal, .kc-auth-pw > input::-ms-clear { display: none; }
1701
1712
  .kc-auth-pw-toggle {
1713
+ /* <button> ไม่รับขนาดตัวอักษรจากแม่ (browser ตั้ง ~13px) — ต้อง inherit ไม่งั้นขนาด em ของไอคอนไม่ขยายตามกรอบ */
1714
+ font: inherit;
1702
1715
  position: absolute;
1703
1716
  top: 50%;
1704
1717
  right: 5px;
@@ -1727,6 +1740,20 @@ const AUTH_CSS = `
1727
1740
  --kc-ss-border: var(--kc-auth-input-border, #e9cde9);
1728
1741
  --kc-ss-text: var(--kc-auth-text, #3a2a3a);
1729
1742
  }
1743
+ .kc-auth-card .kc-auth-field .kc-ss { --kc-ss-height: var(--kc-auth-card-input-height, var(--kc-auth-input-height, 40px)); }
1744
+ /* ในกรอบหน้าเต็มจอ ขนาดย่อยทั้งหมดเป็น em ของตัวอักษรในกรอบ (= px เดิมที่ 14px) — ตั้ง --kc-auth-card-font-size
1745
+ แล้วไอคอน ระยะห่าง และ padding ขยาย/หดตามสัดส่วนเดียวกัน */
1746
+ .kc-auth-card .kc-auth-logo { margin-bottom: 0.86em; }
1747
+ .kc-auth-card .kc-auth-subtitle { margin: 0.3em 0 1.43em; }
1748
+ .kc-auth-card .kc-auth-footer { margin-top: 1.3em; }
1749
+ .kc-auth-card .kc-auth-field { gap: 0.3em; margin-bottom: 0.86em; }
1750
+ .kc-auth-card .kc-auth-input { padding: 0 0.72em; border-radius: 0.57em; }
1751
+ .kc-auth-card .kc-auth-pw > .kc-auth-input { padding-right: 3em; }
1752
+ .kc-auth-card .kc-auth-pw-toggle { right: 0.36em; width: 2.3em; height: 2.3em; border-radius: 0.43em; }
1753
+ .kc-auth-card .kc-auth-pw-toggle svg { width: 1.36em; height: 1.36em; }
1754
+ .kc-auth-card .kc-auth-btn { padding: 0 1.15em; border-radius: 0.57em; gap: 0.43em; }
1755
+ .kc-auth-card .kc-auth-btn-row { gap: 0.72em; margin-top: 0.43em; }
1756
+ .kc-auth-card .kc-auth-alert { padding: 0.72em 0.86em; margin-bottom: 1em; border-radius: 0.43em; }
1730
1757
  .kc-auth-value { padding: 8px 0; }
1731
1758
  .kc-auth-field-error { color: var(--kc-auth-danger, #c62828); font-size: 0.86em; }
1732
1759
  .kc-auth-hint { margin: 2px 0 0; color: var(--kc-auth-muted, #806f80); font-size: 0.86em; }
@@ -1777,6 +1804,7 @@ const AUTH_CSS = `
1777
1804
  /* ปิดรหัสผ่าน: ปุ่ม SSO ปุ่มเดียวตรงกลาง */
1778
1805
  .kc-auth-sso-only { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 8px 0 4px; }
1779
1806
  .kc-auth-sso-only > .kc-auth-btn { min-width: 75%; height: 46px; padding: 0 24px; font-size: 1.05em; }
1807
+ .kc-auth-card .kc-auth-sso-only > .kc-auth-btn { height: calc(var(--kc-auth-card-input-height, var(--kc-auth-input-height, 40px)) * 1.15); padding: 0 1.7em; }
1780
1808
  .kc-auth-btn.block { display: flex; width: 100%; }
1781
1809
  .kc-auth-btn.sm { height: 30px; padding: 0 10px; font-size: 0.93em; }
1782
1810
  .kc-auth-link { color: var(--kc-auth-accent, #a23ea2); text-decoration: none; cursor: pointer; }
@@ -3423,6 +3451,7 @@ var KcConfigUsersComponent = class KcConfigUsersComponent {
3423
3451
  config = inject(KC_AUTH_CONFIG);
3424
3452
  auth = inject(KcAuthService);
3425
3453
  http = inject(HttpClient);
3454
+ org = input("", ...ngDevMode ? [{ debugName: "org" }] : /* istanbul ignore next */ []);
3426
3455
  users = signal([], ...ngDevMode ? [{ debugName: "users" }] : /* istanbul ignore next */ []);
3427
3456
  orgs = signal([], ...ngDevMode ? [{ debugName: "orgs" }] : /* istanbul ignore next */ []);
3428
3457
  roles = signal([], ...ngDevMode ? [{ debugName: "roles" }] : /* istanbul ignore next */ []);
@@ -3483,9 +3512,12 @@ var KcConfigUsersComponent = class KcConfigUsersComponent {
3483
3512
  }, ...ngDevMode ? [{ debugName: "filtered" }] : /* istanbul ignore next */ []);
3484
3513
  constructor() {
3485
3514
  ensureAuthStyles();
3515
+ effect(() => {
3516
+ this.org();
3517
+ untracked(() => this.load());
3518
+ });
3486
3519
  }
3487
3520
  ngOnInit() {
3488
- this.load();
3489
3521
  this.http.get(`${this.config.apiBase}/user/login-methods`).subscribe({
3490
3522
  next: (m) => {
3491
3523
  const v = {
@@ -3534,7 +3566,9 @@ var KcConfigUsersComponent = class KcConfigUsersComponent {
3534
3566
  }
3535
3567
  load() {
3536
3568
  this.loading.set(true);
3537
- this.http.get(`${this.config.apiBase}/config/users`).subscribe({
3569
+ const org = this.org();
3570
+ const params = org ? { org } : {};
3571
+ this.http.get(`${this.config.apiBase}/config/users`, { params }).subscribe({
3538
3572
  next: (res) => {
3539
3573
  this.users.set(res.users ?? []);
3540
3574
  this.orgs.set(res.orgs ?? []);
@@ -3611,6 +3645,13 @@ var KcConfigUsersComponent = class KcConfigUsersComponent {
3611
3645
  type: KcConfigUsersComponent,
3612
3646
  isStandalone: true,
3613
3647
  selector: "kc-config-users",
3648
+ inputs: { org: {
3649
+ classPropertyName: "org",
3650
+ publicName: "org",
3651
+ isSignal: true,
3652
+ isRequired: false,
3653
+ transformFunction: null
3654
+ } },
3614
3655
  host: { listeners: { "document:keydown.escape": "close()" } },
3615
3656
  ngImport: i0,
3616
3657
  template: `
@@ -4001,7 +4042,15 @@ i0.ɵɵngDeclareClassMetadata({
4001
4042
  `
4002
4043
  }]
4003
4044
  }],
4004
- ctorParameters: () => []
4045
+ ctorParameters: () => [],
4046
+ propDecorators: { org: [{
4047
+ type: i0.Input,
4048
+ args: [{
4049
+ isSignal: true,
4050
+ alias: "org",
4051
+ required: false
4052
+ }]
4053
+ }] }
4005
4054
  });
4006
4055
  var KcConfigKclluComponent = class KcConfigKclluComponent {
4007
4056
  config = inject(KC_AUTH_CONFIG);