@lilaquadrat/frontend 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +132 -0
- package/dist/auth.d.ts +194 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +280 -0
- package/dist/auth.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/AuthCallbacks.d.ts +29 -0
- package/dist/interfaces/AuthCallbacks.d.ts.map +1 -0
- package/dist/interfaces/AuthCallbacks.js +2 -0
- package/dist/interfaces/AuthCallbacks.js.map +1 -0
- package/dist/interfaces/AuthInitOptions.d.ts +15 -0
- package/dist/interfaces/AuthInitOptions.d.ts.map +1 -0
- package/dist/interfaces/AuthInitOptions.js +2 -0
- package/dist/interfaces/AuthInitOptions.js.map +1 -0
- package/dist/interfaces/AuthOptions.d.ts +21 -0
- package/dist/interfaces/AuthOptions.d.ts.map +1 -0
- package/dist/interfaces/AuthOptions.js +2 -0
- package/dist/interfaces/AuthOptions.js.map +1 -0
- package/dist/interfaces/KeycloakClient.d.ts +36 -0
- package/dist/interfaces/KeycloakClient.d.ts.map +1 -0
- package/dist/interfaces/KeycloakClient.js +2 -0
- package/dist/interfaces/KeycloakClient.js.map +1 -0
- package/dist/interfaces/KeycloakRedirectOptions.d.ts +13 -0
- package/dist/interfaces/KeycloakRedirectOptions.d.ts.map +1 -0
- package/dist/interfaces/KeycloakRedirectOptions.js +2 -0
- package/dist/interfaces/KeycloakRedirectOptions.js.map +1 -0
- package/dist/interfaces/KeycloakSilentCheckOptions.d.ts +28 -0
- package/dist/interfaces/KeycloakSilentCheckOptions.d.ts.map +1 -0
- package/dist/interfaces/KeycloakSilentCheckOptions.js +2 -0
- package/dist/interfaces/KeycloakSilentCheckOptions.js.map +1 -0
- package/dist/resize.d.ts +165 -0
- package/dist/resize.d.ts.map +1 -0
- package/dist/resize.js +249 -0
- package/dist/resize.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application-specific state hooks used by {@link Auth}.
|
|
3
|
+
*
|
|
4
|
+
* Implement these callbacks with any state mechanism, including plain objects,
|
|
5
|
+
* Redux, Pinia, Vuex, React state, or framework-independent stores.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* const callbacks: AuthCallbacks = {
|
|
10
|
+
* setToken: (token) => session.token = token,
|
|
11
|
+
* isSessionLoaded: () => session.user !== undefined,
|
|
12
|
+
* onAuthenticated: () => session.loadUser(),
|
|
13
|
+
* onUnauthenticated: () => session.reset(),
|
|
14
|
+
* };
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export interface AuthCallbacks {
|
|
18
|
+
/** Stores the active token, or clears it when the user is no longer authenticated. */
|
|
19
|
+
setToken(token: string | null): void;
|
|
20
|
+
/** Returns whether the host app has already loaded the current authenticated session. */
|
|
21
|
+
isSessionLoaded?(): boolean;
|
|
22
|
+
/** Loads user data and permissions after an authenticated session is established. */
|
|
23
|
+
onAuthenticated?(): Promise<void> | void;
|
|
24
|
+
/** Clears user-specific application state after logout or token-refresh failure. */
|
|
25
|
+
onUnauthenticated?(): Promise<void> | void;
|
|
26
|
+
/** Receives token-refresh failures raised from Keycloak's expiration callback. */
|
|
27
|
+
onError?(error: unknown): void;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=AuthCallbacks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthCallbacks.d.ts","sourceRoot":"","sources":["../../src/interfaces/AuthCallbacks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,aAAa;IAC5B,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACrC,yFAAyF;IACzF,eAAe,CAAC,IAAI,OAAO,CAAC;IAC5B,qFAAqF;IACrF,eAAe,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACzC,oFAAoF;IACpF,iBAAiB,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC3C,kFAAkF;IAClF,OAAO,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CAChC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthCallbacks.js","sourceRoot":"","sources":["../../src/interfaces/AuthCallbacks.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Values supplied to {@link Auth.init} for a single authentication initialization.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* await auth.init({ development: false, keycloakConfig: { url, realm, clientId } });
|
|
7
|
+
* ```
|
|
8
|
+
*/
|
|
9
|
+
export interface AuthInitOptions<KeycloakConfiguration> {
|
|
10
|
+
/** Enables local development authentication without constructing a Keycloak client. */
|
|
11
|
+
development: boolean;
|
|
12
|
+
/** Configuration forwarded unchanged to `AuthOptions.createKeycloak` in production. */
|
|
13
|
+
keycloakConfig?: KeycloakConfiguration;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=AuthInitOptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthInitOptions.d.ts","sourceRoot":"","sources":["../../src/interfaces/AuthInitOptions.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe,CAAC,qBAAqB;IACpD,uFAAuF;IACvF,WAAW,EAAE,OAAO,CAAC;IACrB,uFAAuF;IACvF,cAAc,CAAC,EAAE,qBAAqB,CAAC;CACxC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthInitOptions.js","sourceRoot":"","sources":["../../src/interfaces/AuthInitOptions.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AuthCallbacks } from './AuthCallbacks.js';
|
|
2
|
+
import type { KeycloakClient } from './KeycloakClient.js';
|
|
3
|
+
/**
|
|
4
|
+
* Values supplied once when constructing an {@link Auth} instance.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* const options: AuthOptions<KeycloakConfig> = { callbacks, createKeycloak: (config) => new Keycloak(config) };
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export interface AuthOptions<KeycloakConfiguration> {
|
|
12
|
+
/** Application callbacks that connect authentication changes to host state. */
|
|
13
|
+
callbacks: AuthCallbacks;
|
|
14
|
+
/** Builds the Keycloak client from the configuration supplied to `Auth.init`. */
|
|
15
|
+
createKeycloak?(configuration: KeycloakConfiguration): KeycloakClient;
|
|
16
|
+
/** Token used by development mode. Defaults to `DEVTOKEN`. */
|
|
17
|
+
developmentToken?: string;
|
|
18
|
+
/** Application origin used for Keycloak callback URLs. Defaults to `window.location.origin`. */
|
|
19
|
+
origin?: string;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=AuthOptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthOptions.d.ts","sourceRoot":"","sources":["../../src/interfaces/AuthOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW,CAAC,qBAAqB;IAChD,+EAA+E;IAC/E,SAAS,EAAE,aAAa,CAAC;IACzB,iFAAiF;IACjF,cAAc,CAAC,CAAC,aAAa,EAAE,qBAAqB,GAAG,cAAc,CAAC;IACtE,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gGAAgG;IAChG,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthOptions.js","sourceRoot":"","sources":["../../src/interfaces/AuthOptions.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { KeycloakRedirectOptions } from './KeycloakRedirectOptions.js';
|
|
2
|
+
import type { KeycloakSilentCheckOptions } from './KeycloakSilentCheckOptions.js';
|
|
3
|
+
/**
|
|
4
|
+
* Minimal Keycloak client contract consumed by {@link Auth}.
|
|
5
|
+
*
|
|
6
|
+
* Use a `keycloak-js` instance directly, or adapt another authentication client
|
|
7
|
+
* to this shape in `AuthOptions.createKeycloak`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* createKeycloak: (configuration): KeycloakClient => new Keycloak(configuration)
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export interface KeycloakClient {
|
|
15
|
+
/** Whether the client currently has an authenticated session. */
|
|
16
|
+
authenticated?: boolean;
|
|
17
|
+
/** Current access token, populated after initialization or a token refresh. */
|
|
18
|
+
token?: string;
|
|
19
|
+
/** Called by Keycloak after the user logs out in another browser context. */
|
|
20
|
+
onAuthLogout?: () => void;
|
|
21
|
+
/** Called by Keycloak when its access token expires. */
|
|
22
|
+
onTokenExpired?: () => void;
|
|
23
|
+
/** Removes the token held by the client after a refresh failure. */
|
|
24
|
+
clearToken(): void;
|
|
25
|
+
/** Initializes Keycloak and silently checks for an existing session. */
|
|
26
|
+
init(options: KeycloakSilentCheckOptions): Promise<boolean>;
|
|
27
|
+
/** Refreshes the token when it expires within the requested number of seconds. */
|
|
28
|
+
updateToken(minValidity: number): Promise<boolean>;
|
|
29
|
+
/** Redirects the user to Keycloak's login page. */
|
|
30
|
+
login(options: KeycloakRedirectOptions): Promise<unknown> | unknown;
|
|
31
|
+
/** Redirects the user to Keycloak's logout page. */
|
|
32
|
+
logout(options: KeycloakRedirectOptions): Promise<unknown> | unknown;
|
|
33
|
+
/** Redirects the user to Keycloak's registration page. */
|
|
34
|
+
register(options: KeycloakRedirectOptions): Promise<unknown> | unknown;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=KeycloakClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeycloakClient.d.ts","sourceRoot":"","sources":["../../src/interfaces/KeycloakClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAC5E,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAElF;;;;;;;;;;GAUG;AACH,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,oEAAoE;IACpE,UAAU,IAAI,IAAI,CAAC;IACnB,wEAAwE;IACxE,IAAI,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,kFAAkF;IAClF,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,mDAAmD;IACnD,KAAK,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACpE,oDAAoD;IACpD,MAAM,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACrE,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CACxE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeycloakClient.js","sourceRoot":"","sources":["../../src/interfaces/KeycloakClient.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options passed to Keycloak when starting a login, registration, or logout redirect.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* const redirect: KeycloakRedirectOptions = { redirectUri: 'https://app.example.com/login/callback' };
|
|
7
|
+
* ```
|
|
8
|
+
*/
|
|
9
|
+
export interface KeycloakRedirectOptions {
|
|
10
|
+
/** Absolute URL to which Keycloak returns the browser after completing the action. */
|
|
11
|
+
redirectUri: string;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=KeycloakRedirectOptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeycloakRedirectOptions.d.ts","sourceRoot":"","sources":["../../src/interfaces/KeycloakRedirectOptions.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,uBAAuB;IACtC,sFAAsF;IACtF,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeycloakRedirectOptions.js","sourceRoot":"","sources":["../../src/interfaces/KeycloakRedirectOptions.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options used to initialize a Keycloak client with silent single-sign-on checking.
|
|
3
|
+
*
|
|
4
|
+
* `Auth.init` creates these values automatically; define this type only when
|
|
5
|
+
* implementing a custom `KeycloakClient`.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* async init(options: KeycloakSilentCheckOptions) {
|
|
10
|
+
* return keycloak.init(options);
|
|
11
|
+
* }
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export interface KeycloakSilentCheckOptions {
|
|
15
|
+
/** Checks the current session without forcing an authentication redirect. */
|
|
16
|
+
onLoad: 'check-sso';
|
|
17
|
+
/** Uses the authorization-code flow. */
|
|
18
|
+
flow: 'standard';
|
|
19
|
+
/** Requires PKCE using SHA-256 for the authorization-code flow. */
|
|
20
|
+
pkceMethod: 'S256';
|
|
21
|
+
/** Requests the user's basic profile information. */
|
|
22
|
+
scope: 'profile';
|
|
23
|
+
/** URL of the hosted Keycloak silent-check HTML document. */
|
|
24
|
+
silentCheckSsoRedirectUri: string;
|
|
25
|
+
/** Allows Keycloak's fallback when silent checking is unavailable. */
|
|
26
|
+
silentCheckSsoFallback: boolean;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=KeycloakSilentCheckOptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeycloakSilentCheckOptions.d.ts","sourceRoot":"","sources":["../../src/interfaces/KeycloakSilentCheckOptions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,0BAA0B;IACzC,6EAA6E;IAC7E,MAAM,EAAE,WAAW,CAAC;IACpB,wCAAwC;IACxC,IAAI,EAAE,UAAU,CAAC;IACjB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,KAAK,EAAE,SAAS,CAAC;IACjB,6DAA6D;IAC7D,yBAAyB,EAAE,MAAM,CAAC;IAClC,sEAAsE;IACtE,sBAAsB,EAAE,OAAO,CAAC;CACjC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeycloakSilentCheckOptions.js","sourceRoot":"","sources":["../../src/interfaces/KeycloakSilentCheckOptions.ts"],"names":[],"mappings":""}
|
package/dist/resize.d.ts
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser viewport and CSS-media observer used by the shared resize singleton.
|
|
3
|
+
*
|
|
4
|
+
* Import the module-level `resize` instance instead of creating another instance
|
|
5
|
+
* in application code so all components consume the same reactive state.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import resize from '@lilaquadrat/frontend/resize';
|
|
10
|
+
*
|
|
11
|
+
* resize.debounceTime = 100;
|
|
12
|
+
* window.addEventListener('resized', () => console.log(resize.realHeight));
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare class Resize {
|
|
16
|
+
/**
|
|
17
|
+
* Pending debounce timer, exposed for applications that need to cancel it explicitly.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* clearTimeout(resize.timeout);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
timeout?: ReturnType<typeof setTimeout>;
|
|
25
|
+
/**
|
|
26
|
+
* Delay in milliseconds between the last native resize event and the final update.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* resize.debounceTime = 150;
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
debounceTime: number;
|
|
34
|
+
/**
|
|
35
|
+
* Event dispatched on `window` after viewport dimensions are updated.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* window.addEventListener('resized', () => updateLayout());
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
resizedEvent?: Event;
|
|
43
|
+
/**
|
|
44
|
+
* Event dispatched on `window` after the active CSS media name changes.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* window.addEventListener('media', () => updateNavigation(resize.media));
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
mediaEvent?: Event;
|
|
52
|
+
/**
|
|
53
|
+
* Controls whether the next native resize dispatches an immediate initial update.
|
|
54
|
+
*
|
|
55
|
+
* It is reset after the debounced update so resize consumers can respond at the
|
|
56
|
+
* start and end of each resize interaction.
|
|
57
|
+
*/
|
|
58
|
+
triggerStart: import("vue").Ref<boolean, boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* Browser window when available, or `null` during server-side rendering.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* if (resize.safeWindow.value) resize.trigger();
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
safeWindow: import("vue").ComputedRef<Window | null>;
|
|
68
|
+
/**
|
|
69
|
+
* Active media name read from the visible child of `#mediadetection`.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* if (resize.media === 'desktop') showSidebar();
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
get media(): string;
|
|
77
|
+
set media(value: string);
|
|
78
|
+
/**
|
|
79
|
+
* Current visual viewport height in pixels.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* element.style.height = `${resize.realHeight}px`;
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
get realHeight(): number;
|
|
87
|
+
/**
|
|
88
|
+
* Initializes viewport state and listens for browser resize events when running in a browser.
|
|
89
|
+
*
|
|
90
|
+
* Normally the module singleton handles this. Create an instance only for an
|
|
91
|
+
* isolated application or test environment.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* const isolatedResize = new Resize();
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
constructor();
|
|
99
|
+
/**
|
|
100
|
+
* Updates media and viewport state, then dispatches the `resized` window event.
|
|
101
|
+
*
|
|
102
|
+
* Pass `true` only for the immediate event at the beginning of a resize sequence.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* resize.trigger();
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
trigger(isStart?: boolean): void;
|
|
110
|
+
/**
|
|
111
|
+
* Reads the class of the visible child within `#mediadetection` and emits `media` when it changes.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* resize.getMediaQuery();
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
getMediaQuery(): void;
|
|
119
|
+
/**
|
|
120
|
+
* Debounces browser resize events while emitting one immediate initial update.
|
|
121
|
+
*
|
|
122
|
+
* Call this only when forwarding a custom resize source; the browser listener
|
|
123
|
+
* registered by the singleton already calls it for native resize events.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* visualViewport?.addEventListener('resize', () => resize.debounce());
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
debounce(): void;
|
|
131
|
+
private setViewportHeight;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Shared `Resize` instance initialized once when this module is imported in a browser.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* import resize from '@lilaquadrat/frontend/resize';
|
|
139
|
+
* console.log(resize.realHeight);
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
declare const resize: Resize;
|
|
143
|
+
/**
|
|
144
|
+
* Returns the shared reactive viewport state and its controlling singleton.
|
|
145
|
+
*
|
|
146
|
+
* Use `media`, `realHeight`, and `resized` in Vue components; use `plugin` only
|
|
147
|
+
* when manually triggering or configuring the shared resize observer.
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```ts
|
|
151
|
+
* import { useResize } from '@lilaquadrat/frontend/resize';
|
|
152
|
+
*
|
|
153
|
+
* const { media, realHeight } = useResize();
|
|
154
|
+
* // In a Vue template: {{ media }} / {{ realHeight }}
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
export declare function useResize(): {
|
|
158
|
+
realHeight: import("vue").Ref<number, number>;
|
|
159
|
+
media: import("vue").Ref<string, string>;
|
|
160
|
+
resized: import("vue").Ref<number, number>;
|
|
161
|
+
plugin: Resize;
|
|
162
|
+
};
|
|
163
|
+
export { resize };
|
|
164
|
+
export default resize;
|
|
165
|
+
//# sourceMappingURL=resize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resize.d.ts","sourceRoot":"","sources":["../src/resize.ts"],"names":[],"mappings":"AA+BA;;;;;;;;;;;;;GAaG;AACH,qBAAa,MAAM;IACjB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;IAExC;;;;;;;OAOG;IACH,YAAY,SAAM;IAElB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC;IAErB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,KAAK,CAAC;IAEnB;;;;;OAKG;IACH,YAAY,sCAAa;IAEzB;;;;;;;OAOG;IACH,UAAU,2CAAkF;IAE5F;;;;;;;OAOG;IACH,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAED;;;;;;;OAOG;IACH,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED;;;;;;;;;;OAUG;;IAcH;;;;;;;;;OASG;IACH,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI;IAShC;;;;;;;OAOG;IACH,aAAa,IAAI,IAAI;IAuBrB;;;;;;;;;;OAUG;IACH,QAAQ,IAAI,IAAI;IAUhB,OAAO,CAAC,iBAAiB;CAU1B;AAED;;;;;;;;GAQG;AACH,QAAA,MAAM,MAAM,QAAe,CAAC;AAE5B;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS;;;;;EAOxB;AAED,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,eAAe,MAAM,CAAC"}
|
package/dist/resize.js
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { computed, ref } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Vue-compatible browser resize state.
|
|
4
|
+
*
|
|
5
|
+
* Include `#mediadetection` in the page with one child displayed at each CSS
|
|
6
|
+
* breakpoint. The displayed child's class becomes the current media value.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```html
|
|
10
|
+
* <div id="mediadetection">
|
|
11
|
+
* <span class="mobile"></span>
|
|
12
|
+
* <span class="desktop"></span>
|
|
13
|
+
* </div>
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```css
|
|
18
|
+
* #mediadetection > span { display: none; }
|
|
19
|
+
* #mediadetection > .mobile { display: block; }
|
|
20
|
+
* @media (min-width: 768px) {
|
|
21
|
+
* #mediadetection > .mobile { display: none; }
|
|
22
|
+
* #mediadetection > .desktop { display: block; }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
const mediaReference = ref('mobile');
|
|
27
|
+
const resizedReference = ref(Date.now());
|
|
28
|
+
const realHeightReference = ref(0);
|
|
29
|
+
/**
|
|
30
|
+
* Browser viewport and CSS-media observer used by the shared resize singleton.
|
|
31
|
+
*
|
|
32
|
+
* Import the module-level `resize` instance instead of creating another instance
|
|
33
|
+
* in application code so all components consume the same reactive state.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import resize from '@lilaquadrat/frontend/resize';
|
|
38
|
+
*
|
|
39
|
+
* resize.debounceTime = 100;
|
|
40
|
+
* window.addEventListener('resized', () => console.log(resize.realHeight));
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export class Resize {
|
|
44
|
+
/**
|
|
45
|
+
* Pending debounce timer, exposed for applications that need to cancel it explicitly.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* clearTimeout(resize.timeout);
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
timeout;
|
|
53
|
+
/**
|
|
54
|
+
* Delay in milliseconds between the last native resize event and the final update.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* resize.debounceTime = 150;
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
debounceTime = 50;
|
|
62
|
+
/**
|
|
63
|
+
* Event dispatched on `window` after viewport dimensions are updated.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* window.addEventListener('resized', () => updateLayout());
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
resizedEvent;
|
|
71
|
+
/**
|
|
72
|
+
* Event dispatched on `window` after the active CSS media name changes.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* window.addEventListener('media', () => updateNavigation(resize.media));
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
mediaEvent;
|
|
80
|
+
/**
|
|
81
|
+
* Controls whether the next native resize dispatches an immediate initial update.
|
|
82
|
+
*
|
|
83
|
+
* It is reset after the debounced update so resize consumers can respond at the
|
|
84
|
+
* start and end of each resize interaction.
|
|
85
|
+
*/
|
|
86
|
+
triggerStart = ref(true);
|
|
87
|
+
/**
|
|
88
|
+
* Browser window when available, or `null` during server-side rendering.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* if (resize.safeWindow.value) resize.trigger();
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
safeWindow = computed(() => (typeof window === 'undefined' ? null : window));
|
|
96
|
+
/**
|
|
97
|
+
* Active media name read from the visible child of `#mediadetection`.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* if (resize.media === 'desktop') showSidebar();
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
get media() {
|
|
105
|
+
return mediaReference.value;
|
|
106
|
+
}
|
|
107
|
+
set media(value) {
|
|
108
|
+
mediaReference.value = value;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Current visual viewport height in pixels.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* element.style.height = `${resize.realHeight}px`;
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
get realHeight() {
|
|
119
|
+
return realHeightReference.value;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Initializes viewport state and listens for browser resize events when running in a browser.
|
|
123
|
+
*
|
|
124
|
+
* Normally the module singleton handles this. Create an instance only for an
|
|
125
|
+
* isolated application or test environment.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```ts
|
|
129
|
+
* const isolatedResize = new Resize();
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
constructor() {
|
|
133
|
+
const browserWindow = this.safeWindow.value;
|
|
134
|
+
if (!browserWindow)
|
|
135
|
+
return;
|
|
136
|
+
this.resizedEvent = new Event('resized');
|
|
137
|
+
this.mediaEvent = new Event('media');
|
|
138
|
+
realHeightReference.value = this.setViewportHeight();
|
|
139
|
+
this.getMediaQuery();
|
|
140
|
+
browserWindow.addEventListener('resize', () => this.debounce());
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Updates media and viewport state, then dispatches the `resized` window event.
|
|
144
|
+
*
|
|
145
|
+
* Pass `true` only for the immediate event at the beginning of a resize sequence.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```ts
|
|
149
|
+
* resize.trigger();
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
trigger(isStart) {
|
|
153
|
+
this.getMediaQuery();
|
|
154
|
+
realHeightReference.value = this.setViewportHeight();
|
|
155
|
+
resizedReference.value = Date.now();
|
|
156
|
+
if (this.resizedEvent)
|
|
157
|
+
this.safeWindow.value?.dispatchEvent(this.resizedEvent);
|
|
158
|
+
if (!isStart)
|
|
159
|
+
this.triggerStart.value = true;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Reads the class of the visible child within `#mediadetection` and emits `media` when it changes.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* resize.getMediaQuery();
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
getMediaQuery() {
|
|
170
|
+
if (typeof document === 'undefined')
|
|
171
|
+
return;
|
|
172
|
+
const element = document.getElementById('mediadetection');
|
|
173
|
+
if (!element)
|
|
174
|
+
return;
|
|
175
|
+
const child = Array.from(element.children).find((childElement) => this.safeWindow.value?.getComputedStyle(childElement).display === 'block');
|
|
176
|
+
if (!child)
|
|
177
|
+
return;
|
|
178
|
+
const childClass = child.getAttribute('class');
|
|
179
|
+
if (!childClass)
|
|
180
|
+
return;
|
|
181
|
+
const mediaChanged = this.media !== childClass;
|
|
182
|
+
this.media = childClass;
|
|
183
|
+
if (mediaChanged && this.mediaEvent) {
|
|
184
|
+
this.safeWindow.value?.dispatchEvent(this.mediaEvent);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Debounces browser resize events while emitting one immediate initial update.
|
|
189
|
+
*
|
|
190
|
+
* Call this only when forwarding a custom resize source; the browser listener
|
|
191
|
+
* registered by the singleton already calls it for native resize events.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* visualViewport?.addEventListener('resize', () => resize.debounce());
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
debounce() {
|
|
199
|
+
if (this.triggerStart.value) {
|
|
200
|
+
this.triggerStart.value = false;
|
|
201
|
+
this.trigger(true);
|
|
202
|
+
}
|
|
203
|
+
clearTimeout(this.timeout);
|
|
204
|
+
this.timeout = setTimeout(() => this.trigger(), this.debounceTime);
|
|
205
|
+
}
|
|
206
|
+
setViewportHeight() {
|
|
207
|
+
const browserWindow = this.safeWindow.value;
|
|
208
|
+
const height = browserWindow?.visualViewport?.height ?? browserWindow?.innerHeight ?? 0;
|
|
209
|
+
if (typeof document !== 'undefined') {
|
|
210
|
+
document.documentElement.style.setProperty('--vh', `${height}px`);
|
|
211
|
+
}
|
|
212
|
+
return height;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Shared `Resize` instance initialized once when this module is imported in a browser.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```ts
|
|
220
|
+
* import resize from '@lilaquadrat/frontend/resize';
|
|
221
|
+
* console.log(resize.realHeight);
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
const resize = new Resize();
|
|
225
|
+
/**
|
|
226
|
+
* Returns the shared reactive viewport state and its controlling singleton.
|
|
227
|
+
*
|
|
228
|
+
* Use `media`, `realHeight`, and `resized` in Vue components; use `plugin` only
|
|
229
|
+
* when manually triggering or configuring the shared resize observer.
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```ts
|
|
233
|
+
* import { useResize } from '@lilaquadrat/frontend/resize';
|
|
234
|
+
*
|
|
235
|
+
* const { media, realHeight } = useResize();
|
|
236
|
+
* // In a Vue template: {{ media }} / {{ realHeight }}
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
export function useResize() {
|
|
240
|
+
return {
|
|
241
|
+
realHeight: realHeightReference,
|
|
242
|
+
media: mediaReference,
|
|
243
|
+
resized: resizedReference,
|
|
244
|
+
plugin: resize,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
export { resize };
|
|
248
|
+
export default resize;
|
|
249
|
+
//# sourceMappingURL=resize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resize.js","sourceRoot":"","sources":["../src/resize.ts"],"names":[],"mappings":"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"}
|