@ledvance/base 1.1.16 → 1.1.17

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/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "name": "@ledvance/base",
5
5
  "pid": [],
6
6
  "uiid": "",
7
- "version": "1.1.16",
7
+ "version": "1.1.17",
8
8
  "scripts": {},
9
9
  "dependencies": {
10
10
  "@reduxjs/toolkit": "^1.8.6",
@@ -1,41 +1,70 @@
1
- import {IconFont, Utils} from 'tuya-panel-kit'
2
- import {StyleProp, Text, TouchableOpacity, View, ViewStyle} from 'react-native'
1
+ import { IconFont, Utils } from 'tuya-panel-kit'
2
+ import { StyleProp, Text, TextStyle, TouchableOpacity, View, ViewStyle } from 'react-native'
3
3
  import React from 'react'
4
4
 
5
5
  const cx = Utils.RatioUtils.convertX
6
6
 
7
7
  interface CellProps {
8
- title: string,
9
- value: string,
10
- onPress: () => void,
11
- style?: StyleProp<ViewStyle>
8
+ title: string,
9
+ value: string,
10
+ onPress: () => void,
11
+ style?: StyleProp<ViewStyle>
12
12
  }
13
13
 
14
14
  export default function Cell(props: CellProps) {
15
- return (
16
- <TouchableOpacity
17
- style={[{
18
- height: cx(50),
19
- paddingHorizontal: cx(24),
20
- justifyContent: 'center',
21
- }, props.style]}
22
- onPress={props.onPress}>
23
- <View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
24
- <Text style={{
25
- fontSize: cx(14),
26
- color: '#444',
27
- fontFamily: 'helvetica_neue_lt_std_roman',
28
- }}>{props.title}</Text>
29
- <View style={{flexDirection: 'row', alignItems: 'center'}}>
30
- <Text style={{
31
- fontSize: cx(14),
32
- color: '#444',
33
- fontFamily: 'helvetica_neue_lt_std_roman',
34
- }}>{props.value}</Text>
35
- <View style={{width: cx(4)}}/>
36
- <IconFont color={'#444'} size={cx(11)} name="arrow"/>
15
+ return (
16
+ <TouchableOpacity
17
+ style={[{
18
+ height: cx(50),
19
+ paddingHorizontal: cx(24),
20
+ justifyContent: 'center',
21
+ }, props.style]}
22
+ onPress={props.onPress}>
23
+ <CellContent title={props.title} value={props.value} />
24
+ </TouchableOpacity>
25
+ )
26
+ }
27
+
28
+ interface CellContentProps {
29
+ title: string
30
+ value: string
31
+ style?: StyleProp<ViewStyle>
32
+ titleStyle?: StyleProp<TextStyle>
33
+ valueStyle?: StyleProp<TextStyle>
34
+ iconStyle?: { color?: any, size?: number }
35
+ }
36
+
37
+ export function CellContent(props: CellContentProps) {
38
+ return (
39
+ <View
40
+ style={[
41
+ { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },
42
+ props.style,
43
+ ]}>
44
+ <Text
45
+ style={[
46
+ {
47
+ fontSize: cx(14),
48
+ color: '#444',
49
+ fontFamily: 'helvetica_neue_lt_std_roman',
50
+ },
51
+ props.titleStyle,
52
+ ]}>{props.title}</Text>
53
+ <View style={{ flexDirection: 'row', alignItems: 'center' }}>
54
+ <Text style={[
55
+ {
56
+ fontSize: cx(14),
57
+ color: '#444',
58
+ fontFamily: 'helvetica_neue_lt_std_roman',
59
+ },
60
+ props.valueStyle,
61
+ ]}>{props.value}</Text>
62
+ <View style={{ width: cx(4) }} />
63
+ <IconFont
64
+ name="arrow"
65
+ color={props.iconStyle?.color || '#444'}
66
+ size={props.iconStyle?.size || cx(11)} />
67
+ </View>
37
68
  </View>
38
- </View>
39
- </TouchableOpacity>
40
- )
69
+ )
41
70
  }
@@ -0,0 +1,375 @@
1
+ import React, { Component } from 'react'
2
+ import { Dimensions, Image, PanResponder, View, StyleSheet, PanResponderInstance } from 'react-native'
3
+ import { TYSdk } from 'tuya-panel-kit'
4
+
5
+ import ColorUtils from '../utils/ColorUtils'
6
+ import res from '@res'
7
+
8
+ export default class ColorExtractor extends Component<any> {
9
+ state: any
10
+ _panResponder: PanResponderInstance
11
+ onColorChange: any
12
+ lastX: any
13
+ lastY: any
14
+ self: any
15
+ startTouchXY: any
16
+
17
+ constructor(props) {
18
+ super(props)
19
+ let {
20
+ thumbSizeW,
21
+ radius,
22
+ color,
23
+ onColorChange,
24
+ colorTemperatureInterval,
25
+ miniColorTemperature,
26
+ } = !!props && props
27
+ this.onColorChange = onColorChange
28
+ radius = radius || 130
29
+ thumbSizeW = thumbSizeW || 30
30
+ const currentColor = color
31
+ this.state = {
32
+ thumbSizeW,
33
+ radius,
34
+ offset: { x: radius - thumbSizeW / 2, y: radius - thumbSizeW / 2 },
35
+ currentColor,
36
+ ratio: 0,
37
+ miniColorTemperature: !!miniColorTemperature ? miniColorTemperature : 2700,
38
+ colorTemperatureInterval: colorTemperatureInterval,
39
+ }
40
+ this.lastX = radius - thumbSizeW / 2
41
+ this.lastY = radius - thumbSizeW / 2
42
+ }
43
+
44
+ onLayout(_: any) {
45
+
46
+ }
47
+
48
+ componentDidMount() {
49
+ this.updateUIWithColor(this.state.currentColor, true)
50
+ // 图标的手势
51
+ this._panResponder = PanResponder.create({
52
+ onMoveShouldSetPanResponder: () => {
53
+ return true
54
+ },
55
+ onPanResponderMove: (evt, gestureState) => {
56
+ this.handlerData(evt, gestureState, true)
57
+ },
58
+ onPanResponderRelease: (evt, gestureState) => {
59
+ this.handlerData(evt, gestureState, false)
60
+ },
61
+ })
62
+
63
+ if (this.props.showColorTemperature) {
64
+ TYSdk.event.off('onColorTempChange')
65
+ TYSdk.event.on('onColorTempChange', (color) => {
66
+ this.updateUIWithColor(color, false)
67
+ })
68
+ } else {
69
+ TYSdk.event.off('onColorChange')
70
+ TYSdk.event.on('onColorChange', (color) => {
71
+ this.updateUIWithColor(color, false)
72
+ })
73
+ }
74
+ }
75
+
76
+ componentWillUnmount() {
77
+ TYSdk.event.off('onColorChange')
78
+ TYSdk.event.off('onColorTempChange')
79
+ }
80
+
81
+ handleTapData(evt) {
82
+ if (!!this.props.disabled) {
83
+ return
84
+ }
85
+ let tapX = evt.nativeEvent.locationX
86
+ let tapY = evt.nativeEvent.locationY
87
+ let result = this.getPointValues(tapX, tapY)
88
+ let maxX = result.maxX
89
+ let maxY = result.maxY
90
+ this.setState({
91
+ offset: {
92
+ x: maxX,
93
+ y: maxY,
94
+ },
95
+ })
96
+ this.lastX = maxX
97
+ this.lastY = maxY
98
+ this.updateColor(evt.nativeEvent.locationX, evt.nativeEvent.locationY, false)
99
+ }
100
+
101
+ handlerData(_evt, ges, moving) {
102
+ if (!!this.props.disabled) {
103
+ return
104
+ }
105
+
106
+ //此时视图的坐标
107
+ let locationX = this.lastX + ges.dx + this.state.thumbSizeW / 2
108
+ let locationY = this.lastY + ges.dy + this.state.thumbSizeW / 2
109
+ // 获取在父元素的实际坐标点值
110
+ let result = this.getPointValues(locationX, locationY)
111
+ let maxX = result.maxX
112
+ let maxY = result.maxY
113
+ // 获取此点的颜色值
114
+ this.updateColor(locationX, locationY, moving)
115
+
116
+ this.setState({
117
+ offset: {
118
+ x: maxX,
119
+ y: maxY,
120
+ },
121
+ })
122
+
123
+ if (!(!!moving)) {
124
+ // 记录滑动前 图表的位置
125
+ this.lastX = this.state.offset.x
126
+ this.lastY = this.state.offset.y
127
+ }
128
+ }
129
+
130
+ // 获取实际坐标的 角度 坐标值 步长
131
+ getPointValues(locationX, locationY) {
132
+ //半径
133
+ let radius = this.state.radius
134
+ // 求斜边的长度
135
+ let offsetX = Math.abs(radius - locationX)
136
+ let offsetY = Math.abs(radius - locationY)
137
+ let length = Math.sqrt(offsetX * offsetX + offsetY * offsetY)// 斜边长度
138
+ //求角度
139
+ // let angle = Math.atan2(offsetY, offsetX) * (180 / Math.PI)
140
+ let angle = this.getPointAngle(radius - locationX, radius - locationY)
141
+ // console.log('是否出界'+[locationX,locationY,angle])
142
+ // 最终的坐标
143
+ let maxX = locationX - this.state.thumbSizeW / 2//this.lastX + ges.dx
144
+ let maxY = locationY - this.state.thumbSizeW / 2//this.lastY + ges.dy
145
+ if (length > this.state.radius) {
146
+ // 超出边界
147
+ let maxOffsetX = this.state.radius * (locationX - radius) / length
148
+ let maxOffsetY = this.state.radius * (radius - locationY) / length
149
+ maxX = radius + maxOffsetX - this.state.thumbSizeW / 2
150
+ maxY = radius - maxOffsetY - this.state.thumbSizeW / 2
151
+ length = this.state.radius
152
+ }
153
+ return {
154
+ angle: angle,
155
+ maxX: maxX,
156
+ maxY: maxY,
157
+ length: length,
158
+ }
159
+ }
160
+
161
+ getPointAngle(x, y) {
162
+ // 此时的角度是从左边为 0°开始 顺时针 到右边为 180° 逆时针到最右边为 -180°
163
+ let angle = Math.atan2(y, x) * (180 / Math.PI)
164
+ // 此转换为左边 0° 顺时针转一圈为 360°
165
+ angle = 180 - angle
166
+ //console.log('获取角度' + angle)
167
+ return angle
168
+ }
169
+
170
+ // 根据颜色值更新图标的位置 color : #ffffff
171
+ updateUIWithColor(color, isFirst) {
172
+ const { radius } = this.state
173
+ // 根据初始的颜色值回去图标的坐标
174
+ const hsv = ColorUtils.hex2Hsv(color)
175
+ //console.log('初始值颜色' + [hsv.h, hsv.s, hsv.v])
176
+
177
+ //角度
178
+ let angle = 180 - hsv.h
179
+ // 在色盘中的步长
180
+ let length = (radius / 100) * hsv.s
181
+ //
182
+ const offset = this.hypotenuse(length, angle)
183
+ const offsetX = radius - offset.x - this.state.thumbSizeW / 2
184
+ const offsetY = radius - offset.y - this.state.thumbSizeW / 2
185
+
186
+ this.lastX = offsetX
187
+ this.lastY = offsetY
188
+ this.setState({
189
+ currentColor: color,
190
+ offset: {
191
+ x: offsetX,
192
+ y: offsetY,
193
+ },
194
+ ratio: hsv.s / 100,
195
+ }, () => {
196
+ this.updateColor(offsetX + this.state.thumbSizeW / 2, offsetY + this.state.thumbSizeW / 2, false, isFirst)
197
+ })
198
+ }
199
+
200
+ //已知角度和斜边,求直角边
201
+ hypotenuse(long, angle) {
202
+ //获得弧度
203
+ const radian = 2 * Math.PI / 360 * angle
204
+ return {
205
+ x: Math.cos(radian) * long,
206
+ y: Math.sin(radian) * long,
207
+ }
208
+ }
209
+
210
+ // 根据坐标的位置 获取颜色值
211
+ updateColor(x, y, moving, isFirst?: boolean) {
212
+ const { angle, length } = this.getPointValues(x, y)
213
+ //console.log('根据坐标的位置 获取颜色值', angle, maxX, maxY, length);
214
+ let radius = length / this.state.radius
215
+ const rad = radius > 1 ? 1 : radius
216
+ const hsv = { h: angle, s: 100 * rad, v: 100 }
217
+ const currentColor = ColorUtils.hsv2Hex(hsv)
218
+ this.setState({ currentColor, ratio: rad })
219
+ //console.log('获取当前的颜色' + [currentColor, angle])
220
+ //滑动结束 发送当前颜色值
221
+ if (moving === false) {
222
+ this.onColorChange && this.onColorChange(hsv, isFirst)
223
+ }
224
+ }
225
+
226
+ render() {
227
+ const { radius, offset, ratio, miniColorTemperature, colorTemperatureInterval } = this.state
228
+ const { x, y } = offset
229
+ const { showColorTemperature } = this.props
230
+ return (
231
+ <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
232
+ <View
233
+ ref={node => {
234
+ this.self = node
235
+ }}
236
+ onLayout={nativeEvent => this.onLayout(nativeEvent)}
237
+ style={[{
238
+ height: radius * 2,
239
+ width: radius * 2,
240
+ }, this.props.style]}>
241
+
242
+ <View
243
+ style={[styles.img, {
244
+ height: radius * 2,
245
+ width: radius * 2,
246
+ }]}>
247
+ <Image
248
+ style={{
249
+ height: radius * 2,
250
+ width: radius * 2,
251
+ alignItems: 'center',
252
+ position: 'absolute',
253
+ }}
254
+ source={{ uri: !!showColorTemperature ? res.color_temperature_wheel : res.color_wheel }}
255
+ // @ts-ignore
256
+ onStartShouldSetResponder={(evt) => {
257
+ this.startTouchXY = evt.nativeEvent
258
+ return true
259
+ }}
260
+ onResponderMove={() => {
261
+ return false
262
+ }}
263
+ onResponderRelease={(evt) => {
264
+ const { locationX, locationY, timestamp } = !!this.startTouchXY && this.startTouchXY
265
+ const endLocationX = evt.nativeEvent.locationX
266
+ const endLocationY = evt.nativeEvent.locationY
267
+ const endTimestamp = evt.nativeEvent.timestamp
268
+
269
+ if (Math.abs(locationX - endLocationX) <= 10 && Math.abs(locationY - endLocationY) <= 10 && endTimestamp - timestamp < 500) {
270
+ this.handleTapData(evt)
271
+ }
272
+ }} />
273
+ {<View
274
+ {...(this._panResponder || {}).panHandlers}
275
+ style={{
276
+ marginTop: y,
277
+ marginLeft: x,
278
+ width: this.state.thumbSizeW,
279
+ height: this.state.thumbSizeW,
280
+ position: 'absolute',
281
+ backgroundColor: '#ffffff',
282
+ elevation: !!this.props.disabled ? 0 : 3,
283
+ shadowOpacity: 0.15,
284
+ shadowRadius: 5,
285
+ shadowOffset: { width: 0, height: 3.5 },
286
+ borderRadius: this.state.thumbSizeW / 2,
287
+ }}>
288
+ {!(!!showColorTemperature) && <View
289
+ style={{
290
+ marginTop: 3,
291
+ marginLeft: 3,
292
+ width: this.state.thumbSizeW - 6,
293
+ height: this.state.thumbSizeW - 6,
294
+ position: 'absolute',
295
+ backgroundColor: this.state.currentColor,
296
+ borderRadius: (this.state.thumbSizeW - 6) / 2,
297
+ }}>
298
+ </View>}
299
+
300
+ {!!showColorTemperature && <View
301
+ style={{
302
+ marginTop: 3,
303
+ marginLeft: 3,
304
+ width: this.state.thumbSizeW - 6,
305
+ height: this.state.thumbSizeW - 6,
306
+ position: 'absolute',
307
+ backgroundColor: colorTemperatureToColor(miniColorTemperature + ratio * colorTemperatureInterval),
308
+ borderRadius: (this.state.thumbSizeW - 6) / 2,
309
+ }}>
310
+ </View>}
311
+ </View>}
312
+ </View>
313
+ </View>
314
+ </View>
315
+ )
316
+ }
317
+ }
318
+ const styles = StyleSheet.create({
319
+ colorWheelStyle: {
320
+ width: Dimensions.get('window').width,
321
+ },
322
+ coverResponder: {
323
+ width: 260,
324
+ height: 260,
325
+ },
326
+ img: {},
327
+ })
328
+
329
+ export const colorTemperature = {
330
+ 2700: '#FFDC94',
331
+ 2800: '#FFDD96',
332
+ 2900: '#FFDF9A',
333
+ 3000: '#FFE19D',
334
+ 3100: '#FFE29F',
335
+ 3200: '#FFE4A3',
336
+ 3300: '#FFE5A6',
337
+ 3400: '#FFE7A9',
338
+ 3500: '#FFE8AC',
339
+ 3600: '#FFEAAF',
340
+ 3700: '#FFECB3',
341
+ 3800: '#FFEDB6',
342
+ 3900: '#FFEFB9',
343
+ 4000: '#FFF0BB',
344
+ 4100: '#FFF2BF',
345
+ 4200: '#FFF3C2',
346
+ 4300: '#FFF5C5',
347
+ 4400: '#FFF6C8',
348
+ 4500: '#FFF8CB',
349
+ 4600: '#FFFACF',
350
+ 4700: '#FFFBD2',
351
+ 4800: '#FFFCD4',
352
+ 4900: '#FFFDD7',
353
+ 5000: '#FEFEDA',
354
+ 5100: '#FEFEDD',
355
+ 5200: '#FEFFE0',
356
+ 5300: '#FAFEE1',
357
+ 5400: '#F7FEE3',
358
+ 5500: '#F3FCE3',
359
+ 5600: '#F0FCE4',
360
+ 5700: '#EDFBE6',
361
+ 5800: '#E9FAE6',
362
+ 5900: '#E5F9E8',
363
+ 6000: '#E2F9E9',
364
+ 6100: '#DFF8EA',
365
+ 6200: '#DCF7EC',
366
+ 6300: '#D7F6EC',
367
+ 6400: '#D4F5ED',
368
+ 6500: '#D1F5EF',
369
+ }
370
+
371
+ export const colorTemperatureToColor = (temperature) => {
372
+ const colorTemperatureValue = parseInt(`${temperature / 100}`, 10) * 100
373
+ //console.log("colorTemperatureValue :::::: ",colorTemperatureValue,colorTemperature[`${colorTemperatureValue}`])
374
+ return colorTemperature[colorTemperatureValue]
375
+ }
@@ -0,0 +1,59 @@
1
+ import Card from './Card'
2
+ import { FlatList, StyleProp, StyleSheet, View, ViewProps, ViewStyle } from 'react-native'
3
+ import TextButton from './TextButton'
4
+ import Dialog from './Dialog'
5
+ import React from 'react'
6
+ import { Utils } from 'tuya-panel-kit'
7
+
8
+ const cx = Utils.RatioUtils.convertX
9
+
10
+ interface ListData {
11
+ text: string
12
+ value?: any
13
+ }
14
+
15
+ interface CustomListDialogProps extends ViewProps {
16
+ itemStyle?: StyleProp<ViewStyle>
17
+ show: boolean
18
+ onDismiss: () => void
19
+ data: ListData[]
20
+ onItemPress: (item: any | undefined, index: number) => void
21
+ }
22
+
23
+ const CustomListDialog = (props: CustomListDialogProps) => {
24
+ return <Dialog
25
+ show={props.show}
26
+ hideMask={true}
27
+ onRequestClose={props.onDismiss}>
28
+ <Card style={props.style} shadowHeight={cx(7)}>
29
+ <FlatList
30
+ data={props.data}
31
+ renderItem={({ item, index }) => {
32
+ return (
33
+ <TextButton
34
+ text={item.text}
35
+ style={props.itemStyle}
36
+ textStyle={styles.popoverItemText}
37
+ onPress={() => {
38
+ props.onItemPress(item.value, index)
39
+ }} />
40
+ )
41
+ }}
42
+ keyExtractor={(_, index) => `${index}`}
43
+ ItemSeparatorComponent={() => (<View style={styles.line} />)} />
44
+ </Card>
45
+ </Dialog>
46
+ }
47
+
48
+ const styles = StyleSheet.create({
49
+ popoverItemText: {
50
+ color: '#000',
51
+ fontSize: cx(16),
52
+ },
53
+ line: {
54
+ height: .5,
55
+ backgroundColor: 'rgba(60,60,67,.36)',
56
+ },
57
+ })
58
+
59
+ export default CustomListDialog
@@ -1,12 +1,18 @@
1
- import React, {PropsWithChildren} from 'react'
2
- import {View, ViewProps} from 'react-native'
1
+ import React, { PropsWithChildren, useCallback } from 'react'
2
+ import { View, ViewProps } from 'react-native'
3
3
  import LDVTopBar from './ldvTopBar'
4
- import {useNavigation} from '@react-navigation/native'
4
+ import { useNavigation } from '@react-navigation/native'
5
5
  import LdvTopName from './ldvTopName'
6
+ import { Dialog, Toast } from 'tuya-panel-kit'
7
+ import I18n from '../i18n'
6
8
 
7
9
  interface PageProps extends PropsWithChildren<ViewProps> {
10
+ rightButtonDisabled?: boolean
8
11
  backText: string
9
12
  onBackClick?: () => void
13
+ showBackDialog?: boolean
14
+ backDialogTitle?: string
15
+ backDialogContent?: string
10
16
  rightButtonIcon?: string
11
17
  rightButtonIconClick?: () => void
12
18
  headlineText?: string
@@ -14,31 +20,59 @@ interface PageProps extends PropsWithChildren<ViewProps> {
14
20
  onHeadlineIconClick?: () => void
15
21
  showGreenery?: boolean
16
22
  greeneryIcon?: string | undefined | number
23
+ loading?: boolean
17
24
  }
18
25
 
19
26
  const Page = (props: PageProps) => {
20
27
  const navigation = useNavigation()
28
+ const disabled = props.rightButtonDisabled
21
29
 
30
+ const onBack = useCallback(() => {
31
+ if (disabled) {
32
+ navigation.goBack()
33
+ return true
34
+ }
35
+ Dialog.confirm({
36
+ title: props.backDialogTitle || '',
37
+ subTitle: props.backDialogContent || '',
38
+ cancelText: I18n.getLang('cancel_dialog_delete_item_sleepschedule_answer_no_text'),
39
+ confirmText: I18n.getLang('cancel_dialog_delete_item_sleepschedule_answer_yes_text'),
40
+ onConfirm: (_, { close }) => {
41
+ close()
42
+ navigation.goBack()
43
+ },
44
+ })
45
+ return true
46
+ },
47
+ [props.backDialogTitle, props.backDialogContent, disabled],
48
+ )
22
49
  return (
23
- <View style={[{flex: 1}, props.style]}>
24
- <LDVTopBar
25
- title={props.backText}
26
- onBackPress={props.onBackClick || (() => {
27
- navigation.goBack()
28
- })}
29
- rightButtonIcon={props.rightButtonIcon}
30
- onRightButtonPress={props.rightButtonIconClick}
31
- />
32
- {props.headlineText &&
50
+ <>
51
+ <View style={[{ flex: 1 }, props.style]}>
52
+ <LDVTopBar
53
+ title={props.backText}
54
+ onBackPress={props.onBackClick || (() => {
55
+ navigation.goBack()
56
+ })}
57
+ rightButtonIcon={props.rightButtonIcon}
58
+ onRightButtonPress={props.rightButtonIconClick}
59
+ />
60
+ {props.headlineText &&
33
61
  <LdvTopName
34
- title={props.headlineText}
35
- rightIcon={props.headlineIcon}
36
- rightIconClick={props.onHeadlineIconClick}
37
- showGreenery={props.showGreenery}
38
- greeneryIcon={props.greeneryIcon}
62
+ title={props.headlineText}
63
+ rightIcon={props.headlineIcon}
64
+ rightIconClick={props.onHeadlineIconClick}
65
+ showGreenery={props.showGreenery}
66
+ greeneryIcon={props.greeneryIcon}
39
67
  />}
40
- {props.children}
41
- </View>
68
+ {props.children}
69
+ </View>
70
+ <Toast.Loading
71
+ show={!!props.loading}
72
+ onFinish={() => {
73
+
74
+ }} />
75
+ </>
42
76
  )
43
77
  }
44
78
 
@@ -1,4 +1,4 @@
1
- import {Image, StyleSheet, Text, TextInput, TextInputProps, TouchableOpacity, View} from 'react-native'
1
+ import {Image, StyleSheet, Text, TextInput, TextInputProps, ImageSourcePropType,TouchableOpacity, View} from 'react-native'
2
2
  import React from 'react'
3
3
  import {Utils} from 'tuya-panel-kit'
4
4
  import res from '../res'
@@ -6,7 +6,10 @@ import res from '../res'
6
6
  const cx = Utils.RatioUtils.convertX
7
7
 
8
8
  interface TextFieldProps extends TextInputProps {
9
-
9
+ showError?: boolean
10
+ errorText?: string
11
+ tipIcon?: ImageSourcePropType
12
+ tipColor?: string
10
13
  }
11
14
 
12
15
  const TextField = (props: TextFieldProps) => {
@@ -0,0 +1,65 @@
1
+ import { StyleSheet, Text, TouchableOpacity, View, ViewProps } from 'react-native'
2
+ import { Utils } from 'tuya-panel-kit'
3
+ import React from 'react'
4
+
5
+ const cx = Utils.RatioUtils.convertX
6
+
7
+ interface TextFieldStyleButtonProps extends ViewProps {
8
+ placeholder: string
9
+ text: string
10
+ onPress: () => void
11
+ }
12
+
13
+ const TextFieldStyleButton = (props: TextFieldStyleButtonProps) => {
14
+ return (
15
+ <View style={props.style}>
16
+ <Text style={styles.topTip}>{props.placeholder}</Text>
17
+ <TouchableOpacity onPress={props.onPress}>
18
+ <View style={styles.textGroup}>
19
+ <View style={styles.textParent}>
20
+ <Text style={styles.text}>{props.text}</Text>
21
+ </View>
22
+ <View style={styles.line} />
23
+ </View>
24
+ </TouchableOpacity>
25
+ </View>
26
+ )
27
+ }
28
+
29
+ const styles = StyleSheet.create({
30
+ topTip: {
31
+ marginTop: cx(5),
32
+ fontSize: cx(12),
33
+ marginStart: cx(13),
34
+ color: '#666',
35
+ fontFamily: 'helvetica_neue_lt_std_bd',
36
+ },
37
+ textGroup: {
38
+ flexDirection: 'row',
39
+ borderRadius: cx(4),
40
+ backgroundColor: '#f6f6f6',
41
+ alignItems: 'center',
42
+ },
43
+ textParent: {
44
+ flex: 1,
45
+ height: cx(44),
46
+ justifyContent: 'center',
47
+ },
48
+ text: {
49
+ marginStart: cx(16),
50
+ marginEnd: cx(6),
51
+ fontSize: cx(16),
52
+ color: '#000',
53
+ fontFamily: 'helvetica_neue_lt_std_roman',
54
+ },
55
+ line: {
56
+ height: 1,
57
+ position: 'absolute',
58
+ start: cx(4),
59
+ end: cx(4),
60
+ bottom: 0,
61
+ backgroundColor: '#cbcbcb',
62
+ },
63
+ })
64
+
65
+ export default TextFieldStyleButton
@@ -0,0 +1,44 @@
1
+ import React from 'react'
2
+ import { StyleProp, StyleSheet, Text, TextStyle, TouchableOpacity, View, ViewStyle } from 'react-native'
3
+ import { Utils } from 'tuya-panel-kit'
4
+
5
+ const { convertX } = Utils.RatioUtils
6
+
7
+ interface Props {
8
+ style?: StyleProp<ViewStyle>
9
+ textStyle?: StyleProp<TextStyle>
10
+ title: string
11
+ rightComponent?: any
12
+ onPress?: any
13
+ disabled?: boolean
14
+ }
15
+
16
+ const LdvItemView: React.FC<Props> = (props) => {
17
+ const { rightComponent, title, style, onPress, disabled, textStyle } = props
18
+ return (
19
+ <TouchableOpacity onPress={onPress} disabled={disabled}>
20
+ <View style={[styles.bg, style]}>
21
+ <Text style={[styles.text, textStyle]}>
22
+ {title}
23
+ </Text>
24
+ {rightComponent && rightComponent()}
25
+ </View>
26
+ </TouchableOpacity>
27
+ )
28
+ }
29
+
30
+ const styles = StyleSheet.create({
31
+ bg: {
32
+ height: convertX(50),
33
+ flexDirection: 'row',
34
+ justifyContent: 'space-between',
35
+ alignItems: 'center',
36
+ marginHorizontal: convertX(24),
37
+ },
38
+ text: {
39
+ fontSize: convertX(16),
40
+ fontWeight: 'bold',
41
+ },
42
+ })
43
+
44
+ export default LdvItemView
@@ -162,3 +162,11 @@ export const getHSVByHex = (string) => {
162
162
  v: parseInt(v, 16),
163
163
  }
164
164
  }
165
+
166
+ export function mapFloatToRange(value: number, min: number, max: number): number {
167
+ // 确保 value 在 [0, 1] 范围内
168
+ value = Math.max(0, Math.min(1, value))
169
+
170
+ // 计算插值后的值
171
+ return min + value * (max - min)
172
+ }