@aiaiai-pt/design-system 0.8.4 → 0.10.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 (37) hide show
  1. package/components/ActionFormRenderer.svelte +459 -0
  2. package/components/ActionFormRenderer.svelte.d.ts +35 -0
  3. package/components/AppFrame.svelte +75 -0
  4. package/components/AppFrame.svelte.d.ts +42 -0
  5. package/components/ContentBlock.svelte +100 -0
  6. package/components/ContentBlock.svelte.d.ts +37 -0
  7. package/components/Hero.svelte +87 -0
  8. package/components/Hero.svelte.d.ts +37 -0
  9. package/components/LayoutCompactMobile.svelte +72 -0
  10. package/components/LayoutCompactMobile.svelte.d.ts +19 -0
  11. package/components/LayoutInlineRow.svelte +74 -0
  12. package/components/LayoutInlineRow.svelte.d.ts +9 -0
  13. package/components/LayoutStackedDefault.svelte +66 -0
  14. package/components/LayoutStackedDefault.svelte.d.ts +9 -0
  15. package/components/Link.svelte +100 -0
  16. package/components/Link.svelte.d.ts +46 -0
  17. package/components/ServiceNavigation.svelte +160 -0
  18. package/components/ServiceNavigation.svelte.d.ts +49 -0
  19. package/components/SiteFooter.svelte +83 -0
  20. package/components/SiteFooter.svelte.d.ts +37 -0
  21. package/components/SiteHeader.svelte +90 -0
  22. package/components/SiteHeader.svelte.d.ts +36 -0
  23. package/components/SkipLink.svelte +63 -0
  24. package/components/SkipLink.svelte.d.ts +33 -0
  25. package/components/StatusTimeline.svelte +193 -0
  26. package/components/StatusTimeline.svelte.d.ts +44 -0
  27. package/components/VotingWidget.svelte +292 -0
  28. package/components/VotingWidget.svelte.d.ts +80 -0
  29. package/components/WidgetGrid.svelte +83 -0
  30. package/components/WidgetGrid.svelte.d.ts +42 -0
  31. package/components/action-form-renderer-layouts.d.ts +53 -0
  32. package/components/action-form-renderer-layouts.ts +82 -0
  33. package/components/action-form-renderer-payload.d.ts +90 -0
  34. package/components/action-form-renderer-payload.ts +203 -0
  35. package/components/index.js +16 -0
  36. package/package.json +2 -1
  37. package/tokens/themes/valongo.css +44 -0
@@ -0,0 +1,100 @@
1
+ <!--
2
+ @component ContentBlock
3
+
4
+ Prose container for documentation / legal / content pages (privacy, terms,
5
+ accessibility, regulamento — the `content` page template). Applies readable
6
+ measure + typographic rhythm to long-form content, with an optional title
7
+ and a version/date badge slot.
8
+
9
+ SECURITY: ContentBlock only STYLES its children — it does not parse or
10
+ sanitise. A consumer rendering operator-authored markdown/HTML MUST sanitise
11
+ before injecting it (XSS); pass the sanitised result as `children`.
12
+
13
+ @example
14
+ <ContentBlock title="Privacy Policy">
15
+ {#snippet badge()}<Badge>v3 · updated 2026-05-01</Badge>{/snippet}
16
+ {@html sanitizedHtml}
17
+ </ContentBlock>
18
+ -->
19
+ <script>
20
+ let {
21
+ /** @type {string} Page title (rendered as h1 — keep one per page). */
22
+ title = "",
23
+ /** @type {1 | 2} Heading level for `title`. */
24
+ headingLevel = 1,
25
+ /** @type {string} */
26
+ class: className = "",
27
+ /** @type {import('svelte').Snippet | undefined} Version / date badge. */
28
+ badge = undefined,
29
+ /** @type {import('svelte').Snippet | undefined} The (pre-sanitised) prose. */
30
+ children = undefined,
31
+ ...rest
32
+ } = $props();
33
+ </script>
34
+
35
+ <article class="content-block {className}" {...rest}>
36
+ {#if title}
37
+ <header class="content-block-head">
38
+ <svelte:element this={`h${headingLevel}`} class="content-block-title">{title}</svelte:element>
39
+ {#if badge}<div class="content-block-badge">{@render badge()}</div>{/if}
40
+ </header>
41
+ {/if}
42
+ <div class="content-block-prose">
43
+ {#if children}{@render children()}{/if}
44
+ </div>
45
+ </article>
46
+
47
+ <style>
48
+ .content-block {
49
+ width: 100%;
50
+ max-width: var(--content-width-narrow);
51
+ margin-inline: auto;
52
+ padding: var(--space-2xl) var(--content-padding-x);
53
+ }
54
+
55
+ .content-block-head {
56
+ display: flex;
57
+ flex-wrap: wrap;
58
+ align-items: baseline;
59
+ gap: var(--space-sm);
60
+ margin-bottom: var(--space-lg);
61
+ }
62
+
63
+ .content-block-title {
64
+ margin: 0;
65
+ font-family: var(--type-heading-lg-font);
66
+ font-size: var(--type-heading-lg-size);
67
+ color: var(--color-text);
68
+ }
69
+
70
+ /* Long-form rhythm. Scoped to descendants since prose is consumer-injected
71
+ (:global needed — these elements aren't in this component's own markup). */
72
+ .content-block-prose {
73
+ font-family: var(--type-body-font);
74
+ font-size: var(--type-body-size);
75
+ color: var(--color-text);
76
+ line-height: 1.6;
77
+ }
78
+
79
+ .content-block-prose :global(h2) {
80
+ font-family: var(--type-heading-font);
81
+ font-size: var(--type-heading-size);
82
+ margin: var(--space-xl) 0 var(--space-sm);
83
+ }
84
+
85
+ .content-block-prose :global(h3) {
86
+ font-family: var(--type-heading-sm-font);
87
+ font-size: var(--type-heading-sm-size);
88
+ margin: var(--space-lg) 0 var(--space-xs);
89
+ }
90
+
91
+ .content-block-prose :global(p),
92
+ .content-block-prose :global(ul),
93
+ .content-block-prose :global(ol) {
94
+ margin: 0 0 var(--space-md);
95
+ }
96
+
97
+ .content-block-prose :global(a) {
98
+ color: var(--color-accent);
99
+ }
100
+ </style>
@@ -0,0 +1,37 @@
1
+ export default ContentBlock;
2
+ type ContentBlock = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ /**
7
+ * ContentBlock
8
+ *
9
+ * Prose container for documentation / legal / content pages (privacy, terms,
10
+ * accessibility, regulamento — the `content` page template). Applies readable
11
+ * measure + typographic rhythm to long-form content, with an optional title
12
+ * and a version/date badge slot.
13
+ *
14
+ * SECURITY: ContentBlock only STYLES its children — it does not parse or
15
+ * sanitise. A consumer rendering operator-authored markdown/HTML MUST sanitise
16
+ * before injecting it (XSS); pass the sanitised result as `children`.
17
+ *
18
+ * @example
19
+ * <ContentBlock title="Privacy Policy">
20
+ * {#snippet badge()}<Badge>v3 · updated 2026-05-01</Badge>{/snippet}
21
+ * {@html sanitizedHtml}
22
+ * </ContentBlock>
23
+ */
24
+ declare const ContentBlock: import("svelte").Component<{
25
+ title?: string;
26
+ headingLevel?: number;
27
+ class?: string;
28
+ badge?: any;
29
+ children?: any;
30
+ } & Record<string, any>, {}, "">;
31
+ type $$ComponentProps = {
32
+ title?: string;
33
+ headingLevel?: number;
34
+ class?: string;
35
+ badge?: any;
36
+ children?: any;
37
+ } & Record<string, any>;
@@ -0,0 +1,87 @@
1
+ <!--
2
+ @component Hero
3
+
4
+ Landing / page hero. Renders the page's primary heading (an `<h1>` by
5
+ default — keep exactly one per page for the single-H1 a11y contract), an
6
+ optional subtitle, and an actions slot. Use at the top of `landing` and
7
+ `service-flow` page templates.
8
+
9
+ @example
10
+ <Hero title="Report a problem in Valongo" subtitle="Potholes, lighting, waste — in two minutes.">
11
+ {#snippet actions()}<Button href="/report">Start a report</Button>{/snippet}
12
+ </Hero>
13
+
14
+ @example Custom heading level (when the hero is not the page's H1)
15
+ <Hero title="Latest consultations" headingLevel={2} />
16
+ -->
17
+ <script>
18
+ let {
19
+ /** @type {string} */
20
+ title = "",
21
+ /** @type {string} */
22
+ subtitle = "",
23
+ /** @type {1 | 2 | 3} Heading level for `title` — keep one h1 per page. */
24
+ headingLevel = 1,
25
+ /** @type {string} */
26
+ class: className = "",
27
+ /** @type {import('svelte').Snippet | undefined} Title override (rich content). */
28
+ children = undefined,
29
+ /** @type {import('svelte').Snippet | undefined} Call-to-action buttons. */
30
+ actions = undefined,
31
+ ...rest
32
+ } = $props();
33
+ </script>
34
+
35
+ <section class="hero {className}" {...rest}>
36
+ <div class="hero-inner">
37
+ {#if children}
38
+ {@render children()}
39
+ {:else if title}
40
+ <svelte:element this={`h${headingLevel}`} class="hero-title">{title}</svelte:element>
41
+ {/if}
42
+ {#if subtitle}
43
+ <p class="hero-subtitle">{subtitle}</p>
44
+ {/if}
45
+ {#if actions}
46
+ <div class="hero-actions">{@render actions()}</div>
47
+ {/if}
48
+ </div>
49
+ </section>
50
+
51
+ <style>
52
+ .hero {
53
+ background: var(--color-surface);
54
+ }
55
+
56
+ .hero-inner {
57
+ width: 100%;
58
+ max-width: var(--content-width-wide);
59
+ margin-inline: auto;
60
+ padding: var(--space-3xl) var(--content-padding-x);
61
+ display: flex;
62
+ flex-direction: column;
63
+ gap: var(--space-md);
64
+ }
65
+
66
+ .hero-title {
67
+ margin: 0;
68
+ font-family: var(--type-display-font);
69
+ font-size: var(--type-display-size);
70
+ color: var(--color-text);
71
+ }
72
+
73
+ .hero-subtitle {
74
+ margin: 0;
75
+ max-width: var(--content-width-narrow);
76
+ font-family: var(--type-body-font);
77
+ font-size: var(--type-body-size);
78
+ color: var(--color-text-secondary);
79
+ }
80
+
81
+ .hero-actions {
82
+ display: flex;
83
+ flex-wrap: wrap;
84
+ gap: var(--space-sm);
85
+ margin-top: var(--space-sm);
86
+ }
87
+ </style>
@@ -0,0 +1,37 @@
1
+ export default Hero;
2
+ type Hero = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ /**
7
+ * Hero
8
+ *
9
+ * Landing / page hero. Renders the page's primary heading (an `<h1>` by
10
+ * default — keep exactly one per page for the single-H1 a11y contract), an
11
+ * optional subtitle, and an actions slot. Use at the top of `landing` and
12
+ * `service-flow` page templates.
13
+ *
14
+ * @example
15
+ * <Hero title="Report a problem in Valongo" subtitle="Potholes, lighting, waste — in two minutes.">
16
+ * {#snippet actions()}<Button href="/report">Start a report</Button>{/snippet}
17
+ * </Hero>
18
+ *
19
+ * @example Custom heading level (when the hero is not the page's H1)
20
+ * <Hero title="Latest consultations" headingLevel={2} />
21
+ */
22
+ declare const Hero: import("svelte").Component<{
23
+ title?: string;
24
+ subtitle?: string;
25
+ headingLevel?: number;
26
+ class?: string;
27
+ children?: any;
28
+ actions?: any;
29
+ } & Record<string, any>, {}, "">;
30
+ type $$ComponentProps = {
31
+ title?: string;
32
+ subtitle?: string;
33
+ headingLevel?: number;
34
+ class?: string;
35
+ children?: any;
36
+ actions?: any;
37
+ } & Record<string, any>;
@@ -0,0 +1,72 @@
1
+ <script lang="ts">
2
+ /**
3
+ * Compact-mobile layout (#27 / S7).
4
+ *
5
+ * Sections collapse into a single tight column with reduced padding
6
+ * and smaller meta. Used by `public_submit` placements that target
7
+ * narrow viewports (citizen mobile portal). Structurally a single
8
+ * column like stacked-default, but distinguishable by reduced gap +
9
+ * absent section card chrome — section labels become inline headings
10
+ * so the form reads denser on mobile.
11
+ */
12
+ import type { LayoutSection } from "./action-form-renderer-layouts";
13
+ import type { Snippet } from "svelte";
14
+
15
+ let {
16
+ sections,
17
+ field,
18
+ }: {
19
+ sections: LayoutSection[];
20
+ field: Snippet<[Record<string, unknown>]>;
21
+ } = $props();
22
+ </script>
23
+
24
+ <div class="layout-compact" data-layout-shape="compact">
25
+ {#each sections as section (section.name)}
26
+ <section class="compact-section" aria-label={section.name}>
27
+ <h5>{section.name}</h5>
28
+ {#each section.items as parameter}
29
+ <div class="field-row">
30
+ {@render field(parameter)}
31
+ </div>
32
+ {/each}
33
+ </section>
34
+ {/each}
35
+ </div>
36
+
37
+ <style>
38
+ /* Single tight column — distinguishable from stacked-default by:
39
+ 1. No Card chrome around sections (HTML <section>, not DS Card),
40
+ 2. Compact gap and padding,
41
+ 3. <h5> heading not <h4>. */
42
+ .layout-compact {
43
+ display: flex;
44
+ flex-direction: column;
45
+ gap: var(--space-sm);
46
+ }
47
+
48
+ .compact-section {
49
+ display: flex;
50
+ flex-direction: column;
51
+ gap: var(--space-xs);
52
+ padding: var(--space-xs) 0;
53
+ border-bottom: var(--elevation-border);
54
+ }
55
+
56
+ .compact-section:last-child {
57
+ border-bottom: 0;
58
+ }
59
+
60
+ .compact-section h5 {
61
+ margin: 0;
62
+ font-size: var(--type-caption-size);
63
+ /* #63 typography — uppercase reserved for code tokens. */
64
+ color: var(--color-text-muted);
65
+ }
66
+
67
+ .field-row {
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: 2px;
71
+ }
72
+ </style>
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Compact-mobile layout (#27 / S7).
3
+ *
4
+ * Sections collapse into a single tight column with reduced padding
5
+ * and smaller meta. Used by `public_submit` placements that target
6
+ * narrow viewports (citizen mobile portal). Structurally a single
7
+ * column like stacked-default, but distinguishable by reduced gap +
8
+ * absent section card chrome — section labels become inline headings
9
+ * so the form reads denser on mobile.
10
+ */
11
+ import type { LayoutSection } from "./action-form-renderer-layouts";
12
+ import type { Snippet } from "svelte";
13
+ type $$ComponentProps = {
14
+ sections: LayoutSection[];
15
+ field: Snippet<[Record<string, unknown>]>;
16
+ };
17
+ declare const LayoutCompactMobile: import("svelte").Component<$$ComponentProps, {}, "">;
18
+ type LayoutCompactMobile = ReturnType<typeof LayoutCompactMobile>;
19
+ export default LayoutCompactMobile;
@@ -0,0 +1,74 @@
1
+ <script lang="ts">
2
+ /**
3
+ * Inline-row layout (#27 / S7).
4
+ *
5
+ * Parameters in each section are arranged in a single horizontal row
6
+ * using auto-fit grid, suitable for compact admin runtime forms
7
+ * (one-line filters, narrow inline panels). This is structurally
8
+ * distinct from stacked-default — same parameter set produces a grid
9
+ * with multiple columns instead of a vertical column. The S7
10
+ * acceptance asserts the structural difference.
11
+ */
12
+ import Card from "./Card.svelte";
13
+ import type { LayoutSection } from "./action-form-renderer-layouts";
14
+ import type { Snippet } from "svelte";
15
+
16
+ let {
17
+ sections,
18
+ field,
19
+ }: {
20
+ sections: LayoutSection[];
21
+ field: Snippet<[Record<string, unknown>]>;
22
+ } = $props();
23
+ </script>
24
+
25
+ <div class="layout-inline" data-layout-shape="inline">
26
+ {#each sections as section (section.name)}
27
+ <Card variant="flat" class="section" role="group" aria-label={section.name}>
28
+ <h4>{section.name}</h4>
29
+ <div class="row">
30
+ {#each section.items as parameter}
31
+ <div class="field-cell">
32
+ {@render field(parameter)}
33
+ </div>
34
+ {/each}
35
+ </div>
36
+ </Card>
37
+ {/each}
38
+ </div>
39
+
40
+ <style>
41
+ .layout-inline {
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: var(--space-md);
45
+ }
46
+
47
+ .layout-inline :global(.section) {
48
+ display: flex;
49
+ flex-direction: column;
50
+ gap: var(--space-sm);
51
+ }
52
+
53
+ /* The defining shape — auto-fit columns, NOT a vertical stack. The
54
+ same parameter set renders as a multi-column grid here vs. one
55
+ column in stacked-default. */
56
+ .row {
57
+ display: grid;
58
+ grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
59
+ gap: var(--space-md);
60
+ align-items: end;
61
+ }
62
+
63
+ .field-cell {
64
+ display: flex;
65
+ flex-direction: column;
66
+ gap: var(--space-xs);
67
+ min-width: 0;
68
+ }
69
+
70
+ h4 {
71
+ margin: 0;
72
+ font-size: var(--type-body-size);
73
+ }
74
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { LayoutSection } from "./action-form-renderer-layouts";
2
+ import type { Snippet } from "svelte";
3
+ type $$ComponentProps = {
4
+ sections: LayoutSection[];
5
+ field: Snippet<[Record<string, unknown>]>;
6
+ };
7
+ declare const LayoutInlineRow: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type LayoutInlineRow = ReturnType<typeof LayoutInlineRow>;
9
+ export default LayoutInlineRow;
@@ -0,0 +1,66 @@
1
+ <script lang="ts">
2
+ /**
3
+ * Default vertical-stack layout for the action renderer (#27 / S7).
4
+ *
5
+ * Each section is a labelled <fieldset>, parameters laid out as a
6
+ * single-column flex column. This is the safe fallback for unknown
7
+ * layout keys — see `resolve.ts`.
8
+ */
9
+ import Card from "./Card.svelte";
10
+ import type { LayoutSection } from "./action-form-renderer-layouts";
11
+ import type { Snippet } from "svelte";
12
+
13
+ let {
14
+ sections,
15
+ field,
16
+ }: {
17
+ sections: LayoutSection[];
18
+ field: Snippet<[Record<string, unknown>]>;
19
+ } = $props();
20
+ </script>
21
+
22
+ <div class="layout-stacked" data-layout-shape="stacked">
23
+ {#each sections as section (section.name)}
24
+ <Card variant="flat" class="section" role="group" aria-label={section.name}>
25
+ <h4>{section.name}</h4>
26
+ <div class="rows">
27
+ {#each section.items as parameter}
28
+ <div class="field-row">
29
+ {@render field(parameter)}
30
+ </div>
31
+ {/each}
32
+ </div>
33
+ </Card>
34
+ {/each}
35
+ </div>
36
+
37
+ <style>
38
+ .layout-stacked {
39
+ display: flex;
40
+ flex-direction: column;
41
+ gap: var(--space-md);
42
+ }
43
+
44
+ .layout-stacked :global(.section) {
45
+ display: flex;
46
+ flex-direction: column;
47
+ gap: var(--space-sm);
48
+ }
49
+
50
+ .rows {
51
+ display: flex;
52
+ flex-direction: column;
53
+ gap: var(--space-md);
54
+ }
55
+
56
+ .field-row {
57
+ display: flex;
58
+ flex-direction: column;
59
+ gap: var(--space-xs);
60
+ }
61
+
62
+ h4 {
63
+ margin: 0;
64
+ font-size: var(--type-body-size);
65
+ }
66
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { LayoutSection } from "./action-form-renderer-layouts";
2
+ import type { Snippet } from "svelte";
3
+ type $$ComponentProps = {
4
+ sections: LayoutSection[];
5
+ field: Snippet<[Record<string, unknown>]>;
6
+ };
7
+ declare const LayoutStackedDefault: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type LayoutStackedDefault = ReturnType<typeof LayoutStackedDefault>;
9
+ export default LayoutStackedDefault;
@@ -0,0 +1,100 @@
1
+ <!--
2
+ @component Link
3
+
4
+ A text hyperlink. Two variants, following the Carbon convention:
5
+ - `inline` (default): used inside sentences/prose — always underlined so it's
6
+ distinguishable from surrounding text.
7
+ - `standalone`: used on its own after content (lists, CTAs, footers) —
8
+ underlined only on hover/focus.
9
+
10
+ Accessibility:
11
+ - A link with no (or empty) `href` is NOT a link — it renders a
12
+ non-interactive `<span aria-current="page">` (the canonical "you are here"
13
+ treatment) instead of a keyboard-trap `<a>` with no destination.
14
+ - `external` adds `target="_blank"` + `rel="noopener noreferrer"`.
15
+ - Visible focus ring on `:focus-visible`.
16
+
17
+ @example Inline (prose)
18
+ Read our <Link href="/info/privacy">privacy policy</Link>.
19
+
20
+ @example Standalone CTA
21
+ <Link href="/report" variant="standalone">Report a problem</Link>
22
+
23
+ @example Current page (no href → rendered as non-interactive)
24
+ <Link current>Home</Link>
25
+ -->
26
+ <script>
27
+ let {
28
+ /** @type {string | undefined} Destination. Falsy → rendered as a non-interactive span. */
29
+ href = undefined,
30
+ /** @type {'inline' | 'standalone'} */
31
+ variant = "inline",
32
+ /** @type {boolean} Marks the current page (`aria-current="page"`). */
33
+ current = false,
34
+ /** @type {boolean} Open in a new tab with safe rel. */
35
+ external = false,
36
+ /** @type {string} */
37
+ class: className = "",
38
+ /** @type {import('svelte').Snippet | undefined} */
39
+ children = undefined,
40
+ ...rest
41
+ } = $props();
42
+
43
+ const isLink = $derived(typeof href === "string" && href.length > 0);
44
+ const externalAttrs = $derived(
45
+ external ? { target: "_blank", rel: "noopener noreferrer" } : {},
46
+ );
47
+ </script>
48
+
49
+ {#if isLink}
50
+ <a
51
+ {href}
52
+ class="link link-{variant} {className}"
53
+ aria-current={current ? "page" : undefined}
54
+ {...externalAttrs}
55
+ {...rest}
56
+ >
57
+ {#if children}{@render children()}{/if}
58
+ </a>
59
+ {:else}
60
+ <!-- No destination → not a link. Non-interactive, still announces "current". -->
61
+ <span class="link link-{variant} link-static {className}" aria-current={current ? "page" : undefined} {...rest}>
62
+ {#if children}{@render children()}{/if}
63
+ </span>
64
+ {/if}
65
+
66
+ <style>
67
+ .link {
68
+ color: var(--color-accent);
69
+ border-radius: var(--radius-sm);
70
+ }
71
+
72
+ .link-inline {
73
+ text-decoration: underline;
74
+ text-underline-offset: 0.15em;
75
+ }
76
+
77
+ .link-standalone {
78
+ text-decoration: none;
79
+ }
80
+ .link-standalone:hover {
81
+ text-decoration: underline;
82
+ text-underline-offset: 0.15em;
83
+ }
84
+
85
+ a.link:hover {
86
+ color: var(--color-accent-hover);
87
+ }
88
+
89
+ a.link:focus-visible {
90
+ outline: var(--focus-ring-width) solid var(--focus-ring-color);
91
+ outline-offset: var(--focus-ring-offset);
92
+ }
93
+
94
+ /* Non-interactive (current/no-href): inherit text colour, no affordance. */
95
+ .link-static {
96
+ color: var(--color-text);
97
+ text-decoration: none;
98
+ cursor: default;
99
+ }
100
+ </style>
@@ -0,0 +1,46 @@
1
+ export default Link;
2
+ type Link = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ /**
7
+ * Link
8
+ *
9
+ * A text hyperlink. Two variants, following the Carbon convention:
10
+ * - `inline` (default): used inside sentences/prose — always underlined so it's
11
+ * distinguishable from surrounding text.
12
+ * - `standalone`: used on its own after content (lists, CTAs, footers) —
13
+ * underlined only on hover/focus.
14
+ *
15
+ * Accessibility:
16
+ * - A link with no (or empty) `href` is NOT a link — it renders a
17
+ * non-interactive `<span aria-current="page">` (the canonical "you are here"
18
+ * treatment) instead of a keyboard-trap `<a>` with no destination.
19
+ * - `external` adds `target="_blank"` + `rel="noopener noreferrer"`.
20
+ * - Visible focus ring on `:focus-visible`.
21
+ *
22
+ * @example Inline (prose)
23
+ * Read our <Link href="/info/privacy">privacy policy</Link>.
24
+ *
25
+ * @example Standalone CTA
26
+ * <Link href="/report" variant="standalone">Report a problem</Link>
27
+ *
28
+ * @example Current page (no href → rendered as non-interactive)
29
+ * <Link current>Home</Link>
30
+ */
31
+ declare const Link: import("svelte").Component<{
32
+ href?: any;
33
+ variant?: string;
34
+ current?: boolean;
35
+ external?: boolean;
36
+ class?: string;
37
+ children?: any;
38
+ } & Record<string, any>, {}, "">;
39
+ type $$ComponentProps = {
40
+ href?: any;
41
+ variant?: string;
42
+ current?: boolean;
43
+ external?: boolean;
44
+ class?: string;
45
+ children?: any;
46
+ } & Record<string, any>;