From ea62e07bc67cf5c42ad034ffd6f52283c6cfb2ca Mon Sep 17 00:00:00 2001 From: Tara West Date: Thu, 15 Jan 2026 10:39:50 +0100 Subject: [PATCH] feat(element-configs): Add TextConfig + fix Text element sizing bug - TextConfig with 10 semantic typography variants * display, h1, h2, h3, h4 (headings) * body, body-sm (body text) * caption, label, code (special text) - All variants use design tokens - Fix Text element bug: width 'auto' instead of stretching to 100% - Text now properly sizes to content with display: flex + width: auto Part of STYLE-002 MVP 1 implementation. Next: MVP 2 - Node Integration. --- .../ElementConfigs/configs/TextConfig.ts | 146 ++++++++++++++++++ .../models/ElementConfigs/configs/index.ts | 4 +- .../src/nodes/visual/text.js | 4 +- 3 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 packages/noodl-editor/src/editor/src/models/ElementConfigs/configs/TextConfig.ts diff --git a/packages/noodl-editor/src/editor/src/models/ElementConfigs/configs/TextConfig.ts b/packages/noodl-editor/src/editor/src/models/ElementConfigs/configs/TextConfig.ts new file mode 100644 index 0000000..2e15074 --- /dev/null +++ b/packages/noodl-editor/src/editor/src/models/ElementConfigs/configs/TextConfig.ts @@ -0,0 +1,146 @@ +/** + * TextConfig + * + * Element configuration for Text nodes. + * Defines default styling and 10 typography variants. + * + * @module noodl-editor/models/ElementConfigs/configs + * @since 1.2.0 + */ + +import type { ElementConfig } from '../ElementConfigTypes'; + +/** + * Text element configuration + * Provides comprehensive typography system with semantic variants + */ +export const TextConfig: ElementConfig = { + nodeType: 'net.noodl.visual.text', + + description: 'Text element with semantic typography variants', + + categories: ['text', 'typography', 'content'], + + // Default properties applied when a new Text is created + defaults: { + // FIX: Change from width: 100% to width: auto + width: 'auto', + height: 'auto', + + // Layout - Enable flex for proper auto-sizing + display: 'inline-block', + + // Typography + fontSize: 'var(--text-base)', + fontWeight: 'var(--font-normal)', + fontFamily: 'var(--font-sans)', + lineHeight: 'var(--leading-normal)', + color: 'var(--foreground)', + + // Spacing + margin: '0', + padding: '0', + + // Text behavior + whiteSpace: 'normal', + wordWrap: 'break-word', + textAlign: 'left', + + // Default variant + _variant: 'body' + }, + + // Typography variants - semantic naming + variants: { + // Display: Extra large, hero text + display: { + fontSize: 'var(--text-4xl)', + fontWeight: 'var(--font-bold)', + lineHeight: 'var(--leading-tight)', + letterSpacing: '-0.02em', + color: 'var(--foreground)' + }, + + // H1: Main page heading + h1: { + fontSize: 'var(--text-3xl)', + fontWeight: 'var(--font-bold)', + lineHeight: 'var(--leading-tight)', + letterSpacing: '-0.015em', + color: 'var(--foreground)' + }, + + // H2: Section heading + h2: { + fontSize: 'var(--text-2xl)', + fontWeight: 'var(--font-semibold)', + lineHeight: 'var(--leading-tight)', + letterSpacing: '-0.01em', + color: 'var(--foreground)' + }, + + // H3: Subsection heading + h3: { + fontSize: 'var(--text-xl)', + fontWeight: 'var(--font-semibold)', + lineHeight: 'var(--leading-snug)', + color: 'var(--foreground)' + }, + + // H4: Small heading + h4: { + fontSize: 'var(--text-lg)', + fontWeight: 'var(--font-medium)', + lineHeight: 'var(--leading-snug)', + color: 'var(--foreground)' + }, + + // Body: Default text (16px) + body: { + fontSize: 'var(--text-base)', + fontWeight: 'var(--font-normal)', + lineHeight: 'var(--leading-normal)', + color: 'var(--foreground)' + }, + + // Body Small: Slightly smaller (14px) + 'body-sm': { + fontSize: 'var(--text-sm)', + fontWeight: 'var(--font-normal)', + lineHeight: 'var(--leading-normal)', + color: 'var(--foreground)' + }, + + // Caption: Small text for captions (12px) + caption: { + fontSize: 'var(--text-xs)', + fontWeight: 'var(--font-normal)', + lineHeight: 'var(--leading-relaxed)', + color: 'var(--muted-foreground)', + letterSpacing: '0.01em' + }, + + // Label: Form labels, uppercase small text + label: { + fontSize: 'var(--text-sm)', + fontWeight: 'var(--font-medium)', + lineHeight: 'var(--leading-none)', + color: 'var(--foreground)', + textTransform: 'uppercase', + letterSpacing: '0.05em' + }, + + // Code: Monospace text for code snippets + code: { + fontSize: 'var(--text-sm)', + fontWeight: 'var(--font-normal)', + fontFamily: 'var(--font-mono)', + lineHeight: 'var(--leading-relaxed)', + color: 'var(--foreground)', + backgroundColor: 'var(--muted)', + padding: '2px 6px', + borderRadius: 'var(--radius-sm)', + whiteSpace: 'pre-wrap' + } + } +}; diff --git a/packages/noodl-editor/src/editor/src/models/ElementConfigs/configs/index.ts b/packages/noodl-editor/src/editor/src/models/ElementConfigs/configs/index.ts index a543b46..8c8edba 100644 --- a/packages/noodl-editor/src/editor/src/models/ElementConfigs/configs/index.ts +++ b/packages/noodl-editor/src/editor/src/models/ElementConfigs/configs/index.ts @@ -9,9 +9,7 @@ */ export { ButtonConfig } from './ButtonConfig'; - -// TextConfig will be added next -// export { TextConfig } from './TextConfig'; +export { TextConfig } from './TextConfig'; // Other configs to be implemented: // export { GroupConfig } from './GroupConfig'; diff --git a/packages/noodl-viewer-react/src/nodes/visual/text.js b/packages/noodl-viewer-react/src/nodes/visual/text.js index a80d3cb..f80bd8e 100644 --- a/packages/noodl-viewer-react/src/nodes/visual/text.js +++ b/packages/noodl-viewer-react/src/nodes/visual/text.js @@ -28,7 +28,9 @@ const TextNode = { }, defaultCss: { position: 'relative', - display: 'flex' + display: 'flex', + // FIX: Text should size to content by default, not stretch to parent width + width: 'auto' }, inputProps: { text: {