polaris_view_components 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -2
  3. data/app/assets/javascripts/polaris_view_components/autocomplete_controller.js +119 -0
  4. data/app/assets/javascripts/polaris_view_components/button_controller.js +4 -5
  5. data/app/assets/javascripts/polaris_view_components/frame_controller.js +41 -0
  6. data/app/assets/javascripts/polaris_view_components/index.js +9 -1
  7. data/app/assets/javascripts/polaris_view_components/option_list_controller.js +41 -0
  8. data/app/assets/javascripts/polaris_view_components/polaris_controller.js +4 -0
  9. data/app/assets/javascripts/polaris_view_components/popover_controller.js +6 -2
  10. data/app/assets/javascripts/polaris_view_components/text_field_controller.js +4 -0
  11. data/app/assets/javascripts/polaris_view_components/toast_controller.js +68 -0
  12. data/app/assets/javascripts/polaris_view_components.js +415 -18
  13. data/app/assets/stylesheets/polaris_view_components/custom.css +41 -0
  14. data/app/assets/stylesheets/polaris_view_components.css +25 -0
  15. data/app/components/polaris/autocomplete/action_component.rb +7 -0
  16. data/app/components/polaris/autocomplete/option_component.rb +35 -0
  17. data/app/components/polaris/autocomplete/section_component.html.erb +9 -0
  18. data/app/components/polaris/autocomplete/section_component.rb +12 -0
  19. data/app/components/polaris/autocomplete_component.html.erb +30 -0
  20. data/app/components/polaris/autocomplete_component.rb +58 -0
  21. data/app/components/polaris/base_checkbox.rb +48 -0
  22. data/app/components/polaris/base_radio_button.rb +38 -0
  23. data/app/components/polaris/checkbox_component.html.erb +1 -5
  24. data/app/components/polaris/checkbox_component.rb +15 -8
  25. data/app/components/polaris/choice_list_component.rb +1 -1
  26. data/app/components/polaris/filters_component.html.erb +22 -0
  27. data/app/components/polaris/filters_component.rb +57 -4
  28. data/app/components/polaris/frame/save_bar_component.html.erb +23 -0
  29. data/app/components/polaris/frame/save_bar_component.rb +31 -0
  30. data/app/components/polaris/frame/top_bar_component.html.erb +30 -0
  31. data/app/components/polaris/frame/top_bar_component.rb +18 -0
  32. data/app/components/polaris/frame_component.html.erb +44 -0
  33. data/app/components/polaris/frame_component.rb +33 -0
  34. data/app/components/polaris/logo.rb +13 -0
  35. data/app/components/polaris/navigation/item_component.html.erb +31 -0
  36. data/app/components/polaris/navigation/item_component.rb +85 -0
  37. data/app/components/polaris/navigation/section_component.html.erb +17 -0
  38. data/app/components/polaris/navigation/section_component.rb +64 -0
  39. data/app/components/polaris/navigation_component.html.erb +29 -0
  40. data/app/components/polaris/navigation_component.rb +15 -0
  41. data/app/components/polaris/option_list/checkbox_component.html.erb +14 -0
  42. data/app/components/polaris/option_list/checkbox_component.rb +37 -0
  43. data/app/components/polaris/option_list/option_component.rb +24 -0
  44. data/app/components/polaris/option_list/radio_button_component.rb +54 -0
  45. data/app/components/polaris/option_list/section_component.html.erb +14 -0
  46. data/app/components/polaris/option_list/section_component.rb +53 -0
  47. data/app/components/polaris/option_list_component.html.erb +15 -0
  48. data/app/components/polaris/option_list_component.rb +67 -0
  49. data/app/components/polaris/popover_component.html.erb +2 -9
  50. data/app/components/polaris/popover_component.rb +17 -0
  51. data/app/components/polaris/radio_button_component.html.erb +1 -6
  52. data/app/components/polaris/radio_button_component.rb +14 -4
  53. data/app/components/polaris/text_field_component.rb +16 -2
  54. data/app/components/polaris/toast_component.html.erb +21 -0
  55. data/app/components/polaris/toast_component.rb +40 -0
  56. data/app/components/polaris/top_bar/user_menu_component.html.erb +19 -0
  57. data/app/components/polaris/top_bar/user_menu_component.rb +9 -0
  58. data/app/helpers/polaris/form_builder.rb +2 -2
  59. data/app/helpers/polaris/view_helper.rb +11 -0
  60. data/lib/polaris/view_components/engine.rb +5 -1
  61. data/lib/polaris/view_components/version.rb +1 -1
  62. metadata +46 -9
@@ -1,21 +1,125 @@
1
1
  import { Controller } from "@hotwired/stimulus";
2
2
 
3
+ import { get } from "@rails/request.js";
4
+
5
+ class Autocomplete extends Controller {
6
+ static targets=[ "popover", "input", "results", "option", "emptyState" ];
7
+ static values={
8
+ url: String
9
+ };
10
+ connect() {
11
+ this.inputTarget.addEventListener("input", this.onInputChange);
12
+ }
13
+ disconnect() {
14
+ this.inputTarget.removeEventListener("input", this.onInputChange);
15
+ }
16
+ toggle() {
17
+ if (this.visibleOptions.length > 0) {
18
+ this.hideEmptyState();
19
+ this.popoverController.show();
20
+ } else if (this.value.length > 0 && this.hasEmptyStateTarget) {
21
+ this.showEmptyState();
22
+ } else {
23
+ this.popoverController.forceHide();
24
+ }
25
+ }
26
+ select(event) {
27
+ const input = event.currentTarget;
28
+ const label = input.closest("li").dataset.label;
29
+ const changeEvent = new CustomEvent("polaris-autocomplete:change", {
30
+ detail: {
31
+ value: input.value,
32
+ label: label,
33
+ selected: input.checked
34
+ }
35
+ });
36
+ this.element.dispatchEvent(changeEvent);
37
+ }
38
+ onInputChange=debounce$1((() => {
39
+ if (this.isRemote) {
40
+ this.fetchResults();
41
+ } else {
42
+ this.filterOptions();
43
+ }
44
+ }), 200);
45
+ get isRemote() {
46
+ return this.urlValue.length > 0;
47
+ }
48
+ get popoverController() {
49
+ return this.application.getControllerForElementAndIdentifier(this.popoverTarget, "polaris-popover");
50
+ }
51
+ get value() {
52
+ return this.inputTarget.value;
53
+ }
54
+ get visibleOptions() {
55
+ return this.optionTargets.filter((option => !option.classList.contains("Polaris--hidden")));
56
+ }
57
+ filterOptions() {
58
+ if (this.value === "") {
59
+ this.optionTargets.forEach((option => {
60
+ option.classList.remove("Polaris--hidden");
61
+ }));
62
+ } else {
63
+ const filterRegex = new RegExp(this.value, "i");
64
+ this.optionTargets.forEach((option => {
65
+ if (option.dataset.label.match(filterRegex)) {
66
+ option.classList.remove("Polaris--hidden");
67
+ } else {
68
+ option.classList.add("Polaris--hidden");
69
+ }
70
+ }));
71
+ }
72
+ this.toggle();
73
+ }
74
+ async fetchResults() {
75
+ const response = await get(this.urlValue, {
76
+ query: {
77
+ q: this.value
78
+ }
79
+ });
80
+ if (response.ok) {
81
+ const results = await response.html;
82
+ this.resultsTarget.innerHTML = results;
83
+ this.toggle();
84
+ }
85
+ }
86
+ showEmptyState() {
87
+ if (this.hasEmptyStateTarget) {
88
+ this.resultsTarget.classList.add("Polaris--hidden");
89
+ this.emptyStateTarget.classList.remove("Polaris--hidden");
90
+ }
91
+ }
92
+ hideEmptyState() {
93
+ if (this.hasEmptyStateTarget) {
94
+ this.emptyStateTarget.classList.add("Polaris--hidden");
95
+ this.resultsTarget.classList.remove("Polaris--hidden");
96
+ }
97
+ }
98
+ }
99
+
100
+ const debounce$1 = (fn, delay = 10) => {
101
+ let timeoutId = null;
102
+ return (...args) => {
103
+ clearTimeout(timeoutId);
104
+ timeoutId = setTimeout(fn, delay);
105
+ };
106
+ };
107
+
3
108
  class Button extends Controller {
4
109
  disable(event) {
5
- if (this.button.dataset.disabled) {
110
+ if (this.button.disabled) {
6
111
  event.preventDefault();
7
112
  } else {
8
- this.button.dataset.disabled = true;
113
+ this.button.disabled = true;
9
114
  this.button.classList.add("Polaris-Button--disabled", "Polaris-Button--loading");
10
115
  this.buttonContent.insertAdjacentHTML("afterbegin", this.spinnerHTML);
11
116
  }
12
117
  }
13
118
  enable() {
14
- if (this.button.dataset.disabled) {
119
+ if (this.button.disabled) {
15
120
  this.button.disabled = false;
16
- delete this.button.dataset.disabled;
17
121
  this.button.classList.remove("Polaris-Button--disabled", "Polaris-Button--loading");
18
- this.spinner.remove();
122
+ if (this.spinner) this.spinner.remove();
19
123
  }
20
124
  }
21
125
  get button() {
@@ -32,6 +136,196 @@ class Button extends Controller {
32
136
  }
33
137
  }
34
138
 
139
+ const alpineNames = {
140
+ enterFromClass: "enter",
141
+ enterActiveClass: "enterStart",
142
+ enterToClass: "enterEnd",
143
+ leaveFromClass: "leave",
144
+ leaveActiveClass: "leaveStart",
145
+ leaveToClass: "leaveEnd"
146
+ };
147
+
148
+ const defaultOptions = {
149
+ transitioned: false,
150
+ hiddenClass: "hidden",
151
+ preserveOriginalClass: true,
152
+ removeToClasses: true
153
+ };
154
+
155
+ const useTransition = (controller, options = {}) => {
156
+ var _a, _b, _c;
157
+ const targetName = controller.element.dataset.transitionTarget;
158
+ let targetFromAttribute;
159
+ if (targetName) {
160
+ targetFromAttribute = controller[`${targetName}Target`];
161
+ }
162
+ const targetElement = (options === null || options === void 0 ? void 0 : options.element) || targetFromAttribute || controller.element;
163
+ if (!(targetElement instanceof HTMLElement || targetElement instanceof SVGElement)) return;
164
+ const dataset = targetElement.dataset;
165
+ const leaveAfter = parseInt(dataset.leaveAfter || "") || options.leaveAfter || 0;
166
+ const {transitioned: transitioned, hiddenClass: hiddenClass, preserveOriginalClass: preserveOriginalClass, removeToClasses: removeToClasses} = Object.assign(defaultOptions, options);
167
+ const controllerEnter = (_a = controller.enter) === null || _a === void 0 ? void 0 : _a.bind(controller);
168
+ const controllerLeave = (_b = controller.leave) === null || _b === void 0 ? void 0 : _b.bind(controller);
169
+ const controllerToggleTransition = (_c = controller.toggleTransition) === null || _c === void 0 ? void 0 : _c.bind(controller);
170
+ async function enter(event) {
171
+ if (controller.transitioned) return;
172
+ controller.transitioned = true;
173
+ controllerEnter && controllerEnter(event);
174
+ const enterFromClasses = getAttribute("enterFrom", options, dataset);
175
+ const enterActiveClasses = getAttribute("enterActive", options, dataset);
176
+ const enterToClasses = getAttribute("enterTo", options, dataset);
177
+ const leaveToClasses = getAttribute("leaveTo", options, dataset);
178
+ if (!!hiddenClass) {
179
+ targetElement.classList.remove(hiddenClass);
180
+ }
181
+ if (!removeToClasses) {
182
+ removeClasses(targetElement, leaveToClasses);
183
+ }
184
+ await transition(targetElement, enterFromClasses, enterActiveClasses, enterToClasses, hiddenClass, preserveOriginalClass, removeToClasses);
185
+ if (leaveAfter > 0) {
186
+ setTimeout((() => {
187
+ leave(event);
188
+ }), leaveAfter);
189
+ }
190
+ }
191
+ async function leave(event) {
192
+ if (!controller.transitioned) return;
193
+ controller.transitioned = false;
194
+ controllerLeave && controllerLeave(event);
195
+ const leaveFromClasses = getAttribute("leaveFrom", options, dataset);
196
+ const leaveActiveClasses = getAttribute("leaveActive", options, dataset);
197
+ const leaveToClasses = getAttribute("leaveTo", options, dataset);
198
+ const enterToClasses = getAttribute("enterTo", options, dataset);
199
+ if (!removeToClasses) {
200
+ removeClasses(targetElement, enterToClasses);
201
+ }
202
+ await transition(targetElement, leaveFromClasses, leaveActiveClasses, leaveToClasses, hiddenClass, preserveOriginalClass, removeToClasses);
203
+ if (!!hiddenClass) {
204
+ targetElement.classList.add(hiddenClass);
205
+ }
206
+ }
207
+ function toggleTransition(event) {
208
+ controllerToggleTransition && controllerToggleTransition(event);
209
+ if (controller.transitioned) {
210
+ leave();
211
+ } else {
212
+ enter();
213
+ }
214
+ }
215
+ async function transition(element, initialClasses, activeClasses, endClasses, hiddenClass, preserveOriginalClass, removeEndClasses) {
216
+ const stashedClasses = [];
217
+ if (preserveOriginalClass) {
218
+ initialClasses.forEach((cls => element.classList.contains(cls) && cls !== hiddenClass && stashedClasses.push(cls)));
219
+ activeClasses.forEach((cls => element.classList.contains(cls) && cls !== hiddenClass && stashedClasses.push(cls)));
220
+ endClasses.forEach((cls => element.classList.contains(cls) && cls !== hiddenClass && stashedClasses.push(cls)));
221
+ }
222
+ addClasses(element, initialClasses);
223
+ removeClasses(element, stashedClasses);
224
+ addClasses(element, activeClasses);
225
+ await nextAnimationFrame();
226
+ removeClasses(element, initialClasses);
227
+ addClasses(element, endClasses);
228
+ await afterTransition(element);
229
+ removeClasses(element, activeClasses);
230
+ if (removeEndClasses) {
231
+ removeClasses(element, endClasses);
232
+ }
233
+ addClasses(element, stashedClasses);
234
+ }
235
+ function initialState() {
236
+ controller.transitioned = transitioned;
237
+ if (transitioned) {
238
+ if (!!hiddenClass) {
239
+ targetElement.classList.remove(hiddenClass);
240
+ }
241
+ enter();
242
+ } else {
243
+ if (!!hiddenClass) {
244
+ targetElement.classList.add(hiddenClass);
245
+ }
246
+ leave();
247
+ }
248
+ }
249
+ function addClasses(element, classes) {
250
+ if (classes.length > 0) {
251
+ element.classList.add(...classes);
252
+ }
253
+ }
254
+ function removeClasses(element, classes) {
255
+ if (classes.length > 0) {
256
+ element.classList.remove(...classes);
257
+ }
258
+ }
259
+ initialState();
260
+ Object.assign(controller, {
261
+ enter: enter,
262
+ leave: leave,
263
+ toggleTransition: toggleTransition
264
+ });
265
+ return [ enter, leave, toggleTransition ];
266
+ };
267
+
268
+ function getAttribute(name, options, dataset) {
269
+ const datasetName = `transition${name[0].toUpperCase()}${name.substr(1)}`;
270
+ const datasetAlpineName = alpineNames[name];
271
+ const classes = options[name] || dataset[datasetName] || dataset[datasetAlpineName] || " ";
272
+ return isEmpty(classes) ? [] : classes.split(" ");
273
+ }
274
+
275
+ async function afterTransition(element) {
276
+ return new Promise((resolve => {
277
+ const duration = Number(getComputedStyle(element).transitionDuration.split(",")[0].replace("s", "")) * 1e3;
278
+ setTimeout((() => {
279
+ resolve(duration);
280
+ }), duration);
281
+ }));
282
+ }
283
+
284
+ async function nextAnimationFrame() {
285
+ return new Promise((resolve => {
286
+ requestAnimationFrame((() => {
287
+ requestAnimationFrame(resolve);
288
+ }));
289
+ }));
290
+ }
291
+
292
+ function isEmpty(str) {
293
+ return str.length === 0 || !str.trim();
294
+ }
295
+
296
+ class Frame extends Controller {
297
+ static targets=[ "navigationOverlay", "navigation", "saveBar" ];
298
+ connect() {
299
+ if (!this.hasNavigationTarget) {
300
+ return;
301
+ }
302
+ useTransition(this, {
303
+ element: this.navigationTarget,
304
+ enterFrom: "Polaris-Frame__Navigation--enter",
305
+ enterTo: "Polaris-Frame__Navigation--visible Polaris-Frame__Navigation--enterActive",
306
+ leaveActive: "Polaris-Frame__Navigation--exitActive",
307
+ leaveFrom: "Polaris-Frame__Navigation--exit",
308
+ leaveTo: "",
309
+ removeToClasses: false,
310
+ hiddenClass: false
311
+ });
312
+ }
313
+ openMenu() {
314
+ this.enter();
315
+ this.navigationOverlayTarget.classList.add("Polaris-Backdrop", "Polaris-Backdrop--belowNavigation");
316
+ }
317
+ closeMenu() {
318
+ this.leave();
319
+ this.navigationOverlayTarget.classList.remove("Polaris-Backdrop", "Polaris-Backdrop--belowNavigation");
320
+ }
321
+ showSaveBar() {
322
+ this.saveBarTarget.classList.add("Polaris-Frame-CSSAnimation--endFade");
323
+ }
324
+ hideSaveBar() {
325
+ this.saveBarTarget.classList.remove("Polaris-Frame-CSSAnimation--endFade");
326
+ }
327
+ }
328
+
35
329
  class Modal extends Controller {
36
330
  static classes=[ "hidden", "backdrop" ];
37
331
  static values={
@@ -53,6 +347,38 @@ class Modal extends Controller {
53
347
  }
54
348
  }
55
349
 
350
+ class OptionList extends Controller {
351
+ static targets=[ "radioButton" ];
352
+ static classes=[ "selected" ];
353
+ connect() {
354
+ this.updateSelected();
355
+ }
356
+ update(event) {
357
+ const target = event.currentTarget;
358
+ target.classList.add(this.selectedClass);
359
+ this.deselectAll(target);
360
+ }
361
+ updateSelected() {
362
+ this.radioButtonTargets.forEach((element => {
363
+ const input = element.querySelector("input[type=radio]");
364
+ if (input.checked) {
365
+ element.classList.add(this.selectedClass);
366
+ } else {
367
+ element.classList.remove(this.selectedClass);
368
+ }
369
+ }));
370
+ }
371
+ deselectAll(target) {
372
+ this.radioButtonTargets.forEach((element => {
373
+ if (!element.isEqualNode(target)) {
374
+ const input = element.querySelector("input[type=radio]");
375
+ input.checked = false;
376
+ element.classList.remove(this.selectedClass);
377
+ }
378
+ }));
379
+ }
380
+ }
381
+
56
382
  class Polaris extends Controller {
57
383
  openModal() {
58
384
  this.findElement("modal").open();
@@ -63,6 +389,9 @@ class Polaris extends Controller {
63
389
  enableButton() {
64
390
  this.findElement("button").enable();
65
391
  }
392
+ showToast() {
393
+ this.findElement("toast").show();
394
+ }
66
395
  findElement(type) {
67
396
  const targetId = this.element.dataset.target.replace("#", "");
68
397
  const target = document.getElementById(targetId);
@@ -279,7 +608,7 @@ function contains(parent, child) {
279
608
  return false;
280
609
  }
281
610
 
282
- function getComputedStyle(element) {
611
+ function getComputedStyle$1(element) {
283
612
  return getWindow(element).getComputedStyle(element);
284
613
  }
285
614
 
@@ -299,7 +628,7 @@ function getParentNode(element) {
299
628
  }
300
629
 
301
630
  function getTrueOffsetParent(element) {
302
- if (!isHTMLElement(element) || getComputedStyle(element).position === "fixed") {
631
+ if (!isHTMLElement(element) || getComputedStyle$1(element).position === "fixed") {
303
632
  return null;
304
633
  }
305
634
  return element.offsetParent;
@@ -309,14 +638,14 @@ function getContainingBlock(element) {
309
638
  var isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") !== -1;
310
639
  var isIE = navigator.userAgent.indexOf("Trident") !== -1;
311
640
  if (isIE && isHTMLElement(element)) {
312
- var elementCss = getComputedStyle(element);
641
+ var elementCss = getComputedStyle$1(element);
313
642
  if (elementCss.position === "fixed") {
314
643
  return null;
315
644
  }
316
645
  }
317
646
  var currentNode = getParentNode(element);
318
647
  while (isHTMLElement(currentNode) && [ "html", "body" ].indexOf(getNodeName(currentNode)) < 0) {
319
- var css = getComputedStyle(currentNode);
648
+ var css = getComputedStyle$1(currentNode);
320
649
  if (css.transform !== "none" || css.perspective !== "none" || css.contain === "paint" || [ "transform", "perspective" ].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === "filter" || isFirefox && css.filter && css.filter !== "none") {
321
650
  return currentNode;
322
651
  } else {
@@ -329,10 +658,10 @@ function getContainingBlock(element) {
329
658
  function getOffsetParent(element) {
330
659
  var window = getWindow(element);
331
660
  var offsetParent = getTrueOffsetParent(element);
332
- while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === "static") {
661
+ while (offsetParent && isTableElement(offsetParent) && getComputedStyle$1(offsetParent).position === "static") {
333
662
  offsetParent = getTrueOffsetParent(offsetParent);
334
663
  }
335
- if (offsetParent && (getNodeName(offsetParent) === "html" || getNodeName(offsetParent) === "body" && getComputedStyle(offsetParent).position === "static")) {
664
+ if (offsetParent && (getNodeName(offsetParent) === "html" || getNodeName(offsetParent) === "body" && getComputedStyle$1(offsetParent).position === "static")) {
336
665
  return window;
337
666
  }
338
667
  return offsetParent || getContainingBlock(element) || window;
@@ -473,7 +802,7 @@ function mapToStyles(_ref2) {
473
802
  var widthProp = "clientWidth";
474
803
  if (offsetParent === getWindow(popper)) {
475
804
  offsetParent = getDocumentElement(popper);
476
- if (getComputedStyle(offsetParent).position !== "static" && position === "absolute") {
805
+ if (getComputedStyle$1(offsetParent).position !== "static" && position === "absolute") {
477
806
  heightProp = "scrollHeight";
478
807
  widthProp = "scrollWidth";
479
808
  }
@@ -651,7 +980,7 @@ function getDocumentRect(element) {
651
980
  var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);
652
981
  var x = -winScroll.scrollLeft + getWindowScrollBarX(element);
653
982
  var y = -winScroll.scrollTop;
654
- if (getComputedStyle(body || html).direction === "rtl") {
983
+ if (getComputedStyle$1(body || html).direction === "rtl") {
655
984
  x += max(html.clientWidth, body ? body.clientWidth : 0) - width;
656
985
  }
657
986
  return {
@@ -663,7 +992,7 @@ function getDocumentRect(element) {
663
992
  }
664
993
 
665
994
  function isScrollParent(element) {
666
- var _getComputedStyle = getComputedStyle(element), overflow = _getComputedStyle.overflow, overflowX = _getComputedStyle.overflowX, overflowY = _getComputedStyle.overflowY;
995
+ var _getComputedStyle = getComputedStyle$1(element), overflow = _getComputedStyle.overflow, overflowX = _getComputedStyle.overflowX, overflowY = _getComputedStyle.overflowY;
667
996
  return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);
668
997
  }
669
998
 
@@ -718,7 +1047,7 @@ function getClientRectFromMixedType(element, clippingParent) {
718
1047
 
719
1048
  function getClippingParents(element) {
720
1049
  var clippingParents = listScrollParents(getParentNode(element));
721
- var canEscapeClipping = [ "absolute", "fixed" ].indexOf(getComputedStyle(element).position) >= 0;
1050
+ var canEscapeClipping = [ "absolute", "fixed" ].indexOf(getComputedStyle$1(element).position) >= 0;
722
1051
  var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;
723
1052
  if (!isElement(clipperElement)) {
724
1053
  return [];
@@ -1469,10 +1798,13 @@ class Popover extends Controller {
1469
1798
  }
1470
1799
  hide(event) {
1471
1800
  if (!this.element.contains(event.target) && !this.popoverTarget.classList.contains(this.closedClass)) {
1472
- this.popoverTarget.classList.remove(this.openClass);
1473
- this.popoverTarget.classList.add(this.closedClass);
1801
+ this.forceHide();
1474
1802
  }
1475
1803
  }
1804
+ forceHide() {
1805
+ this.popoverTarget.classList.remove(this.openClass);
1806
+ this.popoverTarget.classList.add(this.closedClass);
1807
+ }
1476
1808
  }
1477
1809
 
1478
1810
  class ResourceItem extends Controller {
@@ -1622,20 +1954,85 @@ class TextField extends Controller {
1622
1954
  return;
1623
1955
  }
1624
1956
  const decimalPlaces = Math.max(dpl(numericValue), dpl(this.stepValue));
1957
+ const oldValue = this.value;
1625
1958
  const newValue = Math.min(Number(this.maxValue), Math.max(numericValue + steps * this.stepValue, Number(this.minValue)));
1626
1959
  this.value = String(newValue.toFixed(decimalPlaces));
1960
+ if (this.value != oldValue) {
1961
+ this.inputTarget.dispatchEvent(new Event("change"));
1962
+ }
1963
+ }
1964
+ }
1965
+
1966
+ class Toast extends Controller {
1967
+ static activeClass="Polaris-Frame-ToastManager--toastWrapperEnterDone";
1968
+ static defaultDuration=5e3;
1969
+ static defaultDurationWithAction=1e4;
1970
+ static values={
1971
+ hidden: Boolean,
1972
+ duration: Number,
1973
+ hasAction: Boolean
1974
+ };
1975
+ connect() {
1976
+ if (!this.hiddenValue) {
1977
+ this.show();
1978
+ }
1979
+ }
1980
+ show=() => {
1981
+ this.element.dataset.position = this.position;
1982
+ this.element.style.cssText = this.getStyle(this.position);
1983
+ this.element.classList.add(this.constructor.activeClass);
1984
+ setTimeout(this.close, this.timeoutDuration);
1985
+ };
1986
+ close=() => {
1987
+ this.element.classList.remove(this.constructor.activeClass);
1988
+ this.element.addEventListener("transitionend", this.updatePositions, false);
1989
+ };
1990
+ updatePositions=() => {
1991
+ this.visibleToasts.sort(((a, b) => parseInt(a.dataset.position) - parseInt(b.dataset.position))).forEach(((toast, index) => {
1992
+ const position = index + 1;
1993
+ toast.dataset.position = position;
1994
+ toast.style.cssText = this.getStyle(position);
1995
+ }));
1996
+ this.element.removeEventListener("transitionend", this.updatePositions, false);
1997
+ };
1998
+ getStyle(position) {
1999
+ const translateIn = -80 * position;
2000
+ const translateOut = 150 - 80 * position;
2001
+ return `--toast-translate-y-in: ${translateIn}px; --toast-translate-y-out: ${translateOut}px;`;
2002
+ }
2003
+ get timeoutDuration() {
2004
+ if (this.durationValue > 0) {
2005
+ return this.durationValue;
2006
+ } else if (this.hasActionValue) {
2007
+ return this.constructor.defaultDurationWithAction;
2008
+ } else {
2009
+ return this.constructor.defaultDuration;
2010
+ }
2011
+ }
2012
+ get toastManager() {
2013
+ return this.element.closest(".Polaris-Frame-ToastManager");
2014
+ }
2015
+ get visibleToasts() {
2016
+ return [ ...this.toastManager.querySelectorAll(`.${this.constructor.activeClass}`) ];
2017
+ }
2018
+ get position() {
2019
+ return this.visibleToasts.filter((el => !this.element.isEqualNode(el))).length + 1;
1627
2020
  }
1628
2021
  }
1629
2022
 
1630
2023
  function registerPolarisControllers(application) {
2024
+ application.register("polaris-autocomplete", Autocomplete);
1631
2025
  application.register("polaris-button", Button);
2026
+ application.register("polaris-frame", Frame);
1632
2027
  application.register("polaris-modal", Modal);
2028
+ application.register("polaris-option-list", OptionList);
1633
2029
  application.register("polaris", Polaris);
1634
2030
  application.register("polaris-popover", Popover);
1635
2031
  application.register("polaris-resource-item", ResourceItem);
1636
2032
  application.register("polaris-scrollable", Scrollable);
1637
2033
  application.register("polaris-select", Select);
1638
2034
  application.register("polaris-text-field", TextField);
2035
+ application.register("polaris-toast", Toast);
1639
2036
  }
1640
2037
 
1641
- export { Modal, Polaris, Popover, ResourceItem, Scrollable, Select, TextField, registerPolarisControllers };
2038
+ export { Frame, Modal, Polaris, Popover, ResourceItem, Scrollable, Select, TextField, registerPolarisControllers };
@@ -66,3 +66,44 @@ a.Polaris-Tag__Button {
66
66
  visibility: hidden;
67
67
  pointer-events: none;
68
68
  }
69
+
70
+ /* Filters */
71
+
72
+ .Polaris-Filters-ConnectedFilterControl__RightContainer {
73
+ .Polaris-Filters-ConnectedFilterControl__Item {
74
+ & > div > div > button {
75
+ margin-right: var(--p-button-group-item-spacing);
76
+ border-radius: 0;
77
+ }
78
+
79
+ &:first-of-type > div > div > button {
80
+ border-top-left-radius: var(--p-border-radius-base);
81
+ border-bottom-left-radius: var(--p-border-radius-base);
82
+ }
83
+ }
84
+
85
+ &.Polaris-Filters-ConnectedFilterControl--queryFieldHidden {
86
+ .Polaris-Filters-ConnectedFilterControl__Item:first-of-type > div > div > button {
87
+ border-top-left-radius: var(--p-border-radius-base);
88
+ border-bottom-left-radius: var(--p-border-radius-base);
89
+ }
90
+ }
91
+ }
92
+
93
+ .Polaris-Filters-ConnectedFilterControl__RightContainerWithoutMoreFilters {
94
+ .Polaris-Filters-ConnectedFilterControl__Item:last-child > div > div > button {
95
+ border-top-right-radius: var(--p-border-radius-base);
96
+ border-bottom-right-radius: var(--p-border-radius-base);
97
+ }
98
+ }
99
+
100
+ /* Toast */
101
+ .Polaris-Frame-ToastManager {
102
+ bottom: 0;
103
+ }
104
+
105
+ /* Autocomplete */
106
+
107
+ .Polaris-Autocomplete__EmptyState {
108
+ padding: 0.8rem 1.6rem;
109
+ }
@@ -2232,3 +2232,28 @@ a.Polaris-Tag__Button {
2232
2232
  visibility: hidden;
2233
2233
  pointer-events: none;
2234
2234
  }
2235
+ /* Filters */
2236
+ .Polaris-Filters-ConnectedFilterControl__RightContainer .Polaris-Filters-ConnectedFilterControl__Item > div > div > button {
2237
+ margin-right: var(--p-button-group-item-spacing);
2238
+ border-radius: 0;
2239
+ }
2240
+ .Polaris-Filters-ConnectedFilterControl__RightContainer .Polaris-Filters-ConnectedFilterControl__Item:first-of-type > div > div > button {
2241
+ border-top-left-radius: var(--p-border-radius-base);
2242
+ border-bottom-left-radius: var(--p-border-radius-base);
2243
+ }
2244
+ .Polaris-Filters-ConnectedFilterControl__RightContainer.Polaris-Filters-ConnectedFilterControl--queryFieldHidden .Polaris-Filters-ConnectedFilterControl__Item:first-of-type > div > div > button {
2245
+ border-top-left-radius: var(--p-border-radius-base);
2246
+ border-bottom-left-radius: var(--p-border-radius-base);
2247
+ }
2248
+ .Polaris-Filters-ConnectedFilterControl__RightContainerWithoutMoreFilters .Polaris-Filters-ConnectedFilterControl__Item:last-child > div > div > button {
2249
+ border-top-right-radius: var(--p-border-radius-base);
2250
+ border-bottom-right-radius: var(--p-border-radius-base);
2251
+ }
2252
+ /* Toast */
2253
+ .Polaris-Frame-ToastManager {
2254
+ bottom: 0;
2255
+ }
2256
+ /* Autocomplete */
2257
+ .Polaris-Autocomplete__EmptyState {
2258
+ padding: 0.8rem 1.6rem;
2259
+ }
@@ -0,0 +1,7 @@
1
+ module Polaris
2
+ class Autocomplete::ActionComponent < NewComponent
3
+ def initialize(**system_arguments)
4
+ @system_arguments = system_arguments
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ module Polaris
2
+ class Autocomplete::OptionComponent < NewComponent
3
+ def initialize(
4
+ label:,
5
+ multiple: false,
6
+ **system_arguments
7
+ )
8
+ @label = label
9
+ @multiple = multiple
10
+ @system_arguments = system_arguments
11
+ end
12
+
13
+ def system_arguments
14
+ @system_arguments.tap do |args|
15
+ args[:label] = @label
16
+
17
+ args[:wrapper_arguments] ||= {}
18
+ args[:wrapper_arguments][:data] ||= {}
19
+ args[:wrapper_arguments][:data][:polaris_autocomplete_target] = "option"
20
+ args[:wrapper_arguments][:data][:label] = @label
21
+
22
+ args[:data] ||= {}
23
+ prepend_option(args[:data], :action, "polaris-autocomplete#select")
24
+ end
25
+ end
26
+
27
+ def call
28
+ if @multiple
29
+ render OptionList::CheckboxComponent.new(**system_arguments)
30
+ else
31
+ render OptionList::RadioButtonComponent.new(**system_arguments)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ <%= render(Polaris::OptionList::SectionComponent.new(**@system_arguments)) do %>
2
+ <% if options.present? %>
3
+ <% options.each do |option| %>
4
+ <%= option %>
5
+ <% end %>
6
+ <% else %>
7
+ <%= content %>
8
+ <% end %>
9
+ <% end %>