@startupjs-ui/div 0.3.1 → 0.3.4
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 +11 -0
- package/index.d.ts +7 -0
- package/index.tsx +42 -2
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.3.4](https://github.com/startupjs/startupjs-ui/compare/v0.3.3...v0.3.4) (2026-06-18)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **div, span:** supportTextNodes auto-wrap on Div + pure mode on Span ([#35](https://github.com/startupjs/startupjs-ui/issues/35)) ([d7bf159](https://github.com/startupjs/startupjs-ui/commit/d7bf159e73060a2531f2a1d66ec1932e9ddc3e6f))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
## [0.3.1](https://github.com/startupjs/startupjs-ui/compare/v0.3.0...v0.3.1) (2026-06-08)
|
|
7
18
|
|
|
8
19
|
|
package/index.d.ts
CHANGED
|
@@ -19,6 +19,13 @@ export interface DivProps extends Omit<ViewProps, 'role'> {
|
|
|
19
19
|
style?: StyleProp<ViewStyle>;
|
|
20
20
|
/** Content rendered inside Div */
|
|
21
21
|
children?: ReactNode;
|
|
22
|
+
/** Auto-wrap bare text children. When true, runs of consecutive string/number
|
|
23
|
+
* children (including those inside arrays/fragments) are each wrapped into a
|
|
24
|
+
* single text node so they render correctly in a non-text container. @default false */
|
|
25
|
+
supportTextNodes?: boolean;
|
|
26
|
+
/** How to render an auto-wrapped text run (only used with supportTextNodes).
|
|
27
|
+
* Receives the merged text; should return a text element. Defaults to <Span/>. */
|
|
28
|
+
renderTextNode?: (text: string) => ReactNode;
|
|
22
29
|
/** Visual feedback variant @default 'opacity' */
|
|
23
30
|
variant?: 'opacity' | 'highlight';
|
|
24
31
|
/** Render children in a horizontal row */
|
package/index.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useContext, useLayoutEffect, useMemo, useState, useRef, type ReactNode, type RefObject } from 'react'
|
|
1
|
+
import { Children, cloneElement, createElement, Fragment, isValidElement, useContext, useLayoutEffect, useMemo, useState, useRef, type ReactNode, type RefObject } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
View,
|
|
4
4
|
Pressable,
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
mergeInheritedTextStyles,
|
|
18
18
|
omitInheritedTextStyle
|
|
19
19
|
} from '@startupjs-ui/span/textStyleContext'
|
|
20
|
+
import Span from '@startupjs-ui/span'
|
|
20
21
|
import { useDecorateTooltipProps } from './useTooltip'
|
|
21
22
|
import STYLES from './index.cssx.styl'
|
|
22
23
|
|
|
@@ -51,6 +52,13 @@ export interface DivProps extends Omit<ViewProps, 'role'> {
|
|
|
51
52
|
style?: StyleProp<ViewStyle>
|
|
52
53
|
/** Content rendered inside Div */
|
|
53
54
|
children?: ReactNode
|
|
55
|
+
/** Auto-wrap bare text children. When true, runs of consecutive string/number
|
|
56
|
+
* children (including those inside arrays/fragments) are each wrapped into a
|
|
57
|
+
* single text node so they render correctly in a non-text container. @default false */
|
|
58
|
+
supportTextNodes?: boolean
|
|
59
|
+
/** How to render an auto-wrapped text run (only used with supportTextNodes).
|
|
60
|
+
* Receives the merged text; should return a text element. Defaults to <Span/>. */
|
|
61
|
+
renderTextNode?: (text: string) => ReactNode
|
|
54
62
|
/** Visual feedback variant @default 'opacity' */
|
|
55
63
|
variant?: 'opacity' | 'highlight'
|
|
56
64
|
/** Render children in a horizontal row */
|
|
@@ -106,6 +114,8 @@ export interface DivProps extends Omit<ViewProps, 'role'> {
|
|
|
106
114
|
function Div ({
|
|
107
115
|
style: rawStyle = [],
|
|
108
116
|
children,
|
|
117
|
+
supportTextNodes = false,
|
|
118
|
+
renderTextNode,
|
|
109
119
|
variant = 'opacity',
|
|
110
120
|
row,
|
|
111
121
|
wrap,
|
|
@@ -131,6 +141,7 @@ function Div ({
|
|
|
131
141
|
...props
|
|
132
142
|
}: DivProps): ReactNode {
|
|
133
143
|
assertDeprecatedValues({ pushed, renderTooltip })
|
|
144
|
+
const renderedChildren = supportTextNodes ? wrapTextChildren(children, renderTextNode) : children
|
|
134
145
|
let style = StyleSheet.flatten(rawStyle) as ViewStyle | undefined
|
|
135
146
|
// on RN row-reverse switches margins and paddings sides, so we switch them back
|
|
136
147
|
if (isNative && reverse) style = reverseMarginPaddingSides(style)
|
|
@@ -230,7 +241,7 @@ function Div ({
|
|
|
230
241
|
]
|
|
231
242
|
accessible=accessible
|
|
232
243
|
...renderProps
|
|
233
|
-
)=
|
|
244
|
+
)= renderedChildren
|
|
234
245
|
`
|
|
235
246
|
const styledDivElement = nextInheritedTextStyle
|
|
236
247
|
? pug`
|
|
@@ -247,6 +258,35 @@ function Div ({
|
|
|
247
258
|
} else return styledDivElement
|
|
248
259
|
}
|
|
249
260
|
|
|
261
|
+
// Auto-wrap bare text so it renders in a non-text container. Each maximal run of
|
|
262
|
+
// consecutive string/number children is merged into one text node (so 'a {x} b'
|
|
263
|
+
// becomes one line, not three stacked nodes); element children break a run;
|
|
264
|
+
// fragments are traversed inline; arrays are already flattened by React.Children.
|
|
265
|
+
function wrapTextChildren (children: ReactNode, renderTextNode?: (text: string) => ReactNode): ReactNode {
|
|
266
|
+
const out: ReactNode[] = []
|
|
267
|
+
let run = ''
|
|
268
|
+
let key = 0
|
|
269
|
+
const flush = () => {
|
|
270
|
+
if (run === '') return
|
|
271
|
+
const text = run
|
|
272
|
+
run = ''
|
|
273
|
+
const node = renderTextNode ? renderTextNode(text) : createElement(Span, null, text)
|
|
274
|
+
out.push(isValidElement(node) ? cloneElement(node, { key: `__t${key++}` }) : node)
|
|
275
|
+
}
|
|
276
|
+
const walk = (nodes: ReactNode) => {
|
|
277
|
+
Children.forEach(nodes, child => {
|
|
278
|
+
if (child == null || typeof child === 'boolean') return
|
|
279
|
+
if (typeof child === 'string' || typeof child === 'number') { run += String(child); return }
|
|
280
|
+
if (isValidElement(child) && child.type === Fragment) { walk((child.props as { children?: ReactNode }).children); return }
|
|
281
|
+
flush()
|
|
282
|
+
out.push(isValidElement(child) && child.key == null ? cloneElement(child, { key: `__e${key++}` }) : child)
|
|
283
|
+
})
|
|
284
|
+
}
|
|
285
|
+
walk(children)
|
|
286
|
+
flush()
|
|
287
|
+
return out
|
|
288
|
+
}
|
|
289
|
+
|
|
250
290
|
function isWebOnlyRole (role: unknown): role is Exclude<UIRole, ViewProps['role']> {
|
|
251
291
|
return role === 'listbox' || role === 'gridcell'
|
|
252
292
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@startupjs-ui/div",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@startupjs-ui/abstract-popover": "^0.3.0",
|
|
16
16
|
"@startupjs-ui/core": "^0.3.0",
|
|
17
|
-
"@startupjs-ui/span": "^0.3.
|
|
17
|
+
"@startupjs-ui/span": "^0.3.4"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"react": "*",
|
|
@@ -22,5 +22,5 @@
|
|
|
22
22
|
"react-native-reanimated": ">=4.0.0",
|
|
23
23
|
"startupjs": "*"
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "ad84ad14d189280a9ce4618b3223093fd09ba60e"
|
|
26
26
|
}
|