@geoit/ui 0.0.2

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 (165) hide show
  1. package/AGENTS.md +25 -0
  2. package/README.md +46 -0
  3. package/ai/AGENTS.md +86 -0
  4. package/ai/README.md +44 -0
  5. package/ai/catalog.json +882 -0
  6. package/ai/components/geo-alert.md +56 -0
  7. package/ai/components/geo-back-button.md +54 -0
  8. package/ai/components/geo-breadcrumb.md +52 -0
  9. package/ai/components/geo-button.md +63 -0
  10. package/ai/components/geo-checkbox.md +54 -0
  11. package/ai/components/geo-column-picker.md +54 -0
  12. package/ai/components/geo-confirm-modal.md +70 -0
  13. package/ai/components/geo-date-picker.md +65 -0
  14. package/ai/components/geo-date-range-picker.md +64 -0
  15. package/ai/components/geo-file-picker.md +62 -0
  16. package/ai/components/geo-form-modal.md +88 -0
  17. package/ai/components/geo-icon.md +53 -0
  18. package/ai/components/geo-input.md +65 -0
  19. package/ai/components/geo-page-title.md +53 -0
  20. package/ai/components/geo-pagination.md +59 -0
  21. package/ai/components/geo-radio.md +67 -0
  22. package/ai/components/geo-row-actions.md +54 -0
  23. package/ai/components/geo-select.md +68 -0
  24. package/ai/components/geo-slider.md +56 -0
  25. package/ai/components/geo-status-tag.md +51 -0
  26. package/ai/components/geo-step-form-layout.md +81 -0
  27. package/ai/components/geo-stepper.md +63 -0
  28. package/ai/components/geo-table-filter.md +65 -0
  29. package/ai/components/geo-table-pagination.md +59 -0
  30. package/ai/components/geo-table-toolbar.md +64 -0
  31. package/ai/components/geo-table.md +98 -0
  32. package/ai/components/geo-tabs.md +62 -0
  33. package/ai/components/geo-textarea.md +59 -0
  34. package/ai/components/geo-toast.md +61 -0
  35. package/ai/components/geo-tree.md +58 -0
  36. package/ai/components/geo-typography.md +57 -0
  37. package/ai/components/geo-upload.md +78 -0
  38. package/ai/recipes.md +111 -0
  39. package/esm2022/geoit-ui.mjs +5 -0
  40. package/esm2022/lib/figma/geo-alert/geo-alert.component.mjs +58 -0
  41. package/esm2022/lib/figma/geo-alert/geo-alert.types.mjs +7 -0
  42. package/esm2022/lib/figma/geo-back-button/geo-back-button.component.mjs +48 -0
  43. package/esm2022/lib/figma/geo-breadcrumb/geo-breadcrumb.component.mjs +33 -0
  44. package/esm2022/lib/figma/geo-breadcrumb/geo-breadcrumb.types.mjs +2 -0
  45. package/esm2022/lib/figma/geo-button/geo-button.component.mjs +77 -0
  46. package/esm2022/lib/figma/geo-button/geo-button.types.mjs +2 -0
  47. package/esm2022/lib/figma/geo-checkbox/geo-checkbox.component.mjs +34 -0
  48. package/esm2022/lib/figma/geo-confirm-modal/geo-confirm-modal.component.mjs +76 -0
  49. package/esm2022/lib/figma/geo-confirm-modal/geo-confirm-modal.types.mjs +2 -0
  50. package/esm2022/lib/figma/geo-date-picker/geo-date-picker.component.mjs +119 -0
  51. package/esm2022/lib/figma/geo-date-picker/geo-date-picker.types.mjs +2 -0
  52. package/esm2022/lib/figma/geo-date-range-picker/geo-date-range-picker.component.mjs +116 -0
  53. package/esm2022/lib/figma/geo-date-range-picker/geo-date-range-picker.types.mjs +2 -0
  54. package/esm2022/lib/figma/geo-file-picker/geo-file-picker.component.mjs +145 -0
  55. package/esm2022/lib/figma/geo-file-picker/geo-file-picker.types.mjs +2 -0
  56. package/esm2022/lib/figma/geo-form-modal/geo-form-modal.component.mjs +153 -0
  57. package/esm2022/lib/figma/geo-icon/geo-icon.component.mjs +51 -0
  58. package/esm2022/lib/figma/geo-icon/geo-icon.types.mjs +8 -0
  59. package/esm2022/lib/figma/geo-input/geo-input.component.mjs +118 -0
  60. package/esm2022/lib/figma/geo-page-title/geo-page-title.component.mjs +51 -0
  61. package/esm2022/lib/figma/geo-pagination/geo-pagination.component.mjs +54 -0
  62. package/esm2022/lib/figma/geo-radio/geo-radio.component.mjs +95 -0
  63. package/esm2022/lib/figma/geo-radio/geo-radio.types.mjs +2 -0
  64. package/esm2022/lib/figma/geo-select/geo-select.component.mjs +113 -0
  65. package/esm2022/lib/figma/geo-select/geo-select.types.mjs +2 -0
  66. package/esm2022/lib/figma/geo-slider/geo-slider.component.mjs +43 -0
  67. package/esm2022/lib/figma/geo-status-tag/geo-status-tag.component.mjs +62 -0
  68. package/esm2022/lib/figma/geo-status-tag/geo-status-tag.types.mjs +30 -0
  69. package/esm2022/lib/figma/geo-step-form-layout/geo-step-form-layout.component.mjs +157 -0
  70. package/esm2022/lib/figma/geo-step-form-layout/geo-step-form-layout.types.mjs +2 -0
  71. package/esm2022/lib/figma/geo-stepper/geo-stepper.component.mjs +77 -0
  72. package/esm2022/lib/figma/geo-stepper/geo-stepper.types.mjs +2 -0
  73. package/esm2022/lib/figma/geo-table/geo-column-picker/geo-column-picker.component.mjs +65 -0
  74. package/esm2022/lib/figma/geo-table/geo-column-picker/geo-column-picker.storage.mjs +31 -0
  75. package/esm2022/lib/figma/geo-table/geo-column-picker/geo-column-picker.types.mjs +2 -0
  76. package/esm2022/lib/figma/geo-table/geo-row-actions/geo-row-actions.component.mjs +64 -0
  77. package/esm2022/lib/figma/geo-table/geo-row-actions/geo-row-actions.types.mjs +24 -0
  78. package/esm2022/lib/figma/geo-table/geo-table-filter/geo-table-filter.component.mjs +195 -0
  79. package/esm2022/lib/figma/geo-table/geo-table-pagination/geo-table-pagination.component.mjs +118 -0
  80. package/esm2022/lib/figma/geo-table/geo-table-toolbar/geo-table-toolbar.component.mjs +68 -0
  81. package/esm2022/lib/figma/geo-table/geo-table.component.mjs +381 -0
  82. package/esm2022/lib/figma/geo-table/geo-table.types.mjs +4 -0
  83. package/esm2022/lib/figma/geo-tabs/geo-tabs.component.mjs +94 -0
  84. package/esm2022/lib/figma/geo-tabs/geo-tabs.types.mjs +2 -0
  85. package/esm2022/lib/figma/geo-textarea/geo-textarea.component.mjs +85 -0
  86. package/esm2022/lib/figma/geo-toast/geo-toast.component.mjs +57 -0
  87. package/esm2022/lib/figma/geo-toast/geo-toast.service.mjs +116 -0
  88. package/esm2022/lib/figma/geo-toast/geo-toast.types.mjs +13 -0
  89. package/esm2022/lib/figma/geo-tree/geo-tree.component.mjs +52 -0
  90. package/esm2022/lib/figma/geo-tree/geo-tree.types.mjs +2 -0
  91. package/esm2022/lib/figma/geo-typography/geo-typography.component.mjs +112 -0
  92. package/esm2022/lib/figma/geo-typography/geo-typography.types.mjs +96 -0
  93. package/esm2022/lib/figma/geo-upload/geo-upload.component.mjs +218 -0
  94. package/esm2022/lib/figma/geo-upload/geo-upload.types.mjs +30 -0
  95. package/esm2022/lib/figma/index.mjs +56 -0
  96. package/esm2022/lib/ng-zorro/ng-zorro-antd.module.mjs +293 -0
  97. package/esm2022/lib/styles/tokens.mjs +144 -0
  98. package/esm2022/public-api.mjs +7 -0
  99. package/fesm2022/geoit-ui.mjs +3805 -0
  100. package/fesm2022/geoit-ui.mjs.map +1 -0
  101. package/index.d.ts +5 -0
  102. package/lib/figma/geo-alert/geo-alert.component.d.ts +17 -0
  103. package/lib/figma/geo-alert/geo-alert.types.d.ts +2 -0
  104. package/lib/figma/geo-back-button/geo-back-button.component.d.ts +18 -0
  105. package/lib/figma/geo-breadcrumb/geo-breadcrumb.component.d.ts +12 -0
  106. package/lib/figma/geo-breadcrumb/geo-breadcrumb.types.d.ts +10 -0
  107. package/lib/figma/geo-button/geo-button.component.d.ts +27 -0
  108. package/lib/figma/geo-button/geo-button.types.d.ts +4 -0
  109. package/lib/figma/geo-checkbox/geo-checkbox.component.d.ts +12 -0
  110. package/lib/figma/geo-confirm-modal/geo-confirm-modal.component.d.ts +24 -0
  111. package/lib/figma/geo-confirm-modal/geo-confirm-modal.types.d.ts +5 -0
  112. package/lib/figma/geo-date-picker/geo-date-picker.component.d.ts +35 -0
  113. package/lib/figma/geo-date-picker/geo-date-picker.types.d.ts +2 -0
  114. package/lib/figma/geo-date-range-picker/geo-date-range-picker.component.d.ts +34 -0
  115. package/lib/figma/geo-date-range-picker/geo-date-range-picker.types.d.ts +2 -0
  116. package/lib/figma/geo-file-picker/geo-file-picker.component.d.ts +39 -0
  117. package/lib/figma/geo-file-picker/geo-file-picker.types.d.ts +4 -0
  118. package/lib/figma/geo-form-modal/geo-form-modal.component.d.ts +57 -0
  119. package/lib/figma/geo-icon/geo-icon.component.d.ts +19 -0
  120. package/lib/figma/geo-icon/geo-icon.types.d.ts +3 -0
  121. package/lib/figma/geo-input/geo-input.component.d.ts +37 -0
  122. package/lib/figma/geo-page-title/geo-page-title.component.d.ts +22 -0
  123. package/lib/figma/geo-pagination/geo-pagination.component.d.ts +21 -0
  124. package/lib/figma/geo-radio/geo-radio.component.d.ts +31 -0
  125. package/lib/figma/geo-radio/geo-radio.types.d.ts +9 -0
  126. package/lib/figma/geo-select/geo-select.component.d.ts +33 -0
  127. package/lib/figma/geo-select/geo-select.types.d.ts +7 -0
  128. package/lib/figma/geo-slider/geo-slider.component.d.ts +17 -0
  129. package/lib/figma/geo-status-tag/geo-status-tag.component.d.ts +18 -0
  130. package/lib/figma/geo-status-tag/geo-status-tag.types.d.ts +13 -0
  131. package/lib/figma/geo-step-form-layout/geo-step-form-layout.component.d.ts +67 -0
  132. package/lib/figma/geo-step-form-layout/geo-step-form-layout.types.d.ts +9 -0
  133. package/lib/figma/geo-stepper/geo-stepper.component.d.ts +42 -0
  134. package/lib/figma/geo-stepper/geo-stepper.types.d.ts +9 -0
  135. package/lib/figma/geo-table/geo-column-picker/geo-column-picker.component.d.ts +20 -0
  136. package/lib/figma/geo-table/geo-column-picker/geo-column-picker.storage.d.ts +5 -0
  137. package/lib/figma/geo-table/geo-column-picker/geo-column-picker.types.d.ts +17 -0
  138. package/lib/figma/geo-table/geo-row-actions/geo-row-actions.component.d.ts +21 -0
  139. package/lib/figma/geo-table/geo-row-actions/geo-row-actions.types.d.ts +13 -0
  140. package/lib/figma/geo-table/geo-table-filter/geo-table-filter.component.d.ts +75 -0
  141. package/lib/figma/geo-table/geo-table-pagination/geo-table-pagination.component.d.ts +33 -0
  142. package/lib/figma/geo-table/geo-table-toolbar/geo-table-toolbar.component.d.ts +24 -0
  143. package/lib/figma/geo-table/geo-table.component.d.ts +113 -0
  144. package/lib/figma/geo-table/geo-table.types.d.ts +47 -0
  145. package/lib/figma/geo-tabs/geo-tabs.component.d.ts +31 -0
  146. package/lib/figma/geo-tabs/geo-tabs.types.d.ts +7 -0
  147. package/lib/figma/geo-textarea/geo-textarea.component.d.ts +27 -0
  148. package/lib/figma/geo-toast/geo-toast.component.d.ts +23 -0
  149. package/lib/figma/geo-toast/geo-toast.service.d.ts +33 -0
  150. package/lib/figma/geo-toast/geo-toast.types.d.ts +45 -0
  151. package/lib/figma/geo-tree/geo-tree.component.d.ts +23 -0
  152. package/lib/figma/geo-tree/geo-tree.types.d.ts +12 -0
  153. package/lib/figma/geo-typography/geo-typography.component.d.ts +35 -0
  154. package/lib/figma/geo-typography/geo-typography.types.d.ts +12 -0
  155. package/lib/figma/geo-upload/geo-upload.component.d.ts +59 -0
  156. package/lib/figma/geo-upload/geo-upload.types.d.ts +13 -0
  157. package/lib/figma/index.d.ts +55 -0
  158. package/lib/ng-zorro/ng-zorro-antd.module.d.ts +76 -0
  159. package/lib/styles/tokens.d.ts +184 -0
  160. package/package.json +38 -0
  161. package/public-api.d.ts +3 -0
  162. package/src/lib/styles/design-tokens.scss +143 -0
  163. package/src/lib/styles/geo-toast-notification.scss +129 -0
  164. package/src/lib/styles/scrollbar.scss +38 -0
  165. package/src/lib/styles/theme.scss +153 -0
@@ -0,0 +1,3805 @@
1
+ import * as i0 from '@angular/core';
2
+ import { NgModule, EventEmitter, Component, ViewEncapsulation, Input, Output, inject, ChangeDetectionStrategy, forwardRef, ViewChild, ChangeDetectorRef, Directive, ContentChildren, ElementRef, NgZone, HostBinding, Injectable } from '@angular/core';
3
+ import { NzAffixModule } from 'ng-zorro-antd/affix';
4
+ import { NzAlertModule } from 'ng-zorro-antd/alert';
5
+ import { NzAnchorModule } from 'ng-zorro-antd/anchor';
6
+ import { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';
7
+ import { NzAvatarModule } from 'ng-zorro-antd/avatar';
8
+ import { NzBackTopModule } from 'ng-zorro-antd/back-top';
9
+ import { NzBadgeModule } from 'ng-zorro-antd/badge';
10
+ import * as i2 from 'ng-zorro-antd/breadcrumb';
11
+ import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
12
+ import * as i1$9 from 'ng-zorro-antd/button';
13
+ import { NzButtonModule } from 'ng-zorro-antd/button';
14
+ import { NzCalendarModule } from 'ng-zorro-antd/calendar';
15
+ import { NzCardModule } from 'ng-zorro-antd/card';
16
+ import { NzCarouselModule } from 'ng-zorro-antd/carousel';
17
+ import { NzCascaderModule } from 'ng-zorro-antd/cascader';
18
+ import * as i1$3 from 'ng-zorro-antd/checkbox';
19
+ import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
20
+ import { NzCollapseModule } from 'ng-zorro-antd/collapse';
21
+ import { NzCommentModule } from 'ng-zorro-antd/comment';
22
+ import { NzNoAnimationModule } from 'ng-zorro-antd/core/no-animation';
23
+ import { NzTransButtonModule } from 'ng-zorro-antd/core/trans-button';
24
+ import * as i3$4 from 'ng-zorro-antd/core/wave';
25
+ import { NzWaveModule } from 'ng-zorro-antd/core/wave';
26
+ import * as i3$2 from 'ng-zorro-antd/date-picker';
27
+ import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
28
+ import { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';
29
+ import { NzDividerModule } from 'ng-zorro-antd/divider';
30
+ import { NzDrawerModule } from 'ng-zorro-antd/drawer';
31
+ import * as i2$5 from 'ng-zorro-antd/dropdown';
32
+ import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
33
+ import { NzEmptyModule } from 'ng-zorro-antd/empty';
34
+ import { NzFormModule } from 'ng-zorro-antd/form';
35
+ import { NzGridModule } from 'ng-zorro-antd/grid';
36
+ import { NzI18nModule } from 'ng-zorro-antd/i18n';
37
+ import * as i1 from 'ng-zorro-antd/icon';
38
+ import { NzIconModule } from 'ng-zorro-antd/icon';
39
+ import { NzImageModule } from 'ng-zorro-antd/image';
40
+ import { NzInputModule } from 'ng-zorro-antd/input';
41
+ import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
42
+ import { NzLayoutModule } from 'ng-zorro-antd/layout';
43
+ import { NzListModule } from 'ng-zorro-antd/list';
44
+ import { NzMentionModule } from 'ng-zorro-antd/mention';
45
+ import { NzMenuModule } from 'ng-zorro-antd/menu';
46
+ import { NzMessageModule } from 'ng-zorro-antd/message';
47
+ import * as i3$1 from 'ng-zorro-antd/modal';
48
+ import { NzModalModule } from 'ng-zorro-antd/modal';
49
+ import { NzNotificationModule, NzNotificationService } from 'ng-zorro-antd/notification';
50
+ import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
51
+ import * as i1$6 from 'ng-zorro-antd/pagination';
52
+ import { NzPaginationModule } from 'ng-zorro-antd/pagination';
53
+ import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';
54
+ import { NzPopoverModule } from 'ng-zorro-antd/popover';
55
+ import { NzProgressModule } from 'ng-zorro-antd/progress';
56
+ import * as i2$2 from 'ng-zorro-antd/radio';
57
+ import { NzRadioModule } from 'ng-zorro-antd/radio';
58
+ import { NzRateModule } from 'ng-zorro-antd/rate';
59
+ import { NzResultModule } from 'ng-zorro-antd/result';
60
+ import * as i3$3 from 'ng-zorro-antd/select';
61
+ import { NzSelectModule } from 'ng-zorro-antd/select';
62
+ import { NzSkeletonModule } from 'ng-zorro-antd/skeleton';
63
+ import * as i2$3 from 'ng-zorro-antd/slider';
64
+ import { NzSliderModule } from 'ng-zorro-antd/slider';
65
+ import { NzSpinModule } from 'ng-zorro-antd/spin';
66
+ import { NzStatisticModule } from 'ng-zorro-antd/statistic';
67
+ import { NzStepsModule } from 'ng-zorro-antd/steps';
68
+ import { NzSwitchModule } from 'ng-zorro-antd/switch';
69
+ import * as i1$7 from 'ng-zorro-antd/table';
70
+ import { NzTableModule } from 'ng-zorro-antd/table';
71
+ import * as i2$4 from 'ng-zorro-antd/tabs';
72
+ import { NzTabsModule } from 'ng-zorro-antd/tabs';
73
+ import { NzTagModule } from 'ng-zorro-antd/tag';
74
+ import { NzTimePickerModule } from 'ng-zorro-antd/time-picker';
75
+ import { NzTimelineModule } from 'ng-zorro-antd/timeline';
76
+ import * as i3 from 'ng-zorro-antd/tooltip';
77
+ import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
78
+ import { NzTransferModule } from 'ng-zorro-antd/transfer';
79
+ import * as i1$8 from 'ng-zorro-antd/tree';
80
+ import { NzTreeModule } from 'ng-zorro-antd/tree';
81
+ import { NzTreeViewModule } from 'ng-zorro-antd/tree-view';
82
+ import { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';
83
+ import { NzTypographyModule } from 'ng-zorro-antd/typography';
84
+ import * as i2$1 from 'ng-zorro-antd/upload';
85
+ import { NzUploadModule } from 'ng-zorro-antd/upload';
86
+ import { NzResizableModule } from 'ng-zorro-antd/resizable';
87
+ import { NzPipesModule } from 'ng-zorro-antd/pipes';
88
+ import { NzSpaceModule } from 'ng-zorro-antd/space';
89
+ import { NzSegmentedModule } from 'ng-zorro-antd/segmented';
90
+ import * as i1$2 from '@angular/common';
91
+ import { CommonModule, Location } from '@angular/common';
92
+ import * as i1$1 from '@angular/router';
93
+ import { RouterModule } from '@angular/router';
94
+ import * as i1$4 from '@angular/forms';
95
+ import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
96
+ import * as i1$5 from 'ng-zorro-antd/core/transition-patch';
97
+ import { Subscription } from 'rxjs';
98
+ import { NzConfigService } from 'ng-zorro-antd/core/config';
99
+
100
+ /**
101
+ * GEO UI design tokens (TypeScript).
102
+ * Mirror of CSS variables in design-tokens.scss — use for JS/theme config only.
103
+ */
104
+ const geoColorTokens = {
105
+ primary: {
106
+ default: '#9A4828',
107
+ hover: '#7D3A20',
108
+ light: '#B5643F',
109
+ dark: '#2C1810',
110
+ background: '#FAF5ED',
111
+ backgroundAlt: '#F5F0E8',
112
+ border: '#E8E0D8',
113
+ surfaceLight: '#F8E6DE',
114
+ secondaryHover: '#FAF5ED',
115
+ },
116
+ neutral: {
117
+ 900: '#111827',
118
+ 800: '#212121',
119
+ 700: '#374151',
120
+ 500: '#6B7280',
121
+ 400: '#9CA3AF',
122
+ 300: '#D1D5DB',
123
+ 200: '#E5E7EB',
124
+ 100: '#F3F4F6',
125
+ white: '#FFFFFF',
126
+ disabledText: '#8F9294',
127
+ },
128
+ success: {
129
+ dark: '#166534',
130
+ default: '#22C55E',
131
+ light: '#DCFCE7',
132
+ },
133
+ error: {
134
+ dark: '#991B1B',
135
+ default: '#DC2626',
136
+ light: '#FEE2E2',
137
+ },
138
+ warning: {
139
+ dark: '#92400E',
140
+ default: '#F59E0B',
141
+ light: '#FEF3C7',
142
+ },
143
+ info: {
144
+ dark: '#1E40AF',
145
+ default: '#3B82F6',
146
+ light: '#DBEAFE',
147
+ },
148
+ teal: {
149
+ dark: '#0F766E',
150
+ default: '#14B8A6',
151
+ light: '#CCFBF1',
152
+ },
153
+ };
154
+ /** CSS custom property names for each token path. */
155
+ const geoColorCssVars = {
156
+ primary: {
157
+ default: '--geo-color-primary-default',
158
+ hover: '--geo-color-primary-hover',
159
+ light: '--geo-color-primary-light',
160
+ dark: '--geo-color-primary-dark',
161
+ background: '--geo-color-primary-background',
162
+ backgroundAlt: '--geo-color-primary-background-alt',
163
+ border: '--geo-color-primary-border',
164
+ surfaceLight: '--geo-color-primary-surface-light',
165
+ secondaryHover: '--geo-color-primary-secondary-hover',
166
+ },
167
+ neutral: {
168
+ 900: '--geo-color-neutral-900',
169
+ 800: '--geo-color-neutral-800',
170
+ 700: '--geo-color-neutral-700',
171
+ 500: '--geo-color-neutral-500',
172
+ 400: '--geo-color-neutral-400',
173
+ 300: '--geo-color-neutral-300',
174
+ 200: '--geo-color-neutral-200',
175
+ 100: '--geo-color-neutral-100',
176
+ white: '--geo-color-neutral-white',
177
+ disabledText: '--geo-color-neutral-disabled-text',
178
+ },
179
+ success: {
180
+ dark: '--geo-color-success-dark',
181
+ default: '--geo-color-success-default',
182
+ light: '--geo-color-success-light',
183
+ },
184
+ error: {
185
+ dark: '--geo-color-error-dark',
186
+ default: '--geo-color-error-default',
187
+ light: '--geo-color-error-light',
188
+ },
189
+ warning: {
190
+ dark: '--geo-color-warning-dark',
191
+ default: '--geo-color-warning-default',
192
+ light: '--geo-color-warning-light',
193
+ },
194
+ info: {
195
+ dark: '--geo-color-info-dark',
196
+ default: '--geo-color-info-default',
197
+ light: '--geo-color-info-light',
198
+ },
199
+ teal: {
200
+ dark: '--geo-color-teal-dark',
201
+ default: '--geo-color-teal-default',
202
+ light: '--geo-color-teal-light',
203
+ },
204
+ };
205
+ function cssVar(name) {
206
+ return `var(${name})`;
207
+ }
208
+ /** Typography design tokens (Inter + type scale). */
209
+ const geoTypographyTokens = {
210
+ fontFamily: "'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif",
211
+ weight: {
212
+ regular: 400,
213
+ medium: 500,
214
+ semibold: 600,
215
+ bold: 700,
216
+ },
217
+ scale: {
218
+ h1: { size: '28px', weight: 700, lineHeight: '36px' },
219
+ h2: { size: '24px', weight: 700, lineHeight: '32px' },
220
+ h3: { size: '20px', weight: 700, lineHeight: '28px' },
221
+ h4: { size: '16px', weight: 700, lineHeight: '24px' },
222
+ subtitle: { size: '14px', weight: 600, lineHeight: '20px' },
223
+ body: { size: '14px', weight: 400, lineHeight: '20px' },
224
+ bodySmall: { size: '13px', weight: 400, lineHeight: '18px' },
225
+ caption: { size: '12px', weight: 400, lineHeight: '16px' },
226
+ overline: { size: '11px', weight: 600, lineHeight: '16px' },
227
+ tiny: { size: '10px', weight: 400, lineHeight: '14px' },
228
+ },
229
+ };
230
+ /** Border radius design tokens (default 6px). */
231
+ const geoRadiusTokens = {
232
+ default: '6px',
233
+ sm: '6px',
234
+ md: '6px',
235
+ lg: '6px',
236
+ };
237
+ const geoRadiusCssVars = {
238
+ default: '--geo-radius',
239
+ sm: '--geo-radius-sm',
240
+ md: '--geo-radius-md',
241
+ lg: '--geo-radius-lg',
242
+ };
243
+
244
+ class NgZorroAntdModule {
245
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgZorroAntdModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
246
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: NgZorroAntdModule, exports: [NzAffixModule,
247
+ NzAlertModule,
248
+ NzAnchorModule,
249
+ NzAutocompleteModule,
250
+ NzAvatarModule,
251
+ NzBackTopModule,
252
+ NzBadgeModule,
253
+ NzButtonModule,
254
+ NzBreadCrumbModule,
255
+ NzCalendarModule,
256
+ NzCardModule,
257
+ NzCarouselModule,
258
+ NzCascaderModule,
259
+ NzCheckboxModule,
260
+ NzCollapseModule,
261
+ NzCommentModule,
262
+ NzDatePickerModule,
263
+ NzDescriptionsModule,
264
+ NzDividerModule,
265
+ NzDrawerModule,
266
+ NzDropDownModule,
267
+ NzEmptyModule,
268
+ NzFormModule,
269
+ NzGridModule,
270
+ NzI18nModule,
271
+ NzIconModule,
272
+ NzImageModule,
273
+ NzInputModule,
274
+ NzInputNumberModule,
275
+ NzLayoutModule,
276
+ NzListModule,
277
+ NzMentionModule,
278
+ NzMenuModule,
279
+ NzMessageModule,
280
+ NzModalModule,
281
+ NzNoAnimationModule,
282
+ NzNotificationModule,
283
+ NzPageHeaderModule,
284
+ NzPaginationModule,
285
+ NzPopconfirmModule,
286
+ NzPopoverModule,
287
+ NzProgressModule,
288
+ NzRadioModule,
289
+ NzRateModule,
290
+ NzResultModule,
291
+ NzSelectModule,
292
+ NzSkeletonModule,
293
+ NzSliderModule,
294
+ NzSpinModule,
295
+ NzStatisticModule,
296
+ NzStepsModule,
297
+ NzSwitchModule,
298
+ NzTableModule,
299
+ NzTabsModule,
300
+ NzTagModule,
301
+ NzTimePickerModule,
302
+ NzTimelineModule,
303
+ NzToolTipModule,
304
+ NzTransButtonModule,
305
+ NzTransferModule,
306
+ NzTreeModule,
307
+ NzTreeViewModule,
308
+ NzTreeSelectModule,
309
+ NzTypographyModule,
310
+ NzUploadModule,
311
+ NzWaveModule,
312
+ NzResizableModule,
313
+ NzPipesModule,
314
+ NzSpaceModule,
315
+ NzSegmentedModule] });
316
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgZorroAntdModule, imports: [NzAffixModule,
317
+ NzAlertModule,
318
+ NzAnchorModule,
319
+ NzAutocompleteModule,
320
+ NzAvatarModule,
321
+ NzBackTopModule,
322
+ NzBadgeModule,
323
+ NzButtonModule,
324
+ NzBreadCrumbModule,
325
+ NzCalendarModule,
326
+ NzCardModule,
327
+ NzCarouselModule,
328
+ NzCascaderModule,
329
+ NzCheckboxModule,
330
+ NzCollapseModule,
331
+ NzCommentModule,
332
+ NzDatePickerModule,
333
+ NzDescriptionsModule,
334
+ NzDividerModule,
335
+ NzDrawerModule,
336
+ NzDropDownModule,
337
+ NzEmptyModule,
338
+ NzFormModule,
339
+ NzGridModule,
340
+ NzI18nModule,
341
+ NzIconModule,
342
+ NzImageModule,
343
+ NzInputModule,
344
+ NzInputNumberModule,
345
+ NzLayoutModule,
346
+ NzListModule,
347
+ NzMentionModule,
348
+ NzMenuModule,
349
+ NzMessageModule,
350
+ NzModalModule,
351
+ NzNoAnimationModule,
352
+ NzNotificationModule,
353
+ NzPageHeaderModule,
354
+ NzPaginationModule,
355
+ NzPopconfirmModule,
356
+ NzPopoverModule,
357
+ NzProgressModule,
358
+ NzRadioModule,
359
+ NzRateModule,
360
+ NzResultModule,
361
+ NzSelectModule,
362
+ NzSkeletonModule,
363
+ NzSliderModule,
364
+ NzSpinModule,
365
+ NzStatisticModule,
366
+ NzStepsModule,
367
+ NzSwitchModule,
368
+ NzTableModule,
369
+ NzTabsModule,
370
+ NzTagModule,
371
+ NzTimePickerModule,
372
+ NzTimelineModule,
373
+ NzToolTipModule,
374
+ NzTransButtonModule,
375
+ NzTransferModule,
376
+ NzTreeModule,
377
+ NzTreeViewModule,
378
+ NzTreeSelectModule,
379
+ NzTypographyModule,
380
+ NzUploadModule,
381
+ NzWaveModule,
382
+ NzResizableModule,
383
+ NzPipesModule,
384
+ NzSpaceModule,
385
+ NzSegmentedModule] });
386
+ }
387
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgZorroAntdModule, decorators: [{
388
+ type: NgModule,
389
+ args: [{
390
+ exports: [
391
+ NzAffixModule,
392
+ NzAlertModule,
393
+ NzAnchorModule,
394
+ NzAutocompleteModule,
395
+ NzAvatarModule,
396
+ NzBackTopModule,
397
+ NzBadgeModule,
398
+ NzButtonModule,
399
+ NzBreadCrumbModule,
400
+ NzCalendarModule,
401
+ NzCardModule,
402
+ NzCarouselModule,
403
+ NzCascaderModule,
404
+ NzCheckboxModule,
405
+ NzCollapseModule,
406
+ NzCommentModule,
407
+ NzDatePickerModule,
408
+ NzDescriptionsModule,
409
+ NzDividerModule,
410
+ NzDrawerModule,
411
+ NzDropDownModule,
412
+ NzEmptyModule,
413
+ NzFormModule,
414
+ NzGridModule,
415
+ NzI18nModule,
416
+ NzIconModule,
417
+ NzImageModule,
418
+ NzInputModule,
419
+ NzInputNumberModule,
420
+ NzLayoutModule,
421
+ NzListModule,
422
+ NzMentionModule,
423
+ NzMenuModule,
424
+ NzMessageModule,
425
+ NzModalModule,
426
+ NzNoAnimationModule,
427
+ NzNotificationModule,
428
+ NzPageHeaderModule,
429
+ NzPaginationModule,
430
+ NzPopconfirmModule,
431
+ NzPopoverModule,
432
+ NzProgressModule,
433
+ NzRadioModule,
434
+ NzRateModule,
435
+ NzResultModule,
436
+ NzSelectModule,
437
+ NzSkeletonModule,
438
+ NzSliderModule,
439
+ NzSpinModule,
440
+ NzStatisticModule,
441
+ NzStepsModule,
442
+ NzSwitchModule,
443
+ NzTableModule,
444
+ NzTabsModule,
445
+ NzTagModule,
446
+ NzTimePickerModule,
447
+ NzTimelineModule,
448
+ NzToolTipModule,
449
+ NzTransButtonModule,
450
+ NzTransferModule,
451
+ NzTreeModule,
452
+ NzTreeViewModule,
453
+ NzTreeSelectModule,
454
+ NzTypographyModule,
455
+ NzUploadModule,
456
+ NzWaveModule,
457
+ NzResizableModule,
458
+ NzPipesModule,
459
+ NzSpaceModule,
460
+ NzSegmentedModule,
461
+ ],
462
+ }]
463
+ }] });
464
+
465
+ const UI_ALERT_DEFAULT_TITLES = {
466
+ success: 'Thành công!',
467
+ error: 'Lỗi!',
468
+ warning: 'Cảnh báo!',
469
+ info: 'Thông tin!',
470
+ };
471
+
472
+ class GeoAlertComponent {
473
+ type = 'info';
474
+ title = '';
475
+ message = '';
476
+ closable = true;
477
+ visible = true;
478
+ showIcon = true;
479
+ closed = new EventEmitter();
480
+ get displayTitle() {
481
+ return this.title || UI_ALERT_DEFAULT_TITLES[this.type];
482
+ }
483
+ get iconType() {
484
+ switch (this.type) {
485
+ case 'success':
486
+ return 'check-circle';
487
+ case 'error':
488
+ return 'close-circle';
489
+ case 'warning':
490
+ return 'exclamation-circle';
491
+ default:
492
+ return 'info-circle';
493
+ }
494
+ }
495
+ onClose() {
496
+ this.visible = false;
497
+ this.closed.emit();
498
+ }
499
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoAlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
500
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoAlertComponent, isStandalone: true, selector: "geo-alert", inputs: { type: "type", title: "title", message: "message", closable: "closable", visible: "visible", showIcon: "showIcon" }, outputs: { closed: "closed" }, host: { properties: { "class.geo-alert-host--hidden": "!visible" }, classAttribute: "geo-alert-host" }, ngImport: i0, template: "@if (visible) {\n <div class=\"geo-alert\" [class]=\"'geo-alert--' + type\" role=\"alert\">\n <div class=\"geo-alert__main\">\n @if (showIcon) {\n <span class=\"geo-alert__icon\" nz-icon [nzType]=\"iconType\" nzTheme=\"outline\"></span>\n }\n\n <div class=\"geo-alert__content\">\n <p class=\"geo-alert__title\">{{ displayTitle }}</p>\n @if (message) {\n <p class=\"geo-alert__message\">{{ message }}</p>\n }\n </div>\n </div>\n\n @if (closable) {\n <button type=\"button\" class=\"geo-alert__close\" aria-label=\"\u0110\u00F3ng th\u00F4ng b\u00E1o\" (click)=\"onClose()\">\n <span nz-icon nzType=\"close\" nzTheme=\"outline\"></span>\n </button>\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";geo-alert.geo-alert-host,.geo-alert-host{display:block;width:100%}.geo-alert-host--hidden{display:none}.geo-alert{display:flex;align-items:flex-start;justify-content:space-between;gap:9px;width:100%;padding:16px;border:1px solid transparent;border-radius:var(--geo-radius);box-sizing:border-box}.geo-alert__main{display:flex;align-items:flex-start;gap:8px;min-width:0;flex:1 1 auto}.geo-alert__icon{display:inline-flex;flex-shrink:0;width:24px;height:24px;font-size:24px;line-height:1}.geo-alert__content{display:flex;flex-direction:column;gap:0;min-width:0}.geo-alert__title,.geo-alert__message{margin:0;font-size:var(--geo-font-size-lg);line-height:24px}.geo-alert__title{font-weight:700}.geo-alert__message{font-weight:400}.geo-alert__close{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;background:transparent;cursor:pointer;flex-shrink:0}.geo-alert--success{background:var(--geo-color-success-light);border-color:var(--geo-color-success-default)}.geo-alert--success .geo-alert__title,.geo-alert--success .geo-alert__message,.geo-alert--success .geo-alert__icon{color:var(--geo-color-success-dark)}.geo-alert--success .geo-alert__close{color:var(--geo-color-success-default)}.geo-alert--error{background:var(--geo-color-error-light);border-color:var(--geo-color-error-default)}.geo-alert--error .geo-alert__title,.geo-alert--error .geo-alert__message,.geo-alert--error .geo-alert__icon{color:var(--geo-color-error-default)}.geo-alert--error .geo-alert__close{color:var(--geo-color-error-dark)}.geo-alert--warning{background:var(--geo-color-warning-light);border-color:var(--geo-color-warning-default)}.geo-alert--warning .geo-alert__title,.geo-alert--warning .geo-alert__message{color:var(--geo-color-warning-dark)}.geo-alert--warning .geo-alert__icon,.geo-alert--warning .geo-alert__close{color:var(--geo-color-warning-default)}.geo-alert--info{background:var(--geo-color-info-light);border-color:var(--geo-color-info-default)}.geo-alert--info .geo-alert__title,.geo-alert--info .geo-alert__message,.geo-alert--info .geo-alert__icon{color:var(--geo-color-info-dark)}.geo-alert--info .geo-alert__close{color:var(--geo-color-info-default)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }], encapsulation: i0.ViewEncapsulation.None });
501
+ }
502
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoAlertComponent, decorators: [{
503
+ type: Component,
504
+ args: [{ selector: 'geo-alert', standalone: true, imports: [CommonModule, NzIconModule], encapsulation: ViewEncapsulation.None, host: {
505
+ class: 'geo-alert-host',
506
+ '[class.geo-alert-host--hidden]': '!visible',
507
+ }, template: "@if (visible) {\n <div class=\"geo-alert\" [class]=\"'geo-alert--' + type\" role=\"alert\">\n <div class=\"geo-alert__main\">\n @if (showIcon) {\n <span class=\"geo-alert__icon\" nz-icon [nzType]=\"iconType\" nzTheme=\"outline\"></span>\n }\n\n <div class=\"geo-alert__content\">\n <p class=\"geo-alert__title\">{{ displayTitle }}</p>\n @if (message) {\n <p class=\"geo-alert__message\">{{ message }}</p>\n }\n </div>\n </div>\n\n @if (closable) {\n <button type=\"button\" class=\"geo-alert__close\" aria-label=\"\u0110\u00F3ng th\u00F4ng b\u00E1o\" (click)=\"onClose()\">\n <span nz-icon nzType=\"close\" nzTheme=\"outline\"></span>\n </button>\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";geo-alert.geo-alert-host,.geo-alert-host{display:block;width:100%}.geo-alert-host--hidden{display:none}.geo-alert{display:flex;align-items:flex-start;justify-content:space-between;gap:9px;width:100%;padding:16px;border:1px solid transparent;border-radius:var(--geo-radius);box-sizing:border-box}.geo-alert__main{display:flex;align-items:flex-start;gap:8px;min-width:0;flex:1 1 auto}.geo-alert__icon{display:inline-flex;flex-shrink:0;width:24px;height:24px;font-size:24px;line-height:1}.geo-alert__content{display:flex;flex-direction:column;gap:0;min-width:0}.geo-alert__title,.geo-alert__message{margin:0;font-size:var(--geo-font-size-lg);line-height:24px}.geo-alert__title{font-weight:700}.geo-alert__message{font-weight:400}.geo-alert__close{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;background:transparent;cursor:pointer;flex-shrink:0}.geo-alert--success{background:var(--geo-color-success-light);border-color:var(--geo-color-success-default)}.geo-alert--success .geo-alert__title,.geo-alert--success .geo-alert__message,.geo-alert--success .geo-alert__icon{color:var(--geo-color-success-dark)}.geo-alert--success .geo-alert__close{color:var(--geo-color-success-default)}.geo-alert--error{background:var(--geo-color-error-light);border-color:var(--geo-color-error-default)}.geo-alert--error .geo-alert__title,.geo-alert--error .geo-alert__message,.geo-alert--error .geo-alert__icon{color:var(--geo-color-error-default)}.geo-alert--error .geo-alert__close{color:var(--geo-color-error-dark)}.geo-alert--warning{background:var(--geo-color-warning-light);border-color:var(--geo-color-warning-default)}.geo-alert--warning .geo-alert__title,.geo-alert--warning .geo-alert__message{color:var(--geo-color-warning-dark)}.geo-alert--warning .geo-alert__icon,.geo-alert--warning .geo-alert__close{color:var(--geo-color-warning-default)}.geo-alert--info{background:var(--geo-color-info-light);border-color:var(--geo-color-info-default)}.geo-alert--info .geo-alert__title,.geo-alert--info .geo-alert__message,.geo-alert--info .geo-alert__icon{color:var(--geo-color-info-dark)}.geo-alert--info .geo-alert__close{color:var(--geo-color-info-default)}\n"] }]
508
+ }], propDecorators: { type: [{
509
+ type: Input
510
+ }], title: [{
511
+ type: Input
512
+ }], message: [{
513
+ type: Input
514
+ }], closable: [{
515
+ type: Input
516
+ }], visible: [{
517
+ type: Input
518
+ }], showIcon: [{
519
+ type: Input
520
+ }], closed: [{
521
+ type: Output
522
+ }] } });
523
+
524
+ /**
525
+ * Nút quay lại dùng chung cho các page form/detail.
526
+ * Mặc định `history.back()` (−1). Set `[historyBack]="false"` nếu parent tự navigate.
527
+ */
528
+ class GeoBackButtonComponent {
529
+ location = inject(Location);
530
+ ariaLabel = 'Quay lại';
531
+ title = 'Quay lại';
532
+ disabled = false;
533
+ /** `true` (mặc định): `Location.back()` — về trang trước trong history. */
534
+ historyBack = true;
535
+ clicked = new EventEmitter();
536
+ onClick(event) {
537
+ if (this.disabled) {
538
+ return;
539
+ }
540
+ event.preventDefault();
541
+ event.stopPropagation();
542
+ this.clicked.emit(event);
543
+ if (this.historyBack) {
544
+ this.location.back();
545
+ }
546
+ }
547
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoBackButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
548
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: GeoBackButtonComponent, isStandalone: true, selector: "geo-back-button", inputs: { ariaLabel: "ariaLabel", title: "title", disabled: "disabled", historyBack: "historyBack" }, outputs: { clicked: "clicked" }, host: { classAttribute: "geo-back-button-host" }, ngImport: i0, template: "<button\n type=\"button\"\n class=\"geo-back-button\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.title]=\"title || ariaLabel\"\n [disabled]=\"disabled\"\n (click)=\"onClick($event)\"\n>\n <span nz-icon nzType=\"arrow-left\" nzTheme=\"outline\" aria-hidden=\"true\"></span>\n</button>\n", styles: [":host,.geo-back-button-host{display:inline-flex;flex-shrink:0;position:relative;z-index:2;pointer-events:auto}.geo-back-button{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:0;border-radius:var(--geo-radius);background:var(--geo-color-primary-surface-light);color:var(--geo-color-primary-default);cursor:pointer;pointer-events:auto;transition:background-color .15s ease}.geo-back-button .anticon{font-size:16px;pointer-events:none}.geo-back-button:hover:not(:disabled){background:var(--geo-color-primary-surface-light)}.geo-back-button:focus-visible{outline:2px solid var(--geo-color-primary-default);outline-offset:2px}.geo-back-button:disabled{opacity:.45;cursor:not-allowed}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
549
+ }
550
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoBackButtonComponent, decorators: [{
551
+ type: Component,
552
+ args: [{ selector: 'geo-back-button', standalone: true, imports: [CommonModule, NzIconModule], changeDetection: ChangeDetectionStrategy.OnPush, host: {
553
+ class: 'geo-back-button-host',
554
+ }, template: "<button\n type=\"button\"\n class=\"geo-back-button\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.title]=\"title || ariaLabel\"\n [disabled]=\"disabled\"\n (click)=\"onClick($event)\"\n>\n <span nz-icon nzType=\"arrow-left\" nzTheme=\"outline\" aria-hidden=\"true\"></span>\n</button>\n", styles: [":host,.geo-back-button-host{display:inline-flex;flex-shrink:0;position:relative;z-index:2;pointer-events:auto}.geo-back-button{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:0;border-radius:var(--geo-radius);background:var(--geo-color-primary-surface-light);color:var(--geo-color-primary-default);cursor:pointer;pointer-events:auto;transition:background-color .15s ease}.geo-back-button .anticon{font-size:16px;pointer-events:none}.geo-back-button:hover:not(:disabled){background:var(--geo-color-primary-surface-light)}.geo-back-button:focus-visible{outline:2px solid var(--geo-color-primary-default);outline-offset:2px}.geo-back-button:disabled{opacity:.45;cursor:not-allowed}\n"] }]
555
+ }], propDecorators: { ariaLabel: [{
556
+ type: Input
557
+ }], title: [{
558
+ type: Input
559
+ }], disabled: [{
560
+ type: Input
561
+ }], historyBack: [{
562
+ type: Input
563
+ }], clicked: [{
564
+ type: Output
565
+ }] } });
566
+
567
+ /**
568
+ * Breadcrumb GEO — dựa trên `nz-breadcrumb`.
569
+ * Item thường: neutral gray; item active (cuối): primary + semibold.
570
+ */
571
+ class GeoBreadcrumbComponent {
572
+ items = [];
573
+ isActive(item, index) {
574
+ if (item.active != null) {
575
+ return item.active;
576
+ }
577
+ return index === this.items.length - 1;
578
+ }
579
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
580
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoBreadcrumbComponent, isStandalone: true, selector: "geo-breadcrumb", inputs: { items: "items" }, host: { classAttribute: "geo-breadcrumb-host" }, ngImport: i0, template: "<nav class=\"geo-breadcrumb\" aria-label=\"Breadcrumb\">\n <nz-breadcrumb class=\"geo-breadcrumb__antd\" [nzSeparator]=\"separatorTpl\">\n @for (item of items; track $index) {\n <nz-breadcrumb-item>\n @if (item.link && !isActive(item, $index)) {\n <a\n class=\"geo-breadcrumb__link\"\n [routerLink]=\"item.link\"\n [queryParams]=\"item.queryParams || null\"\n >\n {{ item.label }}\n </a>\n } @else {\n <span\n class=\"geo-breadcrumb__text\"\n [class.geo-breadcrumb__text--active]=\"isActive(item, $index)\"\n [attr.aria-current]=\"isActive(item, $index) ? 'page' : null\"\n >\n {{ item.label }}\n </span>\n }\n </nz-breadcrumb-item>\n }\n </nz-breadcrumb>\n</nav>\n\n<ng-template #separatorTpl>\n <span class=\"geo-breadcrumb__separator\" nz-icon nzType=\"right\" nzTheme=\"outline\"></span>\n</ng-template>\n", styles: ["geo-breadcrumb.geo-breadcrumb-host,.geo-breadcrumb-host{display:block;background:transparent;font-family:var(--geo-font-family)}.geo-breadcrumb__antd.ant-breadcrumb{font-size:var(--geo-font-size-body);line-height:var(--geo-line-height-body);color:var(--geo-color-neutral-500)}.geo-breadcrumb__antd.ant-breadcrumb ol{display:flex;flex-wrap:wrap;align-items:center;gap:0;margin:0;padding:0}.geo-breadcrumb__antd.ant-breadcrumb .ant-breadcrumb-separator{margin:0 8px;color:var(--geo-color-neutral-500)}.geo-breadcrumb__separator{font-size:10px;color:var(--geo-color-neutral-500)}.geo-breadcrumb__link{color:var(--geo-color-neutral-500);font-weight:var(--geo-font-weight-regular);text-decoration:none;transition:color .15s ease}.geo-breadcrumb__link:hover{color:var(--geo-color-primary-default)}.geo-breadcrumb__text{color:var(--geo-color-neutral-500);font-weight:var(--geo-font-weight-regular)}.geo-breadcrumb__text--active{color:var(--geo-color-primary-default);font-weight:var(--geo-font-weight-semibold)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: NzBreadCrumbModule }, { kind: "component", type: i2.NzBreadCrumbComponent, selector: "nz-breadcrumb", inputs: ["nzAutoGenerate", "nzSeparator", "nzRouteLabel", "nzRouteLabelFn", "nzRouteFn"], exportAs: ["nzBreadcrumb"] }, { kind: "component", type: i2.NzBreadCrumbItemComponent, selector: "nz-breadcrumb-item", inputs: ["nzOverlay"], exportAs: ["nzBreadcrumbItem"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }], encapsulation: i0.ViewEncapsulation.None });
581
+ }
582
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoBreadcrumbComponent, decorators: [{
583
+ type: Component,
584
+ args: [{ selector: 'geo-breadcrumb', standalone: true, imports: [CommonModule, RouterModule, NzBreadCrumbModule, NzIconModule], encapsulation: ViewEncapsulation.None, host: {
585
+ class: 'geo-breadcrumb-host',
586
+ }, template: "<nav class=\"geo-breadcrumb\" aria-label=\"Breadcrumb\">\n <nz-breadcrumb class=\"geo-breadcrumb__antd\" [nzSeparator]=\"separatorTpl\">\n @for (item of items; track $index) {\n <nz-breadcrumb-item>\n @if (item.link && !isActive(item, $index)) {\n <a\n class=\"geo-breadcrumb__link\"\n [routerLink]=\"item.link\"\n [queryParams]=\"item.queryParams || null\"\n >\n {{ item.label }}\n </a>\n } @else {\n <span\n class=\"geo-breadcrumb__text\"\n [class.geo-breadcrumb__text--active]=\"isActive(item, $index)\"\n [attr.aria-current]=\"isActive(item, $index) ? 'page' : null\"\n >\n {{ item.label }}\n </span>\n }\n </nz-breadcrumb-item>\n }\n </nz-breadcrumb>\n</nav>\n\n<ng-template #separatorTpl>\n <span class=\"geo-breadcrumb__separator\" nz-icon nzType=\"right\" nzTheme=\"outline\"></span>\n</ng-template>\n", styles: ["geo-breadcrumb.geo-breadcrumb-host,.geo-breadcrumb-host{display:block;background:transparent;font-family:var(--geo-font-family)}.geo-breadcrumb__antd.ant-breadcrumb{font-size:var(--geo-font-size-body);line-height:var(--geo-line-height-body);color:var(--geo-color-neutral-500)}.geo-breadcrumb__antd.ant-breadcrumb ol{display:flex;flex-wrap:wrap;align-items:center;gap:0;margin:0;padding:0}.geo-breadcrumb__antd.ant-breadcrumb .ant-breadcrumb-separator{margin:0 8px;color:var(--geo-color-neutral-500)}.geo-breadcrumb__separator{font-size:10px;color:var(--geo-color-neutral-500)}.geo-breadcrumb__link{color:var(--geo-color-neutral-500);font-weight:var(--geo-font-weight-regular);text-decoration:none;transition:color .15s ease}.geo-breadcrumb__link:hover{color:var(--geo-color-primary-default)}.geo-breadcrumb__text{color:var(--geo-color-neutral-500);font-weight:var(--geo-font-weight-regular)}.geo-breadcrumb__text--active{color:var(--geo-color-primary-default);font-weight:var(--geo-font-weight-semibold)}\n"] }]
587
+ }], propDecorators: { items: [{
588
+ type: Input
589
+ }] } });
590
+
591
+ class GeoButtonComponent {
592
+ appearance = 'primary';
593
+ color = 'brand';
594
+ icon;
595
+ iconTheme = 'outline';
596
+ /** Vị trí icon: `start` (trái) hoặc `end` (phải). */
597
+ iconPlacement = 'start';
598
+ iconOnly = false;
599
+ type = 'button';
600
+ disabled = false;
601
+ /** Tooltip Ant Design (`nz-tooltip`). Ưu tiên hơn `title` native. */
602
+ tooltip = '';
603
+ tooltipPlacement = 'top';
604
+ /** Trạng thái active (vd. toolbar toggle đang bật). */
605
+ active = false;
606
+ /** Native `title` — fallback khi không set `tooltip`. */
607
+ title = '';
608
+ clicked = new EventEmitter();
609
+ get tooltipTitle() {
610
+ return this.tooltip || this.title || '';
611
+ }
612
+ get classNames() {
613
+ return {
614
+ [`geo-button--${this.appearance}`]: true,
615
+ [`geo-button--${this.color}`]: true,
616
+ 'geo-button--icon-only': this.iconOnly,
617
+ 'geo-button--icon-end': !!this.icon && this.iconPlacement === 'end',
618
+ 'geo-button--active': this.active,
619
+ };
620
+ }
621
+ onClick(event) {
622
+ if (!this.disabled) {
623
+ this.clicked.emit(event);
624
+ }
625
+ }
626
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
627
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoButtonComponent, isStandalone: true, selector: "geo-button", inputs: { appearance: "appearance", color: "color", icon: "icon", iconTheme: "iconTheme", iconPlacement: "iconPlacement", iconOnly: "iconOnly", type: "type", disabled: "disabled", tooltip: "tooltip", tooltipPlacement: "tooltipPlacement", active: "active", title: "title" }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\n [type]=\"type\"\n [disabled]=\"disabled\"\n class=\"geo-button\"\n [ngClass]=\"classNames\"\n [nz-tooltip]=\"tooltipTitle\"\n [nzTooltipPlacement]=\"tooltipPlacement\"\n [nzTooltipTrigger]=\"tooltipTitle ? 'hover' : null\"\n [attr.aria-label]=\"tooltipTitle || null\"\n [attr.aria-pressed]=\"active ? true : null\"\n (click)=\"onClick($event)\"\n>\n @if (icon && iconPlacement === 'start') {\n <span class=\"geo-button__icon\">\n <span nz-icon [nzType]=\"icon\" [nzTheme]=\"iconTheme\"></span>\n </span>\n }\n @if (!iconOnly) {\n <span class=\"geo-button__label\">\n <ng-content></ng-content>\n </span>\n }\n @if (icon && iconPlacement === 'end') {\n <span class=\"geo-button__icon\">\n <span nz-icon [nzType]=\"icon\" [nzTheme]=\"iconTheme\"></span>\n </span>\n }\n</button>\n", styles: [".geo-button{display:inline-flex;align-items:center;justify-content:center;gap:6px;height:var(--geo-control-height);min-height:var(--geo-control-height);padding:0 16px;border-radius:var(--geo-radius);border:1px solid transparent;font-size:var(--geo-font-size-sm);font-weight:500;line-height:normal;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,color .15s ease;white-space:nowrap;font-family:inherit;background:transparent;box-sizing:border-box}.geo-button.geo-button--brand{--geo-btn-tone: var(--geo-color-primary-default);--geo-btn-tone-dark: var(--geo-color-primary-hover);--geo-btn-tone-surface: var(--geo-color-primary-surface-light);--geo-btn-secondary-hover: var(--geo-color-primary-secondary-hover)}.geo-button.geo-button--danger{--geo-btn-tone: var(--geo-color-error-default);--geo-btn-tone-dark: var(--geo-color-error-dark);--geo-btn-tone-surface: var(--geo-color-error-light);--geo-btn-secondary-hover: var(--geo-color-error-light)}.geo-button.geo-button--warning{--geo-btn-tone: var(--geo-color-warning-default);--geo-btn-tone-dark: var(--geo-color-warning-dark);--geo-btn-tone-surface: var(--geo-color-warning-light);--geo-btn-secondary-hover: var(--geo-color-warning-light)}.geo-button.geo-button--success{--geo-btn-tone: var(--geo-color-success-default);--geo-btn-tone-dark: var(--geo-color-success-dark);--geo-btn-tone-surface: var(--geo-color-success-light);--geo-btn-secondary-hover: var(--geo-color-success-light)}.geo-button:disabled{cursor:not-allowed;pointer-events:none}.geo-button--primary{background:var(--geo-btn-tone);border-color:var(--geo-btn-tone);color:var(--geo-color-neutral-white)}.geo-button--primary:hover:not(:disabled){background:var(--geo-btn-tone-dark);border-color:var(--geo-btn-tone-dark)}.geo-button--primary:disabled{background:var(--geo-color-neutral-300);border-color:var(--geo-color-neutral-300);color:var(--geo-color-neutral-disabled-text)}.geo-button--secondary{background:var(--geo-color-neutral-white);border-color:var(--geo-btn-tone);color:var(--geo-btn-tone)}.geo-button--secondary:hover:not(:disabled){background:var(--geo-btn-secondary-hover)}.geo-button--secondary:disabled{background:var(--geo-color-neutral-white);border-color:var(--geo-color-neutral-300);color:var(--geo-color-neutral-disabled-text)}.geo-button--tertiary{background:transparent;border-color:transparent;color:var(--geo-btn-tone)}.geo-button--tertiary:hover:not(:disabled){background:var(--geo-btn-tone-surface)}.geo-button--tertiary:disabled{background:transparent;border-color:transparent;color:var(--geo-color-neutral-disabled-text)}.geo-button--icon-only{width:var(--geo-control-height);min-width:var(--geo-control-height);padding:0}.geo-button--active:not(:disabled).geo-button--secondary,.geo-button--active:not(:disabled).geo-button--tertiary{background:var(--geo-btn-tone-surface);border-color:var(--geo-btn-tone);color:var(--geo-btn-tone);box-shadow:inset 0 0 0 1px var(--geo-btn-tone)}.geo-button--active:not(:disabled).geo-button--primary{background:var(--geo-btn-tone-dark);border-color:var(--geo-btn-tone-dark);color:var(--geo-color-neutral-white)}.geo-button__icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:16px;height:16px;font-size:16px;line-height:1}.geo-button__icon:empty{display:none}.geo-button__icon :deep(.anticon),.geo-button__icon :deep(em){width:16px;height:16px;font-size:16px}.geo-button__label{display:inline-flex;align-items:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzToolTipModule }, { kind: "directive", type: i3.NzTooltipDirective, selector: "[nz-tooltip]", inputs: ["nzTooltipTitle", "nzTooltipTitleContext", "nz-tooltip", "nzTooltipTrigger", "nzTooltipPlacement", "nzTooltipOrigin", "nzTooltipVisible", "nzTooltipMouseEnterDelay", "nzTooltipMouseLeaveDelay", "nzTooltipOverlayClassName", "nzTooltipOverlayStyle", "nzTooltipArrowPointAtCenter", "cdkConnectedOverlayPush", "nzTooltipColor"], outputs: ["nzTooltipVisibleChange"], exportAs: ["nzTooltip"] }] });
628
+ }
629
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoButtonComponent, decorators: [{
630
+ type: Component,
631
+ args: [{ selector: 'geo-button', standalone: true, imports: [CommonModule, NzIconModule, NzToolTipModule], template: "<button\n [type]=\"type\"\n [disabled]=\"disabled\"\n class=\"geo-button\"\n [ngClass]=\"classNames\"\n [nz-tooltip]=\"tooltipTitle\"\n [nzTooltipPlacement]=\"tooltipPlacement\"\n [nzTooltipTrigger]=\"tooltipTitle ? 'hover' : null\"\n [attr.aria-label]=\"tooltipTitle || null\"\n [attr.aria-pressed]=\"active ? true : null\"\n (click)=\"onClick($event)\"\n>\n @if (icon && iconPlacement === 'start') {\n <span class=\"geo-button__icon\">\n <span nz-icon [nzType]=\"icon\" [nzTheme]=\"iconTheme\"></span>\n </span>\n }\n @if (!iconOnly) {\n <span class=\"geo-button__label\">\n <ng-content></ng-content>\n </span>\n }\n @if (icon && iconPlacement === 'end') {\n <span class=\"geo-button__icon\">\n <span nz-icon [nzType]=\"icon\" [nzTheme]=\"iconTheme\"></span>\n </span>\n }\n</button>\n", styles: [".geo-button{display:inline-flex;align-items:center;justify-content:center;gap:6px;height:var(--geo-control-height);min-height:var(--geo-control-height);padding:0 16px;border-radius:var(--geo-radius);border:1px solid transparent;font-size:var(--geo-font-size-sm);font-weight:500;line-height:normal;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,color .15s ease;white-space:nowrap;font-family:inherit;background:transparent;box-sizing:border-box}.geo-button.geo-button--brand{--geo-btn-tone: var(--geo-color-primary-default);--geo-btn-tone-dark: var(--geo-color-primary-hover);--geo-btn-tone-surface: var(--geo-color-primary-surface-light);--geo-btn-secondary-hover: var(--geo-color-primary-secondary-hover)}.geo-button.geo-button--danger{--geo-btn-tone: var(--geo-color-error-default);--geo-btn-tone-dark: var(--geo-color-error-dark);--geo-btn-tone-surface: var(--geo-color-error-light);--geo-btn-secondary-hover: var(--geo-color-error-light)}.geo-button.geo-button--warning{--geo-btn-tone: var(--geo-color-warning-default);--geo-btn-tone-dark: var(--geo-color-warning-dark);--geo-btn-tone-surface: var(--geo-color-warning-light);--geo-btn-secondary-hover: var(--geo-color-warning-light)}.geo-button.geo-button--success{--geo-btn-tone: var(--geo-color-success-default);--geo-btn-tone-dark: var(--geo-color-success-dark);--geo-btn-tone-surface: var(--geo-color-success-light);--geo-btn-secondary-hover: var(--geo-color-success-light)}.geo-button:disabled{cursor:not-allowed;pointer-events:none}.geo-button--primary{background:var(--geo-btn-tone);border-color:var(--geo-btn-tone);color:var(--geo-color-neutral-white)}.geo-button--primary:hover:not(:disabled){background:var(--geo-btn-tone-dark);border-color:var(--geo-btn-tone-dark)}.geo-button--primary:disabled{background:var(--geo-color-neutral-300);border-color:var(--geo-color-neutral-300);color:var(--geo-color-neutral-disabled-text)}.geo-button--secondary{background:var(--geo-color-neutral-white);border-color:var(--geo-btn-tone);color:var(--geo-btn-tone)}.geo-button--secondary:hover:not(:disabled){background:var(--geo-btn-secondary-hover)}.geo-button--secondary:disabled{background:var(--geo-color-neutral-white);border-color:var(--geo-color-neutral-300);color:var(--geo-color-neutral-disabled-text)}.geo-button--tertiary{background:transparent;border-color:transparent;color:var(--geo-btn-tone)}.geo-button--tertiary:hover:not(:disabled){background:var(--geo-btn-tone-surface)}.geo-button--tertiary:disabled{background:transparent;border-color:transparent;color:var(--geo-color-neutral-disabled-text)}.geo-button--icon-only{width:var(--geo-control-height);min-width:var(--geo-control-height);padding:0}.geo-button--active:not(:disabled).geo-button--secondary,.geo-button--active:not(:disabled).geo-button--tertiary{background:var(--geo-btn-tone-surface);border-color:var(--geo-btn-tone);color:var(--geo-btn-tone);box-shadow:inset 0 0 0 1px var(--geo-btn-tone)}.geo-button--active:not(:disabled).geo-button--primary{background:var(--geo-btn-tone-dark);border-color:var(--geo-btn-tone-dark);color:var(--geo-color-neutral-white)}.geo-button__icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:16px;height:16px;font-size:16px;line-height:1}.geo-button__icon:empty{display:none}.geo-button__icon :deep(.anticon),.geo-button__icon :deep(em){width:16px;height:16px;font-size:16px}.geo-button__label{display:inline-flex;align-items:center}\n"] }]
632
+ }], propDecorators: { appearance: [{
633
+ type: Input
634
+ }], color: [{
635
+ type: Input
636
+ }], icon: [{
637
+ type: Input
638
+ }], iconTheme: [{
639
+ type: Input
640
+ }], iconPlacement: [{
641
+ type: Input
642
+ }], iconOnly: [{
643
+ type: Input
644
+ }], type: [{
645
+ type: Input
646
+ }], disabled: [{
647
+ type: Input
648
+ }], tooltip: [{
649
+ type: Input
650
+ }], tooltipPlacement: [{
651
+ type: Input
652
+ }], active: [{
653
+ type: Input
654
+ }], title: [{
655
+ type: Input
656
+ }], clicked: [{
657
+ type: Output
658
+ }] } });
659
+
660
+ class GeoCheckboxComponent {
661
+ label = '';
662
+ checked = false;
663
+ disabled = false;
664
+ indeterminate = false;
665
+ checkedChange = new EventEmitter();
666
+ onChange(value) {
667
+ this.checked = value;
668
+ this.checkedChange.emit(value);
669
+ }
670
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
671
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: GeoCheckboxComponent, isStandalone: true, selector: "geo-checkbox", inputs: { label: "label", checked: "checked", disabled: "disabled", indeterminate: "indeterminate" }, outputs: { checkedChange: "checkedChange" }, ngImport: i0, template: "<label\n nz-checkbox\n class=\"geo-checkbox\"\n [nzDisabled]=\"disabled\"\n [nzIndeterminate]=\"indeterminate\"\n [(ngModel)]=\"checked\"\n (ngModelChange)=\"onChange($event)\"\n>{{ label }}</label>\n", styles: ["geo-checkbox{display:inline-block;--ant-primary-color: var(--geo-color-primary-default);--ant-primary-color-hover: var(--geo-color-primary-hover);--ant-primary-color-active: var(--geo-color-primary-hover)}geo-checkbox .geo-checkbox{font-size:14px;color:var(--geo-color-neutral-900)}geo-checkbox .ant-checkbox:not(.ant-checkbox-disabled):hover .ant-checkbox-inner{border-color:var(--geo-color-primary-default)!important}geo-checkbox .ant-checkbox-checked:not(.ant-checkbox-disabled) .ant-checkbox-inner{background-color:var(--geo-color-primary-default)!important;border-color:var(--geo-color-primary-default)!important}geo-checkbox .ant-checkbox-checked:not(.ant-checkbox-disabled):after{border-color:var(--geo-color-primary-default)!important}geo-checkbox .ant-checkbox-indeterminate:not(.ant-checkbox-disabled) .ant-checkbox-inner{background-color:var(--geo-color-neutral-white)!important;border-color:var(--geo-color-primary-default)!important}geo-checkbox .ant-checkbox-indeterminate:not(.ant-checkbox-disabled) .ant-checkbox-inner:after{background-color:var(--geo-color-primary-default)!important}geo-checkbox .ant-checkbox-input:focus+.ant-checkbox-inner,geo-checkbox .ant-checkbox-input:focus-visible+.ant-checkbox-inner{border-color:var(--geo-color-primary-default)!important}geo-checkbox .ant-checkbox-checked:not(.ant-checkbox-disabled):hover .ant-checkbox-inner{background-color:var(--geo-color-primary-hover)!important;border-color:var(--geo-color-primary-hover)!important}geo-checkbox .ant-checkbox-indeterminate:not(.ant-checkbox-disabled):hover .ant-checkbox-inner{border-color:var(--geo-color-primary-hover)!important}geo-checkbox .ant-checkbox-indeterminate:not(.ant-checkbox-disabled):hover .ant-checkbox-inner:after{background-color:var(--geo-color-primary-hover)!important}geo-checkbox .ant-checkbox-disabled .ant-checkbox-inner{background-color:var(--geo-color-neutral-100)!important;border-color:var(--geo-color-neutral-300)!important}geo-checkbox .ant-checkbox-disabled.ant-checkbox-checked .ant-checkbox-inner:after{border-color:#00000040!important}geo-checkbox .ant-checkbox-disabled.ant-checkbox-indeterminate .ant-checkbox-inner:after{background-color:#00000040!important}\n"], dependencies: [{ kind: "ngmodule", type: NgZorroAntdModule }, { kind: "component", type: i1$3.NzCheckboxComponent, selector: "[nz-checkbox]", inputs: ["nzValue", "nzAutoFocus", "nzDisabled", "nzIndeterminate", "nzChecked", "nzId"], outputs: ["nzCheckedChange"], exportAs: ["nzCheckbox"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], encapsulation: i0.ViewEncapsulation.None });
672
+ }
673
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoCheckboxComponent, decorators: [{
674
+ type: Component,
675
+ args: [{ selector: 'geo-checkbox', standalone: true, imports: [NgZorroAntdModule, FormsModule], encapsulation: ViewEncapsulation.None, template: "<label\n nz-checkbox\n class=\"geo-checkbox\"\n [nzDisabled]=\"disabled\"\n [nzIndeterminate]=\"indeterminate\"\n [(ngModel)]=\"checked\"\n (ngModelChange)=\"onChange($event)\"\n>{{ label }}</label>\n", styles: ["geo-checkbox{display:inline-block;--ant-primary-color: var(--geo-color-primary-default);--ant-primary-color-hover: var(--geo-color-primary-hover);--ant-primary-color-active: var(--geo-color-primary-hover)}geo-checkbox .geo-checkbox{font-size:14px;color:var(--geo-color-neutral-900)}geo-checkbox .ant-checkbox:not(.ant-checkbox-disabled):hover .ant-checkbox-inner{border-color:var(--geo-color-primary-default)!important}geo-checkbox .ant-checkbox-checked:not(.ant-checkbox-disabled) .ant-checkbox-inner{background-color:var(--geo-color-primary-default)!important;border-color:var(--geo-color-primary-default)!important}geo-checkbox .ant-checkbox-checked:not(.ant-checkbox-disabled):after{border-color:var(--geo-color-primary-default)!important}geo-checkbox .ant-checkbox-indeterminate:not(.ant-checkbox-disabled) .ant-checkbox-inner{background-color:var(--geo-color-neutral-white)!important;border-color:var(--geo-color-primary-default)!important}geo-checkbox .ant-checkbox-indeterminate:not(.ant-checkbox-disabled) .ant-checkbox-inner:after{background-color:var(--geo-color-primary-default)!important}geo-checkbox .ant-checkbox-input:focus+.ant-checkbox-inner,geo-checkbox .ant-checkbox-input:focus-visible+.ant-checkbox-inner{border-color:var(--geo-color-primary-default)!important}geo-checkbox .ant-checkbox-checked:not(.ant-checkbox-disabled):hover .ant-checkbox-inner{background-color:var(--geo-color-primary-hover)!important;border-color:var(--geo-color-primary-hover)!important}geo-checkbox .ant-checkbox-indeterminate:not(.ant-checkbox-disabled):hover .ant-checkbox-inner{border-color:var(--geo-color-primary-hover)!important}geo-checkbox .ant-checkbox-indeterminate:not(.ant-checkbox-disabled):hover .ant-checkbox-inner:after{background-color:var(--geo-color-primary-hover)!important}geo-checkbox .ant-checkbox-disabled .ant-checkbox-inner{background-color:var(--geo-color-neutral-100)!important;border-color:var(--geo-color-neutral-300)!important}geo-checkbox .ant-checkbox-disabled.ant-checkbox-checked .ant-checkbox-inner:after{border-color:#00000040!important}geo-checkbox .ant-checkbox-disabled.ant-checkbox-indeterminate .ant-checkbox-inner:after{background-color:#00000040!important}\n"] }]
676
+ }], propDecorators: { label: [{
677
+ type: Input
678
+ }], checked: [{
679
+ type: Input
680
+ }], disabled: [{
681
+ type: Input
682
+ }], indeterminate: [{
683
+ type: Input
684
+ }], checkedChange: [{
685
+ type: Output
686
+ }] } });
687
+
688
+ class GeoConfirmModalComponent {
689
+ visible = false;
690
+ title = 'Xác nhận xoá';
691
+ message = '';
692
+ highlight = '';
693
+ description = 'Hành động không thể hoàn tác, bạn chắc chắn muốn thực hiện?';
694
+ cancelText = 'Hủy';
695
+ confirmText = 'Xác nhận';
696
+ confirmLoading = false;
697
+ width = 445;
698
+ maskClosable = false;
699
+ closable = true;
700
+ visibleChange = new EventEmitter();
701
+ confirm = new EventEmitter();
702
+ cancel = new EventEmitter();
703
+ get hasDefaultBody() {
704
+ return !!(this.message || this.highlight || this.description);
705
+ }
706
+ onVisibleChange(visible) {
707
+ if (this.visible === visible) {
708
+ return;
709
+ }
710
+ this.visibleChange.emit(visible);
711
+ }
712
+ onCancel() {
713
+ this.visibleChange.emit(false);
714
+ this.cancel.emit();
715
+ }
716
+ onConfirm() {
717
+ this.confirm.emit();
718
+ }
719
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoConfirmModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
720
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoConfirmModalComponent, isStandalone: true, selector: "geo-confirm-modal", inputs: { visible: "visible", title: "title", message: "message", highlight: "highlight", description: "description", cancelText: "cancelText", confirmText: "confirmText", confirmLoading: "confirmLoading", width: "width", maskClosable: "maskClosable", closable: "closable" }, outputs: { visibleChange: "visibleChange", confirm: "confirm", cancel: "cancel" }, ngImport: i0, template: "<nz-modal\n [nzVisible]=\"visible\"\n [nzTitle]=\"''\"\n [nzFooter]=\"null\"\n [nzClosable]=\"false\"\n [nzMaskClosable]=\"maskClosable\"\n [nzWidth]=\"width\"\n nzWrapClassName=\"geo-confirm-modal-wrap\"\n nzClassName=\"geo-confirm-modal\"\n (nzVisibleChange)=\"onVisibleChange($event)\"\n>\n <ng-container *nzModalContent>\n <div class=\"geo-confirm-modal__content\">\n <div class=\"geo-confirm-modal__header\">\n <h2 class=\"geo-confirm-modal__title\">{{ title }}</h2>\n @if (closable) {\n <button\n type=\"button\"\n class=\"geo-confirm-modal__close\"\n aria-label=\"\u0110\u00F3ng\"\n (click)=\"onCancel()\"\n >\n <span nz-icon nzType=\"close\" nzTheme=\"outline\"></span>\n </button>\n }\n </div>\n\n <div class=\"geo-confirm-modal__body\">\n @if (hasDefaultBody) {\n <div class=\"geo-confirm-modal__message\">\n @if (message || highlight) {\n <p class=\"geo-confirm-modal__paragraph\">\n @if (message) {\n <span>{{ message }}</span>\n }\n @if (highlight) {\n <strong class=\"geo-confirm-modal__highlight\">\u201C{{ highlight }}\u201D</strong>\n }\n </p>\n }\n @if (description) {\n <p class=\"geo-confirm-modal__paragraph\">{{ description }}</p>\n }\n </div>\n } @else {\n <div class=\"geo-confirm-modal__message\">\n <ng-content></ng-content>\n </div>\n }\n </div>\n\n <div class=\"geo-confirm-modal__footer\">\n <geo-button appearance=\"secondary\" color=\"brand\" (clicked)=\"onCancel()\">\n {{ cancelText }}\n </geo-button>\n <geo-button\n appearance=\"primary\"\n color=\"brand\"\n [disabled]=\"confirmLoading\"\n (clicked)=\"onConfirm()\"\n >\n {{ confirmText }}\n </geo-button>\n </div>\n </div>\n </ng-container>\n</nz-modal>\n", styles: [".geo-confirm-modal-wrap .ant-modal-header{display:none}.geo-confirm-modal-wrap .ant-modal-content{border-radius:var(--geo-radius);padding:0;overflow:hidden}.geo-confirm-modal-wrap .ant-modal-body{padding:0}.geo-confirm-modal__content{display:flex;flex-direction:column;gap:17px;padding:24px;background:var(--geo-color-neutral-white)}.geo-confirm-modal__header{display:flex;align-items:center;justify-content:space-between;gap:16px;padding-bottom:16px}.geo-confirm-modal__title{margin:0;font-size:18px;font-weight:700;line-height:normal;color:var(--geo-color-neutral-500)}.geo-confirm-modal__close{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;background:transparent;color:var(--geo-color-neutral-500);cursor:pointer;flex-shrink:0}.geo-confirm-modal__close:hover{color:var(--geo-color-neutral-900)}.geo-confirm-modal__body{display:flex;flex-direction:column}.geo-confirm-modal__message{display:flex;flex-direction:column;gap:8px;max-width:397px;font-size:14px;line-height:1.4;color:var(--geo-color-neutral-900)}.geo-confirm-modal__paragraph{margin:0}.geo-confirm-modal__highlight{font-weight:600}.geo-confirm-modal__footer{display:flex;align-items:center;justify-content:flex-end;gap:12px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: NgZorroAntdModule }, { kind: "directive", type: i1$5.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i1.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "component", type: i3$1.NzModalComponent, selector: "nz-modal", inputs: ["nzMask", "nzMaskClosable", "nzCloseOnNavigation", "nzVisible", "nzClosable", "nzOkLoading", "nzOkDisabled", "nzCancelDisabled", "nzCancelLoading", "nzKeyboard", "nzNoAnimation", "nzCentered", "nzDraggable", "nzContent", "nzFooter", "nzZIndex", "nzWidth", "nzWrapClassName", "nzClassName", "nzStyle", "nzTitle", "nzCloseIcon", "nzMaskStyle", "nzBodyStyle", "nzOkText", "nzCancelText", "nzOkType", "nzOkDanger", "nzIconType", "nzModalType", "nzAutofocus", "nzOnOk", "nzOnCancel"], outputs: ["nzOnOk", "nzOnCancel", "nzAfterOpen", "nzAfterClose", "nzVisibleChange"], exportAs: ["nzModal"] }, { kind: "directive", type: i3$1.NzModalContentDirective, selector: "[nzModalContent]", exportAs: ["nzModalContent"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "component", type: GeoButtonComponent, selector: "geo-button", inputs: ["appearance", "color", "icon", "iconTheme", "iconPlacement", "iconOnly", "type", "disabled", "tooltip", "tooltipPlacement", "active", "title"], outputs: ["clicked"] }], encapsulation: i0.ViewEncapsulation.None });
721
+ }
722
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoConfirmModalComponent, decorators: [{
723
+ type: Component,
724
+ args: [{ selector: 'geo-confirm-modal', standalone: true, imports: [CommonModule, NgZorroAntdModule, NzIconModule, GeoButtonComponent], encapsulation: ViewEncapsulation.None, template: "<nz-modal\n [nzVisible]=\"visible\"\n [nzTitle]=\"''\"\n [nzFooter]=\"null\"\n [nzClosable]=\"false\"\n [nzMaskClosable]=\"maskClosable\"\n [nzWidth]=\"width\"\n nzWrapClassName=\"geo-confirm-modal-wrap\"\n nzClassName=\"geo-confirm-modal\"\n (nzVisibleChange)=\"onVisibleChange($event)\"\n>\n <ng-container *nzModalContent>\n <div class=\"geo-confirm-modal__content\">\n <div class=\"geo-confirm-modal__header\">\n <h2 class=\"geo-confirm-modal__title\">{{ title }}</h2>\n @if (closable) {\n <button\n type=\"button\"\n class=\"geo-confirm-modal__close\"\n aria-label=\"\u0110\u00F3ng\"\n (click)=\"onCancel()\"\n >\n <span nz-icon nzType=\"close\" nzTheme=\"outline\"></span>\n </button>\n }\n </div>\n\n <div class=\"geo-confirm-modal__body\">\n @if (hasDefaultBody) {\n <div class=\"geo-confirm-modal__message\">\n @if (message || highlight) {\n <p class=\"geo-confirm-modal__paragraph\">\n @if (message) {\n <span>{{ message }}</span>\n }\n @if (highlight) {\n <strong class=\"geo-confirm-modal__highlight\">\u201C{{ highlight }}\u201D</strong>\n }\n </p>\n }\n @if (description) {\n <p class=\"geo-confirm-modal__paragraph\">{{ description }}</p>\n }\n </div>\n } @else {\n <div class=\"geo-confirm-modal__message\">\n <ng-content></ng-content>\n </div>\n }\n </div>\n\n <div class=\"geo-confirm-modal__footer\">\n <geo-button appearance=\"secondary\" color=\"brand\" (clicked)=\"onCancel()\">\n {{ cancelText }}\n </geo-button>\n <geo-button\n appearance=\"primary\"\n color=\"brand\"\n [disabled]=\"confirmLoading\"\n (clicked)=\"onConfirm()\"\n >\n {{ confirmText }}\n </geo-button>\n </div>\n </div>\n </ng-container>\n</nz-modal>\n", styles: [".geo-confirm-modal-wrap .ant-modal-header{display:none}.geo-confirm-modal-wrap .ant-modal-content{border-radius:var(--geo-radius);padding:0;overflow:hidden}.geo-confirm-modal-wrap .ant-modal-body{padding:0}.geo-confirm-modal__content{display:flex;flex-direction:column;gap:17px;padding:24px;background:var(--geo-color-neutral-white)}.geo-confirm-modal__header{display:flex;align-items:center;justify-content:space-between;gap:16px;padding-bottom:16px}.geo-confirm-modal__title{margin:0;font-size:18px;font-weight:700;line-height:normal;color:var(--geo-color-neutral-500)}.geo-confirm-modal__close{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;background:transparent;color:var(--geo-color-neutral-500);cursor:pointer;flex-shrink:0}.geo-confirm-modal__close:hover{color:var(--geo-color-neutral-900)}.geo-confirm-modal__body{display:flex;flex-direction:column}.geo-confirm-modal__message{display:flex;flex-direction:column;gap:8px;max-width:397px;font-size:14px;line-height:1.4;color:var(--geo-color-neutral-900)}.geo-confirm-modal__paragraph{margin:0}.geo-confirm-modal__highlight{font-weight:600}.geo-confirm-modal__footer{display:flex;align-items:center;justify-content:flex-end;gap:12px}\n"] }]
725
+ }], propDecorators: { visible: [{
726
+ type: Input
727
+ }], title: [{
728
+ type: Input
729
+ }], message: [{
730
+ type: Input
731
+ }], highlight: [{
732
+ type: Input
733
+ }], description: [{
734
+ type: Input
735
+ }], cancelText: [{
736
+ type: Input
737
+ }], confirmText: [{
738
+ type: Input
739
+ }], confirmLoading: [{
740
+ type: Input
741
+ }], width: [{
742
+ type: Input
743
+ }], maskClosable: [{
744
+ type: Input
745
+ }], closable: [{
746
+ type: Input
747
+ }], visibleChange: [{
748
+ type: Output
749
+ }], confirm: [{
750
+ type: Output
751
+ }], cancel: [{
752
+ type: Output
753
+ }] } });
754
+
755
+ let uiDatePickerErrorId = 0;
756
+ class GeoDatePickerComponent {
757
+ label = '';
758
+ placeholder = 'Chọn ngày';
759
+ format = 'dd/MM/yyyy';
760
+ mode = 'date';
761
+ size = 'default';
762
+ disabled = false;
763
+ required = false;
764
+ error = false;
765
+ errorMessage = '';
766
+ allowClear = true;
767
+ showToday = true;
768
+ showTime = false;
769
+ block = false;
770
+ width;
771
+ disabledDate;
772
+ valueChange = new EventEmitter();
773
+ errorMessageId = `geo-date-picker-error-${++uiDatePickerErrorId}`;
774
+ value = null;
775
+ onChange = () => undefined;
776
+ onTouched = () => undefined;
777
+ get hostWidth() {
778
+ if (this.block || this.width == null) {
779
+ return null;
780
+ }
781
+ return typeof this.width === 'number' ? `${this.width}px` : this.width;
782
+ }
783
+ get controlClassNames() {
784
+ return {
785
+ 'geo-date-picker': true,
786
+ [`geo-date-picker--${this.size}`]: true,
787
+ };
788
+ }
789
+ onValueChange(value) {
790
+ this.value = value;
791
+ this.onChange(value);
792
+ this.onTouched();
793
+ this.valueChange.emit(value);
794
+ }
795
+ writeValue(value) {
796
+ this.value = value ?? null;
797
+ }
798
+ registerOnChange(fn) {
799
+ this.onChange = fn;
800
+ }
801
+ registerOnTouched(fn) {
802
+ this.onTouched = fn;
803
+ }
804
+ setDisabledState(isDisabled) {
805
+ this.disabled = isDisabled;
806
+ }
807
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoDatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
808
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoDatePickerComponent, isStandalone: true, selector: "geo-date-picker", inputs: { label: "label", placeholder: "placeholder", format: "format", mode: "mode", size: "size", disabled: "disabled", required: "required", error: "error", errorMessage: "errorMessage", allowClear: "allowClear", showToday: "showToday", showTime: "showTime", block: "block", width: "width", disabledDate: "disabledDate" }, outputs: { valueChange: "valueChange" }, host: { properties: { "class.geo-date-picker-host--default": "size === \"default\"", "class.geo-date-picker-host--small": "size === \"small\"", "class.geo-date-picker-host--block": "block", "class.geo-date-picker-host--error": "error", "style.width": "hostWidth" }, classAttribute: "geo-date-picker-host" }, providers: [
809
+ {
810
+ provide: NG_VALUE_ACCESSOR,
811
+ useExisting: forwardRef(() => GeoDatePickerComponent),
812
+ multi: true,
813
+ },
814
+ ], ngImport: i0, template: "@if (label) {\n <div class=\"geo-date-picker__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-date-picker__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<nz-date-picker\n [ngClass]=\"controlClassNames\"\n nzDropdownClassName=\"geo-date-picker__dropdown\"\n [nzPlaceHolder]=\"placeholder\"\n [nzFormat]=\"format\"\n [nzMode]=\"mode\"\n [nzDisabled]=\"disabled\"\n [nzAllowClear]=\"allowClear\"\n [nzShowToday]=\"showToday\"\n [nzShowTime]=\"showTime\"\n [nzDisabledDate]=\"disabledDate\"\n [ngModel]=\"value\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n (ngModelChange)=\"onValueChange($event)\"\n></nz-date-picker>\n\n@if (error && errorMessage) {\n <p class=\"geo-date-picker__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: ["geo-date-picker.geo-date-picker-host,.geo-date-picker-host{display:inline-flex;flex-direction:column;gap:8px;width:413px;max-width:100%;vertical-align:top}.geo-date-picker-host--small{width:200px}geo-date-picker.geo-date-picker-host.geo-date-picker-host--block,.geo-date-picker-host.geo-date-picker-host--block{display:flex;width:100%;max-width:none}.geo-date-picker__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-date-picker__required{color:var(--geo-color-error-default)}.geo-date-picker__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}.geo-date-picker{display:inline-flex;align-items:center;width:100%;box-sizing:border-box}.geo-date-picker.ant-picker{border-radius:var(--geo-radius);border-color:var(--geo-color-neutral-300);padding:4px 11px;background:transparent;box-shadow:none;transition:border-color .15s ease,box-shadow .15s ease}.geo-date-picker--default.ant-picker{min-height:40px;height:40px}.geo-date-picker--small.ant-picker{min-height:32px;height:32px;padding:2px 8px}.geo-date-picker .ant-picker-input>input{min-width:0;font-size:14px;line-height:22px;color:var(--geo-color-neutral-900)}.geo-date-picker .ant-picker-input>input::placeholder{color:var(--geo-color-neutral-500)}.geo-date-picker .ant-picker-suffix,.geo-date-picker .ant-picker-clear{display:inline-flex;align-items:center;flex:0 0 auto;color:var(--geo-color-neutral-500)}.geo-date-picker:not(.ant-picker-disabled):hover{border-color:var(--geo-color-primary-default)}.geo-date-picker.ant-picker-focused{border-color:var(--geo-color-primary-default);box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-primary-default) 12%,transparent)}.geo-date-picker.ant-picker-disabled{background:var(--geo-color-neutral-100);border-color:var(--geo-color-neutral-300)}.geo-date-picker.ant-picker-disabled .ant-picker-input>input{color:var(--geo-color-neutral-disabled-text)}.geo-date-picker-host--error .geo-date-picker.ant-picker{border-color:var(--geo-color-error-default)!important}.geo-date-picker-host--error .geo-date-picker.ant-picker-focused{box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-error-default) 12%,transparent)!important}.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-panel-container{border-radius:var(--geo-radius);overflow:hidden}.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-selected .ant-picker-cell-inner,.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-start .ant-picker-cell-inner,.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-end .ant-picker-cell-inner{background:var(--geo-color-primary-default)}.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-today .ant-picker-cell-inner:before{border-color:var(--geo-color-primary-default)}.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-start .ant-picker-cell-inner,.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-end .ant-picker-cell-inner,.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover .ant-picker-cell-inner{background:var(--color-primary-surface-hover, var(--geo-color-primary-background))}.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-today-btn,.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-header-view button:hover,.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-header button:hover{color:var(--geo-color-primary-default)}.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-ok .ant-btn-primary{background:var(--geo-color-primary-default);border-color:var(--geo-color-primary-default)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NgZorroAntdModule }, { kind: "component", type: i3$2.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzAllowClear", "nzAutoFocus", "nzDisabled", "nzBorderless", "nzInputReadOnly", "nzInline", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }], encapsulation: i0.ViewEncapsulation.None });
815
+ }
816
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoDatePickerComponent, decorators: [{
817
+ type: Component,
818
+ args: [{ selector: 'geo-date-picker', standalone: true, imports: [CommonModule, FormsModule, NgZorroAntdModule], encapsulation: ViewEncapsulation.None, host: {
819
+ class: 'geo-date-picker-host',
820
+ '[class.geo-date-picker-host--default]': 'size === "default"',
821
+ '[class.geo-date-picker-host--small]': 'size === "small"',
822
+ '[class.geo-date-picker-host--block]': 'block',
823
+ '[class.geo-date-picker-host--error]': 'error',
824
+ '[style.width]': 'hostWidth',
825
+ }, providers: [
826
+ {
827
+ provide: NG_VALUE_ACCESSOR,
828
+ useExisting: forwardRef(() => GeoDatePickerComponent),
829
+ multi: true,
830
+ },
831
+ ], template: "@if (label) {\n <div class=\"geo-date-picker__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-date-picker__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<nz-date-picker\n [ngClass]=\"controlClassNames\"\n nzDropdownClassName=\"geo-date-picker__dropdown\"\n [nzPlaceHolder]=\"placeholder\"\n [nzFormat]=\"format\"\n [nzMode]=\"mode\"\n [nzDisabled]=\"disabled\"\n [nzAllowClear]=\"allowClear\"\n [nzShowToday]=\"showToday\"\n [nzShowTime]=\"showTime\"\n [nzDisabledDate]=\"disabledDate\"\n [ngModel]=\"value\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n (ngModelChange)=\"onValueChange($event)\"\n></nz-date-picker>\n\n@if (error && errorMessage) {\n <p class=\"geo-date-picker__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: ["geo-date-picker.geo-date-picker-host,.geo-date-picker-host{display:inline-flex;flex-direction:column;gap:8px;width:413px;max-width:100%;vertical-align:top}.geo-date-picker-host--small{width:200px}geo-date-picker.geo-date-picker-host.geo-date-picker-host--block,.geo-date-picker-host.geo-date-picker-host--block{display:flex;width:100%;max-width:none}.geo-date-picker__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-date-picker__required{color:var(--geo-color-error-default)}.geo-date-picker__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}.geo-date-picker{display:inline-flex;align-items:center;width:100%;box-sizing:border-box}.geo-date-picker.ant-picker{border-radius:var(--geo-radius);border-color:var(--geo-color-neutral-300);padding:4px 11px;background:transparent;box-shadow:none;transition:border-color .15s ease,box-shadow .15s ease}.geo-date-picker--default.ant-picker{min-height:40px;height:40px}.geo-date-picker--small.ant-picker{min-height:32px;height:32px;padding:2px 8px}.geo-date-picker .ant-picker-input>input{min-width:0;font-size:14px;line-height:22px;color:var(--geo-color-neutral-900)}.geo-date-picker .ant-picker-input>input::placeholder{color:var(--geo-color-neutral-500)}.geo-date-picker .ant-picker-suffix,.geo-date-picker .ant-picker-clear{display:inline-flex;align-items:center;flex:0 0 auto;color:var(--geo-color-neutral-500)}.geo-date-picker:not(.ant-picker-disabled):hover{border-color:var(--geo-color-primary-default)}.geo-date-picker.ant-picker-focused{border-color:var(--geo-color-primary-default);box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-primary-default) 12%,transparent)}.geo-date-picker.ant-picker-disabled{background:var(--geo-color-neutral-100);border-color:var(--geo-color-neutral-300)}.geo-date-picker.ant-picker-disabled .ant-picker-input>input{color:var(--geo-color-neutral-disabled-text)}.geo-date-picker-host--error .geo-date-picker.ant-picker{border-color:var(--geo-color-error-default)!important}.geo-date-picker-host--error .geo-date-picker.ant-picker-focused{box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-error-default) 12%,transparent)!important}.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-panel-container{border-radius:var(--geo-radius);overflow:hidden}.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-selected .ant-picker-cell-inner,.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-start .ant-picker-cell-inner,.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-end .ant-picker-cell-inner{background:var(--geo-color-primary-default)}.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-today .ant-picker-cell-inner:before{border-color:var(--geo-color-primary-default)}.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-start .ant-picker-cell-inner,.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-end .ant-picker-cell-inner,.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover .ant-picker-cell-inner{background:var(--color-primary-surface-hover, var(--geo-color-primary-background))}.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-today-btn,.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-header-view button:hover,.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-header button:hover{color:var(--geo-color-primary-default)}.geo-date-picker__dropdown.ant-picker-dropdown .ant-picker-ok .ant-btn-primary{background:var(--geo-color-primary-default);border-color:var(--geo-color-primary-default)}\n"] }]
832
+ }], propDecorators: { label: [{
833
+ type: Input
834
+ }], placeholder: [{
835
+ type: Input
836
+ }], format: [{
837
+ type: Input
838
+ }], mode: [{
839
+ type: Input
840
+ }], size: [{
841
+ type: Input
842
+ }], disabled: [{
843
+ type: Input
844
+ }], required: [{
845
+ type: Input
846
+ }], error: [{
847
+ type: Input
848
+ }], errorMessage: [{
849
+ type: Input
850
+ }], allowClear: [{
851
+ type: Input
852
+ }], showToday: [{
853
+ type: Input
854
+ }], showTime: [{
855
+ type: Input
856
+ }], block: [{
857
+ type: Input
858
+ }], width: [{
859
+ type: Input
860
+ }], disabledDate: [{
861
+ type: Input
862
+ }], valueChange: [{
863
+ type: Output
864
+ }] } });
865
+
866
+ let uiDateRangeErrorId = 0;
867
+ class GeoDateRangePickerComponent {
868
+ label = '';
869
+ placeholder = ['Từ ngày', 'Đến ngày'];
870
+ format = 'dd/MM/yyyy';
871
+ size = 'default';
872
+ disabled = false;
873
+ required = false;
874
+ error = false;
875
+ errorMessage = '';
876
+ allowClear = true;
877
+ showTime = false;
878
+ block = false;
879
+ width;
880
+ disabledDate;
881
+ separator = '→';
882
+ valueChange = new EventEmitter();
883
+ errorMessageId = `geo-date-range-picker-error-${++uiDateRangeErrorId}`;
884
+ value = null;
885
+ onChange = () => undefined;
886
+ onTouched = () => undefined;
887
+ get hostWidth() {
888
+ if (this.block || this.width == null) {
889
+ return null;
890
+ }
891
+ return typeof this.width === 'number' ? `${this.width}px` : this.width;
892
+ }
893
+ get controlClassNames() {
894
+ return {
895
+ 'geo-date-range-picker': true,
896
+ [`geo-date-range-picker--${this.size}`]: true,
897
+ };
898
+ }
899
+ onValueChange(value) {
900
+ this.value = value;
901
+ this.onChange(value);
902
+ this.onTouched();
903
+ this.valueChange.emit(value);
904
+ }
905
+ writeValue(value) {
906
+ this.value = value ?? null;
907
+ }
908
+ registerOnChange(fn) {
909
+ this.onChange = fn;
910
+ }
911
+ registerOnTouched(fn) {
912
+ this.onTouched = fn;
913
+ }
914
+ setDisabledState(isDisabled) {
915
+ this.disabled = isDisabled;
916
+ }
917
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoDateRangePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
918
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoDateRangePickerComponent, isStandalone: true, selector: "geo-date-range-picker", inputs: { label: "label", placeholder: "placeholder", format: "format", size: "size", disabled: "disabled", required: "required", error: "error", errorMessage: "errorMessage", allowClear: "allowClear", showTime: "showTime", block: "block", width: "width", disabledDate: "disabledDate", separator: "separator" }, outputs: { valueChange: "valueChange" }, host: { properties: { "class.geo-date-range-picker-host--default": "size === \"default\"", "class.geo-date-range-picker-host--small": "size === \"small\"", "class.geo-date-range-picker-host--block": "block", "class.geo-date-range-picker-host--error": "error", "style.width": "hostWidth" }, classAttribute: "geo-date-range-picker-host" }, providers: [
919
+ {
920
+ provide: NG_VALUE_ACCESSOR,
921
+ useExisting: forwardRef(() => GeoDateRangePickerComponent),
922
+ multi: true,
923
+ },
924
+ ], ngImport: i0, template: "@if (label) {\n <div class=\"geo-date-range-picker__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-date-range-picker__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<nz-range-picker\n [ngClass]=\"controlClassNames\"\n nzDropdownClassName=\"geo-date-range-picker__dropdown\"\n [nzPlaceHolder]=\"placeholder\"\n [nzFormat]=\"format\"\n [nzDisabled]=\"disabled\"\n [nzAllowClear]=\"allowClear\"\n [nzShowTime]=\"showTime\"\n [nzDisabledDate]=\"disabledDate\"\n [nzSeparator]=\"separator\"\n [ngModel]=\"value\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n (ngModelChange)=\"onValueChange($event)\"\n></nz-range-picker>\n\n@if (error && errorMessage) {\n <p class=\"geo-date-range-picker__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: ["geo-date-range-picker.geo-date-range-picker-host,.geo-date-range-picker-host{display:inline-flex;flex-direction:column;gap:8px;width:413px;max-width:100%;vertical-align:top}.geo-date-range-picker-host--small{width:280px}geo-date-range-picker.geo-date-range-picker-host.geo-date-range-picker-host--block,.geo-date-range-picker-host.geo-date-range-picker-host--block{display:flex;width:100%;max-width:none}.geo-date-range-picker__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-date-range-picker__required{color:var(--geo-color-error-default)}.geo-date-range-picker__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}.geo-date-range-picker{display:inline-flex;align-items:center;flex-wrap:nowrap;width:100%;box-sizing:border-box}.geo-date-range-picker.ant-picker{border-radius:var(--geo-radius);border-color:var(--geo-color-neutral-300);padding:4px 11px;background:transparent;box-shadow:none;transition:border-color .15s ease,box-shadow .15s ease}.geo-date-range-picker--default.ant-picker{min-height:40px;height:40px}.geo-date-range-picker--small.ant-picker{min-height:32px;height:32px;padding:2px 8px}.geo-date-range-picker .ant-picker-input>input{min-width:0;font-size:14px;line-height:22px;color:var(--geo-color-neutral-900)}.geo-date-range-picker .ant-picker-input{display:inline-flex;align-items:center;flex:1 1 0;min-width:0}.geo-date-range-picker .ant-picker-input>input::placeholder{color:var(--geo-color-neutral-500)}.geo-date-range-picker .ant-picker-separator,.geo-date-range-picker .ant-picker-suffix,.geo-date-range-picker .ant-picker-clear{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;color:var(--geo-color-neutral-500)}.geo-date-range-picker .ant-picker-separator{padding-inline:8px}.geo-date-range-picker:not(.ant-picker-disabled):hover{border-color:var(--geo-color-primary-default)}.geo-date-range-picker.ant-picker-focused{border-color:var(--geo-color-primary-default);box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-primary-default) 12%,transparent)}.geo-date-range-picker.ant-picker-disabled{background:var(--geo-color-neutral-100);border-color:var(--geo-color-neutral-300)}.geo-date-range-picker.ant-picker-disabled .ant-picker-input>input{color:var(--geo-color-neutral-disabled-text)}.geo-date-range-picker-host--error .geo-date-range-picker.ant-picker{border-color:var(--geo-color-error-default)!important}.geo-date-range-picker-host--error .geo-date-range-picker.ant-picker-focused{box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-error-default) 12%,transparent)!important}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-panel-container{border-radius:var(--geo-radius);overflow:hidden}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-selected .ant-picker-cell-inner,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-start .ant-picker-cell-inner,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-end .ant-picker-cell-inner{background:var(--geo-color-primary-default)}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-today .ant-picker-cell-inner:before{border-color:var(--geo-color-primary-default)}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-in-range:before,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover:before,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-start:before,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-end:before{background:var(--color-primary-surface, var(--geo-color-primary-surface-light))}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-start .ant-picker-cell-inner,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-end .ant-picker-cell-inner,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover .ant-picker-cell-inner{background:var(--color-primary-surface-hover, var(--geo-color-primary-background))}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-today-btn,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-header-view button:hover,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-header button:hover{color:var(--geo-color-primary-default)}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-ok .ant-btn-primary{background:var(--geo-color-primary-default);border-color:var(--geo-color-primary-default)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NgZorroAntdModule }, { kind: "component", type: i3$2.NzDatePickerComponent, selector: "nz-date-picker,nz-week-picker,nz-month-picker,nz-quarter-picker,nz-year-picker,nz-range-picker", inputs: ["nzAllowClear", "nzAutoFocus", "nzDisabled", "nzBorderless", "nzInputReadOnly", "nzInline", "nzOpen", "nzDisabledDate", "nzLocale", "nzPlaceHolder", "nzPopupStyle", "nzDropdownClassName", "nzSize", "nzStatus", "nzFormat", "nzDateRender", "nzDisabledTime", "nzRenderExtraFooter", "nzShowToday", "nzMode", "nzShowNow", "nzRanges", "nzDefaultPickerValue", "nzSeparator", "nzSuffixIcon", "nzBackdrop", "nzId", "nzPlacement", "nzShowWeekNumber", "nzShowTime"], outputs: ["nzOnPanelChange", "nzOnCalendarChange", "nzOnOk", "nzOnOpenChange"], exportAs: ["nzDatePicker"] }, { kind: "directive", type: i3$2.NzRangePickerComponent, selector: "nz-range-picker", exportAs: ["nzRangePicker"] }], encapsulation: i0.ViewEncapsulation.None });
925
+ }
926
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoDateRangePickerComponent, decorators: [{
927
+ type: Component,
928
+ args: [{ selector: 'geo-date-range-picker', standalone: true, imports: [CommonModule, FormsModule, NgZorroAntdModule], encapsulation: ViewEncapsulation.None, host: {
929
+ class: 'geo-date-range-picker-host',
930
+ '[class.geo-date-range-picker-host--default]': 'size === "default"',
931
+ '[class.geo-date-range-picker-host--small]': 'size === "small"',
932
+ '[class.geo-date-range-picker-host--block]': 'block',
933
+ '[class.geo-date-range-picker-host--error]': 'error',
934
+ '[style.width]': 'hostWidth',
935
+ }, providers: [
936
+ {
937
+ provide: NG_VALUE_ACCESSOR,
938
+ useExisting: forwardRef(() => GeoDateRangePickerComponent),
939
+ multi: true,
940
+ },
941
+ ], template: "@if (label) {\n <div class=\"geo-date-range-picker__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-date-range-picker__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<nz-range-picker\n [ngClass]=\"controlClassNames\"\n nzDropdownClassName=\"geo-date-range-picker__dropdown\"\n [nzPlaceHolder]=\"placeholder\"\n [nzFormat]=\"format\"\n [nzDisabled]=\"disabled\"\n [nzAllowClear]=\"allowClear\"\n [nzShowTime]=\"showTime\"\n [nzDisabledDate]=\"disabledDate\"\n [nzSeparator]=\"separator\"\n [ngModel]=\"value\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n (ngModelChange)=\"onValueChange($event)\"\n></nz-range-picker>\n\n@if (error && errorMessage) {\n <p class=\"geo-date-range-picker__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: ["geo-date-range-picker.geo-date-range-picker-host,.geo-date-range-picker-host{display:inline-flex;flex-direction:column;gap:8px;width:413px;max-width:100%;vertical-align:top}.geo-date-range-picker-host--small{width:280px}geo-date-range-picker.geo-date-range-picker-host.geo-date-range-picker-host--block,.geo-date-range-picker-host.geo-date-range-picker-host--block{display:flex;width:100%;max-width:none}.geo-date-range-picker__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-date-range-picker__required{color:var(--geo-color-error-default)}.geo-date-range-picker__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}.geo-date-range-picker{display:inline-flex;align-items:center;flex-wrap:nowrap;width:100%;box-sizing:border-box}.geo-date-range-picker.ant-picker{border-radius:var(--geo-radius);border-color:var(--geo-color-neutral-300);padding:4px 11px;background:transparent;box-shadow:none;transition:border-color .15s ease,box-shadow .15s ease}.geo-date-range-picker--default.ant-picker{min-height:40px;height:40px}.geo-date-range-picker--small.ant-picker{min-height:32px;height:32px;padding:2px 8px}.geo-date-range-picker .ant-picker-input>input{min-width:0;font-size:14px;line-height:22px;color:var(--geo-color-neutral-900)}.geo-date-range-picker .ant-picker-input{display:inline-flex;align-items:center;flex:1 1 0;min-width:0}.geo-date-range-picker .ant-picker-input>input::placeholder{color:var(--geo-color-neutral-500)}.geo-date-range-picker .ant-picker-separator,.geo-date-range-picker .ant-picker-suffix,.geo-date-range-picker .ant-picker-clear{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;color:var(--geo-color-neutral-500)}.geo-date-range-picker .ant-picker-separator{padding-inline:8px}.geo-date-range-picker:not(.ant-picker-disabled):hover{border-color:var(--geo-color-primary-default)}.geo-date-range-picker.ant-picker-focused{border-color:var(--geo-color-primary-default);box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-primary-default) 12%,transparent)}.geo-date-range-picker.ant-picker-disabled{background:var(--geo-color-neutral-100);border-color:var(--geo-color-neutral-300)}.geo-date-range-picker.ant-picker-disabled .ant-picker-input>input{color:var(--geo-color-neutral-disabled-text)}.geo-date-range-picker-host--error .geo-date-range-picker.ant-picker{border-color:var(--geo-color-error-default)!important}.geo-date-range-picker-host--error .geo-date-range-picker.ant-picker-focused{box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-error-default) 12%,transparent)!important}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-panel-container{border-radius:var(--geo-radius);overflow:hidden}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-selected .ant-picker-cell-inner,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-start .ant-picker-cell-inner,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-end .ant-picker-cell-inner{background:var(--geo-color-primary-default)}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-today .ant-picker-cell-inner:before{border-color:var(--geo-color-primary-default)}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-in-range:before,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover:before,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-start:before,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-end:before{background:var(--color-primary-surface, var(--geo-color-primary-surface-light))}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-start .ant-picker-cell-inner,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover-end .ant-picker-cell-inner,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-range-hover .ant-picker-cell-inner{background:var(--color-primary-surface-hover, var(--geo-color-primary-background))}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-today-btn,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-header-view button:hover,.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-header button:hover{color:var(--geo-color-primary-default)}.geo-date-range-picker__dropdown.ant-picker-dropdown .ant-picker-ok .ant-btn-primary{background:var(--geo-color-primary-default);border-color:var(--geo-color-primary-default)}\n"] }]
942
+ }], propDecorators: { label: [{
943
+ type: Input
944
+ }], placeholder: [{
945
+ type: Input
946
+ }], format: [{
947
+ type: Input
948
+ }], size: [{
949
+ type: Input
950
+ }], disabled: [{
951
+ type: Input
952
+ }], required: [{
953
+ type: Input
954
+ }], error: [{
955
+ type: Input
956
+ }], errorMessage: [{
957
+ type: Input
958
+ }], allowClear: [{
959
+ type: Input
960
+ }], showTime: [{
961
+ type: Input
962
+ }], block: [{
963
+ type: Input
964
+ }], width: [{
965
+ type: Input
966
+ }], disabledDate: [{
967
+ type: Input
968
+ }], separator: [{
969
+ type: Input
970
+ }], valueChange: [{
971
+ type: Output
972
+ }] } });
973
+
974
+ let uiFilePickerErrorId = 0;
975
+ class GeoFilePickerComponent {
976
+ fileInput;
977
+ label = 'Tải file';
978
+ placeholder = 'Chọn giá trị';
979
+ buttonText = 'Chọn file';
980
+ required = false;
981
+ disabled = false;
982
+ accept = '';
983
+ multiple = false;
984
+ error = false;
985
+ errorMessage = '';
986
+ block = false;
987
+ width;
988
+ /**
989
+ * Tên file đã upload (server) — hiện khi chưa có File local trong CVA.
990
+ * Dùng cho flow: chọn file → upload → giữ tên từ API.
991
+ */
992
+ selectedName = '';
993
+ fileChange = new EventEmitter();
994
+ errorMessageId = `geo-file-picker-error-${++uiFilePickerErrorId}`;
995
+ value = null;
996
+ onChange = () => undefined;
997
+ onTouched = () => undefined;
998
+ get hostWidth() {
999
+ if (this.block || this.width == null) {
1000
+ return null;
1001
+ }
1002
+ return typeof this.width === 'number' ? `${this.width}px` : this.width;
1003
+ }
1004
+ get displayValue() {
1005
+ if (Array.isArray(this.value) && this.value.length > 0) {
1006
+ return this.value.map((file) => file.name).join(', ');
1007
+ }
1008
+ if (this.value && !Array.isArray(this.value)) {
1009
+ return this.value.name;
1010
+ }
1011
+ if (this.selectedName) {
1012
+ return this.selectedName;
1013
+ }
1014
+ return this.placeholder;
1015
+ }
1016
+ get hasValue() {
1017
+ if (Array.isArray(this.value)) {
1018
+ return this.value.length > 0;
1019
+ }
1020
+ if (this.value != null) {
1021
+ return true;
1022
+ }
1023
+ return !!this.selectedName;
1024
+ }
1025
+ openFilePicker() {
1026
+ if (this.disabled) {
1027
+ return;
1028
+ }
1029
+ this.fileInput?.nativeElement.click();
1030
+ }
1031
+ onFileSelected(event) {
1032
+ const input = event.target;
1033
+ const files = input.files;
1034
+ if (!files || files.length === 0) {
1035
+ return;
1036
+ }
1037
+ const nextValue = this.multiple ? Array.from(files) : files[0];
1038
+ this.setValue(nextValue);
1039
+ input.value = '';
1040
+ }
1041
+ setValue(value) {
1042
+ this.value = value;
1043
+ this.onChange(value);
1044
+ this.onTouched();
1045
+ this.fileChange.emit(value);
1046
+ }
1047
+ writeValue(value) {
1048
+ this.value = value;
1049
+ }
1050
+ registerOnChange(fn) {
1051
+ this.onChange = fn;
1052
+ }
1053
+ registerOnTouched(fn) {
1054
+ this.onTouched = fn;
1055
+ }
1056
+ setDisabledState(isDisabled) {
1057
+ this.disabled = isDisabled;
1058
+ }
1059
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoFilePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1060
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoFilePickerComponent, isStandalone: true, selector: "geo-file-picker", inputs: { label: "label", placeholder: "placeholder", buttonText: "buttonText", required: "required", disabled: "disabled", accept: "accept", multiple: "multiple", error: "error", errorMessage: "errorMessage", block: "block", width: "width", selectedName: "selectedName" }, outputs: { fileChange: "fileChange" }, host: { properties: { "class.geo-file-picker-host--block": "block", "class.geo-file-picker-host--error": "error", "class.geo-file-picker-host--disabled": "disabled", "style.width": "hostWidth" }, classAttribute: "geo-file-picker-host" }, providers: [
1061
+ {
1062
+ provide: NG_VALUE_ACCESSOR,
1063
+ useExisting: forwardRef(() => GeoFilePickerComponent),
1064
+ multi: true,
1065
+ },
1066
+ ], viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "@if (label) {\n <div class=\"geo-file-picker__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-file-picker__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<div\n class=\"geo-file-picker__control\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n>\n <span\n class=\"geo-file-picker__value\"\n [class.geo-file-picker__value--placeholder]=\"!hasValue\"\n >\n {{ displayValue }}\n </span>\n\n <input\n #fileInput\n class=\"geo-file-picker__input\"\n type=\"file\"\n tabindex=\"-1\"\n [accept]=\"accept\"\n [multiple]=\"multiple\"\n [disabled]=\"disabled\"\n (change)=\"onFileSelected($event)\"\n />\n\n <geo-button\n class=\"geo-file-picker__button\"\n appearance=\"primary\"\n color=\"brand\"\n icon=\"plus\"\n [disabled]=\"disabled\"\n (clicked)=\"openFilePicker()\"\n >\n {{ buttonText }}\n </geo-button>\n</div>\n\n@if (error && errorMessage) {\n <p class=\"geo-file-picker__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: ["geo-file-picker.geo-file-picker-host,.geo-file-picker-host{display:inline-flex;flex-direction:column;gap:8px;width:413px;max-width:100%;vertical-align:top}geo-file-picker.geo-file-picker-host.geo-file-picker-host--block,.geo-file-picker-host.geo-file-picker-host--block{display:flex;width:100%;max-width:none}.geo-file-picker__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-file-picker__required{color:var(--geo-color-error-default)}.geo-file-picker__control{display:flex;align-items:center;gap:10px;min-height:40px;height:40px;padding:8px;border:1px solid var(--geo-color-neutral-300);border-radius:var(--geo-radius);background:var(--geo-color-neutral-white);transition:border-color .15s ease,box-shadow .15s ease}.geo-file-picker-host:not(.geo-file-picker-host--disabled) .geo-file-picker__control:hover{border-color:var(--geo-color-primary-default)}.geo-file-picker__value{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-file-picker__value--placeholder{color:var(--geo-color-neutral-500)}.geo-file-picker__input{display:none}.geo-file-picker__button .geo-button{height:32px;min-height:32px;padding:8px;flex-shrink:0}.geo-file-picker-host--disabled .geo-file-picker__control{background:var(--geo-color-neutral-100);border-color:var(--geo-color-neutral-300)}.geo-file-picker-host--disabled .geo-file-picker__value,.geo-file-picker-host--disabled .geo-file-picker__value--placeholder{color:var(--geo-color-neutral-disabled-text)}.geo-file-picker__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: GeoButtonComponent, selector: "geo-button", inputs: ["appearance", "color", "icon", "iconTheme", "iconPlacement", "iconOnly", "type", "disabled", "tooltip", "tooltipPlacement", "active", "title"], outputs: ["clicked"] }], encapsulation: i0.ViewEncapsulation.None });
1067
+ }
1068
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoFilePickerComponent, decorators: [{
1069
+ type: Component,
1070
+ args: [{ selector: 'geo-file-picker', standalone: true, imports: [CommonModule, GeoButtonComponent], encapsulation: ViewEncapsulation.None, host: {
1071
+ class: 'geo-file-picker-host',
1072
+ '[class.geo-file-picker-host--block]': 'block',
1073
+ '[class.geo-file-picker-host--error]': 'error',
1074
+ '[class.geo-file-picker-host--disabled]': 'disabled',
1075
+ '[style.width]': 'hostWidth',
1076
+ }, providers: [
1077
+ {
1078
+ provide: NG_VALUE_ACCESSOR,
1079
+ useExisting: forwardRef(() => GeoFilePickerComponent),
1080
+ multi: true,
1081
+ },
1082
+ ], template: "@if (label) {\n <div class=\"geo-file-picker__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-file-picker__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<div\n class=\"geo-file-picker__control\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n>\n <span\n class=\"geo-file-picker__value\"\n [class.geo-file-picker__value--placeholder]=\"!hasValue\"\n >\n {{ displayValue }}\n </span>\n\n <input\n #fileInput\n class=\"geo-file-picker__input\"\n type=\"file\"\n tabindex=\"-1\"\n [accept]=\"accept\"\n [multiple]=\"multiple\"\n [disabled]=\"disabled\"\n (change)=\"onFileSelected($event)\"\n />\n\n <geo-button\n class=\"geo-file-picker__button\"\n appearance=\"primary\"\n color=\"brand\"\n icon=\"plus\"\n [disabled]=\"disabled\"\n (clicked)=\"openFilePicker()\"\n >\n {{ buttonText }}\n </geo-button>\n</div>\n\n@if (error && errorMessage) {\n <p class=\"geo-file-picker__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: ["geo-file-picker.geo-file-picker-host,.geo-file-picker-host{display:inline-flex;flex-direction:column;gap:8px;width:413px;max-width:100%;vertical-align:top}geo-file-picker.geo-file-picker-host.geo-file-picker-host--block,.geo-file-picker-host.geo-file-picker-host--block{display:flex;width:100%;max-width:none}.geo-file-picker__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-file-picker__required{color:var(--geo-color-error-default)}.geo-file-picker__control{display:flex;align-items:center;gap:10px;min-height:40px;height:40px;padding:8px;border:1px solid var(--geo-color-neutral-300);border-radius:var(--geo-radius);background:var(--geo-color-neutral-white);transition:border-color .15s ease,box-shadow .15s ease}.geo-file-picker-host:not(.geo-file-picker-host--disabled) .geo-file-picker__control:hover{border-color:var(--geo-color-primary-default)}.geo-file-picker__value{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-file-picker__value--placeholder{color:var(--geo-color-neutral-500)}.geo-file-picker__input{display:none}.geo-file-picker__button .geo-button{height:32px;min-height:32px;padding:8px;flex-shrink:0}.geo-file-picker-host--disabled .geo-file-picker__control{background:var(--geo-color-neutral-100);border-color:var(--geo-color-neutral-300)}.geo-file-picker-host--disabled .geo-file-picker__value,.geo-file-picker-host--disabled .geo-file-picker__value--placeholder{color:var(--geo-color-neutral-disabled-text)}.geo-file-picker__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}\n"] }]
1083
+ }], propDecorators: { fileInput: [{
1084
+ type: ViewChild,
1085
+ args: ['fileInput']
1086
+ }], label: [{
1087
+ type: Input
1088
+ }], placeholder: [{
1089
+ type: Input
1090
+ }], buttonText: [{
1091
+ type: Input
1092
+ }], required: [{
1093
+ type: Input
1094
+ }], disabled: [{
1095
+ type: Input
1096
+ }], accept: [{
1097
+ type: Input
1098
+ }], multiple: [{
1099
+ type: Input
1100
+ }], error: [{
1101
+ type: Input
1102
+ }], errorMessage: [{
1103
+ type: Input
1104
+ }], block: [{
1105
+ type: Input
1106
+ }], width: [{
1107
+ type: Input
1108
+ }], selectedName: [{
1109
+ type: Input
1110
+ }], fileChange: [{
1111
+ type: Output
1112
+ }] } });
1113
+
1114
+ function geoFormatBytes(bytes) {
1115
+ if (bytes == null || Number.isNaN(bytes)) {
1116
+ return '0Kb';
1117
+ }
1118
+ const kb = bytes / 1024;
1119
+ if (kb < 1024) {
1120
+ return `${Math.round(kb)}Kb`;
1121
+ }
1122
+ return `${(kb / 1024).toFixed(kb >= 10240 ? 0 : 1)}Mb`;
1123
+ }
1124
+ function geoFormatSpeed(bytesPerSec) {
1125
+ if (bytesPerSec == null || bytesPerSec <= 0) {
1126
+ return '';
1127
+ }
1128
+ const kb = bytesPerSec / 1024;
1129
+ if (kb < 1024) {
1130
+ return `${Math.round(kb)}kb/sec`;
1131
+ }
1132
+ return `${(kb / 1024).toFixed(1)}Mb/sec`;
1133
+ }
1134
+ function geoUploadPercent(file) {
1135
+ if (file.percent != null) {
1136
+ return Math.max(0, Math.min(100, Math.round(file.percent)));
1137
+ }
1138
+ if (file.status === 'done' || file.status === 'success') {
1139
+ return 100;
1140
+ }
1141
+ return 0;
1142
+ }
1143
+
1144
+ /**
1145
+ * Upload kéo-thả theo design GEO (dropzone + danh sách file có progress).
1146
+ * Dựa trên `nz-upload` (Ant Design). Form field gọn dùng `geo-file-picker`.
1147
+ */
1148
+ class GeoUploadComponent {
1149
+ cdr = inject(ChangeDetectorRef);
1150
+ /** Upload endpoint — bỏ trống nếu dùng `customRequest` / chỉ chọn file local. */
1151
+ action = '';
1152
+ accept = '.png,.jpg,.jpeg,.svg';
1153
+ /** Max size (bytes). Default 1MB. `0` = không giới hạn. */
1154
+ maxSize = 1024 * 1024;
1155
+ multiple = true;
1156
+ disabled = false;
1157
+ error = false;
1158
+ errorMessage = '';
1159
+ hint = 'Chỉ cho phép file dạng .png, .jpg, .jpeg, .svg và dung lượng không quá 1Mb';
1160
+ titlePrefix = 'Kéo thả ảnh hoặc';
1161
+ selectText = 'Chọn file';
1162
+ titleSuffix = 'để tải lên';
1163
+ listTitle = 'Tập tin đính kèm';
1164
+ showListTitle = true;
1165
+ /** Controlled file list. */
1166
+ fileList = [];
1167
+ headers;
1168
+ data;
1169
+ name = 'file';
1170
+ withCredentials = false;
1171
+ directory = false;
1172
+ /** Custom XHR — mặc định simulate progress khi không có `action`. */
1173
+ customRequest;
1174
+ beforeUpload;
1175
+ fileListChange = new EventEmitter();
1176
+ change = new EventEmitter();
1177
+ remove = new EventEmitter();
1178
+ reject = new EventEmitter();
1179
+ formatBytes = geoFormatBytes;
1180
+ formatSpeed = geoFormatSpeed;
1181
+ percentOf = geoUploadPercent;
1182
+ get resolvedCustomRequest() {
1183
+ if (this.customRequest) {
1184
+ return this.customRequest;
1185
+ }
1186
+ if (!this.action) {
1187
+ return (item) => this.simulateUpload(item);
1188
+ }
1189
+ return undefined;
1190
+ }
1191
+ onFileListChange(list) {
1192
+ this.fileList = list;
1193
+ this.fileListChange.emit(this.fileList);
1194
+ }
1195
+ onChange(event) {
1196
+ this.fileList = event.fileList;
1197
+ this.fileListChange.emit(this.fileList);
1198
+ this.change.emit(event);
1199
+ }
1200
+ handleBeforeUpload = (file, _fileList) => {
1201
+ if (this.beforeUpload) {
1202
+ return this.beforeUpload(file, _fileList);
1203
+ }
1204
+ const raw = file;
1205
+ const name = (file.name || raw.name || '').toLowerCase();
1206
+ if (this.accept) {
1207
+ const tokens = this.accept
1208
+ .split(',')
1209
+ .map((t) => t.trim().toLowerCase())
1210
+ .filter(Boolean);
1211
+ const ok = tokens.some((token) => {
1212
+ if (token.startsWith('.')) {
1213
+ return name.endsWith(token);
1214
+ }
1215
+ if (token.includes('/*')) {
1216
+ const prefix = token.replace('/*', '');
1217
+ return (file.type || raw.type || '').startsWith(prefix);
1218
+ }
1219
+ return (file.type || raw.type || '') === token;
1220
+ });
1221
+ if (!ok) {
1222
+ this.reject.emit({ file: raw, reason: 'type' });
1223
+ return false;
1224
+ }
1225
+ }
1226
+ const size = file.size ?? raw.size ?? 0;
1227
+ if (this.maxSize > 0 && size > this.maxSize) {
1228
+ this.reject.emit({ file: raw, reason: 'size' });
1229
+ return false;
1230
+ }
1231
+ return true;
1232
+ };
1233
+ onRemove = (file) => {
1234
+ this.remove.emit(file);
1235
+ return true;
1236
+ };
1237
+ removeFile(file, event) {
1238
+ event.preventDefault();
1239
+ event.stopPropagation();
1240
+ if (this.disabled) {
1241
+ return;
1242
+ }
1243
+ if (this.onRemove(file) === false) {
1244
+ return;
1245
+ }
1246
+ this.fileList = this.fileList.filter((item) => item.uid !== file.uid);
1247
+ this.fileListChange.emit(this.fileList);
1248
+ }
1249
+ progressLabel(file) {
1250
+ const total = file.size ?? file.originFileObj?.size ?? 0;
1251
+ const percent = this.percentOf(file);
1252
+ const loaded = file.loaded != null
1253
+ ? file.loaded
1254
+ : Math.round((percent / 100) * total);
1255
+ return `${this.formatBytes(loaded)}/ ${this.formatBytes(total)} (${percent}%)`;
1256
+ }
1257
+ speedLabel(file) {
1258
+ return this.formatSpeed(file.speed);
1259
+ }
1260
+ /** Demo / local upload khi không có action. */
1261
+ simulateUpload(item) {
1262
+ const file = item.file;
1263
+ const total = file.size ?? file.originFileObj?.size ?? 0;
1264
+ let loaded = 0;
1265
+ const started = Date.now();
1266
+ file.status = 'uploading';
1267
+ file.percent = 0;
1268
+ file.loaded = 0;
1269
+ file.speed = 0;
1270
+ const timer = window.setInterval(() => {
1271
+ const step = Math.max(total * 0.08, 16 * 1024);
1272
+ loaded = Math.min(total, loaded + step);
1273
+ const elapsedSec = Math.max((Date.now() - started) / 1000, 0.001);
1274
+ const percent = total > 0 ? Math.round((loaded / total) * 100) : 100;
1275
+ file.loaded = loaded;
1276
+ file.percent = percent;
1277
+ file.speed = loaded / elapsedSec;
1278
+ item.onProgress?.({ percent }, file);
1279
+ this.cdr.markForCheck();
1280
+ if (loaded >= total) {
1281
+ window.clearInterval(timer);
1282
+ file.status = 'done';
1283
+ file.percent = 100;
1284
+ file.loaded = total;
1285
+ item.onSuccess?.({}, file, null);
1286
+ this.cdr.markForCheck();
1287
+ }
1288
+ }, 200);
1289
+ return new Subscription(() => window.clearInterval(timer));
1290
+ }
1291
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1292
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoUploadComponent, isStandalone: true, selector: "geo-upload", inputs: { action: "action", accept: "accept", maxSize: "maxSize", multiple: "multiple", disabled: "disabled", error: "error", errorMessage: "errorMessage", hint: "hint", titlePrefix: "titlePrefix", selectText: "selectText", titleSuffix: "titleSuffix", listTitle: "listTitle", showListTitle: "showListTitle", fileList: "fileList", headers: "headers", data: "data", name: "name", withCredentials: "withCredentials", directory: "directory", customRequest: "customRequest", beforeUpload: "beforeUpload" }, outputs: { fileListChange: "fileListChange", change: "change", remove: "remove", reject: "reject" }, host: { properties: { "class.geo-upload-host--disabled": "disabled", "class.geo-upload-host--error": "error" }, classAttribute: "geo-upload-host" }, ngImport: i0, template: "<div class=\"geo-upload\">\n <nz-upload\n class=\"geo-upload__dragger\"\n nzType=\"drag\"\n [nzAction]=\"action\"\n [nzAccept]=\"accept\"\n [nzMultiple]=\"multiple\"\n [nzDisabled]=\"disabled\"\n [nzDirectory]=\"directory\"\n [nzName]=\"name\"\n [nzHeaders]=\"headers\"\n [nzData]=\"data\"\n [nzWithCredentials]=\"withCredentials\"\n [nzFileList]=\"fileList\"\n [nzShowUploadList]=\"false\"\n [nzBeforeUpload]=\"handleBeforeUpload\"\n [nzCustomRequest]=\"resolvedCustomRequest\"\n [nzRemove]=\"onRemove\"\n (nzFileListChange)=\"onFileListChange($event)\"\n (nzChange)=\"onChange($event)\"\n >\n <div class=\"geo-upload__dropzone\">\n <span class=\"geo-upload__icon-wrap\" aria-hidden=\"true\">\n <span class=\"geo-upload__icon\" nz-icon nzType=\"cloud-upload\" nzTheme=\"outline\"></span>\n </span>\n\n <div class=\"geo-upload__copy\">\n <p class=\"geo-upload__title\">\n <span>{{ titlePrefix }} </span>\n <span class=\"geo-upload__select\">{{ selectText }}</span>\n <span> {{ titleSuffix }}</span>\n </p>\n\n @if (hint) {\n <p class=\"geo-upload__hint\">{{ hint }}</p>\n }\n </div>\n </div>\n </nz-upload>\n\n @if (fileList.length > 0) {\n <div class=\"geo-upload__list\">\n @if (showListTitle) {\n <h4 class=\"geo-upload__list-title\">{{ listTitle }}</h4>\n }\n\n <ul class=\"geo-upload__files\">\n @for (file of fileList; track file.uid) {\n <li class=\"geo-upload__file\" [class.geo-upload__file--error]=\"file.status === 'error'\">\n <div class=\"geo-upload__file-icon\" aria-hidden=\"true\">\n <span nz-icon nzType=\"file\" nzTheme=\"outline\"></span>\n </div>\n\n <div class=\"geo-upload__file-main\">\n <div class=\"geo-upload__file-row\">\n <span class=\"geo-upload__file-name\" [title]=\"file.name\">{{ file.name }}</span>\n <button\n type=\"button\"\n class=\"geo-upload__file-remove\"\n aria-label=\"X\u00F3a t\u1EADp tin\"\n [disabled]=\"disabled\"\n (click)=\"removeFile(file, $event)\"\n >\n <span nz-icon nzType=\"close\" nzTheme=\"outline\"></span>\n </button>\n </div>\n\n <div class=\"geo-upload__progress\" role=\"progressbar\" [attr.aria-valuenow]=\"percentOf(file)\" aria-valuemin=\"0\" aria-valuemax=\"100\">\n <div class=\"geo-upload__progress-bar\" [style.width.%]=\"percentOf(file)\"></div>\n </div>\n\n <div class=\"geo-upload__file-meta\">\n <span>{{ progressLabel(file) }}</span>\n <span>{{ speedLabel(file) }}</span>\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n\n @if (error && errorMessage) {\n <p class=\"geo-upload__error\" role=\"alert\">{{ errorMessage }}</p>\n }\n</div>\n", styles: ["@charset \"UTF-8\";geo-upload.geo-upload-host,.geo-upload-host{display:block;width:100%;font-family:var(--geo-font-family);color:var(--geo-color-neutral-900)}.geo-upload{display:flex;flex-direction:column;gap:20px}.geo-upload__dragger{display:block;width:100%}.geo-upload__dragger .ant-upload.ant-upload-drag{display:block;width:100%;background:var(--geo-color-neutral-100)!important;border:1.5px dashed var(--geo-color-neutral-300)!important;border-radius:var(--geo-radius);text-align:left;cursor:pointer;transition:border-color .15s ease,background-color .15s ease}.geo-upload__dragger .ant-upload.ant-upload-drag .ant-upload-btn{display:block;padding:0;background:transparent}.geo-upload__dragger .ant-upload.ant-upload-drag .ant-upload-drag-icon,.geo-upload__dragger .ant-upload.ant-upload-drag .ant-upload-text,.geo-upload__dragger .ant-upload.ant-upload-drag .ant-upload-hint{display:none}.geo-upload__dragger .ant-upload.ant-upload-drag:not(.ant-upload-disabled):hover,.geo-upload__dragger .ant-upload.ant-upload-drag.ant-upload-drag-hover:not(.ant-upload-disabled){border-color:var(--geo-color-primary-default)!important;background:var(--geo-color-primary-surface-light)!important}.geo-upload__dragger .ant-upload.ant-upload-drag.ant-upload-disabled{cursor:not-allowed;opacity:.65}.geo-upload__dropzone{display:flex;flex-direction:row;align-items:center;justify-content:center;gap:16px;padding:20px 24px;box-sizing:border-box}.geo-upload__icon-wrap{display:inline-flex;align-items:center;justify-content:center;width:48px;height:48px;border-radius:50%;background:var(--geo-color-primary-default);color:var(--geo-color-neutral-white);flex-shrink:0}.geo-upload__icon{font-size:24px;line-height:1;color:var(--geo-color-neutral-white)}.geo-upload__copy{display:flex;flex-direction:column;align-items:flex-start;gap:4px;min-width:0;text-align:left}.geo-upload__title{margin:0;font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-body);color:var(--geo-color-neutral-900)}.geo-upload__select{font-weight:var(--geo-font-weight-semibold);color:var(--geo-color-primary-default)}.geo-upload__hint{margin:0;max-width:420px;font-size:var(--geo-font-size-caption);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-caption);color:var(--geo-color-neutral-500)}.geo-upload__list{display:flex;flex-direction:column;gap:12px}.geo-upload__list-title{margin:0;font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-semibold);line-height:var(--geo-line-height-body);color:var(--geo-color-neutral-900)}.geo-upload__files{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:16px}.geo-upload__file{display:flex;align-items:flex-start;gap:12px}.geo-upload__file-icon{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;flex-shrink:0;border-radius:var(--geo-radius);background:var(--geo-color-neutral-100);color:var(--geo-color-neutral-500);font-size:18px}.geo-upload__file-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:6px}.geo-upload__file-row{display:flex;align-items:center;gap:8px}.geo-upload__file-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-semibold);line-height:var(--geo-line-height-body);color:var(--geo-color-neutral-900)}.geo-upload__file-remove{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;background:transparent;color:var(--geo-color-neutral-500);cursor:pointer;flex-shrink:0;font-size:12px}.geo-upload__file-remove:hover:not(:disabled){color:var(--geo-color-error-default)}.geo-upload__file-remove:disabled{cursor:not-allowed;opacity:.5}.geo-upload__progress{width:100%;height:6px;border-radius:999px;background:var(--geo-color-neutral-200);overflow:hidden}.geo-upload__progress-bar{height:100%;border-radius:inherit;background:var(--geo-color-primary-default);transition:width .2s ease}.geo-upload__file-meta{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:var(--geo-font-size-caption);line-height:var(--geo-line-height-caption);color:var(--geo-color-neutral-500)}.geo-upload__file--error .geo-upload__file-name{color:var(--geo-color-error-default)}.geo-upload__file--error .geo-upload__progress-bar{background:var(--geo-color-error-default)}.geo-upload__error{margin:0;font-size:var(--geo-font-size-body-small);line-height:var(--geo-line-height-body-small);color:var(--geo-color-error-default)}.geo-upload-host--disabled .geo-upload__select{color:var(--geo-color-neutral-disabled-text)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzUploadModule }, { kind: "component", type: i2$1.NzUploadComponent, selector: "nz-upload", inputs: ["nzType", "nzLimit", "nzSize", "nzFileType", "nzAccept", "nzAction", "nzDirectory", "nzOpenFileDialogOnClick", "nzBeforeUpload", "nzCustomRequest", "nzData", "nzFilter", "nzFileList", "nzDisabled", "nzHeaders", "nzListType", "nzMultiple", "nzName", "nzShowUploadList", "nzShowButton", "nzWithCredentials", "nzRemove", "nzPreview", "nzPreviewFile", "nzPreviewIsImage", "nzTransformFile", "nzDownload", "nzIconRender", "nzFileListRender"], outputs: ["nzChange", "nzFileListChange"], exportAs: ["nzUpload"] }], encapsulation: i0.ViewEncapsulation.None });
1293
+ }
1294
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoUploadComponent, decorators: [{
1295
+ type: Component,
1296
+ args: [{ selector: 'geo-upload', standalone: true, imports: [CommonModule, NzIconModule, NzUploadModule], encapsulation: ViewEncapsulation.None, host: {
1297
+ class: 'geo-upload-host',
1298
+ '[class.geo-upload-host--disabled]': 'disabled',
1299
+ '[class.geo-upload-host--error]': 'error',
1300
+ }, template: "<div class=\"geo-upload\">\n <nz-upload\n class=\"geo-upload__dragger\"\n nzType=\"drag\"\n [nzAction]=\"action\"\n [nzAccept]=\"accept\"\n [nzMultiple]=\"multiple\"\n [nzDisabled]=\"disabled\"\n [nzDirectory]=\"directory\"\n [nzName]=\"name\"\n [nzHeaders]=\"headers\"\n [nzData]=\"data\"\n [nzWithCredentials]=\"withCredentials\"\n [nzFileList]=\"fileList\"\n [nzShowUploadList]=\"false\"\n [nzBeforeUpload]=\"handleBeforeUpload\"\n [nzCustomRequest]=\"resolvedCustomRequest\"\n [nzRemove]=\"onRemove\"\n (nzFileListChange)=\"onFileListChange($event)\"\n (nzChange)=\"onChange($event)\"\n >\n <div class=\"geo-upload__dropzone\">\n <span class=\"geo-upload__icon-wrap\" aria-hidden=\"true\">\n <span class=\"geo-upload__icon\" nz-icon nzType=\"cloud-upload\" nzTheme=\"outline\"></span>\n </span>\n\n <div class=\"geo-upload__copy\">\n <p class=\"geo-upload__title\">\n <span>{{ titlePrefix }} </span>\n <span class=\"geo-upload__select\">{{ selectText }}</span>\n <span> {{ titleSuffix }}</span>\n </p>\n\n @if (hint) {\n <p class=\"geo-upload__hint\">{{ hint }}</p>\n }\n </div>\n </div>\n </nz-upload>\n\n @if (fileList.length > 0) {\n <div class=\"geo-upload__list\">\n @if (showListTitle) {\n <h4 class=\"geo-upload__list-title\">{{ listTitle }}</h4>\n }\n\n <ul class=\"geo-upload__files\">\n @for (file of fileList; track file.uid) {\n <li class=\"geo-upload__file\" [class.geo-upload__file--error]=\"file.status === 'error'\">\n <div class=\"geo-upload__file-icon\" aria-hidden=\"true\">\n <span nz-icon nzType=\"file\" nzTheme=\"outline\"></span>\n </div>\n\n <div class=\"geo-upload__file-main\">\n <div class=\"geo-upload__file-row\">\n <span class=\"geo-upload__file-name\" [title]=\"file.name\">{{ file.name }}</span>\n <button\n type=\"button\"\n class=\"geo-upload__file-remove\"\n aria-label=\"X\u00F3a t\u1EADp tin\"\n [disabled]=\"disabled\"\n (click)=\"removeFile(file, $event)\"\n >\n <span nz-icon nzType=\"close\" nzTheme=\"outline\"></span>\n </button>\n </div>\n\n <div class=\"geo-upload__progress\" role=\"progressbar\" [attr.aria-valuenow]=\"percentOf(file)\" aria-valuemin=\"0\" aria-valuemax=\"100\">\n <div class=\"geo-upload__progress-bar\" [style.width.%]=\"percentOf(file)\"></div>\n </div>\n\n <div class=\"geo-upload__file-meta\">\n <span>{{ progressLabel(file) }}</span>\n <span>{{ speedLabel(file) }}</span>\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n\n @if (error && errorMessage) {\n <p class=\"geo-upload__error\" role=\"alert\">{{ errorMessage }}</p>\n }\n</div>\n", styles: ["@charset \"UTF-8\";geo-upload.geo-upload-host,.geo-upload-host{display:block;width:100%;font-family:var(--geo-font-family);color:var(--geo-color-neutral-900)}.geo-upload{display:flex;flex-direction:column;gap:20px}.geo-upload__dragger{display:block;width:100%}.geo-upload__dragger .ant-upload.ant-upload-drag{display:block;width:100%;background:var(--geo-color-neutral-100)!important;border:1.5px dashed var(--geo-color-neutral-300)!important;border-radius:var(--geo-radius);text-align:left;cursor:pointer;transition:border-color .15s ease,background-color .15s ease}.geo-upload__dragger .ant-upload.ant-upload-drag .ant-upload-btn{display:block;padding:0;background:transparent}.geo-upload__dragger .ant-upload.ant-upload-drag .ant-upload-drag-icon,.geo-upload__dragger .ant-upload.ant-upload-drag .ant-upload-text,.geo-upload__dragger .ant-upload.ant-upload-drag .ant-upload-hint{display:none}.geo-upload__dragger .ant-upload.ant-upload-drag:not(.ant-upload-disabled):hover,.geo-upload__dragger .ant-upload.ant-upload-drag.ant-upload-drag-hover:not(.ant-upload-disabled){border-color:var(--geo-color-primary-default)!important;background:var(--geo-color-primary-surface-light)!important}.geo-upload__dragger .ant-upload.ant-upload-drag.ant-upload-disabled{cursor:not-allowed;opacity:.65}.geo-upload__dropzone{display:flex;flex-direction:row;align-items:center;justify-content:center;gap:16px;padding:20px 24px;box-sizing:border-box}.geo-upload__icon-wrap{display:inline-flex;align-items:center;justify-content:center;width:48px;height:48px;border-radius:50%;background:var(--geo-color-primary-default);color:var(--geo-color-neutral-white);flex-shrink:0}.geo-upload__icon{font-size:24px;line-height:1;color:var(--geo-color-neutral-white)}.geo-upload__copy{display:flex;flex-direction:column;align-items:flex-start;gap:4px;min-width:0;text-align:left}.geo-upload__title{margin:0;font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-body);color:var(--geo-color-neutral-900)}.geo-upload__select{font-weight:var(--geo-font-weight-semibold);color:var(--geo-color-primary-default)}.geo-upload__hint{margin:0;max-width:420px;font-size:var(--geo-font-size-caption);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-caption);color:var(--geo-color-neutral-500)}.geo-upload__list{display:flex;flex-direction:column;gap:12px}.geo-upload__list-title{margin:0;font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-semibold);line-height:var(--geo-line-height-body);color:var(--geo-color-neutral-900)}.geo-upload__files{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:16px}.geo-upload__file{display:flex;align-items:flex-start;gap:12px}.geo-upload__file-icon{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;flex-shrink:0;border-radius:var(--geo-radius);background:var(--geo-color-neutral-100);color:var(--geo-color-neutral-500);font-size:18px}.geo-upload__file-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:6px}.geo-upload__file-row{display:flex;align-items:center;gap:8px}.geo-upload__file-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-semibold);line-height:var(--geo-line-height-body);color:var(--geo-color-neutral-900)}.geo-upload__file-remove{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;background:transparent;color:var(--geo-color-neutral-500);cursor:pointer;flex-shrink:0;font-size:12px}.geo-upload__file-remove:hover:not(:disabled){color:var(--geo-color-error-default)}.geo-upload__file-remove:disabled{cursor:not-allowed;opacity:.5}.geo-upload__progress{width:100%;height:6px;border-radius:999px;background:var(--geo-color-neutral-200);overflow:hidden}.geo-upload__progress-bar{height:100%;border-radius:inherit;background:var(--geo-color-primary-default);transition:width .2s ease}.geo-upload__file-meta{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:var(--geo-font-size-caption);line-height:var(--geo-line-height-caption);color:var(--geo-color-neutral-500)}.geo-upload__file--error .geo-upload__file-name{color:var(--geo-color-error-default)}.geo-upload__file--error .geo-upload__progress-bar{background:var(--geo-color-error-default)}.geo-upload__error{margin:0;font-size:var(--geo-font-size-body-small);line-height:var(--geo-line-height-body-small);color:var(--geo-color-error-default)}.geo-upload-host--disabled .geo-upload__select{color:var(--geo-color-neutral-disabled-text)}\n"] }]
1301
+ }], propDecorators: { action: [{
1302
+ type: Input
1303
+ }], accept: [{
1304
+ type: Input
1305
+ }], maxSize: [{
1306
+ type: Input
1307
+ }], multiple: [{
1308
+ type: Input
1309
+ }], disabled: [{
1310
+ type: Input
1311
+ }], error: [{
1312
+ type: Input
1313
+ }], errorMessage: [{
1314
+ type: Input
1315
+ }], hint: [{
1316
+ type: Input
1317
+ }], titlePrefix: [{
1318
+ type: Input
1319
+ }], selectText: [{
1320
+ type: Input
1321
+ }], titleSuffix: [{
1322
+ type: Input
1323
+ }], listTitle: [{
1324
+ type: Input
1325
+ }], showListTitle: [{
1326
+ type: Input
1327
+ }], fileList: [{
1328
+ type: Input
1329
+ }], headers: [{
1330
+ type: Input
1331
+ }], data: [{
1332
+ type: Input
1333
+ }], name: [{
1334
+ type: Input
1335
+ }], withCredentials: [{
1336
+ type: Input
1337
+ }], directory: [{
1338
+ type: Input
1339
+ }], customRequest: [{
1340
+ type: Input
1341
+ }], beforeUpload: [{
1342
+ type: Input
1343
+ }], fileListChange: [{
1344
+ type: Output
1345
+ }], change: [{
1346
+ type: Output
1347
+ }], remove: [{
1348
+ type: Output
1349
+ }], reject: [{
1350
+ type: Output
1351
+ }] } });
1352
+
1353
+ /**
1354
+ * Modal form dùng chung — API bám Ant Design Modal / ng-zorro nz-modal.
1355
+ * Header + footer cố định; body có thể scroll (`bodyScroll`).
1356
+ */
1357
+ class GeoFormModalComponent {
1358
+ /** Tương đương `open` (antd) / `nzVisible` (ng-zorro). */
1359
+ open = false;
1360
+ title = '';
1361
+ /** Title chữ in hoa. Default `true` theo design. */
1362
+ titleUppercase = true;
1363
+ okText = 'Lưu';
1364
+ cancelText = 'Hủy';
1365
+ /** Icon nút cancel (vd. `left` cho Quay lại). */
1366
+ cancelIcon;
1367
+ cancelIconPlacement = 'start';
1368
+ /** Icon nút OK (vd. `right` cho Tiếp theo). */
1369
+ okIcon;
1370
+ okIconPlacement = 'end';
1371
+ /** Nút phụ (vd. Lưu và khởi tạo lại). Chỉ hiện khi có text và không readonly. */
1372
+ secondaryOkText = '';
1373
+ /** Loading trên nút OK — giống antd `confirmLoading` / nz `nzOkLoading`. */
1374
+ confirmLoading = false;
1375
+ /** Disable nút OK — giống antd `okButtonProps.disabled` / nz `nzOkDisabled`. */
1376
+ okDisabled = false;
1377
+ /** Ẩn nút OK (xem chi tiết). */
1378
+ readonly = false;
1379
+ width = 720;
1380
+ closable = true;
1381
+ mask = true;
1382
+ maskClosable = false;
1383
+ keyboard = true;
1384
+ centered = true;
1385
+ zIndex = 1000;
1386
+ className = '';
1387
+ wrapClassName = '';
1388
+ /** Body cuộn, header/footer cố định. */
1389
+ bodyScroll = true;
1390
+ /** Max-height của vùng body khi `bodyScroll` (vd `'60vh'`, `400`). */
1391
+ bodyMaxHeight = '60vh';
1392
+ openChange = new EventEmitter();
1393
+ ok = new EventEmitter();
1394
+ secondaryOk = new EventEmitter();
1395
+ cancel = new EventEmitter();
1396
+ afterOpen = new EventEmitter();
1397
+ afterClose = new EventEmitter();
1398
+ get resolvedWrapClassName() {
1399
+ return ['geo-form-modal-wrap', this.wrapClassName].filter(Boolean).join(' ');
1400
+ }
1401
+ get resolvedClassName() {
1402
+ return ['geo-form-modal', this.className].filter(Boolean).join(' ');
1403
+ }
1404
+ get bodyMaxHeightCss() {
1405
+ return typeof this.bodyMaxHeight === 'number'
1406
+ ? `${this.bodyMaxHeight}px`
1407
+ : this.bodyMaxHeight;
1408
+ }
1409
+ onOpenChange(open) {
1410
+ if (this.open === open) {
1411
+ return;
1412
+ }
1413
+ this.openChange.emit(open);
1414
+ }
1415
+ onCancel() {
1416
+ this.openChange.emit(false);
1417
+ this.cancel.emit();
1418
+ }
1419
+ onOk() {
1420
+ if (!this.okDisabled && !this.confirmLoading) {
1421
+ this.ok.emit();
1422
+ }
1423
+ }
1424
+ onSecondaryOk() {
1425
+ if (!this.okDisabled && !this.confirmLoading) {
1426
+ this.secondaryOk.emit();
1427
+ }
1428
+ }
1429
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoFormModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1430
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoFormModalComponent, isStandalone: true, selector: "geo-form-modal", inputs: { open: "open", title: "title", titleUppercase: "titleUppercase", okText: "okText", cancelText: "cancelText", cancelIcon: "cancelIcon", cancelIconPlacement: "cancelIconPlacement", okIcon: "okIcon", okIconPlacement: "okIconPlacement", secondaryOkText: "secondaryOkText", confirmLoading: "confirmLoading", okDisabled: "okDisabled", readonly: "readonly", width: "width", closable: "closable", mask: "mask", maskClosable: "maskClosable", keyboard: "keyboard", centered: "centered", zIndex: "zIndex", className: "className", wrapClassName: "wrapClassName", bodyScroll: "bodyScroll", bodyMaxHeight: "bodyMaxHeight" }, outputs: { openChange: "openChange", ok: "ok", secondaryOk: "secondaryOk", cancel: "cancel", afterOpen: "afterOpen", afterClose: "afterClose" }, ngImport: i0, template: "<nz-modal\n [nzVisible]=\"open\"\n [nzTitle]=\"''\"\n [nzFooter]=\"null\"\n [nzClosable]=\"false\"\n [nzMask]=\"mask\"\n [nzMaskClosable]=\"maskClosable\"\n [nzKeyboard]=\"keyboard\"\n [nzCentered]=\"centered\"\n [nzWidth]=\"width\"\n [nzZIndex]=\"zIndex\"\n [nzWrapClassName]=\"resolvedWrapClassName\"\n [nzClassName]=\"resolvedClassName\"\n (nzVisibleChange)=\"onOpenChange($event)\"\n (nzAfterOpen)=\"afterOpen.emit()\"\n (nzAfterClose)=\"afterClose.emit()\"\n>\n <ng-container *nzModalContent>\n <div\n class=\"geo-form-modal__content\"\n [class.geo-form-modal__content--body-scroll]=\"bodyScroll\"\n >\n <div class=\"geo-form-modal__header\">\n <h2\n class=\"geo-form-modal__title\"\n [class.geo-form-modal__title--uppercase]=\"titleUppercase\"\n >\n {{ title }}\n </h2>\n @if (closable) {\n <button\n type=\"button\"\n class=\"geo-form-modal__close\"\n aria-label=\"\u0110\u00F3ng\"\n (click)=\"onCancel()\"\n >\n <span nz-icon nzType=\"close\" nzTheme=\"outline\"></span>\n </button>\n }\n </div>\n\n <div\n class=\"geo-form-modal__body\"\n [style.--geo-form-modal-body-max-height]=\"bodyScroll ? bodyMaxHeightCss : null\"\n >\n <ng-content></ng-content>\n </div>\n\n <div class=\"geo-form-modal__footer\">\n <ng-content select=\"[footerStart]\"></ng-content>\n\n <div class=\"geo-form-modal__footer-actions\">\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n [icon]=\"cancelIcon\"\n [iconPlacement]=\"cancelIconPlacement\"\n (clicked)=\"onCancel()\"\n >\n {{ readonly ? '\u0110\u00F3ng' : cancelText }}\n </geo-button>\n @if (!readonly && secondaryOkText) {\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"save\"\n [disabled]=\"okDisabled || confirmLoading\"\n (clicked)=\"onSecondaryOk()\"\n >\n {{ secondaryOkText }}\n </geo-button>\n }\n @if (!readonly) {\n <geo-button\n appearance=\"primary\"\n color=\"brand\"\n [icon]=\"confirmLoading ? 'loading' : okIcon\"\n [iconPlacement]=\"okIconPlacement\"\n [disabled]=\"okDisabled || confirmLoading\"\n (clicked)=\"onOk()\"\n >\n {{ okText }}\n </geo-button>\n }\n </div>\n </div>\n </div>\n </ng-container>\n</nz-modal>\n", styles: [".geo-form-modal-wrap .ant-modal-header{display:none}.geo-form-modal-wrap .ant-modal{max-width:calc(100vw - 32px)}.geo-form-modal-wrap .ant-modal-content{border-radius:var(--geo-radius);padding:0;overflow:hidden;box-shadow:0 8px 24px #1118271f}.geo-form-modal-wrap .ant-modal-body{padding:0}.geo-form-modal__content{display:flex;flex-direction:column;background:var(--geo-color-neutral-white);max-height:inherit}.geo-form-modal__header{position:relative;display:flex;align-items:center;justify-content:space-between;gap:16px;flex-shrink:0;padding:24px 24px 16px;border-bottom:none}.geo-form-modal__header:after{content:\"\";position:absolute;left:24px;right:24px;bottom:0;height:1px;background:var(--geo-color-primary-default);pointer-events:none}.geo-form-modal__title{margin:0;min-width:0;font-family:var(--geo-font-family);font-size:var(--geo-font-size-h4);font-weight:var(--geo-font-weight-bold);line-height:var(--geo-line-height-h4);color:var(--geo-color-neutral-900);letter-spacing:.02em;word-break:break-word}.geo-form-modal__title--uppercase{text-transform:uppercase}.geo-form-modal__close{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;border-radius:var(--geo-radius);background:transparent;color:var(--geo-color-neutral-500);cursor:pointer;flex-shrink:0;transition:color .15s ease,background-color .15s ease}.geo-form-modal__close .anticon{font-size:14px}.geo-form-modal__close:hover{color:var(--geo-color-neutral-900);background:var(--geo-color-neutral-100)}.geo-form-modal__body{display:flex;flex-direction:column;gap:20px;flex:1 1 auto;min-width:0;min-height:0;padding:24px}.geo-form-modal__content--body-scroll .geo-form-modal__body{overflow-x:hidden;overflow-y:auto;max-height:var(--geo-form-modal-body-max-height, 60vh);-webkit-overflow-scrolling:touch}.geo-form-modal__footer{position:relative;display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:12px;flex-shrink:0;padding:16px 24px 24px;border-top:none;background:var(--geo-color-neutral-white)}.geo-form-modal__footer:before{content:\"\";position:absolute;left:24px;right:24px;top:0;height:1px;background:var(--geo-color-primary-default);pointer-events:none}.geo-form-modal__footer-actions{display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:12px;margin-left:auto}@media (max-width: 767.98px){.geo-form-modal-wrap .ant-modal{top:0;max-width:calc(100vw - 24px)!important;width:calc(100vw - 24px)!important;margin:12px auto!important;padding-bottom:0}.geo-form-modal-wrap .ant-modal-content{max-height:calc(100dvh - 24px);display:flex;flex-direction:column}.geo-form-modal-wrap .ant-modal-body{flex:1 1 auto;min-height:0;overflow:hidden}.geo-form-modal__content{max-height:calc(100dvh - 24px);min-height:0}.geo-form-modal__header{gap:12px;padding:24px 24px 16px}.geo-form-modal__title{font-size:var(--geo-font-size-subtitle)}.geo-form-modal__body{gap:16px;padding:24px}.geo-form-modal__content--body-scroll .geo-form-modal__body{max-height:none;flex:1 1 auto}.geo-form-modal__footer{justify-content:stretch;gap:8px;padding:16px 24px 24px}.geo-form-modal__footer-actions{width:100%;margin-left:0}.geo-form-modal__footer-actions>*{flex:1 1 calc(50% - 4px);min-width:0}.geo-form-modal__footer-actions>*:nth-child(n+3){flex:1 1 100%}.geo-form-modal__footer-actions geo-button{display:block;width:100%}.geo-form-modal__footer-actions .geo-button{width:100%;white-space:normal;height:auto;min-height:40px;padding-block:8px;text-align:center}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: NgZorroAntdModule }, { kind: "directive", type: i1$5.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i1.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "component", type: i3$1.NzModalComponent, selector: "nz-modal", inputs: ["nzMask", "nzMaskClosable", "nzCloseOnNavigation", "nzVisible", "nzClosable", "nzOkLoading", "nzOkDisabled", "nzCancelDisabled", "nzCancelLoading", "nzKeyboard", "nzNoAnimation", "nzCentered", "nzDraggable", "nzContent", "nzFooter", "nzZIndex", "nzWidth", "nzWrapClassName", "nzClassName", "nzStyle", "nzTitle", "nzCloseIcon", "nzMaskStyle", "nzBodyStyle", "nzOkText", "nzCancelText", "nzOkType", "nzOkDanger", "nzIconType", "nzModalType", "nzAutofocus", "nzOnOk", "nzOnCancel"], outputs: ["nzOnOk", "nzOnCancel", "nzAfterOpen", "nzAfterClose", "nzVisibleChange"], exportAs: ["nzModal"] }, { kind: "directive", type: i3$1.NzModalContentDirective, selector: "[nzModalContent]", exportAs: ["nzModalContent"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "component", type: GeoButtonComponent, selector: "geo-button", inputs: ["appearance", "color", "icon", "iconTheme", "iconPlacement", "iconOnly", "type", "disabled", "tooltip", "tooltipPlacement", "active", "title"], outputs: ["clicked"] }], encapsulation: i0.ViewEncapsulation.None });
1431
+ }
1432
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoFormModalComponent, decorators: [{
1433
+ type: Component,
1434
+ args: [{ selector: 'geo-form-modal', standalone: true, imports: [CommonModule, NgZorroAntdModule, NzIconModule, GeoButtonComponent], encapsulation: ViewEncapsulation.None, template: "<nz-modal\n [nzVisible]=\"open\"\n [nzTitle]=\"''\"\n [nzFooter]=\"null\"\n [nzClosable]=\"false\"\n [nzMask]=\"mask\"\n [nzMaskClosable]=\"maskClosable\"\n [nzKeyboard]=\"keyboard\"\n [nzCentered]=\"centered\"\n [nzWidth]=\"width\"\n [nzZIndex]=\"zIndex\"\n [nzWrapClassName]=\"resolvedWrapClassName\"\n [nzClassName]=\"resolvedClassName\"\n (nzVisibleChange)=\"onOpenChange($event)\"\n (nzAfterOpen)=\"afterOpen.emit()\"\n (nzAfterClose)=\"afterClose.emit()\"\n>\n <ng-container *nzModalContent>\n <div\n class=\"geo-form-modal__content\"\n [class.geo-form-modal__content--body-scroll]=\"bodyScroll\"\n >\n <div class=\"geo-form-modal__header\">\n <h2\n class=\"geo-form-modal__title\"\n [class.geo-form-modal__title--uppercase]=\"titleUppercase\"\n >\n {{ title }}\n </h2>\n @if (closable) {\n <button\n type=\"button\"\n class=\"geo-form-modal__close\"\n aria-label=\"\u0110\u00F3ng\"\n (click)=\"onCancel()\"\n >\n <span nz-icon nzType=\"close\" nzTheme=\"outline\"></span>\n </button>\n }\n </div>\n\n <div\n class=\"geo-form-modal__body\"\n [style.--geo-form-modal-body-max-height]=\"bodyScroll ? bodyMaxHeightCss : null\"\n >\n <ng-content></ng-content>\n </div>\n\n <div class=\"geo-form-modal__footer\">\n <ng-content select=\"[footerStart]\"></ng-content>\n\n <div class=\"geo-form-modal__footer-actions\">\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n [icon]=\"cancelIcon\"\n [iconPlacement]=\"cancelIconPlacement\"\n (clicked)=\"onCancel()\"\n >\n {{ readonly ? '\u0110\u00F3ng' : cancelText }}\n </geo-button>\n @if (!readonly && secondaryOkText) {\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"save\"\n [disabled]=\"okDisabled || confirmLoading\"\n (clicked)=\"onSecondaryOk()\"\n >\n {{ secondaryOkText }}\n </geo-button>\n }\n @if (!readonly) {\n <geo-button\n appearance=\"primary\"\n color=\"brand\"\n [icon]=\"confirmLoading ? 'loading' : okIcon\"\n [iconPlacement]=\"okIconPlacement\"\n [disabled]=\"okDisabled || confirmLoading\"\n (clicked)=\"onOk()\"\n >\n {{ okText }}\n </geo-button>\n }\n </div>\n </div>\n </div>\n </ng-container>\n</nz-modal>\n", styles: [".geo-form-modal-wrap .ant-modal-header{display:none}.geo-form-modal-wrap .ant-modal{max-width:calc(100vw - 32px)}.geo-form-modal-wrap .ant-modal-content{border-radius:var(--geo-radius);padding:0;overflow:hidden;box-shadow:0 8px 24px #1118271f}.geo-form-modal-wrap .ant-modal-body{padding:0}.geo-form-modal__content{display:flex;flex-direction:column;background:var(--geo-color-neutral-white);max-height:inherit}.geo-form-modal__header{position:relative;display:flex;align-items:center;justify-content:space-between;gap:16px;flex-shrink:0;padding:24px 24px 16px;border-bottom:none}.geo-form-modal__header:after{content:\"\";position:absolute;left:24px;right:24px;bottom:0;height:1px;background:var(--geo-color-primary-default);pointer-events:none}.geo-form-modal__title{margin:0;min-width:0;font-family:var(--geo-font-family);font-size:var(--geo-font-size-h4);font-weight:var(--geo-font-weight-bold);line-height:var(--geo-line-height-h4);color:var(--geo-color-neutral-900);letter-spacing:.02em;word-break:break-word}.geo-form-modal__title--uppercase{text-transform:uppercase}.geo-form-modal__close{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;border-radius:var(--geo-radius);background:transparent;color:var(--geo-color-neutral-500);cursor:pointer;flex-shrink:0;transition:color .15s ease,background-color .15s ease}.geo-form-modal__close .anticon{font-size:14px}.geo-form-modal__close:hover{color:var(--geo-color-neutral-900);background:var(--geo-color-neutral-100)}.geo-form-modal__body{display:flex;flex-direction:column;gap:20px;flex:1 1 auto;min-width:0;min-height:0;padding:24px}.geo-form-modal__content--body-scroll .geo-form-modal__body{overflow-x:hidden;overflow-y:auto;max-height:var(--geo-form-modal-body-max-height, 60vh);-webkit-overflow-scrolling:touch}.geo-form-modal__footer{position:relative;display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:12px;flex-shrink:0;padding:16px 24px 24px;border-top:none;background:var(--geo-color-neutral-white)}.geo-form-modal__footer:before{content:\"\";position:absolute;left:24px;right:24px;top:0;height:1px;background:var(--geo-color-primary-default);pointer-events:none}.geo-form-modal__footer-actions{display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:12px;margin-left:auto}@media (max-width: 767.98px){.geo-form-modal-wrap .ant-modal{top:0;max-width:calc(100vw - 24px)!important;width:calc(100vw - 24px)!important;margin:12px auto!important;padding-bottom:0}.geo-form-modal-wrap .ant-modal-content{max-height:calc(100dvh - 24px);display:flex;flex-direction:column}.geo-form-modal-wrap .ant-modal-body{flex:1 1 auto;min-height:0;overflow:hidden}.geo-form-modal__content{max-height:calc(100dvh - 24px);min-height:0}.geo-form-modal__header{gap:12px;padding:24px 24px 16px}.geo-form-modal__title{font-size:var(--geo-font-size-subtitle)}.geo-form-modal__body{gap:16px;padding:24px}.geo-form-modal__content--body-scroll .geo-form-modal__body{max-height:none;flex:1 1 auto}.geo-form-modal__footer{justify-content:stretch;gap:8px;padding:16px 24px 24px}.geo-form-modal__footer-actions{width:100%;margin-left:0}.geo-form-modal__footer-actions>*{flex:1 1 calc(50% - 4px);min-width:0}.geo-form-modal__footer-actions>*:nth-child(n+3){flex:1 1 100%}.geo-form-modal__footer-actions geo-button{display:block;width:100%}.geo-form-modal__footer-actions .geo-button{width:100%;white-space:normal;height:auto;min-height:40px;padding-block:8px;text-align:center}}\n"] }]
1435
+ }], propDecorators: { open: [{
1436
+ type: Input
1437
+ }], title: [{
1438
+ type: Input
1439
+ }], titleUppercase: [{
1440
+ type: Input
1441
+ }], okText: [{
1442
+ type: Input
1443
+ }], cancelText: [{
1444
+ type: Input
1445
+ }], cancelIcon: [{
1446
+ type: Input
1447
+ }], cancelIconPlacement: [{
1448
+ type: Input
1449
+ }], okIcon: [{
1450
+ type: Input
1451
+ }], okIconPlacement: [{
1452
+ type: Input
1453
+ }], secondaryOkText: [{
1454
+ type: Input
1455
+ }], confirmLoading: [{
1456
+ type: Input
1457
+ }], okDisabled: [{
1458
+ type: Input
1459
+ }], readonly: [{
1460
+ type: Input
1461
+ }], width: [{
1462
+ type: Input
1463
+ }], closable: [{
1464
+ type: Input
1465
+ }], mask: [{
1466
+ type: Input
1467
+ }], maskClosable: [{
1468
+ type: Input
1469
+ }], keyboard: [{
1470
+ type: Input
1471
+ }], centered: [{
1472
+ type: Input
1473
+ }], zIndex: [{
1474
+ type: Input
1475
+ }], className: [{
1476
+ type: Input
1477
+ }], wrapClassName: [{
1478
+ type: Input
1479
+ }], bodyScroll: [{
1480
+ type: Input
1481
+ }], bodyMaxHeight: [{
1482
+ type: Input
1483
+ }], openChange: [{
1484
+ type: Output
1485
+ }], ok: [{
1486
+ type: Output
1487
+ }], secondaryOk: [{
1488
+ type: Output
1489
+ }], cancel: [{
1490
+ type: Output
1491
+ }], afterOpen: [{
1492
+ type: Output
1493
+ }], afterClose: [{
1494
+ type: Output
1495
+ }] } });
1496
+
1497
+ const GEO_ICON_SIZE_MAP = {
1498
+ xs: '12px',
1499
+ sm: '14px',
1500
+ md: '16px',
1501
+ lg: '20px',
1502
+ xl: '24px',
1503
+ };
1504
+
1505
+ /**
1506
+ * Icon wrapper — domain dùng `geo-icon`, không dùng `nz-icon` trực tiếp.
1507
+ * Wrap Ant Design icons (đã register qua `NZ_ICONS` ở app/Storybook).
1508
+ */
1509
+ class GeoIconComponent {
1510
+ /** Tên icon Ant Design (vd. `close`, `search`, `appstore`). */
1511
+ type;
1512
+ theme = 'outline';
1513
+ spin = false;
1514
+ /** xs | sm | md | lg | xl | number(px) | CSS size string */
1515
+ size = 'md';
1516
+ /** CSS color — ưu tiên design token, vd. `var(--geo-color-primary-default)` */
1517
+ color;
1518
+ get resolvedSize() {
1519
+ if (typeof this.size === 'number') {
1520
+ return `${this.size}px`;
1521
+ }
1522
+ if (this.size in GEO_ICON_SIZE_MAP) {
1523
+ return GEO_ICON_SIZE_MAP[this.size];
1524
+ }
1525
+ return String(this.size);
1526
+ }
1527
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1528
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: GeoIconComponent, isStandalone: true, selector: "geo-icon", inputs: { type: "type", theme: "theme", spin: "spin", size: "size", color: "color" }, host: { properties: { "style.--geo-icon-size": "resolvedSize", "style.color": "color || null", "class.geo-icon-host--spin": "spin" }, classAttribute: "geo-icon-host" }, ngImport: i0, template: "<span\n class=\"geo-icon\"\n nz-icon\n [nzType]=\"type\"\n [nzTheme]=\"theme\"\n [nzSpin]=\"spin\"\n></span>\n", styles: [".geo-icon-host{display:inline-flex;align-items:center;justify-content:center;line-height:1;color:inherit;vertical-align:middle}.geo-icon-host--spin{color:var(--geo-color-primary-default)}.geo-icon{display:inline-flex;align-items:center;justify-content:center;line-height:1;font-size:var(--geo-icon-size, 16px)}.geo-icon .anticon{font-size:inherit}\n"], dependencies: [{ kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }], encapsulation: i0.ViewEncapsulation.None });
1529
+ }
1530
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoIconComponent, decorators: [{
1531
+ type: Component,
1532
+ args: [{ selector: 'geo-icon', standalone: true, imports: [NzIconModule], encapsulation: ViewEncapsulation.None, host: {
1533
+ class: 'geo-icon-host',
1534
+ '[style.--geo-icon-size]': 'resolvedSize',
1535
+ '[style.color]': 'color || null',
1536
+ '[class.geo-icon-host--spin]': 'spin',
1537
+ }, template: "<span\n class=\"geo-icon\"\n nz-icon\n [nzType]=\"type\"\n [nzTheme]=\"theme\"\n [nzSpin]=\"spin\"\n></span>\n", styles: [".geo-icon-host{display:inline-flex;align-items:center;justify-content:center;line-height:1;color:inherit;vertical-align:middle}.geo-icon-host--spin{color:var(--geo-color-primary-default)}.geo-icon{display:inline-flex;align-items:center;justify-content:center;line-height:1;font-size:var(--geo-icon-size, 16px)}.geo-icon .anticon{font-size:inherit}\n"] }]
1538
+ }], propDecorators: { type: [{
1539
+ type: Input,
1540
+ args: [{ required: true }]
1541
+ }], theme: [{
1542
+ type: Input
1543
+ }], spin: [{
1544
+ type: Input
1545
+ }], size: [{
1546
+ type: Input
1547
+ }], color: [{
1548
+ type: Input
1549
+ }] } });
1550
+
1551
+ let uiInputErrorId = 0;
1552
+ class GeoInputComponent {
1553
+ label = '';
1554
+ placeholder = '';
1555
+ type = 'text';
1556
+ disabled = false;
1557
+ readonly = false;
1558
+ required = false;
1559
+ error = false;
1560
+ errorMessage = '';
1561
+ maxlength;
1562
+ prefixIcon;
1563
+ suffixIcon;
1564
+ allowClear = false;
1565
+ block = false;
1566
+ width;
1567
+ valueChange = new EventEmitter();
1568
+ enterPressed = new EventEmitter();
1569
+ errorMessageId = `geo-input-error-${++uiInputErrorId}`;
1570
+ value = '';
1571
+ onChange = () => undefined;
1572
+ onTouched = () => undefined;
1573
+ get hostWidth() {
1574
+ if (this.block || this.width == null) {
1575
+ return null;
1576
+ }
1577
+ return typeof this.width === 'number' ? `${this.width}px` : this.width;
1578
+ }
1579
+ get showClear() {
1580
+ return this.allowClear && !this.disabled && !this.readonly && !!this.value;
1581
+ }
1582
+ onInput(value) {
1583
+ this.value = value;
1584
+ this.onChange(value);
1585
+ this.valueChange.emit(value);
1586
+ }
1587
+ onBlur() {
1588
+ this.onTouched();
1589
+ }
1590
+ onClear() {
1591
+ this.onInput('');
1592
+ }
1593
+ writeValue(value) {
1594
+ this.value = value == null ? '' : String(value);
1595
+ }
1596
+ registerOnChange(fn) {
1597
+ this.onChange = fn;
1598
+ }
1599
+ registerOnTouched(fn) {
1600
+ this.onTouched = fn;
1601
+ }
1602
+ setDisabledState(isDisabled) {
1603
+ this.disabled = isDisabled;
1604
+ }
1605
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1606
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoInputComponent, isStandalone: true, selector: "geo-input", inputs: { label: "label", placeholder: "placeholder", type: "type", disabled: "disabled", readonly: "readonly", required: "required", error: "error", errorMessage: "errorMessage", maxlength: "maxlength", prefixIcon: "prefixIcon", suffixIcon: "suffixIcon", allowClear: "allowClear", block: "block", width: "width" }, outputs: { valueChange: "valueChange", enterPressed: "enterPressed" }, host: { properties: { "class.geo-input-host--block": "block", "class.geo-input-host--error": "error", "style.width": "hostWidth" }, classAttribute: "geo-input-host" }, providers: [
1607
+ {
1608
+ provide: NG_VALUE_ACCESSOR,
1609
+ useExisting: forwardRef(() => GeoInputComponent),
1610
+ multi: true,
1611
+ },
1612
+ ], ngImport: i0, template: "@if (label) {\n <div class=\"geo-input__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-input__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<div\n class=\"geo-input__control\"\n [class.geo-input__control--disabled]=\"disabled\"\n [class.geo-input__control--error]=\"error\"\n>\n @if (prefixIcon) {\n <span class=\"geo-input__icon\" nz-icon [nzType]=\"prefixIcon\" nzTheme=\"outline\"></span>\n }\n\n <input\n class=\"geo-input__field\"\n [type]=\"type\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [readonly]=\"readonly\"\n [attr.maxlength]=\"maxlength ?? null\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n [ngModel]=\"value\"\n (ngModelChange)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n (keyup.enter)=\"enterPressed.emit()\"\n />\n\n @if (showClear) {\n <button type=\"button\" class=\"geo-input__clear\" aria-label=\"X\u00F3a n\u1ED9i dung\" (click)=\"onClear()\">\n <span nz-icon nzType=\"close-circle\" nzTheme=\"fill\"></span>\n </button>\n }\n\n @if (suffixIcon) {\n <span class=\"geo-input__icon\" nz-icon [nzType]=\"suffixIcon\" nzTheme=\"outline\"></span>\n }\n</div>\n\n@if (error && errorMessage) {\n <p class=\"geo-input__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: [".geo-input-host{display:inline-flex;flex-direction:column;gap:8px;width:413px;max-width:100%;vertical-align:top}geo-input.geo-input-host.geo-input-host--block,.geo-input-host.geo-input-host--block{display:flex;width:100%;max-width:none}.geo-input__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-input__required{color:var(--geo-color-error-default)}.geo-input__control{display:flex;align-items:center;gap:10px;min-height:40px;height:40px;padding:8px;border:1px solid var(--geo-color-neutral-300);border-radius:var(--geo-radius);background:transparent;box-sizing:border-box;transition:border-color .15s ease,box-shadow .15s ease}.geo-input__control:hover:not(.geo-input__control--disabled){border-color:var(--geo-color-primary-default)}.geo-input__control:focus-within:not(.geo-input__control--disabled){border-color:var(--geo-color-primary-default);box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-primary-default) 12%,transparent)}.geo-input__control--error{border-color:var(--geo-color-error-default)!important}.geo-input__control--error:focus-within{box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-error-default) 12%,transparent)!important}.geo-input__control--disabled{background:var(--geo-color-neutral-100);border-color:var(--geo-color-neutral-300)}.geo-input__field{flex:1 1 auto;min-width:0;height:24px;border:none;outline:none;background:transparent;font-size:14px;line-height:24px;color:var(--geo-color-neutral-900);font-family:inherit}.geo-input__field::placeholder{color:var(--geo-color-neutral-500)}.geo-input__field:disabled{color:var(--geo-color-neutral-disabled-text);cursor:not-allowed}.geo-input__icon{display:inline-flex;flex-shrink:0;font-size:16px;color:var(--geo-color-neutral-500)}.geo-input__clear{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;padding:0;border:none;background:transparent;color:var(--geo-color-neutral-400);font-size:14px;cursor:pointer}.geo-input__clear:hover{color:var(--geo-color-neutral-500)}.geo-input__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }], encapsulation: i0.ViewEncapsulation.None });
1613
+ }
1614
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoInputComponent, decorators: [{
1615
+ type: Component,
1616
+ args: [{ selector: 'geo-input', standalone: true, imports: [CommonModule, FormsModule, NzIconModule], encapsulation: ViewEncapsulation.None, host: {
1617
+ class: 'geo-input-host',
1618
+ '[class.geo-input-host--block]': 'block',
1619
+ '[class.geo-input-host--error]': 'error',
1620
+ '[style.width]': 'hostWidth',
1621
+ }, providers: [
1622
+ {
1623
+ provide: NG_VALUE_ACCESSOR,
1624
+ useExisting: forwardRef(() => GeoInputComponent),
1625
+ multi: true,
1626
+ },
1627
+ ], template: "@if (label) {\n <div class=\"geo-input__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-input__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<div\n class=\"geo-input__control\"\n [class.geo-input__control--disabled]=\"disabled\"\n [class.geo-input__control--error]=\"error\"\n>\n @if (prefixIcon) {\n <span class=\"geo-input__icon\" nz-icon [nzType]=\"prefixIcon\" nzTheme=\"outline\"></span>\n }\n\n <input\n class=\"geo-input__field\"\n [type]=\"type\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [readonly]=\"readonly\"\n [attr.maxlength]=\"maxlength ?? null\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n [ngModel]=\"value\"\n (ngModelChange)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n (keyup.enter)=\"enterPressed.emit()\"\n />\n\n @if (showClear) {\n <button type=\"button\" class=\"geo-input__clear\" aria-label=\"X\u00F3a n\u1ED9i dung\" (click)=\"onClear()\">\n <span nz-icon nzType=\"close-circle\" nzTheme=\"fill\"></span>\n </button>\n }\n\n @if (suffixIcon) {\n <span class=\"geo-input__icon\" nz-icon [nzType]=\"suffixIcon\" nzTheme=\"outline\"></span>\n }\n</div>\n\n@if (error && errorMessage) {\n <p class=\"geo-input__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: [".geo-input-host{display:inline-flex;flex-direction:column;gap:8px;width:413px;max-width:100%;vertical-align:top}geo-input.geo-input-host.geo-input-host--block,.geo-input-host.geo-input-host--block{display:flex;width:100%;max-width:none}.geo-input__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-input__required{color:var(--geo-color-error-default)}.geo-input__control{display:flex;align-items:center;gap:10px;min-height:40px;height:40px;padding:8px;border:1px solid var(--geo-color-neutral-300);border-radius:var(--geo-radius);background:transparent;box-sizing:border-box;transition:border-color .15s ease,box-shadow .15s ease}.geo-input__control:hover:not(.geo-input__control--disabled){border-color:var(--geo-color-primary-default)}.geo-input__control:focus-within:not(.geo-input__control--disabled){border-color:var(--geo-color-primary-default);box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-primary-default) 12%,transparent)}.geo-input__control--error{border-color:var(--geo-color-error-default)!important}.geo-input__control--error:focus-within{box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-error-default) 12%,transparent)!important}.geo-input__control--disabled{background:var(--geo-color-neutral-100);border-color:var(--geo-color-neutral-300)}.geo-input__field{flex:1 1 auto;min-width:0;height:24px;border:none;outline:none;background:transparent;font-size:14px;line-height:24px;color:var(--geo-color-neutral-900);font-family:inherit}.geo-input__field::placeholder{color:var(--geo-color-neutral-500)}.geo-input__field:disabled{color:var(--geo-color-neutral-disabled-text);cursor:not-allowed}.geo-input__icon{display:inline-flex;flex-shrink:0;font-size:16px;color:var(--geo-color-neutral-500)}.geo-input__clear{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;padding:0;border:none;background:transparent;color:var(--geo-color-neutral-400);font-size:14px;cursor:pointer}.geo-input__clear:hover{color:var(--geo-color-neutral-500)}.geo-input__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}\n"] }]
1628
+ }], propDecorators: { label: [{
1629
+ type: Input
1630
+ }], placeholder: [{
1631
+ type: Input
1632
+ }], type: [{
1633
+ type: Input
1634
+ }], disabled: [{
1635
+ type: Input
1636
+ }], readonly: [{
1637
+ type: Input
1638
+ }], required: [{
1639
+ type: Input
1640
+ }], error: [{
1641
+ type: Input
1642
+ }], errorMessage: [{
1643
+ type: Input
1644
+ }], maxlength: [{
1645
+ type: Input
1646
+ }], prefixIcon: [{
1647
+ type: Input
1648
+ }], suffixIcon: [{
1649
+ type: Input
1650
+ }], allowClear: [{
1651
+ type: Input
1652
+ }], block: [{
1653
+ type: Input
1654
+ }], width: [{
1655
+ type: Input
1656
+ }], valueChange: [{
1657
+ type: Output
1658
+ }], enterPressed: [{
1659
+ type: Output
1660
+ }] } });
1661
+
1662
+ /**
1663
+ * Pagination gọn — wrap `nz-pagination`. Dùng cho panel/map (không kèm size changer như `geo-table-pagination`).
1664
+ */
1665
+ class GeoPaginationComponent {
1666
+ pageIndex = 1;
1667
+ pageSize = 10;
1668
+ total = 0;
1669
+ size = 'default';
1670
+ simple = false;
1671
+ hideOnSinglePage = false;
1672
+ showSizeChanger = false;
1673
+ pageSizeOptions = [5, 10, 20, 50];
1674
+ pageIndexChange = new EventEmitter();
1675
+ pageSizeChange = new EventEmitter();
1676
+ onPageIndexChange(page) {
1677
+ this.pageIndex = page;
1678
+ this.pageIndexChange.emit(page);
1679
+ }
1680
+ onPageSizeChange(size) {
1681
+ this.pageSize = size;
1682
+ this.pageSizeChange.emit(size);
1683
+ }
1684
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoPaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1685
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: GeoPaginationComponent, isStandalone: true, selector: "geo-pagination", inputs: { pageIndex: "pageIndex", pageSize: "pageSize", total: "total", size: "size", simple: "simple", hideOnSinglePage: "hideOnSinglePage", showSizeChanger: "showSizeChanger", pageSizeOptions: "pageSizeOptions" }, outputs: { pageIndexChange: "pageIndexChange", pageSizeChange: "pageSizeChange" }, host: { classAttribute: "geo-pagination-host" }, ngImport: i0, template: "<div class=\"geo-pagination\">\n <nz-pagination\n [nzSize]=\"size\"\n [nzSimple]=\"simple\"\n [nzPageIndex]=\"pageIndex\"\n [nzPageSize]=\"pageSize\"\n [nzTotal]=\"total\"\n [nzHideOnSinglePage]=\"hideOnSinglePage\"\n [nzShowSizeChanger]=\"showSizeChanger\"\n [nzPageSizeOptions]=\"pageSizeOptions\"\n (nzPageIndexChange)=\"onPageIndexChange($event)\"\n (nzPageSizeChange)=\"onPageSizeChange($event)\"\n ></nz-pagination>\n</div>\n", styles: [".geo-pagination-host{display:inline-flex;align-items:center}.geo-pagination{display:inline-flex}\n"], dependencies: [{ kind: "ngmodule", type: NzPaginationModule }, { kind: "component", type: i1$6.NzPaginationComponent, selector: "nz-pagination", inputs: ["nzShowTotal", "nzItemRender", "nzSize", "nzPageSizeOptions", "nzShowSizeChanger", "nzShowQuickJumper", "nzSimple", "nzDisabled", "nzResponsive", "nzHideOnSinglePage", "nzTotal", "nzPageIndex", "nzPageSize"], outputs: ["nzPageSizeChange", "nzPageIndexChange"], exportAs: ["nzPagination"] }], encapsulation: i0.ViewEncapsulation.None });
1686
+ }
1687
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoPaginationComponent, decorators: [{
1688
+ type: Component,
1689
+ args: [{ selector: 'geo-pagination', standalone: true, imports: [NzPaginationModule], encapsulation: ViewEncapsulation.None, host: { class: 'geo-pagination-host' }, template: "<div class=\"geo-pagination\">\n <nz-pagination\n [nzSize]=\"size\"\n [nzSimple]=\"simple\"\n [nzPageIndex]=\"pageIndex\"\n [nzPageSize]=\"pageSize\"\n [nzTotal]=\"total\"\n [nzHideOnSinglePage]=\"hideOnSinglePage\"\n [nzShowSizeChanger]=\"showSizeChanger\"\n [nzPageSizeOptions]=\"pageSizeOptions\"\n (nzPageIndexChange)=\"onPageIndexChange($event)\"\n (nzPageSizeChange)=\"onPageSizeChange($event)\"\n ></nz-pagination>\n</div>\n", styles: [".geo-pagination-host{display:inline-flex;align-items:center}.geo-pagination{display:inline-flex}\n"] }]
1690
+ }], propDecorators: { pageIndex: [{
1691
+ type: Input
1692
+ }], pageSize: [{
1693
+ type: Input
1694
+ }], total: [{
1695
+ type: Input
1696
+ }], size: [{
1697
+ type: Input
1698
+ }], simple: [{
1699
+ type: Input
1700
+ }], hideOnSinglePage: [{
1701
+ type: Input
1702
+ }], showSizeChanger: [{
1703
+ type: Input
1704
+ }], pageSizeOptions: [{
1705
+ type: Input
1706
+ }], pageIndexChange: [{
1707
+ type: Output
1708
+ }], pageSizeChange: [{
1709
+ type: Output
1710
+ }] } });
1711
+
1712
+ /** Semantic HTML element rendered for each variant. */
1713
+ const GEO_TYPOGRAPHY_TAG = {
1714
+ h1: 'h1',
1715
+ h2: 'h2',
1716
+ h3: 'h3',
1717
+ h4: 'h4',
1718
+ subtitle: 'p',
1719
+ body: 'p',
1720
+ 'body-small': 'p',
1721
+ caption: 'span',
1722
+ overline: 'span',
1723
+ tiny: 'span',
1724
+ };
1725
+ const GEO_TYPOGRAPHY_VARIANTS = [
1726
+ {
1727
+ variant: 'h1',
1728
+ label: 'Heading 1',
1729
+ size: '28px',
1730
+ weight: 'Bold (700)',
1731
+ lineHeight: '36px',
1732
+ usage: 'Tiêu đề trang chính',
1733
+ },
1734
+ {
1735
+ variant: 'h2',
1736
+ label: 'Heading 2',
1737
+ size: '24px',
1738
+ weight: 'Bold (700)',
1739
+ lineHeight: '32px',
1740
+ usage: 'Tiêu đề section',
1741
+ },
1742
+ {
1743
+ variant: 'h3',
1744
+ label: 'Heading 3',
1745
+ size: '20px',
1746
+ weight: 'Bold (700)',
1747
+ lineHeight: '28px',
1748
+ usage: 'Tiêu đề component, section header',
1749
+ },
1750
+ {
1751
+ variant: 'h4',
1752
+ label: 'Heading 4',
1753
+ size: '16px',
1754
+ weight: 'Bold (700)',
1755
+ lineHeight: '24px',
1756
+ usage: 'Tiêu đề card, form section',
1757
+ },
1758
+ {
1759
+ variant: 'subtitle',
1760
+ label: 'Subtitle',
1761
+ size: '14px',
1762
+ weight: 'Semi Bold (600)',
1763
+ lineHeight: '20px',
1764
+ usage: 'Label, form label, table header',
1765
+ },
1766
+ {
1767
+ variant: 'body',
1768
+ label: 'Body',
1769
+ size: '14px',
1770
+ weight: 'Regular (400)',
1771
+ lineHeight: '20px',
1772
+ usage: 'Nội dung chính, input text',
1773
+ },
1774
+ {
1775
+ variant: 'body-small',
1776
+ label: 'Body Small',
1777
+ size: '13px',
1778
+ weight: 'Regular (400)',
1779
+ lineHeight: '18px',
1780
+ usage: 'Mô tả phụ, toast message',
1781
+ },
1782
+ {
1783
+ variant: 'caption',
1784
+ label: 'Caption',
1785
+ size: '12px',
1786
+ weight: 'Regular (400)',
1787
+ lineHeight: '16px',
1788
+ usage: 'Helper text, timestamp',
1789
+ },
1790
+ {
1791
+ variant: 'overline',
1792
+ label: 'Overline',
1793
+ size: '11px',
1794
+ weight: 'Semi Bold (600)',
1795
+ lineHeight: '16px',
1796
+ usage: 'Badge text, status label',
1797
+ },
1798
+ {
1799
+ variant: 'tiny',
1800
+ label: 'Tiny',
1801
+ size: '10px',
1802
+ weight: 'Regular (400)',
1803
+ lineHeight: '14px',
1804
+ usage: 'Hex code, footnote',
1805
+ },
1806
+ ];
1807
+
1808
+ /**
1809
+ * Typography based on Ant Design Typography, styled with GEO type scale (Inter).
1810
+ *
1811
+ * @example
1812
+ * ```html
1813
+ * <geo-typography variant="h1">Page title</geo-typography>
1814
+ * <geo-typography variant="body" color="secondary">Helper</geo-typography>
1815
+ * ```
1816
+ */
1817
+ class GeoTypographyComponent {
1818
+ /** Type scale variant from the design system. */
1819
+ variant = 'body';
1820
+ /** Semantic text color. */
1821
+ color = 'default';
1822
+ /** Force bold weight (overrides variant weight when true). */
1823
+ strong = false;
1824
+ /** Underline text decoration. */
1825
+ underline = false;
1826
+ /** Strikethrough text decoration. */
1827
+ delete = false;
1828
+ /** Mark / highlight background. */
1829
+ mark = false;
1830
+ /** Monospace code appearance. */
1831
+ code = false;
1832
+ /** Disabled appearance */
1833
+ disabled = false;
1834
+ get hostClassList() {
1835
+ const classes = [
1836
+ 'geo-typography',
1837
+ 'ant-typography',
1838
+ `geo-typography--${this.variant}`,
1839
+ `geo-typography--color-${this.color}`,
1840
+ ];
1841
+ if (this.strong)
1842
+ classes.push('geo-typography--strong');
1843
+ if (this.underline)
1844
+ classes.push('geo-typography--underline');
1845
+ if (this.delete)
1846
+ classes.push('geo-typography--delete');
1847
+ if (this.mark)
1848
+ classes.push('geo-typography--mark');
1849
+ if (this.code)
1850
+ classes.push('geo-typography--code');
1851
+ if (this.disabled)
1852
+ classes.push('geo-typography--disabled', 'ant-typography-disabled');
1853
+ if (this.nzType)
1854
+ classes.push(`ant-typography-${this.nzType}`);
1855
+ return classes.join(' ');
1856
+ }
1857
+ get headingRole() {
1858
+ const tag = GEO_TYPOGRAPHY_TAG[this.variant];
1859
+ return tag.startsWith('h') ? 'heading' : null;
1860
+ }
1861
+ get headingLevel() {
1862
+ switch (this.variant) {
1863
+ case 'h1':
1864
+ return 1;
1865
+ case 'h2':
1866
+ return 2;
1867
+ case 'h3':
1868
+ return 3;
1869
+ case 'h4':
1870
+ return 4;
1871
+ default:
1872
+ return null;
1873
+ }
1874
+ }
1875
+ get nzType() {
1876
+ switch (this.color) {
1877
+ case 'secondary':
1878
+ return 'secondary';
1879
+ case 'success':
1880
+ return 'success';
1881
+ case 'warning':
1882
+ return 'warning';
1883
+ case 'danger':
1884
+ return 'danger';
1885
+ default:
1886
+ return undefined;
1887
+ }
1888
+ }
1889
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTypographyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1890
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: GeoTypographyComponent, isStandalone: true, selector: "geo-typography", inputs: { variant: "variant", color: "color", strong: "strong", underline: "underline", delete: "delete", mark: "mark", code: "code", disabled: "disabled" }, host: { properties: { "class": "hostClassList", "attr.role": "headingRole", "attr.aria-level": "headingLevel" } }, ngImport: i0, template: `<ng-content></ng-content>`, isInline: true, styles: ["@charset \"UTF-8\";.geo-typography.ant-typography,.geo-typography{margin:0;padding:0;font-family:var(--geo-font-family);color:var(--geo-color-neutral-900);box-sizing:border-box}.geo-typography.ant-typography.ant-typography,.geo-typography.ant-typography{margin-bottom:0}.geo-typography.ant-typography--h1,.geo-typography.ant-typography--h2,.geo-typography.ant-typography--h3,.geo-typography.ant-typography--h4,.geo-typography.ant-typography--subtitle,.geo-typography.ant-typography--body,.geo-typography.ant-typography--body-small,.geo-typography--h1,.geo-typography--h2,.geo-typography--h3,.geo-typography--h4,.geo-typography--subtitle,.geo-typography--body,.geo-typography--body-small{display:block}.geo-typography.ant-typography--caption,.geo-typography.ant-typography--overline,.geo-typography.ant-typography--tiny,.geo-typography--caption,.geo-typography--overline,.geo-typography--tiny{display:inline}.geo-typography.ant-typography--h1,.geo-typography--h1{font-size:var(--geo-font-size-h1);font-weight:var(--geo-font-weight-bold);line-height:var(--geo-line-height-h1)}.geo-typography.ant-typography--h2,.geo-typography--h2{font-size:var(--geo-font-size-h2);font-weight:var(--geo-font-weight-bold);line-height:var(--geo-line-height-h2)}.geo-typography.ant-typography--h3,.geo-typography--h3{font-size:var(--geo-font-size-h3);font-weight:var(--geo-font-weight-bold);line-height:var(--geo-line-height-h3)}.geo-typography.ant-typography--h4,.geo-typography--h4{font-size:var(--geo-font-size-h4);font-weight:var(--geo-font-weight-bold);line-height:var(--geo-line-height-h4)}.geo-typography.ant-typography--subtitle,.geo-typography--subtitle{font-size:var(--geo-font-size-subtitle);font-weight:var(--geo-font-weight-semibold);line-height:var(--geo-line-height-subtitle)}.geo-typography.ant-typography--body,.geo-typography--body{font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-body)}.geo-typography.ant-typography--body-small,.geo-typography--body-small{font-size:var(--geo-font-size-body-small);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-body-small)}.geo-typography.ant-typography--caption,.geo-typography--caption{font-size:var(--geo-font-size-caption);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-caption)}.geo-typography.ant-typography--overline,.geo-typography--overline{font-size:var(--geo-font-size-overline);font-weight:var(--geo-font-weight-semibold);line-height:var(--geo-line-height-overline);text-transform:uppercase;letter-spacing:.04em}.geo-typography.ant-typography--tiny,.geo-typography--tiny{font-size:var(--geo-font-size-tiny);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-tiny)}.geo-typography.ant-typography--color-default,.geo-typography--color-default{color:var(--geo-color-neutral-900)}.geo-typography.ant-typography--color-secondary,.geo-typography.ant-typography.ant-typography-secondary,.geo-typography--color-secondary,.geo-typography.ant-typography-secondary{color:var(--geo-color-neutral-500)}.geo-typography.ant-typography--color-primary,.geo-typography--color-primary{color:var(--geo-color-primary-default)}.geo-typography.ant-typography--color-success,.geo-typography.ant-typography.ant-typography-success,.geo-typography--color-success,.geo-typography.ant-typography-success{color:var(--geo-color-success-dark)}.geo-typography.ant-typography--color-warning,.geo-typography.ant-typography.ant-typography-warning,.geo-typography--color-warning,.geo-typography.ant-typography-warning{color:var(--geo-color-warning-dark)}.geo-typography.ant-typography--color-danger,.geo-typography.ant-typography.ant-typography-danger,.geo-typography--color-danger,.geo-typography.ant-typography-danger{color:var(--geo-color-error-default)}.geo-typography.ant-typography--color-disabled,.geo-typography.ant-typography--disabled,.geo-typography.ant-typography.ant-typography-disabled,.geo-typography--color-disabled,.geo-typography--disabled,.geo-typography.ant-typography-disabled{color:var(--geo-color-neutral-disabled-text)!important;cursor:not-allowed}.geo-typography.ant-typography--strong,.geo-typography--strong{font-weight:var(--geo-font-weight-bold)}.geo-typography.ant-typography--underline,.geo-typography--underline{text-decoration:underline}.geo-typography.ant-typography--delete,.geo-typography--delete{text-decoration:line-through}.geo-typography.ant-typography--mark,.geo-typography--mark{background:var(--geo-color-warning-light);padding:0 .25em;border-radius:2px}.geo-typography.ant-typography--code,.geo-typography--code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;background:var(--geo-color-neutral-100);border:1px solid var(--geo-color-neutral-200);border-radius:var(--geo-radius);padding:.1em .35em}\n"], encapsulation: i0.ViewEncapsulation.None });
1891
+ }
1892
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTypographyComponent, decorators: [{
1893
+ type: Component,
1894
+ args: [{ selector: 'geo-typography', standalone: true, template: `<ng-content></ng-content>`, encapsulation: ViewEncapsulation.None, host: {
1895
+ '[class]': 'hostClassList',
1896
+ '[attr.role]': 'headingRole',
1897
+ '[attr.aria-level]': 'headingLevel',
1898
+ }, styles: ["@charset \"UTF-8\";.geo-typography.ant-typography,.geo-typography{margin:0;padding:0;font-family:var(--geo-font-family);color:var(--geo-color-neutral-900);box-sizing:border-box}.geo-typography.ant-typography.ant-typography,.geo-typography.ant-typography{margin-bottom:0}.geo-typography.ant-typography--h1,.geo-typography.ant-typography--h2,.geo-typography.ant-typography--h3,.geo-typography.ant-typography--h4,.geo-typography.ant-typography--subtitle,.geo-typography.ant-typography--body,.geo-typography.ant-typography--body-small,.geo-typography--h1,.geo-typography--h2,.geo-typography--h3,.geo-typography--h4,.geo-typography--subtitle,.geo-typography--body,.geo-typography--body-small{display:block}.geo-typography.ant-typography--caption,.geo-typography.ant-typography--overline,.geo-typography.ant-typography--tiny,.geo-typography--caption,.geo-typography--overline,.geo-typography--tiny{display:inline}.geo-typography.ant-typography--h1,.geo-typography--h1{font-size:var(--geo-font-size-h1);font-weight:var(--geo-font-weight-bold);line-height:var(--geo-line-height-h1)}.geo-typography.ant-typography--h2,.geo-typography--h2{font-size:var(--geo-font-size-h2);font-weight:var(--geo-font-weight-bold);line-height:var(--geo-line-height-h2)}.geo-typography.ant-typography--h3,.geo-typography--h3{font-size:var(--geo-font-size-h3);font-weight:var(--geo-font-weight-bold);line-height:var(--geo-line-height-h3)}.geo-typography.ant-typography--h4,.geo-typography--h4{font-size:var(--geo-font-size-h4);font-weight:var(--geo-font-weight-bold);line-height:var(--geo-line-height-h4)}.geo-typography.ant-typography--subtitle,.geo-typography--subtitle{font-size:var(--geo-font-size-subtitle);font-weight:var(--geo-font-weight-semibold);line-height:var(--geo-line-height-subtitle)}.geo-typography.ant-typography--body,.geo-typography--body{font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-body)}.geo-typography.ant-typography--body-small,.geo-typography--body-small{font-size:var(--geo-font-size-body-small);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-body-small)}.geo-typography.ant-typography--caption,.geo-typography--caption{font-size:var(--geo-font-size-caption);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-caption)}.geo-typography.ant-typography--overline,.geo-typography--overline{font-size:var(--geo-font-size-overline);font-weight:var(--geo-font-weight-semibold);line-height:var(--geo-line-height-overline);text-transform:uppercase;letter-spacing:.04em}.geo-typography.ant-typography--tiny,.geo-typography--tiny{font-size:var(--geo-font-size-tiny);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-tiny)}.geo-typography.ant-typography--color-default,.geo-typography--color-default{color:var(--geo-color-neutral-900)}.geo-typography.ant-typography--color-secondary,.geo-typography.ant-typography.ant-typography-secondary,.geo-typography--color-secondary,.geo-typography.ant-typography-secondary{color:var(--geo-color-neutral-500)}.geo-typography.ant-typography--color-primary,.geo-typography--color-primary{color:var(--geo-color-primary-default)}.geo-typography.ant-typography--color-success,.geo-typography.ant-typography.ant-typography-success,.geo-typography--color-success,.geo-typography.ant-typography-success{color:var(--geo-color-success-dark)}.geo-typography.ant-typography--color-warning,.geo-typography.ant-typography.ant-typography-warning,.geo-typography--color-warning,.geo-typography.ant-typography-warning{color:var(--geo-color-warning-dark)}.geo-typography.ant-typography--color-danger,.geo-typography.ant-typography.ant-typography-danger,.geo-typography--color-danger,.geo-typography.ant-typography-danger{color:var(--geo-color-error-default)}.geo-typography.ant-typography--color-disabled,.geo-typography.ant-typography--disabled,.geo-typography.ant-typography.ant-typography-disabled,.geo-typography--color-disabled,.geo-typography--disabled,.geo-typography.ant-typography-disabled{color:var(--geo-color-neutral-disabled-text)!important;cursor:not-allowed}.geo-typography.ant-typography--strong,.geo-typography--strong{font-weight:var(--geo-font-weight-bold)}.geo-typography.ant-typography--underline,.geo-typography--underline{text-decoration:underline}.geo-typography.ant-typography--delete,.geo-typography--delete{text-decoration:line-through}.geo-typography.ant-typography--mark,.geo-typography--mark{background:var(--geo-color-warning-light);padding:0 .25em;border-radius:2px}.geo-typography.ant-typography--code,.geo-typography--code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;background:var(--geo-color-neutral-100);border:1px solid var(--geo-color-neutral-200);border-radius:var(--geo-radius);padding:.1em .35em}\n"] }]
1899
+ }], propDecorators: { variant: [{
1900
+ type: Input
1901
+ }], color: [{
1902
+ type: Input
1903
+ }], strong: [{
1904
+ type: Input
1905
+ }], underline: [{
1906
+ type: Input
1907
+ }], delete: [{
1908
+ type: Input
1909
+ }], mark: [{
1910
+ type: Input
1911
+ }], code: [{
1912
+ type: Input
1913
+ }], disabled: [{
1914
+ type: Input
1915
+ }] } });
1916
+
1917
+ /**
1918
+ * Page title GEO — chữ in hoa đậm + gạch chân ngắn màu primary (theo design).
1919
+ */
1920
+ class GeoPageTitleComponent {
1921
+ /** Nội dung tiêu đề. */
1922
+ title = '';
1923
+ /** Tự chuyển uppercase. Default `true`. */
1924
+ uppercase = true;
1925
+ /** Chiều rộng gạch chân (px hoặc CSS size). Default `56px`. */
1926
+ accentWidth = 56;
1927
+ /** Độ dày gạch chân. Default `4px`. */
1928
+ accentHeight = 4;
1929
+ /** Heading level → geo-typography variant. */
1930
+ level = 3;
1931
+ get typographyVariant() {
1932
+ return `h${this.level}`;
1933
+ }
1934
+ get accentWidthCss() {
1935
+ return typeof this.accentWidth === 'number'
1936
+ ? `${this.accentWidth}px`
1937
+ : this.accentWidth;
1938
+ }
1939
+ get accentHeightCss() {
1940
+ return typeof this.accentHeight === 'number'
1941
+ ? `${this.accentHeight}px`
1942
+ : this.accentHeight;
1943
+ }
1944
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoPageTitleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1945
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoPageTitleComponent, isStandalone: true, selector: "geo-page-title", inputs: { title: "title", uppercase: "uppercase", accentWidth: "accentWidth", accentHeight: "accentHeight", level: "level" }, host: { classAttribute: "geo-page-title-host" }, ngImport: i0, template: "<div\n class=\"geo-page-title\"\n [class.geo-page-title--uppercase]=\"uppercase\"\n>\n <geo-typography [variant]=\"typographyVariant\">\n @if (title) {\n {{ title }}\n } @else {\n <ng-content></ng-content>\n }\n </geo-typography>\n <span\n class=\"geo-page-title__accent\"\n aria-hidden=\"true\"\n [style.width]=\"accentWidthCss\"\n [style.height]=\"accentHeightCss\"\n ></span>\n</div>\n", styles: ["geo-page-title.geo-page-title-host,.geo-page-title-host{display:block;background:transparent;font-family:var(--geo-font-family)}.geo-page-title{display:flex;flex-direction:column;align-items:flex-start;gap:8px;background:transparent}.geo-page-title--uppercase{text-transform:uppercase;letter-spacing:.02em}.geo-page-title__accent{display:block;flex-shrink:0;width:56px;height:4px;border-radius:2px;background:var(--geo-color-primary-default)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: GeoTypographyComponent, selector: "geo-typography", inputs: ["variant", "color", "strong", "underline", "delete", "mark", "code", "disabled"] }], encapsulation: i0.ViewEncapsulation.None });
1946
+ }
1947
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoPageTitleComponent, decorators: [{
1948
+ type: Component,
1949
+ args: [{ selector: 'geo-page-title', standalone: true, imports: [CommonModule, GeoTypographyComponent], encapsulation: ViewEncapsulation.None, host: {
1950
+ class: 'geo-page-title-host',
1951
+ }, template: "<div\n class=\"geo-page-title\"\n [class.geo-page-title--uppercase]=\"uppercase\"\n>\n <geo-typography [variant]=\"typographyVariant\">\n @if (title) {\n {{ title }}\n } @else {\n <ng-content></ng-content>\n }\n </geo-typography>\n <span\n class=\"geo-page-title__accent\"\n aria-hidden=\"true\"\n [style.width]=\"accentWidthCss\"\n [style.height]=\"accentHeightCss\"\n ></span>\n</div>\n", styles: ["geo-page-title.geo-page-title-host,.geo-page-title-host{display:block;background:transparent;font-family:var(--geo-font-family)}.geo-page-title{display:flex;flex-direction:column;align-items:flex-start;gap:8px;background:transparent}.geo-page-title--uppercase{text-transform:uppercase;letter-spacing:.02em}.geo-page-title__accent{display:block;flex-shrink:0;width:56px;height:4px;border-radius:2px;background:var(--geo-color-primary-default)}\n"] }]
1952
+ }], propDecorators: { title: [{
1953
+ type: Input
1954
+ }], uppercase: [{
1955
+ type: Input
1956
+ }], accentWidth: [{
1957
+ type: Input
1958
+ }], accentHeight: [{
1959
+ type: Input
1960
+ }], level: [{
1961
+ type: Input
1962
+ }] } });
1963
+
1964
+ let uiRadioErrorId = 0;
1965
+ class GeoRadioComponent {
1966
+ options = [];
1967
+ label = '';
1968
+ size = 'default';
1969
+ layout = 'horizontal';
1970
+ /** `true` → dùng `nz-radio-button` thay vì `nz-radio` */
1971
+ buttonStyle = false;
1972
+ /** Chỉ áp dụng khi `buttonStyle: true` */
1973
+ buttonAppearance = 'outline';
1974
+ disabled = false;
1975
+ required = false;
1976
+ error = false;
1977
+ errorMessage = '';
1978
+ block = false;
1979
+ valueChange = new EventEmitter();
1980
+ errorMessageId = `geo-radio-error-${++uiRadioErrorId}`;
1981
+ value = null;
1982
+ onChange = () => undefined;
1983
+ onTouched = () => undefined;
1984
+ onValueChange(value) {
1985
+ this.value = value;
1986
+ this.onChange(value);
1987
+ this.onTouched();
1988
+ this.valueChange.emit(value);
1989
+ }
1990
+ writeValue(value) {
1991
+ this.value = value ?? null;
1992
+ }
1993
+ registerOnChange(fn) {
1994
+ this.onChange = fn;
1995
+ }
1996
+ registerOnTouched(fn) {
1997
+ this.onTouched = fn;
1998
+ }
1999
+ setDisabledState(isDisabled) {
2000
+ this.disabled = isDisabled;
2001
+ }
2002
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoRadioComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2003
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoRadioComponent, isStandalone: true, selector: "geo-radio", inputs: { options: "options", label: "label", size: "size", layout: "layout", buttonStyle: "buttonStyle", buttonAppearance: "buttonAppearance", disabled: "disabled", required: "required", error: "error", errorMessage: "errorMessage", block: "block" }, outputs: { valueChange: "valueChange" }, host: { properties: { "class.geo-radio-host--block": "block", "class.geo-radio-host--error": "error", "class.geo-radio-host--vertical": "layout === \"vertical\"", "class.geo-radio-host--button": "buttonStyle" }, classAttribute: "geo-radio-host" }, providers: [
2004
+ {
2005
+ provide: NG_VALUE_ACCESSOR,
2006
+ useExisting: forwardRef(() => GeoRadioComponent),
2007
+ multi: true,
2008
+ },
2009
+ ], ngImport: i0, template: "@if (label) {\n <div class=\"geo-radio__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-radio__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<nz-radio-group\n class=\"geo-radio\"\n [class.geo-radio--vertical]=\"layout === 'vertical'\"\n [nzSize]=\"size\"\n [nzDisabled]=\"disabled\"\n [nzButtonStyle]=\"buttonAppearance\"\n [ngModel]=\"value\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n (ngModelChange)=\"onValueChange($event)\"\n>\n @for (option of options; track option.value) {\n @if (buttonStyle) {\n <label\n nz-radio-button\n class=\"geo-radio__item\"\n [nzValue]=\"option.value\"\n [nzDisabled]=\"option.disabled ?? false\"\n >\n {{ option.label }}\n </label>\n } @else {\n <label\n nz-radio\n class=\"geo-radio__item\"\n [nzValue]=\"option.value\"\n [nzDisabled]=\"option.disabled ?? false\"\n >\n {{ option.label }}\n </label>\n }\n }\n</nz-radio-group>\n\n@if (error && errorMessage) {\n <p class=\"geo-radio__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: ["geo-radio.geo-radio-host,.geo-radio-host{display:inline-flex;flex-direction:column;gap:8px;max-width:100%;vertical-align:top}geo-radio.geo-radio-host.geo-radio-host--block,.geo-radio-host.geo-radio-host--block{display:flex;width:100%}.geo-radio__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-radio__required{color:var(--geo-color-error-default)}.geo-radio__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}.geo-radio.ant-radio-group{display:inline-flex;flex-wrap:wrap;gap:16px 24px}.geo-radio--vertical.ant-radio-group{flex-direction:column;align-items:flex-start;gap:12px}.geo-radio__item{margin:0!important;font-size:14px;line-height:22px;color:var(--geo-color-neutral-900)}.geo-radio .ant-radio-wrapper{margin-inline-end:0;font-size:14px;line-height:22px;color:var(--geo-color-neutral-900)}.geo-radio .ant-radio:not(.ant-radio-disabled):hover .ant-radio-inner{border-color:var(--geo-color-primary-default)}.geo-radio .ant-radio-checked:not(.ant-radio-disabled) .ant-radio-inner{border-color:var(--geo-color-primary-default);background-color:var(--geo-color-neutral-white)}.geo-radio .ant-radio-checked:not(.ant-radio-disabled) .ant-radio-inner:after{background-color:var(--geo-color-primary-default)}.geo-radio .ant-radio-input:focus+.ant-radio-inner,.geo-radio .ant-radio-input:focus-visible+.ant-radio-inner{border-color:var(--geo-color-primary-default);box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-primary-default) 12%,transparent)}.geo-radio .ant-radio-checked:not(.ant-radio-disabled):hover .ant-radio-inner{border-color:var(--geo-color-primary-hover)}.geo-radio .ant-radio-checked:not(.ant-radio-disabled):hover .ant-radio-inner:after{background-color:var(--geo-color-primary-hover)}.geo-radio .ant-radio-disabled .ant-radio-inner{background-color:var(--geo-color-neutral-100);border-color:var(--geo-color-neutral-300)!important}.geo-radio .ant-radio-disabled+span{color:var(--geo-color-neutral-disabled-text)}.geo-radio-host--button .geo-radio.ant-radio-group{gap:0}.geo-radio .ant-radio-button-wrapper{height:40px;line-height:38px;padding:0 16px;border-color:var(--geo-color-neutral-300);color:var(--geo-color-neutral-900);font-size:14px;transition:color .15s ease,border-color .15s ease,background-color .15s ease}.geo-radio .ant-radio-button-wrapper:first-child{border-radius:var(--geo-radius) 0 0 var(--geo-radius)}.geo-radio .ant-radio-button-wrapper:last-child{border-radius:0 var(--geo-radius) var(--geo-radius) 0}.geo-radio .ant-radio-button-wrapper:not(:first-child):before{background-color:var(--geo-color-neutral-300)}.geo-radio .ant-radio-button-wrapper:hover{color:var(--geo-color-primary-default)}.geo-radio .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled){color:var(--geo-color-primary-default);border-color:var(--geo-color-primary-default)!important;background:var(--color-primary-surface, var(--geo-color-primary-surface-light))}.geo-radio .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):before{background-color:var(--geo-color-primary-default)}.geo-radio .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover{color:var(--geo-color-primary-hover);border-color:var(--geo-color-primary-hover)!important;background:var(--color-primary-surface-hover, var(--geo-color-primary-background))}.geo-radio .ant-radio-button-wrapper-disabled{color:var(--geo-color-neutral-disabled-text);background:var(--geo-color-neutral-100)}.geo-radio.ant-radio-group-small .ant-radio-button-wrapper{height:32px;line-height:30px;padding:0 12px;font-size:13px}.geo-radio.ant-radio-group-large .ant-radio-button-wrapper{height:48px;line-height:46px;padding:0 20px;font-size:16px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NgZorroAntdModule }, { kind: "component", type: i2$2.NzRadioComponent, selector: "[nz-radio],[nz-radio-button]", inputs: ["nzValue", "nzDisabled", "nzAutoFocus", "nz-radio-button"], exportAs: ["nzRadio"] }, { kind: "component", type: i2$2.NzRadioGroupComponent, selector: "nz-radio-group", inputs: ["nzDisabled", "nzButtonStyle", "nzSize", "nzName"], exportAs: ["nzRadioGroup"] }], encapsulation: i0.ViewEncapsulation.None });
2010
+ }
2011
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoRadioComponent, decorators: [{
2012
+ type: Component,
2013
+ args: [{ selector: 'geo-radio', standalone: true, imports: [CommonModule, FormsModule, NgZorroAntdModule], encapsulation: ViewEncapsulation.None, host: {
2014
+ class: 'geo-radio-host',
2015
+ '[class.geo-radio-host--block]': 'block',
2016
+ '[class.geo-radio-host--error]': 'error',
2017
+ '[class.geo-radio-host--vertical]': 'layout === "vertical"',
2018
+ '[class.geo-radio-host--button]': 'buttonStyle',
2019
+ }, providers: [
2020
+ {
2021
+ provide: NG_VALUE_ACCESSOR,
2022
+ useExisting: forwardRef(() => GeoRadioComponent),
2023
+ multi: true,
2024
+ },
2025
+ ], template: "@if (label) {\n <div class=\"geo-radio__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-radio__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<nz-radio-group\n class=\"geo-radio\"\n [class.geo-radio--vertical]=\"layout === 'vertical'\"\n [nzSize]=\"size\"\n [nzDisabled]=\"disabled\"\n [nzButtonStyle]=\"buttonAppearance\"\n [ngModel]=\"value\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n (ngModelChange)=\"onValueChange($event)\"\n>\n @for (option of options; track option.value) {\n @if (buttonStyle) {\n <label\n nz-radio-button\n class=\"geo-radio__item\"\n [nzValue]=\"option.value\"\n [nzDisabled]=\"option.disabled ?? false\"\n >\n {{ option.label }}\n </label>\n } @else {\n <label\n nz-radio\n class=\"geo-radio__item\"\n [nzValue]=\"option.value\"\n [nzDisabled]=\"option.disabled ?? false\"\n >\n {{ option.label }}\n </label>\n }\n }\n</nz-radio-group>\n\n@if (error && errorMessage) {\n <p class=\"geo-radio__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: ["geo-radio.geo-radio-host,.geo-radio-host{display:inline-flex;flex-direction:column;gap:8px;max-width:100%;vertical-align:top}geo-radio.geo-radio-host.geo-radio-host--block,.geo-radio-host.geo-radio-host--block{display:flex;width:100%}.geo-radio__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-radio__required{color:var(--geo-color-error-default)}.geo-radio__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}.geo-radio.ant-radio-group{display:inline-flex;flex-wrap:wrap;gap:16px 24px}.geo-radio--vertical.ant-radio-group{flex-direction:column;align-items:flex-start;gap:12px}.geo-radio__item{margin:0!important;font-size:14px;line-height:22px;color:var(--geo-color-neutral-900)}.geo-radio .ant-radio-wrapper{margin-inline-end:0;font-size:14px;line-height:22px;color:var(--geo-color-neutral-900)}.geo-radio .ant-radio:not(.ant-radio-disabled):hover .ant-radio-inner{border-color:var(--geo-color-primary-default)}.geo-radio .ant-radio-checked:not(.ant-radio-disabled) .ant-radio-inner{border-color:var(--geo-color-primary-default);background-color:var(--geo-color-neutral-white)}.geo-radio .ant-radio-checked:not(.ant-radio-disabled) .ant-radio-inner:after{background-color:var(--geo-color-primary-default)}.geo-radio .ant-radio-input:focus+.ant-radio-inner,.geo-radio .ant-radio-input:focus-visible+.ant-radio-inner{border-color:var(--geo-color-primary-default);box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-primary-default) 12%,transparent)}.geo-radio .ant-radio-checked:not(.ant-radio-disabled):hover .ant-radio-inner{border-color:var(--geo-color-primary-hover)}.geo-radio .ant-radio-checked:not(.ant-radio-disabled):hover .ant-radio-inner:after{background-color:var(--geo-color-primary-hover)}.geo-radio .ant-radio-disabled .ant-radio-inner{background-color:var(--geo-color-neutral-100);border-color:var(--geo-color-neutral-300)!important}.geo-radio .ant-radio-disabled+span{color:var(--geo-color-neutral-disabled-text)}.geo-radio-host--button .geo-radio.ant-radio-group{gap:0}.geo-radio .ant-radio-button-wrapper{height:40px;line-height:38px;padding:0 16px;border-color:var(--geo-color-neutral-300);color:var(--geo-color-neutral-900);font-size:14px;transition:color .15s ease,border-color .15s ease,background-color .15s ease}.geo-radio .ant-radio-button-wrapper:first-child{border-radius:var(--geo-radius) 0 0 var(--geo-radius)}.geo-radio .ant-radio-button-wrapper:last-child{border-radius:0 var(--geo-radius) var(--geo-radius) 0}.geo-radio .ant-radio-button-wrapper:not(:first-child):before{background-color:var(--geo-color-neutral-300)}.geo-radio .ant-radio-button-wrapper:hover{color:var(--geo-color-primary-default)}.geo-radio .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled){color:var(--geo-color-primary-default);border-color:var(--geo-color-primary-default)!important;background:var(--color-primary-surface, var(--geo-color-primary-surface-light))}.geo-radio .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):before{background-color:var(--geo-color-primary-default)}.geo-radio .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover{color:var(--geo-color-primary-hover);border-color:var(--geo-color-primary-hover)!important;background:var(--color-primary-surface-hover, var(--geo-color-primary-background))}.geo-radio .ant-radio-button-wrapper-disabled{color:var(--geo-color-neutral-disabled-text);background:var(--geo-color-neutral-100)}.geo-radio.ant-radio-group-small .ant-radio-button-wrapper{height:32px;line-height:30px;padding:0 12px;font-size:13px}.geo-radio.ant-radio-group-large .ant-radio-button-wrapper{height:48px;line-height:46px;padding:0 20px;font-size:16px}\n"] }]
2026
+ }], propDecorators: { options: [{
2027
+ type: Input
2028
+ }], label: [{
2029
+ type: Input
2030
+ }], size: [{
2031
+ type: Input
2032
+ }], layout: [{
2033
+ type: Input
2034
+ }], buttonStyle: [{
2035
+ type: Input
2036
+ }], buttonAppearance: [{
2037
+ type: Input
2038
+ }], disabled: [{
2039
+ type: Input
2040
+ }], required: [{
2041
+ type: Input
2042
+ }], error: [{
2043
+ type: Input
2044
+ }], errorMessage: [{
2045
+ type: Input
2046
+ }], block: [{
2047
+ type: Input
2048
+ }], valueChange: [{
2049
+ type: Output
2050
+ }] } });
2051
+
2052
+ let uiSelectErrorId = 0;
2053
+ class GeoSelectComponent {
2054
+ options = [];
2055
+ label = '';
2056
+ placeholder = 'Chọn giá trị';
2057
+ size = 'default';
2058
+ mode = 'default';
2059
+ disabled = false;
2060
+ required = false;
2061
+ error = false;
2062
+ errorMessage = '';
2063
+ allowClear = true;
2064
+ showSearch = false;
2065
+ block = false;
2066
+ width;
2067
+ valueChange = new EventEmitter();
2068
+ errorMessageId = `geo-select-error-${++uiSelectErrorId}`;
2069
+ value = null;
2070
+ onChange = () => undefined;
2071
+ onTouched = () => undefined;
2072
+ get hostWidth() {
2073
+ if (this.block || this.width == null) {
2074
+ return null;
2075
+ }
2076
+ return typeof this.width === 'number' ? `${this.width}px` : this.width;
2077
+ }
2078
+ get controlClassNames() {
2079
+ return {
2080
+ 'geo-select': true,
2081
+ [`geo-select--${this.size}`]: true,
2082
+ };
2083
+ }
2084
+ onValueChange(value) {
2085
+ this.value = value;
2086
+ this.onChange(value);
2087
+ this.onTouched();
2088
+ this.valueChange.emit(value);
2089
+ }
2090
+ writeValue(value) {
2091
+ this.value = value;
2092
+ }
2093
+ registerOnChange(fn) {
2094
+ this.onChange = fn;
2095
+ }
2096
+ registerOnTouched(fn) {
2097
+ this.onTouched = fn;
2098
+ }
2099
+ setDisabledState(isDisabled) {
2100
+ this.disabled = isDisabled;
2101
+ }
2102
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2103
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoSelectComponent, isStandalone: true, selector: "geo-select", inputs: { options: "options", label: "label", placeholder: "placeholder", size: "size", mode: "mode", disabled: "disabled", required: "required", error: "error", errorMessage: "errorMessage", allowClear: "allowClear", showSearch: "showSearch", block: "block", width: "width" }, outputs: { valueChange: "valueChange" }, host: { properties: { "class.geo-select-host--default": "size === \"default\"", "class.geo-select-host--small": "size === \"small\"", "class.geo-select-host--block": "block", "class.geo-select-host--error": "error", "style.width": "hostWidth" }, classAttribute: "geo-select-host" }, providers: [
2104
+ {
2105
+ provide: NG_VALUE_ACCESSOR,
2106
+ useExisting: forwardRef(() => GeoSelectComponent),
2107
+ multi: true,
2108
+ },
2109
+ ], ngImport: i0, template: "@if (label) {\n <div class=\"geo-select__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-select__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<nz-select\n [ngClass]=\"controlClassNames\"\n nzDropdownClassName=\"geo-select__dropdown\"\n [nzPlaceHolder]=\"placeholder\"\n [nzDisabled]=\"disabled\"\n [nzAllowClear]=\"allowClear\"\n [nzShowSearch]=\"showSearch\"\n [nzMode]=\"mode\"\n [nzOptionHeightPx]=\"36\"\n [nzOptionOverflowSize]=\"10\"\n [ngModel]=\"value\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n (ngModelChange)=\"onValueChange($event)\"\n>\n @for (option of options; track option.value) {\n <nz-option\n [nzLabel]=\"option.label\"\n [nzValue]=\"option.value\"\n [nzDisabled]=\"option.disabled ?? false\"\n ></nz-option>\n }\n</nz-select>\n\n@if (error && errorMessage) {\n <p class=\"geo-select__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: [".geo-select-host{display:inline-flex;flex-direction:column;gap:8px;width:413px;max-width:100%;vertical-align:top}.geo-select-host--small{width:72px}geo-select.geo-select-host.geo-select-host--block,.geo-select-host.geo-select-host--block{display:flex;width:100%;max-width:none}.geo-select__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-select__required{color:var(--geo-color-error-default)}.geo-select__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}.geo-select{display:block;width:100%}.geo-select .ant-select-selector{border-radius:var(--geo-radius)!important;border-color:var(--geo-color-neutral-300)!important;box-shadow:none!important;padding-inline:8px!important;transition:border-color .15s ease,box-shadow .15s ease}.ant-select:not(.ant-select-customize-input) .ant-select-selector{background:transparent}.geo-select .ant-select-selection-item,.geo-select .ant-select-selection-placeholder{font-size:14px;line-height:1.4}.geo-select .ant-select-selection-placeholder{color:var(--geo-color-neutral-500)}.geo-select .ant-select-selection-item{color:var(--geo-color-neutral-900)}.geo-select .ant-select-arrow{color:var(--geo-color-neutral-500);font-size:12px}.geo-select--default .ant-select-selector{min-height:40px!important;height:40px!important}.geo-select--default .ant-select-selection-search-input{height:38px!important}.geo-select--default .ant-select-selection-item,.geo-select--default .ant-select-selection-placeholder,.geo-select--default.ant-select-multiple .ant-select-selection-item{line-height:38px!important}.geo-select--small .ant-select-selector{min-height:32px!important;height:32px!important;padding-inline:8px!important}.geo-select--small .ant-select-selection-search-input{height:30px!important}.geo-select--small .ant-select-selection-item,.geo-select--small .ant-select-selection-placeholder{line-height:30px!important}.geo-select:not(.ant-select-disabled):hover .ant-select-selector{border-color:var(--geo-color-primary-default)!important}.geo-select.ant-select-focused .ant-select-selector,.geo-select.ant-select-open .ant-select-selector{border-color:var(--geo-color-primary-default)!important;box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-primary-default) 12%,transparent)!important}.geo-select.ant-select-disabled .ant-select-selector{background:var(--geo-color-neutral-100)!important;border-color:var(--geo-color-neutral-300)!important;color:var(--geo-color-neutral-disabled-text)!important}.geo-select.ant-select-disabled .ant-select-selection-item,.geo-select.ant-select-disabled .ant-select-selection-placeholder{color:var(--geo-color-neutral-disabled-text)!important}.geo-select.ant-select-multiple .ant-select-selector{min-height:40px!important;height:auto!important;padding-block:6px!important;padding-inline:6px 8px!important}.geo-select.ant-select-multiple .ant-select-selection-item{height:28px;margin-top:0;margin-bottom:0;padding:2px 4px 2px 8px;border-radius:var(--geo-radius);border:none;background:var(--geo-color-primary-border);font-size:13px;line-height:24px!important;color:var(--geo-color-neutral-900)}.geo-select.ant-select-multiple.ant-select-disabled .ant-select-selection-item{background:var(--geo-color-neutral-100);color:var(--geo-color-neutral-disabled-text)}.geo-select.ant-select-multiple .ant-select-selection-item-remove{color:var(--geo-color-neutral-500)}.geo-select__dropdown.ant-select-dropdown{border-radius:var(--geo-radius);padding:4px;box-shadow:0 6px 16px #00000014}.geo-select__dropdown .ant-select-item{min-height:36px;padding:8px 12px;border-radius:var(--geo-radius);font-size:14px;line-height:20px;color:var(--geo-color-neutral-900)}.geo-select__dropdown .ant-select-item-option-active:not(.ant-select-item-option-disabled){background:var(--color-primary-surface-hover, var(--geo-color-primary-background))}.geo-select__dropdown .ant-select-item-option-selected:not(.ant-select-item-option-disabled){background:var(--color-primary-surface, var(--geo-color-primary-surface-light));color:var(--geo-color-primary-default);font-weight:500}.geo-select__dropdown .ant-select-item-option-selected .ant-select-item-option-state{color:var(--geo-color-primary-default)}.geo-select__dropdown .ant-select-item-empty{padding:8px 12px;color:var(--color-ink-muted, var(--geo-color-neutral-500));font-size:14px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NgZorroAntdModule }, { kind: "component", type: i3$3.NzOptionComponent, selector: "nz-option", inputs: ["nzTitle", "nzLabel", "nzValue", "nzKey", "nzDisabled", "nzHide", "nzCustomContent"], exportAs: ["nzOption"] }, { kind: "component", type: i3$3.NzSelectComponent, selector: "nz-select", inputs: ["nzId", "nzSize", "nzStatus", "nzOptionHeightPx", "nzOptionOverflowSize", "nzDropdownClassName", "nzDropdownMatchSelectWidth", "nzDropdownStyle", "nzNotFoundContent", "nzPlaceHolder", "nzPlacement", "nzMaxTagCount", "nzDropdownRender", "nzCustomTemplate", "nzSuffixIcon", "nzClearIcon", "nzRemoveIcon", "nzMenuItemSelectedIcon", "nzTokenSeparators", "nzMaxTagPlaceholder", "nzMaxMultipleCount", "nzMode", "nzFilterOption", "compareWith", "nzAllowClear", "nzBorderless", "nzShowSearch", "nzLoading", "nzAutoFocus", "nzAutoClearSearchValue", "nzServerSearch", "nzDisabled", "nzOpen", "nzSelectOnTab", "nzBackdrop", "nzOptions", "nzShowArrow"], outputs: ["nzOnSearch", "nzScrollToBottom", "nzOpenChange", "nzBlur", "nzFocus"], exportAs: ["nzSelect"] }], encapsulation: i0.ViewEncapsulation.None });
2110
+ }
2111
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoSelectComponent, decorators: [{
2112
+ type: Component,
2113
+ args: [{ selector: 'geo-select', standalone: true, imports: [CommonModule, FormsModule, NgZorroAntdModule], encapsulation: ViewEncapsulation.None, host: {
2114
+ class: 'geo-select-host',
2115
+ '[class.geo-select-host--default]': 'size === "default"',
2116
+ '[class.geo-select-host--small]': 'size === "small"',
2117
+ '[class.geo-select-host--block]': 'block',
2118
+ '[class.geo-select-host--error]': 'error',
2119
+ '[style.width]': 'hostWidth',
2120
+ }, providers: [
2121
+ {
2122
+ provide: NG_VALUE_ACCESSOR,
2123
+ useExisting: forwardRef(() => GeoSelectComponent),
2124
+ multi: true,
2125
+ },
2126
+ ], template: "@if (label) {\n <div class=\"geo-select__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-select__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<nz-select\n [ngClass]=\"controlClassNames\"\n nzDropdownClassName=\"geo-select__dropdown\"\n [nzPlaceHolder]=\"placeholder\"\n [nzDisabled]=\"disabled\"\n [nzAllowClear]=\"allowClear\"\n [nzShowSearch]=\"showSearch\"\n [nzMode]=\"mode\"\n [nzOptionHeightPx]=\"36\"\n [nzOptionOverflowSize]=\"10\"\n [ngModel]=\"value\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n (ngModelChange)=\"onValueChange($event)\"\n>\n @for (option of options; track option.value) {\n <nz-option\n [nzLabel]=\"option.label\"\n [nzValue]=\"option.value\"\n [nzDisabled]=\"option.disabled ?? false\"\n ></nz-option>\n }\n</nz-select>\n\n@if (error && errorMessage) {\n <p class=\"geo-select__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: [".geo-select-host{display:inline-flex;flex-direction:column;gap:8px;width:413px;max-width:100%;vertical-align:top}.geo-select-host--small{width:72px}geo-select.geo-select-host.geo-select-host--block,.geo-select-host.geo-select-host--block{display:flex;width:100%;max-width:none}.geo-select__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-select__required{color:var(--geo-color-error-default)}.geo-select__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}.geo-select{display:block;width:100%}.geo-select .ant-select-selector{border-radius:var(--geo-radius)!important;border-color:var(--geo-color-neutral-300)!important;box-shadow:none!important;padding-inline:8px!important;transition:border-color .15s ease,box-shadow .15s ease}.ant-select:not(.ant-select-customize-input) .ant-select-selector{background:transparent}.geo-select .ant-select-selection-item,.geo-select .ant-select-selection-placeholder{font-size:14px;line-height:1.4}.geo-select .ant-select-selection-placeholder{color:var(--geo-color-neutral-500)}.geo-select .ant-select-selection-item{color:var(--geo-color-neutral-900)}.geo-select .ant-select-arrow{color:var(--geo-color-neutral-500);font-size:12px}.geo-select--default .ant-select-selector{min-height:40px!important;height:40px!important}.geo-select--default .ant-select-selection-search-input{height:38px!important}.geo-select--default .ant-select-selection-item,.geo-select--default .ant-select-selection-placeholder,.geo-select--default.ant-select-multiple .ant-select-selection-item{line-height:38px!important}.geo-select--small .ant-select-selector{min-height:32px!important;height:32px!important;padding-inline:8px!important}.geo-select--small .ant-select-selection-search-input{height:30px!important}.geo-select--small .ant-select-selection-item,.geo-select--small .ant-select-selection-placeholder{line-height:30px!important}.geo-select:not(.ant-select-disabled):hover .ant-select-selector{border-color:var(--geo-color-primary-default)!important}.geo-select.ant-select-focused .ant-select-selector,.geo-select.ant-select-open .ant-select-selector{border-color:var(--geo-color-primary-default)!important;box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-primary-default) 12%,transparent)!important}.geo-select.ant-select-disabled .ant-select-selector{background:var(--geo-color-neutral-100)!important;border-color:var(--geo-color-neutral-300)!important;color:var(--geo-color-neutral-disabled-text)!important}.geo-select.ant-select-disabled .ant-select-selection-item,.geo-select.ant-select-disabled .ant-select-selection-placeholder{color:var(--geo-color-neutral-disabled-text)!important}.geo-select.ant-select-multiple .ant-select-selector{min-height:40px!important;height:auto!important;padding-block:6px!important;padding-inline:6px 8px!important}.geo-select.ant-select-multiple .ant-select-selection-item{height:28px;margin-top:0;margin-bottom:0;padding:2px 4px 2px 8px;border-radius:var(--geo-radius);border:none;background:var(--geo-color-primary-border);font-size:13px;line-height:24px!important;color:var(--geo-color-neutral-900)}.geo-select.ant-select-multiple.ant-select-disabled .ant-select-selection-item{background:var(--geo-color-neutral-100);color:var(--geo-color-neutral-disabled-text)}.geo-select.ant-select-multiple .ant-select-selection-item-remove{color:var(--geo-color-neutral-500)}.geo-select__dropdown.ant-select-dropdown{border-radius:var(--geo-radius);padding:4px;box-shadow:0 6px 16px #00000014}.geo-select__dropdown .ant-select-item{min-height:36px;padding:8px 12px;border-radius:var(--geo-radius);font-size:14px;line-height:20px;color:var(--geo-color-neutral-900)}.geo-select__dropdown .ant-select-item-option-active:not(.ant-select-item-option-disabled){background:var(--color-primary-surface-hover, var(--geo-color-primary-background))}.geo-select__dropdown .ant-select-item-option-selected:not(.ant-select-item-option-disabled){background:var(--color-primary-surface, var(--geo-color-primary-surface-light));color:var(--geo-color-primary-default);font-weight:500}.geo-select__dropdown .ant-select-item-option-selected .ant-select-item-option-state{color:var(--geo-color-primary-default)}.geo-select__dropdown .ant-select-item-empty{padding:8px 12px;color:var(--color-ink-muted, var(--geo-color-neutral-500));font-size:14px}\n"] }]
2127
+ }], propDecorators: { options: [{
2128
+ type: Input
2129
+ }], label: [{
2130
+ type: Input
2131
+ }], placeholder: [{
2132
+ type: Input
2133
+ }], size: [{
2134
+ type: Input
2135
+ }], mode: [{
2136
+ type: Input
2137
+ }], disabled: [{
2138
+ type: Input
2139
+ }], required: [{
2140
+ type: Input
2141
+ }], error: [{
2142
+ type: Input
2143
+ }], errorMessage: [{
2144
+ type: Input
2145
+ }], allowClear: [{
2146
+ type: Input
2147
+ }], showSearch: [{
2148
+ type: Input
2149
+ }], block: [{
2150
+ type: Input
2151
+ }], width: [{
2152
+ type: Input
2153
+ }], valueChange: [{
2154
+ type: Output
2155
+ }] } });
2156
+
2157
+ /**
2158
+ * Slider (opacity / range) — wrap `nz-slider`. Domain dùng `geo-slider`, không import NzSliderModule.
2159
+ */
2160
+ class GeoSliderComponent {
2161
+ value = 0;
2162
+ min = 0;
2163
+ max = 100;
2164
+ step = 1;
2165
+ disabled = false;
2166
+ tipFormatter;
2167
+ valueChange = new EventEmitter();
2168
+ onChange(next) {
2169
+ this.value = next;
2170
+ this.valueChange.emit(next);
2171
+ }
2172
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoSliderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2173
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: GeoSliderComponent, isStandalone: true, selector: "geo-slider", inputs: { value: "value", min: "min", max: "max", step: "step", disabled: "disabled", tipFormatter: "tipFormatter" }, outputs: { valueChange: "valueChange" }, host: { classAttribute: "geo-slider-host" }, ngImport: i0, template: "<div class=\"geo-slider\">\n <nz-slider\n [ngModel]=\"value\"\n (ngModelChange)=\"onChange($event)\"\n [nzMin]=\"min\"\n [nzMax]=\"max\"\n [nzStep]=\"step\"\n [nzDisabled]=\"disabled\"\n [nzTipFormatter]=\"tipFormatter\"\n ></nz-slider>\n</div>\n", styles: [".geo-slider-host{display:block;width:100%}.geo-slider{width:100%;padding:0 4px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NzSliderModule }, { kind: "component", type: i2$3.NzSliderComponent, selector: "nz-slider", inputs: ["nzDisabled", "nzDots", "nzIncluded", "nzRange", "nzVertical", "nzReverse", "nzDefaultValue", "nzMarks", "nzMax", "nzMin", "nzStep", "nzTooltipVisible", "nzTooltipPlacement", "nzTipFormatter"], outputs: ["nzOnAfterChange"], exportAs: ["nzSlider"] }], encapsulation: i0.ViewEncapsulation.None });
2174
+ }
2175
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoSliderComponent, decorators: [{
2176
+ type: Component,
2177
+ args: [{ selector: 'geo-slider', standalone: true, imports: [FormsModule, NzSliderModule], encapsulation: ViewEncapsulation.None, host: { class: 'geo-slider-host' }, template: "<div class=\"geo-slider\">\n <nz-slider\n [ngModel]=\"value\"\n (ngModelChange)=\"onChange($event)\"\n [nzMin]=\"min\"\n [nzMax]=\"max\"\n [nzStep]=\"step\"\n [nzDisabled]=\"disabled\"\n [nzTipFormatter]=\"tipFormatter\"\n ></nz-slider>\n</div>\n", styles: [".geo-slider-host{display:block;width:100%}.geo-slider{width:100%;padding:0 4px}\n"] }]
2178
+ }], propDecorators: { value: [{
2179
+ type: Input
2180
+ }], min: [{
2181
+ type: Input
2182
+ }], max: [{
2183
+ type: Input
2184
+ }], step: [{
2185
+ type: Input
2186
+ }], disabled: [{
2187
+ type: Input
2188
+ }], tipFormatter: [{
2189
+ type: Input
2190
+ }], valueChange: [{
2191
+ type: Output
2192
+ }] } });
2193
+
2194
+ /** Map legacy / alias presets → semantic color. */
2195
+ const GEO_STATUS_COLOR_MAP = {
2196
+ success: 'success',
2197
+ primary: 'primary',
2198
+ error: 'error',
2199
+ warning: 'warning',
2200
+ info: 'info',
2201
+ teal: 'teal',
2202
+ neutral: 'neutral',
2203
+ completed: 'success',
2204
+ cancelled: 'error',
2205
+ in_progress: 'primary',
2206
+ adjusting: 'warning',
2207
+ };
2208
+ const GEO_STATUS_LABELS = {
2209
+ success: 'Sẵn sàng',
2210
+ primary: 'Đang mượn',
2211
+ error: 'Từ chối',
2212
+ warning: 'Bản nháp',
2213
+ info: 'Đã nộp',
2214
+ teal: 'Trả kết quả',
2215
+ neutral: 'Chưa xử lý',
2216
+ completed: 'Hoàn thành',
2217
+ cancelled: 'Hủy bỏ',
2218
+ in_progress: 'Đang thực hiện',
2219
+ adjusting: 'Đang điều chỉnh',
2220
+ };
2221
+ /** @deprecated Use GEO_STATUS_LABELS */
2222
+ const UI_STATUS_LABELS = GEO_STATUS_LABELS;
2223
+
2224
+ class GeoStatusTagComponent {
2225
+ /**
2226
+ * Status preset or free-form string.
2227
+ * Semantic: success | primary | error | warning | info | teal | neutral
2228
+ * Legacy: completed | cancelled | in_progress | adjusting
2229
+ */
2230
+ status = 'success';
2231
+ /** Override label text. */
2232
+ label;
2233
+ /** Show leading status dot (design default). */
2234
+ showDot = true;
2235
+ get resolvedColor() {
2236
+ if (this.status in GEO_STATUS_COLOR_MAP) {
2237
+ return GEO_STATUS_COLOR_MAP[this.status];
2238
+ }
2239
+ const normalized = this.status
2240
+ .toLowerCase()
2241
+ .replace(/\s+/g, '_')
2242
+ .normalize('NFD')
2243
+ .replace(/[\u0300-\u036f]/g, '');
2244
+ if (normalized.includes('san_sang') || normalized.includes('hoan'))
2245
+ return 'success';
2246
+ if (normalized.includes('tu_choi') || normalized.includes('huy'))
2247
+ return 'error';
2248
+ if (normalized.includes('ban_thao') || normalized.includes('dieu_chinh'))
2249
+ return 'warning';
2250
+ if (normalized.includes('da_nop') || normalized.includes('nop'))
2251
+ return 'info';
2252
+ if (normalized.includes('tra_ket_qua') || normalized.includes('ket_qua'))
2253
+ return 'teal';
2254
+ if (normalized.includes('chua_xu_ly') || normalized.includes('cho'))
2255
+ return 'neutral';
2256
+ if (normalized.includes('muon') || normalized.includes('thuc_hien'))
2257
+ return 'primary';
2258
+ return 'primary';
2259
+ }
2260
+ get displayLabel() {
2261
+ if (this.label)
2262
+ return this.label;
2263
+ if (this.status in GEO_STATUS_LABELS) {
2264
+ return GEO_STATUS_LABELS[this.status];
2265
+ }
2266
+ return this.status;
2267
+ }
2268
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoStatusTagComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2269
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoStatusTagComponent, isStandalone: true, selector: "geo-status-tag", inputs: { status: "status", label: "label", showDot: "showDot" }, ngImport: i0, template: "<span\n class=\"geo-status-tag\"\n [class]=\"'geo-status-tag geo-status-tag--' + resolvedColor\"\n>\n @if (showDot) {\n <span class=\"geo-status-tag__dot\" aria-hidden=\"true\"></span>\n }\n <span class=\"geo-status-tag__label\">{{ displayLabel }}</span>\n</span>\n", styles: ["@charset \"UTF-8\";.geo-status-tag{display:inline-flex;align-items:center;gap:6px;box-sizing:border-box;min-height:24px;padding:4px 12px;border:1px solid transparent;border-radius:999px;font-family:var(--geo-font-family);font-size:var(--geo-font-size-caption);font-weight:var(--geo-font-weight-medium);line-height:var(--geo-line-height-caption);white-space:nowrap;vertical-align:middle}.geo-status-tag__dot{flex-shrink:0;width:6px;height:6px;border-radius:50%}.geo-status-tag__label{display:inline-flex;align-items:center}.geo-status-tag--success{background:var(--geo-color-success-light);border-color:color-mix(in srgb,var(--geo-color-success-default) 45%,var(--geo-color-success-light));color:var(--geo-color-success-dark)}.geo-status-tag--success .geo-status-tag__dot{background:var(--geo-color-success-dark)}.geo-status-tag--primary{background:var(--geo-color-primary-surface-light);border-color:var(--geo-color-primary-border);color:var(--geo-color-primary-default)}.geo-status-tag--primary .geo-status-tag__dot{background:var(--geo-color-primary-default)}.geo-status-tag--error{background:var(--geo-color-error-light);border-color:color-mix(in srgb,var(--geo-color-error-default) 40%,var(--geo-color-error-light));color:var(--geo-color-error-dark)}.geo-status-tag--error .geo-status-tag__dot{background:var(--geo-color-error-dark)}.geo-status-tag--warning{background:var(--geo-color-warning-light);border-color:color-mix(in srgb,var(--geo-color-warning-default) 45%,var(--geo-color-warning-light));color:var(--geo-color-warning-dark)}.geo-status-tag--warning .geo-status-tag__dot{background:var(--geo-color-warning-dark)}.geo-status-tag--info{background:var(--geo-color-info-light);border-color:color-mix(in srgb,var(--geo-color-info-default) 40%,var(--geo-color-info-light));color:var(--geo-color-info-dark)}.geo-status-tag--info .geo-status-tag__dot{background:var(--geo-color-info-dark)}.geo-status-tag--teal{background:var(--geo-color-teal-light);border-color:color-mix(in srgb,var(--geo-color-teal-default) 40%,var(--geo-color-teal-light));color:var(--geo-color-teal-dark)}.geo-status-tag--teal .geo-status-tag__dot{background:var(--geo-color-teal-dark)}.geo-status-tag--neutral{background:var(--geo-color-neutral-100);border-color:var(--geo-color-neutral-300);color:var(--geo-color-neutral-800)}.geo-status-tag--neutral .geo-status-tag__dot{background:var(--geo-color-neutral-800)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
2270
+ }
2271
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoStatusTagComponent, decorators: [{
2272
+ type: Component,
2273
+ args: [{ selector: 'geo-status-tag', standalone: true, imports: [CommonModule], template: "<span\n class=\"geo-status-tag\"\n [class]=\"'geo-status-tag geo-status-tag--' + resolvedColor\"\n>\n @if (showDot) {\n <span class=\"geo-status-tag__dot\" aria-hidden=\"true\"></span>\n }\n <span class=\"geo-status-tag__label\">{{ displayLabel }}</span>\n</span>\n", styles: ["@charset \"UTF-8\";.geo-status-tag{display:inline-flex;align-items:center;gap:6px;box-sizing:border-box;min-height:24px;padding:4px 12px;border:1px solid transparent;border-radius:999px;font-family:var(--geo-font-family);font-size:var(--geo-font-size-caption);font-weight:var(--geo-font-weight-medium);line-height:var(--geo-line-height-caption);white-space:nowrap;vertical-align:middle}.geo-status-tag__dot{flex-shrink:0;width:6px;height:6px;border-radius:50%}.geo-status-tag__label{display:inline-flex;align-items:center}.geo-status-tag--success{background:var(--geo-color-success-light);border-color:color-mix(in srgb,var(--geo-color-success-default) 45%,var(--geo-color-success-light));color:var(--geo-color-success-dark)}.geo-status-tag--success .geo-status-tag__dot{background:var(--geo-color-success-dark)}.geo-status-tag--primary{background:var(--geo-color-primary-surface-light);border-color:var(--geo-color-primary-border);color:var(--geo-color-primary-default)}.geo-status-tag--primary .geo-status-tag__dot{background:var(--geo-color-primary-default)}.geo-status-tag--error{background:var(--geo-color-error-light);border-color:color-mix(in srgb,var(--geo-color-error-default) 40%,var(--geo-color-error-light));color:var(--geo-color-error-dark)}.geo-status-tag--error .geo-status-tag__dot{background:var(--geo-color-error-dark)}.geo-status-tag--warning{background:var(--geo-color-warning-light);border-color:color-mix(in srgb,var(--geo-color-warning-default) 45%,var(--geo-color-warning-light));color:var(--geo-color-warning-dark)}.geo-status-tag--warning .geo-status-tag__dot{background:var(--geo-color-warning-dark)}.geo-status-tag--info{background:var(--geo-color-info-light);border-color:color-mix(in srgb,var(--geo-color-info-default) 40%,var(--geo-color-info-light));color:var(--geo-color-info-dark)}.geo-status-tag--info .geo-status-tag__dot{background:var(--geo-color-info-dark)}.geo-status-tag--teal{background:var(--geo-color-teal-light);border-color:color-mix(in srgb,var(--geo-color-teal-default) 40%,var(--geo-color-teal-light));color:var(--geo-color-teal-dark)}.geo-status-tag--teal .geo-status-tag__dot{background:var(--geo-color-teal-dark)}.geo-status-tag--neutral{background:var(--geo-color-neutral-100);border-color:var(--geo-color-neutral-300);color:var(--geo-color-neutral-800)}.geo-status-tag--neutral .geo-status-tag__dot{background:var(--geo-color-neutral-800)}\n"] }]
2274
+ }], propDecorators: { status: [{
2275
+ type: Input
2276
+ }], label: [{
2277
+ type: Input
2278
+ }], showDot: [{
2279
+ type: Input
2280
+ }] } });
2281
+
2282
+ /**
2283
+ * Steps / Stepper GEO — horizontal (mặc định) hoặc vertical.
2284
+ *
2285
+ * Custom qua `steps`, `activeIndex`, `orientation`, `clickable`.
2286
+ * Trong form modal: đặt `<geo-stepper>` vào body (content projection).
2287
+ *
2288
+ * @example
2289
+ * ```html
2290
+ * <geo-stepper
2291
+ * [steps]="[
2292
+ * { key: 'a', label: 'Bước 1' },
2293
+ * { key: 'b', label: 'Bước 2' }
2294
+ * ]"
2295
+ * [activeIndex]="0"
2296
+ * orientation="horizontal"
2297
+ * (activeIndexChange)="onStep($event)"
2298
+ * ></geo-stepper>
2299
+ * ```
2300
+ */
2301
+ class GeoStepperComponent {
2302
+ steps = [];
2303
+ activeIndex = 0;
2304
+ /** Mặc định horizontal theo design form modal. */
2305
+ orientation = 'horizontal';
2306
+ /** Cho phép click để đổi bước. */
2307
+ clickable = true;
2308
+ activeIndexChange = new EventEmitter();
2309
+ stepSelect = new EventEmitter();
2310
+ trackByIndex(index) {
2311
+ return index;
2312
+ }
2313
+ isActive(index) {
2314
+ return index === this.activeIndex;
2315
+ }
2316
+ isCompleted(index) {
2317
+ return index < this.activeIndex;
2318
+ }
2319
+ isPending(index) {
2320
+ return index > this.activeIndex;
2321
+ }
2322
+ onSelect(index, step) {
2323
+ if (!this.clickable || step.disabled || index === this.activeIndex) {
2324
+ return;
2325
+ }
2326
+ this.activeIndex = index;
2327
+ this.activeIndexChange.emit(index);
2328
+ this.stepSelect.emit({ index, step });
2329
+ }
2330
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoStepperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2331
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoStepperComponent, isStandalone: true, selector: "geo-stepper", inputs: { steps: "steps", activeIndex: "activeIndex", orientation: "orientation", clickable: "clickable" }, outputs: { activeIndexChange: "activeIndexChange", stepSelect: "stepSelect" }, host: { properties: { "class.geo-stepper-host--vertical": "orientation === \"vertical\"", "class.geo-stepper-host--horizontal": "orientation === \"horizontal\"" }, classAttribute: "geo-stepper-host" }, ngImport: i0, template: "<nav class=\"geo-stepper\" [attr.aria-label]=\"'C\u00E1c b\u01B0\u1EDBc'\">\n <ol class=\"geo-stepper__list\">\n @for (step of steps; track trackByIndex($index); let i = $index; let last = $last) {\n <li\n class=\"geo-stepper__item\"\n [class.geo-stepper__item--active]=\"isActive(i)\"\n [class.geo-stepper__item--completed]=\"isCompleted(i)\"\n [class.geo-stepper__item--pending]=\"isPending(i)\"\n [class.geo-stepper__item--disabled]=\"step.disabled\"\n [class.geo-stepper__item--last]=\"last\"\n >\n <button\n type=\"button\"\n class=\"geo-stepper__button\"\n [disabled]=\"!clickable || step.disabled\"\n [attr.aria-current]=\"isActive(i) ? 'step' : null\"\n (click)=\"onSelect(i, step)\"\n >\n <span class=\"geo-stepper__index\" aria-hidden=\"true\">\n @if (isCompleted(i)) {\n <span nz-icon nzType=\"check\" nzTheme=\"outline\"></span>\n } @else {\n {{ i + 1 }}\n }\n </span>\n <span class=\"geo-stepper__label\">{{ step.label }}</span>\n </button>\n\n @if (!last) {\n <span\n class=\"geo-stepper__connector\"\n [class.geo-stepper__connector--done]=\"isCompleted(i)\"\n aria-hidden=\"true\"\n ></span>\n }\n </li>\n }\n </ol>\n</nav>\n", styles: ["@charset \"UTF-8\";.geo-stepper-host{display:block;width:100%;font-family:var(--geo-font-family)}.geo-stepper__list{list-style:none;margin:0;padding:0;display:flex;align-items:center}.geo-stepper-host--horizontal{display:flex;justify-content:center;width:100%}.geo-stepper-host--horizontal .geo-stepper__list{flex-direction:row;flex-wrap:nowrap;justify-content:center;align-items:center;gap:0;width:auto;max-width:100%}.geo-stepper-host--horizontal .geo-stepper__item{display:flex;align-items:center;flex:0 0 auto;min-width:0}.geo-stepper-host--horizontal .geo-stepper__connector{flex:0 0 auto;width:48px;height:1px;margin:0 16px;background:var(--geo-color-neutral-300)}.geo-stepper-host--horizontal .geo-stepper__connector--done{background:var(--geo-color-success-default)}.geo-stepper-host--vertical .geo-stepper__list{flex-direction:column;align-items:stretch;gap:0;width:100%}.geo-stepper-host--vertical .geo-stepper__item{display:flex;flex-direction:column;align-items:flex-start;min-width:0}.geo-stepper-host--vertical .geo-stepper__connector{display:block;width:1px;height:20px;margin:6px 0 6px 15px;background:var(--geo-color-neutral-300)}.geo-stepper-host--vertical .geo-stepper__connector--done{background:var(--geo-color-success-default)}.geo-stepper__button{display:inline-flex;align-items:center;gap:10px;padding:0;border:none;background:transparent;cursor:pointer;font-family:inherit;text-align:left;color:var(--geo-color-neutral-500);flex-shrink:0;max-width:100%}.geo-stepper__button:disabled{cursor:default}.geo-stepper__item--disabled .geo-stepper__button{opacity:.5;cursor:not-allowed}.geo-stepper__index{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;flex-shrink:0;border:1.5px solid var(--geo-color-neutral-300);border-radius:50%;font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-semibold);line-height:1;color:var(--geo-color-neutral-500);background:var(--geo-color-neutral-white);box-sizing:border-box}.geo-stepper__index .anticon{font-size:14px}.geo-stepper__label{font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-body);color:var(--geo-color-neutral-500);white-space:nowrap}.geo-stepper__item--active .geo-stepper__index{border-color:var(--geo-color-primary-default);background:var(--geo-color-primary-default);color:var(--geo-color-neutral-white)}.geo-stepper__item--active .geo-stepper__label{color:var(--geo-color-primary-default);font-weight:var(--geo-font-weight-semibold)}.geo-stepper__item--completed .geo-stepper__index{border-color:var(--geo-color-success-default);background:var(--geo-color-success-default);color:var(--geo-color-neutral-white)}.geo-stepper__item--completed .geo-stepper__label{color:var(--geo-color-success-default);font-weight:var(--geo-font-weight-medium)}.geo-stepper__button:not(:disabled):hover .geo-stepper__label{color:var(--geo-color-primary-default)}.geo-stepper__item--completed .geo-stepper__button:not(:disabled):hover .geo-stepper__label{color:var(--geo-color-success-dark)}@media (max-width: 767.98px){.geo-stepper-host--horizontal .geo-stepper__list{flex-wrap:wrap;row-gap:12px;justify-content:center}.geo-stepper-host--horizontal .geo-stepper__label{white-space:normal;max-width:140px}.geo-stepper-host--horizontal .geo-stepper__connector{width:24px;margin:0 10px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2332
+ }
2333
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoStepperComponent, decorators: [{
2334
+ type: Component,
2335
+ args: [{ selector: 'geo-stepper', standalone: true, imports: [CommonModule, NzIconModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
2336
+ class: 'geo-stepper-host',
2337
+ '[class.geo-stepper-host--vertical]': 'orientation === "vertical"',
2338
+ '[class.geo-stepper-host--horizontal]': 'orientation === "horizontal"',
2339
+ }, template: "<nav class=\"geo-stepper\" [attr.aria-label]=\"'C\u00E1c b\u01B0\u1EDBc'\">\n <ol class=\"geo-stepper__list\">\n @for (step of steps; track trackByIndex($index); let i = $index; let last = $last) {\n <li\n class=\"geo-stepper__item\"\n [class.geo-stepper__item--active]=\"isActive(i)\"\n [class.geo-stepper__item--completed]=\"isCompleted(i)\"\n [class.geo-stepper__item--pending]=\"isPending(i)\"\n [class.geo-stepper__item--disabled]=\"step.disabled\"\n [class.geo-stepper__item--last]=\"last\"\n >\n <button\n type=\"button\"\n class=\"geo-stepper__button\"\n [disabled]=\"!clickable || step.disabled\"\n [attr.aria-current]=\"isActive(i) ? 'step' : null\"\n (click)=\"onSelect(i, step)\"\n >\n <span class=\"geo-stepper__index\" aria-hidden=\"true\">\n @if (isCompleted(i)) {\n <span nz-icon nzType=\"check\" nzTheme=\"outline\"></span>\n } @else {\n {{ i + 1 }}\n }\n </span>\n <span class=\"geo-stepper__label\">{{ step.label }}</span>\n </button>\n\n @if (!last) {\n <span\n class=\"geo-stepper__connector\"\n [class.geo-stepper__connector--done]=\"isCompleted(i)\"\n aria-hidden=\"true\"\n ></span>\n }\n </li>\n }\n </ol>\n</nav>\n", styles: ["@charset \"UTF-8\";.geo-stepper-host{display:block;width:100%;font-family:var(--geo-font-family)}.geo-stepper__list{list-style:none;margin:0;padding:0;display:flex;align-items:center}.geo-stepper-host--horizontal{display:flex;justify-content:center;width:100%}.geo-stepper-host--horizontal .geo-stepper__list{flex-direction:row;flex-wrap:nowrap;justify-content:center;align-items:center;gap:0;width:auto;max-width:100%}.geo-stepper-host--horizontal .geo-stepper__item{display:flex;align-items:center;flex:0 0 auto;min-width:0}.geo-stepper-host--horizontal .geo-stepper__connector{flex:0 0 auto;width:48px;height:1px;margin:0 16px;background:var(--geo-color-neutral-300)}.geo-stepper-host--horizontal .geo-stepper__connector--done{background:var(--geo-color-success-default)}.geo-stepper-host--vertical .geo-stepper__list{flex-direction:column;align-items:stretch;gap:0;width:100%}.geo-stepper-host--vertical .geo-stepper__item{display:flex;flex-direction:column;align-items:flex-start;min-width:0}.geo-stepper-host--vertical .geo-stepper__connector{display:block;width:1px;height:20px;margin:6px 0 6px 15px;background:var(--geo-color-neutral-300)}.geo-stepper-host--vertical .geo-stepper__connector--done{background:var(--geo-color-success-default)}.geo-stepper__button{display:inline-flex;align-items:center;gap:10px;padding:0;border:none;background:transparent;cursor:pointer;font-family:inherit;text-align:left;color:var(--geo-color-neutral-500);flex-shrink:0;max-width:100%}.geo-stepper__button:disabled{cursor:default}.geo-stepper__item--disabled .geo-stepper__button{opacity:.5;cursor:not-allowed}.geo-stepper__index{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;flex-shrink:0;border:1.5px solid var(--geo-color-neutral-300);border-radius:50%;font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-semibold);line-height:1;color:var(--geo-color-neutral-500);background:var(--geo-color-neutral-white);box-sizing:border-box}.geo-stepper__index .anticon{font-size:14px}.geo-stepper__label{font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-body);color:var(--geo-color-neutral-500);white-space:nowrap}.geo-stepper__item--active .geo-stepper__index{border-color:var(--geo-color-primary-default);background:var(--geo-color-primary-default);color:var(--geo-color-neutral-white)}.geo-stepper__item--active .geo-stepper__label{color:var(--geo-color-primary-default);font-weight:var(--geo-font-weight-semibold)}.geo-stepper__item--completed .geo-stepper__index{border-color:var(--geo-color-success-default);background:var(--geo-color-success-default);color:var(--geo-color-neutral-white)}.geo-stepper__item--completed .geo-stepper__label{color:var(--geo-color-success-default);font-weight:var(--geo-font-weight-medium)}.geo-stepper__button:not(:disabled):hover .geo-stepper__label{color:var(--geo-color-primary-default)}.geo-stepper__item--completed .geo-stepper__button:not(:disabled):hover .geo-stepper__label{color:var(--geo-color-success-dark)}@media (max-width: 767.98px){.geo-stepper-host--horizontal .geo-stepper__list{flex-wrap:wrap;row-gap:12px;justify-content:center}.geo-stepper-host--horizontal .geo-stepper__label{white-space:normal;max-width:140px}.geo-stepper-host--horizontal .geo-stepper__connector{width:24px;margin:0 10px}}\n"] }]
2340
+ }], propDecorators: { steps: [{
2341
+ type: Input
2342
+ }], activeIndex: [{
2343
+ type: Input
2344
+ }], orientation: [{
2345
+ type: Input
2346
+ }], clickable: [{
2347
+ type: Input
2348
+ }], activeIndexChange: [{
2349
+ type: Output
2350
+ }], stepSelect: [{
2351
+ type: Output
2352
+ }] } });
2353
+
2354
+ /**
2355
+ * Layout form page multi-step: cột trái stepper + cột phải form card.
2356
+ *
2357
+ * ```html
2358
+ * <geo-step-form-layout
2359
+ * title="Thêm mới ..."
2360
+ * [steps]="steps"
2361
+ * [activeIndex]="activeIndex"
2362
+ * [showScrollButtons]="true"
2363
+ * (cancel)="onCancel()"
2364
+ * (save)="onSave()"
2365
+ * (next)="onNext()"
2366
+ * >
2367
+ * <form>...</form>
2368
+ * </geo-step-form-layout>
2369
+ * ```
2370
+ */
2371
+ class GeoStepFormLayoutComponent {
2372
+ steps = [];
2373
+ activeIndex = 0;
2374
+ title = '';
2375
+ clickableSteps = true;
2376
+ /** Hiện nút ↑/↓ góc phải card (chuyển bước). Mặc định `true`. */
2377
+ showScrollButtons = true;
2378
+ showCancel = true;
2379
+ showPrevious = true;
2380
+ showSave = true;
2381
+ showNext = true;
2382
+ cancelLabel = 'Hủy';
2383
+ previousLabel = 'Trở lại';
2384
+ saveLabel = 'Lưu';
2385
+ nextLabel = 'Tiếp theo';
2386
+ finishLabel = 'Hoàn thành';
2387
+ saveLoading = false;
2388
+ nextLoading = false;
2389
+ /** Ẩn footer actions (dùng slot `[footer]` hoặc không cần nút). */
2390
+ hideDefaultFooter = false;
2391
+ activeIndexChange = new EventEmitter();
2392
+ stepSelect = new EventEmitter();
2393
+ cancel = new EventEmitter();
2394
+ previous = new EventEmitter();
2395
+ save = new EventEmitter();
2396
+ next = new EventEmitter();
2397
+ get isLastStep() {
2398
+ return this.steps.length > 0 && this.activeIndex >= this.steps.length - 1;
2399
+ }
2400
+ get canGoPreviousStep() {
2401
+ return this.findAdjacentStepIndex(-1) != null;
2402
+ }
2403
+ get canGoNextStep() {
2404
+ return this.findAdjacentStepIndex(1) != null;
2405
+ }
2406
+ get resolvedNextLabel() {
2407
+ return this.isLastStep ? this.finishLabel : this.nextLabel;
2408
+ }
2409
+ onActiveIndexChange(index) {
2410
+ this.activeIndex = index;
2411
+ this.activeIndexChange.emit(index);
2412
+ }
2413
+ onStepSelect(event) {
2414
+ this.stepSelect.emit(event);
2415
+ }
2416
+ onCancel() {
2417
+ this.cancel.emit();
2418
+ }
2419
+ onPrevious() {
2420
+ this.previous.emit();
2421
+ }
2422
+ onSave() {
2423
+ this.save.emit();
2424
+ }
2425
+ onNext() {
2426
+ this.next.emit();
2427
+ }
2428
+ goAdjacentStep(direction) {
2429
+ const delta = direction === 'up' ? -1 : 1;
2430
+ const nextIndex = this.findAdjacentStepIndex(delta);
2431
+ if (nextIndex == null)
2432
+ return;
2433
+ const step = this.steps[nextIndex];
2434
+ this.activeIndex = nextIndex;
2435
+ this.activeIndexChange.emit(nextIndex);
2436
+ this.stepSelect.emit({ index: nextIndex, step });
2437
+ }
2438
+ findAdjacentStepIndex(delta) {
2439
+ let index = this.activeIndex + delta;
2440
+ while (index >= 0 && index < this.steps.length) {
2441
+ if (!this.steps[index]?.disabled) {
2442
+ return index;
2443
+ }
2444
+ index += delta;
2445
+ }
2446
+ return null;
2447
+ }
2448
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoStepFormLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2449
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoStepFormLayoutComponent, isStandalone: true, selector: "geo-step-form-layout", inputs: { steps: "steps", activeIndex: "activeIndex", title: "title", clickableSteps: "clickableSteps", showScrollButtons: "showScrollButtons", showCancel: "showCancel", showPrevious: "showPrevious", showSave: "showSave", showNext: "showNext", cancelLabel: "cancelLabel", previousLabel: "previousLabel", saveLabel: "saveLabel", nextLabel: "nextLabel", finishLabel: "finishLabel", saveLoading: "saveLoading", nextLoading: "nextLoading", hideDefaultFooter: "hideDefaultFooter" }, outputs: { activeIndexChange: "activeIndexChange", stepSelect: "stepSelect", cancel: "cancel", previous: "previous", save: "save", next: "next" }, host: { classAttribute: "geo-step-form-layout-host" }, ngImport: i0, template: "<div class=\"geo-step-form-layout\">\n <aside class=\"geo-step-form-layout__aside\">\n <div class=\"geo-step-form-layout__step-card\">\n <geo-stepper\n [steps]=\"steps\"\n [activeIndex]=\"activeIndex\"\n [clickable]=\"clickableSteps\"\n orientation=\"vertical\"\n (activeIndexChange)=\"onActiveIndexChange($event)\"\n (stepSelect)=\"onStepSelect($event)\"\n ></geo-stepper>\n\n <ng-content select=\"[sidebarExtra]\"></ng-content>\n </div>\n </aside>\n\n <div\n class=\"geo-step-form-layout__main-wrap\"\n [class.geo-step-form-layout__main-wrap--with-fab]=\"showScrollButtons\"\n >\n @if (showScrollButtons) {\n <div class=\"geo-step-form-layout__scroll-fab\">\n <button\n type=\"button\"\n class=\"geo-step-form-layout__fab\"\n aria-label=\"B\u01B0\u1EDBc tr\u01B0\u1EDBc\"\n [disabled]=\"!canGoPreviousStep\"\n (click)=\"goAdjacentStep('up')\"\n >\n <span nz-icon nzType=\"arrow-up\" nzTheme=\"outline\"></span>\n </button>\n <button\n type=\"button\"\n class=\"geo-step-form-layout__fab\"\n aria-label=\"B\u01B0\u1EDBc sau\"\n [disabled]=\"!canGoNextStep\"\n (click)=\"goAdjacentStep('down')\"\n >\n <span nz-icon nzType=\"arrow-down\" nzTheme=\"outline\"></span>\n </button>\n </div>\n }\n\n <section class=\"geo-step-form-layout__card\">\n @if (title) {\n <h1 class=\"geo-step-form-layout__title\">{{ title }}</h1>\n }\n\n <div class=\"geo-step-form-layout__body\">\n <ng-content></ng-content>\n </div>\n\n @if (!hideDefaultFooter) {\n <footer class=\"geo-step-form-layout__footer\">\n <ng-content select=\"[footer]\"></ng-content>\n\n <div class=\"geo-step-form-layout__footer-default\">\n <div class=\"geo-step-form-layout__footer-start\">\n @if (showCancel) {\n <geo-button appearance=\"secondary\" color=\"brand\" (clicked)=\"onCancel()\">\n {{ cancelLabel }}\n </geo-button>\n }\n </div>\n\n <div class=\"geo-step-form-layout__footer-end\">\n @if (showPrevious && activeIndex > 0) {\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"left\"\n (clicked)=\"onPrevious()\"\n >\n {{ previousLabel }}\n </geo-button>\n }\n @if (showSave) {\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"save\"\n [disabled]=\"saveLoading\"\n (clicked)=\"onSave()\"\n >\n {{ saveLabel }}\n </geo-button>\n }\n @if (showNext) {\n <geo-button\n appearance=\"primary\"\n color=\"brand\"\n [icon]=\"isLastStep ? 'check' : 'right'\"\n [disabled]=\"nextLoading\"\n (clicked)=\"onNext()\"\n >\n {{ resolvedNextLabel }}\n </geo-button>\n }\n </div>\n </div>\n </footer>\n } @else {\n <ng-content select=\"[footer]\"></ng-content>\n }\n </section>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host,.geo-step-form-layout-host{display:block;width:100%;min-height:100%;box-sizing:border-box}.geo-step-form-layout{display:grid;grid-template-columns:260px minmax(0,1fr);gap:20px;align-items:start;width:100%;min-height:100%;height:100%;padding:16px 24px;box-sizing:border-box;overflow:visible}.geo-step-form-layout__aside{display:flex;flex-direction:column;min-width:0;align-self:start}.geo-step-form-layout__step-card{display:flex;flex-direction:column;gap:16px;width:100%;padding:20px 16px;background:var(--geo-color-neutral-white);border:1px solid var(--geo-color-primary-border);border-radius:var(--geo-radius);box-shadow:0 1px 2px #0000000a;box-sizing:border-box}.geo-step-form-layout__main-wrap{position:relative;width:100%;min-width:0;min-height:0;height:100%;display:flex;flex-direction:column;align-self:stretch;overflow:visible;box-sizing:border-box}.geo-step-form-layout__main-wrap--with-fab{padding-right:48px}.geo-step-form-layout__scroll-fab{position:absolute;top:0;right:0;z-index:2;display:flex;flex-direction:column;gap:10px}.geo-step-form-layout__fab{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid var(--geo-color-primary-default);border-radius:50%;background:var(--geo-color-neutral-white);color:var(--geo-color-primary-default);cursor:pointer;box-shadow:none;transition:background-color .15s ease,opacity .15s ease}.geo-step-form-layout__fab .anticon{font-size:14px}.geo-step-form-layout__fab:hover:not(:disabled){background:var(--geo-color-primary-surface-light)}.geo-step-form-layout__fab:focus-visible{outline:2px solid var(--geo-color-primary-default);outline-offset:2px}.geo-step-form-layout__fab:disabled{opacity:.35;cursor:not-allowed}.geo-step-form-layout__card{display:flex;flex-direction:column;width:100%;min-width:0;min-height:0;flex:1 1 auto;height:calc(100vh - 48px);max-height:calc(100vh - 48px);background:var(--geo-color-neutral-white);border:1px solid var(--geo-color-primary-border);border-radius:var(--geo-radius);overflow:hidden;box-shadow:0 1px 2px #0000000a;box-sizing:border-box}.geo-step-form-layout__title{flex-shrink:0;margin:0;padding:24px 24px 8px;font-size:20px;font-weight:700;line-height:1.3;color:var(--geo-color-neutral-900)}.geo-step-form-layout__body{flex:1 1 auto;min-height:0;overflow:auto;padding:16px 24px 8px;overscroll-behavior:contain}.geo-step-form-layout__footer{flex-shrink:0;border-top:1px solid var(--geo-color-neutral-100);padding:16px 24px 20px;background:var(--geo-color-neutral-white)}.geo-step-form-layout__footer-default{display:flex;align-items:center;justify-content:space-between;gap:12px}.geo-step-form-layout__footer-start,.geo-step-form-layout__footer-end{display:flex;align-items:center;gap:12px}.geo-step-form-section{display:flex;flex-direction:column;gap:16px;margin-bottom:28px}.geo-step-form-section:last-child{margin-bottom:8px}.geo-step-form-section__title{margin:0;font-size:16px;font-weight:700;line-height:1.3;color:var(--geo-color-neutral-900)}.geo-step-form-grid{display:grid;gap:16px;grid-template-columns:repeat(2,minmax(0,1fr))}.geo-step-form-grid--cols-1{grid-template-columns:minmax(0,1fr)}.geo-step-form-grid--cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.geo-step-form-grid--cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.geo-step-form-grid__full{grid-column:1/-1}@media (max-width: 1100px){.geo-step-form-layout{grid-template-columns:220px minmax(0,1fr)}.geo-step-form-grid--cols-4{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width: 900px){.geo-step-form-layout{grid-template-columns:1fr;padding:12px 16px 20px}.geo-step-form-layout__main-wrap{margin-right:0;padding-right:0}.geo-step-form-layout__scroll-fab{display:none}.geo-step-form-layout__card{height:auto;max-height:none}.geo-step-form-grid,.geo-step-form-grid--cols-3,.geo-step-form-grid--cols-4{grid-template-columns:minmax(0,1fr)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "component", type: GeoButtonComponent, selector: "geo-button", inputs: ["appearance", "color", "icon", "iconTheme", "iconPlacement", "iconOnly", "type", "disabled", "tooltip", "tooltipPlacement", "active", "title"], outputs: ["clicked"] }, { kind: "component", type: GeoStepperComponent, selector: "geo-stepper", inputs: ["steps", "activeIndex", "orientation", "clickable"], outputs: ["activeIndexChange", "stepSelect"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2450
+ }
2451
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoStepFormLayoutComponent, decorators: [{
2452
+ type: Component,
2453
+ args: [{ selector: 'geo-step-form-layout', standalone: true, imports: [CommonModule, NzIconModule, GeoButtonComponent, GeoStepperComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
2454
+ class: 'geo-step-form-layout-host',
2455
+ }, template: "<div class=\"geo-step-form-layout\">\n <aside class=\"geo-step-form-layout__aside\">\n <div class=\"geo-step-form-layout__step-card\">\n <geo-stepper\n [steps]=\"steps\"\n [activeIndex]=\"activeIndex\"\n [clickable]=\"clickableSteps\"\n orientation=\"vertical\"\n (activeIndexChange)=\"onActiveIndexChange($event)\"\n (stepSelect)=\"onStepSelect($event)\"\n ></geo-stepper>\n\n <ng-content select=\"[sidebarExtra]\"></ng-content>\n </div>\n </aside>\n\n <div\n class=\"geo-step-form-layout__main-wrap\"\n [class.geo-step-form-layout__main-wrap--with-fab]=\"showScrollButtons\"\n >\n @if (showScrollButtons) {\n <div class=\"geo-step-form-layout__scroll-fab\">\n <button\n type=\"button\"\n class=\"geo-step-form-layout__fab\"\n aria-label=\"B\u01B0\u1EDBc tr\u01B0\u1EDBc\"\n [disabled]=\"!canGoPreviousStep\"\n (click)=\"goAdjacentStep('up')\"\n >\n <span nz-icon nzType=\"arrow-up\" nzTheme=\"outline\"></span>\n </button>\n <button\n type=\"button\"\n class=\"geo-step-form-layout__fab\"\n aria-label=\"B\u01B0\u1EDBc sau\"\n [disabled]=\"!canGoNextStep\"\n (click)=\"goAdjacentStep('down')\"\n >\n <span nz-icon nzType=\"arrow-down\" nzTheme=\"outline\"></span>\n </button>\n </div>\n }\n\n <section class=\"geo-step-form-layout__card\">\n @if (title) {\n <h1 class=\"geo-step-form-layout__title\">{{ title }}</h1>\n }\n\n <div class=\"geo-step-form-layout__body\">\n <ng-content></ng-content>\n </div>\n\n @if (!hideDefaultFooter) {\n <footer class=\"geo-step-form-layout__footer\">\n <ng-content select=\"[footer]\"></ng-content>\n\n <div class=\"geo-step-form-layout__footer-default\">\n <div class=\"geo-step-form-layout__footer-start\">\n @if (showCancel) {\n <geo-button appearance=\"secondary\" color=\"brand\" (clicked)=\"onCancel()\">\n {{ cancelLabel }}\n </geo-button>\n }\n </div>\n\n <div class=\"geo-step-form-layout__footer-end\">\n @if (showPrevious && activeIndex > 0) {\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"left\"\n (clicked)=\"onPrevious()\"\n >\n {{ previousLabel }}\n </geo-button>\n }\n @if (showSave) {\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"save\"\n [disabled]=\"saveLoading\"\n (clicked)=\"onSave()\"\n >\n {{ saveLabel }}\n </geo-button>\n }\n @if (showNext) {\n <geo-button\n appearance=\"primary\"\n color=\"brand\"\n [icon]=\"isLastStep ? 'check' : 'right'\"\n [disabled]=\"nextLoading\"\n (clicked)=\"onNext()\"\n >\n {{ resolvedNextLabel }}\n </geo-button>\n }\n </div>\n </div>\n </footer>\n } @else {\n <ng-content select=\"[footer]\"></ng-content>\n }\n </section>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host,.geo-step-form-layout-host{display:block;width:100%;min-height:100%;box-sizing:border-box}.geo-step-form-layout{display:grid;grid-template-columns:260px minmax(0,1fr);gap:20px;align-items:start;width:100%;min-height:100%;height:100%;padding:16px 24px;box-sizing:border-box;overflow:visible}.geo-step-form-layout__aside{display:flex;flex-direction:column;min-width:0;align-self:start}.geo-step-form-layout__step-card{display:flex;flex-direction:column;gap:16px;width:100%;padding:20px 16px;background:var(--geo-color-neutral-white);border:1px solid var(--geo-color-primary-border);border-radius:var(--geo-radius);box-shadow:0 1px 2px #0000000a;box-sizing:border-box}.geo-step-form-layout__main-wrap{position:relative;width:100%;min-width:0;min-height:0;height:100%;display:flex;flex-direction:column;align-self:stretch;overflow:visible;box-sizing:border-box}.geo-step-form-layout__main-wrap--with-fab{padding-right:48px}.geo-step-form-layout__scroll-fab{position:absolute;top:0;right:0;z-index:2;display:flex;flex-direction:column;gap:10px}.geo-step-form-layout__fab{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid var(--geo-color-primary-default);border-radius:50%;background:var(--geo-color-neutral-white);color:var(--geo-color-primary-default);cursor:pointer;box-shadow:none;transition:background-color .15s ease,opacity .15s ease}.geo-step-form-layout__fab .anticon{font-size:14px}.geo-step-form-layout__fab:hover:not(:disabled){background:var(--geo-color-primary-surface-light)}.geo-step-form-layout__fab:focus-visible{outline:2px solid var(--geo-color-primary-default);outline-offset:2px}.geo-step-form-layout__fab:disabled{opacity:.35;cursor:not-allowed}.geo-step-form-layout__card{display:flex;flex-direction:column;width:100%;min-width:0;min-height:0;flex:1 1 auto;height:calc(100vh - 48px);max-height:calc(100vh - 48px);background:var(--geo-color-neutral-white);border:1px solid var(--geo-color-primary-border);border-radius:var(--geo-radius);overflow:hidden;box-shadow:0 1px 2px #0000000a;box-sizing:border-box}.geo-step-form-layout__title{flex-shrink:0;margin:0;padding:24px 24px 8px;font-size:20px;font-weight:700;line-height:1.3;color:var(--geo-color-neutral-900)}.geo-step-form-layout__body{flex:1 1 auto;min-height:0;overflow:auto;padding:16px 24px 8px;overscroll-behavior:contain}.geo-step-form-layout__footer{flex-shrink:0;border-top:1px solid var(--geo-color-neutral-100);padding:16px 24px 20px;background:var(--geo-color-neutral-white)}.geo-step-form-layout__footer-default{display:flex;align-items:center;justify-content:space-between;gap:12px}.geo-step-form-layout__footer-start,.geo-step-form-layout__footer-end{display:flex;align-items:center;gap:12px}.geo-step-form-section{display:flex;flex-direction:column;gap:16px;margin-bottom:28px}.geo-step-form-section:last-child{margin-bottom:8px}.geo-step-form-section__title{margin:0;font-size:16px;font-weight:700;line-height:1.3;color:var(--geo-color-neutral-900)}.geo-step-form-grid{display:grid;gap:16px;grid-template-columns:repeat(2,minmax(0,1fr))}.geo-step-form-grid--cols-1{grid-template-columns:minmax(0,1fr)}.geo-step-form-grid--cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.geo-step-form-grid--cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.geo-step-form-grid__full{grid-column:1/-1}@media (max-width: 1100px){.geo-step-form-layout{grid-template-columns:220px minmax(0,1fr)}.geo-step-form-grid--cols-4{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width: 900px){.geo-step-form-layout{grid-template-columns:1fr;padding:12px 16px 20px}.geo-step-form-layout__main-wrap{margin-right:0;padding-right:0}.geo-step-form-layout__scroll-fab{display:none}.geo-step-form-layout__card{height:auto;max-height:none}.geo-step-form-grid,.geo-step-form-grid--cols-3,.geo-step-form-grid--cols-4{grid-template-columns:minmax(0,1fr)}}\n"] }]
2456
+ }], propDecorators: { steps: [{
2457
+ type: Input
2458
+ }], activeIndex: [{
2459
+ type: Input
2460
+ }], title: [{
2461
+ type: Input
2462
+ }], clickableSteps: [{
2463
+ type: Input
2464
+ }], showScrollButtons: [{
2465
+ type: Input
2466
+ }], showCancel: [{
2467
+ type: Input
2468
+ }], showPrevious: [{
2469
+ type: Input
2470
+ }], showSave: [{
2471
+ type: Input
2472
+ }], showNext: [{
2473
+ type: Input
2474
+ }], cancelLabel: [{
2475
+ type: Input
2476
+ }], previousLabel: [{
2477
+ type: Input
2478
+ }], saveLabel: [{
2479
+ type: Input
2480
+ }], nextLabel: [{
2481
+ type: Input
2482
+ }], finishLabel: [{
2483
+ type: Input
2484
+ }], saveLoading: [{
2485
+ type: Input
2486
+ }], nextLoading: [{
2487
+ type: Input
2488
+ }], hideDefaultFooter: [{
2489
+ type: Input
2490
+ }], activeIndexChange: [{
2491
+ type: Output
2492
+ }], stepSelect: [{
2493
+ type: Output
2494
+ }], cancel: [{
2495
+ type: Output
2496
+ }], previous: [{
2497
+ type: Output
2498
+ }], save: [{
2499
+ type: Output
2500
+ }], next: [{
2501
+ type: Output
2502
+ }] } });
2503
+
2504
+ class GeoTabDirective {
2505
+ template;
2506
+ key;
2507
+ constructor(template) {
2508
+ this.template = template;
2509
+ }
2510
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTabDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
2511
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: GeoTabDirective, isStandalone: true, selector: "[uiTab]", inputs: { key: ["uiTab", "key"] }, ngImport: i0 });
2512
+ }
2513
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTabDirective, decorators: [{
2514
+ type: Directive,
2515
+ args: [{
2516
+ selector: '[uiTab]',
2517
+ standalone: true,
2518
+ }]
2519
+ }], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { key: [{
2520
+ type: Input,
2521
+ args: ['uiTab']
2522
+ }] } });
2523
+ class GeoTabsComponent {
2524
+ items = [];
2525
+ type = 'line';
2526
+ size = 'default';
2527
+ selectedIndex = 0;
2528
+ selectedKey;
2529
+ centered = false;
2530
+ animated = true;
2531
+ selectedIndexChange = new EventEmitter();
2532
+ selectedKeyChange = new EventEmitter();
2533
+ tabChange = new EventEmitter();
2534
+ tabTemplates;
2535
+ get resolvedSelectedIndex() {
2536
+ if (this.selectedKey) {
2537
+ const index = this.items.findIndex((item) => item.key === this.selectedKey);
2538
+ if (index >= 0) {
2539
+ return index;
2540
+ }
2541
+ }
2542
+ return this.selectedIndex;
2543
+ }
2544
+ getTemplate(key) {
2545
+ return this.tabTemplates?.find((tab) => tab.key === key)?.template ?? null;
2546
+ }
2547
+ onSelectedIndexChange(index) {
2548
+ this.selectedIndex = index;
2549
+ const key = this.items[index]?.key ?? '';
2550
+ this.selectedKey = key || undefined;
2551
+ this.selectedIndexChange.emit(index);
2552
+ if (key) {
2553
+ this.selectedKeyChange.emit(key);
2554
+ this.tabChange.emit({ index, key });
2555
+ }
2556
+ }
2557
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2558
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoTabsComponent, isStandalone: true, selector: "geo-tabs", inputs: { items: "items", type: "type", size: "size", selectedIndex: "selectedIndex", selectedKey: "selectedKey", centered: "centered", animated: "animated" }, outputs: { selectedIndexChange: "selectedIndexChange", selectedKeyChange: "selectedKeyChange", tabChange: "tabChange" }, host: { properties: { "class.geo-tabs-host--card": "type === \"card\"", "class.geo-tabs-host--line": "type === \"line\"" }, classAttribute: "geo-tabs-host" }, queries: [{ propertyName: "tabTemplates", predicate: GeoTabDirective }], ngImport: i0, template: "<nz-tabset\n class=\"geo-tabs\"\n [class.geo-tabs--card]=\"type === 'card'\"\n [class.geo-tabs--line]=\"type === 'line'\"\n [nzType]=\"type\"\n [nzSize]=\"size\"\n [nzSelectedIndex]=\"resolvedSelectedIndex\"\n [nzCentered]=\"centered\"\n [nzAnimated]=\"animated\"\n (nzSelectedIndexChange)=\"onSelectedIndexChange($event)\"\n>\n @for (item of items; track item.key) {\n <nz-tab [nzTitle]=\"item.title\" [nzDisabled]=\"item.disabled ?? false\">\n @if (getTemplate(item.key); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\"></ng-container>\n }\n </nz-tab>\n }\n</nz-tabset>\n", styles: ["@charset \"UTF-8\";.geo-tabs-host{display:block;width:100%;min-width:0;max-width:100%}.geo-tabs.ant-tabs{color:var(--geo-color-neutral-900);min-width:0;width:100%}.geo-tabs .ant-tabs-nav{margin-bottom:16px}.geo-tabs .ant-tabs-nav-wrap{min-width:0;flex:1 1 auto}.geo-tabs .ant-tabs-nav-list{flex-wrap:nowrap}.geo-tabs .ant-tabs-tab{padding:10px 16px;font-size:14px;line-height:20px;color:var(--geo-color-neutral-500);transition:color .15s ease}.geo-tabs .ant-tabs-tab:hover{color:var(--geo-color-primary-default)}.geo-tabs .ant-tabs-tab-btn{font-weight:500}.geo-tabs .ant-tabs-tab-active .ant-tabs-tab-btn{color:var(--geo-color-primary-default)!important;font-weight:600}.geo-tabs .ant-tabs-tab-disabled{color:var(--geo-color-neutral-400)!important;cursor:not-allowed}.geo-tabs .ant-tabs-ink-bar{background:var(--geo-color-primary-default);height:2px}.geo-tabs.ant-tabs-top>.ant-tabs-nav:before,.geo-tabs.ant-tabs-bottom>.ant-tabs-nav:before,.geo-tabs.ant-tabs-top>div>.ant-tabs-nav:before,.geo-tabs.ant-tabs-bottom>div>.ant-tabs-nav:before{border-bottom-color:var(--geo-color-primary-border)}.geo-tabs--card.ant-tabs-card>.ant-tabs-nav .ant-tabs-tab,.geo-tabs--card.ant-tabs-card>div>.ant-tabs-nav .ant-tabs-tab{margin:0 4px 0 0;padding:8px 16px;background:var(--geo-color-neutral-100);border:1px solid var(--geo-color-primary-border);border-radius:var(--geo-radius) var(--geo-radius) 0 0;color:var(--geo-color-neutral-500)}.geo-tabs--card.ant-tabs-card>.ant-tabs-nav .ant-tabs-tab-active,.geo-tabs--card.ant-tabs-card>div>.ant-tabs-nav .ant-tabs-tab-active{background:var(--geo-color-neutral-white);border-color:var(--geo-color-primary-border);border-bottom-color:var(--geo-color-neutral-white);color:var(--geo-color-primary-default)}.geo-tabs--card .ant-tabs-tab-active .ant-tabs-tab-btn{color:var(--geo-color-primary-default)!important}.geo-tabs .ant-tabs-content-holder{color:var(--geo-color-neutral-900);font-size:14px;line-height:22px;min-width:0}.geo-tabs.ant-tabs-small .ant-tabs-tab{padding:6px 12px;font-size:13px}.geo-tabs.ant-tabs-large .ant-tabs-tab{padding:12px 20px;font-size:16px}@media (max-width: 1024px){.geo-tabs .ant-tabs-tab{padding:8px 12px;font-size:13px;line-height:18px}.geo-tabs.ant-tabs-large .ant-tabs-tab{padding:10px 14px;font-size:15px}.geo-tabs--card.ant-tabs-card>.ant-tabs-nav .ant-tabs-tab,.geo-tabs--card.ant-tabs-card>div>.ant-tabs-nav .ant-tabs-tab{padding:6px 12px}}@media (max-width: 767.98px){.geo-tabs .ant-tabs-nav{margin-bottom:12px}.geo-tabs .ant-tabs-nav-wrap{overflow:visible}.geo-tabs .ant-tabs-nav-list{flex-wrap:wrap;row-gap:0;width:100%;transform:none!important}.geo-tabs .ant-tabs-nav-operations,.geo-tabs .ant-tabs-ink-bar{display:none!important}.geo-tabs .ant-tabs-tab{height:auto;min-width:0;max-width:100%;flex:1 1 auto;margin:0;padding:8px 10px;font-size:12px;line-height:1.35;white-space:normal;text-align:center;border-bottom:2px solid transparent}.geo-tabs .ant-tabs-tab-btn{display:inline-block;max-width:100%;white-space:normal;word-break:break-word;line-height:1.35}.geo-tabs .ant-tabs-tab-active{border-bottom-color:var(--geo-color-primary-default)}.geo-tabs.ant-tabs-small .ant-tabs-tab{padding:6px 8px;font-size:12px}.geo-tabs.ant-tabs-large .ant-tabs-tab{padding:8px 12px;font-size:14px}.geo-tabs.ant-tabs-top>.ant-tabs-nav:before,.geo-tabs.ant-tabs-top>div>.ant-tabs-nav:before{left:0;right:0;border-bottom:1px solid var(--geo-color-primary-border)}.geo-tabs--card.ant-tabs-card>.ant-tabs-nav .ant-tabs-tab,.geo-tabs--card.ant-tabs-card>div>.ant-tabs-nav .ant-tabs-tab{margin:0 0 4px;flex:1 1 calc(50% - 4px);padding:8px 10px;border-radius:var(--geo-radius);border-bottom-color:var(--geo-color-primary-border)}.geo-tabs--card.ant-tabs-card>.ant-tabs-nav .ant-tabs-tab-active,.geo-tabs--card.ant-tabs-card>div>.ant-tabs-nav .ant-tabs-tab-active{border-color:var(--geo-color-primary-default);border-bottom-color:var(--geo-color-primary-default);background:var(--geo-color-neutral-white)}.geo-tabs.ant-tabs-centered>.ant-tabs-nav .ant-tabs-nav-wrap:before,.geo-tabs.ant-tabs-centered>.ant-tabs-nav .ant-tabs-nav-wrap:after,.geo-tabs.ant-tabs-centered>div>.ant-tabs-nav .ant-tabs-nav-wrap:before,.geo-tabs.ant-tabs-centered>div>.ant-tabs-nav .ant-tabs-nav-wrap:after{flex:0 0 0;content:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: NgZorroAntdModule }, { kind: "component", type: i2$4.NzTabSetComponent, selector: "nz-tabset", inputs: ["nzSelectedIndex", "nzTabPosition", "nzTabBarExtraContent", "nzCanDeactivate", "nzAddIcon", "nzTabBarStyle", "nzType", "nzSize", "nzAnimated", "nzTabBarGutter", "nzHideAdd", "nzCentered", "nzHideAll", "nzLinkRouter", "nzLinkExact", "nzDestroyInactiveTabPane"], outputs: ["nzSelectChange", "nzSelectedIndexChange", "nzTabListScroll", "nzClose", "nzAdd"], exportAs: ["nzTabset"] }, { kind: "component", type: i2$4.NzTabComponent, selector: "nz-tab", inputs: ["nzTitle", "nzClosable", "nzCloseIcon", "nzDisabled", "nzForceRender"], outputs: ["nzSelect", "nzDeselect", "nzClick", "nzContextmenu"], exportAs: ["nzTab"] }], encapsulation: i0.ViewEncapsulation.None });
2559
+ }
2560
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTabsComponent, decorators: [{
2561
+ type: Component,
2562
+ args: [{ selector: 'geo-tabs', standalone: true, imports: [CommonModule, NgZorroAntdModule], encapsulation: ViewEncapsulation.None, host: {
2563
+ class: 'geo-tabs-host',
2564
+ '[class.geo-tabs-host--card]': 'type === "card"',
2565
+ '[class.geo-tabs-host--line]': 'type === "line"',
2566
+ }, template: "<nz-tabset\n class=\"geo-tabs\"\n [class.geo-tabs--card]=\"type === 'card'\"\n [class.geo-tabs--line]=\"type === 'line'\"\n [nzType]=\"type\"\n [nzSize]=\"size\"\n [nzSelectedIndex]=\"resolvedSelectedIndex\"\n [nzCentered]=\"centered\"\n [nzAnimated]=\"animated\"\n (nzSelectedIndexChange)=\"onSelectedIndexChange($event)\"\n>\n @for (item of items; track item.key) {\n <nz-tab [nzTitle]=\"item.title\" [nzDisabled]=\"item.disabled ?? false\">\n @if (getTemplate(item.key); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\"></ng-container>\n }\n </nz-tab>\n }\n</nz-tabset>\n", styles: ["@charset \"UTF-8\";.geo-tabs-host{display:block;width:100%;min-width:0;max-width:100%}.geo-tabs.ant-tabs{color:var(--geo-color-neutral-900);min-width:0;width:100%}.geo-tabs .ant-tabs-nav{margin-bottom:16px}.geo-tabs .ant-tabs-nav-wrap{min-width:0;flex:1 1 auto}.geo-tabs .ant-tabs-nav-list{flex-wrap:nowrap}.geo-tabs .ant-tabs-tab{padding:10px 16px;font-size:14px;line-height:20px;color:var(--geo-color-neutral-500);transition:color .15s ease}.geo-tabs .ant-tabs-tab:hover{color:var(--geo-color-primary-default)}.geo-tabs .ant-tabs-tab-btn{font-weight:500}.geo-tabs .ant-tabs-tab-active .ant-tabs-tab-btn{color:var(--geo-color-primary-default)!important;font-weight:600}.geo-tabs .ant-tabs-tab-disabled{color:var(--geo-color-neutral-400)!important;cursor:not-allowed}.geo-tabs .ant-tabs-ink-bar{background:var(--geo-color-primary-default);height:2px}.geo-tabs.ant-tabs-top>.ant-tabs-nav:before,.geo-tabs.ant-tabs-bottom>.ant-tabs-nav:before,.geo-tabs.ant-tabs-top>div>.ant-tabs-nav:before,.geo-tabs.ant-tabs-bottom>div>.ant-tabs-nav:before{border-bottom-color:var(--geo-color-primary-border)}.geo-tabs--card.ant-tabs-card>.ant-tabs-nav .ant-tabs-tab,.geo-tabs--card.ant-tabs-card>div>.ant-tabs-nav .ant-tabs-tab{margin:0 4px 0 0;padding:8px 16px;background:var(--geo-color-neutral-100);border:1px solid var(--geo-color-primary-border);border-radius:var(--geo-radius) var(--geo-radius) 0 0;color:var(--geo-color-neutral-500)}.geo-tabs--card.ant-tabs-card>.ant-tabs-nav .ant-tabs-tab-active,.geo-tabs--card.ant-tabs-card>div>.ant-tabs-nav .ant-tabs-tab-active{background:var(--geo-color-neutral-white);border-color:var(--geo-color-primary-border);border-bottom-color:var(--geo-color-neutral-white);color:var(--geo-color-primary-default)}.geo-tabs--card .ant-tabs-tab-active .ant-tabs-tab-btn{color:var(--geo-color-primary-default)!important}.geo-tabs .ant-tabs-content-holder{color:var(--geo-color-neutral-900);font-size:14px;line-height:22px;min-width:0}.geo-tabs.ant-tabs-small .ant-tabs-tab{padding:6px 12px;font-size:13px}.geo-tabs.ant-tabs-large .ant-tabs-tab{padding:12px 20px;font-size:16px}@media (max-width: 1024px){.geo-tabs .ant-tabs-tab{padding:8px 12px;font-size:13px;line-height:18px}.geo-tabs.ant-tabs-large .ant-tabs-tab{padding:10px 14px;font-size:15px}.geo-tabs--card.ant-tabs-card>.ant-tabs-nav .ant-tabs-tab,.geo-tabs--card.ant-tabs-card>div>.ant-tabs-nav .ant-tabs-tab{padding:6px 12px}}@media (max-width: 767.98px){.geo-tabs .ant-tabs-nav{margin-bottom:12px}.geo-tabs .ant-tabs-nav-wrap{overflow:visible}.geo-tabs .ant-tabs-nav-list{flex-wrap:wrap;row-gap:0;width:100%;transform:none!important}.geo-tabs .ant-tabs-nav-operations,.geo-tabs .ant-tabs-ink-bar{display:none!important}.geo-tabs .ant-tabs-tab{height:auto;min-width:0;max-width:100%;flex:1 1 auto;margin:0;padding:8px 10px;font-size:12px;line-height:1.35;white-space:normal;text-align:center;border-bottom:2px solid transparent}.geo-tabs .ant-tabs-tab-btn{display:inline-block;max-width:100%;white-space:normal;word-break:break-word;line-height:1.35}.geo-tabs .ant-tabs-tab-active{border-bottom-color:var(--geo-color-primary-default)}.geo-tabs.ant-tabs-small .ant-tabs-tab{padding:6px 8px;font-size:12px}.geo-tabs.ant-tabs-large .ant-tabs-tab{padding:8px 12px;font-size:14px}.geo-tabs.ant-tabs-top>.ant-tabs-nav:before,.geo-tabs.ant-tabs-top>div>.ant-tabs-nav:before{left:0;right:0;border-bottom:1px solid var(--geo-color-primary-border)}.geo-tabs--card.ant-tabs-card>.ant-tabs-nav .ant-tabs-tab,.geo-tabs--card.ant-tabs-card>div>.ant-tabs-nav .ant-tabs-tab{margin:0 0 4px;flex:1 1 calc(50% - 4px);padding:8px 10px;border-radius:var(--geo-radius);border-bottom-color:var(--geo-color-primary-border)}.geo-tabs--card.ant-tabs-card>.ant-tabs-nav .ant-tabs-tab-active,.geo-tabs--card.ant-tabs-card>div>.ant-tabs-nav .ant-tabs-tab-active{border-color:var(--geo-color-primary-default);border-bottom-color:var(--geo-color-primary-default);background:var(--geo-color-neutral-white)}.geo-tabs.ant-tabs-centered>.ant-tabs-nav .ant-tabs-nav-wrap:before,.geo-tabs.ant-tabs-centered>.ant-tabs-nav .ant-tabs-nav-wrap:after,.geo-tabs.ant-tabs-centered>div>.ant-tabs-nav .ant-tabs-nav-wrap:before,.geo-tabs.ant-tabs-centered>div>.ant-tabs-nav .ant-tabs-nav-wrap:after{flex:0 0 0;content:none}}\n"] }]
2567
+ }], propDecorators: { items: [{
2568
+ type: Input
2569
+ }], type: [{
2570
+ type: Input
2571
+ }], size: [{
2572
+ type: Input
2573
+ }], selectedIndex: [{
2574
+ type: Input
2575
+ }], selectedKey: [{
2576
+ type: Input
2577
+ }], centered: [{
2578
+ type: Input
2579
+ }], animated: [{
2580
+ type: Input
2581
+ }], selectedIndexChange: [{
2582
+ type: Output
2583
+ }], selectedKeyChange: [{
2584
+ type: Output
2585
+ }], tabChange: [{
2586
+ type: Output
2587
+ }], tabTemplates: [{
2588
+ type: ContentChildren,
2589
+ args: [GeoTabDirective]
2590
+ }] } });
2591
+
2592
+ const DEFAULT_UI_ROW_ACTIONS = [
2593
+ { key: 'edit', icon: 'edit', title: 'Chỉnh sửa' },
2594
+ { key: 'more', icon: 'more', title: 'Thêm thao tác' },
2595
+ ];
2596
+ /** ≤2: hiện hết; >2: primary + danger (vd. Sửa + Xóa), còn lại vào menu. */
2597
+ function pickInlineRowActions(actions, primaryActionKey = 'edit') {
2598
+ const list = actions.filter((action) => !action.disabled);
2599
+ if (list.length <= 2) {
2600
+ return list;
2601
+ }
2602
+ const primary = list.find((action) => action.key === primaryActionKey) ?? list[0];
2603
+ const secondary = list.find((action) => action.key !== primary.key && action.danger) ??
2604
+ list.find((action) => action.key !== primary.key);
2605
+ return secondary ? [primary, secondary] : [primary];
2606
+ }
2607
+ function pickOverflowRowActions(actions, primaryActionKey = 'edit') {
2608
+ const list = actions.filter((action) => !action.disabled);
2609
+ if (list.length <= 2) {
2610
+ return [];
2611
+ }
2612
+ const inlineKeys = new Set(pickInlineRowActions(list, primaryActionKey).map((action) => action.key));
2613
+ return list.filter((action) => !inlineKeys.has(action.key));
2614
+ }
2615
+
2616
+ class GeoRowActionsComponent {
2617
+ actions = null;
2618
+ /** Action ưu tiên hiển thị khi có > 2 thao tác (mặc định: edit) */
2619
+ primaryActionKey = 'edit';
2620
+ actionClick = new EventEmitter();
2621
+ /** @deprecated Dùng `actionClick` với key `edit` */
2622
+ edit = new EventEmitter();
2623
+ /** @deprecated Dùng `actionClick` với key `more` */
2624
+ more = new EventEmitter();
2625
+ get resolvedActions() {
2626
+ return this.actions?.length ? this.actions : DEFAULT_UI_ROW_ACTIONS;
2627
+ }
2628
+ get enabledActions() {
2629
+ return this.resolvedActions.filter((action) => !action.disabled);
2630
+ }
2631
+ get inlineActions() {
2632
+ return pickInlineRowActions(this.enabledActions, this.primaryActionKey);
2633
+ }
2634
+ get overflowActions() {
2635
+ return pickOverflowRowActions(this.enabledActions, this.primaryActionKey);
2636
+ }
2637
+ get hasOverflow() {
2638
+ return this.overflowActions.length > 0;
2639
+ }
2640
+ onActionClick(event, action) {
2641
+ if (action.disabled) {
2642
+ return;
2643
+ }
2644
+ event.stopPropagation();
2645
+ this.actionClick.emit(action.key);
2646
+ if (action.key === 'edit') {
2647
+ this.edit.emit();
2648
+ }
2649
+ if (action.key === 'more') {
2650
+ this.more.emit();
2651
+ }
2652
+ }
2653
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoRowActionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2654
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoRowActionsComponent, isStandalone: true, selector: "geo-row-actions", inputs: { actions: "actions", primaryActionKey: "primaryActionKey" }, outputs: { actionClick: "actionClick", edit: "edit", more: "more" }, ngImport: i0, template: "<div class=\"geo-row-actions\">\n @for (action of inlineActions; track action.key) {\n <button\n type=\"button\"\n class=\"geo-row-actions__btn\"\n [class.geo-row-actions__btn--danger]=\"action.danger\"\n [nz-tooltip]=\"action.title ?? action.label ?? ''\"\n [disabled]=\"action.disabled\"\n [attr.aria-label]=\"action.label ?? action.title ?? action.key\"\n (click)=\"onActionClick($event, action)\"\n >\n <span nz-icon [nzType]=\"action.icon\" [nzTheme]=\"action.iconTheme ?? 'outline'\"></span>\n </button>\n }\n\n @if (hasOverflow) {\n <button\n type=\"button\"\n class=\"geo-row-actions__btn\"\n nz-dropdown\n [nzDropdownMenu]=\"overflowMenu\"\n nzTrigger=\"click\"\n nzPlacement=\"bottomRight\"\n nz-tooltip=\"Th\u00EAm thao t\u00E1c\"\n aria-label=\"Th\u00EAm thao t\u00E1c\"\n (click)=\"$event.stopPropagation()\"\n >\n <span nz-icon nzType=\"more\" nzTheme=\"outline\"></span>\n </button>\n\n <nz-dropdown-menu #overflowMenu=\"nzDropdownMenu\">\n <div class=\"geo-row-actions__panel\" (click)=\"$event.stopPropagation()\">\n @for (action of overflowActions; track action.key) {\n <button\n type=\"button\"\n class=\"geo-row-actions__panel-item\"\n [class.geo-row-actions__panel-item--danger]=\"action.danger\"\n [attr.aria-label]=\"action.label ?? action.title ?? action.key\"\n (click)=\"onActionClick($event, action)\"\n >\n <span\n class=\"geo-row-actions__panel-icon\"\n nz-icon\n [nzType]=\"action.icon\"\n [nzTheme]=\"action.iconTheme ?? 'outline'\"\n ></span>\n <span class=\"geo-row-actions__panel-label\">\n {{ action.label ?? action.title ?? action.key }}\n </span>\n </button>\n }\n </div>\n </nz-dropdown-menu>\n }\n</div>\n", styles: [":host{display:inline-block}.geo-row-actions{display:inline-flex;align-items:center;justify-content:center;gap:10px}.geo-row-actions__btn{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:var(--geo-radius);background:transparent;color:var(--geo-color-neutral-500);cursor:pointer;transition:color .15s ease,background-color .15s ease}.geo-row-actions__btn:hover:not(:disabled){color:var(--geo-color-primary-default);background:color-mix(in srgb,var(--geo-color-primary-default) 10%,transparent)}.geo-row-actions__btn:disabled{cursor:not-allowed;opacity:.45}.geo-row-actions__btn--danger:hover:not(:disabled){color:var(--geo-color-error-default);background:#ee003314}.geo-row-actions__btn :deep(.anticon){font-size:16px}.geo-row-actions__panel{min-width:168px;padding:8px;background:var(--geo-color-neutral-white);border-radius:var(--geo-radius);box-shadow:0 6px 16px #00000014;display:flex;flex-direction:column;gap:4px}.geo-row-actions__panel-item{display:flex;align-items:center;gap:10px;width:100%;min-height:36px;padding:8px 12px;border:none;border-radius:var(--geo-radius);background:transparent;color:var(--geo-color-neutral-900);font-size:14px;line-height:20px;cursor:pointer;text-align:left;transition:color .15s ease,background-color .15s ease}.geo-row-actions__panel-item:hover{color:var(--geo-color-primary-default);background:color-mix(in srgb,var(--geo-color-primary-default) 10%,transparent)}.geo-row-actions__panel-item--danger:hover{color:var(--geo-color-error-default);background:#ee003314}.geo-row-actions__panel-icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:16px;height:16px;color:inherit}.geo-row-actions__panel-icon :deep(.anticon){font-size:16px;line-height:1}.geo-row-actions__panel-label{flex:1;line-height:20px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: NgZorroAntdModule }, { kind: "directive", type: i1$5.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i2$5.NzDropDownDirective, selector: "[nz-dropdown]", inputs: ["nzDropdownMenu", "nzTrigger", "nzMatchWidthElement", "nzBackdrop", "nzClickHide", "nzDisabled", "nzVisible", "nzOverlayClassName", "nzOverlayStyle", "nzPlacement"], outputs: ["nzVisibleChange"], exportAs: ["nzDropdown"] }, { kind: "component", type: i2$5.NzDropdownMenuComponent, selector: "nz-dropdown-menu", exportAs: ["nzDropdownMenu"] }, { kind: "directive", type: i1.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "directive", type: i3.NzTooltipDirective, selector: "[nz-tooltip]", inputs: ["nzTooltipTitle", "nzTooltipTitleContext", "nz-tooltip", "nzTooltipTrigger", "nzTooltipPlacement", "nzTooltipOrigin", "nzTooltipVisible", "nzTooltipMouseEnterDelay", "nzTooltipMouseLeaveDelay", "nzTooltipOverlayClassName", "nzTooltipOverlayStyle", "nzTooltipArrowPointAtCenter", "cdkConnectedOverlayPush", "nzTooltipColor"], outputs: ["nzTooltipVisibleChange"], exportAs: ["nzTooltip"] }] });
2655
+ }
2656
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoRowActionsComponent, decorators: [{
2657
+ type: Component,
2658
+ args: [{ selector: 'geo-row-actions', standalone: true, imports: [CommonModule, NgZorroAntdModule], template: "<div class=\"geo-row-actions\">\n @for (action of inlineActions; track action.key) {\n <button\n type=\"button\"\n class=\"geo-row-actions__btn\"\n [class.geo-row-actions__btn--danger]=\"action.danger\"\n [nz-tooltip]=\"action.title ?? action.label ?? ''\"\n [disabled]=\"action.disabled\"\n [attr.aria-label]=\"action.label ?? action.title ?? action.key\"\n (click)=\"onActionClick($event, action)\"\n >\n <span nz-icon [nzType]=\"action.icon\" [nzTheme]=\"action.iconTheme ?? 'outline'\"></span>\n </button>\n }\n\n @if (hasOverflow) {\n <button\n type=\"button\"\n class=\"geo-row-actions__btn\"\n nz-dropdown\n [nzDropdownMenu]=\"overflowMenu\"\n nzTrigger=\"click\"\n nzPlacement=\"bottomRight\"\n nz-tooltip=\"Th\u00EAm thao t\u00E1c\"\n aria-label=\"Th\u00EAm thao t\u00E1c\"\n (click)=\"$event.stopPropagation()\"\n >\n <span nz-icon nzType=\"more\" nzTheme=\"outline\"></span>\n </button>\n\n <nz-dropdown-menu #overflowMenu=\"nzDropdownMenu\">\n <div class=\"geo-row-actions__panel\" (click)=\"$event.stopPropagation()\">\n @for (action of overflowActions; track action.key) {\n <button\n type=\"button\"\n class=\"geo-row-actions__panel-item\"\n [class.geo-row-actions__panel-item--danger]=\"action.danger\"\n [attr.aria-label]=\"action.label ?? action.title ?? action.key\"\n (click)=\"onActionClick($event, action)\"\n >\n <span\n class=\"geo-row-actions__panel-icon\"\n nz-icon\n [nzType]=\"action.icon\"\n [nzTheme]=\"action.iconTheme ?? 'outline'\"\n ></span>\n <span class=\"geo-row-actions__panel-label\">\n {{ action.label ?? action.title ?? action.key }}\n </span>\n </button>\n }\n </div>\n </nz-dropdown-menu>\n }\n</div>\n", styles: [":host{display:inline-block}.geo-row-actions{display:inline-flex;align-items:center;justify-content:center;gap:10px}.geo-row-actions__btn{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:var(--geo-radius);background:transparent;color:var(--geo-color-neutral-500);cursor:pointer;transition:color .15s ease,background-color .15s ease}.geo-row-actions__btn:hover:not(:disabled){color:var(--geo-color-primary-default);background:color-mix(in srgb,var(--geo-color-primary-default) 10%,transparent)}.geo-row-actions__btn:disabled{cursor:not-allowed;opacity:.45}.geo-row-actions__btn--danger:hover:not(:disabled){color:var(--geo-color-error-default);background:#ee003314}.geo-row-actions__btn :deep(.anticon){font-size:16px}.geo-row-actions__panel{min-width:168px;padding:8px;background:var(--geo-color-neutral-white);border-radius:var(--geo-radius);box-shadow:0 6px 16px #00000014;display:flex;flex-direction:column;gap:4px}.geo-row-actions__panel-item{display:flex;align-items:center;gap:10px;width:100%;min-height:36px;padding:8px 12px;border:none;border-radius:var(--geo-radius);background:transparent;color:var(--geo-color-neutral-900);font-size:14px;line-height:20px;cursor:pointer;text-align:left;transition:color .15s ease,background-color .15s ease}.geo-row-actions__panel-item:hover{color:var(--geo-color-primary-default);background:color-mix(in srgb,var(--geo-color-primary-default) 10%,transparent)}.geo-row-actions__panel-item--danger:hover{color:var(--geo-color-error-default);background:#ee003314}.geo-row-actions__panel-icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:16px;height:16px;color:inherit}.geo-row-actions__panel-icon :deep(.anticon){font-size:16px;line-height:1}.geo-row-actions__panel-label{flex:1;line-height:20px}\n"] }]
2659
+ }], propDecorators: { actions: [{
2660
+ type: Input
2661
+ }], primaryActionKey: [{
2662
+ type: Input
2663
+ }], actionClick: [{
2664
+ type: Output
2665
+ }], edit: [{
2666
+ type: Output
2667
+ }], more: [{
2668
+ type: Output
2669
+ }] } });
2670
+
2671
+ /** Breakpoint chuyển bảng → danh sách card (khớp layout mobile). */
2672
+ const UI_TABLE_MOBILE_BREAKPOINT = 767.98;
2673
+ const DEFAULT_UI_TABLE_PAGE_SIZE_OPTIONS = [10, 20, 50, 100];
2674
+
2675
+ class GeoTablePaginationComponent {
2676
+ pageIndex = 1;
2677
+ pageSize = 10;
2678
+ total = 0;
2679
+ pageSizeOptions = DEFAULT_UI_TABLE_PAGE_SIZE_OPTIONS;
2680
+ showSizeChanger = true;
2681
+ hideOnSinglePage = false;
2682
+ showTotalRange = true;
2683
+ sizeLabel = 'Hiển thị';
2684
+ pageIndexChange = new EventEmitter();
2685
+ pageSizeChange = new EventEmitter();
2686
+ get rangeStart() {
2687
+ if (this.total === 0) {
2688
+ return 0;
2689
+ }
2690
+ return (this.pageIndex - 1) * this.pageSize + 1;
2691
+ }
2692
+ get rangeEnd() {
2693
+ if (this.total === 0) {
2694
+ return 0;
2695
+ }
2696
+ return Math.min(this.pageIndex * this.pageSize, this.total);
2697
+ }
2698
+ get totalPages() {
2699
+ return Math.max(1, Math.ceil(this.total / this.pageSize));
2700
+ }
2701
+ get sizeOptions() {
2702
+ return this.pageSizeOptions.map((size) => ({
2703
+ label: size.toString(),
2704
+ value: size,
2705
+ }));
2706
+ }
2707
+ get visible() {
2708
+ if (this.hideOnSinglePage && this.total <= this.pageSize) {
2709
+ return false;
2710
+ }
2711
+ return this.total > 0;
2712
+ }
2713
+ get pages() {
2714
+ return this.buildPageList(this.pageIndex, this.totalPages);
2715
+ }
2716
+ get isFirstPage() {
2717
+ return this.pageIndex <= 1;
2718
+ }
2719
+ get isLastPage() {
2720
+ return this.pageIndex >= this.totalPages;
2721
+ }
2722
+ onPageSizeChange(value) {
2723
+ if (typeof value === 'number') {
2724
+ this.pageSizeChange.emit(value);
2725
+ }
2726
+ }
2727
+ goToFirst() {
2728
+ this.goToPage(1);
2729
+ }
2730
+ goToPrev() {
2731
+ this.goToPage(this.pageIndex - 1);
2732
+ }
2733
+ goToNext() {
2734
+ this.goToPage(this.pageIndex + 1);
2735
+ }
2736
+ goToLast() {
2737
+ this.goToPage(this.totalPages);
2738
+ }
2739
+ goToPage(page) {
2740
+ const next = Math.min(Math.max(page, 1), this.totalPages);
2741
+ if (next !== this.pageIndex) {
2742
+ this.pageIndexChange.emit(next);
2743
+ }
2744
+ }
2745
+ buildPageList(current, total) {
2746
+ if (total <= 5) {
2747
+ return Array.from({ length: total }, (_, index) => index + 1);
2748
+ }
2749
+ if (current <= 3) {
2750
+ return [1, 2, 3, 'ellipsis', total];
2751
+ }
2752
+ if (current >= total - 2) {
2753
+ return [1, 'ellipsis', total - 2, total - 1, total];
2754
+ }
2755
+ return [1, 'ellipsis', current - 1, current, current + 1, 'ellipsis', total];
2756
+ }
2757
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTablePaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2758
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoTablePaginationComponent, isStandalone: true, selector: "geo-table-pagination", inputs: { pageIndex: "pageIndex", pageSize: "pageSize", total: "total", pageSizeOptions: "pageSizeOptions", showSizeChanger: "showSizeChanger", hideOnSinglePage: "hideOnSinglePage", showTotalRange: "showTotalRange", sizeLabel: "sizeLabel" }, outputs: { pageIndexChange: "pageIndexChange", pageSizeChange: "pageSizeChange" }, ngImport: i0, template: "@if (visible) {\n <div class=\"geo-table-pagination\">\n <div class=\"geo-table-pagination__left\">\n @if (showTotalRange) {\n <p class=\"geo-table-pagination__total\">\n <strong>{{ rangeStart }}-{{ rangeEnd }}</strong> tr\u00EAn t\u1ED5ng <strong>{{ total }}</strong>\n </p>\n }\n\n @if (showSizeChanger) {\n <div class=\"geo-table-pagination__size\">\n <span class=\"geo-table-pagination__size-label\">{{ sizeLabel }}</span>\n <geo-select\n class=\"geo-table-pagination__size-select\"\n size=\"small\"\n [options]=\"sizeOptions\"\n [allowClear]=\"false\"\n [ngModel]=\"pageSize\"\n (valueChange)=\"onPageSizeChange($event)\"\n ></geo-select>\n </div>\n }\n </div>\n\n <div class=\"geo-table-pagination__nav\" role=\"navigation\" aria-label=\"Ph\u00E2n trang\">\n <button\n type=\"button\"\n class=\"geo-table-pagination__btn\"\n title=\"Trang \u0111\u1EA7u\"\n [disabled]=\"isFirstPage\"\n (click)=\"goToFirst()\"\n >\n <span aria-hidden=\"true\">&laquo;</span>\n </button>\n\n <button\n type=\"button\"\n class=\"geo-table-pagination__btn\"\n title=\"Trang tr\u01B0\u1EDBc\"\n [disabled]=\"isFirstPage\"\n (click)=\"goToPrev()\"\n >\n <span aria-hidden=\"true\">&lsaquo;</span>\n </button>\n\n @for (page of pages; track $index) {\n @if (page === 'ellipsis') {\n <span class=\"geo-table-pagination__ellipsis\" aria-hidden=\"true\">...</span>\n } @else {\n <button\n type=\"button\"\n class=\"geo-table-pagination__btn geo-table-pagination__btn--page\"\n [class.geo-table-pagination__btn--active]=\"page === pageIndex\"\n [attr.aria-current]=\"page === pageIndex ? 'page' : null\"\n [attr.aria-label]=\"'Trang ' + page\"\n (click)=\"goToPage(page)\"\n >\n {{ page }}\n </button>\n }\n }\n\n <button\n type=\"button\"\n class=\"geo-table-pagination__btn\"\n title=\"Trang k\u1EBF\"\n [disabled]=\"isLastPage\"\n (click)=\"goToNext()\"\n >\n <span aria-hidden=\"true\">&rsaquo;</span>\n </button>\n\n <button\n type=\"button\"\n class=\"geo-table-pagination__btn\"\n title=\"Trang cu\u1ED1i\"\n [disabled]=\"isLastPage\"\n (click)=\"goToLast()\"\n >\n <span aria-hidden=\"true\">&raquo;</span>\n </button>\n </div>\n </div>\n}\n", styles: [":host{display:block}.geo-table-pagination{display:flex;align-items:center;justify-content:space-between;gap:16px;padding-top:16px;flex-wrap:wrap}.geo-table-pagination__left{display:flex;align-items:center;gap:16px;flex-wrap:wrap}.geo-table-pagination__total{margin:0;font-size:14px;line-height:20px;color:var(--geo-color-neutral-700);white-space:nowrap}.geo-table-pagination__total strong{color:var(--geo-color-neutral-900);font-weight:600}.geo-table-pagination__size{display:inline-flex;align-items:center;gap:8px}.geo-table-pagination__size-label{font-size:14px;line-height:20px;color:var(--geo-color-neutral-700);white-space:nowrap}.geo-table-pagination__size-select{width:72px}.geo-table-pagination__nav{display:inline-flex;align-items:center;gap:8px;margin-left:auto}.geo-table-pagination__btn{display:inline-flex;align-items:center;justify-content:center;min-width:32px;height:32px;padding:0 8px;border:1px solid var(--geo-color-primary-border);border-radius:var(--geo-radius);background:var(--geo-color-neutral-white);color:var(--geo-color-neutral-900);font-size:14px;line-height:1;cursor:pointer;transition:border-color .15s ease,color .15s ease}.geo-table-pagination__btn:hover:not(:disabled){border-color:var(--geo-color-primary-default);color:var(--geo-color-primary-default)}.geo-table-pagination__btn:disabled{cursor:not-allowed;color:var(--geo-color-neutral-300);border-color:var(--geo-color-primary-border);background:var(--geo-color-neutral-white)}.geo-table-pagination__btn--page{min-width:32px;padding:0;font-weight:400}.geo-table-pagination__btn--active{border-color:var(--geo-color-primary-default)!important;color:var(--geo-color-primary-default)!important;background:var(--geo-color-neutral-white);font-weight:500}.geo-table-pagination__ellipsis{display:inline-flex;align-items:center;justify-content:center;min-width:32px;height:32px;color:var(--geo-color-neutral-900);font-size:14px;letter-spacing:1px;-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: NgZorroAntdModule }, { kind: "component", type: GeoSelectComponent, selector: "geo-select", inputs: ["options", "label", "placeholder", "size", "mode", "disabled", "required", "error", "errorMessage", "allowClear", "showSearch", "block", "width"], outputs: ["valueChange"] }] });
2759
+ }
2760
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTablePaginationComponent, decorators: [{
2761
+ type: Component,
2762
+ args: [{ selector: 'geo-table-pagination', standalone: true, imports: [CommonModule, FormsModule, NgZorroAntdModule, GeoSelectComponent], template: "@if (visible) {\n <div class=\"geo-table-pagination\">\n <div class=\"geo-table-pagination__left\">\n @if (showTotalRange) {\n <p class=\"geo-table-pagination__total\">\n <strong>{{ rangeStart }}-{{ rangeEnd }}</strong> tr\u00EAn t\u1ED5ng <strong>{{ total }}</strong>\n </p>\n }\n\n @if (showSizeChanger) {\n <div class=\"geo-table-pagination__size\">\n <span class=\"geo-table-pagination__size-label\">{{ sizeLabel }}</span>\n <geo-select\n class=\"geo-table-pagination__size-select\"\n size=\"small\"\n [options]=\"sizeOptions\"\n [allowClear]=\"false\"\n [ngModel]=\"pageSize\"\n (valueChange)=\"onPageSizeChange($event)\"\n ></geo-select>\n </div>\n }\n </div>\n\n <div class=\"geo-table-pagination__nav\" role=\"navigation\" aria-label=\"Ph\u00E2n trang\">\n <button\n type=\"button\"\n class=\"geo-table-pagination__btn\"\n title=\"Trang \u0111\u1EA7u\"\n [disabled]=\"isFirstPage\"\n (click)=\"goToFirst()\"\n >\n <span aria-hidden=\"true\">&laquo;</span>\n </button>\n\n <button\n type=\"button\"\n class=\"geo-table-pagination__btn\"\n title=\"Trang tr\u01B0\u1EDBc\"\n [disabled]=\"isFirstPage\"\n (click)=\"goToPrev()\"\n >\n <span aria-hidden=\"true\">&lsaquo;</span>\n </button>\n\n @for (page of pages; track $index) {\n @if (page === 'ellipsis') {\n <span class=\"geo-table-pagination__ellipsis\" aria-hidden=\"true\">...</span>\n } @else {\n <button\n type=\"button\"\n class=\"geo-table-pagination__btn geo-table-pagination__btn--page\"\n [class.geo-table-pagination__btn--active]=\"page === pageIndex\"\n [attr.aria-current]=\"page === pageIndex ? 'page' : null\"\n [attr.aria-label]=\"'Trang ' + page\"\n (click)=\"goToPage(page)\"\n >\n {{ page }}\n </button>\n }\n }\n\n <button\n type=\"button\"\n class=\"geo-table-pagination__btn\"\n title=\"Trang k\u1EBF\"\n [disabled]=\"isLastPage\"\n (click)=\"goToNext()\"\n >\n <span aria-hidden=\"true\">&rsaquo;</span>\n </button>\n\n <button\n type=\"button\"\n class=\"geo-table-pagination__btn\"\n title=\"Trang cu\u1ED1i\"\n [disabled]=\"isLastPage\"\n (click)=\"goToLast()\"\n >\n <span aria-hidden=\"true\">&raquo;</span>\n </button>\n </div>\n </div>\n}\n", styles: [":host{display:block}.geo-table-pagination{display:flex;align-items:center;justify-content:space-between;gap:16px;padding-top:16px;flex-wrap:wrap}.geo-table-pagination__left{display:flex;align-items:center;gap:16px;flex-wrap:wrap}.geo-table-pagination__total{margin:0;font-size:14px;line-height:20px;color:var(--geo-color-neutral-700);white-space:nowrap}.geo-table-pagination__total strong{color:var(--geo-color-neutral-900);font-weight:600}.geo-table-pagination__size{display:inline-flex;align-items:center;gap:8px}.geo-table-pagination__size-label{font-size:14px;line-height:20px;color:var(--geo-color-neutral-700);white-space:nowrap}.geo-table-pagination__size-select{width:72px}.geo-table-pagination__nav{display:inline-flex;align-items:center;gap:8px;margin-left:auto}.geo-table-pagination__btn{display:inline-flex;align-items:center;justify-content:center;min-width:32px;height:32px;padding:0 8px;border:1px solid var(--geo-color-primary-border);border-radius:var(--geo-radius);background:var(--geo-color-neutral-white);color:var(--geo-color-neutral-900);font-size:14px;line-height:1;cursor:pointer;transition:border-color .15s ease,color .15s ease}.geo-table-pagination__btn:hover:not(:disabled){border-color:var(--geo-color-primary-default);color:var(--geo-color-primary-default)}.geo-table-pagination__btn:disabled{cursor:not-allowed;color:var(--geo-color-neutral-300);border-color:var(--geo-color-primary-border);background:var(--geo-color-neutral-white)}.geo-table-pagination__btn--page{min-width:32px;padding:0;font-weight:400}.geo-table-pagination__btn--active{border-color:var(--geo-color-primary-default)!important;color:var(--geo-color-primary-default)!important;background:var(--geo-color-neutral-white);font-weight:500}.geo-table-pagination__ellipsis{display:inline-flex;align-items:center;justify-content:center;min-width:32px;height:32px;color:var(--geo-color-neutral-900);font-size:14px;letter-spacing:1px;-webkit-user-select:none;user-select:none}\n"] }]
2763
+ }], propDecorators: { pageIndex: [{
2764
+ type: Input
2765
+ }], pageSize: [{
2766
+ type: Input
2767
+ }], total: [{
2768
+ type: Input
2769
+ }], pageSizeOptions: [{
2770
+ type: Input
2771
+ }], showSizeChanger: [{
2772
+ type: Input
2773
+ }], hideOnSinglePage: [{
2774
+ type: Input
2775
+ }], showTotalRange: [{
2776
+ type: Input
2777
+ }], sizeLabel: [{
2778
+ type: Input
2779
+ }], pageIndexChange: [{
2780
+ type: Output
2781
+ }], pageSizeChange: [{
2782
+ type: Output
2783
+ }] } });
2784
+
2785
+ class GeoTableComponent {
2786
+ columns = [];
2787
+ data = [];
2788
+ loading = false;
2789
+ bordered = true;
2790
+ outerBordered = false;
2791
+ size = 'middle';
2792
+ striped = true;
2793
+ clickable = true;
2794
+ tableLayout = 'auto';
2795
+ showPagination = true;
2796
+ frontPagination = true;
2797
+ pageIndex = 1;
2798
+ pageSize = 10;
2799
+ total;
2800
+ pageSizeOptions = DEFAULT_UI_TABLE_PAGE_SIZE_OPTIONS;
2801
+ showSizeChanger = false;
2802
+ showQuickJumper = false;
2803
+ hideOnSinglePage = false;
2804
+ simplePagination = false;
2805
+ paginationPosition = 'bottom';
2806
+ scroll = {};
2807
+ scrollY;
2808
+ /**
2809
+ * Tự bật scroll ngang theo tổng width cột.
2810
+ * Khi có cột `fixed`, scroll.x luôn được tính (bắt buộc với nz-table fixed).
2811
+ */
2812
+ autoScroll = false;
2813
+ tableTitle;
2814
+ footer;
2815
+ emptyText = 'Không có dữ liệu';
2816
+ showTotalRange = false;
2817
+ selectable = false;
2818
+ rowKey = 'id';
2819
+ selectedKeys = [];
2820
+ /**
2821
+ * Mobile card: key cột làm tiêu đề.
2822
+ * Ưu tiên hơn `column.mobileTitle`; nếu không set thì lấy cột dữ liệu đầu tiên.
2823
+ */
2824
+ mobileTitleKey;
2825
+ /** Bật/tắt chuyển card trên mobile (mặc định bật). */
2826
+ mobileCardView = true;
2827
+ rowClick = new EventEmitter();
2828
+ rowEdit = new EventEmitter();
2829
+ rowMore = new EventEmitter();
2830
+ rowAction = new EventEmitter();
2831
+ pageIndexChange = new EventEmitter();
2832
+ pageSizeChange = new EventEmitter();
2833
+ queryParams = new EventEmitter();
2834
+ currentPageDataChange = new EventEmitter();
2835
+ selectedKeysChange = new EventEmitter();
2836
+ selectionChange = new EventEmitter();
2837
+ allChecked = false;
2838
+ indeterminate = false;
2839
+ sortFnCache = new Map();
2840
+ ngOnChanges(changes) {
2841
+ if (changes['columns']) {
2842
+ this.sortFnCache.clear();
2843
+ }
2844
+ }
2845
+ get visibleColumns() {
2846
+ return this.columns.filter((col) => col.visible !== false);
2847
+ }
2848
+ get computedTotal() {
2849
+ return this.total ?? this.data.length;
2850
+ }
2851
+ get paginatedData() {
2852
+ if (!this.showPagination || !this.frontPagination) {
2853
+ return this.data;
2854
+ }
2855
+ const start = (this.pageIndex - 1) * this.pageSize;
2856
+ return this.data.slice(start, start + this.pageSize);
2857
+ }
2858
+ get shouldShowPagination() {
2859
+ return this.showPagination;
2860
+ }
2861
+ get hasFixedColumns() {
2862
+ return this.visibleColumns.some((col) => col.fixed === 'left' || col.fixed === 'right');
2863
+ }
2864
+ /** Có cột fixed → table-layout fixed để header/body cùng width cột. */
2865
+ get computedTableLayout() {
2866
+ return this.hasFixedColumns ? 'fixed' : this.tableLayout;
2867
+ }
2868
+ /** Đồng bộ width cột khi scrollY tách header/body thành 2 bảng. */
2869
+ get widthConfig() {
2870
+ const widths = this.visibleColumns.map((col) => col.width ?? null);
2871
+ return this.selectable ? ['48px', ...widths] : widths;
2872
+ }
2873
+ get computedScroll() {
2874
+ const scroll = { ...this.scroll };
2875
+ if (this.scrollY) {
2876
+ scroll.y = this.scrollY;
2877
+ }
2878
+ // nz-table cần scroll.x để fixed left/right hoạt động.
2879
+ if (!scroll.x && (this.autoScroll || this.hasFixedColumns)) {
2880
+ const minWidth = this.computeMinTableWidth();
2881
+ if (minWidth > 0) {
2882
+ scroll.x = `${minWidth}px`;
2883
+ }
2884
+ }
2885
+ return scroll;
2886
+ }
2887
+ get mobileTitleColumn() {
2888
+ if (this.mobileTitleKey) {
2889
+ return this.visibleColumns.find((col) => col.key === this.mobileTitleKey) ?? null;
2890
+ }
2891
+ const marked = this.visibleColumns.find((col) => col.mobileTitle);
2892
+ if (marked)
2893
+ return marked;
2894
+ return (this.visibleColumns.find((col) => col.renderAs !== 'index' &&
2895
+ col.renderAs !== 'actions' &&
2896
+ !col.mobileHidden) ?? null);
2897
+ }
2898
+ get mobileBodyColumns() {
2899
+ const titleKey = this.mobileTitleColumn?.key;
2900
+ return this.visibleColumns.filter((col) => col.renderAs !== 'actions' &&
2901
+ col.renderAs !== 'index' &&
2902
+ !col.mobileHidden &&
2903
+ col.key !== titleKey);
2904
+ }
2905
+ get mobileActionsColumn() {
2906
+ return this.visibleColumns.find((col) => col.renderAs === 'actions') ?? null;
2907
+ }
2908
+ getRowActions(col, row) {
2909
+ if (col.resolveActions) {
2910
+ return col.resolveActions(row) ?? [];
2911
+ }
2912
+ return col.actions ?? [];
2913
+ }
2914
+ getMobileHeaderActions(col, row) {
2915
+ return pickInlineRowActions(this.getRowActions(col, row), col.primaryActionKey ?? 'edit');
2916
+ }
2917
+ getMobileFooterActions(col, row) {
2918
+ return pickOverflowRowActions(this.getRowActions(col, row), col.primaryActionKey ?? 'edit');
2919
+ }
2920
+ hasFilters(col) {
2921
+ return (col.filters?.length ?? 0) > 0;
2922
+ }
2923
+ getSortFn(col) {
2924
+ if (col.sortFn) {
2925
+ return col.sortFn;
2926
+ }
2927
+ const cached = this.sortFnCache.get(col.key);
2928
+ if (cached) {
2929
+ return cached;
2930
+ }
2931
+ const fn = (a, b) => {
2932
+ const av = a[col.key];
2933
+ const bv = b[col.key];
2934
+ if (av == null || bv == null)
2935
+ return 0;
2936
+ return String(av).localeCompare(String(bv), 'vi');
2937
+ };
2938
+ this.sortFnCache.set(col.key, fn);
2939
+ return fn;
2940
+ }
2941
+ getCellValue(row, key) {
2942
+ const value = row[key];
2943
+ return value == null ? '' : String(value);
2944
+ }
2945
+ /** Tiêu đề cột luôn căn giữa theo quy tắc accessibility */
2946
+ getHeaderAlign(_col) {
2947
+ return 'center';
2948
+ }
2949
+ /**
2950
+ * Căn lề ô dữ liệu:
2951
+ * - text → trái, number → phải, date → giữa
2952
+ * - index / status / actions → giữa
2953
+ */
2954
+ getCellAlign(col) {
2955
+ if (col.align) {
2956
+ return col.align;
2957
+ }
2958
+ if (col.renderAs === 'index' || col.renderAs === 'status' || col.renderAs === 'actions') {
2959
+ return 'center';
2960
+ }
2961
+ if (col.dataType === 'number') {
2962
+ return 'right';
2963
+ }
2964
+ if (col.dataType === 'date') {
2965
+ return 'center';
2966
+ }
2967
+ return 'left';
2968
+ }
2969
+ getRowIndex(rowIndex) {
2970
+ return (this.pageIndex - 1) * this.pageSize + rowIndex + 1;
2971
+ }
2972
+ trackRow(index, row) {
2973
+ const key = row[this.rowKey];
2974
+ return key != null ? String(key) : String(index);
2975
+ }
2976
+ isRowSelected(row) {
2977
+ const key = String(row[this.rowKey] ?? '');
2978
+ return this.selectedKeys.includes(key);
2979
+ }
2980
+ onAllChecked(checked) {
2981
+ const rows = this.selectionRows;
2982
+ const keys = rows.map((row) => String(row[this.rowKey] ?? ''));
2983
+ if (checked) {
2984
+ this.selectedKeys = [...new Set([...this.selectedKeys, ...keys])];
2985
+ }
2986
+ else {
2987
+ this.selectedKeys = this.selectedKeys.filter((key) => !keys.includes(key));
2988
+ }
2989
+ this.refreshSelectionState();
2990
+ this.emitSelection();
2991
+ }
2992
+ onItemChecked(row, checked) {
2993
+ const key = String(row[this.rowKey] ?? '');
2994
+ this.selectedKeys = checked
2995
+ ? [...this.selectedKeys, key]
2996
+ : this.selectedKeys.filter((k) => k !== key);
2997
+ this.refreshSelectionState();
2998
+ this.emitSelection();
2999
+ }
3000
+ onPageIndexChange(index) {
3001
+ this.pageIndex = index;
3002
+ this.refreshSelectionState();
3003
+ this.pageIndexChange.emit(index);
3004
+ }
3005
+ onPageSizeChange(size) {
3006
+ this.pageSize = size;
3007
+ this.pageIndex = 1;
3008
+ this.refreshSelectionState();
3009
+ this.pageSizeChange.emit(size);
3010
+ }
3011
+ onRowActionClick(row, actionKey) {
3012
+ this.rowAction.emit({ row, action: actionKey });
3013
+ if (actionKey === 'edit') {
3014
+ this.rowEdit.emit(row);
3015
+ }
3016
+ if (actionKey === 'more') {
3017
+ this.rowMore.emit(row);
3018
+ }
3019
+ }
3020
+ onMobileCardClick(row, event) {
3021
+ if (!this.clickable)
3022
+ return;
3023
+ const target = event.target;
3024
+ if (target?.closest('button, a, .geo-row-actions, .geo-checkbox, .geo-table-card__footer')) {
3025
+ return;
3026
+ }
3027
+ this.rowClick.emit(row);
3028
+ }
3029
+ computeMinTableWidth() {
3030
+ let total = this.selectable ? 48 : 0;
3031
+ for (const col of this.visibleColumns) {
3032
+ const width = col.width;
3033
+ if (width?.endsWith('px')) {
3034
+ total += Number.parseInt(width, 10);
3035
+ }
3036
+ else {
3037
+ total += 160;
3038
+ }
3039
+ }
3040
+ return total;
3041
+ }
3042
+ refreshSelectionState() {
3043
+ const rows = this.selectionRows;
3044
+ const selectedOnPage = rows.filter((row) => this.selectedKeys.includes(String(row[this.rowKey] ?? ''))).length;
3045
+ this.allChecked = selectedOnPage > 0 && selectedOnPage === rows.length;
3046
+ this.indeterminate = selectedOnPage > 0 && selectedOnPage < rows.length;
3047
+ this.selectedKeysChange.emit([...this.selectedKeys]);
3048
+ }
3049
+ get selectionRows() {
3050
+ return this.showPagination && this.frontPagination ? this.paginatedData : this.data;
3051
+ }
3052
+ emitSelection() {
3053
+ const selected = this.data.filter((row) => this.selectedKeys.includes(String(row[this.rowKey] ?? '')));
3054
+ this.selectionChange.emit(selected);
3055
+ }
3056
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3057
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoTableComponent, isStandalone: true, selector: "geo-table", inputs: { columns: "columns", data: "data", loading: "loading", bordered: "bordered", outerBordered: "outerBordered", size: "size", striped: "striped", clickable: "clickable", tableLayout: "tableLayout", showPagination: "showPagination", frontPagination: "frontPagination", pageIndex: "pageIndex", pageSize: "pageSize", total: "total", pageSizeOptions: "pageSizeOptions", showSizeChanger: "showSizeChanger", showQuickJumper: "showQuickJumper", hideOnSinglePage: "hideOnSinglePage", simplePagination: "simplePagination", paginationPosition: "paginationPosition", scroll: "scroll", scrollY: "scrollY", autoScroll: "autoScroll", tableTitle: "tableTitle", footer: "footer", emptyText: "emptyText", showTotalRange: "showTotalRange", selectable: "selectable", rowKey: "rowKey", selectedKeys: "selectedKeys", mobileTitleKey: "mobileTitleKey", mobileCardView: "mobileCardView" }, outputs: { rowClick: "rowClick", rowEdit: "rowEdit", rowMore: "rowMore", rowAction: "rowAction", pageIndexChange: "pageIndexChange", pageSizeChange: "pageSizeChange", queryParams: "queryParams", currentPageDataChange: "currentPageDataChange", selectedKeysChange: "selectedKeysChange", selectionChange: "selectionChange" }, usesOnChanges: true, ngImport: i0, template: "<div\n class=\"geo-table\"\n [class.geo-table--striped]=\"striped\"\n [class.geo-table--mobile-cards]=\"mobileCardView\"\n>\n @if (shouldShowPagination && (paginationPosition === 'top' || paginationPosition === 'both')) {\n <geo-table-pagination\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [total]=\"computedTotal\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [showSizeChanger]=\"showSizeChanger\"\n [hideOnSinglePage]=\"hideOnSinglePage\"\n [showTotalRange]=\"showTotalRange\"\n (pageIndexChange)=\"onPageIndexChange($event)\"\n (pageSizeChange)=\"onPageSizeChange($event)\"\n ></geo-table-pagination>\n }\n\n <div class=\"geo-table__desktop\">\n <nz-table\n #uiTable\n [nzData]=\"paginatedData\"\n [nzLoading]=\"loading\"\n [nzBordered]=\"bordered\"\n [nzOuterBordered]=\"outerBordered\"\n [nzSize]=\"size\"\n [nzTitle]=\"tableTitle ?? null\"\n [nzFooter]=\"footer ?? null\"\n [nzShowPagination]=\"false\"\n [nzFrontPagination]=\"false\"\n [nzScroll]=\"computedScroll\"\n [nzNoResult]=\"emptyText\"\n [nzTableLayout]=\"computedTableLayout\"\n [nzWidthConfig]=\"widthConfig\"\n (nzQueryParams)=\"queryParams.emit($event)\"\n (nzCurrentPageDataChange)=\"currentPageDataChange.emit($event)\"\n >\n <thead>\n <tr>\n @if (selectable) {\n <th\n class=\"geo-table__checkbox-cell\"\n nzWidth=\"48px\"\n [nzLeft]=\"hasFixedColumns\"\n >\n <geo-checkbox\n [checked]=\"allChecked\"\n [indeterminate]=\"indeterminate\"\n (checkedChange)=\"onAllChecked($event)\"\n ></geo-checkbox>\n </th>\n }\n @for (col of visibleColumns; track col.key) {\n <th\n [nzWidth]=\"col.width ?? null\"\n [nzAlign]=\"getHeaderAlign(col)\"\n [nzColumnKey]=\"col.key\"\n [nzShowSort]=\"col.sortable ?? false\"\n [nzSortOrder]=\"col.sortOrder ?? null\"\n [nzSortFn]=\"col.sortable ? getSortFn(col) : null\"\n [nzShowFilter]=\"hasFilters(col)\"\n [nzFilters]=\"col.filters ?? []\"\n [nzFilterMultiple]=\"col.filterMultiple ?? true\"\n [nzLeft]=\"col.fixed === 'left'\"\n [nzRight]=\"col.fixed === 'right'\"\n >{{ col.title }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of uiTable.data; track trackRow($index, row); let rowIndex = $index) {\n <tr\n class=\"geo-table__row\"\n [class.geo-table__row--selected]=\"isRowSelected(row)\"\n [class.geo-table__row--clickable]=\"clickable\"\n (click)=\"clickable && rowClick.emit(row)\"\n >\n @if (selectable) {\n <td\n class=\"geo-table__checkbox-cell\"\n [nzLeft]=\"hasFixedColumns\"\n (click)=\"$event.stopPropagation()\"\n >\n <geo-checkbox\n [checked]=\"isRowSelected(row)\"\n (checkedChange)=\"onItemChecked(row, $event)\"\n ></geo-checkbox>\n </td>\n }\n @for (col of visibleColumns; track col.key) {\n <td\n [nzAlign]=\"getCellAlign(col)\"\n [nzEllipsis]=\"col.wrap ? false : (col.ellipsis ?? false)\"\n [class.geo-table__cell--wrap]=\"col.wrap\"\n [nzLeft]=\"col.fixed === 'left'\"\n [nzRight]=\"col.fixed === 'right'\"\n [style.width]=\"col.width || null\"\n [style.minWidth]=\"col.width || null\"\n [style.maxWidth]=\"col.fixed ? (col.width || null) : null\"\n >\n @if (col.renderAs === 'index') {\n {{ getRowIndex(rowIndex) }}\n } @else if (col.renderAs === 'status') {\n <geo-status-tag\n [status]=\"getCellValue(row, col.key)\"\n [label]=\"col.statusLabelKey ? getCellValue(row, col.statusLabelKey) || undefined : undefined\"\n ></geo-status-tag>\n } @else if (col.renderAs === 'actions') {\n <geo-row-actions\n [actions]=\"getRowActions(col, row)\"\n [primaryActionKey]=\"col.primaryActionKey ?? 'edit'\"\n (actionClick)=\"onRowActionClick(row, $event)\"\n ></geo-row-actions>\n } @else {\n {{ getCellValue(row, col.key) }}\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </nz-table>\n </div>\n\n @if (mobileCardView) {\n <div\n class=\"geo-table__mobile\"\n [class.geo-table__mobile--loading]=\"loading\"\n [attr.aria-busy]=\"loading ? 'true' : null\"\n >\n @if (selectable && paginatedData.length) {\n <div class=\"geo-table-card__select-all\">\n <geo-checkbox\n [checked]=\"allChecked\"\n [indeterminate]=\"indeterminate\"\n (checkedChange)=\"onAllChecked($event)\"\n ></geo-checkbox>\n <span>Ch\u1ECDn t\u1EA5t c\u1EA3 tr\u00EAn trang</span>\n </div>\n }\n\n @if (!paginatedData.length && !loading) {\n <div class=\"geo-table__mobile-empty\">{{ emptyText }}</div>\n }\n\n @for (row of paginatedData; track trackRow($index, row); let rowIndex = $index) {\n <article\n class=\"geo-table-card\"\n [class.geo-table-card--selected]=\"isRowSelected(row)\"\n [class.geo-table-card--clickable]=\"clickable\"\n (click)=\"onMobileCardClick(row, $event)\"\n >\n <header class=\"geo-table-card__header\">\n <div class=\"geo-table-card__title-wrap\">\n @if (selectable) {\n <geo-checkbox\n class=\"geo-table-card__checkbox\"\n [checked]=\"isRowSelected(row)\"\n (checkedChange)=\"onItemChecked(row, $event)\"\n (click)=\"$event.stopPropagation()\"\n ></geo-checkbox>\n }\n @if (mobileTitleColumn; as titleCol) {\n <h3 class=\"geo-table-card__title\">\n <span class=\"geo-table-card__title-label\">{{ titleCol.title }}</span>\n <span class=\"geo-table-card__title-sep\">:</span>\n <span class=\"geo-table-card__title-value\">\n @if (titleCol.renderAs === 'index') {\n {{ getRowIndex(rowIndex) }}\n } @else {\n {{ getCellValue(row, titleCol.key) }}\n }\n </span>\n </h3>\n }\n </div>\n\n @if (mobileActionsColumn; as actionsCol) {\n <div class=\"geo-table-card__actions\" (click)=\"$event.stopPropagation()\">\n <geo-row-actions\n [actions]=\"getMobileHeaderActions(actionsCol, row)\"\n [primaryActionKey]=\"actionsCol.primaryActionKey ?? 'edit'\"\n (actionClick)=\"onRowActionClick(row, $event)\"\n ></geo-row-actions>\n </div>\n }\n </header>\n\n @if (mobileBodyColumns.length) {\n <div class=\"geo-table-card__body\">\n @for (col of mobileBodyColumns; track col.key) {\n <div class=\"geo-table-card__row\">\n <span class=\"geo-table-card__label\">{{ col.title }}</span>\n <span class=\"geo-table-card__sep\">:</span>\n <span class=\"geo-table-card__value\">\n @if (col.renderAs === 'index') {\n {{ getRowIndex(rowIndex) }}\n } @else if (col.renderAs === 'status') {\n <geo-status-tag\n [status]=\"getCellValue(row, col.key)\"\n [label]=\"col.statusLabelKey ? getCellValue(row, col.statusLabelKey) || undefined : undefined\"\n ></geo-status-tag>\n } @else {\n {{ getCellValue(row, col.key) }}\n }\n </span>\n </div>\n }\n </div>\n }\n\n @if (mobileActionsColumn; as actionsCol) {\n @if (getMobileFooterActions(actionsCol, row); as footerActions) {\n @if (footerActions.length) {\n <footer class=\"geo-table-card__footer\" (click)=\"$event.stopPropagation()\">\n @for (action of footerActions; track action.key) {\n <button\n type=\"button\"\n class=\"geo-table-card__footer-btn\"\n [class.geo-table-card__footer-btn--danger]=\"action.danger\"\n [disabled]=\"action.disabled\"\n (click)=\"onRowActionClick(row, action.key)\"\n >\n {{ action.label ?? action.title ?? action.key }}\n </button>\n }\n </footer>\n }\n }\n }\n </article>\n }\n </div>\n }\n\n @if (shouldShowPagination && (paginationPosition === 'bottom' || paginationPosition === 'both')) {\n <geo-table-pagination\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [total]=\"computedTotal\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [showSizeChanger]=\"showSizeChanger\"\n [hideOnSinglePage]=\"hideOnSinglePage\"\n [showTotalRange]=\"showTotalRange\"\n (pageIndexChange)=\"onPageIndexChange($event)\"\n (pageSizeChange)=\"onPageSizeChange($event)\"\n ></geo-table-pagination>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;max-width:100%;min-width:0}.geo-table{width:100%;max-width:100%;min-width:0;border-radius:var(--geo-radius);overflow:clip}.geo-table__row--clickable{cursor:pointer}.geo-table__row--selected>td{background:var(--geo-color-primary-background)}:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row:nth-child(2n of.geo-table__row)>td{background:var(--geo-color-neutral-100)}:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row:nth-child(2n of.geo-table__row)>td.ant-table-cell-fix-left,:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row:nth-child(2n of.geo-table__row)>td.ant-table-cell-fix-right{background:var(--geo-color-neutral-100)}:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row:nth-child(2n of.geo-table__row):hover>td,:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row:nth-child(2n of.geo-table__row):hover>td.ant-table-cell-fix-left,:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row:nth-child(2n of.geo-table__row):hover>td.ant-table-cell-fix-right{background:var(--geo-color-primary-background)}:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row--selected>td,:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row--selected>td.ant-table-cell-fix-left,:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row--selected>td.ant-table-cell-fix-right{background:var(--geo-color-primary-background)}.geo-table__checkbox-cell{text-align:center;vertical-align:middle;padding-left:12px!important;padding-right:12px!important}.geo-table__cell--wrap{white-space:normal;word-break:break-word;overflow-wrap:anywhere}:host ::ng-deep .geo-table .ant-table{background:var(--geo-color-neutral-white);border-radius:var(--geo-radius)}:host ::ng-deep .geo-table .ant-table-container{border-radius:var(--geo-radius)}:host ::ng-deep .geo-table .ant-table-thead>tr>th{background:var(--geo-color-neutral-100)!important;color:var(--geo-color-neutral-900)!important;font-weight:600;font-size:14px;line-height:20px;height:44px;padding:12px 10px!important;white-space:nowrap;text-align:center;border-bottom:1px solid var(--geo-color-primary-border)!important;box-sizing:border-box}:host ::ng-deep .geo-table .ant-table-body>table>thead{display:none!important}:host ::ng-deep .geo-table .ant-table-tbody>tr.ant-table-measure-now,:host ::ng-deep .geo-table .ant-table-tbody>tr[nz-table-measure-row]{height:0!important;font-size:0!important;line-height:0!important}:host ::ng-deep .geo-table .ant-table-tbody>tr.ant-table-measure-now>td,:host ::ng-deep .geo-table .ant-table-tbody>tr[nz-table-measure-row]>td{padding:0!important;border:0!important;height:0!important;min-height:0!important;line-height:0!important;font-size:0!important}:host ::ng-deep .geo-table .ant-table-tbody>tr>td{color:var(--geo-color-neutral-900);font-size:14px;line-height:normal;min-height:48px;padding:12px 10px!important;vertical-align:middle;border-bottom:1px solid var(--geo-color-primary-border)!important;box-sizing:border-box}:host ::ng-deep .geo-table .ant-table-tbody>tr:hover>td{background:var(--geo-color-primary-background)}:host ::ng-deep .geo-table .ant-table-bordered .ant-table-container{border-color:var(--geo-color-primary-border)}:host ::ng-deep .geo-table .geo-table__row-actions{display:inline-flex;align-items:center;justify-content:center;gap:10px}:host ::ng-deep .geo-table .geo-table__action-icon{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:var(--geo-radius);background:transparent;color:var(--geo-color-neutral-500);cursor:pointer;transition:color .15s ease,background-color .15s ease}:host ::ng-deep .geo-table .geo-table__action-icon:hover{color:var(--geo-color-primary-default);background:color-mix(in srgb,var(--geo-color-primary-default) 10%,transparent)}:host ::ng-deep .geo-table .ant-table-wrapper,:host ::ng-deep .geo-table .ant-spin-nested-loading,:host ::ng-deep .geo-table .ant-spin-container{width:100%;max-width:100%}:host ::ng-deep .geo-table .ant-table{width:100%}:host ::ng-deep .geo-table .ant-table-container{border-radius:var(--geo-radius);overflow:clip}:host ::ng-deep .geo-table .ant-table-body{overflow-x:auto!important;-webkit-overflow-scrolling:touch}:host ::ng-deep .geo-table .ant-table-content{overflow-x:auto;-webkit-overflow-scrolling:touch}:host ::ng-deep .geo-table .ant-table-header.nz-table-hide-scrollbar{overflow-x:hidden!important;overflow-y:scroll!important;scrollbar-gutter:stable}:host ::ng-deep .geo-table .ant-table-body{scrollbar-gutter:stable}:host ::ng-deep .geo-table .ant-table-cell-fix-left,:host ::ng-deep .geo-table .ant-table-cell-fix-right{background:var(--geo-color-neutral-white)}:host ::ng-deep .geo-table .ant-table-thead>tr>th.ant-table-cell-fix-left,:host ::ng-deep .geo-table .ant-table-thead>tr>th.ant-table-cell-fix-right{background:var(--geo-color-neutral-100)!important}:host ::ng-deep .geo-table .ant-table-tbody>tr:hover>td.ant-table-cell-fix-left,:host ::ng-deep .geo-table .ant-table-tbody>tr:hover>td.ant-table-cell-fix-right{background:var(--geo-color-primary-background)}:host ::ng-deep .geo-table .ant-table-thead>tr>th.ant-table-cell-fix-left,:host ::ng-deep .geo-table .ant-table-thead>tr>th.ant-table-cell-fix-right,:host ::ng-deep .geo-table .ant-table-tbody>tr>td.ant-table-cell-fix-left,:host ::ng-deep .geo-table .ant-table-tbody>tr>td.ant-table-cell-fix-right{box-sizing:border-box}:host ::ng-deep .geo-table .ant-table-ping-left:not(.ant-table-ping-right) .ant-table-cell-fix-left-last:after{box-shadow:inset 10px 0 8px -8px #0000001f}:host ::ng-deep .geo-table .ant-table-ping-right:not(.ant-table-ping-left) .ant-table-cell-fix-right-first:after{box-shadow:inset -10px 0 8px -8px #0000001f}.geo-table__mobile{display:none}@media (max-width: 767.98px){.geo-table--mobile-cards{overflow:visible}.geo-table--mobile-cards .geo-table__desktop{display:none}.geo-table--mobile-cards .geo-table__mobile{display:flex;flex-direction:column;gap:12px;padding:0}}.geo-table__mobile--loading{opacity:.55;pointer-events:none}.geo-table__mobile-empty{padding:32px 16px;text-align:center;color:var(--geo-color-neutral-500);font-size:14px;background:var(--geo-color-neutral-white);border:1px solid var(--geo-color-primary-border);border-radius:var(--geo-radius)}.geo-table-card__select-all{display:flex;align-items:center;gap:8px;padding:8px 4px;font-size:14px;color:var(--geo-color-neutral-700)}.geo-table-card{background:var(--geo-color-neutral-white);border:1px solid var(--geo-color-primary-border);border-radius:var(--geo-radius);box-shadow:0 1px 2px #0000000a;overflow:hidden}.geo-table-card--clickable{cursor:pointer}.geo-table-card--selected{border-color:var(--geo-color-primary-light);box-shadow:0 0 0 1px color-mix(in srgb,var(--geo-color-primary-default) 25%,transparent)}.geo-table-card__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:14px 14px 10px}.geo-table-card__title-wrap{display:flex;align-items:flex-start;gap:8px;min-width:0;flex:1}.geo-table-card__checkbox{flex-shrink:0;margin-top:2px}.geo-table-card__title{margin:0;min-width:0;font-size:15px;font-weight:700;line-height:1.4;color:var(--geo-color-neutral-900);word-break:break-word}.geo-table-card__title-label,.geo-table-card__title-sep,.geo-table-card__title-value{font-weight:700;color:var(--geo-color-neutral-900)}.geo-table-card__title-sep{margin-inline:4px}.geo-table-card__actions{flex-shrink:0}:host ::ng-deep .geo-table-card__actions .geo-row-actions{gap:8px}:host ::ng-deep .geo-table-card__actions .geo-row-actions__btn{width:32px;height:32px;border-radius:var(--geo-radius);background:#1890ff1a;color:var(--geo-color-info-default)}:host ::ng-deep .geo-table-card__actions .geo-row-actions__btn:hover:not(:disabled){background:#1890ff2e;color:var(--geo-color-info-dark)}:host ::ng-deep .geo-table-card__actions .geo-row-actions__btn--danger{background:#ee003314;color:var(--geo-color-error-default)}:host ::ng-deep .geo-table-card__actions .geo-row-actions__btn--danger:hover:not(:disabled){background:#ee003324;color:var(--geo-color-error-dark)}:host ::ng-deep .geo-table-card__actions .geo-row-actions__btn :deep(.anticon),:host ::ng-deep .geo-table-card__actions .geo-row-actions__btn .anticon{font-size:16px}.geo-table-card__body{display:flex;flex-direction:column;gap:10px;padding:4px 14px 14px}.geo-table-card__row{display:flex;align-items:flex-start;flex-wrap:wrap;column-gap:4px;row-gap:2px;font-size:14px;line-height:1.45}.geo-table-card__label,.geo-table-card__sep{color:var(--geo-color-neutral-700);font-weight:400;flex-shrink:0}.geo-table-card__value{color:var(--geo-color-neutral-900);font-weight:700;min-width:0;word-break:break-word}.geo-table-card__footer{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;padding:12px 14px;background:var(--geo-color-info-light);border-top:1px solid var(--geo-color-info-light)}.geo-table-card__footer-btn{appearance:none;border:0;background:transparent;padding:0 8px;min-height:24px;font-size:14px;font-weight:600;line-height:1.4;color:var(--geo-color-info-default);cursor:pointer}.geo-table-card__footer-btn:hover:not(:disabled){color:var(--geo-color-info-dark);text-decoration:underline}.geo-table-card__footer-btn:disabled{opacity:.45;cursor:not-allowed}.geo-table-card__footer-btn--danger{color:var(--geo-color-error-default)}.geo-table-card__footer-btn--danger:hover:not(:disabled){color:var(--geo-color-error-dark)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: NgZorroAntdModule }, { kind: "component", type: i1$7.NzTableComponent, selector: "nz-table", inputs: ["nzTableLayout", "nzShowTotal", "nzItemRender", "nzTitle", "nzFooter", "nzNoResult", "nzPageSizeOptions", "nzVirtualItemSize", "nzVirtualMaxBufferPx", "nzVirtualMinBufferPx", "nzVirtualForTrackBy", "nzLoadingDelay", "nzPageIndex", "nzPageSize", "nzTotal", "nzWidthConfig", "nzData", "nzCustomColumn", "nzPaginationPosition", "nzScroll", "noDataVirtualHeight", "nzPaginationType", "nzFrontPagination", "nzTemplateMode", "nzShowPagination", "nzLoading", "nzOuterBordered", "nzLoadingIndicator", "nzBordered", "nzSize", "nzShowSizeChanger", "nzHideOnSinglePage", "nzShowQuickJumper", "nzSimple"], outputs: ["nzPageSizeChange", "nzPageIndexChange", "nzQueryParams", "nzCurrentPageDataChange", "nzCustomColumnChange"], exportAs: ["nzTable"] }, { kind: "component", type: i1$7.NzThAddOnComponent, selector: "th[nzColumnKey], th[nzSortFn], th[nzSortOrder], th[nzFilters], th[nzShowSort], th[nzShowFilter], th[nzCustomFilter]", inputs: ["nzColumnKey", "nzFilterMultiple", "nzSortOrder", "nzSortPriority", "nzSortDirections", "nzFilters", "nzSortFn", "nzFilterFn", "nzShowSort", "nzShowFilter", "nzCustomFilter"], outputs: ["nzCheckedChange", "nzSortOrderChange", "nzFilterChange"] }, { kind: "directive", type: i1$7.NzTableCellDirective, selector: "th:not(.nz-disable-th):not([mat-cell]), td:not(.nz-disable-td):not([mat-cell])" }, { kind: "directive", type: i1$7.NzThMeasureDirective, selector: "th", inputs: ["nzWidth", "colspan", "colSpan", "rowspan", "rowSpan"] }, { kind: "component", type: i1$7.NzTheadComponent, selector: "thead:not(.ant-table-thead)", outputs: ["nzSortOrderChange"] }, { kind: "component", type: i1$7.NzTbodyComponent, selector: "tbody" }, { kind: "directive", type: i1$7.NzTrDirective, selector: "tr:not([mat-row]):not([mat-header-row]):not([nz-table-measure-row]):not([nzExpand]):not([nz-table-fixed-row])" }, { kind: "directive", type: i1$7.NzCellFixedDirective, selector: "td[nzRight],th[nzRight],td[nzLeft],th[nzLeft]", inputs: ["nzRight", "nzLeft", "colspan", "colSpan"] }, { kind: "directive", type: i1$7.NzCellAlignDirective, selector: "th[nzAlign],td[nzAlign]", inputs: ["nzAlign"] }, { kind: "directive", type: i1$7.NzCellEllipsisDirective, selector: "th[nzEllipsis],td[nzEllipsis]", inputs: ["nzEllipsis"] }, { kind: "component", type: GeoStatusTagComponent, selector: "geo-status-tag", inputs: ["status", "label", "showDot"] }, { kind: "component", type: GeoRowActionsComponent, selector: "geo-row-actions", inputs: ["actions", "primaryActionKey"], outputs: ["actionClick", "edit", "more"] }, { kind: "component", type: GeoCheckboxComponent, selector: "geo-checkbox", inputs: ["label", "checked", "disabled", "indeterminate"], outputs: ["checkedChange"] }, { kind: "component", type: GeoTablePaginationComponent, selector: "geo-table-pagination", inputs: ["pageIndex", "pageSize", "total", "pageSizeOptions", "showSizeChanger", "hideOnSinglePage", "showTotalRange", "sizeLabel"], outputs: ["pageIndexChange", "pageSizeChange"] }] });
3058
+ }
3059
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTableComponent, decorators: [{
3060
+ type: Component,
3061
+ args: [{ selector: 'geo-table', standalone: true, imports: [
3062
+ CommonModule,
3063
+ NgZorroAntdModule,
3064
+ GeoStatusTagComponent,
3065
+ GeoRowActionsComponent,
3066
+ GeoCheckboxComponent,
3067
+ GeoTablePaginationComponent,
3068
+ ], template: "<div\n class=\"geo-table\"\n [class.geo-table--striped]=\"striped\"\n [class.geo-table--mobile-cards]=\"mobileCardView\"\n>\n @if (shouldShowPagination && (paginationPosition === 'top' || paginationPosition === 'both')) {\n <geo-table-pagination\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [total]=\"computedTotal\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [showSizeChanger]=\"showSizeChanger\"\n [hideOnSinglePage]=\"hideOnSinglePage\"\n [showTotalRange]=\"showTotalRange\"\n (pageIndexChange)=\"onPageIndexChange($event)\"\n (pageSizeChange)=\"onPageSizeChange($event)\"\n ></geo-table-pagination>\n }\n\n <div class=\"geo-table__desktop\">\n <nz-table\n #uiTable\n [nzData]=\"paginatedData\"\n [nzLoading]=\"loading\"\n [nzBordered]=\"bordered\"\n [nzOuterBordered]=\"outerBordered\"\n [nzSize]=\"size\"\n [nzTitle]=\"tableTitle ?? null\"\n [nzFooter]=\"footer ?? null\"\n [nzShowPagination]=\"false\"\n [nzFrontPagination]=\"false\"\n [nzScroll]=\"computedScroll\"\n [nzNoResult]=\"emptyText\"\n [nzTableLayout]=\"computedTableLayout\"\n [nzWidthConfig]=\"widthConfig\"\n (nzQueryParams)=\"queryParams.emit($event)\"\n (nzCurrentPageDataChange)=\"currentPageDataChange.emit($event)\"\n >\n <thead>\n <tr>\n @if (selectable) {\n <th\n class=\"geo-table__checkbox-cell\"\n nzWidth=\"48px\"\n [nzLeft]=\"hasFixedColumns\"\n >\n <geo-checkbox\n [checked]=\"allChecked\"\n [indeterminate]=\"indeterminate\"\n (checkedChange)=\"onAllChecked($event)\"\n ></geo-checkbox>\n </th>\n }\n @for (col of visibleColumns; track col.key) {\n <th\n [nzWidth]=\"col.width ?? null\"\n [nzAlign]=\"getHeaderAlign(col)\"\n [nzColumnKey]=\"col.key\"\n [nzShowSort]=\"col.sortable ?? false\"\n [nzSortOrder]=\"col.sortOrder ?? null\"\n [nzSortFn]=\"col.sortable ? getSortFn(col) : null\"\n [nzShowFilter]=\"hasFilters(col)\"\n [nzFilters]=\"col.filters ?? []\"\n [nzFilterMultiple]=\"col.filterMultiple ?? true\"\n [nzLeft]=\"col.fixed === 'left'\"\n [nzRight]=\"col.fixed === 'right'\"\n >{{ col.title }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of uiTable.data; track trackRow($index, row); let rowIndex = $index) {\n <tr\n class=\"geo-table__row\"\n [class.geo-table__row--selected]=\"isRowSelected(row)\"\n [class.geo-table__row--clickable]=\"clickable\"\n (click)=\"clickable && rowClick.emit(row)\"\n >\n @if (selectable) {\n <td\n class=\"geo-table__checkbox-cell\"\n [nzLeft]=\"hasFixedColumns\"\n (click)=\"$event.stopPropagation()\"\n >\n <geo-checkbox\n [checked]=\"isRowSelected(row)\"\n (checkedChange)=\"onItemChecked(row, $event)\"\n ></geo-checkbox>\n </td>\n }\n @for (col of visibleColumns; track col.key) {\n <td\n [nzAlign]=\"getCellAlign(col)\"\n [nzEllipsis]=\"col.wrap ? false : (col.ellipsis ?? false)\"\n [class.geo-table__cell--wrap]=\"col.wrap\"\n [nzLeft]=\"col.fixed === 'left'\"\n [nzRight]=\"col.fixed === 'right'\"\n [style.width]=\"col.width || null\"\n [style.minWidth]=\"col.width || null\"\n [style.maxWidth]=\"col.fixed ? (col.width || null) : null\"\n >\n @if (col.renderAs === 'index') {\n {{ getRowIndex(rowIndex) }}\n } @else if (col.renderAs === 'status') {\n <geo-status-tag\n [status]=\"getCellValue(row, col.key)\"\n [label]=\"col.statusLabelKey ? getCellValue(row, col.statusLabelKey) || undefined : undefined\"\n ></geo-status-tag>\n } @else if (col.renderAs === 'actions') {\n <geo-row-actions\n [actions]=\"getRowActions(col, row)\"\n [primaryActionKey]=\"col.primaryActionKey ?? 'edit'\"\n (actionClick)=\"onRowActionClick(row, $event)\"\n ></geo-row-actions>\n } @else {\n {{ getCellValue(row, col.key) }}\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </nz-table>\n </div>\n\n @if (mobileCardView) {\n <div\n class=\"geo-table__mobile\"\n [class.geo-table__mobile--loading]=\"loading\"\n [attr.aria-busy]=\"loading ? 'true' : null\"\n >\n @if (selectable && paginatedData.length) {\n <div class=\"geo-table-card__select-all\">\n <geo-checkbox\n [checked]=\"allChecked\"\n [indeterminate]=\"indeterminate\"\n (checkedChange)=\"onAllChecked($event)\"\n ></geo-checkbox>\n <span>Ch\u1ECDn t\u1EA5t c\u1EA3 tr\u00EAn trang</span>\n </div>\n }\n\n @if (!paginatedData.length && !loading) {\n <div class=\"geo-table__mobile-empty\">{{ emptyText }}</div>\n }\n\n @for (row of paginatedData; track trackRow($index, row); let rowIndex = $index) {\n <article\n class=\"geo-table-card\"\n [class.geo-table-card--selected]=\"isRowSelected(row)\"\n [class.geo-table-card--clickable]=\"clickable\"\n (click)=\"onMobileCardClick(row, $event)\"\n >\n <header class=\"geo-table-card__header\">\n <div class=\"geo-table-card__title-wrap\">\n @if (selectable) {\n <geo-checkbox\n class=\"geo-table-card__checkbox\"\n [checked]=\"isRowSelected(row)\"\n (checkedChange)=\"onItemChecked(row, $event)\"\n (click)=\"$event.stopPropagation()\"\n ></geo-checkbox>\n }\n @if (mobileTitleColumn; as titleCol) {\n <h3 class=\"geo-table-card__title\">\n <span class=\"geo-table-card__title-label\">{{ titleCol.title }}</span>\n <span class=\"geo-table-card__title-sep\">:</span>\n <span class=\"geo-table-card__title-value\">\n @if (titleCol.renderAs === 'index') {\n {{ getRowIndex(rowIndex) }}\n } @else {\n {{ getCellValue(row, titleCol.key) }}\n }\n </span>\n </h3>\n }\n </div>\n\n @if (mobileActionsColumn; as actionsCol) {\n <div class=\"geo-table-card__actions\" (click)=\"$event.stopPropagation()\">\n <geo-row-actions\n [actions]=\"getMobileHeaderActions(actionsCol, row)\"\n [primaryActionKey]=\"actionsCol.primaryActionKey ?? 'edit'\"\n (actionClick)=\"onRowActionClick(row, $event)\"\n ></geo-row-actions>\n </div>\n }\n </header>\n\n @if (mobileBodyColumns.length) {\n <div class=\"geo-table-card__body\">\n @for (col of mobileBodyColumns; track col.key) {\n <div class=\"geo-table-card__row\">\n <span class=\"geo-table-card__label\">{{ col.title }}</span>\n <span class=\"geo-table-card__sep\">:</span>\n <span class=\"geo-table-card__value\">\n @if (col.renderAs === 'index') {\n {{ getRowIndex(rowIndex) }}\n } @else if (col.renderAs === 'status') {\n <geo-status-tag\n [status]=\"getCellValue(row, col.key)\"\n [label]=\"col.statusLabelKey ? getCellValue(row, col.statusLabelKey) || undefined : undefined\"\n ></geo-status-tag>\n } @else {\n {{ getCellValue(row, col.key) }}\n }\n </span>\n </div>\n }\n </div>\n }\n\n @if (mobileActionsColumn; as actionsCol) {\n @if (getMobileFooterActions(actionsCol, row); as footerActions) {\n @if (footerActions.length) {\n <footer class=\"geo-table-card__footer\" (click)=\"$event.stopPropagation()\">\n @for (action of footerActions; track action.key) {\n <button\n type=\"button\"\n class=\"geo-table-card__footer-btn\"\n [class.geo-table-card__footer-btn--danger]=\"action.danger\"\n [disabled]=\"action.disabled\"\n (click)=\"onRowActionClick(row, action.key)\"\n >\n {{ action.label ?? action.title ?? action.key }}\n </button>\n }\n </footer>\n }\n }\n }\n </article>\n }\n </div>\n }\n\n @if (shouldShowPagination && (paginationPosition === 'bottom' || paginationPosition === 'both')) {\n <geo-table-pagination\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [total]=\"computedTotal\"\n [pageSizeOptions]=\"pageSizeOptions\"\n [showSizeChanger]=\"showSizeChanger\"\n [hideOnSinglePage]=\"hideOnSinglePage\"\n [showTotalRange]=\"showTotalRange\"\n (pageIndexChange)=\"onPageIndexChange($event)\"\n (pageSizeChange)=\"onPageSizeChange($event)\"\n ></geo-table-pagination>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;max-width:100%;min-width:0}.geo-table{width:100%;max-width:100%;min-width:0;border-radius:var(--geo-radius);overflow:clip}.geo-table__row--clickable{cursor:pointer}.geo-table__row--selected>td{background:var(--geo-color-primary-background)}:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row:nth-child(2n of.geo-table__row)>td{background:var(--geo-color-neutral-100)}:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row:nth-child(2n of.geo-table__row)>td.ant-table-cell-fix-left,:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row:nth-child(2n of.geo-table__row)>td.ant-table-cell-fix-right{background:var(--geo-color-neutral-100)}:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row:nth-child(2n of.geo-table__row):hover>td,:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row:nth-child(2n of.geo-table__row):hover>td.ant-table-cell-fix-left,:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row:nth-child(2n of.geo-table__row):hover>td.ant-table-cell-fix-right{background:var(--geo-color-primary-background)}:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row--selected>td,:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row--selected>td.ant-table-cell-fix-left,:host ::ng-deep .geo-table--striped .ant-table-tbody>tr.geo-table__row--selected>td.ant-table-cell-fix-right{background:var(--geo-color-primary-background)}.geo-table__checkbox-cell{text-align:center;vertical-align:middle;padding-left:12px!important;padding-right:12px!important}.geo-table__cell--wrap{white-space:normal;word-break:break-word;overflow-wrap:anywhere}:host ::ng-deep .geo-table .ant-table{background:var(--geo-color-neutral-white);border-radius:var(--geo-radius)}:host ::ng-deep .geo-table .ant-table-container{border-radius:var(--geo-radius)}:host ::ng-deep .geo-table .ant-table-thead>tr>th{background:var(--geo-color-neutral-100)!important;color:var(--geo-color-neutral-900)!important;font-weight:600;font-size:14px;line-height:20px;height:44px;padding:12px 10px!important;white-space:nowrap;text-align:center;border-bottom:1px solid var(--geo-color-primary-border)!important;box-sizing:border-box}:host ::ng-deep .geo-table .ant-table-body>table>thead{display:none!important}:host ::ng-deep .geo-table .ant-table-tbody>tr.ant-table-measure-now,:host ::ng-deep .geo-table .ant-table-tbody>tr[nz-table-measure-row]{height:0!important;font-size:0!important;line-height:0!important}:host ::ng-deep .geo-table .ant-table-tbody>tr.ant-table-measure-now>td,:host ::ng-deep .geo-table .ant-table-tbody>tr[nz-table-measure-row]>td{padding:0!important;border:0!important;height:0!important;min-height:0!important;line-height:0!important;font-size:0!important}:host ::ng-deep .geo-table .ant-table-tbody>tr>td{color:var(--geo-color-neutral-900);font-size:14px;line-height:normal;min-height:48px;padding:12px 10px!important;vertical-align:middle;border-bottom:1px solid var(--geo-color-primary-border)!important;box-sizing:border-box}:host ::ng-deep .geo-table .ant-table-tbody>tr:hover>td{background:var(--geo-color-primary-background)}:host ::ng-deep .geo-table .ant-table-bordered .ant-table-container{border-color:var(--geo-color-primary-border)}:host ::ng-deep .geo-table .geo-table__row-actions{display:inline-flex;align-items:center;justify-content:center;gap:10px}:host ::ng-deep .geo-table .geo-table__action-icon{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:var(--geo-radius);background:transparent;color:var(--geo-color-neutral-500);cursor:pointer;transition:color .15s ease,background-color .15s ease}:host ::ng-deep .geo-table .geo-table__action-icon:hover{color:var(--geo-color-primary-default);background:color-mix(in srgb,var(--geo-color-primary-default) 10%,transparent)}:host ::ng-deep .geo-table .ant-table-wrapper,:host ::ng-deep .geo-table .ant-spin-nested-loading,:host ::ng-deep .geo-table .ant-spin-container{width:100%;max-width:100%}:host ::ng-deep .geo-table .ant-table{width:100%}:host ::ng-deep .geo-table .ant-table-container{border-radius:var(--geo-radius);overflow:clip}:host ::ng-deep .geo-table .ant-table-body{overflow-x:auto!important;-webkit-overflow-scrolling:touch}:host ::ng-deep .geo-table .ant-table-content{overflow-x:auto;-webkit-overflow-scrolling:touch}:host ::ng-deep .geo-table .ant-table-header.nz-table-hide-scrollbar{overflow-x:hidden!important;overflow-y:scroll!important;scrollbar-gutter:stable}:host ::ng-deep .geo-table .ant-table-body{scrollbar-gutter:stable}:host ::ng-deep .geo-table .ant-table-cell-fix-left,:host ::ng-deep .geo-table .ant-table-cell-fix-right{background:var(--geo-color-neutral-white)}:host ::ng-deep .geo-table .ant-table-thead>tr>th.ant-table-cell-fix-left,:host ::ng-deep .geo-table .ant-table-thead>tr>th.ant-table-cell-fix-right{background:var(--geo-color-neutral-100)!important}:host ::ng-deep .geo-table .ant-table-tbody>tr:hover>td.ant-table-cell-fix-left,:host ::ng-deep .geo-table .ant-table-tbody>tr:hover>td.ant-table-cell-fix-right{background:var(--geo-color-primary-background)}:host ::ng-deep .geo-table .ant-table-thead>tr>th.ant-table-cell-fix-left,:host ::ng-deep .geo-table .ant-table-thead>tr>th.ant-table-cell-fix-right,:host ::ng-deep .geo-table .ant-table-tbody>tr>td.ant-table-cell-fix-left,:host ::ng-deep .geo-table .ant-table-tbody>tr>td.ant-table-cell-fix-right{box-sizing:border-box}:host ::ng-deep .geo-table .ant-table-ping-left:not(.ant-table-ping-right) .ant-table-cell-fix-left-last:after{box-shadow:inset 10px 0 8px -8px #0000001f}:host ::ng-deep .geo-table .ant-table-ping-right:not(.ant-table-ping-left) .ant-table-cell-fix-right-first:after{box-shadow:inset -10px 0 8px -8px #0000001f}.geo-table__mobile{display:none}@media (max-width: 767.98px){.geo-table--mobile-cards{overflow:visible}.geo-table--mobile-cards .geo-table__desktop{display:none}.geo-table--mobile-cards .geo-table__mobile{display:flex;flex-direction:column;gap:12px;padding:0}}.geo-table__mobile--loading{opacity:.55;pointer-events:none}.geo-table__mobile-empty{padding:32px 16px;text-align:center;color:var(--geo-color-neutral-500);font-size:14px;background:var(--geo-color-neutral-white);border:1px solid var(--geo-color-primary-border);border-radius:var(--geo-radius)}.geo-table-card__select-all{display:flex;align-items:center;gap:8px;padding:8px 4px;font-size:14px;color:var(--geo-color-neutral-700)}.geo-table-card{background:var(--geo-color-neutral-white);border:1px solid var(--geo-color-primary-border);border-radius:var(--geo-radius);box-shadow:0 1px 2px #0000000a;overflow:hidden}.geo-table-card--clickable{cursor:pointer}.geo-table-card--selected{border-color:var(--geo-color-primary-light);box-shadow:0 0 0 1px color-mix(in srgb,var(--geo-color-primary-default) 25%,transparent)}.geo-table-card__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:14px 14px 10px}.geo-table-card__title-wrap{display:flex;align-items:flex-start;gap:8px;min-width:0;flex:1}.geo-table-card__checkbox{flex-shrink:0;margin-top:2px}.geo-table-card__title{margin:0;min-width:0;font-size:15px;font-weight:700;line-height:1.4;color:var(--geo-color-neutral-900);word-break:break-word}.geo-table-card__title-label,.geo-table-card__title-sep,.geo-table-card__title-value{font-weight:700;color:var(--geo-color-neutral-900)}.geo-table-card__title-sep{margin-inline:4px}.geo-table-card__actions{flex-shrink:0}:host ::ng-deep .geo-table-card__actions .geo-row-actions{gap:8px}:host ::ng-deep .geo-table-card__actions .geo-row-actions__btn{width:32px;height:32px;border-radius:var(--geo-radius);background:#1890ff1a;color:var(--geo-color-info-default)}:host ::ng-deep .geo-table-card__actions .geo-row-actions__btn:hover:not(:disabled){background:#1890ff2e;color:var(--geo-color-info-dark)}:host ::ng-deep .geo-table-card__actions .geo-row-actions__btn--danger{background:#ee003314;color:var(--geo-color-error-default)}:host ::ng-deep .geo-table-card__actions .geo-row-actions__btn--danger:hover:not(:disabled){background:#ee003324;color:var(--geo-color-error-dark)}:host ::ng-deep .geo-table-card__actions .geo-row-actions__btn :deep(.anticon),:host ::ng-deep .geo-table-card__actions .geo-row-actions__btn .anticon{font-size:16px}.geo-table-card__body{display:flex;flex-direction:column;gap:10px;padding:4px 14px 14px}.geo-table-card__row{display:flex;align-items:flex-start;flex-wrap:wrap;column-gap:4px;row-gap:2px;font-size:14px;line-height:1.45}.geo-table-card__label,.geo-table-card__sep{color:var(--geo-color-neutral-700);font-weight:400;flex-shrink:0}.geo-table-card__value{color:var(--geo-color-neutral-900);font-weight:700;min-width:0;word-break:break-word}.geo-table-card__footer{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;padding:12px 14px;background:var(--geo-color-info-light);border-top:1px solid var(--geo-color-info-light)}.geo-table-card__footer-btn{appearance:none;border:0;background:transparent;padding:0 8px;min-height:24px;font-size:14px;font-weight:600;line-height:1.4;color:var(--geo-color-info-default);cursor:pointer}.geo-table-card__footer-btn:hover:not(:disabled){color:var(--geo-color-info-dark);text-decoration:underline}.geo-table-card__footer-btn:disabled{opacity:.45;cursor:not-allowed}.geo-table-card__footer-btn--danger{color:var(--geo-color-error-default)}.geo-table-card__footer-btn--danger:hover:not(:disabled){color:var(--geo-color-error-dark)}\n"] }]
3069
+ }], propDecorators: { columns: [{
3070
+ type: Input
3071
+ }], data: [{
3072
+ type: Input
3073
+ }], loading: [{
3074
+ type: Input
3075
+ }], bordered: [{
3076
+ type: Input
3077
+ }], outerBordered: [{
3078
+ type: Input
3079
+ }], size: [{
3080
+ type: Input
3081
+ }], striped: [{
3082
+ type: Input
3083
+ }], clickable: [{
3084
+ type: Input
3085
+ }], tableLayout: [{
3086
+ type: Input
3087
+ }], showPagination: [{
3088
+ type: Input
3089
+ }], frontPagination: [{
3090
+ type: Input
3091
+ }], pageIndex: [{
3092
+ type: Input
3093
+ }], pageSize: [{
3094
+ type: Input
3095
+ }], total: [{
3096
+ type: Input
3097
+ }], pageSizeOptions: [{
3098
+ type: Input
3099
+ }], showSizeChanger: [{
3100
+ type: Input
3101
+ }], showQuickJumper: [{
3102
+ type: Input
3103
+ }], hideOnSinglePage: [{
3104
+ type: Input
3105
+ }], simplePagination: [{
3106
+ type: Input
3107
+ }], paginationPosition: [{
3108
+ type: Input
3109
+ }], scroll: [{
3110
+ type: Input
3111
+ }], scrollY: [{
3112
+ type: Input
3113
+ }], autoScroll: [{
3114
+ type: Input
3115
+ }], tableTitle: [{
3116
+ type: Input
3117
+ }], footer: [{
3118
+ type: Input
3119
+ }], emptyText: [{
3120
+ type: Input
3121
+ }], showTotalRange: [{
3122
+ type: Input
3123
+ }], selectable: [{
3124
+ type: Input
3125
+ }], rowKey: [{
3126
+ type: Input
3127
+ }], selectedKeys: [{
3128
+ type: Input
3129
+ }], mobileTitleKey: [{
3130
+ type: Input
3131
+ }], mobileCardView: [{
3132
+ type: Input
3133
+ }], rowClick: [{
3134
+ type: Output
3135
+ }], rowEdit: [{
3136
+ type: Output
3137
+ }], rowMore: [{
3138
+ type: Output
3139
+ }], rowAction: [{
3140
+ type: Output
3141
+ }], pageIndexChange: [{
3142
+ type: Output
3143
+ }], pageSizeChange: [{
3144
+ type: Output
3145
+ }], queryParams: [{
3146
+ type: Output
3147
+ }], currentPageDataChange: [{
3148
+ type: Output
3149
+ }], selectedKeysChange: [{
3150
+ type: Output
3151
+ }], selectionChange: [{
3152
+ type: Output
3153
+ }] } });
3154
+
3155
+ /** Breakpoint (px) → số cột tối đa khi `responsiveColumns` bật. */
3156
+ const COL_BREAKPOINTS = [
3157
+ { minWidth: 1400, cols: 4 },
3158
+ { minWidth: 1200, cols: 4 },
3159
+ { minWidth: 1024, cols: 3 },
3160
+ { minWidth: 768, cols: 2 },
3161
+ { minWidth: 0, cols: 1 },
3162
+ ];
3163
+ /**
3164
+ * Thanh lọc phía trên bảng: field chính + actions (Tìm kiếm / Bộ lọc nâng cao / Reset).
3165
+ *
3166
+ * ## Số cột hiển thị
3167
+ * - `[columns]="4"` — 4 cột field + 1 cột actions = grid 5 cột đều.
3168
+ * - `[responsiveColumns]="false"` — giữ đúng `columns`, không giảm theo breakpoint.
3169
+ *
3170
+ * ## Layout
3171
+ * - Grid đều `columns + 1`: field cột 1..N, actions cột cuối.
3172
+ * - Advanced span full width (`1 / -1`) với cùng `columns + 1` cột → phủ cả cột button.
3173
+ * - Stacked (màn hẹp): actions → fields → advanced.
3174
+ *
3175
+ * ## Content projection
3176
+ * - Default: luôn hiện. Slot `[advanced]`: chỉ hiện khi `advancedExpanded`.
3177
+ */
3178
+ class GeoTableFilterComponent {
3179
+ host = inject((ElementRef));
3180
+ ngZone = inject(NgZone);
3181
+ cdr = inject(ChangeDetectorRef);
3182
+ /**
3183
+ * Số cột field mỗi hàng (mặc định 4 → tổng 5 cột gồm actions).
3184
+ * Ví dụ: 4 field + columns=2 → 2 hàng × 2 cột field (+ 1 cột actions).
3185
+ */
3186
+ columns = 4;
3187
+ /**
3188
+ * Khi `true` (mặc định): số cột thực tế ≤ `columns` theo breakpoint.
3189
+ * Khi `false`: luôn dùng đúng `columns`.
3190
+ */
3191
+ responsiveColumns = true;
3192
+ /** Đưa actions lên hàng đầu khi màn hẹp (stacked). */
3193
+ responsiveCollapse = true;
3194
+ /** Breakpoint chuyển layout stacked (px). */
3195
+ mobileBreakpoint = 1024;
3196
+ /** Khoảng cách grid (px). */
3197
+ gap = 15;
3198
+ searchLabel = 'Tìm kiếm';
3199
+ searchLoading = false;
3200
+ /** Hiện nút mở/đóng slot `[advanced]`. */
3201
+ showAdvancedToggle = true;
3202
+ showReset = true;
3203
+ /** Mở panel field nâng cao (`[advanced]`). */
3204
+ advancedExpanded = false;
3205
+ /**
3206
+ * Số field advanced đang có giá trị — hiện badge trên nút expand.
3207
+ * Parent tự tính (vd. `countFilledFilters(query, ADVANCED_KEYS)`).
3208
+ */
3209
+ advancedFilterCount = 0;
3210
+ filterToggleTitle = 'Bộ lọc nâng cao';
3211
+ resetTitle = 'Xóa bộ lọc';
3212
+ search = new EventEmitter();
3213
+ reset = new EventEmitter();
3214
+ advancedExpandedChange = new EventEmitter();
3215
+ effectiveCols = 4;
3216
+ stackedLayout = false;
3217
+ resizeObserver;
3218
+ layoutFrame;
3219
+ get hostColumns() {
3220
+ return this.effectiveCols;
3221
+ }
3222
+ /** Tổng cột grid = field cols + 1 cột actions. */
3223
+ get hostTotalColumns() {
3224
+ return this.effectiveCols + 1;
3225
+ }
3226
+ get hostGap() {
3227
+ return this.gap;
3228
+ }
3229
+ get stackedLayoutClass() {
3230
+ return this.stackedLayout;
3231
+ }
3232
+ ngOnChanges(changes) {
3233
+ if (changes['columns'] ||
3234
+ changes['responsiveColumns'] ||
3235
+ changes['responsiveCollapse'] ||
3236
+ changes['mobileBreakpoint']) {
3237
+ this.scheduleLayout();
3238
+ }
3239
+ }
3240
+ ngAfterViewInit() {
3241
+ this.ngZone.runOutsideAngular(() => {
3242
+ this.resizeObserver = new ResizeObserver(() => this.scheduleLayout());
3243
+ this.resizeObserver.observe(this.host.nativeElement);
3244
+ });
3245
+ this.scheduleLayout();
3246
+ }
3247
+ ngOnDestroy() {
3248
+ this.resizeObserver?.disconnect();
3249
+ if (this.layoutFrame) {
3250
+ cancelAnimationFrame(this.layoutFrame);
3251
+ }
3252
+ }
3253
+ toggleAdvanced() {
3254
+ const next = !this.advancedExpanded;
3255
+ this.advancedExpanded = next;
3256
+ this.advancedExpandedChange.emit(next);
3257
+ }
3258
+ onSearch() {
3259
+ this.search.emit();
3260
+ }
3261
+ onReset() {
3262
+ this.reset.emit();
3263
+ }
3264
+ scheduleLayout() {
3265
+ if (this.layoutFrame) {
3266
+ cancelAnimationFrame(this.layoutFrame);
3267
+ }
3268
+ this.layoutFrame = requestAnimationFrame(() => {
3269
+ this.ngZone.run(() => {
3270
+ this.updateResponsiveLayout();
3271
+ this.cdr.markForCheck();
3272
+ });
3273
+ });
3274
+ }
3275
+ updateResponsiveLayout() {
3276
+ const hostWidth = this.host.nativeElement.clientWidth || 0;
3277
+ this.effectiveCols = this.getEffectiveCols(hostWidth);
3278
+ // 1 cột / dưới breakpoint: stacked — actions lên hàng đầu.
3279
+ this.stackedLayout =
3280
+ this.effectiveCols === 1 ||
3281
+ (this.responsiveCollapse && hostWidth > 0 && hostWidth < this.mobileBreakpoint);
3282
+ }
3283
+ getEffectiveCols(width) {
3284
+ const requested = Math.max(1, Math.floor(this.columns) || 1);
3285
+ if (!this.responsiveColumns) {
3286
+ return requested;
3287
+ }
3288
+ if (width <= 0) {
3289
+ return requested;
3290
+ }
3291
+ const preset = COL_BREAKPOINTS.find((bp) => width >= bp.minWidth)?.cols ?? 1;
3292
+ return Math.min(requested, preset);
3293
+ }
3294
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTableFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3295
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoTableFilterComponent, isStandalone: true, selector: "geo-table-filter", inputs: { columns: "columns", responsiveColumns: "responsiveColumns", responsiveCollapse: "responsiveCollapse", mobileBreakpoint: "mobileBreakpoint", gap: "gap", searchLabel: "searchLabel", searchLoading: "searchLoading", showAdvancedToggle: "showAdvancedToggle", showReset: "showReset", advancedExpanded: "advancedExpanded", advancedFilterCount: "advancedFilterCount", filterToggleTitle: "filterToggleTitle", resetTitle: "resetTitle" }, outputs: { search: "search", reset: "reset", advancedExpandedChange: "advancedExpandedChange" }, host: { properties: { "style.--geo-table-filter-cols": "this.hostColumns", "style.--geo-table-filter-total-cols": "this.hostTotalColumns", "style.--geo-table-filter-gap.px": "this.hostGap", "class.geo-table-filter--stacked": "this.stackedLayoutClass" } }, usesOnChanges: true, ngImport: i0, template: "<div\n class=\"geo-table-filter\"\n [class.geo-table-filter--expanded]=\"advancedExpanded\"\n [class.geo-table-filter--no-desktop-toggle]=\"!showAdvancedToggle\"\n>\n <div class=\"geo-table-filter__layout\">\n <div class=\"geo-table-filter__fields\">\n <ng-content></ng-content>\n </div>\n\n <div class=\"geo-table-filter__actions\">\n <geo-button\n appearance=\"primary\"\n color=\"brand\"\n icon=\"search\"\n [disabled]=\"searchLoading\"\n (clicked)=\"onSearch()\"\n >\n {{ searchLabel }}\n </geo-button>\n\n @if (showAdvancedToggle) {\n <span\n class=\"geo-table-filter__toggle\"\n [class.geo-table-filter__toggle--active]=\"advancedExpanded\"\n [class.geo-table-filter__toggle--has-count]=\"advancedFilterCount > 0\"\n >\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"filter\"\n [iconOnly]=\"true\"\n [title]=\"filterToggleTitle\"\n [attr.aria-expanded]=\"advancedExpanded\"\n (clicked)=\"toggleAdvanced()\"\n ></geo-button>\n @if (advancedFilterCount > 0) {\n <span class=\"geo-table-filter__toggle-badge\" aria-hidden=\"true\">\n {{ advancedFilterCount > 99 ? '99+' : advancedFilterCount }}\n </span>\n }\n </span>\n }\n\n @if (showReset) {\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"reload\"\n [iconOnly]=\"true\"\n [title]=\"resetTitle\"\n (clicked)=\"onReset()\"\n ></geo-button>\n }\n </div>\n\n <div\n class=\"geo-table-filter__advanced\"\n [class.geo-table-filter__advanced--visible]=\"advancedExpanded\"\n >\n <ng-content select=\"[advanced]\"></ng-content>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;--geo-table-filter-cols: 4;--geo-table-filter-total-cols: 5;--geo-table-filter-gap: 15px}.geo-table-filter{display:block}.geo-table-filter__layout{display:grid;grid-template-columns:repeat(var(--geo-table-filter-total-cols),minmax(0,1fr));grid-template-rows:auto auto;gap:var(--geo-table-filter-gap);align-items:start}.geo-table-filter__fields{grid-column:1/-2;grid-row:1;display:grid;grid-template-columns:repeat(var(--geo-table-filter-cols),minmax(0,1fr));gap:var(--geo-table-filter-gap);align-items:end;min-width:0}.geo-table-filter__fields>*{min-width:0;width:100%;max-width:100%;box-sizing:border-box}.geo-table-filter__actions{grid-column:-2/-1;grid-row:1;display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;align-self:start;gap:8px;min-width:0;width:100%;padding-top:22px;box-sizing:border-box}.geo-table-filter__advanced{grid-column:1/-1;grid-row:2;display:none;grid-template-columns:repeat(var(--geo-table-filter-total-cols),minmax(0,1fr));gap:var(--geo-table-filter-gap);align-items:end;min-width:0}.geo-table-filter__advanced>*{min-width:0;width:100%;max-width:100%;box-sizing:border-box}.geo-table-filter__advanced--visible{display:grid}.geo-table-filter--no-desktop-toggle .geo-table-filter__toggle{display:none}.geo-table-filter__toggle{position:relative;display:inline-flex;flex-shrink:0}.geo-table-filter__toggle--active ::ng-deep .geo-button.geo-button--secondary{background:var(--geo-color-primary-default);border-color:var(--geo-color-primary-default);color:var(--geo-color-neutral-white)}.geo-table-filter__toggle--active ::ng-deep .geo-button.geo-button--secondary:hover:not(:disabled){background:var(--geo-color-primary-hover);border-color:var(--geo-color-primary-hover);color:var(--geo-color-neutral-white)}.geo-table-filter__toggle--has-count:not(.geo-table-filter__toggle--active) ::ng-deep .geo-button.geo-button--secondary{background:var(--geo-color-primary-surface-light)}.geo-table-filter__toggle-badge{position:absolute;top:-6px;right:-6px;z-index:1;display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;border-radius:999px;background:var(--geo-color-primary-default);color:var(--geo-color-neutral-white);font-size:11px;font-weight:600;line-height:1;box-sizing:border-box;pointer-events:none}.geo-table-filter__toggle--active .geo-table-filter__toggle-badge{background:var(--geo-color-neutral-white);color:var(--geo-color-primary-default);border:1px solid rgba(255,255,255,.35)}@media (max-width: 1023px){:host{--geo-table-filter-gap: 12px}}:host(.geo-table-filter--stacked) .geo-table-filter__layout{display:flex;flex-direction:column;gap:var(--geo-table-filter-gap)}:host(.geo-table-filter--stacked) .geo-table-filter__actions{order:1;width:100%;justify-content:flex-end;align-self:stretch;padding-top:0}:host(.geo-table-filter--stacked) .geo-table-filter__fields{order:2;width:100%}:host(.geo-table-filter--stacked) .geo-table-filter__advanced{order:3;width:100%}@media (max-width: 479px){:host{--geo-table-filter-gap: 10px}:host(.geo-table-filter--stacked) .geo-table-filter__actions{flex-wrap:wrap}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: GeoButtonComponent, selector: "geo-button", inputs: ["appearance", "color", "icon", "iconTheme", "iconPlacement", "iconOnly", "type", "disabled", "tooltip", "tooltipPlacement", "active", "title"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3296
+ }
3297
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTableFilterComponent, decorators: [{
3298
+ type: Component,
3299
+ args: [{ selector: 'geo-table-filter', standalone: true, imports: [CommonModule, GeoButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"geo-table-filter\"\n [class.geo-table-filter--expanded]=\"advancedExpanded\"\n [class.geo-table-filter--no-desktop-toggle]=\"!showAdvancedToggle\"\n>\n <div class=\"geo-table-filter__layout\">\n <div class=\"geo-table-filter__fields\">\n <ng-content></ng-content>\n </div>\n\n <div class=\"geo-table-filter__actions\">\n <geo-button\n appearance=\"primary\"\n color=\"brand\"\n icon=\"search\"\n [disabled]=\"searchLoading\"\n (clicked)=\"onSearch()\"\n >\n {{ searchLabel }}\n </geo-button>\n\n @if (showAdvancedToggle) {\n <span\n class=\"geo-table-filter__toggle\"\n [class.geo-table-filter__toggle--active]=\"advancedExpanded\"\n [class.geo-table-filter__toggle--has-count]=\"advancedFilterCount > 0\"\n >\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"filter\"\n [iconOnly]=\"true\"\n [title]=\"filterToggleTitle\"\n [attr.aria-expanded]=\"advancedExpanded\"\n (clicked)=\"toggleAdvanced()\"\n ></geo-button>\n @if (advancedFilterCount > 0) {\n <span class=\"geo-table-filter__toggle-badge\" aria-hidden=\"true\">\n {{ advancedFilterCount > 99 ? '99+' : advancedFilterCount }}\n </span>\n }\n </span>\n }\n\n @if (showReset) {\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"reload\"\n [iconOnly]=\"true\"\n [title]=\"resetTitle\"\n (clicked)=\"onReset()\"\n ></geo-button>\n }\n </div>\n\n <div\n class=\"geo-table-filter__advanced\"\n [class.geo-table-filter__advanced--visible]=\"advancedExpanded\"\n >\n <ng-content select=\"[advanced]\"></ng-content>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;--geo-table-filter-cols: 4;--geo-table-filter-total-cols: 5;--geo-table-filter-gap: 15px}.geo-table-filter{display:block}.geo-table-filter__layout{display:grid;grid-template-columns:repeat(var(--geo-table-filter-total-cols),minmax(0,1fr));grid-template-rows:auto auto;gap:var(--geo-table-filter-gap);align-items:start}.geo-table-filter__fields{grid-column:1/-2;grid-row:1;display:grid;grid-template-columns:repeat(var(--geo-table-filter-cols),minmax(0,1fr));gap:var(--geo-table-filter-gap);align-items:end;min-width:0}.geo-table-filter__fields>*{min-width:0;width:100%;max-width:100%;box-sizing:border-box}.geo-table-filter__actions{grid-column:-2/-1;grid-row:1;display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;align-self:start;gap:8px;min-width:0;width:100%;padding-top:22px;box-sizing:border-box}.geo-table-filter__advanced{grid-column:1/-1;grid-row:2;display:none;grid-template-columns:repeat(var(--geo-table-filter-total-cols),minmax(0,1fr));gap:var(--geo-table-filter-gap);align-items:end;min-width:0}.geo-table-filter__advanced>*{min-width:0;width:100%;max-width:100%;box-sizing:border-box}.geo-table-filter__advanced--visible{display:grid}.geo-table-filter--no-desktop-toggle .geo-table-filter__toggle{display:none}.geo-table-filter__toggle{position:relative;display:inline-flex;flex-shrink:0}.geo-table-filter__toggle--active ::ng-deep .geo-button.geo-button--secondary{background:var(--geo-color-primary-default);border-color:var(--geo-color-primary-default);color:var(--geo-color-neutral-white)}.geo-table-filter__toggle--active ::ng-deep .geo-button.geo-button--secondary:hover:not(:disabled){background:var(--geo-color-primary-hover);border-color:var(--geo-color-primary-hover);color:var(--geo-color-neutral-white)}.geo-table-filter__toggle--has-count:not(.geo-table-filter__toggle--active) ::ng-deep .geo-button.geo-button--secondary{background:var(--geo-color-primary-surface-light)}.geo-table-filter__toggle-badge{position:absolute;top:-6px;right:-6px;z-index:1;display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;border-radius:999px;background:var(--geo-color-primary-default);color:var(--geo-color-neutral-white);font-size:11px;font-weight:600;line-height:1;box-sizing:border-box;pointer-events:none}.geo-table-filter__toggle--active .geo-table-filter__toggle-badge{background:var(--geo-color-neutral-white);color:var(--geo-color-primary-default);border:1px solid rgba(255,255,255,.35)}@media (max-width: 1023px){:host{--geo-table-filter-gap: 12px}}:host(.geo-table-filter--stacked) .geo-table-filter__layout{display:flex;flex-direction:column;gap:var(--geo-table-filter-gap)}:host(.geo-table-filter--stacked) .geo-table-filter__actions{order:1;width:100%;justify-content:flex-end;align-self:stretch;padding-top:0}:host(.geo-table-filter--stacked) .geo-table-filter__fields{order:2;width:100%}:host(.geo-table-filter--stacked) .geo-table-filter__advanced{order:3;width:100%}@media (max-width: 479px){:host{--geo-table-filter-gap: 10px}:host(.geo-table-filter--stacked) .geo-table-filter__actions{flex-wrap:wrap}}\n"] }]
3300
+ }], propDecorators: { columns: [{
3301
+ type: Input
3302
+ }], responsiveColumns: [{
3303
+ type: Input
3304
+ }], responsiveCollapse: [{
3305
+ type: Input
3306
+ }], mobileBreakpoint: [{
3307
+ type: Input
3308
+ }], gap: [{
3309
+ type: Input
3310
+ }], searchLabel: [{
3311
+ type: Input
3312
+ }], searchLoading: [{
3313
+ type: Input
3314
+ }], showAdvancedToggle: [{
3315
+ type: Input
3316
+ }], showReset: [{
3317
+ type: Input
3318
+ }], advancedExpanded: [{
3319
+ type: Input
3320
+ }], advancedFilterCount: [{
3321
+ type: Input
3322
+ }], filterToggleTitle: [{
3323
+ type: Input
3324
+ }], resetTitle: [{
3325
+ type: Input
3326
+ }], search: [{
3327
+ type: Output
3328
+ }], reset: [{
3329
+ type: Output
3330
+ }], advancedExpandedChange: [{
3331
+ type: Output
3332
+ }], hostColumns: [{
3333
+ type: HostBinding,
3334
+ args: ['style.--geo-table-filter-cols']
3335
+ }], hostTotalColumns: [{
3336
+ type: HostBinding,
3337
+ args: ['style.--geo-table-filter-total-cols']
3338
+ }], hostGap: [{
3339
+ type: HostBinding,
3340
+ args: ['style.--geo-table-filter-gap.px']
3341
+ }], stackedLayoutClass: [{
3342
+ type: HostBinding,
3343
+ args: ['class.geo-table-filter--stacked']
3344
+ }] } });
3345
+
3346
+ let uiTextareaErrorId = 0;
3347
+ class GeoTextareaComponent {
3348
+ label = '';
3349
+ placeholder = '';
3350
+ rows = 3;
3351
+ disabled = false;
3352
+ required = false;
3353
+ error = false;
3354
+ errorMessage = '';
3355
+ maxlength;
3356
+ block = true;
3357
+ valueChange = new EventEmitter();
3358
+ errorMessageId = `geo-textarea-error-${++uiTextareaErrorId}`;
3359
+ value = '';
3360
+ onChange = () => undefined;
3361
+ onTouched = () => undefined;
3362
+ onInput(value) {
3363
+ this.value = value;
3364
+ this.onChange(value);
3365
+ this.valueChange.emit(value);
3366
+ }
3367
+ onBlur() {
3368
+ this.onTouched();
3369
+ }
3370
+ writeValue(value) {
3371
+ this.value = value ?? '';
3372
+ }
3373
+ registerOnChange(fn) {
3374
+ this.onChange = fn;
3375
+ }
3376
+ registerOnTouched(fn) {
3377
+ this.onTouched = fn;
3378
+ }
3379
+ setDisabledState(isDisabled) {
3380
+ this.disabled = isDisabled;
3381
+ }
3382
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTextareaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3383
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoTextareaComponent, isStandalone: true, selector: "geo-textarea", inputs: { label: "label", placeholder: "placeholder", rows: "rows", disabled: "disabled", required: "required", error: "error", errorMessage: "errorMessage", maxlength: "maxlength", block: "block" }, outputs: { valueChange: "valueChange" }, host: { properties: { "class.geo-textarea-host--block": "block", "class.geo-textarea-host--error": "error" }, classAttribute: "geo-textarea-host" }, providers: [
3384
+ {
3385
+ provide: NG_VALUE_ACCESSOR,
3386
+ useExisting: forwardRef(() => GeoTextareaComponent),
3387
+ multi: true,
3388
+ },
3389
+ ], ngImport: i0, template: "@if (label) {\n <div class=\"geo-textarea__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-textarea__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<textarea\n class=\"geo-textarea__field\"\n [class.geo-textarea__field--error]=\"error\"\n [rows]=\"rows\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [attr.maxlength]=\"maxlength ?? null\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n [ngModel]=\"value\"\n (ngModelChange)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n></textarea>\n\n@if (error && errorMessage) {\n <p class=\"geo-textarea__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: ["@charset \"UTF-8\";.geo-scrollbar{scrollbar-width:thin;scrollbar-color:var(--geo-color-neutral-400) transparent}.geo-scrollbar::-webkit-scrollbar{width:var(--scrollbar-size, 8px);height:var(--scrollbar-size, 8px);background:transparent}.geo-scrollbar::-webkit-scrollbar-track{background:transparent;border-radius:999px}.geo-scrollbar::-webkit-scrollbar-thumb{background-color:var(--geo-color-neutral-400);border-radius:999px;border:2px solid transparent;background-clip:padding-box;min-height:40px}.geo-scrollbar::-webkit-scrollbar-thumb:hover{background-color:var(--geo-color-neutral-500)}.geo-scrollbar::-webkit-scrollbar-corner{background:transparent}geo-textarea.geo-textarea-host,.geo-textarea-host{display:flex;flex-direction:column;gap:8px;width:100%}.geo-textarea__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-textarea__required{color:var(--geo-color-error-default)}.geo-textarea__field{width:100%;padding:8px;border:1px solid var(--geo-color-neutral-300);border-radius:var(--geo-radius);background:var(--geo-color-neutral-white);font-size:14px;line-height:1.4;color:var(--geo-color-neutral-900);font-family:inherit;box-sizing:border-box;resize:vertical;transition:border-color .15s ease,box-shadow .15s ease;scrollbar-width:thin;scrollbar-color:var(--geo-color-neutral-400) transparent}.geo-textarea__field::-webkit-scrollbar{width:var(--scrollbar-size, 8px);height:var(--scrollbar-size, 8px);background:transparent}.geo-textarea__field::-webkit-scrollbar-track{background:transparent;border-radius:999px}.geo-textarea__field::-webkit-scrollbar-thumb{background-color:var(--geo-color-neutral-400);border-radius:999px;border:2px solid transparent;background-clip:padding-box;min-height:40px}.geo-textarea__field::-webkit-scrollbar-thumb:hover{background-color:var(--geo-color-neutral-500)}.geo-textarea__field::-webkit-scrollbar-corner{background:transparent}.geo-textarea__field::placeholder{color:var(--geo-color-neutral-500)}.geo-textarea__field:hover:not(:disabled){border-color:var(--geo-color-primary-default)}.geo-textarea__field:focus{outline:none;border-color:var(--geo-color-primary-default);box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-primary-default) 12%,transparent)}.geo-textarea__field:disabled{background:var(--geo-color-neutral-100);color:var(--geo-color-neutral-disabled-text);cursor:not-allowed}.geo-textarea__field--error{border-color:var(--geo-color-error-default)!important}.geo-textarea__field--error:focus{box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-error-default) 12%,transparent)!important}.geo-textarea__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], encapsulation: i0.ViewEncapsulation.None });
3390
+ }
3391
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTextareaComponent, decorators: [{
3392
+ type: Component,
3393
+ args: [{ selector: 'geo-textarea', standalone: true, imports: [CommonModule, FormsModule], encapsulation: ViewEncapsulation.None, host: {
3394
+ class: 'geo-textarea-host',
3395
+ '[class.geo-textarea-host--block]': 'block',
3396
+ '[class.geo-textarea-host--error]': 'error',
3397
+ }, providers: [
3398
+ {
3399
+ provide: NG_VALUE_ACCESSOR,
3400
+ useExisting: forwardRef(() => GeoTextareaComponent),
3401
+ multi: true,
3402
+ },
3403
+ ], template: "@if (label) {\n <div class=\"geo-textarea__label\">\n <span>{{ label }}</span>\n @if (required) {\n <span class=\"geo-textarea__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n}\n\n<textarea\n class=\"geo-textarea__field\"\n [class.geo-textarea__field--error]=\"error\"\n [rows]=\"rows\"\n [placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [attr.maxlength]=\"maxlength ?? null\"\n [attr.aria-invalid]=\"error ? 'true' : null\"\n [attr.aria-describedby]=\"error && errorMessage ? errorMessageId : null\"\n [ngModel]=\"value\"\n (ngModelChange)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n></textarea>\n\n@if (error && errorMessage) {\n <p class=\"geo-textarea__error\" [id]=\"errorMessageId\" role=\"alert\">{{ errorMessage }}</p>\n}\n", styles: ["@charset \"UTF-8\";.geo-scrollbar{scrollbar-width:thin;scrollbar-color:var(--geo-color-neutral-400) transparent}.geo-scrollbar::-webkit-scrollbar{width:var(--scrollbar-size, 8px);height:var(--scrollbar-size, 8px);background:transparent}.geo-scrollbar::-webkit-scrollbar-track{background:transparent;border-radius:999px}.geo-scrollbar::-webkit-scrollbar-thumb{background-color:var(--geo-color-neutral-400);border-radius:999px;border:2px solid transparent;background-clip:padding-box;min-height:40px}.geo-scrollbar::-webkit-scrollbar-thumb:hover{background-color:var(--geo-color-neutral-500)}.geo-scrollbar::-webkit-scrollbar-corner{background:transparent}geo-textarea.geo-textarea-host,.geo-textarea-host{display:flex;flex-direction:column;gap:8px;width:100%}.geo-textarea__label{display:inline-flex;align-items:flex-start;gap:4px;font-size:14px;line-height:normal;color:var(--geo-color-neutral-900)}.geo-textarea__required{color:var(--geo-color-error-default)}.geo-textarea__field{width:100%;padding:8px;border:1px solid var(--geo-color-neutral-300);border-radius:var(--geo-radius);background:var(--geo-color-neutral-white);font-size:14px;line-height:1.4;color:var(--geo-color-neutral-900);font-family:inherit;box-sizing:border-box;resize:vertical;transition:border-color .15s ease,box-shadow .15s ease;scrollbar-width:thin;scrollbar-color:var(--geo-color-neutral-400) transparent}.geo-textarea__field::-webkit-scrollbar{width:var(--scrollbar-size, 8px);height:var(--scrollbar-size, 8px);background:transparent}.geo-textarea__field::-webkit-scrollbar-track{background:transparent;border-radius:999px}.geo-textarea__field::-webkit-scrollbar-thumb{background-color:var(--geo-color-neutral-400);border-radius:999px;border:2px solid transparent;background-clip:padding-box;min-height:40px}.geo-textarea__field::-webkit-scrollbar-thumb:hover{background-color:var(--geo-color-neutral-500)}.geo-textarea__field::-webkit-scrollbar-corner{background:transparent}.geo-textarea__field::placeholder{color:var(--geo-color-neutral-500)}.geo-textarea__field:hover:not(:disabled){border-color:var(--geo-color-primary-default)}.geo-textarea__field:focus{outline:none;border-color:var(--geo-color-primary-default);box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-primary-default) 12%,transparent)}.geo-textarea__field:disabled{background:var(--geo-color-neutral-100);color:var(--geo-color-neutral-disabled-text);cursor:not-allowed}.geo-textarea__field--error{border-color:var(--geo-color-error-default)!important}.geo-textarea__field--error:focus{box-shadow:0 0 0 2px color-mix(in srgb,var(--geo-color-error-default) 12%,transparent)!important}.geo-textarea__error{margin:0;font-size:14px;line-height:normal;color:var(--geo-color-error-default)}\n"] }]
3404
+ }], propDecorators: { label: [{
3405
+ type: Input
3406
+ }], placeholder: [{
3407
+ type: Input
3408
+ }], rows: [{
3409
+ type: Input
3410
+ }], disabled: [{
3411
+ type: Input
3412
+ }], required: [{
3413
+ type: Input
3414
+ }], error: [{
3415
+ type: Input
3416
+ }], errorMessage: [{
3417
+ type: Input
3418
+ }], maxlength: [{
3419
+ type: Input
3420
+ }], block: [{
3421
+ type: Input
3422
+ }], valueChange: [{
3423
+ type: Output
3424
+ }] } });
3425
+
3426
+ const GEO_TOAST_DEFAULT_TITLES = {
3427
+ success: 'Thành công!',
3428
+ error: 'Thất bại!',
3429
+ warning: 'Cảnh báo!',
3430
+ info: 'Thông tin!',
3431
+ };
3432
+ const GEO_TOAST_ICONS = {
3433
+ success: 'check-circle',
3434
+ error: 'close-circle',
3435
+ warning: 'warning',
3436
+ info: 'info-circle',
3437
+ };
3438
+
3439
+ /**
3440
+ * Toast / notification UI theo design GEO (left accent bar + icon + title + message).
3441
+ * Dùng trực tiếp trong template, hoặc qua `GeoToastService` (Ant Design notification).
3442
+ */
3443
+ class GeoToastComponent {
3444
+ type = 'info';
3445
+ title = '';
3446
+ message = '';
3447
+ closable = true;
3448
+ showIcon = true;
3449
+ visible = true;
3450
+ /** Override Ant Design icon type. */
3451
+ icon;
3452
+ closed = new EventEmitter();
3453
+ get displayTitle() {
3454
+ return this.title || GEO_TOAST_DEFAULT_TITLES[this.type];
3455
+ }
3456
+ get iconType() {
3457
+ return this.icon || GEO_TOAST_ICONS[this.type];
3458
+ }
3459
+ onClose() {
3460
+ this.visible = false;
3461
+ this.closed.emit();
3462
+ }
3463
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3464
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoToastComponent, isStandalone: true, selector: "geo-toast", inputs: { type: "type", title: "title", message: "message", closable: "closable", showIcon: "showIcon", visible: "visible", icon: "icon" }, outputs: { closed: "closed" }, host: { properties: { "class.geo-toast-host--hidden": "!visible" }, classAttribute: "geo-toast-host" }, ngImport: i0, template: "@if (visible) {\n <div\n class=\"geo-toast\"\n [class]=\"'geo-toast geo-toast--' + type\"\n role=\"status\"\n [attr.aria-live]=\"type === 'error' ? 'assertive' : 'polite'\"\n >\n <span class=\"geo-toast__accent\" aria-hidden=\"true\"></span>\n\n <div class=\"geo-toast__body\">\n @if (showIcon) {\n <span class=\"geo-toast__icon\" nz-icon [nzType]=\"iconType\" nzTheme=\"fill\"></span>\n }\n\n <div class=\"geo-toast__content\">\n <p class=\"geo-toast__title\">{{ displayTitle }}</p>\n @if (message) {\n <p class=\"geo-toast__message\">{{ message }}</p>\n }\n </div>\n\n @if (closable) {\n <button\n type=\"button\"\n class=\"geo-toast__close\"\n aria-label=\"\u0110\u00F3ng th\u00F4ng b\u00E1o\"\n (click)=\"onClose()\"\n >\n <span nz-icon nzType=\"close\" nzTheme=\"outline\"></span>\n </button>\n }\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";geo-toast.geo-toast-host,.geo-toast-host{display:block;width:100%;max-width:480px}.geo-toast-host--hidden{display:none}.geo-toast{position:relative;display:block;width:100%;box-sizing:border-box;overflow:hidden;border:1px solid transparent;border-radius:var(--geo-radius);font-family:var(--geo-font-family)}.geo-toast__accent{position:absolute;top:0;left:0;bottom:0;width:5px}.geo-toast__body{display:flex;align-items:flex-start;gap:10px;padding:12px 12px 12px 16px;box-sizing:border-box}.geo-toast__icon{display:inline-flex;flex-shrink:0;margin-top:1px;font-size:20px;line-height:1}.geo-toast__content{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px;padding-right:4px}.geo-toast__title{margin:0;font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-bold);line-height:var(--geo-line-height-body)}.geo-toast__message{margin:0;font-size:var(--geo-font-size-body-small);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-body-small);color:var(--geo-color-neutral-800)}.geo-toast__close{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:20px;height:20px;margin-top:1px;padding:0;border:none;background:transparent;cursor:pointer;font-size:12px;line-height:1;opacity:.85}.geo-toast__close:hover{opacity:1}.geo-toast--success{background:var(--geo-color-success-light);border-color:color-mix(in srgb,var(--geo-color-success-default) 45%,var(--geo-color-success-light))}.geo-toast--success .geo-toast__accent{background:var(--geo-color-success-default)}.geo-toast--success .geo-toast__icon,.geo-toast--success .geo-toast__title,.geo-toast--success .geo-toast__close{color:var(--geo-color-success-default)}.geo-toast--error{background:var(--geo-color-error-light);border-color:color-mix(in srgb,var(--geo-color-error-default) 40%,var(--geo-color-error-light))}.geo-toast--error .geo-toast__accent{background:var(--geo-color-error-default)}.geo-toast--error .geo-toast__icon,.geo-toast--error .geo-toast__title,.geo-toast--error .geo-toast__close{color:var(--geo-color-error-default)}.geo-toast--warning{background:var(--geo-color-warning-light);border-color:color-mix(in srgb,var(--geo-color-warning-default) 45%,var(--geo-color-warning-light))}.geo-toast--warning .geo-toast__accent{background:var(--geo-color-warning-default)}.geo-toast--warning .geo-toast__icon,.geo-toast--warning .geo-toast__title,.geo-toast--warning .geo-toast__close{color:var(--geo-color-warning-default)}.geo-toast--info{background:var(--geo-color-info-light);border-color:color-mix(in srgb,var(--geo-color-info-default) 40%,var(--geo-color-info-light))}.geo-toast--info .geo-toast__accent{background:var(--geo-color-info-default)}.geo-toast--info .geo-toast__icon,.geo-toast--info .geo-toast__title,.geo-toast--info .geo-toast__close{color:var(--geo-color-info-default)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1.NzIconDirective, selector: "[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }], encapsulation: i0.ViewEncapsulation.None });
3465
+ }
3466
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoToastComponent, decorators: [{
3467
+ type: Component,
3468
+ args: [{ selector: 'geo-toast', standalone: true, imports: [CommonModule, NzIconModule], encapsulation: ViewEncapsulation.None, host: {
3469
+ class: 'geo-toast-host',
3470
+ '[class.geo-toast-host--hidden]': '!visible',
3471
+ }, template: "@if (visible) {\n <div\n class=\"geo-toast\"\n [class]=\"'geo-toast geo-toast--' + type\"\n role=\"status\"\n [attr.aria-live]=\"type === 'error' ? 'assertive' : 'polite'\"\n >\n <span class=\"geo-toast__accent\" aria-hidden=\"true\"></span>\n\n <div class=\"geo-toast__body\">\n @if (showIcon) {\n <span class=\"geo-toast__icon\" nz-icon [nzType]=\"iconType\" nzTheme=\"fill\"></span>\n }\n\n <div class=\"geo-toast__content\">\n <p class=\"geo-toast__title\">{{ displayTitle }}</p>\n @if (message) {\n <p class=\"geo-toast__message\">{{ message }}</p>\n }\n </div>\n\n @if (closable) {\n <button\n type=\"button\"\n class=\"geo-toast__close\"\n aria-label=\"\u0110\u00F3ng th\u00F4ng b\u00E1o\"\n (click)=\"onClose()\"\n >\n <span nz-icon nzType=\"close\" nzTheme=\"outline\"></span>\n </button>\n }\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";geo-toast.geo-toast-host,.geo-toast-host{display:block;width:100%;max-width:480px}.geo-toast-host--hidden{display:none}.geo-toast{position:relative;display:block;width:100%;box-sizing:border-box;overflow:hidden;border:1px solid transparent;border-radius:var(--geo-radius);font-family:var(--geo-font-family)}.geo-toast__accent{position:absolute;top:0;left:0;bottom:0;width:5px}.geo-toast__body{display:flex;align-items:flex-start;gap:10px;padding:12px 12px 12px 16px;box-sizing:border-box}.geo-toast__icon{display:inline-flex;flex-shrink:0;margin-top:1px;font-size:20px;line-height:1}.geo-toast__content{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px;padding-right:4px}.geo-toast__title{margin:0;font-size:var(--geo-font-size-body);font-weight:var(--geo-font-weight-bold);line-height:var(--geo-line-height-body)}.geo-toast__message{margin:0;font-size:var(--geo-font-size-body-small);font-weight:var(--geo-font-weight-regular);line-height:var(--geo-line-height-body-small);color:var(--geo-color-neutral-800)}.geo-toast__close{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:20px;height:20px;margin-top:1px;padding:0;border:none;background:transparent;cursor:pointer;font-size:12px;line-height:1;opacity:.85}.geo-toast__close:hover{opacity:1}.geo-toast--success{background:var(--geo-color-success-light);border-color:color-mix(in srgb,var(--geo-color-success-default) 45%,var(--geo-color-success-light))}.geo-toast--success .geo-toast__accent{background:var(--geo-color-success-default)}.geo-toast--success .geo-toast__icon,.geo-toast--success .geo-toast__title,.geo-toast--success .geo-toast__close{color:var(--geo-color-success-default)}.geo-toast--error{background:var(--geo-color-error-light);border-color:color-mix(in srgb,var(--geo-color-error-default) 40%,var(--geo-color-error-light))}.geo-toast--error .geo-toast__accent{background:var(--geo-color-error-default)}.geo-toast--error .geo-toast__icon,.geo-toast--error .geo-toast__title,.geo-toast--error .geo-toast__close{color:var(--geo-color-error-default)}.geo-toast--warning{background:var(--geo-color-warning-light);border-color:color-mix(in srgb,var(--geo-color-warning-default) 45%,var(--geo-color-warning-light))}.geo-toast--warning .geo-toast__accent{background:var(--geo-color-warning-default)}.geo-toast--warning .geo-toast__icon,.geo-toast--warning .geo-toast__title,.geo-toast--warning .geo-toast__close{color:var(--geo-color-warning-default)}.geo-toast--info{background:var(--geo-color-info-light);border-color:color-mix(in srgb,var(--geo-color-info-default) 40%,var(--geo-color-info-light))}.geo-toast--info .geo-toast__accent{background:var(--geo-color-info-default)}.geo-toast--info .geo-toast__icon,.geo-toast--info .geo-toast__title,.geo-toast--info .geo-toast__close{color:var(--geo-color-info-default)}\n"] }]
3472
+ }], propDecorators: { type: [{
3473
+ type: Input
3474
+ }], title: [{
3475
+ type: Input
3476
+ }], message: [{
3477
+ type: Input
3478
+ }], closable: [{
3479
+ type: Input
3480
+ }], showIcon: [{
3481
+ type: Input
3482
+ }], visible: [{
3483
+ type: Input
3484
+ }], icon: [{
3485
+ type: Input
3486
+ }], closed: [{
3487
+ type: Output
3488
+ }] } });
3489
+
3490
+ /**
3491
+ * Toast service dựa trên `NzNotificationService` (Ant Design).
3492
+ *
3493
+ * @example
3494
+ * ```ts
3495
+ * this.toast.success('Thành công!', 'Lưu hồ sơ thành công');
3496
+ * this.toast.error('Thất bại!', 'Vui lòng kiểm tra lại', { duration: 0 });
3497
+ * ```
3498
+ */
3499
+ class GeoToastService {
3500
+ notification = inject(NzNotificationService);
3501
+ nzConfig = inject(NzConfigService, { optional: true });
3502
+ defaults = {
3503
+ duration: 4500,
3504
+ placement: 'topRight',
3505
+ pauseOnHover: true,
3506
+ animate: true,
3507
+ showIcon: true,
3508
+ closable: true,
3509
+ };
3510
+ /** Cấu hình mặc định toàn cục (duration, placement, …). */
3511
+ config(options) {
3512
+ if (options.duration != null)
3513
+ this.defaults.duration = options.duration;
3514
+ if (options.placement != null)
3515
+ this.defaults.placement = options.placement;
3516
+ if (options.pauseOnHover != null)
3517
+ this.defaults.pauseOnHover = options.pauseOnHover;
3518
+ if (options.animate != null)
3519
+ this.defaults.animate = options.animate;
3520
+ this.nzConfig?.set('notification', {
3521
+ nzDuration: this.defaults.duration,
3522
+ nzPlacement: this.defaults.placement,
3523
+ nzMaxStack: options.maxStack,
3524
+ nzTop: options.top,
3525
+ nzBottom: options.bottom,
3526
+ nzPauseOnHover: this.defaults.pauseOnHover,
3527
+ nzAnimate: this.defaults.animate,
3528
+ });
3529
+ }
3530
+ success(title, message, options) {
3531
+ return this.create('success', title, message, options);
3532
+ }
3533
+ error(title, message, options) {
3534
+ return this.create('error', title, message, options);
3535
+ }
3536
+ warning(title, message, options) {
3537
+ return this.create('warning', title, message, options);
3538
+ }
3539
+ info(title, message, options) {
3540
+ return this.create('info', title, message, options);
3541
+ }
3542
+ /** API tổng quát — đầy đủ type + options. */
3543
+ create(type, title, message, options) {
3544
+ return this.open({
3545
+ type,
3546
+ title: title ?? GEO_TOAST_DEFAULT_TITLES[type],
3547
+ message: message ?? '',
3548
+ ...options,
3549
+ });
3550
+ }
3551
+ /** Mở toast từ config object. */
3552
+ open(config) {
3553
+ const type = config.type;
3554
+ const title = config.title ?? GEO_TOAST_DEFAULT_TITLES[type];
3555
+ const message = config.message ?? '';
3556
+ const duration = config.duration ?? this.defaults.duration;
3557
+ const placement = config.placement ?? this.defaults.placement;
3558
+ const pauseOnHover = config.pauseOnHover ?? this.defaults.pauseOnHover;
3559
+ const animate = config.animate ?? this.defaults.animate;
3560
+ const showIcon = config.showIcon ?? this.defaults.showIcon;
3561
+ const closable = config.closable ?? this.defaults.closable;
3562
+ const classList = [
3563
+ 'geo-toast-notice',
3564
+ `geo-toast-notice--${type}`,
3565
+ showIcon ? '' : 'geo-toast-notice--no-icon',
3566
+ closable ? '' : 'geo-toast-notice--no-close',
3567
+ typeof config.className === 'string' ? config.className : '',
3568
+ ]
3569
+ .filter(Boolean)
3570
+ .join(' ');
3571
+ // blank + custom class khi không show icon (ẩn icon mặc định của antd)
3572
+ const nzType = showIcon ? type : 'blank';
3573
+ return this.notification.create(nzType, title, message, {
3574
+ nzDuration: duration,
3575
+ nzPlacement: placement,
3576
+ nzPauseOnHover: pauseOnHover,
3577
+ nzAnimate: animate,
3578
+ nzKey: config.key,
3579
+ nzStyle: config.style,
3580
+ nzClass: classList,
3581
+ nzData: config.data,
3582
+ nzCloseIcon: closable ? undefined : ' ',
3583
+ });
3584
+ }
3585
+ /** Đóng 1 toast theo messageId (từ NzNotificationRef). */
3586
+ remove(id) {
3587
+ this.notification.remove(id);
3588
+ }
3589
+ /** Đóng tất cả toast đang mở. */
3590
+ removeAll() {
3591
+ this.notification.remove();
3592
+ }
3593
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoToastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3594
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoToastService, providedIn: 'root' });
3595
+ }
3596
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoToastService, decorators: [{
3597
+ type: Injectable,
3598
+ args: [{ providedIn: 'root' }]
3599
+ }] });
3600
+
3601
+ /**
3602
+ * Tree checkable — wrap `nz-tree`. Domain dùng `geo-tree`, không import NzTreeModule.
3603
+ * API chính: `nodes` + `checkedKeys` / `checkedKeysChange` (giống pattern ILIS → nz-tree).
3604
+ */
3605
+ class GeoTreeComponent {
3606
+ nodes = [];
3607
+ checkable = false;
3608
+ checkedKeys = [];
3609
+ expandedKeys = [];
3610
+ showLine = false;
3611
+ blockNode = false;
3612
+ checkedKeysChange = new EventEmitter();
3613
+ expandedKeysChange = new EventEmitter();
3614
+ nodeClick = new EventEmitter();
3615
+ onCheckedKeysChange(keys) {
3616
+ this.checkedKeys = keys;
3617
+ this.checkedKeysChange.emit(keys);
3618
+ }
3619
+ onExpandedKeysChange(keys) {
3620
+ this.expandedKeys = keys;
3621
+ this.expandedKeysChange.emit(keys);
3622
+ }
3623
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3624
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: GeoTreeComponent, isStandalone: true, selector: "geo-tree", inputs: { nodes: "nodes", checkable: "checkable", checkedKeys: "checkedKeys", expandedKeys: "expandedKeys", showLine: "showLine", blockNode: "blockNode" }, outputs: { checkedKeysChange: "checkedKeysChange", expandedKeysChange: "expandedKeysChange", nodeClick: "nodeClick" }, host: { classAttribute: "geo-tree-host" }, ngImport: i0, template: "<div class=\"geo-tree\">\n <nz-tree\n [nzData]=\"nodes\"\n [nzCheckable]=\"checkable\"\n [nzCheckedKeys]=\"checkedKeys\"\n [nzExpandedKeys]=\"expandedKeys\"\n [nzShowLine]=\"showLine\"\n [nzBlockNode]=\"blockNode\"\n (nzCheckedKeysChange)=\"onCheckedKeysChange($event)\"\n (nzExpandedKeysChange)=\"onExpandedKeysChange($event)\"\n (nzClick)=\"nodeClick.emit($event)\"\n ></nz-tree>\n</div>\n", styles: [".geo-tree-host{display:block;width:100%}.geo-tree{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: NzTreeModule }, { kind: "component", type: i1$8.NzTreeComponent, selector: "nz-tree", inputs: ["nzShowIcon", "nzHideUnMatched", "nzBlockNode", "nzExpandAll", "nzSelectMode", "nzCheckStrictly", "nzShowExpand", "nzShowLine", "nzCheckable", "nzAsyncData", "nzDraggable", "nzMultiple", "nzExpandedIcon", "nzVirtualItemSize", "nzVirtualMaxBufferPx", "nzVirtualMinBufferPx", "nzVirtualHeight", "nzTreeTemplate", "nzBeforeDrop", "nzData", "nzExpandedKeys", "nzSelectedKeys", "nzCheckedKeys", "nzSearchValue", "nzSearchFunc"], outputs: ["nzExpandedKeysChange", "nzSelectedKeysChange", "nzCheckedKeysChange", "nzSearchValueChange", "nzClick", "nzDblClick", "nzContextMenu", "nzCheckBoxChange", "nzExpandChange", "nzOnDragStart", "nzOnDragEnter", "nzOnDragOver", "nzOnDragLeave", "nzOnDrop", "nzOnDragEnd"], exportAs: ["nzTree"] }], encapsulation: i0.ViewEncapsulation.None });
3625
+ }
3626
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTreeComponent, decorators: [{
3627
+ type: Component,
3628
+ args: [{ selector: 'geo-tree', standalone: true, imports: [NzTreeModule], encapsulation: ViewEncapsulation.None, host: { class: 'geo-tree-host' }, template: "<div class=\"geo-tree\">\n <nz-tree\n [nzData]=\"nodes\"\n [nzCheckable]=\"checkable\"\n [nzCheckedKeys]=\"checkedKeys\"\n [nzExpandedKeys]=\"expandedKeys\"\n [nzShowLine]=\"showLine\"\n [nzBlockNode]=\"blockNode\"\n (nzCheckedKeysChange)=\"onCheckedKeysChange($event)\"\n (nzExpandedKeysChange)=\"onExpandedKeysChange($event)\"\n (nzClick)=\"nodeClick.emit($event)\"\n ></nz-tree>\n</div>\n", styles: [".geo-tree-host{display:block;width:100%}.geo-tree{width:100%}\n"] }]
3629
+ }], propDecorators: { nodes: [{
3630
+ type: Input
3631
+ }], checkable: [{
3632
+ type: Input
3633
+ }], checkedKeys: [{
3634
+ type: Input
3635
+ }], expandedKeys: [{
3636
+ type: Input
3637
+ }], showLine: [{
3638
+ type: Input
3639
+ }], blockNode: [{
3640
+ type: Input
3641
+ }], checkedKeysChange: [{
3642
+ type: Output
3643
+ }], expandedKeysChange: [{
3644
+ type: Output
3645
+ }], nodeClick: [{
3646
+ type: Output
3647
+ }] } });
3648
+
3649
+ const STORAGE_PREFIX = 'geo-column-picker:';
3650
+ function loadColumnPickerState(key) {
3651
+ try {
3652
+ const raw = sessionStorage.getItem(`${STORAGE_PREFIX}${key}`);
3653
+ if (!raw) {
3654
+ return null;
3655
+ }
3656
+ return JSON.parse(raw);
3657
+ }
3658
+ catch {
3659
+ return null;
3660
+ }
3661
+ }
3662
+ function saveColumnPickerState(key, payload) {
3663
+ sessionStorage.setItem(`${STORAGE_PREFIX}${key}`, JSON.stringify(payload));
3664
+ }
3665
+ function applyColumnPickerState(items, state) {
3666
+ return items.map((item) => ({
3667
+ ...item,
3668
+ visible: state.visibility[item.key] ?? item.visible,
3669
+ pinned: state.pinned[item.key] ?? item.pinned ?? null,
3670
+ }));
3671
+ }
3672
+ function mergeColumnPickerItems(items, key) {
3673
+ if (!key) {
3674
+ return items;
3675
+ }
3676
+ const saved = loadColumnPickerState(key);
3677
+ return saved ? applyColumnPickerState(items, saved) : items;
3678
+ }
3679
+
3680
+ class GeoColumnPickerComponent {
3681
+ triggerLabel = 'Ẩn hiện cột';
3682
+ hint = 'Chọn cột hiển thị trên bảng.';
3683
+ items = [];
3684
+ /** Lưu trạng thái ẩn/hiện cột theo session khi người dùng áp dụng */
3685
+ storageKey;
3686
+ apply = new EventEmitter();
3687
+ dropdownVisible = false;
3688
+ draftItems = [];
3689
+ onDropdownVisibleChange(visible) {
3690
+ if (visible) {
3691
+ this.syncDraft();
3692
+ }
3693
+ }
3694
+ onItemChange(key, visible) {
3695
+ this.draftItems = this.draftItems.map((item) => item.key === key ? { ...item, visible } : item);
3696
+ }
3697
+ onApply() {
3698
+ const visibility = {};
3699
+ for (const item of this.draftItems) {
3700
+ visibility[item.key] = item.visible;
3701
+ }
3702
+ /** `pinned` giữ empty để tương thích payload/storage cũ — không còn UI ghim/di chuyển cột. */
3703
+ const payload = { visibility, pinned: {} };
3704
+ this.apply.emit(payload);
3705
+ if (this.storageKey) {
3706
+ saveColumnPickerState(this.storageKey, payload);
3707
+ }
3708
+ this.dropdownVisible = false;
3709
+ }
3710
+ onReset() {
3711
+ this.syncDraft();
3712
+ }
3713
+ syncDraft() {
3714
+ this.draftItems = this.items.map((item) => ({ ...item }));
3715
+ }
3716
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoColumnPickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3717
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoColumnPickerComponent, isStandalone: true, selector: "geo-column-picker", inputs: { triggerLabel: "triggerLabel", hint: "hint", items: "items", storageKey: "storageKey" }, outputs: { apply: "apply" }, ngImport: i0, template: "<div\n class=\"geo-column-picker__trigger\"\n nz-dropdown\n [nzDropdownMenu]=\"menu\"\n nzTrigger=\"click\"\n nzPlacement=\"bottomRight\"\n [(nzVisible)]=\"dropdownVisible\"\n (nzVisibleChange)=\"onDropdownVisibleChange($event)\"\n>\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"eye-invisible\"\n [title]=\"triggerLabel\"\n >\n {{ triggerLabel }}\n </geo-button>\n</div>\n\n<nz-dropdown-menu #menu=\"nzDropdownMenu\">\n <div class=\"geo-column-picker__panel\" (click)=\"$event.stopPropagation()\">\n <p class=\"geo-column-picker__hint\">{{ hint }}</p>\n\n <div class=\"geo-column-picker__list\">\n @for (item of draftItems; track item.key) {\n <div class=\"geo-column-picker__row\">\n <geo-checkbox\n class=\"geo-column-picker__item\"\n [label]=\"item.title\"\n [checked]=\"item.visible\"\n [disabled]=\"item.locked ?? false\"\n (checkedChange)=\"onItemChange(item.key, $event)\"\n ></geo-checkbox>\n </div>\n }\n </div>\n\n <div class=\"geo-column-picker__actions\">\n <button nz-button nzType=\"default\" nzSize=\"small\" (click)=\"onReset()\">\u0110\u1EB7t l\u1EA1i</button>\n <button nz-button nzType=\"primary\" nzSize=\"small\" (click)=\"onApply()\">\u00C1p d\u1EE5ng</button>\n </div>\n </div>\n</nz-dropdown-menu>\n", styles: [":host{display:inline-block}.geo-column-picker__trigger{display:inline-flex}.geo-column-picker__panel{width:320px;padding:12px 16px 16px;background:var(--geo-color-neutral-white);border-radius:var(--geo-radius);box-shadow:0 6px 16px #00000014}.geo-column-picker__hint{margin:0 0 12px;color:var(--geo-color-neutral-500);font-size:13px;line-height:20px}.geo-column-picker__list{display:flex;flex-direction:column;gap:8px;max-height:320px;overflow-y:auto}.geo-column-picker__row{display:flex;align-items:center;gap:8px}.geo-column-picker__item{display:flex;align-items:center;flex:1;min-width:0}.geo-column-picker__actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px;padding-top:12px;border-top:1px solid var(--geo-color-neutral-100)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: NgZorroAntdModule }, { kind: "component", type: i1$9.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i1$5.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "directive", type: i3$4.NzWaveDirective, selector: "[nz-wave],button[nz-button]:not([nzType=\"link\"]):not([nzType=\"text\"])", inputs: ["nzWaveExtraNode"], exportAs: ["nzWave"] }, { kind: "directive", type: i2$5.NzDropDownDirective, selector: "[nz-dropdown]", inputs: ["nzDropdownMenu", "nzTrigger", "nzMatchWidthElement", "nzBackdrop", "nzClickHide", "nzDisabled", "nzVisible", "nzOverlayClassName", "nzOverlayStyle", "nzPlacement"], outputs: ["nzVisibleChange"], exportAs: ["nzDropdown"] }, { kind: "component", type: i2$5.NzDropdownMenuComponent, selector: "nz-dropdown-menu", exportAs: ["nzDropdownMenu"] }, { kind: "component", type: GeoButtonComponent, selector: "geo-button", inputs: ["appearance", "color", "icon", "iconTheme", "iconPlacement", "iconOnly", "type", "disabled", "tooltip", "tooltipPlacement", "active", "title"], outputs: ["clicked"] }, { kind: "component", type: GeoCheckboxComponent, selector: "geo-checkbox", inputs: ["label", "checked", "disabled", "indeterminate"], outputs: ["checkedChange"] }] });
3718
+ }
3719
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoColumnPickerComponent, decorators: [{
3720
+ type: Component,
3721
+ args: [{ selector: 'geo-column-picker', standalone: true, imports: [CommonModule, NgZorroAntdModule, GeoButtonComponent, GeoCheckboxComponent], template: "<div\n class=\"geo-column-picker__trigger\"\n nz-dropdown\n [nzDropdownMenu]=\"menu\"\n nzTrigger=\"click\"\n nzPlacement=\"bottomRight\"\n [(nzVisible)]=\"dropdownVisible\"\n (nzVisibleChange)=\"onDropdownVisibleChange($event)\"\n>\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"eye-invisible\"\n [title]=\"triggerLabel\"\n >\n {{ triggerLabel }}\n </geo-button>\n</div>\n\n<nz-dropdown-menu #menu=\"nzDropdownMenu\">\n <div class=\"geo-column-picker__panel\" (click)=\"$event.stopPropagation()\">\n <p class=\"geo-column-picker__hint\">{{ hint }}</p>\n\n <div class=\"geo-column-picker__list\">\n @for (item of draftItems; track item.key) {\n <div class=\"geo-column-picker__row\">\n <geo-checkbox\n class=\"geo-column-picker__item\"\n [label]=\"item.title\"\n [checked]=\"item.visible\"\n [disabled]=\"item.locked ?? false\"\n (checkedChange)=\"onItemChange(item.key, $event)\"\n ></geo-checkbox>\n </div>\n }\n </div>\n\n <div class=\"geo-column-picker__actions\">\n <button nz-button nzType=\"default\" nzSize=\"small\" (click)=\"onReset()\">\u0110\u1EB7t l\u1EA1i</button>\n <button nz-button nzType=\"primary\" nzSize=\"small\" (click)=\"onApply()\">\u00C1p d\u1EE5ng</button>\n </div>\n </div>\n</nz-dropdown-menu>\n", styles: [":host{display:inline-block}.geo-column-picker__trigger{display:inline-flex}.geo-column-picker__panel{width:320px;padding:12px 16px 16px;background:var(--geo-color-neutral-white);border-radius:var(--geo-radius);box-shadow:0 6px 16px #00000014}.geo-column-picker__hint{margin:0 0 12px;color:var(--geo-color-neutral-500);font-size:13px;line-height:20px}.geo-column-picker__list{display:flex;flex-direction:column;gap:8px;max-height:320px;overflow-y:auto}.geo-column-picker__row{display:flex;align-items:center;gap:8px}.geo-column-picker__item{display:flex;align-items:center;flex:1;min-width:0}.geo-column-picker__actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px;padding-top:12px;border-top:1px solid var(--geo-color-neutral-100)}\n"] }]
3722
+ }], propDecorators: { triggerLabel: [{
3723
+ type: Input
3724
+ }], hint: [{
3725
+ type: Input
3726
+ }], items: [{
3727
+ type: Input
3728
+ }], storageKey: [{
3729
+ type: Input
3730
+ }], apply: [{
3731
+ type: Output
3732
+ }] } });
3733
+
3734
+ class GeoTableToolbarComponent {
3735
+ resultLabel = '';
3736
+ resultCount = null;
3737
+ selectedCount = 0;
3738
+ showDelete = true;
3739
+ showExport = true;
3740
+ showColumnToggle = true;
3741
+ showAdd = true;
3742
+ addLabel = 'Thêm mới';
3743
+ columnItems = [];
3744
+ /** Key lưu trạng thái ẩn/hiện cột trong sessionStorage */
3745
+ columnStorageKey;
3746
+ deleteClick = new EventEmitter();
3747
+ exportClick = new EventEmitter();
3748
+ toggleColumns = new EventEmitter();
3749
+ columnApply = new EventEmitter();
3750
+ addClick = new EventEmitter();
3751
+ get displayResultLabel() {
3752
+ if (this.resultLabel) {
3753
+ return this.resultLabel;
3754
+ }
3755
+ const count = this.resultCount ?? 0;
3756
+ return `Kết quả tìm kiếm (${count} kết quả)`;
3757
+ }
3758
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTableToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3759
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoTableToolbarComponent, isStandalone: true, selector: "geo-table-toolbar", inputs: { resultLabel: "resultLabel", resultCount: "resultCount", selectedCount: "selectedCount", showDelete: "showDelete", showExport: "showExport", showColumnToggle: "showColumnToggle", showAdd: "showAdd", addLabel: "addLabel", columnItems: "columnItems", columnStorageKey: "columnStorageKey" }, outputs: { deleteClick: "deleteClick", exportClick: "exportClick", toggleColumns: "toggleColumns", columnApply: "columnApply", addClick: "addClick" }, ngImport: i0, template: "<div class=\"geo-table-toolbar\">\n <div class=\"geo-table-toolbar__info\">{{ displayResultLabel }}</div>\n\n <div class=\"geo-table-toolbar__actions\">\n @if (showDelete && selectedCount > 0) {\n <geo-button\n appearance=\"secondary\"\n color=\"danger\"\n icon=\"delete\"\n title=\"X\u00F3a\"\n (clicked)=\"deleteClick.emit()\"\n >\n X\u00F3a ({{ selectedCount }})\n </geo-button>\n }\n\n @if (showExport) {\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"download\"\n title=\"Xu\u1EA5t d\u1EEF li\u1EC7u\"\n (clicked)=\"exportClick.emit()\"\n >\n Xu\u1EA5t d\u1EEF li\u1EC7u\n </geo-button>\n }\n\n @if (showColumnToggle) {\n @if (columnItems.length) {\n <geo-column-picker\n [items]=\"columnItems\"\n [storageKey]=\"columnStorageKey\"\n (apply)=\"columnApply.emit($event)\"\n ></geo-column-picker>\n } @else {\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"eye-invisible\"\n title=\"\u1EA8n hi\u1EC7n c\u1ED9t\"\n (clicked)=\"toggleColumns.emit()\"\n >\n \u1EA8n hi\u1EC7n c\u1ED9t\n </geo-button>\n }\n }\n\n @if (showAdd) {\n <geo-button\n appearance=\"primary\"\n color=\"brand\"\n icon=\"plus\"\n [title]=\"addLabel\"\n (clicked)=\"addClick.emit()\"\n >\n {{ addLabel }}\n </geo-button>\n }\n </div>\n</div>\n", styles: [":host{display:block}.geo-table-toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}.geo-table-toolbar__info{font-size:16px;font-weight:600;line-height:24px;color:var(--geo-color-neutral-900)}.geo-table-toolbar__actions{display:flex;align-items:center;justify-content:flex-end;gap:10px;flex-wrap:wrap;margin-left:auto}@media (max-width: 767px){.geo-table-toolbar{flex-direction:column;align-items:stretch}.geo-table-toolbar__actions{margin-left:0;justify-content:flex-start}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: NgZorroAntdModule }, { kind: "component", type: GeoButtonComponent, selector: "geo-button", inputs: ["appearance", "color", "icon", "iconTheme", "iconPlacement", "iconOnly", "type", "disabled", "tooltip", "tooltipPlacement", "active", "title"], outputs: ["clicked"] }, { kind: "component", type: GeoColumnPickerComponent, selector: "geo-column-picker", inputs: ["triggerLabel", "hint", "items", "storageKey"], outputs: ["apply"] }] });
3760
+ }
3761
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoTableToolbarComponent, decorators: [{
3762
+ type: Component,
3763
+ args: [{ selector: 'geo-table-toolbar', standalone: true, imports: [CommonModule, NgZorroAntdModule, GeoButtonComponent, GeoColumnPickerComponent], template: "<div class=\"geo-table-toolbar\">\n <div class=\"geo-table-toolbar__info\">{{ displayResultLabel }}</div>\n\n <div class=\"geo-table-toolbar__actions\">\n @if (showDelete && selectedCount > 0) {\n <geo-button\n appearance=\"secondary\"\n color=\"danger\"\n icon=\"delete\"\n title=\"X\u00F3a\"\n (clicked)=\"deleteClick.emit()\"\n >\n X\u00F3a ({{ selectedCount }})\n </geo-button>\n }\n\n @if (showExport) {\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"download\"\n title=\"Xu\u1EA5t d\u1EEF li\u1EC7u\"\n (clicked)=\"exportClick.emit()\"\n >\n Xu\u1EA5t d\u1EEF li\u1EC7u\n </geo-button>\n }\n\n @if (showColumnToggle) {\n @if (columnItems.length) {\n <geo-column-picker\n [items]=\"columnItems\"\n [storageKey]=\"columnStorageKey\"\n (apply)=\"columnApply.emit($event)\"\n ></geo-column-picker>\n } @else {\n <geo-button\n appearance=\"secondary\"\n color=\"brand\"\n icon=\"eye-invisible\"\n title=\"\u1EA8n hi\u1EC7n c\u1ED9t\"\n (clicked)=\"toggleColumns.emit()\"\n >\n \u1EA8n hi\u1EC7n c\u1ED9t\n </geo-button>\n }\n }\n\n @if (showAdd) {\n <geo-button\n appearance=\"primary\"\n color=\"brand\"\n icon=\"plus\"\n [title]=\"addLabel\"\n (clicked)=\"addClick.emit()\"\n >\n {{ addLabel }}\n </geo-button>\n }\n </div>\n</div>\n", styles: [":host{display:block}.geo-table-toolbar{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}.geo-table-toolbar__info{font-size:16px;font-weight:600;line-height:24px;color:var(--geo-color-neutral-900)}.geo-table-toolbar__actions{display:flex;align-items:center;justify-content:flex-end;gap:10px;flex-wrap:wrap;margin-left:auto}@media (max-width: 767px){.geo-table-toolbar{flex-direction:column;align-items:stretch}.geo-table-toolbar__actions{margin-left:0;justify-content:flex-start}}\n"] }]
3764
+ }], propDecorators: { resultLabel: [{
3765
+ type: Input
3766
+ }], resultCount: [{
3767
+ type: Input
3768
+ }], selectedCount: [{
3769
+ type: Input
3770
+ }], showDelete: [{
3771
+ type: Input
3772
+ }], showExport: [{
3773
+ type: Input
3774
+ }], showColumnToggle: [{
3775
+ type: Input
3776
+ }], showAdd: [{
3777
+ type: Input
3778
+ }], addLabel: [{
3779
+ type: Input
3780
+ }], columnItems: [{
3781
+ type: Input
3782
+ }], columnStorageKey: [{
3783
+ type: Input
3784
+ }], deleteClick: [{
3785
+ type: Output
3786
+ }], exportClick: [{
3787
+ type: Output
3788
+ }], toggleColumns: [{
3789
+ type: Output
3790
+ }], columnApply: [{
3791
+ type: Output
3792
+ }], addClick: [{
3793
+ type: Output
3794
+ }] } });
3795
+
3796
+ /*
3797
+ * Public API Surface of geo-ui
3798
+ */
3799
+
3800
+ /**
3801
+ * Generated bundle index. Do not edit.
3802
+ */
3803
+
3804
+ export { DEFAULT_UI_ROW_ACTIONS, DEFAULT_UI_TABLE_PAGE_SIZE_OPTIONS, GEO_ICON_SIZE_MAP, GEO_STATUS_COLOR_MAP, GEO_STATUS_LABELS, GEO_TOAST_DEFAULT_TITLES, GEO_TOAST_ICONS, GEO_TYPOGRAPHY_TAG, GEO_TYPOGRAPHY_VARIANTS, GeoAlertComponent, GeoBackButtonComponent, GeoBreadcrumbComponent, GeoButtonComponent, GeoCheckboxComponent, GeoColumnPickerComponent, GeoConfirmModalComponent, GeoDatePickerComponent, GeoDateRangePickerComponent, GeoFilePickerComponent, GeoFormModalComponent, GeoIconComponent, GeoInputComponent, GeoPageTitleComponent, GeoPaginationComponent, GeoRadioComponent, GeoRowActionsComponent, GeoSelectComponent, GeoSliderComponent, GeoStatusTagComponent, GeoStepFormLayoutComponent, GeoStepperComponent, GeoTabDirective, GeoTableComponent, GeoTableFilterComponent, GeoTablePaginationComponent, GeoTableToolbarComponent, GeoTabsComponent, GeoTextareaComponent, GeoToastComponent, GeoToastService, GeoTreeComponent, GeoTypographyComponent, GeoUploadComponent, NgZorroAntdModule, UI_ALERT_DEFAULT_TITLES, UI_STATUS_LABELS, UI_TABLE_MOBILE_BREAKPOINT, applyColumnPickerState, cssVar, geoColorCssVars, geoColorTokens, geoFormatBytes, geoFormatSpeed, geoRadiusCssVars, geoRadiusTokens, geoTypographyTokens, geoUploadPercent, loadColumnPickerState, mergeColumnPickerItems, pickInlineRowActions, pickOverflowRowActions, saveColumnPickerState };
3805
+ //# sourceMappingURL=geoit-ui.mjs.map