bard-attachment_field 0.5.4 → 0.5.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ce6c35b5100e96423e481bdb7cb16685dd12eb13fd2712f0aa6e0018193a75e8
4
- data.tar.gz: 70a5d3a46439faabb9588ec04655f92092bd94c357ec5b492b56bf1376621d64
3
+ metadata.gz: 81087a83b5826f9f496ec7e3de2a8e06ddf4f4020042ab09fab2f9266ddc9034
4
+ data.tar.gz: ced1aae9518fbec16dd3f588217cad02e3eee964d135d0706917b85a46624d33
5
5
  SHA512:
6
- metadata.gz: 6f73d93cd92298b236646d0bbe72d54bccfe8490fe0bc8dc2dc0e46512afaecca53e6fb44ff4ab4ebb6a2343483afc17fba84171d392ff9981bb0e5ebd1ae4e5
7
- data.tar.gz: 78ecf96abad31aaebf81a9a4d0cc8073a8a565ead77cd6c0406d95bb34b0b05371fb1711db616079969ca437ef6cb72b8039c5fef99f15c15e14e5d6a3af0ae1
6
+ metadata.gz: 03c6a1bd3681a43146ada1ab6afb6e9482ab59a847fb87b242457aeae8e95fbe99c4995f3f3a0fbe7f8e0ed3e6a9b8775e6ccf0a988b1c1972ea247b836410a6
7
+ data.tar.gz: 0d2a288ef42ee0476cda23547b0319c59dc0cacb0d5002fd7d2af3dc3466e1f8f33476a935f8bcd0bf4e518524f481a26a994818d53723422d032a35b023e747
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.5] - 2026-06-06
4
+
5
+ ### Bug Fixes
6
+
7
+ - Capture the block passed to `attachment_field` instead of using its return
8
+ value. Previously the block's markup leaked to the surrounding output buffer,
9
+ leaving `<input-attachment>` with no `<attachment-file>` child — so editing a
10
+ record and saving without touching the file submitted an empty value and
11
+ silently purged the existing attachment.
12
+
3
13
  ## [0.2.0] - 2026-03-03
4
14
 
5
15
  ### Features
@@ -4790,43 +4790,190 @@ var o = H2;
4790
4790
  var e = a;
4791
4791
 
4792
4792
  // dist/components/index2.js
4793
- var r = null;
4794
- function n2(r4) {
4795
- const n3 = Number(r4);
4796
- if (Number.isNaN(n3)) throw new TypeError(`progress-bar: percent must be numeric, got ${JSON.stringify(r4)}`);
4797
- return Math.min(100, Math.max(0, n3));
4793
+ var n2 = null;
4794
+ function r(n3) {
4795
+ const r4 = Number(n3);
4796
+ if (Number.isNaN(r4)) throw new TypeError(`progress-bar: percent must be numeric, got ${JSON.stringify(n3)}`);
4797
+ return Math.min(100, Math.max(0, r4));
4798
4798
  }
4799
4799
  var e2 = class extends HTMLElement {
4800
4800
  constructor() {
4801
- super(), this.attachShadow({ mode: "open" }), this._percent = 0, this._rendered = false;
4801
+ super(), this.attachShadow({ mode: "open" }), this._percent = null, this._renderedMode = null;
4802
4802
  }
4803
4803
  connectedCallback() {
4804
- this._rendered || (this.render(), this._rendered = true), this.updateBar();
4804
+ this.render(), this.setAttribute("role", "progressbar"), this.setAttribute("aria-valuemin", "0"), this.setAttribute("aria-valuemax", "100"), this.updateBar();
4805
4805
  }
4806
4806
  get percent() {
4807
4807
  return this._percent;
4808
4808
  }
4809
- set percent(r4) {
4810
- this.setAttribute("percent", n2(r4));
4809
+ set percent(n3) {
4810
+ null == n3 ? this.removeAttribute("percent") : this.setAttribute("percent", r(n3));
4811
4811
  }
4812
4812
  get error() {
4813
4813
  return this.hasAttribute("error");
4814
4814
  }
4815
- set error(r4) {
4816
- this.toggleAttribute("error", Boolean(r4));
4815
+ set error(n3) {
4816
+ this.toggleAttribute("error", Boolean(n3));
4817
+ }
4818
+ get indeterminate() {
4819
+ return !this.hasAttribute("percent");
4820
+ }
4821
+ get mode() {
4822
+ return "circular" === this.getAttribute("mode") ? "circular" : "linear";
4823
+ }
4824
+ set mode(n3) {
4825
+ this.setAttribute("mode", n3);
4817
4826
  }
4818
4827
  static get observedAttributes() {
4819
- return ["percent"];
4828
+ return ["percent", "mode"];
4820
4829
  }
4821
- attributeChangedCallback(r4, e3, t) {
4822
- "percent" === r4 && (this._percent = n2(t), this.updateBar());
4830
+ attributeChangedCallback(n3, e3, t) {
4831
+ "percent" === n3 && (this._percent = null === t ? null : r(t)), "mode" === n3 && this.render(), this.updateBar();
4823
4832
  }
4824
4833
  updateBar() {
4825
- const r4 = this.shadowRoot?.querySelector(".bar");
4826
- r4 && (r4.style.width = `${this._percent}%`), this.setAttribute("aria-valuenow", String(this._percent));
4834
+ if ("circular" === this.mode) {
4835
+ const n3 = this.shadowRoot?.querySelector(".progress-ring");
4836
+ n3 && (n3.style.strokeDashoffset = this.indeterminate ? "" : String(100 * (1 - this._percent / 100)));
4837
+ } else {
4838
+ const n3 = this.shadowRoot?.querySelector(".bar");
4839
+ n3 && (n3.style.width = this.indeterminate ? "" : `${this._percent}%`);
4840
+ }
4841
+ this.indeterminate ? this.removeAttribute("aria-valuenow") : this.setAttribute("aria-valuenow", String(this._percent));
4827
4842
  }
4828
4843
  render() {
4829
- this.shadowRoot.adoptedStyleSheets = [(r || (r = new CSSStyleSheet(), r.replaceSync("\n :host {\n --progress-color: #2E7D32;\n --error-color: #7a242f;\n --progress-duration: 120ms;\n --bar-height: 32px;\n --bar-padding: 8px;\n display: block;\n overflow: hidden;\n background: #333333;\n border: 1px solid #999;\n border-radius: 4px;\n }\n\n .content {\n position: relative;\n display: flex;\n align-items: center;\n min-height: var(--bar-height);\n box-sizing: border-box;\n padding: var(--bar-padding);\n color: white;\n font-size: 13px;\n z-index: 0;\n }\n\n .bar {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n width: 0%;\n background: var(--progress-color);\n transition: width var(--progress-duration) ease;\n z-index: -1;\n }\n\n :host([error]) .bar {\n background: var(--error-color);\n }\n")), r)], this.shadowRoot.innerHTML = '\n <span class="content">\n <div class="bar"></div>\n <slot></slot>\n </span>\n ', this.setAttribute("role", "progressbar"), this.setAttribute("aria-valuemin", "0"), this.setAttribute("aria-valuemax", "100");
4844
+ const r4 = this.mode;
4845
+ this._renderedMode !== r4 && (this._renderedMode = r4, this.shadowRoot.adoptedStyleSheets = [(n2 || (n2 = new CSSStyleSheet(), n2.replaceSync(`
4846
+ :host {
4847
+ --progress-color: #2E7D32;
4848
+ --error-color: #7a242f;
4849
+ --indeterminate-color: #999;
4850
+ --track-color: #333333;
4851
+ --progress-duration: 120ms;
4852
+ --indeterminate-duration: 1.5s;
4853
+ --bar-height: 32px;
4854
+ --bar-padding: 8px;
4855
+ --circular-size: 64px;
4856
+ --circular-thickness: 16;
4857
+ display: block;
4858
+ overflow: hidden;
4859
+ background: var(--track-color);
4860
+ border: 1px solid #999;
4861
+ border-radius: 4px;
4862
+ min-height: var(--bar-height);
4863
+ padding: var(--bar-padding);
4864
+ font-size: 13px;
4865
+ align-content: center;
4866
+ box-sizing: border-box;
4867
+ position: relative;
4868
+ }
4869
+ .bar {
4870
+ position: absolute;
4871
+ top: 0;
4872
+ left: 0;
4873
+ height: 100%;
4874
+ width: 0%;
4875
+ background: var(--progress-color);
4876
+ transition: width var(--progress-duration) ease;
4877
+ z-index: 1;
4878
+ }
4879
+ .text{position: relative; z-index: 2;}
4880
+ :host([error]) .bar {
4881
+ background: var(--error-color);
4882
+ }
4883
+
4884
+ /* Indeterminate (linear): no percent set \u2014 a fixed-width segment sweeping across the track. */
4885
+ :host(:not([percent])) .bar {
4886
+ background: var(--indeterminate-color);
4887
+ width: 40%;
4888
+ animation: indeterminate-linear var(--indeterminate-duration) infinite linear;
4889
+ }
4890
+
4891
+ @keyframes indeterminate-linear {
4892
+ 0% { transform: translateX(-100%); }
4893
+ 100% { transform: translateX(250%); }
4894
+ }
4895
+
4896
+ /* Circular mode: the host box styling is for the linear track, so drop it. */
4897
+ :host([mode="circular"]) {
4898
+ background: transparent;
4899
+ border: none;
4900
+ overflow: visible;
4901
+ padding: 0;
4902
+ min-height: 0;
4903
+ }
4904
+
4905
+ .circular {
4906
+ position: relative;
4907
+ display: inline-flex;
4908
+ width: var(--circular-size);
4909
+ height: var(--circular-size);
4910
+ }
4911
+
4912
+ .ring {
4913
+ width: 100%;
4914
+ height: 100%;
4915
+ transform: rotate(-90deg);
4916
+ }
4917
+
4918
+ .ring circle {
4919
+ fill: none;
4920
+ stroke-width: var(--circular-thickness);
4921
+ /* Shrink the radius so the stroke's outer edge always lands inside the
4922
+ 100x100 viewBox, no matter how thick --circular-thickness is. */
4923
+ r: calc(49px - var(--circular-thickness) * 0.5px);
4924
+ }
4925
+
4926
+ .track {
4927
+ stroke: var(--track-color);
4928
+ }
4929
+
4930
+ .progress-ring {
4931
+ stroke: var(--progress-color);
4932
+ stroke-linecap: round;
4933
+ stroke-dasharray: 100;
4934
+ stroke-dashoffset: 100;
4935
+ transition: stroke-dashoffset var(--progress-duration) ease;
4936
+ }
4937
+
4938
+ :host(:not([percent])) .progress-ring {
4939
+ stroke: var(--indeterminate-color);
4940
+ }
4941
+
4942
+ :host([error]) .progress-ring {
4943
+ stroke: var(--error-color);
4944
+ }
4945
+
4946
+ .label {
4947
+ position: absolute;
4948
+ inset: 0;
4949
+ display: flex;
4950
+ align-items: center;
4951
+ justify-content: center;
4952
+ color: #fff;
4953
+ mix-blend-mode: difference;
4954
+ }
4955
+
4956
+ /* When the host carries its own inline styling (e.g. a color override), opt
4957
+ out of the blend trick and just inherit, so the override wins predictably. */
4958
+ :host([style]) .label {
4959
+ mix-blend-mode: initial;
4960
+ color: inherit;
4961
+ }
4962
+
4963
+ /* Indeterminate (circular): no percent set \u2014 spin a fixed arc around the ring. */
4964
+ :host(:not([percent])) .ring {
4965
+ animation: indeterminate-rotate var(--indeterminate-duration) infinite linear;
4966
+ }
4967
+
4968
+ :host(:not([percent])) .progress-ring {
4969
+ stroke-dashoffset: 75;
4970
+ }
4971
+
4972
+ @keyframes indeterminate-rotate {
4973
+ 0% { transform: rotate(-90deg); }
4974
+ 100% { transform: rotate(270deg); }
4975
+ }
4976
+ `)), n2)], this.shadowRoot.innerHTML = "circular" === r4 ? '\n <div class="circular">\n <svg class="ring" viewBox="0 0 100 100">\n <circle class="track" cx="50" cy="50" r="40"></circle>\n <circle class="progress-ring" cx="50" cy="50" r="40" pathLength="100"></circle>\n </svg>\n <span class="label"><slot></slot></span>\n </div>\n' : '\n <div class="bar"></div>\n <div class="text"><slot></slot></div>\n');
4830
4977
  }
4831
4978
  };
4832
4979
  customElements.get("progress-bar") || customElements.define("progress-bar", e2);
Binary file
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@botandrose/file-drop": "^0.1.1",
37
- "@botandrose/progress-bar": "^0.3.0",
37
+ "@botandrose/progress-bar": "^0.4.1",
38
38
  "@rails/activestorage": "^8.1.0",
39
39
  "@rails/request.js": "0.0.13",
40
40
  "@stencil/core": "^4.43.2",
@@ -8,8 +8,12 @@ module Bard
8
8
  })
9
9
  add_default_name_and_id(options)
10
10
 
11
- content_tag("input-attachment", options) do
12
- next block.call(options) if block
11
+ content = if block
12
+ # Capture the template block's rendered markup. Using block.call would
13
+ # return the block's value while its markup leaked to the surrounding
14
+ # output buffer, leaving <input-attachment> childless (see BARD #262849).
15
+ @template_object.capture(options, &block)
16
+ else
13
17
  Array(object.try(@method_name)).map do |attachment|
14
18
  content_tag("attachment-file", nil, {
15
19
  name: options["name"],
@@ -20,6 +24,8 @@ module Bard
20
24
  })
21
25
  end.join("\n").html_safe
22
26
  end
27
+
28
+ content_tag("input-attachment", content, options)
23
29
  end
24
30
 
25
31
  private
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Bard
4
4
  module AttachmentField
5
- VERSION = "0.5.4"
5
+ VERSION = "0.5.6"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bard-attachment_field
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.4
4
+ version: 0.5.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Micah Geisel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-05-30 00:00:00.000000000 Z
11
+ date: 2026-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activestorage