@lilydesignsystem/svelte-headless 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/components/CandlestickChart/CandlestickChart.svelte +63 -0
- package/dist/components/CandlestickChart/CandlestickChart.svelte.d.ts +13 -0
- package/dist/components/ChatComposer/ChatComposer.svelte +110 -0
- package/dist/components/ChatComposer/ChatComposer.svelte.d.ts +25 -0
- package/dist/components/ChoroplethChart/ChoroplethChart.svelte +63 -0
- package/dist/components/ChoroplethChart/ChoroplethChart.svelte.d.ts +13 -0
- package/dist/components/ComposedChart/ComposedChart.svelte +63 -0
- package/dist/components/ComposedChart/ComposedChart.svelte.d.ts +13 -0
- package/dist/components/ContentsLink/ContentsLink.svelte +36 -2
- package/dist/components/ContentsLink/ContentsLink.svelte.d.ts +3 -0
- package/dist/components/ContentsNav/ContentsNav.svelte +193 -1
- package/dist/components/ContentsNav/ContentsNav.svelte.d.ts +18 -1
- package/dist/components/DataTableTD/DataTableTD.svelte +5 -7
- package/dist/components/DataTableTD/DataTableTD.svelte.d.ts +1 -1
- package/dist/components/FiveFaceRatingPicker/FiveFaceRatingPicker.svelte +32 -2
- package/dist/components/FiveFaceRatingView/FiveFaceRatingView.svelte +3 -2
- package/dist/components/FiveStarRatingPicker/FiveStarRatingPicker.svelte +34 -2
- package/dist/components/FiveStarRatingPicker/FiveStarRatingPicker.svelte.d.ts +2 -0
- package/dist/components/FunnelChart/FunnelChart.svelte +63 -0
- package/dist/components/FunnelChart/FunnelChart.svelte.d.ts +13 -0
- package/dist/components/GanttTableTD/GanttTableTD.svelte +3 -4
- package/dist/components/KanbanTableTD/KanbanTableTD.svelte +3 -4
- package/dist/components/KanbanTableTD/KanbanTableTD.svelte.d.ts +1 -1
- package/dist/components/Mark/Mark.svelte +27 -0
- package/dist/components/Mark/Mark.svelte.d.ts +9 -0
- package/dist/components/NetPromoterScorePicker/NetPromoterScorePicker.svelte +29 -0
- package/dist/components/PieChart/PieChart.svelte +63 -0
- package/dist/components/PieChart/PieChart.svelte.d.ts +13 -0
- package/dist/components/PinInputDiv/PinInputDiv.svelte +42 -2
- package/dist/components/PinInputDiv/PinInputDiv.svelte.d.ts +5 -0
- package/dist/components/RingChart/RingChart.svelte +63 -0
- package/dist/components/RingChart/RingChart.svelte.d.ts +13 -0
- package/dist/components/StreamingText/StreamingText.svelte +48 -0
- package/dist/components/StreamingText/StreamingText.svelte.d.ts +13 -0
- package/dist/components/SunburstChart/SunburstChart.svelte +63 -0
- package/dist/components/SunburstChart/SunburstChart.svelte.d.ts +13 -0
- package/dist/components/Tag/Tag.svelte +20 -8
- package/dist/components/Tag/Tag.svelte.d.ts +6 -0
- package/dist/components/ToolCall/ToolCall.svelte +54 -0
- package/dist/components/ToolCall/ToolCall.svelte.d.ts +15 -0
- package/dist/components/ToolCallError/ToolCallError.svelte +27 -0
- package/dist/components/ToolCallError/ToolCallError.svelte.d.ts +9 -0
- package/dist/components/ToolCallInput/ToolCallInput.svelte +30 -0
- package/dist/components/ToolCallInput/ToolCallInput.svelte.d.ts +11 -0
- package/dist/components/ToolCallName/ToolCallName.svelte +27 -0
- package/dist/components/ToolCallName/ToolCallName.svelte.d.ts +9 -0
- package/dist/components/ToolCallOutput/ToolCallOutput.svelte +30 -0
- package/dist/components/ToolCallOutput/ToolCallOutput.svelte.d.ts +11 -0
- package/dist/components/ToolCallStatus/ToolCallStatus.svelte +29 -0
- package/dist/components/ToolCallStatus/ToolCallStatus.svelte.d.ts +11 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +16 -0
- package/index.md +1 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,37 @@
|
|
|
3
3
|
The format is loosely based on [Keep a Changelog](https://keepachangelog.com/)
|
|
4
4
|
and the package follows [Semantic Versioning](https://semver.org/).
|
|
5
5
|
|
|
6
|
+
## 0.5.0 — 2026-10-14 (scrollspy, link counts)
|
|
7
|
+
|
|
8
|
+
- `ContentsNav` gains scrollspy (`spy`): the link of the section in view gets `aria-current` and `data-active`. Props `spy`, `offset`, `root`, `current`, bindable `active`, `onActiveChange`.
|
|
9
|
+
- `ContentsLink` gains `count` and `countLabel`: a visible, localised count inside the link, with `data-count` (and `data-complete` at 0). The Svelte `ContentsLink` is now a real `<a>` (it was a placeholder `<div>`).
|
|
10
|
+
|
|
11
|
+
## Unreleased — 2026-10-11 (labels and contracts)
|
|
12
|
+
|
|
13
|
+
`PinInputDiv` takes `digitLabel` and no longer names its boxes in English; `FiveStarRatingPicker` takes `starLabel`; `FiveFaceRatingPicker` / `FiveFaceRatingView` default their labels to the numbers. `Tag` is not a live region unless `live` is set. The form-reset fixes listed above now also reach `components/`, which the build publishes. See the repository CHANGELOG (2026-10-11).
|
|
14
|
+
|
|
15
|
+
## Unreleased — 2026-10-11
|
|
16
|
+
|
|
17
|
+
Fixed: `FiveStarRatingPicker`, `FiveFaceRatingPicker`, `NetPromoterScorePicker` and `PinInputDiv` restore their initial value when their `<form>` is reset (one tick after `reset`, unless it is
|
|
18
|
+
cancelled); before, a reset changed the inputs without telling the component, so its value disagreed with what the
|
|
19
|
+
form showed or submitted. `PinInputDiv` also now shows its initial `value` instead of overwriting it with an empty string on mount.
|
|
20
|
+
|
|
21
|
+
## 0.4.0 — 2026-10-06
|
|
22
|
+
|
|
23
|
+
**16 new components (catalog 555 → 571); no breaking changes.**
|
|
24
|
+
Seven charts built with the graphic + optional data-table structure
|
|
25
|
+
introduced in the previous release: `pie-chart`, `ring-chart`,
|
|
26
|
+
`funnel-chart`, `candlestick-chart`, `composed-chart`, `choropleth-chart`,
|
|
27
|
+
`sunburst-chart`. `streaming-text` (a polite, atomic status region that goes
|
|
28
|
+
busy while text arrives, then announces the finished text once). `tool-call`
|
|
29
|
+
(a native `<details>` with `status`) and its inner parts `tool-call-name`,
|
|
30
|
+
`tool-call-status`, `tool-call-input`, `tool-call-output`, `tool-call-error`.
|
|
31
|
+
`mark` (the native `<mark>` highlight). `chat-composer` (a chat input form:
|
|
32
|
+
growing textarea, Enter sends, Shift+Enter inserts a line break, IME-safe, one
|
|
33
|
+
button that is send or stop). See the monorepo CHANGELOG for the full record
|
|
34
|
+
and the per-library deviations (Blazor: no plain-Enter send; Nunjucks and
|
|
35
|
+
HTML: markup-only `chat-composer`).
|
|
36
|
+
|
|
6
37
|
## 0.3.0 — 2026-10-05
|
|
7
38
|
|
|
8
39
|
**16 new components (catalog 539 → 555) and a breaking chart change.**
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// CandlestickChart component
|
|
3
|
+
//
|
|
4
|
+
// A headless chart container for a financial chart showing open, high, low and close values for each period as candles. The consumer supplies the inline
|
|
5
|
+
// svg as `children`; the component draws nothing. The graphic is a
|
|
6
|
+
// role="img" wrapper named by `label`. The optional `dataTable` snippet
|
|
7
|
+
// renders the accessible table alternative as a SIBLING of that image
|
|
8
|
+
// wrapper, never inside it: a role="img" element makes its descendants
|
|
9
|
+
// presentational, so a table placed inside would be invisible to
|
|
10
|
+
// assistive technology.
|
|
11
|
+
//
|
|
12
|
+
// Props:
|
|
13
|
+
// class — string, optional. Consumer class appended after the base class.
|
|
14
|
+
// label — string, optional. Accessible name of the chart image.
|
|
15
|
+
// children — Snippet. The consumer-supplied inline svg.
|
|
16
|
+
// dataTable — Snippet, optional. The accessible table alternative.
|
|
17
|
+
// ...restProps — spread onto the root <figure>.
|
|
18
|
+
//
|
|
19
|
+
// Markup:
|
|
20
|
+
// <figure class="candlestick-chart">
|
|
21
|
+
// <div class="candlestick-chart-graphic" role="img" aria-label>…svg…</div>
|
|
22
|
+
// <div class="candlestick-chart-data-table">…table…</div> (only when provided)
|
|
23
|
+
// </figure>
|
|
24
|
+
//
|
|
25
|
+
// Keyboard: none on the graphic; the data table follows native table behaviour.
|
|
26
|
+
//
|
|
27
|
+
// Claude rules:
|
|
28
|
+
// - Headless: no CSS, no inline styles; no drawing.
|
|
29
|
+
// - No hardcoded user-facing strings.
|
|
30
|
+
|
|
31
|
+
import type { Snippet } from "svelte";
|
|
32
|
+
|
|
33
|
+
let {
|
|
34
|
+
class: className = "",
|
|
35
|
+
label = undefined,
|
|
36
|
+
children,
|
|
37
|
+
dataTable,
|
|
38
|
+
...restProps
|
|
39
|
+
}: {
|
|
40
|
+
/** Accessible name for the chart. */
|
|
41
|
+
label?: string;
|
|
42
|
+
/** The consumer-supplied inline svg. */
|
|
43
|
+
children: Snippet;
|
|
44
|
+
/** Optional accessible data table alternative. */
|
|
45
|
+
dataTable?: Snippet;
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
} = $props();
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<!-- CandlestickChart.svelte -->
|
|
51
|
+
<figure
|
|
52
|
+
class={`candlestick-chart ${className}`}
|
|
53
|
+
{...restProps}
|
|
54
|
+
>
|
|
55
|
+
<div class="candlestick-chart-graphic" role="img" aria-label={label}>
|
|
56
|
+
{@render children?.()}
|
|
57
|
+
</div>
|
|
58
|
+
{#if dataTable}
|
|
59
|
+
<div class="candlestick-chart-data-table">
|
|
60
|
+
{@render dataTable()}
|
|
61
|
+
</div>
|
|
62
|
+
{/if}
|
|
63
|
+
</figure>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
/** Accessible name for the chart. */
|
|
4
|
+
label?: string;
|
|
5
|
+
/** The consumer-supplied inline svg. */
|
|
6
|
+
children: Snippet;
|
|
7
|
+
/** Optional accessible data table alternative. */
|
|
8
|
+
dataTable?: Snippet;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
};
|
|
11
|
+
declare const CandlestickChart: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
12
|
+
type CandlestickChart = ReturnType<typeof CandlestickChart>;
|
|
13
|
+
export default CandlestickChart;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// ChatComposer component
|
|
3
|
+
//
|
|
4
|
+
// A headless chat input form: a <textarea> that grows with its content (rows from the number of lines, clamped between minRows and maxRows) and ONE button that is "send" normally and turns into "stop" while `busy`. Enter sends; Shift+Enter inserts a line break; Enter while an IME composition is in progress does nothing. The send button is disabled, never hidden, when the text is empty or the form is disabled. The component never clears the text (the consumer does, in its send handler), never animates, and carries no strings: the textarea name, the send word and the stop word are required props. Models, attachments and menus are consumer composition (put them in the default slot, rendered before the textarea).
|
|
5
|
+
//
|
|
6
|
+
// Props:
|
|
7
|
+
// class — string, optional. CSS class name.
|
|
8
|
+
// label — string, required. Accessible name of the textarea.
|
|
9
|
+
// sendLabel — string, required. Visible/accessible word for the send button.
|
|
10
|
+
// stopLabel — string, required. Visible/accessible word for the stop button.
|
|
11
|
+
// value — string, default "". Bindable.
|
|
12
|
+
// placeholder, name — optional, passed to the textarea.
|
|
13
|
+
// minRows — number, default 1. maxRows — number, default 8.
|
|
14
|
+
// busy — boolean, default false. A reply is in progress: the button becomes "stop".
|
|
15
|
+
// disabled — boolean, default false.
|
|
16
|
+
// onSend(value) — called on Enter or submit when there is text and not busy/disabled.
|
|
17
|
+
// onStop() — called when the stop button is pressed.
|
|
18
|
+
// children — Snippet, optional. Rendered inside the form, before the textarea.
|
|
19
|
+
// ...restProps — additional HTML attributes spread onto the root <form>.
|
|
20
|
+
//
|
|
21
|
+
// Keyboard: Enter sends; Shift+Enter inserts a line break; Enter during IME composition is ignored.
|
|
22
|
+
//
|
|
23
|
+
// Claude rules:
|
|
24
|
+
// - Headless: no CSS, no inline styles, no animation, no hardcoded strings
|
|
25
|
+
import type { Snippet } from "svelte";
|
|
26
|
+
|
|
27
|
+
let {
|
|
28
|
+
class: className = "",
|
|
29
|
+
label,
|
|
30
|
+
sendLabel,
|
|
31
|
+
stopLabel,
|
|
32
|
+
value = $bindable(""),
|
|
33
|
+
placeholder = undefined,
|
|
34
|
+
name = undefined,
|
|
35
|
+
minRows = 1,
|
|
36
|
+
maxRows = 8,
|
|
37
|
+
busy = false,
|
|
38
|
+
disabled = false,
|
|
39
|
+
onSend,
|
|
40
|
+
onStop,
|
|
41
|
+
children,
|
|
42
|
+
...restProps
|
|
43
|
+
}: {
|
|
44
|
+
/** Accessible name of the textarea. */
|
|
45
|
+
label: string;
|
|
46
|
+
/** Word for the send button. */
|
|
47
|
+
sendLabel: string;
|
|
48
|
+
/** Word for the stop button. */
|
|
49
|
+
stopLabel: string;
|
|
50
|
+
/** The text. Bindable. */
|
|
51
|
+
value?: string;
|
|
52
|
+
placeholder?: string;
|
|
53
|
+
name?: string;
|
|
54
|
+
minRows?: number;
|
|
55
|
+
maxRows?: number;
|
|
56
|
+
/** A reply is in progress. */
|
|
57
|
+
busy?: boolean;
|
|
58
|
+
disabled?: boolean;
|
|
59
|
+
onSend?: (value: string) => void;
|
|
60
|
+
onStop?: () => void;
|
|
61
|
+
children?: Snippet;
|
|
62
|
+
[key: string]: unknown;
|
|
63
|
+
} = $props();
|
|
64
|
+
|
|
65
|
+
const empty = $derived(value.trim() === "");
|
|
66
|
+
const rows = $derived(Math.min(maxRows, Math.max(minRows, value.split("\n").length)));
|
|
67
|
+
|
|
68
|
+
function trySend(): void {
|
|
69
|
+
if (disabled || busy || empty) return;
|
|
70
|
+
onSend?.(value);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function onKeydown(event: KeyboardEvent): void {
|
|
74
|
+
if (event.key !== "Enter") return;
|
|
75
|
+
if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey) return;
|
|
76
|
+
// IME: Enter that confirms a composition must not send.
|
|
77
|
+
if (event.isComposing || event.keyCode === 229) return;
|
|
78
|
+
event.preventDefault();
|
|
79
|
+
trySend();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function onSubmit(event: SubmitEvent): void {
|
|
83
|
+
event.preventDefault();
|
|
84
|
+
trySend();
|
|
85
|
+
}
|
|
86
|
+
</script>
|
|
87
|
+
|
|
88
|
+
<!-- ChatComposer.svelte -->
|
|
89
|
+
<form class={`chat-composer ${className}`} onsubmit={onSubmit} {...restProps}>
|
|
90
|
+
{@render children?.()}
|
|
91
|
+
<textarea
|
|
92
|
+
class="chat-composer-input"
|
|
93
|
+
aria-label={label}
|
|
94
|
+
bind:value
|
|
95
|
+
{rows}
|
|
96
|
+
{placeholder}
|
|
97
|
+
{name}
|
|
98
|
+
{disabled}
|
|
99
|
+
onkeydown={onKeydown}
|
|
100
|
+
></textarea>
|
|
101
|
+
<button
|
|
102
|
+
class="chat-composer-button"
|
|
103
|
+
type={busy ? "button" : "submit"}
|
|
104
|
+
data-state={busy ? "stop" : "send"}
|
|
105
|
+
disabled={disabled || (!busy && empty)}
|
|
106
|
+
onclick={busy ? () => onStop?.() : undefined}
|
|
107
|
+
>
|
|
108
|
+
<span class="chat-composer-button-label">{busy ? stopLabel : sendLabel}</span>
|
|
109
|
+
</button>
|
|
110
|
+
</form>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
/** Accessible name of the textarea. */
|
|
4
|
+
label: string;
|
|
5
|
+
/** Word for the send button. */
|
|
6
|
+
sendLabel: string;
|
|
7
|
+
/** Word for the stop button. */
|
|
8
|
+
stopLabel: string;
|
|
9
|
+
/** The text. Bindable. */
|
|
10
|
+
value?: string;
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
minRows?: number;
|
|
14
|
+
maxRows?: number;
|
|
15
|
+
/** A reply is in progress. */
|
|
16
|
+
busy?: boolean;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
onSend?: (value: string) => void;
|
|
19
|
+
onStop?: () => void;
|
|
20
|
+
children?: Snippet;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
};
|
|
23
|
+
declare const ChatComposer: import("svelte").Component<$$ComponentProps, {}, "value">;
|
|
24
|
+
type ChatComposer = ReturnType<typeof ChatComposer>;
|
|
25
|
+
export default ChatComposer;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// ChoroplethChart component
|
|
3
|
+
//
|
|
4
|
+
// A headless chart container for a map chart that shades regions by the value of a measure. The consumer supplies the inline
|
|
5
|
+
// svg as `children`; the component draws nothing. The graphic is a
|
|
6
|
+
// role="img" wrapper named by `label`. The optional `dataTable` snippet
|
|
7
|
+
// renders the accessible table alternative as a SIBLING of that image
|
|
8
|
+
// wrapper, never inside it: a role="img" element makes its descendants
|
|
9
|
+
// presentational, so a table placed inside would be invisible to
|
|
10
|
+
// assistive technology.
|
|
11
|
+
//
|
|
12
|
+
// Props:
|
|
13
|
+
// class — string, optional. Consumer class appended after the base class.
|
|
14
|
+
// label — string, optional. Accessible name of the chart image.
|
|
15
|
+
// children — Snippet. The consumer-supplied inline svg.
|
|
16
|
+
// dataTable — Snippet, optional. The accessible table alternative.
|
|
17
|
+
// ...restProps — spread onto the root <figure>.
|
|
18
|
+
//
|
|
19
|
+
// Markup:
|
|
20
|
+
// <figure class="choropleth-chart">
|
|
21
|
+
// <div class="choropleth-chart-graphic" role="img" aria-label>…svg…</div>
|
|
22
|
+
// <div class="choropleth-chart-data-table">…table…</div> (only when provided)
|
|
23
|
+
// </figure>
|
|
24
|
+
//
|
|
25
|
+
// Keyboard: none on the graphic; the data table follows native table behaviour.
|
|
26
|
+
//
|
|
27
|
+
// Claude rules:
|
|
28
|
+
// - Headless: no CSS, no inline styles; no drawing.
|
|
29
|
+
// - No hardcoded user-facing strings.
|
|
30
|
+
|
|
31
|
+
import type { Snippet } from "svelte";
|
|
32
|
+
|
|
33
|
+
let {
|
|
34
|
+
class: className = "",
|
|
35
|
+
label = undefined,
|
|
36
|
+
children,
|
|
37
|
+
dataTable,
|
|
38
|
+
...restProps
|
|
39
|
+
}: {
|
|
40
|
+
/** Accessible name for the chart. */
|
|
41
|
+
label?: string;
|
|
42
|
+
/** The consumer-supplied inline svg. */
|
|
43
|
+
children: Snippet;
|
|
44
|
+
/** Optional accessible data table alternative. */
|
|
45
|
+
dataTable?: Snippet;
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
} = $props();
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<!-- ChoroplethChart.svelte -->
|
|
51
|
+
<figure
|
|
52
|
+
class={`choropleth-chart ${className}`}
|
|
53
|
+
{...restProps}
|
|
54
|
+
>
|
|
55
|
+
<div class="choropleth-chart-graphic" role="img" aria-label={label}>
|
|
56
|
+
{@render children?.()}
|
|
57
|
+
</div>
|
|
58
|
+
{#if dataTable}
|
|
59
|
+
<div class="choropleth-chart-data-table">
|
|
60
|
+
{@render dataTable()}
|
|
61
|
+
</div>
|
|
62
|
+
{/if}
|
|
63
|
+
</figure>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
/** Accessible name for the chart. */
|
|
4
|
+
label?: string;
|
|
5
|
+
/** The consumer-supplied inline svg. */
|
|
6
|
+
children: Snippet;
|
|
7
|
+
/** Optional accessible data table alternative. */
|
|
8
|
+
dataTable?: Snippet;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
};
|
|
11
|
+
declare const ChoroplethChart: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
12
|
+
type ChoroplethChart = ReturnType<typeof ChoroplethChart>;
|
|
13
|
+
export default ChoroplethChart;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// ComposedChart component
|
|
3
|
+
//
|
|
4
|
+
// A headless chart container for a chart that combines several chart types, such as bars and a line, on shared axes. The consumer supplies the inline
|
|
5
|
+
// svg as `children`; the component draws nothing. The graphic is a
|
|
6
|
+
// role="img" wrapper named by `label`. The optional `dataTable` snippet
|
|
7
|
+
// renders the accessible table alternative as a SIBLING of that image
|
|
8
|
+
// wrapper, never inside it: a role="img" element makes its descendants
|
|
9
|
+
// presentational, so a table placed inside would be invisible to
|
|
10
|
+
// assistive technology.
|
|
11
|
+
//
|
|
12
|
+
// Props:
|
|
13
|
+
// class — string, optional. Consumer class appended after the base class.
|
|
14
|
+
// label — string, optional. Accessible name of the chart image.
|
|
15
|
+
// children — Snippet. The consumer-supplied inline svg.
|
|
16
|
+
// dataTable — Snippet, optional. The accessible table alternative.
|
|
17
|
+
// ...restProps — spread onto the root <figure>.
|
|
18
|
+
//
|
|
19
|
+
// Markup:
|
|
20
|
+
// <figure class="composed-chart">
|
|
21
|
+
// <div class="composed-chart-graphic" role="img" aria-label>…svg…</div>
|
|
22
|
+
// <div class="composed-chart-data-table">…table…</div> (only when provided)
|
|
23
|
+
// </figure>
|
|
24
|
+
//
|
|
25
|
+
// Keyboard: none on the graphic; the data table follows native table behaviour.
|
|
26
|
+
//
|
|
27
|
+
// Claude rules:
|
|
28
|
+
// - Headless: no CSS, no inline styles; no drawing.
|
|
29
|
+
// - No hardcoded user-facing strings.
|
|
30
|
+
|
|
31
|
+
import type { Snippet } from "svelte";
|
|
32
|
+
|
|
33
|
+
let {
|
|
34
|
+
class: className = "",
|
|
35
|
+
label = undefined,
|
|
36
|
+
children,
|
|
37
|
+
dataTable,
|
|
38
|
+
...restProps
|
|
39
|
+
}: {
|
|
40
|
+
/** Accessible name for the chart. */
|
|
41
|
+
label?: string;
|
|
42
|
+
/** The consumer-supplied inline svg. */
|
|
43
|
+
children: Snippet;
|
|
44
|
+
/** Optional accessible data table alternative. */
|
|
45
|
+
dataTable?: Snippet;
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
} = $props();
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<!-- ComposedChart.svelte -->
|
|
51
|
+
<figure
|
|
52
|
+
class={`composed-chart ${className}`}
|
|
53
|
+
{...restProps}
|
|
54
|
+
>
|
|
55
|
+
<div class="composed-chart-graphic" role="img" aria-label={label}>
|
|
56
|
+
{@render children?.()}
|
|
57
|
+
</div>
|
|
58
|
+
{#if dataTable}
|
|
59
|
+
<div class="composed-chart-data-table">
|
|
60
|
+
{@render dataTable()}
|
|
61
|
+
</div>
|
|
62
|
+
{/if}
|
|
63
|
+
</figure>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
/** Accessible name for the chart. */
|
|
4
|
+
label?: string;
|
|
5
|
+
/** The consumer-supplied inline svg. */
|
|
6
|
+
children: Snippet;
|
|
7
|
+
/** Optional accessible data table alternative. */
|
|
8
|
+
dataTable?: Snippet;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
};
|
|
11
|
+
declare const ComposedChart: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
12
|
+
type ComposedChart = ReturnType<typeof ComposedChart>;
|
|
13
|
+
export default ComposedChart;
|
|
@@ -1,18 +1,52 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
// ContentsLink component
|
|
3
|
+
//
|
|
4
|
+
// One table of contents link: an <a href> to a page section, with an optional count (for example
|
|
5
|
+
// of tasks to do in that section).
|
|
6
|
+
//
|
|
7
|
+
// Props:
|
|
8
|
+
// className — string, optional. CSS class name.
|
|
9
|
+
// href — string, default "#". The link target.
|
|
10
|
+
// label — string, optional. aria-label override. It replaces the link's whole accessible name, so
|
|
11
|
+
// if you also show a count, include the count in it.
|
|
12
|
+
// count — number, optional. Sets data-count on the link (and data-complete when 0), as CSS hooks.
|
|
13
|
+
// countLabel — string, optional. Visible, localised count text (e.g. "3 to do"), rendered inside
|
|
14
|
+
// the link after the text so the link's accessible name includes it. No default, no English.
|
|
15
|
+
// children — Snippet, required. The link text.
|
|
16
|
+
// ...restProps — additional HTML attributes spread onto the <a>.
|
|
17
|
+
//
|
|
18
|
+
// Accessibility:
|
|
19
|
+
// - The count is text inside the link, never colour alone (WCAG 1.4.1).
|
|
20
|
+
|
|
2
21
|
import type { Snippet } from "svelte";
|
|
22
|
+
|
|
3
23
|
let {
|
|
4
24
|
class: className = "",
|
|
5
25
|
label = undefined,
|
|
26
|
+
href = "#",
|
|
27
|
+
count = undefined,
|
|
28
|
+
countLabel = undefined,
|
|
6
29
|
children,
|
|
7
30
|
...restProps
|
|
8
31
|
}: {
|
|
9
32
|
label?: string;
|
|
33
|
+
href?: string;
|
|
34
|
+
count?: number;
|
|
35
|
+
countLabel?: string;
|
|
10
36
|
children: Snippet;
|
|
11
37
|
[key: string]: unknown;
|
|
12
38
|
} = $props();
|
|
13
39
|
</script>
|
|
14
40
|
|
|
15
41
|
<!-- ContentsLink.svelte -->
|
|
16
|
-
<
|
|
42
|
+
<a
|
|
43
|
+
class={`contents-link ${className}`}
|
|
44
|
+
{href}
|
|
45
|
+
aria-label={label}
|
|
46
|
+
data-count={count}
|
|
47
|
+
data-complete={count === 0 ? "" : undefined}
|
|
48
|
+
{...restProps}
|
|
49
|
+
>
|
|
17
50
|
{@render children?.()}
|
|
18
|
-
</
|
|
51
|
+
{#if countLabel}<span class="contents-link-count">{countLabel}</span>{/if}
|
|
52
|
+
</a>
|