@vsreact/core 0.0.21 → 0.0.22

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.
@@ -21,6 +21,7 @@ const eventPropNames = {
21
21
  onMouseUp: "mouseup",
22
22
  onMouseMove: "mousemove",
23
23
  onKeyDown: "keydown",
24
+ onKeyUp: "keyup",
24
25
  onDragStart: "dragstart",
25
26
  onDrag: "drag",
26
27
  onDragEnd: "dragend",
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import "./runtime";
2
2
  import "./bridge";
3
3
  /** The SDK version — stamp it on support dumps and analytics. */
4
- export declare const VERSION = "0.0.21";
4
+ export declare const VERSION = "0.0.22";
5
5
  export { View, Text, Image, TextInput, NativeView } from "./primitives";
6
6
  export type { CommonProps, TextProps, ImageProps, TextInputProps, NativeViewProps, } from "./primitives";
7
7
  export { render, unmount } from "./render";
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  import "./runtime";
4
4
  import "./bridge";
5
5
  /** The SDK version — stamp it on support dumps and analytics. */
6
- export const VERSION = "0.0.21";
6
+ export const VERSION = "0.0.22";
7
7
  export { View, Text, Image, TextInput, NativeView } from "./primitives";
8
8
  export { render, unmount } from "./render";
9
9
  export { native } from "./native";
@@ -56,6 +56,8 @@ export interface CommonProps {
56
56
  makes the node focusable: click focuses it, Tab cycles, keys arrive
57
57
  here with web KeyboardEvent.key names. */
58
58
  onKeyDown?: (e: KeyEventPayload) => void;
59
+ /** Fires when a key seen by onKeyDown is released (node still focused). */
60
+ onKeyUp?: (e: KeyEventPayload) => void;
59
61
  onFocus?: () => void;
60
62
  onBlur?: () => void;
61
63
  /** Fires after layout whenever this node's root-space rect changes —
@@ -105,6 +107,7 @@ export declare function TextInput({ onChange, onSubmit, ...rest }: TextInputProp
105
107
  onDragEnd?: ((e: DragEventPayload) => void) | undefined;
106
108
  onMouseMove?: ((e: MouseMovePayload) => void) | undefined;
107
109
  onKeyDown?: ((e: KeyEventPayload) => void) | undefined;
110
+ onKeyUp?: ((e: KeyEventPayload) => void) | undefined;
108
111
  onLayout?: ((rect: LayoutRect) => void) | undefined;
109
112
  }, string | import("react").JSXElementConstructor<any>>;
110
113
  export interface NativeViewProps extends CommonProps {
package/dist/tw.js CHANGED
@@ -51,6 +51,14 @@ const staticClasses = {
51
51
  "font-medium": { fontWeight: 500 },
52
52
  "font-semibold": { fontWeight: 600 },
53
53
  "font-bold": { fontWeight: 700 },
54
+ truncate: { numberOfLines: 1 },
55
+ uppercase: { textTransform: "uppercase" },
56
+ lowercase: { textTransform: "lowercase" },
57
+ capitalize: { textTransform: "capitalize" },
58
+ "normal-case": { textTransform: "none" },
59
+ underline: { textDecoration: "underline" },
60
+ "line-through": { textDecoration: "line-through" },
61
+ "no-underline": { textDecoration: "none" },
54
62
  "tracking-tighter": { letterSpacing: -0.8 },
55
63
  "tracking-tight": { letterSpacing: -0.4 },
56
64
  "tracking-normal": { letterSpacing: 0 },
@@ -287,9 +295,21 @@ function resolveClass(cls) {
287
295
  return Number.isFinite(n) ? { opacity: n / 100 } : undefined;
288
296
  }
289
297
  case "leading": {
298
+ if (rest.startsWith("[")) {
299
+ const px = parseLength(rest);
300
+ return typeof px === "number" ? { lineHeight: px } : undefined;
301
+ }
290
302
  const n = Number(rest);
291
303
  return Number.isFinite(n) ? { lineHeight: n * 4 } : undefined;
292
304
  }
305
+ case "line": {
306
+ // line-clamp-N (rest arrives as "clamp-N")
307
+ if (rest.startsWith("clamp-")) {
308
+ const n = Number(rest.slice("clamp-".length));
309
+ return Number.isFinite(n) && n > 0 ? { numberOfLines: n } : undefined;
310
+ }
311
+ return undefined;
312
+ }
293
313
  case "tracking": {
294
314
  // Named scale lives in staticClasses; arbitrary is px: tracking-[3].
295
315
  if (rest.startsWith("[")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vsreact/core",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "description": "Write React. Ship native VST. A React renderer for JUCE audio plugins — QuickJS + Yoga + juce::Graphics, no webview.",
5
5
  "keywords": [
6
6
  "react",
@@ -820,3 +820,18 @@ describe("keyboard control model (0.0.20)", () => {
820
820
  expect(seen.at(-1)?.[1]).toBeCloseTo(0.49);
821
821
  });
822
822
  });
823
+
824
+ describe("keyup wiring (0.0.22)", () => {
825
+ test("onKeyUp registers the keyup listener", () => {
826
+ const ups: string[] = [];
827
+ render(<Slider value={0.5} onChange={() => {}} />);
828
+ unmount();
829
+ batches.length = 0;
830
+ const { View: V } = require("./index");
831
+ render(<V onKeyUp={(e: any) => ups.push(e.key)} />);
832
+
833
+ const id = nodeWithListener("keyup");
834
+ dispatch({ kind: "event", nodeId: id, type: "keyup", payload: { key: "ArrowUp", shift: false, ctrl: false, alt: false, meta: false } });
835
+ expect(ups).toEqual(["ArrowUp"]);
836
+ });
837
+ });
package/src/hostConfig.ts CHANGED
@@ -32,6 +32,7 @@ const eventPropNames: Record<string, string> = {
32
32
  onMouseUp: "mouseup",
33
33
  onMouseMove: "mousemove",
34
34
  onKeyDown: "keydown",
35
+ onKeyUp: "keyup",
35
36
  onDragStart: "dragstart",
36
37
  onDrag: "drag",
37
38
  onDragEnd: "dragend",
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@ import "./runtime";
4
4
  import "./bridge";
5
5
 
6
6
  /** The SDK version — stamp it on support dumps and analytics. */
7
- export const VERSION = "0.0.21";
7
+ export const VERSION = "0.0.22";
8
8
 
9
9
  export { View, Text, Image, TextInput, NativeView } from "./primitives";
10
10
  export type {
@@ -62,6 +62,8 @@ export interface CommonProps {
62
62
  makes the node focusable: click focuses it, Tab cycles, keys arrive
63
63
  here with web KeyboardEvent.key names. */
64
64
  onKeyDown?: (e: KeyEventPayload) => void;
65
+ /** Fires when a key seen by onKeyDown is released (node still focused). */
66
+ onKeyUp?: (e: KeyEventPayload) => void;
65
67
  onFocus?: () => void;
66
68
  onBlur?: () => void;
67
69
  /** Fires after layout whenever this node's root-space rect changes —
package/src/tw.test.ts CHANGED
@@ -234,3 +234,22 @@ describe("zIndex (0.0.20)", () => {
234
234
  expect(tw("-z-1").style).toEqual({ zIndex: -1 });
235
235
  });
236
236
  });
237
+
238
+ describe("typography (0.0.22)", () => {
239
+ test("truncate and line-clamp", () => {
240
+ expect(tw("truncate").style).toEqual({ numberOfLines: 1 });
241
+ expect(tw("line-clamp-3").style).toEqual({ numberOfLines: 3 });
242
+ });
243
+
244
+ test("case transforms and decorations", () => {
245
+ expect(tw("uppercase").style).toEqual({ textTransform: "uppercase" });
246
+ expect(tw("capitalize").style).toEqual({ textTransform: "capitalize" });
247
+ expect(tw("underline").style).toEqual({ textDecoration: "underline" });
248
+ expect(tw("line-through").style).toEqual({ textDecoration: "line-through" });
249
+ });
250
+
251
+ test("arbitrary leading is px", () => {
252
+ expect(tw("leading-[18]").style).toEqual({ lineHeight: 18 });
253
+ expect(tw("leading-5").style).toEqual({ lineHeight: 20 });
254
+ });
255
+ });
package/src/tw.ts CHANGED
@@ -62,6 +62,14 @@ const staticClasses: Record<string, Style> = {
62
62
  "font-medium": { fontWeight: 500 },
63
63
  "font-semibold": { fontWeight: 600 },
64
64
  "font-bold": { fontWeight: 700 },
65
+ truncate: { numberOfLines: 1 },
66
+ uppercase: { textTransform: "uppercase" },
67
+ lowercase: { textTransform: "lowercase" },
68
+ capitalize: { textTransform: "capitalize" },
69
+ "normal-case": { textTransform: "none" },
70
+ underline: { textDecoration: "underline" },
71
+ "line-through": { textDecoration: "line-through" },
72
+ "no-underline": { textDecoration: "none" },
65
73
  "tracking-tighter": { letterSpacing: -0.8 },
66
74
  "tracking-tight": { letterSpacing: -0.4 },
67
75
  "tracking-normal": { letterSpacing: 0 },
@@ -295,9 +303,21 @@ function resolveClass(cls: string): Style | undefined {
295
303
  return Number.isFinite(n) ? { opacity: n / 100 } : undefined;
296
304
  }
297
305
  case "leading": {
306
+ if (rest.startsWith("[")) {
307
+ const px = parseLength(rest);
308
+ return typeof px === "number" ? { lineHeight: px } : undefined;
309
+ }
298
310
  const n = Number(rest);
299
311
  return Number.isFinite(n) ? { lineHeight: n * 4 } : undefined;
300
312
  }
313
+ case "line": {
314
+ // line-clamp-N (rest arrives as "clamp-N")
315
+ if (rest.startsWith("clamp-")) {
316
+ const n = Number(rest.slice("clamp-".length));
317
+ return Number.isFinite(n) && n > 0 ? { numberOfLines: n } : undefined;
318
+ }
319
+ return undefined;
320
+ }
301
321
  case "tracking": {
302
322
  // Named scale lives in staticClasses; arbitrary is px: tracking-[3].
303
323
  if (rest.startsWith("[")) {