@keboola/design 3.2.3 → 4.0.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/AGENTS.md +21 -1
- package/COMPONENT-API.md +26 -25
- package/README.md +8 -8
- package/dist/constants-D3gaMY-W.d.cts +39 -0
- package/dist/constants-D3gaMY-W.d.ts +39 -0
- package/dist/editors.cjs +1976 -0
- package/dist/editors.cjs.map +1 -0
- package/dist/editors.d.cts +113 -0
- package/dist/editors.d.ts +113 -0
- package/dist/editors.js +1948 -0
- package/dist/editors.js.map +1 -0
- package/dist/index.cjs +37 -1204
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +304 -405
- package/dist/index.d.ts +304 -405
- package/dist/index.js +38 -1200
- package/dist/index.js.map +1 -1
- package/dist/markdown-editor.cjs +4 -4
- package/dist/markdown-editor.cjs.map +1 -1
- package/dist/markdown-editor.d.cts +4 -3
- package/dist/markdown-editor.d.ts +4 -3
- package/dist/markdown-editor.js +4 -4
- package/dist/markdown-editor.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +46 -34
- package/src/styles.css +19 -0
package/AGENTS.md
CHANGED
|
@@ -13,6 +13,7 @@ Working **on** the package (commands, layer boundary, token surface, the FA→Lu
|
|
|
13
13
|
- `import '@keboola/design/styles'` — Tailwind-extending consumers. Your PostCSS+Tailwind processes `@tailwind` directives plus design's `dist/` in your content scan. Avoids duplicate preflights/utilities. **Default for any Keboola app.**
|
|
14
14
|
- `import '@keboola/design/styles/compiled'` — drop-in pre-compiled CSS (~176 KB minified). No Tailwind setup required. Use only when you genuinely cannot run Tailwind.
|
|
15
15
|
- Icons: `import { ChevronDown } from '@keboola/design/icons'`.
|
|
16
|
+
- Code editors: `import { CodeEditor, SqlEditor, MergeEditor } from '@keboola/design/editors'`. These pull the full CodeMirror bundle (~1.3 MB), so they ship from a dedicated subpath — keeping the root barrel CodeMirror-free for apps that don't edit code.
|
|
16
17
|
|
|
17
18
|
## Decision tree
|
|
18
19
|
|
|
@@ -112,6 +113,14 @@ This file answers **which** component to use; [`COMPONENT-API.md`](./COMPONENT-A
|
|
|
112
113
|
|
|
113
114
|
Vertical rhythm: prefer `tw-gap-*` on a flex column parent over `tw-mt-*` on children — avoids margin-collapse. Page-level max width: use `PageLayout`'s `maxWidth` prop (`narrow` / `default` / `wide` / `full`), not `tw-max-w-[…]` literals.
|
|
114
115
|
|
|
116
|
+
**Page gutter is consumer-owned.** `AppShell.Main` and `PageLayout` impose **no** page gutter by design — content renders flush against the sidebar/header unless you add one. Put the padding on the content region yourself (the `AppShell` story wraps Main content in `tw-p-6`):
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
<AppShell.Main>
|
|
120
|
+
<div className="tw-flex tw-flex-col tw-gap-4 tw-px-6 tw-py-6">{/* page content */}</div>
|
|
121
|
+
</AppShell.Main>
|
|
122
|
+
```
|
|
123
|
+
|
|
115
124
|
### Navigation / flow
|
|
116
125
|
|
|
117
126
|
| Use | When |
|
|
@@ -148,7 +157,7 @@ The `label` prop implies `orientation="horizontal"` — labels are not rendered
|
|
|
148
157
|
| `CodeEditor` | Generic code editing (JSON, YAML, shell) |
|
|
149
158
|
| `SqlEditor` | SQL editing (syntax + autocomplete) |
|
|
150
159
|
|
|
151
|
-
`Select` is wrong above ~10 items — use `Combobox`. `Combobox` is wrong for free-form values — use `Tagger`. `CodeEditor`/`SqlEditor` load the full CodeMirror bundle; reserve for real code editing.
|
|
160
|
+
`Select` is wrong above ~10 items — use `Combobox`. `Combobox` is wrong for free-form values — use `Tagger`. `CodeEditor`/`SqlEditor` load the full CodeMirror bundle and ship from the `@keboola/design/editors` subpath (not the root); reserve for real code editing.
|
|
152
161
|
|
|
153
162
|
## Composition recipes
|
|
154
163
|
|
|
@@ -357,6 +366,17 @@ const form = useAppForm({
|
|
|
357
366
|
/>
|
|
358
367
|
```
|
|
359
368
|
|
|
369
|
+
**Sheet** — use `Sheet.Header title="…" description="…"` for a styled title + close icon; do **not** hand-roll with the raw `Sheet.Title`, which renders an unstyled `<h2>`. `Sheet.Body` provides horizontal padding only (`tw-px-4`) — add your own vertical rhythm/gap:
|
|
370
|
+
|
|
371
|
+
```tsx
|
|
372
|
+
<Sheet open={open} onOpenChange={setOpen}>
|
|
373
|
+
<Sheet.Content>
|
|
374
|
+
<Sheet.Header title="Edit table" description="Adjust the table metadata." />
|
|
375
|
+
<Sheet.Body className="tw-flex tw-flex-col tw-gap-4 tw-py-4">{/* fields */}</Sheet.Body>
|
|
376
|
+
</Sheet.Content>
|
|
377
|
+
</Sheet>
|
|
378
|
+
```
|
|
379
|
+
|
|
360
380
|
## Icons
|
|
361
381
|
|
|
362
382
|
Canonical icon surface is `@keboola/design/icons` — a wildcard re-export of [lucide-react](https://lucide.dev) plus Keboola-custom inline-SVG icons. Follow **shadcn convention**: import named icons directly, no wrapper component. Every Lucide icon is available without any package edit.
|
package/COMPONENT-API.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @keboola/design — component API reference
|
|
2
2
|
|
|
3
|
-
> **Generated file — do not edit by hand.** Regenerate with `
|
|
3
|
+
> **Generated file — do not edit by hand.** Regenerate with `pnpm --filter @keboola/design generate:api` (extracts prop signatures from the TypeScript types via `react-docgen-typescript`).
|
|
4
4
|
|
|
5
|
-
This is the prop-signature contract for the most-used components. For _which_ component to reach for, see [`AGENTS.md`](./AGENTS.md) (the decision tree); for live worked examples, open the colocated `*.stories.tsx` in Storybook (`
|
|
5
|
+
This is the prop-signature contract for the most-used components. For _which_ component to reach for, see [`AGENTS.md`](./AGENTS.md) (the decision tree); for live worked examples, open the colocated `*.stories.tsx` in Storybook (`pnpm dev --filter=@keboola/design`).
|
|
6
6
|
|
|
7
7
|
Props listed are the ones each component **declares itself**. Components built on a native element (`Button` on `<button>`, `Link` on `<a>`, `Card` on `<div>`, …) also accept that element's standard attributes — called out in each entry's note.
|
|
8
8
|
|
|
@@ -249,29 +249,30 @@ Source: `src/blocks/Form/connectors/NumberField.tsx`
|
|
|
249
249
|
|
|
250
250
|
Source: `src/blocks/Form/connectors/SelectField.tsx`
|
|
251
251
|
|
|
252
|
-
> `options` is required. Forwards `variant === "argo"` to `Select.Content`.
|
|
253
|
-
|
|
254
|
-
| Prop | Type | Required | Default | Description
|
|
255
|
-
| ------------------ | -------------------------------------------- | -------- | ------- |
|
|
256
|
-
| `
|
|
257
|
-
| `
|
|
258
|
-
| `
|
|
259
|
-
| `
|
|
260
|
-
| `
|
|
261
|
-
| `
|
|
262
|
-
| `
|
|
263
|
-
| `
|
|
264
|
-
| `
|
|
265
|
-
| `label` | `ReactNode` | no | — |
|
|
266
|
-
| `name` | `string` | no | — |
|
|
267
|
-
| `onOpenChange` | `((open: boolean) => void)` | no | — |
|
|
268
|
-
| `open` | `boolean` | no | — |
|
|
269
|
-
| `
|
|
270
|
-
| `
|
|
271
|
-
| `
|
|
272
|
-
| `
|
|
273
|
-
| `
|
|
274
|
-
| `
|
|
252
|
+
> Pass `items` (canonical, matches the base `Select`) or the deprecated `options` alias — one is required. Forwards `variant === "argo"` to `Select.Content`.
|
|
253
|
+
|
|
254
|
+
| Prop | Type | Required | Default | Description |
|
|
255
|
+
| ------------------ | -------------------------------------------- | -------- | ------- | ----------------------- |
|
|
256
|
+
| `autoComplete` | `string` | no | — | |
|
|
257
|
+
| `className` | `string` | no | — | |
|
|
258
|
+
| `defaultOpen` | `boolean` | no | — | |
|
|
259
|
+
| `defaultValue` | `string` | no | — | |
|
|
260
|
+
| `dir` | `"rtl" \| "ltr"` | no | — | |
|
|
261
|
+
| `disabled` | `boolean` | no | — | |
|
|
262
|
+
| `form` | `string` | no | — | |
|
|
263
|
+
| `help` | `ReactNode` | no | — | |
|
|
264
|
+
| `items` | `readonly Option[]` | no | — | |
|
|
265
|
+
| `label` | `ReactNode` | no | — | |
|
|
266
|
+
| `name` | `string` | no | — | |
|
|
267
|
+
| `onOpenChange` | `((open: boolean) => void)` | no | — | |
|
|
268
|
+
| `open` | `boolean` | no | — | |
|
|
269
|
+
| `options` | `readonly Option[]` | no | — | @deprecated use `items` |
|
|
270
|
+
| `placeholder` | `string` | no | — | |
|
|
271
|
+
| `required` | `boolean` | no | — | |
|
|
272
|
+
| `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
|
|
273
|
+
| `state` | `"warning" \| "error" \| "default" \| null` | no | — | |
|
|
274
|
+
| `triggerClassName` | `string` | no | — | |
|
|
275
|
+
| `variant` | `"primary" \| "secondary" \| "argo" \| null` | no | — | |
|
|
275
276
|
|
|
276
277
|
### `field.TextAreaField`
|
|
277
278
|
|
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ It is version-pinned to your lockfile, so it always matches the components you a
|
|
|
23
23
|
## Install
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
|
|
26
|
+
pnpm add @keboola/design @keboola/tailwind-config
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
## Use
|
|
@@ -38,7 +38,7 @@ import '@keboola/design/styles';
|
|
|
38
38
|
### Documentation
|
|
39
39
|
|
|
40
40
|
```
|
|
41
|
-
$
|
|
41
|
+
$ pnpm dev
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
See [Storybook's documentation](https://storybook.js.org/docs/react/writing-stories/introduction) for an introduction to writing stories
|
|
@@ -46,13 +46,13 @@ See [Storybook's documentation](https://storybook.js.org/docs/react/writing-stor
|
|
|
46
46
|
### Testing
|
|
47
47
|
|
|
48
48
|
```
|
|
49
|
-
$
|
|
49
|
+
$ pnpm test
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
Or in UI mode:
|
|
53
53
|
|
|
54
54
|
```
|
|
55
|
-
$
|
|
55
|
+
$ pnpm test:ui
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
For more information, read [Vitest's documentation](https://vitest.dev/guide/)
|
|
@@ -65,18 +65,18 @@ Every story is also run as a test via the [Storybook Vitest addon](https://story
|
|
|
65
65
|
- **interaction** — each story's `play()` function runs as a test.
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
|
|
68
|
+
pnpm --filter @keboola/design test:stories
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
This is the cheap, low-flakiness base layer for testing stories. Screenshot/visual regression is a separate, complementary layer (UT-4060) — the Vitest addon does **not** do screenshot comparison.
|
|
72
72
|
|
|
73
73
|
**How it's wired:**
|
|
74
74
|
|
|
75
|
-
- `vitest.config.ts` — a separate Vitest config (browser mode, Playwright Chromium provider) so `
|
|
75
|
+
- `vitest.config.ts` — a separate Vitest config (browser mode, Playwright Chromium provider) so `pnpm test` stays jsdom-only and browser-free; story tests are opt-in via `test:stories`. It is named `vitest.config.ts` (not `vitest.storybook.config.ts`) so the Storybook "Run tests" button (`@storybook/addon-vitest`) can discover it — the addon only scans `vitest.workspace.*` / `vitest.config.*` / `vite.config.*` names; under any other name it falls back to `vite.config.ts` and crashes the dev server (UT-4243). The jsdom `test` script therefore pins `--config vite.config.ts` explicitly.
|
|
76
76
|
- `.storybook/vitest.setup.ts` — applies the Storybook `preview` annotations (decorators, globals) so tests render exactly like Storybook.
|
|
77
77
|
- `optimizeDeps.entries` crawls every story up front so Vite optimizes all story dependencies in one pass — without it, a heavy dep (mermaid, codemirror, …) discovered mid-run makes Vite re-optimize and 404 in-flight imports.
|
|
78
78
|
|
|
79
|
-
**Prerequisites:** build the workspace deps once (`
|
|
79
|
+
**Prerequisites:** build the workspace deps once (`pnpm build --filter='@keboola/design^...'`) and install the browser (`pnpm --filter @keboola/design exec playwright install chromium`).
|
|
80
80
|
|
|
81
81
|
**Adding coverage:** nothing to do — every CSF `*.stories.tsx` is picked up automatically. Add a `play()` to a story to turn it into an interaction test. (MDX docs pages — `src/**/*.mdx` — are not executed as tests; the addon only runs CSF stories.)
|
|
82
82
|
|
|
@@ -127,7 +127,7 @@ Worked examples: `src/components/Button/Button.stories.tsx` (click + disabled),
|
|
|
127
127
|
Coverage is **measured, not gated** — it gives a baseline for the story suite. The default `test:stories` run stays coverage-free and fast; coverage only loads when you opt in:
|
|
128
128
|
|
|
129
129
|
```bash
|
|
130
|
-
|
|
130
|
+
pnpm --filter @keboola/design test:stories:coverage
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
Same prerequisites as `test:stories` (build workspace deps, install Chromium). Reports land in `packages/design/coverage/` (gitignored): a `text` summary in the console and a browsable `html` report at `coverage/index.html`.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
declare const CHUNK_TYPE: {
|
|
2
|
+
readonly UNCHANGED: "unchanged";
|
|
3
|
+
readonly ADDED: "added";
|
|
4
|
+
readonly REMOVED: "removed";
|
|
5
|
+
};
|
|
6
|
+
type ChunkType = (typeof CHUNK_TYPE)[keyof typeof CHUNK_TYPE];
|
|
7
|
+
type DiffChunk = {
|
|
8
|
+
type: ChunkType;
|
|
9
|
+
value: string;
|
|
10
|
+
/** 1-indexed start line in the old (left) text */
|
|
11
|
+
oldStart: number;
|
|
12
|
+
/** 1-indexed end line in the old (left) text */
|
|
13
|
+
oldEnd: number;
|
|
14
|
+
/** 1-indexed start line in the new (right) text */
|
|
15
|
+
newStart: number;
|
|
16
|
+
/** 1-indexed end line in the new (right) text */
|
|
17
|
+
newEnd: number;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* A paired conflict: adjacent REMOVED + ADDED chunks from diffLines,
|
|
21
|
+
* representing a section that was modified. If only one side exists,
|
|
22
|
+
* the other is empty (pure insertion or deletion).
|
|
23
|
+
*/
|
|
24
|
+
type MergeConflict = {
|
|
25
|
+
id: string;
|
|
26
|
+
oldValue: string;
|
|
27
|
+
oldStartLine: number;
|
|
28
|
+
oldEndLine: number;
|
|
29
|
+
newValue: string;
|
|
30
|
+
newStartLine: number;
|
|
31
|
+
newEndLine: number;
|
|
32
|
+
};
|
|
33
|
+
declare const CHANGE_CLASS: {
|
|
34
|
+
readonly SAFE: "safe";
|
|
35
|
+
readonly CONFLICT: "conflict";
|
|
36
|
+
};
|
|
37
|
+
type ChangeClassification = (typeof CHANGE_CLASS)[keyof typeof CHANGE_CLASS];
|
|
38
|
+
|
|
39
|
+
export type { ChangeClassification as C, DiffChunk as D, MergeConflict as M };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
declare const CHUNK_TYPE: {
|
|
2
|
+
readonly UNCHANGED: "unchanged";
|
|
3
|
+
readonly ADDED: "added";
|
|
4
|
+
readonly REMOVED: "removed";
|
|
5
|
+
};
|
|
6
|
+
type ChunkType = (typeof CHUNK_TYPE)[keyof typeof CHUNK_TYPE];
|
|
7
|
+
type DiffChunk = {
|
|
8
|
+
type: ChunkType;
|
|
9
|
+
value: string;
|
|
10
|
+
/** 1-indexed start line in the old (left) text */
|
|
11
|
+
oldStart: number;
|
|
12
|
+
/** 1-indexed end line in the old (left) text */
|
|
13
|
+
oldEnd: number;
|
|
14
|
+
/** 1-indexed start line in the new (right) text */
|
|
15
|
+
newStart: number;
|
|
16
|
+
/** 1-indexed end line in the new (right) text */
|
|
17
|
+
newEnd: number;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* A paired conflict: adjacent REMOVED + ADDED chunks from diffLines,
|
|
21
|
+
* representing a section that was modified. If only one side exists,
|
|
22
|
+
* the other is empty (pure insertion or deletion).
|
|
23
|
+
*/
|
|
24
|
+
type MergeConflict = {
|
|
25
|
+
id: string;
|
|
26
|
+
oldValue: string;
|
|
27
|
+
oldStartLine: number;
|
|
28
|
+
oldEndLine: number;
|
|
29
|
+
newValue: string;
|
|
30
|
+
newStartLine: number;
|
|
31
|
+
newEndLine: number;
|
|
32
|
+
};
|
|
33
|
+
declare const CHANGE_CLASS: {
|
|
34
|
+
readonly SAFE: "safe";
|
|
35
|
+
readonly CONFLICT: "conflict";
|
|
36
|
+
};
|
|
37
|
+
type ChangeClassification = (typeof CHANGE_CLASS)[keyof typeof CHANGE_CLASS];
|
|
38
|
+
|
|
39
|
+
export type { ChangeClassification as C, DiffChunk as D, MergeConflict as M };
|