@aiaiai-pt/design-system 0.8.4 → 0.9.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.
@@ -0,0 +1,49 @@
1
+ export default ServiceNavigation;
2
+ type ServiceNavigation = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ /**
7
+ * ServiceNavigation
8
+ *
9
+ * Primary site navigation for the public portal, modelled on the GOV.UK
10
+ * "Service navigation" and Designers Italia header-nav patterns (the citizen /
11
+ * PA gold standard). Data-driven: it owns its `<a>` markup (rendered from
12
+ * `items`), so it styles its own links — no magic descendant styling of
13
+ * consumer anchors.
14
+ *
15
+ * Accessibility:
16
+ * - `<nav aria-label>` landmark; the current item carries `aria-current="page"`.
17
+ * - Below `--breakpoint` the list collapses behind a toggle button with
18
+ * `aria-expanded` + `aria-controls` (WCAG-friendly disclosure).
19
+ * - Empty `items` renders NOTHING — never an empty nav landmark.
20
+ * - Toggle + links have visible focus rings.
21
+ *
22
+ * @example
23
+ * <ServiceNavigation
24
+ * label="Primary"
25
+ * items={[
26
+ * { href: "/report", label: "Report a problem" },
27
+ * { href: "/track", label: "Track a report", current: true },
28
+ * { href: "/info/privacy", label: "Privacy" },
29
+ * ]}
30
+ * >
31
+ * {#snippet menuIcon()}<MenuIcon />{/snippet}
32
+ * </ServiceNavigation>
33
+ */
34
+ declare const ServiceNavigation: import("svelte").Component<{
35
+ items?: any[];
36
+ label?: string;
37
+ menuId?: string;
38
+ toggleLabel?: string;
39
+ class?: string;
40
+ menuIcon?: any;
41
+ } & Record<string, any>, {}, "">;
42
+ type $$ComponentProps = {
43
+ items?: any[];
44
+ label?: string;
45
+ menuId?: string;
46
+ toggleLabel?: string;
47
+ class?: string;
48
+ menuIcon?: any;
49
+ } & Record<string, any>;
@@ -0,0 +1,83 @@
1
+ <!--
2
+ @component SiteFooter
3
+
4
+ Public site contentinfo landmark (`<footer role="contentinfo">`). Locked
5
+ accessibility chrome for the citizen portal — holds legal links, tenant
6
+ attribution, and secondary navigation. Structure fixed; brand varies via
7
+ `data-theme`.
8
+
9
+ @example
10
+ <SiteFooter>
11
+ {#snippet links()}
12
+ <a href="/info/privacy">Privacy</a>
13
+ <a href="/info/terms">Terms</a>
14
+ <a href="/info/accessibility">Accessibility</a>
15
+ {/snippet}
16
+ {#snippet meta()}© 2026 Município de Valongo{/snippet}
17
+ </SiteFooter>
18
+ -->
19
+ <script>
20
+ let {
21
+ /** @type {string} aria-label for the footer nav (localize it). */
22
+ navLabel = "Footer",
23
+ /** @type {string} */
24
+ class: className = "",
25
+ /** @type {import('svelte').Snippet | undefined} Footer navigation links. */
26
+ links = undefined,
27
+ /** @type {import('svelte').Snippet | undefined} Attribution / fine print. */
28
+ meta = undefined,
29
+ /** @type {import('svelte').Snippet | undefined} Free-form content (overrides links/meta layout). */
30
+ children = undefined,
31
+ ...rest
32
+ } = $props();
33
+ </script>
34
+
35
+ <footer class="site-footer {className}" {...rest}>
36
+ <div class="site-footer-inner">
37
+ {#if children}
38
+ {@render children()}
39
+ {:else}
40
+ {#if links}
41
+ <nav class="site-footer-nav" aria-label={navLabel}>{@render links()}</nav>
42
+ {/if}
43
+ {#if meta}
44
+ <p class="site-footer-meta">{@render meta()}</p>
45
+ {/if}
46
+ {/if}
47
+ </div>
48
+ </footer>
49
+
50
+ <style>
51
+ .site-footer {
52
+ background: var(--color-surface-secondary);
53
+ border-top: 1px solid var(--color-border);
54
+ color: var(--color-text-secondary);
55
+ }
56
+
57
+ .site-footer-inner {
58
+ display: flex;
59
+ flex-wrap: wrap;
60
+ align-items: center;
61
+ justify-content: space-between;
62
+ gap: var(--space-md);
63
+ width: 100%;
64
+ max-width: var(--content-width-wide);
65
+ margin-inline: auto;
66
+ padding: var(--space-xl) var(--content-padding-x);
67
+ }
68
+
69
+ /* The links slot hosts `Link` components (self-styled) — no descendant-anchor
70
+ magic here either. */
71
+ .site-footer-nav {
72
+ display: flex;
73
+ flex-wrap: wrap;
74
+ gap: var(--space-md);
75
+ }
76
+
77
+ .site-footer-meta {
78
+ margin: 0;
79
+ font-family: var(--type-caption-font);
80
+ font-size: var(--type-caption-size);
81
+ color: var(--color-text-muted);
82
+ }
83
+ </style>
@@ -0,0 +1,37 @@
1
+ export default SiteFooter;
2
+ type SiteFooter = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ /**
7
+ * SiteFooter
8
+ *
9
+ * Public site contentinfo landmark (`<footer role="contentinfo">`). Locked
10
+ * accessibility chrome for the citizen portal — holds legal links, tenant
11
+ * attribution, and secondary navigation. Structure fixed; brand varies via
12
+ * `data-theme`.
13
+ *
14
+ * @example
15
+ * <SiteFooter>
16
+ * {#snippet links()}
17
+ * <a href="/info/privacy">Privacy</a>
18
+ * <a href="/info/terms">Terms</a>
19
+ * <a href="/info/accessibility">Accessibility</a>
20
+ * {/snippet}
21
+ * {#snippet meta()}© 2026 Município de Valongo{/snippet}
22
+ * </SiteFooter>
23
+ */
24
+ declare const SiteFooter: import("svelte").Component<{
25
+ navLabel?: string;
26
+ class?: string;
27
+ links?: any;
28
+ meta?: any;
29
+ children?: any;
30
+ } & Record<string, any>, {}, "">;
31
+ type $$ComponentProps = {
32
+ navLabel?: string;
33
+ class?: string;
34
+ links?: any;
35
+ meta?: any;
36
+ children?: any;
37
+ } & Record<string, any>;
@@ -0,0 +1,90 @@
1
+ <!--
2
+ @component SiteHeader
3
+
4
+ Public site banner landmark (`<header role="banner">`). Locked accessibility
5
+ chrome for the citizen portal: a brand area, a primary navigation slot, and
6
+ an actions slot (locale switch, sign-in). Structure and landmarks are fixed
7
+ (conformance-checkable); only brand tokens vary per tenant via `data-theme`.
8
+
9
+ Icon-agnostic, per DS convention — pass icons/logo as snippets.
10
+
11
+ @example
12
+ <SiteHeader>
13
+ {#snippet brand()}<a href="/"><Logo /> Valongo</a>{/snippet}
14
+ {#snippet nav()}<ServiceNavigation items={navItems} />{/snippet}
15
+ {#snippet actions()}<LocaleSwitch /> <Button>Sign in</Button>{/snippet}
16
+ </SiteHeader>
17
+ -->
18
+ <script>
19
+ let {
20
+ /** @type {string} aria-label for the primary nav (localize it). */
21
+ navLabel = "Primary",
22
+ /** @type {string} */
23
+ class: className = "",
24
+ /** @type {import('svelte').Snippet | undefined} Brand / logo area. */
25
+ brand = undefined,
26
+ /** @type {import('svelte').Snippet | undefined} Primary navigation links. */
27
+ nav = undefined,
28
+ /** @type {import('svelte').Snippet | undefined} Trailing actions (locale, auth). */
29
+ actions = undefined,
30
+ ...rest
31
+ } = $props();
32
+ </script>
33
+
34
+ <header class="site-header {className}" {...rest}>
35
+ <div class="site-header-inner">
36
+ {#if brand}
37
+ <div class="site-header-brand">{@render brand()}</div>
38
+ {/if}
39
+ {#if nav}
40
+ <nav class="site-header-nav" aria-label={navLabel}>{@render nav()}</nav>
41
+ {/if}
42
+ {#if actions}
43
+ <div class="site-header-actions">{@render actions()}</div>
44
+ {/if}
45
+ </div>
46
+ </header>
47
+
48
+ <style>
49
+ .site-header {
50
+ position: sticky;
51
+ top: 0;
52
+ z-index: 40;
53
+ background: var(--color-surface);
54
+ border-bottom: 1px solid var(--color-border);
55
+ }
56
+
57
+ .site-header-inner {
58
+ display: flex;
59
+ align-items: center;
60
+ gap: var(--space-lg);
61
+ width: 100%;
62
+ max-width: var(--content-width-wide);
63
+ margin-inline: auto;
64
+ padding: var(--space-sm) var(--content-padding-x);
65
+ }
66
+
67
+ .site-header-brand {
68
+ display: flex;
69
+ align-items: center;
70
+ gap: var(--space-xs);
71
+ font-family: var(--type-heading-sm-font);
72
+ font-size: var(--type-heading-sm-size);
73
+ color: var(--color-text);
74
+ }
75
+
76
+ /* The nav slot hosts a `ServiceNavigation` (data-driven, self-styled).
77
+ The header doesn't style anchors itself — no descendant-anchor magic. */
78
+ .site-header-nav {
79
+ display: flex;
80
+ align-items: center;
81
+ }
82
+
83
+ /* Push trailing actions to the far end regardless of nav presence. */
84
+ .site-header-actions {
85
+ display: flex;
86
+ align-items: center;
87
+ gap: var(--space-sm);
88
+ margin-inline-start: auto;
89
+ }
90
+ </style>
@@ -0,0 +1,36 @@
1
+ export default SiteHeader;
2
+ type SiteHeader = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ /**
7
+ * SiteHeader
8
+ *
9
+ * Public site banner landmark (`<header role="banner">`). Locked accessibility
10
+ * chrome for the citizen portal: a brand area, a primary navigation slot, and
11
+ * an actions slot (locale switch, sign-in). Structure and landmarks are fixed
12
+ * (conformance-checkable); only brand tokens vary per tenant via `data-theme`.
13
+ *
14
+ * Icon-agnostic, per DS convention — pass icons/logo as snippets.
15
+ *
16
+ * @example
17
+ * <SiteHeader>
18
+ * {#snippet brand()}<a href="/"><Logo /> Valongo</a>{/snippet}
19
+ * {#snippet nav()}<a href="/report">Report</a><a href="/info/privacy">Privacy</a>{/snippet}
20
+ * {#snippet actions()}<LocaleSwitch /> <Button>Sign in</Button>{/snippet}
21
+ * </SiteHeader>
22
+ */
23
+ declare const SiteHeader: import("svelte").Component<{
24
+ navLabel?: string;
25
+ class?: string;
26
+ brand?: any;
27
+ nav?: any;
28
+ actions?: any;
29
+ } & Record<string, any>, {}, "">;
30
+ type $$ComponentProps = {
31
+ navLabel?: string;
32
+ class?: string;
33
+ brand?: any;
34
+ nav?: any;
35
+ actions?: any;
36
+ } & Record<string, any>;
@@ -0,0 +1,63 @@
1
+ <!--
2
+ @component SkipLink
3
+
4
+ Accessibility skip-to-content link — the first focusable element on a page.
5
+ Visually hidden until focused, then slides into view. Lets keyboard and
6
+ screen-reader users bypass repeated header/nav landmarks and jump straight
7
+ to the main content (WCAG 2.4.1 Bypass Blocks). Part of the locked public
8
+ site-shell chrome; `AppFrame` renders one automatically.
9
+
10
+ The target must be a focusable element (e.g. `<main id="main" tabindex="-1">`,
11
+ which `AppFrame` provides).
12
+
13
+ @example Default (targets #main)
14
+ <SkipLink />
15
+
16
+ @example Custom target + localized label
17
+ <SkipLink href="#content">{m.skip_to_content()}</SkipLink>
18
+ -->
19
+ <script>
20
+ let {
21
+ /** @type {string} Fragment id of the main-content target. */
22
+ href = "#main",
23
+ /** @type {string} */
24
+ class: className = "",
25
+ /** @type {import('svelte').Snippet | undefined} Override the default label (for i18n). */
26
+ children = undefined,
27
+ ...rest
28
+ } = $props();
29
+ </script>
30
+
31
+ <a class="skip-link {className}" {href} {...rest}>
32
+ {#if children}{@render children()}{:else}Skip to main content{/if}
33
+ </a>
34
+
35
+ <style>
36
+ .skip-link {
37
+ position: absolute;
38
+ left: var(--space-sm);
39
+ /* Off-screen until focused — kept in the DOM + tab order, not display:none. */
40
+ top: calc(-1 * var(--space-4xl) - var(--space-lg));
41
+ z-index: 100;
42
+ padding: var(--space-2xs) var(--space-sm);
43
+ background: var(--color-accent);
44
+ color: var(--color-text-on-accent);
45
+ font-family: var(--type-label-font);
46
+ font-size: var(--type-label-size);
47
+ text-decoration: none;
48
+ border-radius: var(--radius-md);
49
+ transition: top 150ms ease-out;
50
+ }
51
+
52
+ .skip-link:focus-visible {
53
+ top: var(--space-sm);
54
+ outline: var(--focus-ring-width) solid var(--focus-ring-color);
55
+ outline-offset: var(--focus-ring-offset);
56
+ }
57
+
58
+ @media (prefers-reduced-motion: reduce) {
59
+ .skip-link {
60
+ transition: none;
61
+ }
62
+ }
63
+ </style>
@@ -0,0 +1,33 @@
1
+ export default SkipLink;
2
+ type SkipLink = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ /**
7
+ * SkipLink
8
+ *
9
+ * Accessibility skip-to-content link — the first focusable element on a page.
10
+ * Visually hidden until focused, then slides into view. Lets keyboard and
11
+ * screen-reader users bypass repeated header/nav landmarks and jump straight
12
+ * to the main content (WCAG 2.4.1 Bypass Blocks). Part of the locked public
13
+ * site-shell chrome; `AppFrame` renders one automatically.
14
+ *
15
+ * The target must be a focusable element (e.g. `<main id="main" tabindex="-1">`,
16
+ * which `AppFrame` provides).
17
+ *
18
+ * @example Default (targets #main)
19
+ * <SkipLink />
20
+ *
21
+ * @example Custom target + localized label
22
+ * <SkipLink href="#content">{m.skip_to_content()}</SkipLink>
23
+ */
24
+ declare const SkipLink: import("svelte").Component<{
25
+ href?: string;
26
+ class?: string;
27
+ children?: any;
28
+ } & Record<string, any>, {}, "">;
29
+ type $$ComponentProps = {
30
+ href?: string;
31
+ class?: string;
32
+ children?: any;
33
+ } & Record<string, any>;
@@ -0,0 +1,193 @@
1
+ <!--
2
+ @component StatusTimeline
3
+
4
+ Ordered, accessibility-first progress timeline for the citizen portal — the
5
+ `tracker` page template's spine (a submission moving submitted → triaged →
6
+ in-progress → resolved). Renders an `<ol>` so the sequence and position are
7
+ conveyed structurally, with the active step carrying `aria-current="step"`.
8
+
9
+ Each step's state (complete / current / upcoming) is announced to assistive
10
+ tech via a visually-hidden label — pass `stateLabels` to localise it (the
11
+ portal feeds Wuchale strings here). Purely structural: no motion, so it is
12
+ reduced-motion-safe by construction.
13
+
14
+ @example
15
+ <StatusTimeline
16
+ label="Report progress"
17
+ steps={[
18
+ { label: "Submitted", status: "complete", timestamp: "12 May" },
19
+ { label: "Under review", status: "complete", timestamp: "13 May" },
20
+ { label: "In progress", status: "current", description: "Crew assigned" },
21
+ { label: "Resolved", status: "upcoming" },
22
+ ]}
23
+ />
24
+
25
+ @example Localised state labels (portal i18n)
26
+ <StatusTimeline steps={steps} stateLabels={{ complete: "Concluído", current: "Atual", upcoming: "Pendente" }} />
27
+ -->
28
+ <script>
29
+ /**
30
+ * @typedef {'complete' | 'current' | 'upcoming'} StepStatus
31
+ * @typedef {{ label: string, status?: StepStatus, description?: string, timestamp?: string }} Step
32
+ */
33
+
34
+ let {
35
+ /** @type {Step[]} Ordered steps, earliest first. */
36
+ steps = [],
37
+ /** @type {string} Accessible name for the timeline list (localize it). */
38
+ label = "Progress",
39
+ /**
40
+ * @type {Record<StepStatus, string>}
41
+ * Visually-hidden state text announced per step (localize it).
42
+ */
43
+ stateLabels = {
44
+ complete: "Completed",
45
+ current: "Current step",
46
+ upcoming: "Upcoming",
47
+ },
48
+ /** @type {string} */
49
+ class: className = "",
50
+ ...rest
51
+ } = $props();
52
+
53
+ /** @param {Step} step @returns {StepStatus} */
54
+ const statusOf = (step) => step.status ?? "upcoming";
55
+ </script>
56
+
57
+ {#if steps.length > 0}
58
+ <ol class="status-timeline {className}" aria-label={label} {...rest}>
59
+ {#each steps as step, i (i)}
60
+ {@const status = statusOf(step)}
61
+ <li
62
+ class="status-timeline-item status-timeline-item-{status}"
63
+ aria-current={status === "current" ? "step" : undefined}
64
+ >
65
+ <span class="status-timeline-marker" aria-hidden="true">
66
+ <span class="status-timeline-node"></span>
67
+ </span>
68
+ <div class="status-timeline-body">
69
+ <span class="status-timeline-label">
70
+ <span class="status-timeline-state">{stateLabels[status]}: </span>
71
+ {step.label}
72
+ </span>
73
+ {#if step.timestamp}
74
+ <span class="status-timeline-time">{step.timestamp}</span>
75
+ {/if}
76
+ {#if step.description}
77
+ <p class="status-timeline-desc">{step.description}</p>
78
+ {/if}
79
+ </div>
80
+ </li>
81
+ {/each}
82
+ </ol>
83
+ {/if}
84
+
85
+ <style>
86
+ .status-timeline {
87
+ list-style: none;
88
+ margin: 0;
89
+ padding: 0;
90
+ display: flex;
91
+ flex-direction: column;
92
+ }
93
+
94
+ .status-timeline-item {
95
+ position: relative;
96
+ display: grid;
97
+ grid-template-columns: auto 1fr;
98
+ gap: var(--space-md);
99
+ padding-bottom: var(--space-lg);
100
+ }
101
+ .status-timeline-item:last-child {
102
+ padding-bottom: 0;
103
+ }
104
+
105
+ /* Connector line down the marker column, drawn behind the nodes. It stops at
106
+ the last node so the line never dangles past the final step. */
107
+ .status-timeline-marker {
108
+ position: relative;
109
+ display: flex;
110
+ justify-content: center;
111
+ width: var(--space-md);
112
+ }
113
+ .status-timeline-item:not(:last-child) .status-timeline-marker::before {
114
+ content: "";
115
+ position: absolute;
116
+ top: var(--space-md);
117
+ bottom: calc(-1 * var(--space-lg));
118
+ inset-inline-start: 50%;
119
+ transform: translateX(-50%);
120
+ width: var(--border-width-thick);
121
+ background: var(--color-border);
122
+ }
123
+ /* A completed step's connector is filled to show progress reaching the next. */
124
+ .status-timeline-item-complete:not(:last-child) .status-timeline-marker::before {
125
+ background: var(--color-accent);
126
+ }
127
+
128
+ .status-timeline-node {
129
+ position: relative;
130
+ z-index: 1;
131
+ width: var(--space-md);
132
+ height: var(--space-md);
133
+ border-radius: var(--radius-circle);
134
+ background: var(--color-surface);
135
+ box-shadow: inset 0 0 0 var(--border-width-thick) var(--color-border);
136
+ }
137
+ .status-timeline-item-complete .status-timeline-node {
138
+ background: var(--color-accent);
139
+ box-shadow: inset 0 0 0 var(--border-width-thick) var(--color-accent);
140
+ }
141
+ .status-timeline-item-current .status-timeline-node {
142
+ background: var(--color-surface);
143
+ box-shadow:
144
+ inset 0 0 0 var(--border-width-thick) var(--color-accent),
145
+ 0 0 0 var(--border-width-thick) var(--color-accent-subtle);
146
+ }
147
+
148
+ .status-timeline-body {
149
+ padding-top: calc((var(--space-md) - 1em) / 2);
150
+ min-width: 0;
151
+ }
152
+
153
+ .status-timeline-label {
154
+ font-family: var(--type-label-font);
155
+ font-size: var(--type-label-size);
156
+ color: var(--color-text-secondary);
157
+ }
158
+ .status-timeline-item-current .status-timeline-label,
159
+ .status-timeline-item-complete .status-timeline-label {
160
+ color: var(--color-text);
161
+ }
162
+ .status-timeline-item-current .status-timeline-label {
163
+ font-weight: var(--raw-font-weight-semibold);
164
+ }
165
+
166
+ /* State text is for assistive tech only — the visual node carries it sighted. */
167
+ .status-timeline-state {
168
+ position: absolute;
169
+ width: 1px;
170
+ height: 1px;
171
+ margin: -1px;
172
+ padding: 0;
173
+ overflow: hidden;
174
+ clip: rect(0, 0, 0, 0);
175
+ white-space: nowrap;
176
+ border: 0;
177
+ }
178
+
179
+ .status-timeline-time {
180
+ display: block;
181
+ margin-top: var(--space-2xs);
182
+ font-family: var(--type-caption-font);
183
+ font-size: var(--type-caption-size);
184
+ color: var(--color-text-muted);
185
+ }
186
+
187
+ .status-timeline-desc {
188
+ margin: var(--space-2xs) 0 0;
189
+ font-family: var(--type-body-sm-font);
190
+ font-size: var(--type-body-sm-size);
191
+ color: var(--color-text-secondary);
192
+ }
193
+ </style>
@@ -0,0 +1,44 @@
1
+ export default StatusTimeline;
2
+ type StatusTimeline = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ /**
7
+ * StatusTimeline
8
+ *
9
+ * Ordered, accessibility-first progress timeline for the citizen portal — the
10
+ * `tracker` page template's spine (a submission moving submitted → triaged →
11
+ * in-progress → resolved). Renders an `<ol>` so the sequence and position are
12
+ * conveyed structurally, with the active step carrying `aria-current="step"`.
13
+ *
14
+ * Each step's state (complete / current / upcoming) is announced to assistive
15
+ * tech via a visually-hidden label — pass `stateLabels` to localise it (the
16
+ * portal feeds Wuchale strings here). Purely structural: no motion, so it is
17
+ * reduced-motion-safe by construction.
18
+ *
19
+ * @example
20
+ * <StatusTimeline
21
+ * label="Report progress"
22
+ * steps={[
23
+ * { label: "Submitted", status: "complete", timestamp: "12 May" },
24
+ * { label: "Under review", status: "complete", timestamp: "13 May" },
25
+ * { label: "In progress", status: "current", description: "Crew assigned" },
26
+ * { label: "Resolved", status: "upcoming" },
27
+ * ]}
28
+ * />
29
+ *
30
+ * @example Localised state labels (portal i18n)
31
+ * <StatusTimeline steps={steps} stateLabels={{ complete: "Concluído", current: "Atual", upcoming: "Pendente" }} />
32
+ */
33
+ declare const StatusTimeline: import("svelte").Component<{
34
+ steps?: any[];
35
+ label?: string;
36
+ stateLabels?: Record<string, any>;
37
+ class?: string;
38
+ } & Record<string, any>, {}, "">;
39
+ type $$ComponentProps = {
40
+ steps?: any[];
41
+ label?: string;
42
+ stateLabels?: Record<string, any>;
43
+ class?: string;
44
+ } & Record<string, any>;