@nexus-cross/crossx-design-system 1.3.0

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/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # @nexus-cross/crossx-design-system
2
+
3
+ The CROSSx design system — **color**, **typography** and **layout** tokens with
4
+ a swappable `DesignSystem` contract. Pure TypeScript, **no runtime dependencies**.
5
+
6
+ It is the single source of design tokens for `@nexus-cross/dapp-ui` and
7
+ `@nexus-cross/connect-kit-*`. A DApp can replace it wholesale by passing its own
8
+ `DesignSystem`-shaped object — see [Swapping](#swapping).
9
+
10
+ ## Install
11
+
12
+ ```sh
13
+ pnpm add @nexus-cross/crossx-design-system
14
+ ```
15
+
16
+ ## Tokens
17
+
18
+ Transcribed from the CROSSx Figma design system (Embeded v1.0.0):
19
+
20
+ | Axis | Figma node | Shape |
21
+ |---|---|---|
22
+ | color | `2032-6584` | `bg`, `surface`, `content`, `border`, `accent.primary`, `system.{red,blue,orange,purple,green}`, `overlay`, `static` — light + dark |
23
+ | typography | `2019-2351` | `text`, `textMedium`, `textSemibold`, `label`, `labelSemibold`, `heading` (h1–h7), `display` |
24
+ | layout | `2060-1755` | `responsivePadding` (`sm`/`md`/`lg`) |
25
+
26
+ ## CSS output
27
+
28
+ ```ts
29
+ import { buildDesignSystemCss, defaultDesignSystem } from '@nexus-cross/crossx-design-system';
30
+
31
+ const css = buildDesignSystemCss(defaultDesignSystem);
32
+ // inject `css` into a <style>, then set data-ds-theme="light" | "dark"
33
+ ```
34
+
35
+ - **Colors / layout** → `--ds-*` custom properties.
36
+ `content.highest` → `var(--ds-content-highest)`,
37
+ `accent.primary.default` → `var(--ds-accent-primary-default)`,
38
+ `responsivePadding.md` → `var(--ds-responsive-padding-md)`.
39
+ Dark is the `:root` default; light overlays via `[data-ds-theme="light"]`.
40
+ - **Typography** → utility classes, applied with `className`:
41
+ `.ds-text-medium-sm`, `.ds-label-md`, `.ds-heading-h6`, `.ds-display-lg`.
42
+
43
+ ## crossy-sdk bridge
44
+
45
+ ```ts
46
+ import { toSdkColorOverrides, defaultDesignSystem } from '@nexus-cross/crossx-design-system';
47
+
48
+ const overrides = toSdkColorOverrides(defaultDesignSystem, 'dark'); // 12-key SDKColorOverrides
49
+ ```
50
+
51
+ ## Swapping
52
+
53
+ ```ts
54
+ import type { DesignSystem } from '@nexus-cross/crossx-design-system';
55
+
56
+ const myDesignSystem: DesignSystem = { name: 'acme', colors: { light, dark }, typography, layout };
57
+ createCrossxConfig({ /* ... */, designSystem: myDesignSystem });
58
+ ```
59
+
60
+ The contract is structural — a conforming object works even without importing
61
+ the type.
62
+
63
+ See [`docs/design-system/01-architecture.md`](../../docs/design-system/01-architecture.md).
@@ -0,0 +1,273 @@
1
+ /**
2
+ * The `DesignSystem` contract.
3
+ *
4
+ * This is the **swap seam**: a DApp can implement this interface with its own
5
+ * values and pass it to `createCrossxConfig({ designSystem })` instead of using
6
+ * `defaultDesignSystem`. The interface is structural, so a conforming object
7
+ * works even without importing these types.
8
+ *
9
+ * Names mirror the CROSSx Figma design system (Embeded v1.0.0):
10
+ * - color : `2032-6584` (embeded-color)
11
+ * - type : `2019-2351`
12
+ * - layout : `2060-1755` (responsive-padding)
13
+ *
14
+ * No env types leak through — every value is a plain CSS string or number.
15
+ */
16
+ /**
17
+ * A semantic color ramp shared by `accent.*` and every `system.*` color.
18
+ * `on` / `onInverted` are the readable foreground placed on top of the color.
19
+ */
20
+ interface ColorRamp {
21
+ /** Foreground on top of `default` (e.g. text on a filled button). */
22
+ on: string;
23
+ /** The base color. */
24
+ default: string;
25
+ /** Stronger / hover variant. */
26
+ high: string;
27
+ /** Tinted surface (subtle filled background). */
28
+ low: string;
29
+ /** Faintest tinted surface. */
30
+ lowest: string;
31
+ /** Foreground for the inverted (dark-on-light / light-on-dark) context. */
32
+ onInverted: string;
33
+ }
34
+ /**
35
+ * A full set of color roles for one theme mode. The `light` and `dark`
36
+ * `ColorScale`s are parallel structures — same keys, mode-specific values.
37
+ */
38
+ interface ColorScale {
39
+ /** Page / app root background. */
40
+ bg: {
41
+ default: string;
42
+ dim: string;
43
+ };
44
+ /** Raised surfaces (cards, sheets, hover fills). */
45
+ surface: {
46
+ default: string;
47
+ medium: string;
48
+ high: string;
49
+ dim: string;
50
+ inverted: string;
51
+ };
52
+ /** Text & icon colors. Note: no `default` step — `highest` is the strongest. */
53
+ content: {
54
+ highest: string;
55
+ high: string;
56
+ medium: string;
57
+ low: string;
58
+ lowest: string;
59
+ inverted: string;
60
+ };
61
+ /** Borders / dividers. Note: steps are `default`/`medium`/`high` (no `low`). */
62
+ border: {
63
+ default: string;
64
+ medium: string;
65
+ high: string;
66
+ };
67
+ /** Brand accent. */
68
+ accent: {
69
+ primary: ColorRamp;
70
+ };
71
+ /** Semantic status colors. */
72
+ system: {
73
+ red: ColorRamp;
74
+ blue: ColorRamp;
75
+ orange: ColorRamp;
76
+ purple: ColorRamp;
77
+ green: ColorRamp;
78
+ };
79
+ /** Scrim behind modals / drawers. */
80
+ overlay: {
81
+ dim: string;
82
+ subtle: string;
83
+ };
84
+ /** Mode-independent absolutes. */
85
+ static: {
86
+ white: string;
87
+ black: string;
88
+ };
89
+ }
90
+ /**
91
+ * One text style. `fontSize` is px, `lineHeight` is a unitless multiplier,
92
+ * `letterSpacing` is a percentage (Figma convention; `-1` → `-0.01em`).
93
+ */
94
+ interface TypeStyle {
95
+ fontFamily: string;
96
+ fontSize: number;
97
+ fontWeight: number;
98
+ lineHeight: number;
99
+ letterSpacing: number;
100
+ }
101
+ type TextSize = '2xs' | 'xs' | 'sm' | 'base' | 'lg' | 'xl';
102
+ /** `text-semibold` has no `2xs`. */
103
+ type TextSemiboldSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl';
104
+ type LabelSize = 'xs' | 'sm' | 'md' | 'lg';
105
+ type LabelSemiboldSize = 'sm' | 'md' | 'lg';
106
+ type HeadingSize = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'h7';
107
+ type DisplaySize = 'sm' | 'md' | 'lg';
108
+ interface DesignSystemTypography {
109
+ text: Record<TextSize, TypeStyle>;
110
+ textMedium: Record<TextSize, TypeStyle>;
111
+ textSemibold: Record<TextSemiboldSize, TypeStyle>;
112
+ label: Record<LabelSize, TypeStyle>;
113
+ labelSemibold: Record<LabelSemiboldSize, TypeStyle>;
114
+ heading: Record<HeadingSize, TypeStyle>;
115
+ display: Record<DisplaySize, TypeStyle>;
116
+ }
117
+ /**
118
+ * Layout scales. Values are px.
119
+ *
120
+ * `responsivePadding` is the container side-padding per breakpoint bucket
121
+ * (`sm`/`md`/`lg`). Breakpoint wiring (which bucket applies when) is a
122
+ * consumer concern — the tokens only define the values.
123
+ */
124
+ interface DesignSystemLayout {
125
+ responsivePadding: {
126
+ sm: number;
127
+ md: number;
128
+ lg: number;
129
+ };
130
+ }
131
+ /**
132
+ * Shadow / blur effects. Values are ready-to-use CSS:
133
+ * `shadowModal.*` are `box-shadow` values, `bgBlur7` is a `filter`/
134
+ * `backdrop-filter` value.
135
+ */
136
+ interface DesignSystemEffects {
137
+ /** Modal / popover drop shadow, per theme mode. */
138
+ shadowModal: {
139
+ light: string;
140
+ dark: string;
141
+ };
142
+ /** Background blur (Figma `BG_blur7`, 7px radius). */
143
+ bgBlur7: string;
144
+ }
145
+ interface DesignSystem {
146
+ /** Identifier (e.g. `'crossx'`). Surfaced for debugging / theme switching. */
147
+ name: string;
148
+ colors: {
149
+ light: ColorScale;
150
+ dark: ColorScale;
151
+ };
152
+ typography: DesignSystemTypography;
153
+ layout: DesignSystemLayout;
154
+ effects: DesignSystemEffects;
155
+ }
156
+ type ThemeMode = 'light' | 'dark';
157
+
158
+ /**
159
+ * Default color palette — transcribed verbatim from CROSSx Figma
160
+ * `embeded-color` (node `2032-6584`), light + dark modes.
161
+ *
162
+ * Black/white alpha steps (content, border, overlay) are emitted as `rgba()`.
163
+ * Note: `accent.primary` and `system.green` share the same brand-teal ramp.
164
+ */
165
+
166
+ declare const lightColors: ColorScale;
167
+ declare const darkColors: ColorScale;
168
+
169
+ /**
170
+ * Default typography scale — transcribed from CROSSx Figma type styles
171
+ * (node `2019-2351`). All Inter. `letterSpacing` is a percentage:
172
+ * the `text*` families use -1 (-0.01em); label / heading / display use 0.
173
+ */
174
+
175
+ declare const typography: DesignSystemTypography;
176
+
177
+ /**
178
+ * Default layout tokens — transcribed from CROSSx Figma `layout`
179
+ * (node `2060-1755`, `responsive-padding`). Values are px.
180
+ */
181
+
182
+ declare const layout: DesignSystemLayout;
183
+
184
+ /**
185
+ * Default effect tokens — transcribed from CROSSx Figma `Effects` collection.
186
+ *
187
+ * - `shadow-modal-light`: drop shadow, color #0000 @ 15%, offset (0,4), blur 30, spread -1
188
+ * - `shadow-modal-dark` : drop shadow, color #0000 @ 70%, offset (0,4), blur 30, spread -1
189
+ * - `BG_blur7` : background blur, Figma radius 7 → CSS blur(3.5px)
190
+ * (Figma's background-blur radius ≈ 2× the CSS blur,
191
+ * per Dev Mode codegen)
192
+ */
193
+
194
+ declare const effects: DesignSystemEffects;
195
+
196
+ /**
197
+ * The default CROSSx design system — assembled from the Figma-transcribed
198
+ * color, typography and layout tokens. Passed to `createCrossxConfig` when a
199
+ * DApp does not supply its own `designSystem`.
200
+ */
201
+
202
+ declare const defaultDesignSystem: DesignSystem;
203
+
204
+ /**
205
+ * Turn a {@link DesignSystem} into CSS.
206
+ *
207
+ * - **Colors** flatten deterministically to `--ds-*` custom properties under
208
+ * per-mode selectors (dark is the `:root` default; light is overlaid via
209
+ * `[data-ds-theme="light"]`).
210
+ * - **Layout** tokens emit as mode-independent `--ds-*` properties.
211
+ * - **Typography** emits as utility classes (`.ds-text-medium-sm` …) carrying
212
+ * the full font shorthand — applied via `className`, not CSS variables.
213
+ *
214
+ * The walk is generic, so any conforming `DesignSystem` (incl. a DApp's own)
215
+ * produces predictable names.
216
+ */
217
+
218
+ /** `--ds-*` declarations for one mode's color scale (no selector wrapper). */
219
+ declare function buildColorVars(scale: ColorScale): string;
220
+ /** `--ds-*` declarations for layout tokens (px). */
221
+ declare function buildLayoutVars(layout: DesignSystemLayout): string;
222
+ /** `.ds-<group>-<size>` utility classes for every type style. */
223
+ declare function buildTypographyClasses(typography: DesignSystemTypography): string;
224
+ interface BuildCssOptions {
225
+ /** Selector that receives the default (dark) palette. Defaults to `:root`. */
226
+ scope?: string;
227
+ }
228
+ /**
229
+ * Full stylesheet: color vars (both modes) + layout vars + typography classes.
230
+ * Attach the returned string to a `<style>` once; flip palettes by setting
231
+ * `data-ds-theme="light" | "dark"` on any ancestor.
232
+ */
233
+ declare function buildDesignSystemCss(ds: DesignSystem, opts?: BuildCssOptions): string;
234
+
235
+ /**
236
+ * Project a {@link DesignSystem} down to the 12-key color contract that
237
+ * crossy-sdk's embedded modal requires (`SDKColorOverrides`).
238
+ *
239
+ * This is **not** the rejected `--cck-*` alias table — it is the unavoidable
240
+ * adapter for handing colors to a third-party SDK whose theming API is fixed.
241
+ * `@nexus-cross/connect-kit-wagmi` calls this at connector-creation time.
242
+ *
243
+ * The local shape is kept structural so this package does not harden on
244
+ * crossy-sdk internals.
245
+ */
246
+
247
+ interface SdkColorOverrides {
248
+ primary?: string;
249
+ secondary?: string;
250
+ onPrimary?: string;
251
+ borderDefault?: string;
252
+ borderSubtle?: string;
253
+ textIconPrimary?: string;
254
+ textIconSecondary?: string;
255
+ textIconTertiary?: string;
256
+ surfaceDefault?: string;
257
+ surfaceSubtle?: string;
258
+ bg?: string;
259
+ error?: string;
260
+ }
261
+ declare function toSdkColorOverrides(ds: DesignSystem, mode: ThemeMode): SdkColorOverrides;
262
+
263
+ /**
264
+ * `@nexus-cross/crossx-design-system`
265
+ *
266
+ * The CROSSx design system: a swappable `DesignSystem` contract, the default
267
+ * Figma-derived token set, and helpers to emit CSS / project to crossy-sdk.
268
+ */
269
+
270
+ /** Convenience: the default design system's full stylesheet. */
271
+ declare function getDefaultDesignSystemCss(): string;
272
+
273
+ export { type BuildCssOptions, type ColorRamp, type ColorScale, type DesignSystem, type DesignSystemEffects, type DesignSystemLayout, type DesignSystemTypography, type DisplaySize, type HeadingSize, type LabelSemiboldSize, type LabelSize, type SdkColorOverrides, type TextSemiboldSize, type TextSize, type ThemeMode, type TypeStyle, buildColorVars, buildDesignSystemCss, buildLayoutVars, buildTypographyClasses, darkColors, defaultDesignSystem, effects, getDefaultDesignSystemCss, layout, lightColors, toSdkColorOverrides, typography };
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ var a={bg:{default:"#FFFFFF",dim:"#F5F7FA"},surface:{default:"#FFFFFF",medium:"#F5F7FA",high:"#EDF1F2",dim:"#F9FAFB",inverted:"#1E232E"},content:{highest:"#000000",high:"#000000D9",medium:"#000000A6",low:"#00000066",lowest:"#00000040",inverted:"#FFFFFF"},border:{default:"#00000012",medium:"#0000002E",high:"#000000A6"},accent:{primary:{on:"#FFFFFF",default:"#00B4B7",high:"#00A0A2",low:"#E7F9F8",lowest:"#F0FAF9",onInverted:"#00E8C9"}},system:{red:{on:"#FFFFFF",default:"#DA0B2E",high:"#D20609",low:"#FFEEEE",lowest:"#FFF6F6",onInverted:"#FF0F47"},blue:{on:"#FFFFFF",default:"#0888DE",high:"#008DCA",low:"#ECF8FC",lowest:"#F5FBFE",onInverted:"#0FC7FF"},orange:{on:"#FFFFFF",default:"#FC8B01",high:"#E56F00",low:"#FCF5E9",lowest:"#FFF9F2",onInverted:"#FF9F21"},purple:{on:"#FFFFFF",default:"#7E54F4",high:"#7346F3",low:"#F5F3FF",lowest:"#F9F8FF",onInverted:"#9B78FF"},green:{on:"#FFFFFF",default:"#00B4B7",high:"#00A0A2",low:"#E7F9F8",lowest:"#F0FAF9",onInverted:"#00E8C9"}},overlay:{dim:"#00000080",subtle:"#00000005"},static:{white:"#FFFFFF",black:"#000000"}},g={bg:{default:"#1E232E",dim:"#191D27"},surface:{default:"#1E232E",medium:"#252B39",high:"#363B4C",dim:"#161B26",inverted:"#FFFFFF"},content:{highest:"#FFFFFF",high:"#FFFFFFD9",medium:"#FFFFFFA6",low:"#FFFFFF66",lowest:"#FFFFFF40",inverted:"#000000"},border:{default:"#FFFFFF12",medium:"#FFFFFF2E",high:"#FFFFFFA6"},accent:{primary:{on:"#000000",default:"#00CEB2",high:"#00E8C9",low:"#123235",lowest:"#102E31",onInverted:"#00A0A2"}},system:{red:{on:"#FFFFFF",default:"#CD0C40",high:"#FF0F47",low:"#461420",lowest:"#39151E",onInverted:"#D20609"},blue:{on:"#FFFFFF",default:"#0888DE",high:"#0FC7FF",low:"#143446",lowest:"#162B3B",onInverted:"#008DCA"},orange:{on:"#000000",default:"#FF9F21",high:"#FF9F21",low:"#342B1E",lowest:"#2E2820",onInverted:"#E56F00"},purple:{on:"#FFFFFF",default:"#744FDC",high:"#9B78FF",low:"#2E2854",lowest:"#2A2740",onInverted:"#7346F3"},green:{on:"#000000",default:"#00CEB2",high:"#00E8C9",low:"#123235",lowest:"#102E31",onInverted:"#00A0A2"}},overlay:{dim:"#000000B3",subtle:"#00000026"},static:{white:"#FFFFFF",black:"#000000"}};var x="Inter, sans-serif",e=(t,o,r,n)=>({fontFamily:x,fontSize:t,fontWeight:o,lineHeight:r,letterSpacing:n}),d={text:{"2xs":e(10,400,1.5,-1),xs:e(12,400,1.5,-1),sm:e(14,400,1.5,-1),base:e(16,400,1.5,-1),lg:e(18,400,1.5,-1),xl:e(20,400,1.5,-1)},textMedium:{"2xs":e(10,500,1.5,-1),xs:e(12,500,1.5,-1),sm:e(14,500,1.5,-1),base:e(16,500,1.5,-1),lg:e(18,500,1.5,-1),xl:e(20,500,1.5,-1)},textSemibold:{xs:e(12,600,1.5,-1),sm:e(14,600,1.5,-1),base:e(16,600,1.5,-1),lg:e(18,600,1.5,-1),xl:e(20,600,1.5,-1)},label:{xs:e(10,500,1,0),sm:e(12,500,1,0),md:e(14,500,1,0),lg:e(16,500,1,0)},labelSemibold:{sm:e(12,600,1,0),md:e(14,600,1,0),lg:e(16,600,1,0)},heading:{h7:e(14,600,1.25,0),h6:e(16,600,1.25,0),h5:e(18,600,1.25,0),h4:e(20,600,1.25,0),h3:e(24,600,1.25,0),h2:e(30,700,1.25,0),h1:e(36,700,1.25,0)},display:{sm:e(36,700,1.25,0),md:e(48,700,1.25,0),lg:e(60,700,1.25,0)}};var m={responsivePadding:{sm:16,md:24,lg:32}};var c={shadowModal:{light:"0px 4px 30px -1px rgba(0, 0, 0, 0.15)",dark:"0px 4px 30px -1px rgba(0, 0, 0, 0.7)"},bgBlur7:"blur(3.5px)"};var u={name:"crossx",colors:{light:a,dark:g},typography:d,layout:m,effects:c};var y="--ds";function F(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function h(t,o,r){for(let[n,s]of Object.entries(t)){let i=[...o,F(n)];typeof s=="string"?r.push(` ${y}-${i.join("-")}: ${s};`):s&&typeof s=="object"&&h(s,i,r)}}function p(t){let o=[];return h(t,[],o),o.join(`
2
+ `)}function b(t){let o=[];for(let[r,n]of Object.entries(t)){let s=F(r);for(let[i,l]of Object.entries(n))o.push(` ${y}-${s}-${F(i)}: ${l}px;`)}return o.join(`
3
+ `)}function C(t){return t===0?"0":`${t/100}em`}function D(t,o){return[`.${t} {`,` font-family: ${o.fontFamily};`,` font-size: ${o.fontSize}px;`,` font-weight: ${o.fontWeight};`,` line-height: ${o.lineHeight};`,` letter-spacing: ${C(o.letterSpacing)};`,"}"].join(`
4
+ `)}function S(t){let o=[];for(let[r,n]of Object.entries(t)){let s=F(r);for(let[i,l]of Object.entries(n))o.push(D(`ds-${s}-${i}`,l))}return o.join(`
5
+
6
+ `)}function f(t,o={}){return[`${o.scope??":root"}, [data-ds-theme="dark"] {`,p(t.colors.dark),b(t.layout),` --ds-shadow-modal: ${t.effects.shadowModal.dark};`,` --ds-bg-blur-7: ${t.effects.bgBlur7};`,"}","",'[data-ds-theme="light"] {',p(t.colors.light),` --ds-shadow-modal: ${t.effects.shadowModal.light};`,"}","",S(t.typography),""].join(`
7
+ `)}function w(t,o){let r=t.colors[o];return{primary:r.accent.primary.default,secondary:r.system.red.default,onPrimary:r.accent.primary.on,error:r.system.red.default,bg:r.bg.default,surfaceDefault:r.surface.medium,surfaceSubtle:r.surface.high,borderDefault:r.border.default,borderSubtle:r.border.medium,textIconPrimary:r.content.highest,textIconSecondary:r.content.medium,textIconTertiary:r.content.low}}function R(){return f(u)}export{p as buildColorVars,f as buildDesignSystemCss,b as buildLayoutVars,S as buildTypographyClasses,g as darkColors,u as defaultDesignSystem,c as effects,R as getDefaultDesignSystemCss,m as layout,a as lightColors,w as toSdkColorOverrides,d as typography};
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@nexus-cross/crossx-design-system",
3
+ "version": "1.3.0",
4
+ "description": "CROSSx design system — color, typography and layout tokens with a swappable DesignSystem contract",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "sideEffects": false,
18
+ "publishConfig": {
19
+ "registry": "https://registry.npmjs.org",
20
+ "access": "public"
21
+ },
22
+ "devDependencies": {
23
+ "tsup": "^8.4.0",
24
+ "typescript": "^5.7.0"
25
+ },
26
+ "license": "MIT",
27
+ "scripts": {
28
+ "build": "tsup",
29
+ "dev": "tsup --watch",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest",
32
+ "typecheck": "tsc --noEmit"
33
+ }
34
+ }