diff --git a/craft/src/components/basic/ButtonLink.toHtml.test.ts b/craft/src/components/basic/ButtonLink.toHtml.test.ts index 2b40c18..bb86953 100644 --- a/craft/src/components/basic/ButtonLink.toHtml.test.ts +++ b/craft/src/components/basic/ButtonLink.toHtml.test.ts @@ -126,3 +126,12 @@ describe('ButtonLink.toHtml palette token default (Refs #44)', () => { expect(html).not.toContain('#3b82f6'); }); }); + +describe('ButtonLink.toHtml design tokens (#44)', () => { + test('default export references var(--wsb-*) and no longer carries the old hard-coded hex', () => { + const { html } = toHtml({ ...(ButtonLink as any).craft.props }, ''); + const lower = html.toLowerCase(); + for (const t of ["bg", "primary"]) expect(html, `token ${t}`).toContain(`var(--wsb-${t})`); + for (const hex of ["#ffffff"]) expect(lower, `old ${hex}`).not.toContain(hex); + }); +}); diff --git a/craft/src/components/basic/ButtonLink.tsx b/craft/src/components/basic/ButtonLink.tsx index 53036d7..5d450a8 100644 --- a/craft/src/components/basic/ButtonLink.tsx +++ b/craft/src/components/basic/ButtonLink.tsx @@ -77,7 +77,7 @@ ButtonLink.craft = { hoverColor: '', style: { backgroundColor: tokenRef('primary'), - color: '#ffffff', + color: tokenRef('bg'), padding: '12px 24px', borderRadius: '8px', fontWeight: '600', diff --git a/craft/src/components/basic/Divider.toHtml.test.ts b/craft/src/components/basic/Divider.toHtml.test.ts index db186b5..53937b1 100644 --- a/craft/src/components/basic/Divider.toHtml.test.ts +++ b/craft/src/components/basic/Divider.toHtml.test.ts @@ -32,3 +32,12 @@ describe('Divider.toHtml XSS hardening (thickness/color into style=)', () => { expect(html).not.toMatch(/"\s+onmouseover="/); }); }); + +describe('Divider.toHtml design tokens (#44)', () => { + test('default export references var(--wsb-*) and no longer carries the old hard-coded hex', () => { + const { html } = toHtml({}, ''); + const lower = html.toLowerCase(); + for (const t of ["border"]) expect(html, `token ${t}`).toContain(`var(--wsb-${t})`); + for (const hex of ["#e4e4e7"]) expect(lower, `old ${hex}`).not.toContain(hex); + }); +}); diff --git a/craft/src/components/basic/Divider.tsx b/craft/src/components/basic/Divider.tsx index 707c07d..b746f84 100644 --- a/craft/src/components/basic/Divider.tsx +++ b/craft/src/components/basic/Divider.tsx @@ -1,4 +1,5 @@ import React, { CSSProperties } from 'react'; +import { tokenRef } from '../../utils/tokens'; import { useNode, UserComponent } from '@craftjs/core'; import { cssPropsToString } from '../../utils/style-helpers'; @@ -9,7 +10,7 @@ interface DividerProps { } export const Divider: UserComponent = ({ - color = '#e4e4e7', + color = tokenRef('border'), thickness = '1px', style = {}, }) => { @@ -39,7 +40,7 @@ export const Divider: UserComponent = ({ Divider.craft = { displayName: 'Divider', props: { - color: '#e4e4e7', + color: tokenRef('border'), thickness: '1px', style: {}, }, @@ -55,7 +56,7 @@ Divider.craft = { (Divider as any).toHtml = (props: DividerProps, _childrenHtml: string) => { const styleStr = cssPropsToString({ border: 'none', - borderTop: `${props.thickness || '1px'} solid ${props.color || '#e4e4e7'}`, + borderTop: `${props.thickness || '1px'} solid ${props.color || tokenRef('border')}`, margin: '16px 0', ...props.style, }); diff --git a/craft/src/components/basic/Footer.toHtml.test.ts b/craft/src/components/basic/Footer.toHtml.test.ts index c663e66..49db533 100644 --- a/craft/src/components/basic/Footer.toHtml.test.ts +++ b/craft/src/components/basic/Footer.toHtml.test.ts @@ -31,3 +31,13 @@ describe('Footer (F4: box-model + animation + visibility props on craft.props)', expect(craftProps).toHaveProperty('hideOnMobile', false); }); }); + +describe('Footer.toHtml design tokens (#44)', () => { + test('default craft props export var(--wsb-*) and none of the old design hex', () => { + const props = { ...((Footer as any).craft.props as object) }; + const { html } = (((Footer) as any).toHtml)(props, '', 'node-tok'); + const lower = html.toLowerCase(); + for (const t of ['text', 'bg']) expect(html, `token ${t}`).toContain(`var(--wsb-${t})`); + for (const hex of ['#18181b', '#a1a1aa']) expect(lower, `old ${hex}`).not.toContain(hex.toLowerCase()); + }); +}); diff --git a/craft/src/components/basic/Footer.tsx b/craft/src/components/basic/Footer.tsx index b3dd2f3..b4be91e 100644 --- a/craft/src/components/basic/Footer.tsx +++ b/craft/src/components/basic/Footer.tsx @@ -1,6 +1,7 @@ import React, { CSSProperties, useCallback, useRef, useEffect } from 'react'; import { useNode, UserComponent } from '@craftjs/core'; import { cssPropsToString } from '../../utils/style-helpers'; +import { tokenRef } from '../../utils/tokens'; import { escapeHtml } from '../../utils/escape'; interface FooterProps { @@ -92,8 +93,9 @@ Footer.craft = { props: { text: '© 2026 MySite. All rights reserved.', style: { - backgroundColor: '#18181b', - color: '#a1a1aa', + // Dark band: text token as the band, bg token as its (contrast-safe) text. + backgroundColor: tokenRef('text'), + color: tokenRef('bg'), fontSize: '14px', padding: '24px 20px', }, diff --git a/craft/src/components/basic/Logo.toHtml.test.ts b/craft/src/components/basic/Logo.toHtml.test.ts index e6429f4..a9ae530 100644 --- a/craft/src/components/basic/Logo.toHtml.test.ts +++ b/craft/src/components/basic/Logo.toHtml.test.ts @@ -83,3 +83,12 @@ describe('Logo.toHtml text-logo styling sanitization', () => { expect(html).toContain('MySite'); }); }); + +describe('Logo.toHtml design tokens (#44)', () => { + test('default export references var(--wsb-*) and no longer carries the old hard-coded hex', () => { + const { html } = toHtml({ text: "Acme" }, ''); + const lower = html.toLowerCase(); + for (const t of ["text"]) expect(html, `token ${t}`).toContain(`var(--wsb-${t})`); + for (const hex of ["#1f2937"]) expect(lower, `old ${hex}`).not.toContain(hex); + }); +}); diff --git a/craft/src/components/basic/Logo.tsx b/craft/src/components/basic/Logo.tsx index ed39efa..87439a9 100644 --- a/craft/src/components/basic/Logo.tsx +++ b/craft/src/components/basic/Logo.tsx @@ -1,4 +1,5 @@ import React, { CSSProperties } from 'react'; +import { tokenRef } from '../../utils/tokens'; import { useNode, UserComponent } from '@craftjs/core'; import { cssPropsToString } from '../../utils/style-helpers'; import { useSiteDesign } from '../../state/SiteDesignContext'; @@ -125,7 +126,7 @@ Logo.craft = { fontWeight: props.fontWeight || '700', fontSize: props.fontSize || '20px', fontFamily: props.fontFamily || 'Inter, sans-serif', - color: props.color || '#1f2937', + color: props.color || tokenRef('text'), }); innerHtml = `${escapeHtml(props.text || 'MySite')}`; } diff --git a/craft/src/components/basic/Menu.toHtml.test.ts b/craft/src/components/basic/Menu.toHtml.test.ts index 0661456..f2776fd 100644 --- a/craft/src/components/basic/Menu.toHtml.test.ts +++ b/craft/src/components/basic/Menu.toHtml.test.ts @@ -107,3 +107,13 @@ describe('Menu.toHtml dropdowns (#53)', () => { expect((Menu as any).craft.props.followPages).toBe(false); }); }); + +describe('Menu.toHtml design tokens (#44)', () => { + test('default craft props export var(--wsb-*) and none of the old design hex', () => { + const props = { ...((Menu as any).craft.props as object) }; + const { html } = (((Menu) as any).toHtml)(props, '', 'node-tok'); + const lower = html.toLowerCase(); + for (const t of ['text', 'bg']) expect(html, `token ${t}`).toContain(`var(--wsb-${t})`); + for (const hex of ['#3f3f46']) expect(lower, `old ${hex}`).not.toContain(hex.toLowerCase()); + }); +}); diff --git a/craft/src/components/basic/Menu.tsx b/craft/src/components/basic/Menu.tsx index 2697c25..1a73dfd 100644 --- a/craft/src/components/basic/Menu.tsx +++ b/craft/src/components/basic/Menu.tsx @@ -43,10 +43,10 @@ const defaultLinks: MenuLink[] = [ export const Menu: UserComponent = ({ links = defaultLinks, alignment = 'right', - linkColor = '#3f3f46', + linkColor = tokenRef('text'), linkHoverColor = tokenRef('primary'), ctaBgColor = tokenRef('primary'), - ctaTextColor = '#ffffff', + ctaTextColor = tokenRef('bg'), gap = '24px', orientation = 'horizontal', fontSize = '14px', @@ -139,7 +139,7 @@ export const Menu: UserComponent = ({ const SUB_STYLE: CSSProperties = { position: 'absolute', top: '100%', left: 0, zIndex: 1001, minWidth: 180, margin: 0, padding: '8px 0', - listStyle: 'none', background: 'var(--wsb-bg, #ffffff)', borderRadius: 6, boxShadow: '0 8px 24px rgba(0,0,0,0.12)', + listStyle: 'none', background: tokenRef('bg'), borderRadius: 6, boxShadow: '0 8px 24px rgba(0,0,0,0.12)', }; const SUB_STATIC_STYLE: CSSProperties = { margin: 0, padding: '4px 0 0 12px', listStyle: 'none' }; @@ -151,10 +151,10 @@ Menu.craft = { links: defaultLinks, followPages: false, alignment: 'right', - linkColor: '#3f3f46', + linkColor: tokenRef('text'), linkHoverColor: tokenRef('primary'), ctaBgColor: tokenRef('primary'), - ctaTextColor: '#ffffff', + ctaTextColor: tokenRef('bg'), gap: '24px', orientation: 'horizontal', fontSize: '14px', @@ -179,10 +179,10 @@ Menu.craft = { // string-interpolation sinks below (hoverCol goes into a breakout -> arbitrary