gg-wf-scripts 2.5.0 → 2.8.0
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/README.md +33 -0
- package/dist/action-engine.d.ts +3 -0
- package/dist/action-engine.js +78 -0
- package/dist/action-engine.js.map +1 -0
- package/dist/actions.d.ts +14 -0
- package/dist/actions.js +12 -0
- package/dist/actions.js.map +1 -0
- package/dist/auth.d.ts +6 -0
- package/dist/auth.js +27 -0
- package/dist/auth.js.map +1 -0
- package/dist/bridges.d.ts +1 -0
- package/dist/bridges.js +33 -0
- package/dist/bridges.js.map +1 -0
- package/dist/data-engine.d.ts +3 -0
- package/dist/data-engine.js +158 -0
- package/dist/data-engine.js.map +1 -0
- package/dist/dialog.d.ts +1 -0
- package/dist/dialog.js +89 -0
- package/dist/dialog.js.map +1 -0
- package/dist/form-action-engine.d.ts +3 -0
- package/dist/form-action-engine.js +156 -0
- package/dist/form-action-engine.js.map +1 -0
- package/dist/form-actions.d.ts +22 -0
- package/dist/form-actions.js +15 -0
- package/dist/form-actions.js.map +1 -0
- package/dist/form-visibility.d.ts +1 -0
- package/dist/form-visibility.js +108 -0
- package/dist/form-visibility.js.map +1 -0
- package/dist/helpers/dom.d.ts +16 -0
- package/dist/helpers/dom.js +39 -0
- package/dist/helpers/dom.js.map +1 -0
- package/dist/helpers/path.d.ts +2 -0
- package/dist/helpers/path.js +9 -0
- package/dist/helpers/path.js.map +1 -0
- package/dist/helpers/run-handler.d.ts +22 -0
- package/dist/helpers/run-handler.js +33 -0
- package/dist/helpers/run-handler.js.map +1 -0
- package/dist/helpers/run-with-loading.d.ts +6 -0
- package/dist/helpers/run-with-loading.js +28 -0
- package/dist/helpers/run-with-loading.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/queries.d.ts +10 -0
- package/dist/queries.js +12 -0
- package/dist/queries.js.map +1 -0
- package/dist/query-params.d.ts +19 -0
- package/dist/query-params.js +142 -0
- package/dist/query-params.js.map +1 -0
- package/dist/switch-engine.d.ts +1 -0
- package/dist/switch-engine.js +21 -0
- package/dist/switch-engine.js.map +1 -0
- package/package.json +20 -2
- package/src/action-engine.js +0 -64
- package/src/actions.js +0 -14
- package/src/auth.js +0 -28
- package/src/bridges.js +0 -31
- package/src/data-engine.js +0 -165
- package/src/dialog.js +0 -86
- package/src/form-action-engine.js +0 -149
- package/src/form-actions.js +0 -21
- package/src/form-visibility.js +0 -122
- package/src/helpers/dom.js +0 -35
- package/src/helpers/log.js +0 -34
- package/src/helpers/path.js +0 -4
- package/src/index.js +0 -60
- package/src/queries.js +0 -14
- package/src/query-params.js +0 -144
- package/src/switch-engine.js +0 -22
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { formActionRegistry } from "./form-actions.js";
|
|
2
|
+
import { populateFields } from "./helpers/dom.js";
|
|
3
|
+
import { runHandler } from "./helpers/run-handler.js";
|
|
4
|
+
import { runWithLoading } from "./helpers/run-with-loading.js";
|
|
5
|
+
import { getParams } from "./query-params.js";
|
|
6
|
+
function findInputs(form, name) {
|
|
7
|
+
const escaped = CSS.escape(name);
|
|
8
|
+
return form.querySelectorAll(`input[name="${escaped}"], select[name="${escaped}"], textarea[name="${escaped}"]`);
|
|
9
|
+
}
|
|
10
|
+
function clearFieldError(form, name) {
|
|
11
|
+
findInputs(form, name).forEach((el) => {
|
|
12
|
+
el.removeAttribute("gg-form-field-invalid");
|
|
13
|
+
});
|
|
14
|
+
const escaped = CSS.escape(name);
|
|
15
|
+
form
|
|
16
|
+
.querySelectorAll(`[gg-form-field-error="${escaped}"]`)
|
|
17
|
+
.forEach((el) => {
|
|
18
|
+
el.textContent = "";
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function clearFormErrors(form) {
|
|
22
|
+
form.querySelectorAll("[gg-form-field-invalid]").forEach((el) => {
|
|
23
|
+
el.removeAttribute("gg-form-field-invalid");
|
|
24
|
+
});
|
|
25
|
+
form.querySelectorAll("[gg-form-field-error]").forEach((el) => {
|
|
26
|
+
el.textContent = "";
|
|
27
|
+
});
|
|
28
|
+
form.querySelectorAll("[gg-form-error]").forEach((el) => {
|
|
29
|
+
el.textContent = "";
|
|
30
|
+
});
|
|
31
|
+
form.querySelectorAll("[gg-form-error-list]").forEach((list) => {
|
|
32
|
+
const template = list.querySelector("[gg-list-template]");
|
|
33
|
+
Array.from(list.children).forEach((child) => {
|
|
34
|
+
if (child !== template)
|
|
35
|
+
child.remove();
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function applyFieldErrors(form, fieldErrors) {
|
|
40
|
+
fieldErrors.forEach(({ name, message }) => {
|
|
41
|
+
if (!name)
|
|
42
|
+
return;
|
|
43
|
+
findInputs(form, name).forEach((el) => {
|
|
44
|
+
el.setAttribute("gg-form-field-invalid", "true");
|
|
45
|
+
});
|
|
46
|
+
const escaped = CSS.escape(name);
|
|
47
|
+
form
|
|
48
|
+
.querySelectorAll(`[gg-form-field-error="${escaped}"]`)
|
|
49
|
+
.forEach((el) => {
|
|
50
|
+
el.textContent = message ?? "";
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function applyErrorList(form, fieldErrors) {
|
|
55
|
+
form.querySelectorAll("[gg-form-error-list]").forEach((list) => {
|
|
56
|
+
const template = list.querySelector("[gg-list-template]");
|
|
57
|
+
if (!template) {
|
|
58
|
+
console.warn("[gg-form-error-list] no [gg-list-template] inside list:", list);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
fieldErrors.forEach((record) => {
|
|
62
|
+
const clone = template.cloneNode(true);
|
|
63
|
+
clone.removeAttribute("gg-list-template");
|
|
64
|
+
clone.style.display = "";
|
|
65
|
+
populateFields(clone, record);
|
|
66
|
+
list.appendChild(clone);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function applyFormError(form, error) {
|
|
71
|
+
if (error == null)
|
|
72
|
+
return;
|
|
73
|
+
const message = typeof error === "string" ? error : String(error);
|
|
74
|
+
form.querySelectorAll("[gg-form-error]").forEach((el) => {
|
|
75
|
+
el.textContent = message;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function bindFieldClearOnInput(form) {
|
|
79
|
+
if (form.__ggFormErrorBound)
|
|
80
|
+
return;
|
|
81
|
+
form.__ggFormErrorBound = true;
|
|
82
|
+
form.addEventListener("input", (e) => {
|
|
83
|
+
const target = e.target;
|
|
84
|
+
if (!(target instanceof Element))
|
|
85
|
+
return;
|
|
86
|
+
const name = target.getAttribute("name");
|
|
87
|
+
if (!name)
|
|
88
|
+
return;
|
|
89
|
+
if (target.hasAttribute("gg-form-field-invalid")) {
|
|
90
|
+
clearFieldError(form, name);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
export function initFormActionEngine(context, { debug = false } = {}) {
|
|
95
|
+
async function handleSubmit(form, event) {
|
|
96
|
+
const id = form.getAttribute("gg-form-action");
|
|
97
|
+
if (!id)
|
|
98
|
+
return;
|
|
99
|
+
const action = formActionRegistry[id];
|
|
100
|
+
if (!action) {
|
|
101
|
+
console.warn(`[gg-form-action] no form action registered for "${id}"`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
event.preventDefault();
|
|
105
|
+
if (form.hasAttribute("gg-loading"))
|
|
106
|
+
return;
|
|
107
|
+
if (form.hasAttribute("gg-confirm")) {
|
|
108
|
+
const text = form.getAttribute("gg-confirm-text") || "Are you sure?";
|
|
109
|
+
if (!window.confirm(text))
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
clearFormErrors(form);
|
|
113
|
+
const formData = new FormData(form);
|
|
114
|
+
const params = getParams();
|
|
115
|
+
const submitControls = form.querySelectorAll('button[type="submit"], button:not([type]), input[type="submit"]');
|
|
116
|
+
const handlerResult = await runWithLoading([form, ...submitControls], () => runHandler({
|
|
117
|
+
prefix: "[gg-form-action]",
|
|
118
|
+
id,
|
|
119
|
+
fields: {
|
|
120
|
+
form,
|
|
121
|
+
formData: Object.fromEntries(formData),
|
|
122
|
+
params: Object.fromEntries(params),
|
|
123
|
+
},
|
|
124
|
+
debug,
|
|
125
|
+
}, () => action(context, formData, params)));
|
|
126
|
+
if (!handlerResult.ok) {
|
|
127
|
+
applyFormError(form, "Something went wrong. Please try again.");
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const result = handlerResult.value;
|
|
131
|
+
if (result && result.ok === false) {
|
|
132
|
+
const failure = result;
|
|
133
|
+
const fieldErrors = Array.isArray(failure.field_errors)
|
|
134
|
+
? failure.field_errors
|
|
135
|
+
: [];
|
|
136
|
+
applyFieldErrors(form, fieldErrors);
|
|
137
|
+
applyErrorList(form, fieldErrors);
|
|
138
|
+
applyFormError(form, failure.error);
|
|
139
|
+
if (!fieldErrors.length && failure.error == null) {
|
|
140
|
+
console.warn(`[gg-form-action] "${id}" returned ok:false with no error or field_errors`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
document
|
|
145
|
+
.querySelectorAll("form[gg-form-action]")
|
|
146
|
+
.forEach(bindFieldClearOnInput);
|
|
147
|
+
document.addEventListener("submit", (e) => {
|
|
148
|
+
const form = e.target;
|
|
149
|
+
if (form instanceof HTMLFormElement &&
|
|
150
|
+
form.hasAttribute("gg-form-action")) {
|
|
151
|
+
bindFieldClearOnInput(form);
|
|
152
|
+
handleSubmit(form, e);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=form-action-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-action-engine.js","sourceRoot":"","sources":["../src/form-action-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type FormFieldError = {
|
|
2
|
+
name: string;
|
|
3
|
+
message: string;
|
|
4
|
+
};
|
|
5
|
+
export type FormActionResult = {
|
|
6
|
+
ok: boolean;
|
|
7
|
+
error?: unknown;
|
|
8
|
+
field_errors?: FormFieldError[];
|
|
9
|
+
};
|
|
10
|
+
export type FormAction = (context: unknown, formData: FormData, params: URLSearchParams) => Promise<FormActionResult | void> | FormActionResult | void;
|
|
11
|
+
export declare const formActionRegistry: Record<string, FormAction>;
|
|
12
|
+
/**
|
|
13
|
+
* Register a form action triggered by submitting a form with gg-form-action="<id>".
|
|
14
|
+
*
|
|
15
|
+
* Receives the context object passed to init(), a FormData snapshot of the submitted form,
|
|
16
|
+
* and a URLSearchParams snapshot of the current URL query string. Return:
|
|
17
|
+
* - { ok: true } on success
|
|
18
|
+
* - { ok: false, field_errors: [{ name, message }, ...] } for validation errors
|
|
19
|
+
* - { ok: false, error: "..." } for a single form-level error
|
|
20
|
+
* - Both field_errors and error may be present together.
|
|
21
|
+
*/
|
|
22
|
+
export declare function registerFormAction(id: string, fn: FormAction): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const formActionRegistry = {};
|
|
2
|
+
/**
|
|
3
|
+
* Register a form action triggered by submitting a form with gg-form-action="<id>".
|
|
4
|
+
*
|
|
5
|
+
* Receives the context object passed to init(), a FormData snapshot of the submitted form,
|
|
6
|
+
* and a URLSearchParams snapshot of the current URL query string. Return:
|
|
7
|
+
* - { ok: true } on success
|
|
8
|
+
* - { ok: false, field_errors: [{ name, message }, ...] } for validation errors
|
|
9
|
+
* - { ok: false, error: "..." } for a single form-level error
|
|
10
|
+
* - Both field_errors and error may be present together.
|
|
11
|
+
*/
|
|
12
|
+
export function registerFormAction(id, fn) {
|
|
13
|
+
formActionRegistry[id] = fn;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=form-actions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-actions.js","sourceRoot":"","sources":["../src/form-actions.ts"],"names":[],"mappings":"AAcA,MAAM,CAAC,MAAM,kBAAkB,GAA+B,EAAE,CAAC;AAEjE;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,EAAU,EAAE,EAAc;IAC3D,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function initFormVisibility(): void;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const TRANSITION_MS = 200;
|
|
2
|
+
function parseConditions(attr) {
|
|
3
|
+
return attr
|
|
4
|
+
.split(",")
|
|
5
|
+
.map((pair) => {
|
|
6
|
+
const [name, value] = pair.split(":");
|
|
7
|
+
return { name: name?.trim() ?? "", value: value?.trim() ?? "" };
|
|
8
|
+
})
|
|
9
|
+
.filter((p) => p.name && p.value);
|
|
10
|
+
}
|
|
11
|
+
function getFieldValue(scope, name) {
|
|
12
|
+
const escaped = CSS.escape(name);
|
|
13
|
+
const inputs = scope.querySelectorAll(`input[name="${escaped}"], select[name="${escaped}"], textarea[name="${escaped}"]`);
|
|
14
|
+
if (!inputs.length)
|
|
15
|
+
return null;
|
|
16
|
+
const first = inputs[0];
|
|
17
|
+
const type = (first.getAttribute("type") || "").toLowerCase();
|
|
18
|
+
if (type === "radio" || type === "checkbox") {
|
|
19
|
+
for (const input of inputs) {
|
|
20
|
+
if (input instanceof HTMLInputElement && input.checked)
|
|
21
|
+
return input.value;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return first.value.trim();
|
|
26
|
+
}
|
|
27
|
+
function matchesAny(scope, conditions) {
|
|
28
|
+
return conditions.some(({ name, value }) => getFieldValue(scope, name) === value);
|
|
29
|
+
}
|
|
30
|
+
export function initFormVisibility() {
|
|
31
|
+
// Group all [gg-visible-when] elements by their nearest scope —
|
|
32
|
+
// either an explicit [gg-form-scope] or a <form>.
|
|
33
|
+
const scopeTargets = new Map();
|
|
34
|
+
document.querySelectorAll("[gg-visible-when]").forEach((el) => {
|
|
35
|
+
if (!Boolean(el.getAttribute("gg-visible-when"))) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const scope = el.closest("[gg-form-scope], form");
|
|
39
|
+
if (!scope) {
|
|
40
|
+
console.warn("[gg-visible-when] element is not inside a <form> or [gg-form-scope]:", el);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (!scopeTargets.has(scope))
|
|
44
|
+
scopeTargets.set(scope, []);
|
|
45
|
+
scopeTargets.get(scope).push(el);
|
|
46
|
+
});
|
|
47
|
+
scopeTargets.forEach((targets, scope) => {
|
|
48
|
+
const conditions = new WeakMap();
|
|
49
|
+
const lastState = new WeakMap();
|
|
50
|
+
const hideTimers = new WeakMap();
|
|
51
|
+
targets.forEach((el) => {
|
|
52
|
+
conditions.set(el, parseConditions(el.getAttribute("gg-visible-when") ?? ""));
|
|
53
|
+
el.style.transition = "none";
|
|
54
|
+
el.style.opacity = "0";
|
|
55
|
+
el.style.display = "none";
|
|
56
|
+
el.style.pointerEvents = "none";
|
|
57
|
+
el.setAttribute("inert", "");
|
|
58
|
+
el.setAttribute("aria-hidden", "true");
|
|
59
|
+
lastState.set(el, false);
|
|
60
|
+
});
|
|
61
|
+
function show(el) {
|
|
62
|
+
const pending = hideTimers.get(el);
|
|
63
|
+
if (pending) {
|
|
64
|
+
clearTimeout(pending);
|
|
65
|
+
hideTimers.delete(el);
|
|
66
|
+
}
|
|
67
|
+
el.removeAttribute("inert");
|
|
68
|
+
el.removeAttribute("aria-hidden");
|
|
69
|
+
el.style.display = "";
|
|
70
|
+
el.style.pointerEvents = "";
|
|
71
|
+
requestAnimationFrame(() => {
|
|
72
|
+
el.style.opacity = "1";
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function hide(el) {
|
|
76
|
+
el.style.opacity = "0";
|
|
77
|
+
el.style.pointerEvents = "none";
|
|
78
|
+
el.setAttribute("inert", "");
|
|
79
|
+
el.setAttribute("aria-hidden", "true");
|
|
80
|
+
const t = setTimeout(() => {
|
|
81
|
+
el.style.display = "none";
|
|
82
|
+
hideTimers.delete(el);
|
|
83
|
+
}, TRANSITION_MS);
|
|
84
|
+
hideTimers.set(el, t);
|
|
85
|
+
}
|
|
86
|
+
function evaluate() {
|
|
87
|
+
targets.forEach((el) => {
|
|
88
|
+
const shouldShow = matchesAny(scope, conditions.get(el) ?? []);
|
|
89
|
+
if (shouldShow === lastState.get(el))
|
|
90
|
+
return;
|
|
91
|
+
lastState.set(el, shouldShow);
|
|
92
|
+
if (shouldShow)
|
|
93
|
+
show(el);
|
|
94
|
+
else
|
|
95
|
+
hide(el);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
requestAnimationFrame(() => {
|
|
99
|
+
targets.forEach((el) => {
|
|
100
|
+
el.style.transition = `opacity ${TRANSITION_MS}ms ease`;
|
|
101
|
+
});
|
|
102
|
+
evaluate();
|
|
103
|
+
});
|
|
104
|
+
scope.addEventListener("change", evaluate);
|
|
105
|
+
scope.addEventListener("input", evaluate);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=form-visibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-visibility.js","sourceRoot":"","sources":["../src/form-visibility.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Set textContent on every [gg-field] descendant of `root` to the value
|
|
3
|
+
* at that field's dot-path on `record`. Null / missing values are left
|
|
4
|
+
* as-is (keeps whatever the markup's default content was).
|
|
5
|
+
*/
|
|
6
|
+
export declare function populateFields(root: Element, record: unknown): void;
|
|
7
|
+
/**
|
|
8
|
+
* Write a normalized switch state onto an element.
|
|
9
|
+
* null / undefined become "" so gg-case="" can serve as the empty/default.
|
|
10
|
+
*/
|
|
11
|
+
export declare function setSwitchState(el: Element, value: unknown): void;
|
|
12
|
+
/**
|
|
13
|
+
* Show the [gg-case] child whose value matches the container's current
|
|
14
|
+
* gg-switch-state; hide the rest with display:none.
|
|
15
|
+
*/
|
|
16
|
+
export declare function applySwitchState(container: Element): void;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { getPath } from "./path.js";
|
|
2
|
+
/**
|
|
3
|
+
* Set textContent on every [gg-field] descendant of `root` to the value
|
|
4
|
+
* at that field's dot-path on `record`. Null / missing values are left
|
|
5
|
+
* as-is (keeps whatever the markup's default content was).
|
|
6
|
+
*/
|
|
7
|
+
export function populateFields(root, record) {
|
|
8
|
+
root.querySelectorAll("[gg-field]").forEach((el) => {
|
|
9
|
+
const path = el.getAttribute("gg-field");
|
|
10
|
+
if (!path)
|
|
11
|
+
return;
|
|
12
|
+
const value = getPath(record, path);
|
|
13
|
+
if (value != null)
|
|
14
|
+
el.textContent = String(value);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Write a normalized switch state onto an element.
|
|
19
|
+
* null / undefined become "" so gg-case="" can serve as the empty/default.
|
|
20
|
+
*/
|
|
21
|
+
export function setSwitchState(el, value) {
|
|
22
|
+
el.setAttribute("gg-switch-state", value == null ? "" : String(value));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Show the [gg-case] child whose value matches the container's current
|
|
26
|
+
* gg-switch-state; hide the rest with display:none.
|
|
27
|
+
*/
|
|
28
|
+
export function applySwitchState(container) {
|
|
29
|
+
const state = container.getAttribute("gg-switch-state") ?? "";
|
|
30
|
+
Array.from(container.children).forEach((child) => {
|
|
31
|
+
if (!(child instanceof HTMLElement))
|
|
32
|
+
return;
|
|
33
|
+
if (!child.hasAttribute("gg-case"))
|
|
34
|
+
return;
|
|
35
|
+
const match = child.getAttribute("gg-case") === state;
|
|
36
|
+
child.style.display = match ? "" : "none";
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=dom.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom.js","sourceRoot":"","sources":["../../src/helpers/dom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAa,EAAE,MAAe;IAC3D,IAAI,CAAC,gBAAgB,CAAc,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE;QAC9D,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK,IAAI,IAAI;YAAE,EAAE,CAAC,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,EAAW,EAAE,KAAc;IACxD,EAAE,CAAC,YAAY,CAAC,iBAAiB,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AACzE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAkB;IACjD,MAAM,KAAK,GAAG,SAAS,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC;IAC9D,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC/C,IAAI,CAAC,CAAC,KAAK,YAAY,WAAW,CAAC;YAAE,OAAO;QAC5C,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC;YAAE,OAAO;QAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,KAAK,KAAK,CAAC;QACtD,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Resolve a dot-path on an object, e.g. getPath(row, "school.name"). */
|
|
2
|
+
export function getPath(obj, path) {
|
|
3
|
+
return path.split(".").reduce((acc, key) => {
|
|
4
|
+
if (acc == null)
|
|
5
|
+
return undefined;
|
|
6
|
+
return acc[key];
|
|
7
|
+
}, obj);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.js","sourceRoot":"","sources":["../../src/helpers/path.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,MAAM,UAAU,OAAO,CAAC,GAAY,EAAE,IAAY;IAChD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAU,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAClD,IAAI,GAAG,IAAI,IAAI;YAAE,OAAO,SAAS,CAAC;QAClC,OAAQ,GAA+B,CAAC,GAAG,CAAC,CAAC;IAC/C,CAAC,EAAE,GAAG,CAAC,CAAC;AACV,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type RunHandlerOptions = {
|
|
2
|
+
prefix: string;
|
|
3
|
+
id: string;
|
|
4
|
+
fields: Record<string, unknown>;
|
|
5
|
+
debug: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type RunHandlerResult<T> = {
|
|
8
|
+
ok: true;
|
|
9
|
+
value: T;
|
|
10
|
+
} | {
|
|
11
|
+
ok: false;
|
|
12
|
+
error: unknown;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Run a registered handler with debug logging and errors-as-values.
|
|
16
|
+
*
|
|
17
|
+
* Catches throws so engine code can branch on a result instead of try/catch.
|
|
18
|
+
* On success, returns { ok: true, value } where value is whatever the handler
|
|
19
|
+
* returned. On throw, returns { ok: false, error } and logs the error.
|
|
20
|
+
*/
|
|
21
|
+
export declare function runHandler<T>({ prefix, id, fields, debug }: RunHandlerOptions, fn: () => Promise<T> | T): Promise<RunHandlerResult<T>>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run a registered handler with debug logging and errors-as-values.
|
|
3
|
+
*
|
|
4
|
+
* Catches throws so engine code can branch on a result instead of try/catch.
|
|
5
|
+
* On success, returns { ok: true, value } where value is whatever the handler
|
|
6
|
+
* returned. On throw, returns { ok: false, error } and logs the error.
|
|
7
|
+
*/
|
|
8
|
+
export async function runHandler({ prefix, id, fields, debug }, fn) {
|
|
9
|
+
if (debug) {
|
|
10
|
+
console.groupCollapsed(`${prefix} "${id}"`);
|
|
11
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
12
|
+
console.log(`${key}:`, value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const startedAt = debug ? performance.now() : 0;
|
|
16
|
+
try {
|
|
17
|
+
const value = await fn();
|
|
18
|
+
if (debug) {
|
|
19
|
+
const ms = (performance.now() - startedAt).toFixed(1);
|
|
20
|
+
console.log(`result (${ms}ms):`, value);
|
|
21
|
+
}
|
|
22
|
+
return { ok: true, value };
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
console.error(`${prefix} "${id}" threw:`, error);
|
|
26
|
+
return { ok: false, error };
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
if (debug)
|
|
30
|
+
console.groupEnd();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=run-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-handler.js","sourceRoot":"","sources":["../../src/helpers/run-handler.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAqB,EAChD,EAAwB;IAExB,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,CAAC,cAAc,CAAC,GAAG,MAAM,KAAK,EAAE,GAAG,CAAC,CAAC;QAC5C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,EAAE,KAAK,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IACD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,EAAE,EAAE,CAAC;QACzB,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,EAAE,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACtD,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QACjD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;YAAS,CAAC;QACT,IAAI,KAAK;YAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;IAChC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Set gg-loading="true" on each element while fn runs, clearing it (in a
|
|
3
|
+
* finally block) when fn resolves or throws. Form controls (button, input)
|
|
4
|
+
* also get native `disabled` toggled.
|
|
5
|
+
*/
|
|
6
|
+
export declare function runWithLoading<T>(elements: Iterable<Element>, fn: () => Promise<T> | T): Promise<T>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Set gg-loading="true" on each element while fn runs, clearing it (in a
|
|
3
|
+
* finally block) when fn resolves or throws. Form controls (button, input)
|
|
4
|
+
* also get native `disabled` toggled.
|
|
5
|
+
*/
|
|
6
|
+
export async function runWithLoading(elements, fn) {
|
|
7
|
+
const targets = [...elements];
|
|
8
|
+
targets.forEach(applyLoading);
|
|
9
|
+
try {
|
|
10
|
+
return await fn();
|
|
11
|
+
}
|
|
12
|
+
finally {
|
|
13
|
+
targets.forEach(clearLoading);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function applyLoading(el) {
|
|
17
|
+
el.setAttribute("gg-loading", "true");
|
|
18
|
+
if (el instanceof HTMLButtonElement || el instanceof HTMLInputElement) {
|
|
19
|
+
el.disabled = true;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function clearLoading(el) {
|
|
23
|
+
el.removeAttribute("gg-loading");
|
|
24
|
+
if (el instanceof HTMLButtonElement || el instanceof HTMLInputElement) {
|
|
25
|
+
el.disabled = false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=run-with-loading.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-with-loading.js","sourceRoot":"","sources":["../../src/helpers/run-with-loading.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAA2B,EAC3B,EAAwB;IAExB,MAAM,OAAO,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC;IAC9B,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9B,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAChC,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,EAAW;IAC/B,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACtC,IAAI,EAAE,YAAY,iBAAiB,IAAI,EAAE,YAAY,gBAAgB,EAAE,CAAC;QACtE,EAAE,CAAC,QAAQ,GAAG,IAAI,CAAC;IACrB,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,EAAW;IAC/B,EAAE,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;IACjC,IAAI,EAAE,YAAY,iBAAiB,IAAI,EAAE,YAAY,gBAAgB,EAAE,CAAC;QACtE,EAAE,CAAC,QAAQ,GAAG,KAAK,CAAC;IACtB,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { registerQuery } from "./queries.js";
|
|
2
|
+
import { registerAction } from "./actions.js";
|
|
3
|
+
import { registerFormAction } from "./form-actions.js";
|
|
4
|
+
import { setSwitchState, applySwitchState, populateFields } from "./helpers/dom.js";
|
|
5
|
+
import { setQueryParams, removeQueryParams } from "./query-params.js";
|
|
6
|
+
import { type AuthAdapter } from "./auth.js";
|
|
7
|
+
export { setSwitchState, applySwitchState, populateFields, setQueryParams, removeQueryParams };
|
|
8
|
+
export { getPath } from "./helpers/path.js";
|
|
9
|
+
export type { AuthAdapter } from "./auth.js";
|
|
10
|
+
export type { Query } from "./queries.js";
|
|
11
|
+
export type { Action, ActionResult } from "./actions.js";
|
|
12
|
+
export type { FormAction, FormActionResult, FormFieldError } from "./form-actions.js";
|
|
13
|
+
export type InitOptions = {
|
|
14
|
+
/**
|
|
15
|
+
* Arbitrary object passed to every query and action. Put backend clients
|
|
16
|
+
* (Supabase, fetch wrappers, etc.) or anything else your queries need on it.
|
|
17
|
+
*/
|
|
18
|
+
context?: unknown;
|
|
19
|
+
/**
|
|
20
|
+
* Auth adapter. If omitted, gg-auth/gg-role attrs are never set.
|
|
21
|
+
*/
|
|
22
|
+
auth?: AuthAdapter;
|
|
23
|
+
/**
|
|
24
|
+
* When true, every query and action is logged to the console with its
|
|
25
|
+
* trigger/container, data, result, and duration.
|
|
26
|
+
*/
|
|
27
|
+
debug?: boolean;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Create a gg-scripts app instance.
|
|
31
|
+
*/
|
|
32
|
+
export declare function init({ context, auth, debug }?: InitOptions): {
|
|
33
|
+
addQuery: typeof registerQuery;
|
|
34
|
+
addAction: typeof registerAction;
|
|
35
|
+
addFormAction: typeof registerFormAction;
|
|
36
|
+
start(): void;
|
|
37
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { registerQuery } from "./queries.js";
|
|
2
|
+
import { registerAction } from "./actions.js";
|
|
3
|
+
import { registerFormAction } from "./form-actions.js";
|
|
4
|
+
import { setSwitchState, applySwitchState, populateFields } from "./helpers/dom.js";
|
|
5
|
+
import { setQueryParams, removeQueryParams, initQueryParams } from "./query-params.js";
|
|
6
|
+
import { initAuth } from "./auth.js";
|
|
7
|
+
import { initSwitchEngine } from "./switch-engine.js";
|
|
8
|
+
import { initDialog } from "./dialog.js";
|
|
9
|
+
import { initBridges } from "./bridges.js";
|
|
10
|
+
import { initFormVisibility } from "./form-visibility.js";
|
|
11
|
+
import { initDataEngine } from "./data-engine.js";
|
|
12
|
+
import { initActionEngine } from "./action-engine.js";
|
|
13
|
+
import { initFormActionEngine } from "./form-action-engine.js";
|
|
14
|
+
export { setSwitchState, applySwitchState, populateFields, setQueryParams, removeQueryParams };
|
|
15
|
+
export { getPath } from "./helpers/path.js";
|
|
16
|
+
/**
|
|
17
|
+
* Create a gg-scripts app instance.
|
|
18
|
+
*/
|
|
19
|
+
export function init({ context = {}, auth, debug = false } = {}) {
|
|
20
|
+
return {
|
|
21
|
+
addQuery: registerQuery,
|
|
22
|
+
addAction: registerAction,
|
|
23
|
+
addFormAction: registerFormAction,
|
|
24
|
+
start() {
|
|
25
|
+
function run() {
|
|
26
|
+
if (auth)
|
|
27
|
+
initAuth(context, auth);
|
|
28
|
+
initSwitchEngine();
|
|
29
|
+
initQueryParams();
|
|
30
|
+
initDialog();
|
|
31
|
+
initBridges();
|
|
32
|
+
initFormVisibility();
|
|
33
|
+
initDataEngine(context, { debug });
|
|
34
|
+
initActionEngine(context, { debug });
|
|
35
|
+
initFormActionEngine(context, { debug });
|
|
36
|
+
}
|
|
37
|
+
if (document.readyState === "loading") {
|
|
38
|
+
document.addEventListener("DOMContentLoaded", run);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
run();
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAoB,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC;AAC/F,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAuB5C;;GAEG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,OAAO,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,GAAG,KAAK,KAAkB,EAAE;IAC1E,OAAO;QACL,QAAQ,EAAE,aAAa;QACvB,SAAS,EAAE,cAAc;QACzB,aAAa,EAAE,kBAAkB;QACjC,KAAK;YACH,SAAS,GAAG;gBACV,IAAI,IAAI;oBAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gBAClC,gBAAgB,EAAE,CAAC;gBACnB,eAAe,EAAE,CAAC;gBAClB,UAAU,EAAE,CAAC;gBACb,WAAW,EAAE,CAAC;gBACd,kBAAkB,EAAE,CAAC;gBACrB,cAAc,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;gBACnC,gBAAgB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;gBACrC,oBAAoB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YAC3C,CAAC;YAED,IAAI,QAAQ,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBACtC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;YACrD,CAAC;iBAAM,CAAC;gBACN,GAAG,EAAE,CAAC;YACR,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type Query = (context: unknown, params: URLSearchParams) => Promise<unknown> | unknown;
|
|
2
|
+
export declare const queryRegistry: Record<string, Query>;
|
|
3
|
+
/**
|
|
4
|
+
* Register a data query for use with gg-data, gg-data-form, or gg-data-list.
|
|
5
|
+
*
|
|
6
|
+
* Receives the context object passed to init() and a URLSearchParams snapshot of the
|
|
7
|
+
* current URL query string. Return a single object (or null) for gg-data/gg-data-form,
|
|
8
|
+
* or an array for gg-data-list.
|
|
9
|
+
*/
|
|
10
|
+
export declare function registerQuery(id: string, fn: Query): void;
|
package/dist/queries.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const queryRegistry = {};
|
|
2
|
+
/**
|
|
3
|
+
* Register a data query for use with gg-data, gg-data-form, or gg-data-list.
|
|
4
|
+
*
|
|
5
|
+
* Receives the context object passed to init() and a URLSearchParams snapshot of the
|
|
6
|
+
* current URL query string. Return a single object (or null) for gg-data/gg-data-form,
|
|
7
|
+
* or an array for gg-data-list.
|
|
8
|
+
*/
|
|
9
|
+
export function registerQuery(id, fn) {
|
|
10
|
+
queryRegistry[id] = fn;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,aAAa,GAA0B,EAAE,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,EAAU,EAAE,EAAS;IACjD,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC;AACzB,CAAC"}
|