@ruakit/runtime 0.0.0-stage → 0.1.0-alpha.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.
- package/LICENSE +21 -0
- package/NOTICE +4 -0
- package/dist/action-feedback.d.ts +4 -0
- package/dist/action-feedback.d.ts.map +1 -0
- package/dist/action-feedback.js +3 -0
- package/dist/action-feedback.js.map +7 -0
- package/dist/dom.d.ts +17 -0
- package/dist/dom.d.ts.map +1 -0
- package/dist/dom.js +3 -0
- package/dist/dom.js.map +7 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +3 -0
- package/dist/errors.js.map +7 -0
- package/dist/experimental/index.d.ts +24 -0
- package/dist/experimental/index.d.ts.map +1 -0
- package/dist/experimental/index.js +3 -0
- package/dist/experimental/index.js.map +7 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +7 -0
- package/dist/operations.d.ts +5 -0
- package/dist/operations.d.ts.map +1 -0
- package/dist/operations.js +3 -0
- package/dist/operations.js.map +7 -0
- package/dist/runtime.d.ts +4 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +3 -0
- package/dist/runtime.js.map +7 -0
- package/dist/screenshot.d.ts +3 -0
- package/dist/screenshot.d.ts.map +1 -0
- package/dist/screenshot.js +5 -0
- package/dist/screenshot.js.map +7 -0
- package/dist/targets.d.ts +15 -0
- package/dist/targets.d.ts.map +1 -0
- package/dist/targets.js +3 -0
- package/dist/targets.js.map +7 -0
- package/dist/types.d.ts +121 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +7 -0
- package/package.json +37 -3
- package/src/action-feedback.ts +85 -0
- package/src/dom.ts +307 -0
- package/src/errors.ts +14 -0
- package/src/experimental/index.ts +192 -0
- package/src/index.ts +21 -0
- package/src/operations.ts +67 -0
- package/src/runtime.ts +541 -0
- package/src/screenshot.ts +172 -0
- package/src/targets.ts +141 -0
- package/src/types.ts +135 -0
- package/README.md +0 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 RuaKit contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ActionFeedbackOptions, RuntimeAction } from './types.js';
|
|
2
|
+
/** Present one validated local action. The resolver must reject stale or unavailable targets. */
|
|
3
|
+
export declare function withActionFeedback<T>(options: ActionFeedbackOptions, action: RuntimeAction, resolve: () => HTMLElement, signal: AbortSignal, effect: (element: HTMLElement) => T | Promise<T>): Promise<T>;
|
|
4
|
+
//# sourceMappingURL=action-feedback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-feedback.d.ts","sourceRoot":"","sources":["../src/action-feedback.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,qBAAqB,EAErB,aAAa,EAEd,MAAM,YAAY,CAAC;AAIpB,iGAAiG;AACjG,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,OAAO,EAAE,qBAAqB,EAC9B,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,WAAW,EAC1B,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAC/C,OAAO,CAAC,CAAC,CAAC,CAkEZ"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT
|
|
2
|
+
var u=Object.defineProperty;var d=(r,h)=>u(r,"name",{value:h,configurable:!0});import{pause as y}from"./operations.js";let A=0;async function p(r,h,n,o,w){o.throwIfAborted();const i=r.actionDelayMs??0,l=d(e=>{if(!Number.isInteger(e)||e<0||e>1e4)throw new RangeError("actionDelayMs must resolve to an integer from 0 to 10000 milliseconds.");return e},"validateDelay");let c=typeof i=="function"?0:l(i),t=n();if(!r.onAction)return w(t);const s=++A;let b={left:0,top:0,width:0,height:0};const a=d(e=>{if(t.isConnected){const f=t.getBoundingClientRect();b={left:f.left,top:f.top,width:f.width,height:f.height}}try{r.onAction?.({id:s,action:h,phase:e,element:t,rect:{...b},durationMs:c})}catch{}},"notify");try{r.scrollToTarget&&t.scrollIntoView?.({block:"nearest",inline:"nearest",behavior:"instant"}),o.throwIfAborted(),t=n(),typeof i=="function"&&(c=l(i(t)),o.throwIfAborted(),t=n()),a("before"),o.throwIfAborted(),c&&await y(o,c),t=n(),o.throwIfAborted();const e=await w(t);return o.throwIfAborted(),a("after"),e}catch(e){throw a(o.aborted?"cancelled":"failed"),e}}d(p,"withActionFeedback");export{p as withActionFeedback};
|
|
3
|
+
//# sourceMappingURL=action-feedback.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/action-feedback.ts"],
|
|
4
|
+
"sourcesContent": ["// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT\nimport { pause } from './operations.js';\nimport type {\n ActionFeedbackOptions,\n ActionRect,\n RuntimeAction,\n RuntimeActionEvent,\n} from './types.js';\n\nlet nextAction = 0;\n\n/** Present one validated local action. The resolver must reject stale or unavailable targets. */\nexport async function withActionFeedback<T>(\n options: ActionFeedbackOptions,\n action: RuntimeAction,\n resolve: () => HTMLElement,\n signal: AbortSignal,\n effect: (element: HTMLElement) => T | Promise<T>,\n): Promise<T> {\n signal.throwIfAborted();\n\n const delay = options.actionDelayMs ?? 0;\n const validateDelay = (value: number): number => {\n if (!Number.isInteger(value) || value < 0 || value > 10000)\n throw new RangeError('actionDelayMs must resolve to an integer from 0 to 10000 milliseconds.');\n return value;\n };\n\n let durationMs = typeof delay === 'function' ? 0 : validateDelay(delay);\n let element = resolve();\n\n if (!options.onAction) {\n return effect(element);\n }\n\n const id = ++nextAction;\n let rect: ActionRect = { left: 0, top: 0, width: 0, height: 0 };\n\n const notify = (phase: RuntimeActionEvent['phase']): void => {\n if (element.isConnected) {\n const bounds = element.getBoundingClientRect();\n rect = { left: bounds.left, top: bounds.top, width: bounds.width, height: bounds.height };\n }\n\n try {\n options.onAction?.({ id, action, phase, element, rect: { ...rect }, durationMs });\n } catch {\n // UI feedback cannot authorize an action or invalidate its result.\n }\n };\n\n try {\n if (options.scrollToTarget) {\n element.scrollIntoView?.({ block: 'nearest', inline: 'nearest', behavior: 'instant' });\n }\n\n signal.throwIfAborted();\n element = resolve();\n\n if (typeof delay === 'function') {\n durationMs = validateDelay(delay(element));\n signal.throwIfAborted();\n element = resolve();\n }\n\n notify('before');\n signal.throwIfAborted();\n if (durationMs) {\n await pause(signal, durationMs);\n }\n\n // Scrolling, UI callbacks and animation time can all change the application.\n element = resolve();\n signal.throwIfAborted();\n\n const result = await effect(element);\n signal.throwIfAborted();\n notify('after');\n\n return result;\n } catch (error) {\n notify(signal.aborted ? 'cancelled' : 'failed');\n throw error;\n }\n}\n"],
|
|
5
|
+
"mappings": ";+EACA,OAAS,SAAAA,MAAa,kBAQtB,IAAIC,EAAa,EAGjB,eAAsBC,EACpBC,EACAC,EACAC,EACAC,EACAC,EAAgD,CAEhDD,EAAO,eAAc,EAErB,MAAME,EAAQL,EAAQ,eAAiB,EACjCM,EAAgBC,EAACC,GAAyB,CAC9C,GAAI,CAAC,OAAO,UAAUA,CAAK,GAAKA,EAAQ,GAAKA,EAAQ,IACnD,MAAM,IAAI,WAAW,wEAAwE,EAC/F,OAAOA,CACT,EAJsB,iBAMtB,IAAIC,EAAa,OAAOJ,GAAU,WAAa,EAAIC,EAAcD,CAAK,EAClEK,EAAUR,EAAO,EAErB,GAAI,CAACF,EAAQ,SACX,OAAOI,EAAOM,CAAO,EAGvB,MAAMC,EAAK,EAAEb,EACb,IAAIc,EAAmB,CAAE,KAAM,EAAG,IAAK,EAAG,MAAO,EAAG,OAAQ,CAAC,EAE7D,MAAMC,EAASN,EAACO,GAA4C,CAC1D,GAAIJ,EAAQ,YAAa,CACvB,MAAMK,EAASL,EAAQ,sBAAqB,EAC5CE,EAAO,CAAE,KAAMG,EAAO,KAAM,IAAKA,EAAO,IAAK,MAAOA,EAAO,MAAO,OAAQA,EAAO,MAAM,CACzF,CAEA,GAAI,CACFf,EAAQ,WAAW,CAAE,GAAAW,EAAI,OAAAV,EAAQ,MAAAa,EAAO,QAAAJ,EAAS,KAAM,CAAE,GAAGE,CAAI,EAAI,WAAAH,CAAU,CAAE,CAClF,MAAQ,CAER,CACF,EAXe,UAaf,GAAI,CACET,EAAQ,gBACVU,EAAQ,iBAAiB,CAAE,MAAO,UAAW,OAAQ,UAAW,SAAU,SAAS,CAAE,EAGvFP,EAAO,eAAc,EACrBO,EAAUR,EAAO,EAEb,OAAOG,GAAU,aACnBI,EAAaH,EAAcD,EAAMK,CAAO,CAAC,EACzCP,EAAO,eAAc,EACrBO,EAAUR,EAAO,GAGnBW,EAAO,QAAQ,EACfV,EAAO,eAAc,EACjBM,GACF,MAAMZ,EAAMM,EAAQM,CAAU,EAIhCC,EAAUR,EAAO,EACjBC,EAAO,eAAc,EAErB,MAAMa,EAAS,MAAMZ,EAAOM,CAAO,EACnC,OAAAP,EAAO,eAAc,EACrBU,EAAO,OAAO,EAEPG,CACT,OAASC,EAAO,CACd,MAAAJ,EAAOV,EAAO,QAAU,YAAc,QAAQ,EACxCc,CACR,CACF,CAxEsBV,EAAAR,EAAA",
|
|
6
|
+
"names": ["pause", "nextAction", "withActionFeedback", "options", "action", "resolve", "signal", "effect", "delay", "validateDelay", "__name", "value", "durationMs", "element", "id", "rect", "notify", "phase", "bounds", "result", "error"]
|
|
7
|
+
}
|
package/dist/dom.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ControlState } from './types.js';
|
|
2
|
+
export type NativeField = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
|
|
3
|
+
export type ControlData = Omit<ControlState, 'target'>;
|
|
4
|
+
export declare const CONTROL_SELECTOR = "button, a[href], input:not([type=\"hidden\"]):not([type=\"password\"]):not([type=\"file\"]), textarea, select, [contenteditable=\"true\"], [contenteditable=\"\"], [role=\"button\"], [role=\"link\"], [role=\"checkbox\"], [role=\"radio\"], [role=\"textbox\"], [role=\"combobox\"], [tabindex]";
|
|
5
|
+
/** Follow open shadow hosts as well as ordinary DOM ancestors. */
|
|
6
|
+
export declare function composedParent(element: HTMLElement): HTMLElement | null;
|
|
7
|
+
export declare function contains(root: Document | HTMLElement, element: HTMLElement): boolean;
|
|
8
|
+
export declare function activeElement(document: Document): Element | null;
|
|
9
|
+
/** Keep discovery within the configured root, including its open shadow trees. */
|
|
10
|
+
export declare function controls(root: Document | HTMLElement | ShadowRoot): Generator<HTMLElement>;
|
|
11
|
+
export declare function isField(element: HTMLElement): element is NativeField;
|
|
12
|
+
export declare function isVisible(element: HTMLElement): boolean;
|
|
13
|
+
/** Read rendered text without copying hidden content or field values into page prose. */
|
|
14
|
+
export declare function visibleText(root: Document | HTMLElement, limit: number): string;
|
|
15
|
+
export declare function observeControl(element: HTMLElement, root: Document | HTMLElement): ControlData;
|
|
16
|
+
export declare function configuration(element: HTMLElement): string;
|
|
17
|
+
//# sourceMappingURL=dom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../src/dom.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAgB,YAAY,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,MAAM,WAAW,GAAG,gBAAgB,GAAG,mBAAmB,GAAG,iBAAiB,CAAC;AACrF,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;AAEvD,eAAO,MAAM,gBAAgB,sSACkP,CAAC;AAIhR,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW,GAAG,IAAI,CAOvE;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,WAAW,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAMpF;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,IAAI,CAIhE;AAED,kFAAkF;AAClF,wBAAiB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC,WAAW,CAAC,CAU3F;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,IAAI,WAAW,CAEpE;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAwBvD;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA0C/E;AA0GD,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,GAAG,WAAW,GAAG,WAAW,CAsD9F;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAkB1D"}
|
package/dist/dom.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT
|
|
2
|
+
var w=Object.defineProperty;var s=(t,e)=>w(t,"name",{value:e,configurable:!0});import{computeAccessibleDescription as v,computeAccessibleName as T,getRole as m}from"dom-accessibility-api";const R='button, a[href], input:not([type="hidden"]):not([type="password"]):not([type="file"]), textarea, select, [contenteditable="true"], [contenteditable=""], [role="button"], [role="link"], [role="checkbox"], [role="radio"], [role="textbox"], [role="combobox"], [tabindex]',f="script, style, noscript, template, [data-ruakit-ignore], [data-ruakit-toolbar]",p=s(t=>t.replace(/\s+/g," ").trim(),"normalize");function h(t){if(t.parentElement)return t.parentElement;const e=t.getRootNode();return e instanceof t.ownerDocument.defaultView.ShadowRoot?e.host:null}s(h,"composedParent");function g(t,e){for(let i=e;i;i=h(i))if(t.contains(i))return!0;return!1}s(g,"contains");function O(t){let e=t.activeElement;for(;e?.shadowRoot?.activeElement;)e=e.shadowRoot.activeElement;return e}s(O,"activeElement");function*N(t){t.nodeType===1&&t.matches(R)&&(yield t),t.nodeType===1&&t.shadowRoot&&(yield*N(t.shadowRoot));for(const e of t.children)e.matches(f)||(yield*N(e))}s(N,"controls");function x(t){return["INPUT","TEXTAREA","SELECT"].includes(t.tagName)}s(x,"isField");function E(t){if(!t.isConnected||!t.getClientRects().length||t.closest(`${f}, [hidden], [inert], [aria-hidden="true"]`))return!1;const e=t.ownerDocument.defaultView,i=e.getComputedStyle(t);if(i.visibility==="hidden"||i.visibility==="collapse")return!1;for(let r=t;r;r=h(r)){if(r.matches(`${f}, [hidden], [inert], [aria-hidden="true"]`))return!1;const c=e.getComputedStyle(r);if(c.display==="none"||c.opacity==="0")return!1}return!0}s(E,"isVisible");function y(t,e){if(t.nodeType===1&&t.matches(`${f}, input, textarea, select`))return"";const i=t.ownerDocument??t,r=i.defaultView,c=i.createTreeWalker(t,r.NodeFilter.SHOW_ELEMENT|r.NodeFilter.SHOW_TEXT,{acceptNode(n){if(n.nodeType===r.Node.ELEMENT_NODE){const o=n;if(o.matches(`${f}, input, textarea, select`))return r.NodeFilter.FILTER_REJECT;const u=r.getComputedStyle(o).visibility;return E(o)||u==="hidden"||u==="collapse"?r.NodeFilter.FILTER_SKIP:r.NodeFilter.FILTER_REJECT}return n.parentElement&&E(n.parentElement)?r.NodeFilter.FILTER_ACCEPT:r.NodeFilter.FILTER_REJECT}});let l="";for(;c.nextNode();){const n=p(c.currentNode.textContent??"");if(n&&(l+=(l?" ":"")+n),l.length>=e)break}return l}s(y,"visibleText");function C(t){const e=t.getAttribute("role");if(e)return e;if(t.tagName==="A")return"link";if(t.tagName==="BUTTON")return"button";if(t.tagName==="SELECT"){const i=t;return i.multiple||i.size>1?"listbox":"combobox"}if(t.tagName==="INPUT"){const i=t.type;if(["button","submit","reset","image"].includes(i))return"button";if(["checkbox","radio"].includes(i))return i}return x(t)?"textbox":"control"}s(C,"roleOf");const k=new Set(["form","group","radiogroup","region","dialog","alertdialog"]);function A(t,e){const i=[],r=new Set;let c=!1;const l=s(o=>{if(o.closest(`${f}, [hidden], [inert], [aria-hidden="true"]`))return;const u=m(o);if(!u||!k.has(u))return;let a=p(T(o));if(!a){const d=[...o.children].find(b=>b instanceof t.ownerDocument.defaultView.HTMLElement&&b.matches('h1, h2, h3, h4, h5, h6, [role="heading"]')&&E(b));d&&(a=y(d,201))}if(a){if(i.length===4){c=!0;return}c||=a.length>200,i.push({role:u,name:a.slice(0,200)})}},"add"),n=x(t)||t.tagName==="BUTTON"?t.form:null;for(let o=h(t);o&&g(e,o);o=h(o))r.add(o),(o.tagName!=="FORM"||!n||o===n)&&l(o);return n&&g(e,n)&&!r.has(n)&&l(n),{...i.length?{groups:i.reverse()}:{},...c?{groupsTruncated:!0}:{}}}s(A,"observeGroups");function S(t,e){const i=t.matches('[contenteditable="true"], [contenteditable=""]'),r=x(t)?t:void 0,c=t.tagName==="INPUT"?t.type:"",l=t.tagName==="SELECT"?t:void 0,n=t.closest('tr, li, article, [role="row"], [role="listitem"]'),o=p(v(t)).slice(0,1e3),u=t.matches("input, textarea")?p(t.getAttribute("placeholder")??"").slice(0,1e3):"",a={tag:t.tagName.toLowerCase(),role:i?"textbox":C(t),...i?{contentEditable:!0,value:t.innerText??t.textContent??""}:{},...r?{type:c||t.tagName.toLowerCase()}:{},label:p(T(t)).slice(0,1e3),...o?{description:o}:{},...u?{placeholder:u}:{},...A(t,e),context:n&&g(e,n)?y(n,1e3).slice(0,1e3):"",enabled:!t.matches(":disabled")&&!t.closest('[aria-disabled="true"], [inert]'),readOnly:t.getAttribute("aria-readonly")==="true"||!!(r&&"readOnly"in r&&r.readOnly)};return r&&(a.value=r.value,a.valid=r.validity.valid&&t.getAttribute("aria-invalid")!=="true"),c==="checkbox"||c==="radio"?a.checked=t.checked:t.hasAttribute("aria-checked")&&(a.checked=t.getAttribute("aria-checked")==="true"),t.hasAttribute("aria-expanded")&&(a.expanded=t.getAttribute("aria-expanded")==="true"),l&&(a.selectedValues=[...l.selectedOptions].map(d=>d.value),a.options=[...l.options].map(d=>({value:d.value,label:d.label,enabled:!d.disabled&&!d.closest("optgroup[disabled]")}))),a}s(S,"observeControl");function I(t){return JSON.stringify(["type","name","href","role","form","required","min","max","step","pattern","minlength","maxlength","multiple"].map(e=>t.getAttribute(e)))}s(I,"configuration");export{R as CONTROL_SELECTOR,O as activeElement,h as composedParent,I as configuration,g as contains,N as controls,x as isField,E as isVisible,S as observeControl,y as visibleText};
|
|
3
|
+
//# sourceMappingURL=dom.js.map
|
package/dist/dom.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/dom.ts"],
|
|
4
|
+
"sourcesContent": ["// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT\nimport {\n computeAccessibleDescription,\n computeAccessibleName,\n getRole,\n} from 'dom-accessibility-api';\nimport type { ControlGroup, ControlState } from './types.js';\n\nexport type NativeField = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\nexport type ControlData = Omit<ControlState, 'target'>;\n\nexport const CONTROL_SELECTOR =\n 'button, a[href], input:not([type=\"hidden\"]):not([type=\"password\"]):not([type=\"file\"]), textarea, select, [contenteditable=\"true\"], [contenteditable=\"\"], [role=\"button\"], [role=\"link\"], [role=\"checkbox\"], [role=\"radio\"], [role=\"textbox\"], [role=\"combobox\"], [tabindex]';\nconst excluded = 'script, style, noscript, template, [data-ruakit-ignore], [data-ruakit-toolbar]';\nconst normalize = (value: string): string => value.replace(/\\s+/g, ' ').trim();\n\n/** Follow open shadow hosts as well as ordinary DOM ancestors. */\nexport function composedParent(element: HTMLElement): HTMLElement | null {\n if (element.parentElement) return element.parentElement;\n\n const root = element.getRootNode();\n return root instanceof element.ownerDocument.defaultView!.ShadowRoot\n ? (root.host as HTMLElement)\n : null;\n}\n\nexport function contains(root: Document | HTMLElement, element: HTMLElement): boolean {\n for (let current: HTMLElement | null = element; current; current = composedParent(current)) {\n if (root.contains(current)) return true;\n }\n\n return false;\n}\n\nexport function activeElement(document: Document): Element | null {\n let element = document.activeElement;\n while (element?.shadowRoot?.activeElement) element = element.shadowRoot.activeElement;\n return element;\n}\n\n/** Keep discovery within the configured root, including its open shadow trees. */\nexport function* controls(root: Document | HTMLElement | ShadowRoot): Generator<HTMLElement> {\n if (root.nodeType === 1 && (root as HTMLElement).matches(CONTROL_SELECTOR))\n yield root as HTMLElement;\n if (root.nodeType === 1 && (root as HTMLElement).shadowRoot)\n yield* controls((root as HTMLElement).shadowRoot!);\n\n for (const child of root.children) {\n if (child.matches(excluded)) continue;\n yield* controls(child as HTMLElement);\n }\n}\n\nexport function isField(element: HTMLElement): element is NativeField {\n return ['INPUT', 'TEXTAREA', 'SELECT'].includes(element.tagName);\n}\n\nexport function isVisible(element: HTMLElement): boolean {\n if (\n !element.isConnected ||\n !element.getClientRects().length ||\n element.closest(`${excluded}, [hidden], [inert], [aria-hidden=\"true\"]`)\n ) {\n return false;\n }\n\n const view = element.ownerDocument.defaultView!;\n const current = view.getComputedStyle(element);\n if (current.visibility === 'hidden' || current.visibility === 'collapse') {\n return false;\n }\n\n for (let parent: HTMLElement | null = element; parent; parent = composedParent(parent)) {\n if (parent.matches(`${excluded}, [hidden], [inert], [aria-hidden=\"true\"]`)) return false;\n const style = view.getComputedStyle(parent);\n if (style.display === 'none' || style.opacity === '0') {\n return false;\n }\n }\n\n return true;\n}\n\n/** Read rendered text without copying hidden content or field values into page prose. */\nexport function visibleText(root: Document | HTMLElement, limit: number): string {\n if (\n root.nodeType === 1 &&\n (root as HTMLElement).matches(`${excluded}, input, textarea, select`)\n ) {\n return '';\n }\n const document = root.ownerDocument ?? (root as Document);\n const view = document.defaultView!;\n const walker = document.createTreeWalker(\n root,\n view.NodeFilter.SHOW_ELEMENT | view.NodeFilter.SHOW_TEXT,\n {\n acceptNode(node) {\n if (node.nodeType === view.Node.ELEMENT_NODE) {\n const element = node as HTMLElement;\n if (element.matches(`${excluded}, input, textarea, select`)) {\n return view.NodeFilter.FILTER_REJECT;\n }\n // A descendant can override visibility:hidden. Its own text is checked below.\n const visibility = view.getComputedStyle(element).visibility;\n return isVisible(element) || visibility === 'hidden' || visibility === 'collapse'\n ? view.NodeFilter.FILTER_SKIP\n : view.NodeFilter.FILTER_REJECT;\n }\n return node.parentElement && isVisible(node.parentElement)\n ? view.NodeFilter.FILTER_ACCEPT\n : view.NodeFilter.FILTER_REJECT;\n },\n },\n );\n let result = '';\n while (walker.nextNode()) {\n const value = normalize(walker.currentNode.textContent ?? '');\n if (value) {\n result += (result ? ' ' : '') + value;\n }\n if (result.length >= limit) {\n break;\n }\n }\n return result;\n}\n\nfunction roleOf(element: HTMLElement): string {\n const explicit = element.getAttribute('role');\n if (explicit) {\n return explicit;\n }\n if (element.tagName === 'A') {\n return 'link';\n }\n if (element.tagName === 'BUTTON') {\n return 'button';\n }\n if (element.tagName === 'SELECT') {\n const select = element as HTMLSelectElement;\n return select.multiple || select.size > 1 ? 'listbox' : 'combobox';\n }\n if (element.tagName === 'INPUT') {\n const type = (element as HTMLInputElement).type;\n if (['button', 'submit', 'reset', 'image'].includes(type)) {\n return 'button';\n }\n if (['checkbox', 'radio'].includes(type)) {\n return type;\n }\n }\n return isField(element) ? 'textbox' : 'control';\n}\n\nconst groupRoles = new Set<ControlGroup['role']>([\n 'form',\n 'group',\n 'radiogroup',\n 'region',\n 'dialog',\n 'alertdialog',\n]);\n\n/** Preserve group names without copying complete forms, field values or surrounding page prose. */\nfunction observeGroups(\n element: HTMLElement,\n root: Document | HTMLElement,\n): Pick<ControlData, 'groups' | 'groupsTruncated'> {\n const groups: ControlGroup[] = [];\n const ancestors = new Set<HTMLElement>();\n let truncated = false;\n\n const add = (container: HTMLElement): void => {\n if (container.closest(`${excluded}, [hidden], [inert], [aria-hidden=\"true\"]`)) {\n return;\n }\n const role = getRole(container) as ControlGroup['role'] | null;\n if (!role || !groupRoles.has(role)) {\n return;\n }\n let name = normalize(computeAccessibleName(container));\n if (!name) {\n // A direct visible heading also identifies an otherwise unnamed section or group.\n const heading = [...container.children].find(\n (child): child is HTMLElement =>\n child instanceof element.ownerDocument.defaultView!.HTMLElement &&\n child.matches('h1, h2, h3, h4, h5, h6, [role=\"heading\"]') &&\n isVisible(child),\n );\n if (heading) {\n name = visibleText(heading, 201);\n }\n }\n if (!name) {\n return;\n }\n if (groups.length === 4) {\n truncated = true;\n return;\n }\n truncated ||= name.length > 200;\n groups.push({ role, name: name.slice(0, 200) });\n };\n\n const ownerForm =\n isField(element) || element.tagName === 'BUTTON'\n ? (element as NativeField | HTMLButtonElement).form\n : null;\n\n for (\n let parent = composedParent(element);\n parent && contains(root, parent);\n parent = composedParent(parent)\n ) {\n ancestors.add(parent);\n // A form attribute can associate a field with a different form from its DOM ancestor.\n if (parent.tagName !== 'FORM' || !ownerForm || parent === ownerForm) {\n add(parent);\n }\n }\n\n if (ownerForm && contains(root, ownerForm) && !ancestors.has(ownerForm)) {\n add(ownerForm);\n }\n\n return {\n ...(groups.length ? { groups: groups.reverse() } : {}),\n ...(truncated ? { groupsTruncated: true } : {}),\n };\n}\n\nexport function observeControl(element: HTMLElement, root: Document | HTMLElement): ControlData {\n const editable = element.matches('[contenteditable=\"true\"], [contenteditable=\"\"]');\n const field = isField(element) ? element : undefined;\n const type = element.tagName === 'INPUT' ? (element as HTMLInputElement).type : '';\n const select = element.tagName === 'SELECT' ? (element as HTMLSelectElement) : undefined;\n const row = element.closest<HTMLElement>('tr, li, article, [role=\"row\"], [role=\"listitem\"]');\n const description = normalize(computeAccessibleDescription(element)).slice(0, 1000);\n const placeholder = element.matches('input, textarea')\n ? normalize(element.getAttribute('placeholder') ?? '').slice(0, 1000)\n : '';\n\n const data: ControlData = {\n tag: element.tagName.toLowerCase(),\n role: editable ? 'textbox' : roleOf(element),\n ...(editable\n ? { contentEditable: true, value: element.innerText ?? element.textContent ?? '' }\n : {}),\n ...(field ? { type: type || element.tagName.toLowerCase() } : {}),\n label: normalize(computeAccessibleName(element)).slice(0, 1000),\n ...(description ? { description } : {}),\n ...(placeholder ? { placeholder } : {}),\n ...observeGroups(element, root),\n context: row && contains(root, row) ? visibleText(row, 1000).slice(0, 1000) : '',\n enabled: !element.matches(':disabled') && !element.closest('[aria-disabled=\"true\"], [inert]'),\n readOnly:\n element.getAttribute('aria-readonly') === 'true' ||\n Boolean(field && 'readOnly' in field && field.readOnly),\n };\n\n if (field) {\n data.value = field.value;\n data.valid = field.validity.valid && element.getAttribute('aria-invalid') !== 'true';\n }\n\n if (type === 'checkbox' || type === 'radio') {\n data.checked = (element as HTMLInputElement).checked;\n } else if (element.hasAttribute('aria-checked')) {\n data.checked = element.getAttribute('aria-checked') === 'true';\n }\n\n if (element.hasAttribute('aria-expanded')) {\n data.expanded = element.getAttribute('aria-expanded') === 'true';\n }\n\n if (select) {\n data.selectedValues = [...select.selectedOptions].map((option) => option.value);\n data.options = [...select.options].map((option) => ({\n value: option.value,\n label: option.label,\n enabled: !option.disabled && !option.closest('optgroup[disabled]'),\n }));\n }\n\n return data;\n}\n\nexport function configuration(element: HTMLElement): string {\n return JSON.stringify(\n [\n 'type',\n 'name',\n 'href',\n 'role',\n 'form',\n 'required',\n 'min',\n 'max',\n 'step',\n 'pattern',\n 'minlength',\n 'maxlength',\n 'multiple',\n ].map((name) => element.getAttribute(name)),\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["computeAccessibleDescription", "computeAccessibleName", "getRole", "CONTROL_SELECTOR", "excluded", "normalize", "__name", "value", "composedParent", "element", "root", "contains", "current", "activeElement", "document", "controls", "child", "isField", "isVisible", "view", "parent", "style", "visibleText", "limit", "walker", "node", "visibility", "result", "roleOf", "explicit", "select", "type", "groupRoles", "observeGroups", "groups", "ancestors", "truncated", "add", "container", "role", "name", "heading", "ownerForm", "observeControl", "editable", "field", "row", "description", "placeholder", "data", "option", "configuration"]
|
|
7
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type RuntimeErrorCode = 'STALE_TARGET' | 'DISABLED' | 'READ_ONLY' | 'UNSUPPORTED' | 'VALUE_REJECTED' | 'BUSY' | 'TIMEOUT';
|
|
2
|
+
export declare class RuntimeError extends Error {
|
|
3
|
+
readonly code: RuntimeErrorCode;
|
|
4
|
+
constructor(code: RuntimeErrorCode, message: string);
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAC1B,cAAc,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAAC;AAEpG,qBAAa,YAAa,SAAQ,KAAK;IAEnC,QAAQ,CAAC,IAAI,EAAE,gBAAgB;gBAAtB,IAAI,EAAE,gBAAgB,EAC/B,OAAO,EAAE,MAAM;CAKlB"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT
|
|
2
|
+
var s=Object.defineProperty;var o=(e,r)=>s(e,"name",{value:r,configurable:!0});class n extends Error{static{o(this,"RuntimeError")}code;constructor(r,t){super(t),this.code=r,this.name="RuntimeError"}}export{n as RuntimeError};
|
|
3
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/errors.ts"],
|
|
4
|
+
"sourcesContent": ["// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT\n\nexport type RuntimeErrorCode =\n 'STALE_TARGET' | 'DISABLED' | 'READ_ONLY' | 'UNSUPPORTED' | 'VALUE_REJECTED' | 'BUSY' | 'TIMEOUT';\n\nexport class RuntimeError extends Error {\n constructor(\n readonly code: RuntimeErrorCode,\n message: string,\n ) {\n super(message);\n this.name = 'RuntimeError';\n }\n}\n"],
|
|
5
|
+
"mappings": ";+EAKM,MAAOA,UAAqB,KAAK,CALvC,MAKuC,CAAAC,EAAA,qBAE1B,KADX,YACWC,EACTC,EAAe,CAEf,MAAMA,CAAO,EAHJ,KAAA,KAAAD,EAIT,KAAK,KAAO,cACd",
|
|
6
|
+
"names": ["RuntimeError", "__name", "code", "message"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ActionOptions } from '../types.js';
|
|
2
|
+
/** CSS pixels relative to the surface's bounding rectangle, not canvas bitmap pixels. */
|
|
3
|
+
export interface Point {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
}
|
|
7
|
+
export interface DragOptions extends ActionOptions {
|
|
8
|
+
steps?: number;
|
|
9
|
+
durationMs?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface Pointer {
|
|
12
|
+
move(point: Point, options?: ActionOptions): Promise<void>;
|
|
13
|
+
down(point: Point, options?: ActionOptions): Promise<void>;
|
|
14
|
+
up(point: Point, options?: ActionOptions): Promise<void>;
|
|
15
|
+
drag(from: Point, to: Point, options?: DragOptions): Promise<void>;
|
|
16
|
+
cancel(options?: ActionOptions): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Experimental synthetic mouse pointer bound to one surface (including a plain canvas).
|
|
20
|
+
* Events always target this element; this does not implement hit testing, native pointer
|
|
21
|
+
* capture, hover boundaries, browser default actions, or movement of the system cursor.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createPointer(surface: HTMLElement): Pointer;
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/experimental/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,yFAAyF;AACzF,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,WAAY,SAAQ,aAAa;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,MAAM,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAkK3D"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT
|
|
2
|
+
var E=Object.defineProperty;var c=(o,a)=>E(o,"name",{value:a,configurable:!0});import{pause as m,withDeadline as v}from"../operations.js";import{RuntimeError as f}from"../errors.js";function P(o){const a=o.ownerDocument.defaultView;if(!a||!a.PointerEvent)throw new TypeError("createPointer requires a browser with PointerEvent support.");let n=!1,l=!1,h={x:0,y:0};function u(e){if(!Number.isFinite(e.x)||!Number.isFinite(e.y))throw new TypeError("Pointer coordinates must be finite numbers.")}c(u,"validate");function s(e,t){h={...t};const r=o.getBoundingClientRect(),i={bubbles:!0,cancelable:!0,composed:!0,clientX:r.left+t.x,clientY:r.top+t.y,pointerId:1,pointerType:"mouse",isPrimary:!0,button:e==="pointermove"||e==="pointercancel"?-1:0,buttons:n?1:0,pressure:n?.5:0};o.dispatchEvent(new a.PointerEvent(e,i))&&e!=="pointercancel"&&o.dispatchEvent(new a.MouseEvent(e.replace("pointer","mouse"),{...i,button:0}))}c(s,"emit");function b(){n&&(n=!1,s("pointercancel",h))}c(b,"release");async function w(e,t){if(l)throw new f("BUSY","Another pointer operation is running.");l=!0;try{await v(e.timeoutMs??2e3,e.signal,async r=>{if(!o.isConnected)throw new f("STALE_TARGET","The pointer surface is disconnected.");await t(r),await m(r)})}catch(r){throw b(),r}finally{l=!1}}return c(w,"run"),{move(e,t={}){return u(e),w(t,async()=>{s("pointermove",e)})},down(e,t={}){return u(e),w(t,async()=>{if(n)throw new Error("The pointer button is already down.");n=!0,s("pointerdown",e)})},up(e,t={}){return u(e),w(t,async()=>{if(!n)throw new Error("The pointer button is not down.");n=!1,s("pointerup",e)})},drag(e,t,r={}){u(e),u(t);const i=r.steps??12,p=r.durationMs??200;if(!Number.isInteger(i)||i<1||i>1e4||!Number.isFinite(p)||p<0)throw new RangeError("Use 1\u201310000 integer steps and a finite, nonnegative durationMs.");return w(r,async y=>{if(n)throw new Error("Release the pointer button before dragging.");s("pointermove",e),n=!0,s("pointerdown",e);for(let d=1;d<=i;d++){if(await m(y,p/i),y.throwIfAborted(),!o.isConnected)throw new f("STALE_TARGET","The pointer surface is disconnected.");s("pointermove",{x:e.x+(t.x-e.x)*d/i,y:e.y+(t.y-e.y)*d/i})}n=!1,s("pointerup",t)})},cancel(e={}){return w(e,async()=>{b()})}}}c(P,"createPointer");export{P as createPointer};
|
|
3
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/experimental/index.ts"],
|
|
4
|
+
"sourcesContent": ["// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT\nimport { pause, withDeadline } from '../operations.js';\nimport { RuntimeError } from '../errors.js';\nimport type { ActionOptions } from '../types.js';\n\n/** CSS pixels relative to the surface's bounding rectangle, not canvas bitmap pixels. */\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface DragOptions extends ActionOptions {\n steps?: number;\n durationMs?: number;\n}\n\nexport interface Pointer {\n move(point: Point, options?: ActionOptions): Promise<void>;\n down(point: Point, options?: ActionOptions): Promise<void>;\n up(point: Point, options?: ActionOptions): Promise<void>;\n drag(from: Point, to: Point, options?: DragOptions): Promise<void>;\n cancel(options?: ActionOptions): Promise<void>;\n}\n\n/**\n * Experimental synthetic mouse pointer bound to one surface (including a plain canvas).\n * Events always target this element; this does not implement hit testing, native pointer\n * capture, hover boundaries, browser default actions, or movement of the system cursor.\n */\nexport function createPointer(surface: HTMLElement): Pointer {\n const view = surface.ownerDocument.defaultView;\n if (!view || !view.PointerEvent) {\n throw new TypeError('createPointer requires a browser with PointerEvent support.');\n }\n\n let pressed = false;\n let busy = false;\n let position: Point = { x: 0, y: 0 };\n\n function validate(point: Point): void {\n if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) {\n throw new TypeError('Pointer coordinates must be finite numbers.');\n }\n }\n\n function emit(type: string, point: Point): void {\n position = { ...point };\n\n const rect = surface.getBoundingClientRect();\n const init: PointerEventInit = {\n bubbles: true,\n cancelable: true,\n composed: true,\n clientX: rect.left + point.x,\n clientY: rect.top + point.y,\n pointerId: 1,\n pointerType: 'mouse',\n isPrimary: true,\n button: type === 'pointermove' || type === 'pointercancel' ? -1 : 0,\n buttons: pressed ? 1 : 0,\n pressure: pressed ? 0.5 : 0,\n };\n\n const accepted = surface.dispatchEvent(new view!.PointerEvent(type, init));\n\n // Mouse compatibility events are explicit: dispatchEvent does not generate them.\n if (accepted && type !== 'pointercancel') {\n surface.dispatchEvent(\n new view!.MouseEvent(type.replace('pointer', 'mouse'), {\n ...init,\n button: 0,\n }),\n );\n }\n }\n\n function release(): void {\n if (pressed) {\n pressed = false;\n emit('pointercancel', position);\n }\n }\n\n async function run(\n options: ActionOptions,\n work: (signal: AbortSignal) => Promise<void>,\n ): Promise<void> {\n if (busy) {\n throw new RuntimeError('BUSY', 'Another pointer operation is running.');\n }\n\n busy = true;\n try {\n await withDeadline(options.timeoutMs ?? 2000, options.signal, async (signal) => {\n if (!surface.isConnected) {\n throw new RuntimeError('STALE_TARGET', 'The pointer surface is disconnected.');\n }\n\n await work(signal);\n await pause(signal);\n });\n } catch (error) {\n release();\n throw error;\n } finally {\n busy = false;\n }\n }\n\n return {\n move(point, options = {}) {\n validate(point);\n\n return run(options, async () => {\n emit('pointermove', point);\n });\n },\n down(point, options = {}) {\n validate(point);\n\n return run(options, async () => {\n if (pressed) {\n throw new Error('The pointer button is already down.');\n }\n\n pressed = true;\n emit('pointerdown', point);\n });\n },\n up(point, options = {}) {\n validate(point);\n\n return run(options, async () => {\n if (!pressed) {\n throw new Error('The pointer button is not down.');\n }\n\n pressed = false;\n emit('pointerup', point);\n });\n },\n drag(from, to, options = {}) {\n validate(from);\n validate(to);\n\n const steps = options.steps ?? 12;\n const duration = options.durationMs ?? 200;\n\n if (\n !Number.isInteger(steps) ||\n steps < 1 ||\n steps > 10000 ||\n !Number.isFinite(duration) ||\n duration < 0\n ) {\n throw new RangeError('Use 1\u201310000 integer steps and a finite, nonnegative durationMs.');\n }\n\n return run(options, async (signal) => {\n if (pressed) {\n throw new Error('Release the pointer button before dragging.');\n }\n\n emit('pointermove', from);\n pressed = true;\n emit('pointerdown', from);\n\n for (let step = 1; step <= steps; step++) {\n await pause(signal, duration / steps);\n signal.throwIfAborted();\n\n if (!surface.isConnected) {\n throw new RuntimeError('STALE_TARGET', 'The pointer surface is disconnected.');\n }\n\n emit('pointermove', {\n x: from.x + ((to.x - from.x) * step) / steps,\n y: from.y + ((to.y - from.y) * step) / steps,\n });\n }\n\n pressed = false;\n emit('pointerup', to);\n });\n },\n cancel(options = {}) {\n return run(options, async () => {\n release();\n });\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["pause", "withDeadline", "RuntimeError", "createPointer", "surface", "view", "pressed", "busy", "position", "validate", "point", "__name", "emit", "type", "rect", "init", "release", "run", "options", "work", "signal", "error", "from", "to", "steps", "duration", "step"]
|
|
7
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createRuntime } from './runtime.js';
|
|
2
|
+
export { RuntimeError } from './errors.js';
|
|
3
|
+
export { withActionFeedback } from './action-feedback.js';
|
|
4
|
+
export type { RuntimeErrorCode } from './errors.js';
|
|
5
|
+
export type { ActionOptions, ActionFeedbackOptions, ActionRect, ControlGroup, ControlState, KeyOptions, PageState, Runtime, RuntimeOptions, RuntimeAction, RuntimeActionEvent, Target, Screenshot, ScreenshotImage, } from './types.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,YAAY,EACV,aAAa,EACb,qBAAqB,EACrB,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,SAAS,EACT,OAAO,EACP,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,MAAM,EACN,UAAU,EACV,eAAe,GAChB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT
|
|
2
|
+
import{createRuntime as o}from"./runtime.js";import{RuntimeError as m}from"./errors.js";import{withActionFeedback as c}from"./action-feedback.js";export{m as RuntimeError,o as createRuntime,c as withActionFeedback};
|
|
3
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT\nexport { createRuntime } from './runtime.js';\nexport { RuntimeError } from './errors.js';\nexport { withActionFeedback } from './action-feedback.js';\nexport type { RuntimeErrorCode } from './errors.js';\nexport type {\n ActionOptions,\n ActionFeedbackOptions,\n ActionRect,\n ControlGroup,\n ControlState,\n KeyOptions,\n PageState,\n Runtime,\n RuntimeOptions,\n RuntimeAction,\n RuntimeActionEvent,\n Target,\n Screenshot,\n ScreenshotImage,\n} from './types.js';\n"],
|
|
5
|
+
"mappings": ";AACA,OAAS,iBAAAA,MAAqB,eAC9B,OAAS,gBAAAC,MAAoB,cAC7B,OAAS,sBAAAC,MAA0B",
|
|
6
|
+
"names": ["createRuntime", "RuntimeError", "withActionFeedback"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function validateTimeout(value: number): void;
|
|
2
|
+
/** Bound adapter work even when an adapter ignores cancellation. */
|
|
3
|
+
export declare function withDeadline<T>(timeoutMs: number, caller: AbortSignal | undefined, operation: (signal: AbortSignal) => Promise<T>): Promise<T>;
|
|
4
|
+
export declare function pause(signal: AbortSignal, milliseconds?: number): Promise<void>;
|
|
5
|
+
//# sourceMappingURL=operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../src/operations.ts"],"names":[],"mappings":"AAGA,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAInD;AAED,oEAAoE;AACpE,wBAAsB,YAAY,CAAC,CAAC,EAClC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,SAAS,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAC7C,OAAO,CAAC,CAAC,CAAC,CAkCZ;AAED,wBAAgB,KAAK,CAAC,MAAM,EAAE,WAAW,EAAE,YAAY,SAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB1E"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT
|
|
2
|
+
var c=Object.defineProperty;var r=(e,t)=>c(e,"name",{value:t,configurable:!0});import{RuntimeError as d}from"./errors.js";function w(e){if(!Number.isInteger(e)||e<1||e>2147483647)throw new RangeError("timeoutMs must be an integer between 1 and 2147483647.")}r(w,"validateTimeout");async function E(e,t,a){w(e);const i=new AbortController,o=r(()=>i.abort(t?.reason),"cancel");t?.addEventListener("abort",o,{once:!0}),t?.aborted&&o();const s=setTimeout(()=>i.abort(new d("TIMEOUT","The operation timed out.")),e),n=i.signal;try{return n.throwIfAborted(),await new Promise((u,m)=>{const b=r(()=>m(n.reason),"abort");n.addEventListener("abort",b,{once:!0}),Promise.resolve().then(()=>(n.throwIfAborted(),a(n))).then(u,m).finally(()=>n.removeEventListener("abort",b))})}finally{clearTimeout(s),t?.removeEventListener("abort",o)}}r(E,"withDeadline");function h(e,t=0){return e.throwIfAborted(),new Promise((a,i)=>{const o=r(()=>{clearTimeout(s),i(e.reason)},"abort"),s=setTimeout(()=>{e.removeEventListener("abort",o),a()},t);e.addEventListener("abort",o,{once:!0})})}r(h,"pause");export{h as pause,w as validateTimeout,E as withDeadline};
|
|
3
|
+
//# sourceMappingURL=operations.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/operations.ts"],
|
|
4
|
+
"sourcesContent": ["// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT\nimport { RuntimeError } from './errors.js';\n\nexport function validateTimeout(value: number): void {\n if (!Number.isInteger(value) || value < 1 || value > 2147483647) {\n throw new RangeError('timeoutMs must be an integer between 1 and 2147483647.');\n }\n}\n\n/** Bound adapter work even when an adapter ignores cancellation. */\nexport async function withDeadline<T>(\n timeoutMs: number,\n caller: AbortSignal | undefined,\n operation: (signal: AbortSignal) => Promise<T>,\n): Promise<T> {\n validateTimeout(timeoutMs);\n\n const controller = new AbortController();\n const cancel = (): void => controller.abort(caller?.reason);\n\n caller?.addEventListener('abort', cancel, { once: true });\n if (caller?.aborted) {\n cancel();\n }\n\n const timer = setTimeout(\n () => controller.abort(new RuntimeError('TIMEOUT', 'The operation timed out.')),\n timeoutMs,\n );\n const signal = controller.signal;\n\n try {\n signal.throwIfAborted();\n return await new Promise<T>((resolve, reject) => {\n const abort = (): void => reject(signal.reason);\n signal.addEventListener('abort', abort, { once: true });\n Promise.resolve()\n .then(() => {\n signal.throwIfAborted();\n return operation(signal);\n })\n .then(resolve, reject)\n .finally(() => signal.removeEventListener('abort', abort));\n });\n } finally {\n clearTimeout(timer);\n caller?.removeEventListener('abort', cancel);\n }\n}\n\nexport function pause(signal: AbortSignal, milliseconds = 0): Promise<void> {\n signal.throwIfAborted();\n\n return new Promise((resolve, reject) => {\n const abort = (): void => {\n clearTimeout(timer);\n reject(signal.reason);\n };\n\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', abort);\n resolve();\n }, milliseconds);\n\n signal.addEventListener('abort', abort, { once: true });\n });\n}\n"],
|
|
5
|
+
"mappings": ";+EACA,OAAS,gBAAAA,MAAoB,cAEvB,SAAUC,EAAgBC,EAAa,CAC3C,GAAI,CAAC,OAAO,UAAUA,CAAK,GAAKA,EAAQ,GAAKA,EAAQ,WACnD,MAAM,IAAI,WAAW,wDAAwD,CAEjF,CAJgBC,EAAAF,EAAA,mBAOhB,eAAsBG,EACpBC,EACAC,EACAC,EAA8C,CAE9CN,EAAgBI,CAAS,EAEzB,MAAMG,EAAa,IAAI,gBACjBC,EAASN,EAAA,IAAYK,EAAW,MAAMF,GAAQ,MAAM,EAA3C,UAEfA,GAAQ,iBAAiB,QAASG,EAAQ,CAAE,KAAM,EAAI,CAAE,EACpDH,GAAQ,SACVG,EAAM,EAGR,MAAMC,EAAQ,WACZ,IAAMF,EAAW,MAAM,IAAIR,EAAa,UAAW,0BAA0B,CAAC,EAC9EK,CAAS,EAELM,EAASH,EAAW,OAE1B,GAAI,CACF,OAAAG,EAAO,eAAc,EACd,MAAM,IAAI,QAAW,CAACC,EAASC,IAAU,CAC9C,MAAMC,EAAQX,EAAA,IAAYU,EAAOF,EAAO,MAAM,EAAhC,SACdA,EAAO,iBAAiB,QAASG,EAAO,CAAE,KAAM,EAAI,CAAE,EACtD,QAAQ,QAAO,EACZ,KAAK,KACJH,EAAO,eAAc,EACdJ,EAAUI,CAAM,EACxB,EACA,KAAKC,EAASC,CAAM,EACpB,QAAQ,IAAMF,EAAO,oBAAoB,QAASG,CAAK,CAAC,CAC7D,CAAC,CACH,SACE,aAAaJ,CAAK,EAClBJ,GAAQ,oBAAoB,QAASG,CAAM,CAC7C,CACF,CAtCsBN,EAAAC,EAAA,gBAwChB,SAAUW,EAAMJ,EAAqBK,EAAe,EAAC,CACzD,OAAAL,EAAO,eAAc,EAEd,IAAI,QAAQ,CAACC,EAASC,IAAU,CACrC,MAAMC,EAAQX,EAAA,IAAW,CACvB,aAAaO,CAAK,EAClBG,EAAOF,EAAO,MAAM,CACtB,EAHc,SAKRD,EAAQ,WAAW,IAAK,CAC5BC,EAAO,oBAAoB,QAASG,CAAK,EACzCF,EAAO,CACT,EAAGI,CAAY,EAEfL,EAAO,iBAAiB,QAASG,EAAO,CAAE,KAAM,EAAI,CAAE,CACxD,CAAC,CACH,CAhBgBX,EAAAY,EAAA",
|
|
6
|
+
"names": ["RuntimeError", "validateTimeout", "value", "__name", "withDeadline", "timeoutMs", "caller", "operation", "controller", "cancel", "timer", "signal", "resolve", "reject", "abort", "pause", "milliseconds"]
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAGV,OAAO,EAEP,cAAc,EAEf,MAAM,YAAY,CAAC;AA8CpB,gGAAgG;AAChG,wBAAgB,aAAa,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAudnE"}
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT
|
|
2
|
+
var N=Object.defineProperty;var l=(h,u)=>N(h,"name",{value:u,configurable:!0});import{activeElement as A,configuration as P,contains as D,isField as O,isVisible as g,observeControl as E}from"./dom.js";import{RuntimeError as a}from"./errors.js";import{pause as R,validateTimeout as I,withDeadline as C}from"./operations.js";import{Targets as L}from"./targets.js";import{withActionFeedback as k}from"./action-feedback.js";import{captureScreenshot as V}from"./screenshot.js";const K=new Set(["text","search","email","tel","url","number","date","datetime-local","time","month","week","color","range"]);function S(h,u){const c=h.ownerDocument.defaultView,d=h.tagName==="TEXTAREA"?c.HTMLTextAreaElement.prototype:c.HTMLInputElement.prototype;Object.getOwnPropertyDescriptor(d,"value").set.call(h,u)}l(S,"assignValue");function H(h={}){const u=h.root===void 0?globalThis.document:h.root;if(!u)throw new TypeError("Create the runtime in a browser, after the app has mounted.");const c=new L(u),d=c.document,f=d.defaultView,v=h.timeoutMs??2e3;I(v);let b=!1;async function y(t,e){if(b)throw new a("BUSY","Another operation is running. Await it before starting the next one.");b=!0;try{return await C(t.timeoutMs??v,t.signal,e)}finally{b=!1}}l(y,"run");function w(t,e,o){return y(t,async r=>{const n=l(async()=>{const i=await e(r);return await R(r),r.throwIfAborted(),i?.(),c.getState()},"execute");return o?k(h,o.action,()=>c.resolve(o.target,o.requireEnabled),r,n):n()})}l(w,"act");function m(t,e){const o=c.resolve(t);return o.focus({preventScroll:!0}),e.throwIfAborted(),c.resolve(t),o}l(m,"focusTarget");function x(t,e,o){if(!D(u,t)||!g(t)||!E(t,u).enabled||P(t)!==e.configuration||t.form!==e.form||t.parentElement!==e.parent||!o.accepted())throw new a("VALUE_REJECTED","The application did not accept the requested field value.")}l(x,"verifyEdit");function T(t,e,o,r){return w(o,n=>{const i=c.resolve(e);if(!O(i))throw new a("UNSUPPORTED","This operation needs a native input, textarea or select.");if(E(i,u).readOnly)throw new a("READ_ONLY","The field is read-only.");const s=r(i);m(e,n);const p={configuration:P(i),form:i.form,parent:i.parentElement};return s.apply(n),()=>x(i,p,s)},{action:t,target:e})}l(T,"edit");function U(t,e){t.dispatchEvent(new f.Event("input",{bubbles:!0})),e.throwIfAborted(),t.dispatchEvent(new f.Event("change",{bubbles:!0}))}return l(U,"fieldEvents"),{getState:l(()=>c.getState(),"getState"),screenshot(t={}){return y(t,e=>V(u,e))},click(t,e={}){return w(e,()=>c.resolve(t).click(),{action:"click",target:t})},focus(t,e={}){return w(e,o=>{const r=m(t,o);return()=>{if(A(d)!==r)throw new a("UNSUPPORTED","The control did not receive focus.")}},{action:"focus",target:t})},blur(t,e={}){return w(e,()=>c.resolve(t).blur(),{action:"blur",target:t})},setValue(t,e,o={}){return T("fill",t,o,r=>{if(r.tagName==="SELECT"||r.tagName==="INPUT"&&!K.has(r.type))throw new a("UNSUPPORTED","Use setValue with a text or value input or a textarea.");const n=r,i=n.cloneNode(!0);if(S(i,e),i.value!==e||n.maxLength>=0&&e.length>n.maxLength)throw new a("VALUE_REJECTED","The requested value does not fit this field.");return{apply(s){S(n,e),U(n,s)},accepted:l(()=>n.value===e,"accepted")}})},selectOption(t,e,o={}){return T("select",t,o,r=>{if(r.tagName!=="SELECT")throw new a("UNSUPPORTED","Use selectOption with a native select.");const n=r,i=[...n.options];if(new Set(e).size!==e.length||!n.multiple&&e.length>1||e.some(s=>!i.some(p=>p.value===s))||i.some(s=>e.includes(s.value)&&(s.disabled||s.closest("optgroup[disabled]"))))throw new a("UNSUPPORTED","Choose available option values from getState().");return{apply(s){n.selectedIndex=-1;for(const p of i)p.selected=e.includes(p.value);U(n,s)},accepted:l(()=>n.selectedOptions.length===e.length&&[...n.selectedOptions].every(s=>e.includes(s.value)),"accepted")}})},setChecked(t,e,o={}){return T("check",t,o,r=>{const n=r;if(r.tagName!=="INPUT"||!["checkbox","radio"].includes(n.type))throw new a("UNSUPPORTED","Use setChecked with a native checkbox or radio.");if(n.type==="radio"&&n.checked&&!e)throw new a("UNSUPPORTED","Select another radio in the group to change its value.");return{apply(){n.checked!==e&&n.click()},accepted:l(()=>n.checked===e,"accepted")}})},insertText(t,e,o={}){return w(o,r=>{const n=c.resolve(t),i=E(n,u);if(i.readOnly)throw new a("READ_ONLY","The editor is read-only.");if(!i.contentEditable&&!n.matches("input, textarea"))throw new a("UNSUPPORTED","Insert text requires a text field or contenteditable surface.");m(t,r),r.throwIfAborted();const s=new f.InputEvent("beforeinput",{inputType:"insertText",data:e,bubbles:!0,cancelable:!0,composed:!0});if(!n.dispatchEvent(s))return r.throwIfAborted(),()=>{if(e&&E(n,u).value===i.value)throw new a("VALUE_REJECTED","The editor did not accept text insertion.")};if(r.throwIfAborted(),c.resolve(t),typeof d.execCommand!="function")throw new a("UNSUPPORTED","This browser does not support the text insertion command.");if(!d.execCommand("insertText",!1,e))throw new a("VALUE_REJECTED","The browser or editor rejected text insertion.")},{action:"insertText",target:t})},pressKey(t,e,o={}){return w(o,r=>{if(!e)throw new TypeError("Provide a keyboard key, such as Enter or Escape.");const n=m(t,r),i={key:e,bubbles:!0,cancelable:!0,altKey:o.altKey??!1,ctrlKey:o.ctrlKey??!1,metaKey:o.metaKey??!1,shiftKey:o.shiftKey??!1};n.dispatchEvent(new f.KeyboardEvent("keydown",i)),r.throwIfAborted(),n.isConnected&&n.dispatchEvent(new f.KeyboardEvent("keyup",i))},{action:"key",target:t})},scrollIntoView(t,e={}){return w(e,()=>{const o=c.resolve(t,!1);if(typeof o.scrollIntoView!="function")throw new a("UNSUPPORTED","This environment does not support scrollIntoView.");o.scrollIntoView({block:"nearest",inline:"nearest",behavior:"instant"})},{action:"scroll",target:t,requireEnabled:!1})},goto(t,e={}){return w(e,async o=>{const r=h.navigate;if(!r)throw new a("UNSUPPORTED","Pass your router navigation callback to createRuntime.");const n=new URL(t,d.URL);if(n.origin!==d.location.origin||!["http:","https:"].includes(n.protocol))throw new a("UNSUPPORTED","Navigation must stay within this application origin.");return await r(n.pathname+n.search+n.hash,o),o.throwIfAborted(),()=>{if(d.URL!==n.href)throw new a("VALUE_REJECTED","The router did not reach the requested URL.")}})},waitFor(t,e={}){return y(e,async o=>{for(;;){o.throwIfAborted();const r=c.getState();if(t(r))return r;await R(o,50)}})}}}l(H,"createRuntime");export{H as createRuntime};
|
|
3
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/runtime.ts"],
|
|
4
|
+
"sourcesContent": ["// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT\nimport {\n activeElement,\n configuration,\n contains,\n isField,\n isVisible,\n observeControl,\n} from \"./dom.js\";\nimport type { NativeField } from \"./dom.js\";\nimport { RuntimeError } from \"./errors.js\";\nimport { pause, validateTimeout, withDeadline } from \"./operations.js\";\nimport { Targets } from \"./targets.js\";\nimport { withActionFeedback } from \"./action-feedback.js\";\nimport { captureScreenshot } from \"./screenshot.js\";\nimport type {\n ActionOptions,\n PageState,\n Runtime,\n RuntimeAction,\n RuntimeOptions,\n Target,\n} from \"./types.js\";\n\ntype Verification = () => void;\ninterface Edit {\n apply(signal: AbortSignal): void;\n accepted(): boolean;\n}\n\ninterface FieldSnapshot {\n configuration: string;\n form: HTMLFormElement | null;\n parent: HTMLElement | null;\n}\n\nconst textTypes = new Set([\n \"text\",\n \"search\",\n \"email\",\n \"tel\",\n \"url\",\n \"number\",\n \"date\",\n \"datetime-local\",\n \"time\",\n \"month\",\n \"week\",\n \"color\",\n \"range\",\n]);\n\nfunction assignValue(\n element: HTMLInputElement | HTMLTextAreaElement,\n value: string,\n): void {\n const view = element.ownerDocument.defaultView!;\n const prototype =\n element.tagName === \"TEXTAREA\"\n ? view.HTMLTextAreaElement.prototype\n : view.HTMLInputElement.prototype;\n // Bypass React's value tracker so its input handler receives the new value.\n Object.getOwnPropertyDescriptor(prototype, \"value\")!.set!.call(\n element,\n value,\n );\n}\n\n/** Create this after mounting. Importing the package itself is safe during server rendering. */\nexport function createRuntime(options: RuntimeOptions = {}): Runtime {\n const root = options.root === undefined ? globalThis.document : options.root;\n if (!root) {\n throw new TypeError(\n \"Create the runtime in a browser, after the app has mounted.\",\n );\n }\n\n const targets = new Targets(root);\n const document = targets.document;\n const view = document.defaultView!;\n const timeoutMs = options.timeoutMs ?? 2000;\n\n validateTimeout(timeoutMs);\n let busy = false;\n\n async function run<T>(\n settings: ActionOptions,\n operation: (signal: AbortSignal) => Promise<T>,\n ): Promise<T> {\n if (busy) {\n throw new RuntimeError(\n \"BUSY\",\n \"Another operation is running. Await it before starting the next one.\",\n );\n }\n\n busy = true;\n try {\n return await withDeadline(\n settings.timeoutMs ?? timeoutMs,\n settings.signal,\n operation,\n );\n } finally {\n busy = false;\n }\n }\n\n function act(\n settings: ActionOptions,\n effect: (\n signal: AbortSignal,\n ) => void | Verification | Promise<void | Verification>,\n feedback?: {\n action: RuntimeAction;\n target: Target;\n requireEnabled?: boolean;\n },\n ): Promise<PageState> {\n return run(settings, async (signal) => {\n const execute = async (): Promise<PageState> => {\n const verify = await effect(signal);\n\n // Give controlled inputs and ordinary React event updates a turn to commit.\n await pause(signal);\n signal.throwIfAborted();\n verify?.();\n\n return targets.getState();\n };\n\n return feedback\n ? withActionFeedback(\n options,\n feedback.action,\n () => targets.resolve(feedback.target, feedback.requireEnabled),\n signal,\n execute,\n )\n : execute();\n });\n }\n\n function focusTarget(target: Target, signal: AbortSignal): HTMLElement {\n const element = targets.resolve(target);\n element.focus({ preventScroll: true });\n signal.throwIfAborted();\n targets.resolve(target);\n return element;\n }\n\n function verifyEdit(\n field: NativeField,\n before: FieldSnapshot,\n change: Edit,\n ): void {\n // A field replaced or reconfigured during the edit is no longer the same target.\n const fieldChanged =\n !contains(root, field) ||\n !isVisible(field) ||\n !observeControl(field, root).enabled ||\n configuration(field) !== before.configuration ||\n field.form !== before.form ||\n field.parentElement !== before.parent;\n\n if (fieldChanged || !change.accepted()) {\n throw new RuntimeError(\n \"VALUE_REJECTED\",\n \"The application did not accept the requested field value.\",\n );\n }\n }\n\n function edit(\n action: \"fill\" | \"select\" | \"check\",\n target: Target,\n settings: ActionOptions,\n prepare: (field: NativeField) => Edit,\n ): Promise<PageState> {\n return act(\n settings,\n (signal) => {\n const element = targets.resolve(target);\n if (!isField(element)) {\n throw new RuntimeError(\n \"UNSUPPORTED\",\n \"This operation needs a native input, textarea or select.\",\n );\n }\n\n if (observeControl(element, root).readOnly) {\n throw new RuntimeError(\"READ_ONLY\", \"The field is read-only.\");\n }\n\n const change = prepare(element);\n focusTarget(target, signal);\n\n const before: FieldSnapshot = {\n configuration: configuration(element),\n form: element.form,\n parent: element.parentElement,\n };\n\n change.apply(signal);\n\n // Check the result after the application has processed the field events.\n return () => verifyEdit(element, before, change);\n },\n { action, target },\n );\n }\n\n function fieldEvents(element: NativeField, signal: AbortSignal): void {\n element.dispatchEvent(new view.Event(\"input\", { bubbles: true }));\n signal.throwIfAborted();\n element.dispatchEvent(new view.Event(\"change\", { bubbles: true }));\n }\n\n return {\n getState: () => targets.getState(),\n screenshot(settings = {}) {\n return run(settings, (signal) => captureScreenshot(root, signal));\n },\n\n click(target, settings = {}) {\n return act(settings, () => targets.resolve(target).click(), {\n action: \"click\",\n target,\n });\n },\n\n focus(target, settings = {}) {\n return act(\n settings,\n (signal) => {\n const element = focusTarget(target, signal);\n return () => {\n if (activeElement(document) !== element) {\n throw new RuntimeError(\n \"UNSUPPORTED\",\n \"The control did not receive focus.\",\n );\n }\n };\n },\n { action: \"focus\", target },\n );\n },\n\n blur(target, settings = {}) {\n return act(settings, () => targets.resolve(target).blur(), {\n action: \"blur\",\n target,\n });\n },\n\n setValue(target, value, settings = {}) {\n return edit(\"fill\", target, settings, (field) => {\n if (\n field.tagName === \"SELECT\" ||\n (field.tagName === \"INPUT\" &&\n !textTypes.has((field as HTMLInputElement).type))\n ) {\n throw new RuntimeError(\n \"UNSUPPORTED\",\n \"Use setValue with a text or value input or a textarea.\",\n );\n }\n\n const element = field as HTMLInputElement | HTMLTextAreaElement;\n const clone = element.cloneNode(true) as typeof element;\n\n // Check the browser's normalization before changing the real field.\n assignValue(clone, value);\n if (\n clone.value !== value ||\n (element.maxLength >= 0 && value.length > element.maxLength)\n ) {\n throw new RuntimeError(\n \"VALUE_REJECTED\",\n \"The requested value does not fit this field.\",\n );\n }\n\n return {\n apply(signal) {\n assignValue(element, value);\n fieldEvents(element, signal);\n },\n accepted: () => element.value === value,\n };\n });\n },\n\n selectOption(target, values, settings = {}) {\n return edit(\"select\", target, settings, (field) => {\n if (field.tagName !== \"SELECT\") {\n throw new RuntimeError(\n \"UNSUPPORTED\",\n \"Use selectOption with a native select.\",\n );\n }\n\n const select = field as HTMLSelectElement;\n const options = [...select.options];\n\n if (\n new Set(values).size !== values.length ||\n (!select.multiple && values.length > 1) ||\n values.some(\n (value) => !options.some((option) => option.value === value),\n ) ||\n options.some(\n (option) =>\n values.includes(option.value) &&\n (option.disabled || option.closest(\"optgroup[disabled]\")),\n )\n ) {\n throw new RuntimeError(\n \"UNSUPPORTED\",\n \"Choose available option values from getState().\",\n );\n }\n\n return {\n apply(signal) {\n select.selectedIndex = -1;\n for (const option of options) {\n option.selected = values.includes(option.value);\n }\n\n fieldEvents(select, signal);\n },\n accepted: () =>\n select.selectedOptions.length === values.length &&\n [...select.selectedOptions].every((option) =>\n values.includes(option.value),\n ),\n };\n });\n },\n\n setChecked(target, checked, settings = {}) {\n return edit(\"check\", target, settings, (field) => {\n const input = field as HTMLInputElement;\n if (\n field.tagName !== \"INPUT\" ||\n ![\"checkbox\", \"radio\"].includes(input.type)\n ) {\n throw new RuntimeError(\n \"UNSUPPORTED\",\n \"Use setChecked with a native checkbox or radio.\",\n );\n }\n\n if (input.type === \"radio\" && input.checked && !checked) {\n throw new RuntimeError(\n \"UNSUPPORTED\",\n \"Select another radio in the group to change its value.\",\n );\n }\n\n return {\n apply() {\n if (input.checked !== checked) {\n input.click();\n }\n },\n accepted: () => input.checked === checked,\n };\n });\n },\n\n insertText(target, text, settings = {}) {\n return act(\n settings,\n (signal) => {\n const element = targets.resolve(target);\n const data = observeControl(element, root);\n\n if (data.readOnly) {\n throw new RuntimeError(\"READ_ONLY\", \"The editor is read-only.\");\n }\n\n if (!data.contentEditable && !element.matches(\"input, textarea\")) {\n throw new RuntimeError(\n \"UNSUPPORTED\",\n \"Insert text requires a text field or contenteditable surface.\",\n );\n }\n\n focusTarget(target, signal);\n signal.throwIfAborted();\n\n // Rich editors own their document and intercept beforeinput. Let them\n // handle insertion before falling back to the browser editing command.\n const input = new view.InputEvent(\"beforeinput\", {\n inputType: \"insertText\",\n data: text,\n bubbles: true,\n cancelable: true,\n composed: true,\n });\n\n if (!element.dispatchEvent(input)) {\n signal.throwIfAborted();\n return () => {\n if (text && observeControl(element, root).value === data.value) {\n throw new RuntimeError(\n \"VALUE_REJECTED\",\n \"The editor did not accept text insertion.\",\n );\n }\n };\n }\n\n signal.throwIfAborted();\n targets.resolve(target);\n\n if (typeof document.execCommand !== \"function\") {\n throw new RuntimeError(\n \"UNSUPPORTED\",\n \"This browser does not support the text insertion command.\",\n );\n }\n\n if (!document.execCommand(\"insertText\", false, text)) {\n throw new RuntimeError(\n \"VALUE_REJECTED\",\n \"The browser or editor rejected text insertion.\",\n );\n }\n },\n { action: \"insertText\", target },\n );\n },\n\n pressKey(target, key, settings = {}) {\n return act(\n settings,\n (signal) => {\n if (!key) {\n throw new TypeError(\n \"Provide a keyboard key, such as Enter or Escape.\",\n );\n }\n\n const element = focusTarget(target, signal);\n const event = {\n key,\n bubbles: true,\n cancelable: true,\n altKey: settings.altKey ?? false,\n ctrlKey: settings.ctrlKey ?? false,\n metaKey: settings.metaKey ?? false,\n shiftKey: settings.shiftKey ?? false,\n };\n\n element.dispatchEvent(new view.KeyboardEvent(\"keydown\", event));\n signal.throwIfAborted();\n if (element.isConnected) {\n element.dispatchEvent(new view.KeyboardEvent(\"keyup\", event));\n }\n },\n { action: \"key\", target },\n );\n },\n\n scrollIntoView(target, settings = {}) {\n return act(\n settings,\n () => {\n const element = targets.resolve(target, false);\n if (typeof element.scrollIntoView !== \"function\") {\n throw new RuntimeError(\n \"UNSUPPORTED\",\n \"This environment does not support scrollIntoView.\",\n );\n }\n\n element.scrollIntoView({\n block: \"nearest\",\n inline: \"nearest\",\n behavior: \"instant\",\n });\n },\n { action: \"scroll\", target, requireEnabled: false },\n );\n },\n\n goto(path, settings = {}) {\n return act(settings, async (signal) => {\n const navigate = options.navigate;\n if (!navigate) {\n throw new RuntimeError(\n \"UNSUPPORTED\",\n \"Pass your router navigation callback to createRuntime.\",\n );\n }\n\n const url = new URL(path, document.URL);\n if (\n url.origin !== document.location.origin ||\n ![\"http:\", \"https:\"].includes(url.protocol)\n ) {\n throw new RuntimeError(\n \"UNSUPPORTED\",\n \"Navigation must stay within this application origin.\",\n );\n }\n\n await navigate(url.pathname + url.search + url.hash, signal);\n signal.throwIfAborted();\n\n return () => {\n if (document.URL !== url.href) {\n throw new RuntimeError(\n \"VALUE_REJECTED\",\n \"The router did not reach the requested URL.\",\n );\n }\n };\n });\n },\n\n waitFor(condition, settings = {}) {\n return run(settings, async (signal) => {\n while (true) {\n signal.throwIfAborted();\n const state = targets.getState();\n\n if (condition(state)) {\n return state;\n }\n\n await pause(signal, 50);\n }\n });\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["activeElement", "configuration", "contains", "isField", "isVisible", "observeControl", "RuntimeError", "pause", "validateTimeout", "withDeadline", "Targets", "withActionFeedback", "captureScreenshot", "textTypes", "assignValue", "element", "value", "view", "prototype", "__name", "createRuntime", "options", "root", "targets", "document", "timeoutMs", "busy", "run", "settings", "operation", "act", "effect", "feedback", "signal", "execute", "verify", "focusTarget", "target", "verifyEdit", "field", "before", "change", "edit", "action", "prepare", "fieldEvents", "clone", "values", "select", "option", "checked", "input", "text", "data", "key", "event", "path", "navigate", "url", "condition", "state"]
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../src/screenshot.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAoD7C,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,QAAQ,GAAG,WAAW,EAC5B,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,UAAU,CAAC,CAkHrB"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT
|
|
2
|
+
var b=Object.defineProperty;var c=(n,e)=>b(n,"name",{value:e,configurable:!0});import{RuntimeError as r}from"./errors.js";const f='input[type="password"], input[type="file"], [data-ruakit-ignore], [data-ruakit-toolbar]',d=8192,p=4*1024*1024,T=5*1024*1024,R="data:image/png;base64,";function u(n){let e=n;for(;e;){if(e.closest(f))return!0;const i=e.getRootNode();e="host"in i?i.host:null}return["SCRIPT","NOSCRIPT","HEAD","IFRAME"].includes(n.tagName.toUpperCase())?!0:n.namespaceURI==="http://www.w3.org/2000/svg"&&!!(n.querySelector(f)||n.querySelector("use"))}c(u,"excluded");function P(n,e){const i=n.toDataURL("image/png");e.throwIfAborted();const t=i.slice(R.length);if(!i.startsWith(R)||!t.length||t.length%4!==0||t.length>Math.ceil(T/3)*4||!/^[A-Za-z0-9+/]+={0,2}$/.test(t))throw new r("UNSUPPORTED","The screenshot must be a PNG image within 5 MiB.");const s=globalThis.atob(t);if(s.length>T||!s.startsWith(`\x89PNG\r
|
|
3
|
+
|
|
4
|
+
`))throw new r("UNSUPPORTED","The screenshot must be a PNG image within 5 MiB.");return t}c(P,"pngData");async function N(n,e){e.throwIfAborted();const i=n.ownerDocument??n,t=n.nodeType===9?i.documentElement:n,s=i.URL;if(!t?.isConnected)throw new r("STALE_TARGET","The screenshot root is disconnected.");if(u(t))throw new r("UNSUPPORTED","The screenshot root is excluded from observation.");const w=t.getBoundingClientRect(),h=Math.ceil(Math.max(t.offsetWidth,t.clientWidth)||w.width),a=Math.ceil(Math.max(t.offsetHeight,t.clientHeight)||w.height);if(!Number.isFinite(h)||!Number.isFinite(a)||h<1||a<1)throw new r("UNSUPPORTED","The screenshot root has no rendered area.");const g=Math.min(1,d/h,d/a,Math.sqrt(p/h/a)),m=i.defaultView?.getComputedStyle(t),{toCanvas:x}=await import("html-to-image");e.throwIfAborted();const o=await x(t,{width:h,height:a,canvasWidth:Math.max(1,Math.floor(h*g)),canvasHeight:Math.max(1,Math.floor(a*g)),pixelRatio:1,includeQueryParams:!0,fetchRequestInit:{signal:e},style:{margin:"0",top:"0",left:"0",transform:"none",width:m?.width||`${h}px`,height:m?.height||`${a}px`},filter:c(l=>(e.throwIfAborted(),l.nodeType!==1||!u(l)),"filter")});if(e.throwIfAborted(),i.URL!==s||!t.isConnected)throw new r("STALE_TARGET","The page changed during screenshot capture.");if(u(t))throw new r("STALE_TARGET","The screenshot root became excluded during capture.");if(!Number.isInteger(o.width)||o.width<1||o.width>d||!Number.isInteger(o.height)||o.height<1||o.height>d||o.width*o.height>p)throw new r("UNSUPPORTED","The screenshot exceeds the image dimensions limit.");return{data:P(o,e),mimeType:"image/png",width:o.width,height:o.height,capturedAt:Date.now(),url:s}}c(N,"captureScreenshot");export{N as captureScreenshot};
|
|
5
|
+
//# sourceMappingURL=screenshot.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/screenshot.ts"],
|
|
4
|
+
"sourcesContent": ["// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT\nimport { RuntimeError } from './errors.js';\nimport type { Screenshot } from './types.js';\n\nconst privateSelector =\n 'input[type=\"password\"], input[type=\"file\"], [data-ruakit-ignore], [data-ruakit-toolbar]';\nconst maxDimension = 8192;\nconst maxPixels = 4 * 1024 * 1024;\nconst maxBytes = 5 * 1024 * 1024;\nconst pngPrefix = 'data:image/png;base64,';\n\nfunction excluded(element: Element): boolean {\n let ancestor: Element | null = element;\n while (ancestor) {\n if (ancestor.closest(privateSelector)) return true;\n\n const scope = ancestor.getRootNode();\n ancestor = 'host' in scope ? (scope as ShadowRoot).host : null;\n }\n\n if (['SCRIPT', 'NOSCRIPT', 'HEAD', 'IFRAME'].includes(element.tagName.toUpperCase())) {\n return true;\n }\n\n // SVGs and <use> references bypass html-to-image's child filter.\n return (\n element.namespaceURI === 'http://www.w3.org/2000/svg' &&\n Boolean(element.querySelector(privateSelector) || element.querySelector('use'))\n );\n}\n\nfunction pngData(canvas: HTMLCanvasElement, signal: AbortSignal): string {\n const dataUrl = canvas.toDataURL('image/png');\n signal.throwIfAborted();\n\n const data = dataUrl.slice(pngPrefix.length);\n if (\n !dataUrl.startsWith(pngPrefix) ||\n !data.length ||\n data.length % 4 !== 0 ||\n data.length > Math.ceil(maxBytes / 3) * 4 ||\n !/^[A-Za-z0-9+/]+={0,2}$/.test(data)\n ) {\n throw new RuntimeError('UNSUPPORTED', 'The screenshot must be a PNG image within 5 MiB.');\n }\n\n const bytes = globalThis.atob(data);\n if (bytes.length > maxBytes || !bytes.startsWith('\\x89PNG\\r\\n\\x1a\\n')) {\n throw new RuntimeError('UNSUPPORTED', 'The screenshot must be a PNG image within 5 MiB.');\n }\n\n return data;\n}\n\nexport async function captureScreenshot(\n root: Document | HTMLElement,\n signal: AbortSignal,\n): Promise<Screenshot> {\n signal.throwIfAborted();\n\n const document = root.ownerDocument ?? (root as Document);\n const element =\n root.nodeType === 9 ? document.documentElement : (root as HTMLElement);\n const url = document.URL;\n\n if (!element?.isConnected) {\n throw new RuntimeError(\n 'STALE_TARGET',\n 'The screenshot root is disconnected.',\n );\n }\n if (excluded(element)) {\n throw new RuntimeError(\n 'UNSUPPORTED',\n 'The screenshot root is excluded from observation.',\n );\n }\n\n const rect = element.getBoundingClientRect();\n const width = Math.ceil(\n Math.max(element.offsetWidth, element.clientWidth) || rect.width,\n );\n const height = Math.ceil(\n Math.max(element.offsetHeight, element.clientHeight) || rect.height,\n );\n\n if (\n !Number.isFinite(width) ||\n !Number.isFinite(height) ||\n width < 1 ||\n height < 1\n ) {\n throw new RuntimeError(\n 'UNSUPPORTED',\n 'The screenshot root has no rendered area.',\n );\n }\n\n const scale = Math.min(\n 1,\n maxDimension / width,\n maxDimension / height,\n Math.sqrt(maxPixels / width / height),\n );\n const style = document.defaultView?.getComputedStyle(element);\n\n // Import only on demand. Observation, actions and server rendering do not load the renderer.\n const { toCanvas } = await import('html-to-image');\n signal.throwIfAborted();\n\n const canvas = await toCanvas(element, {\n width,\n height,\n canvasWidth: Math.max(1, Math.floor(width * scale)),\n canvasHeight: Math.max(1, Math.floor(height * scale)),\n pixelRatio: 1,\n includeQueryParams: true,\n fetchRequestInit: { signal },\n // Normalize the root's placement in the exported image without changing the live page.\n style: {\n margin: '0',\n top: '0',\n left: '0',\n transform: 'none',\n width: style?.width || `${width}px`,\n height: style?.height || `${height}px`,\n },\n filter: (node) => {\n signal.throwIfAborted();\n return node.nodeType !== 1 || !excluded(node);\n },\n });\n\n signal.throwIfAborted();\n if (document.URL !== url || !element.isConnected) {\n throw new RuntimeError(\n 'STALE_TARGET',\n 'The page changed during screenshot capture.',\n );\n }\n if (excluded(element)) {\n throw new RuntimeError(\n 'STALE_TARGET',\n 'The screenshot root became excluded during capture.',\n );\n }\n\n if (\n !Number.isInteger(canvas.width) ||\n canvas.width < 1 ||\n canvas.width > maxDimension ||\n !Number.isInteger(canvas.height) ||\n canvas.height < 1 ||\n canvas.height > maxDimension ||\n canvas.width * canvas.height > maxPixels\n ) {\n throw new RuntimeError(\n 'UNSUPPORTED',\n 'The screenshot exceeds the image dimensions limit.',\n );\n }\n const data = pngData(canvas, signal);\n\n return {\n data,\n mimeType: 'image/png',\n width: canvas.width,\n height: canvas.height,\n capturedAt: Date.now(),\n url,\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["RuntimeError", "privateSelector", "maxDimension", "maxPixels", "maxBytes", "pngPrefix", "excluded", "element", "ancestor", "scope", "__name", "pngData", "canvas", "signal", "dataUrl", "data", "bytes", "captureScreenshot", "root", "document", "url", "rect", "width", "height", "scale", "style", "toCanvas", "node"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PageState, Target } from './types.js';
|
|
2
|
+
export declare class Targets {
|
|
3
|
+
readonly root: Document | HTMLElement;
|
|
4
|
+
readonly document: Document;
|
|
5
|
+
private readonly prefix;
|
|
6
|
+
private readonly ids;
|
|
7
|
+
private bindings;
|
|
8
|
+
private sequence;
|
|
9
|
+
private version;
|
|
10
|
+
constructor(root: Document | HTMLElement);
|
|
11
|
+
getState(): PageState;
|
|
12
|
+
resolve(target: Target, requireEnabled?: boolean): HTMLElement;
|
|
13
|
+
private matches;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=targets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAcpD,qBAAa,OAAO;IAQN,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,WAAW;IAPjD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IACrD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAsC;IAC1D,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,OAAO,CAAK;gBAEC,IAAI,EAAE,QAAQ,GAAG,WAAW;IAOjD,QAAQ,IAAI,SAAS;IAmErB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,UAAO,GAAG,WAAW;IAsB3D,OAAO,CAAC,OAAO;CAShB"}
|
package/dist/targets.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT
|
|
2
|
+
var g=Object.defineProperty;var a=(i,e)=>g(i,"name",{value:e,configurable:!0});import{configuration as c,activeElement as v,contains as w,controls as x,isField as h,isVisible as m,observeControl as d,visibleText as T}from"./dom.js";import{RuntimeError as f}from"./errors.js";let E=0;class b{static{a(this,"Targets")}root;document;prefix=`runtime-${++E}`;ids=new WeakMap;bindings=new Map;sequence=0;version=0;constructor(e){if(this.root=e,this.document=e.ownerDocument??e,!this.document.defaultView)throw new TypeError("Create the runtime in a browser, after the app has mounted.")}getState(){const e=new Map;let o=!1;for(const t of x(this.root)){if(!m(t)||t.matches('input[type="hidden"], input[type="password"], input[type="file"]'))continue;if(e.size===200){o=!0;break}let s=this.ids.get(t);s||(s=`${this.prefix}:${++this.sequence}`,this.ids.set(t,s));const u=d(t,this.root),r=this.bindings.get(s),p=r&&this.matches(r,u);e.set(s,{element:t,target:{id:s,version:p?r.target.version:++this.version},data:u,configuration:c(t),parent:t.parentElement,form:h(t)?t.form:null,url:this.document.URL})}this.bindings=e;const n=T(this.root,20001),l=[...e.values()].find(({element:t})=>t===v(this.document))?.target;return{url:this.document.URL,title:this.document.title,text:n.slice(0,2e4),controls:[...e.values()].map(({target:t,data:s})=>({target:{...t},...structuredClone(s)})),focused:l?{...l}:null,truncated:o||n.length>2e4||[...e.values()].some(({data:t})=>t.context.length===1e3||t.label.length===1e3||t.description?.length===1e3||t.placeholder?.length===1e3||t.groupsTruncated===!0)}}resolve(e,o=!0){const n=this.bindings.get(e.id);if(!n||n.target.version!==e.version||!w(this.root,n.element)||!m(n.element)||!this.matches(n,d(n.element,this.root)))throw new f("STALE_TARGET","The control changed. Call getState() and choose it again.");if(o&&!n.data.enabled)throw new f("DISABLED","The control is disabled.");return n.element}matches(e,o){return e.url===this.document.URL&&e.parent===e.element.parentElement&&e.form===(h(e.element)?e.element.form:null)&&e.configuration===c(e.element)&&JSON.stringify(e.data)===JSON.stringify(o)}}export{b as Targets};
|
|
3
|
+
//# sourceMappingURL=targets.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/targets.ts"],
|
|
4
|
+
"sourcesContent": ["// Copyright 2026 RuaKit contributors. SPDX-License-Identifier: MIT\nimport {\n configuration,\n activeElement,\n contains,\n controls,\n isField,\n isVisible,\n observeControl,\n visibleText,\n} from './dom.js';\nimport type { ControlData } from './dom.js';\nimport { RuntimeError } from './errors.js';\nimport type { PageState, Target } from './types.js';\n\ninterface Binding {\n element: HTMLElement;\n target: Target;\n data: ControlData;\n configuration: string;\n parent: Element | null;\n form: HTMLFormElement | null;\n url: string;\n}\n\nlet nextRuntime = 0;\n\nexport class Targets {\n readonly document: Document;\n private readonly prefix = `runtime-${++nextRuntime}`;\n private readonly ids = new WeakMap<HTMLElement, string>();\n private bindings = new Map<string, Binding>();\n private sequence = 0;\n private version = 0;\n\n constructor(readonly root: Document | HTMLElement) {\n this.document = root.ownerDocument ?? (root as Document);\n if (!this.document.defaultView) {\n throw new TypeError('Create the runtime in a browser, after the app has mounted.');\n }\n }\n\n getState(): PageState {\n const next = new Map<string, Binding>();\n let truncated = false;\n\n for (const element of controls(this.root)) {\n if (\n !isVisible(element) ||\n element.matches('input[type=\"hidden\"], input[type=\"password\"], input[type=\"file\"]')\n ) {\n continue;\n }\n\n if (next.size === 200) {\n truncated = true;\n break;\n }\n\n let id = this.ids.get(element);\n if (!id) {\n id = `${this.prefix}:${++this.sequence}`;\n this.ids.set(element, id);\n }\n\n const data = observeControl(element, this.root);\n const previous = this.bindings.get(id);\n const unchanged = previous && this.matches(previous, data);\n\n next.set(id, {\n element,\n target: { id, version: unchanged ? previous.target.version : ++this.version },\n data,\n configuration: configuration(element),\n parent: element.parentElement,\n form: isField(element) ? element.form : null,\n url: this.document.URL,\n });\n }\n\n this.bindings = next;\n const text = visibleText(this.root, 20001);\n const focused = [...next.values()].find(\n ({ element }) => element === activeElement(this.document),\n )?.target;\n\n return {\n url: this.document.URL,\n title: this.document.title,\n text: text.slice(0, 20000),\n controls: [...next.values()].map(({ target, data }) => ({\n target: { ...target },\n ...structuredClone(data),\n })),\n focused: focused ? { ...focused } : null,\n truncated:\n truncated ||\n text.length > 20000 ||\n [...next.values()].some(\n ({ data }) =>\n data.context.length === 1000 ||\n data.label.length === 1000 ||\n data.description?.length === 1000 ||\n data.placeholder?.length === 1000 ||\n data.groupsTruncated === true,\n ),\n };\n }\n\n resolve(target: Target, requireEnabled = true): HTMLElement {\n const binding = this.bindings.get(target.id);\n if (\n !binding ||\n binding.target.version !== target.version ||\n !contains(this.root, binding.element) ||\n !isVisible(binding.element) ||\n !this.matches(binding, observeControl(binding.element, this.root))\n ) {\n throw new RuntimeError(\n 'STALE_TARGET',\n 'The control changed. Call getState() and choose it again.',\n );\n }\n\n if (requireEnabled && !binding.data.enabled) {\n throw new RuntimeError('DISABLED', 'The control is disabled.');\n }\n\n return binding.element;\n }\n\n private matches(binding: Binding, data: ControlData): boolean {\n return (\n binding.url === this.document.URL &&\n binding.parent === binding.element.parentElement &&\n binding.form === (isField(binding.element) ? binding.element.form : null) &&\n binding.configuration === configuration(binding.element) &&\n JSON.stringify(binding.data) === JSON.stringify(data)\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["configuration", "activeElement", "contains", "controls", "isField", "isVisible", "observeControl", "visibleText", "RuntimeError", "nextRuntime", "Targets", "__name", "root", "next", "truncated", "element", "id", "data", "previous", "unchanged", "text", "focused", "target", "requireEnabled", "binding"]
|
|
7
|
+
}
|