wings-plugin-sdk 0.5.0 → 0.7.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/ui.d.ts DELETED
@@ -1,238 +0,0 @@
1
- /// <reference path="./wings.d.ts" />
2
- // wings-plugin-sdk/ui: say what a page shows and where, and Wings decides how it looks. Every component renders
3
- // plain elements with `w-*` class names that Wings' plugin-ui.css styles. Your own components and CSS work too.
4
- import type { ComponentPropsWithoutRef, JSX, ReactElement, ReactNode, Ref } from "react";
5
-
6
- import type { Place, ShellOptions } from "./shell";
7
-
8
- export type { Place, ShellOptions } from "./shell";
9
- export { mountShell } from "./shell";
10
- export { useBroadcast } from "./react";
11
-
12
- // ---------- places ----------
13
-
14
- /** Shows `element`, any React element, as the page of a sidebar. One call per page; calling again renders the new element. */
15
- export function showSidebar(element: ReactElement, options?: ShellOptions): void;
16
- /** Shows `element` as a view's page, in a modal or a window of its own. */
17
- export function showView(element: ReactElement, options?: ShellOptions): void;
18
- /** Shows `element` as a view's page in a tab next to the terminals. */
19
- export function showTab(element: ReactElement, options?: ShellOptions): void;
20
- /** Shows `element` as a sidebar's popover. */
21
- export function showPopover(element: ReactElement, options?: ShellOptions): void;
22
- /** Shows `element` as the plugin's page in Wings Settings. */
23
- export function showSettings(element: ReactElement, options?: ShellOptions): void;
24
-
25
- // ---------- talking to main ----------
26
-
27
- /**
28
- * The newest message of `type` the plugin's other pages broadcast, or null until one comes. Sends `hello`
29
- * (`{ type: "hello" }` by default) once when the component mounts, so main answers with its state; pass null to
30
- * send nothing.
31
- */
32
- export function useMainState<T extends { type: string }>(type: T["type"], hello?: unknown): T | null;
33
-
34
- // ---------- shared ----------
35
-
36
- /** A colour that says something. */
37
- export type Tone = "muted" | "info" | "success" | "warn" | "danger";
38
- type Props<Tag extends keyof JSX.IntrinsicElements> = ComponentPropsWithoutRef<Tag>;
39
- type As = "div" | "span" | "p" | "section" | "header" | "footer" | "strong" | "time" | "label" | "li";
40
- /** The elements `Row` and `Stack` can be. */
41
- type BoxAs = As | "form" | "ul" | "ol";
42
- /** The elements `Card` can be. */
43
- type CardAs = As | "form" | "article" | "ul" | "ol";
44
- /** The props of element `E`, with `own` on top: where they share a name, `own` wins. */
45
- type Own<E extends keyof JSX.IntrinsicElements, own> = Omit<Props<E>, keyof own> & own;
46
- /** Spacing between children: none, xs (2px), s (4px), m (8px, the default) or l (12px), set by Wings. */
47
- export type Gap = "none" | "xs" | "s" | "m" | "l";
48
-
49
- // ---------- layout and text ----------
50
-
51
- /**
52
- * Children side by side, centred. `as` picks the element, like a `form` or a `ul`; the props and handlers are the
53
- * element's, so `<Row as="form" onSubmit={(e) => e.currentTarget.requestSubmit()}>` has a `HTMLFormElement`.
54
- */
55
- export function Row<E extends BoxAs = "div">(props: Own<E, { as?: E; gap?: Gap; align?: "start" | "baseline"; justify?: "end" | "between"; wrap?: boolean; grow?: boolean }>): ReactElement;
56
- /** Children one under the other. As a `ul` or `ol` it's a list with no bullets, of `li` children. `as` types the props like `Row`'s. */
57
- export function Stack<E extends BoxAs = "div">(props: Own<E, { as?: E; gap?: Gap; grow?: boolean }>): ReactElement;
58
- /** Text with a tone and size, that can `grow` to fill a row or `truncate` with an ellipsis. */
59
- export function Text(
60
- props: Props<"span"> & {
61
- as?: As;
62
- tone?: Tone;
63
- /** small is 12px, tiny 11px. */
64
- size?: "small" | "tiny";
65
- weight?: "medium" | "strong";
66
- mono?: boolean;
67
- /** Digits of equal width, for figures that change. */
68
- numeric?: boolean;
69
- /** One line, cut with an ellipsis. */
70
- truncate?: boolean;
71
- /** Up to three lines. */
72
- clamp?: boolean;
73
- grow?: boolean;
74
- },
75
- ): ReactElement;
76
- /** A section heading, an `h2`, with `actions` like chips or a button on its right. */
77
- export function Heading(props: Props<"h2"> & { level?: 2 | 3 | 4; actions?: ReactNode }): ReactElement;
78
- /** A page's or a card's title, like a sprint's name or a setup step's question: an `h1` unless `as` says otherwise. */
79
- /** `truncate` cuts a title that's too long for its place to one line, with an ellipsis. */
80
- export function Title(props: Props<"h1"> & { as?: "h1" | "h2" | "h3"; size?: "large"; truncate?: boolean }): ReactElement;
81
- /** A card. `compact` for a summary line. As a `form` it holds a form; as a `ul` or `ol`, a list of `li`. `as` types the props like `Row`'s. */
82
- export function Card<E extends CardAs = "div">(props: Own<E, { as?: E; compact?: boolean }>): ReactElement;
83
-
84
- // ---------- figures ----------
85
-
86
- /** A bar from 0 to 100, with the meter role. */
87
- export function Meter(props: Props<"div"> & { percent: number; label: string; tone?: "warn" | "danger" }): ReactElement;
88
- /** A labelled bar with its percentage and a `note` under it. `levels` are where it turns warn and danger, like `[75, 90]`. */
89
- export function Gauge(props: Props<"div"> & { label: string; percent: number; note?: ReactNode; tone?: "warn" | "danger"; levels?: [number, number] }): ReactElement;
90
- export interface Stat {
91
- label: string;
92
- value: ReactNode;
93
- tone?: "warn" | "danger";
94
- title?: string;
95
- }
96
- /** Small figures side by side, label over value. */
97
- export function Stats(props: Props<"dl"> & { items: Stat[] }): ReactElement;
98
- /** Label and value pairs, one per line. */
99
- export function Properties(props: Props<"dl"> & { items: { label: string; value: ReactNode }[] }): ReactElement;
100
-
101
- // ---------- lists ----------
102
-
103
- /** A list of rows: a `ul`, or an `ol` when `ordered`. `compact` rows have no space between them, for long lists. */
104
- export function List(props: Props<"ul"> & { ordered?: boolean; compact?: boolean }): ReactElement;
105
- /** A row in a `List`. Holding a `ListButton`, the button is the row. */
106
- export function ListItem(props: Props<"li"> & { align?: "start" }): ReactElement;
107
- /** A row that's a button, inside a `ListItem`. */
108
- export function ListButton(props: Props<"button"> & { align?: "baseline" }): ReactElement;
109
-
110
- // ---------- status ----------
111
-
112
- /** A status dot, green unless `tone` says otherwise. With a `label` it's announced; otherwise it's decoration. */
113
- export function Dot(
114
- props: Props<"span"> & {
115
- tone?: Exclude<Tone, "success">;
116
- /** A colour from your data, like a work item type's `#cc293d`, set as `--w-color`. Wins over `tone`. */
117
- color?: string;
118
- label?: string;
119
- },
120
- ): ReactElement;
121
- /** A spinner. With a `label` it's announced; otherwise it's decoration. */
122
- export function Spinner(props: Props<"span"> & { size?: "large"; label?: string }): ReactElement;
123
- /** A filled pill, like a label on a command. */
124
- export function Pill(props: Props<"span"> & { tone?: Exclude<Tone, "muted"> }): ReactElement;
125
- /** An outlined tag, like a branch name. */
126
- export function Tag(props: Props<"span"> & { tone?: Exclude<Tone, "muted"> }): ReactElement;
127
- /** What shows before the first data comes: "Loading…" unless `children` say otherwise. */
128
- export function Loading(props: Props<"p">): ReactElement;
129
- /** Nothing to show: what's missing, and a `detail` line on what to do about it. */
130
- export function Empty(props: Omit<Props<"div">, "title"> & { title: ReactNode; detail?: ReactNode }): ReactElement;
131
-
132
- // ---------- buttons ----------
133
-
134
- /**
135
- * A button, `type="button"` unless you say otherwise. `busy` shows a spinner and ignores clicks while it keeps the
136
- * keyboard focus, unlike `disabled`: it's `aria-busy` and `aria-disabled`.
137
- */
138
- export function Button(props: Props<"button"> & { variant?: "primary" | "ghost" | "danger"; size?: "small"; busy?: boolean }): ReactElement;
139
- /** A small quiet button. With `pressed` it's a toggle. */
140
- export function Chip(props: Props<"button"> & { pressed?: boolean }): ReactElement;
141
- export interface Option<V extends string> {
142
- value: V;
143
- label: ReactNode;
144
- title?: string;
145
- }
146
- /** Chips that pick one of `options`, like a filter, in a group named `label`. `onChange` gets each click, the chip that's on too. */
147
- export function Chips<V extends string>(
148
- props: Omit<Props<"div">, "onChange"> & {
149
- label: string;
150
- /** Each chip's other props, like `id`, go to its button. */
151
- options: (Option<V> & Omit<Props<"button">, "value" | "onClick" | "children">)[];
152
- value: V;
153
- onChange: (value: V) => void;
154
- },
155
- ): ReactElement;
156
- /** Tabs named `label` over the panel they show, `children`. Arrow keys, Home and End move between tabs. */
157
- export function Tabs<V extends string>(props: Omit<Props<"div">, "onChange"> & { label: string; items: Option<V>[]; value: V; onChange: (value: V) => void }): ReactElement;
158
-
159
- // ---------- fields ----------
160
-
161
- /** A labelled field with a `hint` or an `error` under it, for the `TextInput`, `SearchField` or `Select` in `children`. */
162
- export function Field(
163
- props: Props<"div"> & {
164
- label: ReactNode;
165
- hint?: ReactNode;
166
- error?: ReactNode;
167
- /** The input's id, and the label's `htmlFor`, for a page that puts focus back by id. Generated otherwise. */
168
- id?: string;
169
- /** The label and the input on one line. */
170
- inline?: boolean;
171
- },
172
- ): ReactElement;
173
- /** Several controls under one label (a `fieldset` and its `legend`), like checkboxes, with a `hint` or an `error` under them. */
174
- export function FieldGroup(props: Props<"fieldset"> & { label: ReactNode; hint?: ReactNode; error?: ReactNode }): ReactElement;
175
- /** A text input. Outside a `Field`, give it a `label`. */
176
- export function TextInput(props: Props<"input"> & { label?: string; ref?: Ref<HTMLInputElement> }): ReactElement;
177
- /** A search box. `label` names it for screen readers. */
178
- export function SearchField(props: Omit<Props<"input">, "type"> & { label?: string; ref?: Ref<HTMLInputElement> }): ReactElement;
179
- /** A select of `options`. `onChange` gets the value picked. */
180
- export function Select<V extends string>(
181
- props: Omit<Props<"select">, "onChange" | "children"> & { label?: string; options: (Option<V> & { label: string; disabled?: boolean })[]; value?: V; onChange?: (value: V) => void },
182
- ): ReactElement;
183
- /** A checkbox with its label, `children`. `onChange` gets whether it's checked. */
184
- export function Checkbox(props: Omit<Props<"input">, "onChange" | "type"> & { onChange?: (checked: boolean) => void }): ReactElement;
185
- export interface ComboboxOption {
186
- value: string;
187
- label: string;
188
- /** A second, quieter part, like a project's client. */
189
- detail?: string;
190
- }
191
- /**
192
- * A text field with `options` under it. Arrows move, Enter picks, Escape and Tab close, and pressing outside
193
- * closes it. With `freeText` the field keeps what you type (`value`, `onInput`) and starts with nothing
194
- * highlighted; otherwise you type to find an option and the field shows `value`, what you picked, once closed.
195
- * `filter` decides what matches what's typed: the label or the detail containing it, by default. Without
196
- * `freeText` the field's text is selected when it gets focus and after a pick, so typing replaces the label. An
197
- * `onKeyDown` you pass runs first; `preventDefault()` in it keeps the Combobox's own keys from running.
198
- */
199
- export function Combobox(
200
- props: Omit<Props<"input">, "value" | "onInput" | "type"> & {
201
- label?: string;
202
- value: string;
203
- onInput?: (text: string) => void;
204
- options: ComboboxOption[];
205
- onPick: (option: ComboboxOption) => void;
206
- /** Enter with no option highlighted, with the text typed. The Enter doesn't submit a form around it. */
207
- onEnter?: (text: string) => void;
208
- freeText?: boolean;
209
- /** Open the list when the field gets focus, by default; false opens it on a click, a key or typing only, for a page that puts focus back by id after it renders. */
210
- openOnFocus?: boolean;
211
- /**
212
- * When the list is shown. `"auto"` (default): on focus, a click, a key or typing, and Escape, Tab, blur to another
213
- * element or a press outside close it. `"whileText"`: the list is shown exactly while the field has text and an
214
- * option matches it, whether or not the field has focus. Escape, Tab and a press outside only clear the highlighted
215
- * option (`aria-activedescendant`); emptying the text or picking closes it, and there's no `empty` message. A
216
- * list left open after the field loses focus is a screen reader caveat, see the README.
217
- */
218
- open?: "auto" | "whileText";
219
- filter?: (option: ComboboxOption, query: string) => boolean;
220
- /** What shows when nothing matches. */
221
- empty?: ReactNode;
222
- },
223
- ): ReactElement;
224
- export interface MenuItem {
225
- id: string;
226
- label: ReactNode;
227
- onSelect: () => void;
228
- tone?: "danger";
229
- }
230
- /**
231
- * A button, showing `label`, that opens a menu of `items` under it. Arrows, Home and End move, Enter or Space
232
- * picks, Escape closes and puts focus back on the button. `align` end lines the menu up with the button's right.
233
- */
234
- export function Menu(
235
- props: Omit<Props<"button">, "children"> & { label: ReactNode; items: MenuItem[]; align?: "end"; variant?: "primary" | "ghost" | "danger"; size?: "small" },
236
- ): ReactElement;
237
- /** More behind a `summary` line that opens it. */
238
- export function Disclosure(props: Props<"details"> & { summary: ReactNode }): ReactElement;