@botiverse/raft-ui 0.67.0 → 0.69.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/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## [0.69.0](https://github.com/botiverse/raft-design/compare/v0.68.0...v0.69.0) (2026-11-06)
2
+
3
+ ### Added
4
+
5
+ - **InputGroup** `size`: `md` for a field in a toolbar or a filter row, `lg` (the default, unchanged) for a field on its own. At `md` the field is the row's button height: 32px on a phone and a touch screen, like the `md` Buttons and PickerTriggerButtons beside it, with its input taking a 44px tap area, 6px past the box above and below; with a mouse it stays the control height, 34px. The root carries `data-size`. A Button in an `md` field's end addon is 20px by touch (22px with a mouse), 6px inside the box. ([#1039](https://github.com/botiverse/raft-design/pull/1039))
6
+ - Why: on a tablet held landscape, a 44px search field beside 32px filter triggers and a view switch read taller and heavier than the rest of the filter row; a field in a row now takes the row's button height.
7
+ - Affects: nothing until a field opts in with `size="md"`; every InputGroup without it renders as before.
8
+ - Docs: https://raft-design.botiverse.build/components/input-group/#sizes
9
+
10
+ ## [0.68.0](https://github.com/botiverse/raft-design/compare/v0.67.0...v0.68.0) (2026-11-06)
11
+
12
+ ### Changed
13
+
14
+ - **MobileNavServerPopoverDestinations** (`@botiverse/raft-ui/wip`): more than 4 destinations take 3 columns, rows of 3 with the last row from the left (`data-layout="grid"`); each button keeps its height, icon, label size and hit area. 4 or fewer stay in one row (`data-layout="row"`). The count is of the element children, looking inside fragments. ([#1037](https://github.com/botiverse/raft-design/pull/1037))
15
+ - Why: a server tab that holds Artifacts, Members, Computers, Apps and Settings put five in a row, which truncated labels such as "Computadoras" at 360px; a third of the popover keeps them whole in every language.
16
+ - Affects: a server tab popover with more than 4 destinations; up to 4 are unchanged.
17
+ - Docs: https://raft-design.botiverse.build/components/mobile-nav/#the-server-tab
18
+
1
19
  ## [0.67.0](https://github.com/botiverse/raft-design/compare/v0.66.0...v0.67.0) (2026-11-06)
2
20
 
3
21
  ### Added
@@ -7,6 +7,12 @@ import { ComponentPropsWithRef } from "react";
7
7
  import { Input } from "@base-ui/react/input";
8
8
  //#region src/components/input-group/input-group.d.ts
9
9
  declare const inputGroup: import("tailwind-variants/lite").TVReturnType<{
10
+ size: {
11
+ md: {
12
+ root: string[];
13
+ };
14
+ lg: {};
15
+ };
10
16
  align: {
11
17
  "inline-start": {
12
18
  addon: string;
@@ -31,6 +37,12 @@ declare const inputGroup: import("tailwind-variants/lite").TVReturnType<{
31
37
  textInner: string[];
32
38
  control: string[];
33
39
  }, undefined, {
40
+ size: {
41
+ md: {
42
+ root: string[];
43
+ };
44
+ lg: {};
45
+ };
34
46
  align: {
35
47
  "inline-start": {
36
48
  addon: string;
@@ -55,6 +67,12 @@ declare const inputGroup: import("tailwind-variants/lite").TVReturnType<{
55
67
  textInner: string[];
56
68
  control: string[];
57
69
  }, import("tailwind-variants/lite").TVReturnTypeLike<{
70
+ size: {
71
+ md: {
72
+ root: string[];
73
+ };
74
+ lg: {};
75
+ };
58
76
  align: {
59
77
  "inline-start": {
60
78
  addon: string;
@@ -79,8 +97,16 @@ declare const inputGroup: import("tailwind-variants/lite").TVReturnType<{
79
97
  textInner: string[];
80
98
  control: string[];
81
99
  }>>;
82
- export type InputGroupProps = ComponentPropsWithRef<"div">;
83
- export declare function InputGroup({ className, ...props }: InputGroupProps): import("react").JSX.Element;
100
+ export type InputGroupProps = ComponentPropsWithRef<"div"> & {
101
+ /**
102
+ * `lg` (default): the control height, for a field on its own in a form or a
103
+ * dialog. `md`: a field in a toolbar or a filter row, as high as the row's
104
+ * `md` buttons and filter triggers (32px by touch, with a 44px tap area; the
105
+ * control height with a mouse).
106
+ */
107
+ size?: "md" | "lg";
108
+ };
109
+ export declare function InputGroup({ size, className, ...props }: InputGroupProps): import("react").JSX.Element;
84
110
  export type InputGroupAddonProps = ComponentPropsWithRef<"div"> & Pick<VariantProps<typeof inputGroup>, "align" | "variant">;
85
111
  declare function InputGroupAddonRoot({ align, variant, className, ...props }: InputGroupAddonProps): import("react").JSX.Element;
86
112
  export type InputGroupAddonTextProps = ComponentPropsWithRef<"span"> & Pick<VariantProps<typeof inputGroup>, "align" | "variant">;
@@ -37,6 +37,18 @@ const inputGroup = tv({
37
37
  ]
38
38
  },
39
39
  variants: {
40
+ size: {
41
+ md: { root: [
42
+ "h-8 md:pointer-fine:h-control rounded-control overflow-visible",
43
+ "[--ig-hit:calc(--spacing(1.5)+1.5px)] md:pointer-fine:[--ig-hit:0px]",
44
+ "*:data-[slot=input-group-control]:-my-(--ig-hit) *:data-[slot=input-group-control]:h-[calc(100%+2*var(--ig-hit))]",
45
+ "[--control-embedded-size:calc(2rem-2*var(--control-embedded-inset))]",
46
+ "md:pointer-fine:[--control-embedded-size:calc(var(--control-height)-2*var(--control-embedded-inset))]",
47
+ "*:data-[variant=container]:data-[align=inline-start]:rounded-s-[calc(var(--radius-control)-1.5px)]",
48
+ "*:data-[variant=container]:data-[align=inline-end]:rounded-e-[calc(var(--radius-control)-1.5px)]"
49
+ ] },
50
+ lg: {}
51
+ },
40
52
  align: {
41
53
  "inline-start": {
42
54
  addon: "order-first",
@@ -111,14 +123,16 @@ const inputGroup = tv({
111
123
  }
112
124
  ],
113
125
  defaultVariants: {
126
+ size: "lg",
114
127
  align: "inline-start",
115
128
  variant: "default"
116
129
  }
117
130
  });
118
- function InputGroup({ className, ...props }) {
119
- const { root } = inputGroup();
131
+ function InputGroup({ size = "lg", className, ...props }) {
132
+ const { root } = inputGroup({ size });
120
133
  return /* @__PURE__ */ jsx("div", {
121
134
  "data-slot": "input-group",
135
+ "data-size": size,
122
136
  className: root({ className }),
123
137
  ...props
124
138
  });
@@ -47,8 +47,17 @@ export type MobileNavServerPopoverRowLabelProps = ComponentPropsWithRef<"span">;
47
47
  /** A row's label: takes the room and truncates. */
48
48
  export declare function MobileNavServerPopoverRowLabel({ className, ...props }: MobileNavServerPopoverRowLabelProps): import("react").JSX.Element;
49
49
  export type MobileNavServerPopoverDestinationsProps = ComponentPropsWithRef<"div">;
50
- /** The server's own pages, side by side in equal cells; a `group`, named with `aria-label`. */
51
- export declare function MobileNavServerPopoverDestinations({ className, ...props }: MobileNavServerPopoverDestinationsProps): import("react").JSX.Element;
50
+ /**
51
+ * The server's own pages in equal cells; a `group`, named with `aria-label`.
52
+ * Up to 4 sit side by side in one row (`data-layout="row"`). More than 4
53
+ * take 3 columns, rows of 3 with the last row starting at the left
54
+ * (`data-layout="grid"`), so each label keeps a third of the popover and
55
+ * stays whole in every language. The count is of the element children, taken
56
+ * in React, looking inside fragments (a product puts the pages a guest lacks
57
+ * in one): counting them in CSS would take a structural pseudo-class on the
58
+ * children, which the WebKit selector rules in CLAUDE.md forbid.
59
+ */
60
+ export declare function MobileNavServerPopoverDestinations({ className, children, ...props }: MobileNavServerPopoverDestinationsProps): import("react").JSX.Element;
52
61
  export type MobileNavServerPopoverDestinationProps = ComponentPropsWithRef<"button">;
53
62
  /**
54
63
  * One of the server's pages: a 20px icon over a short label in a `span`, which
@@ -2,7 +2,7 @@ import { tv } from "../../lib/tv.mjs";
2
2
  import { MobileNavItem } from "./mobile-nav.mjs";
3
3
  import "../../lib/touch-drag.mjs";
4
4
  import { PopoverContent } from "../popover/popover.mjs";
5
- import { createContext, use, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
5
+ import { Children, Fragment, createContext, isValidElement, use, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  import { Popover } from "@base-ui/react/popover";
8
8
  //#region src/components/mobile-nav/mobile-nav-server.tsx
@@ -33,7 +33,7 @@ const mobileNavServer = tv({ slots: {
33
33
  rowLabel: ["min-w-0 flex-1 truncate"],
34
34
  rowBody: ["flex min-w-0 flex-1 flex-col"],
35
35
  rowDescription: ["min-w-0 truncate", "font-mono text-mono-meta font-normal text-foreground-hint"],
36
- destinations: ["grid shrink-0 grid-flow-col auto-cols-fr gap-1 p-1"],
36
+ destinations: ["grid shrink-0 grid-flow-col auto-cols-fr gap-1 p-1", "data-[layout=grid]:grid-flow-row data-[layout=grid]:grid-cols-3"],
37
37
  destination: [
38
38
  "relative flex min-w-0 cursor-default select-none flex-col items-center justify-center",
39
39
  "outline-none transition-colors",
@@ -231,14 +231,28 @@ function MobileNavServerPopoverRowLabel({ className, ...props }) {
231
231
  ...props
232
232
  });
233
233
  }
234
- /** The server's own pages, side by side in equal cells; a `group`, named with `aria-label`. */
235
- function MobileNavServerPopoverDestinations({ className, ...props }) {
234
+ /** Past this many pages, the row becomes a grid of 3 columns. */
235
+ const DESTINATIONS_IN_ONE_ROW = 4;
236
+ /**
237
+ * The server's own pages in equal cells; a `group`, named with `aria-label`.
238
+ * Up to 4 sit side by side in one row (`data-layout="row"`). More than 4
239
+ * take 3 columns, rows of 3 with the last row starting at the left
240
+ * (`data-layout="grid"`), so each label keeps a third of the popover and
241
+ * stays whole in every language. The count is of the element children, taken
242
+ * in React, looking inside fragments (a product puts the pages a guest lacks
243
+ * in one): counting them in CSS would take a structural pseudo-class on the
244
+ * children, which the WebKit selector rules in CLAUDE.md forbid.
245
+ */
246
+ function MobileNavServerPopoverDestinations({ className, children, ...props }) {
236
247
  const { destinations } = mobileNavServer();
248
+ const count = countElements(children);
237
249
  return /* @__PURE__ */ jsx("div", {
238
250
  role: "group",
239
251
  "data-slot": "mobile-nav-server-popover-destinations",
252
+ "data-layout": count > DESTINATIONS_IN_ONE_ROW ? "grid" : "row",
240
253
  className: destinations({ className }),
241
- ...props
254
+ ...props,
255
+ children
242
256
  });
243
257
  }
244
258
  /**
@@ -279,6 +293,15 @@ function MobileNavServerPopoverRowDescription({ className, ...props }) {
279
293
  ...props
280
294
  });
281
295
  }
296
+ /** The element children, counting a fragment's elements rather than the fragment. */
297
+ function countElements(children) {
298
+ let count = 0;
299
+ for (const child of Children.toArray(children)) {
300
+ if (!isValidElement(child)) continue;
301
+ count += child.type === Fragment ? countElements(child.props.children) : 1;
302
+ }
303
+ return count;
304
+ }
282
305
  function assignRef(ref, value) {
283
306
  if (typeof ref === "function") ref(value);
284
307
  else if (ref) ref.current = value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botiverse/raft-ui",
3
- "version": "0.67.0",
3
+ "version": "0.69.0",
4
4
  "description": "React components and CSS foundations for the Raft Design System.",
5
5
  "keywords": [
6
6
  "agent-skills",