polaris_view_components 0.6.0 → 0.7.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 (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 %>