staffa 0.3.1 → 0.4.1

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.
Files changed (44) hide show
  1. package/README.md +45 -23
  2. package/dist/components/box.d.ts +2 -2
  3. package/dist/components/box.js +3 -4
  4. package/dist/components/button.d.ts +9 -11
  5. package/dist/components/button.js +16 -18
  6. package/dist/components/buttonChooser.d.ts +5 -5
  7. package/dist/components/buttonChooser.js +7 -5
  8. package/dist/components/buttonGroup.d.ts +3 -3
  9. package/dist/components/buttonGroup.js +5 -5
  10. package/dist/components/dialog.d.ts +2 -2
  11. package/dist/components/dialog.js +10 -10
  12. package/dist/components/form.d.ts +4 -4
  13. package/dist/components/form.js +6 -6
  14. package/dist/components/main.d.ts +5 -5
  15. package/dist/components/main.js +28 -40
  16. package/dist/components/menu.d.ts +4 -4
  17. package/dist/components/menu.js +8 -6
  18. package/dist/components/tabs.d.ts +3 -3
  19. package/dist/components/tabs.js +1 -1
  20. package/dist/components/toast.d.ts +1 -3
  21. package/dist/components/toast.js +2 -2
  22. package/dist/components/tooltip.js +2 -2
  23. package/dist/core.d.ts +10 -4
  24. package/dist/core.js +13 -0
  25. package/dist/index.d.ts +19 -65
  26. package/dist/index.js +18 -48
  27. package/dist/staffa.esm.js +1 -1
  28. package/dist/theme.d.ts +0 -7
  29. package/dist/theme.js +37 -14
  30. package/package.json +9 -2
  31. package/src/components/box.ts +5 -5
  32. package/src/components/button.ts +21 -22
  33. package/src/components/buttonChooser.ts +10 -8
  34. package/src/components/buttonGroup.ts +5 -4
  35. package/src/components/dialog.ts +10 -10
  36. package/src/components/form.ts +8 -8
  37. package/src/components/main.ts +31 -40
  38. package/src/components/menu.ts +9 -7
  39. package/src/components/tabs.ts +4 -4
  40. package/src/components/toast.ts +3 -5
  41. package/src/components/tooltip.ts +2 -2
  42. package/src/core.ts +16 -5
  43. package/src/index.ts +21 -76
  44. package/src/theme.ts +36 -22
@@ -15,8 +15,9 @@ A.insertGlobalCss({
15
15
  "> header .s-title": "font-weight:800 font-size:1.1em line-height:1.2 overflow:hidden text-overflow:ellipsis white-space:nowrap letter-spacing:-0.01em background: $s-gradient; -webkit-background-clip:text; background-clip:text; color:transparent; width:fit-content max-width:100%",
16
16
  "> header .s-subtitle": "fg:$s-fg-muted font-size:0.85em overflow:hidden text-overflow:ellipsis white-space:nowrap",
17
17
  "> header .s-menu": "display:flex align-items:center gap:$2",
18
- // Body holds sidebar + separator + <main> side by side (only used in sidebar
19
- // nav mode). It centres `.s-body-inner`, which caps the trio to maxWidth.
18
+ // Body always wraps <main> (with or without a sidebar) so max-width centering
19
+ // and scrollbar alignment work identically in both cases.
20
+ // .s-body centres .s-body-inner; .s-body-inner caps the content to maxWidth.
20
21
  ".s-body": "flex:1 overflow:hidden display:flex flex-direction:row min-height:0 justify-content:center",
21
22
  ".s-body-inner": "flex:1 display:flex flex-direction:row min-height:0",
22
23
  // Put the sidebar on the right (content fills the left) for right-hand navs.
@@ -24,20 +25,19 @@ A.insertGlobalCss({
24
25
  // A vertical hairline between sidebar and content, fading out at both ends —
25
26
  // the vertical sibling of the menu's `hr.s-menu-sep`.
26
27
  ".s-nav-sep": "width:1px flex-shrink:0 align-self:stretch margin: 0.6rem 0; border:0 background: linear-gradient(to bottom, transparent, $s-border-strong 18%, $s-border-strong 82%, transparent);",
27
- // Without a sidebar, <main> is a direct child; with one it lives in .s-body.
28
- "> main, .s-body main": "flex:1 overflow-y:auto display:flex flex-direction:column",
29
- // The content area fills the scroll region with comfortable padding. Without a
30
- // sidebar it caps its own width to maxWidth and centres (applied inline in
31
- // drawMainContent); with one, `.s-body-inner` does the capping for the trio.
28
+ // min-height:0 overrides the flex default of min-height:auto so <main> can
29
+ // shrink to fit the bounded container and show its own scrollbar.
30
+ ".s-body main": "flex:1 min-height:0 overflow-y:auto display:flex flex-direction:column",
31
+ // The content area fills the scroll region with comfortable padding.
32
32
  // It is deliberately NOT a boxed "sheet" — content brings its own boxes.
33
- "> main > .s-content, .s-body main > .s-content": "width:100% flex:1 p:$3",
33
+ ".s-body main > .s-content": "width:100% flex:1 p:$3",
34
34
  // When <main> actually shows a vertical scrollbar (the `.s-scroll-y` class is
35
35
  // toggled from JS by watchVerticalOverflow), inset it from the shell edge by
36
36
  // $3 so the bar's right edge lines up with the header/footer content (which
37
37
  // sits $3 inside the edge via `.s-bar` padding). The $3 gap between the content
38
38
  // and the bar already comes from `.s-content`'s padding. Without a scrollbar
39
39
  // there's no margin, so the content keeps its single $3 edge — not 2×$3.
40
- "> main.s-scroll-y, .s-body main.s-scroll-y": "margin-right:$3",
40
+ ".s-body main.s-scroll-y": "margin-right:$3",
41
41
  },
42
42
  // Sidebar nav panel. Items reuse the shared `.s-menu-item[-link]` /
43
43
  // `.s-menu-sep` styles from menu.ts, so the sidebar and the floating
@@ -63,6 +63,9 @@ A.insertGlobalCss({
63
63
  // On phones a top-level content box becomes a full-bleed block: pull it out
64
64
  // to negate the content padding and drop the rounded corners.
65
65
  ".s-content > .s-box": "margin-inline: calc(-1 * $3); r:0 border-inline:0",
66
+ // At narrow widths, content boxes are full-bleed so there's no inset to
67
+ // align the scrollbar with — cancel the right margin.
68
+ ".s-main .s-body main.s-scroll-y": "margin-right:0",
66
69
  },
67
70
  });
68
71
  /**
@@ -85,7 +88,7 @@ A.insertGlobalCss({
85
88
  * ],
86
89
  * },
87
90
  * navPosition: "left",
88
- * menu: () => S.button({ text: "New", attrs: ".small" }),
91
+ * menu: () => S.button({ content: "New", attrs: ".small" }),
89
92
  * content: () => drawPage(),
90
93
  * footer: "© 2026",
91
94
  * });
@@ -146,31 +149,28 @@ export function main(opts = {}) {
146
149
  });
147
150
  A(() => {
148
151
  if (opts.menu)
149
- A("div.s-menu", () => opts.menu?.());
152
+ A("div.s-menu", () => drawSlot(opts.menu));
150
153
  });
151
154
  });
152
155
  });
153
156
  });
154
- // Body wraps sidebar + separator + main when nav is in sidebar mode. The
155
- // trio together caps to maxWidth (via .s-body-inner); main fills the rest.
156
- if (hasNav && navPos !== "button") {
157
- A("div.s-body", () => {
158
- A("div.s-body-inner", () => {
159
- A(() => {
160
- if (opts.maxWidth != null)
161
- A("max-width:", opts.maxWidth);
162
- });
157
+ // Body always wraps <main> so max-width centering and scrollbar alignment
158
+ // are identical with and without a sidebar nav.
159
+ A("div.s-body", () => {
160
+ A("div.s-body-inner", () => {
161
+ A(() => {
162
+ if (opts.maxWidth != null)
163
+ A("max-width:", opts.maxWidth);
164
+ });
165
+ if (hasNav && navPos !== "button") {
163
166
  A(`nav.s-nav-panel.s-s.raised.s-nav-${navPos}`, opts.navAttrs, () => {
164
167
  drawMenu(nav.items);
165
168
  });
166
169
  A("div.s-nav-sep aria-hidden=true");
167
- drawMainContent(opts, false);
168
- });
170
+ }
171
+ drawMainContent(opts);
169
172
  });
170
- }
171
- else {
172
- drawMainContent(opts, true);
173
- }
173
+ });
174
174
  // Footer — full-width background, content centred to maxWidth via .s-bar.
175
175
  A(() => {
176
176
  if (opts.footer != null) {
@@ -187,22 +187,10 @@ export function main(opts = {}) {
187
187
  });
188
188
  });
189
189
  }
190
- /**
191
- * Draw the scrollable `<main>` + content area. When `capWidth` is true (no
192
- * sidebar), the content caps its own width to maxWidth and centres; in sidebar
193
- * mode the surrounding `.s-body-inner` already caps the sidebar+content trio.
194
- */
195
- function drawMainContent(opts, capWidth) {
190
+ function drawMainContent(opts) {
196
191
  const mainEl = A("main", () => {
197
192
  A("div.s-content", opts.contentAttrs, () => {
198
- if (capWidth) {
199
- A(() => {
200
- if (opts.maxWidth != null)
201
- A("margin-inline:auto max-width:", opts.maxWidth);
202
- });
203
- }
204
- if (opts.content)
205
- opts.content();
193
+ drawSlot(opts.content);
206
194
  });
207
195
  });
208
196
  watchVerticalOverflow(mainEl);
@@ -1,4 +1,4 @@
1
- import { type Content, type Slot, type Attributes } from "../core.js";
1
+ import { type Slot, type Attributes } from "../core.js";
2
2
  import { type ButtonOptions } from "./button.js";
3
3
  /**
4
4
  * A clickable item in a menu or sidebar nav.
@@ -36,10 +36,10 @@ export interface MenuSeparator {
36
36
  * An entry in a menu or sidebar nav list. Three forms:
37
37
  * - `MenuItem` — a clickable/linkable row with label and optional icon.
38
38
  * - `MenuSeparator` — a visual divider (`{ separator: true }`).
39
- * - A draw function `() => void` — renders custom content (section header,
39
+ * - A slot (string or draw function) — renders custom content (section header,
40
40
  * avatar, search box, …). Skipped by keyboard navigation.
41
41
  */
42
- export type MenuEntry = MenuItem | MenuSeparator | Content;
42
+ export type MenuEntry = MenuItem | MenuSeparator | Slot;
43
43
  /** Options for {@link menuButton} and {@link MainOptions.nav}. */
44
44
  export interface MenuOptions {
45
45
  /** Items shown in the dropdown or sidebar nav. */
@@ -106,7 +106,7 @@ export declare function showFloatingMenu(opts: FloatingMenuOptions): () => void;
106
106
  * @example
107
107
  * ```ts
108
108
  * S.menuButton({
109
- * button: { text: "Actions", attrs: ".neutral .outlined" },
109
+ * button: { content: "Actions", attrs: ".neutral .outlined" },
110
110
  * items: [
111
111
  * { label: "Edit", icon: () => A("#✎"), click: () => edit() },
112
112
  * { separator: true },
@@ -1,6 +1,6 @@
1
1
  import A from "aberdeen";
2
2
  import { matchCurrent } from "aberdeen/route";
3
- import { drawSlot } from "../core.js";
3
+ import { drawSlot, mountPortal } from "../core.js";
4
4
  import { button } from "./button.js";
5
5
  // Styles shared by the floating dropdown and the sidebar nav, so both look
6
6
  // identical. The item styles aren't scoped to a container, so `drawMenu` can
@@ -68,8 +68,8 @@ export function drawMenu(items, onActivate) {
68
68
  els[next].focus();
69
69
  });
70
70
  for (const entry of items) {
71
- if (typeof entry === "function") {
72
- entry();
71
+ if (typeof entry === "string" || typeof entry === "function") {
72
+ drawSlot(entry);
73
73
  continue;
74
74
  }
75
75
  if ("separator" in entry) {
@@ -122,7 +122,7 @@ function positionMenu(menuEl, rect) {
122
122
  menuEl.style.left = Math.max(8, x) + "px";
123
123
  menuEl.style.top = Math.max(8, y) + "px";
124
124
  }
125
- A.mount(document.body, () => {
125
+ mountPortal(() => {
126
126
  const f = $floating.opts;
127
127
  if (!f)
128
128
  return;
@@ -187,7 +187,7 @@ export function showFloatingMenu(opts) {
187
187
  * @example
188
188
  * ```ts
189
189
  * S.menuButton({
190
- * button: { text: "Actions", attrs: ".neutral .outlined" },
190
+ * button: { content: "Actions", attrs: ".neutral .outlined" },
191
191
  * items: [
192
192
  * { label: "Edit", icon: () => A("#✎"), click: () => edit() },
193
193
  * { separator: true },
@@ -202,7 +202,9 @@ export function menuButton(opts) {
202
202
  closeFloating(); });
203
203
  button({
204
204
  icon: () => A("span aria-hidden=true #☰"),
205
- ariaLabel: "Open menu",
205
+ // Only label the trigger "Open menu" when it has no visible text of its
206
+ // own — an aria-label would otherwise *hide* that text from AT.
207
+ ...(opts.button?.content == null ? { ariaLabel: "Open menu" } : null),
206
208
  attrs: ".neutral .outlined",
207
209
  ...opts.button,
208
210
  click: (e) => {
@@ -1,4 +1,4 @@
1
- import { type Bindable, type Content, type Slot, type Attributes } from "../core.js";
1
+ import { type Bindable, type Slot, type Attributes } from "../core.js";
2
2
  /** A single tab definition. */
3
3
  export interface Tab {
4
4
  /** Stable id used as the selection value. Falls back to the array index. */
@@ -7,8 +7,8 @@ export interface Tab {
7
7
  label: Slot;
8
8
  /** Optional leading icon. */
9
9
  icon?: Slot;
10
- /** Content rendered in the panel when this tab is active. */
11
- content?: Content;
10
+ /** Content rendered in the panel when this tab is active. A string is rendered as rich text. */
11
+ content?: Slot;
12
12
  /** Disables selecting this tab. */
13
13
  disabled?: boolean;
14
14
  }
@@ -67,7 +67,7 @@ export function tabs(opts) {
67
67
  if (!tab)
68
68
  return;
69
69
  A(`id=${groupId}-panel-${keyOf(tab, index)} aria-labelledby=${groupId}-tab-${keyOf(tab, index)}`);
70
- tab.content?.();
70
+ drawSlot(tab.content);
71
71
  });
72
72
  });
73
73
  });
@@ -1,5 +1,4 @@
1
1
  import { type Slot, type Attributes } from "../core.js";
2
- import type { SurfaceRole } from "../theme.js";
3
2
  /** Options for {@link toast}. */
4
3
  export interface ToastOptions {
5
4
  /** Primary message. A string is rendered as rich text. */
@@ -8,9 +7,8 @@ export interface ToastOptions {
8
7
  title?: Slot;
9
8
  /**
10
9
  * Colour role. Defaults to `"neutral"`.
11
- * Use `"success"` / `"danger"` / `"warning"` for semantic feedback.
12
10
  */
13
- type?: SurfaceRole;
11
+ type?: "success" | "danger" | "warning" | "neutral";
14
12
  /**
15
13
  * Auto-dismiss delay in milliseconds. Defaults to `4000`.
16
14
  * Pass `0` to make the toast persistent until dismissed manually.
@@ -1,6 +1,6 @@
1
1
  import A from "aberdeen";
2
2
  import { grow, shrink } from "aberdeen/transitions";
3
- import { drawSlot } from "../core.js";
3
+ import { drawSlot, mountPortal } from "../core.js";
4
4
  A.insertGlobalCss({
5
5
  ".s-toasts": "position:fixed bottom:$3 right:$3 z-index:400 " +
6
6
  "display:flex flex-direction:column gap:$2 " +
@@ -21,7 +21,7 @@ A.insertGlobalCss({
21
21
  let toastCount = 0;
22
22
  // Keyed by stable ID so A.onEach scopes are per-toast — removing one never re-renders others.
23
23
  const toasts = A.proxy({});
24
- A.mount(document.body, () => {
24
+ mountPortal(() => {
25
25
  A("div.s-toasts aria-live=polite aria-atomic=false", () => {
26
26
  A.onEach(toasts, (entry) => {
27
27
  const { opts } = entry;
@@ -1,5 +1,5 @@
1
1
  import A from "aberdeen";
2
- import { drawSlot } from "../core.js";
2
+ import { drawSlot, mountPortal } from "../core.js";
3
3
  A.insertGlobalCss({
4
4
  ".s-tt-tip": {
5
5
  "&": "position:fixed z-index:500 " +
@@ -67,7 +67,7 @@ function scheduleHide() {
67
67
  }, 100);
68
68
  }
69
69
  // ─── Portal ──────────────────────────────────────────────────────────────────
70
- A.mount(document.body, () => {
70
+ mountPortal(() => {
71
71
  const active = $ttActive.value;
72
72
  if (!active)
73
73
  return;
package/dist/core.d.ts CHANGED
@@ -26,8 +26,6 @@ export type Attributes = string;
26
26
  export type Bindable<T> = {
27
27
  value: T;
28
28
  };
29
- /** A content function. It runs inside the relevant element's reactive scope. */
30
- export type Content = () => void;
31
29
  /**
32
30
  * Something that renders a small piece of content: either a plain string or a
33
31
  * draw function (for icons, badges, custom markup, ...).
@@ -47,8 +45,8 @@ export type Slot<Args extends unknown[] = []> = string | ((...args: Args) => voi
47
45
  export interface ContentOptions {
48
46
  /** Aberdeen attr/style string applied to the widget's outermost element. */
49
47
  attrs?: Attributes;
50
- /** Draws the children of this component. */
51
- content?: Content;
48
+ /** Draws the children of this component. A string is rendered as rich text. */
49
+ content?: Slot;
52
50
  }
53
51
  /** Generates a process-unique id, used to wire `<label for>` to its control. */
54
52
  export declare function uniqueId(prefix?: string): string;
@@ -58,3 +56,11 @@ export declare function uniqueId(prefix?: string): string;
58
56
  * `rich` markup (`*italic*`, `**bold**`, `` `code` ``, `[link](/path)`).
59
57
  */
60
58
  export declare function drawSlot<Args extends unknown[] = []>(slot: Slot<Args> | undefined, ...args: Args): void;
59
+ /**
60
+ * Mount a portal (tooltip, toast, menu, dialog, …) in its own dedicated
61
+ * container under `<body>`. Each portal gets a private parent element because
62
+ * two `A.mount`s sharing one parent can't tell their nodes apart: a redraw of
63
+ * one (e.g. a tooltip hiding) may sweep up nodes another portal inserted
64
+ * earlier in the same parent (e.g. an open menu).
65
+ */
66
+ export declare function mountPortal(draw: () => void): void;
package/dist/core.js CHANGED
@@ -17,3 +17,16 @@ export function drawSlot(slot, ...args) {
17
17
  else
18
18
  A("rich=", slot);
19
19
  }
20
+ /**
21
+ * Mount a portal (tooltip, toast, menu, dialog, …) in its own dedicated
22
+ * container under `<body>`. Each portal gets a private parent element because
23
+ * two `A.mount`s sharing one parent can't tell their nodes apart: a redraw of
24
+ * one (e.g. a tooltip hiding) may sweep up nodes another portal inserted
25
+ * earlier in the same parent (e.g. an open menu).
26
+ */
27
+ export function mountPortal(draw) {
28
+ const container = document.createElement("div");
29
+ container.style.display = "contents";
30
+ document.body.appendChild(container);
31
+ A.mount(container, draw);
32
+ }
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * Import the default `S` object and call its component functions:
6
6
  *
7
7
  * ```ts
8
- * import S from "staffa";
8
+ * import * as S from "staffa";
9
9
  *
10
10
  * S.main({
11
11
  * title: "Hello",
@@ -17,7 +17,7 @@
17
17
  * S.textline({ label: "Email", type: "email", bind: A.ref($u, "email") });
18
18
  * S.checkbox({ label: "Remember me", bind: A.ref($u, "remember") });
19
19
  * },
20
- * actions: () => S.button({ text: "Sign in", type: "submit" }),
20
+ * actions: () => S.button({ content: "Sign in", type: "submit" }),
21
21
  * });
22
22
  * }});
23
23
  * },
@@ -29,68 +29,22 @@
29
29
  * which case the component re-renders the affected parts in place when you
30
30
  * mutate it. See `AGENTS.md` for the design philosophy.
31
31
  */
32
- import { setDarkMode, getDarkMode } from "./theme.js";
33
- import { autocomplete } from "./components/autocomplete.js";
34
- import { box } from "./components/box.js";
35
- import { button } from "./components/button.js";
36
- import { buttonChooser } from "./components/buttonChooser.js";
37
- import { buttonGroup } from "./components/buttonGroup.js";
38
- import { checkbox } from "./components/checkbox.js";
39
- import { form } from "./components/form.js";
40
- import { main } from "./components/main.js";
41
- import { menuButton, showFloatingMenu } from "./components/menu.js";
42
- import { dialog, alert, confirm, prompt } from "./components/dialog.js";
43
- import { select } from "./components/select.js";
44
- import { tabs } from "./components/tabs.js";
45
- import { textarea } from "./components/textarea.js";
46
- import { textline } from "./components/textline.js";
47
- import { toast } from "./components/toast.js";
48
- import { addTooltip } from "./components/tooltip.js";
49
- /** The Staffa component namespace. */
50
- export declare const S: {
51
- main: typeof main;
52
- box: typeof box;
53
- dialog: typeof dialog;
54
- alert: typeof alert;
55
- confirm: typeof confirm;
56
- prompt: typeof prompt;
57
- form: typeof form;
58
- menuButton: typeof menuButton;
59
- showFloatingMenu: typeof showFloatingMenu;
60
- textline: typeof textline;
61
- textarea: typeof textarea;
62
- checkbox: typeof checkbox;
63
- tabs: typeof tabs;
64
- button: typeof button;
65
- buttonChooser: typeof buttonChooser;
66
- buttonGroup: typeof buttonGroup;
67
- autocomplete: typeof autocomplete;
68
- select: typeof select;
69
- toast: typeof toast;
70
- addTooltip: typeof addTooltip;
71
- setDarkMode: typeof setDarkMode;
72
- getDarkMode: typeof getDarkMode;
73
- };
74
- export default S;
75
32
  export { setDarkMode, getDarkMode } from "./theme.js";
76
- export type { SurfaceRole, Variant } from "./theme.js";
77
- export type { ContentOptions, Bindable, Content, Slot, Attributes as Styling, } from "./core.js";
78
- export { drawSlot, uniqueId } from "./core.js";
33
+ export { autocomplete, type AutocompleteOptions, type AutocompleteOptionInput } from "./components/autocomplete.js";
34
+ export { box, type BoxOptions } from "./components/box.js";
35
+ export { button, type ButtonOptions } from "./components/button.js";
36
+ export { buttonChooser, type ButtonChooserOptions } from "./components/buttonChooser.js";
37
+ export { buttonGroup, type ButtonGroupOptions } from "./components/buttonGroup.js";
38
+ export { checkbox, type CheckboxOptions } from "./components/checkbox.js";
39
+ export { form, type FormOptions } from "./components/form.js";
40
+ export { main, type MainOptions } from "./components/main.js";
41
+ export { menuButton, showFloatingMenu, type MenuOptions, type MenuEntry, type MenuItem, type MenuSeparator, type FloatingMenuOptions } from "./components/menu.js";
42
+ export { dialog, alert, confirm, prompt, type DialogOptions } from "./components/dialog.js";
43
+ export { select, type SelectOptions, type SelectOptionInput } from "./components/select.js";
44
+ export { tabs, type Tab, type TabsOptions } from "./components/tabs.js";
45
+ export { textarea, type TextareaOptions } from "./components/textarea.js";
46
+ export { textline, type TextlineOptions, type TextlineType } from "./components/textline.js";
47
+ export { toast, type ToastOptions } from "./components/toast.js";
48
+ export { addTooltip, type TooltipOptions } from "./components/tooltip.js";
79
49
  export type { FieldOptions } from "./components/field.js";
80
- export type { MainOptions } from "./components/main.js";
81
- export type { MenuOptions, MenuEntry, MenuItem, MenuSeparator, FloatingMenuOptions } from "./components/menu.js";
82
- export { drawMenu } from "./components/menu.js";
83
- export type { ToastOptions } from "./components/toast.js";
84
- export type { TooltipOptions } from "./components/tooltip.js";
85
- export type { BoxOptions } from "./components/box.js";
86
- export type { FormOptions } from "./components/form.js";
87
- export type { TextlineOptions, TextlineType } from "./components/textline.js";
88
- export type { TextareaOptions } from "./components/textarea.js";
89
- export type { CheckboxOptions } from "./components/checkbox.js";
90
- export type { Tab, TabsOptions } from "./components/tabs.js";
91
- export type { ButtonOptions } from "./components/button.js";
92
- export type { ButtonChooserOptions } from "./components/buttonChooser.js";
93
- export type { ButtonGroupOptions } from "./components/buttonGroup.js";
94
- export type { AutocompleteOptions, AutocompleteOptionInput } from "./components/autocomplete.js";
95
- export type { SelectOptions, SelectOptionInput } from "./components/select.js";
96
- export type { DialogOptions } from "./components/dialog.js";
50
+ export type { ContentOptions, Bindable, Slot, Attributes } from "./core.js";
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * Import the default `S` object and call its component functions:
6
6
  *
7
7
  * ```ts
8
- * import S from "staffa";
8
+ * import * as S from "staffa";
9
9
  *
10
10
  * S.main({
11
11
  * title: "Hello",
@@ -17,7 +17,7 @@
17
17
  * S.textline({ label: "Email", type: "email", bind: A.ref($u, "email") });
18
18
  * S.checkbox({ label: "Remember me", bind: A.ref($u, "remember") });
19
19
  * },
20
- * actions: () => S.button({ text: "Sign in", type: "submit" }),
20
+ * actions: () => S.button({ content: "Sign in", type: "submit" }),
21
21
  * });
22
22
  * }});
23
23
  * },
@@ -32,50 +32,20 @@
32
32
  // Importing the theme module installs spacing vars, the reactive theme and the
33
33
  // base stylesheet. Customise it from your app with A.insertGlobalCss (see
34
34
  // theme.ts); toggle modes with setDarkMode / getDarkMode.
35
- import { setDarkMode, getDarkMode } from "./theme.js";
36
- import { autocomplete } from "./components/autocomplete.js";
37
- import { box } from "./components/box.js";
38
- import { button } from "./components/button.js";
39
- import { buttonChooser } from "./components/buttonChooser.js";
40
- import { buttonGroup } from "./components/buttonGroup.js";
41
- import { checkbox } from "./components/checkbox.js";
42
- import { form } from "./components/form.js";
43
- import { main } from "./components/main.js";
44
- import { menuButton, showFloatingMenu } from "./components/menu.js";
45
- import { dialog, alert, confirm, prompt } from "./components/dialog.js";
46
- import { select } from "./components/select.js";
47
- import { tabs } from "./components/tabs.js";
48
- import { textarea } from "./components/textarea.js";
49
- import { textline } from "./components/textline.js";
50
- import { toast } from "./components/toast.js";
51
- import { addTooltip } from "./components/tooltip.js";
52
- /** The Staffa component namespace. */
53
- export const S = {
54
- main,
55
- box,
56
- dialog,
57
- alert,
58
- confirm,
59
- prompt,
60
- form,
61
- menuButton,
62
- showFloatingMenu,
63
- textline,
64
- textarea,
65
- checkbox,
66
- tabs,
67
- button,
68
- buttonChooser,
69
- buttonGroup,
70
- autocomplete,
71
- select,
72
- toast,
73
- addTooltip,
74
- setDarkMode,
75
- getDarkMode,
76
- };
77
- export default S;
78
- // Re-export theming and shared types for advanced use.
79
35
  export { setDarkMode, getDarkMode } from "./theme.js";
80
- export { drawSlot, uniqueId } from "./core.js";
81
- export { drawMenu } from "./components/menu.js";
36
+ export { autocomplete } from "./components/autocomplete.js";
37
+ export { box } from "./components/box.js";
38
+ export { button } from "./components/button.js";
39
+ export { buttonChooser } from "./components/buttonChooser.js";
40
+ export { buttonGroup } from "./components/buttonGroup.js";
41
+ export { checkbox } from "./components/checkbox.js";
42
+ export { form } from "./components/form.js";
43
+ export { main } from "./components/main.js";
44
+ export { menuButton, showFloatingMenu } from "./components/menu.js";
45
+ export { dialog, alert, confirm, prompt } from "./components/dialog.js";
46
+ export { select } from "./components/select.js";
47
+ export { tabs } from "./components/tabs.js";
48
+ export { textarea } from "./components/textarea.js";
49
+ export { textline } from "./components/textline.js";
50
+ export { toast } from "./components/toast.js";
51
+ export { addTooltip } from "./components/tooltip.js";