diff --git a/dist/assets/limelight_logo.png b/dist/assets/limelight_logo.png new file mode 100644 index 0000000..459b883 Binary files /dev/null and b/dist/assets/limelight_logo.png differ diff --git a/dist/components/LimelightButton.vue.d.ts b/dist/components/LimelightButton.vue.d.ts new file mode 100644 index 0000000..1d030d5 --- /dev/null +++ b/dist/components/LimelightButton.vue.d.ts @@ -0,0 +1,21 @@ +type __VLS_Props = { + variant?: 'primary' | 'outline' | 'ghost' | 'danger'; + disabled?: boolean; +}; +declare function __VLS_template(): { + attrs: Partial<{}>; + slots: { + default?(_: {}): any; + }; + refs: {}; + rootEl: HTMLButtonElement; +}; +type __VLS_TemplateResult = ReturnType; +declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLButtonElement>; +declare const _default: __VLS_WithTemplateSlots; +export default _default; +type __VLS_WithTemplateSlots = T & { + new (): { + $slots: S; + }; +}; diff --git a/dist/env.d.ts b/dist/env.d.ts new file mode 100644 index 0000000..ee8be9c --- /dev/null +++ b/dist/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/dist/index.css b/dist/index.css new file mode 100644 index 0000000..1031c4a --- /dev/null +++ b/dist/index.css @@ -0,0 +1 @@ +/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */.btn[data-v-e0bc8f43]{height:calc(var(--spacing,.25rem) * 10);font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)));letter-spacing:.06em;text-transform:uppercase;cursor:pointer;clip-path:polygon(8px 0%,100% 0%,calc(100% - 8px) 100%,0% 100%);-webkit-user-select:none;user-select:none;border:none;padding:0 1.5rem;font-family:Barlow,sans-serif;font-weight:700;transition:background .15s,color .15s,border-color .15s,transform .1s}.btn--primary[data-v-e0bc8f43]{background:var(--color-primary);color:var(--color-black)}.btn--primary[data-v-e0bc8f43]:hover{background:var(--color-primary-light);transform:scaleX(1.03)}.btn--outline[data-v-e0bc8f43]{color:var(--color-primary);border:1.5px solid var(--color-primary);background:0 0}.btn--outline[data-v-e0bc8f43]:hover{background:var(--color-primary-dark);transform:scaleX(1.03)}.btn--ghost[data-v-e0bc8f43]{color:var(--color-secondary-light);border:1px solid var(--color-secondary-light);background:0 0}.btn--ghost[data-v-e0bc8f43]:hover{color:var(--color-primary);border-color:var(--color-primary);transform:scaleX(1.03)}.btn--danger[data-v-e0bc8f43]{background:var(--color-red);color:#fff}.btn--danger[data-v-e0bc8f43]:hover{filter:brightness(1.2);transform:scaleX(1.03)}.btn[data-v-e0bc8f43]:active{transform:scale(.97)}.btn--disabled[data-v-e0bc8f43]{opacity:.5;cursor:not-allowed}.btn--disabled[data-v-e0bc8f43]:hover{transform:scale(1)!important} diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..0233170 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,2 @@ +export { default as LimelightButton } from './components/LimelightButton.vue'; +export * from './utils/webviewer'; diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..1e422e2 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,63 @@ +import { defineComponent as s, openBlock as c, createElementBlock as d, normalizeClass as f, renderSlot as u } from "vue"; +const p = ["disabled"], k = /* @__PURE__ */ s({ + __name: "LimelightButton", + props: { + variant: {}, + disabled: { type: Boolean } + }, + setup(e) { + return (t, n) => (c(), d("button", { + type: "button", + class: f(["btn", [e.variant && `btn--${e.variant}`, { "btn--disabled": e.disabled }]]), + disabled: e.disabled + }, [ + u(t.$slots, "default", {}, void 0, !0) + ], 10, p)); + } +}), m = (e, t) => { + const n = e.__vccOpts || e; + for (const [i, a] of t) + n[i] = a; + return n; +}, g = /* @__PURE__ */ m(k, [["__scopeId", "data-v-e0bc8f43"]]); +function y(e, t) { + return typeof FileMaker > "u" ? !1 : (FileMaker.PerformScript(e, t), !0); +} +function _(e, t, n) { + return typeof FileMaker > "u" ? !1 : (FileMaker.PerformScriptWithOption(e, t, n), !0); +} +const r = /* @__PURE__ */ new Map(); +let b = 1; +function S(e, t = "", n) { + return new Promise((i, a) => { + if (typeof FileMaker > "u") { + a({ callbackId: -1, message: "FileMaker runtime not available" }); + return; + } + const l = b++; + r.set(l, { resolve: i, reject: a }); + const o = { callbackId: l, parameter: t }; + FileMaker.PerformScript(e, JSON.stringify(o)), n !== void 0 && setTimeout(() => { + r.has(l) && (r.delete(l), a({ callbackId: l, message: `Timed out after ${n}ms` })); + }, n); + }); +} +function h(e, t = "", n) { + const i = parseInt(e), a = r.get(i); + a && (r.delete(i), n ? a.reject({ callbackId: i, message: t }) : a.resolve(t)); +} +function F(e, t, n = 10, i = 0) { + M() ? e() : i >= n ? t == null || t() : setTimeout(() => F(e, t, n, i + 1), 100); +} +function M() { + return typeof FileMaker < "u"; +} +export { + g as LimelightButton, + S as callFileMakerScript, + M as isFileMakerEnvironment, + y as performScript, + _ as performScriptWithOption, + h as resolveFileMakerCallback, + F as waitForFileMaker +}; diff --git a/dist/index.umd.cjs b/dist/index.umd.cjs new file mode 100644 index 0000000..4a624d9 --- /dev/null +++ b/dist/index.umd.cjs @@ -0,0 +1 @@ +(function(n,l){typeof exports=="object"&&typeof module<"u"?l(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],l):(n=typeof globalThis<"u"?globalThis:n||self,l(n.LimelightCommonWebComponents={},n.Vue))})(this,(function(n,l){"use strict";const d=["disabled"],u=((e,t)=>{const i=e.__vccOpts||e;for(const[a,r]of t)i[a]=r;return i})(l.defineComponent({__name:"LimelightButton",props:{variant:{},disabled:{type:Boolean}},setup(e){return(t,i)=>(l.openBlock(),l.createElementBlock("button",{type:"button",class:l.normalizeClass(["btn",[e.variant&&`btn--${e.variant}`,{"btn--disabled":e.disabled}]]),disabled:e.disabled},[l.renderSlot(t.$slots,"default",{},void 0,!0)],10,d))}}),[["__scopeId","data-v-e0bc8f43"]]);function m(e,t){return typeof FileMaker>"u"?!1:(FileMaker.PerformScript(e,t),!0)}function p(e,t,i){return typeof FileMaker>"u"?!1:(FileMaker.PerformScriptWithOption(e,t,i),!0)}const o=new Map;let k=1;function b(e,t="",i){return new Promise((a,r)=>{if(typeof FileMaker>"u"){r({callbackId:-1,message:"FileMaker runtime not available"});return}const c=k++;o.set(c,{resolve:a,reject:r});const M={callbackId:c,parameter:t};FileMaker.PerformScript(e,JSON.stringify(M)),i!==void 0&&setTimeout(()=>{o.has(c)&&(o.delete(c),r({callbackId:c,message:`Timed out after ${i}ms`}))},i)})}function F(e,t="",i){const a=parseInt(e),r=o.get(a);r&&(o.delete(a),i?r.reject({callbackId:a,message:t}):r.resolve(t))}function f(e,t,i=10,a=0){s()?e():a>=i?t==null||t():setTimeout(()=>f(e,t,i,a+1),100)}function s(){return typeof FileMaker<"u"}n.LimelightButton=u,n.callFileMakerScript=b,n.isFileMakerEnvironment=s,n.performScript=m,n.performScriptWithOption=p,n.resolveFileMakerCallback=F,n.waitForFileMaker=f,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})})); diff --git a/dist/utils/webviewer.d.ts b/dist/utils/webviewer.d.ts new file mode 100644 index 0000000..6dec0cf --- /dev/null +++ b/dist/utils/webviewer.d.ts @@ -0,0 +1,106 @@ +/** The FileMaker object injected by the runtime into web viewers. */ +export interface FileMakerAPI { + PerformScript(script: string, parameter?: string): void; + PerformScriptWithOption(script: string, parameter?: string, option?: ScriptOption): void; +} +declare global { + /** Available only inside a FileMaker web viewer. Always guard with `typeof FileMaker !== 'undefined'`. */ + const FileMaker: FileMakerAPI | undefined; + interface Window { + resolveFileMakerCallback: typeof resolveFileMakerCallback; + } +} +/** + * Controls how a currently running FileMaker script is handled when a new + * script is started via `FileMaker.PerformScriptWithOption`. + * + * | Value | Behaviour | + * |-------|------------------------------------------------------------------| + * | "0" | Pause the current script, run the new one, then resume | + * | "1" | Abort the current script and run the new one | + * | "2" | Exit the current script and run the new one | + * | "3" | Run the new script concurrently (default async behaviour) | + * | "4" | Trigger script (same as 3 but fires as a script trigger would) | + * | "5" | Suspend the current script; resume it after the new one exits | + */ +export type ScriptOption = '0' | '1' | '2' | '3' | '4' | '5'; +/** + * Type-safe wrapper that calls `FileMaker.PerformScript` only when the + * runtime is available (i.e. the page is running inside a web viewer). + * + * @returns `true` if the script was dispatched, `false` otherwise. + * + * @example + * performScript("Delete Record", String(recordId)); + */ +export declare function performScript(script: string, parameter?: string): boolean; +/** + * Type-safe wrapper around `FileMaker.PerformScriptWithOption`. + * + * @returns `true` if the script was dispatched, `false` otherwise. + */ +export declare function performScriptWithOption(script: string, parameter?: string, option?: ScriptOption): boolean; +/** Error thrown when a FileMaker script signals failure. */ +export interface FileMakerScriptError { + /** The callback ID that was active when the error occurred. */ + callbackId: number; + /** Optional error message forwarded from the FileMaker script. */ + message?: string; +} +/** + * Invokes a FileMaker script and returns a `Promise` that resolves when + * FileMaker calls back into JavaScript via {@link resolveFileMakerCallback}. + * + * **FileMaker side:** the script must eventually call + * *Perform JavaScript in Web Viewer* targeting `resolveFileMakerCallback` + * and pass back the same `callbackId` together with the result data. + * + * ``` + * // FileMaker script (pseudocode) + * Set Variable [$payload ; Value: Get(ScriptParameter)] + * Set Variable [$id ; Value: JSONGetElement($payload; "callbackId")] + * Set Variable [$result ; Value: \* … your work … *\] + * Perform JavaScript in Web Viewer [ + * Object Name: "MyWebViewer" + * Function: "resolveFileMakerCallback" + * Parameters: $id, $result + * ] + * ``` + * + * @param script - FileMaker script name. + * @param parameter - Arbitrary string payload for the script. + * @param timeout - Optional ms before the promise is rejected automatically + * (defaults to no timeout). + * + * @example + * const json = await callFileMakerScript("Get Customer", String(customerId)); + * const customer = JSON.parse(json); + */ +export declare function callFileMakerScript(script: string, parameter?: string, timeout?: number): Promise; +/** + * Must be exposed as a global function so that FileMaker's + * *Perform JavaScript in Web Viewer* script step can invoke it. + * + * Call this from your FileMaker script to resolve a promise created by + * {@link callFileMakerScript}. + * + * @param callbackId - The numeric ID forwarded from the script parameter. + * @param result - The string result to hand back to JavaScript. + * @param isError - When truthy, the promise is rejected instead. + * + * @example + * // Expose globally so FileMaker can reach it + * (window as any).resolveFileMakerCallback = resolveFileMakerCallback; + */ +export declare function resolveFileMakerCallback(callbackId: string, result?: string, isError?: boolean): void; +export declare function waitForFileMaker(callback: () => void, onError?: () => void, maxAttempts?: number, // 1 Sekunde bei 100ms Intervall +attempt?: number): void; +/** + * Returns `true` when the page is running inside a FileMaker web viewer. + * + * @example + * if (isFileMakerEnvironment()) { + * FileMaker!.PerformScript("On Load"); + * } + */ +export declare function isFileMakerEnvironment(): boolean;