@penn-libraries/web 1.4.0-dev.1 → 1.4.0-dev.3
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/dist/cjs/{index-DATEsMXP.js → index-DuAtidph.js} +4 -4
- package/dist/cjs/index-DuAtidph.js.map +1 -0
- package/dist/cjs/index.cjs.js +1 -1
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/pennlibs-accordion.pennlibs-expand-text.pennlibs-feedback.pennlibs-footer.pennlibs-header.entry.cjs.js.map +1 -0
- package/dist/cjs/{pennlibs-expand-text_4.cjs.entry.js → pennlibs-accordion_5.cjs.entry.js} +168 -2
- package/dist/cjs/pennlibs-autocomplete.cjs.entry.js +1 -1
- package/dist/cjs/pennlibs-banner.cjs.entry.js +1 -1
- package/dist/cjs/pennlibs-chat.cjs.entry.js +1 -1
- package/dist/cjs/pennlibs-fallback-img.cjs.entry.js +1 -1
- package/dist/cjs/pennlibs-hero.cjs.entry.js +1 -1
- package/dist/cjs/pennlibs-iiif-img.cjs.entry.js +1 -1
- package/dist/cjs/web.cjs.js +2 -2
- package/dist/collection/collection-manifest.json +1 -0
- package/dist/collection/components/pennlibs-accordion/pennlibs-accordion.css +9 -0
- package/dist/collection/components/pennlibs-accordion/pennlibs-accordion.js +228 -0
- package/dist/collection/components/pennlibs-accordion/pennlibs-accordion.js.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +1 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/pennlibs-accordion.d.ts +11 -0
- package/dist/components/pennlibs-accordion.js +192 -0
- package/dist/components/pennlibs-accordion.js.map +1 -0
- package/dist/docs.json +71 -1
- package/dist/{web/p-CgmxDHmi.js → esm/index-BXL8iX4F.js} +4 -4
- package/dist/esm/index-BXL8iX4F.js.map +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/loader.js +3 -3
- package/dist/esm/pennlibs-accordion.pennlibs-expand-text.pennlibs-feedback.pennlibs-footer.pennlibs-header.entry.js.map +1 -0
- package/dist/esm/{pennlibs-expand-text_4.entry.js → pennlibs-accordion_5.entry.js} +168 -3
- package/dist/esm/pennlibs-autocomplete.entry.js +1 -1
- package/dist/esm/pennlibs-banner.entry.js +1 -1
- package/dist/esm/pennlibs-chat.entry.js +1 -1
- package/dist/esm/pennlibs-fallback-img.entry.js +1 -1
- package/dist/esm/pennlibs-hero.entry.js +1 -1
- package/dist/esm/pennlibs-iiif-img.entry.js +1 -1
- package/dist/esm/web.js +3 -3
- package/dist/types/components/pennlibs-accordion/pennlibs-accordion.d.ts +44 -0
- package/dist/types/components.d.ts +89 -0
- package/dist/web/index.esm.js +1 -1
- package/dist/web/{p-eda436e7.entry.js → p-5bf6e5f8.entry.js} +1 -1
- package/dist/web/{p-2d7c03b3.entry.js → p-5f1cef00.entry.js} +1 -1
- package/dist/web/{p-7c1febd2.entry.js → p-61ae9fb2.entry.js} +1 -1
- package/dist/web/{p-6ff0271c.entry.js → p-64e74684.entry.js} +1 -1
- package/dist/web/{p-b674bdca.entry.js → p-8b17cc4d.entry.js} +1 -1
- package/dist/web/{p-6eef97ad.entry.js → p-9de28f5c.entry.js} +1 -1
- package/dist/{esm/index-CgmxDHmi.js → web/p-BXL8iX4F.js} +4 -4
- package/dist/web/p-BXL8iX4F.js.map +1 -0
- package/dist/web/{p-ee89e08f.entry.js → p-ed1b5ac4.entry.js} +168 -3
- package/dist/web/pennlibs-accordion.pennlibs-expand-text.pennlibs-feedback.pennlibs-footer.pennlibs-header.entry.esm.js.map +1 -0
- package/dist/web/web.css +86 -5
- package/dist/web/web.esm.js +3 -3
- package/hydrate/index.js +197 -1
- package/hydrate/index.mjs +197 -1
- package/package.json +1 -1
- package/dist/cjs/index-DATEsMXP.js.map +0 -1
- package/dist/cjs/pennlibs-expand-text.pennlibs-feedback.pennlibs-footer.pennlibs-header.entry.cjs.js.map +0 -1
- package/dist/esm/index-CgmxDHmi.js.map +0 -1
- package/dist/esm/pennlibs-expand-text.pennlibs-feedback.pennlibs-footer.pennlibs-header.entry.js.map +0 -1
- package/dist/web/p-CgmxDHmi.js.map +0 -1
- package/dist/web/pennlibs-expand-text.pennlibs-feedback.pennlibs-footer.pennlibs-header.entry.esm.js.map +0 -1
package/hydrate/index.js
CHANGED
|
@@ -2312,7 +2312,7 @@ var updateComponent = async (hostRef, instance, isInitialLoad) => {
|
|
|
2312
2312
|
};
|
|
2313
2313
|
var callRender = (hostRef, instance, elm, isInitialLoad) => {
|
|
2314
2314
|
try {
|
|
2315
|
-
instance = instance.render()
|
|
2315
|
+
instance = instance.render && instance.render();
|
|
2316
2316
|
{
|
|
2317
2317
|
hostRef.$flags$ &= -17 /* isQueuedForUpdate */;
|
|
2318
2318
|
}
|
|
@@ -3331,6 +3331,201 @@ var setScopedSSR = (opts) => {
|
|
|
3331
3331
|
var needsScopedSSR = () => scopedSSR;
|
|
3332
3332
|
var scopedSSR = false;
|
|
3333
3333
|
|
|
3334
|
+
const pennlibsAccordionCss = "pennlibs-accordion{display:contents}";
|
|
3335
|
+
|
|
3336
|
+
let accordionUid = 0;
|
|
3337
|
+
/**
|
|
3338
|
+
* Composes a group of native `<details class="pl-details">` disclosures into an
|
|
3339
|
+
* accordion. The markup is authored as plain styled details elements (see the
|
|
3340
|
+
* Details pattern) so it works and is accessible without JavaScript; once this
|
|
3341
|
+
* component loads it layers on the WAI-ARIA Accordion behavior: keyboard
|
|
3342
|
+
* navigation between headers, region wiring, and an optional single-open mode.
|
|
3343
|
+
*
|
|
3344
|
+
* To expand or collapse every item at once, add a control with
|
|
3345
|
+
* `data-pl-accordion-toggle`. With no value it controls the closest enclosing
|
|
3346
|
+
* accordion; set the value to an accordion's id to control one from elsewhere
|
|
3347
|
+
* on the page. Add `data-pl-accordion-toggle-deep` to also reach nested
|
|
3348
|
+
* accordions, or give it a number to reach that many levels down.
|
|
3349
|
+
* `data-pl-expand-label` and `data-pl-collapse-label` swap the control's text
|
|
3350
|
+
* to match the state.
|
|
3351
|
+
*
|
|
3352
|
+
* This is a light-DOM component. It does not render its own template; it only
|
|
3353
|
+
* enhances the `<details>` children it is given.
|
|
3354
|
+
*
|
|
3355
|
+
* @slot - One or more details items, each styled with the pl-details classes.
|
|
3356
|
+
*/
|
|
3357
|
+
class Accordion {
|
|
3358
|
+
constructor(hostRef) {
|
|
3359
|
+
registerInstance(this, hostRef);
|
|
3360
|
+
/**
|
|
3361
|
+
* When set, only one panel can be open at a time, so opening one closes the
|
|
3362
|
+
* others, like a classic accordion.
|
|
3363
|
+
* @prop single
|
|
3364
|
+
*/
|
|
3365
|
+
this.single = false;
|
|
3366
|
+
this.uid = accordionUid++;
|
|
3367
|
+
this.items = [];
|
|
3368
|
+
this.summaries = [];
|
|
3369
|
+
// Roving focus between headers per the WAI-ARIA Accordion keyboard model.
|
|
3370
|
+
// Enter/Space toggling is left to the browser's native <details> behavior.
|
|
3371
|
+
this.onKeydown = (event) => {
|
|
3372
|
+
var _a;
|
|
3373
|
+
const current = event.currentTarget;
|
|
3374
|
+
const index = this.summaries.indexOf(current);
|
|
3375
|
+
if (index === -1)
|
|
3376
|
+
return;
|
|
3377
|
+
const count = this.summaries.length;
|
|
3378
|
+
let next;
|
|
3379
|
+
switch (event.key) {
|
|
3380
|
+
case 'ArrowDown':
|
|
3381
|
+
next = (index + 1) % count;
|
|
3382
|
+
break;
|
|
3383
|
+
case 'ArrowUp':
|
|
3384
|
+
next = (index - 1 + count) % count;
|
|
3385
|
+
break;
|
|
3386
|
+
case 'Home':
|
|
3387
|
+
next = 0;
|
|
3388
|
+
break;
|
|
3389
|
+
case 'End':
|
|
3390
|
+
next = count - 1;
|
|
3391
|
+
break;
|
|
3392
|
+
default:
|
|
3393
|
+
return;
|
|
3394
|
+
}
|
|
3395
|
+
event.preventDefault();
|
|
3396
|
+
(_a = this.summaries[next]) === null || _a === void 0 ? void 0 : _a.focus();
|
|
3397
|
+
};
|
|
3398
|
+
this.onToggle = (event) => {
|
|
3399
|
+
if (!this.single)
|
|
3400
|
+
return;
|
|
3401
|
+
const details = event.target;
|
|
3402
|
+
if (!details.open)
|
|
3403
|
+
return;
|
|
3404
|
+
this.items.forEach((other) => {
|
|
3405
|
+
if (other !== details && other.open)
|
|
3406
|
+
other.open = false;
|
|
3407
|
+
});
|
|
3408
|
+
};
|
|
3409
|
+
}
|
|
3410
|
+
componentDidLoad() {
|
|
3411
|
+
this.collectItems();
|
|
3412
|
+
this.enhanceItems();
|
|
3413
|
+
this.syncControls(this.el, this.items.some((details) => details.open));
|
|
3414
|
+
}
|
|
3415
|
+
disconnectedCallback() {
|
|
3416
|
+
this.summaries.forEach((summary) => summary.removeEventListener('keydown', this.onKeydown));
|
|
3417
|
+
this.items.forEach((details) => details.removeEventListener('toggle', this.onToggle));
|
|
3418
|
+
}
|
|
3419
|
+
collectItems() {
|
|
3420
|
+
this.items = Array.from(this.el.querySelectorAll(':scope > details, :scope > .pl-details'));
|
|
3421
|
+
this.summaries = this.items
|
|
3422
|
+
.map((details) => details.querySelector(':scope > summary'))
|
|
3423
|
+
.filter((summary) => summary instanceof HTMLElement);
|
|
3424
|
+
}
|
|
3425
|
+
enhanceItems() {
|
|
3426
|
+
this.items.forEach((details, index) => {
|
|
3427
|
+
const summary = details.querySelector(':scope > summary');
|
|
3428
|
+
if (!summary)
|
|
3429
|
+
return;
|
|
3430
|
+
const panel = summary.nextElementSibling;
|
|
3431
|
+
const baseId = `pl-accordion-${this.uid}-${index}`;
|
|
3432
|
+
// Wire the summary (the disclosure button) to its panel as a labelled
|
|
3433
|
+
// region. Native <summary> already exposes the button role and
|
|
3434
|
+
// aria-expanded, so we only add what it lacks.
|
|
3435
|
+
if (!summary.id)
|
|
3436
|
+
summary.id = `${baseId}-summary`;
|
|
3437
|
+
if (panel) {
|
|
3438
|
+
if (!panel.id)
|
|
3439
|
+
panel.id = `${baseId}-panel`;
|
|
3440
|
+
if (!panel.hasAttribute('role'))
|
|
3441
|
+
panel.setAttribute('role', 'region');
|
|
3442
|
+
if (!panel.hasAttribute('aria-labelledby'))
|
|
3443
|
+
panel.setAttribute('aria-labelledby', summary.id);
|
|
3444
|
+
summary.setAttribute('aria-controls', panel.id);
|
|
3445
|
+
}
|
|
3446
|
+
summary.addEventListener('keydown', this.onKeydown);
|
|
3447
|
+
details.addEventListener('toggle', this.onToggle);
|
|
3448
|
+
});
|
|
3449
|
+
}
|
|
3450
|
+
// A declarative toggle-all control: any element marked with
|
|
3451
|
+
// `data-pl-accordion-toggle`. With no value it controls the closest enclosing
|
|
3452
|
+
// accordion; set the value to an accordion's id to control one from elsewhere
|
|
3453
|
+
// on the page. Add `data-pl-accordion-toggle-deep` to also reach nested
|
|
3454
|
+
// accordions, or a number for that many levels. `data-pl-expand-label` and
|
|
3455
|
+
// `data-pl-collapse-label` swap its text to match the state.
|
|
3456
|
+
onControlClick(event) {
|
|
3457
|
+
var _a;
|
|
3458
|
+
const control = (_a = event.target) === null || _a === void 0 ? void 0 : _a.closest('[data-pl-accordion-toggle]');
|
|
3459
|
+
if (!control || this.controlTarget(control) !== this.el)
|
|
3460
|
+
return;
|
|
3461
|
+
event.preventDefault();
|
|
3462
|
+
const expanded = !this.items.some((details) => details.open);
|
|
3463
|
+
this.setAll(this.el, expanded, this.controlDepth(control));
|
|
3464
|
+
}
|
|
3465
|
+
// The accordion a control points at: the element whose id is in the attribute
|
|
3466
|
+
// value, or the closest enclosing accordion when the value is empty.
|
|
3467
|
+
controlTarget(control) {
|
|
3468
|
+
const id = control.getAttribute('data-pl-accordion-toggle');
|
|
3469
|
+
return id ? document.getElementById(id) : control.closest('pennlibs-accordion');
|
|
3470
|
+
}
|
|
3471
|
+
// How many nested levels a control reaches: absent is none, a bare attribute
|
|
3472
|
+
// is every level, and a non-negative number is that many levels down.
|
|
3473
|
+
controlDepth(control) {
|
|
3474
|
+
if (!control.hasAttribute('data-pl-accordion-toggle-deep'))
|
|
3475
|
+
return 0;
|
|
3476
|
+
const raw = control.getAttribute('data-pl-accordion-toggle-deep');
|
|
3477
|
+
if (raw === null || raw === '')
|
|
3478
|
+
return Infinity;
|
|
3479
|
+
const levels = parseInt(raw, 10);
|
|
3480
|
+
return Number.isFinite(levels) && levels >= 0 ? levels : Infinity;
|
|
3481
|
+
}
|
|
3482
|
+
// Expand or collapse every item in an accordion, pushing the same direction
|
|
3483
|
+
// `levels` deep. Each level reads its own single-open rule, so nothing forces
|
|
3484
|
+
// two panels open in a single-open group.
|
|
3485
|
+
setAll(accordion, expanded, levels) {
|
|
3486
|
+
const items = Array.from(accordion.querySelectorAll(':scope > details, :scope > .pl-details'));
|
|
3487
|
+
if (expanded && accordion.single) {
|
|
3488
|
+
items.forEach((details, index) => (details.open = index === 0));
|
|
3489
|
+
}
|
|
3490
|
+
else {
|
|
3491
|
+
items.forEach((details) => (details.open = expanded));
|
|
3492
|
+
}
|
|
3493
|
+
this.syncControls(accordion, expanded);
|
|
3494
|
+
if (levels > 0) {
|
|
3495
|
+
this.nestedAccordions(accordion).forEach((nested) => this.setAll(nested, expanded, levels - 1));
|
|
3496
|
+
}
|
|
3497
|
+
}
|
|
3498
|
+
// The accordions one level down from the given one (not their descendants).
|
|
3499
|
+
nestedAccordions(accordion) {
|
|
3500
|
+
return Array.from(accordion.querySelectorAll('pennlibs-accordion')).filter((node) => { var _a; return ((_a = node.parentElement) === null || _a === void 0 ? void 0 : _a.closest('pennlibs-accordion')) === accordion; });
|
|
3501
|
+
}
|
|
3502
|
+
// Keep every control pointing at an accordion in sync with its state.
|
|
3503
|
+
syncControls(accordion, expanded) {
|
|
3504
|
+
document.querySelectorAll('[data-pl-accordion-toggle]').forEach((control) => {
|
|
3505
|
+
if (this.controlTarget(control) !== accordion)
|
|
3506
|
+
return;
|
|
3507
|
+
control.setAttribute('aria-expanded', String(expanded));
|
|
3508
|
+
const label = expanded
|
|
3509
|
+
? control.getAttribute('data-pl-collapse-label')
|
|
3510
|
+
: control.getAttribute('data-pl-expand-label');
|
|
3511
|
+
if (label)
|
|
3512
|
+
control.textContent = label;
|
|
3513
|
+
});
|
|
3514
|
+
}
|
|
3515
|
+
get el() { return getElement(this); }
|
|
3516
|
+
static get style() { return pennlibsAccordionCss; }
|
|
3517
|
+
static get cmpMeta() { return {
|
|
3518
|
+
"$flags$": 0,
|
|
3519
|
+
"$tagName$": "pennlibs-accordion",
|
|
3520
|
+
"$members$": {
|
|
3521
|
+
"single": [4]
|
|
3522
|
+
},
|
|
3523
|
+
"$listeners$": [[4, "click", "onControlClick"]],
|
|
3524
|
+
"$lazyBundleId$": "-",
|
|
3525
|
+
"$attrsToReflect$": []
|
|
3526
|
+
}; }
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3334
3529
|
const pennlibsAutocompleteCss = ":host {\n display: block;\n width: 100%;\n border-radius: 1.25rem;\n padding: 0;\n border-top: 0;\n position: relative;\n}\n\n[role=listbox] {\n position: absolute;\n margin-top: var(--pl-space-xs);\n background: var(--pl-color-bg-default);\n border-radius: 1.25rem;\n box-shadow: rgba(140, 149, 159, 0.3) 0px 8px 24px 0px;\n width: 100%;\n overflow: hidden;\n z-index: 1;\n\n display: flex;\n flex-direction: column;\n}\n\np {\n margin: 0;\n font-size: var(--pl-font-size-s);\n color: var(--pl-color-fg-subtle);\n padding: var(--pl-space-xs) calc(var(--pl-space-m) + var(--pl-space-2xs));\n font-size: var(--pl-font-size-s);\n order: 2;\n font-weight: 500;\n background: var(--pl-color-bg-subtle);\n border-radius: 0 0 1.25rem 1.25rem;\n\n display: flex;\n gap: var(--pl-space-s) var(--pl-space-l);\n flex-wrap: wrap;\n}\n\nol {\n list-style: none;\n margin: 0;\n padding: var(--pl-space-xs) 0;\n order: 1;\n}\n\n[role=option] {\n color: var(--pl-color-fg-default);\n padding: var(--pl-space-s) calc(var(--pl-space-m) + var(--pl-space-2xs));\n text-decoration: none;\n font-weight: 700; \n\n &:hover {\n cursor: pointer;\n }\n\n &:hover,\n &:focus {\n text-decoration-thickness: 2px;\n text-underline-offset: 2px;\n text-decoration: underline;\n }\n}\n\n[aria-selected=true] {\n text-decoration-thickness: 2px;\n text-underline-offset: 2px;\n text-decoration: underline;\n}\n\nmark,\nb {\n background: none;\n font-weight: 400;\n}\n\n.suggestion--border {\n border-bottom: solid 1px rgb(from var(--pl-color-fg-default) r g b / 0.2);\n padding-bottom: calc(var(--pl-space-2xs) + var(--pl-space-s));\n margin-bottom: var(--pl-space-2xs);\n}";
|
|
3335
3530
|
|
|
3336
3531
|
/**
|
|
@@ -4422,6 +4617,7 @@ class PennlibsFeedback {
|
|
|
4422
4617
|
}
|
|
4423
4618
|
|
|
4424
4619
|
registerComponents([
|
|
4620
|
+
Accordion,
|
|
4425
4621
|
Autocomplete,
|
|
4426
4622
|
Banner,
|
|
4427
4623
|
Chat,
|
package/hydrate/index.mjs
CHANGED
|
@@ -2310,7 +2310,7 @@ var updateComponent = async (hostRef, instance, isInitialLoad) => {
|
|
|
2310
2310
|
};
|
|
2311
2311
|
var callRender = (hostRef, instance, elm, isInitialLoad) => {
|
|
2312
2312
|
try {
|
|
2313
|
-
instance = instance.render()
|
|
2313
|
+
instance = instance.render && instance.render();
|
|
2314
2314
|
{
|
|
2315
2315
|
hostRef.$flags$ &= -17 /* isQueuedForUpdate */;
|
|
2316
2316
|
}
|
|
@@ -3329,6 +3329,201 @@ var setScopedSSR = (opts) => {
|
|
|
3329
3329
|
var needsScopedSSR = () => scopedSSR;
|
|
3330
3330
|
var scopedSSR = false;
|
|
3331
3331
|
|
|
3332
|
+
const pennlibsAccordionCss = "pennlibs-accordion{display:contents}";
|
|
3333
|
+
|
|
3334
|
+
let accordionUid = 0;
|
|
3335
|
+
/**
|
|
3336
|
+
* Composes a group of native `<details class="pl-details">` disclosures into an
|
|
3337
|
+
* accordion. The markup is authored as plain styled details elements (see the
|
|
3338
|
+
* Details pattern) so it works and is accessible without JavaScript; once this
|
|
3339
|
+
* component loads it layers on the WAI-ARIA Accordion behavior: keyboard
|
|
3340
|
+
* navigation between headers, region wiring, and an optional single-open mode.
|
|
3341
|
+
*
|
|
3342
|
+
* To expand or collapse every item at once, add a control with
|
|
3343
|
+
* `data-pl-accordion-toggle`. With no value it controls the closest enclosing
|
|
3344
|
+
* accordion; set the value to an accordion's id to control one from elsewhere
|
|
3345
|
+
* on the page. Add `data-pl-accordion-toggle-deep` to also reach nested
|
|
3346
|
+
* accordions, or give it a number to reach that many levels down.
|
|
3347
|
+
* `data-pl-expand-label` and `data-pl-collapse-label` swap the control's text
|
|
3348
|
+
* to match the state.
|
|
3349
|
+
*
|
|
3350
|
+
* This is a light-DOM component. It does not render its own template; it only
|
|
3351
|
+
* enhances the `<details>` children it is given.
|
|
3352
|
+
*
|
|
3353
|
+
* @slot - One or more details items, each styled with the pl-details classes.
|
|
3354
|
+
*/
|
|
3355
|
+
class Accordion {
|
|
3356
|
+
constructor(hostRef) {
|
|
3357
|
+
registerInstance(this, hostRef);
|
|
3358
|
+
/**
|
|
3359
|
+
* When set, only one panel can be open at a time, so opening one closes the
|
|
3360
|
+
* others, like a classic accordion.
|
|
3361
|
+
* @prop single
|
|
3362
|
+
*/
|
|
3363
|
+
this.single = false;
|
|
3364
|
+
this.uid = accordionUid++;
|
|
3365
|
+
this.items = [];
|
|
3366
|
+
this.summaries = [];
|
|
3367
|
+
// Roving focus between headers per the WAI-ARIA Accordion keyboard model.
|
|
3368
|
+
// Enter/Space toggling is left to the browser's native <details> behavior.
|
|
3369
|
+
this.onKeydown = (event) => {
|
|
3370
|
+
var _a;
|
|
3371
|
+
const current = event.currentTarget;
|
|
3372
|
+
const index = this.summaries.indexOf(current);
|
|
3373
|
+
if (index === -1)
|
|
3374
|
+
return;
|
|
3375
|
+
const count = this.summaries.length;
|
|
3376
|
+
let next;
|
|
3377
|
+
switch (event.key) {
|
|
3378
|
+
case 'ArrowDown':
|
|
3379
|
+
next = (index + 1) % count;
|
|
3380
|
+
break;
|
|
3381
|
+
case 'ArrowUp':
|
|
3382
|
+
next = (index - 1 + count) % count;
|
|
3383
|
+
break;
|
|
3384
|
+
case 'Home':
|
|
3385
|
+
next = 0;
|
|
3386
|
+
break;
|
|
3387
|
+
case 'End':
|
|
3388
|
+
next = count - 1;
|
|
3389
|
+
break;
|
|
3390
|
+
default:
|
|
3391
|
+
return;
|
|
3392
|
+
}
|
|
3393
|
+
event.preventDefault();
|
|
3394
|
+
(_a = this.summaries[next]) === null || _a === void 0 ? void 0 : _a.focus();
|
|
3395
|
+
};
|
|
3396
|
+
this.onToggle = (event) => {
|
|
3397
|
+
if (!this.single)
|
|
3398
|
+
return;
|
|
3399
|
+
const details = event.target;
|
|
3400
|
+
if (!details.open)
|
|
3401
|
+
return;
|
|
3402
|
+
this.items.forEach((other) => {
|
|
3403
|
+
if (other !== details && other.open)
|
|
3404
|
+
other.open = false;
|
|
3405
|
+
});
|
|
3406
|
+
};
|
|
3407
|
+
}
|
|
3408
|
+
componentDidLoad() {
|
|
3409
|
+
this.collectItems();
|
|
3410
|
+
this.enhanceItems();
|
|
3411
|
+
this.syncControls(this.el, this.items.some((details) => details.open));
|
|
3412
|
+
}
|
|
3413
|
+
disconnectedCallback() {
|
|
3414
|
+
this.summaries.forEach((summary) => summary.removeEventListener('keydown', this.onKeydown));
|
|
3415
|
+
this.items.forEach((details) => details.removeEventListener('toggle', this.onToggle));
|
|
3416
|
+
}
|
|
3417
|
+
collectItems() {
|
|
3418
|
+
this.items = Array.from(this.el.querySelectorAll(':scope > details, :scope > .pl-details'));
|
|
3419
|
+
this.summaries = this.items
|
|
3420
|
+
.map((details) => details.querySelector(':scope > summary'))
|
|
3421
|
+
.filter((summary) => summary instanceof HTMLElement);
|
|
3422
|
+
}
|
|
3423
|
+
enhanceItems() {
|
|
3424
|
+
this.items.forEach((details, index) => {
|
|
3425
|
+
const summary = details.querySelector(':scope > summary');
|
|
3426
|
+
if (!summary)
|
|
3427
|
+
return;
|
|
3428
|
+
const panel = summary.nextElementSibling;
|
|
3429
|
+
const baseId = `pl-accordion-${this.uid}-${index}`;
|
|
3430
|
+
// Wire the summary (the disclosure button) to its panel as a labelled
|
|
3431
|
+
// region. Native <summary> already exposes the button role and
|
|
3432
|
+
// aria-expanded, so we only add what it lacks.
|
|
3433
|
+
if (!summary.id)
|
|
3434
|
+
summary.id = `${baseId}-summary`;
|
|
3435
|
+
if (panel) {
|
|
3436
|
+
if (!panel.id)
|
|
3437
|
+
panel.id = `${baseId}-panel`;
|
|
3438
|
+
if (!panel.hasAttribute('role'))
|
|
3439
|
+
panel.setAttribute('role', 'region');
|
|
3440
|
+
if (!panel.hasAttribute('aria-labelledby'))
|
|
3441
|
+
panel.setAttribute('aria-labelledby', summary.id);
|
|
3442
|
+
summary.setAttribute('aria-controls', panel.id);
|
|
3443
|
+
}
|
|
3444
|
+
summary.addEventListener('keydown', this.onKeydown);
|
|
3445
|
+
details.addEventListener('toggle', this.onToggle);
|
|
3446
|
+
});
|
|
3447
|
+
}
|
|
3448
|
+
// A declarative toggle-all control: any element marked with
|
|
3449
|
+
// `data-pl-accordion-toggle`. With no value it controls the closest enclosing
|
|
3450
|
+
// accordion; set the value to an accordion's id to control one from elsewhere
|
|
3451
|
+
// on the page. Add `data-pl-accordion-toggle-deep` to also reach nested
|
|
3452
|
+
// accordions, or a number for that many levels. `data-pl-expand-label` and
|
|
3453
|
+
// `data-pl-collapse-label` swap its text to match the state.
|
|
3454
|
+
onControlClick(event) {
|
|
3455
|
+
var _a;
|
|
3456
|
+
const control = (_a = event.target) === null || _a === void 0 ? void 0 : _a.closest('[data-pl-accordion-toggle]');
|
|
3457
|
+
if (!control || this.controlTarget(control) !== this.el)
|
|
3458
|
+
return;
|
|
3459
|
+
event.preventDefault();
|
|
3460
|
+
const expanded = !this.items.some((details) => details.open);
|
|
3461
|
+
this.setAll(this.el, expanded, this.controlDepth(control));
|
|
3462
|
+
}
|
|
3463
|
+
// The accordion a control points at: the element whose id is in the attribute
|
|
3464
|
+
// value, or the closest enclosing accordion when the value is empty.
|
|
3465
|
+
controlTarget(control) {
|
|
3466
|
+
const id = control.getAttribute('data-pl-accordion-toggle');
|
|
3467
|
+
return id ? document.getElementById(id) : control.closest('pennlibs-accordion');
|
|
3468
|
+
}
|
|
3469
|
+
// How many nested levels a control reaches: absent is none, a bare attribute
|
|
3470
|
+
// is every level, and a non-negative number is that many levels down.
|
|
3471
|
+
controlDepth(control) {
|
|
3472
|
+
if (!control.hasAttribute('data-pl-accordion-toggle-deep'))
|
|
3473
|
+
return 0;
|
|
3474
|
+
const raw = control.getAttribute('data-pl-accordion-toggle-deep');
|
|
3475
|
+
if (raw === null || raw === '')
|
|
3476
|
+
return Infinity;
|
|
3477
|
+
const levels = parseInt(raw, 10);
|
|
3478
|
+
return Number.isFinite(levels) && levels >= 0 ? levels : Infinity;
|
|
3479
|
+
}
|
|
3480
|
+
// Expand or collapse every item in an accordion, pushing the same direction
|
|
3481
|
+
// `levels` deep. Each level reads its own single-open rule, so nothing forces
|
|
3482
|
+
// two panels open in a single-open group.
|
|
3483
|
+
setAll(accordion, expanded, levels) {
|
|
3484
|
+
const items = Array.from(accordion.querySelectorAll(':scope > details, :scope > .pl-details'));
|
|
3485
|
+
if (expanded && accordion.single) {
|
|
3486
|
+
items.forEach((details, index) => (details.open = index === 0));
|
|
3487
|
+
}
|
|
3488
|
+
else {
|
|
3489
|
+
items.forEach((details) => (details.open = expanded));
|
|
3490
|
+
}
|
|
3491
|
+
this.syncControls(accordion, expanded);
|
|
3492
|
+
if (levels > 0) {
|
|
3493
|
+
this.nestedAccordions(accordion).forEach((nested) => this.setAll(nested, expanded, levels - 1));
|
|
3494
|
+
}
|
|
3495
|
+
}
|
|
3496
|
+
// The accordions one level down from the given one (not their descendants).
|
|
3497
|
+
nestedAccordions(accordion) {
|
|
3498
|
+
return Array.from(accordion.querySelectorAll('pennlibs-accordion')).filter((node) => { var _a; return ((_a = node.parentElement) === null || _a === void 0 ? void 0 : _a.closest('pennlibs-accordion')) === accordion; });
|
|
3499
|
+
}
|
|
3500
|
+
// Keep every control pointing at an accordion in sync with its state.
|
|
3501
|
+
syncControls(accordion, expanded) {
|
|
3502
|
+
document.querySelectorAll('[data-pl-accordion-toggle]').forEach((control) => {
|
|
3503
|
+
if (this.controlTarget(control) !== accordion)
|
|
3504
|
+
return;
|
|
3505
|
+
control.setAttribute('aria-expanded', String(expanded));
|
|
3506
|
+
const label = expanded
|
|
3507
|
+
? control.getAttribute('data-pl-collapse-label')
|
|
3508
|
+
: control.getAttribute('data-pl-expand-label');
|
|
3509
|
+
if (label)
|
|
3510
|
+
control.textContent = label;
|
|
3511
|
+
});
|
|
3512
|
+
}
|
|
3513
|
+
get el() { return getElement(this); }
|
|
3514
|
+
static get style() { return pennlibsAccordionCss; }
|
|
3515
|
+
static get cmpMeta() { return {
|
|
3516
|
+
"$flags$": 0,
|
|
3517
|
+
"$tagName$": "pennlibs-accordion",
|
|
3518
|
+
"$members$": {
|
|
3519
|
+
"single": [4]
|
|
3520
|
+
},
|
|
3521
|
+
"$listeners$": [[4, "click", "onControlClick"]],
|
|
3522
|
+
"$lazyBundleId$": "-",
|
|
3523
|
+
"$attrsToReflect$": []
|
|
3524
|
+
}; }
|
|
3525
|
+
}
|
|
3526
|
+
|
|
3332
3527
|
const pennlibsAutocompleteCss = ":host {\n display: block;\n width: 100%;\n border-radius: 1.25rem;\n padding: 0;\n border-top: 0;\n position: relative;\n}\n\n[role=listbox] {\n position: absolute;\n margin-top: var(--pl-space-xs);\n background: var(--pl-color-bg-default);\n border-radius: 1.25rem;\n box-shadow: rgba(140, 149, 159, 0.3) 0px 8px 24px 0px;\n width: 100%;\n overflow: hidden;\n z-index: 1;\n\n display: flex;\n flex-direction: column;\n}\n\np {\n margin: 0;\n font-size: var(--pl-font-size-s);\n color: var(--pl-color-fg-subtle);\n padding: var(--pl-space-xs) calc(var(--pl-space-m) + var(--pl-space-2xs));\n font-size: var(--pl-font-size-s);\n order: 2;\n font-weight: 500;\n background: var(--pl-color-bg-subtle);\n border-radius: 0 0 1.25rem 1.25rem;\n\n display: flex;\n gap: var(--pl-space-s) var(--pl-space-l);\n flex-wrap: wrap;\n}\n\nol {\n list-style: none;\n margin: 0;\n padding: var(--pl-space-xs) 0;\n order: 1;\n}\n\n[role=option] {\n color: var(--pl-color-fg-default);\n padding: var(--pl-space-s) calc(var(--pl-space-m) + var(--pl-space-2xs));\n text-decoration: none;\n font-weight: 700; \n\n &:hover {\n cursor: pointer;\n }\n\n &:hover,\n &:focus {\n text-decoration-thickness: 2px;\n text-underline-offset: 2px;\n text-decoration: underline;\n }\n}\n\n[aria-selected=true] {\n text-decoration-thickness: 2px;\n text-underline-offset: 2px;\n text-decoration: underline;\n}\n\nmark,\nb {\n background: none;\n font-weight: 400;\n}\n\n.suggestion--border {\n border-bottom: solid 1px rgb(from var(--pl-color-fg-default) r g b / 0.2);\n padding-bottom: calc(var(--pl-space-2xs) + var(--pl-space-s));\n margin-bottom: var(--pl-space-2xs);\n}";
|
|
3333
3528
|
|
|
3334
3529
|
/**
|
|
@@ -4420,6 +4615,7 @@ class PennlibsFeedback {
|
|
|
4420
4615
|
}
|
|
4421
4616
|
|
|
4422
4617
|
registerComponents([
|
|
4618
|
+
Accordion,
|
|
4423
4619
|
Autocomplete,
|
|
4424
4620
|
Banner,
|
|
4425
4621
|
Chat,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@penn-libraries/web",
|
|
3
|
-
"version": "1.4.0-dev.
|
|
3
|
+
"version": "1.4.0-dev.3",
|
|
4
4
|
"description": "Reusable web designs for University of Pennsylvania Libraries websites. This package contains our code for shared Web Components and Cascading Style Sheets (CSS).",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"module": "dist/index.js",
|