tosijs-ui 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +165 -0
- package/dist/ab-test.d.ts +14 -0
- package/dist/ab-test.js +116 -0
- package/dist/babylon-3d.d.ts +53 -0
- package/dist/babylon-3d.js +292 -0
- package/dist/bodymovin-player.d.ts +32 -0
- package/dist/bodymovin-player.js +172 -0
- package/dist/bp-loader.d.ts +1 -0
- package/dist/bp-loader.js +26 -0
- package/dist/carousel.d.ts +113 -0
- package/dist/carousel.js +308 -0
- package/dist/code-editor.d.ts +27 -0
- package/dist/code-editor.js +102 -0
- package/dist/color-input.d.ts +41 -0
- package/dist/color-input.js +112 -0
- package/dist/data-table.d.ts +79 -0
- package/dist/data-table.js +774 -0
- package/dist/drag-and-drop.d.ts +2 -0
- package/dist/drag-and-drop.js +386 -0
- package/dist/editable-rect.d.ts +97 -0
- package/dist/editable-rect.js +450 -0
- package/dist/filter-builder.d.ts +64 -0
- package/dist/filter-builder.js +468 -0
- package/dist/float.d.ts +18 -0
- package/dist/float.js +170 -0
- package/dist/form.d.ts +68 -0
- package/dist/form.js +466 -0
- package/dist/gamepad.d.ts +34 -0
- package/dist/gamepad.js +115 -0
- package/dist/icon-data.d.ts +312 -0
- package/dist/icon-data.js +308 -0
- package/dist/icon-types.d.ts +7 -0
- package/dist/icon-types.js +1 -0
- package/dist/icons.d.ts +17 -0
- package/dist/icons.js +374 -0
- package/dist/iife.js +69 -0
- package/dist/iife.js.map +49 -0
- package/dist/index-iife.d.ts +1 -0
- package/dist/index-iife.js +4 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +47 -0
- package/dist/live-example.d.ts +63 -0
- package/dist/live-example.js +611 -0
- package/dist/localize.d.ts +46 -0
- package/dist/localize.js +381 -0
- package/dist/make-sorter.d.ts +3 -0
- package/dist/make-sorter.js +119 -0
- package/dist/make-sorter.test.d.ts +1 -0
- package/dist/make-sorter.test.js +48 -0
- package/dist/mapbox.d.ts +24 -0
- package/dist/mapbox.js +161 -0
- package/dist/markdown-viewer.d.ts +17 -0
- package/dist/markdown-viewer.js +173 -0
- package/dist/match-shortcut.d.ts +9 -0
- package/dist/match-shortcut.js +13 -0
- package/dist/match-shortcut.test.d.ts +1 -0
- package/dist/match-shortcut.test.js +194 -0
- package/dist/menu.d.ts +60 -0
- package/dist/menu.js +614 -0
- package/dist/notifications.d.ts +106 -0
- package/dist/notifications.js +308 -0
- package/dist/password-strength.d.ts +35 -0
- package/dist/password-strength.js +302 -0
- package/dist/playwright.config.d.ts +9 -0
- package/dist/playwright.config.js +73 -0
- package/dist/pop-float.d.ts +10 -0
- package/dist/pop-float.js +231 -0
- package/dist/rating.d.ts +62 -0
- package/dist/rating.js +192 -0
- package/dist/rich-text.d.ts +35 -0
- package/dist/rich-text.js +296 -0
- package/dist/segmented.d.ts +80 -0
- package/dist/segmented.js +298 -0
- package/dist/select.d.ts +43 -0
- package/dist/select.js +427 -0
- package/dist/side-nav.d.ts +36 -0
- package/dist/side-nav.js +106 -0
- package/dist/size-break.d.ts +18 -0
- package/dist/size-break.js +118 -0
- package/dist/sizer.d.ts +34 -0
- package/dist/sizer.js +92 -0
- package/dist/src/ab-test.d.ts +14 -0
- package/dist/src/babylon-3d.d.ts +53 -0
- package/dist/src/bodymovin-player.d.ts +32 -0
- package/dist/src/bp-loader.d.ts +0 -0
- package/dist/src/carousel.d.ts +113 -0
- package/dist/src/code-editor.d.ts +27 -0
- package/dist/src/color-input.d.ts +41 -0
- package/dist/src/data-table.d.ts +79 -0
- package/dist/src/drag-and-drop.d.ts +2 -0
- package/dist/src/editable-rect.d.ts +97 -0
- package/dist/src/filter-builder.d.ts +64 -0
- package/dist/src/float.d.ts +18 -0
- package/dist/src/form.d.ts +68 -0
- package/dist/src/gamepad.d.ts +34 -0
- package/dist/src/icon-data.d.ts +309 -0
- package/dist/src/icon-types.d.ts +7 -0
- package/dist/src/icons.d.ts +17 -0
- package/dist/src/index.d.ts +37 -0
- package/dist/src/live-example.d.ts +51 -0
- package/dist/src/localize.d.ts +30 -0
- package/dist/src/make-sorter.d.ts +3 -0
- package/dist/src/mapbox.d.ts +24 -0
- package/dist/src/markdown-viewer.d.ts +15 -0
- package/dist/src/match-shortcut.d.ts +9 -0
- package/dist/src/menu.d.ts +60 -0
- package/dist/src/notifications.d.ts +106 -0
- package/dist/src/password-strength.d.ts +35 -0
- package/dist/src/pop-float.d.ts +10 -0
- package/dist/src/rating.d.ts +62 -0
- package/dist/src/rich-text.d.ts +28 -0
- package/dist/src/segmented.d.ts +80 -0
- package/dist/src/select.d.ts +43 -0
- package/dist/src/side-nav.d.ts +36 -0
- package/dist/src/size-break.d.ts +18 -0
- package/dist/src/sizer.d.ts +34 -0
- package/dist/src/tab-selector.d.ts +91 -0
- package/dist/src/tag-list.d.ts +37 -0
- package/dist/src/track-drag.d.ts +5 -0
- package/dist/src/version.d.ts +1 -0
- package/dist/src/via-tag.d.ts +2 -0
- package/dist/tab-selector.d.ts +91 -0
- package/dist/tab-selector.js +326 -0
- package/dist/tag-list.d.ts +37 -0
- package/dist/tag-list.js +375 -0
- package/dist/track-drag.d.ts +5 -0
- package/dist/track-drag.js +143 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/dist/via-tag.d.ts +2 -0
- package/dist/via-tag.js +102 -0
- package/package.json +58 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Component as WebComponent, ElementCreator } from 'xinjs';
|
|
2
|
+
type TabCloseHandler = (tabBody: Element) => boolean | undefined | void;
|
|
3
|
+
export declare class TabSelector extends WebComponent {
|
|
4
|
+
value: number;
|
|
5
|
+
localized: boolean;
|
|
6
|
+
makeTab(tabs: TabSelector, tabBody: HTMLElement, bodyId: string): HTMLElement;
|
|
7
|
+
static styleSpec: {
|
|
8
|
+
':host': {
|
|
9
|
+
display: string;
|
|
10
|
+
flexDirection: string;
|
|
11
|
+
position: string;
|
|
12
|
+
overflow: string;
|
|
13
|
+
boxShadow: string;
|
|
14
|
+
};
|
|
15
|
+
slot: {
|
|
16
|
+
position: string;
|
|
17
|
+
display: string;
|
|
18
|
+
flex: string;
|
|
19
|
+
overflow: string;
|
|
20
|
+
overflowY: string;
|
|
21
|
+
};
|
|
22
|
+
'slot[name="after-tabs"]': {
|
|
23
|
+
flex: string;
|
|
24
|
+
};
|
|
25
|
+
'::slotted([hidden])': {
|
|
26
|
+
display: string;
|
|
27
|
+
};
|
|
28
|
+
':host::part(tabpanel)': {
|
|
29
|
+
display: string;
|
|
30
|
+
flexDirection: string;
|
|
31
|
+
overflowX: string;
|
|
32
|
+
};
|
|
33
|
+
':host::part(tabrow)': {
|
|
34
|
+
display: string;
|
|
35
|
+
};
|
|
36
|
+
':host .tabs': {
|
|
37
|
+
display: string;
|
|
38
|
+
userSelect: string;
|
|
39
|
+
whiteSpace: string;
|
|
40
|
+
};
|
|
41
|
+
':host .tabs > div': {
|
|
42
|
+
padding: string;
|
|
43
|
+
cursor: string;
|
|
44
|
+
display: string;
|
|
45
|
+
alignItems: string;
|
|
46
|
+
};
|
|
47
|
+
':host .tabs > [aria-selected="true"]': {
|
|
48
|
+
'--text-color': any;
|
|
49
|
+
color: any;
|
|
50
|
+
};
|
|
51
|
+
':host .elastic': {
|
|
52
|
+
flex: string;
|
|
53
|
+
};
|
|
54
|
+
':host .border': {
|
|
55
|
+
background: string;
|
|
56
|
+
};
|
|
57
|
+
':host .border > .selected': {
|
|
58
|
+
content: string;
|
|
59
|
+
width: number;
|
|
60
|
+
height: string;
|
|
61
|
+
background: any;
|
|
62
|
+
transition: string;
|
|
63
|
+
};
|
|
64
|
+
':host button.close': {
|
|
65
|
+
border: number;
|
|
66
|
+
background: string;
|
|
67
|
+
textAlign: string;
|
|
68
|
+
marginLeft: any;
|
|
69
|
+
padding: number;
|
|
70
|
+
};
|
|
71
|
+
':host button.close > svg': {
|
|
72
|
+
height: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
onCloseTab: TabCloseHandler | null;
|
|
76
|
+
content: any[];
|
|
77
|
+
constructor();
|
|
78
|
+
addTabBody(body: HTMLElement, selectTab?: boolean): void;
|
|
79
|
+
removeTabBody(body: HTMLElement): void;
|
|
80
|
+
keyTab: (event: Event) => void;
|
|
81
|
+
get bodies(): Element[];
|
|
82
|
+
pickTab: (event: Event) => void;
|
|
83
|
+
setupTabs: () => void;
|
|
84
|
+
connectedCallback(): void;
|
|
85
|
+
disconnectedCallback(): void;
|
|
86
|
+
localeChanged: () => void;
|
|
87
|
+
onResize(): void;
|
|
88
|
+
render(): void;
|
|
89
|
+
}
|
|
90
|
+
export declare const tabSelector: ElementCreator<TabSelector>;
|
|
91
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Component as WebComponent, ElementCreator } from 'xinjs';
|
|
2
|
+
export declare class XinTag extends WebComponent {
|
|
3
|
+
caption: string;
|
|
4
|
+
removeable: boolean;
|
|
5
|
+
removeCallback: (event: Event) => void;
|
|
6
|
+
content: () => any[];
|
|
7
|
+
constructor();
|
|
8
|
+
}
|
|
9
|
+
export declare const xinTag: ElementCreator<XinTag>;
|
|
10
|
+
interface Tag {
|
|
11
|
+
value: string;
|
|
12
|
+
caption?: string;
|
|
13
|
+
color?: string;
|
|
14
|
+
background?: string;
|
|
15
|
+
icon?: string | HTMLElement;
|
|
16
|
+
}
|
|
17
|
+
type TagList = (string | Tag | null)[];
|
|
18
|
+
export declare class XinTagList extends WebComponent {
|
|
19
|
+
disabled: boolean;
|
|
20
|
+
name: string;
|
|
21
|
+
availableTags: string | TagList;
|
|
22
|
+
value: string | string[];
|
|
23
|
+
textEntry: boolean;
|
|
24
|
+
editable: boolean;
|
|
25
|
+
placeholder: string;
|
|
26
|
+
get tags(): string[];
|
|
27
|
+
constructor();
|
|
28
|
+
addTag: (tag: string) => void;
|
|
29
|
+
toggleTag: (toggled: string) => void;
|
|
30
|
+
enterTag: (event: KeyboardEvent) => void;
|
|
31
|
+
popSelectMenu: () => void;
|
|
32
|
+
content: () => any[];
|
|
33
|
+
removeTag: (event: Event) => void;
|
|
34
|
+
render(): void;
|
|
35
|
+
}
|
|
36
|
+
export declare const xinTagList: ElementCreator<XinTagList>;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type TrackerCallback = (dx: number, dy: number, event: PointerEvent) => boolean | undefined;
|
|
2
|
+
export declare const trackDrag: (event: PointerEvent, callback: TrackerCallback, cursor?: string) => void;
|
|
3
|
+
export declare const findHighestZ: (selector?: string) => number;
|
|
4
|
+
export declare const bringToFront: (element: HTMLElement, selector?: string) => void;
|
|
5
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const version = "0.9.15";
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Component as WebComponent, ElementCreator } from 'tosijs';
|
|
2
|
+
type TabCloseHandler = (tabBody: Element) => boolean | undefined | void;
|
|
3
|
+
export declare class TabSelector extends WebComponent {
|
|
4
|
+
value: number;
|
|
5
|
+
localized: boolean;
|
|
6
|
+
makeTab(tabs: TabSelector, tabBody: HTMLElement, bodyId: string): HTMLElement;
|
|
7
|
+
static styleSpec: {
|
|
8
|
+
':host': {
|
|
9
|
+
display: string;
|
|
10
|
+
flexDirection: string;
|
|
11
|
+
position: string;
|
|
12
|
+
overflow: string;
|
|
13
|
+
boxShadow: string;
|
|
14
|
+
};
|
|
15
|
+
slot: {
|
|
16
|
+
position: string;
|
|
17
|
+
display: string;
|
|
18
|
+
flex: string;
|
|
19
|
+
overflow: string;
|
|
20
|
+
overflowY: string;
|
|
21
|
+
};
|
|
22
|
+
'slot[name="after-tabs"]': {
|
|
23
|
+
flex: string;
|
|
24
|
+
};
|
|
25
|
+
'::slotted([hidden])': {
|
|
26
|
+
display: string;
|
|
27
|
+
};
|
|
28
|
+
':host::part(tabpanel)': {
|
|
29
|
+
display: string;
|
|
30
|
+
flexDirection: string;
|
|
31
|
+
overflowX: string;
|
|
32
|
+
};
|
|
33
|
+
':host::part(tabrow)': {
|
|
34
|
+
display: string;
|
|
35
|
+
};
|
|
36
|
+
':host .tabs': {
|
|
37
|
+
display: string;
|
|
38
|
+
userSelect: string;
|
|
39
|
+
whiteSpace: string;
|
|
40
|
+
};
|
|
41
|
+
':host .tabs > div': {
|
|
42
|
+
padding: string;
|
|
43
|
+
cursor: string;
|
|
44
|
+
display: string;
|
|
45
|
+
alignItems: string;
|
|
46
|
+
};
|
|
47
|
+
':host .tabs > [aria-selected="true"]': {
|
|
48
|
+
'--text-color': string;
|
|
49
|
+
color: string;
|
|
50
|
+
};
|
|
51
|
+
':host .elastic': {
|
|
52
|
+
flex: string;
|
|
53
|
+
};
|
|
54
|
+
':host .border': {
|
|
55
|
+
background: string;
|
|
56
|
+
};
|
|
57
|
+
':host .border > .selected': {
|
|
58
|
+
content: string;
|
|
59
|
+
width: number;
|
|
60
|
+
height: string;
|
|
61
|
+
background: string;
|
|
62
|
+
transition: string;
|
|
63
|
+
};
|
|
64
|
+
':host button.close': {
|
|
65
|
+
border: number;
|
|
66
|
+
background: string;
|
|
67
|
+
textAlign: string;
|
|
68
|
+
marginLeft: string;
|
|
69
|
+
padding: number;
|
|
70
|
+
};
|
|
71
|
+
':host button.close > svg': {
|
|
72
|
+
height: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
onCloseTab: TabCloseHandler | null;
|
|
76
|
+
content: (HTMLDivElement | HTMLSlotElement)[];
|
|
77
|
+
constructor();
|
|
78
|
+
addTabBody(body: HTMLElement, selectTab?: boolean): void;
|
|
79
|
+
removeTabBody(body: HTMLElement): void;
|
|
80
|
+
keyTab: (event: Event) => void;
|
|
81
|
+
get bodies(): Element[];
|
|
82
|
+
pickTab: (event: Event) => void;
|
|
83
|
+
setupTabs: () => void;
|
|
84
|
+
connectedCallback(): void;
|
|
85
|
+
disconnectedCallback(): void;
|
|
86
|
+
localeChanged: () => void;
|
|
87
|
+
onResize(): void;
|
|
88
|
+
render(): void;
|
|
89
|
+
}
|
|
90
|
+
export declare const tabSelector: ElementCreator<TabSelector>;
|
|
91
|
+
export {};
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/*#
|
|
2
|
+
# tabs
|
|
3
|
+
|
|
4
|
+
`<xin-tabs>` creates a `tabpanel` for its children, creating a `tab` for each based on its
|
|
5
|
+
`name` attribute.
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
[...preview.querySelectorAll('div[name]')].forEach(div => {
|
|
9
|
+
div.style.color = `hsl(${(Math.random() * 360).toFixed(0)} 50% 50%)`
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const { div, button } = xinjs.elements
|
|
13
|
+
const tabSelector = preview.querySelector('xin-tabs')
|
|
14
|
+
|
|
15
|
+
tabSelector.onCloseTab = body => {
|
|
16
|
+
if (!confirm(`Are you sure you want to close the ${body.getAttribute('name')} tab?`)) {
|
|
17
|
+
return false
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let bodycount = 0
|
|
22
|
+
preview.querySelector('.add').addEventListener('click', () => {
|
|
23
|
+
const name = `new tab ${++bodycount}`
|
|
24
|
+
const body = div(
|
|
25
|
+
{name, dataClose: true},
|
|
26
|
+
name,
|
|
27
|
+
)
|
|
28
|
+
tabSelector.addTabBody(body, true)
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
```html
|
|
32
|
+
<xin-tabs>
|
|
33
|
+
<div name="first">first body</div>
|
|
34
|
+
<div name="second" data-close>
|
|
35
|
+
<template role="tab">
|
|
36
|
+
<xin-icon
|
|
37
|
+
style="
|
|
38
|
+
display: inline-block;
|
|
39
|
+
width: 16px;
|
|
40
|
+
height: 16px;
|
|
41
|
+
transform: translateY(2px);
|
|
42
|
+
margin-right: 4px;
|
|
43
|
+
stroke: var(--brand-color);
|
|
44
|
+
"
|
|
45
|
+
icon="eye"
|
|
46
|
+
></xin-icon>
|
|
47
|
+
<span>Ooooh!!!</span>
|
|
48
|
+
</template>
|
|
49
|
+
look at the html…
|
|
50
|
+
</div>
|
|
51
|
+
<div name="third">third body</div>
|
|
52
|
+
<button class="add" slot="after-tabs">
|
|
53
|
+
<xin-icon icon="plus"></xin-icon>
|
|
54
|
+
</button>
|
|
55
|
+
</xin-tabs>
|
|
56
|
+
```
|
|
57
|
+
```css
|
|
58
|
+
.preview xin-tabs {
|
|
59
|
+
height: 100%;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.preview div[name] {
|
|
63
|
+
padding: 20px;
|
|
64
|
+
text-align: center;
|
|
65
|
+
height: 100%;
|
|
66
|
+
font-size: 200%;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.preview .add {
|
|
70
|
+
width: 38px;
|
|
71
|
+
line-height: 38px;
|
|
72
|
+
height: 38px;
|
|
73
|
+
padding: 0;
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The `<xin-tabs>`s `value` is the index of its active body.
|
|
78
|
+
|
|
79
|
+
A `<xin-tabs>` has `addTabBody(body: HTMLElement, select?: boolean)` and
|
|
80
|
+
`removeTabBody(body: number | HTMLElement)` methods for updating its content.
|
|
81
|
+
|
|
82
|
+
You can also just insert or remove tab bodies directly and call `setupTabs()`.
|
|
83
|
+
|
|
84
|
+
## Closeable Tabs
|
|
85
|
+
|
|
86
|
+
Adding the `data-close` attribute to a tab will make it closeable.
|
|
87
|
+
|
|
88
|
+
When a tab is closed, the `<xin-tabs>` element's `onCloseTab: (tabBody: Element) => boolean | undefined | void`
|
|
89
|
+
will be called. If you override this method and return `false`, the tab will
|
|
90
|
+
not be closed (e.g. if you want to implement save/cancel behavior).
|
|
91
|
+
|
|
92
|
+
## Custom Tab Content
|
|
93
|
+
|
|
94
|
+
You can specify the exact content of the tab for a given body by
|
|
95
|
+
adding a `<template role="tab">` to that body. The contents of that
|
|
96
|
+
template will be cloned into the tab.
|
|
97
|
+
|
|
98
|
+
## Localized Support
|
|
99
|
+
|
|
100
|
+
```html
|
|
101
|
+
<xin-tabs localized>
|
|
102
|
+
<div name="localize"><h2>localize!</h2></div>
|
|
103
|
+
<div name="tabs"><h2>tabs</h2></div>
|
|
104
|
+
</xin-tabs>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`<xin-tabs>` supports the `localized` attribute. It will automatically localize
|
|
108
|
+
tab names (but it won't override custom tab content, so localizing that is on you).
|
|
109
|
+
*/
|
|
110
|
+
import { Component as WebComponent, elements, vars, } from 'xinjs';
|
|
111
|
+
import { xinLocalized, XinLocalized } from './localize';
|
|
112
|
+
import { icons } from '../src';
|
|
113
|
+
const { div, slot, span, button } = elements;
|
|
114
|
+
export class TabSelector extends WebComponent {
|
|
115
|
+
value = 0;
|
|
116
|
+
localized = false;
|
|
117
|
+
makeTab(tabs, tabBody, bodyId) {
|
|
118
|
+
const tabName = tabBody.getAttribute('name');
|
|
119
|
+
const tabContent = tabBody.querySelector('template[role="tab"]')?.content.cloneNode(true) ||
|
|
120
|
+
(this.localized ? xinLocalized(tabName) : span(tabName));
|
|
121
|
+
const tab = div(tabContent, {
|
|
122
|
+
part: 'tab',
|
|
123
|
+
tabindex: 0,
|
|
124
|
+
role: 'tab',
|
|
125
|
+
ariaControls: bodyId,
|
|
126
|
+
}, tabBody.hasAttribute('data-close')
|
|
127
|
+
? button({
|
|
128
|
+
title: 'close',
|
|
129
|
+
class: 'close',
|
|
130
|
+
}, icons.x())
|
|
131
|
+
: {});
|
|
132
|
+
return tab;
|
|
133
|
+
}
|
|
134
|
+
static styleSpec = {
|
|
135
|
+
':host': {
|
|
136
|
+
display: 'flex',
|
|
137
|
+
flexDirection: 'column',
|
|
138
|
+
position: 'relative',
|
|
139
|
+
overflow: 'hidden',
|
|
140
|
+
boxShadow: 'none !important',
|
|
141
|
+
},
|
|
142
|
+
slot: {
|
|
143
|
+
position: 'relative',
|
|
144
|
+
display: 'block',
|
|
145
|
+
flex: '1',
|
|
146
|
+
overflow: 'hidden',
|
|
147
|
+
overflowY: 'auto',
|
|
148
|
+
},
|
|
149
|
+
'slot[name="after-tabs"]': {
|
|
150
|
+
flex: '0 0 auto',
|
|
151
|
+
},
|
|
152
|
+
'::slotted([hidden])': {
|
|
153
|
+
display: 'none !important',
|
|
154
|
+
},
|
|
155
|
+
':host::part(tabpanel)': {
|
|
156
|
+
display: 'flex',
|
|
157
|
+
flexDirection: 'column',
|
|
158
|
+
overflowX: 'auto',
|
|
159
|
+
},
|
|
160
|
+
':host::part(tabrow)': {
|
|
161
|
+
display: 'flex',
|
|
162
|
+
},
|
|
163
|
+
':host .tabs': {
|
|
164
|
+
display: 'flex',
|
|
165
|
+
userSelect: 'none',
|
|
166
|
+
whiteSpace: 'nowrap',
|
|
167
|
+
},
|
|
168
|
+
':host .tabs > div': {
|
|
169
|
+
padding: `${vars.spacing50} ${vars.spacing}`,
|
|
170
|
+
cursor: 'default',
|
|
171
|
+
display: 'flex',
|
|
172
|
+
alignItems: 'baseline',
|
|
173
|
+
},
|
|
174
|
+
':host .tabs > [aria-selected="true"]': {
|
|
175
|
+
'--text-color': vars.xinTabsSelectedColor,
|
|
176
|
+
color: vars.textColor,
|
|
177
|
+
},
|
|
178
|
+
':host .elastic': {
|
|
179
|
+
flex: '1',
|
|
180
|
+
},
|
|
181
|
+
':host .border': {
|
|
182
|
+
background: 'var(--xin-tabs-bar-color, #ccc)',
|
|
183
|
+
},
|
|
184
|
+
':host .border > .selected': {
|
|
185
|
+
content: ' ',
|
|
186
|
+
width: 0,
|
|
187
|
+
height: 'var(--xin-tabs-bar-height, 2px)',
|
|
188
|
+
background: vars.xinTabsSelectedColor,
|
|
189
|
+
transition: 'ease-out 0.2s',
|
|
190
|
+
},
|
|
191
|
+
':host button.close': {
|
|
192
|
+
border: 0,
|
|
193
|
+
background: 'transparent',
|
|
194
|
+
textAlign: 'center',
|
|
195
|
+
marginLeft: vars.spacing50,
|
|
196
|
+
padding: 0,
|
|
197
|
+
},
|
|
198
|
+
':host button.close > svg': {
|
|
199
|
+
height: '12px',
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
onCloseTab = null;
|
|
203
|
+
content = [
|
|
204
|
+
div({ role: 'tabpanel', part: 'tabpanel' }, div({ part: 'tabrow' }, div({ class: 'tabs', part: 'tabs' }), div({ class: 'elastic' }), slot({ name: 'after-tabs' })), div({ class: 'border' }, div({ class: 'selected', part: 'selected' }))),
|
|
205
|
+
slot(),
|
|
206
|
+
];
|
|
207
|
+
constructor() {
|
|
208
|
+
super();
|
|
209
|
+
this.initAttributes('localized');
|
|
210
|
+
}
|
|
211
|
+
addTabBody(body, selectTab = false) {
|
|
212
|
+
if (!body.hasAttribute('name')) {
|
|
213
|
+
console.error('element has no name attribute', body);
|
|
214
|
+
throw new Error('element has no name attribute');
|
|
215
|
+
}
|
|
216
|
+
this.append(body);
|
|
217
|
+
this.setupTabs();
|
|
218
|
+
if (selectTab) {
|
|
219
|
+
this.value = this.bodies.length - 1;
|
|
220
|
+
}
|
|
221
|
+
this.queueRender();
|
|
222
|
+
}
|
|
223
|
+
removeTabBody(body) {
|
|
224
|
+
body.remove();
|
|
225
|
+
this.setupTabs();
|
|
226
|
+
this.queueRender();
|
|
227
|
+
}
|
|
228
|
+
keyTab = (event) => {
|
|
229
|
+
const { tabs } = this.parts;
|
|
230
|
+
const tabIndex = [...tabs.children].indexOf(event.target);
|
|
231
|
+
switch (event.key) {
|
|
232
|
+
case 'ArrowLeft':
|
|
233
|
+
this.value =
|
|
234
|
+
(tabIndex + Number(tabs.children.length) - 1) % tabs.children.length;
|
|
235
|
+
tabs.children[this.value].focus();
|
|
236
|
+
event.preventDefault();
|
|
237
|
+
break;
|
|
238
|
+
case 'ArrowRight':
|
|
239
|
+
this.value = (tabIndex + 1) % tabs.children.length;
|
|
240
|
+
tabs.children[this.value].focus();
|
|
241
|
+
event.preventDefault();
|
|
242
|
+
break;
|
|
243
|
+
case ' ':
|
|
244
|
+
this.pickTab(event);
|
|
245
|
+
event.preventDefault();
|
|
246
|
+
break;
|
|
247
|
+
default:
|
|
248
|
+
// console.log(event.key)
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
get bodies() {
|
|
252
|
+
return [...this.children].filter((elt) => elt.hasAttribute('name'));
|
|
253
|
+
}
|
|
254
|
+
pickTab = (event) => {
|
|
255
|
+
const { tabs } = this.parts;
|
|
256
|
+
const target = event.target;
|
|
257
|
+
const isCloseEvent = target.closest('button.close') !== null;
|
|
258
|
+
const tab = target.closest('.tabs > div');
|
|
259
|
+
const tabIndex = [...tabs.children].indexOf(tab);
|
|
260
|
+
if (isCloseEvent) {
|
|
261
|
+
const body = this.bodies[tabIndex];
|
|
262
|
+
if (!this.onCloseTab || this.onCloseTab(body) !== false) {
|
|
263
|
+
this.removeTabBody(this.bodies[tabIndex]);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
if (tabIndex > -1) {
|
|
268
|
+
this.value = tabIndex;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
setupTabs = () => {
|
|
273
|
+
const { tabs } = this.parts;
|
|
274
|
+
const tabBodies = [...this.children].filter((child) => !child.hasAttribute('slot') && child.hasAttribute('name'));
|
|
275
|
+
tabs.textContent = '';
|
|
276
|
+
if (this.value >= tabBodies.length) {
|
|
277
|
+
this.value = tabBodies.length - 1;
|
|
278
|
+
}
|
|
279
|
+
for (const index in tabBodies) {
|
|
280
|
+
const tabBody = tabBodies[index];
|
|
281
|
+
const bodyId = `${this.instanceId}-${index}`;
|
|
282
|
+
tabBody.id = bodyId;
|
|
283
|
+
const tab = this.makeTab(this, tabBody, bodyId);
|
|
284
|
+
tabs.append(tab);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
connectedCallback() {
|
|
288
|
+
super.connectedCallback();
|
|
289
|
+
const { tabs } = this.parts;
|
|
290
|
+
tabs.addEventListener('click', this.pickTab);
|
|
291
|
+
tabs.addEventListener('keydown', this.keyTab);
|
|
292
|
+
this.setupTabs();
|
|
293
|
+
XinLocalized.allInstances.add(this);
|
|
294
|
+
}
|
|
295
|
+
disconnectedCallback() {
|
|
296
|
+
super.disconnectedCallback();
|
|
297
|
+
XinLocalized.allInstances.delete(this);
|
|
298
|
+
}
|
|
299
|
+
localeChanged = () => {
|
|
300
|
+
this.queueRender();
|
|
301
|
+
};
|
|
302
|
+
onResize() {
|
|
303
|
+
this.queueRender();
|
|
304
|
+
}
|
|
305
|
+
render() {
|
|
306
|
+
const { tabs, selected } = this.parts;
|
|
307
|
+
const tabBodies = this.bodies;
|
|
308
|
+
for (let i = 0; i < tabBodies.length; i++) {
|
|
309
|
+
const tabBody = tabBodies[i];
|
|
310
|
+
const tab = tabs.children[i];
|
|
311
|
+
if (this.value === Number(i)) {
|
|
312
|
+
tab.setAttribute('aria-selected', 'true');
|
|
313
|
+
selected.style.marginLeft = `${tab.offsetLeft - tabs.offsetLeft}px`;
|
|
314
|
+
selected.style.width = `${tab.offsetWidth}px`;
|
|
315
|
+
tabBody.toggleAttribute('hidden', false);
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
tab.toggleAttribute('aria-selected', false);
|
|
319
|
+
tabBody.toggleAttribute('hidden', true);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
export const tabSelector = TabSelector.elementCreator({
|
|
325
|
+
tag: 'xin-tabs',
|
|
326
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Component as WebComponent, ElementCreator } from 'tosijs';
|
|
2
|
+
export declare class XinTag extends WebComponent {
|
|
3
|
+
caption: string;
|
|
4
|
+
removeable: boolean;
|
|
5
|
+
removeCallback: (event: Event) => void;
|
|
6
|
+
content: () => HTMLSpanElement[];
|
|
7
|
+
constructor();
|
|
8
|
+
}
|
|
9
|
+
export declare const xinTag: ElementCreator<XinTag>;
|
|
10
|
+
interface Tag {
|
|
11
|
+
value: string;
|
|
12
|
+
caption?: string;
|
|
13
|
+
color?: string;
|
|
14
|
+
background?: string;
|
|
15
|
+
icon?: string | HTMLElement;
|
|
16
|
+
}
|
|
17
|
+
type TagList = (string | Tag | null)[];
|
|
18
|
+
export declare class XinTagList extends WebComponent {
|
|
19
|
+
disabled: boolean;
|
|
20
|
+
name: string;
|
|
21
|
+
availableTags: string | TagList;
|
|
22
|
+
value: string | string[];
|
|
23
|
+
textEntry: boolean;
|
|
24
|
+
editable: boolean;
|
|
25
|
+
placeholder: string;
|
|
26
|
+
get tags(): string[];
|
|
27
|
+
constructor();
|
|
28
|
+
addTag: (tag: string) => void;
|
|
29
|
+
toggleTag: (toggled: string) => void;
|
|
30
|
+
enterTag: (event: KeyboardEvent) => void;
|
|
31
|
+
popSelectMenu: () => void;
|
|
32
|
+
content: () => (HTMLButtonElement | HTMLDivElement)[];
|
|
33
|
+
removeTag: (event: Event) => void;
|
|
34
|
+
render(): void;
|
|
35
|
+
}
|
|
36
|
+
export declare const xinTagList: ElementCreator<XinTagList>;
|
|
37
|
+
export {};
|