Skip to content

Commit bd2dcc9

Browse files
committed
feat: expand floating parameters
1 parent 9470772 commit bd2dcc9

6 files changed

Lines changed: 179 additions & 8 deletions

File tree

ops.ts

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,24 @@ export function pack(
163163
o += 4;
164164
view.setFloat32(o, f.y ?? 0, true);
165165
o += 4;
166+
view.setFloat32(o, f.expand?.width ?? 0, true);
167+
o += 4;
168+
view.setFloat32(o, f.expand?.height ?? 0, true);
169+
o += 4;
166170
view.setUint32(o, f.parent ?? 0, true);
167171
o += 4;
168172
view.setUint32(
169173
o,
170-
(f.attachTo ?? 0) | ((f.attachPoints ?? 0) << 8) |
171-
((f.zIndex ?? 0) << 16),
174+
(f.attachTo ?? 0) |
175+
((f.attachPoints?.element ?? 0) << 8) |
176+
((f.attachPoints?.parent ?? 0) << 16) |
177+
((f.pointerCaptureMode ?? 0) << 24),
178+
true,
179+
);
180+
o += 4;
181+
view.setUint32(
182+
o,
183+
(f.clipTo ?? 0) | (((f.zIndex ?? 0) & 0xffff) << 8),
172184
true,
173185
);
174186
o += 4;
@@ -264,13 +276,45 @@ export interface OpenElement {
264276
floating?: {
265277
x?: number;
266278
y?: number;
279+
expand?: { width?: number; height?: number };
267280
parent?: number;
268281
attachTo?: number;
269-
attachPoints?: number;
282+
attachPoints?: { element?: number; parent?: number };
283+
pointerCaptureMode?: number;
284+
clipTo?: number;
270285
zIndex?: number;
271286
};
272287
}
273288

289+
export const ATTACH_POINT = {
290+
LEFT_TOP: 0,
291+
LEFT_CENTER: 1,
292+
LEFT_BOTTOM: 2,
293+
CENTER_TOP: 3,
294+
CENTER_CENTER: 4,
295+
CENTER_BOTTOM: 5,
296+
RIGHT_TOP: 6,
297+
RIGHT_CENTER: 7,
298+
RIGHT_BOTTOM: 8,
299+
} as const;
300+
301+
export const ATTACH_TO = {
302+
NONE: 0,
303+
PARENT: 1,
304+
ELEMENT_WITH_ID: 2,
305+
ROOT: 3,
306+
} as const;
307+
308+
export const POINTER_CAPTURE_MODE = {
309+
CAPTURE: 0,
310+
PASSTHROUGH: 1,
311+
} as const;
312+
313+
export const CLIP_TO = {
314+
NONE: 0,
315+
ATTACHED_PARENT: 1,
316+
} as const;
317+
274318
export interface Text {
275319
directive: typeof OP_TEXT;
276320
content: string;

specs/renderer-spec.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -609,10 +609,36 @@ The `open()` constructor currently accepts the following property groups in its
609609
- **`cornerRadius`** — per-corner radius values, producing rounded box-drawing
610610
characters
611611
- **`clip`** — clip region configuration for scroll containers
612-
- **`floating`** — floating-element configuration (offset, parent reference,
613-
attach points, z-index)
612+
- **`floating`** — floating-element configuration (offset, expansion, parent
613+
reference, attach target, structured attach points, pointer capture mode, clip
614+
target, z-index)
614615
- **`scroll`** — scroll container configuration
615616

617+
The current floating surface is:
618+
619+
```ts
620+
floating?: {
621+
x?: number;
622+
y?: number;
623+
expand?: { width?: number; height?: number };
624+
parent?: number;
625+
attachTo?: number;
626+
attachPoints?: {
627+
element?: number;
628+
parent?: number;
629+
};
630+
pointerCaptureMode?: number;
631+
clipTo?: number;
632+
zIndex?: number;
633+
}
634+
```
635+
636+
This shape extends the earlier floating surface in two ways. First,
637+
`attachPoints` is structured as separate element and parent anchor values
638+
instead of a single packed enum. Second, the surface exposes additional Clay
639+
floating controls that were previously unavailable at the TypeScript layer:
640+
`expand`, `pointerCaptureMode`, and `clipTo`.
641+
616642
The `text()` constructor currently accepts: `color`, `fontSize`,
617643
`letterSpacing`, `lineHeight`, and attribute flags (`bold`, `italic`,
618644
`underline`, `strikethrough`).

src/clayterm.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,13 +546,19 @@ void reduce(struct Clayterm *ct, uint32_t *buf, int len, int mode, int row) {
546546
if (mask & PROP_FLOATING) {
547547
decl.floating.offset.x = rdf(buf, len, &i);
548548
decl.floating.offset.y = rdf(buf, len, &i);
549+
decl.floating.expand.width = rdf(buf, len, &i);
550+
decl.floating.expand.height = rdf(buf, len, &i);
549551
decl.floating.parentId = rd(buf, len, &i);
550552

551553
uint32_t fc = rd(buf, len, &i);
552554
decl.floating.attachTo = fc & 0xff;
553555
decl.floating.attachPoints.element = (fc >> 8) & 0xff;
554556
decl.floating.attachPoints.parent = (fc >> 16) & 0xff;
555-
decl.floating.zIndex = (int16_t)((fc >> 24) & 0xff);
557+
decl.floating.pointerCaptureMode = (fc >> 24) & 0xff;
558+
559+
uint32_t fd = rd(buf, len, &i);
560+
decl.floating.clipTo = fd & 0xff;
561+
decl.floating.zIndex = (int16_t)(fd >> 8);
556562
}
557563

558564
Clay__ConfigureOpenElement(decl);

test/term.test.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
import { beforeEach, describe, expect, it } from "./suite.ts";
22
import { createTerm, type Term } from "../term.ts";
3-
import { close, fixed, grow, open, rgba, text } from "../ops.ts";
3+
import {
4+
ATTACH_POINT,
5+
ATTACH_TO,
6+
close,
7+
fixed,
8+
grow,
9+
open,
10+
rgba,
11+
text,
12+
} from "../ops.ts";
413
import { print } from "./print.ts";
514

615
const decode = (bytes: Uint8Array) => new TextDecoder().decode(bytes);
@@ -191,6 +200,50 @@ describe("term", () => {
191200
});
192201
});
193202

203+
it("renders a floating frame with structured attach points", () => {
204+
let out = print(
205+
decode(
206+
term.render([
207+
open("root", {
208+
layout: { width: fixed(40), height: fixed(10), direction: "ttb" },
209+
}),
210+
open("frame", {
211+
layout: {
212+
width: fixed(12),
213+
height: fixed(5),
214+
direction: "ttb",
215+
padding: { left: 1, top: 1 },
216+
},
217+
border: {
218+
color: rgba(255, 255, 255),
219+
left: 1,
220+
right: 1,
221+
top: 1,
222+
bottom: 1,
223+
},
224+
floating: {
225+
x: 3,
226+
y: 1,
227+
attachTo: ATTACH_TO.ROOT,
228+
attachPoints: {
229+
element: ATTACH_POINT.CENTER_CENTER,
230+
parent: ATTACH_POINT.CENTER_CENTER,
231+
},
232+
},
233+
}),
234+
text("box"),
235+
close(),
236+
close(),
237+
]).output,
238+
),
239+
40,
240+
10,
241+
);
242+
243+
expect(out).toContain("│box │");
244+
expect(out).toContain("┌──────────┐");
245+
});
246+
194247
describe("row offset", () => {
195248
it("renders two frames at the offset position", async () => {
196249
let term = await createTerm({ width: 20, height: 5 });

test/validate.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,39 @@ describe("validate", () => {
7878
it("rejects fractional color", () => {
7979
expect(validate([text("hi", { color: 1.5 })])).toBe(false);
8080
});
81+
82+
it("accepts structured floating attach points", () => {
83+
expect(validate([
84+
open("x", {
85+
floating: {
86+
attachPoints: { element: 4, parent: 4 },
87+
},
88+
}),
89+
close(),
90+
])).toBe(true);
91+
});
92+
93+
it("accepts floating expand and clipping fields", () => {
94+
expect(validate([
95+
open("x", {
96+
floating: {
97+
expand: { width: 2, height: 3 },
98+
pointerCaptureMode: 1,
99+
clipTo: 1,
100+
zIndex: 1024,
101+
},
102+
}),
103+
close(),
104+
])).toBe(true);
105+
});
106+
107+
it("rejects numeric floating attachPoints legacy shape", () => {
108+
expect(validate([
109+
// deno-lint-ignore no-explicit-any
110+
open("x", { floating: { attachPoints: 4 as any } }),
111+
close(),
112+
])).toBe(false);
113+
});
81114
});
82115

83116
describe("validated", () => {

validate.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,18 @@ const Clip = Type.Object({
8383
const Floating = Type.Object({
8484
x: Type.Optional(Type.Number()),
8585
y: Type.Optional(Type.Number()),
86+
expand: Type.Optional(Type.Object({
87+
width: Type.Optional(Type.Number()),
88+
height: Type.Optional(Type.Number()),
89+
})),
8690
parent: Type.Optional(Type.Integer({ minimum: 0 })),
8791
attachTo: Type.Optional(u8),
88-
attachPoints: Type.Optional(u8),
92+
attachPoints: Type.Optional(Type.Object({
93+
element: Type.Optional(u8),
94+
parent: Type.Optional(u8),
95+
})),
96+
pointerCaptureMode: Type.Optional(u8),
97+
clipTo: Type.Optional(u8),
8998
zIndex: Type.Optional(u16),
9099
});
91100

0 commit comments

Comments
 (0)