Skip to content

Introduce template primitives for modifiers and attrs #70

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 19, 2021

Conversation

dfreeman
Copy link
Member

Overview

This PR introduces template primitives for enforcing some degree of type safety with attributes and modifiers. It retires invokeModifier and introduces three new primitives:

function applyAttributes<TargetElement extends Element>(attrs: Record<string, unknown>): void;
function applySplattributes<SourceElement extends Element, TargetElement extends Element>(): void;
function applyModifier<TargetElement extends Element>(modifier: CreatesModifier<TargetElement>): void;

It also introduces ElementForTagName and ElementForComponent utility types that take a tag name or an invokable constructor respectively and give an appropriate Element subtype, or null in the case of a component with no root element.

Finally, it adds an Element field to component signatures and propagates that information to be available both for invoking them and in their template context (𝚪) in order to ensure that:

  • a component being invoked accepts attributes at all
  • any modifiers being applied to a component are compatible with its root element
  • forwarding attributes and modifiers via ...attributes within a template is legal (i.e. the target element is equivalent to or a subtype of the component's declare Element)

Examples

Attributes

<div foo="bar"></div>
<SomeComponent foo="bar" />
applyAttributes<ElementForTagName<'div'>>({ foo: 'bar' });
applyAttributes<ElementForComponent<typeof SomeComponent>>({ foo: 'bar' });

Splattributes

<div ...attributes></div>
<SomeComponent ...attributes />
applySplattributes<typeof 𝚪.element, ElementForTagName<'div'>>;
applySplattributes<typeof 𝚪.element, ElementForComponent<typeof SomeComponent>>;

Modifiers

<div {{someModifier}}></div>
<SomeComponent {{someModifier}} />
applyModifier<ElementForTagName<'div'>>(resolve(someModifier)({}));
applyModifier<ElementForComponent<typeof SomeComponent>>(resolve(someModifier)({}));

Notes

This is a breaking change, so I'll probably aim to cut a v0.4.0 release in the near future, depending on the timing of the announcement blog post. If possible I'm also hoping to land some internal cleanup (rationalizing module layout, fixing up some type names, that sort of thing) soon, but that won't block release if we're ready to go sooner.

Closes #21.

@dfreeman dfreeman added the breaking A breaking change label Mar 17, 2021
@dfreeman dfreeman force-pushed the attrs-and-modifiers branch from d5c2ce9 to ce9a9ca Compare March 17, 2021 22:37
@dfreeman dfreeman merged commit ece9bc6 into master Mar 19, 2021
@dfreeman dfreeman deleted the attrs-and-modifiers branch March 19, 2021 08:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking A breaking change
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Attribute and modifier handling
2 participants