@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,10 +1,15 @@
1
1
  import React from "react";
2
2
  import { makeT, useLang } from "../_i18n/i18n.js";
3
+ import { Skeleton } from "../feedback/Skeleton.jsx";
4
+ import { Result } from "../feedback/Result.jsx";
3
5
  import { cx } from "../_utils/cx.js";
4
6
 
5
7
  /**
6
8
  * CyberSkill DataTable — semantic table with caption, column scope headers,
7
- * per-column render, and an empty state. Solid surface (dense content).
9
+ * per-column render, and idle / loading / error / empty async states.
10
+ * Solid surface (dense content). Reference composition for collection async
11
+ * data (FIND-020): Skeleton rows while loading, Result on error, empty cell
12
+ * when idle with no rows. Other data surfaces should follow the same triad.
8
13
  */
9
14
  export function DataTable({
10
15
  caption,
@@ -12,26 +17,94 @@ export function DataTable({
12
17
  rows,
13
18
  rowKey = "id",
14
19
  emptyState,
20
+ state = "idle",
21
+ errorState,
22
+ loadingState,
23
+ loadingRows = 5,
15
24
  lang,
16
25
  className,
17
26
  }) {
18
27
  const normalized = Array.isArray(rows) ? rows : [];
19
28
  const [ref, L] = useLang(lang);
20
- const es = emptyState != null ? emptyState : makeT("DataTable", L)("empty");
29
+ const t = makeT("DataTable", L);
30
+ const es = emptyState != null ? emptyState : t("empty");
31
+ const colCount = Math.max(1, (columns && columns.length) || 1);
32
+
33
+ if (state === "loading") {
34
+ return (
35
+ <div ref={ref} className={cx("cs-table-wrap", className)} aria-busy="true">
36
+ <span className="cs-sr-only">{t("loading")}</span>
37
+ {loadingState != null ? (
38
+ loadingState
39
+ ) : (
40
+ <table className="cs-table">
41
+ {caption ? <caption>{caption}</caption> : null}
42
+ <thead>
43
+ <tr>
44
+ {(columns || []).map((c) => (
45
+ <th key={c.key} scope="col">
46
+ {c.header}
47
+ </th>
48
+ ))}
49
+ </tr>
50
+ </thead>
51
+ <tbody aria-hidden="true">
52
+ {Array.from({ length: Math.max(1, loadingRows) }).map((_, i) => (
53
+ <tr key={i}>
54
+ {Array.from({ length: colCount }).map((__, j) => (
55
+ <td key={j}>
56
+ <Skeleton lines={1} />
57
+ </td>
58
+ ))}
59
+ </tr>
60
+ ))}
61
+ </tbody>
62
+ </table>
63
+ )}
64
+ </div>
65
+ );
66
+ }
67
+
68
+ if (state === "error") {
69
+ return (
70
+ <div ref={ref} className={cx("cs-table-wrap", "cs-table-wrap--status", className)} role="alert">
71
+ {errorState != null ? (
72
+ errorState
73
+ ) : (
74
+ <Result status="error" lang={L} title={t("error")}>
75
+ {t("errorHint")}
76
+ </Result>
77
+ )}
78
+ </div>
79
+ );
80
+ }
81
+
21
82
  return (
22
83
  <div ref={ref} className={cx("cs-table-wrap", className)}>
23
84
  <table className="cs-table">
24
85
  {caption ? <caption>{caption}</caption> : null}
25
86
  <thead>
26
- <tr>{columns.map((c) => <th key={c.key} scope="col">{c.header}</th>)}</tr>
87
+ <tr>
88
+ {(columns || []).map((c) => (
89
+ <th key={c.key} scope="col">
90
+ {c.header}
91
+ </th>
92
+ ))}
93
+ </tr>
27
94
  </thead>
28
95
  <tbody>
29
96
  {normalized.length === 0 ? (
30
- <tr><td colSpan={columns.length} className="cs-table__empty">{es}</td></tr>
97
+ <tr>
98
+ <td colSpan={colCount} className="cs-table__empty">
99
+ {es}
100
+ </td>
101
+ </tr>
31
102
  ) : (
32
103
  normalized.map((row, i) => (
33
104
  <tr key={row[rowKey] ?? i}>
34
- {columns.map((c) => <td key={c.key}>{c.render ? c.render(row) : row[c.key]}</td>)}
105
+ {(columns || []).map((c) => (
106
+ <td key={c.key}>{c.render ? c.render(row) : row[c.key]}</td>
107
+ ))}
35
108
  </tr>
36
109
  ))
37
110
  )}
@@ -1,4 +1,4 @@
1
- **DataTable** — semantic table with a caption, scoped column headers, per-column `render`, and an empty state. Dense content, so it stays on a solid surface (never glass).
1
+ **DataTable** — semantic table with a caption, scoped column headers, per-column `render`, and an async triad (`idle` / `loading` / `error`). Dense content, so it stays on a solid surface (never glass). Use `state` when the host owns a fetch — do not show empty while loading.
2
2
 
3
3
  ```jsx
4
4
  <DataTable
@@ -10,6 +10,7 @@
10
10
  ]}
11
11
  rows={releases}
12
12
  rowKey="ver"
13
+ state={status} /* "idle" | "loading" | "error" */
13
14
  emptyState="No releases yet"
14
15
  />
15
16
  ```
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Components" viewport="700x300" name="DataTable" subtitle="Caption, scoped headers, custom cells, empty state" -->
1
+ <!-- @dsCard group="Components" viewport="700x420" name="DataTable" subtitle="Caption, scoped headers, idle / loading / error / empty" -->
2
2
  <!DOCTYPE html>
3
3
  <html lang="en">
4
4
  <head>
@@ -14,9 +14,9 @@
14
14
  .pill.hold { background: var(--cs-color-semantic-danger); color: #fff; }
15
15
  .mono { font-family: var(--cs-font-family-mono); font-weight: 600; }
16
16
  </style>
17
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
18
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
19
- <script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
17
+ <script src="../../_vendor/react/react.production.min.js"></script>
18
+ <script src="../../_vendor/react/react-dom.production.min.js"></script>
19
+ <script src="../../_vendor/babel/babel.min.js"></script>
20
20
  <script src="../../_ds_bundle.js"></script>
21
21
  </head>
22
22
  <body>
@@ -28,20 +28,24 @@ const rows = [
28
28
  { ver: "v1.6.0", ships: "This week", status: "active", note: "Glass bindings" },
29
29
  { ver: "v1.7.0", ships: "Q3 2026", status: "hold", note: "Awaiting RFC" },
30
30
  ];
31
+ const cols = [
32
+ { key: "ver", header: "Version", render: (r) => <span className="mono">{r.ver}</span> },
33
+ { key: "ships", header: "Ships" },
34
+ { key: "note", header: "Notes" },
35
+ { key: "status", header: "Status", render: (r) => <span className={"pill " + r.status}>{r.status}</span> },
36
+ ];
31
37
  function Demo() {
32
38
  return (
33
- <div className="wrap">
34
- <DataTable
35
- caption="Releases"
36
- rowKey="ver"
37
- columns={[
38
- { key: "ver", header: "Version", render: (r) => <span className="mono">{r.ver}</span> },
39
- { key: "ships", header: "Ships" },
40
- { key: "note", header: "Notes" },
41
- { key: "status", header: "Status", render: (r) => <span className={"pill " + r.status}>{r.status}</span> },
42
- ]}
43
- rows={rows}
44
- />
39
+ <div style={{ display: "grid", gap: 16 }}>
40
+ <div className="wrap">
41
+ <DataTable caption="Releases" rowKey="ver" columns={cols} rows={rows} />
42
+ </div>
43
+ <div className="wrap">
44
+ <DataTable caption="Loading" rowKey="ver" columns={cols} rows={[]} state="loading" loadingRows={3} />
45
+ </div>
46
+ <div className="wrap">
47
+ <DataTable caption="Error" rowKey="ver" columns={cols} rows={[]} state="error" />
48
+ </div>
45
49
  </div>
46
50
  );
47
51
  }
@@ -2,27 +2,12 @@ import React from "react";
2
2
  import { makeT, useLang } from "../_i18n/i18n.js";
3
3
  import { Icon } from "../icon/Icon.jsx";
4
4
  import { cx } from "../_utils/cx.js";
5
-
6
- const FOCUSABLE = [
7
- 'a[href]',
8
- 'area[href]',
9
- 'button:not([disabled])',
10
- 'input:not([disabled]):not([type="hidden"])',
11
- 'select:not([disabled])',
12
- 'textarea:not([disabled])',
13
- 'audio[controls]',
14
- 'video[controls]',
15
- 'summary',
16
- 'iframe',
17
- '[contenteditable]:not([contenteditable="false"])',
18
- '[tabindex]:not([tabindex="-1"])',
19
- ].join(",");
5
+ import { useOverlayLayer } from "../overlays/OverlayManager.jsx";
20
6
 
21
7
  /**
22
8
  * CyberSkill Dialog — modal overlay + panel. aria-modal, labelled by title and
23
9
  * described by its body, scrim click closes. Body scroll is locked while open
24
- * (prior overflow restored on close/unmount). Compose actions in the footer
25
- * with Buttons.
10
+ * via the overlay manager (nested-safe). Compose actions in the footer with Buttons.
26
11
  */
27
12
  export function Dialog({
28
13
  open,
@@ -40,34 +25,17 @@ export function Dialog({
40
25
  const bodyId = children == null ? undefined : baseId + "-body";
41
26
  const [ref, L] = useLang(lang);
42
27
  const panel = React.useRef(null);
43
- const closeRef = React.useRef(onClose); closeRef.current = onClose;
44
- React.useEffect(() => {
45
- if (!open) return;
46
- const prev = document.activeElement;
47
- const prevOverflow = document.body.style.overflow;
48
- document.body.style.overflow = "hidden";
49
- const focusables = () => (panel.current ? [...panel.current.querySelectorAll(FOCUSABLE)] : []);
50
- const first = focusables()[0];
51
- (first || panel.current) && (first || panel.current).focus();
52
- const k = (e) => {
53
- if (e.key === "Escape") { closeRef.current && closeRef.current(); return; }
54
- if (e.key !== "Tab" || !panel.current) return;
55
- const f = focusables();
56
- if (!f.length) { e.preventDefault(); panel.current.focus(); return; }
57
- const a = f[0], z = f[f.length - 1];
58
- const active = document.activeElement;
59
- const inside = panel.current.contains(active);
60
- // Wrap at either edge; if focus somehow escaped the panel, pull it back in.
61
- if (e.shiftKey && (!inside || active === a)) { e.preventDefault(); z.focus(); }
62
- else if (!e.shiftKey && (!inside || active === z)) { e.preventDefault(); a.focus(); }
63
- };
64
- document.addEventListener("keydown", k);
65
- return () => {
66
- document.removeEventListener("keydown", k);
67
- document.body.style.overflow = prevOverflow;
68
- if (prev && prev.focus) prev.focus();
69
- };
70
- }, [open]);
28
+ const closeRef = React.useRef(onClose);
29
+ closeRef.current = onClose;
30
+
31
+ useOverlayLayer({
32
+ open: !!open,
33
+ kind: "modal",
34
+ trapFocus: true,
35
+ onEscape: () => closeRef.current && closeRef.current(),
36
+ panelRef: panel,
37
+ });
38
+
71
39
  const cl = closeLabel != null ? closeLabel : makeT("Dialog", L)("close");
72
40
  if (!open) return null;
73
41
  return (
@@ -12,9 +12,9 @@
12
12
  .frame .cs-dialog-layer { position: absolute; }
13
13
  .frame .cs-dialog { top: 24px; }
14
14
  </style>
15
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
16
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
17
- <script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
15
+ <script src="../../_vendor/react/react.production.min.js"></script>
16
+ <script src="../../_vendor/react/react-dom.production.min.js"></script>
17
+ <script src="../../_vendor/babel/babel.min.js"></script>
18
18
  <script src="../../_ds_bundle.js"></script>
19
19
  </head>
20
20
  <body>
@@ -11,6 +11,8 @@ export interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {
11
11
  title?: ReactNode;
12
12
  icon?: ReactNode;
13
13
  children?: ReactNode;
14
+ /** "en" | "vi" — else resolved from the nearest [lang] ancestor (vi default). */
15
+ lang?: string;
14
16
  }
15
17
 
16
18
  export function Alert(props: AlertProps): React.ReactElement;
@@ -1,4 +1,5 @@
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
  const PATHS = {
@@ -16,14 +17,19 @@ function DefaultIcon({ variant }) {
16
17
  }
17
18
 
18
19
  /** CyberSkill Alert — inline banner. variant: info | success | warning | danger. */
19
- export function Alert({ variant = "info", title, icon, children, className, ...props }) {
20
+ export function Alert({ variant = "info", title, icon, children, onDismiss, lang, className, ...props }) {
21
+ const [ref, L] = useLang(lang);
22
+ const t = makeT("Alert", L);
20
23
  return (
21
- <div role="status" className={cx("cs-alert", `cs-alert--${variant}`, className)} {...props}>
24
+ <div ref={ref} role="status" className={cx("cs-alert", `cs-alert--${variant}`, className)} {...props}>
22
25
  <span className="cs-alert__icon">{icon ?? <DefaultIcon variant={variant} />}</span>
23
26
  <div>
24
27
  {title ? <p className="cs-alert__title">{title}</p> : null}
25
28
  {children ? <div className="cs-alert__body">{children}</div> : null}
26
29
  </div>
30
+ {onDismiss ? (
31
+ <button type="button" className="cs-alert__dismiss" aria-label={t("dismiss")} onClick={onDismiss}>×</button>
32
+ ) : null}
27
33
  </div>
28
34
  );
29
35
  }
@@ -8,6 +8,8 @@ export interface EmptyStateProps {
8
8
  title?: ReactNode;
9
9
  children?: ReactNode;
10
10
  actions?: ReactNode;
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 EmptyState(props: EmptyStateProps): 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 EmptyState — friendly placeholder for empty views. */
5
- export function EmptyState({ icon, title, children, actions, className }) {
6
+ export function EmptyState({ icon, title, children, actions, lang, className }) {
7
+ const [ref, L] = useLang(lang);
8
+ const t = makeT("EmptyState", L);
6
9
  return (
7
- <div className={cx("cs-empty", className)}>
10
+ <div ref={ref} className={cx("cs-empty", className)}>
8
11
  <span className="cs-empty__icon">
9
12
  {icon ?? <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="M3 8l2-4h14l2 4M3 8v10a1 1 0 0 0 1 1h16a1 1 0 0 0 1-1V8M3 8h6l1 3h4l1-3h6" /></svg>}
10
13
  </span>
11
- {title ? <div className="cs-empty__title">{title}</div> : null}
14
+ <div className="cs-empty__title">{title ?? t("title")}</div>
12
15
  {children ? <div className="cs-empty__body">{children}</div> : null}
13
16
  {actions ? <div className="cs-empty__actions">{actions}</div> : null}
14
17
  </div>
@@ -9,6 +9,8 @@ export interface ProgressBarProps {
9
9
  max?: number;
10
10
  variant?: "ochre" | "umber" | "success";
11
11
  label?: string;
12
+ /** "en" | "vi" — else resolved from the nearest [lang] ancestor (vi default). */
13
+ lang?: string;
12
14
  className?: string;
13
15
  }
14
16
 
@@ -1,12 +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 ProgressBar — determinate progress. variant: ochre (default) | umber | success. */
5
- export function ProgressBar({ value = 0, max = 100, variant, label, className }) {
6
- const pct = Math.max(0, Math.min(100, (value / max) * 100));
6
+ export function ProgressBar({ value = 0, max = 100, variant, label, lang, className }) {
7
+ const safeMax = max > 0 ? max : 100;
8
+ const clamped = Math.max(0, Math.min(safeMax, Number(value) || 0));
9
+ const pct = Math.max(0, Math.min(100, (clamped / safeMax) * 100));
10
+ const [ref, L] = useLang(lang);
11
+ const t = makeT("ProgressBar", L);
7
12
  return (
8
- <div className={cx("cs-progress", variant && `cs-progress--${variant}`, className)}
9
- role="progressbar" aria-valuenow={Math.round(value)} aria-valuemin={0} aria-valuemax={max} aria-label={label}>
13
+ <div ref={ref} className={cx("cs-progress", variant && `cs-progress--${variant}`, className)}
14
+ role="progressbar" aria-valuenow={Math.round(clamped)} aria-valuemin={0} aria-valuemax={safeMax} aria-label={label ?? t("label")}>
10
15
  <span className="cs-progress__fill" style={{ inlineSize: pct + "%", width: pct + "%" }} />
11
16
  </div>
12
17
  );
@@ -2,6 +2,20 @@ import React from "react";
2
2
  import { makeT, useLang } from "../_i18n/i18n.js";
3
3
  import { cx } from "../_utils/cx.js";
4
4
 
5
+ /** Variant glyphs — aligned with Alert so status is never colour-alone (FIND-036). */
6
+ const PATHS = {
7
+ default: "M12 8h.01M11 12h1v4h1 M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z",
8
+ success: "M4 12.5l5 5 11-11",
9
+ danger: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z M9 9l6 6 M15 9l-6 6",
10
+ };
11
+ function DefaultIcon({ variant }) {
12
+ return (
13
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
14
+ <path d={PATHS[variant] || PATHS.default} />
15
+ </svg>
16
+ );
17
+ }
18
+
5
19
  /** Fixed-position stack for Toasts (bottom-right). */
6
20
  export function ToastStack({ children, lang, className }) {
7
21
  const [ref, L] = useLang(lang);
@@ -14,7 +28,7 @@ export function Toast({ variant = "default", title, icon, onClose, lang, childre
14
28
  return (
15
29
  <div ref={ref} className={cx("cs-toast", `cs-toast--${variant}`, className)} role="status" {...props}>
16
30
  <span className="cs-toast__icon" aria-hidden="true">
17
- {icon ?? <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M4 12.5l5 5 11-11" /></svg>}
31
+ {icon ?? <DefaultIcon variant={variant} />}
18
32
  </span>
19
33
  <div>
20
34
  {title ? <div className="cs-toast__title">{title}</div> : null}
@@ -1,7 +1,8 @@
1
- **Toast / ToastStack** — transient notification inside a fixed bottom-right stack. Presentational; manage timing + queue in app state.
1
+ **Toast / ToastStack** — transient notification inside a fixed bottom-right stack. Presentational; manage timing + queue in app state. Variants `default` | `success` | `danger` each ship a distinct glyph (info / check / X) plus a status-coloured start border — never a red check-mark for errors.
2
2
 
3
3
  ```jsx
4
4
  <ToastStack>
5
5
  <Toast variant="success" title="Saved" onClose={dismiss}>Your wish is on its way.</Toast>
6
+ <Toast variant="danger" title="Couldn’t save">Check the network and try again.</Toast>
6
7
  </ToastStack>
7
8
  ```
@@ -10,9 +10,9 @@
10
10
  .lbl { width: 100%; font: 600 11px/1 var(--cs-font-family-ui); text-transform: uppercase; letter-spacing: .09em; color: var(--cs-color-text-muted); }
11
11
  .frame { border: 1px solid var(--cs-color-border-default); border-radius: var(--cs-radius-lg); background: var(--cs-color-surface-panel); }
12
12
  </style>
13
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
14
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
15
- <script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
13
+ <script src="../../_vendor/react/react.production.min.js"></script>
14
+ <script src="../../_vendor/react/react-dom.production.min.js"></script>
15
+ <script src="../../_vendor/babel/babel.min.js"></script>
16
16
  <script src="../../_ds_bundle.js"></script>
17
17
  </head>
18
18
  <body>
@@ -13,9 +13,9 @@
13
13
  .frame { position: relative; height: 96px; border: 1px solid var(--cs-color-border-default); border-radius: var(--cs-radius-md); background: var(--cs-color-surface-raised); }
14
14
  .frame .cs-toast-stack { position: absolute; inset-block-end: 12px; inset-inline-end: 12px; }
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>
@@ -2,8 +2,10 @@ import React from "react";
2
2
  import { makeT, useLang } from "../_i18n/i18n.js";
3
3
  import { cx } from "../_utils/cx.js";
4
4
 
5
+ const EMPTY_PATH = [];
6
+
5
7
  /** CyberSkill Cascader — column-per-level picker for hierarchies (province → district style). */
6
- export function Cascader({ nodes = [], value = [], onChange, placeholder, label, disabled = false, lang, className }) {
8
+ export function Cascader({ nodes = [], value = EMPTY_PATH, onChange, placeholder, label, disabled = false, lang, className }) {
7
9
  const [open, setOpen] = React.useState(false);
8
10
  const [path, setPath] = React.useState(value);
9
11
  const wrap = React.useRef(null);
@@ -11,15 +13,59 @@ export function Cascader({ nodes = [], value = [], onChange, placeholder, label,
11
13
  const [ref, L] = useLang(lang);
12
14
  const t = makeT("Cascader", L);
13
15
  const ph = placeholder != null ? placeholder : t("placeholder");
14
- React.useEffect(() => { setPath(value); }, [open]);
16
+ // Controlled value must re-sync even when the popover stays closed (FIND-014).
17
+ // Depend on a stable key — default `[]` must not reset path every render.
18
+ const valueKey = Array.isArray(value) ? value.join("\0") : "";
19
+ React.useEffect(() => { setPath(Array.isArray(value) ? value : EMPTY_PATH); }, [valueKey]);
15
20
  React.useEffect(() => {
16
21
  if (!open) return;
17
22
  const d = (e) => { if (wrap.current && !wrap.current.contains(e.target)) setOpen(false); };
18
- const k = (e) => { if (e.key === "Escape") setOpen(false); };
23
+ const k = (e) => {
24
+ if (e.key === "Escape") {
25
+ setOpen(false);
26
+ const field = wrap.current && wrap.current.querySelector(".cs-treeselect__field");
27
+ field && field.focus && field.focus();
28
+ return;
29
+ }
30
+ if (!wrap.current) return;
31
+ const opts = [...wrap.current.querySelectorAll('[role="option"]')];
32
+ if (!opts.length) return;
33
+ const active = document.activeElement;
34
+ const idx = opts.indexOf(active);
35
+ if (e.key === "ArrowDown") {
36
+ e.preventDefault();
37
+ (opts[idx < 0 ? 0 : Math.min(opts.length - 1, idx + 1)] || opts[0]).focus();
38
+ } else if (e.key === "ArrowUp") {
39
+ e.preventDefault();
40
+ (opts[idx < 0 ? opts.length - 1 : Math.max(0, idx - 1)] || opts[0]).focus();
41
+ } else if (e.key === "Home") {
42
+ e.preventDefault();
43
+ opts[0].focus();
44
+ } else if (e.key === "End") {
45
+ e.preventDefault();
46
+ opts[opts.length - 1].focus();
47
+ } else if (e.key === "ArrowRight" && idx >= 0) {
48
+ // Expand into children by activating the selected option when it has a chevron.
49
+ active.click && active.click();
50
+ } else if (e.key === "ArrowLeft") {
51
+ e.preventDefault();
52
+ if (path.length) {
53
+ const next = path.slice(0, -1);
54
+ setPath(next);
55
+ } else {
56
+ setOpen(false);
57
+ const field = wrap.current.querySelector(".cs-treeselect__field");
58
+ field && field.focus && field.focus();
59
+ }
60
+ }
61
+ };
19
62
  document.addEventListener("mousedown", d);
20
63
  document.addEventListener("keydown", k);
21
- return () => { document.removeEventListener("mousedown", d); document.removeEventListener("keydown", k); };
22
- }, [open]);
64
+ return () => {
65
+ document.removeEventListener("mousedown", d);
66
+ document.removeEventListener("keydown", k);
67
+ };
68
+ }, [open, path]);
23
69
  const cols = [];
24
70
  let level = nodes;
25
71
  for (let i = 0; level && level.length; i++) {
@@ -31,7 +77,22 @@ export function Cascader({ nodes = [], value = [], onChange, placeholder, label,
31
77
  { let lv = nodes; for (const k of value) { const n = (lv || []).find((x) => x.key === k); if (!n) break; labels.push(n.label); lv = n.children; } }
32
78
  return (
33
79
  <div ref={(el) => { wrap.current = el; ref.current = el; }} className={cx("cs-cascader", className)}>
34
- <button type="button" id={fieldId} className="cs-treeselect__field" disabled={disabled} aria-haspopup="listbox" aria-expanded={open} aria-label={label} onClick={() => setOpen((o) => !o)}>
80
+ <button
81
+ type="button"
82
+ id={fieldId}
83
+ className="cs-treeselect__field"
84
+ disabled={disabled}
85
+ aria-haspopup="listbox"
86
+ aria-expanded={open}
87
+ aria-label={label}
88
+ onClick={() => setOpen((o) => !o)}
89
+ onKeyDown={(e) => {
90
+ if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
91
+ e.preventDefault();
92
+ setOpen(true);
93
+ }
94
+ }}
95
+ >
35
96
  <span className={labels.length ? undefined : "ph"}>{labels.length ? labels.join(" / ") : ph}</span><span aria-hidden="true">▾</span>
36
97
  </button>
37
98
  {open ? (
@@ -41,12 +102,19 @@ export function Cascader({ nodes = [], value = [], onChange, placeholder, label,
41
102
  {col.map((n) => (
42
103
  // role="none" — the <li> wrapper must not sit between listbox and option.
43
104
  <li key={n.key} role="none">
44
- <button type="button" role="option" aria-selected={path[i] === n.key} className={cx("cs-cascader__opt", path[i] === n.key && "on")}
105
+ <button
106
+ type="button"
107
+ role="option"
108
+ aria-selected={path[i] === n.key}
109
+ className={cx("cs-cascader__opt", path[i] === n.key && "on")}
110
+ // Keep options in the focusable set for arrow models (E3).
111
+ data-cs-focusable=""
45
112
  onClick={() => {
46
113
  const next = [...path.slice(0, i), n.key];
47
114
  setPath(next);
48
115
  if (!(n.children && n.children.length)) { onChange && onChange(next); setOpen(false); }
49
- }}>
116
+ }}
117
+ >
50
118
  {n.label}{n.children && n.children.length ? <span aria-hidden="true"> ›</span> : null}
51
119
  </button>
52
120
  </li>
@@ -2,13 +2,39 @@ import React from "react";
2
2
  import { makeT, useLang } from "../_i18n/i18n.js";
3
3
  import { cx } from "../_utils/cx.js";
4
4
 
5
+ /** Strip script/style/event-handler markup before injecting HTML (CDS-SEC-001). */
6
+ function sanitizeHtml(html) {
7
+ if (html == null || html === "") return "";
8
+ if (typeof document === "undefined") {
9
+ return String(html)
10
+ .replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, "")
11
+ .replace(/on\w+\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/gi, "")
12
+ .replace(/javascript:/gi, "");
13
+ }
14
+ const tpl = document.createElement("template");
15
+ tpl.innerHTML = String(html);
16
+ tpl.content.querySelectorAll("script,style,iframe,object,embed,link").forEach((n) => n.remove());
17
+ tpl.content.querySelectorAll("*").forEach((n) => {
18
+ [...n.attributes].forEach((a) => {
19
+ if (/^on/i.test(a.name) || /javascript:/i.test(a.value)) n.removeAttribute(a.name);
20
+ });
21
+ });
22
+ return tpl.innerHTML;
23
+ }
24
+
5
25
  /** CyberSkill Editor — light rich-text (contentEditable): bold · italic · bullet list. onChange(html). */
6
26
  export function Editor({ defaultValue = "", onChange, minHeight = 120, lang, className }) {
7
27
  const box = React.useRef(null);
28
+ const seeded = React.useRef(false);
8
29
  const [ref, L] = useLang(lang);
9
30
  const t = makeT("Editor", L);
10
31
  const cmd = (c) => { document.execCommand(c); box.current && box.current.focus(); emit(); };
11
32
  const emit = () => { onChange && box.current && onChange(box.current.innerHTML); };
33
+ React.useLayoutEffect(() => {
34
+ if (!box.current || seeded.current) return;
35
+ box.current.innerHTML = sanitizeHtml(defaultValue);
36
+ seeded.current = true;
37
+ }, [defaultValue]);
12
38
  const B = ({ c, label, children }) => (
13
39
  <button type="button" className="cs-toolbar__btn" aria-label={label} onMouseDown={(e) => { e.preventDefault(); cmd(c); }}>{children}</button>
14
40
  );
@@ -19,8 +45,17 @@ export function Editor({ defaultValue = "", onChange, minHeight = 120, lang, cla
19
45
  <B c="italic" label={t("italic")}><i>I</i></B>
20
46
  <B c="insertUnorderedList" label={t("list")}>≔</B>
21
47
  </div>
22
- <div ref={box} className="cs-editor__area" contentEditable suppressContentEditableWarning role="textbox" aria-multiline="true" aria-label={t("area")}
23
- style={{ minHeight }} onInput={emit} dangerouslySetInnerHTML={{ __html: defaultValue }} />
48
+ <div
49
+ ref={box}
50
+ className="cs-editor__area"
51
+ contentEditable
52
+ suppressContentEditableWarning
53
+ role="textbox"
54
+ aria-multiline="true"
55
+ aria-label={t("area")}
56
+ style={{ minHeight }}
57
+ onInput={emit}
58
+ />
24
59
  </div>
25
60
  );
26
61
  }