@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.
- package/DESIGN.md +28 -5
- package/README.md +23 -22
- package/SKILL.md +7 -7
- package/THIRD-PARTY-NOTICES.md +35 -0
- package/VERSION +1 -1
- package/_ds_bundle.js +1495 -1733
- package/_ds_manifest.json +1 -1
- package/_esm/cs.mjs +18 -4
- package/_esm/react.d.ts +2 -0
- package/_esm/react.mjs +7 -1
- package/_vendor/NOTICE.md +16 -0
- package/_vendor/babel/README.md +7 -0
- package/_vendor/babel/babel.min.js +4 -0
- package/_vendor/react/README.md +3 -0
- package/_vendor/react/react-dom.production.min.js +1 -0
- package/_vendor/react/react.production.min.js +1 -0
- package/assets/aurora-hoa.webp +0 -0
- package/assets/aurora-kim.webp +0 -0
- package/assets/aurora-moc.webp +0 -0
- package/assets/aurora-tho.webp +0 -0
- package/assets/aurora-thuy.webp +0 -0
- package/base/a11y.css +18 -0
- package/base/ai.css +9 -4
- package/base/collections.css +18 -7
- package/base/components.css +16 -4
- package/base/controls.css +116 -66
- package/base/data.css +4 -4
- package/base/feedback.css +14 -2
- package/base/forms.css +10 -4
- package/base/glass.css +7 -1
- package/base/interaction.css +6 -2
- package/base/navigation.css +9 -3
- package/base/reset.css +7 -1
- package/base/responsive.css +38 -12
- package/base/shell.css +15 -3
- package/components/_i18n/i18n.js +41 -4
- package/components/_i18n/strings.js +89 -22
- package/components/ai/ChatMessage.d.ts +2 -0
- package/components/ai/ChatMessage.jsx +8 -4
- package/components/ai/ConfidenceMeter.d.ts +2 -0
- package/components/ai/ConfidenceMeter.jsx +8 -6
- package/components/ai/HumanReviewGate.d.ts +2 -0
- package/components/ai/PromptInput.d.ts +2 -0
- package/components/ai/TypingIndicator.d.ts +2 -0
- package/components/ai/ai-conversation.card.html +3 -3
- package/components/ai/ai-lumi.card.html +3 -3
- package/components/ai/ai.card.html +3 -3
- package/components/brand/brand.card.html +3 -3
- package/components/button/buttons.card.html +3 -3
- package/components/data/Image.jsx +18 -2
- package/components/data/Sortable.d.ts +5 -1
- package/components/data/Sortable.jsx +42 -9
- package/components/data/Sortable.prompt.md +4 -2
- package/components/data/Terminal.jsx +3 -2
- package/components/data/Tooltip.d.ts +2 -0
- package/components/data/Tooltip.jsx +6 -3
- package/components/data/Tree.d.ts +2 -1
- package/components/data/Tree.jsx +137 -16
- package/components/data/Tree.prompt.md +1 -1
- package/components/data/Watermark.jsx +11 -3
- package/components/data/collections.card.html +3 -3
- package/components/data/data.card.html +3 -3
- package/components/datatable/DataGrid.jsx +10 -1
- package/components/datatable/DataTable.d.ts +24 -1
- package/components/datatable/DataTable.jsx +78 -5
- package/components/datatable/DataTable.prompt.md +2 -1
- package/components/datatable/datatable.card.html +20 -16
- package/components/dialog/Dialog.jsx +13 -45
- package/components/dialog/dialog.card.html +3 -3
- package/components/feedback/Alert.d.ts +2 -0
- package/components/feedback/Alert.jsx +8 -2
- package/components/feedback/EmptyState.d.ts +2 -0
- package/components/feedback/EmptyState.jsx +6 -3
- package/components/feedback/ProgressBar.d.ts +2 -0
- package/components/feedback/ProgressBar.jsx +9 -4
- package/components/feedback/Toast.jsx +15 -1
- package/components/feedback/Toast.prompt.md +2 -1
- package/components/feedback/feedback-2.card.html +3 -3
- package/components/feedback/feedback.card.html +3 -3
- package/components/forms/Cascader.jsx +76 -8
- package/components/forms/Editor.jsx +37 -2
- package/components/forms/FileUpload.d.ts +2 -0
- package/components/forms/FileUpload.jsx +22 -8
- package/components/forms/Form.d.ts +3 -1
- package/components/forms/Form.jsx +9 -1
- package/components/forms/Form.prompt.md +1 -1
- package/components/forms/Mentions.d.ts +1 -1
- package/components/forms/Mentions.jsx +59 -7
- package/components/forms/Mentions.prompt.md +3 -1
- package/components/forms/Rating.d.ts +3 -2
- package/components/forms/Rating.jsx +34 -3
- package/components/forms/Rating.prompt.md +1 -1
- package/components/forms/Select.d.ts +2 -0
- package/components/forms/Select.jsx +6 -2
- package/components/forms/Slider.d.ts +2 -0
- package/components/forms/Slider.jsx +5 -2
- package/components/forms/Switch.d.ts +2 -0
- package/components/forms/Switch.jsx +15 -3
- package/components/forms/TimePicker.jsx +3 -1
- package/components/forms/Toggle.d.ts +2 -0
- package/components/forms/Toggle.jsx +14 -2
- package/components/forms/forms-2.card.html +3 -3
- package/components/forms/forms.card.html +3 -3
- package/components/icon/Icon.d.ts +1 -1
- package/components/icon/Icon.jsx +1 -0
- package/components/icon/Icon.prompt.md +1 -1
- package/components/icon/icon.card.html +3 -3
- package/components/logo/logo.card.html +3 -3
- package/components/navigation/CommandPalette.d.ts +2 -0
- package/components/navigation/CommandPalette.jsx +22 -7
- package/components/navigation/Menu.d.ts +2 -0
- package/components/navigation/Menu.jsx +60 -6
- package/components/navigation/Steps.d.ts +2 -0
- package/components/navigation/Steps.jsx +6 -3
- package/components/navigation/Tabs.d.ts +2 -0
- package/components/navigation/Tabs.jsx +6 -3
- package/components/navigation/Toolbar.d.ts +3 -2
- package/components/navigation/Toolbar.jsx +119 -12
- package/components/navigation/Toolbar.prompt.md +1 -1
- package/components/navigation/navigation.card.html +3 -3
- package/components/navigation/shell.card.html +3 -3
- package/components/overlays/AlertDialog.jsx +19 -49
- package/components/overlays/ContextMenu.d.ts +2 -0
- package/components/overlays/ContextMenu.jsx +6 -3
- package/components/overlays/Drawer.d.ts +2 -0
- package/components/overlays/Drawer.jsx +24 -20
- package/components/overlays/OverlayManager.d.ts +40 -0
- package/components/overlays/OverlayManager.jsx +214 -0
- package/components/overlays/OverlayManager.prompt.md +12 -0
- package/components/overlays/Tour.jsx +14 -7
- package/components/overlays/alertdialog.card.html +3 -3
- package/components/overlays/overlays.card.html +3 -3
- package/components/textfield/textfield.card.html +3 -3
- package/dist/styles.min.css +2252 -0
- package/docs/benchmark-rubric.md +1 -1
- package/docs/ci-cd.md +19 -12
- package/docs/consumer-grant.md +3 -0
- package/docs/consuming.md +13 -13
- package/docs/contrast-report.md +79 -1
- package/docs/conventions.md +21 -8
- package/docs/decisions.md +45 -7
- package/docs/deploy.md +17 -6
- package/docs/design-styles.md +2 -2
- package/docs/quality-gates.md +35 -15
- package/docs/release-notes.md +2 -2
- package/docs/release-runbook.md +78 -0
- package/docs/sync.md +2 -2
- package/docs/vi/benchmark-rubric.md +1 -1
- package/docs/vi/ci-cd.md +17 -12
- package/docs/vi/consumer-grant.md +3 -0
- package/docs/vi/consuming.md +13 -13
- package/docs/vi/contrast-report.md +79 -1
- package/docs/vi/conventions.md +20 -7
- package/docs/vi/decisions.md +43 -6
- package/docs/vi/deploy.md +17 -6
- package/docs/vi/quality-gates.md +34 -15
- package/docs/vi/release-notes.md +2 -2
- package/docs/vi/release-runbook.md +78 -0
- package/docs/vi/sync.md +2 -2
- package/docs/viewer.html +2 -2
- package/fonts/OFL.txt +98 -0
- package/guidelines/atomic-view.html +13 -9
- package/guidelines/brand-imagery.html +1 -1
- package/guidelines/elements-variants.html +5 -5
- package/guidelines/spacing-breakpoints.html +2 -1
- package/guidelines/surfaces-glass.html +1 -1
- package/llms.txt +5 -5
- package/package.json +38 -10
- package/templates/_ds-base.canonical.js +55 -0
- package/templates/ai-cluster-demo.html +2 -2
- package/templates/app-shell/AppShell.dc.html +7 -5
- package/templates/app-shell/content-schema.json +7 -0
- package/templates/app-shell/ds-base.js +33 -1
- package/templates/app-shell/support.js +13 -20
- package/templates/article/Article.dc.html +7 -3
- package/templates/article/content-schema.json +7 -0
- package/templates/article/ds-base.js +33 -1
- package/templates/article/support.js +13 -20
- package/templates/auth/Auth.dc.html +33 -12
- package/templates/auth/content-schema.json +37 -0
- package/templates/auth/ds-base.js +33 -1
- package/templates/auth/support.js +13 -20
- package/templates/bod-deck/BodDeck.dc.html +11 -10
- package/templates/bod-deck/ds-base.js +33 -1
- package/templates/bod-deck/support.js +13 -20
- package/templates/bod-investor-update/BodInvestorUpdate.dc.html +4 -3
- package/templates/bod-investor-update/ds-base.js +33 -1
- package/templates/bod-investor-update/support.js +13 -20
- package/templates/bod-memo/BodMemo.dc.html +6 -5
- package/templates/bod-memo/ds-base.js +33 -1
- package/templates/bod-memo/support.js +13 -20
- package/templates/bod-minutes/BodMinutes.dc.html +2 -1
- package/templates/bod-minutes/ds-base.js +33 -1
- package/templates/bod-minutes/support.js +13 -20
- package/templates/bod-report/BodReport.dc.html +3 -2
- package/templates/bod-report/ds-base.js +33 -1
- package/templates/bod-report/support.js +13 -20
- package/templates/bod-resolution/BodResolution.dc.html +5 -4
- package/templates/bod-resolution/ds-base.js +33 -1
- package/templates/bod-resolution/support.js +13 -20
- package/templates/culture-event-invite/CultureEventInvite.dc.html +3 -2
- package/templates/culture-event-invite/ds-base.js +33 -1
- package/templates/culture-event-invite/support.js +13 -20
- package/templates/dashboard/Dashboard.dc.html +10 -6
- package/templates/dashboard/content-schema.json +7 -0
- package/templates/dashboard/ds-base.js +33 -1
- package/templates/dashboard/support.js +13 -20
- package/templates/delivery-change-note/DeliveryChangeNote.dc.html +4 -3
- package/templates/delivery-change-note/ds-base.js +33 -1
- package/templates/delivery-change-note/support.js +13 -20
- package/templates/delivery-kickoff/DeliveryKickoff.dc.html +3 -2
- package/templates/delivery-kickoff/ds-base.js +33 -1
- package/templates/delivery-kickoff/support.js +13 -20
- package/templates/delivery-qbr-deck/DeliveryQbrDeck.dc.html +6 -5
- package/templates/delivery-qbr-deck/ds-base.js +33 -1
- package/templates/delivery-qbr-deck/support.js +13 -20
- package/templates/delivery-runbook/DeliveryRunbook.dc.html +5 -4
- package/templates/delivery-runbook/ds-base.js +33 -1
- package/templates/delivery-runbook/support.js +13 -20
- package/templates/delivery-status-email/DeliveryStatusEmail.dc.html +3 -2
- package/templates/delivery-status-email/ds-base.js +33 -1
- package/templates/delivery-status-email/support.js +13 -20
- package/templates/doc-style-guide/DocStyleGuide.dc.html +67 -64
- package/templates/doc-style-guide/ds-base.js +33 -1
- package/templates/doc-style-guide/support.js +13 -20
- package/templates/doc-suite-index/DocSuiteIndex.dc.html +46 -45
- package/templates/doc-suite-index/ds-base.js +33 -1
- package/templates/doc-suite-index/support.js +13 -20
- package/templates/doc-templates/DocTemplates.dc.html +42 -41
- package/templates/doc-templates/ds-base.js +33 -1
- package/templates/doc-templates/support.js +13 -20
- package/templates/email/Email.dc.html +3 -2
- package/templates/email/ds-base.js +33 -1
- package/templates/email/support.js +13 -20
- package/templates/email-safe/email-announcement.html +2 -2
- package/templates/email-safe/email-dunning.html +2 -2
- package/templates/email-safe/email-investor.html +2 -2
- package/templates/email-safe/email-launch.html +2 -2
- package/templates/email-safe/email-newsletter.html +2 -2
- package/templates/email-safe/email-status.html +2 -2
- package/templates/email-safe/email-transactional.html +2 -2
- package/templates/finance-dunning-email/FinanceDunningEmail.dc.html +6 -5
- package/templates/finance-dunning-email/ds-base.js +33 -1
- package/templates/finance-dunning-email/support.js +13 -20
- package/templates/finance-expense-report/FinanceExpenseReport.dc.html +4 -3
- package/templates/finance-expense-report/ds-base.js +33 -1
- package/templates/finance-expense-report/support.js +13 -20
- package/templates/finance-invoice/FinanceInvoice.dc.html +6 -5
- package/templates/finance-invoice/ds-base.js +33 -1
- package/templates/finance-invoice/support.js +13 -20
- package/templates/finance-quote/FinanceQuote.dc.html +6 -5
- package/templates/finance-quote/ds-base.js +33 -1
- package/templates/finance-quote/support.js +13 -20
- package/templates/hr-announcement/HrAnnouncement.dc.html +5 -4
- package/templates/hr-announcement/ds-base.js +33 -1
- package/templates/hr-announcement/support.js +13 -20
- package/templates/hr-interview-kit/HrInterviewKit.dc.html +5 -4
- package/templates/hr-interview-kit/ds-base.js +33 -1
- package/templates/hr-interview-kit/support.js +13 -20
- package/templates/hr-offboarding/HrOffboarding.dc.html +2 -1
- package/templates/hr-offboarding/ds-base.js +33 -1
- package/templates/hr-offboarding/support.js +13 -20
- package/templates/hr-performance-review/HrPerformanceReview.dc.html +2 -1
- package/templates/hr-performance-review/ds-base.js +33 -1
- package/templates/hr-performance-review/support.js +13 -20
- package/templates/hr-pip/HrPip.dc.html +2 -1
- package/templates/hr-pip/ds-base.js +33 -1
- package/templates/hr-pip/support.js +13 -20
- package/templates/kitchen-sink.html +9 -4
- package/templates/legal-msa/LegalMsa.dc.html +2 -1
- package/templates/legal-msa/ds-base.js +33 -1
- package/templates/legal-msa/support.js +13 -20
- package/templates/legal-sow/LegalSow.dc.html +2 -1
- package/templates/legal-sow/ds-base.js +33 -1
- package/templates/legal-sow/support.js +13 -20
- package/templates/marketing-campaign-brief/MarketingCampaignBrief.dc.html +3 -2
- package/templates/marketing-campaign-brief/ds-base.js +33 -1
- package/templates/marketing-campaign-brief/support.js +13 -20
- package/templates/marketing-case-study/MarketingCaseStudy.dc.html +6 -5
- package/templates/marketing-case-study/ds-base.js +33 -1
- package/templates/marketing-case-study/support.js +13 -20
- package/templates/marketing-launch/MarketingLaunch.dc.html +6 -5
- package/templates/marketing-launch/ds-base.js +33 -1
- package/templates/marketing-launch/support.js +13 -20
- package/templates/marketing-newsletter/MarketingNewsletter.dc.html +13 -12
- package/templates/marketing-newsletter/ds-base.js +33 -1
- package/templates/marketing-newsletter/support.js +13 -20
- package/templates/marketing-page/MarketingPage.dc.html +19 -14
- package/templates/marketing-page/content-schema.json +1 -0
- package/templates/marketing-page/ds-base.js +33 -1
- package/templates/marketing-page/support.js +13 -20
- package/templates/marketing-press-release/MarketingPressRelease.dc.html +2 -1
- package/templates/marketing-press-release/ds-base.js +33 -1
- package/templates/marketing-press-release/support.js +13 -20
- package/templates/marketing-social-kit/MarketingSocialKit.dc.html +5 -4
- package/templates/marketing-social-kit/ds-base.js +33 -1
- package/templates/marketing-social-kit/support.js +13 -20
- package/templates/sales-one-pager/SalesOnePager.dc.html +5 -4
- package/templates/sales-one-pager/ds-base.js +33 -1
- package/templates/sales-one-pager/support.js +13 -20
- package/templates/sales-proposal-deck/SalesProposalDeck.dc.html +7 -6
- package/templates/sales-proposal-deck/ds-base.js +33 -1
- package/templates/sales-proposal-deck/support.js +13 -20
- package/templates/settings/Settings.dc.html +7 -3
- package/templates/settings/content-schema.json +7 -0
- package/templates/settings/ds-base.js +33 -1
- package/templates/settings/support.js +13 -20
- package/templates/slide-deck/SlideDeck.dc.html +5 -4
- package/templates/slide-deck/ds-base.js +33 -1
- package/templates/slide-deck/support.js +13 -20
- package/templates/team-meeting-agenda/TeamMeetingAgenda.dc.html +2 -1
- package/templates/team-meeting-agenda/ds-base.js +33 -1
- package/templates/team-meeting-agenda/support.js +13 -20
- package/templates/tech-incident-report/TechIncidentReport.dc.html +3 -2
- package/templates/tech-incident-report/ds-base.js +33 -1
- package/templates/tech-incident-report/support.js +13 -20
- package/templates/tech-release-notes/TechReleaseNotes.dc.html +6 -5
- package/templates/tech-release-notes/ds-base.js +33 -1
- package/templates/tech-release-notes/support.js +13 -20
- package/templates/tech-retro/TechRetro.dc.html +4 -3
- package/templates/tech-retro/ds-base.js +33 -1
- package/templates/tech-retro/support.js +13 -20
- package/templates/tech-rfc/TechRfc.dc.html +3 -2
- package/templates/tech-rfc/ds-base.js +33 -1
- package/templates/tech-rfc/support.js +13 -20
- package/templates/vn-appointment-transfer/VnAppointmentTransfer.dc.html +36 -35
- package/templates/vn-appointment-transfer/ds-base.js +33 -1
- package/templates/vn-appointment-transfer/support.js +13 -20
- package/templates/vn-certificate-of-employment/VnCertificateOfEmployment.dc.html +27 -26
- package/templates/vn-certificate-of-employment/ds-base.js +33 -1
- package/templates/vn-certificate-of-employment/support.js +13 -20
- package/templates/vn-code-of-conduct/VnCodeOfConduct.dc.html +44 -43
- package/templates/vn-code-of-conduct/ds-base.js +33 -1
- package/templates/vn-code-of-conduct/support.js +13 -20
- package/templates/vn-compensation-regulation/VnCompensationRegulation.dc.html +53 -52
- package/templates/vn-compensation-regulation/ds-base.js +33 -1
- package/templates/vn-compensation-regulation/support.js +13 -20
- package/templates/vn-contract-amendment/VnContractAmendment.dc.html +41 -40
- package/templates/vn-contract-amendment/ds-base.js +33 -1
- package/templates/vn-contract-amendment/support.js +13 -20
- package/templates/vn-contractor-agreement/VnContractorAgreement.dc.html +50 -49
- package/templates/vn-contractor-agreement/ds-base.js +33 -1
- package/templates/vn-contractor-agreement/support.js +13 -20
- package/templates/vn-data-protection-policy/VnDataProtectionPolicy.dc.html +54 -53
- package/templates/vn-data-protection-policy/ds-base.js +33 -1
- package/templates/vn-data-protection-policy/support.js +13 -20
- package/templates/vn-disciplinary-case-file/VnDisciplinaryCaseFile.dc.html +72 -71
- package/templates/vn-disciplinary-case-file/ds-base.js +33 -1
- package/templates/vn-disciplinary-case-file/support.js +13 -20
- package/templates/vn-disciplinary-schedule/VnDisciplinarySchedule.dc.html +21 -20
- package/templates/vn-disciplinary-schedule/ds-base.js +33 -1
- package/templates/vn-disciplinary-schedule/support.js +13 -20
- package/templates/vn-employee-request/VnEmployeeRequest.dc.html +54 -53
- package/templates/vn-employee-request/ds-base.js +33 -1
- package/templates/vn-employee-request/support.js +13 -20
- package/templates/vn-exit-handover/VnExitHandover.dc.html +122 -121
- package/templates/vn-exit-handover/ds-base.js +33 -1
- package/templates/vn-exit-handover/support.js +13 -20
- package/templates/vn-foreign-employee-pack/VnForeignEmployeePack.dc.html +31 -30
- package/templates/vn-foreign-employee-pack/ds-base.js +33 -1
- package/templates/vn-foreign-employee-pack/support.js +13 -20
- package/templates/vn-grassroots-democracy/VnGrassrootsDemocracy.dc.html +54 -53
- package/templates/vn-grassroots-democracy/ds-base.js +33 -1
- package/templates/vn-grassroots-democracy/support.js +13 -20
- package/templates/vn-infosec-policy/VnInfosecPolicy.dc.html +50 -49
- package/templates/vn-infosec-policy/ds-base.js +33 -1
- package/templates/vn-infosec-policy/support.js +13 -20
- package/templates/vn-internal-labor-regulations/VnInternalLaborRegulations.dc.html +84 -83
- package/templates/vn-internal-labor-regulations/ds-base.js +33 -1
- package/templates/vn-internal-labor-regulations/support.js +13 -20
- package/templates/vn-internship-agreement/VnInternshipAgreement.dc.html +44 -43
- package/templates/vn-internship-agreement/ds-base.js +33 -1
- package/templates/vn-internship-agreement/support.js +13 -20
- package/templates/vn-job-description/VnJobDescription.dc.html +28 -27
- package/templates/vn-job-description/ds-base.js +33 -1
- package/templates/vn-job-description/support.js +13 -20
- package/templates/vn-labor-contract/VnLaborContract.dc.html +109 -108
- package/templates/vn-labor-contract/ds-base.js +33 -1
- package/templates/vn-labor-contract/support.js +13 -20
- package/templates/vn-labour-management-book/VnLabourManagementBook.dc.html +32 -31
- package/templates/vn-labour-management-book/ds-base.js +33 -1
- package/templates/vn-labour-management-book/support.js +13 -20
- package/templates/vn-mutual-nda/VnMutualNda.dc.html +45 -44
- package/templates/vn-mutual-nda/ds-base.js +33 -1
- package/templates/vn-mutual-nda/support.js +13 -20
- package/templates/vn-ndnca-ip/VnNdncaIp.dc.html +73 -72
- package/templates/vn-ndnca-ip/ds-base.js +33 -1
- package/templates/vn-ndnca-ip/support.js +13 -20
- package/templates/vn-offer-letter/VnOfferLetter.dc.html +32 -31
- package/templates/vn-offer-letter/ds-base.js +33 -1
- package/templates/vn-offer-letter/support.js +13 -20
- package/templates/vn-onboarding-checklist/VnOnboardingChecklist.dc.html +16 -15
- package/templates/vn-onboarding-checklist/ds-base.js +33 -1
- package/templates/vn-onboarding-checklist/support.js +13 -20
- package/templates/vn-pdpl-consent/VnPdplConsent.dc.html +43 -42
- package/templates/vn-pdpl-consent/ds-base.js +33 -1
- package/templates/vn-pdpl-consent/support.js +13 -20
- package/templates/vn-performance-evaluation-regulation/VnPerformanceEvaluationRegulation.dc.html +65 -64
- package/templates/vn-performance-evaluation-regulation/ds-base.js +33 -1
- package/templates/vn-performance-evaluation-regulation/support.js +13 -20
- package/templates/vn-performance-review-form/VnPerformanceReviewForm.dc.html +49 -48
- package/templates/vn-performance-review-form/ds-base.js +33 -1
- package/templates/vn-performance-review-form/support.js +13 -20
- package/templates/vn-phantom-stock/VnPhantomStock.dc.html +41 -40
- package/templates/vn-phantom-stock/ds-base.js +33 -1
- package/templates/vn-phantom-stock/support.js +13 -20
- package/templates/vn-probation-contract/VnProbationContract.dc.html +56 -55
- package/templates/vn-probation-contract/ds-base.js +33 -1
- package/templates/vn-probation-contract/support.js +13 -20
- package/templates/vn-receipt-acknowledgement/VnReceiptAcknowledgement.dc.html +28 -27
- package/templates/vn-receipt-acknowledgement/ds-base.js +33 -1
- package/templates/vn-receipt-acknowledgement/support.js +13 -20
- package/templates/vn-remote-work-policy/VnRemoteWorkPolicy.dc.html +44 -43
- package/templates/vn-remote-work-policy/ds-base.js +33 -1
- package/templates/vn-remote-work-policy/support.js +13 -20
- package/templates/vn-resignation-letter/VnResignationLetter.dc.html +20 -19
- package/templates/vn-resignation-letter/ds-base.js +33 -1
- package/templates/vn-resignation-letter/support.js +13 -20
- package/templates/vn-salary-scale/VnSalaryScale.dc.html +39 -38
- package/templates/vn-salary-scale/ds-base.js +33 -1
- package/templates/vn-salary-scale/support.js +13 -20
- package/templates/vn-sow-appendix/VnSowAppendix.dc.html +21 -20
- package/templates/vn-sow-appendix/ds-base.js +33 -1
- package/templates/vn-sow-appendix/support.js +13 -20
- package/templates/vn-termination-decision/VnTerminationDecision.dc.html +25 -24
- package/templates/vn-termination-decision/ds-base.js +33 -1
- package/templates/vn-termination-decision/support.js +13 -20
- package/templates/vn-total-rewards-appendix/VnTotalRewardsAppendix.dc.html +63 -62
- package/templates/vn-total-rewards-appendix/ds-base.js +33 -1
- package/templates/vn-total-rewards-appendix/support.js +13 -20
- package/templates/vn-training-commitment/VnTrainingCommitment.dc.html +39 -38
- package/templates/vn-training-commitment/ds-base.js +33 -1
- package/templates/vn-training-commitment/support.js +13 -20
- package/templates/vn-travel-expense-policy/VnTravelExpensePolicy.dc.html +50 -49
- package/templates/vn-travel-expense-policy/ds-base.js +33 -1
- package/templates/vn-travel-expense-policy/support.js +13 -20
- package/tokens/colors.css +19 -1
- package/tokens/component-tokens.css +1 -0
- package/tokens/element-seeds.json +2 -2
- package/tokens/elements.css +228 -21
- package/tokens/elevation.css +8 -2
- package/tokens/native/CSTokens.kt +37 -2
- package/tokens/native/CSTokens.swift +37 -2
- package/tokens/native/cs_tokens.dart +37 -2
- package/tokens/provenance.json +12 -12
- package/tokens/spacing.css +4 -1
- package/tokens/tokens.dtcg.json +129 -16
- package/tokens/tokens.js +59 -18
- package/tokens/tokens.json +58 -17
- package/tokens/typography.css +2 -0
- package/ui_kits/deck/index.html +4 -0
- package/ui_kits/status-hub/StatusHub.jsx +30 -4
- package/ui_kits/status-hub/index.html +3 -3
- package/ui_kits/status-hub/login.html +55 -9
- package/ui_kits/status-hub/project.html +4 -0
- package/ui_kits/status-hub/settings.html +35 -13
- package/ui_kits/status-hub/status.css +5 -1
- package/ui_kits/website/Website.jsx +25 -3
- package/ui_kits/website/careers.html +5 -1
- package/ui_kits/website/chat.html +5 -3
- package/ui_kits/website/index.html +3 -3
- package/ui_kits/website/site.css +3 -3
- package/ui_kits/website/work.html +5 -1
- package/assets/aurora-hoa.png +0 -0
- package/assets/aurora-kim.png +0 -0
- package/assets/aurora-moc.png +0 -0
- package/assets/aurora-thuy.png +0 -0
- package/docs/status/assets/favicon.svg +0 -5
- package/docs/status/assets/status-legacy.css +0 -399
- package/docs/status/assets/status-legacy.js +0 -505
- package/docs/status/assets/status.css +0 -644
- package/docs/status/assets/status.js +0 -1308
- package/docs/status/data/status-feed.json +0 -1
- package/docs/status/data/task/TASK-REL-001.js +0 -1
- package/docs/status/data/task/TASK-REL-002.js +0 -1
- package/docs/status/index.html +0 -42
- package/docs/status/roadmap.html +0 -4
- package/docs/status/status-legacy.html +0 -117
- package/docs/tasks/BACKLOG.md +0 -26
- package/docs/tasks/release/TASK-REL-001-launch-1-1-0/spec.md +0 -55
- 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
|
-
|
|
20
|
-
|
|
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
|
|
23
|
-
filled = Math.round((TONE[tone].fill / 5) *
|
|
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={
|
|
37
|
-
{Array.from({ length:
|
|
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;
|
|
@@ -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="
|
|
14
|
-
<script src="
|
|
15
|
-
<script src="
|
|
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="
|
|
13
|
-
<script src="
|
|
14
|
-
<script src="
|
|
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="
|
|
14
|
-
<script src="
|
|
15
|
-
<script src="
|
|
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="
|
|
13
|
-
<script src="
|
|
14
|
-
<script src="
|
|
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="
|
|
15
|
-
<script src="
|
|
16
|
-
<script src="
|
|
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
|
|
24
|
-
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
5
|
-
export function
|
|
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
|
-
|
|
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={() =>
|
|
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>
|
|
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** —
|
|
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
|
|
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>{
|
|
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>
|
|
@@ -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 (
|
|
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[];
|
package/components/data/Tree.jsx
CHANGED
|
@@ -1,23 +1,144 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { cx } from "../_utils/cx.js";
|
|
3
3
|
|
|
4
|
-
function
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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="
|
|
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, "&").replace(/</g, "<")}</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="
|
|
14
|
-
<script src="
|
|
15
|
-
<script src="
|
|
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="
|
|
15
|
-
<script src="
|
|
16
|
-
<script src="
|
|
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
|
|
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
|
-
*
|
|
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
|
|