@descope/web-components-ui 3.1.4 → 3.1.6

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.
@@ -8965,10 +8965,14 @@ const subdivisionItem = ({ name, state_code, translations, lang }) => {
8965
8965
  return `<div data-id="${escapedStateCode}" data-name="${escapedSearchTerms}" data-label="${escapedLabel}">${escapedLabel}</div>`;
8966
8966
  };
8967
8967
 
8968
- const cityItem = ({ name }) => {
8968
+ const cityItem = ({ name, translations, lang }) => {
8969
+ const displayName = resolveTranslation({ name, translations }, lang);
8970
+ const searchTerms = [displayName];
8971
+ if (displayName !== name) searchTerms.push(name);
8969
8972
  const escapedId = escapeHtml(name);
8970
- const escapedName = escapeHtml(name);
8971
- return `<div data-id="${escapedId}" data-name="${escapedName}">${escapedName}</div>`;
8973
+ const escapedSearchTerms = escapeHtml(searchTerms.join(' '));
8974
+ const escapedLabel = escapeHtml(displayName);
8975
+ return `<div data-id="${escapedId}" data-name="${escapedSearchTerms}" data-label="${escapedLabel}">${escapedLabel}</div>`;
8972
8976
  };
8973
8977
 
8974
8978
  const comboBoxHTML = (id) =>
@@ -9028,6 +9032,7 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass$4 {
9028
9032
  #countriesMap = new Map();
9029
9033
  #cachedCountries = null;
9030
9034
  #cachedSubdivisions = null;
9035
+ #cachedCities = null;
9031
9036
  #labels = null;
9032
9037
 
9033
9038
  // Value requested programmatically before data has loaded.
@@ -9074,8 +9079,8 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass$4 {
9074
9079
  const lang = this.getAttribute('lang') || undefined;
9075
9080
  if (!lang) return undefined;
9076
9081
  try {
9077
- Intl.getCanonicalLocales(lang);
9078
- return lang;
9082
+ const [canonical] = Intl.getCanonicalLocales(lang);
9083
+ return canonical;
9079
9084
  } catch {
9080
9085
  return undefined; // invalid BCP47 tag — fall back to English
9081
9086
  }
@@ -9258,8 +9263,11 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass$4 {
9258
9263
 
9259
9264
  #setupValueTransform() {
9260
9265
  // Display only the item name in the input, while data-name includes ISO codes for search
9261
- [this.#countryComboBox, this.#subdivisionComboBox].forEach((combo) => {
9262
-
9266
+ [
9267
+ this.#countryComboBox,
9268
+ this.#subdivisionComboBox,
9269
+ this.#cityComboBox,
9270
+ ].forEach((combo) => {
9263
9271
  combo.customValueTransformFn = (val) => {
9264
9272
  const item = combo.baseElement?.items?.find(
9265
9273
  (i) => i['data-name'] === val,
@@ -9404,7 +9412,11 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass$4 {
9404
9412
  if (cities) {
9405
9413
  this.#cityVisible = cities.length > 0;
9406
9414
  if (cities.length > 0) {
9407
- this.#cityComboBox.data = cities;
9415
+ this.#cachedCities = cities;
9416
+ this.#cityComboBox.data = cities.map((c) => ({
9417
+ ...c,
9418
+ lang: this.#lang,
9419
+ }));
9408
9420
  if (pendingCity) toSelect.push([this.#cityComboBox, pendingCity]);
9409
9421
  }
9410
9422
  }
@@ -9515,7 +9527,6 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass$4 {
9515
9527
  if (!this.#pendingValue && this.#defaultCountry)
9516
9528
  this.#onCountrySelected(this.#defaultCountry);
9517
9529
  } catch (e) {
9518
-
9519
9530
  console.error(`[${componentName$V}] Failed to load countries`, e);
9520
9531
  } finally {
9521
9532
  this.#countryComboBox.removeAttribute('loading');
@@ -9540,7 +9551,6 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass$4 {
9540
9551
  this.#loadCities(countryIso2);
9541
9552
  }
9542
9553
  } catch (e) {
9543
-
9544
9554
  console.error(
9545
9555
  `[${componentName$V}] Failed to load subdivisions for ${countryIso2}`,
9546
9556
  e,
@@ -9562,10 +9572,13 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass$4 {
9562
9572
  this.#cityVisible = cities.length > 0;
9563
9573
  this.#refreshState();
9564
9574
  if (cities.length > 0) {
9565
- this.#cityComboBox.data = cities;
9575
+ this.#cachedCities = cities;
9576
+ this.#cityComboBox.data = cities.map((c) => ({
9577
+ ...c,
9578
+ lang: this.#lang,
9579
+ }));
9566
9580
  }
9567
9581
  } catch (e) {
9568
-
9569
9582
  console.error(
9570
9583
  `[${componentName$V}] Failed to load cities for ${countryIso2}${stateCode ? `/${stateCode}` : ''}`,
9571
9584
  e,
@@ -9590,6 +9603,14 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass$4 {
9590
9603
  if (prevSubdivision)
9591
9604
  this.#selectItemById(this.#subdivisionComboBox, prevSubdivision);
9592
9605
  }
9606
+ if (this.#cachedCities && this.#cityVisible) {
9607
+ const prevCity = this.#cityComboBox.value;
9608
+ this.#cityComboBox.data = this.#cachedCities.map((c) => ({
9609
+ ...c,
9610
+ lang: this.#lang,
9611
+ }));
9612
+ if (prevCity) this.#selectItemById(this.#cityComboBox, prevCity);
9613
+ }
9593
9614
  // Re-apply translated subdivision type label for the new lang
9594
9615
  const currentIso2 = this.#countryComboBox.value;
9595
9616
  if (currentIso2) {
@@ -9703,6 +9724,7 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass$4 {
9703
9724
  #resetCity() {
9704
9725
  this.#cityComboBox.value = '';
9705
9726
  this.#cityComboBox.data = [];
9727
+ this.#cachedCities = null;
9706
9728
  this.#cityVisible = false;
9707
9729
  this.#refreshState();
9708
9730
  }
@@ -17695,7 +17717,7 @@ const getValueType = (value) => {
17695
17717
  };
17696
17718
 
17697
17719
  const renderCodeSnippet = (value, lang) =>
17698
- `<descope-code-snippet lang="${lang}" class="row-details__value code">${escapeXML(value)}</descope-code-snippet>`;
17720
+ `<descope-code-snippet copy-button="true" lang="${lang}" class="row-details__value code">${escapeXML(value)}</descope-code-snippet>`;
17699
17721
 
17700
17722
  const renderText = (text) =>
17701
17723
  `<div class="row-details__value text" title="${text}">${escapeXML(text)}</div>`;
@@ -17723,16 +17745,31 @@ const defaultRowDetailsValueRenderer = (value) => {
17723
17745
  return renderText(value);
17724
17746
  };
17725
17747
 
17748
+ const isCodeSnippetValue = (value) => {
17749
+ const type = getValueType(value);
17750
+ return (
17751
+ type === 'object' ||
17752
+ type === 'xml' ||
17753
+ (type === 'array' && value.some((v) => getValueType(v) === 'object'))
17754
+ );
17755
+ };
17756
+
17726
17757
  const defaultRowDetailsRenderer = (item, itemLabelsMapping) => `
17727
17758
  <div class="row-details">
17728
17759
  ${Object.entries(item)
17729
- .map(
17730
- ([key, value]) =>
17731
- `<div class="row-details__item" >
17732
- <div class="row-details__label">${itemLabelsMapping[key] || toTitle(key)}</div>
17760
+ .map(([key, value]) => {
17761
+ const label = itemLabelsMapping[key] || toTitle(key);
17762
+ if (isCodeSnippetValue(value)) {
17763
+ return `<details class="row-details__item">
17764
+ <summary class="row-details__label">${label}</summary>
17733
17765
  ${defaultRowDetailsValueRenderer(value)}
17734
- </div>`
17735
- )
17766
+ </details>`;
17767
+ }
17768
+ return `<div class="row-details__item">
17769
+ <div class="row-details__label">${label}</div>
17770
+ ${defaultRowDetailsValueRenderer(value)}
17771
+ </div>`;
17772
+ })
17736
17773
  .join('\n')}
17737
17774
  </div>
17738
17775
  `;
@@ -17760,6 +17797,18 @@ const GridMixin = (superclass) =>
17760
17797
  };
17761
17798
 
17762
17799
  this.baseElement.rowDetailsRenderer = this.#rowDetailsRenderer.bind(this);
17800
+
17801
+ // Stop wheel events from propagating to vaadin-grid when scrolling
17802
+ // inside code snippets, so touchpad horizontal scroll works
17803
+ this.baseElement.addEventListener(
17804
+ 'wheel',
17805
+ (e) => {
17806
+ if (e.target.closest('descope-code-snippet')) {
17807
+ e.stopPropagation();
17808
+ }
17809
+ },
17810
+ true
17811
+ );
17763
17812
  }
17764
17813
 
17765
17814
  // this renders the details panel content
@@ -18070,6 +18119,14 @@ const GridClass = compose$1(
18070
18119
  grid-column: 1 / -1;
18071
18120
  order: 2;
18072
18121
  }
18122
+ vaadin-grid details.row-details__item {
18123
+ padding: 0;
18124
+ }
18125
+ vaadin-grid details.row-details__item > summary.row-details__label {
18126
+ cursor: pointer;
18127
+ list-style: revert;
18128
+ display: revert;
18129
+ }
18073
18130
  vaadin-grid .row-details__value.text {
18074
18131
  overflow: hidden;
18075
18132
  text-overflow: ellipsis;
@@ -18077,8 +18134,7 @@ const GridClass = compose$1(
18077
18134
  }
18078
18135
  vaadin-grid .row-details__value.code {
18079
18136
  margin-top: 5px;
18080
- max-height: 120px;
18081
- overflow: scroll;
18137
+ overflow-x: auto;
18082
18138
  font-size: 0.85em;
18083
18139
  }
18084
18140
  vaadin-grid vaadin-icon.toggle-details-button {
@@ -20009,18 +20065,24 @@ const decode = (input) => {
20009
20065
 
20010
20066
  const tpl = (input, inline) => (inline ? input : `<pre>${input}</pre>`);
20011
20067
 
20068
+ var copyIconSrc = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPgogIDxyZWN0IHg9IjkiIHk9IjkiIHdpZHRoPSIxMyIgaGVpZ2h0PSIxMyIgcng9IjIiIHJ5PSIyIj48L3JlY3Q+CiAgPHBhdGggZD0iTTUgMTVINGEyIDIgMCAwIDEtMi0yVjRhMiAyIDAgMCAxIDItMmg5YTIgMiAwIDAgMSAyIDJ2MSI+PC9wYXRoPgo8L3N2Zz4K";
20069
+
20070
+ var checkIconSrc = "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iY2hlY2staWNvbiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj4KICA8cG9seWxpbmUgcG9pbnRzPSIyMCA2IDkgMTcgNCAxMiI+PC9wb2x5bGluZT4KPC9zdmc+Cg==";
20071
+
20012
20072
  const componentName$e = getComponentName$1('code-snippet');
20013
20073
 
20014
- let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: componentName$e, baseSelector: ':host > code' }) {
20074
+ let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: componentName$e, baseSelector: ':host > .wrapper' }) {
20015
20075
  static get observedAttributes() {
20016
- return ['lang', 'inline'];
20076
+ return ['lang', 'inline', 'copy-button'];
20017
20077
  }
20018
20078
 
20019
20079
  constructor() {
20020
20080
  super();
20021
20081
 
20022
20082
  this.attachShadow({ mode: 'open' }).innerHTML = `
20023
- <code class="hljs"></code>
20083
+ <div class="wrapper">
20084
+ <code class="hljs"></code>
20085
+ </div>
20024
20086
  `;
20025
20087
 
20026
20088
  injectStyle(
@@ -20029,6 +20091,10 @@ let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: c
20029
20091
  display: inline-block;
20030
20092
  width: 100%;
20031
20093
  }
20094
+ .wrapper {
20095
+ position: relative;
20096
+ width: 100%;
20097
+ }
20032
20098
  code {
20033
20099
  display: block;
20034
20100
  width: 100%;
@@ -20039,6 +20105,38 @@ let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: c
20039
20105
  pre {
20040
20106
  margin: 0;
20041
20107
  }
20108
+ .copy-btn {
20109
+ position: absolute;
20110
+ top: 8px;
20111
+ right: 8px;
20112
+ display: flex;
20113
+ align-items: center;
20114
+ justify-content: center;
20115
+ padding: 0;
20116
+ border-style: solid;
20117
+ cursor: pointer;
20118
+ opacity: 0;
20119
+ transition: opacity 150ms ease, background 150ms ease;
20120
+ }
20121
+ .wrapper:hover .copy-btn,
20122
+ .copy-btn:focus-visible {
20123
+ opacity: 1;
20124
+ }
20125
+ .copy-btn descope-icon {
20126
+ width: 16px;
20127
+ height: 16px;
20128
+ pointer-events: none;
20129
+ flex-shrink: 0;
20130
+ }
20131
+ .copy-btn .check-icon {
20132
+ display: none;
20133
+ }
20134
+ .copy-btn.copied .check-icon {
20135
+ display: block;
20136
+ }
20137
+ .copy-btn.copied descope-icon:not(.check-icon) {
20138
+ display: none;
20139
+ }
20042
20140
  `,
20043
20141
  this
20044
20142
  );
@@ -20050,11 +20148,15 @@ let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: c
20050
20148
  this.lang = this.getAttribute('lang');
20051
20149
  this.isInline = this.getAttribute('inline') === 'true';
20052
20150
 
20151
+ if (this.getAttribute('copy-button') === 'true') {
20152
+ this.#initCopyButton();
20153
+ }
20154
+
20053
20155
  observeChildren$1(this, this.#renderSnippet.bind(this));
20054
20156
  }
20055
20157
 
20056
20158
  get contentNode() {
20057
- return this.shadowRoot.querySelector(this.baseSelector);
20159
+ return this.shadowRoot.querySelector('code');
20058
20160
  }
20059
20161
 
20060
20162
  attributeChangedCallback(attrName, oldValue, newValue) {
@@ -20069,10 +20171,58 @@ let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: c
20069
20171
  this.lang = newValue;
20070
20172
  }
20071
20173
 
20174
+ if (attrName === 'copy-button') {
20175
+ if (newValue === 'true') {
20176
+ this.#initCopyButton();
20177
+ } else {
20178
+ this.#destroyCopyButton();
20179
+ }
20180
+ }
20181
+
20072
20182
  this.#renderSnippet();
20073
20183
  }
20074
20184
  }
20075
20185
 
20186
+ // ── Copy button ────────────────────────────────────────────────────────────
20187
+
20188
+ #initCopyButton() {
20189
+ if (this.shadowRoot.querySelector('.copy-btn')) return;
20190
+
20191
+ const btn = document.createElement('button');
20192
+ btn.className = 'copy-btn';
20193
+ btn.type = 'button';
20194
+ btn.setAttribute('aria-label', 'Copy code');
20195
+ const copyIcon = document.createElement('descope-icon');
20196
+ copyIcon.setAttribute('src', copyIconSrc);
20197
+
20198
+ const checkIcon = document.createElement('descope-icon');
20199
+ checkIcon.setAttribute('src', checkIconSrc);
20200
+ checkIcon.classList.add('check-icon');
20201
+
20202
+ btn.appendChild(copyIcon);
20203
+ btn.appendChild(checkIcon);
20204
+ btn.addEventListener('click', () => this.#handleCopyClick());
20205
+
20206
+ this.shadowRoot.querySelector('.wrapper').appendChild(btn);
20207
+ }
20208
+
20209
+ #destroyCopyButton() {
20210
+ this.shadowRoot.querySelector('.copy-btn')?.remove();
20211
+ }
20212
+
20213
+ #handleCopyClick() {
20214
+ const btn = this.shadowRoot.querySelector('.copy-btn');
20215
+ navigator.clipboard
20216
+ .writeText(decode(this.textContent))
20217
+ .then(() => {
20218
+ btn.classList.add('copied');
20219
+ setTimeout(() => btn.classList.remove('copied'), 2000);
20220
+ })
20221
+ .catch(() => {});
20222
+ }
20223
+
20224
+ // ── Snippet rendering ──────────────────────────────────────────────────────
20225
+
20076
20226
  #renderSnippet() {
20077
20227
  const sanitized = decode(this.textContent);
20078
20228
  const language = this.lang;
@@ -20088,6 +20238,8 @@ let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: c
20088
20238
  }
20089
20239
  };
20090
20240
 
20241
+ const copyBtn = { selector: () => '.copy-btn' };
20242
+
20091
20243
  const {
20092
20244
  root,
20093
20245
  docTag,
@@ -20239,6 +20391,16 @@ const CodeSnippetClass = compose$1(
20239
20391
  propertyTextColor: { ...property, property: 'color' },
20240
20392
  punctuationTextColor: { ...punctuation, property: 'color' },
20241
20393
  tagTextColor: { ...tag, property: 'color' },
20394
+ copyButtonSize: [
20395
+ { ...copyBtn, property: 'width' },
20396
+ { ...copyBtn, property: 'height' },
20397
+ ],
20398
+ copyButtonBorderRadius: { ...copyBtn, property: 'border-radius' },
20399
+ copyButtonBorderWidth: { ...copyBtn, property: 'border-width' },
20400
+ copyButtonBorderColor: { ...copyBtn, property: 'border-color' },
20401
+ copyButtonBgColor: { ...copyBtn, property: 'background-color' },
20402
+ copyButtonHoverBgColor: { selector: () => '.copy-btn:hover', property: 'background-color' },
20403
+ copyButtonColor: { ...copyBtn, property: 'color' },
20242
20404
  },
20243
20405
  }),
20244
20406
  draggableMixin,
@@ -20276,6 +20438,13 @@ const dark = {
20276
20438
  };
20277
20439
 
20278
20440
  const CodeSnippet = {
20441
+ [vars$c.copyButtonSize]: '32px',
20442
+ [vars$c.copyButtonBorderRadius]: globalRefs$6.radius.xs,
20443
+ [vars$c.copyButtonBorderWidth]: globalRefs$6.border.xs,
20444
+ [vars$c.copyButtonBorderColor]: globalRefs$6.colors.surface.light,
20445
+ [vars$c.copyButtonBgColor]: globalRefs$6.colors.surface.highlight,
20446
+ [vars$c.copyButtonHoverBgColor]: globalRefs$6.colors.surface.light,
20447
+ [vars$c.copyButtonColor]: globalRefs$6.colors.surface.contrast,
20279
20448
  [vars$c.rootBgColor]: globalRefs$6.colors.surface.main,
20280
20449
  [vars$c.rootTextColor]: globalRefs$6.colors.surface.contrast,
20281
20450
  [vars$c.docTagTextColor]: light.color2,