mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-03-08 01:53:30 +01:00
feat(element-configs): Complete STYLE-002 MVP 2 - Add Group, TextInput, Image configs
- Add GroupConfig with 7 variants (default, card, section, inset, flex-row, flex-col, centered)
- Add TextInputConfig with 2 variants (default, error) and 4 states
- Add ImageConfig with 3 variants (default, rounded, circle)
- Register all 5 configs in initElementConfigs()
- Node creation hook already implemented in NodeGraphNode constructor
- Total: 5 configs with 28 variants across all elements
- All configs use design tokens for theming
MVP 2 Status: ✅ Complete (ready for integration testing)
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* GroupConfig
|
||||
*
|
||||
* Element configuration for Group nodes.
|
||||
* Defines default layout properties and 7 variants for common use cases.
|
||||
*
|
||||
* @module noodl-editor/models/ElementConfigs/configs
|
||||
* @since 1.2.0
|
||||
*/
|
||||
|
||||
import type { ElementConfig } from '../ElementConfigTypes';
|
||||
|
||||
/**
|
||||
* Group element configuration
|
||||
* Provides flexible layout container styles with multiple variants
|
||||
*/
|
||||
export const GroupConfig: ElementConfig = {
|
||||
nodeType: 'Group',
|
||||
|
||||
description: 'Flexible container element for layout composition',
|
||||
|
||||
categories: ['layout', 'container'],
|
||||
|
||||
// Default properties applied when a new Group is created
|
||||
defaults: {
|
||||
// Layout
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'relative',
|
||||
|
||||
// Spacing
|
||||
gap: 'var(--space-4)',
|
||||
padding: '0',
|
||||
|
||||
// Sizing
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
|
||||
// Default variant
|
||||
_variant: 'default'
|
||||
},
|
||||
|
||||
// Style variants
|
||||
variants: {
|
||||
// Default: Simple flex column container
|
||||
default: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 'var(--space-4)',
|
||||
padding: '0',
|
||||
backgroundColor: 'transparent'
|
||||
},
|
||||
|
||||
// Card: Elevated container with border and shadow
|
||||
card: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 'var(--space-4)',
|
||||
padding: 'var(--space-4)',
|
||||
backgroundColor: 'var(--theme-color-bg-3)',
|
||||
borderRadius: 'var(--radius-lg)',
|
||||
borderWidth: 'var(--border-1)',
|
||||
borderStyle: 'solid',
|
||||
borderColor: 'var(--theme-color-border-default)',
|
||||
boxShadow: 'var(--shadow-sm)'
|
||||
},
|
||||
|
||||
// Section: Content section with padding
|
||||
section: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 'var(--space-6)',
|
||||
paddingTop: 'var(--space-8)',
|
||||
paddingBottom: 'var(--space-8)',
|
||||
paddingLeft: 'var(--space-6)',
|
||||
paddingRight: 'var(--space-6)',
|
||||
backgroundColor: 'transparent'
|
||||
},
|
||||
|
||||
// Inset: Subtle background for nested content
|
||||
inset: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 'var(--space-3)',
|
||||
padding: 'var(--space-3)',
|
||||
backgroundColor: 'var(--theme-color-bg-2)',
|
||||
borderRadius: 'var(--radius-md)'
|
||||
},
|
||||
|
||||
// Flex Row: Horizontal layout
|
||||
'flex-row': {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
gap: 'var(--space-4)',
|
||||
alignItems: 'center',
|
||||
padding: '0',
|
||||
backgroundColor: 'transparent'
|
||||
},
|
||||
|
||||
// Flex Column: Vertical layout (explicit)
|
||||
'flex-col': {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 'var(--space-4)',
|
||||
padding: '0',
|
||||
backgroundColor: 'transparent'
|
||||
},
|
||||
|
||||
// Centered: Center content both horizontally and vertically
|
||||
centered: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 'var(--space-4)',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: 'var(--space-4)',
|
||||
backgroundColor: 'transparent'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* ImageConfig
|
||||
*
|
||||
* Element configuration for Image nodes.
|
||||
* Defines default styling and 3 variants for common image presentations.
|
||||
*
|
||||
* @module noodl-editor/models/ElementConfigs/configs
|
||||
* @since 1.2.0
|
||||
*/
|
||||
|
||||
import type { ElementConfig } from '../ElementConfigTypes';
|
||||
|
||||
/**
|
||||
* Image element configuration
|
||||
* Provides flexible image display styles with shape variants
|
||||
*/
|
||||
export const ImageConfig: ElementConfig = {
|
||||
nodeType: 'net.noodl.visual.image',
|
||||
|
||||
description: 'Image element with shape and sizing variants',
|
||||
|
||||
categories: ['media', 'visual'],
|
||||
|
||||
// Default properties applied when a new Image is created
|
||||
defaults: {
|
||||
// Sizing
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
maxWidth: '100%',
|
||||
|
||||
// Display
|
||||
display: 'block',
|
||||
objectFit: 'cover',
|
||||
objectPosition: 'center',
|
||||
|
||||
// Border
|
||||
borderRadius: '0',
|
||||
borderWidth: '0',
|
||||
borderStyle: 'solid',
|
||||
borderColor: 'transparent',
|
||||
|
||||
// Background (for loading/error states)
|
||||
backgroundColor: 'var(--theme-color-bg-2)',
|
||||
|
||||
// Default variant
|
||||
_variant: 'default'
|
||||
},
|
||||
|
||||
// Style variants
|
||||
variants: {
|
||||
// Default: Standard rectangular image
|
||||
default: {
|
||||
borderRadius: '0',
|
||||
objectFit: 'cover',
|
||||
objectPosition: 'center',
|
||||
overflow: 'hidden'
|
||||
},
|
||||
|
||||
// Rounded: Image with rounded corners
|
||||
rounded: {
|
||||
borderRadius: 'var(--radius-lg)',
|
||||
objectFit: 'cover',
|
||||
objectPosition: 'center',
|
||||
overflow: 'hidden'
|
||||
},
|
||||
|
||||
// Circle: Circular image (for avatars, icons)
|
||||
circle: {
|
||||
borderRadius: '9999px',
|
||||
objectFit: 'cover',
|
||||
objectPosition: 'center',
|
||||
overflow: 'hidden',
|
||||
aspectRatio: '1 / 1' // Ensure square for perfect circle
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* TextInputConfig
|
||||
*
|
||||
* Element configuration for TextInput nodes.
|
||||
* Defines default styling, 2 variants, and state-based styling.
|
||||
*
|
||||
* @module noodl-editor/models/ElementConfigs/configs
|
||||
* @since 1.2.0
|
||||
*/
|
||||
|
||||
import type { ElementConfig } from '../ElementConfigTypes';
|
||||
|
||||
/**
|
||||
* TextInput element configuration
|
||||
* Provides modern, accessible input field styles
|
||||
*/
|
||||
export const TextInputConfig: ElementConfig = {
|
||||
nodeType: 'net.noodl.controls.textinput',
|
||||
|
||||
description: 'Interactive text input field with validation states',
|
||||
|
||||
categories: ['input', 'form', 'interactive'],
|
||||
|
||||
// Default properties applied when a new TextInput is created
|
||||
defaults: {
|
||||
// Layout
|
||||
paddingTop: 'var(--space-2)',
|
||||
paddingBottom: 'var(--space-2)',
|
||||
paddingLeft: 'var(--space-3)',
|
||||
paddingRight: 'var(--space-3)',
|
||||
width: '100%',
|
||||
height: '40px',
|
||||
|
||||
// Typography
|
||||
fontSize: 'var(--text-sm)',
|
||||
fontWeight: 'var(--font-normal)',
|
||||
fontFamily: 'var(--font-sans)',
|
||||
lineHeight: 'var(--leading-normal)',
|
||||
color: 'var(--theme-color-fg-default)',
|
||||
|
||||
// Border
|
||||
borderRadius: 'var(--radius-md)',
|
||||
borderWidth: 'var(--border-1)',
|
||||
borderStyle: 'solid',
|
||||
borderColor: 'var(--theme-color-border-default)',
|
||||
|
||||
// Background
|
||||
backgroundColor: 'var(--theme-color-bg-3)',
|
||||
|
||||
// Display
|
||||
display: 'block',
|
||||
outline: 'none',
|
||||
|
||||
// Transitions
|
||||
transitionProperty: 'border-color, box-shadow, background-color',
|
||||
transitionDuration: '150ms',
|
||||
transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
|
||||
// Default variant
|
||||
_variant: 'default'
|
||||
},
|
||||
|
||||
// Style variants
|
||||
variants: {
|
||||
// Default: Standard input appearance
|
||||
default: {
|
||||
backgroundColor: 'var(--theme-color-bg-3)',
|
||||
borderColor: 'var(--theme-color-border-default)',
|
||||
color: 'var(--theme-color-fg-default)',
|
||||
|
||||
states: {
|
||||
focus: {
|
||||
borderColor: 'var(--primary)',
|
||||
boxShadow: '0 0 0 3px var(--primary-alpha-20)',
|
||||
outline: 'none'
|
||||
},
|
||||
hover: {
|
||||
borderColor: 'var(--theme-color-border-hover)'
|
||||
},
|
||||
disabled: {
|
||||
opacity: '0.5',
|
||||
cursor: 'not-allowed',
|
||||
backgroundColor: 'var(--theme-color-bg-2)',
|
||||
color: 'var(--theme-color-fg-default-shy)'
|
||||
},
|
||||
placeholder: {
|
||||
color: 'var(--theme-color-fg-default-shy)',
|
||||
opacity: '0.6'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Error: Validation error state
|
||||
error: {
|
||||
backgroundColor: 'var(--theme-color-bg-3)',
|
||||
borderColor: 'var(--destructive)',
|
||||
color: 'var(--theme-color-fg-default)',
|
||||
|
||||
states: {
|
||||
focus: {
|
||||
borderColor: 'var(--destructive)',
|
||||
boxShadow: '0 0 0 3px var(--destructive-alpha-20)',
|
||||
outline: 'none'
|
||||
},
|
||||
hover: {
|
||||
borderColor: 'var(--destructive-hover)'
|
||||
},
|
||||
disabled: {
|
||||
opacity: '0.5',
|
||||
cursor: 'not-allowed',
|
||||
backgroundColor: 'var(--theme-color-bg-2)',
|
||||
color: 'var(--theme-color-fg-default-shy)'
|
||||
},
|
||||
placeholder: {
|
||||
color: 'var(--theme-color-fg-default-shy)',
|
||||
opacity: '0.6'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
export { ButtonConfig } from './ButtonConfig';
|
||||
export { TextConfig } from './TextConfig';
|
||||
|
||||
// Other configs to be implemented:
|
||||
// export { GroupConfig } from './GroupConfig';
|
||||
// export { TextInputConfig } from './TextInputConfig';
|
||||
// export { ImageConfig } from './ImageConfig';
|
||||
export { GroupConfig } from './GroupConfig';
|
||||
export { TextInputConfig } from './TextInputConfig';
|
||||
export { ImageConfig } from './ImageConfig';
|
||||
|
||||
@@ -25,11 +25,14 @@ export * from './configs';
|
||||
*/
|
||||
export function initElementConfigs(): void {
|
||||
// Import configs and register them
|
||||
import('./configs').then(({ ButtonConfig, TextConfig }) => {
|
||||
import('./configs').then(({ ButtonConfig, TextConfig, GroupConfig, TextInputConfig, ImageConfig }) => {
|
||||
// Import registry from local module
|
||||
import('./ElementConfigRegistry').then(({ ElementConfigRegistry }) => {
|
||||
ElementConfigRegistry.instance.register(ButtonConfig);
|
||||
ElementConfigRegistry.instance.register(TextConfig);
|
||||
ElementConfigRegistry.instance.register(GroupConfig);
|
||||
ElementConfigRegistry.instance.register(TextInputConfig);
|
||||
ElementConfigRegistry.instance.register(ImageConfig);
|
||||
|
||||
console.log('[ElementConfigs] Initialized with', ElementConfigRegistry.instance.getCount(), 'configs');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user