@xaui/native 0.0.20 → 0.0.21
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/dist/list/index.cjs +470 -0
- package/dist/list/index.d.cts +188 -0
- package/dist/list/index.d.ts +188 -0
- package/dist/list/index.js +395 -0
- package/package.json +6 -1
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/components/list/index.ts
|
|
31
|
+
var list_exports = {};
|
|
32
|
+
__export(list_exports, {
|
|
33
|
+
List: () => List,
|
|
34
|
+
ListBuilder: () => ListBuilder,
|
|
35
|
+
ListItem: () => ListItem
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(list_exports);
|
|
38
|
+
|
|
39
|
+
// src/components/list/list.tsx
|
|
40
|
+
var import_react8 = __toESM(require("react"), 1);
|
|
41
|
+
var import_react_native6 = require("react-native");
|
|
42
|
+
|
|
43
|
+
// src/components/list/list-context.ts
|
|
44
|
+
var import_react = require("react");
|
|
45
|
+
var ListContext = (0, import_react.createContext)(null);
|
|
46
|
+
|
|
47
|
+
// src/components/list/list.style.ts
|
|
48
|
+
var import_react_native = require("react-native");
|
|
49
|
+
var styles = import_react_native.StyleSheet.create({
|
|
50
|
+
list: {
|
|
51
|
+
flex: 1
|
|
52
|
+
},
|
|
53
|
+
item: {
|
|
54
|
+
flexDirection: "row",
|
|
55
|
+
alignItems: "center",
|
|
56
|
+
gap: 12
|
|
57
|
+
},
|
|
58
|
+
content: {
|
|
59
|
+
flex: 1,
|
|
60
|
+
gap: 2
|
|
61
|
+
},
|
|
62
|
+
title: {
|
|
63
|
+
fontWeight: "500"
|
|
64
|
+
},
|
|
65
|
+
description: {
|
|
66
|
+
opacity: 0.7
|
|
67
|
+
},
|
|
68
|
+
disabled: {
|
|
69
|
+
opacity: 0.5
|
|
70
|
+
},
|
|
71
|
+
divider: {
|
|
72
|
+
height: 1,
|
|
73
|
+
marginLeft: 10
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// src/components/list/list-divider.tsx
|
|
78
|
+
var import_react7 = __toESM(require("react"), 1);
|
|
79
|
+
var import_react_native5 = require("react-native");
|
|
80
|
+
|
|
81
|
+
// src/core/theme-context.tsx
|
|
82
|
+
var import_react5 = __toESM(require("react"), 1);
|
|
83
|
+
var import_react_native3 = require("react-native");
|
|
84
|
+
var import_theme = require("@xaui/core/theme");
|
|
85
|
+
var import_palette = require("@xaui/core/palette");
|
|
86
|
+
|
|
87
|
+
// src/core/portal/portal.tsx
|
|
88
|
+
var import_react3 = require("react");
|
|
89
|
+
|
|
90
|
+
// src/core/portal/portal-context.ts
|
|
91
|
+
var import_react2 = require("react");
|
|
92
|
+
var PortalContext = (0, import_react2.createContext)(null);
|
|
93
|
+
|
|
94
|
+
// src/core/portal/portal-host.tsx
|
|
95
|
+
var import_react4 = __toESM(require("react"), 1);
|
|
96
|
+
var import_react_native2 = require("react-native");
|
|
97
|
+
var hostStyles = import_react_native2.StyleSheet.create({
|
|
98
|
+
container: {
|
|
99
|
+
flex: 1
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// src/core/theme-context.tsx
|
|
104
|
+
var XUIThemeContext = (0, import_react5.createContext)(null);
|
|
105
|
+
|
|
106
|
+
// src/core/theme-hooks.ts
|
|
107
|
+
var import_react6 = require("react");
|
|
108
|
+
var import_react_native4 = require("react-native");
|
|
109
|
+
function useXUITheme() {
|
|
110
|
+
const theme = (0, import_react6.useContext)(XUIThemeContext);
|
|
111
|
+
if (!theme) {
|
|
112
|
+
throw new Error("useXUITheme must be used within XUIProvider");
|
|
113
|
+
}
|
|
114
|
+
return theme;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/core/index.ts
|
|
118
|
+
var import_theme2 = require("@xaui/core/theme");
|
|
119
|
+
|
|
120
|
+
// src/components/list/list-divider.tsx
|
|
121
|
+
var ListDivider = () => {
|
|
122
|
+
const theme = useXUITheme();
|
|
123
|
+
return /* @__PURE__ */ import_react7.default.createElement(
|
|
124
|
+
import_react_native5.View,
|
|
125
|
+
{
|
|
126
|
+
style: [styles.divider, { backgroundColor: theme.colors.foreground + "30" }]
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
var ListChildren = ({ children, showDivider }) => {
|
|
131
|
+
if (!showDivider) {
|
|
132
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, children);
|
|
133
|
+
}
|
|
134
|
+
const childArray = import_react7.Children.toArray(children);
|
|
135
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, childArray.map((child, index) => /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, { key: index }, child, index < childArray.length - 1 && /* @__PURE__ */ import_react7.default.createElement(ListDivider, null))));
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// src/components/list/list.tsx
|
|
139
|
+
var List = ({
|
|
140
|
+
children,
|
|
141
|
+
selectionMode = "none",
|
|
142
|
+
selectedKeys: controlledSelectedKeys,
|
|
143
|
+
defaultSelectedKeys = [],
|
|
144
|
+
showDivider = false,
|
|
145
|
+
isPressable = true,
|
|
146
|
+
isSelectable = false,
|
|
147
|
+
themeColor = "primary",
|
|
148
|
+
size = "md",
|
|
149
|
+
onSelectionChange,
|
|
150
|
+
style
|
|
151
|
+
}) => {
|
|
152
|
+
const isControlled = controlledSelectedKeys !== void 0;
|
|
153
|
+
const [internalSelectedKeys, setInternalSelectedKeys] = (0, import_react8.useState)(defaultSelectedKeys);
|
|
154
|
+
const selectedKeys = isControlled ? controlledSelectedKeys : internalSelectedKeys;
|
|
155
|
+
const isSelected = (0, import_react8.useCallback)(
|
|
156
|
+
(key) => {
|
|
157
|
+
return selectedKeys.includes(key);
|
|
158
|
+
},
|
|
159
|
+
[selectedKeys]
|
|
160
|
+
);
|
|
161
|
+
const toggleSelection = (0, import_react8.useCallback)(
|
|
162
|
+
(key) => {
|
|
163
|
+
if (selectionMode === "none" || !isSelectable) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
let newSelectedKeys;
|
|
167
|
+
if (selectionMode === "single") {
|
|
168
|
+
newSelectedKeys = isSelected(key) ? [] : [key];
|
|
169
|
+
} else {
|
|
170
|
+
newSelectedKeys = isSelected(key) ? selectedKeys.filter((k) => k !== key) : [...selectedKeys, key];
|
|
171
|
+
}
|
|
172
|
+
if (!isControlled) {
|
|
173
|
+
setInternalSelectedKeys(newSelectedKeys);
|
|
174
|
+
}
|
|
175
|
+
onSelectionChange?.(newSelectedKeys);
|
|
176
|
+
},
|
|
177
|
+
[
|
|
178
|
+
selectionMode,
|
|
179
|
+
isSelectable,
|
|
180
|
+
isSelected,
|
|
181
|
+
selectedKeys,
|
|
182
|
+
isControlled,
|
|
183
|
+
onSelectionChange
|
|
184
|
+
]
|
|
185
|
+
);
|
|
186
|
+
const contextValue = (0, import_react8.useMemo)(
|
|
187
|
+
() => ({
|
|
188
|
+
selectionMode,
|
|
189
|
+
selectedKeys,
|
|
190
|
+
isPressable,
|
|
191
|
+
isSelectable,
|
|
192
|
+
themeColor,
|
|
193
|
+
size,
|
|
194
|
+
showDivider,
|
|
195
|
+
toggleSelection,
|
|
196
|
+
isSelected
|
|
197
|
+
}),
|
|
198
|
+
[
|
|
199
|
+
selectionMode,
|
|
200
|
+
selectedKeys,
|
|
201
|
+
isPressable,
|
|
202
|
+
isSelectable,
|
|
203
|
+
themeColor,
|
|
204
|
+
size,
|
|
205
|
+
showDivider,
|
|
206
|
+
toggleSelection,
|
|
207
|
+
isSelected
|
|
208
|
+
]
|
|
209
|
+
);
|
|
210
|
+
return /* @__PURE__ */ import_react8.default.createElement(ListContext.Provider, { value: contextValue }, /* @__PURE__ */ import_react8.default.createElement(import_react_native6.View, { style: [styles.list, style] }, /* @__PURE__ */ import_react8.default.createElement(ListChildren, { showDivider }, children)));
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// src/components/list/list-item.tsx
|
|
214
|
+
var import_react10 = __toESM(require("react"), 1);
|
|
215
|
+
var import_react_native7 = require("react-native");
|
|
216
|
+
|
|
217
|
+
// src/components/list/list.hook.ts
|
|
218
|
+
var import_react9 = require("react");
|
|
219
|
+
var useListItemSizeStyles = (size) => {
|
|
220
|
+
const theme = useXUITheme();
|
|
221
|
+
return (0, import_react9.useMemo)(() => {
|
|
222
|
+
const sizes = {
|
|
223
|
+
xs: {
|
|
224
|
+
paddingVertical: theme.spacing.sm,
|
|
225
|
+
paddingHorizontal: theme.spacing.sm,
|
|
226
|
+
titleSize: theme.fontSizes.xs,
|
|
227
|
+
descriptionSize: theme.fontSizes.xs
|
|
228
|
+
},
|
|
229
|
+
sm: {
|
|
230
|
+
paddingVertical: theme.spacing.sm,
|
|
231
|
+
paddingHorizontal: theme.spacing.md,
|
|
232
|
+
titleSize: theme.fontSizes.sm,
|
|
233
|
+
descriptionSize: theme.fontSizes.xs
|
|
234
|
+
},
|
|
235
|
+
md: {
|
|
236
|
+
paddingVertical: theme.spacing.md,
|
|
237
|
+
paddingHorizontal: theme.spacing.md,
|
|
238
|
+
titleSize: theme.fontSizes.md,
|
|
239
|
+
descriptionSize: theme.fontSizes.sm
|
|
240
|
+
},
|
|
241
|
+
lg: {
|
|
242
|
+
paddingVertical: theme.spacing.lg,
|
|
243
|
+
paddingHorizontal: theme.spacing.lg,
|
|
244
|
+
titleSize: theme.fontSizes.lg,
|
|
245
|
+
descriptionSize: theme.fontSizes.md
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
return sizes[size];
|
|
249
|
+
}, [size, theme]);
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// src/components/list/list-item.tsx
|
|
253
|
+
var import_core3 = require("@xaui/core");
|
|
254
|
+
var ListItem = ({
|
|
255
|
+
itemKey,
|
|
256
|
+
title,
|
|
257
|
+
description,
|
|
258
|
+
startContent,
|
|
259
|
+
endContent,
|
|
260
|
+
isDisabled = false,
|
|
261
|
+
isSelected: propIsSelected,
|
|
262
|
+
customAppearance,
|
|
263
|
+
onPress
|
|
264
|
+
}) => {
|
|
265
|
+
const context = (0, import_react10.useContext)(ListContext);
|
|
266
|
+
const theme = useXUITheme();
|
|
267
|
+
const selectionMode = context?.selectionMode ?? "none";
|
|
268
|
+
const isPressable = context?.isPressable ?? true;
|
|
269
|
+
const isSelectable = context?.isSelectable ?? false;
|
|
270
|
+
const themeColor = context?.themeColor ?? "primary";
|
|
271
|
+
const size = context?.size ?? "md";
|
|
272
|
+
const isSelected = propIsSelected ?? (context ? context.isSelected(itemKey) : false);
|
|
273
|
+
const sizeStyles = useListItemSizeStyles(size);
|
|
274
|
+
const safeThemeColor = (0, import_core3.getSafeThemeColor)(themeColor);
|
|
275
|
+
const colorScheme = theme.colors[safeThemeColor];
|
|
276
|
+
const backgroundColor = isSelected ? colorScheme.background : "transparent";
|
|
277
|
+
const titleColor = isDisabled ? theme.colors.foreground + "50" : theme.colors.foreground;
|
|
278
|
+
const descriptionColor = isDisabled ? theme.colors.foreground + "50" : theme.colors.foreground + "99";
|
|
279
|
+
const handlePress = () => {
|
|
280
|
+
if (isDisabled) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
if (isSelectable && selectionMode !== "none") {
|
|
284
|
+
context?.toggleSelection(itemKey);
|
|
285
|
+
}
|
|
286
|
+
onPress?.({});
|
|
287
|
+
};
|
|
288
|
+
const renderTitle = () => {
|
|
289
|
+
if (typeof title === "string" || typeof title === "number") {
|
|
290
|
+
return /* @__PURE__ */ import_react10.default.createElement(
|
|
291
|
+
import_react_native7.Text,
|
|
292
|
+
{
|
|
293
|
+
style: [
|
|
294
|
+
styles.title,
|
|
295
|
+
{ fontSize: sizeStyles.titleSize, color: titleColor },
|
|
296
|
+
customAppearance?.title
|
|
297
|
+
],
|
|
298
|
+
numberOfLines: 1
|
|
299
|
+
},
|
|
300
|
+
title
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
return title;
|
|
304
|
+
};
|
|
305
|
+
const renderDescription = () => {
|
|
306
|
+
if (!description) return null;
|
|
307
|
+
if (typeof description === "string" || typeof description === "number") {
|
|
308
|
+
return /* @__PURE__ */ import_react10.default.createElement(
|
|
309
|
+
import_react_native7.Text,
|
|
310
|
+
{
|
|
311
|
+
style: [
|
|
312
|
+
styles.description,
|
|
313
|
+
{ fontSize: sizeStyles.descriptionSize, color: descriptionColor },
|
|
314
|
+
customAppearance?.description
|
|
315
|
+
],
|
|
316
|
+
numberOfLines: 2
|
|
317
|
+
},
|
|
318
|
+
description
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
return description;
|
|
322
|
+
};
|
|
323
|
+
const content = /* @__PURE__ */ import_react10.default.createElement(
|
|
324
|
+
import_react_native7.View,
|
|
325
|
+
{
|
|
326
|
+
style: [
|
|
327
|
+
styles.item,
|
|
328
|
+
{
|
|
329
|
+
paddingVertical: sizeStyles.paddingVertical,
|
|
330
|
+
paddingHorizontal: sizeStyles.paddingHorizontal,
|
|
331
|
+
backgroundColor
|
|
332
|
+
},
|
|
333
|
+
isDisabled && styles.disabled,
|
|
334
|
+
customAppearance?.container
|
|
335
|
+
]
|
|
336
|
+
},
|
|
337
|
+
startContent && /* @__PURE__ */ import_react10.default.createElement(import_react_native7.View, { style: customAppearance?.content }, startContent),
|
|
338
|
+
/* @__PURE__ */ import_react10.default.createElement(import_react_native7.View, { style: [styles.content, customAppearance?.content] }, renderTitle(), renderDescription()),
|
|
339
|
+
endContent && /* @__PURE__ */ import_react10.default.createElement(import_react_native7.View, { style: customAppearance?.content }, endContent)
|
|
340
|
+
);
|
|
341
|
+
if (!isPressable) {
|
|
342
|
+
return content;
|
|
343
|
+
}
|
|
344
|
+
return /* @__PURE__ */ import_react10.default.createElement(
|
|
345
|
+
import_react_native7.Pressable,
|
|
346
|
+
{
|
|
347
|
+
onPress: handlePress,
|
|
348
|
+
disabled: isDisabled,
|
|
349
|
+
style: ({ pressed }) => [
|
|
350
|
+
pressed && !isDisabled && {
|
|
351
|
+
backgroundColor: theme.colors.foreground + "10"
|
|
352
|
+
}
|
|
353
|
+
]
|
|
354
|
+
},
|
|
355
|
+
content
|
|
356
|
+
);
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// src/components/list/list-builder.tsx
|
|
360
|
+
var import_react11 = __toESM(require("react"), 1);
|
|
361
|
+
var import_react_native8 = require("react-native");
|
|
362
|
+
function ListBuilder({
|
|
363
|
+
data,
|
|
364
|
+
keyExtractor,
|
|
365
|
+
renderItem,
|
|
366
|
+
selectionMode = "none",
|
|
367
|
+
selectedKeys: controlledSelectedKeys,
|
|
368
|
+
defaultSelectedKeys = [],
|
|
369
|
+
showDivider = false,
|
|
370
|
+
isPressable = true,
|
|
371
|
+
isSelectable = false,
|
|
372
|
+
themeColor = "primary",
|
|
373
|
+
size = "md",
|
|
374
|
+
onSelectionChange,
|
|
375
|
+
style,
|
|
376
|
+
flatListProps
|
|
377
|
+
}) {
|
|
378
|
+
const theme = useXUITheme();
|
|
379
|
+
const isControlled = controlledSelectedKeys !== void 0;
|
|
380
|
+
const [internalSelectedKeys, setInternalSelectedKeys] = (0, import_react11.useState)(defaultSelectedKeys);
|
|
381
|
+
const selectedKeys = isControlled ? controlledSelectedKeys : internalSelectedKeys;
|
|
382
|
+
const isSelected = (0, import_react11.useCallback)(
|
|
383
|
+
(key) => {
|
|
384
|
+
return selectedKeys.includes(key);
|
|
385
|
+
},
|
|
386
|
+
[selectedKeys]
|
|
387
|
+
);
|
|
388
|
+
const toggleSelection = (0, import_react11.useCallback)(
|
|
389
|
+
(key) => {
|
|
390
|
+
if (selectionMode === "none" || !isSelectable) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
let newSelectedKeys;
|
|
394
|
+
if (selectionMode === "single") {
|
|
395
|
+
newSelectedKeys = isSelected(key) ? [] : [key];
|
|
396
|
+
} else {
|
|
397
|
+
newSelectedKeys = isSelected(key) ? selectedKeys.filter((k) => k !== key) : [...selectedKeys, key];
|
|
398
|
+
}
|
|
399
|
+
if (!isControlled) {
|
|
400
|
+
setInternalSelectedKeys(newSelectedKeys);
|
|
401
|
+
}
|
|
402
|
+
onSelectionChange?.(newSelectedKeys);
|
|
403
|
+
},
|
|
404
|
+
[
|
|
405
|
+
selectionMode,
|
|
406
|
+
isSelectable,
|
|
407
|
+
isSelected,
|
|
408
|
+
selectedKeys,
|
|
409
|
+
isControlled,
|
|
410
|
+
onSelectionChange
|
|
411
|
+
]
|
|
412
|
+
);
|
|
413
|
+
const contextValue = (0, import_react11.useMemo)(
|
|
414
|
+
() => ({
|
|
415
|
+
selectionMode,
|
|
416
|
+
selectedKeys,
|
|
417
|
+
isPressable,
|
|
418
|
+
isSelectable,
|
|
419
|
+
themeColor,
|
|
420
|
+
size,
|
|
421
|
+
showDivider,
|
|
422
|
+
toggleSelection,
|
|
423
|
+
isSelected
|
|
424
|
+
}),
|
|
425
|
+
[
|
|
426
|
+
selectionMode,
|
|
427
|
+
selectedKeys,
|
|
428
|
+
isPressable,
|
|
429
|
+
isSelectable,
|
|
430
|
+
themeColor,
|
|
431
|
+
size,
|
|
432
|
+
showDivider,
|
|
433
|
+
toggleSelection,
|
|
434
|
+
isSelected
|
|
435
|
+
]
|
|
436
|
+
);
|
|
437
|
+
const renderListItem = (0, import_react11.useCallback)(
|
|
438
|
+
(item, index) => {
|
|
439
|
+
const element = renderItem(item, index);
|
|
440
|
+
if (!showDivider || index === data.length - 1) {
|
|
441
|
+
return /* @__PURE__ */ import_react11.default.createElement(import_react11.default.Fragment, { key: keyExtractor(item, index) }, element);
|
|
442
|
+
}
|
|
443
|
+
return /* @__PURE__ */ import_react11.default.createElement(import_react_native8.View, { key: keyExtractor(item, index) }, element, /* @__PURE__ */ import_react11.default.createElement(
|
|
444
|
+
import_react_native8.View,
|
|
445
|
+
{
|
|
446
|
+
style: [
|
|
447
|
+
styles.divider,
|
|
448
|
+
{ backgroundColor: theme.colors.foreground + "15" }
|
|
449
|
+
]
|
|
450
|
+
}
|
|
451
|
+
));
|
|
452
|
+
},
|
|
453
|
+
[data.length, keyExtractor, renderItem, showDivider, theme.colors.foreground]
|
|
454
|
+
);
|
|
455
|
+
return /* @__PURE__ */ import_react11.default.createElement(ListContext.Provider, { value: contextValue }, /* @__PURE__ */ import_react11.default.createElement(import_react_native8.View, { style: [styles.list, style] }, /* @__PURE__ */ import_react11.default.createElement(
|
|
456
|
+
import_react_native8.FlatList,
|
|
457
|
+
{
|
|
458
|
+
data,
|
|
459
|
+
keyExtractor,
|
|
460
|
+
renderItem: ({ item, index }) => renderListItem(item, index),
|
|
461
|
+
...flatListProps
|
|
462
|
+
}
|
|
463
|
+
)));
|
|
464
|
+
}
|
|
465
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
466
|
+
0 && (module.exports = {
|
|
467
|
+
List,
|
|
468
|
+
ListBuilder,
|
|
469
|
+
ListItem
|
|
470
|
+
});
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
import * as react_native from 'react-native';
|
|
3
|
+
import { ViewStyle, TextStyle, GestureResponderEvent } from 'react-native';
|
|
4
|
+
import { T as ThemeColor, S as Size } from '../index-BOw6tbkc.cjs';
|
|
5
|
+
|
|
6
|
+
type ListSelectionMode = 'single' | 'multiple' | 'none';
|
|
7
|
+
type ListItemCustomAppearance = {
|
|
8
|
+
/**
|
|
9
|
+
* Custom styles for the item container
|
|
10
|
+
*/
|
|
11
|
+
container?: ViewStyle;
|
|
12
|
+
/**
|
|
13
|
+
* Custom styles for the content container
|
|
14
|
+
*/
|
|
15
|
+
content?: ViewStyle;
|
|
16
|
+
/**
|
|
17
|
+
* Custom styles for the title text
|
|
18
|
+
*/
|
|
19
|
+
title?: TextStyle;
|
|
20
|
+
/**
|
|
21
|
+
* Custom styles for the description text
|
|
22
|
+
*/
|
|
23
|
+
description?: TextStyle;
|
|
24
|
+
};
|
|
25
|
+
type ListItemProps = {
|
|
26
|
+
/**
|
|
27
|
+
* Unique key for the item (used for selection)
|
|
28
|
+
*/
|
|
29
|
+
itemKey: string;
|
|
30
|
+
/**
|
|
31
|
+
* Title text for the ListItem
|
|
32
|
+
*/
|
|
33
|
+
title: ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* Optional description text
|
|
36
|
+
*/
|
|
37
|
+
description?: ReactNode;
|
|
38
|
+
/**
|
|
39
|
+
* Content to display at the start of the item
|
|
40
|
+
*/
|
|
41
|
+
startContent?: ReactNode;
|
|
42
|
+
/**
|
|
43
|
+
* Content to display at the end of the item
|
|
44
|
+
*/
|
|
45
|
+
endContent?: ReactNode;
|
|
46
|
+
/**
|
|
47
|
+
* Whether the item is disabled
|
|
48
|
+
* @default false
|
|
49
|
+
*/
|
|
50
|
+
isDisabled?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Whether the item is selected
|
|
53
|
+
* @default false
|
|
54
|
+
*/
|
|
55
|
+
isSelected?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Custom appearance styles for item parts
|
|
58
|
+
*/
|
|
59
|
+
customAppearance?: ListItemCustomAppearance;
|
|
60
|
+
/**
|
|
61
|
+
* Callback fired when the item is pressed
|
|
62
|
+
*/
|
|
63
|
+
onPress?: (event: GestureResponderEvent) => void;
|
|
64
|
+
};
|
|
65
|
+
type ListProps = {
|
|
66
|
+
/**
|
|
67
|
+
* List items
|
|
68
|
+
*/
|
|
69
|
+
children: ReactNode;
|
|
70
|
+
/**
|
|
71
|
+
* Selection mode for the list
|
|
72
|
+
* @default 'none'
|
|
73
|
+
*/
|
|
74
|
+
selectionMode?: ListSelectionMode;
|
|
75
|
+
/**
|
|
76
|
+
* Controlled selected keys
|
|
77
|
+
*/
|
|
78
|
+
selectedKeys?: string[];
|
|
79
|
+
/**
|
|
80
|
+
* Default selected keys (uncontrolled)
|
|
81
|
+
*/
|
|
82
|
+
defaultSelectedKeys?: string[];
|
|
83
|
+
/**
|
|
84
|
+
* Whether to show dividers between items
|
|
85
|
+
* @default false
|
|
86
|
+
*/
|
|
87
|
+
showDivider?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Whether items are pressable
|
|
90
|
+
* @default true
|
|
91
|
+
*/
|
|
92
|
+
isPressable?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Whether items are selectable
|
|
95
|
+
* @default false
|
|
96
|
+
*/
|
|
97
|
+
isSelectable?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Theme color for selected items
|
|
100
|
+
* @default 'primary'
|
|
101
|
+
*/
|
|
102
|
+
themeColor?: ThemeColor;
|
|
103
|
+
/**
|
|
104
|
+
* Size of the list items
|
|
105
|
+
* @default 'md'
|
|
106
|
+
*/
|
|
107
|
+
size?: Size;
|
|
108
|
+
/**
|
|
109
|
+
* Callback fired when selection changes
|
|
110
|
+
*/
|
|
111
|
+
onSelectionChange?: (keys: string[]) => void;
|
|
112
|
+
/**
|
|
113
|
+
* Custom styles for the list container
|
|
114
|
+
*/
|
|
115
|
+
style?: ViewStyle;
|
|
116
|
+
};
|
|
117
|
+
type ListBuilderProps<T> = {
|
|
118
|
+
/**
|
|
119
|
+
* Data array to render
|
|
120
|
+
*/
|
|
121
|
+
data: T[];
|
|
122
|
+
/**
|
|
123
|
+
* Function to extract unique key from item
|
|
124
|
+
*/
|
|
125
|
+
keyExtractor: (item: T, index: number) => string;
|
|
126
|
+
/**
|
|
127
|
+
* Function to render each item
|
|
128
|
+
*/
|
|
129
|
+
renderItem: (item: T, index: number) => ReactNode;
|
|
130
|
+
/**
|
|
131
|
+
* Selection mode for the list
|
|
132
|
+
* @default 'none'
|
|
133
|
+
*/
|
|
134
|
+
selectionMode?: ListSelectionMode;
|
|
135
|
+
/**
|
|
136
|
+
* Controlled selected keys
|
|
137
|
+
*/
|
|
138
|
+
selectedKeys?: string[];
|
|
139
|
+
/**
|
|
140
|
+
* Default selected keys (uncontrolled)
|
|
141
|
+
*/
|
|
142
|
+
defaultSelectedKeys?: string[];
|
|
143
|
+
/**
|
|
144
|
+
* Whether to show dividers between items
|
|
145
|
+
* @default false
|
|
146
|
+
*/
|
|
147
|
+
showDivider?: boolean;
|
|
148
|
+
/**
|
|
149
|
+
* Whether items are pressable
|
|
150
|
+
* @default true
|
|
151
|
+
*/
|
|
152
|
+
isPressable?: boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Whether items are selectable
|
|
155
|
+
* @default false
|
|
156
|
+
*/
|
|
157
|
+
isSelectable?: boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Theme color for selected items
|
|
160
|
+
* @default 'primary'
|
|
161
|
+
*/
|
|
162
|
+
themeColor?: ThemeColor;
|
|
163
|
+
/**
|
|
164
|
+
* Size of the list items
|
|
165
|
+
* @default 'md'
|
|
166
|
+
*/
|
|
167
|
+
size?: Size;
|
|
168
|
+
/**
|
|
169
|
+
* Callback fired when selection changes
|
|
170
|
+
*/
|
|
171
|
+
onSelectionChange?: (keys: string[]) => void;
|
|
172
|
+
/**
|
|
173
|
+
* Custom styles for the list container
|
|
174
|
+
*/
|
|
175
|
+
style?: ViewStyle;
|
|
176
|
+
/**
|
|
177
|
+
* FlatList props to pass through
|
|
178
|
+
*/
|
|
179
|
+
flatListProps?: Omit<React.ComponentProps<typeof react_native.FlatList<T>>, 'data' | 'renderItem' | 'keyExtractor'>;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
declare const List: React.FC<ListProps>;
|
|
183
|
+
|
|
184
|
+
declare const ListItem: React.FC<ListItemProps>;
|
|
185
|
+
|
|
186
|
+
declare function ListBuilder<T>({ data, keyExtractor, renderItem, selectionMode, selectedKeys: controlledSelectedKeys, defaultSelectedKeys, showDivider, isPressable, isSelectable, themeColor, size, onSelectionChange, style, flatListProps, }: ListBuilderProps<T>): React.JSX.Element;
|
|
187
|
+
|
|
188
|
+
export { List, ListBuilder, type ListBuilderProps, ListItem, type ListItemCustomAppearance, type ListItemProps, type ListProps, type ListSelectionMode };
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
import * as react_native from 'react-native';
|
|
3
|
+
import { ViewStyle, TextStyle, GestureResponderEvent } from 'react-native';
|
|
4
|
+
import { T as ThemeColor, S as Size } from '../index-BOw6tbkc.js';
|
|
5
|
+
|
|
6
|
+
type ListSelectionMode = 'single' | 'multiple' | 'none';
|
|
7
|
+
type ListItemCustomAppearance = {
|
|
8
|
+
/**
|
|
9
|
+
* Custom styles for the item container
|
|
10
|
+
*/
|
|
11
|
+
container?: ViewStyle;
|
|
12
|
+
/**
|
|
13
|
+
* Custom styles for the content container
|
|
14
|
+
*/
|
|
15
|
+
content?: ViewStyle;
|
|
16
|
+
/**
|
|
17
|
+
* Custom styles for the title text
|
|
18
|
+
*/
|
|
19
|
+
title?: TextStyle;
|
|
20
|
+
/**
|
|
21
|
+
* Custom styles for the description text
|
|
22
|
+
*/
|
|
23
|
+
description?: TextStyle;
|
|
24
|
+
};
|
|
25
|
+
type ListItemProps = {
|
|
26
|
+
/**
|
|
27
|
+
* Unique key for the item (used for selection)
|
|
28
|
+
*/
|
|
29
|
+
itemKey: string;
|
|
30
|
+
/**
|
|
31
|
+
* Title text for the ListItem
|
|
32
|
+
*/
|
|
33
|
+
title: ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* Optional description text
|
|
36
|
+
*/
|
|
37
|
+
description?: ReactNode;
|
|
38
|
+
/**
|
|
39
|
+
* Content to display at the start of the item
|
|
40
|
+
*/
|
|
41
|
+
startContent?: ReactNode;
|
|
42
|
+
/**
|
|
43
|
+
* Content to display at the end of the item
|
|
44
|
+
*/
|
|
45
|
+
endContent?: ReactNode;
|
|
46
|
+
/**
|
|
47
|
+
* Whether the item is disabled
|
|
48
|
+
* @default false
|
|
49
|
+
*/
|
|
50
|
+
isDisabled?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Whether the item is selected
|
|
53
|
+
* @default false
|
|
54
|
+
*/
|
|
55
|
+
isSelected?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Custom appearance styles for item parts
|
|
58
|
+
*/
|
|
59
|
+
customAppearance?: ListItemCustomAppearance;
|
|
60
|
+
/**
|
|
61
|
+
* Callback fired when the item is pressed
|
|
62
|
+
*/
|
|
63
|
+
onPress?: (event: GestureResponderEvent) => void;
|
|
64
|
+
};
|
|
65
|
+
type ListProps = {
|
|
66
|
+
/**
|
|
67
|
+
* List items
|
|
68
|
+
*/
|
|
69
|
+
children: ReactNode;
|
|
70
|
+
/**
|
|
71
|
+
* Selection mode for the list
|
|
72
|
+
* @default 'none'
|
|
73
|
+
*/
|
|
74
|
+
selectionMode?: ListSelectionMode;
|
|
75
|
+
/**
|
|
76
|
+
* Controlled selected keys
|
|
77
|
+
*/
|
|
78
|
+
selectedKeys?: string[];
|
|
79
|
+
/**
|
|
80
|
+
* Default selected keys (uncontrolled)
|
|
81
|
+
*/
|
|
82
|
+
defaultSelectedKeys?: string[];
|
|
83
|
+
/**
|
|
84
|
+
* Whether to show dividers between items
|
|
85
|
+
* @default false
|
|
86
|
+
*/
|
|
87
|
+
showDivider?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Whether items are pressable
|
|
90
|
+
* @default true
|
|
91
|
+
*/
|
|
92
|
+
isPressable?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Whether items are selectable
|
|
95
|
+
* @default false
|
|
96
|
+
*/
|
|
97
|
+
isSelectable?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Theme color for selected items
|
|
100
|
+
* @default 'primary'
|
|
101
|
+
*/
|
|
102
|
+
themeColor?: ThemeColor;
|
|
103
|
+
/**
|
|
104
|
+
* Size of the list items
|
|
105
|
+
* @default 'md'
|
|
106
|
+
*/
|
|
107
|
+
size?: Size;
|
|
108
|
+
/**
|
|
109
|
+
* Callback fired when selection changes
|
|
110
|
+
*/
|
|
111
|
+
onSelectionChange?: (keys: string[]) => void;
|
|
112
|
+
/**
|
|
113
|
+
* Custom styles for the list container
|
|
114
|
+
*/
|
|
115
|
+
style?: ViewStyle;
|
|
116
|
+
};
|
|
117
|
+
type ListBuilderProps<T> = {
|
|
118
|
+
/**
|
|
119
|
+
* Data array to render
|
|
120
|
+
*/
|
|
121
|
+
data: T[];
|
|
122
|
+
/**
|
|
123
|
+
* Function to extract unique key from item
|
|
124
|
+
*/
|
|
125
|
+
keyExtractor: (item: T, index: number) => string;
|
|
126
|
+
/**
|
|
127
|
+
* Function to render each item
|
|
128
|
+
*/
|
|
129
|
+
renderItem: (item: T, index: number) => ReactNode;
|
|
130
|
+
/**
|
|
131
|
+
* Selection mode for the list
|
|
132
|
+
* @default 'none'
|
|
133
|
+
*/
|
|
134
|
+
selectionMode?: ListSelectionMode;
|
|
135
|
+
/**
|
|
136
|
+
* Controlled selected keys
|
|
137
|
+
*/
|
|
138
|
+
selectedKeys?: string[];
|
|
139
|
+
/**
|
|
140
|
+
* Default selected keys (uncontrolled)
|
|
141
|
+
*/
|
|
142
|
+
defaultSelectedKeys?: string[];
|
|
143
|
+
/**
|
|
144
|
+
* Whether to show dividers between items
|
|
145
|
+
* @default false
|
|
146
|
+
*/
|
|
147
|
+
showDivider?: boolean;
|
|
148
|
+
/**
|
|
149
|
+
* Whether items are pressable
|
|
150
|
+
* @default true
|
|
151
|
+
*/
|
|
152
|
+
isPressable?: boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Whether items are selectable
|
|
155
|
+
* @default false
|
|
156
|
+
*/
|
|
157
|
+
isSelectable?: boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Theme color for selected items
|
|
160
|
+
* @default 'primary'
|
|
161
|
+
*/
|
|
162
|
+
themeColor?: ThemeColor;
|
|
163
|
+
/**
|
|
164
|
+
* Size of the list items
|
|
165
|
+
* @default 'md'
|
|
166
|
+
*/
|
|
167
|
+
size?: Size;
|
|
168
|
+
/**
|
|
169
|
+
* Callback fired when selection changes
|
|
170
|
+
*/
|
|
171
|
+
onSelectionChange?: (keys: string[]) => void;
|
|
172
|
+
/**
|
|
173
|
+
* Custom styles for the list container
|
|
174
|
+
*/
|
|
175
|
+
style?: ViewStyle;
|
|
176
|
+
/**
|
|
177
|
+
* FlatList props to pass through
|
|
178
|
+
*/
|
|
179
|
+
flatListProps?: Omit<React.ComponentProps<typeof react_native.FlatList<T>>, 'data' | 'renderItem' | 'keyExtractor'>;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
declare const List: React.FC<ListProps>;
|
|
183
|
+
|
|
184
|
+
declare const ListItem: React.FC<ListItemProps>;
|
|
185
|
+
|
|
186
|
+
declare function ListBuilder<T>({ data, keyExtractor, renderItem, selectionMode, selectedKeys: controlledSelectedKeys, defaultSelectedKeys, showDivider, isPressable, isSelectable, themeColor, size, onSelectionChange, style, flatListProps, }: ListBuilderProps<T>): React.JSX.Element;
|
|
187
|
+
|
|
188
|
+
export { List, ListBuilder, type ListBuilderProps, ListItem, type ListItemCustomAppearance, type ListItemProps, type ListProps, type ListSelectionMode };
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
import "../chunk-DXXNBF5P.js";
|
|
2
|
+
import {
|
|
3
|
+
useXUITheme
|
|
4
|
+
} from "../chunk-LTKYHG5V.js";
|
|
5
|
+
|
|
6
|
+
// src/components/list/list.tsx
|
|
7
|
+
import React2, { useCallback, useMemo, useState } from "react";
|
|
8
|
+
import { View as View2 } from "react-native";
|
|
9
|
+
|
|
10
|
+
// src/components/list/list-context.ts
|
|
11
|
+
import { createContext, useContext } from "react";
|
|
12
|
+
var ListContext = createContext(null);
|
|
13
|
+
|
|
14
|
+
// src/components/list/list.style.ts
|
|
15
|
+
import { StyleSheet } from "react-native";
|
|
16
|
+
var styles = StyleSheet.create({
|
|
17
|
+
list: {
|
|
18
|
+
flex: 1
|
|
19
|
+
},
|
|
20
|
+
item: {
|
|
21
|
+
flexDirection: "row",
|
|
22
|
+
alignItems: "center",
|
|
23
|
+
gap: 12
|
|
24
|
+
},
|
|
25
|
+
content: {
|
|
26
|
+
flex: 1,
|
|
27
|
+
gap: 2
|
|
28
|
+
},
|
|
29
|
+
title: {
|
|
30
|
+
fontWeight: "500"
|
|
31
|
+
},
|
|
32
|
+
description: {
|
|
33
|
+
opacity: 0.7
|
|
34
|
+
},
|
|
35
|
+
disabled: {
|
|
36
|
+
opacity: 0.5
|
|
37
|
+
},
|
|
38
|
+
divider: {
|
|
39
|
+
height: 1,
|
|
40
|
+
marginLeft: 10
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// src/components/list/list-divider.tsx
|
|
45
|
+
import React, { Children } from "react";
|
|
46
|
+
import { View } from "react-native";
|
|
47
|
+
var ListDivider = () => {
|
|
48
|
+
const theme = useXUITheme();
|
|
49
|
+
return /* @__PURE__ */ React.createElement(
|
|
50
|
+
View,
|
|
51
|
+
{
|
|
52
|
+
style: [styles.divider, { backgroundColor: theme.colors.foreground + "30" }]
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
var ListChildren = ({ children, showDivider }) => {
|
|
57
|
+
if (!showDivider) {
|
|
58
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
|
|
59
|
+
}
|
|
60
|
+
const childArray = Children.toArray(children);
|
|
61
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, childArray.map((child, index) => /* @__PURE__ */ React.createElement(React.Fragment, { key: index }, child, index < childArray.length - 1 && /* @__PURE__ */ React.createElement(ListDivider, null))));
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// src/components/list/list.tsx
|
|
65
|
+
var List = ({
|
|
66
|
+
children,
|
|
67
|
+
selectionMode = "none",
|
|
68
|
+
selectedKeys: controlledSelectedKeys,
|
|
69
|
+
defaultSelectedKeys = [],
|
|
70
|
+
showDivider = false,
|
|
71
|
+
isPressable = true,
|
|
72
|
+
isSelectable = false,
|
|
73
|
+
themeColor = "primary",
|
|
74
|
+
size = "md",
|
|
75
|
+
onSelectionChange,
|
|
76
|
+
style
|
|
77
|
+
}) => {
|
|
78
|
+
const isControlled = controlledSelectedKeys !== void 0;
|
|
79
|
+
const [internalSelectedKeys, setInternalSelectedKeys] = useState(defaultSelectedKeys);
|
|
80
|
+
const selectedKeys = isControlled ? controlledSelectedKeys : internalSelectedKeys;
|
|
81
|
+
const isSelected = useCallback(
|
|
82
|
+
(key) => {
|
|
83
|
+
return selectedKeys.includes(key);
|
|
84
|
+
},
|
|
85
|
+
[selectedKeys]
|
|
86
|
+
);
|
|
87
|
+
const toggleSelection = useCallback(
|
|
88
|
+
(key) => {
|
|
89
|
+
if (selectionMode === "none" || !isSelectable) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
let newSelectedKeys;
|
|
93
|
+
if (selectionMode === "single") {
|
|
94
|
+
newSelectedKeys = isSelected(key) ? [] : [key];
|
|
95
|
+
} else {
|
|
96
|
+
newSelectedKeys = isSelected(key) ? selectedKeys.filter((k) => k !== key) : [...selectedKeys, key];
|
|
97
|
+
}
|
|
98
|
+
if (!isControlled) {
|
|
99
|
+
setInternalSelectedKeys(newSelectedKeys);
|
|
100
|
+
}
|
|
101
|
+
onSelectionChange?.(newSelectedKeys);
|
|
102
|
+
},
|
|
103
|
+
[
|
|
104
|
+
selectionMode,
|
|
105
|
+
isSelectable,
|
|
106
|
+
isSelected,
|
|
107
|
+
selectedKeys,
|
|
108
|
+
isControlled,
|
|
109
|
+
onSelectionChange
|
|
110
|
+
]
|
|
111
|
+
);
|
|
112
|
+
const contextValue = useMemo(
|
|
113
|
+
() => ({
|
|
114
|
+
selectionMode,
|
|
115
|
+
selectedKeys,
|
|
116
|
+
isPressable,
|
|
117
|
+
isSelectable,
|
|
118
|
+
themeColor,
|
|
119
|
+
size,
|
|
120
|
+
showDivider,
|
|
121
|
+
toggleSelection,
|
|
122
|
+
isSelected
|
|
123
|
+
}),
|
|
124
|
+
[
|
|
125
|
+
selectionMode,
|
|
126
|
+
selectedKeys,
|
|
127
|
+
isPressable,
|
|
128
|
+
isSelectable,
|
|
129
|
+
themeColor,
|
|
130
|
+
size,
|
|
131
|
+
showDivider,
|
|
132
|
+
toggleSelection,
|
|
133
|
+
isSelected
|
|
134
|
+
]
|
|
135
|
+
);
|
|
136
|
+
return /* @__PURE__ */ React2.createElement(ListContext.Provider, { value: contextValue }, /* @__PURE__ */ React2.createElement(View2, { style: [styles.list, style] }, /* @__PURE__ */ React2.createElement(ListChildren, { showDivider }, children)));
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// src/components/list/list-item.tsx
|
|
140
|
+
import React3, { useContext as useContext2 } from "react";
|
|
141
|
+
import { Pressable, Text, View as View3 } from "react-native";
|
|
142
|
+
|
|
143
|
+
// src/components/list/list.hook.ts
|
|
144
|
+
import { useMemo as useMemo2 } from "react";
|
|
145
|
+
var useListItemSizeStyles = (size) => {
|
|
146
|
+
const theme = useXUITheme();
|
|
147
|
+
return useMemo2(() => {
|
|
148
|
+
const sizes = {
|
|
149
|
+
xs: {
|
|
150
|
+
paddingVertical: theme.spacing.sm,
|
|
151
|
+
paddingHorizontal: theme.spacing.sm,
|
|
152
|
+
titleSize: theme.fontSizes.xs,
|
|
153
|
+
descriptionSize: theme.fontSizes.xs
|
|
154
|
+
},
|
|
155
|
+
sm: {
|
|
156
|
+
paddingVertical: theme.spacing.sm,
|
|
157
|
+
paddingHorizontal: theme.spacing.md,
|
|
158
|
+
titleSize: theme.fontSizes.sm,
|
|
159
|
+
descriptionSize: theme.fontSizes.xs
|
|
160
|
+
},
|
|
161
|
+
md: {
|
|
162
|
+
paddingVertical: theme.spacing.md,
|
|
163
|
+
paddingHorizontal: theme.spacing.md,
|
|
164
|
+
titleSize: theme.fontSizes.md,
|
|
165
|
+
descriptionSize: theme.fontSizes.sm
|
|
166
|
+
},
|
|
167
|
+
lg: {
|
|
168
|
+
paddingVertical: theme.spacing.lg,
|
|
169
|
+
paddingHorizontal: theme.spacing.lg,
|
|
170
|
+
titleSize: theme.fontSizes.lg,
|
|
171
|
+
descriptionSize: theme.fontSizes.md
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
return sizes[size];
|
|
175
|
+
}, [size, theme]);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// src/components/list/list-item.tsx
|
|
179
|
+
import { getSafeThemeColor } from "@xaui/core";
|
|
180
|
+
var ListItem = ({
|
|
181
|
+
itemKey,
|
|
182
|
+
title,
|
|
183
|
+
description,
|
|
184
|
+
startContent,
|
|
185
|
+
endContent,
|
|
186
|
+
isDisabled = false,
|
|
187
|
+
isSelected: propIsSelected,
|
|
188
|
+
customAppearance,
|
|
189
|
+
onPress
|
|
190
|
+
}) => {
|
|
191
|
+
const context = useContext2(ListContext);
|
|
192
|
+
const theme = useXUITheme();
|
|
193
|
+
const selectionMode = context?.selectionMode ?? "none";
|
|
194
|
+
const isPressable = context?.isPressable ?? true;
|
|
195
|
+
const isSelectable = context?.isSelectable ?? false;
|
|
196
|
+
const themeColor = context?.themeColor ?? "primary";
|
|
197
|
+
const size = context?.size ?? "md";
|
|
198
|
+
const isSelected = propIsSelected ?? (context ? context.isSelected(itemKey) : false);
|
|
199
|
+
const sizeStyles = useListItemSizeStyles(size);
|
|
200
|
+
const safeThemeColor = getSafeThemeColor(themeColor);
|
|
201
|
+
const colorScheme = theme.colors[safeThemeColor];
|
|
202
|
+
const backgroundColor = isSelected ? colorScheme.background : "transparent";
|
|
203
|
+
const titleColor = isDisabled ? theme.colors.foreground + "50" : theme.colors.foreground;
|
|
204
|
+
const descriptionColor = isDisabled ? theme.colors.foreground + "50" : theme.colors.foreground + "99";
|
|
205
|
+
const handlePress = () => {
|
|
206
|
+
if (isDisabled) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (isSelectable && selectionMode !== "none") {
|
|
210
|
+
context?.toggleSelection(itemKey);
|
|
211
|
+
}
|
|
212
|
+
onPress?.({});
|
|
213
|
+
};
|
|
214
|
+
const renderTitle = () => {
|
|
215
|
+
if (typeof title === "string" || typeof title === "number") {
|
|
216
|
+
return /* @__PURE__ */ React3.createElement(
|
|
217
|
+
Text,
|
|
218
|
+
{
|
|
219
|
+
style: [
|
|
220
|
+
styles.title,
|
|
221
|
+
{ fontSize: sizeStyles.titleSize, color: titleColor },
|
|
222
|
+
customAppearance?.title
|
|
223
|
+
],
|
|
224
|
+
numberOfLines: 1
|
|
225
|
+
},
|
|
226
|
+
title
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
return title;
|
|
230
|
+
};
|
|
231
|
+
const renderDescription = () => {
|
|
232
|
+
if (!description) return null;
|
|
233
|
+
if (typeof description === "string" || typeof description === "number") {
|
|
234
|
+
return /* @__PURE__ */ React3.createElement(
|
|
235
|
+
Text,
|
|
236
|
+
{
|
|
237
|
+
style: [
|
|
238
|
+
styles.description,
|
|
239
|
+
{ fontSize: sizeStyles.descriptionSize, color: descriptionColor },
|
|
240
|
+
customAppearance?.description
|
|
241
|
+
],
|
|
242
|
+
numberOfLines: 2
|
|
243
|
+
},
|
|
244
|
+
description
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
return description;
|
|
248
|
+
};
|
|
249
|
+
const content = /* @__PURE__ */ React3.createElement(
|
|
250
|
+
View3,
|
|
251
|
+
{
|
|
252
|
+
style: [
|
|
253
|
+
styles.item,
|
|
254
|
+
{
|
|
255
|
+
paddingVertical: sizeStyles.paddingVertical,
|
|
256
|
+
paddingHorizontal: sizeStyles.paddingHorizontal,
|
|
257
|
+
backgroundColor
|
|
258
|
+
},
|
|
259
|
+
isDisabled && styles.disabled,
|
|
260
|
+
customAppearance?.container
|
|
261
|
+
]
|
|
262
|
+
},
|
|
263
|
+
startContent && /* @__PURE__ */ React3.createElement(View3, { style: customAppearance?.content }, startContent),
|
|
264
|
+
/* @__PURE__ */ React3.createElement(View3, { style: [styles.content, customAppearance?.content] }, renderTitle(), renderDescription()),
|
|
265
|
+
endContent && /* @__PURE__ */ React3.createElement(View3, { style: customAppearance?.content }, endContent)
|
|
266
|
+
);
|
|
267
|
+
if (!isPressable) {
|
|
268
|
+
return content;
|
|
269
|
+
}
|
|
270
|
+
return /* @__PURE__ */ React3.createElement(
|
|
271
|
+
Pressable,
|
|
272
|
+
{
|
|
273
|
+
onPress: handlePress,
|
|
274
|
+
disabled: isDisabled,
|
|
275
|
+
style: ({ pressed }) => [
|
|
276
|
+
pressed && !isDisabled && {
|
|
277
|
+
backgroundColor: theme.colors.foreground + "10"
|
|
278
|
+
}
|
|
279
|
+
]
|
|
280
|
+
},
|
|
281
|
+
content
|
|
282
|
+
);
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
// src/components/list/list-builder.tsx
|
|
286
|
+
import React4, { useCallback as useCallback2, useMemo as useMemo3, useState as useState2 } from "react";
|
|
287
|
+
import { FlatList, View as View4 } from "react-native";
|
|
288
|
+
function ListBuilder({
|
|
289
|
+
data,
|
|
290
|
+
keyExtractor,
|
|
291
|
+
renderItem,
|
|
292
|
+
selectionMode = "none",
|
|
293
|
+
selectedKeys: controlledSelectedKeys,
|
|
294
|
+
defaultSelectedKeys = [],
|
|
295
|
+
showDivider = false,
|
|
296
|
+
isPressable = true,
|
|
297
|
+
isSelectable = false,
|
|
298
|
+
themeColor = "primary",
|
|
299
|
+
size = "md",
|
|
300
|
+
onSelectionChange,
|
|
301
|
+
style,
|
|
302
|
+
flatListProps
|
|
303
|
+
}) {
|
|
304
|
+
const theme = useXUITheme();
|
|
305
|
+
const isControlled = controlledSelectedKeys !== void 0;
|
|
306
|
+
const [internalSelectedKeys, setInternalSelectedKeys] = useState2(defaultSelectedKeys);
|
|
307
|
+
const selectedKeys = isControlled ? controlledSelectedKeys : internalSelectedKeys;
|
|
308
|
+
const isSelected = useCallback2(
|
|
309
|
+
(key) => {
|
|
310
|
+
return selectedKeys.includes(key);
|
|
311
|
+
},
|
|
312
|
+
[selectedKeys]
|
|
313
|
+
);
|
|
314
|
+
const toggleSelection = useCallback2(
|
|
315
|
+
(key) => {
|
|
316
|
+
if (selectionMode === "none" || !isSelectable) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
let newSelectedKeys;
|
|
320
|
+
if (selectionMode === "single") {
|
|
321
|
+
newSelectedKeys = isSelected(key) ? [] : [key];
|
|
322
|
+
} else {
|
|
323
|
+
newSelectedKeys = isSelected(key) ? selectedKeys.filter((k) => k !== key) : [...selectedKeys, key];
|
|
324
|
+
}
|
|
325
|
+
if (!isControlled) {
|
|
326
|
+
setInternalSelectedKeys(newSelectedKeys);
|
|
327
|
+
}
|
|
328
|
+
onSelectionChange?.(newSelectedKeys);
|
|
329
|
+
},
|
|
330
|
+
[
|
|
331
|
+
selectionMode,
|
|
332
|
+
isSelectable,
|
|
333
|
+
isSelected,
|
|
334
|
+
selectedKeys,
|
|
335
|
+
isControlled,
|
|
336
|
+
onSelectionChange
|
|
337
|
+
]
|
|
338
|
+
);
|
|
339
|
+
const contextValue = useMemo3(
|
|
340
|
+
() => ({
|
|
341
|
+
selectionMode,
|
|
342
|
+
selectedKeys,
|
|
343
|
+
isPressable,
|
|
344
|
+
isSelectable,
|
|
345
|
+
themeColor,
|
|
346
|
+
size,
|
|
347
|
+
showDivider,
|
|
348
|
+
toggleSelection,
|
|
349
|
+
isSelected
|
|
350
|
+
}),
|
|
351
|
+
[
|
|
352
|
+
selectionMode,
|
|
353
|
+
selectedKeys,
|
|
354
|
+
isPressable,
|
|
355
|
+
isSelectable,
|
|
356
|
+
themeColor,
|
|
357
|
+
size,
|
|
358
|
+
showDivider,
|
|
359
|
+
toggleSelection,
|
|
360
|
+
isSelected
|
|
361
|
+
]
|
|
362
|
+
);
|
|
363
|
+
const renderListItem = useCallback2(
|
|
364
|
+
(item, index) => {
|
|
365
|
+
const element = renderItem(item, index);
|
|
366
|
+
if (!showDivider || index === data.length - 1) {
|
|
367
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: keyExtractor(item, index) }, element);
|
|
368
|
+
}
|
|
369
|
+
return /* @__PURE__ */ React4.createElement(View4, { key: keyExtractor(item, index) }, element, /* @__PURE__ */ React4.createElement(
|
|
370
|
+
View4,
|
|
371
|
+
{
|
|
372
|
+
style: [
|
|
373
|
+
styles.divider,
|
|
374
|
+
{ backgroundColor: theme.colors.foreground + "15" }
|
|
375
|
+
]
|
|
376
|
+
}
|
|
377
|
+
));
|
|
378
|
+
},
|
|
379
|
+
[data.length, keyExtractor, renderItem, showDivider, theme.colors.foreground]
|
|
380
|
+
);
|
|
381
|
+
return /* @__PURE__ */ React4.createElement(ListContext.Provider, { value: contextValue }, /* @__PURE__ */ React4.createElement(View4, { style: [styles.list, style] }, /* @__PURE__ */ React4.createElement(
|
|
382
|
+
FlatList,
|
|
383
|
+
{
|
|
384
|
+
data,
|
|
385
|
+
keyExtractor,
|
|
386
|
+
renderItem: ({ item, index }) => renderListItem(item, index),
|
|
387
|
+
...flatListProps
|
|
388
|
+
}
|
|
389
|
+
)));
|
|
390
|
+
}
|
|
391
|
+
export {
|
|
392
|
+
List,
|
|
393
|
+
ListBuilder,
|
|
394
|
+
ListItem
|
|
395
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xaui/native",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.21",
|
|
4
4
|
"description": "Flutter-inspired React Native UI components with native animations powered by React Native Reanimated",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -151,6 +151,11 @@
|
|
|
151
151
|
"types": "./dist/input/index.d.ts",
|
|
152
152
|
"import": "./dist/input/index.js",
|
|
153
153
|
"require": "./dist/input/index.js"
|
|
154
|
+
},
|
|
155
|
+
"./list": {
|
|
156
|
+
"types": "./dist/list/index.d.ts",
|
|
157
|
+
"import": "./dist/list/index.js",
|
|
158
|
+
"require": "./dist/list/index.js"
|
|
154
159
|
}
|
|
155
160
|
},
|
|
156
161
|
"files": [
|