@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.
@@ -4031,11 +4031,21 @@ var FormSelect = class _FormSelect extends Component {
4031
4031
  }
4032
4032
  li.appendChild(span);
4033
4033
  const iconUrl = realOption.getAttribute("data-icon");
4034
- const classes = realOption.getAttribute("class")?.split(" ").filter(Boolean);
4034
+ let imageUrl;
4035
4035
  if (iconUrl) {
4036
+ try {
4037
+ const url = new URL(iconUrl, this.el.ownerDocument.baseURI);
4038
+ if (["http:", "https:", "blob:"].includes(url.protocol) || /^data:image\/(?:avif|bmp|gif|jpeg|png|svg\+xml|webp|x-icon)(?:;|,)/i.test(url.href)) {
4039
+ imageUrl = url;
4040
+ }
4041
+ } catch {
4042
+ }
4043
+ }
4044
+ const classes = realOption.getAttribute("class")?.split(" ").filter(Boolean);
4045
+ if (imageUrl) {
4036
4046
  const img = document.createElement("img");
4037
4047
  if (classes?.length) img.classList.add(...classes);
4038
- img.src = iconUrl;
4048
+ img.src = imageUrl.href;
4039
4049
  img.ariaHidden = "true";
4040
4050
  li.prepend(img);
4041
4051
  }
@@ -4866,13 +4876,18 @@ var _Datepicker = class _Datepicker extends Component {
4866
4876
  arr.push(className);
4867
4877
  }
4868
4878
  }
4869
- 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>`;
4879
+ const day = _Datepicker._escape(opts.day);
4880
+ const month = _Datepicker._escape(opts.month);
4881
+ const year = _Datepicker._escape(opts.year);
4882
+ 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>`;
4870
4883
  }
4884
+ /** Assemble calendar cells; reject unsupported elements and attributes. */
4871
4885
  renderRow(days, isRTL, isRowSelected) {
4872
- return '<tr class="datepicker-row' + (isRowSelected ? " is-selected" : "") + '">' + (isRTL ? days.reverse() : days).join("") + "</tr>";
4886
+ return '<tr class="datepicker-row' + (isRowSelected ? " is-selected" : "") + '">' + _Datepicker._calendarMarkup((isRTL ? days.reverse() : days).join(""), "tr") + "</tr>";
4873
4887
  }
4888
+ /** Assemble calendar rows; reject unsupported elements and attributes. */
4874
4889
  renderTable(opts, data, randId) {
4875
- 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>";
4890
+ 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>";
4876
4891
  }
4877
4892
  renderHead(opts) {
4878
4893
  const arr = [];
@@ -4884,8 +4899,40 @@ var _Datepicker = class _Datepicker extends Component {
4884
4899
  }
4885
4900
  return "<thead><tr>" + (opts.isRTL ? arr.reverse() : arr).join("") + "</tr></thead>";
4886
4901
  }
4902
+ /** Wrap calendar rows after validating and encoding their contents. */
4887
4903
  renderBody(rows) {
4888
- return "<tbody>" + rows.join("") + "</tbody>";
4904
+ return "<tbody>" + _Datepicker._calendarMarkup(rows.join(""), "tbody") + "</tbody>";
4905
+ }
4906
+ static _calendarMarkup(html, parent) {
4907
+ const template = document.createElement("template");
4908
+ template.innerHTML = html;
4909
+ const attributes = {
4910
+ tr: ["class"],
4911
+ td: ["class", "data-day", "aria-selected"],
4912
+ button: ["class", "type", "data-year", "data-month", "data-day", "aria-label", "disabled", "tabindex"]
4913
+ };
4914
+ const render = (node, container) => {
4915
+ if (node.nodeType === Node.TEXT_NODE) {
4916
+ if (container === "tbody" || container === "tr") {
4917
+ if (node.textContent.trim()) throw new TypeError("Unsupported calendar row content");
4918
+ }
4919
+ return _Datepicker._escape(node.textContent);
4920
+ }
4921
+ if (!(node instanceof HTMLElement)) throw new TypeError("Unsupported calendar row content");
4922
+ const tag = node.localName === "tr" ? "tr" : node.localName === "td" ? "td" : node.localName === "button" ? "button" : null;
4923
+ if (!tag || !(container === "tbody" && tag === "tr" || container === "tr" && tag === "td" || container === "td" && tag === "button")) {
4924
+ throw new TypeError("Unsupported calendar row element");
4925
+ }
4926
+ if ([...node.attributes].some((attr) => !attributes[tag].includes(attr.name))) {
4927
+ throw new TypeError("Unsupported calendar row attribute");
4928
+ }
4929
+ if (tag === "button" && node.getAttribute("type") !== "button") {
4930
+ throw new TypeError('Calendar day buttons require type="button"');
4931
+ }
4932
+ const attrs = attributes[tag].filter((name) => node.hasAttribute(name)).map((name) => ` ${name}="${_Datepicker._escape(node.getAttribute(name))}"`).join("");
4933
+ return `<${tag}${attrs}>${[...node.childNodes].map((child) => render(child, tag)).join("")}</${tag}>`;
4934
+ };
4935
+ return [...template.content.childNodes].map((node) => render(node, parent)).join("");
4889
4936
  }
4890
4937
  /**
4891
4938
  * Whether each month arrow is usable at this position in the allowed range.
@@ -4925,7 +4972,7 @@ var _Datepicker = class _Datepicker extends Component {
4925
4972
  }
4926
4973
  renderTitle(instance, c, year, month, refYear, randId) {
4927
4974
  const opts = this.options, isMinYear = year === opts.minYear, isMaxYear = year === opts.maxYear;
4928
- let i, j, arr = [], html = '<div id="' + randId + '" class="datepicker-controls" role="heading" aria-live="assertive">';
4975
+ let i, j, arr = [], html = '<div id="' + _Datepicker._escape(randId) + '" class="datepicker-controls" role="heading" aria-live="assertive">';
4929
4976
  const { prev, next } = this._arrowState(year, month);
4930
4977
  for (i = 0; i < 12; i++) {
4931
4978
  arr.push(
@@ -7440,7 +7487,7 @@ function AutoInit(context = document.body, options) {
7440
7487
  }
7441
7488
 
7442
7489
  // src/ts/index.ts
7443
- var version = "0.9.0";
7490
+ var version = "0.9.1";
7444
7491
  Forms.Init();
7445
7492
  Chips.Init();
7446
7493
  Slider.Init();