@startupjs-ui/mdx 0.2.0 → 0.3.1
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 +19 -0
- package/client/Code/index.js +14 -6
- package/client/mdxComponents/index.js +136 -94
- package/package.json +12 -12
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.3.1](https://github.com/startupjs/startupjs-ui/compare/v0.3.0...v0.3.1) (2026-06-08)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @startupjs-ui/mdx
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# [0.3.0](https://github.com/startupjs/startupjs-ui/compare/v0.2.3...v0.3.0) (2026-05-27)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* [BREAKING] [0.3] improve accessibility props for E2E tests. Support testID everywhere ([#31](https://github.com/startupjs/startupjs-ui/issues/31)) ([882588c](https://github.com/startupjs/startupjs-ui/commit/882588ca37d5e1fd14b5717b5697cf9ed47042e4))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
6
25
|
# [0.2.0](https://github.com/startupjs/startupjs-ui/compare/v0.1.23...v0.2.0) (2026-05-04)
|
|
7
26
|
|
|
8
27
|
|
package/client/Code/index.js
CHANGED
|
@@ -5,7 +5,10 @@ import Span from '@startupjs-ui/span'
|
|
|
5
5
|
import ScrollView from '@startupjs-ui/scroll-view'
|
|
6
6
|
import refractor from 'refractor/core.js'
|
|
7
7
|
// Supported languages
|
|
8
|
+
import languageJavascript from 'refractor/lang/javascript.js'
|
|
8
9
|
import languageJsx from 'refractor/lang/jsx.js'
|
|
10
|
+
import languageTypescript from 'refractor/lang/typescript.js'
|
|
11
|
+
import languageTsx from 'refractor/lang/tsx.js'
|
|
9
12
|
import languageStyl from 'refractor/lang/stylus.js'
|
|
10
13
|
import languagePug from 'refractor/lang/pug.js'
|
|
11
14
|
import languageMarkdown from 'refractor/lang/markdown.js'
|
|
@@ -14,9 +17,13 @@ import languageBash from 'refractor/lang/bash.js'
|
|
|
14
17
|
import './index.cssx.styl'
|
|
15
18
|
|
|
16
19
|
const SUB_LANGUAGE_REGEX = /(^|\W)(pug|styl|css)(`\s*\n)([^`]*\s*\n)(`)/
|
|
20
|
+
const TEMPLATE_LANGUAGE_ROOTS = new Set(['js', 'javascript', 'jsx', 'ts', 'typescript', 'tsx'])
|
|
17
21
|
|
|
18
22
|
// Register all supported languages
|
|
23
|
+
refractor.register(languageJavascript)
|
|
19
24
|
refractor.register(languageJsx)
|
|
25
|
+
refractor.register(languageTypescript)
|
|
26
|
+
refractor.register(languageTsx)
|
|
20
27
|
refractor.register(languageStyl)
|
|
21
28
|
refractor.register(languagePug)
|
|
22
29
|
refractor.register(languageMarkdown)
|
|
@@ -24,6 +31,7 @@ refractor.register(languageJson)
|
|
|
24
31
|
refractor.register(languageBash)
|
|
25
32
|
|
|
26
33
|
// Register aliases
|
|
34
|
+
refractor.alias({ javascript: ['js'] })
|
|
27
35
|
refractor.alias({ stylus: ['styl'] })
|
|
28
36
|
refractor.alias({ bash: ['sh'] })
|
|
29
37
|
|
|
@@ -74,27 +82,27 @@ function getLines (code, language) {
|
|
|
74
82
|
}
|
|
75
83
|
|
|
76
84
|
function highlight (code, language) {
|
|
77
|
-
if (language
|
|
85
|
+
if (TEMPLATE_LANGUAGE_ROOTS.has(language)) {
|
|
78
86
|
const match = code.match(SUB_LANGUAGE_REGEX)
|
|
79
87
|
if (match) {
|
|
80
88
|
const splitIndex = match.index + match[0].length
|
|
81
89
|
const start = code.slice(0, splitIndex)
|
|
82
90
|
const next = code.slice(splitIndex + 1)
|
|
83
91
|
|
|
84
|
-
const
|
|
85
|
-
const
|
|
92
|
+
const rootCode = start.replace(SUB_LANGUAGE_REGEX, '$1$2$3$5')
|
|
93
|
+
const highlightedRoot = getLines(rootCode, language)
|
|
86
94
|
|
|
87
95
|
const subLanguageName = match[2]
|
|
88
96
|
const bodySubLanguage = match[4]
|
|
89
|
-
const closingBacktick = modifyAndGetLastBacktick(
|
|
97
|
+
const closingBacktick = modifyAndGetLastBacktick(highlightedRoot)
|
|
90
98
|
|
|
91
99
|
const merge = [
|
|
92
|
-
...
|
|
100
|
+
...highlightedRoot, // without trailing ` sign
|
|
93
101
|
...highlight(bodySubLanguage, subLanguageName),
|
|
94
102
|
closingBacktick // the trailing ` sign
|
|
95
103
|
]
|
|
96
104
|
|
|
97
|
-
if (next) merge.push(...highlight(next,
|
|
105
|
+
if (next) merge.push(...highlight(next, language))
|
|
98
106
|
return merge
|
|
99
107
|
}
|
|
100
108
|
}
|
|
@@ -22,10 +22,16 @@ import Code from '../Code'
|
|
|
22
22
|
|
|
23
23
|
// const RowComponent = props => pug`Div(...props row)`
|
|
24
24
|
const ALPHABET = 'abcdefghigklmnopqrstuvwxyz'
|
|
25
|
+
const INLINE_COMPONENT = Symbol('startupjs.mdx.inlineComponent')
|
|
25
26
|
const ListLevelContext = React.createContext()
|
|
26
27
|
const BlockquoteContext = React.createContext()
|
|
27
28
|
const PreContext = React.createContext()
|
|
28
29
|
|
|
30
|
+
function markInline (Component) {
|
|
31
|
+
Component[INLINE_COMPONENT] = true
|
|
32
|
+
return Component
|
|
33
|
+
}
|
|
34
|
+
|
|
29
35
|
function getOrderedListMark (index, level) {
|
|
30
36
|
switch (level) {
|
|
31
37
|
case 1:
|
|
@@ -41,6 +47,130 @@ function P (props) {
|
|
|
41
47
|
`
|
|
42
48
|
}
|
|
43
49
|
|
|
50
|
+
const Strong = markInline(function Strong ({ children }) {
|
|
51
|
+
return pug`
|
|
52
|
+
Text(style={ fontWeight: 'bold' })= children
|
|
53
|
+
`
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const Em = markInline(function Em ({ children }) {
|
|
57
|
+
return pug`
|
|
58
|
+
Text(style={ fontStyle: 'italic' })= children
|
|
59
|
+
`
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const MdxLink = markInline(function MdxLink ({ children, href }) {
|
|
63
|
+
// function onPress (event) {
|
|
64
|
+
// const { url, hash } = $root.get('$render')
|
|
65
|
+
// const [_url, _hash] = href.split('#')
|
|
66
|
+
// if (url === _url && hash === `#${_hash}`) {
|
|
67
|
+
// event.preventDefault()
|
|
68
|
+
// // scrollTo({ anchorId: _hash })
|
|
69
|
+
// }
|
|
70
|
+
// }
|
|
71
|
+
|
|
72
|
+
// TODO: handle Anchor click with onPress
|
|
73
|
+
return pug`
|
|
74
|
+
Link.link(
|
|
75
|
+
to=href
|
|
76
|
+
size='l'
|
|
77
|
+
color='primary'
|
|
78
|
+
)= children
|
|
79
|
+
`
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const MdxCode = markInline(observer(function MdxCode ({ children, className }) {
|
|
83
|
+
const isBlockCode = useContext(PreContext)
|
|
84
|
+
const language = (className || 'language-txt').replace(/language-/, '')
|
|
85
|
+
const [open, setOpen] = useState(false)
|
|
86
|
+
const $copyText = $('Copy code')
|
|
87
|
+
|
|
88
|
+
if (!isBlockCode) {
|
|
89
|
+
return pug`
|
|
90
|
+
Span.inlineCodeWrapper
|
|
91
|
+
Span.inlineCodeSpacer  
|
|
92
|
+
Span.inlineCode(style={
|
|
93
|
+
fontFamily: Platform.OS === 'ios' ? 'Menlo-Regular' : 'monospace'
|
|
94
|
+
})= children
|
|
95
|
+
Span.inlineCodeSpacer  
|
|
96
|
+
`
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function copyHandler () {
|
|
100
|
+
await setStringAsync(children)
|
|
101
|
+
$copyText.set('Copied')
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function onMouseEnter () {
|
|
105
|
+
// we need to reutrn default text if it was copied
|
|
106
|
+
$copyText.set('Copy code')
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let example
|
|
110
|
+
|
|
111
|
+
if (typeof children === 'string' && children.includes('[HACK EXAMPLE CODE]')) {
|
|
112
|
+
children = children.replace('[HACK EXAMPLE CODE]', '')
|
|
113
|
+
example = true
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return pug`
|
|
117
|
+
Div.code(styleName={ 'code-example': example })
|
|
118
|
+
if example
|
|
119
|
+
Collapse.code-collapse(open=open variant='pure')
|
|
120
|
+
Collapse.Header.code-collapse-header(icon=false onPress=null)
|
|
121
|
+
Div.code-actions(align='right' row)
|
|
122
|
+
Div.code-action(
|
|
123
|
+
tooltip=open ? 'Hide code' : 'Show code'
|
|
124
|
+
onPress=() => setOpen(!open)
|
|
125
|
+
)
|
|
126
|
+
Icon.code-action-collapse(icon=faCode color='error')
|
|
127
|
+
Div.code-action(
|
|
128
|
+
tooltip=$copyText.get()
|
|
129
|
+
onPress=copyHandler
|
|
130
|
+
onMouseEnter=onMouseEnter
|
|
131
|
+
)
|
|
132
|
+
Icon.code-action-copy(icon=faCopy)
|
|
133
|
+
Collapse.Content.code-collapse-content
|
|
134
|
+
Code(language=language)= children
|
|
135
|
+
else
|
|
136
|
+
Code(language=language)= children
|
|
137
|
+
`
|
|
138
|
+
}))
|
|
139
|
+
|
|
140
|
+
function isInlineChild (child) {
|
|
141
|
+
if (typeof child === 'string' || typeof child === 'number') return true
|
|
142
|
+
if (!React.isValidElement(child)) return false
|
|
143
|
+
if (child.type === React.Fragment) {
|
|
144
|
+
return React.Children.toArray(child.props.children).every(isInlineChild)
|
|
145
|
+
}
|
|
146
|
+
return Boolean(child.type?.[INLINE_COMPONENT])
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function wrapInlineListChildren (children) {
|
|
150
|
+
const wrappedChildren = []
|
|
151
|
+
let inlineChildren = []
|
|
152
|
+
|
|
153
|
+
function flushInlineChildren () {
|
|
154
|
+
if (!inlineChildren.length) return
|
|
155
|
+
wrappedChildren.push(pug`
|
|
156
|
+
P(key='inline-' + wrappedChildren.length size='l')= inlineChildren
|
|
157
|
+
`)
|
|
158
|
+
inlineChildren = []
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
children.forEach(child => {
|
|
162
|
+
if (isInlineChild(child)) {
|
|
163
|
+
inlineChildren.push(child)
|
|
164
|
+
} else {
|
|
165
|
+
flushInlineChildren()
|
|
166
|
+
wrappedChildren.push(child)
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
flushInlineChildren()
|
|
171
|
+
return wrappedChildren
|
|
172
|
+
}
|
|
173
|
+
|
|
44
174
|
// function getTextChildren (children) {
|
|
45
175
|
// const nestedChildren = _get(children, 'props.children')
|
|
46
176
|
// if (nestedChildren) {
|
|
@@ -111,12 +241,8 @@ export default {
|
|
|
111
241
|
P= children
|
|
112
242
|
`
|
|
113
243
|
},
|
|
114
|
-
strong:
|
|
115
|
-
|
|
116
|
-
`,
|
|
117
|
-
em: ({ children }) => pug`
|
|
118
|
-
Text(style={ fontStyle: 'italic' })= children
|
|
119
|
-
`,
|
|
244
|
+
strong: Strong,
|
|
245
|
+
em: Em,
|
|
120
246
|
hr: ({ children }) => pug`
|
|
121
247
|
Divider(size='l')
|
|
122
248
|
`,
|
|
@@ -138,25 +264,7 @@ export default {
|
|
|
138
264
|
td: Td,
|
|
139
265
|
th: Th,
|
|
140
266
|
delete: P,
|
|
141
|
-
a:
|
|
142
|
-
// function onPress (event) {
|
|
143
|
-
// const { url, hash } = $root.get('$render')
|
|
144
|
-
// const [_url, _hash] = href.split('#')
|
|
145
|
-
// if (url === _url && hash === `#${_hash}`) {
|
|
146
|
-
// event.preventDefault()
|
|
147
|
-
// // scrollTo({ anchorId: _hash })
|
|
148
|
-
// }
|
|
149
|
-
// }
|
|
150
|
-
|
|
151
|
-
// TODO: handle Anchor click with onPress
|
|
152
|
-
return pug`
|
|
153
|
-
Link.link(
|
|
154
|
-
to=href
|
|
155
|
-
size='l'
|
|
156
|
-
color='primary'
|
|
157
|
-
)= children
|
|
158
|
-
`
|
|
159
|
-
},
|
|
267
|
+
a: MdxLink,
|
|
160
268
|
ul: ({ children }) => children,
|
|
161
269
|
ol: ({ children }) => {
|
|
162
270
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
@@ -176,24 +284,15 @@ export default {
|
|
|
176
284
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
177
285
|
const level = useContext(ListLevelContext)
|
|
178
286
|
const listIndex = index == null ? '•' : getOrderedListMark(index, level)
|
|
179
|
-
let hasTextChild = false
|
|
180
287
|
children = React.Children
|
|
181
288
|
.toArray(children)
|
|
182
289
|
.filter(child => child !== '\n')
|
|
183
|
-
|
|
184
|
-
if (typeof child === 'string') {
|
|
185
|
-
hasTextChild = true
|
|
186
|
-
}
|
|
187
|
-
return child
|
|
188
|
-
})
|
|
290
|
+
const wrappedChildren = wrapInlineListChildren(children)
|
|
189
291
|
return pug`
|
|
190
292
|
Div(row)
|
|
191
293
|
Span.listIndex= listIndex
|
|
192
294
|
Div.listContent
|
|
193
|
-
|
|
194
|
-
P(size='l')= children
|
|
195
|
-
else
|
|
196
|
-
= children
|
|
295
|
+
= wrappedChildren
|
|
197
296
|
`
|
|
198
297
|
},
|
|
199
298
|
blockquote: ({ children }) => {
|
|
@@ -258,62 +357,5 @@ export default {
|
|
|
258
357
|
= children
|
|
259
358
|
`
|
|
260
359
|
},
|
|
261
|
-
code:
|
|
262
|
-
const isBlockCode = useContext(PreContext)
|
|
263
|
-
|
|
264
|
-
if (!isBlockCode) {
|
|
265
|
-
return pug`
|
|
266
|
-
Span.inlineCodeWrapper
|
|
267
|
-
Span.inlineCodeSpacer  
|
|
268
|
-
Span.inlineCode(style={
|
|
269
|
-
fontFamily: Platform.OS === 'ios' ? 'Menlo-Regular' : 'monospace'
|
|
270
|
-
})= children
|
|
271
|
-
Span.inlineCodeSpacer  
|
|
272
|
-
`
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const language = (className || 'language-txt').replace(/language-/, '')
|
|
276
|
-
const [open, setOpen] = useState(false)
|
|
277
|
-
const $copyText = $('Copy code')
|
|
278
|
-
|
|
279
|
-
async function copyHandler () {
|
|
280
|
-
await setStringAsync(children)
|
|
281
|
-
$copyText.set('Copied')
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function onMouseEnter () {
|
|
285
|
-
// we need to reutrn default text if it was copied
|
|
286
|
-
$copyText.set('Copy code')
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
let example
|
|
290
|
-
|
|
291
|
-
if (typeof children === 'string' && children.includes('[HACK EXAMPLE CODE]')) {
|
|
292
|
-
children = children.replace('[HACK EXAMPLE CODE]', '')
|
|
293
|
-
example = true
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
return pug`
|
|
297
|
-
Div.code(styleName={ 'code-example': example })
|
|
298
|
-
if example
|
|
299
|
-
Collapse.code-collapse(open=open variant='pure')
|
|
300
|
-
Collapse.Header.code-collapse-header(icon=false onPress=null)
|
|
301
|
-
Div.code-actions(align='right' row)
|
|
302
|
-
Div.code-action(
|
|
303
|
-
tooltip=open ? 'Hide code' : 'Show code'
|
|
304
|
-
onPress=() => setOpen(!open)
|
|
305
|
-
)
|
|
306
|
-
Icon.code-action-collapse(icon=faCode color='error')
|
|
307
|
-
Div.code-action(
|
|
308
|
-
tooltip=$copyText.get()
|
|
309
|
-
onPress=copyHandler
|
|
310
|
-
onMouseEnter=onMouseEnter
|
|
311
|
-
)
|
|
312
|
-
Icon.code-action-copy(icon=faCopy)
|
|
313
|
-
Collapse.Content.code-collapse-content
|
|
314
|
-
Code(language=language)= children
|
|
315
|
-
else
|
|
316
|
-
Code(language=language)= children
|
|
317
|
-
`
|
|
318
|
-
})
|
|
360
|
+
code: MdxCode
|
|
319
361
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@startupjs-ui/mdx",
|
|
3
3
|
"description": "MDX provider with a set of custom components for react-native support and syntax highlighting",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -12,16 +12,16 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@fortawesome/free-solid-svg-icons": "^7.1.0",
|
|
14
14
|
"@mdx-js/react": "^3.0.0",
|
|
15
|
-
"@startupjs-ui/alert": "^0.
|
|
16
|
-
"@startupjs-ui/br": "^0.
|
|
17
|
-
"@startupjs-ui/collapse": "^0.
|
|
18
|
-
"@startupjs-ui/div": "^0.
|
|
19
|
-
"@startupjs-ui/divider": "^0.
|
|
20
|
-
"@startupjs-ui/icon": "^0.
|
|
21
|
-
"@startupjs-ui/link": "^0.
|
|
22
|
-
"@startupjs-ui/scroll-view": "^0.
|
|
23
|
-
"@startupjs-ui/span": "^0.
|
|
24
|
-
"@startupjs-ui/table": "^0.
|
|
15
|
+
"@startupjs-ui/alert": "^0.3.1",
|
|
16
|
+
"@startupjs-ui/br": "^0.3.0",
|
|
17
|
+
"@startupjs-ui/collapse": "^0.3.1",
|
|
18
|
+
"@startupjs-ui/div": "^0.3.1",
|
|
19
|
+
"@startupjs-ui/divider": "^0.3.0",
|
|
20
|
+
"@startupjs-ui/icon": "^0.3.0",
|
|
21
|
+
"@startupjs-ui/link": "^0.3.1",
|
|
22
|
+
"@startupjs-ui/scroll-view": "^0.3.0",
|
|
23
|
+
"@startupjs-ui/span": "^0.3.1",
|
|
24
|
+
"@startupjs-ui/table": "^0.3.1",
|
|
25
25
|
"refractor": "^3.0.0"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
"react-native": "*",
|
|
31
31
|
"startupjs": "*"
|
|
32
32
|
},
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "60311773bdc83f354c797a272774304502d28c58"
|
|
34
34
|
}
|