@startupjs/docs 0.60.0-canary.0 → 0.60.0-canary.11

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.
@@ -1,8 +1,7 @@
1
1
  import React, { useState } from 'react'
2
- import { pug, emit, observer, useModel, $ } from 'startupjs'
2
+ import { pug, emit, observer, useModel } from 'startupjs'
3
3
  import { pathFor, useLocation } from 'startupjs/app'
4
4
  import { AutoSuggest, Button, Div, Layout, Menu, Span } from '@startupjs/ui'
5
- import { MDXProvider } from '@startupjs/mdx'
6
5
  import { ScrollableProvider } from '@startupjs/scrollable-anchors'
7
6
  import { faBars } from '@fortawesome/free-solid-svg-icons/faBars'
8
7
  import { faSearch } from '@fortawesome/free-solid-svg-icons/faSearch'
@@ -89,11 +88,10 @@ export default observer(function StyleguideLayout ({ children }) {
89
88
  // Note: Topbar height is compensated in PDoc
90
89
  // to achieve a semi-transparent effect
91
90
  return pug`
92
- MDXProvider(key=$.session.theme.get())
93
- Layout.layout(testID="Layout")
94
- Sidebar
95
- Topbar
96
- ScrollableProvider
97
- = children
91
+ Layout.layout(testID="Layout")
92
+ Sidebar
93
+ Topbar
94
+ ScrollableProvider
95
+ = children
98
96
  `
99
97
  })
@@ -1,18 +1,18 @@
1
- import { useLocal, useSyncEffect, useComponentId } from 'startupjs'
1
+ import { $, useSyncEffect, useId } from 'startupjs'
2
2
 
3
3
  export default function useLocalWithDefault (path, defaultValue) {
4
4
  if (defaultValue == null) {
5
5
  throw new Error('useLocalWithDefault: default value is required')
6
6
  }
7
7
 
8
- const componentId = useComponentId()
8
+ const componentId = useId()
9
9
  if (!path) path = `_session.${componentId}`
10
- const [value, $value] = useLocal(path)
10
+ const $value = path.split('.').reduce((acc, part) => acc[part], $)
11
11
 
12
12
  useSyncEffect(() => {
13
- if (!(value == null)) return
14
- throw $value.set('', defaultValue)
13
+ if (!($value.get() == null)) return
14
+ throw $value.set(defaultValue)
15
15
  }, [])
16
16
 
17
- return [value, $value]
17
+ return [$value.get(), $value]
18
18
  }
@@ -1,21 +1,21 @@
1
1
  import React, { useCallback, useMemo } from 'react'
2
- import { pug, observer, useValue } from 'startupjs'
2
+ import { pug, observer, $ } from 'startupjs'
3
3
  import { Button, Span, themed } from '@startupjs/ui'
4
4
  import '../index.styl'
5
5
 
6
6
  const MAX_ITEMS = 10
7
7
 
8
8
  export default observer(themed(function TypeCell ({ possibleValues, theme, type }) {
9
- const [collapsed, $collapsed] = useValue(true)
9
+ const $collapsed = $(true)
10
10
 
11
11
  const values = useMemo(() => {
12
12
  if (!Array.isArray(possibleValues)) return []
13
- return collapsed ? possibleValues.slice(0, MAX_ITEMS) : possibleValues
14
- }, [collapsed, possibleValues])
13
+ return $collapsed.get() ? possibleValues.slice(0, MAX_ITEMS) : possibleValues
14
+ }, [$collapsed, possibleValues])
15
15
 
16
16
  const toggleList = useCallback(() => {
17
- $collapsed.setDiff(!collapsed)
18
- }, [collapsed])
17
+ $collapsed.set(!$collapsed.get())
18
+ }, [$collapsed])
19
19
 
20
20
  const renderButton = useCallback(() => {
21
21
  if (possibleValues?.length <= MAX_ITEMS) return null
@@ -26,9 +26,9 @@ export default observer(themed(function TypeCell ({ possibleValues, theme, type
26
26
  size='s'
27
27
  variant='text'
28
28
  onPress=toggleList
29
- )= collapsed ? 'More...' : 'Less'
29
+ )= $collapsed.get() ? 'More...' : 'Less'
30
30
  `
31
- }, [collapsed, possibleValues])
31
+ }, [$collapsed, possibleValues, toggleList]) // eslint-disable-line react-hooks/exhaustive-deps
32
32
 
33
33
  return pug`
34
34
  if type === 'oneOf'
@@ -1,5 +1,5 @@
1
1
  import React, { useCallback, useMemo } from 'react'
2
- import { pug, batch, observer, useValue } from 'startupjs'
2
+ import { pug, batch, observer, $ } from 'startupjs'
3
3
  import { Br, Input, Span } from '@startupjs/ui'
4
4
  import debounce from 'lodash/debounce'
5
5
  import isPlainObject from 'lodash/isPlainObject'
@@ -10,7 +10,7 @@ import omit from 'lodash/omit'
10
10
  import * as icons from '@fortawesome/free-solid-svg-icons'
11
11
  import '../index.styl'
12
12
 
13
- const EDITABLE_TYPES = ['string', 'number', 'bool', 'oneOf', 'array', 'object']
13
+ const EDITABLE_TYPES = ['string', 'number', 'boolean', 'oneOf', 'array', 'object']
14
14
 
15
15
  const IconSelect = observer(function ({ $value, value }) {
16
16
  const _icons = useMemo(
@@ -39,10 +39,10 @@ const JSONInput = observer(function ({ $value, type }) {
39
39
  return value ? JSON.stringify(value) : ''
40
40
  }, [$value])
41
41
 
42
- const [tempJSON, $tempJSON] = useValue(_JSONValue)
43
- const [badJSON, $badJSON] = useValue(false)
42
+ const $tempJSON = $(_JSONValue)
43
+ const $badJSON = $(false)
44
44
 
45
- const validateJson = useCallback(
45
+ const validateJson = useCallback( // eslint-disable-line react-hooks/exhaustive-deps
46
46
  debounce(text => {
47
47
  try {
48
48
  if (!text) {
@@ -52,13 +52,13 @@ const JSONInput = observer(function ({ $value, type }) {
52
52
  const isValidValue = parsedValue && validateByType(type, parsedValue)
53
53
  if (isValidValue) {
54
54
  $value.set(parsedValue)
55
- $badJSON.setDiff(false)
55
+ $badJSON.set(false)
56
56
  } else {
57
- $badJSON.setDiff(true)
57
+ $badJSON.set(true)
58
58
  }
59
59
  }
60
60
  } catch (error) {
61
- $badJSON.setDiff(true)
61
+ $badJSON.set(true)
62
62
  }
63
63
  }, 300),
64
64
  [$badJSON, $value]
@@ -71,10 +71,10 @@ const JSONInput = observer(function ({ $value, type }) {
71
71
 
72
72
  return pug`
73
73
  Input(
74
- inputStyleName={ badJSON }
74
+ inputStyleName={ badJSON: $badJSON.get() }
75
75
  size='s'
76
76
  type='text'
77
- value=tempJSON || ''
77
+ value=$tempJSON.get() || ''
78
78
  onChangeText=onChangeJSON
79
79
  )
80
80
  `
@@ -118,7 +118,7 @@ const PropInput = observer(function ({ $value, extraParams = {}, options, type,
118
118
  ...extraParams
119
119
  )
120
120
  `
121
- case 'bool':
121
+ case 'boolean':
122
122
  return pug`
123
123
  Input.checkbox(
124
124
  type='checkbox'
@@ -159,8 +159,8 @@ const TypesSelect = observer(function ({
159
159
  ),
160
160
  [possibleValues]
161
161
  )
162
- const [selectedValue, $selectedValue] = useValue(names[0])
163
- const $value = $props.at(name)
162
+ const $selectedValue = $(names[0])
163
+ const $value = $props[name]
164
164
  const value = $value.get()
165
165
 
166
166
  function onChange (value) {
@@ -181,15 +181,15 @@ const TypesSelect = observer(function ({
181
181
  showEmptyValue=false
182
182
  size='s'
183
183
  type='select'
184
- value=selectedValue
184
+ value=$selectedValue.get()
185
185
  onChange=onChange
186
186
  )
187
187
  Br(half)
188
188
  PropInput(
189
189
  $value=$value
190
190
  extraParams=extraParams
191
- options=options[selectedValue]
192
- type=selectedValue
191
+ options=options[$selectedValue.get()]
192
+ type=$selectedValue.get()
193
193
  value=value
194
194
  )
195
195
  else
@@ -199,7 +199,7 @@ const TypesSelect = observer(function ({
199
199
 
200
200
  export default observer(function ValueCell ({ $props, entry }) {
201
201
  const { extraParams, name, possibleValues, type } = entry
202
- const $value = $props.at(name)
202
+ const $value = $props[name]
203
203
  const value = $value.get()
204
204
 
205
205
  if (/^\$/.test(name)) { // hide Input for model prop
@@ -230,7 +230,7 @@ function validateByType (type, value) {
230
230
  return Array.isArray(value)
231
231
  case 'object':
232
232
  return isPlainObject(value)
233
- case 'bool':
233
+ case 'boolean':
234
234
  return typeof value === 'boolean'
235
235
  case 'number':
236
236
  return typeof value === 'number'
@@ -1,7 +1,7 @@
1
1
  import React from 'react'
2
2
  import { Platform } from 'react-native'
3
- import { pug, observer } from 'startupjs'
4
- import { Span, Tag, themed } from '@startupjs/ui'
3
+ import { pug, observer, $ } from 'startupjs'
4
+ import { Span, Tag, themed, Div } from '@startupjs/ui'
5
5
  import Table from './Table'
6
6
  import Tbody from './Tbody'
7
7
  import Thead from './Thead'
@@ -13,37 +13,69 @@ import './index.styl'
13
13
 
14
14
  export default observer(themed(function Constructor ({
15
15
  Component,
16
+ extendedFrom,
16
17
  entries,
17
18
  $props,
18
19
  style
19
20
  }) {
21
+ const $showExtends = $()
22
+ function renderEntry (entry) {
23
+ const { name, type, defaultValue, possibleValues, isRequired } = entry
24
+ return pug`
25
+ Tr(key=name)
26
+ Td
27
+ Span.name(
28
+ style={
29
+ fontFamily: Platform.OS === 'ios' ? 'Menlo-Regular' : 'monospace'
30
+ }
31
+ )= name
32
+ if isRequired
33
+ Tag.required(
34
+ variant='outlined'
35
+ size='s'
36
+ color='error'
37
+ shape='rounded'
38
+ ) Required
39
+ if defaultValue != null
40
+ Span.valueDefault
41
+ Span(description) =#{' '}
42
+ Span.value= JSON.stringify(defaultValue)
43
+ Td: Span(description italic)= entry.description || '-'
44
+ Td: TypeCell(possibleValues=possibleValues type=type)
45
+ Td.vCenter: ValueCell(entry=entry $props=$props)
46
+ `
47
+ }
20
48
  return pug`
21
49
  Table.table(style=style)
22
50
  Thead.thead
23
51
  Tr
24
52
  Td: Span.header PROP
53
+ Td: Span.header DESCRIPTION
25
54
  Td: Span.header TYPE
26
- Td: Span.header DEFAULT
27
55
  Td: Span.header.right VALUE
28
56
  Tbody
57
+ if extendedFrom
58
+ Div.extends
59
+ Div.collapsibleHeader(onPress=() => $showExtends.set(!$showExtends.get()))
60
+ Span(italic style={
61
+ fontFamily: Platform.OS === 'ios' ? 'Menlo-Regular' : 'monospace'
62
+ })
63
+ if $showExtends.get()
64
+ | -#{' '}
65
+ else
66
+ | +#{' '}
67
+ | Extends component props from#{' '}
68
+ Span(bold)= extendedFrom + ' '
69
+ if $showExtends.get()
70
+ | (tap to collapse)
71
+ else
72
+ | (tap to expand)
73
+ if $showExtends.get()
74
+ each entry, index in entries
75
+ if entry.extendedFrom === extendedFrom
76
+ = renderEntry(entry)
29
77
  each entry, index in entries
30
- - const { name, type, defaultValue, possibleValues, isRequired } = entry
31
- Tr(key=index)
32
- Td
33
- Span.name(
34
- style={
35
- fontFamily: Platform.OS === 'ios' ? 'Menlo-Regular' : 'monospace'
36
- }
37
- )= name
38
- if isRequired
39
- Tag.required(
40
- variant='outlined'
41
- size='s'
42
- color='error'
43
- shape='rounded'
44
- ) Required
45
- Td: TypeCell(possibleValues=possibleValues type=type)
46
- Td: Span.value= JSON.stringify(defaultValue)
47
- Td.vCenter: ValueCell(entry=entry $props=$props)
78
+ if !entry.extendedFrom
79
+ = renderEntry(entry)
48
80
  `
49
81
  }))
@@ -12,6 +12,14 @@ $type = var(--color-text-info)
12
12
  &.right
13
13
  text-align right
14
14
 
15
+ .extends
16
+ border-bottom-width 2px
17
+ border-bottom-color var(--color-border-main)
18
+ background-color rgba(black, 0.03)
19
+
20
+ .collapsibleHeader
21
+ padding 1u 1u 1u 2u
22
+
15
23
  .possibleValue
16
24
  flex-direction row
17
25
 
@@ -19,6 +27,9 @@ $type = var(--color-text-info)
19
27
  color $value
20
28
  font-style italic
21
29
 
30
+ .valueDefault
31
+ padding-left 4u
32
+
22
33
  .type
23
34
  color $type
24
35
  font-style italic
@@ -1,5 +1,5 @@
1
1
  import React from 'react'
2
- import { pug, observer, useModel, useLocal } from 'startupjs'
2
+ import { pug, observer, $ } from 'startupjs'
3
3
  import { themed, Div, Span } from '@startupjs/ui'
4
4
  import './index.styl'
5
5
 
@@ -17,11 +17,11 @@ export default observer(function GridVisualizer ({
17
17
  style,
18
18
  children
19
19
  }) {
20
- const $componentSize = useModel('_session.Renderer.componentSize')
20
+ const $componentSize = $.session.Renderer.componentSize
21
21
 
22
22
  function onLayout (e) {
23
23
  const { width, height } = e.nativeEvent.layout
24
- $componentSize.setDiffDeep({ width, height })
24
+ $componentSize.set({ width, height })
25
25
  }
26
26
 
27
27
  // TODO: Bring back width check as an option. For now it's commented out.
@@ -45,7 +45,8 @@ export default observer(function GridVisualizer ({
45
45
  })
46
46
 
47
47
  const LeftBar = observer(themed(({ allowHalfUnit, validate, theme }) => {
48
- const [height = 0] = useLocal('_session.Renderer.componentSize.height')
48
+ const $height = $.session.Renderer.componentSize.height
49
+ const height = $height.get() || 0
49
50
  const units = toUnits(height)
50
51
  const valid = validate ? validateGrid(height, allowHalfUnit) : true
51
52
 
@@ -1,18 +1,14 @@
1
1
  import React, { useMemo, useState } from 'react'
2
- import { pug, observer, $root, useComponentId } from 'startupjs'
2
+ import { pug, observer, $, useId } from 'startupjs'
3
3
  import { themed, Button, Div, ScrollView } from '@startupjs/ui'
4
- import parsePropTypesModule from 'parse-prop-types'
5
4
  import Constructor from './Constructor'
6
5
  import Renderer from './Renderer'
7
6
  import './index.styl'
8
7
 
9
- const parsePropTypes = parsePropTypesModule.default || parsePropTypesModule
10
- if (!parsePropTypes) throw Error('> Can\'t load parse-prop-types module. Issues with bundling')
11
-
12
- function useEntries ({ Component, props, extraParams }) {
8
+ function useEntries ({ Component, props, extraParams, propsJsonSchema }) {
13
9
  return useMemo(() => {
14
- const propTypes = parsePropTypes(Component)
15
- const entries = Object.entries(propTypes)
10
+ if (!propsJsonSchema?.properties) return []
11
+ const entries = Object.entries(propsJsonSchema.properties)
16
12
 
17
13
  const res = parseEntries(entries)
18
14
  .filter(entry => entry.name[0] !== '_') // skip private properties
@@ -36,33 +32,43 @@ function useEntries ({ Component, props, extraParams }) {
36
32
  }
37
33
 
38
34
  return res
39
- }, [])
35
+ }, [extraParams, props, propsJsonSchema])
40
36
  }
41
37
 
42
38
  function parseEntries (entries) {
43
39
  return entries.map(entry => {
40
+ const name = entry[0]
44
41
  const meta = entry[1]
42
+ let type = meta.type
43
+ if (meta.enum) type = 'oneOf'
44
+ if (meta.$comment && meta.$comment.startsWith('(')) type = 'function'
45
+ if (!type) type = 'any'
46
+ let extendedFrom = meta.extendedFrom
47
+ // children prop is special, it should not be marked as extendedFrom
48
+ if (name === 'children') extendedFrom = undefined
45
49
  return {
46
- name: entry[0],
47
- type: meta.type.name,
48
- defaultValue: meta.defaultValue && meta.defaultValue.value,
49
- possibleValues: meta.type.value,
50
- isRequired: meta.required
50
+ name,
51
+ type,
52
+ defaultValue: meta.default,
53
+ possibleValues: meta.enum,
54
+ isRequired: meta.required,
55
+ description: meta.description,
56
+ extendedFrom
51
57
  }
52
58
  })
53
59
  }
54
60
 
55
61
  async function useInitDefaultProps ({ entries, $theProps }) {
56
62
  if ($theProps.get()) return
57
- $theProps.setDiff({})
63
+ $theProps.set({})
58
64
 
59
65
  const promises = []
60
66
 
61
67
  for (const { name, value, defaultValue } of entries) {
62
68
  if (value !== undefined) {
63
- promises.push($theProps.set(name, value, null))
69
+ promises.push($theProps[name].set(value))
64
70
  } else if (defaultValue !== undefined) {
65
- promises.push($theProps.set(name, defaultValue, null))
71
+ promises.push($theProps[name].set(defaultValue))
66
72
  }
67
73
  }
68
74
  if (promises.length) throw await Promise.all(promises)
@@ -74,6 +80,7 @@ export default observer(themed(function PComponent ({
74
80
  Component,
75
81
  $props,
76
82
  props,
83
+ propsJsonSchema,
77
84
  extraParams,
78
85
  componentName,
79
86
  showGrid,
@@ -83,17 +90,17 @@ export default observer(themed(function PComponent ({
83
90
  block: defaultBlock
84
91
  }) {
85
92
  const [block, setBlock] = useState(!!defaultBlock)
86
- const componentId = useComponentId()
93
+ const componentId = useId()
87
94
 
88
95
  const $theProps = useMemo(() => {
89
96
  if (!$props) {
90
- return $root.scope(`_session.Props.${componentId}`)
97
+ return $.session.Props[componentId]
91
98
  } else {
92
99
  return $props
93
100
  }
94
- }, [$props])
101
+ }, [$props, componentId])
95
102
 
96
- const entries = useEntries({ Component, props, extraParams })
103
+ const entries = useEntries({ Component, props, extraParams, propsJsonSchema })
97
104
  useInitDefaultProps({ entries, $theProps })
98
105
 
99
106
  function Wrapper ({ children }) {
@@ -117,6 +124,7 @@ export default observer(themed(function PComponent ({
117
124
  Div.top
118
125
  Constructor(
119
126
  Component=Component
127
+ extendedFrom=propsJsonSchema?.extendedFrom
120
128
  $props=$theProps
121
129
  entries=entries
122
130
  )
@@ -1,6 +1,6 @@
1
1
  import React from 'react'
2
- import { pug, observer, $root } from 'startupjs'
3
- import { H4 } from '@startupjs/ui'
2
+ import { pug, observer, $, useId } from 'startupjs'
3
+ import { H4, Alert } from '@startupjs/ui'
4
4
  import Props from '../Props'
5
5
  import {
6
6
  useShowGrid,
@@ -13,12 +13,14 @@ const MODELS = new WeakMap()
13
13
 
14
14
  export default observer(function Sandbox ({
15
15
  Component,
16
+ propsJsonSchema,
16
17
  $props,
17
18
  ...otherProps
18
19
  }) {
19
20
  const [showGrid] = useShowGrid()
20
21
  const [showSizes] = useShowSizes()
21
22
  const [validateWidth] = useValidateWidth()
23
+ const uniqId = useId()
22
24
 
23
25
  if (!Component) {
24
26
  return pug`
@@ -26,10 +28,25 @@ export default observer(function Sandbox ({
26
28
  `
27
29
  }
28
30
 
31
+ if (typeof propsJsonSchema !== 'object' || Object.keys(propsJsonSchema).length === 0) {
32
+ return pug`
33
+ Alert(variant='error')
34
+ | No propsJsonSchema provided for the Sandbox component (or it's an empty object).
35
+ | Make sure that:
36
+ | 1. your component file has the magic 'const export _PropsJsonSchema = ' declaration;
37
+ | 2. your component file has 'export interface' with props interface declared;
38
+ | 3. you import the '_PropsJsonSchema' from the component file
39
+ | and pass it to the Sandbox as 'propsJsonSchema' prop;
40
+ | 4. 'babel-preset-startupjs' must have an option 'docgen: true' enabled
41
+ | to transform the TS interface to JSON schema at build time.
42
+ `
43
+ }
44
+
29
45
  return pug`
30
46
  Props.root(
31
47
  Component=Component
32
- $props=$props || getUniqModel(Component)
48
+ propsJsonSchema=propsJsonSchema
49
+ $props=$props || getUniqModel(Component, uniqId)
33
50
  showSizes=showSizes
34
51
  showGrid=showGrid
35
52
  validateWidth=validateWidth
@@ -38,10 +55,9 @@ export default observer(function Sandbox ({
38
55
  `
39
56
  })
40
57
 
41
- function getUniqModel (Component) {
58
+ function getUniqModel (Component, uniqId) {
42
59
  if (MODELS.has(Component)) return MODELS.get(Component)
43
- const uniqId = $root.id()
44
- const $uniqModel = $root.scope('_session.Props.' + uniqId)
60
+ const $uniqModel = $.session.Props[uniqId]
45
61
  MODELS.set(Component, $uniqModel)
46
62
  return $uniqModel
47
63
  }
package/index.js CHANGED
@@ -1,12 +1,13 @@
1
- import { routes, Layout } from './client/app'
2
- import { wrapDocsContext } from './docsContext'
1
+ // TODO: refactor docs app to work with the new expo app structure
2
+ // import { routes, Layout } from './client/app'
3
+ // import { wrapDocsContext } from './docsContext'
3
4
 
4
- // Wrap Layout into context
5
- export default function (docs) {
6
- return {
7
- routes,
8
- Layout: wrapDocsContext(Layout, docs)
9
- }
10
- }
5
+ // // Wrap Layout into context
6
+ // export default function (docs) {
7
+ // return {
8
+ // routes,
9
+ // Layout: wrapDocsContext(Layout, docs)
10
+ // }
11
+ // }
11
12
 
12
13
  export * from './client/components'
package/package.json CHANGED
@@ -4,14 +4,13 @@
4
4
  "access": "public"
5
5
  },
6
6
  "description": "MDX documentation generator",
7
- "version": "0.60.0-canary.0",
7
+ "version": "0.60.0-canary.11",
8
8
  "type": "module",
9
9
  "main": "index.js",
10
10
  "dependencies": {
11
11
  "@fortawesome/free-solid-svg-icons": "^5.12.0",
12
- "@startupjs/mdx": "^0.60.0-canary.0",
13
- "@startupjs/scrollable-anchors": "^0.60.0-canary.0",
14
- "parse-prop-types": "^0.3.0"
12
+ "@startupjs/mdx": "^0.60.0-canary.9",
13
+ "@startupjs/scrollable-anchors": "^0.60.0-canary.7"
15
14
  },
16
15
  "peerDependencies": {
17
16
  "@startupjs/ui": "*",
@@ -19,5 +18,5 @@
19
18
  "react-native": "*",
20
19
  "startupjs": "*"
21
20
  },
22
- "gitHead": "4c5baa750402d0beb02921a38413620b348bd374"
21
+ "gitHead": "98f7cc4f4c26816b15366986e81de0a4b996f8b1"
23
22
  }