@govtechsg/sgds-web-component 0.0.8 → 0.0.10

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 (263) hide show
  1. package/.github/workflows/publish-latest.yml +22 -0
  2. package/.github/workflows/publish-pr.yml +28 -0
  3. package/.husky/commit-msg +4 -0
  4. package/.husky/prepare-commit-msg +8 -0
  5. package/.storybook/main.js +16 -0
  6. package/.storybook/preview-head.html +11 -0
  7. package/.storybook/preview.js +9 -0
  8. package/.vscode/settings.json +7 -0
  9. package/CONTRIBUTING.md +56 -0
  10. package/LICENSE +20 -0
  11. package/amplify.yml +22 -0
  12. package/commitlint.config.js +1 -0
  13. package/coverage/lcov-report/base.css +224 -0
  14. package/coverage/lcov-report/block-navigation.js +87 -0
  15. package/coverage/lcov-report/button-element.scss.html +112 -0
  16. package/coverage/lcov-report/button-element.ts.html +145 -0
  17. package/coverage/lcov-report/favicon.png +0 -0
  18. package/coverage/lcov-report/index.html +116 -0
  19. package/coverage/lcov-report/prettify.css +1 -0
  20. package/coverage/lcov-report/prettify.js +2 -0
  21. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  22. package/coverage/lcov-report/sorter.js +196 -0
  23. package/coverage/lcov.info +32 -0
  24. package/index.html +430 -0
  25. package/{Button → lib/Button}/index.d.ts +0 -0
  26. package/{Button → lib/Button}/index.js +304 -39
  27. package/lib/Button/index.js.map +1 -0
  28. package/{Button → lib/Button}/package.json +0 -0
  29. package/lib/Button/sgds-button.d.ts +48 -0
  30. package/lib/Card/index.d.ts +1 -0
  31. package/lib/Card/index.js +6150 -0
  32. package/lib/Card/index.js.map +1 -0
  33. package/lib/Card/package.json +7 -0
  34. package/lib/Card/sgds-action-card.d.ts +20 -0
  35. package/lib/Checkbox/index.d.ts +1 -0
  36. package/lib/Checkbox/index.js +6366 -0
  37. package/lib/Checkbox/index.js.map +1 -0
  38. package/lib/Checkbox/package.json +7 -0
  39. package/lib/Checkbox/sgds-checkbox.d.ts +36 -0
  40. package/lib/Dropdown/index.d.ts +3 -0
  41. package/{Mainnav → lib/Dropdown}/index.js +2785 -9262
  42. package/lib/Dropdown/index.js.map +1 -0
  43. package/lib/Dropdown/package.json +7 -0
  44. package/lib/Dropdown/sgds-dropdown-item.d.ts +7 -0
  45. package/lib/Dropdown/sgds-dropdown.d.ts +7 -0
  46. package/{Footer → lib/Footer}/index.d.ts +0 -0
  47. package/{Footer → lib/Footer}/index.js +111 -95
  48. package/lib/Footer/index.js.map +1 -0
  49. package/{Footer → lib/Footer}/package.json +0 -0
  50. package/{Footer → lib/Footer}/sgds-footer.d.ts +2 -2
  51. package/lib/Input/index.d.ts +1 -0
  52. package/lib/Input/index.js +6656 -0
  53. package/lib/Input/index.js.map +1 -0
  54. package/lib/Input/package.json +7 -0
  55. package/lib/Input/sgds-input.d.ts +42 -0
  56. package/{Mainnav → lib/Mainnav}/index.d.ts +1 -0
  57. package/{index.js → lib/Mainnav/index.js} +3870 -23414
  58. package/lib/Mainnav/index.js.map +1 -0
  59. package/{Mainnav → lib/Mainnav}/package.json +0 -0
  60. package/lib/Mainnav/sgds-mainnav-dropdown.d.ts +5 -0
  61. package/lib/Mainnav/sgds-mainnav-item.d.ts +4 -0
  62. package/{Mainnav → lib/Mainnav}/sgds-mainnav.d.ts +2 -2
  63. package/{Masthead → lib/Masthead}/index.d.ts +0 -0
  64. package/{Masthead → lib/Masthead}/index.js +140 -114
  65. package/lib/Masthead/index.js.map +1 -0
  66. package/{Masthead → lib/Masthead}/package.json +0 -0
  67. package/{Masthead → lib/Masthead}/sgds-masthead.d.ts +1 -1
  68. package/lib/Modal/index.d.ts +1 -0
  69. package/lib/Modal/index.js +6432 -0
  70. package/lib/Modal/index.js.map +1 -0
  71. package/lib/Modal/package.json +7 -0
  72. package/lib/Modal/sgds-modal.d.ts +28 -0
  73. package/lib/QuantityToggle/index.d.ts +1 -0
  74. package/lib/QuantityToggle/index.js +7049 -0
  75. package/lib/QuantityToggle/index.js.map +1 -0
  76. package/lib/QuantityToggle/package.json +7 -0
  77. package/lib/QuantityToggle/sgds-quantitytoggle.d.ts +30 -0
  78. package/lib/Radio/index.d.ts +2 -0
  79. package/lib/Radio/index.js +12607 -0
  80. package/lib/Radio/index.js.map +1 -0
  81. package/lib/Radio/package.json +7 -0
  82. package/lib/Radio/sgds-radio.d.ts +31 -0
  83. package/lib/Radio/sgds-radiogroup.d.ts +41 -0
  84. package/{Sidenav → lib/Sidenav}/index.d.ts +0 -0
  85. package/{Sidenav → lib/Sidenav}/index.js +2266 -2171
  86. package/lib/Sidenav/index.js.map +1 -0
  87. package/{Sidenav → lib/Sidenav}/package.json +0 -0
  88. package/{Sidenav → lib/Sidenav}/sgds-sidenav-item.d.ts +2 -1
  89. package/lib/Sidenav/sgds-sidenav-link.d.ts +4 -0
  90. package/{Sidenav → lib/Sidenav}/sgds-sidenav.d.ts +1 -1
  91. package/lib/Tab/index.d.ts +3 -0
  92. package/lib/Tab/index.js +13557 -0
  93. package/lib/Tab/index.js.map +1 -0
  94. package/lib/Tab/package.json +7 -0
  95. package/lib/Tab/sgds-tab.d.ts +26 -0
  96. package/lib/Tab/sgds-tabgroup.d.ts +47 -0
  97. package/lib/Tab/sgds-tabpanel.d.ts +25 -0
  98. package/lib/Textarea/index.d.ts +1 -0
  99. package/lib/Textarea/index.js +6696 -0
  100. package/lib/Textarea/index.js.map +1 -0
  101. package/lib/Textarea/package.json +7 -0
  102. package/lib/Textarea/sgds-textarea.d.ts +53 -0
  103. package/lib/index.d.ts +16 -0
  104. package/lib/index.js +134580 -0
  105. package/lib/index.js.map +1 -0
  106. package/lib/umd/index.js +134587 -0
  107. package/lib/umd/index.js.map +1 -0
  108. package/lib/utils/animate.d.ts +10 -0
  109. package/lib/utils/animation-registry.d.ts +18 -0
  110. package/{utils → lib/utils}/breakpoints.d.ts +0 -0
  111. package/lib/utils/card-element.d.ts +11 -0
  112. package/lib/utils/defaultvalue.d.ts +2 -0
  113. package/lib/utils/dropdown-element.d.ts +37 -0
  114. package/lib/utils/event.d.ts +2 -0
  115. package/lib/utils/form.d.ts +38 -0
  116. package/{utils → lib/utils}/generateId.d.ts +0 -0
  117. package/lib/utils/link-element.d.ts +7 -0
  118. package/lib/utils/mergeDeep.d.ts +2 -0
  119. package/lib/utils/modal.d.ts +12 -0
  120. package/lib/utils/object.d.ts +2 -0
  121. package/lib/utils/offset.d.ts +4 -0
  122. package/lib/utils/scroll.d.ts +13 -0
  123. package/{utils → lib/utils}/sgds-element.d.ts +0 -0
  124. package/lib/utils/slot.d.ts +22 -0
  125. package/lib/utils/tabbable.d.ts +8 -0
  126. package/lib/utils/watch.d.ts +14 -0
  127. package/mocks/dropdown.d.ts +4 -0
  128. package/mocks/dropdown.ts +27 -0
  129. package/mocks/link.d.ts +3 -0
  130. package/mocks/link.ts +6 -0
  131. package/package.json +65 -10
  132. package/rollup.config.js +73 -0
  133. package/rollup.test.config.js +42 -0
  134. package/scripts/buildUtils.js +30 -0
  135. package/scripts/frankBuild.js +49 -0
  136. package/src/Button/index.ts +1 -0
  137. package/src/Button/sgds-button.scss +28 -0
  138. package/src/Button/sgds-button.ts +153 -0
  139. package/src/Card/index.ts +1 -0
  140. package/src/Card/sgds-action-card.scss +27 -0
  141. package/src/Card/sgds-action-card.ts +115 -0
  142. package/src/Checkbox/index.ts +1 -0
  143. package/src/Checkbox/sgds-checkbox.scss +4 -0
  144. package/src/Checkbox/sgds-checkbox.ts +149 -0
  145. package/src/Dropdown/index.ts +3 -0
  146. package/src/Dropdown/sgds-dropdown-item.ts +39 -0
  147. package/src/Dropdown/sgds-dropdown.scss +5 -0
  148. package/src/Dropdown/sgds-dropdown.ts +54 -0
  149. package/src/Footer/index.ts +3 -0
  150. package/src/Footer/sgds-footer.scss +5 -0
  151. package/src/Footer/sgds-footer.ts +121 -0
  152. package/src/Input/index.ts +1 -0
  153. package/src/Input/sgds-input.scss +20 -0
  154. package/src/Input/sgds-input.ts +178 -0
  155. package/src/Mainnav/index.ts +4 -0
  156. package/src/Mainnav/sgds-mainnav-dropdown.scss +13 -0
  157. package/src/Mainnav/sgds-mainnav-dropdown.ts +45 -0
  158. package/src/Mainnav/sgds-mainnav-item.scss +24 -0
  159. package/src/Mainnav/sgds-mainnav-item.ts +8 -0
  160. package/src/Mainnav/sgds-mainnav.scss +39 -0
  161. package/src/Mainnav/sgds-mainnav.ts +183 -0
  162. package/src/Masthead/index.ts +1 -0
  163. package/src/Masthead/sgds-masthead.scss +217 -0
  164. package/src/Masthead/sgds-masthead.ts +189 -0
  165. package/src/Modal/index.ts +1 -0
  166. package/src/Modal/sgds-modal.scss +128 -0
  167. package/src/Modal/sgds-modal.ts +309 -0
  168. package/src/QuantityToggle/index.ts +1 -0
  169. package/src/QuantityToggle/sgds-quantitytoggle.scss +10 -0
  170. package/src/QuantityToggle/sgds-quantitytoggle.ts +130 -0
  171. package/src/Radio/index.ts +2 -0
  172. package/src/Radio/sgds-radio.scss +5 -0
  173. package/src/Radio/sgds-radio.ts +120 -0
  174. package/src/Radio/sgds-radiogroup.scss +22 -0
  175. package/src/Radio/sgds-radiogroup.ts +221 -0
  176. package/src/Sidenav/index.ts +4 -0
  177. package/src/Sidenav/sgds-sidenav-item.scss +73 -0
  178. package/src/Sidenav/sgds-sidenav-item.ts +145 -0
  179. package/src/Sidenav/sgds-sidenav-link.scss +25 -0
  180. package/src/Sidenav/sgds-sidenav-link.ts +8 -0
  181. package/src/Sidenav/sgds-sidenav.scss +6 -0
  182. package/src/Sidenav/sgds-sidenav.ts +33 -0
  183. package/src/Tab/index.ts +3 -0
  184. package/src/Tab/sgds-tab.scss +84 -0
  185. package/src/Tab/sgds-tab.ts +87 -0
  186. package/src/Tab/sgds-tabgroup.scss +198 -0
  187. package/src/Tab/sgds-tabgroup.ts +295 -0
  188. package/src/Tab/sgds-tabpanel.scss +12 -0
  189. package/src/Tab/sgds-tabpanel.ts +55 -0
  190. package/src/Textarea/index.ts +1 -0
  191. package/src/Textarea/sgds-textarea.scss +23 -0
  192. package/src/Textarea/sgds-textarea.ts +201 -0
  193. package/src/index.ts +16 -0
  194. package/src/utils/animate.ts +69 -0
  195. package/src/utils/animation-registry.ts +71 -0
  196. package/src/utils/base.scss +14 -0
  197. package/src/utils/breakpoints.ts +5 -0
  198. package/src/utils/card-element.ts +42 -0
  199. package/src/utils/components.style.scss +531 -0
  200. package/src/utils/defaultvalue.ts +51 -0
  201. package/src/utils/dropdown-element.ts +244 -0
  202. package/src/utils/event.ts +13 -0
  203. package/src/utils/form.ts +183 -0
  204. package/src/utils/generateId.ts +4 -0
  205. package/src/utils/link-element.ts +34 -0
  206. package/src/utils/mergeDeep.ts +22 -0
  207. package/src/utils/modal.ts +64 -0
  208. package/src/utils/object.ts +2 -0
  209. package/src/utils/offset.ts +6 -0
  210. package/src/utils/scroll.ts +57 -0
  211. package/src/utils/sgds-element.ts +18 -0
  212. package/src/utils/slot.ts +102 -0
  213. package/src/utils/tabbable.ts +81 -0
  214. package/src/utils/watch.ts +62 -0
  215. package/stories/ActionCard.stories.mdx +199 -0
  216. package/stories/Button.stories.mdx +194 -0
  217. package/stories/Checkbox.stories.mdx +196 -0
  218. package/stories/Dropdown.stories.mdx +152 -0
  219. package/stories/Footer.stories.mdx +261 -0
  220. package/stories/Input.stories.mdx +236 -0
  221. package/stories/MainNav.stories.mdx +169 -0
  222. package/stories/Masthead.stories.mdx +112 -0
  223. package/stories/Modal.stories.mdx +103 -0
  224. package/stories/QuantityToggle.stories.mdx +97 -0
  225. package/stories/Radio.stories.mdx +262 -0
  226. package/stories/Sample.stories.js +29 -0
  227. package/stories/Sample.stories.mdx +33 -0
  228. package/stories/SideNav.stories.mdx +245 -0
  229. package/stories/common.js +185 -0
  230. package/stories/textarea.stories.mdx +253 -0
  231. package/test/button.element.test.ts +185 -0
  232. package/test/checkbox.test.ts +240 -0
  233. package/test/dropdown.test.ts +637 -0
  234. package/test/footer.test.ts +181 -0
  235. package/test/generateId.test.ts +18 -0
  236. package/test/input.element.test.ts +316 -0
  237. package/test/link-element.test.ts +38 -0
  238. package/test/mainnav.test.ts +313 -0
  239. package/test/masthead.test.ts +116 -0
  240. package/test/modal.test.ts +149 -0
  241. package/test/quantitytoggle.test.ts +76 -0
  242. package/test/radio.test.ts +310 -0
  243. package/test/selectable-card.test.ts +159 -0
  244. package/test/sidenav.test.ts +390 -0
  245. package/test/tab.test.ts +76 -0
  246. package/test/textarea.test.ts +126 -0
  247. package/tsconfig.json +26 -0
  248. package/tsconfig.test.json +24 -0
  249. package/typings/scss.d.ts +5 -0
  250. package/web-dev-server.config.mjs +7 -0
  251. package/web-test-runner.config.mjs +47 -0
  252. package/Button/index.js.map +0 -1
  253. package/Button/sgds-button.d.ts +0 -23
  254. package/Footer/index.js.map +0 -1
  255. package/Mainnav/index.js.map +0 -1
  256. package/Mainnav/sgds-mainnav-item.d.ts +0 -7
  257. package/Masthead/index.js.map +0 -1
  258. package/Sidenav/index.js.map +0 -1
  259. package/Sidenav/sgds-sidenav-link.d.ts +0 -7
  260. package/index.d.ts +0 -5
  261. package/index.js.map +0 -1
  262. package/umd/index.js +0 -52097
  263. package/umd/index.js.map +0 -1
@@ -0,0 +1,201 @@
1
+ import { customElement, property,query, state } from "lit/decorators.js";
2
+ import { html } from 'lit/static-html.js';
3
+ import { ifDefined } from 'lit/directives/if-defined.js';
4
+ import {classMap} from 'lit/directives/class-map.js';
5
+ import { live } from 'lit/directives/live.js';
6
+ import styles from "./sgds-textarea.scss";
7
+ import SgdsElement from "../utils/sgds-element";
8
+ import { defaultValue } from "../utils/defaultvalue";
9
+ import { FormSubmitController } from "../utils/form";
10
+ import genId from "../utils/generateId";
11
+ import { watch } from "../utils/watch";
12
+
13
+ @customElement("sgds-textarea")
14
+ export class SgdsTextArea extends SgdsElement {
15
+ static styles = styles;
16
+
17
+ @query('textarea.form-control') textarea: HTMLTextAreaElement;
18
+ @state() private hasFocus = false;
19
+
20
+ private readonly formSubmitController = new FormSubmitController(this);
21
+ private resizeObserver: ResizeObserver;
22
+
23
+
24
+ @property({ type: String, reflect: true }) label = "label";
25
+ @property({ type: String, reflect: true }) textareaId = genId("textarea","input");
26
+ @property({ type: String, reflect: true }) name;
27
+ @property({ type: String, reflect: true }) textareaClasses?;
28
+ @property({ type: String, reflect: true }) value = '';
29
+ @property({ type: String, reflect: true}) minlength;
30
+ @property({ type: String, reflect: true}) maxlength;
31
+ @property({ type: Boolean, reflect: true}) spellcheck = false;
32
+ /** The number of rows to display by default. */
33
+ @property({ type: Number }) rows = 4;
34
+ @property({ type: String, reflect: true }) placeholder = "Placeholder";
35
+ @property({ type: String, reflect: true }) invalidFeedback = "default feedback";
36
+ @property({ type: Boolean, reflect: true }) autofocus = false;
37
+ @property({ type: Boolean, reflect: true }) disabled = false;
38
+ @property({ type: Boolean, reflect: true }) required = false;
39
+ /** Makes the input readonly. */
40
+ @property({ type: Boolean, reflect: true }) readonly = false;
41
+ @property({ type: Boolean, reflect: true }) invalid = false;
42
+ @property({ type: Boolean, reflect: true }) valid = false;
43
+ /** Controls how the textarea can be resized. */
44
+ @property() resize: 'none' | 'vertical' | 'auto' = 'vertical';
45
+ /** The textarea's inputmode attribute. */
46
+ @property() inputmode: 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';
47
+ /* The textarea's autocorrect attribute. */
48
+ @property() autocorrect: string;
49
+ /** Gets or sets the default value used to reset this element. The initial value corresponds to the one originally specified in the HTML that created this element. */
50
+ @defaultValue()
51
+ defaultValue = '';
52
+
53
+ connectedCallback() {
54
+ super.connectedCallback();
55
+ this.resizeObserver = new ResizeObserver(() => this.setTextareaHeight());
56
+
57
+ this.updateComplete.then(() => {
58
+ this.setTextareaHeight();
59
+ this.resizeObserver.observe(this.textarea);
60
+ });
61
+ }
62
+
63
+ disconnectedCallback() {
64
+ super.disconnectedCallback();
65
+ this.resizeObserver.unobserve(this.textarea);
66
+ }
67
+
68
+ /** Sets focus on the textarea. */
69
+ focus(options?: FocusOptions) {
70
+ this.textarea.focus(options);
71
+ }
72
+
73
+ /** Checks for validity and shows the browser's validation message if the control is invalid. */
74
+ reportValidity() {
75
+ return this.textarea.reportValidity();
76
+ }
77
+
78
+ handleInvalid() {
79
+ this.invalid = true;
80
+ }
81
+
82
+ handleChange(event: string){
83
+ this.value = this.textarea.value;
84
+ this.emit(event);
85
+ }
86
+
87
+ handleFocus() {
88
+ this.hasFocus = true;
89
+ this.emit('sgds-focus');
90
+ }
91
+
92
+ handleBlur() {
93
+ this.hasFocus = false;
94
+ this.emit('sgds-blur');
95
+ }
96
+
97
+ /** Selects all the text in the textarea. */
98
+ select() {
99
+ this.textarea.select();
100
+ }
101
+
102
+ handleKeyDown(event: KeyboardEvent) {
103
+ const hasModifier = event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
104
+
105
+ // Pressing enter when focused on an input should submit the form like a native input, but we wait a tick before
106
+ // submitting to allow users to cancel the keydown event if they need to
107
+ if (event.key === 'Enter' && !hasModifier) {
108
+ setTimeout(() => {
109
+ if (!event.defaultPrevented) {
110
+ this.formSubmitController.submit();
111
+ }
112
+ });
113
+ }
114
+ }
115
+
116
+ @watch('rows', { waitUntilFirstUpdate: true })
117
+ handleRowsChange() {
118
+ this.setTextareaHeight();
119
+ }
120
+
121
+ setTextareaHeight() {
122
+ if (this.resize === 'auto') {
123
+ this.textarea.style.height = 'auto';
124
+ this.textarea.style.height = `${this.textarea.scrollHeight}px`;
125
+ } else {
126
+ (this.textarea.style.height as string | undefined) = undefined;
127
+ }
128
+ }
129
+
130
+ @watch('disabled', { waitUntilFirstUpdate: true })
131
+ handleDisabledChange() {
132
+ // Disabled form controls are always valid, so we need to recheck validity when the state changes
133
+ this.textarea.disabled = this.disabled;
134
+ this.invalid = !this.textarea.checkValidity();
135
+ }
136
+
137
+ @watch('value', { waitUntilFirstUpdate: true })
138
+ handleValueChange() {
139
+ this.invalid = !this.textarea.checkValidity();
140
+ this.valid = this.textarea.checkValidity()
141
+ this.updateComplete.then(() => this.setTextareaHeight());
142
+ }
143
+
144
+ render() {
145
+
146
+ // if maxlength is defined
147
+ const wordCount = html`
148
+ <div class="form-text">${this.value.length}/${this.maxlength}</div>
149
+ `
150
+
151
+ return html`
152
+
153
+ <div class="text-area-label-wrapper d-flex justify-content-between">
154
+ <label for=${ifDefined(this.textareaId)} class="form-label">${this.label}</label>
155
+ ${parseInt(this.maxlength) > 0 ? wordCount : undefined}
156
+ </div>
157
+
158
+ <textarea
159
+ class="${classMap(
160
+ {
161
+ 'form-control': true,
162
+ 'is-invalid' : this.invalid,
163
+ 'is-valid' : this.valid,
164
+ 'textarea-resize-none': this.resize === 'none',
165
+ 'textarea-resize-vertical': this.resize === 'vertical',
166
+ 'textarea-resize-auto': this.resize === 'auto',
167
+ [`${this.textareaClasses}`]: this.textareaClasses,
168
+ })}"
169
+ id=${ifDefined(this.textareaId)}
170
+ name=${ifDefined(this.name)}
171
+ rows=${ifDefined(this.rows)}
172
+ placeholder=${ifDefined(this.placeholder)}
173
+ minlength=${ifDefined(this.minlength)}
174
+ maxlength=${ifDefined(this.maxlength)}
175
+ .value=${live(this.value)}
176
+ aria-invalid=${this.invalid ? 'true' : 'false'}
177
+ spellcheck=${ifDefined(this.spellcheck)}
178
+ ?disabled=${this.disabled}
179
+ ?readonly=${this.readonly}
180
+ ?required=${this.required}
181
+ ?autofocus=${this.autofocus}
182
+ autocorrect=${ifDefined(this.autocorrect)}
183
+ inputmode=${ifDefined(this.inputmode)}
184
+ @keyup=${this.handleValueChange}
185
+ @input=${()=> this.handleChange('sgds-input')}
186
+ @change=${()=> this.handleChange('sgds-change')}
187
+ @invalid=${this.handleInvalid}
188
+ @focus=${this.handleFocus}
189
+ @blur=${this.handleBlur}
190
+ >
191
+ </textarea>
192
+
193
+ <div id="${this.textareaId}-invalid" class="invalid-feedback">${this.invalidFeedback}</div>
194
+
195
+ `;
196
+
197
+ }
198
+ }
199
+
200
+ export default SgdsTextArea;
201
+
package/src/index.ts ADDED
@@ -0,0 +1,16 @@
1
+ import "./Sidenav";
2
+ import "./Radio";
3
+ import "./Masthead";
4
+ import "./Button";
5
+ import "./Footer";
6
+ import "./Mainnav";
7
+ import "./Input";
8
+ import "./Checkbox";
9
+ import "./Dropdown";
10
+ import "./Input";
11
+ import "./Textarea";
12
+ import "./Modal";
13
+ import './QuantityToggle';
14
+ import "./Textarea";
15
+ import "./Tab";
16
+ import "./Card";
@@ -0,0 +1,69 @@
1
+ //
2
+ // Animates an element using keyframes. Returns a promise that resolves after the animation completes or gets canceled.
3
+ //
4
+ export function animateTo(el: HTMLElement, keyframes: Keyframe[], options?: KeyframeAnimationOptions) {
5
+ return new Promise(resolve => {
6
+ if (options?.duration === Infinity) {
7
+ throw new Error('Promise-based animations must be finite.');
8
+ }
9
+
10
+ const animation = el.animate(keyframes, {
11
+ ...options,
12
+ duration: prefersReducedMotion() ? 0 : options!.duration
13
+ });
14
+
15
+ animation.addEventListener('cancel', resolve, { once: true });
16
+ animation.addEventListener('finish', resolve, { once: true });
17
+ });
18
+ }
19
+
20
+ //
21
+ // Parses a CSS duration and returns the number of milliseconds.
22
+ //
23
+ export function parseDuration(delay: number | string) {
24
+ delay = delay.toString().toLowerCase();
25
+
26
+ if (delay.indexOf('ms') > -1) {
27
+ return parseFloat(delay);
28
+ }
29
+
30
+ if (delay.indexOf('s') > -1) {
31
+ return parseFloat(delay) * 1000;
32
+ }
33
+
34
+ return parseFloat(delay);
35
+ }
36
+
37
+ //
38
+ // Tells if the user has enabled the "reduced motion" setting in their browser or OS.
39
+ //
40
+ export function prefersReducedMotion() {
41
+ const query = window.matchMedia('(prefers-reduced-motion: reduce)');
42
+ return query.matches;
43
+ }
44
+
45
+ //
46
+ // Stops all active animations on the target element. Returns a promise that resolves after all animations are canceled.
47
+ //
48
+ export function stopAnimations(el: HTMLElement) {
49
+ return Promise.all(
50
+ el.getAnimations().map(animation => {
51
+ return new Promise(resolve => {
52
+ const handleAnimationEvent = requestAnimationFrame(resolve);
53
+
54
+ animation.addEventListener('cancel', () => handleAnimationEvent, { once: true });
55
+ animation.addEventListener('finish', () => handleAnimationEvent, { once: true });
56
+ animation.cancel();
57
+ });
58
+ })
59
+ );
60
+ }
61
+
62
+ // We can't animate `height: auto`, but we can calculate the height and shim keyframes by replacing it with the
63
+ // element's scrollHeight before the animation.
64
+ export function shimKeyframesHeightAuto(keyframes: Keyframe[], calculatedHeight: number) {
65
+ return keyframes.map(keyframe => ({
66
+ ...keyframe,
67
+ height: keyframe.height === 'auto' ? `${calculatedHeight}px` : keyframe.height
68
+ }));
69
+ }
@@ -0,0 +1,71 @@
1
+ export interface ElementAnimation {
2
+ keyframes: Keyframe[];
3
+ rtlKeyframes?: Keyframe[];
4
+ options?: KeyframeAnimationOptions;
5
+ }
6
+
7
+ export interface ElementAnimationMap {
8
+ [animationName: string]: ElementAnimation;
9
+ }
10
+
11
+ export interface GetAnimationOptions {
12
+ /**
13
+ * The component's directionality. When set to "rtl", `rtlKeyframes` will be preferred over `keyframes` where
14
+ * available using getAnimation().
15
+ */
16
+ dir: string;
17
+ }
18
+
19
+ const defaultAnimationRegistry = new Map<string, ElementAnimation>();
20
+ const customAnimationRegistry = new WeakMap<Element, ElementAnimationMap>();
21
+
22
+ function ensureAnimation(animation: ElementAnimation | null) {
23
+ return animation ?? { keyframes: [], options: { duration: 0 } };
24
+ }
25
+
26
+ //
27
+ // Given an ElementAnimation, this function returns a new ElementAnimation where the keyframes property reflects either
28
+ // keyframes or rtlKeyframes depending on the specified directionality.
29
+ //
30
+ function getLogicalAnimation(animation: ElementAnimation) {
31
+ return animation;
32
+ }
33
+
34
+ //
35
+ // Sets a default animation. Components should use the `name.animation` for primary animations and `name.part.animation`
36
+ // for secondary animations, e.g. `dialog.show` and `dialog.overlay.show`. For modifiers, use `drawer.showTop`.
37
+ //
38
+ export function setDefaultAnimation(animationName: string, animation: ElementAnimation | null) {
39
+ defaultAnimationRegistry.set(animationName, ensureAnimation(animation));
40
+ }
41
+
42
+ //
43
+ // Sets a custom animation for the specified element.
44
+ //
45
+ export function setAnimation(el: Element, animationName: string, animation: ElementAnimation | null) {
46
+ customAnimationRegistry.set(el, { ...customAnimationRegistry.get(el), [animationName]: ensureAnimation(animation) });
47
+ }
48
+
49
+ //
50
+ // Gets an element's animation. Falls back to the default if no animation is found.
51
+ //
52
+ export function getAnimation(el: Element, animationName: string) {
53
+ const customAnimation = customAnimationRegistry.get(el);
54
+
55
+ // Check for a custom animation
56
+ if (customAnimation?.[animationName]) {
57
+ return getLogicalAnimation(customAnimation[animationName]);
58
+ }
59
+
60
+ // Check for a default animation
61
+ const defaultAnimation = defaultAnimationRegistry.get(animationName);
62
+ if (defaultAnimation) {
63
+ return getLogicalAnimation(defaultAnimation);
64
+ }
65
+
66
+ // Fall back to an empty animation
67
+ return {
68
+ keyframes: [],
69
+ options: { duration: 0 }
70
+ };
71
+ }
@@ -0,0 +1,14 @@
1
+
2
+ // @charset "utf-8";
3
+
4
+ @import "~@govtechsg/sgds/sass/functions";
5
+ @import "~@govtechsg/sgds/sass/variables";
6
+ @import "~@govtechsg/sgds/sass/mixins";
7
+
8
+ @import "~@govtechsg/sgds/sass/utilities";
9
+
10
+ @import "~@govtechsg/sgds/sass/root";
11
+ @import "~@govtechsg/sgds/sass/reboot";
12
+ @import "~@govtechsg/sgds/sass/type";
13
+ @import "~@govtechsg/sgds/sass/helpers";
14
+ @import "~@govtechsg/sgds/sass/utilities/api";
@@ -0,0 +1,5 @@
1
+ export const SM_BREAKPOINT = 576;
2
+ export const MD_BREAKPOINT = 768;
3
+ export const LG_BREAKPOINT = 992;
4
+ export const XL_BREAKPOINT = 1200;
5
+ export const XXL_BREAKPOINT = 1400;
@@ -0,0 +1,42 @@
1
+ import { property, state } from "lit/decorators.js";
2
+ import genId from "./generateId";
3
+ import SgdsElement from "./sgds-element";
4
+
5
+ export type Variant =
6
+ | "primary"
7
+ | "secondary"
8
+ | "success"
9
+ | "danger"
10
+ | "warning"
11
+ | "info"
12
+ | "dark"
13
+ | "light"
14
+ | string;
15
+
16
+ export type Color =
17
+ | "primary"
18
+ | "secondary"
19
+ | "success"
20
+ | "danger"
21
+ | "warning"
22
+ | "info"
23
+ | "dark"
24
+ | "light"
25
+ | "white"
26
+ | "muted";
27
+
28
+ export class CardElement extends SgdsElement {
29
+ @property({ type: String })
30
+
31
+ /** The border's variant. */
32
+ @property() borderColor?: Variant;
33
+
34
+ /** The bg's variant. */
35
+ @property() bgColor?: Variant;
36
+
37
+ /** The text's variant. */
38
+ @property() textColor?: Color;
39
+
40
+ @property({ type: Boolean, reflect: true })
41
+ disabled = false;
42
+ }