@peektravel/app-utilities 0.2.5 → 0.2.7

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.
@@ -939,9 +939,15 @@ declare class OdyTabs extends OdyElement {
939
939
  }
940
940
 
941
941
  /**
942
- * `<ody-copy-button>` — a button that copies its `value` to the clipboard via
943
- * `navigator.clipboard.writeText`, showing a transient success (or error) state.
944
- * Dispatches a `copy` CustomEvent with `{ value, ok }`.
942
+ * `<ody-copy-button>` — a button that copies its `value` to the clipboard,
943
+ * showing a transient success (or error) state. Dispatches a `copy`
944
+ * CustomEvent with `{ value, ok }`.
945
+ *
946
+ * The copy uses a synchronous `document.execCommand('copy')` as the source of
947
+ * truth so it works inside cross-origin iframes (where the async Clipboard API
948
+ * is blocked by default) and legacy contexts. The async
949
+ * `navigator.clipboard.writeText` is used only as a best-effort enhancement
950
+ * when the synchronous path can't run.
945
951
  *
946
952
  * Attributes:
947
953
  * - `value` — the text copied to the clipboard.
@@ -939,9 +939,15 @@ declare class OdyTabs extends OdyElement {
939
939
  }
940
940
 
941
941
  /**
942
- * `<ody-copy-button>` — a button that copies its `value` to the clipboard via
943
- * `navigator.clipboard.writeText`, showing a transient success (or error) state.
944
- * Dispatches a `copy` CustomEvent with `{ value, ok }`.
942
+ * `<ody-copy-button>` — a button that copies its `value` to the clipboard,
943
+ * showing a transient success (or error) state. Dispatches a `copy`
944
+ * CustomEvent with `{ value, ok }`.
945
+ *
946
+ * The copy uses a synchronous `document.execCommand('copy')` as the source of
947
+ * truth so it works inside cross-origin iframes (where the async Clipboard API
948
+ * is blocked by default) and legacy contexts. The async
949
+ * `navigator.clipboard.writeText` is used only as a best-effort enhancement
950
+ * when the synchronous path can't run.
945
951
  *
946
952
  * Attributes:
947
953
  * - `value` — the text copied to the clipboard.
package/dist/ui/index.js CHANGED
@@ -2149,16 +2149,47 @@ var OdyCopyButton = class extends OdyElement {
2149
2149
  }
2150
2150
  #onClick = () => {
2151
2151
  const value = this.attr("value");
2152
- const clipboard = typeof navigator !== "undefined" ? navigator.clipboard : void 0;
2153
- if (!clipboard || typeof clipboard.writeText !== "function") {
2154
- this.#feedback("error", value);
2155
- return;
2152
+ const ok = this.#execCopy(value);
2153
+ if (!ok) {
2154
+ const clipboard = typeof navigator !== "undefined" ? navigator.clipboard : void 0;
2155
+ if (clipboard && typeof clipboard.writeText === "function") {
2156
+ void clipboard.writeText(value).then(
2157
+ () => void 0,
2158
+ () => void 0
2159
+ );
2160
+ }
2156
2161
  }
2157
- void clipboard.writeText(value).then(
2158
- () => this.#feedback("success", value),
2159
- () => this.#feedback("error", value)
2160
- );
2162
+ this.#feedback(ok ? "success" : "error", value);
2161
2163
  };
2164
+ /**
2165
+ * Synchronous clipboard write. Must be called within the user-gesture window
2166
+ * (i.e. directly from the click handler, not from an async continuation).
2167
+ * Works in cross-origin iframes and legacy contexts where the async Clipboard
2168
+ * API is unavailable or blocked.
2169
+ */
2170
+ #execCopy(value) {
2171
+ if (!value || typeof document === "undefined") return false;
2172
+ const el = document.createElement("textarea");
2173
+ el.value = value;
2174
+ el.setAttribute("readonly", "");
2175
+ el.style.position = "fixed";
2176
+ el.style.top = "0";
2177
+ el.style.left = "0";
2178
+ el.style.opacity = "0";
2179
+ document.body.appendChild(el);
2180
+ el.select();
2181
+ try {
2182
+ el.setSelectionRange(0, value.length);
2183
+ } catch {
2184
+ }
2185
+ let ok = false;
2186
+ try {
2187
+ ok = document.execCommand("copy");
2188
+ } catch {
2189
+ }
2190
+ document.body.removeChild(el);
2191
+ return ok;
2192
+ }
2162
2193
  #feedback(state, value) {
2163
2194
  this.#state = state;
2164
2195
  this.render();