@expressivecss/expressive 0.9.0 → 0.9.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.
@@ -4084,11 +4084,21 @@ var Expressive = (() => {
4084
4084
  }
4085
4085
  li.appendChild(span);
4086
4086
  const iconUrl = realOption.getAttribute("data-icon");
4087
- const classes = realOption.getAttribute("class")?.split(" ").filter(Boolean);
4087
+ let imageUrl;
4088
4088
  if (iconUrl) {
4089
+ try {
4090
+ const url = new URL(iconUrl, this.el.ownerDocument.baseURI);
4091
+ if (["http:", "https:", "blob:"].includes(url.protocol) || /^data:image\/(?:avif|bmp|gif|jpeg|png|svg\+xml|webp|x-icon)(?:;|,)/i.test(url.href)) {
4092
+ imageUrl = url;
4093
+ }
4094
+ } catch {
4095
+ }
4096
+ }
4097
+ const classes = realOption.getAttribute("class")?.split(" ").filter(Boolean);
4098
+ if (imageUrl) {
4089
4099
  const img = document.createElement("img");
4090
4100
  if (classes?.length) img.classList.add(...classes);
4091
- img.src = iconUrl;
4101
+ img.src = imageUrl.href;
4092
4102
  img.ariaHidden = "true";
4093
4103
  li.prepend(img);
4094
4104
  }
@@ -4919,13 +4929,18 @@ var Expressive = (() => {
4919
4929
  arr.push(className);
4920
4930
  }
4921
4931
  }
4922
- return `<td data-day="${opts.day}" class="${arr.join(" ")}" aria-selected="${ariaSelected}"><button class="datepicker-day-button" type="button" data-year="${opts.year}" data-month="${opts.month}" data-day="${opts.day}">${opts.day}</button></td>`;
4932
+ const day = _Datepicker._escape(opts.day);
4933
+ const month = _Datepicker._escape(opts.month);
4934
+ const year = _Datepicker._escape(opts.year);
4935
+ return `<td data-day="${day}" class="${arr.join(" ")}" aria-selected="${ariaSelected}"><button class="datepicker-day-button" type="button" data-year="${year}" data-month="${month}" data-day="${day}">${day}</button></td>`;
4923
4936
  }
4937
+ /** Assemble calendar cells; reject unsupported elements and attributes. */
4924
4938
  renderRow(days, isRTL, isRowSelected) {
4925
- return '<tr class="datepicker-row' + (isRowSelected ? " is-selected" : "") + '">' + (isRTL ? days.reverse() : days).join("") + "</tr>";
4939
+ return '<tr class="datepicker-row' + (isRowSelected ? " is-selected" : "") + '">' + _Datepicker._calendarMarkup((isRTL ? days.reverse() : days).join(""), "tr") + "</tr>";
4926
4940
  }
4941
+ /** Assemble calendar rows; reject unsupported elements and attributes. */
4927
4942
  renderTable(opts, data, randId) {
4928
- return '<div class="datepicker-table-wrapper"><table cellpadding="0" cellspacing="0" class="datepicker-table" role="grid" aria-labelledby="' + randId + '">' + this.renderHead(opts) + this.renderBody(data) + "</table></div>";
4943
+ return '<div class="datepicker-table-wrapper"><table cellpadding="0" cellspacing="0" class="datepicker-table" role="grid" aria-labelledby="' + _Datepicker._escape(randId) + '">' + this.renderHead(opts) + this.renderBody(data) + "</table></div>";
4929
4944
  }
4930
4945
  renderHead(opts) {
4931
4946
  const arr = [];
@@ -4937,8 +4952,40 @@ var Expressive = (() => {
4937
4952
  }
4938
4953
  return "<thead><tr>" + (opts.isRTL ? arr.reverse() : arr).join("") + "</tr></thead>";
4939
4954
  }
4955
+ /** Wrap calendar rows after validating and encoding their contents. */
4940
4956
  renderBody(rows) {
4941
- return "<tbody>" + rows.join("") + "</tbody>";
4957
+ return "<tbody>" + _Datepicker._calendarMarkup(rows.join(""), "tbody") + "</tbody>";
4958
+ }
4959
+ static _calendarMarkup(html, parent) {
4960
+ const template = document.createElement("template");
4961
+ template.innerHTML = html;
4962
+ const attributes = {
4963
+ tr: ["class"],
4964
+ td: ["class", "data-day", "aria-selected"],
4965
+ button: ["class", "type", "data-year", "data-month", "data-day", "aria-label", "disabled", "tabindex"]
4966
+ };
4967
+ const render = (node, container) => {
4968
+ if (node.nodeType === Node.TEXT_NODE) {
4969
+ if (container === "tbody" || container === "tr") {
4970
+ if (node.textContent.trim()) throw new TypeError("Unsupported calendar row content");
4971
+ }
4972
+ return _Datepicker._escape(node.textContent);
4973
+ }
4974
+ if (!(node instanceof HTMLElement)) throw new TypeError("Unsupported calendar row content");
4975
+ const tag = node.localName === "tr" ? "tr" : node.localName === "td" ? "td" : node.localName === "button" ? "button" : null;
4976
+ if (!tag || !(container === "tbody" && tag === "tr" || container === "tr" && tag === "td" || container === "td" && tag === "button")) {
4977
+ throw new TypeError("Unsupported calendar row element");
4978
+ }
4979
+ if ([...node.attributes].some((attr) => !attributes[tag].includes(attr.name))) {
4980
+ throw new TypeError("Unsupported calendar row attribute");
4981
+ }
4982
+ if (tag === "button" && node.getAttribute("type") !== "button") {
4983
+ throw new TypeError('Calendar day buttons require type="button"');
4984
+ }
4985
+ const attrs = attributes[tag].filter((name) => node.hasAttribute(name)).map((name) => ` ${name}="${_Datepicker._escape(node.getAttribute(name))}"`).join("");
4986
+ return `<${tag}${attrs}>${[...node.childNodes].map((child) => render(child, tag)).join("")}</${tag}>`;
4987
+ };
4988
+ return [...template.content.childNodes].map((node) => render(node, parent)).join("");
4942
4989
  }
4943
4990
  /**
4944
4991
  * Whether each month arrow is usable at this position in the allowed range.
@@ -4978,7 +5025,7 @@ var Expressive = (() => {
4978
5025
  }
4979
5026
  renderTitle(instance, c, year, month, refYear, randId) {
4980
5027
  const opts = this.options, isMinYear = year === opts.minYear, isMaxYear = year === opts.maxYear;
4981
- let i, j, arr = [], html = '<div id="' + randId + '" class="datepicker-controls" role="heading" aria-live="assertive">';
5028
+ let i, j, arr = [], html = '<div id="' + _Datepicker._escape(randId) + '" class="datepicker-controls" role="heading" aria-live="assertive">';
4982
5029
  const { prev, next } = this._arrowState(year, month);
4983
5030
  for (i = 0; i < 12; i++) {
4984
5031
  arr.push(
@@ -7493,7 +7540,7 @@ var Expressive = (() => {
7493
7540
  }
7494
7541
 
7495
7542
  // src/ts/index.ts
7496
- var version = "0.9.0";
7543
+ var version = "0.9.1";
7497
7544
  Forms.Init();
7498
7545
  Chips.Init();
7499
7546
  Slider.Init();