@eocrm/design-system 0.6.22 → 0.6.23
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/AI-PRIMER.md +166 -288
- package/README.md +11 -1
- package/docs/accessible-names.md +22 -0
- package/docs/components/CircularProgress.md +4 -0
- package/docs/components/CurrencySelect.md +1 -1
- package/docs/components/Kbd.md +1 -1
- package/docs/components/MoneyInput.md +1 -1
- package/docs/components/PhoneInput.md +1 -1
- package/docs/components/Progress.md +7 -0
- package/docs/components/Text.md +8 -0
- package/docs/components/Title.md +4 -0
- package/docs/components/index.json +652 -0
- package/docs/i18n.md +74 -0
- package/docs/typescript.md +9 -0
- package/package.json +2 -2
- package/src/components/LiquidEditor/useLiquidAutocomplete.ts +1 -1
- package/src/components/RichText/RichTextAttachment.tsx +1 -1
- package/src/i18n/I18nProvider.tsx +1 -1
package/docs/i18n.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Localization (i18n)
|
|
2
|
+
|
|
3
|
+
How library strings are translated, and how to pair `I18nProvider` with `LocaleProvider`.
|
|
4
|
+
|
|
5
|
+
Every user-facing string the library renders — visible text, aria-labels, placeholders, default empty/loading copy — flows through a single React Context. Wrap your app once; every component picks up the right copy. There are NO `labels` / `cancelLabel` / `searchPlaceholder` props on any component.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { I18nProvider } from '@eocrm/design-system';
|
|
9
|
+
|
|
10
|
+
<I18nProvider locale="ru">
|
|
11
|
+
<App />
|
|
12
|
+
</I18nProvider>;
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Overrides** are a deep-partial of the messages tree:
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
<I18nProvider
|
|
19
|
+
locale="ru"
|
|
20
|
+
overrides={{
|
|
21
|
+
pagination: { next: 'Дальше' },
|
|
22
|
+
badge: { modified: 'Изменено!' },
|
|
23
|
+
}}
|
|
24
|
+
>
|
|
25
|
+
<App />
|
|
26
|
+
</I18nProvider>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Missing override keys fall back to the locale defaults.
|
|
30
|
+
- Missing locale keys do NOT fall back to `en` — `I18nProvider` uses the one locale catalogue and `useTranslation` warns and returns the literal key string. The real guard is the type: `en` and `ru` are both annotated `: Messages` (total, not partial), so a missing key is a `tsc` error and cannot ship.
|
|
31
|
+
- No provider at all = `en` defaults.
|
|
32
|
+
|
|
33
|
+
**Available locales:** `'en'` (default), `'ru'`. v1.
|
|
34
|
+
|
|
35
|
+
**`I18nProvider` vs `LocaleProvider` — pair them.** `I18nProvider` carries the message catalog (translated strings). `LocaleProvider` carries the BCP-47 tag used by `Intl.*` formatters inside Calendar / DatePicker / DateRangePicker (month names, weekday order, date-range formatting). They are independent — a Russian app should wrap with BOTH so visible strings AND Intl-rendered dates speak the right language:
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
<I18nProvider locale="ru">
|
|
39
|
+
<LocaleProvider locale="ru-RU">
|
|
40
|
+
<App />
|
|
41
|
+
</LocaleProvider>
|
|
42
|
+
</I18nProvider>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Adding a new string in a library component**:
|
|
46
|
+
|
|
47
|
+
1. Add the key to `src/i18n/messages.ts` (`Messages` interface).
|
|
48
|
+
2. Add the English value to `src/i18n/en.ts`.
|
|
49
|
+
3. Add the Russian value to `src/i18n/ru.ts` (use `ruPlural()` from `i18n/format.ts` for count-varying strings).
|
|
50
|
+
4. In the component, `const t = useTranslation();` then `aria-label={t('component.key')}`. For array messages (months / weekdays), use `useTranslationArray()`.
|
|
51
|
+
5. Never inline an English string — `aria-label="Close"` is a Hard rule 9 violation.
|
|
52
|
+
|
|
53
|
+
**Drag-and-drop announcements** are localized too. Every drag surface (`Sortable`,
|
|
54
|
+
`SortableGroup`, `Kanban`, `DataTable` column reorder, `RichTextEditor` block
|
|
55
|
+
gutter) overrides dnd-kit's English defaults with the `drag.*` messages, and
|
|
56
|
+
names what it drags by its **rendered text** rather than its id — "Amount due,
|
|
57
|
+
position 3 of 7", not "col_amount was moved over droppable area col_name". Text
|
|
58
|
+
is read from the DOM, so a closed `DropdownMenu` / `Tooltip` / `Popover` inside
|
|
59
|
+
a card contributes nothing, and `aria-hidden` decoration is skipped.
|
|
60
|
+
|
|
61
|
+
Two things are worth doing yourself:
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
{/* Name the CONTAINER — the library can't invent one. Either attribute works. */}
|
|
65
|
+
<Kanban.Column id="qualified" aria-label="Qualified"> {/* → "…in Qualified" */}
|
|
66
|
+
<Kanban.Column id="qualified" aria-labelledby="qualified-h"> {/* same, from the heading */}
|
|
67
|
+
<SortableGroup.Container id="review" items={ids} aria-label="In review" />
|
|
68
|
+
|
|
69
|
+
{/* Override a chatty ITEM. Without this the whole card is read out. */}
|
|
70
|
+
<Kanban.Card id="d-1" aria-label="Acme renewal">…title, owner, due date, badges…</Kanban.Card>
|
|
71
|
+
<Sortable.Item id="f-1" aria-label="Company name">…</Sortable.Item>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
An unnamed container falls back to its position ("column 2 of 3").
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# TypeScript
|
|
2
|
+
|
|
3
|
+
Getting prop types to resolve in your editor.
|
|
4
|
+
|
|
5
|
+
Every prop and variant type is typed. If your editor shows no types:
|
|
6
|
+
|
|
7
|
+
- Confirm `moduleResolution: "bundler"` (or `"node16"`) in your `tsconfig.json`.
|
|
8
|
+
- Confirm your IDE's TS server is running.
|
|
9
|
+
- The package's `types` field points at `./src/index.ts` — source distribution means the consumer's bundler compiles `.tsx`. Vite, Next.js, Webpack 5+ all support this; older configurations may need `transpilePackages: ['@eocrm/design-system']` (Next.js) or equivalent.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eocrm/design-system",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.23",
|
|
4
4
|
"description": "Design system for the EOCRM product — React 19 + SCSS modules + CSS custom properties.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@dnd-kit/core": "^6.3.1",
|
|
51
51
|
"@dnd-kit/sortable": "^10.0.0",
|
|
52
52
|
"@dnd-kit/utilities": "^3.2.2",
|
|
53
|
-
"@eocrm/design-tokens": "0.6.
|
|
53
|
+
"@eocrm/design-tokens": "0.6.23",
|
|
54
54
|
"@floating-ui/react-dom": "^2.1.8",
|
|
55
55
|
"@types/d3-scale": "^4.0.9",
|
|
56
56
|
"@types/d3-shape": "^3.2.0",
|
|
@@ -127,7 +127,7 @@ export function useLiquidAutocomplete({ variables, filters, enabled }: UseLiquid
|
|
|
127
127
|
// `||`, not `??`. This is the SAME prop as InsertVariableMenu's, and it
|
|
128
128
|
// feeds `AutocompleteMenu`'s `<span>{item.label}</span>` — a
|
|
129
129
|
// `role="option"`'s only name source. `label: ''` rendered a blank
|
|
130
|
-
// option, and the docs in `types.ts` and
|
|
130
|
+
// option, and the docs in `types.ts` and docs/accessible-names.md promise it cannot.
|
|
131
131
|
label: v.label || v.code,
|
|
132
132
|
type: v.type,
|
|
133
133
|
group: v.group,
|
|
@@ -94,7 +94,7 @@ export function RichTextAttachment({ block, editable }: { block: Block; editable
|
|
|
94
94
|
// `alt=""` is a real HTML value — "decorative, skip me" — so an empty
|
|
95
95
|
// `block.alt` is a choice to honour, not an unset to fall back from.
|
|
96
96
|
// Everywhere else in this library an empty label means unset; see
|
|
97
|
-
//
|
|
97
|
+
// docs/accessible-names.md, which names this as the exception.
|
|
98
98
|
alt={block.alt ?? name}
|
|
99
99
|
width={block.width}
|
|
100
100
|
height={block.height}
|
|
@@ -32,7 +32,7 @@ export interface I18nProviderProps {
|
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Provides the message catalog (`locale` plus optional `overrides`) to descendants.
|
|
35
|
-
* @see
|
|
35
|
+
* @see docs/i18n.md
|
|
36
36
|
*/
|
|
37
37
|
export function I18nProvider({ locale, overrides, children }: I18nProviderProps) {
|
|
38
38
|
const value = useMemo<I18nContextValue>(() => {
|