hexus / pragma Goto Github PK
View Code? Open in Web Editor NEWDeclarative form builder
Declarative form builder
Denotes paths that should be copied to the keyed path. Cool. ๐
Array values are iterated and the last non-null value is used.
Must be run before other maps, and other maps cannot use the same keys.
Customisable by merging in custom maps that users build into their sheets through the UI.
string
or string[]
values.
'defense.armorClass.abilityModifier': 'abilities.dex.modifier'
// or, for an outdated but relevant example of array values
'defense.armorClass.abilityModifier': ['abilities.dex.modifier', 'abilities.dex.tempModifier']
Denotes paths that should be added to the keyed path... nice. โ๏ธ
Customisable by merging in custom maps that users build into their sheets through the UI.
string
or string[]
values.
'armorClass.total': ['armorClass.armorBonus', 'armorClass.shieldBonus', 'armorClass...', ...]
Customisable by merging in custom maps that users could build into their sheets through the UI.
Denotes fields with values that should be interpolated from other values... tight. ๐
A flattened set of character sheet properties could be passed to these as template arguments.
A select set of Lodash functions could be made available for utility, if needed.
This wouldn't be customisable, or maybe only in an advanced mode with an expression guide.
string
values.
'*.spell.damage': '{class.level}d6'
Interpolating ability modifiers, for example, would require need to be interpolated prior to the propagation mapping. ๐ค
The right solution would involve checking which properties are used in which maps, resolving them backwards, depth first. Properties would be processed individually as part of being processed in a list. Determining these from interpolation maps would be especially fun... it'd have to be part of the interpolation process.
This would also involve keeping track of which have already been processed (removing those processed from a temporary copy of the relevant map).
A domain model suddenly seems less relevant!
Moved from README TODOs
Stencil currently only bundles using Rollup.
With better Public Compiler APIs it should
instead be possible to compile Stencil components and bundle them as part of Webpack, instead of needing to run two
watches. For now, the two watches are seemingly necessary.
Update: The Stencil Core Compiler API is now documented, but there does
not yet appear to be a Webpack plugin that utilises it.
Moved from README TODOs
Consider using Concurrently for the concurrent Webpack & Stencil
watches. The watch script is currently relying on bash's &
.
Build a playground page with a YAML input for form definitions.
Would be fine to look a little like this with the form showing on the right.
There's a lot of duplicated markup and some amounts of duplicated JavaScript.
Moved from README TODOs
Web components can extend built-in HTML elements to inherit functionality and usability.
Stencil doesn't currently support this in any way, but a keen-eyed developer has found a workaround:
Try this out and see if the boilerplate repetition in the Pragma components can be reduced.
Note: This approach doesn't currently include form participation, but the same comment will be updated when the
developer gets around to it.
Moved from README TODOs.
The Pragma runtime (primarily FormProcessor
) is only bundled as a side effect of the example project.
Bundle it separately from the example project after clarifying the shape of Pragma's public API.
Pragma's field definition format is similar to JSON Schema and JSON Editor.
Investigate the overlaps and consider switching over to, and extending, JSON Schema. This could be pretty powerful, but also a overcomplicated due to its extensive feature set (e.g. external references).
Really, the best thing about this approach would be type safety and validation. The worst thing would be potential complexity. Some of this complexity could be avoided if a simplified format could be processed into full JSON Schema.
We could then also provide a meta-schema for the field definitions themselves.
Rough examples of what certain fields types look like now, and what they'd look like with JSON schema.
profile:
type: section
label: Profile
description: Character profile
profile.name:
type: string
label: Name
description: The character's given or chosen name
profile.alignment:
type: selection
label: Alignment
description: The character's general and moral attitude
options:
options:
lawfulGood: Lawful Good
neutralGood: Neutral Good
chaoticGood: Chaotic Good
lawfulNeutral: Lawful Neutral
trueNeutral: True Neutral
chaoticNeutral: Chaotic Neutral
lawfulEvil: Lawful Evil
neutralEvil: Neutral Evil
chaoticEvil: Chaotic Evil
JSON Schema always defines the root, whereas Pragma currently implies one. We can still imply one, we just embed the form fields into the properties
of a type: object
.
type: object
title: Pathfinder Character Sheet
description: JSON Schema for Pragma forms for the Pathfinder roleplaying game.
properties:
profile:
type: object
title: Profile
description: Character profiles
properties:
name:
type: string
title: Name
description: The character's given or chosen name
alignment:
type: string
title: Alignment
description: The character's general and moral attitude
enum: [
'lawfulGood', 'neutralGood', 'chaoticGood', 'lawfulNeutral', 'trueNeutral', 'chaoticNeutral',
'lawfulEvil', 'neutralEvil', 'chaoticEvil'
]
options: # This is where any Pragma-specific data would reside
enumLabels: [
'Lawful Good', 'Neutral Good', 'Chaotic Good', 'Lawful Neutral', 'True Neutral', 'Chaotic Neutral',
'Lawful Evil', 'Neutral Evil', 'Chaotic Evil'
]
It's much more verbose, and introduces the nesting that Pragma's format tries to avoid, but we could find a middle ground that compiles to JSON schema. For example:
profile:
type: object
title: Profile
description: Character profiles
profile.name:
type: string
title: Name
description: The character's given or chosen name
profile.alignment:
type: string
title: Alignment
description: The character's general and moral attitude
enum: [
'lawfulGood', 'neutralGood', 'chaoticGood', 'lawfulNeutral', 'trueNeutral', 'chaoticNeutral',
'lawfulEvil', 'neutralEvil', 'chaoticEvil'
]
options: # This is where any Pragma-specific data would reside
enumLabels: [
'Lawful Good', 'Neutral Good', 'Chaotic Good', 'Lawful Neutral', 'True Neutral', 'Chaotic Neutral',
'Lawful Evil', 'Neutral Evil', 'Chaotic Evil'
]
What we avoid here is properties
, or in the case of Pragma's current format: children
. We instead rely on full paths like profile.alignment
to set the expected properties for different objects.
tag
, which is usually something like 'pragma-section'
or 'pragma-string'
, could then become JSON Schema's/JSON Editor's format
, which could translate to a theme of tag names to decide how to render.
Considering how such schemas might translate to a server-side implementation, however, this falls apart a bit. E.g. type: string
and format: datetime
, where a server-side representation might just see this instead as a Date
type. However, this isn't too much of a problem, as we're specifying a JSON format.
Complete updates are expensive because they update every field regardless of what's changed. This can be optimised by diffing the given data with the current form data, and only updating the leaf paths that changed.
In some situations it may be faster to only update the common ancestors that changed, but typically the form structure is fairly static.
A set of web components could be used to either fully render a form, or selectively render parts of a form. Using field definitions for layout is then optional.
<pragma-form>
would be a decorator element that propagates field data to any relevant children, internally managing a Pragma Form
instance.
<pragma-form fields="..." data="...">
<form>
<div class="saves">
<!-- Automatically render a subset of fields -->
<pragma-fields path="defense.saves"/>
</div>
<!-- Manually lay out elements for fields -->
<textarea name="defense.notes"></textarea>
<!-- Define layout for field templates -->
<template name="templates.spell">
<div class="spell">
<input type="text" name="templates.spell.name"/>
<!-- ... -->
</div>
</template>
</form>
</pragma-form>
<pragma-form>
and <pragma-fields>
elements could optionally load field sets by themselves.
<pragma-form src="/fields.json" data="...">
<pragma-fields/>
</pragma>
<pragma-fields src="/fields.yaml" path="defense.saves"/>
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.