@allurereport/web-commons 3.0.1 → 3.2.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.
Files changed (60) hide show
  1. package/dist/attachments.d.ts +27 -14
  2. package/dist/attachments.js +20 -45
  3. package/dist/charts/generateStatusAgePyramid.d.ts +5 -0
  4. package/dist/charts/{generateFBSUAgePyramid.js → generateStatusAgePyramid.js} +29 -17
  5. package/dist/charts/generators.d.ts +2 -1
  6. package/dist/charts/generators.js +59 -9
  7. package/dist/charts/types.d.ts +3 -3
  8. package/dist/charts/utils.js +1 -1
  9. package/dist/data.d.ts +5 -1
  10. package/dist/data.js +8 -2
  11. package/dist/filters/builders.d.ts +4 -0
  12. package/dist/filters/builders.js +160 -0
  13. package/dist/filters/index.d.ts +3 -0
  14. package/dist/filters/index.js +2 -0
  15. package/dist/filters/model.d.ts +39 -0
  16. package/dist/filters/model.js +1 -0
  17. package/dist/i18n.d.ts +10 -1
  18. package/dist/i18n.js +69 -20
  19. package/dist/index.d.ts +8 -0
  20. package/dist/index.js +8 -0
  21. package/dist/prose.d.ts +2 -0
  22. package/dist/prose.js +390 -0
  23. package/dist/sanitize.d.ts +1 -0
  24. package/dist/sanitize.js +4 -0
  25. package/dist/stores/loadableStore/constants.d.ts +1 -0
  26. package/dist/stores/loadableStore/constants.js +1 -0
  27. package/dist/stores/loadableStore/index.d.ts +3 -0
  28. package/dist/stores/loadableStore/index.js +2 -0
  29. package/dist/stores/loadableStore/store.d.ts +13 -0
  30. package/dist/stores/loadableStore/store.js +47 -0
  31. package/dist/stores/loadableStore/types.d.ts +7 -0
  32. package/dist/stores/loadableStore/types.js +1 -0
  33. package/dist/stores/loadableStore/utils.d.ts +2 -0
  34. package/dist/stores/loadableStore/utils.js +7 -0
  35. package/dist/stores/persister/index.d.ts +12 -0
  36. package/dist/stores/persister/index.js +36 -0
  37. package/dist/stores/router/index.d.ts +18 -0
  38. package/dist/stores/router/index.js +95 -0
  39. package/dist/stores/theme/actions.d.ts +3 -0
  40. package/dist/stores/theme/actions.js +30 -0
  41. package/dist/stores/theme/constants.d.ts +6 -0
  42. package/dist/stores/theme/constants.js +5 -0
  43. package/dist/stores/theme/index.d.ts +2 -0
  44. package/dist/stores/theme/index.js +2 -0
  45. package/dist/stores/theme/store.d.ts +8 -0
  46. package/dist/stores/theme/store.js +41 -0
  47. package/dist/stores/theme/types.d.ts +2 -0
  48. package/dist/stores/theme/types.js +1 -0
  49. package/dist/stores/theme/utils.d.ts +4 -0
  50. package/dist/stores/theme/utils.js +23 -0
  51. package/dist/stores/url/helpers.d.ts +12 -0
  52. package/dist/stores/url/helpers.js +74 -0
  53. package/dist/stores/url/index.d.ts +2 -0
  54. package/dist/stores/url/index.js +2 -0
  55. package/dist/stores/url/store.d.ts +19 -0
  56. package/dist/stores/url/store.js +45 -0
  57. package/dist/utils.d.ts +2 -0
  58. package/dist/utils.js +9 -0
  59. package/package.json +10 -5
  60. package/dist/charts/generateFBSUAgePyramid.d.ts +0 -5
@@ -0,0 +1,13 @@
1
+ import { LOADABLE_STORE_BRAND } from "./constants.js";
2
+ import type { LoadableStoreValue } from "./types.js";
3
+ export type LoadableStore<T> = ReturnType<typeof loadableStore<T>>;
4
+ export declare const loadableStore: <T>(options: {
5
+ initialState: T;
6
+ }) => {
7
+ readonly value: LoadableStoreValue<T>;
8
+ readonly onInit: () => void;
9
+ readonly onLoad: (silent?: boolean) => void;
10
+ readonly onSuccess: (data: T) => void;
11
+ readonly onError: (error?: Error) => void;
12
+ readonly brand: typeof LOADABLE_STORE_BRAND;
13
+ };
@@ -0,0 +1,47 @@
1
+ import { batch, computed, signal } from "@preact/signals-core";
2
+ import { LOADABLE_STORE_BRAND } from "./constants.js";
3
+ export const loadableStore = (options) => {
4
+ const loadingSignal = signal(false);
5
+ const errorSignal = signal(undefined);
6
+ const dataSignal = signal(options.initialState);
7
+ return {
8
+ value: {
9
+ data: computed(() => dataSignal.value),
10
+ loading: computed(() => loadingSignal.value),
11
+ error: computed(() => errorSignal.value),
12
+ errorMessage: computed(() => {
13
+ if (errorSignal.value) {
14
+ return errorSignal.value.message;
15
+ }
16
+ return undefined;
17
+ }),
18
+ },
19
+ onInit: () => {
20
+ batch(() => {
21
+ loadingSignal.value = false;
22
+ errorSignal.value = undefined;
23
+ dataSignal.value = options.initialState;
24
+ });
25
+ },
26
+ onLoad: (silent = false) => {
27
+ batch(() => {
28
+ loadingSignal.value = !silent;
29
+ errorSignal.value = undefined;
30
+ });
31
+ },
32
+ onSuccess: (data) => {
33
+ batch(() => {
34
+ loadingSignal.value = false;
35
+ errorSignal.value = undefined;
36
+ dataSignal.value = data;
37
+ });
38
+ },
39
+ onError: (error = new Error("Unknown error")) => {
40
+ batch(() => {
41
+ loadingSignal.value = false;
42
+ errorSignal.value = error;
43
+ });
44
+ },
45
+ brand: LOADABLE_STORE_BRAND,
46
+ };
47
+ };
@@ -0,0 +1,7 @@
1
+ import type { ReadonlySignal } from "@preact/signals-core";
2
+ export type LoadableStoreValue<T> = {
3
+ error: ReadonlySignal<Error | undefined>;
4
+ errorMessage: ReadonlySignal<string | undefined>;
5
+ loading: ReadonlySignal<boolean>;
6
+ data: ReadonlySignal<T>;
7
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { LoadableStore } from "./store.js";
2
+ export declare const isLoadableStore: <T>(value: unknown) => value is LoadableStore<T>;
@@ -0,0 +1,7 @@
1
+ import { LOADABLE_STORE_BRAND } from "./constants.js";
2
+ export const isLoadableStore = (value) => {
3
+ if (typeof value !== "object" || value === null) {
4
+ return false;
5
+ }
6
+ return "brand" in value && value.brand === LOADABLE_STORE_BRAND;
7
+ };
@@ -0,0 +1,12 @@
1
+ import { type Signal } from "@preact/signals-core";
2
+ export declare const persistSignal: <S extends Signal<unknown>>(options: {
3
+ signal: S;
4
+ key: string;
5
+ shouldPersist?: (v: S extends Signal<infer U> ? U : never) => boolean;
6
+ }) => (() => void) | undefined;
7
+ export declare const restoreSignal: <S extends Signal<unknown>, V = S extends Signal<infer U> ? U : unknown>(options: {
8
+ signal: S;
9
+ key: string;
10
+ defaultValue?: V;
11
+ onRestore?: (value: any) => V | undefined;
12
+ }) => void;
@@ -0,0 +1,36 @@
1
+ import { effect } from "@preact/signals-core";
2
+ export const persistSignal = (options) => {
3
+ if (typeof window === "undefined") {
4
+ return;
5
+ }
6
+ const { signal, key, shouldPersist = () => true } = options;
7
+ return effect(() => {
8
+ const value = signal.value;
9
+ if (!shouldPersist(value)) {
10
+ return;
11
+ }
12
+ try {
13
+ window.localStorage.setItem(key, typeof value === "string" ? value : JSON.stringify(value));
14
+ }
15
+ catch { }
16
+ });
17
+ };
18
+ export const restoreSignal = (options) => {
19
+ if (typeof window === "undefined") {
20
+ return;
21
+ }
22
+ const { signal, key, defaultValue, onRestore = (v) => v } = options;
23
+ const value = window.localStorage.getItem(key);
24
+ if (value !== null) {
25
+ let parsedValue = value;
26
+ try {
27
+ parsedValue = JSON.parse(value);
28
+ }
29
+ catch { }
30
+ signal.value = onRestore(parsedValue);
31
+ return;
32
+ }
33
+ if ("defaultValue" in options) {
34
+ signal.value = defaultValue;
35
+ }
36
+ };
@@ -0,0 +1,18 @@
1
+ export declare const router: import("@preact/signals-core").ReadonlySignal<{
2
+ readonly path: string;
3
+ readonly pathParts: string[];
4
+ }>;
5
+ type NavigateTo = {
6
+ path: string;
7
+ keepSearchParams?: boolean;
8
+ searchParams?: Record<string, string | string[] | number | undefined>;
9
+ params?: Record<string, string | undefined>;
10
+ replace?: boolean;
11
+ };
12
+ export declare const navigateTo: (to: NavigateTo) => void;
13
+ type Route<Params extends Record<string, string | undefined>> = {
14
+ matches: boolean;
15
+ params: Params;
16
+ };
17
+ export declare const createRoute: <Params extends Record<string, string | undefined>>(path: string, validate?: (route: Route<Params>) => boolean) => Route<Params>;
18
+ export {};
@@ -0,0 +1,95 @@
1
+ import { computed } from "@preact/signals-core";
2
+ import { paramsToSearchParams } from "../url/helpers.js";
3
+ import { currentUrl, goTo } from "../url/index.js";
4
+ export const router = computed(() => {
5
+ const hash = currentUrl.value.hash.startsWith("#") ? currentUrl.value.hash.slice(1) : currentUrl.value.hash;
6
+ return {
7
+ path: hash,
8
+ pathParts: hash.split("/").filter(Boolean),
9
+ };
10
+ });
11
+ const createRouteUrl = (path, params) => {
12
+ return path
13
+ .split("/")
14
+ .map((part) => {
15
+ if (part.startsWith(":")) {
16
+ const isOptional = part.endsWith("?");
17
+ const paramKey = isOptional ? part.slice(1, -1) : part.slice(1);
18
+ const value = params[paramKey];
19
+ if (value) {
20
+ return value.toString();
21
+ }
22
+ if (isOptional) {
23
+ return "";
24
+ }
25
+ return part;
26
+ }
27
+ return part;
28
+ })
29
+ .filter(Boolean)
30
+ .join("/");
31
+ };
32
+ export const navigateTo = (to) => {
33
+ const { path, params = {}, replace = false, searchParams = {}, keepSearchParams = false } = to;
34
+ const currentPathname = currentUrl.value.pathname;
35
+ const newUrl = new URL(currentPathname, currentUrl.value.origin);
36
+ const routeUrl = createRouteUrl(path, params);
37
+ newUrl.hash = routeUrl === "" || routeUrl === "/" ? "" : `#${routeUrl}`;
38
+ if (keepSearchParams) {
39
+ paramsToSearchParams(currentUrl.value.params, newUrl.searchParams);
40
+ }
41
+ Object.entries(searchParams).forEach(([key, value]) => {
42
+ if (!value) {
43
+ return;
44
+ }
45
+ if (Array.isArray(value)) {
46
+ for (const v of value) {
47
+ newUrl.searchParams.set(key, v.toString());
48
+ }
49
+ }
50
+ newUrl.searchParams.set(key, value.toString());
51
+ });
52
+ goTo(newUrl, { replace });
53
+ };
54
+ export const createRoute = (path, validate = () => true) => {
55
+ if (path === "/" && router.value.pathParts.length === 0) {
56
+ return { matches: true, params: {} };
57
+ }
58
+ const routeParts = path.split("/").filter(Boolean);
59
+ const currentParts = router.value.pathParts;
60
+ const params = {};
61
+ let routeIndex = 0;
62
+ let currentIndex = 0;
63
+ while (routeIndex < routeParts.length && currentIndex < currentParts.length) {
64
+ const routePart = routeParts[routeIndex];
65
+ const currentPart = currentParts[currentIndex];
66
+ if (routePart.startsWith(":")) {
67
+ const isOptional = routePart.endsWith("?");
68
+ const paramKey = isOptional ? routePart.slice(1, -1) : routePart.slice(1);
69
+ params[paramKey] = currentPart;
70
+ routeIndex++;
71
+ currentIndex++;
72
+ }
73
+ else if (routePart === currentPart) {
74
+ routeIndex++;
75
+ currentIndex++;
76
+ }
77
+ else {
78
+ return { matches: false, params: {} };
79
+ }
80
+ }
81
+ while (routeIndex < routeParts.length) {
82
+ const routePart = routeParts[routeIndex];
83
+ if (routePart.startsWith(":") && routePart.endsWith("?")) {
84
+ const paramKey = routePart.slice(1, -1);
85
+ params[paramKey] = undefined;
86
+ routeIndex++;
87
+ }
88
+ else {
89
+ return { matches: false, params: {} };
90
+ }
91
+ }
92
+ const matches = currentIndex === currentParts.length;
93
+ const route = { matches, params };
94
+ return { matches: matches && validate(route), params };
95
+ };
@@ -0,0 +1,3 @@
1
+ import type { UserTheme } from "./types.js";
2
+ export declare const setUserTheme: (theme: UserTheme) => void;
3
+ export declare const toggleUserTheme: () => void;
@@ -0,0 +1,30 @@
1
+ import { effect } from "@preact/signals-core";
2
+ import { SELECTED_THEMES, THEME_DARK, THEME_LIGHT } from "./constants.js";
3
+ import { currentTheme, preferredTheme, userTheme } from "./store.js";
4
+ import { getPrefersColorSchemeMQ } from "./utils.js";
5
+ const initThemeStore = () => {
6
+ if (typeof window === "undefined") {
7
+ return;
8
+ }
9
+ effect(() => {
10
+ document.documentElement.setAttribute("data-theme", currentTheme.value);
11
+ });
12
+ const preffersMediaQuery = getPrefersColorSchemeMQ();
13
+ preffersMediaQuery.addEventListener("change", (event) => {
14
+ if (event.matches) {
15
+ preferredTheme.value = THEME_DARK;
16
+ }
17
+ else {
18
+ preferredTheme.value = THEME_LIGHT;
19
+ }
20
+ });
21
+ };
22
+ export const setUserTheme = (theme) => {
23
+ userTheme.value = theme;
24
+ };
25
+ export const toggleUserTheme = () => {
26
+ const current = userTheme.peek();
27
+ const next = SELECTED_THEMES[(SELECTED_THEMES.indexOf(current) + 1) % SELECTED_THEMES.length];
28
+ setUserTheme(next);
29
+ };
30
+ initThemeStore();
@@ -0,0 +1,6 @@
1
+ import type { UserTheme } from "./types.js";
2
+ export declare const THEME_AUTO = "auto";
3
+ export declare const THEME_LIGHT = "light";
4
+ export declare const THEME_DARK = "dark";
5
+ export declare const STORAGE_KEY = "theme";
6
+ export declare const SELECTED_THEMES: UserTheme[];
@@ -0,0 +1,5 @@
1
+ export const THEME_AUTO = "auto";
2
+ export const THEME_LIGHT = "light";
3
+ export const THEME_DARK = "dark";
4
+ export const STORAGE_KEY = "theme";
5
+ export const SELECTED_THEMES = [THEME_LIGHT, THEME_DARK, THEME_AUTO];
@@ -0,0 +1,2 @@
1
+ export { setUserTheme, toggleUserTheme } from "./actions.js";
2
+ export { themeStore } from "./store.js";
@@ -0,0 +1,2 @@
1
+ export { setUserTheme, toggleUserTheme } from "./actions.js";
2
+ export { themeStore } from "./store.js";
@@ -0,0 +1,8 @@
1
+ import type { UITheme, UserTheme } from "./types.js";
2
+ export declare const currentTheme: import("@preact/signals-core").ReadonlySignal<UITheme>;
3
+ export declare const userTheme: import("@preact/signals-core").Signal<UserTheme>;
4
+ export declare const preferredTheme: import("@preact/signals-core").Signal<UITheme>;
5
+ export declare const themeStore: import("@preact/signals-core").ReadonlySignal<{
6
+ readonly current: UITheme;
7
+ readonly selected: UserTheme;
8
+ }>;
@@ -0,0 +1,41 @@
1
+ import { computed, signal } from "@preact/signals-core";
2
+ import { getReportOptions } from "../../data.js";
3
+ import { persistSignal, restoreSignal } from "../persister/index.js";
4
+ import { STORAGE_KEY, THEME_AUTO, THEME_DARK, THEME_LIGHT } from "./constants.js";
5
+ import { getPrefersColorSchemeMQ, isAcceptedThemeValue, isAutoTheme } from "./utils.js";
6
+ const reportConfigTheme = getReportOptions()?.theme;
7
+ const getInitialPreferredTheme = () => {
8
+ if (typeof window === "undefined") {
9
+ return THEME_LIGHT;
10
+ }
11
+ if (getPrefersColorSchemeMQ().matches) {
12
+ return THEME_DARK;
13
+ }
14
+ return THEME_LIGHT;
15
+ };
16
+ export const currentTheme = computed(() => {
17
+ if (isAutoTheme(userTheme.value)) {
18
+ return preferredTheme.value;
19
+ }
20
+ return userTheme.value;
21
+ });
22
+ export const userTheme = signal(THEME_AUTO);
23
+ export const preferredTheme = signal(getInitialPreferredTheme());
24
+ restoreSignal({
25
+ signal: userTheme,
26
+ key: STORAGE_KEY,
27
+ onRestore: (value) => {
28
+ if (isAcceptedThemeValue(value)) {
29
+ return value;
30
+ }
31
+ return reportConfigTheme ?? THEME_AUTO;
32
+ },
33
+ });
34
+ persistSignal({
35
+ signal: userTheme,
36
+ key: STORAGE_KEY,
37
+ });
38
+ export const themeStore = computed(() => ({
39
+ current: currentTheme.value,
40
+ selected: userTheme.value,
41
+ }));
@@ -0,0 +1,2 @@
1
+ export type UITheme = "light" | "dark";
2
+ export type UserTheme = UITheme | "auto";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { UserTheme } from "./types.js";
2
+ export declare const getPrefersColorSchemeMQ: () => MediaQueryList;
3
+ export declare const isAcceptedThemeValue: (value: unknown) => value is UserTheme;
4
+ export declare const isAutoTheme: (theme: UserTheme) => theme is "auto";
@@ -0,0 +1,23 @@
1
+ import { SELECTED_THEMES, THEME_AUTO } from "./constants.js";
2
+ const nullMediaQueryList = {
3
+ matches: false,
4
+ addEventListener: () => { },
5
+ removeEventListener: () => { },
6
+ media: "",
7
+ onchange: () => { },
8
+ addListener: () => { },
9
+ removeListener: () => { },
10
+ dispatchEvent: () => true,
11
+ };
12
+ export const getPrefersColorSchemeMQ = () => {
13
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
14
+ return nullMediaQueryList;
15
+ }
16
+ return window.matchMedia("(prefers-color-scheme: dark)");
17
+ };
18
+ export const isAcceptedThemeValue = (value) => {
19
+ return SELECTED_THEMES.includes(value);
20
+ };
21
+ export const isAutoTheme = (theme) => {
22
+ return theme === THEME_AUTO;
23
+ };
@@ -0,0 +1,12 @@
1
+ export declare const subscribeToUrlChange: (callback: () => void) => (() => void) | undefined;
2
+ type NavigateTo = URL | string | {
3
+ path: string;
4
+ };
5
+ type NavigateToOptions = {
6
+ replace?: boolean;
7
+ };
8
+ export declare const goTo: (to: NavigateTo, options?: NavigateToOptions) => void;
9
+ export declare const getCurrentUrl: () => string;
10
+ export declare const paramsToSearchParams: (params: Record<string, string | string[]>, searchParams?: URLSearchParams) => URLSearchParams;
11
+ export declare const searchParamsToParams: (searchParams: URLSearchParams) => Record<string, string | string[]>;
12
+ export {};
@@ -0,0 +1,74 @@
1
+ export const subscribeToUrlChange = (callback) => {
2
+ if (typeof window === "undefined") {
3
+ return;
4
+ }
5
+ window.addEventListener("popstate", callback);
6
+ window.addEventListener("replaceState", callback);
7
+ window.addEventListener("pushState", callback);
8
+ window.addEventListener("hashchange", callback);
9
+ return () => {
10
+ window.removeEventListener("popstate", callback);
11
+ window.removeEventListener("replaceState", callback);
12
+ window.removeEventListener("pushState", callback);
13
+ window.removeEventListener("hashchange", callback);
14
+ };
15
+ };
16
+ const getUrl = (to) => {
17
+ if (typeof to === "string") {
18
+ return to;
19
+ }
20
+ if (to instanceof URL) {
21
+ return to;
22
+ }
23
+ return new URL(to.path, getCurrentUrl());
24
+ };
25
+ export const goTo = (to, options) => {
26
+ if (typeof window === "undefined") {
27
+ return;
28
+ }
29
+ const url = getUrl(to);
30
+ if (options?.replace) {
31
+ window.history.replaceState(null, "", url);
32
+ window.dispatchEvent(new Event("replaceState"));
33
+ }
34
+ else {
35
+ window.history.pushState(null, "", url);
36
+ window.dispatchEvent(new Event("pushState"));
37
+ }
38
+ };
39
+ export const getCurrentUrl = () => {
40
+ if (typeof window === "undefined") {
41
+ return "";
42
+ }
43
+ return window.location.href;
44
+ };
45
+ export const paramsToSearchParams = (params, searchParams = new URLSearchParams()) => {
46
+ Object.entries(params).forEach(([key, value]) => {
47
+ if (Array.isArray(value)) {
48
+ for (const v of value) {
49
+ searchParams.append(key, v);
50
+ }
51
+ }
52
+ else {
53
+ searchParams.set(key, value);
54
+ }
55
+ });
56
+ return searchParams;
57
+ };
58
+ export const searchParamsToParams = (searchParams) => {
59
+ const params = {};
60
+ searchParams.forEach((value, key) => {
61
+ if (key in params) {
62
+ if (Array.isArray(params[key])) {
63
+ params[key].push(value);
64
+ }
65
+ else {
66
+ params[key] = [params[key], value];
67
+ }
68
+ }
69
+ else {
70
+ params[key] = value;
71
+ }
72
+ });
73
+ return params;
74
+ };
@@ -0,0 +1,2 @@
1
+ export { getParamValue, getParamValues, hasParam, setParams, currentUrl, type Param } from "./store.js";
2
+ export { goTo, getCurrentUrl } from "./helpers.js";
@@ -0,0 +1,2 @@
1
+ export { getParamValue, getParamValues, hasParam, setParams, currentUrl } from "./store.js";
2
+ export { goTo, getCurrentUrl } from "./helpers.js";
@@ -0,0 +1,19 @@
1
+ export declare const currentUrlSignal: import("@preact/signals-core").Signal<string>;
2
+ export declare const urlSearchParams: import("@preact/signals-core").ReadonlySignal<URLSearchParams>;
3
+ export type Param = {
4
+ key: string;
5
+ value: string | string[] | undefined;
6
+ };
7
+ export declare const setParams: (...params: Param[]) => void;
8
+ export declare const currentUrl: import("@preact/signals-core").ReadonlySignal<{
9
+ readonly hash: string;
10
+ readonly pathname: string;
11
+ readonly origin: string;
12
+ readonly params: Record<string, string | string[]>;
13
+ }>;
14
+ export declare const getParamValue: (key: string) => string | null;
15
+ export declare const getParamValues: (key: string) => string[];
16
+ export declare const hasParam: (key: string) => boolean;
17
+ export declare const getParamValueComputed: (key: string) => import("@preact/signals-core").ReadonlySignal<string | null>;
18
+ export declare const getParamValuesComputed: (key: string) => import("@preact/signals-core").ReadonlySignal<string[]>;
19
+ export declare const hasParamComputed: (key: string) => import("@preact/signals-core").ReadonlySignal<boolean>;
@@ -0,0 +1,45 @@
1
+ import { computed, signal } from "@preact/signals-core";
2
+ import { getCurrentUrl, goTo, searchParamsToParams, subscribeToUrlChange } from "./helpers.js";
3
+ export const currentUrlSignal = signal(getCurrentUrl());
4
+ subscribeToUrlChange(() => {
5
+ if (currentUrlSignal.peek() === getCurrentUrl()) {
6
+ return;
7
+ }
8
+ currentUrlSignal.value = getCurrentUrl();
9
+ });
10
+ const urlSignal = computed(() => new URL(currentUrlSignal.value));
11
+ export const urlSearchParams = computed(() => urlSignal.value.searchParams);
12
+ export const setParams = (...params) => {
13
+ const newUrl = new URL(getCurrentUrl());
14
+ for (const param of params) {
15
+ newUrl.searchParams.delete(param.key);
16
+ if (Array.isArray(param.value)) {
17
+ for (const value of param.value) {
18
+ newUrl.searchParams.append(param.key, value);
19
+ }
20
+ }
21
+ else if (typeof param.value === "string") {
22
+ newUrl.searchParams.set(param.key, param.value);
23
+ }
24
+ }
25
+ if (newUrl.href === urlSignal.peek().href) {
26
+ return;
27
+ }
28
+ goTo(newUrl.href, {
29
+ replace: true,
30
+ });
31
+ };
32
+ export const currentUrl = computed(() => {
33
+ return {
34
+ hash: urlSignal.value.hash,
35
+ pathname: urlSignal.value.pathname,
36
+ origin: urlSignal.value.origin,
37
+ params: searchParamsToParams(urlSearchParams.value),
38
+ };
39
+ });
40
+ export const getParamValue = (key) => urlSearchParams.value.get(key);
41
+ export const getParamValues = (key) => urlSearchParams.value.getAll(key);
42
+ export const hasParam = (key) => urlSearchParams.value.has(key);
43
+ export const getParamValueComputed = (key) => computed(() => getParamValue(key));
44
+ export const getParamValuesComputed = (key) => computed(() => getParamValues(key));
45
+ export const hasParamComputed = (key) => computed(() => hasParam(key));
@@ -0,0 +1,2 @@
1
+ import { type ReadonlySignal, type Signal } from "@preact/signals-core";
2
+ export declare const isSignal: (value: unknown) => value is Signal | ReadonlySignal;
package/dist/utils.js ADDED
@@ -0,0 +1,9 @@
1
+ import { signal } from "@preact/signals-core";
2
+ const signalExample = signal(1);
3
+ export const isSignal = (value) => {
4
+ return (typeof value === "object" &&
5
+ value !== null &&
6
+ "brand" in value &&
7
+ typeof value.brand === "symbol" &&
8
+ value.brand === signalExample.brand);
9
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/web-commons",
3
- "version": "3.0.1",
3
+ "version": "3.2.0",
4
4
  "description": "Collection of utilities used across the web Allure reports",
5
5
  "keywords": [
6
6
  "allure",
@@ -20,12 +20,16 @@
20
20
  ],
21
21
  "scripts": {
22
22
  "build": "run clean && tsc --project ./tsconfig.json",
23
- "clean": "rimraf ./dist"
23
+ "clean": "rimraf ./dist",
24
+ "test": "vitest run"
24
25
  },
25
26
  "dependencies": {
26
- "@allurereport/charts-api": "3.0.1",
27
- "@allurereport/core-api": "3.0.1",
28
- "@allurereport/plugin-api": "3.0.1",
27
+ "@allurereport/aql": "3.2.0",
28
+ "@allurereport/charts-api": "3.2.0",
29
+ "@allurereport/core-api": "3.2.0",
30
+ "@allurereport/plugin-api": "3.2.0",
31
+ "@preact/signals": "^2.6.1",
32
+ "@preact/signals-core": "^1.12.2",
29
33
  "ansi-to-html": "^0.7.2",
30
34
  "d3-interpolate": "^3.0.1",
31
35
  "d3-scale": "^4.0.2",
@@ -51,6 +55,7 @@
51
55
  "eslint-plugin-n": "^17.10.1",
52
56
  "eslint-plugin-no-null": "^1.0.2",
53
57
  "eslint-plugin-prefer-arrow": "^1.2.3",
58
+ "jsdom": "^26.1.0",
54
59
  "rimraf": "^6.0.1",
55
60
  "tslib": "^2.7.0",
56
61
  "typescript": "^5.6.3",
@@ -1,5 +0,0 @@
1
- import type { AllureChartsStoreData, FBSUAgePyramidChartData, FBSUAgePyramidChartOptions } from "@allurereport/charts-api";
2
- export declare const generateFBSUAgePyramid: (props: {
3
- options: FBSUAgePyramidChartOptions;
4
- storeData: AllureChartsStoreData;
5
- }) => FBSUAgePyramidChartData;