@symbo.ls/default-config 3.8.8 → 3.14.0

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.
Files changed (51) hide show
  1. package/README.md +4 -1
  2. package/blank/font.js +1 -1
  3. package/blank/index.js +8 -8
  4. package/components/Atoms/Block.js +29 -0
  5. package/components/Atoms/Box.js +37 -0
  6. package/components/Atoms/Form.js +5 -0
  7. package/components/Atoms/Grid.js +37 -0
  8. package/components/Atoms/Hgroup.js +57 -0
  9. package/components/Atoms/Iframe.js +8 -0
  10. package/components/Atoms/Img.js +9 -0
  11. package/components/Atoms/InteractiveComponent.js +65 -0
  12. package/components/Atoms/Picture.js +34 -0
  13. package/components/Atoms/Shape/index.js +3 -0
  14. package/components/Atoms/Shape.js +249 -0
  15. package/components/Atoms/Svg.js +45 -0
  16. package/components/Atoms/Text.js +43 -0
  17. package/components/Atoms/Theme.js +20 -0
  18. package/components/Atoms/Video.js +11 -0
  19. package/components/Avatar.js +10 -0
  20. package/components/Button.js +72 -0
  21. package/components/Dialog.js +69 -0
  22. package/components/Dropdown.js +153 -0
  23. package/components/Icon/index.js +236 -0
  24. package/components/Icon/style.js +8 -0
  25. package/components/Input/Checkbox.js +54 -0
  26. package/components/Input/Input.js +37 -0
  27. package/components/Input/NumberInput.js +25 -0
  28. package/components/Input/Radio.js +31 -0
  29. package/components/Input/Textarea.js +47 -0
  30. package/components/Input/Toggle.js +36 -0
  31. package/components/Link.js +166 -0
  32. package/components/Notification.js +43 -0
  33. package/components/Range.js +106 -0
  34. package/components/Select.js +33 -0
  35. package/components/Tooltip/index.js +128 -0
  36. package/components/Tooltip/style.js +12 -0
  37. package/components/index.js +36 -0
  38. package/default/font.js +9 -2
  39. package/default/index.js +2 -2
  40. package/default/typography.js +1 -0
  41. package/designSystem/color.js +70 -0
  42. package/designSystem/font.js +21 -0
  43. package/designSystem/icons.js +69 -0
  44. package/designSystem/index.js +45 -0
  45. package/designSystem/media.js +31 -0
  46. package/designSystem/spacing.js +6 -0
  47. package/designSystem/theme.js +247 -0
  48. package/designSystem/timing.js +8 -0
  49. package/designSystem/typography.js +9 -0
  50. package/index.js +15 -0
  51. package/package.json +4 -1
@@ -0,0 +1,47 @@
1
+ 'use strict'
2
+
3
+ export const Textarea = {
4
+ tag: 'textarea',
5
+ extends: ['Input', 'Flex'],
6
+
7
+ fontfamily: 'Avenir',
8
+ placeholder: 'Leave us a message...',
9
+ padding: 'A',
10
+ theme: 'field',
11
+ border: 'none',
12
+ minHeight: 'E_default',
13
+ width: '100%',
14
+ height: 'E1_default',
15
+ fontFamily: 'inherit',
16
+ round: 'Z2',
17
+ lineHeight: 1.4,
18
+
19
+ '.outlined': {
20
+ borderWidth: '1px',
21
+ borderStyle: 'solid'
22
+ }
23
+
24
+ // NOTE: removed `html: (el, s) => el.value`. It was redundant — the
25
+ // framework's value handling (element/create.js value effect + static value
26
+ // path) already drives `node.value` for textareas. Worse, when `value` was
27
+ // itself a function (the common case for reactive inputs), this html getter
28
+ // returned the function reference, which got serialized to innerHTML as
29
+ // `(el, s) => s.foo` — leaking the function source into the visible text.
30
+ }
31
+
32
+ export const TextareaWithButton = {
33
+ display: 'flex',
34
+ gap: 'Y2',
35
+ Textarea: {
36
+ height: 'C2+W',
37
+ minWidth: 'H',
38
+ padding: 'A',
39
+ fontSize: 'Z1',
40
+ round: 'Z2',
41
+ minHeight: 'fit-content'
42
+ },
43
+ SquareButton: {
44
+ background: 'blue',
45
+ Icon: { name: 'send' }
46
+ }
47
+ }
@@ -0,0 +1,36 @@
1
+ 'use strict'
2
+
3
+ export const Toggle = {
4
+ extends: 'Checkbox',
5
+
6
+ Input: {
7
+ ':checked + div': {
8
+ background: 'green2+8',
9
+ justifyContent: 'flex-end'
10
+ }
11
+ },
12
+
13
+ Flex: {
14
+ boxSize: 'A1 B1',
15
+ padding: '- W_default',
16
+ round: 'D',
17
+ align: 'center flex-start',
18
+ theme: 'field',
19
+ border: 'none',
20
+ transition: 'opacity .15s ease',
21
+ ':after': {
22
+ content: '""',
23
+ boxSize: 'A A',
24
+ round: '100%',
25
+ background: 'white',
26
+ boxShadow: 'gray.2 1px 1px Z'
27
+ },
28
+ Icon: null
29
+ }
30
+ }
31
+
32
+ export const ToggleHgroup = {
33
+ extends: 'CheckboxHgroup',
34
+ Checkbox: null,
35
+ Toggle: {}
36
+ }
@@ -0,0 +1,166 @@
1
+ 'use strict'
2
+
3
+ import { router as defaultRouter } from '@symbo.ls/router'
4
+ import { resolvePropValue } from 'attrs-in-props'
5
+
6
+ // SPA-by-default click handler. `Link` mixes this in below so internal hrefs
7
+ // route through the smbls router instead of triggering a full page reload.
8
+ // External schemes (http(s), mailto:, tel:, etc.) fall through to the browser.
9
+ const routerOnClick = (event, el, s) => {
10
+ const { context: ctx } = el
11
+ const { href: h, scrollToTop, stopPropagation } = el
12
+ let href = el.call('exec', h, el)
13
+
14
+ if (el.call('isString', href) && href.includes('{{')) {
15
+ href = el.call('replaceLiteralsWithObjectFields', href)
16
+ }
17
+
18
+ if (stopPropagation) event.stopPropagation()
19
+ if (!href) return
20
+ const { utils, snippets, functions, routerOptions } = ctx
21
+ const root = el.__ref.root
22
+ const linkIsExternal =
23
+ href.startsWith('http://') ||
24
+ href.startsWith('https://') ||
25
+ href.startsWith('mailto:') ||
26
+ href.startsWith('tel:') ||
27
+ href.startsWith('sketch:') ||
28
+ href.startsWith('whatsapp:') ||
29
+ href.startsWith('sms:') ||
30
+ href.startsWith('skype:') ||
31
+ href.startsWith('viber:') ||
32
+ href.startsWith('callto:') ||
33
+ href.startsWith('facetime:') ||
34
+ href.startsWith('facetime-audio:') ||
35
+ href.startsWith('geo:') ||
36
+ href.startsWith('maps:')
37
+ if (href && !linkIsExternal) {
38
+ event.preventDefault()
39
+ try {
40
+ let targetEl = root
41
+ if (routerOptions && routerOptions.customRouterElement) {
42
+ const parts = Array.isArray(routerOptions.customRouterElement)
43
+ ? routerOptions.customRouterElement
44
+ : routerOptions.customRouterElement.split('.')
45
+ let resolved = root
46
+ for (const part of parts) {
47
+ if (!resolved || !resolved[part]) { resolved = null; break }
48
+ resolved = resolved[part]
49
+ }
50
+ if (resolved) {
51
+ targetEl = resolved
52
+ if (root.routes) targetEl.routes = root.routes
53
+ }
54
+ }
55
+ ;(functions.router || snippets.router || utils.router || defaultRouter)(
56
+ href,
57
+ targetEl,
58
+ {},
59
+ {
60
+ scrollToOptions: { behaviour: 'instant' },
61
+ scrollToTop: el.call('isDefined', scrollToTop) ? scrollToTop : true,
62
+ ...routerOptions,
63
+ ...el.routerOptions
64
+ }
65
+ )
66
+ } catch (e) {
67
+ console.warn(e)
68
+ }
69
+ }
70
+ }
71
+
72
+ export const Link = {
73
+ extends: 'Focusable',
74
+ tag: 'a',
75
+
76
+ aria: {},
77
+ fontWeight: 'bold',
78
+ textDecoration: 'none',
79
+ color: 'currentColor',
80
+ draggable: false,
81
+
82
+ attr: {
83
+ href: (el) => {
84
+ return resolvePropValue(el, el.href) ||
85
+ resolvePropValue(el, el.call('exec', el, el).href)
86
+ },
87
+ 'aria-label': (el) => (el.aria ? el.aria.label : el.text)
88
+ },
89
+
90
+ onClick: routerOnClick
91
+ }
92
+
93
+ export const A = {
94
+ extends: 'Link'
95
+ }
96
+
97
+ // Kept for backwards compatibility — `Link` already has the router onClick
98
+ // built in, so `RouterLink` and `RouteLink` are now thin aliases.
99
+ export const RouterLink = {
100
+ onClick: (event, el, s) => {
101
+ const { context: ctx } = el
102
+ const { href: h, scrollToTop, stopPropagation } = el
103
+ let href = el.call('exec', h, el)
104
+
105
+ if (el.call('isString', href) && href.includes('{{')) {
106
+ href = el.call('replaceLiteralsWithObjectFields', href)
107
+ }
108
+
109
+ if (stopPropagation) event.stopPropagation()
110
+ if (!href) return
111
+ const { utils, snippets, functions, routerOptions } = ctx
112
+ const root = el.__ref.root
113
+ const linkIsExternal =
114
+ href.startsWith('http://') ||
115
+ href.startsWith('https://') ||
116
+ href.startsWith('mailto:') ||
117
+ href.startsWith('tel:') ||
118
+ href.startsWith('sketch:') ||
119
+ href.startsWith('whatsapp:') ||
120
+ href.startsWith('sms:') ||
121
+ href.startsWith('skype:') ||
122
+ href.startsWith('viber:') ||
123
+ href.startsWith('callto:') ||
124
+ href.startsWith('facetime:') ||
125
+ href.startsWith('facetime-audio:') ||
126
+ href.startsWith('geo:') ||
127
+ href.startsWith('maps:')
128
+ if (href && !linkIsExternal) {
129
+ event.preventDefault()
130
+ try {
131
+ let targetEl = root
132
+ if (routerOptions && routerOptions.customRouterElement) {
133
+ const parts = Array.isArray(routerOptions.customRouterElement)
134
+ ? routerOptions.customRouterElement
135
+ : routerOptions.customRouterElement.split('.')
136
+ let resolved = root
137
+ for (const part of parts) {
138
+ if (!resolved || !resolved[part]) { resolved = null; break }
139
+ resolved = resolved[part]
140
+ }
141
+ if (resolved) {
142
+ targetEl = resolved
143
+ if (root.routes) targetEl.routes = root.routes
144
+ }
145
+ }
146
+ ;(functions.router || snippets.router || utils.router || defaultRouter)(
147
+ href,
148
+ targetEl,
149
+ {},
150
+ {
151
+ scrollToOptions: { behaviour: 'instant' },
152
+ scrollToTop: el.call('isDefined', scrollToTop) ? scrollToTop : true,
153
+ ...routerOptions,
154
+ ...el.routerOptions
155
+ }
156
+ )
157
+ } catch (e) {
158
+ console.warn(e)
159
+ }
160
+ }
161
+ }
162
+ }
163
+
164
+ export const RouteLink = {
165
+ extends: [Link, RouterLink]
166
+ }
@@ -0,0 +1,43 @@
1
+ 'use strict'
2
+
3
+ export const Notification = {
4
+ display: 'flex',
5
+ theme: 'alert',
6
+ padding: 'Z1 B Z A',
7
+ round: 'A A A Y2',
8
+ gap: 'X2',
9
+ cursor: 'pointer',
10
+ align: 'flex-start center',
11
+
12
+ IconText: {
13
+ Icon: {
14
+ name: 'info outline'
15
+ },
16
+ Text: {
17
+ ':empty': { hide: true }
18
+ }
19
+ },
20
+
21
+ Hgroup: {
22
+ extends: ['Flex', 'Hgroup'],
23
+ flow: 'y',
24
+ align: 'flex-start',
25
+ gap: 'X2',
26
+
27
+ H: {
28
+ tag: 'h6',
29
+ margin: '0',
30
+ fontWeight: '600',
31
+ lineHeight: '1em',
32
+ text: 'Notification',
33
+ ':empty': { hide: true }
34
+ },
35
+
36
+ P: {
37
+ fontSize: 'Z',
38
+ margin: '0',
39
+ text: 'is not always a distraction',
40
+ ':empty': { hide: true }
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,106 @@
1
+ 'use strict'
2
+
3
+ import { opacify } from '@symbo.ls/scratch'
4
+
5
+ export const Range = {
6
+ tag: 'input',
7
+
8
+ appearance: 'none',
9
+ width: '100%',
10
+ height: '2px',
11
+ outline: 'none',
12
+ flex: 1,
13
+
14
+ onInput: (ev, el, s) => {
15
+ if (el.call('isFunction', el.onInput)) {
16
+ el.onInput(ev, el, s)
17
+ } else {
18
+ s.update({ value: parseFloat(el.node.value) })
19
+ }
20
+ },
21
+ onChange: (ev, el, s) => {
22
+ if (el.call('isFunction', el.onChange)) {
23
+ el.onChange(ev, el, s)
24
+ } else {
25
+ s.update({ value: parseFloat(el.node.value) })
26
+ }
27
+ },
28
+
29
+ '::-webkit-slider-thumb': {
30
+ boxSizing: 'content-box',
31
+ width: '8px',
32
+ height: '8px',
33
+ borderWidth: '2px',
34
+ borderStyle: 'solid',
35
+ borderRadius: '100%',
36
+ opacity: '.8',
37
+ appearance: 'none'
38
+ },
39
+
40
+ '::-webkit-slider-runnable-track': {},
41
+
42
+ '@dark': {
43
+ background: 'white.2',
44
+
45
+ '::-webkit-slider-thumb': {
46
+ background: '#232526',
47
+ borderColor: opacify('#454646', 0.75)
48
+ },
49
+
50
+ ':hover': {
51
+ '::-webkit-slider-thumb': {
52
+ borderColor: opacify('#fff', 0.35)
53
+ }
54
+ },
55
+
56
+ ':focus': {
57
+ '::-webkit-slider-thumb': {
58
+ borderColor: '#3C6AC0'
59
+ }
60
+ }
61
+ },
62
+
63
+ '@light': {
64
+ background: 'gray9',
65
+
66
+ '::-webkit-slider-thumb': {
67
+ background: 'white',
68
+ borderColor: 'gray9'
69
+ },
70
+
71
+ ':hover': {
72
+ '::-webkit-slider-thumb': {
73
+ borderColor: 'gray7'
74
+ }
75
+ },
76
+
77
+ ':focus': {
78
+ '::-webkit-slider-thumb': {
79
+ borderColor: 'blue'
80
+ }
81
+ }
82
+ },
83
+
84
+ deps: {
85
+ returnPropertyValue: (el, property, def) => {
86
+ const val = el.call('exec', el[property], el)
87
+ const r = el.call('isFunction', val)
88
+ ? val(el, el.state)
89
+ : val !== undefined
90
+ ? val
91
+ : def !== undefined
92
+ ? def
93
+ : 0
94
+ return r + ''
95
+ }
96
+ },
97
+
98
+ attr: {
99
+ type: 'range',
100
+ value: (el, s) =>
101
+ el.call('exec', s.value || el.value || el.defaultValue, el),
102
+ min: (el, s) => el.deps.returnPropertyValue(el, 'min', 0),
103
+ max: (el, s) => el.deps.returnPropertyValue(el, 'max', 100),
104
+ step: (el, s) => el.deps.returnPropertyValue(el, 'step', 1)
105
+ }
106
+ }
@@ -0,0 +1,33 @@
1
+ 'use strict'
2
+
3
+ export const Select = {
4
+ extends: 'Focusable',
5
+ tag: 'select',
6
+
7
+ fontSize: 'A',
8
+ border: 'none',
9
+ boxSizing: 'border-box',
10
+ theme: 'field',
11
+ cursor: 'pointer',
12
+ childProps: {
13
+ tag: 'option',
14
+ attr: {
15
+ value: (el) => el.value,
16
+ selected: (el) => el.selected,
17
+ disabled: (el) => el.disabled
18
+ }
19
+ },
20
+
21
+ attr: {
22
+ name: (el) => el.name,
23
+ disabled: (el) => el.disabled,
24
+ value: el => {
25
+ if (!el.value) return
26
+ const val = el.call('exec', el.value, el)
27
+ if (el.call('isString', val) && val.includes('{{')) {
28
+ return el.call('replaceLiteralsWithObjectFields', val)
29
+ }
30
+ return val
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,128 @@
1
+ 'use strict'
2
+
3
+ import { isDefined } from '@symbo.ls/utils'
4
+
5
+ export const Tooltip = {
6
+ display: 'flex',
7
+
8
+ theme: 'dialog',
9
+ background: 'black',
10
+ flow: 'column',
11
+ shape: 'tooltip',
12
+ shapeDirection: 'left',
13
+ padding: 'Z1 A',
14
+ round: 'Y2',
15
+ width: 'fit-content',
16
+ minWidth: 'D2',
17
+ maxWidth: 'F2',
18
+ gap: 'X',
19
+ textAlign: 'center',
20
+ attr: { tooltip: true },
21
+
22
+ Title: {
23
+ if: ({ parent }) => isDefined(parent.title) || parent.title,
24
+ width: 'fit-content',
25
+ fontWeight: 500,
26
+ color: 'gray12',
27
+ text: ({ parent }) => parent.title
28
+ },
29
+
30
+ P: {
31
+ if: (el, s) =>
32
+ el.call('isDefined', el.call('exec', el.parent.description, el)) ||
33
+ el.text,
34
+ width: 'fit-content',
35
+ fontSize: 'Z2',
36
+ margin: '0',
37
+ color: 'gray6',
38
+ fontWeight: '400',
39
+ text: (el, s) => el.call('exec', el.parent.description, el)
40
+ }
41
+ }
42
+
43
+ export const TooltipHidden = {
44
+ extends: 'Tooltip',
45
+
46
+ position: 'absolute',
47
+ pointerEvents: 'none',
48
+ opacity: '0',
49
+ visibility: 'hidden',
50
+ transition:
51
+ 'C defaultBezier opacity, C defaultBezier visibility, B defaultBezier transform',
52
+
53
+ onInit: (el) => {
54
+ const result = !el.shapeDirection || el.shapeDirection === 'top'
55
+ ? {
56
+ top: '112%',
57
+ left: '50%',
58
+ transform: 'translate3d(-50%,10%,0)',
59
+
60
+ '.isActive': {
61
+ transform: 'translate3d(-50%,0,0)',
62
+ opacity: 1,
63
+ visibility: 'visible'
64
+ }
65
+ }
66
+ : el.shapeDirection === 'right'
67
+ ? {
68
+ transform: 'translate3d(10%,-50%,0)',
69
+ left: '112%',
70
+ top: '50%',
71
+
72
+ '.isActive': {
73
+ transform: 'translate3d(0%,-50%,0)',
74
+ opacity: 1,
75
+ visibility: 'visible'
76
+ }
77
+ }
78
+ : el.shapeDirection === 'bottom'
79
+ ? {
80
+ transform: 'translate3d(-50%,-10%,0)',
81
+ bottom: '112%',
82
+ left: '50%',
83
+
84
+ '.isActive': {
85
+ transform: 'translate3d(-50%,0,0)',
86
+ opacity: 1,
87
+ visibility: 'visible'
88
+ }
89
+ }
90
+ : el.shapeDirection === 'left'
91
+ ? {
92
+ transform: 'translate3d(10%,-50%,0)',
93
+ right: '112%',
94
+ top: '50%',
95
+
96
+ '.isActive': {
97
+ transform: 'translate3d(0%,-50%,0)',
98
+ opacity: 1,
99
+ visibility: 'visible'
100
+ }
101
+ }
102
+ : {}
103
+ Object.assign(el, result)
104
+ }
105
+ }
106
+
107
+ export const TooltipParent = {
108
+ position: 'relative',
109
+ zIndex: 999,
110
+
111
+ onInit: (el) => {
112
+ const { Tooltip, TooltipHidden } = el
113
+ const TooltipElem = Tooltip || TooltipHidden
114
+ if (!TooltipElem) return
115
+ const TooltipActive =
116
+ TooltipElem && TooltipElem['.isActive']
117
+ Object.assign(el, {
118
+ ':hover, &:focus-visible': {
119
+ zIndex: 1000,
120
+ '& [tooltip]': TooltipActive || {
121
+ transform: 'translate3d(-50%, 0, 0)',
122
+ opacity: 1,
123
+ visibility: 'visible'
124
+ }
125
+ }
126
+ })
127
+ }
128
+ }
@@ -0,0 +1,12 @@
1
+ 'use strict'
2
+
3
+ export default {
4
+ textAlign: 'center',
5
+ padding: '1.2em',
6
+ caption: {
7
+ whiteSpace: 'nowrap'
8
+ },
9
+ span: {
10
+ opacity: '.5'
11
+ }
12
+ }
@@ -0,0 +1,36 @@
1
+ 'use strict'
2
+
3
+ // Atoms
4
+ export * from './Atoms/Block.js'
5
+ export * from './Atoms/Img.js'
6
+ export * from './Atoms/Form.js'
7
+ export * from './Atoms/Iframe.js'
8
+ export * from './Atoms/InteractiveComponent.js'
9
+ export * from './Atoms/Picture.js'
10
+ export * from './Atoms/Svg.js'
11
+ export * from './Atoms/Shape.js'
12
+ export * from './Atoms/Video.js'
13
+ export * from './Atoms/Theme.js'
14
+ export * from './Atoms/Text.js'
15
+ export * from './Atoms/Box.js'
16
+ export * from './Atoms/Hgroup.js'
17
+
18
+ // Input
19
+ export * from './Input/Input.js'
20
+ export * from './Input/NumberInput.js'
21
+ export * from './Input/Checkbox.js'
22
+ export * from './Input/Radio.js'
23
+ export * from './Input/Toggle.js'
24
+ export * from './Input/Textarea.js'
25
+
26
+ // Components
27
+ export * from './Icon/index.js'
28
+ export * from './Link.js'
29
+ export * from './Select.js'
30
+ export * from './Button.js'
31
+ export * from './Dialog.js'
32
+ export * from './Tooltip/index.js'
33
+ export * from './Avatar.js'
34
+ export * from './Range.js'
35
+ export * from './Dropdown.js'
36
+ export * from './Notification.js'
package/default/font.js CHANGED
@@ -6,9 +6,16 @@ export const font = {
6
6
  }]
7
7
  }
8
8
 
9
- export const font_family = {
9
+ export const fontFamily = {
10
10
  system: {
11
11
  value: ['"Helvetica Neue"', 'Helvetica', 'Arial'],
12
- type: 'sans-serif'
12
+ type: 'sans-serif',
13
+ metrics: {
14
+ capHeight: 714,
15
+ ascent: 952,
16
+ descent: -213,
17
+ lineGap: 28,
18
+ unitsPerEm: 1000
19
+ }
13
20
  }
14
21
  }
package/default/index.js CHANGED
@@ -4,7 +4,7 @@ import { color, gradient } from './color.js'
4
4
  import { theme } from './theme.js'
5
5
  import { typography } from './typography.js'
6
6
  import { spacing } from './spacing.js'
7
- import { font, font_family } from './font.js'
7
+ import { font, fontFamily } from './font.js'
8
8
  import { icons } from './icons.js'
9
9
  import { media } from './media.js'
10
10
  import { timing } from './timing.js'
@@ -17,7 +17,7 @@ export const DEFAULT_CONFIG = {
17
17
  typography,
18
18
  spacing,
19
19
  font,
20
- font_family,
20
+ fontFamily,
21
21
  timing,
22
22
  icons,
23
23
  media,
@@ -4,5 +4,6 @@ export const typography = {
4
4
  base: 16,
5
5
  ratio: 1.25,
6
6
  subSequence: true,
7
+ useCapsize: true,
7
8
  templates: {}
8
9
  }