@konce-pt/react 0.8.1 → 0.8.3
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/README.md +381 -27
- package/dist/accordion/llms.txt +56 -0
- package/dist/alert/llms.txt +45 -0
- package/dist/app-shell/app-shell.d.ts +20 -0
- package/dist/app-shell/app-shell.js +24 -0
- package/dist/app-shell/llms.txt +59 -0
- package/dist/auth/auth.d.ts +1 -1
- package/dist/auth/llms.txt +65 -0
- package/dist/autocomplete/autocomplete.d.ts +1 -1
- package/dist/autocomplete/llms.txt +44 -0
- package/dist/avatar/llms.txt +42 -0
- package/dist/avatar-group/avatar-group.d.ts +1 -1
- package/dist/avatar-group/llms.txt +38 -0
- package/dist/badge/llms.txt +38 -0
- package/dist/bottom-sheet/llms.txt +43 -0
- package/dist/breadcrumb/breadcrumb.d.ts +1 -1
- package/dist/breadcrumb/llms.txt +35 -0
- package/dist/button/llms.txt +56 -0
- package/dist/button-group/button-group.d.ts +1 -1
- package/dist/button-group/llms.txt +40 -0
- package/dist/card/llms.txt +60 -0
- package/dist/carousel/carousel.d.ts +1 -1
- package/dist/carousel/llms.txt +47 -0
- package/dist/charts/chart-legend.d.ts +1 -1
- package/dist/charts/llms.txt +57 -0
- package/dist/checkbox/llms.txt +39 -0
- package/dist/chip/llms.txt +41 -0
- package/dist/chips-input/llms.txt +40 -0
- package/dist/clock/llms.txt +50 -0
- package/dist/color-picker/color-picker.d.ts +1 -1
- package/dist/color-picker/llms.txt +40 -0
- package/dist/confirm/llms.txt +44 -0
- package/dist/context-menu/context-menu.d.ts +1 -1
- package/dist/context-menu/llms.txt +39 -0
- package/dist/data-table/data-table-types.d.ts +1 -1
- package/dist/data-table/data-table.d.ts +2 -10
- package/dist/data-table/data-table.js +17 -9
- package/dist/data-table/llms.txt +79 -0
- package/dist/data-view/data-view.d.ts +1 -1
- package/dist/data-view/llms.txt +49 -0
- package/dist/date-range/llms.txt +54 -0
- package/dist/datepicker/llms.txt +74 -0
- package/dist/dialog/llms.txt +51 -0
- package/dist/divider/llms.txt +28 -0
- package/dist/drawer/llms.txt +47 -0
- package/dist/empty/llms.txt +35 -0
- package/dist/fab/llms.txt +37 -0
- package/dist/fieldset/llms.txt +43 -0
- package/dist/file-upload/llms.txt +48 -0
- package/dist/form-field/llms.txt +55 -0
- package/dist/galleria/galleria.d.ts +1 -1
- package/dist/galleria/llms.txt +46 -0
- package/dist/grid/llms.txt +110 -0
- package/dist/icon/icon-registry.d.ts +5 -2
- package/dist/icon/icon-registry.js +5 -3
- package/dist/icon/llms.txt +66 -0
- package/dist/icon-button/llms.txt +38 -0
- package/dist/icons-entry/public-api.d.ts +5 -1
- package/dist/icons-entry/public-api.js +7 -1
- package/dist/image/llms.txt +46 -0
- package/dist/input/llms.txt +54 -0
- package/dist/input-mask/llms.txt +37 -0
- package/dist/input-number/llms.txt +44 -0
- package/dist/input-otp/llms.txt +43 -0
- package/dist/internal/use-breakpoint.js +18 -10
- package/dist/knob/llms.txt +46 -0
- package/dist/listbox/listbox.d.ts +1 -1
- package/dist/listbox/llms.txt +39 -0
- package/dist/map/llms.txt +108 -0
- package/dist/megamenu/llms.txt +48 -0
- package/dist/megamenu/megamenu.d.ts +1 -1
- package/dist/menu/llms.txt +56 -0
- package/dist/menu/menu-item.d.ts +1 -1
- package/dist/menu/menu-rows.d.ts +1 -1
- package/dist/menu/menu.d.ts +1 -1
- package/dist/menu/menu.js +12 -1
- package/dist/menubar/llms.txt +45 -0
- package/dist/menubar/menubar.d.ts +1 -1
- package/dist/meter-group/llms.txt +47 -0
- package/dist/meter-group/meter-group.d.ts +1 -1
- package/dist/order-list/llms.txt +41 -0
- package/dist/paginator/llms.txt +48 -0
- package/dist/paginator/paginator.d.ts +1 -1
- package/dist/paginator/paginator.js +7 -1
- package/dist/panel/llms.txt +55 -0
- package/dist/password/llms.txt +45 -0
- package/dist/pick-list/llms.txt +52 -0
- package/dist/popover/llms.txt +42 -0
- package/dist/progress/llms.txt +47 -0
- package/dist/public-api.d.ts +2 -1
- package/dist/public-api.js +1 -1
- package/dist/radio-group/llms.txt +40 -0
- package/dist/radio-group/radio-group.d.ts +1 -1
- package/dist/rating/llms.txt +43 -0
- package/dist/rich-text/llms.txt +61 -0
- package/dist/rich-text/rich-text.d.ts +1 -1
- package/dist/roadmap/llms.txt +82 -0
- package/dist/scroll-top/llms.txt +41 -0
- package/dist/select/llms.txt +56 -0
- package/dist/select/select.d.ts +1 -1
- package/dist/sidenav/llms.txt +53 -0
- package/dist/skeleton/llms.txt +33 -0
- package/dist/slider/llms.txt +50 -0
- package/dist/speed-dial/llms.txt +46 -0
- package/dist/speed-dial/speed-dial.d.ts +1 -1
- package/dist/spinner/llms.txt +33 -0
- package/dist/split-button/llms.txt +54 -0
- package/dist/split-button/split-button.d.ts +1 -1
- package/dist/splitter/llms.txt +44 -0
- package/dist/stepper/llms.txt +64 -0
- package/dist/switch/llms.txt +42 -0
- package/dist/switch-group/llms.txt +43 -0
- package/dist/switch-group/switch-group.d.ts +1 -1
- package/dist/tabs/llms.txt +48 -0
- package/dist/textarea/llms.txt +40 -0
- package/dist/timeline/llms.txt +53 -0
- package/dist/timeline/timeline.d.ts +1 -1
- package/dist/toast/llms.txt +52 -0
- package/dist/toolbar/llms.txt +45 -0
- package/dist/tooltip/llms.txt +42 -0
- package/dist/tree/llms.txt +45 -0
- package/dist/tree/tree.d.ts +2 -2
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -1,27 +1,230 @@
|
|
|
1
|
-
<
|
|
2
|
-
<img src="https://ui.konce.pt/images/koncept_ui_lib.png" alt="Koncept UI — component library" width="100%" />
|
|
3
|
-
</p>
|
|
1
|
+
<div align="center">
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
<img src="https://ui.konce.pt/images/koncept_ui_lib.png" alt="Koncept UI — React component library" width="100%" />
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
# Koncept UI — React
|
|
6
|
+
|
|
7
|
+
**Open-source React 19 component library on the Koncept UI design system.**
|
|
8
|
+
80+ components sharing the exact CSS layer with the Angular port — zero runtime dependencies.
|
|
9
|
+
|
|
10
|
+
[](https://www.npmjs.com/package/@konce-pt/react)
|
|
11
|
+
[](https://www.npmjs.com/package/@konce-pt/react)
|
|
12
|
+
[](https://bundlephobia.com/package/@konce-pt/react)
|
|
13
|
+
[](https://www.npmjs.com/package/@konce-pt/react)
|
|
14
|
+
[](https://gitlab.com/konce-pt/koncept-ui/-/blob/main/LICENSE)
|
|
15
|
+
|
|
16
|
+

|
|
17
|
+

|
|
18
|
+

|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Why Koncept UI React
|
|
26
|
+
|
|
27
|
+
**Koncept UI** is a free, MIT-licensed design system. This package is its **React 19** port — not a
|
|
28
|
+
lookalike, but the same rendering contract:
|
|
29
|
+
|
|
30
|
+
- 🎯 **One CSS layer for both ports** — the same `kpt-*` classes, the same `--kpt-*` tokens, the same
|
|
31
|
+
`@layer kpt.*` ordering. The DOM tree matches the Angular port node for node, so an app can mix
|
|
32
|
+
the two and nothing shifts by a pixel.
|
|
33
|
+
- 📦 **Zero runtime dependencies** — no `clsx`, no `radix`, no CSS-in-JS. `cn`, `Slot` and
|
|
34
|
+
`composeRefs` ship with the package.
|
|
35
|
+
- ⚛️ **React 19 native** — `ref` is a plain prop (no `forwardRef`), and every form control renders a
|
|
36
|
+
native `name`/`form`, so `<form action={…}>` Actions and React Hook Form's `register()` work
|
|
37
|
+
**without an adapter**. Controls are usable controlled *and* uncontrolled.
|
|
38
|
+
- 📊 **Flagship data table** — sorting, global and per-column filters, pagination, virtual scroll
|
|
39
|
+
(5000+ rows), selection, column reorder & freeze, inline editing, summary row, CSV export.
|
|
40
|
+
- 🎨 **100% tokenized** — every style is a `var(--kpt-*)` custom property. Light/dark theme, neutral
|
|
41
|
+
OKLCH palette. Rebrand by swapping one token layer.
|
|
42
|
+
- ♿ **Native elements first** — `<button>`, `<input>`, `<label>` wherever one exists, so keyboard and
|
|
43
|
+
screen-reader behaviour comes from the platform. Invalid state travels on `aria-invalid`, never on
|
|
44
|
+
a class.
|
|
45
|
+
- 🌍 **i18n built in** — English (default) & Polish out of the box, runtime locale switch, add any
|
|
46
|
+
language with one JSON.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
10
49
|
|
|
11
50
|
```bash
|
|
12
|
-
npm i @konce-pt/react @konce-pt/
|
|
51
|
+
npm i @konce-pt/react @konce-pt/tokens @konce-pt/styles
|
|
52
|
+
# or: pnpm add / yarn add
|
|
13
53
|
```
|
|
14
54
|
|
|
15
|
-
|
|
55
|
+
`react` and `react-dom` (`>=19`) are peers you already have. Optional extras:
|
|
56
|
+
|
|
57
|
+
- [`@konce-pt/grid`](https://www.npmjs.com/package/@konce-pt/grid) — the mobile-first layout system;
|
|
58
|
+
its React components live in `@konce-pt/react/grid`.
|
|
59
|
+
- [`@konce-pt/validators`](https://www.npmjs.com/package/@konce-pt/validators) — Polish-market
|
|
60
|
+
validators (NIP, REGON, PESEL, IBAN, postal code).
|
|
61
|
+
- `leaflet` (`^1.9`) — an **optional** peer, needed only by `@konce-pt/react/map`, loaded through a
|
|
62
|
+
dynamic `import()`.
|
|
63
|
+
|
|
64
|
+
## Setup
|
|
65
|
+
|
|
66
|
+
The package ships **JavaScript only**. Load the shared CSS layer once, in your app entry:
|
|
16
67
|
|
|
17
68
|
```ts
|
|
18
69
|
import '@konce-pt/tokens/css';
|
|
19
70
|
import '@konce-pt/tokens/css/dark';
|
|
20
|
-
import '@konce-pt/styles';
|
|
21
|
-
import '@konce-pt/styles/components'; //
|
|
22
|
-
import '@konce-pt/grid';
|
|
71
|
+
import '@konce-pt/styles'; // reset, @layer ordering, theme
|
|
72
|
+
import '@konce-pt/styles/components'; // the component layer — REQUIRED, this is what styles kpt-*
|
|
73
|
+
import '@konce-pt/grid'; // optional — only if you use the layout classes
|
|
23
74
|
```
|
|
24
75
|
|
|
76
|
+
`@konce-pt/styles/components` is generated from the same SCSS the Angular port compiles into its own
|
|
77
|
+
bundle, which is why both ports render identically. The Angular package injects those styles at
|
|
78
|
+
runtime; React has no other source for them, so this import is not optional.
|
|
79
|
+
|
|
80
|
+
Dark theme: set `<html data-theme="dark">` (or rely on `prefers-color-scheme`).
|
|
81
|
+
|
|
82
|
+
> **No CDK here.** Components with a floating panel (`KptSelect`, `KptPopover`, `KptMenu`,
|
|
83
|
+
> `KptAutocomplete`, `KptDatepicker`…) portal into `document.body` through the internal
|
|
84
|
+
> `KptOverlay`, so `@angular/cdk/overlay-prebuilt.css` is **not** needed — positioning lives in the
|
|
85
|
+
> component, the look in `@konce-pt/styles/components`. Inside an open `KptDialog` those panels
|
|
86
|
+
> portal into the `<dialog>` instead, because `showModal()` moves it to the browser top layer.
|
|
87
|
+
|
|
88
|
+
## Quick start
|
|
89
|
+
|
|
90
|
+
A login form — controlled values, the error gated on touch, no form library required:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
import { useState } from 'react';
|
|
94
|
+
import { KptButton, KptFormField, KptInput } from '@konce-pt/react';
|
|
95
|
+
|
|
96
|
+
export function Login() {
|
|
97
|
+
const [email, setEmail] = useState('');
|
|
98
|
+
const [password, setPassword] = useState('');
|
|
99
|
+
const [touched, setTouched] = useState<Record<string, boolean>>({});
|
|
100
|
+
|
|
101
|
+
const emailError = !email.includes('@') ? 'Enter a valid e-mail address' : null;
|
|
102
|
+
const passwordError = password.length < 8 ? 'At least 8 characters' : null;
|
|
103
|
+
const invalid = Boolean(emailError || passwordError);
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<form
|
|
107
|
+
onSubmit={(e) => {
|
|
108
|
+
e.preventDefault();
|
|
109
|
+
console.log({ email, password });
|
|
110
|
+
}}
|
|
111
|
+
>
|
|
112
|
+
<KptFormField label="E-mail" error={touched.email ? emailError : null} required>
|
|
113
|
+
<KptInput
|
|
114
|
+
type="email"
|
|
115
|
+
name="email"
|
|
116
|
+
value={email}
|
|
117
|
+
onValueChange={setEmail}
|
|
118
|
+
onTouch={() => setTouched((t) => ({ ...t, email: true }))}
|
|
119
|
+
invalid={Boolean(emailError)}
|
|
120
|
+
/>
|
|
121
|
+
</KptFormField>
|
|
122
|
+
|
|
123
|
+
<KptFormField label="Password" error={touched.password ? passwordError : null} required>
|
|
124
|
+
<KptInput
|
|
125
|
+
type="password"
|
|
126
|
+
name="password"
|
|
127
|
+
value={password}
|
|
128
|
+
onValueChange={setPassword}
|
|
129
|
+
onTouch={() => setTouched((t) => ({ ...t, password: true }))}
|
|
130
|
+
invalid={Boolean(passwordError)}
|
|
131
|
+
/>
|
|
132
|
+
</KptFormField>
|
|
133
|
+
|
|
134
|
+
<KptButton type="submit" disabled={invalid}>Sign in</KptButton>
|
|
135
|
+
</form>
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`KptFormField` generates the control id and publishes it through context, so `label[for]` and
|
|
141
|
+
`input[id]` match with no configuration. Drop `value`/`onValueChange` and the field becomes
|
|
142
|
+
uncontrolled — the value lives in the DOM, and a native `<form action={…}>` or React Hook Form's
|
|
143
|
+
`register()` picks it up as-is.
|
|
144
|
+
|
|
145
|
+
Data table with sorting, filtering, pagination and a custom cell:
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
<KptDataTable
|
|
149
|
+
columns={columns}
|
|
150
|
+
data={users}
|
|
151
|
+
filterable
|
|
152
|
+
exportable
|
|
153
|
+
pageSize={10}
|
|
154
|
+
selectable="multiple"
|
|
155
|
+
rowKey="id"
|
|
156
|
+
selection={selected}
|
|
157
|
+
onSelectionChange={setSelected}
|
|
158
|
+
cells={{ status: (row, value) => <KptBadge value={String(value)} /> }}
|
|
159
|
+
/>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Components (80+)
|
|
163
|
+
|
|
164
|
+
| Category | Components |
|
|
165
|
+
| --- | --- |
|
|
166
|
+
| **Forms** | `KptInput`, `KptTextarea`, `KptSelect`, `KptAutocomplete`, `KptCheckbox`, `KptSwitch`, `KptSwitchGroup`, `KptRadioGroup`, `KptSlider`, `KptRating`, `KptDatepicker`, `KptDateRange`, `KptClock`, `KptColorPicker`, `KptFileUpload`, `KptInputNumber`, `KptPassword`, `KptInputOtp`, `KptChipsInput`, `KptInputMask`, `KptListbox`, `KptKnob`, `KptRichText`, `KptFormField` |
|
|
167
|
+
| **Buttons & actions** | `KptButton`, `KptIconButton`, `KptButtonGroup`, `KptFab`, `KptSplitButton`, `KptSpeedDial` |
|
|
168
|
+
| **Layout** | `KptAppShell`, `KptToolbar`, `KptSidenav`, `KptCard` (+ `Header`, `Footer`, `Media`, `Title`…), `KptDivider`, `KptPanel`, `KptFieldset`, `KptSplitter`, `KptScrollTop` |
|
|
169
|
+
| **Navigation** | `KptTabs`, `KptAccordion`, `KptBreadcrumb`, `KptStepper`, `KptMenu`, `KptMenubar`, `KptMegamenu`, `KptContextMenu` |
|
|
170
|
+
| **Data** | `KptDataTable`, `KptPaginator`, `KptTree`, `KptTimeline`, `KptCarousel`, `KptDataView`, `KptPickList`, `KptOrderList`, `KptGalleria`, `KptMeterGroup` |
|
|
171
|
+
| **Feedback & overlay** | `KptAlert`, `KptDialog`, `kptToast` + `KptToastContainer`, `KptTooltip`, `KptPopover`, `KptDrawer`, `KptBottomSheet`, `kptConfirm`, `KptBadge`, `KptChip`, `KptAvatar`, `KptAvatarGroup`, `KptSpinner`, `KptProgress`, `KptSkeleton`, `KptEmpty`, `KptImage`, `KptAuth` |
|
|
172
|
+
| **Subpaths** | `@konce-pt/react/charts` (`KptChart`), `/roadmap` (`KptRoadmap`), `/grid` (`KptGrid`, `KptCol`, `KptFlex`), `/map` (`KptMap` + legend, POI card, search), `/icons` (full Tabler set) |
|
|
173
|
+
|
|
174
|
+
The heavy pieces (charts, roadmap, maps, the full icon set) live in subpaths on purpose, so the core
|
|
175
|
+
entry point stays small. Every component ships an `llms.txt` API sheet next to its source.
|
|
176
|
+
|
|
177
|
+
## Theming
|
|
178
|
+
|
|
179
|
+
All visuals are driven by `var(--kpt-*)` tokens (three tiers: primitives → semantic → component).
|
|
180
|
+
Override them in a stylesheet imported **after** `@konce-pt/styles`:
|
|
181
|
+
|
|
182
|
+
```css
|
|
183
|
+
:root {
|
|
184
|
+
--kpt-color-primary: oklch(0.55 0.2 265); /* rebrand in one line */
|
|
185
|
+
--kpt-color-primary-hover: oklch(0.5 0.2 265);
|
|
186
|
+
}
|
|
187
|
+
:root[data-theme='dark'] {
|
|
188
|
+
--kpt-color-primary: oklch(0.7 0.16 265);
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Common token names:** surfaces `--kpt-color-surface`, `--kpt-color-surface-sunken|raised|variant|hover|selected`; text `--kpt-color-on-surface`, `--kpt-color-on-surface-muted` (aliases `--kpt-color-text`, `--kpt-color-text-muted|subtle|inverse`); borders `--kpt-color-border`, `--kpt-color-border-strong`; accent roles in full — `{primary,danger,success,warning,info}` each with `-hover`, `-contrast`, `-subtle`, `-border`; radii `--kpt-radius-sm|md|lg|xl|full|none`; elevation `--kpt-elevation-1..4` (aliases `--kpt-shadow-sm|md|lg`). There is no `--kpt-color-bg`.
|
|
193
|
+
|
|
194
|
+
Variants and sizes travel on `data-*` attributes (`data-variant`, `data-size`), never on modifier
|
|
195
|
+
classes — that is what the SCSS reads.
|
|
196
|
+
|
|
197
|
+
## Icons
|
|
198
|
+
|
|
199
|
+
**84 icons are built in and need no configuration** — what the components themselves draw plus the
|
|
200
|
+
staples of an application shell (`sun`, `moon`, `bell`, `settings`, `users`, `logout`,
|
|
201
|
+
`layout-dashboard`, `home`, `activity`, `chart-bar`, `brand-github` …). A typical admin panel needs
|
|
202
|
+
nothing else.
|
|
203
|
+
|
|
204
|
+
For the full **Tabler Icons** set (MIT, 5130 icons) there are two paths, and the difference is the
|
|
205
|
+
bundle. Every icon is its own export, so importing by name lets the bundler keep just those:
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
// Production — two icons reach the bundle.
|
|
209
|
+
import { LayoutDashboard, Rocket } from '@konce-pt/react/icons';
|
|
210
|
+
import { registerKptIcons } from '@konce-pt/react';
|
|
211
|
+
registerKptIcons([LayoutDashboard, Rocket]);
|
|
212
|
+
|
|
213
|
+
// Prototype — every icon, about 1.2 MB.
|
|
214
|
+
import { registerKptTablerIcons } from '@konce-pt/react/icons';
|
|
215
|
+
registerKptTablerIcons();
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`registerKptIcons` is the one that shrinks: it takes the data as an argument and imports nothing from
|
|
219
|
+
the Tabler subpath. For the same reason `registerKptIcons(tabler)` with a namespace import
|
|
220
|
+
(`import * as tabler`) registers everything — a namespace object handed to a function blocks static
|
|
221
|
+
analysis. The registry is global, so one call at the app entry is enough; no provider needed.
|
|
222
|
+
|
|
223
|
+
## Internationalization (i18n)
|
|
224
|
+
|
|
225
|
+
Component labels ship in **English (default)** and **Polish**. Without a provider everything renders
|
|
226
|
+
in English — a missing provider is never an error. `KptI18nProvider` sets the language for a subtree:
|
|
227
|
+
|
|
25
228
|
```tsx
|
|
26
229
|
import { KptI18nProvider, useKptI18n } from '@konce-pt/react';
|
|
27
230
|
|
|
@@ -34,26 +237,177 @@ export function App() {
|
|
|
34
237
|
}
|
|
35
238
|
|
|
36
239
|
function Toolbar() {
|
|
37
|
-
const { t } = useKptI18n();
|
|
38
|
-
return
|
|
240
|
+
const { t, setLocale } = useKptI18n();
|
|
241
|
+
return (
|
|
242
|
+
<button onClick={() => setLocale('en')}>
|
|
243
|
+
{t('paginator.range', { start: 1, end: 10, total: 42 })}
|
|
244
|
+
</button>
|
|
245
|
+
);
|
|
39
246
|
}
|
|
40
247
|
```
|
|
41
248
|
|
|
42
|
-
|
|
249
|
+
`useKptI18n()` returns `{ locale, setLocale, messages, messagesFor, t }`. `t(key, params?)` takes a
|
|
250
|
+
dotted key with `{name}` interpolation and falls back to English, then to the key itself.
|
|
251
|
+
|
|
252
|
+
**Add any language with one JSON** (shape = the `KptMessages` contract; missing keys fall back to
|
|
253
|
+
English):
|
|
254
|
+
|
|
255
|
+
```tsx
|
|
256
|
+
import de from './i18n/de.json';
|
|
257
|
+
|
|
258
|
+
<KptI18nProvider locale="de" messages={{ de }}>…</KptI18nProvider>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Any component with labels also accepts `locale` and `dictionary` props, which take priority over the
|
|
262
|
+
provider. Calendar weekday/month names come from the browser's `Intl` API. The contract and the
|
|
263
|
+
dictionaries live in [`@konce-pt/i18n`](https://www.npmjs.com/package/@konce-pt/i18n), shared with
|
|
264
|
+
the Angular port.
|
|
265
|
+
|
|
266
|
+
## Helpers
|
|
267
|
+
|
|
268
|
+
- `cn(...values)` — class-name joining (the `clsx` role, no dependency).
|
|
269
|
+
- `Slot` + the `asChild` prop — render as another element while keeping classes and attributes.
|
|
270
|
+
- `composeRefs(...refs)` — merge several refs into one callback.
|
|
271
|
+
|
|
272
|
+
## Documentation
|
|
273
|
+
|
|
274
|
+
- **Playground** — live demos with copyable code: [ui.konce.pt/react](https://ui.konce.pt/react).
|
|
275
|
+
- **`llms.txt`** — LLM-friendly API sheets per component, shipped inside the package; the
|
|
276
|
+
package-wide sheet lives at [ui.konce.pt/llms/react/llms.txt](https://ui.konce.pt/llms/react/llms.txt)
|
|
277
|
+
(PL mirror: [llms-pl.txt](https://ui.konce.pt/llms/react/llms-pl.txt)).
|
|
278
|
+
- **Security scanners** — Socket.dev and similar tools flag i18n keys as domain names
|
|
279
|
+
(`.email`, `.today` and friends are real TLDs) and the map's default endpoints; the
|
|
280
|
+
[project sheet](https://ui.konce.pt/llms.txt) explains each alert under "Security scanners".
|
|
281
|
+
- Repository: [gitlab.com/konce-pt/koncept-ui](https://gitlab.com/konce-pt/koncept-ui)
|
|
282
|
+
|
|
283
|
+
## License
|
|
284
|
+
|
|
285
|
+
MIT © konce.pt
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
<div align="center">
|
|
290
|
+
|
|
291
|
+
## 🇵🇱 Wersja polska
|
|
292
|
+
|
|
293
|
+
</div>
|
|
294
|
+
|
|
295
|
+
**Koncept UI** to darmowy system projektowy na licencji **MIT**. Ta paczka to jego port na
|
|
296
|
+
**Reacta 19** — nie podobnie wyglądający zamiennik, tylko ten sam kontrakt renderowania.
|
|
297
|
+
|
|
298
|
+
- 🎯 **Jedna warstwa CSS dla obu portów** — te same klasy `kpt-*`, te same tokeny `--kpt-*`, ta sama
|
|
299
|
+
kolejność `@layer kpt.*`. Drzewo DOM odpowiada wersji Angulara węzeł w węzeł.
|
|
300
|
+
- 📦 **Zero zależności runtime** — `cn`, `Slot` i `composeRefs` są w paczce.
|
|
301
|
+
- ⚛️ **React 19** — `ref` jako zwykły prop (bez `forwardRef`), kontrolki działają kontrolowane
|
|
302
|
+
i niekontrolowane, z natywnym `name`/`form` (React 19 Actions i React Hook Form bez adaptera).
|
|
303
|
+
- 📊 **Flagowa tabela danych** — sortowanie, filtry globalne i kolumnowe, paginacja, virtual scroll,
|
|
304
|
+
zaznaczanie, przestawianie i zamrażanie kolumn, edycja w miejscu, podsumowanie, eksport CSV.
|
|
305
|
+
- 🎨 **100% na tokenach** — każdy styl to `var(--kpt-*)`. Motyw jasny/ciemny, neutralna paleta OKLCH.
|
|
306
|
+
- ♿ **Natywne elementy** — `<button>`, `<input>`, `<label>` wszędzie tam, gdzie istnieją; stan błędu
|
|
307
|
+
na `aria-invalid`, nie na klasie.
|
|
308
|
+
- 🌍 **Wbudowane i18n** — angielski (domyślny) i polski, przełączanie w runtime, dowolny język
|
|
309
|
+
jednym plikiem JSON.
|
|
310
|
+
|
|
311
|
+
### Instalacja
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
npm i @konce-pt/react @konce-pt/tokens @konce-pt/styles
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
`react` i `react-dom` (`>=19`) to peery, które masz już w aplikacji. Opcjonalnie:
|
|
318
|
+
`@konce-pt/grid` (układ; komponenty w `@konce-pt/react/grid`), `@konce-pt/validators`
|
|
319
|
+
(walidatory PL: NIP, REGON, PESEL, IBAN, kod pocztowy) oraz `leaflet` (`^1.9`) — **opcjonalny**
|
|
320
|
+
peer, potrzebny wyłącznie dla `@konce-pt/react/map`.
|
|
321
|
+
|
|
322
|
+
### Konfiguracja
|
|
323
|
+
|
|
324
|
+
Paczka wysyła **sam JavaScript**. CSS ładujesz raz, w wejściu aplikacji:
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
import '@konce-pt/tokens/css';
|
|
328
|
+
import '@konce-pt/tokens/css/dark';
|
|
329
|
+
import '@konce-pt/styles'; // reset, kolejność warstw, motyw
|
|
330
|
+
import '@konce-pt/styles/components'; // warstwa komponentów — WYMAGANE, to ona styluje kpt-*
|
|
331
|
+
import '@konce-pt/grid'; // opcjonalnie — klasy układu
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
`@konce-pt/styles/components` powstaje z tego samego SCSS-a, który port Angulara kompiluje do
|
|
335
|
+
własnego bundla — stąd identyczny wygląd obu portów. Angular wstrzykuje te style w runtime, React
|
|
336
|
+
nie ma dla nich innego źródła, więc ten import nie jest opcjonalny.
|
|
337
|
+
|
|
338
|
+
Motyw ciemny: `<html data-theme="dark">` (albo `prefers-color-scheme`). Nadpisania `--kpt-color-*`
|
|
339
|
+
w arkuszu importowanym **po** `@konce-pt/styles`.
|
|
340
|
+
|
|
341
|
+
> **CDK nie jest tu potrzebny.** Komponenty z panelem (`KptSelect`, `KptPopover`, `KptMenu`,
|
|
342
|
+
> `KptAutocomplete`, `KptDatepicker`…) renderują go przez wewnętrzny `KptOverlay` do portalu na
|
|
343
|
+
> `document.body`, więc `@angular/cdk/overlay-prebuilt.css` nie jest wymagany. W otwartym
|
|
344
|
+
> `KptDialog` panel trafia do `<dialog>`, bo `showModal()` przenosi go do górnej warstwy przeglądarki.
|
|
345
|
+
|
|
346
|
+
### Ikony
|
|
347
|
+
|
|
348
|
+
**84 ikony są wbudowane i nie wymagają konfiguracji** — to, co rysują same komponenty, plus staple
|
|
349
|
+
powłoki aplikacji (`sun`, `moon`, `bell`, `settings`, `users`, `logout`, `layout-dashboard`,
|
|
350
|
+
`home`, `activity`, `chart-bar`, `brand-github`…). Typowy panel administracyjny nie potrzebuje nic
|
|
351
|
+
więcej.
|
|
352
|
+
|
|
353
|
+
Pełny zestaw **Tabler Icons** (MIT, 5130 ikon) ma dwie ścieżki, a różnica jest w bundlu. Każda ikona
|
|
354
|
+
jest osobnym eksportem, więc import po nazwie zostawia w bundlu wyłącznie użyte:
|
|
355
|
+
|
|
356
|
+
```tsx
|
|
357
|
+
// Produkcja — do bundla wchodzą dwie ikony.
|
|
358
|
+
import { LayoutDashboard, Rocket } from '@konce-pt/react/icons';
|
|
359
|
+
import { registerKptIcons } from '@konce-pt/react';
|
|
360
|
+
registerKptIcons([LayoutDashboard, Rocket]);
|
|
361
|
+
|
|
362
|
+
// Prototyp — wszystkie ikony, około 1,2 MB.
|
|
363
|
+
import { registerKptTablerIcons } from '@konce-pt/react/icons';
|
|
364
|
+
registerKptTablerIcons();
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
To `registerKptIcons` odchudza, bo przyjmuje dane argumentem i sam nie importuje pełnego zestawu.
|
|
368
|
+
Z tego samego powodu `registerKptIcons(tabler)` z importem przestrzeni nazw (`import * as tabler`)
|
|
369
|
+
rejestruje komplet — namespace przekazany do funkcji blokuje analizę statyczną. Rejestr jest
|
|
370
|
+
globalny, więc wystarczy jedno wywołanie w wejściu aplikacji.
|
|
371
|
+
|
|
372
|
+
### Internacjonalizacja (i18n)
|
|
373
|
+
|
|
374
|
+
Etykiety są dostępne po **angielsku (domyślnie)** i **polsku**. Bez providera wszystko renderuje się
|
|
375
|
+
po angielsku — brak providera nigdy nie jest błędem. `<KptI18nProvider locale="pl">` ustawia język
|
|
376
|
+
dla poddrzewa, `useKptI18n()` zwraca `{ locale, setLocale, messages, messagesFor, t }`, a
|
|
377
|
+
`t('paginator.range', { start: 1, end: 10, total: 42 })` interpoluje `{nazwa}` i spada na EN, potem
|
|
378
|
+
na sam klucz.
|
|
379
|
+
|
|
380
|
+
**Własny język jednym plikiem JSON** (kształt = kontrakt `KptMessages`; brakujące klucze spadają
|
|
381
|
+
na EN):
|
|
382
|
+
|
|
383
|
+
```tsx
|
|
384
|
+
import de from './i18n/de.json';
|
|
385
|
+
|
|
386
|
+
<KptI18nProvider locale="de" messages={{ de }}>…</KptI18nProvider>
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Propsy `locale` i `dictionary` na komponencie mają priorytet nad providerem. Nazwy dni i miesięcy
|
|
390
|
+
w kalendarzach pochodzą z `Intl`. Kontrakt i słowniki żyją w `@konce-pt/i18n`, wspólnym z portem
|
|
391
|
+
Angulara.
|
|
392
|
+
|
|
393
|
+
### Komponenty (80+)
|
|
394
|
+
|
|
395
|
+
Formularze, przyciski i akcje, layout, nawigacja, dane (z flagową `KptDataTable`), feedback
|
|
396
|
+
i overlay — pełna lista w tabeli powyżej. Ciężkie rzeczy (wykresy, roadmapa, mapy, pełny Tabler)
|
|
397
|
+
siedzą w subpathach `@konce-pt/react/{charts,roadmap,grid,map,icons}`, żeby nie obciążać rdzenia.
|
|
398
|
+
Każdy komponent ma obok źródła plik `llms.txt` z opisem API.
|
|
399
|
+
|
|
400
|
+
### Dokumentacja
|
|
43
401
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
- Warianty i rozmiary przez atrybuty `data-*`, nie przez klasy modyfikatorów.
|
|
49
|
-
- React 19: `ref` jest zwykłym propem — bez `forwardRef`.
|
|
50
|
-
- Kontrolki formularza działają kontrolowane i niekontrolowane, z natywnym `name`/`form`
|
|
51
|
-
(React 19 Actions i React Hook Form bez adaptera).
|
|
52
|
-
- Tłumaczenia pochodzą z `@konce-pt/i18n`, wspólnego z portem Angulara.
|
|
402
|
+
Playground z demami: [ui.konce.pt/react](https://ui.konce.pt/react). Opisy API dla modeli:
|
|
403
|
+
[`llms.txt`](https://ui.konce.pt/llms/react/llms.txt) (EN) i
|
|
404
|
+
[`llms-pl.txt`](https://ui.konce.pt/llms/react/llms-pl.txt) (PL). Repozytorium:
|
|
405
|
+
[gitlab.com/konce-pt/koncept-ui](https://gitlab.com/konce-pt/koncept-ui).
|
|
53
406
|
|
|
54
|
-
|
|
55
|
-
|
|
407
|
+
Alerty skanerów łańcucha dostaw (Socket.dev i podobne) — klucze i18n czytane jak domeny
|
|
408
|
+
oraz domyślne endpointy mapy — omawia sekcja „Skanery bezpieczeństwa" w
|
|
409
|
+
[arkuszu projektu](https://ui.konce.pt/llms-pl.txt).
|
|
56
410
|
|
|
57
|
-
|
|
411
|
+
### Licencja
|
|
58
412
|
|
|
59
413
|
MIT © konce.pt
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# KptAccordion (@konce-pt/react)
|
|
2
|
+
|
|
3
|
+
An accordion — a group of expandable panels. `multi` allows several open at once.
|
|
4
|
+
Import: `import { KptAccordion } from '@konce-pt/react';`
|
|
5
|
+
|
|
6
|
+
## DOM
|
|
7
|
+
<div class="kpt-accordion-host">
|
|
8
|
+
<div class="kpt-accordion-panel-host" style="--kpt-anim-duration: 500ms">
|
|
9
|
+
<div class="kpt-accordion-panel is-open">
|
|
10
|
+
<button class="kpt-accordion-panel__header" aria-expanded="true">
|
|
11
|
+
<span class="kpt-accordion-panel__title">Section 1</span>
|
|
12
|
+
<span class="kpt-icon-host kpt-accordion-panel__chevron is-open">…</span>
|
|
13
|
+
</button>
|
|
14
|
+
<div class="kpt-accordion-panel__collapse is-open">
|
|
15
|
+
<div class="kpt-accordion-panel__collapse-inner">
|
|
16
|
+
<div class="kpt-accordion-panel__body">…children…</div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
## KptAccordion props
|
|
24
|
+
- `multi`: boolean — several panels open at once
|
|
25
|
+
- `openIndexes` / `defaultOpenIndexes` / `onOpenIndexesChange` — the open state, by index
|
|
26
|
+
- `animated`: boolean (default true), `animationDuration`: number (ms, default 500)
|
|
27
|
+
|
|
28
|
+
## KptAccordion.Panel props
|
|
29
|
+
- `title` (required), `disabled`
|
|
30
|
+
- `expanded` / `defaultExpanded` / `onExpandedChange` — used when the panel stands alone
|
|
31
|
+
- `children`
|
|
32
|
+
|
|
33
|
+
## Who owns the state
|
|
34
|
+
The accordion owns it, and panels receive their index by cloning — without that, single mode would
|
|
35
|
+
have no way to close its siblings. A panel used outside an accordion falls back to its own state, so
|
|
36
|
+
it works standalone with no extra wrapper.
|
|
37
|
+
|
|
38
|
+
## Collapsed content stays mounted
|
|
39
|
+
It gets `inert` and `aria-hidden` instead of being removed, so the height can be animated while
|
|
40
|
+
nothing inside takes focus or reaches a screen reader.
|
|
41
|
+
|
|
42
|
+
## Examples
|
|
43
|
+
<KptAccordion defaultOpenIndexes={[0]}>
|
|
44
|
+
<KptAccordion.Panel title="Section 1">…</KptAccordion.Panel>
|
|
45
|
+
<KptAccordion.Panel title="Section 2">…</KptAccordion.Panel>
|
|
46
|
+
</KptAccordion>
|
|
47
|
+
|
|
48
|
+
<KptAccordion multi openIndexes={open} onOpenIndexesChange={setOpen}>…</KptAccordion>
|
|
49
|
+
|
|
50
|
+
## Tokens
|
|
51
|
+
`--kpt-color-border`, `--kpt-color-surface`, `--kpt-motion-easing-standard`, plus
|
|
52
|
+
`--kpt-anim-duration` set by the accordion on each panel.
|
|
53
|
+
|
|
54
|
+
## Accessibility
|
|
55
|
+
The header is a native button with `aria-expanded`; the collapsed region is `inert` and
|
|
56
|
+
`aria-hidden`, so it is skipped by both the keyboard and the screen reader.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# KptAlert (@konce-pt/react)
|
|
2
|
+
|
|
3
|
+
An inline message. Variants info/success/warning/danger, an optional title and dismissal.
|
|
4
|
+
Import: `import { KptAlert } from '@konce-pt/react';`
|
|
5
|
+
|
|
6
|
+
## DOM
|
|
7
|
+
<div class="kpt-alert-host">
|
|
8
|
+
<div class="kpt-alert" data-variant="success" role="alert">
|
|
9
|
+
<span class="kpt-icon-host kpt-alert__icon">…</span>
|
|
10
|
+
<div class="kpt-alert__content">
|
|
11
|
+
<div class="kpt-alert__title">Saved</div>
|
|
12
|
+
<div class="kpt-alert__message">…children…</div>
|
|
13
|
+
</div>
|
|
14
|
+
<button class="kpt-alert__close" type="button" aria-label="Close">…</button>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
## Props
|
|
19
|
+
- `variant`: 'info' | 'success' | 'warning' | 'danger' (default 'info')
|
|
20
|
+
- `title`: string
|
|
21
|
+
- `dismissible`: boolean — adds the close button
|
|
22
|
+
- `onClosed()` — fires after the user dismisses it
|
|
23
|
+
- `locale`, `dictionary` — i18n overrides for this component only
|
|
24
|
+
- `className`, `ref` and every other `<div>` prop go to the host
|
|
25
|
+
|
|
26
|
+
## Dismissal hides, it does not unmount
|
|
27
|
+
Closing sets `hidden` on the host, the same as the Angular port, so the same alert can be shown
|
|
28
|
+
again without rebuilding the tree. When you would rather drive it from outside, simply do not render
|
|
29
|
+
the component — the internal state is a convenience, not the only way.
|
|
30
|
+
|
|
31
|
+
## The icon follows the variant
|
|
32
|
+
Each variant picks its own icon from the built-in set (`info`, `circle-check`, `alert-triangle`,
|
|
33
|
+
`circle-x`), so there is nothing to configure and no way for the icon to contradict the colour.
|
|
34
|
+
|
|
35
|
+
## Examples
|
|
36
|
+
<KptAlert variant="info" title="Info">A new version is available.</KptAlert>
|
|
37
|
+
<KptAlert variant="danger" title="Error" dismissible onClosed={onClosed}>Could not save.</KptAlert>
|
|
38
|
+
|
|
39
|
+
## Tokens
|
|
40
|
+
The semantic colour pairs of each variant (`--kpt-color-info` / `-success` / `-warning` /
|
|
41
|
+
`-danger` with their `-subtle` counterparts), `--kpt-radius-md`.
|
|
42
|
+
|
|
43
|
+
## Accessibility
|
|
44
|
+
The message is `role="alert"`, so a screen reader announces it as it appears. Use it for something
|
|
45
|
+
that just happened — for a permanent note, style your own container without that role.
|
|
@@ -92,3 +92,23 @@ export declare function useKptShellNavToggle(options?: {
|
|
|
92
92
|
readonly 'aria-label': string;
|
|
93
93
|
readonly onClick: () => void;
|
|
94
94
|
};
|
|
95
|
+
/**
|
|
96
|
+
* Etykieta pozycji nawigacji. W szynie ikon (układ md–xl) shell chowa ją techniką
|
|
97
|
+
* „visually hidden", więc pozycja zwęża się do samego znaku, a czytnik ekranu wciąż
|
|
98
|
+
* odczytuje pełny tekst.
|
|
99
|
+
*
|
|
100
|
+
* Nosi atrybut `kptnavlabel` — to po nim celuje wspólny SCSS. Nazwy atrybutów w selektorach
|
|
101
|
+
* CSS są w HTML case-insensitive, więc jedna reguła obsługuje oba porty; zapis małymi literami
|
|
102
|
+
* omija przy okazji ostrzeżenie React o nieznanym propie.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* <a href="/pulpit"><KptIcon name="layout-dashboard" /> <KptNavLabel>Pulpit</KptNavLabel></a>
|
|
106
|
+
*/
|
|
107
|
+
export declare function KptNavLabel({ className, ...rest }: Readonly<ComponentPropsWithRef<'span'>>): import("react").JSX.Element;
|
|
108
|
+
/**
|
|
109
|
+
* Nagłówek grupy pozycji w nawigacji. W szynie ikon chowany tak samo jak [[KptNavLabel]].
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* <KptNavSection>Raporty</KptNavSection>
|
|
113
|
+
*/
|
|
114
|
+
export declare function KptNavSection({ className, ...rest }: Readonly<ComponentPropsWithRef<'div'>>): import("react").JSX.Element;
|
|
@@ -103,3 +103,27 @@ export function useKptShellNavToggle(options) {
|
|
|
103
103
|
onClick: toggleSidenav,
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Etykieta pozycji nawigacji. W szynie ikon (układ md–xl) shell chowa ją techniką
|
|
108
|
+
* „visually hidden", więc pozycja zwęża się do samego znaku, a czytnik ekranu wciąż
|
|
109
|
+
* odczytuje pełny tekst.
|
|
110
|
+
*
|
|
111
|
+
* Nosi atrybut `kptnavlabel` — to po nim celuje wspólny SCSS. Nazwy atrybutów w selektorach
|
|
112
|
+
* CSS są w HTML case-insensitive, więc jedna reguła obsługuje oba porty; zapis małymi literami
|
|
113
|
+
* omija przy okazji ostrzeżenie React o nieznanym propie.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* <a href="/pulpit"><KptIcon name="layout-dashboard" /> <KptNavLabel>Pulpit</KptNavLabel></a>
|
|
117
|
+
*/
|
|
118
|
+
export function KptNavLabel({ className, ...rest }) {
|
|
119
|
+
return _jsx("span", { kptnavlabel: '', className: className, ...rest });
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Nagłówek grupy pozycji w nawigacji. W szynie ikon chowany tak samo jak [[KptNavLabel]].
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* <KptNavSection>Raporty</KptNavSection>
|
|
126
|
+
*/
|
|
127
|
+
export function KptNavSection({ className, ...rest }) {
|
|
128
|
+
return _jsx("div", { kptnavsection: '', className: className, ...rest });
|
|
129
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# KptAppShell (@konce-pt/react)
|
|
2
|
+
|
|
3
|
+
The application skeleton: a bar on top, a side panel and the content.
|
|
4
|
+
Import: `import { KptAppShell, useKptShellNavToggle } from '@konce-pt/react';`
|
|
5
|
+
|
|
6
|
+
## DOM
|
|
7
|
+
<div class="kpt-app-shell kpt-app-shell--nav-open"
|
|
8
|
+
data-sidenav-mode="auto" data-sidenav-breakpoint="lg">
|
|
9
|
+
…toolbar…
|
|
10
|
+
<div class="kpt-app-shell__body">
|
|
11
|
+
<aside class="kpt-app-shell__sidenav" role="navigation" tabindex="-1" id="…">…sidenav…</aside>
|
|
12
|
+
<div class="kpt-app-shell__scrim" aria-hidden="true"></div>
|
|
13
|
+
<main class="kpt-app-shell__content">…children…</main>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
## Props
|
|
18
|
+
- `toolbar`: ReactNode — the slot above the content area (usually `<KptToolbar>`)
|
|
19
|
+
- `sidenav`: ReactNode — the side panel slot (usually `<KptSidenav>`)
|
|
20
|
+
- `children`: ReactNode — the application content
|
|
21
|
+
- `sidenavOpen` / `defaultSidenavOpen` / `onSidenavOpenChange` — the docked layout's open state
|
|
22
|
+
(default open)
|
|
23
|
+
- `sidenavCompactOpen` / `defaultSidenavCompactOpen` / `onSidenavCompactOpenChange` — the overlay's
|
|
24
|
+
open state (default closed)
|
|
25
|
+
- `sidenavMode`: 'auto' | 'side' | 'over' (default 'auto')
|
|
26
|
+
- `sidenavBreakpoint`: 'sm' | 'md' | 'lg' | 'xl' | '2xl' (default 'lg')
|
|
27
|
+
- `sidenavRailBreakpoint`: the same union or null (default null)
|
|
28
|
+
- `sidenavLabel`: string — empty falls back to `appShell.navigation` from the dictionary
|
|
29
|
+
- `locale`, `dictionary` — i18n overrides for this component only
|
|
30
|
+
|
|
31
|
+
## Two open states, on purpose
|
|
32
|
+
The docked layout and the overlay keep separate state. If they shared one, narrowing the window
|
|
33
|
+
would have to overwrite the consumer's state, and widening it back would have nothing to restore.
|
|
34
|
+
`useKptShellNavToggle` hits whichever state governs the current layout, so one button serves both.
|
|
35
|
+
|
|
36
|
+
## The nav toggle
|
|
37
|
+
const toggle = useKptShellNavToggle(); // optional { label }
|
|
38
|
+
<KptButton variant="text" {...toggle}>Menu</KptButton>
|
|
39
|
+
|
|
40
|
+
It returns `aria-expanded`, `aria-controls`, `aria-label` and `onClick`. Spread them on a native
|
|
41
|
+
`<button>` or on `<KptButton>` (which forwards them to its inner `<button>`) — ARIA attributes must
|
|
42
|
+
land on the element that carries the role, never on a wrapper.
|
|
43
|
+
|
|
44
|
+
`useKptAppShell()` exposes the same state directly: `{ isSidenavOpen, isOverlay, sidenavId,
|
|
45
|
+
toggleSidenav, openSidenav, closeSidenav }`. It throws outside `<KptAppShell>`.
|
|
46
|
+
|
|
47
|
+
## Layout is CSS, behaviour is JS
|
|
48
|
+
Which layout applies is decided entirely by the stylesheet from the `data-*` attributes, so nothing
|
|
49
|
+
flickers before hydration and the page is correct with JavaScript disabled. The breakpoint hook only
|
|
50
|
+
decides WHICH state the button flips. The scrim is always in the DOM; CSS controls its visibility.
|
|
51
|
+
|
|
52
|
+
## Tokens
|
|
53
|
+
`--kpt-sidenav-width` (16rem), `--kpt-sidenav-rail-width` (4rem), `--kpt-z-overlay`,
|
|
54
|
+
`--kpt-color-overlay-scrim`, `--kpt-motion-duration-base`, `--kpt-motion-easing-standard`.
|
|
55
|
+
|
|
56
|
+
## Accessibility
|
|
57
|
+
- The panel is an `<aside role="navigation">` with a label and an `id` for `aria-controls`.
|
|
58
|
+
- A closed docked panel leaves the tab order through `visibility`, correct on the first frame.
|
|
59
|
+
- While the overlay is open the content gets `inert`, and Escape closes the panel.
|
package/dist/auth/auth.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export interface KptAuthProps extends Omit<ComponentPropsWithRef<'div'>, 'onSubm
|
|
|
10
10
|
defaultMode?: KptAuthMode;
|
|
11
11
|
onModeChange?: (mode: KptAuthMode) => void;
|
|
12
12
|
layout?: KptAuthLayout;
|
|
13
|
-
providers?: KptAuthProvider[];
|
|
13
|
+
providers?: readonly KptAuthProvider[];
|
|
14
14
|
providerLayout?: KptAuthProviderLayout;
|
|
15
15
|
showName?: boolean;
|
|
16
16
|
requireTerms?: boolean;
|