@diplodoc/tabs-extension 3.4.0 → 3.5.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/build/common.d.ts +24 -10
- package/build/plugin/find.d.ts +12 -0
- package/build/plugin/generate.d.ts +4 -0
- package/build/plugin/index.js +480 -183
- package/build/plugin/index.js.map +4 -4
- package/build/plugin/transform.d.ts +6 -9
- package/build/plugin/types.d.ts +12 -0
- package/build/plugin/{utils.d.ts → utils/index.d.ts} +3 -3
- package/build/plugin/utils/strings.d.ts +3 -0
- package/build/plugin/utils/tabs.d.ts +7 -0
- package/build/plugin/variants/accordion.d.ts +2 -0
- package/build/plugin/variants/dropdown.d.ts +2 -0
- package/build/plugin/variants/index.d.ts +3 -0
- package/build/plugin/variants/radio.d.ts +2 -0
- package/build/plugin/variants/regular.d.ts +2 -0
- package/build/plugin/variants/types.d.ts +15 -0
- package/build/react/index.js.map +2 -2
- package/build/runtime/TabsController.d.ts +8 -3
- package/build/runtime/index.css +1 -1
- package/build/runtime/index.css.map +2 -2
- package/build/runtime/index.js +1 -1
- package/build/runtime/index.js.map +3 -3
- package/package.json +1 -1
- package/build/plugin/getTabId.d.ts +0 -6
- /package/build/plugin/{copyRuntimeFiles.d.ts → utils/files.d.ts} +0 -0
package/build/plugin/index.js
CHANGED
|
@@ -80,28 +80,32 @@ __export(plugin_exports, {
|
|
|
80
80
|
});
|
|
81
81
|
module.exports = __toCommonJS(plugin_exports);
|
|
82
82
|
|
|
83
|
-
// src/plugin/transform.ts
|
|
84
|
-
var import_token = __toESM(require("markdown-it/lib/token"));
|
|
85
|
-
|
|
86
83
|
// src/common.ts
|
|
84
|
+
var TAB_RE = /`?{% list tabs .*?%}`?/;
|
|
87
85
|
var TABS_CLASSNAME = "yfm-tabs";
|
|
88
|
-
var TABS_VERTICAL_CLASSNAME = "yfm-tabs-vertical";
|
|
89
|
-
var TABS_LIST_CLASSNAME = "yfm-tab-list";
|
|
90
86
|
var TAB_CLASSNAME = "yfm-tab";
|
|
91
87
|
var TAB_PANEL_CLASSNAME = "yfm-tab-panel";
|
|
88
|
+
var TABS_LIST_CLASSNAME = "yfm-tab-list";
|
|
92
89
|
var ACTIVE_CLASSNAME = "active";
|
|
93
|
-
var
|
|
94
|
-
var
|
|
90
|
+
var TAB_GROUP_CLASSNAME = "yfm-tab-group";
|
|
91
|
+
var TAB_ACTIVE_KEY = "data-diplodoc-is-active";
|
|
95
92
|
var GROUP_DATA_KEY = "data-diplodoc-group";
|
|
96
93
|
var TAB_DATA_KEY = "data-diplodoc-key";
|
|
94
|
+
var TAB_DATA_VARIANT = "data-diplodoc-variant";
|
|
97
95
|
var TAB_DATA_ID = "data-diplodoc-id";
|
|
98
|
-
var TAB_DATA_VERTICAL_TAB = "data-diplodoc-vertical-tab";
|
|
99
|
-
var TAB_ACTIVE_KEY = "data-diplodoc-is-active";
|
|
100
96
|
var DEFAULT_TABS_GROUP_PREFIX = "defaultTabsGroup-";
|
|
101
97
|
var ACTIVE_TAB_TEXT = "{selected}";
|
|
98
|
+
var TAB_FORCED_OPEN = "data-diplodoc-forced";
|
|
99
|
+
var TABS_DROPDOWN_CLASSNAME = "yfm-tabs-dropdown";
|
|
100
|
+
var TABS_DROPDOWN_MENU_CLASSNAME = "yfm-tabs-dropdown-menu";
|
|
101
|
+
var TABS_DROPDOWN_SELECT = "yfm-tabs-dropdown-select";
|
|
102
|
+
var TABS_ACCORDION_CLASSNAME = "yfm-tabs-accordion";
|
|
103
|
+
var TABS_RADIO_CLASSNAME = "yfm-tabs-vertical";
|
|
104
|
+
var VERTICAL_TAB_CLASSNAME = "yfm-vertical-tab";
|
|
105
|
+
var TAB_DATA_VERTICAL_TAB = "data-diplodoc-vertical-tab";
|
|
102
106
|
var GLOBAL_SYMBOL = Symbol.for("diplodocTabs");
|
|
103
107
|
|
|
104
|
-
// src/plugin/utils.ts
|
|
108
|
+
// src/plugin/utils/strings.ts
|
|
105
109
|
function generateID() {
|
|
106
110
|
const id = Math.random().toString(36).substr(2, 8);
|
|
107
111
|
return id.substring(id.length - 8);
|
|
@@ -112,47 +116,8 @@ function trim(target) {
|
|
|
112
116
|
function unquote(target) {
|
|
113
117
|
return target.match(/^(["']).*\1$/) ? target.slice(1, -1) : target;
|
|
114
118
|
}
|
|
115
|
-
function addHiddenProperty(box, field, value) {
|
|
116
|
-
if (!(field in box)) {
|
|
117
|
-
Object.defineProperty(box, field, {
|
|
118
|
-
enumerable: false,
|
|
119
|
-
value
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
return box;
|
|
123
|
-
}
|
|
124
119
|
|
|
125
|
-
// src/plugin/
|
|
126
|
-
var PATH_TO_RUNTIME = "../runtime";
|
|
127
|
-
function copyRuntimeFiles({
|
|
128
|
-
runtimeJsPath,
|
|
129
|
-
runtimeCssPath,
|
|
130
|
-
output
|
|
131
|
-
}, cache) {
|
|
132
|
-
const { join, resolve } = dynrequire("node:path");
|
|
133
|
-
const runtimeFiles = {
|
|
134
|
-
"index.js": runtimeJsPath,
|
|
135
|
-
"index.css": runtimeCssPath
|
|
136
|
-
};
|
|
137
|
-
for (const [originFile, outputFile] of Object.entries(runtimeFiles)) {
|
|
138
|
-
const file = join(PATH_TO_RUNTIME, originFile);
|
|
139
|
-
if (!cache.has(file)) {
|
|
140
|
-
cache.add(file);
|
|
141
|
-
copyFile(resolve(__dirname, file), join(output, outputFile));
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
function copyFile(from, to) {
|
|
146
|
-
const { mkdirSync, copyFileSync } = dynrequire("node:fs");
|
|
147
|
-
const { dirname } = dynrequire("node:path");
|
|
148
|
-
mkdirSync(dirname(to), { recursive: true });
|
|
149
|
-
copyFileSync(from, to);
|
|
150
|
-
}
|
|
151
|
-
function dynrequire(module) {
|
|
152
|
-
return eval(`require('${module}')`);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// src/plugin/getTabId.ts
|
|
120
|
+
// src/plugin/utils/tabs.ts
|
|
156
121
|
var import_github_slugger = __toESM(require_github_slugger());
|
|
157
122
|
var CUSTOM_ID_REGEXP = /\[?{ ?#(\S+) ?}]?/;
|
|
158
123
|
var sluggersStorage = /* @__PURE__ */ new Map();
|
|
@@ -183,6 +148,10 @@ function getTabId(tab, { runId }) {
|
|
|
183
148
|
}
|
|
184
149
|
return slugger.slug(getRawId(tab));
|
|
185
150
|
}
|
|
151
|
+
function isTabSelected(tab) {
|
|
152
|
+
const { name } = tab;
|
|
153
|
+
return name.includes(ACTIVE_TAB_TEXT);
|
|
154
|
+
}
|
|
186
155
|
function getTabKey(tab) {
|
|
187
156
|
return encodeURIComponent(getRawId(tab)).toLocaleLowerCase();
|
|
188
157
|
}
|
|
@@ -194,79 +163,49 @@ function getRawId(tab) {
|
|
|
194
163
|
return customAnchor || name;
|
|
195
164
|
}
|
|
196
165
|
|
|
197
|
-
// src/plugin/
|
|
198
|
-
var
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (nestedLevel) {
|
|
215
|
-
pending.tokens.push(token);
|
|
216
|
-
} else {
|
|
217
|
-
pending = { name: "", tokens: [], listItem: token };
|
|
218
|
-
}
|
|
219
|
-
break;
|
|
220
|
-
case "list_item_close":
|
|
221
|
-
if (nestedLevel) {
|
|
222
|
-
pending.tokens.push(token);
|
|
223
|
-
} else {
|
|
224
|
-
tabs.push(pending);
|
|
225
|
-
}
|
|
226
|
-
break;
|
|
227
|
-
case "ordered_list_close":
|
|
228
|
-
case "bullet_list_close":
|
|
229
|
-
if (!nestedLevel) {
|
|
230
|
-
return {
|
|
231
|
-
tabs,
|
|
232
|
-
index: i
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
nestedLevel--;
|
|
236
|
-
pending.tokens.push(token);
|
|
237
|
-
break;
|
|
238
|
-
case "paragraph_open":
|
|
239
|
-
if (i === closeTokenIdx && tokens[i + 1].content && tokens[i + 1].content.trim() === "{% endlist %}") {
|
|
240
|
-
if (pending && !nestedLevel) {
|
|
241
|
-
tabs.push(pending);
|
|
242
|
-
}
|
|
243
|
-
return {
|
|
244
|
-
tabs,
|
|
245
|
-
index: i + 2
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
if (!pending.name && tokens[i + 1].type === "inline") {
|
|
249
|
-
pending.name = tokens[i + 1].content;
|
|
250
|
-
i += 2;
|
|
251
|
-
} else {
|
|
252
|
-
pending.tokens.push(token);
|
|
253
|
-
}
|
|
254
|
-
break;
|
|
255
|
-
default:
|
|
256
|
-
pending.tokens.push(token);
|
|
166
|
+
// src/plugin/utils/files.ts
|
|
167
|
+
var PATH_TO_RUNTIME = "../runtime";
|
|
168
|
+
function copyRuntimeFiles({
|
|
169
|
+
runtimeJsPath,
|
|
170
|
+
runtimeCssPath,
|
|
171
|
+
output
|
|
172
|
+
}, cache) {
|
|
173
|
+
const { join, resolve } = dynrequire("node:path");
|
|
174
|
+
const runtimeFiles = {
|
|
175
|
+
"index.js": runtimeJsPath,
|
|
176
|
+
"index.css": runtimeCssPath
|
|
177
|
+
};
|
|
178
|
+
for (const [originFile, outputFile] of Object.entries(runtimeFiles)) {
|
|
179
|
+
const file = join(PATH_TO_RUNTIME, originFile);
|
|
180
|
+
if (!cache.has(file)) {
|
|
181
|
+
cache.add(file);
|
|
182
|
+
copyFile(resolve(__dirname, file), join(output, outputFile));
|
|
257
183
|
}
|
|
258
|
-
i++;
|
|
259
184
|
}
|
|
260
|
-
return {
|
|
261
|
-
tabs,
|
|
262
|
-
index: i
|
|
263
|
-
};
|
|
264
185
|
}
|
|
265
|
-
function
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
186
|
+
function copyFile(from, to) {
|
|
187
|
+
const { mkdirSync, copyFileSync } = dynrequire("node:fs");
|
|
188
|
+
const { dirname } = dynrequire("node:path");
|
|
189
|
+
mkdirSync(dirname(to), { recursive: true });
|
|
190
|
+
copyFileSync(from, to);
|
|
191
|
+
}
|
|
192
|
+
function dynrequire(module) {
|
|
193
|
+
return eval(`require('${module}')`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/plugin/utils/index.ts
|
|
197
|
+
function addHiddenProperty(box, field, value) {
|
|
198
|
+
if (!(field in box)) {
|
|
199
|
+
Object.defineProperty(box, field, {
|
|
200
|
+
enumerable: false,
|
|
201
|
+
value
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
return box;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// src/plugin/variants/regular.ts
|
|
208
|
+
var regular = (tabs, state, { containerClasses, tabsGroup, runId, variant: orientation }) => {
|
|
270
209
|
var _a, _b;
|
|
271
210
|
const tabsTokens = [];
|
|
272
211
|
const tabListTokens = [];
|
|
@@ -276,34 +215,31 @@ function insertTabs(tabs, state, align, { start, end }, {
|
|
|
276
215
|
const tabListOpen = new state.Token("tab-list_open", "div", 1);
|
|
277
216
|
const tabListClose = new state.Token("tab-list_close", "div", -1);
|
|
278
217
|
if (tabs.length) {
|
|
279
|
-
const [
|
|
280
|
-
if (
|
|
218
|
+
const [start] = (_a = tabs[0].listItem.map) != null ? _a : [null];
|
|
219
|
+
if (start == null) {
|
|
281
220
|
throw new Error("failed to parse line mapping");
|
|
282
221
|
}
|
|
283
|
-
const [_,
|
|
284
|
-
if (
|
|
222
|
+
const [_, end] = (_b = tabs[tabs.length - 1].listItem.map) != null ? _b : [null, null];
|
|
223
|
+
if (end == null) {
|
|
285
224
|
throw new Error("failed to parse line mapping");
|
|
286
225
|
}
|
|
287
|
-
tabListOpen.map = [
|
|
226
|
+
tabListOpen.map = [start, end];
|
|
288
227
|
}
|
|
289
228
|
tabsOpen.block = true;
|
|
290
229
|
tabsClose.block = true;
|
|
291
230
|
tabListOpen.block = true;
|
|
292
231
|
tabListClose.block = true;
|
|
293
|
-
const areTabsVerticalClass = align === "radio" && TABS_VERTICAL_CLASSNAME;
|
|
294
232
|
const activeTabsCount = tabs.filter(isTabSelected).length;
|
|
295
233
|
if (activeTabsCount > 1) {
|
|
296
234
|
throw new Error("Unable to render tabs with more than 1 active element");
|
|
297
235
|
}
|
|
298
236
|
const hasDefaultOpenTab = activeTabsCount !== 0;
|
|
299
|
-
tabsOpen.attrSet(
|
|
300
|
-
"class",
|
|
301
|
-
[TABS_CLASSNAME, containerClasses, areTabsVerticalClass].filter(Boolean).join(" ")
|
|
302
|
-
);
|
|
237
|
+
tabsOpen.attrSet("class", [TABS_CLASSNAME, containerClasses].filter(Boolean).join(" "));
|
|
303
238
|
tabsOpen.attrSet(GROUP_DATA_KEY, tabsGroup);
|
|
239
|
+
tabsOpen.attrSet(TAB_DATA_VARIANT, "regular");
|
|
304
240
|
tabListOpen.attrSet("class", TABS_LIST_CLASSNAME);
|
|
305
241
|
tabListOpen.attrSet("role", "tablist");
|
|
306
|
-
if (
|
|
242
|
+
if (orientation === "radio") {
|
|
307
243
|
tabsTokens.push(tabsOpen);
|
|
308
244
|
}
|
|
309
245
|
for (let i = 0; i < tabs.length; i++) {
|
|
@@ -322,7 +258,7 @@ function insertTabs(tabs, state, align, { start, end }, {
|
|
|
322
258
|
const tabId = getTabId(tab, { runId });
|
|
323
259
|
const tabKey = getTabKey(tab);
|
|
324
260
|
const didTabHasActiveAttr = isTabSelected(tab);
|
|
325
|
-
const isTabActive = hasDefaultOpenTab ? didTabHasActiveAttr :
|
|
261
|
+
const isTabActive = hasDefaultOpenTab ? didTabHasActiveAttr : i === 0;
|
|
326
262
|
tab.name = getName(tab);
|
|
327
263
|
const tabPanelId = generateID();
|
|
328
264
|
verticalTabInput.block = true;
|
|
@@ -350,13 +286,13 @@ function insertTabs(tabs, state, align, { start, end }, {
|
|
|
350
286
|
tabPanelOpen.attrSet("role", "tabpanel");
|
|
351
287
|
tabPanelOpen.attrSet("aria-labelledby", tabId);
|
|
352
288
|
tabPanelOpen.attrSet("data-title", tab.name);
|
|
353
|
-
if (
|
|
289
|
+
if (orientation === "radio") {
|
|
354
290
|
tabOpen.attrSet(TAB_DATA_VERTICAL_TAB, "true");
|
|
355
291
|
tabOpen.attrJoin("class", VERTICAL_TAB_CLASSNAME);
|
|
356
292
|
}
|
|
357
293
|
if (isTabActive) {
|
|
358
|
-
if (
|
|
359
|
-
tabOpen.attrSet(
|
|
294
|
+
if (orientation === "radio") {
|
|
295
|
+
tabOpen.attrSet(TAB_FORCED_OPEN, "true");
|
|
360
296
|
verticalTabInput.attrSet("checked", "true");
|
|
361
297
|
tabPanelOpen.attrJoin("class", ACTIVE_CLASSNAME);
|
|
362
298
|
} else {
|
|
@@ -366,7 +302,7 @@ function insertTabs(tabs, state, align, { start, end }, {
|
|
|
366
302
|
tabPanelOpen.attrJoin("class", ACTIVE_CLASSNAME);
|
|
367
303
|
}
|
|
368
304
|
}
|
|
369
|
-
if (
|
|
305
|
+
if (orientation === "radio") {
|
|
370
306
|
tabsTokens.push(
|
|
371
307
|
tabOpen,
|
|
372
308
|
verticalTabInput,
|
|
@@ -381,22 +317,300 @@ function insertTabs(tabs, state, align, { start, end }, {
|
|
|
381
317
|
tabPanelsTokens.push(tabPanelOpen, ...tabs[i].tokens, tabPanelClose);
|
|
382
318
|
}
|
|
383
319
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
320
|
+
tabsTokens.push(tabsOpen);
|
|
321
|
+
tabsTokens.push(tabListOpen);
|
|
322
|
+
tabsTokens.push(...tabListTokens);
|
|
323
|
+
tabsTokens.push(tabListClose);
|
|
324
|
+
tabsTokens.push(...tabPanelsTokens);
|
|
325
|
+
tabsTokens.push(tabsClose);
|
|
326
|
+
return tabsTokens;
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
// src/plugin/variants/radio.ts
|
|
330
|
+
var radio = (tabs, state, { containerClasses, tabsGroup, runId }) => {
|
|
331
|
+
var _a, _b;
|
|
332
|
+
const tabsTokens = [];
|
|
333
|
+
const tabsOpen = new state.Token("tabs_open", "div", 1);
|
|
334
|
+
const tabsClose = new state.Token("tabs_close", "div", -1);
|
|
335
|
+
if (tabs.length) {
|
|
336
|
+
const [start] = (_a = tabs[0].listItem.map) != null ? _a : [null];
|
|
337
|
+
if (start == null) {
|
|
338
|
+
throw new Error("failed to parse line mapping");
|
|
339
|
+
}
|
|
340
|
+
const [_, end] = (_b = tabs[tabs.length - 1].listItem.map) != null ? _b : [null, null];
|
|
341
|
+
if (end == null) {
|
|
342
|
+
throw new Error("failed to parse line mapping");
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
tabsOpen.block = true;
|
|
346
|
+
tabsClose.block = true;
|
|
347
|
+
const activeTabsCount = tabs.filter(isTabSelected).length;
|
|
348
|
+
if (activeTabsCount > 1) {
|
|
349
|
+
throw new Error("Unable to render tabs with more than 1 active element");
|
|
350
|
+
}
|
|
351
|
+
tabsOpen.attrSet(
|
|
352
|
+
"class",
|
|
353
|
+
[TABS_CLASSNAME, containerClasses, TABS_RADIO_CLASSNAME].filter(Boolean).join(" ")
|
|
354
|
+
);
|
|
355
|
+
tabsOpen.attrSet(GROUP_DATA_KEY, tabsGroup);
|
|
356
|
+
tabsOpen.attrSet(TAB_DATA_VARIANT, "radio");
|
|
357
|
+
tabsTokens.push(tabsOpen);
|
|
358
|
+
for (let i = 0; i < tabs.length; i++) {
|
|
359
|
+
const tabOpen = new state.Token("tab_open", "div", 1);
|
|
360
|
+
const tabInline = new state.Token("inline", "", 0);
|
|
361
|
+
const tabText = new state.Token("text", "", 0);
|
|
362
|
+
const tabClose = new state.Token("tab_close", "div", -1);
|
|
363
|
+
const tabPanelOpen = new state.Token("tab-panel_open", "div", 1);
|
|
364
|
+
const tabPanelClose = new state.Token("tab-panel_close", "div", -1);
|
|
365
|
+
const verticalTabInput = new state.Token("tab-input", "input", 0);
|
|
366
|
+
const verticalTabLabelOpen = new state.Token("tab-label_open", "label", 1);
|
|
367
|
+
const verticalTabLabelClose = new state.Token("tab-label_close", "label", -1);
|
|
368
|
+
tabOpen.map = tabs[i].listItem.map;
|
|
369
|
+
tabOpen.markup = tabs[i].listItem.markup;
|
|
370
|
+
const tab = tabs[i];
|
|
371
|
+
const tabId = getTabId(tab, { runId });
|
|
372
|
+
const tabKey = getTabKey(tab);
|
|
373
|
+
const didTabHasActiveAttr = isTabSelected(tab);
|
|
374
|
+
tab.name = getName(tab);
|
|
375
|
+
const tabPanelId = generateID();
|
|
376
|
+
verticalTabInput.block = true;
|
|
377
|
+
verticalTabInput.attrJoin("class", "radio");
|
|
378
|
+
verticalTabInput.attrSet("type", "radio");
|
|
379
|
+
tabOpen.map = tabs[i].listItem.map;
|
|
380
|
+
tabOpen.markup = tabs[i].listItem.markup;
|
|
381
|
+
tabText.content = tabs[i].name;
|
|
382
|
+
tabInline.children = [tabText];
|
|
383
|
+
tabOpen.block = true;
|
|
384
|
+
tabClose.block = true;
|
|
385
|
+
tabPanelOpen.block = true;
|
|
386
|
+
tabPanelClose.block = true;
|
|
387
|
+
tabOpen.attrSet(TAB_DATA_ID, tabId);
|
|
388
|
+
tabOpen.attrSet(TAB_DATA_KEY, tabKey);
|
|
389
|
+
tabOpen.attrSet(
|
|
390
|
+
"class",
|
|
391
|
+
[TAB_CLASSNAME, TAB_GROUP_CLASSNAME, VERTICAL_TAB_CLASSNAME].join(" ")
|
|
392
|
+
);
|
|
393
|
+
tabOpen.attrSet("role", "tab");
|
|
394
|
+
tabOpen.attrSet("aria-controls", tabPanelId);
|
|
395
|
+
tabOpen.attrSet("aria-selected", "false");
|
|
396
|
+
tabOpen.attrSet("tabindex", i === 0 ? "0" : "-1");
|
|
397
|
+
tabOpen.attrSet(TAB_ACTIVE_KEY, "false");
|
|
398
|
+
tabPanelOpen.attrSet("id", tabPanelId);
|
|
399
|
+
tabPanelOpen.attrSet("class", TAB_PANEL_CLASSNAME);
|
|
400
|
+
tabPanelOpen.attrSet("role", "tabpanel");
|
|
401
|
+
tabPanelOpen.attrSet("aria-labelledby", tabId);
|
|
402
|
+
tabPanelOpen.attrSet("data-title", tab.name);
|
|
403
|
+
tabOpen.attrSet(TAB_DATA_VERTICAL_TAB, "true");
|
|
404
|
+
if (didTabHasActiveAttr) {
|
|
405
|
+
tabOpen.attrSet(TAB_FORCED_OPEN, "true");
|
|
406
|
+
verticalTabInput.attrSet("checked", "true");
|
|
407
|
+
tabPanelOpen.attrJoin("class", ACTIVE_CLASSNAME);
|
|
408
|
+
}
|
|
409
|
+
tabsTokens.push(
|
|
410
|
+
tabOpen,
|
|
411
|
+
verticalTabInput,
|
|
412
|
+
verticalTabLabelOpen,
|
|
413
|
+
tabInline,
|
|
414
|
+
verticalTabLabelClose,
|
|
415
|
+
tabClose
|
|
416
|
+
);
|
|
417
|
+
tabsTokens.push(tabPanelOpen, ...tabs[i].tokens, tabPanelClose);
|
|
390
418
|
}
|
|
391
419
|
tabsTokens.push(tabsClose);
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
420
|
+
return tabsTokens;
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
// src/plugin/variants/dropdown.ts
|
|
424
|
+
var dropdown = (tabs, state, { containerClasses, tabsGroup, runId }) => {
|
|
425
|
+
var _a, _b;
|
|
426
|
+
const dropdownTokens = [];
|
|
427
|
+
const dropdownOpen = new state.Token("dropdown_open", "div", 1);
|
|
428
|
+
const dropdownClose = new state.Token("dropdown_close", "div", -1);
|
|
429
|
+
const dropdownSelectOpen = new state.Token("dropdown-select_open", "div", 1);
|
|
430
|
+
const dropdownSelectInline = new state.Token("inline", "", 0);
|
|
431
|
+
const dropdownSelectText = new state.Token("text", "", 0);
|
|
432
|
+
const dropdownSelectClose = new state.Token("dropdown-select_open", "div", -1);
|
|
433
|
+
if (tabs.length) {
|
|
434
|
+
const [start] = (_a = tabs[0].listItem.map) != null ? _a : [null];
|
|
435
|
+
if (start == null) {
|
|
436
|
+
throw new Error("failed to parse line mapping");
|
|
437
|
+
}
|
|
438
|
+
const [_, end] = (_b = tabs[tabs.length - 1].listItem.map) != null ? _b : [null, null];
|
|
439
|
+
if (end == null) {
|
|
440
|
+
throw new Error("failed to parse line mapping");
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
dropdownOpen.block = true;
|
|
444
|
+
dropdownClose.block = true;
|
|
445
|
+
dropdownSelectOpen.block = true;
|
|
446
|
+
dropdownSelectClose.block = true;
|
|
447
|
+
const [activeTab, ...restActiveTabs] = tabs.filter(isTabSelected);
|
|
448
|
+
if (restActiveTabs.length) {
|
|
449
|
+
throw new Error("Unable to dropdown tabs with more than 1 active element");
|
|
450
|
+
}
|
|
451
|
+
dropdownOpen.attrSet(
|
|
452
|
+
"class",
|
|
453
|
+
[TABS_CLASSNAME, containerClasses, TABS_DROPDOWN_CLASSNAME].filter(Boolean).join(" ")
|
|
454
|
+
);
|
|
455
|
+
dropdownOpen.attrSet(GROUP_DATA_KEY, tabsGroup);
|
|
456
|
+
dropdownOpen.attrSet(TAB_DATA_VARIANT, "dropdown");
|
|
457
|
+
dropdownSelectOpen.attrSet("role", "tablist");
|
|
458
|
+
dropdownSelectOpen.attrSet("class", TABS_DROPDOWN_SELECT);
|
|
459
|
+
if (activeTab) {
|
|
460
|
+
dropdownSelectOpen.attrJoin("class", "filled");
|
|
461
|
+
}
|
|
462
|
+
dropdownSelectText.content = activeTab ? activeTab.name : "-";
|
|
463
|
+
dropdownSelectInline.children = [dropdownSelectText];
|
|
464
|
+
dropdownTokens.push(
|
|
465
|
+
dropdownOpen,
|
|
466
|
+
dropdownSelectOpen,
|
|
467
|
+
dropdownSelectInline,
|
|
468
|
+
dropdownSelectClose
|
|
469
|
+
);
|
|
470
|
+
const dropdownMenuOpen = new state.Token("dropdown-menu_open", "ul", 1);
|
|
471
|
+
const dropdownMenuClose = new state.Token("dropdown-menu_close", "ul", -1);
|
|
472
|
+
dropdownMenuOpen.attrSet("class", TABS_DROPDOWN_MENU_CLASSNAME);
|
|
473
|
+
const menuTokens = tabs.flatMap((tab) => {
|
|
474
|
+
const menuListItemOpen = new state.Token("dropdown-menu-item_open", "li", 1);
|
|
475
|
+
const menuListItemClose = new state.Token("dropdown-menu-item_close", "li", -1);
|
|
476
|
+
const menuListItemText = new state.Token("text", "", 0);
|
|
477
|
+
const menuListItemInline = new state.Token("inline", "", 0);
|
|
478
|
+
const tabId = getTabId(tab, { runId });
|
|
479
|
+
const tabKey = getTabKey(tab);
|
|
480
|
+
const isActive = tab === activeTab;
|
|
481
|
+
menuListItemOpen.attrSet(
|
|
482
|
+
"class",
|
|
483
|
+
[TAB_CLASSNAME, isActive && ACTIVE_CLASSNAME].filter(Boolean).join(" ")
|
|
484
|
+
);
|
|
485
|
+
menuListItemOpen.attrSet(TAB_DATA_ID, tabId);
|
|
486
|
+
menuListItemOpen.attrSet(TAB_DATA_KEY, tabKey);
|
|
487
|
+
menuListItemOpen.attrSet("aria-selected", String(isActive));
|
|
488
|
+
menuListItemText.content = tab.name;
|
|
489
|
+
menuListItemInline.children = [menuListItemText];
|
|
490
|
+
return [menuListItemOpen, menuListItemInline, menuListItemClose];
|
|
491
|
+
});
|
|
492
|
+
dropdownTokens.push(dropdownMenuOpen, ...menuTokens, dropdownMenuClose);
|
|
493
|
+
for (let i = 0; i < tabs.length; i++) {
|
|
494
|
+
const tabPanelOpen = new state.Token("tab-panel_open", "div", 1);
|
|
495
|
+
const tabPanelClose = new state.Token("tab-panel_close", "div", -1);
|
|
496
|
+
const tab = tabs[i];
|
|
497
|
+
const tabId = getTabId(tab, { runId });
|
|
498
|
+
const didTabHasActiveAttr = isTabSelected(tab);
|
|
499
|
+
tab.name = getName(tab);
|
|
500
|
+
const tabPanelId = generateID();
|
|
501
|
+
tabPanelOpen.block = true;
|
|
502
|
+
tabPanelClose.block = true;
|
|
503
|
+
tabPanelOpen.attrSet("id", tabPanelId);
|
|
504
|
+
tabPanelOpen.attrSet("class", TAB_PANEL_CLASSNAME);
|
|
505
|
+
tabPanelOpen.attrSet("role", "tabpanel");
|
|
506
|
+
tabPanelOpen.attrSet("aria-labelledby", tabId);
|
|
507
|
+
tabPanelOpen.attrSet("data-title", tab.name);
|
|
508
|
+
if (didTabHasActiveAttr) {
|
|
509
|
+
tabPanelOpen.attrJoin("class", ACTIVE_CLASSNAME);
|
|
510
|
+
}
|
|
511
|
+
dropdownTokens.push(tabPanelOpen, ...tabs[i].tokens, tabPanelClose);
|
|
512
|
+
}
|
|
513
|
+
dropdownTokens.push(dropdownClose);
|
|
514
|
+
return dropdownTokens;
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
// src/plugin/variants/accordion.ts
|
|
518
|
+
var accordion = (tabs, state, { containerClasses, tabsGroup, runId }) => {
|
|
519
|
+
var _a, _b;
|
|
520
|
+
const tabsTokens = [];
|
|
521
|
+
const tabsOpen = new state.Token("tabs_open", "div", 1);
|
|
522
|
+
const tabsClose = new state.Token("tabs_close", "div", -1);
|
|
523
|
+
if (tabs.length) {
|
|
524
|
+
const [start] = (_a = tabs[0].listItem.map) != null ? _a : [null];
|
|
525
|
+
if (start == null) {
|
|
526
|
+
throw new Error("failed to parse line mapping");
|
|
527
|
+
}
|
|
528
|
+
const [_, end] = (_b = tabs[tabs.length - 1].listItem.map) != null ? _b : [null, null];
|
|
529
|
+
if (end == null) {
|
|
530
|
+
throw new Error("failed to parse line mapping");
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
tabsOpen.block = true;
|
|
534
|
+
tabsClose.block = true;
|
|
535
|
+
const activeTabsCount = tabs.filter(isTabSelected).length;
|
|
536
|
+
if (activeTabsCount > 1) {
|
|
537
|
+
throw new Error("Unable to render tabs with more than 1 active element");
|
|
538
|
+
}
|
|
539
|
+
tabsOpen.attrSet(
|
|
540
|
+
"class",
|
|
541
|
+
[TABS_CLASSNAME, containerClasses, TABS_ACCORDION_CLASSNAME].filter(Boolean).join(" ")
|
|
542
|
+
);
|
|
543
|
+
tabsOpen.attrSet(GROUP_DATA_KEY, tabsGroup);
|
|
544
|
+
tabsOpen.attrSet(TAB_DATA_VARIANT, "accordion" /* Accordion */);
|
|
545
|
+
tabsTokens.push(tabsOpen);
|
|
546
|
+
for (let i = 0; i < tabs.length; i++) {
|
|
547
|
+
const tabOpen = new state.Token("tab_open", "div", 1);
|
|
548
|
+
const tabInline = new state.Token("inline", "", 0);
|
|
549
|
+
const tabText = new state.Token("text", "", 0);
|
|
550
|
+
const tabClose = new state.Token("tab_close", "div", -1);
|
|
551
|
+
const tabPanelOpen = new state.Token("tab-panel_open", "div", 1);
|
|
552
|
+
const tabPanelClose = new state.Token("tab-panel_close", "div", -1);
|
|
553
|
+
tabOpen.map = tabs[i].listItem.map;
|
|
554
|
+
tabOpen.markup = tabs[i].listItem.markup;
|
|
555
|
+
const tab = tabs[i];
|
|
556
|
+
const tabId = getTabId(tab, { runId });
|
|
557
|
+
const tabKey = getTabKey(tab);
|
|
558
|
+
const didTabHasActiveAttr = isTabSelected(tab);
|
|
559
|
+
tab.name = getName(tab);
|
|
560
|
+
const tabPanelId = generateID();
|
|
561
|
+
tabOpen.map = tabs[i].listItem.map;
|
|
562
|
+
tabOpen.markup = tabs[i].listItem.markup;
|
|
563
|
+
tabText.content = tabs[i].name;
|
|
564
|
+
tabInline.children = [tabText];
|
|
565
|
+
tabOpen.block = true;
|
|
566
|
+
tabClose.block = true;
|
|
567
|
+
tabPanelOpen.block = true;
|
|
568
|
+
tabPanelClose.block = true;
|
|
569
|
+
tabOpen.attrSet(TAB_DATA_ID, tabId);
|
|
570
|
+
tabOpen.attrSet(TAB_DATA_KEY, tabKey);
|
|
571
|
+
tabOpen.attrSet("class", [TAB_CLASSNAME, TAB_GROUP_CLASSNAME].join(" "));
|
|
572
|
+
tabOpen.attrSet("role", "tab");
|
|
573
|
+
tabOpen.attrSet("aria-controls", tabPanelId);
|
|
574
|
+
tabOpen.attrSet("aria-selected", "false");
|
|
575
|
+
tabOpen.attrSet("tabindex", i === 0 ? "0" : "-1");
|
|
576
|
+
tabOpen.attrSet(TAB_ACTIVE_KEY, "false");
|
|
577
|
+
tabPanelOpen.attrSet("id", tabPanelId);
|
|
578
|
+
tabPanelOpen.attrSet("class", TAB_PANEL_CLASSNAME);
|
|
579
|
+
tabPanelOpen.attrSet("role", "tabpanel");
|
|
580
|
+
tabPanelOpen.attrSet("aria-labelledby", tabId);
|
|
581
|
+
tabPanelOpen.attrSet("data-title", tab.name);
|
|
582
|
+
if (didTabHasActiveAttr) {
|
|
583
|
+
tabPanelOpen.attrSet(TAB_FORCED_OPEN, "true");
|
|
584
|
+
tabPanelOpen.attrJoin("class", ACTIVE_CLASSNAME);
|
|
585
|
+
tabOpen.attrJoin("class", ACTIVE_CLASSNAME);
|
|
586
|
+
}
|
|
587
|
+
tabsTokens.push(tabOpen, tabInline, tabClose);
|
|
588
|
+
tabsTokens.push(tabPanelOpen, ...tabs[i].tokens, tabPanelClose);
|
|
589
|
+
}
|
|
590
|
+
tabsTokens.push(tabsClose);
|
|
591
|
+
return tabsTokens;
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
// src/plugin/variants/index.ts
|
|
595
|
+
var generateByType = {
|
|
596
|
+
regular,
|
|
597
|
+
radio,
|
|
598
|
+
dropdown,
|
|
599
|
+
accordion
|
|
600
|
+
};
|
|
601
|
+
var generateTokensByType = (type) => {
|
|
602
|
+
return generateByType[type];
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
// src/plugin/generate.ts
|
|
606
|
+
function generateTabsTokens(tabs, state, props2) {
|
|
607
|
+
const tokens = generateTokensByType(props2.variant)(tabs, state, props2);
|
|
608
|
+
return tokens;
|
|
398
609
|
}
|
|
399
|
-
|
|
610
|
+
|
|
611
|
+
// src/plugin/find.ts
|
|
612
|
+
var import_token = __toESM(require("markdown-it/lib/token"));
|
|
613
|
+
function findCloseTokenIndex(tokens, idx) {
|
|
400
614
|
let level = 0;
|
|
401
615
|
let i = idx;
|
|
402
616
|
while (i < tokens.length) {
|
|
@@ -416,18 +630,14 @@ function matchCloseToken(tokens, i) {
|
|
|
416
630
|
return tokens[i].type === "paragraph_open" && tokens[i + 1].type === "inline" && tokens[i + 1].content.trim() === "{% endlist %}";
|
|
417
631
|
}
|
|
418
632
|
function matchOpenToken(tokens, i) {
|
|
419
|
-
return tokens[i].type === "paragraph_open" && tokens[i + 1].type === "inline" &&
|
|
633
|
+
return tokens[i].type === "paragraph_open" && tokens[i + 1].type === "inline" && tokens[i + 1].content.match(TAB_RE);
|
|
420
634
|
}
|
|
421
|
-
function props(
|
|
422
|
-
const
|
|
423
|
-
if (!matched) {
|
|
424
|
-
return void 0;
|
|
425
|
-
}
|
|
426
|
-
const clean = trim(matched[0].replace("list tabs", ""));
|
|
635
|
+
function props(content) {
|
|
636
|
+
const clean = trim(content.replace("list tabs", ""));
|
|
427
637
|
const props2 = clean.split(" ");
|
|
428
638
|
const result = {
|
|
429
639
|
content: clean,
|
|
430
|
-
|
|
640
|
+
variant: "regular" /* Regular */,
|
|
431
641
|
group: `${DEFAULT_TABS_GROUP_PREFIX}${generateID()}`
|
|
432
642
|
};
|
|
433
643
|
for (const prop of props2) {
|
|
@@ -435,7 +645,9 @@ function props(target) {
|
|
|
435
645
|
switch (key) {
|
|
436
646
|
case "horizontal":
|
|
437
647
|
case "radio":
|
|
438
|
-
|
|
648
|
+
case "dropdown":
|
|
649
|
+
case "accordion":
|
|
650
|
+
result.variant = key;
|
|
439
651
|
break;
|
|
440
652
|
case "group":
|
|
441
653
|
result.group = unquote(value);
|
|
@@ -445,11 +657,104 @@ function props(target) {
|
|
|
445
657
|
}
|
|
446
658
|
return result;
|
|
447
659
|
}
|
|
660
|
+
function tryToFindTabs(tokens, index) {
|
|
661
|
+
const match = matchOpenToken(tokens, index);
|
|
662
|
+
const openTag = match && match[0];
|
|
663
|
+
const isNotEscaped = openTag && !(openTag.startsWith("`") && openTag.endsWith("`"));
|
|
664
|
+
if (!match || !isNotEscaped) {
|
|
665
|
+
return {
|
|
666
|
+
step: 1
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
const closeTokenIndex = findCloseTokenIndex(tokens, index + 3);
|
|
670
|
+
if (!closeTokenIndex) {
|
|
671
|
+
tokens[index].attrSet("YFM005", "true");
|
|
672
|
+
return {
|
|
673
|
+
step: 3
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
return {
|
|
677
|
+
content: openTag,
|
|
678
|
+
closeTokenIndex
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
function findTabs(tokens, idx, closeTokenIdx) {
|
|
682
|
+
const tabs = [];
|
|
683
|
+
let i = idx;
|
|
684
|
+
let nestedLevel = -1;
|
|
685
|
+
let pending = {
|
|
686
|
+
name: "",
|
|
687
|
+
tokens: [],
|
|
688
|
+
listItem: new import_token.default("list_item_open", "", 0)
|
|
689
|
+
};
|
|
690
|
+
while (i < tokens.length) {
|
|
691
|
+
const token = tokens[i];
|
|
692
|
+
switch (token.type) {
|
|
693
|
+
case "ordered_list_open":
|
|
694
|
+
case "bullet_list_open":
|
|
695
|
+
if (nestedLevel > -1) {
|
|
696
|
+
pending.tokens.push(token);
|
|
697
|
+
}
|
|
698
|
+
nestedLevel++;
|
|
699
|
+
break;
|
|
700
|
+
case "list_item_open":
|
|
701
|
+
if (nestedLevel) {
|
|
702
|
+
pending.tokens.push(token);
|
|
703
|
+
} else {
|
|
704
|
+
pending = { name: "", tokens: [], listItem: token };
|
|
705
|
+
}
|
|
706
|
+
break;
|
|
707
|
+
case "list_item_close":
|
|
708
|
+
if (nestedLevel) {
|
|
709
|
+
pending.tokens.push(token);
|
|
710
|
+
} else {
|
|
711
|
+
tabs.push(pending);
|
|
712
|
+
}
|
|
713
|
+
break;
|
|
714
|
+
case "ordered_list_close":
|
|
715
|
+
case "bullet_list_close":
|
|
716
|
+
if (!nestedLevel) {
|
|
717
|
+
return tabs;
|
|
718
|
+
}
|
|
719
|
+
nestedLevel--;
|
|
720
|
+
pending.tokens.push(token);
|
|
721
|
+
break;
|
|
722
|
+
case "paragraph_open":
|
|
723
|
+
if (i === closeTokenIdx && tokens[i + 1].content && tokens[i + 1].content.trim() === "{% endlist %}") {
|
|
724
|
+
if (pending && !nestedLevel) {
|
|
725
|
+
tabs.push(pending);
|
|
726
|
+
}
|
|
727
|
+
return tabs;
|
|
728
|
+
}
|
|
729
|
+
if (!pending.name && tokens[i + 1].type === "inline") {
|
|
730
|
+
pending.name = tokens[i + 1].content;
|
|
731
|
+
i += 2;
|
|
732
|
+
} else {
|
|
733
|
+
pending.tokens.push(token);
|
|
734
|
+
}
|
|
735
|
+
break;
|
|
736
|
+
default:
|
|
737
|
+
pending.tokens.push(token);
|
|
738
|
+
}
|
|
739
|
+
i++;
|
|
740
|
+
}
|
|
741
|
+
return tabs;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// src/plugin/transform.ts
|
|
745
|
+
var defaultFeatures = {
|
|
746
|
+
enabledVariants: {
|
|
747
|
+
regular: true,
|
|
748
|
+
radio: true
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
var runsCounter = 0;
|
|
448
752
|
function transform({
|
|
449
753
|
runtimeJsPath = "_assets/tabs-extension.js",
|
|
450
754
|
runtimeCssPath = "_assets/tabs-extension.css",
|
|
451
755
|
containerClasses = "",
|
|
452
|
-
bundle = true
|
|
756
|
+
bundle = true,
|
|
757
|
+
features = defaultFeatures
|
|
453
758
|
} = {}) {
|
|
454
759
|
return function tabs(md, options) {
|
|
455
760
|
const { output = "." } = options || {};
|
|
@@ -460,37 +765,29 @@ function transform({
|
|
|
460
765
|
let i = 0;
|
|
461
766
|
let tabsAreInserted = false;
|
|
462
767
|
while (i < tokens.length) {
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
if (!match || !isNotEscaped) {
|
|
467
|
-
i++;
|
|
768
|
+
const result = tryToFindTabs(tokens, i);
|
|
769
|
+
if ("step" in result) {
|
|
770
|
+
i += result.step;
|
|
468
771
|
continue;
|
|
469
772
|
}
|
|
470
|
-
const
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
continue;
|
|
773
|
+
const { content, closeTokenIndex } = result;
|
|
774
|
+
const parsedProps = props(content);
|
|
775
|
+
if (!features.enabledVariants[parsedProps.variant]) {
|
|
776
|
+
parsedProps.variant = "regular" /* Regular */;
|
|
475
777
|
}
|
|
476
|
-
const
|
|
477
|
-
const { tabs: tabs2 } = findTabs(state.tokens, i + 3, closeTokenIdx);
|
|
778
|
+
const tabs2 = findTabs(state.tokens, i + 3, closeTokenIndex);
|
|
478
779
|
if (tabs2.length > 0) {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
tabsGroup,
|
|
487
|
-
runId
|
|
488
|
-
}
|
|
489
|
-
);
|
|
780
|
+
const tabsTokens = generateTabsTokens(tabs2, state, {
|
|
781
|
+
containerClasses,
|
|
782
|
+
tabsGroup: parsedProps.group,
|
|
783
|
+
variant: parsedProps.variant,
|
|
784
|
+
runId
|
|
785
|
+
});
|
|
786
|
+
state.tokens.splice(i, closeTokenIndex - i + 3, ...tabsTokens);
|
|
490
787
|
i++;
|
|
491
788
|
tabsAreInserted = true;
|
|
492
789
|
} else {
|
|
493
|
-
state.tokens.splice(i,
|
|
790
|
+
state.tokens.splice(i, closeTokenIndex - i + 3);
|
|
494
791
|
}
|
|
495
792
|
}
|
|
496
793
|
if (tabsAreInserted) {
|