coveragebook_components 0.5.1 → 0.5.2

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.
@@ -11636,6 +11636,40 @@ ${t4.join("\n")}`);
11636
11636
  // ../../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/index.js
11637
11637
  addEventListener("turbo:before-fetch-request", encodeMethodIntoRequestBody);
11638
11638
 
11639
+ // base/polyfills/request-submit.js
11640
+ (function(prototype) {
11641
+ if (typeof prototype.requestSubmit == "function")
11642
+ return;
11643
+ prototype.requestSubmit = function(submitter) {
11644
+ if (submitter) {
11645
+ validateSubmitter(submitter, this);
11646
+ submitter.click();
11647
+ } else {
11648
+ submitter = document.createElement("input");
11649
+ submitter.type = "submit";
11650
+ submitter.hidden = true;
11651
+ this.appendChild(submitter);
11652
+ submitter.click();
11653
+ this.removeChild(submitter);
11654
+ }
11655
+ };
11656
+ function validateSubmitter(submitter, form) {
11657
+ submitter instanceof HTMLElement || raise(TypeError, "parameter 1 is not of type 'HTMLElement'");
11658
+ submitter.type == "submit" || raise(TypeError, "The specified element is not a submit button");
11659
+ submitter.form == form || raise(
11660
+ DOMException,
11661
+ "The specified element is not owned by this form element",
11662
+ "NotFoundError"
11663
+ );
11664
+ }
11665
+ function raise(errorConstructor, message, name) {
11666
+ throw new errorConstructor(
11667
+ "Failed to execute 'requestSubmit' on 'HTMLFormElement': " + message + ".",
11668
+ name
11669
+ );
11670
+ }
11671
+ })(HTMLFormElement.prototype);
11672
+
11639
11673
  // ../../../node_modules/alpinejs/dist/module.esm.js
11640
11674
  var flushPending = false;
11641
11675
  var flushing = false;
@@ -19579,10 +19613,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
19579
19613
  this.collapsed = false;
19580
19614
  return;
19581
19615
  }
19582
- this.setTooltipText();
19583
19616
  this.$root.setAttribute("data-collapsed", collapsed ? "true" : "false");
19584
19617
  });
19585
- this.$watch("$options.state", () => this.setTooltipText());
19586
19618
  },
19587
19619
  setTooltipText() {
19588
19620
  if (this.disabled) {
@@ -19685,6 +19717,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
19685
19717
  root: {
19686
19718
  "x-options": "options",
19687
19719
  "x-tooltip": "tooltipText",
19720
+ "x-effect": "setTooltipText",
19688
19721
  "@confirmation:confirm": "approveAndRun",
19689
19722
  "@confirmation:cancel": "cancelConfirmation",
19690
19723
  "@dropdown:show": "setState('active')",
@@ -0,0 +1,39 @@
1
+ (function (prototype) {
2
+ if (typeof prototype.requestSubmit == "function") return;
3
+
4
+ prototype.requestSubmit = function (submitter) {
5
+ if (submitter) {
6
+ validateSubmitter(submitter, this);
7
+ submitter.click();
8
+ } else {
9
+ submitter = document.createElement("input");
10
+ submitter.type = "submit";
11
+ submitter.hidden = true;
12
+ this.appendChild(submitter);
13
+ submitter.click();
14
+ this.removeChild(submitter);
15
+ }
16
+ };
17
+
18
+ function validateSubmitter(submitter, form) {
19
+ submitter instanceof HTMLElement ||
20
+ raise(TypeError, "parameter 1 is not of type 'HTMLElement'");
21
+ submitter.type == "submit" ||
22
+ raise(TypeError, "The specified element is not a submit button");
23
+ submitter.form == form ||
24
+ raise(
25
+ DOMException,
26
+ "The specified element is not owned by this form element",
27
+ "NotFoundError"
28
+ );
29
+ }
30
+
31
+ function raise(errorConstructor, message, name) {
32
+ throw new errorConstructor(
33
+ "Failed to execute 'requestSubmit' on 'HTMLFormElement': " +
34
+ message +
35
+ ".",
36
+ name
37
+ );
38
+ }
39
+ })(HTMLFormElement.prototype);
@@ -2,6 +2,8 @@ import "container-query-polyfill";
2
2
  import "alpine-turbo-drive-adapter";
3
3
  import * as Turbo from "@hotwired/turbo-rails";
4
4
 
5
+ import "./polyfills/request-submit";
6
+
5
7
  import Alpine from "@libs/alpine";
6
8
 
7
9
  document.addEventListener("DOMContentLoaded", () => {
@@ -1,8 +1,13 @@
1
- import { toBlob } from "html-to-image";
1
+ import html2canvas from "html2canvas";
2
2
  import { stripExtension } from "./path";
3
3
  import { isObject } from "./lang";
4
4
  import { blobToFile } from "./file";
5
5
 
6
+ const screenshotDefaultOptions = {
7
+ useCORS: true,
8
+ logging: false,
9
+ };
10
+
6
11
  function generateScreenshotFilename(name = null, ext = null) {
7
12
  name = [stripExtension(name || "screenshot"), new Date().getTime()].join("-");
8
13
  return ext ? `${name}.${ext}` : name;
@@ -16,11 +21,22 @@ async function captureElementScreenshot(el, filename, opts = {}) {
16
21
  opts = filename;
17
22
  }
18
23
 
19
- filename = generateScreenshotFilename(filename, "jpg");
24
+ const screenshotFilename = generateScreenshotFilename(filename, "jpg");
25
+ const screenshotOptions = {
26
+ ...screenshotDefaultOptions,
27
+ ...opts,
28
+ };
20
29
 
21
- const imageBlob = await toBlob(el, opts);
30
+ const canvas = await html2canvas(el, screenshotOptions);
31
+ const imageBlob = await new Promise((resolve, reject) => {
32
+ canvas.toBlob((result) => {
33
+ return result
34
+ ? resolve(result)
35
+ : reject(new Error("Screenshot could not be created"));
36
+ });
37
+ });
22
38
 
23
- return blobToFile(imageBlob, filename, "image/jpg");
39
+ return blobToFile(imageBlob, screenshotFilename, "image/jpg");
24
40
  }
25
41
 
26
42
  export { captureElementScreenshot };
@@ -13,7 +13,7 @@
13
13
  }
14
14
 
15
15
  .editor-slide {
16
- @apply shadow-lg;
16
+ @apply shadow-md;
17
17
 
18
18
  textarea {
19
19
  @apply flex-none w-full;
@@ -24,16 +24,12 @@
24
24
  @apply cursor-not-allowed;
25
25
  }
26
26
 
27
- .editor-thumbnail-file {
28
- @apply hidden pointer-events-none;
29
- }
30
-
31
- .editor-screenshot-wrapper {
27
+ .editor-thumbnail-wrapper {
32
28
  @apply w-0 overflow-hidden relative;
33
29
  }
34
30
 
35
- .editor-screenshot {
36
- @apply absolute w-[800px] top-0 z-[-1000] pointer-events-none;
31
+ .editor-thumbnail {
32
+ @apply absolute w-[500px] top-0 z-[-1000] pointer-events-none;
37
33
  }
38
34
 
39
35
  .editor-icon-bg-color {
@@ -41,9 +37,6 @@
41
37
  stroke-width: 2px;
42
38
  }
43
39
 
44
- .editor-icon-text-color {
45
- }
46
-
47
40
  [data-component="app-seamless-textarea"] {
48
41
  textarea {
49
42
  @apply outline outline-1 outline-transparent outline-offset-0;
@@ -18,7 +18,7 @@
18
18
  }
19
19
  ) do |button| %>
20
20
  <% button.with_picker %>
21
- <% button.with_text { "Background colour" } %>
21
+ <% button.with_text { tt("bg_color_picker.label") } %>
22
22
  <% button.with_icon do %>
23
23
  <svg viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="editor-icon-bg-color">
24
24
  <path d="M12 22a7 7 0 0 0 7-7c0-2-1-3.9-3-5.5s-3.5-4-4-6.5c-.5 2.5-2 4.9-4 6.5C6 11.1 5 13 5 15a7 7 0 0 0 7 7z"></path>
@@ -41,12 +41,10 @@
41
41
  }
42
42
  ) do |button| %>
43
43
  <% button.with_picker do |picker| %>
44
- <% picker.with_blank_state_text do %>
45
- Drag a jpg, png or gif onto the slide area or&hellip;
46
- <% end %>
44
+ <% picker.with_blank_state_text { tt("bg_image_picker.blank_state") } %>
47
45
  <% end %>
48
46
 
49
- Background image
47
+ <%= tt("bg_image_picker.label") %>
50
48
  <% end %>
51
49
  <% end %>
52
50
 
@@ -63,9 +61,9 @@
63
61
  }
64
62
  ) do |button| %>
65
63
  <% button.with_picker %>
66
- <% button.with_text { "Text colour" } %>
64
+ <% button.with_text { tt("text_color_picker.label") } %>
67
65
  <% button.with_icon do %>
68
- <svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" class="editor-icon-text-color">
66
+ <svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
69
67
  <path d="M4.99994 13.3333L9.99994 3.33334L14.9999 13.3333" stroke="#111827" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
70
68
  <path d="M6.66656 10H13.3332" stroke="#111827" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
71
69
  <rect x="2.25" y="15.25" width="15.5" height="2.5" rx="1.25" fill="currentColor" stroke="#111827" stroke-width="0.5"/>
@@ -79,7 +77,7 @@
79
77
  <% section.with_button(
80
78
  icon: :undo_2,
81
79
  click: "history.undo",
82
- tooltip: "Undo",
80
+ tooltip: tt("undo_button.tooltip"),
83
81
  theme: :text_secondary,
84
82
  disabled: true,
85
83
  x: { "effect": "disabled = saving || !history.undoable" },
@@ -91,7 +89,7 @@
91
89
  <% section.with_button(
92
90
  icon: :redo_2,
93
91
  click: "history.redo",
94
- tooltip: "Redo",
92
+ tooltip: tt("redo_button.tooltip"),
95
93
  theme: :text_secondary,
96
94
  disabled: true,
97
95
  x: { "effect": "disabled = saving || !history.redoable" },
@@ -115,8 +113,8 @@
115
113
  ":class": "{'editor-saving': saving}"
116
114
  }
117
115
  ) do |button| %>
118
- <% button.with_state(:loading, text: "Saving...") %>
119
- Save
116
+ <% button.with_state(:loading, text: tt("save_button.saving_label")) %>
117
+ <%= tt("save_button.label") %>
120
118
  <% end %>
121
119
  <% end %>
122
120
  <% end %>
@@ -136,8 +134,7 @@
136
134
  role: "slide"
137
135
  },
138
136
  x: {
139
- ":style": "slideStyles",
140
- ":class": "slideClasses",
137
+ bind: "slide"
141
138
  }
142
139
  ) do |slide| %>
143
140
  <% if title? %>
@@ -153,24 +150,20 @@
153
150
  <% end %>
154
151
  <% end %>
155
152
  </div>
156
-
157
- <% if content %>
158
- <div
159
- class="editor-form"
160
- x-ref="form"
161
- @turbo:submit-end="submitSuccess"
162
- @turbo:fetch-request-error="submitError"
163
- @direct-upload:error="directUploadError"
164
- @direct-uploads:end="save">
165
- <%= content %>
166
- </div>
167
- <% end %>
168
153
 
169
- <% if false && thumbnail? %>
154
+ <% if generate_thumbnail? %>
170
155
  <%# Slide used for thumbnail generation %>
171
- <div class="editor-screenshot-wrapper">
172
- <div x-ref="screenshot" class="editor-screenshot">
173
- <%= coco_editable_slide(**slide_args) do |slide| %>
156
+ <div class="editor-thumbnail-wrapper">
157
+ <div x-ref="thumbnail" class="editor-thumbnail">
158
+ <%= coco_editable_slide(
159
+ **slide_args,
160
+ data: {
161
+ role: "slide-thumbnail"
162
+ },
163
+ x: {
164
+ bind: "slide"
165
+ }
166
+ ) do |slide| %>
174
167
  <% if title? %>
175
168
  <% slide.with_title do %>
176
169
  <span x-text="title"></span>
@@ -187,4 +180,15 @@
187
180
  </div>
188
181
  <% end %>
189
182
 
183
+ <% if content %>
184
+ <div
185
+ class="editor-form"
186
+ x-ref="form"
187
+ @turbo:submit-end="submitSuccess"
188
+ @turbo:fetch-request-error="submitError"
189
+ @direct-upload:error="directUploadError"
190
+ @direct-uploads:end="save">
191
+ <%= content %>
192
+ </div>
193
+ <% end %>
190
194
  <% end %>
@@ -2,16 +2,8 @@ import { CocoComponent } from "@js/coco";
2
2
  import { getData } from "@helpers/alpine";
3
3
  import { captureElementScreenshot } from "@helpers/screenshot";
4
4
  import { isDark } from "@helpers/color";
5
- import { wasSuccessful } from "@helpers/turbo_events";
6
5
  import { withUndo } from "@js/base/mixins";
7
6
 
8
- const thumbnailOpts = {
9
- canvasWidth: 800,
10
- canvasHeight: 500,
11
- quality: 0.7,
12
- pixelRatio: 1,
13
- };
14
-
15
7
  export default CocoComponent("appSlideEditor", (data) => {
16
8
  const initialData = {
17
9
  layout: data.layout,
@@ -44,9 +36,6 @@ export default CocoComponent("appSlideEditor", (data) => {
44
36
  },
45
37
 
46
38
  init() {
47
- // Update thumbnail field when new thumbnail is generated
48
- this.$watch("thumbnailFile", () => this._syncThumbnailField());
49
-
50
39
  this.$watch("errors", (errors) => {
51
40
  errors.forEach((error) => console.error(error.message)); // TODO display errors properly!
52
41
  });
@@ -82,10 +71,12 @@ export default CocoComponent("appSlideEditor", (data) => {
82
71
  },
83
72
 
84
73
  async save() {
85
- this.errors.length = 0;
74
+ if (this.saving) return;
75
+
76
+ this.clearErrors();
86
77
  this.saving = true;
87
78
 
88
- if (this.shouldGenerateThumbnail) {
79
+ if (this.$refs.thumbnail) {
89
80
  try {
90
81
  await this._generateThumbnail();
91
82
  } catch (error) {
@@ -96,24 +87,21 @@ export default CocoComponent("appSlideEditor", (data) => {
96
87
  }
97
88
  }
98
89
 
99
- if (this.$refs.form) {
100
- this.$refs.form.querySelector("form").requestSubmit();
90
+ const form = this.$refs.form && this.$refs.form.querySelector("form");
91
+
92
+ if (form && form.dataset.submit !== "false") {
93
+ form.requestSubmit();
101
94
  } else {
102
95
  this.submitSuccess();
103
96
  }
104
97
  },
105
98
 
106
- submitEnd(event) {
107
- handler = wasSuccessful(event) ? "submitSuccess" : "submitError";
108
- this[handler](event);
109
- },
110
-
111
99
  submitSuccess() {
112
100
  this.history.clear();
113
101
  this._fields.forEach((name) => (this.saved[name] = this[name]));
114
102
  this.saving = false;
115
103
 
116
- console.info("Custom slide saved");
104
+ console.info("Slide changes saved");
117
105
  this.$dispatch("slide:save-end", { success: true });
118
106
  },
119
107
 
@@ -127,22 +115,16 @@ export default CocoComponent("appSlideEditor", (data) => {
127
115
  this._handleSaveError($event.detail.error, { event: $event });
128
116
  },
129
117
 
130
- syncImageField(el, image) {
131
- const dataTransfer = new DataTransfer();
132
- if (image.file && image.file instanceof File) {
133
- dataTransfer.items.add(image.file);
134
- }
135
- el.files = dataTransfer.files;
118
+ clearErrors() {
119
+ this.errors.length = 0;
136
120
  },
137
121
 
138
- input: {
139
- layout: { "x-model.fill": "layout" },
140
- title: { "x-model.fill": "title" },
141
- text1: { "x-model.fill": "text1" },
142
- bgColor: { "x-model.fill": "bgColorHex" },
143
- textColor: { "x-model.fill": "textColorHex" },
144
- bgImage: { "x-effect": "syncImageField($el, bgImage)" },
145
- bgImagePurge: { ":checked": "!hasBgImage" },
122
+ syncFileInput(input, file) {
123
+ const dataTransfer = new DataTransfer();
124
+ if (file && file instanceof File) {
125
+ dataTransfer.items.add(file);
126
+ }
127
+ input.files = dataTransfer.files;
146
128
  },
147
129
 
148
130
  get hasBgImage() {
@@ -157,48 +139,18 @@ export default CocoComponent("appSlideEditor", (data) => {
157
139
  return this.textColor.replace("#", "");
158
140
  },
159
141
 
160
- get slideStyles() {
161
- return {
162
- backgroundColor: this.bgColor,
163
- color: this.textColor,
164
- backgroundImage: this.hasBgImage
165
- ? `url('${this.bgImage.data}')`
166
- : "none",
167
- };
168
- },
169
-
170
- get slideClasses() {
171
- return {
172
- "slide-bg-dark": this.isDarkBg,
173
- "slide-bg-light": !this.isDarkBg,
174
- };
175
- },
176
-
177
142
  get isDarkBg() {
178
143
  return this.hasBgImage || this.bgColor ? isDark(this.bgColor) : false;
179
144
  },
180
145
 
181
- get shouldGenerateThumbnail() {
182
- return !!this.$refs.thumbnail;
183
- },
184
-
185
146
  get _fields() {
186
147
  return Object.keys(initialData);
187
148
  },
188
149
 
189
150
  async _generateThumbnail() {
190
- const screenshotSlide = this.$refs.screenshot.firstElementChild;
191
-
192
- // The HTML-to-image library didn't like these styles being dynamically
193
- // bound in the usual Alpine way so we have to manually apply them instead.
194
- for (const [key, value] of Object.entries(this.slideStyles)) {
195
- screenshotSlide.style[key] = value;
196
- }
197
-
198
151
  this.thumbnailFile = await captureElementScreenshot(
199
- screenshotSlide,
200
- "slide-thumbnail",
201
- thumbnailOpts
152
+ this.$refs.thumbnail.firstElementChild,
153
+ "slide-thumbnail"
202
154
  );
203
155
 
204
156
  console.info(
@@ -207,25 +159,42 @@ export default CocoComponent("appSlideEditor", (data) => {
207
159
  );
208
160
  },
209
161
 
210
- // Called whenever a new thumbnail is generated,
211
- // adds the thumbnail file to the hidden thumbnail file
212
- // input upload field.
213
- _syncThumbnailField() {
214
- const dataTransfer = new DataTransfer();
215
- if (this.thumbnailFile instanceof File) {
216
- dataTransfer.items.add(this.thumbnailFile);
217
- }
218
- this.$refs.thumbnail.files = dataTransfer.files;
219
- },
220
-
221
162
  _handleSaveError(message = "Error saving slide", context = {}) {
222
163
  this.errors.push({ message, context });
223
- this.errors.forEach((err) => {
224
- console.log(err.message);
225
- });
226
164
  this.saving = false;
227
165
 
228
166
  this.$dispatch("slide:save-end", { success: false });
229
167
  },
168
+
169
+ /* bindings */
170
+
171
+ slide: {
172
+ [":style"]() {
173
+ return {
174
+ backgroundColor: this.bgColor,
175
+ color: this.textColor,
176
+ backgroundImage: this.hasBgImage
177
+ ? `url('${this.bgImage.data}')`
178
+ : "none",
179
+ };
180
+ },
181
+ [":class"]() {
182
+ return {
183
+ "slide-bg-dark": this.isDarkBg,
184
+ "slide-bg-light": !this.isDarkBg,
185
+ };
186
+ },
187
+ },
188
+
189
+ input: {
190
+ layout: { "x-model.fill": "layout" },
191
+ title: { "x-model.fill": "title" },
192
+ text1: { "x-model.fill": "text1" },
193
+ bgColor: { "x-model.fill": "bgColorHex" },
194
+ textColor: { "x-model.fill": "textColorHex" },
195
+ bgImage: { "x-effect": "syncFileInput($el, bgImage.file)" },
196
+ bgImagePurge: { ":checked": "!hasBgImage" },
197
+ thumbnailImage: { "x-effect": "syncFileInput($el, thumbnailFile)" },
198
+ },
230
199
  };
231
200
  });
@@ -6,8 +6,6 @@ module Coco
6
6
  include Coco::BookHelper
7
7
  include Coco::FormatHelper
8
8
 
9
- renders_one :form
10
-
11
9
  renders_one :title, ->(value = nil, **textarea_options) do
12
10
  Coco::App::Elements::SeamlessTextarea.new(**textarea_options,
13
11
  value: value,
@@ -37,9 +35,11 @@ module Coco
37
35
  @bg_image_options = {src: src, **input_options}
38
36
  end
39
37
 
40
- # renders_one :thumbnail, ->(name: :thumbnail_image, **input_options) do
41
- # add_field(:thumbnail, name, input_options)
42
- # end
38
+ def initialize(generate_thumbnail: true, **kwargs)
39
+ @generate_thumbnail = generate_thumbnail
40
+ end
41
+
42
+ def generate_thumbnail? = @generate_thumbnail
43
43
 
44
44
  def slide_args
45
45
  {
@@ -6,7 +6,7 @@
6
6
  @apply transition-all overflow-hidden;
7
7
  border-radius: 44px;
8
8
 
9
- .button-content {
9
+ & > .button-element .button-content {
10
10
  @apply font-semibold;
11
11
  }
12
12
  }
@@ -23,7 +23,7 @@
23
23
  @apply bg-primary-700;
24
24
  }
25
25
 
26
- &[data-state="loading"] .button-icon {
26
+ &[data-state="loading"] > .button-element .button-icon {
27
27
  @apply text-positive-300;
28
28
  }
29
29
 
@@ -44,7 +44,7 @@
44
44
  @apply bg-gray-blend-100;
45
45
  }
46
46
 
47
- &[data-state="loading"] .button-icon {
47
+ &[data-state="loading"] > .button-element .button-icon {
48
48
  @apply text-positive-300;
49
49
  }
50
50
 
@@ -65,7 +65,7 @@
65
65
  @apply bg-gray-blend-100;
66
66
  }
67
67
 
68
- &[data-state="loading"] .button-icon {
68
+ &[data-state="loading"] > .button-element .button-icon {
69
69
  @apply text-positive-300;
70
70
  }
71
71
 
@@ -86,7 +86,7 @@
86
86
  @apply bg-gray-blend-100;
87
87
  }
88
88
 
89
- &[data-state="loading"] .button-icon {
89
+ &[data-state="loading"] > .button-element .button-icon {
90
90
  @apply text-positive-300;
91
91
  }
92
92
 
@@ -106,7 +106,7 @@
106
106
  @apply bg-negative-800;
107
107
  }
108
108
 
109
- &[data-state="loading"] .button-icon {
109
+ &[data-state="loading"] > .button-element .button-icon {
110
110
  @apply text-negative-300;
111
111
  }
112
112
 
@@ -126,7 +126,7 @@
126
126
  @apply bg-gray-blend-100;
127
127
  }
128
128
 
129
- &[data-state="loading"] .button-icon {
129
+ &[data-state="loading"] > .button-element .button-icon {
130
130
  @apply text-negative-300;
131
131
  }
132
132
 
@@ -146,7 +146,7 @@
146
146
  @apply bg-warning-800;
147
147
  }
148
148
 
149
- &[data-state="loading"] .button-icon {
149
+ &[data-state="loading"] > .button-element .button-icon {
150
150
  @apply text-warning-300;
151
151
  }
152
152
 
@@ -166,7 +166,7 @@
166
166
  @apply bg-gray-blend-100;
167
167
  }
168
168
 
169
- &[data-state="loading"] .button-icon {
169
+ &[data-state="loading"] > .button-element .button-icon {
170
170
  @apply text-warning-300;
171
171
  }
172
172
 
@@ -186,7 +186,7 @@
186
186
  @apply bg-info-800;
187
187
  }
188
188
 
189
- &[data-state="loading"] .button-icon {
189
+ &[data-state="loading"] > .button-element .button-icon {
190
190
  @apply text-info-300;
191
191
  }
192
192
 
@@ -206,7 +206,7 @@
206
206
  @apply bg-gray-blend-100;
207
207
  }
208
208
 
209
- &[data-state="loading"] .button-icon {
209
+ &[data-state="loading"] > .button-element .button-icon {
210
210
  @apply text-info-300;
211
211
  }
212
212
 
@@ -41,7 +41,7 @@
41
41
 
42
42
  /* loading */
43
43
 
44
- &[data-state="loading"] .button-icon {
44
+ &[data-state="loading"] > .button-element .button-icon {
45
45
  @apply animate-spin;
46
46
  }
47
47
 
@@ -53,7 +53,7 @@
53
53
 
54
54
  /* Icons */
55
55
 
56
- &[data-icon-position="end"] {
56
+ &[data-icon-position="end"] > .button-element {
57
57
  .button-content {
58
58
  @apply order-1;
59
59
  }
@@ -67,7 +67,7 @@
67
67
  }
68
68
  }
69
69
 
70
- &.with-icon[data-collapsed="true"] {
70
+ &.with-icon[data-collapsed="true"] > .button-element {
71
71
  .button-content {
72
72
  display: none;
73
73
  }