crelte 0.5.11 → 0.5.13
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/blocks/Blocks.d.ts +1 -1
- package/dist/blocks/Blocks.d.ts.map +1 -1
- package/dist/bodyClass/BodyClass.d.ts +56 -0
- package/dist/bodyClass/BodyClass.d.ts.map +1 -0
- package/dist/bodyClass/BodyClass.js +70 -0
- package/dist/bodyClass/ClientBodyClass.d.ts +17 -0
- package/dist/bodyClass/ClientBodyClass.d.ts.map +1 -0
- package/dist/bodyClass/ClientBodyClass.js +71 -0
- package/dist/bodyClass/ServerBodyClass.d.ts +18 -0
- package/dist/bodyClass/ServerBodyClass.d.ts.map +1 -0
- package/dist/bodyClass/ServerBodyClass.js +61 -0
- package/dist/bodyClass/index.d.ts +2 -0
- package/dist/bodyClass/index.d.ts.map +1 -0
- package/dist/bodyClass/index.js +1 -0
- package/dist/bodyClass/utils.d.ts +39 -0
- package/dist/bodyClass/utils.d.ts.map +1 -0
- package/dist/bodyClass/utils.js +84 -0
- package/dist/cookies/ClientCookies.d.ts +8 -3
- package/dist/cookies/ClientCookies.d.ts.map +1 -1
- package/dist/cookies/ClientCookies.js +31 -7
- package/dist/cookies/Cookies.d.ts +42 -0
- package/dist/cookies/Cookies.d.ts.map +1 -0
- package/dist/cookies/Cookies.js +44 -0
- package/dist/cookies/ServerCookies.d.ts +3 -2
- package/dist/cookies/ServerCookies.d.ts.map +1 -1
- package/dist/cookies/ServerCookies.js +6 -4
- package/dist/cookies/index.d.ts +1 -25
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -1
- package/dist/crelte.d.ts +7 -1
- package/dist/crelte.d.ts.map +1 -1
- package/dist/crelte.js +4 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/init/client.d.ts.map +1 -1
- package/dist/init/client.js +23 -14
- package/dist/init/server.d.ts.map +1 -1
- package/dist/init/server.js +12 -3
- package/dist/init/shared.d.ts +1 -0
- package/dist/init/shared.d.ts.map +1 -1
- package/dist/init/shared.js +19 -5
- package/dist/loadData/Globals.d.ts.map +1 -1
- package/dist/loadData/entry.d.ts +11 -2
- package/dist/loadData/entry.d.ts.map +1 -1
- package/dist/loadData/entry.js +11 -2
- package/dist/node/index.js +1 -1
- package/dist/plugins/Events.d.ts +6 -1
- package/dist/plugins/Events.d.ts.map +1 -1
- package/dist/plugins/Plugins.d.ts +36 -1
- package/dist/plugins/Plugins.d.ts.map +1 -1
- package/dist/plugins/Plugins.js +32 -0
- package/dist/queries/index.d.ts +1 -1
- package/dist/queries/index.d.ts.map +1 -1
- package/dist/routing/route/Request.d.ts +1 -1
- package/dist/routing/route/Request.d.ts.map +1 -1
- package/dist/routing/route/Request.js +7 -3
- package/dist/routing/router/ClientRouter.d.ts.map +1 -1
- package/dist/routing/router/ClientRouter.js +18 -11
- package/dist/routing/router/Router.d.ts.map +1 -1
- package/dist/routing/router/Router.js +8 -12
- package/dist/server/CrelteServer.d.ts +1 -0
- package/dist/server/CrelteServer.d.ts.map +1 -1
- package/dist/server/CrelteServer.js +5 -2
- package/dist/server/queries/QueryGqlRoute.d.ts.map +1 -1
- package/dist/server/queries/QueryGqlRoute.js +3 -3
- package/dist/server/queries/routes.d.ts +1 -1
- package/dist/server/queries/routes.d.ts.map +1 -1
- package/dist/std/stores/StagedWritable.d.ts +48 -0
- package/dist/std/stores/StagedWritable.d.ts.map +1 -0
- package/dist/std/stores/StagedWritable.js +84 -0
- package/dist/std/stores/index.d.ts +2 -1
- package/dist/std/stores/index.d.ts.map +1 -1
- package/dist/std/stores/index.js +2 -1
- package/dist/std/sync/Barrier.js +1 -1
- package/dist/utils.d.ts +9 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +11 -0
- package/package.json +5 -1
- package/src/blocks/Blocks.ts +1 -1
- package/src/bodyClass/BodyClass.ts +94 -0
- package/src/bodyClass/ClientBodyClass.ts +79 -0
- package/src/bodyClass/ServerBodyClass.ts +86 -0
- package/src/bodyClass/index.ts +1 -0
- package/src/bodyClass/utils.ts +118 -0
- package/src/cookies/ClientCookies.ts +41 -10
- package/src/cookies/Cookies.ts +70 -0
- package/src/cookies/ServerCookies.ts +9 -6
- package/src/cookies/index.ts +5 -29
- package/src/crelte.ts +12 -0
- package/src/index.ts +15 -1
- package/src/init/client.ts +26 -14
- package/src/init/server.ts +12 -3
- package/src/init/shared.ts +21 -6
- package/src/loadData/Globals.ts +1 -1
- package/src/loadData/entry.ts +12 -2
- package/src/node/index.ts +1 -1
- package/src/plugins/Events.ts +12 -1
- package/src/plugins/Plugins.ts +66 -1
- package/src/queries/index.ts +5 -1
- package/src/routing/route/Request.ts +11 -4
- package/src/routing/router/ClientRouter.ts +23 -14
- package/src/routing/router/Router.ts +8 -10
- package/src/server/CrelteServer.ts +4 -2
- package/src/server/queries/QueryGqlRoute.ts +3 -2
- package/src/server/queries/routes.ts +1 -0
- package/src/std/stores/StagedWritable.ts +96 -0
- package/src/std/stores/index.ts +2 -1
- package/src/std/sync/Barrier.ts +1 -1
- package/src/utils.ts +15 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import StagedWritable from '../std/stores/StagedWritable.js';
|
|
2
|
+
|
|
3
|
+
export default class BodyClass {
|
|
4
|
+
private inner: PlatformBodyClass;
|
|
5
|
+
private store: StagedWritable<void>;
|
|
6
|
+
|
|
7
|
+
constructor(inner: PlatformBodyClass, store?: StagedWritable<void>) {
|
|
8
|
+
this.inner = inner;
|
|
9
|
+
this.store = store ?? new StagedWritable(void 0);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
subscribe(
|
|
13
|
+
fn: (val: BodyClass) => void,
|
|
14
|
+
invalidate?: () => void,
|
|
15
|
+
): () => void {
|
|
16
|
+
return this.store.subscribe(() => fn(this), invalidate);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Checks if the body contains the given class
|
|
21
|
+
*/
|
|
22
|
+
contains(cls: string): boolean {
|
|
23
|
+
return this.inner.contains(cls);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Adds the given classes to the body
|
|
28
|
+
*/
|
|
29
|
+
add(...classes: string[]): void {
|
|
30
|
+
this.inner.add(...classes);
|
|
31
|
+
this.store.set();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Toggles the given class on the body
|
|
36
|
+
*
|
|
37
|
+
* ## Warning
|
|
38
|
+
* toggle without `force` should almost never be used
|
|
39
|
+
* on the server. If you call this for example in loadData
|
|
40
|
+
* the server will add the class and the client will the remove
|
|
41
|
+
* it.
|
|
42
|
+
*/
|
|
43
|
+
toggle(cls: string, force?: boolean): void {
|
|
44
|
+
if (this.inner.toggle(cls, force)) this.store.set();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Removes the given classes from the body
|
|
49
|
+
*/
|
|
50
|
+
remove(...classes: string[]): void {
|
|
51
|
+
this.inner.remove(...classes);
|
|
52
|
+
this.store.set();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Sets the class for the given variant removing the old class for that
|
|
57
|
+
* variant, if cls is null it will remove the variant class
|
|
58
|
+
*
|
|
59
|
+
* If you just have like a dark or light mode and only for the dark mode a
|
|
60
|
+
* class, **prefer** `toggle('dark', isDarkMode)` over
|
|
61
|
+
* `setVariant('mode', isDarkMode ? 'dark' : null)`
|
|
62
|
+
*
|
|
63
|
+
* ## Note
|
|
64
|
+
* The variant name is only used for the internal state management
|
|
65
|
+
* and has no inpact on the actual class name
|
|
66
|
+
*/
|
|
67
|
+
setVariant(variant: string, cls: string | null): void {
|
|
68
|
+
if (this.inner.setVariant(variant, cls)) this.store.set();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** @hidden */
|
|
72
|
+
z_toRequest(): BodyClass {
|
|
73
|
+
return new BodyClass(this.inner.toRequest(), this.store.stage());
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** @hidden */
|
|
77
|
+
z_render(): void {
|
|
78
|
+
this.inner.render?.();
|
|
79
|
+
this.store.commit();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface PlatformBodyClass {
|
|
84
|
+
contains(cls: string): boolean;
|
|
85
|
+
add(...classes: string[]): void;
|
|
86
|
+
// returns true if the value was changed (this is different to the
|
|
87
|
+
// DOMTokenList.toggle which returns true if the class is now present)
|
|
88
|
+
toggle(cls: string, force?: boolean): boolean;
|
|
89
|
+
remove(...classes: string[]): void;
|
|
90
|
+
// returns true if the value was changed
|
|
91
|
+
setVariant(variant: string, cls: string | null): boolean;
|
|
92
|
+
toRequest(): PlatformBodyClass;
|
|
93
|
+
render?: () => void;
|
|
94
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import SsrCache from '../ssr/SsrCache.js';
|
|
2
|
+
import { PlatformBodyClass } from './BodyClass.js';
|
|
3
|
+
import { ClassSet, ssrCacheToVariants, Variants } from './utils.js';
|
|
4
|
+
|
|
5
|
+
export default class ClientBodyClass implements PlatformBodyClass {
|
|
6
|
+
private variants: Variants;
|
|
7
|
+
// during the request store the classes here
|
|
8
|
+
private inner: ClassSet | null;
|
|
9
|
+
|
|
10
|
+
constructor(variants: Variants, inner?: ClassSet) {
|
|
11
|
+
this.variants = variants;
|
|
12
|
+
this.inner = inner ?? null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static fromSsrCache(ssrCache: SsrCache): ClientBodyClass {
|
|
16
|
+
const variants = ssrCacheToVariants(ssrCache);
|
|
17
|
+
return new ClientBodyClass(variants);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
contains(cls: string): boolean {
|
|
21
|
+
if (this.inner) return this.inner.has(cls);
|
|
22
|
+
return cl().contains(cls);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
add(...classes: string[]): void {
|
|
26
|
+
if (this.inner) classes.forEach(cls => this.inner!.add(cls));
|
|
27
|
+
else cl().add(...classes);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// returns true if the value was changed
|
|
31
|
+
toggle(cls: string, force?: boolean): boolean {
|
|
32
|
+
const exists = this.contains(cls);
|
|
33
|
+
const shouldExist = typeof force === 'boolean' ? force : !exists;
|
|
34
|
+
const changed = shouldExist !== exists;
|
|
35
|
+
|
|
36
|
+
if (this.inner) {
|
|
37
|
+
if (shouldExist) this.inner.add(cls);
|
|
38
|
+
else this.inner.delete(cls);
|
|
39
|
+
} else {
|
|
40
|
+
cl().toggle(cls, force);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return changed;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
remove(...classes: string[]): void {
|
|
47
|
+
if (this.inner) classes.forEach(cls => this.inner!.delete(cls));
|
|
48
|
+
else cl().remove(...classes);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setVariant(variant: string, cls: string | null): boolean {
|
|
52
|
+
if (this.inner) return this.inner.setVariant(variant, cls);
|
|
53
|
+
|
|
54
|
+
const { remove, add } = this.variants.set(variant, cls);
|
|
55
|
+
|
|
56
|
+
if (remove) cl().remove(remove);
|
|
57
|
+
if (add) cl().add(add);
|
|
58
|
+
|
|
59
|
+
return !!remove || !!add;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
toRequest(): ClientBodyClass {
|
|
63
|
+
const inner = new ClassSet(cl(), this.variants.entries(), true);
|
|
64
|
+
return new ClientBodyClass(this.variants, inner);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
render(): void {
|
|
68
|
+
if (!this.inner) throw new Error('call toRequest first');
|
|
69
|
+
|
|
70
|
+
const inner = this.inner;
|
|
71
|
+
this.inner = null;
|
|
72
|
+
|
|
73
|
+
inner.applyHistory(this);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function cl(): DOMTokenList {
|
|
78
|
+
return document.body.classList;
|
|
79
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import SsrCache from '../ssr/SsrCache.js';
|
|
2
|
+
import { PlatformBodyClass } from './BodyClass.js';
|
|
3
|
+
import { ClassSet, variantsToSsrCache } from './utils.js';
|
|
4
|
+
|
|
5
|
+
export default class ServerBodyClass implements PlatformBodyClass {
|
|
6
|
+
private inner: ClassSet;
|
|
7
|
+
|
|
8
|
+
constructor() {
|
|
9
|
+
this.inner = new ClassSet();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
contains(cls: string): boolean {
|
|
13
|
+
return this.inner.has(cls);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
add(...classes: string[]): void {
|
|
17
|
+
validate(classes);
|
|
18
|
+
classes.forEach(cls => this.inner.add(cls));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
toggle(cls: string, force?: boolean): boolean {
|
|
22
|
+
validate([cls]);
|
|
23
|
+
|
|
24
|
+
if (import.meta.env.DEV && typeof force !== 'boolean') {
|
|
25
|
+
console.warn(
|
|
26
|
+
'Using toggle without force on the server can lead ' +
|
|
27
|
+
'to unexpected results. Because in a loadData the server will add it ' +
|
|
28
|
+
'and the client will afterwards remove it.',
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const exists = this.inner.has(cls);
|
|
33
|
+
const shouldExist = typeof force === 'boolean' ? force : !exists;
|
|
34
|
+
const changed = shouldExist !== exists;
|
|
35
|
+
|
|
36
|
+
if (shouldExist) this.inner.add(cls);
|
|
37
|
+
else this.inner.delete(cls);
|
|
38
|
+
|
|
39
|
+
return changed;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
remove(...classes: string[]): void {
|
|
43
|
+
validate(classes);
|
|
44
|
+
classes.forEach(cls => this.inner.delete(cls));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @returns Returns true if the value was changed
|
|
49
|
+
*/
|
|
50
|
+
setVariant(variant: string, cls: string | null): boolean {
|
|
51
|
+
return this.inner.setVariant(variant, cls);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
toRequest(): ServerBodyClass {
|
|
55
|
+
// no second request should ever start on the server
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
z_populateSsrCache(ssrCache: SsrCache): void {
|
|
60
|
+
variantsToSsrCache(this.inner.z_variants, ssrCache);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
z_processHtmlTemplate(html: string): string {
|
|
64
|
+
const SEARCH_STR = '<!--body-class-->';
|
|
65
|
+
if (this.inner.length && !html.includes(SEARCH_STR)) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
'index.html needs to contain `class="<!--body-class-->"`',
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return html.replace(
|
|
72
|
+
SEARCH_STR,
|
|
73
|
+
Array.from(this.inner.classes()).join(' '),
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function validate(classes: string[]) {
|
|
79
|
+
for (const cls of classes) {
|
|
80
|
+
if (cls.includes(' ')) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
`Invalid class name "${cls}". Class names must not contain spaces.`,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as BodyClass } from './BodyClass.js';
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import SsrCache from '../ssr/SsrCache.js';
|
|
2
|
+
|
|
3
|
+
export type HistoryClassSet = {
|
|
4
|
+
add(cls: string): void;
|
|
5
|
+
remove(cls: string): void;
|
|
6
|
+
setVariant(variant: string, cls: string | null): void;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export class ClassSet {
|
|
10
|
+
private _classes: Set<string>;
|
|
11
|
+
/** @hidden */
|
|
12
|
+
z_variants: Variants;
|
|
13
|
+
private history: ((cl: HistoryClassSet) => void)[] | null;
|
|
14
|
+
|
|
15
|
+
constructor(
|
|
16
|
+
classes?: Iterable<string>,
|
|
17
|
+
variants?: Iterable<[string, string]>,
|
|
18
|
+
history: boolean = false,
|
|
19
|
+
) {
|
|
20
|
+
this._classes = new Set(classes);
|
|
21
|
+
this.z_variants = new Variants();
|
|
22
|
+
this.history = history ? [] : null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
classes(): Iterable<string> {
|
|
26
|
+
return this._classes;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get length(): number {
|
|
30
|
+
return this._classes.size;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
has(cls: string): boolean {
|
|
34
|
+
return this._classes.has(cls);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
add(cls: string): void {
|
|
38
|
+
this._classes.add(cls);
|
|
39
|
+
if (this.history) this.history.push(c => c.add(cls));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
delete(cls: string): void {
|
|
43
|
+
this._classes.delete(cls);
|
|
44
|
+
if (this.history) this.history.push(c => c.remove(cls));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @returns Returns true if the value was changed
|
|
49
|
+
*/
|
|
50
|
+
setVariant(variant: string, cls: string | null): boolean {
|
|
51
|
+
const { remove, add } = this.z_variants.set(variant, cls);
|
|
52
|
+
|
|
53
|
+
if (remove) this.delete(remove);
|
|
54
|
+
if (add) this.add(add);
|
|
55
|
+
|
|
56
|
+
const changed = !!remove || !!add;
|
|
57
|
+
|
|
58
|
+
if (this.history) this.history.push(c => c.setVariant(variant, cls));
|
|
59
|
+
|
|
60
|
+
return changed;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Fails if no history is active.
|
|
65
|
+
*/
|
|
66
|
+
applyHistory(cl: HistoryClassSet): void {
|
|
67
|
+
this.history!.forEach(fn => fn(cl));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type VariantSetReturn = {
|
|
72
|
+
remove?: string;
|
|
73
|
+
add?: string;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export class Variants {
|
|
77
|
+
// list of active variant classes
|
|
78
|
+
private inner: Map<string, string>;
|
|
79
|
+
|
|
80
|
+
constructor(entries?: Iterable<[string, string]>) {
|
|
81
|
+
this.inner = new Map(entries);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
set(variant: string, cls: string | null): VariantSetReturn {
|
|
85
|
+
const current = this.inner.get(variant) ?? null;
|
|
86
|
+
|
|
87
|
+
if (current === cls) return {};
|
|
88
|
+
|
|
89
|
+
const obj: VariantSetReturn = {};
|
|
90
|
+
|
|
91
|
+
if (current) obj.remove = current;
|
|
92
|
+
if (cls) {
|
|
93
|
+
obj.add = cls;
|
|
94
|
+
this.inner.set(variant, cls);
|
|
95
|
+
} else {
|
|
96
|
+
this.inner.delete(variant);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return obj;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
entries(): Iterable<[string, string]> {
|
|
103
|
+
return this.inner.entries();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// separate function for tree shaking
|
|
108
|
+
export function ssrCacheToVariants(ssrCache: SsrCache): Variants {
|
|
109
|
+
return new Variants(ssrCache.get('BODY_CLASS_VAR')!);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// separate function for tree shaking
|
|
113
|
+
export function variantsToSsrCache(
|
|
114
|
+
variants: Variants,
|
|
115
|
+
ssrCache: SsrCache,
|
|
116
|
+
): void {
|
|
117
|
+
ssrCache.set('BODY_CLASS_VAR', Array.from(variants.entries()));
|
|
118
|
+
}
|
|
@@ -1,26 +1,57 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { parseCookies, setCookieToString } from './utils.js';
|
|
1
|
+
import { PlatformCookies, RemoveOptions, SetOptions } from './Cookies.js';
|
|
2
|
+
import { parseCookies, SetCookie, setCookieToString } from './utils.js';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
constructor(
|
|
4
|
+
export default class ClientCookies implements PlatformCookies {
|
|
5
|
+
private inner: Map<string, string> | null;
|
|
6
|
+
private setCookies: Map<string, SetCookie> | null;
|
|
7
|
+
|
|
8
|
+
constructor(
|
|
9
|
+
inner?: Map<string, string>,
|
|
10
|
+
setCookies?: Map<string, SetCookie>,
|
|
11
|
+
) {
|
|
12
|
+
this.inner = inner ?? null;
|
|
13
|
+
this.setCookies = setCookies ?? null;
|
|
14
|
+
}
|
|
9
15
|
|
|
10
16
|
get(name: string): string | null {
|
|
11
|
-
|
|
12
|
-
|
|
17
|
+
if (!this.inner || !this.setCookies) {
|
|
18
|
+
const cookies = getCookies();
|
|
19
|
+
return cookies.get(name) ?? null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const setCookie = this.setCookies.get(name);
|
|
23
|
+
if (setCookie) {
|
|
24
|
+
return (setCookie.maxAge ?? 1) > 0 ? setCookie.value : null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return this.inner.get(name) ?? null;
|
|
13
28
|
}
|
|
14
29
|
|
|
15
30
|
set(name: string, value: string, opts?: SetOptions): void {
|
|
16
31
|
const setCookie = { name, value, path: '/', ...opts };
|
|
17
32
|
|
|
18
|
-
|
|
33
|
+
if (this.setCookies) this.setCookies.set(name, setCookie);
|
|
34
|
+
else document.cookie = setCookieToString(setCookie);
|
|
19
35
|
}
|
|
20
36
|
|
|
21
37
|
remove(name: string, opts?: RemoveOptions): void {
|
|
22
38
|
this.set(name, '', { ...opts, maxAge: 0 });
|
|
23
39
|
}
|
|
40
|
+
|
|
41
|
+
toRequest(): ClientCookies {
|
|
42
|
+
return new ClientCookies(getCookies(), new Map());
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
render(): void {
|
|
46
|
+
if (!this.setCookies) throw new Error('call toRequest first');
|
|
47
|
+
|
|
48
|
+
for (const setCookie of this.setCookies.values()) {
|
|
49
|
+
document.cookie = setCookieToString(setCookie);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.inner = null;
|
|
53
|
+
this.setCookies = null;
|
|
54
|
+
}
|
|
24
55
|
}
|
|
25
56
|
|
|
26
57
|
function getCookies(): Map<string, string> {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import StagedWritable from '../std/stores/StagedWritable.js';
|
|
2
|
+
|
|
3
|
+
export type SetOptions = {
|
|
4
|
+
maxAge?: number;
|
|
5
|
+
path?: string;
|
|
6
|
+
domain?: string;
|
|
7
|
+
secure?: boolean;
|
|
8
|
+
httpOnly?: boolean;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type RemoveOptions = Omit<SetOptions, 'maxAge'>;
|
|
12
|
+
|
|
13
|
+
export default class Cookies {
|
|
14
|
+
private inner: PlatformCookies;
|
|
15
|
+
private store: StagedWritable<void>;
|
|
16
|
+
|
|
17
|
+
constructor(inner: PlatformCookies, store?: StagedWritable<void>) {
|
|
18
|
+
this.inner = inner;
|
|
19
|
+
this.store = store ?? new StagedWritable(void 0);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
subscribe(fn: (val: Cookies) => void, invalidate?: () => void): () => void {
|
|
23
|
+
return this.store.subscribe(() => fn(this), invalidate);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* returns the value of the cookie
|
|
28
|
+
*/
|
|
29
|
+
get(name: string): string | null {
|
|
30
|
+
return this.inner.get(name);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* sets the value of the cookie
|
|
35
|
+
*
|
|
36
|
+
* #### Note
|
|
37
|
+
* path defaults to '/'
|
|
38
|
+
*/
|
|
39
|
+
set(name: string, value: string, opts?: SetOptions): void {
|
|
40
|
+
this.inner.set(name, value, opts);
|
|
41
|
+
this.store.set();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* removes the cookie
|
|
46
|
+
*/
|
|
47
|
+
remove(name: string, opts?: RemoveOptions): void {
|
|
48
|
+
this.inner.remove(name, opts);
|
|
49
|
+
this.store.set();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** @hidden */
|
|
53
|
+
z_toRequest(): Cookies {
|
|
54
|
+
return new Cookies(this.inner.toRequest(), this.store.stage());
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** @hidden */
|
|
58
|
+
z_render(): void {
|
|
59
|
+
this.inner.render?.();
|
|
60
|
+
this.store.commit();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface PlatformCookies {
|
|
65
|
+
get(name: string): string | null;
|
|
66
|
+
set(name: string, value: string, opts?: SetOptions): void;
|
|
67
|
+
remove(name: string, opts?: RemoveOptions): void;
|
|
68
|
+
toRequest(): PlatformCookies;
|
|
69
|
+
render?: () => void;
|
|
70
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PlatformCookies, RemoveOptions, SetOptions } from './Cookies.js';
|
|
2
2
|
import { parseCookies, type SetCookie, setCookieToString } from './utils.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* #### Warning
|
|
6
6
|
* This is not stable and should only be used internally by crelte
|
|
7
7
|
*/
|
|
8
|
-
export default class ServerCookies implements
|
|
8
|
+
export default class ServerCookies implements PlatformCookies {
|
|
9
9
|
requestCookies: Map<string, string>;
|
|
10
10
|
setCookies: Map<string, SetCookie>;
|
|
11
11
|
|
|
@@ -14,12 +14,11 @@ export default class ServerCookies implements Cookies {
|
|
|
14
14
|
this.setCookies = new Map();
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
///
|
|
17
|
+
/// Returns the value of the cookie with the given name, or null if it doesn't exist.
|
|
18
18
|
get(name: string): string | null {
|
|
19
19
|
const setCookie = this.setCookies.get(name);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return setCookie.value;
|
|
20
|
+
if (setCookie) {
|
|
21
|
+
return (setCookie.maxAge ?? 1) > 0 ? setCookie.value : null;
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
return this.requestCookies.get(name) ?? null;
|
|
@@ -33,6 +32,10 @@ export default class ServerCookies implements Cookies {
|
|
|
33
32
|
this.set(name, '', { ...opts, maxAge: 0 });
|
|
34
33
|
}
|
|
35
34
|
|
|
35
|
+
toRequest(): ServerCookies {
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
|
|
36
39
|
_populateHeaders(headers: Headers) {
|
|
37
40
|
for (const setCookie of this.setCookies.values()) {
|
|
38
41
|
headers.append('Set-Cookie', setCookieToString(setCookie));
|
package/src/cookies/index.ts
CHANGED
|
@@ -1,29 +1,5 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
httpOnly?: boolean;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export type RemoveOptions = Omit<SetOptions, 'maxAge'>;
|
|
10
|
-
|
|
11
|
-
export interface Cookies {
|
|
12
|
-
/**
|
|
13
|
-
* returns the value of the cookie
|
|
14
|
-
*/
|
|
15
|
-
get(name: string): string | null;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* sets the value of the cookie
|
|
19
|
-
*
|
|
20
|
-
* #### Note
|
|
21
|
-
* path defaults to '/'
|
|
22
|
-
*/
|
|
23
|
-
set(name: string, value: string, opts?: SetOptions): void;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* removes the cookie
|
|
27
|
-
*/
|
|
28
|
-
remove(name: string, opts?: RemoveOptions): void;
|
|
29
|
-
}
|
|
1
|
+
export {
|
|
2
|
+
default as Cookies,
|
|
3
|
+
type SetOptions,
|
|
4
|
+
type RemoveOptions,
|
|
5
|
+
} from './Cookies.js';
|
package/src/crelte.ts
CHANGED
|
@@ -9,6 +9,7 @@ import Queries, { Query, QueryOptions } from './queries/Queries.js';
|
|
|
9
9
|
import { Readable } from './std/stores/index.js';
|
|
10
10
|
import { Entry } from './loadData/index.js';
|
|
11
11
|
import { urlWithPath } from './utils.js';
|
|
12
|
+
import { BodyClass } from './bodyClass/index.js';
|
|
12
13
|
|
|
13
14
|
/** The type for the app.config object */
|
|
14
15
|
export type Config = {
|
|
@@ -113,6 +114,11 @@ export type Crelte = {
|
|
|
113
114
|
*/
|
|
114
115
|
cookies: Cookies;
|
|
115
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Get the BodyClass instance
|
|
119
|
+
*/
|
|
120
|
+
bodyClass: BodyClass;
|
|
121
|
+
|
|
116
122
|
/**
|
|
117
123
|
* Get a Plugin by name
|
|
118
124
|
*/
|
|
@@ -263,6 +269,7 @@ export function newCrelte({
|
|
|
263
269
|
router,
|
|
264
270
|
queries,
|
|
265
271
|
cookies,
|
|
272
|
+
bodyClass,
|
|
266
273
|
}: {
|
|
267
274
|
config: Required<Config>;
|
|
268
275
|
ssrCache: SsrCache;
|
|
@@ -272,6 +279,7 @@ export function newCrelte({
|
|
|
272
279
|
router: Router;
|
|
273
280
|
queries: Queries;
|
|
274
281
|
cookies: Cookies;
|
|
282
|
+
bodyClass: BodyClass;
|
|
275
283
|
}): Crelte {
|
|
276
284
|
return {
|
|
277
285
|
config,
|
|
@@ -282,6 +290,10 @@ export function newCrelte({
|
|
|
282
290
|
router,
|
|
283
291
|
queries,
|
|
284
292
|
cookies,
|
|
293
|
+
bodyClass,
|
|
294
|
+
|
|
295
|
+
// when adding a new helper function make sure to add it to
|
|
296
|
+
// onNewCrelteRequest if needed
|
|
285
297
|
|
|
286
298
|
getPlugin: name => plugins.get(name),
|
|
287
299
|
getEnv: key => ssrCache.get(key as any) as any,
|
package/src/index.ts
CHANGED
|
@@ -17,7 +17,8 @@ import {
|
|
|
17
17
|
LoadDataObj,
|
|
18
18
|
} from './loadData/index.js';
|
|
19
19
|
import Queries from './queries/Queries.js';
|
|
20
|
-
import { Readable } from './std/stores/index.js';
|
|
20
|
+
import { Readable, Writable } from './std/stores/index.js';
|
|
21
|
+
import { BodyClass } from './bodyClass/index.js';
|
|
21
22
|
|
|
22
23
|
export {
|
|
23
24
|
type Crelte,
|
|
@@ -33,6 +34,9 @@ export {
|
|
|
33
34
|
/** The type for the app.init function */
|
|
34
35
|
export type Init = (crelte: Crelte) => void;
|
|
35
36
|
|
|
37
|
+
/** The Props that are passed to the app */
|
|
38
|
+
export type AppProps = { route: Writable<Route> };
|
|
39
|
+
|
|
36
40
|
function innerGetCrelte(): Crelte {
|
|
37
41
|
return getContext('crelte');
|
|
38
42
|
}
|
|
@@ -174,6 +178,16 @@ export function getCookies(): Cookies {
|
|
|
174
178
|
return innerGetCrelte().cookies;
|
|
175
179
|
}
|
|
176
180
|
|
|
181
|
+
/**
|
|
182
|
+
* returns the body class instance
|
|
183
|
+
*
|
|
184
|
+
* #### Note
|
|
185
|
+
* This only works during component initialisation.
|
|
186
|
+
*/
|
|
187
|
+
export function getBodyClass(): BodyClass {
|
|
188
|
+
return innerGetCrelte().bodyClass;
|
|
189
|
+
}
|
|
190
|
+
|
|
177
191
|
/**
|
|
178
192
|
* Listen for route changes
|
|
179
193
|
*
|