@cyberskill/design 1.1.1 → 1.3.8

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 (481) hide show
  1. package/DESIGN.md +28 -5
  2. package/README.md +23 -22
  3. package/SKILL.md +7 -7
  4. package/THIRD-PARTY-NOTICES.md +35 -0
  5. package/VERSION +1 -1
  6. package/_ds_bundle.js +1495 -1733
  7. package/_ds_manifest.json +1 -1
  8. package/_esm/cs.mjs +18 -4
  9. package/_esm/react.d.ts +2 -0
  10. package/_esm/react.mjs +7 -1
  11. package/_vendor/NOTICE.md +16 -0
  12. package/_vendor/babel/README.md +7 -0
  13. package/_vendor/babel/babel.min.js +4 -0
  14. package/_vendor/react/README.md +3 -0
  15. package/_vendor/react/react-dom.production.min.js +1 -0
  16. package/_vendor/react/react.production.min.js +1 -0
  17. package/assets/aurora-hoa.webp +0 -0
  18. package/assets/aurora-kim.webp +0 -0
  19. package/assets/aurora-moc.webp +0 -0
  20. package/assets/aurora-tho.webp +0 -0
  21. package/assets/aurora-thuy.webp +0 -0
  22. package/base/a11y.css +18 -0
  23. package/base/ai.css +9 -4
  24. package/base/collections.css +18 -7
  25. package/base/components.css +16 -4
  26. package/base/controls.css +116 -66
  27. package/base/data.css +4 -4
  28. package/base/feedback.css +14 -2
  29. package/base/forms.css +10 -4
  30. package/base/glass.css +7 -1
  31. package/base/interaction.css +6 -2
  32. package/base/navigation.css +9 -3
  33. package/base/reset.css +7 -1
  34. package/base/responsive.css +38 -12
  35. package/base/shell.css +15 -3
  36. package/components/_i18n/i18n.js +41 -4
  37. package/components/_i18n/strings.js +89 -22
  38. package/components/ai/ChatMessage.d.ts +2 -0
  39. package/components/ai/ChatMessage.jsx +8 -4
  40. package/components/ai/ConfidenceMeter.d.ts +2 -0
  41. package/components/ai/ConfidenceMeter.jsx +8 -6
  42. package/components/ai/HumanReviewGate.d.ts +2 -0
  43. package/components/ai/PromptInput.d.ts +2 -0
  44. package/components/ai/TypingIndicator.d.ts +2 -0
  45. package/components/ai/ai-conversation.card.html +3 -3
  46. package/components/ai/ai-lumi.card.html +3 -3
  47. package/components/ai/ai.card.html +3 -3
  48. package/components/brand/brand.card.html +3 -3
  49. package/components/button/buttons.card.html +3 -3
  50. package/components/data/Image.jsx +18 -2
  51. package/components/data/Sortable.d.ts +5 -1
  52. package/components/data/Sortable.jsx +42 -9
  53. package/components/data/Sortable.prompt.md +4 -2
  54. package/components/data/Terminal.jsx +3 -2
  55. package/components/data/Tooltip.d.ts +2 -0
  56. package/components/data/Tooltip.jsx +6 -3
  57. package/components/data/Tree.d.ts +2 -1
  58. package/components/data/Tree.jsx +137 -16
  59. package/components/data/Tree.prompt.md +1 -1
  60. package/components/data/Watermark.jsx +11 -3
  61. package/components/data/collections.card.html +3 -3
  62. package/components/data/data.card.html +3 -3
  63. package/components/datatable/DataGrid.jsx +10 -1
  64. package/components/datatable/DataTable.d.ts +24 -1
  65. package/components/datatable/DataTable.jsx +78 -5
  66. package/components/datatable/DataTable.prompt.md +2 -1
  67. package/components/datatable/datatable.card.html +20 -16
  68. package/components/dialog/Dialog.jsx +13 -45
  69. package/components/dialog/dialog.card.html +3 -3
  70. package/components/feedback/Alert.d.ts +2 -0
  71. package/components/feedback/Alert.jsx +8 -2
  72. package/components/feedback/EmptyState.d.ts +2 -0
  73. package/components/feedback/EmptyState.jsx +6 -3
  74. package/components/feedback/ProgressBar.d.ts +2 -0
  75. package/components/feedback/ProgressBar.jsx +9 -4
  76. package/components/feedback/Toast.jsx +15 -1
  77. package/components/feedback/Toast.prompt.md +2 -1
  78. package/components/feedback/feedback-2.card.html +3 -3
  79. package/components/feedback/feedback.card.html +3 -3
  80. package/components/forms/Cascader.jsx +76 -8
  81. package/components/forms/Editor.jsx +37 -2
  82. package/components/forms/FileUpload.d.ts +2 -0
  83. package/components/forms/FileUpload.jsx +22 -8
  84. package/components/forms/Form.d.ts +3 -1
  85. package/components/forms/Form.jsx +9 -1
  86. package/components/forms/Form.prompt.md +1 -1
  87. package/components/forms/Mentions.d.ts +1 -1
  88. package/components/forms/Mentions.jsx +59 -7
  89. package/components/forms/Mentions.prompt.md +3 -1
  90. package/components/forms/Rating.d.ts +3 -2
  91. package/components/forms/Rating.jsx +34 -3
  92. package/components/forms/Rating.prompt.md +1 -1
  93. package/components/forms/Select.d.ts +2 -0
  94. package/components/forms/Select.jsx +6 -2
  95. package/components/forms/Slider.d.ts +2 -0
  96. package/components/forms/Slider.jsx +5 -2
  97. package/components/forms/Switch.d.ts +2 -0
  98. package/components/forms/Switch.jsx +15 -3
  99. package/components/forms/TimePicker.jsx +3 -1
  100. package/components/forms/Toggle.d.ts +2 -0
  101. package/components/forms/Toggle.jsx +14 -2
  102. package/components/forms/forms-2.card.html +3 -3
  103. package/components/forms/forms.card.html +3 -3
  104. package/components/icon/Icon.d.ts +1 -1
  105. package/components/icon/Icon.jsx +1 -0
  106. package/components/icon/Icon.prompt.md +1 -1
  107. package/components/icon/icon.card.html +3 -3
  108. package/components/logo/logo.card.html +3 -3
  109. package/components/navigation/CommandPalette.d.ts +2 -0
  110. package/components/navigation/CommandPalette.jsx +22 -7
  111. package/components/navigation/Menu.d.ts +2 -0
  112. package/components/navigation/Menu.jsx +60 -6
  113. package/components/navigation/Steps.d.ts +2 -0
  114. package/components/navigation/Steps.jsx +6 -3
  115. package/components/navigation/Tabs.d.ts +2 -0
  116. package/components/navigation/Tabs.jsx +6 -3
  117. package/components/navigation/Toolbar.d.ts +3 -2
  118. package/components/navigation/Toolbar.jsx +119 -12
  119. package/components/navigation/Toolbar.prompt.md +1 -1
  120. package/components/navigation/navigation.card.html +3 -3
  121. package/components/navigation/shell.card.html +3 -3
  122. package/components/overlays/AlertDialog.jsx +19 -49
  123. package/components/overlays/ContextMenu.d.ts +2 -0
  124. package/components/overlays/ContextMenu.jsx +6 -3
  125. package/components/overlays/Drawer.d.ts +2 -0
  126. package/components/overlays/Drawer.jsx +24 -20
  127. package/components/overlays/OverlayManager.d.ts +40 -0
  128. package/components/overlays/OverlayManager.jsx +214 -0
  129. package/components/overlays/OverlayManager.prompt.md +12 -0
  130. package/components/overlays/Tour.jsx +14 -7
  131. package/components/overlays/alertdialog.card.html +3 -3
  132. package/components/overlays/overlays.card.html +3 -3
  133. package/components/textfield/textfield.card.html +3 -3
  134. package/dist/styles.min.css +2252 -0
  135. package/docs/benchmark-rubric.md +1 -1
  136. package/docs/ci-cd.md +19 -12
  137. package/docs/consumer-grant.md +3 -0
  138. package/docs/consuming.md +13 -13
  139. package/docs/contrast-report.md +79 -1
  140. package/docs/conventions.md +21 -8
  141. package/docs/decisions.md +45 -7
  142. package/docs/deploy.md +17 -6
  143. package/docs/design-styles.md +2 -2
  144. package/docs/quality-gates.md +35 -15
  145. package/docs/release-notes.md +2 -2
  146. package/docs/release-runbook.md +78 -0
  147. package/docs/sync.md +2 -2
  148. package/docs/vi/benchmark-rubric.md +1 -1
  149. package/docs/vi/ci-cd.md +17 -12
  150. package/docs/vi/consumer-grant.md +3 -0
  151. package/docs/vi/consuming.md +13 -13
  152. package/docs/vi/contrast-report.md +79 -1
  153. package/docs/vi/conventions.md +20 -7
  154. package/docs/vi/decisions.md +43 -6
  155. package/docs/vi/deploy.md +17 -6
  156. package/docs/vi/quality-gates.md +34 -15
  157. package/docs/vi/release-notes.md +2 -2
  158. package/docs/vi/release-runbook.md +78 -0
  159. package/docs/vi/sync.md +2 -2
  160. package/docs/viewer.html +2 -2
  161. package/fonts/OFL.txt +98 -0
  162. package/guidelines/atomic-view.html +13 -9
  163. package/guidelines/brand-imagery.html +1 -1
  164. package/guidelines/elements-variants.html +5 -5
  165. package/guidelines/spacing-breakpoints.html +2 -1
  166. package/guidelines/surfaces-glass.html +1 -1
  167. package/llms.txt +5 -5
  168. package/package.json +38 -10
  169. package/templates/_ds-base.canonical.js +55 -0
  170. package/templates/ai-cluster-demo.html +2 -2
  171. package/templates/app-shell/AppShell.dc.html +7 -5
  172. package/templates/app-shell/content-schema.json +7 -0
  173. package/templates/app-shell/ds-base.js +33 -1
  174. package/templates/app-shell/support.js +13 -20
  175. package/templates/article/Article.dc.html +7 -3
  176. package/templates/article/content-schema.json +7 -0
  177. package/templates/article/ds-base.js +33 -1
  178. package/templates/article/support.js +13 -20
  179. package/templates/auth/Auth.dc.html +33 -12
  180. package/templates/auth/content-schema.json +37 -0
  181. package/templates/auth/ds-base.js +33 -1
  182. package/templates/auth/support.js +13 -20
  183. package/templates/bod-deck/BodDeck.dc.html +11 -10
  184. package/templates/bod-deck/ds-base.js +33 -1
  185. package/templates/bod-deck/support.js +13 -20
  186. package/templates/bod-investor-update/BodInvestorUpdate.dc.html +4 -3
  187. package/templates/bod-investor-update/ds-base.js +33 -1
  188. package/templates/bod-investor-update/support.js +13 -20
  189. package/templates/bod-memo/BodMemo.dc.html +6 -5
  190. package/templates/bod-memo/ds-base.js +33 -1
  191. package/templates/bod-memo/support.js +13 -20
  192. package/templates/bod-minutes/BodMinutes.dc.html +2 -1
  193. package/templates/bod-minutes/ds-base.js +33 -1
  194. package/templates/bod-minutes/support.js +13 -20
  195. package/templates/bod-report/BodReport.dc.html +3 -2
  196. package/templates/bod-report/ds-base.js +33 -1
  197. package/templates/bod-report/support.js +13 -20
  198. package/templates/bod-resolution/BodResolution.dc.html +5 -4
  199. package/templates/bod-resolution/ds-base.js +33 -1
  200. package/templates/bod-resolution/support.js +13 -20
  201. package/templates/culture-event-invite/CultureEventInvite.dc.html +3 -2
  202. package/templates/culture-event-invite/ds-base.js +33 -1
  203. package/templates/culture-event-invite/support.js +13 -20
  204. package/templates/dashboard/Dashboard.dc.html +10 -6
  205. package/templates/dashboard/content-schema.json +7 -0
  206. package/templates/dashboard/ds-base.js +33 -1
  207. package/templates/dashboard/support.js +13 -20
  208. package/templates/delivery-change-note/DeliveryChangeNote.dc.html +4 -3
  209. package/templates/delivery-change-note/ds-base.js +33 -1
  210. package/templates/delivery-change-note/support.js +13 -20
  211. package/templates/delivery-kickoff/DeliveryKickoff.dc.html +3 -2
  212. package/templates/delivery-kickoff/ds-base.js +33 -1
  213. package/templates/delivery-kickoff/support.js +13 -20
  214. package/templates/delivery-qbr-deck/DeliveryQbrDeck.dc.html +6 -5
  215. package/templates/delivery-qbr-deck/ds-base.js +33 -1
  216. package/templates/delivery-qbr-deck/support.js +13 -20
  217. package/templates/delivery-runbook/DeliveryRunbook.dc.html +5 -4
  218. package/templates/delivery-runbook/ds-base.js +33 -1
  219. package/templates/delivery-runbook/support.js +13 -20
  220. package/templates/delivery-status-email/DeliveryStatusEmail.dc.html +3 -2
  221. package/templates/delivery-status-email/ds-base.js +33 -1
  222. package/templates/delivery-status-email/support.js +13 -20
  223. package/templates/doc-style-guide/DocStyleGuide.dc.html +67 -64
  224. package/templates/doc-style-guide/ds-base.js +33 -1
  225. package/templates/doc-style-guide/support.js +13 -20
  226. package/templates/doc-suite-index/DocSuiteIndex.dc.html +46 -45
  227. package/templates/doc-suite-index/ds-base.js +33 -1
  228. package/templates/doc-suite-index/support.js +13 -20
  229. package/templates/doc-templates/DocTemplates.dc.html +42 -41
  230. package/templates/doc-templates/ds-base.js +33 -1
  231. package/templates/doc-templates/support.js +13 -20
  232. package/templates/email/Email.dc.html +3 -2
  233. package/templates/email/ds-base.js +33 -1
  234. package/templates/email/support.js +13 -20
  235. package/templates/email-safe/email-announcement.html +2 -2
  236. package/templates/email-safe/email-dunning.html +2 -2
  237. package/templates/email-safe/email-investor.html +2 -2
  238. package/templates/email-safe/email-launch.html +2 -2
  239. package/templates/email-safe/email-newsletter.html +2 -2
  240. package/templates/email-safe/email-status.html +2 -2
  241. package/templates/email-safe/email-transactional.html +2 -2
  242. package/templates/finance-dunning-email/FinanceDunningEmail.dc.html +6 -5
  243. package/templates/finance-dunning-email/ds-base.js +33 -1
  244. package/templates/finance-dunning-email/support.js +13 -20
  245. package/templates/finance-expense-report/FinanceExpenseReport.dc.html +4 -3
  246. package/templates/finance-expense-report/ds-base.js +33 -1
  247. package/templates/finance-expense-report/support.js +13 -20
  248. package/templates/finance-invoice/FinanceInvoice.dc.html +6 -5
  249. package/templates/finance-invoice/ds-base.js +33 -1
  250. package/templates/finance-invoice/support.js +13 -20
  251. package/templates/finance-quote/FinanceQuote.dc.html +6 -5
  252. package/templates/finance-quote/ds-base.js +33 -1
  253. package/templates/finance-quote/support.js +13 -20
  254. package/templates/hr-announcement/HrAnnouncement.dc.html +5 -4
  255. package/templates/hr-announcement/ds-base.js +33 -1
  256. package/templates/hr-announcement/support.js +13 -20
  257. package/templates/hr-interview-kit/HrInterviewKit.dc.html +5 -4
  258. package/templates/hr-interview-kit/ds-base.js +33 -1
  259. package/templates/hr-interview-kit/support.js +13 -20
  260. package/templates/hr-offboarding/HrOffboarding.dc.html +2 -1
  261. package/templates/hr-offboarding/ds-base.js +33 -1
  262. package/templates/hr-offboarding/support.js +13 -20
  263. package/templates/hr-performance-review/HrPerformanceReview.dc.html +2 -1
  264. package/templates/hr-performance-review/ds-base.js +33 -1
  265. package/templates/hr-performance-review/support.js +13 -20
  266. package/templates/hr-pip/HrPip.dc.html +2 -1
  267. package/templates/hr-pip/ds-base.js +33 -1
  268. package/templates/hr-pip/support.js +13 -20
  269. package/templates/kitchen-sink.html +9 -4
  270. package/templates/legal-msa/LegalMsa.dc.html +2 -1
  271. package/templates/legal-msa/ds-base.js +33 -1
  272. package/templates/legal-msa/support.js +13 -20
  273. package/templates/legal-sow/LegalSow.dc.html +2 -1
  274. package/templates/legal-sow/ds-base.js +33 -1
  275. package/templates/legal-sow/support.js +13 -20
  276. package/templates/marketing-campaign-brief/MarketingCampaignBrief.dc.html +3 -2
  277. package/templates/marketing-campaign-brief/ds-base.js +33 -1
  278. package/templates/marketing-campaign-brief/support.js +13 -20
  279. package/templates/marketing-case-study/MarketingCaseStudy.dc.html +6 -5
  280. package/templates/marketing-case-study/ds-base.js +33 -1
  281. package/templates/marketing-case-study/support.js +13 -20
  282. package/templates/marketing-launch/MarketingLaunch.dc.html +6 -5
  283. package/templates/marketing-launch/ds-base.js +33 -1
  284. package/templates/marketing-launch/support.js +13 -20
  285. package/templates/marketing-newsletter/MarketingNewsletter.dc.html +13 -12
  286. package/templates/marketing-newsletter/ds-base.js +33 -1
  287. package/templates/marketing-newsletter/support.js +13 -20
  288. package/templates/marketing-page/MarketingPage.dc.html +19 -14
  289. package/templates/marketing-page/content-schema.json +1 -0
  290. package/templates/marketing-page/ds-base.js +33 -1
  291. package/templates/marketing-page/support.js +13 -20
  292. package/templates/marketing-press-release/MarketingPressRelease.dc.html +2 -1
  293. package/templates/marketing-press-release/ds-base.js +33 -1
  294. package/templates/marketing-press-release/support.js +13 -20
  295. package/templates/marketing-social-kit/MarketingSocialKit.dc.html +5 -4
  296. package/templates/marketing-social-kit/ds-base.js +33 -1
  297. package/templates/marketing-social-kit/support.js +13 -20
  298. package/templates/sales-one-pager/SalesOnePager.dc.html +5 -4
  299. package/templates/sales-one-pager/ds-base.js +33 -1
  300. package/templates/sales-one-pager/support.js +13 -20
  301. package/templates/sales-proposal-deck/SalesProposalDeck.dc.html +7 -6
  302. package/templates/sales-proposal-deck/ds-base.js +33 -1
  303. package/templates/sales-proposal-deck/support.js +13 -20
  304. package/templates/settings/Settings.dc.html +7 -3
  305. package/templates/settings/content-schema.json +7 -0
  306. package/templates/settings/ds-base.js +33 -1
  307. package/templates/settings/support.js +13 -20
  308. package/templates/slide-deck/SlideDeck.dc.html +5 -4
  309. package/templates/slide-deck/ds-base.js +33 -1
  310. package/templates/slide-deck/support.js +13 -20
  311. package/templates/team-meeting-agenda/TeamMeetingAgenda.dc.html +2 -1
  312. package/templates/team-meeting-agenda/ds-base.js +33 -1
  313. package/templates/team-meeting-agenda/support.js +13 -20
  314. package/templates/tech-incident-report/TechIncidentReport.dc.html +3 -2
  315. package/templates/tech-incident-report/ds-base.js +33 -1
  316. package/templates/tech-incident-report/support.js +13 -20
  317. package/templates/tech-release-notes/TechReleaseNotes.dc.html +6 -5
  318. package/templates/tech-release-notes/ds-base.js +33 -1
  319. package/templates/tech-release-notes/support.js +13 -20
  320. package/templates/tech-retro/TechRetro.dc.html +4 -3
  321. package/templates/tech-retro/ds-base.js +33 -1
  322. package/templates/tech-retro/support.js +13 -20
  323. package/templates/tech-rfc/TechRfc.dc.html +3 -2
  324. package/templates/tech-rfc/ds-base.js +33 -1
  325. package/templates/tech-rfc/support.js +13 -20
  326. package/templates/vn-appointment-transfer/VnAppointmentTransfer.dc.html +36 -35
  327. package/templates/vn-appointment-transfer/ds-base.js +33 -1
  328. package/templates/vn-appointment-transfer/support.js +13 -20
  329. package/templates/vn-certificate-of-employment/VnCertificateOfEmployment.dc.html +27 -26
  330. package/templates/vn-certificate-of-employment/ds-base.js +33 -1
  331. package/templates/vn-certificate-of-employment/support.js +13 -20
  332. package/templates/vn-code-of-conduct/VnCodeOfConduct.dc.html +44 -43
  333. package/templates/vn-code-of-conduct/ds-base.js +33 -1
  334. package/templates/vn-code-of-conduct/support.js +13 -20
  335. package/templates/vn-compensation-regulation/VnCompensationRegulation.dc.html +53 -52
  336. package/templates/vn-compensation-regulation/ds-base.js +33 -1
  337. package/templates/vn-compensation-regulation/support.js +13 -20
  338. package/templates/vn-contract-amendment/VnContractAmendment.dc.html +41 -40
  339. package/templates/vn-contract-amendment/ds-base.js +33 -1
  340. package/templates/vn-contract-amendment/support.js +13 -20
  341. package/templates/vn-contractor-agreement/VnContractorAgreement.dc.html +50 -49
  342. package/templates/vn-contractor-agreement/ds-base.js +33 -1
  343. package/templates/vn-contractor-agreement/support.js +13 -20
  344. package/templates/vn-data-protection-policy/VnDataProtectionPolicy.dc.html +54 -53
  345. package/templates/vn-data-protection-policy/ds-base.js +33 -1
  346. package/templates/vn-data-protection-policy/support.js +13 -20
  347. package/templates/vn-disciplinary-case-file/VnDisciplinaryCaseFile.dc.html +72 -71
  348. package/templates/vn-disciplinary-case-file/ds-base.js +33 -1
  349. package/templates/vn-disciplinary-case-file/support.js +13 -20
  350. package/templates/vn-disciplinary-schedule/VnDisciplinarySchedule.dc.html +21 -20
  351. package/templates/vn-disciplinary-schedule/ds-base.js +33 -1
  352. package/templates/vn-disciplinary-schedule/support.js +13 -20
  353. package/templates/vn-employee-request/VnEmployeeRequest.dc.html +54 -53
  354. package/templates/vn-employee-request/ds-base.js +33 -1
  355. package/templates/vn-employee-request/support.js +13 -20
  356. package/templates/vn-exit-handover/VnExitHandover.dc.html +122 -121
  357. package/templates/vn-exit-handover/ds-base.js +33 -1
  358. package/templates/vn-exit-handover/support.js +13 -20
  359. package/templates/vn-foreign-employee-pack/VnForeignEmployeePack.dc.html +31 -30
  360. package/templates/vn-foreign-employee-pack/ds-base.js +33 -1
  361. package/templates/vn-foreign-employee-pack/support.js +13 -20
  362. package/templates/vn-grassroots-democracy/VnGrassrootsDemocracy.dc.html +54 -53
  363. package/templates/vn-grassroots-democracy/ds-base.js +33 -1
  364. package/templates/vn-grassroots-democracy/support.js +13 -20
  365. package/templates/vn-infosec-policy/VnInfosecPolicy.dc.html +50 -49
  366. package/templates/vn-infosec-policy/ds-base.js +33 -1
  367. package/templates/vn-infosec-policy/support.js +13 -20
  368. package/templates/vn-internal-labor-regulations/VnInternalLaborRegulations.dc.html +84 -83
  369. package/templates/vn-internal-labor-regulations/ds-base.js +33 -1
  370. package/templates/vn-internal-labor-regulations/support.js +13 -20
  371. package/templates/vn-internship-agreement/VnInternshipAgreement.dc.html +44 -43
  372. package/templates/vn-internship-agreement/ds-base.js +33 -1
  373. package/templates/vn-internship-agreement/support.js +13 -20
  374. package/templates/vn-job-description/VnJobDescription.dc.html +28 -27
  375. package/templates/vn-job-description/ds-base.js +33 -1
  376. package/templates/vn-job-description/support.js +13 -20
  377. package/templates/vn-labor-contract/VnLaborContract.dc.html +109 -108
  378. package/templates/vn-labor-contract/ds-base.js +33 -1
  379. package/templates/vn-labor-contract/support.js +13 -20
  380. package/templates/vn-labour-management-book/VnLabourManagementBook.dc.html +32 -31
  381. package/templates/vn-labour-management-book/ds-base.js +33 -1
  382. package/templates/vn-labour-management-book/support.js +13 -20
  383. package/templates/vn-mutual-nda/VnMutualNda.dc.html +45 -44
  384. package/templates/vn-mutual-nda/ds-base.js +33 -1
  385. package/templates/vn-mutual-nda/support.js +13 -20
  386. package/templates/vn-ndnca-ip/VnNdncaIp.dc.html +73 -72
  387. package/templates/vn-ndnca-ip/ds-base.js +33 -1
  388. package/templates/vn-ndnca-ip/support.js +13 -20
  389. package/templates/vn-offer-letter/VnOfferLetter.dc.html +32 -31
  390. package/templates/vn-offer-letter/ds-base.js +33 -1
  391. package/templates/vn-offer-letter/support.js +13 -20
  392. package/templates/vn-onboarding-checklist/VnOnboardingChecklist.dc.html +16 -15
  393. package/templates/vn-onboarding-checklist/ds-base.js +33 -1
  394. package/templates/vn-onboarding-checklist/support.js +13 -20
  395. package/templates/vn-pdpl-consent/VnPdplConsent.dc.html +43 -42
  396. package/templates/vn-pdpl-consent/ds-base.js +33 -1
  397. package/templates/vn-pdpl-consent/support.js +13 -20
  398. package/templates/vn-performance-evaluation-regulation/VnPerformanceEvaluationRegulation.dc.html +65 -64
  399. package/templates/vn-performance-evaluation-regulation/ds-base.js +33 -1
  400. package/templates/vn-performance-evaluation-regulation/support.js +13 -20
  401. package/templates/vn-performance-review-form/VnPerformanceReviewForm.dc.html +49 -48
  402. package/templates/vn-performance-review-form/ds-base.js +33 -1
  403. package/templates/vn-performance-review-form/support.js +13 -20
  404. package/templates/vn-phantom-stock/VnPhantomStock.dc.html +41 -40
  405. package/templates/vn-phantom-stock/ds-base.js +33 -1
  406. package/templates/vn-phantom-stock/support.js +13 -20
  407. package/templates/vn-probation-contract/VnProbationContract.dc.html +56 -55
  408. package/templates/vn-probation-contract/ds-base.js +33 -1
  409. package/templates/vn-probation-contract/support.js +13 -20
  410. package/templates/vn-receipt-acknowledgement/VnReceiptAcknowledgement.dc.html +28 -27
  411. package/templates/vn-receipt-acknowledgement/ds-base.js +33 -1
  412. package/templates/vn-receipt-acknowledgement/support.js +13 -20
  413. package/templates/vn-remote-work-policy/VnRemoteWorkPolicy.dc.html +44 -43
  414. package/templates/vn-remote-work-policy/ds-base.js +33 -1
  415. package/templates/vn-remote-work-policy/support.js +13 -20
  416. package/templates/vn-resignation-letter/VnResignationLetter.dc.html +20 -19
  417. package/templates/vn-resignation-letter/ds-base.js +33 -1
  418. package/templates/vn-resignation-letter/support.js +13 -20
  419. package/templates/vn-salary-scale/VnSalaryScale.dc.html +39 -38
  420. package/templates/vn-salary-scale/ds-base.js +33 -1
  421. package/templates/vn-salary-scale/support.js +13 -20
  422. package/templates/vn-sow-appendix/VnSowAppendix.dc.html +21 -20
  423. package/templates/vn-sow-appendix/ds-base.js +33 -1
  424. package/templates/vn-sow-appendix/support.js +13 -20
  425. package/templates/vn-termination-decision/VnTerminationDecision.dc.html +25 -24
  426. package/templates/vn-termination-decision/ds-base.js +33 -1
  427. package/templates/vn-termination-decision/support.js +13 -20
  428. package/templates/vn-total-rewards-appendix/VnTotalRewardsAppendix.dc.html +63 -62
  429. package/templates/vn-total-rewards-appendix/ds-base.js +33 -1
  430. package/templates/vn-total-rewards-appendix/support.js +13 -20
  431. package/templates/vn-training-commitment/VnTrainingCommitment.dc.html +39 -38
  432. package/templates/vn-training-commitment/ds-base.js +33 -1
  433. package/templates/vn-training-commitment/support.js +13 -20
  434. package/templates/vn-travel-expense-policy/VnTravelExpensePolicy.dc.html +50 -49
  435. package/templates/vn-travel-expense-policy/ds-base.js +33 -1
  436. package/templates/vn-travel-expense-policy/support.js +13 -20
  437. package/tokens/colors.css +19 -1
  438. package/tokens/component-tokens.css +1 -0
  439. package/tokens/element-seeds.json +2 -2
  440. package/tokens/elements.css +228 -21
  441. package/tokens/elevation.css +8 -2
  442. package/tokens/native/CSTokens.kt +37 -2
  443. package/tokens/native/CSTokens.swift +37 -2
  444. package/tokens/native/cs_tokens.dart +37 -2
  445. package/tokens/provenance.json +12 -12
  446. package/tokens/spacing.css +4 -1
  447. package/tokens/tokens.dtcg.json +129 -16
  448. package/tokens/tokens.js +59 -18
  449. package/tokens/tokens.json +58 -17
  450. package/tokens/typography.css +2 -0
  451. package/ui_kits/deck/index.html +4 -0
  452. package/ui_kits/status-hub/StatusHub.jsx +30 -4
  453. package/ui_kits/status-hub/index.html +3 -3
  454. package/ui_kits/status-hub/login.html +55 -9
  455. package/ui_kits/status-hub/project.html +4 -0
  456. package/ui_kits/status-hub/settings.html +35 -13
  457. package/ui_kits/status-hub/status.css +5 -1
  458. package/ui_kits/website/Website.jsx +25 -3
  459. package/ui_kits/website/careers.html +5 -1
  460. package/ui_kits/website/chat.html +5 -3
  461. package/ui_kits/website/index.html +3 -3
  462. package/ui_kits/website/site.css +3 -3
  463. package/ui_kits/website/work.html +5 -1
  464. package/assets/aurora-hoa.png +0 -0
  465. package/assets/aurora-kim.png +0 -0
  466. package/assets/aurora-moc.png +0 -0
  467. package/assets/aurora-thuy.png +0 -0
  468. package/docs/status/assets/favicon.svg +0 -5
  469. package/docs/status/assets/status-legacy.css +0 -399
  470. package/docs/status/assets/status-legacy.js +0 -505
  471. package/docs/status/assets/status.css +0 -644
  472. package/docs/status/assets/status.js +0 -1308
  473. package/docs/status/data/status-feed.json +0 -1
  474. package/docs/status/data/task/TASK-REL-001.js +0 -1
  475. package/docs/status/data/task/TASK-REL-002.js +0 -1
  476. package/docs/status/index.html +0 -42
  477. package/docs/status/roadmap.html +0 -4
  478. package/docs/status/status-legacy.html +0 -117
  479. package/docs/tasks/BACKLOG.md +0 -26
  480. package/docs/tasks/release/TASK-REL-001-launch-1-1-0/spec.md +0 -55
  481. package/docs/tasks/release/TASK-REL-002-republish-1-1-1/spec.md +0 -54
@@ -1,25 +1,72 @@
1
1
  import React from "react";
2
+ import { makeT, useLang } from "../_i18n/i18n.js";
2
3
  import { cx } from "../_utils/cx.js";
3
4
 
4
5
  /** CyberSkill Menu — dropdown. Provide a `trigger` element; compose MenuItem children. */
5
- export function Menu({ trigger, children, align = "start", open: controlledOpen, onOpenChange, className }) {
6
+ export function Menu({ trigger, children, align = "start", open: controlledOpen, onOpenChange, lang, className }) {
6
7
  const [uOpen, setUOpen] = React.useState(false);
7
8
  const open = controlledOpen != null ? controlledOpen : uOpen;
8
9
  const set = (v) => { onOpenChange ? onOpenChange(v) : setUOpen(v); };
9
- const ref = React.useRef(null);
10
+ const [ref, L] = useLang(lang);
11
+ const t = makeT("Menu", L);
12
+ const triggerRef = React.useRef(null);
13
+ const listRef = React.useRef(null);
14
+
10
15
  React.useEffect(() => {
11
16
  if (!open) return;
17
+ const items = () => listRef.current
18
+ ? [...listRef.current.querySelectorAll('[role="menuitem"]:not([disabled])')]
19
+ : [];
20
+ // FIND-040 — move focus into the menu on open.
21
+ const first = items()[0];
22
+ if (first && first.focus) first.focus();
23
+
12
24
  const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) set(false); };
13
- const onKey = (e) => { if (e.key === "Escape") set(false); };
25
+ const onKey = (e) => {
26
+ const opts = items();
27
+ if (e.key === "Escape") {
28
+ e.preventDefault();
29
+ set(false);
30
+ const el = triggerRef.current;
31
+ if (el && el.focus) el.focus();
32
+ return;
33
+ }
34
+ if (!opts.length) return;
35
+ const active = document.activeElement;
36
+ const idx = opts.indexOf(active);
37
+ if (e.key === "ArrowDown") {
38
+ e.preventDefault();
39
+ (opts[idx < 0 ? 0 : Math.min(opts.length - 1, idx + 1)] || opts[0]).focus();
40
+ } else if (e.key === "ArrowUp") {
41
+ e.preventDefault();
42
+ (opts[idx < 0 ? opts.length - 1 : Math.max(0, idx - 1)] || opts[0]).focus();
43
+ } else if (e.key === "Home") {
44
+ e.preventDefault();
45
+ opts[0].focus();
46
+ } else if (e.key === "End") {
47
+ e.preventDefault();
48
+ opts[opts.length - 1].focus();
49
+ }
50
+ };
14
51
  document.addEventListener("mousedown", onDoc);
15
52
  document.addEventListener("keydown", onKey);
16
- return () => { document.removeEventListener("mousedown", onDoc); document.removeEventListener("keydown", onKey); };
53
+ return () => {
54
+ document.removeEventListener("mousedown", onDoc);
55
+ document.removeEventListener("keydown", onKey);
56
+ };
17
57
  }, [open]);
58
+
18
59
  const toggle = () => set(!open);
19
60
  // ARIA attrs must live on the interactive trigger (button), not a wrapping <span>
20
61
  // — axe aria-allowed-attr flags aria-haspopup/aria-expanded on generic elements.
21
62
  const triggerNode = React.isValidElement(trigger)
22
63
  ? React.cloneElement(trigger, {
64
+ ref: (node) => {
65
+ triggerRef.current = node;
66
+ const r = trigger.ref;
67
+ if (typeof r === "function") r(node);
68
+ else if (r && typeof r === "object") r.current = node;
69
+ },
23
70
  "aria-haspopup": "menu",
24
71
  "aria-expanded": open,
25
72
  onClick: (e) => {
@@ -27,12 +74,19 @@ export function Menu({ trigger, children, align = "start", open: controlledOpen,
27
74
  if (!e.defaultPrevented) toggle();
28
75
  },
29
76
  })
30
- : <button type="button" aria-haspopup="menu" aria-expanded={open} onClick={toggle}>{trigger}</button>;
77
+ : <button type="button" ref={triggerRef} aria-haspopup="menu" aria-expanded={open} onClick={toggle}>{trigger}</button>;
31
78
  return (
32
79
  <div className={cx("cs-menu", className)} ref={ref}>
33
80
  {triggerNode}
34
81
  {open ? (
35
- <div className={cx("cs-menu__list", align === "end" && "cs-menu__list--end")} role="menu">{children}</div>
82
+ <div
83
+ ref={listRef}
84
+ className={cx("cs-menu__list", align === "end" && "cs-menu__list--end")}
85
+ role="menu"
86
+ aria-label={t("menu")}
87
+ >
88
+ {children}
89
+ </div>
36
90
  ) : null}
37
91
  </div>
38
92
  );
@@ -8,6 +8,8 @@ export interface StepItem { title: ReactNode; body?: ReactNode; n?: ReactNode; }
8
8
  export interface StepsProps {
9
9
  steps: StepItem[];
10
10
  current?: number;
11
+ /** "en" | "vi" — else resolved from the nearest [lang] ancestor (vi default). */
12
+ lang?: string;
11
13
  className?: string;
12
14
  }
13
15
  export function Steps(props: StepsProps): React.ReactElement;
@@ -1,14 +1,17 @@
1
1
  import React from "react";
2
+ import { makeT, useLang } from "../_i18n/i18n.js";
2
3
  import { cx } from "../_utils/cx.js";
3
4
 
4
5
  /** CyberSkill Steps — horizontal progress stepper. Steps before `current` are done, `current` is active. */
5
- export function Steps({ steps = [], current = 0, className }) {
6
+ export function Steps({ steps = [], current = 0, lang, className }) {
7
+ const [ref, L] = useLang(lang);
8
+ const t = makeT("Steps", L);
6
9
  return (
7
- <div className={cx("cs-steps", className)}>
10
+ <div ref={ref} className={cx("cs-steps", className)} role="list" aria-label={t("label")}>
8
11
  {steps.map((s, i) => {
9
12
  const state = i < current ? "done" : i === current ? "active" : "todo";
10
13
  return (
11
- <div key={i} className={cx("cs-step", `cs-step--${state}`)}>
14
+ <div key={i} className={cx("cs-step", `cs-step--${state}`)} role="listitem">
12
15
  <span className="cs-step__marker">{state === "done" ? "✓" : s.n || i + 1}</span>
13
16
  <span className="cs-step__title">{s.title}</span>
14
17
  {s.body ? <span className="cs-step__body">{s.body}</span> : null}
@@ -11,6 +11,8 @@ export interface TabsProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "o
11
11
  tabs: TabItem[];
12
12
  value?: string;
13
13
  onChange?: (value: string) => void;
14
+ /** "en" | "vi" — else resolved from the nearest [lang] ancestor (vi default). */
15
+ lang?: string;
14
16
  }
15
17
  export function Tabs(props: TabsProps): React.ReactElement;
16
18
 
@@ -1,10 +1,13 @@
1
1
  import React from "react";
2
+ import { makeT, useLang } from "../_i18n/i18n.js";
2
3
  import { cx } from "../_utils/cx.js";
3
4
 
4
5
  /** CyberSkill Tabs — data-driven tablist, controlled by value/onChange. Ochre underline on active. */
5
- export function Tabs({ tabs = [], value, onChange, className, ...props }) {
6
+ export function Tabs({ tabs = [], value, onChange, lang, className, "aria-label": ariaLabel, ...props }) {
7
+ const [ref, L] = useLang(lang);
8
+ const t = makeT("Tabs", L);
6
9
  const refs = React.useRef([]);
7
- const idx = Math.max(0, tabs.findIndex((t) => t.value === value));
10
+ const idx = Math.max(0, tabs.findIndex((tab) => tab.value === value));
8
11
  const key = (e, i) => {
9
12
  let n = null;
10
13
  if (e.key === "ArrowRight") n = (i + 1) % tabs.length;
@@ -17,7 +20,7 @@ export function Tabs({ tabs = [], value, onChange, className, ...props }) {
17
20
  const b = refs.current[n]; if (b) b.focus();
18
21
  };
19
22
  return (
20
- <div role="tablist" className={cx("cs-tabs", className)} {...props}>
23
+ <div ref={ref} role="tablist" aria-label={ariaLabel ?? t("list")} className={cx("cs-tabs", className)} {...props}>
21
24
  {tabs.map((t, i) => (
22
25
  <button key={t.value} type="button" role="tab" aria-selected={value === t.value} tabIndex={i === idx ? 0 : -1}
23
26
  ref={(el) => (refs.current[i] = el)} onKeyDown={(e) => key(e, i)}
@@ -1,7 +1,8 @@
1
1
  import type { ReactNode } from "react";
2
2
 
3
- /** Horizontal action bar (role=toolbar). Items after `overflowAfter` collapse
4
- * into a "⋯" menu (bilingual aria). "-" renders a separator. */
3
+ /** Horizontal action bar (APG toolbar: arrow-key roving among controls).
4
+ * Items after `overflowAfter` collapse into a ⋯ menubutton + popup menu
5
+ * (bilingual aria). "-" renders a separator. */
5
6
  export type ToolbarItem = { label?: ReactNode; icon?: ReactNode; onSelect?: () => void } | "-";
6
7
  export interface ToolbarProps {
7
8
  items: ToolbarItem[];
@@ -2,31 +2,138 @@ import React from "react";
2
2
  import { makeT, useLang } from "../_i18n/i18n.js";
3
3
  import { cx } from "../_utils/cx.js";
4
4
 
5
- /** CyberSkill Toolbar — horizontal action bar; overflow items collapse into a "⋯" menu. items: {label,icon,onSelect} or "-". */
5
+ /** CyberSkill Toolbar — horizontal action bar (APG toolbar arrows); overflow items collapse into a menubutton + popup menu. items: {label,icon,onSelect} or "-". */
6
6
  export function Toolbar({ items = [], overflowAfter, label, lang, className }) {
7
7
  const [open, setOpen] = React.useState(false);
8
+ const [focusIdx, setFocusIdx] = React.useState(0);
8
9
  const wrap = React.useRef(null);
10
+ const btnRefs = React.useRef([]);
11
+ const menuRefs = React.useRef([]);
9
12
  const [ref, L] = useLang(lang);
10
13
  const t = makeT("Toolbar", L);
11
14
  const cut = overflowAfter != null ? overflowAfter : items.length;
12
- const head = items.slice(0, cut), tail = items.filter((x) => x !== "-").slice(cut);
15
+ const head = items.slice(0, cut);
16
+ const tail = items.slice(cut).filter((x) => x !== "-");
17
+ const hasMore = tail.length > 0;
18
+
19
+ // Controllable tab stops: head action buttons + optional ⋯ menubutton (separators skipped).
20
+ const controlMeta = [];
21
+ head.forEach((it, i) => {
22
+ if (it !== "-") controlMeta.push({ kind: "head", headIndex: i });
23
+ });
24
+ if (hasMore) controlMeta.push({ kind: "more" });
25
+
13
26
  React.useEffect(() => {
14
27
  if (!open) return;
15
28
  const d = (e) => { if (wrap.current && !wrap.current.contains(e.target)) setOpen(false); };
16
29
  document.addEventListener("mousedown", d);
17
30
  return () => document.removeEventListener("mousedown", d);
18
31
  }, [open]);
32
+
33
+ React.useEffect(() => {
34
+ if (focusIdx >= controlMeta.length) setFocusIdx(Math.max(0, controlMeta.length - 1));
35
+ }, [focusIdx, controlMeta.length]);
36
+
37
+ const focusControl = (i) => {
38
+ const next = Math.max(0, Math.min(controlMeta.length - 1, i));
39
+ setFocusIdx(next);
40
+ requestAnimationFrame(() => {
41
+ const el = btnRefs.current[next];
42
+ if (el) el.focus();
43
+ });
44
+ };
45
+
46
+ const onToolbarKeyDown = (e, i) => {
47
+ if (e.nativeEvent.isComposing || e.keyCode === 229) return;
48
+ if (e.key === "ArrowRight") { e.preventDefault(); focusControl(i + 1); }
49
+ else if (e.key === "ArrowLeft") { e.preventDefault(); focusControl(i - 1); }
50
+ else if (e.key === "Home") { e.preventDefault(); focusControl(0); }
51
+ else if (e.key === "End") { e.preventDefault(); focusControl(controlMeta.length - 1); }
52
+ else if (e.key === "Escape" && open) { e.preventDefault(); setOpen(false); }
53
+ };
54
+
55
+ const onMenuKeyDown = (e, i) => {
56
+ if (e.nativeEvent.isComposing || e.keyCode === 229) return;
57
+ if (e.key === "ArrowDown") {
58
+ e.preventDefault();
59
+ const n = Math.min(tail.length - 1, i + 1);
60
+ const el = menuRefs.current[n]; if (el) el.focus();
61
+ } else if (e.key === "ArrowUp") {
62
+ e.preventDefault();
63
+ const n = Math.max(0, i - 1);
64
+ const el = menuRefs.current[n]; if (el) el.focus();
65
+ } else if (e.key === "Escape") {
66
+ e.preventDefault();
67
+ setOpen(false);
68
+ const moreIdx = controlMeta.findIndex((c) => c.kind === "more");
69
+ if (moreIdx >= 0) focusControl(moreIdx);
70
+ } else if (e.key === "Home") {
71
+ e.preventDefault();
72
+ const el = menuRefs.current[0]; if (el) el.focus();
73
+ } else if (e.key === "End") {
74
+ e.preventDefault();
75
+ const el = menuRefs.current[tail.length - 1]; if (el) el.focus();
76
+ }
77
+ };
78
+
79
+ let controlI = 0;
19
80
  return (
20
- <div ref={(el) => { wrap.current = el; ref.current = el; }} className={cx("cs-toolbar", className)} role="toolbar" aria-label={label}>
21
- {head.map((it, i) => it === "-"
22
- ? <span key={i} className="cs-toolbar__sep" aria-hidden="true" />
23
- : <button key={i} type="button" className="cs-toolbar__btn" onClick={() => it.onSelect && it.onSelect()}>{it.icon}{it.label ? <span>{it.label}</span> : null}</button>)}
24
- {tail.length ? (
25
- <span className="cs-toolbar__more">
26
- <button type="button" className="cs-toolbar__btn" aria-haspopup="menu" aria-expanded={open} aria-label={t("more")} onClick={() => setOpen((o) => !o)}>⋯</button>
27
- {open ? <span className="cs-menu__list" role="menu">{tail.map((it, i) => <button key={i} type="button" role="menuitem" className="cs-menu__item" onClick={() => { setOpen(false); it.onSelect && it.onSelect(); }}>{it.label}</button>)}</span> : null}
28
- </span>
29
- ) : null}
81
+ <div ref={(el) => { wrap.current = el; ref.current = el; }} className={cx("cs-toolbar", className)} role="toolbar" aria-label={label} aria-orientation="horizontal">
82
+ {head.map((it, i) => {
83
+ if (it === "-") return <span key={"sep-" + i} className="cs-toolbar__sep" aria-hidden="true" />;
84
+ const ci = controlI++;
85
+ return (
86
+ <button
87
+ key={"btn-" + i}
88
+ type="button"
89
+ className="cs-toolbar__btn"
90
+ tabIndex={ci === focusIdx ? 0 : -1}
91
+ ref={(el) => { btnRefs.current[ci] = el; }}
92
+ onFocus={() => setFocusIdx(ci)}
93
+ onKeyDown={(e) => onToolbarKeyDown(e, ci)}
94
+ onClick={() => it.onSelect && it.onSelect()}
95
+ >{it.icon}{it.label ? <span>{it.label}</span> : null}</button>
96
+ );
97
+ })}
98
+ {hasMore ? (() => {
99
+ const ci = controlI++;
100
+ return (
101
+ <span className="cs-toolbar__more">
102
+ <button
103
+ type="button"
104
+ className="cs-toolbar__btn"
105
+ aria-haspopup="menu"
106
+ aria-expanded={open}
107
+ aria-label={t("more")}
108
+ tabIndex={ci === focusIdx ? 0 : -1}
109
+ ref={(el) => { btnRefs.current[ci] = el; }}
110
+ onFocus={() => setFocusIdx(ci)}
111
+ onKeyDown={(e) => {
112
+ onToolbarKeyDown(e, ci);
113
+ if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
114
+ if (!open) { e.preventDefault(); setOpen(true); requestAnimationFrame(() => { const el = menuRefs.current[0]; if (el) el.focus(); }); }
115
+ }
116
+ }}
117
+ onClick={() => setOpen((o) => !o)}
118
+ >⋯</button>
119
+ {open ? (
120
+ <span className="cs-menu__list" role="menu">
121
+ {tail.map((it, i) => (
122
+ <button
123
+ key={i}
124
+ type="button"
125
+ role="menuitem"
126
+ className="cs-menu__item"
127
+ ref={(el) => { menuRefs.current[i] = el; }}
128
+ onKeyDown={(e) => onMenuKeyDown(e, i)}
129
+ onClick={() => { setOpen(false); it.onSelect && it.onSelect(); }}
130
+ >{it.label}</button>
131
+ ))}
132
+ </span>
133
+ ) : null}
134
+ </span>
135
+ );
136
+ })() : null}
30
137
  </div>
31
138
  );
32
139
  }
@@ -1,4 +1,4 @@
1
- **Toolbar** — action bar with "⋯" overflow menu and "-" separators.
1
+ **Toolbar** — action bar with APG arrow navigation, "⋯" overflow menubutton + popup menu, and "-" separators. Escape closes the overflow menu.
2
2
 
3
3
  ```jsx
4
4
  <Toolbar label="Editor" overflowAfter={3} items={[{icon:<Icon name="edit" size="sm"/>,label:"Edit"},"-",{label:"Share"},{label:"Export"},{label:"Archive"}]}/>
@@ -11,9 +11,9 @@
11
11
  .lbl { font: 600 11px/1 var(--cs-font-family-ui); text-transform: uppercase; letter-spacing: .09em; color: var(--cs-color-text-muted); margin-bottom: 10px; }
12
12
  .row { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
13
13
  </style>
14
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
15
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
16
- <script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
14
+ <script src="../../_vendor/react/react.production.min.js"></script>
15
+ <script src="../../_vendor/react/react-dom.production.min.js"></script>
16
+ <script src="../../_vendor/babel/babel.min.js"></script>
17
17
  <script src="../../_ds_bundle.js"></script>
18
18
  </head>
19
19
  <body>
@@ -13,9 +13,9 @@
13
13
  .frame .cs-cmdk-scrim { position: absolute; padding-top: 14px; }
14
14
  .frame .cs-cmdk { inline-size: 100%; box-shadow: none; }
15
15
  </style>
16
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
17
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
18
- <script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
16
+ <script src="../../_vendor/react/react.production.min.js"></script>
17
+ <script src="../../_vendor/react/react-dom.production.min.js"></script>
18
+ <script src="../../_vendor/babel/babel.min.js"></script>
19
19
  <script src="../../_ds_bundle.js"></script>
20
20
  </head>
21
21
  <body>
@@ -1,26 +1,12 @@
1
1
  import React from "react";
2
2
  import { makeT, useLang } from "../_i18n/i18n.js";
3
3
  import { cx } from "../_utils/cx.js";
4
-
5
- const FOCUSABLE = [
6
- 'a[href]',
7
- 'area[href]',
8
- 'button:not([disabled])',
9
- 'input:not([disabled]):not([type="hidden"])',
10
- 'select:not([disabled])',
11
- 'textarea:not([disabled])',
12
- 'audio[controls]',
13
- 'video[controls]',
14
- 'summary',
15
- 'iframe',
16
- '[contenteditable]:not([contenteditable="false"])',
17
- '[tabindex]:not([tabindex="-1"])',
18
- ].join(",");
4
+ import { useOverlayLayer } from "./OverlayManager.jsx";
19
5
 
20
6
  /**
21
7
  * CyberSkill AlertDialog — first-class destructive/confirm modal (role=alertdialog).
22
8
  * Distinct from Popconfirm (inline bubble) and Dialog (general modal). Focus trap +
23
- * restore; bilingual confirm/cancel via the registry.
9
+ * restore via overlay manager; bilingual confirm/cancel via the registry.
24
10
  */
25
11
  export function AlertDialog({
26
12
  open,
@@ -53,40 +39,24 @@ export function AlertDialog({
53
39
  onOpenChange?.(next);
54
40
  };
55
41
  const destructive = (tone ?? variant) === "destructive";
56
- const confirmRef = React.useRef(onConfirm); confirmRef.current = onConfirm;
57
- const cancelRef = React.useRef(onCancel); cancelRef.current = onCancel;
42
+ const confirmRef = React.useRef(onConfirm);
43
+ confirmRef.current = onConfirm;
44
+ const cancelRef = React.useRef(onCancel);
45
+ cancelRef.current = onCancel;
46
+ const setOpenRef = React.useRef(setOpen);
47
+ setOpenRef.current = setOpen;
58
48
 
59
- React.useEffect(() => {
60
- if (!isOpen) return;
61
- const prev = document.activeElement;
62
- const prevOverflow = document.body.style.overflow;
63
- document.body.style.overflow = "hidden";
64
- const focusables = () => (panel.current ? [...panel.current.querySelectorAll(FOCUSABLE)] : []);
65
- // Prefer the confirm action for destructive prompts (WAI-ARIA alertdialog).
66
- const preferred = panel.current?.querySelector(".cs-alert-dialog__confirm") || focusables()[0];
67
- (preferred || panel.current)?.focus?.();
68
- const k = (e) => {
69
- if (e.key === "Escape") {
70
- setOpen(false);
71
- cancelRef.current?.();
72
- return;
73
- }
74
- if (e.key !== "Tab" || !panel.current) return;
75
- const f = focusables();
76
- if (!f.length) { e.preventDefault(); panel.current.focus(); return; }
77
- const a = f[0], z = f[f.length - 1];
78
- const active = document.activeElement;
79
- const inside = panel.current.contains(active);
80
- if (e.shiftKey && (!inside || active === a)) { e.preventDefault(); z.focus(); }
81
- else if (!e.shiftKey && (!inside || active === z)) { e.preventDefault(); a.focus(); }
82
- };
83
- document.addEventListener("keydown", k);
84
- return () => {
85
- document.removeEventListener("keydown", k);
86
- document.body.style.overflow = prevOverflow;
87
- if (prev && prev.focus) prev.focus();
88
- };
89
- }, [isOpen]);
49
+ useOverlayLayer({
50
+ open: isOpen,
51
+ kind: "modal",
52
+ trapFocus: true,
53
+ preferFocusSelector: ".cs-alert-dialog__confirm",
54
+ onEscape: () => {
55
+ setOpenRef.current(false);
56
+ cancelRef.current?.();
57
+ },
58
+ panelRef: panel,
59
+ });
90
60
 
91
61
  const cl = cancelLabel != null ? cancelLabel : t("cancel");
92
62
  const cf = confirmLabel != null ? confirmLabel : t("confirm");
@@ -5,6 +5,8 @@ export type ContextMenuItem = { label: ReactNode; onSelect?: () => void; danger?
5
5
  export interface ContextMenuProps {
6
6
  items: ContextMenuItem[];
7
7
  children?: ReactNode;
8
+ /** "en" | "vi" — else resolved from the nearest [lang] ancestor (vi default). */
9
+ lang?: string;
8
10
  className?: string;
9
11
  }
10
12
  export function ContextMenu(props: ContextMenuProps): React.ReactElement;
@@ -1,9 +1,12 @@
1
1
  import React from "react";
2
+ import { makeT, useLang } from "../_i18n/i18n.js";
2
3
  import { cx } from "../_utils/cx.js";
3
4
 
4
5
  /** CyberSkill ContextMenu — right-click menu scoped to its children. items: {label,onSelect,danger} or "-" separator. */
5
- export function ContextMenu({ items = [], children, className }) {
6
+ export function ContextMenu({ items = [], children, lang, className }) {
6
7
  const [pos, setPos] = React.useState(null);
8
+ const [ref, L] = useLang(lang);
9
+ const t = makeT("ContextMenu", L);
7
10
  React.useEffect(() => {
8
11
  if (!pos) return;
9
12
  const close = () => setPos(null);
@@ -13,11 +16,11 @@ export function ContextMenu({ items = [], children, className }) {
13
16
  return () => { document.removeEventListener("click", close); document.removeEventListener("keydown", k); };
14
17
  }, [pos]);
15
18
  return (
16
- <div className={cx("cs-ctxmenu-zone", className)}
19
+ <div ref={ref} className={cx("cs-ctxmenu-zone", className)}
17
20
  onContextMenu={(e) => { e.preventDefault(); const r = e.currentTarget.getBoundingClientRect(); setPos({ x: e.clientX - r.left, y: e.clientY - r.top }); }}>
18
21
  {children}
19
22
  {pos ? (
20
- <div className="cs-menu__list" role="menu" style={{ position: "absolute", insetInlineStart: pos.x, insetBlockStart: pos.y }}>
23
+ <div className="cs-menu__list" role="menu" aria-label={t("menu")} style={{ position: "absolute", insetInlineStart: pos.x, insetBlockStart: pos.y }}>
21
24
  {items.map((it, i) => it === "-"
22
25
  ? <div key={i} className="cs-menu__sep" />
23
26
  : <button key={i} type="button" role="menuitem" className={cx("cs-menu__item", it.danger && "cs-menu__item--danger")} onClick={() => { setPos(null); it.onSelect && it.onSelect(); }}>{it.label}</button>)}
@@ -13,6 +13,8 @@ export interface DrawerProps {
13
13
  side?: "right" | "left";
14
14
  children?: ReactNode;
15
15
  actions?: ReactNode;
16
+ /** "en" | "vi" — else resolved from the nearest [lang] ancestor (vi default). */
17
+ lang?: string;
16
18
  className?: string;
17
19
  }
18
20
  export function Drawer(props: DrawerProps): React.ReactElement | null;
@@ -1,35 +1,39 @@
1
1
  import React from "react";
2
2
  import { makeT, useLang } from "../_i18n/i18n.js";
3
3
  import { cx } from "../_utils/cx.js";
4
+ import { useOverlayLayer } from "./OverlayManager.jsx";
4
5
 
5
6
  /** CyberSkill Drawer — slide-in side panel with scrim. side: right (default) | left. */
6
7
  export function Drawer({ open, onClose, title, side = "right", children, actions, lang, className }) {
7
8
  const [ref, L] = useLang(lang);
8
- React.useEffect(() => {
9
- if (!open) return;
10
- const prev = document.activeElement;
11
- const SEL = 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
12
- const p = ref.current;
13
- const first = p ? p.querySelector(SEL) : null;
14
- (first || p) && (first || p).focus();
15
- const k = (e) => {
16
- if (e.key === "Escape") { onClose && onClose(); return; }
17
- if (e.key !== "Tab" || !ref.current) return;
18
- const f = [...ref.current.querySelectorAll(SEL)];
19
- if (!f.length) return;
20
- const a = f[0], z = f[f.length - 1];
21
- if (e.shiftKey && document.activeElement === a) { e.preventDefault(); z.focus(); }
22
- else if (!e.shiftKey && document.activeElement === z) { e.preventDefault(); a.focus(); }
23
- };
24
- document.addEventListener("keydown", k);
25
- return () => { document.removeEventListener("keydown", k); if (prev && prev.focus) prev.focus(); };
26
- }, [open]);
9
+ const panel = React.useRef(null);
10
+ const closeRef = React.useRef(onClose);
11
+ closeRef.current = onClose;
12
+
13
+ useOverlayLayer({
14
+ open: !!open,
15
+ kind: "modal",
16
+ trapFocus: true,
17
+ onEscape: () => closeRef.current && closeRef.current(),
18
+ panelRef: panel,
19
+ });
20
+
27
21
  const t = makeT("Drawer", L);
28
22
  if (!open) return null;
29
23
  return (
30
24
  <>
31
25
  <div className="cs-drawer-scrim" onClick={onClose} aria-hidden="true" />
32
- <aside ref={ref} tabIndex={-1} className={cx("cs-drawer", side === "left" && "cs-drawer--left", className)} role="dialog" aria-modal="true" aria-label={typeof title === "string" ? title : t("panel")}>
26
+ <aside
27
+ ref={(el) => {
28
+ panel.current = el;
29
+ ref.current = el;
30
+ }}
31
+ tabIndex={-1}
32
+ className={cx("cs-drawer", side === "left" && "cs-drawer--left", className)}
33
+ role="dialog"
34
+ aria-modal="true"
35
+ aria-label={typeof title === "string" ? title : t("panel")}
36
+ >
33
37
  <div className="cs-drawer__header">
34
38
  {title ? <h2 className="cs-drawer__title">{title}</h2> : null}
35
39
  <button type="button" className="cs-drawer__close" aria-label={t("close")} onClick={onClose}>
@@ -0,0 +1,40 @@
1
+ import type { ReactNode, RefObject } from "react";
2
+
3
+ export type OverlayLayerKind = "dropdown" | "popover" | "modal" | "toast" | "tour";
4
+
5
+ export type OverlayLayerRegistration = {
6
+ id?: string;
7
+ kind: OverlayLayerKind;
8
+ trapFocus?: boolean;
9
+ lockScroll?: boolean;
10
+ onEscape?: () => void;
11
+ restoreEl?: HTMLElement | null;
12
+ };
13
+
14
+ export type OverlayManagerApi = {
15
+ register(layer: OverlayLayerRegistration): () => void;
16
+ top(): OverlayLayerRegistration | null;
17
+ readonly scrollLocked: boolean;
18
+ readonly depth: number;
19
+ };
20
+
21
+ export function getOverlayManager(): OverlayManagerApi;
22
+
23
+ export function OverlayProvider(props: { children?: ReactNode }): JSX.Element;
24
+
25
+ export function useOverlayLayer(opts: {
26
+ open: boolean;
27
+ kind?: OverlayLayerKind;
28
+ trapFocus?: boolean;
29
+ lockScroll?: boolean;
30
+ onEscape?: () => void;
31
+ panelRef?: RefObject<HTMLElement | null>;
32
+ preferFocusSelector?: string;
33
+ }): { manager: OverlayManagerApi };
34
+
35
+ export function attachFocusTrap(
36
+ panelEl: HTMLElement | null,
37
+ opts?: { handleEscape?: boolean; onEscape?: () => void }
38
+ ): () => void;
39
+
40
+ export const focusableSelector: string;