@estiva-app/ui 0.1.0 → 0.3.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/README.md +12 -9
- package/base.css +43 -0
- package/dist/AppShell.d.ts +39 -0
- package/dist/AppShell.d.ts.map +1 -0
- package/dist/Avatar.d.ts +7 -2
- package/dist/Avatar.d.ts.map +1 -1
- package/dist/AvatarGroup.d.ts +23 -0
- package/dist/AvatarGroup.d.ts.map +1 -0
- package/dist/Banner.d.ts +19 -0
- package/dist/Banner.d.ts.map +1 -0
- package/dist/Breadcrumb.d.ts +28 -0
- package/dist/Breadcrumb.d.ts.map +1 -0
- package/dist/Checkbox.d.ts +18 -0
- package/dist/Checkbox.d.ts.map +1 -0
- package/dist/ChipInput.d.ts +57 -0
- package/dist/ChipInput.d.ts.map +1 -0
- package/dist/ConfirmDialog.d.ts +22 -0
- package/dist/ConfirmDialog.d.ts.map +1 -0
- package/dist/DialogShell.d.ts +9 -2
- package/dist/DialogShell.d.ts.map +1 -1
- package/dist/EditableText.d.ts +56 -0
- package/dist/EditableText.d.ts.map +1 -0
- package/dist/IdentityMenu.d.ts +58 -0
- package/dist/IdentityMenu.d.ts.map +1 -0
- package/dist/Menu.d.ts +82 -0
- package/dist/Menu.d.ts.map +1 -0
- package/dist/NavItem.d.ts +26 -0
- package/dist/NavItem.d.ts.map +1 -0
- package/dist/Person.d.ts +26 -0
- package/dist/Person.d.ts.map +1 -0
- package/dist/PersonTrigger.d.ts +23 -0
- package/dist/PersonTrigger.d.ts.map +1 -0
- package/dist/Property.d.ts +24 -0
- package/dist/Property.d.ts.map +1 -0
- package/dist/Rail.d.ts +18 -0
- package/dist/Rail.d.ts.map +1 -0
- package/dist/RailItem.d.ts +23 -0
- package/dist/RailItem.d.ts.map +1 -0
- package/dist/SearchInput.d.ts +21 -0
- package/dist/SearchInput.d.ts.map +1 -0
- package/dist/SectionHeader.d.ts +34 -0
- package/dist/SectionHeader.d.ts.map +1 -0
- package/dist/SectionLabel.d.ts +19 -0
- package/dist/SectionLabel.d.ts.map +1 -0
- package/dist/Select.d.ts +42 -5
- package/dist/Select.d.ts.map +1 -1
- package/dist/Sidebar.d.ts +18 -0
- package/dist/Sidebar.d.ts.map +1 -0
- package/dist/Tabs.d.ts +34 -0
- package/dist/Tabs.d.ts.map +1 -0
- package/dist/Toast.d.ts +48 -0
- package/dist/Toast.d.ts.map +1 -0
- package/dist/Tooltip.d.ts +3 -1
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/TopBar.d.ts +33 -0
- package/dist/TopBar.d.ts.map +1 -0
- package/dist/cn.d.ts +14 -4
- package/dist/cn.d.ts.map +1 -1
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1254 -106
- package/dist/index.js.map +4 -4
- package/package.json +5 -2
- package/src/AppShell.mdx +66 -0
- package/src/AppShell.stories.tsx +117 -0
- package/src/AppShell.tsx +77 -0
- package/src/Avatar.initials.test.ts +21 -0
- package/src/Avatar.mdx +49 -0
- package/src/Avatar.tsx +12 -9
- package/src/AvatarGroup.mdx +39 -0
- package/src/AvatarGroup.stories.tsx +56 -0
- package/src/AvatarGroup.tsx +42 -0
- package/src/Banner.mdx +45 -0
- package/src/Banner.stories.tsx +35 -0
- package/src/Banner.tsx +35 -0
- package/src/Breadcrumb.mdx +52 -0
- package/src/Breadcrumb.stories.tsx +42 -0
- package/src/Breadcrumb.tsx +106 -0
- package/src/Button.mdx +57 -0
- package/src/Checkbox.mdx +44 -0
- package/src/Checkbox.stories.tsx +49 -0
- package/src/Checkbox.tsx +46 -0
- package/src/Chip.mdx +43 -0
- package/src/ChipInput.mdx +68 -0
- package/src/ChipInput.stories.tsx +99 -0
- package/src/ChipInput.tsx +247 -0
- package/src/ConfirmDialog.mdx +51 -0
- package/src/ConfirmDialog.stories.tsx +63 -0
- package/src/ConfirmDialog.tsx +55 -0
- package/src/DialogShell.mdx +68 -0
- package/src/DialogShell.tsx +12 -5
- package/src/Divider.mdx +41 -0
- package/src/EditableText.mdx +59 -0
- package/src/EditableText.stories.tsx +63 -0
- package/src/EditableText.tsx +169 -0
- package/src/EmptyState.mdx +41 -0
- package/src/Field.mdx +39 -0
- package/src/IconButton.mdx +47 -0
- package/src/IdentityMenu.mdx +62 -0
- package/src/IdentityMenu.stories.tsx +52 -0
- package/src/IdentityMenu.tsx +159 -0
- package/src/Menu.mdx +111 -0
- package/src/Menu.stories.tsx +66 -0
- package/src/Menu.tsx +172 -0
- package/src/MenuItem.mdx +55 -0
- package/src/MenuItem.stories.tsx +98 -0
- package/src/NavItem.mdx +53 -0
- package/src/NavItem.stories.tsx +36 -0
- package/src/NavItem.tsx +53 -0
- package/src/Person.mdx +44 -0
- package/src/Person.stories.tsx +43 -0
- package/src/Person.tsx +39 -0
- package/src/PersonTrigger.mdx +51 -0
- package/src/PersonTrigger.stories.tsx +30 -0
- package/src/PersonTrigger.tsx +62 -0
- package/src/Property.mdx +51 -0
- package/src/Property.stories.tsx +91 -0
- package/src/Property.tsx +44 -0
- package/src/Rail.tsx +26 -0
- package/src/RailItem.mdx +50 -0
- package/src/RailItem.stories.tsx +37 -0
- package/src/RailItem.tsx +53 -0
- package/src/SearchInput.mdx +39 -0
- package/src/SearchInput.stories.tsx +24 -0
- package/src/SearchInput.tsx +45 -0
- package/src/SectionHeader.mdx +52 -0
- package/src/SectionHeader.stories.tsx +66 -0
- package/src/SectionHeader.tsx +85 -0
- package/src/SectionLabel.mdx +42 -0
- package/src/SectionLabel.stories.tsx +31 -0
- package/src/SectionLabel.tsx +28 -0
- package/src/Select.fit.test.ts +97 -0
- package/src/Select.mdx +71 -0
- package/src/Select.stories.tsx +95 -0
- package/src/Select.tsx +123 -15
- package/src/Sidebar.mdx +56 -0
- package/src/Sidebar.stories.tsx +50 -0
- package/src/Sidebar.tsx +32 -0
- package/src/Skeleton.mdx +39 -0
- package/src/Tabs.mdx +53 -0
- package/src/Tabs.stories.tsx +91 -0
- package/src/Tabs.tsx +73 -0
- package/src/TextInput.mdx +39 -0
- package/src/Textarea.mdx +36 -0
- package/src/Toast.mdx +54 -0
- package/src/Toast.stories.tsx +87 -0
- package/src/Toast.tsx +169 -0
- package/src/Tooltip.mdx +51 -0
- package/src/Tooltip.tsx +4 -2
- package/src/TopBar.mdx +62 -0
- package/src/TopBar.stories.tsx +96 -0
- package/src/TopBar.tsx +57 -0
- package/src/cn.test.ts +27 -0
- package/src/cn.ts +25 -5
- package/src/index.ts +23 -0
- package/tailwind-preset.js +4 -3
- package/tokens.css +4 -0
package/README.md
CHANGED
|
@@ -74,15 +74,18 @@ permission. A library people are afraid to deviate from becomes a tax.
|
|
|
74
74
|
If the colour you need has no token, the token is missing: add it here, in
|
|
75
75
|
every theme, rather than reaching for hex in an app.
|
|
76
76
|
|
|
77
|
-
### The tailwind-merge pitfall
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
`
|
|
84
|
-
|
|
85
|
-
|
|
77
|
+
### The tailwind-merge pitfall — retired for `cn()` users
|
|
78
|
+
|
|
79
|
+
Stock `tailwind-merge` **silently drops** a custom text-size class
|
|
80
|
+
(`text-btn-small`, `text-caption`, `text-h2`…) when a `text-{colour}` class
|
|
81
|
+
sits in the same merged list — it cannot classify the size, files it as a
|
|
82
|
+
colour, and lets the real colour knock it out. Since 2026-09-01 the
|
|
83
|
+
package's `cn()` is taught the preset's type ramp (`src/cn.ts`; `cn.test.ts`
|
|
84
|
+
pins the list to the preset), so **token size classes are safe in merged
|
|
85
|
+
lists** and are what new code should write. The trap still exists for anyone
|
|
86
|
+
merging with their own un-extended config — both apps re-export this `cn`,
|
|
87
|
+
so don't. Older components still spell sizes as arbitrary values; they
|
|
88
|
+
render identically and migrate to tokens as they are touched.
|
|
86
89
|
|
|
87
90
|
### Menus and popovers — five rules
|
|
88
91
|
|
package/base.css
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Shared app chrome that is not a token — the styling every Estiva app repeats
|
|
3
|
+
and a new app should not have to know about.
|
|
4
|
+
|
|
5
|
+
First occupant: the scrollbar (Katerina, 2026-09-01). Peek and Ship carried
|
|
6
|
+
this exact block in their own index.css, character for character, and the
|
|
7
|
+
library's Storybook carried nothing — so a menu that scrolls looked right in
|
|
8
|
+
both apps and wrong in the place components are reviewed. Colours come from
|
|
9
|
+
the theme's own tokens, so it follows whichever theme block is active.
|
|
10
|
+
|
|
11
|
+
Import it next to tokens.css:
|
|
12
|
+
|
|
13
|
+
@import '@estiva-app/ui/tokens.css';
|
|
14
|
+
@import '@estiva-app/ui/base.css';
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/* Firefox */
|
|
18
|
+
* {
|
|
19
|
+
scrollbar-width: thin;
|
|
20
|
+
scrollbar-color: var(--border-strong) transparent;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* Chrome / Safari / Edge */
|
|
24
|
+
::-webkit-scrollbar {
|
|
25
|
+
width: 5px;
|
|
26
|
+
height: 5px;
|
|
27
|
+
}
|
|
28
|
+
::-webkit-scrollbar-track {
|
|
29
|
+
background: transparent;
|
|
30
|
+
}
|
|
31
|
+
::-webkit-scrollbar-thumb {
|
|
32
|
+
background: var(--border-strong);
|
|
33
|
+
border-radius: 9999px;
|
|
34
|
+
}
|
|
35
|
+
::-webkit-scrollbar-thumb:hover {
|
|
36
|
+
background: var(--text-muted);
|
|
37
|
+
}
|
|
38
|
+
::-webkit-scrollbar-button {
|
|
39
|
+
display: none;
|
|
40
|
+
}
|
|
41
|
+
::-webkit-scrollbar-corner {
|
|
42
|
+
background: transparent;
|
|
43
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The frame of an app, in the two manners that pair with the TopBar's
|
|
4
|
+
* (Katerina, 2026-09-02: the two shells go together — the solid bar with
|
|
5
|
+
* the sidebar, the floating bar with the rail):
|
|
6
|
+
*
|
|
7
|
+
* - `solid` — the structured frame: a solid TopBar, the navigation
|
|
8
|
+
* column, the content beside it, sidebar and main scrolling
|
|
9
|
+
* independently (2026-09-02, verbatim from the structured app).
|
|
10
|
+
* - `floating` — the floating frame: the TopBar floats over the top
|
|
11
|
+
* edge, the rail stands on the app background, and the content lives
|
|
12
|
+
* in the rounded card beside it (2026-09-02, the floating app's frame
|
|
13
|
+
* geometry; its collapse animation and launcher stay in the app).
|
|
14
|
+
*
|
|
15
|
+
* The banner belongs to the content area (her ruling, 2026-09-02): it
|
|
16
|
+
* renders at the top of the main column — inside the card, in the
|
|
17
|
+
* floating manner — never across the navigation.
|
|
18
|
+
*
|
|
19
|
+
* Layout only. What goes in each region is the caller's; this component
|
|
20
|
+
* has no data and no routes.
|
|
21
|
+
*/
|
|
22
|
+
export interface AppShellProps {
|
|
23
|
+
variant?: 'solid' | 'floating';
|
|
24
|
+
/** The top bar's menu button, in an app whose navigation collapses. */
|
|
25
|
+
menu?: ReactNode;
|
|
26
|
+
/** The top bar's left: the app's logo mark, or its name as text. */
|
|
27
|
+
logo?: ReactNode;
|
|
28
|
+
/** The top bar's centre — a search field, when there is one. */
|
|
29
|
+
search?: ReactNode;
|
|
30
|
+
/** The top bar's right cluster — an `IdentityMenu`. */
|
|
31
|
+
identity?: ReactNode;
|
|
32
|
+
/** A `Banner`, or nothing — drawn at the top of the content area. */
|
|
33
|
+
banner?: ReactNode;
|
|
34
|
+
/** The navigation: a `Sidebar` in the solid manner, a `Rail` in the floating one. */
|
|
35
|
+
nav: ReactNode;
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
}
|
|
38
|
+
export declare function AppShell({ variant, menu, logo, search, identity, banner, nav, children }: AppShellProps): import("react").JSX.Element;
|
|
39
|
+
//# sourceMappingURL=AppShell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppShell.d.ts","sourceRoot":"","sources":["../src/AppShell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,OAAO,GAAG,UAAU,CAAA;IAC9B,uEAAuE;IACvE,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,oEAAoE;IACpE,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,gEAAgE;IAChE,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,qEAAqE;IACrE,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,qFAAqF;IACrF,GAAG,EAAE,SAAS,CAAA;IACd,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,QAAQ,CAAC,EAAE,OAAiB,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,aAAa,+BAmCjH"}
|
package/dist/Avatar.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export declare const hueFor: (key: string) => string;
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Peek's rule, sharpened: the first letter of the first two words — counting
|
|
4
|
+
* only words that begin with a letter or digit, so "Claude (steered by
|
|
5
|
+
* Katerina Kelepouri)" shows "C", never "C(" (Katerina, 2026-09-01: a name
|
|
6
|
+
* carrying such symbols gets a single letter rather than one of them).
|
|
7
|
+
*/
|
|
3
8
|
export declare const initialsFor: (name: string) => string;
|
|
4
9
|
export interface AvatarProps {
|
|
5
10
|
/** The picture URL, resolved by the caller. A picture that fails to load falls back to the initials. */
|
|
@@ -8,7 +13,7 @@ export interface AvatarProps {
|
|
|
8
13
|
name?: string;
|
|
9
14
|
/** Alt text for the picture; the name when absent. Also the initials' source when there is no name. */
|
|
10
15
|
alt?: string;
|
|
11
|
-
/** Pixels.
|
|
16
|
+
/** Pixels. The scale: 16 · 24 · 32 · 36 (default). */
|
|
12
17
|
size?: number;
|
|
13
18
|
className?: string;
|
|
14
19
|
}
|
package/dist/Avatar.d.ts.map
CHANGED
|
@@ -1 +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
|
|
1
|
+
{"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../src/Avatar.tsx"],"names":[],"mappings":"AA2BA,eAAO,MAAM,MAAM,GAAI,KAAK,MAAM,WAIjC,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,WAIvC,CAAA;AAED,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,sDAAsD;IACtD,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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Up to three overlapping 24px faces with a `bg-surface` ring — Peek's member
|
|
3
|
+
* stack (2026-09-01), with one generalisation on the way in: a member is a
|
|
4
|
+
* name plus an optional picture URL, resolved by the caller, exactly as
|
|
5
|
+
* Avatar takes its `src`. Peek's version took bare names because its Avatar
|
|
6
|
+
* wrapper resolves pictures itself; a consumer without such a wrapper could
|
|
7
|
+
* never have shown one.
|
|
8
|
+
*
|
|
9
|
+
* The ring sits on the Avatar itself: the old extra wrapper was a 24px
|
|
10
|
+
* window minus a 2px border with a fixed 24px Avatar inside, so
|
|
11
|
+
* overflow-hidden clipped 4px of face — and the right edge of the initials
|
|
12
|
+
* with it, which is how "CO" rendered as "C(". One box, whole letters.
|
|
13
|
+
*/
|
|
14
|
+
export interface AvatarGroupMember {
|
|
15
|
+
name: string;
|
|
16
|
+
/** Resolved by the caller. Absent draws the initials. */
|
|
17
|
+
picture?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface AvatarGroupProps {
|
|
20
|
+
members: AvatarGroupMember[];
|
|
21
|
+
}
|
|
22
|
+
export declare function AvatarGroup({ members }: AvatarGroupProps): import("react").JSX.Element;
|
|
23
|
+
//# sourceMappingURL=AvatarGroup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AvatarGroup.d.ts","sourceRoot":"","sources":["../src/AvatarGroup.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,iBAAiB,EAAE,CAAA;CAC7B;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,gBAAgB,+BAgBxD"}
|
package/dist/Banner.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The strip under the header where the app says something happened —
|
|
3
|
+
* one line, gone when there is nothing to say (Ship's Banner,
|
|
4
|
+
* 2026-09-02, verbatim; `info` and `warning` added on extraction,
|
|
5
|
+
* Katerina's ruling — the semantic set is four everywhere else).
|
|
6
|
+
*
|
|
7
|
+
* body-2, her ruling (2026-09-01): the caption this once claimed never
|
|
8
|
+
* rendered, so 14px is what it has always been and what she kept.
|
|
9
|
+
* An `error` announces itself (`role="alert"`); the other tones are
|
|
10
|
+
* polite (`role="status"`).
|
|
11
|
+
*/
|
|
12
|
+
export type BannerTone = 'ok' | 'error' | 'info' | 'warning';
|
|
13
|
+
export interface BannerProps {
|
|
14
|
+
tone: BannerTone;
|
|
15
|
+
children: string;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function Banner({ tone, children, className }: BannerProps): import("react").JSX.Element;
|
|
19
|
+
//# sourceMappingURL=Banner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Banner.d.ts","sourceRoot":"","sources":["../src/Banner.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;AAE5D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AASD,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,WAAW,+BAMhE"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A trail: "Documents / Quarterly plan / DOC-12". Ship's Breadcrumb
|
|
3
|
+
* (2026-09-01), which knows nothing about what the places are.
|
|
4
|
+
*
|
|
5
|
+
* An item with an `href` is a link, even when it is last — a page may end its
|
|
6
|
+
* trail on somewhere to go. The last item is where you are when it has none,
|
|
7
|
+
* and may be `mono` (a ref, an id) or plain. The separator is a slash, muted,
|
|
8
|
+
* never read aloud.
|
|
9
|
+
*
|
|
10
|
+
* A crumb that truncates shows its whole label in a tooltip on hover
|
|
11
|
+
* (Katerina, 2026-09-01); one that fits shows nothing extra. Truncation is
|
|
12
|
+
* re-measured when the trail resizes, so the tooltip appears and disappears
|
|
13
|
+
* with the room the trail actually has.
|
|
14
|
+
*/
|
|
15
|
+
export interface Crumb {
|
|
16
|
+
label: string;
|
|
17
|
+
href?: string;
|
|
18
|
+
/** Set the item in the mono face — a ref, an id. */
|
|
19
|
+
mono?: boolean;
|
|
20
|
+
/** Quieter — a label that is not a place. */
|
|
21
|
+
muted?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface BreadcrumbProps {
|
|
24
|
+
items: Crumb[];
|
|
25
|
+
className?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function Breadcrumb({ items, className }: BreadcrumbProps): import("react").JSX.Element;
|
|
28
|
+
//# sourceMappingURL=Breadcrumb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Breadcrumb.d.ts","sourceRoot":"","sources":["../src/Breadcrumb.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,oDAAoD;IACpD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,6CAA6C;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,EAAE,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,eAAe,+BAyE/D"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A 16px square that fills with the accent when checked — Peek's Checkbox
|
|
3
|
+
* (2026-09-01), verbatim.
|
|
4
|
+
*
|
|
5
|
+
* Controlled only; parents own the state. Rendered as a button with the
|
|
6
|
+
* checkbox role so it works standalone or inside clickable rows: a caller
|
|
7
|
+
* that toggles on the row's own click passes no `onChange`, and the square
|
|
8
|
+
* goes inert rather than stealing the click.
|
|
9
|
+
*/
|
|
10
|
+
export interface CheckboxProps {
|
|
11
|
+
checked: boolean;
|
|
12
|
+
onChange?: (checked: boolean) => void;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
'aria-label'?: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function Checkbox({ checked, onChange, disabled, className, ...aria }: CheckboxProps): import("react").JSX.Element;
|
|
18
|
+
//# sourceMappingURL=Checkbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Checkbox.d.ts","sourceRoot":"","sources":["../src/Checkbox.tsx"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,QAAQ,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAgB,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,aAAa,+BAyBlG"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The chip a `ChipInput` is made of: a 24px pill with an optional 16px
|
|
4
|
+
* leading (a face, an icon), a 12px label, and the ✕ that removes it.
|
|
5
|
+
* Exported on its own (Katerina, 2026-09-01) under a name that promises
|
|
6
|
+
* nothing about people — a chip like this may one day hold a label, a file,
|
|
7
|
+
* a filter.
|
|
8
|
+
*/
|
|
9
|
+
export interface InputChipProps {
|
|
10
|
+
label: string;
|
|
11
|
+
/** Before the label, 16px — an Avatar, an icon. */
|
|
12
|
+
leading?: ReactNode;
|
|
13
|
+
/** Draws the ✕; absent, the chip is display-only. */
|
|
14
|
+
onRemove?: () => void;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function InputChip({ label, leading, onRemove, className }: InputChipProps): import("react").JSX.Element;
|
|
18
|
+
/**
|
|
19
|
+
* A multi-select input: chips for the chosen, a typeahead for the rest —
|
|
20
|
+
* Peek's PersonChipInput (2026-09-01), generalised on the way in. Peek's
|
|
21
|
+
* version knew it was picking people: it read the directory from Peek's own
|
|
22
|
+
* data layer and drew every face itself. Here the caller hands in `options`,
|
|
23
|
+
* and — when the entries have faces or icons — the two leading slots: 16px
|
|
24
|
+
* in a chip, 32px in a suggestion row. Nothing in this file knows what is
|
|
25
|
+
* being picked.
|
|
26
|
+
*
|
|
27
|
+
* Suggestions appear only once the user types — focusing (or auto-focus on
|
|
28
|
+
* dialog open) must not drop the full directory over the surface below.
|
|
29
|
+
* Backspace on an empty query removes the last chip; Escape clears the query
|
|
30
|
+
* when there is one and bubbles when there is not, so the surface around it
|
|
31
|
+
* (dialog, launcher) can act.
|
|
32
|
+
*
|
|
33
|
+
* Generic over the option type: the objects handed back through `onChange`
|
|
34
|
+
* are the caller's own, extra fields and all — no re-mapping on the way out.
|
|
35
|
+
*/
|
|
36
|
+
export interface ChipInputOption {
|
|
37
|
+
id: string;
|
|
38
|
+
label: string;
|
|
39
|
+
/** The suggestion row's second line — a role, an address. Also searched. */
|
|
40
|
+
description?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface ChipInputProps<T extends ChipInputOption = ChipInputOption> {
|
|
43
|
+
value: T[];
|
|
44
|
+
onChange: (next: T[]) => void;
|
|
45
|
+
/** The directory the typeahead searches. */
|
|
46
|
+
options: T[];
|
|
47
|
+
placeholder?: string;
|
|
48
|
+
autoFocus?: boolean;
|
|
49
|
+
/** Option ids excluded from the suggestion list (e.g., the current user). */
|
|
50
|
+
excludeIds?: string[];
|
|
51
|
+
/** Before a chip's label, 16px — a face, an icon. */
|
|
52
|
+
chipLeading?: (option: T) => ReactNode;
|
|
53
|
+
/** Before a suggestion row's label, 32px. */
|
|
54
|
+
rowLeading?: (option: T) => ReactNode;
|
|
55
|
+
}
|
|
56
|
+
export declare function ChipInput<T extends ChipInputOption = ChipInputOption>({ value, onChange, options, placeholder, autoFocus, excludeIds, chipLeading, rowLeading, }: ChipInputProps<T>): import("react").JSX.Element;
|
|
57
|
+
//# sourceMappingURL=ChipInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChipInput.d.ts","sourceRoot":"","sources":["../src/ChipInput.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6E,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAMjH;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,mDAAmD;IACnD,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,cAAc,+BAiChF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe;IACzE,KAAK,EAAE,CAAC,EAAE,CAAA;IACV,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,IAAI,CAAA;IAC7B,4CAA4C;IAC5C,OAAO,EAAE,CAAC,EAAE,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,qDAAqD;IACrD,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,SAAS,CAAA;IACtC,6CAA6C;IAC7C,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,SAAS,CAAA;CACtC;AAED,wBAAgB,SAAS,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe,EAAE,EACrE,KAAK,EACL,QAAQ,EACR,OAAO,EACP,WAAuB,EACvB,SAAS,EACT,UAAe,EACf,WAAW,EACX,UAAU,GACX,EAAE,cAAc,CAAC,CAAC,CAAC,+BA4InB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* A question with two answers, before something a person would want back —
|
|
4
|
+
* Ship's ConfirmDialog (2026-09-01), verbatim. Its own comment always called
|
|
5
|
+
* it a package candidate: nothing here knows what is being confirmed.
|
|
6
|
+
*
|
|
7
|
+
* The confirm button is `destructive` when the action is (a deletion, an
|
|
8
|
+
* archive); `primary` otherwise. While the action runs the buttons wait;
|
|
9
|
+
* an action that resolves `false` keeps the dialog open, so the caller's
|
|
10
|
+
* banner can say why.
|
|
11
|
+
*/
|
|
12
|
+
export interface ConfirmDialogProps {
|
|
13
|
+
title: string;
|
|
14
|
+
/** The body — plain sentences, body-2. */
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
confirmLabel: string;
|
|
17
|
+
destructive?: boolean;
|
|
18
|
+
onConfirm: () => Promise<boolean | void> | boolean | void;
|
|
19
|
+
onClose: () => void;
|
|
20
|
+
}
|
|
21
|
+
export declare function ConfirmDialog({ title, children, confirmLabel, destructive, onConfirm, onClose }: ConfirmDialogProps): import("react").JSX.Element;
|
|
22
|
+
//# sourceMappingURL=ConfirmDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfirmDialog.d.ts","sourceRoot":"","sources":["../src/ConfirmDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAIhD;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,QAAQ,EAAE,SAAS,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,MAAM,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,OAAO,GAAG,IAAI,CAAA;IACzD,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAmB,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,kBAAkB,+BA8B3H"}
|
package/dist/DialogShell.d.ts
CHANGED
|
@@ -7,13 +7,20 @@ import { type ReactNode } from 'react';
|
|
|
7
7
|
* says what it is to assistive tech.
|
|
8
8
|
*/
|
|
9
9
|
export interface DialogShellProps {
|
|
10
|
+
/** Labels the dialog for assistive tech, and renders as the header text
|
|
11
|
+
* unless `headerContent` replaces it. */
|
|
10
12
|
title: string;
|
|
11
13
|
onClose: () => void;
|
|
12
|
-
|
|
14
|
+
/** Replaces the title text in the header — a back button beside the title,
|
|
15
|
+
* a count chip after it. The close button stays. */
|
|
16
|
+
headerContent?: ReactNode;
|
|
17
|
+
/** Absent: no footer row, and the body keeps the card's own bottom edge
|
|
18
|
+
* (a roster that simply ends). */
|
|
19
|
+
footer?: ReactNode;
|
|
13
20
|
children: ReactNode;
|
|
14
21
|
/** Extra classes on the body (e.g. `flex flex-col gap-6`, or a max height with `overflow-y-auto`). */
|
|
15
22
|
bodyClassName?: string;
|
|
16
23
|
width?: number;
|
|
17
24
|
}
|
|
18
|
-
export declare function DialogShell({ title, onClose, footer, children, bodyClassName, width }: DialogShellProps): import("react").ReactPortal;
|
|
25
|
+
export declare function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, width }: DialogShellProps): import("react").ReactPortal;
|
|
19
26
|
//# sourceMappingURL=DialogShell.d.ts.map
|
|
@@ -1 +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;
|
|
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;8CAC0C;IAC1C,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB;yDACqD;IACrD,aAAa,CAAC,EAAE,SAAS,CAAA;IACzB;uCACmC;IACnC,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,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,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAW,EAAE,EAAE,gBAAgB,+BAyC5H"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Text you click to edit — Ship's EditableText (2026-09-01), verbatim. Its
|
|
4
|
+
* own comment always called it a package candidate: nothing here knows what
|
|
5
|
+
* is being edited.
|
|
6
|
+
*
|
|
7
|
+
* Reads as text until clicked; then it is a field. Enter commits (Shift+Enter
|
|
8
|
+
* is a new line when multiline), Escape cancels, blur commits. A commit that
|
|
9
|
+
* fails keeps the field open with the text in it, so an edit is never
|
|
10
|
+
* silently lost — the caller has already said why. An unchanged value is not
|
|
11
|
+
* committed at all. Empty shows the placeholder, muted.
|
|
12
|
+
*/
|
|
13
|
+
export interface EditableTextProps {
|
|
14
|
+
value: string;
|
|
15
|
+
placeholder: string;
|
|
16
|
+
/** Resolve `true` when saved; `false` (or throw) keeps the field open with the text. */
|
|
17
|
+
onCommit: (value: string) => Promise<boolean> | boolean;
|
|
18
|
+
multiline?: boolean;
|
|
19
|
+
/** Applied to both the text and the field, so they are the same size. */
|
|
20
|
+
className?: string;
|
|
21
|
+
/** The accessible name of the field — "Title", "Description". */
|
|
22
|
+
label: string;
|
|
23
|
+
/**
|
|
24
|
+
* What to *show* when not editing, when that differs from what is edited —
|
|
25
|
+
* a value carrying a raw reference that the caller renders as a live object
|
|
26
|
+
* below the text, say.
|
|
27
|
+
*
|
|
28
|
+
* It overrides the display branch only. `value` is still what the editor
|
|
29
|
+
* opens with and what a commit compares against, so nothing is silently lost
|
|
30
|
+
* — which is the failure a naive `value={stripped}` would cause.
|
|
31
|
+
*/
|
|
32
|
+
display?: string;
|
|
33
|
+
/**
|
|
34
|
+
* What to *draw* when not editing, when the value is structured rather than
|
|
35
|
+
* a line of prose.
|
|
36
|
+
*
|
|
37
|
+
* A node, not a string, because a heading and a bullet are elements. Added
|
|
38
|
+
* for a rich text field (SPEC §13): the app renders the parsed body and
|
|
39
|
+
* hands the result in.
|
|
40
|
+
*
|
|
41
|
+
* `display` stays the **string**, and stays what decides emptiness — so a
|
|
42
|
+
* blank field still shows its placeholder rather than an empty element. Like
|
|
43
|
+
* `display`, this overrides the display branch only: `value` is what the
|
|
44
|
+
* editor opens with and what a commit compares against, so what is edited is
|
|
45
|
+
* unchanged.
|
|
46
|
+
*
|
|
47
|
+
* `whitespace-pre-wrap` is dropped when this is set. Structured content
|
|
48
|
+
* carries its own line breaks, and preserving the source's as well doubles
|
|
49
|
+
* every one of them.
|
|
50
|
+
*/
|
|
51
|
+
displayNode?: ReactNode;
|
|
52
|
+
/** Show the value only — no edit affordance. For a reader who cannot write. */
|
|
53
|
+
readOnly?: boolean;
|
|
54
|
+
}
|
|
55
|
+
export declare function EditableText({ value, display, displayNode, placeholder, onCommit, multiline, className, label, readOnly }: EditableTextProps): import("react").JSX.Element;
|
|
56
|
+
//# sourceMappingURL=EditableText.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditableText.d.ts","sourceRoot":"","sources":["../src/EditableText.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAmD,KAAK,SAAS,EAAkB,MAAM,OAAO,CAAA;AAGvG;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,wFAAwF;IACxF,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;IACvD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAA;IACb;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;;;;;;;;;;;;;OAiBG;IACH,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAiB,EAAE,SAAS,EAAE,KAAK,EAAE,QAAgB,EAAE,EAAE,iBAAiB,+BA+G5J"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Who you are, and where you are — the top bar's identity trigger and the
|
|
4
|
+
* menu it opens. Ship's IdentityMenu (2026-09-01), moved in whole: every app
|
|
5
|
+
* needs one, and this one is already made of nothing but shared parts.
|
|
6
|
+
*
|
|
7
|
+
* The trigger is a face and a name, never a key (Ship's ruling A4) — or, with
|
|
8
|
+
* `compact`, the face alone, as Peek's top bar draws it. Anonymous is a
|
|
9
|
+
* silhouette and the word "Anonymous": the truth of the situation rather than
|
|
10
|
+
* eight hex characters posing as a name.
|
|
11
|
+
*
|
|
12
|
+
* The menu keeps the two honest sentences, and the workspace line names the
|
|
13
|
+
* relay because on this substrate the relay *is* the workspace. Every section
|
|
14
|
+
* hides when the app cannot fill it: no `relayUrl`, no workspace section; no
|
|
15
|
+
* `onCopyKey`, no copy item — only offer actions that can succeed. The one
|
|
16
|
+
* place a key appears is as the *result* of "Copy public key" — this
|
|
17
|
+
* component never receives the key, so it cannot show one; the caller
|
|
18
|
+
* copies. Items are text only, no icons (her ruling).
|
|
19
|
+
*/
|
|
20
|
+
export interface Identity {
|
|
21
|
+
/** From `kind:0`. Absent means anonymous. */
|
|
22
|
+
name?: string;
|
|
23
|
+
picture?: string;
|
|
24
|
+
/** Known to Estiva ID, never published to the relay. */
|
|
25
|
+
email?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface IdentityMenuProps {
|
|
28
|
+
me: Identity;
|
|
29
|
+
/** Signed in through Estiva ID, as opposed to a browser-held key. */
|
|
30
|
+
signedIn: boolean;
|
|
31
|
+
/** Names the workspace; absent hides the workspace section. */
|
|
32
|
+
relayUrl?: string;
|
|
33
|
+
/** Estiva ID's base URL when this build offers sign-in; absent = anonymous-only build. */
|
|
34
|
+
idBase?: string;
|
|
35
|
+
/** "Copy public key" appears only when the app can supply one. */
|
|
36
|
+
onCopyKey?: () => void;
|
|
37
|
+
onSignOut?: () => void;
|
|
38
|
+
/** Face-only trigger, 36px — no chevron, no name beside it. */
|
|
39
|
+
compact?: boolean;
|
|
40
|
+
className?: string;
|
|
41
|
+
/**
|
|
42
|
+
* App-specific rows, drawn as their own group between the workspace
|
|
43
|
+
* section and the actions. A function receives `close`, so a row can
|
|
44
|
+
* shut the menu before opening what it opens.
|
|
45
|
+
*/
|
|
46
|
+
children?: ReactNode | ((close: () => void) => ReactNode);
|
|
47
|
+
}
|
|
48
|
+
export interface IdentityPanelProps extends Omit<IdentityMenuProps, 'compact' | 'className'> {
|
|
49
|
+
onClose: () => void;
|
|
50
|
+
/** On the Menu surface — the stories pass `static` to stand it in flow. */
|
|
51
|
+
className?: string;
|
|
52
|
+
}
|
|
53
|
+
/** The menu alone — what `IdentityMenu` opens. Exported so the stories show
|
|
54
|
+
* the designed artifact rather than a closed trigger, and for any surface
|
|
55
|
+
* that wants the panel without the trigger. */
|
|
56
|
+
export declare function IdentityPanel({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, onClose, className, children }: IdentityPanelProps): import("react").JSX.Element;
|
|
57
|
+
export declare function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, compact, className, children }: IdentityMenuProps): import("react").JSX.Element;
|
|
58
|
+
//# sourceMappingURL=IdentityMenu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IdentityMenu.d.ts","sourceRoot":"","sources":["../src/IdentityMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAOhD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,QAAQ;IACvB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,QAAQ,CAAA;IACZ,qEAAqE;IACrE,QAAQ,EAAE,OAAO,CAAA;IACjB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,0FAA0F;IAC1F,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,SAAS,CAAC,CAAA;CAC1D;AAED,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,WAAW,CAAC;IAC1F,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;gDAEgD;AAChD,wBAAgB,aAAa,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAmDvI;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,OAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,iBAAiB,+BAqC7I"}
|
package/dist/Menu.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { type ComponentPropsWithRef, type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* THE menu shell (2026-09-01) — extracted once, for every menu in every app.
|
|
4
|
+
*
|
|
5
|
+
* Peek has no single Menu file; its topic menu, conversation menus, files
|
|
6
|
+
* menu and the top bar's account menu each hand-roll the same thing, and
|
|
7
|
+
* they disagree: some close on Escape, most do not, and row heights and
|
|
8
|
+
* minimum widths drift copy by copy. Ship extracted the shape so it would
|
|
9
|
+
* not become the next copy; the package exists so nobody becomes the one
|
|
10
|
+
* after that.
|
|
11
|
+
*
|
|
12
|
+
* What every menu shares, kept exactly: an elevated container with a
|
|
13
|
+
* hairline border, 8px radius, 8px padding and the large shadow; items that
|
|
14
|
+
* are 8px-radius rows, `px-2 py-1.5`, hover fill, 14px text, destructive
|
|
15
|
+
* ones in the error colour; section headings as a SectionLabel in a 32px
|
|
16
|
+
* row; and the two exits every menu has — Escape and a click outside —
|
|
17
|
+
* owned by the menu, never copied into a caller.
|
|
18
|
+
*
|
|
19
|
+
* Two anchorings: `position` portals it to the body at fixed viewport
|
|
20
|
+
* coordinates (for menus opened inside scrolling containers that clip);
|
|
21
|
+
* without it the menu hangs below its trigger, right-aligned, and the
|
|
22
|
+
* caller's wrapper is `relative`.
|
|
23
|
+
*/
|
|
24
|
+
export interface MenuProps {
|
|
25
|
+
onClose: () => void;
|
|
26
|
+
/** Viewport coordinates; the menu is portalled, hung from `top`, and aligned to whichever edge is given. */
|
|
27
|
+
position?: {
|
|
28
|
+
top: number;
|
|
29
|
+
right: number;
|
|
30
|
+
} | {
|
|
31
|
+
top: number;
|
|
32
|
+
left: number;
|
|
33
|
+
};
|
|
34
|
+
children: ReactNode;
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function Menu({ onClose, position, children, className }: MenuProps): import("react").JSX.Element;
|
|
38
|
+
export interface MenuItemProps extends Omit<ComponentPropsWithRef<'button'>, 'children'> {
|
|
39
|
+
label?: string;
|
|
40
|
+
/** Replaces the label/description block — for rows whose middle is richer
|
|
41
|
+
* than text (the launcher's form rows). Leading/trailing still apply. */
|
|
42
|
+
children?: ReactNode;
|
|
43
|
+
/** `tall` is the picker row — content height with a 40px floor, px-3,
|
|
44
|
+
* gap-3, room for a 32px face or icon tile and the description line.
|
|
45
|
+
* `default` is the command row. */
|
|
46
|
+
size?: 'default' | 'tall';
|
|
47
|
+
/** A second line under the label — a role, an address — 12px, secondary, truncating. */
|
|
48
|
+
description?: string;
|
|
49
|
+
/** Before the label: a 16px icon (stroke 1.5, secondary), or an Avatar, for rows led by a face. */
|
|
50
|
+
leading?: ReactNode;
|
|
51
|
+
/** At the right edge: a hint, a value — anything. Wins over `shortcut` and `submenu`. */
|
|
52
|
+
trailing?: ReactNode;
|
|
53
|
+
/** A keyboard hint, drawn as the kbd chip. */
|
|
54
|
+
shortcut?: string;
|
|
55
|
+
/** The row opens another menu: draws the chevron at the right edge. */
|
|
56
|
+
submenu?: boolean;
|
|
57
|
+
destructive?: boolean;
|
|
58
|
+
/** The row the menu currently points at (a submenu's chosen value). */
|
|
59
|
+
selected?: boolean;
|
|
60
|
+
}
|
|
61
|
+
export declare function MenuItem({ label, children, size, description, leading, trailing, shortcut, submenu, destructive, selected, className, ...props }: MenuItemProps): import("react").JSX.Element;
|
|
62
|
+
/**
|
|
63
|
+
* The keyboard hint a picker row shows while highlighted — "↩ Enter",
|
|
64
|
+
* "↩ #topic" — hand-rolled in five files before this (2026-09-01).
|
|
65
|
+
*/
|
|
66
|
+
export declare function EnterHint({ label }: {
|
|
67
|
+
label?: string;
|
|
68
|
+
}): import("react").JSX.Element;
|
|
69
|
+
/** A section heading inside a menu: the 32px row with a SectionLabel, read
|
|
70
|
+
* secondary — a heading inside a menu labels the rows, it is not one of
|
|
71
|
+
* them (Katerina, 2026-09-01). */
|
|
72
|
+
export declare function MenuSection({ label, children, className }: {
|
|
73
|
+
label: string;
|
|
74
|
+
children: ReactNode; /** On the heading row — a surface whose rows are px-3 aligns its heading with px-3. */
|
|
75
|
+
className?: string;
|
|
76
|
+
}): import("react").JSX.Element;
|
|
77
|
+
/** A non-interactive row inside a menu, at the item's own geometry. */
|
|
78
|
+
export declare function MenuRow({ children, className }: {
|
|
79
|
+
children: ReactNode;
|
|
80
|
+
className?: string;
|
|
81
|
+
}): import("react").JSX.Element;
|
|
82
|
+
//# sourceMappingURL=Menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Menu.d.ts","sourceRoot":"","sources":["../src/Menu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,qBAAqB,EAAsB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAMzG;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,4GAA4G;IAC5G,QAAQ,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACzE,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,SAAS,+BAoCzE;AAED,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;8EAC0E;IAC1E,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB;;wCAEoC;IACpC,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACzB,wFAAwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mGAAmG;IACnG,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,yFAAyF;IACzF,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,uEAAuE;IACvE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAgB,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,aAAa,+BAyC3K;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,EAAE,KAAe,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,+BAOhE;AAED;;mCAEmC;AACnC,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,uFAAuF;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,+BAS7M;AAED,uEAAuE;AACvE,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,+BAE3F"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* One row of a sidebar: a label, an optional count, an active state
|
|
4
|
+
* (Ship's NavItem, 2026-09-02, verbatim).
|
|
5
|
+
*
|
|
6
|
+
* A count is a number of ONE thing, and its tooltip says which ("18
|
|
7
|
+
* open", "5 active") — the caller passes the number and the words for it,
|
|
8
|
+
* and a zero is not drawn at all. That is this row's rule; a *tab's*
|
|
9
|
+
* count draws its zero (see Tabs) — both rulings stand, deliberately.
|
|
10
|
+
*
|
|
11
|
+
* Active is the same fill as a selected tab — `bg-active`, neutral.
|
|
12
|
+
*/
|
|
13
|
+
export interface NavItemProps extends Omit<ComponentPropsWithoutRef<'a'>, 'href'> {
|
|
14
|
+
label: string;
|
|
15
|
+
href: string;
|
|
16
|
+
/** `0` or absent renders no counter. */
|
|
17
|
+
count?: number;
|
|
18
|
+
/** What the count counts, for the tooltip — "18 open", "5 active". */
|
|
19
|
+
countLabel?: string;
|
|
20
|
+
active?: boolean;
|
|
21
|
+
/** 16px, stroke 1.5. */
|
|
22
|
+
icon?: ReactNode;
|
|
23
|
+
className?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function NavItem({ label, href, count, countLabel, active, icon, className, ...props }: NavItemProps): import("react").JSX.Element;
|
|
26
|
+
//# sourceMappingURL=NavItem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NavItem.d.ts","sourceRoot":"","sources":["../src/NavItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAIhE;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAC/E,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,wBAAwB;IACxB,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,MAAc,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,YAAY,+BAwBlH"}
|