@penn-libraries/web 1.2.0 → 1.2.1-dev.1

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.
Files changed (51) hide show
  1. package/dist/cjs/{index-Ag6DtE87.js → index-C2lJ0X_b.js} +64 -2
  2. package/dist/cjs/index-C2lJ0X_b.js.map +1 -0
  3. package/dist/cjs/index.cjs.js +1 -1
  4. package/dist/cjs/loader.cjs.js +2 -2
  5. package/dist/cjs/pennlibs-autocomplete.cjs.entry.js +1 -1
  6. package/dist/cjs/pennlibs-banner.cjs.entry.js +1 -1
  7. package/dist/cjs/pennlibs-chat.cjs.entry.js +1 -1
  8. package/dist/cjs/pennlibs-fallback-img.cjs.entry.js +1 -1
  9. package/dist/cjs/pennlibs-feedback.pennlibs-footer.pennlibs-header.entry.cjs.js.map +1 -1
  10. package/dist/cjs/pennlibs-feedback_3.cjs.entry.js +39 -9
  11. package/dist/cjs/pennlibs-hero.cjs.entry.js +1 -1
  12. package/dist/cjs/pennlibs-iiif-img.cjs.entry.js +1 -1
  13. package/dist/cjs/web.cjs.js +2 -2
  14. package/dist/collection/components/pennlibs-feedback/pennlibs-feedback.css +1 -29
  15. package/dist/collection/components/pennlibs-feedback/pennlibs-feedback.js +38 -8
  16. package/dist/collection/components/pennlibs-feedback/pennlibs-feedback.js.map +1 -1
  17. package/dist/components/pennlibs-feedback.js +39 -10
  18. package/dist/components/pennlibs-feedback.js.map +1 -1
  19. package/dist/docs.json +2 -2
  20. package/dist/{web/p-mkVX9lU0.js → esm/index-kmszRyIe.js} +64 -2
  21. package/dist/esm/index-kmszRyIe.js.map +1 -0
  22. package/dist/esm/index.js +1 -1
  23. package/dist/esm/loader.js +3 -3
  24. package/dist/esm/pennlibs-autocomplete.entry.js +1 -1
  25. package/dist/esm/pennlibs-banner.entry.js +1 -1
  26. package/dist/esm/pennlibs-chat.entry.js +1 -1
  27. package/dist/esm/pennlibs-fallback-img.entry.js +1 -1
  28. package/dist/esm/pennlibs-feedback.pennlibs-footer.pennlibs-header.entry.js.map +1 -1
  29. package/dist/esm/pennlibs-feedback_3.entry.js +39 -9
  30. package/dist/esm/pennlibs-hero.entry.js +1 -1
  31. package/dist/esm/pennlibs-iiif-img.entry.js +1 -1
  32. package/dist/esm/web.js +3 -3
  33. package/dist/types/components/pennlibs-feedback/pennlibs-feedback.d.ts +7 -1
  34. package/dist/web/index.esm.js +1 -1
  35. package/dist/web/{p-7c6382d0.entry.js → p-1c0dd1ec.entry.js} +1 -1
  36. package/dist/web/{p-e426fb61.entry.js → p-51bc70b8.entry.js} +1 -1
  37. package/dist/web/{p-10931f0a.entry.js → p-5c02b8da.entry.js} +39 -9
  38. package/dist/web/{p-4fb3e5a4.entry.js → p-906263a3.entry.js} +1 -1
  39. package/dist/web/{p-190f0293.entry.js → p-badb334a.entry.js} +1 -1
  40. package/dist/web/{p-154851d1.entry.js → p-d392e98a.entry.js} +1 -1
  41. package/dist/web/{p-0c1113f4.entry.js → p-e1947e84.entry.js} +1 -1
  42. package/dist/{esm/index-mkVX9lU0.js → web/p-kmszRyIe.js} +64 -2
  43. package/dist/web/p-kmszRyIe.js.map +1 -0
  44. package/dist/web/pennlibs-feedback.pennlibs-footer.pennlibs-header.entry.esm.js.map +1 -1
  45. package/dist/web/web.esm.js +3 -3
  46. package/hydrate/index.js +68 -9
  47. package/hydrate/index.mjs +68 -9
  48. package/package.json +1 -1
  49. package/dist/cjs/index-Ag6DtE87.js.map +0 -1
  50. package/dist/esm/index-mkVX9lU0.js.map +0 -1
  51. package/dist/web/p-mkVX9lU0.js.map +0 -1
@@ -1,10 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-Ag6DtE87.js');
3
+ var index = require('./index-C2lJ0X_b.js');
4
4
 
5
- const pennlibsFeedbackCss = ":host{display:block;background:#eeeff4;font-family:var(--pl-font-family);font-size:var(--pl-font-size);color:var(--pl-color-fg-default);line-height:1.4;box-sizing:border-box;padding:0.75em 0}@media print{:host{display:none}}*,*::before,*::after{box-sizing:border-box}.viewport-margins{max-width:var(--pl-viewport-margins-max-width);margin:0 auto;padding:0 var(--pl-viewport-margins-gutter, 1em)}.feedback__content{display:flex;justify-content:space-between;gap:var(--pl-space-s);flex-wrap:wrap}.feedback__inline-question{display:flex;flex-wrap:wrap;gap:0.5em;align-items:center}h2{display:inline-block;margin:0;font-family:var(--pl-font-sans-serif);font-size:1em;font-weight:400}p{margin:0;padding:calc(0.5em + 1px) 0}strong{font-weight:600}a{color:var(--pl-color-fg-accent);text-decoration:underline;text-underline-offset:var(--pl-link-text-underline-offset);text-decoration-thickness:var(--pl-link-hover-text-decoration-thickness)}button{all:unset;display:flex;align-items:center;gap:0.5em;padding:0.25em 1.25em;font-family:var(--pl-font-family);font-weight:500;line-height:1.4;color:var(--pl-color-fg-default);background:var(--pl-color-bg-default);border:solid 1px var(--pl-color-fg-subtle);border-radius:1em;box-sizing:border-box}button:hover{cursor:pointer}button:hover span{text-decoration:underline}button.selected{background:var(--pl-color-bg-accent-emphasis);color:var(--pl-color-fg-on-emphasis);border-color:var(--pl-color-bg-accent-emphasis)}.feedback__inline-question+.feedback__share-feedback,p{animation:none}.feedback__content>p{animation:fadeIn 300ms ease-in}@keyframes fadeIn{from{opacity:0}to{opacity:1}}*:focus{outline:0;box-shadow:0 0 0 2px var(--pl-color-bg-attention),\n 0 0 0 3px var(--pl-color-bg-emphasis)}p:focus{outline:none;box-shadow:0 0 0 2px var(--pl-color-bg-attention), 0 0 0 3px var(--pl-color-bg-emphasis)}@media (max-width: 26em){h2{display:block;width:100%;text-align:center}}.help-us{display:flex;flex-direction:column;gap:0.5em}.visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}.visually-hidden:focus,.visually-hidden:active{clip:auto;clip-path:none;height:auto;overflow:visible;position:static;white-space:normal;width:auto}";
5
+ const pennlibsFeedbackCss = ".feedback__container.sc-pennlibs-feedback{display:block;background:#eeeff4;font-family:var(--pl-font-family);font-size:var(--pl-font-size);color:var(--pl-color-fg-default);line-height:1.4;box-sizing:border-box;padding:0.75em 0}@media print{.sc-pennlibs-feedback-h{display:none}}*.sc-pennlibs-feedback,*.sc-pennlibs-feedback::before,*.sc-pennlibs-feedback::after{box-sizing:border-box}.viewport-margins.sc-pennlibs-feedback{max-width:var(--pl-viewport-margins-max-width);margin:0 auto;padding:0 var(--pl-viewport-margins-gutter, 1em)}.feedback__content.sc-pennlibs-feedback{display:flex;justify-content:space-between;gap:var(--pl-space-s);flex-wrap:wrap}.feedback__inline-question.sc-pennlibs-feedback{display:flex;flex-wrap:wrap;gap:0.5em;align-items:center}h2.sc-pennlibs-feedback{display:inline-block;margin:0;font-family:var(--pl-font-sans-serif);font-size:1em;font-weight:400}p.sc-pennlibs-feedback{margin:0;padding:calc(0.5em + 1px) 0}a.sc-pennlibs-feedback{color:var(--pl-color-fg-accent);text-decoration:underline;text-underline-offset:var(--pl-link-text-underline-offset);text-decoration-thickness:var(--pl-link-hover-text-decoration-thickness)}button.sc-pennlibs-feedback{all:unset;display:flex;align-items:center;gap:0.5em;padding:0.25em 1.25em;font-family:var(--pl-font-family);font-weight:500;line-height:1.4;color:var(--pl-color-fg-default);background:var(--pl-color-bg-default);border:solid 1px var(--pl-color-fg-subtle);border-radius:1em;box-sizing:border-box}button.sc-pennlibs-feedback:hover{cursor:pointer}button.sc-pennlibs-feedback:hover span.sc-pennlibs-feedback{text-decoration:underline}button.selected.sc-pennlibs-feedback{background:var(--pl-color-bg-accent-emphasis);color:var(--pl-color-fg-on-emphasis);border-color:var(--pl-color-bg-accent-emphasis)}.feedback__inline-question.sc-pennlibs-feedback+.feedback__share-feedback.sc-pennlibs-feedback,p.sc-pennlibs-feedback{animation:none}.feedback__content.sc-pennlibs-feedback>p.sc-pennlibs-feedback{animation:fadeIn 300ms ease-in}@keyframes fadeIn{from{opacity:0}to{opacity:1}}*.sc-pennlibs-feedback:focus{outline:0;box-shadow:0 0 0 2px var(--pl-color-bg-attention),\n 0 0 0 3px var(--pl-color-bg-emphasis)}@media (max-width: 26em){h2.sc-pennlibs-feedback{display:block;width:100%}}.visually-hidden.sc-pennlibs-feedback{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}";
6
6
 
7
- const FEEDBACK_STORAGE_KEY = `pennlibs-feedback-${window.location.pathname}`;
8
7
  const FEEDBACK_TTL = 5 * 60 * 1000; // 5 minutes
9
8
  const FEEDBACK_QUESTION = 'Did you find what you need?';
10
9
  const PennlibsFeedback = class {
@@ -17,28 +16,59 @@ const PennlibsFeedback = class {
17
16
  this.hideQuestion = false;
18
17
  this.answer = undefined;
19
18
  this.selected = undefined;
19
+ this.currentUrl = '';
20
+ this.onNavigate = (event) => {
21
+ try {
22
+ const destinationUrl = new URL(event.destination.url).href;
23
+ if (destinationUrl !== this.currentUrl) {
24
+ this.currentUrl = destinationUrl;
25
+ this.selected = undefined;
26
+ this.answer = undefined;
27
+ this.loadStoredAnswer();
28
+ }
29
+ }
30
+ catch (_a) {
31
+ this.selected = undefined;
32
+ this.answer = undefined;
33
+ }
34
+ };
35
+ }
36
+ get storageKey() {
37
+ return `pennlibs-feedback-${this.currentUrl}`;
38
+ }
39
+ connectedCallback() {
40
+ this.currentUrl = window.location.href;
41
+ window.navigation.addEventListener('navigate', this.onNavigate);
42
+ }
43
+ disconnectedCallback() {
44
+ window.navigation.removeEventListener('navigate', this.onNavigate);
20
45
  }
21
46
  componentWillLoad() {
22
- const stored = sessionStorage.getItem(FEEDBACK_STORAGE_KEY);
47
+ this.loadStoredAnswer();
48
+ }
49
+ loadStoredAnswer() {
50
+ const stored = sessionStorage.getItem(this.storageKey);
23
51
  if (stored) {
24
52
  try {
25
53
  const { answer, timestamp } = JSON.parse(stored);
26
54
  if (Date.now() - timestamp > FEEDBACK_TTL) {
27
- sessionStorage.removeItem(FEEDBACK_STORAGE_KEY);
55
+ sessionStorage.removeItem(this.storageKey);
28
56
  }
29
57
  else {
30
58
  this.answer = answer;
31
59
  }
32
60
  }
33
61
  catch (_a) {
34
- sessionStorage.removeItem(FEEDBACK_STORAGE_KEY);
62
+ sessionStorage.removeItem(this.storageKey);
35
63
  }
36
64
  }
37
65
  }
38
- handleFeedback(answer) {
66
+ handleSubmit(event) {
39
67
  var _a;
68
+ event.preventDefault();
69
+ const answer = event.submitter.value;
40
70
  this.selected = answer;
41
- sessionStorage.setItem(FEEDBACK_STORAGE_KEY, JSON.stringify({ answer, timestamp: Date.now() }));
71
+ sessionStorage.setItem(this.storageKey, JSON.stringify({ answer, timestamp: Date.now() }));
42
72
  this.feedbackEvent.emit({
43
73
  question: FEEDBACK_QUESTION,
44
74
  answer: answer,
@@ -51,7 +81,7 @@ const PennlibsFeedback = class {
51
81
  }, 600);
52
82
  }
53
83
  render() {
54
- return (index.h("div", { key: 'e470cb9ce96fecddda37c8a557c6670b581d8414', class: "feedback__container" }, index.h("div", { key: '0f3729d63102379f7219fd9a65c370f05c3f271c', class: "viewport-margins" }, index.h("div", { key: '3eaa8419d9b5fed5d7cf33de60ab93dd911afa34', class: "feedback__content" }, !this.hideQuestion && (this.answer === 'yes' ? (index.h("p", null, "Thank you for letting us know.")) : this.answer === 'no' ? (index.h("p", null, "We'd like to help. ", index.h("a", { href: "https://www.library.upenn.edu/contact-us" }, "Contact us"), " and let us know what you're looking for.")) : (index.h("div", { class: "feedback__inline-question" }, index.h("h2", null, "Did you find what you need?"), index.h("button", { class: { 'selected': this.selected === 'yes' }, disabled: !!this.selected, onClick: () => this.handleFeedback('yes') }, index.h("span", null, "Yes"), index.h("span", { class: "visually-hidden" }, ", I found what I needed.")), index.h("button", { class: { 'selected': this.selected === 'no' }, disabled: !!this.selected, onClick: () => this.handleFeedback('no') }, index.h("span", null, "No"), index.h("span", { class: "visually-hidden" }, ", I did not find what I needed."))))), index.h("div", { key: '50da9c1f23d14feeb6a2c408b0461a439331fcd9', class: "feedback__share-feedback" }, index.h("p", { key: '3580e25ecd7b463bb46103a6aee54a710e88c0ff' }, "To help us improve, ", index.h("a", { key: '276e226f4487ce94b9de30ae40f964e63f0d045b', href: `https://upenn.co1.qualtrics.com/jfe/form/SV_3xVrP7EKWS92zfE?reporting_from_url=${encodeURIComponent(window.location.href)}` }, "share your feedback"), "."))))));
84
+ return (index.h("div", { key: '12bdec6f975166a4c5d451fc1834f70fbce3b424', class: "feedback__container" }, index.h("div", { key: '4c607ceef5f10760d540d2549a2b186a871714c7', class: "viewport-margins" }, index.h("div", { key: 'a967498163e05ce60a12bf230d303caa31373c8d', class: "feedback__content" }, !this.hideQuestion && (this.answer === 'yes' ? (index.h("p", null, "Thank you for letting us know.")) : this.answer === 'no' ? (index.h("p", null, "We'd like to help. ", index.h("a", { href: "https://www.library.upenn.edu/contact-us" }, "Contact us"), " and let us know what you're looking for.")) : (index.h("form", { class: "feedback__inline-question", onSubmit: (e) => this.handleSubmit(e) }, index.h("h2", null, "Did you find what you need?"), index.h("button", { type: "submit", name: "answer", value: "yes", class: { 'selected': this.selected === 'yes' }, disabled: !!this.selected }, index.h("span", null, "Yes"), index.h("span", { class: "visually-hidden" }, ", I found what I needed.")), index.h("button", { type: "submit", name: "answer", value: "no", class: { 'selected': this.selected === 'no' }, disabled: !!this.selected }, index.h("span", null, "No"), index.h("span", { class: "visually-hidden" }, ", I did not find what I needed."))))), index.h("div", { key: 'f918da2833ae0c64e67a9e95551edaeb78e2ba05', class: "feedback__share-feedback" }, index.h("p", { key: '12928af116ffadf669cbc694160ee6ca3458528b' }, "To help us improve, ", index.h("a", { key: '7281b7423677b104fb622a7fdcf8e768517ea84e', href: `https://upenn.co1.qualtrics.com/jfe/form/SV_3xVrP7EKWS92zfE?reporting_from_url=${encodeURIComponent(window.location.href)}` }, "share your feedback"), "."))))));
55
85
  }
56
86
  };
57
87
  PennlibsFeedback.style = pennlibsFeedbackCss;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-Ag6DtE87.js');
3
+ var index = require('./index-C2lJ0X_b.js');
4
4
 
5
5
  const pennlibsHeroCss = ":host{--pl-hero-height:clamp(42vh, 32rem, 26rem);--pl-hero-heading-font:var(--pl-font-serif);--pl-hero-color:var(--pl-color-fg-on-emphasis)}*,*:before,*:after{box-sizing:inherit}.visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0}.viewport-margins{width:100%;max-width:var(--pl-viewport-margins-max-width);margin:0 auto;padding:0 var(--pl-viewport-margins-gutter, 1em)}.hero{position:relative;min-height:var(--pl-hero-height);height:100%;background-size:cover;background-repeat:no-repeat;background-position:50% 33%;display:flex}.hero::before{content:\"\";display:flex;width:100%;height:100%;top:0;position:absolute;background:linear-gradient(360deg, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.7) 20%, rgba(0, 0, 0, 0.4) 40%, rgba(0, 0, 0, 0.05) 100%);z-index:0}.hero::after{content:\"\";display:flex;width:100%;height:100%;top:0;position:absolute;background:linear-gradient(180deg, rgba(1, 31, 91, 1) 0%, rgba(1, 31, 91, 0.9) 10%, rgba(1, 31, 91, 0.8) 20%, rgba(1, 31, 91, 0.1) 50%, rgba(1, 31, 91, 0.0) 100%);z-index:0}.hero__content{position:relative;display:flex;flex-direction:column;width:100%;z-index:1}.hero__heading-container{margin-top:auto;padding-top:var(--pl-space-3xl);padding-bottom:var(--pl-space-3xl)}.hero__heading{text-shadow:1px 1px 2px var(--pl-color-fg-default);line-height:1.1;font-size:3em;font-weight:400;font-family:var(--pl-hero-heading-font);text-wrap:pretty;max-width:30ch;margin:0;color:var(--pl-hero-color)}@media (max-width: 920px){.hero__heading{font-size:2.5em}}.hero__sub-heading{font-size:1.25em;font-family:var(--pl-font-family);font-weight:500;color:var(--pl-hero-color);max-width:52ch;text-wrap:pretty;margin-top:1em;margin-bottom:0}.hero__sub-heading a{text-decoration:underline;text-underline-offset:var(--pl-link-text-underline-offset);text-decoration-thickness:var(--pl-link-text-decoration-thickness);color:var(--pl-hero-color)}.hero__sub-heading a:hover{text-decoration-thickness:var(--pl-link-hover-text-decoration-thickness)}.hero__sub-heading strong{font-weight:bold}@media (max-width: 620px){.hero__heading{font-size:2.75em}.hero__sub-heading{font-size:1em}}";
6
6
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-Ag6DtE87.js');
3
+ var index = require('./index-C2lJ0X_b.js');
4
4
 
5
5
  const pennlibsIiifImgCss = ":host{display:block;width:100%;max-width:100%;align-self:flex-start;aspect-ratio:var(--aspect-ratio, auto)}picture{display:block;line-height:0}.iiif-img{display:block;width:100%;max-width:100%;height:auto;opacity:0;filter:blur(5px);transition:opacity 0.15s ease-in, filter 0.15s ease-in}.iiif-img.loaded{opacity:1;filter:blur(0)}.fallback-container{display:block;width:100%;height:100%}.fallback-container pennlibs-fallback-img{width:100%;height:100%}pennlibs-fallback-img{display:block;width:100%;height:100%}";
6
6
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-Ag6DtE87.js');
3
+ var index = require('./index-C2lJ0X_b.js');
4
4
 
5
5
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
6
6
  /*
@@ -18,7 +18,7 @@ var patchBrowser = () => {
18
18
 
19
19
  patchBrowser().then(async (options) => {
20
20
  await index.globalScripts();
21
- return index.bootstrapLazy([["pennlibs-iiif-img.cjs",[[257,"pennlibs-iiif-img",{"uuid":[1],"alt":[1],"region":[513],"rotation":[1],"quality":[1],"loading":[1],"showFallback":[4,"show-fallback"],"isLoaded":[32],"hasError":[32],"imageDimensions":[32],"observedWidth":[32]},null,{"region":["handleRegionChange"]}]]],["pennlibs-feedback_3.cjs",[[257,"pennlibs-feedback",{"hideQuestion":[4,"hide-question"],"answer":[32],"selected":[32]}],[257,"pennlibs-footer",{"showBuiltWith":[4,"show-built-with"],"navigationByChildren":[32]}],[257,"pennlibs-header",{"serviceName":[1,"service-name"],"serviceLede":[1,"service-lede"],"serviceHref":[1,"service-href"],"theme":[1],"isMenuOpen":[32],"navigation":[32]}]]],["pennlibs-autocomplete.cjs",[[257,"pennlibs-autocomplete",{"for":[1],"showSuggestions":[32],"currentIndex":[32],"originalValue":[32],"options":[32]},[[0,"slotchange","handleSlotChange"],[16,"input","handleInputEvent"],[16,"focus","handleFocusEvent"],[16,"blur","handleBlurEvent"],[0,"focusout","handleFocusOut"],[4,"keydown","handleKeyDown"]]]]],["pennlibs-banner.cjs",[[257,"pennlibs-banner"]]],["pennlibs-chat.cjs",[[257,"pennlibs-chat",{"href":[32]}]]],["pennlibs-hero.cjs",[[257,"pennlibs-hero",{"heroPictureElement":[32],"heroHeadingElement":[32],"heroParagraphElement":[32],"heroSrc":[32]}]]],["pennlibs-fallback-img.cjs",[[257,"pennlibs-fallback-img"]]]], options);
21
+ return index.bootstrapLazy([["pennlibs-iiif-img.cjs",[[257,"pennlibs-iiif-img",{"uuid":[1],"alt":[1],"region":[513],"rotation":[1],"quality":[1],"loading":[1],"showFallback":[4,"show-fallback"],"isLoaded":[32],"hasError":[32],"imageDimensions":[32],"observedWidth":[32]},null,{"region":["handleRegionChange"]}]]],["pennlibs-feedback_3.cjs",[[258,"pennlibs-feedback",{"hideQuestion":[4,"hide-question"],"answer":[32],"selected":[32]}],[257,"pennlibs-footer",{"showBuiltWith":[4,"show-built-with"],"navigationByChildren":[32]}],[257,"pennlibs-header",{"serviceName":[1,"service-name"],"serviceLede":[1,"service-lede"],"serviceHref":[1,"service-href"],"theme":[1],"isMenuOpen":[32],"navigation":[32]}]]],["pennlibs-autocomplete.cjs",[[257,"pennlibs-autocomplete",{"for":[1],"showSuggestions":[32],"currentIndex":[32],"originalValue":[32],"options":[32]},[[0,"slotchange","handleSlotChange"],[16,"input","handleInputEvent"],[16,"focus","handleFocusEvent"],[16,"blur","handleBlurEvent"],[0,"focusout","handleFocusOut"],[4,"keydown","handleKeyDown"]]]]],["pennlibs-banner.cjs",[[257,"pennlibs-banner"]]],["pennlibs-chat.cjs",[[257,"pennlibs-chat",{"href":[32]}]]],["pennlibs-hero.cjs",[[257,"pennlibs-hero",{"heroPictureElement":[32],"heroHeadingElement":[32],"heroParagraphElement":[32],"heroSrc":[32]}]]],["pennlibs-fallback-img.cjs",[[257,"pennlibs-fallback-img"]]]], options);
22
22
  });
23
23
 
24
24
  exports.setNonce = index.setNonce;
@@ -1,6 +1,6 @@
1
1
  /* Component Root Styles
2
2
  ---------------------------------------- */
3
- :host {
3
+ .feedback__container {
4
4
  display: block;
5
5
  background: #eeeff4;
6
6
  font-family: var(--pl-font-family);
@@ -58,10 +58,6 @@ p {
58
58
  padding: calc(0.5em + 1px) 0;
59
59
  }
60
60
 
61
- strong {
62
- font-weight: 600;
63
- }
64
-
65
61
  /* Links
66
62
  ---------------------------------------- */
67
63
  a {
@@ -127,27 +123,15 @@ p {
127
123
  0 0 0 3px var(--pl-color-bg-emphasis);
128
124
  }
129
125
 
130
- p:focus {
131
- outline: none;
132
- box-shadow: 0 0 0 2px var(--pl-color-bg-attention), 0 0 0 3px var(--pl-color-bg-emphasis);
133
- }
134
-
135
126
  /* Responsive Adjustments
136
127
  ---------------------------------------- */
137
128
  @media (max-width: 26em) {
138
129
  h2 {
139
130
  display: block;
140
131
  width: 100%;
141
- text-align: center;
142
132
  }
143
133
  }
144
134
 
145
- .help-us {
146
- display: flex;
147
- flex-direction: column;
148
- gap: 0.5em;
149
- }
150
-
151
135
  /* Accessibility Helpers
152
136
  ---------------------------------------- */
153
137
  .visually-hidden {
@@ -159,15 +143,3 @@ p:focus {
159
143
  white-space: nowrap;
160
144
  width: 1px;
161
145
  }
162
-
163
- /* This ensures the element remains hidden even when focused */
164
- .visually-hidden:focus,
165
- .visually-hidden:active {
166
- clip: auto;
167
- clip-path: none;
168
- height: auto;
169
- overflow: visible;
170
- position: static;
171
- white-space: normal;
172
- width: auto;
173
- }
@@ -1,5 +1,4 @@
1
1
  import { h } from "@stencil/core";
2
- const FEEDBACK_STORAGE_KEY = `pennlibs-feedback-${window.location.pathname}`;
3
2
  const FEEDBACK_TTL = 5 * 60 * 1000; // 5 minutes
4
3
  const FEEDBACK_QUESTION = 'Did you find what you need?';
5
4
  /**
@@ -21,28 +20,59 @@ export class PennlibsFeedback {
21
20
  this.hideQuestion = false;
22
21
  this.answer = undefined;
23
22
  this.selected = undefined;
23
+ this.currentUrl = '';
24
+ this.onNavigate = (event) => {
25
+ try {
26
+ const destinationUrl = new URL(event.destination.url).href;
27
+ if (destinationUrl !== this.currentUrl) {
28
+ this.currentUrl = destinationUrl;
29
+ this.selected = undefined;
30
+ this.answer = undefined;
31
+ this.loadStoredAnswer();
32
+ }
33
+ }
34
+ catch (_a) {
35
+ this.selected = undefined;
36
+ this.answer = undefined;
37
+ }
38
+ };
39
+ }
40
+ get storageKey() {
41
+ return `pennlibs-feedback-${this.currentUrl}`;
42
+ }
43
+ connectedCallback() {
44
+ this.currentUrl = window.location.href;
45
+ window.navigation.addEventListener('navigate', this.onNavigate);
46
+ }
47
+ disconnectedCallback() {
48
+ window.navigation.removeEventListener('navigate', this.onNavigate);
24
49
  }
25
50
  componentWillLoad() {
26
- const stored = sessionStorage.getItem(FEEDBACK_STORAGE_KEY);
51
+ this.loadStoredAnswer();
52
+ }
53
+ loadStoredAnswer() {
54
+ const stored = sessionStorage.getItem(this.storageKey);
27
55
  if (stored) {
28
56
  try {
29
57
  const { answer, timestamp } = JSON.parse(stored);
30
58
  if (Date.now() - timestamp > FEEDBACK_TTL) {
31
- sessionStorage.removeItem(FEEDBACK_STORAGE_KEY);
59
+ sessionStorage.removeItem(this.storageKey);
32
60
  }
33
61
  else {
34
62
  this.answer = answer;
35
63
  }
36
64
  }
37
65
  catch (_a) {
38
- sessionStorage.removeItem(FEEDBACK_STORAGE_KEY);
66
+ sessionStorage.removeItem(this.storageKey);
39
67
  }
40
68
  }
41
69
  }
42
- handleFeedback(answer) {
70
+ handleSubmit(event) {
43
71
  var _a;
72
+ event.preventDefault();
73
+ const answer = event.submitter.value;
44
74
  this.selected = answer;
45
- sessionStorage.setItem(FEEDBACK_STORAGE_KEY, JSON.stringify({ answer, timestamp: Date.now() }));
75
+ sessionStorage.setItem(this.storageKey, JSON.stringify({ answer, timestamp: Date.now() }));
46
76
  this.feedbackEvent.emit({
47
77
  question: FEEDBACK_QUESTION,
48
78
  answer: answer,
@@ -55,10 +85,10 @@ export class PennlibsFeedback {
55
85
  }, 600);
56
86
  }
57
87
  render() {
58
- return (h("div", { key: 'e470cb9ce96fecddda37c8a557c6670b581d8414', class: "feedback__container" }, h("div", { key: '0f3729d63102379f7219fd9a65c370f05c3f271c', class: "viewport-margins" }, h("div", { key: '3eaa8419d9b5fed5d7cf33de60ab93dd911afa34', class: "feedback__content" }, !this.hideQuestion && (this.answer === 'yes' ? (h("p", null, "Thank you for letting us know.")) : this.answer === 'no' ? (h("p", null, "We'd like to help. ", h("a", { href: "https://www.library.upenn.edu/contact-us" }, "Contact us"), " and let us know what you're looking for.")) : (h("div", { class: "feedback__inline-question" }, h("h2", null, "Did you find what you need?"), h("button", { class: { 'selected': this.selected === 'yes' }, disabled: !!this.selected, onClick: () => this.handleFeedback('yes') }, h("span", null, "Yes"), h("span", { class: "visually-hidden" }, ", I found what I needed.")), h("button", { class: { 'selected': this.selected === 'no' }, disabled: !!this.selected, onClick: () => this.handleFeedback('no') }, h("span", null, "No"), h("span", { class: "visually-hidden" }, ", I did not find what I needed."))))), h("div", { key: '50da9c1f23d14feeb6a2c408b0461a439331fcd9', class: "feedback__share-feedback" }, h("p", { key: '3580e25ecd7b463bb46103a6aee54a710e88c0ff' }, "To help us improve, ", h("a", { key: '276e226f4487ce94b9de30ae40f964e63f0d045b', href: `https://upenn.co1.qualtrics.com/jfe/form/SV_3xVrP7EKWS92zfE?reporting_from_url=${encodeURIComponent(window.location.href)}` }, "share your feedback"), "."))))));
88
+ return (h("div", { key: '12bdec6f975166a4c5d451fc1834f70fbce3b424', class: "feedback__container" }, h("div", { key: '4c607ceef5f10760d540d2549a2b186a871714c7', class: "viewport-margins" }, h("div", { key: 'a967498163e05ce60a12bf230d303caa31373c8d', class: "feedback__content" }, !this.hideQuestion && (this.answer === 'yes' ? (h("p", null, "Thank you for letting us know.")) : this.answer === 'no' ? (h("p", null, "We'd like to help. ", h("a", { href: "https://www.library.upenn.edu/contact-us" }, "Contact us"), " and let us know what you're looking for.")) : (h("form", { class: "feedback__inline-question", onSubmit: (e) => this.handleSubmit(e) }, h("h2", null, "Did you find what you need?"), h("button", { type: "submit", name: "answer", value: "yes", class: { 'selected': this.selected === 'yes' }, disabled: !!this.selected }, h("span", null, "Yes"), h("span", { class: "visually-hidden" }, ", I found what I needed.")), h("button", { type: "submit", name: "answer", value: "no", class: { 'selected': this.selected === 'no' }, disabled: !!this.selected }, h("span", null, "No"), h("span", { class: "visually-hidden" }, ", I did not find what I needed."))))), h("div", { key: 'f918da2833ae0c64e67a9e95551edaeb78e2ba05', class: "feedback__share-feedback" }, h("p", { key: '12928af116ffadf669cbc694160ee6ca3458528b' }, "To help us improve, ", h("a", { key: '7281b7423677b104fb622a7fdcf8e768517ea84e', href: `https://upenn.co1.qualtrics.com/jfe/form/SV_3xVrP7EKWS92zfE?reporting_from_url=${encodeURIComponent(window.location.href)}` }, "share your feedback"), "."))))));
59
89
  }
60
90
  static get is() { return "pennlibs-feedback"; }
61
- static get encapsulation() { return "shadow"; }
91
+ static get encapsulation() { return "scoped"; }
62
92
  static get originalStyleUrls() {
63
93
  return {
64
94
  "$": ["pennlibs-feedback.css"]
@@ -1 +1 @@
1
- {"version":3,"file":"pennlibs-feedback.js","sourceRoot":"","sources":["../../../src/components/pennlibs-feedback/pennlibs-feedback.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component, h, Prop, State, Event, EventEmitter } from '@stencil/core';\n\nconst FEEDBACK_STORAGE_KEY = `pennlibs-feedback-${window.location.pathname}`;\nconst FEEDBACK_TTL = 5 * 60 * 1000; // 5 minutes\nconst FEEDBACK_QUESTION = 'Did you find what you need?';\n\n\n/**\n * A feedback component that asks visitors \"Did you find what you need?\" and\n * links to a feedback form. The answer is stored in sessionStorage for 5 minutes\n * to avoid re-prompting during a browsing session.\n *\n * @example\n * <pennlibs-feedback></pennlibs-feedback>\n *\n * @example\n * <pennlibs-feedback hide-question></pennlibs-feedback>\n */\n@Component({\n tag: 'pennlibs-feedback',\n styleUrl: 'pennlibs-feedback.css',\n shadow: true,\n})\nexport class PennlibsFeedback {\n /**\n * When true, hides the yes/no question and only shows the \"share your feedback\" link.\n */\n @Prop() hideQuestion: boolean = false;\n\n @State() answer: string | undefined = undefined;\n @State() selected: string | undefined = undefined;\n\n /**\n * Emitted when a visitor answers the feedback question. Includes the question,\n * answer, current URL, and page heading/title for context.\n */\n @Event({\n eventName: 'pennlibs-feedback',\n composed: true,\n cancelable: true,\n bubbles: true,\n }) feedbackEvent!: EventEmitter<{\n question: string;\n answer: string;\n url: string;\n pageHeading?: string;\n pageTitle?: string;\n }>;\n\n componentWillLoad() {\n const stored = sessionStorage.getItem(FEEDBACK_STORAGE_KEY);\n if (stored) {\n try {\n const { answer, timestamp } = JSON.parse(stored);\n if (Date.now() - timestamp > FEEDBACK_TTL) {\n sessionStorage.removeItem(FEEDBACK_STORAGE_KEY);\n } else {\n this.answer = answer;\n }\n } catch {\n sessionStorage.removeItem(FEEDBACK_STORAGE_KEY);\n }\n }\n }\n\n handleFeedback(answer: string) {\n this.selected = answer;\n sessionStorage.setItem(FEEDBACK_STORAGE_KEY, JSON.stringify({ answer, timestamp: Date.now() }));\n\n this.feedbackEvent.emit({\n question: FEEDBACK_QUESTION,\n answer: answer,\n url: window.location.href,\n pageHeading: document.querySelector('h1')?.textContent || undefined,\n pageTitle: document.title || undefined\n });\n\n setTimeout(() => {\n this.answer = answer;\n }, 600);\n }\n \n render() {\n return (\n <div class=\"feedback__container\">\n <div class=\"viewport-margins\">\n <div class=\"feedback__content\">\n {!this.hideQuestion && (this.answer === 'yes' ? (\n <p>Thank you for letting us know.</p>\n ) : this.answer === 'no' ? (\n <p>We'd like to help. <a href=\"https://www.library.upenn.edu/contact-us\">Contact us</a> and let us know what you're looking for.</p>\n ) : (\n <div class=\"feedback__inline-question\">\n <h2>Did you find what you need?</h2>\n <button class={{ 'selected': this.selected === 'yes' }} disabled={!!this.selected} onClick={() => this.handleFeedback('yes')}>\n <span>Yes</span><span class=\"visually-hidden\">, I found what I needed.</span>\n </button>\n <button class={{ 'selected': this.selected === 'no' }} disabled={!!this.selected} onClick={() => this.handleFeedback('no')}>\n <span>No</span><span class=\"visually-hidden\">, I did not find what I needed.</span>\n </button>\n </div>\n ))}\n <div class=\"feedback__share-feedback\">\n <p>To help us improve, <a href={`https://upenn.co1.qualtrics.com/jfe/form/SV_3xVrP7EKWS92zfE?reporting_from_url=${encodeURIComponent(window.location.href)}`}>share your feedback</a>.</p>\n </div>\n </div>\n </div>\n </div>\n )\n }\n}\n\n"]}
1
+ {"version":3,"file":"pennlibs-feedback.js","sourceRoot":"","sources":["../../../src/components/pennlibs-feedback/pennlibs-feedback.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component, h, Prop, State, Event, EventEmitter } from '@stencil/core';\n\nconst FEEDBACK_TTL = 5 * 60 * 1000; // 5 minutes\nconst FEEDBACK_QUESTION = 'Did you find what you need?';\n\n\n/**\n * A feedback component that asks visitors \"Did you find what you need?\" and\n * links to a feedback form. The answer is stored in sessionStorage for 5 minutes\n * to avoid re-prompting during a browsing session.\n *\n * @example\n * <pennlibs-feedback></pennlibs-feedback>\n *\n * @example\n * <pennlibs-feedback hide-question></pennlibs-feedback>\n */\n@Component({\n tag: 'pennlibs-feedback',\n styleUrl: 'pennlibs-feedback.css',\n scoped: true,\n})\nexport class PennlibsFeedback {\n /**\n * When true, hides the yes/no question and only shows the \"share your feedback\" link.\n */\n @Prop() hideQuestion: boolean = false;\n\n @State() answer: string | undefined = undefined;\n @State() selected: string | undefined = undefined;\n\n private currentUrl: string = '';\n\n private get storageKey(): string {\n return `pennlibs-feedback-${this.currentUrl}`;\n }\n\n connectedCallback() {\n this.currentUrl = window.location.href;\n (window as any).navigation.addEventListener('navigate', this.onNavigate);\n }\n\n disconnectedCallback() {\n (window as any).navigation.removeEventListener('navigate', this.onNavigate);\n }\n\n private onNavigate = (event: any) => {\n try {\n const destinationUrl = new URL(event.destination.url).href;\n if (destinationUrl !== this.currentUrl) {\n this.currentUrl = destinationUrl;\n this.selected = undefined;\n this.answer = undefined;\n this.loadStoredAnswer();\n }\n } catch {\n this.selected = undefined;\n this.answer = undefined;\n }\n };\n\n /**\n * Emitted when a visitor answers the feedback question. Includes the question,\n * answer, current URL, and page heading/title for context.\n */\n @Event({\n eventName: 'pennlibs-feedback',\n composed: true,\n cancelable: true,\n bubbles: true,\n }) feedbackEvent!: EventEmitter<{\n question: string;\n answer: string;\n url: string;\n pageHeading?: string;\n pageTitle?: string;\n }>;\n\n componentWillLoad() {\n this.loadStoredAnswer();\n }\n\n private loadStoredAnswer() {\n const stored = sessionStorage.getItem(this.storageKey);\n if (stored) {\n try {\n const { answer, timestamp } = JSON.parse(stored);\n if (Date.now() - timestamp > FEEDBACK_TTL) {\n sessionStorage.removeItem(this.storageKey);\n } else {\n this.answer = answer;\n }\n } catch {\n sessionStorage.removeItem(this.storageKey);\n }\n }\n }\n\n handleSubmit(event: SubmitEvent) {\n event.preventDefault();\n const answer = (event.submitter as HTMLButtonElement).value;\n this.selected = answer;\n sessionStorage.setItem(this.storageKey, JSON.stringify({ answer, timestamp: Date.now() }));\n\n this.feedbackEvent.emit({\n question: FEEDBACK_QUESTION,\n answer: answer,\n url: window.location.href,\n pageHeading: document.querySelector('h1')?.textContent || undefined,\n pageTitle: document.title || undefined\n });\n\n setTimeout(() => {\n this.answer = answer;\n }, 600);\n }\n\n render() {\n return (\n <div class=\"feedback__container\">\n <div class=\"viewport-margins\">\n <div class=\"feedback__content\">\n {!this.hideQuestion && (this.answer === 'yes' ? (\n <p>Thank you for letting us know.</p>\n ) : this.answer === 'no' ? (\n <p>We'd like to help. <a href=\"https://www.library.upenn.edu/contact-us\">Contact us</a> and let us know what you're looking for.</p>\n ) : (\n <form class=\"feedback__inline-question\" onSubmit={(e) => this.handleSubmit(e as unknown as SubmitEvent)}>\n <h2>Did you find what you need?</h2>\n <button type=\"submit\" name=\"answer\" value=\"yes\" class={{ 'selected': this.selected === 'yes' }} disabled={!!this.selected}>\n <span>Yes</span><span class=\"visually-hidden\">, I found what I needed.</span>\n </button>\n <button type=\"submit\" name=\"answer\" value=\"no\" class={{ 'selected': this.selected === 'no' }} disabled={!!this.selected}>\n <span>No</span><span class=\"visually-hidden\">, I did not find what I needed.</span>\n </button>\n </form>\n ))}\n <div class=\"feedback__share-feedback\">\n <p>To help us improve, <a href={`https://upenn.co1.qualtrics.com/jfe/form/SV_3xVrP7EKWS92zfE?reporting_from_url=${encodeURIComponent(window.location.href)}`}>share your feedback</a>.</p>\n </div>\n </div>\n </div>\n </div>\n )\n }\n}\n"]}
@@ -1,8 +1,7 @@
1
1
  import { proxyCustomElement, HTMLElement, createEvent, h } from '@stencil/core/internal/client';
2
2
 
3
- const pennlibsFeedbackCss = ":host{display:block;background:#eeeff4;font-family:var(--pl-font-family);font-size:var(--pl-font-size);color:var(--pl-color-fg-default);line-height:1.4;box-sizing:border-box;padding:0.75em 0}@media print{:host{display:none}}*,*::before,*::after{box-sizing:border-box}.viewport-margins{max-width:var(--pl-viewport-margins-max-width);margin:0 auto;padding:0 var(--pl-viewport-margins-gutter, 1em)}.feedback__content{display:flex;justify-content:space-between;gap:var(--pl-space-s);flex-wrap:wrap}.feedback__inline-question{display:flex;flex-wrap:wrap;gap:0.5em;align-items:center}h2{display:inline-block;margin:0;font-family:var(--pl-font-sans-serif);font-size:1em;font-weight:400}p{margin:0;padding:calc(0.5em + 1px) 0}strong{font-weight:600}a{color:var(--pl-color-fg-accent);text-decoration:underline;text-underline-offset:var(--pl-link-text-underline-offset);text-decoration-thickness:var(--pl-link-hover-text-decoration-thickness)}button{all:unset;display:flex;align-items:center;gap:0.5em;padding:0.25em 1.25em;font-family:var(--pl-font-family);font-weight:500;line-height:1.4;color:var(--pl-color-fg-default);background:var(--pl-color-bg-default);border:solid 1px var(--pl-color-fg-subtle);border-radius:1em;box-sizing:border-box}button:hover{cursor:pointer}button:hover span{text-decoration:underline}button.selected{background:var(--pl-color-bg-accent-emphasis);color:var(--pl-color-fg-on-emphasis);border-color:var(--pl-color-bg-accent-emphasis)}.feedback__inline-question+.feedback__share-feedback,p{animation:none}.feedback__content>p{animation:fadeIn 300ms ease-in}@keyframes fadeIn{from{opacity:0}to{opacity:1}}*:focus{outline:0;box-shadow:0 0 0 2px var(--pl-color-bg-attention),\n 0 0 0 3px var(--pl-color-bg-emphasis)}p:focus{outline:none;box-shadow:0 0 0 2px var(--pl-color-bg-attention), 0 0 0 3px var(--pl-color-bg-emphasis)}@media (max-width: 26em){h2{display:block;width:100%;text-align:center}}.help-us{display:flex;flex-direction:column;gap:0.5em}.visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}.visually-hidden:focus,.visually-hidden:active{clip:auto;clip-path:none;height:auto;overflow:visible;position:static;white-space:normal;width:auto}";
3
+ const pennlibsFeedbackCss = ".feedback__container.sc-pennlibs-feedback{display:block;background:#eeeff4;font-family:var(--pl-font-family);font-size:var(--pl-font-size);color:var(--pl-color-fg-default);line-height:1.4;box-sizing:border-box;padding:0.75em 0}@media print{.sc-pennlibs-feedback-h{display:none}}*.sc-pennlibs-feedback,*.sc-pennlibs-feedback::before,*.sc-pennlibs-feedback::after{box-sizing:border-box}.viewport-margins.sc-pennlibs-feedback{max-width:var(--pl-viewport-margins-max-width);margin:0 auto;padding:0 var(--pl-viewport-margins-gutter, 1em)}.feedback__content.sc-pennlibs-feedback{display:flex;justify-content:space-between;gap:var(--pl-space-s);flex-wrap:wrap}.feedback__inline-question.sc-pennlibs-feedback{display:flex;flex-wrap:wrap;gap:0.5em;align-items:center}h2.sc-pennlibs-feedback{display:inline-block;margin:0;font-family:var(--pl-font-sans-serif);font-size:1em;font-weight:400}p.sc-pennlibs-feedback{margin:0;padding:calc(0.5em + 1px) 0}a.sc-pennlibs-feedback{color:var(--pl-color-fg-accent);text-decoration:underline;text-underline-offset:var(--pl-link-text-underline-offset);text-decoration-thickness:var(--pl-link-hover-text-decoration-thickness)}button.sc-pennlibs-feedback{all:unset;display:flex;align-items:center;gap:0.5em;padding:0.25em 1.25em;font-family:var(--pl-font-family);font-weight:500;line-height:1.4;color:var(--pl-color-fg-default);background:var(--pl-color-bg-default);border:solid 1px var(--pl-color-fg-subtle);border-radius:1em;box-sizing:border-box}button.sc-pennlibs-feedback:hover{cursor:pointer}button.sc-pennlibs-feedback:hover span.sc-pennlibs-feedback{text-decoration:underline}button.selected.sc-pennlibs-feedback{background:var(--pl-color-bg-accent-emphasis);color:var(--pl-color-fg-on-emphasis);border-color:var(--pl-color-bg-accent-emphasis)}.feedback__inline-question.sc-pennlibs-feedback+.feedback__share-feedback.sc-pennlibs-feedback,p.sc-pennlibs-feedback{animation:none}.feedback__content.sc-pennlibs-feedback>p.sc-pennlibs-feedback{animation:fadeIn 300ms ease-in}@keyframes fadeIn{from{opacity:0}to{opacity:1}}*.sc-pennlibs-feedback:focus{outline:0;box-shadow:0 0 0 2px var(--pl-color-bg-attention),\n 0 0 0 3px var(--pl-color-bg-emphasis)}@media (max-width: 26em){h2.sc-pennlibs-feedback{display:block;width:100%}}.visually-hidden.sc-pennlibs-feedback{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}";
4
4
 
5
- const FEEDBACK_STORAGE_KEY = `pennlibs-feedback-${window.location.pathname}`;
6
5
  const FEEDBACK_TTL = 5 * 60 * 1000; // 5 minutes
7
6
  const FEEDBACK_QUESTION = 'Did you find what you need?';
8
7
  const PennlibsFeedback$1 = /*@__PURE__*/ proxyCustomElement(class PennlibsFeedback extends HTMLElement {
@@ -11,7 +10,6 @@ const PennlibsFeedback$1 = /*@__PURE__*/ proxyCustomElement(class PennlibsFeedba
11
10
  if (registerHost !== false) {
12
11
  this.__registerHost();
13
12
  }
14
- this.__attachShadow();
15
13
  this.feedbackEvent = createEvent(this, "pennlibs-feedback", 7);
16
14
  /**
17
15
  * When true, hides the yes/no question and only shows the "share your feedback" link.
@@ -19,28 +17,59 @@ const PennlibsFeedback$1 = /*@__PURE__*/ proxyCustomElement(class PennlibsFeedba
19
17
  this.hideQuestion = false;
20
18
  this.answer = undefined;
21
19
  this.selected = undefined;
20
+ this.currentUrl = '';
21
+ this.onNavigate = (event) => {
22
+ try {
23
+ const destinationUrl = new URL(event.destination.url).href;
24
+ if (destinationUrl !== this.currentUrl) {
25
+ this.currentUrl = destinationUrl;
26
+ this.selected = undefined;
27
+ this.answer = undefined;
28
+ this.loadStoredAnswer();
29
+ }
30
+ }
31
+ catch (_a) {
32
+ this.selected = undefined;
33
+ this.answer = undefined;
34
+ }
35
+ };
36
+ }
37
+ get storageKey() {
38
+ return `pennlibs-feedback-${this.currentUrl}`;
39
+ }
40
+ connectedCallback() {
41
+ this.currentUrl = window.location.href;
42
+ window.navigation.addEventListener('navigate', this.onNavigate);
43
+ }
44
+ disconnectedCallback() {
45
+ window.navigation.removeEventListener('navigate', this.onNavigate);
22
46
  }
23
47
  componentWillLoad() {
24
- const stored = sessionStorage.getItem(FEEDBACK_STORAGE_KEY);
48
+ this.loadStoredAnswer();
49
+ }
50
+ loadStoredAnswer() {
51
+ const stored = sessionStorage.getItem(this.storageKey);
25
52
  if (stored) {
26
53
  try {
27
54
  const { answer, timestamp } = JSON.parse(stored);
28
55
  if (Date.now() - timestamp > FEEDBACK_TTL) {
29
- sessionStorage.removeItem(FEEDBACK_STORAGE_KEY);
56
+ sessionStorage.removeItem(this.storageKey);
30
57
  }
31
58
  else {
32
59
  this.answer = answer;
33
60
  }
34
61
  }
35
62
  catch (_a) {
36
- sessionStorage.removeItem(FEEDBACK_STORAGE_KEY);
63
+ sessionStorage.removeItem(this.storageKey);
37
64
  }
38
65
  }
39
66
  }
40
- handleFeedback(answer) {
67
+ handleSubmit(event) {
41
68
  var _a;
69
+ event.preventDefault();
70
+ const answer = event.submitter.value;
42
71
  this.selected = answer;
43
- sessionStorage.setItem(FEEDBACK_STORAGE_KEY, JSON.stringify({ answer, timestamp: Date.now() }));
72
+ sessionStorage.setItem(this.storageKey, JSON.stringify({ answer, timestamp: Date.now() }));
44
73
  this.feedbackEvent.emit({
45
74
  question: FEEDBACK_QUESTION,
46
75
  answer: answer,
@@ -53,10 +82,10 @@ const PennlibsFeedback$1 = /*@__PURE__*/ proxyCustomElement(class PennlibsFeedba
53
82
  }, 600);
54
83
  }
55
84
  render() {
56
- return (h("div", { key: 'e470cb9ce96fecddda37c8a557c6670b581d8414', class: "feedback__container" }, h("div", { key: '0f3729d63102379f7219fd9a65c370f05c3f271c', class: "viewport-margins" }, h("div", { key: '3eaa8419d9b5fed5d7cf33de60ab93dd911afa34', class: "feedback__content" }, !this.hideQuestion && (this.answer === 'yes' ? (h("p", null, "Thank you for letting us know.")) : this.answer === 'no' ? (h("p", null, "We'd like to help. ", h("a", { href: "https://www.library.upenn.edu/contact-us" }, "Contact us"), " and let us know what you're looking for.")) : (h("div", { class: "feedback__inline-question" }, h("h2", null, "Did you find what you need?"), h("button", { class: { 'selected': this.selected === 'yes' }, disabled: !!this.selected, onClick: () => this.handleFeedback('yes') }, h("span", null, "Yes"), h("span", { class: "visually-hidden" }, ", I found what I needed.")), h("button", { class: { 'selected': this.selected === 'no' }, disabled: !!this.selected, onClick: () => this.handleFeedback('no') }, h("span", null, "No"), h("span", { class: "visually-hidden" }, ", I did not find what I needed."))))), h("div", { key: '50da9c1f23d14feeb6a2c408b0461a439331fcd9', class: "feedback__share-feedback" }, h("p", { key: '3580e25ecd7b463bb46103a6aee54a710e88c0ff' }, "To help us improve, ", h("a", { key: '276e226f4487ce94b9de30ae40f964e63f0d045b', href: `https://upenn.co1.qualtrics.com/jfe/form/SV_3xVrP7EKWS92zfE?reporting_from_url=${encodeURIComponent(window.location.href)}` }, "share your feedback"), "."))))));
85
+ return (h("div", { key: '12bdec6f975166a4c5d451fc1834f70fbce3b424', class: "feedback__container" }, h("div", { key: '4c607ceef5f10760d540d2549a2b186a871714c7', class: "viewport-margins" }, h("div", { key: 'a967498163e05ce60a12bf230d303caa31373c8d', class: "feedback__content" }, !this.hideQuestion && (this.answer === 'yes' ? (h("p", null, "Thank you for letting us know.")) : this.answer === 'no' ? (h("p", null, "We'd like to help. ", h("a", { href: "https://www.library.upenn.edu/contact-us" }, "Contact us"), " and let us know what you're looking for.")) : (h("form", { class: "feedback__inline-question", onSubmit: (e) => this.handleSubmit(e) }, h("h2", null, "Did you find what you need?"), h("button", { type: "submit", name: "answer", value: "yes", class: { 'selected': this.selected === 'yes' }, disabled: !!this.selected }, h("span", null, "Yes"), h("span", { class: "visually-hidden" }, ", I found what I needed.")), h("button", { type: "submit", name: "answer", value: "no", class: { 'selected': this.selected === 'no' }, disabled: !!this.selected }, h("span", null, "No"), h("span", { class: "visually-hidden" }, ", I did not find what I needed."))))), h("div", { key: 'f918da2833ae0c64e67a9e95551edaeb78e2ba05', class: "feedback__share-feedback" }, h("p", { key: '12928af116ffadf669cbc694160ee6ca3458528b' }, "To help us improve, ", h("a", { key: '7281b7423677b104fb622a7fdcf8e768517ea84e', href: `https://upenn.co1.qualtrics.com/jfe/form/SV_3xVrP7EKWS92zfE?reporting_from_url=${encodeURIComponent(window.location.href)}` }, "share your feedback"), "."))))));
57
86
  }
58
87
  static get style() { return pennlibsFeedbackCss; }
59
- }, [257, "pennlibs-feedback", {
88
+ }, [258, "pennlibs-feedback", {
60
89
  "hideQuestion": [4, "hide-question"],
61
90
  "answer": [32],
62
91
  "selected": [32]
@@ -1 +1 @@
1
- {"file":"pennlibs-feedback.js","mappings":"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","names":["PennlibsFeedback","__stencil_proxyCustomElement"],"sources":["src/components/pennlibs-feedback/pennlibs-feedback.css?tag=pennlibs-feedback&encapsulation=shadow","src/components/pennlibs-feedback/pennlibs-feedback.tsx"],"sourcesContent":["/* Component Root Styles\n---------------------------------------- */\n:host {\n display: block;\n background: #eeeff4;\n font-family: var(--pl-font-family);\n font-size: var(--pl-font-size);\n color: var(--pl-color-fg-default);\n line-height: 1.4;\n box-sizing: border-box;\n padding: 0.75em 0;\n}\n\n@media print {\n :host {\n display: none;\n }\n}\n\n*, *::before, *::after {\n box-sizing: border-box;\n}\n\n.viewport-margins {\n max-width: var(--pl-viewport-margins-max-width);\n margin: 0 auto;\n padding: 0 var(--pl-viewport-margins-gutter, 1em);\n}\n\n.feedback__content {\n display: flex;\n justify-content: space-between;\n gap: var(--pl-space-s);\n flex-wrap: wrap;\n}\n\n/* Container Layout\n---------------------------------------- */\n.feedback__inline-question {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5em;\n align-items: center;\n}\n\n/* Typography\n---------------------------------------- */\nh2 {\n display: inline-block;\n margin: 0;\n font-family: var(--pl-font-sans-serif);\n font-size: 1em;\n font-weight: 400;\n}\n\np {\n margin: 0;\n padding: calc(0.5em + 1px) 0;\n}\n\nstrong {\n font-weight: 600;\n}\n\n/* Links\n---------------------------------------- */\na {\n color: var(--pl-color-fg-accent);\n text-decoration: underline;\n text-underline-offset: var(--pl-link-text-underline-offset);\n text-decoration-thickness: var(--pl-link-hover-text-decoration-thickness);\n}\n\n/* Buttons\n---------------------------------------- */\nbutton {\n all: unset;\n display: flex;\n align-items: center;\n gap: 0.5em;\n padding: 0.25em 1.25em;\n font-family: var(--pl-font-family);\n font-weight: 500;\n line-height: 1.4;\n color: var(--pl-color-fg-default);\n background: var(--pl-color-bg-default);\n border: solid 1px var(--pl-color-fg-subtle);\n border-radius: 1em;\n box-sizing: border-box;\n}\n\nbutton:hover {\n cursor: pointer;\n}\n\nbutton:hover span {\n text-decoration: underline;\n}\n\nbutton.selected {\n background: var(--pl-color-bg-accent-emphasis);\n color: var(--pl-color-fg-on-emphasis);\n border-color: var(--pl-color-bg-accent-emphasis);\n}\n\n/* Thank you message fade-in */\n.feedback__inline-question + .feedback__share-feedback,\np {\n animation: none;\n}\n\n.feedback__content > p {\n animation: fadeIn 300ms ease-in;\n}\n\n@keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n/* Focus States\n---------------------------------------- */\n*:focus {\n outline: 0;\n box-shadow: \n 0 0 0 2px var(--pl-color-bg-attention),\n 0 0 0 3px var(--pl-color-bg-emphasis);\n}\n\np:focus {\n outline: none;\n box-shadow: 0 0 0 2px var(--pl-color-bg-attention), 0 0 0 3px var(--pl-color-bg-emphasis);\n}\n\n/* Responsive Adjustments\n---------------------------------------- */\n@media (max-width: 26em) {\n h2 {\n display: block;\n width: 100%;\n text-align: center;\n }\n}\n\n.help-us {\n display: flex;\n flex-direction: column;\n gap: 0.5em;\n}\n\n/* Accessibility Helpers\n---------------------------------------- */\n.visually-hidden {\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n height: 1px;\n overflow: hidden;\n position: absolute;\n white-space: nowrap;\n width: 1px;\n}\n\n/* This ensures the element remains hidden even when focused */\n.visually-hidden:focus,\n.visually-hidden:active {\n clip: auto;\n clip-path: none;\n height: auto;\n overflow: visible;\n position: static;\n white-space: normal;\n width: auto;\n}","import { Component, h, Prop, State, Event, EventEmitter } from '@stencil/core';\n\nconst FEEDBACK_STORAGE_KEY = `pennlibs-feedback-${window.location.pathname}`;\nconst FEEDBACK_TTL = 5 * 60 * 1000; // 5 minutes\nconst FEEDBACK_QUESTION = 'Did you find what you need?';\n\n\n/**\n * A feedback component that asks visitors \"Did you find what you need?\" and\n * links to a feedback form. The answer is stored in sessionStorage for 5 minutes\n * to avoid re-prompting during a browsing session.\n *\n * @example\n * <pennlibs-feedback></pennlibs-feedback>\n *\n * @example\n * <pennlibs-feedback hide-question></pennlibs-feedback>\n */\n@Component({\n tag: 'pennlibs-feedback',\n styleUrl: 'pennlibs-feedback.css',\n shadow: true,\n})\nexport class PennlibsFeedback {\n /**\n * When true, hides the yes/no question and only shows the \"share your feedback\" link.\n */\n @Prop() hideQuestion: boolean = false;\n\n @State() answer: string | undefined = undefined;\n @State() selected: string | undefined = undefined;\n\n /**\n * Emitted when a visitor answers the feedback question. Includes the question,\n * answer, current URL, and page heading/title for context.\n */\n @Event({\n eventName: 'pennlibs-feedback',\n composed: true,\n cancelable: true,\n bubbles: true,\n }) feedbackEvent!: EventEmitter<{\n question: string;\n answer: string;\n url: string;\n pageHeading?: string;\n pageTitle?: string;\n }>;\n\n componentWillLoad() {\n const stored = sessionStorage.getItem(FEEDBACK_STORAGE_KEY);\n if (stored) {\n try {\n const { answer, timestamp } = JSON.parse(stored);\n if (Date.now() - timestamp > FEEDBACK_TTL) {\n sessionStorage.removeItem(FEEDBACK_STORAGE_KEY);\n } else {\n this.answer = answer;\n }\n } catch {\n sessionStorage.removeItem(FEEDBACK_STORAGE_KEY);\n }\n }\n }\n\n handleFeedback(answer: string) {\n this.selected = answer;\n sessionStorage.setItem(FEEDBACK_STORAGE_KEY, JSON.stringify({ answer, timestamp: Date.now() }));\n\n this.feedbackEvent.emit({\n question: FEEDBACK_QUESTION,\n answer: answer,\n url: window.location.href,\n pageHeading: document.querySelector('h1')?.textContent || undefined,\n pageTitle: document.title || undefined\n });\n\n setTimeout(() => {\n this.answer = answer;\n }, 600);\n }\n \n render() {\n return (\n <div class=\"feedback__container\">\n <div class=\"viewport-margins\">\n <div class=\"feedback__content\">\n {!this.hideQuestion && (this.answer === 'yes' ? (\n <p>Thank you for letting us know.</p>\n ) : this.answer === 'no' ? (\n <p>We'd like to help. <a href=\"https://www.library.upenn.edu/contact-us\">Contact us</a> and let us know what you're looking for.</p>\n ) : (\n <div class=\"feedback__inline-question\">\n <h2>Did you find what you need?</h2>\n <button class={{ 'selected': this.selected === 'yes' }} disabled={!!this.selected} onClick={() => this.handleFeedback('yes')}>\n <span>Yes</span><span class=\"visually-hidden\">, I found what I needed.</span>\n </button>\n <button class={{ 'selected': this.selected === 'no' }} disabled={!!this.selected} onClick={() => this.handleFeedback('no')}>\n <span>No</span><span class=\"visually-hidden\">, I did not find what I needed.</span>\n </button>\n </div>\n ))}\n <div class=\"feedback__share-feedback\">\n <p>To help us improve, <a href={`https://upenn.co1.qualtrics.com/jfe/form/SV_3xVrP7EKWS92zfE?reporting_from_url=${encodeURIComponent(window.location.href)}`}>share your feedback</a>.</p>\n </div>\n </div>\n </div>\n </div>\n )\n }\n}\n\n"],"version":3}
1
+ {"file":"pennlibs-feedback.js","mappings":"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","names":["PennlibsFeedback","__stencil_proxyCustomElement"],"sources":["src/components/pennlibs-feedback/pennlibs-feedback.css?tag=pennlibs-feedback&encapsulation=scoped","src/components/pennlibs-feedback/pennlibs-feedback.tsx"],"sourcesContent":["/* Component Root Styles\n---------------------------------------- */\n.feedback__container {\n display: block;\n background: #eeeff4;\n font-family: var(--pl-font-family);\n font-size: var(--pl-font-size);\n color: var(--pl-color-fg-default);\n line-height: 1.4;\n box-sizing: border-box;\n padding: 0.75em 0;\n}\n\n@media print {\n :host {\n display: none;\n }\n}\n\n*, *::before, *::after {\n box-sizing: border-box;\n}\n\n.viewport-margins {\n max-width: var(--pl-viewport-margins-max-width);\n margin: 0 auto;\n padding: 0 var(--pl-viewport-margins-gutter, 1em);\n}\n\n.feedback__content {\n display: flex;\n justify-content: space-between;\n gap: var(--pl-space-s);\n flex-wrap: wrap;\n}\n\n/* Container Layout\n---------------------------------------- */\n.feedback__inline-question {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5em;\n align-items: center;\n}\n\n/* Typography\n---------------------------------------- */\nh2 {\n display: inline-block;\n margin: 0;\n font-family: var(--pl-font-sans-serif);\n font-size: 1em;\n font-weight: 400;\n}\n\np {\n margin: 0;\n padding: calc(0.5em + 1px) 0;\n}\n\n/* Links\n---------------------------------------- */\na {\n color: var(--pl-color-fg-accent);\n text-decoration: underline;\n text-underline-offset: var(--pl-link-text-underline-offset);\n text-decoration-thickness: var(--pl-link-hover-text-decoration-thickness);\n}\n\n/* Buttons\n---------------------------------------- */\nbutton {\n all: unset;\n display: flex;\n align-items: center;\n gap: 0.5em;\n padding: 0.25em 1.25em;\n font-family: var(--pl-font-family);\n font-weight: 500;\n line-height: 1.4;\n color: var(--pl-color-fg-default);\n background: var(--pl-color-bg-default);\n border: solid 1px var(--pl-color-fg-subtle);\n border-radius: 1em;\n box-sizing: border-box;\n}\n\nbutton:hover {\n cursor: pointer;\n}\n\nbutton:hover span {\n text-decoration: underline;\n}\n\nbutton.selected {\n background: var(--pl-color-bg-accent-emphasis);\n color: var(--pl-color-fg-on-emphasis);\n border-color: var(--pl-color-bg-accent-emphasis);\n}\n\n/* Thank you message fade-in */\n.feedback__inline-question + .feedback__share-feedback,\np {\n animation: none;\n}\n\n.feedback__content > p {\n animation: fadeIn 300ms ease-in;\n}\n\n@keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n/* Focus States\n---------------------------------------- */\n*:focus {\n outline: 0;\n box-shadow: \n 0 0 0 2px var(--pl-color-bg-attention),\n 0 0 0 3px var(--pl-color-bg-emphasis);\n}\n\n/* Responsive Adjustments\n---------------------------------------- */\n@media (max-width: 26em) {\n h2 {\n display: block;\n width: 100%;\n }\n}\n\n/* Accessibility Helpers\n---------------------------------------- */\n.visually-hidden {\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n height: 1px;\n overflow: hidden;\n position: absolute;\n white-space: nowrap;\n width: 1px;\n}\n","import { Component, h, Prop, State, Event, EventEmitter } from '@stencil/core';\n\nconst FEEDBACK_TTL = 5 * 60 * 1000; // 5 minutes\nconst FEEDBACK_QUESTION = 'Did you find what you need?';\n\n\n/**\n * A feedback component that asks visitors \"Did you find what you need?\" and\n * links to a feedback form. The answer is stored in sessionStorage for 5 minutes\n * to avoid re-prompting during a browsing session.\n *\n * @example\n * <pennlibs-feedback></pennlibs-feedback>\n *\n * @example\n * <pennlibs-feedback hide-question></pennlibs-feedback>\n */\n@Component({\n tag: 'pennlibs-feedback',\n styleUrl: 'pennlibs-feedback.css',\n scoped: true,\n})\nexport class PennlibsFeedback {\n /**\n * When true, hides the yes/no question and only shows the \"share your feedback\" link.\n */\n @Prop() hideQuestion: boolean = false;\n\n @State() answer: string | undefined = undefined;\n @State() selected: string | undefined = undefined;\n\n private currentUrl: string = '';\n\n private get storageKey(): string {\n return `pennlibs-feedback-${this.currentUrl}`;\n }\n\n connectedCallback() {\n this.currentUrl = window.location.href;\n (window as any).navigation.addEventListener('navigate', this.onNavigate);\n }\n\n disconnectedCallback() {\n (window as any).navigation.removeEventListener('navigate', this.onNavigate);\n }\n\n private onNavigate = (event: any) => {\n try {\n const destinationUrl = new URL(event.destination.url).href;\n if (destinationUrl !== this.currentUrl) {\n this.currentUrl = destinationUrl;\n this.selected = undefined;\n this.answer = undefined;\n this.loadStoredAnswer();\n }\n } catch {\n this.selected = undefined;\n this.answer = undefined;\n }\n };\n\n /**\n * Emitted when a visitor answers the feedback question. Includes the question,\n * answer, current URL, and page heading/title for context.\n */\n @Event({\n eventName: 'pennlibs-feedback',\n composed: true,\n cancelable: true,\n bubbles: true,\n }) feedbackEvent!: EventEmitter<{\n question: string;\n answer: string;\n url: string;\n pageHeading?: string;\n pageTitle?: string;\n }>;\n\n componentWillLoad() {\n this.loadStoredAnswer();\n }\n\n private loadStoredAnswer() {\n const stored = sessionStorage.getItem(this.storageKey);\n if (stored) {\n try {\n const { answer, timestamp } = JSON.parse(stored);\n if (Date.now() - timestamp > FEEDBACK_TTL) {\n sessionStorage.removeItem(this.storageKey);\n } else {\n this.answer = answer;\n }\n } catch {\n sessionStorage.removeItem(this.storageKey);\n }\n }\n }\n\n handleSubmit(event: SubmitEvent) {\n event.preventDefault();\n const answer = (event.submitter as HTMLButtonElement).value;\n this.selected = answer;\n sessionStorage.setItem(this.storageKey, JSON.stringify({ answer, timestamp: Date.now() }));\n\n this.feedbackEvent.emit({\n question: FEEDBACK_QUESTION,\n answer: answer,\n url: window.location.href,\n pageHeading: document.querySelector('h1')?.textContent || undefined,\n pageTitle: document.title || undefined\n });\n\n setTimeout(() => {\n this.answer = answer;\n }, 600);\n }\n\n render() {\n return (\n <div class=\"feedback__container\">\n <div class=\"viewport-margins\">\n <div class=\"feedback__content\">\n {!this.hideQuestion && (this.answer === 'yes' ? (\n <p>Thank you for letting us know.</p>\n ) : this.answer === 'no' ? (\n <p>We'd like to help. <a href=\"https://www.library.upenn.edu/contact-us\">Contact us</a> and let us know what you're looking for.</p>\n ) : (\n <form class=\"feedback__inline-question\" onSubmit={(e) => this.handleSubmit(e as unknown as SubmitEvent)}>\n <h2>Did you find what you need?</h2>\n <button type=\"submit\" name=\"answer\" value=\"yes\" class={{ 'selected': this.selected === 'yes' }} disabled={!!this.selected}>\n <span>Yes</span><span class=\"visually-hidden\">, I found what I needed.</span>\n </button>\n <button type=\"submit\" name=\"answer\" value=\"no\" class={{ 'selected': this.selected === 'no' }} disabled={!!this.selected}>\n <span>No</span><span class=\"visually-hidden\">, I did not find what I needed.</span>\n </button>\n </form>\n ))}\n <div class=\"feedback__share-feedback\">\n <p>To help us improve, <a href={`https://upenn.co1.qualtrics.com/jfe/form/SV_3xVrP7EKWS92zfE?reporting_from_url=${encodeURIComponent(window.location.href)}`}>share your feedback</a>.</p>\n </div>\n </div>\n </div>\n </div>\n )\n }\n}\n"],"version":3}
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-03-16T15:51:31",
2
+ "timestamp": "2026-03-24T15:34:58",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.38.1",
@@ -189,7 +189,7 @@
189
189
  },
190
190
  {
191
191
  "filePath": "src/components/pennlibs-feedback/pennlibs-feedback.tsx",
192
- "encapsulation": "shadow",
192
+ "encapsulation": "scoped",
193
193
  "tag": "pennlibs-feedback",
194
194
  "readme": "# pennlibs-feedback\n\n\n",
195
195
  "docs": "A feedback component that asks visitors \"Did you find what you need?\" and\nlinks to a feedback form. The answer is stored in sessionStorage for 5 minutes\nto avoid re-prompting during a browsing session.",