@spaethtech/svelte-ui 0.5.1-dev.24.9a705e3 → 0.5.1-dev.26.4a7da0b

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.
@@ -99,7 +99,8 @@ surfaces through the **native validity tooltip** (shown on form submit); the con
99
99
  prop is the inline row. Both flip the field's error border.
100
100
 
101
101
  **Groups:** for a set of radios/checkboxes/toggles under one legend, wrap them in **`FieldGroup`**
102
- (same `label`/`description`/`error`/`required` vocab on a `<fieldset>`, plus `orientation`). Inside a
102
+ (same `label`/`description`/`error`/`required` vocab on a `<fieldset>`, plus `columns` a number or
103
+ responsive map; default 1 = stacked, higher lays items across equal auto-placed columns). Inside a
103
104
  group, item labels render **inline** (right of the control). For a radio group, `bind:value` on the
104
105
  `FieldGroup` (+ optional `name`) and the child `<Radio>`s share it automatically — no `bind:group`:
105
106
 
@@ -15,7 +15,7 @@
15
15
  import type { Variant } from "../types/variants.js";
16
16
  import type { Responsive } from "../types/responsive.js";
17
17
  import FieldsetChrome from "./FieldsetChrome.svelte";
18
- import { setFieldGroup } from "./field-group.js";
18
+ import { setFieldGroup, type Columns } from "./field-group.js";
19
19
 
20
20
  let {
21
21
  value = $bindable(),
@@ -25,7 +25,7 @@
25
25
  error = null,
26
26
  description = null,
27
27
  required = false,
28
- orientation = "vertical",
28
+ columns = 1,
29
29
  size = "md",
30
30
  variant,
31
31
  disabled = false,
@@ -41,7 +41,8 @@
41
41
  error?: string | Snippet | null;
42
42
  description?: string | Snippet | null;
43
43
  required?: boolean;
44
- orientation?: "vertical" | "horizontal";
44
+ /** Grid track count (default 1 = stacked vertical). Set >1 (or a responsive map) for columns. */
45
+ columns?: Columns;
45
46
  size?: Responsive<Size>;
46
47
  variant?: Variant;
47
48
  disabled?: boolean;
@@ -49,13 +50,11 @@
49
50
  children: Snippet;
50
51
  } = $props();
51
52
 
52
- // Reactive context: getters keep size/variant/orientation/disabled live; getValue/select share the
53
- // radio-group value. Set once (context is stable); the getters read current prop values.
53
+ // Reactive context: getters keep size/variant/disabled live; getValue/select share the radio-group
54
+ // value. Set once (context is stable); the getters read current prop values. Layout is the grid's
55
+ // job (columns), so items need no orientation awareness.
54
56
  setFieldGroup({
55
57
  inGroup: true,
56
- get orientation() {
57
- return orientation;
58
- },
59
58
  get size() {
60
59
  return size;
61
60
  },
@@ -75,6 +74,6 @@
75
74
  });
76
75
  </script>
77
76
 
78
- <FieldsetChrome {label} {aside} {error} {description} {required} {orientation} {size} class={cls}>
77
+ <FieldsetChrome {label} {aside} {error} {description} {required} {columns} {size} class={cls}>
79
78
  {@render children()}
80
79
  </FieldsetChrome>
@@ -2,6 +2,7 @@ import type { Snippet } from "svelte";
2
2
  import type { Size } from "../types/sizes.js";
3
3
  import type { Variant } from "../types/variants.js";
4
4
  import type { Responsive } from "../types/responsive.js";
5
+ import { type Columns } from "./field-group.js";
5
6
  type $$ComponentProps = {
6
7
  /** Radio groups: the selected value (bindable). Ignored by checkbox/toggle children. */
7
8
  value?: string | number;
@@ -12,7 +13,8 @@ type $$ComponentProps = {
12
13
  error?: string | Snippet | null;
13
14
  description?: string | Snippet | null;
14
15
  required?: boolean;
15
- orientation?: "vertical" | "horizontal";
16
+ /** Grid track count (default 1 = stacked vertical). Set >1 (or a responsive map) for columns. */
17
+ columns?: Columns;
16
18
  size?: Responsive<Size>;
17
19
  variant?: Variant;
18
20
  disabled?: boolean;
@@ -2,11 +2,12 @@
2
2
  import type { Snippet } from "svelte";
3
3
  import type { Size } from "../types/sizes.js";
4
4
  import { responsiveClasses, type Responsive } from "../types/responsive.js";
5
+ import { gridColsClass, type Columns } from "./field-group.js";
5
6
 
6
7
  /**
7
8
  * FieldsetChrome — the group counterpart of FieldChrome: a `<fieldset>` with a `<legend>` (the
8
- * group label) plus the same error/description rows, and an orientation-controlled slot for its
9
- * child controls. Used by `RadioGroup` / `FieldGroup`. Same prop vocabulary as FieldChrome.
9
+ * group label) plus the same error/description rows, and a `columns`-driven CSS-grid slot. Child
10
+ * controls are auto-placed into cells (no per-child prop). Used by `FieldGroup`.
10
11
  */
11
12
  interface Props {
12
13
  label?: string | null;
@@ -14,7 +15,8 @@
14
15
  error?: string | Snippet | null;
15
16
  description?: string | Snippet | null;
16
17
  required?: boolean;
17
- orientation?: "vertical" | "horizontal";
18
+ /** Grid track count (default 1 = stacked). Items auto-flow into equal cells. */
19
+ columns?: Columns;
18
20
  size?: Responsive<Size>;
19
21
  class?: string;
20
22
  children: Snippet;
@@ -26,7 +28,7 @@
26
28
  error = null,
27
29
  description = null,
28
30
  required = false,
29
- orientation = "vertical",
31
+ columns = 1,
30
32
  size = "md",
31
33
  class: cls = "",
32
34
  children,
@@ -41,9 +43,9 @@
41
43
  const hasError = $derived(isSnippet(error) ? true : !!(error && String(error).trim()));
42
44
  const hasDesc = $derived(isSnippet(description) ? true : !!(description && String(description).trim()));
43
45
 
44
- const itemsClass = $derived(
45
- orientation === "horizontal" ? "flex flex-wrap gap-x-6 gap-y-2" : "flex flex-col gap-2",
46
- );
46
+ // Auto-placed CSS grid: each direct child (a Radio/Checkbox/Toggle label) is one cell — no
47
+ // per-child prop. `columns` sets the equal-width tracks; gap is the single density knob.
48
+ const itemsClass = $derived(`grid ${gridColsClass(columns)} gap-x-6 gap-y-1`);
47
49
  </script>
48
50
 
49
51
  <fieldset class="m-0 flex min-w-0 flex-col gap-1 border-0 p-0 {cls}">
@@ -1,10 +1,11 @@
1
1
  import type { Snippet } from "svelte";
2
2
  import type { Size } from "../types/sizes.js";
3
3
  import { type Responsive } from "../types/responsive.js";
4
+ import { type Columns } from "./field-group.js";
4
5
  /**
5
6
  * FieldsetChrome — the group counterpart of FieldChrome: a `<fieldset>` with a `<legend>` (the
6
- * group label) plus the same error/description rows, and an orientation-controlled slot for its
7
- * child controls. Used by `RadioGroup` / `FieldGroup`. Same prop vocabulary as FieldChrome.
7
+ * group label) plus the same error/description rows, and a `columns`-driven CSS-grid slot. Child
8
+ * controls are auto-placed into cells (no per-child prop). Used by `FieldGroup`.
8
9
  */
9
10
  interface Props {
10
11
  label?: string | null;
@@ -12,7 +13,8 @@ interface Props {
12
13
  error?: string | Snippet | null;
13
14
  description?: string | Snippet | null;
14
15
  required?: boolean;
15
- orientation?: "vertical" | "horizontal";
16
+ /** Grid track count (default 1 = stacked). Items auto-flow into equal cells. */
17
+ columns?: Columns;
16
18
  size?: Responsive<Size>;
17
19
  class?: string;
18
20
  children: Snippet;
@@ -1,17 +1,24 @@
1
+ import type { Breakpoint } from "../types/breakpoints.js";
1
2
  import type { Size } from "../types/sizes.js";
2
3
  import type { Variant } from "../types/variants.js";
3
- import type { Responsive } from "../types/responsive.js";
4
+ import { type Responsive } from "../types/responsive.js";
4
5
  export interface FieldGroupContext {
5
6
  /** Present ⇒ the item is inside a group and renders its label inline (right of the control). */
6
7
  inGroup: true;
7
- orientation: "vertical" | "horizontal";
8
8
  size?: Responsive<Size>;
9
9
  variant?: Variant;
10
10
  disabled?: boolean;
11
- /** RadioGroup only — the shared radio-group name + controlled value. */
11
+ /** Radio groups only — the shared radio-group name + controlled value. */
12
12
  name?: string;
13
13
  getValue?: () => string | number | undefined;
14
14
  select?: (v: string | number) => void;
15
15
  }
16
+ /**
17
+ * FieldGroup `columns`: a track count (1–6) as a scalar or a per-breakpoint map. `1` (default) = a
18
+ * stacked vertical list; anything higher lays the auto-placed items across that many equal columns.
19
+ */
20
+ export type Columns = number | Partial<Record<Breakpoint, number>>;
21
+ /** Resolve a `Columns` value to `grid-cols-*` classes (responsive-aware). */
22
+ export declare function gridColsClass(columns: Columns | undefined): string;
16
23
  export declare function setFieldGroup(ctx: FieldGroupContext): void;
17
24
  export declare function getFieldGroup(): FieldGroupContext | undefined;
@@ -5,6 +5,26 @@
5
5
  * the radio-group value + `name` so a child `<Radio>` needs no `bind:group`.
6
6
  */
7
7
  import { getContext, setContext } from "svelte";
8
+ import { responsiveClasses } from "../types/responsive.js";
9
+ // Static literal map so Tailwind's scanner emits the base classes; the bp:-prefixed variants are
10
+ // safelisted in theme.css (`@source inline(... grid-cols-{1..6})`).
11
+ const COLS_MAP = {
12
+ "1": "grid-cols-1",
13
+ "2": "grid-cols-2",
14
+ "3": "grid-cols-3",
15
+ "4": "grid-cols-4",
16
+ "5": "grid-cols-5",
17
+ "6": "grid-cols-6",
18
+ };
19
+ /** Resolve a `Columns` value to `grid-cols-*` classes (responsive-aware). */
20
+ export function gridColsClass(columns) {
21
+ if (columns == null)
22
+ return COLS_MAP["1"];
23
+ const value = typeof columns === "number"
24
+ ? String(columns)
25
+ : Object.fromEntries(Object.entries(columns).map(([bp, n]) => [bp, String(n)]));
26
+ return responsiveClasses(value, COLS_MAP) || COLS_MAP["1"];
27
+ }
8
28
  const KEY = Symbol("svelte-ui-field-group");
9
29
  export function setFieldGroup(ctx) {
10
30
  setContext(KEY, ctx);
package/dist/theme.css CHANGED
@@ -203,3 +203,5 @@ body {
203
203
  @source inline("{,4xs:,3xs:,2xs:,xs:,sm:,md:,lg:,xl:,2xl:,3xl:}gap-{1.5,2,3}");
204
204
  @source inline("{,4xs:,3xs:,2xs:,xs:,sm:,md:,lg:,xl:,2xl:,3xl:}text-{xs,sm,base,lg,2xl}");
205
205
  @source inline("{,4xs:,3xs:,2xs:,xs:,sm:,md:,lg:,xl:,2xl:,3xl:}[&_svg]:{w,h}-{3.5,4,5,6}");
206
+ /* FieldGroup `columns` → responsive grid tracks (auto-placed cells). */
207
+ @source inline("{,4xs:,3xs:,2xs:,xs:,sm:,md:,lg:,xl:,2xl:,3xl:}grid-cols-{1,2,3,4,5,6}");
@@ -129,7 +129,8 @@ One wrapper for a set of Radios, Checkboxes, or Toggles under a shared legend (a
129
129
 
130
130
  - **Location**: `src/lib/components/FieldGroup.svelte`
131
131
  - **Props**: `label` (legend), `aside`, `description`, `error`, `required` (the shared field-chrome
132
- vocabulary), `orientation` (`'vertical'` default | `'horizontal'`), `size`, `variant`, `disabled`
132
+ vocabulary), `columns` (`number | { base, md, … }`, default `1` = stacked; higher = that many
133
+ equal auto-placed columns), `size`, `variant`, `disabled`
133
134
  (propagate to children), and for radio groups `value` (bindable) + `name`. Children render their
134
135
  label inline; radios auto-share the group value/name via context.
135
136
 
package/docs/usage.md CHANGED
@@ -135,7 +135,7 @@ inline. For radios, bind the group `value` — children need no `bind:group`.
135
135
  <Radio value="push" label="Push notification" />
136
136
  </FieldGroup>
137
137
 
138
- <FieldGroup label="Capabilities" orientation="horizontal">
138
+ <FieldGroup label="Capabilities" columns={2}>
139
139
  <Checkbox label="Webhook triggers" bind:checked={caps.webhook} />
140
140
  <Checkbox label="Script actions" bind:checked={caps.script} />
141
141
  </FieldGroup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaethtech/svelte-ui",
3
- "version": "0.5.1-dev.24.9a705e3",
3
+ "version": "0.5.1-dev.26.4a7da0b",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/spaethtech/svelte-ui.git"