@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,83 @@
1
+ @import "@muonic/muon/css/default.css";
2
+
3
+ :host {
4
+ display: block;
5
+
6
+ & summary {
7
+ &::-webkit-details-marker {
8
+ display: none;
9
+ }
10
+ }
11
+
12
+ & .heading {
13
+ display: flex;
14
+ align-items: center;
15
+ column-gap: $DETAIL_HEADING_GAP;
16
+ padding-block-start: $DETAIL_HEADING_PADDING_BLOCK;
17
+ padding-block-end: $DETAIL_HEADING_PADDING_BLOCK;
18
+ padding-inline-start: $DETAIL_HEADING_PADDING_INLINE;
19
+ padding-inline-end: $DETAIL_HEADING_PADDING_INLINE;
20
+ background-color: $DETAIL_HEADING_BACKGROUND_COLOR;
21
+ color: $DETAIL_HEADING_COLOR;
22
+ cursor: pointer;
23
+ font-size: 21px;
24
+
25
+ &:hover {
26
+ background-color: $DETAIL_HEADING_HOVER_BACKGROUND_COLOR;
27
+ color: $DETAIL_HEADING_HOVER_COLOR;
28
+ text-decoration: underline;
29
+ }
30
+
31
+ & :focus:not(:focus-visible) {
32
+ /*
33
+ https://matthiasott.com/notes/focus-visible-is-here and
34
+ https://www.tpgi.com/focus-visible-and-backwards-compatibility/
35
+ */
36
+ outline-style: none;
37
+ }
38
+
39
+ &:focus-visible {
40
+ background-color: $DETAIL_HEADING_FOCUS_BACKGROUND_COLOR;
41
+ color: $DETAIL_HEADING_FOCUS_COLOR;
42
+ outline-color: $DETAIL_HEADING_FOCUS_OUTLINE_COLOR;
43
+ outline-style: solid;
44
+ outline-width: 3px;
45
+ outline-offset: 0;
46
+ text-decoration: underline;
47
+ }
48
+ }
49
+
50
+ & .content {
51
+ color: $DETAIL_CONTENT_COLOR;
52
+ padding-block-start: $DETAIL_CONTENT_PADDING_BLOCK;
53
+ padding-block-end: $DETAIL_CONTENT_PADDING_BLOCK;
54
+ padding-inline-start: $DETAIL_CONTENT_PADDING_INLINE;
55
+ padding-inline-end: $DETAIL_CONTENT_PADDING_INLINE;
56
+ }
57
+
58
+ & .has-icon,
59
+ & .toggle-start {
60
+ & .content {
61
+ padding-inline-start: $DETAIL_CONTENT_ICON_SPACER;
62
+ }
63
+ }
64
+
65
+ & .toggle,
66
+ & .icon {
67
+ width: $DETAIL_TOGGLE_ICON_SIZE;
68
+ height: $DETAIL_TOGGLE_ICON_SIZE;
69
+ flex-shrink: 0;
70
+ }
71
+
72
+ & .toggle-start {
73
+ & .icon {
74
+ margin-inline-start: auto; /* this aligns the icon to the opposite end */
75
+ }
76
+ }
77
+
78
+ & .toggle-end {
79
+ & .toggle {
80
+ margin-inline-start: auto; /* this aligns the toggle to the opposite end */
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,33 @@
1
+ import { Detail } from '@muonic/muon/components/detail';
2
+ import setup from '@muonic/muon/storybook/stories';
3
+ import { staticHTML, unsafeStatic } from '@muonic/muon';
4
+
5
+ const details = setup('detail', Detail);
6
+
7
+ export default {
8
+ ...details.defaultValues,
9
+ parameters: {
10
+ controls: {
11
+ exclude: ['standardTemplate']
12
+ }
13
+ }
14
+ };
15
+
16
+ const innerDetail = (args) => staticHTML`
17
+ <div slot="heading">${unsafeStatic(args.heading)}</div>
18
+ ${unsafeStatic(args.content)}
19
+ `;
20
+
21
+ const StandardTemplate = (args) => details.template(args, innerDetail);
22
+ export const Standard = StandardTemplate.bind({});
23
+ Standard.args = {
24
+ heading: 'Where can I buy an ice cream?',
25
+ content: 'We have the most wonderful shop just in town, that sells a whole variety of different ice creams. Just pop on in and we can get you sorted with your favourite flavour!'
26
+ };
27
+
28
+ export const WithIcon = StandardTemplate.bind({});
29
+ WithIcon.args = {
30
+ icon: 'dot-circle',
31
+ heading: 'Where can I buy an ice cream?',
32
+ content: 'We have the most wonderful shop just in town, that sells a whole variety of different ice creams. Just pop on in and we can get you sorted with your favourite flavour!'
33
+ };
@@ -0,0 +1 @@
1
+ export { Form } from './src/form-component.js';
@@ -0,0 +1,11 @@
1
+ {
2
+ "form": {
3
+ "config": {
4
+ "type": {
5
+ "description": "Default value for `type` property which renders the template.",
6
+ "value": "standard",
7
+ "type": "string"
8
+ }
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "form": {
3
+ "row": {
4
+ "gap": {
5
+ "value": "{ theme.spacer.lg.value }"
6
+ }
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,197 @@
1
+ import { html, MuonElement, css, unsafeCSS } from '@muonic/muon';
2
+ import scrollTo from '@muon/utils/scroll';
3
+ import styles from './form-styles.css';
4
+
5
+ /**
6
+ * A form.
7
+ *
8
+ * @element form
9
+ */
10
+
11
+ export class Form extends MuonElement {
12
+
13
+ constructor() {
14
+ super();
15
+ this._submit = this._submit.bind(this);
16
+ this._reset = this._reset.bind(this);
17
+ }
18
+
19
+ static get styles() {
20
+ return css`${unsafeCSS(styles)}`;
21
+ }
22
+
23
+ connectedCallback() {
24
+ super.connectedCallback();
25
+
26
+ queueMicrotask(() => {
27
+ this.__checkForFormEl();
28
+ if (this._nativeForm) {
29
+ this.__registerEvents();
30
+ // hack to stop browser validation pop up
31
+ this._nativeForm.setAttribute('novalidate', true);
32
+ // hack to force implicit submission (https://github.com/WICG/webcomponents/issues/187)
33
+ const input = document.createElement('input');
34
+ input.type = 'submit';
35
+ input.hidden = true;
36
+ this._nativeForm.appendChild(input);
37
+ }
38
+ });
39
+ }
40
+
41
+ disconnectedCallback() {
42
+ super.disconnectedCallback();
43
+ this.__teardownEvents();
44
+ }
45
+
46
+ __registerEvents() {
47
+ this._nativeForm?.addEventListener('submit', this._submit);
48
+ this._submitButton?.addEventListener('click', this._submit);
49
+ this._nativeForm?.addEventListener('reset', this._reset);
50
+ this._resetButton?.addEventListener('click', this._reset);
51
+ }
52
+
53
+ __teardownEvents() {
54
+ this._nativeForm?.removeEventListener('submit', this._submit);
55
+ this._submitButton?.removeEventListener('click', this._submit);
56
+ this._nativeForm?.removeEventListener('reset', this._reset);
57
+ this._resetButton?.removeEventListener('click', this._reset);
58
+ }
59
+
60
+ __checkForFormEl() {
61
+ if (!this._nativeForm) {
62
+ throw new Error(
63
+ 'No form node found. Did you put a <form> element inside?'
64
+ );
65
+ }
66
+ }
67
+
68
+ _reset() {
69
+ this.__checkForFormEl();
70
+
71
+ if (
72
+ !this._resetButton.disabled ||
73
+ !this._resetButton.loading
74
+ ) {
75
+ this._nativeForm.reset();
76
+ Array.from(this._nativeForm.elements).forEach((element) => {
77
+ const componentElement = this._findInputElement(element);
78
+ if (componentElement !== element) {
79
+ componentElement.reset?.();
80
+ }
81
+ });
82
+ }
83
+ }
84
+
85
+ _submit(event) {
86
+ event.preventDefault();
87
+ event.stopPropagation();
88
+
89
+ this.__checkForFormEl();
90
+
91
+ if (
92
+ !this._submitButton ||
93
+ this._submitButton.disabled ||
94
+ this._submitButton.loading
95
+ ) {
96
+ return undefined; // should this be false?
97
+ }
98
+
99
+ const validity = this.validate();
100
+
101
+ if (validity.isValid) {
102
+ this.dispatchEvent(new Event('submit', { cancelable: true }));
103
+ } else {
104
+ const invalidElements = validity.validationStates.filter((state) => {
105
+ return !state.isValid;
106
+ });
107
+
108
+ scrollTo({ element: invalidElements[0].formElement });
109
+ }
110
+
111
+ return validity.isValid;
112
+ }
113
+
114
+ get _nativeForm() {
115
+ return this.querySelector('form');
116
+ }
117
+
118
+ get _submitButton() {
119
+ return this.querySelector('button:not([hidden])[type="submit"]') ||
120
+ this.querySelector('input:not([hidden])[type="submit"]') ||
121
+ this.querySelector('*:not([hidden])[type="submit"]');
122
+ }
123
+
124
+ get _resetButton() {
125
+ return this.querySelector('button:not([hidden])[type="reset"]') ||
126
+ this.querySelector('input:not([hidden])[type="reset"]') ||
127
+ this.querySelector('*:not([hidden])[type="reset"]');
128
+ }
129
+
130
+ _findInputElement(element) {
131
+ if (element.parentElement._inputElement) {
132
+ return element.parentElement;
133
+ }
134
+ // Due to any layout container elements - @TODO - need better logic
135
+ if (element.parentElement.parentElement._inputElement) {
136
+ return element.parentElement.parentElement;
137
+ }
138
+
139
+ return element;
140
+ }
141
+
142
+ validate() {
143
+ let isValid = true;
144
+ // @TODO: Check how this works with form associated
145
+ const validationStates = Array.from(this._nativeForm.elements).reduce((acc, element) => {
146
+ element = this._findInputElement(element);
147
+ const { name } = element;
148
+ const hasBeenSet = acc.filter((el) => el.name === name).length > 0;
149
+
150
+ // For checkboxes and radio button - don't set multiple times (needs checking for native inputs)
151
+ // Ignore buttons (including hidden reset)
152
+ if (
153
+ hasBeenSet ||
154
+ element === this._submitButton ||
155
+ element === this._resetButton ||
156
+ element.type === 'submit'
157
+ ) {
158
+ return acc;
159
+ }
160
+
161
+ if (element.reportValidity) {
162
+ element.reportValidity();
163
+ }
164
+
165
+ const { validity } = element;
166
+
167
+ if (validity) {
168
+ const { value } = element;
169
+ const { valid, validationMessage } = validity;
170
+
171
+ isValid = Boolean(isValid & validity.valid);
172
+
173
+ acc.push({
174
+ name,
175
+ value,
176
+ isValid: valid,
177
+ error: validationMessage,
178
+ validity: validity,
179
+ formElement: element
180
+ });
181
+ }
182
+
183
+ return acc;
184
+ }, []);
185
+
186
+ return {
187
+ isValid,
188
+ validationStates
189
+ };
190
+ }
191
+
192
+ get standardTemplate() {
193
+ return html`
194
+ <slot></slot>
195
+ `;
196
+ }
197
+ }
@@ -0,0 +1,10 @@
1
+ @import "@muonic/muon/css/default.css";
2
+
3
+ :host {
4
+ display: block;
5
+
6
+ & ::slotted(.layout-row) {
7
+ display: grid;
8
+ row-gap: $FORM_ROW_GAP;
9
+ }
10
+ }
@@ -0,0 +1,71 @@
1
+ import { Form } from '@muonic/muon/components/form';
2
+ import setup from '@muonic/muon/storybook/stories';
3
+ import * as InputterStories from '../inputter/story';
4
+ import { Standard as SubmitCTA } from '../cta/story';
5
+ import { staticHTML } from '@muonic/muon';
6
+
7
+ const details = setup('form', Form);
8
+
9
+ export default {
10
+ ...details.defaultValues,
11
+ parameters: {
12
+ controls: {
13
+ exclude: ['standardTemplate', 'submit']
14
+ }
15
+ }
16
+ };
17
+
18
+ const innerDetail = (args) => staticHTML`
19
+ <form>
20
+ ${InputterStories.Select(args.Title)}
21
+ ${InputterStories.Text(args.Text)}
22
+ ${InputterStories.Email(args.Email)}
23
+
24
+ <label for="user-id">User ID</label>
25
+ <input type="text" id="user-id" name="user-id" required/>
26
+
27
+ ${InputterStories.DateMask(args.DOB)}
28
+
29
+ ${InputterStories.Checkbox(args.Checkbox)}
30
+
31
+ <input type="reset" />
32
+ ${SubmitCTA(args.Submit)}
33
+ <form>`;
34
+
35
+ export const Standard = (args) => details.template(args, innerDetail);
36
+ Standard.args = {
37
+ Title: {
38
+ ...InputterStories.Select.args,
39
+ name: 'title',
40
+ label: 'Title'
41
+ },
42
+ Text: {
43
+ ...InputterStories.Text.args,
44
+ name: 'username',
45
+ label: 'Name',
46
+ value: 'text'
47
+ },
48
+ Email: {
49
+ ...InputterStories.Email.args,
50
+ name: 'useremail'
51
+ },
52
+ Checkbox: {
53
+ ...InputterStories.Checkbox.args,
54
+ value: 'b',
55
+ options: [
56
+ { label: 'Option A', value: 'a' },
57
+ { label: 'Option B', value: 'b' }
58
+ ]
59
+ },
60
+ DOB: {
61
+ ...InputterStories.DateMask.args,
62
+ name: 'dob',
63
+ label: 'Date of birth',
64
+ validation: ['maxDate(\'031/12/2022\')']
65
+ },
66
+ Submit: {
67
+ ...SubmitCTA.args,
68
+ type: 'submit',
69
+ text: 'Submit'
70
+ }
71
+ };
@@ -0,0 +1 @@
1
+ export { Icon } from './src/icon-component';
@@ -0,0 +1,31 @@
1
+ {
2
+ "icon": {
3
+ "config": {
4
+ "type": {
5
+ "description": "Default value for `type` property which renders the template",
6
+ "value": "standard",
7
+ "type": "string"
8
+ },
9
+ "name": {
10
+ "description": "Default value for `name` property to load the icon. (name) required in URL token to load specific icon",
11
+ "value": "arrow-right",
12
+ "type": "string"
13
+ },
14
+ "category": {
15
+ "description": "Optional default value for category in URL. (category) required in URL token",
16
+ "value": "",
17
+ "type": "string"
18
+ },
19
+ "sizes": {
20
+ "description": "Array of set values for available icon sizes in px",
21
+ "value": [16, 32, 48, 64, 72],
22
+ "type": "array"
23
+ },
24
+ "url": {
25
+ "description": "CDN URL to fetch icons. (name) and (category) to replace in URL to get specific icon",
26
+ "value": "https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.1/svgs/solid/(name).svg",
27
+ "type": "string"
28
+ }
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "icon": {
3
+ "fill": {
4
+ "description": "CSS fill value for the icon SVG",
5
+ "value": "{ theme.color.current.value }"
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,91 @@
1
+ import { MuonElement, html, ifDefined, classMap, styleMap } from '@muonic/muon';
2
+ import { svgLoader } from '@muon/directives/svg-loader-directive';
3
+ import {
4
+ ICON_CONFIG_TYPE,
5
+ ICON_CONFIG_NAME,
6
+ ICON_CONFIG_CATEGORY,
7
+ ICON_CONFIG_SIZES,
8
+ ICON_CONFIG_URL
9
+ } from '@muon/tokens';
10
+
11
+ import styles from './icon-styles.css';
12
+
13
+ /**
14
+ * Icons are visual symbols that are used to represent objects or actions to reduce cognitive load to a user.
15
+ *
16
+ * @element icon
17
+ */
18
+
19
+ export class Icon extends MuonElement {
20
+
21
+ static get properties() {
22
+ return {
23
+ name: { type: String, attribute: true },
24
+ describe: { type: String },
25
+ size: { type: Number },
26
+ category: { type: String },
27
+ url: { type: String, state: true }
28
+ };
29
+ }
30
+
31
+ static get styles() {
32
+ return styles;
33
+ }
34
+
35
+ constructor() {
36
+ super();
37
+
38
+ this.type = ICON_CONFIG_TYPE;
39
+ this.name = ICON_CONFIG_NAME;
40
+ this.category = ICON_CONFIG_CATEGORY;
41
+ this.allSizes = ICON_CONFIG_SIZES;
42
+ this.url = ICON_CONFIG_URL;
43
+ this.describe = '';
44
+ }
45
+
46
+ /**
47
+ * A getter method to get size of image.
48
+ *
49
+ * @returns {number | string} - Size at specific index or 100%.
50
+ * @readonly
51
+ */
52
+ get sizes() {
53
+ const size = this.size - 1;
54
+
55
+ return this.allSizes[size] || '100%';
56
+ }
57
+
58
+ get iconSize() {
59
+ const computedSize = this.sizes;
60
+ const size = computedSize === '100%' ? computedSize : `${computedSize}px`;
61
+
62
+ return size;
63
+ }
64
+
65
+ get standardTemplate() {
66
+ const hidden = this.describe?.length === 0 ? 'true' : undefined;
67
+ const role = !hidden ? 'img' : undefined;
68
+ const classes = {
69
+ icon: true,
70
+ [this.type]: true
71
+ };
72
+
73
+ const styles = {
74
+ '--icon-size': this.iconSize
75
+ };
76
+
77
+ return html`
78
+ <div aria-hidden=${ifDefined(hidden)} role=${ifDefined(role)} aria-label=${ifDefined(role && this.describe)} class=${classMap(classes)} style=${styleMap(styles)}>
79
+ ${svgLoader({ name: this.name, category: this.category, path: this.url })}
80
+ </div>
81
+ `;
82
+ }
83
+
84
+ render() {
85
+ if (!this.name?.length > 0) {
86
+ return undefined;
87
+ }
88
+
89
+ return super.render();
90
+ }
91
+ }
@@ -0,0 +1,26 @@
1
+ @import "@muonic/muon/css/default.css";
2
+
3
+ :host {
4
+ display: inline-block;
5
+ min-width: 10px; /* to give a minimum size to be observable */
6
+ min-height: 10px; /* to give a minimum size to be observable */
7
+
8
+ &,
9
+ & svg,
10
+ & .icon {
11
+ width: var(--icon-size, 100%);
12
+ height: var(--icon-size, 100%);
13
+ }
14
+
15
+ & svg {
16
+ display: block;
17
+ fill: $ICON_FILL;
18
+ }
19
+
20
+ @media (-ms-high-contrast: active), (forced-colors: active) {
21
+ & svg {
22
+ forced-color-adjust: none;
23
+ fill: canvastext;
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,26 @@
1
+ import { Icon } from '@muonic/muon/components/icon';
2
+ import setup from '@muonic/muon/storybook/stories';
3
+ import {
4
+ ICON_CONFIG_SIZES
5
+ } from '@muonic/muon/build/tokens/es6/muon-tokens.mjs';
6
+
7
+ const details = setup('icon', Icon);
8
+
9
+ export default {
10
+ ...details.defaultValues,
11
+ parameters: {
12
+ controls: {
13
+ exclude: ['standardTemplate', 'sizes', 'iconSize', 'allSizes']
14
+ }
15
+ },
16
+ argTypes: {
17
+ ...details.defaultValues.argTypes,
18
+ size: {
19
+ control:
20
+ { type: 'range', min: 1, max: ICON_CONFIG_SIZES.length, step: 1 }
21
+ }
22
+ }
23
+ };
24
+
25
+ export const Standard = (args) => details.template(args);
26
+ Standard.args = { name: 'arrow-right' };
@@ -0,0 +1 @@
1
+ export { Image } from './src/image-component';
@@ -0,0 +1,26 @@
1
+ {
2
+ "image": {
3
+ "config": {
4
+ "type": {
5
+ "description": "Default value for `type` property which renders the template",
6
+ "value": "standard",
7
+ "type": "string"
8
+ },
9
+ "ratios": {
10
+ "description": "Default value for `ratios` available for ratio",
11
+ "value": ["1 / 1", "4 / 3", "16 / 9"],
12
+ "type": "array"
13
+ },
14
+ "ratio": {
15
+ "description": "Default value for `ratio` property which decides the ratio size for the image",
16
+ "value": "16 / 9",
17
+ "type": "string"
18
+ },
19
+ "placeholder": {
20
+ "description": "Default value for `placeholder` property which creates the thumbnail placeholder image. (src) can be used to bring in the src property",
21
+ "value": "",
22
+ "type": "string"
23
+ }
24
+ }
25
+ }
26
+ }