@startinblox/boilerplate 3.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/.gitlab-ci.yml +57 -0
- package/.storybook/main.ts +15 -0
- package/.storybook/preview-head.html +8 -0
- package/.storybook/preview.ts +22 -0
- package/LICENSE +21 -0
- package/README.md +85 -0
- package/biome.json +39 -0
- package/cypress/component/solid-boilerplate.cy.ts +9 -0
- package/cypress/cypress.d.ts +1 -0
- package/cypress/support/component-index.html +12 -0
- package/cypress/support/component.ts +17 -0
- package/cypress.config.ts +11 -0
- package/dist/boilerplate.css +1 -0
- package/dist/index.js +1213 -0
- package/lit-localize.json +15 -0
- package/locales/en.xlf +13 -0
- package/package.json +92 -0
- package/postcss.config.js +8 -0
- package/src/component.d.ts +161 -0
- package/src/components/solid-boilerplate.ts +79 -0
- package/src/components/ui/sample-object.ts +37 -0
- package/src/components/ui/sample-objects.ts +40 -0
- package/src/context.json +1 -0
- package/src/helpers/components/componentObjectHandler.ts +100 -0
- package/src/helpers/components/componentObjectsHandler.ts +44 -0
- package/src/helpers/components/orbitComponent.ts +241 -0
- package/src/helpers/components/setupCacheInvalidation.ts +37 -0
- package/src/helpers/components/setupCacheOnResourceReady.ts +32 -0
- package/src/helpers/components/setupComponentSubscriptions.ts +73 -0
- package/src/helpers/components/setupOnSaveReset.ts +20 -0
- package/src/helpers/datas/dataBuilder.ts +43 -0
- package/src/helpers/datas/filterGenerator.ts +29 -0
- package/src/helpers/datas/filterObjectByDateAfter.ts +80 -0
- package/src/helpers/datas/filterObjectById.ts +54 -0
- package/src/helpers/datas/filterObjectByInterval.ts +133 -0
- package/src/helpers/datas/filterObjectByNamedValue.ts +103 -0
- package/src/helpers/datas/filterObjectByType.ts +30 -0
- package/src/helpers/datas/filterObjectByValue.ts +81 -0
- package/src/helpers/datas/sort.ts +40 -0
- package/src/helpers/i18n/configureLocalization.ts +17 -0
- package/src/helpers/index.ts +41 -0
- package/src/helpers/ui/formatDate.ts +18 -0
- package/src/helpers/ui/lipsum.ts +12 -0
- package/src/helpers/utils/requestNavigation.ts +12 -0
- package/src/helpers/utils/uniq.ts +6 -0
- package/src/index.ts +7 -0
- package/src/initializer.ts +11 -0
- package/src/mocks/orbit.mock.ts +33 -0
- package/src/mocks/user.mock.ts +67 -0
- package/src/styles/component-sample.scss +4 -0
- package/src/styles/index.scss +16 -0
- package/stories/sample-objects.stories.ts +47 -0
- package/tsconfig.json +36 -0
- package/vite.config.ts +44 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/lit/lit/main/packages/localize-tools/config.schema.json",
|
|
3
|
+
"sourceLocale": "en",
|
|
4
|
+
"targetLocales": ["en"],
|
|
5
|
+
"tsConfig": "./tsconfig.json",
|
|
6
|
+
"output": {
|
|
7
|
+
"mode": "runtime",
|
|
8
|
+
"outputDir": "./src/generated/locales",
|
|
9
|
+
"localeCodesModule": "./src/generated/locale-codes.ts"
|
|
10
|
+
},
|
|
11
|
+
"interchange": {
|
|
12
|
+
"format": "xliff",
|
|
13
|
+
"xliffDir": "./locales/"
|
|
14
|
+
}
|
|
15
|
+
}
|
package/locales/en.xlf
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
|
3
|
+
<file target-language="en" source-language="en" original="lit-localize-inputs" datatype="plaintext">
|
|
4
|
+
<body>
|
|
5
|
+
<trans-unit id="se975788b1544119d">
|
|
6
|
+
<source>Here are all of our objects:</source>
|
|
7
|
+
</trans-unit>
|
|
8
|
+
<trans-unit id="s9cb0b52fd65ea225">
|
|
9
|
+
<source>Sample object named: <x id="0" equiv-text="${this.object.name}"/></source>
|
|
10
|
+
</trans-unit>
|
|
11
|
+
</body>
|
|
12
|
+
</file>
|
|
13
|
+
</xliff>
|
package/package.json
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@startinblox/boilerplate",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Startin'blox Boilerplate",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://git.startinblox.com/components/solid-boilerplate.git"
|
|
10
|
+
},
|
|
11
|
+
"author": "startinblox",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"release": {
|
|
14
|
+
"branches": [
|
|
15
|
+
"master",
|
|
16
|
+
{
|
|
17
|
+
"name": "beta",
|
|
18
|
+
"prerelease": true
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "alpha",
|
|
22
|
+
"prerelease": true
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"plugins": [
|
|
26
|
+
[
|
|
27
|
+
"@semantic-release/commit-analyzer",
|
|
28
|
+
{
|
|
29
|
+
"preset": "angular",
|
|
30
|
+
"releaseRules": [
|
|
31
|
+
{
|
|
32
|
+
"type": "major",
|
|
33
|
+
"release": "major"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"type": "minor",
|
|
37
|
+
"release": "minor"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"type": "*",
|
|
41
|
+
"release": "patch"
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"@semantic-release/release-notes-generator",
|
|
47
|
+
"@semantic-release/gitlab",
|
|
48
|
+
"@semantic-release/npm"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"watch": "lit-localize build && vite",
|
|
56
|
+
"build": "lit-localize build && vite build",
|
|
57
|
+
"serve": "vite preview",
|
|
58
|
+
"cy:open": "cypress open --component",
|
|
59
|
+
"cy:run": "lit-localize build && cypress run --component",
|
|
60
|
+
"storybook": "lit-localize build && storybook dev -p 6006",
|
|
61
|
+
"build-storybook": "lit-localize build && storybook build",
|
|
62
|
+
"locale:extract": "lit-localize extract",
|
|
63
|
+
"locale:build": "lit-localize build"
|
|
64
|
+
},
|
|
65
|
+
"browserslist": [
|
|
66
|
+
"last 2 Chrome versions"
|
|
67
|
+
],
|
|
68
|
+
"dependencies": {
|
|
69
|
+
"@lit/localize": "^0.12.2",
|
|
70
|
+
"@lit/task": "^1.0.2",
|
|
71
|
+
"autoprefixer": "^10.4.21",
|
|
72
|
+
"cssnano": "^7.0.6",
|
|
73
|
+
"lit": "^3.2.1",
|
|
74
|
+
"postcss": "^8.5.3",
|
|
75
|
+
"postcss-preset-env": "^9.6.0",
|
|
76
|
+
"postcss-scss": "^4.0.9",
|
|
77
|
+
"sass": "^1.86.0",
|
|
78
|
+
"unplugin-icons": "^0.19.3",
|
|
79
|
+
"vite": "^6.2.2"
|
|
80
|
+
},
|
|
81
|
+
"devDependencies": {
|
|
82
|
+
"@lit/localize-tools": "^0.8.0",
|
|
83
|
+
"@storybook/addon-essentials": "^8.6.7",
|
|
84
|
+
"@storybook/blocks": "^8.5.8",
|
|
85
|
+
"@storybook/web-components": "^8.5.8",
|
|
86
|
+
"@storybook/web-components-vite": "^8.6.7",
|
|
87
|
+
"cypress": "^14.2.0",
|
|
88
|
+
"cypress-ct-lit": "^1.0.0",
|
|
89
|
+
"lorem-ipsum": "^2.0.8",
|
|
90
|
+
"storybook": "^8.6.7"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
/// <reference types="unplugin-icons/types/raw" />
|
|
3
|
+
/// <reference types="unplugin-icons/types/web-components" />
|
|
4
|
+
|
|
5
|
+
import type { TemplateResult } from "lit";
|
|
6
|
+
|
|
7
|
+
interface PWAIcons {
|
|
8
|
+
src: string;
|
|
9
|
+
sizes: string;
|
|
10
|
+
type: string;
|
|
11
|
+
purpose: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface PWA {
|
|
15
|
+
dir: string;
|
|
16
|
+
icons: PWAIcons[];
|
|
17
|
+
start_url: string;
|
|
18
|
+
display: string;
|
|
19
|
+
orientation: string;
|
|
20
|
+
background_color: string;
|
|
21
|
+
theme_color: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface I18n {
|
|
25
|
+
lang: string;
|
|
26
|
+
force: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface ComponentParameters {
|
|
30
|
+
replacement?: string;
|
|
31
|
+
bindResources?: string;
|
|
32
|
+
bindUser?: string;
|
|
33
|
+
dataSrc?: string;
|
|
34
|
+
nestedField?: string;
|
|
35
|
+
authority?: string;
|
|
36
|
+
authorityName?: string;
|
|
37
|
+
noRender?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface OrbitComponent {
|
|
41
|
+
type?: string;
|
|
42
|
+
parameters: ComponentParameters;
|
|
43
|
+
route: string | false;
|
|
44
|
+
integration?: string[];
|
|
45
|
+
uniq?: string;
|
|
46
|
+
experimental?: string[];
|
|
47
|
+
routeAttributes?: {
|
|
48
|
+
"rdf-type": string;
|
|
49
|
+
"use-id": string;
|
|
50
|
+
};
|
|
51
|
+
defaultRoute?: boolean;
|
|
52
|
+
extensions?: OrbitComponent[];
|
|
53
|
+
attributes?: Record<string, any>;
|
|
54
|
+
instance?: Element;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface OrbitClient {
|
|
58
|
+
name: string;
|
|
59
|
+
logo: string;
|
|
60
|
+
server?: string;
|
|
61
|
+
css?: string[] | string | false;
|
|
62
|
+
description?: string;
|
|
63
|
+
favicon?: string;
|
|
64
|
+
defaultAvatar?: string;
|
|
65
|
+
i18n?: I18n;
|
|
66
|
+
pwa?: PWA;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface NpmPackage {
|
|
70
|
+
package: string;
|
|
71
|
+
version: string;
|
|
72
|
+
path: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface Orbit {
|
|
76
|
+
client: OrbitClient;
|
|
77
|
+
components: OrbitComponent[];
|
|
78
|
+
npm?: NpmPackage[];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface LiveOrbit extends Orbit {
|
|
82
|
+
componentSet: Set<string>;
|
|
83
|
+
federations: Record<string, any>;
|
|
84
|
+
getDefaultRoute: () => string;
|
|
85
|
+
getComponent: (type: string) => OrbitComponent | undefined;
|
|
86
|
+
getComponentFromRoute: (route: string) => OrbitComponent | undefined;
|
|
87
|
+
getRoute: (
|
|
88
|
+
type: string,
|
|
89
|
+
returnFirst?: boolean,
|
|
90
|
+
ignoreError?: boolean
|
|
91
|
+
) => string | false;
|
|
92
|
+
Swal: any;
|
|
93
|
+
defaultRoute: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
type Context = Record<string, string | { "@id": string }>;
|
|
97
|
+
type Permission = "add" | "delete" | "change" | "control" | "view" | string;
|
|
98
|
+
type DateTime = string;
|
|
99
|
+
|
|
100
|
+
interface LimitedResource {
|
|
101
|
+
"@id": string;
|
|
102
|
+
"@type"?: string | string[] | Promise<string | string[]>;
|
|
103
|
+
_originalResource?: Resource;
|
|
104
|
+
properties?: string[] | Promise<string[]>;
|
|
105
|
+
permissions?: Permission[];
|
|
106
|
+
clientContext?: Context | Promise<Context>;
|
|
107
|
+
serverContext?: Context | Promise<Context>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface Resource extends LimitedResource {
|
|
111
|
+
[key: string]: any;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
interface UnknownResource {
|
|
115
|
+
[key: string]: any;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
interface Container<T> extends Resource {
|
|
119
|
+
"ldp:contains": T[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
type ProxyValue<T> = T extends Array<infer U> ? U[] : Resource & T;
|
|
123
|
+
|
|
124
|
+
interface User extends Resource {
|
|
125
|
+
account?: Account;
|
|
126
|
+
first_name?: string;
|
|
127
|
+
last_name?: string;
|
|
128
|
+
name?: string;
|
|
129
|
+
username?: string;
|
|
130
|
+
email?: string;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
interface Account extends Resource {
|
|
134
|
+
picture?: string | null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
interface PropertiesPicker {
|
|
138
|
+
key: string;
|
|
139
|
+
value: string;
|
|
140
|
+
cast?: function;
|
|
141
|
+
expand?: boolean;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
type TemplateResultOrSymbol = TemplateResult | symbol;
|
|
145
|
+
|
|
146
|
+
export declare global {
|
|
147
|
+
interface Window {
|
|
148
|
+
orbit: LiveOrbit;
|
|
149
|
+
sibStore: { getData: ProxyValue<Resource | Container>; [key: string]: any };
|
|
150
|
+
sibRouter: { [key: string]: any };
|
|
151
|
+
}
|
|
152
|
+
interface Element {
|
|
153
|
+
currentRouteName: string;
|
|
154
|
+
}
|
|
155
|
+
interface Event {
|
|
156
|
+
[key: string]: any;
|
|
157
|
+
}
|
|
158
|
+
interface EventTarget {
|
|
159
|
+
[key: string]: any;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { css, html, nothing } from "lit";
|
|
2
|
+
import { customElement } from "lit/decorators.js";
|
|
3
|
+
import { Task } from "@lit/task";
|
|
4
|
+
|
|
5
|
+
import type { PropertiesPicker } from "@src/component";
|
|
6
|
+
|
|
7
|
+
import "@src/initializer";
|
|
8
|
+
import * as utils from "@helpers";
|
|
9
|
+
|
|
10
|
+
@customElement("solid-boilerplate")
|
|
11
|
+
export class SolidBoilerplate extends utils.OrbitComponent {
|
|
12
|
+
async _afterAttach() {
|
|
13
|
+
// Eg. https://api.server/some-keyword/1/ should trigger an update:
|
|
14
|
+
utils.setupCacheInvalidation(this, {
|
|
15
|
+
keywords: ["some-keyword", "for-invalidating", "cache"],
|
|
16
|
+
});
|
|
17
|
+
return Promise.resolve();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static styles = css`
|
|
21
|
+
div {
|
|
22
|
+
background-color: red;
|
|
23
|
+
position: absolute;
|
|
24
|
+
top: 0;
|
|
25
|
+
left: 0;
|
|
26
|
+
right: 0;
|
|
27
|
+
bottom: 0;
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
cherryPickedProperties: PropertiesPicker[] = [
|
|
32
|
+
{ key: "name", value: "name" },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
_getResource = new Task(this, {
|
|
36
|
+
task: async ([dataSrc]) => {
|
|
37
|
+
if (
|
|
38
|
+
!dataSrc ||
|
|
39
|
+
!this.orbit ||
|
|
40
|
+
(!this.noRouter &&
|
|
41
|
+
this.route &&
|
|
42
|
+
this.currentRoute &&
|
|
43
|
+
!this.route.startsWith(this.currentRoute))
|
|
44
|
+
)
|
|
45
|
+
return;
|
|
46
|
+
|
|
47
|
+
if (!this.hasCachedDatas || this.oldDataSrc !== dataSrc) {
|
|
48
|
+
if (!dataSrc) return;
|
|
49
|
+
this.datas = await this._getProxyValue(dataSrc);
|
|
50
|
+
this.hasCachedDatas = true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (this.oldDataSrc !== dataSrc) {
|
|
54
|
+
this.oldDataSrc = dataSrc;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return utils.sort(this.datas, "name", "asc");
|
|
58
|
+
},
|
|
59
|
+
args: () => [this.dataSrc, this.caching, this.currentRoute],
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
render() {
|
|
63
|
+
return (
|
|
64
|
+
this.gatekeeper() ||
|
|
65
|
+
this._getResource.render({
|
|
66
|
+
pending: () => html`<solid-loader></solid-loader>`,
|
|
67
|
+
complete: (datas) => {
|
|
68
|
+
if (!datas) {
|
|
69
|
+
return nothing;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return html`<div>
|
|
73
|
+
<sample-objects .objects=${datas}></sample-objects>
|
|
74
|
+
</div>`;
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { localized, msg, str } from "@lit/localize";
|
|
2
|
+
import { css, html, nothing, unsafeCSS } from "lit";
|
|
3
|
+
import { customElement, property } from "lit/decorators.js";
|
|
4
|
+
|
|
5
|
+
import "@src/initializer";
|
|
6
|
+
import { ComponentObjectHandler } from "@helpers";
|
|
7
|
+
|
|
8
|
+
import type { LimitedResource } from "@src/component";
|
|
9
|
+
|
|
10
|
+
import ComponentStyle from "@styles/component-sample.scss?inline";
|
|
11
|
+
|
|
12
|
+
export type ComponentProps = LimitedResource & {
|
|
13
|
+
name?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
@customElement("sample-object")
|
|
17
|
+
@localized()
|
|
18
|
+
export class SampleObject extends ComponentObjectHandler {
|
|
19
|
+
static styles = css`
|
|
20
|
+
${unsafeCSS(ComponentStyle)}
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
@property({ attribute: false, type: Object })
|
|
24
|
+
object: ComponentProps = { "@id": "" };
|
|
25
|
+
|
|
26
|
+
render() {
|
|
27
|
+
// Eg. reject object if its type is "some:Type"
|
|
28
|
+
if (this.isType("some:Type")) {
|
|
29
|
+
return nothing;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Eg. use localization to display object's name
|
|
33
|
+
return html`<li>
|
|
34
|
+
${msg(str`Sample object named: ${this.object.name}`)}
|
|
35
|
+
</li>`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { localized, msg } from "@lit/localize";
|
|
2
|
+
import { css, html, nothing, unsafeCSS } from "lit";
|
|
3
|
+
import { customElement, property } from "lit/decorators.js";
|
|
4
|
+
|
|
5
|
+
import "@src/initializer";
|
|
6
|
+
import { ComponentObjectsHandler } from "@helpers";
|
|
7
|
+
|
|
8
|
+
import type { LimitedResource } from "@src/component";
|
|
9
|
+
|
|
10
|
+
import ComponentStyle from "@styles/component-sample.scss?inline";
|
|
11
|
+
|
|
12
|
+
export type ComponentProps = LimitedResource & {
|
|
13
|
+
name?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
@customElement("sample-objects")
|
|
17
|
+
@localized()
|
|
18
|
+
export class SampleObjects extends ComponentObjectsHandler {
|
|
19
|
+
static styles = css`
|
|
20
|
+
${unsafeCSS(ComponentStyle)}
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
@property({ attribute: false, type: Object })
|
|
24
|
+
objects: ComponentProps[] = [];
|
|
25
|
+
|
|
26
|
+
render() {
|
|
27
|
+
// Eg. reject if any object has a type "some:Type"
|
|
28
|
+
if (this.hasType("some:Type")) {
|
|
29
|
+
return nothing;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Eg. display a sample-object for each object
|
|
33
|
+
return html`${msg("Here are all of our objects:")}<br />
|
|
34
|
+
<ul>
|
|
35
|
+
${this.objects.map(
|
|
36
|
+
(obj) => html`<sample-object .object=${obj}></sample-object>`
|
|
37
|
+
)}
|
|
38
|
+
</ul>`;
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/context.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
LimitedResource,
|
|
3
|
+
Resource,
|
|
4
|
+
TemplateResultOrSymbol,
|
|
5
|
+
} from "@src/component";
|
|
6
|
+
import { LitElement, nothing } from "lit";
|
|
7
|
+
|
|
8
|
+
import * as rdf from "@src/initializer";
|
|
9
|
+
|
|
10
|
+
const rdfs = Object.values(rdf);
|
|
11
|
+
|
|
12
|
+
export class ComponentObjectHandler extends LitElement {
|
|
13
|
+
object?: LimitedResource = {
|
|
14
|
+
"@id": ""
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
isType = (type: string, obj: Resource = (this.object as Resource)) => {
|
|
18
|
+
const typeValue = obj["@type"];
|
|
19
|
+
if (Array.isArray(typeValue)) {
|
|
20
|
+
return typeValue.includes(type);
|
|
21
|
+
}
|
|
22
|
+
if (typeof typeValue === "string") {
|
|
23
|
+
return typeValue === type;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
private getNestedProperty(path: string, obj: Resource = (this.object as Resource)): any {
|
|
29
|
+
return path.split(".").reduce((subObj: any, key) => {
|
|
30
|
+
if (subObj === undefined) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const arrayMatch = key.match(/(.*)\[(.*)\]/);
|
|
35
|
+
if (arrayMatch) {
|
|
36
|
+
const baseKey = arrayMatch[1];
|
|
37
|
+
const index = arrayMatch[2];
|
|
38
|
+
|
|
39
|
+
const array = subObj[baseKey];
|
|
40
|
+
|
|
41
|
+
if (!Array.isArray(array)) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (index === "") {
|
|
46
|
+
if (array.length > 0) {
|
|
47
|
+
return array;
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const numericIndex = Number.parseInt(index, 10);
|
|
53
|
+
if (
|
|
54
|
+
Number.isNaN(numericIndex) ||
|
|
55
|
+
numericIndex < 0 ||
|
|
56
|
+
numericIndex >= array.length
|
|
57
|
+
) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return subObj[baseKey][numericIndex];
|
|
62
|
+
}
|
|
63
|
+
return subObj && subObj[key] !== "undefined" ? subObj[key] : undefined;
|
|
64
|
+
}, obj);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
renderTemplateWhenWith(
|
|
68
|
+
requiredProperties: (string | string[])[],
|
|
69
|
+
template: () => TemplateResultOrSymbol,
|
|
70
|
+
obj: Resource = (this.object as Resource)
|
|
71
|
+
): TemplateResultOrSymbol {
|
|
72
|
+
const tester = (
|
|
73
|
+
property: string | string[],
|
|
74
|
+
cb: (some: string) => boolean
|
|
75
|
+
) =>
|
|
76
|
+
Array.isArray(property)
|
|
77
|
+
? property.some((subProp) => cb(subProp))
|
|
78
|
+
: cb(property);
|
|
79
|
+
|
|
80
|
+
const typeProperties = requiredProperties.filter((property) =>
|
|
81
|
+
tester(property, (p) => rdfs.includes(p))
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const keyProperties = requiredProperties.filter((property) =>
|
|
85
|
+
tester(property, (p) => !rdfs.includes(p))
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
if (
|
|
89
|
+
keyProperties.every((property) =>
|
|
90
|
+
tester(property, (p) => this.getNestedProperty(p, obj))
|
|
91
|
+
) &&
|
|
92
|
+
typeProperties.every((property) =>
|
|
93
|
+
tester(property, (p) => this.isType(p, obj))
|
|
94
|
+
)
|
|
95
|
+
) {
|
|
96
|
+
return template.call(this);
|
|
97
|
+
}
|
|
98
|
+
return nothing;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Resource, TemplateResultOrSymbol } from "@src/component";
|
|
2
|
+
import { LitElement, nothing } from "lit";
|
|
3
|
+
|
|
4
|
+
import * as rdf from "@src/initializer";
|
|
5
|
+
import { property } from "lit/decorators.js";
|
|
6
|
+
|
|
7
|
+
const rdfs = Object.values(rdf);
|
|
8
|
+
|
|
9
|
+
export class ComponentObjectsHandler extends LitElement {
|
|
10
|
+
@property({ attribute: false })
|
|
11
|
+
objects?: Resource[] = [];
|
|
12
|
+
|
|
13
|
+
hasType = (type: string, objs: Resource[] = this.objects as Resource[]) => {
|
|
14
|
+
const typeValue = new Set(objs.flatMap((o) => o["@type"]));
|
|
15
|
+
return typeValue.has(type);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
renderTemplateWhenWith(
|
|
19
|
+
requiredProperties: (string | string[])[],
|
|
20
|
+
template: () => TemplateResultOrSymbol,
|
|
21
|
+
objs: Resource[] = this.objects as Resource[]
|
|
22
|
+
): TemplateResultOrSymbol {
|
|
23
|
+
const tester = (
|
|
24
|
+
property: string | string[],
|
|
25
|
+
cb: (some: string) => boolean
|
|
26
|
+
) =>
|
|
27
|
+
Array.isArray(property)
|
|
28
|
+
? property.some((subProp) => cb(subProp))
|
|
29
|
+
: cb(property);
|
|
30
|
+
|
|
31
|
+
const typeProperties = requiredProperties.filter((property) =>
|
|
32
|
+
tester(property, (p) => rdfs.includes(p))
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (
|
|
36
|
+
typeProperties.every((property) =>
|
|
37
|
+
tester(property, (p) => this.hasType(p, objs))
|
|
38
|
+
)
|
|
39
|
+
) {
|
|
40
|
+
return template.call(this);
|
|
41
|
+
}
|
|
42
|
+
return nothing;
|
|
43
|
+
}
|
|
44
|
+
}
|