@spectric/ui 0.0.4
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 +28 -0
- package/.nvmrc +1 -0
- package/.storybook/analyze.sh +4 -0
- package/.storybook/main.ts +55 -0
- package/.storybook/preview.ts +42 -0
- package/.vscode/extensions.json +5 -0
- package/.vscode/settings.json +41 -0
- package/README.MD +50 -0
- package/html-include.png +0 -0
- package/package.json +33 -0
- package/src/classes/BitArray.ts +48 -0
- package/src/classes/DisposibleElement.ts +108 -0
- package/src/components/Banner.ts +102 -0
- package/src/components/Bitdisplay.ts +383 -0
- package/src/components/Button.ts +121 -0
- package/src/components/Header.ts +125 -0
- package/src/components/Page.ts +157 -0
- package/src/components/Panel.ts +56 -0
- package/src/components/ThemeProvider.ts +251 -0
- package/src/components/button.css.ts +160 -0
- package/src/components/configurations/classifications.ts +194 -0
- package/src/components/dialog/dialog.css.ts +50 -0
- package/src/components/dialog/dialog.ts +163 -0
- package/src/components/dialog/index.ts +1 -0
- package/src/components/header.css.ts +38 -0
- package/src/components/index.ts +10 -0
- package/src/components/input.css +75 -0
- package/src/components/input.ts +312 -0
- package/src/components/page.css.ts +158 -0
- package/src/components/panel.css.ts +44 -0
- package/src/components/query_bar/QueryBar.css +48 -0
- package/src/components/query_bar/QueryBar.ts +378 -0
- package/src/components/query_bar/index.ts +2 -0
- package/src/components/query_bar/querylanguage/kuery/ast/_generated_/kuery.js +3186 -0
- package/src/components/query_bar/querylanguage/kuery/ast/ast.ts +113 -0
- package/src/components/query_bar/querylanguage/kuery/ast/index.ts +31 -0
- package/src/components/query_bar/querylanguage/kuery/ast/kuery.peg +417 -0
- package/src/components/query_bar/querylanguage/kuery/functions/and.ts +55 -0
- package/src/components/query_bar/querylanguage/kuery/functions/exists.ts +62 -0
- package/src/components/query_bar/querylanguage/kuery/functions/index.ts +47 -0
- package/src/components/query_bar/querylanguage/kuery/functions/is.ts +211 -0
- package/src/components/query_bar/querylanguage/kuery/functions/nested.ts +63 -0
- package/src/components/query_bar/querylanguage/kuery/functions/not.ts +53 -0
- package/src/components/query_bar/querylanguage/kuery/functions/or.ts +56 -0
- package/src/components/query_bar/querylanguage/kuery/functions/range.ts +163 -0
- package/src/components/query_bar/querylanguage/kuery/functions/utils/get_fields.ts +49 -0
- package/src/components/query_bar/querylanguage/kuery/functions/utils/get_full_field_name_node.ts +87 -0
- package/src/components/query_bar/querylanguage/kuery/index.ts +38 -0
- package/src/components/query_bar/querylanguage/kuery/kuery_syntax_error.ts +76 -0
- package/src/components/query_bar/querylanguage/kuery/node_types/function.ts +75 -0
- package/src/components/query_bar/querylanguage/kuery/node_types/index.ts +46 -0
- package/src/components/query_bar/querylanguage/kuery/node_types/literal.ts +42 -0
- package/src/components/query_bar/querylanguage/kuery/node_types/named_arg.ts +47 -0
- package/src/components/query_bar/querylanguage/kuery/node_types/types.ts +108 -0
- package/src/components/query_bar/querylanguage/kuery/node_types/wildcard.ts +80 -0
- package/src/components/query_bar/querylanguage/kuery/types.ts +52 -0
- package/src/components/query_bar/querylanguage/outputTypes/toCQL.ts +122 -0
- package/src/components/query_bar/querylanguage/outputTypes/toMongo.ts +103 -0
- package/src/components/query_bar/querylanguage/utils.ts +35 -0
- package/src/components/query_bar/types.ts +59 -0
- package/src/components/splitview/index.ts +1 -0
- package/src/components/splitview/splitview.css.ts +66 -0
- package/src/components/splitview/splitview.ts +183 -0
- package/src/components/types.ts +35 -0
- package/src/index.ts +1 -0
- package/src/stories/Banner.stories.ts +46 -0
- package/src/stories/BitDisplay.stories.ts +68 -0
- package/src/stories/Button.stories.ts +138 -0
- package/src/stories/Header.stories.ts +55 -0
- package/src/stories/Page.stories.ts +108 -0
- package/src/stories/QueryBar.stories.ts +63 -0
- package/src/stories/Splitview.stories.ts +52 -0
- package/src/stories/fixtures/Bits.ts +15 -0
- package/src/stories/fixtures/ExampleContent.ts +102 -0
- package/src/stories/fixtures/data.ts +30 -0
- package/src/stories/fixtures/lorumipsum.ts +19 -0
- package/src/stories/input.stories.ts +77 -0
- package/src/stories/tsconfig.json +35 -0
- package/src/utils/debounce.ts +18 -0
- package/src/utils/spread.ts +71 -0
- package/src/vite-env.d.ts +1 -0
- package/test/__init__.py +9 -0
- package/test/elastic.py +9 -0
- package/test/interface.py +16 -0
- package/tsconfig.json +29 -0
- package/vite.config.js +34 -0
- package/vue-example.png +0 -0
- package/vue-include.png +0 -0
package/.gitlab-ci.yml
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
stages:
|
|
2
|
+
- publish
|
|
3
|
+
- pages
|
|
4
|
+
|
|
5
|
+
publish:
|
|
6
|
+
image: node:20.15.1
|
|
7
|
+
stage: publish
|
|
8
|
+
only:
|
|
9
|
+
- tags
|
|
10
|
+
script:
|
|
11
|
+
- npm install
|
|
12
|
+
- echo '//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}'>.npmrc
|
|
13
|
+
- echo '//${CI_SERVER_HOST}/api/v4/groups/${CI_PROJECT_NAMESPACE_ID}/-/packages/npm/:_authToken=<token>'>>.npmrc
|
|
14
|
+
- echo '//${CI_SERVER_HOST}/api/v4/packages/npm/:_authToken=${CI_JOB_TOKEN}'>>.npmrc
|
|
15
|
+
- npm run build
|
|
16
|
+
- npm publish
|
|
17
|
+
|
|
18
|
+
pages:
|
|
19
|
+
image: node:20.15.1
|
|
20
|
+
stage: pages
|
|
21
|
+
only:
|
|
22
|
+
- tags
|
|
23
|
+
script:
|
|
24
|
+
- npm install
|
|
25
|
+
- npm run storybook:build
|
|
26
|
+
artifacts:
|
|
27
|
+
paths:
|
|
28
|
+
- public
|
package/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
20.15.1
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
npx web-component-analyzer src --outFiles .storybook/build/custom-elements-next.json
|
|
3
|
+
cmp -s .storybook/build/custom-elements.json .storybook/build/custom-elements-next.json || mv .storybook/build/custom-elements-next.json .storybook/build/custom-elements.json
|
|
4
|
+
npx web-component-analyzer src -f vscode --outFiles dist/vscode-custom-elements.json
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { StorybookConfig } from "@storybook/web-components-vite";
|
|
2
|
+
import run from "vite-plugin-run";
|
|
3
|
+
import execa from 'execa';
|
|
4
|
+
import { version } from '../package.json';
|
|
5
|
+
const config: StorybookConfig = {
|
|
6
|
+
managerHead: (headHtmlContent) => {
|
|
7
|
+
console.log(headHtmlContent)
|
|
8
|
+
const style = `
|
|
9
|
+
<style>
|
|
10
|
+
.sidebar-header {
|
|
11
|
+
margin-bottom: 36px;
|
|
12
|
+
position: relative;
|
|
13
|
+
}
|
|
14
|
+
.sidebar-header div:first-of-type {
|
|
15
|
+
display: none;
|
|
16
|
+
}
|
|
17
|
+
.sidebar-header::before {
|
|
18
|
+
content: 'Spectric UI ${version}';
|
|
19
|
+
font-size: 20px;
|
|
20
|
+
color: #5C6870;
|
|
21
|
+
font-weight: normal;
|
|
22
|
+
}
|
|
23
|
+
</style>
|
|
24
|
+
`;
|
|
25
|
+
return `${headHtmlContent}\n${style}`;
|
|
26
|
+
},
|
|
27
|
+
stories: [{
|
|
28
|
+
// 👇 Sets the directory containing your stories
|
|
29
|
+
directory: '../src/stories/',
|
|
30
|
+
// 👇 Storybook will load all files that match this glob
|
|
31
|
+
files: '*.stories.*',
|
|
32
|
+
// 👇 Used when generating automatic titles for your stories.
|
|
33
|
+
titlePrefix: 'Spectric UI Components',
|
|
34
|
+
}],
|
|
35
|
+
addons: ["@storybook/addon-essentials", "@chromatic-com/storybook"],
|
|
36
|
+
framework: {
|
|
37
|
+
name: "@storybook/web-components-vite",
|
|
38
|
+
options: {
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
async viteFinal(config, options) {
|
|
42
|
+
//analyze webcomponent and if the json output is different move it into place this will cause storybook to reload the fresh info
|
|
43
|
+
config.plugins?.push(
|
|
44
|
+
run(
|
|
45
|
+
{
|
|
46
|
+
silent: false,
|
|
47
|
+
name: 'Create webcomponent json',
|
|
48
|
+
run: ['.storybook/analyze.sh'],
|
|
49
|
+
pattern: ['**/*.ts'],
|
|
50
|
+
},
|
|
51
|
+
))
|
|
52
|
+
return config;
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
export default config;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Preview } from "@storybook/web-components";
|
|
2
|
+
import { addons } from '@storybook/manager-api';
|
|
3
|
+
import { setCustomElementsManifest } from '@storybook/web-components';
|
|
4
|
+
import customElements from './build/custom-elements.json';
|
|
5
|
+
customElements.tags.forEach(tag => {
|
|
6
|
+
if (tag.properties) {
|
|
7
|
+
let stylesindex = tag.properties.findIndex(e => e.name == "styles")
|
|
8
|
+
if (stylesindex != -1) {
|
|
9
|
+
tag.properties.splice(stylesindex, 1)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
})
|
|
13
|
+
setCustomElementsManifest(customElements);
|
|
14
|
+
|
|
15
|
+
import { create } from '@storybook/theming/create';
|
|
16
|
+
import { version } from '../package.json';
|
|
17
|
+
|
|
18
|
+
const theme = create({
|
|
19
|
+
base: "light",
|
|
20
|
+
// Typography
|
|
21
|
+
fontBase: "'Helvetica Neue', Arial, sans-serif",
|
|
22
|
+
fontCode: "Menlo, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', Courier, monospace",
|
|
23
|
+
brandTitle: `Spectric UI ${version}`,
|
|
24
|
+
brandImage: "https://static.wixstatic.com/media/bb8de2_d075320863814eeb9c954fcc57ce2822%7Emv2.png/v1/fill/w_192%2Ch_192%2Clg_1%2Cusm_0.66_1.00_0.01/bb8de2_d075320863814eeb9c954fcc57ce2822%7Emv2.png",
|
|
25
|
+
brandUrl: 'https://gitlab.spectric.com/web/spectric-ui',
|
|
26
|
+
});
|
|
27
|
+
addons.setConfig({
|
|
28
|
+
theme
|
|
29
|
+
});
|
|
30
|
+
const preview: Preview = {
|
|
31
|
+
parameters: {
|
|
32
|
+
docs: { canvas: { layout: "padded" }, theme: theme },
|
|
33
|
+
controls: {
|
|
34
|
+
matchers: {
|
|
35
|
+
color: /(background|color)$/i,
|
|
36
|
+
date: /Date$/i,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default preview;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"editor.formatOnSave": true,
|
|
3
|
+
"javascript.format.enable": true,
|
|
4
|
+
"typescript.format.enable": true,
|
|
5
|
+
"javascript.format.insertSpaceAfterCommaDelimiter": true,
|
|
6
|
+
"javascript.format.insertSpaceAfterConstructor": false,
|
|
7
|
+
"javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": true,
|
|
8
|
+
"javascript.format.insertSpaceAfterKeywordsInControlFlowStatements": true,
|
|
9
|
+
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": true,
|
|
10
|
+
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false,
|
|
11
|
+
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true,
|
|
12
|
+
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false,
|
|
13
|
+
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false,
|
|
14
|
+
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false,
|
|
15
|
+
"javascript.format.insertSpaceAfterSemicolonInForStatements": true,
|
|
16
|
+
"javascript.format.insertSpaceBeforeAndAfterBinaryOperators": true,
|
|
17
|
+
"javascript.format.insertSpaceBeforeFunctionParenthesis": false,
|
|
18
|
+
"javascript.format.placeOpenBraceOnNewLineForControlBlocks": false,
|
|
19
|
+
"javascript.format.placeOpenBraceOnNewLineForFunctions": false,
|
|
20
|
+
"javascript.format.semicolons": "ignore",
|
|
21
|
+
"typescript.format.indentSwitchCase": true,
|
|
22
|
+
"typescript.format.insertSpaceAfterCommaDelimiter": true,
|
|
23
|
+
"typescript.format.insertSpaceAfterConstructor": false,
|
|
24
|
+
"typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": true,
|
|
25
|
+
"typescript.format.insertSpaceAfterKeywordsInControlFlowStatements": true,
|
|
26
|
+
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": true,
|
|
27
|
+
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false,
|
|
28
|
+
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true,
|
|
29
|
+
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false,
|
|
30
|
+
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false,
|
|
31
|
+
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false,
|
|
32
|
+
"typescript.format.insertSpaceAfterSemicolonInForStatements": true,
|
|
33
|
+
"typescript.format.insertSpaceAfterTypeAssertion": false,
|
|
34
|
+
"typescript.format.insertSpaceBeforeAndAfterBinaryOperators": true,
|
|
35
|
+
"typescript.format.insertSpaceBeforeFunctionParenthesis": false,
|
|
36
|
+
"typescript.format.placeOpenBraceOnNewLineForControlBlocks": false,
|
|
37
|
+
"typescript.format.placeOpenBraceOnNewLineForFunctions": false,
|
|
38
|
+
"typescript.format.semicolons": "ignore",
|
|
39
|
+
"typescript.tsserver.enableTracing": false,
|
|
40
|
+
"typescript.tsserver.log": "off"
|
|
41
|
+
}
|
package/README.MD
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Component Examples and playground
|
|
2
|
+
https://pages.spectric.com/web/spectric-ui/?path=/docs/spectric-ui-components-ui-page--docs
|
|
3
|
+
|
|
4
|
+
# Developing
|
|
5
|
+
```
|
|
6
|
+
nvm use
|
|
7
|
+
npm start
|
|
8
|
+
```
|
|
9
|
+
# Publishing
|
|
10
|
+
|
|
11
|
+
To publish a new version run
|
|
12
|
+
```
|
|
13
|
+
npm version patch
|
|
14
|
+
git push --follow-tags
|
|
15
|
+
```
|
|
16
|
+
This will trigger a pipeline to run and build the source and publish to our internal gitlab NPM
|
|
17
|
+
|
|
18
|
+
# Installing In your project
|
|
19
|
+
Internally (for now) we use gitlab as the package registry. To configure npm to use gitlab for `@spectric` packages follow the one time steps below
|
|
20
|
+
1. Create an access token for npm [Personal Access Token](https://gitlab.spectric.com/-/user_settings/personal_access_tokens)
|
|
21
|
+
- ensure it has api access
|
|
22
|
+
2. Point npm to install `@spectric` packages from gitlab
|
|
23
|
+
- run `npm config set -- @spectric:registry=https://gitlab.spectric.com/api/v4/groups/585/-/packages/npm/`
|
|
24
|
+
3. Have npm use the access token created in 1. to authenticate
|
|
25
|
+
- run `npm config set -- //gitlab.spectric.com/api/v4/groups/585/-/packages/npm/:_authToken <token>`
|
|
26
|
+
|
|
27
|
+
After you have setup npm witht he steps above you can install this package normally.
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
npm i @spectric/ui
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
# Javascript/typescript integration
|
|
34
|
+
The types files produced when building seemlessly integrate the custom elements into javascript giving full type hinting
|
|
35
|
+
|
|
36
|
+
# HTML integration
|
|
37
|
+
Add the dist/custom-element.json to the html.languge settings
|
|
38
|
+
https://code.visualstudio.com/docs/languages/html#_html-custom-data
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
# VUE Integration
|
|
42
|
+
Complete steps to include custom elements in the HTML language server
|
|
43
|
+
then
|
|
44
|
+
Add the HTML language server in the @ext:Vue.volar extention
|
|
45
|
+

|
|
46
|
+
Once setup hovering over spectric elements will provide documentation
|
|
47
|
+

|
|
48
|
+
|
|
49
|
+
# Python Jinja
|
|
50
|
+
Same as HTML Integration
|
package/html-include.png
ADDED
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@spectric/ui",
|
|
3
|
+
"version": "0.0.4",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.es.js",
|
|
6
|
+
"module": "./dist/index.es.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc && vite build",
|
|
10
|
+
"start": "storybook dev -p 6006",
|
|
11
|
+
"storybook:build": "web-component-analyzer src --outFiles .storybook/build/custom-elements.json && storybook build --output-dir public",
|
|
12
|
+
"release": "npm version patch && git push --follow-tags"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"lit": "^3.2.1"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@chromatic-com/storybook": "^3.2.2",
|
|
19
|
+
"@storybook/addon-essentials": "^8.4.6",
|
|
20
|
+
"@storybook/blocks": "^8.4.6",
|
|
21
|
+
"@storybook/client-api": "^7.6.17",
|
|
22
|
+
"@storybook/test": "^8.4.6",
|
|
23
|
+
"@storybook/web-components": "^8.4.6",
|
|
24
|
+
"@storybook/web-components-vite": "^8.4.6",
|
|
25
|
+
"@types/react": "^18.3.12",
|
|
26
|
+
"storybook": "^8.4.6",
|
|
27
|
+
"typescript": "~5.6.2",
|
|
28
|
+
"vite": "^5.4.10",
|
|
29
|
+
"vite-plugin-dts": "^4.3.0",
|
|
30
|
+
"vite-plugin-run": "^0.6.1",
|
|
31
|
+
"web-component-analyzer": "^2.0.0"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export const BitArray = class BitArray {
|
|
2
|
+
buffer: ArrayBuffer;
|
|
3
|
+
u8: Uint8Array;
|
|
4
|
+
constructor(buf: ArrayBuffer) {
|
|
5
|
+
this.buffer = buf;
|
|
6
|
+
this.u8 = new Uint8Array(buf);
|
|
7
|
+
return new Proxy(this, {
|
|
8
|
+
get(obj: any, prop) {
|
|
9
|
+
if (!obj[prop]) {
|
|
10
|
+
return obj.getBit(prop);
|
|
11
|
+
} else {
|
|
12
|
+
return obj[prop];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
getBit(idx: number) {
|
|
18
|
+
var v = this.u8[idx >> 3];
|
|
19
|
+
var off = idx & 0x7;
|
|
20
|
+
return (v >> (7 - off)) & 1;
|
|
21
|
+
}
|
|
22
|
+
setBit(idx: number, val: any) {
|
|
23
|
+
var off = idx & 0x7;
|
|
24
|
+
if (val) {
|
|
25
|
+
this.u8[idx >> 3] |= 0x80 >> off;
|
|
26
|
+
} else {
|
|
27
|
+
this.u8[idx >> 3] &= ~(0x80 >> off);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
get length() {
|
|
31
|
+
return this.u8.byteLength * 8;
|
|
32
|
+
}
|
|
33
|
+
set(array: string | any[], start: number) {
|
|
34
|
+
for (let i = start || 0, j = 0, len = array.length; j < len; i++, j++) {
|
|
35
|
+
this.setBit(i, array[j]);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
subarray(start: number, stop: number) {
|
|
39
|
+
let sub = [];
|
|
40
|
+
start = start || 0;
|
|
41
|
+
stop = stop || this.length;
|
|
42
|
+
stop = stop > this.length ? this.length : stop;
|
|
43
|
+
for (let i = start; i < stop; i++) {
|
|
44
|
+
sub.push(this.getBit(i));
|
|
45
|
+
}
|
|
46
|
+
return sub;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { LitElement } from "lit-element/lit-element.js";
|
|
2
|
+
|
|
3
|
+
export interface IDisposable {
|
|
4
|
+
dispose(): void;
|
|
5
|
+
}
|
|
6
|
+
class DomListener implements IDisposable {
|
|
7
|
+
|
|
8
|
+
private _handler?: (e: any) => void;
|
|
9
|
+
private _node?: EventTarget;
|
|
10
|
+
private __target?: EventTarget | Promise<EventTarget>
|
|
11
|
+
private readonly _type: string;
|
|
12
|
+
private readonly _options: boolean | AddEventListenerOptions;
|
|
13
|
+
|
|
14
|
+
constructor(node: EventTarget | Promise<EventTarget>, type: string, handler: (e: any) => void, options?: boolean | AddEventListenerOptions) {
|
|
15
|
+
this.__target = node
|
|
16
|
+
this._handler = handler;
|
|
17
|
+
this._type = type;
|
|
18
|
+
this._handler = handler;
|
|
19
|
+
this._options = (options || false);
|
|
20
|
+
if (node instanceof Promise) {
|
|
21
|
+
node.then(targetNode => {
|
|
22
|
+
if (!this._handler) {
|
|
23
|
+
//Already disposed
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
this._node = targetNode
|
|
27
|
+
this._node.addEventListener(this._type, this._handler, this._options);
|
|
28
|
+
})
|
|
29
|
+
} else {
|
|
30
|
+
this._node = node
|
|
31
|
+
this._node.addEventListener(this._type, this._handler, this._options);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
dispose(): void {
|
|
36
|
+
if (!this._handler) {
|
|
37
|
+
// Already disposed
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (this._node) {
|
|
41
|
+
console.log(`removing event ${this._type} from `, this._node, this.__target instanceof Promise)
|
|
42
|
+
this._node.removeEventListener(this._type, this._handler, this._options);
|
|
43
|
+
}
|
|
44
|
+
// Prevent leakers from holding on to the dom or handler func
|
|
45
|
+
this.__target = undefined;
|
|
46
|
+
this._node = undefined;
|
|
47
|
+
this._handler = undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export class DisposableElement extends LitElement {
|
|
51
|
+
private readonly _disposables = new Set<IDisposable>();
|
|
52
|
+
private _isDisposed = false;
|
|
53
|
+
private _disposableListeners: { target: HTMLElement | Promise<HTMLElement>, event: string, handler: any }[] = []
|
|
54
|
+
private _connected: boolean = false;
|
|
55
|
+
/**
|
|
56
|
+
* Creates listeners on a target that will automatically get cleaned up when the element is removed from the DOM. This prevents memory leaks.
|
|
57
|
+
* @param target The element| promise<element> we plan to attach the listener to
|
|
58
|
+
* @param event The event name
|
|
59
|
+
* @param handler The event handler
|
|
60
|
+
*/
|
|
61
|
+
public addDisposableListener<K extends keyof GlobalEventHandlersEventMap>(target: HTMLElement | Promise<HTMLElement>, event: K, handler: (event: GlobalEventHandlersEventMap[K]) => void): void
|
|
62
|
+
public addDisposableListener<K extends keyof SpectricGlobalEvents>(target: HTMLElement | Promise<HTMLElement>, event: K, handler: SpectricGlobalEvents[K]): void
|
|
63
|
+
public addDisposableListener(target: HTMLElement | Promise<HTMLElement>, event: string, handler: any): void {
|
|
64
|
+
let exists = this._disposableListeners.find(d => d.event === event && d.target === target && d.handler === handler)
|
|
65
|
+
if (exists) {
|
|
66
|
+
console.warn("Event handler already exists best practice is to add the this in the constructor")
|
|
67
|
+
return //Event handler has already been added, maybe they added it in a callback
|
|
68
|
+
}
|
|
69
|
+
this._disposableListeners.push({ target, event, handler })
|
|
70
|
+
if (this._connected) {
|
|
71
|
+
this.registerDisposable(new DomListener(target, event, handler))
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
public registerDisposable<T extends IDisposable>(o: T): T {
|
|
75
|
+
if (!o) {
|
|
76
|
+
return o;
|
|
77
|
+
}
|
|
78
|
+
if ((o as unknown) === this) {
|
|
79
|
+
throw new Error('Cannot register a disposable on itself!');
|
|
80
|
+
}
|
|
81
|
+
if (this._isDisposed) {
|
|
82
|
+
console.warn(new Error('Trying to add a disposable to something that has already been disposed of. The added object will be leaked!').stack);
|
|
83
|
+
} else {
|
|
84
|
+
this._disposables.add(o);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return o;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
connectedCallback(): void {
|
|
91
|
+
super.connectedCallback();
|
|
92
|
+
this._connected = true
|
|
93
|
+
this._isDisposed = false
|
|
94
|
+
this._disposableListeners.forEach(({ target, event, handler }) => {
|
|
95
|
+
this.registerDisposable(new DomListener(target, event, handler))
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
disconnectedCallback(): void {
|
|
100
|
+
super.disconnectedCallback();
|
|
101
|
+
this._connected = false
|
|
102
|
+
this._disposables.forEach(disposable => {
|
|
103
|
+
disposable.dispose()
|
|
104
|
+
})
|
|
105
|
+
this._isDisposed = true;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { html, LitElement } from 'lit';
|
|
2
|
+
import { StyleInfo, styleMap } from 'lit/directives/style-map.js';
|
|
3
|
+
import "./Button"
|
|
4
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
5
|
+
import { HTMLElementTagWithEvents, ReactElementWithPropsAndEvents } from './types';
|
|
6
|
+
|
|
7
|
+
export interface BannerProps {
|
|
8
|
+
/**What is returned in the event details when a banner is dismissed */
|
|
9
|
+
bannerId?: any,
|
|
10
|
+
/** Banner Text to display */
|
|
11
|
+
text?: string;
|
|
12
|
+
/** What background color to use */
|
|
13
|
+
headerStyle?: StyleInfo;
|
|
14
|
+
/** Can be dismissed */
|
|
15
|
+
dismissable?: boolean;
|
|
16
|
+
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
const DEFAULT_STYLE: StyleInfo = {
|
|
22
|
+
display: "flex",
|
|
23
|
+
alignItems: "center",
|
|
24
|
+
backgroundColor: "black",
|
|
25
|
+
color: "white",
|
|
26
|
+
textAlign: "center"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @slot text - Banner Text content
|
|
31
|
+
*/
|
|
32
|
+
@customElement('spectric-banner')
|
|
33
|
+
export class SpectricBanner extends LitElement implements BannerProps {
|
|
34
|
+
@property({ type: Boolean, reflect: true })
|
|
35
|
+
dismissable: boolean = false;
|
|
36
|
+
//static styles?: CSSResultGroup | undefined = style;
|
|
37
|
+
@property({ type: String, reflect: true })
|
|
38
|
+
text?: string = "";
|
|
39
|
+
@property({ type: String, reflect: true })
|
|
40
|
+
bannerId?: string = "";
|
|
41
|
+
@property({ type: Object })
|
|
42
|
+
headerStyle?: StyleInfo = {};
|
|
43
|
+
|
|
44
|
+
@property({ state: true, type: Boolean, attribute: false })
|
|
45
|
+
private _dismissed: boolean = false;
|
|
46
|
+
|
|
47
|
+
private onDismiss = (e: PointerEvent) => {
|
|
48
|
+
e.preventDefault()
|
|
49
|
+
e.stopPropagation()
|
|
50
|
+
const options = {
|
|
51
|
+
bubbles: true,
|
|
52
|
+
composed: true,
|
|
53
|
+
};
|
|
54
|
+
this._dismissed = true;
|
|
55
|
+
let { bannerId, text, headerStyle, dismissable }: BannerProps = this
|
|
56
|
+
this.dispatchEvent(new CustomEvent<BannerProps>('bannerDismissed', {
|
|
57
|
+
detail: { bannerId, text, headerStyle, dismissable },
|
|
58
|
+
...options
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
protected render(): unknown {
|
|
62
|
+
if (this._dismissed) {
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
return html`
|
|
66
|
+
<header style=${styleMap({ ...DEFAULT_STYLE, ...this.headerStyle })}>
|
|
67
|
+
<div style="flex-grow:1"><slot name="text">${this.text}</slot><slot></slot></div>
|
|
68
|
+
${this.dismissable ? html`<spectric-button size="small" @click=${this.onDismiss}>X</spectric-button>` : null}
|
|
69
|
+
</header>
|
|
70
|
+
`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface BannerEventMap {
|
|
75
|
+
'bannerDismissed': (event: CustomEvent<BannerProps>) => void
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
declare global {
|
|
79
|
+
|
|
80
|
+
interface HTMLElementTagNameMap {
|
|
81
|
+
"spectric-banner": HTMLElementTagWithEvents<SpectricBanner, BannerEventMap>
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
namespace JSX {
|
|
85
|
+
interface IntrinsicElements {
|
|
86
|
+
/**
|
|
87
|
+
* {@link SpectricBanner}
|
|
88
|
+
*/
|
|
89
|
+
"spectric-banner": ReactElementWithPropsAndEvents<SpectricBanner, BannerProps, BannerEventMap>;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
namespace React {
|
|
93
|
+
namespace JSX {
|
|
94
|
+
interface IntrinsicElements {
|
|
95
|
+
/**
|
|
96
|
+
* {@link SpectricBanner}
|
|
97
|
+
*/
|
|
98
|
+
"spectric-banner": ReactElementWithPropsAndEvents<SpectricBanner, BannerProps, BannerEventMap>;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|