1
1
/* @flow strict-local */
2
2
3
- import React from 'react' ;
4
- import type { Node } from 'react' ;
3
+ import * as React from 'react' ;
5
4
6
- import type { LocalizableText } from '../types ' ;
5
+ import ZulipText from './ZulipText ' ;
7
6
import ZulipTextIntl from './ZulipTextIntl' ;
8
7
import { openLinkEmbedded } from '../utils/openLink' ;
9
8
import { BRAND_COLOR , createStyleSheet } from '../styles' ;
10
9
11
10
type Props = $ReadOnly < { |
12
- label : LocalizableText ,
11
+ ... $Exact < React$ElementConfig < typeof ZulipText >> ,
13
12
url : URL ,
14
13
| } > ;
15
14
@@ -21,15 +20,52 @@ const componentStyles = createStyleSheet({
21
20
22
21
/**
23
22
* A button styled like a web link.
23
+ *
24
+ * Accepts `ZulipText`s, `ZulipTextIntl`s, and strings as children.
25
+ *
26
+ * Note: This sort of messes in those non-string children's business by
27
+ * unsetting some of their default style attributes. It does this so that
28
+ * its own special formatting can be passed down through the limited style
29
+ * inheritance that RN supports:
30
+ * https://reactnative.dev/docs/text#limited-style-inheritance
31
+ * See `aggressiveDefaultStyle` in ZulipText.
32
+ *
33
+ * TODO: Possibly there's a better way handle this.
24
34
*/
25
- export default function WebLink ( props : Props ) : Node {
35
+ export default function WebLink ( props : Props ) : React . Node {
36
+ const { children } = props ;
37
+
26
38
return (
27
- < ZulipTextIntl
39
+ < ZulipText
28
40
style = { componentStyles . link }
29
- text = { props . label }
30
41
onPress = { ( ) => {
31
42
openLinkEmbedded ( props . url . toString ( ) ) ;
32
43
} }
33
- />
44
+ >
45
+ { React . Children . map ( children , child => {
46
+ if ( ! React . isValidElement ( child ) ) {
47
+ // Some React node that isn't a React element (a `React.Element`);
48
+ // e.g., a plain string. The enclosing ZulipText will apply its
49
+ // styles directly.
50
+ return child ;
51
+ }
52
+ // `child` should be a React.Element at this point. Docs are very
53
+ // vague, but this sounds like it should be true, and it seems true
54
+ // empirically. Would at least be good to have better type checking.
55
+
56
+ if ( child . type !== ZulipText && child . type !== ZulipTextIntl ) {
57
+ return child ;
58
+ }
59
+ // These element types will have a style prop that we want to add to.
60
+
61
+ return React . cloneElement ( child , {
62
+ style : {
63
+ // Defeat ZulipText's aggressiveDefaultStyle.color so that our
64
+ // color gets applied.
65
+ color : undefined ,
66
+ } ,
67
+ } ) ;
68
+ } ) }
69
+ </ ZulipText >
34
70
) ;
35
71
}
0 commit comments