element-book 0.0.13 → 1.0.0
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/data/element-book-entry/element-book-chapter/element-book-chapter.js +6 -1
- package/dist/data/element-book-entry/element-book-page/element-book-page.js +13 -3
- package/dist/data/element-book-entry/entry-tree/entry-tree.js +8 -1
- package/dist/routing/create-element-book-router.d.ts +1 -1
- package/dist/ui/elements/element-book-app/element-book-app.element.d.ts +3 -1
- package/dist/ui/elements/element-book-app/element-book-app.element.js +44 -48
- package/dist/ui/elements/element-book-app/element-book-config.d.ts +25 -9
- package/dist/ui/elements/element-book-nav.element.js +1 -0
- package/package.json +3 -3
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { ElementBookEntryTypeEnum } from '../element-book-entry-type';
|
|
2
2
|
export function defineElementBookChapter(chapterSetup) {
|
|
3
3
|
if (!chapterSetup.title) {
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* We don't want the Error type to actually be a part of this function's return type, cause
|
|
6
|
+
* users shouldn't actually return errors, but we still want to pass errors to element-book
|
|
7
|
+
* so element-book can handle them.
|
|
8
|
+
*/
|
|
9
|
+
return new Error(`Cannot have an element-book chapter with an empty title.`);
|
|
5
10
|
}
|
|
6
11
|
const chapter = {
|
|
7
12
|
type: ElementBookEntryTypeEnum.Chapter,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { combineErrors } from '@augment-vir/common';
|
|
1
2
|
import { ElementBookEntryTypeEnum } from '../element-book-entry-type';
|
|
2
3
|
import { listBreadcrumbs } from '../entry-tree/entry-tree';
|
|
3
4
|
export function defineElementBookPage(pageSetup) {
|
|
5
|
+
const errors = [];
|
|
4
6
|
if (!pageSetup.title) {
|
|
5
|
-
|
|
7
|
+
errors.push(new Error(`Cannot have an element-book page with an empty title.`));
|
|
6
8
|
}
|
|
7
9
|
const page = {
|
|
8
10
|
type: ElementBookEntryTypeEnum.Page,
|
|
@@ -15,12 +17,20 @@ export function defineElementBookPage(pageSetup) {
|
|
|
15
17
|
.concat(example.title)
|
|
16
18
|
.join(' > ')}'`;
|
|
17
19
|
if (exampleTitlesSet.has(example.title)) {
|
|
18
|
-
|
|
20
|
+
errors.push(Error(`${failureMessage}: title '${example.title}' is already being used.`));
|
|
19
21
|
}
|
|
20
22
|
else if (!example.title) {
|
|
21
|
-
|
|
23
|
+
errors.push(Error(`${failureMessage}: example title is missing or empty.`));
|
|
22
24
|
}
|
|
23
25
|
exampleTitlesSet.add(example.title);
|
|
24
26
|
});
|
|
27
|
+
if (errors.length) {
|
|
28
|
+
/**
|
|
29
|
+
* We don't want the Error type to actually be a part of this function's return type, cause
|
|
30
|
+
* users shouldn't actually return errors, but we still want to pass errors to element-book
|
|
31
|
+
* so element-book can handle them.
|
|
32
|
+
*/
|
|
33
|
+
return combineErrors(errors);
|
|
34
|
+
}
|
|
25
35
|
return page;
|
|
26
36
|
}
|
|
@@ -31,10 +31,17 @@ export function titleToBreadcrumb(title) {
|
|
|
31
31
|
export function entriesToTree(entries, everythingTitle) {
|
|
32
32
|
const tree = createEmptyEntryTreeRoot(everythingTitle);
|
|
33
33
|
entries.forEach((newEntry) => {
|
|
34
|
+
/**
|
|
35
|
+
* The type for newEntry does not include Error but if errors occur during entry definition
|
|
36
|
+
* they will be replaced with errors.
|
|
37
|
+
*/
|
|
38
|
+
if (newEntry instanceof Error) {
|
|
39
|
+
throw newEntry;
|
|
40
|
+
}
|
|
34
41
|
const immediateParent = traverseToImmediateParent(newEntry, tree);
|
|
35
42
|
const breadcrumb = titleToBreadcrumb(newEntry.title);
|
|
36
43
|
if (breadcrumb in immediateParent.children) {
|
|
37
|
-
throw new Error(`Cannot create duplicate entry '${breadcrumb}' in parent '${immediateParent.breadcrumb}'.`);
|
|
44
|
+
throw new Error(`Cannot create duplicate entry '${breadcrumb}'${immediateParent.breadcrumb ? ` in parent '${immediateParent.breadcrumb}'.` : ''}`);
|
|
38
45
|
}
|
|
39
46
|
const newNode = {
|
|
40
47
|
[markerKeyName]: true,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { ElementBookRouter } from './element-book-routing';
|
|
2
|
-
export declare function createElementBookRouter(baseRoute: string): ElementBookRouter;
|
|
2
|
+
export declare function createElementBookRouter(baseRoute: string | undefined): ElementBookRouter;
|
|
@@ -9,5 +9,7 @@ export declare const ElementBookApp: import("element-vir").DeclarativeElementDef
|
|
|
9
9
|
currentRoute: Readonly<Required<Readonly<import("spa-router-vir").FullRoute<import("../../../routing/element-book-routing").ValidElementBookPaths, undefined, undefined>>>>;
|
|
10
10
|
router: Readonly<import("spa-router-vir").SpaRouter<import("../../../routing/element-book-routing").ValidElementBookPaths, undefined, undefined>> | undefined;
|
|
11
11
|
colors: ColorThemeState;
|
|
12
|
-
}, {
|
|
12
|
+
}, {
|
|
13
|
+
pathUpdate: import("element-vir").DefinedTypedEventNameDefinition<readonly string[]>;
|
|
14
|
+
}, "", "", import("lit-html").HTMLTemplateResult>;
|
|
13
15
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { areJsonEqual, extractErrorMessage, getOrSetFromMap } from '@augment-vir/common';
|
|
2
|
-
import { assign, css, defineElement, html, listen } from 'element-vir';
|
|
3
|
-
import { entriesToTree, findEntryByBreadcrumbs,
|
|
2
|
+
import { assign, css, defineElement, defineElementEvent, html, listen } from 'element-vir';
|
|
3
|
+
import { entriesToTree, findEntryByBreadcrumbs, } from '../../../data/element-book-entry/entry-tree/entry-tree';
|
|
4
4
|
import { createElementBookRouter } from '../../../routing/create-element-book-router';
|
|
5
5
|
import { ElementBookMainRoute, defaultElementBookFullRoute, } from '../../../routing/element-book-routing';
|
|
6
6
|
import { colorThemeCssVars, setThemeCssVars } from '../../color-theme/color-theme';
|
|
@@ -11,6 +11,9 @@ import { ElementBookEntryDisplay } from '../entry-display/element-book-entry-dis
|
|
|
11
11
|
const treeCache = new Map();
|
|
12
12
|
export const ElementBookApp = defineElement()({
|
|
13
13
|
tagName: 'element-book-app',
|
|
14
|
+
events: {
|
|
15
|
+
pathUpdate: defineElementEvent(),
|
|
16
|
+
},
|
|
14
17
|
stateInit: {
|
|
15
18
|
currentRoute: defaultElementBookFullRoute,
|
|
16
19
|
router: undefined,
|
|
@@ -56,32 +59,8 @@ export const ElementBookApp = defineElement()({
|
|
|
56
59
|
top: 0;
|
|
57
60
|
}
|
|
58
61
|
`,
|
|
59
|
-
|
|
60
|
-
if (inputs.baseUrl && !state.router) {
|
|
61
|
-
const router = createElementBookRouter(inputs.baseUrl);
|
|
62
|
-
updateState({ router });
|
|
63
|
-
router.addRouteListener(true, (fullRoute) => {
|
|
64
|
-
updateState({
|
|
65
|
-
currentRoute: fullRoute,
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
renderCallback: ({ state, inputs, host, updateState }) => {
|
|
62
|
+
renderCallback: ({ state, inputs, host, updateState, dispatch, events }) => {
|
|
71
63
|
try {
|
|
72
|
-
const inputThemeConfig = {
|
|
73
|
-
themeColor: inputs.themeColor,
|
|
74
|
-
};
|
|
75
|
-
if (!areJsonEqual(inputThemeConfig, state.colors?.config)) {
|
|
76
|
-
const newTheme = createTheme(inputThemeConfig);
|
|
77
|
-
updateState({
|
|
78
|
-
colors: {
|
|
79
|
-
config: inputThemeConfig,
|
|
80
|
-
theme: newTheme,
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
setThemeCssVars(host, newTheme);
|
|
84
|
-
}
|
|
85
64
|
function updateRoutes(newRoute) {
|
|
86
65
|
if (state.router) {
|
|
87
66
|
state.router.setRoutes(newRoute);
|
|
@@ -94,29 +73,45 @@ export const ElementBookApp = defineElement()({
|
|
|
94
73
|
},
|
|
95
74
|
});
|
|
96
75
|
}
|
|
76
|
+
dispatch(new events.pathUpdate(newRoute.paths ?? []));
|
|
77
|
+
}
|
|
78
|
+
if (inputs.internalRouterConfig?.useInternalRouter && !state.router) {
|
|
79
|
+
const router = createElementBookRouter(inputs.internalRouterConfig.basePath);
|
|
80
|
+
updateState({ router });
|
|
81
|
+
router.addRouteListener(true, (fullRoute) => {
|
|
82
|
+
updateState({
|
|
83
|
+
currentRoute: fullRoute,
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else if (!inputs.internalRouterConfig?.useInternalRouter && state.router) {
|
|
88
|
+
state.router.removeAllRouteListeners();
|
|
89
|
+
}
|
|
90
|
+
const inputThemeConfig = {
|
|
91
|
+
themeColor: inputs.themeColor,
|
|
92
|
+
};
|
|
93
|
+
if (!areJsonEqual(inputThemeConfig, state.colors?.config)) {
|
|
94
|
+
const newTheme = createTheme(inputThemeConfig);
|
|
95
|
+
updateState({
|
|
96
|
+
colors: {
|
|
97
|
+
config: inputThemeConfig,
|
|
98
|
+
theme: newTheme,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
setThemeCssVars(host, newTheme);
|
|
97
102
|
}
|
|
98
103
|
const entriesTree = getOrSetFromMap(treeCache, inputs.entries, () => entriesToTree(inputs.entries, inputs.everythingTitle));
|
|
99
|
-
const
|
|
100
|
-
if (!
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
(firstEntryBreadcrumbs.length ? firstEntryBreadcrumbs : undefined);
|
|
108
|
-
if (defaultPath && defaultPath.length) {
|
|
109
|
-
const newRoute = {
|
|
110
|
-
paths: [
|
|
111
|
-
ElementBookMainRoute.Book,
|
|
112
|
-
...defaultPath,
|
|
113
|
-
],
|
|
114
|
-
};
|
|
115
|
-
updateRoutes(newRoute);
|
|
116
|
-
}
|
|
104
|
+
const entryTreeNodeByInitialPath = findEntryByBreadcrumbs(state.currentRoute.paths.slice(1), entriesTree);
|
|
105
|
+
if (!entryTreeNodeByInitialPath) {
|
|
106
|
+
const newRoute = {
|
|
107
|
+
paths: [
|
|
108
|
+
ElementBookMainRoute.Book,
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
updateRoutes(newRoute);
|
|
117
112
|
}
|
|
118
|
-
const
|
|
119
|
-
if (!
|
|
113
|
+
const currentEntryTreeNode = findEntryByBreadcrumbs(state.currentRoute.paths.slice(1), entriesTree);
|
|
114
|
+
if (!currentEntryTreeNode) {
|
|
120
115
|
throw new Error(`Tried to self-correct for invalid path ${state.currentRoute.paths.join('/')}
|
|
121
116
|
but failed to do so.`);
|
|
122
117
|
}
|
|
@@ -146,7 +141,7 @@ export const ElementBookApp = defineElement()({
|
|
|
146
141
|
<${ElementBookEntryDisplay}
|
|
147
142
|
${assign(ElementBookEntryDisplay, {
|
|
148
143
|
currentRoute: state.currentRoute,
|
|
149
|
-
currentNode,
|
|
144
|
+
currentNode: currentEntryTreeNode,
|
|
150
145
|
router: state.router,
|
|
151
146
|
})}
|
|
152
147
|
></${ElementBookEntryDisplay}>
|
|
@@ -154,6 +149,7 @@ export const ElementBookApp = defineElement()({
|
|
|
154
149
|
`;
|
|
155
150
|
}
|
|
156
151
|
catch (error) {
|
|
152
|
+
console.error(error);
|
|
157
153
|
return html `
|
|
158
154
|
<p class="error">${extractErrorMessage(error)}</p>
|
|
159
155
|
`;
|
|
@@ -1,20 +1,36 @@
|
|
|
1
1
|
import { PartialAndUndefined } from '@augment-vir/common';
|
|
2
|
+
import { RequireExactlyOne } from 'type-fest';
|
|
2
3
|
import { ElementBookEntry } from '../../../data/element-book-entry/element-book-entry';
|
|
3
4
|
export type ElementBookConfig = {
|
|
4
5
|
/** All element-book entries in order. */
|
|
5
6
|
entries: ReadonlyArray<ElementBookEntry>;
|
|
6
7
|
} & PartialAndUndefined<OptionalConfig>;
|
|
7
8
|
type OptionalConfig = {
|
|
8
|
-
/**
|
|
9
|
-
* Path to this page, used for routing. For example, if this page is hosted at
|
|
10
|
-
* www.example.org/my-page then this value should be `my-page`.
|
|
11
|
-
*/
|
|
12
|
-
baseUrl: string;
|
|
13
|
-
/** Starting /book/ path. */
|
|
14
|
-
defaultPath: ReadonlyArray<string>;
|
|
15
|
-
/** Color from which to base all element-book colors from. */
|
|
9
|
+
/** The base theme color from which all other element-book colors will be generated from. */
|
|
16
10
|
themeColor: string;
|
|
17
11
|
/** The title to use for the "Everything" nav link. */
|
|
18
12
|
everythingTitle: string;
|
|
19
|
-
}
|
|
13
|
+
} & RequireExactlyOne<{
|
|
14
|
+
/**
|
|
15
|
+
* Set this internal router config if element-book is intended to be the current website's
|
|
16
|
+
* entire web app. Meaning, you're not embedded element-book within another website.
|
|
17
|
+
*
|
|
18
|
+
* In this case, element-book will create its own internal router for managing the URL. In other
|
|
19
|
+
* cases, when element-book is embedded in another website, use the elementBookRoutePaths input
|
|
20
|
+
* property instead.
|
|
21
|
+
*/
|
|
22
|
+
internalRouterConfig: {
|
|
23
|
+
useInternalRouter: true;
|
|
24
|
+
/**
|
|
25
|
+
* Path to this page, used for routing. For example, if this page is hosted at
|
|
26
|
+
* www.example.org/my-page then this value should be `my-page`.
|
|
27
|
+
*/
|
|
28
|
+
basePath?: string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Current route paths for element-book to handle. These are intended to come from a router
|
|
32
|
+
* that's external to the element-book app itself.
|
|
33
|
+
*/
|
|
34
|
+
elementBookRoutePaths: ReadonlyArray<string>;
|
|
35
|
+
}>;
|
|
20
36
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "element-book",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"book",
|
|
6
6
|
"design system",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"@augment-vir/common": "^13.4.0",
|
|
42
42
|
"@electrovir/icon-element": "^0.0.2",
|
|
43
43
|
"colorjs.io": "^0.4.3",
|
|
44
|
-
"element-vir": "^12.4.
|
|
44
|
+
"element-vir": "^12.4.6",
|
|
45
45
|
"lit-css-vars": "^2.0.2",
|
|
46
|
-
"spa-router-vir": "^2.0
|
|
46
|
+
"spa-router-vir": "^2.1.0",
|
|
47
47
|
"typed-event-target": "^1.2.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|