Pure, framework-free core: port media + color schemes with compatibility rules, typed/grouped property model with coercion and validation, catalogue store with physics seeds, SVG symbol registry with port layouts, and a mass-conserving mock flow solver. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
138 lines
4.8 KiB
TypeScript
138 lines
4.8 KiB
TypeScript
/**
|
|
* Reusable property-schema fragments for nodes and edges. Each symbol composes
|
|
* a base (Identity + Presentation) with its own Physics group.
|
|
*/
|
|
import type { PropertyGroup, PropertySchema, PropertyDef } from './properties'
|
|
|
|
const yesNo: PropertyDef['options'] = [
|
|
{ value: 'yes', label: 'Show' },
|
|
{ value: 'no', label: 'Hide' }
|
|
]
|
|
|
|
export function identityGroup(defaultTitle: string): PropertyGroup {
|
|
return {
|
|
id: 'identity',
|
|
label: 'Identity',
|
|
defs: [
|
|
{ key: 'title', label: 'Title', type: 'string', group: 'identity', default: defaultTitle },
|
|
{ key: 'tag', label: 'Tag / ID', type: 'string', group: 'identity', default: '' },
|
|
{
|
|
key: 'notes',
|
|
label: 'Notes',
|
|
type: 'string',
|
|
group: 'identity',
|
|
default: ''
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
export function nodePresentationGroup(color: string): PropertyGroup {
|
|
return {
|
|
id: 'presentation',
|
|
label: 'Presentation',
|
|
defs: [
|
|
{ key: 'color', label: 'Accent color', type: 'color', group: 'presentation', default: color },
|
|
{
|
|
key: 'rotation',
|
|
label: 'Rotation',
|
|
type: 'int',
|
|
group: 'presentation',
|
|
unit: '°',
|
|
min: 0,
|
|
max: 270,
|
|
step: 90,
|
|
default: 0
|
|
},
|
|
{ key: 'width', label: 'Width', type: 'int', group: 'presentation', unit: 'px', min: 24, max: 240, default: 72 },
|
|
{ key: 'height', label: 'Height', type: 'int', group: 'presentation', unit: 'px', min: 24, max: 240, default: 72 },
|
|
{ key: 'showLabel', label: 'Label', type: 'enum', group: 'presentation', options: yesNo, default: 'yes' }
|
|
]
|
|
}
|
|
}
|
|
|
|
export function physicsGroup(defs: PropertyDef[]): PropertyGroup {
|
|
return { id: 'physics', label: 'Physics', defs: defs.map((d) => ({ ...d, group: 'physics' })) }
|
|
}
|
|
|
|
/** Build a node schema from a physics-group definition list. */
|
|
export function nodeSchema(
|
|
defaultTitle: string,
|
|
color: string,
|
|
physics: PropertyDef[]
|
|
): PropertySchema {
|
|
return [identityGroup(defaultTitle), nodePresentationGroup(color), physicsGroup(physics)]
|
|
}
|
|
|
|
// ---- Edge schema ----------------------------------------------------------
|
|
|
|
export const MARKER_OPTIONS: PropertyDef['options'] = [
|
|
{ value: 'none', label: 'None' },
|
|
{ value: 'arrow', label: 'Arrow' },
|
|
{ value: 'openArrow', label: 'Open arrow' },
|
|
{ value: 'circle', label: 'Circle' },
|
|
{ value: 'diamond', label: 'Diamond' },
|
|
{ value: 'bar', label: 'Bar' }
|
|
]
|
|
|
|
export const LINE_STYLE_OPTIONS: PropertyDef['options'] = [
|
|
{ value: 'solid', label: 'Solid' },
|
|
{ value: 'dashed', label: 'Dashed' },
|
|
{ value: 'dotted', label: 'Dotted' }
|
|
]
|
|
|
|
export function edgeSchema(): PropertySchema {
|
|
return [
|
|
{
|
|
id: 'identity',
|
|
label: 'Identity',
|
|
defs: [
|
|
{ key: 'title', label: 'Title', type: 'string', group: 'identity', default: '' },
|
|
{ key: 'tag', label: 'Tag / ID', type: 'string', group: 'identity', default: '' }
|
|
]
|
|
},
|
|
{
|
|
id: 'presentation',
|
|
label: 'Presentation',
|
|
defs: [
|
|
{ key: 'color', label: 'Line color', type: 'color', group: 'presentation', default: '#2f7fe0' },
|
|
{ key: 'lineStyle', label: 'Line style', type: 'enum', group: 'presentation', options: LINE_STYLE_OPTIONS, default: 'solid' },
|
|
{ key: 'strokeWidth', label: 'Width', type: 'int', group: 'presentation', unit: 'px', min: 1, max: 12, default: 3 },
|
|
{ key: 'tailMarker', label: 'Tail marker', type: 'enum', group: 'presentation', options: MARKER_OPTIONS, default: 'none' },
|
|
{ key: 'headMarker', label: 'Head marker', type: 'enum', group: 'presentation', options: MARKER_OPTIONS, default: 'arrow' }
|
|
]
|
|
},
|
|
{
|
|
id: 'physics',
|
|
label: 'Physics',
|
|
defs: [
|
|
{ key: 'length', label: 'Length', type: 'float', group: 'physics', unit: 'm', min: 0, step: 0.1, default: 10 },
|
|
{ key: 'diameter', label: 'Diameter', type: 'float', group: 'physics', unit: 'mm', min: 1, step: 1, default: 100 },
|
|
{ key: 'material', label: 'Material', type: 'catalogueItem', group: 'physics', catalogue: 'pipeMaterial', default: 'steel' },
|
|
{ key: 'roughness', label: 'Roughness', type: 'float', group: 'physics', unit: 'mm', min: 0, step: 0.001, default: 0.045 },
|
|
{
|
|
key: 'flowType',
|
|
label: 'Flow type',
|
|
type: 'enum',
|
|
group: 'physics',
|
|
options: [
|
|
{ value: 'auto', label: 'Auto' },
|
|
{ value: 'laminar', label: 'Laminar' },
|
|
{ value: 'turbulent', label: 'Turbulent' }
|
|
],
|
|
default: 'auto'
|
|
},
|
|
{ key: 'designFlow', label: 'Design flow', type: 'float', group: 'physics', unit: 'm³/h', min: 0, step: 0.1, default: 0 },
|
|
{
|
|
key: 'tags',
|
|
label: 'Zone tags',
|
|
type: 'listOfValues',
|
|
group: 'physics',
|
|
itemType: 'string',
|
|
default: []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|