@diplodoc/tabs-extension 0.0.5 → 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/Readme.md +7 -2
- package/package.json +4 -3
- package/runtime/index.js +164 -1
- package/runtime/index.js.map +3 -3
- package/runtime/styles.css +1 -0
- package/runtime/styles.css.map +1 -0
- package/runtime/utils.d.ts +1 -0
package/Readme.md
CHANGED
|
@@ -36,8 +36,9 @@ You can add assets files which were generated by the [MarkdownIt transform plugi
|
|
|
36
36
|
```html
|
|
37
37
|
<html>
|
|
38
38
|
<head>
|
|
39
|
-
<!-- Read more about '_assets/tabs-extension.js' in 'Transform plugin' section -->
|
|
39
|
+
<!-- Read more about '_assets/tabs-extension.js' and '_assets/tabs-extension.css' in 'Transform plugin' section -->
|
|
40
40
|
<script src='_assets/tabs-extension.js' async></script>
|
|
41
|
+
<link rel='stylesheet' href='_assets/tabs-extension.css' />
|
|
41
42
|
</head>
|
|
42
43
|
<body>
|
|
43
44
|
${result.html}
|
|
@@ -47,7 +48,8 @@ You can add assets files which were generated by the [MarkdownIt transform plugi
|
|
|
47
48
|
|
|
48
49
|
Or you can just include runtime's source code in your bundle.
|
|
49
50
|
```js
|
|
50
|
-
import '@diplodoc/runtime
|
|
51
|
+
import '@diplodoc/tabs-extension/runtime'
|
|
52
|
+
import '@diplodoc/tabs-extension/runtime/styles.css'
|
|
51
53
|
```
|
|
52
54
|
|
|
53
55
|
## MarkdownIt transform plugin
|
|
@@ -58,6 +60,9 @@ Options:
|
|
|
58
60
|
- `runtimeJsPath` - name on runtime script which will be exposed in results `script` section.<br>
|
|
59
61
|
Default: `_assets/mermaid-extension.js`<br>
|
|
60
62
|
|
|
63
|
+
- `runtimeCssPath` - name on runtime css file which will be exposed in results `style` section.<br>
|
|
64
|
+
(Default: `_assets/mermaid-extension.css`)<br>
|
|
65
|
+
|
|
61
66
|
- `bundle` - boolean flag to enable/disable copying of bundled runtime to target directory.<br>
|
|
62
67
|
Where target directore is `<transformer output option>/<plugin runtime option>`<br>
|
|
63
68
|
Default: `true`<br>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diplodoc/tabs-extension",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "TBD",
|
|
5
5
|
"main": "plugin/index.js",
|
|
6
6
|
"types": "plugin/index.d.ts",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"./react": "./react/index.js"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
|
-
"build": "
|
|
20
|
+
"build": "run-p build:*",
|
|
21
|
+
"build:css": "sass src/runtime/scss/tabs.scss runtime/styles.css --style=compressed",
|
|
21
22
|
"build:js": "./esbuild/build.mjs",
|
|
22
23
|
"build:declarations": "tsc --emitDeclarationOnly --outDir .",
|
|
23
24
|
"lint": "npx eslint \"{src,example}/**/*.{js,ts}\"",
|
|
@@ -52,7 +53,6 @@
|
|
|
52
53
|
"@yandex-cloud/eslint-config": "^1.1.0",
|
|
53
54
|
"@yandex-cloud/prettier-config": "^1.0.0",
|
|
54
55
|
"esbuild": "^0.17.12",
|
|
55
|
-
"esbuild-inline-sass": "^0.4.1",
|
|
56
56
|
"eslint": "^8.43.0",
|
|
57
57
|
"github-slugger": "^2.0.0",
|
|
58
58
|
"husky": "^8.0.3",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"markdown-it": "^13.0.1",
|
|
61
61
|
"npm-run-all": "^4.1.5",
|
|
62
62
|
"prettier": "^2.8.8",
|
|
63
|
+
"sass": "^1.64.1",
|
|
63
64
|
"ts-jest": "^29.1.0",
|
|
64
65
|
"typescript": "^5.0.2",
|
|
65
66
|
"uuid": "^9.0.0"
|
package/runtime/index.js
CHANGED
|
@@ -1,2 +1,165 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
(() => {
|
|
3
|
+
// src/common.ts
|
|
4
|
+
var TABS_CLASSNAME = "diplodoc-tabs";
|
|
5
|
+
var TABS_LIST_CLASSNAME = "diplodoc-tab-list";
|
|
6
|
+
var TAB_CLASSNAME = "diplodoc-tab";
|
|
7
|
+
var TAB_PANEL_CLASSNAME = "diplodoc-tab-panel";
|
|
8
|
+
var ACTIVE_CLASSNAME = "active";
|
|
9
|
+
var GROUP_DATA_KEY = "data-diplodoc-group";
|
|
10
|
+
var TAB_DATA_KEY = "data-diplodoc-key";
|
|
11
|
+
var TAB_DATA_ID = "data-diplodoc-id";
|
|
12
|
+
var SELECT_TAB_EVENT_NAME = "selecttab";
|
|
13
|
+
var DEFAULT_TABS_GROUP_PREFIX = "defaultTabsGroup-";
|
|
14
|
+
var GLOBAL_SYMBOL = Symbol.for("diplodocTabs");
|
|
15
|
+
|
|
16
|
+
// src/runtime/utils.ts
|
|
17
|
+
var getEventTarget = (event) => {
|
|
18
|
+
const path = event.composedPath();
|
|
19
|
+
return Array.isArray(path) && path.length > 0 ? path[0] : event.target;
|
|
20
|
+
};
|
|
21
|
+
var isCustom = (event) => {
|
|
22
|
+
const target = getEventTarget(event);
|
|
23
|
+
return !target || !target.matches;
|
|
24
|
+
};
|
|
25
|
+
var getClosestScrollableParent = (element) => {
|
|
26
|
+
if (element.scrollHeight - element.clientHeight > 1) {
|
|
27
|
+
return element;
|
|
28
|
+
}
|
|
29
|
+
return element.parentElement ? getClosestScrollableParent(element.parentElement) : null;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// src/runtime/TabsController.ts
|
|
33
|
+
var Selector = {
|
|
34
|
+
TABS: `.${TABS_CLASSNAME}`,
|
|
35
|
+
TAB_LIST: `.${TABS_LIST_CLASSNAME}`,
|
|
36
|
+
TAB: `.${TAB_CLASSNAME}`,
|
|
37
|
+
TAB_PANEL: `.${TAB_PANEL_CLASSNAME}`
|
|
38
|
+
};
|
|
39
|
+
var TabsController = class extends EventTarget {
|
|
40
|
+
constructor(document2) {
|
|
41
|
+
super();
|
|
42
|
+
this._document = document2;
|
|
43
|
+
this._document.addEventListener("click", (event) => {
|
|
44
|
+
const target = getEventTarget(event);
|
|
45
|
+
if (isCustom(event) || !this.isValidTabElement(target)) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const tab = this.getTabDataFromHTMLElement(target);
|
|
49
|
+
if (tab) {
|
|
50
|
+
this._selectTab(tab, target);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
selectTabById(id, options) {
|
|
55
|
+
const target = this._document.querySelector(
|
|
56
|
+
`${Selector.TAB}[${TAB_DATA_ID}="${id}"]`
|
|
57
|
+
);
|
|
58
|
+
if (!target || !this.isValidTabElement(target)) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const tab = this.getTabDataFromHTMLElement(target);
|
|
62
|
+
if (tab) {
|
|
63
|
+
this._selectTab(tab, target);
|
|
64
|
+
}
|
|
65
|
+
if (options == null ? void 0 : options.scrollToElement) {
|
|
66
|
+
target.scrollIntoView();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
selectTab(tab) {
|
|
70
|
+
this._selectTab(tab);
|
|
71
|
+
}
|
|
72
|
+
_selectTab(tab, targetTab) {
|
|
73
|
+
const { group, key } = tab;
|
|
74
|
+
if (!group) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const oldTargetBoundingBox = targetTab == null ? void 0 : targetTab.getBoundingClientRect();
|
|
78
|
+
const tabs = this._document.querySelectorAll(
|
|
79
|
+
`${Selector.TABS}[${GROUP_DATA_KEY}="${group}"] ${Selector.TAB}[${TAB_DATA_KEY}="${key}"]`
|
|
80
|
+
);
|
|
81
|
+
let found = 0;
|
|
82
|
+
tabs.forEach((element) => {
|
|
83
|
+
const htmlElem = element;
|
|
84
|
+
if (!this.isValidTabElement(htmlElem) || element.classList.contains(ACTIVE_CLASSNAME)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
found++;
|
|
88
|
+
const tab2 = element;
|
|
89
|
+
const tabList = tab2.parentNode;
|
|
90
|
+
const tabsContainer = tabList == null ? void 0 : tabList.parentNode;
|
|
91
|
+
const allTabs = Array.from((tabsContainer == null ? void 0 : tabsContainer.querySelectorAll(Selector.TAB)) || []);
|
|
92
|
+
const allPanels = Array.from((tabsContainer == null ? void 0 : tabsContainer.querySelectorAll(Selector.TAB_PANEL)) || []);
|
|
93
|
+
const targetIndex = allTabs.indexOf(tab2);
|
|
94
|
+
allTabs.forEach((tab3, i) => {
|
|
95
|
+
const panel = allPanels[i];
|
|
96
|
+
const isTargetTab = i === targetIndex;
|
|
97
|
+
tab3.classList.toggle(ACTIVE_CLASSNAME, isTargetTab);
|
|
98
|
+
tab3.setAttribute("aria-selected", isTargetTab.toString());
|
|
99
|
+
tab3.setAttribute("tabindex", isTargetTab ? "0" : "-1");
|
|
100
|
+
panel.classList.toggle(ACTIVE_CLASSNAME, isTargetTab);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
if (found > 0) {
|
|
104
|
+
if (targetTab && oldTargetBoundingBox) {
|
|
105
|
+
const { left, top } = getCoords(targetTab);
|
|
106
|
+
const scrollableParent = getClosestScrollableParent(targetTab);
|
|
107
|
+
if (scrollableParent) {
|
|
108
|
+
console.log(`>> ${scrollableParent.offsetTop - targetTab.offsetTop}`);
|
|
109
|
+
scrollableParent.scrollTo(
|
|
110
|
+
0,
|
|
111
|
+
(scrollableParent.offsetTop - targetTab.offsetTop) * -1
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const eventTab = group.startsWith(DEFAULT_TABS_GROUP_PREFIX) ? { key: tab.key } : tab;
|
|
116
|
+
this.dispatchEvent(
|
|
117
|
+
new CustomEvent(SELECT_TAB_EVENT_NAME, {
|
|
118
|
+
detail: { tab: eventTab, currentTabId: targetTab == null ? void 0 : targetTab.dataset.diplodocId }
|
|
119
|
+
})
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
isValidTabElement(element) {
|
|
124
|
+
const tabList = element.matches(Selector.TAB) && element.dataset.diplodocId ? element.closest(Selector.TAB_LIST) : null;
|
|
125
|
+
return tabList == null ? void 0 : tabList.closest(Selector.TABS);
|
|
126
|
+
}
|
|
127
|
+
getTabDataFromHTMLElement(target) {
|
|
128
|
+
var _a;
|
|
129
|
+
const key = target.dataset.diplodocKey;
|
|
130
|
+
const group = (_a = target.closest(Selector.TABS)) == null ? void 0 : _a.dataset.diplodocGroup;
|
|
131
|
+
return key && group ? { group, key } : null;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
function getCoords(elem) {
|
|
135
|
+
const box = elem.getBoundingClientRect();
|
|
136
|
+
const body = document.body;
|
|
137
|
+
const docEl = document.documentElement;
|
|
138
|
+
const scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
|
|
139
|
+
const scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
|
|
140
|
+
const clientTop = docEl.clientTop || body.clientTop || 0;
|
|
141
|
+
const clientLeft = docEl.clientLeft || body.clientLeft || 0;
|
|
142
|
+
const top = box.top + scrollTop - clientTop;
|
|
143
|
+
const left = box.left + scrollLeft - clientLeft;
|
|
144
|
+
return { top: Math.round(top), left: Math.round(left) };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// style-helper:index.js
|
|
148
|
+
function inject_style(text) {
|
|
149
|
+
if (typeof document !== "undefined") {
|
|
150
|
+
var style = document.createElement("style");
|
|
151
|
+
var node = document.createTextNode(text);
|
|
152
|
+
style.appendChild(node);
|
|
153
|
+
document.head.appendChild(style);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/runtime/scss/tabs.scss
|
|
158
|
+
inject_style('.diplodoc-tabs{margin-bottom:15px}.diplodoc-tabs ol{counter-reset:tabs-list}.diplodoc-tabs ol>li{counter-increment:tabs-list}.diplodoc-tabs ol>li:before{content:counters(tabs-list,".") ". "}.diplodoc-tab-list{display:flex;flex-wrap:wrap;margin-bottom:15px}.diplodoc-tab{margin-bottom:-1px;margin-right:20px;border-bottom:2px solid transparent;padding:6px 0 7px;font-weight:700;outline:none;cursor:pointer;user-select:none;white-space:break-spaces}.diplodoc-tab:last-child{margin-right:0}.diplodoc-tab:hover,.diplodoc-tab:active{color:#004080}.diplodoc-tab.active{border-bottom-color:#027bf3}.diplodoc-tab-panel{display:none}.diplodoc-tab-panel:first-child{margin-top:0!important}.diplodoc-tab-panel:last-child{margin-bottom:0!important}.diplodoc-tab-panel.active{display:block}');
|
|
159
|
+
|
|
160
|
+
// src/runtime/index.ts
|
|
161
|
+
if (typeof window !== "undefined" && typeof document !== "undefined" && !window[GLOBAL_SYMBOL]) {
|
|
162
|
+
window[GLOBAL_SYMBOL] = new TabsController(document);
|
|
163
|
+
}
|
|
164
|
+
})();
|
|
2
165
|
//# sourceMappingURL=index.js.map
|
package/runtime/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/common.ts", "../src/runtime/utils.ts", "../src/runtime/TabsController.ts", "style-helper:index.js", "../src/runtime/scss/tabs.scss", "../src/runtime/index.ts"],
|
|
4
|
-
"sourcesContent": ["import {TabsController} from './runtime/TabsController';\n\nexport const TABS_CLASSNAME = 'diplodoc-tabs';\nexport const TABS_LIST_CLASSNAME = 'diplodoc-tab-list';\nexport const TAB_CLASSNAME = 'diplodoc-tab';\nexport const TAB_PANEL_CLASSNAME = 'diplodoc-tab-panel';\nexport const ACTIVE_CLASSNAME = 'active';\n\nexport const GROUP_DATA_KEY = 'data-diplodoc-group';\nexport const TAB_DATA_KEY = 'data-diplodoc-key';\nexport const TAB_DATA_ID = 'data-diplodoc-id';\n\nexport const SELECT_TAB_EVENT_NAME = 'selecttab';\n\nexport const DEFAULT_TABS_GROUP_PREFIX = 'defaultTabsGroup-';\n\nexport interface Tab {\n group?: string;\n key: string;\n}\n\nexport interface SelectedTabEvent {\n tab: Tab;\n currentTabId?: string;\n}\n\nexport const GLOBAL_SYMBOL: unique symbol = Symbol.for('diplodocTabs');\n\ndeclare global {\n interface Window {\n [GLOBAL_SYMBOL]: TabsController;\n }\n}\n", "export const getEventTarget = (event: Event) => {\n const path = event.composedPath();\n return Array.isArray(path) && path.length > 0 ? path[0] : event.target;\n};\n\nexport const isCustom = (event: Event) => {\n const target = getEventTarget(event);\n return !target || !(target as HTMLElement).matches;\n};\n", "import {\n ACTIVE_CLASSNAME,\n DEFAULT_TABS_GROUP_PREFIX,\n GROUP_DATA_KEY,\n SELECT_TAB_EVENT_NAME,\n SelectedTabEvent,\n TABS_CLASSNAME,\n TABS_LIST_CLASSNAME,\n TAB_CLASSNAME,\n TAB_DATA_ID,\n TAB_DATA_KEY,\n TAB_PANEL_CLASSNAME,\n Tab,\n} from '../common';\nimport {isCustom, getEventTarget} from './utils';\n\nconst Selector = {\n TABS: `.${TABS_CLASSNAME}`,\n TAB_LIST: `.${TABS_LIST_CLASSNAME}`,\n TAB: `.${TAB_CLASSNAME}`,\n TAB_PANEL: `.${TAB_PANEL_CLASSNAME}`,\n};\n\nexport interface ISelectTabByIdOptions {\n scrollToElement: boolean;\n}\n\nexport class TabsController extends EventTarget {\n private _document: Document;\n\n constructor(document: Document) {\n super();\n\n this._document = document;\n this._document.addEventListener('click', (event) => {\n const target = getEventTarget(event) as HTMLElement;\n\n if (isCustom(event) || !this.isValidTabElement(target)) {\n return;\n }\n\n const tab = this.getTabDataFromHTMLElement(target);\n if (tab) {\n this._selectTab(tab, target);\n }\n });\n }\n\n selectTabById(id: string, options?: ISelectTabByIdOptions) {\n const target = this._document.querySelector(\n `${Selector.TAB}[${TAB_DATA_ID}=\"${id}\"]`,\n ) as HTMLElement;\n\n if (!target || !this.isValidTabElement(target)) {\n return;\n }\n\n const tab = this.getTabDataFromHTMLElement(target);\n if (tab) {\n this._selectTab(tab, target);\n }\n\n if (options?.scrollToElement) {\n target.scrollIntoView();\n }\n }\n\n selectTab(tab: Tab) {\n this._selectTab(tab);\n }\n\n private _selectTab(tab: Tab, targetTab?: HTMLElement) {\n const {group, key} = tab;\n\n if (!group) {\n return;\n }\n\n const tabs = this._document.querySelectorAll(\n `${Selector.TABS}[${GROUP_DATA_KEY}=\"${group}\"] ${Selector.TAB}[${TAB_DATA_KEY}=\"${key}\"]`,\n );\n\n let found = 0;\n\n tabs.forEach((element) => {\n const htmlElem = element as HTMLElement;\n if (!this.isValidTabElement(htmlElem) || element.classList.contains(ACTIVE_CLASSNAME)) {\n return;\n }\n\n found++;\n\n const tab = element;\n const tabList = tab.parentNode;\n const tabsContainer = tabList?.parentNode;\n const allTabs = Array.from(tabsContainer?.querySelectorAll(Selector.TAB) || []);\n const allPanels = Array.from(tabsContainer?.querySelectorAll(Selector.TAB_PANEL) || []);\n const targetIndex = allTabs.indexOf(tab);\n\n allTabs.forEach((tab, i) => {\n const panel = allPanels[i];\n const isTargetTab = i === targetIndex;\n\n tab.classList.toggle(ACTIVE_CLASSNAME, isTargetTab);\n tab.setAttribute('aria-selected', isTargetTab.toString());\n tab.setAttribute('tabindex', isTargetTab ? '0' : '-1');\n panel.classList.toggle(ACTIVE_CLASSNAME, isTargetTab);\n });\n });\n\n if (found > 0) {\n const eventTab: Tab = group.startsWith(DEFAULT_TABS_GROUP_PREFIX)\n ? {key: tab.key}\n : tab;\n this.dispatchEvent(\n new CustomEvent<SelectedTabEvent>(SELECT_TAB_EVENT_NAME, {\n detail: {tab: eventTab, currentTabId: targetTab?.dataset.diplodocId},\n }),\n );\n }\n }\n\n private isValidTabElement(element: HTMLElement) {\n const tabList =\n element.matches(Selector.TAB) && element.dataset.diplodocId\n ? element.closest(Selector.TAB_LIST)\n : null;\n return tabList?.closest(Selector.TABS);\n }\n\n private getTabDataFromHTMLElement(target: HTMLElement): Tab | null {\n const key = target.dataset.diplodocKey;\n const group = (target.closest(Selector.TABS) as HTMLElement)?.dataset.diplodocGroup;\n return key && group ? {group, key} : null;\n }\n}\n", "export function inject_style(text) {\n if (typeof document !== 'undefined') {\n var style = document.createElement('style')\n var node = document.createTextNode(text)\n style.appendChild(node)\n document.head.appendChild(style)\n }\n}", "import { inject_style } from \"__style_helper__\"\ninject_style(\".diplodoc-tabs{margin-bottom:15px}.diplodoc-tabs ol{counter-reset:tabs-list}.diplodoc-tabs ol>li{counter-increment:tabs-list}.diplodoc-tabs ol>li:before{content:counters(tabs-list,\\\".\\\") \\\". \\\"}.diplodoc-tab-list{display:flex;flex-wrap:wrap;margin-bottom:15px
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["
|
|
4
|
+
"sourcesContent": ["import {TabsController} from './runtime/TabsController';\n\nexport const TABS_CLASSNAME = 'diplodoc-tabs';\nexport const TABS_LIST_CLASSNAME = 'diplodoc-tab-list';\nexport const TAB_CLASSNAME = 'diplodoc-tab';\nexport const TAB_PANEL_CLASSNAME = 'diplodoc-tab-panel';\nexport const ACTIVE_CLASSNAME = 'active';\n\nexport const GROUP_DATA_KEY = 'data-diplodoc-group';\nexport const TAB_DATA_KEY = 'data-diplodoc-key';\nexport const TAB_DATA_ID = 'data-diplodoc-id';\n\nexport const SELECT_TAB_EVENT_NAME = 'selecttab';\n\nexport const DEFAULT_TABS_GROUP_PREFIX = 'defaultTabsGroup-';\n\nexport interface Tab {\n group?: string;\n key: string;\n}\n\nexport interface SelectedTabEvent {\n tab: Tab;\n currentTabId?: string;\n}\n\nexport const GLOBAL_SYMBOL: unique symbol = Symbol.for('diplodocTabs');\n\ndeclare global {\n interface Window {\n [GLOBAL_SYMBOL]: TabsController;\n }\n}\n", "export const getEventTarget = (event: Event) => {\n const path = event.composedPath();\n return Array.isArray(path) && path.length > 0 ? path[0] : event.target;\n};\n\nexport const isCustom = (event: Event) => {\n const target = getEventTarget(event);\n return !target || !(target as HTMLElement).matches;\n};\n\nexport const getClosestScrollableParent = (element: HTMLElement): HTMLElement | null => {\n if (element.scrollHeight - element.clientHeight > 1) {\n return element;\n }\n\n return element.parentElement ? getClosestScrollableParent(element.parentElement) : null;\n};\n", "import {\n ACTIVE_CLASSNAME,\n DEFAULT_TABS_GROUP_PREFIX,\n GROUP_DATA_KEY,\n SELECT_TAB_EVENT_NAME,\n SelectedTabEvent,\n TABS_CLASSNAME,\n TABS_LIST_CLASSNAME,\n TAB_CLASSNAME,\n TAB_DATA_ID,\n TAB_DATA_KEY,\n TAB_PANEL_CLASSNAME,\n Tab,\n} from '../common';\nimport {isCustom, getEventTarget, getClosestScrollableParent} from './utils';\n\nconst Selector = {\n TABS: `.${TABS_CLASSNAME}`,\n TAB_LIST: `.${TABS_LIST_CLASSNAME}`,\n TAB: `.${TAB_CLASSNAME}`,\n TAB_PANEL: `.${TAB_PANEL_CLASSNAME}`,\n};\n\nexport interface ISelectTabByIdOptions {\n scrollToElement: boolean;\n}\n\nexport class TabsController extends EventTarget {\n private _document: Document;\n\n constructor(document: Document) {\n super();\n\n this._document = document;\n this._document.addEventListener('click', (event) => {\n const target = getEventTarget(event) as HTMLElement;\n\n if (isCustom(event) || !this.isValidTabElement(target)) {\n return;\n }\n\n const tab = this.getTabDataFromHTMLElement(target);\n if (tab) {\n this._selectTab(tab, target);\n }\n });\n }\n\n selectTabById(id: string, options?: ISelectTabByIdOptions) {\n const target = this._document.querySelector(\n `${Selector.TAB}[${TAB_DATA_ID}=\"${id}\"]`,\n ) as HTMLElement;\n\n if (!target || !this.isValidTabElement(target)) {\n return;\n }\n\n const tab = this.getTabDataFromHTMLElement(target);\n if (tab) {\n this._selectTab(tab, target);\n }\n\n if (options?.scrollToElement) {\n target.scrollIntoView();\n }\n }\n\n selectTab(tab: Tab) {\n this._selectTab(tab);\n }\n\n private _selectTab(tab: Tab, targetTab?: HTMLElement) {\n const {group, key} = tab;\n\n if (!group) {\n return;\n }\n\n const oldTargetBoundingBox = targetTab?.getBoundingClientRect();\n\n const tabs = this._document.querySelectorAll(\n `${Selector.TABS}[${GROUP_DATA_KEY}=\"${group}\"] ${Selector.TAB}[${TAB_DATA_KEY}=\"${key}\"]`,\n );\n\n let found = 0;\n\n tabs.forEach((element) => {\n const htmlElem = element as HTMLElement;\n if (!this.isValidTabElement(htmlElem) || element.classList.contains(ACTIVE_CLASSNAME)) {\n return;\n }\n\n found++;\n\n const tab = element;\n const tabList = tab.parentNode;\n const tabsContainer = tabList?.parentNode;\n const allTabs = Array.from(tabsContainer?.querySelectorAll(Selector.TAB) || []);\n const allPanels = Array.from(tabsContainer?.querySelectorAll(Selector.TAB_PANEL) || []);\n const targetIndex = allTabs.indexOf(tab);\n\n allTabs.forEach((tab, i) => {\n const panel = allPanels[i];\n const isTargetTab = i === targetIndex;\n\n tab.classList.toggle(ACTIVE_CLASSNAME, isTargetTab);\n tab.setAttribute('aria-selected', isTargetTab.toString());\n tab.setAttribute('tabindex', isTargetTab ? '0' : '-1');\n panel.classList.toggle(ACTIVE_CLASSNAME, isTargetTab);\n });\n });\n\n if (found > 0) {\n if (targetTab && oldTargetBoundingBox) {\n const {left, top} = getCoords(targetTab);\n const scrollableParent = getClosestScrollableParent(targetTab);\n\n if (scrollableParent) {\n console.log(`>> ${scrollableParent.offsetTop - targetTab.offsetTop}`);\n\n scrollableParent.scrollTo(\n 0,\n (scrollableParent.offsetTop - targetTab.offsetTop) * -1,\n );\n }\n\n // scrollableParent?.scrollTo(\n // left - oldTargetBoundingBox.left,\n // top - oldTargetBoundingBox.top,\n // );\n }\n\n const eventTab: Tab = group.startsWith(DEFAULT_TABS_GROUP_PREFIX)\n ? {key: tab.key}\n : tab;\n this.dispatchEvent(\n new CustomEvent<SelectedTabEvent>(SELECT_TAB_EVENT_NAME, {\n detail: {tab: eventTab, currentTabId: targetTab?.dataset.diplodocId},\n }),\n );\n }\n }\n\n private isValidTabElement(element: HTMLElement) {\n const tabList =\n element.matches(Selector.TAB) && element.dataset.diplodocId\n ? element.closest(Selector.TAB_LIST)\n : null;\n return tabList?.closest(Selector.TABS);\n }\n\n private getTabDataFromHTMLElement(target: HTMLElement): Tab | null {\n const key = target.dataset.diplodocKey;\n const group = (target.closest(Selector.TABS) as HTMLElement)?.dataset.diplodocGroup;\n return key && group ? {group, key} : null;\n }\n}\n\n// TODO TODO TODO\nfunction getCoords(elem: HTMLElement) {\n const box = elem.getBoundingClientRect();\n\n const body = document.body;\n const docEl = document.documentElement;\n\n const scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;\n const scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;\n\n const clientTop = docEl.clientTop || body.clientTop || 0;\n const clientLeft = docEl.clientLeft || body.clientLeft || 0;\n\n const top = box.top + scrollTop - clientTop;\n const left = box.left + scrollLeft - clientLeft;\n\n return {top: Math.round(top), left: Math.round(left)};\n}\n", "export function inject_style(text) {\n if (typeof document !== 'undefined') {\n var style = document.createElement('style')\n var node = document.createTextNode(text)\n style.appendChild(node)\n document.head.appendChild(style)\n }\n}", "import { inject_style } from \"__style_helper__\"\ninject_style(\".diplodoc-tabs{margin-bottom:15px}.diplodoc-tabs ol{counter-reset:tabs-list}.diplodoc-tabs ol>li{counter-increment:tabs-list}.diplodoc-tabs ol>li:before{content:counters(tabs-list,\\\".\\\") \\\". \\\"}.diplodoc-tab-list{display:flex;flex-wrap:wrap;margin-bottom:15px}.diplodoc-tab{margin-bottom:-1px;margin-right:20px;border-bottom:2px solid transparent;padding:6px 0 7px;font-weight:700;outline:none;cursor:pointer;user-select:none;white-space:break-spaces}.diplodoc-tab:last-child{margin-right:0}.diplodoc-tab:hover,.diplodoc-tab:active{color:#004080}.diplodoc-tab.active{border-bottom-color:#027bf3}.diplodoc-tab-panel{display:none}.diplodoc-tab-panel:first-child{margin-top:0!important}.diplodoc-tab-panel:last-child{margin-bottom:0!important}.diplodoc-tab-panel.active{display:block}\")", "import {GLOBAL_SYMBOL} from '../common';\nimport {TabsController} from './TabsController';\nimport './scss/tabs.scss';\n\nif (typeof window !== 'undefined' && typeof document !== 'undefined' && !window[GLOBAL_SYMBOL]) {\n window[GLOBAL_SYMBOL] = new TabsController(document);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["document", "tab"]
|
|
7
7
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.diplodoc-tabs{margin-bottom:15px}.diplodoc-tabs ol{counter-reset:tabs-list}.diplodoc-tabs ol>li{counter-increment:tabs-list}.diplodoc-tabs ol>li::before{content:counters(tabs-list, ".") ". "}.diplodoc-tab-list{display:flex;flex-wrap:wrap;margin-bottom:15px;border-bottom:1px solid rgba(0,0,0,.07)}.diplodoc-tab{margin-bottom:-1px;margin-right:20px;border-bottom:2px solid rgba(0,0,0,0);padding:6px 0 7px 0;font-weight:700;outline:none;cursor:pointer;user-select:none;white-space:break-spaces}.diplodoc-tab:last-child{margin-right:0}.diplodoc-tab:hover,.diplodoc-tab:active{color:#004080}.diplodoc-tab.active{border-bottom-color:#027bf3}.diplodoc-tab-panel{display:none}.diplodoc-tab-panel:first-child{margin-top:0 !important}.diplodoc-tab-panel:last-child{margin-bottom:0 !important}.diplodoc-tab-panel.active{display:block}/*# sourceMappingURL=styles.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sourceRoot":"","sources":["../src/runtime/scss/tabs.scss"],"names":[],"mappings":"AAAA,eACI,mBAEA,kBACI,wBAEA,qBACI,4BAEA,6BACI,sCAMhB,mBACI,aACA,eACA,mBAEA,wCAGJ,cACI,mBACA,kBACA,sCAEA,oBACA,gBACA,aACA,eACA,iBACA,yBAEA,yBACI,eAGJ,yCACI,cAGJ,qBACI,4BAIR,oBACI,aAEA,gCACI,wBAGJ,+BACI,2BAGJ,2BACI","file":"styles.css"}
|
package/runtime/utils.d.ts
CHANGED