@glint/template 0.9.0 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,4 @@
1
+ import { AttrValue, ContentValue } from '..';
1
2
  import {
2
3
  AcceptsBlocks,
3
4
  AnyContext,
@@ -8,18 +9,18 @@ import {
8
9
  Invokable,
9
10
  TemplateContext,
10
11
  } from '../integration';
11
- import { ElementForTagName, EmittableValue } from './types';
12
+ import { ElementForTagName } from './types';
12
13
 
13
14
  /*
14
- * Emits the given value to the DOM. This corresponds to a mustache
15
- * statement either at the top level:
15
+ * Emits the given value as top-level content to the DOM. This:
16
16
  *
17
- * {{value}}
18
- * {{value foo=bar}}
19
- * <div data-x={{value foo=bar}}>
20
- * <div data-x="hello {{value foo=bar}}">
17
+ * Hello, {{world}}
18
+ *
19
+ * Would produce code like:
20
+ *
21
+ * emitContent(resolveOrReturn(value)({}))
21
22
  */
22
- export declare function emitValue(value: AcceptsBlocks<{}, any> | EmittableValue): void;
23
+ export declare function emitContent(value: ContentValue): void;
23
24
 
24
25
  /*
25
26
  * Emits an element of the given name, providing a value to the
@@ -63,16 +64,36 @@ export declare function emitComponent<T extends AcceptsBlocks<any, any>>(
63
64
  blockParams: T extends AcceptsBlocks<infer Yields, any> ? Required<Yields> : any;
64
65
  };
65
66
 
66
- /**
67
- * Acts as a top-level wrapper for translated template bodies. The given
68
- * callback accepts a template context value as well as an instance of the
67
+ /*
68
+ * Wraps a template body that appears as a standalone expression and is therefore not
69
+ * associated with any backing value.
70
+ *
71
+ * The given callback accepts a template context value as well as an instance of the
69
72
  * environment's DSL export.
70
73
  */
71
- export declare function template<
74
+ export declare function templateExpression<
72
75
  Signature extends AnyFunction = (args: EmptyObject) => AcceptsBlocks<EmptyObject>,
73
76
  Context extends AnyContext = TemplateContext<void, EmptyObject, EmptyObject, void>
74
77
  >(f: (𝚪: Context, χ: never) => void): new () => Invokable<Signature> & HasContext<Context>;
75
78
 
79
+ /*
80
+ * Wraps a template body that's backed by a known value (typically a class), either
81
+ * via a `.hbs` association to a default export or via embedding e.g. with `<template>`.
82
+ *
83
+ * The given callback accepts a template context value as well as an instance of the
84
+ * environment's DSL export.
85
+ *
86
+ * Note that this signature is structured carefully to trigger TypeScript's higher-order function
87
+ * type inference so that any type parameters on the given backing value (if it's a class) will
88
+ * be preserved and reflected in the template body. Both the `Args` type and the constructor return
89
+ * value are necessary for this, despite the fact that we don't actually do anything with those
90
+ * types (see https://github.com/microsoft/TypeScript/pull/30215).
91
+ */
92
+ export declare function templateForBackingValue<Args extends unknown[], Context extends AnyContext>(
93
+ backingValue: abstract new (...args: Args) => HasContext<Context>,
94
+ body: (𝚪: Context, χ: never) => void
95
+ ): abstract new () => unknown;
96
+
76
97
  /*
77
98
  * Used in template bodies to encode a `{{yield}}` statement.
78
99
  *
@@ -82,10 +103,10 @@ export declare function template<
82
103
  *
83
104
  * yieldToBlock(𝚪, 'name', foo, bar);
84
105
  */
85
- export declare function yieldToBlock<Context extends AnyContext, K extends keyof Context['yields']>(
106
+ export declare function yieldToBlock<Context extends AnyContext, K extends keyof Context['blocks']>(
86
107
  𝚪: Context,
87
108
  to: K,
88
- ...values: NonNullable<Context['yields'][K]>
109
+ ...values: NonNullable<Context['blocks'][K]>
89
110
  ): void;
90
111
 
91
112
  /*
@@ -106,7 +127,7 @@ export declare function applySplattributes<
106
127
  * <div foo={{bar}}></div>
107
128
  * <AnotherComponent foo={{bar}} />
108
129
  */
109
- export declare function applyAttributes(element: Element, attrs: Record<string, unknown>): void;
130
+ export declare function applyAttributes(element: Element, attrs: Record<string, AttrValue>): void;
110
131
 
111
132
  /*
112
133
  * Applies a modifier to an element or component.
@@ -1,4 +1,4 @@
1
- import { EmptyObject, HasContext } from '@glint/template/-private/integration';
1
+ import { EmptyObject } from '@glint/template/-private/integration';
2
2
 
3
3
  type Constructor<T> = abstract new (...args: never[]) => T;
4
4
 
@@ -19,22 +19,3 @@ export type ElementForTagName<Name extends string> = Name extends keyof HTMLElem
19
19
  : Name extends keyof SVGElementTagNameMap
20
20
  ? SVGElementTagNameMap[Name]
21
21
  : Element;
22
-
23
- /**
24
- * Given the constructor or instance type of a component backing class, produces the appropriate
25
- * `TemplateContext` type for its template.
26
- */
27
- export type ResolveContext<T> = T extends HasContext<infer Context>
28
- ? Context
29
- : T extends Constructor<HasContext<infer Context>>
30
- ? Context
31
- : unknown;
32
-
33
- // This encompasses both @glimmer/runtime and @ember/template's notion of `SafeString`s,
34
- // and this coverage is tested in `emit-value.test.ts`.
35
- type SafeString = { toHTML(): string };
36
-
37
- /**
38
- * Represents values that can safely be emitted into the DOM i.e. as `<span>{{value}}</span>`.
39
- */
40
- export type EmittableValue = SafeString | Element | string | number | boolean | null | void;
@@ -8,6 +8,36 @@ import {
8
8
  } from './integration';
9
9
  import { ExpandSignature } from '@glimmer/component/-private/component';
10
10
 
11
+ /**
12
+ * Any value that can be safely emitted into the DOM as top-level content,
13
+ * i.e. as `<div>{{value}}</div>`.
14
+ *
15
+ * This includes primitives like strings, numbers and booleans; "nothing"
16
+ * values like `null` and `undefined`; DOM nodes; and blockless curly
17
+ * component invocations.
18
+ */
19
+ export type ContentValue =
20
+ | string
21
+ | number
22
+ | boolean
23
+ | null
24
+ | undefined
25
+ | void
26
+ | SafeString
27
+ | Node
28
+ | ArglessCurlyComponent;
29
+
30
+ /**
31
+ * Any value that can be safely set as an HTML attribute on a DOM node.
32
+ * This includes strings, numbers, booleans and `null`/`undefined`.
33
+ *
34
+ * Note that this does not include functions, as writing something like
35
+ * `onclick={{this.handleClick}}` in a template ultimately relies on
36
+ * fallback behavior in the VM to set the `onclick` property, and is
37
+ * better performed using the `{{on}}` modifier.
38
+ */
39
+ export type AttrValue = string | number | boolean | null | undefined | SafeString;
40
+
11
41
  /**
12
42
  * A value that is invokable like a component in a template. In an
13
43
  * appropriate Glint environment, subclasses of `EmberComponent` and
@@ -112,3 +142,13 @@ type InvokableArgs<S> = [
112
142
  named: GuardEmpty<Get<Get<S, 'Args'>, 'Named'>>,
113
143
  ...positional: Constrain<Get<Get<S, 'Args'>, 'Positional'>, Array<unknown>, []>
114
144
  ];
145
+
146
+ // This encompasses both @glimmer/runtime and @ember/template's notion of `SafeString`s,
147
+ // and this coverage is tested in `emit-content.test.ts`.
148
+ type SafeString = { toHTML(): string };
149
+
150
+ // `{{foo}}` becomes `emitContent(resolveOrReturn(foo)({})`, which means if `foo`
151
+ // is a component that accepts no args, then this is a valid invocation.
152
+ type ArglessCurlyComponent = AcceptsBlocks<{}, any>;
153
+
154
+ export {};
@@ -2,6 +2,9 @@
2
2
  // module exports the symbols and types necessary to declare a class or
3
3
  // other entity as integrating with Glint's template system.
4
4
 
5
+ import { EmptyObject } from '@glimmer/component/-private/component';
6
+ export { EmptyObject };
7
+
5
8
  /** Any function, which is the tighest bound we can put on an object's `[Invoke]` field. */
6
9
  export type AnyFunction = (...params: any) => any;
7
10
 
@@ -23,8 +26,7 @@ export type HasContext<T extends AnyContext = AnyContext> = { [Context]: T };
23
26
  // These shenanigans are necessary to get TS to report when named args
24
27
  // are passed to a signature that doesn't expect any, because `{}` is
25
28
  // special-cased in the type system not to trigger EPC.
26
- declare const EmptyObject: unique symbol;
27
- export type EmptyObject = { [EmptyObject]?: void };
29
+
28
30
  export type GuardEmpty<T> = T extends any ? (keyof T extends never ? EmptyObject : T) : never;
29
31
 
30
32
  declare const Element: unique symbol;
@@ -47,10 +49,10 @@ export type AcceptsBlocks<BlockImpls, El = null> = {
47
49
  * Determines the type of `this` and any `@arg`s used in a template,
48
50
  * as well as valid `{{yield}}` invocations and `...attributes` usage.
49
51
  */
50
- export type TemplateContext<This, Args, Yields, Element> = {
52
+ export type TemplateContext<This, Args, Blocks, Element> = {
51
53
  this: This;
52
54
  args: Args;
53
- yields: Yields;
55
+ blocks: Blocks;
54
56
  element: Element;
55
57
  };
56
58
 
@@ -1,5 +1,10 @@
1
1
  import { AcceptsBlocks, DirectInvokable } from '../integration';
2
2
 
3
3
  export type InElementKeyword = DirectInvokable<{
4
- (args: { insertBefore?: null | undefined }, element: Element): AcceptsBlocks<{ default: [] }>;
4
+ (
5
+ args: {
6
+ insertBefore?: null | undefined;
7
+ },
8
+ element: ShadowRoot | Element
9
+ ): AcceptsBlocks<{ default: [] }>;
5
10
  }>;
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "@glint/template",
3
- "version": "0.9.0",
3
+ "version": "0.9.3",
4
4
  "repository": "typed-ember/glint",
5
5
  "description": "Type definitions to back typechecking for Glimmer templates",
6
6
  "license": "MIT",
7
7
  "author": "Dan Freeman (https://github.com/dfreeman)",
8
8
  "types": "-private/index.d.ts",
9
9
  "scripts": {
10
- "lint": "eslint . --max-warnings 0 && prettier --check .",
11
10
  "test": "tsc --project __tests__"
12
11
  },
13
12
  "files": [
@@ -20,7 +19,7 @@
20
19
  },
21
20
  "devDependencies": {
22
21
  "@glimmer/component": "^1.1.2",
23
- "@glimmerx/component": "^0.4.2",
22
+ "@glimmerx/component": "^0.6.7",
24
23
  "@types/ember__component": "~4.0.8",
25
24
  "expect-type": "0.11.0",
26
25
  "sums-up": "^2.1.0"