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