@cyberskill/design 1.7.0 → 1.7.2
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 +1 -1
- package/README.md +4 -4
- package/SKILL.md +3 -3
- package/VERSION +1 -1
- package/_ds_bundle.js +2 -2
- package/_esm/cs.mjs +2 -2
- package/docs/contrast-report.md +1 -1
- package/docs/conventions.md +2 -2
- package/docs/quality-gates.md +1 -1
- package/docs/release-notes.md +1 -1
- package/docs/vi/contrast-report.md +1 -1
- package/docs/vi/conventions.md +2 -2
- package/docs/vi/quality-gates.md +1 -1
- package/docs/vi/release-notes.md +1 -1
- package/llms.txt +3 -3
- package/package.json +1 -1
- package/templates/_vendor/doc-export.js +354 -72
- package/tokens/element-seeds.json +1 -1
- package/tokens/native/CSTokens.kt +1 -1
- package/tokens/native/CSTokens.swift +1 -1
- package/tokens/native/cs_tokens.dart +1 -1
- package/tokens/provenance.json +6 -6
- package/tokens/tokens.dtcg.json +1 -1
- package/tokens/tokens.js +2 -2
- package/tokens/tokens.json +1 -1
package/DESIGN.md
CHANGED
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## Start here
|
|
8
8
|
|
|
9
|
-
This is the **entrance document** for the CyberSkill Design System — VERSION **1.7.
|
|
9
|
+
This is the **entrance document** for the CyberSkill Design System — VERSION **1.7.2** (see `VERSION`). The **product site** is Storybook at **`/`** on `design.cyberskill.world` (host-only; local: `npm run storybook`). Operator documentation is published in the Storybook **Docs** sidebar (and the Documentation Library at `/docs/viewer.html`). Legacy `/dashboard`, `/dashboard.html`, and `/playground/*` redirect to `/`. One sentence: a warm, Vietnamese-first, enterprise-grade system where every surface resolves four independent axes — **Theme** (light · dark · system) × **Element** (Ngũ Hành product identity: Kim · Mộc · Thủy · Hỏa · Thổ, 15 variants) × **Language** (EN · VI) × **Style** (`data-cs-style` — sole pack **liquid-glass**; absent ≡ default).
|
|
10
10
|
|
|
11
11
|
**Quick start by audience**
|
|
12
12
|
- **Designers** — open Storybook (**Foundations / Components / Templates / Pages / Docs**). **Templates** lists all 85 starting points (Gallery → Atomic View, plus category stories including the 38-document VN A4 suite (Employment Suite + commercial framework) under **Templates → HR**). Flip Theme × Element × Language × Style live via the Storybook toolbar, Atomic View, and the Elements Geometry specimen.
|
|
@@ -15,7 +15,7 @@ This is the **entrance document** for the CyberSkill Design System — VERSION *
|
|
|
15
15
|
|
|
16
16
|
- **Static / open-spec** (e.g. Google Stitch) — start at **`DESIGN.md`** (generated open-spec) → `llms.txt` → `tokens/tokens.dtcg.json`. Build **static** UI with `styles.css` + `.cs-*` / kitchen-sink / `examples/static-hello/`. **Do not** treat `templates/**/*.dc.html` as source of truth.
|
|
17
17
|
|
|
18
|
-
- **Implementers** — npm package **`@cyberskill/design@1.7.
|
|
18
|
+
- **Implementers** — npm package **`@cyberskill/design@1.7.2`** (see `docs/consuming.md`; grant in `docs/consumer-grant.md` — still UNLICENSED). **Next/SSR:** `import { Button } from "@cyberskill/design"` (peer React). **Browser demo:** **`examples/npm-hello/`** (Lumi · Hỏa · plasma, legacy `_esm/cs.mjs`). Or link **`styles.css`** from a clone/subtree (one file = everything), or copy a `templates/<slug>/` folder and edit one line in its `ds-base.js` (one-line rebind, validated end-to-end Jul 2026). Scope identity with `data-theme` · `data-cs-element` (+`data-cs-variant`) · `lang`. Release signal: tip SHA + `docs/release-notes.md` (VERSION is **1.7.2**; no CHANGELOG).
|
|
19
19
|
|
|
20
20
|
- **Maintainers** — `docs/doctrine.md` (expansion + verification), then `CONTRIBUTING.md` and `docs/quality-gates.md`.
|
|
21
21
|
|
|
@@ -170,7 +170,7 @@ Copied assets live in `assets/`: `logo-mark.svg` / `logo-mark.png` (official mas
|
|
|
170
170
|
|
|
171
171
|
Highlights: **Button** — Umber primary; variants primary/secondary/tertiary/ghost/danger/danger-ghost; sizes xs–lg; loading, icon, fullWidth. **TextField / Textarea / Select / NativeSelect** share one `.cs-field` frame (label + description/error; diacritic/IME-safe). **DataTable** — caption, scoped headers, per-column render, idle/loading/error/empty triad. **Card** — warm panel + header/body/footer. **Logo** renders the exact official mark; **Icon** drives the in-repo line-icon set. The **AI-native** family carries the brand's explainability doctrine — disclosure, human review, wish capture, and confidence, all stated in words (never colour alone).
|
|
172
172
|
|
|
173
|
-
**Install / package name.** This monolith publishes as **`@cyberskill/design`** (live at **1.7.
|
|
173
|
+
**Install / package name.** This monolith publishes as **`@cyberskill/design`** (live at **1.7.2**; grant in `docs/consumer-grant.md` governs *use* — package remains UNLICENSED). Do **not** install `@cyberskill/react` for this tree — that name is historical marketing-site inventory, not this package.
|
|
174
174
|
|
|
175
175
|
**Source inventory vs. extensions.** An earlier CyberSkill surface shipped six primitives — `Button`, `TextField`, `Dialog`, `DataTable`, `AIDisclosureBadge`, `HumanReviewGate` — plus a brand `Logo`. Everything else in **this** package is an **intentional extension** built in the brand's own token vocabulary so consumers have a complete working kit: `Icon` (the marketing site's real in-repo line-icon set), the standard Forms / Feedback / Data / Navigation / Overlays primitives (search, stepper, slider, file upload, list, description list, timeline, accordion, kbd, code block, sidebar, steps, command palette, popover, drawer, and more), added AI-native pieces (`PromptInput`, `ChatMessage`, `ConfidenceMeter`, `PromptSuggestions`, `TypingIndicator`, `CitationList`) that formalise the Lumi wish-flow, and the `LumiAvatar` mascot. None invent new visual language — they reuse the anchors, surfaces, type, and motion already defined.
|
|
176
176
|
|
|
@@ -283,7 +283,7 @@ Every template resolves to one of six archetypes, framed by `templates/doc-templ
|
|
|
283
283
|
## Index / manifest
|
|
284
284
|
|
|
285
285
|
```
|
|
286
|
-
styles.css ← single entry point (@import manifest only) · VERSION 1.7.
|
|
286
|
+
styles.css ← single entry point (@import manifest only) · VERSION 1.7.2
|
|
287
287
|
tokens/ fonts · colors · typography · spacing · elevation · motion · component-tokens · elements (Ngũ Hành packs)
|
|
288
288
|
base/ reset · typography · components · forms · feedback · data · navigation · ai · controls · collections · shell · glass · interaction · a11y · responsive
|
|
289
289
|
components/ button · textfield · dialog · datatable · forms · feedback · data · navigation · overlays · ai · logo · icon · brand
|
package/SKILL.md
CHANGED
|
@@ -17,7 +17,7 @@ If the user invokes this skill without any other guidance, ask them what they wa
|
|
|
17
17
|
| **Bundler React (Next/Vite/SSR)** | `docs/consuming.md` | `import { Button } from "@cyberskill/design"` + `styles.css`. React is a peer. |
|
|
18
18
|
| **Maintainers** | `docs/doctrine.md` | Expansion + verification; Storybook Docs at `design.cyberskill.world`. |
|
|
19
19
|
|
|
20
|
-
Dual-path detail: `docs/consuming.md`. Release signal: tip SHA + `docs/release-notes.md` (VERSION is **1.7.
|
|
20
|
+
Dual-path detail: `docs/consuming.md`. Release signal: tip SHA + `docs/release-notes.md` (VERSION is **1.7.2**; no CHANGELOG).
|
|
21
21
|
|
|
22
22
|
- **`README.md`** — the entrance + design guide + manifest: anchor immutables, CONTENT FUNDAMENTALS (voice = warm/direct/honest/respectful, Vietnamese-first, the "wish" metaphor), VISUAL FOUNDATIONS, ICONOGRAPHY, and the component/kit index. Read it first.
|
|
23
23
|
|
|
@@ -43,7 +43,7 @@ Dual-path detail: `docs/consuming.md`. Release signal: tip SHA + `docs/release-n
|
|
|
43
43
|
|
|
44
44
|
## Exporting
|
|
45
45
|
|
|
46
|
-
Every artifact exports, all paths preserving Vietnamese Unicode (see `docs/conventions.md` → Export paths). Decks → **editable PPTX** (`gen_pptx`, force VN per slide via `__dcSetProps`); documents (any with `@page{size}` / `omelette-owns-print`) → **PDF + editable DOCX** from one **Tải / Download** menu (`templates/_vendor/doc-export.js`, live `.cs-sheet`, no CDN; CI PDF via Playwright); emails / product pages / any DC → **standalone offline HTML** (make a same-folder `*-standalone.html` copy with static `<link>`/`<script>` resource tags, then `super_inline_html`). Contribution/expansion process is **`docs/doctrine.md`** + the decision log in `docs/conventions.md`; deep-verification harnesses live in `_audit/` (see `_audit/README.md`).
|
|
46
|
+
Every artifact exports, all paths preserving Vietnamese Unicode (see `docs/conventions.md` → Export paths). Decks → **editable PPTX** (`gen_pptx`, force VN per slide via `__dcSetProps`); documents (any with `@page{size}` / `omelette-owns-print`) → **PDF + editable DOCX** from one **Tải / Download** menu (`templates/_vendor/doc-export.js`, live `.cs-sheet`, Flate PDF + OOXML walk, no CDN; CI PDF via Playwright); emails / product pages / any DC → **standalone offline HTML** (make a same-folder `*-standalone.html` copy with static `<link>`/`<script>` resource tags, then `super_inline_html`). Contribution/expansion process is **`docs/doctrine.md`** + the decision log in `docs/conventions.md`; deep-verification harnesses live in `_audit/` (see `_audit/README.md`).
|
|
47
47
|
|
|
48
48
|
## Hard rules
|
|
49
49
|
|
|
@@ -63,7 +63,7 @@ Every artifact exports, all paths preserving Vietnamese Unicode (see `docs/conve
|
|
|
63
63
|
|
|
64
64
|
- Voice stays warm/direct/honest/respectful — never fun/playful/edgy. Products are "wishes" that Lumi helps grant.
|
|
65
65
|
|
|
66
|
-
- Expansion rule: when any set grows (element/variant, icon, component, language), update every deliverable in the same change — tokens, cards + related guidelines, contract trio, all template enums, Storybook toolbar / Atomic View, docs incl. every related document/README — and grep the old list to prove it. Full text: `docs/doctrine.md`. VERSION **1.7.
|
|
66
|
+
- Expansion rule: when any set grows (element/variant, icon, component, language), update every deliverable in the same change — tokens, cards + related guidelines, contract trio, all template enums, Storybook toolbar / Atomic View, docs incl. every related document/README — and grep the old list to prove it. Full text: `docs/doctrine.md`. VERSION **1.7.2** (auto-bumps on `main`; owner may still force a bump; no changelog).
|
|
67
67
|
|
|
68
68
|
- **Stitch / non-DC tools must not consume `*.dc.html` as source of truth.** Those files need the Design Components compiler (tweaks, `x-import`, `__dcSetProps`). Generate static UI from `DESIGN.md` / DTCG / `styles.css` + `.cs-*` / kitchen-sink / `examples/static-hello/` instead. DC authoring requires a compiler session (Claude Design, or a full clone with the compiler).
|
|
69
69
|
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.7.
|
|
1
|
+
1.7.2
|
package/_ds_bundle.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* @ds-bundle: {"format":4,"namespace":"CyberSkillDesignSystem_847b3c","components":[{"name":"AIDisclosureBadge","sourcePath":"components/ai/AIDisclosureBadge.jsx"},{"name":"ChatMessage","sourcePath":"components/ai/ChatMessage.jsx"},{"name":"CitationList","sourcePath":"components/ai/CitationList.jsx"},{"name":"ConfidenceMeter","sourcePath":"components/ai/ConfidenceMeter.jsx"},{"name":"HumanReviewGate","sourcePath":"components/ai/HumanReviewGate.jsx"},{"name":"PromptInput","sourcePath":"components/ai/PromptInput.jsx"},{"name":"PromptSuggestions","sourcePath":"components/ai/PromptSuggestions.jsx"},{"name":"TypingIndicator","sourcePath":"components/ai/TypingIndicator.jsx"},{"name":"LumiAvatar","sourcePath":"components/brand/LumiAvatar.jsx"},{"name":"Button","sourcePath":"components/button/Button.jsx"},{"name":"ButtonGroup","sourcePath":"components/button/ButtonGroup.jsx"},{"name":"FloatingActionButton","sourcePath":"components/button/FloatingActionButton.jsx"},{"name":"Accordion","sourcePath":"components/data/Accordion.jsx"},{"name":"AspectRatio","sourcePath":"components/data/AspectRatio.jsx"},{"name":"Avatar","sourcePath":"components/data/Avatar.jsx"},{"name":"AvatarGroup","sourcePath":"components/data/Avatar.jsx"},{"name":"Card","sourcePath":"components/data/Card.jsx"},{"name":"CardHeader","sourcePath":"components/data/Card.jsx"},{"name":"CardBody","sourcePath":"components/data/Card.jsx"},{"name":"CardFooter","sourcePath":"components/data/Card.jsx"},{"name":"Carousel","sourcePath":"components/data/Carousel.jsx"},{"name":"Chart","sourcePath":"components/data/Chart.jsx"},{"name":"CodeBlock","sourcePath":"components/data/CodeBlock.jsx"},{"name":"Collapsible","sourcePath":"components/data/Collapsible.jsx"},{"name":"Comment","sourcePath":"components/data/Comment.jsx"},{"name":"DescriptionList","sourcePath":"components/data/DescriptionList.jsx"},{"name":"Divider","sourcePath":"components/data/Divider.jsx"},{"name":"Image","sourcePath":"components/data/Image.jsx"},{"name":"Item","sourcePath":"components/data/Item.jsx"},{"name":"Kbd","sourcePath":"components/data/Kbd.jsx"},{"name":"List","sourcePath":"components/data/List.jsx"},{"name":"ListItem","sourcePath":"components/data/List.jsx"},{"name":"Masonry","sourcePath":"components/data/Masonry.jsx"},{"name":"QRCode","sourcePath":"components/data/QRCode.jsx"},{"name":"ScrollArea","sourcePath":"components/data/ScrollArea.jsx"},{"name":"Sortable","sourcePath":"components/data/Sortable.jsx"},{"name":"Splitter","sourcePath":"components/data/Splitter.jsx"},{"name":"Stat","sourcePath":"components/data/Stat.jsx"},{"name":"Terminal","sourcePath":"components/data/Terminal.jsx"},{"name":"Timeline","sourcePath":"components/data/Timeline.jsx"},{"name":"Tooltip","sourcePath":"components/data/Tooltip.jsx"},{"name":"Tree","sourcePath":"components/data/Tree.jsx"},{"name":"Watermark","sourcePath":"components/data/Watermark.jsx"},{"name":"DataGrid","sourcePath":"components/datatable/DataGrid.jsx"},{"name":"DataTable","sourcePath":"components/datatable/DataTable.jsx"},{"name":"TreeTable","sourcePath":"components/datatable/TreeTable.jsx"},{"name":"Dialog","sourcePath":"components/dialog/Dialog.jsx"},{"name":"Alert","sourcePath":"components/feedback/Alert.jsx"},{"name":"Badge","sourcePath":"components/feedback/Badge.jsx"},{"name":"EmptyState","sourcePath":"components/feedback/EmptyState.jsx"},{"name":"ProgressBar","sourcePath":"components/feedback/ProgressBar.jsx"},{"name":"Result","sourcePath":"components/feedback/Result.jsx"},{"name":"Skeleton","sourcePath":"components/feedback/Skeleton.jsx"},{"name":"Spinner","sourcePath":"components/feedback/Spinner.jsx"},{"name":"StatusIndicator","sourcePath":"components/feedback/StatusIndicator.jsx"},{"name":"Tag","sourcePath":"components/feedback/Tag.jsx"},{"name":"ToastStack","sourcePath":"components/feedback/Toast.jsx"},{"name":"Toast","sourcePath":"components/feedback/Toast.jsx"},{"name":"Calendar","sourcePath":"components/forms/Calendar.jsx"},{"name":"Cascader","sourcePath":"components/forms/Cascader.jsx"},{"name":"Checkbox","sourcePath":"components/forms/Checkbox.jsx"},{"name":"ColorPicker","sourcePath":"components/forms/ColorPicker.jsx"},{"name":"Combobox","sourcePath":"components/forms/Combobox.jsx"},{"name":"DatePicker","sourcePath":"components/forms/DatePicker.jsx"},{"name":"Editor","sourcePath":"components/forms/Editor.jsx"},{"name":"FileUpload","sourcePath":"components/forms/FileUpload.jsx"},{"name":"Form","sourcePath":"components/forms/Form.jsx"},{"name":"FormField","sourcePath":"components/forms/Form.jsx"},{"name":"FormFieldArray","sourcePath":"components/forms/Form.jsx"},{"name":"FormWizard","sourcePath":"components/forms/Form.jsx"},{"name":"InlineEdit","sourcePath":"components/forms/InlineEdit.jsx"},{"name":"InputGroup","sourcePath":"components/forms/InputGroup.jsx"},{"name":"InputOTP","sourcePath":"components/forms/InputOTP.jsx"},{"name":"Mentions","sourcePath":"components/forms/Mentions.jsx"},{"name":"NativeSelect","sourcePath":"components/forms/NativeSelect.jsx"},{"name":"NumberField","sourcePath":"components/forms/NumberField.jsx"},{"name":"Radio","sourcePath":"components/forms/RadioGroup.jsx"},{"name":"RadioGroup","sourcePath":"components/forms/RadioGroup.jsx"},{"name":"Rating","sourcePath":"components/forms/Rating.jsx"},{"name":"SearchField","sourcePath":"components/forms/SearchField.jsx"},{"name":"SegmentedControl","sourcePath":"components/forms/SegmentedControl.jsx"},{"name":"Select","sourcePath":"components/forms/Select.jsx"},{"name":"Slider","sourcePath":"components/forms/Slider.jsx"},{"name":"Switch","sourcePath":"components/forms/Switch.jsx"},{"name":"TagInput","sourcePath":"components/forms/TagInput.jsx"},{"name":"Textarea","sourcePath":"components/forms/Textarea.jsx"},{"name":"TimePicker","sourcePath":"components/forms/TimePicker.jsx"},{"name":"Toggle","sourcePath":"components/forms/Toggle.jsx"},{"name":"Transfer","sourcePath":"components/forms/Transfer.jsx"},{"name":"TreeSelect","sourcePath":"components/forms/TreeSelect.jsx"},{"name":"CS_ICONS","sourcePath":"components/icon/Icon.jsx"},{"name":"Icon","sourcePath":"components/icon/Icon.jsx"},{"name":"Logo","sourcePath":"components/logo/Logo.jsx"},{"name":"CS_LOGO_VIEWBOX","sourcePath":"components/logo/logo-data.js"},{"name":"CS_LOGO_MARK_INNER","sourcePath":"components/logo/logo-data.js"},{"name":"Anchor","sourcePath":"components/navigation/Anchor.jsx"},{"name":"BackTop","sourcePath":"components/navigation/BackTop.jsx"},{"name":"Breadcrumb","sourcePath":"components/navigation/Breadcrumb.jsx"},{"name":"CommandPalette","sourcePath":"components/navigation/CommandPalette.jsx"},{"name":"Dock","sourcePath":"components/navigation/Dock.jsx"},{"name":"HotKeys","sourcePath":"components/navigation/HotKeys.jsx"},{"name":"Link","sourcePath":"components/navigation/Link.jsx"},{"name":"Menu","sourcePath":"components/navigation/Menu.jsx"},{"name":"MenuItem","sourcePath":"components/navigation/Menu.jsx"},{"name":"Menubar","sourcePath":"components/navigation/Menubar.jsx"},{"name":"NavigationMenu","sourcePath":"components/navigation/NavigationMenu.jsx"},{"name":"Pagination","sourcePath":"components/navigation/Pagination.jsx"},{"name":"Sidebar","sourcePath":"components/navigation/Sidebar.jsx"},{"name":"NavItem","sourcePath":"components/navigation/Sidebar.jsx"},{"name":"Steps","sourcePath":"components/navigation/Steps.jsx"},{"name":"Tabs","sourcePath":"components/navigation/Tabs.jsx"},{"name":"Tab","sourcePath":"components/navigation/Tabs.jsx"},{"name":"Toolbar","sourcePath":"components/navigation/Toolbar.jsx"},{"name":"AlertDialog","sourcePath":"components/overlays/AlertDialog.jsx"},{"name":"ContextMenu","sourcePath":"components/overlays/ContextMenu.jsx"},{"name":"Drawer","sourcePath":"components/overlays/Drawer.jsx"},{"name":"HoverCard","sourcePath":"components/overlays/HoverCard.jsx"},{"name":"OverlayProvider","sourcePath":"components/overlays/OverlayManager.jsx"},{"name":"Popconfirm","sourcePath":"components/overlays/Popconfirm.jsx"},{"name":"Popover","sourcePath":"components/overlays/Popover.jsx"},{"name":"Tour","sourcePath":"components/overlays/Tour.jsx"},{"name":"TextField","sourcePath":"components/textfield/TextField.jsx"}],"sourceHashes":{"components/_i18n/i18n.js":"c8fc9f74a4c0","components/_i18n/strings.js":"0e63dc7515d8","components/_utils/cx.js":"ad6a747ea116","components/ai/AIDisclosureBadge.jsx":"4c8954aa2d79","components/ai/ChatMessage.jsx":"344e9c13fcfe","components/ai/CitationList.jsx":"4d12ef868ff3","components/ai/ConfidenceMeter.jsx":"68cf2bba3a9e","components/ai/HumanReviewGate.jsx":"922b278dca5c","components/ai/PromptInput.jsx":"7634643dafa5","components/ai/PromptSuggestions.jsx":"02d64117ecfa","components/ai/TypingIndicator.jsx":"149e3a0c7ef8","components/brand/LumiAvatar.jsx":"b6444360cf80","components/button/Button.jsx":"6d902a925eed","components/button/ButtonGroup.jsx":"1a1481f6fb93","components/button/FloatingActionButton.jsx":"ce49fe4129a3","components/data/Accordion.jsx":"fed81278cefd","components/data/AspectRatio.jsx":"6c1e8703891e","components/data/Avatar.jsx":"88c8f59334e6","components/data/Card.jsx":"96e1f9ef44a9","components/data/Carousel.jsx":"caf09a766c42","components/data/Chart.jsx":"1953e9fef120","components/data/CodeBlock.jsx":"04e0bd2507e2","components/data/Collapsible.jsx":"3d961fef83f8","components/data/Comment.jsx":"81469a910d80","components/data/DescriptionList.jsx":"ce50d72546bb","components/data/Divider.jsx":"2d08b4a7b18e","components/data/Image.jsx":"0ea06cfe1532","components/data/Item.jsx":"7e1ac68c4e96","components/data/Kbd.jsx":"3b3d867cbdd8","components/data/List.jsx":"5c221b19efe0","components/data/Masonry.jsx":"a65508731d79","components/data/QRCode.jsx":"6acaf577a7fc","components/data/ScrollArea.jsx":"c2e2ec304b1e","components/data/Sortable.jsx":"ed7615a9469a","components/data/Splitter.jsx":"d231064601e9","components/data/Stat.jsx":"35734a801a71","components/data/Terminal.jsx":"9d419686bea8","components/data/Timeline.jsx":"22058a781a98","components/data/Tooltip.jsx":"3f30c6b1bf1d","components/data/Tree.jsx":"a1d33dec0451","components/data/Watermark.jsx":"66b7b71488d8","components/data/qr-encode.js":"14e8de77df5f","components/datatable/DataGrid.jsx":"c84fe5d5b8cc","components/datatable/DataTable.jsx":"2a7c3bda5142","components/datatable/TreeTable.jsx":"597c35135ebb","components/dialog/Dialog.jsx":"8ef7722c37c4","components/feedback/Alert.jsx":"4dbf685af3e1","components/feedback/Badge.jsx":"e691ae1634f8","components/feedback/EmptyState.jsx":"5ba1437e6d81","components/feedback/ProgressBar.jsx":"c63a431e9eed","components/feedback/Result.jsx":"c168f8dcb009","components/feedback/Skeleton.jsx":"86ee345cb412","components/feedback/Spinner.jsx":"cad2ed4008a6","components/feedback/StatusIndicator.jsx":"d27a5fc3db2a","components/feedback/Tag.jsx":"13d288da9f38","components/feedback/Toast.jsx":"6a7832751669","components/forms/Calendar.jsx":"8a66cbe766af","components/forms/Cascader.jsx":"63f35db7101d","components/forms/Checkbox.jsx":"2badb7b3b72b","components/forms/ColorPicker.jsx":"d04db0ee7678","components/forms/Combobox.jsx":"3f2fb4d28922","components/forms/DatePicker.jsx":"7a6c18e1e635","components/forms/Editor.jsx":"194484fb9dc4","components/forms/FileUpload.jsx":"509dfaff8bea","components/forms/Form.jsx":"6945025a205f","components/forms/InlineEdit.jsx":"5ffb40598769","components/forms/InputGroup.jsx":"06d6c22420d0","components/forms/InputOTP.jsx":"c3a5d02ffebc","components/forms/Mentions.jsx":"3924619137f3","components/forms/NativeSelect.jsx":"d6f6d300f75d","components/forms/NumberField.jsx":"44975fd25721","components/forms/RadioGroup.jsx":"1a64f7600e01","components/forms/Rating.jsx":"bd5c94741d63","components/forms/SearchField.jsx":"2a12c65900ec","components/forms/SegmentedControl.jsx":"1f143c62fb56","components/forms/Select.jsx":"009495d18845","components/forms/Slider.jsx":"213b7b9edec9","components/forms/Switch.jsx":"3cdf185f757c","components/forms/TagInput.jsx":"2d1554422097","components/forms/Textarea.jsx":"cf244fee0e37","components/forms/TimePicker.jsx":"abd6e54b2983","components/forms/Toggle.jsx":"a5378fd66713","components/forms/Transfer.jsx":"dd0c02d1014e","components/forms/TreeSelect.jsx":"a5b1b91d1d6a","components/icon/Icon.jsx":"280fba8477db","components/logo/Logo.jsx":"445c5f5fbd40","components/logo/logo-data.js":"f1a251a50c8f","components/navigation/Anchor.jsx":"491fb330e718","components/navigation/BackTop.jsx":"5cac0081fc20","components/navigation/Breadcrumb.jsx":"45636f3b0a51","components/navigation/CommandPalette.jsx":"51c25b8416eb","components/navigation/Dock.jsx":"3073e2870c65","components/navigation/HotKeys.jsx":"f0f707a3335d","components/navigation/Link.jsx":"d4fe3fcffd2c","components/navigation/Menu.jsx":"999e1659f8b3","components/navigation/Menubar.jsx":"1aa64f59891e","components/navigation/NavigationMenu.jsx":"020279fd7f79","components/navigation/Pagination.jsx":"a1fc19bfd104","components/navigation/Sidebar.jsx":"d578b013ad33","components/navigation/Steps.jsx":"e26c4a18cdfc","components/navigation/Tabs.jsx":"16964d61f349","components/navigation/Toolbar.jsx":"0f1f25d9e0c5","components/overlays/AlertDialog.jsx":"dcfbb7f61506","components/overlays/ContextMenu.jsx":"e3fb63e7b74f","components/overlays/Drawer.jsx":"a1c719da3f62","components/overlays/HoverCard.jsx":"5cfabde80960","components/overlays/OverlayManager.jsx":"6b58c4dad9da","components/overlays/Popconfirm.jsx":"55f08dba5f38","components/overlays/Popover.jsx":"1582f7fa5533","components/overlays/Tour.jsx":"707cd7464f0c","components/textfield/TextField.jsx":"c06bd9729f20","tokens/tokens.js":"ed1c735bcda9"},"inlinedExternals":[],"unexposedExports":[{"name":"attachFocusTrap","sourcePath":"components/overlays/OverlayManager.jsx"},{"name":"cx","sourcePath":"components/_utils/cx.js"},{"name":"focusableSelector","sourcePath":"components/overlays/OverlayManager.jsx"},{"name":"formatCurrency","sourcePath":"components/_i18n/i18n.js"},{"name":"formatDate","sourcePath":"components/_i18n/i18n.js"},{"name":"formatNumber","sourcePath":"components/_i18n/i18n.js"},{"name":"getOverlayManager","sourcePath":"components/overlays/OverlayManager.jsx"},{"name":"getPath","sourcePath":"components/forms/Form.jsx"},{"name":"makeT","sourcePath":"components/_i18n/i18n.js"},{"name":"monthName","sourcePath":"components/_i18n/i18n.js"},{"name":"qrMatrix","sourcePath":"components/data/qr-encode.js"},{"name":"reorderItems","sourcePath":"components/data/Sortable.jsx"},{"name":"resolveLang","sourcePath":"components/_i18n/i18n.js"},{"name":"setPath","sourcePath":"components/forms/Form.jsx"},{"name":"strings","sourcePath":"components/_i18n/strings.js"},{"name":"tokens","sourcePath":"tokens/tokens.js"},{"name":"tr","sourcePath":"components/_i18n/i18n.js"},{"name":"useLang","sourcePath":"components/_i18n/i18n.js"},{"name":"useOverlayLayer","sourcePath":"components/overlays/OverlayManager.jsx"}]} */
|
|
1
|
+
/* @ds-bundle: {"format":4,"namespace":"CyberSkillDesignSystem_847b3c","components":[{"name":"AIDisclosureBadge","sourcePath":"components/ai/AIDisclosureBadge.jsx"},{"name":"ChatMessage","sourcePath":"components/ai/ChatMessage.jsx"},{"name":"CitationList","sourcePath":"components/ai/CitationList.jsx"},{"name":"ConfidenceMeter","sourcePath":"components/ai/ConfidenceMeter.jsx"},{"name":"HumanReviewGate","sourcePath":"components/ai/HumanReviewGate.jsx"},{"name":"PromptInput","sourcePath":"components/ai/PromptInput.jsx"},{"name":"PromptSuggestions","sourcePath":"components/ai/PromptSuggestions.jsx"},{"name":"TypingIndicator","sourcePath":"components/ai/TypingIndicator.jsx"},{"name":"LumiAvatar","sourcePath":"components/brand/LumiAvatar.jsx"},{"name":"Button","sourcePath":"components/button/Button.jsx"},{"name":"ButtonGroup","sourcePath":"components/button/ButtonGroup.jsx"},{"name":"FloatingActionButton","sourcePath":"components/button/FloatingActionButton.jsx"},{"name":"Accordion","sourcePath":"components/data/Accordion.jsx"},{"name":"AspectRatio","sourcePath":"components/data/AspectRatio.jsx"},{"name":"Avatar","sourcePath":"components/data/Avatar.jsx"},{"name":"AvatarGroup","sourcePath":"components/data/Avatar.jsx"},{"name":"Card","sourcePath":"components/data/Card.jsx"},{"name":"CardHeader","sourcePath":"components/data/Card.jsx"},{"name":"CardBody","sourcePath":"components/data/Card.jsx"},{"name":"CardFooter","sourcePath":"components/data/Card.jsx"},{"name":"Carousel","sourcePath":"components/data/Carousel.jsx"},{"name":"Chart","sourcePath":"components/data/Chart.jsx"},{"name":"CodeBlock","sourcePath":"components/data/CodeBlock.jsx"},{"name":"Collapsible","sourcePath":"components/data/Collapsible.jsx"},{"name":"Comment","sourcePath":"components/data/Comment.jsx"},{"name":"DescriptionList","sourcePath":"components/data/DescriptionList.jsx"},{"name":"Divider","sourcePath":"components/data/Divider.jsx"},{"name":"Image","sourcePath":"components/data/Image.jsx"},{"name":"Item","sourcePath":"components/data/Item.jsx"},{"name":"Kbd","sourcePath":"components/data/Kbd.jsx"},{"name":"List","sourcePath":"components/data/List.jsx"},{"name":"ListItem","sourcePath":"components/data/List.jsx"},{"name":"Masonry","sourcePath":"components/data/Masonry.jsx"},{"name":"QRCode","sourcePath":"components/data/QRCode.jsx"},{"name":"ScrollArea","sourcePath":"components/data/ScrollArea.jsx"},{"name":"Sortable","sourcePath":"components/data/Sortable.jsx"},{"name":"Splitter","sourcePath":"components/data/Splitter.jsx"},{"name":"Stat","sourcePath":"components/data/Stat.jsx"},{"name":"Terminal","sourcePath":"components/data/Terminal.jsx"},{"name":"Timeline","sourcePath":"components/data/Timeline.jsx"},{"name":"Tooltip","sourcePath":"components/data/Tooltip.jsx"},{"name":"Tree","sourcePath":"components/data/Tree.jsx"},{"name":"Watermark","sourcePath":"components/data/Watermark.jsx"},{"name":"DataGrid","sourcePath":"components/datatable/DataGrid.jsx"},{"name":"DataTable","sourcePath":"components/datatable/DataTable.jsx"},{"name":"TreeTable","sourcePath":"components/datatable/TreeTable.jsx"},{"name":"Dialog","sourcePath":"components/dialog/Dialog.jsx"},{"name":"Alert","sourcePath":"components/feedback/Alert.jsx"},{"name":"Badge","sourcePath":"components/feedback/Badge.jsx"},{"name":"EmptyState","sourcePath":"components/feedback/EmptyState.jsx"},{"name":"ProgressBar","sourcePath":"components/feedback/ProgressBar.jsx"},{"name":"Result","sourcePath":"components/feedback/Result.jsx"},{"name":"Skeleton","sourcePath":"components/feedback/Skeleton.jsx"},{"name":"Spinner","sourcePath":"components/feedback/Spinner.jsx"},{"name":"StatusIndicator","sourcePath":"components/feedback/StatusIndicator.jsx"},{"name":"Tag","sourcePath":"components/feedback/Tag.jsx"},{"name":"ToastStack","sourcePath":"components/feedback/Toast.jsx"},{"name":"Toast","sourcePath":"components/feedback/Toast.jsx"},{"name":"Calendar","sourcePath":"components/forms/Calendar.jsx"},{"name":"Cascader","sourcePath":"components/forms/Cascader.jsx"},{"name":"Checkbox","sourcePath":"components/forms/Checkbox.jsx"},{"name":"ColorPicker","sourcePath":"components/forms/ColorPicker.jsx"},{"name":"Combobox","sourcePath":"components/forms/Combobox.jsx"},{"name":"DatePicker","sourcePath":"components/forms/DatePicker.jsx"},{"name":"Editor","sourcePath":"components/forms/Editor.jsx"},{"name":"FileUpload","sourcePath":"components/forms/FileUpload.jsx"},{"name":"Form","sourcePath":"components/forms/Form.jsx"},{"name":"FormField","sourcePath":"components/forms/Form.jsx"},{"name":"FormFieldArray","sourcePath":"components/forms/Form.jsx"},{"name":"FormWizard","sourcePath":"components/forms/Form.jsx"},{"name":"InlineEdit","sourcePath":"components/forms/InlineEdit.jsx"},{"name":"InputGroup","sourcePath":"components/forms/InputGroup.jsx"},{"name":"InputOTP","sourcePath":"components/forms/InputOTP.jsx"},{"name":"Mentions","sourcePath":"components/forms/Mentions.jsx"},{"name":"NativeSelect","sourcePath":"components/forms/NativeSelect.jsx"},{"name":"NumberField","sourcePath":"components/forms/NumberField.jsx"},{"name":"Radio","sourcePath":"components/forms/RadioGroup.jsx"},{"name":"RadioGroup","sourcePath":"components/forms/RadioGroup.jsx"},{"name":"Rating","sourcePath":"components/forms/Rating.jsx"},{"name":"SearchField","sourcePath":"components/forms/SearchField.jsx"},{"name":"SegmentedControl","sourcePath":"components/forms/SegmentedControl.jsx"},{"name":"Select","sourcePath":"components/forms/Select.jsx"},{"name":"Slider","sourcePath":"components/forms/Slider.jsx"},{"name":"Switch","sourcePath":"components/forms/Switch.jsx"},{"name":"TagInput","sourcePath":"components/forms/TagInput.jsx"},{"name":"Textarea","sourcePath":"components/forms/Textarea.jsx"},{"name":"TimePicker","sourcePath":"components/forms/TimePicker.jsx"},{"name":"Toggle","sourcePath":"components/forms/Toggle.jsx"},{"name":"Transfer","sourcePath":"components/forms/Transfer.jsx"},{"name":"TreeSelect","sourcePath":"components/forms/TreeSelect.jsx"},{"name":"CS_ICONS","sourcePath":"components/icon/Icon.jsx"},{"name":"Icon","sourcePath":"components/icon/Icon.jsx"},{"name":"Logo","sourcePath":"components/logo/Logo.jsx"},{"name":"CS_LOGO_VIEWBOX","sourcePath":"components/logo/logo-data.js"},{"name":"CS_LOGO_MARK_INNER","sourcePath":"components/logo/logo-data.js"},{"name":"Anchor","sourcePath":"components/navigation/Anchor.jsx"},{"name":"BackTop","sourcePath":"components/navigation/BackTop.jsx"},{"name":"Breadcrumb","sourcePath":"components/navigation/Breadcrumb.jsx"},{"name":"CommandPalette","sourcePath":"components/navigation/CommandPalette.jsx"},{"name":"Dock","sourcePath":"components/navigation/Dock.jsx"},{"name":"HotKeys","sourcePath":"components/navigation/HotKeys.jsx"},{"name":"Link","sourcePath":"components/navigation/Link.jsx"},{"name":"Menu","sourcePath":"components/navigation/Menu.jsx"},{"name":"MenuItem","sourcePath":"components/navigation/Menu.jsx"},{"name":"Menubar","sourcePath":"components/navigation/Menubar.jsx"},{"name":"NavigationMenu","sourcePath":"components/navigation/NavigationMenu.jsx"},{"name":"Pagination","sourcePath":"components/navigation/Pagination.jsx"},{"name":"Sidebar","sourcePath":"components/navigation/Sidebar.jsx"},{"name":"NavItem","sourcePath":"components/navigation/Sidebar.jsx"},{"name":"Steps","sourcePath":"components/navigation/Steps.jsx"},{"name":"Tabs","sourcePath":"components/navigation/Tabs.jsx"},{"name":"Tab","sourcePath":"components/navigation/Tabs.jsx"},{"name":"Toolbar","sourcePath":"components/navigation/Toolbar.jsx"},{"name":"AlertDialog","sourcePath":"components/overlays/AlertDialog.jsx"},{"name":"ContextMenu","sourcePath":"components/overlays/ContextMenu.jsx"},{"name":"Drawer","sourcePath":"components/overlays/Drawer.jsx"},{"name":"HoverCard","sourcePath":"components/overlays/HoverCard.jsx"},{"name":"OverlayProvider","sourcePath":"components/overlays/OverlayManager.jsx"},{"name":"Popconfirm","sourcePath":"components/overlays/Popconfirm.jsx"},{"name":"Popover","sourcePath":"components/overlays/Popover.jsx"},{"name":"Tour","sourcePath":"components/overlays/Tour.jsx"},{"name":"TextField","sourcePath":"components/textfield/TextField.jsx"}],"sourceHashes":{"components/_i18n/i18n.js":"c8fc9f74a4c0","components/_i18n/strings.js":"0e63dc7515d8","components/_utils/cx.js":"ad6a747ea116","components/ai/AIDisclosureBadge.jsx":"4c8954aa2d79","components/ai/ChatMessage.jsx":"344e9c13fcfe","components/ai/CitationList.jsx":"4d12ef868ff3","components/ai/ConfidenceMeter.jsx":"68cf2bba3a9e","components/ai/HumanReviewGate.jsx":"922b278dca5c","components/ai/PromptInput.jsx":"7634643dafa5","components/ai/PromptSuggestions.jsx":"02d64117ecfa","components/ai/TypingIndicator.jsx":"149e3a0c7ef8","components/brand/LumiAvatar.jsx":"b6444360cf80","components/button/Button.jsx":"6d902a925eed","components/button/ButtonGroup.jsx":"1a1481f6fb93","components/button/FloatingActionButton.jsx":"ce49fe4129a3","components/data/Accordion.jsx":"fed81278cefd","components/data/AspectRatio.jsx":"6c1e8703891e","components/data/Avatar.jsx":"88c8f59334e6","components/data/Card.jsx":"96e1f9ef44a9","components/data/Carousel.jsx":"caf09a766c42","components/data/Chart.jsx":"1953e9fef120","components/data/CodeBlock.jsx":"04e0bd2507e2","components/data/Collapsible.jsx":"3d961fef83f8","components/data/Comment.jsx":"81469a910d80","components/data/DescriptionList.jsx":"ce50d72546bb","components/data/Divider.jsx":"2d08b4a7b18e","components/data/Image.jsx":"0ea06cfe1532","components/data/Item.jsx":"7e1ac68c4e96","components/data/Kbd.jsx":"3b3d867cbdd8","components/data/List.jsx":"5c221b19efe0","components/data/Masonry.jsx":"a65508731d79","components/data/QRCode.jsx":"6acaf577a7fc","components/data/ScrollArea.jsx":"c2e2ec304b1e","components/data/Sortable.jsx":"ed7615a9469a","components/data/Splitter.jsx":"d231064601e9","components/data/Stat.jsx":"35734a801a71","components/data/Terminal.jsx":"9d419686bea8","components/data/Timeline.jsx":"22058a781a98","components/data/Tooltip.jsx":"3f30c6b1bf1d","components/data/Tree.jsx":"a1d33dec0451","components/data/Watermark.jsx":"66b7b71488d8","components/data/qr-encode.js":"14e8de77df5f","components/datatable/DataGrid.jsx":"c84fe5d5b8cc","components/datatable/DataTable.jsx":"2a7c3bda5142","components/datatable/TreeTable.jsx":"597c35135ebb","components/dialog/Dialog.jsx":"8ef7722c37c4","components/feedback/Alert.jsx":"4dbf685af3e1","components/feedback/Badge.jsx":"e691ae1634f8","components/feedback/EmptyState.jsx":"5ba1437e6d81","components/feedback/ProgressBar.jsx":"c63a431e9eed","components/feedback/Result.jsx":"c168f8dcb009","components/feedback/Skeleton.jsx":"86ee345cb412","components/feedback/Spinner.jsx":"cad2ed4008a6","components/feedback/StatusIndicator.jsx":"d27a5fc3db2a","components/feedback/Tag.jsx":"13d288da9f38","components/feedback/Toast.jsx":"6a7832751669","components/forms/Calendar.jsx":"8a66cbe766af","components/forms/Cascader.jsx":"63f35db7101d","components/forms/Checkbox.jsx":"2badb7b3b72b","components/forms/ColorPicker.jsx":"d04db0ee7678","components/forms/Combobox.jsx":"3f2fb4d28922","components/forms/DatePicker.jsx":"7a6c18e1e635","components/forms/Editor.jsx":"194484fb9dc4","components/forms/FileUpload.jsx":"509dfaff8bea","components/forms/Form.jsx":"6945025a205f","components/forms/InlineEdit.jsx":"5ffb40598769","components/forms/InputGroup.jsx":"06d6c22420d0","components/forms/InputOTP.jsx":"c3a5d02ffebc","components/forms/Mentions.jsx":"3924619137f3","components/forms/NativeSelect.jsx":"d6f6d300f75d","components/forms/NumberField.jsx":"44975fd25721","components/forms/RadioGroup.jsx":"1a64f7600e01","components/forms/Rating.jsx":"bd5c94741d63","components/forms/SearchField.jsx":"2a12c65900ec","components/forms/SegmentedControl.jsx":"1f143c62fb56","components/forms/Select.jsx":"009495d18845","components/forms/Slider.jsx":"213b7b9edec9","components/forms/Switch.jsx":"3cdf185f757c","components/forms/TagInput.jsx":"2d1554422097","components/forms/Textarea.jsx":"cf244fee0e37","components/forms/TimePicker.jsx":"abd6e54b2983","components/forms/Toggle.jsx":"a5378fd66713","components/forms/Transfer.jsx":"dd0c02d1014e","components/forms/TreeSelect.jsx":"a5b1b91d1d6a","components/icon/Icon.jsx":"280fba8477db","components/logo/Logo.jsx":"445c5f5fbd40","components/logo/logo-data.js":"f1a251a50c8f","components/navigation/Anchor.jsx":"491fb330e718","components/navigation/BackTop.jsx":"5cac0081fc20","components/navigation/Breadcrumb.jsx":"45636f3b0a51","components/navigation/CommandPalette.jsx":"51c25b8416eb","components/navigation/Dock.jsx":"3073e2870c65","components/navigation/HotKeys.jsx":"f0f707a3335d","components/navigation/Link.jsx":"d4fe3fcffd2c","components/navigation/Menu.jsx":"999e1659f8b3","components/navigation/Menubar.jsx":"1aa64f59891e","components/navigation/NavigationMenu.jsx":"020279fd7f79","components/navigation/Pagination.jsx":"a1fc19bfd104","components/navigation/Sidebar.jsx":"d578b013ad33","components/navigation/Steps.jsx":"e26c4a18cdfc","components/navigation/Tabs.jsx":"16964d61f349","components/navigation/Toolbar.jsx":"0f1f25d9e0c5","components/overlays/AlertDialog.jsx":"dcfbb7f61506","components/overlays/ContextMenu.jsx":"e3fb63e7b74f","components/overlays/Drawer.jsx":"a1c719da3f62","components/overlays/HoverCard.jsx":"5cfabde80960","components/overlays/OverlayManager.jsx":"6b58c4dad9da","components/overlays/Popconfirm.jsx":"55f08dba5f38","components/overlays/Popover.jsx":"1582f7fa5533","components/overlays/Tour.jsx":"707cd7464f0c","components/textfield/TextField.jsx":"c06bd9729f20","tokens/tokens.js":"c4638b1eba09"},"inlinedExternals":[],"unexposedExports":[{"name":"attachFocusTrap","sourcePath":"components/overlays/OverlayManager.jsx"},{"name":"cx","sourcePath":"components/_utils/cx.js"},{"name":"focusableSelector","sourcePath":"components/overlays/OverlayManager.jsx"},{"name":"formatCurrency","sourcePath":"components/_i18n/i18n.js"},{"name":"formatDate","sourcePath":"components/_i18n/i18n.js"},{"name":"formatNumber","sourcePath":"components/_i18n/i18n.js"},{"name":"getOverlayManager","sourcePath":"components/overlays/OverlayManager.jsx"},{"name":"getPath","sourcePath":"components/forms/Form.jsx"},{"name":"makeT","sourcePath":"components/_i18n/i18n.js"},{"name":"monthName","sourcePath":"components/_i18n/i18n.js"},{"name":"qrMatrix","sourcePath":"components/data/qr-encode.js"},{"name":"reorderItems","sourcePath":"components/data/Sortable.jsx"},{"name":"resolveLang","sourcePath":"components/_i18n/i18n.js"},{"name":"setPath","sourcePath":"components/forms/Form.jsx"},{"name":"strings","sourcePath":"components/_i18n/strings.js"},{"name":"tokens","sourcePath":"tokens/tokens.js"},{"name":"tr","sourcePath":"components/_i18n/i18n.js"},{"name":"useLang","sourcePath":"components/_i18n/i18n.js"},{"name":"useOverlayLayer","sourcePath":"components/overlays/OverlayManager.jsx"}]} */
|
|
2
2
|
|
|
3
3
|
(() => {
|
|
4
4
|
|
|
@@ -4874,7 +4874,7 @@ try { (() => {
|
|
|
4874
4874
|
const tokens = {
|
|
4875
4875
|
"$meta": {
|
|
4876
4876
|
"system": "CyberSkill Design System",
|
|
4877
|
-
"version": "1.7.
|
|
4877
|
+
"version": "1.7.2",
|
|
4878
4878
|
"generated": "2026-07-23",
|
|
4879
4879
|
"note": "Generated from tokens/*.css. Root grouped by category; theme/element scopes carry overrides only. Regenerate after any token change (see docs/conventions.md)."
|
|
4880
4880
|
},
|
package/_esm/cs.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// CyberSkill Design System — ESM entry point (GENERATED from _ds_manifest.json at v1.7.
|
|
1
|
+
// CyberSkill Design System — ESM entry point (GENERATED from _ds_manifest.json at v1.7.2).
|
|
2
2
|
// No build step: import this module directly in a browser. It ensures React 19.2.8 via umd-react
|
|
3
3
|
// (official React 19 dropped UMD; pinned + SRI; skipped when window.React already exists), side-loads
|
|
4
4
|
// ../_ds_bundle.js once, resolves the compiler-assigned namespace BY PREFIX (never a hardcoded suffix),
|
|
@@ -32,7 +32,7 @@ if (!found()) await ensureScript("../_ds_bundle.js");
|
|
|
32
32
|
export const CS = g[found()];
|
|
33
33
|
if (!CS) throw new Error("cs.js: bundle loaded but no CyberSkillDesignSystem_* namespace found");
|
|
34
34
|
export default CS;
|
|
35
|
-
export const VERSION = "1.7.
|
|
35
|
+
export const VERSION = "1.7.2";
|
|
36
36
|
export const AIDisclosureBadge = CS.AIDisclosureBadge;
|
|
37
37
|
export const Accordion = CS.Accordion;
|
|
38
38
|
export const Alert = CS.Alert;
|
package/docs/contrast-report.md
CHANGED
package/docs/conventions.md
CHANGED
|
@@ -38,7 +38,7 @@ Style’s sole pack today is **liquid-glass**. Immutable under all axes: Umber/O
|
|
|
38
38
|
|
|
39
39
|
**New element variant** — stay inside the element's oklch envelope; set the 10 `--cs-accent-*` contract tokens (incl. `--cs-accent-on-strong` ≥4.5:1 on `-strong`) plus `--cs-color-text-accent`/`--cs-color-link` (APCA-check both); the aurora wash inherits from the element via `.cs-aurora-wash` (override the class rule only if the variant truly needs its own image); gradient partner (`grad-b`) must follow Tương sinh.
|
|
40
40
|
|
|
41
|
-
**Ship check** — run the compiler check until clean, then run `_audit/docs-consistency.html` **and** `_audit/namespace-portability.html` (both must be green). VERSION **1.7.
|
|
41
|
+
**Ship check** — run the compiler check until clean, then run `_audit/docs-consistency.html` **and** `_audit/namespace-portability.html` (both must be green). VERSION **1.7.2** (auto-bumps on `main`).
|
|
42
42
|
|
|
43
43
|
## Decision log (owner-approved)
|
|
44
44
|
|
|
@@ -64,7 +64,7 @@ Every template exports; the right path depends on the archetype. All paths prese
|
|
|
64
64
|
| Archetype | Path | Notes |
|
|
65
65
|
|---|---|---|
|
|
66
66
|
| Deck (`*-deck`, `slide-deck`) | **PPTX (editable)** | `gen_pptx` at 960×540; force VN per-slide with `showJs: __dcSetProps(__dcRootName(),{language:'Tiếng Việt'})`. Text exports as native runs; only the Logo is an image. |
|
|
67
|
-
| Document (any with `@page{size:…}` / `<meta name="omelette-owns-print">`) | **PDF + editable DOCX** | One **Tải / Download** control (`data-omelette-chrome`, print-stripped) from `templates/_vendor/doc-export.js` via `ds-base.js`, with a PDF \| DOCX menu. Both formats are built from the live `.cs-sheet` so the file matches the HTML preview. **PDF** =
|
|
67
|
+
| Document (any with `@page{size:…}` / `<meta name="omelette-owns-print">`) | **PDF + editable DOCX** | One **Tải / Download** control (`data-omelette-chrome`, print-stripped) from `templates/_vendor/doc-export.js` via `ds-base.js`, with a PDF \| DOCX menu. Both formats are built from the live `.cs-sheet` so the file matches the HTML preview. **PDF** = one Flate DeviceRGB page of the painted sheet at scale 3 (MediaBox aspect = the card — do not JPEG-blur, slice to A4, or stretch leftover slices); fallback: print a same-origin sheet clone — not the Storybook URL. CI still uses Playwright `page.pdf` for the print path. **DOCX** = editable OOXML walked from that same sheet (header flex as logo\|number table, measured font sizes/colors, tables + colspan, yellow `--cs-doc-fill` blanks, bilingual cell paras, umber headings, VN Unicode; Word header/footer stay empty so the sheet lockup is not duplicated); ZIP via `CompressionStream` — no CDN. Decks stay PPTX. |
|
|
68
68
|
| Email / product page / any DC | **Standalone offline HTML** | The DC loads CSS + bundle dynamically via `ds-base.js`, which `super_inline_html` can't see. To bundle: make a `*-standalone.html` copy **in the same folder** (keeps `./support.js` relative) with **static** `<link rel="stylesheet" href="../../styles.css">` + `<script src="../../_ds_bundle.js">` in the raw `<head>` (both inlinable) instead of `ds-base.js`, plus a `<template id="__bundler_thumbnail">`. Bake the target language into the props default. Then `super_inline_html`. |
|
|
69
69
|
| Any | **Editor-native + Claude Code handoff** | The whole project is dev-handoff-ready (compiled bundle + `.d.ts` + `prompt.md` per component); generate the package on request via the handoff skill. |
|
|
70
70
|
|
package/docs/quality-gates.md
CHANGED
|
@@ -52,7 +52,7 @@ Benchmark principles (WCAG · APCA · OKLCH · DTCG · CDS doctrine + style expa
|
|
|
52
52
|
| Axe smoke | `_audit/axe-smoke.html` + `_audit/lib/axe-fixtures.js` | axe-core 4.10.0 (vendored at `_audit/vendor/axe.min.js`) serious/critical WCAG 2 A/AA rules on every public primary (inventory-locked fixtures; bilingual EN·VI) — Dialog, AlertDialog, Drawer, Tour, CommandPalette, and Menu mount open, and Cascader / TreeSelect / Menubar / Combobox surfaces are expanded before the scan; gate-equivalent Storybook a11y enforcement (no separate test-runner) | 0 serious/critical findings (`__axesmoke`) | Hard | Fast board CI |
|
|
53
53
|
| Print smoke | `_audit/print-smoke.html` | **Every** `omelette-owns-print` document declares print-ownership meta and A4/Letter `@page` hooks the PDF/DOCX export path relies on | ≥60 print docs, 0 missing hooks (`__printsmoke`) | Hard | Fast board CI |
|
|
54
54
|
| Support no-eval (Node) | `_audit/ci/test-support-no-eval.mjs` | Canonical `templates/_vendor/support.js` + all template copies are identical and contain no Function-constructor / `eval(` call sites (CSP-safe inline-script runtime) | Exit 0 | Hard | Unit test |
|
|
55
|
-
| Doc export (Node+PW) | `_audit/ci/test-doc-export.mjs` | Every print template under site CSP: no EvalError, one Download menu (PDF\|DOCX), PDF `%PDF` + A4/Letter MediaBox, DOCX ZIP + `word/document.xml` + VN diacritics + ≥70% sheet-text overlap | Exit 0 | Hard | Unit test |
|
|
55
|
+
| Doc export (Node+PW) | `_audit/ci/test-doc-export.mjs` | Every print template under site CSP: no EvalError, one Download menu (PDF\|DOCX), Playwright PDF `%PDF` + A4/Letter MediaBox, downloaded `buildPdfBlob` is one unstretched FlateDecode page of the live sheet (framework), DOCX ZIP + `word/document.xml` + VN diacritics + ≥70% sheet-text overlap + yellow fills/colspan + header lockup text (HĐNT) on framework | Exit 0 | Hard | Unit test |
|
|
56
56
|
| DOCX source parity (Node) | `_audit/ci/test-docx-source-parity.mjs` | DC text vs committed fixtures under `_audit/fixtures/hr-suite-docx-text/` for every mapped HR instrument | ≥85% phrase overlap; exit 0 | Hard | Unit test |
|
|
57
57
|
| Pixel CI | `_audit/pixel-ci.html` + `_audit/ci/pixel-diff.mjs` | 15 curated baselines exist; Playwright capture script performs real % pixel compare; last report must be clean (`drifted[]` empty) | Contract + clean compare (`__pixelci.pass`); drift or missing report fails | Hard | Fast board CI (compare step feeds the row) + `pixel-diff` job |
|
|
58
58
|
|
package/docs/release-notes.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Release Notes
|
|
2
2
|
|
|
3
|
-
Curated product highlights for operators. This is **not** a git log and **not** a `CHANGELOG.md` — the design system does not maintain a changelog file. VERSION **1.7.
|
|
3
|
+
Curated product highlights for operators. This is **not** a git log and **not** a `CHANGELOG.md` — the design system does not maintain a changelog file. VERSION **1.7.2** (auto-bumps on push to `main` from Conventional Commits; owner may still force a bump). Technical continuity is the repo tip; product-facing continuity is this page (mirrored in Storybook **Release Notes**). Published on Storybook **Docs** at `design.cyberskill.world`.
|
|
4
4
|
|
|
5
5
|
## Release — `@cyberskill/design@1.3.10`
|
|
6
6
|
|
package/docs/vi/conventions.md
CHANGED
|
@@ -38,7 +38,7 @@ Pack Style duy nhất hiện nay là **liquid-glass**. Bất biến dưới mọ
|
|
|
38
38
|
|
|
39
39
|
**Element variant mới** — ở trong envelope oklch của element; đặt 10 token hợp đồng `--cs-accent-*` (gồm `--cs-accent-on-strong` ≥4.5:1 trên `-strong`) cộng `--cs-color-text-accent`/`--cs-color-link` (APCA-check cả hai); aurora wash kế thừa từ element qua `.cs-aurora-wash` (chỉ override class rule nếu variant thật sự cần ảnh riêng); đối tác gradient (`grad-b`) phải theo Tương sinh.
|
|
40
40
|
|
|
41
|
-
**Ship check** — chạy compiler check đến sạch, rồi chạy `_audit/docs-consistency.html` **và** `_audit/namespace-portability.html` (cả hai phải xanh). VERSION **1.7.
|
|
41
|
+
**Ship check** — chạy compiler check đến sạch, rồi chạy `_audit/docs-consistency.html` **và** `_audit/namespace-portability.html` (cả hai phải xanh). VERSION **1.7.2** (auto-bump trên `main`).
|
|
42
42
|
|
|
43
43
|
## Decision log (owner duyệt)
|
|
44
44
|
|
|
@@ -64,7 +64,7 @@ Mọi template export; đường đúng phụ thuộc archetype. Mọi đường
|
|
|
64
64
|
| Archetype | Đường | Ghi chú |
|
|
65
65
|
|---|---|---|
|
|
66
66
|
| Deck (`*-deck`, `slide-deck`) | **PPTX (editable)** | `gen_pptx` ở 960×540; ép VN từng slide với `showJs: __dcSetProps(__dcRootName(),{language:'Tiếng Việt'})`. Text export như native runs; chỉ Logo là ảnh. |
|
|
67
|
-
| Document (mọi cái có `@page{size:…}` / `<meta name="omelette-owns-print">`) | **PDF + DOCX chỉnh sửa được** | Một nút **Tải / Download** (`data-omelette-chrome`, ẩn khi in) từ `templates/_vendor/doc-export.js` qua `ds-base.js`, menu PDF \| DOCX. Cả hai format dựng từ `.cs-sheet` sống để file khớp preview HTML. **PDF** =
|
|
67
|
+
| Document (mọi cái có `@page{size:…}` / `<meta name="omelette-owns-print">`) | **PDF + DOCX chỉnh sửa được** | Một nút **Tải / Download** (`data-omelette-chrome`, ẩn khi in) từ `templates/_vendor/doc-export.js` qua `ds-base.js`, menu PDF \| DOCX. Cả hai format dựng từ `.cs-sheet` sống để file khớp preview HTML. **PDF** = một trang Flate DeviceRGB của sheet đã vẽ, scale 3 (tỉ lệ MediaBox = thẻ — không JPEG mờ, không cắt A4 hay kéo dãn lát cuối); fallback: in bản clone same-origin — không phải URL Storybook. CI vẫn dùng Playwright `page.pdf` cho đường in. **DOCX** = OOXML editable walk từ cùng sheet (flex header thành bảng logo\|số, cỡ/màu chữ đo được, bảng + colspan, ô vàng `--cs-doc-fill`, đoạn bilingual trong ô, heading umber, Unicode VN; header/footer Word để trống để không nhân đôi lockup); ZIP qua `CompressionStream` — không CDN. Deck vẫn PPTX. |
|
|
68
68
|
| Email / product page / mọi DC | **Standalone offline HTML** | DC load CSS + bundle động qua `ds-base.js`, mà `super_inline_html` không thấy. Để bundle: tạo bản `*-standalone.html` **cùng thư mục** (giữ `./support.js` relative) với `<link rel="stylesheet" href="../../styles.css">` + `<script src="../../_ds_bundle.js">` **static** trong raw `<head>` (cả hai inline được) thay `ds-base.js`, cộng `<template id="__bundler_thumbnail">`. Nướng ngôn ngữ đích vào props default. Rồi `super_inline_html`. |
|
|
69
69
|
| Bất kỳ | **Editor-native + Claude Code handoff** | Cả project sẵn sàng handoff-dev (compiled bundle + `.d.ts` + `prompt.md` mỗi component); generate package theo request qua handoff skill. |
|
|
70
70
|
|
package/docs/vi/quality-gates.md
CHANGED
|
@@ -52,7 +52,7 @@ Nguyên tắc benchmark (WCAG · APCA · OKLCH · DTCG · doctrine CDS + mở r
|
|
|
52
52
|
| Axe smoke | `_audit/axe-smoke.html` + `_audit/lib/axe-fixtures.js` | Rule serious/critical WCAG 2 A/AA của axe-core 4.10.0 (vendored tại `_audit/vendor/axe.min.js`) trên mọi public primary (fixture khoá inventory; bilingual EN·VI) — Dialog, AlertDialog, Drawer, Tour, CommandPalette và Menu mount mở, còn Cascader / TreeSelect / Menubar / Combobox được bung trước khi quét; tương đương enforcement a11y Storybook (không test-runner riêng) | 0 finding serious/critical (`__axesmoke`) | Hard | Fast board CI |
|
|
53
53
|
| Print smoke | `_audit/print-smoke.html` | **Every** `omelette-owns-print` document declares print-ownership meta and A4/Letter `@page` hooks the PDF/DOCX export path relies on | ≥60 print docs, 0 missing hooks (`__printsmoke`) | Hard | Fast board CI |
|
|
54
54
|
| Support no-eval (Node) | `_audit/ci/test-support-no-eval.mjs` | Canonical `templates/_vendor/support.js` + all template copies are identical and contain no Function-constructor / `eval(` call sites (CSP-safe inline-script runtime) | Exit 0 | Hard | Unit test |
|
|
55
|
-
| Doc export (Node+PW) | `_audit/ci/test-doc-export.mjs` |
|
|
55
|
+
| Doc export (Node+PW) | `_audit/ci/test-doc-export.mjs` | Mọi template in dưới CSP site: không EvalError, một menu Download (PDF\|DOCX), PDF Playwright `%PDF` + MediaBox A4/Letter, `buildPdfBlob` tải về là một trang FlateDecode không méo của sheet sống (framework), DOCX ZIP + `word/document.xml` + dấu VN + ≥70% chồng text sheet + fill vàng/colspan + text lockup header (HĐNT) trên framework | Exit 0 | Hard | Unit test |
|
|
56
56
|
| DOCX source parity (Node) | `_audit/ci/test-docx-source-parity.mjs` | DC text vs committed fixtures under `_audit/fixtures/hr-suite-docx-text/` for every mapped HR instrument | ≥85% phrase overlap; exit 0 | Hard | Unit test |
|
|
57
57
|
| Pixel CI | `_audit/pixel-ci.html` + `_audit/ci/pixel-diff.mjs` | 15 baseline curated tồn tại; script Playwright capture so sánh % pixel thật; report gần nhất phải sạch (`drifted[]` rỗng) | Hợp đồng + compare sạch (`__pixelci.pass`); drift hoặc thiếu report → fail | Hard | Fast board CI (bước compare nuôi hàng) + job `pixel-diff` |
|
|
58
58
|
|
package/docs/vi/release-notes.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Ghi chú phát hành
|
|
2
2
|
|
|
3
|
-
Điểm nổi bật sản phẩm cho operator — **không** phải git log và **không** phải `CHANGELOG.md`. Hệ thống thiết kế không maintain file changelog. VERSION **1.7.
|
|
3
|
+
Điểm nổi bật sản phẩm cho operator — **không** phải git log và **không** phải `CHANGELOG.md`. Hệ thống thiết kế không maintain file changelog. VERSION **1.7.2** (auto-bump khi push lên `main` từ Conventional Commits; owner vẫn có thể force bump). Chân lý kỹ thuật là tip repo; chân lý hướng sản phẩm là trang này (đồng bộ Storybook **Release Notes**). Xuất bản trên Storybook **Docs** tại `design.cyberskill.world`.
|
|
4
4
|
|
|
5
5
|
## Release — `@cyberskill/design@1.3.10`
|
|
6
6
|
|
package/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CyberSkill Design System
|
|
2
2
|
|
|
3
|
-
> HTML-first, Vietnamese-first design system, VERSION **1.7.
|
|
3
|
+
> HTML-first, Vietnamese-first design system, VERSION **1.7.2**. Immutable anchors: Umber #45210E · Ochre #F4BA17. Four independent axes — Theme (light · dark · system) × Element (Ngũ Hành, 15 variants) × Language (EN · VI) × Style (`data-cs-style` — sole pack **liquid-glass**; absent ≡ default). It ships 106 components / 122 exports, 85 copyable templates (EN·VN for emails + team/legal/finance; client/media collateral EN-first), and tokens in CSS + JSON + ESM + W3C DTCG + native mirrors. This file is the agent/tool front door: it maps each **capability** to the format it should consume. npm package name is **`@cyberskill/design`** (not `@cyberskill/react`). Release signal: tip SHA + [docs/release-notes.md](docs/release-notes.md) — VERSION **1.7.2**, no CHANGELOG.
|
|
4
4
|
|
|
5
5
|
The portable contract covers browser and bundler entry points: `styles.css` · `_esm/cs.mjs` legacy · `_ds_bundle.js` · tokens work without a build step; `_esm/react.mjs` is bundler-native JSX (Next/Vite must transpile — not a bare-browser import). The DC layer (`templates/**/*.dc.html`) needs a **Design Components compiler**. **Google Stitch must not treat `*.dc.html` as source of truth** — use `DESIGN.md`, DTCG, `styles.css`, kitchen-sink, and `.cs-*` static HTML instead. Dual path: [docs/consuming.md](docs/consuming.md). The full non-negotiables list lives in `CONTRIBUTING.md` and `docs/doctrine.md`. Operator docs are published on the Storybook **Docs** sidebar at `design.cyberskill.world`.
|
|
6
6
|
|
|
@@ -31,7 +31,7 @@ The portable contract covers browser and bundler entry points: `styles.css` · `
|
|
|
31
31
|
- [templates/](templates/): 85 copyable starting points (`.dc.html`); `email-safe/` send-ready emails; `kitchen-sink.html`; `playground.html`
|
|
32
32
|
- [guidelines/](guidelines/): specimen cards + `atomic-view.html` (portable component grid) — host product surface is Storybook at `/`
|
|
33
33
|
- [examples/static-hello/](examples/static-hello/): zero-install static consumer (Stitch / plain HTML)
|
|
34
|
-
- [examples/npm-hello/](examples/npm-hello/): first registry **browser** consumer — `@cyberskill/design@1.7.
|
|
34
|
+
- [examples/npm-hello/](examples/npm-hello/): first registry **browser** consumer — `@cyberskill/design@1.7.2` legacy entry (Lumi · Hỏa · plasma); Status Hub teams swap to `thuy`; Next/SSR apps use default `@cyberskill/design` React entry instead
|
|
35
35
|
- [examples/native/](examples/native/): SwiftUI / Compose / Flutter sample apps + store scaffolds — Compose is **Android Studio**-first (no committed `gradlew`; see `examples/native/README.md`)
|
|
36
36
|
- [ui_kits/](ui_kits/): product recreations — status-hub · website · deck
|
|
37
37
|
- [fonts/](fonts/): self-hosted Be Vietnam Pro (UI) + Space Grotesk (opt-in display, `--cs-font-family-display`) + JetBrains Mono woff2
|
|
@@ -48,7 +48,7 @@ The portable contract covers browser and bundler entry points: `styles.css` · `
|
|
|
48
48
|
Published on Storybook **Docs** (`design.cyberskill.world`) and in [docs/viewer.html](docs/viewer.html) (EN|VI).
|
|
49
49
|
|
|
50
50
|
- [docs/consuming.md](docs/consuming.md): adopting & upgrading, DC-capable vs static dual path, package name `@cyberskill/design`; first registry install at [examples/npm-hello/](examples/npm-hello/) (Lumi · Hỏa · plasma); native mirrors at [examples/native/](examples/native/) (SwiftUI / Compose / Flutter samples)
|
|
51
|
-
- [docs/release-notes.md](docs/release-notes.md): curated product highlights (not a changelog) — includes `@cyberskill/design@1.7.
|
|
51
|
+
- [docs/release-notes.md](docs/release-notes.md): curated product highlights (not a changelog) — includes `@cyberskill/design@1.7.2` Trusted Publishing / grant pointer
|
|
52
52
|
- [docs/consumer-grant.md](docs/consumer-grant.md): written npm grant (CyberSkill portfolio; UNLICENSED)
|
|
53
53
|
- [docs/conventions.md](docs/conventions.md): authoring rules (naming grammar, the four axes)
|
|
54
54
|
- [docs/design-styles.md](docs/design-styles.md): the live styling axes and the fixed liquid-glass treatment
|
package/package.json
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
(() => {
|
|
8
8
|
const UMBER = '45210E';
|
|
9
|
+
const DOC_FILL = 'FDE68A';
|
|
9
10
|
const A4 = { w: 11906, h: 16838, name: 'A4', ptW: 595.28, ptH: 841.89 };
|
|
10
11
|
const LETTER = { w: 12240, h: 15840, name: 'Letter', ptW: 612, ptH: 792 };
|
|
11
12
|
function pageSizeFromCss() {
|
|
@@ -123,23 +124,44 @@
|
|
|
123
124
|
return el.getAttribute && el.getAttribute('data-omelette-chrome') != null;
|
|
124
125
|
}
|
|
125
126
|
|
|
127
|
+
function isDocFillColor(bg) {
|
|
128
|
+
return bg && /rgb\(\s*253\s*,\s*230\s*,\s*138\s*\)/i.test(bg);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function rgbToHex(rgb) {
|
|
132
|
+
const m = rgb && String(rgb).match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i);
|
|
133
|
+
if (!m) return null;
|
|
134
|
+
const r = Number(m[1]);
|
|
135
|
+
const g = Number(m[2]);
|
|
136
|
+
const b = Number(m[3]);
|
|
137
|
+
if (r < 25 && g < 25 && b < 25) return null;
|
|
138
|
+
const hex = [r, g, b].map((n) => n.toString(16).padStart(2, '0')).join('').toUpperCase();
|
|
139
|
+
return hex === '000000' ? null : hex;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function halfPt(fontSize) {
|
|
143
|
+
const px = parseFloat(fontSize);
|
|
144
|
+
if (!px) return null;
|
|
145
|
+
return Math.max(14, Math.round((px * 72) / 96) * 2);
|
|
146
|
+
}
|
|
147
|
+
|
|
126
148
|
function textRuns(el) {
|
|
127
149
|
const parts = [];
|
|
128
|
-
const walk = (node, italic, bold, color) => {
|
|
150
|
+
const walk = (node, italic, bold, color, fill, size) => {
|
|
129
151
|
if (node.nodeType === 3) {
|
|
130
152
|
const raw = node.textContent || '';
|
|
131
153
|
if (!raw) return;
|
|
132
154
|
if (!raw.replace(/\s+/g, '').length) {
|
|
133
|
-
if (parts.length) parts.push({ t: ' ', italic, bold, color });
|
|
155
|
+
if (parts.length) parts.push({ t: ' ', italic, bold, color, fill, size });
|
|
134
156
|
return;
|
|
135
157
|
}
|
|
136
|
-
parts.push({ t: raw.replace(/\s+/g, ' '), italic, bold, color });
|
|
158
|
+
parts.push({ t: raw.replace(/\s+/g, ' '), italic, bold, color, fill, size });
|
|
137
159
|
return;
|
|
138
160
|
}
|
|
139
161
|
if (node.nodeType !== 1) return;
|
|
140
162
|
if (isChrome(node)) return;
|
|
141
163
|
const tag = node.tagName.toLowerCase();
|
|
142
|
-
if (tag === 'script' || tag === 'style' || tag === 'noscript') return;
|
|
164
|
+
if (tag === 'script' || tag === 'style' || tag === 'noscript' || tag === 'svg') return;
|
|
143
165
|
const st = window.getComputedStyle(node);
|
|
144
166
|
const nextItalic = italic || st.fontStyle === 'italic' || tag === 'i' || tag === 'em';
|
|
145
167
|
const nextBold =
|
|
@@ -151,10 +173,33 @@
|
|
|
151
173
|
let nextColor = color;
|
|
152
174
|
if (/^h[1-6]$/.test(tag) || (st.color && /rgb\(\s*69\s*,\s*33\s*,\s*14\s*\)/.test(st.color))) {
|
|
153
175
|
nextColor = UMBER;
|
|
176
|
+
} else {
|
|
177
|
+
nextColor = rgbToHex(st.color) || color;
|
|
178
|
+
}
|
|
179
|
+
const nextFill = fill || (isDocFillColor(st.backgroundColor) ? DOC_FILL : null);
|
|
180
|
+
const nextSize = halfPt(st.fontSize) || size;
|
|
181
|
+
const kids = [...node.childNodes];
|
|
182
|
+
for (let i = 0; i < kids.length; i++) {
|
|
183
|
+
const before = parts.length;
|
|
184
|
+
walk(kids[i], nextItalic, nextBold, nextColor, nextFill, nextSize);
|
|
185
|
+
const nxt = kids[i + 1];
|
|
186
|
+
if (parts.length > before && nxt) {
|
|
187
|
+
const last = parts[parts.length - 1];
|
|
188
|
+
const nextRaw = nxt.textContent || '';
|
|
189
|
+
if (last && last.t && !/\s$/.test(last.t) && nextRaw.replace(/\s+/g, '') && !/^\s/.test(nextRaw)) {
|
|
190
|
+
parts.push({
|
|
191
|
+
t: ' ',
|
|
192
|
+
italic: nextItalic,
|
|
193
|
+
bold: nextBold,
|
|
194
|
+
color: nextColor,
|
|
195
|
+
fill: nextFill,
|
|
196
|
+
size: nextSize,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
154
200
|
}
|
|
155
|
-
for (const c of node.childNodes) walk(c, nextItalic, nextBold, nextColor);
|
|
156
201
|
};
|
|
157
|
-
walk(el, false, false, null);
|
|
202
|
+
walk(el, false, false, null, null, null);
|
|
158
203
|
const merged = [];
|
|
159
204
|
for (const r of parts) {
|
|
160
205
|
const prev = merged[merged.length - 1];
|
|
@@ -162,7 +207,9 @@
|
|
|
162
207
|
prev &&
|
|
163
208
|
prev.italic === r.italic &&
|
|
164
209
|
prev.bold === r.bold &&
|
|
165
|
-
prev.color === r.color
|
|
210
|
+
prev.color === r.color &&
|
|
211
|
+
prev.fill === r.fill &&
|
|
212
|
+
prev.size === r.size
|
|
166
213
|
) {
|
|
167
214
|
prev.t += r.t;
|
|
168
215
|
} else {
|
|
@@ -182,6 +229,8 @@
|
|
|
182
229
|
if (r.bold) rPr.push('<w:b/>');
|
|
183
230
|
if (r.italic) rPr.push('<w:i/>');
|
|
184
231
|
if (r.color) rPr.push(`<w:color w:val="${r.color}"/>`);
|
|
232
|
+
if (r.fill) rPr.push(`<w:shd w:val="clear" w:fill="${r.fill}"/><w:highlight w:val="yellow"/>`);
|
|
233
|
+
if (r.size) rPr.push(`<w:sz w:val="${r.size}"/><w:szCs w:val="${r.size}"/>`);
|
|
185
234
|
rPr.push('<w:rFonts w:ascii="Arial" w:hAnsi="Arial" w:cs="Arial"/>');
|
|
186
235
|
const pr = rPr.length ? `<w:rPr>${rPr.join('')}</w:rPr>` : '';
|
|
187
236
|
return `<w:r>${pr}<w:t xml:space="preserve">${xmlEscape(r.t)}</w:t></w:r>`;
|
|
@@ -189,11 +238,25 @@
|
|
|
189
238
|
.join('');
|
|
190
239
|
}
|
|
191
240
|
|
|
241
|
+
function pPrXml(el, style) {
|
|
242
|
+
const bits = [];
|
|
243
|
+
if (style) bits.push(`<w:pStyle w:val="${style}"/>`);
|
|
244
|
+
if (el) {
|
|
245
|
+
const st = window.getComputedStyle(el);
|
|
246
|
+
const ta = st.textAlign;
|
|
247
|
+
if (ta === 'center') bits.push('<w:jc w:val="center"/>');
|
|
248
|
+
else if (ta === 'right' || ta === 'end') bits.push('<w:jc w:val="right"/>');
|
|
249
|
+
const before = Math.max(0, Math.round((parseFloat(st.marginTop) || 0) * 15));
|
|
250
|
+
const after = Math.max(0, Math.round((parseFloat(st.marginBottom) || 0) * 15));
|
|
251
|
+
if (before || after) bits.push(`<w:spacing w:before="${before}" w:after="${after}"/>`);
|
|
252
|
+
}
|
|
253
|
+
return bits.length ? `<w:pPr>${bits.join('')}</w:pPr>` : '';
|
|
254
|
+
}
|
|
255
|
+
|
|
192
256
|
function paraXml(el, style) {
|
|
193
257
|
const runs = textRuns(el);
|
|
194
258
|
if (!runs.length && !el.querySelector?.('br')) return '';
|
|
195
|
-
|
|
196
|
-
return `<w:p>${pPr}${runsToXml(runs)}</w:p>`;
|
|
259
|
+
return `<w:p>${pPrXml(el, style)}${runsToXml(runs)}</w:p>`;
|
|
197
260
|
}
|
|
198
261
|
|
|
199
262
|
function cellInnerXml(cell, fillWhite) {
|
|
@@ -214,11 +277,32 @@
|
|
|
214
277
|
return `<w:p>${runsToXml(paint(textRuns(cell)))}</w:p>`;
|
|
215
278
|
}
|
|
216
279
|
|
|
280
|
+
function cellColSpan(cell) {
|
|
281
|
+
return Math.max(1, Number(cell.getAttribute('colspan')) || 1);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function rowColCount(tr) {
|
|
285
|
+
return [...tr.children].reduce((n, c) => n + cellColSpan(c), 0);
|
|
286
|
+
}
|
|
287
|
+
|
|
217
288
|
function tableXml(table) {
|
|
218
289
|
const rows = [...table.querySelectorAll(':scope > tbody > tr, :scope > thead > tr, :scope > tr')];
|
|
219
290
|
if (!rows.length) return '';
|
|
220
|
-
const gridCols = Math.max(...rows.map(
|
|
221
|
-
|
|
291
|
+
const gridCols = Math.max(...rows.map(rowColCount), 1);
|
|
292
|
+
let colWidths;
|
|
293
|
+
if (gridCols === 2) {
|
|
294
|
+
const tableW = table.getBoundingClientRect().width || 1;
|
|
295
|
+
const sample = rows.find((r) => r.children.length >= 2) || rows[0];
|
|
296
|
+
const c0 = sample && sample.children[0];
|
|
297
|
+
const ratio = c0 ? c0.getBoundingClientRect().width / tableW : 0.28;
|
|
298
|
+
const col0 = Math.round(9000 * Math.min(0.42, Math.max(0.18, ratio)));
|
|
299
|
+
colWidths = [col0, 9000 - col0];
|
|
300
|
+
} else {
|
|
301
|
+
const even = Math.floor(9000 / gridCols);
|
|
302
|
+
colWidths = Array.from({ length: gridCols }, () => even);
|
|
303
|
+
}
|
|
304
|
+
const gridColsXml = colWidths.map((w) => `<w:gridCol w:w="${w}"/>`).join('');
|
|
305
|
+
const colW = colWidths[0];
|
|
222
306
|
let xml = `<w:tbl><w:tblPr><w:tblW w:w="5000" w:type="pct"/><w:tblBorders>
|
|
223
307
|
<w:top w:val="single" w:sz="4" w:color="C9B8A8"/>
|
|
224
308
|
<w:left w:val="single" w:sz="4" w:color="C9B8A8"/>
|
|
@@ -226,16 +310,22 @@
|
|
|
226
310
|
<w:right w:val="single" w:sz="4" w:color="C9B8A8"/>
|
|
227
311
|
<w:insideH w:val="single" w:sz="4" w:color="C9B8A8"/>
|
|
228
312
|
<w:insideV w:val="single" w:sz="4" w:color="C9B8A8"/>
|
|
229
|
-
</w:tblBorders></w:tblPr><w:tblGrid>${
|
|
313
|
+
</w:tblBorders></w:tblPr><w:tblGrid>${gridColsXml}</w:tblGrid>`;
|
|
230
314
|
for (const tr of rows) {
|
|
231
315
|
xml += '<w:tr>';
|
|
232
316
|
for (const cell of tr.children) {
|
|
233
317
|
const bg = window.getComputedStyle(cell).backgroundColor;
|
|
234
318
|
const umberFill = bg && /rgb\(\s*69\s*,\s*33\s*,\s*14\s*\)/.test(bg);
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
319
|
+
const yellowFill = isDocFillColor(bg);
|
|
320
|
+
const span = cellColSpan(cell);
|
|
321
|
+
const spanXml = span > 1 ? `<w:gridSpan w:val="${span}"/>` : '';
|
|
322
|
+
const fillXml = umberFill
|
|
323
|
+
? `<w:shd w:val="clear" w:fill="${UMBER}"/>`
|
|
324
|
+
: yellowFill
|
|
325
|
+
? `<w:shd w:val="clear" w:fill="${DOC_FILL}"/>`
|
|
326
|
+
: '';
|
|
327
|
+
const tw = colWidths.slice(0, span).reduce((n, w) => n + w, 0);
|
|
328
|
+
xml += `<w:tc><w:tcPr>${fillXml}${spanXml}<w:tcW w:w="${tw}" w:type="dxa"/></w:tcPr>${cellInnerXml(cell, umberFill)}</w:tc>`;
|
|
239
329
|
}
|
|
240
330
|
xml += '</w:tr>';
|
|
241
331
|
}
|
|
@@ -257,10 +347,11 @@
|
|
|
257
347
|
const kids = [...el.children].filter((c) => c.nodeType === 1 && !isChrome(c));
|
|
258
348
|
if (kids.length < 2) return '';
|
|
259
349
|
const colW = Math.floor(9000 / cols);
|
|
350
|
+
const gridColsXml = Array.from({ length: cols }, () => `<w:gridCol w:w="${colW}"/>`).join('');
|
|
260
351
|
let xml = `<w:tbl><w:tblPr><w:tblW w:w="5000" w:type="pct"/><w:tblBorders>
|
|
261
352
|
<w:top w:val="nil"/><w:left w:val="nil"/><w:bottom w:val="nil"/><w:right w:val="nil"/>
|
|
262
353
|
<w:insideH w:val="nil"/><w:insideV w:val="nil"/>
|
|
263
|
-
</w:tblBorders></w:tblPr><w:tblGrid>${
|
|
354
|
+
</w:tblBorders></w:tblPr><w:tblGrid>${gridColsXml}</w:tblGrid>`;
|
|
264
355
|
for (let i = 0; i < kids.length; i += cols) {
|
|
265
356
|
xml += '<w:tr>';
|
|
266
357
|
for (let c = 0; c < cols; c++) {
|
|
@@ -274,19 +365,168 @@
|
|
|
274
365
|
return xml;
|
|
275
366
|
}
|
|
276
367
|
|
|
277
|
-
function
|
|
368
|
+
function drawingRun(relId, cx, cy) {
|
|
369
|
+
return `<w:r><w:drawing>
|
|
370
|
+
<wp:inline distT="0" distB="0" distL="0" distR="0">
|
|
371
|
+
<wp:extent cx="${cx}" cy="${cy}"/>
|
|
372
|
+
<wp:docPr id="${relId.replace(/\D/g, '') || '1'}" name="img"/>
|
|
373
|
+
<a:graphic>
|
|
374
|
+
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
|
|
375
|
+
<pic:pic>
|
|
376
|
+
<pic:nvPicPr><pic:cNvPr id="0" name="image.png"/><pic:cNvPicPr/></pic:nvPicPr>
|
|
377
|
+
<pic:blipFill><a:blip r:embed="${relId}"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill>
|
|
378
|
+
<pic:spPr>
|
|
379
|
+
<a:xfrm><a:off x="0" y="0"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm>
|
|
380
|
+
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
|
|
381
|
+
</pic:spPr>
|
|
382
|
+
</pic:pic>
|
|
383
|
+
</a:graphicData>
|
|
384
|
+
</a:graphic>
|
|
385
|
+
</wp:inline>
|
|
386
|
+
</w:drawing></w:r>`;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function findSvg(el) {
|
|
390
|
+
if (!el || el.nodeType !== 1) return null;
|
|
391
|
+
if (el.tagName.toLowerCase() === 'svg') return el;
|
|
392
|
+
const light = el.querySelector?.('svg');
|
|
393
|
+
if (light) return light;
|
|
394
|
+
if (el.shadowRoot) {
|
|
395
|
+
const sh = el.shadowRoot.querySelector('svg');
|
|
396
|
+
if (sh) return sh;
|
|
397
|
+
}
|
|
398
|
+
for (const c of el.children || []) {
|
|
399
|
+
const nested = findSvg(c);
|
|
400
|
+
if (nested) return nested;
|
|
401
|
+
}
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
async function addSvgPng(svg, bag) {
|
|
406
|
+
const box = svg.getBoundingClientRect();
|
|
407
|
+
const cssW = Math.max(box.width || parseFloat(svg.getAttribute('width')) || 18, 12);
|
|
408
|
+
const cssH = Math.max(box.height || parseFloat(svg.getAttribute('height')) || cssW, 12);
|
|
409
|
+
const scale = 3;
|
|
410
|
+
const w = Math.max(1, Math.round(cssW * scale));
|
|
411
|
+
const h = Math.max(1, Math.round(cssH * scale));
|
|
412
|
+
try {
|
|
413
|
+
const clone = svg.cloneNode(true);
|
|
414
|
+
clone.setAttribute('width', String(cssW));
|
|
415
|
+
clone.setAttribute('height', String(cssH));
|
|
416
|
+
if (!clone.getAttribute('xmlns')) clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
|
|
417
|
+
const xml = new XMLSerializer().serializeToString(clone);
|
|
418
|
+
if (/foreignObject/i.test(xml)) return '';
|
|
419
|
+
const blob = new Blob([xml], { type: 'image/svg+xml;charset=utf-8' });
|
|
420
|
+
const url = URL.createObjectURL(blob);
|
|
421
|
+
try {
|
|
422
|
+
const img = await loadImage(url);
|
|
423
|
+
const c = document.createElement('canvas');
|
|
424
|
+
c.width = w;
|
|
425
|
+
c.height = h;
|
|
426
|
+
const ctx = c.getContext('2d');
|
|
427
|
+
ctx.drawImage(img, 0, 0, w, h);
|
|
428
|
+
const bytes = dataUrlToBytes(c.toDataURL('image/png'));
|
|
429
|
+
const n = bag.media.length + 1;
|
|
430
|
+
const relId = `rIdImg${n}`;
|
|
431
|
+
bag.media.push({ name: `word/media/image${n}.png`, bytes, relId });
|
|
432
|
+
const emu = Math.round(cssW * 9525);
|
|
433
|
+
return drawingRun(relId, emu, Math.round(emu * (h / w)));
|
|
434
|
+
} finally {
|
|
435
|
+
URL.revokeObjectURL(url);
|
|
436
|
+
}
|
|
437
|
+
} catch (_) {
|
|
438
|
+
return '';
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async function groupInnerXml(els, bag) {
|
|
443
|
+
let drawings = '';
|
|
444
|
+
const textEls = [];
|
|
445
|
+
for (const el of els) {
|
|
446
|
+
const svg = findSvg(el);
|
|
447
|
+
if (svg) drawings += await addSvgPng(svg, bag);
|
|
448
|
+
if (!svg || textRuns(el).length) textEls.push(el);
|
|
449
|
+
}
|
|
450
|
+
let runs = [];
|
|
451
|
+
for (const el of textEls) {
|
|
452
|
+
const next = textRuns(el);
|
|
453
|
+
if (
|
|
454
|
+
runs.length &&
|
|
455
|
+
next.length &&
|
|
456
|
+
!/\s$/.test(runs[runs.length - 1].t) &&
|
|
457
|
+
!/^\s/.test(next[0].t)
|
|
458
|
+
) {
|
|
459
|
+
runs.push({
|
|
460
|
+
t: ' ',
|
|
461
|
+
italic: next[0].italic,
|
|
462
|
+
bold: next[0].bold,
|
|
463
|
+
color: next[0].color,
|
|
464
|
+
fill: next[0].fill,
|
|
465
|
+
size: next[0].size,
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
runs.push(...next);
|
|
469
|
+
}
|
|
470
|
+
if (!drawings && !runs.length) return `<w:p>${runsToXml([])}</w:p>`;
|
|
471
|
+
return `<w:p>${pPrXml(textEls[0] || els[0])}${drawings}${runsToXml(runs)}</w:p>`;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
async function flexAsTable(el, bag) {
|
|
475
|
+
const st = window.getComputedStyle(el);
|
|
476
|
+
if (st.display !== 'flex' && st.display !== 'inline-flex') return '';
|
|
477
|
+
const dir = st.flexDirection || 'row';
|
|
478
|
+
if (dir === 'column' || dir === 'column-reverse') return '';
|
|
479
|
+
const kids = [...el.children].filter((c) => c.nodeType === 1 && !isChrome(c));
|
|
480
|
+
if (kids.length < 2) return '';
|
|
481
|
+
const hasLogo = kids.some((c) => {
|
|
482
|
+
const t = c.tagName.toLowerCase();
|
|
483
|
+
return t === 'svg' || t === 'x-import' || !!findSvg(c);
|
|
484
|
+
});
|
|
485
|
+
if (!hasLogo && kids.length !== 2) return '';
|
|
486
|
+
let split = -1;
|
|
487
|
+
for (let i = 1; i < kids.length; i++) {
|
|
488
|
+
const inline = kids[i].style?.marginLeft || '';
|
|
489
|
+
const attr = kids[i].getAttribute?.('style') || '';
|
|
490
|
+
if (inline === 'auto' || /margin-left\s*:\s*auto/i.test(attr)) {
|
|
491
|
+
split = i;
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
if (split < 0) {
|
|
496
|
+
if (kids.length === 2) split = 1;
|
|
497
|
+
else return '';
|
|
498
|
+
}
|
|
499
|
+
const left = await groupInnerXml(kids.slice(0, split), bag);
|
|
500
|
+
const right = await groupInnerXml(kids.slice(split), bag);
|
|
501
|
+
return `<w:tbl><w:tblPr><w:tblW w:w="5000" w:type="pct"/><w:tblBorders>
|
|
502
|
+
<w:top w:val="nil"/><w:left w:val="nil"/><w:bottom w:val="nil"/><w:right w:val="nil"/>
|
|
503
|
+
<w:insideH w:val="nil"/><w:insideV w:val="nil"/>
|
|
504
|
+
</w:tblBorders></w:tblPr><w:tblGrid><w:gridCol w:w="6200"/><w:gridCol w:w="2800"/></w:tblGrid>
|
|
505
|
+
<w:tr>
|
|
506
|
+
<w:tc><w:tcPr><w:tcW w:w="6200" w:type="dxa"/></w:tcPr>${left}</w:tc>
|
|
507
|
+
<w:tc><w:tcPr><w:tcW w:w="2800" w:type="dxa"/></w:tcPr>${right}</w:tc>
|
|
508
|
+
</w:tr></w:tbl>`;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
async function sheetBodyXml(sheet, bag) {
|
|
278
512
|
const blocks = [];
|
|
279
|
-
const visit = (nodes) => {
|
|
513
|
+
const visit = async (nodes) => {
|
|
280
514
|
for (const el of nodes) {
|
|
281
515
|
if (el.nodeType !== 1) continue;
|
|
282
516
|
if (isChrome(el)) continue;
|
|
283
517
|
const tag = el.tagName.toLowerCase();
|
|
518
|
+
const svg = findSvg(el);
|
|
519
|
+
if (svg && (tag === 'svg' || !textRuns(el).length)) {
|
|
520
|
+
const drawing = await addSvgPng(svg, bag);
|
|
521
|
+
if (drawing) blocks.push(`<w:p>${drawing}</w:p>`);
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
284
524
|
if (tag === 'table') {
|
|
285
525
|
blocks.push(tableXml(el));
|
|
286
526
|
continue;
|
|
287
527
|
}
|
|
288
528
|
if (/^h[1-6]$/.test(tag)) {
|
|
289
|
-
blocks.push(paraXml(el, 'Heading1'));
|
|
529
|
+
blocks.push(paraXml(el, tag === 'h1' ? 'Heading1' : 'Heading2'));
|
|
290
530
|
continue;
|
|
291
531
|
}
|
|
292
532
|
const gridXml = gridAsTable(el);
|
|
@@ -294,12 +534,17 @@
|
|
|
294
534
|
blocks.push(gridXml);
|
|
295
535
|
continue;
|
|
296
536
|
}
|
|
537
|
+
const flexXml = await flexAsTable(el, bag);
|
|
538
|
+
if (flexXml) {
|
|
539
|
+
blocks.push(flexXml);
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
297
542
|
if (tag === 'p' || tag === 'div' || tag === 'section' || tag === 'li') {
|
|
298
543
|
const hasBlock = [...el.children].some((c) =>
|
|
299
|
-
/^(DIV|TABLE|SECTION|UL|OL|H1|H2|H3|H4|H5|H6)$/.test(c.tagName),
|
|
544
|
+
/^(DIV|TABLE|SECTION|UL|OL|H1|H2|H3|H4|H5|H6|X-IMPORT)$/.test(c.tagName),
|
|
300
545
|
);
|
|
301
546
|
if (hasBlock && tag !== 'p') {
|
|
302
|
-
visit([...el.children]);
|
|
547
|
+
await visit([...el.children]);
|
|
303
548
|
} else {
|
|
304
549
|
const px = paraXml(el);
|
|
305
550
|
if (px) blocks.push(px);
|
|
@@ -307,33 +552,38 @@
|
|
|
307
552
|
continue;
|
|
308
553
|
}
|
|
309
554
|
if (tag === 'ul' || tag === 'ol') {
|
|
310
|
-
visit([...el.children]);
|
|
555
|
+
await visit([...el.children]);
|
|
311
556
|
continue;
|
|
312
557
|
}
|
|
313
|
-
|
|
558
|
+
const leftover = paraXml(el);
|
|
559
|
+
if (leftover) blocks.push(leftover);
|
|
560
|
+
else await visit([...el.children]);
|
|
314
561
|
}
|
|
315
562
|
};
|
|
316
|
-
visit([...sheet.children]);
|
|
563
|
+
await visit([...sheet.children]);
|
|
317
564
|
return blocks.filter(Boolean).join('');
|
|
318
565
|
}
|
|
319
566
|
|
|
320
567
|
function headerFooterText() {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
};
|
|
568
|
+
// Sheet already carries lockup + footer. Word chrome stays empty so the
|
|
569
|
+
// file does not duplicate the card into header/footer.
|
|
570
|
+
return { header: '', footer: '' };
|
|
325
571
|
}
|
|
326
572
|
|
|
327
573
|
async function buildDocxBlob(sheet) {
|
|
328
574
|
const page = pageSizeFromCss();
|
|
329
575
|
const enc = new TextEncoder();
|
|
330
576
|
const { header, footer } = headerFooterText();
|
|
331
|
-
const
|
|
577
|
+
const bag = { media: [] };
|
|
578
|
+
const body = await sheetBodyXml(sheet, bag);
|
|
332
579
|
|
|
580
|
+
const pngDefault = bag.media.length
|
|
581
|
+
? `\n <Default Extension="png" ContentType="image/png"/>`
|
|
582
|
+
: '';
|
|
333
583
|
const contentTypes = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
334
584
|
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
|
335
585
|
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
|
336
|
-
<Default Extension="xml" ContentType="application/xml"
|
|
586
|
+
<Default Extension="xml" ContentType="application/xml"/>${pngDefault}
|
|
337
587
|
<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
|
|
338
588
|
<Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>
|
|
339
589
|
<Override PartName="/word/header1.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml"/>
|
|
@@ -345,11 +595,18 @@
|
|
|
345
595
|
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
|
|
346
596
|
</Relationships>`;
|
|
347
597
|
|
|
598
|
+
const mediaRels = bag.media
|
|
599
|
+
.map(
|
|
600
|
+
(m) =>
|
|
601
|
+
` <Relationship Id="${m.relId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/${m.name.split('/').pop()}"/>`,
|
|
602
|
+
)
|
|
603
|
+
.join('\n');
|
|
348
604
|
const docRels = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
349
605
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
350
606
|
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
|
|
351
607
|
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header1.xml"/>
|
|
352
608
|
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" Target="footer1.xml"/>
|
|
609
|
+
${mediaRels}
|
|
353
610
|
</Relationships>`;
|
|
354
611
|
|
|
355
612
|
const styles = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
@@ -362,37 +619,35 @@
|
|
|
362
619
|
<w:name w:val="heading 1"/><w:basedOn w:val="Normal"/><w:qFormat/>
|
|
363
620
|
<w:rPr><w:b/><w:color w:val="${UMBER}"/><w:sz w:val="28"/></w:rPr>
|
|
364
621
|
</w:style>
|
|
622
|
+
<w:style w:type="paragraph" w:styleId="Heading2">
|
|
623
|
+
<w:name w:val="heading 2"/><w:basedOn w:val="Normal"/><w:qFormat/>
|
|
624
|
+
<w:rPr><w:b/><w:color w:val="${UMBER}"/><w:sz w:val="24"/></w:rPr>
|
|
625
|
+
</w:style>
|
|
365
626
|
</w:styles>`;
|
|
366
627
|
|
|
367
628
|
const headerXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
368
629
|
<w:hdr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
|
369
|
-
<w:p
|
|
370
|
-
<w:r><w:rPr><w:b/><w:color w:val="${UMBER}"/><w:sz w:val="18"/></w:rPr>
|
|
371
|
-
<w:t xml:space="preserve">${xmlEscape(header)}</w:t></w:r>
|
|
372
|
-
</w:p>
|
|
630
|
+
<w:p>${header ? `<w:r><w:t xml:space="preserve">${xmlEscape(header)}</w:t></w:r>` : ''}</w:p>
|
|
373
631
|
</w:hdr>`;
|
|
374
632
|
|
|
375
633
|
const footerXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
376
634
|
<w:ftr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
|
377
|
-
<w:p>
|
|
378
|
-
<w:r><w:rPr><w:sz w:val="16"/><w:color w:val="6B5D4F"/></w:rPr>
|
|
379
|
-
<w:t xml:space="preserve">${xmlEscape(footer)} · </w:t></w:r>
|
|
380
|
-
<w:r><w:fldChar w:fldCharType="begin"/></w:r>
|
|
381
|
-
<w:r><w:instrText xml:space="preserve"> PAGE </w:instrText></w:r>
|
|
382
|
-
<w:r><w:fldChar w:fldCharType="end"/></w:r>
|
|
383
|
-
</w:p>
|
|
635
|
+
<w:p>${footer ? `<w:r><w:t xml:space="preserve">${xmlEscape(footer)}</w:t></w:r>` : ''}</w:p>
|
|
384
636
|
</w:ftr>`;
|
|
385
637
|
|
|
386
638
|
const documentXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
387
639
|
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
|
388
|
-
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
|
640
|
+
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
|
641
|
+
xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
|
|
642
|
+
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
|
|
643
|
+
xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
|
|
389
644
|
<w:body>
|
|
390
645
|
${body || '<w:p><w:r><w:t></w:t></w:r></w:p>'}
|
|
391
646
|
<w:sectPr>
|
|
392
647
|
<w:headerReference w:type="default" r:id="rId2"/>
|
|
393
648
|
<w:footerReference w:type="default" r:id="rId3"/>
|
|
394
649
|
<w:pgSz w:w="${page.w}" w:h="${page.h}"/>
|
|
395
|
-
<w:pgMar w:top="
|
|
650
|
+
<w:pgMar w:top="360" w:right="360" w:bottom="360" w:left="360" w:header="0" w:footer="0"/>
|
|
396
651
|
</w:sectPr>
|
|
397
652
|
</w:body>
|
|
398
653
|
</w:document>`;
|
|
@@ -405,6 +660,7 @@
|
|
|
405
660
|
{ name: 'word/styles.xml', bytes: enc.encode(styles) },
|
|
406
661
|
{ name: 'word/header1.xml', bytes: enc.encode(headerXml) },
|
|
407
662
|
{ name: 'word/footer1.xml', bytes: enc.encode(footerXml) },
|
|
663
|
+
...bag.media.map((m) => ({ name: m.name, bytes: m.bytes })),
|
|
408
664
|
]);
|
|
409
665
|
return new Blob([zip], {
|
|
410
666
|
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
@@ -461,7 +717,7 @@
|
|
|
461
717
|
return out;
|
|
462
718
|
}
|
|
463
719
|
|
|
464
|
-
function
|
|
720
|
+
function imagePagesToPdf(pages, mediaW, mediaH) {
|
|
465
721
|
const enc = new TextEncoder();
|
|
466
722
|
const nl = enc.encode('\n');
|
|
467
723
|
const chunks = [enc.encode('%PDF-1.4\n')];
|
|
@@ -493,10 +749,11 @@
|
|
|
493
749
|
pageId,
|
|
494
750
|
`<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${mediaW.toFixed(2)} ${mediaH.toFixed(2)}] /Resources << /XObject << /Im0 ${imgId} 0 R >> >> /Contents ${contentId} 0 R >>`,
|
|
495
751
|
);
|
|
752
|
+
const filter = page.filter || 'FlateDecode';
|
|
496
753
|
pushObj(
|
|
497
754
|
imgId,
|
|
498
|
-
`<< /Type /XObject /Subtype /Image /Width ${page.w} /Height ${page.h} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter
|
|
499
|
-
page.
|
|
755
|
+
`<< /Type /XObject /Subtype /Image /Width ${page.w} /Height ${page.h} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /${filter} /Length ${page.bytes.length} >>`,
|
|
756
|
+
page.bytes,
|
|
500
757
|
);
|
|
501
758
|
const contentBytes = enc.encode(content);
|
|
502
759
|
pushObj(contentId, `<< /Length ${contentBytes.length} >>`, contentBytes);
|
|
@@ -518,6 +775,27 @@
|
|
|
518
775
|
return concatBytes([body, enc.encode(xref), enc.encode(trailer)]);
|
|
519
776
|
}
|
|
520
777
|
|
|
778
|
+
function canvasRgb(ctx, w, h) {
|
|
779
|
+
const src = ctx.getImageData(0, 0, w, h).data;
|
|
780
|
+
const rgb = new Uint8Array(w * h * 3);
|
|
781
|
+
let j = 0;
|
|
782
|
+
for (let i = 0; i < src.length; i += 4) {
|
|
783
|
+
rgb[j++] = src[i];
|
|
784
|
+
rgb[j++] = src[i + 1];
|
|
785
|
+
rgb[j++] = src[i + 2];
|
|
786
|
+
}
|
|
787
|
+
return rgb;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
async function deflateZlib(u8) {
|
|
791
|
+
const cs = new CompressionStream('deflate');
|
|
792
|
+
const writer = cs.writable.getWriter();
|
|
793
|
+
writer.write(u8);
|
|
794
|
+
writer.close();
|
|
795
|
+
const ab = await new Response(cs.readable).arrayBuffer();
|
|
796
|
+
return new Uint8Array(ab);
|
|
797
|
+
}
|
|
798
|
+
|
|
521
799
|
function relBox(el, origin, sheet) {
|
|
522
800
|
const r = el.getBoundingClientRect();
|
|
523
801
|
return {
|
|
@@ -640,9 +918,15 @@
|
|
|
640
918
|
|
|
641
919
|
async function rasterizeSheet(sheet) {
|
|
642
920
|
const page = pageSizeFromCss();
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
921
|
+
let scale = 3;
|
|
922
|
+
let painted;
|
|
923
|
+
try {
|
|
924
|
+
painted = await paintSheet(sheet, scale);
|
|
925
|
+
} catch (_) {
|
|
926
|
+
scale = 2;
|
|
927
|
+
painted = await paintSheet(sheet, scale);
|
|
928
|
+
}
|
|
929
|
+
const { canvas, ctx } = painted;
|
|
646
930
|
let ink = true;
|
|
647
931
|
try {
|
|
648
932
|
ink = canvasHasInk(ctx, canvas.width, Math.min(canvas.height, 400));
|
|
@@ -650,28 +934,26 @@
|
|
|
650
934
|
ink = true;
|
|
651
935
|
}
|
|
652
936
|
if (!ink) throw new Error('blank-raster');
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
h:
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
}
|
|
673
|
-
if (!pages.length) throw new Error('no-pages');
|
|
674
|
-
return jpegPagesToPdf(pages, page.ptW, page.ptH);
|
|
937
|
+
// One PDF page = the whole card. Lossless Flate RGB (not JPEG) so type
|
|
938
|
+
// stays sharp; scale 3 ≈ 288 dpi on the A4-width MediaBox.
|
|
939
|
+
const ptW = page.ptW;
|
|
940
|
+
const ptH = ptW * (canvas.height / canvas.width);
|
|
941
|
+
try {
|
|
942
|
+
const rgb = canvasRgb(ctx, canvas.width, canvas.height);
|
|
943
|
+
const bytes = await deflateZlib(rgb);
|
|
944
|
+
return imagePagesToPdf(
|
|
945
|
+
[{ bytes, w: canvas.width, h: canvas.height, filter: 'FlateDecode' }],
|
|
946
|
+
ptW,
|
|
947
|
+
ptH,
|
|
948
|
+
);
|
|
949
|
+
} catch (_) {
|
|
950
|
+
const jpeg = dataUrlToBytes(canvas.toDataURL('image/jpeg', 0.95));
|
|
951
|
+
return imagePagesToPdf(
|
|
952
|
+
[{ bytes: jpeg, w: canvas.width, h: canvas.height, filter: 'DCTDecode' }],
|
|
953
|
+
ptW,
|
|
954
|
+
ptH,
|
|
955
|
+
);
|
|
956
|
+
}
|
|
675
957
|
}
|
|
676
958
|
|
|
677
959
|
async function buildPdfBlob(sheet) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$meta": {
|
|
3
3
|
"system": "CyberSkill Design System",
|
|
4
|
-
"version": "1.7.
|
|
4
|
+
"version": "1.7.2",
|
|
5
5
|
"note": "OKLCH seed contract for the 15 element packs × light/dark (30 sets). SoT for scripts/generate-element-packs.mjs — do not hand-edit tokens/elements.css. Owner bar (Jul 2026): soft/middle/deep clearly distinct; middle intensity synced across elements; harmonious role palettes; light↔dark same-hue identity. Public variant names unchanged."
|
|
6
6
|
},
|
|
7
7
|
"intensity": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// CyberSkill Design System — native design tokens.
|
|
2
2
|
// GENERATED from tokens/tokens.dtcg.json — do not hand-edit; regenerate on token change.
|
|
3
|
-
// release v1.7.
|
|
3
|
+
// release v1.7.2 · source sha256 1e71e4553ab540dd…
|
|
4
4
|
// conversions: rem→px at 16 · em→…Em relative doubles · rgba alpha→ARGB byte (round(a*255)) · durations in ms
|
|
5
5
|
// dark element packs: see $extensions.overrides.elementsDark
|
|
6
6
|
// provenance: tokens/provenance.json · parity gate: _audit/token-pipeline-test.html
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// CyberSkill Design System — native design tokens.
|
|
2
2
|
// GENERATED from tokens/tokens.dtcg.json — do not hand-edit; regenerate on token change.
|
|
3
|
-
// release v1.7.
|
|
3
|
+
// release v1.7.2 · source sha256 1e71e4553ab540dd…
|
|
4
4
|
// conversions: rem→px at 16 · em→…Em relative doubles · rgba alpha→ARGB byte (round(a*255)) · durations in ms
|
|
5
5
|
// dark element packs: see $extensions.overrides.elementsDark
|
|
6
6
|
// provenance: tokens/provenance.json · parity gate: _audit/token-pipeline-test.html
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// CyberSkill Design System — native design tokens.
|
|
2
2
|
// GENERATED from tokens/tokens.dtcg.json — do not hand-edit; regenerate on token change.
|
|
3
|
-
// release v1.7.
|
|
3
|
+
// release v1.7.2 · source sha256 1e71e4553ab540dd…
|
|
4
4
|
// conversions: rem→px at 16 · em→…Em relative doubles · rgba alpha→ARGB byte (round(a*255)) · durations in ms
|
|
5
5
|
// dark element packs: see $extensions.overrides.elementsDark
|
|
6
6
|
// provenance: tokens/provenance.json · parity gate: _audit/token-pipeline-test.html
|
package/tokens/provenance.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"system": "CyberSkill Design System",
|
|
3
|
-
"release": "1.7.
|
|
3
|
+
"release": "1.7.2",
|
|
4
4
|
"source": "tokens/tokens.dtcg.json",
|
|
5
|
-
"sourceSha256": "
|
|
5
|
+
"sourceSha256": "1e71e4553ab540dd0154ece1315b9a5148525ebdf7197d99400a6bc067b277c3",
|
|
6
6
|
"dtcgStamp": {
|
|
7
|
-
"version": "1.7.
|
|
7
|
+
"version": "1.7.2",
|
|
8
8
|
"generated": "2026-07-23"
|
|
9
9
|
},
|
|
10
10
|
"conversions": {
|
|
@@ -36,17 +36,17 @@
|
|
|
36
36
|
{
|
|
37
37
|
"file": "tokens/native/CSTokens.swift",
|
|
38
38
|
"lang": "swift",
|
|
39
|
-
"sha256": "
|
|
39
|
+
"sha256": "b4a7f3e5315bbb5de5469ea9b18e01906e739fd3d38c25d51026b30343509004"
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
42
|
"file": "tokens/native/CSTokens.kt",
|
|
43
43
|
"lang": "kotlin",
|
|
44
|
-
"sha256": "
|
|
44
|
+
"sha256": "662502acc441f711495ddb29a9129937b88466f337a365a7ed36bef11822cb8c"
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
"file": "tokens/native/cs_tokens.dart",
|
|
48
48
|
"lang": "dart",
|
|
49
|
-
"sha256": "
|
|
49
|
+
"sha256": "4bc9f7c849a82f8f5932c63b199d44d86d50868f8fc895a2980f77869b68cd19"
|
|
50
50
|
}
|
|
51
51
|
]
|
|
52
52
|
}
|
package/tokens/tokens.dtcg.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"$extensions": {
|
|
4
4
|
"com.cyberskill": {
|
|
5
5
|
"system": "CyberSkill Design System",
|
|
6
|
-
"version": "1.7.
|
|
6
|
+
"version": "1.7.2",
|
|
7
7
|
"generated": "2026-07-23",
|
|
8
8
|
"source": "tokens/tokens.json",
|
|
9
9
|
"note": "Scope overrides (dark/system theme · 15 element×variant packs) are carried under $extensions.overrides keyed by CSS selector — apply the matching selector on :root/ancestor to activate.",
|
package/tokens/tokens.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// CyberSkill design tokens — generated from tokens/*.css (v1.7.
|
|
1
|
+
// CyberSkill design tokens — generated from tokens/*.css (v1.7.2). Do not edit by hand.
|
|
2
2
|
export const tokens = {
|
|
3
3
|
"$meta": {
|
|
4
4
|
"system": "CyberSkill Design System",
|
|
5
|
-
"version": "1.7.
|
|
5
|
+
"version": "1.7.2",
|
|
6
6
|
"generated": "2026-07-23",
|
|
7
7
|
"note": "Generated from tokens/*.css. Root grouped by category; theme/element scopes carry overrides only. Regenerate after any token change (see docs/conventions.md)."
|
|
8
8
|
},
|
package/tokens/tokens.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$meta": {
|
|
3
3
|
"system": "CyberSkill Design System",
|
|
4
|
-
"version": "1.7.
|
|
4
|
+
"version": "1.7.2",
|
|
5
5
|
"generated": "2026-07-23",
|
|
6
6
|
"note": "Generated from tokens/*.css. Root grouped by category; theme/element scopes carry overrides only. Regenerate after any token change (see docs/conventions.md)."
|
|
7
7
|
},
|