From 2faa3dcd9f2ed4351fdf7af3127520aa6745b292 Mon Sep 17 00:00:00 2001 From: Fabio Gartenmann <137318798+artiphishle@users.noreply.github.com> Date: Sun, 16 Aug 2026 15:34:04 +0200 Subject: [PATCH 1/4] fix: preserve Stack direct child layout --- src/layout/Stack.tsx | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/layout/Stack.tsx b/src/layout/Stack.tsx index e9252ec..03ef071 100644 --- a/src/layout/Stack.tsx +++ b/src/layout/Stack.tsx @@ -1,5 +1,4 @@ -import React from 'react'; -import { View } from 'react-native'; +import type React from 'react'; import { resolveResponsive, type Responsive, useResponsiveRuntime } from '../core/responsive'; import { useTheme } from '../theme/ThemeContext'; @@ -34,14 +33,13 @@ export function Stack({ const activeJustify = resolveResponsive(justify, breakpoint); const activeWrap = resolveResponsive(wrap, breakpoint); - const nodes = React.Children.toArray(children); - return ( - {nodes.map((node, index) => { - const spacing = - index === 0 - ? undefined - : activeDirection === 'row' - ? { marginLeft: activeGap } - : { marginTop: activeGap }; - return ( - - {node} - - ); - })} + {children} ); } From 0cc5f2c5623b31163191a1aae6f4e9f4b1d8e468 Mon Sep 17 00:00:00 2001 From: Fabio Gartenmann <137318798+artiphishle@users.noreply.github.com> Date: Sun, 16 Aug 2026 15:34:12 +0200 Subject: [PATCH 2/4] test: lock Stack direct child invariant --- src/layout/Stack.test.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/layout/Stack.test.ts diff --git a/src/layout/Stack.test.ts b/src/layout/Stack.test.ts new file mode 100644 index 0000000..874b79e --- /dev/null +++ b/src/layout/Stack.test.ts @@ -0,0 +1,14 @@ +import { readFile } from 'node:fs/promises'; + +import { describe, expect, it } from 'bun:test'; + +describe('Stack layout contract', () => { + it('keeps authored children as direct flex items and applies spacing through gap', async () => { + const source = await readFile(new URL('./Stack.tsx', import.meta.url), 'utf8'); + + expect(source).toContain('gap: activeGap'); + expect(source).toContain('{children}'); + expect(source).not.toContain("from 'react-native'"); + expect(source).not.toContain('React.Children'); + }); +}); From 7f410d4cb58f9ea6ae5eca6e5a8a24ac5ea63cb6 Mon Sep 17 00:00:00 2001 From: Fabio Gartenmann <137318798+artiphishle@users.noreply.github.com> Date: Sun, 16 Aug 2026 15:34:20 +0200 Subject: [PATCH 3/4] chore: add Stack layout changeset --- .changeset/direct-stack-children.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/direct-stack-children.md diff --git a/.changeset/direct-stack-children.md b/.changeset/direct-stack-children.md new file mode 100644 index 0000000..af43bcd --- /dev/null +++ b/.changeset/direct-stack-children.md @@ -0,0 +1,5 @@ +--- +"@ankhorage/surface": patch +--- + +Preserve Stack child flex and min-size semantics by applying spacing with the container gap property instead of wrapper views. From 78420b0fc43676e4dffed6edb2fbbe8d38c06f83 Mon Sep 17 00:00:00 2001 From: artiphishle Date: Sun, 16 Aug 2026 16:06:28 +0200 Subject: [PATCH 4/4] docs: update --- .changeset/direct-stack-children.md | 2 +- README.md | 2 +- paradox/badges/npm.svg | 6 +++--- paradox/components.md | 2 +- paradox/exports.json | 4 ++-- paradox/exports.md | 4 ++-- paradox/index.html | 8 ++++---- paradox/paradox.json | 18 ++++++------------ 8 files changed, 20 insertions(+), 26 deletions(-) diff --git a/.changeset/direct-stack-children.md b/.changeset/direct-stack-children.md index af43bcd..248bf92 100644 --- a/.changeset/direct-stack-children.md +++ b/.changeset/direct-stack-children.md @@ -1,5 +1,5 @@ --- -"@ankhorage/surface": patch +'@ankhorage/surface': patch --- Preserve Stack child flex and min-size semantics by applying spacing with the container gap property instead of wrapper views. diff --git a/README.md b/README.md index f075692..3e7f8b9 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ # @ankhorage/surface -![license: MIT](././paradox/badges/license.svg) ![npm: v2.1.1](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![docs: paradox](././paradox/badges/docs.svg) +![license: MIT](././paradox/badges/license.svg) ![npm: v2.2.0](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![docs: paradox](././paradox/badges/docs.svg) Cross-platform UI foundation for React Native and React Native Web. Provides theming, layout primitives, and core building blocks for modern apps. diff --git a/paradox/badges/npm.svg b/paradox/badges/npm.svg index dcc4ebe..fd0ade5 100644 --- a/paradox/badges/npm.svg +++ b/paradox/badges/npm.svg @@ -1,7 +1,7 @@ - -npm: v2.1.1 + +npm: v2.2.0 npm -v2.1.1 +v2.2.0 diff --git a/paradox/components.md b/paradox/components.md index 7e27ac3..8da2b5f 100644 --- a/paradox/components.md +++ b/paradox/components.md @@ -1289,7 +1289,7 @@ Export paths: `src/index.ts` ## Stack -Source: `src/layout/Stack.tsx:20:1` +Source: `src/layout/Stack.tsx:19:1` Export paths: `src/index.ts` diff --git a/paradox/exports.json b/paradox/exports.json index 1f3455d..389aa84 100644 --- a/paradox/exports.json +++ b/paradox/exports.json @@ -9373,7 +9373,7 @@ "modulePath": "src/layout/Stack.tsx", "sourceLocation": { "filePath": "src/layout/Stack.tsx", - "line": 20, + "line": 19, "column": 1 }, "exportPaths": ["src/index.ts"], @@ -9405,7 +9405,7 @@ "modulePath": "src/layout/Stack.tsx", "sourceLocation": { "filePath": "src/layout/Stack.tsx", - "line": 9, + "line": 8, "column": 1 }, "exportPaths": ["src/index.ts"], diff --git a/paradox/exports.md b/paradox/exports.md index 623caed..37e8db0 100644 --- a/paradox/exports.md +++ b/paradox/exports.md @@ -2651,7 +2651,7 @@ Source: `src/layout/Spacer.tsx:6:1` Kind: `function` Module: `src/layout/Stack.tsx` -Source: `src/layout/Stack.tsx:20:1` +Source: `src/layout/Stack.tsx:19:1` ### Signatures @@ -2679,7 +2679,7 @@ Source: `src/layout/Stack.tsx:20:1` Kind: `type` Module: `src/layout/Stack.tsx` -Source: `src/layout/Stack.tsx:9:1` +Source: `src/layout/Stack.tsx:8:1` ### Members diff --git a/paradox/index.html b/paradox/index.html index 9e8e3a8..c99a357 100644 --- a/paradox/index.html +++ b/paradox/index.html @@ -17266,7 +17266,7 @@

src/layout/Stack.tsx

data-search="Stack function src/layout/Stack.tsx StackProps ({ children, direction = 'column', gap = 0, align, justify, wrap, ...props }: StackProps) => React.JSX.Element" >

Stack

-

function • src/layout/Stack.tsx:20:1

+

function • src/layout/Stack.tsx:19:1

Export paths: src/index.ts

@@ -17320,7 +17320,7 @@
Signature
data-search="StackProps type src/layout/Stack.tsx Responsive" >

StackProps

-

type • src/layout/Stack.tsx:9:1

+

type • src/layout/Stack.tsx:8:1

Export paths: src/index.ts

@@ -27869,7 +27869,7 @@

Spacer

data-search="Stack src/layout/Stack.tsx accessibilityLabel ReactNativeViewProps['accessibilityLabel'] | undefined accessibilityRole ReactNativeViewProps['accessibilityRole'] | undefined accessibilityState ReactNativeViewProps['accessibilityState'] | undefined accessible ReactNativeViewProps['accessible'] | undefined align Responsive<'flex-start' | 'center' | 'flex-end' | 'stretch' | 'baseline'> | undefined alignSelf Responsive<ViewStyle['alignSelf']> | undefined bg Responsive<ColorValue> | undefined borderColor Responsive<ColorValue> | undefined borderWidth Responsive<number> | undefined bottom Responsive<number> | undefined children React.ReactNode | undefined direction Responsive<'row' | 'column'> | undefined flex Responsive<number> | undefined flexBasis Responsive<number | string> | undefined flexGrow Responsive<number> | undefined flexShrink Responsive<number> | undefined gap Responsive<SpaceValue> | undefined height Responsive<number | string> | undefined justify Responsive< 'flex-start' | 'center' | 'flex-end' | 'space-between' | 'space-around' | 'space-evenly' > | undefined left Responsive<number> | undefined m Responsive<SpaceValue> | undefined maxHeight Responsive<number | string> | undefined maxWidth Responsive<number | string> | undefined mb Responsive<SpaceValue> | undefined minHeight Responsive<number | string> | undefined minWidth Responsive<number | string> | undefined ml Responsive<SpaceValue> | undefined mr Responsive<SpaceValue> | undefined mt Responsive<SpaceValue> | undefined mx Responsive<SpaceValue> | undefined my Responsive<SpaceValue> | undefined opacity Responsive<number> | undefined overflow Responsive<ViewStyle['overflow']> | undefined p Responsive<SpaceValue> | undefined pb Responsive<SpaceValue> | undefined pl Responsive<SpaceValue> | undefined pointerEvents ReactNativeViewProps['pointerEvents'] | undefined position Responsive<ViewStyle['position']> | undefined pr Responsive<SpaceValue> | undefined pt Responsive<SpaceValue> | undefined px Responsive<SpaceValue> | undefined py Responsive<SpaceValue> | undefined radius Responsive<RadiusValue> | undefined right Responsive<number> | undefined style StyleProp<ViewStyle> | undefined testID string | undefined top Responsive<number> | undefined width Responsive<number | string> | undefined wrap Responsive<'nowrap' | 'wrap'> | undefined zIndex Responsive<number> | undefined" >

Stack

-

src/layout/Stack.tsx:20:1

+

src/layout/Stack.tsx:19:1

Export paths: src/index.ts

@@ -38919,7 +38919,7 @@

Spacer

src/layout/Stack.tsx

Stack

-

src/layout/Stack.tsx:20:1

+

src/layout/Stack.tsx:19:1

No description available.

diff --git a/paradox/paradox.json b/paradox/paradox.json index 97183fd..7117bce 100644 --- a/paradox/paradox.json +++ b/paradox/paradox.json @@ -12,7 +12,7 @@ { "id": "npm", "label": "npm", - "value": "v2.1.1", + "value": "v2.2.0", "color": "cb3837" }, { @@ -11106,7 +11106,7 @@ "modulePath": "src/layout/Stack.tsx", "sourceLocation": { "filePath": "src/layout/Stack.tsx", - "line": 20, + "line": 19, "column": 1 }, "exportPaths": ["src/index.ts"], @@ -11138,7 +11138,7 @@ "modulePath": "src/layout/Stack.tsx", "sourceLocation": { "filePath": "src/layout/Stack.tsx", - "line": 9, + "line": 8, "column": 1 }, "exportPaths": ["src/index.ts"], @@ -23116,7 +23116,7 @@ "modulePath": "src/layout/Stack.tsx", "sourceLocation": { "filePath": "src/layout/Stack.tsx", - "line": 20, + "line": 19, "column": 1 }, "exportPaths": ["src/index.ts"], @@ -27877,7 +27877,7 @@ "description": null, "sourceLocation": { "filePath": "src/layout/Stack.tsx", - "line": 20, + "line": 19, "column": 1 } }, @@ -36383,13 +36383,7 @@ { "fromComponent": "Stack", "toComponent": "Box", - "jsxElement": "", - "sourcePath": "src/layout/Stack.tsx" - }, - { - "fromComponent": "Stack", - "toComponent": "View", - "jsxElement": "", + "jsxElement": "", "sourcePath": "src/layout/Stack.tsx" }, {