fml's People
fml's Issues
Create a way to reuse configs across implementations
Part of the motivation behind this library is to be able to declare the interface you want in implementation-agnostic terms. It's currently possible to declare a bunch of component registry types and subsequently declare a corresponding configuration. However, it's completely possible to have the types declared but nothing in the runtime registry, resulting in a runtime exception.
Ideally, there would be a way to declare the types and a corresponding configuration, but not be able to, say, use that configuration for anything meaningful (like passing to a component to render) without adding an implementation to the runtime registry. It gets more complicated, though ๐ญ
To pass that configuration to, say, a React component, should we require all configurations have a corresponding React implementation? To what extend can we mix-and-match implementations? E.g., we can potentially proxy data and function calls between an Angular and React component, similarly between Svelte and Custom Elements, etc., but some would work more easily than others out of the box.
Keeping the configuration agnostic of implementation details affords a couple of interesting abilities:
- Mix/match/swap implementations without touching configurations
- Reuse configurations across projects built with different implementations (e.g., one in React, another in Swift, another in Java...)
Form submission callback signature
The React implementation's Form
component's onSubmit
callback should more closely reflect the native event handler signature. As a user, it was confusing to have a second argument for the event and have to explicitly call preventDefault
- putting the event as the first arg will feel more ergonomic.
React: further separate display/rendering from state management
As it stands now, it isn't as easy as I'd like it to be to alter the display of form sections (e.g., label styling, fieldset legends, etc.). I'd like to distill the React implementation down as much as possible to make it really trivial to change how something renders while providing the state propagation as close to "for free" as possible.
One idea: Export more generic hooks that provide the appropriate state management dynamically (so consumers don't have to learn multiple hooks, they just get callbacks and already-rendered content).
Another idea: Have a separate registry for renderers that can be dynamically resolved. Every overridable component would have to have a compatible interface.
More ideas might come later.
Add linting
Add linting
Implement React bindings
Layouts
Create typing extensions for alternate layouts, including:
- Wizards
- Drawers
- Tabs
React: Required fields should indicate they are required
We should render a red asterisk or something
React: revise hook return method names
It's a bit awkward to have names like handleBlur
return from the hook bind to onBlur
on the component - would make it more ergonomic to match the native event handler names more closely and enable spreading of props
React: ease resolution of FmlComponentProps
Currently, config extensions have to be specified in two locations:
// first in the config registry augmentation:
declare module '@fml/core' {
export interface FmlFieldControlRegistry<TValue>
extends Record<string, FmlFieldControlRegistration<unknown>> {
customImpl: [string | undefined, { extra: { stuff: boolean } }];
}
}
// then again where the component is implemented and used:
interface CustomImplProps extends FmlComponentProps<string | undefined> {
extra: {
stuff: boolean;
}
}
registerControl('customImpl', CustomImpl);
function MuiText(props: CustomImplProps) {
// ...
}
As a consumer, it would be more convenient to resolve the config extension for the corresponding, already-registered component - something like this:
declare module '@fml/core' {
export interface FmlFieldControlRegistry<TValue>
extends Record<string, FmlFieldControlRegistration<unknown>> {
customImpl: [string | undefined, { extra: { stuff: boolean } }];
}
}
registerComponent('customImpl', CustomImpl)
function CustomImpl(props: FmlComponentProps<'customImpl'>) {
// ...
}
Core: tests
React: revise handling of defaultValue
As a consumer, I want to optionally specify different default values for different form fields, but conflicts can arise when rendering a form with a default value set to the value of an existing object. For example:
interface Thing {
dataProperty: string
}
const { data } = useQuery('whatever', () => fetch('/api/things/123'))
// async returns something like { dataProperty: 'i came from the api' }
...
return (
<Form
config={{
defaultValue={data}
schema: {
dataProperty: {
defaultValue: '' // ?!?! should this not use 'i came from the api' as the defaultValue?
}
}
}}
/>
)
Gets much more complicated with lists and models ๐ฌ
Behaviors
Create typing extensions for adding behaviors to sections of forms, such as
- Hide a particular field if another field's value is greater than X
- Field selections need to be strongly typed - this could be challenging :|
- Take some influence from the MongoDB query syntax (eq, in, gt/gte, lt/lte, etc.) for comparisons
- Disable a field if another field's value is equal to X
- others?
React: tests
React: revise hook onChange signature
It's awkward to have a value
and validity
in this object and have to pass both back to the change handler - let's
- Output the
value
andvalidity
separately - Push the validity checking responsibility back into the change handler provided by the hook, only requiring the consumer to pass the
value
like this:onChange={e => hookReturn.onChange({ value })}
Revise config contract
Given the stability of the function signature for JSX elements, I'd like to explore consistently configuring everything as follows:
[tagName, properties, ...validChildren]
Core: support explicit ordering of model properties
properties end up getting rendered in declaration order, but the order of iteration isnt guaranteed - fix this :)
Conditionally enable submission
As a user, it is often convenient to have custom submission handling. Let's make the onSubmit
prop for the Form
in the React implementation optional and conditionally render the submit
button.
React: ease extension of FmlComponentProps<Value>
Types aren't defined to easily reflect how FmlComponent implementation configs can be extended.
As it stands right now, the extra props are mixed into props.config
, like this:
declare module '@fml/core' {
export interface FmlFieldControlRegistry<TValue>
extends Record<string, FmlFieldControlRegistration<unknown>> {
customImpl: [string | undefined, { stuff: boolean }];
}
}
function CustomImpl(props) {
console.log(props) // { config: { stuff: false, ...rest } }
}
but the interface makes it seem like it should add extra props to... well, y'know, the PROPS, like this:
interface CustomProps extends FmlComponentProps<string | undefined> {
stuff: boolean;
}
function CustomImpl(props: CustomProps) {
const {
config,
stuff // this doesn't actually exist, but the types make it seem like it ought to ๐ญ
} = props
}
Let's add another generic argument for extra props to FmlComponentProps
:
interface FmlComponentProps<Value, ExtraConfig extends never = never> {
config: FmlConfiguration<TValue> & ExtraConfig;
}
Core: support string templating for labels
As a user, it is nice to have the label contain additional, contextual information about the property I am editing, especially in lists. For example:
<ul>
<li>
<label for='label1'>
Phone number:
</label>
<input id='label1' type='text' />
</li>
<li>
<label for='label2'>
Phone number:
</label>
<input id='label2' type='text' />
</li>
<li>
<label for='label3'>
Phone number:
</label>
<input id='label3' type='text' />
</li>
</ul>
It sometimes isn't very clear which phone number the user is editing (home, business, etc.), and this is especially true when the list contains nested objects.
Ideally the string templating could safely resolve any nested property in the bound data, so we could do things like:
{
label: 'Phone number ({ type }):'
}
Prefer single curly brackets or some other syntax? Don't want to confuse it with native string interpolation syntax...
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. ๐๐๐
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google โค๏ธ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.