@estiva-app/ui 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.
- package/LICENSE +21 -0
- package/README.md +124 -0
- package/dist/Avatar.d.ts +16 -0
- package/dist/Avatar.d.ts.map +1 -0
- package/dist/Button.d.ts +28 -0
- package/dist/Button.d.ts.map +1 -0
- package/dist/Chip.d.ts +21 -0
- package/dist/Chip.d.ts.map +1 -0
- package/dist/DialogShell.d.ts +19 -0
- package/dist/DialogShell.d.ts.map +1 -0
- package/dist/Divider.d.ts +12 -0
- package/dist/Divider.d.ts.map +1 -0
- package/dist/EmptyState.d.ts +14 -0
- package/dist/EmptyState.d.ts.map +1 -0
- package/dist/Field.d.ts +13 -0
- package/dist/Field.d.ts.map +1 -0
- package/dist/IconButton.d.ts +17 -0
- package/dist/IconButton.d.ts.map +1 -0
- package/dist/Select.d.ts +30 -0
- package/dist/Select.d.ts.map +1 -0
- package/dist/Skeleton.d.ts +24 -0
- package/dist/Skeleton.d.ts.map +1 -0
- package/dist/TextInput.d.ts +11 -0
- package/dist/TextInput.d.ts.map +1 -0
- package/dist/Textarea.d.ts +8 -0
- package/dist/Textarea.d.ts.map +1 -0
- package/dist/Tooltip.d.ts +22 -0
- package/dist/Tooltip.d.ts.map +1 -0
- package/dist/cn.d.ts +10 -0
- package/dist/cn.d.ts.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +486 -0
- package/dist/index.js.map +7 -0
- package/package.json +74 -0
- package/src/Avatar.stories.tsx +55 -0
- package/src/Avatar.tsx +81 -0
- package/src/Button.stories.tsx +53 -0
- package/src/Button.tsx +67 -0
- package/src/Chip.stories.tsx +37 -0
- package/src/Chip.tsx +43 -0
- package/src/DialogShell.stories.tsx +97 -0
- package/src/DialogShell.tsx +65 -0
- package/src/Divider.stories.tsx +44 -0
- package/src/Divider.tsx +22 -0
- package/src/EmptyState.stories.tsx +18 -0
- package/src/EmptyState.tsx +24 -0
- package/src/Field.stories.tsx +22 -0
- package/src/Field.tsx +24 -0
- package/src/IconButton.stories.tsx +44 -0
- package/src/IconButton.tsx +60 -0
- package/src/Select.stories.tsx +107 -0
- package/src/Select.tsx +195 -0
- package/src/Skeleton.stories.tsx +33 -0
- package/src/Skeleton.tsx +38 -0
- package/src/TextInput.stories.tsx +18 -0
- package/src/TextInput.tsx +29 -0
- package/src/Textarea.stories.tsx +17 -0
- package/src/Textarea.tsx +25 -0
- package/src/Tooltip.stories.tsx +47 -0
- package/src/Tooltip.tsx +70 -0
- package/src/cn.ts +13 -0
- package/src/index.ts +25 -0
- package/tailwind-preset.js +162 -0
- package/tokens.css +225 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Estiva
|
|
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,124 @@
|
|
|
1
|
+
# @estiva-app/ui
|
|
2
|
+
|
|
3
|
+
Estiva's design tokens, and a small set of primitives built on them, for
|
|
4
|
+
every Estiva app — Peek, Ship, and whatever comes next.
|
|
5
|
+
|
|
6
|
+
**Tokens are the contract. Components are a convenience.**
|
|
7
|
+
|
|
8
|
+
## What is in it
|
|
9
|
+
|
|
10
|
+
- `tailwind-preset.js` — the token *names*, as a Tailwind preset: colours,
|
|
11
|
+
type ramp, radii, shadows, the skeleton animation. Peek's, verbatim.
|
|
12
|
+
- `tokens.css` — the token *values*, one block per theme: `signal` (what
|
|
13
|
+
Peek renders), `ship` (what Ship renders), and the `light` / `dark` bases.
|
|
14
|
+
Same names in every block.
|
|
15
|
+
- Primitives — arriving one at a time (see Storybook). Each has stories that
|
|
16
|
+
need no app data; if a story needs a fixture, the component is not a
|
|
17
|
+
primitive and does not belong here.
|
|
18
|
+
|
|
19
|
+
## Using it
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
// tailwind.config.js
|
|
23
|
+
import estiva from '@estiva-app/ui/tailwind-preset'
|
|
24
|
+
export default {
|
|
25
|
+
presets: [estiva],
|
|
26
|
+
content: ['./index.html', './src/**/*.{ts,tsx}'],
|
|
27
|
+
theme: { extend: { /* your app's own tokens, if any */ } },
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```css
|
|
32
|
+
/* your entry CSS, before anything that uses a token */
|
|
33
|
+
@import '@estiva-app/ui/tokens.css';
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```html
|
|
37
|
+
<html data-theme="ship"> <!-- or "signal" / "dark"; nothing = light. Peek uses the classes: <html class="dark signal">. -->
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Install it:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install @estiva-app/ui
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Spread `estivaContent` into your `content`.** Tailwind does not merge
|
|
47
|
+
`content` from a preset — measured, see the comment in `tailwind-preset.js` —
|
|
48
|
+
so without this every class used only by these components is purged, and the
|
|
49
|
+
result is a build that succeeds with components rendering at the wrong size:
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
import estiva, { estivaContent } from '@estiva-app/ui/tailwind-preset'
|
|
53
|
+
export default {
|
|
54
|
+
presets: [estiva],
|
|
55
|
+
content: [...estivaContent, './index.html', './src/**/*.{ts,tsx}'],
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## The rules
|
|
60
|
+
|
|
61
|
+
### Forking is allowed
|
|
62
|
+
|
|
63
|
+
> Forking a component into your app is allowed and is not a failure. If you
|
|
64
|
+
> fork one, you owe nothing back. Tokens are the only thing you must not
|
|
65
|
+
> diverge from.
|
|
66
|
+
|
|
67
|
+
If a primitive nearly fits but not quite, copy it into your app and change
|
|
68
|
+
it. Say so on the package's ticket — a fork is information about the seam —
|
|
69
|
+
but do not bend your view around a component, and do not wait for
|
|
70
|
+
permission. A library people are afraid to deviate from becomes a tax.
|
|
71
|
+
|
|
72
|
+
### Tokens, never raw hex
|
|
73
|
+
|
|
74
|
+
If the colour you need has no token, the token is missing: add it here, in
|
|
75
|
+
every theme, rather than reaching for hex in an app.
|
|
76
|
+
|
|
77
|
+
### The tailwind-merge pitfall
|
|
78
|
+
|
|
79
|
+
A custom text-size class (`text-btn-small`, `text-caption`, `text-h2`…) is
|
|
80
|
+
**silently dropped** by `tailwind-merge` when a `text-{colour}` class follows
|
|
81
|
+
it in the same merged list. In shared components, spell sizes as arbitrary
|
|
82
|
+
values — `text-[12px] leading-[12px]` — and keep the token classes for plain
|
|
83
|
+
`className` strings that never go through `cn()`. The bug appears in the
|
|
84
|
+
consuming app and its cause is in the package, which is why this rule lives
|
|
85
|
+
here.
|
|
86
|
+
|
|
87
|
+
### Menus and popovers — five rules
|
|
88
|
+
|
|
89
|
+
Stay open on hover · close on mouse leave (for hover-opened menus) · guard
|
|
90
|
+
the parent's hover state · close on outside click · close on Escape. Each is
|
|
91
|
+
forgettable on its own, and a popover that fails one feels broken without
|
|
92
|
+
anyone being able to say why. A click-opened menu (Select, a `…` menu) owes
|
|
93
|
+
the last two; a hover-opened one owes all five.
|
|
94
|
+
|
|
95
|
+
### Only offer actions that can succeed
|
|
96
|
+
|
|
97
|
+
An action appears only where it works. A control that cannot succeed right
|
|
98
|
+
now is disabled *with its reason* (a tooltip), and a control someone may
|
|
99
|
+
never use is absent, not disabled. Primitives expose what that needs: a
|
|
100
|
+
`disabled` that can explain itself, never a button that fails.
|
|
101
|
+
|
|
102
|
+
## Themes
|
|
103
|
+
|
|
104
|
+
| Theme | Selected by | Whose |
|
|
105
|
+
|----------|------------------------------------------------|--------------------------------|
|
|
106
|
+
| `signal` | `data-theme="signal"` or `.dark.signal` | Peek — what it renders |
|
|
107
|
+
| `ship` | `data-theme="ship"` | Ship — what it renders |
|
|
108
|
+
| `dark` | `data-theme="dark"` or `.dark` | Peek's base under Signal |
|
|
109
|
+
| `light` | nothing | the `:root` base; Estiva ID |
|
|
110
|
+
|
|
111
|
+
Peek's Signal-only extras (washes, glows, the summary highlight, the huddle
|
|
112
|
+
register, the wordmark, the mono stack) are product, not the contract, and
|
|
113
|
+
stay in Peek's own `.signal` block.
|
|
114
|
+
|
|
115
|
+
## Working on it
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
npm install
|
|
119
|
+
npm test # every theme defines every token the preset names, and no other
|
|
120
|
+
npm run storybook # http://localhost:6008 — Design Tokens, and each primitive, in signal and ship
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Extracting a primitive from Peek must not change how Peek renders:
|
|
124
|
+
screenshot-compare before and after, in Peek's own Storybook.
|
package/dist/Avatar.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const hueFor: (key: string) => string;
|
|
2
|
+
/** Peek's rule: the first letter of the first two words. */
|
|
3
|
+
export declare const initialsFor: (name: string) => string;
|
|
4
|
+
export interface AvatarProps {
|
|
5
|
+
/** The picture URL, resolved by the caller. A picture that fails to load falls back to the initials. */
|
|
6
|
+
src?: string;
|
|
7
|
+
/** The person's name — where the initials and the colour come from. */
|
|
8
|
+
name?: string;
|
|
9
|
+
/** Alt text for the picture; the name when absent. Also the initials' source when there is no name. */
|
|
10
|
+
alt?: string;
|
|
11
|
+
/** Pixels. Peek's scale: 16 · 24 · 32 · 36 (default). */
|
|
12
|
+
size?: number;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function Avatar({ src, name, alt, size, className }: AvatarProps): import("react").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=Avatar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../src/Avatar.tsx"],"names":[],"mappings":"AA2BA,eAAO,MAAM,MAAM,GAAI,KAAK,MAAM,WAIjC,CAAA;AAED,4DAA4D;AAC5D,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,WAMtB,CAAA;AAElB,MAAM,WAAW,WAAW;IAC1B,wGAAwG;IACxG,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uGAAuG;IACvG,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,MAAM,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,GAAQ,EAAE,IAAS,EAAE,SAAS,EAAE,EAAE,WAAW,+BA0BhF"}
|
package/dist/Button.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Peek's Button (2026-08-28), verbatim, plus what Ship added and Peek should
|
|
4
|
+
* adopt: a `destructive` variant — the muted button in the error colour, for
|
|
5
|
+
* "Delete project" and its kind; a destructive action is a button like any
|
|
6
|
+
* other, not a dotted link — and `type="button"` by default, so a button
|
|
7
|
+
* inside a form submits it only when asked to.
|
|
8
|
+
*
|
|
9
|
+
* Three variants and two sizes: 32px default / 24px small, 6px radius, 500
|
|
10
|
+
* weight. Sizes are spelled as arbitrary values for the reason the README
|
|
11
|
+
* records: tailwind-merge drops a custom `text-{size}` that is followed by a
|
|
12
|
+
* `text-{colour}`.
|
|
13
|
+
*
|
|
14
|
+
* The primary reads in `text-inverse` on the accent — a theme decides what
|
|
15
|
+
* that is (dark on Peek's light accents, light on Ship's dark one). Under
|
|
16
|
+
* Signal it is also semibold, as Peek has it.
|
|
17
|
+
*/
|
|
18
|
+
export type ButtonVariant = 'primary' | 'outlined' | 'muted' | 'destructive';
|
|
19
|
+
export type ButtonSize = 'default' | 'small';
|
|
20
|
+
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
21
|
+
variant?: ButtonVariant;
|
|
22
|
+
size?: ButtonSize;
|
|
23
|
+
/** 16px, stroke 1.5 on the default size; 14px on small. */
|
|
24
|
+
leadingIcon?: ReactNode;
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
}
|
|
27
|
+
export declare function Button({ variant, size, leadingIcon, className, children, disabled, type, ...props }: ButtonProps): import("react").JSX.Element;
|
|
28
|
+
//# sourceMappingURL=Button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../src/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAG5D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,aAAa,CAAA;AAC5E,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,CAAA;AAE5C,MAAM,WAAW,WAAY,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IAC1E,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,MAAM,CAAC,EACrB,OAAiB,EACjB,IAAgB,EAChB,WAAW,EACX,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,IAAe,EACf,GAAG,KAAK,EACT,EAAE,WAAW,+BA2Bb"}
|
package/dist/Chip.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Peek's Chip (2026-08-28), verbatim: a 20px pill in one of six colour
|
|
4
|
+
* types, with room for a 12px icon either side. Under Signal the label is
|
|
5
|
+
* mono and the coloured types carry a hairline, as Peek has it. The icon
|
|
6
|
+
* slots centre their icon (Ship's addition — an icon beside text otherwise
|
|
7
|
+
* rides on the baseline).
|
|
8
|
+
*
|
|
9
|
+
* The label is the `chip` type token, 11px / 500; it is a plain class here,
|
|
10
|
+
* never merged, so tailwind-merge cannot drop it.
|
|
11
|
+
*/
|
|
12
|
+
export type ChipType = 'neutral' | 'brand' | 'info' | 'warning' | 'success' | 'error';
|
|
13
|
+
export interface ChipProps {
|
|
14
|
+
type?: ChipType;
|
|
15
|
+
label?: string;
|
|
16
|
+
leadingIcon?: ReactNode;
|
|
17
|
+
trailingIcon?: ReactNode;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function Chip({ type, label, leadingIcon, trailingIcon, className }: ChipProps): import("react").JSX.Element;
|
|
21
|
+
//# sourceMappingURL=Chip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Chip.d.ts","sourceRoot":"","sources":["../src/Chip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC;;;;;;;;;GASG;AACH,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;AAErF,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,YAAY,CAAC,EAAE,SAAS,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAWD,wBAAgB,IAAI,CAAC,EAAE,IAAgB,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE,SAAS,+BAUhG"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Peek's DialogShell (2026-08-28), verbatim: the portal, the backdrop, the
|
|
4
|
+
* 502px card and its chrome — a 48px header with the title and a close
|
|
5
|
+
* button, a body, a 48px footer for the buttons. A dialog is just what goes
|
|
6
|
+
* in the three slots. Plus what Ship added: Escape closes it, and the card
|
|
7
|
+
* says what it is to assistive tech.
|
|
8
|
+
*/
|
|
9
|
+
export interface DialogShellProps {
|
|
10
|
+
title: string;
|
|
11
|
+
onClose: () => void;
|
|
12
|
+
footer: ReactNode;
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
/** Extra classes on the body (e.g. `flex flex-col gap-6`, or a max height with `overflow-y-auto`). */
|
|
15
|
+
bodyClassName?: string;
|
|
16
|
+
width?: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function DialogShell({ title, onClose, footer, children, bodyClassName, width }: DialogShellProps): import("react").ReactPortal;
|
|
19
|
+
//# sourceMappingURL=DialogShell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DialogShell.d.ts","sourceRoot":"","sources":["../src/DialogShell.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAMjD;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,MAAM,EAAE,SAAS,CAAA;IACjB,QAAQ,EAAE,SAAS,CAAA;IACnB,sGAAsG;IACtG,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAW,EAAE,EAAE,gBAAgB,+BAyC7G"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Peek's Divider (2026-08-28): a hairline in `border-subtle`, inset 12px each
|
|
3
|
+
* side. Plus what Ship added: `orientation="vertical"` — the same hairline
|
|
4
|
+
* standing up, stretching to its row's height, no inset — and the separator
|
|
5
|
+
* role for assistive tech.
|
|
6
|
+
*/
|
|
7
|
+
export interface DividerProps {
|
|
8
|
+
orientation?: 'horizontal' | 'vertical';
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function Divider({ orientation, className }: DividerProps): import("react").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=Divider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Divider.d.ts","sourceRoot":"","sources":["../src/Divider.tsx"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAA;IACvC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,OAAO,CAAC,EAAE,WAA0B,EAAE,SAAS,EAAE,EAAE,YAAY,+BAQ9E"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Peek's EmptyState (2026-08-28), verbatim: a 16px icon over a centred line
|
|
4
|
+
* of secondary text. The message is the caller's — a shared component has no
|
|
5
|
+
* words of its own for what is missing.
|
|
6
|
+
*/
|
|
7
|
+
export interface EmptyStateProps {
|
|
8
|
+
/** 16px, stroke 1.5. A speech bubble when absent. */
|
|
9
|
+
icon?: ReactNode;
|
|
10
|
+
message: string;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function EmptyState({ icon, message, className }: EmptyStateProps): import("react").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=EmptyState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["../src/EmptyState.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,qDAAqD;IACrD,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,eAAe,+BAOvE"}
|
package/dist/Field.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Peek's Field (2026-08-28), verbatim: a label over a control, 8px apart,
|
|
4
|
+
* with a red asterisk when required. The label is the `input-label` type
|
|
5
|
+
* token as a plain class, never merged.
|
|
6
|
+
*/
|
|
7
|
+
export interface FieldProps {
|
|
8
|
+
label: string;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
export declare function Field({ label, required, children }: FieldProps): import("react").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=Field.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Field.d.ts","sourceRoot":"","sources":["../src/Field.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,KAAK,CAAC,EAAE,KAAK,EAAE,QAAgB,EAAE,QAAQ,EAAE,EAAE,UAAU,+BAUtE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Peek's IconButton (2026-08-28), verbatim: a square 4px-padded button
|
|
4
|
+
* around a 16px icon, 8px radius, three variants, an optional tooltip that
|
|
5
|
+
* portals above or below. Plus `type="button"` by default (Ship's addition),
|
|
6
|
+
* so it never submits a form by accident.
|
|
7
|
+
*/
|
|
8
|
+
export type IconButtonVariant = 'muted' | 'outlined' | 'primary';
|
|
9
|
+
export interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
10
|
+
variant?: IconButtonVariant;
|
|
11
|
+
tooltip?: string;
|
|
12
|
+
tooltipPlacement?: 'top' | 'bottom';
|
|
13
|
+
/** The icon: 16px, stroke 1.5. */
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
}
|
|
16
|
+
export declare function IconButton({ variant, className, children, disabled, tooltip, tooltipPlacement, type, ...props }: IconButtonProps): import("react").JSX.Element;
|
|
17
|
+
//# sourceMappingURL=IconButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IconButton.d.ts","sourceRoot":"","sources":["../src/IconButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAI5D;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAA;AAEhE,MAAM,WAAW,eAAgB,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IAC9E,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gBAAgB,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAA;IACnC,kCAAkC;IAClC,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAiB,EACjB,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,gBAAgB,EAChB,IAAe,EACf,GAAG,KAAK,EACT,EAAE,eAAe,+BA8BjB"}
|
package/dist/Select.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Peek's Select (2026-08-28), verbatim, plus what Ship added: an option may
|
|
4
|
+
* carry a `leading` node — an avatar beside a person's name — shown in the
|
|
5
|
+
* trigger and in the list.
|
|
6
|
+
*
|
|
7
|
+
* A button that opens a portalled listbox under itself: arrows move, Home
|
|
8
|
+
* and End jump, Enter and Space pick, Escape closes and returns focus to the
|
|
9
|
+
* trigger, Tab closes, a click outside closes, a scroll or resize closes
|
|
10
|
+
* (the list is fixed to where the trigger was). Two sizes; `disabled`
|
|
11
|
+
* explains nothing by itself — wrap it in a tooltip that does.
|
|
12
|
+
*/
|
|
13
|
+
export interface SelectOption {
|
|
14
|
+
value: string;
|
|
15
|
+
label: string;
|
|
16
|
+
/** Drawn before the label, 16px — an Avatar, an icon. */
|
|
17
|
+
leading?: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
export interface SelectProps {
|
|
20
|
+
value: string;
|
|
21
|
+
onChange: (value: string) => void;
|
|
22
|
+
options: SelectOption[];
|
|
23
|
+
size?: 'default' | 'small';
|
|
24
|
+
ariaLabel?: string;
|
|
25
|
+
placeholder?: string;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
className?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function Select({ value, onChange, options, size, ariaLabel, placeholder, disabled, className }: SelectProps): import("react").JSX.Element;
|
|
30
|
+
//# sourceMappingURL=Select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../src/Select.tsx"],"names":[],"mappings":"AACA,OAAO,EAAgF,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAIpH;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,yDAAyD;IACzD,OAAO,CAAC,EAAE,SAAS,CAAA;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,MAAM,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAgB,EAAE,SAAS,EAAE,WAAuB,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,WAAW,+BAgK1I"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Peek's Skeleton (2026-08-28), the generic parts only: the bar, a row
|
|
4
|
+
* shaped like a list row, and a list of them. Peek's placeholders shaped
|
|
5
|
+
* like a conversation card or a huddle card know what those are and stay
|
|
6
|
+
* in Peek, built from the bar.
|
|
7
|
+
*
|
|
8
|
+
* A list reveals after 150ms (`animate-skeleton-in`, in the preset) so a
|
|
9
|
+
* fast load never flashes a skeleton — Peek's rule.
|
|
10
|
+
*/
|
|
11
|
+
export declare function SkeletonBar({ className, style }: {
|
|
12
|
+
className?: string;
|
|
13
|
+
style?: CSSProperties;
|
|
14
|
+
}): import("react").JSX.Element;
|
|
15
|
+
/** A 32px row: a 16px square and a bar, like a row with a face and a name. */
|
|
16
|
+
export declare function SkeletonRow({ barWidth }: {
|
|
17
|
+
barWidth?: number;
|
|
18
|
+
}): import("react").JSX.Element;
|
|
19
|
+
/** Rows of varied widths, so the placeholder does not read as a pattern. */
|
|
20
|
+
export declare function SkeletonList({ rows, className }: {
|
|
21
|
+
rows?: number;
|
|
22
|
+
className?: string;
|
|
23
|
+
}): import("react").JSX.Element;
|
|
24
|
+
//# sourceMappingURL=Skeleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Skeleton.d.ts","sourceRoot":"","sources":["../src/Skeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAG1C;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,aAAa,CAAA;CAAE,+BAE9F;AAID,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,EAAE,QAAc,EAAE,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,+BAOpE;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,EAAE,IAAQ,EAAE,SAAS,EAAE,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,+BAQ1F"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type InputHTMLAttributes } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Peek's TextInput (2026-08-28): the inset field with a 8px radius, 14px
|
|
4
|
+
* text, the focus border in every theme (Katerina, 2026-08-28: Ship's inputs
|
|
5
|
+
* focus like Signal's) — and Signal's glow on top.
|
|
6
|
+
* Plus a disabled look (Ship's addition): the disabled surface and text,
|
|
7
|
+
* no pointer.
|
|
8
|
+
*/
|
|
9
|
+
export type TextInputProps = InputHTMLAttributes<HTMLInputElement>;
|
|
10
|
+
export declare const TextInput: import("react").ForwardRefExoticComponent<TextInputProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
11
|
+
//# sourceMappingURL=TextInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TextInput.d.ts","sourceRoot":"","sources":["../src/TextInput.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,mBAAmB,EAAE,MAAM,OAAO,CAAA;AAG5D;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,mBAAmB,CAAC,gBAAgB,CAAC,CAAA;AAElE,eAAO,MAAM,SAAS,6GAgBpB,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type TextareaHTMLAttributes } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Peek's Textarea (2026-08-28), verbatim: TextInput's look on a textarea
|
|
4
|
+
* that does not resize. Plus a disabled look (Ship's addition).
|
|
5
|
+
*/
|
|
6
|
+
export type TextareaProps = TextareaHTMLAttributes<HTMLTextAreaElement>;
|
|
7
|
+
export declare const Textarea: import("react").ForwardRefExoticComponent<TextareaProps & import("react").RefAttributes<HTMLTextAreaElement>>;
|
|
8
|
+
//# sourceMappingURL=Textarea.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Textarea.d.ts","sourceRoot":"","sources":["../src/Textarea.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,sBAAsB,EAAE,MAAM,OAAO,CAAA;AAG/D;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,sBAAsB,CAAC,mBAAmB,CAAC,CAAA;AAEvE,eAAO,MAAM,QAAQ,+GAenB,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Peek's Tooltip and WithTooltip (2026-08-28), verbatim, in one file.
|
|
4
|
+
*
|
|
5
|
+
* `Tooltip` is the surface: a 30px elevated pill with a caption. `WithTooltip`
|
|
6
|
+
* wraps a trigger and portals the surface above or below it on hover, fixed
|
|
7
|
+
* to the viewport and kept 8px inside it. The wrapper is `inline-flex` and
|
|
8
|
+
* shrinks nothing — wrap a control, never a block (a form inside it
|
|
9
|
+
* collapses to its content width; Ship learnt that).
|
|
10
|
+
*/
|
|
11
|
+
export interface TooltipProps {
|
|
12
|
+
label: string;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function Tooltip({ label, className }: TooltipProps): import("react").JSX.Element;
|
|
16
|
+
export interface WithTooltipProps {
|
|
17
|
+
label: string;
|
|
18
|
+
placement?: 'top' | 'bottom';
|
|
19
|
+
children: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
export declare function WithTooltip({ label, placement, children }: WithTooltipProps): import("react").JSX.Element;
|
|
22
|
+
//# sourceMappingURL=Tooltip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../src/Tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAsE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAI1G;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,YAAY,+BAMzD;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAA;IAC5B,QAAQ,EAAE,SAAS,CAAA;CACpB;AAKD,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,SAAiB,EAAE,QAAQ,EAAE,EAAE,gBAAgB,+BAkCnF"}
|
package/dist/cn.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ClassValue } from 'clsx';
|
|
2
|
+
/**
|
|
3
|
+
* Peek's `cn`: clsx for the conditionals, tailwind-merge for the conflicts.
|
|
4
|
+
*
|
|
5
|
+
* Remember the pitfall the README records: a custom text-size class in a
|
|
6
|
+
* merged list is dropped when a `text-{colour}` follows it. Inside this
|
|
7
|
+
* package, sizes are arbitrary values (`text-[12px]`), never the token class.
|
|
8
|
+
*/
|
|
9
|
+
export declare function cn(...inputs: ClassValue[]): string;
|
|
10
|
+
//# sourceMappingURL=cn.d.ts.map
|
package/dist/cn.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../src/cn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAA;AAG5C;;;;;;GAMG;AACH,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @estiva-app/ui — the primitives.
|
|
3
|
+
*
|
|
4
|
+
* Shipped **built**: `dist/index.js` (esbuild, one bundle, React external) plus
|
|
5
|
+
* `.d.ts` from `tsc`. Not source — a package of `.ts` is compiled with the
|
|
6
|
+
* *consumer's* tsconfig, and Ship's `noUnusedLocals` alone is enough to fail a
|
|
7
|
+
* build over a library it does not own. See estiva-docs ADR 0002 §4a.
|
|
8
|
+
*
|
|
9
|
+
* `src/` still ships in the tarball, so stepping into a component lands on the
|
|
10
|
+
* TypeScript that produced it.
|
|
11
|
+
*/
|
|
12
|
+
export { Avatar, hueFor, initialsFor, type AvatarProps } from './Avatar';
|
|
13
|
+
export { Button, type ButtonProps, type ButtonSize, type ButtonVariant } from './Button';
|
|
14
|
+
export { Chip, type ChipProps, type ChipType } from './Chip';
|
|
15
|
+
export { IconButton, type IconButtonProps, type IconButtonVariant } from './IconButton';
|
|
16
|
+
export { Tooltip, WithTooltip, type TooltipProps, type WithTooltipProps } from './Tooltip';
|
|
17
|
+
export { Field, type FieldProps } from './Field';
|
|
18
|
+
export { Select, type SelectOption, type SelectProps } from './Select';
|
|
19
|
+
export { TextInput, type TextInputProps } from './TextInput';
|
|
20
|
+
export { Textarea, type TextareaProps } from './Textarea';
|
|
21
|
+
export { DialogShell, type DialogShellProps } from './DialogShell';
|
|
22
|
+
export { Divider, type DividerProps } from './Divider';
|
|
23
|
+
export { EmptyState, type EmptyStateProps } from './EmptyState';
|
|
24
|
+
export { SkeletonBar, SkeletonList, SkeletonRow } from './Skeleton';
|
|
25
|
+
export { cn } from './cn';
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAA;AACxE,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAA;AACxF,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAC5D,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAA;AACvF,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAC1F,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAA;AACtE,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAClE,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACnE,OAAO,EAAE,EAAE,EAAE,MAAM,MAAM,CAAA"}
|