@masmarino/gabarit 0.1.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,216 @@
1
+ # Accessibility
2
+
3
+ Target standard: **RGAA 4.1.2** (the current version of the French
4
+ accessibility standard, 106 criteria, aligned with WCAG 2.1 AA and EN 301
5
+ 549), plus the WCAG 2.2 AA additions that RGAA 5 will fold in by the end
6
+ of 2026 — 2.4.11 focus not obscured and 2.5.8 target size.
7
+
8
+ Text contrast targets level **AAA (7:1)**, beyond RGAA's own requirement
9
+ of AA (4.5:1). UI component contrast stays at 3:1: criterion 3.3 has no
10
+ AAA level.
11
+
12
+ ## What Gabarit guarantees, and what it can't guarantee
13
+
14
+ **RGAA is assessed on a page or a service, never on a library.** Gabarit
15
+ is therefore not "RGAA-compliant" and cannot be: it's your application
16
+ that is, or isn't. What Gabarit guarantees is that **the 30 criteria that
17
+ depend on its components are met**, verified by `axe-core` in the unit
18
+ tests, by a contrast test on the tokens, and by thirteen manual audit
19
+ checklists (`AUDIT.md`) — one alone covers seven chart-base components,
20
+ another covers both tab components, and five components have none. The
21
+ first two means run locally via `npm test`, not in continuous
22
+ integration: this repository has no CI. The checklists are handwritten
23
+ and reviewed by a human.
24
+
25
+ ## How it's actually verified, and where that stops
26
+
27
+ **This describes what actually runs, not what would be desirable.**
28
+ This repository has no continuous integration, and no `axe-core` pass
29
+ runs on Storybook stories. What does exist:
30
+
31
+ - **`axe-core`, run in the unit tests (`npm test`, local).** Each
32
+ component has its own `expectNoA11yViolations` test. It covers only
33
+ around 30% of RGAA criteria: necessary, and very insufficient on its
34
+ own.
35
+ - **`@storybook/addon-a11y`** is registered in Storybook and gives a
36
+ visual inspection panel per story — useful in manual review, but
37
+ **nothing runs it as a test**: it isn't wired to a test runner, so no
38
+ story can "fail" on an accessibility violation. Reading it is part of
39
+ the manual audit checklist below, not of automated verification.
40
+ - **A dedicated contrast test** (`tokens/contrast.spec.ts`), which
41
+ recomputes the ratio of a **hand-maintained** list of token pairs in
42
+ that file against the thresholds above, in both themes — not "every
43
+ token pair" in an exhaustive sense: a token added without being added
44
+ to that list is checked by nothing, and the test measures token
45
+ values in isolation without asking which token a component actually
46
+ uses — a component can paint text with a graphic-only token at 3:1
47
+ and this test still comes back green. It also covers **hover
48
+ states**, checking that every hovered fill stays perceptibly distinct
49
+ from its resting state.
50
+ - **A token-usage test** (`tokens/token-usage.spec.ts`), which closes the
51
+ blind spot described above in three parts, under an explicit exemption
52
+ you need to know before them. **A `*-base` token (validated at 3:1,
53
+ never a text threshold) may paint a purely graphic HTML fill if its
54
+ declaration carries the `// token-graphique-sans-texte` marker at the
55
+ end of the line**, and this exemption is refused outright as soon as
56
+ the selector of the rule carrying it itself denotes text (BEM word
57
+ `label`, `text`, `caption`, or `title`). It is used in three places
58
+ today: the fill of `gbt-gauge-bar`, which carries no text, and the
59
+ fills of `gbt-dimension-card` and `gbt-funnel-chart`, themselves
60
+ translucent, on which opaque text is laid — never in the exempted
61
+ declaration itself. That said, the three parts: the test re-reads the
62
+ components' stylesheets — and the `styles:` blocks declared inline in
63
+ decorators — and fails the suite as soon as a direct reference to the
64
+ raw palette appears (the families are **derived from
65
+ `_palette.scss`**, never hand-enumerated) or a `color` declaration
66
+ tied to a `*-base` token. Its third part measures the **actual
67
+ pairing**: for a rule's own `background` declaration, it resolves the
68
+ **effective** text color — the rule's own if it sets one, otherwise
69
+ its nearest ancestor's that does — up to the palette, composites
70
+ translucent overlays over the real background, and checks the ratio as
71
+ it will actually be painted. It's the only check in this repository
72
+ that measures a pair under rendering conditions, rather than two
73
+ tokens side by side.
74
+ - **Thirteen manual audit checklists** (`AUDIT.md` in the folder of the
75
+ components that have one — not all of them). One (`chart-frame/AUDIT.md`)
76
+ alone covers seven chart-base components (`chart-frame`, `chart-axis`,
77
+ `chart-tooltip`, `chart-legend`, `chart-empty`, `chart-table`,
78
+ `chart-context`), another (`tabs/AUDIT.md`) covers both the `Tabs` and
79
+ `Tab` components. Each checklist records what automation doesn't see —
80
+ actual keyboard use, screen reader, measurements in Storybook, reading
81
+ the `@storybook/addon-a11y` panel. Conversely, five components
82
+ (`bar-chart`, `funnel-chart`, `icon`, `sparkline`, `timeline-chart`)
83
+ have none.
84
+
85
+ Two measured limits of `axe-core` in this tooling, worth knowing before
86
+ reproducing this approach:
87
+
88
+ - **`color-contrast` can't be evaluated under jsdom.** The rule needs a
89
+ real canvas; under jsdom it consistently returns "incomplete" rather
90
+ than a verdict. It's therefore disabled in the test helper
91
+ (`expectNoA11yViolations`) and replaced by the dedicated contrast test
92
+ above — which is actually a **more rigorous** check, since it measures
93
+ the tokens' real values rather than inspecting rendered output.
94
+ - **`axe` doesn't infer the implicit role of an unknown custom
95
+ element.** Measured empirically: the `aria-prohibited-attr` rule fires
96
+ on `<div role="generic" aria-label="x">` but **not** on
97
+ `<gbt-icon aria-label="x">`. And the host of every Gabarit component is
98
+ a custom element of that kind. Consequence: no ARIA assertion about the
99
+ host of a `gbt-*` component relies on `axe` alone — it's also checked
100
+ by direct DOM inspection in that component's tests.
101
+
102
+ A different kind of gap is worth distinguishing from the two axe
103
+ limits above: a duplicate-id defect between two instances of
104
+ `gbt-tabs` on the same page is only observable when a fixture actually
105
+ renders two instances at once — a single-instance fixture can't
106
+ surface it, however thorough the test. The `duplicate-id` and
107
+ `duplicate-id-aria` rules are part of the default rule set used here
108
+ (`wcag2a`/`wcag2aa`/`wcag21a`/`wcag21aa`/`wcag22aa`) and do catch this
109
+ class of defect, given that scenario; `tabs.spec.ts` includes it, and
110
+ `gbt-tabs` namespaces every instance's generated ids accordingly (see
111
+ `tabs/AUDIT.md`). The distinction matters for anyone adopting this
112
+ verification method: a rule with no violation to show isn't the same
113
+ as a rule with nothing to check — check the scenario, not just the
114
+ rule.
115
+
116
+ ## Criteria covered by Gabarit
117
+
118
+ | Topic | Criteria |
119
+ | --------------- | --------------------------------------------------------- |
120
+ | 3 Colors | 3.1, 3.2, 3.3 |
121
+ | 5 Tables | 5.4, 5.5, 5.6, 5.7, 5.8 |
122
+ | 7 Scripting | 7.1, 7.3, 7.4, 7.5 |
123
+ | 9 Structure | 9.3 |
124
+ | 10 Presentation | 10.5, 10.7, 10.8, 10.9, 10.10, 10.11, 10.12, 10.13, 10.14 |
125
+ | 11 Forms | 11.1, 11.4, 11.9, 11.11 |
126
+ | 12 Navigation | 12.8, 12.9, 12.11 |
127
+ | 13 Consultation | 13.8 |
128
+
129
+ That's 30 out of the 106 criteria in RGAA 4.1.2. Two topics that might
130
+ look like they belong here don't: **Topic 6 Links (6.1, 6.2)** isn't
131
+ listed because no `<a>` element exists anywhere in the library — a
132
+ library that never produces a link cannot guarantee a criterion about
133
+ links. And **11.2, 11.10, and 11.13** sit under "What remains your
134
+ responsibility" below rather than here, since the components only
135
+ provide the mechanism (`label`/field association, `role="alert"`,
136
+ `aria-describedby`, an `autocomplete` you can override) — never the
137
+ label text, the error text, or the field-specific `autocomplete`
138
+ value itself.
139
+
140
+ ## What remains your responsibility
141
+
142
+ The other 76 criteria. The main ones:
143
+
144
+ | Topic | What you need to do |
145
+ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
146
+ | 1 Images | Text alternatives for your images. `gbt-icon` is unconditionally decorative — see "Points to watch" below — a meaningful icon must be accompanied by text on your side. |
147
+ | 6 Links | Explicit (6.1) and relevant (6.2) wording for every link in your application. No Gabarit component renders an `<a>`: nothing to delegate. |
148
+ | 8 Mandatory elements | Doctype, `lang`, page `<title>`, absence of validity errors. |
149
+ | 9 Structure | Heading hierarchy of the page. `gbt-card` lets you choose its level via `headingLevel` — it's up to you to set it correctly. |
150
+ | 10 Presentation | 200% zoom, page-wide reflow. The components hold up their end; the layout is yours. |
151
+ | 11 Forms | Field grouping (`fieldset` / `legend`), **relevance** of your labels (11.2 — the component associates `label`/field, the text is yours), **content** of your error messages (11.10 — the component announces them via `role="alert"`, you write the text in `errorMessage`), and a correct `autocomplete` value (11.13 — `gbt-input` sets it to `'off'` by default, to override field by field). |
152
+ | 12 Navigation | Two navigation systems, sitemap, skip link, ARIA regions. The `.skip-link` utility is provided (`tokens/_utilities.scss`), using it is up to you. |
153
+ | 13 Consultation | Time limits, opening new windows, downloadable documents, screen orientation. |
154
+
155
+ ## Points to watch when integrating
156
+
157
+ - **`gbt-table`** — `caption` is a **required** input (criteria 5.4 and
158
+ 5.5): the component won't compile without it. As soon as you listen to
159
+ `rowClick`, pass `clickableRows`, otherwise the feature is inaccessible
160
+ from the keyboard (criterion 7.3).
161
+ - **`gbt-search-bar`** — the outputs are `queryChange` and
162
+ `itemSelected` (not `search` / `select`: `@angular-eslint/no-output-native`
163
+ forbids those, they're native DOM events).
164
+ - **`gbt-card`** — `headingLevel` defaults to 2. Adjust it to the card's
165
+ actual place in the page (criterion 9.1).
166
+ - **`gbt-button`** — a button with no `text` must have an `ariaLabel`
167
+ (criterion 11.9).
168
+ - **`gbt-modal` restores focus on both closing paths, regardless of how
169
+ you mount it.** Whether you unmount the component on close
170
+ (`@if (open()) { <gbt-modal ... /> }`) or keep it mounted and toggle it
171
+ (`[isOpen]="open()"`), focus returns to the element that held it before
172
+ opening — respectively on the component's destruction and on the
173
+ `isOpen()` transition from `true` to `false`. Both usages are therefore
174
+ safe; neither lets focus fall onto `<body>`.
175
+ - **`gbt-icon` is unconditionally decorative.** It receives no input to
176
+ carry an accessible name: its host carries a bound `aria-hidden="true"`,
177
+ set after any attribute written by the consumer — an `aria-label` you
178
+ set on `<gbt-icon>` is ignored by assistive technology regardless. The
179
+ accessible name of an action belongs to the control that contains it
180
+ (button, field, link), never to the icon itself.
181
+ - **The four standalone charts** (`gbt-sparkline`, `gbt-gauge-bar`,
182
+ `gbt-dimension-card`, `gbt-funnel-chart`) have neither an axis nor a
183
+ frame: each carries its own text alternative rather than assembling the
184
+ `gbt-chart-frame` base. Three inputs there distinguish similar-sounding
185
+ roles, not to be confused: `tableCaption` is the caption of a chart's
186
+ non-visual table (`gbt-sparkline`, `gbt-funnel-chart`); `caption` is the
187
+ caption of a **visible** table, taking the name of the HTML element
188
+ (`gbt-dimension-card`); `label` is the visible, accessible name of the
189
+ component itself — the heading of `gbt-gauge-bar`, and the `aria-label`
190
+ of `gbt-funnel-chart`'s `<ol>`, distinct from its `tableCaption`.
191
+ - **`gbt-gauge-bar` expresses its ARIA as a percentage, never in the
192
+ consumer's own scale.** `aria-valuenow`, `aria-valuemin`, and
193
+ `aria-valuemax` are always bounded to [0, 100]: with `[max]="500"` and
194
+ `[value]="62"`, a screen reader reads `aria-valuenow="12.4"` — neither
195
+ "62" nor "62 out of 500". Only `aria-valuetext` (your `formattedValue`)
196
+ carries the human-readable quantity; it's the only one of the five ARIA
197
+ values worth reading if you inspect the attribute rather than letting
198
+ assistive technology announce it.
199
+ - **Default strings in English, to override in a non-English
200
+ application** — these components carry visible or announced labels
201
+ with no localized default:
202
+ - `gbt-button`: `loadingLabel` (`'Loading'`).
203
+ - `gbt-input`: `showPasswordLabel` (`'Show password'`),
204
+ `hidePasswordLabel` (`'Hide password'`).
205
+ - `gbt-select`: `placeholder` (`'Select…'`), `selectedCountLabel`
206
+ (function, `` `${count} selected` ``).
207
+ - `gbt-modal`: `closeLabel` (`'Close'`).
208
+ - `gbt-table`: `emptyMessage` (`'No data'`).
209
+ - `gbt-search-bar`: `placeholder` (`'Search…'`), `noResultsMessage`
210
+ (`'No results'`), `noResultsHint` (`'Try a different search.'`),
211
+ `clearLabel` (`'Clear search'`), `resultsAnnouncement` (function,
212
+ announces the result count — criterion 7.5), `navigateHint`
213
+ (`'Navigate'`), `selectHint` (`'Select'`), `closeHint` (`'Close'`).
214
+ - **Token overrides** — if you redefine the semantic colors, you take on
215
+ criteria 3.2 and 3.3 yourself. Gabarit's contrast test only checks its
216
+ own values.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Florian Simon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,188 @@
1
+ # Gabarit
2
+
3
+ [![CI](https://github.com/Masmarino/Gabarit/actions/workflows/ci.yml/badge.svg)](https://github.com/Masmarino/Gabarit/actions/workflows/ci.yml)
4
+ [![npm](https://img.shields.io/npm/v/%40masmarino%2Fgabarit)](https://www.npmjs.com/package/@masmarino/gabarit)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+
7
+ Angular design system for self-hosted applications — UI components and
8
+ dataviz, no external dependency.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install @masmarino/gabarit
14
+ ```
15
+
16
+ ## Components
17
+
18
+ Each component has its own README, with the detail of its inputs and
19
+ outputs — the link is on its name.
20
+
21
+ ### Atoms
22
+
23
+ | Component | Selector | Role |
24
+ | -------------------------------------------------------------------------- | --------------- | ------------------------------------- |
25
+ | [Button](projects/gabarit/src/lib/components/atoms/button/README.md) | `gbt-button` | Action button. |
26
+ | [Checkbox](projects/gabarit/src/lib/components/atoms/checkbox/README.md) | `gbt-checkbox` | Checkbox, integrated with forms. |
27
+ | [GaugeBar](projects/gabarit/src/lib/components/atoms/gauge-bar/README.md) | `gbt-gauge-bar` | Progress gauge with alert thresholds. |
28
+ | [Icon](projects/gabarit/src/lib/components/atoms/icon/README.md) | `gbt-icon` | Registered SVG icon. |
29
+ | [Input](projects/gabarit/src/lib/components/atoms/input/README.md) | `gbt-input` | Text or password field. |
30
+ | [Sparkline](projects/gabarit/src/lib/components/atoms/sparkline/README.md) | `gbt-sparkline` | Fixed-size trend mini-chart. |
31
+
32
+ ### Molecules
33
+
34
+ | Component | Selector | Role |
35
+ | --------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------- |
36
+ | [Card](projects/gabarit/src/lib/components/molecules/card/README.md) | `gbt-card` | Titled container. |
37
+ | [DimensionCard](projects/gabarit/src/lib/components/molecules/dimension-card/README.md) | `gbt-dimension-card` | Dimension table with an accented hover row. |
38
+ | [FunnelChart](projects/gabarit/src/lib/components/molecules/funnel-chart/README.md) | `gbt-funnel-chart` | Step-by-step conversion funnel. |
39
+ | [Menu](projects/gabarit/src/lib/components/molecules/menu/README.md) | `gbt-menu` | Generic dropdown menu. |
40
+ | [Select](projects/gabarit/src/lib/components/molecules/select/README.md) | `gbt-select` | Dropdown list, single or multiple. |
41
+ | [Table](projects/gabarit/src/lib/components/molecules/table/README.md) | `gbt-table` | Data table. |
42
+ | [Tabs](projects/gabarit/src/lib/components/molecules/tabs/README.md) | `gbt-tabs` / `gbt-tab` | Tab navigation. |
43
+
44
+ ### Organisms
45
+
46
+ | Component | Selector | Role |
47
+ | --------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------ |
48
+ | [BarChart](projects/gabarit/src/lib/components/organisms/bar-chart/README.md) | `gbt-bar-chart` | Bar chart on the dataviz base. |
49
+ | [ChartAxis](projects/gabarit/src/lib/components/organisms/chart-axis/README.md) | `g[gbtChartAxis]` | Axis ticks — base building block. |
50
+ | [ChartEmpty](projects/gabarit/src/lib/components/organisms/chart-empty/README.md) | `gbt-chart-empty` | Empty state — base building block. |
51
+ | [ChartFrame](projects/gabarit/src/lib/components/organisms/chart-frame/README.md) | `gbt-chart-frame` | Low-level base, for a custom chart. |
52
+ | [ChartLegend](projects/gabarit/src/lib/components/organisms/chart-legend/README.md) | `gbt-chart-legend` | Multi-series legend — base building block. |
53
+ | [ChartTable](projects/gabarit/src/lib/components/organisms/chart-table/README.md) | `gbt-chart-table` | Non-visual table — base building block. |
54
+ | [ChartTooltip](projects/gabarit/src/lib/components/organisms/chart-tooltip/README.md) | `gbt-chart-tooltip` | Tooltip — base building block. |
55
+ | [LineChart](projects/gabarit/src/lib/components/organisms/line-chart/README.md) | `gbt-line-chart` | Line(s) on the dataviz base. |
56
+ | [Modal](projects/gabarit/src/lib/components/organisms/modal/README.md) | `gbt-modal` | Modal dialog box. |
57
+ | [SearchBar](projects/gabarit/src/lib/components/organisms/search-bar/README.md) | `gbt-search-bar` | Search with grouped results. |
58
+ | [TimelineChart](projects/gabarit/src/lib/components/organisms/timeline-chart/README.md) | `gbt-timeline-chart` | Timeline on the dataviz base. |
59
+
60
+ ### Templates
61
+
62
+ | Component | Selector | Role |
63
+ | ----------------------------------------------------------------------------- | --------------- | -------------------------------------- |
64
+ | [AppShell](projects/gabarit/src/lib/components/templates/app-shell/README.md) | `gbt-app-shell` | Page shell: side nav, header, content. |
65
+
66
+ ## Styles
67
+
68
+ Import the tokens in the application's `styles.scss`:
69
+
70
+ ```scss
71
+ @use 'gabarit/tokens' as *;
72
+ ```
73
+
74
+ Gabarit declares **no** `@font-face` rule. The tokens expose
75
+ `--font-family: 'Inter', sans-serif`, but serving and declaring the font
76
+ is the application's responsibility.
77
+
78
+ ### Color tokens
79
+
80
+ Every component exclusively reads the custom properties below, set on
81
+ `:root` by `_semantic.scss`. **These, and only these, are what an
82
+ application should override to re-theme itself** — the raw palette
83
+ (`--brand-*`, `--grey-*`, `--red-*`…) is an internal detail, never
84
+ referenced outside `_semantic.scss` (enforced by `token-usage.spec.ts`).
85
+
86
+ | Category | Token | Role |
87
+ | ----------- | ------------------------------------------------------------------------ | --------------------------------------------------------------- |
88
+ | Brand | `--primary` / `--primary-hover` | Action color (buttons, active links, focus) and its hover state |
89
+ | Backgrounds | `--bg-principal` | Page and surface background (cards, panels) |
90
+ | | `--bg-panel` | Background of persistent navigation areas (nav, header) |
91
+ | | `--bg-hover` | Hover state of an interactive element on a neutral background |
92
+ | Border | `--border-color` | All borders |
93
+ | Text | `--text-primary` / `--text-secondary` / `--text-discret` | From most to least emphasized |
94
+ | | `--text-on-primary` / `--text-on-error` / `--text-on-color` | Text set on a `--primary` fill, an error fill, or a solid color |
95
+ | Success | `--color-success-base` / `-hover` / `-text` / `-bg` / `-bg-text` | Fill, hover, text, light background, text on that background |
96
+ | Warning | `--color-warning-base` / `-hover` / `-text` / `-bg` / `-bg-text` | Same |
97
+ | Error | `--color-error-base` / `-fill` / `-hover` / `-text` / `-bg` / `-bg-text` | Same (`-fill`: solid fill, e.g. an icon) |
98
+ | Dataviz | `--chart-series-1-base`, `-2-base`, `-3-base` | The three chart series, in order |
99
+ | | `--chart-grid` | Chart grid and axes |
100
+
101
+ Other tokens live on `:root` without being colors — border radii
102
+ (`--site-border-radius*`), shadows (`--site-shadow-*`), transition
103
+ durations (`--site-transition-*`) — overridable the same way.
104
+
105
+ Overriding a token after the import:
106
+
107
+ ```scss
108
+ @use 'gabarit/tokens' as *;
109
+
110
+ :root {
111
+ --primary: #7c3aed;
112
+ }
113
+ ```
114
+
115
+ **Dark mode activates via `prefers-color-scheme` or `[data-theme='dark']`
116
+ on `<html>`, and reapplies to the same tokens.** An override set on a bare
117
+ `:root` applies to both themes indifferently; for a value specific to
118
+ dark mode, redeclare it under the same conditions as Gabarit, after its
119
+ import:
120
+
121
+ ```scss
122
+ @media (prefers-color-scheme: dark) {
123
+ :root {
124
+ --primary: #a78bfa;
125
+ }
126
+ }
127
+ ```
128
+
129
+ ## Internationalization
130
+
131
+ Gabarit ships no translation mechanism. Every visible string is a
132
+ component input, supplied by the application.
133
+
134
+ ## Accessibility
135
+
136
+ [`ACCESSIBILITY.md`](./ACCESSIBILITY.md) documents what Gabarit
137
+ guarantees with respect to RGAA (30 out of 106 criteria, checked on every
138
+ push by CI — `axe-core` in the unit tests, a dedicated contrast test, and
139
+ a manual audit per component), what remains the application's
140
+ responsibility (76 criteria), and the points to watch when integrating
141
+ each component. Read it before writing your application's accessibility
142
+ statement — without it, that statement will be incomplete.
143
+
144
+ ## Known limitations
145
+
146
+ **Not every non-resting state is covered by a test.** Hover and focus
147
+ are: `contrast.spec.ts` checks every hover fill and its perceptibility,
148
+ and `token-usage.spec.ts` measures the text/fill pairing as it will
149
+ actually be painted, translucent overlays and compositing included. The
150
+ `:active` and `:disabled` states are not — the latter is out of scope
151
+ for RGAA, which exempts inactive controls.
152
+
153
+ **Token-usage checking only reads the library's own CSS.** If your
154
+ application overrides a semantic token, verifying the resulting contrast
155
+ is your responsibility: Gabarit's tests only measure its own values. See
156
+ `ACCESSIBILITY.md`.
157
+
158
+ **Two global utility classes are not prefixed: `.sr-only` and
159
+ `.skip-link`.** They live in `_utilities.scss`, which `@use
160
+ 'gabarit/tokens'` pours unencapsulated into the application's **global**
161
+ stylesheet — deliberately, so they stay usable outside the library's
162
+ components. An application that already defines one of these two common
163
+ names collides with it. Inside the library's own components
164
+ (`gbt-search-bar`, `gbt-button`), it's safe: each carries its own local
165
+ `.sr-only`, and the scoping attribute Angular adds under encapsulation
166
+ (specificity 0-2-0) beats the unscoped global rule (0-1-0). The other
167
+ utilities in the same file do carry the `gbt-` prefix.
168
+
169
+ ## Release
170
+
171
+ The published version is the one in `projects/gabarit/package.json`. To
172
+ cut a new release:
173
+
174
+ ```bash
175
+ npm version <patch|minor|major> --prefix projects/gabarit --no-git-tag-version
176
+ git add projects/gabarit/package.json
177
+ git commit -m "chore(release): vX.Y.Z"
178
+ git tag vX.Y.Z
179
+ git push origin main --follow-tags
180
+ ```
181
+
182
+ The tag triggers the `release.yml` workflow: full rebuild, verification
183
+ that the tag matches the package version, then publishing to npm with
184
+ provenance attestation.
185
+
186
+ ## License
187
+
188
+ MIT.