react-solidlike 2.2.4 → 2.3.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/README.en.md CHANGED
@@ -166,6 +166,48 @@ import { Repeat } from "react-solidlike";
166
166
  </Repeat>
167
167
  ```
168
168
 
169
+ ### `<Split>` - String Split Rendering
170
+
171
+ Split a string by separator and render each part.
172
+
173
+ ```tsx
174
+ import { Split } from "react-solidlike";
175
+
176
+ // Basic usage - splits without keeping separator
177
+ <Split string="a,b,c" separator=",">
178
+ {(part) => <span>{part}</span>}
179
+ </Split>
180
+ // Renders: ["a", "b", "c"]
181
+
182
+ // Keep separator in result
183
+ <Split string="9+5=(9+1)+4" separator="=" keepSeparator>
184
+ {(part) => <span>{part}</span>}
185
+ </Split>
186
+ // Renders: ["9+5", "=", "(9+1)+4"]
187
+
188
+ // Using RegExp separator
189
+ <Split string="a1b2c3" separator={/\d/} keepSeparator>
190
+ {(part) => <span>{part}</span>}
191
+ </Split>
192
+ // Renders: ["a", "1", "b", "2", "c", "3"]
193
+
194
+ // With wrapper element
195
+ <Split string="hello world" separator=" " wrapper={<div className="words" />}>
196
+ {(word) => <span>{word}</span>}
197
+ </Split>
198
+
199
+ // With fallback for empty string
200
+ <Split string={text} separator="," fallback={<EmptyState />}>
201
+ {(part) => <Tag>{part}</Tag>}
202
+ </Split>
203
+
204
+ // Reverse rendering
205
+ <Split string="a,b,c" separator="," reverse>
206
+ {(part) => <span>{part}</span>}
207
+ </Split>
208
+ // Render order: ["c", "b", "a"]
209
+ ```
210
+
169
211
  ### `<Dynamic>` - Dynamic Component
170
212
 
171
213
  Dynamically select component type based on conditions.
package/README.md CHANGED
@@ -166,6 +166,48 @@ import { Repeat } from "react-solidlike";
166
166
  </Repeat>
167
167
  ```
168
168
 
169
+ ### `<Split>` - 字符串切割渲染
170
+
171
+ 按分隔符切割字符串并渲染每个部分。
172
+
173
+ ```tsx
174
+ import { Split } from "react-solidlike";
175
+
176
+ // 基础用法 - 切割后不保留分隔符
177
+ <Split string="a,b,c" separator=",">
178
+ {(part) => <span>{part}</span>}
179
+ </Split>
180
+ // 渲染: ["a", "b", "c"]
181
+
182
+ // 保留分隔符
183
+ <Split string="9+5=(9+1)+4" separator="=" keepSeparator>
184
+ {(part) => <span>{part}</span>}
185
+ </Split>
186
+ // 渲染: ["9+5", "=", "(9+1)+4"]
187
+
188
+ // 使用正则表达式分隔符
189
+ <Split string="a1b2c3" separator={/\d/} keepSeparator>
190
+ {(part) => <span>{part}</span>}
191
+ </Split>
192
+ // 渲染: ["a", "1", "b", "2", "c", "3"]
193
+
194
+ // 带 wrapper 包装元素
195
+ <Split string="hello world" separator=" " wrapper={<div className="words" />}>
196
+ {(word) => <span>{word}</span>}
197
+ </Split>
198
+
199
+ // 带 fallback 处理空字符串
200
+ <Split string={text} separator="," fallback={<EmptyState />}>
201
+ {(part) => <Tag>{part}</Tag>}
202
+ </Split>
203
+
204
+ // 倒序渲染
205
+ <Split string="a,b,c" separator="," reverse>
206
+ {(part) => <span>{part}</span>}
207
+ </Split>
208
+ // 渲染顺序: ["c", "b", "a"]
209
+ ```
210
+
169
211
  ### `<Dynamic>` - 动态组件
170
212
 
171
213
  根据条件动态选择要渲染的组件类型。
package/dist/Repeat.d.ts CHANGED
@@ -1,13 +1,8 @@
1
- import { type ReactElement, type ReactNode } from "react";
2
- export interface RepeatProps {
1
+ import type { ReactNode } from 'react';
2
+ import { type ForProps } from './For';
3
+ export interface RepeatProps extends Omit<ForProps<number>, 'each'> {
3
4
  /** Number of times to repeat | 重复次数 */
4
5
  times: number;
5
- /** Render function, receives current index and total length | 渲染函数,接收当前索引和总长度 */
6
- children: (index: number, length: number) => ReactNode;
7
- /** Wrapper element for all rendered elements | 包装所有渲染元素的元素 */
8
- wrapper?: ReactElement;
9
- /** Reverse the rendering order | 倒序渲染 */
10
- reverse?: boolean;
11
6
  }
12
7
  /**
13
8
  * Repeat rendering component, replaces Array.from({ length: n }).map()
@@ -38,4 +33,4 @@ export interface RepeatProps {
38
33
  * {(i) => <Star key={i} />}
39
34
  * </Repeat>
40
35
  */
41
- export declare function Repeat({ times, children, wrapper, reverse }: RepeatProps): ReactNode;
36
+ export declare function Repeat({ times, children, ...props }: RepeatProps): ReactNode;
@@ -0,0 +1,49 @@
1
+ import type { ReactNode } from 'react';
2
+ import { type ForProps } from './For';
3
+ export interface SplitProps extends Omit<ForProps<string>, 'each'> {
4
+ /** String to split | 要切割的字符串 */
5
+ string: string | null | undefined;
6
+ /** Separator to split by, can be string or RegExp | 分隔符,可以是字符串或正则表达式 */
7
+ separator: string | RegExp;
8
+ /** Whether to keep separator in result array | 是否在结果数组中保留分隔符 */
9
+ keepSeparator?: boolean;
10
+ }
11
+ /**
12
+ * String splitting and rendering component, splits a string by separator and renders each part
13
+ *
14
+ * 字符串切割渲染组件,按分隔符切割字符串并渲染每个部分
15
+ *
16
+ * @example
17
+ * // Basic usage | 基础用法
18
+ * <Split string="a,b,c" separator=",">
19
+ * {(part) => <span>{part}</span>}
20
+ * </Split>
21
+ *
22
+ * @example
23
+ * // Keep separator | 保留分隔符
24
+ * <Split string="9+5=(9+1)+4" separator="=" keepSeparator>
25
+ * {(part) => <span>{part}</span>}
26
+ * </Split>
27
+ * // Renders: ["9+5", "=", "(9+1)+4"]
28
+ *
29
+ * @example
30
+ * // Without keeping separator | 不保留分隔符
31
+ * <Split string="9+5=(9+1)+4" separator="=">
32
+ * {(part) => <span>{part}</span>}
33
+ * </Split>
34
+ * // Renders: ["9+5", "(9+1)+4"]
35
+ *
36
+ * @example
37
+ * // With RegExp separator | 使用正则表达式分隔符
38
+ * <Split string="a1b2c3" separator={/\d/} keepSeparator>
39
+ * {(part) => <span>{part}</span>}
40
+ * </Split>
41
+ * // Renders: ["a", "1", "b", "2", "c", "3"]
42
+ *
43
+ * @example
44
+ * // With wrapper element | 使用包装元素
45
+ * <Split string="hello world" separator=" " wrapper={<div className="words" />}>
46
+ * {(word) => <span>{word}</span>}
47
+ * </Split>
48
+ */
49
+ export declare function Split({ string, separator, keepSeparator, children, ...props }: SplitProps): ReactNode;
package/dist/index.d.ts CHANGED
@@ -5,4 +5,5 @@ export { For, type ForProps } from "./For";
5
5
  export { QueryBoundary, type QueryBoundaryProps, type QueryResult } from "./QueryBoundary";
6
6
  export { Repeat, type RepeatProps } from "./Repeat";
7
7
  export { Show, type ShowProps } from "./Show";
8
+ export { Split, type SplitProps } from "./Split";
8
9
  export { Default, type DefaultProps, Match, type MatchProps, Switch, type SwitchProps } from "./Switch";
package/dist/index.js CHANGED
@@ -103,12 +103,13 @@ function QueryBoundary({ query, loading = null, error = null, empty = null, chil
103
103
  return children;
104
104
  }
105
105
 
106
- function Repeat({ times, children, wrapper, reverse }) {
107
- if (times <= 0) return null;
108
- const elements = [];
109
- if (reverse) for (let i = times - 1; i >= 0; i--) elements.push(/* @__PURE__ */ jsx(Fragment, { children: children(i, times) }, i));
110
- else for (let i = 0; i < times; i++) elements.push(/* @__PURE__ */ jsx(Fragment, { children: children(i, times) }, i));
111
- return wrapper && isValidElement(wrapper) ? cloneElement(wrapper, {}, elements) : elements;
106
+ function Repeat({ times, children, ...props }) {
107
+ const indices = times > 0 ? Array.from({ length: times }, (_, i) => i) : [];
108
+ return /* @__PURE__ */ jsx(For, {
109
+ ...props,
110
+ each: indices,
111
+ children: (i, _i, array) => children(i, array.length, array)
112
+ });
112
113
  }
113
114
 
114
115
  function Show({ when, children, fallback = null }) {
@@ -123,6 +124,28 @@ function isEmpty(value) {
123
124
  return false;
124
125
  }
125
126
 
127
+ function Split({ string, separator, keepSeparator = false, children, ...props }) {
128
+ const parts = splitString(string, separator, keepSeparator);
129
+ return /* @__PURE__ */ jsx(For, {
130
+ ...props,
131
+ each: parts,
132
+ children
133
+ });
134
+ }
135
+
136
+ function splitString(string, separator, keepSeparator) {
137
+ if (!string) return [];
138
+ if (keepSeparator) {
139
+ const regex = separator instanceof RegExp ? new RegExp(`(${separator.source})`, separator.flags.includes("g") ? separator.flags : `${separator.flags}g`) : new RegExp(`(${escapeRegExp(separator)})`, "g");
140
+ return string.split(regex).filter((part) => part !== "");
141
+ }
142
+ return string.split(separator);
143
+ }
144
+
145
+ function escapeRegExp(str) {
146
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
147
+ }
148
+
126
149
  function Match(_props) {
127
150
  return null;
128
151
  }
@@ -158,4 +181,4 @@ function Switch({ children, fallback = null }) {
158
181
  return defaultContent;
159
182
  }
160
183
 
161
- export { Await, Default, Dynamic, ErrorBoundary, For, Match, QueryBoundary, Repeat, Show, Switch };
184
+ export { Await, Default, Dynamic, ErrorBoundary, For, Match, QueryBoundary, Repeat, Show, Split, Switch };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-solidlike",
3
- "version": "2.2.4",
3
+ "version": "2.3.0",
4
4
  "description": "Declarative React control flow components inspired by Solid.js, replacing ternary expressions and array.map() in JSX",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",