@fui-org/fui-cli 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/README.md +20 -2
  2. package/dist/fui.js +347 -44
  3. package/package.json +15 -3
  4. package/skills/fui/SKILL.md +149 -66
  5. package/skills/fui-skill/README.md +112 -0
  6. package/skills/fui-skill/SKILL.md +269 -0
  7. package/skills/fui-skill/assets/projectdefaultstyle.css +518 -0
  8. package/skills/fui-skill/design-md/airbnb/DESIGN.md +545 -0
  9. package/skills/fui-skill/design-md/airbnb/README.md +5 -0
  10. package/skills/fui-skill/design-md/airtable/DESIGN.md +554 -0
  11. package/skills/fui-skill/design-md/airtable/README.md +5 -0
  12. package/skills/fui-skill/design-md/apple/DESIGN.md +562 -0
  13. package/skills/fui-skill/design-md/apple/README.md +5 -0
  14. package/skills/fui-skill/design-md/asu/DESIGN.md +179 -0
  15. package/skills/fui-skill/design-md/asu/README.md +107 -0
  16. package/skills/fui-skill/design-md/binance/DESIGN.md +634 -0
  17. package/skills/fui-skill/design-md/binance/README.md +5 -0
  18. package/skills/fui-skill/design-md/bmw/DESIGN.md +544 -0
  19. package/skills/fui-skill/design-md/bmw/README.md +5 -0
  20. package/skills/fui-skill/design-md/bmw-m/DESIGN.md +503 -0
  21. package/skills/fui-skill/design-md/bmw-m/README.md +5 -0
  22. package/skills/fui-skill/design-md/bugatti/DESIGN.md +454 -0
  23. package/skills/fui-skill/design-md/bugatti/README.md +5 -0
  24. package/skills/fui-skill/design-md/cal/DESIGN.md +542 -0
  25. package/skills/fui-skill/design-md/cal/README.md +5 -0
  26. package/skills/fui-skill/design-md/claude/DESIGN.md +589 -0
  27. package/skills/fui-skill/design-md/claude/README.md +5 -0
  28. package/skills/fui-skill/design-md/clay/DESIGN.md +541 -0
  29. package/skills/fui-skill/design-md/clay/README.md +5 -0
  30. package/skills/fui-skill/design-md/clickhouse/DESIGN.md +544 -0
  31. package/skills/fui-skill/design-md/clickhouse/README.md +5 -0
  32. package/skills/fui-skill/design-md/cohere/DESIGN.md +451 -0
  33. package/skills/fui-skill/design-md/cohere/README.md +5 -0
  34. package/skills/fui-skill/design-md/coinbase/DESIGN.md +570 -0
  35. package/skills/fui-skill/design-md/coinbase/README.md +5 -0
  36. package/skills/fui-skill/design-md/composio/DESIGN.md +506 -0
  37. package/skills/fui-skill/design-md/composio/README.md +5 -0
  38. package/skills/fui-skill/design-md/cursor/DESIGN.md +537 -0
  39. package/skills/fui-skill/design-md/cursor/README.md +5 -0
  40. package/skills/fui-skill/design-md/elevenlabs/DESIGN.md +504 -0
  41. package/skills/fui-skill/design-md/elevenlabs/README.md +5 -0
  42. package/skills/fui-skill/design-md/expo/DESIGN.md +526 -0
  43. package/skills/fui-skill/design-md/expo/README.md +5 -0
  44. package/skills/fui-skill/design-md/ferrari/DESIGN.md +531 -0
  45. package/skills/fui-skill/design-md/ferrari/README.md +5 -0
  46. package/skills/fui-skill/design-md/figma/DESIGN.md +578 -0
  47. package/skills/fui-skill/design-md/figma/README.md +5 -0
  48. package/skills/fui-skill/design-md/framer/DESIGN.md +544 -0
  49. package/skills/fui-skill/design-md/framer/README.md +5 -0
  50. package/skills/fui-skill/design-md/fui/DESIGN.md +532 -0
  51. package/skills/fui-skill/design-md/hashicorp/DESIGN.md +575 -0
  52. package/skills/fui-skill/design-md/hashicorp/README.md +5 -0
  53. package/skills/fui-skill/design-md/ibm/DESIGN.md +550 -0
  54. package/skills/fui-skill/design-md/ibm/README.md +5 -0
  55. package/skills/fui-skill/design-md/intercom/DESIGN.md +546 -0
  56. package/skills/fui-skill/design-md/intercom/README.md +5 -0
  57. package/skills/fui-skill/design-md/kraken/DESIGN.md +125 -0
  58. package/skills/fui-skill/design-md/kraken/README.md +5 -0
  59. package/skills/fui-skill/design-md/lamborghini/DESIGN.md +288 -0
  60. package/skills/fui-skill/design-md/lamborghini/README.md +5 -0
  61. package/skills/fui-skill/design-md/linear.app/DESIGN.md +548 -0
  62. package/skills/fui-skill/design-md/linear.app/README.md +5 -0
  63. package/skills/fui-skill/design-md/lovable/DESIGN.md +298 -0
  64. package/skills/fui-skill/design-md/lovable/README.md +5 -0
  65. package/skills/fui-skill/design-md/mastercard/DESIGN.md +365 -0
  66. package/skills/fui-skill/design-md/mastercard/README.md +5 -0
  67. package/skills/fui-skill/design-md/meta/DESIGN.md +683 -0
  68. package/skills/fui-skill/design-md/meta/README.md +5 -0
  69. package/skills/fui-skill/design-md/minimax/DESIGN.md +746 -0
  70. package/skills/fui-skill/design-md/minimax/README.md +5 -0
  71. package/skills/fui-skill/design-md/mintlify/DESIGN.md +852 -0
  72. package/skills/fui-skill/design-md/mintlify/README.md +5 -0
  73. package/skills/fui-skill/design-md/miro/DESIGN.md +825 -0
  74. package/skills/fui-skill/design-md/miro/README.md +5 -0
  75. package/skills/fui-skill/design-md/mistral.ai/DESIGN.md +773 -0
  76. package/skills/fui-skill/design-md/mistral.ai/README.md +5 -0
  77. package/skills/fui-skill/design-md/mongodb/DESIGN.md +767 -0
  78. package/skills/fui-skill/design-md/mongodb/README.md +5 -0
  79. package/skills/fui-skill/design-md/nike/DESIGN.md +575 -0
  80. package/skills/fui-skill/design-md/nike/README.md +5 -0
  81. package/skills/fui-skill/design-md/notion/DESIGN.md +821 -0
  82. package/skills/fui-skill/design-md/notion/README.md +5 -0
  83. package/skills/fui-skill/design-md/nvidia/DESIGN.md +640 -0
  84. package/skills/fui-skill/design-md/nvidia/README.md +5 -0
  85. package/skills/fui-skill/design-md/ollama/DESIGN.md +539 -0
  86. package/skills/fui-skill/design-md/ollama/README.md +5 -0
  87. package/skills/fui-skill/design-md/opencode.ai/DESIGN.md +521 -0
  88. package/skills/fui-skill/design-md/opencode.ai/README.md +5 -0
  89. package/skills/fui-skill/design-md/pinterest/DESIGN.md +597 -0
  90. package/skills/fui-skill/design-md/pinterest/README.md +5 -0
  91. package/skills/fui-skill/design-md/playstation/DESIGN.md +661 -0
  92. package/skills/fui-skill/design-md/playstation/README.md +5 -0
  93. package/skills/fui-skill/design-md/posthog/DESIGN.md +690 -0
  94. package/skills/fui-skill/design-md/posthog/README.md +5 -0
  95. package/skills/fui-skill/design-md/raycast/DESIGN.md +669 -0
  96. package/skills/fui-skill/design-md/raycast/README.md +5 -0
  97. package/skills/fui-skill/design-md/renault/DESIGN.md +589 -0
  98. package/skills/fui-skill/design-md/renault/README.md +5 -0
  99. package/skills/fui-skill/design-md/replicate/DESIGN.md +616 -0
  100. package/skills/fui-skill/design-md/replicate/README.md +5 -0
  101. package/skills/fui-skill/design-md/resend/DESIGN.md +585 -0
  102. package/skills/fui-skill/design-md/resend/README.md +5 -0
  103. package/skills/fui-skill/design-md/revolut/DESIGN.md +636 -0
  104. package/skills/fui-skill/design-md/revolut/README.md +5 -0
  105. package/skills/fui-skill/design-md/runwayml/DESIGN.md +244 -0
  106. package/skills/fui-skill/design-md/runwayml/README.md +5 -0
  107. package/skills/fui-skill/design-md/sanity/DESIGN.md +357 -0
  108. package/skills/fui-skill/design-md/sanity/README.md +5 -0
  109. package/skills/fui-skill/design-md/sentry/DESIGN.md +551 -0
  110. package/skills/fui-skill/design-md/sentry/README.md +5 -0
  111. package/skills/fui-skill/design-md/shopify/DESIGN.md +516 -0
  112. package/skills/fui-skill/design-md/shopify/README.md +5 -0
  113. package/skills/fui-skill/design-md/slack/DESIGN.md +482 -0
  114. package/skills/fui-skill/design-md/spacex/DESIGN.md +363 -0
  115. package/skills/fui-skill/design-md/spacex/README.md +5 -0
  116. package/skills/fui-skill/design-md/spotify/DESIGN.md +246 -0
  117. package/skills/fui-skill/design-md/spotify/README.md +5 -0
  118. package/skills/fui-skill/design-md/starbucks/DESIGN.md +580 -0
  119. package/skills/fui-skill/design-md/starbucks/README.md +5 -0
  120. package/skills/fui-skill/design-md/stripe/DESIGN.md +487 -0
  121. package/skills/fui-skill/design-md/stripe/README.md +5 -0
  122. package/skills/fui-skill/design-md/supabase/DESIGN.md +462 -0
  123. package/skills/fui-skill/design-md/supabase/README.md +5 -0
  124. package/skills/fui-skill/design-md/superhuman/DESIGN.md +448 -0
  125. package/skills/fui-skill/design-md/superhuman/README.md +5 -0
  126. package/skills/fui-skill/design-md/tesla/DESIGN.md +286 -0
  127. package/skills/fui-skill/design-md/tesla/README.md +5 -0
  128. package/skills/fui-skill/design-md/theverge/DESIGN.md +339 -0
  129. package/skills/fui-skill/design-md/theverge/README.md +5 -0
  130. package/skills/fui-skill/design-md/together.ai/DESIGN.md +633 -0
  131. package/skills/fui-skill/design-md/together.ai/README.md +5 -0
  132. package/skills/fui-skill/design-md/uber/DESIGN.md +636 -0
  133. package/skills/fui-skill/design-md/uber/README.md +5 -0
  134. package/skills/fui-skill/design-md/vercel/DESIGN.md +736 -0
  135. package/skills/fui-skill/design-md/vercel/README.md +5 -0
  136. package/skills/fui-skill/design-md/vodafone/DESIGN.md +538 -0
  137. package/skills/fui-skill/design-md/vodafone/README.md +5 -0
  138. package/skills/fui-skill/design-md/voltagent/DESIGN.md +521 -0
  139. package/skills/fui-skill/design-md/voltagent/README.md +5 -0
  140. package/skills/fui-skill/design-md/warp/DESIGN.md +526 -0
  141. package/skills/fui-skill/design-md/warp/README.md +5 -0
  142. package/skills/fui-skill/design-md/webflow/DESIGN.md +588 -0
  143. package/skills/fui-skill/design-md/webflow/README.md +5 -0
  144. package/skills/fui-skill/design-md/wired/DESIGN.md +497 -0
  145. package/skills/fui-skill/design-md/wired/README.md +5 -0
  146. package/skills/fui-skill/design-md/wise/DESIGN.md +544 -0
  147. package/skills/fui-skill/design-md/wise/README.md +5 -0
  148. package/skills/fui-skill/design-md/x.ai/DESIGN.md +465 -0
  149. package/skills/fui-skill/design-md/x.ai/README.md +5 -0
  150. package/skills/fui-skill/design-md/zapier/DESIGN.md +537 -0
  151. package/skills/fui-skill/design-md/zapier/README.md +5 -0
  152. package/skills/fui-skill/examples/component.vue +162 -0
  153. package/skills/fui-skill/examples/f-table-patterns.json +331 -0
  154. package/skills/fui-skill/examples/module-patterns.json +973 -0
  155. package/skills/fui-skill/examples/project-patterns.json +222 -0
  156. package/skills/fui-skill/metadata.json +75 -0
  157. package/skills/fui-skill/references/INDEX.md +144 -0
  158. package/skills/fui-skill/references/advanced-techniques.md +160 -0
  159. package/skills/fui-skill/references/coding-standards.md +112 -0
  160. package/skills/fui-skill/references/component-design.md +455 -0
  161. package/skills/fui-skill/references/component-quickref.md +77 -0
  162. package/skills/fui-skill/references/component-table.md +276 -0
  163. package/skills/fui-skill/references/components-dialog.md +192 -0
  164. package/skills/fui-skill/references/components-display.md +147 -0
  165. package/skills/fui-skill/references/components-echart.md +391 -0
  166. package/skills/fui-skill/references/components-input.md +359 -0
  167. package/skills/fui-skill/references/controls-patterns.md +847 -0
  168. package/skills/fui-skill/references/controls-styling-vocabulary.md +140 -0
  169. package/skills/fui-skill/references/db-table-design.md +77 -0
  170. package/skills/fui-skill/references/db-workflow.md +504 -0
  171. package/skills/fui-skill/references/default-function.md +415 -0
  172. package/skills/fui-skill/references/design-modes.md +85 -0
  173. package/skills/fui-skill/references/echart-templates.md +481 -0
  174. package/skills/fui-skill/references/fastproject.md +97 -0
  175. package/skills/fui-skill/references/fsheet.md +218 -0
  176. package/skills/fui-skill/references/fullstack-workflow.md +351 -0
  177. package/skills/fui-skill/references/module-data-patterns.md +126 -0
  178. package/skills/fui-skill/references/module-json-anatomy.md +137 -0
  179. package/skills/fui-skill/references/module-structure.md +260 -0
  180. package/skills/fui-skill/references/new-session.md +108 -0
  181. package/skills/fui-skill/references/pdfmake.md +60 -0
  182. package/skills/fui-skill/references/permission-system.md +169 -0
  183. package/skills/fui-skill/references/platform-architecture.md +294 -0
  184. package/skills/fui-skill/references/project-config.md +335 -0
  185. package/skills/fui-skill/references/project-provisioning.md +383 -0
  186. package/skills/fui-skill/references/script-map.md +296 -0
  187. package/skills/fui-skill/references/sql-clr-functions.md +224 -0
  188. package/skills/fui-skill/references/system-design.md +116 -0
  189. package/skills/fui-skill/references/tapi-file-api.md +191 -0
  190. package/skills/fui-skill/references/tapi-permission-patterns.md +158 -0
  191. package/skills/fui-skill/references/tapi-reference.md +549 -0
  192. package/skills/fui-skill/references/tools-registry.md +460 -0
  193. package/skills/fui-skill/references/ui-crosswindow-patterns.md +317 -0
  194. package/skills/fui-skill/references/ui-dialog-patterns.md +229 -0
  195. package/skills/fui-skill/references/ui-layout-patterns.md +176 -0
  196. package/skills/fui-skill/references/ui-patterns.md +315 -0
  197. package/skills/fui-skill/references/ui-screenshot-review.md +94 -0
  198. package/skills/fui-skill/references/ui-table-cell-patterns.md +316 -0
  199. package/skills/fui-skill/references/ui-templates.md +29 -0
  200. package/skills/fui-skill/references/verification.md +246 -0
  201. package/skills/fui-skill/references/watcher-patterns.md +196 -0
  202. package/skills/fui-skill/references/websocket-realtime.md +254 -0
  203. package/skills/fui-skill/scripts/component-3.0.js +2549 -0
  204. package/skills/fui-skill/scripts/component.js +3142 -0
  205. package/skills/fui-skill/scripts/componentTable-3.0.js +909 -0
  206. package/skills/fui-skill/scripts/componentTable.js +769 -0
  207. package/skills/fui-skill/scripts/defaultfunction-3.0.js +781 -0
  208. package/skills/fui-skill/scripts/defaultfunction.js +966 -0
  209. package/skills/fui-skill/scripts/fastproject-3.0.js +870 -0
  210. package/skills/fui-skill/scripts/fastproject.js +828 -0
  211. package/skills/fui-skill/scripts/fechart.js +890 -0
  212. package/skills/fui-skill/scripts/fsheet.js +1330 -0
@@ -0,0 +1,317 @@
1
+ # FUI Cross-window Patterns — openWindow & data exchange
2
+
3
+ > File này sở hữu: **`openWindow`, trao đổi dữ liệu giữa cửa sổ (`#PARENT`/`#Win`), `set.menu` cho module con, `onclose`**.
4
+
5
+ Mở module như sub-window và trao đổi dữ liệu giữa các window/iframe (`#PARENT`, `#WinID`). Rút ra từ project **security-manager** và các ví dụ `ex-v3-*`.
6
+
7
+ > Xem thêm: [ui-patterns.md](ui-patterns.md), [default-function.md](default-function.md) (`openWindow`, `windowSendMessage`).
8
+
9
+ ---
10
+
11
+ ## 1. Mở Sub-window (openWindow) — Đầy đủ
12
+
13
+ Mở module khác như popup window riêng biệt. `id` là định danh để tham chiếu sau này.
14
+
15
+ ```json
16
+ {
17
+ "FUN": "openWindow",
18
+ "IN": {
19
+ "id": "`Win1",
20
+ "title": "`User Permission",
21
+ "url": "`/UserPermission",
22
+ "data": "danhSachChoTable",
23
+ "width": "`800px",
24
+ "height": "`600px",
25
+ "onclose": {
26
+ "CALL": "reloadData"
27
+ }
28
+ }
29
+ }
30
+ ```
31
+
32
+ | Param | Bắt buộc | Mô tả |
33
+ |---|---|---|
34
+ | `id` | ✅ | Định danh window (backtick = literal) — dùng để ref qua `#Win1` |
35
+ | `url` | ✅ | URL module — không truyền `?menu=0`; module con tự khai báo `"set": { "menu": false }` |
36
+ | `title` | ❌ | Tiêu đề dialog |
37
+ | `data` | ❌ | Truyền dữ liệu vào window con — window con đọc qua `#PARENT.data` |
38
+ | `width` / `height` | ❌ | Kích thước window (`"800px"`, `"50%"`) |
39
+ | `onclose` | ❌ | Action chạy sau khi sub-window đóng |
40
+
41
+ > **Module con mở qua openWindow:** Không truyền `?menu=0` trong URL. Module con tự khai báo `"set": { "menu": false }` trong module.json để ẩn menu vĩnh viễn cho module đó — bất kể cách mở. URL chỉ truyền ID cần thiết để query DB.
42
+
43
+ **`onclose` targeting window khác:**
44
+
45
+ ```json
46
+ "onclose": {
47
+ "#Win1": { "CALL": "cmdThongBao" }
48
+ }
49
+ ```
50
+
51
+ > Khi Win2 đóng → chạy `cmdThongBao` trong Win1 (không phải trong window hiện tại).
52
+
53
+ ---
54
+
55
+ ## 2. Cross-window Data Exchange — Đầy đủ
56
+
57
+ FUI dùng `#PARENT` và `#WinID` để trao đổi dữ liệu giữa các window (iframe). Hoạt động cả same-domain và cross-domain (qua `postMessage`).
58
+
59
+ ### Đọc dữ liệu từ window khác (value position)
60
+
61
+ ```json
62
+ "data": [
63
+ {
64
+ "sUserID": "#PARENT.sUserID",
65
+ "sFullName": "#PARENT.sFullName",
66
+ "dataFromWin1": "#Win1.apiChart"
67
+ }
68
+ ]
69
+ ```
70
+
71
+ | Cú pháp | Ý nghĩa |
72
+ |---|---|
73
+ | `"#PARENT.field"` | Đọc `vueData.field` từ window cha |
74
+ | `"#Win1.field"` | Đọc `vueData.field` từ iframe có id `Win1` |
75
+
76
+ ### Ghi dữ liệu vào window khác (key position)
77
+
78
+ ```json
79
+ "data": [
80
+ {
81
+ "#PARENT.abcdef": 1234567890,
82
+ "#Win1.dulieuTuForm2": "`huynh cao tuan"
83
+ }
84
+ ]
85
+ ```
86
+
87
+ ```json
88
+ ":action": {
89
+ "#PARENT.val4": "DauRaTuCauTruc_IN"
90
+ }
91
+ ```
92
+
93
+ | Cú pháp | Ý nghĩa |
94
+ |---|---|
95
+ | `"#PARENT.field": value` | Ghi value vào `vueData.field` của parent |
96
+ | `"#Win1.field": value` | Ghi value vào `vueData.field` của Win1 |
97
+
98
+ ### Gọi action trong window khác
99
+
100
+ ```json
101
+ ":action": {
102
+ "#PARENT": { "CALL": "cmdSETData" }
103
+ }
104
+ ```
105
+
106
+ ```json
107
+ "#Win1": { "CALL": "cmdThongBao" }
108
+ ```
109
+
110
+ - `"#PARENT"` (không có field) với value là action → `runAction(value)` trong parent
111
+ - `"#Win1"` với value là action → `runAction(value)` trong Win1
112
+
113
+ ### Nhận dữ liệu được truyền khi openWindow
114
+
115
+ Khi window cha mở con với `"data": "sourceData"`:
116
+
117
+ ```json
118
+ "data": [
119
+ {
120
+ "LayDuLieuWinCha": "#PARENT.Win1"
121
+ }
122
+ ]
123
+ ```
124
+
125
+ > `#PARENT.Win1` đọc biến `Win1` từ parent. Khi cha gọi `openWindow` với `id: "Win1"`, FUI tự set `vueData.Win1 = data_đã_truyền` trong parent trước khi mở window.
126
+
127
+ ### Pattern đầy đủ — Sub-window nhận data từ parent
128
+
129
+ **Module cha (ex-v3-1SetData):**
130
+ ```json
131
+ ":action": {
132
+ "FUN": "openWindow",
133
+ "IN": {
134
+ "id": "`Win1",
135
+ "url": "`/ex/ex-v3-2CauTruc",
136
+ "data": "danhSachChoTable"
137
+ }
138
+ }
139
+ ```
140
+
141
+ **Module con (ex-v3-2CauTruc):**
142
+ ```json
143
+ "data": [
144
+ {
145
+ "IF": "typeof menu != 'undefined' && menu=='0'",
146
+ "THEN": { "v_Set.menu": false }
147
+ },
148
+ {
149
+ "LayDuLieuWinCha": "#PARENT.Win1",
150
+ "GiaTriTuCHA.thu.xem": "#PARENT.val7",
151
+ "GiaTriSetTuCHA": null
152
+ }
153
+ ]
154
+ ```
155
+
156
+ > Đặt `#PARENT.*` TRƯỚC các CALL startup để data sẵn sàng trước khi API đầu tiên chạy.
157
+
158
+ ---
159
+
160
+ ## 3. Sub-window Checklist
161
+
162
+ Module được mở qua `openWindow` cần:
163
+
164
+ - `"set": { "menu": false }` — ẩn navigation header (khai báo trong module.json, không dùng `?menu=0` trong URL)
165
+ - URL params tự động inject vào `vueData` trước khi `data[]` chạy — `{ "CALL": "apiLoad" }` ở cuối `data[]` là đủ
166
+ - URL chỉ truyền **ID** của record cha mà module con thực sự dùng — không truyền name hay field có thể tra lại từ DB
167
+
168
+ ```json
169
+ // module.json của module con
170
+ "set": { "menu": false },
171
+ "data": [
172
+ { "ContestID": null },
173
+ {
174
+ "getDetail": {
175
+ "API": "/SM_Contest_Detail",
176
+ "IN": { "ContestID": "ContestID" },
177
+ "OUT": "dsDetail"
178
+ }
179
+ },
180
+ { "CALL": "getDetail" }
181
+ ]
182
+ // ContestID tự động inject từ URL ?ContestID=xxx trước khi data[] chạy
183
+ ```
184
+
185
+ ---
186
+
187
+ ## 4. Ví dụ hoàn chỉnh cha ↔ con (chuẩn `ex-v3-1SetData` → `ex-v3-2CauTruc`)
188
+
189
+ Đây là mẫu chuẩn: **cửa sổ cha mở con qua `openWindow`, truyền dữ liệu bảng, con đọc/ghi/gọi lệnh ngược lên cha.**
190
+
191
+ ### 4.1 Cửa sổ CHA — f-table + nút mở con, truyền `data`
192
+
193
+ `data` trong `openWindow.IN` truyền thẳng object/array (ở đây là danh sách bảng `danhSachChoTable`) sang con; con đọc qua `#PARENT.<id>`.
194
+
195
+ ```json
196
+ {
197
+ "el": "f-table",
198
+ "attr": {
199
+ "label": "Danh sách",
200
+ ":items": "danhSachChoTable",
201
+ ":headers": [
202
+ { "text": "STT", "value": "STT" },
203
+ { "text": "Họ", "value": "ho" },
204
+ { "text": "Tên", "value": "ten" }
205
+ ]
206
+ },
207
+ "w": "6"
208
+ },
209
+ {
210
+ "el": "f-button",
211
+ "attr": {
212
+ "label": "Open Window",
213
+ ":action": {
214
+ "FUN": "openWindow",
215
+ "IN": {
216
+ "id": "`Win1",
217
+ "title": "`Chỉnh sửa cho module",
218
+ "url": "`/ex/ex-v3-2CauTruc",
219
+ "data": "danhSachChoTable"
220
+ }
221
+ }
222
+ },
223
+ "w": "3"
224
+ }
225
+ ```
226
+
227
+ Cha cũng có thể khai báo **action đặt tên** để con gọi ngược lên, và ghi thẳng vào con trong `data[]`:
228
+
229
+ ```json
230
+ "data": [
231
+ { "#PARENT.abcdef": 1234567890, "#Win1": { "CALL": "cmdTHONGBao" } },
232
+ {
233
+ "cmdSETData": [
234
+ { "MESS": "Lệnh của form CHA được gọi từ form CON" },
235
+ { "#Win1.GiaTriSetTuCHA": "Giá trị set từ CHA" }
236
+ ]
237
+ }
238
+ ]
239
+ ```
240
+
241
+ ### 4.2 Cửa sổ CON — đọc data cha, ghi ngược, gọi lệnh cha, mở thêm con
242
+
243
+ ```json
244
+ // data[] của con: đọc dữ liệu cha NGAY đầu tiên
245
+ "data": [
246
+ {
247
+ "LayDuLieuWinCha": "#PARENT.Win1", // = data cha đã truyền qua openWindow (id=Win1)
248
+ "GiaTriTuCHA.thu.xem": "#PARENT.val7",
249
+ "GiaTriSetTuCHA": null
250
+ }
251
+ ],
252
+ "set": { "menu": false, "login": false }
253
+ ```
254
+
255
+ ```json
256
+ // Các nút trong controls của con:
257
+ { "el": "f-button", "attr": { "label": "Lấy dữ liệu từ cha",
258
+ ":action": { "USERINFO": "#PARENT.val4" } } },
259
+
260
+ { "el": "f-button", "attr": { "label": "Set dữ liệu xuống cha",
261
+ ":action": { "#PARENT.val4": "DauRaTuCauTruc_IN" } } },
262
+
263
+ { "el": "f-button", "attr": { "label": "Gọi lệnh ở cha",
264
+ ":action": { "#PARENT": { "CALL": "cmdSETData" } } } },
265
+
266
+ { "el": "f-button", "attr": { "label": "Mở thêm form con",
267
+ ":action": { "FUN": "openWindow", "IN": {
268
+ "id": "`Win2",
269
+ "url": "`https://fui.vn/ex/ex-v3-1SetData",
270
+ "onclose": { "#Win1": { "CALL": "cmdThongBaoCuaFormNay" } }
271
+ } } } }
272
+ ```
273
+
274
+ **Tổng hợp cú pháp trao đổi (value = đọc, key = ghi):**
275
+
276
+ | Cú pháp | Ý nghĩa |
277
+ |---|---|
278
+ | `"x": "#PARENT.field"` | Đọc `field` của cha vào `x` |
279
+ | `"x": "#Win1.field"` | Đọc `field` của cửa sổ id `Win1` |
280
+ | `"#PARENT.field": "src"` | Ghi `src` vào `field` của cha |
281
+ | `"#Win1.field": "src"` | Ghi vào cửa sổ `Win1` |
282
+ | `"#PARENT": { "CALL": "cmd" }` | Gọi action `cmd` trong cha |
283
+ | `"#Win1": { "CALL": "cmd" }` | Gọi action trong `Win1` |
284
+ | `openWindow.IN.data` | Truyền object/array sang con; con đọc `#PARENT.<id>` |
285
+ | `openWindow.IN.onclose` | Action chạy sau khi con đóng (có thể nhắm `#WinX`) |
286
+
287
+ > Hoạt động cả **same-domain và cross-domain** (runtime tự dùng `postMessage` khi khác tên miền).
288
+
289
+ ---
290
+
291
+ ## 5. f-table / f-sheet + mở cửa sổ chi tiết
292
+
293
+ Pattern rất phổ biến: bảng danh sách → click một dòng → mở cửa sổ con để xem/sửa chi tiết dòng đó.
294
+
295
+ - Trong `headers` của `f-table`, dùng `t-button` hoặc `t-menu` với `:action` gọi `openWindow`; `item` là dòng hiện tại.
296
+ - Truyền **chỉ ID** của dòng qua URL (con tự query DB), hoặc truyền cả object dòng qua `openWindow.IN.data`.
297
+
298
+ ```json
299
+ {
300
+ "el": "t-button", "text": "Chi tiết", "value": "ID", "align": "center",
301
+ "attr": {
302
+ "icon-text": "mdi-eye", "color": "primary",
303
+ ":action": {
304
+ "FUN": "openWindow",
305
+ "IN": {
306
+ "id": "`WinDetail",
307
+ "title": "`Chi tiết",
308
+ "url": "`/DetailModule?RecordID={{item.ID}}",
309
+ "onclose": { "CALL": "reloadList" }
310
+ }
311
+ }
312
+ }
313
+ }
314
+ ```
315
+
316
+ - **`f-sheet`** (bảng tính nhập lưới) kết hợp tương tự: nút/menu trong sheet gọi `openWindow`, hoặc lưu cả `vueData` của sheet rồi mở con để nhập bổ sung; con ghi ngược qua `#PARENT.<field>` khi đóng.
317
+ - Reload sau khi con đóng: đặt `onclose: { "CALL": "reloadList" }` (chạy trong cửa sổ mở nó) — xem §1.
@@ -0,0 +1,229 @@
1
+ # FUI Dialog Patterns — v-dialog thủ công (CHUẨN), hidden-container, checkbox-list
2
+
3
+ > File này sở hữu: **dialog thủ công: `hidden-container`, anatomy `v-card`/`v-toolbar`, mở dialog kèm row, checkbox-list**. `f-dialog` xem [components-dialog.md](components-dialog.md).
4
+
5
+ Các pattern dialog/form popup trong FUI. Rút ra từ **security-manager** và demo **ex-v3-dialog**.
6
+
7
+ > **CHUẨN thiết kế dialog: dựng `v-dialog` thủ công theo anatomy trong mục 1** (dễ đọc/chỉnh sửa từng phần), với **diện mạo mô phỏng `f-dialog`**: toolbar `dense flat` không màu + close icon, form floating label, hàng cuối là `v-card-actions`. Hàng action căn phải, button giữ chiều ngang tự nhiên; chỉ action chính mới được tô màu nền, action phụ dùng nút text. Anatomy đầy đủ + bảng quy tắc: xem `design_read("fui")` §4–5. `f-dialog` (mục 0) là lựa chọn phụ cho form rất nhỏ.
8
+
9
+ > Xem thêm: [ui-patterns.md](ui-patterns.md), [ui-table-cell-patterns.md](ui-table-cell-patterns.md) (menuChucNang mở dialog), [components-dialog.md](components-dialog.md).
10
+
11
+ ---
12
+
13
+ ## 0. `f-dialog` — component dialog gọn (lựa chọn phụ)
14
+
15
+ `f-dialog` gói sẵn card + toolbar + nút — ngắn hơn so với dựng `v-dialog` thủ công, nhưng khó tùy biến layout. Chỉ dùng cho form rất nhỏ/đơn giản; mặc định vẫn là `v-dialog` thủ công (mục 1). Các field bên trong dùng `v-model` **trỏ thẳng tới key của object `data`** (không cần `vueData.dialogData.X`).
16
+
17
+ ```json
18
+ {
19
+ "el": "f-dialog",
20
+ "attr": {
21
+ "v-model": "dialogOpen", // boolean mở/đóng
22
+ "v-model:data": "dialogData", // object dữ liệu của form
23
+ "title": "Nhập dữ liệu",
24
+ ":open-action": { "MESSBOX": "Bạn vừa mở dialog" },
25
+ ":controls": [
26
+ { "el": "v-text-field", "attr": { "v-model": "Domain", "label": "Domain" }, "w": 4 },
27
+ { "el": "v-text-field", "attr": { "v-model": "ModuleID", "label": "ModuleID" }, "w": 3 },
28
+ { "el": "v-checkbox", "attr": { "v-model": "checkBoxValue",
29
+ ":label": "`Tôi đồng ý: ${checkBoxValue}`" } },
30
+ { "el": "v-select", "attr": { "label": "Chọn", "v-model": "bienselect",
31
+ ":items": "vueData.Mang", "item-title": "AppName", "item-value": "AppListID" } }
32
+ ],
33
+ ":watch": {
34
+ "bienselect": { "MESSBOX": "Watch {{bienselect}}" }
35
+ },
36
+ ":button": [
37
+ { "label": "Lưu", "type": "submit", ":disabled": "!checkBoxValue",
38
+ "action": [ { "MESSBOX": "Đã lưu" }, { "dialogOpen": false } ] },
39
+ { "label": "Chạy API", "checkvalid": true, "v-if": "ModuleID==1",
40
+ "action": [ { "API": "/chaymotapi" } ] },
41
+ { "label": "Đóng", "action": [ { "dialogOpen": false } ] }
42
+ ]
43
+ }
44
+ }
45
+ ```
46
+
47
+ | Prop | Vai trò |
48
+ |---|---|
49
+ | `v-model` | Biến boolean mở/đóng dialog |
50
+ | `v-model:data` | Object chứa dữ liệu form; field trong `:controls` bind trực tiếp tới key của nó |
51
+ | `title` | Tiêu đề dialog |
52
+ | `:open-action` | Action chạy khi dialog mở |
53
+ | `:controls` | Mảng Control Object = các field của form |
54
+ | `:watch` | Watcher phạm vi trong dialog (theo tên field) |
55
+ | `:button` | Mảng nút: `label`, `type:"submit"`, `checkvalid`, `:disabled`, `v-if`, `action` |
56
+
57
+ **Khi nào dùng gì:** mặc định mọi dialog → **`v-dialog` thủ công theo mục 1** (chuẩn project). `f-dialog` chỉ khi form rất nhỏ (1–3 field, không layout đặc biệt) và user không yêu cầu tùy biến.
58
+
59
+ ---
60
+
61
+ ## 1. Dialog Pattern — v-dialog thủ công trong hidden-container (CHUẨN)
62
+
63
+ Dialogs luôn đặt trong container riêng với `prop: "hidden-container"` — không nằm trong rows chính.
64
+
65
+ **Cấu trúc chuẩn:**
66
+
67
+ ```json
68
+ {
69
+ "prop": "hidden-container",
70
+ "rows": [
71
+ {
72
+ "prop": "",
73
+ "cols": [
74
+ {
75
+ "el": "v-dialog",
76
+ "attr": {
77
+ "v-model": "dlUserInfo",
78
+ "width": 650
79
+ },
80
+ "innerHTML": [
81
+ {
82
+ "el": "v-card",
83
+ "attr": { "class": "pa-0" },
84
+ "innerHTML": [
85
+ {
86
+ "el": "v-toolbar",
87
+ "attr": { "dense": "", "flat": "" },
88
+ "innerHTML": [
89
+ { "el": "v-toolbar-title", "attr": {}, "innerHTML": "Update User Info" },
90
+ { "el": "v-spacer", "attr": {} },
91
+ {
92
+ "el": "v-btn",
93
+ "innerHTML": "<v-icon>mdi-close</v-icon>",
94
+ "attr": { "icon": "", "v-on:click": "vueData.dlUserInfo = false" }
95
+ }
96
+ ]
97
+ },
98
+ {
99
+ "el": "v-container",
100
+ "attr": { "class": "grid-list-md px-4" },
101
+ "innerHTML": [
102
+ { "el": "v-layout", "w": 12, "attr": { "row": "", "wrap": "" }, "innerHTML": [
103
+ { "el": "v-text-field", "col": {}, "attr": { "v-model": "vueData.sUserName", "label": "Tên đăng nhập" }, "w": 6 },
104
+ { "el": "v-text-field", "col": {}, "attr": { "v-model": "vueData.sLastName", "label": "Họ tên" }, "w": 6 }
105
+ ]}
106
+ ]
107
+ },
108
+ {
109
+ "el": "v-card-actions",
110
+ "attr": { "class": "mr-1 mb-1" },
111
+ "innerHTML": [
112
+ { "el": "v-spacer", "attr": {} },
113
+ {
114
+ "el": "f-button",
115
+ "attr": {
116
+ "text": "",
117
+ "label": "Đặt lại",
118
+ ":action": { "CALL": "resetForm" }
119
+ }
120
+ },
121
+ {
122
+ "el": "f-button",
123
+ "attr": {
124
+ "color": "primary",
125
+ ":checkvalid": true,
126
+ "label": "Lưu",
127
+ "icon-text": "mdi-content-save",
128
+ ":action": {
129
+ "API": "SM_Users_Update",
130
+ "IN": { "UserID": "sUserID", "UserName": "sUserName" },
131
+ "CALLBACK": [
132
+ { "MESS": "Cập nhật thành công." },
133
+ { "dlUserInfo": false },
134
+ { "CALL": "getUser" }
135
+ ]
136
+ }
137
+ }
138
+ }
139
+ ]
140
+ }
141
+ ]
142
+ }
143
+ ]
144
+ }
145
+ ]
146
+ }
147
+ ]
148
+ }
149
+ ```
150
+
151
+ **Quy tắc dialog (phong cách f-dialog):**
152
+ - `v-card[class="pa-0"]` — triệt đệm để toolbar tràn sát mép (ưu tiên class Vuetify, không inline style); không elevation/outlined
153
+ - `v-toolbar[dense flat]` — thanh tiêu đề mỏng, **không** color/dark
154
+ - Nút đóng: `v-btn[icon]` mdi-close + `v-on:click: "vueData.dlXxx = false"` — không thêm nút "Đóng" ở actions
155
+ - Thân form: `v-container.grid-list-md.px-4` > `v-layout[row wrap]` > field **floating label** (`label` trong attr, w:12 dài / 6+6 ngắn) — KHÔNG dùng label div rời
156
+ - Hàng cuối chứa nút phải là `v-card-actions[class="mr-1 mb-1"]`, không đặt nhóm action trong một `v-layout`, `v-container` hay row form thông thường
157
+ - `v-spacer` đứng trước nhóm nút → toàn bộ action căn phải
158
+ - Button giữ chiều ngang tự nhiên theo nội dung: không đặt `w`, `width`, `block`, `flex-grow` hoặc bọc mỗi nút trong cột giãn
159
+ - Tối đa một action quan trọng nhất (ví dụ **Lưu**) được dùng nền `color="primary"`; action phụ/ít quan trọng dùng `f-button` + `"text": ""`, không tô nền. Giữ số nút ít, nhãn ngắn và trình bày nhã nhặn
160
+ - CALLBACK của Save: MESS → đóng dialog → reload data
161
+
162
+ ---
163
+
164
+ ## 2. Mở Dialog với Dữ Liệu Row
165
+
166
+ Pattern 2 bước: copy dữ liệu vào state → set `dlXxx = true`.
167
+
168
+ **Từ menuChucNang:**
169
+ ```json
170
+ "action": [
171
+ {
172
+ "addNew": 0,
173
+ "dongChon": "item",
174
+ "sUserID": "item.UserID",
175
+ "sUserName": "item.UserName",
176
+ "sLastName": "item.LastName"
177
+ },
178
+ { "dlUserInfo": true }
179
+ ]
180
+ ```
181
+
182
+ **Từ f-button:**
183
+ ```json
184
+ ":action": [
185
+ { "addNew": 1, "sUserID": "", "sUserName": "" },
186
+ { "dlUserInfo": true }
187
+ ]
188
+ ```
189
+
190
+ > `addNew: 0` = edit mode, `addNew: 1` = new mode. Trong dialog, dùng `:disabled="addNew==0"` để khóa field ID khi edit.
191
+
192
+ ---
193
+
194
+ ## 3. Checkbox List Dialog Pattern
195
+
196
+ Dialog chứa danh sách checkbox để chọn nhiều items, lưu ngay khi click.
197
+
198
+ ```json
199
+ {
200
+ "el": "v-card-text",
201
+ "attr": {},
202
+ "innerHTML": [
203
+ {
204
+ "el": "v-layout",
205
+ "attr": { "class": "fluid row justify-center grid-list-lg fill-height mt-3" },
206
+ "innerHTML": [
207
+ {
208
+ "el": "div",
209
+ "attr": { "v-for": "fc in vueData.dsFunctionRight", ":key": "fc.FunctionID" },
210
+ "innerHTML": [
211
+ {
212
+ "el": "v-checkbox",
213
+ "attr": {
214
+ "color": "primary",
215
+ "v-model": "sFunctionSelected",
216
+ ":value": "`${fc.FunctionID}`",
217
+ ":label": "`${fc.FunctionName}`",
218
+ "v-on:click": "CALL(saveFunction)"
219
+ }
220
+ }
221
+ ]
222
+ }
223
+ ]
224
+ }
225
+ ]
226
+ }
227
+ ```
228
+
229
+ > `v-on:click` trên checkbox → save ngay không cần nút Save. `v-model` nhận array, `:value` dùng backtick literal.