@bit.rhplus/ui.f7.detail-item 0.0.2 → 0.0.3

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.
Files changed (54) hide show
  1. package/components/Category.jsx +167 -0
  2. package/components/Contact.jsx +105 -0
  3. package/components/Custom.jsx +209 -4
  4. package/components/Download.jsx +32 -7
  5. package/components/Grid.jsx +230 -0
  6. package/components/InputNumber.jsx +17 -2
  7. package/components/InputText.jsx +17 -2
  8. package/components/List.jsx +305 -0
  9. package/components/Select.jsx +199 -0
  10. package/components/Switch.jsx +12 -1
  11. package/components/Text.jsx +36 -3
  12. package/components/index.jsx +6 -1
  13. package/dist/components/Category.d.ts +13 -0
  14. package/dist/components/Category.js +86 -0
  15. package/dist/components/Category.js.map +1 -0
  16. package/dist/components/Contact.d.ts +10 -0
  17. package/dist/components/Contact.js +60 -0
  18. package/dist/components/Contact.js.map +1 -0
  19. package/dist/components/Custom.d.ts +19 -2
  20. package/dist/components/Custom.js +114 -5
  21. package/dist/components/Custom.js.map +1 -1
  22. package/dist/components/Download.d.ts +5 -1
  23. package/dist/components/Download.js +19 -3
  24. package/dist/components/Download.js.map +1 -1
  25. package/dist/components/Grid.d.ts +19 -0
  26. package/dist/components/Grid.js +144 -0
  27. package/dist/components/Grid.js.map +1 -0
  28. package/dist/components/InputNumber.d.ts +3 -1
  29. package/dist/components/InputNumber.js +16 -2
  30. package/dist/components/InputNumber.js.map +1 -1
  31. package/dist/components/InputText.d.ts +3 -1
  32. package/dist/components/InputText.js +16 -2
  33. package/dist/components/InputText.js.map +1 -1
  34. package/dist/components/List.d.ts +20 -0
  35. package/dist/components/List.js +173 -0
  36. package/dist/components/List.js.map +1 -0
  37. package/dist/components/Select.d.ts +13 -0
  38. package/dist/components/Select.js +89 -0
  39. package/dist/components/Select.js.map +1 -0
  40. package/dist/components/Switch.d.ts +3 -1
  41. package/dist/components/Switch.js +11 -2
  42. package/dist/components/Switch.js.map +1 -1
  43. package/dist/components/Text.d.ts +8 -1
  44. package/dist/components/Text.js +25 -3
  45. package/dist/components/Text.js.map +1 -1
  46. package/dist/components/index.d.ts +5 -0
  47. package/dist/components/index.js +5 -0
  48. package/dist/components/index.js.map +1 -1
  49. package/dist/index.d.ts +3 -2
  50. package/dist/index.js +18 -11
  51. package/dist/index.js.map +1 -1
  52. package/index.jsx +109 -62
  53. package/package.json +6 -3
  54. /package/dist/{preview-1756999926762.js → preview-1757077532569.js} +0 -0
@@ -0,0 +1,230 @@
1
+ /* eslint-disable */
2
+ import React, { useState, useEffect, useMemo } from 'react';
3
+ import {
4
+ Link,
5
+ Icon,
6
+ Popup,
7
+ Navbar,
8
+ NavLeft,
9
+ NavTitle,
10
+ NavTitleLarge,
11
+ NavRight,
12
+ Page,
13
+ Block,
14
+ List,
15
+ ListInput,
16
+ Button
17
+ } from 'framework7-react';
18
+ import { Table } from 'lucide-react';
19
+ import AgGrid from '@bit.rhplus/ui.grid';
20
+ import SaveButton from '@bit.rhplus/ui.f7.save-button';
21
+
22
+ // Grid komponenta s modální editací - zobrazuje AG Grid pro výběr položky
23
+ export const Grid = ({
24
+ children,
25
+ value,
26
+ onSave,
27
+ onChange, // Přidáno pro Form.Item kompatibilitu
28
+ title = 'Editace výběru',
29
+ placeholder = 'Vyberte položku',
30
+ color = '#6887d3',
31
+ size = 16,
32
+ lucideIcon, // Lucide React ikona (např. Table)
33
+ icon, // Jakákoliv React komponenta ikony
34
+ rowData = [], // Array dat pro grid
35
+ columnDefs = [], // Definice sloupců pro AG Grid
36
+ gridOptions = {}, // Dodatečné možnosti pro AG Grid
37
+ onRowDoubleClicked, // Callback pro double click na řádek
38
+ gridHeight = '400px', // Výška gridu
39
+ selectionMode = 'single', // 'single' nebo 'multiple'
40
+ displayField = 'name' // Pole, které se zobrazí v detail-item při výběru
41
+ }) => {
42
+ const [popupOpened, setPopupOpened] = useState(false);
43
+ // Inicializuj selectedRows pouze jednou při mount
44
+ const initialSelectedRows = useMemo(() => {
45
+ return value ? (Array.isArray(value) ? value : [value]) : [];
46
+ }, []); // Prázdné dependency array - pouze při mount
47
+
48
+ const [selectedRows, setSelectedRows] = useState(initialSelectedRows);
49
+
50
+ const linkStyle = {
51
+ color,
52
+ cursor: 'pointer',
53
+ display: 'flex',
54
+ alignItems: 'center',
55
+ gap: '6px'
56
+ };
57
+
58
+ const handleCancel = () => {
59
+ // Při zrušení resetuj na původní hodnoty
60
+ const originalValue = value ? (Array.isArray(value) ? value : [value]) : [];
61
+ setSelectedRows(originalValue);
62
+ setPopupOpened(false);
63
+ };
64
+
65
+ const handleOpenPopup = () => {
66
+ // Při otevření nastav aktuální hodnotu
67
+ const currentValue = value ? (Array.isArray(value) ? value : [value]) : [];
68
+ setSelectedRows(currentValue);
69
+ setPopupOpened(true);
70
+ };
71
+
72
+ const handleRowSelection = (event) => {
73
+ console.log('Grid selection changed - event:', event);
74
+
75
+ if (event && event.api) {
76
+ const selectedNodes = event.api.getSelectedNodes();
77
+ const selectedData = selectedNodes.map(node => node.data);
78
+
79
+ console.log('Grid selection changed:', {
80
+ selectedNodes: selectedNodes.length,
81
+ selectedData,
82
+ previousSelectedRows: selectedRows
83
+ });
84
+
85
+ // Pro oba režimy pouze aktualizujeme stav - uložení bude přes Save button
86
+ setSelectedRows(selectedData);
87
+ } else {
88
+ console.log('Grid API not available in event');
89
+ }
90
+ };
91
+
92
+ const handleSaveSelection = () => {
93
+ // Uložení vybraných položek pro oba režimy
94
+ let result;
95
+
96
+ if (selectionMode === 'single') {
97
+ result = selectedRows.length > 0 ? selectedRows[0] : null;
98
+ } else {
99
+ result = selectedRows.length === 1 ? selectedRows[0] : selectedRows;
100
+ }
101
+
102
+ // Debug pouze při uložení
103
+ console.log('Saving Grid selection:', { selectedRows, result, selectionMode, hasOnChange: !!onChange, hasOnSave: !!onSave });
104
+
105
+ if (onChange) {
106
+ onChange(result);
107
+ console.log('Grid - onChange called with:', result);
108
+ } else if (onSave) {
109
+ onSave(result);
110
+ console.log('Grid - onSave called with:', result);
111
+ }
112
+
113
+ setPopupOpened(false);
114
+ };
115
+
116
+
117
+ // Určí jakou ikonu použít - priorita: icon > lucideIcon > výchozí Table
118
+ const renderIcon = () => {
119
+ if (icon) {
120
+ return React.cloneElement(icon, { size, color, ...icon.props });
121
+ }
122
+ if (lucideIcon) {
123
+ const LucideIcon = lucideIcon;
124
+ return <LucideIcon size={size} color={color} />;
125
+ }
126
+ return <Table size={size} color={color} />;
127
+ };
128
+
129
+
130
+ // Kombinované grid options
131
+ const combinedGridOptions = {
132
+ rowSelection: selectionMode,
133
+ onSelectionChanged: handleRowSelection,
134
+ onRowDoubleClicked: onRowDoubleClicked,
135
+ suppressRowClickSelection: false, // Umožní výběr kliknutím na řádek pro oba režimy
136
+ ...gridOptions
137
+ };
138
+
139
+ return (
140
+ <>
141
+ <Link onClick={handleOpenPopup} className="link" style={linkStyle}>
142
+ {renderIcon()}
143
+ {(() => {
144
+ // Použij value prop pro zobrazení (value obsahuje uloženou hodnotu)
145
+ const currentValue = value ? (Array.isArray(value) ? value : [value]) : [];
146
+
147
+ if (currentValue.length === 1) {
148
+ // Pokud je vybraná jedna položka, zobraz hodnotu z displayField
149
+ const item = currentValue[0];
150
+ return item[displayField] || item.name || item.title || item.id || 'Vybraná položka';
151
+ } else if (currentValue.length > 1) {
152
+ return `${currentValue.length} vybraných položek`;
153
+ }
154
+ return placeholder;
155
+ })()}
156
+ </Link>
157
+
158
+ <Popup
159
+ opened={popupOpened}
160
+ onPopupClosed={() => setPopupOpened(false)}
161
+ animate
162
+ backdrop
163
+ push={false}
164
+ className="f7-parallax grid-popup"
165
+ style={{
166
+ '--f7-popup-tablet-width': '90vw',
167
+ '--f7-popup-tablet-height': '90vh'
168
+ }}
169
+ >
170
+ <div className="view view-init">
171
+ <div className="page page-with-navbar-large">
172
+ <Navbar large className="navbar-transparent">
173
+ <NavLeft>
174
+ <Link onClick={handleCancel}>
175
+ <Icon f7="arrow_left" style={{ fontWeight: 'bold' }} />
176
+ </Link>
177
+ </NavLeft>
178
+ <NavTitle>Výběr</NavTitle>
179
+ <NavTitleLarge>Vyberte položky</NavTitleLarge>
180
+ </Navbar>
181
+
182
+ <div className="page-content">
183
+ {/* AG Grid */}
184
+ <Block style={{
185
+ flex: 1,
186
+ display: 'flex',
187
+ flexDirection: 'column',
188
+ height: 'calc(100vh - 230px)', // Více prostoru pro SaveButton
189
+ padding: '0'
190
+ }}>
191
+ <div
192
+ className="ag-theme-quartz"
193
+ style={{
194
+ height: '100%',
195
+ width: '100%',
196
+ flex: 1,
197
+ '--ag-background-color': 'transparent',
198
+ '--ag-odd-row-background-color': 'transparent'
199
+ }}
200
+ >
201
+ <AgGrid
202
+ columnDefs={columnDefs}
203
+ rowData={rowData}
204
+ gridOptions={{
205
+ ...combinedGridOptions,
206
+ popupParent: document.body, // Popup menu se zobrazí v body, ne v popup
207
+ rowHeight: 48, // Explicitní výška řádku
208
+ headerHeight: 56 // Explicitní výška hlavičky
209
+ }}
210
+ height="100%"
211
+ // appearance="ag-theme-quartz"
212
+ defaultColDef={{
213
+ sortable: true,
214
+ filter: true,
215
+ resizable: true,
216
+ minWidth: 100, // Minimální šířka sloupců pro mobil
217
+ ...gridOptions.defaultColDef
218
+ }}
219
+ />
220
+ </div>
221
+ </Block>
222
+
223
+ <SaveButton onClick={handleSaveSelection} variant="black" />
224
+ </div>
225
+ </div>
226
+ </div>
227
+ </Popup>
228
+ </>
229
+ );
230
+ };
@@ -15,6 +15,7 @@ import {
15
15
  ListInput,
16
16
  Button
17
17
  } from 'framework7-react';
18
+ import { Hash } from 'lucide-react';
18
19
  import SaveButton from '@bit.rhplus/ui.f7.save-button';
19
20
 
20
21
  // InputNumber komponenta s modální editací číselných hodnot kompatibilní s Ant Design Form
@@ -29,7 +30,9 @@ export const InputNumber = ({
29
30
  size = 16,
30
31
  min,
31
32
  max,
32
- step = 1
33
+ step = 1,
34
+ lucideIcon, // Lucide React ikona
35
+ icon // Jakákoliv React komponenta ikony
33
36
  }) => {
34
37
  const [popupOpened, setPopupOpened] = useState(false);
35
38
  const [inputValue, setInputValue] = useState(value || children || '');
@@ -83,10 +86,22 @@ export const InputNumber = ({
83
86
  }
84
87
  };
85
88
 
89
+ // Určí jakou ikonu použít - priorita: icon > lucideIcon > výchozí Hash
90
+ const renderIcon = () => {
91
+ if (icon) {
92
+ return React.cloneElement(icon, { size, color, ...icon.props });
93
+ }
94
+ if (lucideIcon) {
95
+ const LucideIcon = lucideIcon;
96
+ return <LucideIcon size={size} color={color} />;
97
+ }
98
+ return <Hash size={size} color={color} />;
99
+ };
100
+
86
101
  return (
87
102
  <>
88
103
  <Link onClick={() => setPopupOpened(true)} className="link" style={linkStyle}>
89
- <Icon f7="pencil" size={size} />
104
+ {renderIcon()}
90
105
  {(value !== null && value !== undefined && value !== '') ? (value || children) : placeholder}
91
106
  </Link>
92
107
 
@@ -15,6 +15,7 @@ import {
15
15
  ListInput,
16
16
  Button
17
17
  } from 'framework7-react';
18
+ import { Pencil } from 'lucide-react';
18
19
  import SaveButton from '@bit.rhplus/ui.f7.save-button';
19
20
 
20
21
  // Input komponenta s modální editací kompatibilní s Ant Design Form
@@ -26,7 +27,9 @@ export const InputText = ({
26
27
  title = 'Editace',
27
28
  placeholder = 'Zadejte hodnotu',
28
29
  color = '#6887d3',
29
- size = 16
30
+ size = 16,
31
+ lucideIcon, // Lucide React ikona (např. Pencil, Edit3)
32
+ icon // Jakákoliv React komponenta ikony
30
33
  }) => {
31
34
  const [popupOpened, setPopupOpened] = useState(false);
32
35
  const [inputValue, setInputValue] = useState(value || children || '');
@@ -61,10 +64,22 @@ export const InputText = ({
61
64
  setPopupOpened(false);
62
65
  };
63
66
 
67
+ // Určí jakou ikonu použít - priorita: icon > lucideIcon > výchozí Pencil
68
+ const renderIcon = () => {
69
+ if (icon) {
70
+ return React.cloneElement(icon, { size, color, ...icon.props });
71
+ }
72
+ if (lucideIcon) {
73
+ const LucideIcon = lucideIcon;
74
+ return <LucideIcon size={size} color={color} />;
75
+ }
76
+ return <Pencil size={size} color={color} />;
77
+ };
78
+
64
79
  return (
65
80
  <>
66
81
  <Link onClick={() => setPopupOpened(true)} className="link" style={linkStyle}>
67
- <Icon f7="pencil" size={size} />
82
+ {renderIcon()}
68
83
  {(value !== null && value !== undefined && value !== '') ? (value || children) : placeholder}
69
84
  </Link>
70
85
 
@@ -0,0 +1,305 @@
1
+ /* eslint-disable */
2
+ import React, { useState, useEffect, useMemo } from 'react';
3
+ import {
4
+ Link,
5
+ Icon,
6
+ Popup,
7
+ Navbar,
8
+ NavLeft,
9
+ NavTitle,
10
+ NavTitleLarge,
11
+ NavRight,
12
+ Page,
13
+ Block,
14
+ List as F7List,
15
+ ListItem,
16
+ Card,
17
+ Button
18
+ } from 'framework7-react';
19
+ import { List as ListIcon } from 'lucide-react';
20
+ import SaveButton from '@bit.rhplus/ui.f7.save-button';
21
+
22
+ // List komponenta s modální editací - zobrazuje seznam jako ListItem komponenty
23
+ export const List = ({
24
+ children,
25
+ value,
26
+ onSave,
27
+ onChange, // Přidáno pro Form.Item kompatibilitu
28
+ title = 'Editace výběru',
29
+ placeholder = 'Vyberte položku',
30
+ color = '#6887d3',
31
+ size = 16,
32
+ lucideIcon, // Lucide React ikona (např. List)
33
+ icon, // Jakákoliv React komponenta ikony
34
+ options = [], // Array možností pro výběr
35
+ selectionMode = 'single', // 'single' nebo 'multiple'
36
+ displayField = 'name', // Pole, které se zobrazí v detail-item při výběru
37
+ titleField = 'name', // Pole pro nadpis v ListItem
38
+ subtitleField = 'description', // Pole pro popis v ListItem
39
+ iconField = 'icon', // Pole pro ikonu v ListItem
40
+ colorField = 'color', // Pole pro barvu v ListItem
41
+ ItemRenderer // Custom komponenta pro renderování jednotlivých položek
42
+ }) => {
43
+ const [popupOpened, setPopupOpened] = useState(false);
44
+ // Inicializuj selectedItems pouze jednou při mount
45
+ const initialSelectedItems = useMemo(() => {
46
+ return value ? (Array.isArray(value) ? value : [value]) : [];
47
+ }, []); // Prázdné dependency array - pouze při mount
48
+
49
+ const [selectedItems, setSelectedItems] = useState(initialSelectedItems);
50
+
51
+ const linkStyle = {
52
+ color,
53
+ cursor: 'pointer',
54
+ display: 'flex',
55
+ alignItems: 'center',
56
+ gap: '6px'
57
+ };
58
+
59
+ const handleCancel = () => {
60
+ const originalValue = value ? (Array.isArray(value) ? value : [value]) : [];
61
+ setSelectedItems(originalValue);
62
+ setPopupOpened(false);
63
+ };
64
+
65
+ const handleOpenPopup = () => {
66
+ // Reset selected items při otevření
67
+ const currentValue = value ? (Array.isArray(value) ? value : [value]) : [];
68
+ setSelectedItems(currentValue);
69
+ setPopupOpened(true);
70
+ };
71
+
72
+ const isSelected = (item) => {
73
+ return selectedItems.some(selected => selected.id === item.id);
74
+ };
75
+
76
+ const handleItemClick = (item) => {
77
+ if (selectionMode === 'single') {
78
+ // Single selection - přímé uložení položky bez použití state
79
+ if (onChange) {
80
+ onChange(item);
81
+ } else if (onSave) {
82
+ onSave(item);
83
+ }
84
+
85
+ // Zavři popup
86
+ setPopupOpened(false);
87
+ return;
88
+ } else {
89
+ // Multiple selection - toggle výběr
90
+ let newSelection;
91
+ if (isSelected(item)) {
92
+ newSelection = selectedItems.filter(selected => selected.id !== item.id);
93
+ } else {
94
+ newSelection = [...selectedItems, item];
95
+ }
96
+
97
+ setSelectedItems(newSelection);
98
+ }
99
+ };
100
+
101
+ const handleSaveSelection = () => {
102
+ // Uložení vybraných položek pro oba režimy
103
+ let result;
104
+
105
+ if (selectionMode === 'single') {
106
+ result = selectedItems.length > 0 ? selectedItems[0] : null;
107
+ } else {
108
+ result = selectedItems.length === 1 ? selectedItems[0] : selectedItems;
109
+ }
110
+
111
+ if (onChange) {
112
+ onChange(result);
113
+ } else if (onSave) {
114
+ onSave(result);
115
+ }
116
+
117
+ setPopupOpened(false);
118
+ };
119
+
120
+ // Určí jakou ikonu použít - priorita: icon > lucideIcon > výchozí List
121
+ const renderIcon = () => {
122
+ if (icon) {
123
+ return React.cloneElement(icon, { size, color, ...icon.props });
124
+ }
125
+ if (lucideIcon) {
126
+ const LucideIcon = lucideIcon;
127
+ return <LucideIcon size={size} color={color} />;
128
+ }
129
+ return <ListIcon size={size} color={color} />;
130
+ };
131
+
132
+ // Renderování ikony pro ListItem
133
+ const renderItemIcon = (item) => {
134
+ const itemIcon = item[iconField];
135
+ const itemColor = item[colorField] || color;
136
+
137
+ if (React.isValidElement(itemIcon)) {
138
+ return React.cloneElement(itemIcon, { size: 20, color: itemColor });
139
+ }
140
+
141
+ return <Icon f7="circle_fill" color={itemColor} size="20" />;
142
+ };
143
+
144
+ return (
145
+ <>
146
+ <Link onClick={handleOpenPopup} className="link" style={linkStyle}>
147
+ {renderIcon()}
148
+ {(() => {
149
+ // Použij value prop pro zobrazení (ne selectedItems state)
150
+ const currentValue = value ? (Array.isArray(value) ? value : [value]) : [];
151
+
152
+ if (currentValue.length === 1) {
153
+ // Pokud je vybraná jedna položka, zobraz hodnotu z displayField
154
+ const item = currentValue[0];
155
+ return item[displayField] || item.name || item.title || item.id || 'Vybraná položka';
156
+ } else if (currentValue.length > 1) {
157
+ return `${currentValue.length} vybraných položek`;
158
+ }
159
+ return placeholder;
160
+ })()}
161
+ </Link>
162
+
163
+ <Popup
164
+ opened={popupOpened}
165
+ onPopupClosed={() => setPopupOpened(false)}
166
+ animate
167
+ backdrop
168
+ push={false}
169
+ className="f7-parallax list-popup"
170
+ style={{
171
+ '--f7-popup-tablet-width': '90vw',
172
+ '--f7-popup-tablet-height': '90vh'
173
+ }}
174
+ >
175
+ <div className="view view-init">
176
+ <div className="page page-with-navbar-large">
177
+ <Navbar large className="navbar-transparent">
178
+ <NavLeft>
179
+ <Link onClick={handleCancel}>
180
+ <Icon f7="arrow_left" style={{ fontWeight: 'bold' }} />
181
+ </Link>
182
+ </NavLeft>
183
+ <NavTitle>Vyberte položku</NavTitle>
184
+ <NavTitleLarge>Vyberte položku</NavTitleLarge>
185
+ </Navbar>
186
+
187
+ <div className="page-content">
188
+ <Block style={{
189
+ padding: '10px 0'
190
+ }}>
191
+ <Card>
192
+ <F7List style={{
193
+ marginTop: '0',
194
+ marginBottom: '0'
195
+ }}>
196
+ {options.map((item, index) => {
197
+ const selected = isSelected(item);
198
+
199
+ // Pokud je předán custom ItemRenderer, použij ho
200
+ if (ItemRenderer) {
201
+ return (
202
+ <ItemRenderer
203
+ key={item.id || index}
204
+ item={item}
205
+ index={index}
206
+ selected={selected}
207
+ onItemClick={(e) => {
208
+ e.preventDefault();
209
+ e.stopPropagation();
210
+ handleItemClick(item);
211
+ }}
212
+ titleField={titleField}
213
+ subtitleField={subtitleField}
214
+ iconField={iconField}
215
+ colorField={colorField}
216
+ color={color}
217
+ />
218
+ );
219
+ }
220
+
221
+ // Defaultní renderování
222
+ const title = item[titleField] || item.name || item.title || `Položka ${index + 1}`;
223
+ const subtitle = item[subtitleField] || item.description;
224
+
225
+ return (
226
+ <ListItem
227
+ key={item.id || index}
228
+ link="#"
229
+ noChevron
230
+ onClick={() => handleItemClick(item)}
231
+ style={{
232
+ '--f7-list-item-padding-horizontal': '15px',
233
+ '--f7-list-item-padding-vertical': '12px',
234
+ backgroundColor: selected ? '#f0f9ff' : 'transparent'
235
+ }}
236
+ >
237
+ <div
238
+ slot="media"
239
+ style={{
240
+ display: 'flex',
241
+ alignItems: 'center',
242
+ marginRight: '12px'
243
+ }}
244
+ >
245
+ {renderItemIcon(item)}
246
+ </div>
247
+
248
+ <div
249
+ slot="inner"
250
+ style={{
251
+ display: 'flex',
252
+ flexDirection: 'column',
253
+ width: '100%',
254
+ minHeight: '50px'
255
+ }}
256
+ >
257
+ {/* Title row */}
258
+ <div style={{
259
+ display: 'flex',
260
+ justifyContent: 'space-between',
261
+ alignItems: 'center',
262
+ marginBottom: subtitle ? '4px' : '0'
263
+ }}>
264
+ <span style={{
265
+ fontWeight: selected ? 600 : 500,
266
+ fontSize: '16px',
267
+ color: selected ? '#007aff' : '#000'
268
+ }}>
269
+ {title}
270
+ </span>
271
+ {selected && (
272
+ <Icon
273
+ f7="checkmark_circle_fill"
274
+ color="#007aff"
275
+ size="20"
276
+ />
277
+ )}
278
+ </div>
279
+
280
+ {/* Subtitle */}
281
+ {subtitle && (
282
+ <div style={{
283
+ fontSize: '14px',
284
+ color: '#666',
285
+ overflow: 'hidden',
286
+ textOverflow: 'ellipsis',
287
+ whiteSpace: 'nowrap'
288
+ }}>
289
+ {subtitle}
290
+ </div>
291
+ )}
292
+ </div>
293
+ </ListItem>
294
+ );
295
+ })}
296
+ </F7List>
297
+ </Card>
298
+ </Block>
299
+ </div>
300
+ </div>
301
+ </div>
302
+ </Popup>
303
+ </>
304
+ );
305
+ };