@startupjs-ui/link 0.1.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/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ ## [0.1.3](https://github.com/startupjs/startupjs-ui/compare/v0.1.2...v0.1.3) (2025-12-29)
7
+
8
+ **Note:** Version bump only for package @startupjs-ui/link
9
+
10
+
11
+
12
+
13
+
14
+ ## [0.1.2](https://github.com/startupjs/startupjs-ui/compare/v0.1.1...v0.1.2) (2025-12-29)
15
+
16
+
17
+ ### Features
18
+
19
+ * add mdx and docs packages. Refactor docs to get rid of any @startupjs/ui usage and use startupjs-ui instead ([703c926](https://github.com/startupjs/startupjs-ui/commit/703c92636efb0421ffd11783f692fc892b74018f))
20
+ * **link:** refactor Link component ([2729a36](https://github.com/startupjs/startupjs-ui/commit/2729a36d48b7930a3182c0c69070541e1bd2cf8c))
package/README.mdx ADDED
@@ -0,0 +1,148 @@
1
+ import Link, { _PropsJsonSchema as LinkPropsJsonSchema } from './index'
2
+ import Br from '@startupjs-ui/br'
3
+ import Button from '@startupjs-ui/button'
4
+ import Div from '@startupjs-ui/div'
5
+ import Rating from '@startupjs-ui/rating'
6
+ import { u } from 'startupjs'
7
+ import { Sandbox } from '@startupjs-ui/docs'
8
+
9
+ # Link
10
+
11
+ Link allows to navigate of the app and customize anchors.
12
+
13
+ ```jsx
14
+ import { Link } from 'startupjs-ui'
15
+ ```
16
+
17
+ ## Simple example
18
+
19
+ ```jsx example
20
+ return (
21
+ <Link to='/docs/Card'>
22
+ Card
23
+ </Link>
24
+ )
25
+ ```
26
+
27
+ ## Different display
28
+
29
+ There are two options `inline` and `block` of the `display` property. It is detected automatically based on the type of `children`, if not specified. When type of `children` is string it `inline` and `block` otherwise. Depending on the `display` property, component has a different appearance.
30
+
31
+ ```jsx example
32
+ return (
33
+ <Div>
34
+ <Link to='/docs/Card'>
35
+ Card
36
+ </Link>
37
+ <Br />
38
+ <Link to='/docs/Rating'>
39
+ <Rating value={4.5} readonly />
40
+ </Link>
41
+ </Div>
42
+ )
43
+ ```
44
+
45
+ ## Colors
46
+
47
+ To change link color pass the property `color` (works only when `display` value is `inline`).
48
+
49
+ ```jsx example
50
+ return (
51
+ <Link
52
+ to='/docs/Card'
53
+ color='primary'
54
+ >
55
+ Card
56
+ </Link>
57
+ )
58
+ ```
59
+
60
+ ## Bold link
61
+
62
+ To make link text bold pass the property `bold` to component.
63
+
64
+ ```jsx example
65
+ return (
66
+ <Link to='/docs/Card' bold>
67
+ Card
68
+ </Link>
69
+ )
70
+ ```
71
+
72
+ ## Italic link
73
+
74
+ To make link text italic pass the property `italic` to component.
75
+
76
+ ```jsx example
77
+ return (
78
+ <Link to='/docs/Card' italic>
79
+ Card
80
+ </Link>
81
+ )
82
+ ```
83
+
84
+ ## Hover style
85
+
86
+ You can change hover style like in [Div component](/docs/Div) by passing `variant='highlight'` (works only when `display` value is `block`).
87
+
88
+ ```jsx example
89
+ const style = {
90
+ height: u(10),
91
+ backgroundColor: 'white',
92
+ alignItems: 'center',
93
+ justifyContent: 'center'
94
+ }
95
+ return (
96
+ <Link
97
+ style={style}
98
+ to='/docs/Rating'
99
+ variant='highlight'
100
+ >
101
+ <Rating value={4.5} readonly />
102
+ </Link>
103
+ )
104
+ ```
105
+
106
+ ## Button as link
107
+
108
+ Sometimes you want to make button as link. The example below illustrates how to do this correctly.
109
+
110
+ ```jsx example
111
+ return (
112
+ <Link
113
+ to='/docs/Card'
114
+ >
115
+ <Button color='primary' variant='flat'>Card</Button>
116
+ </Link>
117
+ )
118
+ ```
119
+
120
+ ## Actions
121
+
122
+ By passing `onPress` handler to component you can run some logic before redirecting.
123
+
124
+ ```jsx example
125
+ function onPress (event) {
126
+ console.log('Go to alert docs')
127
+ }
128
+ return (
129
+ <Link
130
+ color='primary'
131
+ to='/docs/Alert'
132
+ onPress={onPress}
133
+ >
134
+ Alert docs
135
+ </Link>
136
+ )
137
+ ```
138
+
139
+ ## Sandbox
140
+
141
+ <Sandbox
142
+ Component={Link}
143
+ propsJsonSchema={LinkPropsJsonSchema}
144
+ props={{
145
+ to: '#',
146
+ children: 'StartupJS'
147
+ }}
148
+ />
@@ -0,0 +1,12 @@
1
+ .root
2
+ color: var(--color-text-secondary)
3
+ text-decoration-line underline
4
+ text-decoration-color @color
5
+
6
+ &.primary
7
+ color var(--color-text-primary)
8
+ text-decoration-color @color
9
+
10
+ &.block
11
+ display flex
12
+ text-decoration none
package/index.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ /* eslint-disable */
2
+ // DO NOT MODIFY THIS FILE - IT IS AUTOMATICALLY GENERATED ON COMMITS.
3
+
4
+ import { type ReactNode } from 'react';
5
+ import { type StyleProp, type TextStyle, type ViewStyle } from 'react-native';
6
+ import { type DivProps } from '@startupjs-ui/div';
7
+ import './index.cssx.styl';
8
+ declare const _default: import("react").ComponentType<LinkProps>;
9
+ export default _default;
10
+ export declare const _PropsJsonSchema: {};
11
+ export interface LinkProps extends Omit<DivProps, 'style'> {
12
+ /** Custom styles applied to the root view */
13
+ style?: StyleProp<TextStyle | ViewStyle>;
14
+ /** Content rendered inside Link */
15
+ children?: ReactNode;
16
+ /** Link target path or URL */
17
+ to?: string;
18
+ /** Alias for `to` */
19
+ href?: string;
20
+ /** Use router push instead of navigate */
21
+ push?: boolean;
22
+ /** Replace current history entry instead of pushing */
23
+ replace?: boolean;
24
+ /** Display mode @default auto-detected */
25
+ display?: 'inline' | 'block';
26
+ /** Color variant for inline links @default 'default' */
27
+ color?: 'default' | 'primary';
28
+ /** Theme name used for styling */
29
+ theme?: string;
30
+ /** Render text in bold style when inline @default false */
31
+ bold?: boolean;
32
+ /** Render text in italic style when inline @default false */
33
+ italic?: boolean;
34
+ /** onPress handler */
35
+ onPress?: (event: any) => void;
36
+ }
package/index.tsx ADDED
@@ -0,0 +1,142 @@
1
+ import { Children, cloneElement, type ReactNode } from 'react'
2
+ import { Linking, Platform, type StyleProp, type TextStyle, type ViewStyle } from 'react-native'
3
+ import { pug, observer } from 'startupjs'
4
+ import useRouter from 'startupjs/useRouter'
5
+ import { themed } from '@startupjs-ui/core'
6
+ import Button from '@startupjs-ui/button'
7
+ import Div, { type DivProps } from '@startupjs-ui/div'
8
+ import Span from '@startupjs-ui/span'
9
+ import './index.cssx.styl'
10
+
11
+ const isWeb = Platform.OS === 'web'
12
+ const EXTERNAL_LINK_REGEXP = /^(https?:\/\/|\/\/)/i
13
+
14
+ export default observer(themed('Link', Link))
15
+
16
+ export const _PropsJsonSchema = {/* LinkProps */} // used in docs generation
17
+ export interface LinkProps extends Omit<DivProps, 'style'> {
18
+ /** Custom styles applied to the root view */
19
+ style?: StyleProp<TextStyle | ViewStyle>
20
+ /** Content rendered inside Link */
21
+ children?: ReactNode
22
+ /** Link target path or URL */
23
+ to?: string
24
+ /** Alias for `to` */
25
+ href?: string
26
+ /** Use router push instead of navigate */
27
+ push?: boolean
28
+ /** Replace current history entry instead of pushing */
29
+ replace?: boolean
30
+ /** Display mode @default auto-detected */
31
+ display?: 'inline' | 'block'
32
+ /** Color variant for inline links @default 'default' */
33
+ color?: 'default' | 'primary'
34
+ /** Theme name used for styling */
35
+ theme?: string
36
+ /** Render text in bold style when inline @default false */
37
+ bold?: boolean
38
+ /** Render text in italic style when inline @default false */
39
+ italic?: boolean
40
+ /** onPress handler */
41
+ onPress?: (event: any) => void
42
+ }
43
+
44
+ function Link ({
45
+ style,
46
+ to,
47
+ href,
48
+ color = 'default',
49
+ theme,
50
+ display,
51
+ push,
52
+ replace = false,
53
+ children,
54
+ onPress,
55
+ ...restProps
56
+ }: LinkProps): ReactNode {
57
+ let bold = restProps.bold
58
+ let italic = restProps.italic
59
+ if (bold == null) bold = false
60
+ if (italic == null) italic = false
61
+ restProps.bold = bold
62
+ restProps.italic = italic
63
+
64
+ let target = to ?? ''
65
+ if (href) target = href
66
+
67
+ let resolvedDisplay = display
68
+ if (!resolvedDisplay) resolvedDisplay = typeof children === 'string' ? 'inline' : 'block'
69
+
70
+ const isBlock = resolvedDisplay === 'block'
71
+ const Component = isBlock ? Div : Span
72
+ const extraProps: Record<string, any> = { accessibilityRole: 'link', onPress: handlePress }
73
+ const {
74
+ navigate: routerNavigate,
75
+ push: routerPush,
76
+ replace: routerReplace,
77
+ usePathname
78
+ } = useRouter()
79
+
80
+ const pathname = usePathname()
81
+
82
+ if (isWeb) {
83
+ let hrefValue = target ?? ''
84
+ if (!EXTERNAL_LINK_REGEXP.test(hrefValue) && !/^[/?#]/.test(hrefValue)) {
85
+ let p = pathname
86
+ p = p.replace(/#.*$/, '')
87
+ p = p.replace(/\?.*$/, '')
88
+ p = p.replace(/\/$/, '')
89
+ hrefValue = hrefValue.replace(/^\//, '')
90
+ hrefValue = hrefValue.replace(/\/$/, '')
91
+ hrefValue = p + '/' + hrefValue
92
+ }
93
+ extraProps.href = hrefValue
94
+ }
95
+
96
+ function handlePress (event: any) {
97
+ if (onPress) onPress(event)
98
+
99
+ if (!event.defaultPrevented) {
100
+ if (isWeb) {
101
+ if (isModifiedEvent(event)) return
102
+ event.preventDefault()
103
+ }
104
+
105
+ if (EXTERNAL_LINK_REGEXP.test(target ?? '')) {
106
+ isWeb
107
+ ? window.open(target, '_blank')
108
+ : Linking.openURL(target ?? '')
109
+ } else {
110
+ let method
111
+ if (push) method = routerPush
112
+ else if (replace) method = routerReplace
113
+ else method = routerNavigate
114
+ method(target)
115
+ }
116
+ }
117
+ }
118
+
119
+ if (isBlock) {
120
+ try {
121
+ Children.only(children as any)
122
+ if ((children as any)?.props?.originalType === Button || (children as any)?.type === Button) {
123
+ return cloneElement(children as any, { style, ...restProps, ...extraProps })
124
+ }
125
+ } catch (e) {
126
+ // ignore errors when children contains multiple elements
127
+ }
128
+ }
129
+
130
+ return pug`
131
+ Component.root(
132
+ style=style
133
+ styleName=[theme, color, resolvedDisplay]
134
+ ...restProps
135
+ ...extraProps
136
+ )= children
137
+ `
138
+ }
139
+
140
+ function isModifiedEvent (event: any) {
141
+ return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey)
142
+ }
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@startupjs-ui/link",
3
+ "version": "0.1.3",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "main": "index.tsx",
8
+ "types": "index.d.ts",
9
+ "type": "module",
10
+ "dependencies": {
11
+ "@startupjs-ui/button": "^0.1.3",
12
+ "@startupjs-ui/core": "^0.1.3",
13
+ "@startupjs-ui/div": "^0.1.3",
14
+ "@startupjs-ui/span": "^0.1.3"
15
+ },
16
+ "peerDependencies": {
17
+ "react": "*",
18
+ "react-native": "*",
19
+ "startupjs": "*"
20
+ },
21
+ "gitHead": "fd964ebc3892d3dd0a6c85438c0af619cc50c3f0"
22
+ }