@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 +18 -0
- package/dist/components/input-group/input-group.d.mts +28 -2
- package/dist/components/input-group/input-group.mjs +16 -2
- package/dist/components/mobile-nav/mobile-nav-server.d.mts +11 -2
- package/dist/components/mobile-nav/mobile-nav-server.mjs +28 -5
- package/package.json +1 -1
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
|
-
|
|
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
|
-
/**
|
|
51
|
-
|
|
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
|
-
/**
|
|
235
|
-
|
|
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;
|