bard-attachment_field 0.1.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 (71) hide show
  1. checksums.yaml +7 -0
  2. data/.nvmrc +1 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Appraisals +17 -0
  6. data/CHANGELOG.md +15 -0
  7. data/Gemfile +6 -0
  8. data/LICENSE +21 -0
  9. data/README.md +39 -0
  10. data/Rakefile +10 -0
  11. data/app/assets/javascripts/input-attachment.js +6021 -0
  12. data/app/controllers/bard/attachment_field/blobs_controller.rb +11 -0
  13. data/bard-attachment_field.gemspec +56 -0
  14. data/config/cucumber.yml +1 -0
  15. data/config/routes.rb +6 -0
  16. data/gemfiles/rails_7.1.gemfile +7 -0
  17. data/gemfiles/rails_7.2.gemfile +7 -0
  18. data/gemfiles/rails_8.0.gemfile +7 -0
  19. data/gemfiles/rails_8.1.gemfile +7 -0
  20. data/input-attachment/.editorconfig +15 -0
  21. data/input-attachment/.github/workflows/test.yml +21 -0
  22. data/input-attachment/.gitignore +27 -0
  23. data/input-attachment/.prettierrc.json +13 -0
  24. data/input-attachment/CLAUDE.md +63 -0
  25. data/input-attachment/LICENSE +21 -0
  26. data/input-attachment/README.md +288 -0
  27. data/input-attachment/bin/log +2 -0
  28. data/input-attachment/bin/server +1 -0
  29. data/input-attachment/bin/setup +4 -0
  30. data/input-attachment/bun.lockb +0 -0
  31. data/input-attachment/bundle.js +3 -0
  32. data/input-attachment/jest-setup.js +24 -0
  33. data/input-attachment/package.json +56 -0
  34. data/input-attachment/src/components/attachment-file/accepts.ts +32 -0
  35. data/input-attachment/src/components/attachment-file/attachment-file.css +89 -0
  36. data/input-attachment/src/components/attachment-file/attachment-file.e2e.ts +11 -0
  37. data/input-attachment/src/components/attachment-file/attachment-file.spec.tsx +20 -0
  38. data/input-attachment/src/components/attachment-file/attachment-file.tsx +157 -0
  39. data/input-attachment/src/components/attachment-file/direct-upload-controller.tsx +100 -0
  40. data/input-attachment/src/components/attachment-file/extensions.ts +13 -0
  41. data/input-attachment/src/components/attachment-file/max.ts +46 -0
  42. data/input-attachment/src/components/attachment-file/readme.md +55 -0
  43. data/input-attachment/src/components/attachment-preview/attachment-preview.css +8 -0
  44. data/input-attachment/src/components/attachment-preview/attachment-preview.e2e.ts +11 -0
  45. data/input-attachment/src/components/attachment-preview/attachment-preview.spec.tsx +19 -0
  46. data/input-attachment/src/components/attachment-preview/attachment-preview.tsx +42 -0
  47. data/input-attachment/src/components/attachment-preview/readme.md +31 -0
  48. data/input-attachment/src/components/input-attachment/form-controller.tsx +146 -0
  49. data/input-attachment/src/components/input-attachment/input-attachment.css +100 -0
  50. data/input-attachment/src/components/input-attachment/input-attachment.e2e.ts +11 -0
  51. data/input-attachment/src/components/input-attachment/input-attachment.spec.tsx +37 -0
  52. data/input-attachment/src/components/input-attachment/input-attachment.tsx +353 -0
  53. data/input-attachment/src/components/input-attachment/readme.md +45 -0
  54. data/input-attachment/src/components.d.ts +175 -0
  55. data/input-attachment/src/global.d.ts +3 -0
  56. data/input-attachment/src/images/example.jpg +0 -0
  57. data/input-attachment/src/index.html +36 -0
  58. data/input-attachment/src/index.ts +1 -0
  59. data/input-attachment/src/utils/utils.spec.ts +19 -0
  60. data/input-attachment/src/utils/utils.ts +14 -0
  61. data/input-attachment/stencil.config.ts +43 -0
  62. data/input-attachment/test-mocks/file-drop.cjs +7 -0
  63. data/input-attachment/test-mocks/progress-bar.cjs +9 -0
  64. data/input-attachment/tsconfig.json +32 -0
  65. data/lib/bard/attachment_field/cucumber.rb +277 -0
  66. data/lib/bard/attachment_field/field.rb +33 -0
  67. data/lib/bard/attachment_field/form_builder.rb +12 -0
  68. data/lib/bard/attachment_field/version.rb +7 -0
  69. data/lib/bard/attachment_field.rb +20 -0
  70. data/lib/bard-attachment_field.rb +1 -0
  71. metadata +409 -0
@@ -0,0 +1,11 @@
1
+ module Bard
2
+ module AttachmentField
3
+ class BlobsController < ActionController::Base
4
+ def show
5
+ @blob = ActiveStorage::Blob.find_signed!(params[:signed_id])
6
+ render json: @blob
7
+ end
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/bard/attachment_field/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "bard-attachment_field"
7
+ spec.version = Bard::AttachmentField::VERSION
8
+ spec.authors = ["Micah Geisel"]
9
+ spec.email = ["micah@botandrose.com"]
10
+
11
+ spec.summary = "Enhanced file upload field for Rails forms with drag-and-drop and previews"
12
+ spec.description = "An enhanced file upload field for Rails forms, powered by web components. Provides drag-and-drop uploads, image/video previews, and seamless ActiveStorage integration."
13
+ spec.homepage = "https://github.com/botandrose/bard-attachment_field"
14
+ spec.required_ruby_version = ">= 3.0.0"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "https://github.com/botandrose/bard-attachment_field"
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(__dir__) do
22
+ `git ls-files -z`.split("\x0").reject do |f|
23
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
24
+ end
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_dependency "activestorage", ">=7.1.0"
31
+
32
+ # Development dependencies
33
+ spec.add_development_dependency "debug"
34
+ spec.add_development_dependency "rails"
35
+ spec.add_development_dependency "sqlite3"
36
+ spec.add_development_dependency "cucumber"
37
+ spec.add_development_dependency "cucumber-rails"
38
+ spec.add_development_dependency "capybara"
39
+ spec.add_development_dependency "cuprite"
40
+ spec.add_development_dependency "cuprite-downloads"
41
+ spec.add_development_dependency "chop"
42
+ spec.add_development_dependency "rspec"
43
+ spec.add_development_dependency "capybara-shadowdom"
44
+ spec.add_development_dependency "capybara-screenshot"
45
+ spec.add_development_dependency "database_cleaner"
46
+ spec.add_development_dependency "puma"
47
+ spec.add_development_dependency "sprockets-rails"
48
+ spec.add_development_dependency "importmap-rails"
49
+ spec.add_development_dependency "turbo-rails"
50
+ spec.add_development_dependency "stimulus-rails"
51
+ spec.add_development_dependency "rake", "~> 13.0"
52
+ spec.add_development_dependency "appraisal"
53
+
54
+ # For more information and examples about making a new gem, check out our
55
+ # guide at: https://bundler.io/guides/creating_gem.html
56
+ end
@@ -0,0 +1 @@
1
+ default: --strict <%= "--retry 2 --no-strict-flaky" if ENV["CI"] %> --format pretty --guess --require features/support --publish-quiet --tags 'not @pending'
data/config/routes.rb ADDED
@@ -0,0 +1,6 @@
1
+ Rails.application.routes.draw do
2
+ scope ActiveStorage.routes_prefix do
3
+ get "/blobs/info/:signed_id" => "bard/attachment_field/blobs#show"
4
+ end
5
+ end
6
+
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 7.1.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 7.2.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 8.0.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 8.1.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,15 @@
1
+ # http://editorconfig.org
2
+
3
+ root = true
4
+
5
+ [*]
6
+ charset = utf-8
7
+ indent_style = space
8
+ indent_size = 2
9
+ end_of_line = lf
10
+ insert_final_newline = true
11
+ trim_trailing_whitespace = true
12
+
13
+ [*.md]
14
+ insert_final_newline = false
15
+ trim_trailing_whitespace = false
@@ -0,0 +1,21 @@
1
+ name: Test
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ runs-on: ubuntu-latest
8
+
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+
12
+ - name: Setup Bun
13
+ uses: oven-sh/setup-bun@v1
14
+ with:
15
+ bun-version: latest
16
+
17
+ - name: Install dependencies
18
+ run: bun install
19
+
20
+ - name: Run tests
21
+ run: NODE_OPTIONS=--experimental-vm-modules bun run test
@@ -0,0 +1,27 @@
1
+ www/
2
+ dist/
3
+ loader/
4
+
5
+ *~
6
+ *.sw[mnpcod]
7
+ *.log
8
+ *.lock
9
+ *.tmp
10
+ *.tmp.*
11
+ log.txt
12
+ *.sublime-project
13
+ *.sublime-workspace
14
+
15
+ .stencil/
16
+ .idea/
17
+ .vscode/
18
+ .sass-cache/
19
+ .versions/
20
+ node_modules/
21
+ $RECYCLE.BIN/
22
+
23
+ .DS_Store
24
+ Thumbs.db
25
+ UserInterfaceState.xcuserstate
26
+ .env
27
+ PLAN
@@ -0,0 +1,13 @@
1
+ {
2
+ "arrowParens": "avoid",
3
+ "bracketSpacing": true,
4
+ "jsxBracketSameLine": false,
5
+ "jsxSingleQuote": false,
6
+ "quoteProps": "consistent",
7
+ "printWidth": 180,
8
+ "semi": true,
9
+ "singleQuote": true,
10
+ "tabWidth": 2,
11
+ "trailingComma": "all",
12
+ "useTabs": false
13
+ }
@@ -0,0 +1,63 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Development Commands
6
+
7
+ **Note: This project uses Bun instead of npm for package management and script execution.**
8
+
9
+ - **Build**: `bun run build` - Compiles Stencil components with docs generation
10
+ - **Development server**: `bun start` - Watch mode with live reload
11
+ - **Tests**: `bun run test` - Run unit tests (Jest via Stencil)
12
+ - **E2E tests**: `bun run test:e2e` - Run unit + e2e
13
+ - **Spec tests only**: `bun run spec` - Run unit tests without e2e
14
+ - **Watch tests**: `bun run test.watch` - Run tests in watch mode
15
+ - **Generate component**: `bun run generate` - Create new Stencil component
16
+
17
+ ## Architecture Overview
18
+
19
+ This is a Stencil-based Web Components library for advanced file upload functionality, specifically designed to work with Rails Active Storage direct uploads.
20
+
21
+ ### Core Components Structure
22
+
23
+ - **`<input-attachment>`** - Main file upload component with drag/drop support
24
+ - Acts as form field replacement with validation API compatibility
25
+ - Manages file state and coordinates with Rails Active Storage
26
+ - Uses `FormController` for upload orchestration and progress tracking
27
+
28
+ - **`<attachment-file>`** - Individual file representation component
29
+ - Handles direct upload via `DirectUploadController`
30
+ - Manages file preview, validation, and removal
31
+ - Supports both existing files (via signed IDs) and new uploads
32
+
33
+ - **`<file-drop>`** - Drag and drop interface component (provided by `@botandrose/file-drop` package)
34
+ - **`<attachment-preview>`** - File preview display component
35
+ - **`<progress-bar>`** - Upload progress indicator (provided by `@botandrose/progress-bar` package)
36
+
37
+ ### Key Integration Points
38
+
39
+ - **Rails Active Storage**: Uses `@rails/activestorage` for direct uploads
40
+ - **Form Integration**: Components integrate with standard HTML forms via `FormController`
41
+ - **Validation**: Implements HTML5 form validation APIs (`checkValidity`, `setCustomValidity`, etc.)
42
+
43
+ ### Component Communication
44
+
45
+ - Uses Stencil's event system for component communication
46
+ - Key events: `direct-upload:*`, `attachment-file:remove`, `change`
47
+ - `FormController` coordinates upload queue and progress display
48
+ - Components maintain form field compatibility for seamless integration
49
+
50
+ ### File Upload Flow
51
+
52
+ 1. User selects/drops files into `<input-attachment>`
53
+ 2. Files become `<attachment-file>` components with validation
54
+ 3. On form submit, `FormController` manages upload queue
55
+ 4. `DirectUploadController` handles Rails Active Storage uploads
56
+ 5. Progress tracked via `<progress-bar>` components
57
+ 6. Completed uploads provide signed IDs for form submission
58
+
59
+ ## Testing Configuration
60
+
61
+ - Uses Jest with ts-jest for TypeScript support
62
+ - Puppeteer for e2e testing (headless Chrome)
63
+ - ESM modules enabled via `NODE_OPTIONS=--experimental-vm-modules`
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,288 @@
1
+ # input-attachment
2
+
3
+ A web components library providing advanced file upload functionality for Rails Active Storage with drag-and-drop support and real-time progress tracking.
4
+
5
+ ## Features
6
+
7
+ - 📁 **Multiple File Support** - Upload single or multiple files
8
+ - 🎨 **Drag & Drop** - Intuitive drag-and-drop file selection
9
+ - 📸 **File Previews** - Automatic preview generation for images and videos
10
+ - 📊 **Progress Tracking** - Real-time upload progress with visual feedback
11
+ - ✅ **Validation** - Built-in file type and size validation
12
+ - 🔐 **Rails Active Storage Integration** - Seamless direct uploads to AWS S3 or other storage backends
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @botandrose/input-attachment
18
+ ```
19
+
20
+ or with Bun:
21
+
22
+ ```bash
23
+ bun add @botandrose/input-attachment
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ### Basic Example
29
+
30
+ ```html
31
+ <form>
32
+ <input-attachment
33
+ name="files"
34
+ directupload="/rails/active_storage/direct_uploads"
35
+ multiple
36
+ ></input-attachment>
37
+
38
+ <button type="submit">Upload</button>
39
+ </form>
40
+ ```
41
+
42
+ ### With Validation
43
+
44
+ ```html
45
+ <input-attachment
46
+ name="photos"
47
+ directupload="/rails/active_storage/direct_uploads"
48
+ accepts="image"
49
+ max="5242880"
50
+ required
51
+ ></input-attachment>
52
+ ```
53
+
54
+ ## API Reference
55
+
56
+ ### `<input-attachment>`
57
+
58
+ The main component providing file upload functionality.
59
+
60
+ #### Props
61
+
62
+ | Prop | Type | Default | Description |
63
+ | ------ | ------ | --------- | ------------- |
64
+ | `name` | string | - | Form field name for form submission |
65
+ | `directupload` | string | - | Rails Active Storage direct upload endpoint URL |
66
+ | `multiple` | boolean | false | Allow multiple file selection |
67
+ | `required` | boolean | false | Require at least one file |
68
+ | `accepts` | string | - | Comma-separated file types (e.g., "image", "video", "pdf") |
69
+ | `max` | number | - | Maximum file size in bytes |
70
+ | `preview` | boolean | true | Show file previews |
71
+ | `disabled` | boolean | false | Disable file selection (used during form submission) |
72
+
73
+ #### Methods
74
+
75
+ ```typescript
76
+ // Get/set array of file objects
77
+ get files(): AttachmentFile[]
78
+ set files(val: AttachmentFile[])
79
+
80
+ // Get/set array of signed IDs from Active Storage
81
+ get value(): string[]
82
+ set value(val: string[])
83
+
84
+ // Clear all files
85
+ reset(): void
86
+
87
+ // Validate the component
88
+ checkValidity(): boolean
89
+ setCustomValidity(msg: string): void
90
+ reportValidity(): boolean
91
+
92
+ // Get validation error message
93
+ get validationMessage(): string
94
+ ```
95
+
96
+ #### Events
97
+
98
+ | Event | Detail | Description |
99
+ | ------- | -------- | ------------- |
100
+ | `change` | - | Fired when file list changes (bubbles) |
101
+ | `direct-upload:initialize` | `{ id, file, controller }` | Upload queue initialized |
102
+ | `direct-upload:start` | `{ id }` | Upload started |
103
+ | `direct-upload:progress` | `{ id, progress }` | Upload progress (0-100) |
104
+ | `direct-upload:error` | `{ id, error }` | Upload failed |
105
+ | `direct-upload:end` | `{ id }` | Upload completed |
106
+
107
+ ### `<attachment-file>`
108
+
109
+ Individual file representation within the upload component.
110
+
111
+ #### Props
112
+
113
+ | Prop | Type | Default | Description |
114
+ | ------ | ------ | --------- | ------------- |
115
+ | `name` | string | - | Form field name |
116
+ | `value` | string | "" | Signed ID from Rails Active Storage |
117
+ | `filename` | string | - | Display filename |
118
+ | `src` | string | - | Preview image/video URL |
119
+ | `filetype` | string | - | File category (image/video/pdf/unknown) |
120
+ | `size` | number | - | File size in bytes |
121
+ | `state` | string | "complete" | Upload state (pending/complete/error) |
122
+ | `percent` | number | 100 | Upload progress percentage |
123
+ | `preview` | boolean | true | Show preview |
124
+ | `accepts` | string | - | Allowed file types |
125
+ | `max` | number | - | Maximum file size |
126
+
127
+ #### Methods
128
+
129
+ ```typescript
130
+ // Set file to upload
131
+ set file(file: File)
132
+
133
+ // Load existing file from Active Storage
134
+ set signedId(val: string)
135
+
136
+ // Validate the file
137
+ checkValidity(): boolean
138
+ ```
139
+
140
+ ## Form Submission Flow
141
+
142
+ 1. User selects/drops files into `<input-attachment>`
143
+ 2. Files become `<attachment-file>` components with validation
144
+ 3. On form submit, `FormController` intercepts and manages upload queue
145
+ 4. Each file uploads to Rails Active Storage via `DirectUploadController`
146
+ 5. Signed IDs are collected via `ElementInternals.setFormValue()`
147
+ 6. After all uploads complete, form is actually submitted
148
+ 7. Server receives signed IDs in form data
149
+
150
+ ## Architecture
151
+
152
+ ### Components
153
+
154
+ - **`<input-attachment>`** - Main form field replacement with drag-and-drop
155
+ - **`<attachment-file>`** - Individual file representation
156
+ - **`<attachment-preview>`** - File preview display
157
+ - **`<file-drop>`** - Drag and drop interface (from `@botandrose/file-drop`)
158
+ - **`<progress-bar>`** - Upload progress indicator (from `@botandrose/progress-bar`)
159
+
160
+ ## Styling
161
+
162
+ The component uses Shadow DOM with customizable CSS custom properties:
163
+
164
+ ```css
165
+ input-attachment {
166
+ --input-attachment-text-color: #000;
167
+ }
168
+ ```
169
+
170
+ Style the file-drop area using the `::part()` pseudo-element:
171
+
172
+ ```css
173
+ input-attachment::part(title) {
174
+ font-size: 16px;
175
+ color: #333;
176
+ }
177
+ ```
178
+
179
+ ## Rails Integration
180
+
181
+ ### Setup Active Storage Direct Uploads
182
+
183
+ In your Rails app, ensure Active Storage is configured:
184
+
185
+ ```ruby
186
+ # config/storage.yml
187
+ amazon:
188
+ service: S3
189
+ access_key_id: ...
190
+ secret_access_key: ...
191
+ ```
192
+
193
+ The `directupload` prop should point to:
194
+ ```
195
+ /rails/active_storage/direct_uploads
196
+ ```
197
+
198
+ ### Accessing Uploaded Files in Rails
199
+
200
+ ```ruby
201
+ class Post < ApplicationRecord
202
+ has_many_attached :attachments
203
+ end
204
+
205
+ # In controller
206
+ @post = Post.create(attachments: attachment_signed_ids)
207
+
208
+ # The signed_ids are automatically resolved to blobs
209
+ ```
210
+
211
+ ## Validation
212
+
213
+ ### File Type Validation
214
+
215
+ ```html
216
+ <input-attachment
217
+ accepts="image,video"
218
+ ></input-attachment>
219
+ ```
220
+
221
+ Supported types: `image`, `video`, `pdf`, or specific MIME types
222
+
223
+ ### File Size Validation
224
+
225
+ ```html
226
+ <!-- Max 5MB -->
227
+ <input-attachment
228
+ max="5242880"
229
+ ></input-attachment>
230
+ ```
231
+
232
+ ### Custom Validation
233
+
234
+ ```javascript
235
+ const attachment = document.querySelector('input-attachment');
236
+
237
+ // Check validity
238
+ if (!attachment.checkValidity()) {
239
+ console.log(attachment.validationMessage);
240
+ }
241
+
242
+ // Set custom error
243
+ attachment.setCustomValidity('Custom error message');
244
+ ```
245
+
246
+ ## Development
247
+
248
+ ### Prerequisites
249
+
250
+ - Node.js 18+
251
+ - Bun
252
+
253
+ ### Commands
254
+
255
+ ```bash
256
+ # Install dependencies
257
+ bun install
258
+
259
+ # Start development server
260
+ bun start
261
+
262
+ # Build for production
263
+ bun run build
264
+
265
+ # Run tests
266
+ bun run test
267
+
268
+ # Watch tests
269
+ bun run test.watch
270
+
271
+ # Run e2e tests only
272
+ bun run test:e2e
273
+
274
+ # Generate new component
275
+ bun run generate
276
+ ```
277
+
278
+ ## Browser Support
279
+
280
+ - Chrome/Edge 88+
281
+ - Firefox 85+
282
+ - Safari 15.1+
283
+
284
+ ElementInternals requires modern browsers with form-associated custom elements support.
285
+
286
+ ## License
287
+
288
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ tail -f -n100 /var/log/apache2/error.log
@@ -0,0 +1 @@
1
+ bun run start
@@ -0,0 +1,4 @@
1
+ if [[ ! $(command -v bun) ]] || [[ $(bun --version) != "1.0.14" ]]; then
2
+ curl -fsSL https://bun.sh/install | bash -s -- bun-v1.0.14
3
+ fi
4
+ bun install
Binary file
@@ -0,0 +1,3 @@
1
+ export * from './dist/components/index.js';
2
+ import { defineCustomElements } from './dist/components/index.js';
3
+ defineCustomElements();
@@ -0,0 +1,24 @@
1
+ // Jest setup file for DOM polyfills
2
+
3
+ // Polyfill replaceChildren for test environment
4
+ Element.prototype.replaceChildren = Element.prototype.replaceChildren || function(...nodes) {
5
+ while (this.lastChild) {
6
+ this.removeChild(this.lastChild);
7
+ }
8
+ this.append(...nodes);
9
+ };
10
+
11
+ // Mock HTML input validation methods
12
+ if (typeof HTMLInputElement !== 'undefined') {
13
+ Object.defineProperty(HTMLInputElement.prototype, 'setCustomValidity', {
14
+ value: function() {},
15
+ writable: true
16
+ });
17
+
18
+ Object.defineProperty(HTMLInputElement.prototype, 'reportValidity', {
19
+ value: function() { return true; },
20
+ writable: true
21
+ });
22
+ }
23
+
24
+ // Progress-bar and file-drop components are mocked via moduleNameMapper in stencil.config.ts
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@botandrose/input-attachment",
3
+ "version": "0.0.1",
4
+ "description": "Next-gen file field",
5
+ "type": "module",
6
+ "module": "dist/components/index.js",
7
+ "types": "./dist/components/index.d.ts",
8
+ "files": [
9
+ "dist/"
10
+ ],
11
+ "scripts": {
12
+ "prepublishOnly": "bun run build",
13
+ "build": "bunx stencil build --docs && bun run bundle",
14
+ "bundle": "bunx esbuild dist/components/index.js --bundle --format=esm --outfile=dist/input-attachment.esm.js --footer:js='defineCustomElements();'",
15
+ "start": "bunx stencil build --docs --watch --serve",
16
+ "test": "NODE_OPTIONS=--experimental-vm-modules bunx stencil test --spec --e2e --max-workers=1",
17
+ "test:spec": "NODE_OPTIONS=--experimental-vm-modules bunx stencil test --spec --max-workers=1",
18
+ "test:e2e": "NODE_OPTIONS=--experimental-vm-modules bunx stencil test --e2e --max-workers=1",
19
+ "test:watch": "NODE_OPTIONS=--experimental-vm-modules bunx stencil test --spec --watchAll --max-workers=1",
20
+ "generate": "bunx stencil generate"
21
+ },
22
+ "jest": {
23
+ "testEnvironment": "jsdom",
24
+ "extensionsToTreatAsEsm": [".ts", ".tsx"],
25
+ "globals": {
26
+ "ts-jest": {
27
+ "useESM": true
28
+ }
29
+ }
30
+ },
31
+ "dependencies": {
32
+ "@botandrose/file-drop": "^0.1.0",
33
+ "@botandrose/progress-bar": "^0.1.1",
34
+ "@rails/activestorage": "^8.1.0",
35
+ "@stencil/core": "^4.38.2",
36
+ "rails-request-json": "^0.2.0",
37
+ "ts-jest": "^29.4.5"
38
+ },
39
+ "devDependencies": {
40
+ "@types/jest": "^29.5.12",
41
+ "@types/node": "^24.9.1",
42
+ "jest": "^29.7.0",
43
+ "jest-cli": "^29.7.0",
44
+ "puppeteer": "^24.26.1"
45
+ },
46
+ "peerDependencies": {
47
+ "@rails/activestorage": ">=7.0.0"
48
+ },
49
+ "exports": {
50
+ ".": {
51
+ "types": "./dist/types/components.d.ts",
52
+ "import": "./dist/components/index.js"
53
+ }
54
+ },
55
+ "license": "MIT"
56
+ }