@dosgato/templating 0.0.37 → 0.0.40
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/dist/component.d.ts +57 -10
- package/dist/component.js +23 -14
- package/package.json +2 -2
- package/dist/editbar.d.ts +0 -11
- package/dist/editbar.js +0 -23
package/dist/component.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { EditBarOpts } from './editbar.js';
|
|
2
1
|
import { ResourceProvider } from './provider.js';
|
|
3
2
|
import { APIClient } from './render.js';
|
|
4
3
|
/**
|
|
@@ -9,8 +8,15 @@ import { APIClient } from './render.js';
|
|
|
9
8
|
* parent and child components linked.
|
|
10
9
|
*/
|
|
11
10
|
export declare abstract class Component<DataType extends ComponentData = any, FetchedType = any, RenderContextType extends ContextBase = any> extends ResourceProvider {
|
|
11
|
+
/**
|
|
12
|
+
* Provide this when you create a template to identify what you are defining.
|
|
13
|
+
*/
|
|
12
14
|
static templateKey: string;
|
|
13
|
-
|
|
15
|
+
/**
|
|
16
|
+
* These functions will be provided by the rendering server
|
|
17
|
+
*/
|
|
18
|
+
static editBar: (path: string, opts: EditBarOpts) => string;
|
|
19
|
+
static newBar: (path: string, opts: EditBarOpts) => string;
|
|
14
20
|
areas: Map<string, Component<any, any, any>[]>;
|
|
15
21
|
data: Omit<DataType, 'areas'>;
|
|
16
22
|
fetched: FetchedType;
|
|
@@ -19,6 +25,26 @@ export declare abstract class Component<DataType extends ComponentData = any, Fe
|
|
|
19
25
|
parent?: Component;
|
|
20
26
|
page?: Page;
|
|
21
27
|
hadError: boolean;
|
|
28
|
+
autoLabel: () => string;
|
|
29
|
+
autoNewLabel: () => string;
|
|
30
|
+
/**
|
|
31
|
+
* When hydrating an inherited component, the renderer will set this to the id of the page it
|
|
32
|
+
* came from. You may use this information in any of the phases to alter your behavior if needed.
|
|
33
|
+
*
|
|
34
|
+
* For instance, you may decide that your fetch function needs some extra information from the
|
|
35
|
+
* originating page instead of the page you're being inherited into (your `this.page` will
|
|
36
|
+
* be the page currently being rendered, NOT the page the inheritable component came from).
|
|
37
|
+
*
|
|
38
|
+
* This property is also used to alter the edit bar. Inherited components may never be edited
|
|
39
|
+
* except on their original page, so the edit bar will render with a link to the original page.
|
|
40
|
+
*/
|
|
41
|
+
inheritedFrom?: string;
|
|
42
|
+
/**
|
|
43
|
+
* This property will be set during page render and you may refer to it at any time to
|
|
44
|
+
* determine whether you are doing your work in edit mode or regular rendering mode.
|
|
45
|
+
* The editBar and newBar methods will automatically use it to blank out the editing UI.
|
|
46
|
+
*/
|
|
47
|
+
editMode: boolean;
|
|
22
48
|
/**
|
|
23
49
|
* The rendering server will provide an instance of the APIClient interface so that
|
|
24
50
|
* you can run any API GraphQL query you like in your `fetch` function. There are also
|
|
@@ -49,6 +75,13 @@ export declare abstract class Component<DataType extends ComponentData = any, Fe
|
|
|
49
75
|
* other Component instances.
|
|
50
76
|
*/
|
|
51
77
|
getAncestorPageData: () => Promise<PageData[]>;
|
|
78
|
+
/**
|
|
79
|
+
* Some components may be inheritable to subpages within the same site. For instance, a site's
|
|
80
|
+
* social media links may appear on every page's footer. To accomplish this in your template,
|
|
81
|
+
* you need to fetch the data in your fetch phase and then call this function within your fetch
|
|
82
|
+
* to let the renderer know it needs to hydrate them and include them in the render.
|
|
83
|
+
*/
|
|
84
|
+
registerInherited: (area: string, components: ComponentData[], top?: true) => void;
|
|
52
85
|
/**
|
|
53
86
|
* The first phase of rendering a component is the fetch phase. Each component may
|
|
54
87
|
* provide a fetch method that looks up data it needs from external sources. This step
|
|
@@ -63,7 +96,7 @@ export declare abstract class Component<DataType extends ComponentData = any, Fe
|
|
|
63
96
|
* you may add them to your this.areas map, e.g.
|
|
64
97
|
* `this.areas.get('myarea').push(new Component(inheritedData, this.path + '/myarea/inherit1', this))`
|
|
65
98
|
*/
|
|
66
|
-
fetch(
|
|
99
|
+
fetch(): Promise<FetchedType>;
|
|
67
100
|
/**
|
|
68
101
|
* The second phase of rendering a component is the context phase. This step is TOP-DOWN and
|
|
69
102
|
* NON-MUTATING. Each component will receive the parent component's context and then pass a
|
|
@@ -79,14 +112,14 @@ export declare abstract class Component<DataType extends ComponentData = any, Fe
|
|
|
79
112
|
* the context received from the parent, but use it sparingly since it will stall the process.
|
|
80
113
|
* Try to do all asynchronous work in the fetch phase.
|
|
81
114
|
*/
|
|
82
|
-
setContext(renderCtxFromParent: RenderContextType
|
|
115
|
+
setContext(renderCtxFromParent: RenderContextType): RenderContextType | Promise<RenderContextType>;
|
|
83
116
|
/**
|
|
84
117
|
* The final phase of rendering a component is the render phase. This step is BOTTOM-UP -
|
|
85
118
|
* components at the bottom of the hierarchy will be rendered first, and the result of the
|
|
86
119
|
* render will be passed to parent components so that the HTML can be included during the
|
|
87
120
|
* render of the parent component.
|
|
88
121
|
*/
|
|
89
|
-
abstract render(renderedAreas: Map<string,
|
|
122
|
+
abstract render(renderedAreas: Map<string, RenderedComponent[]>): string;
|
|
90
123
|
/**
|
|
91
124
|
* Sometimes pages are requested with an alternate extension like .rss or .ics. In these
|
|
92
125
|
* situations, each component should consider whether it should output anything. For
|
|
@@ -100,7 +133,7 @@ export declare abstract class Component<DataType extends ComponentData = any, Fe
|
|
|
100
133
|
* will be skipped.
|
|
101
134
|
*/
|
|
102
135
|
renderVariation(extension: string, renderedAreas: Map<string, string>): string;
|
|
103
|
-
constructor(data: DataType, path: string, parent: Component | undefined);
|
|
136
|
+
constructor(data: DataType, path: string, parent: Component | undefined, editMode: boolean);
|
|
104
137
|
/**
|
|
105
138
|
* For logging errors during rendering without crashing the render. If your fetch, setContext,
|
|
106
139
|
* render, or renderVariation functions throw, the error will be logged but the page render will
|
|
@@ -108,6 +141,9 @@ export declare abstract class Component<DataType extends ComponentData = any, Fe
|
|
|
108
141
|
*/
|
|
109
142
|
logError(e: Error): void;
|
|
110
143
|
protected passError(e: Error, path: string): void;
|
|
144
|
+
renderComponents(components?: RenderedComponent[], opts?: {
|
|
145
|
+
hideInheritBars?: boolean;
|
|
146
|
+
}): string;
|
|
111
147
|
/**
|
|
112
148
|
* During rendering, each component should determine the CSS blocks that it needs. This may
|
|
113
149
|
* change depending on the data. For instance, if you need some CSS to style up an image, but
|
|
@@ -124,11 +160,11 @@ export declare abstract class Component<DataType extends ComponentData = any, Fe
|
|
|
124
160
|
jsBlocks(): string[];
|
|
125
161
|
/**
|
|
126
162
|
* Components may override this function to give their edit bars a custom
|
|
127
|
-
* label instead of using the
|
|
163
|
+
* label instead of using the template name
|
|
128
164
|
*
|
|
129
165
|
* For instance, you could return this.data.title
|
|
130
166
|
*/
|
|
131
|
-
editLabel():
|
|
167
|
+
editLabel(): undefined;
|
|
132
168
|
/**
|
|
133
169
|
* Components may override this function to give their edit bars a custom
|
|
134
170
|
* CSS class
|
|
@@ -141,7 +177,7 @@ export declare abstract class Component<DataType extends ComponentData = any, Fe
|
|
|
141
177
|
* For instance, an area that only accepts 'layout' components could
|
|
142
178
|
* return "Add Layout"
|
|
143
179
|
*/
|
|
144
|
-
newLabel(areaName: string):
|
|
180
|
+
newLabel(areaName: string): undefined;
|
|
145
181
|
/**
|
|
146
182
|
* Components may override this function to give their new bars a custom
|
|
147
183
|
* CSS class
|
|
@@ -189,6 +225,17 @@ export interface ContextBase {
|
|
|
189
225
|
*/
|
|
190
226
|
headerLevel: number;
|
|
191
227
|
}
|
|
228
|
+
export interface EditBarOpts {
|
|
229
|
+
extraClass?: string;
|
|
230
|
+
label?: string;
|
|
231
|
+
editMode?: boolean;
|
|
232
|
+
inheritedFrom?: string;
|
|
233
|
+
}
|
|
234
|
+
export interface RenderedComponent {
|
|
235
|
+
inherited: boolean;
|
|
236
|
+
html: string;
|
|
237
|
+
editbar: string;
|
|
238
|
+
}
|
|
192
239
|
export declare abstract class Page<DataType extends PageData = any, FetchedType = any, RenderContextType extends ContextBase = any> extends Component<DataType, FetchedType, RenderContextType> {
|
|
193
240
|
pagePath: string;
|
|
194
241
|
/**
|
|
@@ -198,5 +245,5 @@ export declare abstract class Page<DataType extends PageData = any, FetchedType
|
|
|
198
245
|
*/
|
|
199
246
|
headContent: string;
|
|
200
247
|
protected passError(e: Error, path: string): void;
|
|
201
|
-
constructor(page: PageRecord<DataType
|
|
248
|
+
constructor(page: PageRecord<DataType>, editMode: boolean);
|
|
202
249
|
}
|
package/dist/component.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isNotBlank } from 'txstate-utils';
|
|
2
2
|
import { ResourceProvider } from './provider.js';
|
|
3
3
|
/**
|
|
4
4
|
* This is the primary templating class to build your templates. Subclass it and provide
|
|
@@ -10,11 +10,12 @@ import { ResourceProvider } from './provider.js';
|
|
|
10
10
|
export class Component extends ResourceProvider {
|
|
11
11
|
// the constructor is part of the recursive hydration mechanism: constructing
|
|
12
12
|
// a Component will also construct/hydrate all its child components
|
|
13
|
-
constructor(data, path, parent) {
|
|
13
|
+
constructor(data, path, parent, editMode) {
|
|
14
14
|
super();
|
|
15
15
|
// properties for use during hydration, you do not have to provide these when
|
|
16
16
|
// building a template, but you can use them in the functions you do provide
|
|
17
17
|
this.areas = new Map();
|
|
18
|
+
this.editMode = editMode;
|
|
18
19
|
this.parent = parent;
|
|
19
20
|
const { areas, ...ownData } = data;
|
|
20
21
|
this.data = ownData;
|
|
@@ -41,7 +42,7 @@ export class Component extends ResourceProvider {
|
|
|
41
42
|
* you may add them to your this.areas map, e.g.
|
|
42
43
|
* `this.areas.get('myarea').push(new Component(inheritedData, this.path + '/myarea/inherit1', this))`
|
|
43
44
|
*/
|
|
44
|
-
async fetch(
|
|
45
|
+
async fetch() {
|
|
45
46
|
return undefined;
|
|
46
47
|
}
|
|
47
48
|
/**
|
|
@@ -59,7 +60,7 @@ export class Component extends ResourceProvider {
|
|
|
59
60
|
* the context received from the parent, but use it sparingly since it will stall the process.
|
|
60
61
|
* Try to do all asynchronous work in the fetch phase.
|
|
61
62
|
*/
|
|
62
|
-
setContext(renderCtxFromParent
|
|
63
|
+
setContext(renderCtxFromParent) {
|
|
63
64
|
return renderCtxFromParent;
|
|
64
65
|
}
|
|
65
66
|
/**
|
|
@@ -90,6 +91,11 @@ export class Component extends ResourceProvider {
|
|
|
90
91
|
passError(e, path) {
|
|
91
92
|
this.parent?.passError(e, path);
|
|
92
93
|
}
|
|
94
|
+
// helper function to help you print an area, but you can also override this if you
|
|
95
|
+
// need to do something advanced like wrap each component in a div
|
|
96
|
+
renderComponents(components = [], opts) {
|
|
97
|
+
return components.flatMap(c => c.inherited && opts?.hideInheritBars ? [c.html] : [c.editbar, c.html]).join('');
|
|
98
|
+
}
|
|
93
99
|
/**
|
|
94
100
|
* During rendering, each component should determine the CSS blocks that it needs. This may
|
|
95
101
|
* change depending on the data. For instance, if you need some CSS to style up an image, but
|
|
@@ -110,13 +116,12 @@ export class Component extends ResourceProvider {
|
|
|
110
116
|
}
|
|
111
117
|
/**
|
|
112
118
|
* Components may override this function to give their edit bars a custom
|
|
113
|
-
* label instead of using the
|
|
119
|
+
* label instead of using the template name
|
|
114
120
|
*
|
|
115
121
|
* For instance, you could return this.data.title
|
|
116
122
|
*/
|
|
117
123
|
editLabel() {
|
|
118
|
-
|
|
119
|
-
return This.templateName;
|
|
124
|
+
return undefined;
|
|
120
125
|
}
|
|
121
126
|
/**
|
|
122
127
|
* Components may override this function to give their edit bars a custom
|
|
@@ -133,7 +138,7 @@ export class Component extends ResourceProvider {
|
|
|
133
138
|
* return "Add Layout"
|
|
134
139
|
*/
|
|
135
140
|
newLabel(areaName) {
|
|
136
|
-
return
|
|
141
|
+
return undefined;
|
|
137
142
|
}
|
|
138
143
|
/**
|
|
139
144
|
* Components may override this function to give their new bars a custom
|
|
@@ -148,9 +153,11 @@ export class Component extends ResourceProvider {
|
|
|
148
153
|
* Generally should not be overridden - override editLabel and editClass instead
|
|
149
154
|
*/
|
|
150
155
|
editBar(opts = {}) {
|
|
151
|
-
opts.label ?? (opts.label = this.editLabel());
|
|
156
|
+
opts.label ?? (opts.label = this.editLabel() ?? this.autoLabel());
|
|
152
157
|
opts.extraClass ?? (opts.extraClass = this.editClass());
|
|
153
|
-
|
|
158
|
+
opts.editMode ?? (opts.editMode = this.editMode);
|
|
159
|
+
opts.inheritedFrom ?? (opts.inheritedFrom = this.inheritedFrom);
|
|
160
|
+
return Component.editBar(this.path, opts);
|
|
154
161
|
}
|
|
155
162
|
/**
|
|
156
163
|
* Components may override this function to provide a custom new bar
|
|
@@ -158,14 +165,16 @@ export class Component extends ResourceProvider {
|
|
|
158
165
|
* Generally should not be overridden - override newLabel and newClass instead
|
|
159
166
|
*/
|
|
160
167
|
newBar(areaName, opts = {}) {
|
|
161
|
-
opts.label ?? (opts.label = this.newLabel(areaName));
|
|
168
|
+
opts.label ?? (opts.label = this.newLabel(areaName) ?? this.autoNewLabel());
|
|
162
169
|
opts.extraClass ?? (opts.extraClass = this.newClass(areaName));
|
|
163
|
-
|
|
170
|
+
opts.editMode ?? (opts.editMode = this.editMode);
|
|
171
|
+
opts.inheritedFrom ?? (opts.inheritedFrom = this.inheritedFrom);
|
|
172
|
+
return Component.newBar([this.path, 'areas', areaName].filter(isNotBlank).join('.'), opts);
|
|
164
173
|
}
|
|
165
174
|
}
|
|
166
175
|
export class Page extends Component {
|
|
167
|
-
constructor(page) {
|
|
168
|
-
super(page.data, '
|
|
176
|
+
constructor(page, editMode) {
|
|
177
|
+
super(page.data, '', undefined, editMode);
|
|
169
178
|
this.pagePath = page.path;
|
|
170
179
|
}
|
|
171
180
|
passError(e, path) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dosgato/templating",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.40",
|
|
4
4
|
"description": "A library to support building templates for dosgato CMS.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"txstate-utils": "^1.7.1"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"eslint-config-standard-with-typescript": "^
|
|
21
|
+
"eslint-config-standard-with-typescript": "^22.0.0",
|
|
22
22
|
"typescript": "^4.4.2"
|
|
23
23
|
},
|
|
24
24
|
"repository": {
|
package/dist/editbar.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export interface EditBarOpts {
|
|
2
|
-
extraClass?: string;
|
|
3
|
-
label?: string;
|
|
4
|
-
editMode?: boolean;
|
|
5
|
-
}
|
|
6
|
-
export declare function editBar(path: string, opts: EditBarOpts & {
|
|
7
|
-
label: string;
|
|
8
|
-
}): string;
|
|
9
|
-
export declare function newBar(path: string, opts: EditBarOpts & {
|
|
10
|
-
label: string;
|
|
11
|
-
}): string;
|
package/dist/editbar.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { htmlEncode, randomid } from 'txstate-utils';
|
|
2
|
-
export function editBar(path, opts) {
|
|
3
|
-
if (!opts.editMode)
|
|
4
|
-
return '';
|
|
5
|
-
const id = randomid();
|
|
6
|
-
return `
|
|
7
|
-
<div class="dg-edit-bar ${opts.extraClass ?? ''}" data-path="${htmlEncode(path)}" draggable="true" ondragstart="window.dgEditing.drag(event)" ondragover="window.dgEditing.over(event)" ondragend="window.dgEditing.drop(event)">
|
|
8
|
-
<span id="${id}" class="dg-edit-bar-label">${htmlEncode(opts.label)}</span>
|
|
9
|
-
<button onclick="window.dgEditing.edit(event)" aria-describedby="${id}">Edit</button>
|
|
10
|
-
<button onclick="window.dgEditing.move(event)" aria-describedby="${id}">Move</button>
|
|
11
|
-
<button onclick="window.dgEditing.del(event)" aria-describedby="${id}">Trash</button>
|
|
12
|
-
</div>
|
|
13
|
-
`.trim();
|
|
14
|
-
}
|
|
15
|
-
export function newBar(path, opts) {
|
|
16
|
-
if (!opts.editMode)
|
|
17
|
-
return '';
|
|
18
|
-
return `
|
|
19
|
-
<div role="button" onclick="window.dgEditing.create(event)" class="dg-new-bar ${opts.extraClass ?? ''}" data-path="${htmlEncode(path)}">
|
|
20
|
-
${htmlEncode(opts.label)}
|
|
21
|
-
</div>
|
|
22
|
-
`.trim();
|
|
23
|
-
}
|