@cyberskill/design 1.0.0 → 1.1.1
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 +10 -9
- package/README.md +31 -28
- package/SKILL.md +13 -9
- package/VERSION +1 -1
- package/_ds_bundle.js +660 -202
- package/_ds_manifest.json +1 -1
- package/_esm/cs.mjs +14 -8
- package/_esm/react.d.ts +216 -0
- package/_esm/react.mjs +114 -0
- package/base/collections.css +31 -0
- package/base/components.css +3 -0
- package/base/data.css +33 -0
- package/base/forms.css +8 -0
- package/base/interaction.css +1 -0
- package/base/typography.css +6 -0
- package/components/_i18n/strings.js +8 -4
- package/components/ai/ai-conversation.card.html +2 -2
- package/components/ai/ai-lumi.card.html +2 -2
- package/components/ai/ai.card.html +2 -2
- package/components/brand/brand.card.html +2 -2
- package/components/button/buttons.card.html +2 -2
- package/components/data/AspectRatio.d.ts +16 -0
- package/components/data/AspectRatio.figma.tsx +12 -0
- package/components/data/AspectRatio.jsx +16 -0
- package/components/data/AspectRatio.prompt.md +7 -0
- package/components/data/Collapsible.d.ts +21 -0
- package/components/data/Collapsible.figma.tsx +12 -0
- package/components/data/Collapsible.jsx +49 -0
- package/components/data/Collapsible.prompt.md +7 -0
- package/components/data/Image.d.ts +4 -0
- package/components/data/Image.prompt.md +2 -2
- package/components/data/Item.d.ts +26 -0
- package/components/data/Item.figma.tsx +12 -0
- package/components/data/Item.jsx +63 -0
- package/components/data/Item.prompt.md +10 -0
- package/components/data/ScrollArea.d.ts +16 -0
- package/components/data/ScrollArea.figma.tsx +12 -0
- package/components/data/ScrollArea.jsx +25 -0
- package/components/data/ScrollArea.prompt.md +7 -0
- package/components/data/collections.card.html +15 -4
- package/components/data/data.card.html +15 -4
- package/components/datatable/datatable.card.html +2 -2
- package/components/dialog/dialog.card.html +2 -2
- package/components/feedback/feedback-2.card.html +2 -2
- package/components/feedback/feedback.card.html +2 -2
- package/components/forms/Cascader.jsx +5 -3
- package/components/forms/Editor.prompt.md +1 -1
- package/components/forms/InputGroup.d.ts +4 -0
- package/components/forms/InputGroup.jsx +38 -8
- package/components/forms/InputGroup.prompt.md +3 -3
- package/components/forms/NativeSelect.d.ts +22 -0
- package/components/forms/NativeSelect.figma.tsx +12 -0
- package/components/forms/NativeSelect.jsx +56 -0
- package/components/forms/NativeSelect.prompt.md +10 -0
- package/components/forms/NumberField.d.ts +5 -0
- package/components/forms/NumberField.jsx +51 -7
- package/components/forms/NumberField.prompt.md +2 -2
- package/components/forms/SegmentedControl.jsx +1 -1
- package/components/forms/TagInput.d.ts +3 -0
- package/components/forms/TagInput.jsx +62 -20
- package/components/forms/TagInput.prompt.md +2 -2
- package/components/forms/forms-2.card.html +2 -2
- package/components/forms/forms.card.html +5 -4
- package/components/icon/Icon.prompt.md +1 -1
- package/components/icon/icon.card.html +2 -2
- package/components/logo/Logo.jsx +2 -1
- package/components/logo/logo.card.html +2 -2
- package/components/navigation/Menu.jsx +14 -1
- package/components/navigation/navigation.card.html +2 -2
- package/components/navigation/shell.card.html +2 -2
- package/components/overlays/AlertDialog.d.ts +29 -0
- package/components/overlays/AlertDialog.figma.tsx +12 -0
- package/components/overlays/AlertDialog.jsx +142 -0
- package/components/overlays/AlertDialog.prompt.md +12 -0
- package/components/overlays/Drawer.jsx +1 -1
- package/components/overlays/Popconfirm.jsx +14 -1
- package/components/overlays/Popover.jsx +14 -1
- package/components/overlays/alertdialog.card.html +42 -0
- package/components/overlays/overlays.card.html +2 -2
- package/components/textfield/textfield.card.html +2 -2
- package/docs/benchmark-rubric.md +46 -0
- package/docs/ci-cd.md +17 -11
- package/docs/consumer-grant.md +37 -0
- package/docs/consuming.md +45 -16
- package/docs/contrast-report.md +91 -103
- package/docs/conventions.md +12 -9
- package/docs/decisions.md +33 -10
- package/docs/deploy.md +1 -1
- package/docs/design-styles.md +26 -8
- package/docs/figma.md +3 -3
- package/docs/live-hub.md +5 -3
- package/docs/products.md +13 -11
- package/docs/quality-gates.md +35 -21
- package/docs/release-notes.md +21 -3
- package/docs/status/assets/favicon.svg +5 -0
- package/docs/status/assets/status-legacy.css +399 -0
- package/docs/status/assets/status-legacy.js +505 -0
- package/docs/status/assets/status.css +644 -0
- package/docs/status/assets/status.js +1308 -0
- package/docs/status/data/status-feed.json +1 -0
- package/docs/status/data/task/TASK-REL-001.js +1 -0
- package/docs/status/data/task/TASK-REL-002.js +1 -0
- package/docs/status/index.html +42 -0
- package/docs/status/roadmap.html +4 -0
- package/docs/status/status-legacy.html +117 -0
- package/docs/storybook.md +5 -4
- package/docs/sync.md +3 -2
- package/docs/tasks/BACKLOG.md +26 -0
- package/docs/tasks/release/TASK-REL-001-launch-1-1-0/spec.md +55 -0
- package/docs/tasks/release/TASK-REL-002-republish-1-1-1/spec.md +54 -0
- package/docs/template-schema-v2.md +15 -3
- package/docs/vi/benchmark-rubric.md +46 -0
- package/docs/vi/ci-cd.md +17 -11
- package/docs/vi/consumer-grant.md +37 -0
- package/docs/vi/consuming.md +45 -16
- package/docs/vi/contrast-report.md +94 -106
- package/docs/vi/conventions.md +12 -9
- package/docs/vi/decisions.md +33 -10
- package/docs/vi/deploy.md +1 -1
- package/docs/vi/design-styles.md +26 -8
- package/docs/vi/figma.md +3 -3
- package/docs/vi/live-hub.md +5 -3
- package/docs/vi/products.md +13 -11
- package/docs/vi/quality-gates.md +35 -21
- package/docs/vi/release-notes.md +26 -8
- package/docs/vi/storybook.md +5 -4
- package/docs/vi/sync.md +3 -2
- package/docs/vi/template-schema-v2.md +15 -3
- package/docs/viewer.html +2 -2
- package/fonts/spacegrotesk-var-latin-ext.woff2 +0 -0
- package/fonts/spacegrotesk-var-latin.woff2 +0 -0
- package/fonts/spacegrotesk-var-vietnamese.woff2 +0 -0
- package/guidelines/atomic-view.html +40 -27
- package/guidelines/elements-geometry.html +69 -0
- package/guidelines/elements-variants.html +17 -17
- package/guidelines/type-families.html +16 -10
- package/llms.txt +17 -11
- package/package.json +38 -16
- package/styles.css +1 -0
- package/templates/ai-cluster-demo.html +29 -14
- package/templates/app-shell/support.js +4 -4
- package/templates/article/content-schema.json +6 -0
- package/templates/article/support.js +4 -4
- package/templates/auth/support.js +4 -4
- package/templates/bod-deck/support.js +4 -4
- package/templates/bod-investor-update/support.js +4 -4
- package/templates/bod-memo/support.js +4 -4
- package/templates/bod-minutes/content-schema.json +12 -0
- package/templates/bod-minutes/support.js +4 -4
- package/templates/bod-report/support.js +4 -4
- package/templates/bod-resolution/support.js +4 -4
- package/templates/culture-event-invite/support.js +4 -4
- package/templates/dashboard/support.js +4 -4
- package/templates/delivery-change-note/support.js +4 -4
- package/templates/delivery-kickoff/support.js +4 -4
- package/templates/delivery-qbr-deck/support.js +4 -4
- package/templates/delivery-runbook/content-schema.json +6 -0
- package/templates/delivery-runbook/support.js +4 -4
- package/templates/delivery-status-email/support.js +4 -4
- package/templates/doc-style-guide/DocStyleGuide.dc.html +2 -2
- package/templates/doc-style-guide/support.js +4 -4
- package/templates/doc-suite-index/support.js +4 -4
- package/templates/doc-templates/DocTemplates.dc.html +1 -1
- package/templates/doc-templates/support.js +4 -4
- package/templates/email/support.js +4 -4
- package/templates/email-safe/README.md +17 -4
- package/templates/email-safe/email-launch.html +3 -3
- package/templates/email-safe/email-newsletter.html +1 -1
- package/templates/finance-dunning-email/support.js +4 -4
- package/templates/finance-expense-report/support.js +4 -4
- package/templates/finance-invoice/support.js +4 -4
- package/templates/finance-quote/support.js +4 -4
- package/templates/hr-announcement/support.js +4 -4
- package/templates/hr-interview-kit/content-schema.json +12 -0
- package/templates/hr-interview-kit/support.js +4 -4
- package/templates/hr-offboarding/content-schema.json +12 -0
- package/templates/hr-offboarding/support.js +4 -4
- package/templates/hr-performance-review/content-schema.json +12 -0
- package/templates/hr-performance-review/support.js +4 -4
- package/templates/hr-pip/content-schema.json +12 -0
- package/templates/hr-pip/support.js +4 -4
- package/templates/legal-msa/content-schema.json +16 -0
- package/templates/legal-msa/support.js +4 -4
- package/templates/legal-sow/support.js +4 -4
- package/templates/marketing-campaign-brief/support.js +4 -4
- package/templates/marketing-case-study/support.js +4 -4
- package/templates/marketing-launch/support.js +4 -4
- package/templates/marketing-newsletter/support.js +4 -4
- package/templates/marketing-page/content-schema.json +0 -1
- package/templates/marketing-page/support.js +4 -4
- package/templates/marketing-press-release/support.js +4 -4
- package/templates/marketing-social-kit/support.js +4 -4
- package/templates/playground.html +8 -4
- package/templates/sales-one-pager/support.js +4 -4
- package/templates/sales-proposal-deck/support.js +4 -4
- package/templates/settings/Settings.dc.html +26 -14
- package/templates/settings/content-schema.json +36 -0
- package/templates/settings/support.js +4 -4
- package/templates/slide-deck/support.js +4 -4
- package/templates/team-meeting-agenda/content-schema.json +16 -0
- package/templates/team-meeting-agenda/support.js +4 -4
- package/templates/tech-incident-report/support.js +4 -4
- package/templates/tech-release-notes/support.js +4 -4
- package/templates/tech-retro/content-schema.json +12 -0
- package/templates/tech-retro/support.js +4 -4
- package/templates/tech-rfc/content-schema.json +6 -0
- package/templates/tech-rfc/support.js +4 -4
- package/templates/vn-appointment-transfer/support.js +4 -4
- package/templates/vn-certificate-of-employment/support.js +4 -4
- package/templates/vn-code-of-conduct/support.js +4 -4
- package/templates/vn-compensation-regulation/support.js +4 -4
- package/templates/vn-contract-amendment/support.js +4 -4
- package/templates/vn-contractor-agreement/support.js +4 -4
- package/templates/vn-data-protection-policy/support.js +4 -4
- package/templates/vn-disciplinary-case-file/support.js +4 -4
- package/templates/vn-disciplinary-schedule/content-schema.json +15 -0
- package/templates/vn-disciplinary-schedule/support.js +4 -4
- package/templates/vn-employee-request/support.js +4 -4
- package/templates/vn-exit-handover/support.js +4 -4
- package/templates/vn-foreign-employee-pack/support.js +4 -4
- package/templates/vn-grassroots-democracy/support.js +4 -4
- package/templates/vn-infosec-policy/support.js +4 -4
- package/templates/vn-internal-labor-regulations/support.js +4 -4
- package/templates/vn-internship-agreement/support.js +4 -4
- package/templates/vn-job-description/support.js +4 -4
- package/templates/vn-labor-contract/support.js +4 -4
- package/templates/vn-labour-management-book/content-schema.json +15 -0
- package/templates/vn-labour-management-book/support.js +4 -4
- package/templates/vn-mutual-nda/support.js +4 -4
- package/templates/vn-ndnca-ip/support.js +4 -4
- package/templates/vn-offer-letter/support.js +4 -4
- package/templates/vn-onboarding-checklist/support.js +4 -4
- package/templates/vn-pdpl-consent/support.js +4 -4
- package/templates/vn-performance-evaluation-regulation/support.js +4 -4
- package/templates/vn-performance-review-form/support.js +4 -4
- package/templates/vn-phantom-stock/support.js +4 -4
- package/templates/vn-probation-contract/support.js +4 -4
- package/templates/vn-receipt-acknowledgement/content-schema.json +15 -0
- package/templates/vn-receipt-acknowledgement/support.js +4 -4
- package/templates/vn-remote-work-policy/support.js +4 -4
- package/templates/vn-resignation-letter/support.js +4 -4
- package/templates/vn-salary-scale/content-schema.json +15 -0
- package/templates/vn-salary-scale/support.js +4 -4
- package/templates/vn-sow-appendix/support.js +4 -4
- package/templates/vn-termination-decision/support.js +4 -4
- package/templates/vn-total-rewards-appendix/support.js +4 -4
- package/templates/vn-training-commitment/support.js +4 -4
- package/templates/vn-travel-expense-policy/support.js +4 -4
- package/tokens/element-seeds.json +112 -0
- package/tokens/elements.css +274 -187
- package/tokens/fonts.css +12 -3
- package/tokens/native/CSTokens.kt +84 -68
- package/tokens/native/CSTokens.swift +84 -68
- package/tokens/native/cs_tokens.dart +84 -68
- package/tokens/provenance.json +9 -9
- package/tokens/styles.css +15 -0
- package/tokens/tokens.dtcg.json +258 -233
- package/tokens/tokens.js +168 -167
- package/tokens/tokens.json +167 -166
- package/tokens/typography.css +9 -1
- package/ui_kits/status-hub/README.md +1 -2
- package/ui_kits/status-hub/index.html +2 -2
- package/ui_kits/status-hub/settings.html +6 -3
- package/ui_kits/website/chat.html +2 -2
- package/ui_kits/website/index.html +2 -2
- package/ui_kits/status-hub/identity-lab.html +0 -134
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
**InputGroup** — input with prefix/suffix addons, clearable ×, password reveal.
|
|
1
|
+
**InputGroup** — input with prefix/suffix addons, clearable ×, password reveal. Pass `label` for a visible field name; bilingual button labels via the registry.
|
|
2
2
|
|
|
3
3
|
```jsx
|
|
4
|
-
<InputGroup prefix="https://" suffix=".world" defaultValue="cyberskill" clearable/>
|
|
5
|
-
<InputGroup password placeholder="Password"/>
|
|
4
|
+
<InputGroup label="Host" prefix="https://" suffix=".world" defaultValue="cyberskill" clearable/>
|
|
5
|
+
<InputGroup label="Password" password placeholder="Password"/>
|
|
6
6
|
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
export interface NativeSelectOption {
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Progressive-enhancement native <select> styled to CS tokens beside Select.
|
|
12
|
+
* Leaner chrome: size · label · error (no description slot).
|
|
13
|
+
*/
|
|
14
|
+
export interface NativeSelectProps extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, "size"> {
|
|
15
|
+
label?: ReactNode;
|
|
16
|
+
error?: ReactNode;
|
|
17
|
+
options?: NativeSelectOption[];
|
|
18
|
+
size?: "sm" | "md";
|
|
19
|
+
children?: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function NativeSelect(props: NativeSelectProps): React.ReactElement;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import figma from '@figma/code-connect'
|
|
2
|
+
import { NativeSelect } from './NativeSelect.jsx'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Code Connect stub — NativeSelect
|
|
6
|
+
* Prop maps stay minimal until the matching Figma library component is published;
|
|
7
|
+
* then set nodeId in code-connect/node-map.json and re-run generate-code-connect.
|
|
8
|
+
*/
|
|
9
|
+
figma.connect(NativeSelect, 'https://www.figma.com/design/CS_FIGMA_FILE_KEY/CyberSkill?node-id=9999-60', {
|
|
10
|
+
example: () => <NativeSelect />,
|
|
11
|
+
imports: ["import { NativeSelect } from '@cyberskill/design'"],
|
|
12
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { cx } from "../_utils/cx.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* CyberSkill NativeSelect — progressive-enhancement native <select> styled to
|
|
6
|
+
* CS tokens beside Select. Leaner field chrome (size + label + error); pass
|
|
7
|
+
* `options` [{value,label}] (preferred) or <option> children.
|
|
8
|
+
*/
|
|
9
|
+
export function NativeSelect({
|
|
10
|
+
id,
|
|
11
|
+
label,
|
|
12
|
+
error,
|
|
13
|
+
options,
|
|
14
|
+
children,
|
|
15
|
+
disabled = false,
|
|
16
|
+
size = "md",
|
|
17
|
+
className,
|
|
18
|
+
value,
|
|
19
|
+
defaultValue,
|
|
20
|
+
onChange,
|
|
21
|
+
...props
|
|
22
|
+
}) {
|
|
23
|
+
const gid = React.useId();
|
|
24
|
+
const sid = id ?? gid;
|
|
25
|
+
const errId = error ? sid + "-err" : undefined;
|
|
26
|
+
return (
|
|
27
|
+
<label className={cx("cs-field", "cs-native-select-field", disabled && "is-disabled", error && "is-invalid", className)} htmlFor={sid}>
|
|
28
|
+
{label ? <span className="cs-field__label">{label}</span> : null}
|
|
29
|
+
<span className={cx("cs-native-select", `cs-native-select--${size}`)}>
|
|
30
|
+
<select
|
|
31
|
+
{...props}
|
|
32
|
+
id={sid}
|
|
33
|
+
disabled={disabled}
|
|
34
|
+
value={value}
|
|
35
|
+
defaultValue={defaultValue}
|
|
36
|
+
onChange={onChange}
|
|
37
|
+
aria-invalid={error ? true : undefined}
|
|
38
|
+
aria-describedby={errId}
|
|
39
|
+
className="cs-field__control"
|
|
40
|
+
>
|
|
41
|
+
{options
|
|
42
|
+
? options.map((o) => (
|
|
43
|
+
<option key={o.value} value={o.value} disabled={o.disabled}>
|
|
44
|
+
{o.label}
|
|
45
|
+
</option>
|
|
46
|
+
))
|
|
47
|
+
: children}
|
|
48
|
+
</select>
|
|
49
|
+
<span className="cs-native-select__chevron" aria-hidden="true">
|
|
50
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M6 9l6 6 6-6" /></svg>
|
|
51
|
+
</span>
|
|
52
|
+
</span>
|
|
53
|
+
{error ? <span id={errId} className="cs-field__error" role="alert">{error}</span> : null}
|
|
54
|
+
</label>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
**NativeSelect** — progressive-enhancement native `<select>` styled to CS tokens beside Select. Supports `size`, label, and inline error.
|
|
2
|
+
|
|
3
|
+
```jsx
|
|
4
|
+
<NativeSelect
|
|
5
|
+
label="Squad"
|
|
6
|
+
size="sm"
|
|
7
|
+
options={[{value:"plat",label:"Platform"},{value:"ai",label:"AI"}]}
|
|
8
|
+
defaultValue="ai"
|
|
9
|
+
/>
|
|
10
|
+
```
|
|
@@ -3,12 +3,17 @@ import type * as React from "react";
|
|
|
3
3
|
/** Numeric stepper with −/+ buttons, keyboard entry, and min/max clamping.
|
|
4
4
|
* Controlled via value/onChange or uncontrolled. */
|
|
5
5
|
export interface NumberFieldProps {
|
|
6
|
+
id?: string;
|
|
7
|
+
/** Visible field label (associates via htmlFor). When omitted, the input uses the bilingual "value" aria-label. */
|
|
8
|
+
label?: string;
|
|
6
9
|
value?: number;
|
|
7
10
|
onChange?: (value: number) => void;
|
|
8
11
|
min?: number;
|
|
9
12
|
max?: number;
|
|
10
13
|
step?: number;
|
|
11
14
|
disabled?: boolean;
|
|
15
|
+
/** "en" | "vi" — else resolved from the nearest [lang] ancestor (vi default). */
|
|
16
|
+
lang?: string;
|
|
12
17
|
className?: string;
|
|
13
18
|
}
|
|
14
19
|
export function NumberField(props: NumberFieldProps): React.ReactElement;
|
|
@@ -4,18 +4,62 @@ import { cx } from "../_utils/cx.js";
|
|
|
4
4
|
|
|
5
5
|
/** CyberSkill NumberField — numeric stepper with −/+ buttons and clamping. */
|
|
6
6
|
// `children` is destructured but never rendered on purpose: keeps stray children out of {...props} → void <input>.
|
|
7
|
-
export function NumberField({
|
|
7
|
+
export function NumberField({
|
|
8
|
+
id,
|
|
9
|
+
label,
|
|
10
|
+
value,
|
|
11
|
+
onChange,
|
|
12
|
+
min,
|
|
13
|
+
max,
|
|
14
|
+
step = 1,
|
|
15
|
+
disabled = false,
|
|
16
|
+
lang,
|
|
17
|
+
className,
|
|
18
|
+
children,
|
|
19
|
+
...props
|
|
20
|
+
}) {
|
|
8
21
|
const [inner, setInner] = React.useState(0);
|
|
9
22
|
const val = value != null ? value : inner;
|
|
10
|
-
const clamp = (n) => {
|
|
11
|
-
|
|
23
|
+
const clamp = (n) => {
|
|
24
|
+
if (min != null) n = Math.max(min, n);
|
|
25
|
+
if (max != null) n = Math.min(max, n);
|
|
26
|
+
return n;
|
|
27
|
+
};
|
|
28
|
+
const set = (n) => {
|
|
29
|
+
const c = clamp(n);
|
|
30
|
+
onChange ? onChange(c) : setInner(c);
|
|
31
|
+
};
|
|
12
32
|
const [ref, L] = useLang(lang);
|
|
13
33
|
const t = makeT("NumberField", L);
|
|
34
|
+
const gid = React.useId();
|
|
35
|
+
const sid = id ?? gid;
|
|
14
36
|
return (
|
|
15
|
-
<div ref={ref} className={cx("cs-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
37
|
+
<div ref={ref} className={cx("cs-field", disabled && "is-disabled", className)}>
|
|
38
|
+
{label ? (
|
|
39
|
+
<label className="cs-field__label" htmlFor={sid}>
|
|
40
|
+
{label}
|
|
41
|
+
</label>
|
|
42
|
+
) : null}
|
|
43
|
+
<div className="cs-stepper">
|
|
44
|
+
<button type="button" aria-label={t("decrease")} disabled={disabled || (min != null && val <= min)} onClick={() => set(val - step)}>
|
|
45
|
+
−
|
|
46
|
+
</button>
|
|
47
|
+
<input
|
|
48
|
+
{...props}
|
|
49
|
+
id={sid}
|
|
50
|
+
type="number"
|
|
51
|
+
value={val}
|
|
52
|
+
min={min}
|
|
53
|
+
max={max}
|
|
54
|
+
step={step}
|
|
55
|
+
disabled={disabled}
|
|
56
|
+
aria-label={label ? undefined : t("value")}
|
|
57
|
+
onChange={(e) => set(Number(e.target.value))}
|
|
58
|
+
/>
|
|
59
|
+
<button type="button" aria-label={t("increase")} disabled={disabled || (max != null && val >= max)} onClick={() => set(val + step)}>
|
|
60
|
+
+
|
|
61
|
+
</button>
|
|
62
|
+
</div>
|
|
19
63
|
</div>
|
|
20
64
|
);
|
|
21
65
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
**NumberField** — numeric stepper with −/+ buttons and min/max clamping.
|
|
1
|
+
**NumberField** — numeric stepper with −/+ buttons and min/max clamping. Pass `label` for a visible field name; bilingual decrease/increase/value labels via the registry.
|
|
2
2
|
|
|
3
3
|
```jsx
|
|
4
|
-
<NumberField value={seats} onChange={setSeats} min={1} max={20} />
|
|
4
|
+
<NumberField label="Seats" value={seats} onChange={setSeats} min={1} max={20} />
|
|
5
5
|
```
|
|
@@ -19,7 +19,7 @@ export function SegmentedControl({ options = [], value, onChange, className, ...
|
|
|
19
19
|
return (
|
|
20
20
|
<div role="tablist" className={cx("cs-segmented", className)} {...props}>
|
|
21
21
|
{options.map((o, i) => (
|
|
22
|
-
<button key={o.value} type="button" role="tab" aria-selected={value === o.value}
|
|
22
|
+
<button key={o.value} type="button" role="tab" aria-selected={value === o.value}
|
|
23
23
|
tabIndex={i === idx ? 0 : -1} ref={(el) => (refs.current[i] = el)} onKeyDown={(e) => key(e, i)}
|
|
24
24
|
onClick={() => onChange && onChange(o.value)}>
|
|
25
25
|
{o.icon ? <span aria-hidden="true">{o.icon}</span> : null}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/** Multi-value token input: Enter/comma adds a tag, Backspace removes the last,
|
|
2
2
|
* blur commits, duplicates ignored. Controlled (value/onChange) or uncontrolled. */
|
|
3
3
|
export interface TagInputProps {
|
|
4
|
+
id?: string;
|
|
5
|
+
/** Visible field label (associates via htmlFor). When omitted, the input uses the placeholder as aria-label. */
|
|
6
|
+
label?: string;
|
|
4
7
|
value?: string[];
|
|
5
8
|
defaultValue?: string[];
|
|
6
9
|
onChange?: (tags: string[]) => void;
|
|
@@ -3,37 +3,79 @@ import { makeT, useLang } from "../_i18n/i18n.js";
|
|
|
3
3
|
import { cx } from "../_utils/cx.js";
|
|
4
4
|
|
|
5
5
|
/** CyberSkill TagInput — multi-value token input. Enter/comma adds, Backspace removes last, blur commits. */
|
|
6
|
-
export function TagInput({
|
|
6
|
+
export function TagInput({
|
|
7
|
+
id,
|
|
8
|
+
label,
|
|
9
|
+
value,
|
|
10
|
+
defaultValue = [],
|
|
11
|
+
onChange,
|
|
12
|
+
placeholder,
|
|
13
|
+
max,
|
|
14
|
+
disabled = false,
|
|
15
|
+
lang,
|
|
16
|
+
className,
|
|
17
|
+
}) {
|
|
7
18
|
const [inner, setInner] = React.useState(defaultValue);
|
|
8
19
|
const tags = value != null ? value : inner;
|
|
9
20
|
const [q, setQ] = React.useState("");
|
|
10
|
-
const set = (arr) => {
|
|
21
|
+
const set = (arr) => {
|
|
22
|
+
if (value == null) setInner(arr);
|
|
23
|
+
onChange && onChange(arr);
|
|
24
|
+
};
|
|
11
25
|
const add = (s) => {
|
|
12
26
|
s = s.trim();
|
|
13
27
|
if (!s) return;
|
|
14
|
-
if (tags.includes(s)) {
|
|
28
|
+
if (tags.includes(s)) {
|
|
29
|
+
setQ("");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
15
32
|
if (max != null && tags.length >= max) return;
|
|
16
|
-
set([...tags, s]);
|
|
33
|
+
set([...tags, s]);
|
|
34
|
+
setQ("");
|
|
17
35
|
};
|
|
18
36
|
const [ref, L] = useLang(lang);
|
|
19
37
|
const t = makeT("TagInput", L);
|
|
20
38
|
const ph = placeholder != null ? placeholder : t("placeholder");
|
|
39
|
+
const gid = React.useId();
|
|
40
|
+
const sid = id ?? gid;
|
|
21
41
|
return (
|
|
22
|
-
<
|
|
23
|
-
{
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
<label ref={ref} className={cx("cs-field", disabled && "is-disabled", className)} htmlFor={sid}>
|
|
43
|
+
{label ? <span className="cs-field__label">{label}</span> : null}
|
|
44
|
+
<div className="cs-taginput">
|
|
45
|
+
{tags.map((tag) => (
|
|
46
|
+
<span key={tag} className="cs-tag">
|
|
47
|
+
{tag}
|
|
48
|
+
<button
|
|
49
|
+
type="button"
|
|
50
|
+
className="cs-tag__close"
|
|
51
|
+
aria-label={t("remove") + " " + tag}
|
|
52
|
+
onClick={() => set(tags.filter((x) => x !== tag))}
|
|
53
|
+
disabled={disabled}
|
|
54
|
+
>
|
|
55
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" aria-hidden="true">
|
|
56
|
+
<path d="M6 6l12 12M18 6L6 18" />
|
|
57
|
+
</svg>
|
|
58
|
+
</button>
|
|
59
|
+
</span>
|
|
60
|
+
))}
|
|
61
|
+
<input
|
|
62
|
+
id={sid}
|
|
63
|
+
value={q}
|
|
64
|
+
placeholder={tags.length ? "" : ph}
|
|
65
|
+
disabled={disabled}
|
|
66
|
+
aria-label={label ? undefined : ph}
|
|
67
|
+
onChange={(e) => setQ(e.target.value)}
|
|
68
|
+
onKeyDown={(e) => {
|
|
69
|
+
if (e.key === "Enter" || e.key === ",") {
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
add(q);
|
|
72
|
+
} else if (e.key === "Backspace" && !q && tags.length) {
|
|
73
|
+
set(tags.slice(0, -1));
|
|
74
|
+
}
|
|
75
|
+
}}
|
|
76
|
+
onBlur={() => add(q)}
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
</label>
|
|
38
80
|
);
|
|
39
81
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
**TagInput** — multi-value tokens (Enter/comma adds · Backspace removes · blur commits).
|
|
1
|
+
**TagInput** — multi-value tokens (Enter/comma adds · Backspace removes · blur commits). Pass `label` for a visible field name; bilingual placeholder + remove labels via the registry.
|
|
2
2
|
|
|
3
3
|
```jsx
|
|
4
|
-
<TagInput defaultValue={["Web apps","Bilingual"]} onChange={setTags} max={8}/>
|
|
4
|
+
<TagInput label="Tags" defaultValue={["Web apps","Bilingual"]} onChange={setTags} max={8}/>
|
|
5
5
|
```
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
.row { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
|
|
11
11
|
.lbl { width: 100%; font: 600 11px/1 var(--cs-font-family-ui); text-transform: uppercase; letter-spacing: .09em; color: var(--cs-color-text-muted); }
|
|
12
12
|
</style>
|
|
13
|
-
<script src="https://unpkg.com/react@
|
|
14
|
-
<script src="https://unpkg.com/react
|
|
13
|
+
<script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
|
|
14
|
+
<script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
|
|
15
15
|
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
16
16
|
<script src="../../_ds_bundle.js"></script>
|
|
17
17
|
</head>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- @dsCard group="Components" viewport="700x360" name="Form controls" subtitle="Select, Checkbox, Radio, Switch, Textarea — brand accent" -->
|
|
1
|
+
<!-- @dsCard group="Components" viewport="700x360" name="Form controls" subtitle="Select, NativeSelect, Checkbox, Radio, Switch, Textarea — brand accent" -->
|
|
2
2
|
<!DOCTYPE html>
|
|
3
3
|
<html lang="en">
|
|
4
4
|
<head>
|
|
@@ -9,21 +9,22 @@
|
|
|
9
9
|
body { margin: 0; background: var(--cs-color-surface-page); padding: 22px 24px; }
|
|
10
10
|
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 22px 28px; max-width: 640px; align-items: start; }
|
|
11
11
|
</style>
|
|
12
|
-
<script src="https://unpkg.com/react@
|
|
13
|
-
<script src="https://unpkg.com/react
|
|
12
|
+
<script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
|
|
13
|
+
<script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
|
|
14
14
|
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
15
15
|
<script src="../../_ds_bundle.js"></script>
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
18
18
|
<div id="root"></div>
|
|
19
19
|
<script type="text/babel">
|
|
20
|
-
const { Select, Checkbox, RadioGroup, Switch, Textarea } = window[Object.keys(window).find(k=>/^CyberSkillDesignSystem_[0-9a-f]{6}$/.test(k))] || {};
|
|
20
|
+
const { Select, NativeSelect, Checkbox, RadioGroup, Switch, Textarea } = window[Object.keys(window).find(k=>/^CyberSkillDesignSystem_[0-9a-f]{6}$/.test(k))] || {};
|
|
21
21
|
function Demo() {
|
|
22
22
|
const [plan, setPlan] = React.useState("yr");
|
|
23
23
|
const [dark, setDark] = React.useState(true);
|
|
24
24
|
return (
|
|
25
25
|
<div className="grid">
|
|
26
26
|
<Select label="Squad" options={[{value:"plat",label:"Platform"},{value:"ai",label:"AI"},{value:"growth",label:"Growth"}]} defaultValue="ai" />
|
|
27
|
+
<NativeSelect label="Interface" size="sm" options={[{value:"en",label:"English"},{value:"vi",label:"Tiếng Việt"}]} defaultValue="en" />
|
|
27
28
|
<RadioGroup legend="Billing" value={plan} onChange={setPlan} options={[{value:"mo",label:"Monthly"},{value:"yr",label:"Annual",description:"Two months free"}]} />
|
|
28
29
|
<div style={{display:"grid",gap:12}}>
|
|
29
30
|
<Checkbox label="Email me release notes" defaultChecked />
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
<Icon name="sparkle" size="lg" label="Wish" /> {/* meaningful */}
|
|
6
6
|
```
|
|
7
7
|
|
|
8
|
-
Set: `close · sun · moon · arrow-right · check · sparkle · chat · sound-on · sound-off` + v2.0 extension `search · sliders · upload · download · calendar · user · plus · trash · external · menu` + v2.13 `chevron-down/up/left/right · edit · copy · info · alert-triangle`
|
|
8
|
+
Set: `close · sun · moon · arrow-right · check · sparkle · chat · sound-on · sound-off` + v2.0 extension `search · sliders · upload · download · calendar · user · plus · trash · external · menu` + v2.13 `chevron-down/up/left/right · edit · copy · info · alert-triangle` (same grammar). `sparkle` is the brand's "wish" glyph. Colour follows the surrounding text token — set `color` on a parent to recolour.
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
.cell .g { color: var(--cs-color-brand-umber); }
|
|
14
14
|
.cell:nth-child(6) .g { color: var(--cs-color-brand-ochre); }
|
|
15
15
|
</style>
|
|
16
|
-
<script src="https://unpkg.com/react@
|
|
17
|
-
<script src="https://unpkg.com/react
|
|
16
|
+
<script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
|
|
17
|
+
<script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
|
|
18
18
|
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
19
19
|
<script src="../../_ds_bundle.js"></script>
|
|
20
20
|
</head>
|
package/components/logo/Logo.jsx
CHANGED
|
@@ -8,6 +8,7 @@ import { cx } from "../_utils/cx.js";
|
|
|
8
8
|
* Do not recreate or recolour the mark.
|
|
9
9
|
*/
|
|
10
10
|
export function Logo({ size = 32, title = "CyberSkill", decorative = false, className, ...props }) {
|
|
11
|
+
const safeTitle = String(title).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
11
12
|
return (
|
|
12
13
|
<svg
|
|
13
14
|
{...props}
|
|
@@ -19,7 +20,7 @@ export function Logo({ size = 32, title = "CyberSkill", decorative = false, clas
|
|
|
19
20
|
role={decorative ? undefined : "img"}
|
|
20
21
|
aria-hidden={decorative ? true : undefined}
|
|
21
22
|
aria-label={decorative ? undefined : title}
|
|
22
|
-
dangerouslySetInnerHTML={{ __html: (decorative ? "" : `<title>${
|
|
23
|
+
dangerouslySetInnerHTML={{ __html: (decorative ? "" : `<title>${safeTitle}</title>`) + CS_LOGO_MARK_INNER }}
|
|
23
24
|
/>
|
|
24
25
|
);
|
|
25
26
|
}
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
.lockup b { font: 800 22px/1 var(--cs-font-family-ui); color: var(--cs-color-brand-umber); letter-spacing: -.01em; }
|
|
16
16
|
.cap { font: 500 12px/1.4 var(--cs-font-family-ui); color: var(--cs-color-text-muted); }
|
|
17
17
|
</style>
|
|
18
|
-
<script src="https://unpkg.com/react@
|
|
19
|
-
<script src="https://unpkg.com/react
|
|
18
|
+
<script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
|
|
19
|
+
<script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
|
|
20
20
|
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
21
21
|
<script src="../../_ds_bundle.js"></script>
|
|
22
22
|
</head>
|
|
@@ -15,9 +15,22 @@ export function Menu({ trigger, children, align = "start", open: controlledOpen,
|
|
|
15
15
|
document.addEventListener("keydown", onKey);
|
|
16
16
|
return () => { document.removeEventListener("mousedown", onDoc); document.removeEventListener("keydown", onKey); };
|
|
17
17
|
}, [open]);
|
|
18
|
+
const toggle = () => set(!open);
|
|
19
|
+
// ARIA attrs must live on the interactive trigger (button), not a wrapping <span>
|
|
20
|
+
// — axe aria-allowed-attr flags aria-haspopup/aria-expanded on generic elements.
|
|
21
|
+
const triggerNode = React.isValidElement(trigger)
|
|
22
|
+
? React.cloneElement(trigger, {
|
|
23
|
+
"aria-haspopup": "menu",
|
|
24
|
+
"aria-expanded": open,
|
|
25
|
+
onClick: (e) => {
|
|
26
|
+
if (typeof trigger.props.onClick === "function") trigger.props.onClick(e);
|
|
27
|
+
if (!e.defaultPrevented) toggle();
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
: <button type="button" aria-haspopup="menu" aria-expanded={open} onClick={toggle}>{trigger}</button>;
|
|
18
31
|
return (
|
|
19
32
|
<div className={cx("cs-menu", className)} ref={ref}>
|
|
20
|
-
|
|
33
|
+
{triggerNode}
|
|
21
34
|
{open ? (
|
|
22
35
|
<div className={cx("cs-menu__list", align === "end" && "cs-menu__list--end")} role="menu">{children}</div>
|
|
23
36
|
) : null}
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
.lbl { font: 600 11px/1 var(--cs-font-family-ui); text-transform: uppercase; letter-spacing: .09em; color: var(--cs-color-text-muted); margin-bottom: 10px; }
|
|
12
12
|
.row { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
|
|
13
13
|
</style>
|
|
14
|
-
<script src="https://unpkg.com/react@
|
|
15
|
-
<script src="https://unpkg.com/react
|
|
14
|
+
<script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
|
|
15
|
+
<script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
|
|
16
16
|
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
17
17
|
<script src="../../_ds_bundle.js"></script>
|
|
18
18
|
</head>
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
.frame .cs-cmdk-scrim { position: absolute; padding-top: 14px; }
|
|
14
14
|
.frame .cs-cmdk { inline-size: 100%; box-shadow: none; }
|
|
15
15
|
</style>
|
|
16
|
-
<script src="https://unpkg.com/react@
|
|
17
|
-
<script src="https://unpkg.com/react
|
|
16
|
+
<script src="https://unpkg.com/umd-react@19.2.8/dist/react.development.js" integrity="sha384-r22tQd8qRIHDPIkmdXZcVtvPi1Tj2x1QaW2tmFQHEvHscATUnHQ5siTyxWw5PMUs" crossorigin="anonymous"></script>
|
|
17
|
+
<script src="https://unpkg.com/umd-react@19.2.8/dist/react-dom.development.js" integrity="sha384-gJZYmumEmwqVmX3JVsLZq+4QrxoPGh/BW47Rk7SqNPCPFpTGnRtvmeRPJ7//ZDPk" crossorigin="anonymous"></script>
|
|
18
18
|
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
|
19
19
|
<script src="../../_ds_bundle.js"></script>
|
|
20
20
|
</head>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* First-class confirm / destructive modal — role="alertdialog", focus trap + restore.
|
|
5
|
+
* Distinct from Popconfirm (inline bubble) and Dialog (general modal).
|
|
6
|
+
*/
|
|
7
|
+
export interface AlertDialogProps {
|
|
8
|
+
open?: boolean;
|
|
9
|
+
defaultOpen?: boolean;
|
|
10
|
+
onOpenChange?: (open: boolean) => void;
|
|
11
|
+
title: ReactNode;
|
|
12
|
+
/** Prefer over children for the described body. */
|
|
13
|
+
description?: ReactNode;
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
/** Defaults from the registry ("Confirm" / "Xác nhận"). */
|
|
16
|
+
confirmLabel?: string;
|
|
17
|
+
/** Defaults from the registry ("Cancel" / "Hủy"). */
|
|
18
|
+
cancelLabel?: string;
|
|
19
|
+
/** `destructive` styles the confirm action as danger. Alias: `variant`. */
|
|
20
|
+
tone?: "default" | "destructive";
|
|
21
|
+
variant?: "default" | "destructive";
|
|
22
|
+
onConfirm?: () => void;
|
|
23
|
+
onCancel?: () => void;
|
|
24
|
+
/** "en" | "vi" — else resolved from the nearest [lang] ancestor (vi default). */
|
|
25
|
+
lang?: string;
|
|
26
|
+
className?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function AlertDialog(props: AlertDialogProps): React.ReactElement | null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import figma from '@figma/code-connect'
|
|
2
|
+
import { AlertDialog } from './AlertDialog.jsx'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Code Connect stub — AlertDialog
|
|
6
|
+
* Prop maps stay minimal until the matching Figma library component is published;
|
|
7
|
+
* then set nodeId in code-connect/node-map.json and re-run generate-code-connect.
|
|
8
|
+
*/
|
|
9
|
+
figma.connect(AlertDialog, 'https://www.figma.com/design/CS_FIGMA_FILE_KEY/CyberSkill?node-id=9999-4', {
|
|
10
|
+
example: () => <AlertDialog />,
|
|
11
|
+
imports: ["import { AlertDialog } from '@cyberskill/design'"],
|
|
12
|
+
})
|