@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
@@ -15,12 +15,14 @@ const TONE = {
15
15
  */
16
16
  export function ConfidenceMeter({ value, level, segments = 5, label, lang, className }) {
17
17
  let tone, filled;
18
+ const segs = Math.max(1, Number(segments) || 5);
18
19
  if (value != null) {
19
- tone = value < 0.4 ? "low" : value < 0.75 ? "medium" : "high";
20
- filled = Math.max(1, Math.round(value * segments));
20
+ const v = Math.max(0, Math.min(1, Number(value) || 0));
21
+ tone = v < 0.4 ? "low" : v < 0.75 ? "medium" : "high";
22
+ filled = Math.max(0, Math.min(segs, Math.round(v * segs)));
21
23
  } else {
22
- tone = level || "medium";
23
- filled = Math.round((TONE[tone].fill / 5) * segments);
24
+ tone = TONE[level] ? level : "medium";
25
+ filled = Math.max(0, Math.min(segs, Math.round((TONE[tone].fill / 5) * segs)));
24
26
  }
25
27
  const meta = TONE[tone];
26
28
  const [ref, L] = useLang(lang);
@@ -33,8 +35,8 @@ export function ConfidenceMeter({ value, level, segments = 5, label, lang, class
33
35
  <span>{lbl}</span>
34
36
  <span className="cs-confidence__level" style={{ color: meta.color }}>{levelText}</span>
35
37
  </div>
36
- <div className="cs-confidence__track" role="meter" aria-valuemin={0} aria-valuemax={segments} aria-valuenow={filled} aria-label={lbl + ": " + levelText}>
37
- {Array.from({ length: segments }).map((_, i) => (
38
+ <div className="cs-confidence__track" role="meter" aria-valuemin={0} aria-valuemax={segs} aria-valuenow={filled} aria-label={lbl + ": " + levelText}>
39
+ {Array.from({ length: segs }).map((_, i) => (
38
40
  <span key={i} className="cs-confidence__seg" style={i < filled ? { background: meta.color } : undefined} />
39
41
  ))}
40
42
  </div>
@@ -12,6 +12,8 @@ export interface HumanReviewGateProps {
12
12
  reviewer?: ReactNode;
13
13
  approveLabel?: string;
14
14
  rejectLabel?: string;
15
+ /** "en" | "vi" — else resolved from the nearest [lang] ancestor (vi default). */
16
+ lang?: string;
15
17
  className?: string;
16
18
  onApprove?: () => void;
17
19
  onReject?: () => void;
@@ -15,6 +15,8 @@ export interface PromptInputProps {
15
15
  hint?: ReactNode;
16
16
  disabled?: boolean;
17
17
  busy?: boolean;
18
+ /** "en" | "vi" — else resolved from the nearest [lang] ancestor (vi default). */
19
+ lang?: string;
18
20
  className?: string;
19
21
  }
20
22
 
@@ -4,6 +4,8 @@ import type * as React from "react";
4
4
  * under reduced-motion. */
5
5
  export interface TypingIndicatorProps {
6
6
  label?: string;
7
+ /** "en" | "vi" — else resolved from the nearest [lang] ancestor (vi default). */
8
+ lang?: string;
7
9
  className?: string;
8
10
  }
9
11
  export function TypingIndicator(props: TypingIndicatorProps): React.ReactElement;
@@ -10,9 +10,9 @@
10
10
  .grid { display: grid; grid-template-columns: 1.2fr 1fr; gap: 24px; max-width: 660px; align-items: start; }
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
  </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>
@@ -9,9 +9,9 @@
9
9
  .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; }
10
10
  .blk { margin-bottom: 20px; }
11
11
  </style>
12
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
13
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
14
- <script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
12
+ <script src="../../_vendor/react/react.production.min.js"></script>
13
+ <script src="../../_vendor/react/react-dom.production.min.js"></script>
14
+ <script src="../../_vendor/babel/babel.min.js"></script>
15
15
  <script src="../../_ds_bundle.js"></script>
16
16
  </head>
17
17
  <body>
@@ -10,9 +10,9 @@
10
10
  .stack { display: grid; gap: 18px; max-width: 560px; }
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: 8px; }
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>
@@ -9,9 +9,9 @@
9
9
  .row { display: flex; align-items: center; gap: 24px; }
10
10
  .cap { font: 500 12px/1.4 var(--cs-font-family-ui); color: var(--cs-color-text-muted); margin-top: 8px; }
11
11
  </style>
12
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
13
- <script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
14
- <script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
12
+ <script src="../../_vendor/react/react.production.min.js"></script>
13
+ <script src="../../_vendor/react/react-dom.production.min.js"></script>
14
+ <script src="../../_vendor/babel/babel.min.js"></script>
15
15
  <script src="../../_ds_bundle.js"></script>
16
16
  </head>
17
17
  <body>
@@ -11,9 +11,9 @@
11
11
  .row:last-child { margin-bottom: 0; }
12
12
  .lbl { width: 100%; font: 600 11px/1 var(--cs-font-family-ui); text-transform: uppercase; letter-spacing: .09em; color: var(--cs-color-text-muted); margin-bottom: 2px; }
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>
@@ -15,13 +15,29 @@ export function Image({ src, alt = "", ratio, preview = false, fallback, lang, c
15
15
  document.addEventListener("keydown", k);
16
16
  return () => document.removeEventListener("keydown", k);
17
17
  }, [zoom]);
18
+ const openPreview = () => setZoom(true);
19
+ const onPreviewKey = (e) => {
20
+ if (e.key === "Enter" || e.key === " ") {
21
+ e.preventDefault();
22
+ openPreview();
23
+ }
24
+ };
18
25
  const body = state === "error"
19
26
  ? <span className="cs-image__fallback">{fallback || <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2" /><circle cx="9" cy="9" r="2" /><path d="M21 15l-5-5-9 9" /></svg>}</span>
20
27
  : <img {...props} src={src} alt={alt} onLoad={() => setState("ok")} onError={() => setState("error")} />;
28
+ const canPreview = preview && state === "ok";
21
29
  return (
22
30
  <>
23
- <span ref={ref} className={cx("cs-image", state === "loading" && "is-loading", preview && state === "ok" && "is-zoomable", className)} style={ratio ? { aspectRatio: ratio } : undefined}
24
- onClick={preview && state === "ok" ? () => setZoom(true) : undefined} role={preview && state === "ok" ? "button" : undefined} aria-label={preview && state === "ok" ? t("preview") + (alt ? ": " + alt : "") : undefined}>
31
+ <span
32
+ ref={ref}
33
+ className={cx("cs-image", state === "loading" && "is-loading", canPreview && "is-zoomable", className)}
34
+ style={ratio ? { aspectRatio: ratio } : undefined}
35
+ onClick={canPreview ? openPreview : undefined}
36
+ onKeyDown={canPreview ? onPreviewKey : undefined}
37
+ role={canPreview ? "button" : undefined}
38
+ tabIndex={canPreview ? 0 : undefined}
39
+ aria-label={canPreview ? t("preview") + (alt ? ": " + alt : "") : undefined}
40
+ >
25
41
  {body}
26
42
  </span>
27
43
  {zoom ? (
@@ -1,10 +1,14 @@
1
1
  import type { ReactNode } from "react";
2
2
 
3
- /** Drag-to-reorder list (HTML5 drag and drop). onChange receives the new order. */
3
+ /** Reorderable list item. */
4
4
  export interface SortableItem { key: string; label: ReactNode; }
5
5
  export interface SortableProps {
6
6
  items: SortableItem[];
7
7
  onChange?: (items: SortableItem[]) => void;
8
+ lang?: string;
8
9
  className?: string;
9
10
  }
11
+ /** Pure reorder helper shared by drag and move-button paths. */
12
+ export function reorderItems<T>(items: T[], from: number, to: number): T[];
13
+ /** Reorderable list — move-up/down buttons (WCAG 2.5.7) plus HTML5 DnD enhancement. */
10
14
  export function Sortable(props: SortableProps): React.ReactElement;
@@ -1,28 +1,61 @@
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
- /** CyberSkill Sortable — drag-to-reorder list (HTML5 DnD). items: [{key,label}]; onChange(newItems). */
5
- export function Sortable({ items = [], onChange, className }) {
5
+ /** Move item at `from` to index `to` (shared by drag drop and move buttons). */
6
+ export function reorderItems(items, from, to) {
7
+ if (from < 0 || to < 0 || from >= items.length || to >= items.length || from === to) return items;
8
+ const next = [...items];
9
+ next.splice(to, 0, next.splice(from, 1)[0]);
10
+ return next;
11
+ }
12
+
13
+ /** CyberSkill Sortable — reorderable list (move buttons + HTML5 DnD enhancement). items: [{key,label}]; onChange(newItems). */
14
+ export function Sortable({ items = [], onChange, lang, className }) {
6
15
  const [dragKey, setDragKey] = React.useState(null);
7
16
  const [over, setOver] = React.useState(null);
17
+ const [ref, L] = useLang(lang);
18
+ const t = makeT("Sortable", L);
19
+ const move = (from, to) => {
20
+ const next = reorderItems(items, from, to);
21
+ if (next !== items) onChange && onChange(next);
22
+ };
8
23
  const drop = () => {
9
24
  if (dragKey == null || over == null || dragKey === over) { setDragKey(null); setOver(null); return; }
10
25
  const from = items.findIndex((i) => i.key === dragKey);
11
26
  const to = items.findIndex((i) => i.key === over);
12
- const next = [...items];
13
- next.splice(to, 0, next.splice(from, 1)[0]);
14
- onChange && onChange(next);
27
+ move(from, to);
15
28
  setDragKey(null); setOver(null);
16
29
  };
17
30
  return (
18
- <ul className={cx("cs-sortable", className)}>
19
- {items.map((it) => (
31
+ <ul ref={ref} className={cx("cs-sortable", className)}>
32
+ {items.map((it, idx) => (
20
33
  <li key={it.key} draggable
21
34
  className={cx("cs-sortable__item", dragKey === it.key && "is-dragging", over === it.key && "is-over")}
22
- onDragStart={() => setDragKey(it.key)}
35
+ onDragStart={(e) => {
36
+ if (e.target.closest && e.target.closest(".cs-sortable__ops")) { e.preventDefault(); return; }
37
+ setDragKey(it.key);
38
+ }}
23
39
  onDragOver={(e) => { e.preventDefault(); setOver(it.key); }}
24
40
  onDrop={drop} onDragEnd={drop}>
25
- <span className="cs-sortable__grip" aria-hidden="true">⠿</span>{it.label}
41
+ <span className="cs-sortable__grip" aria-hidden="true">⠿</span>
42
+ <span className="cs-sortable__label">{it.label}</span>
43
+ <span className="cs-sortable__ops" onMouseDown={(e) => e.stopPropagation()}>
44
+ <button
45
+ type="button"
46
+ className="cs-button cs-button--secondary cs-button--xs"
47
+ aria-label={t("moveUp")}
48
+ disabled={idx === 0}
49
+ onClick={() => move(idx, idx - 1)}
50
+ >↑</button>
51
+ <button
52
+ type="button"
53
+ className="cs-button cs-button--secondary cs-button--xs"
54
+ aria-label={t("moveDown")}
55
+ disabled={idx === items.length - 1}
56
+ onClick={() => move(idx, idx + 1)}
57
+ >↓</button>
58
+ </span>
26
59
  </li>
27
60
  ))}
28
61
  </ul>
@@ -1,5 +1,7 @@
1
- **Sortable** — drag-to-reorder list (compose columns of it for a kanban).
1
+ **Sortable** — reorderable list with move-up/down buttons (keyboard + single-pointer) and optional HTML5 drag. Compose columns of it for a kanban.
2
2
 
3
3
  ```jsx
4
- <Sortable items={tasks} onChange={setTasks}/>
4
+ <Sortable items={tasks} onChange={setTasks} lang="en"/>
5
5
  ```
6
+
7
+ Buttons expose i18n `aria-label`s (`moveUp` / `moveDown`); first/last controls are disabled.
@@ -3,11 +3,12 @@ import { makeT, useLang } from "../_i18n/i18n.js";
3
3
  import { cx } from "../_utils/cx.js";
4
4
 
5
5
  /** CyberSkill Terminal — command console: history + prompt input; onCommand returns output (string or lines). */
6
- export function Terminal({ title = "cyberskill — zsh", welcome, onCommand, prompt = "➜", lang, className }) {
6
+ export function Terminal({ title, welcome, onCommand, prompt = "➜", lang, className }) {
7
7
  const [hist, setHist] = React.useState(() => (welcome ? [{ out: welcome }] : []));
8
8
  const [q, setQ] = React.useState("");
9
9
  const [ref, L] = useLang(lang);
10
10
  const t = makeT("Terminal", L);
11
+ const barTitle = title ?? t("title");
11
12
  const run = () => {
12
13
  if (!q.trim()) return;
13
14
  const res = onCommand ? onCommand(q.trim()) : "";
@@ -16,7 +17,7 @@ export function Terminal({ title = "cyberskill — zsh", welcome, onCommand, pro
16
17
  };
17
18
  return (
18
19
  <div ref={ref} className={cx("cs-terminal", className)}>
19
- <div className="cs-terminal__bar"><i /><i /><i /><span>{title}</span></div>
20
+ <div className="cs-terminal__bar"><i /><i /><i /><span>{barTitle}</span></div>
20
21
  <div className="cs-terminal__body">
21
22
  {hist.map((l, i) => l.cmd != null
22
23
  ? <div key={i} className="cs-terminal__line"><span className="p">{prompt}</span> {l.cmd}</div>
@@ -8,6 +8,8 @@ import type { ReactNode } from "react";
8
8
  export interface TooltipProps {
9
9
  label: ReactNode;
10
10
  children: ReactNode;
11
+ /** "en" | "vi" — else resolved from the nearest [lang] ancestor (vi default). */
12
+ lang?: string;
11
13
  className?: string;
12
14
  }
13
15
 
@@ -1,12 +1,15 @@
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 Tooltip — hover/focus bubble above the trigger. Keep label short. */
5
- export function Tooltip({ label, children, className }) {
6
+ export function Tooltip({ label, children, lang, className }) {
7
+ const [ref, L] = useLang(lang);
8
+ const t = makeT("Tooltip", L);
6
9
  return (
7
- <span className={cx("cs-tooltip", className)}>
10
+ <span ref={ref} className={cx("cs-tooltip", className)}>
8
11
  {children}
9
- <span className="cs-tooltip__bubble" role="tooltip">{label}</span>
12
+ <span className="cs-tooltip__bubble" role="tooltip">{label ?? t("label")}</span>
10
13
  </span>
11
14
  );
12
15
  }
@@ -1,6 +1,7 @@
1
1
  import type { ReactNode } from "react";
2
2
 
3
- /** Expandable hierarchy (role=tree). Single-select via onSelect(key, node). */
3
+ /** Expandable hierarchy (APG tree: roving tabindex + arrow navigate/expand).
4
+ * Single-select via onSelect(key, node). */
4
5
  export interface TreeNode { key: string; label: ReactNode; children?: TreeNode[]; }
5
6
  export interface TreeProps {
6
7
  nodes: TreeNode[];
@@ -1,23 +1,144 @@
1
1
  import React from "react";
2
2
  import { cx } from "../_utils/cx.js";
3
3
 
4
- function Node({ n, depth, selected, onSelect, defaultOpen }) {
5
- const [open, setOpen] = React.useState(!!defaultOpen);
6
- const kids = n.children || [];
7
- return (
8
- <li role="treeitem" aria-expanded={kids.length ? open : undefined} aria-selected={selected === n.key}>
9
- <span className={cx("cs-tree__row", selected === n.key && "is-selected")} style={{ paddingInlineStart: depth * 18 + 6 }}>
10
- {kids.length ? (
11
- <button type="button" className="cs-tree__twist" aria-hidden="true" tabIndex={-1} onClick={() => setOpen((o) => !o)}>{open ? "▾" : "▸"}</button>
12
- ) : <span className="cs-tree__twist" aria-hidden="true" />}
13
- <button type="button" className="cs-tree__label" onClick={() => { onSelect && onSelect(n.key, n); if (kids.length) setOpen((o) => !o); }}>{n.label}</button>
14
- </span>
15
- {kids.length && open ? <ul role="group">{kids.map((c) => <Node key={c.key} n={c} depth={depth + 1} selected={selected} onSelect={onSelect} defaultOpen={defaultOpen} />)}</ul> : null}
16
- </li>
17
- );
4
+ function collectVisible(nodes, openMap, out = []) {
5
+ for (const n of nodes) {
6
+ out.push(n);
7
+ const kids = n.children || [];
8
+ if (kids.length && openMap[n.key]) collectVisible(kids, openMap, out);
9
+ }
10
+ return out;
18
11
  }
19
12
 
20
- /** CyberSkill Tree — expandable hierarchy. nodes: {key,label,children[]}. Single select via onSelect. */
13
+ function parentOf(nodes, key, parent = null) {
14
+ for (const n of nodes) {
15
+ if (n.key === key) return parent;
16
+ const kids = n.children || [];
17
+ if (kids.length) {
18
+ const p = parentOf(kids, key, n);
19
+ if (p !== undefined) return p;
20
+ }
21
+ }
22
+ return undefined;
23
+ }
24
+
25
+ function findNode(nodes, key) {
26
+ for (const n of nodes) {
27
+ if (n.key === key) return n;
28
+ const kids = n.children || [];
29
+ if (kids.length) {
30
+ const hit = findNode(kids, key);
31
+ if (hit) return hit;
32
+ }
33
+ }
34
+ return null;
35
+ }
36
+
37
+ function seedOpen(nodes, defaultOpen, map = {}) {
38
+ for (const n of nodes) {
39
+ const kids = n.children || [];
40
+ if (kids.length) {
41
+ map[n.key] = !!defaultOpen;
42
+ seedOpen(kids, defaultOpen, map);
43
+ }
44
+ }
45
+ return map;
46
+ }
47
+
48
+ /** CyberSkill Tree — expandable hierarchy with APG tree keyboard (roving tabindex + arrows). nodes: {key,label,children[]}. Single select via onSelect. */
21
49
  export function Tree({ nodes = [], selected, onSelect, defaultOpen = false, className }) {
22
- return <ul role="tree" className={cx("cs-tree", className)}>{nodes.map((n) => <Node key={n.key} n={n} depth={0} selected={selected} onSelect={onSelect} defaultOpen={defaultOpen} />)}</ul>;
50
+ const [openMap, setOpenMap] = React.useState(() => seedOpen(nodes, defaultOpen));
51
+ const [focusKey, setFocusKey] = React.useState(() => {
52
+ if (selected && findNode(nodes, selected)) return selected;
53
+ return nodes[0] ? nodes[0].key : null;
54
+ });
55
+ const itemRefs = React.useRef({});
56
+
57
+ React.useEffect(() => {
58
+ setOpenMap((prev) => {
59
+ const next = seedOpen(nodes, defaultOpen);
60
+ for (const k of Object.keys(next)) if (k in prev) next[k] = prev[k];
61
+ return next;
62
+ });
63
+ }, [nodes, defaultOpen]);
64
+
65
+ const visible = React.useMemo(() => collectVisible(nodes, openMap), [nodes, openMap]);
66
+ React.useEffect(() => {
67
+ if (!visible.length) { setFocusKey(null); return; }
68
+ if (!focusKey || !visible.some((n) => n.key === focusKey)) setFocusKey(visible[0].key);
69
+ }, [visible, focusKey]);
70
+
71
+ const toggle = (key) => setOpenMap((m) => ({ ...m, [key]: !m[key] }));
72
+
73
+ const focusItem = (key) => {
74
+ setFocusKey(key);
75
+ requestAnimationFrame(() => {
76
+ const el = itemRefs.current[key];
77
+ if (el) el.focus();
78
+ });
79
+ };
80
+
81
+ const onKeyDown = (e, key) => {
82
+ if (e.nativeEvent.isComposing || e.keyCode === 229) return;
83
+ const idx = visible.findIndex((n) => n.key === key);
84
+ if (idx < 0) return;
85
+ const node = visible[idx];
86
+ const kids = node.children || [];
87
+ const open = !!openMap[key];
88
+
89
+ if (e.key === "ArrowDown") {
90
+ e.preventDefault();
91
+ if (idx < visible.length - 1) focusItem(visible[idx + 1].key);
92
+ } else if (e.key === "ArrowUp") {
93
+ e.preventDefault();
94
+ if (idx > 0) focusItem(visible[idx - 1].key);
95
+ } else if (e.key === "Home") {
96
+ e.preventDefault();
97
+ focusItem(visible[0].key);
98
+ } else if (e.key === "End") {
99
+ e.preventDefault();
100
+ focusItem(visible[visible.length - 1].key);
101
+ } else if (e.key === "ArrowRight") {
102
+ e.preventDefault();
103
+ if (kids.length && !open) toggle(key);
104
+ else if (kids.length && open) focusItem(kids[0].key);
105
+ } else if (e.key === "ArrowLeft") {
106
+ e.preventDefault();
107
+ if (kids.length && open) toggle(key);
108
+ else {
109
+ const p = parentOf(nodes, key);
110
+ if (p) focusItem(p.key);
111
+ }
112
+ } else if (e.key === "Enter" || e.key === " ") {
113
+ e.preventDefault();
114
+ onSelect && onSelect(key, node);
115
+ if (kids.length) toggle(key);
116
+ }
117
+ };
118
+
119
+ const renderNodes = (list, depth) => list.map((n) => {
120
+ const kids = n.children || [];
121
+ const open = !!openMap[n.key];
122
+ return (
123
+ <li key={n.key} role="treeitem" aria-expanded={kids.length ? open : undefined} aria-selected={selected === n.key}>
124
+ <span className={cx("cs-tree__row", selected === n.key && "is-selected")} style={{ paddingInlineStart: depth * 18 + 6 }}>
125
+ {kids.length ? (
126
+ <button type="button" className="cs-tree__twist" aria-hidden="true" tabIndex={-1} onClick={() => toggle(n.key)}>{open ? "▾" : "▸"}</button>
127
+ ) : <span className="cs-tree__twist" aria-hidden="true" />}
128
+ <button
129
+ type="button"
130
+ className="cs-tree__label"
131
+ tabIndex={focusKey === n.key ? 0 : -1}
132
+ ref={(el) => { itemRefs.current[n.key] = el; }}
133
+ onClick={() => { onSelect && onSelect(n.key, n); if (kids.length) toggle(n.key); }}
134
+ onKeyDown={(e) => onKeyDown(e, n.key)}
135
+ onFocus={() => setFocusKey(n.key)}
136
+ >{n.label}</button>
137
+ </span>
138
+ {kids.length && open ? <ul role="group">{renderNodes(kids, depth + 1)}</ul> : null}
139
+ </li>
140
+ );
141
+ });
142
+
143
+ return <ul role="tree" className={cx("cs-tree", className)}>{renderNodes(nodes, 0)}</ul>;
23
144
  }
@@ -1,4 +1,4 @@
1
- **Tree** — expandable hierarchy with single select.
1
+ **Tree** — expandable hierarchy with APG keyboard (ArrowUp/Down move, ArrowRight/Left expand-collapse, Home/End) and single select.
2
2
 
3
3
  ```jsx
4
4
  <Tree selected={k} onSelect={setK} nodes={[{key:"p",label:"Platform",children:[{key:"ds",label:"Design System"}]}]}/>
@@ -1,13 +1,21 @@
1
1
  import React from "react";
2
2
  import { cx } from "../_utils/cx.js";
3
3
 
4
- /** CyberSkill Watermark — repeats rotated text behind children (draft/confidential marking). */
4
+ /** CyberSkill Watermark — repeats rotated text behind children (draft/confidential marking).
5
+ * Fill colour is read from --cs-color-text-primary at render time (data-URIs cannot resolve CSS vars). */
5
6
  export function Watermark({ text = "CyberSkill", opacity = 0.09, gap = 140, rotate = -22, children, className }) {
7
+ const host = React.useRef(null);
8
+ const [fill, setFill] = React.useState("#45210E");
9
+ React.useLayoutEffect(() => {
10
+ if (!host.current || typeof getComputedStyle === "undefined") return;
11
+ const c = getComputedStyle(host.current).getPropertyValue("--cs-color-text-primary").trim();
12
+ if (c) setFill(c);
13
+ }, []);
6
14
  const svg = encodeURIComponent(
7
- `<svg xmlns="http://www.w3.org/2000/svg" width="${gap}" height="${gap}"><text x="50%" y="50%" font-family="Be Vietnam Pro, sans-serif" font-size="14" font-weight="700" fill="#45210E" fill-opacity="${opacity}" text-anchor="middle" transform="rotate(${rotate} ${gap / 2} ${gap / 2})">${String(text).replace(/&/g, "&amp;").replace(/</g, "&lt;")}</text></svg>`
15
+ `<svg xmlns="http://www.w3.org/2000/svg" width="${gap}" height="${gap}"><text x="50%" y="50%" font-family="Be Vietnam Pro, sans-serif" font-size="14" font-weight="700" fill="${fill}" fill-opacity="${opacity}" text-anchor="middle" transform="rotate(${rotate} ${gap / 2} ${gap / 2})">${String(text).replace(/&/g, "&amp;").replace(/</g, "&lt;")}</text></svg>`
8
16
  );
9
17
  return (
10
- <div className={cx("cs-watermark", className)} style={{ position: "relative" }}>
18
+ <div ref={host} className={cx("cs-watermark", className)} style={{ position: "relative" }}>
11
19
  {children}
12
20
  <div aria-hidden="true" style={{ position: "absolute", inset: 0, pointerEvents: "none", backgroundImage: `url("data:image/svg+xml,${svg}")` }} />
13
21
  </div>
@@ -10,9 +10,9 @@
10
10
  .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; }
11
11
  .blk { margin-bottom: 20px; }
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>
@@ -11,9 +11,9 @@
11
11
  .stats { display: flex; gap: 26px; align-items: center; }
12
12
  .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; }
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>
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { makeT, useLang } from "../_i18n/i18n.js";
3
+ import { Icon } from "../icon/Icon.jsx";
3
4
  import { cx } from "../_utils/cx.js";
4
5
 
5
6
  /**
@@ -114,7 +115,15 @@ export function DataGrid({
114
115
  </button>
115
116
  ) : c.header}
116
117
  {persistKey ? (
117
- <button type="button" className="cs-datagrid__pin" title="Pin column first" onClick={() => pinColumn(c.key)} aria-label={"Pin " + c.key}>⟂</button>
118
+ <button
119
+ type="button"
120
+ className="cs-datagrid__pin"
121
+ title={t("pin")}
122
+ onClick={() => pinColumn(c.key)}
123
+ aria-label={t("pinNamed").replace("{name}", String(c.header != null ? c.header : c.key))}
124
+ >
125
+ <Icon name="pin" size="sm" />
126
+ </button>
118
127
  ) : null}
119
128
  </th>
120
129
  ))}
@@ -8,9 +8,17 @@ export interface DataTableColumn<Row> {
8
8
  render?: (row: Row) => ReactNode;
9
9
  }
10
10
 
11
+ /**
12
+ * Async triad for collection surfaces (FIND-020). Prefer composing existing
13
+ * feedback: Skeleton for loading, Result for error, emptyState for idle empty.
14
+ * Idle is the default — omit `state` for static tables.
15
+ */
16
+ export type DataTableState = "idle" | "loading" | "error";
17
+
11
18
  /**
12
19
  * Enterprise data table: caption, scoped column headers, per-column render, and
13
- * an empty state. Dense content — keep it on a solid surface (no glass).
20
+ * idle / loading / error / empty states. Dense content — keep it on a solid
21
+ * surface (no glass).
14
22
  */
15
23
  export interface DataTableProps<Row extends Record<string, unknown>> {
16
24
  caption?: ReactNode;
@@ -19,6 +27,21 @@ export interface DataTableProps<Row extends Record<string, unknown>> {
19
27
  /** Field used as React key. Default "id". */
20
28
  rowKey?: keyof Row & string;
21
29
  emptyState?: ReactNode;
30
+ /**
31
+ * Async data ownership. Default `"idle"`.
32
+ * - `loading` — Skeleton rows (or `loadingState`) + polite status text
33
+ * - `error` — Result (or `errorState`) with `role="alert"`
34
+ * - `idle` — rows or empty cell
35
+ */
36
+ state?: DataTableState;
37
+ /** Override the default Result error view. */
38
+ errorState?: ReactNode;
39
+ /** Override the default Skeleton-row loading view. */
40
+ loadingState?: ReactNode;
41
+ /** Skeleton row count when `state="loading"` and no `loadingState`. Default 5. */
42
+ loadingRows?: number;
43
+ /** "en" | "vi" — else resolved from the nearest [lang] ancestor (vi default). */
44
+ lang?: string;
22
45
  className?: string;
23
46
  }
24
47