fragtml 0.0.2 → 0.0.4
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.
- package/README.md +132 -51
- package/index.d.ts +4 -1
- package/index.d.ts.map +1 -1
- package/index.js +5 -2
- package/lib/create-tag.d.ts +1 -15
- package/lib/create-tag.d.ts.map +1 -1
- package/lib/create-tag.js +16 -27
- package/lib/fragment.d.ts +2 -17
- package/lib/fragment.d.ts.map +1 -1
- package/lib/fragment.js +9 -10
- package/lib/html-result.d.ts +2 -2
- package/lib/html-result.d.ts.map +1 -1
- package/lib/html-result.js +1 -2
- package/lib/html-types.d.ts +23 -2
- package/lib/html-types.d.ts.map +1 -1
- package/lib/html-types.ts +34 -3
- package/package.json +3 -1
- package/types.d.ts +4 -0
- package/types.d.ts.map +1 -0
package/README.md
CHANGED
|
@@ -156,45 +156,15 @@ html`<button ?disabled="${loading}">Save</button>`
|
|
|
156
156
|
html`<button ?disabled='${loading}'>Save</button>`
|
|
157
157
|
```
|
|
158
158
|
|
|
159
|
-
##
|
|
160
|
-
|
|
161
|
-
`html(options)` returns a configured tag. This is useful for fragment rendering and for editor syntax highlighting, because many editors highlight tagged templates better when the tag is a simple identifier.
|
|
162
|
-
|
|
163
|
-
```js
|
|
164
|
-
import { createHtml, render } from 'fragtml'
|
|
165
|
-
|
|
166
|
-
export function view ({ fragmentId }) {
|
|
167
|
-
const html = createHtml({ fragmentId })
|
|
168
|
-
|
|
169
|
-
return render(html`
|
|
170
|
-
<main>...</main>
|
|
171
|
-
`)
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
`createHtml` is an alias of `html`:
|
|
176
|
-
|
|
177
|
-
```js
|
|
178
|
-
import html, { createHtml } from 'fragtml'
|
|
179
|
-
|
|
180
|
-
createHtml === html
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
You can also use the short fragment-target form:
|
|
159
|
+
## Fragments
|
|
184
160
|
|
|
185
|
-
|
|
186
|
-
const html = createHtml('archive-ui')
|
|
187
|
-
```
|
|
161
|
+
Fragments mark named ranges inside a larger template. Calling `html(fragmentId)` on that template renders either the full template or one selected fragment:
|
|
188
162
|
|
|
189
|
-
|
|
163
|
+
- `html()` / `html(undefined)` renders the full template.
|
|
164
|
+
- `html('archive-ui')` renders only the `archive-ui` fragment.
|
|
165
|
+
- `html({ fragmentId: 'archive-ui' })` is the options-object form.
|
|
190
166
|
|
|
191
|
-
|
|
192
|
-
const html = createHtml({ fragmentId: 'archive-ui' })
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
## Fragments
|
|
196
|
-
|
|
197
|
-
Fragments mark a named range inside a larger template. Rendering without `fragmentId` returns the whole template. Rendering with `fragmentId` returns only that fragment.
|
|
167
|
+
This lets one view function serve both full-page requests and htmx-style fragment requests by passing the requested fragment ID through to `html(fragmentId)`.
|
|
198
168
|
|
|
199
169
|
This mirrors the htmx article’s idea:
|
|
200
170
|
|
|
@@ -215,12 +185,10 @@ ${html.fragment.end}
|
|
|
215
185
|
### Example
|
|
216
186
|
|
|
217
187
|
```js
|
|
218
|
-
import {
|
|
188
|
+
import html, { render } from 'fragtml'
|
|
219
189
|
|
|
220
190
|
export function contactDetail ({ contact, fragmentId }) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
return render(html`
|
|
191
|
+
return render(html(fragmentId)`
|
|
224
192
|
<html>
|
|
225
193
|
<body>
|
|
226
194
|
<div hx-target="this">
|
|
@@ -253,6 +221,51 @@ contactDetail({ contact, fragmentId: 'archive-ui' })
|
|
|
253
221
|
|
|
254
222
|
Fragment boundary tokens are not included in either output.
|
|
255
223
|
|
|
224
|
+
If you want a simple local tag name for editor highlighting or repeated use, `frag` is an alias of `html`:
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
import { frag, render } from 'fragtml'
|
|
228
|
+
|
|
229
|
+
export function contactDetail ({ contact, fragmentId }) {
|
|
230
|
+
const html = frag(fragmentId)
|
|
231
|
+
|
|
232
|
+
return render(html`
|
|
233
|
+
${html.fragment.start('archive-ui')}
|
|
234
|
+
<button>${contact.archived ? 'Unarchive' : 'Archive'}</button>
|
|
235
|
+
${html.fragment.end}
|
|
236
|
+
`)
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
In TypeScript, you can use an explicit fragment-name union to type-check both incoming fragment IDs and declared fragment boundaries:
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
import { frag, render } from 'fragtml'
|
|
244
|
+
import type { RenderOptions } from 'fragtml/types.js'
|
|
245
|
+
|
|
246
|
+
const contactFragments = {
|
|
247
|
+
archiveUi: 'archive-ui',
|
|
248
|
+
details: 'details'
|
|
249
|
+
} as const
|
|
250
|
+
|
|
251
|
+
type ContactFragment = typeof contactFragments[keyof typeof contactFragments]
|
|
252
|
+
|
|
253
|
+
export function contactDetail ({
|
|
254
|
+
contact,
|
|
255
|
+
fragmentId
|
|
256
|
+
}: {
|
|
257
|
+
contact: Contact
|
|
258
|
+
} & RenderOptions<ContactFragment>) {
|
|
259
|
+
const html = frag<ContactFragment>(fragmentId)
|
|
260
|
+
|
|
261
|
+
return render(html`
|
|
262
|
+
${html.fragment.start(contactFragments.archiveUi)}
|
|
263
|
+
<button>${contact.archived ? 'Unarchive' : 'Archive'}</button>
|
|
264
|
+
${html.fragment.end}
|
|
265
|
+
`)
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
256
269
|
### Fragment rules
|
|
257
270
|
|
|
258
271
|
- Fragment IDs must be unique within a rendered template.
|
|
@@ -266,12 +279,10 @@ Fragment boundary tokens are not included in either output.
|
|
|
266
279
|
Nested fragments are supported with stack semantics. This is useful when a larger region can be re-rendered as a whole, but a smaller region inside it is also a valid htmx update target.
|
|
267
280
|
|
|
268
281
|
```js
|
|
269
|
-
import {
|
|
282
|
+
import html, { render } from 'fragtml'
|
|
270
283
|
|
|
271
284
|
export function page ({ fragmentId }) {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
return render(html`
|
|
285
|
+
return render(html(fragmentId)`
|
|
275
286
|
${html.fragment.start('outer')}
|
|
276
287
|
<section>
|
|
277
288
|
<h2>Outer</h2>
|
|
@@ -311,21 +322,21 @@ Safe-by-default template tag.
|
|
|
311
322
|
html`<p>${value}</p>`
|
|
312
323
|
```
|
|
313
324
|
|
|
314
|
-
|
|
325
|
+
Pass a fragment ID before the tagged template to render a selected fragment from that template:
|
|
315
326
|
|
|
316
327
|
```js
|
|
317
|
-
|
|
318
|
-
|
|
328
|
+
html('name')`...`
|
|
329
|
+
html({ fragmentId: 'name' })`...`
|
|
319
330
|
```
|
|
320
331
|
|
|
321
|
-
### `
|
|
332
|
+
### `frag`
|
|
322
333
|
|
|
323
|
-
Alias of `html`,
|
|
334
|
+
Alias of `html`, useful when you want a local tag name for editor highlighting or repeated use:
|
|
324
335
|
|
|
325
336
|
```js
|
|
326
|
-
import {
|
|
337
|
+
import { frag } from 'fragtml'
|
|
327
338
|
|
|
328
|
-
const html =
|
|
339
|
+
const html = frag(fragmentId)
|
|
329
340
|
```
|
|
330
341
|
|
|
331
342
|
### `render(value)`
|
|
@@ -344,6 +355,42 @@ Marks trusted HTML so it is inserted without escaping.
|
|
|
344
355
|
html`<p>${raw('<strong>trusted</strong>')}</p>`
|
|
345
356
|
```
|
|
346
357
|
|
|
358
|
+
### `HtmlResult`
|
|
359
|
+
|
|
360
|
+
Class returned by `html` and `frag` tagged templates.
|
|
361
|
+
|
|
362
|
+
```js
|
|
363
|
+
import html, { HtmlResult } from 'fragtml'
|
|
364
|
+
|
|
365
|
+
const result = html`<p>Hello</p>`
|
|
366
|
+
|
|
367
|
+
result instanceof HtmlResult
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### `RawHtml`
|
|
371
|
+
|
|
372
|
+
Class returned by `raw(value)` and `html.raw(value)`.
|
|
373
|
+
|
|
374
|
+
```js
|
|
375
|
+
import { RawHtml, raw } from 'fragtml'
|
|
376
|
+
|
|
377
|
+
const trusted = raw('<strong>trusted</strong>')
|
|
378
|
+
|
|
379
|
+
trusted instanceof RawHtml
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Type guards
|
|
383
|
+
|
|
384
|
+
Use the public type guards to narrow unknown values without importing from internal `lib/` paths:
|
|
385
|
+
|
|
386
|
+
```js
|
|
387
|
+
import {
|
|
388
|
+
isFragmentBoundary,
|
|
389
|
+
isHtmlResult,
|
|
390
|
+
isRawHtml
|
|
391
|
+
} from 'fragtml'
|
|
392
|
+
```
|
|
393
|
+
|
|
347
394
|
### Boolean attributes
|
|
348
395
|
|
|
349
396
|
Use unquoted `?name=${condition}` syntax to toggle a boolean attribute.
|
|
@@ -382,6 +429,40 @@ import {
|
|
|
382
429
|
|
|
383
430
|
`fragtml` is written in typed JavaScript and ships generated declaration files.
|
|
384
431
|
|
|
432
|
+
Runtime classes such as `HtmlResult` and `RawHtml` are exported from the package root. Type-only aliases are exported from `fragtml/types.js`:
|
|
433
|
+
|
|
434
|
+
```ts
|
|
435
|
+
import type {
|
|
436
|
+
FragmentBoundary,
|
|
437
|
+
FragmentEndBoundary,
|
|
438
|
+
FragmentHelpers,
|
|
439
|
+
FragmentStartBoundary,
|
|
440
|
+
HtmlArrayScalarSubstitution,
|
|
441
|
+
HtmlArraySubstitution,
|
|
442
|
+
HtmlPrimitiveSubstitution,
|
|
443
|
+
HtmlSubstitution,
|
|
444
|
+
HtmlTag,
|
|
445
|
+
RawHtml,
|
|
446
|
+
RenderOptions,
|
|
447
|
+
TemplateStrings
|
|
448
|
+
} from 'fragtml/types.js'
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
`HtmlResult` is both a runtime class from the package root and an importable type from `fragtml/types.js`:
|
|
452
|
+
|
|
453
|
+
```ts
|
|
454
|
+
import { HtmlResult } from 'fragtml'
|
|
455
|
+
import type { HtmlResult as HtmlResultType } from 'fragtml/types.js'
|
|
456
|
+
|
|
457
|
+
function sendHtml (result: HtmlResultType) {
|
|
458
|
+
return result.toString()
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function isHtmlResultValue (value: unknown): value is HtmlResultType {
|
|
462
|
+
return value instanceof HtmlResult
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
385
466
|
## License
|
|
386
467
|
|
|
387
468
|
MIT
|
package/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export default html;
|
|
2
|
+
export { isFragmentBoundary } from "./lib/fragment.js";
|
|
2
3
|
import { html } from './lib/html.js';
|
|
3
|
-
export const
|
|
4
|
+
export const frag: import("./types.js").HtmlTag;
|
|
4
5
|
import { raw } from './lib/raw.js';
|
|
5
6
|
import { render } from './lib/render.js';
|
|
6
7
|
export { html, raw, render };
|
|
8
|
+
export { HtmlResult, isHtmlResult } from "./lib/html-result.js";
|
|
9
|
+
export { RawHtml, isRawHtml } from "./lib/raw.js";
|
|
7
10
|
export { DuplicateFragmentError, FragmentBoundaryError, FragmentNotFoundError } from "./lib/render.js";
|
|
8
11
|
//# sourceMappingURL=index.d.ts.map
|
package/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":";;qBAAqB,eAAe;AAIpC,gDAAiB;oBAHG,cAAc;uBACX,iBAAiB"}
|
package/index.js
CHANGED
|
@@ -2,8 +2,11 @@ import { html } from './lib/html.js'
|
|
|
2
2
|
import { raw } from './lib/raw.js'
|
|
3
3
|
import { render } from './lib/render.js'
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const frag = html
|
|
6
6
|
|
|
7
7
|
export default html
|
|
8
|
-
export {
|
|
8
|
+
export { frag, html, raw, render }
|
|
9
|
+
export { isFragmentBoundary } from './lib/fragment.js'
|
|
10
|
+
export { HtmlResult, isHtmlResult } from './lib/html-result.js'
|
|
11
|
+
export { RawHtml, isRawHtml } from './lib/raw.js'
|
|
9
12
|
export { DuplicateFragmentError, FragmentBoundaryError, FragmentNotFoundError } from './lib/render.js'
|
package/lib/create-tag.d.ts
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
1
|
export const html: HtmlTag;
|
|
2
|
-
|
|
3
|
-
fragmentId?: string | undefined;
|
|
4
|
-
};
|
|
5
|
-
export type CompiledTemplate = {
|
|
6
|
-
strings: readonly string[];
|
|
7
|
-
};
|
|
8
|
-
export type HtmlTag = ((strings: TemplateStrings, ...substitutions: HtmlSubstitution[]) => HtmlResult) & ((options?: RenderOptions | string) => HtmlTag) & {
|
|
9
|
-
fragment: FragmentHelpers;
|
|
10
|
-
raw: (value: unknown) => RawHtml;
|
|
11
|
-
};
|
|
12
|
-
import type { TemplateStrings } from './html-types.js';
|
|
13
|
-
import type { HtmlSubstitution } from './html-types.js';
|
|
14
|
-
import { HtmlResult } from './html-result.js';
|
|
15
|
-
import type { FragmentHelpers } from './fragment.js';
|
|
16
|
-
import type { RawHtml } from './raw.js';
|
|
2
|
+
import type { HtmlTag } from './html-types.js';
|
|
17
3
|
//# sourceMappingURL=create-tag.d.ts.map
|
package/lib/create-tag.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-tag.d.ts","sourceRoot":"","sources":["create-tag.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create-tag.d.ts","sourceRoot":"","sources":["create-tag.js"],"names":[],"mappings":"AA8EA,mBADW,OAAO,CACoB;6BA9E4E,iBAAiB"}
|
package/lib/create-tag.js
CHANGED
|
@@ -1,22 +1,10 @@
|
|
|
1
|
-
/** @import { FragmentHelpers } from './
|
|
2
|
-
/** @import { HtmlSubstitution, TemplateStrings } from './html-types.js' */
|
|
3
|
-
/** @import { RawHtml } from './raw.js' */
|
|
1
|
+
/** @import { CompiledTemplate, FragmentHelpers, HtmlSubstitution, HtmlTag, RenderOptions, TemplateStrings } from './html-types.js' */
|
|
4
2
|
|
|
5
3
|
import { createFragmentHelpers } from './fragment.js'
|
|
6
4
|
import { HtmlResult } from './html-result.js'
|
|
7
5
|
import { raw } from './raw.js'
|
|
8
6
|
import { renderResult } from './render.js'
|
|
9
7
|
|
|
10
|
-
/**
|
|
11
|
-
* @typedef {object} RenderOptions
|
|
12
|
-
* @property {string | undefined} [fragmentId]
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @typedef {object} CompiledTemplate
|
|
17
|
-
* @property {readonly string[]} strings
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
8
|
/** @type {WeakMap<TemplateStringsArray | readonly string[], CompiledTemplate>} */
|
|
21
9
|
const templateCache = new WeakMap()
|
|
22
10
|
const fragment = createFragmentHelpers()
|
|
@@ -44,26 +32,31 @@ function isTemplateStrings (value) {
|
|
|
44
32
|
}
|
|
45
33
|
|
|
46
34
|
/**
|
|
47
|
-
* @
|
|
48
|
-
* @
|
|
35
|
+
* @template {string} FragmentId
|
|
36
|
+
* @param {RenderOptions<FragmentId> | string | undefined} options
|
|
37
|
+
* @returns {RenderOptions<FragmentId>}
|
|
49
38
|
*/
|
|
50
39
|
function normalizeOptions (options) {
|
|
51
|
-
if (typeof options === 'string')
|
|
40
|
+
if (typeof options === 'string') {
|
|
41
|
+
return /** @type {RenderOptions<FragmentId>} */ ({ fragmentId: options })
|
|
42
|
+
}
|
|
52
43
|
return options ? { ...options } : {}
|
|
53
44
|
}
|
|
54
45
|
|
|
55
46
|
/**
|
|
56
|
-
* @
|
|
57
|
-
* @
|
|
47
|
+
* @template {string} FragmentId
|
|
48
|
+
* @param {RenderOptions<FragmentId>} options
|
|
49
|
+
* @returns {HtmlTag<FragmentId>}
|
|
58
50
|
*/
|
|
59
51
|
function createBoundTag (options) {
|
|
60
52
|
/**
|
|
61
|
-
* @
|
|
62
|
-
* @param {
|
|
53
|
+
* @template {string} NextFragmentId
|
|
54
|
+
* @param {TemplateStrings | RenderOptions<NextFragmentId> | string | undefined} strings
|
|
55
|
+
* @param {...HtmlSubstitution<FragmentId>} substitutions
|
|
63
56
|
*/
|
|
64
57
|
function tag (strings, ...substitutions) {
|
|
65
58
|
if (!isTemplateStrings(strings)) {
|
|
66
|
-
return createBoundTag(normalizeOptions(/** @type {RenderOptions | string | undefined} */ strings))
|
|
59
|
+
return createBoundTag(normalizeOptions(/** @type {RenderOptions<NextFragmentId> | string | undefined} */ strings))
|
|
67
60
|
}
|
|
68
61
|
|
|
69
62
|
return new HtmlResult(
|
|
@@ -74,9 +67,9 @@ function createBoundTag (options) {
|
|
|
74
67
|
)
|
|
75
68
|
}
|
|
76
69
|
|
|
77
|
-
const htmlTag = /** @type {HtmlTag} */ (tag)
|
|
70
|
+
const htmlTag = /** @type {HtmlTag<FragmentId>} */ (tag)
|
|
78
71
|
|
|
79
|
-
htmlTag.fragment = fragment
|
|
72
|
+
htmlTag.fragment = /** @type {FragmentHelpers<FragmentId>} */ (/** @type {unknown} */ (fragment))
|
|
80
73
|
htmlTag.raw = raw
|
|
81
74
|
|
|
82
75
|
return htmlTag
|
|
@@ -84,7 +77,3 @@ function createBoundTag (options) {
|
|
|
84
77
|
|
|
85
78
|
/** @type {HtmlTag} */
|
|
86
79
|
export const html = createBoundTag({})
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* @typedef {((strings: TemplateStrings, ...substitutions: HtmlSubstitution[]) => HtmlResult) & ((options?: RenderOptions | string) => HtmlTag) & { fragment: FragmentHelpers, raw: (value: unknown) => RawHtml }} HtmlTag
|
|
90
|
-
*/
|
package/lib/fragment.d.ts
CHANGED
|
@@ -1,20 +1,5 @@
|
|
|
1
|
-
export function createFragmentHelpers(): FragmentHelpers
|
|
1
|
+
export function createFragmentHelpers<FragmentId extends string = string>(): FragmentHelpers<FragmentId>;
|
|
2
2
|
export function isFragmentBoundary(value: unknown): value is FragmentBoundary;
|
|
3
3
|
export const fragmentBoundarySymbol: unique symbol;
|
|
4
|
-
|
|
5
|
-
[fragmentBoundarySymbol]: true;
|
|
6
|
-
kind: "start";
|
|
7
|
-
id: string;
|
|
8
|
-
};
|
|
9
|
-
export type FragmentEndBoundary = {
|
|
10
|
-
[fragmentBoundarySymbol]: true;
|
|
11
|
-
kind: "end";
|
|
12
|
-
};
|
|
13
|
-
export type FragmentBoundary = FragmentStartBoundary | FragmentEndBoundary;
|
|
14
|
-
export type FragmentHelpers = {
|
|
15
|
-
start: typeof start;
|
|
16
|
-
end: FragmentEndBoundary;
|
|
17
|
-
};
|
|
18
|
-
declare function start(id: string): FragmentStartBoundary;
|
|
19
|
-
export {};
|
|
4
|
+
import type { FragmentHelpers } from './html-types.js';
|
|
20
5
|
//# sourceMappingURL=fragment.d.ts.map
|
package/lib/fragment.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fragment.d.ts","sourceRoot":"","sources":["fragment.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fragment.d.ts","sourceRoot":"","sources":["fragment.js"],"names":[],"mappings":"AAgCA,sCAHuB,UAAU,SAApB,MAAQ,cACR,gBAAgB,UAAU,CAAC,CAIvC;AAMD,0CAHW,OAAO,GACL,KAAK,IAAI,gBAAgB,CAQrC;AA5CD,mDAAwE;qCAFS,iBAAiB"}
|
package/lib/fragment.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {{ [fragmentBoundarySymbol]: true, kind: 'start', id: string }} FragmentStartBoundary
|
|
3
|
-
* @typedef {{ [fragmentBoundarySymbol]: true, kind: 'end' }} FragmentEndBoundary
|
|
4
|
-
* @typedef {FragmentStartBoundary | FragmentEndBoundary} FragmentBoundary
|
|
5
|
-
* @typedef {{ start: typeof start, end: FragmentEndBoundary }} FragmentHelpers
|
|
6
|
-
*/
|
|
1
|
+
/** @import { FragmentEndBoundary, FragmentHelpers, FragmentStartBoundary } from './html-types.js' */
|
|
7
2
|
|
|
8
3
|
export const fragmentBoundarySymbol = Symbol('fragtml.fragmentBoundary')
|
|
9
4
|
|
|
@@ -13,23 +8,27 @@ const end = Object.freeze(/** @type {FragmentEndBoundary} */ ({
|
|
|
13
8
|
}))
|
|
14
9
|
|
|
15
10
|
/**
|
|
16
|
-
* @
|
|
17
|
-
* @
|
|
11
|
+
* @template {string} FragmentId
|
|
12
|
+
* @param {FragmentId} id
|
|
13
|
+
* @returns {FragmentStartBoundary<FragmentId>}
|
|
18
14
|
*/
|
|
19
15
|
function start (id) {
|
|
20
16
|
if (typeof id !== 'string' || id.length === 0) {
|
|
21
17
|
throw new TypeError('fragment.start(id) requires a non-empty string id')
|
|
22
18
|
}
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
const boundary = {
|
|
25
21
|
[fragmentBoundarySymbol]: true,
|
|
26
22
|
kind: 'start',
|
|
27
23
|
id
|
|
28
24
|
}
|
|
25
|
+
|
|
26
|
+
return /** @type {FragmentStartBoundary<FragmentId>} */ (boundary)
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
/**
|
|
32
|
-
* @
|
|
30
|
+
* @template {string} [FragmentId=string]
|
|
31
|
+
* @returns {FragmentHelpers<FragmentId>}
|
|
33
32
|
*/
|
|
34
33
|
export function createFragmentHelpers () {
|
|
35
34
|
return Object.freeze({ start, end })
|
package/lib/html-result.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export class HtmlResult {
|
|
|
11
11
|
[Symbol.toPrimitive](): string;
|
|
12
12
|
[htmlResultSymbol]: boolean;
|
|
13
13
|
}
|
|
14
|
-
import type { CompiledTemplate } from './
|
|
14
|
+
import type { CompiledTemplate } from './html-types.js';
|
|
15
15
|
import type { HtmlSubstitution } from './html-types.js';
|
|
16
|
-
import type { RenderOptions } from './
|
|
16
|
+
import type { RenderOptions } from './html-types.js';
|
|
17
17
|
//# sourceMappingURL=html-result.d.ts.map
|
package/lib/html-result.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-result.d.ts","sourceRoot":"","sources":["html-result.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"html-result.d.ts","sourceRoot":"","sources":["html-result.js"],"names":[],"mappings":"AAoCA,oCAHW,OAAO,GACL,KAAK,IAAI,UAAU,CAQ/B;AAxCD,6CAA4D;AAE5D;IAOE,sBALW,gBAAgB,iBAChB,gBAAgB,EAAE,WAClB,aAAa,UACb,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,EAQxC;IAJC,2BAAwB;IACxB,kCAAkC;IAClC,uBAAsB;IACtB,iBAPkB,UAAU,KAAK,MAAM,CAOnB;IAGtB,mBAEC;IAED,kBAEC;IAED,+BAEC;IAjBC,4BAA6B;CAkBhC;sCA9BsE,iBAAiB;sCAAjB,iBAAiB;mCAAjB,iBAAiB"}
|
package/lib/html-result.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
/** @import { CompiledTemplate, RenderOptions } from './
|
|
2
|
-
/** @import { HtmlSubstitution } from './html-types.js' */
|
|
1
|
+
/** @import { CompiledTemplate, HtmlSubstitution, RenderOptions } from './html-types.js' */
|
|
3
2
|
|
|
4
3
|
export const htmlResultSymbol = Symbol('fragtml.htmlResult')
|
|
5
4
|
|
package/lib/html-types.d.ts
CHANGED
|
@@ -1,9 +1,30 @@
|
|
|
1
|
-
import type { FragmentBoundary } from './fragment.js';
|
|
2
1
|
import type { HtmlResult } from './html-result.js';
|
|
3
2
|
import type { RawHtml } from './raw.js';
|
|
3
|
+
export type FragmentStartBoundary<FragmentId extends string = string> = {
|
|
4
|
+
readonly kind: 'start';
|
|
5
|
+
readonly id: FragmentId;
|
|
6
|
+
};
|
|
7
|
+
export type FragmentEndBoundary = {
|
|
8
|
+
readonly kind: 'end';
|
|
9
|
+
};
|
|
10
|
+
export type FragmentBoundary<FragmentId extends string = string> = FragmentStartBoundary<FragmentId> | FragmentEndBoundary;
|
|
11
|
+
export type FragmentHelpers<FragmentId extends string = string> = {
|
|
12
|
+
start: (id: FragmentId) => FragmentStartBoundary<FragmentId>;
|
|
13
|
+
end: FragmentEndBoundary;
|
|
14
|
+
};
|
|
15
|
+
export type RenderOptions<FragmentId extends string = string> = {
|
|
16
|
+
fragmentId?: FragmentId | undefined;
|
|
17
|
+
};
|
|
18
|
+
export type CompiledTemplate = {
|
|
19
|
+
strings: readonly string[];
|
|
20
|
+
};
|
|
4
21
|
export type HtmlPrimitiveSubstitution = string | number | bigint | boolean | null | undefined;
|
|
5
22
|
export type HtmlArrayScalarSubstitution = HtmlPrimitiveSubstitution | HtmlResult | RawHtml;
|
|
6
23
|
export type HtmlArraySubstitution = HtmlArrayScalarSubstitution | readonly HtmlArraySubstitution[];
|
|
7
|
-
export type HtmlSubstitution = HtmlArraySubstitution | FragmentBoundary
|
|
24
|
+
export type HtmlSubstitution<FragmentId extends string = string> = HtmlArraySubstitution | FragmentBoundary<FragmentId>;
|
|
8
25
|
export type TemplateStrings = TemplateStringsArray | readonly string[];
|
|
26
|
+
export type HtmlTag<FragmentId extends string = string> = ((strings: TemplateStrings, ...substitutions: HtmlSubstitution<FragmentId>[]) => HtmlResult) & (<NextFragmentId extends string = string>(options?: RenderOptions<NextFragmentId> | string) => HtmlTag<NextFragmentId>) & {
|
|
27
|
+
fragment: FragmentHelpers<FragmentId>;
|
|
28
|
+
raw: (value: unknown) => RawHtml;
|
|
29
|
+
};
|
|
9
30
|
//# sourceMappingURL=html-types.d.ts.map
|
package/lib/html-types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-types.d.ts","sourceRoot":"","sources":["html-types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"html-types.d.ts","sourceRoot":"","sources":["html-types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAEvC,MAAM,MAAM,qBAAqB,CAAC,UAAU,SAAS,MAAM,GAAG,MAAM,IAAI;IACtE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAA;CACxB,CAAA;AACD,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;CACrB,CAAA;AACD,MAAM,MAAM,gBAAgB,CAAC,UAAU,SAAS,MAAM,GAAG,MAAM,IAC7D,qBAAqB,CAAC,UAAU,CAAC,GAAG,mBAAmB,CAAA;AACzD,MAAM,MAAM,eAAe,CAAC,UAAU,SAAS,MAAM,GAAG,MAAM,IAAI;IAChE,KAAK,EAAE,CAAC,EAAE,EAAE,UAAU,KAAK,qBAAqB,CAAC,UAAU,CAAC,CAAA;IAC5D,GAAG,EAAE,mBAAmB,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,aAAa,CAAC,UAAU,SAAS,MAAM,GAAG,MAAM,IAAI;IAC9D,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAA;AAC7F,MAAM,MAAM,2BAA2B,GAAG,yBAAyB,GAAG,UAAU,GAAG,OAAO,CAAA;AAC1F,MAAM,MAAM,qBAAqB,GAC/B,2BAA2B,GAAG,SAAS,qBAAqB,EAAE,CAAA;AAChE,MAAM,MAAM,gBAAgB,CAAC,UAAU,SAAS,MAAM,GAAG,MAAM,IAC7D,qBAAqB,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAA;AACtD,MAAM,MAAM,eAAe,GAAG,oBAAoB,GAAG,SAAS,MAAM,EAAE,CAAA;AACtE,MAAM,MAAM,OAAO,CAAC,UAAU,SAAS,MAAM,GAAG,MAAM,IACpD,CAAC,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,aAAa,EAAE,gBAAgB,CAAC,UAAU,CAAC,EAAE,KAAK,UAAU,CAAC,GAC5F,CAAC,CAAC,cAAc,SAAS,MAAM,GAAG,MAAM,EACtC,OAAO,CAAC,EAAE,aAAa,CAAC,cAAc,CAAC,GAAG,MAAM,KAC7C,OAAO,CAAC,cAAc,CAAC,CAAC,GAAG;IAC9B,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,CAAA;IACrC,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;CACjC,CAAA"}
|
package/lib/html-types.ts
CHANGED
|
@@ -1,10 +1,41 @@
|
|
|
1
1
|
// Type exports only. Do not add runtime implementations to this module.
|
|
2
|
-
import type { FragmentBoundary } from './fragment.js'
|
|
3
2
|
import type { HtmlResult } from './html-result.js'
|
|
4
3
|
import type { RawHtml } from './raw.js'
|
|
5
4
|
|
|
5
|
+
export type FragmentStartBoundary<FragmentId extends string = string> = {
|
|
6
|
+
readonly kind: 'start'
|
|
7
|
+
readonly id: FragmentId
|
|
8
|
+
}
|
|
9
|
+
export type FragmentEndBoundary = {
|
|
10
|
+
readonly kind: 'end'
|
|
11
|
+
}
|
|
12
|
+
export type FragmentBoundary<FragmentId extends string = string> =
|
|
13
|
+
FragmentStartBoundary<FragmentId> | FragmentEndBoundary
|
|
14
|
+
export type FragmentHelpers<FragmentId extends string = string> = {
|
|
15
|
+
start: (id: FragmentId) => FragmentStartBoundary<FragmentId>
|
|
16
|
+
end: FragmentEndBoundary
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type RenderOptions<FragmentId extends string = string> = {
|
|
20
|
+
fragmentId?: FragmentId | undefined
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type CompiledTemplate = {
|
|
24
|
+
strings: readonly string[]
|
|
25
|
+
}
|
|
26
|
+
|
|
6
27
|
export type HtmlPrimitiveSubstitution = string | number | bigint | boolean | null | undefined
|
|
7
28
|
export type HtmlArrayScalarSubstitution = HtmlPrimitiveSubstitution | HtmlResult | RawHtml
|
|
8
|
-
export type HtmlArraySubstitution =
|
|
9
|
-
|
|
29
|
+
export type HtmlArraySubstitution =
|
|
30
|
+
HtmlArrayScalarSubstitution | readonly HtmlArraySubstitution[]
|
|
31
|
+
export type HtmlSubstitution<FragmentId extends string = string> =
|
|
32
|
+
HtmlArraySubstitution | FragmentBoundary<FragmentId>
|
|
10
33
|
export type TemplateStrings = TemplateStringsArray | readonly string[]
|
|
34
|
+
export type HtmlTag<FragmentId extends string = string> =
|
|
35
|
+
((strings: TemplateStrings, ...substitutions: HtmlSubstitution<FragmentId>[]) => HtmlResult) &
|
|
36
|
+
(<NextFragmentId extends string = string>(
|
|
37
|
+
options?: RenderOptions<NextFragmentId> | string
|
|
38
|
+
) => HtmlTag<NextFragmentId>) & {
|
|
39
|
+
fragment: FragmentHelpers<FragmentId>
|
|
40
|
+
raw: (value: unknown) => RawHtml
|
|
41
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fragtml",
|
|
3
3
|
"description": "WIP - nothing to see here",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.4",
|
|
5
5
|
"author": "Bret Comnes <bcomnes@gmail.com> (https://bret.io)",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/bcomnes/fragtml/issues"
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
"index.js",
|
|
31
31
|
"index.d.ts",
|
|
32
32
|
"index.d.ts.map",
|
|
33
|
+
"types.d.ts",
|
|
34
|
+
"types.d.ts.map",
|
|
33
35
|
"lib"
|
|
34
36
|
],
|
|
35
37
|
"repository": {
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { CompiledTemplate, FragmentBoundary, FragmentEndBoundary, FragmentHelpers, FragmentStartBoundary, HtmlArrayScalarSubstitution, HtmlArraySubstitution, HtmlPrimitiveSubstitution, HtmlSubstitution, HtmlTag, RenderOptions, TemplateStrings } from './lib/html-types.js';
|
|
2
|
+
export type { HtmlResult } from './lib/html-result.js';
|
|
3
|
+
export type { RawHtml } from './lib/raw.js';
|
|
4
|
+
//# sourceMappingURL=types.d.ts.map
|
package/types.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"AACA,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,2BAA2B,EAC3B,qBAAqB,EACrB,yBAAyB,EACzB,gBAAgB,EAChB,OAAO,EACP,aAAa,EACb,eAAe,EAChB,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACtD,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA"}
|