@lattice-php/lattice 0.33.0 → 0.35.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/dist/appearance/index.js +2 -6
- package/dist/appearance/index.js.map +1 -1
- package/dist/chat/lib/transport.d.ts +2 -2
- package/dist/chat/lib/transport.js +22 -23
- package/dist/chat/lib/transport.js.map +1 -1
- package/dist/core/api.d.ts +0 -1
- package/dist/core/api.js +2 -2
- package/dist/core/api.js.map +1 -1
- package/dist/core/hooks/column-sizing.d.ts +1 -1
- package/dist/core/hooks/column-sizing.js +7 -14
- package/dist/core/hooks/column-sizing.js.map +1 -1
- package/dist/core/hooks/use-column-resizing.js +22 -54
- package/dist/core/hooks/use-column-resizing.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +2 -2
- package/dist/core/registry.d.ts +1 -5
- package/dist/core/registry.js +1 -2
- package/dist/core/registry.js.map +1 -1
- package/dist/core/renderer.js +4 -10
- package/dist/core/renderer.js.map +1 -1
- package/dist/effects/registry.js +1 -4
- package/dist/effects/registry.js.map +1 -1
- package/dist/event-bridge.d.ts +1 -4
- package/dist/event-bridge.js +1 -11
- package/dist/event-bridge.js.map +1 -1
- package/dist/form/components/fields/choice.js +1 -1
- package/dist/form/components/fields/choice.js.map +1 -1
- package/dist/form/types.d.ts +1 -4
- package/dist/i18n/config.d.ts +1 -1
- package/dist/i18n/config.js +5 -21
- package/dist/i18n/config.js.map +1 -1
- package/dist/i18n/index.d.ts +2 -2
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/locale-switcher.d.ts +0 -5
- package/dist/i18n/locale-switcher.js +1 -5
- package/dist/i18n/locale-switcher.js.map +1 -1
- package/dist/i18n/locale.js +2 -10
- package/dist/i18n/locale.js.map +1 -1
- package/dist/i18n/timezone.js +2 -10
- package/dist/i18n/timezone.js.map +1 -1
- package/dist/icons/icon-renderer.d.ts +1 -2
- package/dist/icons/icon-renderer.js +2 -6
- package/dist/icons/icon-renderer.js.map +1 -1
- package/dist/lattice.css +89 -0
- package/dist/lib/listeners.d.ts +5 -0
- package/dist/lib/listeners.js +19 -0
- package/dist/lib/listeners.js.map +1 -0
- package/dist/table/hooks/use-column-visibility.js +4 -12
- package/dist/table/hooks/use-column-visibility.js.map +1 -1
- package/dist/toast/callout.js +8 -16
- package/dist/toast/callout.js.map +1 -1
- package/dist/toast/toast.d.ts +2 -0
- package/dist/toast/toast.js +16 -10
- package/dist/toast/toast.js.map +1 -1
- package/dist/types/generated.d.ts +3 -1
- package/dist/ui/grid.js +17 -5
- package/dist/ui/grid.js.map +1 -1
- package/dist/ui/segmented-pills.d.ts +1 -1
- package/dist/ui/segmented-pills.js +1 -1
- package/dist/ui/segmented-pills.js.map +1 -1
- package/dist-standalone/chunks/{chart-view-WqyMTZiX.js → chart-view-CR1X2aGE.js} +1 -1
- package/dist-standalone/chunks/{date-picker-field-CCnkf4SC.js → date-picker-field-B4Xzow-A.js} +1 -1
- package/dist-standalone/chunks/{dist-CK9gk4iB.js → dist-ci5ng714.js} +1 -1
- package/dist-standalone/chunks/{icon-button-D4DKcnhp.js → icon-button-D3AltHNz.js} +1 -1
- package/dist-standalone/chunks/{instance-BQeVkUpw.js → instance-C4O1XWa6.js} +1 -1
- package/dist-standalone/chunks/locale-GyqtaX1O.js +1 -0
- package/dist-standalone/chunks/{page-props-BA5zqTIT.js → page-props-BHNNVkgJ.js} +1 -1
- package/dist-standalone/chunks/{rich-editor-field-BeeSr2Zx.js → rich-editor-field-JM3jBEV1.js} +1 -1
- package/dist-standalone/chunks/{subscriptions-Cwd1jFs5.js → subscriptions-BV4g0s0U.js} +1 -1
- package/dist-standalone/chunks/{time-picker-DSs9fDWe.js → time-picker-kbhOHEPd.js} +1 -1
- package/dist-standalone/chunks/timezone-CyoBch3a.js +1 -0
- package/dist-standalone/chunks/{use-effect-dispatcher-CiWYRvsF.js → use-effect-dispatcher-CJXFkAv1.js} +2 -2
- package/dist-standalone/lattice.css +1 -1
- package/dist-standalone/lattice.js +4 -4
- package/dist-standalone/manifest.json +1 -27
- package/package.json +2 -2
- package/dist-standalone/chunks/locale-CgtcxthU.js +0 -1
- package/dist-standalone/chunks/timezone-BORzyZp2.js +0 -1
package/dist/appearance/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createListeners } from "../lib/listeners.js";
|
|
1
2
|
import { useSyncExternalStore } from "react";
|
|
2
3
|
//#region resources/js/appearance/index.ts
|
|
3
4
|
var appearances = [
|
|
@@ -5,7 +6,7 @@ var appearances = [
|
|
|
5
6
|
"dark",
|
|
6
7
|
"system"
|
|
7
8
|
];
|
|
8
|
-
var
|
|
9
|
+
var { subscribe, notify } = createListeners();
|
|
9
10
|
var currentAppearance = "system";
|
|
10
11
|
var serverAppearance = "system";
|
|
11
12
|
/**
|
|
@@ -43,11 +44,6 @@ var applyAppearance = (appearance) => {
|
|
|
43
44
|
document.documentElement.classList.toggle("dark", isDark);
|
|
44
45
|
document.documentElement.style.colorScheme = isDark ? "dark" : "light";
|
|
45
46
|
};
|
|
46
|
-
var subscribe = (callback) => {
|
|
47
|
-
listeners.add(callback);
|
|
48
|
-
return () => listeners.delete(callback);
|
|
49
|
-
};
|
|
50
|
-
var notify = () => listeners.forEach((listener) => listener());
|
|
51
47
|
var mediaQuery = () => {
|
|
52
48
|
if (typeof window === "undefined") return null;
|
|
53
49
|
return window.matchMedia("(prefers-color-scheme: dark)");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../resources/js/appearance/index.ts"],"sourcesContent":["import { useSyncExternalStore } from \"react\";\n\nconst appearances = [\"light\", \"dark\", \"system\"] as const;\n\nexport type Appearance = (typeof appearances)[number];\n\nexport type ResolvedAppearance = \"light\" | \"dark\";\n\nexport type UseAppearanceReturn = {\n readonly appearance: Appearance;\n readonly resolvedAppearance: ResolvedAppearance;\n readonly updateAppearance: (mode: Appearance) => void;\n};\n\nconst
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../resources/js/appearance/index.ts"],"sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport { createListeners } from \"@lattice-php/lattice/lib/listeners\";\n\nconst appearances = [\"light\", \"dark\", \"system\"] as const;\n\nexport type Appearance = (typeof appearances)[number];\n\nexport type ResolvedAppearance = \"light\" | \"dark\";\n\nexport type UseAppearanceReturn = {\n readonly appearance: Appearance;\n readonly resolvedAppearance: ResolvedAppearance;\n readonly updateAppearance: (mode: Appearance) => void;\n};\n\nconst { subscribe, notify } = createListeners();\nlet currentAppearance: Appearance = \"system\";\nlet serverAppearance: Appearance = \"system\";\n\n/**\n * Seed the SSR/hydration snapshot from the backend-shared `lattice.appearance`\n * prop. The server render and the client's hydration pass must read the same\n * value, or components branching on the appearance mismatch on hydration.\n */\nexport function seedAppearance(value: unknown): void {\n if (isAppearance(value)) {\n serverAppearance = value;\n }\n}\n\nexport function isAppearance(value: unknown): value is Appearance {\n return appearances.some((appearance) => appearance === value);\n}\n\nconst prefersDark = (): boolean => {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n};\n\nconst setCookie = (name: string, value: string, days = 365): void => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const maxAge = days * 24 * 60 * 60;\n document.cookie = `${name}=${value};path=/;max-age=${maxAge};SameSite=Lax`;\n};\n\nconst getStoredAppearance = (): Appearance => {\n if (typeof window === \"undefined\") {\n return \"system\";\n }\n\n const stored = localStorage.getItem(\"appearance\");\n\n return isAppearance(stored) ? stored : \"system\";\n};\n\nconst isDarkMode = (appearance: Appearance): boolean => {\n return appearance === \"dark\" || (appearance === \"system\" && prefersDark());\n};\n\nconst getSystemAppearance = (): ResolvedAppearance => (prefersDark() ? \"dark\" : \"light\");\n\nconst applyAppearance = (appearance: Appearance): void => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const isDark = isDarkMode(appearance);\n\n document.documentElement.classList.toggle(\"dark\", isDark);\n document.documentElement.style.colorScheme = isDark ? \"dark\" : \"light\";\n};\n\nconst mediaQuery = (): MediaQueryList | null => {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n return window.matchMedia(\"(prefers-color-scheme: dark)\");\n};\n\nconst handleSystemAppearanceChange = (): void => {\n applyAppearance(currentAppearance);\n notify();\n};\n\nexport function updateAppearance(mode: Appearance): void {\n currentAppearance = mode;\n\n localStorage.setItem(\"appearance\", mode);\n\n setCookie(\"appearance\", mode);\n\n applyAppearance(mode);\n notify();\n}\n\nexport function initializeAppearance(): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n if (!localStorage.getItem(\"appearance\")) {\n localStorage.setItem(\"appearance\", \"system\");\n setCookie(\"appearance\", \"system\");\n }\n\n currentAppearance = getStoredAppearance();\n applyAppearance(currentAppearance);\n\n mediaQuery()?.addEventListener(\"change\", handleSystemAppearanceChange);\n}\n\nexport function useAppearance(): UseAppearanceReturn {\n const appearance: Appearance = useSyncExternalStore(\n subscribe,\n () => currentAppearance,\n () => serverAppearance,\n );\n const systemAppearance: ResolvedAppearance = useSyncExternalStore(\n subscribe,\n getSystemAppearance,\n () => \"light\",\n );\n\n const resolvedAppearance: ResolvedAppearance =\n appearance === \"system\" ? systemAppearance : appearance;\n\n return { appearance, resolvedAppearance, updateAppearance } as const;\n}\n"],"mappings":";;;AAGA,IAAM,cAAc;CAAC;CAAS;CAAQ;AAAQ;AAY9C,IAAM,EAAE,WAAW,WAAW,gBAAgB;AAC9C,IAAI,oBAAgC;AACpC,IAAI,mBAA+B;;;;;;AAOnC,SAAgB,eAAe,OAAsB;CACnD,IAAI,aAAa,KAAK,GACpB,mBAAmB;AAEvB;AAEA,SAAgB,aAAa,OAAqC;CAChE,OAAO,YAAY,MAAM,eAAe,eAAe,KAAK;AAC9D;AAEA,IAAM,oBAA6B;CACjC,IAAI,OAAO,WAAW,aACpB,OAAO;CAGT,OAAO,OAAO,WAAW,8BAA8B,CAAC,CAAC;AAC3D;AAEA,IAAM,aAAa,MAAc,OAAe,OAAO,QAAc;CACnE,IAAI,OAAO,aAAa,aACtB;CAGF,MAAM,SAAS,OAAO,KAAK,KAAK;CAChC,SAAS,SAAS,GAAG,KAAK,GAAG,MAAM,kBAAkB,OAAO;AAC9D;AAEA,IAAM,4BAAwC;CAC5C,IAAI,OAAO,WAAW,aACpB,OAAO;CAGT,MAAM,SAAS,aAAa,QAAQ,YAAY;CAEhD,OAAO,aAAa,MAAM,IAAI,SAAS;AACzC;AAEA,IAAM,cAAc,eAAoC;CACtD,OAAO,eAAe,UAAW,eAAe,YAAY,YAAY;AAC1E;AAEA,IAAM,4BAAiD,YAAY,IAAI,SAAS;AAEhF,IAAM,mBAAmB,eAAiC;CACxD,IAAI,OAAO,aAAa,aACtB;CAGF,MAAM,SAAS,WAAW,UAAU;CAEpC,SAAS,gBAAgB,UAAU,OAAO,QAAQ,MAAM;CACxD,SAAS,gBAAgB,MAAM,cAAc,SAAS,SAAS;AACjE;AAEA,IAAM,mBAA0C;CAC9C,IAAI,OAAO,WAAW,aACpB,OAAO;CAGT,OAAO,OAAO,WAAW,8BAA8B;AACzD;AAEA,IAAM,qCAA2C;CAC/C,gBAAgB,iBAAiB;CACjC,OAAO;AACT;AAEA,SAAgB,iBAAiB,MAAwB;CACvD,oBAAoB;CAEpB,aAAa,QAAQ,cAAc,IAAI;CAEvC,UAAU,cAAc,IAAI;CAE5B,gBAAgB,IAAI;CACpB,OAAO;AACT;AAEA,SAAgB,uBAA6B;CAC3C,IAAI,OAAO,WAAW,aACpB;CAGF,IAAI,CAAC,aAAa,QAAQ,YAAY,GAAG;EACvC,aAAa,QAAQ,cAAc,QAAQ;EAC3C,UAAU,cAAc,QAAQ;CAClC;CAEA,oBAAoB,oBAAoB;CACxC,gBAAgB,iBAAiB;CAEjC,WAAW,CAAC,EAAE,iBAAiB,UAAU,4BAA4B;AACvE;AAEA,SAAgB,gBAAqC;CACnD,MAAM,aAAyB,qBAC7B,iBACM,yBACA,gBACR;CACA,MAAM,mBAAuC,qBAC3C,WACA,2BACM,OACR;CAKA,OAAO;EAAE;EAAY,oBAFnB,eAAe,WAAW,mBAAmB;EAEN;CAAiB;AAC5D"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { RemoteAccess } from '../../core/api.js';
|
|
2
2
|
import { ChatFrame, ChatTransportRequest } from '../types.js';
|
|
3
|
-
export declare
|
|
4
|
-
export declare function createRemoteNdjsonChatTransport(remote: RemoteAccess): (
|
|
3
|
+
export declare const ndjsonChatTransport: (request: ChatTransportRequest) => AsyncGenerator<ChatFrame>;
|
|
4
|
+
export declare function createRemoteNdjsonChatTransport(remote: RemoteAccess): (request: ChatTransportRequest) => AsyncGenerator<ChatFrame>;
|
|
@@ -7,33 +7,32 @@ function parseFrame(line) {
|
|
|
7
7
|
return null;
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
function ndjsonTransport(fetchResponse) {
|
|
11
|
+
return async function* transport(request) {
|
|
12
|
+
const res = await fetchResponse(request);
|
|
13
|
+
if (!res.ok || !res.body) throw new Error(`Chat stream failed (${res.status})`);
|
|
14
|
+
yield* readNdjsonFrames(res.body);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
var ndjsonChatTransport = ndjsonTransport(({ url, body, signal }) => apiFetch(url, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
signal,
|
|
20
|
+
headers: { Accept: "application/x-ndjson" },
|
|
21
|
+
body: JSON.stringify(body),
|
|
22
|
+
throwOnError: false
|
|
23
|
+
}));
|
|
24
|
+
function createRemoteNdjsonChatTransport(remote) {
|
|
25
|
+
return ndjsonTransport(({ url, body, signal }) => remoteFetch(url, {
|
|
26
|
+
remote,
|
|
12
27
|
method: "POST",
|
|
13
28
|
signal,
|
|
14
|
-
headers: {
|
|
29
|
+
headers: {
|
|
30
|
+
Accept: "application/x-ndjson",
|
|
31
|
+
"Content-Type": "application/json"
|
|
32
|
+
},
|
|
15
33
|
body: JSON.stringify(body),
|
|
16
34
|
throwOnError: false
|
|
17
|
-
});
|
|
18
|
-
if (!res.ok || !res.body) throw new Error(`Chat stream failed (${res.status})`);
|
|
19
|
-
yield* readNdjsonFrames(res.body);
|
|
20
|
-
}
|
|
21
|
-
function createRemoteNdjsonChatTransport(remote) {
|
|
22
|
-
return async function* remoteNdjsonChatTransport({ url, body, signal }) {
|
|
23
|
-
const res = await remoteFetch(url, {
|
|
24
|
-
remote,
|
|
25
|
-
method: "POST",
|
|
26
|
-
signal,
|
|
27
|
-
headers: {
|
|
28
|
-
Accept: "application/x-ndjson",
|
|
29
|
-
"Content-Type": "application/json"
|
|
30
|
-
},
|
|
31
|
-
body: JSON.stringify(body),
|
|
32
|
-
throwOnError: false
|
|
33
|
-
});
|
|
34
|
-
if (!res.ok || !res.body) throw new Error(`Chat stream failed (${res.status})`);
|
|
35
|
-
yield* readNdjsonFrames(res.body);
|
|
36
|
-
};
|
|
35
|
+
}));
|
|
37
36
|
}
|
|
38
37
|
async function* readNdjsonFrames(body) {
|
|
39
38
|
const reader = body.getReader();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","names":[],"sources":["../../../resources/js/chat/lib/transport.ts"],"sourcesContent":["import { apiFetch, remoteFetch, type RemoteAccess } from \"@lattice-php/lattice/core/api\";\nimport type { ChatFrame, ChatTransportRequest } from \"@lattice-php/lattice/chat/types\";\n\nfunction parseFrame(line: string): ChatFrame | null {\n try {\n return JSON.parse(line) as ChatFrame;\n } catch {\n return null;\n }\n}\n\
|
|
1
|
+
{"version":3,"file":"transport.js","names":[],"sources":["../../../resources/js/chat/lib/transport.ts"],"sourcesContent":["import { apiFetch, remoteFetch, type RemoteAccess } from \"@lattice-php/lattice/core/api\";\nimport type { ChatFrame, ChatTransportRequest } from \"@lattice-php/lattice/chat/types\";\n\nfunction parseFrame(line: string): ChatFrame | null {\n try {\n return JSON.parse(line) as ChatFrame;\n } catch {\n return null;\n }\n}\n\nfunction ndjsonTransport(fetchResponse: (request: ChatTransportRequest) => Promise<Response>) {\n return async function* transport(request: ChatTransportRequest): AsyncGenerator<ChatFrame> {\n const res = await fetchResponse(request);\n\n if (!res.ok || !res.body) {\n throw new Error(`Chat stream failed (${res.status})`);\n }\n\n yield* readNdjsonFrames(res.body);\n };\n}\n\nexport const ndjsonChatTransport = ndjsonTransport(({ url, body, signal }) =>\n apiFetch(url, {\n method: \"POST\",\n signal,\n headers: { Accept: \"application/x-ndjson\" },\n body: JSON.stringify(body),\n throwOnError: false,\n }),\n);\n\nexport function createRemoteNdjsonChatTransport(remote: RemoteAccess) {\n return ndjsonTransport(({ url, body, signal }) =>\n remoteFetch(url, {\n remote,\n method: \"POST\",\n signal,\n headers: {\n Accept: \"application/x-ndjson\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n throwOnError: false,\n }),\n );\n}\n\nasync function* readNdjsonFrames(body: ReadableStream<Uint8Array>): AsyncGenerator<ChatFrame> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (line.trim() === \"\") {\n continue;\n }\n\n const frame = parseFrame(line);\n if (frame) {\n yield frame;\n }\n }\n }\n\n buffer += decoder.decode();\n if (buffer.trim() !== \"\") {\n const frame = parseFrame(buffer);\n if (frame) {\n yield frame;\n }\n }\n } finally {\n await reader.cancel().catch(() => {});\n }\n}\n"],"mappings":";;AAGA,SAAS,WAAW,MAAgC;CAClD,IAAI;EACF,OAAO,KAAK,MAAM,IAAI;CACxB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,gBAAgB,eAAqE;CAC5F,OAAO,gBAAgB,UAAU,SAA0D;EACzF,MAAM,MAAM,MAAM,cAAc,OAAO;EAEvC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,MAClB,MAAM,IAAI,MAAM,uBAAuB,IAAI,OAAO,EAAE;EAGtD,OAAO,iBAAiB,IAAI,IAAI;CAClC;AACF;AAEA,IAAa,sBAAsB,iBAAiB,EAAE,KAAK,MAAM,aAC/D,SAAS,KAAK;CACZ,QAAQ;CACR;CACA,SAAS,EAAE,QAAQ,uBAAuB;CAC1C,MAAM,KAAK,UAAU,IAAI;CACzB,cAAc;AAChB,CAAC,CACH;AAEA,SAAgB,gCAAgC,QAAsB;CACpE,OAAO,iBAAiB,EAAE,KAAK,MAAM,aACnC,YAAY,KAAK;EACf;EACA,QAAQ;EACR;EACA,SAAS;GACP,QAAQ;GACR,gBAAgB;EAClB;EACA,MAAM,KAAK,UAAU,IAAI;EACzB,cAAc;CAChB,CAAC,CACH;AACF;AAEA,gBAAgB,iBAAiB,MAA6D;CAC5F,MAAM,SAAS,KAAK,UAAU;CAC9B,MAAM,UAAU,IAAI,YAAY;CAChC,IAAI,SAAS;CAEb,IAAI;EACF,SAAS;GACP,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;GAC1C,IAAI,MACF;GAGF,UAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;GAChD,MAAM,QAAQ,OAAO,MAAM,IAAI;GAC/B,SAAS,MAAM,IAAI,KAAK;GAExB,KAAK,MAAM,QAAQ,OAAO;IACxB,IAAI,KAAK,KAAK,MAAM,IAClB;IAGF,MAAM,QAAQ,WAAW,IAAI;IAC7B,IAAI,OACF,MAAM;GAEV;EACF;EAEA,UAAU,QAAQ,OAAO;EACzB,IAAI,OAAO,KAAK,MAAM,IAAI;GACxB,MAAM,QAAQ,WAAW,MAAM;GAC/B,IAAI,OACF,MAAM;EAEV;CACF,UAAU;EACR,MAAM,OAAO,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC;CACtC;AACF"}
|
package/dist/core/api.d.ts
CHANGED
|
@@ -18,7 +18,6 @@ export type RemoteAccess = GeneratedRemoteAccess;
|
|
|
18
18
|
export type RemoteInit = Omit<RequestInit, "credentials" | "headers"> & {
|
|
19
19
|
headers?: Record<string, string>;
|
|
20
20
|
remote: RemoteAccess;
|
|
21
|
-
retryOnUnauthorized?: boolean;
|
|
22
21
|
throwOnError?: boolean;
|
|
23
22
|
};
|
|
24
23
|
/**
|
package/dist/core/api.js
CHANGED
|
@@ -145,10 +145,10 @@ async function fetchRemoteWithToken(url, init, token) {
|
|
|
145
145
|
});
|
|
146
146
|
}
|
|
147
147
|
async function remoteFetch(url, init) {
|
|
148
|
-
const { remote,
|
|
148
|
+
const { remote, throwOnError = true, ...request } = init;
|
|
149
149
|
let token = await remoteToken(remote);
|
|
150
150
|
let response = await fetchRemoteWithToken(url, request, token);
|
|
151
|
-
if (
|
|
151
|
+
if (isUnauthorized(response)) {
|
|
152
152
|
invalidateRemoteToken(remote);
|
|
153
153
|
token = await remoteToken(remote);
|
|
154
154
|
response = await fetchRemoteWithToken(url, request, token);
|
package/dist/core/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","names":[],"sources":["../../resources/js/core/api.ts"],"sourcesContent":["/**\n * The single funnel for raw-fetch HTTP, so the cross-cutting header, credential,\n * and error policy has one home and call sites only declare intent. Returns a\n * Response (not parsed data) so one primitive serves JSON, the chat's streaming\n * getReader(), and multipart alike. Not for the Inertia world (router/useHttp),\n * which carries its own headers.\n */\n\nimport { latestRef, storeRefreshedRef } from \"./component-ref\";\nimport { withHeaders } from \"./headers\";\nimport { localeHeader } from \"@lattice-php/lattice/i18n/locale\";\nimport type {\n BrowserToken as GeneratedBrowserToken,\n RemoteAccess as GeneratedRemoteAccess,\n} from \"@lattice-php/lattice/types/generated\";\n\nexport class ApiError extends Error {\n constructor(readonly response: Response) {\n super(`HTTP ${response.status}`);\n }\n}\n\n/**\n * Exported so the few transports that cannot go through apiFetch — an XHR that\n * reports upload progress, for instance — still send the same CSRF header.\n */\nexport function xsrfToken(): string {\n const match = document.cookie.match(/XSRF-TOKEN=([^;]+)/);\n\n return match ? decodeURIComponent(match[1]) : \"\";\n}\n\nexport type ApiInit = Omit<RequestInit, \"headers\"> & {\n ref?: string;\n headers?: Record<string, string>;\n throwOnError?: boolean;\n};\n\nexport type BrowserToken = GeneratedBrowserToken;\nexport type RemoteAccess = GeneratedRemoteAccess;\n\nexport type RemoteInit = Omit<RequestInit, \"credentials\" | \"headers\"> & {\n headers?: Record<string, string>;\n remote: RemoteAccess;\n retryOnUnauthorized?: boolean;\n throwOnError?: boolean;\n};\n\ntype CachedBrowserToken = {\n expiresAt: number;\n token: BrowserToken;\n};\n\nconst tokenRefreshSkewMs = 10_000;\nconst remoteTokenCache = new Map<string, CachedBrowserToken>();\nconst pendingRemoteTokens = new Map<string, Promise<BrowserToken>>();\n\nfunction defaultHeaders(method: string | undefined): Record<string, string> {\n const isWrite = method !== undefined && method !== \"GET\" && method !== \"HEAD\";\n\n if (!isWrite) {\n return { Accept: \"application/json\" };\n }\n\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"X-Requested-With\": \"XMLHttpRequest\",\n \"X-XSRF-TOKEN\": xsrfToken(),\n };\n}\n\nlet refRefreshEndpoint = \"/lattice/refs/refresh\";\n\n/**\n * Boot paths call this with the server-minted URL so subdirectory installs\n * refresh against the right path; the default covers root installs.\n */\nexport function setRefRefreshEndpoint(url: string): void {\n refRefreshEndpoint = url;\n}\n\nconst pendingRefRefreshes = new Map<string, Promise<string | null>>();\n\n/**\n * Trade an expired-but-authentic ref for a fresh one. Deduped per original ref\n * so a burst of 403s from one component costs a single round-trip. The renewed\n * token lands in the component-ref map, so every later request that resolves\n * its ref through withHeaders picks it up — this is the transport-agnostic\n * primitive both the fetch funnel below and the Inertia form retry build on.\n */\nexport async function refreshRef(componentRef: string): Promise<string | null> {\n const pending = pendingRefRefreshes.get(componentRef);\n\n if (pending) {\n return pending;\n }\n\n const request = apiJson<{ ref: string }>(refRefreshEndpoint, {\n method: \"POST\",\n body: JSON.stringify({ ref: latestRef(componentRef) }),\n })\n .then((data) => {\n storeRefreshedRef(componentRef, data.ref);\n\n return data.ref;\n })\n .catch(() => null)\n .finally(() => {\n pendingRefRefreshes.delete(componentRef);\n });\n\n pendingRefRefreshes.set(componentRef, request);\n\n return request;\n}\n\nexport async function apiFetch(url: string, init: ApiInit = {}): Promise<Response> {\n const { ref = \"\", headers, throwOnError = true, method, ...rest } = init;\n // Some servers reject a lower-case method line, and fetch only normalizes the\n // standard verbs, so upper-case it here.\n const normalizedMethod = method?.toUpperCase();\n const request = () =>\n fetch(url, {\n credentials: \"same-origin\",\n ...rest,\n method: normalizedMethod,\n // withHeaders resolves the latest refreshed token for the ref, so the\n // retry below picks up the renewal without threading it through.\n headers: withHeaders(ref, { ...defaultHeaders(normalizedMethod), ...headers }),\n });\n\n let response = await request();\n\n if (ref !== \"\" && response.status === 403 && (await refreshRef(ref)) !== null) {\n response = await request();\n }\n\n if (throwOnError && !response.ok) {\n throw new ApiError(response);\n }\n\n return response;\n}\n\nexport async function apiJson<T>(url: string, init?: ApiInit): Promise<T> {\n return (await apiFetch(url, init)).json() as Promise<T>;\n}\n\nfunction remoteTokenKey(remote: RemoteAccess): string {\n return [remote.source, remote.audience, [...remote.scopes].sort().join(\" \")].join(\"\\u001f\");\n}\n\nexport function clearRemoteTokenCache(): void {\n remoteTokenCache.clear();\n pendingRemoteTokens.clear();\n}\n\nexport function invalidateRemoteToken(remote: RemoteAccess): void {\n remoteTokenCache.delete(remoteTokenKey(remote));\n}\n\nexport async function remoteToken(remote: RemoteAccess): Promise<BrowserToken> {\n const key = remoteTokenKey(remote);\n const cached = remoteTokenCache.get(key);\n\n if (cached && cached.expiresAt > Date.now() + tokenRefreshSkewMs) {\n return cached.token;\n }\n\n const pending = pendingRemoteTokens.get(key);\n\n if (pending) {\n return pending;\n }\n\n const request = apiJson<BrowserToken>(remote.tokenEndpoint, {\n method: \"POST\",\n ref: remote.ref,\n body: JSON.stringify({\n nodeId: remote.nodeId,\n nodeType: remote.nodeType,\n audience: remote.audience,\n scopes: remote.scopes,\n }),\n })\n .then((token) => {\n remoteTokenCache.set(key, {\n token,\n expiresAt: Date.now() + Math.max(0, token.expiresIn) * 1000,\n });\n\n return token;\n })\n .finally(() => {\n pendingRemoteTokens.delete(key);\n });\n\n pendingRemoteTokens.set(key, request);\n\n return request;\n}\n\nfunction isUnauthorized(response: Response): boolean {\n return response.status === 401 || response.status === 403;\n}\n\nasync function fetchRemoteWithToken(\n url: string,\n init: Omit<RemoteInit, \"remote\" | \"retryOnUnauthorized\" | \"throwOnError\">,\n token: BrowserToken,\n): Promise<Response> {\n const { headers, ...rest } = init;\n\n return fetch(url, {\n ...rest,\n credentials: \"omit\",\n headers: {\n Accept: \"application/json\",\n ...localeHeader(),\n ...headers,\n Authorization: `${token.tokenType} ${token.accessToken}`,\n },\n });\n}\n\nexport async function remoteFetch(url: string, init: RemoteInit): Promise<Response> {\n const { remote, retryOnUnauthorized = true, throwOnError = true, ...request } = init;\n let token = await remoteToken(remote);\n let response = await fetchRemoteWithToken(url, request, token);\n\n if (retryOnUnauthorized && isUnauthorized(response)) {\n invalidateRemoteToken(remote);\n token = await remoteToken(remote);\n response = await fetchRemoteWithToken(url, request, token);\n }\n\n if (throwOnError && !response.ok) {\n throw new ApiError(response);\n }\n\n return response;\n}\n\nexport async function remoteJson<T>(url: string, init: RemoteInit): Promise<T> {\n return (await remoteFetch(url, init)).json() as Promise<T>;\n}\n"],"mappings":";;;;;;;;;;;AAgBA,IAAa,WAAb,cAA8B,MAAM;CACb;CAArB,YAAY,UAA6B;EACvC,MAAM,QAAQ,SAAS,QAAQ;EADZ,KAAA,WAAA;CAErB;AACF;;;;;AAMA,SAAgB,YAAoB;CAClC,MAAM,QAAQ,SAAS,OAAO,MAAM,oBAAoB;CAExD,OAAO,QAAQ,mBAAmB,MAAM,EAAE,IAAI;AAChD;AAuBA,IAAM,qBAAqB;AAC3B,IAAM,mCAAmB,IAAI,IAAgC;AAC7D,IAAM,sCAAsB,IAAI,IAAmC;AAEnE,SAAS,eAAe,QAAoD;CAG1E,IAAI,EAFY,WAAW,KAAA,KAAa,WAAW,SAAS,WAAW,SAGrE,OAAO,EAAE,QAAQ,mBAAmB;CAGtC,OAAO;EACL,QAAQ;EACR,gBAAgB;EAChB,oBAAoB;EACpB,gBAAgB,UAAU;CAC5B;AACF;AAEA,IAAI,qBAAqB;;;;;AAMzB,SAAgB,sBAAsB,KAAmB;CACvD,qBAAqB;AACvB;AAEA,IAAM,sCAAsB,IAAI,IAAoC;;;;;;;;AASpE,eAAsB,WAAW,cAA8C;CAC7E,MAAM,UAAU,oBAAoB,IAAI,YAAY;CAEpD,IAAI,SACF,OAAO;CAGT,MAAM,UAAU,QAAyB,oBAAoB;EAC3D,QAAQ;EACR,MAAM,KAAK,UAAU,EAAE,KAAK,UAAU,YAAY,EAAE,CAAC;CACvD,CAAC,CAAC,CACC,MAAM,SAAS;EACd,kBAAkB,cAAc,KAAK,GAAG;EAExC,OAAO,KAAK;CACd,CAAC,CAAC,CACD,YAAY,IAAI,CAAC,CACjB,cAAc;EACb,oBAAoB,OAAO,YAAY;CACzC,CAAC;CAEH,oBAAoB,IAAI,cAAc,OAAO;CAE7C,OAAO;AACT;AAEA,eAAsB,SAAS,KAAa,OAAgB,CAAC,GAAsB;CACjF,MAAM,EAAE,MAAM,IAAI,SAAS,eAAe,MAAM,QAAQ,GAAG,SAAS;CAGpE,MAAM,mBAAmB,QAAQ,YAAY;CAC7C,MAAM,gBACJ,MAAM,KAAK;EACT,aAAa;EACb,GAAG;EACH,QAAQ;EAGR,SAAS,YAAY,KAAK;GAAE,GAAG,eAAe,gBAAgB;GAAG,GAAG;EAAQ,CAAC;CAC/E,CAAC;CAEH,IAAI,WAAW,MAAM,QAAQ;CAE7B,IAAI,QAAQ,MAAM,SAAS,WAAW,OAAQ,MAAM,WAAW,GAAG,MAAO,MACvE,WAAW,MAAM,QAAQ;CAG3B,IAAI,gBAAgB,CAAC,SAAS,IAC5B,MAAM,IAAI,SAAS,QAAQ;CAG7B,OAAO;AACT;AAEA,eAAsB,QAAW,KAAa,MAA4B;CACxE,QAAQ,MAAM,SAAS,KAAK,IAAI,EAAA,CAAG,KAAK;AAC1C;AAEA,SAAS,eAAe,QAA8B;CACpD,OAAO;EAAC,OAAO;EAAQ,OAAO;EAAU,CAAC,GAAG,OAAO,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG;CAAC,CAAC,CAAC,KAAK,GAAQ;AAC5F;AAEA,SAAgB,wBAA8B;CAC5C,iBAAiB,MAAM;CACvB,oBAAoB,MAAM;AAC5B;AAEA,SAAgB,sBAAsB,QAA4B;CAChE,iBAAiB,OAAO,eAAe,MAAM,CAAC;AAChD;AAEA,eAAsB,YAAY,QAA6C;CAC7E,MAAM,MAAM,eAAe,MAAM;CACjC,MAAM,SAAS,iBAAiB,IAAI,GAAG;CAEvC,IAAI,UAAU,OAAO,YAAY,KAAK,IAAI,IAAI,oBAC5C,OAAO,OAAO;CAGhB,MAAM,UAAU,oBAAoB,IAAI,GAAG;CAE3C,IAAI,SACF,OAAO;CAGT,MAAM,UAAU,QAAsB,OAAO,eAAe;EAC1D,QAAQ;EACR,KAAK,OAAO;EACZ,MAAM,KAAK,UAAU;GACnB,QAAQ,OAAO;GACf,UAAU,OAAO;GACjB,UAAU,OAAO;GACjB,QAAQ,OAAO;EACjB,CAAC;CACH,CAAC,CAAC,CACC,MAAM,UAAU;EACf,iBAAiB,IAAI,KAAK;GACxB;GACA,WAAW,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,MAAM,SAAS,IAAI;EACzD,CAAC;EAED,OAAO;CACT,CAAC,CAAC,CACD,cAAc;EACb,oBAAoB,OAAO,GAAG;CAChC,CAAC;CAEH,oBAAoB,IAAI,KAAK,OAAO;CAEpC,OAAO;AACT;AAEA,SAAS,eAAe,UAA6B;CACnD,OAAO,SAAS,WAAW,OAAO,SAAS,WAAW;AACxD;AAEA,eAAe,qBACb,KACA,MACA,OACmB;CACnB,MAAM,EAAE,SAAS,GAAG,SAAS;CAE7B,OAAO,MAAM,KAAK;EAChB,GAAG;EACH,aAAa;EACb,SAAS;GACP,QAAQ;GACR,GAAG,aAAa;GAChB,GAAG;GACH,eAAe,GAAG,MAAM,UAAU,GAAG,MAAM;EAC7C;CACF,CAAC;AACH;AAEA,eAAsB,YAAY,KAAa,MAAqC;CAClF,MAAM,EAAE,QAAQ,sBAAsB,MAAM,eAAe,MAAM,GAAG,YAAY;CAChF,IAAI,QAAQ,MAAM,YAAY,MAAM;CACpC,IAAI,WAAW,MAAM,qBAAqB,KAAK,SAAS,KAAK;CAE7D,IAAI,uBAAuB,eAAe,QAAQ,GAAG;EACnD,sBAAsB,MAAM;EAC5B,QAAQ,MAAM,YAAY,MAAM;EAChC,WAAW,MAAM,qBAAqB,KAAK,SAAS,KAAK;CAC3D;CAEA,IAAI,gBAAgB,CAAC,SAAS,IAC5B,MAAM,IAAI,SAAS,QAAQ;CAG7B,OAAO;AACT;AAEA,eAAsB,WAAc,KAAa,MAA8B;CAC7E,QAAQ,MAAM,YAAY,KAAK,IAAI,EAAA,CAAG,KAAK;AAC7C"}
|
|
1
|
+
{"version":3,"file":"api.js","names":[],"sources":["../../resources/js/core/api.ts"],"sourcesContent":["/**\n * The single funnel for raw-fetch HTTP, so the cross-cutting header, credential,\n * and error policy has one home and call sites only declare intent. Returns a\n * Response (not parsed data) so one primitive serves JSON, the chat's streaming\n * getReader(), and multipart alike. Not for the Inertia world (router/useHttp),\n * which carries its own headers.\n */\n\nimport { latestRef, storeRefreshedRef } from \"./component-ref\";\nimport { withHeaders } from \"./headers\";\nimport { localeHeader } from \"@lattice-php/lattice/i18n/locale\";\nimport type {\n BrowserToken as GeneratedBrowserToken,\n RemoteAccess as GeneratedRemoteAccess,\n} from \"@lattice-php/lattice/types/generated\";\n\nexport class ApiError extends Error {\n constructor(readonly response: Response) {\n super(`HTTP ${response.status}`);\n }\n}\n\n/**\n * Exported so the few transports that cannot go through apiFetch — an XHR that\n * reports upload progress, for instance — still send the same CSRF header.\n */\nexport function xsrfToken(): string {\n const match = document.cookie.match(/XSRF-TOKEN=([^;]+)/);\n\n return match ? decodeURIComponent(match[1]) : \"\";\n}\n\nexport type ApiInit = Omit<RequestInit, \"headers\"> & {\n ref?: string;\n headers?: Record<string, string>;\n throwOnError?: boolean;\n};\n\nexport type BrowserToken = GeneratedBrowserToken;\nexport type RemoteAccess = GeneratedRemoteAccess;\n\nexport type RemoteInit = Omit<RequestInit, \"credentials\" | \"headers\"> & {\n headers?: Record<string, string>;\n remote: RemoteAccess;\n throwOnError?: boolean;\n};\n\ntype CachedBrowserToken = {\n expiresAt: number;\n token: BrowserToken;\n};\n\nconst tokenRefreshSkewMs = 10_000;\nconst remoteTokenCache = new Map<string, CachedBrowserToken>();\nconst pendingRemoteTokens = new Map<string, Promise<BrowserToken>>();\n\nfunction defaultHeaders(method: string | undefined): Record<string, string> {\n const isWrite = method !== undefined && method !== \"GET\" && method !== \"HEAD\";\n\n if (!isWrite) {\n return { Accept: \"application/json\" };\n }\n\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"X-Requested-With\": \"XMLHttpRequest\",\n \"X-XSRF-TOKEN\": xsrfToken(),\n };\n}\n\nlet refRefreshEndpoint = \"/lattice/refs/refresh\";\n\n/**\n * Boot paths call this with the server-minted URL so subdirectory installs\n * refresh against the right path; the default covers root installs.\n */\nexport function setRefRefreshEndpoint(url: string): void {\n refRefreshEndpoint = url;\n}\n\nconst pendingRefRefreshes = new Map<string, Promise<string | null>>();\n\n/**\n * Trade an expired-but-authentic ref for a fresh one. Deduped per original ref\n * so a burst of 403s from one component costs a single round-trip. The renewed\n * token lands in the component-ref map, so every later request that resolves\n * its ref through withHeaders picks it up — this is the transport-agnostic\n * primitive both the fetch funnel below and the Inertia form retry build on.\n */\nexport async function refreshRef(componentRef: string): Promise<string | null> {\n const pending = pendingRefRefreshes.get(componentRef);\n\n if (pending) {\n return pending;\n }\n\n const request = apiJson<{ ref: string }>(refRefreshEndpoint, {\n method: \"POST\",\n body: JSON.stringify({ ref: latestRef(componentRef) }),\n })\n .then((data) => {\n storeRefreshedRef(componentRef, data.ref);\n\n return data.ref;\n })\n .catch(() => null)\n .finally(() => {\n pendingRefRefreshes.delete(componentRef);\n });\n\n pendingRefRefreshes.set(componentRef, request);\n\n return request;\n}\n\nexport async function apiFetch(url: string, init: ApiInit = {}): Promise<Response> {\n const { ref = \"\", headers, throwOnError = true, method, ...rest } = init;\n // Some servers reject a lower-case method line, and fetch only normalizes the\n // standard verbs, so upper-case it here.\n const normalizedMethod = method?.toUpperCase();\n const request = () =>\n fetch(url, {\n credentials: \"same-origin\",\n ...rest,\n method: normalizedMethod,\n // withHeaders resolves the latest refreshed token for the ref, so the\n // retry below picks up the renewal without threading it through.\n headers: withHeaders(ref, { ...defaultHeaders(normalizedMethod), ...headers }),\n });\n\n let response = await request();\n\n if (ref !== \"\" && response.status === 403 && (await refreshRef(ref)) !== null) {\n response = await request();\n }\n\n if (throwOnError && !response.ok) {\n throw new ApiError(response);\n }\n\n return response;\n}\n\nexport async function apiJson<T>(url: string, init?: ApiInit): Promise<T> {\n return (await apiFetch(url, init)).json() as Promise<T>;\n}\n\nfunction remoteTokenKey(remote: RemoteAccess): string {\n return [remote.source, remote.audience, [...remote.scopes].sort().join(\" \")].join(\"\\u001f\");\n}\n\nexport function clearRemoteTokenCache(): void {\n remoteTokenCache.clear();\n pendingRemoteTokens.clear();\n}\n\nexport function invalidateRemoteToken(remote: RemoteAccess): void {\n remoteTokenCache.delete(remoteTokenKey(remote));\n}\n\nexport async function remoteToken(remote: RemoteAccess): Promise<BrowserToken> {\n const key = remoteTokenKey(remote);\n const cached = remoteTokenCache.get(key);\n\n if (cached && cached.expiresAt > Date.now() + tokenRefreshSkewMs) {\n return cached.token;\n }\n\n const pending = pendingRemoteTokens.get(key);\n\n if (pending) {\n return pending;\n }\n\n const request = apiJson<BrowserToken>(remote.tokenEndpoint, {\n method: \"POST\",\n ref: remote.ref,\n body: JSON.stringify({\n nodeId: remote.nodeId,\n nodeType: remote.nodeType,\n audience: remote.audience,\n scopes: remote.scopes,\n }),\n })\n .then((token) => {\n remoteTokenCache.set(key, {\n token,\n expiresAt: Date.now() + Math.max(0, token.expiresIn) * 1000,\n });\n\n return token;\n })\n .finally(() => {\n pendingRemoteTokens.delete(key);\n });\n\n pendingRemoteTokens.set(key, request);\n\n return request;\n}\n\nfunction isUnauthorized(response: Response): boolean {\n return response.status === 401 || response.status === 403;\n}\n\nasync function fetchRemoteWithToken(\n url: string,\n init: Omit<RemoteInit, \"remote\" | \"throwOnError\">,\n token: BrowserToken,\n): Promise<Response> {\n const { headers, ...rest } = init;\n\n return fetch(url, {\n ...rest,\n credentials: \"omit\",\n headers: {\n Accept: \"application/json\",\n ...localeHeader(),\n ...headers,\n Authorization: `${token.tokenType} ${token.accessToken}`,\n },\n });\n}\n\nexport async function remoteFetch(url: string, init: RemoteInit): Promise<Response> {\n const { remote, throwOnError = true, ...request } = init;\n let token = await remoteToken(remote);\n let response = await fetchRemoteWithToken(url, request, token);\n\n if (isUnauthorized(response)) {\n invalidateRemoteToken(remote);\n token = await remoteToken(remote);\n response = await fetchRemoteWithToken(url, request, token);\n }\n\n if (throwOnError && !response.ok) {\n throw new ApiError(response);\n }\n\n return response;\n}\n\nexport async function remoteJson<T>(url: string, init: RemoteInit): Promise<T> {\n return (await remoteFetch(url, init)).json() as Promise<T>;\n}\n"],"mappings":"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"}
|
|
@@ -5,10 +5,10 @@ export type SizableColumn = {
|
|
|
5
5
|
width: ColumnWidth;
|
|
6
6
|
};
|
|
7
7
|
export declare const DEFAULT_COLUMN_WIDTH: ColumnWidth;
|
|
8
|
+
export declare const maxColumnWidthPx = 1024;
|
|
8
9
|
export declare function columnWidthTrack(width: ColumnWidth): string;
|
|
9
10
|
export declare function minColumnWidthPx(column: SizableColumn): number;
|
|
10
11
|
export declare function defaultColumnWidthPx(column: SizableColumn): number;
|
|
11
|
-
export declare function maxColumnWidthPx(column: SizableColumn): number;
|
|
12
12
|
export declare function buildColumnGridTemplate({ columns, leadingTracks, trailingTracks, overrides, }: {
|
|
13
13
|
columns: SizableColumn[];
|
|
14
14
|
leadingTracks?: string[];
|
|
@@ -4,34 +4,30 @@ var tracks = {
|
|
|
4
4
|
xs: {
|
|
5
5
|
track: "minmax(4rem, 0.35fr)",
|
|
6
6
|
minPx: 64,
|
|
7
|
-
defaultPx: 96
|
|
8
|
-
maxPx: 1024
|
|
7
|
+
defaultPx: 96
|
|
9
8
|
},
|
|
10
9
|
sm: {
|
|
11
10
|
track: "minmax(6rem, 0.5fr)",
|
|
12
11
|
minPx: 96,
|
|
13
|
-
defaultPx: 128
|
|
14
|
-
maxPx: 1024
|
|
12
|
+
defaultPx: 128
|
|
15
13
|
},
|
|
16
14
|
md: {
|
|
17
15
|
track: "minmax(8rem, 1fr)",
|
|
18
16
|
minPx: 128,
|
|
19
|
-
defaultPx: 176
|
|
20
|
-
maxPx: 1024
|
|
17
|
+
defaultPx: 176
|
|
21
18
|
},
|
|
22
19
|
lg: {
|
|
23
20
|
track: "minmax(12rem, 1.5fr)",
|
|
24
21
|
minPx: 192,
|
|
25
|
-
defaultPx: 240
|
|
26
|
-
maxPx: 1024
|
|
22
|
+
defaultPx: 240
|
|
27
23
|
},
|
|
28
24
|
xl: {
|
|
29
25
|
track: "minmax(16rem, 2fr)",
|
|
30
26
|
minPx: 256,
|
|
31
|
-
defaultPx: 320
|
|
32
|
-
maxPx: 1024
|
|
27
|
+
defaultPx: 320
|
|
33
28
|
}
|
|
34
29
|
};
|
|
30
|
+
var maxColumnWidthPx = 1024;
|
|
35
31
|
function columnWidthTrack(width) {
|
|
36
32
|
return tracks[width].track;
|
|
37
33
|
}
|
|
@@ -41,15 +37,12 @@ function minColumnWidthPx(column) {
|
|
|
41
37
|
function defaultColumnWidthPx(column) {
|
|
42
38
|
return tracks[column.width].defaultPx;
|
|
43
39
|
}
|
|
44
|
-
function maxColumnWidthPx(column) {
|
|
45
|
-
return tracks[column.width].maxPx;
|
|
46
|
-
}
|
|
47
40
|
function buildColumnGridTemplate({ columns, leadingTracks = [], trailingTracks = [], overrides = {} }) {
|
|
48
41
|
return [
|
|
49
42
|
...leadingTracks,
|
|
50
43
|
...columns.map((column) => {
|
|
51
44
|
const override = overrides[column.key];
|
|
52
|
-
if (override !== void 0) return `${Math.min(maxColumnWidthPx
|
|
45
|
+
if (override !== void 0) return `${Math.min(maxColumnWidthPx, Math.max(minColumnWidthPx(column), override))}px`;
|
|
53
46
|
return columnWidthTrack(column.width);
|
|
54
47
|
}),
|
|
55
48
|
...trailingTracks
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"column-sizing.js","names":[],"sources":["../../../resources/js/core/hooks/column-sizing.ts"],"sourcesContent":["import type { ColumnWidth } from \"@lattice-php/lattice/types/generated\";\n\nexport type SizableColumn = {\n key: string;\n label?: string | null;\n width: ColumnWidth;\n};\n\nexport const DEFAULT_COLUMN_WIDTH: ColumnWidth = \"md\";\n\nconst tracks: Record
|
|
1
|
+
{"version":3,"file":"column-sizing.js","names":[],"sources":["../../../resources/js/core/hooks/column-sizing.ts"],"sourcesContent":["import type { ColumnWidth } from \"@lattice-php/lattice/types/generated\";\n\nexport type SizableColumn = {\n key: string;\n label?: string | null;\n width: ColumnWidth;\n};\n\nexport const DEFAULT_COLUMN_WIDTH: ColumnWidth = \"md\";\n\nconst tracks: Record<ColumnWidth, { track: string; minPx: number; defaultPx: number }> = {\n xs: { track: \"minmax(4rem, 0.35fr)\", minPx: 64, defaultPx: 96 },\n sm: { track: \"minmax(6rem, 0.5fr)\", minPx: 96, defaultPx: 128 },\n md: { track: \"minmax(8rem, 1fr)\", minPx: 128, defaultPx: 176 },\n lg: { track: \"minmax(12rem, 1.5fr)\", minPx: 192, defaultPx: 240 },\n xl: { track: \"minmax(16rem, 2fr)\", minPx: 256, defaultPx: 320 },\n};\n\nexport const maxColumnWidthPx = 1024;\n\nexport function columnWidthTrack(width: ColumnWidth): string {\n return tracks[width].track;\n}\n\nexport function minColumnWidthPx(column: SizableColumn): number {\n return tracks[column.width].minPx;\n}\n\nexport function defaultColumnWidthPx(column: SizableColumn): number {\n return tracks[column.width].defaultPx;\n}\n\nexport function buildColumnGridTemplate({\n columns,\n leadingTracks = [],\n trailingTracks = [],\n overrides = {},\n}: {\n columns: SizableColumn[];\n leadingTracks?: string[];\n trailingTracks?: string[];\n overrides?: Record<string, number | undefined>;\n}): string {\n return [\n ...leadingTracks,\n ...columns.map((column) => {\n const override = overrides[column.key];\n\n if (override !== undefined) {\n return `${Math.min(maxColumnWidthPx, Math.max(minColumnWidthPx(column), override))}px`;\n }\n\n return columnWidthTrack(column.width);\n }),\n ...trailingTracks,\n ].join(\" \");\n}\n"],"mappings":";AAQA,IAAa,uBAAoC;AAEjD,IAAM,SAAmF;CACvF,IAAI;EAAE,OAAO;EAAwB,OAAO;EAAI,WAAW;CAAG;CAC9D,IAAI;EAAE,OAAO;EAAuB,OAAO;EAAI,WAAW;CAAI;CAC9D,IAAI;EAAE,OAAO;EAAqB,OAAO;EAAK,WAAW;CAAI;CAC7D,IAAI;EAAE,OAAO;EAAwB,OAAO;EAAK,WAAW;CAAI;CAChE,IAAI;EAAE,OAAO;EAAsB,OAAO;EAAK,WAAW;CAAI;AAChE;AAEA,IAAa,mBAAmB;AAEhC,SAAgB,iBAAiB,OAA4B;CAC3D,OAAO,OAAO,MAAM,CAAC;AACvB;AAEA,SAAgB,iBAAiB,QAA+B;CAC9D,OAAO,OAAO,OAAO,MAAM,CAAC;AAC9B;AAEA,SAAgB,qBAAqB,QAA+B;CAClE,OAAO,OAAO,OAAO,MAAM,CAAC;AAC9B;AAEA,SAAgB,wBAAwB,EACtC,SACA,gBAAgB,CAAC,GACjB,iBAAiB,CAAC,GAClB,YAAY,CAAC,KAMJ;CACT,OAAO;EACL,GAAG;EACH,GAAG,QAAQ,KAAK,WAAW;GACzB,MAAM,WAAW,UAAU,OAAO;GAElC,IAAI,aAAa,KAAA,GACf,OAAO,GAAG,KAAK,IAAI,kBAAkB,KAAK,IAAI,iBAAiB,MAAM,GAAG,QAAQ,CAAC,EAAE;GAGrF,OAAO,iBAAiB,OAAO,KAAK;EACtC,CAAC;EACD,GAAG;CACL,CAAC,CAAC,KAAK,GAAG;AACZ"}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { usePersistentState } from "../../lib/use-persistent-state.js";
|
|
1
2
|
import { buildColumnGridTemplate, defaultColumnWidthPx, maxColumnWidthPx, minColumnWidthPx } from "./column-sizing.js";
|
|
2
|
-
import { useCallback, useMemo, useRef
|
|
3
|
+
import { useCallback, useMemo, useRef } from "react";
|
|
3
4
|
//#region resources/js/core/hooks/use-column-resizing.ts
|
|
4
5
|
var emptyTracks = [];
|
|
5
6
|
function useColumnResizing({ columnGapPx = 0, columns, enabled, leadingTracks = emptyTracks, showIndicator = false, storageKey, trailingTracks = emptyTracks }) {
|
|
6
7
|
const columnKeys = useMemo(() => columns.map((column) => column.key), [columns]);
|
|
7
|
-
const [overrides, setOverrides] =
|
|
8
|
+
const [overrides, setOverrides] = usePersistentState(storageKey ?? "", {}, {
|
|
9
|
+
enabled: Boolean(storageKey),
|
|
10
|
+
parse: (raw) => parseStoredOverrides(raw, columns),
|
|
11
|
+
serialize: (value) => serializeOverrides(value, columnKeys)
|
|
12
|
+
});
|
|
8
13
|
const overridesRef = useRef(overrides);
|
|
9
14
|
const drag = useRef(null);
|
|
10
15
|
const resizeRootRef = useRef(null);
|
|
@@ -29,17 +34,15 @@ function useColumnResizing({ columnGapPx = 0, columns, enabled, leadingTracks =
|
|
|
29
34
|
const commitOverrides = useCallback((next) => {
|
|
30
35
|
overridesRef.current = next;
|
|
31
36
|
setOverrides(next);
|
|
32
|
-
writeStoredOverrides(storageKey, columnKeys, next);
|
|
33
37
|
applyTemplate(templateForOverrides(next));
|
|
34
38
|
}, [
|
|
35
39
|
applyTemplate,
|
|
36
|
-
|
|
37
|
-
storageKey,
|
|
40
|
+
setOverrides,
|
|
38
41
|
templateForOverrides
|
|
39
42
|
]);
|
|
40
43
|
const overridesWithColumnWidth = useCallback((current, column, width, maxWidth) => ({
|
|
41
44
|
...current,
|
|
42
|
-
[column.key]: Math.min(maxWidth ??
|
|
45
|
+
[column.key]: Math.min(maxWidth ?? 1024, Math.max(minColumnWidthPx(column), width))
|
|
43
46
|
}), []);
|
|
44
47
|
const setColumnWidth = useCallback((column, width, maxWidth) => {
|
|
45
48
|
commitOverrides(overridesWithColumnWidth(overridesRef.current, column, width, maxWidth));
|
|
@@ -56,7 +59,7 @@ function useColumnResizing({ columnGapPx = 0, columns, enabled, leadingTracks =
|
|
|
56
59
|
const currentColumnWidth = useCallback((column) => overridesRef.current[column.key] ?? defaultColumnWidthPx(column), []);
|
|
57
60
|
return {
|
|
58
61
|
getResizeHandleProps: useCallback((column) => {
|
|
59
|
-
const max = maxColumnWidthPx
|
|
62
|
+
const max = maxColumnWidthPx;
|
|
60
63
|
const min = minColumnWidthPx(column);
|
|
61
64
|
const current = currentColumnWidth(column);
|
|
62
65
|
const label = column.label ?? column.key;
|
|
@@ -167,69 +170,34 @@ function useColumnResizing({ columnGapPx = 0, columns, enabled, leadingTracks =
|
|
|
167
170
|
}
|
|
168
171
|
function maxColumnWidthForGrid({ column, columnGapPx, columns, grid, leadingTracks, trailingTracks }) {
|
|
169
172
|
const gridWidth = grid?.getBoundingClientRect().width ?? 0;
|
|
170
|
-
if (gridWidth <= 0) return maxColumnWidthPx
|
|
173
|
+
if (gridWidth <= 0) return maxColumnWidthPx;
|
|
171
174
|
const utilityWidth = [...leadingTracks, ...trailingTracks].reduce((sum, track) => sum + fixedTrackWidthPx(track), 0);
|
|
172
175
|
const siblingMinWidth = columns.reduce((sum, sibling) => sibling.key === column.key ? sum : sum + minColumnWidthPx(sibling), 0);
|
|
173
176
|
const trackCount = columns.length + leadingTracks.length + trailingTracks.length;
|
|
174
177
|
const gapWidth = Math.max(0, trackCount - 1) * columnGapPx;
|
|
175
178
|
const available = gridWidth - utilityWidth - siblingMinWidth - gapWidth;
|
|
176
|
-
return Math.min(maxColumnWidthPx
|
|
179
|
+
return Math.min(maxColumnWidthPx, Math.max(minColumnWidthPx(column), available));
|
|
177
180
|
}
|
|
178
|
-
function
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (!isStoredColumnWidths(stored)) {
|
|
185
|
-
removeStoredOverrides(storageKey);
|
|
186
|
-
return {};
|
|
187
|
-
}
|
|
188
|
-
const overrides = sanitizeOverrides(stored.overrides, columns);
|
|
189
|
-
if (Object.keys(overrides).length === 0) removeStoredOverrides(storageKey);
|
|
190
|
-
return overrides;
|
|
191
|
-
} catch {
|
|
192
|
-
removeStoredOverrides(storageKey);
|
|
193
|
-
return {};
|
|
194
|
-
}
|
|
181
|
+
function parseStoredOverrides(raw, columns) {
|
|
182
|
+
const overrides = JSON.parse(raw)?.overrides;
|
|
183
|
+
if (typeof overrides !== "object" || overrides === null || Array.isArray(overrides)) throw new Error("unexpected stored column widths shape");
|
|
184
|
+
const sanitized = sanitizeOverrides(overrides, columns);
|
|
185
|
+
if (Object.keys(sanitized).length === 0) throw new Error("stored column widths hold no usable overrides");
|
|
186
|
+
return sanitized;
|
|
195
187
|
}
|
|
196
|
-
function
|
|
197
|
-
if (!storageKey || typeof window === "undefined") return;
|
|
188
|
+
function serializeOverrides(overrides, columnKeys) {
|
|
198
189
|
const stored = {};
|
|
199
190
|
const knownKeys = new Set(columnKeys);
|
|
200
191
|
for (const [key, value] of Object.entries(overrides)) if (knownKeys.has(key) && typeof value === "number" && Number.isFinite(value)) stored[key] = value;
|
|
201
|
-
if (Object.keys(stored).length === 0)
|
|
202
|
-
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
try {
|
|
206
|
-
window.localStorage.setItem(storageKey, JSON.stringify({
|
|
207
|
-
columns: columnKeys,
|
|
208
|
-
overrides: stored
|
|
209
|
-
}));
|
|
210
|
-
} catch {
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
function removeStoredOverrides(storageKey) {
|
|
215
|
-
if (typeof window === "undefined") return;
|
|
216
|
-
try {
|
|
217
|
-
window.localStorage.removeItem(storageKey);
|
|
218
|
-
} catch {
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
function isStoredColumnWidths(value) {
|
|
223
|
-
if (typeof value !== "object" || value === null) return false;
|
|
224
|
-
const record = value;
|
|
225
|
-
return Array.isArray(record.columns) && record.columns.every((column) => typeof column === "string") && typeof record.overrides === "object" && record.overrides !== null && !Array.isArray(record.overrides);
|
|
192
|
+
if (Object.keys(stored).length === 0) return null;
|
|
193
|
+
return JSON.stringify({ overrides: stored });
|
|
226
194
|
}
|
|
227
195
|
function sanitizeOverrides(overrides, columns) {
|
|
228
196
|
const next = {};
|
|
229
197
|
for (const column of columns) {
|
|
230
198
|
const value = overrides[column.key];
|
|
231
199
|
if (typeof value !== "number" || !Number.isFinite(value)) continue;
|
|
232
|
-
next[column.key] = Math.min(maxColumnWidthPx
|
|
200
|
+
next[column.key] = Math.min(maxColumnWidthPx, Math.max(minColumnWidthPx(column), value));
|
|
233
201
|
}
|
|
234
202
|
return next;
|
|
235
203
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-column-resizing.js","names":[],"sources":["../../../resources/js/core/hooks/use-column-resizing.ts"],"sourcesContent":["import type { HTMLAttributes, KeyboardEvent, PointerEvent } from \"react\";\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport {\n buildColumnGridTemplate,\n defaultColumnWidthPx,\n maxColumnWidthPx,\n minColumnWidthPx,\n type SizableColumn,\n} from \"./column-sizing\";\n\ntype DragState = {\n key: string;\n maxWidth: number;\n overrides: Record<string, number | undefined> | null;\n startWidth: number;\n startX: number;\n};\n\ntype ResizeHandleProps = HTMLAttributes<HTMLDivElement> & {\n \"aria-label\": string;\n \"aria-orientation\": \"vertical\";\n \"aria-valuemax\": number;\n \"aria-valuemin\": number;\n \"aria-valuenow\": number;\n role: \"separator\";\n tabIndex: number;\n};\n\ntype StoredColumnWidths = {\n columns: string[];\n overrides: Record<string, number>;\n};\n\nconst emptyTracks: string[] = [];\n\nexport function useColumnResizing({\n columnGapPx = 0,\n columns,\n enabled,\n leadingTracks = emptyTracks,\n showIndicator = false,\n storageKey,\n trailingTracks = emptyTracks,\n}: {\n columnGapPx?: number;\n columns: SizableColumn[];\n enabled: boolean;\n leadingTracks?: string[];\n showIndicator?: boolean;\n storageKey?: string;\n trailingTracks?: string[];\n}) {\n const columnKeys = useMemo(() => columns.map((column) => column.key), [columns]);\n const [overrides, setOverrides] = useState<Record<string, number | undefined>>(() =>\n readStoredOverrides(storageKey, columns),\n );\n const overridesRef = useRef(overrides);\n const drag = useRef<DragState | null>(null);\n const resizeRootRef = useRef<HTMLDivElement | null>(null);\n\n const templateForOverrides = useCallback(\n (nextOverrides: Record<string, number | undefined>): string =>\n buildColumnGridTemplate({\n columns,\n leadingTracks,\n trailingTracks,\n overrides: enabled ? nextOverrides : {},\n }),\n [columns, enabled, leadingTracks, trailingTracks],\n );\n\n const gridTemplateColumns = useMemo(\n () => templateForOverrides(overrides),\n [overrides, templateForOverrides],\n );\n\n const applyTemplate = useCallback((template: string): void => {\n const root = resizeRootRef.current;\n\n if (!root) {\n return;\n }\n\n root.style.gridTemplateColumns = template;\n root.style.setProperty(\"--lattice-table-columns\", template);\n }, []);\n\n const commitOverrides = useCallback(\n (next: Record<string, number | undefined>) => {\n overridesRef.current = next;\n setOverrides(next);\n writeStoredOverrides(storageKey, columnKeys, next);\n applyTemplate(templateForOverrides(next));\n },\n [applyTemplate, columnKeys, storageKey, templateForOverrides],\n );\n\n const overridesWithColumnWidth = useCallback(\n (\n current: Record<string, number | undefined>,\n column: SizableColumn,\n width: number,\n maxWidth?: number,\n ): Record<string, number | undefined> => ({\n ...current,\n [column.key]: Math.min(\n maxWidth ?? maxColumnWidthPx(column),\n Math.max(minColumnWidthPx(column), width),\n ),\n }),\n [],\n );\n\n const setColumnWidth = useCallback(\n (column: SizableColumn, width: number, maxWidth?: number) => {\n commitOverrides(overridesWithColumnWidth(overridesRef.current, column, width, maxWidth));\n },\n [commitOverrides, overridesWithColumnWidth],\n );\n\n const resetColumnWidth = useCallback(\n (column: SizableColumn) => {\n const next = { ...overridesRef.current };\n delete next[column.key];\n\n commitOverrides(next);\n },\n [commitOverrides],\n );\n\n const resetColumns = useCallback(() => {\n commitOverrides({});\n }, [commitOverrides]);\n\n const hasOverrides =\n enabled && Object.values(overrides).some((width) => typeof width === \"number\");\n\n const currentColumnWidth = useCallback(\n (column: SizableColumn): number =>\n overridesRef.current[column.key] ?? defaultColumnWidthPx(column),\n [],\n );\n\n const getResizeHandleProps = useCallback(\n (column: SizableColumn): ResizeHandleProps => {\n const max = maxColumnWidthPx(column);\n const min = minColumnWidthPx(column);\n const current = currentColumnWidth(column);\n const label = column.label ?? column.key;\n const indicatorClass = showIndicator ? \"after:bg-lt-border\" : \"after:bg-transparent\";\n\n const maxWidthForHandle = (handle: HTMLDivElement): number =>\n maxColumnWidthForGrid({\n column,\n columnGapPx,\n columns,\n grid: resizeRootRef.current ?? handle.parentElement?.parentElement,\n leadingTracks,\n trailingTracks,\n });\n\n const resizeBy = (handle: HTMLDivElement, delta: number): void =>\n setColumnWidth(column, current + delta, maxWidthForHandle(handle));\n\n const finishDrag = (event: PointerEvent<HTMLDivElement>, releaseCapture: boolean): void => {\n const active = drag.current;\n\n if (active?.key !== column.key) {\n return;\n }\n\n drag.current = null;\n if (active.overrides !== null) {\n commitOverrides(active.overrides);\n }\n\n if (releaseCapture) {\n event.currentTarget.releasePointerCapture?.(event.pointerId);\n }\n };\n\n return {\n \"aria-label\": `Resize ${label}`,\n \"aria-orientation\": \"vertical\",\n \"aria-valuemax\": max,\n \"aria-valuemin\": min,\n \"aria-valuenow\": current,\n className: `absolute inset-y-0 right-0 hidden w-2 cursor-col-resize touch-none items-stretch justify-center md:flex after:my-1 after:w-px ${indicatorClass} hover:after:bg-lt-border focus-visible:outline-none focus-visible:after:bg-lt-ring`,\n onDoubleClick: () => resetColumnWidth(column),\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => {\n if (!enabled) {\n return;\n }\n\n const step = event.shiftKey ? 32 : 8;\n\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n resizeBy(event.currentTarget, -step);\n }\n\n if (event.key === \"ArrowRight\") {\n event.preventDefault();\n resizeBy(event.currentTarget, step);\n }\n\n if (event.key === \"Home\") {\n event.preventDefault();\n setColumnWidth(column, min);\n }\n\n if (event.key === \"End\") {\n event.preventDefault();\n const handleMax = maxWidthForHandle(event.currentTarget);\n setColumnWidth(column, handleMax, handleMax);\n }\n\n if (event.key === \"Enter\" || event.key === \"Escape\") {\n event.preventDefault();\n resetColumnWidth(column);\n }\n },\n onPointerDown: (event: PointerEvent<HTMLDivElement>) => {\n if (!enabled) {\n return;\n }\n\n const parentWidth = event.currentTarget.parentElement?.getBoundingClientRect().width ?? 0;\n drag.current = {\n key: column.key,\n maxWidth: maxWidthForHandle(event.currentTarget),\n overrides: null,\n startWidth: parentWidth > 0 ? parentWidth : current,\n startX: event.clientX,\n };\n event.currentTarget.setPointerCapture?.(event.pointerId);\n event.preventDefault();\n },\n onPointerMove: (event: PointerEvent<HTMLDivElement>) => {\n const active = drag.current;\n\n if (!enabled || active?.key !== column.key) {\n return;\n }\n\n const next = overridesWithColumnWidth(\n overridesRef.current,\n column,\n active.startWidth + event.clientX - active.startX,\n active.maxWidth,\n );\n\n active.overrides = next;\n overridesRef.current = next;\n applyTemplate(templateForOverrides(next));\n },\n onPointerUp: (event: PointerEvent<HTMLDivElement>) => {\n finishDrag(event, true);\n },\n onPointerCancel: (event: PointerEvent<HTMLDivElement>) => {\n finishDrag(event, true);\n },\n onLostPointerCapture: (event: PointerEvent<HTMLDivElement>) => {\n finishDrag(event, false);\n },\n role: \"separator\",\n tabIndex: 0,\n };\n },\n [\n columnGapPx,\n columns,\n currentColumnWidth,\n enabled,\n leadingTracks,\n applyTemplate,\n commitOverrides,\n overridesWithColumnWidth,\n resetColumnWidth,\n setColumnWidth,\n showIndicator,\n templateForOverrides,\n trailingTracks,\n ],\n );\n\n return {\n getResizeHandleProps,\n gridTemplateColumns,\n hasOverrides,\n resizeRootRef,\n resetColumns,\n resetColumnWidth,\n };\n}\n\nfunction maxColumnWidthForGrid({\n column,\n columnGapPx,\n columns,\n grid,\n leadingTracks,\n trailingTracks,\n}: {\n column: SizableColumn;\n columnGapPx: number;\n columns: SizableColumn[];\n grid: Element | null | undefined;\n leadingTracks: string[];\n trailingTracks: string[];\n}): number {\n const gridWidth = grid?.getBoundingClientRect().width ?? 0;\n\n if (gridWidth <= 0) {\n return maxColumnWidthPx(column);\n }\n\n const utilityWidth = [...leadingTracks, ...trailingTracks].reduce(\n (sum, track) => sum + fixedTrackWidthPx(track),\n 0,\n );\n const siblingMinWidth = columns.reduce(\n (sum, sibling) => (sibling.key === column.key ? sum : sum + minColumnWidthPx(sibling)),\n 0,\n );\n const trackCount = columns.length + leadingTracks.length + trailingTracks.length;\n const gapWidth = Math.max(0, trackCount - 1) * columnGapPx;\n const available = gridWidth - utilityWidth - siblingMinWidth - gapWidth;\n\n return Math.min(maxColumnWidthPx(column), Math.max(minColumnWidthPx(column), available));\n}\n\nfunction readStoredOverrides(\n storageKey: string | undefined,\n columns: SizableColumn[],\n): Record<string, number | undefined> {\n if (!storageKey || typeof window === \"undefined\") {\n return {};\n }\n\n try {\n const raw = window.localStorage.getItem(storageKey);\n\n if (raw === null) {\n return {};\n }\n\n const stored = JSON.parse(raw) as unknown;\n\n if (!isStoredColumnWidths(stored)) {\n removeStoredOverrides(storageKey);\n\n return {};\n }\n\n const overrides = sanitizeOverrides(stored.overrides, columns);\n\n if (Object.keys(overrides).length === 0) {\n removeStoredOverrides(storageKey);\n }\n\n return overrides;\n } catch {\n removeStoredOverrides(storageKey);\n\n return {};\n }\n}\n\nfunction writeStoredOverrides(\n storageKey: string | undefined,\n columnKeys: string[],\n overrides: Record<string, number | undefined>,\n): void {\n if (!storageKey || typeof window === \"undefined\") {\n return;\n }\n\n const stored: Record<string, number> = {};\n const knownKeys = new Set(columnKeys);\n\n for (const [key, value] of Object.entries(overrides)) {\n if (knownKeys.has(key) && typeof value === \"number\" && Number.isFinite(value)) {\n stored[key] = value;\n }\n }\n\n if (Object.keys(stored).length === 0) {\n removeStoredOverrides(storageKey);\n\n return;\n }\n\n try {\n window.localStorage.setItem(\n storageKey,\n JSON.stringify({\n columns: columnKeys,\n overrides: stored,\n }),\n );\n } catch {\n return;\n }\n}\n\nfunction removeStoredOverrides(storageKey: string): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n try {\n window.localStorage.removeItem(storageKey);\n } catch {\n return;\n }\n}\n\nfunction isStoredColumnWidths(value: unknown): value is StoredColumnWidths {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n\n const record = value as Record<string, unknown>;\n\n return (\n Array.isArray(record.columns) &&\n record.columns.every((column) => typeof column === \"string\") &&\n typeof record.overrides === \"object\" &&\n record.overrides !== null &&\n !Array.isArray(record.overrides)\n );\n}\n\nfunction sanitizeOverrides(\n overrides: Record<string, unknown>,\n columns: SizableColumn[],\n): Record<string, number | undefined> {\n const next: Record<string, number | undefined> = {};\n\n for (const column of columns) {\n const value = overrides[column.key];\n\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n continue;\n }\n\n next[column.key] = Math.min(\n maxColumnWidthPx(column),\n Math.max(minColumnWidthPx(column), value),\n );\n }\n\n return next;\n}\n\nfunction fixedTrackWidthPx(track: string): number {\n const value = track.trim();\n const px = value.match(/^([0-9.]+)px$/);\n\n if (px) {\n return Number.parseFloat(px[1]);\n }\n\n const rem = value.match(/^([0-9.]+)rem$/);\n\n if (rem) {\n return Number.parseFloat(rem[1]) * rootFontSizePx();\n }\n\n return 0;\n}\n\nfunction rootFontSizePx(): number {\n if (typeof window === \"undefined\") {\n return 16;\n }\n\n const parsed = Number.parseFloat(window.getComputedStyle(document.documentElement).fontSize);\n\n return Number.isFinite(parsed) && parsed > 0 ? parsed : 16;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-column-resizing.js","names":[],"sources":["../../../resources/js/core/hooks/use-column-resizing.ts"],"sourcesContent":["import type { HTMLAttributes, KeyboardEvent, PointerEvent } from \"react\";\nimport { useCallback, useMemo, useRef } from \"react\";\nimport { usePersistentState } from \"@lattice-php/lattice/lib/use-persistent-state\";\nimport {\n buildColumnGridTemplate,\n defaultColumnWidthPx,\n maxColumnWidthPx,\n minColumnWidthPx,\n type SizableColumn,\n} from \"./column-sizing\";\n\ntype DragState = {\n key: string;\n maxWidth: number;\n overrides: Record<string, number | undefined> | null;\n startWidth: number;\n startX: number;\n};\n\ntype ResizeHandleProps = HTMLAttributes<HTMLDivElement> & {\n \"aria-label\": string;\n \"aria-orientation\": \"vertical\";\n \"aria-valuemax\": number;\n \"aria-valuemin\": number;\n \"aria-valuenow\": number;\n role: \"separator\";\n tabIndex: number;\n};\n\nconst emptyTracks: string[] = [];\n\nexport function useColumnResizing({\n columnGapPx = 0,\n columns,\n enabled,\n leadingTracks = emptyTracks,\n showIndicator = false,\n storageKey,\n trailingTracks = emptyTracks,\n}: {\n columnGapPx?: number;\n columns: SizableColumn[];\n enabled: boolean;\n leadingTracks?: string[];\n showIndicator?: boolean;\n storageKey?: string;\n trailingTracks?: string[];\n}) {\n const columnKeys = useMemo(() => columns.map((column) => column.key), [columns]);\n const [overrides, setOverrides] = usePersistentState<Record<string, number | undefined>>(\n storageKey ?? \"\",\n {},\n {\n enabled: Boolean(storageKey),\n parse: (raw) => parseStoredOverrides(raw, columns),\n serialize: (value) => serializeOverrides(value, columnKeys),\n },\n );\n const overridesRef = useRef(overrides);\n const drag = useRef<DragState | null>(null);\n const resizeRootRef = useRef<HTMLDivElement | null>(null);\n\n const templateForOverrides = useCallback(\n (nextOverrides: Record<string, number | undefined>): string =>\n buildColumnGridTemplate({\n columns,\n leadingTracks,\n trailingTracks,\n overrides: enabled ? nextOverrides : {},\n }),\n [columns, enabled, leadingTracks, trailingTracks],\n );\n\n const gridTemplateColumns = useMemo(\n () => templateForOverrides(overrides),\n [overrides, templateForOverrides],\n );\n\n const applyTemplate = useCallback((template: string): void => {\n const root = resizeRootRef.current;\n\n if (!root) {\n return;\n }\n\n root.style.gridTemplateColumns = template;\n root.style.setProperty(\"--lattice-table-columns\", template);\n }, []);\n\n const commitOverrides = useCallback(\n (next: Record<string, number | undefined>) => {\n overridesRef.current = next;\n setOverrides(next);\n applyTemplate(templateForOverrides(next));\n },\n [applyTemplate, setOverrides, templateForOverrides],\n );\n\n const overridesWithColumnWidth = useCallback(\n (\n current: Record<string, number | undefined>,\n column: SizableColumn,\n width: number,\n maxWidth?: number,\n ): Record<string, number | undefined> => ({\n ...current,\n [column.key]: Math.min(\n maxWidth ?? maxColumnWidthPx,\n Math.max(minColumnWidthPx(column), width),\n ),\n }),\n [],\n );\n\n const setColumnWidth = useCallback(\n (column: SizableColumn, width: number, maxWidth?: number) => {\n commitOverrides(overridesWithColumnWidth(overridesRef.current, column, width, maxWidth));\n },\n [commitOverrides, overridesWithColumnWidth],\n );\n\n const resetColumnWidth = useCallback(\n (column: SizableColumn) => {\n const next = { ...overridesRef.current };\n delete next[column.key];\n\n commitOverrides(next);\n },\n [commitOverrides],\n );\n\n const resetColumns = useCallback(() => {\n commitOverrides({});\n }, [commitOverrides]);\n\n const hasOverrides =\n enabled && Object.values(overrides).some((width) => typeof width === \"number\");\n\n const currentColumnWidth = useCallback(\n (column: SizableColumn): number =>\n overridesRef.current[column.key] ?? defaultColumnWidthPx(column),\n [],\n );\n\n const getResizeHandleProps = useCallback(\n (column: SizableColumn): ResizeHandleProps => {\n const max = maxColumnWidthPx;\n const min = minColumnWidthPx(column);\n const current = currentColumnWidth(column);\n const label = column.label ?? column.key;\n const indicatorClass = showIndicator ? \"after:bg-lt-border\" : \"after:bg-transparent\";\n\n const maxWidthForHandle = (handle: HTMLDivElement): number =>\n maxColumnWidthForGrid({\n column,\n columnGapPx,\n columns,\n grid: resizeRootRef.current ?? handle.parentElement?.parentElement,\n leadingTracks,\n trailingTracks,\n });\n\n const resizeBy = (handle: HTMLDivElement, delta: number): void =>\n setColumnWidth(column, current + delta, maxWidthForHandle(handle));\n\n const finishDrag = (event: PointerEvent<HTMLDivElement>, releaseCapture: boolean): void => {\n const active = drag.current;\n\n if (active?.key !== column.key) {\n return;\n }\n\n drag.current = null;\n if (active.overrides !== null) {\n commitOverrides(active.overrides);\n }\n\n if (releaseCapture) {\n event.currentTarget.releasePointerCapture?.(event.pointerId);\n }\n };\n\n return {\n \"aria-label\": `Resize ${label}`,\n \"aria-orientation\": \"vertical\",\n \"aria-valuemax\": max,\n \"aria-valuemin\": min,\n \"aria-valuenow\": current,\n className: `absolute inset-y-0 right-0 hidden w-2 cursor-col-resize touch-none items-stretch justify-center md:flex after:my-1 after:w-px ${indicatorClass} hover:after:bg-lt-border focus-visible:outline-none focus-visible:after:bg-lt-ring`,\n onDoubleClick: () => resetColumnWidth(column),\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => {\n if (!enabled) {\n return;\n }\n\n const step = event.shiftKey ? 32 : 8;\n\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n resizeBy(event.currentTarget, -step);\n }\n\n if (event.key === \"ArrowRight\") {\n event.preventDefault();\n resizeBy(event.currentTarget, step);\n }\n\n if (event.key === \"Home\") {\n event.preventDefault();\n setColumnWidth(column, min);\n }\n\n if (event.key === \"End\") {\n event.preventDefault();\n const handleMax = maxWidthForHandle(event.currentTarget);\n setColumnWidth(column, handleMax, handleMax);\n }\n\n if (event.key === \"Enter\" || event.key === \"Escape\") {\n event.preventDefault();\n resetColumnWidth(column);\n }\n },\n onPointerDown: (event: PointerEvent<HTMLDivElement>) => {\n if (!enabled) {\n return;\n }\n\n const parentWidth = event.currentTarget.parentElement?.getBoundingClientRect().width ?? 0;\n drag.current = {\n key: column.key,\n maxWidth: maxWidthForHandle(event.currentTarget),\n overrides: null,\n startWidth: parentWidth > 0 ? parentWidth : current,\n startX: event.clientX,\n };\n event.currentTarget.setPointerCapture?.(event.pointerId);\n event.preventDefault();\n },\n onPointerMove: (event: PointerEvent<HTMLDivElement>) => {\n const active = drag.current;\n\n if (!enabled || active?.key !== column.key) {\n return;\n }\n\n const next = overridesWithColumnWidth(\n overridesRef.current,\n column,\n active.startWidth + event.clientX - active.startX,\n active.maxWidth,\n );\n\n active.overrides = next;\n overridesRef.current = next;\n applyTemplate(templateForOverrides(next));\n },\n onPointerUp: (event: PointerEvent<HTMLDivElement>) => {\n finishDrag(event, true);\n },\n onPointerCancel: (event: PointerEvent<HTMLDivElement>) => {\n finishDrag(event, true);\n },\n onLostPointerCapture: (event: PointerEvent<HTMLDivElement>) => {\n finishDrag(event, false);\n },\n role: \"separator\",\n tabIndex: 0,\n };\n },\n [\n columnGapPx,\n columns,\n currentColumnWidth,\n enabled,\n leadingTracks,\n applyTemplate,\n commitOverrides,\n overridesWithColumnWidth,\n resetColumnWidth,\n setColumnWidth,\n showIndicator,\n templateForOverrides,\n trailingTracks,\n ],\n );\n\n return {\n getResizeHandleProps,\n gridTemplateColumns,\n hasOverrides,\n resizeRootRef,\n resetColumns,\n resetColumnWidth,\n };\n}\n\nfunction maxColumnWidthForGrid({\n column,\n columnGapPx,\n columns,\n grid,\n leadingTracks,\n trailingTracks,\n}: {\n column: SizableColumn;\n columnGapPx: number;\n columns: SizableColumn[];\n grid: Element | null | undefined;\n leadingTracks: string[];\n trailingTracks: string[];\n}): number {\n const gridWidth = grid?.getBoundingClientRect().width ?? 0;\n\n if (gridWidth <= 0) {\n return maxColumnWidthPx;\n }\n\n const utilityWidth = [...leadingTracks, ...trailingTracks].reduce(\n (sum, track) => sum + fixedTrackWidthPx(track),\n 0,\n );\n const siblingMinWidth = columns.reduce(\n (sum, sibling) => (sibling.key === column.key ? sum : sum + minColumnWidthPx(sibling)),\n 0,\n );\n const trackCount = columns.length + leadingTracks.length + trailingTracks.length;\n const gapWidth = Math.max(0, trackCount - 1) * columnGapPx;\n const available = gridWidth - utilityWidth - siblingMinWidth - gapWidth;\n\n return Math.min(maxColumnWidthPx, Math.max(minColumnWidthPx(column), available));\n}\n\nfunction parseStoredOverrides(\n raw: string,\n columns: SizableColumn[],\n): Record<string, number | undefined> {\n const stored = JSON.parse(raw) as { overrides?: unknown };\n const overrides = stored?.overrides;\n\n if (typeof overrides !== \"object\" || overrides === null || Array.isArray(overrides)) {\n throw new Error(\"unexpected stored column widths shape\");\n }\n\n const sanitized = sanitizeOverrides(overrides as Record<string, unknown>, columns);\n\n if (Object.keys(sanitized).length === 0) {\n throw new Error(\"stored column widths hold no usable overrides\");\n }\n\n return sanitized;\n}\n\nfunction serializeOverrides(\n overrides: Record<string, number | undefined>,\n columnKeys: string[],\n): string | null {\n const stored: Record<string, number> = {};\n const knownKeys = new Set(columnKeys);\n\n for (const [key, value] of Object.entries(overrides)) {\n if (knownKeys.has(key) && typeof value === \"number\" && Number.isFinite(value)) {\n stored[key] = value;\n }\n }\n\n if (Object.keys(stored).length === 0) {\n return null;\n }\n\n return JSON.stringify({ overrides: stored });\n}\n\nfunction sanitizeOverrides(\n overrides: Record<string, unknown>,\n columns: SizableColumn[],\n): Record<string, number | undefined> {\n const next: Record<string, number | undefined> = {};\n\n for (const column of columns) {\n const value = overrides[column.key];\n\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n continue;\n }\n\n next[column.key] = Math.min(maxColumnWidthPx, Math.max(minColumnWidthPx(column), value));\n }\n\n return next;\n}\n\nfunction fixedTrackWidthPx(track: string): number {\n const value = track.trim();\n const px = value.match(/^([0-9.]+)px$/);\n\n if (px) {\n return Number.parseFloat(px[1]);\n }\n\n const rem = value.match(/^([0-9.]+)rem$/);\n\n if (rem) {\n return Number.parseFloat(rem[1]) * rootFontSizePx();\n }\n\n return 0;\n}\n\nfunction rootFontSizePx(): number {\n if (typeof window === \"undefined\") {\n return 16;\n }\n\n const parsed = Number.parseFloat(window.getComputedStyle(document.documentElement).fontSize);\n\n return Number.isFinite(parsed) && parsed > 0 ? parsed : 16;\n}\n"],"mappings":"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"}
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ApiError, apiFetch, apiJson,
|
|
1
|
+
export { ApiError, apiFetch, apiJson, invalidateRemoteToken, remoteFetch, remoteJson, remoteToken, xsrfToken, } from './api.js';
|
|
2
2
|
export type { ApiInit, BrowserToken, RemoteAccess, RemoteInit } from './api.js';
|
|
3
3
|
export { CollapsedContext, useCollapsed } from './collapsed-context.js';
|
|
4
4
|
export { LATTICE_REF_HEADER, withRefHeader } from './component-ref.js';
|
package/dist/core/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LATTICE_REF_HEADER, withRefHeader } from "./component-ref.js";
|
|
2
2
|
import { withHeaders } from "./headers.js";
|
|
3
|
-
import { ApiError, apiFetch, apiJson,
|
|
3
|
+
import { ApiError, apiFetch, apiJson, invalidateRemoteToken, remoteFetch, remoteJson, remoteToken, xsrfToken } from "./api.js";
|
|
4
4
|
import { dataBindings, isRecord, materializeNode, materializeProps, materializeSchema, rowValue } from "./materialize.js";
|
|
5
5
|
import { createPlugin, createRegistry, eagerComponent, extendRegistry, lazyComponent } from "./registry.js";
|
|
6
6
|
import { RegistryContext, setDefaultRegistry, useColumnRegistry, useComponentRegistry, useEffectHandlerRegistry } from "./registry-context.js";
|
|
@@ -10,4 +10,4 @@ import { CollapsedContext, useCollapsed } from "./collapsed-context.js";
|
|
|
10
10
|
import { RenderNode, Renderer } from "./renderer.js";
|
|
11
11
|
import { nodeIdentity } from "./test-id.js";
|
|
12
12
|
import { usePersistentState } from "../lib/use-persistent-state.js";
|
|
13
|
-
export { ApiError, CollapsedContext, LATTICE_REF_HEADER, RegistryContext, RenderNode, Renderer, apiFetch, apiJson,
|
|
13
|
+
export { ApiError, CollapsedContext, LATTICE_REF_HEADER, RegistryContext, RenderNode, Renderer, apiFetch, apiJson, cn, createPlugin, createRegistry, dataBindings, eagerComponent, extendRegistry, invalidateRemoteToken, isRecord, lazyComponent, materializeNode, materializeProps, materializeSchema, nodeIdentity, remoteFetch, remoteJson, remoteToken, rowValue, setDefaultRegistry, toNodes, useCollapsed, useColumnRegistry, useComponentRegistry, useEffectHandlerRegistry, usePersistentState, withHeaders, withRefHeader, xsrfToken };
|
package/dist/core/registry.d.ts
CHANGED
|
@@ -9,7 +9,6 @@ export type EagerComponentRegistration = {
|
|
|
9
9
|
};
|
|
10
10
|
export type LazyComponentRegistration = {
|
|
11
11
|
component: LazyExoticComponent<RendererComponent>;
|
|
12
|
-
fallback?: RendererComponent;
|
|
13
12
|
load: () => Promise<RendererComponentModule>;
|
|
14
13
|
mode: "lazy";
|
|
15
14
|
};
|
|
@@ -32,11 +31,8 @@ export type Registry = {
|
|
|
32
31
|
columns: ColumnRegistry;
|
|
33
32
|
effects: EffectHandlerRegistry;
|
|
34
33
|
};
|
|
35
|
-
export type LazyComponentOptions<TType extends string> = {
|
|
36
|
-
fallback?: RendererComponent<TType>;
|
|
37
|
-
};
|
|
38
34
|
export declare function eagerComponent<TType extends string>(component: RendererComponent<TType>): EagerComponentRegistration;
|
|
39
|
-
export declare function lazyComponent<TType extends string>(load: () => Promise<RendererComponentModule<TType
|
|
35
|
+
export declare function lazyComponent<TType extends string>(load: () => Promise<RendererComponentModule<TType>>): LazyComponentRegistration;
|
|
40
36
|
export declare function createPlugin(plugin: Plugin): Plugin;
|
|
41
37
|
export declare function createRegistry(...plugins: Plugin[]): Registry;
|
|
42
38
|
export declare function extendRegistry(registry: Registry, ...plugins: Plugin[]): Registry;
|
package/dist/core/registry.js
CHANGED
|
@@ -6,11 +6,10 @@ function eagerComponent(component) {
|
|
|
6
6
|
mode: "eager"
|
|
7
7
|
};
|
|
8
8
|
}
|
|
9
|
-
function lazyComponent(load
|
|
9
|
+
function lazyComponent(load) {
|
|
10
10
|
const erasedLoader = load;
|
|
11
11
|
return {
|
|
12
12
|
component: lazy(erasedLoader),
|
|
13
|
-
fallback: options.fallback,
|
|
14
13
|
load: erasedLoader,
|
|
15
14
|
mode: "lazy"
|
|
16
15
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","names":[],"sources":["../../resources/js/core/registry.ts"],"sourcesContent":["import { lazy } from \"react\";\nimport type { LazyExoticComponent } from \"react\";\nimport type { RendererComponent, RendererComponentModule } from \"./types\";\nimport type { EffectHandlerRegistry } from \"@lattice-php/lattice/effects/registry\";\nimport type { ColumnRegistry } from \"@lattice-php/lattice/table/registry\";\nimport type { ComponentPropsMap } from \"@lattice-php/lattice/types/generated\";\n\nexport type EagerComponentRegistration = {\n component: RendererComponent;\n mode: \"eager\";\n};\n\nexport type LazyComponentRegistration = {\n component: LazyExoticComponent<RendererComponent>;\n
|
|
1
|
+
{"version":3,"file":"registry.js","names":[],"sources":["../../resources/js/core/registry.ts"],"sourcesContent":["import { lazy } from \"react\";\nimport type { LazyExoticComponent } from \"react\";\nimport type { RendererComponent, RendererComponentModule } from \"./types\";\nimport type { EffectHandlerRegistry } from \"@lattice-php/lattice/effects/registry\";\nimport type { ColumnRegistry } from \"@lattice-php/lattice/table/registry\";\nimport type { ComponentPropsMap } from \"@lattice-php/lattice/types/generated\";\n\nexport type EagerComponentRegistration = {\n component: RendererComponent;\n mode: \"eager\";\n};\n\nexport type LazyComponentRegistration = {\n component: LazyExoticComponent<RendererComponent>;\n load: () => Promise<RendererComponentModule>;\n mode: \"lazy\";\n};\n\nexport type ComponentRegistration = EagerComponentRegistration | LazyComponentRegistration;\n\nexport type ComponentRegistry = Record<string, ComponentRegistration>;\n\nexport type ComponentRegistryFor<TTypes extends keyof ComponentPropsMap & string> = Record<\n TTypes,\n ComponentRegistration\n>;\n\nexport type PluginI18n = {\n /** i18next namespace the plugin's components translate under. */\n namespace: string;\n};\n\nexport type Plugin = {\n name: string;\n components?: ComponentRegistry;\n columns?: ColumnRegistry;\n effects?: EffectHandlerRegistry;\n i18n?: PluginI18n;\n};\n\nexport type Registry = {\n components: ComponentRegistry;\n columns: ColumnRegistry;\n effects: EffectHandlerRegistry;\n};\n\nexport function eagerComponent<TType extends string>(\n component: RendererComponent<TType>,\n): EagerComponentRegistration {\n return {\n component: component as unknown as RendererComponent,\n mode: \"eager\",\n };\n}\n\nexport function lazyComponent<TType extends string>(\n load: () => Promise<RendererComponentModule<TType>>,\n): LazyComponentRegistration {\n const erasedLoader = load as unknown as () => Promise<RendererComponentModule>;\n\n return {\n component: lazy(erasedLoader),\n load: erasedLoader,\n mode: \"lazy\",\n };\n}\n\nexport function createPlugin(plugin: Plugin): Plugin {\n return plugin;\n}\n\nexport function createRegistry(...plugins: Plugin[]): Registry {\n return plugins.reduce<Registry>(\n (registry, plugin) => ({\n components: { ...registry.components, ...plugin.components },\n columns: { ...registry.columns, ...plugin.columns },\n effects: { ...registry.effects, ...plugin.effects },\n }),\n { components: {}, columns: {}, effects: {} },\n );\n}\n\nexport function extendRegistry(registry: Registry, ...plugins: Plugin[]): Registry {\n const merged = createRegistry(...plugins);\n\n return {\n components: { ...registry.components, ...merged.components },\n columns: { ...registry.columns, ...merged.columns },\n effects: { ...registry.effects, ...merged.effects },\n };\n}\n"],"mappings":";;AA8CA,SAAgB,eACd,WAC4B;CAC5B,OAAO;EACM;EACX,MAAM;CACR;AACF;AAEA,SAAgB,cACd,MAC2B;CAC3B,MAAM,eAAe;CAErB,OAAO;EACL,WAAW,KAAK,YAAY;EAC5B,MAAM;EACN,MAAM;CACR;AACF;AAEA,SAAgB,aAAa,QAAwB;CACnD,OAAO;AACT;AAEA,SAAgB,eAAe,GAAG,SAA6B;CAC7D,OAAO,QAAQ,QACZ,UAAU,YAAY;EACrB,YAAY;GAAE,GAAG,SAAS;GAAY,GAAG,OAAO;EAAW;EAC3D,SAAS;GAAE,GAAG,SAAS;GAAS,GAAG,OAAO;EAAQ;EAClD,SAAS;GAAE,GAAG,SAAS;GAAS,GAAG,OAAO;EAAQ;CACpD,IACA;EAAE,YAAY,CAAC;EAAG,SAAS,CAAC;EAAG,SAAS,CAAC;CAAE,CAC7C;AACF;AAEA,SAAgB,eAAe,UAAoB,GAAG,SAA6B;CACjF,MAAM,SAAS,eAAe,GAAG,OAAO;CAExC,OAAO;EACL,YAAY;GAAE,GAAG,SAAS;GAAY,GAAG,OAAO;EAAW;EAC3D,SAAS;GAAE,GAAG,SAAS;GAAS,GAAG,OAAO;EAAQ;EAClD,SAAS;GAAE,GAAG,SAAS;GAAS,GAAG,OAAO;EAAQ;CACpD;AACF"}
|