@excom/content-tabs 0.1.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/.rush/temp/chunked-rush-logs/content-tabs.apply-exports.chunks.jsonl +1 -0
- package/.rush/temp/chunked-rush-logs/content-tabs.build_docs.chunks.jsonl +1 -0
- package/.rush/temp/chunked-rush-logs/content-tabs.build_package-metas.chunks.jsonl +1 -0
- package/.rush/temp/operation/apply-exports/all.log +1 -0
- package/.rush/temp/operation/apply-exports/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/apply-exports/state.json +3 -0
- package/.rush/temp/operation/build_docs/all.log +1 -0
- package/.rush/temp/operation/build_docs/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/build_docs/state.json +3 -0
- package/.rush/temp/operation/build_package-metas/all.log +1 -0
- package/.rush/temp/operation/build_package-metas/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/build_package-metas/state.json +3 -0
- package/.rush/temp/shrinkwrap-deps.json +3 -0
- package/config/rig.json +5 -0
- package/content-tabs-body.ts +26 -0
- package/content-tabs-header.ts +64 -0
- package/content-tabs.ts +174 -0
- package/index.css +5 -0
- package/index.ts +33 -0
- package/package.json +43 -0
- package/rush-logs/content-tabs.apply-exports.cache.log +1 -0
- package/rush-logs/content-tabs.apply-exports.log +1 -0
- package/rush-logs/content-tabs.build_docs.cache.log +1 -0
- package/rush-logs/content-tabs.build_docs.log +1 -0
- package/rush-logs/content-tabs.build_package-metas.cache.log +1 -0
- package/rush-logs/content-tabs.build_package-metas.log +1 -0
- package/src/content-tabs.css +137 -0
- package/support/custom-elements.json +376 -0
- package/support/demos/file-tabs.html +6 -0
- package/support/demos/multi.html +6 -0
- package/support/demos/named.html +6 -0
- package/support/demos/simple.html +8 -0
- package/support/dist-docs/content-tabs-body.md +20 -0
- package/support/dist-docs/content-tabs-header.md +26 -0
- package/support/dist-docs/content-tabs.md +183 -0
- package/support/docs/README.md +74 -0
- package/support/package-meta.json +252 -0
- package/support/tests/content-tabs.test.ts +426 -0
- package/support/tests/file-tabs.view.test.ts +26 -0
- package/support/tests/multi.view.test.ts +29 -0
- package/support/tests/named.view.test.ts +27 -0
- package/support/tests/simple.view.test.ts +29 -0
- package/tsconfig.json +5 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"modules": [
|
|
4
|
+
{
|
|
5
|
+
"kind": "javascript-module",
|
|
6
|
+
"path": "content-tabs.ts",
|
|
7
|
+
"declarations": [
|
|
8
|
+
{
|
|
9
|
+
"kind": "class",
|
|
10
|
+
"name": "ContentTabs",
|
|
11
|
+
"customElement": true,
|
|
12
|
+
"tagName": "content-tabs",
|
|
13
|
+
"summary": "Tabs / accordion — single, multi, or toggle selection.",
|
|
14
|
+
"description": "Open state of a `<content-tabs>` group. A tab is its header's `tab-name`, or its index among the group's own headers when unnamed. Nested groups are excluded.",
|
|
15
|
+
"attributes": [
|
|
16
|
+
{
|
|
17
|
+
"name": "tab-type",
|
|
18
|
+
"type": {
|
|
19
|
+
"text": "string"
|
|
20
|
+
},
|
|
21
|
+
"description": "Selection mode. `single` opens one header at a time (radio-like); `multi` allows any number open at once (accordion); `toggle` is like `single`, but re-clicking the open header closes it.",
|
|
22
|
+
"fieldName": "tabType",
|
|
23
|
+
"default": "single",
|
|
24
|
+
"values": [
|
|
25
|
+
"single",
|
|
26
|
+
"multi",
|
|
27
|
+
"toggle"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"members": [
|
|
32
|
+
{
|
|
33
|
+
"kind": "field",
|
|
34
|
+
"name": "tabType",
|
|
35
|
+
"type": {
|
|
36
|
+
"text": "string"
|
|
37
|
+
},
|
|
38
|
+
"privacy": "public",
|
|
39
|
+
"readonly": false,
|
|
40
|
+
"description": "Selection mode. `single` opens one header at a time (radio-like); `multi` allows any number open at once (accordion); `toggle` is like `single`, but re-clicking the open header closes it.",
|
|
41
|
+
"default": "single",
|
|
42
|
+
"_neutron": {
|
|
43
|
+
"surface": "option"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"kind": "field",
|
|
48
|
+
"name": "provision",
|
|
49
|
+
"type": {
|
|
50
|
+
"text": "ContentTabsProvision",
|
|
51
|
+
"expanded": "{ tabType: string | null; openTabs: Array<string | number>; activeTab: string | number | null; }"
|
|
52
|
+
},
|
|
53
|
+
"privacy": "public",
|
|
54
|
+
"readonly": false,
|
|
55
|
+
"description": "Open state: `{ tabType, openTabs, activeTab }`. A tab is its header's `tab-name`, or its index among this group's own headers when unnamed; `activeTab` is the first open one (`null` when none). Set after mount and after every header change (batched with the body sync). Not reflected as an attribute.",
|
|
56
|
+
"_neutron": {
|
|
57
|
+
"surface": "option"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"_neutron": {
|
|
62
|
+
"provisions": [
|
|
63
|
+
{
|
|
64
|
+
"name": "provision",
|
|
65
|
+
"type": {
|
|
66
|
+
"text": "ContentTabsProvision",
|
|
67
|
+
"expanded": "{ tabType: string | null; openTabs: Array<string | number>; activeTab: string | number | null; }"
|
|
68
|
+
},
|
|
69
|
+
"description": "Open state: `{ tabType, openTabs, activeTab }`. A tab is its header's `tab-name`, or its index among this group's own headers when unnamed; `activeTab` is the first open one (`null` when none). Set after mount and after every header change (batched with the body sync). Not reflected as an attribute.",
|
|
70
|
+
"fieldName": "provision"
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"listens": [
|
|
74
|
+
{
|
|
75
|
+
"name": "content-tabs-header-opened",
|
|
76
|
+
"description": "Closes sibling headers when `tab-type` is `single` (default) or `toggle`.",
|
|
77
|
+
"type": {
|
|
78
|
+
"text": "ContentTabsHeaderOpenedEvent",
|
|
79
|
+
"expanded": "CustomEvent & { type: \"content-tabs-header-opened\"; detail: void; bubbles: true; cancelable: true; composed: true }"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"expectedChildren": [
|
|
84
|
+
{
|
|
85
|
+
"relationship": "child",
|
|
86
|
+
"selector": "content-tabs-header",
|
|
87
|
+
"required": true,
|
|
88
|
+
"description": "Clickable tab headers."
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"relationship": "child",
|
|
92
|
+
"selector": "content-tabs-body",
|
|
93
|
+
"required": true,
|
|
94
|
+
"description": "Panels shown / hidden to match their header."
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
"cssClasses": [
|
|
98
|
+
{
|
|
99
|
+
"name": "file-tabs",
|
|
100
|
+
"description": "File-explorer look — headers render as bordered folder tabs joined to the active body."
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"name": "underline",
|
|
104
|
+
"description": "Paper / underline look — the active header gets a bottom accent border instead of a bordered card."
|
|
105
|
+
}
|
|
106
|
+
],
|
|
107
|
+
"cssAliases": [
|
|
108
|
+
{
|
|
109
|
+
"name": ":--content-tabs",
|
|
110
|
+
"selectors": [
|
|
111
|
+
"content-tabs",
|
|
112
|
+
".tag-content-tabs"
|
|
113
|
+
],
|
|
114
|
+
"kind": "element"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"name": ":--content-tab--is-open",
|
|
118
|
+
"selectors": [
|
|
119
|
+
"[is-open]",
|
|
120
|
+
"[aria-selected=\"true\"]"
|
|
121
|
+
],
|
|
122
|
+
"kind": "state"
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
"cssProperties": [
|
|
127
|
+
{
|
|
128
|
+
"name": "--content-tabs-border-color",
|
|
129
|
+
"description": "Border color for `.file-tabs` headers / bodies.",
|
|
130
|
+
"syntax": "<color>",
|
|
131
|
+
"default": "var(--v-muted-border-color, currentColor)"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"name": "--content-tabs-border-width",
|
|
135
|
+
"description": "Border width for `.file-tabs` headers / bodies.",
|
|
136
|
+
"syntax": "<length>",
|
|
137
|
+
"default": "var(--v-border-width, 2px)"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"name": "--content-tabs-color-active",
|
|
141
|
+
"description": "Text color for the active header in `.underline`.",
|
|
142
|
+
"syntax": "<color>",
|
|
143
|
+
"default": "var(--v-color-primary, inherit)"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"name": "--content-tabs-header-padding",
|
|
147
|
+
"description": "Padding for each header.",
|
|
148
|
+
"syntax": "<length>{1,4}",
|
|
149
|
+
"default": "10px 15px"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"name": "--content-tabs-body-padding",
|
|
153
|
+
"description": "Padding for each body in `.file-tabs`.",
|
|
154
|
+
"syntax": "<length>{1,4}",
|
|
155
|
+
"default": "var(--v-spacing, 15px)"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"name": "--content-tabs-active-indicator-height",
|
|
159
|
+
"description": "Height of the `.file-tabs` active-tab accent bar.",
|
|
160
|
+
"syntax": "<length>",
|
|
161
|
+
"default": "2px"
|
|
162
|
+
}
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
"exports": [
|
|
167
|
+
{
|
|
168
|
+
"kind": "js",
|
|
169
|
+
"name": "ContentTabs",
|
|
170
|
+
"declaration": {
|
|
171
|
+
"name": "ContentTabs",
|
|
172
|
+
"module": "content-tabs.ts"
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"kind": "custom-element-definition",
|
|
177
|
+
"name": "content-tabs",
|
|
178
|
+
"declaration": {
|
|
179
|
+
"name": "ContentTabs",
|
|
180
|
+
"module": "content-tabs.ts"
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"kind": "javascript-module",
|
|
187
|
+
"path": "content-tabs-body.ts",
|
|
188
|
+
"declarations": [
|
|
189
|
+
{
|
|
190
|
+
"kind": "class",
|
|
191
|
+
"name": "ContentTabsBody",
|
|
192
|
+
"customElement": true,
|
|
193
|
+
"tagName": "content-tabs-body",
|
|
194
|
+
"summary": "Tab panel — visible when its paired header is open.",
|
|
195
|
+
"description": "Panel paired with a `<content-tabs-header>` — shown when that header is open. Lives inside a `<content-tabs>`.",
|
|
196
|
+
"attributes": [
|
|
197
|
+
{
|
|
198
|
+
"name": "is-open",
|
|
199
|
+
"type": {
|
|
200
|
+
"text": "boolean"
|
|
201
|
+
},
|
|
202
|
+
"description": "Visibility, kept in sync with the paired header's `is-open`. Set directly only if this body is not paired with a header.",
|
|
203
|
+
"fieldName": "isOpen"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"name": "tab-name",
|
|
207
|
+
"type": {
|
|
208
|
+
"text": "string"
|
|
209
|
+
},
|
|
210
|
+
"description": "Pairs this body with the `<content-tabs-header>` sharing the same `tab-name`. Unset headers / bodies pair by position instead.",
|
|
211
|
+
"fieldName": "tabName"
|
|
212
|
+
}
|
|
213
|
+
],
|
|
214
|
+
"members": [
|
|
215
|
+
{
|
|
216
|
+
"kind": "field",
|
|
217
|
+
"name": "isOpen",
|
|
218
|
+
"type": {
|
|
219
|
+
"text": "boolean"
|
|
220
|
+
},
|
|
221
|
+
"privacy": "public",
|
|
222
|
+
"readonly": false,
|
|
223
|
+
"description": "Visibility, kept in sync with the paired header's `is-open`. Set directly only if this body is not paired with a header.",
|
|
224
|
+
"_neutron": {
|
|
225
|
+
"surface": "hybrid"
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"kind": "field",
|
|
230
|
+
"name": "tabName",
|
|
231
|
+
"type": {
|
|
232
|
+
"text": "string"
|
|
233
|
+
},
|
|
234
|
+
"privacy": "public",
|
|
235
|
+
"readonly": false,
|
|
236
|
+
"description": "Pairs this body with the `<content-tabs-header>` sharing the same `tab-name`. Unset headers / bodies pair by position instead.",
|
|
237
|
+
"_neutron": {
|
|
238
|
+
"surface": "option"
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
],
|
|
242
|
+
"_neutron": {
|
|
243
|
+
"cssAliases": [
|
|
244
|
+
{
|
|
245
|
+
"name": ":--content-tabs-body",
|
|
246
|
+
"selectors": [
|
|
247
|
+
"content-tabs-body",
|
|
248
|
+
".tag-content-tabs-body"
|
|
249
|
+
],
|
|
250
|
+
"kind": "element"
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
],
|
|
256
|
+
"exports": [
|
|
257
|
+
{
|
|
258
|
+
"kind": "js",
|
|
259
|
+
"name": "ContentTabsBody",
|
|
260
|
+
"declaration": {
|
|
261
|
+
"name": "ContentTabsBody",
|
|
262
|
+
"module": "content-tabs-body.ts"
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"kind": "custom-element-definition",
|
|
267
|
+
"name": "content-tabs-body",
|
|
268
|
+
"declaration": {
|
|
269
|
+
"name": "ContentTabsBody",
|
|
270
|
+
"module": "content-tabs-body.ts"
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
]
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"kind": "javascript-module",
|
|
277
|
+
"path": "content-tabs-header.ts",
|
|
278
|
+
"declarations": [
|
|
279
|
+
{
|
|
280
|
+
"kind": "class",
|
|
281
|
+
"name": "ContentTabsHeader",
|
|
282
|
+
"customElement": true,
|
|
283
|
+
"tagName": "content-tabs-header",
|
|
284
|
+
"summary": "Tab header — opens its paired body on click.",
|
|
285
|
+
"description": "Clickable tab header — lives inside a `<content-tabs>`. Click opens (`single` / `toggle`) or toggles (`multi`) `is-open`, which keeps the paired `<content-tabs-body>` in sync.",
|
|
286
|
+
"attributes": [
|
|
287
|
+
{
|
|
288
|
+
"name": "tab-name",
|
|
289
|
+
"type": {
|
|
290
|
+
"text": "string"
|
|
291
|
+
},
|
|
292
|
+
"description": "Pairs this header with the `<content-tabs-body>` sharing the same `tab-name`. Unset headers / bodies pair by position instead.",
|
|
293
|
+
"fieldName": "tabName"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"name": "is-open",
|
|
297
|
+
"type": {
|
|
298
|
+
"text": "boolean"
|
|
299
|
+
},
|
|
300
|
+
"description": "Open state. Click sets or toggles this depending on the parent's `tab-type`; set it directly to drive the tab programmatically.",
|
|
301
|
+
"fieldName": "isOpen"
|
|
302
|
+
}
|
|
303
|
+
],
|
|
304
|
+
"members": [
|
|
305
|
+
{
|
|
306
|
+
"kind": "field",
|
|
307
|
+
"name": "tabName",
|
|
308
|
+
"type": {
|
|
309
|
+
"text": "string"
|
|
310
|
+
},
|
|
311
|
+
"privacy": "public",
|
|
312
|
+
"readonly": false,
|
|
313
|
+
"description": "Pairs this header with the `<content-tabs-body>` sharing the same `tab-name`. Unset headers / bodies pair by position instead.",
|
|
314
|
+
"_neutron": {
|
|
315
|
+
"surface": "option"
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
"kind": "field",
|
|
320
|
+
"name": "isOpen",
|
|
321
|
+
"type": {
|
|
322
|
+
"text": "boolean"
|
|
323
|
+
},
|
|
324
|
+
"privacy": "public",
|
|
325
|
+
"readonly": false,
|
|
326
|
+
"description": "Open state. Click sets or toggles this depending on the parent's `tab-type`; set it directly to drive the tab programmatically.",
|
|
327
|
+
"_neutron": {
|
|
328
|
+
"surface": "hybrid"
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
],
|
|
332
|
+
"events": [
|
|
333
|
+
{
|
|
334
|
+
"name": "content-tabs-header-opened",
|
|
335
|
+
"description": "Whenever `is-open` is set. The parent `<content-tabs>` listens for this to close sibling headers.",
|
|
336
|
+
"type": {
|
|
337
|
+
"text": "ContentTabsHeaderOpenedEvent",
|
|
338
|
+
"expanded": "CustomEvent & { type: \"content-tabs-header-opened\"; detail: void; bubbles: true; cancelable: true; composed: true }"
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
],
|
|
342
|
+
"_neutron": {
|
|
343
|
+
"cssAliases": [
|
|
344
|
+
{
|
|
345
|
+
"name": ":--content-tabs-header",
|
|
346
|
+
"selectors": [
|
|
347
|
+
"content-tabs-header",
|
|
348
|
+
".tag-content-tabs-header"
|
|
349
|
+
],
|
|
350
|
+
"kind": "element"
|
|
351
|
+
}
|
|
352
|
+
]
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
],
|
|
356
|
+
"exports": [
|
|
357
|
+
{
|
|
358
|
+
"kind": "js",
|
|
359
|
+
"name": "ContentTabsHeader",
|
|
360
|
+
"declaration": {
|
|
361
|
+
"name": "ContentTabsHeader",
|
|
362
|
+
"module": "content-tabs-header.ts"
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
"kind": "custom-element-definition",
|
|
367
|
+
"name": "content-tabs-header",
|
|
368
|
+
"declaration": {
|
|
369
|
+
"name": "ContentTabsHeader",
|
|
370
|
+
"module": "content-tabs-header.ts"
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
]
|
|
374
|
+
}
|
|
375
|
+
]
|
|
376
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<content-tabs class="file-tabs">
|
|
2
|
+
<content-tabs-header is-open>index.ts</content-tabs-header>
|
|
3
|
+
<content-tabs-header>utils.ts</content-tabs-header>
|
|
4
|
+
<content-tabs-body is-open><pre>export const value = 1;</pre></content-tabs-body>
|
|
5
|
+
<content-tabs-body><pre>export const double = (n) => n * 2;</pre></content-tabs-body>
|
|
6
|
+
</content-tabs>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<content-tabs tab-type="multi">
|
|
2
|
+
<content-tabs-header is-open role="button">Shipping</content-tabs-header>
|
|
3
|
+
<content-tabs-header role="button">Billing</content-tabs-header>
|
|
4
|
+
<content-tabs-body is-open><p>Ships in 3-5 business days.</p></content-tabs-body>
|
|
5
|
+
<content-tabs-body><p>Charged on shipment, not on order.</p></content-tabs-body>
|
|
6
|
+
</content-tabs>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<content-tabs class="underline">
|
|
2
|
+
<content-tabs-body tab-name="b"><p>Body B — paired by name, not position.</p></content-tabs-body>
|
|
3
|
+
<content-tabs-body tab-name="a" is-open><p>Body A — paired by name, not position.</p></content-tabs-body>
|
|
4
|
+
<content-tabs-header tab-name="a" is-open>A</content-tabs-header>
|
|
5
|
+
<content-tabs-header tab-name="b">B</content-tabs-header>
|
|
6
|
+
</content-tabs>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<content-tabs class="underline">
|
|
2
|
+
<content-tabs-header is-open>Overview</content-tabs-header>
|
|
3
|
+
<content-tabs-header>Details</content-tabs-header>
|
|
4
|
+
<content-tabs-header>Settings</content-tabs-header>
|
|
5
|
+
<content-tabs-body is-open><p>Overview copy goes here.</p></content-tabs-body>
|
|
6
|
+
<content-tabs-body><p>Details copy goes here.</p></content-tabs-body>
|
|
7
|
+
<content-tabs-body><p>Settings copy goes here.</p></content-tabs-body>
|
|
8
|
+
</content-tabs>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# `<content-tabs-body>`
|
|
2
|
+
|
|
3
|
+
> Tab panel — visible when its paired header is open.
|
|
4
|
+
|
|
5
|
+
**Tag:** `<content-tabs-body>`
|
|
6
|
+
|
|
7
|
+
## API
|
|
8
|
+
|
|
9
|
+
### Attributes
|
|
10
|
+
|
|
11
|
+
| Name | Surface | Type | Default | Values | Description |
|
|
12
|
+
| --- | --- | --- | --- | --- | --- |
|
|
13
|
+
| `is-open` | hybrid | `boolean` | | | Visibility, kept in sync with the paired header's `is-open`. Set directly only if this body is not paired with a header. |
|
|
14
|
+
| `tab-name` | option | `string` | | | Pairs this body with the `<content-tabs-header>` sharing the same `tab-name`. Unset headers / bodies pair by position instead. |
|
|
15
|
+
|
|
16
|
+
### CSS Aliases
|
|
17
|
+
|
|
18
|
+
| Alias | Kind | Matches | Description |
|
|
19
|
+
| --- | --- | --- | --- |
|
|
20
|
+
| `:--content-tabs-body` | element | `content-tabs-body`, `.tag-content-tabs-body` | |
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# `<content-tabs-header>`
|
|
2
|
+
|
|
3
|
+
> Tab header — opens its paired body on click.
|
|
4
|
+
|
|
5
|
+
**Tag:** `<content-tabs-header>`
|
|
6
|
+
|
|
7
|
+
## API
|
|
8
|
+
|
|
9
|
+
### Attributes
|
|
10
|
+
|
|
11
|
+
| Name | Surface | Type | Default | Values | Description |
|
|
12
|
+
| --- | --- | --- | --- | --- | --- |
|
|
13
|
+
| `tab-name` | option | `string` | | | Pairs this header with the `<content-tabs-body>` sharing the same `tab-name`. Unset headers / bodies pair by position instead. |
|
|
14
|
+
| `is-open` | hybrid | `boolean` | | | Open state. Click sets or toggles this depending on the parent's `tab-type`; set it directly to drive the tab programmatically. |
|
|
15
|
+
|
|
16
|
+
### Fires
|
|
17
|
+
|
|
18
|
+
| Name | Type | Description |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| `content-tabs-header-opened` | `ContentTabsHeaderOpenedEvent` (`CustomEvent & { type: "content-tabs-header-opened"; detail: void; bubbles: true; cancelable: true; composed: true }`) | Whenever `is-open` is set. The parent `<content-tabs>` listens for this to close sibling headers. |
|
|
21
|
+
|
|
22
|
+
### CSS Aliases
|
|
23
|
+
|
|
24
|
+
| Alias | Kind | Matches | Description |
|
|
25
|
+
| --- | --- | --- | --- |
|
|
26
|
+
| `:--content-tabs-header` | element | `content-tabs-header`, `.tag-content-tabs-header` | |
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# content-tabs
|
|
2
|
+
|
|
3
|
+
Tabs and accordions — single, multi, or toggle selection, paired by name
|
|
4
|
+
or position.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<content-tabs class="underline">
|
|
9
|
+
<content-tabs-header is-open>Overview</content-tabs-header>
|
|
10
|
+
<content-tabs-header>Details</content-tabs-header>
|
|
11
|
+
<content-tabs-header>Settings</content-tabs-header>
|
|
12
|
+
<content-tabs-body is-open><p>Overview copy goes here.</p></content-tabs-body>
|
|
13
|
+
<content-tabs-body><p>Details copy goes here.</p></content-tabs-body>
|
|
14
|
+
<content-tabs-body><p>Settings copy goes here.</p></content-tabs-body>
|
|
15
|
+
</content-tabs>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- **Single / multi / toggle** Radio-like tabs, an accordion, or re-click
|
|
22
|
+
to close
|
|
23
|
+
- **Pair by name or position** Match headers to bodies with `tab-name`,
|
|
24
|
+
or by index when unnamed
|
|
25
|
+
- **Isolated nesting** Nested `<content-tabs>` groups never cross-wire
|
|
26
|
+
- **Bindable state** `.provision` is `{ tabType, openTabs, activeTab }` —
|
|
27
|
+
read the active tab from Quark with `prop("provision")`
|
|
28
|
+
- **Included looks** `.underline` and `.file-tabs` styles ship built in
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
`@excom/content-tabs` v0.1.0
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pnpm add @excom/content-tabs
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install @excom/content-tabs
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
yarn add @excom/content-tabs
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Import
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import "@excom/content-tabs";
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
Put `<content-tabs-header>` and `<content-tabs-body>` elements inside
|
|
58
|
+
`<content-tabs>`. A header pairs with the body sharing its `tab-name`,
|
|
59
|
+
or by position when both are unnamed.
|
|
60
|
+
|
|
61
|
+
```html
|
|
62
|
+
<content-tabs class="underline">
|
|
63
|
+
<content-tabs-header is-open>Overview</content-tabs-header>
|
|
64
|
+
<content-tabs-header>Details</content-tabs-header>
|
|
65
|
+
<content-tabs-body is-open><p>Overview copy.</p></content-tabs-body>
|
|
66
|
+
<content-tabs-body><p>Details copy.</p></content-tabs-body>
|
|
67
|
+
</content-tabs>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The open state is a fact, not just an event: `.provision` holds
|
|
71
|
+
`{ tabType, openTabs, activeTab }`, where a tab is its header's `tab-name`
|
|
72
|
+
(or its index when unnamed) and `activeTab` is the first open one. Quark
|
|
73
|
+
reads it on the group and binds it anywhere below:
|
|
74
|
+
|
|
75
|
+
```quark
|
|
76
|
+
content-tabs {
|
|
77
|
+
$tab: prop("provision").activeTab;
|
|
78
|
+
h2 { content: $tab; }
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### API Reference
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
#### Attributes
|
|
86
|
+
|
|
87
|
+
| Name | Surface | Type | Default | Values | Description |
|
|
88
|
+
| --- | --- | --- | --- | --- | --- |
|
|
89
|
+
| `tab-type` | option | `string` | `"single"` | `"single"` \| `"multi"` \| `"toggle"` | Selection mode. `single` opens one header at a time (radio-like); `multi` allows any number open at once (accordion); `toggle` is like `single`, but re-clicking the open header closes it. |
|
|
90
|
+
|
|
91
|
+
#### Provision
|
|
92
|
+
|
|
93
|
+
| Name | Type | Description |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| `provision` | `ContentTabsProvision` (`{ tabType: string \| null; openTabs: Array<string \| number>; activeTab: string \| number \| null; }`) | Open state: `{ tabType, openTabs, activeTab }`. A tab is its header's `tab-name`, or its index among this group's own headers when unnamed; `activeTab` is the first open one (`null` when none). Set after mount and after every header change (batched with the body sync). Not reflected as an attribute. |
|
|
96
|
+
|
|
97
|
+
#### Recognized Elements
|
|
98
|
+
|
|
99
|
+
| Relationship | Selector | Required | Description |
|
|
100
|
+
| --- | --- | --- | --- |
|
|
101
|
+
| `content-tabs-header` | child | yes | Clickable tab headers. |
|
|
102
|
+
| `content-tabs-body` | child | yes | Panels shown / hidden to match their header. |
|
|
103
|
+
|
|
104
|
+
#### Listens for
|
|
105
|
+
|
|
106
|
+
| Name | Type | Description |
|
|
107
|
+
| --- | --- | --- |
|
|
108
|
+
| `content-tabs-header-opened` | `ContentTabsHeaderOpenedEvent` (`CustomEvent & { type: "content-tabs-header-opened"; detail: void; bubbles: true; cancelable: true; composed: true }`) | Closes sibling headers when `tab-type` is `single` (default) or `toggle`. |
|
|
109
|
+
|
|
110
|
+
#### CSS Custom Properties
|
|
111
|
+
|
|
112
|
+
| Name | Syntax | Default | Description |
|
|
113
|
+
| --- | --- | --- | --- |
|
|
114
|
+
| `--content-tabs-border-color` | `<color>` | `var(--v-muted-border-color, currentColor)` | Border color for `.file-tabs` headers / bodies. |
|
|
115
|
+
| `--content-tabs-border-width` | `<length>` | `var(--v-border-width, 2px)` | Border width for `.file-tabs` headers / bodies. |
|
|
116
|
+
| `--content-tabs-color-active` | `<color>` | `var(--v-color-primary, inherit)` | Text color for the active header in `.underline`. |
|
|
117
|
+
| `--content-tabs-header-padding` | `<length>{1,4}` | `10px 15px` | Padding for each header. |
|
|
118
|
+
| `--content-tabs-body-padding` | `<length>{1,4}` | `var(--v-spacing, 15px)` | Padding for each body in `.file-tabs`. |
|
|
119
|
+
| `--content-tabs-active-indicator-height` | `<length>` | `2px` | Height of the `.file-tabs` active-tab accent bar. |
|
|
120
|
+
|
|
121
|
+
#### CSS Classes
|
|
122
|
+
|
|
123
|
+
| Name | Description |
|
|
124
|
+
| --- | --- |
|
|
125
|
+
| `.file-tabs` | File-explorer look — headers render as bordered folder tabs joined to the active body. |
|
|
126
|
+
| `.underline` | Paper / underline look — the active header gets a bottom accent border instead of a bordered card. |
|
|
127
|
+
|
|
128
|
+
#### CSS Aliases
|
|
129
|
+
|
|
130
|
+
| Alias | Kind | Matches | Description |
|
|
131
|
+
| --- | --- | --- | --- |
|
|
132
|
+
| `:--content-tabs` | element | `content-tabs`, `.tag-content-tabs` | |
|
|
133
|
+
| `:--content-tab--is-open` | state | `[is-open]`, `[aria-selected="true"]` | |
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
### Examples
|
|
138
|
+
|
|
139
|
+
#### File tabs
|
|
140
|
+
|
|
141
|
+
`.file-tabs` renders each header like a folder tab, joined to its body.
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
```html
|
|
145
|
+
<content-tabs class="file-tabs">
|
|
146
|
+
<content-tabs-header is-open>index.ts</content-tabs-header>
|
|
147
|
+
<content-tabs-header>utils.ts</content-tabs-header>
|
|
148
|
+
<content-tabs-body is-open><pre>export const value = 1;</pre></content-tabs-body>
|
|
149
|
+
<content-tabs-body><pre>export const double = (n) => n * 2;</pre></content-tabs-body>
|
|
150
|
+
</content-tabs>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
#### Multi-select accordion
|
|
155
|
+
|
|
156
|
+
`tab-type="multi"` lets any number of headers stay open — clicking one does not close the others. Also displayed are the tab headers as buttons, if using Valence.css.
|
|
157
|
+
|
|
158
|
+
Useful for building your own UI toggle systems.
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
```html
|
|
162
|
+
<content-tabs tab-type="multi">
|
|
163
|
+
<content-tabs-header is-open role="button">Shipping</content-tabs-header>
|
|
164
|
+
<content-tabs-header role="button">Billing</content-tabs-header>
|
|
165
|
+
<content-tabs-body is-open><p>Ships in 3-5 business days.</p></content-tabs-body>
|
|
166
|
+
<content-tabs-body><p>Charged on shipment, not on order.</p></content-tabs-body>
|
|
167
|
+
</content-tabs>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
#### Pair by tab-name
|
|
172
|
+
|
|
173
|
+
Give a header and body matching `tab-name` values to pair them regardless of their order in the DOM.
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
```html
|
|
177
|
+
<content-tabs class="underline">
|
|
178
|
+
<content-tabs-body tab-name="b"><p>Body B — paired by name, not position.</p></content-tabs-body>
|
|
179
|
+
<content-tabs-body tab-name="a" is-open><p>Body A — paired by name, not position.</p></content-tabs-body>
|
|
180
|
+
<content-tabs-header tab-name="a" is-open>A</content-tabs-header>
|
|
181
|
+
<content-tabs-header tab-name="b">B</content-tabs-header>
|
|
182
|
+
</content-tabs>
|
|
183
|
+
```
|