@brightspace-ui/core 3.175.4 → 3.176.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.
@@ -0,0 +1,173 @@
1
+ import './demo-flags.js';
2
+ import '../button/button.js';
3
+ import '../inputs/input-checkbox-group.js';
4
+ import '../inputs/input-checkbox.js';
5
+ import '../inputs/input-group.js';
6
+ import '../collapsible-panel/collapsible-panel.js';
7
+ import '../collapsible-panel/collapsible-panel-summary-item.js';
8
+ import { css, html, LitElement, nothing } from 'lit';
9
+ import { getDocumentLocaleSettings, supportedLocalesDetails } from '@brightspace-ui/intl/lib/common.js';
10
+ import { getFlagOverrides, getKnownFlags } from '../../helpers/flags.js';
11
+ import { inputLabelStyles } from '../inputs/input-label-styles.js';
12
+ import { selectStyles } from '../inputs/input-select-styles.js';
13
+
14
+ const localeSettings = getDocumentLocaleSettings();
15
+
16
+ class DemoPageSettings extends LitElement {
17
+
18
+ static get properties() {
19
+ return {
20
+ panelTitle: { type: String, attribute: 'panel-title' },
21
+ _language: { state: true }
22
+ };
23
+ }
24
+
25
+ static get styles() {
26
+ return [ inputLabelStyles, selectStyles, css`
27
+ :host {
28
+ display: block;
29
+ }
30
+ :host[hidden] {
31
+ display: none;
32
+ }
33
+ d2l-collapsible-panel {
34
+ width: 100%;
35
+ }
36
+ #applyFlagsButton {
37
+ margin-block-start: 1rem;
38
+ }
39
+ `];
40
+ }
41
+
42
+ constructor() {
43
+ super();
44
+ this.#handleFlagsKnownBound = this.#handleFlagsKnown.bind(this);
45
+ this.#handleDocumentLanguageChangeBound = this.#handleDocumentLanguageChange.bind(this);
46
+ const urlParams = new URLSearchParams(window.location.search);
47
+ if (urlParams.has('lang')) {
48
+ const newLanguageCode = urlParams.get('lang');
49
+ document.documentElement.dir = newLanguageCode === 'ar-sa' ? 'rtl' : 'ltr';
50
+ document.documentElement.lang = newLanguageCode;
51
+ this._language = newLanguageCode;
52
+ } else {
53
+ this._language = getDocumentLocaleSettings().language;
54
+ }
55
+ }
56
+
57
+ connectedCallback() {
58
+ super.connectedCallback();
59
+ document.addEventListener('d2l-flags-known', this.#handleFlagsKnownBound);
60
+ localeSettings.addChangeListener(this.#handleDocumentLanguageChangeBound);
61
+ }
62
+
63
+ disconnectedCallback() {
64
+ super.disconnectedCallback();
65
+ document.removeEventListener('d2l-flags-known', this.#handleFlagsKnownBound);
66
+ localeSettings.removeChangeListener(this.#handleDocumentLanguageChangeBound);
67
+ }
68
+
69
+ render() {
70
+
71
+ let selectedLanguageCode = this._language;
72
+ if (selectedLanguageCode === 'en') selectedLanguageCode = 'en-us';
73
+ let foundSelected = false;
74
+ const languageOptions = supportedLocalesDetails.map((l) => {
75
+ const selected = !foundSelected && l.code.startsWith(selectedLanguageCode);
76
+ foundSelected = foundSelected || selected;
77
+ return html`<option value="${l.code}" ?selected="${selected}">${l.code} - ${l.name}</option>`;
78
+ });
79
+ let languageItem = nothing;
80
+ if (selectedLanguageCode !== 'en-us') {
81
+ languageItem = html`<d2l-collapsible-panel-summary-item slot="summary" text="Language: ${selectedLanguageCode}"></d2l-collapsible-panel-summary-item>`;
82
+ }
83
+
84
+ const knownFlags = this.#getKnownFlagsSorted();
85
+ const knownFlagCheckboxes = [];
86
+ knownFlags.forEach((knownFlag, key) => {
87
+ knownFlagCheckboxes.push(html`<d2l-input-checkbox label="${key}" data-flag-key="${key}" ?checked="${knownFlag.value}"></d2l-input-checkbox>`);
88
+ });
89
+
90
+ const flagOverrides = getFlagOverrides();
91
+ const flagOverrideItems = [];
92
+ flagOverrides.forEach((value, key) => {
93
+ const knownFlag = knownFlags.get(key);
94
+ const defaultValue = knownFlag ? knownFlag.defaultValue : 'unknown';
95
+ flagOverrideItems.push(html`<d2l-collapsible-panel-summary-item slot="summary" text="${key} (default: ${defaultValue}; override: ${value})"></d2l-collapsible-panel-summary-item>`);
96
+ });
97
+
98
+ return html`
99
+ <d2l-collapsible-panel panel-title="${this.panelTitle}" heading-level="1" heading-style="3" type="subtle">
100
+ <d2l-input-group>
101
+ <label>
102
+ <span class="d2l-input-label">Language</span>
103
+ <select class="d2l-input-select" @change="${this.#handleLanguageChange}">${languageOptions}</select>
104
+ </label>
105
+ ${knownFlagCheckboxes.length > 0 ? html`
106
+ <d2l-input-checkbox-group id="flagsCheckboxGroup" label="Flags">
107
+ ${knownFlagCheckboxes}
108
+ </d2l-input-checkbox-group>
109
+ <d2l-button id="applyFlagsButton" @click="${this.#handleApplyFlagsClick}">Apply</d2l-button>
110
+ ` : 'No known flags'}
111
+ </d2l-input-group>
112
+ ${languageItem}
113
+ ${flagOverrideItems}
114
+ </d2l-collapsible-panel>
115
+ `;
116
+ }
117
+
118
+ #handleDocumentLanguageChangeBound;
119
+ #handleFlagsKnownBound;
120
+
121
+ #getKnownFlagsSorted() {
122
+ return new Map([...getKnownFlags().entries()].sort((entry1, entry2) => {
123
+ const key1 = entry1[0].toLowerCase();
124
+ const key2 = entry2[0].toLowerCase();
125
+ if (key1 < key2) return -1;
126
+ else if (key1 > key2) return 1;
127
+ else return 0;
128
+ }));
129
+ }
130
+
131
+ #handleApplyFlagsClick() {
132
+ const urlParams = new URLSearchParams(window.location.search);
133
+ const elems = [...this.shadowRoot.querySelectorAll('#flagsCheckboxGroup > d2l-input-checkbox')];
134
+
135
+ const knownFlags = getKnownFlags();
136
+ elems.forEach(elem => {
137
+ const key = elem.dataset.flagKey;
138
+ const flag = knownFlags.get(key);
139
+
140
+ if (flag.defaultValue === elem.checked) {
141
+ urlParams.delete(`demo-flag-${key}`);
142
+ } else if (flag.defaultValue !== elem.checked) {
143
+ urlParams.set(`demo-flag-${key}`, elem.checked);
144
+ }
145
+ });
146
+
147
+ window.location.search = urlParams.toString();
148
+ }
149
+
150
+ #handleDocumentLanguageChange() {
151
+ this._language = localeSettings.language;
152
+ const url = new URL(window.location.href);
153
+ if (this._language === 'en-us') {
154
+ url.searchParams.delete('lang');
155
+ } else {
156
+ url.searchParams.set('lang', this._language);
157
+ }
158
+ window.history.replaceState({}, '', url.toString());
159
+ }
160
+
161
+ #handleFlagsKnown() {
162
+ this.requestUpdate();
163
+ }
164
+
165
+ #handleLanguageChange(e) {
166
+ const newLanguageCode = e.target[e.target.selectedIndex].value;
167
+ document.documentElement.dir = newLanguageCode === 'ar-sa' ? 'rtl' : 'ltr';
168
+ document.documentElement.lang = newLanguageCode;
169
+ }
170
+
171
+ }
172
+
173
+ customElements.define('d2l-demo-page-settings', DemoPageSettings);
@@ -1,19 +1,10 @@
1
- import './demo-flags.js';
2
- import '../button/button.js';
1
+ import './demo-page-settings.js';
3
2
  import './demo-snippet.js';
4
- import '../inputs/input-checkbox-group.js';
5
- import '../inputs/input-checkbox.js';
6
3
  import './code-view.js';
7
- import '../collapsible-panel/collapsible-panel.js';
8
- import '../collapsible-panel/collapsible-panel-summary-item.js';
9
4
  import '../colors/colors.js';
10
5
  import '../typography/typography.js';
11
6
  import { css, html, LitElement } from 'lit';
12
- import { getDocumentLocaleSettings, supportedLocalesDetails } from '@brightspace-ui/intl/lib/common.js';
13
- import { getFlagOverrides, getKnownFlags } from '../../helpers/flags.js';
14
7
  import { classMap } from 'lit/directives/class-map.js';
15
- import { inputLabelStyles } from '../inputs/input-label-styles.js';
16
- import { selectStyles } from '../inputs/input-select-styles.js';
17
8
 
18
9
  document.body.classList.add('d2l-typography');
19
10
 
@@ -38,7 +29,7 @@ class DemoPage extends LitElement {
38
29
  }
39
30
 
40
31
  static get styles() {
41
- return [ inputLabelStyles, selectStyles, css`
32
+ return [ css`
42
33
  :host {
43
34
  background-color: var(--d2l-color-sylvite);
44
35
  display: block;
@@ -50,17 +41,9 @@ class DemoPage extends LitElement {
50
41
  padding: 0;
51
42
  }
52
43
  header {
53
- align-items: center;
54
- display: flex;
55
44
  margin-bottom: 1.5rem;
56
45
  max-width: 900px;
57
46
  }
58
- d2l-collapsible-panel {
59
- width: 100%;
60
- }
61
- .d2l-input-label {
62
- margin-bottom: 0;
63
- }
64
47
  .d2l-demo-page-content > ::slotted(h2),
65
48
  .d2l-demo-page-content > ::slotted(h3) {
66
49
  font-size: 0.8rem;
@@ -73,29 +56,14 @@ class DemoPage extends LitElement {
73
56
  .d2l-demo-page-content > ::slotted(d2l-demo-snippet) {
74
57
  margin-bottom: 36px;
75
58
  }
76
-
77
- #applyFlagsButton {
78
- margin-block-start: 1rem;
79
- }
80
59
  `];
81
60
  }
82
61
 
83
- constructor() {
84
- super();
85
- this.#handleFlagsKnownBound = this.#handleFlagsKnown.bind(this);
86
- }
87
-
88
62
  connectedCallback() {
89
63
  super.connectedCallback();
90
64
  const title = document.createElement('title');
91
65
  title.textContent = this.pageTitle;
92
66
  document.head.insertBefore(title, document.head.firstChild);
93
- document.addEventListener('d2l-flags-known', this.#handleFlagsKnownBound);
94
- }
95
-
96
- disconnectedCallback() {
97
- super.disconnectedCallback();
98
- document.removeEventListener('d2l-flags-known', this.#handleFlagsKnownBound);
99
67
  }
100
68
 
101
69
  render() {
@@ -103,44 +71,9 @@ class DemoPage extends LitElement {
103
71
  'no-scroll': this._noScroll
104
72
  };
105
73
 
106
- let selectedLanguageCode = getDocumentLocaleSettings().language;
107
- if (selectedLanguageCode === 'en') selectedLanguageCode = 'en-us';
108
- let foundSelected = false;
109
- const languageOptions = supportedLocalesDetails.map((l) => {
110
- const selected = !foundSelected && l.code.startsWith(selectedLanguageCode);
111
- foundSelected = foundSelected || selected;
112
- return html`<option value="${l.code}" ?selected="${selected}">${l.code} - ${l.name}</option>`;
113
- });
114
-
115
- const knownFlags = this.#getKnownFlagsSorted();
116
- const knownFlagCheckboxes = [];
117
- knownFlags.forEach((knownFlag, key) => {
118
- knownFlagCheckboxes.push(html`<d2l-input-checkbox label="${key}" data-flag-key="${key}" ?checked="${knownFlag.value}"></d2l-input-checkbox>`);
119
- });
120
-
121
- const flagOverrides = getFlagOverrides();
122
- const flagOverrideItems = [];
123
- flagOverrides.forEach((value, key) => {
124
- const knownFlag = knownFlags.get(key);
125
- const defaultValue = knownFlag ? knownFlag.defaultValue : 'unknown';
126
- flagOverrideItems.push(html`<d2l-collapsible-panel-summary-item slot="summary" text="${key} (default: ${defaultValue}; override: ${value})"></d2l-collapsible-panel-summary-item>`);
127
- });
128
-
129
74
  return html`
130
75
  <header>
131
- <d2l-collapsible-panel panel-title="${this.pageTitle}" heading-level="1" heading-style="3" type="subtle">
132
- <label class="d2l-input-label" slot="actions">
133
- Language:
134
- <select class="d2l-input-select" @change="${this.#handleLanguageChange}">${languageOptions}</select>
135
- </label>
136
- ${knownFlagCheckboxes.length > 0 ? html`
137
- <d2l-input-checkbox-group id="flagsCheckboxGroup" label="Flags">
138
- ${knownFlagCheckboxes}
139
- </d2l-input-checkbox-group>
140
- <d2l-button id="applyFlagsButton" @click="${this.#handleApplyFlagsClick}">Apply</d2l-button>
141
- ` : 'No known flags'}
142
- ${flagOverrideItems}
143
- </d2l-collapsible-panel>
76
+ <d2l-demo-page-settings panel-title="${this.pageTitle}"></d2l-demo-page-settings>
144
77
  </header>
145
78
  <main class="${classMap(classes)}">
146
79
  <div class="d2l-demo-page-content" @d2l-demo-snippet-fullscreen-toggle="${this.#handleFullscreenToggle}"><slot></slot></div>
@@ -148,41 +81,6 @@ class DemoPage extends LitElement {
148
81
  `;
149
82
  }
150
83
 
151
- #handleFlagsKnownBound;
152
-
153
- #getKnownFlagsSorted() {
154
- return new Map([...getKnownFlags().entries()].sort((entry1, entry2) => {
155
- const key1 = entry1[0].toLowerCase();
156
- const key2 = entry2[0].toLowerCase();
157
- if (key1 < key2) return -1;
158
- else if (key1 > key2) return 1;
159
- else return 0;
160
- }));
161
- }
162
-
163
- #handleApplyFlagsClick() {
164
- const urlParams = new URLSearchParams(window.location.search);
165
- const elems = [...this.shadowRoot.querySelectorAll('#flagsCheckboxGroup > d2l-input-checkbox')];
166
-
167
- const knownFlags = getKnownFlags();
168
- elems.forEach(elem => {
169
- const key = elem.dataset.flagKey;
170
- const flag = knownFlags.get(key);
171
-
172
- if (flag.defaultValue === elem.checked) {
173
- urlParams.delete(`demo-flag-${key}`);
174
- } else if (flag.defaultValue !== elem.checked) {
175
- urlParams.set(`demo-flag-${key}`, elem.checked);
176
- }
177
- });
178
-
179
- window.location.search = urlParams.toString();
180
- }
181
-
182
- #handleFlagsKnown() {
183
- this.requestUpdate();
184
- }
185
-
186
84
  async #handleFullscreenToggle() {
187
85
  if (this._noScroll) {
188
86
  this._noScroll = false;
@@ -195,12 +93,6 @@ class DemoPage extends LitElement {
195
93
  }
196
94
  }
197
95
 
198
- #handleLanguageChange(e) {
199
- const newLanguageCode = e.target[e.target.selectedIndex].value;
200
- document.documentElement.dir = newLanguageCode === 'ar-sa' ? 'rtl' : 'ltr';
201
- document.documentElement.lang = newLanguageCode;
202
- }
203
-
204
96
  }
205
97
 
206
98
  customElements.define('d2l-demo-page', DemoPage);
@@ -2082,6 +2082,23 @@
2082
2082
  }
2083
2083
  ]
2084
2084
  },
2085
+ {
2086
+ "name": "d2l-demo-page-settings",
2087
+ "path": "./components/demo/demo-page-settings.js",
2088
+ "attributes": [
2089
+ {
2090
+ "name": "panel-title",
2091
+ "type": "string"
2092
+ }
2093
+ ],
2094
+ "properties": [
2095
+ {
2096
+ "name": "panelTitle",
2097
+ "attribute": "panel-title",
2098
+ "type": "string"
2099
+ }
2100
+ ]
2101
+ },
2085
2102
  {
2086
2103
  "name": "d2l-demo-page",
2087
2104
  "path": "./components/demo/demo-page.js",
package/lang/th.js CHANGED
@@ -3,7 +3,7 @@ export default {
3
3
  "components.breadcrumbs.breadcrumb": "แถบนำทาง",
4
4
  "components.button-add.addItem": "เพิ่มรายการ",
5
5
  "components.button-copy.copied": "คัดลอกแล้ว!",
6
- "components.button-copy.error": "Copy failed. Try again, or try copying manually.",
6
+ "components.button-copy.error": "การคัดลอกล้มเหลว ลองอีกครั้ง หรือลองคัดลอกด้วยตนเอง",
7
7
  "components.button-split.otherOptions": "ตัวเลือกอื่น",
8
8
  "components.calendar.hasEvents": "มีกิจกรรม",
9
9
  "components.calendar.notSelected": "ยังไม่ได้เลือก",
@@ -114,7 +114,7 @@ export default {
114
114
  "components.input-date-time-range-to.to": "ถึง",
115
115
  "components.input-number.hintDecimalDuplicate": "มีทศนิยมอยู่ในตัวเลขนี้แล้ว",
116
116
  "components.input-number.hintDecimalIncorrectComma": "หากต้องการเพิ่มทศนิยม ใช้อักขระเครื่องหมายจุลภาค “,”",
117
- "components.input-number.hintDecimalIncorrectPeriod": "หากต้องการเพิ่มทศนิยม ใช้อักขระจุด “.”",
117
+ "components.input-number.hintDecimalIncorrectPeriod": "หากต้องการเพิ่มทศนิยม ใช้อักขระเครื่องหมายจุด “.”",
118
118
  "components.input-number.hintInteger": "ฟิลด์นี้ยอมรับค่าจำนวนเต็มเท่านั้น (ไม่ใช้ทศนิยม)",
119
119
  "components.input-search.clear": "ล้างการค้นหา",
120
120
  "components.input-search.defaultPlaceholder": "ค้นหา...",
@@ -157,8 +157,8 @@ export default {
157
157
  "components.pager-load-more.action": "โหลดเพิ่มเติม",
158
158
  "components.pager-load-more.action-with-page-size": "โหลดเพิ่ม {count} รายการ",
159
159
  "components.pager-load-more.status-loading": "กำลังโหลดรายการเพิ่มเติม",
160
- "components.scroll-wrapper.scroll-left": "Scroll left",
161
- "components.scroll-wrapper.scroll-right": "Scroll right",
160
+ "components.scroll-wrapper.scroll-left": "เลื่อนไปทางซ้าย",
161
+ "components.scroll-wrapper.scroll-right": "เลื่อนไปทางขวา",
162
162
  "components.selection.action-max-hint":
163
163
  `{count, plural,
164
164
  other {ปิดใช้งานเมื่อเลือกมากกว่า {countFormatted} รายการ}
@@ -167,13 +167,14 @@ export default {
167
167
  "components.selection.select-all": "เลือกทั้งหมด",
168
168
  "components.selection.select-all-items":
169
169
  `{count, plural,
170
+ =1 {เลือกรายการ}
170
171
  other {เลือกทั้ง {countFormatted} รายการ}
171
172
  }`,
172
173
  "components.selection.selected": "{count} ที่เลือกแล้ว",
173
174
  "components.selection.selected-plus": "{count}+ ที่เลือกแล้ว",
174
175
  "components.selection-controls.label": "การดำเนินการสำหรับการเลือก",
175
- "components.sort.label": "Sort",
176
- "components.sort.text": "Sort: {selectedItemText}",
176
+ "components.sort.label": "เรียงลำดับ",
177
+ "components.sort.text": "เรียงลำดับ: {selectedItemText}",
177
178
  "components.switch.conditions": "ต้องตรงตามเงื่อนไข",
178
179
  "components.switch.hidden": "ซ่อนอยู่",
179
180
  "components.switch.visible": "มองเห็นได้",
@@ -211,8 +212,8 @@ export default {
211
212
  "components.tag-list.num-hidden": "+ อีก {count} รายการ",
212
213
  "components.tag-list.role-description":
213
214
  `{count, plural,
214
- =0 {Tag List with 0 items}
215
- other {Tag List with {count} items}
215
+ =0 {แท็กรายการที่มี 0 รายการ}
216
+ other {แท็กรายการที่มี {count} รายการ}
216
217
  }`,
217
218
  "components.tag-list.show-less": "แสดงน้อยลง",
218
219
  "components.tag-list.show-more-description": "เลือกเพื่อแสดงรายการแท็กที่ซ่อนอยู่",
package/lang/vi.js CHANGED
@@ -3,7 +3,7 @@ export default {
3
3
  "components.breadcrumbs.breadcrumb": "Breadcrumb",
4
4
  "components.button-add.addItem": "Thêm mục",
5
5
  "components.button-copy.copied": "Đã sao chép!",
6
- "components.button-copy.error": "Copy failed. Try again, or try copying manually.",
6
+ "components.button-copy.error": "Sao chép không thành công. Hãy thử lại hoặc thử sao chép thủ công.",
7
7
  "components.button-split.otherOptions": "Các lựa chọn khác",
8
8
  "components.calendar.hasEvents": "Có các sự kiện.",
9
9
  "components.calendar.notSelected": "Không được chọn.",
@@ -157,8 +157,8 @@ export default {
157
157
  "components.pager-load-more.action": "Tải thêm",
158
158
  "components.pager-load-more.action-with-page-size": "Tải thêm {count} mục",
159
159
  "components.pager-load-more.status-loading": "Đang tải thêm các mục",
160
- "components.scroll-wrapper.scroll-left": "Scroll left",
161
- "components.scroll-wrapper.scroll-right": "Scroll right",
160
+ "components.scroll-wrapper.scroll-left": "Cuộn trái",
161
+ "components.scroll-wrapper.scroll-right": "Cuộn phải",
162
162
  "components.selection.action-max-hint":
163
163
  `{count, plural,
164
164
  other {Vô hiệu hóa khi chọn nhiều hơn {countFormatted} mục}
@@ -167,13 +167,14 @@ export default {
167
167
  "components.selection.select-all": "Chọn tất cả",
168
168
  "components.selection.select-all-items":
169
169
  `{count, plural,
170
- other {Chọn tất cả các mục {countFormatted}}
170
+ =1 {Chọn mục}
171
+ other {Chọn tất cả {countFormatted} mục}
171
172
  }`,
172
173
  "components.selection.selected": "{count} mục được chọn",
173
174
  "components.selection.selected-plus": "{count}+ mục được chọn",
174
175
  "components.selection-controls.label": "Các thao tác để chọn",
175
- "components.sort.label": "Sort",
176
- "components.sort.text": "Sort: {selectedItemText}",
176
+ "components.sort.label": "Sắp xếp",
177
+ "components.sort.text": "Sắp xếp: {selectedItemText}",
177
178
  "components.switch.conditions": "Phải đáp ứng các điều kiện",
178
179
  "components.switch.hidden": "Bị ẩn",
179
180
  "components.switch.visible": "Nhìn thấy được",
@@ -211,8 +212,8 @@ export default {
211
212
  "components.tag-list.num-hidden": "+ {count} mục nữa",
212
213
  "components.tag-list.role-description":
213
214
  `{count, plural,
214
- =0 {Tag List with 0 items}
215
- other {Tag List with {count} items}
215
+ =0 {Danh sách thẻ với 0 mục}
216
+ other {Danh sách thẻ với {count} mục}
216
217
  }`,
217
218
  "components.tag-list.show-less": "Ẩn bớt",
218
219
  "components.tag-list.show-more-description": "Chọn để hiển thị các mục danh sách thẻ ẩn",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "3.175.4",
3
+ "version": "3.176.0",
4
4
  "description": "A collection of accessible, free, open-source web components for building Brightspace applications",
5
5
  "type": "module",
6
6
  "repository": "https://github.com/BrightspaceUI/core.git",
@@ -54,7 +54,7 @@
54
54
  "chalk": "^5",
55
55
  "eslint": "^9",
56
56
  "eslint-config-brightspace": "^2.0.0",
57
- "eslint-plugin-unicorn": "^61",
57
+ "eslint-plugin-unicorn": "^62",
58
58
  "glob-all": "^3",
59
59
  "messageformat-validator": "^3.0.0-beta",
60
60
  "rollup": "^4",