bard-attachment_field 0.6.4 → 0.6.5

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: 97544f73074b88b48df66fd5a7aa865a8b88fd4eb8078bfc11ff605973c312ed
4
- data.tar.gz: f29d06de7233f15966ae9b139d10bf0c048fc02aa3c233af72aadcffdd4cf2b6
3
+ metadata.gz: f2ae64b317884629f1640e9e60042f4fd6483a5f76aa27a541e8cb090a9ab513
4
+ data.tar.gz: 18b7d64724a970afb9a8bc9c9dfe63fa07531033929b8ce25f8b8072d3243949
5
5
  SHA512:
6
- metadata.gz: 118ac9484ef7b4f96a7e2a837fcc38bf3443ca576555ac9d0dcfdab5d16c57074d7927f1e3f454f51c4e2bd83d0fadc60d5810773817825044c7aa5c311dd570
7
- data.tar.gz: 708a641e9b386a0e91a80f14046711518ca6a9e19a461f894aadefa949c2c36927479a0774fc882a0fea36dbd678f47fb1d787168618e0da76c5a6d943ecdef2
6
+ metadata.gz: e5dba5578a41090328f203826e7032b41557ee5e7d552809c7958d15af8ddecf7c7a7dd3467319ed8aca8ffb31a5487ed76472201d12053832c69fe55165f4f4
7
+ data.tar.gz: f061a728c792c4f1d42882fdf791617e3fe020461642f8560fe83908a407d565de2e33ba73e8e35488bc9bddb5b22a65d1aaf38ac0f0f72e308aa4e5f2e63e7c
@@ -4252,10 +4252,10 @@ var l = class _l {
4252
4252
  return false;
4253
4253
  }
4254
4254
  };
4255
- function d(t2, e3) {
4255
+ function u(t2, e3) {
4256
4256
  return "string" == typeof t2 && (e3 = t2, t2 = document), t2.querySelector(e3);
4257
4257
  }
4258
- function u(t2, e3, i2 = {}) {
4258
+ function d(t2, e3, i2 = {}) {
4259
4259
  const { disabled: s } = t2, { bubbles: r4, cancelable: n3, detail: o3 } = i2, a3 = document.createEvent("Event");
4260
4260
  a3.initEvent(e3, r4 || true, n3 || true), a3.detail = o3 || {};
4261
4261
  try {
@@ -4274,7 +4274,7 @@ var f = class {
4274
4274
  this.xhr.setRequestHeader(t3, s[t3]);
4275
4275
  }));
4276
4276
  const r4 = (function() {
4277
- const t3 = d(document.head, 'meta[name="csrf-token"]');
4277
+ const t3 = u(document.head, 'meta[name="csrf-token"]');
4278
4278
  if (t3) return t3.getAttribute("content");
4279
4279
  })();
4280
4280
  null != r4 && this.xhr.setRequestHeader("X-CSRF-Token", r4), this.xhr.addEventListener("load", ((t3) => this.requestDidLoad(t3))), this.xhr.addEventListener("error", ((t3) => this.requestDidError(t3)));
@@ -4365,7 +4365,7 @@ var v = class {
4365
4365
  return this.input.getAttribute("data-direct-upload-url");
4366
4366
  }
4367
4367
  dispatch(t2, e3 = {}) {
4368
- return e3.file = this.file, e3.id = this.directUpload.id, u(this.input, `direct-upload:${t2}`, { detail: e3 });
4368
+ return e3.file = this.file, e3.id = this.directUpload.id, d(this.input, `direct-upload:${t2}`, { detail: e3 });
4369
4369
  }
4370
4370
  dispatchError(t2) {
4371
4371
  this.dispatch("error", { error: t2 }).defaultPrevented || alert(t2);
@@ -4417,7 +4417,7 @@ var y = class {
4417
4417
  })), t2;
4418
4418
  }
4419
4419
  dispatch(t2, e3 = {}) {
4420
- return u(this.form, `direct-uploads:${t2}`, { detail: e3 });
4420
+ return d(this.form, `direct-uploads:${t2}`, { detail: e3 });
4421
4421
  }
4422
4422
  };
4423
4423
  var x = "data-direct-uploads-processing";
@@ -4439,7 +4439,7 @@ function $(t2) {
4439
4439
  const i2 = new y(e3), { inputs: s } = i2;
4440
4440
  s.length && (t2.preventDefault(), e3.setAttribute(x, ""), s.forEach(E), i2.start(((t3) => {
4441
4441
  e3.removeAttribute(x), t3 ? s.forEach(U) : (function(t4) {
4442
- let e4 = k.get(t4) || d(t4, "input[type=submit], button[type=submit]");
4442
+ let e4 = k.get(t4) || u(t4, "input[type=submit], button[type=submit]");
4443
4443
  if (e4) {
4444
4444
  const { disabled: t5 } = e4;
4445
4445
  e4.disabled = false, e4.focus(), e4.click(), e4.disabled = t5;
@@ -4532,6 +4532,16 @@ var q = class {
4532
4532
  return parseFloat((t2 / Math.pow(1024, s)).toFixed(i2)) + ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"][s];
4533
4533
  }
4534
4534
  };
4535
+ var F = class {
4536
+ uploadedFile;
4537
+ constructor(t2) {
4538
+ this.uploadedFile = t2;
4539
+ }
4540
+ get errors() {
4541
+ return this.#t || (this.#t = [], 0 === this.uploadedFile.size && this.#t.push("Must be larger than 0 bytes.")), this.#t;
4542
+ }
4543
+ #t;
4544
+ };
4535
4545
  var B = class {
4536
4546
  uploadedFile;
4537
4547
  constructor(t2) {
@@ -4548,11 +4558,11 @@ var B = class {
4548
4558
  return t2.length >= 3 ? (t2.slice(0, -1) + [`or ${t2.at(-1)}`]).join(", ") : t2.join(" or ");
4549
4559
  }
4550
4560
  };
4551
- var F = { image: ["ase", "art", "bmp", "blp", "cd5", "cit", "cpt", "cr2", "cut", "dds", "dib", "djvu", "egt", "exif", "gif", "gpl", "grf", "icns", "ico", "iff", "jng", "jpeg", "jpg", "jfif", "jp2", "jps", "lbm", "max", "miff", "mng", "msp", "nef", "nitf", "ota", "pbm", "pc1", "pc2", "pc3", "pcf", "pcx", "pdn", "pgm", "PI1", "PI2", "PI3", "pict", "pct", "pnm", "pns", "ppm", "psb", "psd", "pdd", "psp", "px", "pxm", "pxr", "qfx", "raw", "rle", "sct", "sgi", "rgb", "int", "bw", "tga", "tiff", "tif", "vtf", "xbm", "xcf", "xpm", "3dv", "amf", "ai", "awg", "cgm", "cdr", "cmx", "dxf", "e2d", "egt", "eps", "fs", "gbr", "odg", "svg", "stl", "vrml", "x3d", "sxd", "v2d", "vnd", "wmf", "emf", "art", "xar", "png", "webp", "jxr", "hdp", "wdp", "cur", "ecw", "iff", "lbm", "liff", "nrrd", "pam", "pcx", "pgf", "sgi", "rgb", "rgba", "bw", "int", "inta", "sid", "ras", "sun", "tga", "heic", "heif"], video: ["3g2", "3gp", "3gpp", "aaf", "asf", "avchd", "avi", "drc", "flv", "m2v", "m3u8", "m4p", "m4v", "mkv", "mng", "mov", "mp2", "mp4", "mpe", "mpeg", "mpg", "mpv", "mxf", "nsv", "ogg", "ogv", "qt", "rm", "rmvb", "roq", "svi", "vob", "webm", "wmv", "yuv"], pdf: ["pdf"], getFileType: function(t2) {
4561
+ var S = { image: ["ase", "art", "bmp", "blp", "cd5", "cit", "cpt", "cr2", "cut", "dds", "dib", "djvu", "egt", "exif", "gif", "gpl", "grf", "icns", "ico", "iff", "jng", "jpeg", "jpg", "jfif", "jp2", "jps", "lbm", "max", "miff", "mng", "msp", "nef", "nitf", "ota", "pbm", "pc1", "pc2", "pc3", "pcf", "pcx", "pdn", "pgm", "PI1", "PI2", "PI3", "pict", "pct", "pnm", "pns", "ppm", "psb", "psd", "pdd", "psp", "px", "pxm", "pxr", "qfx", "raw", "rle", "sct", "sgi", "rgb", "int", "bw", "tga", "tiff", "tif", "vtf", "xbm", "xcf", "xpm", "3dv", "amf", "ai", "awg", "cgm", "cdr", "cmx", "dxf", "e2d", "egt", "eps", "fs", "gbr", "odg", "svg", "stl", "vrml", "x3d", "sxd", "v2d", "vnd", "wmf", "emf", "art", "xar", "png", "webp", "jxr", "hdp", "wdp", "cur", "ecw", "iff", "lbm", "liff", "nrrd", "pam", "pcx", "pgf", "sgi", "rgb", "rgba", "bw", "int", "inta", "sid", "ras", "sun", "tga", "heic", "heif"], video: ["3g2", "3gp", "3gpp", "aaf", "asf", "avchd", "avi", "drc", "flv", "m2v", "m3u8", "m4p", "m4v", "mkv", "mng", "mov", "mp2", "mp4", "mpe", "mpeg", "mpg", "mpv", "mxf", "nsv", "ogg", "ogv", "qt", "rm", "rmvb", "roq", "svi", "vob", "webm", "wmv", "yuv"], pdf: ["pdf"], getFileType: function(t2) {
4552
4562
  const e3 = t2.toString().split(".").at(-1).toLowerCase().trim();
4553
4563
  return this.video.includes(e3) ? "video" : this.image.includes(e3) ? "image" : this.pdf.includes(e3) ? "pdf" : "unknown";
4554
4564
  } };
4555
- var S = class {
4565
+ var T = class {
4556
4566
  constructor(t2) {
4557
4567
  this.response = t2;
4558
4568
  }
@@ -4597,7 +4607,7 @@ var S = class {
4597
4607
  window.Turbo ? await window.Turbo.renderStreamMessage(await this.text) : console.warn("You must set `window.Turbo = Turbo` to automatically process Turbo Stream events with request.js");
4598
4608
  }
4599
4609
  };
4600
- var T = class {
4610
+ var W = class {
4601
4611
  static register(t2) {
4602
4612
  this.interceptor = t2;
4603
4613
  }
@@ -4608,22 +4618,22 @@ var T = class {
4608
4618
  this.interceptor = void 0;
4609
4619
  }
4610
4620
  };
4611
- function W(t2) {
4621
+ function X(t2) {
4612
4622
  const e3 = document.head.querySelector(`meta[name="${t2}"]`);
4613
4623
  return e3 && e3.content;
4614
4624
  }
4615
- var X = class {
4625
+ var H2 = class {
4616
4626
  constructor(t2, e3, i2 = {}) {
4617
4627
  this.method = t2, this.options = i2, this.originalUrl = e3.toString();
4618
4628
  }
4619
4629
  async perform() {
4620
4630
  try {
4621
- const t3 = T.get();
4631
+ const t3 = W.get();
4622
4632
  t3 && await t3(this);
4623
4633
  } catch (t3) {
4624
4634
  console.error(t3);
4625
4635
  }
4626
- const t2 = new S(await window.fetch(this.url, this.fetchOptions));
4636
+ const t2 = new T(await window.fetch(this.url, this.fetchOptions));
4627
4637
  return t2.unauthenticated && t2.authenticationURL ? Promise.reject(window.location.href = t2.authenticationURL) : (t2.ok && t2.isTurboStream && await t2.renderTurboStream(), t2);
4628
4638
  }
4629
4639
  addHeader(t2, e3) {
@@ -4650,7 +4660,7 @@ var X = class {
4650
4660
  const t3 = s.split("=").slice(1).join("=");
4651
4661
  if (t3) return decodeURIComponent(t3);
4652
4662
  }
4653
- })(W("csrf-param")) || W("csrf-token");
4663
+ })(X("csrf-param")) || X("csrf-token");
4654
4664
  }
4655
4665
  get contentType() {
4656
4666
  return this.options.contentType ? this.options.contentType : null == this.body || this.body instanceof window.FormData ? void 0 : this.body instanceof window.File ? this.body.type : "application/json";
@@ -4700,7 +4710,7 @@ var X = class {
4700
4710
  return "application/json" !== this.headers["Content-Type"] || t2 ? this.body : JSON.stringify(this.body);
4701
4711
  }
4702
4712
  };
4703
- var H2 = proxyCustomElement(class extends H {
4713
+ var z = proxyCustomElement(class extends H {
4704
4714
  constructor(t2) {
4705
4715
  super(), false !== t2 && this.__registerHost(), this.__attachShadow(), this.removeEvent = createEvent(this, "attachment-file:remove", 7), this.validationEvent = createEvent(this, "attachment-file:validation", 7), this.readyEvent = createEvent(this, "attachment-file:ready", 7);
4706
4716
  }
@@ -4745,12 +4755,12 @@ var H2 = proxyCustomElement(class extends H {
4745
4755
  this.src = URL.createObjectURL(t2), this.filename = t2.name, this.size = t2.size, this.state = "pending", this.percent = 0, this._file = t2;
4746
4756
  }
4747
4757
  set signedId(t2) {
4748
- this.value !== t2 && ((t3, e3 = {}, i2 = {}) => ((t4, e4, i3, s) => new X("get", e4, { headers: { Accept: "application/json", ...s }, query: i3 }).perform().then(((t5) => t5.response.ok ? t5.json : t5)))(0, t3, e3, i2))(`/rails/active_storage/blobs/info/${t2}`).then(((e3) => {
4758
+ this.value !== t2 && ((t3, e3 = {}, i2 = {}) => ((t4, e4, i3, s) => new H2("get", e4, { headers: { Accept: "application/json", ...s }, query: i3 }).perform().then(((t5) => t5.response.ok ? t5.json : t5)))(0, t3, e3, i2))(`/rails/active_storage/blobs/info/${t2}`).then(((e3) => {
4749
4759
  this.src = `/rails/active_storage/blobs/redirect/${t2}/${e3.filename}`, this.filename = e3.filename, this.size = e3.byte_size, this.state = "complete", this.percent = 100, this.value = t2, this.readyEvent.emit(this);
4750
4760
  }));
4751
4761
  }
4752
4762
  setMissingFiletype(t2, e3) {
4753
- !this.filetype && this.filename && (this.filetype = F.getFileType(this.filename));
4763
+ !this.filetype && this.filename && (this.filetype = S.getFileType(this.filename));
4754
4764
  }
4755
4765
  start(t2) {
4756
4766
  this.state = "pending", this.percent = 0;
@@ -4768,14 +4778,14 @@ var H2 = proxyCustomElement(class extends H {
4768
4778
  "error" !== this.state && (this.state = "complete", this.percent = 100);
4769
4779
  }
4770
4780
  render() {
4771
- return h(Host, { key: "8468877f30120b32201867ab5466d4d0fed5e514" }, h("slot", { key: "f44af091a15ff9ae425a61b708c5ea64a19a5057" }), h("figure", { key: "c629a6dece58606c37979d8d21cfe37d2312511e" }, h("div", { key: "87b9629c3133c7050cf84ec6a8824a68dadb81d0", class: "progress-details" }, h("progress-bar", { key: "63238eeda3adb36ce17a355d4cb2db0dbf45f0df", percent: this.percent, class: this.state, error: "error" === this.state }, h("a", { key: "dacdd7679ee07177fc5a18dcca018dcb6b32406e", class: "download-link", href: this.href || this.src, download: this.download || this.filename, onClick: (t2) => t2.stopPropagation() }, this.filename)), h("span", { key: "5618922137596fc76b569ac876064a0444d8d73a", class: "progress-icon" }), h("a", { key: "6ac34bc373c61db029a1e0101ea2219846e960fd", class: "remove-media", onClick: this.removeClicked, href: "#" }, h("span", { key: "ef9f0d6e8ba6fab4d876cd788e75a34ada1fe572" }, "Remove media")), this.uploadError && this._file ? h("a", { class: "retry-media", onClick: this.retryClicked, href: "#" }, h("span", null, "Retry upload")) : ""), this.validationError || this.uploadError ? h("p", { class: "validation-error" }, this.validationError || this.uploadError) : "", this.preview ? h("attachment-preview", { src: this.src, filetype: this.filetype }) : ""));
4781
+ return h(Host, { key: "58b4ee95bbb2847b70e0eb7273a5da05c9f65243" }, h("slot", { key: "1a50d5449d200b72f25b2824c2f0130cf09b5c9d" }), h("figure", { key: "a2ebf2d116499c28a4f83a2168df42e6fd0a450b" }, h("div", { key: "0d8ac23f1961b46affef09a23265da0c5e57fb33", class: "progress-details" }, h("progress-bar", { key: "2d6af9889678f6ae07f6deed914cddc4107a0a2d", percent: this.percent, class: this.state, error: "error" === this.state }, h("a", { key: "ebfcdd0382a04d1921447b2d659a88eb7522c1ce", class: "download-link", href: this.href || this.src, download: this.download || this.filename, onClick: (t2) => t2.stopPropagation() }, this.filename)), h("span", { key: "42dfc08c869e2cbb475d05e2f316c79733743e05", class: "progress-icon" }), h("a", { key: "f2286259bb36fb3d32036459e7383fe1e29be962", class: "remove-media", onClick: this.removeClicked, href: "#" }, h("span", { key: "2a36a5856faae7292ed2ac0572e180f3892af728" }, "Remove media")), this.uploadError && this._file ? h("a", { class: "retry-media", onClick: this.retryClicked, href: "#" }, h("span", null, "Retry upload")) : ""), this.validationError || this.uploadError ? h("p", { class: "validation-error" }, this.validationError || this.uploadError) : "", this.preview ? h("attachment-preview", { src: this.src, filetype: this.filetype }) : ""));
4772
4782
  }
4773
4783
  componentDidLoad() {
4774
4784
  "pending" == this.state && this._file && (this.checkValidity() ? (this.controller = new C(this.el, this._file), this.controller.dispatch("initialize", { controller: this.controller })) : this.state = "error");
4775
4785
  }
4776
4786
  checkValidity() {
4777
4787
  let t2 = [];
4778
- return t2.push(...new B(this).errors), t2.push(...new q(this).errors), this.validationError = t2.join(" "), this.validationEvent.emit({ valid: 0 === t2.length, error: this.validationError }), 0 === t2.length;
4788
+ return t2.push(...new B(this).errors), t2.push(...new q(this).errors), t2.push(...new F(this).errors), this.validationError = t2.join(" "), this.validationEvent.emit({ valid: 0 === t2.length, error: this.validationError }), 0 === t2.length;
4779
4789
  }
4780
4790
  static get watchers() {
4781
4791
  return { filename: [{ setMissingFiletype: 0 }] };
@@ -4786,7 +4796,7 @@ var H2 = proxyCustomElement(class extends H {
4786
4796
  }, [769, "attachment-file", { name: [1537], accepts: [1537], max: [1538], url: [1537], value: [1537], filename: [1537], src: [1537], href: [1537], download: [1537], filetype: [1537], size: [1538], state: [1537], percent: [1538], preview: [1540], validationMessage: [1, "validation-message"] }, [[0, "direct-upload:initialize", "start"], [0, "direct-upload:start", "start"], [0, "direct-upload:progress", "progress"], [0, "direct-upload:error", "error"], [0, "direct-upload:end", "end"]], { filename: [{ setMissingFiletype: 0 }] }]);
4787
4797
 
4788
4798
  // dist/components/attachment-file.js
4789
- var o = H2;
4799
+ var o = z;
4790
4800
 
4791
4801
  // dist/components/attachment-preview.js
4792
4802
  var e = a;
@@ -77,9 +77,9 @@ The main component providing file upload functionality.
77
77
  get files(): AttachmentFile[]
78
78
  set files(val: AttachmentFile[])
79
79
 
80
- // Get/set array of signed IDs from Active Storage
81
- get value(): string[]
82
- set value(val: string[])
80
+ // Get/set the attachments as a JSON string of { value: signed_id, filename, src, ... } objects
81
+ get value(): string
82
+ set value(val: string)
83
83
 
84
84
  // Clear all files
85
85
  reset(): void
@@ -137,6 +137,38 @@ set signedId(val: string)
137
137
  checkValidity(): boolean
138
138
  ```
139
139
 
140
+ ## Outside Rails (cross-origin, token auth)
141
+
142
+ `directupload` can be an absolute URL on another origin, as long as that endpoint speaks the
143
+ `@rails/activestorage` protocol and the storage bucket's CORS allows your origin. Add
144
+ credentials from the `direct-upload:before-blob-request` event, which carries the XHR for the
145
+ blob-reserving request:
146
+
147
+ ```js
148
+ const el = document.querySelector("input-attachment")
149
+ el.addEventListener("direct-upload:before-blob-request", event => {
150
+ event.detail.xhr.setRequestHeader("Authorization", `Bearer ${token}`)
151
+ })
152
+ ```
153
+
154
+ The element registers itself only after `defineCustomElements()` runs, so in a framework call it
155
+ once on the client:
156
+
157
+ ```js
158
+ import { defineCustomElements } from "@botandrose/input-attachment"
159
+ defineCustomElements()
160
+ ```
161
+
162
+ Without a `<form>` submit, read the signed id from the `change` event: `value` is a JSON string
163
+ of the current attachments, and each one's `value` is its signed id.
164
+
165
+ ```js
166
+ el.addEventListener("change", () => {
167
+ const [attachment] = JSON.parse(el.value)
168
+ console.log(attachment?.value) // the signed id, or undefined once removed
169
+ })
170
+ ```
171
+
140
172
  ## Form Submission Flow
141
173
 
142
174
  1. User selects/drops files into `<input-attachment>`
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botandrose/input-attachment",
3
- "version": "0.0.1",
3
+ "version": "0.6.4",
4
4
  "description": "Next-gen file field",
5
5
  "type": "module",
6
6
  "module": "dist/components/index.js",
@@ -2,6 +2,7 @@ import { Component, Prop, Element, Watch, Host, h } from '@stencil/core'
2
2
  import { Listen, Event, EventEmitter } from '@stencil/core'
3
3
  import DirectUploadController from './direct-upload-controller'
4
4
  import Max from './max'
5
+ import NotEmpty from './not-empty'
5
6
  import Accepts from './accepts'
6
7
  import Extensions from './extensions'
7
8
  import { get } from 'rails-request-json'
@@ -170,6 +171,7 @@ export class AttachmentFile {
170
171
  let errors = []
171
172
  errors.push(...new Accepts(this).errors)
172
173
  errors.push(...new Max(this).errors)
174
+ errors.push(...new NotEmpty(this).errors)
173
175
  this.validationError = errors.join(" ")
174
176
  // Notify parent of validation state change
175
177
  this.validationEvent.emit({ valid: errors.length === 0, error: this.validationError })
@@ -0,0 +1,20 @@
1
+ import { AttachmentFile } from './attachment-file'
2
+
3
+ export default class NotEmpty {
4
+ uploadedFile: AttachmentFile
5
+
6
+ constructor(uploadedFile) {
7
+ this.uploadedFile = uploadedFile
8
+ }
9
+
10
+ get errors() {
11
+ if(this.#errors) return this.#errors
12
+ this.#errors = []
13
+ if(this.uploadedFile.size === 0) {
14
+ this.#errors.push("Must be larger than 0 bytes.")
15
+ }
16
+ return this.#errors
17
+ }
18
+
19
+ #errors: Array<string>
20
+ }
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Bard
4
4
  module AttachmentField
5
- VERSION = "0.6.4"
5
+ VERSION = "0.6.5"
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.6.4
4
+ version: 0.6.5
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-09-13 00:00:00.000000000 Z
11
+ date: 2026-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activestorage
@@ -327,6 +327,7 @@ files:
327
327
  - input-attachment/src/components/attachment-file/direct-upload-controller.tsx
328
328
  - input-attachment/src/components/attachment-file/extensions.ts
329
329
  - input-attachment/src/components/attachment-file/max.ts
330
+ - input-attachment/src/components/attachment-file/not-empty.ts
330
331
  - input-attachment/src/components/attachment-file/readme.md
331
332
  - input-attachment/src/components/attachment-preview/attachment-preview.css
332
333
  - input-attachment/src/components/attachment-preview/attachment-preview.e2e.ts