@muonic/muon 0.0.2-beta.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 (124) hide show
  1. package/.nycrc +17 -0
  2. package/.versionrc +3 -0
  3. package/CHANGELOG.md +389 -0
  4. package/components/card/index.js +1 -0
  5. package/components/card/src/card-component.js +43 -0
  6. package/components/card/src/card-styles.css +25 -0
  7. package/components/card/src/config-tokens.json +11 -0
  8. package/components/card/src/design-tokens.json +34 -0
  9. package/components/card/story.js +52 -0
  10. package/components/cta/index.js +1 -0
  11. package/components/cta/src/config-tokens.json +11 -0
  12. package/components/cta/src/cta-component.js +174 -0
  13. package/components/cta/src/cta-styles.css +105 -0
  14. package/components/cta/src/design-tokens.json +132 -0
  15. package/components/cta/story.js +99 -0
  16. package/components/detail/index.js +1 -0
  17. package/components/detail/src/config-tokens.json +11 -0
  18. package/components/detail/src/design-tokens.json +102 -0
  19. package/components/detail/src/detail-component.js +27 -0
  20. package/components/detail/src/detail-styles.css +83 -0
  21. package/components/detail/story.js +33 -0
  22. package/components/form/index.js +1 -0
  23. package/components/form/src/config-tokens.json +11 -0
  24. package/components/form/src/design-tokens.json +9 -0
  25. package/components/form/src/form-component.js +197 -0
  26. package/components/form/src/form-styles.css +10 -0
  27. package/components/form/story.js +71 -0
  28. package/components/icon/index.js +1 -0
  29. package/components/icon/src/config-tokens.json +31 -0
  30. package/components/icon/src/design-tokens.json +8 -0
  31. package/components/icon/src/icon-component.js +91 -0
  32. package/components/icon/src/icon-styles.css +26 -0
  33. package/components/icon/story.js +26 -0
  34. package/components/image/index.js +1 -0
  35. package/components/image/src/config-tokens.json +26 -0
  36. package/components/image/src/image-component.js +96 -0
  37. package/components/image/src/image-styles.css +71 -0
  38. package/components/image/story.js +31 -0
  39. package/components/inputter/index.js +1 -0
  40. package/components/inputter/src/config-tokens.json +14 -0
  41. package/components/inputter/src/design-tokens.json +308 -0
  42. package/components/inputter/src/inputter-component.js +227 -0
  43. package/components/inputter/src/inputter-styles-detail.css +59 -0
  44. package/components/inputter/src/inputter-styles.css +305 -0
  45. package/components/inputter/src/inputter-styles.slotted.css +64 -0
  46. package/components/inputter/story.js +243 -0
  47. package/css/accessibility.css +3 -0
  48. package/css/default.css +9 -0
  49. package/css/global.css +8 -0
  50. package/directives/image-loader-directive.js +116 -0
  51. package/directives/svg-loader-directive.js +94 -0
  52. package/index.js +52 -0
  53. package/mixins/card-mixin.js +27 -0
  54. package/mixins/detail-mixin.js +128 -0
  55. package/mixins/form-associate-mixin.js +36 -0
  56. package/mixins/form-element-mixin.js +378 -0
  57. package/mixins/image-holder-mixin.js +20 -0
  58. package/mixins/mask-mixin.js +159 -0
  59. package/mixins/validation-mixin.js +272 -0
  60. package/muon-element/index.js +97 -0
  61. package/package.json +72 -0
  62. package/rollup.config.mjs +30 -0
  63. package/scripts/build/storybook/index.mjs +11 -0
  64. package/scripts/build/storybook/run.mjs +47 -0
  65. package/scripts/rollup-plugins.mjs +116 -0
  66. package/scripts/serve/index.mjs +11 -0
  67. package/scripts/serve/run.mjs +27 -0
  68. package/scripts/style-dictionary.mjs +64 -0
  69. package/scripts/utils/config.mjs +30 -0
  70. package/scripts/utils/index.mjs +283 -0
  71. package/storybook/find-stories.js +36 -0
  72. package/storybook/server.config.mjs +19 -0
  73. package/storybook/stories.js +86 -0
  74. package/storybook/tokens/color.js +87 -0
  75. package/storybook/tokens/font.js +52 -0
  76. package/storybook/tokens/spacer.js +48 -0
  77. package/tests/README.md +3 -0
  78. package/tests/components/card/__snapshots__/card.test.snap.js +70 -0
  79. package/tests/components/card/card.test.js +81 -0
  80. package/tests/components/cta/__snapshots__/cta.test.snap.js +246 -0
  81. package/tests/components/cta/cta.test.js +212 -0
  82. package/tests/components/form/__snapshots__/form.test.snap.js +115 -0
  83. package/tests/components/form/form.test.js +336 -0
  84. package/tests/components/icon/__snapshots__/icon.test.snap.js +95 -0
  85. package/tests/components/icon/icon.test.js +197 -0
  86. package/tests/components/image/__snapshots__/image.test.snap.js +205 -0
  87. package/tests/components/image/image.test.js +314 -0
  88. package/tests/components/image/images/15.png +0 -0
  89. package/tests/components/image/images/150.png +0 -0
  90. package/tests/components/inputter/__snapshots__/inputter.test.snap.js +357 -0
  91. package/tests/components/inputter/inputter.test.js +427 -0
  92. package/tests/helpers/index.js +30 -0
  93. package/tests/mixins/__snapshots__/card.test.snap.js +35 -0
  94. package/tests/mixins/__snapshots__/detail.test.snap.js +237 -0
  95. package/tests/mixins/__snapshots__/form-element.test.snap.js +137 -0
  96. package/tests/mixins/__snapshots__/mask.test.snap.js +53 -0
  97. package/tests/mixins/__snapshots__/validation.test.snap.js +297 -0
  98. package/tests/mixins/card.test.js +63 -0
  99. package/tests/mixins/detail.test.js +223 -0
  100. package/tests/mixins/form-element.test.js +473 -0
  101. package/tests/mixins/mask.test.js +261 -0
  102. package/tests/mixins/muon-element.test.js +52 -0
  103. package/tests/mixins/validation.test.js +423 -0
  104. package/tests/runner/commands.mjs +19 -0
  105. package/tests/scripts/utils/card-component.js +26 -0
  106. package/tests/scripts/utils/muon.config.test.json +13 -0
  107. package/tests/scripts/utils/single.component.config.json +5 -0
  108. package/tests/scripts/utils/test-runner.mjs +1 -0
  109. package/tests/scripts/utils/utils-test.mjs +284 -0
  110. package/tests/utils/validation.functions.test.js +199 -0
  111. package/tokens/theme/color.json +482 -0
  112. package/tokens/theme/font.json +61 -0
  113. package/tokens/theme/size.json +27 -0
  114. package/tokens/theme/spacer.json +73 -0
  115. package/tokens/utils/formats/reference.js +17 -0
  116. package/tokens/utils/modular-scale.js +33 -0
  117. package/tokens/utils/templates/font-face.css.template +30 -0
  118. package/tokens/utils/transforms/color.js +27 -0
  119. package/tokens/utils/transforms/string.js +6 -0
  120. package/tokens/utils/validation.json +76 -0
  121. package/utils/scroll/index.js +31 -0
  122. package/utils/validation/index.js +205 -0
  123. package/web-test-runner.browserstack.config.mjs +123 -0
  124. package/web-test-runner.config.mjs +44 -0
@@ -0,0 +1,96 @@
1
+ import { MuonElement, html, styleMap, classMap } from '@muonic/muon';
2
+ import { imageInlineLoader, imageBackgroundLoader } from '@muon/directives/image-loader-directive';
3
+ import {
4
+ IMAGE_CONFIG_TYPE,
5
+ IMAGE_CONFIG_RATIOS,
6
+ IMAGE_CONFIG_RATIO,
7
+ IMAGE_CONFIG_PLACEHOLDER
8
+ } from '@muon/tokens';
9
+
10
+ import styles from './image-styles.css';
11
+
12
+ /**
13
+ * Loading images with default lazy loading.
14
+ *
15
+ * @element image
16
+ */
17
+
18
+ export class Image extends MuonElement {
19
+
20
+ static get properties() {
21
+ return {
22
+ background: { type: Boolean },
23
+ backgroundsize: { type: String, attribute: 'background-size' },
24
+ src: { type: String },
25
+ alt: { type: String },
26
+ ratio: { type: String },
27
+ placeholder: { type: String },
28
+ loading: { type: String },
29
+ _ratios: { type: Array, state: true }
30
+ };
31
+ }
32
+
33
+ static get styles() {
34
+ return styles;
35
+ }
36
+
37
+ constructor() {
38
+ super();
39
+
40
+ this.type = IMAGE_CONFIG_TYPE;
41
+ this.background = false;
42
+ this.backgroundsize = 'cover'; // cover, contain
43
+ this.alt = '';
44
+ this.ratio = IMAGE_CONFIG_RATIO;
45
+ this.placeholder = IMAGE_CONFIG_PLACEHOLDER;
46
+ this.loading = 'lazy'; // eager|lazy
47
+ this._ratios = IMAGE_CONFIG_RATIOS;
48
+
49
+ }
50
+
51
+ get placeholderImage() {
52
+ return this.placeholder.replace('(src)', this.src); // @TODO: test alternative ways for this
53
+ }
54
+
55
+ get standardTemplate() {
56
+ const isBackground = this.background;
57
+
58
+ if (!this._ratios.includes(this.ratio)) {
59
+ this.ratio = IMAGE_CONFIG_RATIO; // @TODO: add fallback `|| this._ratios[0]`
60
+ }
61
+
62
+ if (isBackground) {
63
+ this.ratio = this.ratio?.length > 0 ? this.ratio : '16 / 9'; // without a default size background images won't show
64
+ }
65
+
66
+ const [x, y] = this.ratio.split(' / ');
67
+ const styles = {
68
+ '--image-ratio': CSS?.supports('aspect-ratio', '1 / 1') && this.ratio ? this.ratio : undefined,
69
+ '--image-padding': CSS?.supports('aspect-ratio', '1 / 1') || !x && !y ? undefined : `${y / x * 100}%`,
70
+ '--background-size': isBackground ? this.backgroundsize : undefined
71
+ };
72
+
73
+ const classes = {
74
+ image: true,
75
+ 'no-ratio': !this.ratio || this.ratio?.length < 1,
76
+ 'is-background': isBackground
77
+ };
78
+
79
+ if (this.src && this.src.length > 0) {
80
+ const imageObj = {
81
+ src: this.src,
82
+ alt: this.alt,
83
+ placeholder: this.placeholderImage,
84
+ loading: this.loading
85
+ };
86
+
87
+ return html`
88
+ <div class=${classMap(classes)} style=${styleMap(styles)}>
89
+ ${isBackground ? imageBackgroundLoader(imageObj) : imageInlineLoader(imageObj)}
90
+ </div>
91
+ `;
92
+ } else {
93
+ return html`<div class="image"></div>`;
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,71 @@
1
+ @import "@muonic/muon/css/default.css";
2
+
3
+ :host {
4
+ display: block;
5
+
6
+ &,
7
+ & .image .image-holder,
8
+ & .image .image-lazy {
9
+ display: block;
10
+ width: 100%;
11
+ overflow: hidden;
12
+ box-sizing: border-box;
13
+ min-width: 1px; /* Enforces a size to be observable */
14
+ min-height: 1px; /* Enforces a size to be observable */
15
+ }
16
+
17
+ & .image {
18
+ position: relative;
19
+ aspect-ratio: var(--image-ratio);
20
+
21
+ @supports not (aspect-ratio: 1/1) {
22
+ padding-top: var(--image-padding);
23
+ }
24
+
25
+ & .blur {
26
+ filter: blur(0.7em);
27
+ transform: scale(1.03);
28
+ transition-timing-function: ease-out;
29
+ }
30
+
31
+ & .blur-out {
32
+ animation: blur-out 0.5s ease-out;
33
+ }
34
+
35
+ & .image-holder,
36
+ & .image-lazy {
37
+ position: absolute;
38
+ top: 0;
39
+ bottom: 0;
40
+ left: 0;
41
+ right: 0;
42
+ }
43
+
44
+ &.is-background {
45
+ & .image-holder {
46
+ background-repeat: no-repeat;
47
+ background-position: center center;
48
+ background-image: var(--background-image);
49
+ background-size: var(--background-size);
50
+ }
51
+ }
52
+
53
+ &.no-ratio {
54
+ padding: 0;
55
+
56
+ & .image-lazy {
57
+ position: static;
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ @keyframes blur-out {
64
+ 0% {
65
+ filter: blur(0.7em);
66
+ }
67
+
68
+ 100% {
69
+ filter: blur(0);
70
+ }
71
+ }
@@ -0,0 +1,31 @@
1
+ import { Image } from '@muonic/muon/components/image';
2
+ import setup from '@muonic/muon/storybook/stories';
3
+ import { IMAGE_CONFIG_RATIOS } from '@muonic/muon/build/tokens/es6/muon-tokens.mjs';
4
+
5
+ const details = setup('image', Image);
6
+
7
+ export default {
8
+ ...details.defaultValues,
9
+ parameters: {
10
+ controls: {
11
+ exclude: ['standardTemplate', 'placeholderImage']
12
+ }
13
+ },
14
+ argTypes: {
15
+ ...details.defaultValues.argTypes,
16
+ ratio: {
17
+ options: IMAGE_CONFIG_RATIOS,
18
+ control: {
19
+ type: 'inline-radio'
20
+ }
21
+ }
22
+ }
23
+ };
24
+
25
+ const StandardTemplate = (args) => details.template(args, (args) => args.text);
26
+
27
+ export const Standard = StandardTemplate.bind({});
28
+ Standard.args = { src: 'https://blog.nucleus.design/vanilla-first/vanilla-ice-cream-cone.jpg', placeholder: '(src).thumb.48.48.png' };
29
+
30
+ export const Background = StandardTemplate.bind({});
31
+ Background.args = { src: 'https://blog.nucleus.design/multi-branding/Multibrand.jpg', placeholder: '(src).thumb.48.48.png', background: true };
@@ -0,0 +1 @@
1
+ export { Inputter } from './src/inputter-component';
@@ -0,0 +1,14 @@
1
+ {
2
+ "inputter": {
3
+ "config": {
4
+ "type": {
5
+ "description": "Default value for `type` property which renders the template.",
6
+ "value": "standard",
7
+ "type": "string"
8
+ },
9
+ "disabled": {
10
+ "value": true
11
+ }
12
+ }
13
+ }
14
+ }
@@ -0,0 +1,308 @@
1
+ {
2
+ "inputter": {
3
+ "field": {
4
+ "color": {
5
+ "description": "Text color for the field. Inherits the theme's text dark color.",
6
+ "value": "{ theme.color.text.dark.value }"
7
+ },
8
+ "background": {
9
+ "color": {
10
+ "description": "Background color for the field. Inherits the theme's base background color.",
11
+ "value": "{ theme.color.base.background.value }"
12
+ }
13
+ },
14
+ "font": {
15
+ "family": {
16
+ "description": "Font family used for field. Inherits the theme's default font.",
17
+ "value": "{ theme.font.family.default.value }"
18
+ },
19
+ "size": {
20
+ "description": "Font size used for field.",
21
+ "value": "{ theme.font.size.default.value }"
22
+ }
23
+ },
24
+ "padding": {
25
+ "block": {
26
+ "description": "Padding space above and below the field text. Equal values in the block axis.",
27
+ "value": "{ theme.spacer.sm.value }"
28
+ },
29
+ "inline": {
30
+ "description": "Padding space left and right of the field text. Equal values in the inline axis.",
31
+ "value": "{ inputter.field.padding.block.value }"
32
+ }
33
+ },
34
+ "margin": {
35
+ "block": {
36
+ "description": "Margin space between the label and the field.",
37
+ "value": "{ theme.spacer.sm.value }"
38
+ }
39
+ },
40
+ "border": {
41
+ "color": {
42
+ "description": "Border color of the field.",
43
+ "value": "{ inputter.field.color.value }"
44
+ }
45
+ },
46
+ "icon": {
47
+ "size": {
48
+ "description": "Size of the icon used within the field.",
49
+ "value": "{ theme.size.sm.value }"
50
+ },
51
+ "spacer": {
52
+ "description": "Padding space used if an icon exists at the start or end of the field.",
53
+ "value": "calc({ inputter.field.padding.block.value } + { inputter.field.icon.size.value } + { inputter.field.padding.block.value })"
54
+ }
55
+ },
56
+ "date": {
57
+ "icon": {
58
+ "description": "Icon used to open a calendar from the field.",
59
+ "value": "calendar"
60
+ }
61
+ },
62
+ "select": {
63
+ "icon": {
64
+ "description": "Icon used to open a drop-down selection from the field.",
65
+ "value": "chevron-circle-down"
66
+ }
67
+ },
68
+ "search": {
69
+ "icon": {
70
+ "description": "Icon used to indicate that a search term is expected to be entered in the field.",
71
+ "value": "search"
72
+ }
73
+ }
74
+ },
75
+ "multiple": {
76
+ "background": {
77
+ "color": {
78
+ "description": "Background color for radio button and checkbox.",
79
+ "value": "{ inputter.field.background.color.value }"
80
+ }
81
+ },
82
+ "gap": {
83
+ "description": "Gap between radio button, checkbox and their label.",
84
+ "value": "0.5em"
85
+ },
86
+ "size": {
87
+ "description": "Size of the radio button and checkbox. Use an `em` unit to scale with label.",
88
+ "value": "1em"
89
+ },
90
+ "border": {
91
+ "color": {
92
+ "description": "Border color for the radio button and checkbox.",
93
+ "value": "{ inputter.field.color.value }"
94
+ }
95
+ }
96
+ },
97
+ "label": {
98
+ "color": {
99
+ "description": "Label text color of field.",
100
+ "value": "{ inputter.field.color.value }"
101
+ }
102
+ },
103
+ "placeholder": {
104
+ "color": {
105
+ "description": "Placeholder text color of the inputter.",
106
+ "value": "{ theme.color.placeholder.value }"
107
+ }
108
+ },
109
+ "mask": {
110
+ "__private_color": {
111
+ "value": "{ theme.color.darkest.value }",
112
+ "modify": [{
113
+ "type": "brighten",
114
+ "amount": 2.75
115
+ }]
116
+ },
117
+ "color": {
118
+ "description": "Text color for the mask of the inputter. Defaults to brightened version of the darkest color.",
119
+ "value": "{ inputter.mask.__private_color.value }"
120
+ },
121
+ "font": {
122
+ "family": {
123
+ "description": "Font family used for a masked inputter. Defaults to monospaced Courier New or Courier.",
124
+ "value": "Courier New, Courier, { theme.font.family.monospace.value }"
125
+ },
126
+ "weight": {
127
+ "description": "Weight of the font used for a masked inputter.",
128
+ "value": "{ theme.font.weight.heading.value }"
129
+ }
130
+ }
131
+ },
132
+ "hover": {
133
+ "__private_color": {
134
+ "value": "{ inputter.field.color.value }",
135
+ "modify": [{
136
+ "type": "darken",
137
+ "amount": 1.5
138
+ }]
139
+ },
140
+ "color": {
141
+ "description": "Color of the field on `hover` state. Defaults to a darkened version of the color.",
142
+ "value": "{ inputter.hover.__private_color.value }"
143
+ },
144
+ "border": {
145
+ "color": {
146
+ "description": "Border color of the field on `hover` state.",
147
+ "value": "{ inputter.hover.color.value }"
148
+ }
149
+ }
150
+ },
151
+ "focus": {
152
+ "color": {
153
+ "description": "Color of the field on `focus` state.",
154
+ "value": "{ inputter.hover.color.value }"
155
+ },
156
+ "border": {
157
+ "color": {
158
+ "description": "Border color of the field on `focus` state.",
159
+ "value": "{ inputter.focus.color.value }"
160
+ }
161
+ },
162
+ "outline": {
163
+ "color": {
164
+ "description": "Outline color for `keyboard focus` state. Defaults to theme's focus color.",
165
+ "value": "{ theme.color.focus.value }"
166
+ }
167
+ }
168
+ },
169
+ "disabled": {
170
+ "color": {
171
+ "description": "Disabled text color. Defaults to theme's disabled color.",
172
+ "value": "{ theme.color.disabled.value }"
173
+ },
174
+ "border": {
175
+ "color": {
176
+ "description": "Disabled border color. Defaults to theme's disabled color.",
177
+ "value": "{ inputter.disabled.color.value }"
178
+ }
179
+ },
180
+ "background": {
181
+ "__private_color": {
182
+ "value": "{ inputter.disabled.color.value }",
183
+ "modify": [{
184
+ "type": "brighten",
185
+ "amount": 1
186
+ }]
187
+ },
188
+ "color": {
189
+ "description": "Disabled background color. Defaults to a brightened version of theme's disabled color.",
190
+ "value": "{ inputter.disabled.background.__private_color.value }"
191
+ }
192
+ },
193
+ "placeholder": {
194
+ "color": {
195
+ "description": "Disabled placeholder color. Defaults to theme's disabled color.",
196
+ "value": "{ inputter.disabled.color.value }"
197
+ }
198
+ }
199
+ },
200
+ "validation": {
201
+ "margin": {
202
+ "block": {
203
+ "description": "Margin space above and below the validation message. Equal values in the block axis.",
204
+ "value": "{ theme.spacer.sm.value }"
205
+ }
206
+ },
207
+ "gap": {
208
+ "description": "Gap between the validation message and icon.",
209
+ "value": "{ theme.spacer.sm.value }"
210
+ },
211
+ "icon": {
212
+ "size": {
213
+ "description": "Icon size for the validation.",
214
+ "value": "{ theme.size.sm.value }"
215
+ }
216
+ },
217
+ "warning": {
218
+ "color": {
219
+ "description": "Color indicative of a validation warning.",
220
+ "value": "{ theme.color.warning.@.value }"
221
+ },
222
+ "icon": {
223
+ "description": "Icon indicative of a validation warning.",
224
+ "value": "exclamation-circle"
225
+ }
226
+ }
227
+ },
228
+ "detail": {
229
+ "color": {
230
+ "description": "Text color for the detail.",
231
+ "value": "{ inputter.field.color.value }"
232
+ },
233
+ "hover": {
234
+ "color": {
235
+ "description": "Text color for the `hover` state of the detail.",
236
+ "value": "{ inputter.hover.color.value }"
237
+ }
238
+ },
239
+ "heading": {
240
+ "margin": {
241
+ "block": {
242
+ "description": "Margin space between the detail heading and the field.",
243
+ "value": "{ theme.spacer.sm.value }"
244
+ }
245
+ },
246
+ "gap": {
247
+ "description": "Gap between the detail icon and heading.",
248
+ "value": "{ theme.spacer.sm.value }"
249
+ }
250
+ },
251
+ "content": {
252
+ "margin": {
253
+ "block": {
254
+ "description": "Margin space between the detail's heading and content.",
255
+ "value": "{ theme.spacer.sm.value }"
256
+ }
257
+ },
258
+ "padding": {
259
+ "inline": {
260
+ "description": "Padding space at the start of the detail's content.",
261
+ "value": "{ theme.spacer.sm.value }"
262
+ }
263
+ }
264
+ },
265
+ "icon": {
266
+ "size": {
267
+ "description": "Size of the icon used within the detail.",
268
+ "value": "{ theme.size.sm.value }"
269
+ }
270
+ },
271
+ "toggle": {
272
+ "open": {
273
+ "description": "Icon used to open the detail's content.",
274
+ "value": "chevron-circle-down"
275
+ },
276
+ "close": {
277
+ "description": "Icon used to close the detail's content.",
278
+ "value": "chevron-circle-up"
279
+ },
280
+ "position": {
281
+ "description": "Position of the detail's toggle icon. Valid values: `start`, `end`.",
282
+ "value": "start"
283
+ }
284
+ },
285
+ "focus": {
286
+ "outline": {
287
+ "color": {
288
+ "description": "Outline color of the detail on `keyboard focus` state.",
289
+ "value": "{ inputter.focus.outline.color.value }"
290
+ }
291
+ }
292
+ },
293
+ "border": {
294
+ "__private_color": {
295
+ "value": "{ inputter.field.color.value }",
296
+ "modify": [{
297
+ "type": "brighten",
298
+ "amount": 3
299
+ }]
300
+ },
301
+ "color": {
302
+ "description": "Border color of the detail. Defaults to a brightened version of the field color.",
303
+ "value": "{ inputter.detail.border.__private_color.value }"
304
+ }
305
+ }
306
+ }
307
+ }
308
+ }