@cratis/scene.blueprint.default 4.2.0 → 4.3.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/esm/tsconfig.tsbuildinfo +1 -1
- package/package.json +17 -16
- package/dist/esm/for_AppShell/when_rendering_a_gallery_screen.d.ts +0 -2
- package/dist/esm/for_AppShell/when_rendering_a_gallery_screen.d.ts.map +0 -1
- package/dist/esm/for_AppShell/when_rendering_a_gallery_screen.js +0 -61
- package/dist/esm/for_AppShell/when_rendering_a_gallery_screen.js.map +0 -1
- package/dist/esm/for_LayoutConfigProvider/when_switching_mode_and_reloading.d.ts +0 -2
- package/dist/esm/for_LayoutConfigProvider/when_switching_mode_and_reloading.d.ts.map +0 -1
- package/dist/esm/for_LayoutConfigProvider/when_switching_mode_and_reloading.js +0 -60
- package/dist/esm/for_LayoutConfigProvider/when_switching_mode_and_reloading.js.map +0 -1
- package/dist/esm/for_appShellLayout/when_evaluating_the_arrangement_at_each_size_class.d.ts +0 -2
- package/dist/esm/for_appShellLayout/when_evaluating_the_arrangement_at_each_size_class.d.ts.map +0 -1
- package/dist/esm/for_appShellLayout/when_evaluating_the_arrangement_at_each_size_class.js +0 -26
- package/dist/esm/for_appShellLayout/when_evaluating_the_arrangement_at_each_size_class.js.map +0 -1
- package/dist/esm/for_defaultBlueprint/when_validating_the_bundle.d.ts +0 -2
- package/dist/esm/for_defaultBlueprint/when_validating_the_bundle.d.ts.map +0 -1
- package/dist/esm/for_defaultBlueprint/when_validating_the_bundle.js +0 -32
- package/dist/esm/for_defaultBlueprint/when_validating_the_bundle.js.map +0 -1
- package/dist/esm/for_defaultBlueprintThemes/when_checking_attribution_and_tokens.d.ts +0 -2
- package/dist/esm/for_defaultBlueprintThemes/when_checking_attribution_and_tokens.d.ts.map +0 -1
- package/dist/esm/for_defaultBlueprintThemes/when_checking_attribution_and_tokens.js +0 -40
- package/dist/esm/for_defaultBlueprintThemes/when_checking_attribution_and_tokens.js.map +0 -1
- package/dist/esm/for_fullPageLayout/when_evaluating_the_arrangement_at_each_size_class.d.ts +0 -2
- package/dist/esm/for_fullPageLayout/when_evaluating_the_arrangement_at_each_size_class.d.ts.map +0 -1
- package/dist/esm/for_fullPageLayout/when_evaluating_the_arrangement_at_each_size_class.js +0 -27
- package/dist/esm/for_fullPageLayout/when_evaluating_the_arrangement_at_each_size_class.js.map +0 -1
- package/dist/esm/for_galleryScreenTemplates/when_checking_that_arrangements_reference_declared_slots.d.ts +0 -2
- package/dist/esm/for_galleryScreenTemplates/when_checking_that_arrangements_reference_declared_slots.d.ts.map +0 -1
- package/dist/esm/for_galleryScreenTemplates/when_checking_that_arrangements_reference_declared_slots.js +0 -41
- package/dist/esm/for_galleryScreenTemplates/when_checking_that_arrangements_reference_declared_slots.js.map +0 -1
- package/dist/esm/for_galleryScreenTemplates/when_following_the_nesting_chain.d.ts +0 -2
- package/dist/esm/for_galleryScreenTemplates/when_following_the_nesting_chain.d.ts.map +0 -1
- package/dist/esm/for_galleryScreenTemplates/when_following_the_nesting_chain.js +0 -31
- package/dist/esm/for_galleryScreenTemplates/when_following_the_nesting_chain.js.map +0 -1
- package/dist/esm/for_galleryScreens/when_checking_the_layouts_and_slots_they_fill.d.ts +0 -2
- package/dist/esm/for_galleryScreens/when_checking_the_layouts_and_slots_they_fill.d.ts.map +0 -1
- package/dist/esm/for_galleryScreens/when_checking_the_layouts_and_slots_they_fill.js +0 -33
- package/dist/esm/for_galleryScreens/when_checking_the_layouts_and_slots_they_fill.js.map +0 -1
- package/dist/esm/for_galleryScreens/when_resolving_the_component_names_they_reference.d.ts +0 -2
- package/dist/esm/for_galleryScreens/when_resolving_the_component_names_they_reference.d.ts.map +0 -1
- package/dist/esm/for_galleryScreens/when_resolving_the_component_names_they_reference.js +0 -44
- package/dist/esm/for_galleryScreens/when_resolving_the_component_names_they_reference.js.map +0 -1
- package/dist/esm/for_layoutConfigStorage/when_restoring_a_persisted_configuration.d.ts +0 -2
- package/dist/esm/for_layoutConfigStorage/when_restoring_a_persisted_configuration.d.ts.map +0 -1
- package/dist/esm/for_layoutConfigStorage/when_restoring_a_persisted_configuration.js +0 -60
- package/dist/esm/for_layoutConfigStorage/when_restoring_a_persisted_configuration.js.map +0 -1
- package/dist/esm/for_layoutConfigTransitions/when_anchoring_a_reveal_sidebar.d.ts +0 -2
- package/dist/esm/for_layoutConfigTransitions/when_anchoring_a_reveal_sidebar.d.ts.map +0 -1
- package/dist/esm/for_layoutConfigTransitions/when_anchoring_a_reveal_sidebar.js +0 -28
- package/dist/esm/for_layoutConfigTransitions/when_anchoring_a_reveal_sidebar.js.map +0 -1
- package/dist/esm/for_layoutConfigTransitions/when_the_viewport_crosses_the_mobile_breakpoint.d.ts +0 -2
- package/dist/esm/for_layoutConfigTransitions/when_the_viewport_crosses_the_mobile_breakpoint.d.ts.map +0 -1
- package/dist/esm/for_layoutConfigTransitions/when_the_viewport_crosses_the_mobile_breakpoint.js +0 -38
- package/dist/esm/for_layoutConfigTransitions/when_the_viewport_crosses_the_mobile_breakpoint.js.map +0 -1
- package/dist/esm/for_layoutWrapperClasses/when_rendering_each_mode.d.ts +0 -2
- package/dist/esm/for_layoutWrapperClasses/when_rendering_each_mode.d.ts.map +0 -1
- package/dist/esm/for_layoutWrapperClasses/when_rendering_each_mode.js +0 -39
- package/dist/esm/for_layoutWrapperClasses/when_rendering_each_mode.js.map +0 -1
- package/dist/esm/for_navigation/when_aggregating_the_navigation_contributions.d.ts +0 -2
- package/dist/esm/for_navigation/when_aggregating_the_navigation_contributions.d.ts.map +0 -1
- package/dist/esm/for_navigation/when_aggregating_the_navigation_contributions.js +0 -37
- package/dist/esm/for_navigation/when_aggregating_the_navigation_contributions.js.map +0 -1
- package/for_AppShell/when_rendering_a_gallery_screen.tsx +0 -85
- package/for_LayoutConfigProvider/when_switching_mode_and_reloading.tsx +0 -77
- package/for_appShellLayout/when_evaluating_the_arrangement_at_each_size_class.ts +0 -42
- package/for_defaultBlueprint/when_validating_the_bundle.ts +0 -43
- package/for_defaultBlueprintThemes/when_checking_attribution_and_tokens.ts +0 -50
- package/for_fullPageLayout/when_evaluating_the_arrangement_at_each_size_class.ts +0 -36
- package/for_galleryScreenTemplates/when_checking_that_arrangements_reference_declared_slots.ts +0 -53
- package/for_galleryScreenTemplates/when_following_the_nesting_chain.ts +0 -41
- package/for_galleryScreens/when_checking_the_layouts_and_slots_they_fill.ts +0 -44
- package/for_galleryScreens/when_resolving_the_component_names_they_reference.ts +0 -60
- package/for_layoutConfigStorage/when_restoring_a_persisted_configuration.ts +0 -76
- package/for_layoutConfigTransitions/when_anchoring_a_reveal_sidebar.ts +0 -44
- package/for_layoutConfigTransitions/when_the_viewport_crosses_the_mobile_breakpoint.ts +0 -61
- package/for_layoutWrapperClasses/when_rendering_each_mode.ts +0 -63
- package/for_navigation/when_aggregating_the_navigation_contributions.ts +0 -50
package/for_galleryScreenTemplates/when_checking_that_arrangements_reference_declared_slots.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
-
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
-
|
|
4
|
-
import { Arrangement, FlowArrangement, FlowContainer, FlowNode, Slot } from '@cratis/scene.model';
|
|
5
|
-
import { defaultBlueprint } from '../defaultBlueprint';
|
|
6
|
-
import { galleryScreenTemplates } from '../gallery';
|
|
7
|
-
|
|
8
|
-
function slotNamesIn(node: FlowNode): string[] {
|
|
9
|
-
if ('slotName' in node) {
|
|
10
|
-
return [(node as { slotName: string }).slotName];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if ('children' in node) {
|
|
14
|
-
return (node as FlowContainer).children.flatMap(slotNamesIn);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return [];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function referencedSlots(arrangement: Arrangement | undefined): string[] {
|
|
21
|
-
const flow = arrangement as FlowArrangement | undefined;
|
|
22
|
-
if (!flow?.root) {
|
|
23
|
-
return [];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return [flow.root, ...(flow.overrides ?? []).map(override => override.root)].flatMap(slotNamesIn);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function undeclared(slots: Slot[], arrangement: Arrangement | undefined): string[] {
|
|
30
|
-
const declared = new Set(slots.map(slot => slot.name));
|
|
31
|
-
return [...new Set(referencedSlots(arrangement))].filter(name => !declared.has(name));
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
describe('when checking that arrangements reference declared slots', () => {
|
|
35
|
-
for (const layout of defaultBlueprint.layouts ?? []) {
|
|
36
|
-
it(`should reference only slots the '${layout.name}' layout declares`, () => {
|
|
37
|
-
undeclared(layout.slots, layout.arrangement).should.be.empty;
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
for (const template of galleryScreenTemplates.filter(candidate => candidate.arrangement !== undefined)) {
|
|
42
|
-
it(`should reference only slots the '${template.name}' template declares`, () => {
|
|
43
|
-
undeclared(template.slots, template.arrangement).should.be.empty;
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
for (const template of galleryScreenTemplates) {
|
|
48
|
-
it(`should file '${template.name}' content only under slots it declares`, () => {
|
|
49
|
-
const declared = new Set(template.slots.map(slot => slot.name));
|
|
50
|
-
Object.keys(template.content ?? {}).filter(name => !declared.has(name)).should.be.empty;
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
});
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
-
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
-
|
|
4
|
-
import { Slot } from '@cratis/scene.model';
|
|
5
|
-
import { appShellLayout, fullPageLayout } from '../layouts';
|
|
6
|
-
import { featureSectionTemplate, galleryScreenTemplates, moduleWorkspaceTemplate, sliceSectionTemplate } from '../gallery';
|
|
7
|
-
|
|
8
|
-
function declares(slots: Slot[], name: string | undefined): boolean {
|
|
9
|
-
return name !== undefined && slots.some(slot => slot.name === name);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
describe('when following the nesting chain', () => {
|
|
13
|
-
it('should fit the module template into a slot the application layout declares', () => {
|
|
14
|
-
declares(appShellLayout.slots, moduleWorkspaceTemplate.fitsSlot).should.be.true;
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('should fit the feature template into a slot the module template declares', () => {
|
|
18
|
-
declares(moduleWorkspaceTemplate.slots, featureSectionTemplate.fitsSlot).should.be.true;
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should fit the slice template into a slot the feature template declares', () => {
|
|
22
|
-
declares(featureSectionTemplate.slots, sliceSectionTemplate.fitsSlot).should.be.true;
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should resolve each level against its direct parent rather than globally', () => {
|
|
26
|
-
featureSectionTemplate.fitsSlot!.should.equal(sliceSectionTemplate.fitsSlot!);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should fit every other template into a slot one of the layouts declares', () => {
|
|
30
|
-
const layoutSlots = [...appShellLayout.slots, ...fullPageLayout.slots];
|
|
31
|
-
const templateSlots = galleryScreenTemplates.flatMap(template => template.slots);
|
|
32
|
-
galleryScreenTemplates
|
|
33
|
-
.filter(template => !declares(layoutSlots, template.fitsSlot) && !declares(templateSlots, template.fitsSlot))
|
|
34
|
-
.map(template => template.name)
|
|
35
|
-
.should.be.empty;
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should give every screen template a slot to fit into', () => {
|
|
39
|
-
galleryScreenTemplates.filter(template => template.fitsSlot === undefined).map(template => template.name).should.be.empty;
|
|
40
|
-
});
|
|
41
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
-
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
-
|
|
4
|
-
import { Layout } from '@cratis/scene.model';
|
|
5
|
-
import { defaultBlueprint } from '../defaultBlueprint';
|
|
6
|
-
import { galleryScreens } from '../gallery';
|
|
7
|
-
import { shellComponentForLayout } from '../layouts';
|
|
8
|
-
|
|
9
|
-
describe('when checking the layouts and slots they fill', () => {
|
|
10
|
-
const layouts = defaultBlueprint.layouts ?? [];
|
|
11
|
-
const layoutsByName = new Map<string, Layout>(layouts.map(layout => [layout.name, layout]));
|
|
12
|
-
|
|
13
|
-
it('should have at least one screen to check', () => {
|
|
14
|
-
galleryScreens.should.not.be.empty;
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
for (const screen of galleryScreens) {
|
|
18
|
-
describe(`and the screen is '${screen.name}'`, () => {
|
|
19
|
-
const layout = layoutsByName.get(screen.layout);
|
|
20
|
-
|
|
21
|
-
it('should name a layout this blueprint provides', () => {
|
|
22
|
-
(layout !== undefined).should.be.true;
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should fill only slots the layout declares', () => {
|
|
26
|
-
const declared = new Set((layout?.slots ?? []).map(slot => slot.name));
|
|
27
|
-
const filled = Object.keys(screen.slotContent);
|
|
28
|
-
filled.filter(name => !declared.has(name)).should.be.empty;
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('should fill the content slot, which is the only one every layout declares', () => {
|
|
32
|
-
(screen.slotContent.content?.length ?? 0).should.be.greaterThan(0);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('should name a screen template this blueprint provides', () => {
|
|
36
|
-
(defaultBlueprint.screenTemplates ?? []).map(template => template.name).should.contain(screen.screenTemplate);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should render in a shell this blueprint provides', () => {
|
|
40
|
-
(shellComponentForLayout(screen.layout) !== undefined).should.be.true;
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
});
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
-
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
-
|
|
4
|
-
import { resolveComponentName } from '@cratis/scene.engine';
|
|
5
|
-
import { ComponentName } from '../ComponentName';
|
|
6
|
-
import {
|
|
7
|
-
composeScreenElement,
|
|
8
|
-
distinctComponentNames,
|
|
9
|
-
galleryComponentCatalog,
|
|
10
|
-
galleryDialogTemplates,
|
|
11
|
-
galleryProfile,
|
|
12
|
-
galleryScreens,
|
|
13
|
-
} from '../gallery';
|
|
14
|
-
import { defaultBlueprintName } from '../packageName';
|
|
15
|
-
|
|
16
|
-
describe('when resolving the component names they reference', () => {
|
|
17
|
-
const fromScreens = distinctComponentNames(galleryScreens.map(composeScreenElement));
|
|
18
|
-
const fromDialogs = distinctComponentNames(galleryDialogTemplates.flatMap(template => Object.values(template.content ?? {}).flat()));
|
|
19
|
-
const names = [...new Set([...fromScreens, ...fromDialogs])].sort();
|
|
20
|
-
const resolutions = names.map(name => ({ name, resolution: resolveComponentName(name, galleryProfile, galleryComponentCatalog) }));
|
|
21
|
-
const blueprintNames = new Set<string>(Object.values(ComponentName));
|
|
22
|
-
|
|
23
|
-
it('should reference something', () => {
|
|
24
|
-
names.should.not.be.empty;
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should reference something from the dialog templates too', () => {
|
|
28
|
-
fromDialogs.should.not.be.empty;
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('should resolve every referenced name against the profile', () => {
|
|
32
|
-
resolutions
|
|
33
|
-
.filter(entry => entry.resolution === undefined)
|
|
34
|
-
.map(entry => entry.name)
|
|
35
|
-
.should.be.empty;
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should resolve this blueprint own names to this blueprint', () => {
|
|
39
|
-
resolutions
|
|
40
|
-
.filter(entry => blueprintNames.has(entry.name))
|
|
41
|
-
.filter(entry => entry.resolution?.package !== defaultBlueprintName)
|
|
42
|
-
.map(entry => entry.name)
|
|
43
|
-
.should.be.empty;
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('should shadow the component libraries for the names this blueprint also declares', () => {
|
|
47
|
-
const menu = resolveComponentName(ComponentName.Menu, galleryProfile, galleryComponentCatalog);
|
|
48
|
-
menu!.package.should.equal(defaultBlueprintName);
|
|
49
|
-
menu!.shadows.should.contain('PrimeReact');
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('should reference every shell component the blueprint registers except the ones a host places itself', () => {
|
|
53
|
-
const referenced = new Set(names);
|
|
54
|
-
const placedByAHostRatherThanATemplate = [ComponentName.Mask, ComponentName.ThemeSwitcher, ComponentName.LayoutModeSwitcher, ComponentName.RightPanel];
|
|
55
|
-
Object.values(ComponentName)
|
|
56
|
-
.filter(name => !placedByAHostRatherThanATemplate.includes(name))
|
|
57
|
-
.filter(name => !referenced.has(name))
|
|
58
|
-
.should.be.empty;
|
|
59
|
-
});
|
|
60
|
-
});
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
-
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
-
|
|
4
|
-
import { ColorScheme, LayoutMode, MenuTheme, defaultLayoutConfigState, layoutConfigStorageKey, persistLayoutConfig, readPersistedLayoutConfig, withMobile, withMode, withSidebarAnchored } from '../configuration';
|
|
5
|
-
|
|
6
|
-
class FakeStorage {
|
|
7
|
-
entries = new Map<string, string>();
|
|
8
|
-
getItem(key: string): string | null {
|
|
9
|
-
return this.entries.has(key) ? this.entries.get(key)! : null;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
setItem(key: string, value: string): void {
|
|
13
|
-
this.entries.set(key, value);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function storageWith(raw: string): Storage {
|
|
18
|
-
const storage = new FakeStorage();
|
|
19
|
-
storage.setItem(layoutConfigStorageKey, raw);
|
|
20
|
-
return storage as unknown as Storage;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
describe('when restoring a persisted configuration', () => {
|
|
24
|
-
it('should fall back to the defaults when nothing was persisted', () => {
|
|
25
|
-
readPersistedLayoutConfig(new FakeStorage() as unknown as Storage).should.deep.equal(defaultLayoutConfigState());
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('should fall back to the defaults when there is no storage at all', () => {
|
|
29
|
-
readPersistedLayoutConfig(undefined).should.deep.equal(defaultLayoutConfigState());
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('should round-trip the preferences that are worth keeping', () => {
|
|
33
|
-
const storage = new FakeStorage() as unknown as Storage;
|
|
34
|
-
const chosen = withSidebarAnchored(withMode(defaultLayoutConfigState(), LayoutMode.Drawer), true);
|
|
35
|
-
persistLayoutConfig(chosen, storage);
|
|
36
|
-
|
|
37
|
-
const restored = readPersistedLayoutConfig(storage);
|
|
38
|
-
restored.mode.should.equal(LayoutMode.Drawer);
|
|
39
|
-
restored.isSidebarAnchored.should.be.true;
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should not restore the transient state', () => {
|
|
43
|
-
const storage = new FakeStorage() as unknown as Storage;
|
|
44
|
-
persistLayoutConfig(withMobile(defaultLayoutConfigState(), true), storage);
|
|
45
|
-
readPersistedLayoutConfig(storage).isMobile.should.be.false;
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('should ignore an unrecognized mode rather than putting a class no rule matches on the wrapper', () => {
|
|
49
|
-
readPersistedLayoutConfig(storageWith('{"mode":"kaleidoscope"}')).mode.should.equal(defaultLayoutConfigState().mode);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('should ignore an unrecognized menu theme and color scheme', () => {
|
|
53
|
-
const restored = readPersistedLayoutConfig(storageWith('{"menuTheme":"neon","colorScheme":"sepia"}'));
|
|
54
|
-
restored.menuTheme.should.equal(MenuTheme.Light);
|
|
55
|
-
restored.colorScheme.should.equal(ColorScheme.Light);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should survive malformed json', () => {
|
|
59
|
-
readPersistedLayoutConfig(storageWith('{ not json')).should.deep.equal(defaultLayoutConfigState());
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('should survive json that is not an object', () => {
|
|
63
|
-
readPersistedLayoutConfig(storageWith('[1,2,3]')).should.deep.equal(defaultLayoutConfigState());
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should not throw when storage refuses to write', () => {
|
|
67
|
-
const refusing = {
|
|
68
|
-
getItem: () => null,
|
|
69
|
-
setItem: () => {
|
|
70
|
-
throw new Error('QuotaExceededError');
|
|
71
|
-
},
|
|
72
|
-
} as unknown as Storage;
|
|
73
|
-
|
|
74
|
-
(() => persistLayoutConfig(defaultLayoutConfigState(), refusing)).should.not.throw();
|
|
75
|
-
});
|
|
76
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
-
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
LayoutMode,
|
|
6
|
-
defaultLayoutConfigState,
|
|
7
|
-
isPointerRevealMode,
|
|
8
|
-
toggleSidebarAnchor,
|
|
9
|
-
withMode,
|
|
10
|
-
withSidebarRevealed,
|
|
11
|
-
} from '../configuration';
|
|
12
|
-
|
|
13
|
-
describe('when anchoring a reveal sidebar', () => {
|
|
14
|
-
const reveal = withMode(defaultLayoutConfigState(), LayoutMode.Reveal);
|
|
15
|
-
const anchored = toggleSidebarAnchor(reveal);
|
|
16
|
-
|
|
17
|
-
it('should recognize reveal and drawer as the pointer-driven modes', () => {
|
|
18
|
-
isPointerRevealMode(LayoutMode.Reveal).should.be.true;
|
|
19
|
-
isPointerRevealMode(LayoutMode.Drawer).should.be.true;
|
|
20
|
-
isPointerRevealMode(LayoutMode.Static).should.be.false;
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should hold the sidebar out as soon as it is anchored', () => {
|
|
24
|
-
anchored.isSidebarRevealed.should.be.true;
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should ignore the pointer while anchored', () => {
|
|
28
|
-
withSidebarRevealed(anchored, false).should.equal(anchored);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('should let the pointer take over again once unanchored', () => {
|
|
32
|
-
const unanchored = toggleSidebarAnchor(anchored);
|
|
33
|
-
unanchored.isSidebarAnchored.should.be.false;
|
|
34
|
-
withSidebarRevealed(unanchored, true).isSidebarRevealed.should.be.true;
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should keep the pin across a mode change, since it is a preference rather than transient state', () => {
|
|
38
|
-
withMode(anchored, LayoutMode.Drawer).isSidebarAnchored.should.be.true;
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should drop a pointer-held reveal when the mode changes', () => {
|
|
42
|
-
withMode(withSidebarRevealed(reveal, true), LayoutMode.Static).isSidebarRevealed.should.be.false;
|
|
43
|
-
});
|
|
44
|
-
});
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
-
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
LayoutMode,
|
|
6
|
-
defaultLayoutConfigState,
|
|
7
|
-
effectiveLayoutMode,
|
|
8
|
-
isMobileWidth,
|
|
9
|
-
layoutModes,
|
|
10
|
-
layoutWrapperClasses,
|
|
11
|
-
mobileBreakpoint,
|
|
12
|
-
toggleSidebar,
|
|
13
|
-
withMobile,
|
|
14
|
-
withMode,
|
|
15
|
-
} from '../configuration';
|
|
16
|
-
|
|
17
|
-
describe('when the viewport crosses the mobile breakpoint', () => {
|
|
18
|
-
const desktop = withMode(defaultLayoutConfigState(), LayoutMode.Slim);
|
|
19
|
-
const mobile = withMobile(desktop, true);
|
|
20
|
-
const backToDesktop = withMobile(mobile, false);
|
|
21
|
-
|
|
22
|
-
it('should treat the breakpoint itself as mobile, matching the stylesheet', () => {
|
|
23
|
-
isMobileWidth(mobileBreakpoint).should.be.true;
|
|
24
|
-
isMobileWidth(mobileBreakpoint + 1).should.be.false;
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should force every mode off-canvas below the breakpoint', () => {
|
|
28
|
-
for (const mode of layoutModes) {
|
|
29
|
-
effectiveLayoutMode(withMobile(withMode(desktop, mode), true)).should.equal(LayoutMode.Overlay);
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should keep the chosen mode rather than overwriting it', () => {
|
|
34
|
-
mobile.mode.should.equal(LayoutMode.Slim);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should close the sidebar on the way in so the page is not covered on arrival', () => {
|
|
38
|
-
mobile.isSidebarOpen.should.be.false;
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should mark the wrapper mobile', () => {
|
|
42
|
-
layoutWrapperClasses(mobile).should.contain('layout-mobile');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should mark the wrapper mobile-active once the sidebar is opened', () => {
|
|
46
|
-
layoutWrapperClasses(toggleSidebar(mobile)).should.contain('layout-mobile-active');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('should restore the chosen mode on the way back out', () => {
|
|
50
|
-
effectiveLayoutMode(backToDesktop).should.equal(LayoutMode.Slim);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('should leave the state untouched when the regime has not actually changed', () => {
|
|
54
|
-
withMobile(mobile, true).should.equal(mobile);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should reopen a static sidebar on the way back out, since docked is its resting state', () => {
|
|
58
|
-
const staticMobile = withMobile(withMode(defaultLayoutConfigState(), LayoutMode.Static), true);
|
|
59
|
-
withMobile(staticMobile, false).isSidebarOpen.should.be.true;
|
|
60
|
-
});
|
|
61
|
-
});
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
-
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
LayoutMode,
|
|
6
|
-
defaultLayoutConfigState,
|
|
7
|
-
isLayoutMaskVisible,
|
|
8
|
-
layoutModes,
|
|
9
|
-
layoutWrapperClasses,
|
|
10
|
-
toggleSidebar,
|
|
11
|
-
withMobile,
|
|
12
|
-
withMode,
|
|
13
|
-
withSidebarAnchored,
|
|
14
|
-
withSidebarRevealed,
|
|
15
|
-
} from '../configuration';
|
|
16
|
-
|
|
17
|
-
describe('when rendering each mode', () => {
|
|
18
|
-
const started = defaultLayoutConfigState();
|
|
19
|
-
|
|
20
|
-
it('should always start with the wrapper class', () => {
|
|
21
|
-
layoutWrapperClasses(started)[0].should.equal('layout-wrapper');
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
for (const mode of layoutModes) {
|
|
25
|
-
it(`should put the '${mode}' mode class on the wrapper`, () => {
|
|
26
|
-
layoutWrapperClasses(withMode(started, mode)).should.contain(`layout-${mode}`);
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
it('should mark a closed static sidebar inactive', () => {
|
|
31
|
-
layoutWrapperClasses(toggleSidebar(withMode(started, LayoutMode.Static))).should.contain('layout-static-inactive');
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should not mark an open static sidebar inactive', () => {
|
|
35
|
-
layoutWrapperClasses(withMode(started, LayoutMode.Static)).should.not.contain('layout-static-inactive');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should mark an opened overlay sidebar active', () => {
|
|
39
|
-
layoutWrapperClasses(toggleSidebar(withMode(started, LayoutMode.Overlay))).should.contain('layout-overlay-active');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should mark a revealed sidebar active', () => {
|
|
43
|
-
layoutWrapperClasses(withSidebarRevealed(withMode(started, LayoutMode.Reveal), true)).should.contain('layout-sidebar-active');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('should mark an anchored sidebar anchored', () => {
|
|
47
|
-
layoutWrapperClasses(withSidebarAnchored(withMode(started, LayoutMode.Drawer), true)).should.contain('layout-sidebar-anchored');
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should not mark a static sidebar anchored, since only reveal and drawer answer to the pointer', () => {
|
|
51
|
-
layoutWrapperClasses(withSidebarAnchored(withMode(started, LayoutMode.Static), true)).should.not.contain('layout-sidebar-anchored');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('should show the mask only while a floating sidebar is open', () => {
|
|
55
|
-
isLayoutMaskVisible(toggleSidebar(withMode(started, LayoutMode.Overlay))).should.be.true;
|
|
56
|
-
isLayoutMaskVisible(withMode(started, LayoutMode.Overlay)).should.be.false;
|
|
57
|
-
isLayoutMaskVisible(withMode(started, LayoutMode.Static)).should.be.false;
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should show the mask on mobile once the sidebar is opened, whatever the chosen mode', () => {
|
|
61
|
-
isLayoutMaskVisible(toggleSidebar(withMobile(withMode(started, LayoutMode.Horizontal), true))).should.be.true;
|
|
62
|
-
});
|
|
63
|
-
});
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
-
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
-
|
|
4
|
-
import { NavigationItem } from '@cratis/scene.model';
|
|
5
|
-
import { aggregateContributions } from '@cratis/scene.engine';
|
|
6
|
-
import { extractNavigationItem } from '@cratis/scene.react';
|
|
7
|
-
import { galleryScreen, galleryScreenTemplates, navigationContributionPoint, navigationContributions, navigationEntries } from '../gallery';
|
|
8
|
-
|
|
9
|
-
describe('when aggregating the navigation contributions', () => {
|
|
10
|
-
const aggregated = aggregateContributions(navigationContributions, navigationContributionPoint);
|
|
11
|
-
const items = aggregated.map(extractNavigationItem).filter((item): item is NavigationItem => item !== undefined);
|
|
12
|
-
|
|
13
|
-
it('should aggregate one contribution per navigation entry', () => {
|
|
14
|
-
aggregated.should.have.lengthOf(navigationEntries.length);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('should extract every one of them as a navigation item', () => {
|
|
18
|
-
items.should.have.lengthOf(navigationEntries.length);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should carry the label and target screen through the property bag unchanged', () => {
|
|
22
|
-
const dashboard = items.find(item => item.targetScreen === 'Dashboard');
|
|
23
|
-
dashboard!.label.should.equal('Dashboard');
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('should carry the group so an aggregated navigation can section itself', () => {
|
|
27
|
-
items.filter(item => item.group === undefined).should.be.empty;
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should carry a route parameter bag rather than leaving it undefined', () => {
|
|
31
|
-
items.filter(item => item.routeParameterBindings === undefined).should.be.empty;
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should point every entry at a screen template this blueprint provides', () => {
|
|
35
|
-
const provided = new Set(galleryScreenTemplates.map(template => template.name));
|
|
36
|
-
items.filter(item => !provided.has(item.targetScreen)).map(item => item.targetScreen).should.be.empty;
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should point every entry at a screen the gallery actually ships', () => {
|
|
40
|
-
items.filter(item => galleryScreen(item.targetScreen) === undefined).map(item => item.targetScreen).should.be.empty;
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should carry the contributions on every application-shell screen', () => {
|
|
44
|
-
galleryScreen('Dashboard')!.contributions.should.have.lengthOf(navigationEntries.length);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should not carry navigation on a full-page screen, which has no navigation to render', () => {
|
|
48
|
-
galleryScreen('Login')!.contributions.should.be.empty;
|
|
49
|
-
});
|
|
50
|
-
});
|