@limetech/lime-elements 40.6.2 → 40.7.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/cjs/lime-elements.cjs.js +1 -1
  3. package/dist/cjs/limel-file-viewer.cjs.entry.js +71 -30
  4. package/dist/cjs/limel-markdown.cjs.entry.js +2 -2
  5. package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +1 -1
  6. package/dist/cjs/limel-tab-bar.cjs.entry.js +39 -55
  7. package/dist/cjs/limel-tab-panel.cjs.entry.js +7 -2
  8. package/dist/cjs/loader.cjs.js +1 -1
  9. package/dist/cjs/{markdown-exporter-C-UW43FF.js → markdown-exporter-VtX_2D1d.js} +40 -11
  10. package/dist/cjs/{markdown-parser-ssDij8_l.js → markdown-parser-BYtTHL4W.js} +11 -3
  11. package/dist/collection/components/tab-bar/tab-bar.css +213 -450
  12. package/dist/collection/components/tab-bar/tab-bar.js +62 -55
  13. package/dist/collection/components/tab-panel/tab-panel.css +9 -0
  14. package/dist/collection/components/tab-panel/tab-panel.js +27 -1
  15. package/dist/esm/lime-elements.js +1 -1
  16. package/dist/esm/limel-file-viewer.entry.js +71 -30
  17. package/dist/esm/limel-markdown.entry.js +2 -2
  18. package/dist/esm/limel-prosemirror-adapter.entry.js +1 -1
  19. package/dist/esm/limel-tab-bar.entry.js +39 -55
  20. package/dist/esm/limel-tab-panel.entry.js +7 -2
  21. package/dist/esm/loader.js +1 -1
  22. package/dist/esm/{markdown-exporter-DblYRMhY.js → markdown-exporter-tb8ft8Gq.js} +40 -11
  23. package/dist/esm/{markdown-parser-CAPDx7i8.js → markdown-parser-DFP65EFu.js} +11 -3
  24. package/dist/lime-elements/lime-elements.esm.js +1 -1
  25. package/dist/lime-elements/p-14a28a08.entry.js +1 -0
  26. package/dist/lime-elements/p-1740cb87.entry.js +1 -0
  27. package/dist/lime-elements/{p-22fd1c87.entry.js → p-21ab902a.entry.js} +1 -1
  28. package/dist/lime-elements/{p-05038bbb.entry.js → p-91a572c8.entry.js} +1 -1
  29. package/dist/lime-elements/p-Bgn2bikC.js +1 -0
  30. package/dist/lime-elements/p-C0wwdPYT.js +7 -0
  31. package/dist/lime-elements/p-aa897903.entry.js +1 -0
  32. package/dist/types/components/tab-bar/tab-bar.d.ts +17 -12
  33. package/dist/types/components/tab-panel/tab-panel.d.ts +6 -0
  34. package/dist/types/components.d.ts +48 -10
  35. package/package.json +4 -4
  36. package/dist/lime-elements/p-2e33d2a4.entry.js +0 -1
  37. package/dist/lime-elements/p-9e084e7c.entry.js +0 -1
  38. package/dist/lime-elements/p-Bvyt2bmV.js +0 -1
  39. package/dist/lime-elements/p-I0PrvthC.js +0 -7
  40. package/dist/lime-elements/p-a550ba18.entry.js +0 -1
@@ -626,6 +626,14 @@ function decodeParameterValueContinuations(header) {
626
626
  delete header.params[key];
627
627
  });
628
628
  paramKeys.forEach((paramVal, key) => {
629
+ if (Object.prototype.hasOwnProperty.call(header.params, key)) {
630
+ // The same name was also given as a plain parameter, which the starred keys were
631
+ // just deleted from around, so this write would be the only one here to override a
632
+ // name already taken. `filename="plain"; filename*0="cont"` resolves to the plain
633
+ // parameter either way round, so the reading does not come down to which of the
634
+ // two spellings the sender put first. See storeParam in mime-node.ts
635
+ return;
636
+ }
629
637
  let result = '';
630
638
  // Adjacent encoded sections are decoded together, because a single multi byte
631
639
  // character may be percent encoded across a section boundary.
@@ -651,12 +659,24 @@ function decodeParameterValueContinuations(header) {
651
659
  class PassThroughDecoder {
652
660
  constructor() {
653
661
  this.chunks = [];
662
+ this.pendingLineBreak = false;
654
663
  }
664
+ // The line break is written when the next line arrives, not after each line. The
665
+ // CRLF in front of a multipart boundary belongs to the boundary (RFC 2046 5.1.1), so
666
+ // the last line of a part ended by a boundary must not carry one.
655
667
  update(line) {
668
+ if (this.pendingLineBreak) {
669
+ this.chunks.push('\n');
670
+ }
656
671
  this.chunks.push(line);
657
- this.chunks.push('\n');
672
+ this.pendingLineBreak = true;
658
673
  }
659
- finalize() {
674
+ // A part ended by the end of the message has no boundary to own its final line
675
+ // break, so there it stays content
676
+ finalize(boundaryEnded = false) {
677
+ if (!boundaryEnded && this.pendingLineBreak) {
678
+ this.chunks.push('\n');
679
+ }
660
680
  // convert an array of arraybuffers into a blob and then back into a single arraybuffer
661
681
  return blobToArrayBuffer(new Blob(this.chunks, { type: 'application/octet-stream' }));
662
682
  }
@@ -712,6 +732,7 @@ class QPDecoder {
712
732
  this.buffer = new Uint8Array(this.maxChunkSize);
713
733
  this.bufferPos = 0;
714
734
  this.chunks = [];
735
+ this.pendingLineBreak = false;
715
736
  }
716
737
  writeByte(byte) {
717
738
  if (this.bufferPos >= this.buffer.length) {
@@ -742,7 +763,13 @@ class QPDecoder {
742
763
  // the result is handed on as bytes. Running the body charset over the encoded source
743
764
  // instead corrupted every part whose charset was not ASCII compatible: the same
744
765
  // content that decoded correctly in base64 came out as mojibake in quoted-printable.
766
+ //
767
+ // As in PassThroughDecoder, a hard line break is only written once the next line
768
+ // arrives, so the CRLF that belongs to a following boundary is not decoded as content.
745
769
  update(line) {
770
+ if (this.pendingLineBreak) {
771
+ this.writeByte(CHR_LF);
772
+ }
746
773
  let len = line.length;
747
774
  // a line ending in '=' is a soft line break, the newline is not part of the content
748
775
  const softBreak = len > 0 && line[len - 1] === CHR_EQUALS;
@@ -766,11 +793,13 @@ class QPDecoder {
766
793
  literalStart = i + 1;
767
794
  }
768
795
  this.writeBytes(line, literalStart, len);
769
- if (!softBreak) {
796
+ this.pendingLineBreak = !softBreak;
797
+ }
798
+ // see PassThroughDecoder.finalize
799
+ finalize(boundaryEnded = false) {
800
+ if (!boundaryEnded && this.pendingLineBreak) {
770
801
  this.writeByte(CHR_LF);
771
802
  }
772
- }
773
- finalize() {
774
803
  this.flushBuffer();
775
804
  // convert an array of arraybuffers into a blob and then back into a single arraybuffer
776
805
  return blobToArrayBuffer(new Blob(this.chunks, { type: 'application/octet-stream' }));
@@ -868,7 +897,9 @@ class MimeNode {
868
897
  this.contentDecoder = new PassThroughDecoder();
869
898
  }
870
899
  }
871
- async finalize() {
900
+ // `boundaryEnded` tells that the part was ended by a multipart boundary, which owns
901
+ // the line break after the last line of the part (RFC 2046 5.1.1)
902
+ async finalize(boundaryEnded = false) {
872
903
  if (this.state === 'finished') {
873
904
  return;
874
905
  }
@@ -884,19 +915,19 @@ class MimeNode {
884
915
  break;
885
916
  }
886
917
  }
887
- await this.finalizeChildNodes();
888
- this.content = this.contentDecoder ? await this.contentDecoder.finalize() : null;
918
+ await this.finalizeChildNodes(boundaryEnded);
919
+ this.content = this.contentDecoder ? await this.contentDecoder.finalize(boundaryEnded) : null;
889
920
  // The decoder buffers every body line it received, so keeping it around
890
921
  // retains a second copy of the content for the lifetime of the node.
891
922
  // Nothing reads it once the node is finished, so release it here.
892
923
  this.contentDecoder = null;
893
924
  this.state = 'finished';
894
925
  }
895
- async finalizeChildNodes() {
926
+ async finalizeChildNodes(boundaryEnded = false) {
896
927
  // Children are only ever appended, so everything before the cursor is already
897
928
  // finished and re-visiting it only costs time.
898
929
  while (this.finalizedChildCount < this.childNodes.length) {
899
- await this.childNodes[this.finalizedChildCount++].finalize();
930
+ await this.childNodes[this.finalizedChildCount++].finalize(boundaryEnded);
900
931
  }
901
932
  }
902
933
  // Strip RFC 822 comments (parenthesized text) from structured header values.
@@ -999,11 +1030,16 @@ class MimeNode {
999
1030
  let quote = false;
1000
1031
  let escaped = false;
1001
1032
  let chr;
1002
- const addChr = (c) => {
1033
+ // Whitespace ahead of the first character of a value is padding and is dropped, the
1034
+ // whitespace between two characters of it is content
1035
+ const flushSpace = () => {
1003
1036
  if (value.length) {
1004
1037
  value += pendingSpace;
1005
1038
  }
1006
1039
  pendingSpace = '';
1040
+ };
1041
+ const addChr = (c) => {
1042
+ flushSpace();
1007
1043
  value += c;
1008
1044
  };
1009
1045
  const takeValue = () => {
@@ -1017,9 +1053,10 @@ class MimeNode {
1017
1053
  // headers are resolved. Letting the last one win means `boundary="b"; boundary="c"`
1018
1054
  // registers a boundary that no delimiter in the message matches, which drops the
1019
1055
  // body without an error. hasOwnProperty, because a parameter may be named
1020
- // `constructor` or `toString`.
1056
+ // `constructor` or `toString`. A name is a token and a token is never empty, so the
1057
+ // nameless parameter of `text/plain; =v` names nothing and is dropped.
1021
1058
  const storeParam = (name, result) => {
1022
- if (!Object.prototype.hasOwnProperty.call(response.params, name)) {
1059
+ if (name && !Object.prototype.hasOwnProperty.call(response.params, name)) {
1023
1060
  response.params[name] = result;
1024
1061
  }
1025
1062
  };
@@ -1036,10 +1073,7 @@ class MimeNode {
1036
1073
  // next one. Without this the name would keep growing across the `;` and swallow
1037
1074
  // whatever followed, which is how `x=1; flag; boundary="AAA"` loses its boundary.
1038
1075
  const storeEmptyKey = () => {
1039
- const name = takeValue().trim();
1040
- if (name) {
1041
- storeParam(name.toLowerCase(), '');
1042
- }
1076
+ storeParam(takeValue().trim().toLowerCase(), '');
1043
1077
  };
1044
1078
  for (let i = 0, len = str.length; i < len; i++) {
1045
1079
  chr = str.charAt(i);
@@ -1057,6 +1091,22 @@ class MimeNode {
1057
1091
  value += chr;
1058
1092
  break;
1059
1093
  case 'value':
1094
+ if (quoteClosed && chr !== ';') {
1095
+ // Nothing behind a closed quoted string reaches the value. RFC 2045
1096
+ // says a parameter value is a token or a quoted string, not both, so
1097
+ // what follows one is junk and only the `;` that ends the parameter
1098
+ // still counts. Tested ahead of the branches rather than beside the
1099
+ // append at the foot of them, where each branch above was a way
1100
+ // around it. A second `"` reopened quoting, which both carried the
1101
+ // whitespace in front of it into the value and took the `;` along, so
1102
+ // `boundary="AAA" "; boundary=BBB"` registered a boundary of `AAA `
1103
+ // that no delimiter matches and the whole body was dropped without an
1104
+ // error; the escape branch appended arbitrary characters the same way.
1105
+ // quoteClosed is only ever set while no quote is open, and this is
1106
+ // what keeps one from being opened afterwards.
1107
+ escaped = false;
1108
+ break;
1109
+ }
1060
1110
  if (escaped) {
1061
1111
  addChr(chr);
1062
1112
  }
@@ -1073,12 +1123,7 @@ class MimeNode {
1073
1123
  }
1074
1124
  else if (!quote && chr === '"') {
1075
1125
  quote = chr;
1076
- // whitespace before a quote that opens the value is padding, but
1077
- // between a token and a quoted string it is content
1078
- if (value.length) {
1079
- value += pendingSpace;
1080
- }
1081
- pendingSpace = '';
1126
+ flushSpace();
1082
1127
  }
1083
1128
  else if (!quote && chr === ';') {
1084
1129
  storeValue();
@@ -1087,13 +1132,9 @@ class MimeNode {
1087
1132
  else if (!quote && (chr === ' ' || chr === '\t')) {
1088
1133
  pendingSpace += chr;
1089
1134
  }
1090
- else if (!quoteClosed) {
1135
+ else {
1091
1136
  addChr(chr);
1092
1137
  }
1093
- // Anything else is trailing junk after a closed quoted string. RFC 2045
1094
- // says a parameter value is a token or a quoted string, not both, and
1095
- // appending the junk is how `boundary="AAA" (unterminated comment`
1096
- // turned into a boundary that no delimiter in the message matches.
1097
1138
  escaped = false;
1098
1139
  break;
1099
1140
  }
@@ -4988,12 +5029,12 @@ class PostalMime {
4988
5029
  continue;
4989
5030
  }
4990
5031
  if (isTerminator) {
4991
- await boundary.node.finalize();
5032
+ await boundary.node.finalize(true);
4992
5033
  this.currentNode = boundary.node.parentNode || this.root;
4993
5034
  }
4994
5035
  else {
4995
5036
  // finalize any open child nodes (should be just one though)
4996
- await boundary.node.finalizeChildNodes();
5037
+ await boundary.node.finalizeChildNodes(true);
4997
5038
  this.currentNode = new MimeNode({
4998
5039
  postalMime: this,
4999
5040
  parentNode: boundary.node,
@@ -1,5 +1,5 @@
1
1
  import { r as registerInstance, h, H as Host } from './index-BU9IJqli.js';
2
- import { m as markdownToHTML } from './markdown-parser-CAPDx7i8.js';
2
+ import { m as markdownToHTML } from './markdown-parser-DFP65EFu.js';
3
3
  import { g as globalConfig } from './config-Dnt5w_Bp.js';
4
4
  import { d as defaultSchema } from './index-BN64nlbO.js';
5
5
  import { a as adaptColorContrast } from './adapt-color-contrast-BQoih_t0.js';
@@ -1136,7 +1136,7 @@ const Markdown = class {
1136
1136
  */
1137
1137
  async toMarkdown() {
1138
1138
  await this.rendering;
1139
- const { exportMarkdown } = await import('./markdown-exporter-DblYRMhY.js');
1139
+ const { exportMarkdown } = await import('./markdown-exporter-tb8ft8Gq.js');
1140
1140
  return exportMarkdown(this.rootElement, this.cachedCombinedWhitelist);
1141
1141
  }
1142
1142
  textChanged() {
@@ -1,6 +1,6 @@
1
1
  import { r as registerInstance, c as createEvent, h, H as Host, a as getElement } from './index-BU9IJqli.js';
2
2
  import { L as LevelMapping, E as EditorMenuTypes, i as isInlineImageTag, M as MouseButtons, e as editorMenuTypesArray } from './types-C_Yu8dOg.js';
3
- import { g as getLinkAttributes, m as markdownToHTML, s as sanitizeHTML } from './markdown-parser-CAPDx7i8.js';
3
+ import { g as getLinkAttributes, m as markdownToHTML, s as sanitizeHTML } from './markdown-parser-DFP65EFu.js';
4
4
  import { c as cloneDeep } from './cloneDeep-DAbOtbs8.js';
5
5
  import { t as translations } from './translations-Y4i8PVc9.js';
6
6
  import { c as decodeHTML, e as decodeHTMLStrict } from './index-BN64nlbO.js';
@@ -2,10 +2,8 @@ import { r as registerInstance, c as createEvent, h, a as getElement } from './i
2
2
  import { g as getIconName, b as getIconColor } from './get-icon-props-CgNJbSP4.js';
3
3
  import { A as ARROW_UP, b as ARROW_DOWN, H as HOME, c as END, d as ARROW_LEFT, e as ARROW_RIGHT } from './keycodes-DQ5DmW_Y.js';
4
4
  import { i as isEqual } from './isEqual-CE83yS8T.js';
5
- import { M as MDCRipple } from './component-CrjPGt1I.js';
6
5
  import { S as SetCache, c as cacheHas } from './_baseIsEqual-CyF4P8uM.js';
7
6
  import { a as arrayIncludes, b as baseRest, i as isArrayLikeObject, c as baseFlatten } from './isArrayLikeObject-CJB8HbtH.js';
8
- import './ponyfill-6YuZiAPi.js';
9
7
  import './eq-CZ30nDJE.js';
10
8
  import './_getTag-BiAaLWvH.js';
11
9
  import './isObject-BJQylLSL.js';
@@ -259,12 +257,8 @@ function findReachable(count, start, step, wrap, canMoveTo) {
259
257
  return NO_NAVIGATION_TARGET;
260
258
  }
261
259
 
262
- const tabBarCss = () => `.mdc-tab-bar{width:100%}.mdc-tab{height:48px}.mdc-tab--stacked{height:72px}.mdc-tab-indicator .mdc-tab-indicator__content--underline{border-color:#6200ee;border-color:var(--mdc-theme-primary, #6200ee)}.mdc-tab-indicator .mdc-tab-indicator__content--icon{color:#018786;color:var(--mdc-theme-secondary, #018786)}.mdc-tab-indicator .mdc-tab-indicator__content--underline{border-top-width:2px}.mdc-tab-indicator .mdc-tab-indicator__content--icon{height:34px;font-size:34px}.mdc-tab-indicator{display:flex;position:absolute;top:0;left:0;justify-content:center;width:100%;height:100%;pointer-events:none;z-index:1}.mdc-tab-indicator__content{transform-origin:left;opacity:0}.mdc-tab-indicator__content--underline{align-self:flex-end;box-sizing:border-box;width:100%;border-top-style:solid}.mdc-tab-indicator__content--icon{align-self:center;margin:0 auto}.mdc-tab-indicator--active .mdc-tab-indicator__content{opacity:1}.mdc-tab-indicator .mdc-tab-indicator__content{transition:250ms transform cubic-bezier(0.4, 0, 0.2, 1)}.mdc-tab-indicator--no-transition .mdc-tab-indicator__content{transition:none}.mdc-tab-indicator--fade .mdc-tab-indicator__content{transition:150ms opacity linear}.mdc-tab-indicator--active.mdc-tab-indicator--fade .mdc-tab-indicator__content{transition-delay:100ms}.mdc-tab{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-family:Roboto, sans-serif;font-family:var(--mdc-typography-button-font-family, var(--mdc-typography-font-family, Roboto, sans-serif));font-size:0.875rem;font-size:var(--mdc-typography-button-font-size, 0.875rem);line-height:2.25rem;line-height:var(--mdc-typography-button-line-height, 2.25rem);font-weight:500;font-weight:var(--mdc-typography-button-font-weight, 500);letter-spacing:0.0892857143em;letter-spacing:var(--mdc-typography-button-letter-spacing, 0.0892857143em);text-decoration:none;text-decoration:var(--mdc-typography-button-text-decoration, none);text-transform:uppercase;text-transform:var(--mdc-typography-button-text-transform, uppercase)}.mdc-tab .mdc-tab__text-label{color:rgba(0, 0, 0, 0.6)}.mdc-tab .mdc-tab__icon{color:rgba(0, 0, 0, 0.54);fill:currentColor}.mdc-tab{position:relative}.mdc-tab__content{position:relative}.mdc-tab__icon{width:24px;height:24px;font-size:24px}.mdc-tab--active .mdc-tab__text-label{color:#6200ee;color:var(--mdc-theme-primary, #6200ee)}.mdc-tab--active .mdc-tab__icon{color:#6200ee;color:var(--mdc-theme-primary, #6200ee);fill:currentColor}.mdc-tab{background:none}.mdc-tab{min-width:90px;padding-right:24px;padding-left:24px;display:flex;flex:1 0 auto;justify-content:center;box-sizing:border-box;margin:0;padding-top:0;padding-bottom:0;border:none;outline:none;text-align:center;white-space:nowrap;cursor:pointer;-webkit-appearance:none;z-index:1}.mdc-tab::-moz-focus-inner{padding:0;border:0}.mdc-tab--min-width{flex:0 1 auto}.mdc-tab__content{display:flex;align-items:center;justify-content:center;height:inherit;pointer-events:none}.mdc-tab__text-label{transition:150ms color linear;display:inline-block;line-height:1;z-index:2}.mdc-tab__icon{transition:150ms color linear;z-index:2}.mdc-tab--stacked .mdc-tab__content{flex-direction:column;align-items:center;justify-content:center}.mdc-tab--stacked .mdc-tab__text-label{padding-top:6px;padding-bottom:4px}.mdc-tab--active .mdc-tab__text-label,.mdc-tab--active .mdc-tab__icon{transition-delay:100ms}.mdc-tab:not(.mdc-tab--stacked) .mdc-tab__icon+.mdc-tab__text-label{padding-left:8px;padding-right:0}[dir=rtl] .mdc-tab:not(.mdc-tab--stacked) .mdc-tab__icon+.mdc-tab__text-label,.mdc-tab:not(.mdc-tab--stacked) .mdc-tab__icon+.mdc-tab__text-label[dir=rtl]{padding-left:0;padding-right:8px;}@keyframes mdc-ripple-fg-radius-in{from{animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transform:translate(var(--mdc-ripple-fg-translate-start, 0)) scale(1)}to{transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}}@keyframes mdc-ripple-fg-opacity-in{from{animation-timing-function:linear;opacity:0}to{opacity:var(--mdc-ripple-fg-opacity, 0)}}@keyframes mdc-ripple-fg-opacity-out{from{animation-timing-function:linear;opacity:var(--mdc-ripple-fg-opacity, 0)}to{opacity:0}}.mdc-tab{--mdc-ripple-fg-size:0;--mdc-ripple-left:0;--mdc-ripple-top:0;--mdc-ripple-fg-scale:1;--mdc-ripple-fg-translate-end:0;--mdc-ripple-fg-translate-start:0;-webkit-tap-highlight-color:rgba(0, 0, 0, 0)}.mdc-tab .mdc-tab__ripple::before,.mdc-tab .mdc-tab__ripple::after{position:absolute;border-radius:50%;opacity:0;pointer-events:none;content:""}.mdc-tab .mdc-tab__ripple::before{transition:opacity 15ms linear, background-color 15ms linear;z-index:1;z-index:var(--mdc-ripple-z-index, 1)}.mdc-tab .mdc-tab__ripple::after{z-index:0;z-index:var(--mdc-ripple-z-index, 0)}.mdc-tab.mdc-ripple-upgraded .mdc-tab__ripple::before{transform:scale(var(--mdc-ripple-fg-scale, 1))}.mdc-tab.mdc-ripple-upgraded .mdc-tab__ripple::after{top:0;left:0;transform:scale(0);transform-origin:center center}.mdc-tab.mdc-ripple-upgraded--unbounded .mdc-tab__ripple::after{top:var(--mdc-ripple-top, 0);left:var(--mdc-ripple-left, 0)}.mdc-tab.mdc-ripple-upgraded--foreground-activation .mdc-tab__ripple::after{animation:mdc-ripple-fg-radius-in 225ms forwards, mdc-ripple-fg-opacity-in 75ms forwards}.mdc-tab.mdc-ripple-upgraded--foreground-deactivation .mdc-tab__ripple::after{animation:mdc-ripple-fg-opacity-out 150ms;transform:translate(var(--mdc-ripple-fg-translate-end, 0)) scale(var(--mdc-ripple-fg-scale, 1))}.mdc-tab .mdc-tab__ripple::before,.mdc-tab .mdc-tab__ripple::after{top:calc(50% - 100%);left:calc(50% - 100%);width:200%;height:200%}.mdc-tab.mdc-ripple-upgraded .mdc-tab__ripple::after{width:var(--mdc-ripple-fg-size, 100%);height:var(--mdc-ripple-fg-size, 100%)}.mdc-tab .mdc-tab__ripple::before,.mdc-tab .mdc-tab__ripple::after{background-color:#6200ee;background-color:var(--mdc-ripple-color, var(--mdc-theme-primary, #6200ee))}.mdc-tab:hover .mdc-tab__ripple::before,.mdc-tab.mdc-ripple-surface--hover .mdc-tab__ripple::before{opacity:0.04;opacity:var(--mdc-ripple-hover-opacity, 0.04)}.mdc-tab.mdc-ripple-upgraded--background-focused .mdc-tab__ripple::before,.mdc-tab:not(.mdc-ripple-upgraded):focus .mdc-tab__ripple::before{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-focus-opacity, 0.12)}.mdc-tab:not(.mdc-ripple-upgraded) .mdc-tab__ripple::after{transition:opacity 150ms linear}.mdc-tab:not(.mdc-ripple-upgraded):active .mdc-tab__ripple::after{transition-duration:75ms;opacity:0.12;opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-tab.mdc-ripple-upgraded{--mdc-ripple-fg-opacity:var(--mdc-ripple-press-opacity, 0.12)}.mdc-tab__ripple{position:absolute;top:0;left:0;width:100%;height:100%;overflow:hidden;will-change:transform, opacity}:host(limel-tab-bar){--limel-tab-background-color:var(--contrast-300);--limel-tab-border-radius:0.625rem;--limel-active-tab-background-color:var( --tab-panel-background-color, rgb(var(--contrast-100)) );--limel-tab-active-outer-edge-curve-size:0.75rem;--limel-tab-separator-width:0.125rem;--limel-tab-separator-background-color:rgb(var(--contrast-600));isolation:isolate;display:block;position:relative}limel-scroller{--limel-scroller-fade-color:var(--limel-tab-background-color);--limel-scroller-content-padding:0.25rem var(--limel-tab-active-outer-edge-curve-size) 0;background-color:rgb(var(--limel-tab-background-color))}:host(.has-tabs-with-equal-width) .mdc-tab{flex:1 0 auto}.mdc-tab{font-family:inherit;font-weight:400;letter-spacing:normal;font-size:var(--limel-theme-default-font-size);text-transform:none}.mdc-tab-indicator .mdc-tab-indicator__content{border:none}.mdc-tab__ripple{box-sizing:border-box;border-radius:var(--limel-tab-border-radius);border-style:solid;border-color:transparent;border-width:0.25rem;opacity:0.7}.mdc-tab__ripple:before,.mdc-tab__ripple:after{transition:background-color 0.5s ease}.mdc-tab{border-radius:0;padding-right:1rem;padding-left:1rem;min-width:2.5rem;background-color:transparent;flex:0 0 auto;height:2.5rem}.mdc-tab:not(.mdc-tab--active):after{content:"";display:block;background-color:var(--limel-tab-separator-background-color);width:var(--limel-tab-separator-width);height:1rem;margin:auto;position:absolute;top:0;bottom:0;border-radius:1rem;right:calc(-1 * var(--limel-tab-separator-width))}.mdc-tab:not(.mdc-tab--active):last-of-type:after{display:none}.mdc-tab .mdc-tab__icon{color:rgb(var(--contrast-800));margin-left:-0.25rem}.mdc-tab limel-badge{margin-right:-0.25rem;box-shadow:0 0 0 1px rgb(var(--contrast-600))}.mdc-tab--active{border-radius:var(--limel-tab-border-radius) var(--limel-tab-border-radius) 0 0;background-color:var(--limel-active-tab-background-color);z-index:2}.mdc-tab--active:before,.mdc-tab--active:after{content:"";display:block;width:var(--limel-tab-active-outer-edge-curve-size);height:var(--limel-tab-active-outer-edge-curve-size);position:absolute;bottom:0;background-color:var(--limel-active-tab-background-color);-webkit-mask-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20fill-rule='evenodd'%20stroke-linejoin='round'%20stroke-miterlimit='2'%20clip-rule='evenodd'%20viewBox='0%200%2050%2050'%3E%3Cdefs/%3E%3Cpath%20d='M0%200c0%2027.594%2022.406%2050%2050%2050H0V0z'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20fill-rule='evenodd'%20stroke-linejoin='round'%20stroke-miterlimit='2'%20clip-rule='evenodd'%20viewBox='0%200%2050%2050'%3E%3Cdefs/%3E%3Cpath%20d='M0%200c0%2027.594%2022.406%2050%2050%2050H0V0z'/%3E%3C/svg%3E")}.mdc-tab--active:before{left:calc(-1 * var(--limel-tab-active-outer-edge-curve-size));transform:rotateY(180deg)}.mdc-tab--active:after{right:calc(-1 * var(--limel-tab-active-outer-edge-curve-size))}.mdc-tab--active .mdc-ripple-upgraded--background-focused:before{background-color:transparent;transition:background-color 1s ease}.mdc-tab--active .mdc-tab__icon{color:var(--mdc-theme-primary)}.mdc-tab__content{gap:0.375rem}.mdc-tab .mdc-tab__text-label{transition:color 0.2s ease;padding-left:0 !important;color:var(--limel-theme-on-surface-color)}.mdc-tab:hover .mdc-tab__text-label{color:var(--limel-theme-text-primary-on-background-color)}.mdc-tab.mdc-tab--active .mdc-tab__text-label{color:var(--lime-primary-color, var(--limel-theme-primary-color))}`;
260
+ const tabBarCss = () => `@charset "UTF-8";:host(limel-tab-bar){--limel-tab-background-color:var(--contrast-300);--limel-tab-border-radius:0.625rem;--limel-tab-content-inset:0.25rem;--limel-active-tab-background-color:var( --tab-panel-background-color, rgb(var(--contrast-100)) );--limel-active-tab-color:var( --lime-primary-color, var(--limel-theme-primary-color) );--limel-tab-active-outer-edge-curve-size:0.75rem;--limel-tab-separator-width:0.125rem;--limel-tab-separator-background-color:rgb(var(--contrast-600));isolation:isolate;display:block;position:relative}limel-scroller{--limel-scroller-fade-color:var(--limel-tab-background-color);--limel-scroller-content-padding:0.25rem var(--limel-tab-active-outer-edge-curve-size) 0;background-color:rgb(var(--limel-tab-background-color))}:host(.has-tabs-with-equal-width:not([orientation=vertical])) button{flex:1 0 auto;max-width:var(--tab-bar-horizontal-tab-max-width, none)}button{appearance:none;background:none;border:none;padding:0;margin:0;font:inherit;color:inherit;text-align:inherit;position:relative;display:flex;box-sizing:border-box;border-radius:0;padding:var(--limel-tab-content-inset);min-width:2.5rem;background-color:transparent;flex:0 0 auto;height:2.5rem;outline:none;cursor:pointer;white-space:nowrap;font-size:var(--limel-theme-default-font-size)}button limel-icon{transition:color 0.2s ease;color:rgb(var(--contrast-800));margin-left:-0.25rem;flex-shrink:0}button span.text{transition:color 0.2s ease;line-height:1.25;overflow:hidden;text-overflow:ellipsis;color:var(--limel-theme-on-surface-color)}button:hover span.text{color:var(--limel-theme-text-primary-on-background-color)}button limel-badge{margin-right:-0.25rem;box-shadow:0 0 0 1px rgb(var(--contrast-600));pointer-events:none;flex-shrink:0}button[aria-selected=true]{background-color:var(--limel-active-tab-background-color);z-index:2}button[aria-selected=true]:before,button[aria-selected=true]:after{content:"";display:block;width:var(--limel-tab-active-outer-edge-curve-size);height:var(--limel-tab-active-outer-edge-curve-size);position:absolute;background-color:var(--limel-active-tab-background-color);-webkit-mask-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20fill-rule='evenodd'%20stroke-linejoin='round'%20stroke-miterlimit='2'%20clip-rule='evenodd'%20viewBox='0%200%2050%2050'%3E%3Cdefs/%3E%3Cpath%20d='M0%200c0%2027.594%2022.406%2050%2050%2050H0V0z'/%3E%3C/svg%3E");mask-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20fill-rule='evenodd'%20stroke-linejoin='round'%20stroke-miterlimit='2'%20clip-rule='evenodd'%20viewBox='0%200%2050%2050'%3E%3Cdefs/%3E%3Cpath%20d='M0%200c0%2027.594%2022.406%2050%2050%2050H0V0z'/%3E%3C/svg%3E")}button[aria-selected=true] limel-icon{color:var(--limel-active-tab-color)}button[aria-selected=true] span.text{color:var(--limel-active-tab-color)}span.content{transition:box-shadow 0.2s ease;display:flex;flex-grow:1;min-width:0;align-items:center;justify-content:center;gap:0.375rem;padding:0 0.75rem;border-radius:calc(var(--limel-tab-border-radius) - var(--limel-tab-content-inset))}button:focus-visible span.content{transition-duration:0.3s;box-shadow:var(--shadow-depth-8-focused)}:host(limel-tab-bar:not([orientation=vertical])) button{max-width:var(--tab-bar-horizontal-tab-max-width, 16rem)}:host(limel-tab-bar:not([orientation=vertical])) button:not([aria-selected=true]):after{content:"";display:block;background-color:var(--limel-tab-separator-background-color);width:var(--limel-tab-separator-width);height:1rem;margin:auto;position:absolute;top:0;bottom:0;border-radius:1rem;right:calc(-1 * var(--limel-tab-separator-width))}:host(limel-tab-bar:not([orientation=vertical])) button:not([aria-selected=true]):last-of-type:after{display:none}:host(limel-tab-bar:not([orientation=vertical])) button[aria-selected=true]{border-radius:var(--limel-tab-border-radius) var(--limel-tab-border-radius) 0 0}:host(limel-tab-bar:not([orientation=vertical])) button[aria-selected=true]:before,:host(limel-tab-bar:not([orientation=vertical])) button[aria-selected=true]:after{bottom:0}:host(limel-tab-bar:not([orientation=vertical])) button[aria-selected=true]:before{left:calc(-1 * var(--limel-tab-active-outer-edge-curve-size));transform:rotateY(180deg)}:host(limel-tab-bar:not([orientation=vertical])) button[aria-selected=true]:after{right:calc(-1 * var(--limel-tab-active-outer-edge-curve-size))}:host(limel-tab-bar[orientation=vertical]){width:var(--tab-bar-vertical-width, 10rem)}:host(limel-tab-bar[orientation=vertical]) div[role=tablist]{height:100%}:host(limel-tab-bar[orientation=vertical]) limel-scroller{--limel-scroller-content-padding:var( --limel-tab-active-outer-edge-curve-size ) 0 var(--limel-tab-active-outer-edge-curve-size) 0.25rem;height:100%}:host(limel-tab-bar[orientation=vertical]) button[aria-selected=true]{border-radius:var(--limel-tab-border-radius) 0 0 var(--limel-tab-border-radius)}:host(limel-tab-bar[orientation=vertical]) button[aria-selected=true]:before,:host(limel-tab-bar[orientation=vertical]) button[aria-selected=true]:after{right:0}:host(limel-tab-bar[orientation=vertical]) button[aria-selected=true]:before{bottom:100%;transform:rotateY(180deg)}:host(limel-tab-bar[orientation=vertical]) button[aria-selected=true]:after{top:100%;transform:rotate(180deg)}:host(limel-tab-bar[orientation=vertical]) span.content{justify-content:flex-start}:host(limel-tab-bar[orientation=vertical]) span.text{flex-grow:1}`;
263
261
 
264
- const NAVIGATION = {
265
- orientation: 'horizontal',
266
- wrap: true,
267
- };
268
262
  const TabBar = class {
269
263
  constructor(hostRef) {
270
264
  registerInstance(this, hostRef);
@@ -273,8 +267,13 @@ const TabBar = class {
273
267
  * List of tabs to display
274
268
  */
275
269
  this.tabs = [];
276
- this.ripples = new Map();
270
+ /**
271
+ * Whether the tabs are laid out in a row, above the content they belong
272
+ * to, or in a column, next to it.
273
+ */
274
+ this.orientation = 'horizontal';
277
275
  this.hasLoaded = false;
276
+ this.isLaidOutAgain = false;
278
277
  this.handleKeyDown = this.handleKeyDown.bind(this);
279
278
  }
280
279
  async connectedCallback() {
@@ -283,7 +282,6 @@ const TabBar = class {
283
282
  if (!this.hasLoaded) {
284
283
  return;
285
284
  }
286
- this.updateRipples();
287
285
  this.revealedTabId = undefined;
288
286
  await this.revealActiveTab('auto');
289
287
  }
@@ -292,15 +290,13 @@ const TabBar = class {
292
290
  this.triggerIconColorWarning();
293
291
  }
294
292
  async componentDidRender() {
295
- this.updateRipples();
296
- await this.revealActiveTab(this.hasLoaded ? undefined : 'auto');
297
- }
298
- disconnectedCallback() {
299
- this.destroyRipples();
293
+ const isLaidOutAgain = this.isLaidOutAgain;
294
+ this.isLaidOutAgain = false;
295
+ await this.revealActiveTab(!this.hasLoaded || isLaidOutAgain ? 'auto' : undefined, isLaidOutAgain);
300
296
  }
301
297
  render() {
302
- const tabStop = findTabStop(this.tabs, this.tabs.findIndex((tab) => tab.active), NAVIGATION);
303
- return (h("div", { key: '7ab809d50e3605613f027a1782d54511e734de93', class: "mdc-tab-bar", role: "tablist", onKeyDown: this.handleKeyDown }, h("limel-scroller", { key: 'd6ac2c90e6da77a239292ac0e90288c3e70b62f8' }, this.tabs.map((tab, index) => this.renderTab(tab, index, index === tabStop)))));
298
+ const tabStop = findTabStop(this.tabs, this.tabs.findIndex((tab) => tab.active), this.getNavigationOptions());
299
+ return (h("div", { key: 'd9f9e2659c8199ddd8202f04ed08535a91da2948', role: "tablist", "aria-orientation": this.getOrientation(), onKeyDown: this.handleKeyDown }, h("limel-scroller", { key: 'fdc0e8389ddc7ac8d0d63e5c777de6b6bf337697', orientation: this.getOrientation() }, this.tabs.map((tab, index) => this.renderTab(tab, index, index === tabStop)))));
304
300
  }
305
301
  tabsChanged(newTabs = [], oldTabs = []) {
306
302
  const newIds = newTabs.map((tab) => tab.id);
@@ -310,44 +306,31 @@ const TabBar = class {
310
306
  }
311
307
  this.revealedTabId = undefined;
312
308
  }
309
+ orientationChanged() {
310
+ this.revealedTabId = undefined;
311
+ this.isLaidOutAgain = true;
312
+ }
313
+ getOrientation() {
314
+ return this.orientation === 'vertical' ? 'vertical' : 'horizontal';
315
+ }
316
+ getNavigationOptions() {
317
+ return { orientation: this.getOrientation(), wrap: true };
318
+ }
313
319
  getTabElements() {
314
320
  return [
315
321
  ...this.host.shadowRoot.querySelectorAll('button[role="tab"]'),
316
322
  ];
317
323
  }
318
324
  /**
319
- * Gives every tab MDC's ripple, which is the feedback when a tab is
320
- * pressed. Tabs that are gone lose theirs.
321
- */
322
- updateRipples() {
323
- const tabs = this.getTabElements();
324
- for (const [tab, ripple] of this.ripples) {
325
- if (tabs.includes(tab)) {
326
- continue;
327
- }
328
- ripple.destroy();
329
- this.ripples.delete(tab);
330
- }
331
- for (const tab of tabs) {
332
- if (!this.ripples.has(tab)) {
333
- this.ripples.set(tab, new MDCRipple(tab));
334
- }
335
- }
336
- }
337
- destroyRipples() {
338
- for (const ripple of this.ripples.values()) {
339
- ripple.destroy();
340
- }
341
- this.ripples.clear();
342
- }
343
- /**
344
- * A tab that is activated by the user has focus, and the scroller reveals
345
- * what has focus. This is for a tab that becomes active without it.
325
+ * A tab that is activated by the user receives focus, and the scroller
326
+ * reveals what receives focus. This is for a tab that becomes active
327
+ * without it, or that keeps it while the bar is laid out again.
346
328
  *
347
329
  * @param behavior - `auto` to jump to the tab. Leave it out to let the
348
330
  * scroller glide there.
331
+ * @param evenWithFocus - reveal the tab also when it has focus
349
332
  */
350
- async revealActiveTab(behavior) {
333
+ async revealActiveTab(behavior, evenWithFocus = false) {
351
334
  const index = this.tabs.findIndex((tab) => tab.active);
352
335
  if (index === -1) {
353
336
  this.revealedTabId = undefined;
@@ -359,19 +342,23 @@ const TabBar = class {
359
342
  this.revealedTabId = this.tabs[index].id;
360
343
  const element = this.getTabElements()[index];
361
344
  const scroller = this.host.shadowRoot.querySelector('limel-scroller');
362
- if (!element || !scroller || element.matches(':focus')) {
345
+ if (!element || !scroller) {
346
+ return;
347
+ }
348
+ if (element.matches(':focus') && !evenWithFocus) {
363
349
  return;
364
350
  }
365
351
  await scroller.componentOnReady();
366
352
  await scroller.reveal(element, behavior);
367
353
  }
368
354
  handleKeyDown(event) {
369
- if (!isNavigationKey(event, NAVIGATION)) {
355
+ const options = this.getNavigationOptions();
356
+ if (!isNavigationKey(event, options)) {
370
357
  return;
371
358
  }
372
359
  event.preventDefault();
373
360
  const current = this.getTabElements().indexOf(event.target);
374
- this.activateTab(findNavigationTarget(this.tabs, event.key, current, NAVIGATION));
361
+ this.activateTab(findNavigationTarget(this.tabs, event.key, current, options));
375
362
  }
376
363
  activateTab(index) {
377
364
  if (index === NO_NAVIGATION_TARGET) {
@@ -403,16 +390,10 @@ const TabBar = class {
403
390
  if (color) {
404
391
  style.color = color;
405
392
  }
406
- return (h("limel-icon", { class: "mdc-tab__icon", name: name, style: style, size: "small", "aria-hidden": "true" }));
393
+ return (h("limel-icon", { name: name, style: style, size: "small", "aria-hidden": "true" }));
407
394
  }
408
395
  renderTab(tab, index, isTabStop) {
409
- return (h("button", { class: {
410
- 'mdc-tab': true,
411
- 'mdc-tab--active': !!tab.active,
412
- }, role: "tab", "aria-selected": tab.active ? 'true' : 'false', tabindex: isTabStop ? 0 : -1, onClick: () => this.activateTab(index) }, h("span", { class: "mdc-tab__content" }, this.renderIcon(tab), h("span", { class: "mdc-tab__text-label" }, tab.text), tab.badge ? h("limel-badge", { label: tab.badge }) : ''), h("span", { class: {
413
- 'mdc-tab-indicator': true,
414
- 'mdc-tab-indicator--active': !!tab.active,
415
- } }, h("span", { class: "mdc-tab-indicator__content mdc-tab-indicator__content--underline" })), h("span", { class: "mdc-tab__ripple" })));
396
+ return (h("button", { role: "tab", "aria-selected": tab.active ? 'true' : 'false', tabindex: isTabStop ? 0 : -1, onClick: () => this.activateTab(index) }, h("span", { class: "content" }, this.renderIcon(tab), h("span", { class: "text" }, tab.text), tab.badge ? h("limel-badge", { label: tab.badge }) : '')));
416
397
  }
417
398
  triggerIconColorWarning() {
418
399
  if (this.tabs.some((tab) => tab.iconColor)) {
@@ -423,6 +404,9 @@ const TabBar = class {
423
404
  static get watchers() { return {
424
405
  "tabs": [{
425
406
  "tabsChanged": 0
407
+ }],
408
+ "orientation": [{
409
+ "orientationChanged": 0
426
410
  }]
427
411
  }; }
428
412
  };
@@ -1,7 +1,7 @@
1
1
  import { r as registerInstance, c as createEvent, h, H as Host, a as getElement } from './index-BU9IJqli.js';
2
2
  import { d as dispatchResizeEvent } from './dispatch-resize-event-z_E3sq3p.js';
3
3
 
4
- const tabPanelCss = () => `:host(limel-tab-panel){--tab-panel-background-color:rgb(var(--contrast-100));display:block;height:100%}.tab-panel{height:100%;position:relative;display:flex;flex-direction:column}.tab-content{height:100%;flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch;box-sizing:border-box;background-color:var(--tab-panel-background-color)}`;
4
+ const tabPanelCss = () => `:host(limel-tab-panel){--tab-panel-background-color:rgb(var(--contrast-100));display:block;height:100%}.tab-panel{height:100%;position:relative;display:flex;flex-direction:column}.tab-content{height:100%;flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch;box-sizing:border-box;background-color:var(--tab-panel-background-color)}:host(limel-tab-panel[orientation=vertical]) div.tab-panel{flex-direction:row}:host(limel-tab-panel[orientation=vertical]) div.tab-content{min-width:0}`;
5
5
 
6
6
  const TabPanel = class {
7
7
  constructor(hostRef) {
@@ -11,6 +11,11 @@ const TabPanel = class {
11
11
  * The tabs to display in the panel
12
12
  */
13
13
  this.tabs = [];
14
+ /**
15
+ * Whether the tabs are laid out in a row, above the content, or in a
16
+ * column, to the left of it.
17
+ */
18
+ this.orientation = 'horizontal';
14
19
  this.slotElements = [];
15
20
  this.handleChangeTabs = this.handleChangeTabs.bind(this);
16
21
  this.setSlotElements = this.setSlotElements.bind(this);
@@ -44,7 +49,7 @@ const TabPanel = class {
44
49
  }
45
50
  }
46
51
  render() {
47
- return (h(Host, { key: 'acb9f2f1081972fc45104cc357055af883ebad2d', onChangeTab: this.handleChangeTabs }, h("div", { key: '318df7ddc8d28f5952c7e67b154088ca13f4355a', class: "tab-panel" }, h("limel-tab-bar", { key: '2656eb61f4e815eba9636bf939e368651bbd8dcf', tabs: this.tabs }), h("div", { key: '41d1bf3149a19d28d7d9f1ace0744ffe26811080', class: "tab-content" }, h("slot", { key: 'ee234615e96536b40ce089978cba5bd21a1fb129' })))));
52
+ return (h(Host, { key: '130cd711926c119be1b3084dfb966afe6d280926', onChangeTab: this.handleChangeTabs }, h("div", { key: 'e76da7ba8c93a3d9d4c03a84a01a5358b39b17ed', class: "tab-panel" }, h("limel-tab-bar", { key: '0866cd6c59e5e4ea372678a969bc646db81ed285', tabs: this.tabs, orientation: this.orientation }), h("div", { key: 'c0ee8b9d6bffcb32fc4894bf0ba7409ac194577d', class: "tab-content" }, h("slot", { key: '46b6cd024188a04ba466d831051cf3628996d97e' })))));
48
53
  }
49
54
  setSlotElements() {
50
55
  const slot = this.getSlot();