@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.
package/dist/index.esm.js CHANGED
@@ -14305,6 +14305,10 @@ const componentName$J = getComponentName('grid-item-details-column');
14305
14305
 
14306
14306
  customElements.define(componentName$J, GridItemDetailsColumnClass);
14307
14307
 
14308
+ customElements.define(componentName$1e, ImageClass);
14309
+
14310
+ customElements.define(componentName$1d, IconClass);
14311
+
14308
14312
  const decode = (input) => {
14309
14313
  const txt = document.createElement('textarea');
14310
14314
  txt.innerHTML = input;
@@ -14313,18 +14317,24 @@ const decode = (input) => {
14313
14317
 
14314
14318
  const tpl = (input, inline) => (inline ? input : `<pre>${input}</pre>`);
14315
14319
 
14320
+ var copyIconSrc = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPgogIDxyZWN0IHg9IjkiIHk9IjkiIHdpZHRoPSIxMyIgaGVpZ2h0PSIxMyIgcng9IjIiIHJ5PSIyIj48L3JlY3Q+CiAgPHBhdGggZD0iTTUgMTVINGEyIDIgMCAwIDEtMi0yVjRhMiAyIDAgMCAxIDItMmg5YTIgMiAwIDAgMSAyIDJ2MSI+PC9wYXRoPgo8L3N2Zz4K";
14321
+
14322
+ var checkIconSrc = "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iY2hlY2staWNvbiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj4KICA8cG9seWxpbmUgcG9pbnRzPSIyMCA2IDkgMTcgNCAxMiI+PC9wb2x5bGluZT4KPC9zdmc+Cg==";
14323
+
14316
14324
  const componentName$I = getComponentName('code-snippet');
14317
14325
 
14318
- let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: componentName$I, baseSelector: ':host > code' }) {
14326
+ let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: componentName$I, baseSelector: ':host > .wrapper' }) {
14319
14327
  static get observedAttributes() {
14320
- return ['lang', 'inline'];
14328
+ return ['lang', 'inline', 'copy-button'];
14321
14329
  }
14322
14330
 
14323
14331
  constructor() {
14324
14332
  super();
14325
14333
 
14326
14334
  this.attachShadow({ mode: 'open' }).innerHTML = `
14327
- <code class="hljs"></code>
14335
+ <div class="wrapper">
14336
+ <code class="hljs"></code>
14337
+ </div>
14328
14338
  `;
14329
14339
 
14330
14340
  injectStyle(
@@ -14333,6 +14343,10 @@ let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: c
14333
14343
  display: inline-block;
14334
14344
  width: 100%;
14335
14345
  }
14346
+ .wrapper {
14347
+ position: relative;
14348
+ width: 100%;
14349
+ }
14336
14350
  code {
14337
14351
  display: block;
14338
14352
  width: 100%;
@@ -14343,6 +14357,38 @@ let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: c
14343
14357
  pre {
14344
14358
  margin: 0;
14345
14359
  }
14360
+ .copy-btn {
14361
+ position: absolute;
14362
+ top: 8px;
14363
+ right: 8px;
14364
+ display: flex;
14365
+ align-items: center;
14366
+ justify-content: center;
14367
+ padding: 0;
14368
+ border-style: solid;
14369
+ cursor: pointer;
14370
+ opacity: 0;
14371
+ transition: opacity 150ms ease, background 150ms ease;
14372
+ }
14373
+ .wrapper:hover .copy-btn,
14374
+ .copy-btn:focus-visible {
14375
+ opacity: 1;
14376
+ }
14377
+ .copy-btn descope-icon {
14378
+ width: 16px;
14379
+ height: 16px;
14380
+ pointer-events: none;
14381
+ flex-shrink: 0;
14382
+ }
14383
+ .copy-btn .check-icon {
14384
+ display: none;
14385
+ }
14386
+ .copy-btn.copied .check-icon {
14387
+ display: block;
14388
+ }
14389
+ .copy-btn.copied descope-icon:not(.check-icon) {
14390
+ display: none;
14391
+ }
14346
14392
  `,
14347
14393
  this
14348
14394
  );
@@ -14354,11 +14400,15 @@ let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: c
14354
14400
  this.lang = this.getAttribute('lang');
14355
14401
  this.isInline = this.getAttribute('inline') === 'true';
14356
14402
 
14403
+ if (this.getAttribute('copy-button') === 'true') {
14404
+ this.#initCopyButton();
14405
+ }
14406
+
14357
14407
  observeChildren(this, this.#renderSnippet.bind(this));
14358
14408
  }
14359
14409
 
14360
14410
  get contentNode() {
14361
- return this.shadowRoot.querySelector(this.baseSelector);
14411
+ return this.shadowRoot.querySelector('code');
14362
14412
  }
14363
14413
 
14364
14414
  attributeChangedCallback(attrName, oldValue, newValue) {
@@ -14373,10 +14423,58 @@ let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: c
14373
14423
  this.lang = newValue;
14374
14424
  }
14375
14425
 
14426
+ if (attrName === 'copy-button') {
14427
+ if (newValue === 'true') {
14428
+ this.#initCopyButton();
14429
+ } else {
14430
+ this.#destroyCopyButton();
14431
+ }
14432
+ }
14433
+
14376
14434
  this.#renderSnippet();
14377
14435
  }
14378
14436
  }
14379
14437
 
14438
+ // ── Copy button ────────────────────────────────────────────────────────────
14439
+
14440
+ #initCopyButton() {
14441
+ if (this.shadowRoot.querySelector('.copy-btn')) return;
14442
+
14443
+ const btn = document.createElement('button');
14444
+ btn.className = 'copy-btn';
14445
+ btn.type = 'button';
14446
+ btn.setAttribute('aria-label', 'Copy code');
14447
+ const copyIcon = document.createElement('descope-icon');
14448
+ copyIcon.setAttribute('src', copyIconSrc);
14449
+
14450
+ const checkIcon = document.createElement('descope-icon');
14451
+ checkIcon.setAttribute('src', checkIconSrc);
14452
+ checkIcon.classList.add('check-icon');
14453
+
14454
+ btn.appendChild(copyIcon);
14455
+ btn.appendChild(checkIcon);
14456
+ btn.addEventListener('click', () => this.#handleCopyClick());
14457
+
14458
+ this.shadowRoot.querySelector('.wrapper').appendChild(btn);
14459
+ }
14460
+
14461
+ #destroyCopyButton() {
14462
+ this.shadowRoot.querySelector('.copy-btn')?.remove();
14463
+ }
14464
+
14465
+ #handleCopyClick() {
14466
+ const btn = this.shadowRoot.querySelector('.copy-btn');
14467
+ navigator.clipboard
14468
+ .writeText(decode(this.textContent))
14469
+ .then(() => {
14470
+ btn.classList.add('copied');
14471
+ setTimeout(() => btn.classList.remove('copied'), 2000);
14472
+ })
14473
+ .catch(() => {});
14474
+ }
14475
+
14476
+ // ── Snippet rendering ──────────────────────────────────────────────────────
14477
+
14380
14478
  #renderSnippet() {
14381
14479
  const sanitized = decode(this.textContent);
14382
14480
  const language = this.lang;
@@ -14392,6 +14490,8 @@ let CodeSnippet$1 = class CodeSnippet extends createBaseClass({ componentName: c
14392
14490
  }
14393
14491
  };
14394
14492
 
14493
+ const copyBtn = { selector: () => '.copy-btn' };
14494
+
14395
14495
  const {
14396
14496
  root,
14397
14497
  docTag,
@@ -14543,6 +14643,16 @@ const CodeSnippetClass = compose(
14543
14643
  propertyTextColor: { ...property, property: 'color' },
14544
14644
  punctuationTextColor: { ...punctuation, property: 'color' },
14545
14645
  tagTextColor: { ...tag, property: 'color' },
14646
+ copyButtonSize: [
14647
+ { ...copyBtn, property: 'width' },
14648
+ { ...copyBtn, property: 'height' },
14649
+ ],
14650
+ copyButtonBorderRadius: { ...copyBtn, property: 'border-radius' },
14651
+ copyButtonBorderWidth: { ...copyBtn, property: 'border-width' },
14652
+ copyButtonBorderColor: { ...copyBtn, property: 'border-color' },
14653
+ copyButtonBgColor: { ...copyBtn, property: 'background-color' },
14654
+ copyButtonHoverBgColor: { selector: () => '.copy-btn:hover', property: 'background-color' },
14655
+ copyButtonColor: { ...copyBtn, property: 'color' },
14546
14656
  },
14547
14657
  }),
14548
14658
  draggableMixin,
@@ -14580,7 +14690,7 @@ const getValueType = (value) => {
14580
14690
  };
14581
14691
 
14582
14692
  const renderCodeSnippet = (value, lang) =>
14583
- `<descope-code-snippet lang="${lang}" class="row-details__value code">${escapeXML(value)}</descope-code-snippet>`;
14693
+ `<descope-code-snippet copy-button="true" lang="${lang}" class="row-details__value code">${escapeXML(value)}</descope-code-snippet>`;
14584
14694
 
14585
14695
  const renderText = (text) =>
14586
14696
  `<div class="row-details__value text" title="${text}">${escapeXML(text)}</div>`;
@@ -14608,16 +14718,31 @@ const defaultRowDetailsValueRenderer = (value) => {
14608
14718
  return renderText(value);
14609
14719
  };
14610
14720
 
14721
+ const isCodeSnippetValue = (value) => {
14722
+ const type = getValueType(value);
14723
+ return (
14724
+ type === 'object' ||
14725
+ type === 'xml' ||
14726
+ (type === 'array' && value.some((v) => getValueType(v) === 'object'))
14727
+ );
14728
+ };
14729
+
14611
14730
  const defaultRowDetailsRenderer = (item, itemLabelsMapping) => `
14612
14731
  <div class="row-details">
14613
14732
  ${Object.entries(item)
14614
- .map(
14615
- ([key, value]) =>
14616
- `<div class="row-details__item" >
14617
- <div class="row-details__label">${itemLabelsMapping[key] || toTitle(key)}</div>
14733
+ .map(([key, value]) => {
14734
+ const label = itemLabelsMapping[key] || toTitle(key);
14735
+ if (isCodeSnippetValue(value)) {
14736
+ return `<details class="row-details__item">
14737
+ <summary class="row-details__label">${label}</summary>
14618
14738
  ${defaultRowDetailsValueRenderer(value)}
14619
- </div>`
14620
- )
14739
+ </details>`;
14740
+ }
14741
+ return `<div class="row-details__item">
14742
+ <div class="row-details__label">${label}</div>
14743
+ ${defaultRowDetailsValueRenderer(value)}
14744
+ </div>`;
14745
+ })
14621
14746
  .join('\n')}
14622
14747
  </div>
14623
14748
  `;
@@ -14645,6 +14770,18 @@ const GridMixin = (superclass) =>
14645
14770
  };
14646
14771
 
14647
14772
  this.baseElement.rowDetailsRenderer = this.#rowDetailsRenderer.bind(this);
14773
+
14774
+ // Stop wheel events from propagating to vaadin-grid when scrolling
14775
+ // inside code snippets, so touchpad horizontal scroll works
14776
+ this.baseElement.addEventListener(
14777
+ 'wheel',
14778
+ (e) => {
14779
+ if (e.target.closest('descope-code-snippet')) {
14780
+ e.stopPropagation();
14781
+ }
14782
+ },
14783
+ true
14784
+ );
14648
14785
  }
14649
14786
 
14650
14787
  // this renders the details panel content
@@ -14955,6 +15092,14 @@ const GridClass = compose(
14955
15092
  grid-column: 1 / -1;
14956
15093
  order: 2;
14957
15094
  }
15095
+ vaadin-grid details.row-details__item {
15096
+ padding: 0;
15097
+ }
15098
+ vaadin-grid details.row-details__item > summary.row-details__label {
15099
+ cursor: pointer;
15100
+ list-style: revert;
15101
+ display: revert;
15102
+ }
14958
15103
  vaadin-grid .row-details__value.text {
14959
15104
  overflow: hidden;
14960
15105
  text-overflow: ellipsis;
@@ -14962,8 +15107,7 @@ const GridClass = compose(
14962
15107
  }
14963
15108
  vaadin-grid .row-details__value.code {
14964
15109
  margin-top: 5px;
14965
- max-height: 120px;
14966
- overflow: scroll;
15110
+ overflow-x: auto;
14967
15111
  font-size: 0.85em;
14968
15112
  }
14969
15113
  vaadin-grid vaadin-icon.toggle-details-button {
@@ -16956,10 +17100,6 @@ const UserAttributeClass = compose(
16956
17100
 
16957
17101
  customElements.define(componentName$z, BadgeClass);
16958
17102
 
16959
- customElements.define(componentName$1e, ImageClass);
16960
-
16961
- customElements.define(componentName$1d, IconClass);
16962
-
16963
17103
  customElements.define(componentName$y, UserAttributeClass);
16964
17104
 
16965
17105
  var greenVIcon = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTggMEMzLjYgMCAwIDMuNiAwIDhDMCAxMi40IDMuNiAxNiA4IDE2QzEyLjQgMTYgMTYgMTIuNCAxNiA4QzE2IDMuNiAxMi40IDAgOCAwWk03LjEgMTEuN0wyLjkgNy42TDQuMyA2LjJMNyA4LjlMMTIgNEwxMy40IDUuNEw3LjEgMTEuN1oiIGZpbGw9IiM0Q0FGNTAiLz4KPC9zdmc+Cg==";
@@ -24167,10 +24307,14 @@ const subdivisionItem = ({ name, state_code, translations, lang }) => {
24167
24307
  return `<div data-id="${escapedStateCode}" data-name="${escapedSearchTerms}" data-label="${escapedLabel}">${escapedLabel}</div>`;
24168
24308
  };
24169
24309
 
24170
- const cityItem = ({ name }) => {
24310
+ const cityItem = ({ name, translations, lang }) => {
24311
+ const displayName = resolveTranslation({ name, translations }, lang);
24312
+ const searchTerms = [displayName];
24313
+ if (displayName !== name) searchTerms.push(name);
24171
24314
  const escapedId = escapeHtml(name);
24172
- const escapedName = escapeHtml(name);
24173
- return `<div data-id="${escapedId}" data-name="${escapedName}">${escapedName}</div>`;
24315
+ const escapedSearchTerms = escapeHtml(searchTerms.join(' '));
24316
+ const escapedLabel = escapeHtml(displayName);
24317
+ return `<div data-id="${escapedId}" data-name="${escapedSearchTerms}" data-label="${escapedLabel}">${escapedLabel}</div>`;
24174
24318
  };
24175
24319
 
24176
24320
  const comboBoxHTML = (id) =>
@@ -24230,6 +24374,7 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass {
24230
24374
  #countriesMap = new Map();
24231
24375
  #cachedCountries = null;
24232
24376
  #cachedSubdivisions = null;
24377
+ #cachedCities = null;
24233
24378
  #labels = null;
24234
24379
 
24235
24380
  // Value requested programmatically before data has loaded.
@@ -24276,8 +24421,8 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass {
24276
24421
  const lang = this.getAttribute('lang') || undefined;
24277
24422
  if (!lang) return undefined;
24278
24423
  try {
24279
- Intl.getCanonicalLocales(lang);
24280
- return lang;
24424
+ const [canonical] = Intl.getCanonicalLocales(lang);
24425
+ return canonical;
24281
24426
  } catch {
24282
24427
  return undefined; // invalid BCP47 tag — fall back to English
24283
24428
  }
@@ -24460,8 +24605,11 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass {
24460
24605
 
24461
24606
  #setupValueTransform() {
24462
24607
  // Display only the item name in the input, while data-name includes ISO codes for search
24463
- [this.#countryComboBox, this.#subdivisionComboBox].forEach((combo) => {
24464
-
24608
+ [
24609
+ this.#countryComboBox,
24610
+ this.#subdivisionComboBox,
24611
+ this.#cityComboBox,
24612
+ ].forEach((combo) => {
24465
24613
  combo.customValueTransformFn = (val) => {
24466
24614
  const item = combo.baseElement?.items?.find(
24467
24615
  (i) => i['data-name'] === val,
@@ -24606,7 +24754,11 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass {
24606
24754
  if (cities) {
24607
24755
  this.#cityVisible = cities.length > 0;
24608
24756
  if (cities.length > 0) {
24609
- this.#cityComboBox.data = cities;
24757
+ this.#cachedCities = cities;
24758
+ this.#cityComboBox.data = cities.map((c) => ({
24759
+ ...c,
24760
+ lang: this.#lang,
24761
+ }));
24610
24762
  if (pendingCity) toSelect.push([this.#cityComboBox, pendingCity]);
24611
24763
  }
24612
24764
  }
@@ -24717,7 +24869,6 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass {
24717
24869
  if (!this.#pendingValue && this.#defaultCountry)
24718
24870
  this.#onCountrySelected(this.#defaultCountry);
24719
24871
  } catch (e) {
24720
-
24721
24872
  console.error(`[${componentName$3}] Failed to load countries`, e);
24722
24873
  } finally {
24723
24874
  this.#countryComboBox.removeAttribute('loading');
@@ -24742,7 +24893,6 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass {
24742
24893
  this.#loadCities(countryIso2);
24743
24894
  }
24744
24895
  } catch (e) {
24745
-
24746
24896
  console.error(
24747
24897
  `[${componentName$3}] Failed to load subdivisions for ${countryIso2}`,
24748
24898
  e,
@@ -24764,10 +24914,13 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass {
24764
24914
  this.#cityVisible = cities.length > 0;
24765
24915
  this.#refreshState();
24766
24916
  if (cities.length > 0) {
24767
- this.#cityComboBox.data = cities;
24917
+ this.#cachedCities = cities;
24918
+ this.#cityComboBox.data = cities.map((c) => ({
24919
+ ...c,
24920
+ lang: this.#lang,
24921
+ }));
24768
24922
  }
24769
24923
  } catch (e) {
24770
-
24771
24924
  console.error(
24772
24925
  `[${componentName$3}] Failed to load cities for ${countryIso2}${stateCode ? `/${stateCode}` : ''}`,
24773
24926
  e,
@@ -24792,6 +24945,14 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass {
24792
24945
  if (prevSubdivision)
24793
24946
  this.#selectItemById(this.#subdivisionComboBox, prevSubdivision);
24794
24947
  }
24948
+ if (this.#cachedCities && this.#cityVisible) {
24949
+ const prevCity = this.#cityComboBox.value;
24950
+ this.#cityComboBox.data = this.#cachedCities.map((c) => ({
24951
+ ...c,
24952
+ lang: this.#lang,
24953
+ }));
24954
+ if (prevCity) this.#selectItemById(this.#cityComboBox, prevCity);
24955
+ }
24795
24956
  // Re-apply translated subdivision type label for the new lang
24796
24957
  const currentIso2 = this.#countryComboBox.value;
24797
24958
  if (currentIso2) {
@@ -24905,6 +25066,7 @@ class RawCountrySubdivisionCityFieldInternal extends BaseInputClass {
24905
25066
  #resetCity() {
24906
25067
  this.#cityComboBox.value = '';
24907
25068
  this.#cityComboBox.data = [];
25069
+ this.#cachedCities = null;
24908
25070
  this.#cityVisible = false;
24909
25071
  this.#refreshState();
24910
25072
  }
@@ -26654,6 +26816,13 @@ const dark = {
26654
26816
  };
26655
26817
 
26656
26818
  const CodeSnippet = {
26819
+ [vars$c.copyButtonSize]: '32px',
26820
+ [vars$c.copyButtonBorderRadius]: globalRefs$6.radius.xs,
26821
+ [vars$c.copyButtonBorderWidth]: globalRefs$6.border.xs,
26822
+ [vars$c.copyButtonBorderColor]: globalRefs$6.colors.surface.light,
26823
+ [vars$c.copyButtonBgColor]: globalRefs$6.colors.surface.highlight,
26824
+ [vars$c.copyButtonHoverBgColor]: globalRefs$6.colors.surface.light,
26825
+ [vars$c.copyButtonColor]: globalRefs$6.colors.surface.contrast,
26657
26826
  [vars$c.rootBgColor]: globalRefs$6.colors.surface.main,
26658
26827
  [vars$c.rootTextColor]: globalRefs$6.colors.surface.contrast,
26659
26828
  [vars$c.docTagTextColor]: light.color2,