@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.
- package/components/Category.jsx +167 -0
- package/components/Contact.jsx +105 -0
- package/components/Custom.jsx +209 -4
- package/components/Download.jsx +32 -7
- package/components/Grid.jsx +230 -0
- package/components/InputNumber.jsx +17 -2
- package/components/InputText.jsx +17 -2
- package/components/List.jsx +305 -0
- package/components/Select.jsx +199 -0
- package/components/Switch.jsx +12 -1
- package/components/Text.jsx +36 -3
- package/components/index.jsx +6 -1
- package/dist/components/Category.d.ts +13 -0
- package/dist/components/Category.js +86 -0
- package/dist/components/Category.js.map +1 -0
- package/dist/components/Contact.d.ts +10 -0
- package/dist/components/Contact.js +60 -0
- package/dist/components/Contact.js.map +1 -0
- package/dist/components/Custom.d.ts +19 -2
- package/dist/components/Custom.js +114 -5
- package/dist/components/Custom.js.map +1 -1
- package/dist/components/Download.d.ts +5 -1
- package/dist/components/Download.js +19 -3
- package/dist/components/Download.js.map +1 -1
- package/dist/components/Grid.d.ts +19 -0
- package/dist/components/Grid.js +144 -0
- package/dist/components/Grid.js.map +1 -0
- package/dist/components/InputNumber.d.ts +3 -1
- package/dist/components/InputNumber.js +16 -2
- package/dist/components/InputNumber.js.map +1 -1
- package/dist/components/InputText.d.ts +3 -1
- package/dist/components/InputText.js +16 -2
- package/dist/components/InputText.js.map +1 -1
- package/dist/components/List.d.ts +20 -0
- package/dist/components/List.js +173 -0
- package/dist/components/List.js.map +1 -0
- package/dist/components/Select.d.ts +13 -0
- package/dist/components/Select.js +89 -0
- package/dist/components/Select.js.map +1 -0
- package/dist/components/Switch.d.ts +3 -1
- package/dist/components/Switch.js +11 -2
- package/dist/components/Switch.js.map +1 -1
- package/dist/components/Text.d.ts +8 -1
- package/dist/components/Text.js +25 -3
- package/dist/components/Text.js.map +1 -1
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.js +5 -0
- package/dist/components/index.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +18 -11
- package/dist/index.js.map +1 -1
- package/index.jsx +109 -62
- package/package.json +6 -3
- /package/dist/{preview-1756999926762.js → preview-1757077532569.js} +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import React, { useState, useEffect } 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 { Tag } from 'lucide-react';
|
|
19
|
+
import CircleButton from '@bit.rhplus/ui.circle-button';
|
|
20
|
+
|
|
21
|
+
// Category komponenta s modální editací - zobrazuje výběr jedné kategorie jako avatar
|
|
22
|
+
export const Category = ({
|
|
23
|
+
children,
|
|
24
|
+
value,
|
|
25
|
+
onSave,
|
|
26
|
+
onChange, // Přidáno pro Form.Item kompatibilitu
|
|
27
|
+
title = 'Vyber',
|
|
28
|
+
placeholder = 'Vyber kategorii',
|
|
29
|
+
color = '#6887d3',
|
|
30
|
+
size = 16,
|
|
31
|
+
lucideIcon, // Lucide React ikona (např. Tag)
|
|
32
|
+
icon, // Jakákoliv React komponenta ikony
|
|
33
|
+
categories = [] // Array kategorií ve formátu [{ id, name, icon, color }]
|
|
34
|
+
}) => {
|
|
35
|
+
const [popupOpened, setPopupOpened] = useState(false);
|
|
36
|
+
const [selectedCategory, setSelectedCategory] = useState(value || null);
|
|
37
|
+
|
|
38
|
+
// Aktualizuj selectedCategory když se změní value prop (pro Form.Item kompatibilitu)
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (value !== undefined) {
|
|
41
|
+
setSelectedCategory(value || null);
|
|
42
|
+
}
|
|
43
|
+
}, [value]);
|
|
44
|
+
|
|
45
|
+
const linkStyle = {
|
|
46
|
+
color,
|
|
47
|
+
cursor: 'pointer',
|
|
48
|
+
display: 'flex',
|
|
49
|
+
alignItems: 'center',
|
|
50
|
+
gap: '6px'
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const handleCancel = () => {
|
|
54
|
+
setSelectedCategory(value || null);
|
|
55
|
+
setPopupOpened(false);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const selectCategory = (category) => {
|
|
59
|
+
// Automaticky ulož a zavři popup
|
|
60
|
+
setSelectedCategory(category);
|
|
61
|
+
|
|
62
|
+
// Preferuj onChange pro Form.Item kompatibilitu, jinak použij onSave
|
|
63
|
+
if (onChange) {
|
|
64
|
+
onChange(category);
|
|
65
|
+
} else if (onSave) {
|
|
66
|
+
onSave(category);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setPopupOpened(false);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Určí jakou ikonu použít - priorita: icon > lucideIcon > výchozí Tag
|
|
73
|
+
const renderIcon = () => {
|
|
74
|
+
if (icon) {
|
|
75
|
+
return React.cloneElement(icon, { size, color, ...icon.props });
|
|
76
|
+
}
|
|
77
|
+
if (lucideIcon) {
|
|
78
|
+
const LucideIcon = lucideIcon;
|
|
79
|
+
return <LucideIcon size={size} color={color} />;
|
|
80
|
+
}
|
|
81
|
+
return <Tag size={size} color={color} />;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Zobrazí název vybrané kategorie nebo placeholder
|
|
85
|
+
const renderDisplayText = () => {
|
|
86
|
+
if (selectedCategory && selectedCategory.name) {
|
|
87
|
+
return selectedCategory.name;
|
|
88
|
+
}
|
|
89
|
+
return placeholder;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<>
|
|
94
|
+
<Link onClick={() => setPopupOpened(true)} className="link" style={linkStyle}>
|
|
95
|
+
{renderIcon()}
|
|
96
|
+
{renderDisplayText()}
|
|
97
|
+
</Link>
|
|
98
|
+
|
|
99
|
+
<Popup
|
|
100
|
+
opened={popupOpened}
|
|
101
|
+
onPopupClosed={() => setPopupOpened(false)}
|
|
102
|
+
animate
|
|
103
|
+
backdrop
|
|
104
|
+
push={false}
|
|
105
|
+
className="f7-parallax category-popup"
|
|
106
|
+
style={{
|
|
107
|
+
'--f7-popup-tablet-width': '90vw',
|
|
108
|
+
'--f7-popup-tablet-height': '90vh'
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
<div className="view view-init">
|
|
112
|
+
<div className="page page-with-navbar-large">
|
|
113
|
+
<Navbar large className="navbar-transparent">
|
|
114
|
+
<NavLeft>
|
|
115
|
+
<Link onClick={handleCancel}>
|
|
116
|
+
<Icon f7="arrow_left" style={{ fontWeight: 'bold' }} />
|
|
117
|
+
</Link>
|
|
118
|
+
</NavLeft>
|
|
119
|
+
<NavTitle>{title}</NavTitle>
|
|
120
|
+
<NavTitleLarge>{title}</NavTitleLarge>
|
|
121
|
+
</Navbar>
|
|
122
|
+
|
|
123
|
+
<div className="page-content">
|
|
124
|
+
{/* Dostupné kategorie */}
|
|
125
|
+
<Block>
|
|
126
|
+
<div style={{
|
|
127
|
+
display: 'grid',
|
|
128
|
+
gridTemplateColumns: 'repeat(auto-fit, minmax(80px, 1fr))',
|
|
129
|
+
gap: '15px',
|
|
130
|
+
marginTop: '15px',
|
|
131
|
+
padding: '10px 5px'
|
|
132
|
+
}}>
|
|
133
|
+
{categories.map((category) => {
|
|
134
|
+
const isSelected = selectedCategory && selectedCategory.id === category.id;
|
|
135
|
+
return (
|
|
136
|
+
<div key={category.id} style={{
|
|
137
|
+
display: 'flex',
|
|
138
|
+
justifyContent: 'center',
|
|
139
|
+
minWidth: '80px'
|
|
140
|
+
}}>
|
|
141
|
+
<CircleButton
|
|
142
|
+
icon={category.icon || 'tag'}
|
|
143
|
+
name={category.name}
|
|
144
|
+
bgColor={isSelected ? '#28a745' : (category.color || '#6887d3')}
|
|
145
|
+
iconColor="white"
|
|
146
|
+
textColor="#333"
|
|
147
|
+
onClick={() => selectCategory(category)}
|
|
148
|
+
style={{
|
|
149
|
+
opacity: isSelected ? 1 : 0.7,
|
|
150
|
+
transform: isSelected ? 'scale(1.05)' : 'scale(1)',
|
|
151
|
+
transition: 'all 0.2s ease',
|
|
152
|
+
width: '100%',
|
|
153
|
+
maxWidth: '100px'
|
|
154
|
+
}}
|
|
155
|
+
/>
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
})}
|
|
159
|
+
</div>
|
|
160
|
+
</Block>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
</Popup>
|
|
165
|
+
</>
|
|
166
|
+
);
|
|
167
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { ListInput } from 'framework7-react';
|
|
4
|
+
import { UserCheck } from 'lucide-react';
|
|
5
|
+
import { Custom } from './Custom';
|
|
6
|
+
|
|
7
|
+
// Renderer pro Contact formulář
|
|
8
|
+
const ContactRenderer = ({ fields, formData, onChange }) => {
|
|
9
|
+
const handleInputChange = (fieldKey, event) => {
|
|
10
|
+
const newValue = event.target.value;
|
|
11
|
+
onChange(fieldKey, newValue);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<>
|
|
16
|
+
{fields.map((field, index) => (
|
|
17
|
+
<ListInput
|
|
18
|
+
key={field.key || index}
|
|
19
|
+
type={field.type || 'text'}
|
|
20
|
+
label={field.label}
|
|
21
|
+
placeholder={field.placeholder}
|
|
22
|
+
value={formData[field.key] || ''}
|
|
23
|
+
onInput={(e) => handleInputChange(field.key, e)}
|
|
24
|
+
clearButton
|
|
25
|
+
style={{ fontSize: '18px' }}
|
|
26
|
+
// Speciální styling pro různé typy polí
|
|
27
|
+
{...(field.type === 'email' && {
|
|
28
|
+
inputMode: 'email',
|
|
29
|
+
autoComplete: 'email'
|
|
30
|
+
})}
|
|
31
|
+
{...(field.type === 'tel' && {
|
|
32
|
+
inputMode: 'tel',
|
|
33
|
+
autoComplete: 'tel'
|
|
34
|
+
})}
|
|
35
|
+
/>
|
|
36
|
+
))}
|
|
37
|
+
</>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Externí PM komponenta s předdefinovanými poli
|
|
42
|
+
export const Contact = ({
|
|
43
|
+
value,
|
|
44
|
+
onSave,
|
|
45
|
+
onChange,
|
|
46
|
+
title = 'Kontakt',
|
|
47
|
+
placeholder = 'Zadej kontakt',
|
|
48
|
+
color = '#6887d3',
|
|
49
|
+
size = 16,
|
|
50
|
+
...restProps
|
|
51
|
+
}) => {
|
|
52
|
+
// Předdefinovaná pole pro Externí PM
|
|
53
|
+
const pmFields = [
|
|
54
|
+
{
|
|
55
|
+
key: 'firstName',
|
|
56
|
+
label: 'Jméno',
|
|
57
|
+
type: 'text',
|
|
58
|
+
placeholder: 'Zadejte jméno'
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
key: 'lastName',
|
|
62
|
+
label: 'Příjmení',
|
|
63
|
+
type: 'text',
|
|
64
|
+
placeholder: 'Zadejte příjmení'
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
key: 'email',
|
|
68
|
+
label: 'Email',
|
|
69
|
+
type: 'email',
|
|
70
|
+
placeholder: 'Zadejte email'
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
key: 'phone',
|
|
74
|
+
label: 'Telefon',
|
|
75
|
+
type: 'tel',
|
|
76
|
+
placeholder: 'Zadejte telefon'
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
key: 'position',
|
|
80
|
+
label: 'Pozice',
|
|
81
|
+
type: 'text',
|
|
82
|
+
placeholder: 'Zadejte pozici'
|
|
83
|
+
}
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
// Pole pro zobrazení v linku - jméno, příjmení a pozice
|
|
87
|
+
const displayFields = ['firstName', 'lastName', 'position'];
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<Custom
|
|
91
|
+
value={value}
|
|
92
|
+
onSave={onSave}
|
|
93
|
+
onChange={onChange}
|
|
94
|
+
title={title}
|
|
95
|
+
placeholder={placeholder}
|
|
96
|
+
color={color}
|
|
97
|
+
size={size}
|
|
98
|
+
lucideIcon={UserCheck}
|
|
99
|
+
FormRenderer={ContactRenderer}
|
|
100
|
+
fields={pmFields}
|
|
101
|
+
displayFields={displayFields}
|
|
102
|
+
{...restProps}
|
|
103
|
+
/>
|
|
104
|
+
);
|
|
105
|
+
};
|
package/components/Custom.jsx
CHANGED
|
@@ -1,6 +1,211 @@
|
|
|
1
1
|
/* eslint-disable */
|
|
2
|
-
import React from 'react';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import React, { useState, useEffect } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
Link,
|
|
5
|
+
Icon,
|
|
6
|
+
Popup,
|
|
7
|
+
Navbar,
|
|
8
|
+
NavLeft,
|
|
9
|
+
NavTitle,
|
|
10
|
+
NavTitleLarge,
|
|
11
|
+
Page,
|
|
12
|
+
Block,
|
|
13
|
+
List,
|
|
14
|
+
ListInput
|
|
15
|
+
} from 'framework7-react';
|
|
16
|
+
import { User } from 'lucide-react';
|
|
17
|
+
import SaveButton from '@bit.rhplus/ui.f7.save-button';
|
|
18
|
+
|
|
19
|
+
// External Contact komponenta - formulář pro zadání externího kontaktu
|
|
20
|
+
export const Custom = ({
|
|
21
|
+
value,
|
|
22
|
+
onSave,
|
|
23
|
+
onChange,
|
|
24
|
+
title = 'Externí kontakt',
|
|
25
|
+
placeholder = 'Zadejte kontakt',
|
|
26
|
+
color = '#6887d3',
|
|
27
|
+
size = 16,
|
|
28
|
+
lucideIcon,
|
|
29
|
+
icon,
|
|
30
|
+
FormRenderer, // Custom komponenta pro renderování formuláře
|
|
31
|
+
fields = [ // Výchozí definice polí
|
|
32
|
+
{ key: 'firstName', label: 'Jméno', type: 'text', placeholder: 'Zadejte jméno' },
|
|
33
|
+
{ key: 'lastName', label: 'Příjmení', type: 'text', placeholder: 'Zadejte příjmení' },
|
|
34
|
+
{ key: 'phone', label: 'Telefon', type: 'tel', placeholder: 'Zadejte telefon' },
|
|
35
|
+
{ key: 'email', label: 'Email', type: 'email', placeholder: 'Zadejte email' },
|
|
36
|
+
{ key: 'position', label: 'Pozice', type: 'text', placeholder: 'Zadejte pozici' }
|
|
37
|
+
],
|
|
38
|
+
displayFields = ['firstName', 'lastName', 'position'], // Pole pro zobrazení v linku
|
|
39
|
+
...restProps
|
|
40
|
+
}) => {
|
|
41
|
+
const [popupOpened, setPopupOpened] = useState(false);
|
|
42
|
+
|
|
43
|
+
// Dynamicky inicializuj formData na základě fields
|
|
44
|
+
const getInitialFormData = () => {
|
|
45
|
+
const initialData = {};
|
|
46
|
+
fields.forEach(field => {
|
|
47
|
+
initialData[field.key] = '';
|
|
48
|
+
});
|
|
49
|
+
return initialData;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const [formData, setFormData] = useState(getInitialFormData());
|
|
53
|
+
|
|
54
|
+
// Aktualizuj formData když se změní value prop nebo fields (ale ne když je popup otevřený)
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (popupOpened) return; // Neaktualizuj formData když je popup otevřený
|
|
57
|
+
|
|
58
|
+
const newFormData = {};
|
|
59
|
+
fields.forEach(field => {
|
|
60
|
+
newFormData[field.key] = '';
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (value && typeof value === 'object') {
|
|
64
|
+
fields.forEach(field => {
|
|
65
|
+
newFormData[field.key] = value[field.key] || '';
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setFormData(newFormData);
|
|
70
|
+
}, [value, fields, popupOpened]);
|
|
71
|
+
|
|
72
|
+
const linkStyle = {
|
|
73
|
+
color,
|
|
74
|
+
cursor: 'pointer',
|
|
75
|
+
display: 'flex',
|
|
76
|
+
alignItems: 'center',
|
|
77
|
+
gap: '6px'
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const handleSave = () => {
|
|
81
|
+
const result = { ...formData };
|
|
82
|
+
|
|
83
|
+
if (onChange) {
|
|
84
|
+
onChange(result);
|
|
85
|
+
} else if (onSave) {
|
|
86
|
+
onSave(result);
|
|
87
|
+
}
|
|
88
|
+
setPopupOpened(false);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const handleCancel = () => {
|
|
92
|
+
const newFormData = {};
|
|
93
|
+
fields.forEach(field => {
|
|
94
|
+
newFormData[field.key] = '';
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
if (value && typeof value === 'object') {
|
|
98
|
+
fields.forEach(field => {
|
|
99
|
+
newFormData[field.key] = value[field.key] || '';
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
setFormData(newFormData);
|
|
104
|
+
setPopupOpened(false);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const handleInputChange = (field, newValue) => {
|
|
108
|
+
setFormData(prev => ({
|
|
109
|
+
...prev,
|
|
110
|
+
[field]: newValue
|
|
111
|
+
}));
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const handleOpenPopup = () => {
|
|
115
|
+
// Před otevřením popupu nastav aktuální hodnoty do formData
|
|
116
|
+
const newFormData = {};
|
|
117
|
+
fields.forEach(field => {
|
|
118
|
+
newFormData[field.key] = '';
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (value && typeof value === 'object') {
|
|
122
|
+
fields.forEach(field => {
|
|
123
|
+
newFormData[field.key] = value[field.key] || '';
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
setFormData(newFormData);
|
|
128
|
+
setPopupOpened(true);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Určí jakou ikonu použít - priorita: icon > lucideIcon > výchozí User
|
|
132
|
+
const renderIcon = () => {
|
|
133
|
+
if (icon) {
|
|
134
|
+
return React.cloneElement(icon, { size, color, ...icon.props });
|
|
135
|
+
}
|
|
136
|
+
if (lucideIcon) {
|
|
137
|
+
const LucideIcon = lucideIcon;
|
|
138
|
+
return <LucideIcon size={size} color={color} />;
|
|
139
|
+
}
|
|
140
|
+
return <User size={size} color={color} />;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// Zobrazí text v linku podle vyplněných dat
|
|
144
|
+
const getDisplayText = () => {
|
|
145
|
+
if (value && typeof value === 'object') {
|
|
146
|
+
const displayValues = displayFields
|
|
147
|
+
.map(fieldKey => value[fieldKey])
|
|
148
|
+
.filter(Boolean);
|
|
149
|
+
|
|
150
|
+
if (displayValues.length > 0) {
|
|
151
|
+
return displayValues.join(' - ');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return placeholder;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<div {...restProps}>
|
|
159
|
+
<Link onClick={handleOpenPopup} className="link" style={linkStyle}>
|
|
160
|
+
{renderIcon()}
|
|
161
|
+
{getDisplayText()}
|
|
162
|
+
</Link>
|
|
163
|
+
|
|
164
|
+
<Popup
|
|
165
|
+
opened={popupOpened}
|
|
166
|
+
onPopupClosed={() => setPopupOpened(false)}
|
|
167
|
+
animate
|
|
168
|
+
backdrop
|
|
169
|
+
className="f7-parallax"
|
|
170
|
+
>
|
|
171
|
+
<Page>
|
|
172
|
+
<Navbar large>
|
|
173
|
+
<NavLeft>
|
|
174
|
+
<Link onClick={handleCancel}>
|
|
175
|
+
<Icon f7="arrow_left" style={{ fontWeight: 'bold' }} />
|
|
176
|
+
</Link>
|
|
177
|
+
</NavLeft>
|
|
178
|
+
<NavTitle>{title}</NavTitle>
|
|
179
|
+
<NavTitleLarge>{title}</NavTitleLarge>
|
|
180
|
+
</Navbar>
|
|
181
|
+
|
|
182
|
+
<Block style={{ marginTop: '20px' }}>
|
|
183
|
+
<List>
|
|
184
|
+
{FormRenderer ? (
|
|
185
|
+
<FormRenderer
|
|
186
|
+
fields={fields}
|
|
187
|
+
formData={formData}
|
|
188
|
+
onChange={handleInputChange}
|
|
189
|
+
/>
|
|
190
|
+
) : (
|
|
191
|
+
fields.map((field, index) => (
|
|
192
|
+
<ListInput
|
|
193
|
+
key={field.key || index}
|
|
194
|
+
type={field.type || 'text'}
|
|
195
|
+
label={field.label}
|
|
196
|
+
placeholder={field.placeholder}
|
|
197
|
+
value={formData[field.key]}
|
|
198
|
+
onInput={(e) => handleInputChange(field.key, e.target.value)}
|
|
199
|
+
clearButton
|
|
200
|
+
style={{ fontSize: '18px' }}
|
|
201
|
+
/>
|
|
202
|
+
))
|
|
203
|
+
)}
|
|
204
|
+
</List>
|
|
205
|
+
</Block>
|
|
206
|
+
<SaveButton onClick={handleSave} variant="black" />
|
|
207
|
+
</Page>
|
|
208
|
+
</Popup>
|
|
209
|
+
</div>
|
|
210
|
+
);
|
|
6
211
|
};
|
package/components/Download.jsx
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
/* eslint-disable */
|
|
2
2
|
import React, { useState } from 'react';
|
|
3
3
|
import { Link, Icon, Preloader } from 'framework7-react';
|
|
4
|
+
import { Download as DownloadIcon } from 'lucide-react';
|
|
4
5
|
|
|
5
6
|
// Download komponenta s loading stavem
|
|
6
|
-
export const Download = ({
|
|
7
|
+
export const Download = ({
|
|
8
|
+
children,
|
|
9
|
+
href,
|
|
10
|
+
onClick,
|
|
11
|
+
color = '#6887d3',
|
|
12
|
+
size = 16,
|
|
13
|
+
value,
|
|
14
|
+
lucideIcon, // Lucide React ikona
|
|
15
|
+
icon, // Jakákoliv React komponenta ikony
|
|
16
|
+
...restProps
|
|
17
|
+
}) => {
|
|
18
|
+
// Pro Form.Item kompatibilitu - zobraz value pokud je poskytnut, jinak children
|
|
19
|
+
const displayText = value !== undefined ? value : children;
|
|
7
20
|
const [isLoading, setIsLoading] = useState(false);
|
|
8
21
|
|
|
9
22
|
const handleClick = async (e) => {
|
|
@@ -24,28 +37,40 @@ export const Download = ({ children, href, onClick, color = '#6887d3', size = 16
|
|
|
24
37
|
alignItems: 'center',
|
|
25
38
|
gap: '6px'
|
|
26
39
|
};
|
|
40
|
+
|
|
41
|
+
// Určí jakou ikonu použít - priorita: icon > lucideIcon > výchozí DownloadIcon
|
|
42
|
+
const renderIcon = () => {
|
|
43
|
+
if (icon) {
|
|
44
|
+
return React.cloneElement(icon, { size, color, ...icon.props });
|
|
45
|
+
}
|
|
46
|
+
if (lucideIcon) {
|
|
47
|
+
const LucideIcon = lucideIcon;
|
|
48
|
+
return <LucideIcon size={size} color={color} />;
|
|
49
|
+
}
|
|
50
|
+
return <DownloadIcon size={size} color={color} />;
|
|
51
|
+
};
|
|
27
52
|
|
|
28
53
|
if (href) {
|
|
29
54
|
return (
|
|
30
|
-
<Link href={href} className="link" style={linkStyle}>
|
|
55
|
+
<Link href={href} className="link" style={linkStyle} {...restProps}>
|
|
31
56
|
{isLoading ? (
|
|
32
57
|
<Preloader size={size} />
|
|
33
58
|
) : (
|
|
34
|
-
|
|
59
|
+
renderIcon()
|
|
35
60
|
)}
|
|
36
|
-
{
|
|
61
|
+
{displayText}
|
|
37
62
|
</Link>
|
|
38
63
|
);
|
|
39
64
|
}
|
|
40
65
|
|
|
41
66
|
return (
|
|
42
|
-
<Link onClick={handleClick} className="link" style={linkStyle}>
|
|
67
|
+
<Link onClick={handleClick} className="link" style={linkStyle} {...restProps}>
|
|
43
68
|
{isLoading ? (
|
|
44
69
|
<Preloader size={size} />
|
|
45
70
|
) : (
|
|
46
|
-
|
|
71
|
+
renderIcon()
|
|
47
72
|
)}
|
|
48
|
-
{
|
|
73
|
+
{displayText}
|
|
49
74
|
</Link>
|
|
50
75
|
);
|
|
51
76
|
};
|